diff --git a/MakefileNSO b/MakefileNSO index a301b90..3f8ea04 100644 --- a/MakefileNSO +++ b/MakefileNSO @@ -32,7 +32,7 @@ include $(DEVKITPRO)/libnx/switch_rules #--------------------------------------------------------------------------------- TARGET ?= $(notdir $(CURDIR))$(SMOVER) BUILD ?= build$(SMOVER) -SOURCES := source/sead/time source/sead source/puppets source/server source/layouts source/states source/cameras source/nx source +SOURCES := source/sead/time source/sead source/puppets source/server/hns source/server/gamemode source/server source/layouts source/states source/cameras source/nx source DATA := data INCLUDES := include include/sead @@ -46,7 +46,7 @@ CFLAGS := -g -Wall -ffunction-sections \ CFLAGS += $(INCLUDE) -D__SWITCH__ -DSMOVER=$(SMOVER) -O3 -DNNSDK -DSWITCH -DBUILDVERSTR=$(BUILDVERSTR) -DBUILDVER=$(BUILDVER) -DDEBUGLOG=$(DEBUGLOG) -DSERVERIP=$(SERVERIP) -DEMU=$(EMU) -CXXFLAGS := $(CFLAGS) -fno-rtti -fomit-frame-pointer -fno-exceptions -fno-asynchronous-unwind-tables -fno-unwind-tables -std=gnu++20 +CXXFLAGS := $(CFLAGS) -Wno-invalid-offsetof -Wno-volatile -fno-rtti -fomit-frame-pointer -fno-exceptions -fno-asynchronous-unwind-tables -fno-unwind-tables -std=gnu++20 ASFLAGS := -g $(ARCH) LDFLAGS = -specs=../switch.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map) -Wl,--version-script=$(TOPDIR)/exported.txt -Wl,-init=__custom_init -Wl,-fini=__custom_fini -nostdlib diff --git a/include/al/util.hpp b/include/al/util.hpp index 3ef495d..2735fc1 100644 --- a/include/al/util.hpp +++ b/include/al/util.hpp @@ -72,6 +72,9 @@ namespace al PlayerActorBase *tryGetPlayerActor(al::PlayerHolder const *, int); sead::Heap *getCurrentHeap(void); + sead::Heap* getStationedHeap(); + sead::Heap* getSequenceHeap(); + sead::Heap* getSceneHeap(); al::Projection *getProjection(al::IUseCamera const *, int); diff --git a/include/game/StageScene/StageSceneStateServerConfig.hpp b/include/game/StageScene/StageSceneStateServerConfig.hpp index 95d4c28..8956bdc 100644 --- a/include/game/StageScene/StageSceneStateServerConfig.hpp +++ b/include/game/StageScene/StageSceneStateServerConfig.hpp @@ -17,6 +17,7 @@ #include "logger.hpp" #include "server/gamemode/GameModeConfigMenu.hpp" +#include "server/gamemode/GameModeConfigMenuFactory.hpp" class FooterParts; @@ -65,14 +66,18 @@ class StageSceneStateServerConfig : public al::HostStateBase, public // Root Page, contains buttons for gamemode config, server reconnecting, and server ip address changing SimpleLayoutMenu* mMainOptions = nullptr; CommonVerticalList *mMainOptionsList = nullptr; - // Sub-Page for Mode configuration, has buttons for selecting current gamemode and configuring currently selected mode (if no mode is chosen, button will not do anything) - SimpleLayoutMenu* mGamemodeConfig = nullptr; - CommonVerticalList* mGameModeConfigList = nullptr; // Sub-Page of Mode config, used to select a gamemode for the client to use SimpleLayoutMenu* mModeSelect = nullptr; CommonVerticalList* mModeSelectList = nullptr; - // Controls what shows up in specific gamemode config page - GameModeConfigMenu *mGamemodeConfigMenu = nullptr; + + // Sub-Pages for Mode configuration, has buttons for selecting current gamemode and configuring currently selected mode (if no mode is chosen, button will not do anything) + struct GameModeEntry { + GameModeConfigMenu* mMenu; + SimpleLayoutMenu* mLayout = nullptr; + CommonVerticalList* mList = nullptr; + }; + sead::SafeArray mGamemodeConfigMenus; + GameModeEntry *mGamemodeConfigMenu = nullptr; bool mIsDecideConfig = false; }; diff --git a/include/server/Client.hpp b/include/server/Client.hpp index 7682263..63bfd29 100644 --- a/include/server/Client.hpp +++ b/include/server/Client.hpp @@ -96,8 +96,6 @@ class Client { static bool isNeedUpdateShines(); bool isShineCollected(int shineId); - static void initMode(GameModeInitInfo const &initInfo); - static void sendHackCapInfPacket(const HackCap *hackCap); static void sendPlayerInfPacket(const PlayerActorHakoniwa *player); static void sendGameInfPacket(const PlayerActorHakoniwa *player, GameDataHolderAccessor holder); @@ -110,8 +108,6 @@ class Client { int getCollectedShinesCount() { return curCollectedShines.size(); } int getShineID(int index) { if (index < curCollectedShines.size()) { return curCollectedShines[index]; } return -1; } - static void setGameActive(bool state); - static void setStageInfo(GameDataHolderAccessor holder); static bool tryAddPuppet(PuppetActor *puppet); @@ -130,27 +126,8 @@ class Client { static PuppetActor* getDebugPuppet(); - static GameMode getServerMode() { - return sInstance ? sInstance->mServerMode : GameMode::NONE; - } - - static void setServerMode(GameMode mode) { - if (sInstance) sInstance->mServerMode = mode; - } - - static GameMode getCurrentMode(); - - static GameModeBase* getModeBase() { return sInstance ? sInstance->mCurMode : nullptr; } - - template - static T* getMode() {return sInstance ? (T*)sInstance->mCurMode : nullptr;} - - static GameModeConfigMenu* tryCreateModeMenu(); - static int getMaxPlayerCount() { return sInstance ? sInstance->maxPuppets + 1 : 10;} - static void toggleCurrentMode(); - static void updateStates(); static void clearArrays(); @@ -173,6 +150,12 @@ class Client { return 0; } + static PuppetHolder* getPuppetHolder() { + if (sInstance) + return sInstance->mPuppetHolder; + return nullptr; + } + static void setSceneInfo(const al::ActorInitInfo& initInfo, const StageScene *stageScene); static bool tryRegisterShine(Shine* shine); @@ -184,23 +167,6 @@ class Client { static bool openKeyboardIP(); static bool openKeyboardPort(); - static GameModeInfoBase* getModeInfo() { - return sInstance ? sInstance->mModeInfo : nullptr; - } - - // should only be called during mode init - static void setModeInfo(GameModeInfoBase* info) { - if(sInstance) sInstance->mModeInfo = info; - } - - static void tryRestartCurrentMode(); - - static bool isModeActive() { return sInstance ? sInstance->mIsModeActive : false; } - - static bool isSelectedMode(GameMode mode) { - return sInstance ? sInstance->mCurMode->getMode() == mode : false; - } - static void showConnect(); static void showConnectError(const char16_t* msg); @@ -295,21 +261,11 @@ class Client { sead::FrameHeap *mHeap = nullptr; // Custom FrameHeap used for all Client related memory - // --- Mode Info --- - - GameModeBase* mCurMode = nullptr; - - GameMode mServerMode = GameMode::NONE; // current mode set by server, will sometimes not match up with current game mode (until scene re-init) if server switches gamemodes - - GameModeInfoBase *mModeInfo = nullptr; - - bool mIsModeActive = false; - // --- Puppet Info --- int maxPuppets = 9; // default max player count is 10, so default max puppets will be 9 - PuppetInfo *mPuppetInfoArr[MAXPUPINDEX]; + PuppetInfo *mPuppetInfoArr[MAXPUPINDEX] = {}; PuppetHolder *mPuppetHolder = nullptr; diff --git a/include/server/gamemode/GameModeBase.hpp b/include/server/gamemode/GameModeBase.hpp index d0baed6..e7e4715 100644 --- a/include/server/gamemode/GameModeBase.hpp +++ b/include/server/gamemode/GameModeBase.hpp @@ -21,7 +21,6 @@ enum GameMode : s8 { // struct containing info about the games state for use in gamemodes struct GameModeInitInfo { - GameModeInitInfo(al::ActorInitInfo* info, al::Scene *scene){ mLayoutInitInfo = info->mLayoutInitInfo; mPlayerHolder = info->mActorSceneInfo.mPlayerHolder; @@ -47,6 +46,7 @@ struct GameModeInitInfo { class GameModeBase : public al::IUseName, public al::IUseSceneObjHolder { public: GameModeBase(const char* name) { mName = name; } + virtual ~GameModeBase() = default; const char* getName() const override { return mName.cstr(); } al::SceneObjHolder* getSceneObjHolder() const override { return mSceneObjHolder; } @@ -56,7 +56,7 @@ public: virtual void init(GameModeInitInfo const &info); - virtual void begin() { mIsActive = true;} + virtual void begin() { mIsActive = true; } virtual void update(); virtual void end() { mIsActive = false; } diff --git a/include/server/gamemode/GameModeConfigMenuFactory.hpp b/include/server/gamemode/GameModeConfigMenuFactory.hpp new file mode 100644 index 0000000..d76d307 --- /dev/null +++ b/include/server/gamemode/GameModeConfigMenuFactory.hpp @@ -0,0 +1,38 @@ +#pragma once + +#include "al/factory/Factory.h" +#include "server/hns/HideAndSeekConfigMenu.hpp" +#include "server/gamemode/GameModeConfigMenu.hpp" + +typedef GameModeConfigMenu* (*createMenu)(const char* name); + +template +GameModeConfigMenu* createGameModeConfigMenu(const char* name) { + return new T(); +}; + +__attribute((used)) constexpr al::NameToCreator menuTable[] = { + {"HideAndSeek", &createGameModeConfigMenu}, +}; + +class GameModeConfigMenuFactory : public al::Factory { +public: + GameModeConfigMenuFactory(const char* fName) { + this->factoryName = fName; + this->actorTable = menuTable; + this->factoryCount = sizeof(menuTable) / sizeof(menuTable[0]); + }; + + constexpr static const char* getMenuName(int idx); + constexpr static int getMenuCount(); +}; + +constexpr const char* GameModeConfigMenuFactory::getMenuName(int idx) { + if (idx >= 0 && idx < sizeof(menuTable) / sizeof(menuTable[0])) + return menuTable[idx].creatorName; + return nullptr; +} + +constexpr int GameModeConfigMenuFactory::getMenuCount() { + return sizeof(menuTable) / sizeof(menuTable[0]); +} \ No newline at end of file diff --git a/include/server/gamemode/GameModeFactory.hpp b/include/server/gamemode/GameModeFactory.hpp index 334fe00..27ca263 100644 --- a/include/server/gamemode/GameModeFactory.hpp +++ b/include/server/gamemode/GameModeFactory.hpp @@ -1,9 +1,8 @@ #pragma once #include "al/factory/Factory.h" -#include "layouts/HideAndSeekIcon.h" #include "server/gamemode/GameModeBase.hpp" -#include "server/HideAndSeekMode.hpp" +#include "server/hns/HideAndSeekMode.hpp" typedef GameModeBase* (*createMode)(const char* name); @@ -37,19 +36,19 @@ class GameModeFactory : public al::Factory { // TODO: possibly use shadows' crc32 hash algorithm for this constexpr const char* GameModeFactory::getModeString(GameMode mode) { - if(mode >= 0 && mode < sizeof(modeTable)/sizeof(modeTable[0])) + if(mode >= 0 && (size_t)mode < sizeof(modeTable)/sizeof(modeTable[0])) return modeTable[mode].creatorName; return nullptr; } constexpr const char* GameModeFactory::getModeName(GameMode mode) { - if(mode >= 0 && mode < sizeof(modeNames)/sizeof(modeNames[0])) + if(mode >= 0 && (size_t)mode < sizeof(modeNames)/sizeof(modeNames[0])) return modeNames[mode]; return nullptr; } constexpr const char* GameModeFactory::getModeName(int idx) { - if(idx >= 0 && idx < sizeof(modeNames)/sizeof(modeNames[0])) + if(idx >= 0 && (size_t)idx < sizeof(modeNames)/sizeof(modeNames[0])) return modeNames[idx]; return nullptr; } diff --git a/include/server/gamemode/GameModeInfoBase.hpp b/include/server/gamemode/GameModeInfoBase.hpp index 0f0cdab..b2d24be 100644 --- a/include/server/gamemode/GameModeInfoBase.hpp +++ b/include/server/gamemode/GameModeInfoBase.hpp @@ -1,21 +1,11 @@ #pragma once #include "server/gamemode/GameModeBase.hpp" +#include // base struct containing info about the current gamemode struct GameModeInfoBase { GameMode mMode; }; -template -T *createModeInfo() { - // using sequence heap to create mode info should allow for mode info to persist between scenes - sead::Heap* seqHeap = sead::HeapMgr::instance()->findHeapByName("SequenceHeap", 0); - - if (seqHeap) { - return new (seqHeap) T(); - } else { - // if failed to get sequence heap, fall back to current heap (will return null if current heap is also null) - return new T(); - } -} \ No newline at end of file +#include "server/gamemode/GameModeManager.hpp" \ No newline at end of file diff --git a/include/server/gamemode/GameModeManager.hpp b/include/server/gamemode/GameModeManager.hpp new file mode 100644 index 0000000..3b881ac --- /dev/null +++ b/include/server/gamemode/GameModeManager.hpp @@ -0,0 +1,59 @@ +#pragma once + +#include +#include +#include +#include "server/gamemode/GameModeBase.hpp" +#include "server/gamemode/GameModeInfoBase.hpp" + +class GameModeManager { + SEAD_SINGLETON_DISPOSER(GameModeManager) + GameModeManager(); + ~GameModeManager(); + +public: + void setMode(GameMode mode); + void initScene(const GameModeInitInfo& info); + void begin(); + void end(); + void update(); + + GameMode getGameMode() const { return mCurMode; } + template T* getMode() const { return static_cast(mCurModeBase); } + template T* getInfo() const { return static_cast(mModeInfo); } + void setInfo(GameModeInfoBase* info) { + mModeInfo = info; + } + + template + T* createModeInfo(); + + sead::Heap* getHeap() { return mHeap; } + void toggleActive(); + void setActive(bool active) { mActive = active; } + void setPaused(bool paused); + bool isMode(GameMode mode) const { return mCurMode == mode; } + bool isActive() const { return mActive; } + bool isModeAndActive(GameMode mode) const { return isMode(mode) && isActive(); } + bool isPaused() const { return mPaused; } +private: + sead::Heap* mHeap = nullptr; + + bool mActive = false; + bool mPaused = false; + bool mWasSceneTrans = false; + bool mWasSetMode = false; + GameMode mCurMode = GameMode::NONE; + GameModeBase* mCurModeBase = nullptr; + GameModeInfoBase *mModeInfo = nullptr; + GameModeInitInfo *mLastInitInfo = nullptr; +}; + +template +T* GameModeManager::createModeInfo() { + sead::ScopedCurrentHeapSetter heapSetter(mHeap); + + T* info = new T(); + mModeInfo = info; + return info; +} \ No newline at end of file diff --git a/include/server/HideAndSeekConfigMenu.hpp b/include/server/hns/HideAndSeekConfigMenu.hpp similarity index 90% rename from include/server/HideAndSeekConfigMenu.hpp rename to include/server/hns/HideAndSeekConfigMenu.hpp index b0fa4d5..f2039c9 100644 --- a/include/server/HideAndSeekConfigMenu.hpp +++ b/include/server/hns/HideAndSeekConfigMenu.hpp @@ -1,6 +1,6 @@ #pragma once -#include "gamemode/GameModeConfigMenu.hpp" +#include "server/gamemode/GameModeConfigMenu.hpp" #include "game/Layouts/CommonVerticalList.h" #include "server/gamemode/GameModeBase.hpp" diff --git a/include/server/HideAndSeekMode.hpp b/include/server/hns/HideAndSeekMode.hpp similarity index 90% rename from include/server/HideAndSeekMode.hpp rename to include/server/hns/HideAndSeekMode.hpp index 4f7e370..b321bdd 100644 --- a/include/server/HideAndSeekMode.hpp +++ b/include/server/hns/HideAndSeekMode.hpp @@ -2,11 +2,11 @@ #include #include "al/camera/CameraTicket.h" -#include "gamemode/GameModeBase.hpp" -#include "gamemode/GameModeInfoBase.hpp" +#include "server/gamemode/GameModeBase.hpp" +#include "server/gamemode/GameModeInfoBase.hpp" #include "server/gamemode/GameModeConfigMenu.hpp" #include "server/gamemode/GameModeTimer.hpp" -#include "server/HideAndSeekConfigMenu.hpp" +#include "server/hns/HideAndSeekConfigMenu.hpp" struct HideAndSeekInfo : GameModeInfoBase { HideAndSeekInfo() { mMode = GameMode::HIDEANDSEEK; } diff --git a/source/hooks.cpp b/source/hooks.cpp index 3fc0fad..0e6febd 100644 --- a/source/hooks.cpp +++ b/source/hooks.cpp @@ -26,10 +26,10 @@ #include "math/seadVector.h" #include "rs/util/InputUtil.h" #include "sead/prim/seadSafeString.h" -#include "server/HideAndSeekMode.hpp" +#include "server/hns/HideAndSeekMode.hpp" bool comboBtnHook(int port) { - if (Client::isModeActive()) { // only switch to combo if any gamemode is active + if (GameModeManager::instance()->isActive()) { // only switch to combo if any gamemode is active return !al::isPadHoldL(port) && al::isPadTriggerDown(port); } else { return al::isPadTriggerDown(port); @@ -110,19 +110,19 @@ void initNerveStateHook(StageSceneStatePauseMenu* stateParent, StageSceneStateOp // skips starting both coin counters void startCounterHook(CoinCounter* thisPtr) { - if (!Client::isModeActive()) { + if (!GameModeManager::instance()->isActive()) { thisPtr->tryStart(); } } // Simple hook that can be used to override isModeE3 checks to enable/disable certain behaviors bool modeE3Hook() { - return Client::isModeActive(); + return GameModeManager::instance()->isActive(); } // Skips ending the play guide layout if a mode is active, since the mode would have already ended it void playGuideEndHook(al::SimpleLayoutAppearWaitEnd* thisPtr) { - if (!Client::isModeActive()) { + if (!GameModeManager::instance()->isActive()) { thisPtr->end(); } } @@ -135,14 +135,14 @@ void initHackCapHook(al::LiveActor *cappy) { al::PlayerHolder* createTicketHook(StageScene* curScene) { // only creates custom gravity camera ticket if hide and seek mode is active - if (Client::isSelectedMode(GameMode::HIDEANDSEEK)) { + if (GameModeManager::instance()->isMode(GameMode::HIDEANDSEEK)) { al::CameraDirector* director = curScene->getCameraDirector(); if (director) { if (director->mFactory) { al::CameraTicket* gravityCamera = director->createCameraFromFactory( "CameraPoserCustom", nullptr, 0, 5, sead::Matrix34f::ident); - HideAndSeekMode* mode = Client::getMode(); + HideAndSeekMode* mode = GameModeManager::instance()->getMode(); mode->setCameraTicket(gravityCamera); } @@ -157,9 +157,9 @@ bool borderPullBackHook(WorldEndBorderKeeper* thisPtr) { bool isFirstStep = al::isFirstStep(thisPtr); if (isFirstStep) { - if (Client::isSelectedMode(GameMode::HIDEANDSEEK) && Client::isModeActive()) { + if (GameModeManager::instance()->isModeAndActive(GameMode::HIDEANDSEEK)) { - HideAndSeekMode* mode = Client::getMode(); + HideAndSeekMode* mode = GameModeManager::instance()->getMode(); if (mode->isUseGravity()) { killMainPlayer(thisPtr->mActor); diff --git a/source/layouts/HideAndSeekIcon.cpp b/source/layouts/HideAndSeekIcon.cpp index 7b8b579..c12b664 100644 --- a/source/layouts/HideAndSeekIcon.cpp +++ b/source/layouts/HideAndSeekIcon.cpp @@ -5,7 +5,7 @@ #include "al/string/StringTmp.h" #include "prim/seadSafeString.h" #include "server/gamemode/GameModeTimer.hpp" -#include "server/HideAndSeekMode.hpp" +#include "server/hns/HideAndSeekMode.hpp" #include "server/Client.hpp" #include "al/util.hpp" #include "logger.hpp" @@ -16,7 +16,7 @@ HideAndSeekIcon::HideAndSeekIcon(const char* name, const al::LayoutInitInfo& ini al::initLayoutActor(this, initInfo, "HideAndSeekIcon", 0); - mInfo = (HideAndSeekInfo*)Client::getModeInfo(); + mInfo = GameModeManager::instance()->getInfo(); initNerve(&nrvHideAndSeekIconEnd, 0); diff --git a/source/main.cpp b/source/main.cpp index 74b9010..8cb5a27 100644 --- a/source/main.cpp +++ b/source/main.cpp @@ -21,7 +21,8 @@ #include "logger.hpp" #include "rs/util.hpp" #include "server/gamemode/GameModeBase.hpp" -#include "server/HideAndSeekMode.hpp" +#include "server/hns/HideAndSeekMode.hpp" +#include "server/gamemode/GameModeManager.hpp" static int pInfSendTimer = 0; static int gameInfSendTimer = 0; @@ -252,10 +253,11 @@ void stageInitHook(al::ActorInitInfo *info, StageScene *curScene, al::PlacementI Client::setSceneInfo(*info, curScene); - if (Client::getServerMode() != NONE) { + if (GameModeManager::instance()->getGameMode() != NONE) { GameModeInitInfo initModeInfo(info, curScene); + initModeInfo.initServerInfo(GameModeManager::instance()->getGameMode(), Client::getPuppetHolder()); - Client::initMode(initModeInfo); + GameModeManager::instance()->initScene(initModeInfo); } Client::sendGameInfPacket(info->mActorSceneInfo.mSceneObjHolder); @@ -278,6 +280,7 @@ ulong constructHook() { // hook for constructing anything we need to globally b initInfo)); // Save our scenes init info to a gloabl ptr so we can access it later Client::createInstance(al::getCurrentHeap()); + GameModeManager::createInstance(al::getCurrentHeap()); // Create the GameModeManager on the current al heap return 0x20; } @@ -303,13 +306,9 @@ bool hakoniwaSequenceHook(HakoniwaSequence* sequence) { al::PlayerHolder *pHolder = al::getScenePlayerHolder(stageScene); PlayerActorHakoniwa* p1 = (PlayerActorHakoniwa*)al::tryGetPlayerActor(pHolder, 0); - if (isFirstStep) { - Client::tryRestartCurrentMode(); - } - isInGame = !stageScene->isPause(); - Client::setGameActive(!stageScene->isPause()); + GameModeManager::instance()->setPaused(stageScene->isPause()); Client::setStageInfo(stageScene->mHolder); Client::updateStates(); @@ -345,7 +344,7 @@ bool hakoniwaSequenceHook(HakoniwaSequence* sequence) { } } else if (al::isPadHoldL(-1)) { - if (al::isPadTriggerLeft(-1)) Client::toggleCurrentMode(); + if (al::isPadTriggerLeft(-1)) GameModeManager::instance()->toggleActive(); if (al::isPadTriggerRight(-1)) { if (debugMode) { PuppetInfo *debugPuppet = Client::getDebugPuppetInfo(); diff --git a/source/puppets/PuppetActor.cpp b/source/puppets/PuppetActor.cpp index 2478571..2c20b61 100644 --- a/source/puppets/PuppetActor.cpp +++ b/source/puppets/PuppetActor.cpp @@ -14,8 +14,9 @@ #include "actors/PuppetActor.h" #include "math/seadQuat.h" #include "math/seadVector.h" +#include "server/gamemode/GameModeManager.hpp" #include "server/gamemode/GameModeBase.hpp" -#include "server/HideAndSeekMode.hpp" +#include "server/hns/HideAndSeekMode.hpp" static const char *subActorNames[] = { "顔", // Face @@ -189,9 +190,9 @@ void PuppetActor::control() { } if (mNameTag) { - if (Client::isSelectedMode(GameMode::HIDEANDSEEK) && Client::isModeActive()) { + if (GameModeManager::instance()->isModeAndActive(GameMode::HIDEANDSEEK)) { mNameTag->mIsAlive = - Client::getMode()->isPlayerIt() && mInfo->isIt; + GameModeManager::instance()->getMode()->isPlayerIt() && mInfo->isIt; } else { if(!mNameTag->mIsAlive) diff --git a/source/server/Client.cpp b/source/server/Client.cpp index ef67b19..eb55be4 100644 --- a/source/server/Client.cpp +++ b/source/server/Client.cpp @@ -35,9 +35,9 @@ #include "sead/basis/seadRawPrint.h" #include "sead/math/seadQuat.h" #include "server/gamemode/GameModeBase.hpp" -#include "server/gamemode/GameModeFactory.hpp" -#include "server/HideAndSeekConfigMenu.hpp" -#include "server/HideAndSeekMode.hpp" +#include "server/gamemode/GameModeManager.hpp" +#include "server/hns/HideAndSeekConfigMenu.hpp" +#include "server/hns/HideAndSeekMode.hpp" SEAD_SINGLETON_DISPOSER_IMPL(Client) @@ -93,8 +93,6 @@ Client::Client() { Logger::log("%s Build Number: %s\n", playerName.name, TOSTRING(BUILDVERSTR)); - mServerMode = GameMode::HIDEANDSEEK; // temp for testing - } /** @@ -118,39 +116,6 @@ void Client::init(al::LayoutInitInfo const &initInfo, GameDataHolderAccessor hol } -/** - * @brief creates and initializes the gamemode selected by either server or client settings - * - * @param initInfo init info used to initialize gamemode - */ -void Client::initMode(GameModeInitInfo const& initInfo) { - - if (!sInstance) { - Logger::log("Static Instance is null!\n"); - return; - } - - GameModeInitInfo newInfo = initInfo; - - newInfo.initServerInfo(sInstance->mServerMode, sInstance->mPuppetHolder); - - GameModeFactory modeFactory("GameModeFactory"); - - const char* modeName = GameModeFactory::getModeString(newInfo.mMode); - - if (modeName) { - auto creator = modeFactory.getCreator(modeName); - if (creator) { - sInstance->mCurMode = creator(modeName); - } - } - - if (sInstance->mCurMode) { - sInstance->mCurMode->init(newInfo); - } else { - Logger::log("Failed to Create Gamemode! Mode: \n", modeName ? modeName : "Unknown"); - } -} /** * @brief starts client read thread * @@ -712,13 +677,14 @@ void Client::sendTagInfPacket() { return; } - if (sInstance->mServerMode != GameMode::HIDEANDSEEK) { + HideAndSeekMode* hsMode = GameModeManager::instance()->getMode(); + + if (!GameModeManager::instance()->isMode(GameMode::HIDEANDSEEK)) { Logger::log("State is not Hide and Seek!\n"); return; } - HideAndSeekMode* hsMode = (HideAndSeekMode*)sInstance->mCurMode; - HideAndSeekInfo* curInfo = (HideAndSeekInfo*)sInstance->mModeInfo; + HideAndSeekInfo* curInfo = GameModeManager::instance()->getInfo(); TagInf packet = TagInf(); @@ -994,10 +960,10 @@ void Client::updateGameInfo(GameInf *packet) { void Client::updateTagInfo(TagInf *packet) { // if the packet is for our player, edit info for our player - if (packet->mUserID == mUserID && mCurMode->getMode() == GameMode::HIDEANDSEEK) { + if (packet->mUserID == mUserID && GameModeManager::instance()->isMode(GameMode::HIDEANDSEEK)) { - HideAndSeekMode* mMode = (HideAndSeekMode*)mCurMode; - HideAndSeekInfo* curInfo = (HideAndSeekInfo*)mModeInfo; + HideAndSeekMode* mMode = GameModeManager::instance()->getMode(); + HideAndSeekInfo* curInfo = GameModeManager::instance()->getInfo(); if (packet->updateType & TagUpdateType::STATE) { mMode->setPlayerTagState(packet->isIt); @@ -1299,34 +1265,7 @@ void Client::updateStates() { if(sInstance) { sInstance->mPuppetHolder->update(); - if(sInstance->mCurMode && sInstance->mCurMode->isModeActive()) - sInstance->mCurMode->update(); - } -} - -/** - * @brief - * - * @param state - */ -void Client::setGameActive(bool state) { - if (sInstance) { - - sInstance->mIsInGame = state; - - // only modify mode state if mode should be active - if (sInstance->mIsModeActive) { - - bool modeActive = sInstance->mCurMode->isModeActive(); - - if (state && !modeActive) { - Logger::log("Resuming Current Mode.\n"); - sInstance->mCurMode->begin(); - } else if (!state && modeActive) { - Logger::log("Pausing Current Mode.\n"); - sInstance->mCurMode->end(); - } - } + GameModeManager::instance()->update(); } } @@ -1485,66 +1424,6 @@ Shine* Client::findStageShine(int shineID) { return nullptr; } -/** - * @brief gets the client's currently selected gamemode - * - * @return GameMode - */ -GameMode Client::getCurrentMode() { - return sInstance && sInstance->mCurMode ? sInstance->mCurMode->getMode() : GameMode::NONE; -} - -/** - * @brief enables or disables currently selected gamemode - * - */ -void Client::toggleCurrentMode() { - if (!sInstance || !sInstance->mCurMode) { - return; - } - - GameModeBase* curMode = sInstance->mCurMode; - - if (curMode->isModeActive()) { - Logger::log("Ending Gamemode: %s\n", curMode->getName()); - curMode->end(); - sInstance->mIsModeActive = false; - } else { - Logger::log("Starting Gamemode: %s\n", curMode->getName()); - curMode->begin(); - sInstance->mIsModeActive = true; - } -} - -/** - * @brief re-enables current gamemode if previously activated (if a stage reload occurs while the gamemode was previously active, this will turn it back on after initialized) - * - */ -void Client::tryRestartCurrentMode() { - if (!sInstance || !sInstance->mCurMode) { - return; - } - // restart mode if previous scene had one active - if (sInstance->mIsModeActive) { - sInstance->mCurMode->begin(); - } -} - -GameModeConfigMenu* Client::tryCreateModeMenu() { - if (!sInstance) - return nullptr; - - switch (sInstance->mServerMode) { - case HIDEANDSEEK: { - return new HideAndSeekConfigMenu(); - } - default: - return nullptr; - } -} - - - void Client::showConnectError(const char16_t* msg) { if (!sInstance) return; diff --git a/source/server/gamemode/GameModeManager.cpp b/source/server/gamemode/GameModeManager.cpp new file mode 100644 index 0000000..39a1721 --- /dev/null +++ b/source/server/gamemode/GameModeManager.cpp @@ -0,0 +1,92 @@ +#include "server/gamemode/GameModeManager.hpp" +#include +#include +#include "al/util.hpp" +#include "basis/seadNew.h" +#include "heap/seadHeapMgr.h" +#include "server/gamemode/GameModeBase.hpp" +#include "server/gamemode/GameModeFactory.hpp" + +SEAD_SINGLETON_DISPOSER_IMPL(GameModeManager) + +GameModeManager::GameModeManager() { + mHeap = sead::FrameHeap::create(0x100000, "GameModeHeap", al::getSequenceHeap(), 8, + sead::Heap::HeapDirection::cHeapDirection_Reverse, false); + setMode(GameMode::HIDEANDSEEK); +} + +void GameModeManager::begin() { + if (mCurModeBase) { + sead::ScopedCurrentHeapSetter heapSetter(mHeap); + mCurModeBase->begin(); + } +} + +void GameModeManager::end() { + if (mCurModeBase) { + sead::ScopedCurrentHeapSetter heapSetter(mHeap); + mCurModeBase->end(); + } +} + +void GameModeManager::toggleActive() { + mActive = !mActive; +} + +void GameModeManager::setPaused(bool paused) { + mPaused = paused; +} + +void GameModeManager::setMode(GameMode mode) { + mCurMode = mode; + + mWasSetMode = true; // recreate in initScene +} + +void GameModeManager::update() { + if (!mCurModeBase) return; + bool inScene = al::getSceneHeap() != nullptr; + if ((mActive && inScene && !mPaused && !mCurModeBase->isModeActive()) || mWasSceneTrans) begin(); + if ((!mActive || mPaused || !inScene) && mCurModeBase->isModeActive()) end(); + mWasSceneTrans = false; + if (mCurModeBase && mCurModeBase->isModeActive()) { + sead::ScopedCurrentHeapSetter heapSetter(mHeap); + mCurModeBase->update(); + } +} + +void GameModeManager::initScene(const GameModeInitInfo& info) { + sead::ScopedCurrentHeapSetter heapSetter(mHeap); + + if (mCurModeBase != nullptr) { + delete mCurModeBase; + } + + if (mLastInitInfo != nullptr) { + delete mLastInitInfo; + } + + if (mCurMode == GameMode::NONE) { + mCurModeBase = nullptr; + mModeInfo = nullptr; + return; + } + + mLastInitInfo = new GameModeInitInfo(info); + + if (!mCurModeBase && mWasSetMode) { + GameModeFactory factory("GameModeFactory"); + const char* name = factory.getModeString(mCurMode); + mCurModeBase = factory.getCreator(name)(name); + if (mLastInitInfo) { // check if there's a previously used init info + mCurModeBase->init(*mLastInitInfo); + } + mWasSetMode = false; + } + + if (mCurModeBase) { + mCurModeBase->init(*mLastInitInfo); + if (mCurModeBase->isModeActive()) + mWasSceneTrans = true; + } +} \ No newline at end of file diff --git a/source/server/GameModeTimer.cpp b/source/server/hns/GameModeTimer.cpp similarity index 59% rename from source/server/GameModeTimer.cpp rename to source/server/hns/GameModeTimer.cpp index 95e364a..02aeace 100644 --- a/source/server/GameModeTimer.cpp +++ b/source/server/hns/GameModeTimer.cpp @@ -2,6 +2,7 @@ #include #include "al/util/ControllerUtil.h" #include "server/DeltaTime.hpp" +#include "logger.hpp" GameModeTimer::GameModeTimer(bool isCountUp, float milli, int seconds, int minutes, int hours) { mIsCountUp = isCountUp; @@ -24,10 +25,14 @@ GameModeTimer::GameModeTimer() { } void GameModeTimer::setTime(float milli, int seconds, int minutes, int hours) { - if(milli >= 0) mTime.mMilliseconds = milli; - if(seconds >= 0) mTime.mSeconds = seconds; - if(minutes >= 0) mTime.mMinutes = minutes; - if(hours >= 0) mTime.mHours = hours; + if (milli >= 0) + mTime.mMilliseconds = milli; + if (seconds >= 0) + mTime.mSeconds = seconds; + if (minutes >= 0) + mTime.mMinutes = minutes; + if (hours >= 0) + mTime.mHours = hours; } void GameModeTimer::setTime(GameTime const& time) { @@ -35,7 +40,6 @@ void GameModeTimer::setTime(GameTime const& time) { } void GameModeTimer::updateTimer() { - if (mIsUseControl) { timerControl(); } @@ -43,11 +47,11 @@ void GameModeTimer::updateTimer() { if (mIsEnabled) { if (mIsCountUp) { mTime.mMilliseconds += Time::deltaTime; - - if(mTime.mMilliseconds >= 1) { + + if (mTime.mMilliseconds >= 1) { mTime.mMilliseconds--; mTime.mSeconds++; - if(mTime.mSeconds >= 60) { + if (mTime.mSeconds >= 60) { mTime.mSeconds = 0; mTime.mMinutes++; if (mTime.mMinutes >= 60) { @@ -61,7 +65,7 @@ void GameModeTimer::updateTimer() { if (mTime.mMilliseconds >= 1) { mTime.mMilliseconds--; mTime.mSeconds--; - if(mTime.mSeconds < 0) { + if (mTime.mSeconds < 0) { mTime.mSeconds = 59; mTime.mMinutes--; if (mTime.mMinutes < 0) { @@ -79,41 +83,44 @@ void GameModeTimer::updateTimer() { } void GameModeTimer::timerControl() { - - if(al::isPadHoldRight(-1)) { - mTime.mMilliseconds = 0; - mTime.mSeconds++; - if(mTime.mSeconds >= 60) { + if (al::isPadHoldL(-1)) { + if (al::isPadTriggerDown(-1)) { + mTime.mMilliseconds = 0; mTime.mSeconds = 0; - mTime.mMinutes++; - if (mTime.mMinutes >= 60) { - mTime.mMinutes = 0; - mTime.mHours++; + mTime.mMinutes = 0; + mTime.mHours = 0; + } + } else { + if (al::isPadHoldRight(-1)) { + mTime.mMilliseconds = 0; + mTime.mSeconds++; + if (mTime.mSeconds >= 60) { + mTime.mSeconds = 0; + mTime.mMinutes++; + if (mTime.mMinutes >= 60) { + mTime.mMinutes = 0; + mTime.mHours++; + } } } - } - if(al::isPadTriggerLeft(-1)) { - mTime.mMilliseconds = 0; - mTime.mSeconds--; - if(mTime.mSeconds < 0) { - mTime.mSeconds = 59; - mTime.mMinutes--; - if (mTime.mMinutes < 0) { - if (mTime.mHours > 0) { - mTime.mMinutes = 59; - mTime.mHours--; - } else { - mTime.mMinutes = 0; + if (al::isPadTriggerLeft(-1)) { + mTime.mMilliseconds = 0; + if (mTime.mMinutes != 0) { + mTime.mSeconds--; + if (mTime.mSeconds < 0) { + mTime.mSeconds = 59; + mTime.mMinutes--; + if (mTime.mMinutes < 0) { + if (mTime.mHours > 0) { + mTime.mMinutes = 59; + mTime.mHours--; + } else { + mTime.mMinutes = 0; + } + } } } } } - - if(al::isPadHoldL(-1) && al::isPadTriggerDown(-1)) { - mTime.mMilliseconds = 0; - mTime.mSeconds = 0; - mTime.mMinutes = 0; - mTime.mHours = 0; - } } \ No newline at end of file diff --git a/source/server/HideAndSeekConfigMenu.cpp b/source/server/hns/HideAndSeekConfigMenu.cpp similarity index 76% rename from source/server/HideAndSeekConfigMenu.cpp rename to source/server/hns/HideAndSeekConfigMenu.cpp index 3e5c203..79fc7a4 100644 --- a/source/server/HideAndSeekConfigMenu.cpp +++ b/source/server/hns/HideAndSeekConfigMenu.cpp @@ -1,7 +1,8 @@ -#include "server/HideAndSeekConfigMenu.hpp" +#include "server/hns/HideAndSeekConfigMenu.hpp" #include #include "logger.hpp" -#include "server/HideAndSeekMode.hpp" +#include "server/gamemode/GameModeManager.hpp" +#include "server/hns/HideAndSeekMode.hpp" #include "server/Client.hpp" HideAndSeekConfigMenu::HideAndSeekConfigMenu() : GameModeConfigMenu() {} @@ -22,7 +23,7 @@ const sead::WFixedSafeString<0x200> *HideAndSeekConfigMenu::getStringData() { bool HideAndSeekConfigMenu::updateMenu(int selectIndex) { - HideAndSeekInfo *curMode = (HideAndSeekInfo*)Client::getModeInfo(); + HideAndSeekInfo *curMode = GameModeManager::instance()->getInfo(); Logger::log("Setting Gravity Mode.\n"); @@ -33,13 +34,13 @@ bool HideAndSeekConfigMenu::updateMenu(int selectIndex) { switch (selectIndex) { case 0: { - if (Client::isSelectedMode(GameMode::HIDEANDSEEK)) { + if (GameModeManager::instance()->isMode(GameMode::HIDEANDSEEK)) { curMode->mIsUseGravity = true; } return true; } case 1: { - if (Client::isSelectedMode(GameMode::HIDEANDSEEK)) { + if (GameModeManager::instance()->isMode(GameMode::HIDEANDSEEK)) { curMode->mIsUseGravity = false; } return true; diff --git a/source/server/HideAndSeekMode.cpp b/source/server/hns/HideAndSeekMode.cpp similarity index 83% rename from source/server/HideAndSeekMode.cpp rename to source/server/hns/HideAndSeekMode.cpp index 032965c..3f87ffe 100644 --- a/source/server/HideAndSeekMode.cpp +++ b/source/server/hns/HideAndSeekMode.cpp @@ -1,4 +1,4 @@ -#include "server/HideAndSeekMode.hpp" +#include "server/hns/HideAndSeekMode.hpp" #include #include "al/async/FunctorV0M.hpp" #include "al/util.hpp" @@ -7,15 +7,19 @@ #include "game/Layouts/CoinCounter.h" #include "game/Layouts/MapMini.h" #include "game/Player/PlayerActorHakoniwa.h" +#include "heap/seadHeapMgr.h" #include "layouts/HideAndSeekIcon.h" #include "logger.hpp" #include "rs/util.hpp" #include "server/gamemode/GameModeBase.hpp" #include "server/Client.hpp" #include "server/gamemode/GameModeTimer.hpp" +#include +#include "server/gamemode/GameModeManager.hpp" +#include "server/gamemode/GameModeFactory.hpp" #include "basis/seadNew.h" -#include "server/HideAndSeekConfigMenu.hpp" +#include "server/hns/HideAndSeekConfigMenu.hpp" HideAndSeekMode::HideAndSeekMode(const char* name) : GameModeBase(name) {} @@ -25,17 +29,21 @@ void HideAndSeekMode::init(const GameModeInitInfo& info) { mCurScene = (StageScene*)info.mScene; mPuppetHolder = info.mPuppetHolder; - GameModeInfoBase* curGameInfo = Client::getModeInfo(); + GameModeInfoBase* curGameInfo = GameModeManager::instance()->getInfo(); + sead::ScopedCurrentHeapSetter heapSetter(GameModeManager::instance()->getHeap()); + + if (curGameInfo) Logger::log("Gamemode info found: %s %s\n", GameModeFactory::getModeString(curGameInfo->mMode), GameModeFactory::getModeString(info.mMode)); + else Logger::log("No gamemode info found\n"); if (curGameInfo && curGameInfo->mMode == mMode) { mInfo = (HideAndSeekInfo*)curGameInfo; mModeTimer = new GameModeTimer(mInfo->mHidingTime); + Logger::log("Reinitialized timer with time %d:%.2d\n", mInfo->mHidingTime.mMinutes, mInfo->mHidingTime.mSeconds); } else { - sead::system::DeleteImpl( - curGameInfo); // attempt to destory previous info before creating new one + if (curGameInfo) delete curGameInfo; // attempt to destory previous info before creating new one + + mInfo = GameModeManager::instance()->createModeInfo(); - mInfo = createModeInfo(); - Client::setModeInfo(mInfo); mModeTimer = new GameModeTimer(); } @@ -48,7 +56,6 @@ void HideAndSeekMode::init(const GameModeInitInfo& info) { } void HideAndSeekMode::begin() { - mModeLayout->appear(); mIsFirstFrame = true; @@ -118,10 +125,15 @@ void HideAndSeekMode::update() { if (mInvulnTime >= 5) { if (mainPlayer) { - for (size_t i = 0; i < mPuppetHolder->getSize(); i++) + for (int i = 0; i < mPuppetHolder->getSize(); i++) { PuppetInfo *curInfo = Client::getPuppetInfo(i); + if (!curInfo) { + Logger::log("Checking %d, hit bounds %d-%d\n", i, mPuppetHolder->getSize(), Client::getMaxPlayerCount()); + break; + } + if(curInfo->isConnected && curInfo->isInSameStage && curInfo->isIt) { float pupDist = al::calcDistance(mainPlayer, curInfo->playerPos); // TODO: remove distance calculations and use hit sensors to determine this diff --git a/source/states/StageSceneStateServerConfig.cpp b/source/states/StageSceneStateServerConfig.cpp index c4eeb51..0528166 100644 --- a/source/states/StageSceneStateServerConfig.cpp +++ b/source/states/StageSceneStateServerConfig.cpp @@ -12,8 +12,10 @@ #include "prim/seadStringUtil.h" #include "rs/util/InputUtil.h" #include "server/gamemode/GameModeBase.hpp" +#include "server/gamemode/GameModeConfigMenuFactory.hpp" #include "server/gamemode/GameModeFactory.hpp" -#include "server/HideAndSeekMode.hpp" +#include "server/gamemode/GameModeManager.hpp" +#include "server/hns/HideAndSeekMode.hpp" StageSceneStateServerConfig::StageSceneStateServerConfig(const char *name, al::Scene *scene, const al::LayoutInitInfo &initInfo, FooterParts *footerParts, GameDataHolder *dataHolder, bool) : al::HostStateBase(name, scene) { mFooterParts = footerParts; @@ -64,19 +66,23 @@ StageSceneStateServerConfig::StageSceneStateServerConfig(const char *name, al::S mModeSelectList->addStringData(modeSelectOptions->mBuffer, "TxtContent"); // gamemode config menu - mGamemodeConfig = new SimpleLayoutMenu("GameModeConfigMenu", "OptionSelect", initInfo, 0, false); - mGameModeConfigList = new CommonVerticalList(mGamemodeConfig, initInfo, true); + GameModeConfigMenuFactory factory("GameModeConfigFactory"); + for (int mode = 0; mode < factory.getMenuCount(); mode++) { + GameModeEntry& entry = mGamemodeConfigMenus[mode]; + const char* name = factory.getMenuName(mode); + entry.mMenu = factory.getCreator(name)(name); + entry.mLayout = new SimpleLayoutMenu("GameModeConfigMenu", "OptionSelect", initInfo, 0, false); + entry.mList = new CommonVerticalList(entry.mLayout, initInfo, true); - al::setPaneString(mGamemodeConfig, "TxtOption", u"Gamemode Configuration", 0); + al::setPaneString(entry.mLayout, "TxtOption", u"Gamemode Configuration", 0); - mGamemodeConfigMenu = Client::tryCreateModeMenu(); + entry.mList->initDataNoResetSelected(entry.mMenu->getMenuSize()); - if (mGamemodeConfigMenu) { - mGameModeConfigList->initDataNoResetSelected(mGamemodeConfigMenu->getMenuSize()); - mGameModeConfigList->addStringData(mGamemodeConfigMenu->getStringData(), "TxtContent"); + entry.mList->addStringData(entry.mMenu->getStringData(), "TxtContent"); } + mCurrentList = mMainOptionsList; mCurrentMenu = mMainOptions; } @@ -224,15 +230,16 @@ void StageSceneStateServerConfig::exeRestartServer() { void StageSceneStateServerConfig::exeGamemodeConfig() { if (al::isFirstStep(this)) { - mCurrentList = mGameModeConfigList; - mCurrentMenu = mGamemodeConfig; + mGamemodeConfigMenu = &mGamemodeConfigMenus[GameModeManager::instance()->getGameMode()]; + mCurrentList = mGamemodeConfigMenu->mList; + mCurrentMenu = mGamemodeConfigMenu->mLayout; subMenuStart(); } subMenuUpdate(); if (mIsDecideConfig && mCurrentList->isDecideEnd()) { - if (mGamemodeConfigMenu->updateMenu(mCurrentList->mCurSelected)) { + if (mGamemodeConfigMenu->mMenu->updateMenu(mCurrentList->mCurSelected)) { endSubMenu(); } } @@ -252,7 +259,7 @@ void StageSceneStateServerConfig::exeGamemodeSelect() { if (mIsDecideConfig && mCurrentList->isDecideEnd()) { Logger::log("Setting Server Mode to: %d\n", mCurrentList->mCurSelected); - Client::setServerMode(static_cast(mCurrentList->mCurSelected)); + GameModeManager::instance()->setMode(static_cast(mCurrentList->mCurSelected)); endSubMenu(); } }