/**
 * Give the async task time to do its work
 * Can only be called on the async task manager thread
 */
void FOnlineAsyncTaskSteamLogoffServer::Tick() 
{
	if (!bInit)
	{
		// @TODO ONLINE Listen Servers need to unset rich presence
		//SteamFriends()->SetRichPresence("connect", ""); for master server sessions
		SteamGameServer()->EnableHeartbeats(false);
		SteamGameServer()->LogOff();
		bInit = true;
	}

	// Wait for the disconnect
	FOnlineSessionSteamPtr SessionInt = StaticCastSharedPtr<FOnlineSessionSteam>(Subsystem->GetSessionInterface());
	if (!SessionInt->bSteamworksGameServerConnected && !SessionInt->GameServerSteamId.IsValid())
	{
		bIsComplete = true;
		bWasSuccessful = true;
	}
	else
	{
		// Fallback timeout in case we don't hear from Steam
		if (GetElapsedTime() >= ASYNC_TASK_TIMEOUT)
		{
			SessionInt->bSteamworksGameServerConnected = false;
			SessionInt->GameServerSteamId = NULL;
			bIsComplete = true;
			bWasSuccessful = false;
		}
	}
}
Example #2
0
//-----------------------------------------------------------------------------
// Purpose: Destructor
//-----------------------------------------------------------------------------
CSpaceWarServer::~CSpaceWarServer()
{
#ifdef USE_GS_AUTH_API
	// Notify Steam master server we are going offline
	SteamGameServer()->EnableHeartbeats( false );
#endif

	delete m_pSun;

	for( uint32 i=0; i < MAX_PLAYERS_PER_SERVER; ++i )
	{
		if ( m_rgpShips[i] )
		{
			// Tell this client we are exiting
			MsgServerExiting_t msg;
			BSendDataToClient( i, (char*)&msg, sizeof(msg) );

			delete m_rgpShips[i];
			m_rgpShips[i] = NULL;
		}
	}

	// Disconnect from the steam servers
	SteamGameServer()->LogOff();

	// release our reference to the steam client library
	SteamGameServer_Shutdown();
}
void FOnlineSubsystemSteam::ShutdownSteamworks()
{
	if (bSteamworksGameServerInitialized)
	{
		if (SteamGameServer() != nullptr)
		{
			// Since SteamSDK 1.17, LogOff is required to stop the game server advertising after exit; ensure we don't miss this at shutdown
			if (SteamGameServer()->BLoggedOn())
			{
				SteamGameServer()->LogOff();
			}

			SteamGameServer_Shutdown();
			if (SessionInterface.IsValid())
			{
				SessionInterface->GameServerSteamId = nullptr;
				SessionInterface->bSteamworksGameServerConnected = false;
			}	
		}
	}

	if (bSteamworksClientInitialized)
	{
		SteamAPI_Shutdown();
		bSteamworksClientInitialized = false;
	}
}
Example #4
0
/* <ee28a> ../engine/sv_steam3.cpp:506 */
void CSteam3Server::Shutdown(void) /* linkage=_ZN13CSteam3Server8ShutdownEv */
{
    if (this->m_bLoggedOn)
    {
        SteamGameServer()->EnableHeartbeats(0);
        SteamGameServer()->LogOff();

        SteamGameServer_Shutdown();
        this->m_bLoggedOn = false;
    }
}
Example #5
0
void CSteam3Server::Shutdown()
{
	if (m_bLoggedOn)
	{
		SteamGameServer()->EnableHeartbeats(0);
		SteamGameServer()->LogOff();

		SteamGameServer_Shutdown();
		m_bLoggedOn = false;
	}
}
Example #6
0
//-----------------------------------------------------------------------------
// Purpose: Removes a player at the given position
//-----------------------------------------------------------------------------
void CSpaceWarServer::RemovePlayerFromServer( uint32 uShipPosition )
{
	if ( uShipPosition >= MAX_PLAYERS_PER_SERVER )
	{
		OutputDebugString( "Trying to remove ship at invalid position\n" );
		return;
	}

	if ( !m_rgpShips[uShipPosition] )
	{
		OutputDebugString( "Trying to remove a ship that does not exist\n" );
		return;
	}

	OutputDebugString( "Removing a ship\n" );
	delete m_rgpShips[uShipPosition];
	m_rgpShips[uShipPosition] = NULL;
	m_rguPlayerScores[uShipPosition] = 0;

#ifdef USE_GS_AUTH_API
	// Tell the GS the user is leaving the server
	SteamGameServer()->EndAuthSession( m_rgClientData[uShipPosition].m_SteamIDUser );
#endif
	memset( &m_rgClientData[uShipPosition], 0, sizeof( ClientConnectionData_t ) );
}
Example #7
0
//-----------------------------------------------------------------------------
// Purpose: Handle a new client connecting
//-----------------------------------------------------------------------------
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 steamid
	for( uint32 i = 0; i < MAX_PLAYERS_PER_SERVER; ++i ) 
	{
		if ( m_rgClientData[i].m_SteamIDUser == steamIDClient )
		{
			// We already logged them on... (should maybe tell them again incase they don't know?)
			return;
		}
	}

	// Second, do we have room?
	uint32 nPendingOrActivePlayerCount = 0;
	for ( uint32 i = 0; i < MAX_PLAYERS_PER_SERVER; ++i )
	{
		if ( m_rgPendingClientData[i].m_bActive )
			++nPendingOrActivePlayerCount;
		
		if ( m_rgClientData[i].m_bActive )
			++nPendingOrActivePlayerCount;
	}

	// We are full (or will be if the pending players auth), deny new login
	if ( nPendingOrActivePlayerCount >=  MAX_PLAYERS_PER_SERVER )
	{
		MsgServerFailAuthentication_t msg;
		SteamGameServerNetworking()->SendP2PPacket( steamIDClient, &msg, sizeof( msg ), k_EP2PSendReliable );
	}

	// If we get here there is room, add the player as pending
	for( uint32 i = 0; i < MAX_PLAYERS_PER_SERVER; ++i ) 
	{
		if ( !m_rgPendingClientData[i].m_bActive )
		{
			m_rgPendingClientData[i].m_ulTickCountLastData = m_pGameEngine->GetGameTickCount();
#ifdef USE_GS_AUTH_API
			// authenticate the user with the Steam back-end servers
			if ( k_EBeginAuthSessionResultOK != SteamGameServer()->BeginAuthSession( pToken, uTokenLen, steamIDClient ) )
			{
				MsgServerFailAuthentication_t msg;
				SteamGameServerNetworking()->SendP2PPacket( steamIDClient, &msg, sizeof( msg ), k_EP2PSendReliable );
				break;
			}

			m_rgPendingClientData[i].m_SteamIDUser = steamIDClient;
			m_rgPendingClientData[i].m_bActive = true;
			break;
#else
			m_rgPendingClientData[i].m_bActive = true;
			// we need to tell the server our Steam id in the non-auth case, so we stashed it in the login message, pull it back out
			m_rgPendingClientData[i].m_SteamIDUser = *(CSteamID *)pToken;
			// You would typically do your own authentication method here and later call OnAuthCompleted
			// In this sample we just automatically auth anyone who connects
			OnAuthCompleted( true, i );
			break;
#endif
		}
	}
}
Example #8
0
//-----------------------------------------------------------------------------
// Purpose: Callback from Steam when logon is fully completed and VAC secure policy is set
//-----------------------------------------------------------------------------
void CSpaceWarServer::OnPolicyResponse( GSPolicyResponse_t *pPolicyResponse )
{
#ifdef USE_GS_AUTH_API
	// Check if we were able to go VAC secure or not
	if ( SteamGameServer()->BSecure() )
	{
		OutputDebugString( "SpaceWarServer is VAC Secure!\n" );
	}
	else
	{
		OutputDebugString( "SpaceWarServer is not VAC Secure!\n" );
	}
	char rgch[128];
	sprintf_safe( rgch, "Game server SteamID: %llu\n", SteamGameServer()->GetSteamID().ConvertToUint64() );
	rgch[ sizeof(rgch) - 1 ] = 0;
	OutputDebugString( rgch );
#endif
}
Example #9
0
//-----------------------------------------------------------------------------
// Purpose: Returns the SteamID of the game server
//-----------------------------------------------------------------------------
CSteamID CSpaceWarServer::GetSteamID()
{
#ifdef USE_GS_AUTH_API
	return SteamGameServer()->GetSteamID();
#else
	// this is a placeholder steam id to use when not making use of Steam auth or matchmaking
	return k_steamIDNonSteamGS;
#endif
}
/**
 * Give the async task time to do its work
 * Can only be called on the async task manager thread
 */
