steam relay networking

This commit is contained in:
2026-03-01 23:06:28 +02:00
parent 03c560c2b7
commit 468d765aa1
16 changed files with 628 additions and 101 deletions

View File

@@ -12,6 +12,7 @@
#ifdef STEAM #ifdef STEAM
#include "steam/steam_api.h" #include "steam/steam_api.h"
#include "steam/steam_gameserver.h"
#endif #endif
IRenderContext *g_pRenderContext; IRenderContext *g_pRenderContext;
@@ -21,17 +22,30 @@ IGameWindowManager *g_pWindowManager;
CServerGameDLL *g_pServerGame; CServerGameDLL *g_pServerGame;
CClientGameDLL *g_pClientGame; CClientGameDLL *g_pClientGame;
extern "C" void __cdecl SteamAPIDebug( ESteamNetworkingSocketsDebugOutputType nType, const char *pszMsg )
{
V_printf("STEAM: %s\n", pszMsg);
}
extern "C" void FunnyMain( int argc, char **argv ) extern "C" void FunnyMain( int argc, char **argv )
{ {
CommandLine()->CreateCommandLine(argc, argv); CommandLine()->CreateCommandLine(argc, argv);
EngineConsts_t stConstants = {}; EngineConsts_t stConstants = {};
#ifdef STEAM #ifdef STEAM
if(SteamAPI_RestartAppIfNecessary(480))
{
V_printf("Mshallah we are doing reboot\n");
Plat_Exit(0);
}
stConstants.m_bIsSteam = true; stConstants.m_bIsSteam = true;
if (!SteamAPI_Init()) if (!SteamAPI_Init())
Plat_FatalErrorFunc("SteamAPI_Init failed lol\n"); Plat_FatalErrorFunc("SteamAPI_Init failed lol\n");
stConstants.LaunchServer = LaunchLocalBridge; stConstants.LaunchServer = LaunchServerAtSteamRelay;
stConstants.ConnectSteamServer = ConnectBySteamID; stConstants.ConnectSteamServer = ConnectBySteamID;
//SteamNetworkingUtils()->SetDebugOutputFunction(k_ESteamNetworkingSocketsDebugOutputType_Debug, SteamAPIDebug);
#endif #endif
stConstants.m_bIsDedicated = CommandLine()->CheckParam("-dedicated"); stConstants.m_bIsDedicated = CommandLine()->CheckParam("-dedicated");
stConstants.LaunchLocalBridge = LaunchLocalBridge; stConstants.LaunchLocalBridge = LaunchLocalBridge;
@@ -75,9 +89,13 @@ extern "C" void FunnyMain( int argc, char **argv )
double fPrevious = Plat_GetTime(); double fPrevious = Plat_GetTime();
for (;;) { for (;;) {
#ifdef STEAM
SteamAPI_RunCallbacks();
#endif
double fCurrent = Plat_GetTime(); double fCurrent = Plat_GetTime();
double fDelta = fCurrent-fPrevious; double fDelta = fCurrent-fPrevious;
fPrevious = fCurrent; fPrevious = fCurrent;
g_pServerGame->m_pBridge->Frame(fDelta); g_pServerGame->m_pBridge->Frame(fDelta);
if (!stConstants.m_bIsDedicated) if (!stConstants.m_bIsDedicated)

View File

@@ -12,13 +12,16 @@ public:
virtual ~CLocalNetworkServer() override; virtual ~CLocalNetworkServer() override;
virtual void NetThink() override; virtual void NetThink() override;
virtual void SetCallback( NetCallbackFn fnCallback ) override;
virtual uint32_t BHasUpdates() override; virtual uint32_t BHasUpdates() override;
virtual NetPacket_t RecievePacket() override; virtual NetPacket_t RecievePacket() override;
virtual NetPacket_t PeekPacket() override;
virtual NetPacket_t PeekPacket() override;
virtual void SendPacket( NetPacket_t stPacket ) override; virtual void SendPacket( NetPacket_t stPacket ) override;
virtual bool BIsActive() override;
virtual uint64_t GetSteamID() override; virtual uint64_t GetSteamID() override;
virtual const char *GetIP() override; virtual const char *GetIP() override;
virtual uint16_t GetPort() override; virtual uint16_t GetPort() override;
@@ -27,6 +30,7 @@ public:
CUtlVector<NetPacket_t> m_packets; CUtlVector<NetPacket_t> m_packets;
CUtlVector<NetPacket_t> m_clientPackets; CUtlVector<NetPacket_t> m_clientPackets;
CUtlVector<void*> m_freedPackets; CUtlVector<void*> m_freedPackets;
NetCallbackFn m_fnCallback;
const uint16_t m_uPort; const uint16_t m_uPort;
}; };
@@ -41,16 +45,18 @@ CLocalNetworkServer::~CLocalNetworkServer()
} }
void CLocalNetworkServer::SetCallback( NetCallbackFn fnCallback )
{
m_fnCallback = fnCallback;
}
void CLocalNetworkServer::NetThink() void CLocalNetworkServer::NetThink()
{ {
m_lock.Lock();
for ( auto p: m_freedPackets) for ( auto p: m_freedPackets)
{ {
V_free(p); V_free(p);
} }
m_freedPackets = {}; m_freedPackets = {};
m_lock.Unlock();
} }
@@ -61,23 +67,19 @@ uint32_t CLocalNetworkServer::BHasUpdates()
NetPacket_t CLocalNetworkServer::RecievePacket() NetPacket_t CLocalNetworkServer::RecievePacket()
{ {
m_lock.Lock();
if (!BHasUpdates()) if (!BHasUpdates())
return {}; return {};
NetPacket_t p = m_clientPackets[0]; NetPacket_t p = m_clientPackets[0];
m_clientPackets.RemoveHead(1); m_clientPackets.RemoveHead(1);
m_freedPackets.AppendTail(p.pData); m_freedPackets.AppendTail(p.pData);
m_lock.Unlock();
return p; return p;
} }
NetPacket_t CLocalNetworkServer::PeekPacket() NetPacket_t CLocalNetworkServer::PeekPacket()
{ {
m_lock.Lock();
if (!BHasUpdates()) if (!BHasUpdates())
return {}; return {};
NetPacket_t p = m_clientPackets[0]; NetPacket_t p = m_clientPackets[0];
m_lock.Unlock();
return p; return p;
} }
@@ -86,14 +88,17 @@ void CLocalNetworkServer::SendPacket( NetPacket_t stPacket )
{ {
NetPacket_t stSavedPacked; NetPacket_t stSavedPacked;
stSavedPacked.uSize = stPacket.uSize; stSavedPacked.uSize = stPacket.uSize;
stSavedPacked.m_uOwner = 0;
stSavedPacked.pData = V_malloc(stPacket.uSize); stSavedPacked.pData = V_malloc(stPacket.uSize);
V_memcpy(stSavedPacked.pData, stPacket.pData, stPacket.uSize); V_memcpy(stSavedPacked.pData, stPacket.pData, stPacket.uSize);
m_lock.Lock();
m_packets.AppendTail(stSavedPacked); m_packets.AppendTail(stSavedPacked);
m_lock.Unlock();
} }
bool CLocalNetworkServer::BIsActive()
{
return true;
}
uint64_t CLocalNetworkServer::GetSteamID() uint64_t CLocalNetworkServer::GetSteamID()
{ {
@@ -117,12 +122,15 @@ public:
virtual ~CLocalNetworkClient() override; virtual ~CLocalNetworkClient() override;
virtual void NetThink() override; virtual void NetThink() override;
virtual void SetCallback( NetCallbackFn fnCallback ) override;
virtual uint32_t BHasUpdates() override; virtual uint32_t BHasUpdates() override;
virtual NetPacket_t RecievePacket() override; virtual NetPacket_t RecievePacket() override;
virtual NetPacket_t PeekPacket() override; virtual NetPacket_t PeekPacket() override;
virtual void SendPacket( NetPacket_t stPacket ) override; virtual void SendPacket( NetPacket_t stPacket ) override;
virtual bool BIsActive() override;
virtual uint64_t GetSteamID() override; virtual uint64_t GetSteamID() override;
virtual const char *GetIP() override; virtual const char *GetIP() override;
@@ -131,6 +139,11 @@ public:
CLocalNetworkServer *m_pServer; CLocalNetworkServer *m_pServer;
}; };
bool CLocalNetworkClient::BIsActive()
{
return true;
}
CLocalNetworkClient::CLocalNetworkClient( uint16_t uPort ) CLocalNetworkClient::CLocalNetworkClient( uint16_t uPort )
{ {
m_pServer = s_pLocalServers[uPort]; m_pServer = s_pLocalServers[uPort];
@@ -154,23 +167,19 @@ uint32_t CLocalNetworkClient::BHasUpdates()
NetPacket_t CLocalNetworkClient::RecievePacket() NetPacket_t CLocalNetworkClient::RecievePacket()
{ {
m_pServer->m_lock.Lock();
if (!BHasUpdates()) if (!BHasUpdates())
return {}; return {};
NetPacket_t p = m_pServer->m_packets[0]; NetPacket_t p = m_pServer->m_packets[0];
m_pServer->m_packets.RemoveHead(1); m_pServer->m_packets.RemoveHead(1);
m_pServer->m_freedPackets.AppendTail(p.pData); m_pServer->m_freedPackets.AppendTail(p.pData);
m_pServer->m_lock.Unlock();
return p; return p;
} }
NetPacket_t CLocalNetworkClient::PeekPacket() NetPacket_t CLocalNetworkClient::PeekPacket()
{ {
m_pServer->m_lock.Lock();
if (!BHasUpdates()) if (!BHasUpdates())
return {}; return {};
NetPacket_t p = m_pServer->m_packets[0]; NetPacket_t p = m_pServer->m_packets[0];
m_pServer->m_lock.Unlock();
return p; return p;
} }
@@ -179,12 +188,15 @@ void CLocalNetworkClient::SendPacket( NetPacket_t stPacket )
{ {
NetPacket_t stSavedPacked; NetPacket_t stSavedPacked;
stSavedPacked.uSize = stPacket.uSize; stSavedPacked.uSize = stPacket.uSize;
stSavedPacked.m_uOwner = 0;
stSavedPacked.pData = V_malloc(stPacket.uSize); stSavedPacked.pData = V_malloc(stPacket.uSize);
V_memcpy(stSavedPacked.pData, stPacket.pData, stPacket.uSize); V_memcpy(stSavedPacked.pData, stPacket.pData, stPacket.uSize);
m_pServer->m_lock.Lock();
m_pServer->m_clientPackets.AppendTail(stSavedPacked); m_pServer->m_clientPackets.AppendTail(stSavedPacked);
m_pServer->m_lock.Unlock(); }
void CLocalNetworkClient::SetCallback( NetCallbackFn fnCallback )
{
} }

View File

@@ -1,5 +1,11 @@
#include "inetworkserver.h" #include "inetworkserver.h"
#include "inetworkclient.h" #include "inetworkclient.h"
#include "tier0/lib.h"
#include "tier1/utlmutex.h"
#include "tier1/utlvector.h"
#ifdef STEAM
#include "steam/steam_gameserver.h"
#endif
#include "steam/isteamnetworkingsockets.h" #include "steam/isteamnetworkingsockets.h"
class CSteamNetworkServer: public INetworkBase class CSteamNetworkServer: public INetworkBase
@@ -9,22 +15,37 @@ public:
virtual ~CSteamNetworkServer() override; virtual ~CSteamNetworkServer() override;
virtual void NetThink() override; virtual void NetThink() override;
virtual void SetCallback( NetCallbackFn fnCallback ) override;
virtual uint32_t BHasUpdates() override; virtual uint32_t BHasUpdates() override;
virtual NetPacket_t PeekPacket() override;
virtual NetPacket_t RecievePacket() override; virtual NetPacket_t RecievePacket() override;
virtual void SendPacket( NetPacket_t stPacket ) override; virtual void SendPacket( NetPacket_t stPacket ) override;
virtual bool BIsActive() override;
virtual uint64_t GetSteamID() override; virtual uint64_t GetSteamID() override;
virtual const char *GetIP() override; virtual const char *GetIP() override;
virtual uint16_t GetPort() override; virtual uint16_t GetPort() override;
ISteamNetworkingSockets *m_pInterface;
HSteamListenSocket m_hSocket; HSteamListenSocket m_hSocket;
NetCallbackFn m_fnCallback;
HSteamNetPollGroup m_hPollGroup;
uint64_t m_uSteamId;
CUtlVector<HSteamNetPollGroup> m_hConnections;
STEAM_GAMESERVER_CALLBACK(CSteamNetworkServer, ClientConnected, SteamNetConnectionStatusChangedCallback_t);
STEAM_GAMESERVER_CALLBACK(CSteamNetworkServer, SteamNetAuthenticated, SteamNetAuthenticationStatus_t);
}; };
CSteamNetworkServer::CSteamNetworkServer( uint16_t uPort ) CSteamNetworkServer::CSteamNetworkServer( uint16_t uPort )
{ {
m_hSocket = SteamNetworkingSockets()->CreateListenSocketP2P(uPort, 0, NULL); m_pInterface = SteamGameServerNetworkingSockets();
m_hSocket = m_pInterface->CreateListenSocketP2P(0, 0, NULL);
m_hPollGroup = m_pInterface->CreatePollGroup();
} }
CSteamNetworkServer::~CSteamNetworkServer() CSteamNetworkServer::~CSteamNetworkServer()
@@ -37,8 +58,17 @@ void CSteamNetworkServer::NetThink()
{ {
} }
void CSteamNetworkServer::SetCallback( NetCallbackFn fnCallback )
{
m_fnCallback = fnCallback;
}
uint32_t CSteamNetworkServer::BHasUpdates() uint32_t CSteamNetworkServer::BHasUpdates()
{
return 0;
}
NetPacket_t CSteamNetworkServer::PeekPacket()
{ {
} }
@@ -51,6 +81,21 @@ NetPacket_t CSteamNetworkServer::RecievePacket()
void CSteamNetworkServer::SendPacket( NetPacket_t stPacket ) void CSteamNetworkServer::SendPacket( NetPacket_t stPacket )
{ {
if ( stPacket.m_uOwner == 0 )
{
for ( auto c: m_hConnections )
{
if (stPacket.m_eArrival == PACKET_MAY_ARRIVE)
m_pInterface->SendMessageToConnection(c, stPacket.pData, stPacket.uSize, k_nSteamNetworkingSend_Unreliable, 0);
if (stPacket.m_eArrival == PACKET_MUST_ARRIVE)
m_pInterface->SendMessageToConnection(c, stPacket.pData, stPacket.uSize, k_nSteamNetworkingSend_Reliable, 0);
}
}
}
bool CSteamNetworkServer::BIsActive()
{
return true;
} }
@@ -69,6 +114,189 @@ uint16_t CSteamNetworkServer::GetPort()
return 0; return 0;
} }
void CSteamNetworkServer::ClientConnected( SteamNetConnectionStatusChangedCallback_t *pParam )
{
uint32_t uResult;
NetCallback_t callback = {};
switch (pParam->m_info.m_eState)
{
case k_ESteamNetworkingConnectionState_Connecting:
callback.m_eType = NET_TRYING_TO_CONNECT;
callback.m_ullUserID = pParam->m_info.m_identityRemote.GetSteamID64();
break;
case k_ESteamNetworkingConnectionState_Connected:
callback.m_eType = NET_CONNECTED;
callback.m_ullUserID = pParam->m_info.m_identityRemote.GetSteamID64();
m_pInterface->SetConnectionPollGroup(pParam->m_hConn, m_hPollGroup);
m_hConnections.AppendTail(pParam->m_hConn);
break;
default:
break;
}
V_printf("%p\n", m_fnCallback);
if (m_fnCallback)
uResult = m_fnCallback(&callback);
else
uResult = 0;
switch (pParam->m_info.m_eState)
{
case k_ESteamNetworkingConnectionState_Connecting:
if (uResult != 0)
m_pInterface->AcceptConnection(pParam->m_hConn);
else
m_pInterface->CloseConnection(pParam->m_hConn, 0, "Connection denied", 0);
break;
default:
break;
}
}
void CSteamNetworkServer::SteamNetAuthenticated( SteamNetAuthenticationStatus_t *pParam )
{
NetCallback_t callback = {};
callback.m_eType = NET_SERVER_READY_TO_USE;
if ( pParam->m_eAvail != k_ESteamNetworkingAvailability_Current )
return;
if (m_fnCallback)
m_fnCallback(&callback);
}
class CSteamNetworkClient: public INetworkBase
{
public:
CSteamNetworkClient( uint64_t uID, uint16_t uPort );
virtual ~CSteamNetworkClient() override;
virtual void NetThink() override;
virtual void SetCallback( NetCallbackFn fnCallback ) override;
virtual uint32_t BHasUpdates() override;
virtual NetPacket_t PeekPacket() override;
virtual NetPacket_t RecievePacket() override;
virtual void SendPacket( NetPacket_t stPacket ) override;
virtual bool BIsActive() override;
virtual uint64_t GetSteamID() override;
virtual const char *GetIP() override;
virtual uint16_t GetPort() override;
ISteamNetworkingSockets *m_pInterface;
HSteamNetConnection m_hConnection;
CUtlVector<NetPacket_t> m_incomingPackets = {};
CUtlVector<SteamNetworkingMessage_t*> m_incomingSteamPackets = {};
CUtlVector<SteamNetworkingMessage_t*> m_freeSteamPackets = {};
CUtlLock m_lock;
};
CSteamNetworkClient::CSteamNetworkClient( uint64_t uID, uint16_t uPort )
{
m_pInterface = SteamNetworkingSockets();
SteamNetworkingIdentity id = {};
id.Clear();
id.SetSteamID64(uID);
m_hConnection = m_pInterface->ConnectP2P(id, 0, 0, NULL);
}
CSteamNetworkClient::~CSteamNetworkClient()
{
}
void CSteamNetworkClient::NetThink()
{
int nReceived = 1;
for ( auto p: m_freeSteamPackets )
{
p->Release();
}
m_freeSteamPackets = {};
while (nReceived)
{
SteamNetworkingMessage_t *pMessages[64];
nReceived = m_pInterface->ReceiveMessagesOnConnection(m_hConnection, pMessages, 64);
for ( int i = 0; i < nReceived; i++ )
{
SteamNetConnectionInfo_t info = {};
m_pInterface->GetConnectionInfo(pMessages[i]->GetConnection(), &info);
m_incomingSteamPackets.AppendTail(pMessages[i]);
NetPacket_t packet = {};
packet.m_uOwner = info.m_identityRemote.GetSteamID64();
packet.uSize = pMessages[i]->GetSize();
packet.pData = (void*)pMessages[i]->GetData();
m_incomingPackets.AppendTail(packet);
}
}
}
void CSteamNetworkClient::SetCallback( NetCallbackFn fnCallback )
{
}
uint32_t CSteamNetworkClient::BHasUpdates()
{
return m_incomingPackets.GetSize();
}
NetPacket_t CSteamNetworkClient::PeekPacket()
{
m_lock.Lock();
if (!BHasUpdates())
return {};
NetPacket_t p = m_incomingPackets[0];
m_lock.Unlock();
return p;
}
NetPacket_t CSteamNetworkClient::RecievePacket()
{
m_lock.Lock();
if (!BHasUpdates())
return {};
NetPacket_t p = m_incomingPackets[0];
m_freeSteamPackets.AppendTail(m_incomingSteamPackets[0]);
m_incomingSteamPackets.RemoveHead(1);
m_incomingPackets.RemoveHead(1);
m_lock.Unlock();
return p;
}
void CSteamNetworkClient::SendPacket( NetPacket_t stPacket )
{
}
bool CSteamNetworkClient::BIsActive()
{
return true;
}
uint64_t CSteamNetworkClient::GetSteamID()
{
return 0;
}
const char *CSteamNetworkClient::GetIP()
{
return 0;
}
uint16_t CSteamNetworkClient::GetPort()
{
return 0;
}
INetworkBase *LaunchServerAtSteamRelay( uint16_t uPort ) INetworkBase *LaunchServerAtSteamRelay( uint16_t uPort )
{ {
@@ -78,5 +306,11 @@ INetworkBase *LaunchServerAtSteamRelay( uint16_t uPort )
INetworkBase *ConnectBySteamID( uint64_t uID, uint16_t uPort ) INetworkBase *ConnectBySteamID( uint64_t uID, uint16_t uPort )
{ {
return NULL; CSteamNetworkClient *pBase = new CSteamNetworkClient(uID, uPort);
if (pBase->m_hConnection == k_HSteamNetConnection_Invalid)
{
delete pBase;
return NULL;
}
return pBase;
} }

0
engine/steamserver.cpp Normal file
View File

View File

@@ -128,7 +128,9 @@ BEGIN_DATADESC_NOBASE(C_BaseEntity)
END_DATADESC() END_DATADESC()
IMPLEMENT_RECV_DT_NOBASE(C_BaseEntity) IMPLEMENT_RECV_DT_NOBASE(C_BaseEntity)
NetPropFloat3(m_vPosition) NetPropFloat3(m_vPosition),
NetPropQuaternion(m_vRotation),
NetPropFloat3(m_vScale)
END_RECV_DT() END_RECV_DT()
IMPLEMENT_EMPTY_SEND_DT_NOBASE(C_BaseEntity) IMPLEMENT_EMPTY_SEND_DT_NOBASE(C_BaseEntity)

View File

@@ -33,9 +33,12 @@ DECLARE_BUILD_STAGE(Client)
"../shared", "../shared",
"../../public", "../../public",
FUNNYSTDLIB"public", FUNNYSTDLIB"public",
EXTERNAL"cglm/include" EXTERNAL"cglm/include",
EXTERNAL"steamworks/public",
}; };
compileProject.bFPIC = true; compileProject.bFPIC = true;
if ( GET_PROJECT_VALUE(config, "steam") == "true" )
compileProject.macros.AppendTail({"STEAM", "TRUE"});
ldProject = ccompiler->Compile(&compileProject); ldProject = ccompiler->Compile(&compileProject);
if ( GET_PROJECT_VALUE(config, "static") == "true" ) if ( GET_PROJECT_VALUE(config, "static") == "true" )
@@ -44,6 +47,10 @@ DECLARE_BUILD_STAGE(Client)
} }
else else
{ {
if ( GET_PROJECT_VALUE(config, "steam") == "true" ) {
ldProject.libraryDirectories.AppendTail(EXTERNAL"steamworks/redistributable_bin/linux64");
ldProject.libraries.AppendTail("steam_api");
}
ldProject.linkType = ELINK_DYNAMIC_LIBRARY; ldProject.linkType = ELINK_DYNAMIC_LIBRARY;
ldProject.libraryObjects = { ldProject.libraryObjects = {
GET_PROJECT_LIBRARY(tier0, "tier0"), GET_PROJECT_LIBRARY(tier0, "tier0"),

View File

@@ -1,4 +1,5 @@
#include "tier2/ifilesystem.h" #include "tier2/ifilesystem.h"
#include "tier0/commandline.h"
#include "materialsystem/imaterialsystem.h" #include "materialsystem/imaterialsystem.h"
#include "enginebridge.h" #include "enginebridge.h"
#include "worldrender.h" #include "worldrender.h"
@@ -9,6 +10,10 @@
#include "cglm/cglm.h" #include "cglm/cglm.h"
#include "inetworkclient.h" #include "inetworkclient.h"
#include "netprotocol.h" #include "netprotocol.h"
#ifdef STEAM
#include "steam/isteamgameserver.h"
#include "steam/steam_gameserver.h"
#endif
IFileSystem *filesystem; IFileSystem *filesystem;
IRenderContext *g_pRenderContext; IRenderContext *g_pRenderContext;
@@ -16,7 +21,9 @@ IGameWindow *g_pMainWindow;
static CEngineVars s_vars; static CEngineVars s_vars;
CEngineVars *g_pEngineVars = &s_vars; CEngineVars *g_pEngineVars = &s_vars;
EngineConsts_t *g_pEngineConstants; EngineConsts_t *g_pEngineConstants;
INetworkBase *g_pServerBridge; INetworkBase *g_pServerBridge;
INetworkBase *g_pServerConnection;
class CFunnyGameBridge: public IEngineBridge class CFunnyGameBridge: public IEngineBridge
{ {
@@ -25,6 +32,11 @@ class CFunnyGameBridge: public IEngineBridge
virtual void Frame( float fDelta ) override; virtual void Frame( float fDelta ) override;
virtual void Shutdown() override; virtual void Shutdown() override;
virtual void ConnectInterface( const char *psz, void *pInterface ) override; virtual void ConnectInterface( const char *psz, void *pInterface ) override;
void TryToConnectToServer();
bool m_bIsConnectedToSteamRelay;
bool m_bIsConnectedToServer;
}; };
IEngineBridge *EngineBridge() IEngineBridge *EngineBridge()
@@ -35,16 +47,29 @@ IEngineBridge *EngineBridge()
EXPOSE_INTERFACE_FN(EngineBridge, IEngineBridge, ENGINE_BRIDGE_INTERFACE_VERSION) EXPOSE_INTERFACE_FN(EngineBridge, IEngineBridge, ENGINE_BRIDGE_INTERFACE_VERSION)
void CFunnyGameBridge::Init() void CFunnyGameBridge::Init()
{ {
g_pWorldRenderer->Init(); g_pWorldRenderer->Init();
g_pServerBridge = g_pEngineConstants->ConnectLocalBridge(0); #ifdef STEAM
if (g_pEngineConstants->m_bIsSteam)
{
SteamErrMsg err = { 0 };
m_bIsConnectedToSteamRelay = 0;
SteamNetworkingUtils()->InitRelayNetworkAccess();
}
#endif
PlayerJoined_t join = { m_bIsConnectedToServer = false;
MESSAGE_PLAYER_JOINED, g_pServerBridge = g_pEngineConstants->ConnectLocalBridge(0);
"LocalPlayer" if (g_pServerBridge)
}; {
g_pServerBridge->SendPacket({&join, sizeof(join)}); PlayerJoined_t join = {
MESSAGE_PLAYER_JOINED,
"LocalPlayer"
};
g_pServerBridge->SendPacket({&join, sizeof(join)});
}
} }
void CFunnyGameBridge::Tick( float fDelta ) void CFunnyGameBridge::Tick( float fDelta )
@@ -70,55 +95,106 @@ searchIndex:
return (char*)pEntity+pCurrentMap->m_pFields[uCurrentIndex].m_uOffset; return (char*)pEntity+pCurrentMap->m_pFields[uCurrentIndex].m_uOffset;
} }
void CFunnyGameBridge::TryToConnectToServer()
{
#ifdef STEAM
if (g_pEngineConstants->m_bIsSteam)
{
if (m_bIsConnectedToSteamRelay != 0 )
return;
if ( SteamNetworkingUtils()->GetRelayNetworkStatus(NULL) == k_ESteamNetworkingAvailability_Current)
{
m_bIsConnectedToSteamRelay = 1;
V_printf("%llu\n", SteamUser()->GetSteamID().ConvertToUint64());
if (CommandLine()->ParamValue("-steam-connect"))
{
char *pEnd = NULL;
uint64_t uValue = strtoull(CommandLine()->ParamValue("-steam-connect"), &pEnd, 10);
g_pServerConnection = g_pEngineConstants->ConnectSteamServer(uValue, FUNNY_SECURE_PORT);
if (g_pServerConnection)
{
m_bIsConnectedToServer = true;
}
return;
}
}
}
#endif
}
void CFunnyGameBridge::Frame( float fDelta ) void CFunnyGameBridge::Frame( float fDelta )
{ {
g_pEngineVars->m_fTime += fDelta; g_pEngineVars->m_fTime += fDelta;
g_pEngineVars->m_fDeltaTime = fDelta; g_pEngineVars->m_fDeltaTime = fDelta;
g_pServerBridge->NetThink(); TryToConnectToServer();
while ( g_pServerBridge->BHasUpdates() )
{
NetPacket_t packet = g_pServerBridge->PeekPacket();
// discard it
if (packet.uSize < sizeof (EMessageType))
continue;
PlayerPacket_t *pPacket = (PlayerPacket_t*)packet.pData;
C_BaseEntity *pEntity;
switch (pPacket->m_eType)
{
case MESSAGE_ENTITY_CLASS_SYNC:
pEntity = EntitySystem()->CreateByClassnameWithIndex(
(char*)pPacket->m_entityClass.m_szEntityName, pPacket->m_entityClass.m_uIndex
);
pEntity->Spawn();
g_pServerBridge->RecievePacket();
break;
case MESSAGE_ENTITY_DATA_SYNC:
pEntity = EntitySystem()->GetEntities()[pPacket->m_entityData.m_uIndex];
union {
void *pData;
char *pcCurrentData;
EntityDataSyncValue_t *pcSyncValue;
};
pData = pPacket;
pcCurrentData += sizeof(EntityDataSync_t);
for ( uint32_t u = 0; u < pPacket->m_entityData.m_uCount; u++ )
{
uint32_t uVariableSize = pcSyncValue->m_uVariableSize;
void *pValueData = (float*)ENT_GetNetMapData(
pEntity,
pEntity->GetRecvMap(),
pcSyncValue->m_uVariableIndex);
pcCurrentData += sizeof(EntityDataSyncValue_t); INetworkBase *pCurrentServer = g_pServerBridge;
if (pValueData) pCurrentServer = g_pServerBridge;
V_memcpy(pValueData, pcCurrentData, uVariableSize); if (m_bIsConnectedToServer)
pcCurrentData += (uVariableSize+7) & ~7; if (g_pServerConnection->BIsActive())
pCurrentServer = g_pServerConnection;
if (pCurrentServer)
{
pCurrentServer->NetThink();
while ( pCurrentServer->BHasUpdates() )
{
NetPacket_t packet = pCurrentServer->PeekPacket();
// discard it
if (packet.uSize < sizeof (EMessageType))
continue;
PlayerPacket_t *pPacket = (PlayerPacket_t*)packet.pData;
C_BaseEntity *pEntity;
switch (pPacket->m_eType)
{
case MESSAGE_ENTITY_CLASS_SYNC:
pEntity = EntitySystem()->CreateByClassnameWithIndex(
(char*)pPacket->m_entityClass.m_szEntityName, pPacket->m_entityClass.m_uIndex
);
if (pEntity == NULL)
{
pCurrentServer->RecievePacket();
continue;
}
pEntity->Spawn();
pCurrentServer->RecievePacket();
break;
case MESSAGE_ENTITY_DATA_SYNC:
pEntity = EntitySystem()->GetEntities()[pPacket->m_entityData.m_uIndex];
if (pEntity == NULL)
{
pCurrentServer->RecievePacket();
continue;
}
union {
void *pData;
char *pcCurrentData;
EntityDataSyncValue_t *pcSyncValue;
};
pData = pPacket;
pcCurrentData += sizeof(EntityDataSync_t);
for ( uint32_t u = 0; u < pPacket->m_entityData.m_uCount; u++ )
{
uint32_t uVariableSize = pcSyncValue->m_uVariableSize;
void *pValueData = (float*)ENT_GetNetMapData(
pEntity,
pEntity->GetRecvMap(),
pcSyncValue->m_uVariableIndex);
pcCurrentData += sizeof(EntityDataSyncValue_t);
if (pValueData)
V_memcpy(pValueData, pcCurrentData, uVariableSize);
pcCurrentData += (uVariableSize+7) & ~7;
}
pCurrentServer->RecievePacket();
break;
default:
pCurrentServer->RecievePacket();
V_printf("worng packet\n");
continue;
} }
g_pServerBridge->RecievePacket();
break;
default:
continue;
} }
} }

View File

@@ -25,6 +25,12 @@ void CBaseEntity::Spawn()
void CBaseEntity::SetAbsAngles( float fPitch, float fYaw, float fRoll ) void CBaseEntity::SetAbsAngles( float fPitch, float fYaw, float fRoll )
{ {
versor q;
glm_euler_yzx_quat((vec3){fPitch, fYaw, fRoll}, q);
m_vRotation.x = q[0];
m_vRotation.y = q[1];
m_vRotation.z = q[2];
m_vRotation.w = q[3];
} }
void CBaseEntity::SetAbsOrigin( Vector origin ) void CBaseEntity::SetAbsOrigin( Vector origin )
@@ -42,7 +48,6 @@ void CBaseEntity::SetScale( float fScale )
QAngle CBaseEntity::GetAbsQAngles( void ) QAngle CBaseEntity::GetAbsQAngles( void )
{ {
} }
Quat CBaseEntity::GetAbsAngles( void ) Quat CBaseEntity::GetAbsAngles( void )
{ {
@@ -119,7 +124,9 @@ BEGIN_DATADESC_NOBASE(CBaseEntity)
END_DATADESC() END_DATADESC()
IMPLEMENT_SEND_DT_NOBASE(CBaseEntity) IMPLEMENT_SEND_DT_NOBASE(CBaseEntity)
NetPropFloat3(m_vPosition) NetPropFloat3(m_vPosition),
NetPropQuaternion(m_vRotation),
NetPropFloat3(m_vScale),
END_SEND_DT() END_SEND_DT()
IMPLEMENT_EMPTY_RECV_DT_NOBASE(CBaseEntity) IMPLEMENT_EMPTY_RECV_DT_NOBASE(CBaseEntity)

View File

@@ -27,9 +27,12 @@ DECLARE_BUILD_STAGE(Server)
".", ".",
"../shared", "../shared",
FUNNYSTDLIB"public", FUNNYSTDLIB"public",
EXTERNAL"cglm/include" EXTERNAL"cglm/include",
EXTERNAL"steamworks/public",
}; };
compileProject.bFPIC = true; compileProject.bFPIC = true;
if ( GET_PROJECT_VALUE(config, "steam") == "true" )
compileProject.macros.AppendTail({"STEAM", "TRUE"});
ldProject = ccompiler->Compile(&compileProject); ldProject = ccompiler->Compile(&compileProject);
if ( GET_PROJECT_VALUE(config, "static") == "true" ) if ( GET_PROJECT_VALUE(config, "static") == "true" )
{ {
@@ -37,6 +40,10 @@ DECLARE_BUILD_STAGE(Server)
} }
else else
{ {
if ( GET_PROJECT_VALUE(config, "steam") == "true" ) {
ldProject.libraryDirectories.AppendTail(EXTERNAL"steamworks/redistributable_bin/linux64");
ldProject.libraries.AppendTail("steam_api");
}
ldProject.linkType = ELINK_DYNAMIC_LIBRARY; ldProject.linkType = ELINK_DYNAMIC_LIBRARY;
ldProject.libraryObjects = { ldProject.libraryObjects = {
GET_PROJECT_LIBRARY(tier0, "tier0"), GET_PROJECT_LIBRARY(tier0, "tier0"),

View File

@@ -92,7 +92,8 @@ CBaseEntity *CEntitySystem::CreateByClassname( const char *szName )
iSelectedSlot, iSelectedSlot,
}; };
V_strncpy((char*)stClassSync.m_szEntityName, szName, 256); V_strncpy((char*)stClassSync.m_szEntityName, szName, 256);
g_pClientBridge->SendPacket({&stClassSync, sizeof(stClassSync)}); if (g_pCurrentConnection)
g_pCurrentConnection->SendPacket({&stClassSync, sizeof(stClassSync)});
return pEntity; return pEntity;
} }
IEntityFactory *CEntitySystem::GetFactoryByClassname( const char *szName ) IEntityFactory *CEntitySystem::GetFactoryByClassname( const char *szName )
@@ -113,6 +114,25 @@ void CEntitySystem::Think()
CBaseEntity *pEntity; CBaseEntity *pEntity;
int i; int i;
for ( i = 0; i < MAX_EDICTS; i++ )
{
pEntity = m_pEntities[i];
if ( pEntity == NULL )
continue;
if ( !pEntity->m_pfnThink )
continue;
(pEntity->*pEntity->m_pfnThink)(0);
}
}
void CEntitySystem::NetThink( INetworkBase *pBase )
{
CBaseEntity *pEntity;
int i;
uint32_t u; uint32_t u;
uint32_t x; uint32_t x;
uint32_t uSize; uint32_t uSize;
@@ -125,19 +145,15 @@ void CEntitySystem::Think()
EntityDataSyncValue_t *pValue; EntityDataSyncValue_t *pValue;
}; };
for ( i = 0; i < MAX_EDICTS; i++ ) for ( i = 0; i < MAX_EDICTS; i++ )
{ {
pEntity = m_pEntities[i]; pEntity = m_pEntities[i];
if ( pEntity == NULL ) if ( pEntity == NULL )
continue; continue;
if ( !pEntity->m_pfnThink ) if ( !pEntity->m_pfnThink )
continue; continue;
(pEntity->*pEntity->m_pfnThink)(0);
pNetMap = pEntity->GetSendMap(); pNetMap = pEntity->GetSendMap();
uSize = sizeof(EntityDataSyncValue_t); uSize = sizeof(EntityDataSyncValue_t);
x = 0; x = 0;
@@ -177,9 +193,10 @@ void CEntitySystem::Think()
} }
pNetMap = pNetMap->m_pBase; pNetMap = pNetMap->m_pBase;
} }
g_pClientBridge->SendPacket({pData, uSize}); if (g_pCurrentConnection)
g_pCurrentConnection->SendPacket({pData, uSize});
V_free(pData); V_free(pData);
} }
} }

