Compare commits
79 Commits
Author | SHA1 | Date |
---|---|---|
Jack Garrard | ad79fe1732 | |
Jack Garrard | ca5cef2ff4 | |
Jack Garrard | f548de2117 | |
Jack Garrard | cdac0a8679 | |
Jack Garrard | cf97f2b214 | |
Jack Garrard | 6b81465197 | |
Jack Garrard | 800ade7842 | |
Jack Garrard | d0dfb63519 | |
Robin C. Ladiges | b4d90d1d85 | |
Jack Garrard | f27875f65f | |
Jack Garrard | 44f8ece7ce | |
Jack Garrard | 83a1d70e01 | |
Jack Garrard | 1da9626a44 | |
Jack Garrard | 8acb8700bf | |
Jack Garrard | d5b49b2ea9 | |
Jack Garrard | 7064122902 | |
Jack Garrard | 8d94cf7856 | |
Jack Garrard | 9bf07b3e0d | |
Jack Garrard | 125e2bdde2 | |
Robin C. Ladiges | 45cd4442c8 | |
Robin C. Ladiges | c736878df1 | |
Robin C. Ladiges | 366ad5e888 | |
Robin C. Ladiges | f810e8f07d | |
Robin C. Ladiges | 2bef6f796e | |
Robin C. Ladiges | 4835692672 | |
Robin C. Ladiges | 27b9a095f7 | |
Piplup | b86322f346 | |
piplup | 936e0fd49f | |
piplup | 4d242a5e44 | |
piplup | 41719e1f9f | |
piplup | f8a3deefc4 | |
piplup | cd8bf4e257 | |
Jack Garrard | 76d61a8067 | |
Jack Garrard | 8c992649fd | |
Jack Garrard | 477f1c9e7d | |
Jack Garrard | 4ab6b56598 | |
Jack Garrard | 158f782a2a | |
Jack Garrard | 7e128679ab | |
Jack Garrard | 1fc3a78943 | |
Jack Garrard | 627e07cd65 | |
Jack Garrard | 57333d71e9 | |
Jack Garrard | 4171390f42 | |
Jack Garrard | 5c04bb1006 | |
Jack Garrard | 04fc8cb309 | |
Jack Garrard | a58471c19f | |
Jack Garrard | 0147f4d738 | |
Jack Garrard | 000d24a7db | |
Jack Garrard | 78b532a316 | |
Jack Garrard | efef24fbbe | |
Jack Garrard | 3e5c0c89e5 | |
Jack Garrard | 64b56c32da | |
Jack Garrard | 89415e6f96 | |
Jack Garrard | e6871da878 | |
Jack Garrard | 24e724a824 | |
Jack Garrard | 28c7f92453 | |
Jack Garrard | 4a5a10f910 | |
Jack Garrard | bf646b2b3d | |
Jack Garrard | 53f91b8695 | |
Jack Garrard | a9c3ec4006 | |
Jack Garrard | 4655b0755e | |
Jack Garrard | 93c750ccf7 | |
Jack Garrard | 655368241f | |
Jack Garrard | ed83827cc1 | |
Jack Garrard | 2654650804 | |
Jack Garrard | 694c9e73d6 | |
Jack Garrard | 968f513bf2 | |
Jack Garrard | 7c17db2d93 | |
Jack Garrard | ba7612a304 | |
Jack Garrard | d666707e24 | |
Jack Garrard | 1fd02147b6 | |
Jack Garrard | f6408e2b1e | |
Jack Garrard | 2f5ed106fa | |
Jack Garrard | b163749c77 | |
Jack Garrard | 009755ceba | |
Jack Garrard | f417d39f3b | |
Jack Garrard | 66c8bb9e1b | |
Jack Garrard | 19c6d800bd | |
Jack Garrard | 1204e27adb | |
Jack Garrard | b18671f113 |
|
@ -11,7 +11,7 @@ inputs:
|
|||
required : false
|
||||
default : ''
|
||||
emu:
|
||||
description : 'what system the build is for: Switch, Ryujinx or yuzu'
|
||||
description : 'what system the build is for: Switch or Emulators'
|
||||
required : false
|
||||
default : 'Switch'
|
||||
|
||||
|
@ -62,9 +62,9 @@ runs:
|
|||
;
|
||||
cp -r ./romfs/ ./starlight_patch_100/atmosphere/contents/0100000000010000/.
|
||||
-
|
||||
name : Yuzu
|
||||
name : Emulators
|
||||
shell : bash
|
||||
if : ${{ inputs.emu == 'yuzu' }}
|
||||
if : ${{ inputs.emu == 'Emulators' }}
|
||||
run: |
|
||||
cd ./starlight_patch_100/
|
||||
mkdir ./SMOO/
|
||||
|
|
|
@ -22,7 +22,7 @@ jobs:
|
|||
build:
|
||||
strategy:
|
||||
matrix:
|
||||
emu : [ Switch, Ryujinx, yuzu ]
|
||||
emu : [ Switch, Emulators ]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
-
|
||||
|
|
|
@ -21,12 +21,11 @@ jobs:
|
|||
build:
|
||||
strategy:
|
||||
matrix:
|
||||
emu : [ Switch, Ryujinx, yuzu ]
|
||||
emu : [ Switch, Emulators ]
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
filename1: ${{ steps.set-output.outputs.filename-Switch }}
|
||||
filename2: ${{ steps.set-output.outputs.filename-Ryujinx }}
|
||||
filename3: ${{ steps.set-output.outputs.filename-yuzu }}
|
||||
filename2: ${{ steps.set-output.outputs.filename-Emulators }}
|
||||
steps:
|
||||
-
|
||||
name : Checkout
|
||||
|
@ -73,19 +72,12 @@ jobs:
|
|||
upload_url : ${{ steps.release.outputs.upload_url }}
|
||||
GITHUB_TOKEN : ${{ secrets.GITHUB_TOKEN }}
|
||||
-
|
||||
name : Attach build artifacts to release (Ryujinx)
|
||||
name : Attach build artifacts to release (Emulators)
|
||||
uses : ./.github/actions/attach
|
||||
with:
|
||||
filename : ${{ needs.build.outputs.filename2 }}
|
||||
upload_url : ${{ steps.release.outputs.upload_url }}
|
||||
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:
|
||||
needs: attach
|
||||
|
|
|
@ -14,12 +14,11 @@ jobs:
|
|||
build:
|
||||
strategy:
|
||||
matrix:
|
||||
emu : [ Switch, Ryujinx, yuzu ]
|
||||
emu : [ Switch, Emulators ]
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
filename1: ${{ steps.set-output.outputs.filename-Switch }}
|
||||
filename2: ${{ steps.set-output.outputs.filename-Ryujinx }}
|
||||
filename3: ${{ steps.set-output.outputs.filename-yuzu }}
|
||||
filename2: ${{ steps.set-output.outputs.filename-Emulators }}
|
||||
steps:
|
||||
-
|
||||
name : Checkout
|
||||
|
@ -60,16 +59,9 @@ jobs:
|
|||
upload_url : ${{ steps.release.outputs.upload_url }}
|
||||
GITHUB_TOKEN : ${{ secrets.GITHUB_TOKEN }}
|
||||
-
|
||||
name : Attach build artifacts to release (Ryujinx)
|
||||
name : Attach build artifacts to release (Emulators)
|
||||
uses : ./.github/actions/attach
|
||||
with:
|
||||
filename : ${{ needs.build.outputs.filename2 }}
|
||||
upload_url : ${{ steps.release.outputs.upload_url }}
|
||||
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 }}
|
||||
|
|
10
Makefile
10
Makefile
|
@ -45,15 +45,15 @@ emu:
|
|||
mv $(shell basename $(CURDIR))$(SMOVER).nso starlight_patch_$(SMOVER)/yuzu/subsdk1
|
||||
# builds and sends project to FTP server hosted on provided IP
|
||||
send: all
|
||||
python3.8 scripts/sendPatch.py $(IP) $(PROJNAME)
|
||||
python3 scripts/sendPatch.py $(IP) $(PROJNAME)
|
||||
|
||||
log: all
|
||||
python3.8 scripts/tcpServer.py $(SERVERIP)
|
||||
python3 scripts/tcpServer.py $(SERVERIP)
|
||||
|
||||
sendlog: all
|
||||
python3.8 scripts/sendPatch.py $(IP) $(PROJNAME) $(USER) $(PASS)
|
||||
python3.8 scripts/tcpServer.py $(SERVERIP)
|
||||
python3 scripts/sendPatch.py $(IP) $(PROJNAME) $(USER) $(PASS)
|
||||
python3 scripts/tcpServer.py $(SERVERIP)
|
||||
|
||||
clean:
|
||||
$(MAKE) clean -f MakefileNSO
|
||||
@rm -fr starlight_patch_*
|
||||
@rm -fr starlight_patch_*
|
||||
|
|
68
README.md
68
README.md
|
@ -10,63 +10,45 @@ Welcome to the official repository for the Super Mario Odyssey Online mod! Have
|
|||
* Moon Collection is shared between all players
|
||||
* Custom Configuration Menu (Accessible by holding ZL and selecting any option in the pause/start menu)
|
||||
* Support for custom gamemodes (WIP)
|
||||
### Available Gamemodes
|
||||
* Hide and Seek
|
||||
|
||||
|
||||
## SMO Version Support
|
||||
## Installation and Usage
|
||||
For the typical installation along with how to setup and use muliplayer/hide and seek, please visit the [Super Mario Odyssey Online website](https://smoo.it).
|
||||
|
||||
* 1.0
|
||||
<details>
|
||||
|
||||
## Installation Tutorial
|
||||
<summary>Developer build instructions</summary>
|
||||
|
||||
Before installing, Ensure that your switch is hacked. If not, follow [This Guide](https://switch.homebrew.guide/) to get your switch setup for modding. Make sure you set up a way to block Nintendo's servers as you will need to have your switch connected to the internet for this mod to work!
|
||||
### Building Prerequisites
|
||||
|
||||
1. Download the latest mod build from either [Gamebanana](https://gamebanana.com/mods/384214) or from the [Releases](https://github.com/CraftyBoss/SuperMarioOdysseyOnline/releases) tab. (Alternatively, build from source)
|
||||
2. Extract the downloaded zip onto the root of your Switch's SD card.
|
||||
3. If you need to host an online server, head over to the [Super Mario Odyssey Online Server](https://github.com/Sanae6/SmoOnlineServer) repository and follow the instructions there to set up the server.
|
||||
4. Launch the game! Upon first time bootup, the mod should ask for a server IP to save to the games common save file. This IP address will be the server you wish to connect to every time you launch the game with the mod installed. (Note: un-installing the mod and launching the game will remove the server IP from the common save file.)
|
||||
- [devkitPro](https://devkitpro.org/)
|
||||
- Python 3
|
||||
- The [Keystone-Engine](https://www.keystone-engine.org/) Python Module
|
||||
|
||||
## Gamemode Info
|
||||
### Hide and Seek
|
||||
* Depending on Group size, select who will start as seekers at the beginning of each round and a kingdom to hide in.
|
||||
* Each player has a timer on the top right of the screen that will increase while they are hiding during a round.
|
||||
* When a seeker gets close enough to a player, the player will die and respawn as a seeker.
|
||||
* During the round, hiders who die by other means will also become seekers upon respawning.
|
||||
* If a hider loads into a new stage (via a pipe, door, etc.) the hider will get 5 seconds of tag invincibility to prevent spawn point camping.
|
||||
* The player with the most time at the end of a round (or set of rounds) is considered the winner.
|
||||
* While not a concrete rule, it's generally agreed upon that hiding should not be done out of bounds, inside objects that don't sync across games yet, and inside objects that completely conceal a player from others (such as trees).
|
||||
### Building
|
||||
|
||||
## Gamemode Controls
|
||||
### Hide and Seek
|
||||
- Left D-Pad: Decrease time
|
||||
- Right D-Pad: Increase Time
|
||||
- L + D-Pad Down: Reset Time
|
||||
- D-Pad Up: Switch from Hider/Seeker
|
||||
Build has only been tested on WSL2 running Ubuntu 20.04.1.
|
||||
|
||||
## Building Prerequisites
|
||||
Just run:
|
||||
```
|
||||
DEVKITPRO={path_to_devkitpro} make
|
||||
```
|
||||
|
||||
- [devkitPro](https://devkitpro.org/)
|
||||
- Python 3
|
||||
- The [Keystone-Engine](https://www.keystone-engine.org/) Python Module
|
||||
On Ubuntu (and other Debian-based systems), devkitPro will be installed to `/opt/devkitpro` by default:
|
||||
|
||||
## Building
|
||||
```
|
||||
DEVKITPRO=/opt/devkitpro/ make
|
||||
```
|
||||
|
||||
Build has only been tested on WSL2 running Ubuntu 20.04.1.
|
||||
### Installing (Atmosphère)
|
||||
|
||||
Just run:
|
||||
```
|
||||
DEVKITPRO={path_to_devkitpro} make
|
||||
```
|
||||
After a successful build, simply transfer the `atmosphere` folder located inside `starlight_patch_100` to the root of your switch's SD card.
|
||||
</details>
|
||||
|
||||
On Ubuntu (and other Debian-based systems), devkitPro will be installed to `/opt/devkitpro` by default:
|
||||
## Troubleshooting
|
||||
|
||||
```
|
||||
DEVKITPRO=/opt/devkitpro/ make
|
||||
```
|
||||
|
||||
## Installing (Atmosphère)
|
||||
|
||||
After a successful build, simply transfer the `atmosphere` folder located inside `starlight_patch_100` to the root of your switch's SD card.
|
||||
The [Super Mario Odyssey Online website](https://smoo.it) has a FAQ section that should solve many issues.
|
||||
However, for any further questions or help not covered by the site, please visit the [CraftyBoss Community Discord Server](discord.gg/jYCueK2BqD) and ask in the `help`/`help-2` channel.
|
||||
|
||||
---
|
||||
|
||||
|
|
|
@ -29,7 +29,6 @@ class StageSceneStateServerConfig : public al::HostStateBase<al::Scene>, public
|
|||
enum ServerConfigOption {
|
||||
GAMEMODECONFIG,
|
||||
GAMEMODESWITCH,
|
||||
RECONNECT,
|
||||
SETIP,
|
||||
SETPORT
|
||||
};
|
||||
|
@ -42,11 +41,9 @@ class StageSceneStateServerConfig : public al::HostStateBase<al::Scene>, public
|
|||
void exeMainMenu();
|
||||
void exeOpenKeyboardIP();
|
||||
void exeOpenKeyboardPort();
|
||||
void exeRestartServer();
|
||||
void exeGamemodeConfig();
|
||||
void exeGamemodeSelect();
|
||||
void exeSaveData();
|
||||
void exeConnectError();
|
||||
|
||||
void endSubMenu();
|
||||
|
||||
|
@ -63,7 +60,7 @@ class StageSceneStateServerConfig : public al::HostStateBase<al::Scene>, public
|
|||
|
||||
SimpleLayoutMenu* mCurrentMenu = 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;
|
||||
CommonVerticalList *mMainOptionsList = nullptr;
|
||||
// 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, OpenKeyboardIP)
|
||||
NERVE_HEADER(StageSceneStateServerConfig, OpenKeyboardPort)
|
||||
NERVE_HEADER(StageSceneStateServerConfig, RestartServer)
|
||||
NERVE_HEADER(StageSceneStateServerConfig, GamemodeConfig)
|
||||
NERVE_HEADER(StageSceneStateServerConfig, GamemodeSelect)
|
||||
NERVE_HEADER(StageSceneStateServerConfig, SaveData)
|
||||
NERVE_HEADER(StageSceneStateServerConfig, ConnectError)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,8 +37,8 @@ namespace al {
|
|||
al::GameDrawInfo *mDrawInfo; // 0x38 from Application::sInstance + 0x30
|
||||
ProjectNfpDirector *mProjNfpDirector; // 0x48
|
||||
al::HtmlViewer *mHtmlViewer; // 0x50
|
||||
ApplicationMessageReceiver *mMessageReciever; // 0x58
|
||||
ApplicationMessageReceiver *mMessageReceiver; // 0x58
|
||||
al::WaveVibrationHolder *mWaveVibrationHolder; // 0x60
|
||||
void *gap2;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,12 @@
|
|||
|
||||
#include "../types.h"
|
||||
|
||||
struct pollfd
|
||||
{
|
||||
s32 fd;
|
||||
s16 events;
|
||||
s16 revents;
|
||||
};
|
||||
|
||||
struct in_addr
|
||||
{
|
||||
|
@ -38,13 +44,19 @@ s32 Connect(s32 socket, const sockaddr* address, u32 addressLen);
|
|||
Result Close(s32 socket);
|
||||
|
||||
s32 Send(s32 socket, const void* data, ulong dataLen, s32 flags);
|
||||
s32 SendTo(s32 socket, const void* data, ulong dataLen, s32 flags, const struct sockaddr* to, u32 toLen);
|
||||
s32 Recv(s32 socket, void* out, ulong outLen, s32 flags);
|
||||
s32 RecvFrom(s32 socket, void* out, ulong outLen, s32 flags, struct sockaddr* from, u32* fromLen);
|
||||
|
||||
s32 GetSockName(s32 socket, struct sockaddr* name, u32* dataLen);
|
||||
u16 InetHtons(u16 val);
|
||||
u16 InetNtohs(u16 val);
|
||||
s32 InetAton(const char* addressStr, in_addr* addressOut);
|
||||
|
||||
struct hostent* GetHostByName(const char* name);
|
||||
|
||||
u32 GetLastErrno();
|
||||
s32 Bind(s32 fd, sockaddr* addr, u32 addrlen);
|
||||
s32 Poll(struct pollfd* fd, u64 addr, s32 timeout);
|
||||
|
||||
} }
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "Packet.h"
|
||||
|
||||
struct PACKED HolePunch : Packet {
|
||||
HolePunch() : Packet() {this->mType = PacketType::HOLEPUNCH; mPacketSize = sizeof(HolePunch) - sizeof(Packet);};
|
||||
};
|
|
@ -26,6 +26,8 @@ enum PacketType : short {
|
|||
CAPTUREINF,
|
||||
CHANGESTAGE,
|
||||
CMD,
|
||||
UDPINIT,
|
||||
HOLEPUNCH,
|
||||
End // end of enum for bounds checking
|
||||
};
|
||||
|
||||
|
@ -43,7 +45,9 @@ USED static const char *packetNames[] = {
|
|||
"Moon Collection",
|
||||
"Capture Info",
|
||||
"Change Stage",
|
||||
"Server Command"
|
||||
"Server Command",
|
||||
"Udp Initialization",
|
||||
"Hole punch",
|
||||
};
|
||||
|
||||
enum SenderType {
|
||||
|
@ -83,4 +87,6 @@ struct PACKED Packet {
|
|||
#include "packets/CaptureInf.h"
|
||||
#include "packets/HackCapInf.h"
|
||||
#include "packets/ChangeStagePacket.h"
|
||||
#include "packets/InitPacket.h"
|
||||
#include "packets/InitPacket.h"
|
||||
#include "packets/UdpPacket.h"
|
||||
#include "packets/HolePunchPacket.h"
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
#pragma once
|
||||
|
||||
#include "Packet.h"
|
||||
|
||||
struct PACKED UdpInit : Packet {
|
||||
UdpInit() : Packet() {this->mType = PacketType::UDPINIT; mPacketSize = sizeof(UdpInit) - sizeof(Packet);};
|
||||
u16 port = 0;
|
||||
};
|
|
@ -88,7 +88,6 @@ class Client {
|
|||
|
||||
bool startThread();
|
||||
void readFunc();
|
||||
static void restartConnection();
|
||||
|
||||
static bool isSocketActive() { return sInstance ? sInstance->mSocket->isConnected() : false; };
|
||||
bool isPlayerConnected(int index) { return mPuppetInfoArr[index]->isConnected; }
|
||||
|
@ -175,11 +174,8 @@ class Client {
|
|||
static bool openKeyboardIP();
|
||||
static bool openKeyboardPort();
|
||||
|
||||
static void showConnect();
|
||||
|
||||
static void showConnectError(const char16_t* msg);
|
||||
|
||||
static void hideConnect();
|
||||
static void showUIMessage(const char16_t* msg);
|
||||
static void hideUIMessage();
|
||||
|
||||
void resetCollectedShines();
|
||||
|
||||
|
@ -198,6 +194,8 @@ class Client {
|
|||
void updateTagInfo(TagInf *packet);
|
||||
void updateCaptureInfo(CaptureInf* packet);
|
||||
void sendToStage(ChangeStagePacket* packet);
|
||||
void sendUdpHolePunch();
|
||||
void sendUdpInit();
|
||||
void disconnectPlayer(PlayerDC *packet);
|
||||
|
||||
PuppetInfo* findPuppetInfo(const nn::account::Uid& id, bool isFindAvailable);
|
||||
|
@ -218,7 +216,7 @@ class Client {
|
|||
|
||||
// --- 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
|
||||
// array of shine IDs for checking if multiple shines have been collected in quick succession, all moons within the players stage that match the ID will be deleted
|
||||
sead::SafeArray<int, 128> curCollectedShines;
|
||||
int collectedShineCount = 0;
|
||||
|
||||
|
@ -229,6 +227,8 @@ class Client {
|
|||
GameInf lastGameInfPacket = GameInf();
|
||||
GameInf emptyGameInfPacket = GameInf();
|
||||
CostumeInf lastCostumeInfPacket = CostumeInf();
|
||||
TagInf lastTagInfPacket = TagInf();
|
||||
CaptureInf lastCaptureInfPacket = CaptureInf();
|
||||
|
||||
Keyboard* mKeyboard = nullptr; // keyboard for setting server IP
|
||||
|
||||
|
@ -240,9 +240,7 @@ class Client {
|
|||
bool mIsFirstConnect = true;
|
||||
|
||||
// --- Game Layouts ---
|
||||
|
||||
al::WindowConfirmWait* mConnectionWait;
|
||||
|
||||
al::WindowConfirmWait* mUIMessage;
|
||||
al::SimpleLayoutAppearWaitEnd *mConnectStatus;
|
||||
|
||||
// --- Game Info ---
|
||||
|
|
|
@ -31,12 +31,13 @@ class SocketClient : public SocketBase {
|
|||
|
||||
bool startThreads();
|
||||
void endThreads();
|
||||
void waitForThreads();
|
||||
|
||||
bool send(Packet* packet);
|
||||
bool recv();
|
||||
|
||||
bool queuePacket(Packet *packet);
|
||||
void trySendQueue();
|
||||
bool trySendQueue();
|
||||
|
||||
void sendFunc();
|
||||
void recvFunc();
|
||||
|
@ -46,12 +47,20 @@ class SocketClient : public SocketBase {
|
|||
void printPacket(Packet* packet);
|
||||
bool isConnected() { return socket_log_state == SOCKET_LOG_CONNECTED; }
|
||||
|
||||
u16 getLocalUdpPort();
|
||||
s32 setPeerUdpPort(u16 port);
|
||||
const char* getUdpStateChar();
|
||||
|
||||
u32 getSendCount() { return mSendQueue.getCount(); }
|
||||
u32 getSendMaxCount() { return mSendQueue.getMaxCount(); }
|
||||
|
||||
u32 getRecvCount() { return mRecvQueue.getCount(); }
|
||||
u32 getRecvMaxCount() { return mRecvQueue.getMaxCount(); }
|
||||
|
||||
void clearMessageQueues();
|
||||
void setQueueOpen(bool value) { mPacketQueueOpen = value; }
|
||||
|
||||
|
||||
void setIsFirstConn(bool value) { mIsFirstConnect = value; }
|
||||
|
||||
private:
|
||||
|
@ -63,9 +72,20 @@ class SocketClient : public SocketBase {
|
|||
|
||||
sead::MessageQueue mRecvQueue;
|
||||
sead::MessageQueue mSendQueue;
|
||||
char* recvBuf = nullptr;
|
||||
|
||||
int maxBufSize = 100;
|
||||
bool mIsFirstConnect = true;
|
||||
bool mPacketQueueOpen = true;
|
||||
int pollTime = 0;
|
||||
|
||||
|
||||
bool mHasRecvUdp;
|
||||
s32 mUdpSocket;
|
||||
sockaddr mUdpAddress;
|
||||
|
||||
bool recvTcp();
|
||||
bool recvUdp();
|
||||
|
||||
/**
|
||||
* @param str a string containing an IPv4 address or a hostname that can be resolved via DNS
|
||||
|
|
|
@ -9,11 +9,13 @@ public:
|
|||
HideAndSeekConfigMenu();
|
||||
|
||||
void initMenu(const al::LayoutInitInfo &initInfo) override;
|
||||
const sead::WFixedSafeString<0x200> *getStringData() override;
|
||||
const sead::WFixedSafeString<0x200>* getStringData() override;
|
||||
bool updateMenu(int selectIndex) override;
|
||||
|
||||
const int getMenuSize() override { return mItemCount; }
|
||||
|
||||
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;
|
||||
};
|
||||
|
|
|
@ -35,36 +35,37 @@ if '.' not in consoleIP:
|
|||
print(sys.argv[0], "ERROR: Please specify with `IP=[Your console's IP]`")
|
||||
sys.exit(-1)
|
||||
|
||||
isNeedOtherSwitch = True
|
||||
|
||||
altSwitchIP = sys.argv[2]
|
||||
if '.' not in altSwitchIP:
|
||||
isNeedOtherSwitch = False
|
||||
isNeedOtherSwitch = False
|
||||
|
||||
consolePort = 5000
|
||||
|
||||
if len(sys.argv) < 4:
|
||||
if len(sys.argv) < 3:
|
||||
projName = 'StarlightBase'
|
||||
else:
|
||||
projName = sys.argv[3]
|
||||
projName = sys.argv[2]
|
||||
|
||||
if len(sys.argv) < 5:
|
||||
user = 'crafty'
|
||||
passwd = 'boss'
|
||||
else:
|
||||
user = sys.argv[3]
|
||||
passwd = sys.argv[4]
|
||||
|
||||
curDir = os.curdir
|
||||
|
||||
ftp = FTP()
|
||||
|
||||
otherftp = FTP()
|
||||
|
||||
print(f'Connecting to {consoleIP}... ', end='')
|
||||
ftp.connect(consoleIP, consolePort)
|
||||
print('logging into server...', end='')
|
||||
ftp.login('crafty','boss')
|
||||
ftp.login(user,passwd)
|
||||
print('Connected!')
|
||||
|
||||
if isNeedOtherSwitch:
|
||||
print(f'Connecting to {altSwitchIP}... ', end='')
|
||||
otherftp.connect(altSwitchIP, consolePort)
|
||||
print('logging into server...', end='')
|
||||
otherftp.login('crafty','boss')
|
||||
otherftp.login(user,passwd)
|
||||
print('Connected!')
|
||||
|
||||
patchDirectories = []
|
||||
|
|
|
@ -118,6 +118,7 @@ void drawMainHook(HakoniwaSequence *curSequence, sead::Viewport *viewport, sead:
|
|||
}
|
||||
|
||||
gTextWriter->printf("Client Socket Connection Status: %s\n", Client::instance()->mSocket->getStateChar());
|
||||
gTextWriter->printf("Udp socket status: %s\n", Client::instance()->mSocket->getUdpStateChar());
|
||||
//gTextWriter->printf("nn::socket::GetLastErrno: 0x%x\n", Client::instance()->mSocket->socket_errno);
|
||||
gTextWriter->printf("Connected Players: %d/%d\n", Client::getConnectCount() + 1, Client::getMaxPlayerCount());
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@ PuppetHolder::PuppetHolder(int size) {
|
|||
* @brief resizes puppet ptr array by creating a new ptr array and storing previous ptrs in it, before freeing the previous array
|
||||
*
|
||||
* @param size the size of the new ptr array
|
||||
* @return returns true if resizing was sucessful
|
||||
* @return returns true if resizing was successful
|
||||
*/
|
||||
bool PuppetHolder::resizeHolder(int size) {
|
||||
|
||||
|
@ -106,4 +106,4 @@ bool PuppetHolder::checkInfoIsInStage(PuppetInfo *info) {
|
|||
void PuppetHolder::setStageInfo(const char *stageName, u8 scenarioNo) {
|
||||
mStageName = stageName;
|
||||
mScenarioNo = scenarioNo;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -71,16 +71,14 @@ Client::Client() {
|
|||
*/
|
||||
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);
|
||||
|
||||
mConnectionWait->setTxtMessage(u"Connecting to Server.");
|
||||
mConnectionWait->setTxtMessageConfirm(u"Failed to Connect!");
|
||||
|
||||
al::setPaneString(mConnectStatus, "TxtSave", 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;
|
||||
|
||||
startThread();
|
||||
|
@ -91,13 +89,13 @@ void Client::init(al::LayoutInitInfo const &initInfo, GameDataHolderAccessor hol
|
|||
/**
|
||||
* @brief starts client read thread
|
||||
*
|
||||
* @return true if read thread was sucessfully started
|
||||
* @return true if read thread was succesfully started
|
||||
* @return false if read thread was unable to start, or thread was already started.
|
||||
*/
|
||||
bool Client::startThread() {
|
||||
if(mReadThread->isDone() ) {
|
||||
mReadThread->start();
|
||||
Logger::log("Read Thread Sucessfully Started.\n");
|
||||
Logger::log("Read Thread Successfully Started.\n");
|
||||
return true;
|
||||
}else {
|
||||
Logger::log("Read Thread has already started! Or other unknown reason.\n");
|
||||
|
@ -105,44 +103,6 @@ bool Client::startThread() {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @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->queuePacket(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.
|
||||
*
|
||||
|
@ -179,7 +139,7 @@ bool Client::startConnection() {
|
|||
|
||||
if (mIsConnectionActive) {
|
||||
|
||||
Logger::log("Sucessful Connection. Waiting to recieve init packet.\n");
|
||||
Logger::log("Succesful Connection. Waiting to receive init packet.\n");
|
||||
|
||||
bool waitingForInitPacket = true;
|
||||
// wait for client init packet
|
||||
|
@ -203,11 +163,13 @@ bool Client::startConnection() {
|
|||
mHeap->free(curPacket);
|
||||
|
||||
} else {
|
||||
Logger::log("Recieve failed! Stopping Connection.\n");
|
||||
Logger::log("Receive failed! Stopping Connection.\n");
|
||||
mIsConnectionActive = false;
|
||||
waitingForInitPacket = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
return mIsConnectionActive;
|
||||
|
@ -293,6 +255,33 @@ bool Client::openKeyboardPort() {
|
|||
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
|
||||
*
|
||||
|
@ -326,7 +315,7 @@ void Client::readFunc() {
|
|||
|
||||
while(mIsConnectionActive) {
|
||||
|
||||
Packet *curPacket = mSocket->tryGetPacket(); // will block until a packet has been recieved, or socket disconnected
|
||||
Packet *curPacket = mSocket->tryGetPacket(); // will block until a packet has been received, or socket disconnected
|
||||
|
||||
if (curPacket) {
|
||||
|
||||
|
@ -361,6 +350,10 @@ void Client::readFunc() {
|
|||
mSocket->send(&lastPlayerInfPacket);
|
||||
if (lastCostumeInfPacket.mUserID == mUserID)
|
||||
mSocket->send(&lastCostumeInfPacket);
|
||||
if (lastTagInfPacket.mUserID == mUserID)
|
||||
mSocket->send(&lastTagInfPacket);
|
||||
if (lastCaptureInfPacket.mUserID == mUserID)
|
||||
mSocket->send(&lastCaptureInfPacket);
|
||||
|
||||
break;
|
||||
case PacketType::COSTUMEINF:
|
||||
|
@ -386,6 +379,19 @@ void Client::readFunc() {
|
|||
maxPuppets = initPacket->maxPlayers - 1;
|
||||
break;
|
||||
}
|
||||
case PacketType::UDPINIT: {
|
||||
UdpInit* initPacket = (UdpInit*)curPacket;
|
||||
Logger::log("Received udp init packet from server\n");
|
||||
|
||||
sInstance->mSocket->setPeerUdpPort(initPacket->port);
|
||||
sendUdpHolePunch();
|
||||
sendUdpInit();
|
||||
|
||||
break;
|
||||
}
|
||||
case PacketType::HOLEPUNCH:
|
||||
sendUdpHolePunch();
|
||||
break;
|
||||
default:
|
||||
Logger::log("Discarding Unknown Packet Type.\n");
|
||||
break;
|
||||
|
@ -393,8 +399,8 @@ void Client::readFunc() {
|
|||
|
||||
mHeap->free(curPacket);
|
||||
|
||||
}else { // if false, socket has errored or disconnected, so close the socket and end this thread.
|
||||
Logger::log("Client Socket Encountered an Error! Errno: 0x%x\n", mSocket->socket_errno);
|
||||
}else { // if false, socket has errored or disconnected, so restart the connection
|
||||
Logger::log("Client Socket Encountered an Error, restarting connection! Errno: 0x%x\n", mSocket->socket_errno);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -622,13 +628,15 @@ void Client::sendTagInfPacket() {
|
|||
|
||||
packet->mUserID = sInstance->mUserID;
|
||||
|
||||
packet->isIt = hsMode->isPlayerIt();
|
||||
packet->isIt = hsMode->isPlayerIt() && hsMode->isModeActive();
|
||||
|
||||
packet->minutes = curInfo->mHidingTime.mMinutes;
|
||||
packet->seconds = curInfo->mHidingTime.mSeconds;
|
||||
packet->updateType = static_cast<TagUpdateType>(TagUpdateType::STATE | TagUpdateType::TIME);
|
||||
|
||||
sInstance->mSocket->queuePacket(packet);
|
||||
|
||||
sInstance->lastTagInfPacket = *packet;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -673,12 +681,14 @@ void Client::sendCaptureInfPacket(const PlayerActorHakoniwa* player) {
|
|||
packet->mUserID = sInstance->mUserID;
|
||||
strcpy(packet->hackName, tryConvertName(player->mHackKeeper->getCurrentHackName()));
|
||||
sInstance->mSocket->queuePacket(packet);
|
||||
sInstance->lastCaptureInfPacket = *packet;
|
||||
sInstance->isSentCaptureInf = true;
|
||||
} else if (!sInstance->isClientCaptured && sInstance->isSentCaptureInf) {
|
||||
CaptureInf *packet = new CaptureInf();
|
||||
packet->mUserID = sInstance->mUserID;
|
||||
strcpy(packet->hackName, "");
|
||||
sInstance->mSocket->queuePacket(packet);
|
||||
sInstance->lastCaptureInfPacket = *packet;
|
||||
sInstance->isSentCaptureInf = false;
|
||||
}
|
||||
}
|
||||
|
@ -696,6 +706,16 @@ void Client::resendInitPackets() {
|
|||
if (lastGameInfPacket != emptyGameInfPacket) {
|
||||
mSocket->queuePacket(&lastGameInfPacket);
|
||||
}
|
||||
|
||||
// TagInfPacket
|
||||
if (lastTagInfPacket.mUserID == mUserID) {
|
||||
mSocket->queuePacket(&lastTagInfPacket);
|
||||
}
|
||||
|
||||
// CaptureInfPacket
|
||||
if (lastCaptureInfPacket.mUserID == mUserID) {
|
||||
mSocket->queuePacket(&lastCaptureInfPacket);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -962,7 +982,45 @@ void Client::sendToStage(ChangeStagePacket* packet) {
|
|||
GameDataFunction::tryChangeNextStage(accessor, &info);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @brief
|
||||
* Send a udp holepunch packet to the server
|
||||
*/
|
||||
void Client::sendUdpHolePunch() {
|
||||
|
||||
if (!sInstance) {
|
||||
Logger::log("Static Instance is Null!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
sead::ScopedCurrentHeapSetter setter(sInstance->mHeap);
|
||||
|
||||
HolePunch *packet = new HolePunch();
|
||||
|
||||
packet->mUserID = sInstance->mUserID;
|
||||
|
||||
sInstance->mSocket->queuePacket(packet);
|
||||
}
|
||||
/**
|
||||
* @brief
|
||||
* Send a udp init packet to server
|
||||
*/
|
||||
void Client::sendUdpInit() {
|
||||
|
||||
if (!sInstance) {
|
||||
Logger::log("Static Instance is Null!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
sead::ScopedCurrentHeapSetter setter(sInstance->mHeap);
|
||||
|
||||
UdpInit *packet = new UdpInit();
|
||||
|
||||
packet->mUserID = sInstance->mUserID;
|
||||
packet->port = sInstance->mSocket->getLocalUdpPort();
|
||||
|
||||
sInstance->mSocket->queuePacket(packet);
|
||||
}
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
|
@ -1393,37 +1451,3 @@ Shine* Client::findStageShine(int shineID) {
|
|||
}
|
||||
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();
|
||||
}
|
||||
|
|
|
@ -72,12 +72,13 @@ s32 SocketBase::getFd() {
|
|||
|
||||
bool SocketBase::closeSocket() {
|
||||
|
||||
this->socket_log_state = SOCKET_LOG_DISCONNECTED; // probably not safe to assume socket will be closed
|
||||
if (this->socket_log_state != SOCKET_LOG_DISCONNECTED) {
|
||||
nn::Result result = nn::socket::Close(this->socket_log_socket);
|
||||
if (result.isSuccess()) {
|
||||
this->socket_log_state = SOCKET_LOG_DISCONNECTED;
|
||||
}
|
||||
return result.isSuccess();
|
||||
}
|
||||
|
||||
nn::Result result = nn::socket::Close(this->socket_log_socket);
|
||||
|
||||
return result.isSuccess();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include "nn/result.h"
|
||||
#include "nn/socket.h"
|
||||
#include "packets/Packet.h"
|
||||
#include "packets/UdpPacket.h"
|
||||
#include "server/Client.hpp"
|
||||
#include "thread/seadMessageQueue.h"
|
||||
#include "types.h"
|
||||
|
@ -16,12 +17,18 @@
|
|||
SocketClient::SocketClient(const char* name, sead::Heap* heap, Client* client) : mHeap(heap), SocketBase(name) {
|
||||
|
||||
this->client = client;
|
||||
#if EMU
|
||||
this->pollTime = 0;
|
||||
#else
|
||||
this->pollTime = -1;
|
||||
#endif
|
||||
|
||||
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});
|
||||
|
||||
mRecvQueue.allocate(maxBufSize, mHeap);
|
||||
mSendQueue.allocate(maxBufSize, mHeap);
|
||||
recvBuf = (char*)mHeap->alloc(MAXPACKSIZE+1);
|
||||
};
|
||||
|
||||
nn::Result SocketClient::init(const char* ip, u16 port) {
|
||||
|
@ -31,6 +38,7 @@ nn::Result SocketClient::init(const char* ip, u16 port) {
|
|||
|
||||
in_addr hostAddress = { 0 };
|
||||
sockaddr serverAddress = { 0 };
|
||||
sockaddr udpAddress = { 0 };
|
||||
|
||||
Logger::log("SocketClient::init: %s:%d sock %s\n", ip, port, getStateChar());
|
||||
|
||||
|
@ -80,11 +88,25 @@ nn::Result SocketClient::init(const char* ip, u16 port) {
|
|||
return result;
|
||||
}
|
||||
|
||||
if ((this->mUdpSocket = nn::socket::Socket(2, 2, 17)) < 0) {
|
||||
Logger::log("Udp Socket failed to create");
|
||||
this->socket_errno = nn::socket::GetLastErrno();
|
||||
this->socket_log_state = SOCKET_LOG_UNAVAILABLE;
|
||||
return -1;
|
||||
}
|
||||
|
||||
udpAddress.address = hostAddress;
|
||||
udpAddress.port = 0;
|
||||
udpAddress.family = 2;
|
||||
this->mUdpAddress = udpAddress;
|
||||
this->mHasRecvUdp = false;
|
||||
this->mPacketQueueOpen = true;
|
||||
|
||||
this->socket_log_state = SOCKET_LOG_CONNECTED;
|
||||
|
||||
Logger::log("Socket fd: %d\n", socket_log_socket);
|
||||
|
||||
startThreads(); // start recv and send threads after sucessful connection
|
||||
startThreads(); // start recv and send threads after succesful connection
|
||||
|
||||
// send init packet to server once we connect (an issue with the server prevents this from working properly, waiting for a fix to implement)
|
||||
|
||||
|
@ -104,31 +126,98 @@ nn::Result SocketClient::init(const char* ip, u16 port) {
|
|||
// 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;
|
||||
|
||||
}
|
||||
|
||||
u16 SocketClient::getLocalUdpPort() {
|
||||
sockaddr udpAddress = { 0 };
|
||||
u32 size = sizeof(udpAddress);
|
||||
|
||||
nn::Result result;
|
||||
if((result = nn::socket::GetSockName(this->mUdpSocket, &udpAddress, &size)).isFailure()) {
|
||||
this->socket_errno = nn::socket::GetLastErrno();
|
||||
return 0;
|
||||
}
|
||||
|
||||
return nn::socket::InetNtohs(udpAddress.port);
|
||||
}
|
||||
|
||||
|
||||
s32 SocketClient::setPeerUdpPort(u16 port) {
|
||||
u16 net_port = nn::socket::InetHtons(port);
|
||||
this->mUdpAddress.port = net_port;
|
||||
|
||||
nn::Result result;
|
||||
if((result = nn::socket::Connect(this->mUdpSocket, &this->mUdpAddress, sizeof(this->mUdpAddress))).isFailure()) {
|
||||
Logger::log("Udp socket connection failed to connect to port %d!\n", port);
|
||||
this->socket_errno = nn::socket::GetLastErrno();
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
const char* SocketClient::getUdpStateChar() {
|
||||
if (this->mUdpAddress.port == 0) {
|
||||
return "Waiting for handshake";
|
||||
}
|
||||
|
||||
if (!this->mHasRecvUdp) {
|
||||
return "Waiting for holepunch";
|
||||
}
|
||||
|
||||
return "Utilizing UDP";
|
||||
}
|
||||
bool SocketClient::send(Packet *packet) {
|
||||
|
||||
if (this->socket_log_state != SOCKET_LOG_CONNECTED)
|
||||
if (this->socket_log_state != SOCKET_LOG_CONNECTED || packet == nullptr)
|
||||
return false;
|
||||
|
||||
char* buffer = reinterpret_cast<char*>(packet);
|
||||
|
||||
int valread = 0;
|
||||
|
||||
if (packet->mType != PLAYERINF && packet->mType != HACKCAPINF)
|
||||
Logger::log("Sending packet: %s\n", packetNames[packet->mType]);
|
||||
int fd = -1;
|
||||
if ((packet->mType != PLAYERINF && packet->mType != HACKCAPINF && packet->mType != HOLEPUNCH)
|
||||
|| (!this->mHasRecvUdp && packet->mType != HOLEPUNCH)
|
||||
|| this->mUdpAddress.port == 0) {
|
||||
|
||||
if ((valread = nn::socket::Send(this->socket_log_socket, buffer, packet->mPacketSize + sizeof(Packet), 0) > 0)) {
|
||||
if (packet->mType != PLAYERINF && packet->mType != HACKCAPINF) {
|
||||
Logger::log("Sending packet: %s\n", packetNames[packet->mType]);
|
||||
}
|
||||
|
||||
fd = this->socket_log_socket;
|
||||
} else {
|
||||
|
||||
fd = this->mUdpSocket;
|
||||
}
|
||||
|
||||
|
||||
if ((valread = nn::socket::Send(fd, buffer, packet->mPacketSize + sizeof(Packet), 0) > 0)) {
|
||||
return true;
|
||||
} else {
|
||||
Logger::log("Failed to Fully Send Packet! Result: %d Type: %s Packet Size: %d\n", valread, packetNames[packet->mType], packet->mPacketSize);
|
||||
this->socket_errno = nn::socket::GetLastErrno();
|
||||
this->tryReconnect();
|
||||
return false;
|
||||
return this->tryReconnect();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -141,17 +230,63 @@ bool SocketClient::recv() {
|
|||
return this->tryReconnect();
|
||||
}
|
||||
|
||||
const int fd_count = 2;
|
||||
struct pollfd pfds[fd_count] = {{0}, {0}};
|
||||
|
||||
// TCP Connection
|
||||
pfds[0].fd = this->socket_log_socket;
|
||||
pfds[0].events = 1;
|
||||
pfds[0].revents = 0;
|
||||
|
||||
// UDP Connection
|
||||
pfds[1].fd = this->mUdpSocket;
|
||||
pfds[1].events = 1;
|
||||
pfds[1].revents = 0;
|
||||
|
||||
|
||||
int result = nn::socket::Poll(pfds, fd_count, this->pollTime);
|
||||
|
||||
if (result == 0) {
|
||||
return true;
|
||||
} else if (result < 0) {
|
||||
Logger::log("Error occurred when polling for packets\n");
|
||||
this->socket_errno = nn::socket::GetLastErrno();
|
||||
return this->tryReconnect();
|
||||
}
|
||||
|
||||
s32 index = -1;
|
||||
for (int i = 0; i < fd_count; i++){
|
||||
if (pfds[i].revents & 1) {
|
||||
index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
switch (index) {
|
||||
case 0:
|
||||
return recvTcp();
|
||||
case 1:
|
||||
return recvUdp();
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
bool SocketClient::recvTcp() {
|
||||
int headerSize = sizeof(Packet);
|
||||
char headerBuf[sizeof(Packet)] = {};
|
||||
int valread = 0;
|
||||
s32 fd = this->socket_log_socket;
|
||||
|
||||
// read only the size of a header
|
||||
while(valread < headerSize) {
|
||||
int result = nn::socket::Recv(this->socket_log_socket, headerBuf + valread,
|
||||
headerSize - valread, this->sock_flags);
|
||||
int result = 0;
|
||||
result = nn::socket::Recv(fd, recvBuf + valread,
|
||||
headerSize - valread, this->sock_flags);
|
||||
|
||||
this->socket_errno = nn::socket::GetLastErrno();
|
||||
|
||||
|
||||
if(result > 0) {
|
||||
valread += result;
|
||||
} else {
|
||||
|
@ -159,70 +294,125 @@ bool SocketClient::recv() {
|
|||
return true;
|
||||
} else {
|
||||
Logger::log("Header Read Failed! Value: %d Total Read: %d\n", result, valread);
|
||||
return this->tryReconnect(); // if we sucessfully reconnect, we dont want
|
||||
return this->tryReconnect();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(valread > 0) {
|
||||
Packet* header = reinterpret_cast<Packet*>(headerBuf);
|
||||
|
||||
int fullSize = header->mPacketSize + sizeof(Packet);
|
||||
|
||||
if (header->mType > PacketType::UNKNOWN && header->mType < PacketType::End &&
|
||||
fullSize <= MAXPACKSIZE && fullSize > 0 && valread == sizeof(Packet)) {
|
||||
|
||||
if (header->mType != PLAYERINF && header->mType != HACKCAPINF) {
|
||||
Logger::log("Received packet (from %02X%02X):", header->mUserID.data[0],
|
||||
header->mUserID.data[1]);
|
||||
Logger::disableName();
|
||||
Logger::log(" Size: %d", header->mPacketSize);
|
||||
Logger::log(" Type: %d", header->mType);
|
||||
if(packetNames[header->mType])
|
||||
Logger::log(" Type String: %s\n", packetNames[header->mType]);
|
||||
Logger::enableName();
|
||||
}
|
||||
|
||||
char* packetBuf = (char*)mHeap->alloc(fullSize);
|
||||
|
||||
if (packetBuf) {
|
||||
|
||||
memcpy(packetBuf, headerBuf, sizeof(Packet));
|
||||
|
||||
while (valread < fullSize) {
|
||||
|
||||
int result = nn::socket::Recv(this->socket_log_socket, packetBuf + valread,
|
||||
fullSize - valread, this->sock_flags);
|
||||
|
||||
this->socket_errno = nn::socket::GetLastErrno();
|
||||
|
||||
if (result > 0) {
|
||||
valread += result;
|
||||
} else {
|
||||
mHeap->free(packetBuf);
|
||||
Logger::log("Packet Read Failed! Value: %d\nPacket Size: %d\nPacket Type: %s\n", result, header->mPacketSize, packetNames[header->mType]);
|
||||
return this->tryReconnect();
|
||||
}
|
||||
}
|
||||
|
||||
Packet* packet = reinterpret_cast<Packet*>(packetBuf);
|
||||
|
||||
if (!mRecvQueue.isFull()) {
|
||||
mRecvQueue.push((s64)packet, sead::MessageQueue::BlockType::NonBlocking);
|
||||
} else {
|
||||
mHeap->free(packetBuf);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Logger::log("Failed to aquire valid data! Packet Type: %d Full Packet Size %d valread size: %d", header->mType, fullSize, valread);
|
||||
}
|
||||
|
||||
return true;
|
||||
} else { // if we error'd, close the socket
|
||||
if(valread <= 0) { // if we error'd, close the socket
|
||||
Logger::log("valread was zero! Disconnecting.\n");
|
||||
this->socket_errno = nn::socket::GetLastErrno();
|
||||
return this->tryReconnect();
|
||||
}
|
||||
|
||||
Packet* header = reinterpret_cast<Packet*>(recvBuf);
|
||||
int fullSize = header->mPacketSize + sizeof(Packet);
|
||||
|
||||
if (!(fullSize <= MAXPACKSIZE && fullSize > 0 && valread == sizeof(Packet))) {
|
||||
Logger::log("Failed to acquire valid data! Packet Type: %d Full Packet Size %d valread size: %d\n", header->mType, fullSize, valread);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (header->mType != PLAYERINF && header->mType != HACKCAPINF) {
|
||||
Logger::log("Received packet (from %02X%02X):", header->mUserID.data[0],
|
||||
header->mUserID.data[1]);
|
||||
Logger::disableName();
|
||||
Logger::log(" Size: %d", header->mPacketSize);
|
||||
Logger::log(" Type: %d", header->mType);
|
||||
if(packetNames[header->mType])
|
||||
Logger::log(" Type String: %s\n", packetNames[header->mType]);
|
||||
Logger::enableName();
|
||||
}
|
||||
|
||||
char* packetBuf = (char*)mHeap->alloc(fullSize);
|
||||
|
||||
if (!packetBuf) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
memcpy(packetBuf, recvBuf, sizeof(Packet));
|
||||
|
||||
while (valread < fullSize) {
|
||||
|
||||
int result = nn::socket::Recv(fd, packetBuf + valread,
|
||||
fullSize - valread, this->sock_flags);
|
||||
|
||||
this->socket_errno = nn::socket::GetLastErrno();
|
||||
|
||||
if (result > 0) {
|
||||
valread += result;
|
||||
} else {
|
||||
mHeap->free(packetBuf);
|
||||
Logger::log("Packet Read Failed! Value: %d\nPacket Size: %d\nPacket Type: %s\n", result, header->mPacketSize, packetNames[header->mType]);
|
||||
return this->tryReconnect();
|
||||
}
|
||||
}
|
||||
|
||||
if (!(header->mType > PacketType::UNKNOWN && header->mType < PacketType::End)) {
|
||||
Logger::log("Failed to acquire valid packet type! Packet Type: %d Full Packet Size %d valread size: %d\n", header->mType, fullSize, valread);
|
||||
mHeap->free(packetBuf);
|
||||
return true;
|
||||
}
|
||||
|
||||
Packet *packet = reinterpret_cast<Packet*>(packetBuf);
|
||||
|
||||
if (!mRecvQueue.isFull() && mPacketQueueOpen) {
|
||||
mRecvQueue.push((s64)packet, sead::MessageQueue::BlockType::NonBlocking);
|
||||
} else {
|
||||
mHeap->free(packetBuf);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SocketClient::recvUdp() {
|
||||
int headerSize = sizeof(Packet);
|
||||
s32 fd = this->mUdpSocket;
|
||||
|
||||
int valread = nn::socket::Recv(fd, recvBuf, MAXPACKSIZE, this->sock_flags);
|
||||
|
||||
if (valread == 0) {
|
||||
Logger::log("Udp connection valread was zero. Disconnecting.\n");
|
||||
return this->tryReconnect();
|
||||
}
|
||||
|
||||
if (valread < headerSize){
|
||||
return true;
|
||||
}
|
||||
|
||||
Packet* header = reinterpret_cast<Packet*>(recvBuf);
|
||||
int fullSize = header->mPacketSize + sizeof(Packet);
|
||||
// Verify packet size is appropriate
|
||||
if (valread < fullSize || valread > MAXPACKSIZE || fullSize > MAXPACKSIZE){
|
||||
return true;
|
||||
}
|
||||
|
||||
// Verify type of packet
|
||||
if (!(header->mType > PacketType::UNKNOWN && header->mType < PacketType::End)) {
|
||||
Logger::log("Failed to acquire valid packet type! Packet Type: %d Full Packet Size %d valread size: %d\n", header->mType, fullSize, valread);
|
||||
return true;
|
||||
}
|
||||
|
||||
this->mHasRecvUdp = true;
|
||||
|
||||
char* packetBuf = (char*)mHeap->alloc(fullSize);
|
||||
if (!packetBuf) {
|
||||
return true;
|
||||
}
|
||||
|
||||
memcpy(packetBuf, recvBuf, fullSize);
|
||||
|
||||
|
||||
Packet *packet = reinterpret_cast<Packet*>(packetBuf);
|
||||
|
||||
if(!mRecvQueue.isFull()) {
|
||||
mRecvQueue.push((s64)packet, sead::MessageQueue::BlockType::NonBlocking);
|
||||
} else {
|
||||
mHeap->free(packetBuf);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// prints packet to debug logger
|
||||
|
@ -259,6 +449,10 @@ bool SocketClient::closeSocket() {
|
|||
|
||||
Logger::log("Closing Socket.\n");
|
||||
|
||||
mHasRecvUdp = false;
|
||||
mUdpAddress.port = 0;
|
||||
mPacketQueueOpen = false;
|
||||
|
||||
bool result = false;
|
||||
|
||||
if (!(result = SocketBase::closeSocket())) {
|
||||
|
@ -291,7 +485,7 @@ bool SocketClient::stringToIPAddress(const char* str, in_addr* out) {
|
|||
/**
|
||||
* @brief starts client read thread
|
||||
*
|
||||
* @return true if read thread was sucessfully started
|
||||
* @return true if read thread was successfully started
|
||||
* @return false if read thread was unable to start, or thread was already started.
|
||||
*/
|
||||
bool SocketClient::startThreads() {
|
||||
|
@ -302,7 +496,7 @@ bool SocketClient::startThreads() {
|
|||
if(this->mRecvThread->isDone() && this->mSendThread->isDone()) {
|
||||
this->mRecvThread->start();
|
||||
this->mSendThread->start();
|
||||
Logger::log("Socket threads sucessfully started.\n");
|
||||
Logger::log("Socket threads succesfully started.\n");
|
||||
return true;
|
||||
}else {
|
||||
Logger::log("Socket threads failed to start.\n");
|
||||
|
@ -315,14 +509,18 @@ void SocketClient::endThreads() {
|
|||
mSendThread->mDelegateThread->destroy();
|
||||
}
|
||||
|
||||
void SocketClient::waitForThreads() {
|
||||
while (!mRecvThread->isDone()){}
|
||||
while (!mSendThread->isDone()){}
|
||||
}
|
||||
|
||||
void SocketClient::sendFunc() {
|
||||
|
||||
Logger::log("Starting Send Thread.\n");
|
||||
|
||||
while (true) {
|
||||
trySendQueue();
|
||||
}
|
||||
while (trySendQueue() || socket_log_state != SOCKET_LOG_DISCONNECTED) {}
|
||||
|
||||
Logger::log("Sending packet failed!\n");
|
||||
Logger::log("Ending Send Thread.\n");
|
||||
}
|
||||
|
||||
|
@ -332,17 +530,18 @@ void SocketClient::recvFunc() {
|
|||
|
||||
Logger::log("Starting Recv Thread.\n");
|
||||
|
||||
while (true) {
|
||||
if (!recv()) {
|
||||
Logger::log("Receiving Packet Failed!\n");
|
||||
}
|
||||
}
|
||||
while (recv() || socket_log_state != SOCKET_LOG_DISCONNECTED) {}
|
||||
|
||||
// Free up all blocked threads
|
||||
mSendQueue.push(0, sead::MessageQueue::BlockType::NonBlocking);
|
||||
mRecvQueue.push(0, sead::MessageQueue::BlockType::NonBlocking);
|
||||
|
||||
Logger::log("Receiving Packet Failed!\n");
|
||||
Logger::log("Ending Recv Thread.\n");
|
||||
}
|
||||
|
||||
bool SocketClient::queuePacket(Packet* packet) {
|
||||
if (socket_log_state == SOCKET_LOG_CONNECTED) {
|
||||
if (socket_log_state == SOCKET_LOG_CONNECTED && mPacketQueueOpen) {
|
||||
mSendQueue.push((s64)packet,
|
||||
sead::MessageQueue::BlockType::NonBlocking); // as this is non-blocking, it
|
||||
// will always return true.
|
||||
|
@ -353,15 +552,34 @@ bool SocketClient::queuePacket(Packet* packet) {
|
|||
}
|
||||
}
|
||||
|
||||
void SocketClient::trySendQueue() {
|
||||
bool SocketClient::trySendQueue() {
|
||||
|
||||
Packet* curPacket = (Packet*)mSendQueue.pop(sead::MessageQueue::BlockType::Blocking);
|
||||
|
||||
send(curPacket);
|
||||
bool successful = send(curPacket);
|
||||
|
||||
mHeap->free(curPacket);
|
||||
|
||||
return successful;
|
||||
}
|
||||
|
||||
Packet* SocketClient::tryGetPacket(sead::MessageQueue::BlockType blockType) {
|
||||
return socket_log_state == SOCKET_LOG_CONNECTED ? (Packet*)mRecvQueue.pop(blockType) : nullptr;
|
||||
}
|
||||
|
||||
void SocketClient::clearMessageQueues() {
|
||||
bool prevQueueOpenness = this->mPacketQueueOpen;
|
||||
this->mPacketQueueOpen = false;
|
||||
|
||||
while (mSendQueue.getCount() > 0) {
|
||||
Packet* curPacket = (Packet*)mSendQueue.pop(sead::MessageQueue::BlockType::Blocking);
|
||||
mHeap->free(curPacket);
|
||||
}
|
||||
|
||||
while (mRecvQueue.getCount() > 0) {
|
||||
Packet* curPacket = (Packet*)mRecvQueue.pop(sead::MessageQueue::BlockType::Blocking);
|
||||
mHeap->free(curPacket);
|
||||
}
|
||||
|
||||
this->mPacketQueueOpen = prevQueueOpenness;
|
||||
}
|
||||
|
|
|
@ -5,20 +5,27 @@
|
|||
#include "server/hns/HideAndSeekMode.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) {
|
||||
|
||||
}
|
||||
|
||||
const sead::WFixedSafeString<0x200> *HideAndSeekConfigMenu::getStringData() {
|
||||
sead::SafeArray<sead::WFixedSafeString<0x200>, mItemCount>* gamemodeConfigOptions =
|
||||
new sead::SafeArray<sead::WFixedSafeString<0x200>, mItemCount>();
|
||||
|
||||
gamemodeConfigOptions->mBuffer[0].copy(u"Toggle H&S Gravity On");
|
||||
gamemodeConfigOptions->mBuffer[1].copy(u"Toggle H&S Gravity Off");
|
||||
|
||||
return gamemodeConfigOptions->mBuffer;
|
||||
const sead::WFixedSafeString<0x200>* HideAndSeekConfigMenu::getStringData() {
|
||||
HideAndSeekInfo *curMode = GameModeManager::instance()->getInfo<HideAndSeekInfo>();
|
||||
return (
|
||||
GameModeManager::instance()->isMode(GameMode::HIDEANDSEEK)
|
||||
&& curMode != nullptr
|
||||
&& curMode->mIsUseGravity
|
||||
? gravityOn->mBuffer
|
||||
: gravityOff->mBuffer
|
||||
);
|
||||
}
|
||||
|
||||
bool HideAndSeekConfigMenu::updateMenu(int selectIndex) {
|
||||
|
@ -35,13 +42,7 @@ bool HideAndSeekConfigMenu::updateMenu(int selectIndex) {
|
|||
switch (selectIndex) {
|
||||
case 0: {
|
||||
if (GameModeManager::instance()->isMode(GameMode::HIDEANDSEEK)) {
|
||||
curMode->mIsUseGravity = true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
case 1: {
|
||||
if (GameModeManager::instance()->isMode(GameMode::HIDEANDSEEK)) {
|
||||
curMode->mIsUseGravity = false;
|
||||
curMode->mIsUseGravity = !curMode->mIsUseGravity;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -50,4 +51,4 @@ bool HideAndSeekConfigMenu::updateMenu(int selectIndex) {
|
|||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -84,6 +84,8 @@ void HideAndSeekMode::begin() {
|
|||
playGuideLyt->end();
|
||||
|
||||
GameModeBase::begin();
|
||||
|
||||
Client::sendTagInfPacket();
|
||||
}
|
||||
|
||||
void HideAndSeekMode::end() {
|
||||
|
@ -109,6 +111,8 @@ void HideAndSeekMode::end() {
|
|||
playGuideLyt->appear();
|
||||
|
||||
GameModeBase::end();
|
||||
|
||||
Client::sendTagInfPacket();
|
||||
}
|
||||
|
||||
void HideAndSeekMode::update() {
|
||||
|
|
|
@ -111,7 +111,7 @@ void Logger::log(const char* fmt, ...) {
|
|||
}
|
||||
|
||||
bool Logger::pingSocket() {
|
||||
return socket_log("ping") > 0; // if value is greater than zero, than the socket recieved our message, otherwise the connection was lost.
|
||||
return socket_log("ping") > 0; // if value is greater than zero, than the socket received our message, otherwise the connection was lost.
|
||||
}
|
||||
|
||||
void tryInitSocket() {
|
||||
|
@ -119,4 +119,4 @@ void tryInitSocket() {
|
|||
#if DEBUGLOG
|
||||
Logger::createInstance(); // creates a static instance for debug logger
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
|
|
@ -41,14 +41,13 @@ StageSceneStateServerConfig::StageSceneStateServerConfig(const char *name, al::S
|
|||
|
||||
mMainOptionsList->unkInt1 = 1;
|
||||
|
||||
mMainOptionsList->initDataNoResetSelected(5);
|
||||
mMainOptionsList->initDataNoResetSelected(4);
|
||||
|
||||
sead::SafeArray<sead::WFixedSafeString<0x200>, 5>* mainMenuOptions =
|
||||
new sead::SafeArray<sead::WFixedSafeString<0x200>, 5>();
|
||||
sead::SafeArray<sead::WFixedSafeString<0x200>, 4>* mainMenuOptions =
|
||||
new sead::SafeArray<sead::WFixedSafeString<0x200>, 4>();
|
||||
|
||||
mainMenuOptions->mBuffer[ServerConfigOption::GAMEMODECONFIG].copy(u"Gamemode Config");
|
||||
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::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);
|
||||
|
||||
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() {
|
||||
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) {
|
||||
|
@ -176,10 +179,6 @@ void StageSceneStateServerConfig::exeMainMenu() {
|
|||
al::setNerve(this, &nrvStageSceneStateServerConfigGamemodeSelect);
|
||||
break;
|
||||
}
|
||||
case ServerConfigOption::RECONNECT: {
|
||||
al::setNerve(this, &nrvStageSceneStateServerConfigRestartServer);
|
||||
break;
|
||||
}
|
||||
case ServerConfigOption::SETIP: {
|
||||
al::setNerve(this, &nrvStageSceneStateServerConfigOpenKeyboardIP);
|
||||
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() {
|
||||
if (al::isFirstStep(this)) {
|
||||
mGamemodeConfigMenu = &mGamemodeConfigMenus[GameModeManager::instance()->getGameMode()];
|
||||
|
||||
mGamemodeConfigMenu->mList->initDataNoResetSelected(mGamemodeConfigMenu->mMenu->getMenuSize());
|
||||
mGamemodeConfigMenu->mList->addStringData(mGamemodeConfigMenu->mMenu->getStringData(), "TxtContent");
|
||||
|
||||
mCurrentList = mGamemodeConfigMenu->mList;
|
||||
mCurrentMenu = mGamemodeConfigMenu->mLayout;
|
||||
|
||||
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() {
|
||||
|
||||
if (al::isFirstStep(this)) {
|
||||
|
@ -373,9 +344,7 @@ namespace {
|
|||
NERVE_IMPL(StageSceneStateServerConfig, MainMenu)
|
||||
NERVE_IMPL(StageSceneStateServerConfig, OpenKeyboardIP)
|
||||
NERVE_IMPL(StageSceneStateServerConfig, OpenKeyboardPort)
|
||||
NERVE_IMPL(StageSceneStateServerConfig, RestartServer)
|
||||
NERVE_IMPL(StageSceneStateServerConfig, GamemodeConfig)
|
||||
NERVE_IMPL(StageSceneStateServerConfig, GamemodeSelect)
|
||||
NERVE_IMPL(StageSceneStateServerConfig, SaveData)
|
||||
NERVE_IMPL(StageSceneStateServerConfig, ConnectError)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue