Skip to content

Commit

Permalink
Clean up reordering logic
Browse files Browse the repository at this point in the history
no longer reallocates BPM data 6 times 👍
  • Loading branch information
rcelyte committed Apr 28, 2023
1 parent 3b77535 commit 070d77c
Show file tree
Hide file tree
Showing 4 changed files with 159 additions and 140 deletions.
4 changes: 2 additions & 2 deletions makefile
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ $(OBJDIR)/%.cpp.o: %.cpp extern makefile | ndk
\"name\": \"Mapping Extensions\",\n\
\"id\": \"MappingExtensions\",\n\
\"author\": \"StackDoubleFlow, rxzz0, rcelyte\",\n\
\"version\": \"0.22.3\",\n\
\"version\": \"0.22.4\",\n\
\"packageId\": \"com.beatgames.beatsaber\",\n\
\"packageVersion\": \"1.28.0_4124311467\",\n\
\"description\": \"This adds a host of new things you can do with your maps as a mapper, and allows you to play said maps as a player. An update of the port of the PC original mod by Kyle 1413. Previously maintained by zoller27osu.\",\n\
Expand All @@ -47,7 +47,7 @@ $(OBJDIR)/%.cpp.o: %.cpp extern makefile | ndk
\"id\": \"codegen\",\n\
\"downloadIfMissing\": \"https://github.com/sc2ad/BeatSaber-Quest-Codegen/releases/download/v0.33.0/Codegen.qmod\"\n\
}, {\n\
\"version\": \"1.8.9\",\n\
\"version\": \"^1.8.9\",\n\
\"id\": \"pinkcore\",\n\
\"downloadIfMissing\": \"https://github.com/BSMGPink/PinkCore/releases/download/v1.8.9/PinkCore.qmod\"\n\
}\n\
Expand Down
2 changes: 1 addition & 1 deletion qpm.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"info": {
"name": "MappingExtensions",
"id": "MappingExtensions",
"version": "0.22.3",
"version": "0.22.4",
"url": null,
"additionalData": {}
},
Expand Down
272 changes: 145 additions & 127 deletions src/conversions.hpp
Original file line number Diff line number Diff line change
@@ -1,27 +1,30 @@
#pragma once
#include <BeatmapSaveDataVersion3/BeatmapSaveData_BpmChangeEventData.hpp>

template<class SaveData> struct Linematch;
struct BpmChangeData {
float time, beat, bpm;
};

