diff --git a/engine/source/autosplitter/autosplitter.cpp b/engine/source/autosplitter/autosplitter.cpp new file mode 100644 index 00000000..c285e0cd --- /dev/null +++ b/engine/source/autosplitter/autosplitter.cpp @@ -0,0 +1,72 @@ +#include + +#include "autosplitter.h" +#include "platform/platform.h" + + +Autosplitter *Autosplitter::smInstance = nullptr; + +void Autosplitter::init() +{ + if (smInstance) + return; + + smInstance = new Autosplitter(); +} + +void Autosplitter::destroy() +{ + if (!smInstance) + return; + + delete smInstance; + smInstance = nullptr; +} + +Autosplitter *Autosplitter::get() +{ + if (!smInstance) + init(); + + return smInstance; +} + +Autosplitter::Autosplitter() +{ + mActive = false; + mFilename = Platform::getPrefsPath(AUTOSPLITTER_FILE_NAME); + mFile.open(mFilename, std::ios_base::app); + if (!mFile.is_open()) + { + Con::errorf("Failed to open autosplitter file %s.", mFilename); + Con::errorf("Autosplitter is disabled."); + return; + } + Con::printf("Autosplitter Initialized to file %s", mFilename.c_str()); + mActive = true; +} + +Autosplitter::~Autosplitter() +{ + mFile.close(); + std::remove(mFilename.c_str()); +} + +void Autosplitter::sendData(const char *data) +{ + if (!mActive) + return; + + mFile << data << std::endl; +} + +ConsoleFunction(sendAutosplitterData, void, 2, 2, "") +{ + Autosplitter *autosplitter = Autosplitter::get(); + if (!autosplitter->isActive()) + return; + + Con::printf("Sending autosplitter message '%s'", argv[1]); + + autosplitter->sendData(argv[1]); +} diff --git a/engine/source/autosplitter/autosplitter.h b/engine/source/autosplitter/autosplitter.h new file mode 100644 index 00000000..6b67873b --- /dev/null +++ b/engine/source/autosplitter/autosplitter.h @@ -0,0 +1,29 @@ +#ifndef _AUTOSPLITTER_H_ +#define _AUTOSPLITTER_H_ + +#include +#include + +#include "console/console.h" + +constexpr const char *AUTOSPLITTER_FILE_NAME = "autosplitter.txt"; +constexpr U32 AUTOSPLITTER_BUF_SIZE = 512; + +class Autosplitter +{ +public: + static void init(); + static void destroy(); + static Autosplitter *get(); + bool isActive() { return mActive; } + void sendData(const char *data); +private: + Autosplitter(); + ~Autosplitter(); + static Autosplitter *smInstance; + bool mActive; + std::string mFilename; + std::fstream mFile; +}; + +#endif // _AUTOSPLITTER_H_ diff --git a/engine/source/game/main.cpp b/engine/source/game/main.cpp index d062fa81..237ad149 100644 --- a/engine/source/game/main.cpp +++ b/engine/source/game/main.cpp @@ -62,6 +62,7 @@ #include "lightingSystem/sgFormatManager.h" #include "sfx/sfxSystem.h" +#include "autosplitter/autosplitter.h" #ifndef BUILD_TOOLS DemoGame GameObject; @@ -188,6 +189,8 @@ static bool initLibraries() RedBook::init(); SFXSystem::init(); + Autosplitter::init(); + return true; } @@ -200,6 +203,8 @@ static void shutdownLibraries() if (ResourceManager) ResourceManager->purge(); + Autosplitter::destroy(); + RedBook::destroy(); TSShapeInstance::destroy(); InteriorInstance::destroy(); diff --git a/game/MBU.torsion.exports b/game/MBU.torsion.exports index b8956332..c2a459f1 100644 --- a/game/MBU.torsion.exports +++ b/game/MBU.torsion.exports @@ -7895,6 +7895,8 @@ Valid inputs for xRumble/yRumble are [0 - 1]. Take a screenshot. @param format One of JPEG or PNG. + + sendAutosplitterData setClipboard string text diff --git a/game/marble/client/scripts/game.cs b/game/marble/client/scripts/game.cs index 4de89ffa..5b817aab 100644 --- a/game/marble/client/scripts/game.cs +++ b/game/marble/client/scripts/game.cs @@ -778,6 +778,9 @@ function clientCmdSetGameState(%state, %data) { $GameEndUserName = XBLiveGetUserName(); $GameEndNoAllowPause = true; + + // Tell autosplitter we finished the level + sendAutosplitterData("finish" SPC GameMissionInfo.getCurrentMission().level); } else $GameEndNoAllowPause = false; diff --git a/game/marble/client/scripts/playGui.cs b/game/marble/client/scripts/playGui.cs index 1947685e..432a8da0 100644 --- a/game/marble/client/scripts/playGui.cs +++ b/game/marble/client/scripts/playGui.cs @@ -80,6 +80,8 @@ %isFreeLevel = (%levelPlaying == $PDLC::MapPack0LevelStart); UpsellGui.displayPDLCUpsell = %isFreeLevel ? false : !%hasLevel; } + + sendAutosplitterData("loading finished"); } function PlayGui::show(%this) diff --git a/game/marble/client/ui/LevelPreviewGui.gui b/game/marble/client/ui/LevelPreviewGui.gui index 3f4f7dd1..53992264 100644 --- a/game/marble/client/ui/LevelPreviewGui.gui +++ b/game/marble/client/ui/LevelPreviewGui.gui @@ -219,6 +219,10 @@ function levelPreviewGui::onA() // Create a new server loadMission(GameMissionInfo.getCurrentMission().file, true); + + // Tell autosplitter to start + sendAutosplitterData("start" SPC GameMissionInfo.getCurrentMission().level); + sendAutosplitterData("loading started"); } else { diff --git a/game/marble/server/scripts/easter.cs b/game/marble/server/scripts/easter.cs index aa76a66f..ec93cec0 100644 --- a/game/marble/server/scripts/easter.cs +++ b/game/marble/server/scripts/easter.cs @@ -58,6 +58,8 @@ function clientCmdOnEasterEggPickup( %index ) return; } + sendAutosplitterData("egg" SPC %index); + if( hasFoundEgg( %index ) ) { serverPlay2d(easterNotNewSfx); diff --git a/tools/cmake/marbleblast.cmake b/tools/cmake/marbleblast.cmake index cf77384b..3a95e405 100644 --- a/tools/cmake/marbleblast.cmake +++ b/tools/cmake/marbleblast.cmake @@ -71,6 +71,7 @@ endif() # Always enabled paths first ############################################################################### addPath("${srcDir}/") # must come first :) +addPath("${srcDir}/autosplitter") addPath("${srcDir}/collision") addPath("${srcDir}/console") addPath("${srcDir}/core")