View File

@@ -7,6 +7,8 @@
#ifndef ENTITIES_H #ifndef ENTITIES_H
#define ENTITIES_H #define ENTITIES_H
#include "networkbase.h"
class IEntityFactory; class IEntityFactory;
class CBaseEntity; class CBaseEntity;
@@ -23,6 +25,7 @@ public:
virtual IEntityFactory *GetFactoryByClassname( const char *szName ); virtual IEntityFactory *GetFactoryByClassname( const char *szName );
virtual void Think(); virtual void Think();
virtual void NetThink( INetworkBase *pBase );
virtual CBaseEntity **GetEntities(); virtual CBaseEntity **GetEntities();
private: private:
CBaseEntity *m_pEntities[MAX_EDICTS]; CBaseEntity *m_pEntities[MAX_EDICTS];

View File

@@ -5,6 +5,11 @@
#include "game.h" #include "game.h"
#include "inetworkserver.h" #include "inetworkserver.h"
#include "netprotocol.h" #include "netprotocol.h"
#ifdef STEAM
#include "steam/isteamgameserver.h"
#include "steam/steam_gameserver.h"
#endif
IFileSystem *filesystem; IFileSystem *filesystem;
IRenderContext *g_pRenderContext; IRenderContext *g_pRenderContext;
@@ -13,6 +18,8 @@ static CEngineVars s_vars;
CEngineVars *g_pEngineVars = &s_vars; CEngineVars *g_pEngineVars = &s_vars;
EngineConsts_t *g_pEngineConstants; EngineConsts_t *g_pEngineConstants;
INetworkBase *g_pClientBridge; INetworkBase *g_pClientBridge;
INetworkBase *g_pPublicConnection;
INetworkBase *g_pCurrentConnection;
class CFunnyGameBridge: public IEngineBridge class CFunnyGameBridge: public IEngineBridge
{ {
@@ -21,6 +28,9 @@ class CFunnyGameBridge: public IEngineBridge
virtual void Frame( float fDelta ) override; virtual void Frame( float fDelta ) override;
virtual void Shutdown() override; virtual void Shutdown() override;
virtual void ConnectInterface( const char *psz, void *pInterface ) override; virtual void ConnectInterface( const char *psz, void *pInterface ) override;
bool m_bIsConnectedToSteamRelay;
float m_fNetUpdateTimer;
}; };
@@ -32,9 +42,64 @@ IEngineBridge *EngineBridge()
EXPOSE_INTERFACE_FN(EngineBridge, IEngineBridge, ENGINE_BRIDGE_INTERFACE_VERSION) EXPOSE_INTERFACE_FN(EngineBridge, IEngineBridge, ENGINE_BRIDGE_INTERFACE_VERSION)
uint32_t NET_ServerCallback( NetCallback_t *pCallback )
{
V_printf("hi %u\n", pCallback->m_eType);
if (pCallback->m_eType == NET_SERVER_READY_TO_USE)
{
V_printf("//--- LAUNCHED SERVER AT ---\n");
V_printf("// %llu\n", SteamGameServer()->GetSteamID().ConvertToUint64());
return 0;
}
if (pCallback->m_eType == NET_TRYING_TO_CONNECT)
{
V_printf("user %llu is trying to connect\n", pCallback->m_ullUserID);
return 1;
}
if (pCallback->m_eType == NET_CONNECTED)
{
V_printf("user %llu has connected, hi!\n", pCallback->m_ullUserID);
CBaseEntity *pEntity;
pEntity = EntitySystem()->CreateByClassname("player");
pEntity->Spawn();
return 1;
}
return 0;
}
void CFunnyGameBridge::Init() void CFunnyGameBridge::Init()
{ {
g_pClientBridge = g_pEngineConstants->LaunchLocalBridge(0); if (g_pEngineConstants->m_bIsDedicated == false)
g_pClientBridge = g_pEngineConstants->LaunchLocalBridge(0);
g_pPublicConnection = NULL;
g_pCurrentConnection = g_pClientBridge;
#ifdef STEAM
if (g_pEngineConstants->m_bIsSteam)
{
SteamErrMsg err = { 0 };
if (SteamGameServer_InitEx(INADDR_ANY, FUNNY_SECURE_PORT, FUNNY_QUERY_PORT, eServerModeAuthentication, "0.0.0.0", &err));
{
V_printf("SteamGameServer_InitEx: %s", err);
}
SteamNetworkingUtils()->InitRelayNetworkAccess();
}
if (g_pEngineConstants->m_bIsDedicated && g_pEngineConstants->m_bIsSteam)
{
SteamGameServer()->SetModDir("funnygame");
SteamGameServer()->SetProduct("funnygame");
SteamGameServer()->SetGameDescription("not that funny but ok");
SteamGameServer()->LogOnAnonymous();
SteamNetworkingUtils()->InitRelayNetworkAccess();
SteamGameServer()->SetDedicatedServer(true);
SteamGameServer()->SetMaxPlayerCount(128);
SteamGameServer()->SetAdvertiseServerActive(true);
}
if (g_pEngineConstants->m_bIsSteam)
{
}
#endif
m_fNetUpdateTimer = 0;
} }
void CFunnyGameBridge::Tick( float fDelta ) void CFunnyGameBridge::Tick( float fDelta )
@@ -42,34 +107,74 @@ void CFunnyGameBridge::Tick( float fDelta )
} }
void NET_ProcessPacket( INetworkBase *pBase )
{
NetPacket_t packet = pBase->PeekPacket();
// discard it
if (packet.uSize < sizeof (EMessageType))
{
pBase->RecievePacket();
return;
}
PlayerPacket_t *pPacket = (PlayerPacket_t*)packet.pData;
CBaseEntity *pEntity;
switch (pPacket->m_eType)
{
case MESSAGE_PLAYER_JOINED:
// online packets don't generate these
if (g_pEngineConstants->m_bIsDedicated)
break;
pBase->RecievePacket();
V_printf("Hi %s\n",pPacket->m_playerJoined.m_szPlayerName);
pEntity = EntitySystem()->CreateByClassname("player");
pEntity->Spawn();
break;
default:
break;
}
pBase->RecievePacket();
}
void CFunnyGameBridge::Frame( float fDelta ) void CFunnyGameBridge::Frame( float fDelta )
{ {
g_pEngineVars->m_fTime += fDelta; g_pEngineVars->m_fTime += fDelta;
g_pEngineVars->m_fDeltaTime = fDelta; g_pEngineVars->m_fDeltaTime = fDelta;
g_pClientBridge->NetThink(); #ifdef STEAM
while (g_pClientBridge->BHasUpdates()) if (g_pEngineConstants->m_bIsSteam && g_pEngineConstants->m_bIsDedicated)
{ {
NetPacket_t packet = g_pClientBridge->PeekPacket(); SteamGameServer_RunCallbacks();
// discard it if (m_bIsConnectedToSteamRelay == 0 && SteamNetworkingUtils()->GetRelayNetworkStatus(NULL) == k_ESteamNetworkingAvailability_Current)
if (packet.uSize < sizeof (EMessageType))
continue;
PlayerPacket_t *pPacket = (PlayerPacket_t*)packet.pData;
CBaseEntity *pEntity;
switch (pPacket->m_eType)
{ {
case MESSAGE_PLAYER_JOINED: m_bIsConnectedToSteamRelay = 1;
g_pClientBridge->RecievePacket(); g_pPublicConnection = g_pEngineConstants->LaunchServer( FUNNY_SECURE_PORT );
V_printf("Hi %s\n",pPacket->m_playerJoined.m_szPlayerName); g_pPublicConnection->SetCallback(NET_ServerCallback);
pEntity = EntitySystem()->CreateByClassname("player"); g_pCurrentConnection = g_pPublicConnection;
pEntity->Spawn(); return;
break; }
default: }
continue; #endif
if (g_pCurrentConnection)
{
g_pCurrentConnection->NetThink();
while (g_pCurrentConnection->BHasUpdates())
NET_ProcessPacket(g_pCurrentConnection);
}
float fTickRate = 1.0/60.0;
m_fNetUpdateTimer += fDelta;
while (m_fNetUpdateTimer >= fTickRate)
{
m_fNetUpdateTimer-=fTickRate;
EntitySystem()->Think();
if (g_pCurrentConnection)
{
EntitySystem()->NetThink(g_pCurrentConnection);
} }
} }
EntitySystem()->Think();
} }

