mirror of
https://github.com/rlabrecque/SteamworksSDK.git
synced 2026-10-10 09:33:04 +08:00
v1.05
This commit is contained in:
+34
-2
@@ -1,5 +1,3 @@
|
||||
This is the Steamworks SDK v1.03
|
||||
|
||||
================================================================
|
||||
|
||||
Copyright © 1996-2009, Valve Corporation, All rights reserved.
|
||||
@@ -13,6 +11,40 @@ website at: http://partner.steamgames.com
|
||||
|
||||
Revision History:
|
||||
|
||||
----------------------------------------------------------------
|
||||
v1.05 11th June 2009
|
||||
----------------------------------------------------------------
|
||||
|
||||
Matchmaking
|
||||
* Added the SteamID of the gameserver to the gameserveritem_t structure (returned only by newer game servers)
|
||||
* Added ISteamUserStats::GetNumberOfCurrentPlayers(), asyncronously returns the number users currently running this game
|
||||
* Added k_ELobbyComparisonNotEqual comparision functions for filters
|
||||
* Added option to use comparison functions for string filters
|
||||
* Added ISteamMatchmaking::AddRequestLobbyListFilterSlotsAvailable( int nSlotsAvailable ) filter function, so you can find a lobby for a group of users to join
|
||||
* Extended ISteamMatchmaking::CreateLobby() to take the max number of users in the lobby
|
||||
* Added ISteamMatchmaking::GetLobbyDataCount(), ISteamMatchmaking::GetLobbyDataByIndex() so you can iterate all the data set on a lobby
|
||||
* Added ISteamMatchmaking::DeleteLobbyData() so you can clear a key from a lobby
|
||||
* Added ISteamMatchmaking::SetLobbyOwner() so that ownership of a lobby can be transferred
|
||||
* Added ISteamMatchmaking::SetLobbyJoinable()
|
||||
* Added ISteamGameServer::SetGameData(), so game server can set more information that can be filtered for in the server pinging API
|
||||
|
||||
Networking
|
||||
* Added a set of connectionless networking functions for easy use for making peer-to-peer (NAT traversal) connections. Includes supports for windowed reliable sendsand fragementation/re-assembly of large packets. See ISteamNetworking.h for more details.
|
||||
|
||||
Leaderboards
|
||||
* Added enum ELeaderboardUploadScoreMethod and changed ISteamUserStats::UploadLeaderboardScore() to take this - lets you force a score to be changed even if it's worse than the prior score
|
||||
|
||||
Callbacks
|
||||
* Added CCallbackManual<> class to steam_api.h, a version of CCallback<> that doesn't register itself automatically in it's the constructor
|
||||
|
||||
Downloadable Content
|
||||
* Added ISteamUser::UserHasLicenseForApp() and ISteamGameServer::UserHasLicenseForApp() to enable checking if a user owns DLC in multiplayer. See the DLC documentation for more info.
|
||||
|
||||
Game Overlay
|
||||
* ISteamFriends::ActivateGameOverlay() now accepts "Stats" and "Achievements"
|
||||
|
||||
|
||||
|
||||
----------------------------------------------------------------
|
||||
v1.04 9th Mar 2009
|
||||
----------------------------------------------------------------
|
||||
|
||||
@@ -101,26 +101,9 @@ CGameEngine::CGameEngine( HINSTANCE hInstance, int nShowCommand, int32 nWindowWi
|
||||
m_dwQuadBufferBatchPos = 0;
|
||||
m_hTextureWhite = NULL;
|
||||
m_bDeviceLost = false;
|
||||
m_bFirstFrame = true;
|
||||
m_flMaxFPS = 120.0f;
|
||||
m_hLastTexture = NULL;
|
||||
m_ulPreviousGameTickCount = 0;
|
||||
m_ulGameTickCount = 0;
|
||||
|
||||
// restrict this main game thread to the first processor, so queryperformance counter won't jump on crappy AMD cpus
|
||||
DWORD dwThreadAffinityMask = 0x01;
|
||||
::SetThreadAffinityMask( ::GetCurrentThread(), dwThreadAffinityMask );
|
||||
|
||||
LARGE_INTEGER l;
|
||||
if ( QueryPerformanceFrequency( &l ) )
|
||||
{
|
||||
m_ulPerfCounterToMillisecondsDivisor = l.QuadPart/1000;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_ulPerfCounterToMillisecondsDivisor = 0;
|
||||
}
|
||||
|
||||
m_dwBackgroundColor = D3DCOLOR_ARGB(0, 255, 255, 255 );
|
||||
|
||||
if ( !BCreateGameWindow( nShowCommand ) || !m_hWnd )
|
||||
@@ -518,32 +501,6 @@ void CGameEngine::SetBackgroundColor( short a, short r, short g, short b )
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CGameEngine::StartFrame()
|
||||
{
|
||||
// Track current game time
|
||||
// bugbug jmccaskey - use a more reliable timer that won't wrap and has better precision!
|
||||
if ( m_bFirstFrame )
|
||||
{
|
||||
LARGE_INTEGER l;
|
||||
if ( !QueryPerformanceCounter( &l ) )
|
||||
OutputDebugString( "QueryPerformanceCounter failed\n" );
|
||||
|
||||
m_ulLastQueryPerformanceCounterValue = l.QuadPart;
|
||||
|
||||
m_ulPreviousGameTickCount = 0;
|
||||
m_ulGameTickCount = 0;
|
||||
m_bFirstFrame = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_ulPreviousGameTickCount = m_ulGameTickCount;
|
||||
|
||||
LARGE_INTEGER l;
|
||||
if ( !QueryPerformanceCounter( &l ) )
|
||||
OutputDebugString( "QueryPerformanceCounter failed\n" );
|
||||
|
||||
m_ulGameTickCount += (l.QuadPart - m_ulLastQueryPerformanceCounterValue)/m_ulPerfCounterToMillisecondsDivisor;
|
||||
m_ulLastQueryPerformanceCounterValue = l.QuadPart;
|
||||
}
|
||||
|
||||
// Before doing anything else pump messages
|
||||
MessagePump();
|
||||
|
||||
@@ -664,30 +621,6 @@ void CGameEngine::EndFrame()
|
||||
OutputDebugString( "Present() call failed\n" );
|
||||
return;
|
||||
}
|
||||
|
||||
// Frame rate limiting
|
||||
float flDesiredFrameMilliseconds = 1000.0f/m_flMaxFPS;
|
||||
while( 1 )
|
||||
{
|
||||
uint64 ulCurrentTickCount = m_ulGameTickCount;
|
||||
LARGE_INTEGER l;
|
||||
if ( !QueryPerformanceCounter( &l ) )
|
||||
OutputDebugString( "QueryPerformanceCounter failed\n" );
|
||||
|
||||
ulCurrentTickCount += (l.QuadPart-m_ulLastQueryPerformanceCounterValue)/m_ulPerfCounterToMillisecondsDivisor;
|
||||
|
||||
float flMillisecondsElapsed = (float)(ulCurrentTickCount - m_ulGameTickCount);
|
||||
if ( flMillisecondsElapsed < flDesiredFrameMilliseconds )
|
||||
{
|
||||
// If enough time is left sleep, otherwise just keep spinning so we don't go over the limit...
|
||||
if ( flDesiredFrameMilliseconds - flMillisecondsElapsed > 2.0f )
|
||||
Sleep( 2 );
|
||||
else
|
||||
continue;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
@@ -166,6 +166,8 @@ public:
|
||||
// way to handle that.
|
||||
uint64 GetGameTicksFrameDelta() { return m_ulGameTickCount - m_ulPreviousGameTickCount; }
|
||||
|
||||
void SetGameTickCount( uint64 ulGameTickCount ) { m_ulPreviousGameTickCount = m_ulGameTickCount; m_ulGameTickCount = ulGameTickCount; }
|
||||
|
||||
// Get the game engines hwnd
|
||||
HWND GetGameHWND() { return m_hWnd; }
|
||||
|
||||
@@ -302,15 +304,6 @@ private:
|
||||
// Game time at the start of the previous frame
|
||||
uint64 m_ulPreviousGameTickCount;
|
||||
|
||||
// Track whether this is the first frame
|
||||
bool m_bFirstFrame;
|
||||
|
||||
// Value to divide from QueryPerformanceCounter results to get milliseconds
|
||||
uint64 m_ulPerfCounterToMillisecondsDivisor;
|
||||
|
||||
// Last value from QueryPerformanceCounter
|
||||
uint64 m_ulLastQueryPerformanceCounterValue;
|
||||
|
||||
// Maximum FPS to run the engine at
|
||||
float m_flMaxFPS;
|
||||
|
||||
|
||||
@@ -291,7 +291,7 @@ void CLeaderboards::UpdateLeaderboards( CStatsAndAchievements *pStats )
|
||||
// if the user won, update the leaderboard with the time it took. If the user's previous time was faster, this time will be thrown out.
|
||||
if ( m_hQuickestWinLeaderboard && SpaceWarClient()->BLocalPlayerWonLastGame() )
|
||||
{
|
||||
SteamAPICall_t hSteamAPICall = SteamUserStats()->UploadLeaderboardScore( m_hQuickestWinLeaderboard, (int)pStats->GetGameDurationSeconds(), NULL, 0 );
|
||||
SteamAPICall_t hSteamAPICall = SteamUserStats()->UploadLeaderboardScore( m_hQuickestWinLeaderboard, k_ELeaderboardUploadScoreMethodKeepBest, (int)pStats->GetGameDurationSeconds(), NULL, 0 );
|
||||
m_SteamCallResultUploadScore.Set( hSteamAPICall, this, &CLeaderboards::OnUploadScore );
|
||||
}
|
||||
|
||||
@@ -299,7 +299,7 @@ void CLeaderboards::UpdateLeaderboards( CStatsAndAchievements *pStats )
|
||||
// this value will be thrown out
|
||||
if ( m_hFeetTraveledLeaderboard )
|
||||
{
|
||||
SteamUserStats()->UploadLeaderboardScore( m_hFeetTraveledLeaderboard, (int)pStats->GetGameFeetTraveled(), NULL, 0 );
|
||||
SteamUserStats()->UploadLeaderboardScore( m_hFeetTraveledLeaderboard, k_ELeaderboardUploadScoreMethodKeepBest, (int)pStats->GetGameFeetTraveled(), NULL, 0 );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "Lobby.h"
|
||||
#include "SpaceWarClient.h"
|
||||
#include "p2pauth.h"
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@@ -167,6 +169,18 @@ void CLobby::OnLobbyChatUpdate( LobbyChatUpdate_t *pCallback )
|
||||
|
||||
// rebuild the menu
|
||||
m_pMenu->Rebuild( m_steamIDLobby );
|
||||
|
||||
|
||||
int cLobbyMembers = SteamMatchmaking()->GetNumLobbyMembers( m_steamIDLobby );
|
||||
for ( int i = 0; i < cLobbyMembers; i++ )
|
||||
{
|
||||
CSteamID steamIDLobbyMember = SteamMatchmaking()->GetLobbyMemberByIndex( m_steamIDLobby, i ) ;
|
||||
|
||||
// ignore yourself.
|
||||
if ( SteamUser()->GetSteamID() == steamIDLobbyMember )
|
||||
continue;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@ class CSpaceWarClient;
|
||||
class CLobbyBrowserMenu;
|
||||
class CLobbyMenu;
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Displays the other users in a lobby and allows the game to be started
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
@@ -54,6 +54,14 @@ int APIENTRY RealMain(HINSTANCE hInstance,
|
||||
LPSTR lpCmdLine,
|
||||
int nCmdShow)
|
||||
{
|
||||
// Init Steam CEG
|
||||
if ( !Steamworks_InitCEGLibrary() )
|
||||
{
|
||||
OutputDebugString( "Steamworks_InitCEGLibrary() failed\n" );
|
||||
::MessageBox( NULL, "Steam must be running to play this game (InitDrmLibrary() failed).\n", "Fatal Error", MB_OK );
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Initialize SteamAPI, if this fails we bail out since we depend on Steam for lots of stuff.
|
||||
// You don't necessarily have to though if you write your code to check whether all the Steam
|
||||
// interfaces are NULL before using them and provide alternate paths when they are unavailable.
|
||||
@@ -76,8 +84,7 @@ int APIENTRY RealMain(HINSTANCE hInstance,
|
||||
// Generally you should use the default and not call this as users will be most comfortable with
|
||||
// the default position. The API is provided in case the bottom right creates a serious conflict
|
||||
// with important UI in your game.
|
||||
// disabled temporarily until calling issue is resolved
|
||||
// SteamUtils()->SetOverlayNotificationPosition( k_EPositionTopRight );
|
||||
SteamUtils()->SetOverlayNotificationPosition( k_EPositionTopRight );
|
||||
|
||||
// Look for the +connect ipaddress:port parameter in the command line,
|
||||
// Steam will pass this when a user has used the Steam Server browser to find
|
||||
@@ -103,6 +110,8 @@ int APIENTRY RealMain(HINSTANCE hInstance,
|
||||
pchLobbyID = pchCmdLine + ( pchConnectLobby - pchCmdLine ) + strlen( pchConnectLobbyParam ) + 1;
|
||||
}
|
||||
|
||||
// do a DRM self check
|
||||
Steamworks_SelfCheck();
|
||||
|
||||
// Construct a new instance of the game engine
|
||||
// bugbug jmccaskey - make screen resolution dynamic, maybe take it on command line?
|
||||
@@ -147,14 +156,65 @@ int APIENTRY RealMain(HINSTANCE hInstance,
|
||||
}
|
||||
}
|
||||
|
||||
// test a user specific secret before entering main loop
|
||||
Steamworks_TestSecret();
|
||||
|
||||
static const int m_flMaxFPS = 120;
|
||||
|
||||
// restrict this main game thread to the first processor, so queryperformance counter won't jump on crappy AMD cpus
|
||||
DWORD dwThreadAffinityMask = 0x01;
|
||||
::SetThreadAffinityMask( ::GetCurrentThread(), dwThreadAffinityMask );
|
||||
|
||||
uint64 ulPerfCounterToMillisecondsDivisor;
|
||||
LARGE_INTEGER l;
|
||||
::QueryPerformanceFrequency( &l );
|
||||
ulPerfCounterToMillisecondsDivisor = l.QuadPart/1000;
|
||||
|
||||
::QueryPerformanceCounter( &l );
|
||||
uint64 ulFirstQueryPerformanceCounterValue = l.QuadPart;
|
||||
uint64 ulGameTickCount = 0;
|
||||
|
||||
while( !pGameEngine->BShuttingDown() )
|
||||
{
|
||||
if ( pGameEngine->StartFrame() )
|
||||
{
|
||||
// update timers
|
||||
::QueryPerformanceCounter( &l );
|
||||
|
||||
ulGameTickCount = (l.QuadPart - ulFirstQueryPerformanceCounterValue) / ulPerfCounterToMillisecondsDivisor;
|
||||
pGameEngine->SetGameTickCount( ulGameTickCount );
|
||||
|
||||
// Run a game frame
|
||||
pGameClient->RunFrame();
|
||||
|
||||
pGameEngine->EndFrame();
|
||||
|
||||
// Frame rate limiting
|
||||
float flDesiredFrameMilliseconds = 1000.0f/m_flMaxFPS;
|
||||
while( 1 )
|
||||
{
|
||||
::QueryPerformanceCounter( &l );
|
||||
|
||||
ulGameTickCount = (l.QuadPart - ulFirstQueryPerformanceCounterValue) / ulPerfCounterToMillisecondsDivisor;
|
||||
|
||||
float flMillisecondsElapsed = (float)(ulGameTickCount - pGameEngine->GetGameTickCount());
|
||||
if ( flMillisecondsElapsed < flDesiredFrameMilliseconds )
|
||||
{
|
||||
// run networking each frame first
|
||||
pGameClient->ReceiveNetworkData();
|
||||
|
||||
// If enough time is left sleep, otherwise just keep spinning so we don't go over the limit...
|
||||
if ( flDesiredFrameMilliseconds - flMillisecondsElapsed > 2.0f )
|
||||
{
|
||||
Sleep( 2 );
|
||||
}
|
||||
else
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -167,6 +227,9 @@ int APIENTRY RealMain(HINSTANCE hInstance,
|
||||
// Shutdown the SteamAPI
|
||||
SteamAPI_Shutdown();
|
||||
|
||||
// Shutdown Steam CEG
|
||||
Steamworks_TermCEGLibrary();
|
||||
|
||||
// exit
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ enum EMessage
|
||||
k_EMsgServerPassAuthentication = k_EMsgServerBegin+3,
|
||||
k_EMsgServerUpdateWorld = k_EMsgServerBegin+4,
|
||||
k_EMsgServerExiting = k_EMsgServerBegin+5,
|
||||
k_EMsgServerPingResponse = k_EMsgServerBegin+6,
|
||||
|
||||
// Client messages
|
||||
k_EMsgClientBegin = 500,
|
||||
@@ -27,6 +28,11 @@ enum EMessage
|
||||
k_EMsgClientBeginAuthentication = k_EMsgClientBegin+2,
|
||||
k_EMsgClientSendLocalUpdate = k_EMsgClientBegin+3,
|
||||
k_EMsgClientLeavingServer = k_EMsgClientBegin+4,
|
||||
k_EMsgClientPing = k_EMsgClientBegin+5,
|
||||
|
||||
// P2P messages
|
||||
k_EMsgP2PBegin = 500,
|
||||
k_EMsgP2PSendingTicket = k_EMsgP2PBegin+1,
|
||||
|
||||
|
||||
// force 32-bit size enum so the wire protocol doesn't get outgrown later
|
||||
@@ -78,6 +84,13 @@ struct MsgServerExiting_t
|
||||
const DWORD m_dwMessageType;
|
||||
};
|
||||
|
||||
// Msg from server to clients when it is exiting
|
||||
struct MsgServerPingResponse_t
|
||||
{
|
||||
MsgServerPingResponse_t() : m_dwMessageType( k_EMsgServerPingResponse ) {}
|
||||
const DWORD m_dwMessageType;
|
||||
};
|
||||
|
||||
// Msg from client to server when trying to connect
|
||||
struct MsgClientInitiateConnection_t
|
||||
{
|
||||
@@ -94,9 +107,8 @@ struct MsgClientBeginAuthentication_t
|
||||
uint32 m_uTokenLen;
|
||||
#ifdef USE_GS_AUTH_API
|
||||
char m_rgchToken[1024];
|
||||
#else
|
||||
CSteamID m_SteamID;
|
||||
#endif
|
||||
CSteamID m_SteamID;
|
||||
};
|
||||
|
||||
// Msg from client to server when sending state update
|
||||
@@ -109,7 +121,6 @@ struct MsgClientSendLocalUpdate_t
|
||||
ClientSpaceWarUpdateData_t m_ClientUpdateData;
|
||||
};
|
||||
|
||||
|
||||
// Msg from the client telling the server it is about to leave
|
||||
struct MsgClientLeavingServer_t
|
||||
{
|
||||
@@ -117,5 +128,21 @@ struct MsgClientLeavingServer_t
|
||||
const DWORD m_dwMessageType;
|
||||
};
|
||||
|
||||
// server ping
|
||||
struct MsgClientPing_t
|
||||
{
|
||||
MsgClientPing_t() : m_dwMessageType( k_EMsgClientPing ) {}
|
||||
const DWORD m_dwMessageType;
|
||||
};
|
||||
|
||||
// Msg from client to server when trying to connect
|
||||
struct MsgP2PSendingTicket_t
|
||||
{
|
||||
MsgP2PSendingTicket_t() : m_dwMessageType( k_EMsgP2PSendingTicket ) {}
|
||||
const DWORD m_dwMessageType;
|
||||
uint32 m_uTokenLen;
|
||||
char m_rgchToken[1024];
|
||||
CSteamID m_SteamID;
|
||||
};
|
||||
|
||||
#endif // MESSAGES_H
|
||||
@@ -29,6 +29,7 @@ CGameServer::CGameServer( gameserveritem_t *pGameServerItem )
|
||||
m_nServerVersion = pGameServerItem->m_nServerVersion;
|
||||
strncpy( m_szServerName, pGameServerItem->GetName(), ARRAYSIZE( m_szServerName ) );
|
||||
_snprintf( m_szServerString, ARRAYSIZE( m_szServerString ), "%s (%i/%i) at %s ping(%d)", pGameServerItem->GetName(), pGameServerItem->m_nPlayers, pGameServerItem->m_nMaxPlayers, pGameServerItem->m_NetAdr.GetConnectionAddressString(), pGameServerItem->m_nPing );
|
||||
m_steamID = pGameServerItem->m_steamID;
|
||||
}
|
||||
|
||||
|
||||
@@ -78,6 +79,8 @@ void CServerBrowser::RefreshInternetServers()
|
||||
|
||||
m_pMenu->Rebuild( m_ListGameServers, m_bRequestingServers );
|
||||
|
||||
Steamworks_TestSecret();
|
||||
|
||||
// Allocate some filters, there are some common pre-defined values that can be used:
|
||||
//
|
||||
// "gamedir" -- this is used to specify mods inside or a single product/appid
|
||||
|
||||
@@ -31,6 +31,7 @@ public:
|
||||
uint32 GetIP() { return m_unIPAddress; }
|
||||
|
||||
int32 GetPort() { return m_nConnectionPort; }
|
||||
CSteamID GetSteamID() { return m_steamID; }
|
||||
|
||||
private:
|
||||
uint32 m_unIPAddress; // IP address for the server
|
||||
@@ -46,7 +47,7 @@ private:
|
||||
int m_nServerVersion; // server version as reported to Steam
|
||||
char m_szServerName[64]; // Game server name
|
||||
char m_szServerString[128]; // String to show in server browser
|
||||
|
||||
CSteamID m_steamID;
|
||||
};
|
||||
|
||||
class CServerBrowser : public ISteamMatchmakingServerListResponse
|
||||
|
||||
@@ -27,8 +27,7 @@ public:
|
||||
for( iter = List.begin(); iter != List.end(); ++iter )
|
||||
{
|
||||
data.m_eStateToTransitionTo = k_EClientGameConnecting;
|
||||
data.m_unIPAddress = iter->GetIP();
|
||||
data.m_nConnectionPort = iter->GetPort();
|
||||
data.m_steamIDGameServer = iter->GetSteamID();
|
||||
AddMenuItem( MenuItem_t( iter->GetDisplayString(), data ) );
|
||||
}
|
||||
|
||||
|
||||
@@ -502,6 +502,8 @@ void CShip::SetExploding( bool bExploding )
|
||||
if ( m_bExploding == bExploding )
|
||||
return;
|
||||
|
||||
Steamworks_TestSecret();
|
||||
|
||||
// Track that we are exploding, and disable collision detection
|
||||
m_bExploding = bExploding;
|
||||
SetCollisionDetectionDisabled( m_bExploding );
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include "ServerBrowser.h"
|
||||
#include "Leaderboards.h"
|
||||
#include "Lobby.h"
|
||||
#include "p2pauth.h"
|
||||
|
||||
CSpaceWarClient *g_pSpaceWarClient = NULL;
|
||||
CSpaceWarClient* SpaceWarClient() { return g_pSpaceWarClient; }
|
||||
@@ -23,7 +24,7 @@ CSpaceWarClient* SpaceWarClient() { return g_pSpaceWarClient; }
|
||||
// Purpose: Constructor
|
||||
//-----------------------------------------------------------------------------
|
||||
CSpaceWarClient::CSpaceWarClient( CGameEngine *pGameEngine, CSteamID steamIDUser ) :
|
||||
m_SocketStatusCallback( this, &CSpaceWarClient::OnSocketStatusCallback ),
|
||||
m_CallbackP2PSessionConnectFail( this, &CSpaceWarClient::OnP2PSessionConnectFail ),
|
||||
m_LobbyGameCreated( this, &CSpaceWarClient::OnLobbyGameCreated ),
|
||||
m_IPCFailureCallback( this, &CSpaceWarClient::OnIPCFailure ),
|
||||
m_SteamShutdownCallback( this, &CSpaceWarClient::OnSteamShutdown )
|
||||
@@ -39,11 +40,11 @@ CSpaceWarClient::CSpaceWarClient( CGameEngine *pGameEngine, CSteamID steamIDUser
|
||||
m_uPlayerShipIndex = 0;
|
||||
m_SteamIDLocalUser = steamIDUser;
|
||||
m_eConnectedStatus = k_EClientNotConnected;
|
||||
m_hSocketClient = NULL;
|
||||
m_bTransitionedGameState = false;
|
||||
m_rgchErrorText[0] = 0;
|
||||
m_unServerIP = 0;
|
||||
m_usServerPort = 0;
|
||||
m_ulPingSentTime = 0;
|
||||
|
||||
for( uint32 i = 0; i < MAX_PLAYERS_PER_SERVER; ++i )
|
||||
{
|
||||
@@ -74,11 +75,15 @@ CSpaceWarClient::CSpaceWarClient( CGameEngine *pGameEngine, CSteamID steamIDUser
|
||||
// Initialize sun
|
||||
m_pSun = new CSun( pGameEngine );
|
||||
|
||||
// initialize P2P auth engine
|
||||
m_pP2PAuthedGame = new CP2PAuthedGame( m_pGameEngine );
|
||||
|
||||
// Create matchmaking menus
|
||||
m_pServerBrowser = new CServerBrowser( m_pGameEngine );
|
||||
m_pLobbyBrowser = new CLobbyBrowser( m_pGameEngine );
|
||||
m_pLobby = new CLobby( m_pGameEngine );
|
||||
|
||||
|
||||
// Init stats
|
||||
m_pStatsAndAchievements = new CStatsAndAchievements( pGameEngine );
|
||||
m_pLeaderboards = new CLeaderboards( pGameEngine );
|
||||
@@ -95,6 +100,13 @@ CSpaceWarClient::~CSpaceWarClient()
|
||||
{
|
||||
DisconnectFromServer();
|
||||
|
||||
if ( m_pP2PAuthedGame )
|
||||
{
|
||||
m_pP2PAuthedGame->EndGame();
|
||||
delete m_pP2PAuthedGame;
|
||||
m_pP2PAuthedGame = NULL;
|
||||
}
|
||||
|
||||
if ( m_pServer )
|
||||
{
|
||||
delete m_pServer;
|
||||
@@ -127,13 +139,6 @@ CSpaceWarClient::~CSpaceWarClient()
|
||||
m_rgpShips[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// Close down our socket if it appears to be valid
|
||||
if ( m_hSocketClient )
|
||||
{
|
||||
SteamNetworking()->DestroySocket( m_hSocketClient, true );
|
||||
m_hSocketClient = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -147,9 +152,20 @@ void CSpaceWarClient::DisconnectFromServer()
|
||||
SteamUser()->TerminateGameConnection( m_unServerIP, m_usServerPort );
|
||||
|
||||
MsgClientLeavingServer_t msg;
|
||||
BSendServerData( (char*)&msg, sizeof(msg), true );
|
||||
BSendServerData( &msg, sizeof(msg) );
|
||||
m_eConnectedStatus = k_EClientNotConnected;
|
||||
}
|
||||
if ( m_pP2PAuthedGame )
|
||||
{
|
||||
m_pP2PAuthedGame->EndGame();
|
||||
}
|
||||
|
||||
// forget the game server ID
|
||||
if ( m_steamIDGameServer.IsValid() )
|
||||
{
|
||||
SteamNetworking()->CloseP2PSessionWithUser( m_steamIDGameServer );
|
||||
m_steamIDGameServer = CSteamID();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -160,6 +176,13 @@ void CSpaceWarClient::OnReceiveServerInfo( CSteamID steamIDGameServer, bool bVAC
|
||||
{
|
||||
m_eConnectedStatus = k_EClientConnectedPendingAuthentication;
|
||||
m_pQuitMenu->SetHeading( pchServerName );
|
||||
m_steamIDGameServer = steamIDGameServer;
|
||||
|
||||
// look up the servers IP and Port from the connection
|
||||
P2PSessionState_t p2pSessionState;
|
||||
SteamNetworking()->GetP2PSessionState( steamIDGameServer, &p2pSessionState );
|
||||
m_unServerIP = p2pSessionState.m_nRemoteIP;
|
||||
m_usServerPort = p2pSessionState.m_nRemotePort;
|
||||
|
||||
MsgClientBeginAuthentication_t msg;
|
||||
#ifdef USE_GS_AUTH_API
|
||||
@@ -171,10 +194,12 @@ void CSpaceWarClient::OnReceiveServerInfo( CSteamID steamIDGameServer, bool bVAC
|
||||
msg.m_SteamID = SteamUser()->GetSteamID();
|
||||
#endif
|
||||
|
||||
Steamworks_TestSecret();
|
||||
|
||||
if ( msg.m_uTokenLen < 1 )
|
||||
OutputDebugString( "Warning: Looks like InitiateGameConnection didn't give us a good token\n" );
|
||||
|
||||
BSendServerData( (char*)&msg, sizeof(msg), true );
|
||||
BSendServerData( &msg, sizeof(msg) );
|
||||
}
|
||||
|
||||
|
||||
@@ -197,6 +222,11 @@ void CSpaceWarClient::OnReceiveServerAuthenticationResponse( bool bSuccess, uint
|
||||
|
||||
m_uPlayerShipIndex = uPlayerPosition;
|
||||
m_eConnectedStatus = k_EClientConnectedAndAuthenticated;
|
||||
|
||||
// send a ping, to measure round-trip time
|
||||
m_ulPingSentTime = m_pGameEngine->GetGameTickCount();
|
||||
MsgClientPing_t msg;
|
||||
BSendServerData( &msg, sizeof( msg ) );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -264,6 +294,56 @@ void CSpaceWarClient::OnReceiveServerUpdate( ServerSpaceWarUpdateData_t UpdateDa
|
||||
// Update who won last
|
||||
m_uPlayerWhoWonGame = UpdateData.m_uPlayerWhoWonGame;
|
||||
|
||||
if ( m_pP2PAuthedGame )
|
||||
{
|
||||
// has the player list changed?
|
||||
if ( m_pServer )
|
||||
{
|
||||
// if i am the server owner i need to auth everyone who wants to play
|
||||
// assume i am in slot 0, so start at slot 1
|
||||
for( uint32 i=1; i < MAX_PLAYERS_PER_SERVER; ++i )
|
||||
{
|
||||
CSteamID steamIDNew( UpdateData.m_rgPlayerSteamIDs[i] );
|
||||
if ( steamIDNew == SteamUser()->GetSteamID() )
|
||||
{
|
||||
OutputDebugStringA( "Server player slot 0 is not server owner.\n" );
|
||||
}
|
||||
else if ( steamIDNew != m_rgSteamIDPlayers[i] )
|
||||
{
|
||||
if ( m_rgSteamIDPlayers[i].IsValid() )
|
||||
{
|
||||
m_pP2PAuthedGame->PlayerDisconnect( i );
|
||||
}
|
||||
if ( steamIDNew.IsValid() )
|
||||
{
|
||||
m_pP2PAuthedGame->RegisterPlayer( i, steamIDNew );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// i am just a client, i need to auth the game owner ( slot 0 )
|
||||
CSteamID steamIDNew( UpdateData.m_rgPlayerSteamIDs[0] );
|
||||
if ( steamIDNew == SteamUser()->GetSteamID() )
|
||||
{
|
||||
OutputDebugStringA( "Server player slot 0 is not server owner.\n" );
|
||||
}
|
||||
else if ( steamIDNew != m_rgSteamIDPlayers[0] )
|
||||
{
|
||||
if ( m_rgSteamIDPlayers[0].IsValid() )
|
||||
{
|
||||
OutputDebugStringA( "Server player slot 0 has disconnected - but thats the server owner.\n" );
|
||||
m_pP2PAuthedGame->PlayerDisconnect( 0 );
|
||||
}
|
||||
if ( steamIDNew.IsValid() )
|
||||
{
|
||||
m_pP2PAuthedGame->StartAuthPlayer( 0, steamIDNew );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Update the ships
|
||||
for( uint32 i=0; i < MAX_PLAYERS_PER_SERVER; ++i )
|
||||
{
|
||||
@@ -336,9 +416,9 @@ void CSpaceWarClient::SetConnectionFailureText( const char *pchErrorText )
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Send data to the current server
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CSpaceWarClient::BSendServerData( char *pData, uint32 nSizeOfData, bool bSendReliably )
|
||||
bool CSpaceWarClient::BSendServerData( const void *pData, uint32 nSizeOfData )
|
||||
{
|
||||
if ( !SteamNetworking()->SendDataOnSocket( m_hSocketClient, pData, nSizeOfData, bSendReliably ) )
|
||||
if ( !SteamNetworking()->SendP2PPacket( m_steamIDGameServer, pData, nSizeOfData, k_EP2PSendUnreliable ) )
|
||||
{
|
||||
OutputDebugString( "Failed sending data to server\n" );
|
||||
return false;
|
||||
@@ -364,14 +444,10 @@ void CSpaceWarClient::InitiateServerConnection( uint32 unServerAddress, const in
|
||||
// and so we will retry at appropriate intervals if packets drop
|
||||
m_ulLastNetworkDataReceivedTime = m_ulLastConnectionAttemptRetryTime = m_pGameEngine->GetGameTickCount();
|
||||
|
||||
// Create UDP socket for the client to talk to the server over
|
||||
m_hSocketClient = SteamNetworking()->CreateConnectionSocket( unServerAddress, nPort, 10 );
|
||||
if ( !m_hSocketClient )
|
||||
{
|
||||
OutputDebugString( "Failed creating socket for CSpaceWarClient -- won't be able to talk to server\n" );
|
||||
}
|
||||
|
||||
// wait for the callback before initiating connection
|
||||
// ping the server to find out what it's steamID is
|
||||
m_unServerIP = unServerAddress;
|
||||
m_usServerPort = (uint16)nPort;
|
||||
m_GameServerPing.RetrieveSteamIDFromGameServer( this, m_unServerIP, m_usServerPort );
|
||||
}
|
||||
|
||||
|
||||
@@ -387,52 +463,28 @@ void CSpaceWarClient::InitiateServerConnection( CSteamID steamIDGameServer )
|
||||
|
||||
SetGameState( k_EClientGameConnecting );
|
||||
|
||||
m_steamIDGameServer = steamIDGameServer;
|
||||
|
||||
// Update when we last retried the connection, as well as the last packet received time so we won't timeout too soon,
|
||||
// and so we will retry at appropriate intervals if packets drop
|
||||
m_ulLastNetworkDataReceivedTime = m_ulLastConnectionAttemptRetryTime = m_pGameEngine->GetGameTickCount();
|
||||
|
||||
// Create UDP socket for the client to talk to the server over
|
||||
m_hSocketClient = SteamNetworking()->CreateP2PConnectionSocket( steamIDGameServer, 0, 10, true );
|
||||
if ( !m_hSocketClient )
|
||||
{
|
||||
OutputDebugString( "Failed creating socket for CSpaceWarClient -- won't be able to talk to server\n" );
|
||||
}
|
||||
|
||||
// wait for the callback before initiating connection
|
||||
// send the packet to the server
|
||||
MsgClientInitiateConnection_t msg;
|
||||
BSendServerData( &msg, sizeof( msg ) );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: steam callback, trigger when our connection state changes
|
||||
//-----------------------------------------------------------------------------
|
||||
void CSpaceWarClient::OnSocketStatusCallback( SocketStatusCallback_t *pCallback )
|
||||
void CSpaceWarClient::OnP2PSessionConnectFail( P2PSessionConnectFail_t *pCallback )
|
||||
{
|
||||
// make sure the callback is for our socket
|
||||
if ( pCallback->m_hSocket != m_hSocketClient )
|
||||
return;
|
||||
|
||||
// Update out network data received time even though we haven't really received anything yet,
|
||||
// this will help us make sure we don't time out prematurely during the handshake
|
||||
m_ulLastNetworkDataReceivedTime = m_pGameEngine->GetGameTickCount();
|
||||
|
||||
// if we've finished connecting to the server, send the connect message
|
||||
if ( pCallback->m_eSNetSocketState == k_ESNetSocketStateConnected )
|
||||
{
|
||||
MsgClientInitiateConnection_t msg;
|
||||
BSendServerData( (char*)&msg, sizeof( msg ), true );
|
||||
}
|
||||
|
||||
// handling being disconnect from the server signal via network breakage, or the remote end dying
|
||||
if ( pCallback->m_eSNetSocketState == k_ESNetSocketStateRemoteEndDisconnected
|
||||
|| pCallback->m_eSNetSocketState == k_ESNetSocketStateConnectionBroken )
|
||||
if ( pCallback->m_steamIDRemote == m_steamIDGameServer )
|
||||
{
|
||||
// failed, error out
|
||||
OutputDebugString( "Failed to make P2P connection, quiting server" );
|
||||
OnReceiveServerExiting();
|
||||
m_hSocketClient = NULL;
|
||||
}
|
||||
|
||||
if ( pCallback->m_eSNetSocketState >= k_ESNetSocketStateDisconnecting )
|
||||
{
|
||||
m_hSocketClient = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -442,9 +494,6 @@ void CSpaceWarClient::OnSocketStatusCallback( SocketStatusCallback_t *pCallback
|
||||
//-----------------------------------------------------------------------------
|
||||
void CSpaceWarClient::ReceiveNetworkData()
|
||||
{
|
||||
if ( !m_hSocketClient )
|
||||
return;
|
||||
|
||||
char rgchRecvBuf[MAX_SPACEWAR_PACKET_SIZE];
|
||||
char *pchRecvBuf = rgchRecvBuf;
|
||||
uint32 cubMsgSize;
|
||||
@@ -458,90 +507,115 @@ void CSpaceWarClient::ReceiveNetworkData()
|
||||
}
|
||||
|
||||
// see if there is any data waiting on the socket
|
||||
if ( !SteamNetworking()->RetrieveDataFromSocket( m_hSocketClient, rgchRecvBuf, sizeof( rgchRecvBuf ), &cubMsgSize ) )
|
||||
if ( !SteamNetworking()->IsP2PPacketAvailable( &cubMsgSize ) )
|
||||
break;
|
||||
|
||||
// not enough space in buffer, so message won't have been popped off of list
|
||||
// not enough space in default buffer
|
||||
// alloc custom size and try again
|
||||
if ( cubMsgSize > sizeof(rgchRecvBuf) )
|
||||
{
|
||||
pchRecvBuf = (char *)malloc( cubMsgSize );
|
||||
SteamNetworking()->RetrieveDataFromSocket( m_hSocketClient, pchRecvBuf, cubMsgSize, &cubMsgSize );
|
||||
}
|
||||
CSteamID steamIDRemote;
|
||||
if ( !SteamNetworking()->ReadP2PPacket( pchRecvBuf, cubMsgSize, &cubMsgSize, &steamIDRemote ) )
|
||||
break;
|
||||
|
||||
m_ulLastNetworkDataReceivedTime = m_pGameEngine->GetGameTickCount();
|
||||
|
||||
// make sure we're connected
|
||||
if ( m_eConnectedStatus == k_EClientNotConnected && m_eGameState != k_EClientGameConnecting )
|
||||
continue;
|
||||
|
||||
if ( cubMsgSize < sizeof( EMessage ) )
|
||||
// see if it's from the game server
|
||||
if ( steamIDRemote == m_steamIDGameServer )
|
||||
{
|
||||
OutputDebugString( "Got garbage on client socket, too short\n" );
|
||||
}
|
||||
m_ulLastNetworkDataReceivedTime = m_pGameEngine->GetGameTickCount();
|
||||
|
||||
EMessage *pEMsg = (EMessage*)pchRecvBuf;
|
||||
switch ( *pEMsg )
|
||||
// make sure we're connected
|
||||
if ( m_eConnectedStatus == k_EClientNotConnected && m_eGameState != k_EClientGameConnecting )
|
||||
continue;
|
||||
|
||||
if ( cubMsgSize < sizeof( EMessage ) )
|
||||
{
|
||||
OutputDebugString( "Got garbage on client socket, too short\n" );
|
||||
}
|
||||
|
||||
EMessage *pEMsg = (EMessage*)pchRecvBuf;
|
||||
switch ( *pEMsg )
|
||||
{
|
||||
case k_EMsgServerSendInfo:
|
||||
{
|
||||
if ( cubMsgSize != sizeof( MsgServerSendInfo_t ) )
|
||||
{
|
||||
OutputDebugString ("Bad server info msg\n" );
|
||||
continue;
|
||||
}
|
||||
MsgServerSendInfo_t *pMsg = (MsgServerSendInfo_t*)pchRecvBuf;
|
||||
|
||||
// pull the IP address of the user from the socket
|
||||
OnReceiveServerInfo( CSteamID( pMsg->m_ulSteamIDServer ), pMsg->m_bIsVACSecure, pMsg->m_rgchServerName );
|
||||
}
|
||||
break;
|
||||
case k_EMsgServerPassAuthentication:
|
||||
{
|
||||
if ( cubMsgSize != sizeof( MsgServerPassAuthentication_t ) )
|
||||
{
|
||||
OutputDebugString( "Bad accept connection msg\n" );
|
||||
continue;
|
||||
}
|
||||
MsgServerPassAuthentication_t *pMsg = (MsgServerPassAuthentication_t*)pchRecvBuf;
|
||||
|
||||
// Our game client doesn't really care about whether the server is secure, or what its
|
||||
// steamID is, but if it did we would pass them in here as they are part of the accept message
|
||||
OnReceiveServerAuthenticationResponse( true, pMsg->m_uPlayerPosition );
|
||||
}
|
||||
break;
|
||||
case k_EMsgServerFailAuthentication:
|
||||
{
|
||||
OnReceiveServerAuthenticationResponse( false, 0 );
|
||||
}
|
||||
break;
|
||||
case k_EMsgServerUpdateWorld:
|
||||
{
|
||||
if ( cubMsgSize != sizeof( MsgServerUpdateWorld_t ) )
|
||||
{
|
||||
OutputDebugString( "Bad server world update msg\n" );
|
||||
continue;
|
||||
}
|
||||
|
||||
MsgServerUpdateWorld_t *pMsg = (MsgServerUpdateWorld_t*)pchRecvBuf;
|
||||
OnReceiveServerUpdate( pMsg->m_ServerUpdateData );
|
||||
}
|
||||
break;
|
||||
case k_EMsgServerExiting:
|
||||
{
|
||||
if ( cubMsgSize != sizeof( MsgServerExiting_t ) )
|
||||
{
|
||||
OutputDebugString( "Bad server exiting msg\n" );
|
||||
}
|
||||
OnReceiveServerExiting();
|
||||
}
|
||||
break;
|
||||
case k_EMsgServerPingResponse:
|
||||
{
|
||||
uint64 ulTimePassedMS = m_pGameEngine->GetGameTickCount() - m_ulPingSentTime;
|
||||
char rgchT[256];
|
||||
_snprintf( rgchT, sizeof(rgchT), "Round-trip ping time to server %d ms\n", (int)ulTimePassedMS );
|
||||
OutputDebugString( rgchT );
|
||||
m_ulPingSentTime = 0;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
OutputDebugString( "Unhandled message from server\n" );
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
case k_EMsgServerSendInfo:
|
||||
{
|
||||
if ( cubMsgSize != sizeof( MsgServerSendInfo_t ) )
|
||||
{
|
||||
OutputDebugString ("Bad server info msg\n" );
|
||||
continue;
|
||||
}
|
||||
MsgServerSendInfo_t *pMsg = (MsgServerSendInfo_t*)pchRecvBuf;
|
||||
|
||||
// pull the IP address of the user from the socket
|
||||
SteamNetworking()->GetSocketInfo( m_hSocketClient, NULL, NULL, &m_unServerIP, &m_usServerPort );
|
||||
OnReceiveServerInfo( CSteamID( pMsg->m_ulSteamIDServer ), pMsg->m_bIsVACSecure, pMsg->m_rgchServerName );
|
||||
}
|
||||
break;
|
||||
case k_EMsgServerPassAuthentication:
|
||||
{
|
||||
if ( cubMsgSize != sizeof( MsgServerPassAuthentication_t ) )
|
||||
{
|
||||
OutputDebugString( "Bad accept connection msg\n" );
|
||||
continue;
|
||||
}
|
||||
MsgServerPassAuthentication_t *pMsg = (MsgServerPassAuthentication_t*)pchRecvBuf;
|
||||
|
||||
// Our game client doesn't really care about whether the server is secure, or what its
|
||||
// steamID is, but if it did we would pass them in here as they are part of the accept message
|
||||
OnReceiveServerAuthenticationResponse( true, pMsg->m_uPlayerPosition );
|
||||
}
|
||||
break;
|
||||
case k_EMsgServerFailAuthentication:
|
||||
{
|
||||
OnReceiveServerAuthenticationResponse( false, 0 );
|
||||
}
|
||||
break;
|
||||
case k_EMsgServerUpdateWorld:
|
||||
{
|
||||
if ( cubMsgSize != sizeof( MsgServerUpdateWorld_t ) )
|
||||
{
|
||||
OutputDebugString( "Bad server world update msg\n" );
|
||||
continue;
|
||||
}
|
||||
|
||||
MsgServerUpdateWorld_t *pMsg = (MsgServerUpdateWorld_t*)pchRecvBuf;
|
||||
OnReceiveServerUpdate( pMsg->m_ServerUpdateData );
|
||||
}
|
||||
break;
|
||||
case k_EMsgServerExiting:
|
||||
{
|
||||
if ( cubMsgSize != sizeof( MsgServerExiting_t ) )
|
||||
{
|
||||
OutputDebugString( "Bad server exiting msg\n" );
|
||||
}
|
||||
OnReceiveServerExiting();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
OutputDebugString( "Unhandled message from server\n" );
|
||||
break;
|
||||
EMessage *pEMsg = (EMessage*)pchRecvBuf;
|
||||
m_pP2PAuthedGame->HandleMessage( *pEMsg, pchRecvBuf );
|
||||
}
|
||||
}
|
||||
|
||||
// if we're running a server, do that as well
|
||||
if ( m_pServer )
|
||||
{
|
||||
m_pServer->ReceiveNetworkData();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -550,6 +624,8 @@ void CSpaceWarClient::ReceiveNetworkData()
|
||||
//-----------------------------------------------------------------------------
|
||||
void CSpaceWarClient::OnReceiveServerExiting()
|
||||
{
|
||||
if ( m_pP2PAuthedGame )
|
||||
m_pP2PAuthedGame->EndGame();
|
||||
if ( m_eGameState != k_EClientGameActive )
|
||||
return;
|
||||
|
||||
@@ -611,6 +687,18 @@ void CSpaceWarClient::OnLobbyEntered( LobbyEnter_t *pCallback, bool bIOFailure )
|
||||
|
||||
}
|
||||
|
||||
void CSpaceWarClient::OnLobbyDataChange( LobbyDataUpdate_t *pCallback, bool bIOFailure )
|
||||
{
|
||||
OutputDebugStringA( "OnLobbyDataChange ");
|
||||
CSteamID steamIDLobbyMember( pCallback->m_ulSteamIDMember );
|
||||
}
|
||||
|
||||
void CSpaceWarClient::OnLobbyChatUpdate( LobbyChatUpdate_t *pCallback, bool bIOFailure )
|
||||
{
|
||||
CSteamID steamIDLobbyMember( pCallback->m_ulSteamIDUserChanged );
|
||||
CSteamID steamIDLobbyMember2( pCallback->m_ulSteamIDMakingChange );
|
||||
OutputDebugStringA( "OnLobbyChatUpdate ");
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Joins a game from a lobby
|
||||
@@ -625,11 +713,6 @@ void CSpaceWarClient::OnLobbyGameCreated( LobbyGameCreated_t *pCallback )
|
||||
{
|
||||
InitiateServerConnection( CSteamID( pCallback->m_ulSteamIDGameServer ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
// fall back to using the IP address directly
|
||||
InitiateServerConnection( pCallback->m_unIP, pCallback->m_usPort );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -701,7 +784,7 @@ void CSpaceWarClient::OnGameStateChanged( EClientGameState eGameStateNew )
|
||||
if ( !m_SteamCallResultLobbyCreated.IsActive() )
|
||||
{
|
||||
// ask steam to create a lobby
|
||||
SteamAPICall_t hSteamAPICall = SteamMatchmaking()->CreateLobby( k_ELobbyTypePublic /* public lobby, anyone can find it */ );
|
||||
SteamAPICall_t hSteamAPICall = SteamMatchmaking()->CreateLobby( k_ELobbyTypePublic /* public lobby, anyone can find it */, 4 );
|
||||
// set the function to call when this completes
|
||||
m_SteamCallResultLobbyCreated.Set( hSteamAPICall, this, &CSpaceWarClient::OnLobbyCreated );
|
||||
}
|
||||
@@ -838,11 +921,9 @@ void CSpaceWarClient::RunFrame()
|
||||
if ( m_pServer && m_pServer->IsConnectedToSteam() )
|
||||
{
|
||||
// server is up; tell everyone else to connect
|
||||
SteamMatchmaking()->SetLobbyGameServer( m_steamIDLobby, m_pServer->GetIP(), m_pServer->GetPort(), m_pServer->GetSteamID() );
|
||||
|
||||
SteamMatchmaking()->SetLobbyGameServer( m_steamIDLobby, 0, 0, m_pServer->GetSteamID() );
|
||||
// start connecting ourself via localhost (this will automatically leave the lobby)
|
||||
uint32 unIPAddress = ( 1 ) + ( 0 << 8 ) + ( 0 << 16 ) + ( 127 << 24 );
|
||||
InitiateServerConnection( unIPAddress, m_pServer->GetPort() );
|
||||
InitiateServerConnection( m_pServer->GetSteamID() );
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -884,9 +965,12 @@ void CSpaceWarClient::RunFrame()
|
||||
// Check if we've waited too long and should time out the connection
|
||||
if ( m_pGameEngine->GetGameTickCount() - m_ulStateTransitionTime > MILLISECONDS_CONNECTION_TIMEOUT )
|
||||
{
|
||||
if ( m_pP2PAuthedGame )
|
||||
m_pP2PAuthedGame->EndGame();
|
||||
if ( m_eConnectedStatus == k_EClientConnectedAndAuthenticated )
|
||||
SteamUser()->TerminateGameConnection( m_unServerIP, m_usServerPort );
|
||||
|
||||
|
||||
m_GameServerPing.CancelPing();
|
||||
SetConnectionFailureText( "Timed out connecting to game server" );
|
||||
SetGameState( k_EClientGameConnectionFailure );
|
||||
}
|
||||
@@ -941,14 +1025,13 @@ void CSpaceWarClient::RunFrame()
|
||||
if ( !m_pServer )
|
||||
{
|
||||
m_pServer = new CSpaceWarServer( m_pGameEngine );
|
||||
uint32 unIPAddress = ( 1 ) + ( 0 << 8 ) + ( 0 << 16 ) + ( 127 << 24 );
|
||||
InitiateServerConnection( unIPAddress, SPACEWAR_SERVER_PORT );
|
||||
}
|
||||
else
|
||||
{
|
||||
OutputDebugString( "Server already started locally when in k_EClientGameStartServer state!\n" );
|
||||
}
|
||||
|
||||
if ( m_pServer && m_pServer->IsConnectedToSteam() )
|
||||
{
|
||||
// server is ready, connect to it
|
||||
InitiateServerConnection( m_pServer->GetSteamID() );
|
||||
}
|
||||
break;
|
||||
case k_EClientGameDraw:
|
||||
case k_EClientGameWinner:
|
||||
@@ -1004,7 +1087,37 @@ void CSpaceWarClient::RunFrame()
|
||||
|
||||
// If this fails, it probably just means its not time to send an update yet
|
||||
if ( m_rgpShips[ m_uPlayerShipIndex ]->BGetClientUpdateData( &msg.m_ClientUpdateData ) )
|
||||
BSendServerData( (char*)&msg, sizeof( msg ), false );
|
||||
BSendServerData( &msg, sizeof( msg ) );
|
||||
}
|
||||
|
||||
if ( m_pP2PAuthedGame )
|
||||
{
|
||||
if ( m_pServer )
|
||||
{
|
||||
// Now if we are the owner of the game, lets make sure all of our players are legit.
|
||||
// if they are not, we tell the server to kick them off
|
||||
// Start at 1 to skip myself
|
||||
for ( int i = 1; i < MAX_PLAYERS_PER_SERVER; i++ )
|
||||
{
|
||||
if ( m_pP2PAuthedGame->m_rgpP2PAuthPlayer[i] && !m_pP2PAuthedGame->m_rgpP2PAuthPlayer[i]->BIsAuthOk() )
|
||||
{
|
||||
m_pServer->KickPlayerOffServer( m_pP2PAuthedGame->m_rgpP2PAuthPlayer[i]->m_steamID );
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// If we are not the owner of the game, lets make sure the game owner is legit
|
||||
// if he is not, we leave the game
|
||||
if ( m_pP2PAuthedGame->m_rgpP2PAuthPlayer[0] )
|
||||
{
|
||||
if ( !m_pP2PAuthedGame->m_rgpP2PAuthPlayer[0]->BIsAuthOk() )
|
||||
{
|
||||
// leave the game
|
||||
SetGameState( k_EClientGameMenu );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If we've started a local server run it
|
||||
|
||||
@@ -28,6 +28,8 @@ class CServerBrowser;
|
||||
class CLobbyBrowser;
|
||||
class CLobby;
|
||||
class CLeaderboards;
|
||||
class CP2PAuthPlayer;
|
||||
class CP2PAuthedGame;
|
||||
|
||||
// Height of the HUD font
|
||||
#define HUD_FONT_HEIGHT 18
|
||||
@@ -47,8 +49,7 @@ enum EClientConnectionState
|
||||
struct ServerBrowserMenuData_t
|
||||
{
|
||||
EClientGameState m_eStateToTransitionTo;
|
||||
uint32 m_unIPAddress;
|
||||
int32 m_nConnectionPort;
|
||||
CSteamID m_steamIDGameServer;
|
||||
};
|
||||
|
||||
// a lobby as shown in the find lobbies menu
|
||||
@@ -92,11 +93,11 @@ public:
|
||||
void ReceiveNetworkData();
|
||||
|
||||
// Connect to a server at a given IP address or game server steamID
|
||||
void InitiateServerConnection( uint32 unServerAddress, const int32 nPort );
|
||||
void InitiateServerConnection( CSteamID steamIDGameServer );
|
||||
void InitiateServerConnection( uint32 unServerAddress, const int32 nPort );
|
||||
|
||||
// Send data to a client at the given ship index
|
||||
bool BSendServerData( char *pData, uint32 nSizeOfData, bool bSendReliably );
|
||||
bool BSendServerData( const void *pData, uint32 nSizeOfData );
|
||||
|
||||
// Menu callback handler (handles a bunch of menus that just change state with no extra data)
|
||||
void OnMenuSelection( EClientGameState eState ) { SetGameState( eState ); }
|
||||
@@ -106,7 +107,7 @@ public:
|
||||
{
|
||||
if ( selection.m_eStateToTransitionTo == k_EClientGameConnecting )
|
||||
{
|
||||
InitiateServerConnection( selection.m_unIPAddress, selection.m_nConnectionPort );
|
||||
InitiateServerConnection( selection.m_steamIDGameServer );
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -122,6 +123,8 @@ public:
|
||||
SteamAPICall_t hSteamAPICall = SteamMatchmaking()->JoinLobby( selection.m_steamIDLobby );
|
||||
// set the function to call when this API completes
|
||||
m_SteamCallResultLobbyEntered.Set( hSteamAPICall, this, &CSpaceWarClient::OnLobbyEntered );
|
||||
m_SteamCallResultLobbyDataChange.Set( hSteamAPICall, this, &CSpaceWarClient::OnLobbyDataChange );
|
||||
m_SteamCallResultLobbyChatUpdate.Set( hSteamAPICall, this, &CSpaceWarClient::OnLobbyChatUpdate );
|
||||
}
|
||||
|
||||
SetGameState( selection.m_eStateToTransitionTo );
|
||||
@@ -232,16 +235,62 @@ private:
|
||||
// Time we last got data from the server
|
||||
uint64 m_ulLastNetworkDataReceivedTime;
|
||||
|
||||
// Time when we sent our ping
|
||||
uint64 m_ulPingSentTime;
|
||||
|
||||
// Text to display if we are in an error state
|
||||
char m_rgchErrorText[256];
|
||||
|
||||
// Socket to use when communicating with servers
|
||||
SNetSocket_t m_hSocketClient;
|
||||
|
||||
// Server address data
|
||||
CSteamID m_steamIDGameServer;
|
||||
uint32 m_unServerIP;
|
||||
uint16 m_usServerPort;
|
||||
|
||||
// simple class to marshal callbacks from pinging a game server
|
||||
class CGameServerPing : public ISteamMatchmakingPingResponse
|
||||
{
|
||||
public:
|
||||
CGameServerPing()
|
||||
{
|
||||
m_hGameServerQuery = HSERVERQUERY_INVALID;
|
||||
m_pSpaceWarsClient = NULL;
|
||||
}
|
||||
|
||||
void RetrieveSteamIDFromGameServer( CSpaceWarClient *pSpaceWarClient, uint32 unIP, uint16 unPort )
|
||||
{
|
||||
m_pSpaceWarsClient = pSpaceWarClient;
|
||||
m_hGameServerQuery = SteamMatchmakingServers()->PingServer( unIP, unPort, this );
|
||||
}
|
||||
|
||||
void CancelPing()
|
||||
{
|
||||
m_hGameServerQuery = HSERVERQUERY_INVALID;
|
||||
}
|
||||
|
||||
// Server has responded successfully and has updated data
|
||||
virtual void ServerResponded( gameserveritem_t &server )
|
||||
{
|
||||
if ( m_hGameServerQuery != HSERVERQUERY_INVALID && server.m_steamID.IsValid() )
|
||||
{
|
||||
m_pSpaceWarsClient->InitiateServerConnection( server.m_steamID );
|
||||
}
|
||||
|
||||
m_hGameServerQuery = HSERVERQUERY_INVALID;
|
||||
}
|
||||
|
||||
// Server failed to respond to the ping request
|
||||
virtual void ServerFailedToRespond()
|
||||
{
|
||||
m_hGameServerQuery = HSERVERQUERY_INVALID;
|
||||
}
|
||||
|
||||
private:
|
||||
HServerQuery m_hGameServerQuery; // we're ping a game server, so we can convert IP:Port to a steamID
|
||||
CSpaceWarClient *m_pSpaceWarsClient;
|
||||
};
|
||||
CGameServerPing m_GameServerPing;
|
||||
|
||||
|
||||
// Track whether we are connected to a server (and what specific state that connection is in)
|
||||
EClientConnectionState m_eConnectedStatus;
|
||||
|
||||
@@ -281,6 +330,11 @@ private:
|
||||
void OnLobbyEntered( LobbyEnter_t *pCallback, bool bIOFailure );
|
||||
CCallResult<CSpaceWarClient, LobbyEnter_t> m_SteamCallResultLobbyEntered;
|
||||
|
||||
void OnLobbyDataChange( LobbyDataUpdate_t *pCallback, bool bIOFailure );
|
||||
CCallResult<CSpaceWarClient, LobbyDataUpdate_t> m_SteamCallResultLobbyDataChange;
|
||||
void OnLobbyChatUpdate( LobbyChatUpdate_t *pCallback, bool bIOFailure );
|
||||
CCallResult<CSpaceWarClient, LobbyChatUpdate_t> m_SteamCallResultLobbyChatUpdate;
|
||||
|
||||
// callback for when the lobby game server has started
|
||||
STEAM_CALLBACK( CSpaceWarClient, OnLobbyGameCreated, LobbyGameCreated_t, m_LobbyGameCreated );
|
||||
|
||||
@@ -289,9 +343,11 @@ private:
|
||||
|
||||
// local lobby display
|
||||
CLobby *m_pLobby;
|
||||
// p2p game auth manager
|
||||
CP2PAuthedGame *m_pP2PAuthedGame;
|
||||
|
||||
// connection handler
|
||||
STEAM_CALLBACK( CSpaceWarClient, OnSocketStatusCallback, SocketStatusCallback_t, m_SocketStatusCallback );
|
||||
STEAM_CALLBACK( CSpaceWarClient, OnP2PSessionConnectFail, P2PSessionConnectFail_t, m_CallbackP2PSessionConnectFail );
|
||||
|
||||
// ipc failure handler
|
||||
STEAM_CALLBACK( CSpaceWarClient, OnIPCFailure, IPCFailure_t, m_IPCFailureCallback );
|
||||
|
||||
@@ -21,7 +21,8 @@ CSpaceWarServer::CSpaceWarServer( CGameEngine *pGameEngine ) :
|
||||
m_CallbackGSClientApprove( this, &CSpaceWarServer::OnGSClientApprove ),
|
||||
m_CallbackGSClientDeny( this, &CSpaceWarServer::OnGSClientDeny ),
|
||||
m_CallbackGSClientKick( this, &CSpaceWarServer::OnGSClientKick ),
|
||||
m_CallbackSocketStatus( this, &CSpaceWarServer::OnSocketStatusCallback )
|
||||
m_CallbackP2PSessionConnectFail( this, &CSpaceWarServer::OnP2PSessionConnectFail ),
|
||||
m_CallbackP2PSessionRequest( this, &CSpaceWarServer::OnP2PSessionRequest )
|
||||
{
|
||||
m_bConnectedToSteam = false;
|
||||
|
||||
@@ -92,21 +93,8 @@ CSpaceWarServer::CSpaceWarServer( CGameEngine *pGameEngine ) :
|
||||
// Initialize sun
|
||||
m_pSun = new CSun( pGameEngine );
|
||||
|
||||
// We don't create our socket to listen for clients yet, because we have to be logged
|
||||
// into Steam and have our own game server SteamID before we can really handle them.
|
||||
//
|
||||
// We'll setup our socket and start listening after that happens.
|
||||
m_hSocketServer = NULL;
|
||||
|
||||
// Initialize ships
|
||||
ResetPlayerShips();
|
||||
|
||||
// Start listening for client connections, as we now have enough info to really handle them
|
||||
m_hSocketServer = SteamGameServerNetworking()->CreateListenSocket( 0, 0, SPACEWAR_SERVER_PORT, true );
|
||||
if ( !m_hSocketServer )
|
||||
{
|
||||
OutputDebugString( "Failed creating socket for CSpaceWarServer -- no one will be able to connect\n" );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -140,39 +128,38 @@ CSpaceWarServer::~CSpaceWarServer()
|
||||
SteamGameServer()->LogOff();
|
||||
#endif
|
||||
|
||||
// Close down our socket if it appears to be valid
|
||||
if ( m_hSocketServer )
|
||||
{
|
||||
SteamGameServerNetworking()->DestroyListenSocket( m_hSocketServer, true );
|
||||
}
|
||||
// release our reference to the steam client library
|
||||
SteamGameServer_Shutdown();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Handle sending data to a client at a given index
|
||||
// Purpose: Handle clients connecting
|
||||
//-----------------------------------------------------------------------------
|
||||
void CSpaceWarServer::OnSocketStatusCallback( SocketStatusCallback_t *pCallback )
|
||||
void CSpaceWarServer::OnP2PSessionRequest( P2PSessionRequest_t *pCallback )
|
||||
{
|
||||
// make sure the callback involves our listen socket (the callbacks go to all listeners, so you have to filter)
|
||||
if ( pCallback->m_hListenSocket != m_hSocketServer )
|
||||
return;
|
||||
// we'll accept a connection from anyone
|
||||
SteamGameServerNetworking()->AcceptP2PSessionWithUser( pCallback->m_steamIDRemote );
|
||||
}
|
||||
|
||||
// lookup disconnect users
|
||||
if ( pCallback->m_eSNetSocketState >= k_ESNetSocketStateDisconnecting )
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Handle clients disconnecting
|
||||
//-----------------------------------------------------------------------------
|
||||
void CSpaceWarServer::OnP2PSessionConnectFail( P2PSessionConnectFail_t *pCallback )
|
||||
{
|
||||
// socket has closed, kick the user associated with it
|
||||
for( uint32 i = 0; i < MAX_PLAYERS_PER_SERVER; ++i )
|
||||
{
|
||||
// socket has closed, kick the user associated with it
|
||||
for( uint32 i = 0; i < MAX_PLAYERS_PER_SERVER; ++i )
|
||||
{
|
||||
// If there is no ship, skip
|
||||
if ( !m_rgClientData[i].m_bActive )
|
||||
continue;
|
||||
// If there is no ship, skip
|
||||
if ( !m_rgClientData[i].m_bActive )
|
||||
continue;
|
||||
|
||||
if ( m_rgClientData[i].m_hSocket == pCallback->m_hSocket )
|
||||
{
|
||||
OutputDebugString( "Disconnected dropped user\n" );
|
||||
RemovePlayerFromServer( i );
|
||||
break;
|
||||
}
|
||||
if ( m_rgClientData[i].m_SteamIDUser == pCallback->m_steamIDRemote )
|
||||
{
|
||||
OutputDebugString( "Disconnected dropped user\n" );
|
||||
RemovePlayerFromServer( i );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -187,7 +174,7 @@ bool CSpaceWarServer::BSendDataToClient( uint32 uShipIndex, char *pData, uint32
|
||||
if ( uShipIndex >= MAX_PLAYERS_PER_SERVER )
|
||||
return false;
|
||||
|
||||
if ( !SteamGameServerNetworking()->SendDataOnSocket( m_rgClientData[uShipIndex].m_hSocket, pData, nSizeOfData, false ) )
|
||||
if ( !SteamGameServerNetworking()->SendP2PPacket( m_rgClientData[uShipIndex].m_SteamIDUser, pData, nSizeOfData, k_EP2PSendUnreliable ) )
|
||||
{
|
||||
OutputDebugString( "Failed sending data to a client\n" );
|
||||
return false;
|
||||
@@ -206,7 +193,7 @@ bool CSpaceWarServer::BSendDataToPendingClient( uint32 uShipIndex, char *pData,
|
||||
if ( uShipIndex >= MAX_PLAYERS_PER_SERVER )
|
||||
return false;
|
||||
|
||||
if ( !SteamGameServerNetworking()->SendDataOnSocket( m_rgPendingClientData[uShipIndex].m_hSocket, pData, nSizeOfData, false ) )
|
||||
if ( !SteamGameServerNetworking()->SendP2PPacket( m_rgPendingClientData[uShipIndex].m_SteamIDUser, pData, nSizeOfData, k_EP2PSendReliable ) )
|
||||
{
|
||||
OutputDebugString( "Failed sending data to a pending client\n" );
|
||||
return false;
|
||||
@@ -216,30 +203,15 @@ bool CSpaceWarServer::BSendDataToPendingClient( uint32 uShipIndex, char *pData,
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Handle sending data to a client at a given address
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CSpaceWarServer::BSendDataToClientOnSocket( SNetSocket_t hSocket, char *pData, uint32 nSizeOfData )
|
||||
{
|
||||
if ( !SteamGameServerNetworking()->SendDataOnSocket( hSocket, pData, nSizeOfData, false ) )
|
||||
{
|
||||
OutputDebugString( "Failed sending data to a client\n" );
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Handle a new client connecting
|
||||
//-----------------------------------------------------------------------------
|
||||
void CSpaceWarServer::OnClientBeginAuthentication( SNetSocket_t hSocketClient, void *pToken, uint32 uTokenLen )
|
||||
void CSpaceWarServer::OnClientBeginAuthentication( CSteamID steamIDClient, void *pToken, uint32 uTokenLen )
|
||||
{
|
||||
// First, check this isn't a duplicate and we already have a user logged on from the same ip/port combo
|
||||
for( uint32 i = 0; i < MAX_PLAYERS_PER_SERVER; ++i )
|
||||
{
|
||||
if ( m_rgClientData[i].m_hSocket == hSocketClient )
|
||||
if ( m_rgClientData[i].m_SteamIDUser == steamIDClient )
|
||||
{
|
||||
// We already logged them on... (should maybe tell them again incase they don't know?)
|
||||
return;
|
||||
@@ -261,7 +233,7 @@ void CSpaceWarServer::OnClientBeginAuthentication( SNetSocket_t hSocketClient, v
|
||||
if ( nPendingOrActivePlayerCount >= MAX_PLAYERS_PER_SERVER )
|
||||
{
|
||||
MsgServerFailAuthentication_t msg;
|
||||
BSendDataToClientOnSocket( hSocketClient, (char*)&msg, sizeof( msg ) );
|
||||
SteamGameServerNetworking()->SendP2PPacket( steamIDClient, &msg, sizeof( msg ), k_EP2PSendReliable );
|
||||
}
|
||||
|
||||
// If we get here there is room, add the player as pending
|
||||
@@ -269,20 +241,20 @@ void CSpaceWarServer::OnClientBeginAuthentication( SNetSocket_t hSocketClient, v
|
||||
{
|
||||
if ( !m_rgPendingClientData[i].m_bActive )
|
||||
{
|
||||
m_rgPendingClientData[i].m_hSocket = hSocketClient;
|
||||
m_rgPendingClientData[i].m_ulTickCountLastData = m_pGameEngine->GetGameTickCount();
|
||||
|
||||
// pull the IP address of the user from the socket
|
||||
uint32 unIPClient = 0;
|
||||
SteamGameServerNetworking()->GetSocketInfo( hSocketClient, NULL, NULL, &unIPClient, NULL );
|
||||
|
||||
#ifdef USE_GS_AUTH_API
|
||||
// authenticate the user with the Steam back-end servers
|
||||
m_rgPendingClientData[i].m_bActive = SteamGameServer()->SendUserConnectAndAuthenticate( unIPClient, pToken, uTokenLen, &m_rgPendingClientData[i].m_SteamIDUser );
|
||||
|
||||
// we use the server-seen IP address of the client as an extra bit of data for the authentication
|
||||
P2PSessionState_t p2pSessionState;
|
||||
SteamNetworking()->GetP2PSessionState( m_rgPendingClientData[i].m_SteamIDUser, &p2pSessionState );
|
||||
|
||||
m_rgPendingClientData[i].m_bActive = SteamGameServer()->SendUserConnectAndAuthenticate( p2pSessionState.m_nRemoteIP, pToken, uTokenLen, &m_rgPendingClientData[i].m_SteamIDUser );
|
||||
if ( !m_rgPendingClientData[i].m_bActive )
|
||||
{
|
||||
MsgServerFailAuthentication_t msg;
|
||||
BSendDataToClientOnSocket( hSocketClient, (char*)&msg, sizeof( msg ) );
|
||||
SteamGameServerNetworking()->SendP2PPacket( m_rgPendingClientData[i].m_SteamIDUser, &msg, sizeof( msg ), k_EP2PSendReliable );
|
||||
}
|
||||
break;
|
||||
#else
|
||||
@@ -317,7 +289,7 @@ void CSpaceWarServer::OnAuthCompleted( bool bAuthSuccessful, uint32 iPendingAuth
|
||||
#endif
|
||||
// Send a deny for the client, and zero out the pending data
|
||||
MsgServerFailAuthentication_t msg;
|
||||
BSendDataToClientOnSocket( m_rgPendingClientData[iPendingAuthIndex].m_hSocket, (char*)&msg, sizeof( msg ) );
|
||||
SteamGameServerNetworking()->SendP2PPacket( m_rgPendingClientData[iPendingAuthIndex].m_SteamIDUser, &msg, sizeof( msg ), k_EP2PSendReliable );
|
||||
memset( &m_rgPendingClientData[iPendingAuthIndex], 0, sizeof( ClientConnectionData_t ) );
|
||||
return;
|
||||
}
|
||||
@@ -511,13 +483,10 @@ void CSpaceWarServer::SetGameState( EServerGameState eState )
|
||||
//-----------------------------------------------------------------------------
|
||||
void CSpaceWarServer::ReceiveNetworkData()
|
||||
{
|
||||
if ( !m_hSocketServer )
|
||||
return;
|
||||
|
||||
char *pchRecvBuf = NULL;
|
||||
SNetSocket_t hSocketClient;
|
||||
uint32 cubMsgSize;
|
||||
while ( SteamGameServerNetworking()->IsDataAvailable( m_hSocketServer, &cubMsgSize, &hSocketClient ) )
|
||||
CSteamID steamIDRemote;
|
||||
while ( SteamGameServerNetworking()->IsP2PPacketAvailable( &cubMsgSize ) )
|
||||
{
|
||||
// free any previous receive buffer
|
||||
if ( pchRecvBuf )
|
||||
@@ -527,7 +496,7 @@ void CSpaceWarServer::ReceiveNetworkData()
|
||||
pchRecvBuf = (char *)malloc( cubMsgSize );
|
||||
|
||||
// see if there is any data waiting on the socket
|
||||
if ( !SteamGameServerNetworking()->RetrieveData( m_hSocketServer, pchRecvBuf, cubMsgSize, &cubMsgSize, &hSocketClient ) )
|
||||
if ( !SteamGameServerNetworking()->ReadP2PPacket( pchRecvBuf, cubMsgSize, &cubMsgSize, &steamIDRemote ) )
|
||||
break;
|
||||
|
||||
if ( cubMsgSize < sizeof( EMessage ) )
|
||||
@@ -550,7 +519,7 @@ void CSpaceWarServer::ReceiveNetworkData()
|
||||
msg.m_bIsVACSecure = SteamGameServer()->BSecure();
|
||||
#endif
|
||||
_snprintf( msg.m_rgchServerName, sizeof( msg.m_rgchServerName ), "%s", m_sServerName.c_str() );
|
||||
BSendDataToClientOnSocket( hSocketClient, (char*)&msg, sizeof( MsgServerSendInfo_t ) );
|
||||
SteamGameServerNetworking()->SendP2PPacket( steamIDRemote, &msg, sizeof( MsgServerSendInfo_t ), k_EP2PSendReliable );
|
||||
}
|
||||
break;
|
||||
case k_EMsgClientBeginAuthentication:
|
||||
@@ -562,9 +531,9 @@ void CSpaceWarServer::ReceiveNetworkData()
|
||||
}
|
||||
MsgClientBeginAuthentication_t *pMsg = (MsgClientBeginAuthentication_t*)pchRecvBuf;
|
||||
#ifdef USE_GS_AUTH_API
|
||||
OnClientBeginAuthentication( hSocketClient, &pMsg->m_rgchToken, pMsg->m_uTokenLen );
|
||||
OnClientBeginAuthentication( steamIDRemote, &pMsg->m_rgchToken, pMsg->m_uTokenLen );
|
||||
#else
|
||||
OnClientBeginAuthentication( hSocketClient, &pMsg->m_SteamID, 0 );
|
||||
OnClientBeginAuthentication( steamIDRemote, 0 );
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
@@ -580,7 +549,7 @@ void CSpaceWarServer::ReceiveNetworkData()
|
||||
bool bFound = false;
|
||||
for( uint32 i=0; i<MAX_PLAYERS_PER_SERVER; ++i )
|
||||
{
|
||||
if ( m_rgClientData[i].m_hSocket == hSocketClient )
|
||||
if ( m_rgClientData[i].m_SteamIDUser == steamIDRemote )
|
||||
{
|
||||
bFound = true;
|
||||
MsgClientSendLocalUpdate_t *pMsg = (MsgClientSendLocalUpdate_t*)pchRecvBuf;
|
||||
@@ -592,6 +561,13 @@ void CSpaceWarServer::ReceiveNetworkData()
|
||||
OutputDebugString( "Got a client data update, but couldn't find a matching client\n" );
|
||||
}
|
||||
break;
|
||||
case k_EMsgClientPing:
|
||||
{
|
||||
// send back a response
|
||||
MsgServerPingResponse_t msg;
|
||||
SteamGameServerNetworking()->SendP2PPacket( steamIDRemote, &msg, sizeof( msg ), k_EP2PSendUnreliable );
|
||||
}
|
||||
break;
|
||||
case k_EMsgClientLeavingServer:
|
||||
if ( cubMsgSize != sizeof( MsgClientLeavingServer_t ) )
|
||||
{
|
||||
@@ -602,7 +578,7 @@ void CSpaceWarServer::ReceiveNetworkData()
|
||||
bool bFound = false;
|
||||
for( uint32 i=0; i<MAX_PLAYERS_PER_SERVER; ++i )
|
||||
{
|
||||
if ( m_rgClientData[i].m_hSocket == hSocketClient )
|
||||
if ( m_rgClientData[i].m_SteamIDUser == steamIDRemote )
|
||||
{
|
||||
bFound = true;
|
||||
RemovePlayerFromServer( i );
|
||||
@@ -610,7 +586,7 @@ void CSpaceWarServer::ReceiveNetworkData()
|
||||
}
|
||||
|
||||
// Also check for pending connections that may match
|
||||
if ( m_rgPendingClientData[i].m_hSocket == hSocketClient )
|
||||
if ( m_rgPendingClientData[i].m_SteamIDUser == steamIDRemote )
|
||||
{
|
||||
#ifdef USE_GS_AUTH_API
|
||||
// Tell the GS the user is leaving the server
|
||||
@@ -638,9 +614,6 @@ void CSpaceWarServer::RunFrame()
|
||||
// Run any Steam Game Server API callbacks
|
||||
SteamGameServer_RunCallbacks();
|
||||
|
||||
// Get any new data off the network to begin with
|
||||
ReceiveNetworkData();
|
||||
|
||||
// Update our server details
|
||||
SendUpdatedServerDetailsToSteam();
|
||||
|
||||
@@ -1033,38 +1006,6 @@ void CSpaceWarServer::OnGSClientKick( GSClientKick_t *pGSClientKick )
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Returns the public IP address of the game server
|
||||
//-----------------------------------------------------------------------------
|
||||
uint32 CSpaceWarServer::GetIP()
|
||||
{
|
||||
if ( m_hSocketServer )
|
||||
{
|
||||
uint32 unIP;
|
||||
uint16 unPort;
|
||||
SteamGameServerNetworking()->GetListenSocketInfo( m_hSocketServer, &unIP, &unPort );
|
||||
return unIP;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Returns the public port of the game server
|
||||
//-----------------------------------------------------------------------------
|
||||
uint16 CSpaceWarServer::GetPort()
|
||||
{
|
||||
if ( m_hSocketServer )
|
||||
{
|
||||
uint32 unIP;
|
||||
uint16 unPort;
|
||||
SteamGameServerNetworking()->GetListenSocketInfo( m_hSocketServer, &unIP, &unPort );
|
||||
return unPort;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Returns the SteamID of the game server
|
||||
//-----------------------------------------------------------------------------
|
||||
@@ -1077,3 +1018,29 @@ CSteamID CSpaceWarServer::GetSteamID()
|
||||
return k_steamIDNonSteamGS;
|
||||
#endif
|
||||
}
|
||||
|
||||
void CSpaceWarServer::KickPlayerOffServer( CSteamID steamID )
|
||||
{
|
||||
uint32 uPlayerCount = 0;
|
||||
for( uint32 i=0; i < MAX_PLAYERS_PER_SERVER; ++i )
|
||||
{
|
||||
// If there is no ship, skip
|
||||
if ( !m_rgClientData[i].m_bActive )
|
||||
continue;
|
||||
|
||||
if ( m_rgClientData[i].m_SteamIDUser == steamID )
|
||||
{
|
||||
OutputDebugString( "Kicking player\n" );
|
||||
RemovePlayerFromServer( i );
|
||||
// send him a kick message
|
||||
MsgServerFailAuthentication_t msg;
|
||||
SteamGameServerNetworking()->SendP2PPacket( steamID, &msg, sizeof( msg ), k_EP2PSendReliable );
|
||||
}
|
||||
else
|
||||
{
|
||||
++uPlayerCount;
|
||||
}
|
||||
}
|
||||
m_uPlayerCount = uPlayerCount;
|
||||
|
||||
}
|
||||
|
||||
@@ -23,8 +23,6 @@ class CSpaceWarClient;
|
||||
struct ClientConnectionData_t
|
||||
{
|
||||
bool m_bActive; // Is this slot in use? Or is it available for new connections?
|
||||
|
||||
SNetSocket_t m_hSocket; // Socket to send data on to get to this client
|
||||
CSteamID m_SteamIDUser; // What is the steamid of the player?
|
||||
uint64 m_ulTickCountLastData; // What was the last time we got data from the player?
|
||||
};
|
||||
@@ -44,6 +42,9 @@ public:
|
||||
// Set game state
|
||||
void SetGameState( EServerGameState eState );
|
||||
|
||||
// Checks for any incoming network data, then dispatches it
|
||||
void ReceiveNetworkData();
|
||||
|
||||
// Reset player scores (occurs when starting a new game)
|
||||
void ResetScores();
|
||||
|
||||
@@ -53,10 +54,10 @@ public:
|
||||
// Checks various game objects for collisions and updates state appropriately if they have occurred
|
||||
void CheckForCollisions();
|
||||
|
||||
void KickPlayerOffServer( CSteamID steamID );
|
||||
|
||||
// data accessors
|
||||
bool IsConnectedToSteam() { return m_bConnectedToSteam; }
|
||||
uint32 GetIP();
|
||||
uint16 GetPort();
|
||||
CSteamID GetSteamID();
|
||||
|
||||
private:
|
||||
@@ -90,7 +91,8 @@ private:
|
||||
STEAM_GAMESERVER_CALLBACK( CSpaceWarServer, OnGSClientKick, GSClientKick_t, m_CallbackGSClientKick );
|
||||
|
||||
// client connection state
|
||||
STEAM_GAMESERVER_CALLBACK( CSpaceWarServer, OnSocketStatusCallback, SocketStatusCallback_t, m_CallbackSocketStatus );
|
||||
STEAM_GAMESERVER_CALLBACK( CSpaceWarServer, OnP2PSessionRequest, P2PSessionRequest_t, m_CallbackP2PSessionRequest );
|
||||
STEAM_GAMESERVER_CALLBACK( CSpaceWarServer, OnP2PSessionConnectFail, P2PSessionConnectFail_t, m_CallbackP2PSessionConnectFail );
|
||||
|
||||
// Function to tell Steam about our servers details
|
||||
void SendUpdatedServerDetailsToSteam();
|
||||
@@ -98,20 +100,14 @@ private:
|
||||
// Receive updates from client
|
||||
void OnReceiveClientUpdateData( uint32 uShipIndex, ClientSpaceWarUpdateData_t UpdateData );
|
||||
|
||||
// Checks for any incoming network data, then dispatches it
|
||||
void ReceiveNetworkData();
|
||||
|
||||
// Send data to a client at the given ship index
|
||||
bool BSendDataToClient( uint32 uShipIndex, char *pData, uint32 nSizeOfData );
|
||||
|
||||
// Send data to a client at the given pending index
|
||||
bool BSendDataToPendingClient( uint32 uShipIndex, char *pData, uint32 nSizeOfData );
|
||||
|
||||
// Send data to a client at a given address
|
||||
bool BSendDataToClientOnSocket( SNetSocket_t hSocket, char *pData, uint32 nSizeOfData );
|
||||
|
||||
// Connect a client, will send a success/failure response to the client
|
||||
void OnClientBeginAuthentication( SNetSocket_t hSocketClient, void *pToken, uint32 uTokenLen );
|
||||
void OnClientBeginAuthentication( CSteamID steamIDClient, void *pToken, uint32 uTokenLen );
|
||||
|
||||
// Handles authentication completing for a client
|
||||
void OnAuthCompleted( bool bAuthSuccess, uint32 iPendingAuthIndex );
|
||||
@@ -156,9 +152,6 @@ private:
|
||||
// Sun instance
|
||||
CSun *m_pSun;
|
||||
|
||||
// Server socket (which has been bound to our known port)
|
||||
SNetSocket_t m_hSocketServer;
|
||||
|
||||
// pointer to game engine instance we are running under
|
||||
CGameEngine *m_pGameEngine;
|
||||
|
||||
|
||||
@@ -226,6 +226,10 @@
|
||||
RelativePath=".\MainMenu.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\p2pauth.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\PhotonBeam.cpp"
|
||||
>
|
||||
@@ -316,6 +320,10 @@
|
||||
RelativePath=".\Messages.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\p2pauth.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\PhotonBeam.h"
|
||||
>
|
||||
|
||||
@@ -0,0 +1,413 @@
|
||||
//========= Copyright © 1996-2004, Valve LLC, All rights reserved. ============
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================
|
||||
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "SpaceWarClient.h"
|
||||
#include "p2pauth.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: constructor
|
||||
//-----------------------------------------------------------------------------
|
||||
CNetworkTransport::CNetworkTransport() :
|
||||
m_CallbackP2PSessionRequest( this, &CNetworkTransport::OnP2PSessionRequest ),
|
||||
m_CallbackP2PSessionConnectFail( this, &CNetworkTransport::OnP2PSessionConnectFail )
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: send ticket message to steamIDTo
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CNetworkTransport::SendTicket( CSteamID steamIDFrom, CSteamID steamIDTo, uint32 cubTicket, uint8 *pubTicket )
|
||||
{
|
||||
MsgP2PSendingTicket_t msg;
|
||||
msg.m_uTokenLen = cubTicket;
|
||||
memcpy( msg.m_rgchToken, pubTicket, cubTicket );
|
||||
msg.m_SteamID = steamIDFrom;
|
||||
return SendNetMessage( steamIDTo, (void*)&msg, sizeof( msg ) );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: actual implementation
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CNetworkTransport::SendNetMessage( CSteamID steamIDTo, void *pMessage, int cubMessage )
|
||||
{
|
||||
return SteamNetworking()->SendP2PPacket( steamIDTo, pMessage, cubMessage, k_EP2PSendReliable );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: close connection to steamID
|
||||
//-----------------------------------------------------------------------------
|
||||
void CNetworkTransport::CloseConnection( CSteamID steamID )
|
||||
{
|
||||
SteamNetworking()->CloseP2PSessionWithUser( steamID );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: another user has sent us a packet - do we accept?
|
||||
//-----------------------------------------------------------------------------
|
||||
void CNetworkTransport::OnP2PSessionRequest( P2PSessionRequest_t *pP2PSessionRequest )
|
||||
{
|
||||
// always accept packets
|
||||
// the packet itself will come through when you call SteamNetworking()->ReadP2PPacket()
|
||||
SteamNetworking()->AcceptP2PSessionWithUser( pP2PSessionRequest->m_steamIDRemote );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: another user has sent us a packet - do we accept?
|
||||
//-----------------------------------------------------------------------------
|
||||
void CNetworkTransport::OnP2PSessionConnectFail( P2PSessionConnectFail_t *pP2PSessionConnectFail )
|
||||
{
|
||||
// we've sent a packet to the user, but it never got through
|
||||
// we can just use the normal timeout
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: constructor
|
||||
//-----------------------------------------------------------------------------
|
||||
CP2PAuthPlayer::CP2PAuthPlayer( CGameEngine *pGameEngine, CNetworkTransport *pNetworkTransport ):m_CallbackBeginAuthResponse( this, &CP2PAuthPlayer::OnBeginAuthResponse )
|
||||
{
|
||||
m_pGameEngine = pGameEngine;
|
||||
m_pNetworkTransport = pNetworkTransport;
|
||||
m_bSentTicket = false;
|
||||
m_bSubmittedHisTicket = false;
|
||||
m_bHaveAnswer = false;
|
||||
m_ulConnectTime = GetGameTimeInSeconds();
|
||||
m_cubTicketIGaveThisUser = 0;
|
||||
m_cubTicketHeGaveMe = 0;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: destructor
|
||||
//-----------------------------------------------------------------------------
|
||||
CP2PAuthPlayer::~CP2PAuthPlayer()
|
||||
{
|
||||
EndGame();
|
||||
m_pNetworkTransport->CloseConnection( SteamUser()->GetSteamID() );
|
||||
m_pNetworkTransport = NULL;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: the steam backend has responded
|
||||
//-----------------------------------------------------------------------------
|
||||
void CP2PAuthPlayer::OnBeginAuthResponse( ValidateAuthTicketResponse_t *pCallback )
|
||||
{
|
||||
if ( m_steamID == pCallback->m_SteamID )
|
||||
{
|
||||
char rgch[128];
|
||||
sprintf( rgch, "P2P:: Received steam response for account=%d\n", m_steamID.GetAccountID() );
|
||||
OutputDebugStringA( rgch );
|
||||
m_ulAnswerTime = GetGameTimeInSeconds();
|
||||
m_bHaveAnswer = true;
|
||||
m_eAuthSessionResponse = pCallback->m_eAuthSessionResponse;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: internal implementation
|
||||
//-----------------------------------------------------------------------------
|
||||
void CP2PAuthPlayer::InitPlayer( CSteamID steamID )
|
||||
{
|
||||
m_steamID = steamID;
|
||||
m_bSentTicket = false;
|
||||
m_bSubmittedHisTicket = false;
|
||||
m_bHaveAnswer = false;
|
||||
m_ulConnectTime = GetGameTimeInSeconds();
|
||||
m_cubTicketIGaveThisUser = 0;
|
||||
m_cubTicketHeGaveMe = 0;
|
||||
}
|
||||
|
||||
void CP2PAuthPlayer::StartAuthPlayer()
|
||||
{
|
||||
// send him the ticket if we havent yet
|
||||
if ( m_cubTicketIGaveThisUser == 0 )
|
||||
{
|
||||
m_hAuthTicketIGaveThisUser = SteamUser()->GetAuthSessionTicket( m_rgubTicketIGaveThisUser, sizeof( m_rgubTicketIGaveThisUser ), &m_cubTicketIGaveThisUser );
|
||||
}
|
||||
// sample has no retry here
|
||||
m_bSentTicket = m_pNetworkTransport->SendTicket( SteamUser()->GetSteamID(), m_steamID, m_cubTicketIGaveThisUser, m_rgubTicketIGaveThisUser );
|
||||
// start a timer on this, if we dont get a ticket back within reasonable time, mark him timed out
|
||||
m_ulTicketTime = GetGameTimeInSeconds();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: is this auth ok?
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CP2PAuthPlayer::BIsAuthOk()
|
||||
{
|
||||
if ( m_steamID.IsValid() )
|
||||
{
|
||||
// Timeout if we fail to establish communication with this player
|
||||
if ( !m_bSentTicket && !m_bSubmittedHisTicket )
|
||||
{
|
||||
if ( GetGameTimeInSeconds() - m_ulConnectTime > 30 )
|
||||
{
|
||||
char rgch[128];
|
||||
sprintf( rgch, "P2P:: Nothing received for account=%d\n", m_steamID.GetAccountID() );
|
||||
OutputDebugStringA( rgch );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// first ticket check: if i submitted his ticket - was it good?
|
||||
if ( m_bSubmittedHisTicket && m_eBeginAuthSessionResult != k_EBeginAuthSessionResultOK )
|
||||
{
|
||||
char rgch[128];
|
||||
sprintf( rgch, "P2P:: Ticket from account=%d was bad\n", m_steamID.GetAccountID() );
|
||||
OutputDebugStringA( rgch );
|
||||
return false;
|
||||
}
|
||||
// second ticket check: if the steam backend replied, was that good?
|
||||
if ( m_bHaveAnswer && m_eAuthSessionResponse != k_EAuthSessionResponseOK )
|
||||
{
|
||||
char rgch[128];
|
||||
sprintf( rgch, "P2P:: Steam response for account=%d was bad\n", m_steamID.GetAccountID() );
|
||||
OutputDebugStringA( rgch );
|
||||
return false;
|
||||
}
|
||||
// last: if i sent him a ticket and he has not reciprocated, time out after 30 sec
|
||||
if ( m_bSentTicket && !m_bSubmittedHisTicket )
|
||||
{
|
||||
if ( GetGameTimeInSeconds() - m_ulTicketTime > 30 )
|
||||
{
|
||||
char rgch[128];
|
||||
sprintf( rgch, "P2P:: No ticket received for account=%d\n", m_steamID.GetAccountID() );
|
||||
OutputDebugStringA( rgch );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: the game engine is telling us about someone who left the game
|
||||
//-----------------------------------------------------------------------------
|
||||
void CP2PAuthPlayer::EndGame()
|
||||
{
|
||||
if ( m_bSentTicket )
|
||||
{
|
||||
SteamUser()->CancelAuthTicket( m_hAuthTicketIGaveThisUser );
|
||||
m_bSentTicket = false;
|
||||
}
|
||||
if ( m_bSubmittedHisTicket )
|
||||
{
|
||||
SteamUser()->EndAuthSession( m_steamID );
|
||||
m_bSubmittedHisTicket = false;
|
||||
}
|
||||
if ( m_steamID.IsValid() )
|
||||
m_pNetworkTransport->CloseConnection( m_steamID );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: message handler
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CP2PAuthPlayer::HandleMessage( EMessage eMsg, void *pMessage )
|
||||
{
|
||||
switch ( eMsg )
|
||||
{
|
||||
// message from another player providing his ticket
|
||||
case k_EMsgP2PSendingTicket:
|
||||
{
|
||||
MsgP2PSendingTicket_t *pMsg = (MsgP2PSendingTicket_t*)pMessage;
|
||||
// is this message for me?
|
||||
if ( pMsg->m_SteamID != m_steamID )
|
||||
return false;
|
||||
m_cubTicketHeGaveMe = pMsg->m_uTokenLen;
|
||||
memcpy( m_rgubTicketHeGaveMe, pMsg->m_rgchToken, m_cubTicketHeGaveMe );
|
||||
m_eBeginAuthSessionResult = SteamUser()->BeginAuthSession( m_rgubTicketHeGaveMe, m_cubTicketHeGaveMe, m_steamID );
|
||||
m_bSubmittedHisTicket = true;
|
||||
char rgch[128];
|
||||
sprintf( rgch, "P2P:: ReceivedTicket from account=%d \n", m_steamID.GetAccountID() );
|
||||
OutputDebugStringA( rgch );
|
||||
if ( !m_bSentTicket )
|
||||
StartAuthPlayer();
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
{
|
||||
OutputDebugStringA( "P2P:: Received unknown message on our listen socket\n" );
|
||||
break;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: utility wrapper
|
||||
//-----------------------------------------------------------------------------
|
||||
CSteamID CP2PAuthPlayer::GetSteamID()
|
||||
{
|
||||
return SteamUser()->GetSteamID();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: constructor
|
||||
//-----------------------------------------------------------------------------
|
||||
CP2PAuthedGame::CP2PAuthedGame( CGameEngine *pGameEngine )
|
||||
{
|
||||
m_pNetworkTransport = new CNetworkTransport;
|
||||
m_pGameEngine = pGameEngine;
|
||||
// no players yet
|
||||
for ( int i = 0; i < MAX_PLAYERS_PER_SERVER; i++ )
|
||||
{
|
||||
m_rgpP2PAuthPlayer[i] = NULL;
|
||||
}
|
||||
// no queued messages
|
||||
for ( int i = 0; i < MAX_PLAYERS_PER_SERVER; i++ )
|
||||
{
|
||||
m_rgpQueuedMessage[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: game with this player is over
|
||||
//-----------------------------------------------------------------------------
|
||||
void CP2PAuthedGame::PlayerDisconnect( int iSlot )
|
||||
{
|
||||
if ( m_rgpP2PAuthPlayer[iSlot] )
|
||||
{
|
||||
m_rgpP2PAuthPlayer[iSlot]->EndGame();
|
||||
delete m_rgpP2PAuthPlayer[iSlot];
|
||||
m_rgpP2PAuthPlayer[iSlot] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: game is over, disconnect everyone
|
||||
//-----------------------------------------------------------------------------
|
||||
void CP2PAuthedGame::EndGame()
|
||||
{
|
||||
for ( int i = 0; i < MAX_PLAYERS_PER_SERVER; i++ )
|
||||
{
|
||||
if ( m_rgpP2PAuthPlayer[i] )
|
||||
{
|
||||
m_rgpP2PAuthPlayer[i]->EndGame();
|
||||
delete m_rgpP2PAuthPlayer[i];
|
||||
m_rgpP2PAuthPlayer[i] = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: initialize player
|
||||
//-----------------------------------------------------------------------------
|
||||
void CP2PAuthedGame::InternalInitPlayer( int iSlot, CSteamID steamID, bool bStartAuthProcess )
|
||||
{
|
||||
char rgch[128];
|
||||
sprintf( rgch, "P2P:: StartAuthPlayer slot=%d account=%d \n", iSlot, steamID.GetAccountID() );
|
||||
OutputDebugStringA( rgch );
|
||||
m_rgpP2PAuthPlayer[iSlot] = new CP2PAuthPlayer( m_pGameEngine, m_pNetworkTransport );
|
||||
m_rgpP2PAuthPlayer[iSlot]->InitPlayer( steamID );
|
||||
if ( bStartAuthProcess )
|
||||
m_rgpP2PAuthPlayer[iSlot]->StartAuthPlayer();
|
||||
|
||||
// check our queued messages list to see if this guys ticket message arrived before we noticed him
|
||||
for ( int i = 0; i < MAX_PLAYERS_PER_SERVER; i++ )
|
||||
{
|
||||
if ( m_rgpQueuedMessage[i] != NULL )
|
||||
{
|
||||
if ( m_rgpP2PAuthPlayer[i]->HandleMessage( k_EMsgP2PSendingTicket, m_rgpQueuedMessage[i] ) )
|
||||
{
|
||||
OutputDebugStringA( "P2P:: Consumed queued message \n" );
|
||||
free( m_rgpQueuedMessage[i] );
|
||||
m_rgpQueuedMessage[i] = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: game host register this player, we wait for this player
|
||||
// to start the auth process by sending us his ticket, then we will
|
||||
// reciprocate
|
||||
//-----------------------------------------------------------------------------
|
||||
void CP2PAuthedGame::RegisterPlayer( int iSlot, CSteamID steamID )
|
||||
{
|
||||
if ( iSlot < MAX_PLAYERS_PER_SERVER )
|
||||
InternalInitPlayer( iSlot, steamID, false );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: start the auth process by sending ticket to this player
|
||||
// he will reciprocate
|
||||
//-----------------------------------------------------------------------------
|
||||
void CP2PAuthedGame::StartAuthPlayer( int iSlot, CSteamID steamID )
|
||||
{
|
||||
if ( iSlot < MAX_PLAYERS_PER_SERVER )
|
||||
InternalInitPlayer( iSlot, steamID, true );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: message handler
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CP2PAuthedGame::HandleMessage( EMessage eMsg, void *pMessage )
|
||||
{
|
||||
switch ( eMsg )
|
||||
{
|
||||
// message from another player providing his ticket
|
||||
case k_EMsgP2PSendingTicket:
|
||||
{
|
||||
MsgP2PSendingTicket_t *pMsg = (MsgP2PSendingTicket_t*)pMessage;
|
||||
for ( int i = 0; i < MAX_PLAYERS_PER_SERVER; i++ )
|
||||
{
|
||||
if ( m_rgpP2PAuthPlayer[i] )
|
||||
{
|
||||
if ( m_rgpP2PAuthPlayer[i]->HandleMessage( eMsg, pMessage ) )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
// if we dont have the player in our list yet, lets queue the message and assume he will show up soon
|
||||
OutputDebugStringA( "P2P:: HandleMessage queueing message \n" );
|
||||
for ( int i = 0; i < MAX_PLAYERS_PER_SERVER; i++ )
|
||||
{
|
||||
if ( m_rgpQueuedMessage[i] == NULL )
|
||||
{
|
||||
m_rgpQueuedMessage[i] = pMsg;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
OutputDebugStringA( "Received unknown message on our listen socket\n" );
|
||||
break;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: utility wrapper
|
||||
//-----------------------------------------------------------------------------
|
||||
CSteamID CP2PAuthedGame::GetSteamID()
|
||||
{
|
||||
return SteamUser()->GetSteamID();
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
//========= Copyright © 1996-2004, Valve LLC, All rights reserved. ============
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================
|
||||
|
||||
|
||||
|
||||
const int k_cMaxSockets = 16;
|
||||
class CP2PAuthPlayer;
|
||||
class CNetworkTransport;
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: one player p2p auth process state machine
|
||||
//-----------------------------------------------------------------------------
|
||||
class CP2PAuthPlayer
|
||||
{
|
||||
public:
|
||||
CP2PAuthPlayer( CGameEngine *pGameEngine, CNetworkTransport *pNetworkTransport );
|
||||
~CP2PAuthPlayer();
|
||||
void EndGame();
|
||||
void InitPlayer( CSteamID steamID );
|
||||
void StartAuthPlayer();
|
||||
bool BIsAuthOk();
|
||||
virtual bool HandleMessage( EMessage eMsg, void *pMessage );
|
||||
virtual CSteamID GetSteamID();
|
||||
|
||||
STEAM_CALLBACK( CP2PAuthPlayer, OnBeginAuthResponse, ValidateAuthTicketResponse_t, m_CallbackBeginAuthResponse );
|
||||
|
||||
CSteamID m_steamID;
|
||||
private:
|
||||
uint64 GetGameTimeInSeconds()
|
||||
{
|
||||
return m_pGameEngine->GetGameTickCount()/1000;
|
||||
}
|
||||
bool m_bSentTicket;
|
||||
bool m_bSubmittedHisTicket;
|
||||
bool m_bHaveAnswer;
|
||||
uint64 m_ulConnectTime;
|
||||
uint64 m_ulTicketTime;
|
||||
uint64 m_ulAnswerTime;
|
||||
uint32 m_cubTicketIGaveThisUser;
|
||||
uint8 m_rgubTicketIGaveThisUser[1024];
|
||||
uint32 m_cubTicketHeGaveMe;
|
||||
uint8 m_rgubTicketHeGaveMe[1024];
|
||||
HAuthTicket m_hAuthTicketIGaveThisUser;
|
||||
EBeginAuthSessionResult m_eBeginAuthSessionResult;
|
||||
EAuthSessionResponse m_eAuthSessionResponse;
|
||||
|
||||
CNetworkTransport *m_pNetworkTransport;
|
||||
CGameEngine *m_pGameEngine;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: simple wrapper for multiple players
|
||||
//-----------------------------------------------------------------------------
|
||||
class CP2PAuthedGame
|
||||
{
|
||||
public:
|
||||
CP2PAuthedGame( CGameEngine *pGameEngine );
|
||||
void PlayerDisconnect( int iSlot );
|
||||
void EndGame();
|
||||
void StartAuthPlayer( int iSlot, CSteamID steamID );
|
||||
void RegisterPlayer( int iSlot, CSteamID steamID );
|
||||
virtual bool HandleMessage( EMessage eMsg, void *pMessage );
|
||||
virtual CSteamID GetSteamID();
|
||||
void InternalInitPlayer( int iSlot, CSteamID steamID, bool bStartAuthProcess );
|
||||
|
||||
CP2PAuthPlayer *m_rgpP2PAuthPlayer[MAX_PLAYERS_PER_SERVER];
|
||||
MsgP2PSendingTicket_t *m_rgpQueuedMessage[MAX_PLAYERS_PER_SERVER];
|
||||
CGameEngine *m_pGameEngine;
|
||||
CNetworkTransport *m_pNetworkTransport;
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: trivial wrapper on network messaging
|
||||
//-----------------------------------------------------------------------------
|
||||
class CNetworkTransport
|
||||
{
|
||||
public:
|
||||
CNetworkTransport();
|
||||
|
||||
bool SendTicket( CSteamID steamIDFrom, CSteamID steamIDTo, uint32 cubTicket, uint8 *pubTicket );
|
||||
void CloseConnection( CSteamID steamID );
|
||||
|
||||
bool SendNetMessage( CSteamID steamIDTo, void *pMessage, int cubMessage );
|
||||
|
||||
STEAM_CALLBACK( CNetworkTransport, OnP2PSessionRequest, P2PSessionRequest_t, m_CallbackP2PSessionRequest );
|
||||
STEAM_CALLBACK( CNetworkTransport, OnP2PSessionConnectFail, P2PSessionConnectFail_t, m_CallbackP2PSessionConnectFail );
|
||||
};
|
||||
@@ -44,7 +44,7 @@
|
||||
#include <tchar.h>
|
||||
|
||||
// Winsock
|
||||
#include <winsock.h>
|
||||
#include <winsock2.h>
|
||||
#pragma comment(lib, "ws2_32.lib" )
|
||||
|
||||
// d3d header files
|
||||
@@ -59,4 +59,15 @@ typedef __int64 int64;
|
||||
typedef unsigned __int64 uint64;
|
||||
|
||||
// steam api header file
|
||||
#include "steam/steam_api.h"
|
||||
#include "steam/steam_api.h"
|
||||
|
||||
#ifdef STEAM_CEG
|
||||
// Steam DRM header file
|
||||
#include "cegclient.h"
|
||||
#else
|
||||
#define Steamworks_InitCEGLibrary() (true)
|
||||
#define Steamworks_TermCEGLibrary() (true)
|
||||
#define Steamworks_TestSecret() (true)
|
||||
#define Steamworks_SelfCheck() (true)
|
||||
#endif
|
||||
|
||||
|
||||
Binary file not shown.
@@ -13,6 +13,7 @@
|
||||
#include "isteamclient.h"
|
||||
#include "steamclientpublic.h"
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: set of relationships to other users
|
||||
//-----------------------------------------------------------------------------
|
||||
@@ -163,7 +164,7 @@ public:
|
||||
virtual void SetInGameVoiceSpeaking( CSteamID steamIDUser, bool bSpeaking ) = 0;
|
||||
|
||||
// activates the game overlay, with an optional dialog to open
|
||||
// valid options are "Friends", "Community", "Players", "Settings", "LobbyInvite", "OfficialGameGroup"
|
||||
// valid options are "Friends", "Community", "Players", "Settings", "LobbyInvite", "OfficialGameGroup", "Stats", "Achievements"
|
||||
virtual void ActivateGameOverlay( const char *pchDialog ) = 0;
|
||||
|
||||
// activates game overlay to a specific place
|
||||
|
||||
@@ -102,9 +102,18 @@ public:
|
||||
// connect to
|
||||
virtual uint32 GetPublicIP() = 0;
|
||||
|
||||
// Sets a string defining the "gamedata" for this server, this is optional, but if it is set
|
||||
// it allows users to filter in the matchmaking/server-browser interfaces based on the value
|
||||
// don't set this unless it actually changes, its only uploaded to the master once (when
|
||||
// acknowledged)
|
||||
virtual void SetGameData( const char *pchGameData) = 0;
|
||||
|
||||
// After receiving a user's authentication data, and passing it to SendUserConnectAndAuthenticate, use this function
|
||||
// to determine if the user owns downloadable content specified by the provided AppID.
|
||||
virtual EUserHasLicenseForAppResult UserHasLicenseForApp( CSteamID steamID, AppId_t appID ) = 0;
|
||||
};
|
||||
|
||||
#define STEAMGAMESERVER_INTERFACE_VERSION "SteamGameServer008"
|
||||
#define STEAMGAMESERVER_INTERFACE_VERSION "SteamGameServer009"
|
||||
|
||||
// game server flags
|
||||
const uint32 k_unServerFlagNone = 0x00;
|
||||
|
||||
@@ -16,15 +16,17 @@
|
||||
#include "isteamclient.h"
|
||||
#include "isteamfriends.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Functions for match making services for clients to get to favorites
|
||||
//-----------------------------------------------------------------------------
|
||||
// lobby type description
|
||||
enum ELobbyType
|
||||
{
|
||||
k_ELobbyTypeFriendsOnly = 1, // shows for friends or invitees, but not in lobby list
|
||||
k_ELobbyTypePublic = 2, // visible for friends and in lobby list
|
||||
k_ELobbyTypeInvisible = 3, // returned by search, but not visible to other friends
|
||||
// useful if you want a user in two lobbies, for example matching groups together
|
||||
// a user can be in only one regular lobby, and up to two invisible lobbies
|
||||
};
|
||||
|
||||
// lobby search filter tools
|
||||
enum ELobbyComparison
|
||||
{
|
||||
k_ELobbyComparisonEqualToOrLessThan = -2,
|
||||
@@ -32,8 +34,10 @@ enum ELobbyComparison
|
||||
k_ELobbyComparisonEqual = 0,
|
||||
k_ELobbyComparisonGreaterThan = 1,
|
||||
k_ELobbyComparisonEqualToOrGreaterThan = 2,
|
||||
k_ELobbyComparisonNotEqual = 3,
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Functions for match making services for clients to get to favorites
|
||||
// and to operate on game lobbies.
|
||||
@@ -91,11 +95,13 @@ public:
|
||||
// filters for lobbies
|
||||
// this needs to be called before RequestLobbyList() to take effect
|
||||
// these are cleared on each call to RequestLobbyList()
|
||||
virtual void AddRequestLobbyListFilter( const char *pchKeyToMatch, const char *pchValueToMatch ) = 0;
|
||||
virtual void AddRequestLobbyListStringFilter( const char *pchKeyToMatch, const char *pchValueToMatch, ELobbyComparison eComparisonType ) = 0;
|
||||
// numerical comparison
|
||||
virtual void AddRequestLobbyListNumericalFilter( const char *pchKeyToMatch, int nValueToMatch, int nComparisonType ) = 0;
|
||||
virtual void AddRequestLobbyListNumericalFilter( const char *pchKeyToMatch, int nValueToMatch, ELobbyComparison eComparisonType ) = 0;
|
||||
// returns results closest to the specified value. Multiple near filters can be added, with early filters taking precedence
|
||||
virtual void AddRequestLobbyListNearValueFilter( const char *pchKeyToMatch, int nValueToBeCloseTo ) = 0;
|
||||
// returns only lobbies with the specified number of slots available
|
||||
virtual void AddRequestLobbyListFilterSlotsAvailable( int nSlotsAvailable ) = 0;
|
||||
|
||||
// returns the CSteamID of a lobby, as retrieved by a RequestLobbyList call
|
||||
// should only be called after a LobbyMatchList_t callback is received
|
||||
@@ -109,7 +115,7 @@ public:
|
||||
// this is an asynchronous request
|
||||
// results will be returned by LobbyCreated_t callback and call result; lobby is joined & ready to use at this pointer
|
||||
// a LobbyEnter_t callback will also be received (since the local user is joining their own lobby)
|
||||
virtual SteamAPICall_t CreateLobby( ELobbyType eLobbyType ) = 0;
|
||||
virtual SteamAPICall_t CreateLobby( ELobbyType eLobbyType, int cMaxMembers ) = 0;
|
||||
|
||||
// Joins an existing lobby
|
||||
// this is an asynchronous request
|
||||
@@ -125,6 +131,8 @@ public:
|
||||
// the target user will receive a LobbyInvite_t callback
|
||||
// will return true if the invite is successfully sent, whether or not the target responds
|
||||
// returns false if the local user is not connected to the Steam servers
|
||||
// if the other user clicks the join link, a GameLobbyJoinRequested_t will be posted if the user is in-game,
|
||||
// or if the game isn't running yet the game will be launched with the parameter +connect_lobby <64-bit lobby id>
|
||||
virtual bool InviteUserToLobby( CSteamID steamIDLobby, CSteamID steamIDInvitee ) = 0;
|
||||
|
||||
// Lobby iteration, for viewing details of users in a lobby
|
||||
@@ -149,7 +157,16 @@ public:
|
||||
// other users in the lobby will receive notification of the lobby data change via a LobbyDataUpdate_t callback
|
||||
virtual bool SetLobbyData( CSteamID steamIDLobby, const char *pchKey, const char *pchValue ) = 0;
|
||||
|
||||
// As above, but gets per-user data for someone in this lobby
|
||||
// returns the number of metadata keys set on the specified lobby
|
||||
virtual int GetLobbyDataCount( CSteamID steamIDLobby ) = 0;
|
||||
|
||||
// returns a lobby metadata key/values pair by index, of range [0, GetLobbyDataCount())
|
||||
virtual bool GetLobbyDataByIndex( CSteamID steamIDLobby, int iLobbyData, char *pchKey, int cchKeyBufferSize, char *pchValue, int cchValueBufferSize ) = 0;
|
||||
|
||||
// removes a metadata key from the lobby
|
||||
virtual bool DeleteLobbyData( CSteamID steamIDLobby, const char *pchKey ) = 0;
|
||||
|
||||
// Gets per-user metadata for someone in this lobby
|
||||
virtual const char *GetLobbyMemberData( CSteamID steamIDLobby, CSteamID steamIDUser, const char *pchKey ) = 0;
|
||||
// Sets per-user metadata (for the local user implicitly)
|
||||
virtual void SetLobbyMemberData( CSteamID steamIDLobby, const char *pchKey, const char *pchValue ) = 0;
|
||||
@@ -188,16 +205,25 @@ public:
|
||||
virtual int GetLobbyMemberLimit( CSteamID steamIDLobby ) = 0;
|
||||
|
||||
// updates which type of lobby it is
|
||||
// only lobbies that are k_ELobbyTypePublic will be returned by RequestLobbyList() calls
|
||||
// only lobbies that are k_ELobbyTypePublic or k_ELobbyTypeInvisible, and are set to joinable, will be returned by RequestLobbyList() calls
|
||||
virtual bool SetLobbyType( CSteamID steamIDLobby, ELobbyType eLobbyType ) = 0;
|
||||
|
||||
// sets whether or not a lobby is joinable - defaults to true for a new lobby
|
||||
// if set to false, no user can join, even if they are a friend or have been invited
|
||||
virtual bool SetLobbyJoinable( CSteamID steamIDLobby, bool bLobbyJoinable ) = 0;
|
||||
|
||||
// returns the current lobby owner
|
||||
// you must be a member of the lobby to access this
|
||||
// there always one lobby owner - if the current owner leaves, another user will become the owner
|
||||
// it is possible (bur rare) to join a lobby just as the owner is leaving, thus entering a lobby with self as the owner
|
||||
virtual CSteamID GetLobbyOwner( CSteamID steamIDLobby ) = 0;
|
||||
|
||||
// changes who the lobby owner is
|
||||
// you must be the lobby owner for this to succeed, and steamIDNewOwner must be in the lobby
|
||||
// after completion, the local user will no longer be the owner
|
||||
virtual bool SetLobbyOwner( CSteamID steamIDLobby, CSteamID steamIDNewOwner ) = 0;
|
||||
};
|
||||
#define STEAMMATCHMAKING_INTERFACE_VERSION "SteamMatchMaking006"
|
||||
#define STEAMMATCHMAKING_INTERFACE_VERSION "SteamMatchMaking007"
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@@ -432,7 +458,9 @@ struct FavoritesListChanged_t
|
||||
// Purpose: Someone has invited you to join a Lobby
|
||||
// normally you don't need to do anything with this, since
|
||||
// the Steam UI will also display a '<user> has invited you to the lobby, join?' dialog
|
||||
// if the user outside a game chooses to join, your game will be launched with the parameter "+connect_lobby <64-bit lobby id>"
|
||||
//
|
||||
// if the user outside a game chooses to join, your game will be launched with the parameter "+connect_lobby <64-bit lobby id>",
|
||||
// or with the callback GameLobbyJoinRequested_t if they're already in-game
|
||||
//-----------------------------------------------------------------------------
|
||||
struct LobbyInvite_t
|
||||
{
|
||||
@@ -532,29 +560,6 @@ struct LobbyMatchList_t
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Called when the lobby is being forcefully closed
|
||||
// lobby details functions will no longer be updated
|
||||
//-----------------------------------------------------------------------------
|
||||
struct LobbyClosing_t
|
||||
{
|
||||
enum { k_iCallback = k_iSteamMatchmakingCallbacks + 11 };
|
||||
uint64 m_ulSteamIDLobby; // Lobby
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Called when the local user has been kicked from the lobby
|
||||
// lobby details functions will no longer be updated
|
||||
//-----------------------------------------------------------------------------
|
||||
struct LobbyKicked_t
|
||||
{
|
||||
enum { k_iCallback = k_iSteamMatchmakingCallbacks + 12 };
|
||||
uint64 m_ulSteamIDLobby; // Lobby
|
||||
uint64 m_ulSteamIDAdmin; // User who kicked you
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Result of our request to create a Lobby
|
||||
// m_eResult == k_EResultOK on success
|
||||
|
||||
@@ -13,12 +13,67 @@
|
||||
#include "steamtypes.h"
|
||||
#include "steamclientpublic.h"
|
||||
|
||||
|
||||
// list of possible errors returned by SendP2PPacket() API
|
||||
// these will be posted in the P2PSessionConnectFail_t callback
|
||||
enum EP2PSessionError
|
||||
{
|
||||
k_EP2PSessionErrorNone = 0,
|
||||
k_EP2PSessionErrorNotRunningApp = 1, // target is not running the same game
|
||||
k_EP2PSessionErrorNoRightsToApp = 2, // local user doesn't own the app that is running
|
||||
k_EP2PSessionErrorDestinationNotLoggedIn = 3, // target user isn't connected to Steam
|
||||
k_EP2PSessionErrorTimeout = 4, // target isn't responding, perhaps not calling AcceptP2PSessionWithUser()
|
||||
|
||||
};
|
||||
|
||||
// SendP2PPacket() send types
|
||||
// Typically k_EP2PSendUnreliable is what you want for UDP-like packets, k_EP2PSendReliable for TCP-like packets
|
||||
enum EP2PSend
|
||||
{
|
||||
// Basic UDP send. Packets can't be bigger than 1200 bytes (your typical MTU size). Can be lost, or arrive out of order (rare).
|
||||
// The sending API does have some knowledge of the underlying connection, so if there is no NAT-traversal accomplished or
|
||||
// there is a recognized adjustment happening on the connection, the packet will be batched until the connection is open again.
|
||||
k_EP2PSendUnreliable = 0,
|
||||
|
||||
// As above, but if the underlying p2p connection isn't yet established the packet will just be thrown away. Using this on the first
|
||||
// packet sent to a remote host almost guarantees the packet will be dropped.
|
||||
// This is only really useful for kinds of data that should never buffer up, i.e. voice payload packets
|
||||
k_EP2PSendUnreliableNoDelay = 1,
|
||||
|
||||
// Reliable message send. Can send up to 1MB of data in a single message.
|
||||
// Does fragmentation/re-assembly of messages under the hood, as well as a sliding window for efficient sends of large chunks of data.
|
||||
k_EP2PSendReliable = 2,
|
||||
|
||||
// As above, but applies the Nagle algorithm to the send - sends will accumulate
|
||||
// until the current MTU size (typically ~1200 bytes, but can change) or ~200ms has passed (Nagle algorithm).
|
||||
// Useful if you want to send a set of smaller messages but have the coalesced into a single packet
|
||||
// Since the reliable stream is all ordered, you can do several small message sends with k_EP2PSendReliableWithBuffering and then
|
||||
// do a normal k_EP2PSendReliable to force all the buffered data to be sent.
|
||||
k_EP2PSendReliableWithBuffering = 3,
|
||||
|
||||
};
|
||||
|
||||
|
||||
// connection state to a specified user, returned by GetP2PSessionState()
|
||||
// this is under-the-hood info about what's going on with a SendP2PPacket(), shouldn't be needed except for debuggin
|
||||
struct P2PSessionState_t
|
||||
{
|
||||
uint8 m_bConnectionActive; // true if we've got an active open connection
|
||||
uint8 m_bConnecting; // true if we're currently trying to establish a connection
|
||||
uint8 m_eP2PSessionError; // last error recorded (see enum above)
|
||||
uint8 m_bUsingRelay; // true if it's going through a relay server (TURN)
|
||||
int32 m_nBytesQueuedForSend;
|
||||
int32 m_nPacketsQueuedForSend;
|
||||
uint32 m_nRemoteIP; // potential IP:Port of remote host. Could be TURN server.
|
||||
uint16 m_nRemotePort; // Only exists for compatibility with older authentication api's
|
||||
};
|
||||
|
||||
|
||||
// handle to a socket
|
||||
typedef uint32 SNetSocket_t;
|
||||
typedef uint32 SNetListenSocket_t;
|
||||
typedef uint32 SNetSocket_t; // CreateP2PConnectionSocket()
|
||||
typedef uint32 SNetListenSocket_t; // CreateListenSocket()
|
||||
|
||||
|
||||
// connection progress indicators
|
||||
// connection progress indicators, used by CreateP2PConnectionSocket()
|
||||
enum ESNetSocketState
|
||||
{
|
||||
k_ESNetSocketStateInvalid = 0,
|
||||
@@ -61,6 +116,54 @@ enum ESNetSocketConnectionType
|
||||
class ISteamNetworking
|
||||
{
|
||||
public:
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Session-less connection functions
|
||||
// automatically establishes NAT-traversing or Relay server connections
|
||||
|
||||
// Sends a P2P packet to the specified user
|
||||
// UDP-like, unreliable and a max packet size of 1200 bytes
|
||||
// the first packet send may be delayed as the NAT-traversal code runs
|
||||
// if we can't get through to the user, an error will be posted via the callback P2PSessionConnectFail_t
|
||||
// see EP2PSend enum above for the descriptions of the different ways of sending packets
|
||||
virtual bool SendP2PPacket( CSteamID steamIDRemote, const void *pubData, uint32 cubData, EP2PSend eP2PSendType ) = 0;
|
||||
|
||||
// returns true if any data is available for read, and the amount of data that will need to be read
|
||||
virtual bool IsP2PPacketAvailable( uint32 *pcubMsgSize ) = 0;
|
||||
|
||||
// reads in a packet that has been sent from another user via SendP2PPacket()
|
||||
// returns the size of the message and the steamID of the user who sent it in the last two parameters
|
||||
// if the buffer passed in is too small, the message will be truncated
|
||||
// this call is not blocking, and will return false if no data is available
|
||||
virtual bool ReadP2PPacket( void *pubDest, uint32 cubDest, uint32 *pcubMsgSize, CSteamID *psteamIDRemote ) = 0;
|
||||
|
||||
// AcceptP2PSessionWithUser() should only be called in response to a P2PSessionRequest_t callback
|
||||
// P2PSessionRequest_t will be posted if another user tries to send you a packet that you haven't talked to yet
|
||||
// if you don't want to talk to the user, just ignore the request
|
||||
// if the user continues to send you packets, another P2PSessionRequest_t will be posted periodically
|
||||
// this may be called multiple times for a single user
|
||||
// (if you've called SendP2PPacket() on the other user, this implicitly accepts the session request)
|
||||
virtual bool AcceptP2PSessionWithUser( CSteamID steamIDRemote ) = 0;
|
||||
|
||||
// call CloseP2PSessionWithUser() when you're done talking to a user, will free up resources under-the-hood
|
||||
// if the remote user tries to send data to you again, another P2PSessionRequest_t callback will be posted
|
||||
virtual bool CloseP2PSessionWithUser( CSteamID steamIDRemote ) = 0;
|
||||
|
||||
// fills out P2PSessionState_t structure with details about the underlying connection to the user
|
||||
// should only needed for debugging purposes
|
||||
// returns false if no connection exists to the specified user
|
||||
virtual bool GetP2PSessionState( CSteamID steamIDRemote, P2PSessionState_t *pConnectionState ) = 0;
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// LISTEN / CONNECT style interface functions
|
||||
//
|
||||
// This is an older set of functions designed around the Berkeley TCP sockets model
|
||||
// it's preferential that you use the above P2P functions, they're more robust
|
||||
// and these older functions will be removed eventually
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
// creates a socket and listens others to connect
|
||||
// will trigger a SocketStatusCallback_t callback on another client connecting
|
||||
// nVirtualP2PPort is the unique ID that the client will connect to, in case you have multiple ports
|
||||
@@ -130,10 +233,31 @@ public:
|
||||
// max packet size, in bytes
|
||||
virtual int GetMaxPacketSize( SNetSocket_t hSocket ) = 0;
|
||||
};
|
||||
#define STEAMNETWORKING_INTERFACE_VERSION "SteamNetworking002"
|
||||
#define STEAMNETWORKING_INTERFACE_VERSION "SteamNetworking003"
|
||||
|
||||
|
||||
// callback notification - a user wants to talk to us over the P2P channel via the SendP2PPacket() API
|
||||
// in response, a call to AcceptP2PPacketsFromUser() needs to be made, if you want to talk with them
|
||||
struct P2PSessionRequest_t
|
||||
{
|
||||
enum { k_iCallback = k_iSteamNetworkingCallbacks + 2 };
|
||||
CSteamID m_steamIDRemote; // user who wants to talk to us
|
||||
};
|
||||
|
||||
|
||||
// callback notification - packets can't get through to the specified user via the SendP2PPacket() API
|
||||
// all packets queued packets unsent at this point will be dropped
|
||||
// further attempts to send will retry making the connection (but will be dropped if we fail again)
|
||||
struct P2PSessionConnectFail_t
|
||||
{
|
||||
enum { k_iCallback = k_iSteamNetworkingCallbacks + 3 };
|
||||
CSteamID m_steamIDRemote; // user we were sending packets to
|
||||
uint8 m_eP2PSessionError; // EP2PSessionError indicating why we're having trouble
|
||||
};
|
||||
|
||||
|
||||
// callback notification - status of a socket has changed
|
||||
// used as part of the CreateListenSocket() / CreateP2PConnectionSocket()
|
||||
struct SocketStatusCallback_t
|
||||
{
|
||||
enum { k_iCallback = k_iSteamNetworkingCallbacks + 1 };
|
||||
|
||||
@@ -105,6 +105,10 @@ public:
|
||||
|
||||
// Cancel auth ticket from GetAuthSessionTicket, called when no longer playing game with the entity you gave the ticket to
|
||||
virtual void CancelAuthTicket( HAuthTicket hAuthTicket ) = 0;
|
||||
|
||||
// After receiving a user's authentication data, and passing it to BeginAuthSession, use this function
|
||||
// to determine if the user owns downloadable content specified by the provided AppID.
|
||||
virtual EUserHasLicenseForAppResult UserHasLicenseForApp( CSteamID steamID, AppId_t appID ) = 0;
|
||||
};
|
||||
|
||||
#define STEAMUSER_INTERFACE_VERSION "SteamUser012"
|
||||
|
||||
@@ -52,6 +52,13 @@ enum ELeaderboardDisplayType
|
||||
k_ELeaderboardDisplayTypeTimeMilliSeconds = 3, // the score represents a time, in milliseconds
|
||||
};
|
||||
|
||||
enum ELeaderboardUploadScoreMethod
|
||||
{
|
||||
k_ELeaderboardUploadScoreMethodNone = 0,
|
||||
k_ELeaderboardUploadScoreMethodKeepBest = 1, // Leaderboard will keep user's best score
|
||||
k_ELeaderboardUploadScoreMethodForceUpdate = 2, // Leaderboard will always replace score with specified
|
||||
};
|
||||
|
||||
// a single entry in a leaderboard, as returned by GetDownloadedLeaderboardEntry()
|
||||
struct LeaderboardEntry_t
|
||||
{
|
||||
@@ -166,13 +173,16 @@ public:
|
||||
|
||||
// Uploads a user score to the Steam back-end.
|
||||
// This call is asynchronous, with the result returned in LeaderboardScoreUploaded_t
|
||||
// If the score passed in is no better than the existing score this user has in the leaderboard, then the leaderboard will not be updated.
|
||||
// Details are extra game-defined information regarding how the user got that score
|
||||
// pScoreDetails points to an array of int32's, cScoreDetailsCount is the number of int32's in the list
|
||||
virtual SteamAPICall_t UploadLeaderboardScore( SteamLeaderboard_t hSteamLeaderboard, int32 nScore, int32 *pScoreDetails, int cScoreDetailsCount ) = 0;
|
||||
virtual SteamAPICall_t UploadLeaderboardScore( SteamLeaderboard_t hSteamLeaderboard, ELeaderboardUploadScoreMethod eLeaderboardUploadScoreMethod, int32 nScore, const int32 *pScoreDetails, int cScoreDetailsCount ) = 0;
|
||||
|
||||
// Retrieves the number of players currently playing your game (online + offline)
|
||||
// This call is asynchronous, with the result returned in NumberOfCurrentPlayers_t
|
||||
virtual SteamAPICall_t GetNumberOfCurrentPlayers() = 0;
|
||||
};
|
||||
|
||||
#define STEAMUSERSTATS_INTERFACE_VERSION "STEAMUSERSTATS_INTERFACE_VERSION005"
|
||||
#define STEAMUSERSTATS_INTERFACE_VERSION "STEAMUSERSTATS_INTERFACE_VERSION006"
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@@ -256,5 +266,12 @@ struct LeaderboardScoreUploaded_t
|
||||
int m_nGlobalRankPrevious; // the previous global rank of the user in this leaderboard; 0 if the user had no existing entry in the leaderboard
|
||||
};
|
||||
|
||||
struct NumberOfCurrentPlayers_t
|
||||
{
|
||||
enum { k_iCallback = k_iSteamUserStatsCallbacks + 7 };
|
||||
uint8 m_bSuccess; // 1 if the call was successful
|
||||
int32 m_cPlayers; // Number of players currently playing
|
||||
};
|
||||
|
||||
|
||||
#endif // ISTEAMUSER_H
|
||||
|
||||
@@ -212,6 +212,7 @@ private:
|
||||
// For data added after SteamMatchMaking001 add it here
|
||||
public:
|
||||
char m_szGameTags[128]; // the tags this server exposes
|
||||
CSteamID m_steamID; // steamID of the game server - invalid if it's doesn't have one (old server, or not connected to Steam)
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -270,10 +270,20 @@ private:
|
||||
func_t m_Func;
|
||||
};
|
||||
|
||||
// Allows you to defer registration of the callback
|
||||
template< class T, class P, bool bGameServer >
|
||||
class CCallbackManual : public CCallback< T, P, bGameServer >
|
||||
{
|
||||
public:
|
||||
CCallbackManual() : CCallback< T, P, bGameServer >( NULL, NULL ) {}
|
||||
};
|
||||
|
||||
// utility macro for declaring the function and callback object together
|
||||
#define STEAM_CALLBACK( thisclass, func, param, var ) CCallback< thisclass, param, false > var; void func( param *pParam )
|
||||
|
||||
// same as above, but lets you defer the callback binding by calling Register later
|
||||
#define STEAM_CALLBACK_MANUAL( thisclass, func, param, var ) CCallbackManual< thisclass, param, false > var; void func( param *pParam )
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
// disable this warning; this pattern need for steam callback registration
|
||||
|
||||
@@ -69,6 +69,11 @@ enum EResult
|
||||
k_EResultNoMatch = 42, // nothing matching the request found
|
||||
k_EResultAccountDisabled = 43,
|
||||
k_EResultServiceReadOnly = 44, // this service is not accepting content changes right now
|
||||
k_EResultAccountNotFeatured = 45, // account doesn't have value, so this feature isn't available
|
||||
k_EResultAdministratorOK = 46, // allowed to take this action, but only because requester is admin
|
||||
k_EResultContentVersion = 47, // A Version mismatch in content transmitted within the Steam protocol.
|
||||
k_EResultTryAnotherCM = 48, // The current CM can't service the user making a request, user should try another.
|
||||
|
||||
};
|
||||
|
||||
// Error codes for use with the voice functions
|
||||
@@ -132,6 +137,14 @@ typedef enum
|
||||
k_EAuthSessionResponseAuthTicketInvalid = 8, // This ticket is not from a user instance currently connected to steam.
|
||||
} EAuthSessionResponse;
|
||||
|
||||
// results from UserHasLicenseForApp
|
||||
typedef enum
|
||||
{
|
||||
k_EUserHasLicenseResultHasLicense = 0, // User has a license for specified app
|
||||
k_EUserHasLicenseResultDoesNotHaveLicense = 1, // User does not have a license for the specified app
|
||||
k_EUserHasLicenseResultNoAuth = 2, // User has not been authenticated
|
||||
} EUserHasLicenseForAppResult;
|
||||
|
||||
|
||||
// Steam universes. Each universe is a self-contained Steam instance.
|
||||
enum EUniverse
|
||||
@@ -186,11 +199,13 @@ enum ESteamUserStatType
|
||||
//-----------------------------------------------------------------------------
|
||||
enum EChatEntryType
|
||||
{
|
||||
k_EChatEntryTypeInvalid = 0,
|
||||
k_EChatEntryTypeChatMsg = 1, // Normal text message from another user
|
||||
k_EChatEntryTypeTyping = 2, // Another user is typing (not used in multi-user chat)
|
||||
k_EChatEntryTypeInviteGame = 3, // Invite from other user into that users current game
|
||||
k_EChatEntryTypeEmote = 4, // text emote message
|
||||
k_EChatEntryTypeLobbyGameStart = 5, // lobby game is starting
|
||||
k_EChatEntryTypeLeftConversation = 6, // user has left the conversation ( closed chat window )
|
||||
// Above are previous FriendMsgType entries, now merged into more generic chat entry types
|
||||
};
|
||||
|
||||
@@ -209,6 +224,18 @@ enum EChatRoomEnterResponse
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Status of a given depot version, these are stored in the DB, don't renumber
|
||||
//-----------------------------------------------------------------------------
|
||||
enum EStatusDepotVersion
|
||||
{
|
||||
k_EStatusDepotVersionInvalid = 0,
|
||||
k_EStatusDepotVersionCompleteDisabled = 1,
|
||||
k_EStatusDepotVersionCompleteEnabledBeta = 2,
|
||||
k_EStatusDepotVersionCompleteEnabledPublic = 3,
|
||||
};
|
||||
|
||||
|
||||
typedef void (*PFNLegacyKeyRegistration)( const char *pchCDKey, const char *pchInstallPath );
|
||||
typedef bool (*PFNLegacyKeyInstalled)();
|
||||
|
||||
|
||||
@@ -74,6 +74,14 @@ const PackageId_t k_uPackageIdInvalid = 0xFFFFFFFF;
|
||||
typedef uint32 AppId_t;
|
||||
const AppId_t k_uAppIdInvalid = 0x0;
|
||||
|
||||
|
||||
// this is baked into client messages and interfaces as an int,
|
||||
// make sure we never break this. AppIds and DepotIDs also presently
|
||||
// share the same namespace, but since we'd like to change that in the future
|
||||
// I've defined it seperately here.
|
||||
typedef uint32 DepotId_t;
|
||||
const DepotId_t k_uDepotIdInvalid = 0x0;
|
||||
|
||||
// RTime32
|
||||
// We use this 32 bit time representing real world time.
|
||||
// It offers 1 second resolution beginning on January 1, 1970 (Unix time)
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Reference in New Issue
Block a user