From 7c7b06542b8a5e637829e0c129324f62b5cf4be7 Mon Sep 17 00:00:00 2001 From: Sanae Date: Sat, 18 Jun 2022 18:48:37 -0600 Subject: [PATCH 01/48] Improve keyboard support and add port selection --- include/Keyboard.hpp | 5 +- .../StageSceneStateServerConfig.hpp | 9 ++- include/server/Client.hpp | 9 ++- source/Keyboard.cpp | 10 +-- source/hooks.cpp | 12 +++ source/server/Client.cpp | 74 ++++++++++++++++--- source/states/StageSceneStateServerConfig.cpp | 42 ++++++++--- 7 files changed, 128 insertions(+), 33 deletions(-) diff --git a/include/Keyboard.hpp b/include/Keyboard.hpp index 003d339..88d1098 100644 --- a/include/Keyboard.hpp +++ b/include/Keyboard.hpp @@ -9,12 +9,14 @@ #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()) { @@ -36,6 +38,7 @@ class Keyboard { bool mIsDoneKeyboard; sead::FixedSafeString<0x10> mInitialText; + KeyboardSetup mSetupFunc; const char16_t *mHeaderText = u"Enter Server IP Here!"; const char16_t *mSubText = u"Must be a Valid Address."; diff --git a/include/game/StageScene/StageSceneStateServerConfig.hpp b/include/game/StageScene/StageSceneStateServerConfig.hpp index cbcbe19..0a69ece 100644 --- a/include/game/StageScene/StageSceneStateServerConfig.hpp +++ b/include/game/StageScene/StageSceneStateServerConfig.hpp @@ -29,7 +29,8 @@ class StageSceneStateServerConfig : public al::HostStateBase, public GAMEMODECONFIG, GAMEMODESWITCH, RECONNECT, - SETIP + SETIP, + SETPORT }; virtual al::MessageSystem* getMessageSystem(void) const override; @@ -38,7 +39,8 @@ 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(); @@ -75,7 +77,8 @@ class StageSceneStateServerConfig : public al::HostStateBase, public 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) diff --git a/include/server/Client.hpp b/include/server/Client.hpp index 736b7d8..14a10e2 100644 --- a/include/server/Client.hpp +++ b/include/server/Client.hpp @@ -150,10 +150,16 @@ class Client { 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() { @@ -171,6 +177,7 @@ class Client { static void updateShines(); static void openKeyboardIP(); + static void openKeyboardPort(); static GameModeInfoBase* getModeInfo() { return sInstance ? sInstance->mModeInfo : nullptr; @@ -243,7 +250,7 @@ class Client { sead::FixedSafeString<0x10> mServerIP; - int mServerPort = 1027; // TODO: implement a way to set this the same way the IP can + int mServerPort = 0; bool isFirstConnect = true; diff --git a/source/Keyboard.cpp b/source/Keyboard.cpp index 47a5e00..047e7ec 100644 --- a/source/Keyboard.cpp +++ b/source/Keyboard.cpp @@ -27,12 +27,7 @@ void Keyboard::keyboardThread() { 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); @@ -55,9 +50,10 @@ void Keyboard::keyboardThread() { } -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..3fc0fad 100644 --- a/source/hooks.cpp +++ b/source/hooks.cpp @@ -39,6 +39,7 @@ 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); @@ -46,16 +47,27 @@ void saveWriteHook(al::ByamlWriter* saveByml) { saveByml->addString("ServerIP", "0.0.0.0"); } + if (serverPort) { + saveByml->addInt("ServerPort", serverPort); + } else { + saveByml->addInt("ServerPort", 0); + } + saveByml->pop(); } 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); } diff --git a/source/server/Client.cpp b/source/server/Client.cpp index 381fae6..95524f4 100644 --- a/source/server/Client.cpp +++ b/source/server/Client.cpp @@ -16,6 +16,8 @@ #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" @@ -200,19 +202,17 @@ void Client::stopConnection() { */ bool Client::startConnection() { if (mServerIP.isEmpty()) { - mKeyboard->setHeaderText(u"Save File does not contain an IP!"); mKeyboard->setSubText(u"Please set a Server IP Below."); + mServerIP = "0.0.0.0"; + Client::openKeyboardIP(); + } - mKeyboard->openKeyboard("0.0.0.0"); - - while (true) { - if (mKeyboard->isThreadDone()) { - mServerIP = mKeyboard->getResult(); - break; - } - nn::os::YieldThread(); // allow other threads to run - } + if (!mServerPort) { + mKeyboard->setHeaderText(u"Save File does not contain a port!"); + mKeyboard->setSubText(u"Please set a Server Port Below."); + mServerPort = 1027; + Client::openKeyboardPort(); } bool result = mSocket->init(mServerIP.cstr(), mServerPort).isSuccess(); @@ -260,7 +260,15 @@ void Client::openKeyboardIP() { return; } - 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::ModeNumeric; + config.leftOptionalSymbolKey = '.'; + config.textMaxLength = 15; + config.textMinLength = 1; + config.isUseUtf8 = true; + config.inputFormMode = nn::swkbd::InputFormMode::OneLine; + }); while (true) { if (sInstance->mKeyboard->isThreadDone()) { @@ -271,6 +279,38 @@ void Client::openKeyboardIP() { } } +/** + * @brief Opens up OS's software keyboard in order to change the currently used server port. + * + */ +void Client::openKeyboardPort() { + + if (!sInstance) { + Logger::log("Static Instance is null!\n"); + return; + } + + // 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; + }); + + while (true) { + if (sInstance->mKeyboard->isThreadDone()) { + sInstance->mServerPort = ::atoi(sInstance->mKeyboard->getResult()); + break; + } + nn::os::YieldThread(); // allow other threads to run + } +} + /** * @brief main thread function for read thread, responsible for receiving and processing packets from server * @@ -1297,6 +1337,18 @@ PuppetActor *Client::getDebugPuppet() { } } +/** + * @brief + * + * @return Keyboard* + */ +Keyboard* Client::getKeyboard() { + if (sInstance) { + return sInstance->mKeyboard; + } + return nullptr; +} + /** * @brief * diff --git a/source/states/StageSceneStateServerConfig.cpp b/source/states/StageSceneStateServerConfig.cpp index d28db9d..230b55a 100644 --- a/source/states/StageSceneStateServerConfig.cpp +++ b/source/states/StageSceneStateServerConfig.cpp @@ -28,15 +28,16 @@ StageSceneStateServerConfig::StageSceneStateServerConfig(const char *name, al::S al::setPaneString(mMainOptions, "TxtOption", u"Server Configuration", 0); - mMainOptionsList->initDataNoResetSelected(4); + mMainOptionsList->initDataNoResetSelected(5); - sead::SafeArray, 4>* mainMenuOptions = - new sead::SafeArray, 4>(); + sead::SafeArray, 5>* mainMenuOptions = + new sead::SafeArray, 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"); + 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"); @@ -147,7 +148,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,11 +162,27 @@ void StageSceneStateServerConfig::exeMainMenu() { } } -void StageSceneStateServerConfig::exeOpenKeyboard() { +void StageSceneStateServerConfig::exeOpenKeyboardIP() { if (al::isFirstStep(this)) { mCurrentList->deactivate(); + Client::getKeyboard()->setHeaderText(u"Set a Server IP Below."); + Client::getKeyboard()->setSubText(u""); + Client::openKeyboardIP(); + // anything that happens after this will be ran after the keyboard closes + al::startHitReaction(mCurrentMenu, "リセット", 0); + 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""); Client::openKeyboardIP(); // anything that happens after this will be ran after the keyboard closes al::startHitReaction(mCurrentMenu, "リセット", 0); @@ -272,7 +293,8 @@ 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) From 2b7ca6d9147a50fa30227bcf27b88cea1b55d55e Mon Sep 17 00:00:00 2001 From: Somebody Whoisbored <13044396+shadowninja108@users.noreply.github.com> Date: Sat, 18 Jun 2022 18:25:15 -0700 Subject: [PATCH 02/48] Add svcOutputDebugString --- MakefileNSO | 2 +- include/nx/svc.h | 20 ++++++++++++++++++++ source/nx/svc.s | 17 +++++++++++++++++ 3 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 include/nx/svc.h create mode 100644 source/nx/svc.s diff --git a/MakefileNSO b/MakefileNSO index e37bcfe..969473f 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 source/layouts source/states source/cameras source/nx source DATA := data INCLUDES := include include/sead 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/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 From 41746805c244164dd5df746860d3390601ffc777 Mon Sep 17 00:00:00 2001 From: Somebody Whoisbored <13044396+shadowninja108@users.noreply.github.com> Date: Sat, 18 Jun 2022 18:26:11 -0700 Subject: [PATCH 03/48] Ignore .lst build artifact --- .gitignore | 1 + 1 file changed, 1 insertion(+) 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 From b25cad88122c666d1ebbd73ca057b57c41ba21a6 Mon Sep 17 00:00:00 2001 From: Somebody Whoisbored <13044396+shadowninja108@users.noreply.github.com> Date: Sat, 18 Jun 2022 18:36:00 -0700 Subject: [PATCH 04/48] Add socket errno display --- include/SocketBase.hpp | 1 + include/nn/socket.h | 2 ++ source/main.cpp | 1 + source/server/SocketClient.cpp | 8 ++++++++ 4 files changed, 12 insertions(+) diff --git a/include/SocketBase.hpp b/include/SocketBase.hpp index 622b4c0..e14bd72 100644 --- a/include/SocketBase.hpp +++ b/include/SocketBase.hpp @@ -22,6 +22,7 @@ class SocketBase { bool closeSocket(); void setName(const char *name) {strcpy(sockName, name);}; + u32 socket_errno; protected: s32 socket_log(const char* str); diff --git a/include/nn/socket.h b/include/nn/socket.h index 2fc4b6d..b308e33 100644 --- a/include/nn/socket.h +++ b/include/nn/socket.h @@ -34,4 +34,6 @@ s32 Recv(s32 socket, void* out, ulong outLen, s32 flags); u16 InetHtons(u16 val); s32 InetAton(const char* addressStr, in_addr* addressOut); +u32 GetLastErrno(); + } } diff --git a/source/main.cpp b/source/main.cpp index 49b0d07..bc184df 100644 --- a/source/main.cpp +++ b/source/main.cpp @@ -89,6 +89,7 @@ void drawMainHook(HakoniwaSequence *curSequence, sead::Viewport *viewport, sead: gTextWriter->setScaleFromFontHeight(20.f); gTextWriter->printf("Client Socket Connection Status: %s\n", Client::sInstance->mSocket->getStateChar()); + gTextWriter->printf("nn::socket::GetLastErrno: 0x%x\n", Client::sInstance->mSocket->socket_errno); gTextWriter->printf("Packet Queue Length: %d\n", Client::sInstance->mSocket->mPacketQueue.size()); gTextWriter->printf("Total Connected Players: %d\n", Client::getConnectCount() + 1); diff --git a/source/server/SocketClient.cpp b/source/server/SocketClient.cpp index 7943ec1..4e720e0 100644 --- a/source/server/SocketClient.cpp +++ b/source/server/SocketClient.cpp @@ -30,6 +30,7 @@ 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 @@ -38,6 +39,7 @@ nn::Result SocketClient::init(const char* ip, u16 port) { Logger::log("Socket Unavailable.\n"); + this->socket_errno = nn::socket::GetLastErrno(); this->socket_log_state = SOCKET_LOG_UNAVAILABLE; return -1; } @@ -56,6 +58,7 @@ nn::Result SocketClient::init(const char* ip, u16 port) { nn::Result result; if((result = nn::socket::Connect(this->socket_log_socket, &serverAddress, sizeof(serverAddress))).isFailure()) { + this->socket_errno = nn::socket::GetLastErrno(); this->socket_log_state = SOCKET_LOG_UNAVAILABLE; return result; } @@ -81,6 +84,7 @@ bool SocketClient::SEND(Packet *packet) { 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; } @@ -91,6 +95,7 @@ bool SocketClient::RECV() { if (this->socket_log_state != SOCKET_LOG_CONNECTED) { Logger::log("Unable To Recieve! Socket Not Connected.\n"); + this->socket_errno = nn::socket::GetLastErrno(); return false; } @@ -105,6 +110,7 @@ bool SocketClient::RECV() { valread += result; } else { Logger::log("Header Read Failed! Value: %d Total Read: %d\n", result, valread); + this->socket_errno = nn::socket::GetLastErrno(); this->closeSocket(); return false; } @@ -132,6 +138,7 @@ bool SocketClient::RECV() { }else { free(packetBuf); Logger::log("Packet Read Failed! Value: %d\nPacket Size: %d\nPacket Type: %s\n", result, header->mPacketSize, packetNames[header->mType]); + this->socket_errno = nn::socket::GetLastErrno(); this->closeSocket(); return false; } @@ -154,6 +161,7 @@ bool SocketClient::RECV() { 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; } From 8bddc5622ccfee20ce0aef2223e79372689beb46 Mon Sep 17 00:00:00 2001 From: Somebody Whoisbored <13044396+shadowninja108@users.noreply.github.com> Date: Sat, 18 Jun 2022 18:36:17 -0700 Subject: [PATCH 05/48] Remove libnx link --- MakefileNSO | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MakefileNSO b/MakefileNSO index 969473f..43b1f34 100644 --- a/MakefileNSO +++ b/MakefileNSO @@ -51,7 +51,7 @@ CXXFLAGS := $(CFLAGS) -fno-rtti -fomit-frame-pointer -fno-exceptions -fno-asynch 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 From 0657047d9c1a9badb14bd8d0c24fd2393bdeb5b4 Mon Sep 17 00:00:00 2001 From: Somebody Whoisbored <13044396+shadowninja108@users.noreply.github.com> Date: Sat, 18 Jun 2022 18:36:46 -0700 Subject: [PATCH 06/48] Fix DEBUGLOG check --- source/server/logger.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/server/logger.cpp b/source/server/logger.cpp index d2e804a..8291219 100644 --- a/source/server/logger.cpp +++ b/source/server/logger.cpp @@ -104,7 +104,7 @@ bool Logger::pingSocket() { void tryInitSocket() { __asm("STR X20, [X8,#0x18]"); - #if DEBUGLOG + #ifdef DEBUGLOG Logger::createInstance(); // creates a static instance for debug logger #endif } From a7715c15dab310af88621ced29ac9e80fa4b6229 Mon Sep 17 00:00:00 2001 From: Somebody Whoisbored <13044396+shadowninja108@users.noreply.github.com> Date: Sat, 18 Jun 2022 18:37:46 -0700 Subject: [PATCH 07/48] Correct socket option/levels --- source/server/SocketClient.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/source/server/SocketClient.cpp b/source/server/SocketClient.cpp index 4e720e0..8dd50d8 100644 --- a/source/server/SocketClient.cpp +++ b/source/server/SocketClient.cpp @@ -35,7 +35,7 @@ nn::Result SocketClient::init(const char* ip, u16 port) { } #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"); @@ -51,9 +51,9 @@ nn::Result SocketClient::init(const char* ip, u16 port) { 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; From f8b4bd690da3d14adae15fed4880405d17a2510c Mon Sep 17 00:00:00 2001 From: Somebody Whoisbored <13044396+shadowninja108@users.noreply.github.com> Date: Sat, 18 Jun 2022 18:38:46 -0700 Subject: [PATCH 08/48] Enable music by default --- source/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/main.cpp b/source/main.cpp index bc184df..01054cd 100644 --- a/source/main.cpp +++ b/source/main.cpp @@ -325,7 +325,7 @@ bool hakoniwaSequenceHook(HakoniwaSequence* sequence) { updatePlayerInfo(stageScene->mHolder, p1); - static bool isDisableMusic = true; + static bool isDisableMusic = false; if (al::isPadHoldZR(-1)) { if (al::isPadTriggerUp(-1)) debugMode = !debugMode; From 9b275da22bd40c9bdf4efccaea16cad56558afe6 Mon Sep 17 00:00:00 2001 From: Somebody Whoisbored <13044396+shadowninja108@users.noreply.github.com> Date: Sat, 18 Jun 2022 21:42:59 -0700 Subject: [PATCH 09/48] Implement Client::setLastUsedPort --- source/server/Client.cpp | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/source/server/Client.cpp b/source/server/Client.cpp index 95524f4..a6560d7 100644 --- a/source/server/Client.cpp +++ b/source/server/Client.cpp @@ -1361,6 +1361,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. * @@ -1372,6 +1384,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. * From 3b3c5584d9bcad04921e001236ae7ff764376bfb Mon Sep 17 00:00:00 2001 From: fruityloops1 Date: Sun, 19 Jun 2022 16:10:20 +0200 Subject: [PATCH 10/48] remove fixed buffer size from runner (+ run clang-format) --- source/server/logger.cpp | 72 +++++++++++++++++++++++----------------- 1 file changed, 41 insertions(+), 31 deletions(-) diff --git a/source/server/logger.cpp b/source/server/logger.cpp index 8291219..d63d62b 100644 --- a/source/server/logger.cpp +++ b/source/server/logger.cpp @@ -1,25 +1,26 @@ #include "logger.hpp" #include "helpers.hpp" #include "nn/result.h" +#include "nn/util.h" +#include "nx/svc.h" Logger* Logger::sInstance = nullptr; void Logger::createInstance() { - #ifdef SERVERIP +#ifdef SERVERIP sInstance = new Logger(TOSTRING(SERVERIP), 3080, "MainLogger"); - #else +#else sInstance = new Logger(0, 3080, "MainLogger"); - #endif +#endif } nn::Result Logger::init(const char* ip, u16 port) { - sock_ip = ip; - + this->port = port; - - in_addr hostAddress = { 0 }; - sockaddr serverAddress = { 0 }; + + in_addr hostAddress = {0}; + sockaddr serverAddress = {0}; if (this->socket_log_state != SOCKET_LOG_UNINITIALIZED) return -1; @@ -27,23 +28,24 @@ nn::Result Logger::init(const char* ip, u16 port) { nn::nifm::Initialize(); nn::nifm::SubmitNetworkRequest(); - while (nn::nifm::IsNetworkRequestOnHold()) { } + while (nn::nifm::IsNetworkRequestOnHold()) { + } - // emulators make this return false always, so skip it during init - #ifndef EMU +// emulators make this return false always, so skip it during init +#ifndef EMU if (!nn::nifm::IsNetworkAvailable()) { this->socket_log_state = SOCKET_LOG_UNAVAILABLE; return -1; } - #endif - +#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; @@ -52,11 +54,13 @@ nn::Result Logger::init(const char* ip, u16 port) { nn::Result result; - if ((result = nn::socket::Connect(this->socket_log_socket, &serverAddress, sizeof(serverAddress))).isFailure()) { + if ((result = + nn::socket::Connect(this->socket_log_socket, &serverAddress, sizeof(serverAddress))) + .isFailure()) { this->socket_log_state = SOCKET_LOG_UNAVAILABLE; return result; } - + this->socket_log_state = SOCKET_LOG_CONNECTED; this->isDisableName = false; @@ -64,7 +68,7 @@ nn::Result Logger::init(const char* ip, u16 port) { return 0; } -void Logger::log(const char *fmt, va_list args) { // impl for replacing seads system::print +void Logger::log(const char* fmt, va_list args) { // impl for replacing seads system::print if (!sInstance) return; char buf[0x500]; @@ -73,7 +77,7 @@ void Logger::log(const char *fmt, va_list args) { // impl for replacing seads sy } } -s32 Logger::read(char *out) { +s32 Logger::read(char* out) { return this->socket_read_char(out); } @@ -83,29 +87,35 @@ void Logger::log(const char* fmt, ...) { va_list args; va_start(args, fmt); - char buf[0x500]; + size_t bufSize = nn::util::VSNPrintf(nullptr, 0, fmt, args); + size_t prefixSize = bufSize += 3 /* "[] " */ + strlen(sInstance->sockName); + if (!sInstance->isDisableName) + bufSize += prefixSize; + char buf[bufSize]; - if (nn::util::VSNPrintf(buf, sizeof(buf), fmt, args) > 0) { - if (!sInstance->isDisableName) { - char prefix[0x510]; - nn::util::SNPrintf(prefix, sizeof(prefix), "[%s] %s", sInstance->sockName, buf); - sInstance->socket_log(prefix); - } else { - sInstance->socket_log(buf); - } + if (sInstance->isDisableName) + nn::util::VSNPrintf(buf, bufSize, fmt, args); + else { + nn::util::VSNPrintf(buf + prefixSize, bufSize - prefixSize, fmt, args); + nn::util::SNPrintf(buf, prefixSize, "[%s] ", sInstance->sockName); } + sInstance->socket_log(buf); +#ifdef EMU + svcOutputDebugString(buf, bufSize); +#endif + va_end(args); } bool Logger::pingSocket() { - return socket_log("ping") > 0; // if value is greater than zero, than the socket recieved our message, otherwise the connection was lost. + return socket_log("ping") > 0; // if value is greater than zero, than the socket recieved our + // message, otherwise the connection was lost. } void tryInitSocket() { __asm("STR X20, [X8,#0x18]"); - #ifdef DEBUGLOG +#ifdef DEBUGLOG Logger::createInstance(); // creates a static instance for debug logger - #endif +#endif } - From cbadd82b21a85713972079f89bd6a91598016915 Mon Sep 17 00:00:00 2001 From: CraftyBoss <43161115+CraftyBoss@users.noreply.github.com> Date: Sun, 19 Jun 2022 23:56:37 -0700 Subject: [PATCH 11/48] Revert "remove fixed buffer size from logger (+ run clang-format)" --- source/server/logger.cpp | 72 +++++++++++++++++----------------------- 1 file changed, 31 insertions(+), 41 deletions(-) diff --git a/source/server/logger.cpp b/source/server/logger.cpp index d63d62b..8291219 100644 --- a/source/server/logger.cpp +++ b/source/server/logger.cpp @@ -1,26 +1,25 @@ #include "logger.hpp" #include "helpers.hpp" #include "nn/result.h" -#include "nn/util.h" -#include "nx/svc.h" Logger* Logger::sInstance = nullptr; void Logger::createInstance() { -#ifdef SERVERIP + #ifdef SERVERIP sInstance = new Logger(TOSTRING(SERVERIP), 3080, "MainLogger"); -#else + #else sInstance = new Logger(0, 3080, "MainLogger"); -#endif + #endif } nn::Result Logger::init(const char* ip, u16 port) { + sock_ip = ip; - + this->port = port; - - in_addr hostAddress = {0}; - sockaddr serverAddress = {0}; + + in_addr hostAddress = { 0 }; + sockaddr serverAddress = { 0 }; if (this->socket_log_state != SOCKET_LOG_UNINITIALIZED) return -1; @@ -28,24 +27,23 @@ nn::Result Logger::init(const char* ip, u16 port) { nn::nifm::Initialize(); nn::nifm::SubmitNetworkRequest(); - while (nn::nifm::IsNetworkRequestOnHold()) { - } + while (nn::nifm::IsNetworkRequestOnHold()) { } -// emulators make this return false always, so skip it during init -#ifndef EMU + // emulators make this return false always, so skip it during init + #ifndef EMU if (!nn::nifm::IsNetworkAvailable()) { this->socket_log_state = SOCKET_LOG_UNAVAILABLE; return -1; } -#endif - + #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; @@ -54,13 +52,11 @@ nn::Result Logger::init(const char* ip, u16 port) { nn::Result result; - if ((result = - nn::socket::Connect(this->socket_log_socket, &serverAddress, sizeof(serverAddress))) - .isFailure()) { + if ((result = nn::socket::Connect(this->socket_log_socket, &serverAddress, sizeof(serverAddress))).isFailure()) { this->socket_log_state = SOCKET_LOG_UNAVAILABLE; return result; } - + this->socket_log_state = SOCKET_LOG_CONNECTED; this->isDisableName = false; @@ -68,7 +64,7 @@ nn::Result Logger::init(const char* ip, u16 port) { return 0; } -void Logger::log(const char* fmt, va_list args) { // impl for replacing seads system::print +void Logger::log(const char *fmt, va_list args) { // impl for replacing seads system::print if (!sInstance) return; char buf[0x500]; @@ -77,7 +73,7 @@ void Logger::log(const char* fmt, va_list args) { // impl for replacing seads s } } -s32 Logger::read(char* out) { +s32 Logger::read(char *out) { return this->socket_read_char(out); } @@ -87,35 +83,29 @@ void Logger::log(const char* fmt, ...) { va_list args; va_start(args, fmt); - size_t bufSize = nn::util::VSNPrintf(nullptr, 0, fmt, args); - size_t prefixSize = bufSize += 3 /* "[] " */ + strlen(sInstance->sockName); - if (!sInstance->isDisableName) - bufSize += prefixSize; - char buf[bufSize]; + char buf[0x500]; - if (sInstance->isDisableName) - nn::util::VSNPrintf(buf, bufSize, fmt, args); - else { - nn::util::VSNPrintf(buf + prefixSize, bufSize - prefixSize, fmt, args); - nn::util::SNPrintf(buf, prefixSize, "[%s] ", sInstance->sockName); + if (nn::util::VSNPrintf(buf, sizeof(buf), fmt, args) > 0) { + if (!sInstance->isDisableName) { + char prefix[0x510]; + nn::util::SNPrintf(prefix, sizeof(prefix), "[%s] %s", sInstance->sockName, buf); + sInstance->socket_log(prefix); + } else { + sInstance->socket_log(buf); + } } - sInstance->socket_log(buf); -#ifdef EMU - svcOutputDebugString(buf, bufSize); -#endif - va_end(args); } bool Logger::pingSocket() { - return socket_log("ping") > 0; // if value is greater than zero, than the socket recieved our - // message, otherwise the connection was lost. + return socket_log("ping") > 0; // if value is greater than zero, than the socket recieved our message, otherwise the connection was lost. } void tryInitSocket() { __asm("STR X20, [X8,#0x18]"); -#ifdef DEBUGLOG + #ifdef DEBUGLOG Logger::createInstance(); // creates a static instance for debug logger -#endif + #endif } + From 5c715695457f6515a1f1d42efd0eadd839acff36 Mon Sep 17 00:00:00 2001 From: Nick Renieris Date: Wed, 22 Jun 2022 20:11:01 +0300 Subject: [PATCH 12/48] tcpServer: Don't print intermittent newlines --- scripts/tcpServer.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/tcpServer.py b/scripts/tcpServer.py index 5f2c7b5..8ed2453 100644 --- a/scripts/tcpServer.py +++ b/scripts/tcpServer.py @@ -23,11 +23,11 @@ while True: 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 - + finally: # Clean up the connection connection.close() \ No newline at end of file From 9227e37623ccd75f2735ca7c3d3184f2043d621f Mon Sep 17 00:00:00 2001 From: Nick Renieris Date: Wed, 22 Jun 2022 20:16:08 +0300 Subject: [PATCH 13/48] packets: Fix struct packing related bugs - sizeof(bool) is implementation defined. The server assumes it's 4 but for me it was 1 (tested with Release too) which caused some bugs - Structs aren't guaranteed to be packed. The compiler is free to change the layout, which we wouldn't want to for the Packet structs that we deserialize on the server. --- include/packets/CaptureInf.h | 4 ++-- include/packets/ChangeStagePacket.h | 2 +- include/packets/CostumeInf.h | 2 +- include/packets/GameInf.h | 4 ++-- include/packets/HackCapInf.h | 4 ++-- include/packets/InitPacket.h | 2 +- include/packets/Packet.h | 6 ++++-- include/packets/PlayerConnect.h | 2 +- include/packets/PlayerDC.h | 2 +- include/packets/PlayerInfPacket.h | 4 ++-- include/packets/ServerCommand.h | 2 +- include/packets/ShineCollect.h | 4 ++-- include/packets/TagInf.h | 4 ++-- include/types.h | 5 +++++ 14 files changed, 27 insertions(+), 20 deletions(-) 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..0665bc8 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; + bool4 is2D = false; u8 scenarioNo = -1; char stageName[0x40] = {}; diff --git a/include/packets/HackCapInf.h b/include/packets/HackCapInf.h index 7434bd5..c01ea60 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; + bool4 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..6a98562 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 @@ -27,7 +29,7 @@ enum PacketType : short { }; // attribute otherwise the build log is spammed with unused warnings -__attribute((used)) static const char *packetNames[] = { +USED static const char *packetNames[] = { "Unknown", "Player Info", "Player Cap Info", @@ -59,7 +61,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..52acbea 100644 --- a/include/packets/PlayerConnect.h +++ b/include/packets/PlayerConnect.h @@ -2,7 +2,7 @@ #include "Packet.h" -struct PlayerConnect : Packet { +struct PACKED PlayerConnect : Packet { PlayerConnect() : Packet() {this->mType = PacketType::PLAYERCON; mPacketSize = sizeof(PlayerConnect) - sizeof(Packet);}; ConnectionTypes conType; u16 maxPlayerCount; 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..5153c57 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; + bool4 isGrand = false; }; \ No newline at end of file diff --git a/include/packets/TagInf.h b/include/packets/TagInf.h index 22bcdb9..9adba20 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; + bool4 isIt = false; u8 seconds; u16 minutes; }; \ No newline at end of file diff --git a/include/types.h b/include/types.h index 4937f7b..ebcbc23 100644 --- a/include/types.h +++ b/include/types.h @@ -18,6 +18,8 @@ typedef signed int s32; typedef int64_t s64; typedef __int128_t s128; +typedef u32 bool4; // guaranteed to be 4 bytes, 'bool' is impl. defined + typedef float f32; typedef double f64; @@ -76,3 +78,6 @@ struct Rect float right; float top; }; + +#define PACKED __attribute__((packed)) +#define USED __attribute__((used)) From 7e4a80b9342ca9fb59fc465be5a5e45f83e870fc Mon Sep 17 00:00:00 2001 From: Nick Renieris Date: Wed, 22 Jun 2022 20:16:34 +0300 Subject: [PATCH 14/48] packet: Add missing packetNames entries --- include/packets/Packet.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/packets/Packet.h b/include/packets/Packet.h index 6a98562..f536331 100644 --- a/include/packets/Packet.h +++ b/include/packets/Packet.h @@ -31,6 +31,7 @@ enum PacketType : short { // attribute otherwise the build log is spammed with unused warnings USED static const char *packetNames[] = { "Unknown", + "Client Initialization", "Player Info", "Player Cap Info", "Game Info", @@ -40,6 +41,7 @@ USED static const char *packetNames[] = { "Costume Info", "Moon Collection", "Capture Info", + "Change Stage", "Server Command" }; From 60a5179e4b5f24e4aa3b6a7afe72a028abdeae59 Mon Sep 17 00:00:00 2001 From: Nick Renieris Date: Wed, 22 Jun 2022 22:08:00 +0300 Subject: [PATCH 15/48] Anims/Types: Handle out of bounds FindStr accesses without throwing Throwing tries to call `std::__throw_out_of_range_fmt` which results in a crash. The cause of the out of bounds accesses needs to be investigated. --- include/algorithms/CaptureAnims.h | 6 +++++- include/algorithms/CaptureTypes.h | 6 +++++- include/algorithms/PlayerAnims.h | 6 +++++- include/algorithms/WipeTypes.h | 6 +++++- source/server/Client.cpp | 4 ++++ 5 files changed, 24 insertions(+), 4 deletions(-) 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/source/server/Client.cpp b/source/server/Client.cpp index a6560d7..010436b 100644 --- a/source/server/Client.cpp +++ b/source/server/Client.cpp @@ -783,12 +783,16 @@ void Client::updatePlayerInfo(PlayerInf *packet) { } else { strcpy(curInfo->curAnimStr, "Wait"); } + if (strlen(curInfo->curAnimStr) == 0) + Logger::log("[ERROR] %s: actName was out of bounds: %d", __func__, packet->actName); if(packet->subActName != PlayerAnims::Type::Unknown) { strcpy(curInfo->curSubAnimStr, PlayerAnims::FindStr(packet->subActName)); } else { strcpy(curInfo->curSubAnimStr, ""); } + if (strlen(curInfo->curSubAnimStr) == 0) + Logger::log("[ERROR] %s: subActName was out of bounds: %d", __func__, packet->subActName); curInfo->curAnim = packet->actName; curInfo->curSubAnim = packet->subActName; From 8f21d43bc359fa5e33c41b4527f35b590b8ff417 Mon Sep 17 00:00:00 2001 From: Nick Renieris Date: Fri, 24 Jun 2022 03:18:40 +0300 Subject: [PATCH 16/48] packets/PlayerConnect: Initialize maxPlayerCount It was sending bad data since it wasn't getting inited anywhere. --- include/packets/PlayerConnect.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/include/packets/PlayerConnect.h b/include/packets/PlayerConnect.h index 52acbea..f3ea37c 100644 --- a/include/packets/PlayerConnect.h +++ b/include/packets/PlayerConnect.h @@ -2,9 +2,11 @@ #include "Packet.h" +#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 From 23cdf1442d0f9ee90b182429cea58d1a497a794e Mon Sep 17 00:00:00 2001 From: Nick Renieris Date: Sat, 25 Jun 2022 03:46:58 +0300 Subject: [PATCH 17/48] Make "Reconnect to Server" option work if initial socket conn failed --- include/server/Client.hpp | 17 ++++++------ source/server/Client.cpp | 27 ++++++++++--------- source/server/SocketClient.cpp | 3 +-- source/states/StageSceneStateServerConfig.cpp | 19 ++++++++----- 4 files changed, 38 insertions(+), 28 deletions(-) diff --git a/include/server/Client.hpp b/include/server/Client.hpp index 14a10e2..d3bf076 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 @@ -92,7 +92,7 @@ class Client { bool isShineCollected(int shineId); static void initMode(GameModeInitInfo const &initInfo); - + static void sendHackCapInfPacket(const HackCap *hackCap); static void sendPlayerInfPacket(const PlayerActorHakoniwa *player); static void sendGameInfPacket(const PlayerActorHakoniwa *player, GameDataHolderAccessor holder); @@ -191,7 +191,7 @@ class Client { static void tryRestartCurrentMode(); static bool isModeActive() { return sInstance ? sInstance->mIsModeActive : false; } - + static bool isSelectedMode(GameMode mode) { return sInstance ? sInstance->mCurMode->getMode() == mode: false; } void resetCollectedShines(); @@ -224,7 +224,7 @@ class Client { // currently, only readThread is used to recieve and update PuppetInfo, while the main game thread is used to send packets without queueing them up first, which might cause performance issues 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; @@ -233,10 +233,10 @@ class Client { sead::FixedSafeString<0x20> mUsername; - // --- Server Syncing Members --- - + // --- 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; @@ -252,6 +252,7 @@ class Client { int mServerPort = 0; + bool waitForGameInit = true; bool isFirstConnect = true; // --- Game Layouts --- diff --git a/source/server/Client.cpp b/source/server/Client.cpp index 010436b..2eff7b7 100644 --- a/source/server/Client.cpp +++ b/source/server/Client.cpp @@ -215,14 +215,16 @@ bool Client::startConnection() { Client::openKeyboardPort(); } - bool result = mSocket->init(mServerIP.cstr(), mServerPort).isSuccess(); + bool socketConnected = mSocket->isConnected(); + if (!socketConnected) { + socketConnected = mSocket->init(mServerIP.cstr(), mServerPort).isSuccess(); + } - if (result) { + bool clientConnected = false; + if (socketConnected) { // wait for client init packet while (true) { - if (mSocket->RECV()) { - Packet* curPacket = mSocket->mPacketQueue.popFront(); if (curPacket->mType == PacketType::CLIENTINIT) { @@ -232,21 +234,20 @@ bool Client::startConnection() { maxPuppets = initPacket->maxPlayers - 1; - }else { + clientConnected = true; + } else { Logger::log("First Packet was not Init!\n"); - result = false; + clientConnected = false; } free(curPacket); - } break; } } - - return result; + return clientConnected; } /** @@ -317,9 +318,10 @@ void Client::openKeyboardPort() { */ 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 @@ -398,7 +400,8 @@ void Client::readFunc() { mSocket->SEND(&initPacket); // re-send init packet as reconnect packet 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 @@ -449,7 +452,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; diff --git a/source/server/SocketClient.cpp b/source/server/SocketClient.cpp index 8dd50d8..bcf5a82 100644 --- a/source/server/SocketClient.cpp +++ b/source/server/SocketClient.cpp @@ -17,8 +17,7 @@ nn::Result SocketClient::init(const char* ip, u16 port) { 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(); diff --git a/source/states/StageSceneStateServerConfig.cpp b/source/states/StageSceneStateServerConfig.cpp index 230b55a..5dcb513 100644 --- a/source/states/StageSceneStateServerConfig.cpp +++ b/source/states/StageSceneStateServerConfig.cpp @@ -80,7 +80,7 @@ StageSceneStateServerConfig::StageSceneStateServerConfig(const char *name, al::S mCurrentMenu = mMainOptions; } -void StageSceneStateServerConfig::init() { +void StageSceneStateServerConfig::init() { initNerve(&nrvStageSceneStateServerConfigMainMenu, 0); } @@ -193,13 +193,20 @@ void StageSceneStateServerConfig::exeOpenKeyboardPort() { void StageSceneStateServerConfig::exeRestartServer() { if (al::isFirstStep(this)) { mCurrentList->deactivate(); + Logger::log("Stopping connection\n"); Client::stopConnection(); } - if (Client::isSocketActive()) { - al::startHitReaction(mCurrentMenu, "リセット", 0); - al::setNerve(this, &nrvStageSceneStateServerConfigMainMenu); + auto* client = Client::sInstance; + + if (client) { + Logger::log("%s: Socket state: %s\n", __func__, client->mSocket->getStateChar()); + + client->StartThreads(); } + + al::startHitReaction(mCurrentMenu, "リセット", 0); + al::setNerve(this, &nrvStageSceneStateServerConfigMainMenu); } void StageSceneStateServerConfig::exeGamemodeConfig() { @@ -210,7 +217,7 @@ void StageSceneStateServerConfig::exeGamemodeConfig() { } subMenuUpdate(); - + if (mIsDecideConfig && mCurrentList->isDecideEnd()) { if (mGamemodeConfigMenu->updateMenu(mCurrentList->mCurSelected)) { endSubMenu(); @@ -220,7 +227,7 @@ void StageSceneStateServerConfig::exeGamemodeConfig() { void StageSceneStateServerConfig::exeGamemodeSelect() { if (al::isFirstStep(this)) { - + mCurrentList = mModeSelectList; mCurrentMenu = mModeSelect; From 0bfd7a70b2b5488c37a5c47f476326eb02e8da0b Mon Sep 17 00:00:00 2001 From: Nick Renieris Date: Sat, 25 Jun 2022 03:47:23 +0300 Subject: [PATCH 18/48] main: Log puppet costume --- source/main.cpp | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/source/main.cpp b/source/main.cpp index 01054cd..2306de1 100644 --- a/source/main.cpp +++ b/source/main.cpp @@ -137,6 +137,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); @@ -165,7 +166,7 @@ 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); @@ -178,14 +179,14 @@ void drawMainHook(HakoniwaSequence *curSequence, sead::Viewport *viewport, sead: } break; case 2: - { + { al::PlayerHolder *pHolder = al::getScenePlayerHolder(curScene); PlayerActorHakoniwa *p1 = pHolder->tryGetPlayer(0); if (p1->mHackKeeper && p1->mHackKeeper->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()); @@ -209,14 +210,14 @@ 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. @@ -244,7 +245,7 @@ void sendShinePacket(GameDataHolderWriter thisPtr, Shine* curShine) { if (!curShine->isGot()) { Client::sendShineCollectPacket(curShine->shineId); } - + GameDataFunction::setGotShine(thisPtr, curShine->curShineInfo); } @@ -252,7 +253,7 @@ void stageInitHook(al::ActorInitInfo *info, StageScene *curScene, al::PlacementI al::initActorInitInfo(info, curScene, placement, lytInfo, factory, sceneMsgCtrl, dataHolder); - + Client::clearArrays(); Client::setSceneInfo(*info, curScene); @@ -264,7 +265,7 @@ void stageInitHook(al::ActorInitInfo *info, StageScene *curScene, al::PlacementI } 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) { @@ -281,7 +282,7 @@ 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); return 0x20; @@ -311,7 +312,7 @@ bool hakoniwaSequenceHook(HakoniwaSequence* sequence) { if (isFirstStep) { Client::tryRestartCurrentMode(); } - + isInGame = !stageScene->isPause(); Client::setGameActive(!stageScene->isPause()); @@ -348,7 +349,7 @@ bool hakoniwaSequenceHook(HakoniwaSequence* sequence) { if (debugPuppetIndex >= playBufSize) debugPuppetIndex = 0; } - + } else if (al::isPadHoldL(-1)) { if (al::isPadTriggerLeft(-1)) Client::toggleCurrentMode(); if (al::isPadTriggerRight(-1)) { @@ -389,7 +390,7 @@ bool hakoniwaSequenceHook(HakoniwaSequence* sequence) { } -void seadPrintHook(const char *fmt, ...) +void seadPrintHook(const char *fmt, ...) { va_list args; va_start(args, fmt); From d1e4466fba86a13c0f5e209a74f8f8c46ccdb327 Mon Sep 17 00:00:00 2001 From: Nick Renieris Date: Sat, 25 Jun 2022 03:48:06 +0300 Subject: [PATCH 19/48] tcpServer: Handle connection reset --- scripts/tcpServer.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/scripts/tcpServer.py b/scripts/tcpServer.py index 8ed2453..f5eeb0d 100644 --- a/scripts/tcpServer.py +++ b/scripts/tcpServer.py @@ -22,12 +22,16 @@ 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"), 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() From 733f239d68cb3b2ff1afe085e8f71db5a4bd2dfb Mon Sep 17 00:00:00 2001 From: Nick Renieris Date: Sat, 25 Jun 2022 03:48:33 +0300 Subject: [PATCH 20/48] socketBase: Initialize state --- include/SocketBase.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/SocketBase.hpp b/include/SocketBase.hpp index e14bd72..ea04e18 100644 --- a/include/SocketBase.hpp +++ b/include/SocketBase.hpp @@ -32,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; }; From 90f09a8340b7d0cb49aebd9a532aaa7cd28a6339 Mon Sep 17 00:00:00 2001 From: Nick Renieris Date: Sat, 25 Jun 2022 03:54:23 +0300 Subject: [PATCH 21/48] states: Fix "Change Server Port" dialog --- source/states/StageSceneStateServerConfig.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/states/StageSceneStateServerConfig.cpp b/source/states/StageSceneStateServerConfig.cpp index 5dcb513..38695e5 100644 --- a/source/states/StageSceneStateServerConfig.cpp +++ b/source/states/StageSceneStateServerConfig.cpp @@ -183,7 +183,7 @@ void StageSceneStateServerConfig::exeOpenKeyboardPort() { Client::getKeyboard()->setHeaderText(u"Set a Server Port Below."); Client::getKeyboard()->setSubText(u""); - Client::openKeyboardIP(); + Client::openKeyboardPort(); // anything that happens after this will be ran after the keyboard closes al::startHitReaction(mCurrentMenu, "リセット", 0); al::setNerve(this, &nrvStageSceneStateServerConfigMainMenu); From 71b4237d84796bd551747f2165cc10eda3dd2d77 Mon Sep 17 00:00:00 2001 From: Nick Renieris Date: Sat, 25 Jun 2022 03:55:34 +0300 Subject: [PATCH 22/48] Client: Don't erroneously log some errors --- source/server/Client.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/source/server/Client.cpp b/source/server/Client.cpp index 2eff7b7..a3accbd 100644 --- a/source/server/Client.cpp +++ b/source/server/Client.cpp @@ -783,19 +783,19 @@ void Client::updatePlayerInfo(PlayerInf *packet) { 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 (strlen(curInfo->curAnimStr) == 0) - Logger::log("[ERROR] %s: actName was out of bounds: %d", __func__, packet->actName); 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, ""); } - if (strlen(curInfo->curSubAnimStr) == 0) - Logger::log("[ERROR] %s: subActName was out of bounds: %d", __func__, packet->subActName); curInfo->curAnim = packet->actName; curInfo->curSubAnim = packet->subActName; From 86de2206195587f7cae4fa5639143a9733986c9b Mon Sep 17 00:00:00 2001 From: Nick Renieris Date: Sun, 26 Jun 2022 06:11:06 +0300 Subject: [PATCH 23/48] Client: Sync Player & Costume info on connect --- include/server/Client.hpp | 6 +++--- source/server/Client.cpp | 18 ++++++++++++------ 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/include/server/Client.hpp b/include/server/Client.hpp index d3bf076..876b76d 100644 --- a/include/server/Client.hpp +++ b/include/server/Client.hpp @@ -241,10 +241,10 @@ class Client { 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 diff --git a/source/server/Client.cpp b/source/server/Client.cpp index a3accbd..8ae385c 100644 --- a/source/server/Client.cpp +++ b/source/server/Client.cpp @@ -435,15 +435,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); @@ -698,6 +703,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; } /** From 62cc2a5102605207614862661a6a2a988a2fb58d Mon Sep 17 00:00:00 2001 From: Nick Renieris Date: Sun, 26 Jun 2022 06:13:05 +0300 Subject: [PATCH 24/48] SocketClient: Log packets by default (also recv), excluding Player and Cap They're too spammy. --- source/server/SocketClient.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/source/server/SocketClient.cpp b/source/server/SocketClient.cpp index bcf5a82..d22c89f 100644 --- a/source/server/SocketClient.cpp +++ b/source/server/SocketClient.cpp @@ -77,7 +77,8 @@ 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)) { return true; @@ -93,7 +94,7 @@ 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; } @@ -122,6 +123,10 @@ bool SocketClient::RECV() { if (header->mType != PacketType::UNKNOWN && fullSize <= MAXPACKSIZE && fullSize > 0) { + if (header->mType != PLAYERINF && header->mType != HACKCAPINF) + Logger::log("Received packet (from %02X%02X): %s\n", + header->mUserID.data[0], header->mUserID.data[1], packetNames[header->mType]); + char* packetBuf = (char*)malloc(fullSize); if (packetBuf) { From 740f562906cc3f28a552ebfb0157c2f20f1b3286 Mon Sep 17 00:00:00 2001 From: Nick Renieris Date: Sun, 26 Jun 2022 06:30:38 +0300 Subject: [PATCH 25/48] server/logger: Support trying additional ports --- source/server/logger.cpp | 34 +++++++++++++++++++++++----------- 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/source/server/logger.cpp b/source/server/logger.cpp index 8291219..6fa0b61 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 From a416458e731f7a84dfa1f7fdcd977ffc050e1c75 Mon Sep 17 00:00:00 2001 From: Nick Renieris Date: Sun, 26 Jun 2022 06:30:51 +0300 Subject: [PATCH 26/48] tcpServer: Support specifying port number --- scripts/tcpServer.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/scripts/tcpServer.py b/scripts/tcpServer.py index f5eeb0d..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) @@ -35,3 +39,4 @@ while True: finally: # Clean up the connection connection.close() + From 951844e428ddf9be2b437bbd6529f7d554f327ad Mon Sep 17 00:00:00 2001 From: Nick Renieris Date: Sun, 26 Jun 2022 06:31:21 +0300 Subject: [PATCH 27/48] main: Fix debug puppet index incrementing The last one was empty. --- source/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/main.cpp b/source/main.cpp index 2306de1..971a735 100644 --- a/source/main.cpp +++ b/source/main.cpp @@ -346,7 +346,7 @@ bool hakoniwaSequenceHook(HakoniwaSequence* sequence) { if(debugPuppetIndex < 0) { debugPuppetIndex = playBufSize - 2; } - if (debugPuppetIndex >= playBufSize) + if (debugPuppetIndex >= playBufSize - 1) debugPuppetIndex = 0; } From 0e9fde928919ea8534bdfa5d40b26311aca78bb6 Mon Sep 17 00:00:00 2001 From: Nick Renieris Date: Tue, 28 Jun 2022 13:26:26 +0300 Subject: [PATCH 28/48] packets: Make bools take up 1 byte --- include/packets/GameInf.h | 2 +- include/packets/HackCapInf.h | 2 +- include/packets/ShineCollect.h | 2 +- include/packets/TagInf.h | 2 +- include/types.h | 4 +++- 5 files changed, 7 insertions(+), 5 deletions(-) diff --git a/include/packets/GameInf.h b/include/packets/GameInf.h index 0665bc8..34c5793 100644 --- a/include/packets/GameInf.h +++ b/include/packets/GameInf.h @@ -5,7 +5,7 @@ struct PACKED GameInf : Packet { GameInf() : Packet() {this->mType = PacketType::GAMEINF; mPacketSize = sizeof(GameInf) - sizeof(Packet);}; - bool4 is2D = false; + bool1 is2D = false; u8 scenarioNo = -1; char stageName[0x40] = {}; diff --git a/include/packets/HackCapInf.h b/include/packets/HackCapInf.h index c01ea60..fc92534 100644 --- a/include/packets/HackCapInf.h +++ b/include/packets/HackCapInf.h @@ -6,6 +6,6 @@ struct PACKED HackCapInf : Packet { HackCapInf() : Packet() {this->mType = PacketType::HACKCAPINF; mPacketSize = sizeof(HackCapInf) - sizeof(Packet);}; sead::Vector3f capPos; sead::Quatf capQuat; - bool4 isCapVisible = false; + bool1 isCapVisible = false; char capAnim[PACKBUFSIZE] = {}; }; \ No newline at end of file diff --git a/include/packets/ShineCollect.h b/include/packets/ShineCollect.h index 5153c57..2e6bdad 100644 --- a/include/packets/ShineCollect.h +++ b/include/packets/ShineCollect.h @@ -5,5 +5,5 @@ struct PACKED ShineCollect : Packet { ShineCollect() : Packet() {this->mType = PacketType::SHINECOLL; mPacketSize = sizeof(ShineCollect) - sizeof(Packet);}; int shineId = -1; - bool4 isGrand = false; + bool1 isGrand = false; }; \ No newline at end of file diff --git a/include/packets/TagInf.h b/include/packets/TagInf.h index 9adba20..bd5a64e 100644 --- a/include/packets/TagInf.h +++ b/include/packets/TagInf.h @@ -11,7 +11,7 @@ enum TagUpdateType : u8 { struct PACKED TagInf : Packet { TagInf() : Packet() { this->mType = PacketType::TAGINF; mPacketSize = sizeof(TagInf) - sizeof(Packet);}; TagUpdateType updateType; - bool4 isIt = false; + bool1 isIt = false; u8 seconds; u16 minutes; }; \ No newline at end of file diff --git a/include/types.h b/include/types.h index ebcbc23..397a50c 100644 --- a/include/types.h +++ b/include/types.h @@ -18,7 +18,9 @@ typedef signed int s32; typedef int64_t s64; typedef __int128_t s128; -typedef u32 bool4; // guaranteed to be 4 bytes, 'bool' is impl. defined +// bool size is implementation defined, so use these where it's important +typedef u8 bool1; +typedef u32 bool4; typedef float f32; typedef double f64; From b00540b1d9fbd59317c6b060809add04faf464d1 Mon Sep 17 00:00:00 2001 From: CraftyBoss Date: Tue, 5 Jul 2022 12:45:22 -0700 Subject: [PATCH 29/48] impl saving after ip/port change, add sceneobj headers, rework puppet info system a bit --- Makefile | 14 +- MakefileNSO | 2 +- include/SocketBase.hpp | 2 +- include/al/scene/SceneObjFactory.h | 89 ++++ include/al/scene/SceneObjHolder.h | 10 +- include/al/scene/SceneObjs.h | 179 ++++++++ .../game/GameData/GameDataHolderAccessor.h | 1 + .../game/SaveData/SaveDataAccessFunction.h | 19 + include/game/SceneObjs/RouteGuideDirector.h | 31 ++ .../StageSceneStateServerConfig.hpp | 2 + include/nn/account.h | 10 +- include/nn/system_settings.ini | 53 --- include/server/Client.hpp | 17 +- include/server/SocketClient.hpp | 3 +- source/main.cpp | 2 +- source/server/Client.cpp | 384 +++++++++--------- source/server/SocketClient.cpp | 31 +- source/states/StageSceneStateServerConfig.cpp | 27 +- 18 files changed, 589 insertions(+), 287 deletions(-) create mode 100644 include/al/scene/SceneObjFactory.h create mode 100644 include/al/scene/SceneObjs.h create mode 100644 include/game/SaveData/SaveDataAccessFunction.h create mode 100644 include/game/SceneObjs/RouteGuideDirector.h delete mode 100644 include/nn/system_settings.ini diff --git a/Makefile b/Makefile index 9c8c846..7b9a40e 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)/ @@ -29,9 +31,9 @@ starlight_patch_$(SMOVER)/*.ips: patches/*.slpatch patches/configs/$(SMOVER).con @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 43b1f34..a301b90 100644 --- a/MakefileNSO +++ b/MakefileNSO @@ -44,7 +44,7 @@ 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 diff --git a/include/SocketBase.hpp b/include/SocketBase.hpp index e14bd72..9ffc58a 100644 --- a/include/SocketBase.hpp +++ b/include/SocketBase.hpp @@ -12,6 +12,7 @@ class SocketBase { SocketBase(const char *name); virtual nn::Result init(const char * ip, u16 port) = 0; + virtual bool closeSocket(); const char *getStateChar(); u8 getLogState(); @@ -19,7 +20,6 @@ class SocketBase { void set_sock_flags(int flags); - bool closeSocket(); void setName(const char *name) {strcpy(sockName, name);}; u32 socket_errno; 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/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/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/StageScene/StageSceneStateServerConfig.hpp b/include/game/StageScene/StageSceneStateServerConfig.hpp index 0a69ece..f3c3469 100644 --- a/include/game/StageScene/StageSceneStateServerConfig.hpp +++ b/include/game/StageScene/StageSceneStateServerConfig.hpp @@ -44,6 +44,7 @@ class StageSceneStateServerConfig : public al::HostStateBase, public void exeRestartServer(); void exeGamemodeConfig(); void exeGamemodeSelect(); + void exeSaveData(); void endSubMenu(); @@ -82,4 +83,5 @@ namespace { NERVE_HEADER(StageSceneStateServerConfig, RestartServer) NERVE_HEADER(StageSceneStateServerConfig, GamemodeConfig) NERVE_HEADER(StageSceneStateServerConfig, GamemodeSelect) + NERVE_HEADER(StageSceneStateServerConfig, SaveData) } \ No newline at end of file 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/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/server/Client.hpp b/include/server/Client.hpp index 14a10e2..67b3b0f 100644 --- a/include/server/Client.hpp +++ b/include/server/Client.hpp @@ -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" @@ -65,6 +66,8 @@ #include +#define MAXPUPINDEX 32 + struct UIDIndexNode { nn::account::Uid uid; int puppetIndex; @@ -78,12 +81,12 @@ class 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; }; @@ -215,7 +218,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(); @@ -225,7 +228,7 @@ 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; + sead::SafeArray puppetPlayerID; int mConnectCount = 0; @@ -233,6 +236,8 @@ class Client { 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 @@ -277,6 +282,8 @@ class Client { sead::FixedSafeString<0x40> mStageName; + GameDataHolderAccessor mHolder; + u8 mScenario = 0; // --- Mode Info --- @@ -291,7 +298,7 @@ class Client { // --- Puppet Info --- - PuppetInfo *mPuppetInfoArr[32]; + PuppetInfo *mPuppetInfoArr[MAXPUPINDEX]; PuppetHolder *mPuppetHolder = nullptr; diff --git a/include/server/SocketClient.hpp b/include/server/SocketClient.hpp index 0aa4959..128af87 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); diff --git a/source/main.cpp b/source/main.cpp index 01054cd..5b7a3ef 100644 --- a/source/main.cpp +++ b/source/main.cpp @@ -293,7 +293,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::sInstance->init(lytInfo, mainSeq->mGameDataHolder); return GameDataFunction::isPlayDemoOpening(mainSeq->mGameDataHolder); } diff --git a/source/server/Client.cpp b/source/server/Client.cpp index a6560d7..82bc48c 100644 --- a/source/server/Client.cpp +++ b/source/server/Client.cpp @@ -1,4 +1,5 @@ #include "server/Client.hpp" +#include #include #include "al/actor/ActorSceneInfo.h" #include "al/layout/WindowConfirmWait.h" @@ -8,6 +9,7 @@ #include "game/GameData/GameDataHolderAccessor.h" #include "game/Info/QuestInfo.h" #include "game/Player/PlayerActorHakoniwa.h" +#include "game/SaveData/SaveDataAccessFunction.h" #include "game/StageScene/StageScene.h" #include "heap/seadHeapMgr.h" #include "helpers.hpp" @@ -22,7 +24,9 @@ #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" @@ -62,7 +66,7 @@ Client::Client(int bufferSize) { strcpy(mDebugPuppetInfo.puppetName, "PuppetDebug"); - puppetPlayerID.fill({0, 0}); + puppetPlayerID.fill({0}); mConnectCount = 0; @@ -83,9 +87,7 @@ Client::Client(int bufferSize) { 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 @@ -101,7 +103,7 @@ 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); @@ -109,9 +111,9 @@ void Client::init(al::LayoutInitInfo const &initInfo) { mConnectionWait->setTxtMessageConfirm(u"Failed to Connect!"); - StartThreads(); + mHolder = holder; - // mConnectionWait->tryEndForce(); + StartThreads(); } /** @@ -168,30 +170,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"); + + PlayerDC playerDC = PlayerDC(); + + playerDC.mUserID = sInstance->mUserID; + + sInstance->mSocket->SEND(&playerDC); + + if (sInstance->mSocket->closeSocket()) { + Logger::log("Sucessfully Closed Socket.\n"); + } sInstance->puppetPlayerID.fill({0,0}); 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; sInstance->mSocket->SEND(&initPacket); + + } else { + Logger::log("Reconnect Unsuccessful.\n"); } } /** @@ -201,11 +216,15 @@ void Client::stopConnection() { * @return false if connection was unable to establish */ bool Client::startConnection() { + + bool isNeedSave = false; + if (mServerIP.isEmpty()) { mKeyboard->setHeaderText(u"Save File does not contain an IP!"); mKeyboard->setSubText(u"Please set a Server IP Below."); mServerIP = "0.0.0.0"; Client::openKeyboardIP(); + isNeedSave = true; } if (!mServerPort) { @@ -213,11 +232,19 @@ bool Client::startConnection() { mKeyboard->setSubText(u"Please set a Server Port Below."); mServerPort = 1027; Client::openKeyboardPort(); + isNeedSave = true; } - bool result = mSocket->init(mServerIP.cstr(), mServerPort).isSuccess(); + 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"); - if (result) { // wait for client init packet while (true) { @@ -234,19 +261,21 @@ bool Client::startConnection() { }else { Logger::log("First Packet was not Init!\n"); - result = false; + mIsConnectionActive = false; } free(curPacket); + } else { + Logger::log("Recieve failed! Stopping Connection.\n"); + mIsConnectionActive = false; } break; } } - - - return result; + + return mIsConnectionActive; } /** @@ -331,6 +360,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"); @@ -342,16 +373,6 @@ 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()); @@ -370,7 +391,7 @@ void Client::readFunc() { isFirstConnect = false; - while(true) { + while(mIsConnectionActive) { if (mSocket->getLogState() != SOCKET_LOG_CONNECTED) { @@ -383,14 +404,9 @@ 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"); @@ -399,12 +415,12 @@ void Client::readFunc() { mConnectionWait->tryEnd(); continue; + } else { + Logger::log("Connection Failed! Retrying in 5 Seconds.\n"); } 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 } @@ -474,11 +490,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 @@ -753,61 +771,55 @@ void Client::sendShineCollectPacket(int shineID) { * @param packet */ void Client::updatePlayerInfo(PlayerInf *packet) { - - 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; - } - - 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)); - } else { - strcpy(curInfo->curAnimStr, "Wait"); - } - - if(packet->subActName != PlayerAnims::Type::Unknown) { - strcpy(curInfo->curSubAnimStr, PlayerAnims::FindStr(packet->subActName)); - } else { - strcpy(curInfo->curSubAnimStr, ""); - } - - 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]; - } - } - - //TEMP - - if(!curInfo->isCapThrow) { - curInfo->capPos = packet->playerPos; - } + PuppetInfo* curInfo = findPuppetInfo(packet->mUserID, false); + if (!curInfo) { + 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 (packet->actName != PlayerAnims::Type::Unknown) { + strcpy(curInfo->curAnimStr, PlayerAnims::FindStr(packet->actName)); + } else { + strcpy(curInfo->curAnimStr, "Wait"); + } + + if(packet->subActName != PlayerAnims::Type::Unknown) { + strcpy(curInfo->curSubAnimStr, PlayerAnims::FindStr(packet->subActName)); + } else { + strcpy(curInfo->curSubAnimStr, ""); + } + + 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]; + } + } + + //TEMP + + if(!curInfo->isCapThrow) { + curInfo->capPos = packet->playerPos; + } + } /** @@ -817,24 +829,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); } } @@ -843,22 +846,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); } } @@ -868,21 +867,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); } /** @@ -902,18 +895,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++; } } /** @@ -922,26 +926,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; } } @@ -971,20 +971,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; } /** @@ -1011,29 +1006,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) { + return; } + + curInfo->isConnected = false; + + curInfo->scenarioNo = -1; + strcpy(curInfo->stageName, ""); + curInfo->isInSameStage = false; + + mConnectCount--; } /** @@ -1064,23 +1050,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(); 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; } /** diff --git a/source/server/SocketClient.cpp b/source/server/SocketClient.cpp index 8dd50d8..9f84467 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" @@ -17,8 +18,7 @@ nn::Result SocketClient::init(const char* ip, u16 port) { 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(); @@ -58,6 +58,7 @@ nn::Result SocketClient::init(const char* ip, u16 port) { 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; @@ -78,7 +79,6 @@ bool SocketClient::SEND(Packet *packet) { int valread = 0; - //Logger::log("Sending Packet Size: %d Sending Type: %s\n", packet->mPacketSize, packetNames[packet->mType]); if ((valread = nn::socket::Send(this->socket_log_socket, buffer, packet->mPacketSize + sizeof(Packet), this->sock_flags) > 0)) { return true; @@ -105,12 +105,15 @@ 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->socket_errno = nn::socket::GetLastErrno(); this->closeSocket(); return false; } @@ -131,14 +134,16 @@ 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->socket_errno = nn::socket::GetLastErrno(); this->closeSocket(); return false; } @@ -151,11 +156,7 @@ 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); } return true; @@ -183,3 +184,9 @@ void SocketClient::printPacket(Packet *packet) { } } +bool SocketClient::closeSocket() { + + Logger::log("Closing Socket.\n"); + + return SocketBase::closeSocket(); +} \ No newline at end of file diff --git a/source/states/StageSceneStateServerConfig.cpp b/source/states/StageSceneStateServerConfig.cpp index 230b55a..6fb959f 100644 --- a/source/states/StageSceneStateServerConfig.cpp +++ b/source/states/StageSceneStateServerConfig.cpp @@ -1,6 +1,7 @@ #include "game/StageScene/StageSceneStateServerConfig.hpp" #include #include +#include "game/SaveData/SaveDataAccessFunction.h" #include "server/Client.hpp" #include "al/util.hpp" #include "al/util/NerveUtil.h" @@ -172,7 +173,7 @@ void StageSceneStateServerConfig::exeOpenKeyboardIP() { Client::openKeyboardIP(); // anything that happens after this will be ran after the keyboard closes al::startHitReaction(mCurrentMenu, "リセット", 0); - al::setNerve(this, &nrvStageSceneStateServerConfigMainMenu); + al::setNerve(this, &nrvStageSceneStateServerConfigSaveData); } } @@ -183,23 +184,22 @@ void StageSceneStateServerConfig::exeOpenKeyboardPort() { Client::getKeyboard()->setHeaderText(u"Set a Server Port Below."); Client::getKeyboard()->setSubText(u""); - Client::openKeyboardIP(); + Client::openKeyboardPort(); // anything that happens after this will be ran after the keyboard closes - al::startHitReaction(mCurrentMenu, "リセット", 0); - al::setNerve(this, &nrvStageSceneStateServerConfigMainMenu); + al::setNerve(this, &nrvStageSceneStateServerConfigSaveData); } } void StageSceneStateServerConfig::exeRestartServer() { if (al::isFirstStep(this)) { mCurrentList->deactivate(); - Client::stopConnection(); + Client::restartConnection(); } - if (Client::isSocketActive()) { + //if (Client::isSocketActive()) { al::startHitReaction(mCurrentMenu, "リセット", 0); al::setNerve(this, &nrvStageSceneStateServerConfigMainMenu); - } + //} } void StageSceneStateServerConfig::exeGamemodeConfig() { @@ -291,6 +291,18 @@ void StageSceneStateServerConfig::subMenuUpdate() { } } +void StageSceneStateServerConfig::exeSaveData() { + + if (al::isFirstStep(this)) { + SaveDataAccessFunction::startSaveDataWrite(mGameDataHolder); + } + + if (SaveDataAccessFunction::updateSaveDataAccess(mGameDataHolder, false)) { + al::startHitReaction(mCurrentMenu, "リセット", 0); + al::setNerve(this, &nrvStageSceneStateServerConfigMainMenu); + } +} + namespace { NERVE_IMPL(StageSceneStateServerConfig, MainMenu) NERVE_IMPL(StageSceneStateServerConfig, OpenKeyboardIP) @@ -298,4 +310,5 @@ NERVE_IMPL(StageSceneStateServerConfig, OpenKeyboardPort) NERVE_IMPL(StageSceneStateServerConfig, RestartServer) NERVE_IMPL(StageSceneStateServerConfig, GamemodeConfig) NERVE_IMPL(StageSceneStateServerConfig, GamemodeSelect) +NERVE_IMPL(StageSceneStateServerConfig, SaveData) } \ No newline at end of file From c9b1dfa911528005de475480c2ca20b9f87f0dec Mon Sep 17 00:00:00 2001 From: Link4565 <49906383+Link4565@users.noreply.github.com> Date: Wed, 6 Jul 2022 22:42:41 +0100 Subject: [PATCH 30/48] Disable blocking on Recv calls Adding non-blocking support to emulators prevents them from stalling with this change --- source/server/Client.cpp | 30 +++++++++++++++++------------- source/server/SocketBase.cpp | 2 +- source/server/SocketClient.cpp | 12 ++++++++---- 3 files changed, 26 insertions(+), 18 deletions(-) diff --git a/source/server/Client.cpp b/source/server/Client.cpp index adfbff8..33b3e92 100644 --- a/source/server/Client.cpp +++ b/source/server/Client.cpp @@ -245,30 +245,34 @@ bool Client::startConnection() { 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()) { - Packet* curPacket = mSocket->mPacketQueue.popFront(); + if(!mSocket->mPacketQueue.isEmpty()){ - if (curPacket->mType == PacketType::CLIENTINIT) { - InitPacket* initPacket = (InitPacket*)curPacket; + Packet* curPacket = mSocket->mPacketQueue.popFront(); - Logger::log("Server Max Player Size: %d\n", initPacket->maxPlayers); + if (curPacket->mType == PacketType::CLIENTINIT) { + InitPacket* initPacket = (InitPacket*)curPacket; - maxPuppets = initPacket->maxPlayers - 1; - } else { - Logger::log("First Packet was not Init!\n"); - mIsConnectionActive = false; + Logger::log("Server Max Player Size: %d\n", initPacket->maxPlayers); + + maxPuppets = initPacket->maxPlayers - 1; + } else { + Logger::log("First Packet was not Init!\n"); + mIsConnectionActive = false; + } + + free(curPacket); + waitingForInitPacket = false; } - free(curPacket); - } else { Logger::log("Recieve failed! Stopping Connection.\n"); mIsConnectionActive = false; + waitingForInitPacket = false; } - - break; } } diff --git a/source/server/SocketBase.cpp b/source/server/SocketBase.cpp index 4dbe7ac..9ffb93c 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() { diff --git a/source/server/SocketClient.cpp b/source/server/SocketClient.cpp index 041984a..f60952d 100644 --- a/source/server/SocketClient.cpp +++ b/source/server/SocketClient.cpp @@ -82,7 +82,7 @@ bool SocketClient::SEND(Packet *packet) { 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); @@ -115,9 +115,13 @@ bool SocketClient::RECV() { 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; + } } } From 1df21b2a3e6baf27e1f8c93c56916b0236d61348 Mon Sep 17 00:00:00 2001 From: CraftyBoss Date: Thu, 7 Jul 2022 22:36:29 -0700 Subject: [PATCH 31/48] added new headers, puppet actor archive, basic player interaction impl --- include/actors/PuppetActor.h | 3 + include/al/LiveActor/LiveActor.h | 6 +- include/al/sensor/HitSensorKeeper.h | 4 +- include/al/util/LiveActorUtil.h | 2 +- include/al/util/SensorUtil.h | 480 ++++++++++++++++++ .../cameras/CameraVerticalAbsorber2DGalaxy.h | 38 ++ include/rs/util/SensorUtil.h | 6 +- romfs/ObjectData/PuppetActor.szs | Bin 0 -> 3588 bytes source/puppets/PuppetActor.cpp | 25 +- source/puppets/PuppetMain.cpp | 2 +- source/server/Client.cpp | 11 +- 11 files changed, 565 insertions(+), 12 deletions(-) create mode 100644 include/al/util/SensorUtil.h create mode 100644 include/cameras/CameraVerticalAbsorber2DGalaxy.h create mode 100644 romfs/ObjectData/PuppetActor.szs diff --git a/include/actors/PuppetActor.h b/include/actors/PuppetActor.h index e6ed730..c32f93a 100644 --- a/include/actors/PuppetActor.h +++ b/include/actors/PuppetActor.h @@ -33,6 +33,9 @@ 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; void initOnline(PuppetInfo *pupInfo); 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/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/LiveActorUtil.h b/include/al/util/LiveActorUtil.h index ace88f8..fdd1a0b 100644 --- a/include/al/util/LiveActorUtil.h +++ b/include/al/util/LiveActorUtil.h @@ -29,7 +29,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*); 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/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/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/romfs/ObjectData/PuppetActor.szs b/romfs/ObjectData/PuppetActor.szs new file mode 100644 index 0000000000000000000000000000000000000000..75fd89ff8d51f1dd7cd6b5149b42b370cd96b684 GIT binary patch literal 3588 zcmYLMdsq`^)<5!s5rfQ`1O!B3LaeB`8i+0K+9e4fphX>smb%o12qUIk5m2auTaOv|F+b|eTGZ66pvvC$X{ zum*`nz4#+80vQ)7-$hdTuh%ookz6uro+|&UDg(!$vWB`& ztqje)l<-jMNAkBjUzS~&!WmF_HSqz!T$}WnmSgTt2IxYv{ou8~+)t&JQ~8H!++MP5 z95ybjvpVIR8mrxIt*g2>d)0>88eYxYZq^GvX2I&!Ld7Ack<~Hlg^C8}=Qc;V)>MH} z1yR@=S09H*nkXD~I~uC&^CP(1-I8f<^D$y8*B#hh2AL)z_a+&4H%qsYvE=O+3zvLIq2Y^(jtU zuI^DISyq(4*!;8(t20>e!52{g=xfr+PO)i;r8dwsjcZN!Hth@)SgLJx*2aw%PKH)Z zc@uZ9oU3Mak8_ObId}|74%<-moz1a9w{5vyv(eGi-zs_cO5T&wUC$B8i(%cRi)Gt7 zp;oAKuAIrYVpwm=*j^mhhl-Z<(Eb=ecDanWqg?&|pROv^USx7L-ypFrN8(1Z1Ia-o z=c(`>k}r{bkK}$+y0%tuSj=lIf2|hMr-{t64fX&dKW!E0$Ey_N^{}ws?6lc`F;@t6 zLZ058b3z8*Qd!(kyQ;ayxX3<1SAY{rEbDp%BfGGEdA*P;3AMJ~iRDkY*r#m|Y8q;V zY)eg!F0MFJm+JC3R#le(_$yguEs}Lewj%MrisTfMcaRKfI+v@o^fYH7F(6q^Go`ir z5|aH$dS+^!Na)LqSGP`~PV{3MX`vyhpu(d-G|pM-rM-N8^!0u~GUmr{01n9$NQxf? zYev#ZE4d8GzmX^+0OF{g#+r*{5t4E$(7fnI^tiTAfgaf&Bqxx(OY4V*{Td03g^wTs z2~FZ*K~bZ8B+nwTA$frcyOEqk(ud>|Dhxh4WF(VcQJ{=uA(9nHYUqjw$!kb1A^Di5 z@?Rw5#sO&P9yv&OBpJD(2S>IJU1|q?|2VnSyg+iFmfUjBO5h6zHt&>gT{$?sXIto4 z&$eK6==96CE^U4QlG`J>+qf{<(mxr%PT@@^l{6MQxpd+H;aeZkF7e zCHKaVylIQ%ZVzpG^Lxp&Ef7C=!DAGfT&kgChllqa3H@;7?7%DB8dp4jRC?Wm&tvZq z$-NEVdnph*(DI7p-ep(yyfIg|S@QZM&x3Q4*DHCq7-Jutp_@tGW1K%T@G&NO-554> zAs|bhmVpbK23=(_&QrX`b6N7XH{sNylIMctIsLrP?3cWIxJ900pM(yhaTmmo89sXQ zzeAlJk{hkAB>deDFZX|<3X{FJySK=p?z6YLPTlU_zcrxhWv-m|sWt{vX6qO+#NR>sxyz zFRS4qg0nG+)9B{9I*qZaXW0)@p2g|DlbHC{PIjN3~#dUZ%{IWV}fE!6T>BNsIgIM0tA65qakt7{uZ9S^m( z-Gxx|CEcXgjt$&Cbs1EhLv05K5BYb!4Js%dI@dmY-?e`wgt}BI?Y9SBKBKdDy&XFB zFHv&8T(MjItv_YnOZNDIEte(tfsxqN`cskzGmY`xv~hmu3~jlX(`5dm={npW2z1`+ zYGG$cz24nyNnlOC*u9-_UHDVVMU}AA0ZCD%8E@xu zrdGn#WlKQ{YAThwjGikgSy&V$1T-WcdQaC@jNkY2nOhPp;}Nba8Wy;xW-KrAun zo`r<)(2nh)z(yNRx%`GELH;QNVi_$q0=@*T%6A2OaTqqi95NlLmaa*-0c_qt1Vxu0je`{~vZE67f;m?<4s; zl75O?V`Tt}nZDn`FhB$kekx?Uaq7RXvb_^ftvD{%U4bKG9uo?PrGS4Z0Eh>M*DT~zH zHaM(`;Nn1^#O!Bv=}~^mJekt7u2IRj7i4CnNY>_>mP$Ec1loR1bU6Xc;_c` zM8hmFM5F`_C+3Ox3GsPWgqVo6zQ5h{NpX8KSu!yMdc#692p-h zG3SVxs^S9(86VDrzw6Sl8NsFgr^8ATrisrl7$Zkc4QBca#LRS2nJp@F zMWsJSR5EZVGA>w!V&;i?qH?yV{8jpF$_7__MHvrg;4--nud=yIIc72vZAW%h?Q*$Z za8L>&z-MN`J|3=ONfai(pxL(A;;`DdYVAlER&(K+R&Yc>6X9U4dcFTD8|*^m2S^5J z3H^*@0v1ji9ZmkU(J#f)wwe@5~-6&_AoY*tZDM1|Q%elt4lo}mIQR9c2R zN6XkxhwmRp=OR&^_tO#jDcm4NY~{+PoeI zJE@pbx5buw>vJvjYaoW?S#H)lN8*bc>L5q9*mEq-iZ#4!v*$Z3>#WY64VCxiz-6( z!cPn9>j4pYLDKn;nYc#Ps zMXy2Cpi=;-`KlOR5!;|E*_SnuFN@QabbOu_Z=92zU^JK}QIjL4MBX-;Upl3PFH7Pn z3@E-Wns+mcL&fUV16i8qjB$n(UZLe1r}BzRkLlt*HBIB0R96zowreJv$lV2e2k;PJ>rGgqkstm9G|2TpiLd}GVla*UmaPI- z4=kgbBb%H~OGPzg%eKl5u*6;gS9(?PeRL$)F|lQL%6u$C@ToE(d;UiS*_h&^d@*G{ zd5%e7p%QOgCj*Z!Feau&M-ayc38Wvb_a+ApzH3dy>=Vw@@t9#Z}Xl=DBL{Qcd~ L$6e#k&@TTU^jqYl literal 0 HcmV?d00001 diff --git a/source/puppets/PuppetActor.cpp b/source/puppets/PuppetActor.cpp index 20b4b5d..cf1be28 100644 --- a/source/puppets/PuppetActor.cpp +++ b/source/puppets/PuppetActor.cpp @@ -1,3 +1,6 @@ +#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" @@ -31,7 +34,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"; @@ -243,6 +246,26 @@ void PuppetActor::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 void PuppetActor::startAction(const char *actName) { diff --git a/source/puppets/PuppetMain.cpp b/source/puppets/PuppetMain.cpp index d3de1c9..2f60af4 100644 --- a/source/puppets/PuppetMain.cpp +++ b/source/puppets/PuppetMain.cpp @@ -66,7 +66,7 @@ void initPuppetActors(al::Scene *scene, al::ActorInitInfo const &rootInfo, char } // create a debug puppet for testing purposes - // createPuppetActorFromFactory(rootInfo, playerPlacement, true); + createPuppetActorFromFactory(rootInfo, playerPlacement, true); } al::initPlacementObjectMap(scene, rootInfo, listName); // run init for ObjectList after we init our puppet actors diff --git a/source/server/Client.cpp b/source/server/Client.cpp index adfbff8..581b657 100644 --- a/source/server/Client.cpp +++ b/source/server/Client.cpp @@ -3,6 +3,7 @@ #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" @@ -219,7 +220,9 @@ bool Client::startConnection() { bool isNeedSave = false; - if (mServerIP.isEmpty()) { + 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."); mServerIP = "0.0.0.0"; @@ -227,7 +230,7 @@ bool Client::startConnection() { isNeedSave = true; } - if (!mServerPort) { + if (!mServerPort || isOverride) { mKeyboard->setHeaderText(u"Save File does not contain a port!"); mKeyboard->setSubText(u"Please set a Server Port Below."); mServerPort = 1027; @@ -585,7 +588,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; @@ -1016,7 +1019,7 @@ void Client::disconnectPlayer(PlayerDC *packet) { PuppetInfo* curInfo = findPuppetInfo(packet->mUserID, false); - if (!curInfo) { + if (!curInfo || !curInfo->isConnected) { return; } From 88de1dcecf9c89674e7002d0b20ac375d2510775 Mon Sep 17 00:00:00 2001 From: CraftyBoss Date: Fri, 8 Jul 2022 01:02:28 -0700 Subject: [PATCH 32/48] shift to sead singleton for Client, new custom heap for Client usage --- include/actors/PuppetActor.h | 10 ++++-- include/puppets/PuppetHolder.hpp | 4 ++- include/server/Client.hpp | 15 ++++---- source/layouts/NameTag.cpp | 2 +- source/main.cpp | 14 ++++---- source/puppets/PuppetActor.cpp | 3 +- source/puppets/PuppetHolder.cpp | 41 ++++++++++++++++++++- source/puppets/PuppetMain.cpp | 2 +- source/server/Client.cpp | 62 ++++++++++++++++---------------- 9 files changed, 101 insertions(+), 52 deletions(-) diff --git a/include/actors/PuppetActor.h b/include/actors/PuppetActor.h index c32f93a..3f88254 100644 --- a/include/actors/PuppetActor.h +++ b/include/actors/PuppetActor.h @@ -35,7 +35,13 @@ class PuppetActor : public al::LiveActor { 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 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); @@ -50,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(); 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/server/Client.hpp b/include/server/Client.hpp index 6fc062e..651dd72 100644 --- a/include/server/Client.hpp +++ b/include/server/Client.hpp @@ -32,6 +32,7 @@ #include "game/GameData/GameDataHolderWriter.h" #include "game/GameData/GameDataFunction.h" +#include "heap/seadHeap.h" #include "layouts/HideAndSeekIcon.h" #include "rs/util.hpp" @@ -76,10 +77,10 @@ struct UIDIndexNode { class HideAndSeekIcon; class Client { - public: - static Client *sInstance; + SEAD_SINGLETON_DISPOSER(Client) - Client(int bufferSize); + public: + Client(); void init(al::LayoutInitInfo const &initInfo, GameDataHolderAccessor holder); @@ -145,7 +146,7 @@ class Client { static GameModeConfigMenu* tryCreateModeMenu(); - static int getMaxPlayerCount() { return sInstance ? sInstance->maxPuppets : 10;} + static int getMaxPlayerCount() { return sInstance ? sInstance->maxPuppets + 1 : 10;} static void toggleCurrentMode(); @@ -204,8 +205,6 @@ class Client { // public for debug purposes SocketClient *mSocket; - int maxPuppets; - private: void updatePlayerInfo(PlayerInf *packet); void updateHackCapInfo(HackCapInf *packet); @@ -287,6 +286,8 @@ class Client { u8 mScenario = 0; + sead::Heap *mHeap = nullptr; // Heap that Client::sInstance was created in + // --- Mode Info --- GameModeBase* mCurMode = nullptr; @@ -299,6 +300,8 @@ class Client { // --- Puppet Info --- + int maxPuppets = 9; // default max player count is 10, so default max puppets will be 9 + PuppetInfo *mPuppetInfoArr[MAXPUPINDEX]; PuppetHolder *mPuppetHolder = nullptr; 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 92917d3..871878d 100644 --- a/source/main.cpp +++ b/source/main.cpp @@ -88,9 +88,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("nn::socket::GetLastErrno: 0x%x\n", Client::sInstance->mSocket->socket_errno); - 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; @@ -283,7 +283,7 @@ ulong constructHook() { // hook for constructing anything we need to globally b : [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()); return 0x20; } @@ -294,7 +294,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, mainSeq->mGameDataHolder); + Client::instance()->init(lytInfo, mainSeq->mGameDataHolder); return GameDataFunction::isPlayDemoOpening(mainSeq->mGameDataHolder); } @@ -344,9 +344,9 @@ bool hakoniwaSequenceHook(HakoniwaSequence* sequence) { if (al::isPadTriggerRight(-1)) debugPuppetIndex++; if(debugPuppetIndex < 0) { - debugPuppetIndex = playBufSize - 2; + debugPuppetIndex = Client::getMaxPlayerCount() - 2; } - if (debugPuppetIndex >= playBufSize - 1) + if (debugPuppetIndex >= Client::getMaxPlayerCount() - 1) debugPuppetIndex = 0; } diff --git a/source/puppets/PuppetActor.cpp b/source/puppets/PuppetActor.cpp index cf1be28..1a5fdb2 100644 --- a/source/puppets/PuppetActor.cpp +++ b/source/puppets/PuppetActor.cpp @@ -210,7 +210,7 @@ void PuppetActor::control() { } void PuppetActor::makeActorAlive() { - + al::LiveActor *curModel = getCurrentModel(); if (al::isDead(curModel)) { @@ -227,6 +227,7 @@ void PuppetActor::makeActorAlive() { } al::LiveActor::makeActorAlive(); + } } diff --git a/source/puppets/PuppetHolder.cpp b/source/puppets/PuppetHolder.cpp index 5fe34a9..d650478 100644 --- a/source/puppets/PuppetHolder.cpp +++ b/source/puppets/PuppetHolder.cpp @@ -1,13 +1,52 @@ #include "puppets/PuppetHolder.hpp" +#include +#include "actors/PuppetActor.h" #include "al/util.hpp" +#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()) { diff --git a/source/puppets/PuppetMain.cpp b/source/puppets/PuppetMain.cpp index 2f60af4..c485ec2 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 581b657..7d2ce93 100644 --- a/source/server/Client.cpp +++ b/source/server/Client.cpp @@ -12,6 +12,9 @@ #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" @@ -35,7 +38,7 @@ #include "server/HideAndSeekConfigMenu.hpp" #include "server/HideAndSeekMode.hpp" -Client* Client::sInstance; +SEAD_SINGLETON_DISPOSER_IMPL(Client) typedef void (Client::*ClientThreadFunc)(void); @@ -44,21 +47,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 < maxPuppets; i++) { mPuppetInfoArr[i] = new PuppetInfo(); @@ -83,6 +86,7 @@ Client::Client(int bufferSize) { nn::account::Nickname playerName; nn::account::GetNickname(&playerName, mUserID); + Logger::setLogName(playerName.name); // set Debug logger name to player name mUsername = playerName.name; @@ -90,13 +94,8 @@ Client::Client(int bufferSize) { 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 - mServerMode = GameMode::HIDEANDSEEK; // temp for testing - - if(!sInstance) { - sInstance = this; - } } /** @@ -106,7 +105,7 @@ Client::Client(int bufferSize) { */ 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."); @@ -115,6 +114,7 @@ void Client::init(al::LayoutInitInfo const &initInfo, GameDataHolderAccessor hol mHolder = holder; StartThreads(); + } /** @@ -352,7 +352,7 @@ void Client::readFunc() { 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(); @@ -1094,7 +1094,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); } } @@ -1106,8 +1106,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; } @@ -1121,8 +1121,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; } @@ -1135,8 +1135,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; } @@ -1148,8 +1148,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; } @@ -1162,9 +1162,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); @@ -1317,8 +1317,8 @@ void Client::clearArrays() { * @return PuppetInfo* */ PuppetInfo *Client::getDebugPuppetInfo() { - if(Client::sInstance) { - return &Client::sInstance->mDebugPuppetInfo; + if(sInstance) { + return &sInstance->mDebugPuppetInfo; }else { return nullptr; } @@ -1330,8 +1330,8 @@ 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; } From 4f2bb984f2abb6d77316444467398710c54e64d2 Mon Sep 17 00:00:00 2001 From: CraftyBoss Date: Fri, 8 Jul 2022 15:09:04 -0700 Subject: [PATCH 33/48] begin work on join/disconnect particle effect, fix index oob error --- include/actors/PuppetActor.h | 10 ++++++---- include/main.hpp | 2 -- source/main.cpp | 14 ++++++-------- source/puppets/PuppetActor.cpp | 32 +++++++++++++++++--------------- source/puppets/PuppetHolder.cpp | 9 +++++++-- source/server/Client.cpp | 6 +++--- 6 files changed, 39 insertions(+), 34 deletions(-) diff --git a/include/actors/PuppetActor.h b/include/actors/PuppetActor.h index 3f88254..b10868b 100644 --- a/include/actors/PuppetActor.h +++ b/include/actors/PuppetActor.h @@ -66,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/main.hpp b/include/main.hpp index 7b82e89..548f2f7 100644 --- a/include/main.hpp +++ b/include/main.hpp @@ -51,8 +51,6 @@ #include "Keyboard.hpp" #include "server/DeltaTime.hpp" -static const int playBufSize = 8; - static bool isInGame = false; static bool debugMode = false; diff --git a/source/main.cpp b/source/main.cpp index 871878d..74b9010 100644 --- a/source/main.cpp +++ b/source/main.cpp @@ -167,12 +167,6 @@ void drawMainHook(HakoniwaSequence *curSequence, sead::Viewport *viewport, sead: 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)); } @@ -370,9 +364,13 @@ bool hakoniwaSequenceHook(HakoniwaSequence* sequence) { } 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; diff --git a/source/puppets/PuppetActor.cpp b/source/puppets/PuppetActor.cpp index 1a5fdb2..2478571 100644 --- a/source/puppets/PuppetActor.cpp +++ b/source/puppets/PuppetActor.cpp @@ -1,4 +1,5 @@ #include +#include #include "al/util/SensorUtil.h" #include "rs/util/SensorUtil.h" #include "server/Client.hpp" @@ -217,19 +218,15 @@ void PuppetActor::makeActorAlive() { 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() { @@ -240,11 +237,9 @@ void PuppetActor::makeActorDead() { curModel->makeActorDead(); } - if (!al::isDead(this)) { - mPuppetCap->makeActorDead(); // make sure we kill the cap puppet along with regular puppet - - al::LiveActor::makeActorDead(); - } + mPuppetCap->makeActorDead(); + + al::LiveActor::makeActorDead(); } void PuppetActor::attackSensor(al::HitSensor* source, al::HitSensor* target) { @@ -403,3 +398,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 d650478..f730c7b 100644 --- a/source/puppets/PuppetHolder.cpp +++ b/source/puppets/PuppetHolder.cpp @@ -2,6 +2,7 @@ #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" @@ -78,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/server/Client.cpp b/source/server/Client.cpp index 7d2ce93..2380692 100644 --- a/source/server/Client.cpp +++ b/source/server/Client.cpp @@ -82,13 +82,13 @@ Client::Client() { 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); @@ -1064,7 +1064,7 @@ PuppetInfo* Client::findPuppetInfo(const nn::account::Uid& id, bool isFindAvaila PuppetInfo *firstAvailable = nullptr; - for (size_t i = 0; i < getMaxPlayerCount(); i++) { + for (size_t i = 0; i < getMaxPlayerCount() - 1; i++) { PuppetInfo* curInfo = mPuppetInfoArr[i]; From 3c4a20a6d457efda72c71b34639f3daa773a4a31 Mon Sep 17 00:00:00 2001 From: CraftyBoss Date: Sat, 9 Jul 2022 18:24:00 -0700 Subject: [PATCH 34/48] only save ip/port changes if actually changed, reconnect fixes --- include/Keyboard.hpp | 8 +- include/SocketBase.hpp | 2 +- .../StageSceneStateServerConfig.hpp | 2 + include/nn/swkbd/swkbd.h | 53 ++++---- include/server/Client.hpp | 19 ++- source/Keyboard.cpp | 11 +- source/puppets/PuppetMain.cpp | 2 +- source/server/Client.cpp | 121 +++++++++++++----- source/server/SocketBase.cpp | 8 +- source/server/SocketClient.cpp | 14 +- source/states/StageSceneStateServerConfig.cpp | 68 +++++++--- 11 files changed, 205 insertions(+), 103 deletions(-) diff --git a/include/Keyboard.hpp b/include/Keyboard.hpp index 88d1098..f4c5349 100644 --- a/include/Keyboard.hpp +++ b/include/Keyboard.hpp @@ -25,6 +25,8 @@ class Keyboard { return nullptr; }; + bool isKeyboardCancelled() const { return mIsCancelled; } + bool isThreadDone() { return mThread->isDone(); } void setHeaderText(const char16_t* text) { mHeaderText = text; } @@ -35,13 +37,13 @@ class Keyboard { al::AsyncFunctorThread* mThread; nn::swkbd::String mResultString; - bool mIsDoneKeyboard; - sead::FixedSafeString<0x10> 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; diff --git a/include/SocketBase.hpp b/include/SocketBase.hpp index 2437039..02feca5 100644 --- a/include/SocketBase.hpp +++ b/include/SocketBase.hpp @@ -16,7 +16,7 @@ class SocketBase { const char *getStateChar(); u8 getLogState(); - s32 getSocket(); + s32 getFd(); void set_sock_flags(int flags); diff --git a/include/game/StageScene/StageSceneStateServerConfig.hpp b/include/game/StageScene/StageSceneStateServerConfig.hpp index f3c3469..95d4c28 100644 --- a/include/game/StageScene/StageSceneStateServerConfig.hpp +++ b/include/game/StageScene/StageSceneStateServerConfig.hpp @@ -45,6 +45,7 @@ class StageSceneStateServerConfig : public al::HostStateBase, public void exeGamemodeConfig(); void exeGamemodeSelect(); void exeSaveData(); + void exeConnectError(); void endSubMenu(); @@ -84,4 +85,5 @@ namespace { 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/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/server/Client.hpp b/include/server/Client.hpp index 651dd72..7682263 100644 --- a/include/server/Client.hpp +++ b/include/server/Client.hpp @@ -32,6 +32,7 @@ #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" @@ -180,8 +181,8 @@ class Client { static void updateShines(); - static void openKeyboardIP(); - static void openKeyboardPort(); + static bool openKeyboardIP(); + static bool openKeyboardPort(); static GameModeInfoBase* getModeInfo() { return sInstance ? sInstance->mModeInfo : nullptr; @@ -196,7 +197,15 @@ class Client { static bool isModeActive() { return sInstance ? sInstance->mIsModeActive : false; } - static bool isSelectedMode(GameMode mode) { return sInstance ? sInstance->mCurMode->getMode() == mode: false; } + static bool isSelectedMode(GameMode mode) { + return sInstance ? sInstance->mCurMode->getMode() == mode : false; + } + + static void showConnect(); + + static void showConnectError(const char16_t* msg); + + static void hideConnect(); void resetCollectedShines(); @@ -227,8 +236,6 @@ 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; @@ -286,7 +293,7 @@ class Client { u8 mScenario = 0; - sead::Heap *mHeap = nullptr; // Heap that Client::sInstance was created in + sead::FrameHeap *mHeap = nullptr; // Custom FrameHeap used for all Client related memory // --- Mode Info --- diff --git a/source/Keyboard.cpp b/source/Keyboard.cpp index 047e7ec..63dfa25 100644 --- a/source/Keyboard.cpp +++ b/source/Keyboard.cpp @@ -15,14 +15,10 @@ 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); @@ -44,10 +40,9 @@ 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, KeyboardSetup setupFunc) { diff --git a/source/puppets/PuppetMain.cpp b/source/puppets/PuppetMain.cpp index c485ec2..e222547 100644 --- a/source/puppets/PuppetMain.cpp +++ b/source/puppets/PuppetMain.cpp @@ -66,7 +66,7 @@ void initPuppetActors(al::Scene *scene, al::ActorInitInfo const &rootInfo, char } // create a debug puppet for testing purposes - createPuppetActorFromFactory(rootInfo, playerPlacement, true); + // createPuppetActorFromFactory(rootInfo, playerPlacement, true); } al::initPlacementObjectMap(scene, rootInfo, listName); // run init for ObjectList after we init our puppet actors diff --git a/source/server/Client.cpp b/source/server/Client.cpp index 2380692..6059bc1 100644 --- a/source/server/Client.cpp +++ b/source/server/Client.cpp @@ -30,6 +30,7 @@ #include "packets/PlayerConnect.h" #include "packets/PlayerDC.h" #include "packets/TagInf.h" +#include "prim/seadSafeString.h" #include "puppets/PuppetInfo.h" #include "sead/basis/seadRawPrint.h" #include "sead/math/seadQuat.h" @@ -61,7 +62,7 @@ Client::Client() { mPuppetHolder = new PuppetHolder(maxPuppets); - for (size_t i = 0; i < maxPuppets; i++) + for (size_t i = 0; i < MAXPUPINDEX; i++) { mPuppetInfoArr[i] = new PuppetInfo(); @@ -70,8 +71,6 @@ Client::Client() { strcpy(mDebugPuppetInfo.puppetName, "PuppetDebug"); - puppetPlayerID.fill({0}); - mConnectCount = 0; curCollectedShines.fill(-1); @@ -115,6 +114,8 @@ void Client::init(al::LayoutInitInfo const &initInfo, GameDataHolderAccessor hol StartThreads(); + Logger::log("Remaining Heap Size: %d\n", mHeap->getFreeSize()); + } /** @@ -190,8 +191,6 @@ void Client::restartConnection() { Logger::log("Sucessfully Closed Socket.\n"); } - sInstance->puppetPlayerID.fill({0,0}); - sInstance->mConnectCount = 0; sInstance->mIsConnectionActive = sInstance->mSocket->init(sInstance->mServerIP.cstr(), sInstance->mServerPort).isSuccess(); @@ -203,7 +202,14 @@ void Client::restartConnection() { PlayerConnect initPacket; initPacket.mUserID = sInstance->mUserID; strcpy(initPacket.clientName, sInstance->mUsername.cstr()); - initPacket.conType = ConnectionTypes::RECONNECT; + + if (sInstance->isFirstConnect) { + initPacket.conType = ConnectionTypes::INIT; + sInstance->isFirstConnect = false; + } else { + initPacket.conType = ConnectionTypes::RECONNECT; + } + sInstance->mSocket->SEND(&initPacket); } else { @@ -280,50 +286,58 @@ bool Client::startConnection() { /** * @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; } // 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::ModeNumeric; - config.leftOptionalSymbolKey = '.'; - config.textMaxLength = 15; - config.textMinLength = 1; - config.isUseUtf8 = true; - config.inputFormMode = nn::swkbd::InputFormMode::OneLine; - }); + sInstance->mKeyboard->openKeyboard( + sInstance->mServerIP.cstr(), [](nn::swkbd::KeyboardConfig& config) { + config.keyboardMode = nn::swkbd::KeyboardMode::ModeNumeric; + config.leftOptionalSymbolKey = '.'; + config.textMaxLength = 15; + config.textMinLength = 1; + config.isUseUtf8 = true; + config.inputFormMode = nn::swkbd::InputFormMode::OneLine; + }); + + sead::FixedSafeString<0x10> 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. */ -void Client::openKeyboardPort() { +bool Client::openKeyboardPort() { if (!sInstance) { Logger::log("Static Instance is null!\n"); - return; + 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) { + + sInstance->mKeyboard->openKeyboard(buf, [](nn::swkbd::KeyboardConfig& config) { config.keyboardMode = nn::swkbd::KeyboardMode::ModeNumeric; config.textMaxLength = 5; config.textMinLength = 2; @@ -331,13 +345,20 @@ void Client::openKeyboardPort() { config.inputFormMode = nn::swkbd::InputFormMode::OneLine; }); + int prevPort = sInstance->mServerPort; + while (true) { if (sInstance->mKeyboard->isThreadDone()) { - sInstance->mServerPort = ::atoi(sInstance->mKeyboard->getResult()); + 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; } /** @@ -380,6 +401,7 @@ void Client::readFunc() { if (isFirstConnect) { initPacket.conType = ConnectionTypes::INIT; + isFirstConnect = false; } else { initPacket.conType = ConnectionTypes::RECONNECT; } @@ -390,8 +412,6 @@ void Client::readFunc() { mConnectionWait->tryEnd(); - isFirstConnect = false; - while(mIsConnectionActive) { if (mSocket->getLogState() != SOCKET_LOG_CONNECTED) { @@ -411,8 +431,16 @@ void Client::readFunc() { 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 { @@ -421,7 +449,6 @@ void Client::readFunc() { 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)); - } if(mSocket->RECV()) { // will block until a packet has been recieved, or socket disconnected @@ -1511,3 +1538,39 @@ GameModeConfigMenu* Client::tryCreateModeMenu() { return nullptr; } } + + + +void Client::showConnectError(const char16_t* msg) { + if (!sInstance) + return; + + 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(); +} \ No newline at end of file diff --git a/source/server/SocketBase.cpp b/source/server/SocketBase.cpp index 4dbe7ac..649a4fe 100644 --- a/source/server/SocketBase.cpp +++ b/source/server/SocketBase.cpp @@ -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 041984a..9dd5d97 100644 --- a/source/server/SocketClient.cpp +++ b/source/server/SocketClient.cpp @@ -66,6 +66,8 @@ nn::Result SocketClient::init(const char* ip, u16 port) { this->socket_log_state = SOCKET_LOG_CONNECTED; + Logger::log("Socket fd: %d\n", socket_log_socket); + return result; } @@ -126,7 +128,7 @@ bool SocketClient::RECV() { int fullSize = header->mPacketSize + sizeof(Packet); - if (header->mType != PacketType::UNKNOWN && fullSize <= MAXPACKSIZE && fullSize > 0) { + if (header->mType != PacketType::UNKNOWN && fullSize <= MAXPACKSIZE && fullSize > 0 && valread == sizeof(Packet)) { if (header->mType != PLAYERINF && header->mType != HACKCAPINF) Logger::log("Received packet (from %02X%02X): %s\n", @@ -163,6 +165,8 @@ bool SocketClient::RECV() { free(packetBuf); } } + } else { + Logger::log("Failed to aquire valid data! Packet Type: %d Full Packet Size %d valread size: %d", header->mType, fullSize, valread); } return true; @@ -194,5 +198,11 @@ bool SocketClient::closeSocket() { Logger::log("Closing Socket.\n"); - return SocketBase::closeSocket(); + bool result = false; + + if (!(result = SocketBase::closeSocket())) { + Logger::log("Failed to close socket!\n"); + } + + return result; } \ No newline at end of file diff --git a/source/states/StageSceneStateServerConfig.cpp b/source/states/StageSceneStateServerConfig.cpp index 642db84..c4eeb51 100644 --- a/source/states/StageSceneStateServerConfig.cpp +++ b/source/states/StageSceneStateServerConfig.cpp @@ -170,10 +170,15 @@ void StageSceneStateServerConfig::exeOpenKeyboardIP() { Client::getKeyboard()->setHeaderText(u"Set a Server IP Below."); Client::getKeyboard()->setSubText(u""); - Client::openKeyboardIP(); - // anything that happens after this will be ran after the keyboard closes + + bool isSave = Client::openKeyboardIP(); // anything that happens after this will be ran after the keyboard closes + al::startHitReaction(mCurrentMenu, "リセット", 0); - al::setNerve(this, &nrvStageSceneStateServerConfigSaveData); + + if(isSave) + al::setNerve(this, &nrvStageSceneStateServerConfigSaveData); + else + al::setNerve(this, &nrvStageSceneStateServerConfigMainMenu); } } @@ -184,21 +189,36 @@ void StageSceneStateServerConfig::exeOpenKeyboardPort() { Client::getKeyboard()->setHeaderText(u"Set a Server Port Below."); Client::getKeyboard()->setSubText(u""); - Client::openKeyboardPort(); - // anything that happens after this will be ran after the keyboard closes - al::setNerve(this, &nrvStageSceneStateServerConfigSaveData); + + 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::showConnect(); + Client::restartConnection(); } if (Client::isSocketActive()) { + + Client::hideConnect(); + al::startHitReaction(mCurrentMenu, "リセット", 0); + al::setNerve(this, &nrvStageSceneStateServerConfigMainMenu); + } else { + al::setNerve(this, &nrvStageSceneStateServerConfigConnectError); } } @@ -237,6 +257,30 @@ void StageSceneStateServerConfig::exeGamemodeSelect() { } } +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(); @@ -291,17 +335,6 @@ void StageSceneStateServerConfig::subMenuUpdate() { } } -void StageSceneStateServerConfig::exeSaveData() { - - if (al::isFirstStep(this)) { - SaveDataAccessFunction::startSaveDataWrite(mGameDataHolder); - } - - if (SaveDataAccessFunction::updateSaveDataAccess(mGameDataHolder, false)) { - al::startHitReaction(mCurrentMenu, "リセット", 0); - al::setNerve(this, &nrvStageSceneStateServerConfigMainMenu); - } -} namespace { NERVE_IMPL(StageSceneStateServerConfig, MainMenu) @@ -311,4 +344,5 @@ 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 From b3b49bd5479ffd8f9ec8deb582ba2325d396d2ad Mon Sep 17 00:00:00 2001 From: "Robin C. Ladiges" Date: Sun, 10 Jul 2022 08:13:28 +0200 Subject: [PATCH 35/48] on invalid IPv4 addresses, assume it's a hostname and do a DNS lookup Enable the full keyboard to enter non-numbers and increase max length from 15 to 50 for longer hostnames. I know FQDNs can be longer than 50 characters, but that's less common (and painful to type on the Switch). --- include/Keyboard.hpp | 5 ++-- include/nn/socket.h | 11 +++++++++ include/server/Client.hpp | 4 ++-- include/server/SocketClient.hpp | 9 +++++++- include/types.h | 4 ++++ source/server/Client.cpp | 7 +++--- source/server/SocketClient.cpp | 41 +++++++++++++++++++++++++-------- 7 files changed, 61 insertions(+), 20 deletions(-) diff --git a/include/Keyboard.hpp b/include/Keyboard.hpp index f4c5349..4553645 100644 --- a/include/Keyboard.hpp +++ b/include/Keyboard.hpp @@ -7,7 +7,6 @@ #include "nn/swkbd/swkbd.h" #include "logger.hpp" -#include "sead/prim/seadSafeString.h" typedef void (*KeyboardSetup)(nn::swkbd::KeyboardConfig&); @@ -37,7 +36,7 @@ class Keyboard { al::AsyncFunctorThread* mThread; nn::swkbd::String mResultString; - sead::FixedSafeString<0x10> mInitialText; + hostname mInitialText; KeyboardSetup mSetupFunc; const char16_t *mHeaderText = u"Enter Server IP Here!"; @@ -51,4 +50,4 @@ class Keyboard { int mTextCheckSize; char* mCustomizeDicBuf; int mCustomizeDicSize; -}; \ No newline at end of file +}; diff --git a/include/nn/socket.h b/include/nn/socket.h index b308e33..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,6 +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/server/Client.hpp b/include/server/Client.hpp index 7682263..a01749d 100644 --- a/include/server/Client.hpp +++ b/include/server/Client.hpp @@ -259,7 +259,7 @@ class Client { Keyboard* mKeyboard = nullptr; // keyboard for setting server IP - sead::FixedSafeString<0x10> mServerIP; + hostname mServerIP; int mServerPort = 0; @@ -314,4 +314,4 @@ class Client { PuppetHolder *mPuppetHolder = nullptr; PuppetInfo mDebugPuppetInfo; -}; \ No newline at end of file +}; diff --git a/include/server/SocketClient.hpp b/include/server/SocketClient.hpp index 128af87..42dad30 100644 --- a/include/server/SocketClient.hpp +++ b/include/server/SocketClient.hpp @@ -33,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/types.h b/include/types.h index 397a50c..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; @@ -41,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, diff --git a/source/server/Client.cpp b/source/server/Client.cpp index 6059bc1..9a339ef 100644 --- a/source/server/Client.cpp +++ b/source/server/Client.cpp @@ -30,7 +30,6 @@ #include "packets/PlayerConnect.h" #include "packets/PlayerDC.h" #include "packets/TagInf.h" -#include "prim/seadSafeString.h" #include "puppets/PuppetInfo.h" #include "sead/basis/seadRawPrint.h" #include "sead/math/seadQuat.h" @@ -300,13 +299,13 @@ bool Client::openKeyboardIP() { sInstance->mServerIP.cstr(), [](nn::swkbd::KeyboardConfig& config) { config.keyboardMode = nn::swkbd::KeyboardMode::ModeNumeric; config.leftOptionalSymbolKey = '.'; - config.textMaxLength = 15; + config.textMaxLength = MAX_HOSTNAME_LENGTH; config.textMinLength = 1; config.isUseUtf8 = true; config.inputFormMode = nn::swkbd::InputFormMode::OneLine; }); - sead::FixedSafeString<0x10> prevIp = sInstance->mServerIP; + hostname prevIp = sInstance->mServerIP; while (true) { if (sInstance->mKeyboard->isThreadDone()) { @@ -1573,4 +1572,4 @@ void Client::hideConnect() { return; sInstance->mConnectionWait->tryEnd(); -} \ No newline at end of file +} diff --git a/source/server/SocketClient.cpp b/source/server/SocketClient.cpp index 9dd5d97..1d06879 100644 --- a/source/server/SocketClient.cpp +++ b/source/server/SocketClient.cpp @@ -11,11 +11,10 @@ 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 }; Logger::log("SocketClient::init: %s:%d sock %s\n", ip, port, getStateChar()); @@ -34,18 +33,20 @@ nn::Result SocketClient::init(const char* ip, u16 port) { return -1; } #endif - + 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); @@ -205,4 +206,24 @@ bool SocketClient::closeSocket() { } return result; -} \ No newline at end of file +} + +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; +} From dd4f3202ae85b31eb79ddcc9a5d9a15bbb7618d9 Mon Sep 17 00:00:00 2001 From: "Robin C. Ladiges" Date: Mon, 18 Jul 2022 03:30:14 +0200 Subject: [PATCH 36/48] change default IP This might otherwise cause confusion with the server.json setting, which should stay at 0.0.0.0. 127.0.0.1 might at least work with emulators running on the same PC out of the box. Whereas 0.0.0.0 should be invalid (except on some systems that map it to localhost). --- source/hooks.cpp | 4 ++-- source/server/Client.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/source/hooks.cpp b/source/hooks.cpp index 3fc0fad..da9adf0 100644 --- a/source/hooks.cpp +++ b/source/hooks.cpp @@ -44,7 +44,7 @@ void saveWriteHook(al::ByamlWriter* saveByml) { if (serverIP) { saveByml->addString("ServerIP", serverIP); } else { - saveByml->addString("ServerIP", "0.0.0.0"); + saveByml->addString("ServerIP", "127.0.0.1"); } if (serverPort) { @@ -168,4 +168,4 @@ bool borderPullBackHook(WorldEndBorderKeeper* thisPtr) { } return isFirstStep; -} \ No newline at end of file +} diff --git a/source/server/Client.cpp b/source/server/Client.cpp index 9a339ef..3a72bf1 100644 --- a/source/server/Client.cpp +++ b/source/server/Client.cpp @@ -230,7 +230,7 @@ bool Client::startConnection() { if (mServerIP.isEmpty() || isOverride) { mKeyboard->setHeaderText(u"Save File does not contain an IP!"); mKeyboard->setSubText(u"Please set a Server IP Below."); - mServerIP = "0.0.0.0"; + mServerIP = "127.0.0.1"; Client::openKeyboardIP(); isNeedSave = true; } From ce5b799593082a0eab5fd7482d49dfb042ef9aac Mon Sep 17 00:00:00 2001 From: "Robin C. Ladiges" Date: Mon, 18 Jul 2022 03:31:02 +0200 Subject: [PATCH 37/48] change KeyboardMode from Numeric to ASCII --- source/server/Client.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/source/server/Client.cpp b/source/server/Client.cpp index 3a72bf1..41881cc 100644 --- a/source/server/Client.cpp +++ b/source/server/Client.cpp @@ -297,8 +297,7 @@ bool Client::openKeyboardIP() { // 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::ModeNumeric; - config.leftOptionalSymbolKey = '.'; + config.keyboardMode = nn::swkbd::KeyboardMode::ModeASCII; config.textMaxLength = MAX_HOSTNAME_LENGTH; config.textMinLength = 1; config.isUseUtf8 = true; From 34691affb0d0fa3e42f39e524d946b5b83b782b9 Mon Sep 17 00:00:00 2001 From: Sanae Date: Sun, 7 Aug 2022 15:42:56 -0600 Subject: [PATCH 38/48] Overhaul gamemode management --- MakefileNSO | 4 +- include/al/util.hpp | 3 + .../StageSceneStateServerConfig.hpp | 15 +- include/server/Client.hpp | 58 +------ include/server/gamemode/GameModeBase.hpp | 4 +- .../gamemode/GameModeConfigMenuFactory.hpp | 38 +++++ include/server/gamemode/GameModeFactory.hpp | 9 +- include/server/gamemode/GameModeInfoBase.hpp | 14 +- include/server/gamemode/GameModeManager.hpp | 59 ++++++++ .../{ => hns}/HideAndSeekConfigMenu.hpp | 2 +- include/server/{ => hns}/HideAndSeekMode.hpp | 6 +- source/hooks.cpp | 18 +-- source/layouts/HideAndSeekIcon.cpp | 4 +- source/main.cpp | 17 +-- source/puppets/PuppetActor.cpp | 7 +- source/server/Client.cpp | 143 ++---------------- source/server/gamemode/GameModeManager.cpp | 92 +++++++++++ source/server/{ => hns}/GameModeTimer.cpp | 83 +++++----- .../{ => hns}/HideAndSeekConfigMenu.cpp | 11 +- source/server/{ => hns}/HideAndSeekMode.cpp | 30 ++-- source/states/StageSceneStateServerConfig.cpp | 31 ++-- 21 files changed, 348 insertions(+), 300 deletions(-) create mode 100644 include/server/gamemode/GameModeConfigMenuFactory.hpp create mode 100644 include/server/gamemode/GameModeManager.hpp rename include/server/{ => hns}/HideAndSeekConfigMenu.hpp (90%) rename include/server/{ => hns}/HideAndSeekMode.hpp (90%) create mode 100644 source/server/gamemode/GameModeManager.cpp rename source/server/{ => hns}/GameModeTimer.cpp (59%) rename source/server/{ => hns}/HideAndSeekConfigMenu.cpp (76%) rename source/server/{ => hns}/HideAndSeekMode.cpp (83%) diff --git a/MakefileNSO b/MakefileNSO index a301b90..3f8ea04 100644 --- a/MakefileNSO +++ b/MakefileNSO @@ -32,7 +32,7 @@ include $(DEVKITPRO)/libnx/switch_rules #--------------------------------------------------------------------------------- TARGET ?= $(notdir $(CURDIR))$(SMOVER) BUILD ?= build$(SMOVER) -SOURCES := source/sead/time source/sead source/puppets source/server source/layouts source/states source/cameras source/nx source +SOURCES := source/sead/time source/sead source/puppets source/server/hns source/server/gamemode source/server source/layouts source/states source/cameras source/nx source DATA := data INCLUDES := include include/sead @@ -46,7 +46,7 @@ CFLAGS := -g -Wall -ffunction-sections \ CFLAGS += $(INCLUDE) -D__SWITCH__ -DSMOVER=$(SMOVER) -O3 -DNNSDK -DSWITCH -DBUILDVERSTR=$(BUILDVERSTR) -DBUILDVER=$(BUILDVER) -DDEBUGLOG=$(DEBUGLOG) -DSERVERIP=$(SERVERIP) -DEMU=$(EMU) -CXXFLAGS := $(CFLAGS) -fno-rtti -fomit-frame-pointer -fno-exceptions -fno-asynchronous-unwind-tables -fno-unwind-tables -std=gnu++20 +CXXFLAGS := $(CFLAGS) -Wno-invalid-offsetof -Wno-volatile -fno-rtti -fomit-frame-pointer -fno-exceptions -fno-asynchronous-unwind-tables -fno-unwind-tables -std=gnu++20 ASFLAGS := -g $(ARCH) LDFLAGS = -specs=../switch.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map) -Wl,--version-script=$(TOPDIR)/exported.txt -Wl,-init=__custom_init -Wl,-fini=__custom_fini -nostdlib diff --git a/include/al/util.hpp b/include/al/util.hpp index 3ef495d..2735fc1 100644 --- a/include/al/util.hpp +++ b/include/al/util.hpp @@ -72,6 +72,9 @@ namespace al PlayerActorBase *tryGetPlayerActor(al::PlayerHolder const *, int); sead::Heap *getCurrentHeap(void); + sead::Heap* getStationedHeap(); + sead::Heap* getSequenceHeap(); + sead::Heap* getSceneHeap(); al::Projection *getProjection(al::IUseCamera const *, int); diff --git a/include/game/StageScene/StageSceneStateServerConfig.hpp b/include/game/StageScene/StageSceneStateServerConfig.hpp index 95d4c28..8956bdc 100644 --- a/include/game/StageScene/StageSceneStateServerConfig.hpp +++ b/include/game/StageScene/StageSceneStateServerConfig.hpp @@ -17,6 +17,7 @@ #include "logger.hpp" #include "server/gamemode/GameModeConfigMenu.hpp" +#include "server/gamemode/GameModeConfigMenuFactory.hpp" class FooterParts; @@ -65,14 +66,18 @@ class StageSceneStateServerConfig : public al::HostStateBase, public // Root Page, contains buttons for gamemode config, server reconnecting, and server ip address changing SimpleLayoutMenu* mMainOptions = nullptr; CommonVerticalList *mMainOptionsList = nullptr; - // Sub-Page for Mode configuration, has buttons for selecting current gamemode and configuring currently selected mode (if no mode is chosen, button will not do anything) - SimpleLayoutMenu* mGamemodeConfig = nullptr; - CommonVerticalList* mGameModeConfigList = nullptr; // Sub-Page of Mode config, used to select a gamemode for the client to use SimpleLayoutMenu* mModeSelect = nullptr; CommonVerticalList* mModeSelectList = nullptr; - // Controls what shows up in specific gamemode config page - GameModeConfigMenu *mGamemodeConfigMenu = nullptr; + + // Sub-Pages for Mode configuration, has buttons for selecting current gamemode and configuring currently selected mode (if no mode is chosen, button will not do anything) + struct GameModeEntry { + GameModeConfigMenu* mMenu; + SimpleLayoutMenu* mLayout = nullptr; + CommonVerticalList* mList = nullptr; + }; + sead::SafeArray mGamemodeConfigMenus; + GameModeEntry *mGamemodeConfigMenu = nullptr; bool mIsDecideConfig = false; }; diff --git a/include/server/Client.hpp b/include/server/Client.hpp index 7682263..63bfd29 100644 --- a/include/server/Client.hpp +++ b/include/server/Client.hpp @@ -96,8 +96,6 @@ class Client { static bool isNeedUpdateShines(); bool isShineCollected(int shineId); - static void initMode(GameModeInitInfo const &initInfo); - static void sendHackCapInfPacket(const HackCap *hackCap); static void sendPlayerInfPacket(const PlayerActorHakoniwa *player); static void sendGameInfPacket(const PlayerActorHakoniwa *player, GameDataHolderAccessor holder); @@ -110,8 +108,6 @@ class Client { int getCollectedShinesCount() { return curCollectedShines.size(); } int getShineID(int index) { if (index < curCollectedShines.size()) { return curCollectedShines[index]; } return -1; } - static void setGameActive(bool state); - static void setStageInfo(GameDataHolderAccessor holder); static bool tryAddPuppet(PuppetActor *puppet); @@ -130,27 +126,8 @@ class Client { static PuppetActor* getDebugPuppet(); - static GameMode getServerMode() { - return sInstance ? sInstance->mServerMode : GameMode::NONE; - } - - static void setServerMode(GameMode mode) { - if (sInstance) sInstance->mServerMode = mode; - } - - static GameMode getCurrentMode(); - - static GameModeBase* getModeBase() { return sInstance ? sInstance->mCurMode : nullptr; } - - template - static T* getMode() {return sInstance ? (T*)sInstance->mCurMode : nullptr;} - - static GameModeConfigMenu* tryCreateModeMenu(); - static int getMaxPlayerCount() { return sInstance ? sInstance->maxPuppets + 1 : 10;} - static void toggleCurrentMode(); - static void updateStates(); static void clearArrays(); @@ -173,6 +150,12 @@ class Client { return 0; } + static PuppetHolder* getPuppetHolder() { + if (sInstance) + return sInstance->mPuppetHolder; + return nullptr; + } + static void setSceneInfo(const al::ActorInitInfo& initInfo, const StageScene *stageScene); static bool tryRegisterShine(Shine* shine); @@ -184,23 +167,6 @@ class Client { static bool openKeyboardIP(); static bool openKeyboardPort(); - static GameModeInfoBase* getModeInfo() { - return sInstance ? sInstance->mModeInfo : nullptr; - } - - // should only be called during mode init - static void setModeInfo(GameModeInfoBase* info) { - if(sInstance) sInstance->mModeInfo = info; - } - - static void tryRestartCurrentMode(); - - static bool isModeActive() { return sInstance ? sInstance->mIsModeActive : false; } - - static bool isSelectedMode(GameMode mode) { - return sInstance ? sInstance->mCurMode->getMode() == mode : false; - } - static void showConnect(); static void showConnectError(const char16_t* msg); @@ -295,21 +261,11 @@ class Client { sead::FrameHeap *mHeap = nullptr; // Custom FrameHeap used for all Client related memory - // --- Mode Info --- - - GameModeBase* mCurMode = nullptr; - - GameMode mServerMode = GameMode::NONE; // current mode set by server, will sometimes not match up with current game mode (until scene re-init) if server switches gamemodes - - GameModeInfoBase *mModeInfo = nullptr; - - bool mIsModeActive = false; - // --- Puppet Info --- int maxPuppets = 9; // default max player count is 10, so default max puppets will be 9 - PuppetInfo *mPuppetInfoArr[MAXPUPINDEX]; + PuppetInfo *mPuppetInfoArr[MAXPUPINDEX] = {}; PuppetHolder *mPuppetHolder = nullptr; diff --git a/include/server/gamemode/GameModeBase.hpp b/include/server/gamemode/GameModeBase.hpp index d0baed6..e7e4715 100644 --- a/include/server/gamemode/GameModeBase.hpp +++ b/include/server/gamemode/GameModeBase.hpp @@ -21,7 +21,6 @@ enum GameMode : s8 { // struct containing info about the games state for use in gamemodes struct GameModeInitInfo { - GameModeInitInfo(al::ActorInitInfo* info, al::Scene *scene){ mLayoutInitInfo = info->mLayoutInitInfo; mPlayerHolder = info->mActorSceneInfo.mPlayerHolder; @@ -47,6 +46,7 @@ struct GameModeInitInfo { class GameModeBase : public al::IUseName, public al::IUseSceneObjHolder { public: GameModeBase(const char* name) { mName = name; } + virtual ~GameModeBase() = default; const char* getName() const override { return mName.cstr(); } al::SceneObjHolder* getSceneObjHolder() const override { return mSceneObjHolder; } @@ -56,7 +56,7 @@ public: virtual void init(GameModeInitInfo const &info); - virtual void begin() { mIsActive = true;} + virtual void begin() { mIsActive = true; } virtual void update(); virtual void end() { mIsActive = false; } diff --git a/include/server/gamemode/GameModeConfigMenuFactory.hpp b/include/server/gamemode/GameModeConfigMenuFactory.hpp new file mode 100644 index 0000000..d76d307 --- /dev/null +++ b/include/server/gamemode/GameModeConfigMenuFactory.hpp @@ -0,0 +1,38 @@ +#pragma once + +#include "al/factory/Factory.h" +#include "server/hns/HideAndSeekConfigMenu.hpp" +#include "server/gamemode/GameModeConfigMenu.hpp" + +typedef GameModeConfigMenu* (*createMenu)(const char* name); + +template +GameModeConfigMenu* createGameModeConfigMenu(const char* name) { + return new T(); +}; + +__attribute((used)) constexpr al::NameToCreator menuTable[] = { + {"HideAndSeek", &createGameModeConfigMenu}, +}; + +class GameModeConfigMenuFactory : public al::Factory { +public: + GameModeConfigMenuFactory(const char* fName) { + this->factoryName = fName; + this->actorTable = menuTable; + this->factoryCount = sizeof(menuTable) / sizeof(menuTable[0]); + }; + + constexpr static const char* getMenuName(int idx); + constexpr static int getMenuCount(); +}; + +constexpr const char* GameModeConfigMenuFactory::getMenuName(int idx) { + if (idx >= 0 && idx < sizeof(menuTable) / sizeof(menuTable[0])) + return menuTable[idx].creatorName; + return nullptr; +} + +constexpr int GameModeConfigMenuFactory::getMenuCount() { + return sizeof(menuTable) / sizeof(menuTable[0]); +} \ No newline at end of file diff --git a/include/server/gamemode/GameModeFactory.hpp b/include/server/gamemode/GameModeFactory.hpp index 334fe00..27ca263 100644 --- a/include/server/gamemode/GameModeFactory.hpp +++ b/include/server/gamemode/GameModeFactory.hpp @@ -1,9 +1,8 @@ #pragma once #include "al/factory/Factory.h" -#include "layouts/HideAndSeekIcon.h" #include "server/gamemode/GameModeBase.hpp" -#include "server/HideAndSeekMode.hpp" +#include "server/hns/HideAndSeekMode.hpp" typedef GameModeBase* (*createMode)(const char* name); @@ -37,19 +36,19 @@ class GameModeFactory : public al::Factory { // TODO: possibly use shadows' crc32 hash algorithm for this constexpr const char* GameModeFactory::getModeString(GameMode mode) { - if(mode >= 0 && mode < sizeof(modeTable)/sizeof(modeTable[0])) + if(mode >= 0 && (size_t)mode < sizeof(modeTable)/sizeof(modeTable[0])) return modeTable[mode].creatorName; return nullptr; } constexpr const char* GameModeFactory::getModeName(GameMode mode) { - if(mode >= 0 && mode < sizeof(modeNames)/sizeof(modeNames[0])) + if(mode >= 0 && (size_t)mode < sizeof(modeNames)/sizeof(modeNames[0])) return modeNames[mode]; return nullptr; } constexpr const char* GameModeFactory::getModeName(int idx) { - if(idx >= 0 && idx < sizeof(modeNames)/sizeof(modeNames[0])) + if(idx >= 0 && (size_t)idx < sizeof(modeNames)/sizeof(modeNames[0])) return modeNames[idx]; return nullptr; } diff --git a/include/server/gamemode/GameModeInfoBase.hpp b/include/server/gamemode/GameModeInfoBase.hpp index 0f0cdab..b2d24be 100644 --- a/include/server/gamemode/GameModeInfoBase.hpp +++ b/include/server/gamemode/GameModeInfoBase.hpp @@ -1,21 +1,11 @@ #pragma once #include "server/gamemode/GameModeBase.hpp" +#include // base struct containing info about the current gamemode struct GameModeInfoBase { GameMode mMode; }; -template -T *createModeInfo() { - // using sequence heap to create mode info should allow for mode info to persist between scenes - sead::Heap* seqHeap = sead::HeapMgr::instance()->findHeapByName("SequenceHeap", 0); - - if (seqHeap) { - return new (seqHeap) T(); - } else { - // if failed to get sequence heap, fall back to current heap (will return null if current heap is also null) - return new T(); - } -} \ No newline at end of file +#include "server/gamemode/GameModeManager.hpp" \ No newline at end of file diff --git a/include/server/gamemode/GameModeManager.hpp b/include/server/gamemode/GameModeManager.hpp new file mode 100644 index 0000000..3b881ac --- /dev/null +++ b/include/server/gamemode/GameModeManager.hpp @@ -0,0 +1,59 @@ +#pragma once + +#include +#include +#include +#include "server/gamemode/GameModeBase.hpp" +#include "server/gamemode/GameModeInfoBase.hpp" + +class GameModeManager { + SEAD_SINGLETON_DISPOSER(GameModeManager) + GameModeManager(); + ~GameModeManager(); + +public: + void setMode(GameMode mode); + void initScene(const GameModeInitInfo& info); + void begin(); + void end(); + void update(); + + GameMode getGameMode() const { return mCurMode; } + template T* getMode() const { return static_cast(mCurModeBase); } + template T* getInfo() const { return static_cast(mModeInfo); } + void setInfo(GameModeInfoBase* info) { + mModeInfo = info; + } + + template + T* createModeInfo(); + + sead::Heap* getHeap() { return mHeap; } + void toggleActive(); + void setActive(bool active) { mActive = active; } + void setPaused(bool paused); + bool isMode(GameMode mode) const { return mCurMode == mode; } + bool isActive() const { return mActive; } + bool isModeAndActive(GameMode mode) const { return isMode(mode) && isActive(); } + bool isPaused() const { return mPaused; } +private: + sead::Heap* mHeap = nullptr; + + bool mActive = false; + bool mPaused = false; + bool mWasSceneTrans = false; + bool mWasSetMode = false; + GameMode mCurMode = GameMode::NONE; + GameModeBase* mCurModeBase = nullptr; + GameModeInfoBase *mModeInfo = nullptr; + GameModeInitInfo *mLastInitInfo = nullptr; +}; + +template +T* GameModeManager::createModeInfo() { + sead::ScopedCurrentHeapSetter heapSetter(mHeap); + + T* info = new T(); + mModeInfo = info; + return info; +} \ No newline at end of file diff --git a/include/server/HideAndSeekConfigMenu.hpp b/include/server/hns/HideAndSeekConfigMenu.hpp similarity index 90% rename from include/server/HideAndSeekConfigMenu.hpp rename to include/server/hns/HideAndSeekConfigMenu.hpp index b0fa4d5..f2039c9 100644 --- a/include/server/HideAndSeekConfigMenu.hpp +++ b/include/server/hns/HideAndSeekConfigMenu.hpp @@ -1,6 +1,6 @@ #pragma once -#include "gamemode/GameModeConfigMenu.hpp" +#include "server/gamemode/GameModeConfigMenu.hpp" #include "game/Layouts/CommonVerticalList.h" #include "server/gamemode/GameModeBase.hpp" diff --git a/include/server/HideAndSeekMode.hpp b/include/server/hns/HideAndSeekMode.hpp similarity index 90% rename from include/server/HideAndSeekMode.hpp rename to include/server/hns/HideAndSeekMode.hpp index 4f7e370..b321bdd 100644 --- a/include/server/HideAndSeekMode.hpp +++ b/include/server/hns/HideAndSeekMode.hpp @@ -2,11 +2,11 @@ #include #include "al/camera/CameraTicket.h" -#include "gamemode/GameModeBase.hpp" -#include "gamemode/GameModeInfoBase.hpp" +#include "server/gamemode/GameModeBase.hpp" +#include "server/gamemode/GameModeInfoBase.hpp" #include "server/gamemode/GameModeConfigMenu.hpp" #include "server/gamemode/GameModeTimer.hpp" -#include "server/HideAndSeekConfigMenu.hpp" +#include "server/hns/HideAndSeekConfigMenu.hpp" struct HideAndSeekInfo : GameModeInfoBase { HideAndSeekInfo() { mMode = GameMode::HIDEANDSEEK; } diff --git a/source/hooks.cpp b/source/hooks.cpp index 3fc0fad..0e6febd 100644 --- a/source/hooks.cpp +++ b/source/hooks.cpp @@ -26,10 +26,10 @@ #include "math/seadVector.h" #include "rs/util/InputUtil.h" #include "sead/prim/seadSafeString.h" -#include "server/HideAndSeekMode.hpp" +#include "server/hns/HideAndSeekMode.hpp" bool comboBtnHook(int port) { - if (Client::isModeActive()) { // only switch to combo if any gamemode is active + if (GameModeManager::instance()->isActive()) { // only switch to combo if any gamemode is active return !al::isPadHoldL(port) && al::isPadTriggerDown(port); } else { return al::isPadTriggerDown(port); @@ -110,19 +110,19 @@ void initNerveStateHook(StageSceneStatePauseMenu* stateParent, StageSceneStateOp // skips starting both coin counters void startCounterHook(CoinCounter* thisPtr) { - if (!Client::isModeActive()) { + if (!GameModeManager::instance()->isActive()) { thisPtr->tryStart(); } } // Simple hook that can be used to override isModeE3 checks to enable/disable certain behaviors bool modeE3Hook() { - return Client::isModeActive(); + return GameModeManager::instance()->isActive(); } // Skips ending the play guide layout if a mode is active, since the mode would have already ended it void playGuideEndHook(al::SimpleLayoutAppearWaitEnd* thisPtr) { - if (!Client::isModeActive()) { + if (!GameModeManager::instance()->isActive()) { thisPtr->end(); } } @@ -135,14 +135,14 @@ void initHackCapHook(al::LiveActor *cappy) { al::PlayerHolder* createTicketHook(StageScene* curScene) { // only creates custom gravity camera ticket if hide and seek mode is active - if (Client::isSelectedMode(GameMode::HIDEANDSEEK)) { + if (GameModeManager::instance()->isMode(GameMode::HIDEANDSEEK)) { al::CameraDirector* director = curScene->getCameraDirector(); if (director) { if (director->mFactory) { al::CameraTicket* gravityCamera = director->createCameraFromFactory( "CameraPoserCustom", nullptr, 0, 5, sead::Matrix34f::ident); - HideAndSeekMode* mode = Client::getMode(); + HideAndSeekMode* mode = GameModeManager::instance()->getMode(); mode->setCameraTicket(gravityCamera); } @@ -157,9 +157,9 @@ bool borderPullBackHook(WorldEndBorderKeeper* thisPtr) { bool isFirstStep = al::isFirstStep(thisPtr); if (isFirstStep) { - if (Client::isSelectedMode(GameMode::HIDEANDSEEK) && Client::isModeActive()) { + if (GameModeManager::instance()->isModeAndActive(GameMode::HIDEANDSEEK)) { - HideAndSeekMode* mode = Client::getMode(); + HideAndSeekMode* mode = GameModeManager::instance()->getMode(); if (mode->isUseGravity()) { killMainPlayer(thisPtr->mActor); diff --git a/source/layouts/HideAndSeekIcon.cpp b/source/layouts/HideAndSeekIcon.cpp index 7b8b579..c12b664 100644 --- a/source/layouts/HideAndSeekIcon.cpp +++ b/source/layouts/HideAndSeekIcon.cpp @@ -5,7 +5,7 @@ #include "al/string/StringTmp.h" #include "prim/seadSafeString.h" #include "server/gamemode/GameModeTimer.hpp" -#include "server/HideAndSeekMode.hpp" +#include "server/hns/HideAndSeekMode.hpp" #include "server/Client.hpp" #include "al/util.hpp" #include "logger.hpp" @@ -16,7 +16,7 @@ HideAndSeekIcon::HideAndSeekIcon(const char* name, const al::LayoutInitInfo& ini al::initLayoutActor(this, initInfo, "HideAndSeekIcon", 0); - mInfo = (HideAndSeekInfo*)Client::getModeInfo(); + mInfo = GameModeManager::instance()->getInfo(); initNerve(&nrvHideAndSeekIconEnd, 0); diff --git a/source/main.cpp b/source/main.cpp index 74b9010..8cb5a27 100644 --- a/source/main.cpp +++ b/source/main.cpp @@ -21,7 +21,8 @@ #include "logger.hpp" #include "rs/util.hpp" #include "server/gamemode/GameModeBase.hpp" -#include "server/HideAndSeekMode.hpp" +#include "server/hns/HideAndSeekMode.hpp" +#include "server/gamemode/GameModeManager.hpp" static int pInfSendTimer = 0; static int gameInfSendTimer = 0; @@ -252,10 +253,11 @@ void stageInitHook(al::ActorInitInfo *info, StageScene *curScene, al::PlacementI Client::setSceneInfo(*info, curScene); - if (Client::getServerMode() != NONE) { + if (GameModeManager::instance()->getGameMode() != NONE) { GameModeInitInfo initModeInfo(info, curScene); + initModeInfo.initServerInfo(GameModeManager::instance()->getGameMode(), Client::getPuppetHolder()); - Client::initMode(initModeInfo); + GameModeManager::instance()->initScene(initModeInfo); } Client::sendGameInfPacket(info->mActorSceneInfo.mSceneObjHolder); @@ -278,6 +280,7 @@ ulong constructHook() { // hook for constructing anything we need to globally b initInfo)); // Save our scenes init info to a gloabl ptr so we can access it later Client::createInstance(al::getCurrentHeap()); + GameModeManager::createInstance(al::getCurrentHeap()); // Create the GameModeManager on the current al heap return 0x20; } @@ -303,13 +306,9 @@ bool hakoniwaSequenceHook(HakoniwaSequence* sequence) { al::PlayerHolder *pHolder = al::getScenePlayerHolder(stageScene); PlayerActorHakoniwa* p1 = (PlayerActorHakoniwa*)al::tryGetPlayerActor(pHolder, 0); - if (isFirstStep) { - Client::tryRestartCurrentMode(); - } - isInGame = !stageScene->isPause(); - Client::setGameActive(!stageScene->isPause()); + GameModeManager::instance()->setPaused(stageScene->isPause()); Client::setStageInfo(stageScene->mHolder); Client::updateStates(); @@ -345,7 +344,7 @@ bool hakoniwaSequenceHook(HakoniwaSequence* sequence) { } } else if (al::isPadHoldL(-1)) { - if (al::isPadTriggerLeft(-1)) Client::toggleCurrentMode(); + if (al::isPadTriggerLeft(-1)) GameModeManager::instance()->toggleActive(); if (al::isPadTriggerRight(-1)) { if (debugMode) { PuppetInfo *debugPuppet = Client::getDebugPuppetInfo(); diff --git a/source/puppets/PuppetActor.cpp b/source/puppets/PuppetActor.cpp index 2478571..2c20b61 100644 --- a/source/puppets/PuppetActor.cpp +++ b/source/puppets/PuppetActor.cpp @@ -14,8 +14,9 @@ #include "actors/PuppetActor.h" #include "math/seadQuat.h" #include "math/seadVector.h" +#include "server/gamemode/GameModeManager.hpp" #include "server/gamemode/GameModeBase.hpp" -#include "server/HideAndSeekMode.hpp" +#include "server/hns/HideAndSeekMode.hpp" static const char *subActorNames[] = { "顔", // Face @@ -189,9 +190,9 @@ void PuppetActor::control() { } if (mNameTag) { - if (Client::isSelectedMode(GameMode::HIDEANDSEEK) && Client::isModeActive()) { + if (GameModeManager::instance()->isModeAndActive(GameMode::HIDEANDSEEK)) { mNameTag->mIsAlive = - Client::getMode()->isPlayerIt() && mInfo->isIt; + GameModeManager::instance()->getMode()->isPlayerIt() && mInfo->isIt; } else { if(!mNameTag->mIsAlive) diff --git a/source/server/Client.cpp b/source/server/Client.cpp index ef67b19..eb55be4 100644 --- a/source/server/Client.cpp +++ b/source/server/Client.cpp @@ -35,9 +35,9 @@ #include "sead/basis/seadRawPrint.h" #include "sead/math/seadQuat.h" #include "server/gamemode/GameModeBase.hpp" -#include "server/gamemode/GameModeFactory.hpp" -#include "server/HideAndSeekConfigMenu.hpp" -#include "server/HideAndSeekMode.hpp" +#include "server/gamemode/GameModeManager.hpp" +#include "server/hns/HideAndSeekConfigMenu.hpp" +#include "server/hns/HideAndSeekMode.hpp" SEAD_SINGLETON_DISPOSER_IMPL(Client) @@ -93,8 +93,6 @@ Client::Client() { Logger::log("%s Build Number: %s\n", playerName.name, TOSTRING(BUILDVERSTR)); - mServerMode = GameMode::HIDEANDSEEK; // temp for testing - } /** @@ -118,39 +116,6 @@ void Client::init(al::LayoutInitInfo const &initInfo, GameDataHolderAccessor hol } -/** - * @brief creates and initializes the gamemode selected by either server or client settings - * - * @param initInfo init info used to initialize gamemode - */ -void Client::initMode(GameModeInitInfo const& initInfo) { - - if (!sInstance) { - Logger::log("Static Instance is null!\n"); - return; - } - - GameModeInitInfo newInfo = initInfo; - - newInfo.initServerInfo(sInstance->mServerMode, sInstance->mPuppetHolder); - - GameModeFactory modeFactory("GameModeFactory"); - - const char* modeName = GameModeFactory::getModeString(newInfo.mMode); - - if (modeName) { - auto creator = modeFactory.getCreator(modeName); - if (creator) { - sInstance->mCurMode = creator(modeName); - } - } - - if (sInstance->mCurMode) { - sInstance->mCurMode->init(newInfo); - } else { - Logger::log("Failed to Create Gamemode! Mode: \n", modeName ? modeName : "Unknown"); - } -} /** * @brief starts client read thread * @@ -712,13 +677,14 @@ void Client::sendTagInfPacket() { return; } - if (sInstance->mServerMode != GameMode::HIDEANDSEEK) { + HideAndSeekMode* hsMode = GameModeManager::instance()->getMode(); + + if (!GameModeManager::instance()->isMode(GameMode::HIDEANDSEEK)) { Logger::log("State is not Hide and Seek!\n"); return; } - HideAndSeekMode* hsMode = (HideAndSeekMode*)sInstance->mCurMode; - HideAndSeekInfo* curInfo = (HideAndSeekInfo*)sInstance->mModeInfo; + HideAndSeekInfo* curInfo = GameModeManager::instance()->getInfo(); TagInf packet = TagInf(); @@ -994,10 +960,10 @@ void Client::updateGameInfo(GameInf *packet) { void Client::updateTagInfo(TagInf *packet) { // if the packet is for our player, edit info for our player - if (packet->mUserID == mUserID && mCurMode->getMode() == GameMode::HIDEANDSEEK) { + if (packet->mUserID == mUserID && GameModeManager::instance()->isMode(GameMode::HIDEANDSEEK)) { - HideAndSeekMode* mMode = (HideAndSeekMode*)mCurMode; - HideAndSeekInfo* curInfo = (HideAndSeekInfo*)mModeInfo; + HideAndSeekMode* mMode = GameModeManager::instance()->getMode(); + HideAndSeekInfo* curInfo = GameModeManager::instance()->getInfo(); if (packet->updateType & TagUpdateType::STATE) { mMode->setPlayerTagState(packet->isIt); @@ -1299,34 +1265,7 @@ void Client::updateStates() { if(sInstance) { sInstance->mPuppetHolder->update(); - if(sInstance->mCurMode && sInstance->mCurMode->isModeActive()) - sInstance->mCurMode->update(); - } -} - -/** - * @brief - * - * @param state - */ -void Client::setGameActive(bool state) { - if (sInstance) { - - sInstance->mIsInGame = state; - - // only modify mode state if mode should be active - if (sInstance->mIsModeActive) { - - bool modeActive = sInstance->mCurMode->isModeActive(); - - if (state && !modeActive) { - Logger::log("Resuming Current Mode.\n"); - sInstance->mCurMode->begin(); - } else if (!state && modeActive) { - Logger::log("Pausing Current Mode.\n"); - sInstance->mCurMode->end(); - } - } + GameModeManager::instance()->update(); } } @@ -1485,66 +1424,6 @@ Shine* Client::findStageShine(int shineID) { return nullptr; } -/** - * @brief gets the client's currently selected gamemode - * - * @return GameMode - */ -GameMode Client::getCurrentMode() { - return sInstance && sInstance->mCurMode ? sInstance->mCurMode->getMode() : GameMode::NONE; -} - -/** - * @brief enables or disables currently selected gamemode - * - */ -void Client::toggleCurrentMode() { - if (!sInstance || !sInstance->mCurMode) { - return; - } - - GameModeBase* curMode = sInstance->mCurMode; - - if (curMode->isModeActive()) { - Logger::log("Ending Gamemode: %s\n", curMode->getName()); - curMode->end(); - sInstance->mIsModeActive = false; - } else { - Logger::log("Starting Gamemode: %s\n", curMode->getName()); - curMode->begin(); - sInstance->mIsModeActive = true; - } -} - -/** - * @brief re-enables current gamemode if previously activated (if a stage reload occurs while the gamemode was previously active, this will turn it back on after initialized) - * - */ -void Client::tryRestartCurrentMode() { - if (!sInstance || !sInstance->mCurMode) { - return; - } - // restart mode if previous scene had one active - if (sInstance->mIsModeActive) { - sInstance->mCurMode->begin(); - } -} - -GameModeConfigMenu* Client::tryCreateModeMenu() { - if (!sInstance) - return nullptr; - - switch (sInstance->mServerMode) { - case HIDEANDSEEK: { - return new HideAndSeekConfigMenu(); - } - default: - return nullptr; - } -} - - - void Client::showConnectError(const char16_t* msg) { if (!sInstance) return; diff --git a/source/server/gamemode/GameModeManager.cpp b/source/server/gamemode/GameModeManager.cpp new file mode 100644 index 0000000..39a1721 --- /dev/null +++ b/source/server/gamemode/GameModeManager.cpp @@ -0,0 +1,92 @@ +#include "server/gamemode/GameModeManager.hpp" +#include +#include +#include "al/util.hpp" +#include "basis/seadNew.h" +#include "heap/seadHeapMgr.h" +#include "server/gamemode/GameModeBase.hpp" +#include "server/gamemode/GameModeFactory.hpp" + +SEAD_SINGLETON_DISPOSER_IMPL(GameModeManager) + +GameModeManager::GameModeManager() { + mHeap = sead::FrameHeap::create(0x100000, "GameModeHeap", al::getSequenceHeap(), 8, + sead::Heap::HeapDirection::cHeapDirection_Reverse, false); + setMode(GameMode::HIDEANDSEEK); +} + +void GameModeManager::begin() { + if (mCurModeBase) { + sead::ScopedCurrentHeapSetter heapSetter(mHeap); + mCurModeBase->begin(); + } +} + +void GameModeManager::end() { + if (mCurModeBase) { + sead::ScopedCurrentHeapSetter heapSetter(mHeap); + mCurModeBase->end(); + } +} + +void GameModeManager::toggleActive() { + mActive = !mActive; +} + +void GameModeManager::setPaused(bool paused) { + mPaused = paused; +} + +void GameModeManager::setMode(GameMode mode) { + mCurMode = mode; + + mWasSetMode = true; // recreate in initScene +} + +void GameModeManager::update() { + if (!mCurModeBase) return; + bool inScene = al::getSceneHeap() != nullptr; + if ((mActive && inScene && !mPaused && !mCurModeBase->isModeActive()) || mWasSceneTrans) begin(); + if ((!mActive || mPaused || !inScene) && mCurModeBase->isModeActive()) end(); + mWasSceneTrans = false; + if (mCurModeBase && mCurModeBase->isModeActive()) { + sead::ScopedCurrentHeapSetter heapSetter(mHeap); + mCurModeBase->update(); + } +} + +void GameModeManager::initScene(const GameModeInitInfo& info) { + sead::ScopedCurrentHeapSetter heapSetter(mHeap); + + if (mCurModeBase != nullptr) { + delete mCurModeBase; + } + + if (mLastInitInfo != nullptr) { + delete mLastInitInfo; + } + + if (mCurMode == GameMode::NONE) { + mCurModeBase = nullptr; + mModeInfo = nullptr; + return; + } + + mLastInitInfo = new GameModeInitInfo(info); + + if (!mCurModeBase && mWasSetMode) { + GameModeFactory factory("GameModeFactory"); + const char* name = factory.getModeString(mCurMode); + mCurModeBase = factory.getCreator(name)(name); + if (mLastInitInfo) { // check if there's a previously used init info + mCurModeBase->init(*mLastInitInfo); + } + mWasSetMode = false; + } + + if (mCurModeBase) { + mCurModeBase->init(*mLastInitInfo); + if (mCurModeBase->isModeActive()) + mWasSceneTrans = true; + } +} \ No newline at end of file diff --git a/source/server/GameModeTimer.cpp b/source/server/hns/GameModeTimer.cpp similarity index 59% rename from source/server/GameModeTimer.cpp rename to source/server/hns/GameModeTimer.cpp index 95e364a..02aeace 100644 --- a/source/server/GameModeTimer.cpp +++ b/source/server/hns/GameModeTimer.cpp @@ -2,6 +2,7 @@ #include #include "al/util/ControllerUtil.h" #include "server/DeltaTime.hpp" +#include "logger.hpp" GameModeTimer::GameModeTimer(bool isCountUp, float milli, int seconds, int minutes, int hours) { mIsCountUp = isCountUp; @@ -24,10 +25,14 @@ GameModeTimer::GameModeTimer() { } void GameModeTimer::setTime(float milli, int seconds, int minutes, int hours) { - if(milli >= 0) mTime.mMilliseconds = milli; - if(seconds >= 0) mTime.mSeconds = seconds; - if(minutes >= 0) mTime.mMinutes = minutes; - if(hours >= 0) mTime.mHours = hours; + if (milli >= 0) + mTime.mMilliseconds = milli; + if (seconds >= 0) + mTime.mSeconds = seconds; + if (minutes >= 0) + mTime.mMinutes = minutes; + if (hours >= 0) + mTime.mHours = hours; } void GameModeTimer::setTime(GameTime const& time) { @@ -35,7 +40,6 @@ void GameModeTimer::setTime(GameTime const& time) { } void GameModeTimer::updateTimer() { - if (mIsUseControl) { timerControl(); } @@ -43,11 +47,11 @@ void GameModeTimer::updateTimer() { if (mIsEnabled) { if (mIsCountUp) { mTime.mMilliseconds += Time::deltaTime; - - if(mTime.mMilliseconds >= 1) { + + if (mTime.mMilliseconds >= 1) { mTime.mMilliseconds--; mTime.mSeconds++; - if(mTime.mSeconds >= 60) { + if (mTime.mSeconds >= 60) { mTime.mSeconds = 0; mTime.mMinutes++; if (mTime.mMinutes >= 60) { @@ -61,7 +65,7 @@ void GameModeTimer::updateTimer() { if (mTime.mMilliseconds >= 1) { mTime.mMilliseconds--; mTime.mSeconds--; - if(mTime.mSeconds < 0) { + if (mTime.mSeconds < 0) { mTime.mSeconds = 59; mTime.mMinutes--; if (mTime.mMinutes < 0) { @@ -79,41 +83,44 @@ void GameModeTimer::updateTimer() { } void GameModeTimer::timerControl() { - - if(al::isPadHoldRight(-1)) { - mTime.mMilliseconds = 0; - mTime.mSeconds++; - if(mTime.mSeconds >= 60) { + if (al::isPadHoldL(-1)) { + if (al::isPadTriggerDown(-1)) { + mTime.mMilliseconds = 0; mTime.mSeconds = 0; - mTime.mMinutes++; - if (mTime.mMinutes >= 60) { - mTime.mMinutes = 0; - mTime.mHours++; + mTime.mMinutes = 0; + mTime.mHours = 0; + } + } else { + if (al::isPadHoldRight(-1)) { + mTime.mMilliseconds = 0; + mTime.mSeconds++; + if (mTime.mSeconds >= 60) { + mTime.mSeconds = 0; + mTime.mMinutes++; + if (mTime.mMinutes >= 60) { + mTime.mMinutes = 0; + mTime.mHours++; + } } } - } - if(al::isPadTriggerLeft(-1)) { - mTime.mMilliseconds = 0; - mTime.mSeconds--; - if(mTime.mSeconds < 0) { - mTime.mSeconds = 59; - mTime.mMinutes--; - if (mTime.mMinutes < 0) { - if (mTime.mHours > 0) { - mTime.mMinutes = 59; - mTime.mHours--; - } else { - mTime.mMinutes = 0; + if (al::isPadTriggerLeft(-1)) { + mTime.mMilliseconds = 0; + if (mTime.mMinutes != 0) { + mTime.mSeconds--; + if (mTime.mSeconds < 0) { + mTime.mSeconds = 59; + mTime.mMinutes--; + if (mTime.mMinutes < 0) { + if (mTime.mHours > 0) { + mTime.mMinutes = 59; + mTime.mHours--; + } else { + mTime.mMinutes = 0; + } + } } } } } - - if(al::isPadHoldL(-1) && al::isPadTriggerDown(-1)) { - mTime.mMilliseconds = 0; - mTime.mSeconds = 0; - mTime.mMinutes = 0; - mTime.mHours = 0; - } } \ No newline at end of file diff --git a/source/server/HideAndSeekConfigMenu.cpp b/source/server/hns/HideAndSeekConfigMenu.cpp similarity index 76% rename from source/server/HideAndSeekConfigMenu.cpp rename to source/server/hns/HideAndSeekConfigMenu.cpp index 3e5c203..79fc7a4 100644 --- a/source/server/HideAndSeekConfigMenu.cpp +++ b/source/server/hns/HideAndSeekConfigMenu.cpp @@ -1,7 +1,8 @@ -#include "server/HideAndSeekConfigMenu.hpp" +#include "server/hns/HideAndSeekConfigMenu.hpp" #include #include "logger.hpp" -#include "server/HideAndSeekMode.hpp" +#include "server/gamemode/GameModeManager.hpp" +#include "server/hns/HideAndSeekMode.hpp" #include "server/Client.hpp" HideAndSeekConfigMenu::HideAndSeekConfigMenu() : GameModeConfigMenu() {} @@ -22,7 +23,7 @@ const sead::WFixedSafeString<0x200> *HideAndSeekConfigMenu::getStringData() { bool HideAndSeekConfigMenu::updateMenu(int selectIndex) { - HideAndSeekInfo *curMode = (HideAndSeekInfo*)Client::getModeInfo(); + HideAndSeekInfo *curMode = GameModeManager::instance()->getInfo(); Logger::log("Setting Gravity Mode.\n"); @@ -33,13 +34,13 @@ bool HideAndSeekConfigMenu::updateMenu(int selectIndex) { switch (selectIndex) { case 0: { - if (Client::isSelectedMode(GameMode::HIDEANDSEEK)) { + if (GameModeManager::instance()->isMode(GameMode::HIDEANDSEEK)) { curMode->mIsUseGravity = true; } return true; } case 1: { - if (Client::isSelectedMode(GameMode::HIDEANDSEEK)) { + if (GameModeManager::instance()->isMode(GameMode::HIDEANDSEEK)) { curMode->mIsUseGravity = false; } return true; diff --git a/source/server/HideAndSeekMode.cpp b/source/server/hns/HideAndSeekMode.cpp similarity index 83% rename from source/server/HideAndSeekMode.cpp rename to source/server/hns/HideAndSeekMode.cpp index 032965c..3f87ffe 100644 --- a/source/server/HideAndSeekMode.cpp +++ b/source/server/hns/HideAndSeekMode.cpp @@ -1,4 +1,4 @@ -#include "server/HideAndSeekMode.hpp" +#include "server/hns/HideAndSeekMode.hpp" #include #include "al/async/FunctorV0M.hpp" #include "al/util.hpp" @@ -7,15 +7,19 @@ #include "game/Layouts/CoinCounter.h" #include "game/Layouts/MapMini.h" #include "game/Player/PlayerActorHakoniwa.h" +#include "heap/seadHeapMgr.h" #include "layouts/HideAndSeekIcon.h" #include "logger.hpp" #include "rs/util.hpp" #include "server/gamemode/GameModeBase.hpp" #include "server/Client.hpp" #include "server/gamemode/GameModeTimer.hpp" +#include +#include "server/gamemode/GameModeManager.hpp" +#include "server/gamemode/GameModeFactory.hpp" #include "basis/seadNew.h" -#include "server/HideAndSeekConfigMenu.hpp" +#include "server/hns/HideAndSeekConfigMenu.hpp" HideAndSeekMode::HideAndSeekMode(const char* name) : GameModeBase(name) {} @@ -25,17 +29,21 @@ void HideAndSeekMode::init(const GameModeInitInfo& info) { mCurScene = (StageScene*)info.mScene; mPuppetHolder = info.mPuppetHolder; - GameModeInfoBase* curGameInfo = Client::getModeInfo(); + GameModeInfoBase* curGameInfo = GameModeManager::instance()->getInfo(); + sead::ScopedCurrentHeapSetter heapSetter(GameModeManager::instance()->getHeap()); + + if (curGameInfo) Logger::log("Gamemode info found: %s %s\n", GameModeFactory::getModeString(curGameInfo->mMode), GameModeFactory::getModeString(info.mMode)); + else Logger::log("No gamemode info found\n"); if (curGameInfo && curGameInfo->mMode == mMode) { mInfo = (HideAndSeekInfo*)curGameInfo; mModeTimer = new GameModeTimer(mInfo->mHidingTime); + Logger::log("Reinitialized timer with time %d:%.2d\n", mInfo->mHidingTime.mMinutes, mInfo->mHidingTime.mSeconds); } else { - sead::system::DeleteImpl( - curGameInfo); // attempt to destory previous info before creating new one + if (curGameInfo) delete curGameInfo; // attempt to destory previous info before creating new one + + mInfo = GameModeManager::instance()->createModeInfo(); - mInfo = createModeInfo(); - Client::setModeInfo(mInfo); mModeTimer = new GameModeTimer(); } @@ -48,7 +56,6 @@ void HideAndSeekMode::init(const GameModeInitInfo& info) { } void HideAndSeekMode::begin() { - mModeLayout->appear(); mIsFirstFrame = true; @@ -118,10 +125,15 @@ void HideAndSeekMode::update() { if (mInvulnTime >= 5) { if (mainPlayer) { - for (size_t i = 0; i < mPuppetHolder->getSize(); i++) + for (int i = 0; i < mPuppetHolder->getSize(); i++) { PuppetInfo *curInfo = Client::getPuppetInfo(i); + if (!curInfo) { + Logger::log("Checking %d, hit bounds %d-%d\n", i, mPuppetHolder->getSize(), Client::getMaxPlayerCount()); + break; + } + if(curInfo->isConnected && curInfo->isInSameStage && curInfo->isIt) { float pupDist = al::calcDistance(mainPlayer, curInfo->playerPos); // TODO: remove distance calculations and use hit sensors to determine this diff --git a/source/states/StageSceneStateServerConfig.cpp b/source/states/StageSceneStateServerConfig.cpp index c4eeb51..0528166 100644 --- a/source/states/StageSceneStateServerConfig.cpp +++ b/source/states/StageSceneStateServerConfig.cpp @@ -12,8 +12,10 @@ #include "prim/seadStringUtil.h" #include "rs/util/InputUtil.h" #include "server/gamemode/GameModeBase.hpp" +#include "server/gamemode/GameModeConfigMenuFactory.hpp" #include "server/gamemode/GameModeFactory.hpp" -#include "server/HideAndSeekMode.hpp" +#include "server/gamemode/GameModeManager.hpp" +#include "server/hns/HideAndSeekMode.hpp" StageSceneStateServerConfig::StageSceneStateServerConfig(const char *name, al::Scene *scene, const al::LayoutInitInfo &initInfo, FooterParts *footerParts, GameDataHolder *dataHolder, bool) : al::HostStateBase(name, scene) { mFooterParts = footerParts; @@ -64,19 +66,23 @@ StageSceneStateServerConfig::StageSceneStateServerConfig(const char *name, al::S mModeSelectList->addStringData(modeSelectOptions->mBuffer, "TxtContent"); // gamemode config menu - mGamemodeConfig = new SimpleLayoutMenu("GameModeConfigMenu", "OptionSelect", initInfo, 0, false); - mGameModeConfigList = new CommonVerticalList(mGamemodeConfig, initInfo, true); + GameModeConfigMenuFactory factory("GameModeConfigFactory"); + for (int mode = 0; mode < factory.getMenuCount(); mode++) { + GameModeEntry& entry = mGamemodeConfigMenus[mode]; + const char* name = factory.getMenuName(mode); + entry.mMenu = factory.getCreator(name)(name); + entry.mLayout = new SimpleLayoutMenu("GameModeConfigMenu", "OptionSelect", initInfo, 0, false); + entry.mList = new CommonVerticalList(entry.mLayout, initInfo, true); - al::setPaneString(mGamemodeConfig, "TxtOption", u"Gamemode Configuration", 0); + al::setPaneString(entry.mLayout, "TxtOption", u"Gamemode Configuration", 0); - mGamemodeConfigMenu = Client::tryCreateModeMenu(); + entry.mList->initDataNoResetSelected(entry.mMenu->getMenuSize()); - if (mGamemodeConfigMenu) { - mGameModeConfigList->initDataNoResetSelected(mGamemodeConfigMenu->getMenuSize()); - mGameModeConfigList->addStringData(mGamemodeConfigMenu->getStringData(), "TxtContent"); + entry.mList->addStringData(entry.mMenu->getStringData(), "TxtContent"); } + mCurrentList = mMainOptionsList; mCurrentMenu = mMainOptions; } @@ -224,15 +230,16 @@ void StageSceneStateServerConfig::exeRestartServer() { void StageSceneStateServerConfig::exeGamemodeConfig() { if (al::isFirstStep(this)) { - mCurrentList = mGameModeConfigList; - mCurrentMenu = mGamemodeConfig; + mGamemodeConfigMenu = &mGamemodeConfigMenus[GameModeManager::instance()->getGameMode()]; + mCurrentList = mGamemodeConfigMenu->mList; + mCurrentMenu = mGamemodeConfigMenu->mLayout; subMenuStart(); } subMenuUpdate(); if (mIsDecideConfig && mCurrentList->isDecideEnd()) { - if (mGamemodeConfigMenu->updateMenu(mCurrentList->mCurSelected)) { + if (mGamemodeConfigMenu->mMenu->updateMenu(mCurrentList->mCurSelected)) { endSubMenu(); } } @@ -252,7 +259,7 @@ void StageSceneStateServerConfig::exeGamemodeSelect() { if (mIsDecideConfig && mCurrentList->isDecideEnd()) { Logger::log("Setting Server Mode to: %d\n", mCurrentList->mCurSelected); - Client::setServerMode(static_cast(mCurrentList->mCurSelected)); + GameModeManager::instance()->setMode(static_cast(mCurrentList->mCurSelected)); endSubMenu(); } } From d18276d25520c7b1e90197eb255bad19556ac318 Mon Sep 17 00:00:00 2001 From: Sanae Date: Wed, 10 Aug 2022 15:10:28 -0600 Subject: [PATCH 39/48] Fix switching modes between scenes --- source/server/gamemode/GameModeManager.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/source/server/gamemode/GameModeManager.cpp b/source/server/gamemode/GameModeManager.cpp index 39a1721..2bb341b 100644 --- a/source/server/gamemode/GameModeManager.cpp +++ b/source/server/gamemode/GameModeManager.cpp @@ -58,8 +58,9 @@ void GameModeManager::update() { void GameModeManager::initScene(const GameModeInitInfo& info) { sead::ScopedCurrentHeapSetter heapSetter(mHeap); - if (mCurModeBase != nullptr) { + if (mCurModeBase != nullptr && mWasSetMode) { delete mCurModeBase; + mCurModeBase = nullptr; } if (mLastInitInfo != nullptr) { @@ -68,19 +69,17 @@ void GameModeManager::initScene(const GameModeInitInfo& info) { if (mCurMode == GameMode::NONE) { mCurModeBase = nullptr; + delete mModeInfo; mModeInfo = nullptr; return; } mLastInitInfo = new GameModeInitInfo(info); - if (!mCurModeBase && mWasSetMode) { + if (mWasSetMode) { GameModeFactory factory("GameModeFactory"); const char* name = factory.getModeString(mCurMode); mCurModeBase = factory.getCreator(name)(name); - if (mLastInitInfo) { // check if there's a previously used init info - mCurModeBase->init(*mLastInitInfo); - } mWasSetMode = false; } From 8f4fac417fd718fa1bda515228c713061e30df14 Mon Sep 17 00:00:00 2001 From: CraftyBoss Date: Wed, 10 Aug 2022 14:11:52 -0700 Subject: [PATCH 40/48] change recieve logs, update headers, fix bound bowl crash --- include/al/PlayerHolder/PlayerHolder.h | 5 +- include/al/util.hpp | 2 +- include/al/util/LiveActorUtil.h | 3 +- include/game/Actors/Shine.h | 80 ++++++- include/game/GameData/GameDataFile.h | 202 +++++++++++++++++- include/game/GameData/GameDataFunction.h | 14 ++ .../game/HakoniwaSequence/HakoniwaSequence.h | 30 +-- include/game/Interfaces/IUsePlayerHack.h | 3 +- include/game/Layouts/CommonVerticalList.h | 9 +- include/game/Player/HackCap.h | 7 +- .../Player/HackCap/PlayerCapActionHistory.h | 29 +++ include/game/Player/PlayerActorBase.h | 58 ++++- include/game/Player/PlayerActorHakoniwa.h | 139 +++++++++--- include/game/Player/PlayerInfo.h | 6 +- include/game/Sequence/SequenceFactory.h | 6 + include/game/StageScene/StageScene.h | 115 ++++++++-- .../game/StageScene/StageSceneStateOption.h | 4 +- include/main.hpp | 6 + include/packets/Packet.h | 3 +- include/rs/util.hpp | 9 +- include/server/Client.hpp | 2 +- patches/codehook.slpatch | 4 +- source/layouts/HideAndSeekIcon.cpp | 4 +- source/main.cpp | 77 ++++--- source/server/Client.cpp | 84 +++++--- source/server/HideAndSeekMode.cpp | 73 ++++--- source/server/SocketClient.cpp | 17 +- source/server/logger.cpp | 5 +- source/states/StageSceneStateServerConfig.cpp | 26 +++ 29 files changed, 816 insertions(+), 206 deletions(-) create mode 100644 include/game/Player/HackCap/PlayerCapActionHistory.h create mode 100644 include/game/Sequence/SequenceFactory.h 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/util.hpp b/include/al/util.hpp index 3ef495d..981543e 100644 --- a/include/al/util.hpp +++ b/include/al/util.hpp @@ -242,7 +242,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 fdd1a0b..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" @@ -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/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/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/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/main.hpp b/include/main.hpp index 548f2f7..b288d12 100644 --- a/include/main.hpp +++ b/include/main.hpp @@ -55,6 +55,12 @@ 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/packets/Packet.h b/include/packets/Packet.h index f536331..400ee46 100644 --- a/include/packets/Packet.h +++ b/include/packets/Packet.h @@ -25,7 +25,8 @@ 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 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/server/Client.hpp b/include/server/Client.hpp index 7682263..b20c062 100644 --- a/include/server/Client.hpp +++ b/include/server/Client.hpp @@ -99,7 +99,7 @@ class Client { 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); 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/source/layouts/HideAndSeekIcon.cpp b/source/layouts/HideAndSeekIcon.cpp index 7b8b579..bf44212 100644 --- a/source/layouts/HideAndSeekIcon.cpp +++ b/source/layouts/HideAndSeekIcon.cpp @@ -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/main.cpp b/source/main.cpp index 74b9010..5076130 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" @@ -26,20 +30,29 @@ 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; } @@ -100,7 +113,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); @@ -174,16 +187,19 @@ void drawMainHook(HakoniwaSequence *curSequence, sead::Viewport *viewport, sead: 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) { - al::LiveActor *curHack = p1->mHackKeeper->currentHackActor; + 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; 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); @@ -191,7 +207,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())); @@ -205,6 +221,8 @@ void drawMainHook(HakoniwaSequence *curSequence, sead::Viewport *viewport, sead: } } } + + } break; default: break; @@ -301,11 +319,13 @@ bool hakoniwaSequenceHook(HakoniwaSequence* sequence) { bool isFirstStep = al::isFirstStep(sequence); al::PlayerHolder *pHolder = al::getScenePlayerHolder(stageScene); - PlayerActorHakoniwa* p1 = (PlayerActorHakoniwa*)al::tryGetPlayerActor(pHolder, 0); + PlayerActorBase* playerBase = al::tryGetPlayerActor(pHolder, 0); if (isFirstStep) { Client::tryRestartCurrentMode(); } + + bool isYukimaru = !playerBase->getPlayerInfo(); isInGame = !stageScene->isPause(); @@ -318,7 +338,7 @@ bool hakoniwaSequenceHook(HakoniwaSequence* sequence) { Client::updateShines(); } - updatePlayerInfo(stageScene->mHolder, p1); + updatePlayerInfo(stageScene->mHolder, playerBase, isYukimaru); static bool isDisableMusic = false; @@ -348,17 +368,26 @@ bool hakoniwaSequenceHook(HakoniwaSequence* sequence) { if (al::isPadTriggerLeft(-1)) Client::toggleCurrentMode(); 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, ""); + } } + } } } diff --git a/source/server/Client.cpp b/source/server/Client.cpp index 6059bc1..e5d77f0 100644 --- a/source/server/Client.cpp +++ b/source/server/Client.cpp @@ -9,6 +9,7 @@ #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" @@ -203,12 +204,7 @@ void Client::restartConnection() { initPacket.mUserID = sInstance->mUserID; strcpy(initPacket.clientName, sInstance->mUsername.cstr()); - if (sInstance->isFirstConnect) { - initPacket.conType = ConnectionTypes::INIT; - sInstance->isFirstConnect = false; - } else { - initPacket.conType = ConnectionTypes::RECONNECT; - } + initPacket.conType = ConnectionTypes::INIT; sInstance->mSocket->SEND(&initPacket); @@ -541,14 +537,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; } @@ -556,36 +552,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) { @@ -641,7 +657,7 @@ void Client::sendHackCapInfPacket(const HackCap* hackCap) { /** * @brief - * + * Sends both stage info and player 2D info to the server. * @param player * @param holder */ @@ -673,7 +689,7 @@ void Client::sendGameInfPacket(const PlayerActorHakoniwa* player, GameDataHolder } /** * @brief - * + * Sends only stage info to the server. * @param holder */ void Client::sendGameInfPacket(GameDataHolderAccessor holder) { @@ -1284,7 +1300,7 @@ void Client::updateShines() { } sInstance->resetCollectedShines(); - sInstance->mCurStageScene->stageSceneLayout->startShineCountAnim(false); + sInstance->mCurStageScene->mSceneLayout->startShineCountAnim(false); } /** diff --git a/source/server/HideAndSeekMode.cpp b/source/server/HideAndSeekMode.cpp index 032965c..128703f 100644 --- a/source/server/HideAndSeekMode.cpp +++ b/source/server/HideAndSeekMode.cpp @@ -6,6 +6,7 @@ #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 "layouts/HideAndSeekIcon.h" #include "logger.hpp" @@ -61,10 +62,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 +85,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 +104,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 +120,41 @@ 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->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 +167,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 +188,7 @@ void HideAndSeekMode::update() { } } else if (al::isPadTriggerZL(-1)) { if (al::isPadTriggerLeft(-1)) { - killMainPlayer(mainPlayer); + killMainPlayer(((PlayerActorHakoniwa*)playerBase)); } } } diff --git a/source/server/SocketClient.cpp b/source/server/SocketClient.cpp index 9dd5d97..0279964 100644 --- a/source/server/SocketClient.cpp +++ b/source/server/SocketClient.cpp @@ -128,11 +128,20 @@ bool SocketClient::RECV() { int fullSize = header->mPacketSize + sizeof(Packet); - if (header->mType != PacketType::UNKNOWN && fullSize <= MAXPACKSIZE && fullSize > 0 && valread == sizeof(Packet)) { + 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): %s\n", - header->mUserID.data[0], header->mUserID.data[1], packetNames[header->mType]); + 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); diff --git a/source/server/logger.cpp b/source/server/logger.cpp index 6fa0b61..99fd356 100644 --- a/source/server/logger.cpp +++ b/source/server/logger.cpp @@ -116,8 +116,7 @@ bool Logger::pingSocket() { void tryInitSocket() { __asm("STR X20, [X8,#0x18]"); - #ifdef DEBUGLOG + #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 c4eeb51..0163845 100644 --- a/source/states/StageSceneStateServerConfig.cpp +++ b/source/states/StageSceneStateServerConfig.cpp @@ -1,6 +1,10 @@ #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" @@ -15,6 +19,10 @@ #include "server/gamemode/GameModeFactory.hpp" #include "server/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; mGameDataHolder = dataHolder; @@ -29,6 +37,8 @@ StageSceneStateServerConfig::StageSceneStateServerConfig(const char *name, al::S al::setPaneString(mMainOptions, "TxtOption", u"Server Configuration", 0); + mMainOptionsList->unkInt1 = 1; + mMainOptionsList->initDataNoResetSelected(5); sead::SafeArray, 5>* mainMenuOptions = @@ -42,6 +52,22 @@ StageSceneStateServerConfig::StageSceneStateServerConfig(const char *name, al::S 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); From 71a9da11bf51ca3dde6055342931da5799f584b5 Mon Sep 17 00:00:00 2001 From: CraftyBoss Date: Wed, 10 Aug 2022 14:52:27 -0700 Subject: [PATCH 41/48] copy romfs folder to build folder --- Makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Makefile b/Makefile index 7b9a40e..d1b8bfa 100644 --- a/Makefile +++ b/Makefile @@ -25,6 +25,8 @@ 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 From b3a30b09f79508034d3a060de9aa47736f73d466 Mon Sep 17 00:00:00 2001 From: Sanae Date: Wed, 10 Aug 2022 16:06:49 -0600 Subject: [PATCH 42/48] Remove a check which blocks players from being updated Oops! teehee SmileW --- include/server/Client.hpp | 2 -- source/server/Client.cpp | 4 +--- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/include/server/Client.hpp b/include/server/Client.hpp index ab3473c..75df45f 100644 --- a/include/server/Client.hpp +++ b/include/server/Client.hpp @@ -238,8 +238,6 @@ class Client { // --- Game Info --- - bool mIsInGame = false; - bool isClientCaptured = false; bool isSentCaptureInf = false; diff --git a/source/server/Client.cpp b/source/server/Client.cpp index dfa2851..bd5dc6c 100644 --- a/source/server/Client.cpp +++ b/source/server/Client.cpp @@ -423,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); From 3325c50c005e66de5ff90e8268cd04d2f8a72994 Mon Sep 17 00:00:00 2001 From: "Robin C. Ladiges" Date: Sat, 9 Jul 2022 21:56:38 +0200 Subject: [PATCH 43/48] build w/ docker --- Dockerfile | 26 ++++++++++++++++++++++++++ docker-build.sh | 12 ++++++++++++ 2 files changed, 38 insertions(+) create mode 100644 Dockerfile create mode 100755 docker-build.sh diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..7cf9951 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,26 @@ +FROM ubuntu:20.04 as builder + +# install dependencies +RUN apt-get update \ + && apt-get install -y \ + curl \ + apt-transport-https \ + python3 \ + python3-pip \ + && pip install keystone-engine \ +; + +# install devkitpro +RUN ln -s /proc/self/mounts /etc/mtab \ + && mkdir /devkitpro/ \ + && echo "deb [signed-by=/devkitpro/pub.gpg] https://apt.devkitpro.org stable main" >/etc/apt/sources.list.d/devkitpro.list \ + && curl --fail -o /devkitpro/pub.gpg https://apt.devkitpro.org/devkitpro-pub.gpg \ + && apt-get update \ + && DEBIAN_FRONTEND=noninteractive apt-get install -y devkitpro-pacman \ + && dkp-pacman --noconfirm -S switch-dev \ +; + +WORKDIR /app/ + +ENV DEVKITPRO /opt/devkitpro +ENTRYPOINT make diff --git a/docker-build.sh b/docker-build.sh new file mode 100755 index 0000000..4064e74 --- /dev/null +++ b/docker-build.sh @@ -0,0 +1,12 @@ +#!/bin/bash + +export DOCKER_BUILDKIT=1 +docker build . -t smoo-client-build +docker run --rm \ + -u $(id -u):$(id -g) \ + -v "/$PWD/":/app/ \ + smoo-client-build \ +; +docker rmi smoo-client-build + +cp -r ./romfs/ ./starlight_patch_*/atmosphere/contents/0100000000010000/. From 71ff477bb9007bcf22cb41d055d0406e432517e0 Mon Sep 17 00:00:00 2001 From: "Robin C. Ladiges" Date: Wed, 13 Jul 2022 00:01:23 +0200 Subject: [PATCH 44/48] github workflow to build and release --- .github/actions/attach/action.yml | 40 ++++++++++++++++++++ .github/actions/build/action.yml | 61 ++++++++++++++++++++++++++++++ .github/actions/release/action.yml | 36 ++++++++++++++++++ .github/workflows/build.yml | 26 +++++++++++++ .github/workflows/release.yml | 47 +++++++++++++++++++++++ 5 files changed, 210 insertions(+) create mode 100644 .github/actions/attach/action.yml create mode 100644 .github/actions/build/action.yml create mode 100644 .github/actions/release/action.yml create mode 100644 .github/workflows/build.yml create mode 100644 .github/workflows/release.yml diff --git a/.github/actions/attach/action.yml b/.github/actions/attach/action.yml new file mode 100644 index 0000000..cbcefea --- /dev/null +++ b/.github/actions/attach/action.yml @@ -0,0 +1,40 @@ +name: Attach build artifacts to release + + +inputs: + filename: + description : 'Filename of the build artifact' + required : true + upload_url: + description : 'Upload URL of the release' + required : true + GITHUB_TOKEN: + description : 'Secret GitHub token required for uploading to the release' + required : true + + +runs: + using: composite + steps: + - + name : Download artifacts + uses : actions/download-artifact@v3 + with: + name : ${{ inputs.filename }} + path : ./starlight_patch_100/ + - + name : Zip artifacts + shell : bash + run: | + cd ./starlight_patch_100/ + zip -rmT9 ${{ inputs.filename }}.zip ./* + - + name : Attach to release + uses : actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ inputs.GITHUB_TOKEN }} + with: + upload_url : ${{ inputs.upload_url }} + asset_path : ./starlight_patch_100/${{ inputs.filename }}.zip + asset_name : ${{ inputs.filename }}.zip + asset_content_type : application/zip diff --git a/.github/actions/build/action.yml b/.github/actions/build/action.yml new file mode 100644 index 0000000..9adf5e3 --- /dev/null +++ b/.github/actions/build/action.yml @@ -0,0 +1,61 @@ +name: Build artifacts + + +inputs: + tag: + description : 'version tag' + required : false + default : '' + + +outputs: + filename: + description : 'Filename for the build artifacts' + value : ${{ steps.env.outputs.filename }} + + +runs: + using: composite + steps: + - + name : Environment + id : env + shell : bash + run: | + VERS=${{ inputs.tag }} + echo "::set-output name=version::${VERS:1}" + echo "::set-output name=filename::SMO_Online${{ (inputs.tag != '' && format('_{0}', inputs.tag)) || '' }}" + - + name : Set up Docker Buildx + uses : docker/setup-buildx-action@v2 + - + name : Build environment + uses : docker/build-push-action@v3 + with: + pull : true + push : false + load : true + context : . + file : ./Dockerfile + tags : smoo-build-env + platforms : linux/amd64 + cache-from : type=gha,scope=smoo-build-env + cache-to : type=gha,scope=smoo-build-env,mode=max + - + name : Build mod + shell : bash + run: | + docker run --rm \ + -u `id -u`:`id -g` \ + -v "/$PWD/":/app/ \ + ${{ (steps.env.outputs.version != '' && format('-e BUILDVER={0}', steps.env.outputs.version)) || '' }} \ + smoo-build-env \ + ; + cp -r ./romfs/ ./starlight_patch_100/atmosphere/contents/0100000000010000/. + - + name : Upload artifacts + uses : actions/upload-artifact@v3 + with: + name : ${{ steps.env.outputs.filename }} + path : ./starlight_patch_100/ + if-no-files-found : error diff --git a/.github/actions/release/action.yml b/.github/actions/release/action.yml new file mode 100644 index 0000000..e0d5576 --- /dev/null +++ b/.github/actions/release/action.yml @@ -0,0 +1,36 @@ +name: Create release + + +inputs: + tag: + description : 'Version tag' + required : true + GITHUB_TOKEN: + description : 'Secret GitHub token required to create the release' + required : true + + +outputs: + id: + value: ${{ steps.release.outputs.id }} + html_url: + value: ${{ steps.release.outputs.html_url }} + upload_url: + value: ${{ steps.release.outputs.upload_url }} + + +runs: + using: composite + steps: + - + name : Create release + id : release + uses : actions/create-release@v1 + env: + GITHUB_TOKEN: ${{ inputs.GITHUB_TOKEN }} + with: + tag_name : ${{ inputs.tag }} + release_name : Release ${{ inputs.tag }} + body : '' + draft : true + prerelease : false diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..f954ed7 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,26 @@ +name: Build + + +on: + push: + branches: + - '**' + tags: + - '**' + - '!v[0-9]+.[0-9]+.[0-9]+' + pull_request: + branches: + - '**' + + +jobs: + + build: + runs-on: ubuntu-latest + steps: + - + name : Checkout + uses : actions/checkout@v3 + - + name : Build artifacts + uses : ./.github/actions/build diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..00c84b6 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,47 @@ +name: Release + + +on: + push: + tags: + - 'v[0-9]+.[0-9]+.[0-9]+' + + +jobs: + + build: + runs-on: ubuntu-latest + outputs: + filename: ${{ steps.build.outputs.filename }} + steps: + - + name : Checkout + uses : actions/checkout@v3 + - + name : Build artifacts + id : build + uses : ./.github/actions/build + with: + tag : ${{ github.ref_name }} + + release: + needs: build + runs-on: ubuntu-latest + steps: + - + name : Checkout + uses : actions/checkout@v3 + - + name : Create release + id : release + uses : ./.github/actions/release + with: + tag : ${{ github.ref_name }} + GITHUB_TOKEN : ${{ secrets.GITHUB_TOKEN }} + - + 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 }} From 89a76aedab581c3a7543dba2a2f90b88c19ac8c3 Mon Sep 17 00:00:00 2001 From: "Robin C. Ladiges" Date: Sat, 13 Aug 2022 22:33:51 +0200 Subject: [PATCH 45/48] don't start release names with "Release " the title of the page will otherwise read "Release Release v..." --- .github/actions/release/action.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 From aff422a6e0c83c412d73fbfd46ca459941beece8 Mon Sep 17 00:00:00 2001 From: "Robin C. Ladiges" Date: Sat, 13 Aug 2022 21:13:16 +0200 Subject: [PATCH 46/48] allow build or pre-release details in release tags Examples: - v1.2.3-rc.1 (release candidate 1) - v1.2.3-dev+2 (dev pre-release, build 2) --- .github/workflows/build.yml | 2 ++ .github/workflows/release.yml | 2 ++ 2 files changed, 4 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index f954ed7..175a8f7 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -8,6 +8,8 @@ on: tags: - '**' - '!v[0-9]+.[0-9]+.[0-9]+' + - '!v[0-9]+.[0-9]+.[0-9]+\+*' + - '!v[0-9]+.[0-9]+.[0-9]+-*' pull_request: branches: - '**' 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: From 2898a762d4713c1ed05db34ad06679dd1c5f0659 Mon Sep 17 00:00:00 2001 From: "Robin C. Ladiges" Date: Sat, 13 Aug 2022 21:17:11 +0200 Subject: [PATCH 47/48] attach dev builds all into one release Requirements: - there exists a tag named `latest-dev` already - there exists a release on that tag --- .github/actions/build/action.yml | 6 ++- .github/workflows/build.yml | 2 + .github/workflows/dev-release.yml | 62 +++++++++++++++++++++++++++++++ 3 files changed, 69 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/dev-release.yml 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/workflows/build.yml b/.github/workflows/build.yml index 175a8f7..893e378 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -5,11 +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..386dcb7 --- /dev/null +++ b/.github/workflows/dev-release.yml @@ -0,0 +1,62 @@ +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 }} From 81a0726836fa6e8c1555de1334c50051a9370e0c Mon Sep 17 00:00:00 2001 From: "Robin C. Ladiges" Date: Sat, 13 Aug 2022 22:01:38 +0200 Subject: [PATCH 48/48] move latest-dev tag --- .github/workflows/dev-release.yml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/.github/workflows/dev-release.yml b/.github/workflows/dev-release.yml index 386dcb7..4051a44 100644 --- a/.github/workflows/dev-release.yml +++ b/.github/workflows/dev-release.yml @@ -60,3 +60,18 @@ jobs: 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 }}