mirror of
https://github.com/melonDS-emu/melonDS.git
synced 2025-07-26 07:39:56 -06:00
Backport LAN (#2131)
backport the old LAN feature to the modern melonDS codebase.
This commit is contained in:
@ -6,6 +6,9 @@ add_library(net-utils STATIC
|
||||
Net_Slirp.cpp
|
||||
PacketDispatcher.cpp
|
||||
LocalMP.cpp
|
||||
LAN.cpp
|
||||
Netplay.cpp
|
||||
MPInterface.cpp
|
||||
)
|
||||
|
||||
target_include_directories(net-utils PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}")
|
||||
@ -21,3 +24,12 @@ else()
|
||||
add_subdirectory(libslirp EXCLUDE_FROM_ALL)
|
||||
target_link_libraries(net-utils PUBLIC slirp)
|
||||
endif()
|
||||
|
||||
if (USE_VCPKG)
|
||||
find_package(unofficial-enet CONFIG REQUIRED)
|
||||
target_link_libraries(net-utils PRIVATE unofficial::enet::enet)
|
||||
else()
|
||||
pkg_check_modules(ENet REQUIRED IMPORTED_TARGET libenet)
|
||||
fix_interface_includes(PkgConfig::ENet)
|
||||
target_link_libraries(net-utils PUBLIC PkgConfig::ENet)
|
||||
endif()
|
||||
|
1091
src/net/LAN.cpp
Normal file
1091
src/net/LAN.cpp
Normal file
File diff suppressed because it is too large
Load Diff
156
src/net/LAN.h
Normal file
156
src/net/LAN.h
Normal file
@ -0,0 +1,156 @@
|
||||
/*
|
||||
Copyright 2016-2024 melonDS team
|
||||
|
||||
This file is part of melonDS.
|
||||
|
||||
melonDS is free software: you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation, either version 3 of the License, or (at your option)
|
||||
any later version.
|
||||
|
||||
melonDS is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with melonDS. If not, see http://www.gnu.org/licenses/.
|
||||
*/
|
||||
|
||||
#ifndef LAN_H
|
||||
#define LAN_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <queue>
|
||||
|
||||
#include <enet/enet.h>
|
||||
|
||||
#ifndef socket_t
|
||||
#ifdef __WIN32__
|
||||
#include <winsock2.h>
|
||||
#define socket_t SOCKET
|
||||
#else
|
||||
#define socket_t int
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include "types.h"
|
||||
#include "Platform.h"
|
||||
#include "MPInterface.h"
|
||||
|
||||
namespace melonDS
|
||||
{
|
||||
|
||||
class LAN : public MPInterface
|
||||
{
|
||||
public:
|
||||
LAN() noexcept;
|
||||
LAN(const LAN&) = delete;
|
||||
LAN& operator=(const LAN&) = delete;
|
||||
LAN(LAN&& other) = delete;
|
||||
LAN& operator=(LAN&& other) = delete;
|
||||
~LAN() noexcept;
|
||||
|
||||
enum PlayerStatus
|
||||
{
|
||||
Player_None = 0, // no player in this entry
|
||||
Player_Client, // game client
|
||||
Player_Host, // game host
|
||||
Player_Connecting, // player still connecting
|
||||
Player_Disconnected, // player disconnected
|
||||
};
|
||||
|
||||
struct Player
|
||||
{
|
||||
int ID;
|
||||
char Name[32];
|
||||
PlayerStatus Status;
|
||||
u32 Address;
|
||||
|
||||
bool IsLocalPlayer;
|
||||
u32 Ping;
|
||||
};
|
||||
|
||||
struct DiscoveryData
|
||||
{
|
||||
u32 Magic;
|
||||
u32 Version;
|
||||
u32 Tick;
|
||||
char SessionName[64];
|
||||
u8 NumPlayers;
|
||||
u8 MaxPlayers;
|
||||
u8 Status; // 0=idle 1=playing
|
||||
};
|
||||
|
||||
bool StartDiscovery();
|
||||
void EndDiscovery();
|
||||
bool StartHost(const char* player, int numplayers);
|
||||
bool StartClient(const char* player, const char* host);
|
||||
void EndSession();
|
||||
|
||||
std::map<u32, DiscoveryData> GetDiscoveryList();
|
||||
std::vector<Player> GetPlayerList();
|
||||
int GetNumPlayers() { return NumPlayers; }
|
||||
int GetMaxPlayers() { return MaxPlayers; }
|
||||
|
||||
void Process() override;
|
||||
|
||||
void Begin(int inst) override;
|
||||
void End(int inst) override;
|
||||
|
||||
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:
|
||||
bool Inited;
|
||||
bool Active;
|
||||
bool IsHost;
|
||||
|
||||
ENetHost* Host;
|
||||
ENetPeer* RemotePeers[16];
|
||||
|
||||
socket_t DiscoverySocket;
|
||||
u32 DiscoveryLastTick;
|
||||
std::map<u32, DiscoveryData> DiscoveryList;
|
||||
Platform::Mutex* DiscoveryMutex;
|
||||
|
||||
Player Players[16];
|
||||
int NumPlayers;
|
||||
int MaxPlayers;
|
||||
Platform::Mutex* PlayersMutex;
|
||||
|
||||
Player MyPlayer;
|
||||
u32 HostAddress;
|
||||
|
||||
u16 ConnectedBitmask;
|
||||
|
||||
int MPRecvTimeout;
|
||||
int LastHostID;
|
||||
ENetPeer* LastHostPeer;
|
||||
std::queue<ENetPacket*> RXQueue;
|
||||
|
||||
u32 FrameCount;
|
||||
|
||||
void ProcessDiscovery();
|
||||
|
||||
void HostUpdatePlayerList();
|
||||
void ClientUpdatePlayerList();
|
||||
|
||||
void ProcessHostEvent(ENetEvent& event);
|
||||
void ProcessClientEvent(ENetEvent& event);
|
||||
void ProcessEvent(ENetEvent& event);
|
||||
void ProcessLAN(int type);
|
||||
|
||||
int SendPacketGeneric(u32 type, u8* packet, int len, u64 timestamp);
|
||||
int RecvPacketGeneric(u8* packet, bool block, u64* timestamp);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // LAN_H
|
@ -19,8 +19,6 @@
|
||||
#include <cstring>
|
||||
|
||||
#include "LocalMP.h"
|
||||
#include "Platform.h"
|
||||
#include "types.h"
|
||||
|
||||
using namespace melonDS;
|
||||
using namespace melonDS::Platform;
|
||||
|
@ -21,6 +21,7 @@
|
||||
|
||||
#include "types.h"
|
||||
#include "Platform.h"
|
||||
#include "MPInterface.h"
|
||||
|
||||
namespace melonDS
|
||||
{
|
||||
@ -33,20 +34,11 @@ struct MPStatusData
|
||||
u16 MPReplyBitmask; // bitmask of which clients replied in time
|
||||
};
|
||||
|
||||
struct MPPacketHeader
|
||||
{
|
||||
u32 Magic;
|
||||
u32 SenderID;
|
||||
u32 Type; // 0=regular 1=CMD 2=reply 3=ack
|
||||
u32 Length;
|
||||
u64 Timestamp;
|
||||
};
|
||||
|
||||
constexpr u32 kPacketQueueSize = 0x10000;
|
||||
constexpr u32 kReplyQueueSize = 0x10000;
|
||||
constexpr u32 kMaxFrameSize = 0x948;
|
||||
|
||||
class LocalMP
|
||||
class LocalMP : public MPInterface
|
||||
{
|
||||
public:
|
||||
LocalMP() noexcept;
|
||||
@ -56,8 +48,7 @@ public:
|
||||
LocalMP& operator=(LocalMP&& other) = delete;
|
||||
~LocalMP() noexcept;
|
||||
|
||||
[[nodiscard]] int GetRecvTimeout() const noexcept { return RecvTimeout; }
|
||||
void SetRecvTimeout(int timeout) noexcept { RecvTimeout = timeout; }
|
||||
void Process() {}
|
||||
|
||||
void Begin(int inst);
|
||||
void End(int inst);
|
||||
@ -69,11 +60,13 @@ public:
|
||||
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);
|
||||
|
||||
private:
|
||||
void FIFORead(int inst, int fifo, void* buf, int len) noexcept;
|
||||
void FIFOWrite(int inst, int fifo, void* buf, int len) noexcept;
|
||||
int SendPacketGeneric(int inst, u32 type, u8* packet, int len, u64 timestamp) noexcept;
|
||||
int RecvPacketGeneric(int inst, u8* packet, bool block, u64* timestamp) noexcept;
|
||||
|
||||
Platform::Mutex* MPQueueLock;
|
||||
MPStatusData MPStatus {};
|
||||
u8 MPPacketQueue[kPacketQueueSize] {};
|
||||
@ -81,8 +74,6 @@ private:
|
||||
u32 PacketReadOffset[16] {};
|
||||
u32 ReplyReadOffset[16] {};
|
||||
|
||||
int RecvTimeout = 25;
|
||||
|
||||
int LastHostID = -1;
|
||||
Platform::Semaphore* SemPool[32] {};
|
||||
};
|
||||
|
68
src/net/MPInterface.cpp
Normal file
68
src/net/MPInterface.cpp
Normal file
@ -0,0 +1,68 @@
|
||||
/*
|
||||
Copyright 2016-2024 melonDS team
|
||||
|
||||
This file is part of melonDS.
|
||||
|
||||
melonDS is free software: you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation, either version 3 of the License, or (at your option)
|
||||
any later version.
|
||||
|
||||
melonDS is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with melonDS. If not, see http://www.gnu.org/licenses/.
|
||||
*/
|
||||
|
||||
#include "MPInterface.h"
|
||||
#include "LocalMP.h"
|
||||
#include "LAN.h"
|
||||
|
||||
namespace melonDS
|
||||
{
|
||||
|
||||
class DummyMP : public MPInterface
|
||||
{
|
||||
public:
|
||||
void Process() override {}
|
||||
|
||||
void Begin(int inst) override {}
|
||||
void End(int inst) override {}
|
||||
|
||||
int SendPacket(int inst, u8* data, int len, u64 timestamp) override { return 0; }
|
||||
int RecvPacket(int inst, u8* data, u64* timestamp) override { return 0; }
|
||||
int SendCmd(int inst, u8* data, int len, u64 timestamp) override { return 0; }
|
||||
int SendReply(int inst, u8* data, int len, u64 timestamp, u16 aid) override { return 0; }
|
||||
int SendAck(int inst, u8* data, int len, u64 timestamp) override { return 0; }
|
||||
int RecvHostPacket(int inst, u8* data, u64* timestamp) override { return 0; }
|
||||
u16 RecvReplies(int inst, u8* data, u64 timestamp, u16 aidmask) override { return 0; }
|
||||
};
|
||||
|
||||
|
||||
std::unique_ptr<MPInterface> MPInterface::Current(std::make_unique<DummyMP>());
|
||||
MPInterfaceType MPInterface::CurrentType = MPInterface_Dummy;
|
||||
|
||||
|
||||
void MPInterface::Set(MPInterfaceType type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case MPInterface_Local:
|
||||
Current = std::make_unique<LocalMP>();
|
||||
break;
|
||||
|
||||
case MPInterface_LAN:
|
||||
Current = std::make_unique<LAN>();
|
||||
break;
|
||||
|
||||
default:
|
||||
Current = std::make_unique<DummyMP>();
|
||||
break;
|
||||
}
|
||||
|
||||
CurrentType = type;
|
||||
}
|
||||
|
||||
}
|
82
src/net/MPInterface.h
Normal file
82
src/net/MPInterface.h
Normal file
@ -0,0 +1,82 @@
|
||||
/*
|
||||
Copyright 2016-2024 melonDS team
|
||||
|
||||
This file is part of melonDS.
|
||||
|
||||
melonDS is free software: you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation, either version 3 of the License, or (at your option)
|
||||
any later version.
|
||||
|
||||
melonDS is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with melonDS. If not, see http://www.gnu.org/licenses/.
|
||||
*/
|
||||
|
||||
#ifndef MPINTERFACE_H
|
||||
#define MPINTERFACE_H
|
||||
|
||||
#include <memory>
|
||||
#include "types.h"
|
||||
|
||||
namespace melonDS
|
||||
{
|
||||
|
||||
// TODO: provision for excluding unwanted interfaces at compile time
|
||||
enum MPInterfaceType
|
||||
{
|
||||
MPInterface_Dummy = -1,
|
||||
MPInterface_Local,
|
||||
MPInterface_LAN,
|
||||
MPInterface_Netplay,
|
||||
};
|
||||
|
||||
struct MPPacketHeader
|
||||
{
|
||||
u32 Magic;
|
||||
u32 SenderID;
|
||||
u32 Type; // 0=regular 1=CMD 2=reply 3=ack
|
||||
u32 Length;
|
||||
u64 Timestamp;
|
||||
};
|
||||
|
||||
class MPInterface
|
||||
{
|
||||
public:
|
||||
virtual ~MPInterface() = default;
|
||||
|
||||
static MPInterface& Get() { return *Current; }
|
||||
static MPInterfaceType GetType() { return CurrentType; }
|
||||
static void Set(MPInterfaceType type);
|
||||
|
||||
[[nodiscard]] int GetRecvTimeout() const noexcept { return RecvTimeout; }
|
||||
void SetRecvTimeout(int timeout) noexcept { RecvTimeout = timeout; }
|
||||
|
||||
// function called every video frame
|
||||
virtual void Process() = 0;
|
||||
|
||||
virtual void Begin(int inst) = 0;
|
||||
virtual void End(int inst) = 0;
|
||||
|
||||
virtual int SendPacket(int inst, u8* data, int len, u64 timestamp) = 0;
|
||||
virtual int RecvPacket(int inst, u8* data, u64* timestamp) = 0;
|
||||
virtual int SendCmd(int inst, u8* data, int len, u64 timestamp) = 0;
|
||||
virtual int SendReply(int inst, u8* data, int len, u64 timestamp, u16 aid) = 0;
|
||||
virtual int SendAck(int inst, u8* data, int len, u64 timestamp) = 0;
|
||||
virtual int RecvHostPacket(int inst, u8* data, u64* timestamp) = 0;
|
||||
virtual u16 RecvReplies(int inst, u8* data, u64 timestamp, u16 aidmask) = 0;
|
||||
|
||||
protected:
|
||||
int RecvTimeout = 25;
|
||||
|
||||
private:
|
||||
static MPInterfaceType CurrentType;
|
||||
static std::unique_ptr<MPInterface> Current;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // MPINTERFACE_H
|
1085
src/net/Netplay.cpp
Normal file
1085
src/net/Netplay.cpp
Normal file
File diff suppressed because it is too large
Load Diff
57
src/net/Netplay.h
Normal file
57
src/net/Netplay.h
Normal file
@ -0,0 +1,57 @@
|
||||
/*
|
||||
Copyright 2016-2024 melonDS team
|
||||
|
||||
This file is part of melonDS.
|
||||
|
||||
melonDS is free software: you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation, either version 3 of the License, or (at your option)
|
||||
any later version.
|
||||
|
||||
melonDS is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with melonDS. If not, see http://www.gnu.org/licenses/.
|
||||
*/
|
||||
|
||||
#ifndef NETPLAY_H
|
||||
#define NETPLAY_H
|
||||
|
||||
#include "types.h"
|
||||
|
||||
namespace Netplay
|
||||
{
|
||||
|
||||
struct Player
|
||||
{
|
||||
int ID;
|
||||
char Name[32];
|
||||
int Status; // 0=no player 1=normal 2=host 3=connecting
|
||||
melonDS::u32 Address;
|
||||
};
|
||||
|
||||
|
||||
extern bool Active;
|
||||
|
||||
bool Init();
|
||||
void DeInit();
|
||||
|
||||
void StartHost(const char* player, int port);
|
||||
void StartClient(const char* player, const char* host, int port);
|
||||
void StartMirror(const Player* player);
|
||||
|
||||
melonDS::u32 PlayerAddress(int id);
|
||||
|
||||
void StartGame();
|
||||
void StartLocal();
|
||||
|
||||
void StartGame();
|
||||
|
||||
void ProcessFrame();
|
||||
void ProcessInput();
|
||||
|
||||
}
|
||||
|
||||
#endif // NETPLAY_H
|
Reference in New Issue
Block a user