Skip to content

Commit

Permalink
allow loading raw online timestamp replays
Browse files Browse the repository at this point in the history
for converting online-only replays back to normal
  • Loading branch information
poco0317 committed Sep 30, 2023
1 parent 394a045 commit 3cb489d
Show file tree
Hide file tree
Showing 3 changed files with 124 additions and 3 deletions.
116 changes: 114 additions & 2 deletions src/Etterna/Models/HighScore/Replay.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
#include "Etterna/Singletons/ScoreManager.h"
#include "Etterna/Singletons/SongManager.h"

#include "rapidjson/document.h"

// STL
#include <algorithm>
#include <cmath>
Expand Down Expand Up @@ -99,7 +101,7 @@ auto
Replay::HasWrittenReplayData() -> bool
{
return DoesFileExist(GetInputPath()) || DoesFileExist(GetFullPath()) ||
DoesFileExist(GetBasicPath());
DoesFileExist(GetBasicPath()) || DoesFileExist(GetOnlinePath());
}

auto
Expand Down Expand Up @@ -306,7 +308,7 @@ auto
Replay::LoadReplayData() -> bool
{
return LoadReplayDataFull() || LoadReplayDataBasic() ||
LoadStoredOnlineData();
LoadStoredOnlineData() || LoadOnlineDataFromDisk();
}

auto
Expand Down Expand Up @@ -997,6 +999,116 @@ Replay::LoadReplayDataFull(const std::string& replayDir) -> bool
return true;
}

auto
Replay::LoadOnlineDataFromDisk(const std::string& replayDir) -> bool
{
if (vNoteRowVector.size() > 4 && vOffsetVector.size() > 4 &&
vTrackVector.size() > 4) {
return true;
}

std::vector<float> timestamps;
std::vector<float> offsets;
std::vector<int> tracks;
std::vector<int> rows;
std::vector<TapNoteType> types;
const auto path = replayDir + scoreKey;

std::ifstream fileStream(path, std::ios::binary);
std::string line;
std::string buffer;
std::vector<std::string> tokens;
int noteRow = 0;
float offset = 0.f;
int track = 0;
TapNoteType tnt = TapNoteType_Invalid;
int tmp = 0;

// check file
if (!fileStream) {
return false;
}

rapidjson::Document d;
try {
std::stringstream buffer;
buffer << fileStream.rdbuf();
fileStream.close();

if (d.Parse(buffer.str().c_str()).HasParseError()) {
Locator::getLogger()->error("Malformed online replay data {}",
path);
return false;
}

if (!d.IsArray()) {
Locator::getLogger()->error(
"Online replay data {} was not an array as expected - skipped",
path);
return false;
}

for (auto& note : d.GetArray()) {
if (!note.IsArray() || note.Size() < 2 || !note[0].IsNumber() ||
!note[1].IsNumber())
continue;

timestamps.push_back(note[0].GetFloat());
// horrid temp hack --
// EO keeps misses as 180ms bads for not a great reason
// convert them back to misses here
auto offset = note[1].GetFloat() / 1000.F;
if (offset == .18F)
offset = 1.F;
offsets.push_back(offset);
if (note.Size() == 3 && note[2].IsInt()) { // pre-0.6 with noterows
rows.push_back(note[2].GetInt());
}
if (note.Size() > 3 && note[2].IsInt() &&
note[3].IsInt()) { // 0.6 without noterows
tracks.push_back(note[2].GetInt());
types.push_back(static_cast<TapNoteType>(note[3].GetInt()));
}
if (note.Size() == 5 && note[4].IsInt()) { // 0.6 with noterows
rows.push_back(note[4].GetInt());
}
}
}
catch (std::exception& e) {
Locator::getLogger()->error(
"Caught exception while reading online replay data {}: {}",
path,
e.what());
return false;
}

SetNoteRowVector(rows);
SetOffsetVector(offsets);
SetTrackVector(tracks);
SetTapNoteTypeVector(types);
SetOnlineReplayTimestampVector(timestamps);

Locator::getLogger()->info(
"Loaded online replay data {} - attempting to save as local replay",
path);
if (!GenerateNoterowsFromTimestamps()) {
Locator::getLogger()->warn("Found old online replay data format for "
"score {}, but could not load noterow data",
scoreKey);
return false;
}

if (!WriteReplayData()) {
Locator::getLogger()->error(
"Failed to save converted online replay data from {}", path);
return false;
}

Locator::getLogger()->info("Converted online replay data for score {}",
scoreKey);
return true;
}

auto
Replay::FillInBlanksForInputData() -> bool
{
Expand Down
8 changes: 7 additions & 1 deletion src/Etterna/Models/HighScore/Replay.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,11 @@ class Replay
return INPUT_DATA_DIR + scoreKey;
}

inline auto GetOnlinePath() const -> const std::string
{
return ONLINE_DATA_DIR + scoreKey;
}

auto GetOffsetVector() const -> const std::vector<float>&
{
return vOffsetVector;
Expand Down Expand Up @@ -407,7 +412,8 @@ class Replay
auto LoadReplayDataFull(const std::string& replayDir = FULL_REPLAY_DIR)
-> bool;
auto LoadInputData(const std::string& replayDir = INPUT_DATA_DIR) -> bool;

auto LoadOnlineDataFromDisk(const std::string& replayDir = ONLINE_DATA_DIR)
-> bool;
auto LoadStoredOnlineData() -> bool;

/// For V1 or earlier replays lacking column data, we need to assume
Expand Down
3 changes: 3 additions & 0 deletions src/Etterna/Models/HighScore/ReplayConstantsAndTypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ const std::string FULL_REPLAY_DIR = "Save/ReplaysV2/";
// contains input data files corresponding to replays
const std::string INPUT_DATA_DIR = "Save/InputData/";

// contains replays to be imported from online
const std::string ONLINE_DATA_DIR = "Save/OnlineReplays/";

const std::string NO_MODS = "none";

/// enum values defined by Replay.GetReplayType()
Expand Down

0 comments on commit 3cb489d

Please sign in to comment.