Skip to content

Commit

Permalink
WIP Adding presets support and refactoring
Browse files Browse the repository at this point in the history
  • Loading branch information
FrozenAlex committed Jan 4, 2025
1 parent 7551b68 commit 7aa8007
Show file tree
Hide file tree
Showing 15 changed files with 550 additions and 559 deletions.
320 changes: 65 additions & 255 deletions include/FilterOptions.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,260 +2,70 @@

#include <vector>
#include <limits>
#include "main.hpp"
#include "song-details/shared/Data/MapCharacteristic.hpp"
#include "song-details/shared/Data/MapDifficulty.hpp"
#include "song-details/shared/Data/RankedStates.hpp"
#include "song-details/shared/Data/MapMods.hpp"
#include "song-details/shared/Data/SongDifficulty.hpp"



class FilterOptions
{
public:
// FilterOptions(FilterOptions const&) = delete; // no accidental copying
// FilterOptions() = default;

enum class DownloadFilterType
{
All,
OnlyDownloaded,
HideDownloaded
};
enum class LocalScoreFilterType
{
All,
HidePassed,
OnlyPassed
};
enum class RankedFilterType
{
ShowAll,
ScoreSaberRanked,
BeatLeaderRanked,
ScoreSaberQualified,
BeatLeaderQualified
};
enum class DifficultyFilterType
{
All,
Easy,
Normal,
Hard,
Expert,
ExpertPlus
};
enum class CharFilterType
{
All,
Custom,
Standard,
OneSaber,
NoArrows,
NinetyDegrees,
ThreeSixtyDegrees,
LightShow,
Lawless,
};

enum class RequirementType {
Any,
NoodleExtensions,
MappingExtensions,
Chroma,
Cinema,
None
};

static inline const float SONG_LENGTH_FILTER_MAX = 15.0f;
static inline const float STAR_FILTER_MAX = 18.0f;
static inline const float NJS_FILTER_MAX = 25.0f;
static inline const float NPS_FILTER_MAX = 12.0f;
static inline const int64_t BEATSAVER_EPOCH = 1525136400;

//General
DownloadFilterType downloadType = DownloadFilterType::All;
LocalScoreFilterType localScoreType = LocalScoreFilterType::All;
float minLength = 0, maxLength = 900;

//Mapping
float minNJS = 0, maxNJS = NJS_FILTER_MAX;
float minNPS = 0, maxNPS = NPS_FILTER_MAX;

// Ranked
RankedFilterType rankedType = RankedFilterType::ShowAll;
float minStars = 0, maxStars = STAR_FILTER_MAX;

//BeatSaver
int minUploadDate = BEATSAVER_EPOCH;
int minUploadDateInMonths = 0;
float minRating = 0;
int minVotes = 0;
std::vector<std::string> uploaders;
bool uploadersBlackList = false;

//Difficulty
DifficultyFilterType difficultyFilter = DifficultyFilterType::All;
CharFilterType charFilter = CharFilterType::All;

//Mods
RequirementType modRequirement = RequirementType::Any;
};

enum class SortMode {
Newest,
Oldest,
Latest_Ranked,
Most_Stars,
Least_Stars,
Best_rated,
Worst_rated
};

enum class PreferredLeaderBoard {
ScoreSaber = 0,
BeatLeader = 1
};



// Map for characteristics
static const std::unordered_map<FilterOptions::CharFilterType, SongDetailsCache::MapCharacteristic> charMap = {
{FilterOptions::CharFilterType::Custom, SongDetailsCache::MapCharacteristic::Custom},
{FilterOptions::CharFilterType::Standard, SongDetailsCache::MapCharacteristic::Standard},
{FilterOptions::CharFilterType::OneSaber, SongDetailsCache::MapCharacteristic::OneSaber},
{FilterOptions::CharFilterType::NoArrows, SongDetailsCache::MapCharacteristic::NoArrows},
{FilterOptions::CharFilterType::NinetyDegrees, SongDetailsCache::MapCharacteristic::NinetyDegree},
{FilterOptions::CharFilterType::ThreeSixtyDegrees, SongDetailsCache::MapCharacteristic::ThreeSixtyDegree},
{FilterOptions::CharFilterType::LightShow, SongDetailsCache::MapCharacteristic::LightShow},
{FilterOptions::CharFilterType::Lawless, SongDetailsCache::MapCharacteristic::Lawless}
};

