From 468d765aa101419abdfe04ff0477ce11047e0af8 Mon Sep 17 00:00:00 2001 From: kotofyt Date: Sun, 1 Mar 2026 23:06:28 +0200 Subject: [PATCH] steam relay networking --- engine/engine.cpp | 20 ++- engine/localnetwork.cpp | 42 +++--- engine/steamnetwork.cpp | 240 ++++++++++++++++++++++++++++++++- engine/steamserver.cpp | 0 game/client/baseentity.cpp | 4 +- game/client/build.cpp | 9 +- game/client/game.cpp | 172 ++++++++++++++++------- game/server/baseentity.cpp | 11 +- game/server/build.cpp | 9 +- game/server/entitysystem.cpp | 33 +++-- game/server/entitysystem.h | 3 + game/server/game.cpp | 143 +++++++++++++++++--- game/server/milmoba/player.cpp | 6 +- game/shared/engine.h | 2 + game/shared/game.h | 4 + public/networkbase.h | 31 +++++ 16 files changed, 628 insertions(+), 101 deletions(-) create mode 100644 engine/steamserver.cpp diff --git a/engine/engine.cpp b/engine/engine.cpp index 09e00c6..8240423 100644 --- a/engine/engine.cpp +++ b/engine/engine.cpp @@ -12,6 +12,7 @@ #ifdef STEAM #include "steam/steam_api.h" +#include "steam/steam_gameserver.h" #endif IRenderContext *g_pRenderContext; @@ -21,17 +22,30 @@ IGameWindowManager *g_pWindowManager; CServerGameDLL *g_pServerGame; 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 ) { CommandLine()->CreateCommandLine(argc, argv); EngineConsts_t stConstants = {}; #ifdef STEAM + if(SteamAPI_RestartAppIfNecessary(480)) + { + V_printf("Mshallah we are doing reboot\n"); + Plat_Exit(0); + } + stConstants.m_bIsSteam = true; if (!SteamAPI_Init()) Plat_FatalErrorFunc("SteamAPI_Init failed lol\n"); - stConstants.LaunchServer = LaunchLocalBridge; + stConstants.LaunchServer = LaunchServerAtSteamRelay; stConstants.ConnectSteamServer = ConnectBySteamID; + + //SteamNetworkingUtils()->SetDebugOutputFunction(k_ESteamNetworkingSocketsDebugOutputType_Debug, SteamAPIDebug); #endif stConstants.m_bIsDedicated = CommandLine()->CheckParam("-dedicated"); stConstants.LaunchLocalBridge = LaunchLocalBridge; @@ -75,9 +89,13 @@ extern "C" void FunnyMain( int argc, char **argv ) double fPrevious = Plat_GetTime(); for (;;) { +#ifdef STEAM + SteamAPI_RunCallbacks(); +#endif double fCurrent = Plat_GetTime(); double fDelta = fCurrent-fPrevious; fPrevious = fCurrent; + g_pServerGame->m_pBridge->Frame(fDelta); if (!stConstants.m_bIsDedicated) diff --git a/engine/localnetwork.cpp b/engine/localnetwork.cpp index 11ba4ed..9f4c7f4 100644 --- a/engine/localnetwork.cpp +++ b/engine/localnetwork.cpp @@ -12,13 +12,16 @@ public: virtual ~CLocalNetworkServer() override; virtual void NetThink() override; + virtual void SetCallback( NetCallbackFn fnCallback ) override; virtual uint32_t BHasUpdates() override; virtual NetPacket_t RecievePacket() override; - virtual NetPacket_t PeekPacket() override; + virtual NetPacket_t PeekPacket() 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; @@ -27,6 +30,7 @@ public: CUtlVector m_packets; CUtlVector m_clientPackets; CUtlVector m_freedPackets; + NetCallbackFn m_fnCallback; const uint16_t m_uPort; }; @@ -41,16 +45,18 @@ CLocalNetworkServer::~CLocalNetworkServer() } +void CLocalNetworkServer::SetCallback( NetCallbackFn fnCallback ) +{ + m_fnCallback = fnCallback; +} void CLocalNetworkServer::NetThink() { - m_lock.Lock(); for ( auto p: m_freedPackets) { V_free(p); } m_freedPackets = {}; - m_lock.Unlock(); } @@ -61,23 +67,19 @@ uint32_t CLocalNetworkServer::BHasUpdates() NetPacket_t CLocalNetworkServer::RecievePacket() { - m_lock.Lock(); if (!BHasUpdates()) return {}; NetPacket_t p = m_clientPackets[0]; m_clientPackets.RemoveHead(1); m_freedPackets.AppendTail(p.pData); - m_lock.Unlock(); return p; } NetPacket_t CLocalNetworkServer::PeekPacket() { - m_lock.Lock(); if (!BHasUpdates()) return {}; NetPacket_t p = m_clientPackets[0]; - m_lock.Unlock(); return p; } @@ -86,14 +88,17 @@ void CLocalNetworkServer::SendPacket( NetPacket_t stPacket ) { NetPacket_t stSavedPacked; stSavedPacked.uSize = stPacket.uSize; + stSavedPacked.m_uOwner = 0; stSavedPacked.pData = V_malloc(stPacket.uSize); V_memcpy(stSavedPacked.pData, stPacket.pData, stPacket.uSize); - m_lock.Lock(); m_packets.AppendTail(stSavedPacked); - m_lock.Unlock(); } +bool CLocalNetworkServer::BIsActive() +{ + return true; +} uint64_t CLocalNetworkServer::GetSteamID() { @@ -117,12 +122,15 @@ public: virtual ~CLocalNetworkClient() override; virtual void NetThink() override; + virtual void SetCallback( NetCallbackFn fnCallback ) override; virtual uint32_t BHasUpdates() override; virtual NetPacket_t RecievePacket() override; virtual NetPacket_t PeekPacket() override; virtual void SendPacket( NetPacket_t stPacket ) override; + + virtual bool BIsActive() override; virtual uint64_t GetSteamID() override; virtual const char *GetIP() override; @@ -131,6 +139,11 @@ public: CLocalNetworkServer *m_pServer; }; +bool CLocalNetworkClient::BIsActive() +{ + return true; +} + CLocalNetworkClient::CLocalNetworkClient( uint16_t uPort ) { m_pServer = s_pLocalServers[uPort]; @@ -154,23 +167,19 @@ uint32_t CLocalNetworkClient::BHasUpdates() NetPacket_t CLocalNetworkClient::RecievePacket() { - m_pServer->m_lock.Lock(); if (!BHasUpdates()) return {}; NetPacket_t p = m_pServer->m_packets[0]; m_pServer->m_packets.RemoveHead(1); m_pServer->m_freedPackets.AppendTail(p.pData); - m_pServer->m_lock.Unlock(); return p; } NetPacket_t CLocalNetworkClient::PeekPacket() { - m_pServer->m_lock.Lock(); if (!BHasUpdates()) return {}; NetPacket_t p = m_pServer->m_packets[0]; - m_pServer->m_lock.Unlock(); return p; } @@ -179,12 +188,15 @@ void CLocalNetworkClient::SendPacket( NetPacket_t stPacket ) { NetPacket_t stSavedPacked; stSavedPacked.uSize = stPacket.uSize; + stSavedPacked.m_uOwner = 0; stSavedPacked.pData = V_malloc(stPacket.uSize); V_memcpy(stSavedPacked.pData, stPacket.pData, stPacket.uSize); - m_pServer->m_lock.Lock(); m_pServer->m_clientPackets.AppendTail(stSavedPacked); - m_pServer->m_lock.Unlock(); +} + +void CLocalNetworkClient::SetCallback( NetCallbackFn fnCallback ) +{ } diff --git a/engine/steamnetwork.cpp b/engine/steamnetwork.cpp index 93df8f0..2515ed1 100644 --- a/engine/steamnetwork.cpp +++ b/engine/steamnetwork.cpp @@ -1,5 +1,11 @@ #include "inetworkserver.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" class CSteamNetworkServer: public INetworkBase @@ -9,22 +15,37 @@ public: virtual ~CSteamNetworkServer() 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; HSteamListenSocket m_hSocket; + NetCallbackFn m_fnCallback; + HSteamNetPollGroup m_hPollGroup; + uint64_t m_uSteamId; + + CUtlVector m_hConnections; + + STEAM_GAMESERVER_CALLBACK(CSteamNetworkServer, ClientConnected, SteamNetConnectionStatusChangedCallback_t); + STEAM_GAMESERVER_CALLBACK(CSteamNetworkServer, SteamNetAuthenticated, SteamNetAuthenticationStatus_t); }; 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() @@ -37,8 +58,17 @@ void CSteamNetworkServer::NetThink() { } +void CSteamNetworkServer::SetCallback( NetCallbackFn fnCallback ) +{ + m_fnCallback = fnCallback; +} + uint32_t CSteamNetworkServer::BHasUpdates() +{ + return 0; +} +NetPacket_t CSteamNetworkServer::PeekPacket() { } @@ -51,6 +81,21 @@ NetPacket_t CSteamNetworkServer::RecievePacket() 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; } +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 m_incomingPackets = {}; + CUtlVector m_incomingSteamPackets = {}; + CUtlVector 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 ) { @@ -78,5 +306,11 @@ INetworkBase *LaunchServerAtSteamRelay( 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; } diff --git a/engine/steamserver.cpp b/engine/steamserver.cpp new file mode 100644 index 0000000..e69de29 diff --git a/game/client/baseentity.cpp b/game/client/baseentity.cpp index 885b525..73a5982 100644 --- a/game/client/baseentity.cpp +++ b/game/client/baseentity.cpp @@ -128,7 +128,9 @@ BEGIN_DATADESC_NOBASE(C_BaseEntity) END_DATADESC() IMPLEMENT_RECV_DT_NOBASE(C_BaseEntity) - NetPropFloat3(m_vPosition) + NetPropFloat3(m_vPosition), + NetPropQuaternion(m_vRotation), + NetPropFloat3(m_vScale) END_RECV_DT() IMPLEMENT_EMPTY_SEND_DT_NOBASE(C_BaseEntity) diff --git a/game/client/build.cpp b/game/client/build.cpp index edec58d..4a836ac 100644 --- a/game/client/build.cpp +++ b/game/client/build.cpp @@ -33,9 +33,12 @@ DECLARE_BUILD_STAGE(Client) "../shared", "../../public", FUNNYSTDLIB"public", - EXTERNAL"cglm/include" + EXTERNAL"cglm/include", + EXTERNAL"steamworks/public", }; compileProject.bFPIC = true; + if ( GET_PROJECT_VALUE(config, "steam") == "true" ) + compileProject.macros.AppendTail({"STEAM", "TRUE"}); ldProject = ccompiler->Compile(&compileProject); if ( GET_PROJECT_VALUE(config, "static") == "true" ) @@ -44,6 +47,10 @@ DECLARE_BUILD_STAGE(Client) } 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.libraryObjects = { GET_PROJECT_LIBRARY(tier0, "tier0"), diff --git a/game/client/game.cpp b/game/client/game.cpp index 788a344..ab1b3f3 100644 --- a/game/client/game.cpp +++ b/game/client/game.cpp @@ -1,4 +1,5 @@ #include "tier2/ifilesystem.h" +#include "tier0/commandline.h" #include "materialsystem/imaterialsystem.h" #include "enginebridge.h" #include "worldrender.h" @@ -9,6 +10,10 @@ #include "cglm/cglm.h" #include "inetworkclient.h" #include "netprotocol.h" +#ifdef STEAM +#include "steam/isteamgameserver.h" +#include "steam/steam_gameserver.h" +#endif IFileSystem *filesystem; IRenderContext *g_pRenderContext; @@ -16,7 +21,9 @@ IGameWindow *g_pMainWindow; static CEngineVars s_vars; CEngineVars *g_pEngineVars = &s_vars; EngineConsts_t *g_pEngineConstants; + INetworkBase *g_pServerBridge; +INetworkBase *g_pServerConnection; class CFunnyGameBridge: public IEngineBridge { @@ -25,6 +32,11 @@ class CFunnyGameBridge: public IEngineBridge virtual void Frame( float fDelta ) override; virtual void Shutdown() override; virtual void ConnectInterface( const char *psz, void *pInterface ) override; + void TryToConnectToServer(); + + bool m_bIsConnectedToSteamRelay; + bool m_bIsConnectedToServer; + }; IEngineBridge *EngineBridge() @@ -35,16 +47,29 @@ IEngineBridge *EngineBridge() EXPOSE_INTERFACE_FN(EngineBridge, IEngineBridge, ENGINE_BRIDGE_INTERFACE_VERSION) + void CFunnyGameBridge::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 = { - MESSAGE_PLAYER_JOINED, - "LocalPlayer" - }; - g_pServerBridge->SendPacket({&join, sizeof(join)}); + m_bIsConnectedToServer = false; + g_pServerBridge = g_pEngineConstants->ConnectLocalBridge(0); + if (g_pServerBridge) + { + PlayerJoined_t join = { + MESSAGE_PLAYER_JOINED, + "LocalPlayer" + }; + g_pServerBridge->SendPacket({&join, sizeof(join)}); + } } void CFunnyGameBridge::Tick( float fDelta ) @@ -70,55 +95,106 @@ searchIndex: 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 ) { g_pEngineVars->m_fTime += fDelta; g_pEngineVars->m_fDeltaTime = fDelta; - g_pServerBridge->NetThink(); - 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); + TryToConnectToServer(); - pcCurrentData += sizeof(EntityDataSyncValue_t); - if (pValueData) - V_memcpy(pValueData, pcCurrentData, uVariableSize); - pcCurrentData += (uVariableSize+7) & ~7; + INetworkBase *pCurrentServer = g_pServerBridge; + pCurrentServer = g_pServerBridge; + if (m_bIsConnectedToServer) + 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; } } diff --git a/game/server/baseentity.cpp b/game/server/baseentity.cpp index 0c9994e..7ca689f 100644 --- a/game/server/baseentity.cpp +++ b/game/server/baseentity.cpp @@ -25,6 +25,12 @@ void CBaseEntity::Spawn() 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 ) @@ -42,7 +48,6 @@ void CBaseEntity::SetScale( float fScale ) QAngle CBaseEntity::GetAbsQAngles( void ) { - } Quat CBaseEntity::GetAbsAngles( void ) { @@ -119,7 +124,9 @@ BEGIN_DATADESC_NOBASE(CBaseEntity) END_DATADESC() IMPLEMENT_SEND_DT_NOBASE(CBaseEntity) - NetPropFloat3(m_vPosition) + NetPropFloat3(m_vPosition), + NetPropQuaternion(m_vRotation), + NetPropFloat3(m_vScale), END_SEND_DT() IMPLEMENT_EMPTY_RECV_DT_NOBASE(CBaseEntity) diff --git a/game/server/build.cpp b/game/server/build.cpp index fa6152e..78594b2 100644 --- a/game/server/build.cpp +++ b/game/server/build.cpp @@ -27,9 +27,12 @@ DECLARE_BUILD_STAGE(Server) ".", "../shared", FUNNYSTDLIB"public", - EXTERNAL"cglm/include" + EXTERNAL"cglm/include", + EXTERNAL"steamworks/public", }; compileProject.bFPIC = true; + if ( GET_PROJECT_VALUE(config, "steam") == "true" ) + compileProject.macros.AppendTail({"STEAM", "TRUE"}); ldProject = ccompiler->Compile(&compileProject); if ( GET_PROJECT_VALUE(config, "static") == "true" ) { @@ -37,6 +40,10 @@ DECLARE_BUILD_STAGE(Server) } 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.libraryObjects = { GET_PROJECT_LIBRARY(tier0, "tier0"), diff --git a/game/server/entitysystem.cpp b/game/server/entitysystem.cpp index 3859337..ded7242 100644 --- a/game/server/entitysystem.cpp +++ b/game/server/entitysystem.cpp @@ -92,7 +92,8 @@ CBaseEntity *CEntitySystem::CreateByClassname( const char *szName ) iSelectedSlot, }; 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; } IEntityFactory *CEntitySystem::GetFactoryByClassname( const char *szName ) @@ -113,6 +114,25 @@ void CEntitySystem::Think() CBaseEntity *pEntity; 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 x; uint32_t uSize; @@ -125,19 +145,15 @@ void CEntitySystem::Think() EntityDataSyncValue_t *pValue; }; - 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); - + pNetMap = pEntity->GetSendMap(); uSize = sizeof(EntityDataSyncValue_t); x = 0; @@ -177,9 +193,10 @@ void CEntitySystem::Think() } pNetMap = pNetMap->m_pBase; } - g_pClientBridge->SendPacket({pData, uSize}); + if (g_pCurrentConnection) + g_pCurrentConnection->SendPacket({pData, uSize}); V_free(pData); - + } } diff --git a/game/server/entitysystem.h b/game/server/entitysystem.h index 66e211f..ee864df 100644 --- a/game/server/entitysystem.h +++ b/game/server/entitysystem.h @@ -7,6 +7,8 @@ #ifndef ENTITIES_H #define ENTITIES_H +#include "networkbase.h" + class IEntityFactory; class CBaseEntity; @@ -23,6 +25,7 @@ public: virtual IEntityFactory *GetFactoryByClassname( const char *szName ); virtual void Think(); + virtual void NetThink( INetworkBase *pBase ); virtual CBaseEntity **GetEntities(); private: CBaseEntity *m_pEntities[MAX_EDICTS]; diff --git a/game/server/game.cpp b/game/server/game.cpp index 0690086..9e14cb4 100644 --- a/game/server/game.cpp +++ b/game/server/game.cpp @@ -5,6 +5,11 @@ #include "game.h" #include "inetworkserver.h" #include "netprotocol.h" +#ifdef STEAM +#include "steam/isteamgameserver.h" +#include "steam/steam_gameserver.h" +#endif + IFileSystem *filesystem; IRenderContext *g_pRenderContext; @@ -13,6 +18,8 @@ static CEngineVars s_vars; CEngineVars *g_pEngineVars = &s_vars; EngineConsts_t *g_pEngineConstants; INetworkBase *g_pClientBridge; +INetworkBase *g_pPublicConnection; +INetworkBase *g_pCurrentConnection; class CFunnyGameBridge: public IEngineBridge { @@ -21,6 +28,9 @@ class CFunnyGameBridge: public IEngineBridge virtual void Frame( float fDelta ) override; virtual void Shutdown() 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) +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() { - 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 ) @@ -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 ) { g_pEngineVars->m_fTime += fDelta; g_pEngineVars->m_fDeltaTime = fDelta; - g_pClientBridge->NetThink(); - while (g_pClientBridge->BHasUpdates()) +#ifdef STEAM + if (g_pEngineConstants->m_bIsSteam && g_pEngineConstants->m_bIsDedicated) { - NetPacket_t packet = g_pClientBridge->PeekPacket(); - // discard it - if (packet.uSize < sizeof (EMessageType)) - continue; - PlayerPacket_t *pPacket = (PlayerPacket_t*)packet.pData; - CBaseEntity *pEntity; - switch (pPacket->m_eType) + SteamGameServer_RunCallbacks(); + if (m_bIsConnectedToSteamRelay == 0 && SteamNetworkingUtils()->GetRelayNetworkStatus(NULL) == k_ESteamNetworkingAvailability_Current) { - case MESSAGE_PLAYER_JOINED: - g_pClientBridge->RecievePacket(); - V_printf("Hi %s\n",pPacket->m_playerJoined.m_szPlayerName); - pEntity = EntitySystem()->CreateByClassname("player"); - pEntity->Spawn(); - break; - default: - continue; + m_bIsConnectedToSteamRelay = 1; + g_pPublicConnection = g_pEngineConstants->LaunchServer( FUNNY_SECURE_PORT ); + g_pPublicConnection->SetCallback(NET_ServerCallback); + g_pCurrentConnection = g_pPublicConnection; + return; + } + } +#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(); } diff --git a/game/server/milmoba/player.cpp b/game/server/milmoba/player.cpp index 68ecf9a..dda4512 100644 --- a/game/server/milmoba/player.cpp +++ b/game/server/milmoba/player.cpp @@ -10,8 +10,10 @@ void CMOBAPlayer::Spawn() void CMOBAPlayer::Think( float fDelta ) { - m_fTimer = g_pEngineVars->m_fTime; - SetAbsOrigin({m_fTimer,0,0}); + m_fTimer += 1.0/60.0; + SetAbsOrigin({m_fTimer, 0, 0}); + SetAbsAngles(glm_rad(90), m_fTimer, 0); + SetScale(1); }; LINK_ENTITY_TO_CLASS(player, CMOBAPlayer) diff --git a/game/shared/engine.h b/game/shared/engine.h index 043a11d..11b9998 100644 --- a/game/shared/engine.h +++ b/game/shared/engine.h @@ -22,5 +22,7 @@ extern IGameWindow *g_pMainWindow; extern EngineConsts_t *g_pEngineConstants; extern INetworkBase *g_pServerBridge; extern INetworkBase *g_pClientBridge; +extern INetworkBase *g_pPublicConnection; +extern INetworkBase *g_pCurrentConnection; #endif diff --git a/game/shared/game.h b/game/shared/game.h index 19f2cad..08db964 100644 --- a/game/shared/game.h +++ b/game/shared/game.h @@ -14,4 +14,8 @@ public: }; extern CEngineVars *g_pEngineVars; + +#define FUNNY_SECURE_PORT 27015 +#define FUNNY_QUERY_PORT 27016 + #endif diff --git a/public/networkbase.h b/public/networkbase.h index 04299f1..e4609d8 100644 --- a/public/networkbase.h +++ b/public/networkbase.h @@ -3,18 +3,45 @@ #define NETWORK_BASE_H #include "tier1/interface.h" +enum EPacketArrival +{ + PACKET_MAY_ARRIVE, + PACKET_MUST_ARRIVE +}; + struct NetPacket_t { void *pData; 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 { public: virtual ~INetworkBase() = default; virtual void NetThink() = 0; + virtual void SetCallback( NetCallbackFn fnCallback ) = 0; virtual uint32_t BHasUpdates() = 0; virtual NetPacket_t RecievePacket() = 0; @@ -22,9 +49,13 @@ public: virtual void SendPacket( NetPacket_t stPacket ) = 0; + virtual bool BIsActive() = 0; + virtual uint64_t GetSteamID() = 0; virtual const char *GetIP() = 0; virtual uint16_t GetPort() = 0; }; +#define GAME_PORT + #endif