From 23cdf1442d0f9ee90b182429cea58d1a497a794e Mon Sep 17 00:00:00 2001 From: Nick Renieris Date: Sat, 25 Jun 2022 03:46:58 +0300 Subject: [PATCH 1/6] 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 2/6] 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 3/6] 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 4/6] 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 5/6] 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 6/6] 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;