mirror of
https://github.com/melonDS-emu/melonDS.git
synced 2025-07-25 07:10:00 -06:00
updates to LAN player list thingy
This commit is contained in:
@ -286,6 +286,8 @@ LANDialog::LANDialog(QWidget* parent) : QDialog(parent), ui(new Ui::LANDialog)
|
|||||||
|
|
||||||
QStandardItemModel* model = new QStandardItemModel();
|
QStandardItemModel* model = new QStandardItemModel();
|
||||||
ui->tvPlayerList->setModel(model);
|
ui->tvPlayerList->setModel(model);
|
||||||
|
const QStringList header = {"#", "Player", "Status", "Ping", "IP"};
|
||||||
|
model->setHorizontalHeaderLabels(header);
|
||||||
|
|
||||||
connect(this, &LANDialog::sgUpdatePlayerList, this, &LANDialog::doUpdatePlayerList);
|
connect(this, &LANDialog::sgUpdatePlayerList, this, &LANDialog::doUpdatePlayerList);
|
||||||
}
|
}
|
||||||
@ -302,50 +304,90 @@ void LANDialog::done(int r)
|
|||||||
QDialog::done(r);
|
QDialog::done(r);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LANDialog::updatePlayerList(LAN::Player* players, int num)
|
void LANDialog::updatePlayerList()
|
||||||
{
|
{
|
||||||
emit sgUpdatePlayerList(players, num);
|
playerListMutex.lock();
|
||||||
|
memcpy(playerList, LAN::Players, sizeof(playerList));
|
||||||
|
memcpy(playerPing, LAN::PlayerPing, sizeof(playerPing));
|
||||||
|
numPlayers = LAN::NumPlayers;
|
||||||
|
maxPlayers = LAN::MaxPlayers;
|
||||||
|
myPlayerID = LAN::MyPlayer.ID;
|
||||||
|
hostAddress = LAN::HostAddress;
|
||||||
|
playerListMutex.unlock();
|
||||||
|
|
||||||
|
emit sgUpdatePlayerList();
|
||||||
}
|
}
|
||||||
|
|
||||||
void LANDialog::doUpdatePlayerList(LAN::Player* players, int num)
|
void LANDialog::doUpdatePlayerList()
|
||||||
{
|
{
|
||||||
|
playerListMutex.lock();
|
||||||
|
|
||||||
QStandardItemModel* model = (QStandardItemModel*)ui->tvPlayerList->model();
|
QStandardItemModel* model = (QStandardItemModel*)ui->tvPlayerList->model();
|
||||||
|
int curcount = model->rowCount();
|
||||||
model->clear();
|
int newcount = numPlayers;
|
||||||
model->setRowCount(num);
|
if (curcount > newcount)
|
||||||
|
|
||||||
// TODO: remove IP column in final product
|
|
||||||
|
|
||||||
const QStringList header = {"#", "Player", "Status", "Ping", "IP"};
|
|
||||||
model->setHorizontalHeaderLabels(header);
|
|
||||||
|
|
||||||
for (int i = 0; i < num; i++)
|
|
||||||
{
|
{
|
||||||
LAN::Player* player = &players[i];
|
model->removeRows(newcount, curcount-newcount);
|
||||||
|
}
|
||||||
|
else if (curcount < newcount)
|
||||||
|
{
|
||||||
|
for (int i = curcount; i < newcount; i++)
|
||||||
|
{
|
||||||
|
QList<QStandardItem*> row;
|
||||||
|
row.append(new QStandardItem());
|
||||||
|
row.append(new QStandardItem());
|
||||||
|
row.append(new QStandardItem());
|
||||||
|
row.append(new QStandardItem());
|
||||||
|
row.append(new QStandardItem());
|
||||||
|
model->appendRow(row);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < 16; i++)
|
||||||
|
{
|
||||||
|
LAN::Player* player = &playerList[i];
|
||||||
|
if (player->Status == 0) break;
|
||||||
|
|
||||||
QString id = QString("%0").arg(player->ID+1);
|
QString id = QString("%0").arg(player->ID+1);
|
||||||
model->setItem(i, 0, new QStandardItem(id));
|
model->item(i, 0)->setText(id);
|
||||||
|
|
||||||
QString name = player->Name;
|
QString name = player->Name;
|
||||||
model->setItem(i, 1, new QStandardItem(name));
|
model->item(i, 1)->setText(name);
|
||||||
|
|
||||||
QString status;
|
QString status;
|
||||||
switch (player->Status)
|
switch (player->Status)
|
||||||
{
|
{
|
||||||
case 1: status = ""; break;
|
case 1: status = "Ready"; break;
|
||||||
case 2: status = "Host"; break;
|
case 2: status = "Host"; break;
|
||||||
default: status = "ded"; break;
|
case 3: status = "Connecting"; break;
|
||||||
}
|
}
|
||||||
model->setItem(i, 2, new QStandardItem(status));
|
model->item(i, 2)->setText(status);
|
||||||
|
|
||||||
// TODO: ping
|
if (i == myPlayerID)
|
||||||
model->setItem(i, 3, new QStandardItem("x"));
|
{
|
||||||
|
model->item(i, 3)->setText("");
|
||||||
|
model->item(i, 4)->setText("(local)");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
QString ping = QString("%0 ms").arg(playerPing[i]);
|
||||||
|
model->item(i, 3)->setText(ping);
|
||||||
|
|
||||||
char ip[32];
|
// note on the player IP display
|
||||||
u32 addr = player->Address;
|
// * we make an exception for the host -- the player list is issued by the host, so the host IP would be 127.0.0.1
|
||||||
sprintf(ip, "%d.%d.%d.%d", addr&0xFF, (addr>>8)&0xFF, (addr>>16)&0xFF, addr>>24);
|
// * for the same reason, the host can't know its own IP, so for the current player we force it to 127.0.0.1
|
||||||
model->setItem(i, 4, new QStandardItem(ip));
|
u32 ip;
|
||||||
|
if (player->Status == 1)
|
||||||
|
ip = hostAddress;
|
||||||
|
else
|
||||||
|
ip = player->Address;
|
||||||
|
|
||||||
|
QString ips = QString("%0.%1.%2.%3").arg(ip&0xFF).arg((ip>>8)&0xFF).arg((ip>>16)&0xFF).arg(ip>>24);
|
||||||
|
model->item(i, 4)->setText(ips);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
playerListMutex.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -353,6 +395,7 @@ namespace LAN
|
|||||||
{
|
{
|
||||||
|
|
||||||
const u32 kDiscoveryMagic = 0x444E414C; // LAND
|
const u32 kDiscoveryMagic = 0x444E414C; // LAND
|
||||||
|
const u32 kLANMagic = 0x504E414C; // LANP
|
||||||
const u32 kPacketMagic = 0x4946494E; // NIFI
|
const u32 kPacketMagic = 0x4946494E; // NIFI
|
||||||
|
|
||||||
const u32 kProtocolVersion = 1;
|
const u32 kProtocolVersion = 1;
|
||||||
@ -381,6 +424,7 @@ ENetHost* Host;
|
|||||||
ENetPeer* RemotePeers[16];
|
ENetPeer* RemotePeers[16];
|
||||||
|
|
||||||
Player Players[16];
|
Player Players[16];
|
||||||
|
u32 PlayerPing[16];
|
||||||
int NumPlayers;
|
int NumPlayers;
|
||||||
int MaxPlayers;
|
int MaxPlayers;
|
||||||
|
|
||||||
@ -395,6 +439,8 @@ int LastHostID;
|
|||||||
ENetPeer* LastHostPeer;
|
ENetPeer* LastHostPeer;
|
||||||
std::queue<ENetPacket*> RXQueue;
|
std::queue<ENetPacket*> RXQueue;
|
||||||
|
|
||||||
|
u32 FrameCount;
|
||||||
|
|
||||||
|
|
||||||
bool Init()
|
bool Init()
|
||||||
{
|
{
|
||||||
@ -408,6 +454,7 @@ bool Init()
|
|||||||
|
|
||||||
memset(RemotePeers, 0, sizeof(RemotePeers));
|
memset(RemotePeers, 0, sizeof(RemotePeers));
|
||||||
memset(Players, 0, sizeof(Players));
|
memset(Players, 0, sizeof(Players));
|
||||||
|
memset(PlayerPing, 0, sizeof(PlayerPing));
|
||||||
NumPlayers = 0;
|
NumPlayers = 0;
|
||||||
MaxPlayers = 0;
|
MaxPlayers = 0;
|
||||||
|
|
||||||
@ -417,6 +464,8 @@ bool Init()
|
|||||||
LastHostID = -1;
|
LastHostID = -1;
|
||||||
LastHostPeer = nullptr;
|
LastHostPeer = nullptr;
|
||||||
|
|
||||||
|
FrameCount = 0;
|
||||||
|
|
||||||
// TODO we init enet here but also in Netplay
|
// TODO we init enet here but also in Netplay
|
||||||
// that is redundant
|
// that is redundant
|
||||||
if (enet_initialize() != 0)
|
if (enet_initialize() != 0)
|
||||||
@ -533,7 +582,7 @@ bool StartHost(const char* playername, int numplayers)
|
|||||||
IsHost = true;
|
IsHost = true;
|
||||||
|
|
||||||
if (lanDlg)
|
if (lanDlg)
|
||||||
lanDlg->updatePlayerList(Players, NumPlayers);
|
lanDlg->updatePlayerList();
|
||||||
|
|
||||||
StartDiscovery();
|
StartDiscovery();
|
||||||
return true;
|
return true;
|
||||||
@ -583,21 +632,39 @@ bool StartClient(const char* playername, const char* host)
|
|||||||
u8* data = event.packet->data;
|
u8* data = event.packet->data;
|
||||||
if (event.channelID != 0) continue;
|
if (event.channelID != 0) continue;
|
||||||
if (data[0] != 0x01) continue;
|
if (data[0] != 0x01) continue;
|
||||||
if (event.packet->dataLength != 3) continue;
|
if (event.packet->dataLength != 11) continue;
|
||||||
|
|
||||||
MaxPlayers = data[2];
|
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 != kLANMagic) continue;
|
||||||
|
if (version != kProtocolVersion) continue;
|
||||||
|
|
||||||
|
MaxPlayers = data[10];
|
||||||
|
|
||||||
// send player information
|
// send player information
|
||||||
MyPlayer.ID = data[1];
|
MyPlayer.ID = data[9];
|
||||||
u8 cmd[1+sizeof(Player)];
|
u8 cmd[9+sizeof(Player)];
|
||||||
cmd[0] = 0x02;
|
cmd[0] = 0x02;
|
||||||
memcpy(&cmd[1], &MyPlayer, sizeof(Player));
|
cmd[1] = (u8)kLANMagic;
|
||||||
ENetPacket* pkt = enet_packet_create(cmd, 1+sizeof(Player), ENET_PACKET_FLAG_RELIABLE);
|
cmd[2] = (u8)(kLANMagic >> 8);
|
||||||
|
cmd[3] = (u8)(kLANMagic >> 16);
|
||||||
|
cmd[4] = (u8)(kLANMagic >> 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, 0, pkt);
|
enet_peer_send(event.peer, 0, pkt);
|
||||||
|
|
||||||
conn = 2;
|
conn = 2;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
else if (event.type == ENET_EVENT_TYPE_DISCONNECT)
|
||||||
|
{
|
||||||
|
conn = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
break;
|
break;
|
||||||
@ -614,6 +681,7 @@ bool StartClient(const char* playername, const char* host)
|
|||||||
HostAddress = addr.host;
|
HostAddress = addr.host;
|
||||||
LastHostID = -1;
|
LastHostID = -1;
|
||||||
LastHostPeer = nullptr;
|
LastHostPeer = nullptr;
|
||||||
|
RemotePeers[0] = peer;
|
||||||
|
|
||||||
Active = true;
|
Active = true;
|
||||||
IsHost = false;
|
IsHost = false;
|
||||||
@ -689,6 +757,7 @@ void ProcessDiscovery()
|
|||||||
}
|
}
|
||||||
|
|
||||||
beacon.Magic = tick;
|
beacon.Magic = tick;
|
||||||
|
beacon.SessionName[63] = '\0';
|
||||||
DiscoveryList[key] = beacon;
|
DiscoveryList[key] = beacon;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -718,6 +787,19 @@ void ProcessDiscovery()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void HostUpdatePlayerList()
|
||||||
|
{
|
||||||
|
u8 cmd[2+sizeof(Players)];
|
||||||
|
cmd[0] = 0x03;
|
||||||
|
cmd[1] = (u8)NumPlayers;
|
||||||
|
memcpy(&cmd[2], Players, sizeof(Players));
|
||||||
|
ENetPacket* pkt = enet_packet_create(cmd, 2+sizeof(Players), ENET_PACKET_FLAG_RELIABLE);
|
||||||
|
enet_host_broadcast(Host, 0, pkt);
|
||||||
|
|
||||||
|
if (lanDlg)
|
||||||
|
lanDlg->updatePlayerList();
|
||||||
|
}
|
||||||
|
|
||||||
void ProcessHostEvent(ENetEvent& event)
|
void ProcessHostEvent(ENetEvent& event)
|
||||||
{
|
{
|
||||||
switch (event.type)
|
switch (event.type)
|
||||||
@ -742,11 +824,19 @@ void ProcessHostEvent(ENetEvent& event)
|
|||||||
|
|
||||||
if (id < 16)
|
if (id < 16)
|
||||||
{
|
{
|
||||||
u8 cmd[3];
|
u8 cmd[11];
|
||||||
cmd[0] = 0x01;
|
cmd[0] = 0x01;
|
||||||
cmd[1] = (u8)id;
|
cmd[1] = (u8)kLANMagic;
|
||||||
cmd[2] = MaxPlayers;
|
cmd[2] = (u8)(kLANMagic >> 8);
|
||||||
ENetPacket* pkt = enet_packet_create(cmd, 3, ENET_PACKET_FLAG_RELIABLE);
|
cmd[3] = (u8)(kLANMagic >> 16);
|
||||||
|
cmd[4] = (u8)(kLANMagic >> 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, 0, pkt);
|
enet_peer_send(event.peer, 0, pkt);
|
||||||
|
|
||||||
Players[id].ID = id;
|
Players[id].ID = id;
|
||||||
@ -767,8 +857,18 @@ void ProcessHostEvent(ENetEvent& event)
|
|||||||
|
|
||||||
case ENET_EVENT_TYPE_DISCONNECT:
|
case ENET_EVENT_TYPE_DISCONNECT:
|
||||||
{
|
{
|
||||||
// TODO
|
Player* player = (Player*)event.peer->data;
|
||||||
printf("disco\n");
|
if (!player) break;
|
||||||
|
|
||||||
|
int id = player->ID;
|
||||||
|
RemotePeers[id] = nullptr;
|
||||||
|
|
||||||
|
player->ID = 0;
|
||||||
|
player->Status = 0;
|
||||||
|
NumPlayers--;
|
||||||
|
|
||||||
|
// broadcast updated player list
|
||||||
|
HostUpdatePlayerList();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -781,17 +881,24 @@ void ProcessHostEvent(ENetEvent& event)
|
|||||||
{
|
{
|
||||||
case 0x02: // client sending player info
|
case 0x02: // client sending player info
|
||||||
{
|
{
|
||||||
if (event.packet->dataLength != (1+sizeof(Player))) break;
|
if (event.packet->dataLength != (9+sizeof(Player))) break;
|
||||||
|
|
||||||
|
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 != kLANMagic) || (version != kProtocolVersion))
|
||||||
|
{
|
||||||
|
enet_peer_disconnect(event.peer, 0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
Player player;
|
Player player;
|
||||||
memcpy(&player, &data[1], sizeof(Player));
|
memcpy(&player, &data[9], sizeof(Player));
|
||||||
player.Name[31] = '\0';
|
player.Name[31] = '\0';
|
||||||
|
|
||||||
Player* hostside = (Player*)event.peer->data;
|
Player* hostside = (Player*)event.peer->data;
|
||||||
if (player.ID != hostside->ID)
|
if (player.ID != hostside->ID)
|
||||||
{
|
{
|
||||||
printf("what??? %d =/= %d\n", player.ID, hostside->ID);
|
enet_peer_disconnect(event.peer, 0);
|
||||||
// TODO: disconnect
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -800,15 +907,7 @@ void ProcessHostEvent(ENetEvent& event)
|
|||||||
memcpy(hostside, &player, sizeof(Player));
|
memcpy(hostside, &player, sizeof(Player));
|
||||||
|
|
||||||
// broadcast updated player list
|
// broadcast updated player list
|
||||||
u8 cmd[2+sizeof(Players)];
|
HostUpdatePlayerList();
|
||||||
cmd[0] = 0x03;
|
|
||||||
cmd[1] = (u8)NumPlayers;
|
|
||||||
memcpy(&cmd[2], Players, sizeof(Players));
|
|
||||||
ENetPacket* pkt = enet_packet_create(cmd, 2+sizeof(Players), ENET_PACKET_FLAG_RELIABLE);
|
|
||||||
enet_host_broadcast(Host, 0, pkt);
|
|
||||||
|
|
||||||
if (lanDlg)
|
|
||||||
lanDlg->updatePlayerList(Players, NumPlayers);
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -851,7 +950,7 @@ void ProcessClientEvent(ENetEvent& event)
|
|||||||
for (int i = 0; i < 16; i++)
|
for (int i = 0; i < 16; i++)
|
||||||
{
|
{
|
||||||
Player* player = &Players[i];
|
Player* player = &Players[i];
|
||||||
if (player->ID == MyPlayer.ID) continue;
|
if (i == MyPlayer.ID) continue;
|
||||||
if (player->Status != 1) continue;
|
if (player->Status != 1) continue;
|
||||||
|
|
||||||
if (player->Address == event.peer->address.host)
|
if (player->Address == event.peer->address.host)
|
||||||
@ -874,8 +973,11 @@ void ProcessClientEvent(ENetEvent& event)
|
|||||||
|
|
||||||
case ENET_EVENT_TYPE_DISCONNECT:
|
case ENET_EVENT_TYPE_DISCONNECT:
|
||||||
{
|
{
|
||||||
// TODO
|
Player* player = (Player*)event.peer->data;
|
||||||
printf("shma\n");
|
if (!player) break;
|
||||||
|
|
||||||
|
int id = player->ID;
|
||||||
|
RemotePeers[id] = nullptr;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -899,13 +1001,13 @@ void ProcessClientEvent(ENetEvent& event)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (lanDlg)
|
if (lanDlg)
|
||||||
lanDlg->updatePlayerList(Players, NumPlayers);
|
lanDlg->updatePlayerList();
|
||||||
|
|
||||||
// establish connections to any new clients
|
// establish connections to any new clients
|
||||||
for (int i = 0; i < 16; i++)
|
for (int i = 0; i < 16; i++)
|
||||||
{
|
{
|
||||||
Player* player = &Players[i];
|
Player* player = &Players[i];
|
||||||
if (player->ID == MyPlayer.ID) continue;
|
if (i == MyPlayer.ID) continue;
|
||||||
if (player->Status != 1) continue;
|
if (player->Status != 1) continue;
|
||||||
|
|
||||||
if (!RemotePeers[i])
|
if (!RemotePeers[i])
|
||||||
@ -992,6 +1094,24 @@ void ProcessFrame()
|
|||||||
{
|
{
|
||||||
ProcessDiscovery();
|
ProcessDiscovery();
|
||||||
Process(false);
|
Process(false);
|
||||||
|
|
||||||
|
FrameCount++;
|
||||||
|
if (FrameCount >= 60)
|
||||||
|
{
|
||||||
|
FrameCount = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < 16; i++)
|
||||||
|
{
|
||||||
|
if (Players[i].Status == 0) continue;
|
||||||
|
if (i == MyPlayer.ID) continue;
|
||||||
|
if (!RemotePeers[i]) continue;
|
||||||
|
|
||||||
|
PlayerPing[i] = RemotePeers[i]->roundTripTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lanDlg)
|
||||||
|
lanDlg->updatePlayerList();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -127,18 +127,26 @@ public:
|
|||||||
return dlg;
|
return dlg;
|
||||||
}
|
}
|
||||||
|
|
||||||
void updatePlayerList(LAN::Player* players, int num);
|
void updatePlayerList();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void sgUpdatePlayerList(LAN::Player* players, int num);
|
void sgUpdatePlayerList();
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void done(int r);
|
void done(int r);
|
||||||
|
|
||||||
void doUpdatePlayerList(LAN::Player* players, int num);
|
void doUpdatePlayerList();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Ui::LANDialog* ui;
|
Ui::LANDialog* ui;
|
||||||
|
|
||||||
|
LAN::Player playerList[16];
|
||||||
|
u32 playerPing[16];
|
||||||
|
int numPlayers;
|
||||||
|
int maxPlayers;
|
||||||
|
int myPlayerID;
|
||||||
|
u32 hostAddress;
|
||||||
|
QMutex playerListMutex;
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace LAN
|
namespace LAN
|
||||||
@ -149,6 +157,14 @@ extern bool Active;
|
|||||||
extern std::map<u32, DiscoveryData> DiscoveryList;
|
extern std::map<u32, DiscoveryData> DiscoveryList;
|
||||||
extern QMutex DiscoveryMutex;
|
extern QMutex DiscoveryMutex;
|
||||||
|
|
||||||
|
extern Player Players[16];
|
||||||
|
extern u32 PlayerPing[16];
|
||||||
|
extern int NumPlayers;
|
||||||
|
extern int MaxPlayers;
|
||||||
|
|
||||||
|
extern Player MyPlayer;
|
||||||
|
extern u32 HostAddress;
|
||||||
|
|
||||||
bool Init();
|
bool Init();
|
||||||
void DeInit();
|
void DeInit();
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user