void FOnlineAsyncTaskSteamCreateServer::Tick() 
{
	if (!bInit)
	{
		ISteamGameServer* SteamGameServerPtr = SteamGameServer();
		check(SteamGameServerPtr);

		UE_LOG_ONLINE(Verbose, TEXT("Initializing Steam game server"));

		SteamGameServerPtr->SetModDir(STEAMGAMEDIR);
		SteamGameServerPtr->SetProduct(STEAMPRODUCTNAME);
		SteamGameServerPtr->SetGameDescription(STEAMGAMEDESC);

		if (!SteamGameServerPtr->BLoggedOn())
		{
			// Login the server with Steam
			SteamGameServerPtr->LogOnAnonymous();
		}

		// Setup advertisement and force the initial update
		SteamGameServerPtr->SetHeartbeatInterval(-1);
		SteamGameServerPtr->EnableHeartbeats(true);
		SteamGameServerPtr->ForceHeartbeat();
		
		bInit = true;
	}

	// Wait for the connection and policy response callbacks
	FOnlineSessionSteamPtr SessionInt = StaticCastSharedPtr<FOnlineSessionSteam>(Subsystem->GetSessionInterface());
	if (SessionInt->bSteamworksGameServerConnected && SessionInt->GameServerSteamId->IsValid() && SessionInt->bPolicyResponseReceived)
	{
		bIsComplete = true;
		bWasSuccessful = true;
	}
	else
	{
		// Fallback timeout in case we don't hear from Steam
		if (GetElapsedTime() >= ASYNC_TASK_TIMEOUT)
		{
			bIsComplete = true;
			bWasSuccessful = false;
		}
	}
}
Example #11
0
//-----------------------------------------------------------------------------
// Purpose: Called once we are connected to Steam to tell it about our details
//-----------------------------------------------------------------------------
void CSpaceWarServer::SendUpdatedServerDetailsToSteam()
{

	// Tell the Steam authentication servers about our game
	char rgchServerName[128];
	if ( SpaceWarClient() )
	{
		// If a client is running (should always be since we don't support a dedicated server)
		// then we'll form the name based off of it
		sprintf_safe( rgchServerName, "%s's game", SpaceWarClient()->GetLocalPlayerName() );
	}
	else
	{
		sprintf_safe( rgchServerName, "%s", "Spacewar!" );
	}
	m_sServerName = rgchServerName;

	//
	// Set state variables, relevant to any master server updates or client pings
	//

	// These server state variables may be changed at any time.  Note that there is no lnoger a mechanism
	// to send the player count.  The player count is maintained by steam and you should use the player
	// creation/authentication functions to maintain your player count.
	SteamGameServer()->SetMaxPlayerCount( 4 );
	SteamGameServer()->SetPasswordProtected( false );
	SteamGameServer()->SetServerName( m_sServerName.c_str() );
	SteamGameServer()->SetBotPlayerCount( 0 ); // optional, defaults to zero
	SteamGameServer()->SetMapName( "MilkyWay" );

#ifdef USE_GS_AUTH_API

	// Update all the players names/scores
	for( uint32 i=0; i < MAX_PLAYERS_PER_SERVER; ++i )
	{
		if ( m_rgClientData[i].m_bActive && m_rgpShips[i] )
		{
			SteamGameServer()->BUpdateUserData( m_rgClientData[i].m_SteamIDUser, m_rgpShips[i]->GetPlayerName(), m_rguPlayerScores[i] );
		}
	}
#endif

	// game type is a special string you can use for your game to differentiate different game play types occurring on the same maps
	// When users search for this parameter they do a sub-string search of this string 
	// (i.e if you report "abc" and a client requests "ab" they return your server)
	//SteamGameServer()->SetGameType( "dm" );

	// update any rule values we publish
	//SteamMasterServerUpdater()->SetKeyValue( "rule1_setting", "value" );
	//SteamMasterServerUpdater()->SetKeyValue( "rule2_setting", "value2" );
}
/**
 * Give the async task a chance to marshal its data back to the game thread
 * Can only be called on the game thread by the async task manager
 */
