Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[db] Support duplicate charts in song database #463

Draft
wants to merge 1 commit into
base: develop
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
109 changes: 95 additions & 14 deletions Beatmap/src/MapDatabase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ class MapDatabase_Impl
Map<int32, PracticeSetupIndex*> m_practiceSetups;

Map<String, ChartIndex*> m_chartsByHash;
Map<string, Vector<ChartIndex*>> m_chartDuplicates;
Map<String, FolderIndex*> m_foldersByPath;
Multimap<int32, PracticeSetupIndex*> m_practiceSetupsByChartId;

Expand Down Expand Up @@ -1037,7 +1038,8 @@ class MapDatabase_Impl
m_SortScores(chart);

m_charts.Add(chart->id, chart);
m_chartsByHash.Add(chart->hash, chart);
m_addToChartsByHash(chart);

// Add diff to map and resort
folder->charts.Add(chart);
m_SortCharts(folder);
Expand Down Expand Up @@ -1123,13 +1125,23 @@ class MapDatabase_Impl


// Check if the hash has changed...
if (chart->hash != e.hash && m_transferScores) {
if (chart->hash != e.hash && m_transferScores)
{
moveScores.BindString(1, e.hash);
moveScores.BindString(2, chart->hash);
moveScores.Step();
moveScores.Rewind();
}
chart->hash = e.hash;

if (chart->hash != e.hash)
{
m_removeFromChartsByHash(chart);

// Update chart hash and re-add
chart->hash = e.hash;

m_addToChartsByHash(chart);
}


auto itFolder = m_folders.find(chart->folderId);
Expand All @@ -1148,6 +1160,8 @@ class MapDatabase_Impl

itFolder->second->charts.Remove(itChart->second);

m_removeFromChartsByHash(itChart->second);

for (auto s : itChart->second->scores)
{
delete s;
Expand Down Expand Up @@ -1279,6 +1293,8 @@ class MapDatabase_Impl
addScore.Rewind();

m_database.Exec("END");

m_addScoreToCharts(score);
}

void UpdateChallengeResult(ChallengeIndex* chal, uint32 clearMark, uint32 bestScore)
Expand Down Expand Up @@ -1571,10 +1587,84 @@ class MapDatabase_Impl
"lwt INTEGER"
")");
}

void m_removeFromChartsByHash(ChartIndex* chart)
{
// Update charts by hash if needed
auto it = m_chartsByHash.find(chart->hash);
auto dups = m_chartDuplicates.Find(chart->hash);

if (it != m_chartsByHash.end() && it->second == chart)
{
m_chartsByHash.erase(it); // Remove old entry

// Promote a duplicate if exists
if (dups && dups->size())
{
m_chartsByHash.Add(chart->hash, dups->back());
dups->pop_back();
}
}
else
{
// Also remove from dup vectors
if (dups)
std::remove(dups->begin(), dups->end(), chart);
}
}

void m_addToChartsByHash(ChartIndex* chart)
{
if (m_chartsByHash.Find(chart->hash) != nullptr)
{
auto existing = m_chartDuplicates.Find(chart->hash);
if (existing)
existing->push_back(chart);
else
m_chartDuplicates[chart->hash] = Vector<ChartIndex*>(1, chart);
}
else
{
m_chartsByHash.Add(chart->hash, chart);
}

}

void m_addScoreToCharts(ScoreIndex* score)
{
// Add difficulty to map and resort difficulties
auto diffIt = m_chartsByHash.find(score->chartHash);

// If for whatever reason the diff that the score is attatched to is not in the db, ignore the score.
if (diffIt == m_chartsByHash.end())
{
delete score;
return;
}

diffIt->second->scores.Add(score);
m_SortScores(diffIt->second);

// Check for duplicates of the same chart and copy the score to those
auto dups = m_chartDuplicates.Find(score->chartHash);
if (dups != nullptr)
{
for (auto chart : *dups) {
ScoreIndex* scoreCopy = new ScoreIndex(); // Must be new allocation
*scoreCopy = *score; // Copy data from score
chart->scores.Add(scoreCopy);
m_SortScores(chart);
}
}
}