View File

@@ -10,8 +10,10 @@ void CMOBAPlayer::Spawn()
void CMOBAPlayer::Think( float fDelta ) void CMOBAPlayer::Think( float fDelta )
{ {
m_fTimer = g_pEngineVars->m_fTime; m_fTimer += 1.0/60.0;
SetAbsOrigin({m_fTimer,0,0}); SetAbsOrigin({m_fTimer, 0, 0});
SetAbsAngles(glm_rad(90), m_fTimer, 0);
SetScale(1);
}; };
LINK_ENTITY_TO_CLASS(player, CMOBAPlayer) LINK_ENTITY_TO_CLASS(player, CMOBAPlayer)

View File

@@ -22,5 +22,7 @@ extern IGameWindow *g_pMainWindow;
extern EngineConsts_t *g_pEngineConstants; extern EngineConsts_t *g_pEngineConstants;
extern INetworkBase *g_pServerBridge; extern INetworkBase *g_pServerBridge;
extern INetworkBase *g_pClientBridge; extern INetworkBase *g_pClientBridge;
extern INetworkBase *g_pPublicConnection;
extern INetworkBase *g_pCurrentConnection;
#endif #endif

View File

@@ -14,4 +14,8 @@ public:
}; };
extern CEngineVars *g_pEngineVars; extern CEngineVars *g_pEngineVars;
#define FUNNY_SECURE_PORT 27015
#define FUNNY_QUERY_PORT 27016
#endif #endif

