Merge branch 'dev' into packet-acceptance

This commit is contained in:
Jack Garrard 2023-09-02 12:58:53 -07:00 committed by GitHub
commit 7064122902
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 215 additions and 217 deletions

View file

@ -11,7 +11,7 @@ inputs:
required : false required : false
default : '' default : ''
emu: emu:
description : 'what system the build is for, Switch or Emulators' description : 'what system the build is for: Switch, Ryujinx or yuzu'
required : false required : false
default : 'Switch' default : 'Switch'
@ -31,8 +31,8 @@ runs:
shell : bash shell : bash
run: | run: |
VERS=${{ inputs.tag }} VERS=${{ inputs.tag }}
echo "::set-output name=version::${VERS:1}" echo "version=${VERS:1}" >>$GITHUB_OUTPUT
echo "::set-output name=filename::${{ inputs.prefix }}SMO_Online${{ (inputs.tag != '' && format('_{0}', inputs.tag)) || '' }}_for_${{ inputs.emu }}" echo "filename=${{ inputs.prefix }}SMO_Online${{ (inputs.tag != '' && format('_{0}', inputs.tag)) || '' }}_for_${{ inputs.emu }}" >>$GITHUB_OUTPUT
- -
name : Set up Docker Buildx name : Set up Docker Buildx
uses : docker/setup-buildx-action@v2 uses : docker/setup-buildx-action@v2
@ -56,11 +56,22 @@ runs:
docker run --rm \ docker run --rm \
-u `id -u`:`id -g` \ -u `id -u`:`id -g` \
-v "/$PWD/":/app/ \ -v "/$PWD/":/app/ \
-e ISEMU=${{ (inputs.emu == 'Emulators' && '1') || '0' }} \ -e ISEMU=${{ (inputs.emu != 'Switch' && '1') || '0' }} \
${{ (steps.env.outputs.version != '' && format('-e BUILDVER={0}', steps.env.outputs.version)) || '' }} \ ${{ (steps.env.outputs.version != '' && format('-e BUILDVER={0}', steps.env.outputs.version)) || '' }} \
smoo-build-env \ smoo-build-env \
; ;
cp -r ./romfs/ ./starlight_patch_100/atmosphere/contents/0100000000010000/. cp -r ./romfs/ ./starlight_patch_100/atmosphere/contents/0100000000010000/.
-
name : Yuzu
shell : bash
if : ${{ inputs.emu == 'yuzu' }}
run: |
cd ./starlight_patch_100/
mkdir ./SMOO/
mv ./atmosphere/contents/0100000000010000/exefs ./SMOO/exefs
mv ./atmosphere/contents/0100000000010000/romfs ./SMOO/romfs
mv ./atmosphere/exefs_patches/StarlightBase/3CA12DFAAF9C82DA064D1698DF79CDA1.ips ./SMOO/exefs/
rm -rf ./atmosphere/
- -
name : Upload artifacts name : Upload artifacts
uses : actions/upload-artifact@v3 uses : actions/upload-artifact@v3

View file

@ -22,7 +22,7 @@ jobs:
build: build:
strategy: strategy:
matrix: matrix:
emu : [ Switch, Emulators ] emu : [ Switch, Ryujinx, yuzu ]
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- -

View file

@ -21,11 +21,12 @@ jobs:
build: build:
strategy: strategy:
matrix: matrix:
emu : [ Switch, Emulators ] emu : [ Switch, Ryujinx, yuzu ]
runs-on: ubuntu-latest runs-on: ubuntu-latest
outputs: outputs:
filename1: ${{ steps.set-output.outputs.filename-Switch }} filename1: ${{ steps.set-output.outputs.filename-Switch }}
filename2: ${{ steps.set-output.outputs.filename-Emulators }} filename2: ${{ steps.set-output.outputs.filename-Ryujinx }}
filename3: ${{ steps.set-output.outputs.filename-yuzu }}
steps: steps:
- -
name : Checkout name : Checkout
@ -35,7 +36,7 @@ jobs:
id : env id : env
shell : bash shell : bash
run: | run: |
echo "::set-output name=prefix::$(date +'%Y%m%d_%H%M%S_' --utc)" echo "prefix=$(date +'%Y%m%d_%H%M%S_' --utc)" >>$GITHUB_OUTPUT
- -
name : Build artifacts name : Build artifacts
id : build id : build
@ -48,7 +49,7 @@ jobs:
id : set-output id : set-output
shell : bash shell : bash
run : | run : |
echo "::set-output name=filename-${{ matrix.emu }}::${{ steps.build.outputs.filename }}" echo "filename-${{ matrix.emu }}=${{ steps.build.outputs.filename }}" >>$GITHUB_OUTPUT
attach: attach:
needs: build needs: build
@ -63,7 +64,7 @@ jobs:
shell : bash shell : bash
run: | run: |
url=`curl -sS --fail ${{ github.api_url }}/repos/${{ github.repository }}/releases/tags/${{ env.TAG }} | jq .upload_url -r` 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" echo "upload_url=$url" >>$GITHUB_OUTPUT
- -
name : Attach build artifacts to release (Switch) name : Attach build artifacts to release (Switch)
uses : ./.github/actions/attach uses : ./.github/actions/attach
@ -72,12 +73,19 @@ jobs:
upload_url : ${{ steps.release.outputs.upload_url }} upload_url : ${{ steps.release.outputs.upload_url }}
GITHUB_TOKEN : ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN : ${{ secrets.GITHUB_TOKEN }}
- -
name : Attach build artifacts to release (Emulators) name : Attach build artifacts to release (Ryujinx)
uses : ./.github/actions/attach uses : ./.github/actions/attach
with: with:
filename : ${{ needs.build.outputs.filename2 }} filename : ${{ needs.build.outputs.filename2 }}
upload_url : ${{ steps.release.outputs.upload_url }} upload_url : ${{ steps.release.outputs.upload_url }}
GITHUB_TOKEN : ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN : ${{ secrets.GITHUB_TOKEN }}
-
name : Attach build artifacts to release (yuzu)
uses : ./.github/actions/attach
with:
filename : ${{ needs.build.outputs.filename3 }}
upload_url : ${{ steps.release.outputs.upload_url }}
GITHUB_TOKEN : ${{ secrets.GITHUB_TOKEN }}
move: move:
needs: attach needs: attach