void m_LoadInitialData()
{
assert(!m_searching);

m_chartsByHash.clear();
m_chartDuplicates.clear();

// Clear search state
m_searchState.difficulties.clear();

Expand Down Expand Up @@ -1644,7 +1734,7 @@ class MapDatabase_Impl

// Add existing diff
m_charts.Add(chart->id, chart);
m_chartsByHash.Add(chart->hash, chart);
m_addToChartsByHash(chart);

// Add difficulty to map and resort difficulties
auto folderIt = m_folders.find(chart->folderId);
Expand Down Expand Up @@ -1700,16 +1790,7 @@ class MapDatabase_Impl
score->mirror = scoreScan.IntColumn(20) == 1;
score->random = scoreScan.IntColumn(21) == 1;

// Add difficulty to map and resort difficulties
auto diffIt = m_chartsByHash.find(score->chartHash);
if (diffIt == m_chartsByHash.end()) // If for whatever reason the diff that the score is attatched to is not in the db, ignore the score.
{
delete score;
continue;
}

diffIt->second->scores.Add(score);
m_SortScores(diffIt->second);
m_addScoreToCharts(score);
}

// Select Practice setups
Expand Down
7 changes: 4 additions & 3 deletions Main/include/ScoreScreen.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,14 @@
#include "json.hpp"

class MultiplayerScreen;
class MapDatabase;

class ScoreScreen : public IAsyncLoadableApplicationTickable
{
public:
virtual ~ScoreScreen() = default;
static ScoreScreen* Create(class Game* game);
static ScoreScreen* Create(class Game* game, class ChallengeManager*);
static ScoreScreen* Create(class Game* game, MapDatabase*);
static ScoreScreen* Create(class Game* game, class ChallengeManager*, MapDatabase*);
static ScoreScreen* Create(class Game* game, String uid,
Vector<nlohmann::json> const*, MultiplayerScreen*);
Vector<nlohmann::json> const*, MultiplayerScreen*, MapDatabase*);
};
1 change: 1 addition & 0 deletions Main/src/ChallengeSelect.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1692,6 +1692,7 @@ bool ChallengeManager::m_setupNextChart()
Log("Failed to start game", Logger::Severity::Error);
return false;
}
game->SetSongDB(m_challengeSelect->GetMapDatabase());

if (m_currentOptions.gauge_carry_over.Get(false) && m_lastGauges.size() > 0)
{
Expand Down
14 changes: 9 additions & 5 deletions Main/src/Game.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1470,21 +1470,25 @@ class Game_Impl : public Game
}
else
{
assert(m_db != nullptr);
// Transition to score screen
if (IsMultiplayerGame())
{
g_transition->TransitionTo(ScoreScreen::Create(
ScoreScreen* scoreScreen = ScoreScreen::Create(
this, m_multiplayer->GetUserId(),
m_multiplayer->GetFinalStats(), m_multiplayer));
m_multiplayer->GetFinalStats(), m_multiplayer, m_db);
g_transition->TransitionTo(scoreScreen);
}
else if (m_challengeManager != nullptr)
{
g_transition->TransitionTo(ScoreScreen::Create(
this, m_challengeManager));
ScoreScreen* scoreScreen = ScoreScreen::Create(
this, m_challengeManager, m_db);
g_transition->TransitionTo(scoreScreen);
}
else
{
g_transition->TransitionTo(ScoreScreen::Create(this));
ScoreScreen* scoreScreen = ScoreScreen::Create(this, m_db);
g_transition->TransitionTo(scoreScreen);
}
m_transitioning = true;
}
Expand Down
2 changes: 2 additions & 0 deletions Main/src/MultiplayerScreen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -392,6 +392,8 @@ bool MultiplayerScreen::m_handleStartPacket(nlohmann::json& packet)
return 0;
}

game->SetSongDB(m_mapDatabase);

m_suspended = true;

// Switch to the new tickable
Expand Down
35 changes: 18 additions & 17 deletions Main/src/ScoreScreen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
class ScoreScreen_Impl : public ScoreScreen
{
private:
MapDatabase m_mapDatabase;
MapDatabase* m_mapDatabase = nullptr;
// Things for score screen
Graphics::Font m_specialFont;
Sample m_applause;
Expand Down Expand Up @@ -283,7 +283,10 @@ class ScoreScreen_Impl : public ScoreScreen
newScore->hitWindowMiss = m_hitWindow.miss;
newScore->hitWindowSlam = m_hitWindow.slam;

m_mapDatabase.AddScore(newScore);
// This adds the score to the chart
m_mapDatabase->AddScore(newScore);

assert(m_mapDatabase != nullptr);

if (g_gameConfig.GetString(GameConfigKeys::IRBaseURL) != "")
{
Expand Down Expand Up @@ -317,12 +320,6 @@ class ScoreScreen_Impl : public ScoreScreen
}
}

