Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
d986579
first 1.40.8 fixes
Qwasyx Nov 12, 2025
02e0ef2
Merge branch '1.37' of github.com:ScoreSaber/ScoreSaber-Quest into 1.37
Qwasyx Nov 12, 2025
93ccc4d
Merge branch '1.37'
Qwasyx Nov 12, 2025
9b3ee68
1.40 replays
Qwasyx Nov 12, 2025
1b570e8
fixed missing parameters
Qwasyx Nov 12, 2025
12a8b8d
fix scrubbing with hud off
Qwasyx Nov 12, 2025
5fc4756
implement metacore score submissions
Qwasyx Nov 12, 2025
583d398
revert back to bshook SafePtrs
Qwasyx Nov 12, 2025
c7837fa
switch from semver to custom built simple version class.
Qwasyx Nov 18, 2025
9d95511
pass logging params
Qwasyx Dec 16, 2025
9628e50
prevent BL from thinking our replays are actual plays
Qwasyx Dec 16, 2025
cf96bb5
Replay Fixes for 1.40
RileyDevS15 Dec 16, 2025
c3aedd8
fix instant replay with disabled score submission
Qwasyx Dec 16, 2025
e6801dd
Orig behaviour w fixes
RileyDevS15 Dec 16, 2025
7e83a80
fix includes and scoreplayer
RileyDevS15 Dec 16, 2025
1f9270b
Merge pull request #1 from ScoreSaber/1.40.8
speecil Dec 16, 2025
cd6ca19
fix combo checks and cutsound ctor
RileyDevS15 Dec 16, 2025
098d8cb
fix metacore note calculations
RileyDevS15 Dec 16, 2025
227a4f5
Merge pull request #24 from speecil/1.40.8
Qwasyx Dec 16, 2025
2332c27
fix energy after last energy event
Qwasyx Dec 16, 2025
fd7ffbb
fix combo calculation once more
RileyDevS15 Dec 17, 2025
606f9cb
Merge pull request #25 from speecil/1.40.8
Qwasyx Dec 17, 2025
0fb5d31
pin versions of everything to hopefully make CI/CD build again
Qwasyx Dec 18, 2025
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
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@ ndkpath.txt
*.txt
extern/
Android.mk.backup
qpm.shared.json
qpm_defines.cmake
extern.cmake
build/
Expand Down
5 changes: 5 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,17 @@ add_compile_definitions(MOD_ID=\"${MOD_ID}\")
RECURSE_FILES(cpp_file_list ${SOURCE_DIR}/*.cpp)
RECURSE_FILES(c_file_list ${SOURCE_DIR}/*.c)

RECURSE_FILES(inline_hook_c ${EXTERN_DIR}/includes/beatsaber-hook/shared/inline-hook/*.c)
RECURSE_FILES(inline_hook_cpp ${EXTERN_DIR}/includes/beatsaber-hook/shared/inline-hook/*.cpp)

# add all src files to compile
add_library(
${COMPILE_ID}
SHARED
${cpp_file_list}
${c_file_list}
${inline_hook_c}
${inline_hook_cpp}
)

# add src dir as include dir
Expand Down
51 changes: 24 additions & 27 deletions include/CustomTypes/Components/CellClicker.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,31 +14,28 @@

#include <functional>

#define INTERFACES \
{ \
classof(UnityEngine::EventSystems::IPointerClickHandler*), \
classof(UnityEngine::EventSystems::IPointerEnterHandler*), \
classof(UnityEngine::EventSystems::IPointerExitHandler*), \
classof(UnityEngine::EventSystems::IEventSystemHandler*) \
}
DECLARE_CLASS_CODEGEN_INTERFACES(
ScoreSaber::CustomTypes::Components,
CellClicker,
UnityEngine::MonoBehaviour,
UnityEngine::EventSystems::IPointerClickHandler*,
UnityEngine::EventSystems::IPointerEnterHandler*,
UnityEngine::EventSystems::IPointerExitHandler*,
UnityEngine::EventSystems::IEventSystemHandler*) {
DECLARE_DEFAULT_CTOR();
DECLARE_PRIVATE_METHOD(void, Start);
DECLARE_PRIVATE_METHOD(void, OnDestroy);
DECLARE_OVERRIDE_METHOD_MATCH(void, OnPointerClick, &UnityEngine::EventSystems::IPointerClickHandler::OnPointerClick, UnityEngine::EventSystems::PointerEventData* eventData);
DECLARE_OVERRIDE_METHOD_MATCH(void, OnPointerEnter, &UnityEngine::EventSystems::IPointerEnterHandler::OnPointerEnter, UnityEngine::EventSystems::PointerEventData* eventData);
DECLARE_OVERRIDE_METHOD_MATCH(void, OnPointerExit, &UnityEngine::EventSystems::IPointerExitHandler::OnPointerExit, UnityEngine::EventSystems::PointerEventData* eventData);
DECLARE_INSTANCE_FIELD(UnityW<HMUI::ImageView>, seperator);
DECLARE_INSTANCE_FIELD_PRIVATE(UnityEngine::Vector3, originalScale);
DECLARE_INSTANCE_FIELD_PRIVATE_DEFAULT(UnityEngine::Color, origColour, UnityEngine::Color(1, 1, 1, 1));
DECLARE_INSTANCE_FIELD_PRIVATE_DEFAULT(UnityEngine::Color, origColour0, UnityEngine::Color(1, 1, 1, 0.2509804f));
DECLARE_INSTANCE_FIELD_PRIVATE_DEFAULT(UnityEngine::Color, origColour1, UnityEngine::Color(1, 1, 1, 0));

___DECLARE_TYPE_WRAPPER_INHERITANCE(ScoreSaber::CustomTypes::Components, CellClicker, Il2CppTypeEnum::IL2CPP_TYPE_CLASS, UnityEngine::MonoBehaviour, "ScoreSaber::CustomTypes::Components", INTERFACES, 0, nullptr,
DECLARE_DEFAULT_CTOR();
DECLARE_PRIVATE_METHOD(void, Start);
DECLARE_PRIVATE_METHOD(void, OnDestroy);
DECLARE_OVERRIDE_METHOD_MATCH(void, OnPointerClick, &UnityEngine::EventSystems::IPointerClickHandler::OnPointerClick, UnityEngine::EventSystems::PointerEventData* eventData);
DECLARE_OVERRIDE_METHOD_MATCH(void, OnPointerEnter, &UnityEngine::EventSystems::IPointerEnterHandler::OnPointerEnter, UnityEngine::EventSystems::PointerEventData* eventData);
DECLARE_OVERRIDE_METHOD_MATCH(void, OnPointerExit, &UnityEngine::EventSystems::IPointerExitHandler::OnPointerExit, UnityEngine::EventSystems::PointerEventData* eventData);
DECLARE_INSTANCE_FIELD(UnityW<HMUI::ImageView>, seperator);
DECLARE_INSTANCE_FIELD_PRIVATE(UnityEngine::Vector3, originalScale);
DECLARE_INSTANCE_FIELD_PRIVATE_DEFAULT(UnityEngine::Color, origColour, UnityEngine::Color(1, 1, 1, 1));
DECLARE_INSTANCE_FIELD_PRIVATE_DEFAULT(UnityEngine::Color, origColour0, UnityEngine::Color(1, 1, 1, 0.2509804f));
DECLARE_INSTANCE_FIELD_PRIVATE_DEFAULT(UnityEngine::Color, origColour1, UnityEngine::Color(1, 1, 1, 0));

public:
int index;
std::function<void(int)> onClick;
bool isScaled = false;
)

#undef INTERFACES
public:
int index;
std::function<void(int)> onClick;
bool isScaled = false;
};
14 changes: 4 additions & 10 deletions include/CustomTypes/Components/GlobalLeaderboardTableCell.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
#include "CustomTypes/Components/GlobalLeaderboardTableData.hpp"
#include "Data/Player.hpp"
#include "UI/Other/PlayerProfileModal.hpp"

#include <HMUI/ImageView.hpp>
#include <HMUI/TableCell.hpp>
#include <HMUI/TableView.hpp>
Expand All @@ -14,11 +13,7 @@
#include <bsml/shared/BSML/Components/Backgroundable.hpp>
#include <custom-types/shared/macros.hpp>

#define GET_FIND_METHOD(mPtr) \
il2cpp_utils::il2cpp_type_check::MetadataGetter<mPtr>::get()

DECLARE_CLASS_CODEGEN(
ScoreSaber::CustomTypes::Components, GlobalLeaderboardTableCell, HMUI::TableCell,
DECLARE_CLASS_CODEGEN(ScoreSaber::CustomTypes::Components, GlobalLeaderboardTableCell, HMUI::TableCell) {
DECLARE_INSTANCE_FIELD(UnityW<TMPro::TextMeshProUGUI>, rank);
DECLARE_INSTANCE_FIELD(UnityW<TMPro::TextMeshProUGUI>, pp);
DECLARE_INSTANCE_FIELD(UnityW<TMPro::TextMeshProUGUI>, country);
Expand All @@ -33,12 +28,11 @@ DECLARE_CLASS_CODEGEN(

DECLARE_CTOR(ctor);

public
: std::string playerId;
public:
std::string playerId;
static GlobalLeaderboardTableCell * CreateCell();
void Refresh(ScoreSaber::Data::Player& player, ScoreSaber::CustomTypes::Components::GlobalLeaderboardTableData::LeaderboardType leaderboardType);
void stopProfileRoutine();
void stopFlagRoutine();
void OpenPlayerProfileModal();

)
};
24 changes: 9 additions & 15 deletions include/CustomTypes/Components/GlobalLeaderboardTableData.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,12 @@
#include <custom-types/shared/coroutine.hpp>
#include <custom-types/shared/macros.hpp>

#define GET_FIND_METHOD(mPtr) \
il2cpp_utils::il2cpp_type_check::MetadataGetter<mPtr>::get()

static std::vector<Il2CppClass*> GetInterfaces()
{
return {classof(HMUI::TableView::IDataSource*)};
}

___DECLARE_TYPE_WRAPPER_INHERITANCE(
ScoreSaber::CustomTypes::Components, GlobalLeaderboardTableData,
Il2CppTypeEnum::IL2CPP_TYPE_CLASS, UnityEngine::MonoBehaviour, "ScoreSaber",
GetInterfaces(), 0, nullptr,

DECLARE_CLASS_CODEGEN_INTERFACES(
ScoreSaber::CustomTypes::Components,
GlobalLeaderboardTableData,
UnityEngine::MonoBehaviour,
HMUI::TableView::IDataSource*) {
DECLARE_INSTANCE_FIELD(StringW, reuseIdentifier);
DECLARE_INSTANCE_FIELD(float, cellSize);
DECLARE_INSTANCE_FIELD(UnityW<HMUI::TableView>, tableView);
Expand All @@ -47,8 +41,7 @@ ___DECLARE_TYPE_WRAPPER_INHERITANCE(
int, NumberOfCells,
&HMUI::TableView::IDataSource::NumberOfCells);

public
:
public:

enum LeaderboardType{
Global,
Expand All @@ -60,4 +53,5 @@ ___DECLARE_TYPE_WRAPPER_INHERITANCE(
void set_LeaderboardType(LeaderboardType type);
std::string get_LeaderboardURL();
void StartRefresh();
custom_types::Helpers::Coroutine Refresh();)
custom_types::Helpers::Coroutine Refresh();
};
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,18 @@
#include "Data/Score.hpp"
#include <vector>

DECLARE_CLASS_CODEGEN(ScoreSaber::CustomTypes::Components, LeaderboardScoreInfoButtonHandler, UnityEngine::MonoBehaviour,
DECLARE_INSTANCE_FIELD(UnityW<ScoreSaber::UI::Other::ScoreInfoModal>, scoreInfoModal);
DECLARE_INSTANCE_FIELD(GlobalNamespace::BeatmapLevel*, beatmapLevel);
DECLARE_INSTANCE_FIELD(GlobalNamespace::BeatmapKey, beatmapKey);
DECLARE_CLASS_CODEGEN(ScoreSaber::CustomTypes::Components, LeaderboardScoreInfoButtonHandler, UnityEngine::MonoBehaviour) {
DECLARE_INSTANCE_FIELD(UnityW<ScoreSaber::UI::Other::ScoreInfoModal>, scoreInfoModal);
DECLARE_INSTANCE_FIELD(GlobalNamespace::BeatmapLevel*, beatmapLevel);
DECLARE_INSTANCE_FIELD(GlobalNamespace::BeatmapKey, beatmapKey);

public:
void Setup();
void set_scoreCollection(std::vector<ScoreSaber::Data::Score> scores, GlobalNamespace::BeatmapLevel* beatmapLevel, GlobalNamespace::BeatmapKey beatmapKey, int leaderboardId, int maxScore);
void ShowScoreInfoModal(int buttonIdx);
public:
void Setup();
void set_scoreCollection(std::vector<ScoreSaber::Data::Score> scores, GlobalNamespace::BeatmapLevel* beatmapLevel, GlobalNamespace::BeatmapKey beatmapKey, int leaderboardId, int maxScore);
void ShowScoreInfoModal(int buttonIdx);

private:
int leaderboardId;
int maxScore;
std::vector<ScoreSaber::Data::Score> scores;

)
private:
int leaderboardId;
int maxScore;
std::vector<ScoreSaber::Data::Score> scores;
};
23 changes: 20 additions & 3 deletions include/Data/Private/ReplayFile.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
#include <UnityEngine/Quaternion.hpp>
#include <UnityEngine/Vector3.hpp>

#include "Utils/Versions.hpp"

using namespace std;

namespace ScoreSaber::Data::Private
Expand Down Expand Up @@ -84,6 +86,16 @@ namespace ScoreSaber::Data::Private
Bomb
};

enum ScoringType_pre1_40 {
Ignore = -1,
NoScore,
Normal,
SliderHead,
SliderTail,
BurstSliderHead,
BurstSliderElement
};

struct NoteID
{
NoteID();
Expand All @@ -97,6 +109,8 @@ namespace ScoreSaber::Data::Private
std::optional<int> GameplayType;
std::optional<int> ScoringType;
std::optional<float> CutDirectionAngleOffset;

bool MatchesScoringType(GlobalNamespace::NoteData_ScoringType comparedScoringType, optional<version> gameVersion) const;
};

struct EnergyEvent
Expand Down Expand Up @@ -138,9 +152,9 @@ namespace ScoreSaber::Data::Private
struct Metadata
{
Metadata();
Metadata(string Version, string LevelID, int Difficulty, string Characteristic, string Environment, vector<string> Modifiers, float NoteSpawnOffset,
bool LeftHanded, float InitialHeight, float RoomRotation, VRPosition RoomCenter, float FailTime);
string Version;
Metadata(version Version, string LevelID, int Difficulty, string Characteristic, string Environment, vector<string> Modifiers, float NoteSpawnOffset,
bool LeftHanded, float InitialHeight, float RoomRotation, VRPosition RoomCenter, float FailTime, optional<version> GameVersion, optional<version> PluginVersion, optional<string> Platform);
version Version;
string LevelID;
int Difficulty;
string Characteristic;
Expand All @@ -152,6 +166,9 @@ namespace ScoreSaber::Data::Private
float RoomRotation;
VRPosition RoomCenter;
float FailTime;
optional<version> GameVersion;
optional<version> PluginVersion;
optional<string> Platform;
};

struct NoteEvent
Expand Down
2 changes: 1 addition & 1 deletion include/Data/Private/ScoreSaberUploadData.hpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#pragma once
#include "Utils/StringUtils.hpp"
#include <beatsaber-hook/shared/config/rapidjson-utils.hpp>
#include "paper/shared/string_convert.hpp"
#include <paper2_scotland2/shared/string_convert.hpp>

#include <iostream>
#include <string>
Expand Down
7 changes: 4 additions & 3 deletions include/MainInstaller.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include <custom-types/shared/macros.hpp>
#include <lapiz/shared/macros.hpp>

DECLARE_CLASS_CODEGEN(ScoreSaber, MainInstaller, ::Zenject::Installer,
DECLARE_OVERRIDE_METHOD_MATCH(void, InstallBindings, &::Zenject::Installer::InstallBindings);
DECLARE_DEFAULT_CTOR();)
DECLARE_CLASS_CODEGEN(ScoreSaber, MainInstaller, ::Zenject::Installer) {
DECLARE_OVERRIDE_METHOD_MATCH(void, InstallBindings, &::Zenject::Installer::InstallBindings);
DECLARE_DEFAULT_CTOR();
};
7 changes: 4 additions & 3 deletions include/ReplaySystem/Installers/ImberInstaller.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include <custom-types/shared/macros.hpp>
#include <lapiz/shared/macros.hpp>

DECLARE_CLASS_CODEGEN(ScoreSaber::ReplaySystem::Installers, ImberInstaller, ::Zenject::Installer,
DECLARE_OVERRIDE_METHOD_MATCH(void, InstallBindings, &::Zenject::Installer::InstallBindings);
DECLARE_DEFAULT_CTOR();)
DECLARE_CLASS_CODEGEN(ScoreSaber::ReplaySystem::Installers, ImberInstaller, ::Zenject::Installer) {
DECLARE_OVERRIDE_METHOD_MATCH(void, InstallBindings, &::Zenject::Installer::InstallBindings);
DECLARE_DEFAULT_CTOR();
};
9 changes: 5 additions & 4 deletions include/ReplaySystem/Installers/PlaybackInstaller.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
#include <custom-types/shared/macros.hpp>
#include <lapiz/shared/macros.hpp>

DECLARE_CLASS_CODEGEN(ScoreSaber::ReplaySystem::Installers, PlaybackInstaller, ::Zenject::Installer,
DECLARE_INSTANCE_FIELD_PRIVATE(GlobalNamespace::GameplayCoreSceneSetupData*, _gameplayCoreSceneSetupData);
DECLARE_OVERRIDE_METHOD_MATCH(void, InstallBindings, &::Zenject::Installer::InstallBindings);
DECLARE_CTOR(ctor, GlobalNamespace::GameplayCoreSceneSetupData* gameplayCoreSceneSetupData);)
DECLARE_CLASS_CODEGEN(ScoreSaber::ReplaySystem::Installers, PlaybackInstaller, ::Zenject::Installer) {
DECLARE_INSTANCE_FIELD_PRIVATE(GlobalNamespace::GameplayCoreSceneSetupData*, _gameplayCoreSceneSetupData);
DECLARE_OVERRIDE_METHOD_MATCH(void, InstallBindings, &::Zenject::Installer::InstallBindings);
DECLARE_CTOR(ctor, GlobalNamespace::GameplayCoreSceneSetupData* gameplayCoreSceneSetupData);
};
7 changes: 4 additions & 3 deletions include/ReplaySystem/Installers/RecordInstaller.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include <custom-types/shared/macros.hpp>
#include <lapiz/shared/macros.hpp>

DECLARE_CLASS_CODEGEN(ScoreSaber::ReplaySystem::Installers, RecordInstaller, ::Zenject::Installer,
DECLARE_OVERRIDE_METHOD_MATCH(void, InstallBindings, &::Zenject::Installer::InstallBindings);
DECLARE_DEFAULT_CTOR();)
DECLARE_CLASS_CODEGEN(ScoreSaber::ReplaySystem::Installers, RecordInstaller, ::Zenject::Installer) {
DECLARE_OVERRIDE_METHOD_MATCH(void, InstallBindings, &::Zenject::Installer::InstallBindings);
DECLARE_DEFAULT_CTOR();
};
6 changes: 3 additions & 3 deletions include/ReplaySystem/Playback/ComboPlayer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@
#include <custom-types/shared/macros.hpp>
#include <lapiz/shared/macros.hpp>

DECLARE_CLASS_CODEGEN(
ScoreSaber::ReplaySystem::Playback, ComboPlayer, Il2CppObject,
DECLARE_CLASS_CODEGEN(ScoreSaber::ReplaySystem::Playback, ComboPlayer, Il2CppObject) {
DECLARE_INSTANCE_FIELD_PRIVATE(UnityW<GlobalNamespace::AudioTimeSyncController>, _audioTimeSyncController);
DECLARE_INSTANCE_FIELD_PRIVATE(UnityW<GlobalNamespace::ComboController>, _comboController);
DECLARE_INSTANCE_FIELD_PRIVATE(UnityW<GlobalNamespace::ComboUIController>, _comboUIController);
DECLARE_CTOR(ctor, GlobalNamespace::AudioTimeSyncController* audioTimeSyncController, GlobalNamespace::ComboController* comboController);
DECLARE_INSTANCE_METHOD(void, TimeUpdate, float songTime);
vector<Data::Private::NoteEvent> _sortedNoteEvents;
vector<Data::Private::ComboEvent> _sortedComboEvents;
void UpdateCombo(float time, int combo);)
void UpdateCombo(float time, int combo);
};
12 changes: 6 additions & 6 deletions include/ReplaySystem/Playback/EnergyPlayer.hpp
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
#pragma once

#include "Data/Private/ReplayFile.hpp"
#include <GlobalNamespace/AudioTimeSyncController.hpp>
#include <GlobalNamespace/GameEnergyCounter.hpp>
#include <GlobalNamespace/GameEnergyUIPanel.hpp>
#include <GlobalNamespace/PlayerDataModel.hpp>
#include <Zenject/DiContainer.hpp>
#include <custom-types/shared/macros.hpp>
#include <lapiz/shared/macros.hpp>

DECLARE_CLASS_CODEGEN(
ScoreSaber::ReplaySystem::Playback, EnergyPlayer, Il2CppObject,
DECLARE_INSTANCE_FIELD_PRIVATE(UnityW<GlobalNamespace::AudioTimeSyncController>, _audioTimeSyncController);
DECLARE_CLASS_CODEGEN(ScoreSaber::ReplaySystem::Playback, EnergyPlayer, Il2CppObject) {
DECLARE_INSTANCE_FIELD_PRIVATE(UnityW<GlobalNamespace::GameEnergyCounter>, _gameEnergyCounter);
DECLARE_INSTANCE_FIELD_PRIVATE(UnityW<GlobalNamespace::GameEnergyUIPanel>, _gameEnergyUIPanel);
DECLARE_CTOR(ctor, GlobalNamespace::AudioTimeSyncController* audioTimeSyncController, GlobalNamespace::GameEnergyCounter* gameEnergyCounter, Zenject::DiContainer* container);
DECLARE_INSTANCE_FIELD_PRIVATE(UnityW<GlobalNamespace::PlayerDataModel>, _playerDataModel);
DECLARE_CTOR(ctor, GlobalNamespace::GameEnergyCounter* gameEnergyCounter, GlobalNamespace::PlayerDataModel* playerDataModel, Zenject::DiContainer* container);
DECLARE_INSTANCE_METHOD(void, TimeUpdate, float songTime);
vector<Data::Private::EnergyEvent> _sortedEnergyEvents;
void UpdateEnergy(float energy);)
void UpdateEnergy(float energy);
};
Loading
Loading