From 36f9343f838505b2f933dccf40d16e303aa0e74c Mon Sep 17 00:00:00 2001 From: "Robin C. Ladiges" Date: Mon, 5 Sep 2022 03:21:43 +0200 Subject: [PATCH] don't send empty GameInf and CostumeInf packets and resend them on reconnect Resend because: on server restarts the server will lose the stage and costume information. If only one client is connected to the server, the packets currently aren't resent, so the server doesn't know in which stage the client is and what costume it wears (which I'd like to display on the website). With more then one client connected it already works, because when another client joins the server, the client will send both packets. --- include/packets/GameInf.h | 4 +-- include/server/Client.hpp | 2 ++ include/server/SocketClient.hpp | 7 +++-- source/server/Client.cpp | 55 ++++++++++++++++++++++++--------- source/server/SocketClient.cpp | 11 +++++-- 5 files changed, 58 insertions(+), 21 deletions(-) diff --git a/include/packets/GameInf.h b/include/packets/GameInf.h index 34c5793..f435421 100644 --- a/include/packets/GameInf.h +++ b/include/packets/GameInf.h @@ -6,7 +6,7 @@ struct PACKED GameInf : Packet { GameInf() : Packet() {this->mType = PacketType::GAMEINF; mPacketSize = sizeof(GameInf) - sizeof(Packet);}; bool1 is2D = false; - u8 scenarioNo = -1; + u8 scenarioNo = 255; char stageName[0x40] = {}; bool operator==(const GameInf &rhs) const { @@ -19,4 +19,4 @@ struct PACKED GameInf : Packet { bool operator!=(const GameInf& rhs) const { return !operator==(rhs); } -}; \ No newline at end of file +}; diff --git a/include/server/Client.hpp b/include/server/Client.hpp index 16a2ca2..028fee9 100644 --- a/include/server/Client.hpp +++ b/include/server/Client.hpp @@ -103,6 +103,7 @@ class Client { static void sendShineCollectPacket(int shineId); static void sendTagInfPacket(); static void sendCaptureInfPacket(const PlayerActorHakoniwa *player); + void resendInitPackets(); int getCollectedShinesCount() { return curCollectedShines.size(); } int getShineID(int index) { if (index < curCollectedShines.size()) { return curCollectedShines[index]; } return -1; } @@ -226,6 +227,7 @@ class Client { // Backups for our last player/game packets, used for example to re-send them for newly connected clients PlayerInf lastPlayerInfPacket = PlayerInf(); GameInf lastGameInfPacket = GameInf(); + GameInf emptyGameInfPacket = GameInf(); CostumeInf lastCostumeInfPacket = CostumeInf(); Keyboard* mKeyboard = nullptr; // keyboard for setting server IP diff --git a/include/server/SocketClient.hpp b/include/server/SocketClient.hpp index 2f6dd74..217b292 100644 --- a/include/server/SocketClient.hpp +++ b/include/server/SocketClient.hpp @@ -20,9 +20,11 @@ #include "packets/Packet.h" +class Client; + class SocketClient : public SocketBase { public: - SocketClient(const char *name, sead::Heap *heap); + SocketClient(const char* name, sead::Heap* heap, Client* client); nn::Result init(const char* ip, u16 port) override; bool tryReconnect(); bool closeSocket() override; @@ -54,6 +56,7 @@ class SocketClient : public SocketBase { private: sead::Heap* mHeap = nullptr; + Client* client = nullptr; al::AsyncFunctorThread* mRecvThread = nullptr; al::AsyncFunctorThread* mSendThread = nullptr; @@ -72,4 +75,4 @@ class SocketClient : public SocketBase { bool stringToIPAddress(const char* str, in_addr* out); }; -typedef void (SocketClient::*SocketThreadFunc)(void); \ No newline at end of file +typedef void (SocketClient::*SocketThreadFunc)(void); diff --git a/source/server/Client.cpp b/source/server/Client.cpp index 9f8f1c4..4457ef0 100644 --- a/source/server/Client.cpp +++ b/source/server/Client.cpp @@ -27,7 +27,7 @@ Client::Client() { mKeyboard = new Keyboard(nn::swkbd::GetRequiredStringBufferSize()); - mSocket = new SocketClient("SocketClient", mHeap); + mSocket = new SocketClient("SocketClient", mHeap, this); mPuppetHolder = new PuppetHolder(maxPuppets); @@ -87,6 +87,7 @@ void Client::init(al::LayoutInitInfo const &initInfo, GameDataHolderAccessor hol Logger::log("Heap Free Size: %f/%f\n", mHeap->getFreeSize() * 0.001f, mHeap->getSize() * 0.001f); } + /** * @brief starts client read thread * @@ -103,6 +104,7 @@ bool Client::startThread() { return false; } } + /** * @brief restarts currently active connection to server * @@ -140,6 +142,7 @@ void Client::restartConnection() { Logger::log("Reconnect Unsuccessful.\n"); } } + /** * @brief starts a connection using client's TCP socket class, pulling up the software keyboard for user inputted IP if save file does not have one saved. * @@ -346,16 +349,18 @@ void Client::readFunc() { // Send relevant info packets when another client is connected - // Assume game packets are empty from first connection - if (lastGameInfPacket.mUserID != mUserID) - lastGameInfPacket.mUserID = mUserID; - mSocket->send(&lastGameInfPacket); + if (lastGameInfPacket != emptyGameInfPacket) { + // Assume game packets are empty from first connection + if (lastGameInfPacket.mUserID != mUserID) + lastGameInfPacket.mUserID = mUserID; + 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); + // 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: @@ -479,6 +484,7 @@ void Client::sendPlayerInfPacket(const PlayerActorBase *playerBase, bool isYukim } } + /** * @brief sends info related to player's cap actor to server * @@ -553,14 +559,14 @@ void Client::sendGameInfPacket(const PlayerActorHakoniwa* player, GameDataHolder strcpy(packet->stageName, GameDataFunction::getCurrentStageName(holder)); - if(*packet != sInstance->lastGameInfPacket) { + if (*packet != sInstance->lastGameInfPacket && *packet != sInstance->emptyGameInfPacket) { sInstance->lastGameInfPacket = *packet; sInstance->mSocket->queuePacket(packet); } else { sInstance->mHeap->free(packet); // free packet if we're not using it } - } + /** * @brief * Sends only stage info to the server. @@ -584,9 +590,10 @@ void Client::sendGameInfPacket(GameDataHolderAccessor holder) { strcpy(packet->stageName, GameDataFunction::getCurrentStageName(holder)); - sInstance->lastGameInfPacket = *packet; - - sInstance->mSocket->queuePacket(packet); + if (*packet != sInstance->emptyGameInfPacket) { + sInstance->lastGameInfPacket = *packet; + sInstance->mSocket->queuePacket(packet); + } } /** @@ -637,6 +644,8 @@ void Client::sendCostumeInfPacket(const char* body, const char* cap) { return; } + if (!strcmp(body, "") && !strcmp(cap, "")) { return; } + sead::ScopedCurrentHeapSetter setter(sInstance->mHeap); CostumeInf *packet = new CostumeInf(body, cap); @@ -674,6 +683,21 @@ void Client::sendCaptureInfPacket(const PlayerActorHakoniwa* player) { } } +/** + * @brief + */ +void Client::resendInitPackets() { + // CostumeInfPacket + if (lastCostumeInfPacket.mUserID == mUserID) { + mSocket->queuePacket(&lastCostumeInfPacket); + } + + // GameInfPacket + if (lastGameInfPacket != emptyGameInfPacket) { + mSocket->queuePacket(&lastGameInfPacket); + } +} + /** * @brief * @@ -858,6 +882,7 @@ void Client::updatePlayerConnect(PlayerConnect* packet) { mConnectCount++; } } + /** * @brief * diff --git a/source/server/SocketClient.cpp b/source/server/SocketClient.cpp index 08d9349..2389cc7 100644 --- a/source/server/SocketClient.cpp +++ b/source/server/SocketClient.cpp @@ -13,7 +13,9 @@ #include "thread/seadMessageQueue.h" #include "types.h" -SocketClient::SocketClient(const char* name, sead::Heap* heap) : mHeap(heap), SocketBase(name) { +SocketClient::SocketClient(const char* name, sead::Heap* heap, Client* client) : mHeap(heap), SocketBase(name) { + + this->client = client; mRecvThread = new al::AsyncFunctorThread("SocketRecvThread", al::FunctorV0M(this, &SocketClient::recvFunc), 0, 0x1000, {0}); mSendThread = new al::AsyncFunctorThread("SocketSendThread", al::FunctorV0M(this, &SocketClient::sendFunc), 0, 0x1000, {0}); @@ -99,6 +101,11 @@ nn::Result SocketClient::init(const char* ip, u16 port) { send(&initPacket); + // on a reconnect, resend some maybe missing packets + if (initPacket.conType == ConnectionTypes::RECONNECT) { + client->resendInitPackets(); + } + return result; } @@ -357,4 +364,4 @@ void SocketClient::trySendQueue() { Packet* SocketClient::tryGetPacket(sead::MessageQueue::BlockType blockType) { return socket_log_state == SOCKET_LOG_CONNECTED ? (Packet*)mRecvQueue.pop(blockType) : nullptr; -} \ No newline at end of file +}