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.
This commit is contained in:
Robin C. Ladiges 2022-09-05 03:21:43 +02:00 committed by Sanae
parent 13c873aae0
commit 36f9343f83
5 changed files with 58 additions and 21 deletions

View file

@ -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); }
};
};

View file

@ -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

View file

@ -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);
typedef void (SocketClient::*SocketThreadFunc)(void);

View file

@ -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
*

View file

@ -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<SocketClient*, SocketThreadFunc>(this, &SocketClient::recvFunc), 0, 0x1000, {0});
mSendThread = new al::AsyncFunctorThread("SocketSendThread", al::FunctorV0M<SocketClient*, SocketThreadFunc>(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;
}
}