void FOnlineAsyncTaskSteamCreateServer::Finalize() 	
{
	FOnlineSessionSteamPtr SessionInt = StaticCastSharedPtr<FOnlineSessionSteam>(Subsystem->GetSessionInterface());
	if (bWasSuccessful)
	{
		FNamedOnlineSession* Session = SessionInt->GetNamedSession(SessionName);
		if (Session)
		{
			// Setup the host session info
			FOnlineSessionInfoSteam* NewSessionInfo = new FOnlineSessionInfoSteam(ESteamSession::AdvertisedSessionHost, *SessionInt->GameServerSteamId);
			NewSessionInfo->Init();

			ISteamGameServer* SteamGameServerPtr = SteamGameServer();
			check(SteamGameServerPtr);

			// Create the proper Steam P2P address for this machine
			NewSessionInfo->SteamP2PAddr = ISocketSubsystem::Get()->GetLocalBindAddr(*GLog);
			NewSessionInfo->SteamP2PAddr->SetPort(Subsystem->GetGameServerGamePort());
			UE_LOG_ONLINE(Verbose, TEXT("Server SteamP2P IP: %s"), *NewSessionInfo->SteamP2PAddr->ToString(true));

			// Create the proper ip address for this server
			NewSessionInfo->HostAddr = ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM)->CreateInternetAddr(SteamGameServerPtr->GetPublicIP(), Subsystem->GetGameServerGamePort());
			UE_LOG_ONLINE(Verbose, TEXT("Server IP: %s"), *NewSessionInfo->HostAddr->ToString(true));

			if (!Session->OwningUserId.IsValid())
			{
				check(Session->SessionSettings.bIsDedicated);
				// Associate the dedicated server anonymous login as the owning user
				Session->OwningUserId = SessionInt->GameServerSteamId;
				Session->OwningUserName = Session->OwningUserId->ToString();
			}
			
			Session->SessionInfo = MakeShareable(NewSessionInfo);
			Session->SessionSettings.bAntiCheatProtected = SteamGameServerPtr->BSecure() != 0 ? true : false;

			Session->SessionState = EOnlineSessionState::Pending;

			UWorld* World = GetWorldForOnline(Subsystem->GetInstanceName());
			UpdatePublishedSettings(World, Session);

			SessionInt->RegisterLocalPlayers(Session);

			if (SteamUser())
			{
				SteamUser()->AdvertiseGame(NewSessionInfo->SessionId, SteamGameServerPtr->GetPublicIP(), Subsystem->GetGameServerGamePort());
			}
			
			// Set host rich presence string so we can find via FindFriendSession()
// 			FString ConnectionString = Sessions->GetSteamConnectionString(Session->SessionName);
// 			if (!SteamFriends()->SetRichPresence("connect", TCHAR_TO_UTF8(*ConnectionString)))
// 			{
// 				UE_LOG_ONLINE(Verbose, TEXT("Failed to set rich presence for session %s"), *Session->SessionName.ToString());
// 			}
		}
		else
		{
			UE_LOG_ONLINE(Warning, TEXT("No session %s found to update with Steam backend"), *SessionName.ToString());
		}
	}
	else
	{
		SessionInt->RemoveNamedSession(SessionName);
	}
}
/** 
 *  Update the backend with the currently defined settings
 *
 * @param World current running world instance
 * @param SessionName name of session to update published settings
 */