struct BpmState {
struct BpmChangeData {
float time, beat, bpm;
};
static inline std::vector<BpmChangeData> ConvertBpmChanges(float startBpm, System::Collections::Generic::List_1<BeatmapSaveDataVersion3::BeatmapSaveData::BpmChangeEventData*> *events) {
const uint32_t count = events->get_Count();
bool skipFirst = (count > 0 && events->get_Item(0)->get_beat() == 0);
std::vector<BpmChangeData> changes;
uint32_t current = 0;
BpmState(float startBpm, System::Collections::Generic::List_1<BeatmapSaveDataVersion3::BeatmapSaveData::BpmChangeEventData*> *events) {
const uint32_t count = events->get_Count();
bool skipFirst = (count > 0 && events->get_Item(0)->get_beat() == 0);
changes.reserve(count + !skipFirst);
BpmChangeData lastEntry = {0, 0, skipFirst ? events->get_Item(0)->get_bpm() : startBpm};
changes.reserve(count + !skipFirst);
BpmChangeData lastEntry = {0, 0, skipFirst ? events->get_Item(0)->get_bpm() : startBpm};
changes.push_back(lastEntry);
for(uint32_t i = skipFirst; i < count; i++) {
BeatmapSaveDataVersion3::BeatmapSaveData::BpmChangeEventData *event = events->get_Item(i);
const float beat = event->get_beat();
lastEntry = {lastEntry.time + (beat - lastEntry.beat) / lastEntry.bpm * 60, beat, event->get_bpm()};
changes.push_back(lastEntry);
for(uint32_t i = skipFirst; i < count; i++) {
BeatmapSaveDataVersion3::BeatmapSaveData::BpmChangeEventData *event = events->get_Item(i);
const float beat = event->get_beat();
lastEntry = {lastEntry.time + (beat - lastEntry.beat) / lastEntry.bpm * 60, beat, event->get_bpm()};
changes.push_back(lastEntry);
}
}
return changes;
}

struct BpmState {
std::basic_string_view<BpmChangeData> changes;
uint32_t current = 0;
BpmState(std::basic_string_view<BpmChangeData> changes) : changes(changes) {}
float GetTime(float beat) {
while(current > 0 && changes[current].beat >= beat)
--current;
Expand All @@ -39,56 +42,70 @@ static inline GlobalNamespace::ColorType ConvertColorType(BeatmapSaveDataVersion
}
}

template<> struct Linematch<BeatmapSaveDataVersion3::BeatmapSaveData::ColorNoteData> {
float time;
int32_t lineIndex;
GlobalNamespace::ColorType colorType;
GlobalNamespace::NoteCutDirection cutDirection;
float cutDirectionAngleOffset;
Linematch(GlobalNamespace::NoteData *from) :
time(from->get_time()),
lineIndex(from->get_lineIndex()),
colorType(from->get_colorType()),
cutDirection(from->get_cutDirection()),
cutDirectionAngleOffset(from->get_cutDirectionAngleOffset()) {}
Linematch(BeatmapSaveDataVersion3::BeatmapSaveData::ColorNoteData *from, BpmState *bpmState) :
time(bpmState->GetTime(from->get_beat())),
lineIndex(from->get_line()),
colorType(ConvertColorType(from->get_color())),
cutDirection(from->get_cutDirection()),
cutDirectionAngleOffset(from->get_angleOffset()) {}
template<class SaveData> struct RestoreBlob;

template<> struct RestoreBlob<BeatmapSaveDataVersion3::BeatmapSaveData::ColorNoteData> {
struct Ident {
float time;
int32_t lineIndex;
GlobalNamespace::ColorType colorType;
GlobalNamespace::NoteCutDirection cutDirection;
float cutDirectionAngleOffset;
Ident(GlobalNamespace::NoteData *from) :
time(from->get_time()),
lineIndex(from->get_lineIndex()),
colorType(from->get_colorType()),
cutDirection(from->get_cutDirection()),
cutDirectionAngleOffset(from->get_cutDirectionAngleOffset()) {}
Ident(BeatmapSaveDataVersion3::BeatmapSaveData::ColorNoteData *from, BpmState *bpmState) :
time(bpmState->GetTime(from->get_beat())),
lineIndex(from->get_line()),
colorType(ConvertColorType(from->get_color())),
cutDirection(from->get_cutDirection()),
cutDirectionAngleOffset(from->get_angleOffset()) {}
} ident;
int32_t layer;
RestoreBlob(BeatmapSaveDataVersion3::BeatmapSaveData::ColorNoteData *from, BpmState *bpmState) : ident(from, bpmState), layer(from->get_layer()) {}
};

template<> struct Linematch<BeatmapSaveDataVersion3::BeatmapSaveData::BombNoteData> {
float time;
int32_t lineIndex;
Linematch(GlobalNamespace::NoteData *from) :
time(from->get_time()),
lineIndex(from->get_lineIndex()) {}
Linematch(BeatmapSaveDataVersion3::BeatmapSaveData::BombNoteData *from, BpmState *bpmState) :
time(bpmState->GetTime(from->get_beat())),
lineIndex(from->get_line()) {}
template<> struct RestoreBlob<BeatmapSaveDataVersion3::BeatmapSaveData::BombNoteData> {
struct Ident {
float time;
int32_t lineIndex;
Ident(GlobalNamespace::NoteData *from) :
time(from->get_time()),
lineIndex(from->get_lineIndex()) {}
Ident(BeatmapSaveDataVersion3::BeatmapSaveData::BombNoteData *from, BpmState *bpmState) :
time(bpmState->GetTime(from->get_beat())),
lineIndex(from->get_line()) {}
} ident;
int32_t layer;
RestoreBlob(BeatmapSaveDataVersion3::BeatmapSaveData::BombNoteData *from, BpmState *bpmState) : ident(from, bpmState), layer(from->get_layer()) {}
};


template<> struct Linematch<BeatmapSaveDataVersion3::BeatmapSaveData::ObstacleData> {
float time;
int32_t lineIndex;
float duration;
int32_t width;
int32_t height;
Linematch(GlobalNamespace::ObstacleData *from) :
time(from->get_time()),
lineIndex(from->get_lineIndex()),
duration(from->get_duration()),
width(from->get_width()),
height(from->get_height()) {}
Linematch(BeatmapSaveDataVersion3::BeatmapSaveData::ObstacleData *from, BpmState *bpmState) :
time(bpmState->GetTime(from->get_beat())),
lineIndex(from->get_line()),
duration(bpmState->GetTime(from->get_beat() + from->get_duration()) - time),
width(from->get_width()),
height(from->get_height()) {}
template<> struct RestoreBlob<BeatmapSaveDataVersion3::BeatmapSaveData::ObstacleData> {
struct Ident {
float time;
int32_t lineIndex;
float duration;
int32_t width;
int32_t height;
Ident(GlobalNamespace::ObstacleData *from) :
time(from->get_time()),
lineIndex(from->get_lineIndex()),
duration(from->get_duration()),
width(from->get_width()),
height(from->get_height()) {}
Ident(BeatmapSaveDataVersion3::BeatmapSaveData::ObstacleData *from, BpmState *bpmState) :
time(bpmState->GetTime(from->get_beat())),
lineIndex(from->get_line()),
duration(bpmState->GetTime(from->get_beat() + from->get_duration()) - time),
width(from->get_width()),
height(from->get_height()) {}
} ident;
int32_t layer;
RestoreBlob(BeatmapSaveDataVersion3::BeatmapSaveData::ObstacleData *from, BpmState *bpmState) : ident(from, bpmState), layer(from->get_layer()) {}
};

struct SliderLinematch {
Expand All @@ -114,87 +131,88 @@ struct SliderLinematch {
tailLineIndex(from->get_tailLine()) {}
};

template<> struct Linematch<BeatmapSaveDataVersion3::BeatmapSaveData::SliderData> {
SliderLinematch base;
GlobalNamespace::NoteCutDirection tailCutDirection;
GlobalNamespace::SliderMidAnchorMode midAnchorMode;
float headControlPointLengthMultiplier;
float tailControlPointLengthMultiplier;
Linematch(GlobalNamespace::SliderData *from) :
base(from),
tailCutDirection(from->get_tailCutDirection()),
midAnchorMode(from->get_midAnchorMode()),
headControlPointLengthMultiplier(from->get_headControlPointLengthMultiplier()),
tailControlPointLengthMultiplier(from->get_tailControlPointLengthMultiplier()) {}
Linematch(BeatmapSaveDataVersion3::BeatmapSaveData::SliderData *from, BpmState *bpmState) :
base(from, bpmState),
tailCutDirection(from->get_tailCutDirection()),
midAnchorMode(from->get_sliderMidAnchorMode()),
headControlPointLengthMultiplier(from->get_headControlPointLengthMultiplier()),
tailControlPointLengthMultiplier(from->get_tailControlPointLengthMultiplier()) {}
template<> struct RestoreBlob<BeatmapSaveDataVersion3::BeatmapSaveData::SliderData> {
struct Ident {
SliderLinematch base;
GlobalNamespace::NoteCutDirection tailCutDirection;
GlobalNamespace::SliderMidAnchorMode midAnchorMode;
float headControlPointLengthMultiplier;
float tailControlPointLengthMultiplier;
Ident(GlobalNamespace::SliderData *from) :
base(from),
tailCutDirection(from->get_tailCutDirection()),
midAnchorMode(from->get_midAnchorMode()),
headControlPointLengthMultiplier(from->get_headControlPointLengthMultiplier()),
tailControlPointLengthMultiplier(from->get_tailControlPointLengthMultiplier()) {}
Ident(BeatmapSaveDataVersion3::BeatmapSaveData::SliderData *from, BpmState *bpmState) :
base(from, bpmState),
tailCutDirection(from->get_tailCutDirection()),
midAnchorMode(from->get_sliderMidAnchorMode()),
headControlPointLengthMultiplier(from->get_headControlPointLengthMultiplier()),
tailControlPointLengthMultiplier(from->get_tailControlPointLengthMultiplier()) {}
} ident;
std::array<int32_t, 2> layer;
RestoreBlob(BeatmapSaveDataVersion3::BeatmapSaveData::SliderData *from, BpmState *bpmState) : ident(from, bpmState), layer({from->get_headLayer(), from->get_tailLayer()}) {}
};

template<> struct Linematch<BeatmapSaveDataVersion3::BeatmapSaveData::BurstSliderData> {
SliderLinematch base;
int32_t sliceCount;
float squishAmount;
Linematch(GlobalNamespace::SliderData *from) :
base(from),
sliceCount(from->get_sliceCount()),
squishAmount(from->get_squishAmount()) {}
Linematch(BeatmapSaveDataVersion3::BeatmapSaveData::BurstSliderData *from, BpmState *bpmState) :
base(from, bpmState),
sliceCount(from->get_sliceCount()),
squishAmount(from->get_squishAmount()) {}
template<> struct RestoreBlob<BeatmapSaveDataVersion3::BeatmapSaveData::BurstSliderData> {
struct Ident {
SliderLinematch base;
int32_t sliceCount;
float squishAmount;
Ident(GlobalNamespace::SliderData *from) :
base(from),
sliceCount(from->get_sliceCount()),
squishAmount(from->get_squishAmount()) {}
Ident(BeatmapSaveDataVersion3::BeatmapSaveData::BurstSliderData *from, BpmState *bpmState) :
base(from, bpmState),
sliceCount(from->get_sliceCount()),
squishAmount(from->get_squishAmount()) {}
} ident;
std::array<int32_t, 2> layer;
RestoreBlob(BeatmapSaveDataVersion3::BeatmapSaveData::BurstSliderData *from, BpmState *bpmState) : ident(from, bpmState), layer({from->get_headLayer(), from->get_tailLayer()}) {}
};

template<> struct Linematch<BeatmapSaveDataVersion3::BeatmapSaveData::WaypointData> {
float time;
int32_t lineIndex;
GlobalNamespace::OffsetDirection offsetDirection;
Linematch(GlobalNamespace::WaypointData *from) :
time(from->get_time()),
lineIndex(from->get_lineIndex()),
offsetDirection(from->get_offsetDirection()) {}
Linematch(BeatmapSaveDataVersion3::BeatmapSaveData::WaypointData *from, BpmState *bpmState) :
time(bpmState->GetTime(from->get_beat())),
lineIndex(from->get_line()),
offsetDirection(from->get_offsetDirection()) {}
template<> struct RestoreBlob<BeatmapSaveDataVersion3::BeatmapSaveData::WaypointData> {
struct Ident {
float time;
int32_t lineIndex;
GlobalNamespace::OffsetDirection offsetDirection;
Ident(GlobalNamespace::WaypointData *from) :
time(from->get_time()),
lineIndex(from->get_lineIndex()),
offsetDirection(from->get_offsetDirection()) {}
Ident(BeatmapSaveDataVersion3::BeatmapSaveData::WaypointData *from, BpmState *bpmState) :
time(bpmState->GetTime(from->get_beat())),
lineIndex(from->get_line()),
offsetDirection(from->get_offsetDirection()) {}
} ident;
int32_t layer;
RestoreBlob(BeatmapSaveDataVersion3::BeatmapSaveData::WaypointData *from, BpmState *bpmState) : ident(from, bpmState), layer(from->get_layer()) {}
};

std::array<int32_t, 1> GetLineLayers(BeatmapSaveDataVersion3::BeatmapSaveData::BombNoteData *saveData) {return {saveData->get_layer()};}
std::array<int32_t, 1> GetLineLayers(BeatmapSaveDataVersion3::BeatmapSaveData::ColorNoteData *saveData) {return {saveData->get_layer()};}
std::array<int32_t, 1> GetLineLayers(BeatmapSaveDataVersion3::BeatmapSaveData::ObstacleData *saveData) {return {saveData->get_layer()};}
std::array<int32_t, 1> GetLineLayers(BeatmapSaveDataVersion3::BeatmapSaveData::WaypointData *saveData) {return {saveData->get_layer()};}
std::array<int32_t, 2> GetLineLayers(BeatmapSaveDataVersion3::BeatmapSaveData::BaseSliderData *saveData) {return {saveData->get_headLayer(), saveData->get_tailLayer()};}

template<class SaveData, std::size_t layerCount = 1>
template<class SaveData>
struct LayerCache {
struct Entry {
Linematch<SaveData> match;
std::array<int32_t, layerCount> layers;
};
std::vector<Entry> cache;
std::vector<RestoreBlob<SaveData>> cache;
std::vector<bool> matched;
size_t head = 0, failCount = 0;
LayerCache(System::Collections::Generic::List_1<SaveData*> *list, float startBpm, System::Collections::Generic::List_1<BeatmapSaveDataVersion3::BeatmapSaveData::BpmChangeEventData*> *bpmEvents) : matched(list->get_Count()) {
BpmState bpmState(startBpm, bpmEvents);
LayerCache(System::Collections::Generic::List_1<SaveData*> *list, const std::vector<BpmChangeData> *changes) : matched(list->get_Count()) {
BpmState bpmState(std::basic_string_view<BpmChangeData>(&(*changes)[0], changes->size()));
cache.reserve(matched.size());
for(size_t i = 0; i < matched.size(); ++i) {
SaveData *entry = list->get_Item(i);
cache.push_back({Linematch<SaveData>(entry, &bpmState), GetLineLayers(entry)});
}
for(size_t i = 0; i < matched.size(); ++i)
cache.emplace_back(list->get_Item(i), &bpmState);
}
template<class BeatmapData> std::array<int32_t, layerCount> restore(BeatmapData *data) {
const Linematch<SaveData> match(data);
std::array<int32_t, layerCount> res = {};
using LayerType = decltype(RestoreBlob<SaveData>::layer);
template<class BeatmapData> LayerType restore(BeatmapData *data) {
const typename RestoreBlob<SaveData>::Ident match(data);
LayerType res = {};
size_t i = head;
for(; i < cache.size(); ++i) {
if(matched[i])
continue;
if(memcmp(&match, &cache[i].match, sizeof(match)))
if(memcmp(&match, &cache[i].ident, sizeof(match)))
continue;
res = cache[i].layers;
res = cache[i].layer;
matched[i] = true;
break;
}
Expand Down
Loading

0 comments on commit 070d77c

Please sign in to comment.