View File

@@ -3,18 +3,45 @@
#define NETWORK_BASE_H #define NETWORK_BASE_H
#include "tier1/interface.h" #include "tier1/interface.h"
enum EPacketArrival
{
PACKET_MAY_ARRIVE,
PACKET_MUST_ARRIVE
};
struct NetPacket_t struct NetPacket_t
{ {
void *pData; void *pData;
uint32_t uSize; uint32_t uSize;
uint64_t m_uOwner;
EPacketArrival m_eArrival;
}; };
enum ENetCallbackType
{
NET_NONE = 0,
NET_TRYING_TO_CONNECT,
NET_CONNECTED,
NET_DISCONNECTED,
NET_SERVER_READY_TO_USE,
};
struct NetCallback_t
{
ENetCallbackType m_eType;
uint64_t m_ullUserID;
};
typedef uint32_t (*NetCallbackFn)( NetCallback_t *pUser );
abstract_class INetworkBase abstract_class INetworkBase
{ {
public: public:
virtual ~INetworkBase() = default; virtual ~INetworkBase() = default;
virtual void NetThink() = 0; virtual void NetThink() = 0;
virtual void SetCallback( NetCallbackFn fnCallback ) = 0;
virtual uint32_t BHasUpdates() = 0; virtual uint32_t BHasUpdates() = 0;
virtual NetPacket_t RecievePacket() = 0; virtual NetPacket_t RecievePacket() = 0;
@@ -22,9 +49,13 @@ public:
virtual void SendPacket( NetPacket_t stPacket ) = 0; virtual void SendPacket( NetPacket_t stPacket ) = 0;
virtual bool BIsActive() = 0;
virtual uint64_t GetSteamID() = 0; virtual uint64_t GetSteamID() = 0;
virtual const char *GetIP() = 0; virtual const char *GetIP() = 0;
virtual uint16_t GetPort() = 0; virtual uint16_t GetPort() = 0;
}; };
#define GAME_PORT
#endif #endif