diff --git a/.github/actions/build/action.yml b/.github/actions/build/action.yml index 9adf5e3..0790503 100644 --- a/.github/actions/build/action.yml +++ b/.github/actions/build/action.yml @@ -6,6 +6,10 @@ inputs: description : 'version tag' required : false default : '' + prefix: + description : 'filename prefix' + required : false + default : '' outputs: @@ -24,7 +28,7 @@ runs: run: | VERS=${{ inputs.tag }} echo "::set-output name=version::${VERS:1}" - echo "::set-output name=filename::SMO_Online${{ (inputs.tag != '' && format('_{0}', inputs.tag)) || '' }}" + echo "::set-output name=filename::${{ inputs.prefix }}SMO_Online${{ (inputs.tag != '' && format('_{0}', inputs.tag)) || '' }}" - name : Set up Docker Buildx uses : docker/setup-buildx-action@v2 diff --git a/.github/actions/release/action.yml b/.github/actions/release/action.yml index e0d5576..81916a5 100644 --- a/.github/actions/release/action.yml +++ b/.github/actions/release/action.yml @@ -30,7 +30,7 @@ runs: GITHUB_TOKEN: ${{ inputs.GITHUB_TOKEN }} with: tag_name : ${{ inputs.tag }} - release_name : Release ${{ inputs.tag }} + release_name : ${{ inputs.tag }} body : '' draft : true prerelease : false diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index f954ed7..893e378 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -5,9 +5,13 @@ on: push: branches: - '**' + - '!dev' tags: - '**' - '!v[0-9]+.[0-9]+.[0-9]+' + - '!v[0-9]+.[0-9]+.[0-9]+\+*' + - '!v[0-9]+.[0-9]+.[0-9]+-*' + - '!latest-dev' pull_request: branches: - '**' diff --git a/.github/workflows/dev-release.yml b/.github/workflows/dev-release.yml new file mode 100644 index 0000000..4051a44 --- /dev/null +++ b/.github/workflows/dev-release.yml @@ -0,0 +1,77 @@ +name: Dev Release + + +on: + push: + branches: + - 'dev' + + +env: + TAG : 'latest-dev' + + +concurrency: + group: ${{ github.workflow }} + cancel-in-progress: true + + +jobs: + + build: + runs-on: ubuntu-latest + outputs: + filename: ${{ steps.build.outputs.filename }} + steps: + - + name : Checkout + uses : actions/checkout@v3 + - + name : Environment + id : env + shell : bash + run: | + echo "::set-output name=prefix::$(date +'%Y%m%d_%H%M%S_' --utc)" + - + name : Build artifacts + id : build + uses : ./.github/actions/build + with: + prefix : ${{ steps.env.outputs.prefix }} + + attach: + needs: build + runs-on: ubuntu-latest + steps: + - + name : Checkout + uses : actions/checkout@v3 + - + name : Get release info + id : release + shell : bash + run: | + url=`curl -sS --fail ${{ github.api_url }}/repos/${{ github.repository }}/releases/tags/${{ env.TAG }} | jq .upload_url -r` + echo "::set-output name=upload_url::$url" + - + name : Attach build artifacts to release + uses : ./.github/actions/attach + with: + filename : ${{ needs.build.outputs.filename }} + upload_url : ${{ steps.release.outputs.upload_url }} + GITHUB_TOKEN : ${{ secrets.GITHUB_TOKEN }} + + move: + needs: attach + runs-on: ubuntu-latest + steps: + - + name : Checkout + uses : actions/checkout@v3 + - + name : Move ${{ env.TAG }} tag + shell : bash + run: | + git config user.email "${{ github.actor }}@users.noreply.github.com" + git tag -f ${{ env.TAG }} + git push --force origin ${{ env.TAG }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 00c84b6..3def7de 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -5,6 +5,8 @@ on: push: tags: - 'v[0-9]+.[0-9]+.[0-9]+' + - 'v[0-9]+.[0-9]+.[0-9]+\+*' + - 'v[0-9]+.[0-9]+.[0-9]+-*' jobs: diff --git a/.gitignore b/.gitignore index d5fd286..02fd517 100644 --- a/.gitignore +++ b/.gitignore @@ -5,5 +5,6 @@ romfs stuff/** Crash Reports/** .cache/** Custom Stage Builds/** +*.lst compile_commands.json diff --git a/Makefile b/Makefile index 9c8c846..d1b8bfa 100644 --- a/Makefile +++ b/Makefile @@ -4,17 +4,19 @@ .PHONY: all clean starlight send SMOVER ?= 100 -BUILDVER ?= 99.37 -IP ?= 10.0.0.221 +BUILDVER ?= 101 +BUILDVERSTR ?= 1.0.1 +IP ?= 10.0.0.221 # ftp server ip (usually is switch's local IP) DEBUGLOG ?= 0 # defaults to disable debug logger SERVERIP ?= 0.0.0.0 # put debug logger server IP here +ISEMU ?= 0 # set to 1 to compile for emulators PROJNAME ?= StarlightBase all: starlight starlight: - $(MAKE) all -f MakefileNSO SMOVER=$(SMOVER) BUILDVER=$(BUILDVER) DEBUGLOG=$(DEBUGLOG) SERVERIP=${SERVERIP} + $(MAKE) all -f MakefileNSO SMOVER=$(SMOVER) BUILDVERSTR=$(BUILDVERSTR) BUILDVER=$(BUILDVER) DEBUGLOG=$(DEBUGLOG) SERVERIP=${SERVERIP} EMU=${ISEMU} $(MAKE) starlight_patch_$(SMOVER)/*.ips mkdir -p starlight_patch_$(SMOVER)/atmosphere/exefs_patches/$(PROJNAME)/ @@ -23,15 +25,17 @@ starlight: mv starlight_patch_$(SMOVER)/3CA12DFAAF9C82DA064D1698DF79CDA1.ips starlight_patch_$(SMOVER)/atmosphere/exefs_patches/$(PROJNAME)/3CA12DFAAF9C82DA064D1698DF79CDA1.ips mv $(shell basename $(CURDIR))$(SMOVER).elf starlight_patch_$(SMOVER)/subsdk1.elf mv $(shell basename $(CURDIR))$(SMOVER).nso starlight_patch_$(SMOVER)/atmosphere/contents/0100000000010000/exefs/subsdk1 + + cp -R romfs starlight_patch_$(SMOVER)/atmosphere/contents/0100000000010000 starlight_patch_$(SMOVER)/*.ips: patches/*.slpatch patches/configs/$(SMOVER).config patches/maps/$(SMOVER)/*.map \ build$(SMOVER)/$(shell basename $(CURDIR))$(SMOVER).map scripts/genPatch.py @rm -f starlight_patch_$(SMOVER)/*.ips python3 scripts/genPatch.py $(SMOVER) -# builds project with the file structure used in the yuzu emulator -yuzu: - $(MAKE) all -f MakefileNSO SMOVER=$(SMOVER) BUILDVER=$(BUILDVER) +# builds project with the file structure and flags used for emulators +emu: + $(MAKE) all -f MakefileNSO SMOVER=$(SMOVER) BUILDVERSTR=$(BUILDVERSTR) BUILDVER=$(BUILDVER) EMU=1 $(MAKE) starlight_patch_$(SMOVER)/*.ips mkdir -p starlight_patch_$(SMOVER)/yuzu/ diff --git a/MakefileNSO b/MakefileNSO index e37bcfe..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 +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 @@ -44,14 +44,14 @@ ARCH := -march=armv8-a -mtune=cortex-a57 -mtp=soft -fPIC -ftls-model=local-exec CFLAGS := -g -Wall -ffunction-sections \ $(ARCH) $(DEFINES) -CFLAGS += $(INCLUDE) -D__SWITCH__ -DSMOVER=$(SMOVER) -O3 -DNNSDK -DSWITCH -DBUILDVER=$(BUILDVER) -DDEBUGLOG=$(DEBUGLOG) -DSERVERIP=$(SERVERIP) +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 -LIBS := -lnx +LIBS := #--------------------------------------------------------------------------------- # list of directories containing libraries, this must be the top level containing diff --git a/include/Keyboard.hpp b/include/Keyboard.hpp index 003d339..4553645 100644 --- a/include/Keyboard.hpp +++ b/include/Keyboard.hpp @@ -7,14 +7,15 @@ #include "nn/swkbd/swkbd.h" #include "logger.hpp" -#include "sead/prim/seadSafeString.h" + +typedef void (*KeyboardSetup)(nn::swkbd::KeyboardConfig&); class Keyboard { public: Keyboard(ulong strSize); void keyboardThread(); - void openKeyboard(const char* initialText); + void openKeyboard(const char* initialText, KeyboardSetup setup); const char* getResult() { if (mThread->isDone()) { @@ -23,6 +24,8 @@ class Keyboard { return nullptr; }; + bool isKeyboardCancelled() const { return mIsCancelled; } + bool isThreadDone() { return mThread->isDone(); } void setHeaderText(const char16_t* text) { mHeaderText = text; } @@ -33,12 +36,13 @@ class Keyboard { al::AsyncFunctorThread* mThread; nn::swkbd::String mResultString; - bool mIsDoneKeyboard; - - sead::FixedSafeString<0x10> mInitialText; + hostname mInitialText; + KeyboardSetup mSetupFunc; const char16_t *mHeaderText = u"Enter Server IP Here!"; - const char16_t *mSubText = u"Must be a Valid Address."; + const char16_t* mSubText = u"Must be a Valid Address."; + + bool mIsCancelled = false; char* mWorkBuf; int mWorkBufSize; @@ -46,4 +50,4 @@ class Keyboard { int mTextCheckSize; char* mCustomizeDicBuf; int mCustomizeDicSize; -}; \ No newline at end of file +}; diff --git a/include/SocketBase.hpp b/include/SocketBase.hpp index 622b4c0..02feca5 100644 --- a/include/SocketBase.hpp +++ b/include/SocketBase.hpp @@ -12,16 +12,17 @@ class SocketBase { SocketBase(const char *name); virtual nn::Result init(const char * ip, u16 port) = 0; + virtual bool closeSocket(); const char *getStateChar(); u8 getLogState(); - s32 getSocket(); + s32 getFd(); void set_sock_flags(int flags); - bool closeSocket(); void setName(const char *name) {strcpy(sockName, name);}; + u32 socket_errno; protected: s32 socket_log(const char* str); @@ -31,9 +32,9 @@ class SocketBase { const char *sock_ip; u16 port; - u8 socket_log_state; + u8 socket_log_state = SOCKET_LOG_UNINITIALIZED; s32 socket_log_socket; - + int sock_flags; }; diff --git a/include/actors/PuppetActor.h b/include/actors/PuppetActor.h index e6ed730..b10868b 100644 --- a/include/actors/PuppetActor.h +++ b/include/actors/PuppetActor.h @@ -33,6 +33,15 @@ class PuppetActor : public al::LiveActor { virtual void movement(void) override; virtual void makeActorAlive(void) override; virtual void makeActorDead(void) override; + + virtual void attackSensor(al::HitSensor *, al::HitSensor *) override; + virtual bool receiveMsg(const al::SensorMsg*, al::HitSensor*, al::HitSensor*) override; + + virtual const char* getName() const override { + if (mInfo) + return mInfo->puppetName; + return mActorName; + } void initOnline(PuppetInfo *pupInfo); @@ -47,8 +56,6 @@ class PuppetActor : public al::LiveActor { PuppetInfo* getInfo() { return mInfo; } - const char *getPuppetName() { return mInfo->puppetName; } - bool addCapture(PuppetHackActor *capture, const char *hackType); al::LiveActor* getCurrentModel(); @@ -59,27 +66,29 @@ class PuppetActor : public al::LiveActor { void debugTeleportCapture(const sead::Vector3f& pos, int index); - bool mIsDebug = false; + void emitJoinEffect(); - float mClosingSpeed = 0; + bool mIsDebug = false; - NameTag *mNameTag = nullptr; // temp public private: void changeModel(const char* newModel); bool setCapture(const char* captureName); void syncPose(); - + PlayerCostumeInfo *mCostumeInfo = nullptr; PuppetInfo *mInfo = nullptr; PuppetCapActor *mPuppetCap = nullptr; PlayerModelHolder *mModelHolder = nullptr; HackModelHolder* mCaptures = nullptr; + NameTag *mNameTag = nullptr; CaptureTypes::Type mCurCapture = CaptureTypes::Type::Unknown; bool mIs2DModel = false; bool mIsCaptureModel = false; + + float mClosingSpeed = 0; }; diff --git a/include/al/LiveActor/LiveActor.h b/include/al/LiveActor/LiveActor.h index b27b0ca..444eebf 100644 --- a/include/al/LiveActor/LiveActor.h +++ b/include/al/LiveActor/LiveActor.h @@ -61,8 +61,10 @@ namespace al virtual void draw() const; virtual void startClipped(); virtual void endClipped(); - virtual void attackSensor(HitSensor *, HitSensor *); - virtual bool receiveMsg(const SensorMsg *, HitSensor *, HitSensor *); + // source = sensor belonging to this actor + // target = sensor belonging to other actor + virtual void attackSensor(HitSensor *source, HitSensor *target); + virtual bool receiveMsg(const SensorMsg *msg, HitSensor *source, HitSensor *target); virtual bool receiveMsgScreenPoint(const SensorMsg *, ScreenPointer *, ScreenPointTarget *); virtual const char *getName() const { return this->mActorName; }; diff --git a/include/al/PlayerHolder/PlayerHolder.h b/include/al/PlayerHolder/PlayerHolder.h index 068bb93..88be704 100644 --- a/include/al/PlayerHolder/PlayerHolder.h +++ b/include/al/PlayerHolder/PlayerHolder.h @@ -1,5 +1,6 @@ #pragma once +#include "game/Player/PlayerActorBase.h" #include "sead/math/seadVector.h" #include "al/scene/Scene.h" #include "al/LiveActor/LiveActor.h" @@ -15,8 +16,8 @@ namespace al { PlayerHolder(int bufSize); void clear(void); void registerPlayer(al::LiveActor *, al::PadRumbleKeeper *); - PlayerActorHakoniwa *getPlayer(int) const; - PlayerActorHakoniwa *tryGetPlayer(int) const; + PlayerActorBase *getPlayer(int) const; + PlayerActorBase *tryGetPlayer(int) const; int getPlayerNum() const; int getBufferSize() const {return bufferSize;}; bool isFull(void) const; diff --git a/include/al/scene/SceneObjFactory.h b/include/al/scene/SceneObjFactory.h new file mode 100644 index 0000000..eb8a73e --- /dev/null +++ b/include/al/scene/SceneObjFactory.h @@ -0,0 +1,89 @@ +#pragma once + +#include "al/scene/ISceneObj.h" +#include "al/scene/SceneObjHolder.h" +#include "SceneObjs.h" + +al::ISceneObj *sub_4C4300(int objIndex) { + switch (objIndex) + { + case 0: + return new AmiiboNpcDirector(); + case 1: + return new BgmAnimeSyncDirector(); + case 3: + return new CapManHeroDemoDirector(); + case 4: + return new CapMessageDirector(); + case 5: + return new CapMessageMoonNotifier(); + case 7: + return new CoinCollectHolder(); + case 8: + return new CoinCollectWatcher(); + case 9: + return new CollectBgmPlayer(); + case 11: + return new EchoEmitterHolder(); + case 12: + return new ElectricWireCameraTicketHolder(); + case 17: + return new FukankunZoomObjHolder(); + case 21: + return new GrowPlantDirector(); + case 22: + return new GuidePosInfoHolder(); + case 23: + return new HintPhotoLayoutHolder(); + case 26: + return new HtmlViewerRequester(); + case 29: + return new KidsModeLayoutAccessor(); + case 34: + return new LoginLotteryDirector(); + case 36: + return new MoviePlayer(); + case 39: + return new PaintObjHolder(); + case 42: + return new PlayerStartInfoHolder(); + case 44: + return new QuestInfoHolder(64); + case 49: + return new RandomItemSelector(); + case 52: + return nullptr; + case 53: + return new RhyhtmInfoWatcher(""); + case 55: + return new RouteGuideDirector(); + case 56: + return new SceneEventNotifier(); + case 60: + return new al::StageSyncCounter(); + case 62: + return new TalkNpcParamHolder(); + case 63: + return new TalkNpcSceneEventSwitcher(); + case 64: + return new TestStageTimeDirector(); + case 65: + return new TimeBalloonDirector(); + case 70: + return new TsukkunTraceHolder(); + case 71: + return new WipeHolderRequester(); + case 72: + return new YoshiFruitWatcher(); + case 73: + return new HelpAmiiboDirector(); + default: + return nullptr; + } +} + +class SceneObjFactory { +public: + al::SceneObjHolder *createSceneObjHolder(void) { return new al::SceneObjHolder(&sub_4C4300, 0x4A);} +}; + diff --git a/include/al/scene/SceneObjHolder.h b/include/al/scene/SceneObjHolder.h index ddf5afd..951d0d8 100644 --- a/include/al/scene/SceneObjHolder.h +++ b/include/al/scene/SceneObjHolder.h @@ -4,9 +4,11 @@ namespace al { + typedef al::ISceneObj* (*SceneObjCreator)(int); + class SceneObjHolder { public: - SceneObjHolder(al::ISceneObj* (*)(int), int); + SceneObjHolder(SceneObjCreator, int); ISceneObj *tryGetObj(int) const; // unsafe get still void setSceneObj(al::ISceneObj *,int); @@ -15,8 +17,14 @@ namespace al { ISceneObj *getObj(int) const; void create(int); + SceneObjCreator mObjCreator; + al::ISceneObj **mSceneObjs; + int mMaxObjCount; + }; + static_assert(sizeof(SceneObjHolder) == 0x18, "SceneObjHolder Size"); + class IUseSceneObjHolder { public: diff --git a/include/al/scene/SceneObjs.h b/include/al/scene/SceneObjs.h new file mode 100644 index 0000000..5bf9925 --- /dev/null +++ b/include/al/scene/SceneObjs.h @@ -0,0 +1,179 @@ +#pragma once + +#include "al/scene/ISceneObj.h" +#include "al/scene/SceneObjHolder.h" +#include "game/SceneObjs/RouteGuideDirector.h" + +// temp header to cleanup SceneObjFactory + +namespace al { + struct StageSyncCounter : public al::ISceneObj { + virtual const char* getSceneObjName() override; + virtual void initAfterPlacementSceneObj(al::ActorInitInfo const&) override; + virtual void initSceneObj(void) override; + }; +} + +struct AmiiboNpcDirector : public al::ISceneObj { + virtual const char* getSceneObjName() override; + virtual void initAfterPlacementSceneObj(al::ActorInitInfo const&) override; + virtual void initSceneObj(void) override; +}; +struct BgmAnimeSyncDirector : public al::ISceneObj { + virtual const char* getSceneObjName() override; + virtual void initAfterPlacementSceneObj(al::ActorInitInfo const&) override; + virtual void initSceneObj(void) override; +}; +struct CapManHeroDemoDirector : public al::ISceneObj { + virtual const char* getSceneObjName() override; + virtual void initAfterPlacementSceneObj(al::ActorInitInfo const&) override; + virtual void initSceneObj(void) override; +}; +struct CapMessageDirector : public al::ISceneObj { + virtual const char* getSceneObjName() override; + virtual void initAfterPlacementSceneObj(al::ActorInitInfo const&) override; + virtual void initSceneObj(void) override; +}; +struct CapMessageMoonNotifier : public al::ISceneObj { + virtual const char* getSceneObjName() override; + virtual void initAfterPlacementSceneObj(al::ActorInitInfo const&) override; + virtual void initSceneObj(void) override; +}; +struct CoinCollectHolder : public al::ISceneObj { + virtual const char* getSceneObjName() override; + virtual void initAfterPlacementSceneObj(al::ActorInitInfo const&) override; + virtual void initSceneObj(void) override; +}; +struct CoinCollectWatcher : public al::ISceneObj { + virtual const char* getSceneObjName() override; + virtual void initAfterPlacementSceneObj(al::ActorInitInfo const&) override; + virtual void initSceneObj(void) override; +}; +struct CollectBgmPlayer : public al::ISceneObj { + virtual const char* getSceneObjName() override; + virtual void initAfterPlacementSceneObj(al::ActorInitInfo const&) override; + virtual void initSceneObj(void) override; +}; +struct EchoEmitterHolder : public al::ISceneObj { + virtual const char* getSceneObjName() override; + virtual void initAfterPlacementSceneObj(al::ActorInitInfo const&) override; + virtual void initSceneObj(void) override; +}; +struct ElectricWireCameraTicketHolder : public al::ISceneObj { + virtual const char* getSceneObjName() override; + virtual void initAfterPlacementSceneObj(al::ActorInitInfo const&) override; + virtual void initSceneObj(void) override; +}; +struct FukankunZoomObjHolder : public al::ISceneObj { + virtual const char* getSceneObjName() override; + virtual void initAfterPlacementSceneObj(al::ActorInitInfo const&) override; + virtual void initSceneObj(void) override; +}; +struct GrowPlantDirector : public al::ISceneObj { + virtual const char* getSceneObjName() override; + virtual void initAfterPlacementSceneObj(al::ActorInitInfo const&) override; + virtual void initSceneObj(void) override; +}; +struct GuidePosInfoHolder : public al::ISceneObj { + virtual const char* getSceneObjName() override; + virtual void initAfterPlacementSceneObj(al::ActorInitInfo const&) override; + virtual void initSceneObj(void) override; +}; +struct HintPhotoLayoutHolder : public al::ISceneObj { + virtual const char* getSceneObjName() override; + virtual void initAfterPlacementSceneObj(al::ActorInitInfo const&) override; + virtual void initSceneObj(void) override; +}; +struct HtmlViewerRequester : public al::ISceneObj { + virtual const char* getSceneObjName() override; + virtual void initAfterPlacementSceneObj(al::ActorInitInfo const&) override; + virtual void initSceneObj(void) override; +}; +struct KidsModeLayoutAccessor : public al::ISceneObj { + virtual const char* getSceneObjName() override; + virtual void initAfterPlacementSceneObj(al::ActorInitInfo const&) override; + virtual void initSceneObj(void) override; +}; +struct LoginLotteryDirector : public al::ISceneObj { + virtual const char* getSceneObjName() override; + virtual void initAfterPlacementSceneObj(al::ActorInitInfo const&) override; + virtual void initSceneObj(void) override; +}; +struct MoviePlayer : public al::ISceneObj { + virtual const char* getSceneObjName() override; + virtual void initAfterPlacementSceneObj(al::ActorInitInfo const&) override; + virtual void initSceneObj(void) override; +}; +struct PaintObjHolder : public al::ISceneObj { + virtual const char* getSceneObjName() override; + virtual void initAfterPlacementSceneObj(al::ActorInitInfo const&) override; + virtual void initSceneObj(void) override; +}; +struct PlayerStartInfoHolder : public al::ISceneObj { + virtual const char* getSceneObjName() override; + virtual void initAfterPlacementSceneObj(al::ActorInitInfo const&) override; + virtual void initSceneObj(void) override; +}; +struct RandomItemSelector : public al::ISceneObj { + virtual const char* getSceneObjName() override; + virtual void initAfterPlacementSceneObj(al::ActorInitInfo const&) override; + virtual void initSceneObj(void) override; +}; +struct SceneEventNotifier : public al::ISceneObj { + virtual const char* getSceneObjName() override; + virtual void initAfterPlacementSceneObj(al::ActorInitInfo const&) override; + virtual void initSceneObj(void) override; +}; +struct TalkNpcParamHolder : public al::ISceneObj { + virtual const char* getSceneObjName() override; + virtual void initAfterPlacementSceneObj(al::ActorInitInfo const&) override; + virtual void initSceneObj(void) override; +}; +struct TalkNpcSceneEventSwitcher : public al::ISceneObj { + virtual const char* getSceneObjName() override; + virtual void initAfterPlacementSceneObj(al::ActorInitInfo const&) override; + virtual void initSceneObj(void) override; +}; +struct TestStageTimeDirector : public al::ISceneObj { + virtual const char* getSceneObjName() override; + virtual void initAfterPlacementSceneObj(al::ActorInitInfo const&) override; + virtual void initSceneObj(void) override; +}; +struct TimeBalloonDirector : public al::ISceneObj { + virtual const char* getSceneObjName() override; + virtual void initAfterPlacementSceneObj(al::ActorInitInfo const&) override; + virtual void initSceneObj(void) override; +}; +struct TsukkunTraceHolder : public al::ISceneObj { + virtual const char* getSceneObjName() override; + virtual void initAfterPlacementSceneObj(al::ActorInitInfo const&) override; + virtual void initSceneObj(void) override; +}; +struct WipeHolderRequester : public al::ISceneObj { + virtual const char* getSceneObjName() override; + virtual void initAfterPlacementSceneObj(al::ActorInitInfo const&) override; + virtual void initSceneObj(void) override; +}; +struct YoshiFruitWatcher : public al::ISceneObj { + virtual const char* getSceneObjName() override; + virtual void initAfterPlacementSceneObj(al::ActorInitInfo const&) override; + virtual void initSceneObj(void) override; +}; +struct HelpAmiiboDirector : public al::ISceneObj { + virtual const char* getSceneObjName() override; + virtual void initAfterPlacementSceneObj(al::ActorInitInfo const&) override; + virtual void initSceneObj(void) override; +}; + +struct QuestInfoHolder : public al::ISceneObj { + QuestInfoHolder(int); + virtual const char* getSceneObjName() override; + virtual void initAfterPlacementSceneObj(al::ActorInitInfo const&) override; + virtual void initSceneObj(void) override; +}; +struct RhyhtmInfoWatcher : public al::ISceneObj { + RhyhtmInfoWatcher(const char*); + virtual const char* getSceneObjName() override; + virtual void initAfterPlacementSceneObj(al::ActorInitInfo const&) override; + virtual void initSceneObj(void) override; +}; \ No newline at end of file diff --git a/include/al/sensor/HitSensorKeeper.h b/include/al/sensor/HitSensorKeeper.h index 03edf6d..9771950 100644 --- a/include/al/sensor/HitSensorKeeper.h +++ b/include/al/sensor/HitSensorKeeper.h @@ -1,7 +1,6 @@ #pragma once #include "types.h" -#include "al/LiveActor/LiveActor.h" #include "al/sensor/SensorHitGroup.h" #include "sead/math/seadVector.h" #include "sead/math/seadMatrix.h" @@ -9,6 +8,9 @@ namespace al { + + class LiveActor; + class HitSensorKeeper { public: diff --git a/include/al/util.hpp b/include/al/util.hpp index 3ef495d..527285b 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); @@ -242,7 +245,7 @@ namespace al bool tryGetByamlColor(sead::Color4f *,al::ByamlIter const&); bool tryGetByamlColor(sead::Color4f *,al::ByamlIter const&,char const*); bool tryGetByamlBool(bool *,al::ByamlIter const&,char const*); - bool tryGetByamlKeyStringOrNULL(al::ByamlIter const&,char const*); + const char * tryGetByamlKeyStringOrNULL(al::ByamlIter const&,char const*); bool tryGetByamlKeyIntOrZero(al::ByamlIter const&,char const*); bool tryGetByamlKeyU32OrZero(al::ByamlIter const&,char const*); bool tryGetByamlKeyFloatOrZero(al::ByamlIter const&,char const*); diff --git a/include/al/util/LiveActorUtil.h b/include/al/util/LiveActorUtil.h index ace88f8..7c42255 100644 --- a/include/al/util/LiveActorUtil.h +++ b/include/al/util/LiveActorUtil.h @@ -7,6 +7,7 @@ #include "al/LiveActor/LiveActor.h" #include "al/async/FunctorBase.h" #include "al/collision/Collider.h" +#include "game/Player/PlayerActorBase.h" #include "game/Player/PlayerActorHakoniwa.h" #include "al/layout/LayoutActor.h" #include "al/layout/LayoutInitInfo.h" @@ -29,7 +30,7 @@ namespace al { void startAction(LiveActor*, char const*); void startAction(IUseLayoutAction*, const char *, const char *); void startFreezeActionEnd(IUseLayoutAction *,char const*,char const*); - void startHitReaction(LiveActor*, char const*); + void startHitReaction(const LiveActor *, char const*); void invalidateClipping(const LiveActor *); void validateClipping(const LiveActor *); void setNerveAtActionEnd(LiveActor*, const al::Nerve*); @@ -91,7 +92,7 @@ namespace al { bool tryOnSwitchDeadOn(IUseStageSwitch *); bool trySyncStageSwitchAppear(LiveActor *); - PlayerActorHakoniwa* tryFindNearestPlayerActor(const LiveActor *); + PlayerActorBase* tryFindNearestPlayerActor(const LiveActor *); bool tryFindNearestPlayerPos(sead::Vector3f *, const LiveActor *); bool tryAddRippleMiddle(LiveActor*); bool tryStartActionIfNotPlaying(LiveActor*, const char*); diff --git a/include/al/util/SensorUtil.h b/include/al/util/SensorUtil.h new file mode 100644 index 0000000..684645d --- /dev/null +++ b/include/al/util/SensorUtil.h @@ -0,0 +1,480 @@ +#pragma once + +#include "al/sensor/HitSensor.h" +#include "al/sensor/HitSensorKeeper.h" +#include "al/sensor/SensorHitGroup.h" + +#include "al/LiveActor/LiveActor.h" // for SensorMsg + +#include + +struct SaveObjInfo; +struct HackEndParam; +struct IUsePlayerCollision; +struct IUsePlayerHack; + +struct DigPoint; +struct TouchTargetInfo; +struct WhipTargetInfo; +struct CapTargetInfo; +struct GotogotonMark; +struct FishingFish; + +typedef unsigned int uint; + +namespace al +{ + + struct ComboCounter; + struct EventFlowExecutor; + struct ParabolicPath; + + sead::Vector3f *getSensorPos(al::HitSensor const *); + sead::Vector3f* getActorTrans(al::HitSensor const*); + + bool tryReceiveMsgPushAndAddVelocity(al::LiveActor*, al::SensorMsg const*, al::HitSensor const*, + al::HitSensor const*, float); + + bool isSensorTypeYoshiEnableSendPush(al::HitSensor const*); + bool isSensorTypeYoshiMsgReceivable(al::HitSensor const*); + bool isSensorValid(al::HitSensor const*); + bool isSensorName(al::HitSensor const*, char const*); + bool isSensorHostName(al::HitSensor const*, char const*); + bool isSensorHost(al::HitSensor const*, al::LiveActor const*); + bool isSensorValid(al::LiveActor const*, char const*); + bool isSensorBindableAll(al::HitSensor const*); + bool isSensorEnemy(al::HitSensor const*); + bool isSensorEnemyAttack(al::HitSensor const*); + bool isSensorEnemyBody(al::HitSensor const*); + bool isSensorEye(al::HitSensor const*); + bool isSensorMapObj(al::HitSensor const*); + bool isSensorNpc(al::HitSensor const*); + bool isSensorPlayerAll(al::HitSensor const*); + bool isSensorRide(al::HitSensor const*); + bool isSensorPlayerAttack(al::HitSensor const*); + bool isSensorPlayer(al::HitSensor const*); + bool isSensorPlayerFoot(al::HitSensor const*); + bool isSensorPlayerDecoration(al::HitSensor const*); + bool isSensorPlayerEye(al::HitSensor const*); + bool isSensorPlayerOrPlayerWeapon(al::HitSensor const*); + bool isSensorCollision(al::HitSensor const*); + bool isSensorPlayerFireBall(al::HitSensor const*); + bool isSensorHoldObj(al::HitSensor const*); + bool isSensorLookAt(al::HitSensor const*); + bool isSensorBindableGoal(al::HitSensor const*); + bool isSensorBindableAllPlayer(al::HitSensor const*); + bool isSensorBindableBubbleOutScreen(al::HitSensor const*); + bool isSensorBindableKoura(al::HitSensor const*); + bool isSensorBindableRouteDokan(al::HitSensor const*); + bool isSensorBindableBubblePadInput(al::HitSensor const*); + bool isSensorBindable(al::HitSensor const*); + bool isSensorSimple(al::HitSensor const*); + bool isSensorHitAnyPlane(al::HitSensor const*,al::HitSensor const*, sead::Vector3 const&); + bool isSensorHitRingShape(al::HitSensor const*, al::HitSensor const*, float); + + bool isMsgRequestPlayerStainWet(al::SensorMsg const *, int *); + bool isMsgPushAll(al::SensorMsg const *); + bool isMsgPush(al::SensorMsg const *); + bool isMsgPushStrong(al::SensorMsg const *); + bool isMsgPushVeryStrong(al::SensorMsg const *); + bool isMsgHoldReleaseAll(al::SensorMsg const *); + bool isMsgHoldCancel(al::SensorMsg const *); + bool isMsgPlayerRelease(al::SensorMsg const *); + bool isMsgPlayerReleaseBySwing(al::SensorMsg const *); + bool isMsgPlayerReleaseDead(al::SensorMsg const *); + bool isMsgPlayerReleaseDamage(al::SensorMsg const *); + bool isMsgPlayerReleaseDemo(al::SensorMsg const *); + bool isMsgItemGetDirectAll(al::SensorMsg const *); + bool isMsgPlayerItemGet(al::SensorMsg const *); + bool isMsgRideAllPlayerItemGet(al::SensorMsg const *); + bool isMsgPlayerTailAttack(al::SensorMsg const *); + bool isMsgItemGetByObjAll(al::SensorMsg const *); + bool isMsgBallItemGet(al::SensorMsg const *); + bool isMsgKickKouraItemGet(al::SensorMsg const *); + bool isMsgKillerItemGet(al::SensorMsg const *); + bool isMsgItemGetAll(al::SensorMsg const *); + bool isMsgFloorTouch(al::SensorMsg const *); + bool isMsgPlayerFloorTouch(al::SensorMsg const *); + bool isMsgEnemyFloorTouch(al::SensorMsg const *); + bool isMsgUpperPunch(al::SensorMsg const *); + bool isMsgPlayerUpperPunch(al::SensorMsg const *); + bool isMsgEnemyUpperPunch(al::SensorMsg const *); + bool isMsgPlayerTrample(al::SensorMsg const *); + bool isMsgPlayerTrampleReflect(al::SensorMsg const *); + bool isMsgPlayerHipDropAll(al::SensorMsg const *); + bool isMsgPlayerStatueDrop(al::SensorMsg const *); + bool isMsgPlayerObjHipDropAll(al::SensorMsg const *); + bool isMsgPlayerObjStatueDrop(al::SensorMsg const *); + bool isMsgPlayerObjHipDropReflectAll(al::SensorMsg const *); + bool isMsgPlayerObjStatueDropReflect(al::SensorMsg const *); + bool isMsgPlayerObjHipDropHighJump(al::SensorMsg const *); + bool isMsgPlayerHipDropKnockDown(al::SensorMsg const *); + bool isMsgPlayerObjStatueDropReflectNoCondition(al::SensorMsg const *); + bool isMsgPlayerStatueTouch(al::SensorMsg const *); + bool isMsgPlayerObjUpperPunch(al::SensorMsg const *); + bool isMsgPlayerRollingAttack(al::SensorMsg const *); + bool isMsgPlayerRollingReflect(al::SensorMsg const *); + bool isMsgPlayerObjRollingAttack(al::SensorMsg const *); + bool isMsgPlayerObjRollingAttackFailure(al::SensorMsg const *); + bool isMsgPlayerInvincibleAttack(al::SensorMsg const *); + bool isMsgPlayerFireBallAttack(al::SensorMsg const *); + bool isMsgPlayerRouteDokanFireBallAttack(al::SensorMsg const *); + bool isMsgPlayerKick(al::SensorMsg const *); + bool isMsgPlayerCatch(al::SensorMsg const *); + bool isMsgPlayerSlidingAttack(al::SensorMsg const *); + bool isMsgPlayerBoomerangAttack(al::SensorMsg const *); + bool isMsgPlayerBoomerangAttackCollide(al::SensorMsg const *); + bool isMsgPlayerBoomerangReflect(al::SensorMsg const *); + bool isMsgPlayerBoomerangBreak(al::SensorMsg const *); + bool isMsgPlayerBodyAttack(al::SensorMsg const *); + bool isMsgPlayerBodyLanding(al::SensorMsg const *); + bool isMsgPlayerBodyAttackReflect(al::SensorMsg const *); + bool isMsgPlayerClimbAttack(al::SensorMsg const *); + bool isMsgPlayerSpinAttack(al::SensorMsg const *); + bool isMsgPlayerGiantAttack(al::SensorMsg const *); + bool isMsgPlayerCooperationHipDrop(al::SensorMsg const *); + bool isMsgPlayerClimbSlidingAttack(al::SensorMsg const *); + bool isMsgPlayerClimbRollingAttack(al::SensorMsg const *); + bool isMsgPlayerGiantHipDrop(al::SensorMsg const *); + bool isMsgPlayerDisregard(al::SensorMsg const *); + bool isMsgPlayerDash(al::SensorMsg const *); + bool isMsgPlayerDamageTouch(al::SensorMsg const *); + bool isMsgPlayerFloorTouchBind(al::SensorMsg const *); + bool isMsgPlayerTouch(al::SensorMsg const *); + bool isMsgPlayerInvincibleTouch(al::SensorMsg const *); + bool isMsgPlayerGiantTouch(al::SensorMsg const *); + bool isMsgPlayerObjTouch(al::SensorMsg const *); + bool isMsgPlayerPutOnEquipment(al::SensorMsg const *); + bool isMsgPlayerReleaseEquipment(al::SensorMsg const *); + bool isMsgPlayerReleaseEquipmentGoal(al::SensorMsg const *); + bool isMsgPlayerCarryFront(al::SensorMsg const *); + bool isMsgPlayerCarryFrontWallKeep(al::SensorMsg const *); + bool isMsgPlayerCarryUp(al::SensorMsg const *); + bool isMsgPlayerCarryKeepDemo(al::SensorMsg const *); + bool isMsgPlayerCarryWarp(al::SensorMsg const *); + bool isMsgPlayerLeave(al::SensorMsg const *); + bool isMsgPlayerToss(al::SensorMsg const *); + bool isMsgEnemyAttack(al::SensorMsg const *); + bool isMsgEnemyAttackFire(al::SensorMsg const *); + bool isMsgEnemyAttackKnockDown(al::SensorMsg const *); + bool isMsgEnemyAttackBoomerang(al::SensorMsg const *); + bool isMsgEnemyAttackNeedle(al::SensorMsg const *); + bool isMsgEnemyItemGet(al::SensorMsg const *); + bool isMsgEnemyRouteDokanAttack(al::SensorMsg const *); + bool isMsgEnemyRouteDokanFire(al::SensorMsg const *); + bool isMsgExplosion(al::SensorMsg const *); + bool isMsgExplosionCollide(al::SensorMsg const *); + bool isMsgBindStart(al::SensorMsg const *); + bool isMsgBindInit(al::SensorMsg const *); + bool isMsgBindEnd(al::SensorMsg const *); + bool isMsgBindCancel(al::SensorMsg const *); + bool isMsgBindCancelByDemo(al::SensorMsg const *); + bool isMsgBindDamage(al::SensorMsg const *); + bool isMsgBindSteal(al::SensorMsg const *); + bool isMsgBindGiant(al::SensorMsg const *); + bool isMsgPressureDeath(al::SensorMsg const *); + bool isMsgNpcTouch(al::SensorMsg const *); + bool isMsgHit(al::SensorMsg const *); + bool isMsgHitStrong(al::SensorMsg const *); + bool isMsgHitVeryStrong(al::SensorMsg const *); + bool isMsgKnockDown(al::SensorMsg const *); + bool isMsgMapPush(al::SensorMsg const *); + bool isMsgVanish(al::SensorMsg const *); + bool isMsgChangeAlpha(al::SensorMsg const *); + bool isMsgShowModel(al::SensorMsg const *); + bool isMsgHideModel(al::SensorMsg const *); + bool isMsgRestart(al::SensorMsg const *); + bool isMsgEnemyTouch(al::SensorMsg const *); + bool isMsgEnemyTrample(al::SensorMsg const *); + bool isMsgMapObjTrample(al::SensorMsg const *); + bool isMsgNeedleBallAttack(al::SensorMsg const *); + bool isMsgPunpunFloorTouch(al::SensorMsg const *); + bool isMsgInvalidateFootPrint(al::SensorMsg const *); + bool isMsgKickKouraAttack(al::SensorMsg const *); + bool isMsgKickKouraAttackCollide(al::SensorMsg const *); + bool isMsgKickKouraReflect(al::SensorMsg const *); + bool isMsgKickKouraCollideNoReflect(al::SensorMsg const *); + bool isMsgKickKouraBreak(al::SensorMsg const *); + bool isMsgKickKouraBlow(al::SensorMsg const *); + bool isMsgKickStoneAttack(al::SensorMsg const *); + bool isMsgKickStoneAttackCollide(al::SensorMsg const *); + bool isMsgKickStoneAttackHold(al::SensorMsg const *); + bool isMsgKickStoneAttackReflect(al::SensorMsg const *); + bool isMsgKickStoneTrample(al::SensorMsg const *); + bool isMsgKillerAttack(al::SensorMsg const *); + bool isMsgLiftGeyser(al::SensorMsg const *); + bool isMsgWarpStart(al::SensorMsg const *); + bool isMsgWarpEnd(al::SensorMsg const *); + bool isMsgHoleIn(al::SensorMsg const *); + bool isMsgJumpInhibit(al::SensorMsg const *); + bool isMsgGoalKill(al::SensorMsg const *); + bool isMsgGoal(al::SensorMsg const *); + bool isMsgBallAttack(al::SensorMsg const *); + bool isMsgBallRouteDokanAttack(al::SensorMsg const *); + bool isMsgBallAttackHold(al::SensorMsg const *); + bool isMsgBallAttackDRCHold(al::SensorMsg const *); + bool isMsgBallAttackCollide(al::SensorMsg const *); + bool isMsgBallTrample(al::SensorMsg const *); + bool isMsgBallTrampleCollide(al::SensorMsg const *); + bool isMsgFireBallCollide(al::SensorMsg const *); + bool isMsgFireBallFloorTouch(al::SensorMsg const *); + bool isMsgDokanBazookaAttack(al::SensorMsg const *); + bool isMsgSwitchOn(al::SensorMsg const *); + bool isMsgSwitchOnInit(al::SensorMsg const *); + bool isMsgSwitchOffInit(al::SensorMsg const *); + bool isMsgSwitchKillOn(al::SensorMsg const *); + bool isMsgSwitchKillOnInit(al::SensorMsg const *); + bool isMsgSwitchKillOffInit(al::SensorMsg const *); + bool isMsgAskSafetyPoint(al::SensorMsg const *); + bool isMsgTouchAssist(al::SensorMsg const *); + bool isMsgTouchAssistNoPat(al::SensorMsg const *); + bool isMsgTouchAssistTrig(al::SensorMsg const *); + bool isMsgTouchAssistTrigOff(al::SensorMsg const *); + bool isMsgTouchAssistTrigNoPat(al::SensorMsg const *); + bool isMsgTouchAssistBurn(al::SensorMsg const *); + bool isMsgTouchAssistAll(al::SensorMsg const *); + bool isMsgTouchCarryItem(al::SensorMsg const *); + bool isMsgTouchReleaseItem(al::SensorMsg const *); + bool isMsgTouchStroke(al::SensorMsg const *); + bool isMsgIsNerveSupportFreeze(al::SensorMsg const *); + bool isMsgOnSyncSupportFreeze(al::SensorMsg const *); + bool isMsgOffSyncSupportFreeze(al::SensorMsg const *); + bool isMsgScreenPointInvalidCollisionParts(al::SensorMsg const *); + bool isMsgBlockUpperPunch(al::SensorMsg const *); + bool isMsgBlockLowerPunch(al::SensorMsg const *); + bool isMsgBlockItemGet(al::SensorMsg const *); + bool isMsgPlayerKouraAttack(al::SensorMsg const *); + bool isMsgLightFlash(al::SensorMsg const *); + bool isMsgForceAbyss(al::SensorMsg const *); + bool isMsgSwordAttackHigh(al::SensorMsg const *); + bool isMsgSwordAttackHighLeft(al::SensorMsg const *); + bool isMsgSwordAttackHighRight(al::SensorMsg const *); + bool isMsgSwordAttackLow(al::SensorMsg const *); + bool isMsgSwordAttackLowLeft(al::SensorMsg const *); + bool isMsgSwordAttackLowRight(al::SensorMsg const *); + bool isMsgSwordBeamAttack(al::SensorMsg const *); + bool isMsgSwordBeamReflectAttack(al::SensorMsg const *); + bool isMsgSwordAttackJumpUnder(al::SensorMsg const *); + bool isMsgShieldGuard(al::SensorMsg const *); + bool isMsgAskMultiPlayerEnemy(al::SensorMsg const *); + bool isMsgItemGettable(al::SensorMsg const *); + bool isMsgKikkiThrow(al::SensorMsg const *); + bool isMsgIsKikkiThrowTarget(al::SensorMsg const *); + bool isMsgPlayerCloudGet(al::SensorMsg const *); + bool isMsgAutoJump(al::SensorMsg const *); + bool isMsgPlayerTouchShadow(al::SensorMsg const *); + bool isMsgPlayerPullOutShadow(al::SensorMsg const *); + bool isMsgPlayerAttackShadow(al::SensorMsg const *); + bool isMsgPlayerAttackShadowStrong(al::SensorMsg const *); + bool isMsgPlayerAttackChangePos(al::SensorMsg const *); + bool isMsgAtmosOnlineLight(al::SensorMsg const *); + bool isMsgLightBurn(al::SensorMsg const *); + bool isMsgMoonLightBurn(al::SensorMsg const *); + bool isMsgString(al::SensorMsg const *); + bool isMsgStringV4fPtr(al::SensorMsg const *); + bool isMsgStringV4fSensorPtr(al::SensorMsg const *); + bool isMsgStringVoidPtr(al::SensorMsg const *); + bool isMsgPlayerTrampleForCrossoverSensor(al::SensorMsg const *, al::HitSensor const *, al::HitSensor const *); + bool isMsgPlayerTrampleReflectForCrossoverSensor(al::SensorMsg const *, al::HitSensor const *, al::HitSensor const *); + bool isMsgPlayerUpperPunchForCrossoverSensor(al::SensorMsg const *, al::HitSensor const *, al::HitSensor const *, float); + bool isMsgKickStoneTrampleForCrossoverSensor(al::SensorMsg const *, al::HitSensor const *, al::HitSensor const *); + + bool sendMsgPlayerAttackTrample(al::HitSensor *, al::HitSensor *, al::ComboCounter *); + bool sendMsgPlayerTrampleReflect(al::HitSensor *, al::HitSensor *, al::ComboCounter *); + bool sendMsgPlayerReflectOrTrample(al::HitSensor *, al::HitSensor *, al::ComboCounter *); + bool sendMsgPlayerHipDrop(al::HitSensor *, al::HitSensor *, al::ComboCounter *); + bool sendMsgPlayerObjHipDrop(al::HitSensor *, al::HitSensor *, al::ComboCounter *); + bool sendMsgPlayerObjHipDropReflect(al::HitSensor *, al::HitSensor *, al::ComboCounter *); + bool sendMsgPlayerObjHipDropHighJump(al::HitSensor *, al::HitSensor *, al::ComboCounter *); + bool sendMsgPlayerHipDropKnockDown(al::HitSensor *, al::HitSensor *); + bool sendMsgPlayerStatueDrop(al::HitSensor *, al::HitSensor *, al::ComboCounter *); + bool sendMsgPlayerObjStatueDrop(al::HitSensor *, al::HitSensor *, al::ComboCounter *); + bool sendMsgPlayerObjStatueDropReflect(al::HitSensor *, al::HitSensor *, al::ComboCounter *); + bool sendMsgPlayerObjStatueDropReflectNoCondition(al::HitSensor *, al::HitSensor *); + bool sendMsgPlayerStatueTouch(al::HitSensor *, al::HitSensor *); + bool sendMsgPlayerUpperPunch(al::HitSensor *, al::HitSensor *); + bool sendMsgPlayerObjUpperPunch(al::HitSensor *, al::HitSensor *); + bool sendMsgPlayerRollingAttack(al::HitSensor *, al::HitSensor *); + bool sendMsgPlayerRollingReflect(al::HitSensor *, al::HitSensor *); + bool sendMsgPlayerObjRollingAttack(al::HitSensor *, al::HitSensor *); + bool sendMsgPlayerObjRollingAttackFailure(al::HitSensor *, al::HitSensor *); + bool sendMsgPlayerInvincibleAttack(al::HitSensor *, al::HitSensor *, al::ComboCounter *); + bool sendMsgPlayerFireBallAttack(al::HitSensor *, al::HitSensor *); + bool sendMsgPlayerRouteDokanFireBallAttack(al::HitSensor *, al::HitSensor *); + bool sendMsgPlayerTailAttack(al::HitSensor *, al::HitSensor *, al::ComboCounter *); + bool sendMsgPlayerTouch(al::HitSensor *, al::HitSensor *); + bool sendMsgPlayerKick(al::HitSensor *, al::HitSensor *); + bool sendMsgPlayerCatch(al::HitSensor *, al::HitSensor *); + bool sendMsgPlayerSlidingAttack(al::HitSensor *, al::HitSensor *, al::ComboCounter *); + bool sendMsgPlayerBoomerangAttack(al::HitSensor *, al::HitSensor *, al::ComboCounter *); + bool sendMsgPlayerBoomerangAttackCollide(al::HitSensor *, al::HitSensor *); + bool sendMsgPlayerBoomerangReflect(al::HitSensor *, al::HitSensor *); + bool sendMsgPlayerBoomerangBreak(al::HitSensor *, al::HitSensor *); + bool sendMsgPlayerBodyAttack(al::HitSensor *, al::HitSensor *, al::ComboCounter *); + bool sendMsgPlayerBodyLanding(al::HitSensor *, al::HitSensor *, al::ComboCounter *); + bool sendMsgPlayerBodyAttackReflect(al::HitSensor *, al::HitSensor *, al::ComboCounter *); + bool sendMsgPlayerClimbAttack(al::HitSensor *, al::HitSensor *, al::ComboCounter *); + bool sendMsgPlayerSpinAttack(al::HitSensor *, al::HitSensor *, al::ComboCounter *); + bool sendMsgPlayerGiantAttack(al::HitSensor *, al::HitSensor *, al::ComboCounter *); + bool sendMsgPlayerCooperationHipDrop(al::HitSensor *, al::HitSensor *, al::ComboCounter *); + bool sendMsgPlayerClimbSlidingAttack(al::HitSensor *, al::HitSensor *, al::ComboCounter *); + bool sendMsgPlayerClimbRollingAttack(al::HitSensor *, al::HitSensor *, al::ComboCounter *); + bool sendMsgPlayerGiantHipDrop(al::HitSensor *, al::HitSensor *, al::ComboCounter *); + bool sendMsgPlayerDisregard(al::HitSensor *, al::HitSensor *); + bool sendMsgPlayerItemGet(al::HitSensor *, al::HitSensor *); + bool sendMsgPlayerPutOnEquipment(al::HitSensor *, al::HitSensor *); + bool sendMsgPlayerReleaseEquipment(al::HitSensor *, al::HitSensor *); + bool sendMsgPlayerReleaseEquipmentGoal(al::HitSensor *, al::HitSensor *, uint); + bool sendMsgPlayerFloorTouch(al::HitSensor *, al::HitSensor *); + bool sendMsgPlayerDamageTouch(al::HitSensor *, al::HitSensor *); + bool sendMsgPlayerCarryFront(al::HitSensor *, al::HitSensor *); + bool sendMsgPlayerCarryFrontWallKeep(al::HitSensor *, al::HitSensor *); + bool sendMsgPlayerCarryUp(al::HitSensor *, al::HitSensor *); + bool sendMsgPlayerCarryKeepDemo(al::HitSensor *, al::HitSensor *); + bool sendMsgPlayerCarryWarp(al::HitSensor *, al::HitSensor *); + bool sendMsgPlayerLeave(al::HitSensor *, al::HitSensor *); + bool sendMsgPlayerRelease(al::HitSensor *, al::HitSensor *); + bool sendMsgPlayerReleaseBySwing(al::HitSensor *, al::HitSensor *); + bool sendMsgPlayerReleaseDamage(al::HitSensor *, al::HitSensor *); + bool sendMsgPlayerReleaseDead(al::HitSensor *, al::HitSensor *); + bool sendMsgPlayerReleaseDemo(al::HitSensor *, al::HitSensor *); + bool sendMsgPlayerToss(al::HitSensor *, al::HitSensor *); + bool sendMsgPlayerInvincibleTouch(al::HitSensor *, al::HitSensor *, al::ComboCounter *); + bool sendMsgEnemyAttack(al::HitSensor *, al::HitSensor *); + bool sendMsgEnemyAttackBoomerang(al::HitSensor *, al::HitSensor *); + bool sendMsgEnemyAttackFire(al::HitSensor *, al::HitSensor *, char const *); + bool sendMsgEnemyAttackNeedle(al::HitSensor *, al::HitSensor *); + bool sendMsgEnemyFloorTouch(al::HitSensor *, al::HitSensor *); + bool sendMsgEnemyItemGet(al::HitSensor *, al::HitSensor *); + bool sendMsgEnemyRouteDokanAttack(al::HitSensor *, al::HitSensor *); + bool sendMsgEnemyRouteDokanFire(al::HitSensor *, al::HitSensor *); + bool sendMsgEnemyTouch(al::HitSensor *, al::HitSensor *); + bool sendMsgEnemyUpperPunch(al::HitSensor *, al::HitSensor *); + bool sendMsgEnemyTrample(al::HitSensor *, al::HitSensor *); + bool sendMsgMapObjTrample(al::HitSensor *, al::HitSensor *); + bool sendMsgPressureDeath(al::HitSensor *, al::HitSensor *); + bool sendMsgNpcTouch(al::HitSensor *, al::HitSensor *); + bool sendMsgExplosion(al::HitSensor *, al::HitSensor *, al::ComboCounter *); + bool sendMsgExplosionCollide(al::HitSensor *, al::HitSensor *, al::ComboCounter *); + bool sendMsgPush(al::HitSensor *, al::HitSensor *); + bool sendMsgPushStrong(al::HitSensor *, al::HitSensor *); + bool sendMsgPushVeryStrong(al::HitSensor *, al::HitSensor *); + bool sendMsgHit(al::HitSensor *, al::HitSensor *); + bool sendMsgHitStrong(al::HitSensor *, al::HitSensor *); + bool sendMsgHitVeryStrong(al::HitSensor *, al::HitSensor *); + bool sendMsgKnockDown(al::HitSensor *, al::HitSensor *); + bool sendMsgMapPush(al::HitSensor *, al::HitSensor *); + bool sendMsgVanish(al::HitSensor *, al::HitSensor *); + bool sendMsgChangeAlpha(al::LiveActor *, float); + bool sendMsgShowModel(al::HitSensor *, al::HitSensor *); + bool sendMsgHideModel(al::HitSensor *, al::HitSensor *); + bool sendMsgRestart(al::HitSensor *, al::HitSensor *); + bool sendMsgNeedleBallAttack(al::HitSensor *, al::HitSensor *); + bool sendMsgPunpunFloorTouch(al::HitSensor *, al::HitSensor *); + bool sendMsgInvalidateFootPrint(al::HitSensor *, al::HitSensor *); + bool sendMsgKickKouraAttack(al::HitSensor *, al::HitSensor *, al::ComboCounter *); + bool sendMsgKickKouraAttackCollide(al::HitSensor *, al::HitSensor *, al::ComboCounter *); + bool sendMsgKickKouraGetItem(al::HitSensor *, al::HitSensor *); + bool sendMsgKickKouraReflect(al::HitSensor *, al::HitSensor *); + bool sendMsgKickKouraCollideNoReflect(al::HitSensor *, al::HitSensor *); + bool sendMsgKickKouraBreak(al::HitSensor *, al::HitSensor *); + bool sendMsgKickKouraBlow(al::HitSensor *, al::HitSensor *); + bool sendMsgKickStoneAttack(al::HitSensor *, al::HitSensor *); + bool sendMsgKickStoneAttackCollide(al::HitSensor *, al::HitSensor *); + bool sendMsgKickStoneAttackHold(al::HitSensor *, al::HitSensor *); + bool sendMsgKickStoneAttackReflect(al::HitSensor *, al::HitSensor *); + bool sendMsgKickStoneTrample(al::HitSensor *, al::HitSensor *); + bool sendMsgKillerAttack(al::HitSensor *, al::HitSensor *); + bool sendMsgLiftGeyser(al::HitSensor *, al::HitSensor *); + bool sendMsgWarpStart(al::HitSensor *, al::HitSensor *); + bool sendMsgWarpEnd(al::HitSensor *, al::HitSensor *); + bool sendMsgHoldCancel(al::HitSensor *, al::HitSensor *); + bool sendMsgHoleIn(al::HitSensor *, al::HitSensor *); + bool sendMsgJumpInhibit(al::HitSensor *, al::HitSensor *); + bool sendMsgGoalKill(al::HitSensor *, al::HitSensor *); + bool sendMsgGoal(al::HitSensor *, al::HitSensor *); + bool sendMsgBindStart(al::HitSensor *, al::HitSensor *); + bool sendMsgBindInit(al::HitSensor *, al::HitSensor *, uint); + bool sendMsgBindEnd(al::HitSensor *, al::HitSensor *); + bool sendMsgBindCancel(al::HitSensor *, al::HitSensor *); + bool sendMsgBindCancelByDemo(al::HitSensor *, al::HitSensor *); + bool sendMsgBindDamage(al::HitSensor *, al::HitSensor *); + bool sendMsgBindSteal(al::HitSensor *, al::HitSensor *); + bool sendMsgBindGiant(al::HitSensor *, al::HitSensor *); + bool sendMsgBallAttack(al::HitSensor *, al::HitSensor *, al::ComboCounter *); + bool sendMsgBallRouteDokanAttack(al::HitSensor *, al::HitSensor *, al::ComboCounter *); + bool sendMsgBallAttackHold(al::HitSensor *, al::HitSensor *); + bool sendMsgBallAttackDRCHold(al::HitSensor *, al::HitSensor *); + bool sendMsgBallAttackCollide(al::HitSensor *, al::HitSensor *); + bool sendMsgBallTrample(al::HitSensor *, al::HitSensor *, al::ComboCounter *); + bool sendMsgBallTrampleCollide(al::HitSensor *, al::HitSensor *); + bool sendMsgBallItemGet(al::HitSensor *, al::HitSensor *); + bool sendMsgFireBalCollide(al::HitSensor *, al::HitSensor *); + bool sendMsgFireBallFloorTouch(al::HitSensor *, al::HitSensor *); + bool sendMsgDokanBazookaAttack(al::HitSensor *, al::HitSensor *); + bool sendMsgRideAllPlayerItemGet(al::HitSensor *, al::HitSensor *); + bool sendMsgHideModel(al::LiveActor *); + bool sendMsgShowModel(al::LiveActor *); + bool sendMsgRestart(al::LiveActor *); + bool sendMsgCollisionImpulse(al::HitSensor *, al::HitSensor *, sead::Vector3f *, sead::Vector3f const &, float, sead::Vector3f const &, float); + bool sendMsgSwitchOn(al::LiveActor *); + bool sendMsgSwitchOnInit(al::LiveActor *); + bool sendMsgSwitchOffInit(al::LiveActor *); + bool sendMsgSwitchKillOn(al::LiveActor *); + bool sendMsgSwitchKillOnInit(al::LiveActor *); + bool sendMsgSwitchKillOffInit(al::LiveActor *); + bool sendMsgPlayerFloorTouchToColliderGround(al::LiveActor *, al::HitSensor *); + bool sendMsgPlayerUpperPunchToColliderCeiling(al::LiveActor *, al::HitSensor *); + bool sendMsgEnemyFloorTouchToColliderGround(al::LiveActor *, al::HitSensor *); + bool sendMsgEnemyUpperPunchToColliderCeiling(al::LiveActor *, al::HitSensor *); + bool sendMsgAskSafetyPoint(al::HitSensor *, al::HitSensor *, sead::Vector3f **); + bool sendMsgAskSafetyPointToColliderGround(al::LiveActor *, al::HitSensor *, sead::Vector3f **); + bool sendMsgTouchAssist(al::HitSensor *, al::HitSensor *); + bool sendMsgTouchAssistTrig(al::HitSensor *, al::HitSensor *); + bool sendMsgTouchStroke(al::HitSensor *, al::HitSensor *); + bool sendMsgScreenPointInvalidCollisionParts(al::HitSensor *, al::HitSensor *); + bool sendMsgBlockUpperPunch(al::HitSensor *, al::HitSensor *, al::ComboCounter *); + bool sendMsgBlockLowerPunch(al::HitSensor *, al::HitSensor *, al::ComboCounter *); + bool sendMsgBlockItemGet(al::HitSensor *, al::HitSensor *); + bool sendMsgKillerItemGet(al::HitSensor *, al::HitSensor *); + bool sendMsgPlayerKouraAttack(al::HitSensor *, al::HitSensor *, al::ComboCounter *); + bool sendMsgLightFlash(al::HitSensor *, al::HitSensor *); + bool sendMsgForceAbyss(al::HitSensor *, al::HitSensor *); + bool sendMsgIsNerveSupportFreeze(al::HitSensor *, al::HitSensor *); + bool sendMsgOnSyncSupportFreeze(al::HitSensor *, al::HitSensor *); + bool sendMsgOffSyncSupportFreeze(al::HitSensor *, al::HitSensor *); + bool sendMsgSwordAttackHighLeft(al::HitSensor *, al::HitSensor *); + bool sendMsgSwordAttackLowLeft(al::HitSensor *, al::HitSensor *); + bool sendMsgSwordAttackHighRight(al::HitSensor *, al::HitSensor *); + bool sendMsgSwordAttackLowRight(al::HitSensor *, al::HitSensor *); + bool sendMsgSwordAttackJumpUnder(al::HitSensor *, al::HitSensor *); + bool sendMsgSwordBeamAttack(al::HitSensor *, al::HitSensor *); + bool sendMsgSwordBeamReflectAttack(al::HitSensor *, al::HitSensor *); + bool sendMsgShieldGuard(al::HitSensor *, al::HitSensor *); + bool sendMsgEnemyAttackKnockDown(al::HitSensor *, al::HitSensor *); + bool sendMsgAskMultiPlayerEnemy(al::HitSensor *, al::HitSensor *); + bool sendMsgItemGettable(al::HitSensor *, al::HitSensor *); + bool sendMsgKikkiThrow(al::HitSensor *, al::HitSensor *); + bool sendMsgIsKikkiThrowTarget(al::HitSensor *, al::HitSensor *); + bool sendMsgPlayerCloudGet(al::HitSensor *, al::HitSensor *); + bool sendMsgAutoJump(al::HitSensor *, al::HitSensor *); + bool sendMsgPlayerTouchShadow(al::HitSensor *, al::HitSensor *); + bool sendMsgPlayerPullOutShadow(al::HitSensor *, al::HitSensor *); + bool sendMsgPlayerAttackShadow(al::HitSensor *, al::HitSensor *); + bool sendMsgPlayerAttackShadowStrong(al::HitSensor *, al::HitSensor *); + bool sendMsgPlayerAttackChangePos(al::HitSensor *, al::HitSensor *, sead::Vector3f *); + bool sendMsgAtmosOnlineLight(al::HitSensor *, al::HitSensor *); + bool sendMsgLightBurn(al::HitSensor *, al::HitSensor *); + bool sendMsgMoonLightBurn(al::HitSensor *, al::HitSensor *); + bool sendMsgString(al::HitSensor *, al::HitSensor *, char const *); + bool sendMsgStringV4fPtr(al::HitSensor *, al::HitSensor *, char const *, sead::Vector4f *); + bool sendMsgStringV4fSensorPtr(al::HitSensor *, al::HitSensor *, char const *, sead::Vector4f *); + bool sendMsgStringVoidPtr(al::HitSensor *, al::HitSensor *, char const *, void *); + bool sendMsgEnemyAttackForCrossoverSensor(al::HitSensor *, al::HitSensor *); + bool sendMsgEnemyAttackForCrossoverCylinderSensor(al::HitSensor *, al::HitSensor *, sead::Vector3f const &, sead::Vector3f const &, float); + bool sendMsgPushAndKillVelocityToTarget(al::LiveActor *, al::HitSensor *, al::HitSensor *); + bool sendMsgPushAndKillVelocityToTargetH(al::LiveActor *, al::HitSensor *, al::HitSensor *); + bool sendMsgCollidePush(al::HitSensor *, al::HitSensor *, sead::Vector3f const &); + bool sendMsgScreenPointTarget(al::SensorMsg const &, al::ScreenPointer *, al::ScreenPointTarget *); + +} // namespace al diff --git a/include/algorithms/CaptureAnims.h b/include/algorithms/CaptureAnims.h index 86b47c9..b5c23e9 100644 --- a/include/algorithms/CaptureAnims.h +++ b/include/algorithms/CaptureAnims.h @@ -488,6 +488,10 @@ namespace CaptureAnims { } static constexpr const char *FindStr(Type type) { - return s_Strs.at(ToValue(type)); + const s16 type_ = (s16)type; + if (0 <= type_ && type_ < s_Strs.size()) + return s_Strs[type_]; + else + return ""; } } \ No newline at end of file diff --git a/include/algorithms/CaptureTypes.h b/include/algorithms/CaptureTypes.h index b98552a..614c4e8 100644 --- a/include/algorithms/CaptureTypes.h +++ b/include/algorithms/CaptureTypes.h @@ -98,6 +98,10 @@ namespace CaptureTypes { } static constexpr const char *FindStr(Type type) { - return s_Strs.at(ToValue(type)); + const s16 type_ = (s16)type; + if (0 <= type_ && type_ < s_Strs.size()) + return s_Strs[type_]; + else + return ""; } } \ No newline at end of file diff --git a/include/algorithms/PlayerAnims.h b/include/algorithms/PlayerAnims.h index 5e2e9ad..2cd50fb 100644 --- a/include/algorithms/PlayerAnims.h +++ b/include/algorithms/PlayerAnims.h @@ -1154,6 +1154,10 @@ namespace PlayerAnims { } static constexpr const char *FindStr(Type type) { - return s_Strs.at(ToValue(type)); + const s16 type_ = (s16)type; + if (0 <= type_ && type_ < s_Strs.size()) + return s_Strs[type_]; + else + return ""; } } \ No newline at end of file diff --git a/include/algorithms/WipeTypes.h b/include/algorithms/WipeTypes.h index 5f40910..5c9bcee 100644 --- a/include/algorithms/WipeTypes.h +++ b/include/algorithms/WipeTypes.h @@ -72,6 +72,10 @@ namespace WipeTypes { } static constexpr const char *FindStr(Type type) { - return s_Strs.at(ToValue(type)); + const s16 type_ = (s16)type; + if (0 <= type_ && type_ < s_Strs.size()) + return s_Strs[type_]; + else + return ""; } } \ No newline at end of file diff --git a/include/cameras/CameraVerticalAbsorber2DGalaxy.h b/include/cameras/CameraVerticalAbsorber2DGalaxy.h new file mode 100644 index 0000000..8c08172 --- /dev/null +++ b/include/cameras/CameraVerticalAbsorber2DGalaxy.h @@ -0,0 +1,38 @@ +#pragma once + +#include "al/camera/CameraPoser.h" +#include "al/nerve/NerveExecutor.h" +#include "math/seadVector.h" + +namespace al { +class CameraVerticalAbsorber2DGalaxy : public al::NerveExecutor { +public: + CameraVerticalAbsorber2DGalaxy(void); + + void start(al::CameraPoser const*); + void update(al::CameraPoser const*); + void applyLimit(sead::Vector3f* output); + + void exeNone(void); + void exeGround(void); + void exeLimit(void); + void exeLimitOver(void); + void exeLimitAfter(void); + + sead::Vector3f mTargetTrans; + sead::Vector3f mTargetGravity; + sead::Vector3f mTargetUp; + bool mIsTargetCollideGround; + sead::Vector3f mPrevTargetTrans; + sead::Vector3f mPrevTargetGravity; + float unkFloat; + sead::Vector3f mLimit; + sead::Vector3f unkVec; + float unkFloat2; + +}; + +static_assert(sizeof(CameraVerticalAbsorber2DGalaxy) == 0x70, ""); + + +} \ No newline at end of file diff --git a/include/game/Actors/Shine.h b/include/game/Actors/Shine.h index f27db23..c51df7a 100644 --- a/include/game/Actors/Shine.h +++ b/include/game/Actors/Shine.h @@ -8,6 +8,12 @@ #include "game/Interfaces/IUseDimension.h" #include "al/LiveActor/LiveActor.h" +enum ShineType { Normal, Dot, Grand }; + +namespace al { + struct RateParamV3f; +} + class Shine : public al::LiveActor , public IUseDimension { public: Shine(const char* actorName); @@ -16,23 +22,79 @@ class Shine : public al::LiveActor , public IUseDimension { void offAppear(); void onAppear(); - void getDirectWithDemo(void); void getDirect(); void get(); - void onSwitchGet(void); - bool isGot() const; - void setGrandShine(void); - unsigned char padding[0x10]; - // 0x11C mIsEmptyShine + void *qword110; + int dword118; + bool mIsGotShine; ShineInfo *curShineInfo; // 0x120 - unsigned char padding_290[0x278 - 0x128]; + unsigned char padding_188[0x188 - 0x128]; + al::RateParamV3f *mRateParam; + void * qword190; + void * qword198; + ShineType mModelType; + void * qword1A8; + bool byte1B0; + void * qword1B8; + int dword1C0; + int dword1C4; + sead::FixedSafeString<0x80> mShineLabel; + void * qword260; + int dword268; + bool byte26C; + void * qword270; QuestInfo *shineQuestInfo; // 0x278 void *unkPtr1; // 0x280 ActorDimensionKeeper *mDimensionKeeper; // 0x288 - int shineId; // 0x290 -}; \ No newline at end of file + int shineId; // 0x290 + bool mIsMainShine; + void *qword298; + void *qword2A0; + void *qword2A8; + void *qword2B0; + void *qword2B8; + int dword2C0; + __attribute__((packed)) void * qword2C4; + int dword2CC; + int dword2D0; + bool mIsAddHeight; + int dword2D8; + al::LiveActor *mModelEmpty; + al::LiveActor *mModelShine; + int dword2F0; + u16 word2F4; + int dword2F8; + bool mIsNoRotate; + void * qword300; + bool mIsUseDemoCam; + struct WaterSurfaceShadow *mWaterShadow; + void * qword318; + int dword320; + int dword324; + bool byte328; + void * qword330; + bool mIsCheckGroundHeightMoon; + bool mIsHintPhoto; + void * qword340; + bool byte348; + void * qword350; + bool mIsUseAppearDemoForce; + int dword35C; + int dword360; + int dword364; + int dword368; + bool mIsPowerStar; + bool mIsAppearDemoHeightHigh; + void * qword370; + u16 word378; + int dword37C; +}; + +namespace rs { + void setStageShineAnimFrame(al::LiveActor *,char const*,int,bool); +} \ No newline at end of file diff --git a/include/game/GameData/GameDataFile.h b/include/game/GameData/GameDataFile.h index 0dcd582..5728bfa 100644 --- a/include/game/GameData/GameDataFile.h +++ b/include/game/GameData/GameDataFile.h @@ -6,8 +6,10 @@ #pragma once #include "al/scene/SceneObjHolder.h" +#include "container/seadPtrArray.h" #include "types.h" #include "UniqueObjInfo.h" +#include "GameProgressData.h" #include "sead/math/seadVector.h" #include "sead/stream/seadStream.h" @@ -16,7 +18,24 @@ namespace al { class ActorInitInfo; class PlacementInfo; class PlacementId; -} + } // namespace al + +class SphinxQuizData; +class TimeBalloonSaveData; +class WorldWarpTalkData; +class VisitStageData; +class MoonRockData; +class BossSaveData; +class AchievementSaveData; +class SearchAmiiboDataTable; +class NetworkUploadFlag; +class SequenceDemoSkipData; +class HintPhotoData; +class ShopTalkData; +class RaceRecord; + +class PlayerHitPointData; + class GameDataHolder; class ShineInfo; @@ -296,15 +315,176 @@ class GameDataFile bool isEmpty(void) const; bool isKidsMode(void) const; - undefined padding[0x5C8]; - UniqObjInfo** mUniqueInfo; // 0x5C8 - void *unkPtr1; // 0x5D0 - void *unkPtr2; // 0x5D8 - void *unkPtr3; // 0x5E0 - void* unkPtr4; // 0x5E8 - void* unkPtr5; // 0x5F0 - bool unkBool1; // 0x5F8 - bool unkBool2; // 0x5F9 - bool mIsCapEnable; // 0x5FA + ShineInfo **mShineInfoArray; + ShineInfo **mShineInfoArray2; + ShineInfo *mShineInfo; + void *qword18; + void *qword20; + int dword28; + int dword2C; + sead::FixedSafeString<0x80> char30; + sead::FixedSafeString<0x80> charC8; + sead::FixedSafeString<0x80> char160; + sead::FixedSafeString<0x80> char1F8; + sead::FixedSafeString<0x80> char290; + sead::FixedSafeString<0x80> char328; + sead::FixedSafeString<0x80> char3C0; + u16 word458; + char gap45A[6]; + void *qword460; + void *qword468; + void *qword470; + void *qword478; + void *qword480; + void *qword488; + sead::FixedSafeString<0x100> char490; + void *qword5A8; + bool byte5B0; + void *qword5B4; + sead::FixedSafeString<0x80> *qword5C0; + UniqObjInfo** mUniqueObjInfoArr; + void *qword5D0; + void *qword5D8; + void *qword5E0; + void *qword5E8; + void *qword5F0; + u16 word5F8; + bool byte5FA; + void *qword600; + int dword608; + bool byte60C; + SphinxQuizData *mSphinxQuizData; + void *qword618; + void *qword620; + void *qword628; + TimeBalloonSaveData *qword630; + sead::FixedSafeString<0x40> char638; + int dword690; + WorldWarpTalkData *mWorldWarpTalkData; + VisitStageData *mVisitStageData; + GameProgressData *mGameProgressData; + MoonRockData *mMoonRockData; + BossSaveData *mBossSaveData; + AchievementSaveData *mAchievementSaveData; + SearchAmiiboDataTable *mSearchAmiiboDataTable; + NetworkUploadFlag *mNetworkUploadFlag; + SequenceDemoSkipData *mSequenceDemoSkipData; + HintPhotoData *mHintPhotoData; + void *qword6E8; + void *qword6F0; + void *qword6F8; + void *qword700; + void *qword708; + sead::FixedSafeString<0x40> char710; + sead::FixedSafeString<0x40> char768; + u16 word7C0; + void *qword7C8; + u16 word7D0; + void *qword7D8; + sead::PtrArray mLatestRaceRecords; + void *qword7F0; + void *qword7F8; + void *qword800; + void *qword808; + void *qword810; + bool byte818; + void *qword820; + bool byte828; + sead::PtrArrayImpl sead__ptrarrayimpl830; + u16 word840; + bool byte842; + int dword844; + bool byte848; + GameDataHolder *mGameDataHolder; + void *qword858; + PlayerHitPointData *mPlayerHintPointData; + sead::FixedSafeString<0x80> char868; + bool byte900; + bool byte901; + int dword904; + sead::FixedSafeString<0x80> char908; + void *char9A0; + sead::PtrArrayImpl sead__ptrarrayimpl9A8; + sead::PtrArrayImpl sead__ptrarrayimpl9B8; + sead::PtrArrayImpl sead__ptrarrayimpl9C8; + sead::PtrArrayImpl sead__ptrarrayimpl9D8; + void *qword9E8; + int mCurWorldID; + void *qword9F8; + void *qwordA00; + u16 wordA08; + bool byteA0A; + void *qwordA10; + void *qwordA18; + int dwordA20; + int dwordA24; + int dwordA28; + bool byteA2C; + ChangeStageInfo *mChangeStageInfo; + ChangeStageInfo *mChangeStageInfo2; + void *qwordA40; + void *qwordA48; + void *qwordA50; + void *qwordA58; + ShopTalkData *mShopTalkData; + void *qwordA68; + bool byteA70; + char gapA71[3]; + void *qwordA74; + void *qwordA7C; + int dwordA84; + bool byteA88; + char gapA89[3]; + void *qwordA8C; + int dwordA94; + bool byteA98; + char gapA99[3]; + void *qwordA9C; + int dwordAA4; + bool byteAA8; + char gapAA9[3]; + void *qwordAAC; + int dwordAB4; + bool byteAB8; + char gapAB9[3]; + void *qwordABC; + int dwordAC4; + bool byteAC8; + char gapAC9[3]; + void *qwordACC; + int dwordAD4; + bool byteAD8; + char gapAD9[3]; + void *qwordADC; + int dwordAE4; + bool byteAE8; + char gapAE9[3]; + void *qwordAEC; + int dwordAF4; + bool byteAF8; + char gapAF9[3]; + void *qwordAFC; + int dwordB04; + bool byteB08; + char gapB09[3]; + void *qwordB0C; + int dwordB14; + bool byteB18; + char gapB19[3]; + void *qwordB1C; + int dwordB24; + bool byteB28; + char gapB29[7]; + void *qwordB30; + bool byteB38; + char gapB39[7]; + void *qwordB40; + int dwordB48; + char gapB4C[4]; + void *qwordB50; + int dwordB58; + int dwordB5C; + int dwordB60; + u16 wordB64; }; \ No newline at end of file diff --git a/include/game/GameData/GameDataFunction.h b/include/game/GameData/GameDataFunction.h index 3641870..bd9a987 100644 --- a/include/game/GameData/GameDataFunction.h +++ b/include/game/GameData/GameDataFunction.h @@ -138,4 +138,18 @@ public: // subtracts the supplied int value from the current coin count static void subCoin(GameDataHolderWriter, int value); + static bool isUnlockedWorld(GameDataHolderAccessor, int); + + static bool isUnlockedNextWorld(GameDataHolderAccessor); + + static bool isUnlockedAllWorld(GameDataHolderAccessor); + + static bool isUnlockedCurrentWorld(GameDataHolderAccessor); + + static bool isUnlockWorld(int); + + static bool isUnlockFirstForest(void); + + static bool isUnlockFirstSea(void); + }; \ No newline at end of file diff --git a/include/game/GameData/GameDataHolderAccessor.h b/include/game/GameData/GameDataHolderAccessor.h index 60d1740..7e409d6 100644 --- a/include/game/GameData/GameDataHolderAccessor.h +++ b/include/game/GameData/GameDataHolderAccessor.h @@ -18,4 +18,5 @@ class GameDataHolderAccessor : public GameDataHolderWriter public: GameDataHolderAccessor(al::IUseSceneObjHolder const *IUseObjHolder) {mData = (GameDataHolder*)al::getSceneObj(IUseObjHolder, 18);} GameDataHolderAccessor(al::SceneObjHolder const *objHolder) {mData = (GameDataHolder*)objHolder->getObj(18); } + GameDataHolderAccessor() {mData = nullptr; } // default ctor }; \ No newline at end of file diff --git a/include/game/HakoniwaSequence/HakoniwaSequence.h b/include/game/HakoniwaSequence/HakoniwaSequence.h index fe673cc..2e4b056 100644 --- a/include/game/HakoniwaSequence/HakoniwaSequence.h +++ b/include/game/HakoniwaSequence/HakoniwaSequence.h @@ -70,32 +70,6 @@ class HakoniwaSequence : public al::Sequence { HakoniwaStateBootLoadData *mBootLoadData; // 0xE8 HakoniwaStateDeleteScene *mDeleteScene; // 0xF0 al::LayoutKit* mLytKit; // 0xF8 - - // al::initSceneCreator(al::IUseSceneCreator *,al::SequenceInitInfo const&,al::GameDataHolderBase *,al::AudioDirector *,al::ScreenCaptureExecutor *,alSceneFunction::SceneFactory *) .text 00000000009F2270 0000007C 00000050 FFFFFFFFFFFFFFF8 R . . . B . . - - - // undefined * * field_0x0; - // undefined padding_120[0x120]; - // al::Scene * curScene; - // undefined padding_8[0x8]; - // al::AudioDirector * field_0x90; - // undefined padding_24[0x24]; - // StageScene * stageScene; - // GameDataHolderAccessor *gameDataHolder; - // undefined padding_024[0x24]; - // HakoniwaStateDemoWorldWarp * stateDemoWorldWarp; - // undefined padding_192[0x192]; - // int nextScenarioNo; - // undefined padding_12[0x12]; - // al::WipeHolder * field_0x1b0; - // undefined padding_0024[0x24]; - // long * field_0x1d0; - // undefined padding_48[0x48]; - // WorldResourceLoader * worldResourceLoader; - // undefined padding_0x16[0x16]; - // undefined * field_0x220; - // undefined padding_0x144[0x144]; - // undefined * field_0x2b8; - // undefined padding_0x160[0x160]; - // undefined8 field_0x360; + unsigned char padding_168[0x108]; + WorldResourceLoader* mResourceLoader; // 0x208 }; \ No newline at end of file diff --git a/include/game/Interfaces/IUsePlayerHack.h b/include/game/Interfaces/IUsePlayerHack.h index 5ecaa73..91597f3 100644 --- a/include/game/Interfaces/IUsePlayerHack.h +++ b/include/game/Interfaces/IUsePlayerHack.h @@ -6,5 +6,6 @@ */ class IUsePlayerHack { - +public: + virtual struct PlayerHackKeeper *getPlayerHackKeeper() const = 0; }; \ No newline at end of file diff --git a/include/game/Layouts/CommonVerticalList.h b/include/game/Layouts/CommonVerticalList.h index 0035603..20c1de9 100644 --- a/include/game/Layouts/CommonVerticalList.h +++ b/include/game/Layouts/CommonVerticalList.h @@ -6,7 +6,10 @@ #include "prim/seadSafeString.h" struct RollPartsData { - + int mRollMsgCount = 0; // 0x0 + const char16_t **mRollMsgList; // 0x8 + int unkInt1 = 0; // 0x10 + bool mUnkBool = false; // 0x14 }; class CommonVerticalList : public al::NerveExecutor { @@ -75,14 +78,14 @@ public: void *unkPtr3; // 0x50 sead::Vector2f mCursorPos; // 0x58 void *unkPtr4; // 0x60 - void *unkPtr5; // 0x68 + int unkInt1; // 0x68 sead::WFixedSafeString<0x200> **mStringDataArr; // 0x70 sead::FixedSafeString<0x90> **mPaneNameList; // 0x78 void *unkPtr8; // 0x80 void *unkPtr9; // 0x88 const bool *mIsEnableData; // 0x90 int mStringDataCount; // 0x98 - int unkInt2; // 0x9C + int mDataCount; // 0x9C void *unkPtr12; // 0xA0 void *unkPtr13; // 0xA8 void *unkPtr14; // 0xB0 diff --git a/include/game/Player/HackCap.h b/include/game/Player/HackCap.h index eb7fa57..eccc2d5 100644 --- a/include/game/Player/HackCap.h +++ b/include/game/Player/HackCap.h @@ -14,9 +14,9 @@ #include "HackCapThrowParam.h" #include "HackCap/HackCapJointControlKeeper.h" +#include "HackCap/PlayerCapActionHistory.h" class PlayerWallActionHistory; -class PlayerCapActionHistory; class PlayerEyeSensorHitHolder; class IUsePlayerHeightCheck; class PlayerWetControl; @@ -201,6 +201,9 @@ class HackCap : public al::LiveActor { al::LiveActor *mCapEyes; // 0x120 PlayerActorHakoniwa *mPlayerActor; // 0x128 unsigned char padding_220[0x220-0x130]; - HackCapThrowParam throwParam; // 0x220 + HackCapThrowParam *throwParam; // 0x220 + unsigned char padding_2B8[0x2B8-0x228]; + PlayerCapActionHistory *mCapActionHistory; // 0x2B8 + unsigned char padding_2E0[0x2E0-0x2C0]; HackCapJointControlKeeper *mJointKeeper; // 0x2E0 }; \ No newline at end of file diff --git a/include/game/Player/HackCap/PlayerCapActionHistory.h b/include/game/Player/HackCap/PlayerCapActionHistory.h new file mode 100644 index 0000000..979bd66 --- /dev/null +++ b/include/game/Player/HackCap/PlayerCapActionHistory.h @@ -0,0 +1,29 @@ +#pragma once + +#include "al/LiveActor/LiveActor.h" +#include "game/Interfaces/IUsePlayerCollision.h" +#include "game/Player/PlayerConst.h" +#include "math/seadVector.h" + +class PlayerCapActionHistory { +public: + PlayerCapActionHistory(al::LiveActor const*,PlayerConst const*,struct PlayerTrigger const*,IUsePlayerCollision const*); + void update(void); + void clearLandLimit(void); + void clearLimitHeight(void); + void clearCapJump(void); + void clearLandLimitStandAngle(void); + void clearWallAirLimit(void); + void recordLimitHeight(void); + bool isOverLimitHeight(void) const; + + al::LiveActor* mHostActor; // 0x0 + PlayerConst* mPlayerConst; // 0x8 + PlayerTrigger* mPlayerTrigger; // 0x10 + IUsePlayerCollision* mCollider; // 0x18 + struct PlayerCounterAfterCapCatch* mCapCatchCounter; // 0x20 + bool mIsCapBounced = false; // 0x28 + sead::Vector3f mUnkVec = sead::Vector3f::zero; // 0x2C + bool mIsCapJumpReady = true; // 0x38 + bool mIsLimited = true; // 0x39 (unsure what this actually is called) +}; \ No newline at end of file diff --git a/include/game/Player/PlayerActorBase.h b/include/game/Player/PlayerActorBase.h index 01f0baf..b26ce2c 100644 --- a/include/game/Player/PlayerActorBase.h +++ b/include/game/Player/PlayerActorBase.h @@ -7,11 +7,61 @@ #include "PlayerHackKeeper.h" #include "al/LiveActor/LiveActor.h" +#include "game/Interfaces/IUsePlayerCollision.h" #include "game/Interfaces/IUsePlayerHack.h" +#include "game/Player/PlayerCollider.h" +#include "game/Player/PlayerInfo.h" +#include "game/Player/PlayerInitInfo.h" +#include "game/Player/PlayerPuppet.h" -class PlayerActorBase : public al::LiveActor , public IUsePlayerHack { +class PlayerActorBase : public al::LiveActor, public IUsePlayerHack { public: - PlayerHackKeeper *getPlayerHackKeeper() const; - void movement(void); - int getPortNo(); + PlayerActorBase(char const*); + + virtual void movement(void) override; + virtual void init(al::ActorInitInfo const&) override; + virtual void initPlayer(al::ActorInitInfo const&, PlayerInitInfo const&); + virtual int getPortNo(void); + virtual sead::Matrix34f *getViewMtx(void) const; + virtual IUsePlayerCollision* getPlayerCollision(void) const; + + virtual bool isEnableDemo(void); + virtual void startDemo(void); + virtual void endDemo(void); + + virtual void startDemoPuppetable(void); + virtual void endDemoPuppetable(void); + + virtual void startDemoShineGet(void); + virtual void endDemoShineGet(void); + + virtual void startDemoMainShineGet(void); + virtual void endDemoMainShineGet(void); + + virtual void startDemoHack(void); + virtual void endDemoHack(void); + + virtual void startDemoKeepBind(void); + virtual void noticeDemoKeepBindExecute(void); + virtual void endDemoKeepBind(void); + + virtual void startDemoKeepCarry(void); + virtual void endDemoKeepCarry(void); + + virtual void getDemoActor(void); + virtual void getDemoAnimator(void); + + virtual bool isDamageStopDemo(void) const; + + virtual PlayerPuppet *getPlayerPuppet(void); + virtual PlayerInfo *getPlayerInfo(void) const; + + virtual bool checkDeathArea(void); + virtual void sendCollisionMsg(void); + + virtual bool receivePushMsg(al::SensorMsg const*,al::HitSensor *,al::HitSensor *,float); + virtual PlayerHackKeeper* getPlayerHackKeeper() const override; + + sead::Matrix34f* mViewMtx; // 0x110 + int mPortNo; // 0x118 }; \ No newline at end of file diff --git a/include/game/Player/PlayerActorHakoniwa.h b/include/game/Player/PlayerActorHakoniwa.h index 02458ae..54dd75d 100644 --- a/include/game/Player/PlayerActorHakoniwa.h +++ b/include/game/Player/PlayerActorHakoniwa.h @@ -25,7 +25,9 @@ #include "Attacks/PlayerSpinCapAttack.h" -#define PACTORSIZE 0xC8 +namespace al { +class WaterSurfaceFinder; +} class PlayerActorHakoniwa : public PlayerActorBase , public IUseDimension { public: @@ -36,11 +38,10 @@ class PlayerActorHakoniwa : public PlayerActorBase , public IUseDimension { void startPlayerPuppet(void); void initPlayer(al::ActorInitInfo const&, PlayerInitInfo const&); - unsigned char padding[0x18]; // 0x108 PlayerInfo *mPlayerInfo; // 0x128 PlayerConst *mPlayerConst; // 0x130 PlayerInput *mPlayerInput; //0x138 - unsigned char padding_148[0x8]; // PlayerTrigger + PlayerTrigger *mPlayerTrigger; // 0x140 HackCap *mHackCap; // 0x148 ActorDimensionKeeper *mDimKeeper; // 0x150 PlayerModelKeeper *mPlayerModelKeeper; // 0x158 @@ -48,27 +49,117 @@ class PlayerActorHakoniwa : public PlayerActorBase , public IUseDimension { PlayerAnimator *mPlayerAnimator; // 0x168 PlayerColliderHakoniwa *mPlayerCollider; // 0x170 PlayerPuppet *mPlayerPuppet; // 0x178 - // 0x180 PlayerAreaChecker - // 0x188 WaterSurfaceFinder - // 0x190 unk - // 0x198 unk - // 0x1A0 unk - // 0x1A8 unk - // 0x1B0 unk - // 0x1B8 unk - // 0x1C0 unk - // 0x1C8 unk - // 0x1D0 unk - // 0x1D8 unk - // 0x1E0 unk - // 0x1E8 unk - // 0x1F0 unk - // 0x1F8 PlayerBindKeeper - unsigned char padding_208[0x208 - 0x180]; + PlayerAreaChecker *mAreaChecker; // 0x180 + al::WaterSurfaceFinder *mWaterSurfaceFinder; // 0x188 + PlayerOxygen* mPlayerOxygen; // 0x190 + PlayerDamageKeeper* mPlayerDamageKeeper; // 0x198 + PlayerDemoActionFlag* mPlayerDemoActionFlag; // 0x1A0 + PlayerCapActionHistory* mPlayerCapActionHistory; // 0x1A8 + PlayerCapManHeroEyesControl* mPlayerCapManHeroEyesControl; // 0x1B0 + struct PlayerContinuousJump* mPlayerContinuousJump; // 0x1B8 + struct PlayerContinuousLongJump* mPlayerContinuousLongJump; // 0x1C0 + struct PlayerCounterAfterUpperPunch* mPlayerCounterAfterUpperPunch; // 0x1C8 + struct PlayerCounterForceRun* mPlayerCounterForceRun; // 0x1D0 + PlayerCounterIceWater* mPlayerCounterIceWater; // 0x1D8 + struct PlayerCounterQuickTurnJump* mPlayerCounterQuickTurnJump; // 0x1E0 + PlayerWallActionHistory* mPlayerWallActionHistory; // 0x1E8 + PlayerBindKeeper* mPlayerBindKeeper; // 0x1F0 + PlayerCarryKeeper* mPlayerCarryKeeper; // 0x1F8 + PlayerEquipmentUser* mPlayerEquipmentUser; // 0x200 PlayerHackKeeper *mHackKeeper; // 0x208 PlayerFormSensorCollisionArranger *mCollArranger; // 0x210 - void *unkPtr2; // 0x218 - void *unkPtr3; // 0x220 - PlayerSpinCapAttack *mSpinCapAttack; // 0x228 - + struct PlayerJumpMessageRequest* mPlayerJumpMessageRequest; // 0x218 + struct PlayerSandSinkAffect* mPlayerSandSinkAffect; // 0x220 + PlayerSpinCapAttack* mSpinCapAttack; // 0x228 + struct PlayerActionDiveInWater* mPlayerActionDiveInWater; + struct PlayerEffect* mPlayerEffect; + PlayerEyeSensorHitHolder* mPlayerEyeSensorHitHolder; + struct PlayerPushReceiver* mPlayerPushReceiver; + struct PlayerHitPush* mPlayerHitPush; + struct PlayerExternalVelocity* mPlayerExternalVelocity; + PlayerJointControlKeeper* mPlayerJointControlKeeper; + PlayerPainPartsKeeper* mPlayerPainPartsKeeper; + PlayerRecoverySafetyPoint* mPlayerRecoverySafetyPoint; + struct PlayerRippleGenerator* mPlayerRippleGenerator; + PlayerSeparateCapFlag* mPlayerSeparateCapFlag; + PlayerWetControl* mPlayerWetControl; + PlayerStainControl* mPlayerStainControl; + al::FootPrintHolder* mFootPrintHolder; + struct GaugeAir* mGaugeAir; + struct WaterSurfaceShadow* mWaterSurfaceShadow; + WorldEndBorderKeeper* mWorldEndBorderKeeper; + void* gap; + struct PlayerSeCtrl* mPlayerSeCtrl; + al::HitSensor* mBodyHitSensor; + bool mIsLongShadow; + struct PlayerStateWait* mPlayerStateWait; + struct PlayerStateSquat* mPlayerStateSquat; + struct PlayerStateRunHakoniwa2D3D* mPlayerStateRunHakoniwa2D3D; + struct PlayerStateSlope* mPlayerStateSlope; + struct PlayerStateRolling* mPlayerStateRolling; + struct PlayerStateSpinCap* mPlayerStateSpinCap; + struct PlayerStateJump* mPlayerStateJump; + struct PlayerStateCapCatchPop* mPlayerStateCapCatchPop; + struct PlayerStateWallAir* mPlayerStateWallAir; + struct PlayerStateWallCatch* mPlayerStateWallCatch; + struct PlayerStateGrabCeil* mPlayerStateGrabCeil; + struct PlayerStatePoleClimb* mPlayerStatePoleClimb; + struct PlayerStateHipDrop* mPlayerStateHipDrop; + struct PlayerStateHeadSliding* mPlayerStateHeadSliding; + struct PlayerStateLongJump* mPlayerStateLongJump; + struct PlayerStateFallHakoniwa* mPlayerStateFallHakoniwa; + struct PlayerStateSandSink* mPlayerStateSandSink; + struct ActorStateSandGeyser* mActorStateSandGeyser; + struct PlayerStateRise* mPlayerStateRise; + struct PlayerStateSwim* mPlayerStateSwim; + struct PlayerStateDamageLife* mPlayerStateDamageLife; + struct PlayerStateDamageSwim* mPlayerStateDamageSwim; + struct PlayerStateDamageFire* mPlayerStateDamageFire; + struct PlayerStatePress* mPlayerStatePress; + struct PlayerStateBind* mPlayerStateBind; + struct PlayerStateHack* mPlayerStateHack; + struct PlayerStateEndHack* mPlayerStateEndHack; + struct PlayerStateCameraSubjective* mPlayerStateCameraSubjective; + struct PlayerStateAbyss* mPlayerStateAbyss; + struct PlayerJudgeAirForceCount* mPlayerJudgeAirForceCount; + struct PlayerJudgeCameraSubjective* mPlayerJudgeCameraSubjective; + struct PlayerJudgeCapCatchPop* mPlayerJudgeCapCatchPop; + struct PlayerJudgeDeadWipeStart* mPlayerJudgeDeadWipeStart; + struct PlayerJudgeDirectRolling* mPlayerJudgeDirectRolling; + struct PlayerJudgeEnableStandUp* mPlayerJudgeEnableStandUp; + struct PlayerJudgeForceLand* mPlayerJudgeForceLand; + struct PlayerJudgeForceSlopeSlide* mPlayerJudgeForceSlopeSlide; + struct PlayerJudgeForceRolling* mPlayerJudgeForceRolling; + struct PlayerJudgeGrabCeil* mPlayerJudgeGrabCeil; + struct PlayerJudgeInWater* mPlayerJudgeInWater1; + struct PlayerJudgeInWater* mPlayerJudgeInWater2; + struct PlayerJudgeInWater* mPlayerJudgeInWater3; + struct PlayerJudgeInWater* mPlayerJudgeInWater4; + struct PlayerJudgeInvalidateInputFall* mPlayerJudgeInvalidateInputFall; + struct PlayerJudgeLongFall* mPlayerJudgeLongFall; + struct PlayerJudgeOutInWater* mPlayerJudgeOutInWater; + struct PlayerJudgeRecoveryLifeFast* mPlayerJudgeRecoveryLifeFast; + struct PlayerJudgeSandSink* mPlayerJudgeSandSink; + struct PlayerJudgeSpeedCheckFall* mPlayerJudgeSpeedCheckFall; + struct PlayerJudgeStartHipDrop* mPlayerJudgeStartHipDrop; + struct PlayerJudgeStartRise* mPlayerJudgeStartRise; + struct PlayerJudgeStartRolling* mPlayerJudgeStartRolling; + struct PlayerJudgeStartRun* mPlayerJudgeStartRun; + struct PlayerJudgeStartSquat* mPlayerJudgeStartSquat; + struct PlayerJudgeStartWaterSurfaceRun* mPlayerJudgeStartWaterSurfaceRun; + struct PlayerJudgeSlopeSlide* mPlayerJudgeSlopeSlide; + struct PlayerJudgePoleClimb* mPlayerJudgePoleClimb; + struct PlayerJudgePreInputJump* mPlayerJudgePreInputJump; + struct PlayerJudgePreInputCapThrow* mPlayerJudgePreInputCapThrow; + struct PlayerJudgePreInputHackAction* mPlayerJudgePreInputHackAction; + struct HackCapJudgePreInputHoveringJump* mHackCapJudgePreInputHoveringJump; + struct HackCapJudgePreInputSeparateThrow* mHackCapJudgePreInputSeparateThrow; + struct HackCapJudgePreInputSeparateJump* mHackCapJudgePreInputSeparateJump; + struct PlayerJudgeWallCatch* mPlayerJudgeWallCatch; + struct PlayerJudgeWallCatchInputDir* mPlayerJudgeWallCatchInputDir; + struct PlayerJudgeWallHitDown* mPlayerJudgeWallHitDown; + struct PlayerJudgeWallHitDownForceRun* mPlayerJudgeWallHitDownForceRun; + struct PlayerJudgeWallHitDownRolling* mPlayerJudgeWallHitDownRolling; + struct PlayerJudgeWallKeep* mPlayerJudgeWallKeep; + void* gap_2; }; \ No newline at end of file diff --git a/include/game/Player/PlayerInfo.h b/include/game/Player/PlayerInfo.h index 444e318..5dbcbd2 100644 --- a/include/game/Player/PlayerInfo.h +++ b/include/game/Player/PlayerInfo.h @@ -9,6 +9,10 @@ #include "PlayerCostumeInfo.h" #include "PlayerModelChangerHakoniwa.h" +namespace al { +struct FootPrintHolder; +} + class PlayerInfo { public: PlayerInfo(); @@ -26,7 +30,7 @@ class PlayerInfo { struct PlayerJointControlKeeper *pJoinControlKeeper; // 0x50 struct PlayerCounterIceWater *pCounterIceWater; // 0x58 struct PlayerStainControl *pStainControl; // 0x60 - struct FootPrintHolder *mFootPrintHolder; // 0x68 + al::FootPrintHolder *mFootPrintHolder; // 0x68 al::HitSensor *mHitSensor; // 0x70 struct PlayerFormSensorCollisionArranger *pSensorCollArranger; // 0x78 PlayerInput *pInput; // 0x80 diff --git a/include/game/SaveData/SaveDataAccessFunction.h b/include/game/SaveData/SaveDataAccessFunction.h new file mode 100644 index 0000000..2ae6b8f --- /dev/null +++ b/include/game/SaveData/SaveDataAccessFunction.h @@ -0,0 +1,19 @@ +#pragma once + +#include "game/GameData/GameDataHolder.h" + +namespace SaveDataAccessFunction { + void startSaveDataInit(GameDataHolder *); + void startSaveDataInitSync(GameDataHolder *); + void startSaveDataLoadFile(GameDataHolder *); + void startSaveDataReadSync(GameDataHolder *); + void startSaveDataReadAll(GameDataHolder *); + void startSaveDataWrite(GameDataHolder *); + void startSaveDataWriteWithWindow(GameDataHolder *); + void startSaveDataCopyWithWindow(GameDataHolder *,int,int); + void startSaveDataDeleteWithWindow(GameDataHolder *,int); + void startSaveDataWriteSync(GameDataHolder *); + bool updateSaveDataAccess(GameDataHolder *,bool); + bool isEnableSave(GameDataHolder const*); + bool isDoneSave(GameDataHolder *); +} \ No newline at end of file diff --git a/include/game/SceneObjs/RouteGuideDirector.h b/include/game/SceneObjs/RouteGuideDirector.h new file mode 100644 index 0000000..e365f1b --- /dev/null +++ b/include/game/SceneObjs/RouteGuideDirector.h @@ -0,0 +1,31 @@ +#pragma once + +#include "al/LiveActor/LiveActor.h" +#include "al/scene/ISceneObj.h" + +class RouteGuideDirector : public al::LiveActor, public al::ISceneObj { +public: + RouteGuideDirector(); + + void initAfterPlacementSceneObj(al::ActorInitInfo const&) override; + + bool isValidate(void) const; + void offGuideSystem(void); + void deactivateGuide(void); + void onGuideSystem(void); + void activateGuide(void); + void offGuideByActor(al::LiveActor *); + void addInvidateList(al::LiveActor *); + void onGuideByActor(al::LiveActor *); + void removeInvidateList(al::LiveActor const*); + void addRouteGuidePointBufferCount(int); + void registerRouteGuidePoint(struct RouteGuidePoint *); + void addRouteGuideArrowBufferCount(int); + void registerRouteGuideArrow(struct RouteGuideArrowBase*); + + void exeOff(void); + void exeOn(void); + + virtual const char* getSceneObjName() override; + virtual void initSceneObj(void) override; +}; \ No newline at end of file diff --git a/include/game/Sequence/SequenceFactory.h b/include/game/Sequence/SequenceFactory.h new file mode 100644 index 0000000..f5c414e --- /dev/null +++ b/include/game/Sequence/SequenceFactory.h @@ -0,0 +1,6 @@ +#pragma once + +class SequenceFactory { +public: + static void createSequence(const char *); +}; \ No newline at end of file diff --git a/include/game/StageScene/StageScene.h b/include/game/StageScene/StageScene.h index 684d4b7..c3ed20e 100644 --- a/include/game/StageScene/StageScene.h +++ b/include/game/StageScene/StageScene.h @@ -4,22 +4,113 @@ #include "game/StageScene/StageSceneLayout.h" #include "game/StageScene/StageSceneStatePauseMenu.h" -#define INHERITSIZE sizeof(al::Scene) +namespace al { +struct LayoutTextureRenderer; +struct SimpleAudioUser; +struct ParabolicPath; +struct DemoSyncedEventKeeper; +struct ChromakeyDrawer; +struct WipeHolder; +} class StageScene : public al::Scene { public: bool isPause() const; - // 0x88 StageResourceKeeper * - // 0x90 LiveActorKit * - // 0x98 LayoutKit * - // 0xA0 SceneObjHolder * - // 0xA8 SceneStopCtrl * - unsigned char padding_180[0x180 - INHERITSIZE]; - StageSceneStatePauseMenu *mStatePauseMenu; // 0x180 - unsigned char padding_2D0[0x148]; - GameDataHolderAccessor mHolder; // 0x2D0 - unsigned char padding_2F8[0x20]; - StageSceneLayout *stageSceneLayout; // 0x2F8 + sead::FixedSafeString<0x40> mStageName; + int field_130; + struct StageSceneStateWorldMap *field_138; + struct StageSceneStateShop *field_140; + struct StageSceneStateSnapShot *field_148; + struct StageSceneStateGetShine *field_150; + struct StageSceneStateGetShineMain *field_158; + struct StageSceneStateGetShineGrand *field_160; + struct StageSceneStateCollectBgm *field_168; + struct StageSceneStateCollectionList *field_170; + struct StageSceneStateMiniGameRanking *field_178; + struct StageSceneStatePauseMenu *field_180; + struct StageSceneStateCloset *field_188; + struct StageSceneStateSkipDemo *field_190; + struct StageSceneStateCheckpointWarp *field_198; + struct StageSceneStateCarryMeat *field_1A0; + void *field_1A8; + void *field_1B0; + struct StageSceneStateMiss *field_1B8; + struct StageSceneStateYukimaruRace *field_1C0; + struct StageSceneStateYukimaruRaceTutorial *field_1C8; + struct StageSceneStateRaceManRace *field_1D0; + struct StageSceneStateRadicon *field_1D8; + struct StageSceneStateScenarioCamera *field_1E0; + struct StageSceneStateRecoverLife *field_1E8; + struct StageSceneStateGetShineMainSandWorld *field_1F0; + void *field_1F8; + struct StageSceneStateWarp *field_200; + void *field_208; + struct ScenarioStartCameraHolder *field_210; + sead::FixedSafeString<0x40> field_218; + sead::FixedSafeString<0x40> field_270; + void *qword2C8; + GameDataHolderAccessor mHolder; + void *qword2D8; + al::LayoutTextureRenderer *qword2E0; + struct PlayGuideSkip *qword2E8; + struct CinemaCaption *qword2F0; + StageSceneLayout *mSceneLayout; + char field_300; + char field_301; + al::SimpleLayoutAppearWaitEnd *char308; + al::SimpleLayoutAppearWaitEnd *field_310; + al::SimpleLayoutAppearWaitEnd *field_318; + struct ControllerGuideSnapShotCtrl *field_320; + InputSeparator *field_328; + al::WipeSimple *field_330; + al::WipeHolder *field_338; + void *field_340; + al::WindowConfirm *field_348; + struct MiniGameMenu *field_350; + bool field_358; + char gap359[15]; + char char368; + struct MapLayout *field_370; + al::SimpleLayoutAppearWaitEnd *field_378; + al::LiveActorGroup *field_380; + void *field_388; + void *mKoopaLv1Actor; + struct TimeBalloonNpc *mTimeBalloonNpc; + struct ProjectItemDirector *field_3A0; + struct Pyramid *field_3A8; + void *field_3B0; + al::Nerve *field_3B8; + SceneAudioSystemPauseController *field_3C0; + struct DemoSoundSynchronizer *mDemoSoundSynchronizer; + al::SimpleAudioUser *mStageStartAtmosSe; + al::SimpleAudioUser *mSePlayArea; + al::SimpleAudioUser *mSnapShotCameraCtrlAudio; + struct ProjectSeNamedList *field_3E8; + void *field_3F0; + struct TimeBalloonDirector *mTimeBalloonDirector; + struct TimeBalloonSequenceInfo *mTimeBalloonSequenceInfo; + void *qword408; + void *qword410; + sead::Vector3f qword418; + sead::Vector3f qword424; + void *qword430; + int dword438; + const al::LiveActor *field_440; + al::ParabolicPath *field_448; + al::LiveActor *field_450; + void *qword458; + int dword460; + struct CollectBgmPlayer *qword468; + struct CollectBgmRegister *qword470; + struct BgmAnimeSyncDirector *qword478; + al::DemoSyncedEventKeeper *field_480; + void *field_488; + int field_490; + struct NpcEventDirector *qword498; + al::ChromakeyDrawer *field_4A0; + void *qword4A8; + ProjectNfpDirector *qword4B0; + void *qword4B8; }; diff --git a/include/game/StageScene/StageSceneStateOption.h b/include/game/StageScene/StageSceneStateOption.h index fcf88ef..bdc69ad 100644 --- a/include/game/StageScene/StageSceneStateOption.h +++ b/include/game/StageScene/StageSceneStateOption.h @@ -125,4 +125,6 @@ class StageSceneStateOption : public al::HostStateBase, public al::IU bool field_0x180; al::MessageSystem *mMsgSystem; InputSeparator *mInputSeperator; -}; \ No newline at end of file +}; + +static_assert(sizeof(StageSceneStateOption) == 0x198, "StageSceneStateOption Size"); \ No newline at end of file diff --git a/include/game/StageScene/StageSceneStateServerConfig.hpp b/include/game/StageScene/StageSceneStateServerConfig.hpp index cbcbe19..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; @@ -29,7 +30,8 @@ class StageSceneStateServerConfig : public al::HostStateBase, public GAMEMODECONFIG, GAMEMODESWITCH, RECONNECT, - SETIP + SETIP, + SETPORT }; virtual al::MessageSystem* getMessageSystem(void) const override; @@ -38,10 +40,13 @@ class StageSceneStateServerConfig : public al::HostStateBase, public virtual void kill(void) override; void exeMainMenu(); - void exeOpenKeyboard(); + void exeOpenKeyboardIP(); + void exeOpenKeyboardPort(); void exeRestartServer(); void exeGamemodeConfig(); void exeGamemodeSelect(); + void exeSaveData(); + void exeConnectError(); void endSubMenu(); @@ -61,22 +66,29 @@ 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; }; namespace { NERVE_HEADER(StageSceneStateServerConfig, MainMenu) - NERVE_HEADER(StageSceneStateServerConfig, OpenKeyboard) + NERVE_HEADER(StageSceneStateServerConfig, OpenKeyboardIP) + NERVE_HEADER(StageSceneStateServerConfig, OpenKeyboardPort) NERVE_HEADER(StageSceneStateServerConfig, RestartServer) NERVE_HEADER(StageSceneStateServerConfig, GamemodeConfig) NERVE_HEADER(StageSceneStateServerConfig, GamemodeSelect) + NERVE_HEADER(StageSceneStateServerConfig, SaveData) + NERVE_HEADER(StageSceneStateServerConfig, ConnectError) } \ No newline at end of file diff --git a/include/main.hpp b/include/main.hpp index 7b82e89..b288d12 100644 --- a/include/main.hpp +++ b/include/main.hpp @@ -51,12 +51,16 @@ #include "Keyboard.hpp" #include "server/DeltaTime.hpp" -static const int playBufSize = 8; - static bool isInGame = false; static bool debugMode = false; +static bool isSmallMode = true; + +static float scale = 0.3f; + +extern float camDist; + constexpr const char* captureNames[] = { "AnagramAlphabetCharacter", "Byugo", "Bubble", "Bull", "Car", "ElectricWire", "KillerLauncherMagnum", "KuriboPossessed", diff --git a/include/nn/account.h b/include/nn/account.h index 1f05d2f..9b0b6c9 100644 --- a/include/nn/account.h +++ b/include/nn/account.h @@ -33,7 +33,11 @@ namespace nn return *this; } - inline void print() { + inline bool isEmpty() const { + return *this == EmptyId; + } + + inline void print() const { Logger::log("Player ID: 0x"); Logger::disableName(); for (size_t i = 0; i < 0x10; i++) { Logger::log("%02X", data[i]); } @@ -41,13 +45,15 @@ namespace nn Logger::enableName(); } - inline void print(const char *prefix) { + inline void print(const char *prefix) const { Logger::log("%s: 0x", prefix); Logger::disableName(); for (size_t i = 0; i < 0x10; i++) { Logger::log("%02X", data[i]); } Logger::log("\n"); Logger::enableName(); } + + static const Uid EmptyId; }; typedef u64 NetworkServiceAccountId; diff --git a/include/nn/socket.h b/include/nn/socket.h index 2fc4b6d..3e8290b 100644 --- a/include/nn/socket.h +++ b/include/nn/socket.h @@ -17,6 +17,15 @@ struct sockaddr u8 _8[8]; // 8 }; +struct hostent +{ + char* h_name; + char** h_aliases; + int h_addrtype; + int h_length; + char** h_addr_list; +}; + namespace nn { namespace socket { @@ -34,4 +43,8 @@ s32 Recv(s32 socket, void* out, ulong outLen, s32 flags); u16 InetHtons(u16 val); s32 InetAton(const char* addressStr, in_addr* addressOut); +struct hostent* GetHostByName(const char* name); + +u32 GetLastErrno(); + } } diff --git a/include/nn/swkbd/swkbd.h b/include/nn/swkbd/swkbd.h index fb822f5..b12ebe0 100644 --- a/include/nn/swkbd/swkbd.h +++ b/include/nn/swkbd/swkbd.h @@ -2,13 +2,23 @@ #include #include +#include "types.h" typedef unsigned long int ulong; typedef unsigned short int ushort; typedef unsigned int uint; typedef unsigned char uchar; -namespace nn -{ +namespace nn { + + namespace applet { + enum ExitReason { + Normal = 0, + Canceled = 1, + Abnormal = 2, + Unexpected = 10 + }; + } + namespace swkbd { enum Preset @@ -103,40 +113,18 @@ namespace nn Max_DictionaryLang }; + enum CloseResult + { + Enter, + Cancel + }; + struct DictionaryInfo { uint offset; // 0x0 ushort size; // 0x4 DictionaryLang lang; // 0x6 }; - - // KeyboardMode keyboardMode; // 0x0 - // const char okText[0x8]; // 0x8 - // char leftOptionalSymbolKey; // 0x10 - // char rightOptionalSymbolKey; // 0x12 - // bool isPredictionEnabled; // 0x14 - // InvalidChar invalidCharFlag; // 0x18 - // InitialCursorPos initialCursorPos; // 0x1C - // const char headerText[0x40]; // 0x20 - // const char subText[0x80]; // 0x28 - // const char guideText[0x100]; // 0x30 - // int textMaxLength; // 0x38 - // int textMinLength; // 0x3C - // PasswordMode passwordMode; // 0x40 - // InputFormMode inputFormMode; // 0x44 - // bool isUseNewLine; // 0x48 - // bool isUseUtf8; // 0x49 - // bool isUseBlurBackground; // 0x4A - // int _initialStringOffset; // 0x4C - // int _initialStringLength; // 0x50 - // int _userDictionaryOffset; // 0x54 - // int _userDictionaryNum; // 0x58 - // bool _isUseTextCheck; // 0x5C - // void *_textCheckCallback; // 0x60 - // int* separateTextPos; // 0x68 - // DictionaryInfo* _customizedDicInfoList; // 0x70 - // unsigned char _customizedDicCount; // 0x78 - // unsigned char* _reserved; // 0x80 struct KeyboardConfig { @@ -193,6 +181,7 @@ namespace nn ulong GetRequiredWorkBufferSize(bool); ulong GetRequiredStringBufferSize(void); + nn::applet::ExitReason getExitReason(); void MakePreset(nn::swkbd::KeyboardConfig *,nn::swkbd::Preset); //void SetHeaderText(nn::swkbd::KeyboardConfig *,char16_t const*); //void SetSubText(nn::swkbd::KeyboardConfig*, char16_t const*); @@ -211,7 +200,9 @@ namespace nn void SetInitialText(nn::swkbd::ShowKeyboardArg *,char16_t const*); void SetInitialTextUtf8(nn::swkbd::ShowKeyboardArg *,char const*); //void SetUserWordList(nn::swkbd::ShowKeyboardArg *,nn::swkbd::UserWord const*,int); - void ShowKeyboard(nn::swkbd::String *,nn::swkbd::ShowKeyboardArg const&); + int ShowKeyboard(nn::swkbd::String*, nn::swkbd::ShowKeyboardArg const&); + + __attribute__((used)) static nn::applet::ExitReason g_ExitReason; } // namespace swkbd } // namespace nn diff --git a/include/nn/system_settings.ini b/include/nn/system_settings.ini deleted file mode 100644 index 600d03c..0000000 --- a/include/nn/system_settings.ini +++ /dev/null @@ -1,53 +0,0 @@ -; Disable uploading error reports to Nintendo -[eupld] -; upload_enabled = u8!0x0 -; Control whether RO should ease its validation of NROs. -; (note: this is normally not necessary, and ips patches can be used.) -[ro] -; ease_nro_restriction = u8!0x1 -; Atmosphere custom settings -[atmosphere] -; Reboot from fatal automatically after some number of milliseconds. -; If field is not present or 0, fatal will wait indefinitely for user input. -; fatal_auto_reboot_interval = u64!0x0 -; Make the power menu's "reboot" button reboot to payload. -; Set to "normal" for normal reboot, "rcm" for rcm reboot. -; power_menu_reboot_function = str!payload -; Controls whether dmnt cheats should be toggled on or off by -; default. 1 = toggled on by default, 0 = toggled off by default. -; dmnt_cheats_enabled_by_default = u8!0x1 -; Controls whether dmnt should always save cheat toggle state -; for restoration on new game launch. 1 = always save toggles, -; 0 = only save toggles if toggle file exists. -; dmnt_always_save_cheat_toggles = u8!0x0 -; Enable writing to BIS partitions for HBL. -; This is probably undesirable for normal usage. -; enable_hbl_bis_write = u8!0x0 -; Enable reading the CAL0 partition for HBL. -; This is probably undesirable for normal usage. -; enable_hbl_cal_read = u8!0x0 -; Controls whether fs.mitm should redirect save files -; to directories on the sd card. -; 0 = Do not redirect, 1 = Redirect. -; NOTE: EXPERIMENTAL -; If you do not know what you are doing, do not touch this yet. -; fsmitm_redirect_saves_to_sd = u8!0x0 -; Controls whether to enable the deprecated hid mitm -; to fix compatibility with old homebrew. -; 0 = Do not enable, 1 = Enable. -; Please note this setting may be removed in a -; future release of Atmosphere. -; enable_deprecated_hid_mitm = u8!0x0 -; Controls whether am sees system settings "DebugModeFlag" as -; enabled or disabled. -; 0 = Disabled (not debug mode), 1 = Enabled (debug mode) -; enable_am_debug_mode = u8!0x0 -[hbloader] -; Controls the size of the homebrew heap when running as applet. -; If set to zero, all available applet memory is used as heap. -; The default is zero. -; applet_heap_size = u64!0x0 -; Controls the amount of memory to reserve when running as applet -; for usage by other applets. This setting has no effect if -; applet_heap_size is non-zero. The default is 0x8600000. -; applet_heap_reservation_size = u64!0x8600000 \ No newline at end of file diff --git a/include/nx/svc.h b/include/nx/svc.h new file mode 100644 index 0000000..8761d3f --- /dev/null +++ b/include/nx/svc.h @@ -0,0 +1,20 @@ +/** + * @file svc.h + * @brief Wrappers for kernel syscalls. + * @copyright libnx Authors + */ +#pragma once + +extern "C" { + +/** + * @brief Outputs debug text, if used during debugging. + * @param[in] str Text to output. + * @param[in] size Size of the text in bytes. + * @return Result code. + * @note Syscall number 0x27. + */ +Result svcOutputDebugString(const char *str, u64 size); + + +} \ No newline at end of file diff --git a/include/packets/CaptureInf.h b/include/packets/CaptureInf.h index dc40f23..ede4cc0 100644 --- a/include/packets/CaptureInf.h +++ b/include/packets/CaptureInf.h @@ -2,12 +2,12 @@ #include "Packet.h" -struct CaptureInf : Packet { +struct PACKED CaptureInf : Packet { CaptureInf() : Packet() { this->mType = PacketType::CAPTUREINF; mPacketSize = sizeof(CaptureInf) - sizeof(Packet); }; char hackName[0x20] = {}; - + }; \ No newline at end of file diff --git a/include/packets/ChangeStagePacket.h b/include/packets/ChangeStagePacket.h index 69d0f29..961ceef 100644 --- a/include/packets/ChangeStagePacket.h +++ b/include/packets/ChangeStagePacket.h @@ -2,7 +2,7 @@ #include "Packet.h" -struct ChangeStagePacket : Packet { +struct PACKED ChangeStagePacket : Packet { ChangeStagePacket() : Packet() { this->mType = PacketType::CHANGESTAGE; mPacketSize = sizeof(ChangeStagePacket) - sizeof(Packet); diff --git a/include/packets/CostumeInf.h b/include/packets/CostumeInf.h index bba2277..672ff79 100644 --- a/include/packets/CostumeInf.h +++ b/include/packets/CostumeInf.h @@ -2,7 +2,7 @@ #include "Packet.h" -struct CostumeInf : Packet { +struct PACKED CostumeInf : Packet { CostumeInf() : Packet() {this->mType = PacketType::COSTUMEINF; mPacketSize = sizeof(CostumeInf) - sizeof(Packet);}; CostumeInf(const char* body, const char* cap) : Packet() { this->mType = PacketType::COSTUMEINF; diff --git a/include/packets/GameInf.h b/include/packets/GameInf.h index 7b82954..34c5793 100644 --- a/include/packets/GameInf.h +++ b/include/packets/GameInf.h @@ -3,9 +3,9 @@ #include "Packet.h" #include "al/util.hpp" -struct GameInf : Packet { +struct PACKED GameInf : Packet { GameInf() : Packet() {this->mType = PacketType::GAMEINF; mPacketSize = sizeof(GameInf) - sizeof(Packet);}; - bool is2D = false; + bool1 is2D = false; u8 scenarioNo = -1; char stageName[0x40] = {}; diff --git a/include/packets/HackCapInf.h b/include/packets/HackCapInf.h index 7434bd5..fc92534 100644 --- a/include/packets/HackCapInf.h +++ b/include/packets/HackCapInf.h @@ -2,10 +2,10 @@ #include "Packet.h" -struct HackCapInf : Packet { +struct PACKED HackCapInf : Packet { HackCapInf() : Packet() {this->mType = PacketType::HACKCAPINF; mPacketSize = sizeof(HackCapInf) - sizeof(Packet);}; sead::Vector3f capPos; sead::Quatf capQuat; - bool isCapVisible = false; + bool1 isCapVisible = false; char capAnim[PACKBUFSIZE] = {}; }; \ No newline at end of file diff --git a/include/packets/InitPacket.h b/include/packets/InitPacket.h index 002b93d..177b932 100644 --- a/include/packets/InitPacket.h +++ b/include/packets/InitPacket.h @@ -2,7 +2,7 @@ #include "Packet.h" -struct InitPacket : Packet { +struct PACKED InitPacket : Packet { InitPacket() : Packet() {this->mType = PacketType::CLIENTINIT; mPacketSize = sizeof(InitPacket) - sizeof(Packet);}; u16 maxPlayers = 0; }; \ No newline at end of file diff --git a/include/packets/Packet.h b/include/packets/Packet.h index 9fe183c..400ee46 100644 --- a/include/packets/Packet.h +++ b/include/packets/Packet.h @@ -5,6 +5,8 @@ #include "nn/account.h" +#include "types.h" + #define PACKBUFSIZE 0x30 #define COSTUMEBUFSIZE 0x20 @@ -23,12 +25,14 @@ enum PacketType : short { SHINECOLL, CAPTUREINF, CHANGESTAGE, - CMD + CMD, + End // end of enum for bounds checking }; // attribute otherwise the build log is spammed with unused warnings -__attribute((used)) static const char *packetNames[] = { +USED static const char *packetNames[] = { "Unknown", + "Client Initialization", "Player Info", "Player Cap Info", "Game Info", @@ -38,6 +42,7 @@ __attribute((used)) static const char *packetNames[] = { "Costume Info", "Moon Collection", "Capture Info", + "Change Stage", "Server Command" }; @@ -59,7 +64,7 @@ static const char *senderNames[] = { }; */ -struct Packet { +struct PACKED Packet { nn::account::Uid mUserID; // User ID of the packet owner PacketType mType = PacketType::UNKNOWN; short mPacketSize = 0; // represents packet size without size of header diff --git a/include/packets/PlayerConnect.h b/include/packets/PlayerConnect.h index 24e577e..f3ea37c 100644 --- a/include/packets/PlayerConnect.h +++ b/include/packets/PlayerConnect.h @@ -2,9 +2,11 @@ #include "Packet.h" -struct PlayerConnect : Packet { +#include + +struct PACKED PlayerConnect : Packet { PlayerConnect() : Packet() {this->mType = PacketType::PLAYERCON; mPacketSize = sizeof(PlayerConnect) - sizeof(Packet);}; ConnectionTypes conType; - u16 maxPlayerCount; + u16 maxPlayerCount = USHRT_MAX; char clientName[COSTUMEBUFSIZE] = {}; }; \ No newline at end of file diff --git a/include/packets/PlayerDC.h b/include/packets/PlayerDC.h index d88432e..1086b74 100644 --- a/include/packets/PlayerDC.h +++ b/include/packets/PlayerDC.h @@ -2,6 +2,6 @@ #include "Packet.h" -struct PlayerDC : Packet { +struct PACKED PlayerDC : Packet { PlayerDC() : Packet() {this->mType = PacketType::PLAYERDC; mPacketSize = sizeof(PlayerDC) - sizeof(Packet);}; }; \ No newline at end of file diff --git a/include/packets/PlayerInfPacket.h b/include/packets/PlayerInfPacket.h index 0b54b0a..3ff35c4 100644 --- a/include/packets/PlayerInfPacket.h +++ b/include/packets/PlayerInfPacket.h @@ -4,9 +4,9 @@ #include "al/util.hpp" #include "algorithms/PlayerAnims.h" -struct PlayerInf : Packet { +struct PACKED PlayerInf : Packet { PlayerInf() : Packet() {mType = PacketType::PLAYERINF; mPacketSize = sizeof(PlayerInf) - sizeof(Packet);}; - sead::Vector3f playerPos; + sead::Vector3f playerPos; sead::Quatf playerRot; float animBlendWeights[6]; PlayerAnims::Type actName; diff --git a/include/packets/ServerCommand.h b/include/packets/ServerCommand.h index 4edd608..a5ced3f 100644 --- a/include/packets/ServerCommand.h +++ b/include/packets/ServerCommand.h @@ -2,7 +2,7 @@ #include "Packet.h" -struct ServerCommand : Packet { +struct PACKED ServerCommand : Packet { ServerCommand(const char *command) : Packet() {this->mType = PacketType::CMD; strcpy(srvCmd, command); mPacketSize = sizeof(ServerCommand) - sizeof(Packet);}; char srvCmd[PACKBUFSIZE] = {}; }; \ No newline at end of file diff --git a/include/packets/ShineCollect.h b/include/packets/ShineCollect.h index 9f8a8c7..2e6bdad 100644 --- a/include/packets/ShineCollect.h +++ b/include/packets/ShineCollect.h @@ -2,8 +2,8 @@ #include "Packet.h" -struct ShineCollect : Packet { +struct PACKED ShineCollect : Packet { ShineCollect() : Packet() {this->mType = PacketType::SHINECOLL; mPacketSize = sizeof(ShineCollect) - sizeof(Packet);}; int shineId = -1; - bool isGrand = false; + bool1 isGrand = false; }; \ No newline at end of file diff --git a/include/packets/TagInf.h b/include/packets/TagInf.h index 22bcdb9..bd5a64e 100644 --- a/include/packets/TagInf.h +++ b/include/packets/TagInf.h @@ -8,10 +8,10 @@ enum TagUpdateType : u8 { STATE = 1 << 1 }; -struct TagInf : Packet { +struct PACKED TagInf : Packet { TagInf() : Packet() { this->mType = PacketType::TAGINF; mPacketSize = sizeof(TagInf) - sizeof(Packet);}; TagUpdateType updateType; - bool isIt = false; + bool1 isIt = false; u8 seconds; u16 minutes; }; \ No newline at end of file diff --git a/include/puppets/PuppetHolder.hpp b/include/puppets/PuppetHolder.hpp index 0b4efd6..d01f5f4 100644 --- a/include/puppets/PuppetHolder.hpp +++ b/include/puppets/PuppetHolder.hpp @@ -28,8 +28,10 @@ class PuppetHolder { void clearPuppets() { mPuppetArr.clear(); } + bool resizeHolder(int size); + private: - sead::PtrArray mPuppetArr; + sead::PtrArray mPuppetArr = sead::PtrArray(); PuppetActor *mDebugPuppet; diff --git a/include/rs/util.hpp b/include/rs/util.hpp index 6da13c9..11f6ad2 100644 --- a/include/rs/util.hpp +++ b/include/rs/util.hpp @@ -2,6 +2,7 @@ #include "game/GameData/GameDataFile.h" #include "game/Info/QuestInfoHolder.h" +#include "game/Player/PlayerActorBase.h" #include "sead/math/seadVector.h" #include "al/util.hpp" #include "al/sensor/SensorMsg.h" @@ -33,7 +34,7 @@ namespace rs { bool isPlayerDamageStopDemo(const al::LiveActor *); - PlayerActorHakoniwa * getPlayerActor(const al::Scene *); + PlayerActorBase * getPlayerActor(const al::Scene *); void get2DAreaPos(sead::Vector3 *, al::AreaObj const *); @@ -75,5 +76,9 @@ namespace rs { void calcGroundNormalOrGravityDir(sead::Vector3f *result, al::LiveActor const *actor, IUsePlayerCollision const *col); - void calcPlayerFrontDir(sead::Vector3f *result, al::LiveActor const *); + void calcPlayerFrontDir(sead::Vector3f* result, al::LiveActor const*); + + int getStageShineAnimFrame(al::LiveActor const*, char const*); + const char* getStageShineArchiveName(al::LiveActor const*, char const*); + const char* getStageShineEmptyArchiveName(al::LiveActor const*, char const*); } diff --git a/include/rs/util/SensorUtil.h b/include/rs/util/SensorUtil.h index 959b520..12e4cc2 100644 --- a/include/rs/util/SensorUtil.h +++ b/include/rs/util/SensorUtil.h @@ -5,6 +5,8 @@ #include "al/sensor/SensorHitGroup.h" #include "al/LiveActor/LiveActor.h" // for SensorMsg +#include "game/Interfaces/IUsePlayerHack.h" +#include "game/Player/PlayerHackKeeper.h" #include @@ -880,7 +882,7 @@ bool sendMsgGolemStampPress(al::HitSensor*, al::HitSensor*); // bool sendMsgSwitchOnWithSaveRequest(al::LiveActor*, SaveObjInfo*); bool sendMsgWanwanReboundAttackToCollided(al::LiveActor const*, al::HitSensor*); bool sendMsgWanwanBlockAttackToCollided(al::LiveActor const*, al::HitSensor*); -bool sendMsgDigPointSmell(al::HitSensor*, al::HitSensor*, DigPoint*); +bool sendMsgDigPointSmell(al::HitSensor*, al::HitSensor*, struct DigPoint*); bool sendMsgMofumofuBodyChainExplode(al::HitSensor*, al::HitSensor*, int); bool sendMsgMoonBasementRockThroughCollision(al::HitSensor*, al::HitSensor*, bool); bool sendMsgFishingWait(al::HitSensor*, al::HitSensor*, al::HitSensor*); @@ -1006,7 +1008,7 @@ bool sendMsgBossMagmaDeadDemoStart(al::HitSensor*, al::HitSensor*); bool sendMsgBossMagmaDeadDemoEnd(al::HitSensor*, al::HitSensor*, sead::Vector3 const&); bool sendMsgBossMagmaResetPos(al::HitSensor*, al::HitSensor*, sead::Vector3 const&); bool sendMsgBossMagmaQueryToBubble(al::HitSensor*, al::HitSensor*); -bool sendMsgCheckFishingTarget(al::HitSensor*, al::HitSensor*, FishingFish const*); +bool sendMsgCheckFishingTarget(al::HitSensor*, al::HitSensor*, struct FishingFish const*); bool sendMsgPushToPlayerAndKillVelocityToTarget(al::LiveActor*, al::HitSensor*, al::HitSensor*); bool sendMsgPushToPlayerAndKillVelocityToTargetH(al::LiveActor*, al::HitSensor*, al::HitSensor*); bool sendMsgInitCapTarget(al::HitSensor*, al::HitSensor*, CapTargetInfo const**); diff --git a/include/server/Client.hpp b/include/server/Client.hpp index 736b7d8..75df45f 100644 --- a/include/server/Client.hpp +++ b/include/server/Client.hpp @@ -2,9 +2,9 @@ * @file server/Client.hpp * @author CraftyBoss (https://github.com/CraftyBoss) * @brief main class responsible for handing all client-server related communications, as well as any gamemodes. - * + * * @copyright Copyright (c) 2022 - * + * */ #pragma once @@ -24,6 +24,7 @@ #include "container/seadPtrArray.h" #include "game/Actors/Shine.h" +#include "game/GameData/GameDataHolderAccessor.h" #include "game/Player/PlayerActorHakoniwa.h" #include "game/StageScene/StageScene.h" #include "game/Layouts/CoinCounter.h" @@ -31,6 +32,8 @@ #include "game/GameData/GameDataHolderWriter.h" #include "game/GameData/GameDataFunction.h" +#include "heap/seadFrameHeap.h" +#include "heap/seadHeap.h" #include "layouts/HideAndSeekIcon.h" #include "rs/util.hpp" @@ -65,6 +68,8 @@ #include +#define MAXPUPINDEX 32 + struct UIDIndexNode { nn::account::Uid uid; int puppetIndex; @@ -73,17 +78,17 @@ struct UIDIndexNode { class HideAndSeekIcon; class Client { + SEAD_SINGLETON_DISPOSER(Client) + public: - static Client *sInstance; + Client(); - Client(int bufferSize); - - void init(al::LayoutInitInfo const &initInfo); + void init(al::LayoutInitInfo const &initInfo, GameDataHolderAccessor holder); bool StartThreads(); void readFunc(); void recvFunc(); - static void stopConnection(); + static void restartConnection(); bool isDone() { return mReadThread->isDone(); }; static bool isSocketActive() { return sInstance ? sInstance->mSocket->isConnected() : false; }; @@ -91,10 +96,8 @@ 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 sendPlayerInfPacket(const PlayerActorBase *player, bool isYukimaru); static void sendGameInfPacket(const PlayerActorHakoniwa *player, GameDataHolderAccessor holder); static void sendGameInfPacket(GameDataHolderAccessor holder); static void sendCostumeInfPacket(const char *body, const char *cap); @@ -105,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); @@ -125,35 +126,22 @@ 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 : 10;} - - static void toggleCurrentMode(); + static int getMaxPlayerCount() { return sInstance ? sInstance->maxPuppets + 1 : 10;} static void updateStates(); static void clearArrays(); + static Keyboard* getKeyboard(); + static const char* getCurrentIP(); static void setLastUsedIP(const char* ip); + static const int getCurrentPort(); + + static void setLastUsedPort(const int port); + static void setTagState(bool state); static int getConnectCount() { @@ -162,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); @@ -170,22 +164,14 @@ class Client { static void updateShines(); - static void openKeyboardIP(); + static bool openKeyboardIP(); + static bool openKeyboardPort(); - static GameModeInfoBase* getModeInfo() { - return sInstance ? sInstance->mModeInfo : nullptr; - } + static void showConnect(); - // should only be called during mode init - static void setModeInfo(GameModeInfoBase* info) { - if(sInstance) sInstance->mModeInfo = info; - } + static void showConnectError(const char16_t* msg); - 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 hideConnect(); void resetCollectedShines(); @@ -194,8 +180,6 @@ class Client { // public for debug purposes SocketClient *mSocket; - int maxPuppets; - private: void updatePlayerInfo(PlayerInf *packet); void updateHackCapInfo(HackCapInf *packet); @@ -208,7 +192,7 @@ class Client { void sendToStage(ChangeStagePacket* packet); void disconnectPlayer(PlayerDC *packet); - int findPuppetID(const nn::account::Uid& id); + PuppetInfo* findPuppetInfo(const nn::account::Uid& id, bool isFindAvailable); bool startConnection(); @@ -218,33 +202,34 @@ class Client { al::AsyncFunctorThread *mReadThread = nullptr; // TODO: use this thread to send any queued packets // al::AsyncFunctorThread *mRecvThread; // TODO: use this thread to recieve packets and update PuppetInfo - sead::SafeArray puppetPlayerID; - int mConnectCount = 0; nn::account::Uid mUserID; sead::FixedSafeString<0x20> mUsername; + bool mIsConnectionActive = false; + // --- Server Syncing Members --- // array of shine IDs for checking if multiple shines have been collected in quick sucession, all moons within the players stage that match the ID will be deleted - sead::SafeArray curCollectedShines; + sead::SafeArray curCollectedShines; int collectedShineCount = 0; int lastCollectedShine = -1; - PlayerInf lastPlayerInfPacket = - PlayerInf(); // Info struct for storing our currently logged player information - + // Backups for our last player/game packets, used for example to re-send them for newly connected clients + PlayerInf lastPlayerInfPacket = PlayerInf(); GameInf lastGameInfPacket = GameInf(); + CostumeInf lastCostumeInfPacket = CostumeInf(); Keyboard* mKeyboard = nullptr; // keyboard for setting server IP - sead::FixedSafeString<0x10> mServerIP; + hostname mServerIP; - int mServerPort = 1027; // TODO: implement a way to set this the same way the IP can + int mServerPort = 0; + bool waitForGameInit = true; bool isFirstConnect = true; // --- Game Layouts --- @@ -253,8 +238,6 @@ class Client { // --- Game Info --- - bool mIsInGame = false; - bool isClientCaptured = false; bool isSentCaptureInf = false; @@ -270,23 +253,19 @@ class Client { sead::FixedSafeString<0x40> mStageName; + GameDataHolderAccessor mHolder; + u8 mScenario = 0; - // --- 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; + sead::FrameHeap *mHeap = nullptr; // Custom FrameHeap used for all Client related memory // --- Puppet Info --- - PuppetInfo *mPuppetInfoArr[32]; + int maxPuppets = 9; // default max player count is 10, so default max puppets will be 9 + + PuppetInfo *mPuppetInfoArr[MAXPUPINDEX] = {}; PuppetHolder *mPuppetHolder = nullptr; PuppetInfo mDebugPuppetInfo; -}; \ No newline at end of file +}; diff --git a/include/server/SocketClient.hpp b/include/server/SocketClient.hpp index 0aa4959..42dad30 100644 --- a/include/server/SocketClient.hpp +++ b/include/server/SocketClient.hpp @@ -22,7 +22,8 @@ class SocketClient : public SocketBase { mPacketQueue = sead::PtrArray(); mPacketQueue.tryAllocBuffer(maxBufSize, nullptr); }; - nn::Result init(const char * ip, u16 port) override; + nn::Result init(const char* ip, u16 port) override; + bool closeSocket() override; bool SEND(Packet *packet); bool RECV(); void printPacket(Packet* packet); @@ -32,4 +33,11 @@ class SocketClient : public SocketBase { private: int maxBufSize = 100; -}; \ No newline at end of file + + /** + * @param str a string containing an IPv4 address or a hostname that can be resolved via DNS + * @param out IPv4 address + * @return if this function was successfull and out contains a valid IP address + */ + bool stringToIPAddress(const char* str, in_addr* out); +}; 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/include/types.h b/include/types.h index 4937f7b..e571b4d 100644 --- a/include/types.h +++ b/include/types.h @@ -5,6 +5,7 @@ #include #include #include +#include "sead/prim/seadSafeString.h" typedef unsigned char u8; typedef unsigned short u16; @@ -18,6 +19,10 @@ typedef signed int s32; typedef int64_t s64; typedef __int128_t s128; +// bool size is implementation defined, so use these where it's important +typedef u8 bool1; +typedef u32 bool4; + typedef float f32; typedef double f64; @@ -37,6 +42,9 @@ typedef unsigned int undefined3; typedef unsigned int undefined4; typedef unsigned long undefined8; +const u8 MAX_HOSTNAME_LENGTH = 50; +typedef sead::FixedSafeString hostname; + enum SocketLogState { SOCKET_LOG_UNINITIALIZED = 0, SOCKET_LOG_CONNECTED = 1, @@ -76,3 +84,6 @@ struct Rect float right; float top; }; + +#define PACKED __attribute__((packed)) +#define USED __attribute__((used)) diff --git a/patches/codehook.slpatch b/patches/codehook.slpatch index 0a67d8c..992672f 100644 --- a/patches/codehook.slpatch +++ b/patches/codehook.slpatch @@ -29,6 +29,7 @@ B59E28 B seadPrintHook // sead::system::print 1B3F0C NOP // disables call to open HTML viewer during first time odyssey flight 1F2A2C MOV W0, #1 // patches checkpoint system to always allow warping +216FAC MOV W0, #0 // disables AppearSwitchTimer's camera switch // Puppet Actor Setup 4B5E30 B ProjectActorFactory // patches actor factory ctor with custom matching factory @@ -110,4 +111,5 @@ B59E28 B seadPrintHook // sead::system::print 4C9080 BL createTicketHook // hook to the init of a stage to create custom gravity camera ticket 5C00B0 BL borderPullBackHook // hooks over isFirstStep in WorldEndBorderKeeper::exePullBack so we can kill the player if they reach the border of the map - \ No newline at end of file + +// 4E46BC NOP // removes call to setEnableData for one of the commonverticallists in the options menu, which makes all entries in the menu look the same \ No newline at end of file diff --git a/romfs/ObjectData/PuppetActor.szs b/romfs/ObjectData/PuppetActor.szs new file mode 100644 index 0000000..75fd89f Binary files /dev/null and b/romfs/ObjectData/PuppetActor.szs differ diff --git a/scripts/tcpServer.py b/scripts/tcpServer.py index 5f2c7b5..6740768 100644 --- a/scripts/tcpServer.py +++ b/scripts/tcpServer.py @@ -6,8 +6,12 @@ import sys # Create a TCP/IP socket sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) +port = 3080 +if len(sys.argv) == 3: + port = int(sys.argv[2]) + # Bind the socket to the port -server_address = (sys.argv[1], 3080) +server_address = (sys.argv[1], port) print(f"Starting TCP Server with IP {server_address[0]} and Port {server_address[1]}.") sock.bind(server_address) @@ -22,12 +26,17 @@ while True: print(f'Switch Connected! IP: {client_address[0]} Port: {client_address[1]}') while True: data = connection.recv(1024) + if data: - print(data.decode("utf-8")) + print(data.decode("utf-8"), end='', flush=True) else: print(f'Connection Terminated.') break - + + except ConnectionResetError: + print("Connection reset") + finally: # Clean up the connection - connection.close() \ No newline at end of file + connection.close() + diff --git a/source/Keyboard.cpp b/source/Keyboard.cpp index 47a5e00..63dfa25 100644 --- a/source/Keyboard.cpp +++ b/source/Keyboard.cpp @@ -15,24 +15,15 @@ Keyboard::Keyboard(ulong strSize) : mResultString(strSize) { mCustomizeDicSize = 0x400; mCustomizeDicBuf = (char*)malloc(mCustomizeDicSize); - - mIsDoneKeyboard = false; } void Keyboard::keyboardThread() { - - mIsDoneKeyboard = false; nn::swkbd::ShowKeyboardArg keyboardArg = nn::swkbd::ShowKeyboardArg(); nn::swkbd::MakePreset(&keyboardArg.keyboardConfig, nn::swkbd::Preset::Default); - keyboardArg.keyboardConfig.keyboardMode = nn::swkbd::KeyboardMode::ModeNumeric; - keyboardArg.keyboardConfig.leftOptionalSymbolKey = '.'; - keyboardArg.keyboardConfig.textMaxLength = 15; - keyboardArg.keyboardConfig.textMinLength = 1; - keyboardArg.keyboardConfig.isUseUtf8 = true; - keyboardArg.keyboardConfig.inputFormMode = nn::swkbd::InputFormMode::OneLine; + mSetupFunc(keyboardArg.keyboardConfig); nn::swkbd::SetHeaderText(&keyboardArg.keyboardConfig, mHeaderText); nn::swkbd::SetSubText(&keyboardArg.keyboardConfig, mSubText); @@ -49,15 +40,15 @@ void Keyboard::keyboardThread() { nn::swkbd::SetInitialTextUtf8(&keyboardArg, mInitialText.cstr()); } - nn::swkbd::ShowKeyboard(&mResultString, keyboardArg); - - mIsDoneKeyboard = true; - + mIsCancelled = + nn::swkbd::ShowKeyboard(&mResultString, keyboardArg) == 671; // no idea what 671 could be + } -void Keyboard::openKeyboard(const char* initialText) { +void Keyboard::openKeyboard(const char* initialText, KeyboardSetup setupFunc) { mInitialText = initialText; + mSetupFunc = setupFunc; mThread->start(); } \ No newline at end of file diff --git a/source/hooks.cpp b/source/hooks.cpp index acfbb3f..4cb2cea 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); @@ -39,11 +39,18 @@ bool comboBtnHook(int port) { void saveWriteHook(al::ByamlWriter* saveByml) { const char *serverIP = Client::getCurrentIP(); + const int serverPort = Client::getCurrentPort(); if (serverIP) { saveByml->addString("ServerIP", serverIP); } else { - saveByml->addString("ServerIP", "0.0.0.0"); + saveByml->addString("ServerIP", "127.0.0.1"); + } + + if (serverPort) { + saveByml->addInt("ServerPort", serverPort); + } else { + saveByml->addInt("ServerPort", 0); } saveByml->pop(); @@ -52,10 +59,15 @@ void saveWriteHook(al::ByamlWriter* saveByml) { bool saveReadHook(int* padRumbleInt, al::ByamlIter const& saveByml, char const* padRumbleKey) { const char *serverIP = ""; + int serverPort = 0; if (al::tryGetByamlString(&serverIP, saveByml, "ServerIP")) { Client::setLastUsedIP(serverIP); } + + if (al::tryGetByamlS32(&serverPort, saveByml, "ServerPort")) { + Client::setLastUsedPort(serverPort); + } return al::tryGetByamlS32(padRumbleInt, saveByml, padRumbleKey); } @@ -98,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(); } } @@ -123,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); } @@ -145,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); @@ -156,4 +168,4 @@ bool borderPullBackHook(WorldEndBorderKeeper* thisPtr) { } return isFirstStep; -} \ No newline at end of file +} diff --git a/source/layouts/HideAndSeekIcon.cpp b/source/layouts/HideAndSeekIcon.cpp index 7b8b579..3f47326 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); @@ -80,7 +80,7 @@ void HideAndSeekIcon::exeWait() { - int playerCount = Client::getConnectCount(); + int playerCount = Client::getMaxPlayerCount(); if (playerCount > 0) { @@ -91,7 +91,7 @@ void HideAndSeekIcon::exeWait() { for (size_t i = 0; i < playerCount; i++) { PuppetInfo* curPuppet = Client::getPuppetInfo(i); - if (curPuppet->isConnected && (curPuppet->isIt == mInfo->mIsPlayerIt)) { + if (curPuppet && curPuppet->isConnected && (curPuppet->isIt == mInfo->mIsPlayerIt)) { playerList.appendWithFormat("%s\n", curPuppet->puppetName); } } diff --git a/source/layouts/NameTag.cpp b/source/layouts/NameTag.cpp index 5d42f81..44bbe4b 100644 --- a/source/layouts/NameTag.cpp +++ b/source/layouts/NameTag.cpp @@ -37,7 +37,7 @@ void NameTag::appear() { return; } - setText(mPuppet->getPuppetName()); + setText(mPuppet->getName()); al::startAction(this, "Appear", 0); LayoutActor::appear(); diff --git a/source/main.cpp b/source/main.cpp index 49b0d07..c328ada 100644 --- a/source/main.cpp +++ b/source/main.cpp @@ -1,6 +1,10 @@ #include "main.hpp" #include #include +#include "game/Player/PlayerActorBase.h" +#include "game/Player/PlayerActorHakoniwa.h" +#include "game/Player/PlayerHackKeeper.h" +#include "math/seadVector.h" #include "server/Client.hpp" #include "puppets/PuppetInfo.h" #include "actors/PuppetActor.h" @@ -21,25 +25,35 @@ #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; -void updatePlayerInfo(GameDataHolderAccessor holder, PlayerActorHakoniwa *p1) { - if(pInfSendTimer >= 3) { - Client::sendPlayerInfPacket(p1); +void updatePlayerInfo(GameDataHolderAccessor holder, PlayerActorBase* playerBase, bool isYukimaru) { + + if (pInfSendTimer >= 3) { - Client::sendHackCapInfPacket(p1->mHackCap); + Client::sendPlayerInfPacket(playerBase, isYukimaru); - Client::sendCaptureInfPacket(p1); + if (!isYukimaru) { + Client::sendHackCapInfPacket(((PlayerActorHakoniwa*)playerBase)->mHackCap); + + Client::sendCaptureInfPacket((PlayerActorHakoniwa*)playerBase); + } pInfSendTimer = 0; } if (gameInfSendTimer >= 60) { - Client::sendGameInfPacket(p1, holder); + if (isYukimaru) { + Client::sendGameInfPacket(holder); + } else { + Client::sendGameInfPacket((PlayerActorHakoniwa*)playerBase, holder); + } + gameInfSendTimer = 0; } @@ -88,8 +102,9 @@ void drawMainHook(HakoniwaSequence *curSequence, sead::Viewport *viewport, sead: gTextWriter->setCursorFromTopLeft(sead::Vector2f(10.f, (dispHeight / 3) + 30.f)); gTextWriter->setScaleFromFontHeight(20.f); - gTextWriter->printf("Client Socket Connection Status: %s\n", Client::sInstance->mSocket->getStateChar()); - gTextWriter->printf("Packet Queue Length: %d\n", Client::sInstance->mSocket->mPacketQueue.size()); + gTextWriter->printf("Client Socket Connection Status: %s\n", Client::instance()->mSocket->getStateChar()); + gTextWriter->printf("nn::socket::GetLastErrno: 0x%x\n", Client::instance()->mSocket->socket_errno); + gTextWriter->printf("Packet Queue Length: %d\n", Client::instance()->mSocket->mPacketQueue.size()); gTextWriter->printf("Total Connected Players: %d\n", Client::getConnectCount() + 1); al::Scene *curScene = curSequence->curScene; @@ -99,7 +114,7 @@ void drawMainHook(HakoniwaSequence *curSequence, sead::Viewport *viewport, sead: sead::LookAtCamera *cam = al::getLookAtCamera(curScene, 0); sead::Projection* projection = al::getProjectionSead(curScene, 0); - PlayerActorHakoniwa* p1 = rs::getPlayerActor(curScene); + PlayerActorBase* playerBase = rs::getPlayerActor(curScene); PuppetActor* curPuppet = Client::getPuppet(debugPuppetIndex); @@ -136,6 +151,7 @@ void drawMainHook(HakoniwaSequence *curSequence, sead::Viewport *viewport, sead: gTextWriter->printf("Is in Capture: %s\n", curPupInfo->isCaptured ? "True" : "False"); gTextWriter->printf("Puppet Stage: %s\n", curPupInfo->stageName); gTextWriter->printf("Puppet Scenario: %u\n", curPupInfo->scenarioNo); + gTextWriter->printf("Puppet Costume: H: %s B: %s\n", curPupInfo->costumeHead, curPupInfo->costumeBody); //gTextWriter->printf("Packet Coords:\nX: %f\nY: %f\nZ: %f\n", curPupInfo->playerPos.x, curPupInfo->playerPos.y, curPupInfo->playerPos.z); // if (curModel) { // sead::Vector3f* pupPos = al::getTrans(curModel); @@ -164,30 +180,27 @@ void drawMainHook(HakoniwaSequence *curSequence, sead::Viewport *viewport, sead: if (debugPuppet && debugInfo) { al::LiveActor *curModel = debugPuppet->getCurrentModel(); - - gTextWriter->printf("Is Nametag Visible: %s\n", BTOC(debugPuppet->mNameTag->isVisible())); - gTextWriter->printf("Is Nametag Alive: %s\n", BTOC(debugPuppet->mNameTag->mIsAlive)); - gTextWriter->printf("Nametag Normalized Dist: %f\n", debugPuppet->mNameTag->mNormalizedDist); - gTextWriter->printf("Nametag State: %s\n", debugPuppet->mNameTag->getCurrentState()); - gTextWriter->printf("Is Current Model Clipped: %s\n", - BTOC(al::isClipped(curModel))); + gTextWriter->printf("Is Debug Puppet Tagged: %s\n", BTOC(debugInfo->isIt)); } } break; case 2: - { - al::PlayerHolder *pHolder = al::getScenePlayerHolder(curScene); - PlayerActorHakoniwa *p1 = pHolder->tryGetPlayer(0); + { + PlayerHackKeeper* hackKeeper = playerBase->getPlayerHackKeeper(); - if (p1->mHackKeeper && p1->mHackKeeper->currentHackActor) { + if (hackKeeper) { + + PlayerActorHakoniwa *p1 = (PlayerActorHakoniwa*)playerBase; // its safe to assume that we're using a playeractorhakoniwa if the hack keeper isnt null + + if(hackKeeper->currentHackActor) { + + al::LiveActor *curHack = hackKeeper->currentHackActor; - al::LiveActor *curHack = p1->mHackKeeper->currentHackActor; - gTextWriter->printf("Current Hack Animation: %s\n", al::getActionName(curHack)); gTextWriter->printf("Current Hack Name: %s\n", - p1->mHackKeeper->getCurrentHackName()); + hackKeeper->getCurrentHackName()); sead::Quatf captureRot = curHack->mPoseKeeper->getQuat(); gTextWriter->printf("Current Hack Rot: %f %f %f %f\n", captureRot.x, captureRot.y, captureRot.z, captureRot.w); @@ -195,7 +208,7 @@ void drawMainHook(HakoniwaSequence *curSequence, sead::Viewport *viewport, sead: al::calcQuat(&calcRot, curHack); gTextWriter->printf("Calc Hack Rot: %f %f %f %f\n", calcRot.x, calcRot.y, calcRot.z, calcRot.w); - }else { + } else { gTextWriter->printf("Cur Action: %s\n", p1->mPlayerAnimator->mAnimFrameCtrl->getActionName()); gTextWriter->printf("Cur Sub Action: %s\n", p1->mPlayerAnimator->curSubAnim.cstr()); gTextWriter->printf("Is Cappy Flying? %s\n", BTOC(p1->mHackCap->isFlying())); @@ -208,14 +221,16 @@ void drawMainHook(HakoniwaSequence *curSequence, sead::Viewport *viewport, sead: gTextWriter->printf("Cap Skew: %f\n", p1->mHackCap->mJointKeeper->mSkew); } } - } + } + + } break; default: break; } renderer->begin(); - + //sead::Matrix34f mat = sead::Matrix34f::ident; //mat.setBase(3, sead::Vector3f::zero); // Sets the position of the matrix. // For cubes, you need to put this at the location. @@ -243,7 +258,7 @@ void sendShinePacket(GameDataHolderWriter thisPtr, Shine* curShine) { if (!curShine->isGot()) { Client::sendShineCollectPacket(curShine->shineId); } - + GameDataFunction::setGotShine(thisPtr, curShine->curShineInfo); } @@ -251,19 +266,20 @@ void stageInitHook(al::ActorInitInfo *info, StageScene *curScene, al::PlacementI al::initActorInitInfo(info, curScene, placement, lytInfo, factory, sceneMsgCtrl, dataHolder); - + Client::clearArrays(); 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); - + } PlayerCostumeInfo *setPlayerModel(al::LiveActor *player, const al::ActorInitInfo &initInfo, const char *bodyModel, const char *capModel, al::AudioKeeper *keeper, bool isCloset) { @@ -280,8 +296,9 @@ ulong constructHook() { // hook for constructing anything we need to globally b __asm("MOV %[result], X20" : [result] "=r"( initInfo)); // Save our scenes init info to a gloabl ptr so we can access it later - - Client::sInstance = new Client(playBufSize); + + Client::createInstance(al::getCurrentHeap()); + GameModeManager::createInstance(al::getCurrentHeap()); // Create the GameModeManager on the current al heap return 0x20; } @@ -292,7 +309,7 @@ bool threadInit(HakoniwaSequence *mainSeq) { // hook for initializing client cl al::initLayoutInitInfo(&lytInfo, mainSeq->mLytKit, 0, mainSeq->mAudioDirector, initInfo->mSystemInfo->mLayoutSys, initInfo->mSystemInfo->mMessageSys, initInfo->mSystemInfo->mGamePadSys); - Client::sInstance->init(lytInfo); + Client::instance()->init(lytInfo, mainSeq->mGameDataHolder); return GameDataFunction::isPlayDemoOpening(mainSeq->mGameDataHolder); } @@ -305,15 +322,13 @@ bool hakoniwaSequenceHook(HakoniwaSequence* sequence) { bool isFirstStep = al::isFirstStep(sequence); al::PlayerHolder *pHolder = al::getScenePlayerHolder(stageScene); - PlayerActorHakoniwa* p1 = (PlayerActorHakoniwa*)al::tryGetPlayerActor(pHolder, 0); - - if (isFirstStep) { - Client::tryRestartCurrentMode(); - } + PlayerActorBase* playerBase = al::tryGetPlayerActor(pHolder, 0); + bool isYukimaru = !playerBase->getPlayerInfo(); + isInGame = !stageScene->isPause(); - Client::setGameActive(!stageScene->isPause()); + GameModeManager::instance()->setPaused(stageScene->isPause()); Client::setStageInfo(stageScene->mHolder); Client::updateStates(); @@ -322,9 +337,9 @@ bool hakoniwaSequenceHook(HakoniwaSequence* sequence) { Client::updateShines(); } - updatePlayerInfo(stageScene->mHolder, p1); + updatePlayerInfo(stageScene->mHolder, playerBase, isYukimaru); - static bool isDisableMusic = true; + static bool isDisableMusic = false; if (al::isPadHoldZR(-1)) { if (al::isPadTriggerUp(-1)) debugMode = !debugMode; @@ -342,35 +357,48 @@ bool hakoniwaSequenceHook(HakoniwaSequence* sequence) { if (al::isPadTriggerRight(-1)) debugPuppetIndex++; if(debugPuppetIndex < 0) { - debugPuppetIndex = playBufSize - 2; + debugPuppetIndex = Client::getMaxPlayerCount() - 2; } - if (debugPuppetIndex >= playBufSize) + if (debugPuppetIndex >= Client::getMaxPlayerCount() - 1) debugPuppetIndex = 0; } - + } 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(); + + PuppetInfo* debugPuppet = Client::getDebugPuppetInfo(); + if (debugPuppet) { - debugPuppet->playerPos = al::getTrans(p1); - al::calcQuat(&debugPuppet->playerRot, p1); - const char *hackName = p1->mHackKeeper->getCurrentHackName(); - debugPuppet->isCaptured = hackName != nullptr; - if (debugPuppet->isCaptured) { - strcpy(debugPuppet->curHack, hackName); - } else { - strcpy(debugPuppet->curHack, ""); + + debugPuppet->playerPos = al::getTrans(playerBase); + al::calcQuat(&debugPuppet->playerRot, playerBase); + + PlayerHackKeeper* hackKeeper = playerBase->getPlayerHackKeeper(); + + if (hackKeeper) { + const char *hackName = hackKeeper->getCurrentHackName(); + debugPuppet->isCaptured = hackName != nullptr; + if (debugPuppet->isCaptured) { + strcpy(debugPuppet->curHack, hackName); + } else { + strcpy(debugPuppet->curHack, ""); + } } + } } } if (al::isPadTriggerUp(-1)) { if (debugMode) { - PuppetInfo* debugPuppet = Client::getDebugPuppetInfo(); + PuppetActor* debugPuppet = Client::getDebugPuppet(); if (debugPuppet) { - debugPuppet->isIt = !debugPuppet->isIt; + PuppetInfo *info = debugPuppet->getInfo(); + // info->isIt = !info->isIt; + + debugPuppet->emitJoinEffect(); + } } else { isDisableMusic = !isDisableMusic; @@ -388,7 +416,7 @@ bool hakoniwaSequenceHook(HakoniwaSequence* sequence) { } -void seadPrintHook(const char *fmt, ...) +void seadPrintHook(const char *fmt, ...) { va_list args; va_start(args, fmt); diff --git a/source/nx/svc.s b/source/nx/svc.s new file mode 100644 index 0000000..7d9b618 --- /dev/null +++ b/source/nx/svc.s @@ -0,0 +1,17 @@ +.macro SVC_BEGIN name + .section .text.\name, "ax", %progbits + .global \name + .type \name, %function + .align 2 + .cfi_startproc +\name: +.endm + +.macro SVC_END + .cfi_endproc +.endm + +SVC_BEGIN svcOutputDebugString + svc 0x27 + ret +SVC_END \ No newline at end of file diff --git a/source/puppets/PuppetActor.cpp b/source/puppets/PuppetActor.cpp index 20b4b5d..2c20b61 100644 --- a/source/puppets/PuppetActor.cpp +++ b/source/puppets/PuppetActor.cpp @@ -1,3 +1,7 @@ +#include +#include +#include "al/util/SensorUtil.h" +#include "rs/util/SensorUtil.h" #include "server/Client.hpp" #include "al/LiveActor/LiveActor.h" #include "al/layout/BalloonMessage.h" @@ -10,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 @@ -31,7 +36,7 @@ void PuppetActor::init(al::ActorInitInfo const &initInfo) { mPuppetCap->init(initInfo); - al::initActorWithArchiveName(this, initInfo, "PlayerActorHakoniwa", nullptr); + al::initActorWithArchiveName(this, initInfo, "PuppetActor", nullptr); const char *bodyName = "Mario"; const char *capName = "Mario"; @@ -185,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) @@ -207,25 +212,22 @@ void PuppetActor::control() { } void PuppetActor::makeActorAlive() { - + al::LiveActor *curModel = getCurrentModel(); if (al::isDead(curModel)) { curModel->makeActorAlive(); } - if (al::isDead(this)) { - - // update name tag when puppet becomes active again - if (mInfo) { - if (mNameTag) { - mNameTag->setText(mInfo->puppetName); - } + // update name tag when puppet becomes active again + if (mInfo) { + if (mNameTag) { + mNameTag->setText(mInfo->puppetName); } - - al::LiveActor::makeActorAlive(); } + al::LiveActor::makeActorAlive(); + } void PuppetActor::makeActorDead() { @@ -236,11 +238,29 @@ void PuppetActor::makeActorDead() { curModel->makeActorDead(); } - if (!al::isDead(this)) { - mPuppetCap->makeActorDead(); // make sure we kill the cap puppet along with regular puppet + mPuppetCap->makeActorDead(); + + al::LiveActor::makeActorDead(); +} - al::LiveActor::makeActorDead(); +void PuppetActor::attackSensor(al::HitSensor* source, al::HitSensor* target) { + + if (!al::sendMsgPush(target, source)) { + rs::sendMsgPushToPlayer(target, source); } + +} + +bool PuppetActor::receiveMsg(const al::SensorMsg* msg, al::HitSensor* source, + al::HitSensor* target) { + + if ((al::isMsgPlayerTrampleReflect(msg) || rs::isMsgPlayerAndCapObjHipDropReflectAll(msg)) && al::isSensorName(target, "Body")) + { + rs::requestHitReactionToAttacker(msg, target, source); + return true; + } + + return false; } // this is more or less how nintendo does it with marios demo puppet @@ -379,3 +399,10 @@ void PuppetActor::syncPose() { al::setTrans(curModel, al::getTrans(this)); } + +void PuppetActor::emitJoinEffect() { + + al::tryDeleteEffect(this, "Disappear"); // remove previous effect (if played previously) + + al::tryEmitEffect(this, "Disappear", nullptr); +} \ No newline at end of file diff --git a/source/puppets/PuppetHolder.cpp b/source/puppets/PuppetHolder.cpp index 5fe34a9..f730c7b 100644 --- a/source/puppets/PuppetHolder.cpp +++ b/source/puppets/PuppetHolder.cpp @@ -1,13 +1,53 @@ #include "puppets/PuppetHolder.hpp" +#include +#include "actors/PuppetActor.h" #include "al/util.hpp" +#include "al/util/LiveActorUtil.h" +#include "container/seadPtrArray.h" +#include "heap/seadHeap.h" +#include "heap/seadHeapMgr.h" #include "logger.hpp" PuppetHolder::PuppetHolder(int size) { - mPuppetArr = sead::PtrArray(); if(!mPuppetArr.tryAllocBuffer(size, nullptr)) { Logger::log("Buffer Alloc Failed on Puppet Holder!\n"); } } +/** + * @brief resizes puppet ptr array by creating a new ptr array and storing previous ptrs in it, before freeing the previous array + * + * @param size the size of the new ptr array + * @return returns true if resizing was sucessful + */ +bool PuppetHolder::resizeHolder(int size) { + + if (mPuppetArr.capacity() == size) + return true; // no need to resize if we're already at the same capacity + + sead::Heap *seqHeap = sead::HeapMgr::instance()->findHeapByName("SequenceHeap", 0); + + if (!mPuppetArr.isBufferReady()) + return mPuppetArr.tryAllocBuffer(size, seqHeap); + + sead::PtrArray newPuppets = sead::PtrArray(); + + if (newPuppets.tryAllocBuffer(size, seqHeap)) { + + int curPupCount = mPuppetArr.size(); + + for (int i = 0; i < curPupCount > size ? size : curPupCount; i++) { + newPuppets.pushBack(mPuppetArr[i]); + } + + mPuppetArr.freeBuffer(); + + mPuppetArr = newPuppets; + + return true; + } else { + return false; + } +} bool PuppetHolder::tryRegisterPuppet(PuppetActor *puppet) { if(!mPuppetArr.isFull()) { @@ -39,10 +79,14 @@ void PuppetHolder::update() { curInfo->isInSameStage = checkInfoIsInStage(curInfo); - if(curInfo->isInSameStage) { + if(curInfo->isInSameStage && al::isDead(curPuppet)) { curPuppet->makeActorAlive(); - }else if(!curInfo->isInSameStage) { + + curPuppet->emitJoinEffect(); + }else if(!curInfo->isInSameStage && !al::isDead(curPuppet)) { curPuppet->makeActorDead(); + + curPuppet->emitJoinEffect(); } } } diff --git a/source/puppets/PuppetMain.cpp b/source/puppets/PuppetMain.cpp index d3de1c9..e222547 100644 --- a/source/puppets/PuppetMain.cpp +++ b/source/puppets/PuppetMain.cpp @@ -60,7 +60,7 @@ void initPuppetActors(al::Scene *scene, al::ActorInitInfo const &rootInfo, char al::PlacementInfo playerPlacement = al::PlacementInfo(); al::getPlacementInfoByIndex(&playerPlacement, rootPlacement, 0); - for (size_t i = 0; i < Client::sInstance->maxPuppets; i++) + for (size_t i = 0; i < Client::getMaxPlayerCount(); i++) { createPuppetActorFromFactory(rootInfo, playerPlacement, false); } diff --git a/source/server/Client.cpp b/source/server/Client.cpp index 381fae6..bd5dc6c 100644 --- a/source/server/Client.cpp +++ b/source/server/Client.cpp @@ -1,14 +1,21 @@ #include "server/Client.hpp" +#include #include #include "al/actor/ActorSceneInfo.h" #include "al/layout/WindowConfirmWait.h" +#include "al/util/ControllerUtil.h" #include "al/util/LiveActorUtil.h" #include "algorithms/PlayerAnims.h" #include "game/GameData/GameDataFunction.h" #include "game/GameData/GameDataHolderAccessor.h" #include "game/Info/QuestInfo.h" +#include "game/Player/PlayerActorBase.h" #include "game/Player/PlayerActorHakoniwa.h" +#include "game/SaveData/SaveDataAccessFunction.h" #include "game/StageScene/StageScene.h" +#include "heap/seadDisposer.h" +#include "heap/seadHeap.h" +#include "heap/seadFrameHeap.h" #include "heap/seadHeapMgr.h" #include "helpers.hpp" #include "layouts/HideAndSeekIcon.h" @@ -16,19 +23,23 @@ #include "math/seadVector.h" #include "nn/err.h" #include "nn/result.h" +#include "nn/swkbd/swkbd.h" +#include "nn/util.h" #include "packets/ChangeStagePacket.h" #include "packets/InitPacket.h" #include "packets/Packet.h" #include "packets/PlayerConnect.h" +#include "packets/PlayerDC.h" #include "packets/TagInf.h" +#include "puppets/PuppetInfo.h" #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" -Client* Client::sInstance; +SEAD_SINGLETON_DISPOSER_IMPL(Client) typedef void (Client::*ClientThreadFunc)(void); @@ -37,21 +48,21 @@ typedef void (Client::*ClientThreadFunc)(void); * * @param bufferSize defines the maximum amount of puppets the client can handle */ -Client::Client(int bufferSize) { +Client::Client() { + + mHeap = sead::FrameHeap::create(0x100000, "ClientHeap", sead::HeapMgr::instance()->getCurrentHeap(), 8, sead::Heap::cHeapDirection_Forward, false); + + sead::ScopedCurrentHeapSetter heapSetter(mHeap); // every new call after this will use ClientHeap instead of SequenceHeap + this->mReadThread = new al::AsyncFunctorThread("ClientReadThread", al::FunctorV0M(this, &Client::readFunc), 0, 0x10000, {0}); - // this->recvThread = new al::AsyncFunctorThread("ClientRecvThread", - // al::FunctorV0M(this, &Client::recvFunc), 0, 0x10000, - // {0}); mKeyboard = new Keyboard(nn::swkbd::GetRequiredStringBufferSize()); mSocket = new SocketClient("SocketClient"); - maxPuppets = bufferSize - 1; - mPuppetHolder = new PuppetHolder(maxPuppets); - for (size_t i = 0; i < bufferSize + 1; i++) + for (size_t i = 0; i < MAXPUPINDEX; i++) { mPuppetInfoArr[i] = new PuppetInfo(); @@ -60,8 +71,6 @@ Client::Client(int bufferSize) { strcpy(mDebugPuppetInfo.puppetName, "PuppetDebug"); - puppetPlayerID.fill({0, 0}); - mConnectCount = 0; curCollectedShines.fill(-1); @@ -72,26 +81,18 @@ Client::Client(int bufferSize) { nn::account::GetLastOpenedUser(&mUserID); - mUserID.print(); - nn::account::Nickname playerName; nn::account::GetNickname(&playerName, mUserID); + Logger::setLogName(playerName.name); // set Debug logger name to player name mUsername = playerName.name; + + mUserID.print(); Logger::log("Player Name: %s\n", playerName.name); - #ifdef BUILDVER - Logger::log("%s Build Number: %s\n", playerName.name, TOSTRING(BUILDVER)); - #endif + Logger::log("%s Build Number: %s\n", playerName.name, TOSTRING(BUILDVERSTR)); - Logger::setLogName(playerName.name); // set Debug logger name to player name - - mServerMode = GameMode::HIDEANDSEEK; // temp for testing - - if(!sInstance) { - sInstance = this; - } } /** @@ -99,52 +100,22 @@ Client::Client(int bufferSize) { * * @param initInfo init info used to create layouts used by client */ -void Client::init(al::LayoutInitInfo const &initInfo) { +void Client::init(al::LayoutInitInfo const &initInfo, GameDataHolderAccessor holder) { - mConnectionWait = new al::WindowConfirmWait("ServerWaitConnect", "WindowConfirmWait", initInfo); + mConnectionWait = new (mHeap) al::WindowConfirmWait("ServerWaitConnect", "WindowConfirmWait", initInfo); mConnectionWait->setTxtMessage(u"Connecting to Server."); mConnectionWait->setTxtMessageConfirm(u"Failed to Connect!"); + mHolder = holder; + StartThreads(); - // mConnectionWait->tryEndForce(); + Logger::log("Remaining Heap Size: %d\n", mHeap->getFreeSize()); + } -/** - * @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 * @@ -166,30 +137,43 @@ bool Client::StartThreads() { * @brief restarts currently active connection to server * */ -void Client::stopConnection() { +void Client::restartConnection() { if (!sInstance) { Logger::log("Static Instance is null!\n"); return; } - sInstance->mSocket->closeSocket(); + Logger::log("Sending Disconnect.\n"); - sInstance->puppetPlayerID.fill({0,0}); + PlayerDC playerDC = PlayerDC(); + + playerDC.mUserID = sInstance->mUserID; + + sInstance->mSocket->SEND(&playerDC); + + if (sInstance->mSocket->closeSocket()) { + Logger::log("Sucessfully Closed Socket.\n"); + } sInstance->mConnectCount = 0; - sInstance->mSocket->init(sInstance->mServerIP.cstr(), sInstance->mServerPort); + sInstance->mIsConnectionActive = sInstance->mSocket->init(sInstance->mServerIP.cstr(), sInstance->mServerPort).isSuccess(); if(sInstance->mSocket->getLogState() == SOCKET_LOG_CONNECTED) { - Logger::log("Connected!\n"); + Logger::log("Reconnect Sucessful!\n"); PlayerConnect initPacket; initPacket.mUserID = sInstance->mUserID; strcpy(initPacket.clientName, sInstance->mUsername.cstr()); - initPacket.conType = ConnectionTypes::RECONNECT; + + initPacket.conType = ConnectionTypes::INIT; + sInstance->mSocket->SEND(&initPacket); + + } else { + Logger::log("Reconnect Unsuccessful.\n"); } } /** @@ -199,76 +183,145 @@ void Client::stopConnection() { * @return false if connection was unable to establish */ bool Client::startConnection() { - if (mServerIP.isEmpty()) { + bool isNeedSave = false; + + bool isOverride = al::isPadHoldZL(-1); + + if (mServerIP.isEmpty() || isOverride) { mKeyboard->setHeaderText(u"Save File does not contain an IP!"); mKeyboard->setSubText(u"Please set a Server IP Below."); - - mKeyboard->openKeyboard("0.0.0.0"); - - while (true) { - if (mKeyboard->isThreadDone()) { - mServerIP = mKeyboard->getResult(); - break; - } - nn::os::YieldThread(); // allow other threads to run - } + mServerIP = "127.0.0.1"; + Client::openKeyboardIP(); + isNeedSave = true; } - bool result = mSocket->init(mServerIP.cstr(), mServerPort).isSuccess(); + if (!mServerPort || isOverride) { + mKeyboard->setHeaderText(u"Save File does not contain a port!"); + mKeyboard->setSubText(u"Please set a Server Port Below."); + mServerPort = 1027; + Client::openKeyboardPort(); + isNeedSave = true; + } - if (result) { + if (isNeedSave) { + SaveDataAccessFunction::startSaveDataWrite(mHolder.mData); + } + + mIsConnectionActive = mSocket->init(mServerIP.cstr(), mServerPort).isSuccess(); + + if (mIsConnectionActive) { + + Logger::log("Sucessful Connection. Waiting to recieve init packet.\n"); + + bool waitingForInitPacket = true; // wait for client init packet - while (true) { - + while (waitingForInitPacket) { if (mSocket->RECV()) { + if(!mSocket->mPacketQueue.isEmpty()){ - Packet* curPacket = mSocket->mPacketQueue.popFront(); + Packet* curPacket = mSocket->mPacketQueue.popFront(); - if (curPacket->mType == PacketType::CLIENTINIT) { - InitPacket* initPacket = (InitPacket*)curPacket; + if (curPacket->mType == PacketType::CLIENTINIT) { + InitPacket* initPacket = (InitPacket*)curPacket; - Logger::log("Server Max Player Size: %d\n", initPacket->maxPlayers); + Logger::log("Server Max Player Size: %d\n", initPacket->maxPlayers); - maxPuppets = initPacket->maxPlayers - 1; + maxPuppets = initPacket->maxPlayers - 1; + } else { + Logger::log("First Packet was not Init!\n"); + mIsConnectionActive = false; + } - }else { - Logger::log("First Packet was not Init!\n"); - result = false; + free(curPacket); + waitingForInitPacket = false; } - free(curPacket); - + } else { + Logger::log("Recieve failed! Stopping Connection.\n"); + mIsConnectionActive = false; + waitingForInitPacket = false; } - - break; } } - - - return result; + + return mIsConnectionActive; } /** * @brief Opens up OS's software keyboard in order to change the currently used server IP. - * + * @returns whether or not a new IP has been defined and needs to be saved. */ -void Client::openKeyboardIP() { +bool Client::openKeyboardIP() { if (!sInstance) { Logger::log("Static Instance is null!\n"); - return; + return false; } - sInstance->mKeyboard->openKeyboard(sInstance->mServerIP.cstr()); // opens swkbd with the initial text set to the last saved IP + // opens swkbd with the initial text set to the last saved IP + sInstance->mKeyboard->openKeyboard( + sInstance->mServerIP.cstr(), [](nn::swkbd::KeyboardConfig& config) { + config.keyboardMode = nn::swkbd::KeyboardMode::ModeASCII; + config.textMaxLength = MAX_HOSTNAME_LENGTH; + config.textMinLength = 1; + config.isUseUtf8 = true; + config.inputFormMode = nn::swkbd::InputFormMode::OneLine; + }); + + hostname prevIp = sInstance->mServerIP; while (true) { if (sInstance->mKeyboard->isThreadDone()) { - sInstance->mServerIP = sInstance->mKeyboard->getResult(); + if(!sInstance->mKeyboard->isKeyboardCancelled()) + sInstance->mServerIP = sInstance->mKeyboard->getResult(); break; } nn::os::YieldThread(); // allow other threads to run } + + sInstance->isFirstConnect = prevIp != sInstance->mServerIP; + + return sInstance->isFirstConnect; +} + +/** + * @brief Opens up OS's software keyboard in order to change the currently used server port. + * @returns whether or not a new port has been defined and needs to be saved. + */ +bool Client::openKeyboardPort() { + + if (!sInstance) { + Logger::log("Static Instance is null!\n"); + return false; + } + + // opens swkbd with the initial text set to the last saved port + char buf[6]; + nn::util::SNPrintf(buf, 6, "%u", sInstance->mServerPort); + + sInstance->mKeyboard->openKeyboard(buf, [](nn::swkbd::KeyboardConfig& config) { + config.keyboardMode = nn::swkbd::KeyboardMode::ModeNumeric; + config.textMaxLength = 5; + config.textMinLength = 2; + config.isUseUtf8 = true; + config.inputFormMode = nn::swkbd::InputFormMode::OneLine; + }); + + int prevPort = sInstance->mServerPort; + + while (true) { + if (sInstance->mKeyboard->isThreadDone()) { + if(!sInstance->mKeyboard->isKeyboardCancelled()) + sInstance->mServerPort = ::atoi(sInstance->mKeyboard->getResult()); + break; + } + nn::os::YieldThread(); // allow other threads to run + } + + sInstance->isFirstConnect = prevPort != sInstance->mServerPort; + + return sInstance->isFirstConnect; } /** @@ -277,12 +330,13 @@ void Client::openKeyboardIP() { */ void Client::readFunc() { - if (isFirstConnect) { + if (waitForGameInit) { nn::os::YieldThread(); // sleep the thread for the first thing we do so that game init can finish nn::os::SleepThread(nn::TimeSpan::FromSeconds(2)); + waitForGameInit = false; } - // we can use the start of readFunc to display an al::WindowConfirmWait while the server + // we can use the start of readFunc to display an al::WindowConfirmWait while the client // connects mConnectionWait->appear(); @@ -291,6 +345,8 @@ void Client::readFunc() { if (!startConnection()) { + Logger::log("Failed to Connect to Server.\n"); + al::hidePane(mConnectionWait, "Page01"); // hide A button prompt since connection message automatically hides after 0.25 seconds al::startAction(mConnectionWait, "Confirm", "State"); @@ -302,22 +358,13 @@ void Client::readFunc() { return; } - if (isFirstConnect) { - sead::Heap* seqHeap = sead::HeapMgr::instance()->findHeapByName("SequenceHeap", 0); - - if (seqHeap) { - Logger::log("Current Heap Name: %s\n", seqHeap->getName().cstr()); - } - - - } - PlayerConnect initPacket; initPacket.mUserID = mUserID; strcpy(initPacket.clientName, mUsername.cstr()); if (isFirstConnect) { initPacket.conType = ConnectionTypes::INIT; + isFirstConnect = false; } else { initPacket.conType = ConnectionTypes::RECONNECT; } @@ -328,9 +375,7 @@ void Client::readFunc() { mConnectionWait->tryEnd(); - isFirstConnect = false; - - while(true) { + while(mIsConnectionActive) { if (mSocket->getLogState() != SOCKET_LOG_CONNECTED) { @@ -343,29 +388,30 @@ void Client::readFunc() { // if we ever disconnect, reset all our values until we reconnect - puppetPlayerID.fill({0,0}); mConnectCount = 0; - mSocket->closeSocket(); - - mSocket->init(mServerIP.cstr(), mServerPort); - - if (mSocket->getLogState() == SOCKET_LOG_CONNECTED) { + if (mSocket->init(mServerIP.cstr(), mServerPort).isSuccess()) { Logger::log("Connected!\n"); - initPacket.conType = ConnectionTypes::RECONNECT; - mSocket->SEND(&initPacket); // re-send init packet as reconnect packet + if (isFirstConnect) { + initPacket.conType = + ConnectionTypes::INIT; // if we've changed the IP/Port since last connect, + // send init instead of reconnect + isFirstConnect = false; + } else { + initPacket.conType = ConnectionTypes::RECONNECT; + } + + mSocket->SEND(&initPacket); mConnectionWait->tryEnd(); continue; - + } else { + Logger::log("%s: not reconnected\n", __func__); } nn::os::YieldThread(); // if we're currently waiting on the socket to be initialized, wait until it is nn::os::SleepThread(nn::TimeSpan::FromSeconds(5)); - - // TODO: if a reconnect is sucessful, we should let the server know that this client has already connected, and that their player ID is already active - } if(mSocket->RECV()) { // will block until a packet has been recieved, or socket disconnected @@ -377,9 +423,7 @@ void Client::readFunc() { switch (curPacket->mType) { case PacketType::PLAYERINF: - if(mIsInGame) { - updatePlayerInfo((PlayerInf*)curPacket); - } + updatePlayerInfo((PlayerInf*)curPacket); break; case PacketType::GAMEINF: updateGameInfo((GameInf*)curPacket); @@ -392,15 +436,20 @@ void Client::readFunc() { break; case PacketType::PLAYERCON: updatePlayerConnect((PlayerConnect*)curPacket); - // send game info packet when client recieves connection - if (lastGameInfPacket.mUserID != mUserID) { - // assume game info packet is empty from first connection + // Send relevant info packets when another client is connected + + // Assume game packets are empty from first connection + if (lastGameInfPacket.mUserID != mUserID) lastGameInfPacket.mUserID = mUserID; - // leave rest blank - } - mSocket->SEND(&lastGameInfPacket); + + // No need to send player/costume packets if they're empty + if (lastPlayerInfPacket.mUserID == mUserID) + mSocket->SEND(&lastPlayerInfPacket); + if (lastCostumeInfPacket.mUserID == mUserID) + mSocket->SEND(&lastCostumeInfPacket); + break; case PacketType::COSTUMEINF: updateCostumeInfo((CostumeInf*)curPacket); @@ -409,7 +458,7 @@ void Client::readFunc() { updateShineInfo((ShineCollect*)curPacket); break; case PacketType::PLAYERDC: - Logger::log("Recieved Player Disconnect!\n"); + Logger::log("Received Player Disconnect!\n"); curPacket->mUserID.print(); disconnectPlayer((PlayerDC*)curPacket); break; @@ -434,11 +483,13 @@ void Client::readFunc() { } }else { // if false, socket has errored or disconnected, so close the socket and end this thread. - Logger::log("Client Socket Encountered an Error!\n"); + Logger::log("Client Socket Encountered an Error! Errno: 0x%x\n", mSocket->socket_errno); } nn::os::YieldThread(); // allow other threads to run } + + Logger::log("Client Read Thread ending.\n"); } /** * @brief unused thread function for receiving thread @@ -451,14 +502,14 @@ void Client::recvFunc() {} * * @param player pointer to current player class, used to get translation, animation, and capture data */ -void Client::sendPlayerInfPacket(const PlayerActorHakoniwa *player) { +void Client::sendPlayerInfPacket(const PlayerActorBase *playerBase, bool isYukimaru) { if (!sInstance) { Logger::log("Static Instance is Null!\n"); return; } - if(!player) { + if(!playerBase) { Logger::log("Error: Null Player Reference\n"); return; } @@ -466,36 +517,56 @@ void Client::sendPlayerInfPacket(const PlayerActorHakoniwa *player) { PlayerInf packet = PlayerInf(); packet.mUserID = sInstance->mUserID; - packet.playerPos = al::getTrans(player); + packet.playerPos = al::getTrans(playerBase); - al::calcQuat(&packet.playerRot, player); // calculate rotation based off pose instead of using quat rotation + al::calcQuat(&packet.playerRot, + playerBase); // calculate rotation based off pose instead of using quat rotation - for (size_t i = 0; i < 6; i++) - { - packet.animBlendWeights[i] = player->mPlayerAnimator->getBlendWeight(i); - } + if (!isYukimaru) { + + PlayerActorHakoniwa* player = (PlayerActorHakoniwa*)playerBase; - const char *hackName = player->mHackKeeper->getCurrentHackName(); - - if (hackName != nullptr) { - - sInstance->isClientCaptured = true; - - const char* actName = al::getActionName(player->mHackKeeper->currentHackActor); - - if (actName) { - packet.actName = PlayerAnims::FindType(actName); - packet.subActName = PlayerAnims::Type::Unknown; - //strcpy(packet.actName, actName); - } else { - packet.actName = PlayerAnims::Type::Unknown; - packet.subActName = PlayerAnims::Type::Unknown; + for (size_t i = 0; i < 6; i++) + { + packet.animBlendWeights[i] = player->mPlayerAnimator->getBlendWeight(i); } + + const char *hackName = player->mHackKeeper->getCurrentHackName(); + + if (hackName != nullptr) { + + sInstance->isClientCaptured = true; + + const char* actName = al::getActionName(player->mHackKeeper->currentHackActor); + + if (actName) { + packet.actName = PlayerAnims::FindType(actName); + packet.subActName = PlayerAnims::Type::Unknown; + //strcpy(packet.actName, actName); + } else { + packet.actName = PlayerAnims::Type::Unknown; + packet.subActName = PlayerAnims::Type::Unknown; + } + } else { + packet.actName = PlayerAnims::FindType(player->mPlayerAnimator->mAnimFrameCtrl->getActionName()); + packet.subActName = PlayerAnims::FindType(player->mPlayerAnimator->curSubAnim.cstr()); + + sInstance->isClientCaptured = false; + } + } else { - packet.actName = PlayerAnims::FindType(player->mPlayerAnimator->mAnimFrameCtrl->getActionName()); - packet.subActName = PlayerAnims::FindType(player->mPlayerAnimator->curSubAnim.cstr()); + + // TODO: implement YukimaruRacePlayer syncing + + for (size_t i = 0; i < 6; i++) + { + packet.animBlendWeights[i] = 0; + } sInstance->isClientCaptured = false; + + packet.actName = PlayerAnims::Type::Unknown; + packet.subActName = PlayerAnims::Type::Unknown; } if(sInstance->lastPlayerInfPacket != packet) { @@ -525,7 +596,7 @@ void Client::sendHackCapInfPacket(const HackCap* hackCap) { packet.mUserID = sInstance->mUserID; packet.capPos = al::getTrans(hackCap); - packet.isCapVisible = hackCap->isFlying(); + packet.isCapVisible = isFlying; packet.capQuat.x = hackCap->mJointKeeper->mJointRot.x; packet.capQuat.y = hackCap->mJointKeeper->mJointRot.y; @@ -551,7 +622,7 @@ void Client::sendHackCapInfPacket(const HackCap* hackCap) { /** * @brief - * + * Sends both stage info and player 2D info to the server. * @param player * @param holder */ @@ -583,7 +654,7 @@ void Client::sendGameInfPacket(const PlayerActorHakoniwa* player, GameDataHolder } /** * @brief - * + * Sends only stage info to the server. * @param holder */ void Client::sendGameInfPacket(GameDataHolderAccessor holder) { @@ -618,13 +689,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(); @@ -655,6 +727,7 @@ void Client::sendCostumeInfPacket(const char* body, const char* cap) { CostumeInf packet = CostumeInf(body, cap); packet.mUserID = sInstance->mUserID; sInstance->mSocket->SEND(&packet); + sInstance->lastCostumeInfPacket = packet; } /** @@ -713,61 +786,59 @@ void Client::sendShineCollectPacket(int shineID) { * @param packet */ void Client::updatePlayerInfo(PlayerInf *packet) { - - int puppetIndex = findPuppetID(packet->mUserID); - if(puppetIndex >= 0) { + PuppetInfo* curInfo = findPuppetInfo(packet->mUserID, false); - PuppetInfo* curInfo = mPuppetInfoArr[puppetIndex]; + if (!curInfo) { + return; + } - if (!curInfo) { - Logger::log("Attempting to Access Puppet Out of Bounds! Value: %d\n", puppetIndex); - return; - } - - if(!curInfo->isConnected) { - curInfo->isConnected = true; - } - - curInfo->playerPos = packet->playerPos; - - // check if rotation is larger than zero and less than or equal to 1 - if(abs(packet->playerRot.x) > 0.f || abs(packet->playerRot.y) > 0.f || abs(packet->playerRot.z) > 0.f || abs(packet->playerRot.w) > 0.f) { - if(abs(packet->playerRot.x) <= 1.f || abs(packet->playerRot.y) <= 1.f || abs(packet->playerRot.z) <= 1.f || abs(packet->playerRot.w) <= 1.f) { - curInfo->playerRot = packet->playerRot; - } + if(!curInfo->isConnected) { + curInfo->isConnected = true; + } + + curInfo->playerPos = packet->playerPos; + + // check if rotation is larger than zero and less than or equal to 1 + if(abs(packet->playerRot.x) > 0.f || abs(packet->playerRot.y) > 0.f || abs(packet->playerRot.z) > 0.f || abs(packet->playerRot.w) > 0.f) { + if(abs(packet->playerRot.x) <= 1.f || abs(packet->playerRot.y) <= 1.f || abs(packet->playerRot.z) <= 1.f || abs(packet->playerRot.w) <= 1.f) { + curInfo->playerRot = packet->playerRot; } + } if (packet->actName != PlayerAnims::Type::Unknown) { strcpy(curInfo->curAnimStr, PlayerAnims::FindStr(packet->actName)); + if (curInfo->curAnimStr[0] == '\0') + Logger::log("[ERROR] %s: actName was out of bounds: %d\n", __func__, packet->actName); } else { strcpy(curInfo->curAnimStr, "Wait"); } if(packet->subActName != PlayerAnims::Type::Unknown) { strcpy(curInfo->curSubAnimStr, PlayerAnims::FindStr(packet->subActName)); + if (curInfo->curSubAnimStr[0] == '\0') + Logger::log("[ERROR] %s: subActName was out of bounds: %d\n", __func__, packet->subActName); } else { strcpy(curInfo->curSubAnimStr, ""); } - curInfo->curAnim = packet->actName; - curInfo->curSubAnim = packet->subActName; + curInfo->curAnim = packet->actName; + curInfo->curSubAnim = packet->subActName; - for (size_t i = 0; i < 6; i++) - { - // weights can only be between 0 and 1 - if(packet->animBlendWeights[i] >= 0.f && packet->animBlendWeights[i] <= 1.f) { - curInfo->blendWeights[i] = packet->animBlendWeights[i]; - } + for (size_t i = 0; i < 6; i++) + { + // weights can only be between 0 and 1 + if(packet->animBlendWeights[i] >= 0.f && packet->animBlendWeights[i] <= 1.f) { + curInfo->blendWeights[i] = packet->animBlendWeights[i]; } - - //TEMP - - if(!curInfo->isCapThrow) { - curInfo->capPos = packet->playerPos; - } - } + + //TEMP + + if(!curInfo->isCapThrow) { + curInfo->capPos = packet->playerPos; + } + } /** @@ -777,24 +848,15 @@ void Client::updatePlayerInfo(PlayerInf *packet) { */ void Client::updateHackCapInfo(HackCapInf *packet) { - int puppetIndex = findPuppetID(packet->mUserID); + PuppetInfo* curInfo = findPuppetInfo(packet->mUserID, false); - if(puppetIndex >= 0) { + if (curInfo) { + curInfo->capPos = packet->capPos; + curInfo->capRot = packet->capQuat; - PuppetInfo* curInfo = mPuppetInfoArr[puppetIndex]; + curInfo->isCapThrow = packet->isCapVisible; - if (curInfo) { - curInfo->capPos = packet->capPos; - curInfo->capRot = packet->capQuat; - - curInfo->isCapThrow = packet->isCapVisible; - - if (curInfo->capAnim && packet->capAnim) { - strcpy(curInfo->capAnim, packet->capAnim); - } - } else { - Logger::log("Attempting to Access Puppet Out of Bounds! Value: %d\n", puppetIndex); - } + strcpy(curInfo->capAnim, packet->capAnim); } } @@ -803,22 +865,18 @@ void Client::updateHackCapInfo(HackCapInf *packet) { * * @param packet */ -void Client::updateCaptureInfo(CaptureInf *packet) { - int puppetIndex = findPuppetID(packet->mUserID); - if (puppetIndex >= 0) { +void Client::updateCaptureInfo(CaptureInf* packet) { + + PuppetInfo* curInfo = findPuppetInfo(packet->mUserID, false); - PuppetInfo* curInfo = mPuppetInfoArr[puppetIndex]; - - if (!curInfo) { - Logger::log("Attempting to Access Puppet Out of Bounds! Value: %d\n", puppetIndex); - return; - } + if (!curInfo) { + return; + } - curInfo->isCaptured = strlen(packet->hackName) > 0; + curInfo->isCaptured = strlen(packet->hackName) > 0; - if (curInfo->isCaptured) { - strcpy(curInfo->curHack, packet->hackName); - } + if (curInfo->isCaptured) { + strcpy(curInfo->curHack, packet->hackName); } } @@ -828,21 +886,15 @@ void Client::updateCaptureInfo(CaptureInf *packet) { * @param packet */ void Client::updateCostumeInfo(CostumeInf *packet) { - if(packet->bodyModel && packet->capModel) { - int puppetIndex = findPuppetID(packet->mUserID); - if(puppetIndex >= 0) { - PuppetInfo* curInfo = mPuppetInfoArr[puppetIndex]; - if (!curInfo) { - Logger::log("Attempting to Access Puppet Out of Bounds! Value: %d\n", puppetIndex); - return; - } + PuppetInfo* curInfo = findPuppetInfo(packet->mUserID, false); - strcpy(curInfo->costumeBody, packet->bodyModel); - strcpy(curInfo->costumeHead, packet->capModel); - - } + if (!curInfo) { + return; } + + strcpy(curInfo->costumeBody, packet->bodyModel); + strcpy(curInfo->costumeHead, packet->capModel); } /** @@ -862,18 +914,29 @@ void Client::updateShineInfo(ShineCollect* packet) { * * @param packet */ -void Client::updatePlayerConnect(PlayerConnect *packet) { - int puppetIndex = findPuppetID(packet->mUserID); - if(puppetIndex >= 0) { - PuppetInfo* curInfo = mPuppetInfoArr[puppetIndex]; +void Client::updatePlayerConnect(PlayerConnect* packet) { + + PuppetInfo* curInfo = findPuppetInfo(packet->mUserID, true); + + if (!curInfo) { + return; + } + + if (curInfo->isConnected) { + + Logger::log("Info is already being used by another connected player!\n"); + packet->mUserID.print("Connection ID"); + curInfo->playerID.print("Target Info"); + + } else { + + packet->mUserID.print("Player Connected! ID"); - if (!curInfo) { - Logger::log("Attempting to Access Puppet Out of Bounds! Value: %d\n", puppetIndex); - return; - } curInfo->playerID = packet->mUserID; curInfo->isConnected = true; strcpy(curInfo->puppetName, packet->clientName); + + mConnectCount++; } } /** @@ -882,26 +945,22 @@ void Client::updatePlayerConnect(PlayerConnect *packet) { * @param packet */ void Client::updateGameInfo(GameInf *packet) { - int puppetIndex = findPuppetID(packet->mUserID); - if(puppetIndex >= 0) { - PuppetInfo* curInfo = mPuppetInfoArr[puppetIndex]; + PuppetInfo* curInfo = findPuppetInfo(packet->mUserID, false); - if (!curInfo) { - Logger::log("Attempting to Access Puppet Out of Bounds! Value: %d\n", puppetIndex); - return; + if (!curInfo) { + return; + } + + if(curInfo->isConnected) { + + curInfo->scenarioNo = packet->scenarioNo; + + if(strcmp(packet->stageName, "") != 0 && strlen(packet->stageName) > 3) { + strcpy(curInfo->stageName, packet->stageName); } - if(curInfo->isConnected) { - - curInfo->scenarioNo = packet->scenarioNo; - - if(strcmp(packet->stageName, "") != 0 && strlen(packet->stageName) > 3) { - strcpy(curInfo->stageName, packet->stageName); - } - - curInfo->is2D = packet->is2D; - } + curInfo->is2D = packet->is2D; } } @@ -913,10 +972,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); @@ -931,20 +990,15 @@ void Client::updateTagInfo(TagInf *packet) { } - int puppetIndex = findPuppetID(packet->mUserID); + PuppetInfo* curInfo = findPuppetInfo(packet->mUserID, false); - if(puppetIndex >= 0) { - PuppetInfo* curInfo = mPuppetInfoArr[puppetIndex]; - - if (!curInfo) { - Logger::log("Attempting to Access Puppet Out of Bounds! Value: %d\n", puppetIndex); - return; - } - - curInfo->isIt = packet->isIt; - curInfo->seconds = packet->seconds; - curInfo->minutes = packet->minutes; + if (!curInfo) { + return; } + + curInfo->isIt = packet->isIt; + curInfo->seconds = packet->seconds; + curInfo->minutes = packet->minutes; } /** @@ -971,29 +1025,20 @@ void Client::sendToStage(ChangeStagePacket* packet) { * @param packet */ void Client::disconnectPlayer(PlayerDC *packet) { - int puppetIndex = findPuppetID(packet->mUserID); - if(puppetIndex >= 0) { - PuppetInfo* curInfo = mPuppetInfoArr[puppetIndex]; + PuppetInfo* curInfo = findPuppetInfo(packet->mUserID, false); - if (!curInfo) { - Logger::log("Attempting to Access Puppet Out of Bounds! Value: %d\n", puppetIndex); - return; - } - - curInfo->isConnected = false; - - curInfo->scenarioNo = -1; - strcpy(curInfo->stageName, ""); - curInfo->isInSameStage = false; - - mConnectCount--; - - if (mConnectCount < 0) { - Logger::log("Connection Count went Negative!\n"); - mConnectCount = 0; - } + if (!curInfo || !curInfo->isConnected) { + return; } + + curInfo->isConnected = false; + + curInfo->scenarioNo = -1; + strcpy(curInfo->stageName, ""); + curInfo->isInSameStage = false; + + mConnectCount--; } /** @@ -1024,23 +1069,27 @@ bool Client::isShineCollected(int shineId) { * @param id * @return int */ -int Client::findPuppetID(const nn::account::Uid &id) { - for (size_t i = 0; i < this->puppetPlayerID.size(); i++) - { - if(this->puppetPlayerID[i].uid == id) { - return this->puppetPlayerID[i].puppetIndex; +PuppetInfo* Client::findPuppetInfo(const nn::account::Uid& id, bool isFindAvailable) { + + PuppetInfo *firstAvailable = nullptr; + + for (size_t i = 0; i < getMaxPlayerCount() - 1; i++) { + + PuppetInfo* curInfo = mPuppetInfoArr[i]; + + if (curInfo->playerID == id) { + return curInfo; + } else if (isFindAvailable && !firstAvailable && !curInfo->isConnected) { + firstAvailable = curInfo; } } - if(this->puppetPlayerID.size() > mConnectCount) { - int newIndex = mConnectCount; - this->puppetPlayerID[newIndex].puppetIndex = newIndex; - this->puppetPlayerID[newIndex].uid = id; - mConnectCount++; - return newIndex; + if (!firstAvailable) { + Logger::log("Unable to find Assigned Puppet for Player!\n"); + id.print("User ID"); } - return -1; + return firstAvailable; } /** @@ -1054,7 +1103,7 @@ void Client::setStageInfo(GameDataHolderAccessor holder) { sInstance->mStageName = GameDataFunction::getCurrentStageName(holder); sInstance->mScenario = holder.mData->mGameDataFile->getScenarioNo(); //holder.mData->mGameDataFile->getMainScenarioNoCurrent(); - Client::sInstance->mPuppetHolder->setStageInfo(sInstance->mStageName.cstr(), sInstance->mScenario); + sInstance->mPuppetHolder->setStageInfo(sInstance->mStageName.cstr(), sInstance->mScenario); } } @@ -1066,8 +1115,8 @@ void Client::setStageInfo(GameDataHolderAccessor holder) { * @return false */ bool Client::tryAddPuppet(PuppetActor *puppet) { - if(Client::sInstance) { - return Client::sInstance->mPuppetHolder->tryRegisterPuppet(puppet); + if(sInstance) { + return sInstance->mPuppetHolder->tryRegisterPuppet(puppet); }else { return false; } @@ -1081,8 +1130,8 @@ bool Client::tryAddPuppet(PuppetActor *puppet) { * @return false */ bool Client::tryAddDebugPuppet(PuppetActor *puppet) { - if(Client::sInstance) { - return Client::sInstance->mPuppetHolder->tryRegisterDebugPuppet(puppet); + if(sInstance) { + return sInstance->mPuppetHolder->tryRegisterDebugPuppet(puppet); }else { return false; } @@ -1095,8 +1144,8 @@ bool Client::tryAddDebugPuppet(PuppetActor *puppet) { * @return PuppetActor* */ PuppetActor *Client::getPuppet(int idx) { - if(Client::sInstance) { - return Client::sInstance->mPuppetHolder->getPuppetActor(idx); + if(sInstance) { + return sInstance->mPuppetHolder->getPuppetActor(idx); }else { return nullptr; } @@ -1108,8 +1157,8 @@ PuppetActor *Client::getPuppet(int idx) { * @return PuppetInfo* */ PuppetInfo *Client::getLatestInfo() { - if(Client::sInstance) { - return Client::getPuppetInfo(Client::sInstance->mPuppetHolder->getSize() - 1); + if(sInstance) { + return Client::getPuppetInfo(sInstance->mPuppetHolder->getSize() - 1); }else { return nullptr; } @@ -1122,9 +1171,9 @@ PuppetInfo *Client::getLatestInfo() { * @return PuppetInfo* */ PuppetInfo *Client::getPuppetInfo(int idx) { - if(Client::sInstance) { + if(sInstance) { // unsafe get - PuppetInfo *curInfo = Client::sInstance->mPuppetInfoArr[idx]; + PuppetInfo *curInfo = sInstance->mPuppetInfoArr[idx]; if (!curInfo) { Logger::log("Attempting to Access Puppet Out of Bounds! Value: %d\n", idx); @@ -1217,7 +1266,7 @@ void Client::updateShines() { } sInstance->resetCollectedShines(); - sInstance->mCurStageScene->stageSceneLayout->startShineCountAnim(false); + sInstance->mCurStageScene->mSceneLayout->startShineCountAnim(false); } /** @@ -1228,34 +1277,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(); } } @@ -1277,8 +1299,8 @@ void Client::clearArrays() { * @return PuppetInfo* */ PuppetInfo *Client::getDebugPuppetInfo() { - if(Client::sInstance) { - return &Client::sInstance->mDebugPuppetInfo; + if(sInstance) { + return &sInstance->mDebugPuppetInfo; }else { return nullptr; } @@ -1290,13 +1312,25 @@ PuppetInfo *Client::getDebugPuppetInfo() { * @return PuppetActor* */ PuppetActor *Client::getDebugPuppet() { - if(Client::sInstance) { - return Client::sInstance->mPuppetHolder->getDebugPuppet(); + if(sInstance) { + return sInstance->mPuppetHolder->getDebugPuppet(); }else { return nullptr; } } +/** + * @brief + * + * @return Keyboard* + */ +Keyboard* Client::getKeyboard() { + if (sInstance) { + return sInstance->mKeyboard; + } + return nullptr; +} + /** * @brief * @@ -1309,6 +1343,18 @@ const char* Client::getCurrentIP() { return nullptr; } +/** + * @brief + * + * @return const int + */ +const int Client::getCurrentPort() { + if (sInstance) { + return sInstance->mServerPort; + } + return -1; +} + /** * @brief sets server IP to supplied string, used specifically for loading IP from the save file. * @@ -1320,6 +1366,17 @@ void Client::setLastUsedIP(const char* ip) { } } +/** + * @brief sets server port to supplied string, used specifically for loading port from the save file. + * + * @param port + */ +void Client::setLastUsedPort(const int port) { + if (sInstance) { + sInstance->mServerPort = port; + } +} + /** * @brief creates new scene info and copies supplied info to the new info, as well as stores a const ptr to the current stage scene. * @@ -1379,60 +1436,36 @@ 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() { +void Client::showConnectError(const char16_t* msg) { if (!sInstance) - return nullptr; + return; - switch (sInstance->mServerMode) { - case HIDEANDSEEK: { - return new HideAndSeekConfigMenu(); - } - default: - return nullptr; + sInstance->mConnectionWait->setTxtMessageConfirm(msg); + + al::hidePane(sInstance->mConnectionWait, "Page01"); // hide A button prompt + + if (!sInstance->mConnectionWait->mIsAlive) { + sInstance->mConnectionWait->appear(); + + sInstance->mConnectionWait->playLoop(); } + + al::startAction(sInstance->mConnectionWait, "Confirm", "State"); +} + +void Client::showConnect() { + if (!sInstance) + return; + + sInstance->mConnectionWait->appear(); + + sInstance->mConnectionWait->playLoop(); + +} + +void Client::hideConnect() { + if (!sInstance) + return; + + sInstance->mConnectionWait->tryEnd(); } diff --git a/source/server/SocketBase.cpp b/source/server/SocketBase.cpp index 4dbe7ac..d36b8ef 100644 --- a/source/server/SocketBase.cpp +++ b/source/server/SocketBase.cpp @@ -7,7 +7,7 @@ SocketBase::SocketBase(const char *name) { strcpy(this->sockName, name); - this->sock_flags = 0; + this->sock_flags = 0x80; } const char *SocketBase::getStateChar() { @@ -59,7 +59,7 @@ s32 SocketBase::socket_read_char(char *out) { return valread; } -s32 SocketBase::getSocket() { +s32 SocketBase::getFd() { if(this->socket_log_state == SOCKET_LOG_CONNECTED) { return this->socket_log_socket; }else { @@ -69,11 +69,9 @@ s32 SocketBase::getSocket() { bool SocketBase::closeSocket() { - nn::Result result = nn::socket::Close(this->socket_log_socket); + this->socket_log_state = SOCKET_LOG_DISCONNECTED; // probably not safe to assume socket will be closed - if (result.isSuccess()) { - this->socket_log_state = SOCKET_LOG_DISCONNECTED; - } + nn::Result result = nn::socket::Close(this->socket_log_socket); return result.isSuccess(); } diff --git a/source/server/SocketClient.cpp b/source/server/SocketClient.cpp index 7943ec1..8abc7e6 100644 --- a/source/server/SocketClient.cpp +++ b/source/server/SocketClient.cpp @@ -2,6 +2,7 @@ #include #include +#include "SocketBase.hpp" #include "logger.hpp" #include "nn/result.h" #include "nn/socket.h" @@ -10,15 +11,13 @@ nn::Result SocketClient::init(const char* ip, u16 port) { - sock_ip = ip; - - this->port = port; + this->sock_ip = ip; + this->port = port; - in_addr hostAddress = { 0 }; + in_addr hostAddress = { 0 }; sockaddr serverAddress = { 0 }; - if (socket_log_state != SOCKET_LOG_UNINITIALIZED && socket_log_state != SOCKET_LOG_DISCONNECTED) - return -1; + Logger::log("SocketClient::init: %s:%d sock %s\n", ip, port, getStateChar()); nn::nifm::Initialize(); nn::nifm::SubmitNetworkRequest(); @@ -30,38 +29,46 @@ nn::Result SocketClient::init(const char* ip, u16 port) { if (!nn::nifm::IsNetworkAvailable()) { Logger::log("Network Unavailable.\n"); this->socket_log_state = SOCKET_LOG_UNAVAILABLE; + this->socket_errno = nn::socket::GetLastErrno(); return -1; } #endif - - if ((this->socket_log_socket = nn::socket::Socket(2, 1, 0)) < 0) { + if ((this->socket_log_socket = nn::socket::Socket(2, 1, 6)) < 0) { Logger::log("Socket Unavailable.\n"); - + this->socket_errno = nn::socket::GetLastErrno(); this->socket_log_state = SOCKET_LOG_UNAVAILABLE; return -1; } - - nn::socket::InetAton(this->sock_ip, &hostAddress); + if (! this->stringToIPAddress(this->sock_ip, &hostAddress)) { + Logger::log("IP address is invalid or hostname not resolveable.\n"); + this->socket_errno = nn::socket::GetLastErrno(); + this->socket_log_state = SOCKET_LOG_UNAVAILABLE; + return -1; + } serverAddress.address = hostAddress; serverAddress.port = nn::socket::InetHtons(this->port); serverAddress.family = 2; - bool sockOptValue = true; + int sockOptValue = true; - nn::socket::SetSockOpt(this->socket_log_socket, 0, TCP_NODELAY, &sockOptValue, sizeof(bool)); + nn::socket::SetSockOpt(this->socket_log_socket, 6, TCP_NODELAY, &sockOptValue, sizeof(sockOptValue)); nn::Result result; if((result = nn::socket::Connect(this->socket_log_socket, &serverAddress, sizeof(serverAddress))).isFailure()) { + Logger::log("Socket Connection Failed!\n"); + this->socket_errno = nn::socket::GetLastErrno(); this->socket_log_state = SOCKET_LOG_UNAVAILABLE; return result; } this->socket_log_state = SOCKET_LOG_CONNECTED; + Logger::log("Socket fd: %d\n", socket_log_socket); + return result; } @@ -75,12 +82,14 @@ bool SocketClient::SEND(Packet *packet) { int valread = 0; - //Logger::log("Sending Packet Size: %d Sending Type: %s\n", packet->mPacketSize, packetNames[packet->mType]); + if (packet->mType != PLAYERINF && packet->mType != HACKCAPINF) + Logger::log("Sending packet: %s\n", packetNames[packet->mType]); - if ((valread = nn::socket::Send(this->socket_log_socket, buffer, packet->mPacketSize + sizeof(Packet), this->sock_flags) > 0)) { + if ((valread = nn::socket::Send(this->socket_log_socket, buffer, packet->mPacketSize + sizeof(Packet), 0) > 0)) { return true; } else { Logger::log("Failed to Fully Send Packet! Result: %d Type: %s Packet Size: %d\n", valread, packetNames[packet->mType], packet->mPacketSize); + this->socket_errno = nn::socket::GetLastErrno(); this->closeSocket(); return false; } @@ -90,7 +99,8 @@ bool SocketClient::SEND(Packet *packet) { bool SocketClient::RECV() { if (this->socket_log_state != SOCKET_LOG_CONNECTED) { - Logger::log("Unable To Recieve! Socket Not Connected.\n"); + Logger::log("Unable To Receive! Socket Not Connected.\n"); + this->socket_errno = nn::socket::GetLastErrno(); return false; } @@ -100,13 +110,21 @@ bool SocketClient::RECV() { // read only the size of a header while(valread < headerSize) { - int result = nn::socket::Recv(this->socket_log_socket, headerBuf + valread, headerSize - valread, this->sock_flags); + int result = nn::socket::Recv(this->socket_log_socket, headerBuf + valread, + headerSize - valread, this->sock_flags); + + this->socket_errno = nn::socket::GetLastErrno(); + if(result > 0) { valread += result; } else { - Logger::log("Header Read Failed! Value: %d Total Read: %d\n", result, valread); - this->closeSocket(); - return false; + if(this->socket_errno==11){ + return true; + } else { + Logger::log("Header Read Failed! Value: %d Total Read: %d\n", result, valread); + this->closeSocket(); + return false; + } } } @@ -115,7 +133,20 @@ bool SocketClient::RECV() { int fullSize = header->mPacketSize + sizeof(Packet); - if (header->mType != PacketType::UNKNOWN && fullSize <= MAXPACKSIZE && fullSize > 0) { + if (header->mType > PacketType::UNKNOWN && header->mType < PacketType::End && + fullSize <= MAXPACKSIZE && fullSize > 0 && valread == sizeof(Packet)) { + + if (header->mType != PLAYERINF && header->mType != HACKCAPINF) { + Logger::log("Received packet (from %02X%02X):", header->mUserID.data[0], + header->mUserID.data[1]); + Logger::disableName(); + Logger::log(" Size: %d", header->mPacketSize); + Logger::log(" Type: %d", header->mType); + if(packetNames[header->mType]) + Logger::log(" Type String: %s\n", packetNames[header->mType]); + Logger::enableName(); + } + char* packetBuf = (char*)malloc(fullSize); @@ -125,11 +156,14 @@ bool SocketClient::RECV() { while (valread < fullSize) { - int result = nn::socket::Recv(this->socket_log_socket, packetBuf + valread, fullSize - valread, this->sock_flags); + int result = nn::socket::Recv(this->socket_log_socket, packetBuf + valread, + fullSize - valread, this->sock_flags); + + this->socket_errno = nn::socket::GetLastErrno(); if (result > 0) { valread += result; - }else { + } else { free(packetBuf); Logger::log("Packet Read Failed! Value: %d\nPacket Size: %d\nPacket Type: %s\n", result, header->mPacketSize, packetNames[header->mType]); this->closeSocket(); @@ -144,16 +178,15 @@ bool SocketClient::RECV() { } else { free(packetBuf); } - } else { - // Logger::log("Heap Allocation Failed! Returned nullptr\n"); } } else { - // Logger::log("Recieved Unknown Packet Type! Size: %d\n", header->mPacketSize); + Logger::log("Failed to aquire valid data! Packet Type: %d Full Packet Size %d valread size: %d", header->mType, fullSize, valread); } return true; } else { // if we error'd, close the socket Logger::log("valread was zero! Disconnecting.\n"); + this->socket_errno = nn::socket::GetLastErrno(); this->closeSocket(); return false; } @@ -175,3 +208,35 @@ void SocketClient::printPacket(Packet *packet) { } } +bool SocketClient::closeSocket() { + + Logger::log("Closing Socket.\n"); + + bool result = false; + + if (!(result = SocketBase::closeSocket())) { + Logger::log("Failed to close socket!\n"); + } + + return result; +} + +bool SocketClient::stringToIPAddress(const char* str, in_addr* out) { + // string to IPv4 + if (nn::socket::InetAton(str, out)) { + return true; + } + + // get IPs via DNS + struct hostent *he = nn::socket::GetHostByName(str); + if (! he) { return false; } + + // might give us multiple IP addresses, so pick the first one + struct in_addr **addr_list = (struct in_addr **) he->h_addr_list; + for (int i = 0 ; addr_list[i] != NULL ; i++) { + *out = *addr_list[i]; + return true; + } + + return false; +} diff --git a/source/server/gamemode/GameModeManager.cpp b/source/server/gamemode/GameModeManager.cpp new file mode 100644 index 0000000..2bb341b --- /dev/null +++ b/source/server/gamemode/GameModeManager.cpp @@ -0,0 +1,91 @@ +#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 && mWasSetMode) { + delete mCurModeBase; + mCurModeBase = nullptr; + } + + if (mLastInitInfo != nullptr) { + delete mLastInitInfo; + } + + if (mCurMode == GameMode::NONE) { + mCurModeBase = nullptr; + delete mModeInfo; + mModeInfo = nullptr; + return; + } + + mLastInitInfo = new GameModeInitInfo(info); + + if (mWasSetMode) { + GameModeFactory factory("GameModeFactory"); + const char* name = factory.getModeString(mCurMode); + mCurModeBase = factory.getCreator(name)(name); + 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 53% rename from source/server/HideAndSeekMode.cpp rename to source/server/hns/HideAndSeekMode.cpp index 032965c..0038c75 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" @@ -6,16 +6,21 @@ #include "game/GameData/GameDataHolderAccessor.h" #include "game/Layouts/CoinCounter.h" #include "game/Layouts/MapMini.h" +#include "game/Player/PlayerActorBase.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 +30,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 +57,6 @@ void HideAndSeekMode::init(const GameModeInitInfo& info) { } void HideAndSeekMode::begin() { - mModeLayout->appear(); mIsFirstFrame = true; @@ -61,10 +69,10 @@ void HideAndSeekMode::begin() { mModeLayout->showSeeking(); } - CoinCounter *coinCollect = mCurScene->stageSceneLayout->mCoinCollectLyt; - CoinCounter* coinCounter = mCurScene->stageSceneLayout->mCoinCountLyt; - MapMini* compass = mCurScene->stageSceneLayout->mMapMiniLyt; - al::SimpleLayoutAppearWaitEnd* playGuideLyt = mCurScene->stageSceneLayout->mPlayGuideMenuLyt; + CoinCounter *coinCollect = mCurScene->mSceneLayout->mCoinCollectLyt; + CoinCounter* coinCounter = mCurScene->mSceneLayout->mCoinCountLyt; + MapMini* compass = mCurScene->mSceneLayout->mMapMiniLyt; + al::SimpleLayoutAppearWaitEnd* playGuideLyt = mCurScene->mSceneLayout->mPlayGuideMenuLyt; if(coinCounter->mIsAlive) coinCounter->tryEnd(); @@ -84,10 +92,10 @@ void HideAndSeekMode::end() { mModeTimer->disableTimer(); - CoinCounter *coinCollect = mCurScene->stageSceneLayout->mCoinCollectLyt; - CoinCounter* coinCounter = mCurScene->stageSceneLayout->mCoinCountLyt; - MapMini* compass = mCurScene->stageSceneLayout->mMapMiniLyt; - al::SimpleLayoutAppearWaitEnd* playGuideLyt = mCurScene->stageSceneLayout->mPlayGuideMenuLyt; + CoinCounter *coinCollect = mCurScene->mSceneLayout->mCoinCollectLyt; + CoinCounter* coinCounter = mCurScene->mSceneLayout->mCoinCountLyt; + MapMini* compass = mCurScene->mSceneLayout->mMapMiniLyt; + al::SimpleLayoutAppearWaitEnd* playGuideLyt = mCurScene->mSceneLayout->mPlayGuideMenuLyt; if(!coinCounter->mIsAlive) coinCounter->tryStart(); @@ -103,7 +111,9 @@ void HideAndSeekMode::end() { void HideAndSeekMode::update() { - PlayerActorHakoniwa* mainPlayer = rs::getPlayerActor(mCurScene); + PlayerActorBase* playerBase = rs::getPlayerActor(mCurScene); + + bool isYukimaru = !playerBase->getPlayerInfo(); // if PlayerInfo is a nullptr, that means we're dealing with the bound bowl racer if (mIsFirstFrame) { @@ -117,39 +127,46 @@ void HideAndSeekMode::update() { if (!mInfo->mIsPlayerIt) { if (mInvulnTime >= 5) { - if (mainPlayer) { + if (playerBase) { for (size_t 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 + float pupDist = al::calcDistance(playerBase, curInfo->playerPos); // TODO: remove distance calculations and use hit sensors to determine this - if(pupDist < 200.f && mainPlayer->mDimKeeper->is2DModel == curInfo->is2D) { - if(!PlayerFunction::isPlayerDeadStatus(mainPlayer)) { - - GameDataFunction::killPlayer(GameDataHolderAccessor(this)); - mainPlayer->startDemoPuppetable(); - al::setVelocityZero(mainPlayer); - rs::faceToCamera(mainPlayer); - mainPlayer->mPlayerAnimator->endSubAnim(); - mainPlayer->mPlayerAnimator->startAnimDead(); + if (!isYukimaru) { + if(pupDist < 200.f && ((PlayerActorHakoniwa*)playerBase)->mDimKeeper->is2DModel == curInfo->is2D) { + if(!PlayerFunction::isPlayerDeadStatus(playerBase)) { + + GameDataFunction::killPlayer(GameDataHolderAccessor(this)); + playerBase->startDemoPuppetable(); + al::setVelocityZero(playerBase); + rs::faceToCamera(playerBase); + ((PlayerActorHakoniwa*)playerBase)->mPlayerAnimator->endSubAnim(); + ((PlayerActorHakoniwa*)playerBase)->mPlayerAnimator->startAnimDead(); + + mInfo->mIsPlayerIt = true; + mModeTimer->disableTimer(); + mModeLayout->showSeeking(); + + Client::sendTagInfPacket(); + } + } else if (PlayerFunction::isPlayerDeadStatus(playerBase)) { mInfo->mIsPlayerIt = true; mModeTimer->disableTimer(); mModeLayout->showSeeking(); - + Client::sendTagInfPacket(); + } - } else if (PlayerFunction::isPlayerDeadStatus(mainPlayer)) { - - mInfo->mIsPlayerIt = true; - mModeTimer->disableTimer(); - mModeLayout->showSeeking(); - - Client::sendTagInfPacket(); - } } } @@ -162,13 +179,13 @@ void HideAndSeekMode::update() { mModeTimer->updateTimer(); } - if (mInfo->mIsUseGravity) { + if (mInfo->mIsUseGravity && !isYukimaru) { sead::Vector3f gravity; - if (rs::calcOnGroundNormalOrGravityDir(&gravity, mainPlayer, mainPlayer->mPlayerCollider)) { + if (rs::calcOnGroundNormalOrGravityDir(&gravity, playerBase, playerBase->getPlayerCollision())) { gravity = -gravity; al::normalize(&gravity); - al::setGravity(mainPlayer, gravity); - al::setGravity(mainPlayer->mHackCap, gravity); + al::setGravity(playerBase, gravity); + al::setGravity(((PlayerActorHakoniwa*)playerBase)->mHackCap, gravity); } if (al::isPadHoldL(-1)) { @@ -183,7 +200,7 @@ void HideAndSeekMode::update() { } } else if (al::isPadTriggerZL(-1)) { if (al::isPadTriggerLeft(-1)) { - killMainPlayer(mainPlayer); + killMainPlayer(((PlayerActorHakoniwa*)playerBase)); } } } diff --git a/source/server/logger.cpp b/source/server/logger.cpp index d2e804a..99fd356 100644 --- a/source/server/logger.cpp +++ b/source/server/logger.cpp @@ -2,6 +2,10 @@ #include "helpers.hpp" #include "nn/result.h" +// If connection fails, try X ports above the specified one +// Useful for debugging multple clients on the same machine +constexpr u32 ADDITIONAL_LOG_PORT_COUNT = 2; + Logger* Logger::sInstance = nullptr; void Logger::createInstance() { @@ -15,9 +19,9 @@ void Logger::createInstance() { nn::Result Logger::init(const char* ip, u16 port) { sock_ip = ip; - + this->port = port; - + in_addr hostAddress = { 0 }; sockaddr serverAddress = { 0 }; @@ -38,12 +42,12 @@ nn::Result Logger::init(const char* ip, u16 port) { } #endif - + if ((this->socket_log_socket = nn::socket::Socket(2, 1, 0)) < 0) { this->socket_log_state = SOCKET_LOG_UNAVAILABLE; return -1; } - + nn::socket::InetAton(this->sock_ip, &hostAddress); serverAddress.address = hostAddress; @@ -51,17 +55,25 @@ nn::Result Logger::init(const char* ip, u16 port) { serverAddress.family = 2; nn::Result result; + bool connected = false; + for (u32 i = 0; i < ADDITIONAL_LOG_PORT_COUNT + 1; ++i) { + result = nn::socket::Connect(this->socket_log_socket, &serverAddress, sizeof(serverAddress)); + if (result.isSuccess()) { + connected = true; + break; + } + this->port++; + serverAddress.port = nn::socket::InetHtons(this->port); + } - if ((result = nn::socket::Connect(this->socket_log_socket, &serverAddress, sizeof(serverAddress))).isFailure()) { + if (connected) { + this->socket_log_state = SOCKET_LOG_CONNECTED; + this->isDisableName = false; + return 0; + } else { this->socket_log_state = SOCKET_LOG_UNAVAILABLE; return result; } - - this->socket_log_state = SOCKET_LOG_CONNECTED; - - this->isDisableName = false; - - return 0; } void Logger::log(const char *fmt, va_list args) { // impl for replacing seads system::print @@ -107,5 +119,4 @@ void tryInitSocket() { #if DEBUGLOG Logger::createInstance(); // creates a static instance for debug logger #endif -} - +} \ No newline at end of file diff --git a/source/states/StageSceneStateServerConfig.cpp b/source/states/StageSceneStateServerConfig.cpp index d28db9d..e8d0e2e 100644 --- a/source/states/StageSceneStateServerConfig.cpp +++ b/source/states/StageSceneStateServerConfig.cpp @@ -1,6 +1,11 @@ #include "game/StageScene/StageSceneStateServerConfig.hpp" #include +#include #include +#include "al/string/StringTmp.h" +#include "basis/seadNew.h" +#include "game/Layouts/CommonVerticalList.h" +#include "game/SaveData/SaveDataAccessFunction.h" #include "server/Client.hpp" #include "al/util.hpp" #include "al/util/NerveUtil.h" @@ -11,8 +16,14 @@ #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" + +// WIP work on RollPartsData, not exactly working out atm +const char16_t* testValues[] = {u"Test 1", u"Test 2", u"Test 3", u"Test 4", u"Test 5", + u"Test 6", u"Test 7", u"Test 8", u"Test 9"}; StageSceneStateServerConfig::StageSceneStateServerConfig(const char *name, al::Scene *scene, const al::LayoutInitInfo &initInfo, FooterParts *footerParts, GameDataHolder *dataHolder, bool) : al::HostStateBase(name, scene) { mFooterParts = footerParts; @@ -28,18 +39,37 @@ StageSceneStateServerConfig::StageSceneStateServerConfig(const char *name, al::S al::setPaneString(mMainOptions, "TxtOption", u"Server Configuration", 0); - mMainOptionsList->initDataNoResetSelected(4); + mMainOptionsList->unkInt1 = 1; - sead::SafeArray, 4>* mainMenuOptions = - new sead::SafeArray, 4>(); + mMainOptionsList->initDataNoResetSelected(5); - mainMenuOptions->mBuffer[0].copy(u"Gamemode Config"); - mainMenuOptions->mBuffer[1].copy(u"Change Gamemode"); - mainMenuOptions->mBuffer[2].copy(u"Reconnect to Server"); - mainMenuOptions->mBuffer[3].copy(u"Change Server IP"); + sead::SafeArray, 5>* mainMenuOptions = + new sead::SafeArray, 5>(); + + mainMenuOptions->mBuffer[ServerConfigOption::GAMEMODECONFIG].copy(u"Gamemode Config"); + mainMenuOptions->mBuffer[ServerConfigOption::GAMEMODESWITCH].copy(u"Change Gamemode"); + mainMenuOptions->mBuffer[ServerConfigOption::RECONNECT].copy(u"Reconnect to Server"); + mainMenuOptions->mBuffer[ServerConfigOption::SETIP].copy(u"Change Server IP"); + mainMenuOptions->mBuffer[ServerConfigOption::SETPORT].copy(u"Change Server Port"); mMainOptionsList->addStringData(mainMenuOptions->mBuffer, "TxtContent"); + // WIP work on RollPartsData, not exactly working out atm + // RollPartsData* testArr = new RollPartsData[2](); + + // for (int i = 0; i < 2; i++) { + // RollPartsData* part = &testArr[i]; + + // part->mRollMsgCount = 3; + // part->mRollMsgList = testValues; + // part->unkInt1 = 0; + // part->mUnkBool = i == 0; + // } + + //mMainOptionsList->startLoopActionAll("Loop", "Loop"); + + // mMainOptionsList->setRollPartsData(testArr); + // gamemode select menu mModeSelect = new SimpleLayoutMenu("GamemodeSelectMenu", "OptionSelect", initInfo, 0, false); @@ -62,24 +92,28 @@ 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; } -void StageSceneStateServerConfig::init() { +void StageSceneStateServerConfig::init() { initNerve(&nrvStageSceneStateServerConfigMainMenu, 0); } @@ -147,7 +181,11 @@ void StageSceneStateServerConfig::exeMainMenu() { break; } case ServerConfigOption::SETIP: { - al::setNerve(this, &nrvStageSceneStateServerConfigOpenKeyboard); + al::setNerve(this, &nrvStageSceneStateServerConfigOpenKeyboardIP); + break; + } + case ServerConfigOption::SETPORT: { + al::setNerve(this, &nrvStageSceneStateServerConfigOpenKeyboardPort); break; } default: @@ -157,41 +195,77 @@ void StageSceneStateServerConfig::exeMainMenu() { } } -void StageSceneStateServerConfig::exeOpenKeyboard() { +void StageSceneStateServerConfig::exeOpenKeyboardIP() { if (al::isFirstStep(this)) { mCurrentList->deactivate(); - Client::openKeyboardIP(); - // anything that happens after this will be ran after the keyboard closes + Client::getKeyboard()->setHeaderText(u"Set a Server IP Below."); + Client::getKeyboard()->setSubText(u""); + + bool isSave = Client::openKeyboardIP(); // anything that happens after this will be ran after the keyboard closes + al::startHitReaction(mCurrentMenu, "リセット", 0); - al::setNerve(this, &nrvStageSceneStateServerConfigMainMenu); + + if(isSave) + al::setNerve(this, &nrvStageSceneStateServerConfigSaveData); + else + al::setNerve(this, &nrvStageSceneStateServerConfigMainMenu); + } +} + +void StageSceneStateServerConfig::exeOpenKeyboardPort() { + if (al::isFirstStep(this)) { + + mCurrentList->deactivate(); + + Client::getKeyboard()->setHeaderText(u"Set a Server Port Below."); + Client::getKeyboard()->setSubText(u""); + + bool isSave = Client::openKeyboardPort(); // anything that happens after this will be ran after the keyboard closes + + al::startHitReaction(mCurrentMenu, "リセット", 0); + + if(isSave) + al::setNerve(this, &nrvStageSceneStateServerConfigSaveData); + else + al::setNerve(this, &nrvStageSceneStateServerConfigMainMenu); } } void StageSceneStateServerConfig::exeRestartServer() { if (al::isFirstStep(this)) { mCurrentList->deactivate(); - Client::stopConnection(); + + Client::showConnect(); + + Client::restartConnection(); } if (Client::isSocketActive()) { + + Client::hideConnect(); + al::startHitReaction(mCurrentMenu, "リセット", 0); + al::setNerve(this, &nrvStageSceneStateServerConfigMainMenu); + } else { + al::setNerve(this, &nrvStageSceneStateServerConfigConnectError); } } 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(); } } @@ -199,7 +273,7 @@ void StageSceneStateServerConfig::exeGamemodeConfig() { void StageSceneStateServerConfig::exeGamemodeSelect() { if (al::isFirstStep(this)) { - + mCurrentList = mModeSelectList; mCurrentMenu = mModeSelect; @@ -211,11 +285,35 @@ 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(); } } +void StageSceneStateServerConfig::exeConnectError() { + if (al::isFirstStep(this)) { + Client::showConnectError(u"Failed to Reconnect!"); + } + + if (al::isGreaterEqualStep(this, 60)) { // close after 1 second + Client::hideConnect(); + al::startHitReaction(mCurrentMenu, "リセット", 0); + al::setNerve(this, &nrvStageSceneStateServerConfigMainMenu); + } +} + +void StageSceneStateServerConfig::exeSaveData() { + + if (al::isFirstStep(this)) { + SaveDataAccessFunction::startSaveDataWrite(mGameDataHolder); + } + + if (SaveDataAccessFunction::updateSaveDataAccess(mGameDataHolder, false)) { + al::startHitReaction(mCurrentMenu, "リセット", 0); + al::setNerve(this, &nrvStageSceneStateServerConfigMainMenu); + } +} + void StageSceneStateServerConfig::endSubMenu() { mCurrentList->deactivate(); mCurrentMenu->kill(); @@ -270,10 +368,14 @@ void StageSceneStateServerConfig::subMenuUpdate() { } } + namespace { NERVE_IMPL(StageSceneStateServerConfig, MainMenu) -NERVE_IMPL(StageSceneStateServerConfig, OpenKeyboard) +NERVE_IMPL(StageSceneStateServerConfig, OpenKeyboardIP) +NERVE_IMPL(StageSceneStateServerConfig, OpenKeyboardPort) NERVE_IMPL(StageSceneStateServerConfig, RestartServer) NERVE_IMPL(StageSceneStateServerConfig, GamemodeConfig) NERVE_IMPL(StageSceneStateServerConfig, GamemodeSelect) +NERVE_IMPL(StageSceneStateServerConfig, SaveData) +NERVE_IMPL(StageSceneStateServerConfig, ConnectError) } \ No newline at end of file