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
{"Instance*.Gdb.ARM7.Port", 3334},
{"Instance*.Gdb.ARM9.Port", 3333},
#endif,
#endif
{"LAN.HostNumPlayers", 16},
};

View File

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

View File

@ -843,7 +843,7 @@ void LAN::ProcessLAN(int type)
bool good = true;
if (event.packet->dataLength < sizeof(MPPacketHeader))
good = false;
else if (header->Magic != 0x4946494E)
else if (header->Magic != kPacketMagic)
good = false;
else if (header->SenderID == MyPlayer.ID)
good = false;
@ -881,7 +881,7 @@ void LAN::ProcessLAN(int type)
}
}
void LAN::Process()
void LAN::Process(int inst)
{
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);
MPPacketHeader pktheader;
pktheader.Magic = 0x4946494E;
pktheader.Magic = kPacketMagic;
pktheader.SenderID = MyPlayer.ID;
pktheader.Type = type;
pktheader.Length = len;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -37,8 +37,27 @@
namespace melonDS
{
const u32 kNetplayMagic = 0x5054454E; // NETP
const u32 kProtocolVersion = 1;
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)
{
@ -175,7 +194,7 @@ bool Netplay::StartClient(const char* playername, const char* host, int port)
return false;
}
ENetEvent event;
/*ENetEvent event;
bool conn = false;
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");
enet_peer_reset(peer);
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;
@ -200,6 +287,7 @@ bool Netplay::StartClient(const char* playername, const char* host, int port)
player->Status = 3;
HostAddress = addr.host;
RemotePeers[0] = peer;
Active = true;
IsHost = false;
@ -649,28 +737,57 @@ void Netplay::ProcessHost()
{
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
int id;
for (id = 0; id < 16; id++)
{
if (id >= NumPlayers) break;
if (Players[id].Status == 0) break;
if (Players[id].Status == Player_None) break;
}
if (id < 16)
{
u8 cmd[2];
cmd[0] = 0x01;
cmd[1] = (u8)id;
ENetPacket* pkt = enet_packet_create(cmd, 2, ENET_PACKET_FLAG_RELIABLE);
enet_peer_send(event.peer, 0, pkt);
u8 cmd[11];
cmd[0] = Cmd_ClientInit;
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);
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].Status = 3;
Players[id].Status = Player_Connecting;
Players[id].Address = event.peer->address.host;
event.peer->data = &Players[id];
NumPlayers++;
Platform::Mutex_Unlock(PlayersMutex);
RemotePeers[id] = event.peer;
}
else
{
// ???
enet_peer_disconnect(event.peer, 0);
}
}
break;
@ -737,7 +854,32 @@ void Netplay::ProcessClient()
switch (event.type)
{
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;
case ENET_EVENT_TYPE_DISCONNECT:
@ -754,7 +896,7 @@ void Netplay::ProcessClient()
u8* data = (u8*)event.packet->data;
switch (data[0])
{
case 0x01: // host sending player ID
case Cmd_ClientInit: // host sending player ID
{
if (event.packet->dataLength != 2) break;
@ -782,10 +924,12 @@ printf("client mirror host connecting to %08X:%d\n", mirroraddr.host, mirroraddr
}
break;
case 0x03: // host sending player list
case Cmd_PlayerList: // host sending player list
{
if (event.packet->dataLength != (2+sizeof(Players))) 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];
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';
}
//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;
@ -982,13 +1147,14 @@ printf("mirror client lag notify: %d\n", lag);
}
#endif
void Netplay::ProcessFrame()
void Netplay::ProcessFrame(int inst)
{
/*if (IsMirror)
{
ProcessMirrorClient();
}
else*/
if (inst == 0)
{
if (IsHost)
{
@ -1079,10 +1245,10 @@ void Netplay::ProcessInput()
}
#endif
void Netplay::Process()
void Netplay::Process(int inst)
{
ProcessFrame();
LocalMP::Process();
ProcessFrame(inst);
LocalMP::Process(inst);
}
}

View File

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