void UpdatePublishedSettings(UWorld* World, FNamedOnlineSession* Session)
{
	ISteamGameServer* SteamGameServerPtr = SteamGameServer();
	check(SteamGameServerPtr);

	// Copy the current settings so we can remove the ones used for well defined search parameters
	FOnlineSessionSettings TempSessionSettings = Session->SessionSettings;

	// Server name
	FString ServerName = Session->OwningUserName;
	SteamGameServerPtr->SetServerName(TCHAR_TO_UTF8(*ServerName));

	// Max user slots reported
	int32 NumTotalSlots = Session->SessionSettings.NumPublicConnections + Session->SessionSettings.NumPrivateConnections;
	SteamGameServerPtr->SetMaxPlayerCount(NumTotalSlots);

	// Region setting
	FString Region(TEXT(""));
	SteamGameServerPtr->SetRegion(TCHAR_TO_UTF8(*Region));

	// @TODO ONLINE Password protected or not
	SteamGameServerPtr->SetPasswordProtected(false);

	// Dedicated server or not
	SteamGameServerPtr->SetDedicatedServer(Session->SessionSettings.bIsDedicated ? true : false);

	// Map name
	FString MapName;
	if (TempSessionSettings.Get(SETTING_MAPNAME, MapName) && !MapName.IsEmpty())
	{
		SteamGameServerPtr->SetMapName(TCHAR_TO_UTF8(*MapName));
	}
	TempSessionSettings.Remove(SETTING_MAPNAME);

	// Bot Count
	int32 BotCount = 0;
	if (TempSessionSettings.Get(SETTING_NUMBOTS, BotCount))
	{
		SteamGameServerPtr->SetBotPlayerCount(BotCount);
	}
	TempSessionSettings.Remove(SETTING_NUMBOTS);

	// Update all the players names/scores
	if (World)
	{
		AGameState const* const GameState = World->GameState;
		if (GameState)
		{
			for (int32 PlayerIdx=0; PlayerIdx < GameState->PlayerArray.Num(); PlayerIdx++)
			{
				APlayerState const* const PlayerState = GameState->PlayerArray[PlayerIdx];
				if (PlayerState && PlayerState->UniqueId.IsValid())
				{
					CSteamID SteamId(*(uint64*)PlayerState->UniqueId->GetBytes());
					SteamGameServerPtr->BUpdateUserData(SteamId, TCHAR_TO_UTF8(*PlayerState->PlayerName), PlayerState->Score);
				}
			}
		}
	}

	// Get the advertised session settings out as Steam key/value pairs
	FSteamSessionKeyValuePairs AdvertisedKeyValuePairs;
	GetServerKeyValuePairsFromSession(Session, AdvertisedKeyValuePairs);

	if (Session->SessionInfo.IsValid())
	{
		FOnlineSessionInfoSteam* SessionInfo = (FOnlineSessionInfoSteam*)(Session->SessionInfo.Get());
		GetServerKeyValuePairsFromSessionInfo(SessionInfo, AdvertisedKeyValuePairs);
	}

	FString SessionFlags = GetSessionFlagsAsString(Session->SessionSettings);
	AdvertisedKeyValuePairs.Add(STEAMKEY_SESSIONFLAGS, SessionFlags);

	FString SessionBuildUniqueId = GetBuildIdAsSteamKey(Session->SessionSettings);

	GetServerKeyValuePairsFromSessionSettings(TempSessionSettings, AdvertisedKeyValuePairs, EOnlineDataAdvertisementType::ViaOnlineService);

	FSteamSessionKeyValuePairs AuxKeyValuePairs;
	GetServerKeyValuePairsFromSessionSettings(TempSessionSettings, AuxKeyValuePairs, EOnlineDataAdvertisementType::ViaPingOnly);
	
	FSteamSessionKeyValuePairs TempKeyValuePairs;
	GetServerKeyValuePairsFromSessionSettings(TempSessionSettings, TempKeyValuePairs, EOnlineDataAdvertisementType::ViaOnlineServiceAndPing);

	AdvertisedKeyValuePairs.Append(TempKeyValuePairs);
	AuxKeyValuePairs.Append(TempKeyValuePairs);
	
	FString GameTagsString, GameDataString;

	// Start the game tags with the build id so search results can early out
	GameTagsString = SessionBuildUniqueId;

	// Create the properly formatted Steam string (ie key:value,key:value,key) for GameTags/GameData
	FSteamSessionKeyValuePairs::TConstIterator It(AdvertisedKeyValuePairs);
	if (It)
	{
		UE_LOG_ONLINE(Verbose, TEXT("Master Server Data (%s, %s)"), *It.Key(), *It.Value());
		FString NewKey = FString::Printf(TEXT("%s:%s"), *It.Key(), *It.Value());

		if (GameTagsString.Len() + NewKey.Len() < k_cbMaxGameServerTags)
		{
			GameTagsString = GameTagsString + "," + NewKey;
		}
		else
		{
			UE_LOG_ONLINE(Warning, TEXT("Server setting %s overflows Steam SetGameTags call"), *NewKey);
		}

		if (NewKey.Len() < k_cbMaxGameServerGameData)
		{
			GameDataString = NewKey;
		}
		else
		{
			UE_LOG_ONLINE(Warning, TEXT("Server setting %s overflows Steam SetGameData call"), *NewKey);
		}

		++It;
	}
	for (; It; ++It)
	{
		UE_LOG_ONLINE(Verbose, TEXT("Master Server Data (%s, %s)"), *It.Key(), *It.Value());
		FString NewKey = FString::Printf(TEXT(",%s:%s"), *It.Key(), *It.Value());
		if (GameTagsString.Len() + NewKey.Len() < k_cbMaxGameServerTags)
		{
			GameTagsString += NewKey;
		}
		else
		{
			UE_LOG_ONLINE(Warning, TEXT("Server setting %s overflows Steam SetGameTags call"), *NewKey);
		}

		if (GameDataString.Len() + NewKey.Len() < k_cbMaxGameServerGameData)
		{
			GameDataString += NewKey;
		}
		else
		{
			UE_LOG_ONLINE(Warning, TEXT("Server setting %s overflows Steam SetGameData call"), *NewKey);
		}
	}

	// Small and searchable game tags (returned in initial server query structure)
	if (GameTagsString.Len() > 0 && GameTagsString.Len() < k_cbMaxGameServerTags)
	{
		UE_LOG_ONLINE(Verbose, TEXT("SetGameTags(%s)"), *GameTagsString);
		SteamGameServerPtr->SetGameTags(TCHAR_TO_UTF8(*GameTagsString));
	}

	// Large and searchable game data (never returned)
	if (GameDataString.Len() > 0 && GameDataString.Len() < k_cbMaxGameServerGameData)
	{
		UE_LOG_ONLINE(Verbose, TEXT("SetGameData(%s)"), *GameDataString);
		SteamGameServerPtr->SetGameData(TCHAR_TO_UTF8(*GameDataString));
	}

	// @TODO ONLINE - distinguish between server side keys (SetGameData()) and client side keys (SetKeyValue())
	// Set the advertised filter keys (these can not be filtered at master-server level, only client side)
	SteamGameServerPtr->ClearAllKeyValues();

	// Key value pairs sent as rules (requires secondary RulesRequest call)
	for (FSteamSessionKeyValuePairs::TConstIterator AdvKeyIt(AdvertisedKeyValuePairs); AdvKeyIt; ++AdvKeyIt)
	{
		UE_LOG_ONLINE(Verbose, TEXT("Aux Server Data (%s, %s)"), *AdvKeyIt.Key(), *AdvKeyIt.Value());
		SteamGameServerPtr->SetKeyValue(TCHAR_TO_UTF8(*AdvKeyIt.Key()), TCHAR_TO_UTF8(*AdvKeyIt.Value()));
	}

	// Key value pairs sent as rules (requires secondary RulesRequest call)
	for (FSteamSessionKeyValuePairs::TConstIterator AuxKeyIt(AuxKeyValuePairs); AuxKeyIt; ++AuxKeyIt)
	{
		UE_LOG_ONLINE(Verbose, TEXT("Aux Server Data (%s, %s)"), *AuxKeyIt.Key(), *AuxKeyIt.Value());
		SteamGameServerPtr->SetKeyValue(TCHAR_TO_UTF8(*AuxKeyIt.Key()), TCHAR_TO_UTF8(*AuxKeyIt.Value()));
	}
}	
Example #14
0
//-----------------------------------------------------------------------------
// Purpose: Receives incoming network data
//-----------------------------------------------------------------------------
void CSpaceWarServer::ReceiveNetworkData()
{
	char *pchRecvBuf = NULL;
	uint32 cubMsgSize;
	CSteamID steamIDRemote;
	while ( SteamGameServerNetworking()->IsP2PPacketAvailable( &cubMsgSize ) )
	{
		// free any previous receive buffer
		if ( pchRecvBuf )
			free( pchRecvBuf );

		// alloc a new receive buffer of the right size
		pchRecvBuf = (char *)malloc( cubMsgSize );

		// see if there is any data waiting on the socket
		if ( !SteamGameServerNetworking()->ReadP2PPacket( pchRecvBuf, cubMsgSize, &cubMsgSize, &steamIDRemote ) )
			break;

		if ( cubMsgSize < sizeof( DWORD ) )
		{
			OutputDebugString( "Got garbage on server socket, too short\n" );
			continue;
		}

		EMessage eMsg = (EMessage)LittleDWord( *(DWORD*)pchRecvBuf );
		switch ( eMsg )
		{
		case k_EMsgClientInitiateConnection:
			{
				// We always let clients do this without even checking for room on the server since we reserve that for 
				// the authentication phase of the connection which comes next
				MsgServerSendInfo_t msg;
				msg.SetSteamIDServer( SteamGameServer()->GetSteamID().ConvertToUint64() );
#ifdef USE_GS_AUTH_API
				// You can only make use of VAC when using the Steam authentication system
				msg.SetSecure( SteamGameServer()->BSecure() );
#endif
				msg.SetServerName( m_sServerName.c_str() );
				SteamGameServerNetworking()->SendP2PPacket( steamIDRemote, &msg, sizeof( MsgServerSendInfo_t ), k_EP2PSendReliable );
			}
			break;
		case k_EMsgClientBeginAuthentication:
			{
				if ( cubMsgSize != sizeof( MsgClientBeginAuthentication_t ) )
				{
					OutputDebugString( "Bad connection attempt msg\n" );
					continue;
				}
				MsgClientBeginAuthentication_t *pMsg = (MsgClientBeginAuthentication_t*)pchRecvBuf;
#ifdef USE_GS_AUTH_API
				OnClientBeginAuthentication( steamIDRemote, (void*)pMsg->GetTokenPtr(), pMsg->GetTokenLen() );
#else
				OnClientBeginAuthentication( steamIDRemote, 0 );
#endif
			}
			break;
		case k_EMsgClientSendLocalUpdate:
			{
				if ( cubMsgSize != sizeof( MsgClientSendLocalUpdate_t ) )
				{
					OutputDebugString( "Bad client update msg\n" );
					continue;
				}

				// Find the connection that should exist for this users address
				bool bFound = false;
				for( uint32 i=0; i<MAX_PLAYERS_PER_SERVER; ++i )
				{
					if ( m_rgClientData[i].m_SteamIDUser == steamIDRemote ) 
					{
						bFound = true;
						MsgClientSendLocalUpdate_t *pMsg = (MsgClientSendLocalUpdate_t*)pchRecvBuf;
						OnReceiveClientUpdateData( i, pMsg->AccessUpdateData() );
						break;
					}
				}
				if ( !bFound )
					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 ) )
				{
					OutputDebugString( "Bad leaving server msg\n" );
					continue;
				}
				// Find the connection that should exist for this users address
				bool bFound = false;
				for( uint32 i=0; i<MAX_PLAYERS_PER_SERVER; ++i )
				{
					if ( m_rgClientData[i].m_SteamIDUser == steamIDRemote )
					{
						bFound = true;
						RemovePlayerFromServer( i );
						break;
					}

					// Also check for pending connections that may match
					if ( m_rgPendingClientData[i].m_SteamIDUser == steamIDRemote )
					{
	#ifdef USE_GS_AUTH_API
						// Tell the GS the user is leaving the server
						SteamGameServer()->SendUserDisconnect( m_rgPendingClientData[i].m_SteamIDUser );
	#endif
						// Clear our data on the user
						memset( &m_rgPendingClientData[i], 0 , sizeof( ClientConnectionData_t ) );
						break;
					}
				}
				if ( !bFound )
					OutputDebugString( "Got a client leaving server msg, but couldn't find a matching client\n" );
			}
		default:
			char rgch[128];
			sprintf_safe( rgch, "Invalid message %x\n", eMsg );
			rgch[ sizeof(rgch) - 1 ] = 0;
			OutputDebugString( rgch );
		}
	}

	if ( pchRecvBuf )
		free( pchRecvBuf );
}
Example #15
0
//-----------------------------------------------------------------------------
// Purpose: A new client that connected has had their authentication processed
//-----------------------------------------------------------------------------
void CSpaceWarServer::OnAuthCompleted( bool bAuthSuccessful, uint32 iPendingAuthIndex )
{
	if ( !m_rgPendingClientData[iPendingAuthIndex].m_bActive )
	{
		OutputDebugString( "Got auth completed callback for client who is not pending\n" );
		return;
	}

	if ( !bAuthSuccessful )
	{
#ifdef USE_GS_AUTH_API
		// Tell the GS the user is leaving the server
		SteamGameServer()->EndAuthSession( m_rgPendingClientData[iPendingAuthIndex].m_SteamIDUser );
#endif
		// Send a deny for the client, and zero out the pending data
		MsgServerFailAuthentication_t msg;
		SteamGameServerNetworking()->SendP2PPacket( m_rgPendingClientData[iPendingAuthIndex].m_SteamIDUser, &msg, sizeof( msg ), k_EP2PSendReliable );
		memset( &m_rgPendingClientData[iPendingAuthIndex], 0, sizeof( ClientConnectionData_t ) );
		return;
	}


	bool bAddedOk = false;
	for( uint32 i = 0; i < MAX_PLAYERS_PER_SERVER; ++i ) 
	{
		if ( !m_rgClientData[i].m_bActive )
		{
			// copy over the data from the pending array
			memcpy( &m_rgClientData[i], &m_rgPendingClientData[iPendingAuthIndex], sizeof( ClientConnectionData_t ) );
			memset( &m_rgPendingClientData[iPendingAuthIndex], 0, sizeof( ClientConnectionData_t	) );
			m_rgClientData[i].m_ulTickCountLastData = m_pGameEngine->GetGameTickCount();

			// Add a new ship, make it dead immediately
			AddPlayerShip( i );
			m_rgpShips[i]->SetDisabled( true );

			MsgServerPassAuthentication_t msg;
			msg.SetPlayerPosition( i );
			BSendDataToClient( i, (char*)&msg, sizeof( msg ) );

			bAddedOk = true;

			break;
		}
	}

	// If we just successfully added the player, check if they are #2 so we can restart the round
	if ( bAddedOk )
	{
		uint32 uPlayers = 0;
		for( uint32 i = 0; i < MAX_PLAYERS_PER_SERVER; ++i ) 
		{
			if ( m_rgClientData[i].m_bActive )
				++uPlayers;
		}

		// If we just got the second player, immediately reset round as a draw.  This will prevent
		// the existing player getting a win, and it will cause a new round to start right off
		// so that the one player can't just float around not letting the new one get into the game.
		if ( uPlayers == 2 )
		{
			if ( m_eGameState != k_EServerWaitingForPlayers )
				SetGameState( k_EServerDraw );
		}
	}
}
Example #16
0
//-----------------------------------------------------------------------------
// Purpose: Constructor -- note the syntax for setting up Steam API callback handlers
//-----------------------------------------------------------------------------
CSpaceWarServer::CSpaceWarServer( IGameEngine *pGameEngine ) 
{
	m_bConnectedToSteam = false;


	const char *pchGameDir = "spacewar";
	uint32 unIP = INADDR_ANY;
	uint16 usMasterServerUpdaterPort = SPACEWAR_MASTER_SERVER_UPDATER_PORT;

#ifdef USE_GS_AUTH_API
	EServerMode eMode = eServerModeAuthenticationAndSecure;
#else
	// Don't let Steam do authentication
	EServerMode eMode = eServerModeNoAuthentication;
#endif
	// Initialize the SteamGameServer interface, we tell it some info about us, and we request support
	// for both Authentication (making sure users own games) and secure mode, VAC running in our game
	// and kicking users who are VAC banned

	// !FIXME! We need a way to pass the dedicated server flag here!

#ifdef _PS3
	if ( !SteamGameServer_Init( &g_SteamPS3Params, unIP, SPACEWAR_AUTHENTICATION_PORT, SPACEWAR_SERVER_PORT, usMasterServerUpdaterPort, eMode, SPACEWAR_SERVER_VERSION ) )
#else
	if ( !SteamGameServer_Init( unIP, SPACEWAR_AUTHENTICATION_PORT, SPACEWAR_SERVER_PORT, usMasterServerUpdaterPort, eMode, SPACEWAR_SERVER_VERSION ) )
#endif
	{
		OutputDebugString( "SteamGameServer_Init call failed\n" );
	}

	if ( SteamGameServer() )
	{

		// Set the "game dir".
		// This is currently required for all games.  However, soon we will be
		// using the AppID for most purposes, and this string will only be needed
		// for mods.  it may not be changed after the server has logged on
		SteamGameServer()->SetModDir( pchGameDir );

		// These fields are currently required, but will go away soon.
		// See their documentation for more info
		SteamGameServer()->SetProduct( "SteamworksExample" );
		SteamGameServer()->SetGameDescription( "Steamworks Example" );

		// We don't support specators in our game.
		// .... but if we did:
		//SteamGameServer()->SetSpectatorPort( ... );
		//SteamGameServer()->SetSpectatorServerName( ... );

		// Initiate Anonymous logon.
		// Coming soon: Logging into authenticated, persistent game server account
		SteamGameServer()->LogOnAnonymous();

		// We want to actively update the master server with our presence so players can
		// find us via the steam matchmaking/server browser interfaces
		#ifdef USE_GS_AUTH_API
			SteamGameServer()->EnableHeartbeats( true );
		#endif
	}
	else
	{
		OutputDebugString( "SteamGameServer() interface is invalid\n" );
	}

	m_uPlayerCount = 0;
	m_pGameEngine = pGameEngine;
	m_eGameState = k_EServerWaitingForPlayers;

	for( uint32 i = 0; i < MAX_PLAYERS_PER_SERVER; ++i )
	{
		m_rguPlayerScores[i] = 0;
		m_rgpShips[i] = NULL;
	}

	// No one has won
	m_uPlayerWhoWonGame = 0;
	m_ulStateTransitionTime = m_pGameEngine->GetGameTickCount();
	m_ulLastServerUpdateTick = 0;

	// zero the client connection data
	memset( &m_rgClientData, 0, sizeof( m_rgClientData ) );
	memset( &m_rgPendingClientData, 0, sizeof( m_rgPendingClientData ) );

	// Seed random num generator
	srand( (uint32)time( NULL ) );

	// Initialize sun
	m_pSun = new CSun( pGameEngine );

	// Initialize ships
	ResetPlayerShips();
}