networking
This commit is contained in:
356
engine/networking.cpp
Normal file
356
engine/networking.cpp
Normal file
@@ -0,0 +1,356 @@
|
||||
#include "networking.h"
|
||||
#include "console.h"
|
||||
#include "engine.h"
|
||||
#include "gamemode.h"
|
||||
#include "server.h"
|
||||
#include "steam/isteamfriends.h"
|
||||
#include "steam/isteamnetworking.h"
|
||||
#include "tier0/platform.h"
|
||||
#include "tier0/lib.h"
|
||||
#include "tier1/commandline.h"
|
||||
#include "tier0/network.h"
|
||||
#include "tier1/utlvector.h"
|
||||
#include "baseplayer.h"
|
||||
|
||||
#include "steam/steamnetworkingsockets.h"
|
||||
#include "steam/isteamnetworkingutils.h"
|
||||
#ifndef STEAMNETWORKINGSOCKETS_OPENSOURCE
|
||||
#include "steam/steam_api.h"
|
||||
#endif
|
||||
|
||||
HSteamNetConnection net_connection = 0;
|
||||
HSteamNetConnection net_server = 0;
|
||||
HSteamListenSocket net_listenSocket = -1;
|
||||
CUtlVector<IIClient*> net_clients;
|
||||
|
||||
class CNetworkingCallbacks
|
||||
{
|
||||
STEAM_CALLBACK(CNetworkingCallbacks, ClientConnectedCallback, SteamNetConnectionStatusChangedCallback_t);
|
||||
};
|
||||
|
||||
void CNetworkingCallbacks::ClientConnectedCallback( SteamNetConnectionStatusChangedCallback_t *pCallback )
|
||||
{
|
||||
INetworking::ClientConnectedCallback(pCallback);
|
||||
};
|
||||
|
||||
|
||||
bool net_bIsServer = false;
|
||||
static CNetworkingCallbacks *pCallbacks;
|
||||
|
||||
void INetworking::Init()
|
||||
{
|
||||
Net_Init();
|
||||
|
||||
SteamDatagramErrMsg errMsg = {};
|
||||
#ifdef STEAMNETWORKINGSOCKETS_OPENSOURCE
|
||||
GameNetworkingSockets_Init(NULL, &errMsg)
|
||||
#endif
|
||||
SteamNetworkingUtils()->SetDebugOutputFunction(k_ESteamNetworkingSocketsDebugOutputType_Msg,
|
||||
[](ESteamNetworkingSocketsDebugOutputType severity, const char *szMessage) {
|
||||
V_printf("Steam: %s\n", szMessage);
|
||||
});
|
||||
|
||||
if (ICommandLine::CheckParam("-dedicated"))
|
||||
{
|
||||
pCallbacks = new CNetworkingCallbacks;
|
||||
SteamNetworkingIPAddr localAddress = {};
|
||||
localAddress.Clear();
|
||||
localAddress.SetIPv4(0x7F000001, 27015);
|
||||
net_listenSocket = SteamNetworkingSockets()->CreateListenSocketIP(localAddress, 0, NULL);
|
||||
net_bIsServer = true;
|
||||
}
|
||||
}
|
||||
void INetworking::Deinit()
|
||||
{
|
||||
if (net_listenSocket == -1)
|
||||
return;
|
||||
if (ICommandLine::CheckParam("-dedicated"))
|
||||
SteamNetworkingSockets()->CloseListenSocket(net_listenSocket);
|
||||
else
|
||||
SteamNetworkingSockets()->CloseConnection(net_listenSocket, 0, NULL, false);
|
||||
}
|
||||
|
||||
bool INetworking::IsServer()
|
||||
{
|
||||
return net_bIsServer;
|
||||
}
|
||||
|
||||
bool INetworking::IsClient()
|
||||
{
|
||||
return !net_bIsServer;
|
||||
}
|
||||
|
||||
bool INetworking::IsConnected()
|
||||
{
|
||||
return (bool)net_server;
|
||||
}
|
||||
|
||||
void INetworking::Frame()
|
||||
{
|
||||
SteamNetworkingSockets()->RunCallbacks();
|
||||
|
||||
if (IsServer())
|
||||
{
|
||||
for (auto &client: g_clients)
|
||||
{
|
||||
SteamNetworkingMessage_t *pMessages[64];
|
||||
while (true)
|
||||
{
|
||||
int nMessages = SteamNetworkingSockets()->ReceiveMessagesOnConnection(client->playerHandle, pMessages, 64);
|
||||
if ( nMessages <= 0 )
|
||||
break;
|
||||
for ( int i = 0; i < nMessages; i++ )
|
||||
{
|
||||
ProcessPacket((void*)pMessages[i]->GetData(), pMessages[i]->GetSize(), client);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
SteamNetworkingMessage_t *pMessages[64];
|
||||
while (true)
|
||||
{
|
||||
int nMessages = SteamNetworkingSockets()->ReceiveMessagesOnConnection(net_connection, pMessages, 64);
|
||||
if ( nMessages <= 0 )
|
||||
break;
|
||||
for ( int i = 0; i < nMessages; i++ )
|
||||
{
|
||||
ProcessPacket((void*)pMessages[i]->GetData(), pMessages[i]->GetSize(), NULL);
|
||||
pMessages[i]->Release();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void INetworking::SendData( void *pData, uint32_t nSize, IIClient *pClient, EMessageMode messageMode )
|
||||
{
|
||||
if (!IsConnected() && IsClient())
|
||||
return;
|
||||
int nSendFlags = 0;
|
||||
switch ( messageMode )
|
||||
{
|
||||
case MESSAGE_MODE_UNRELIABLE:
|
||||
nSendFlags |= k_nSteamNetworkingSend_Unreliable;
|
||||
break;
|
||||
case MESSAGE_MODE_RELIABLE:
|
||||
nSendFlags |= k_nSteamNetworkingSend_Reliable;
|
||||
break;
|
||||
};
|
||||
/* Send to server if client is NULL */
|
||||
EResult r = k_EResultNone;
|
||||
if (pClient == NULL)
|
||||
r = SteamNetworkingSockets()->SendMessageToConnection(net_server, pData, nSize, nSendFlags, NULL);
|
||||
else
|
||||
r = SteamNetworkingSockets()->SendMessageToConnection(pClient->playerHandle, pData, nSize, nSendFlags, NULL);
|
||||
}
|
||||
void INetworking::SendDataEverybody( void *pData, uint32_t nSize, EMessageMode messageMode )
|
||||
{
|
||||
for (auto &client: g_clients)
|
||||
{
|
||||
SendData(pData, nSize, client, messageMode);
|
||||
}
|
||||
}
|
||||
|
||||
void INetworking::SendDataEverybodyExcept( void *pData, uint32_t nSize, IIClient *pClient, EMessageMode messageMode )
|
||||
{
|
||||
for (auto &client: g_clients)
|
||||
{
|
||||
if (client == pClient)
|
||||
continue;
|
||||
SendData(pData, nSize, client, messageMode);
|
||||
}
|
||||
}
|
||||
|
||||
void INetworking::SendDataEverybodyExcept( void *pData, uint32_t nSize, CBasePlayer *pPlayer, EMessageMode messageMode )
|
||||
{
|
||||
for (auto &client: g_clients)
|
||||
{
|
||||
if (client->pBasePlayer == pPlayer)
|
||||
continue;
|
||||
SendData(pData, nSize, client, messageMode);
|
||||
}
|
||||
}
|
||||
|
||||
void INetworking::ProcessPacket( void *pData, uint32_t nSize, IIClient *pClient )
|
||||
{
|
||||
Packet_t *pPacketHeader = (Packet_t*)pData;
|
||||
if (IsServer() && pPacketHeader->type != PACKET_TYPE_PLAYER_MOVEMENT)
|
||||
return;
|
||||
if (nSize < sizeof(Packet_t))
|
||||
return;
|
||||
PacketPlayer_t *pPlayerPacket = (PacketPlayer_t*)pData;
|
||||
PacketGameMode_t *pGameModePacket = (PacketGameMode_t*)pData;
|
||||
IIClient *pNewClient;
|
||||
|
||||
switch(pPacketHeader->type)
|
||||
{
|
||||
case PACKET_TYPE_PLAYER_MOVEMENT:
|
||||
if (nSize < sizeof(PacketPlayer_t))
|
||||
return;
|
||||
if (IsServer())
|
||||
{
|
||||
if (pClient->pBasePlayer)
|
||||
pClient->pBasePlayer->Sync(pData, nSize);
|
||||
}
|
||||
for (auto &client: g_clients)
|
||||
{
|
||||
if (client->playerHandle == pPlayerPacket->playerHandle)
|
||||
{
|
||||
if (!client->pBasePlayer)
|
||||
return;
|
||||
client->pBasePlayer->Sync(pData, nSize);
|
||||
return;
|
||||
}
|
||||
}
|
||||
return;
|
||||
case PACKET_TYPE_PLAYER_JOIN:
|
||||
if (nSize != sizeof(PacketPlayer_t))
|
||||
return;
|
||||
// Player join and leave can be processed only by the clients
|
||||
pNewClient = new IIClient;
|
||||
*pNewClient = {
|
||||
.playerID = pPlayerPacket->playerID,
|
||||
.playerHandle = pPlayerPacket->playerHandle,
|
||||
};
|
||||
IIEngine::ConnectClient(pNewClient);
|
||||
|
||||
for (auto &client: g_clients)
|
||||
{
|
||||
CSteamID steamID = CSteamID();
|
||||
if ( client->playerID == 0)
|
||||
V_printf("%s\t", SteamFriends()->GetPlayerNickname((uint64)client->playerID));
|
||||
else
|
||||
V_printf("%s\t", SteamFriends()->GetPersonaName());
|
||||
V_printf("%llu\t", client->playerID);
|
||||
V_printf("%u\n", client->playerHandle);
|
||||
if (client->playerHandle == 0)
|
||||
g_localClient = client;
|
||||
}
|
||||
return;
|
||||
case PACKET_TYPE_PLAYER_LEAVE:
|
||||
IIEngine::DisconnectClientByHandle(pPlayerPacket->playerHandle);
|
||||
return;
|
||||
case PACKET_TYPE_GAMEMODE_START:
|
||||
V_printf("PacketGameMode\n");
|
||||
if (nSize != sizeof(PacketGameMode_t))
|
||||
return;
|
||||
IGameModeManager::StartGameMode(pGameModePacket->szName);
|
||||
return;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void INetworking::GetServerInfo()
|
||||
{
|
||||
}
|
||||
|
||||
uint32_t INetworking_IPv4ToUint(const char *szIP) {
|
||||
if (CUtlString(szIP) == "localhost")
|
||||
return 0x7F000001;
|
||||
|
||||
struct in_addr ipAdress;
|
||||
if (inet_pton(AF_INET, szIP, &ipAdress) != 1) {
|
||||
V_printf("Invalid IPv4 address: %s\n", szIP);
|
||||
return 0;
|
||||
}
|
||||
return ntohl(ipAdress.s_addr);
|
||||
}
|
||||
|
||||
void INetworking::JoinServer( const char *szIP )
|
||||
{
|
||||
if (net_connection)
|
||||
{
|
||||
g_clients = {};
|
||||
SteamNetworkingSockets()->CloseConnection(net_connection, 0, NULL, false);
|
||||
}
|
||||
SteamNetworkingIPAddr localAddress = {};
|
||||
localAddress.Clear();
|
||||
localAddress.SetIPv4(INetworking_IPv4ToUint(szIP), 27015);
|
||||
net_connection = SteamNetworkingSockets()->ConnectByIPAddress(localAddress, 0, NULL);
|
||||
net_server = net_connection;
|
||||
}
|
||||
|
||||
void INetworking::ClientConnectedCallback( SteamNetConnectionStatusChangedCallback_t *pCallback )
|
||||
{
|
||||
IIClient *pClient = new IIClient;
|
||||
switch (pCallback->m_info.m_eState)
|
||||
{
|
||||
case k_ESteamNetworkingConnectionState_Connecting:
|
||||
V_printf("Awaiting connection: %llu\n",pCallback->m_info.m_identityRemote.GetSteamID64());
|
||||
SteamNetworkingSockets()->AcceptConnection(pCallback->m_hConn);
|
||||
break;
|
||||
case k_ESteamNetworkingConnectionState_Connected:
|
||||
V_printf("Connected: %llu %u\n",pCallback->m_info.m_identityRemote.GetSteamID64(), pCallback->m_hConn);
|
||||
*pClient = {
|
||||
.playerID = pCallback->m_info.m_identityRemote.GetSteamID64(),
|
||||
.playerHandle = pCallback->m_hConn,
|
||||
};
|
||||
// send out to all clients
|
||||
for (auto &client: g_clients)
|
||||
{
|
||||
PacketPlayer_t packet = {
|
||||
.playerID = pClient->playerID,
|
||||
.playerHandle = pClient->playerHandle,
|
||||
};
|
||||
packet.type = PACKET_TYPE_PLAYER_JOIN;
|
||||
SendData(&packet, sizeof(packet), client, MESSAGE_MODE_RELIABLE);
|
||||
};
|
||||
IIEngine::ConnectClient(pClient);
|
||||
// register all clients on connected one
|
||||
for (auto &client: g_clients)
|
||||
{
|
||||
PacketPlayer_t packet = {
|
||||
.playerID = client->playerID,
|
||||
.playerHandle = client->playerHandle,
|
||||
};
|
||||
if (client == pClient)
|
||||
{
|
||||
packet.playerID = 0;
|
||||
packet.playerHandle = 0;
|
||||
}
|
||||
packet.type = PACKET_TYPE_PLAYER_JOIN;
|
||||
SendData(&packet, sizeof(packet), pClient, MESSAGE_MODE_RELIABLE);
|
||||
};
|
||||
|
||||
|
||||
IGameModeManager::RestartCurrentGameMode();
|
||||
break;
|
||||
case k_ESteamNetworkingConnectionState_ClosedByPeer:
|
||||
case k_ESteamNetworkingConnectionState_ProblemDetectedLocally:
|
||||
SteamNetworkingSockets()->CloseConnection(pCallback->m_hConn, 0, NULL, false);
|
||||
|
||||
V_printf("Disconnected: %llu %u\n",pCallback->m_info.m_identityRemote.GetSteamID64(), pCallback->m_hConn);
|
||||
IIEngine::DisconnectClientByHandle(pCallback->m_hConn);
|
||||
|
||||
// send out to all clients
|
||||
for (auto &client: g_clients)
|
||||
{
|
||||
PacketPlayer_t packet = {
|
||||
.playerID = pCallback->m_info.m_identityRemote.GetSteamID64(),
|
||||
.playerHandle = pCallback->m_hConn,
|
||||
};
|
||||
packet.type = PACKET_TYPE_PLAYER_LEAVE;
|
||||
SendData(&packet, sizeof(packet), client, MESSAGE_MODE_RELIABLE);
|
||||
};
|
||||
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void INetworking_Connect( int argc, char **argv )
|
||||
{
|
||||
if (ICommandLine::CheckParam("-dedicated"))
|
||||
return;
|
||||
if (argc != 2)
|
||||
{
|
||||
V_printf("connect <IPv4>\n");
|
||||
return;
|
||||
}
|
||||
|
||||
INetworking::JoinServer(argv[1]);
|
||||
};
|
||||
|
||||
ConCommand ConnectCmd("connect", INetworking_Connect);
|
||||
Reference in New Issue
Block a user