// Map for difficulties
static const std::unordered_map<FilterOptions::DifficultyFilterType, SongDetailsCache::MapDifficulty> diffMap = {
{FilterOptions::DifficultyFilterType::Easy, SongDetailsCache::MapDifficulty::Easy},
{FilterOptions::DifficultyFilterType::Normal, SongDetailsCache::MapDifficulty::Normal},
{FilterOptions::DifficultyFilterType::Hard, SongDetailsCache::MapDifficulty::Hard},
{FilterOptions::DifficultyFilterType::Expert, SongDetailsCache::MapDifficulty::Expert},
{FilterOptions::DifficultyFilterType::ExpertPlus, SongDetailsCache::MapDifficulty::ExpertPlus}
};


// Map for ranked states
static const std::unordered_map<FilterOptions::RankedFilterType, SongDetailsCache::RankedStates> rankMap = {
{FilterOptions::RankedFilterType::ScoreSaberRanked, SongDetailsCache::RankedStates::ScoresaberRanked},
{FilterOptions::RankedFilterType::BeatLeaderRanked, SongDetailsCache::RankedStates::BeatleaderRanked},
{FilterOptions::RankedFilterType::ScoreSaberQualified, SongDetailsCache::RankedStates::ScoresaberQualified},
{FilterOptions::RankedFilterType::BeatLeaderQualified, SongDetailsCache::RankedStates::BeatleaderQualified}
};

// Map for preferred leaderboard
static const std::unordered_map<std::string, PreferredLeaderBoard> leaderBoardMap = {
{"Scoresaber", PreferredLeaderBoard::ScoreSaber},
{"Beatleader", PreferredLeaderBoard::BeatLeader}
};