chart->scores.Add(newScore);
chart->scores.Sort([](ScoreIndex* a, ScoreIndex* b)
{
return a->score > b->score;
});

// Update chart song offset
bool updateSongOffset = false;
switch (g_gameConfig.GetEnum<Enum_SongOffsetUpdateMethod>(GameConfigKeys::UpdateSongOffsetAfterFirstPlay))
Expand Down Expand Up @@ -370,7 +367,7 @@ class ScoreScreen_Impl : public ScoreScreen
chart->custom_offset = oldOffset + m_medianHitDelta[0];

Logf("Updating song offset %d -> %d based on hitstat", Logger::Severity::Info, oldOffset, chart->custom_offset);
m_mapDatabase.UpdateChartOffset(chart);
m_mapDatabase->UpdateChartOffset(chart);
}
}

Expand Down Expand Up @@ -481,8 +478,9 @@ class ScoreScreen_Impl : public ScoreScreen
}

ScoreScreen_Impl(class Game* game, MultiplayerScreen* multiplayer,
String uid, Vector<nlohmann::json> const* multistats, ChallengeManager* manager)
String uid, Vector<nlohmann::json> const* multistats, ChallengeManager* manager, MapDatabase* db)
{
m_mapDatabase = db;
m_challengeManager = manager;
m_displayIndex = 0;
m_selfDisplayIndex = 0;
Expand Down Expand Up @@ -840,7 +838,7 @@ class ScoreScreen_Impl : public ScoreScreen
return false;

updateLuaData();
m_collDiag.Init(&m_mapDatabase);
m_collDiag.Init(m_mapDatabase);
g_input.OnButtonPressed.Add(this, &ScoreScreen_Impl::m_OnButtonPressed);

return true;
Expand Down Expand Up @@ -1078,22 +1076,25 @@ class ScoreScreen_Impl : public ScoreScreen
lua_settop(m_lua, 0);
}


};

ScoreScreen* ScoreScreen::Create(class Game* game)
ScoreScreen* ScoreScreen::Create(class Game* game, MapDatabase* db)
{
ScoreScreen_Impl* impl = new ScoreScreen_Impl(game, nullptr, "", nullptr, nullptr);
ScoreScreen_Impl* impl = new ScoreScreen_Impl(game, nullptr, "", nullptr, nullptr, db);
return impl;
}

ScoreScreen* ScoreScreen::Create(class Game* game, ChallengeManager* manager)
ScoreScreen* ScoreScreen::Create(class Game* game, ChallengeManager* manager, MapDatabase* db)
{
ScoreScreen_Impl* impl = new ScoreScreen_Impl(game, nullptr, "", nullptr, manager);
ScoreScreen_Impl* impl = new ScoreScreen_Impl(game, nullptr, "", nullptr, manager, db);
return impl;
}

ScoreScreen* ScoreScreen::Create(class Game* game, String uid, Vector<nlohmann::json> const* stats, MultiplayerScreen* multi)
ScoreScreen* ScoreScreen::Create(class Game* game, String uid, Vector<nlohmann::json> const* stats, MultiplayerScreen* multi, MapDatabase* db)
{
ScoreScreen_Impl* impl = new ScoreScreen_Impl(game, multi, uid, stats, nullptr);
ScoreScreen_Impl* impl = new ScoreScreen_Impl(game, multi, uid, stats, nullptr, db);
return impl;
}


1 change: 1 addition & 0 deletions Main/src/SongSelect.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1287,6 +1287,7 @@ class SongSelect_Impl : public SongSelect
Log("Failed to start game", Logger::Severity::Error);
return;
}
game->SetSongDB(m_mapDatabase);
game->GetScoring().autoplayInfo.autoplay = autoplay;

// Transition to game
Expand Down