View file

@ -14,11 +14,12 @@ jobs:
build: build:
strategy: strategy:
matrix: matrix:
emu : [ Switch, Emulators ] emu : [ Switch, Ryujinx, yuzu ]
runs-on: ubuntu-latest runs-on: ubuntu-latest
outputs: outputs:
filename1: ${{ steps.set-output.outputs.filename-Switch }} filename1: ${{ steps.set-output.outputs.filename-Switch }}
filename2: ${{ steps.set-output.outputs.filename-Emulators }} filename2: ${{ steps.set-output.outputs.filename-Ryujinx }}
filename3: ${{ steps.set-output.outputs.filename-yuzu }}
steps: steps:
- -
name : Checkout name : Checkout
@ -59,9 +60,16 @@ jobs:
upload_url : ${{ steps.release.outputs.upload_url }} upload_url : ${{ steps.release.outputs.upload_url }}
GITHUB_TOKEN : ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN : ${{ secrets.GITHUB_TOKEN }}
- -
name : Attach build artifacts to release (Emulators) name : Attach build artifacts to release (Ryujinx)
uses : ./.github/actions/attach uses : ./.github/actions/attach
with: with:
filename : ${{ needs.build.outputs.filename2 }} filename : ${{ needs.build.outputs.filename2 }}
upload_url : ${{ steps.release.outputs.upload_url }} upload_url : ${{ steps.release.outputs.upload_url }}
GITHUB_TOKEN : ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN : ${{ secrets.GITHUB_TOKEN }}
-
name : Attach build artifacts to release (yuzu)
uses : ./.github/actions/attach
with:
filename : ${{ needs.build.outputs.filename3 }}
upload_url : ${{ steps.release.outputs.upload_url }}
GITHUB_TOKEN : ${{ secrets.GITHUB_TOKEN }}

View file

@ -1,26 +1,13 @@
FROM ubuntu:20.04 as builder FROM devkitpro/devkita64:latest as builder
# install dependencies # install dependencies
RUN apt-get update \ RUN apt-get update \
&& apt-get install -y \ && apt-get install -y \
curl \
apt-transport-https \
python3 \ python3 \
python3-pip \ python3-pip \
&& pip install keystone-engine \ && pip3 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/ WORKDIR /app/
ENV DEVKITPRO /opt/devkitpro
ENTRYPOINT make ENTRYPOINT make

View file

