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 +}