lay some groundwork

This commit is contained in:
Arisotura 2024-08-15 16:42:36 +02:00
parent 7e52831ce1
commit b496bb4856
10 changed files with 208 additions and 39 deletions

View File

@ -71,7 +71,7 @@ DefaultList<int> DefaultInts =
#ifdef GDBSTUB_ENABLED #ifdef GDBSTUB_ENABLED
{"Instance*.Gdb.ARM7.Port", 3334}, {"Instance*.Gdb.ARM7.Port", 3334},
{"Instance*.Gdb.ARM9.Port", 3333}, {"Instance*.Gdb.ARM9.Port", 3333},
#endif, #endif
{"LAN.HostNumPlayers", 16}, {"LAN.HostNumPlayers", 16},
}; };

View File

@ -151,7 +151,7 @@ void EmuThread::run()
while (emuStatus != emuStatus_Exit) while (emuStatus != emuStatus_Exit)
{ {
MPInterface::Get().Process(); MPInterface::Get().Process(emuInstance->instanceID);
emuInstance->inputProcess(); emuInstance->inputProcess();
if (emuInstance->hotkeyPressed(HK_FastForwardToggle)) emit windowLimitFPSChange(); if (emuInstance->hotkeyPressed(HK_FastForwardToggle)) emit windowLimitFPSChange();

View File

@ -843,7 +843,7 @@ void LAN::ProcessLAN(int type)
bool good = true; bool good = true;
if (event.packet->dataLength < sizeof(MPPacketHeader)) if (event.packet->dataLength < sizeof(MPPacketHeader))
good = false; good = false;
else if (header->Magic != 0x4946494E) else if (header->Magic != kPacketMagic)
good = false; good = false;
else if (header->SenderID == MyPlayer.ID) else if (header->SenderID == MyPlayer.ID)
good = false; good = false;
@ -881,7 +881,7 @@ void LAN::ProcessLAN(int type)
} }
} }
void LAN::Process() void LAN::Process(int inst)
{ {
if (!Active) return; if (!Active) return;
@ -945,7 +945,7 @@ int LAN::SendPacketGeneric(u32 type, u8* packet, int len, u64 timestamp)
ENetPacket* enetpacket = enet_packet_create(nullptr, sizeof(MPPacketHeader)+len, flags); ENetPacket* enetpacket = enet_packet_create(nullptr, sizeof(MPPacketHeader)+len, flags);
MPPacketHeader pktheader; MPPacketHeader pktheader;
pktheader.Magic = 0x4946494E; pktheader.Magic = kPacketMagic;
pktheader.SenderID = MyPlayer.ID; pktheader.SenderID = MyPlayer.ID;
pktheader.Type = type; pktheader.Type = type;
pktheader.Length = len; pktheader.Length = len;

View File

@ -94,7 +94,7 @@ public:
int GetNumPlayers() { return NumPlayers; } int GetNumPlayers() { return NumPlayers; }
int GetMaxPlayers() { return MaxPlayers; } int GetMaxPlayers() { return MaxPlayers; }
void Process() override; void Process(int inst) override;
void Begin(int inst) override; void Begin(int inst) override;
void End(int inst) override; void End(int inst) override;

View File

@ -29,6 +29,9 @@ using Platform::LogLevel;
namespace melonDS namespace melonDS
{ {
const u32 kPacketMagic = 0x4946494E; // NIFI
LocalMP::LocalMP() noexcept : LocalMP::LocalMP() noexcept :
MPQueueLock(Mutex_Create()) MPQueueLock(Mutex_Create())
{ {
@ -166,7 +169,7 @@ int LocalMP::SendPacketGeneric(int inst, u32 type, u8* packet, int len, u64 time
// TODO: check if the FIFO is full! // TODO: check if the FIFO is full!
MPPacketHeader pktheader; MPPacketHeader pktheader;
pktheader.Magic = 0x4946494E; pktheader.Magic = kPacketMagic;
pktheader.SenderID = inst; pktheader.SenderID = inst;
pktheader.Type = type; pktheader.Type = type;
pktheader.Length = len; pktheader.Length = len;
@ -224,7 +227,7 @@ int LocalMP::RecvPacketGeneric(int inst, u8* packet, bool block, u64* timestamp)
MPPacketHeader pktheader = {}; MPPacketHeader pktheader = {};
FIFORead(inst, 0, &pktheader, sizeof(pktheader)); FIFORead(inst, 0, &pktheader, sizeof(pktheader));
if (pktheader.Magic != 0x4946494E) if (pktheader.Magic != kPacketMagic)
{ {
Log(LogLevel::Warn, "PACKET FIFO OVERFLOW\n"); Log(LogLevel::Warn, "PACKET FIFO OVERFLOW\n");
PacketReadOffset[inst] = MPStatus.PacketWriteOffset; PacketReadOffset[inst] = MPStatus.PacketWriteOffset;
@ -323,7 +326,7 @@ u16 LocalMP::RecvReplies(int inst, u8* packets, u64 timestamp, u16 aidmask)
MPPacketHeader pktheader = {}; MPPacketHeader pktheader = {};
FIFORead(inst, 1, &pktheader, sizeof(pktheader)); FIFORead(inst, 1, &pktheader, sizeof(pktheader));
if (pktheader.Magic != 0x4946494E) if (pktheader.Magic != kPacketMagic)
{ {
Log(LogLevel::Warn, "REPLY FIFO OVERFLOW\n"); Log(LogLevel::Warn, "REPLY FIFO OVERFLOW\n");
ReplyReadOffset[inst] = MPStatus.ReplyWriteOffset; ReplyReadOffset[inst] = MPStatus.ReplyWriteOffset;

View File

@ -48,18 +48,18 @@ public:
LocalMP& operator=(LocalMP&& other) = delete; LocalMP& operator=(LocalMP&& other) = delete;
~LocalMP() noexcept; ~LocalMP() noexcept;
void Process() {} void Process(int inst) override {}
void Begin(int inst); void Begin(int inst) override;
void End(int inst); void End(int inst) override;
int SendPacket(int inst, u8* data, int len, u64 timestamp); int SendPacket(int inst, u8* data, int len, u64 timestamp) override;
int RecvPacket(int inst, u8* data, u64* timestamp); int RecvPacket(int inst, u8* data, u64* timestamp) override;
int SendCmd(int inst, u8* data, int len, u64 timestamp); int SendCmd(int inst, u8* data, int len, u64 timestamp) override;
int SendReply(int inst, u8* data, int len, u64 timestamp, u16 aid); int SendReply(int inst, u8* data, int len, u64 timestamp, u16 aid) override;
int SendAck(int inst, u8* data, int len, u64 timestamp); int SendAck(int inst, u8* data, int len, u64 timestamp) override;
int RecvHostPacket(int inst, u8* data, u64* timestamp); int RecvHostPacket(int inst, u8* data, u64* timestamp) override;
u16 RecvReplies(int inst, u8* data, u64 timestamp, u16 aidmask); u16 RecvReplies(int inst, u8* data, u64 timestamp, u16 aidmask) override;
private: private:
void FIFORead(int inst, int fifo, void* buf, int len) noexcept; void FIFORead(int inst, int fifo, void* buf, int len) noexcept;

View File

@ -27,7 +27,7 @@ namespace melonDS
class DummyMP : public MPInterface class DummyMP : public MPInterface
{ {
public: public:
void Process() override {} void Process(int inst) override {}
void Begin(int inst) override {} void Begin(int inst) override {}
void End(int inst) override {} void End(int inst) override {}

View File

@ -56,7 +56,7 @@ public:
void SetRecvTimeout(int timeout) noexcept { RecvTimeout = timeout; } void SetRecvTimeout(int timeout) noexcept { RecvTimeout = timeout; }
// function called every video frame // function called every video frame
virtual void Process() = 0; virtual void Process(int inst) = 0;
virtual void Begin(int inst) = 0; virtual void Begin(int inst) = 0;
virtual void End(int inst) = 0; virtual void End(int inst) = 0;

View File

@ -37,8 +37,27 @@
namespace melonDS namespace melonDS
{ {
const u32 kNetplayMagic = 0x5054454E; // NETP
const u32 kProtocolVersion = 1;
const u32 kLocalhost = 0x0100007F; const u32 kLocalhost = 0x0100007F;
enum
{
Chan_Input0 = 0, // channels 0-15 -- input from players 0-15 resp.
Chan_Cmd = 16, // channel 16 -- control commands
};
enum
{
Cmd_ClientInit = 1, // 01 -- host->client -- init new client and assign ID
Cmd_PlayerInfo, // 02 -- client->host -- send client player info to host
Cmd_PlayerList, // 03 -- host->client -- broadcast updated player list
//Cmd_PlayerConnect, // 04 -- both -- signal connected state (ready to receive MP frames)
//Cmd_PlayerDisconnect, // 05 -- both -- signal disconnected state (not receiving MP frames)
};
Netplay::Netplay() noexcept : LocalMP(), Inited(false) Netplay::Netplay() noexcept : LocalMP(), Inited(false)
{ {
@ -175,7 +194,7 @@ bool Netplay::StartClient(const char* playername, const char* host, int port)
return false; return false;
} }
ENetEvent event; /*ENetEvent event;
bool conn = false; bool conn = false;
if (enet_host_service(Host, &event, 5000) > 0) if (enet_host_service(Host, &event, 5000) > 0)
{ {
@ -191,6 +210,74 @@ bool Netplay::StartClient(const char* playername, const char* host, int port)
printf("connection failed\n"); printf("connection failed\n");
enet_peer_reset(peer); enet_peer_reset(peer);
return false; return false;
}*/
ENetEvent event;
int conn = 0;
u32 starttick = (u32)Platform::GetMSCount();
const int conntimeout = 5000;
for (;;)
{
u32 curtick = (u32)Platform::GetMSCount();
if (curtick < starttick) break;
int timeout = conntimeout - (int)(curtick - starttick);
if (timeout < 0) break;
if (enet_host_service(Host, &event, timeout) > 0)
{
if (conn == 0 && event.type == ENET_EVENT_TYPE_CONNECT)
{
conn = 1;
}
else if (conn == 1 && event.type == ENET_EVENT_TYPE_RECEIVE)
{
u8* data = event.packet->data;
if (event.channelID != Chan_Cmd) continue;
if (data[0] != Cmd_ClientInit) continue;
if (event.packet->dataLength != 11) continue;
u32 magic = data[1] | (data[2] << 8) | (data[3] << 16) | (data[4] << 24);
u32 version = data[5] | (data[6] << 8) | (data[7] << 16) | (data[8] << 24);
if (magic != kNetplayMagic) continue;
if (version != kProtocolVersion) continue;
if (data[10] > 16) continue;
MaxPlayers = data[10];
// send player information
MyPlayer.ID = data[9];
u8 cmd[9+sizeof(Player)];
cmd[0] = Cmd_PlayerInfo;
cmd[1] = (u8)kNetplayMagic;
cmd[2] = (u8)(kNetplayMagic >> 8);
cmd[3] = (u8)(kNetplayMagic >> 16);
cmd[4] = (u8)(kNetplayMagic >> 24);
cmd[5] = (u8)kProtocolVersion;
cmd[6] = (u8)(kProtocolVersion >> 8);
cmd[7] = (u8)(kProtocolVersion >> 16);
cmd[8] = (u8)(kProtocolVersion >> 24);
memcpy(&cmd[9], &MyPlayer, sizeof(Player));
ENetPacket* pkt = enet_packet_create(cmd, 9+sizeof(Player), ENET_PACKET_FLAG_RELIABLE);
enet_peer_send(event.peer, Chan_Cmd, pkt);
conn = 2;
break;
}
else if (event.type == ENET_EVENT_TYPE_DISCONNECT)
{
conn = 0;
break;
}
}
else
break;
}
if (conn != 2)
{
enet_peer_reset(peer);
enet_host_destroy(Host);
Host = nullptr;
return false;
} }
Player* player = &MyPlayer; Player* player = &MyPlayer;
@ -200,6 +287,7 @@ bool Netplay::StartClient(const char* playername, const char* host, int port)
player->Status = 3; player->Status = 3;
HostAddress = addr.host; HostAddress = addr.host;
RemotePeers[0] = peer;
Active = true; Active = true;
IsHost = false; IsHost = false;
@ -649,28 +737,57 @@ void Netplay::ProcessHost()
{ {
case ENET_EVENT_TYPE_CONNECT: case ENET_EVENT_TYPE_CONNECT:
{ {
if ((NumPlayers >= MaxPlayers) || (NumPlayers >= 16))
{
// game is full, reject connection
enet_peer_disconnect(event.peer, 0);
break;
}
// TODO: reject connection if game is running
// client connected; assign player number // client connected; assign player number
int id; int id;
for (id = 0; id < 16; id++) for (id = 0; id < 16; id++)
{ {
if (id >= NumPlayers) break; if (id >= NumPlayers) break;
if (Players[id].Status == 0) break; if (Players[id].Status == Player_None) break;
} }
if (id < 16) if (id < 16)
{ {
u8 cmd[2]; u8 cmd[11];
cmd[0] = 0x01; cmd[0] = Cmd_ClientInit;
cmd[1] = (u8)id; cmd[1] = (u8)kNetplayMagic;
ENetPacket* pkt = enet_packet_create(cmd, 2, ENET_PACKET_FLAG_RELIABLE); cmd[2] = (u8)(kNetplayMagic >> 8);
enet_peer_send(event.peer, 0, pkt); cmd[3] = (u8)(kNetplayMagic >> 16);
cmd[4] = (u8)(kNetplayMagic >> 24);
cmd[5] = (u8)kProtocolVersion;
cmd[6] = (u8)(kProtocolVersion >> 8);
cmd[7] = (u8)(kProtocolVersion >> 16);
cmd[8] = (u8)(kProtocolVersion >> 24);
cmd[9] = (u8)id;
cmd[10] = MaxPlayers;
ENetPacket* pkt = enet_packet_create(cmd, 11, ENET_PACKET_FLAG_RELIABLE);
enet_peer_send(event.peer, Chan_Cmd, pkt);
Platform::Mutex_Lock(PlayersMutex);
Players[id].ID = id; Players[id].ID = id;
Players[id].Status = 3; Players[id].Status = Player_Connecting;
Players[id].Address = event.peer->address.host; Players[id].Address = event.peer->address.host;
event.peer->data = &Players[id]; event.peer->data = &Players[id];
NumPlayers++; NumPlayers++;
Platform::Mutex_Unlock(PlayersMutex);
RemotePeers[id] = event.peer;
}
else
{
// ???
enet_peer_disconnect(event.peer, 0);
} }
} }
break; break;
@ -737,7 +854,32 @@ void Netplay::ProcessClient()
switch (event.type) switch (event.type)
{ {
case ENET_EVENT_TYPE_CONNECT: case ENET_EVENT_TYPE_CONNECT:
printf("schmo\n"); {
// another client is establishing a direct connection to us
int playerid = -1;
for (int i = 0; i < 16; i++)
{
Player* player = &Players[i];
if (i == MyPlayer.ID) continue;
if (player->Status != Player_Client) continue;
if (player->Address == event.peer->address.host)
{
playerid = i;
break;
}
}
if (playerid < 0)
{
enet_peer_disconnect(event.peer, 0);
break;
}
RemotePeers[playerid] = event.peer;
event.peer->data = &Players[playerid];
}
break; break;
case ENET_EVENT_TYPE_DISCONNECT: case ENET_EVENT_TYPE_DISCONNECT:
@ -754,7 +896,7 @@ void Netplay::ProcessClient()
u8* data = (u8*)event.packet->data; u8* data = (u8*)event.packet->data;
switch (data[0]) switch (data[0])
{ {
case 0x01: // host sending player ID case Cmd_ClientInit: // host sending player ID
{ {
if (event.packet->dataLength != 2) break; if (event.packet->dataLength != 2) break;
@ -782,10 +924,12 @@ printf("client mirror host connecting to %08X:%d\n", mirroraddr.host, mirroraddr
} }
break; break;
case 0x03: // host sending player list case Cmd_PlayerList: // host sending player list
{ {
if (event.packet->dataLength != (2+sizeof(Players))) break; if (event.packet->dataLength != (2+sizeof(Players))) break;
if (data[1] > 16) break; if (data[1] > 16) break;
printf("client: receive player list, %08X %d\n", event.peer->address.host, event.peer->address.port);
Platform::Mutex_Lock(PlayersMutex);
NumPlayers = data[1]; NumPlayers = data[1];
memcpy(Players, &data[2], sizeof(Players)); memcpy(Players, &data[2], sizeof(Players));
@ -794,7 +938,28 @@ printf("client mirror host connecting to %08X:%d\n", mirroraddr.host, mirroraddr
Players[i].Name[31] = '\0'; Players[i].Name[31] = '\0';
} }
//netplayDlg->updatePlayerList(Players, NumPlayers); Platform::Mutex_Unlock(PlayersMutex);
// establish connections to any new clients
for (int i = 0; i < 16; i++)
{
Player* player = &Players[i];
if (i == MyPlayer.ID) continue;
if (player->Status != Player_Client) continue;
if (!RemotePeers[i])
{
ENetAddress peeraddr;
peeraddr.host = player->Address;
peeraddr.port = event.peer->address.port;
ENetPeer* peer = enet_host_connect(Host, &peeraddr, 2, 0);
if (!peer)
{
// TODO deal with this
continue;
}
}
}
} }
break; break;
@ -982,13 +1147,14 @@ printf("mirror client lag notify: %d\n", lag);
} }
#endif #endif
void Netplay::ProcessFrame() void Netplay::ProcessFrame(int inst)
{ {
/*if (IsMirror) /*if (IsMirror)
{ {
ProcessMirrorClient(); ProcessMirrorClient();
} }
else*/ else*/
if (inst == 0)
{ {
if (IsHost) if (IsHost)
{ {
@ -1079,10 +1245,10 @@ void Netplay::ProcessInput()
} }
#endif #endif
void Netplay::Process() void Netplay::Process(int inst)
{ {
ProcessFrame(); ProcessFrame(inst);
LocalMP::Process(); LocalMP::Process(inst);
} }
} }

View File

@ -68,7 +68,7 @@ public:
int GetNumPlayers() { return NumPlayers; } int GetNumPlayers() { return NumPlayers; }
int GetMaxPlayers() { return MaxPlayers; } int GetMaxPlayers() { return MaxPlayers; }
void Process() override; void Process(int inst) override;
private: private:
bool Inited; bool Inited;
@ -103,7 +103,7 @@ private:
void StartLocal(); void StartLocal();
void ProcessHost(); void ProcessHost();
void ProcessClient(); void ProcessClient();
void ProcessFrame(); void ProcessFrame(int inst);
}; };
} }