@ -29,7 +29,6 @@ class StageSceneStateServerConfig : public al::HostStateBase<al::Scene>, public
enum ServerConfigOption { enum ServerConfigOption {
GAMEMODECONFIG, GAMEMODECONFIG,
GAMEMODESWITCH, GAMEMODESWITCH,
RECONNECT,
SETIP, SETIP,
SETPORT SETPORT
}; };
@ -42,11 +41,9 @@ class StageSceneStateServerConfig : public al::HostStateBase<al::Scene>, public
void exeMainMenu(); void exeMainMenu();
void exeOpenKeyboardIP(); void exeOpenKeyboardIP();
void exeOpenKeyboardPort(); void exeOpenKeyboardPort();
void exeRestartServer();
void exeGamemodeConfig(); void exeGamemodeConfig();
void exeGamemodeSelect(); void exeGamemodeSelect();
void exeSaveData(); void exeSaveData();
void exeConnectError();
void endSubMenu(); void endSubMenu();
@ -63,7 +60,7 @@ class StageSceneStateServerConfig : public al::HostStateBase<al::Scene>, public
SimpleLayoutMenu* mCurrentMenu = nullptr; SimpleLayoutMenu* mCurrentMenu = nullptr;
CommonVerticalList* mCurrentList = nullptr; CommonVerticalList* mCurrentList = nullptr;
// Root Page, contains buttons for gamemode config, server reconnecting, and server ip address changing // Root Page, contains buttons for gamemode config, and server ip address changing
SimpleLayoutMenu* mMainOptions = nullptr; SimpleLayoutMenu* mMainOptions = nullptr;
CommonVerticalList *mMainOptionsList = nullptr; CommonVerticalList *mMainOptionsList = nullptr;
// Sub-Page of Mode config, used to select a gamemode for the client to use // Sub-Page of Mode config, used to select a gamemode for the client to use
@ -86,9 +83,7 @@ namespace {
NERVE_HEADER(StageSceneStateServerConfig, MainMenu) NERVE_HEADER(StageSceneStateServerConfig, MainMenu)
NERVE_HEADER(StageSceneStateServerConfig, OpenKeyboardIP) NERVE_HEADER(StageSceneStateServerConfig, OpenKeyboardIP)
NERVE_HEADER(StageSceneStateServerConfig, OpenKeyboardPort) NERVE_HEADER(StageSceneStateServerConfig, OpenKeyboardPort)
NERVE_HEADER(StageSceneStateServerConfig, RestartServer)
NERVE_HEADER(StageSceneStateServerConfig, GamemodeConfig) NERVE_HEADER(StageSceneStateServerConfig, GamemodeConfig)
NERVE_HEADER(StageSceneStateServerConfig, GamemodeSelect) NERVE_HEADER(StageSceneStateServerConfig, GamemodeSelect)
NERVE_HEADER(StageSceneStateServerConfig, SaveData) NERVE_HEADER(StageSceneStateServerConfig, SaveData)
NERVE_HEADER(StageSceneStateServerConfig, ConnectError) }
}

View file

@ -6,7 +6,7 @@
struct PACKED GameInf : Packet { struct PACKED GameInf : Packet {
GameInf() : Packet() {this->mType = PacketType::GAMEINF; mPacketSize = sizeof(GameInf) - sizeof(Packet);}; GameInf() : Packet() {this->mType = PacketType::GAMEINF; mPacketSize = sizeof(GameInf) - sizeof(Packet);};
bool1 is2D = false; bool1 is2D = false;
u8 scenarioNo = -1; u8 scenarioNo = 255;
char stageName[0x40] = {}; char stageName[0x40] = {};
bool operator==(const GameInf &rhs) const { bool operator==(const GameInf &rhs) const {
@ -19,4 +19,4 @@ struct PACKED GameInf : Packet {
bool operator!=(const GameInf& rhs) const { return !operator==(rhs); } bool operator!=(const GameInf& rhs) const { return !operator==(rhs); }
}; };

View file

@ -88,7 +88,6 @@ class Client {
bool startThread(); bool startThread();
void readFunc(); void readFunc();
static void restartConnection();
static bool isSocketActive() { return sInstance ? sInstance->mSocket->isConnected() : false; }; static bool isSocketActive() { return sInstance ? sInstance->mSocket->isConnected() : false; };
bool isPlayerConnected(int index) { return mPuppetInfoArr[index]->isConnected; } bool isPlayerConnected(int index) { return mPuppetInfoArr[index]->isConnected; }
@ -103,6 +102,7 @@ class Client {
static void sendShineCollectPacket(int shineId); static void sendShineCollectPacket(int shineId);
static void sendTagInfPacket(); static void sendTagInfPacket();
static void sendCaptureInfPacket(const PlayerActorHakoniwa *player); static void sendCaptureInfPacket(const PlayerActorHakoniwa *player);
void resendInitPackets();
int getCollectedShinesCount() { return curCollectedShines.size(); } int getCollectedShinesCount() { return curCollectedShines.size(); }
int getShineID(int index) { if (index < curCollectedShines.size()) { return curCollectedShines[index]; } return -1; } int getShineID(int index) { if (index < curCollectedShines.size()) { return curCollectedShines[index]; } return -1; }
@ -174,11 +174,8 @@ class Client {
static bool openKeyboardIP(); static bool openKeyboardIP();
static bool openKeyboardPort(); static bool openKeyboardPort();
static void showConnect(); static void showUIMessage(const char16_t* msg);
static void hideUIMessage();
static void showConnectError(const char16_t* msg);
static void hideConnect();
void resetCollectedShines(); void resetCollectedShines();
@ -226,7 +223,10 @@ class Client {
// Backups for our last player/game packets, used for example to re-send them for newly connected clients // Backups for our last player/game packets, used for example to re-send them for newly connected clients
PlayerInf lastPlayerInfPacket = PlayerInf(); PlayerInf lastPlayerInfPacket = PlayerInf();
GameInf lastGameInfPacket = GameInf(); GameInf lastGameInfPacket = GameInf();
GameInf emptyGameInfPacket = GameInf();
CostumeInf lastCostumeInfPacket = CostumeInf(); CostumeInf lastCostumeInfPacket = CostumeInf();
TagInf lastTagInfPacket = TagInf();
CaptureInf lastCaptureInfPacket = CaptureInf();
Keyboard* mKeyboard = nullptr; // keyboard for setting server IP Keyboard* mKeyboard = nullptr; // keyboard for setting server IP
@ -238,9 +238,7 @@ class Client {
bool mIsFirstConnect = true; bool mIsFirstConnect = true;
// --- Game Layouts --- // --- Game Layouts ---
al::WindowConfirmWait* mUIMessage;
al::WindowConfirmWait* mConnectionWait;
al::SimpleLayoutAppearWaitEnd *mConnectStatus; al::SimpleLayoutAppearWaitEnd *mConnectStatus;
// --- Game Info --- // --- Game Info ---

View file

@ -20,9 +20,11 @@
#include "packets/Packet.h" #include "packets/Packet.h"
class Client;
class SocketClient : public SocketBase { class SocketClient : public SocketBase {
public: 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; nn::Result init(const char* ip, u16 port) override;
bool tryReconnect(); bool tryReconnect();
bool closeSocket() override; bool closeSocket() override;
@ -58,6 +60,7 @@ class SocketClient : public SocketBase {
private: private:
sead::Heap* mHeap = nullptr; sead::Heap* mHeap = nullptr;
Client* client = nullptr;
al::AsyncFunctorThread* mRecvThread = nullptr; al::AsyncFunctorThread* mRecvThread = nullptr;
al::AsyncFunctorThread* mSendThread = nullptr; al::AsyncFunctorThread* mSendThread = nullptr;
@ -78,4 +81,4 @@ class SocketClient : public SocketBase {
bool stringToIPAddress(const char* str, in_addr* out); bool stringToIPAddress(const char* str, in_addr* out);
}; };
typedef void (SocketClient::*SocketThreadFunc)(void); typedef void (SocketClient::*SocketThreadFunc)(void);

View file

@ -9,11 +9,13 @@ public:
HideAndSeekConfigMenu(); HideAndSeekConfigMenu();
void initMenu(const al::LayoutInitInfo &initInfo) override; void initMenu(const al::LayoutInitInfo &initInfo) override;
const sead::WFixedSafeString<0x200> *getStringData() override; const sead::WFixedSafeString<0x200>* getStringData() override;
bool updateMenu(int selectIndex) override; bool updateMenu(int selectIndex) override;
const int getMenuSize() override { return mItemCount; } const int getMenuSize() override { return mItemCount; }
private: private:
static constexpr int mItemCount = 2; static constexpr int mItemCount = 1;
}; sead::SafeArray<sead::WFixedSafeString<0x200>, mItemCount>* gravityOn = nullptr;
sead::SafeArray<sead::WFixedSafeString<0x200>, mItemCount>* gravityOff = nullptr;
};

View file

@ -27,7 +27,7 @@ Client::Client() {
mKeyboard = new Keyboard(nn::swkbd::GetRequiredStringBufferSize()); mKeyboard = new Keyboard(nn::swkbd::GetRequiredStringBufferSize());
mSocket = new SocketClient("SocketClient", mHeap); mSocket = new SocketClient("SocketClient", mHeap, this);
mPuppetHolder = new PuppetHolder(maxPuppets); mPuppetHolder = new PuppetHolder(maxPuppets);
@ -71,22 +71,21 @@ Client::Client() {
*/ */
void Client::init(al::LayoutInitInfo const &initInfo, GameDataHolderAccessor holder) { void Client::init(al::LayoutInitInfo const &initInfo, GameDataHolderAccessor holder) {
mConnectionWait = new (mHeap) al::WindowConfirmWait("ServerWaitConnect", "WindowConfirmWait", initInfo);
mConnectStatus = new (mHeap) al::SimpleLayoutAppearWaitEnd("", "SaveMessage", initInfo, 0, false); mConnectStatus = new (mHeap) al::SimpleLayoutAppearWaitEnd("", "SaveMessage", initInfo, 0, false);
mConnectionWait->setTxtMessage(u"Connecting to Server.");
mConnectionWait->setTxtMessageConfirm(u"Failed to Connect!");
al::setPaneString(mConnectStatus, "TxtSave", u"Connecting to Server.", 0); al::setPaneString(mConnectStatus, "TxtSave", u"Connecting to Server.", 0);
al::setPaneString(mConnectStatus, "TxtSaveSh", u"Connecting to Server.", 0); al::setPaneString(mConnectStatus, "TxtSaveSh", u"Connecting to Server.", 0);
mUIMessage = new (mHeap) al::WindowConfirmWait("ServerWaitConnect", "WindowConfirmWait", initInfo);
mUIMessage->setTxtMessage(u"a");
mUIMessage->setTxtMessageConfirm(u"b");
mHolder = holder; mHolder = holder;
startThread(); startThread();
Logger::log("Heap Free Size: %f/%f\n", mHeap->getFreeSize() * 0.001f, mHeap->getSize() * 0.001f); Logger::log("Heap Free Size: %f/%f\n", mHeap->getFreeSize() * 0.001f, mHeap->getSize() * 0.001f);
} }
/** /**
* @brief starts client read thread * @brief starts client read thread
* *
@ -103,49 +102,7 @@ bool Client::startThread() {
return false; return false;
} }
} }
/**
* @brief restarts currently active connection to server
*
*/
void Client::restartConnection() {
if (!sInstance) {
Logger::log("Static Instance is null!\n");
return;
}
sead::ScopedCurrentHeapSetter setter(sInstance->mHeap);
Logger::log("Sending Disconnect.\n");
PlayerDC *playerDC = new PlayerDC();
playerDC->mUserID = sInstance->mUserID;
sInstance->mSocket->setQueueOpen(false);
sInstance->mSocket->clearMessageQueues();
sInstance->mSocket->send(playerDC);
sInstance->mHeap->free(playerDC);
if (sInstance->mSocket->closeSocket()) {
Logger::log("Sucessfully Closed Socket.\n");
}
sInstance->mConnectCount = 0;
sInstance->mIsConnectionActive = sInstance->mSocket->init(sInstance->mServerIP.cstr(), sInstance->mServerPort).isSuccess();
if(sInstance->mSocket->getLogState() == SOCKET_LOG_CONNECTED) {
Logger::log("Reconnect Sucessful!\n");
} else {
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. * @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.
* *
@ -296,6 +253,33 @@ bool Client::openKeyboardPort() {
return isFirstConnect; return isFirstConnect;
} }
void Client::showUIMessage(const char16_t* msg) {
if (!sInstance) {
return;
}
sInstance->mUIMessage->setTxtMessageConfirm(msg);
al::hidePane(sInstance->mUIMessage, "Page01"); // hide A button prompt
if (!sInstance->mUIMessage->mIsAlive) {
sInstance->mUIMessage->appear();
sInstance->mUIMessage->playLoop();
}
al::startAction(sInstance->mUIMessage, "Confirm", "State");
}
void Client::hideUIMessage() {
if (!sInstance) {
return;
}
sInstance->mUIMessage->tryEnd();
}
/** /**
* @brief main thread function for read thread, responsible for processing packets from server * @brief main thread function for read thread, responsible for processing packets from server
* *
@ -352,16 +336,22 @@ void Client::readFunc() {
// Send relevant info packets when another client is connected // Send relevant info packets when another client is connected
// Assume game packets are empty from first connection if (lastGameInfPacket != emptyGameInfPacket) {
if (lastGameInfPacket.mUserID != mUserID) // Assume game packets are empty from first connection
lastGameInfPacket.mUserID = mUserID; if (lastGameInfPacket.mUserID != mUserID)
mSocket->send(&lastGameInfPacket); lastGameInfPacket.mUserID = mUserID;
mSocket->send(&lastGameInfPacket);
}
// No need to send player/costume packets if they're empty // No need to send player/costume packets if they're empty
if (lastPlayerInfPacket.mUserID == mUserID) if (lastPlayerInfPacket.mUserID == mUserID)
mSocket->send(&lastPlayerInfPacket); mSocket->send(&lastPlayerInfPacket);
if (lastCostumeInfPacket.mUserID == mUserID) if (lastCostumeInfPacket.mUserID == mUserID)
mSocket->send(&lastCostumeInfPacket); mSocket->send(&lastCostumeInfPacket);
if (lastTagInfPacket.mUserID == mUserID)
mSocket->send(&lastTagInfPacket);
if (lastCaptureInfPacket.mUserID == mUserID)
mSocket->send(&lastCaptureInfPacket);
break; break;
case PacketType::COSTUMEINF: case PacketType::COSTUMEINF:
@ -485,6 +475,7 @@ void Client::sendPlayerInfPacket(const PlayerActorBase *playerBase, bool isYukim
} }
} }
/** /**
* @brief sends info related to player's cap actor to server * @brief sends info related to player's cap actor to server
* *
@ -559,14 +550,14 @@ void Client::sendGameInfPacket(const PlayerActorHakoniwa* player, GameDataHolder
strcpy(packet->stageName, GameDataFunction::getCurrentStageName(holder)); strcpy(packet->stageName, GameDataFunction::getCurrentStageName(holder));
if(*packet != sInstance->lastGameInfPacket) { if (*packet != sInstance->lastGameInfPacket && *packet != sInstance->emptyGameInfPacket) {
sInstance->lastGameInfPacket = *packet; sInstance->lastGameInfPacket = *packet;
sInstance->mSocket->queuePacket(packet); sInstance->mSocket->queuePacket(packet);
} else { } else {
sInstance->mHeap->free(packet); // free packet if we're not using it sInstance->mHeap->free(packet); // free packet if we're not using it
} }
} }
/** /**
* @brief * @brief
* Sends only stage info to the server. * Sends only stage info to the server.
@ -590,9 +581,10 @@ void Client::sendGameInfPacket(GameDataHolderAccessor holder) {
strcpy(packet->stageName, GameDataFunction::getCurrentStageName(holder)); strcpy(packet->stageName, GameDataFunction::getCurrentStageName(holder));
sInstance->lastGameInfPacket = *packet; if (*packet != sInstance->emptyGameInfPacket) {
sInstance->lastGameInfPacket = *packet;
sInstance->mSocket->queuePacket(packet); sInstance->mSocket->queuePacket(packet);
}
} }
/** /**
@ -621,13 +613,15 @@ void Client::sendTagInfPacket() {
packet->mUserID = sInstance->mUserID; packet->mUserID = sInstance->mUserID;
packet->isIt = hsMode->isPlayerIt(); packet->isIt = hsMode->isPlayerIt() && hsMode->isModeActive();
packet->minutes = curInfo->mHidingTime.mMinutes; packet->minutes = curInfo->mHidingTime.mMinutes;
packet->seconds = curInfo->mHidingTime.mSeconds; packet->seconds = curInfo->mHidingTime.mSeconds;
packet->updateType = static_cast<TagUpdateType>(TagUpdateType::STATE | TagUpdateType::TIME); packet->updateType = static_cast<TagUpdateType>(TagUpdateType::STATE | TagUpdateType::TIME);
sInstance->mSocket->queuePacket(packet); sInstance->mSocket->queuePacket(packet);
sInstance->lastTagInfPacket = *packet;
} }
/** /**
@ -643,6 +637,8 @@ void Client::sendCostumeInfPacket(const char* body, const char* cap) {
return; return;
} }
if (!strcmp(body, "") && !strcmp(cap, "")) { return; }
sead::ScopedCurrentHeapSetter setter(sInstance->mHeap); sead::ScopedCurrentHeapSetter setter(sInstance->mHeap);
CostumeInf *packet = new CostumeInf(body, cap); CostumeInf *packet = new CostumeInf(body, cap);
@ -670,16 +666,43 @@ void Client::sendCaptureInfPacket(const PlayerActorHakoniwa* player) {
packet->mUserID = sInstance->mUserID; packet->mUserID = sInstance->mUserID;
strcpy(packet->hackName, tryConvertName(player->mHackKeeper->getCurrentHackName())); strcpy(packet->hackName, tryConvertName(player->mHackKeeper->getCurrentHackName()));
sInstance->mSocket->queuePacket(packet); sInstance->mSocket->queuePacket(packet);
sInstance->lastCaptureInfPacket = *packet;
sInstance->isSentCaptureInf = true; sInstance->isSentCaptureInf = true;
} else if (!sInstance->isClientCaptured && sInstance->isSentCaptureInf) { } else if (!sInstance->isClientCaptured && sInstance->isSentCaptureInf) {
CaptureInf *packet = new CaptureInf(); CaptureInf *packet = new CaptureInf();
packet->mUserID = sInstance->mUserID; packet->mUserID = sInstance->mUserID;
strcpy(packet->hackName, ""); strcpy(packet->hackName, "");
sInstance->mSocket->queuePacket(packet); sInstance->mSocket->queuePacket(packet);
sInstance->lastCaptureInfPacket = *packet;
sInstance->isSentCaptureInf = false; sInstance->isSentCaptureInf = false;
} }
} }
/**
* @brief
*/
void Client::resendInitPackets() {
// CostumeInfPacket
if (lastCostumeInfPacket.mUserID == mUserID) {
mSocket->queuePacket(&lastCostumeInfPacket);
}
// GameInfPacket
if (lastGameInfPacket != emptyGameInfPacket) {
mSocket->queuePacket(&lastGameInfPacket);
}
// TagInfPacket
if (lastTagInfPacket.mUserID == mUserID) {
mSocket->queuePacket(&lastTagInfPacket);
}
// CaptureInfPacket
if (lastCaptureInfPacket.mUserID == mUserID) {
mSocket->queuePacket(&lastCaptureInfPacket);
}
}
/** /**
* @brief * @brief
* *
@ -864,6 +887,7 @@ void Client::updatePlayerConnect(PlayerConnect* packet) {
mConnectCount++; mConnectCount++;
} }
} }
/** /**
* @brief * @brief
* *
@ -1374,37 +1398,3 @@ Shine* Client::findStageShine(int shineID) {
} }
return nullptr; 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();
}

View file

@ -13,7 +13,9 @@
#include "thread/seadMessageQueue.h" #include "thread/seadMessageQueue.h"
#include "types.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}); 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}); mSendThread = new al::AsyncFunctorThread("SocketSendThread", al::FunctorV0M<SocketClient*, SocketThreadFunc>(this, &SocketClient::sendFunc), 0, 0x1000, {0});
@ -101,6 +103,26 @@ nn::Result SocketClient::init(const char* ip, u16 port) {
send(&initPacket); send(&initPacket);
// on a reconnect, resend some maybe missing packets
if (initPacket.conType == ConnectionTypes::RECONNECT) {
client->resendInitPackets();
} else {
// empty TagInf
TagInf tagInf;
tagInf.mUserID = initPacket.mUserID;
tagInf.isIt = false;
tagInf.minutes = 0;
tagInf.seconds = 0;
tagInf.updateType = static_cast<TagUpdateType>(TagUpdateType::STATE | TagUpdateType::TIME);
send(&tagInf);
// empty CaptureInf
CaptureInf capInf;
capInf.mUserID = initPacket.mUserID;
strcpy(capInf.hackName, "");
send(&capInf);
}
return result; return result;
} }

View file

@ -5,20 +5,27 @@
#include "server/hns/HideAndSeekMode.hpp" #include "server/hns/HideAndSeekMode.hpp"
#include "server/Client.hpp" #include "server/Client.hpp"
HideAndSeekConfigMenu::HideAndSeekConfigMenu() : GameModeConfigMenu() {} HideAndSeekConfigMenu::HideAndSeekConfigMenu() : GameModeConfigMenu() {
gravityOn = new sead::SafeArray<sead::WFixedSafeString<0x200>, mItemCount>();
gravityOn->mBuffer[0].copy(u"Toggle H&S Gravity (ON)");
gravityOff = new sead::SafeArray<sead::WFixedSafeString<0x200>, mItemCount>();
gravityOff->mBuffer[0].copy(u"Toggle H&S Gravity (OFF)");
}
void HideAndSeekConfigMenu::initMenu(const al::LayoutInitInfo &initInfo) { void HideAndSeekConfigMenu::initMenu(const al::LayoutInitInfo &initInfo) {
} }
const sead::WFixedSafeString<0x200> *HideAndSeekConfigMenu::getStringData() { const sead::WFixedSafeString<0x200>* HideAndSeekConfigMenu::getStringData() {
sead::SafeArray<sead::WFixedSafeString<0x200>, mItemCount>* gamemodeConfigOptions = HideAndSeekInfo *curMode = GameModeManager::instance()->getInfo<HideAndSeekInfo>();
new sead::SafeArray<sead::WFixedSafeString<0x200>, mItemCount>(); return (
GameModeManager::instance()->isMode(GameMode::HIDEANDSEEK)
gamemodeConfigOptions->mBuffer[0].copy(u"Toggle H&S Gravity On"); && curMode != nullptr
gamemodeConfigOptions->mBuffer[1].copy(u"Toggle H&S Gravity Off"); && curMode->mIsUseGravity
? gravityOn->mBuffer
return gamemodeConfigOptions->mBuffer; : gravityOff->mBuffer
);
} }
bool HideAndSeekConfigMenu::updateMenu(int selectIndex) { bool HideAndSeekConfigMenu::updateMenu(int selectIndex) {
@ -35,13 +42,7 @@ bool HideAndSeekConfigMenu::updateMenu(int selectIndex) {
switch (selectIndex) { switch (selectIndex) {
case 0: { case 0: {
if (GameModeManager::instance()->isMode(GameMode::HIDEANDSEEK)) { if (GameModeManager::instance()->isMode(GameMode::HIDEANDSEEK)) {
curMode->mIsUseGravity = true; curMode->mIsUseGravity = !curMode->mIsUseGravity;
}
return true;
}
case 1: {
if (GameModeManager::instance()->isMode(GameMode::HIDEANDSEEK)) {
curMode->mIsUseGravity = false;
} }
return true; return true;
} }
@ -50,4 +51,4 @@ bool HideAndSeekConfigMenu::updateMenu(int selectIndex) {
return false; return false;
} }
} }

View file

@ -84,6 +84,8 @@ void HideAndSeekMode::begin() {
playGuideLyt->end(); playGuideLyt->end();
GameModeBase::begin(); GameModeBase::begin();
Client::sendTagInfPacket();
} }
void HideAndSeekMode::end() { void HideAndSeekMode::end() {
@ -109,6 +111,8 @@ void HideAndSeekMode::end() {
playGuideLyt->appear(); playGuideLyt->appear();
GameModeBase::end(); GameModeBase::end();
Client::sendTagInfPacket();
} }
void HideAndSeekMode::update() { void HideAndSeekMode::update() {

View file

@ -41,14 +41,13 @@ StageSceneStateServerConfig::StageSceneStateServerConfig(const char *name, al::S
mMainOptionsList->unkInt1 = 1; mMainOptionsList->unkInt1 = 1;
mMainOptionsList->initDataNoResetSelected(5); mMainOptionsList->initDataNoResetSelected(4);
sead::SafeArray<sead::WFixedSafeString<0x200>, 5>* mainMenuOptions = sead::SafeArray<sead::WFixedSafeString<0x200>, 4>* mainMenuOptions =
new sead::SafeArray<sead::WFixedSafeString<0x200>, 5>(); new sead::SafeArray<sead::WFixedSafeString<0x200>, 4>();
mainMenuOptions->mBuffer[ServerConfigOption::GAMEMODECONFIG].copy(u"Gamemode Config"); mainMenuOptions->mBuffer[ServerConfigOption::GAMEMODECONFIG].copy(u"Gamemode Config");
mainMenuOptions->mBuffer[ServerConfigOption::GAMEMODESWITCH].copy(u"Change Gamemode"); 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::SETIP].copy(u"Change Server IP");
mainMenuOptions->mBuffer[ServerConfigOption::SETPORT].copy(u"Change Server Port"); mainMenuOptions->mBuffer[ServerConfigOption::SETPORT].copy(u"Change Server Port");
@ -101,11 +100,6 @@ StageSceneStateServerConfig::StageSceneStateServerConfig(const char *name, al::S
entry.mList = new CommonVerticalList(entry.mLayout, initInfo, true); entry.mList = new CommonVerticalList(entry.mLayout, initInfo, true);
al::setPaneString(entry.mLayout, "TxtOption", u"Gamemode Configuration", 0); al::setPaneString(entry.mLayout, "TxtOption", u"Gamemode Configuration", 0);
entry.mList->initDataNoResetSelected(entry.mMenu->getMenuSize());
entry.mList->addStringData(entry.mMenu->getStringData(), "TxtContent");
} }
@ -115,6 +109,15 @@ StageSceneStateServerConfig::StageSceneStateServerConfig(const char *name, al::S
void StageSceneStateServerConfig::init() { void StageSceneStateServerConfig::init() {
initNerve(&nrvStageSceneStateServerConfigMainMenu, 0); initNerve(&nrvStageSceneStateServerConfigMainMenu, 0);
#ifdef EMU
char ryujinx[0x10] = { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
nn::account::Uid user;
nn::account::GetLastOpenedUser(&user);
if (memcmp(user.data, ryujinx, 0x10) == 0) {
Client::showUIMessage(u"Error: Ryujinx default profile detected.\nYou have to create a new user profile!");
}
#endif
} }
void StageSceneStateServerConfig::appear(void) { void StageSceneStateServerConfig::appear(void) {
@ -176,10 +179,6 @@ void StageSceneStateServerConfig::exeMainMenu() {
al::setNerve(this, &nrvStageSceneStateServerConfigGamemodeSelect); al::setNerve(this, &nrvStageSceneStateServerConfigGamemodeSelect);
break; break;
} }
case ServerConfigOption::RECONNECT: {
al::setNerve(this, &nrvStageSceneStateServerConfigRestartServer);
break;
}
case ServerConfigOption::SETIP: { case ServerConfigOption::SETIP: {
al::setNerve(this, &nrvStageSceneStateServerConfigOpenKeyboardIP); al::setNerve(this, &nrvStageSceneStateServerConfigOpenKeyboardIP);
break; break;
@ -233,32 +232,16 @@ void StageSceneStateServerConfig::exeOpenKeyboardPort() {
} }
} }
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);
}
}
void StageSceneStateServerConfig::exeGamemodeConfig() { void StageSceneStateServerConfig::exeGamemodeConfig() {
if (al::isFirstStep(this)) { if (al::isFirstStep(this)) {
mGamemodeConfigMenu = &mGamemodeConfigMenus[GameModeManager::instance()->getGameMode()]; mGamemodeConfigMenu = &mGamemodeConfigMenus[GameModeManager::instance()->getGameMode()];
mGamemodeConfigMenu->mList->initDataNoResetSelected(mGamemodeConfigMenu->mMenu->getMenuSize());
mGamemodeConfigMenu->mList->addStringData(mGamemodeConfigMenu->mMenu->getStringData(), "TxtContent");
mCurrentList = mGamemodeConfigMenu->mList; mCurrentList = mGamemodeConfigMenu->mList;
mCurrentMenu = mGamemodeConfigMenu->mLayout; mCurrentMenu = mGamemodeConfigMenu->mLayout;
subMenuStart(); subMenuStart();
} }
@ -290,18 +273,6 @@ 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() { void StageSceneStateServerConfig::exeSaveData() {
if (al::isFirstStep(this)) { if (al::isFirstStep(this)) {
@ -373,9 +344,7 @@ namespace {
NERVE_IMPL(StageSceneStateServerConfig, MainMenu) NERVE_IMPL(StageSceneStateServerConfig, MainMenu)
NERVE_IMPL(StageSceneStateServerConfig, OpenKeyboardIP) NERVE_IMPL(StageSceneStateServerConfig, OpenKeyboardIP)
NERVE_IMPL(StageSceneStateServerConfig, OpenKeyboardPort) NERVE_IMPL(StageSceneStateServerConfig, OpenKeyboardPort)
NERVE_IMPL(StageSceneStateServerConfig, RestartServer)
NERVE_IMPL(StageSceneStateServerConfig, GamemodeConfig) NERVE_IMPL(StageSceneStateServerConfig, GamemodeConfig)
NERVE_IMPL(StageSceneStateServerConfig, GamemodeSelect) NERVE_IMPL(StageSceneStateServerConfig, GamemodeSelect)
NERVE_IMPL(StageSceneStateServerConfig, SaveData) NERVE_IMPL(StageSceneStateServerConfig, SaveData)
NERVE_IMPL(StageSceneStateServerConfig, ConnectError) }
}