class FilterOptionsCache
{
public:
FilterOptionsCache(FilterOptionsCache const&) = delete; // no accidental copying
FilterOptionsCache() = default;

void cache(FilterOptions s){
downloadType=s.downloadType;
localScoreType=s.localScoreType;
minLength=s.minLength;
if (s.maxLength / 60 >= FilterOptions::SONG_LENGTH_FILTER_MAX) { maxLength=std::numeric_limits<float>::infinity(); } else { maxLength=s.maxLength;}
minNJS=s.minNJS;
if (s.maxNJS >= FilterOptions::NJS_FILTER_MAX) { maxNJS=std::numeric_limits<float>::infinity(); } else { maxNJS=s.maxNJS;}
minNPS=s.minNPS;
if (s.maxNPS >= FilterOptions::NPS_FILTER_MAX) { maxNPS=std::numeric_limits<float>::infinity(); } else { maxNPS=s.maxNPS;}
rankedType=s.rankedType;
minStars=s.minStars;
if (s.maxStars >= FilterOptions::STAR_FILTER_MAX) { maxStars=std::numeric_limits<float>::infinity(); } else { maxStars=s.maxStars;}
minUploadDate=s.minUploadDate;
minRating=s.minRating;
minVotes=s.minVotes;
uploaders=s.uploaders;
uploadersBlackList=s.uploadersBlackList;
difficultyFilter=s.difficultyFilter;
charFilter=s.charFilter;
modRequirement=s.modRequirement;

// Process char filter
if (s.charFilter != FilterOptions::CharFilterType::All) {
charFilterPreprocessed = charMap.at(s.charFilter);
};

// Map difficulty filter
if (s.difficultyFilter != FilterOptions::DifficultyFilterType::All) {
difficultyFilterPreprocessed = diffMap.at(s.difficultyFilter);
};

// Check if filter is needed at all
skipFilter = false;
skipFilter = (
downloadType == FilterOptions::DownloadFilterType::All &&
localScoreType == FilterOptions::LocalScoreFilterType::All &&
(s.maxLength / 60 >= FilterOptions::SONG_LENGTH_FILTER_MAX) &&
(s.minLength == 0) &&
minNJS == 0 &&
s.maxNJS >= FilterOptions::NJS_FILTER_MAX &&
s.minNPS == 0 &&
s.maxNPS >= FilterOptions::NPS_FILTER_MAX &&
rankedType == FilterOptions::RankedFilterType::ShowAll &&
minStars == 0 &&
s.maxStars >= FilterOptions::STAR_FILTER_MAX &&
s.minUploadDateInMonths == 0 &&
minRating == 0 &&
minVotes == 0 &&
uploaders.size() == 0 &&
difficultyFilter == FilterOptions::DifficultyFilterType::All &&
charFilter == FilterOptions::CharFilterType::All &&
modRequirement == FilterOptions::RequirementType::Any
);

// Do infinity checks for songs that are out of bounds
if (s.maxStars >= FilterOptions::STAR_FILTER_MAX) { maxStars=std::numeric_limits<float>::infinity(); }
if (s.maxNJS >= FilterOptions::NJS_FILTER_MAX) { maxNJS=std::numeric_limits<float>::infinity(); }
if (s.maxNPS >= FilterOptions::NPS_FILTER_MAX) { maxNPS=std::numeric_limits<float>::infinity(); }
if (s.maxLength / 60 >= FilterOptions::SONG_LENGTH_FILTER_MAX) { maxLength=std::numeric_limits<float>::infinity(); }
}

bool skipFilter = false;


//General
FilterOptions::DownloadFilterType downloadType = FilterOptions::DownloadFilterType::All;
FilterOptions::LocalScoreFilterType localScoreType = FilterOptions::LocalScoreFilterType::All;
float minLength = 0, maxLength = 900;

//Mapping
float minNJS = 0, maxNJS = FilterOptions::NJS_FILTER_MAX;
float minNPS = 0, maxNPS = FilterOptions::NPS_FILTER_MAX;

//ScoreSaber
FilterOptions::RankedFilterType rankedType = FilterOptions::RankedFilterType::ShowAll;
float minStars = 0, maxStars = FilterOptions::STAR_FILTER_MAX;

//BeatSaver
int minUploadDate = FilterOptions::BEATSAVER_EPOCH;
float minRating = 0;
int minVotes = 0;
std::vector<std::string> uploaders;
bool uploadersBlackList = false;

//Difficulty
FilterOptions::DifficultyFilterType difficultyFilter = FilterOptions::DifficultyFilterType::All;
SongDetailsCache::MapDifficulty difficultyFilterPreprocessed;


/// @brief Char filter for gui
FilterOptions::CharFilterType charFilter = FilterOptions::CharFilterType::All;
/// @brief Used to speedup filtering, only if not All
SongDetailsCache::MapCharacteristic charFilterPreprocessed = SongDetailsCache::MapCharacteristic::Custom;
#include "rapidjson-macros/shared/macros.hpp"
#include "song-details/shared/Data/MapMods.hpp"
#include "PluginConfig.hpp"

using namespace SongDetailsCache;

namespace BetterSongSearch {
DECLARE_JSON_CLASS(FilterProfile,
VALUE_DEFAULT(FilterTypes::DownloadFilter, downloadType, FilterTypes::DownloadFilter::All);
VALUE_DEFAULT(FilterTypes::LocalScoreFilter, localScoreType, FilterTypes::LocalScoreFilter::All);
VALUE_DEFAULT(FilterTypes::RankedFilter, rankedType, FilterTypes::RankedFilter::ShowAll);
VALUE_DEFAULT(FilterTypes::DifficultyFilter, difficultyFilter, FilterTypes::DifficultyFilter::All);
VALUE_DEFAULT(FilterTypes::CharFilter, charFilter, FilterTypes::CharFilter::All);
VALUE_DEFAULT(FilterTypes::Requirement, modRequirement, FilterTypes::Requirement::Any);

VALUE_DEFAULT(float, minLength, 0);
VALUE_DEFAULT(float, maxLength, 900);
VALUE_DEFAULT(float, minNJS, 0);
VALUE_DEFAULT(float, maxNJS, NJS_FILTER_MAX);
VALUE_DEFAULT(float, minNPS, 0);
VALUE_DEFAULT(float, maxNPS, NPS_FILTER_MAX);

VALUE_DEFAULT(float, minStars, 0);
VALUE_DEFAULT(float, maxStars, STAR_FILTER_MAX);
VALUE_DEFAULT(int, minUploadDate, BEATSAVER_EPOCH);
VALUE_DEFAULT(int, minUploadDateInMonths, 0);
VALUE_DEFAULT(float, minRating, 0);
VALUE_DEFAULT(int, minVotes, 0);

VECTOR_DEFAULT(std::string, uploaders, {});
VALUE_DEFAULT(bool, uploadersBlackList, false);

public:
SongDetailsCache::MapCharacteristic charFilterPreprocessed = SongDetailsCache::MapCharacteristic::Custom;
SongDetailsCache::MapDifficulty difficultyFilterPreprocessed = SongDetailsCache::MapDifficulty::Easy;

bool isDefaultPreprocessed = true;

// @brief Checks if the profile is the default profile (no filters)
bool IsDefault();

// @brief Recalculates preprocessed values
void RecalculatePreprocessedValues();

// @brief Loads the profile from the mod config
void LoadFromConfig();

// @brief Saves the profile to the mod config
void SaveToConfig();

// @brief Saves the profile to a preset
// @param presetName The name of the preset to save
// @return True if the preset was saved successfully
bool SaveToPreset(std::string presetName) const;

// @brief Gets a list of all available presets
// @return A list of all available presets
static std::vector<std::string> GetPresetList();

// @brief Loads the profile from a preset
// @param presetName The name of the preset to load
// @return The loaded profile
static std::optional<FilterProfile> LoadFromPreset(std::string presetName);
)
}

//Mods
FilterOptions::RequirementType modRequirement = FilterOptions::RequirementType::Any;
};
Loading

0 comments on commit 7aa8007

Please sign in to comment.