This commit is contained in:
Riley Labrecque
2025-03-30 17:07:09 -07:00
parent e7bb839178
commit 1b9765621f
41 changed files with 780 additions and 289 deletions
+15
View File
@@ -23,6 +23,7 @@ enum EMessage
k_EMsgServerUpdateWorld = k_EMsgServerBegin+4,
k_EMsgServerExiting = k_EMsgServerBegin+5,
k_EMsgServerPingResponse = k_EMsgServerBegin+6,
k_EMsgServerPlayerHitSun = k_EMsgServerBegin+7,
// Client messages
k_EMsgClientBegin = 500,
@@ -204,6 +205,20 @@ private:
CSteamID from_steamID;
};
// A notification to the client that this player collided with the sun
struct MsgServerPlayerHitSun_t
{
MsgServerPlayerHitSun_t() : m_dwMessageType( LittleDWord( k_EMsgServerPlayerHitSun ) ) {}
DWORD GetMessageType() const { return LittleDWord( m_dwMessageType ); }
void SetSteamID( CSteamID steamID ) { from_steamID = steamID; }
CSteamID GetSteamID() const { return from_steamID; }
private:
const DWORD m_dwMessageType;
CSteamID from_steamID;
};
#pragma pack( pop )
#endif // MESSAGES_H
+58 -1
View File
@@ -68,6 +68,15 @@ public:
AddMenuItem( COverlayExamplesMenu::MenuItem_t( "Set Notification Position: Bottom Left", { OverlayExample_t::k_EOverlayExampleItem_Notification_SetPosition, "2" } ) );
AddMenuItem( COverlayExamplesMenu::MenuItem_t( "Set Notification Position: Bottom Right", { OverlayExample_t::k_EOverlayExampleItem_Notification_SetPosition, "3" } ) );
if ( m_pOverlayExamples->BHasLastGamePhase() )
{
AddMenuItem( COverlayExamplesMenu::MenuItem_t( "Show last match", { OverlayExample_t::k_EOverlayExampleItem_Timeline_OpenOverlayToGamePhase } ) );
}
if ( m_pOverlayExamples->BHasLastTimelineEvent() )
{
AddMenuItem( COverlayExamplesMenu::MenuItem_t( "Show last crash into sun", { OverlayExample_t::k_EOverlayExampleItem_Timeline_OpenOverlayToTimelineEvent } ) );
}
AddMenuItem( COverlayExamplesMenu::MenuItem_t( "Return to main menu", { OverlayExample_t::k_EOverlayExampleItem_BackToMenu, NULL } ) );
PopSelectedItem();
@@ -195,6 +204,13 @@ void COverlayExamples::RunFrame()
SteamUtils()->SetOverlayNotificationPosition( (ENotificationPosition)atoi( m_delayedCommand.m_pchExtraCommandData ) );
break;
case OverlayExample_t::k_EOverlayExampleItem_Timeline_OpenOverlayToGamePhase:
SteamTimeline()->OpenOverlayToGamePhase( m_strLastGamePhaseIDToShow.c_str() );
break;
case OverlayExample_t::k_EOverlayExampleItem_Timeline_OpenOverlayToTimelineEvent:
SteamTimeline()->OpenOverlayToTimelineEvent( m_ulLastCrashIntoSunEventIDToShow );
break;
default:
break;
}
@@ -218,6 +234,20 @@ void COverlayExamples::OnMenuSelection( OverlayExample_t selection )
//-----------------------------------------------------------------------------
void COverlayExamples::Show()
{
if ( SpaceWarClient()->GetLastGamePhaseID() )
{
SteamAPICall_t hSteamAPICall = SteamTimeline()->DoesGamePhaseRecordingExist( std::to_string( SpaceWarClient()->GetLastGamePhaseID() ).c_str() );
m_SteamCallResultDoesGamePhaseRecordingExist.Set( hSteamAPICall, this, &COverlayExamples::OnDoesGamePhaseRecordingExist );
}
m_strLastGamePhaseIDToShow.erase();
if ( SpaceWarClient()->GetLastCrashIntoSunEvent() )
{
SteamAPICall_t hSteamAPICall = SteamTimeline()->DoesEventRecordingExist( SpaceWarClient()->GetLastCrashIntoSunEvent() );
m_SteamCallResultDoesEventRecordingExist.Set( hSteamAPICall, this, &COverlayExamples::OnDoesEventRecordingExist );
}
m_pMenu->Rebuild();
}
@@ -229,4 +259,31 @@ void COverlayExamples::OnScreenshotRequested( ScreenshotRequested_t *pCallback )
void COverlayExamples::OnSteamScreenshotReady( ScreenshotReady_t *pCallback )
{
}
}
void COverlayExamples::OnDoesEventRecordingExist( SteamTimelineEventRecordingExists_t *pCallback, bool bIOFailure )
{
if ( bIOFailure || !pCallback->m_bRecordingExists )
{
// nothing to do here. We didn't show these items when showing the menu
return;
}
m_ulLastCrashIntoSunEventIDToShow = pCallback->m_ulEventID;
m_pMenu->Rebuild();
}
void COverlayExamples::OnDoesGamePhaseRecordingExist( SteamTimelineGamePhaseRecordingExists_t *pCallback, bool bIOFailure )
{
if ( bIOFailure || ( pCallback->m_ulRecordingMS == 0 && pCallback->m_unClipCount == 0 ) )
{
// nothing to do here. We didn't show these items when showing the menu
return;
}
m_strLastGamePhaseIDToShow = pCallback->m_rgchPhaseID;
m_pMenu->Rebuild();
}
+14 -1
View File
@@ -29,7 +29,10 @@ public:
// handles input from menu
void OnMenuSelection( OverlayExample_t selection );
bool BHasLastGamePhase() const { return !m_strLastGamePhaseIDToShow.empty(); }
bool BHasLastTimelineEvent() const { return m_ulLastCrashIntoSunEventIDToShow != 0; }
private:
// Engine
@@ -37,9 +40,19 @@ private:
COverlayExamplesMenu *m_pMenu;
OverlayExample_t m_delayedCommand;
std::string m_strLastGamePhaseIDToShow;
uint64 m_ulLastCrashIntoSunEventIDToShow = 0;
STEAM_CALLBACK( COverlayExamples, OnScreenshotRequested, ScreenshotRequested_t );
STEAM_CALLBACK( COverlayExamples, OnSteamScreenshotReady, ScreenshotReady_t );
// callback for when we ask about an event having recordings
void OnDoesEventRecordingExist( SteamTimelineEventRecordingExists_t *pCallback, bool bIOFailure );
CCallResult<COverlayExamples, SteamTimelineEventRecordingExists_t> m_SteamCallResultDoesEventRecordingExist;
// callback for when we ask about a phase having recordings
void OnDoesGamePhaseRecordingExist( SteamTimelineGamePhaseRecordingExists_t *pCallback, bool bIOFailure );
CCallResult<COverlayExamples, SteamTimelineGamePhaseRecordingExists_t> m_SteamCallResultDoesGamePhaseRecordingExist;
};
#endif // OVERLAYEXAMPLES_H
+75
View File
@@ -292,6 +292,12 @@ void CSpaceWarClient::DisconnectFromServer()
SteamUser()->BSetDurationControlOnlineState( k_EDurationControlOnlineState_Offline );
m_eConnectedStatus = k_EClientNotConnected;
UpdateScoreInGamePhase( true );
SteamTimeline()->EndGamePhase();
m_unLastGamePhaseID = m_unGamePhaseID;
m_unGamePhaseID = 0;
}
if ( m_pP2PAuthedGame )
{
@@ -454,9 +460,15 @@ void CSpaceWarClient::OnReceiveServerUpdate( ServerSpaceWarUpdateData_t *pUpdate
}
// Update scores
bool bScoresChanged = false;
for( int i=0; i < MAX_PLAYERS_PER_SERVER; ++i )
{
m_rguPlayerScores[i] = pUpdateData->GetPlayerScore(i);
bScoresChanged = bScoresChanged || m_rguPlayerScores[ i ] != pUpdateData->GetPlayerScore( i );
}
if ( bScoresChanged )
{
UpdateScoreInGamePhase( false );
}
// Update who won last
@@ -678,6 +690,12 @@ void CSpaceWarClient::InitiateServerConnection( CSteamID 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();
SteamTimeline()->StartGamePhase();
// When you call this function for real, you should use an ID that you'll refer back to
m_unGamePhaseID = Plat_GetTicks();
//SteamTimeline()->SetGamePhaseID( std::to_string( m_unGamePhaseID ).c_str() );
}
@@ -839,6 +857,15 @@ void CSpaceWarClient::ReceiveNetworkData()
m_pP2PAuthedGame->HandleP2PSendingTicket( message->GetData() );
break;
case k_EMsgServerPlayerHitSun:
{
TimelineEventHandle_t ulEvent = SteamTimeline()->StartRangeTimelineEvent( "Hit Sun", "This description will be replaced", "steam_8", 8, 0, k_ETimelineEventClipPriority_None );
SteamTimeline()->UpdateRangeTimelineEvent( ulEvent, nullptr, "It was too hot to handle", "steam_starburst", 10, k_ETimelineEventClipPriority_Standard );
SteamTimeline()->EndRangeTimelineEvent( ulEvent, 3.f );
m_ulLastCrashIntoSunEvent = 0;
}
break;
default:
OutputDebugString("Unhandled message from server\n");
break;
@@ -1224,6 +1251,7 @@ void CSpaceWarClient::OnGameStateChanged( EClientGameState eGameStateNew )
pchSteamRichPresenceDisplay = SetInGameRichPresence();
bDisplayScoreInRichPresence = true;
UpdateScoreInGamePhase( true );
}
else if ( m_eGameState == k_EClientLeaderboards )
{
@@ -1318,6 +1346,7 @@ void CSpaceWarClient::OnGameStateChanged( EClientGameState eGameStateNew )
}
//-----------------------------------------------------------------------------
// Purpose: Handles notification of a steam ipc failure
// we may get multiple callbacks, one for each IPC operation we attempted
@@ -2778,3 +2807,49 @@ void CSpaceWarClient::DrawWorkshopItems()
}
m_pGameEngine->BDrawString(m_hInstructionsFont, rect, D3DCOLOR_ARGB(255, 25, 200, 25), TEXTPOS_CENTER | TEXTPOS_TOP, rgchBuffer);
}
//-----------------------------------------------------------------------------
// Purpose: Draws PublishFileID, title & description for each subscribed Workshop item
//-----------------------------------------------------------------------------
void CSpaceWarClient::UpdateScoreInGamePhase( bool bFinal )
{
std::string strScores;
uint32 unHighScore = 0;
for ( int i = 0; i < MAX_PLAYERS_PER_SERVER; i++ )
{
if ( !strScores.empty() )
strScores += " / ";
strScores += std::to_string( m_rguPlayerScores[ i ] );
unHighScore = unHighScore < m_rguPlayerScores[ i ] ? m_rguPlayerScores[ i ] : unHighScore;
}
uint32 unCountAtHighScore = 0;
for ( int i = 0; i < MAX_PLAYERS_PER_SERVER; i++ )
{
if ( m_rguPlayerScores[ i ] == unHighScore )
unCountAtHighScore++;
}
std::string strPlayerScore = "0";
SteamTimeline()->SetGamePhaseAttribute( "Scores", strScores.c_str(), 1 );
SteamTimeline()->SetGamePhaseAttribute( "Player Score", strPlayerScore.c_str(), 2 );
if ( BLocalPlayerWonLastGame() )
{
SteamTimeline()->AddGamePhaseTag( "Won", "steam_ribbon", "Game Outcome", 3 );
}
else if ( unCountAtHighScore == 1 && unHighScore > 0 )
{
SteamTimeline()->AddGamePhaseTag( "Lost", "steam_death", "Game Outcome", 3 );
}
else if ( unCountAtHighScore > 1 && unHighScore > 0 )
{
SteamTimeline()->AddGamePhaseTag( "Tied", "steam_triangle", "Game Outcome", 3 );
}
else
{
SteamTimeline()->AddGamePhaseTag( "Stalemate", "steam_minus", "Game Outcome", 3 );
}
}
+11
View File
@@ -149,6 +149,8 @@ struct OverlayExample_t
k_EOverlayExampleItem_RequestKeyboard,
k_EOverlayExampleItem_Notification_SetInset,
k_EOverlayExampleItem_Notification_SetPosition,
k_EOverlayExampleItem_Timeline_OpenOverlayToTimelineEvent,
k_EOverlayExampleItem_Timeline_OpenOverlayToGamePhase,
};
EOverlayExampleItem m_eItem;
@@ -255,6 +257,9 @@ public:
void ExecCommandLineConnect( const char *pchServerAddress, const char *pchLobbyID );
void SetShowTimer( bool bShowTimer ) { m_bShowTimer = bShowTimer; }
uint32 GetLastGamePhaseID() const { return m_unLastGamePhaseID; }
uint64 GetLastCrashIntoSunEvent() const { return m_ulLastCrashIntoSunEvent; }
private:
// Receive a response from the server for a connection attempt
@@ -310,6 +315,9 @@ private:
// return the value that should go in steam_display
const char *SetInGameRichPresence() const;
// Sets the player scores in the game phase
void UpdateScoreInGamePhase( bool bFinal );
// load a workshop item from file
bool LoadWorkshopItem( PublishedFileId_t workshopItemID );
CWorkshopItem *LoadWorkshopItemFromFile( const char *pszFileName );
@@ -459,6 +467,9 @@ private:
CStatsAndAchievements *m_pStatsAndAchievements;
CTimeline *m_pTimeline;
uint32 m_unGamePhaseID = 0;
uint32 m_unLastGamePhaseID = 0;
uint64 m_ulLastCrashIntoSunEvent = 0;
CLeaderboards *m_pLeaderboards;
CFriendsList *m_pFriendsList;
+6
View File
@@ -847,6 +847,12 @@ void CSpaceWarServer::CheckForCollisions()
if ( m_rgpShips[i]->BCollidesWith( m_pSun ) )
{
{
MsgServerPlayerHitSun_t msg;
msg.SetSteamID( m_rgClientData[ i ].m_SteamIDUser );
BSendDataToClient( i, ( char * )&msg, sizeof( msg ) );
}
rgbExplodingShips[i] |= 1;
}
+19 -65
View File
@@ -42,7 +42,6 @@ CStatsAndAchievements::CStatsAndAchievements( IGameEngine *pGameEngine )
m_pSteamUser( NULL ),
m_pSteamUserStats( NULL ),
m_GameID( SteamUtils()->GetAppID() ),
m_CallbackUserStatsReceived( this, &CStatsAndAchievements::OnUserStatsReceived ),
m_CallbackUserStatsStored( this, &CStatsAndAchievements::OnUserStatsStored ),
m_CallbackAchievementStored( this, &CStatsAndAchievements::OnAchievementStored ),
m_CallbackPS3TrophiesInstalled( this, &CStatsAndAchievements::OnPS3TrophiesInstalled )
@@ -50,7 +49,6 @@ CStatsAndAchievements::CStatsAndAchievements( IGameEngine *pGameEngine )
m_pSteamUser = SteamUser();
m_pSteamUserStats = SteamUserStats();
m_bRequestedStats = false;
m_bStatsValid = false;
m_bStoreStats = false;
@@ -102,29 +100,9 @@ void CStatsAndAchievements::RunFrame()
m_bStartedPS3TrophyInstall = true;
#endif
}
else if ( !m_bRequestedStats )
{
// Is Steam Loaded? if no, can't get stats, done
if ( NULL == m_pSteamUserStats || NULL == m_pSteamUser )
{
m_bRequestedStats = true;
return;
}
LoadUserStatsOnPS3();
// If yes, request our stats
bool bSuccess = m_pSteamUserStats->RequestCurrentStats();
// This function should only return false if we weren't logged in, and we already checked that.
// But handle it being false again anyway, just ask again later.
m_bRequestedStats = bSuccess;
}
if ( !m_bStatsValid )
return;
// Get info from sources
LoadUserStats();
// Evaluate achievements
for ( int iAch = 0; iAch < ARRAYSIZE( g_rgAchievements ); ++iAch )
@@ -290,49 +268,29 @@ void CStatsAndAchievements::StoreStatsIfNecessary()
// Purpose: We have stats data from Steam. It is authoritative, so update
// our data with those results now.
//-----------------------------------------------------------------------------
void CStatsAndAchievements::OnUserStatsReceived( UserStatsReceived_t *pCallback )
void CStatsAndAchievements::LoadUserStats()
{
if ( !m_pSteamUserStats )
return;
// we may get callbacks for other games' stats arriving, ignore them
if ( m_GameID.ToUint64() == pCallback->m_nGameID )
// load achievements
for ( int iAch = 0; iAch < ARRAYSIZE( g_rgAchievements ); ++iAch )
{
if ( k_EResultOK == pCallback->m_eResult )
{
OutputDebugString( "Received stats and achievements from Steam\n" );
m_bStatsValid = true;
// load achievements
for ( int iAch = 0; iAch < ARRAYSIZE( g_rgAchievements ); ++iAch )
{
Achievement_t &ach = g_rgAchievements[iAch];
m_pSteamUserStats->GetAchievement( ach.m_pchAchievementID, &ach.m_bAchieved );
sprintf_safe( ach.m_rgchName, "%s",
m_pSteamUserStats->GetAchievementDisplayAttribute( ach.m_pchAchievementID, "name" ) );
sprintf_safe( ach.m_rgchDescription, "%s",
m_pSteamUserStats->GetAchievementDisplayAttribute( ach.m_pchAchievementID, "desc" ) );
}
// load stats
m_pSteamUserStats->GetStat( "NumGames", &m_nTotalGamesPlayed );
m_pSteamUserStats->GetStat( "NumWins", &m_nTotalNumWins );
m_pSteamUserStats->GetStat( "NumLosses", &m_nTotalNumLosses );
m_pSteamUserStats->GetStat( "FeetTraveled", &m_flTotalFeetTraveled );
m_pSteamUserStats->GetStat( "MaxFeetTraveled", &m_flMaxFeetTraveled );
m_pSteamUserStats->GetStat( "AverageSpeed", &m_flAverageSpeed );
SaveUserStatsOnPS3();
}
else
{
char buffer[128];
sprintf_safe( buffer, "RequestStats - failed, %d\n", pCallback->m_eResult );
buffer[ sizeof(buffer) - 1 ] = 0;
OutputDebugString( buffer );
}
Achievement_t &ach = g_rgAchievements[iAch];
m_pSteamUserStats->GetAchievement( ach.m_pchAchievementID, &ach.m_bAchieved );
sprintf_safe( ach.m_rgchName, "%s", m_pSteamUserStats->GetAchievementDisplayAttribute( ach.m_pchAchievementID, "name" ) );
sprintf_safe( ach.m_rgchDescription, "%s", m_pSteamUserStats->GetAchievementDisplayAttribute( ach.m_pchAchievementID, "desc" ) );
}
// load stats
m_pSteamUserStats->GetStat( "NumGames", &m_nTotalGamesPlayed );
m_pSteamUserStats->GetStat( "NumWins", &m_nTotalNumWins );
m_pSteamUserStats->GetStat( "NumLosses", &m_nTotalNumLosses );
m_pSteamUserStats->GetStat( "FeetTraveled", &m_flTotalFeetTraveled );
m_pSteamUserStats->GetStat( "MaxFeetTraveled", &m_flMaxFeetTraveled );
m_pSteamUserStats->GetStat( "AverageSpeed", &m_flAverageSpeed );
m_bStatsValid = true;
}
@@ -354,11 +312,7 @@ void CStatsAndAchievements::OnUserStatsStored( UserStatsStored_t *pCallback )
// One or more stats we set broke a constraint. They've been reverted,
// and we should re-iterate the values now to keep in sync.
OutputDebugString( "StoreStats - some failed to validate\n" );
// Fake up a callback here so that we re-load the values.
UserStatsReceived_t callback;
callback.m_eResult = k_EResultOK;
callback.m_nGameID = m_GameID.ToUint64();
OnUserStatsReceived( &callback );
LoadUserStats();
}
else
{
+3 -4
View File
@@ -56,14 +56,14 @@ public:
float GetGameFeetTraveled() { return m_flGameFeetTraveled; }
double GetGameDurationSeconds() { return m_flGameDurationSeconds; }
STEAM_CALLBACK( CStatsAndAchievements, OnUserStatsReceived, UserStatsReceived_t, m_CallbackUserStatsReceived );
STEAM_CALLBACK( CStatsAndAchievements, OnUserStatsStored, UserStatsStored_t, m_CallbackUserStatsStored );
STEAM_CALLBACK( CStatsAndAchievements, OnAchievementStored, UserAchievementStored_t, m_CallbackAchievementStored );
STEAM_CALLBACK( CStatsAndAchievements, OnPS3TrophiesInstalled, PS3TrophiesInstalled_t, m_CallbackPS3TrophiesInstalled );
private:
void LoadUserStats();
// Determine if we get this achievement now
void EvaluateAchievement( Achievement_t &achievement );
void UnlockAchievement( Achievement_t &achievement );
@@ -96,7 +96,6 @@ private:
HGAMEFONT m_hDisplayFont;
// Did we get the stats from Steam?
bool m_bRequestedStats;
bool m_bStatsValid;
// Should we store stats this frame?
@@ -120,4 +119,4 @@ private:
bool m_bInstalledPS3Trophies;
};
#endif // STATS_AND_ACHIEVEMENTS_H
#endif // STATS_AND_ACHIEVEMENTS_H
+4 -4
View File
@@ -76,7 +76,7 @@ void CTimeline::OnGameStateChange( EClientGameState eNewState )
float flDurationSeconds = (float)unSessionDuration / 1000.f;
float flStartOffsetSeconds = -flDurationSeconds;
SteamTimeline()->AddTimelineEvent( "steam_starburst", "In Match", nullptr, 100, flStartOffsetSeconds, flDurationSeconds, k_ETimelineEventClipPriority_None );
SteamTimeline()->AddRangeTimelineEvent( "In Match", nullptr, "steam_starburst", 100, flStartOffsetSeconds, flDurationSeconds, k_ETimelineEventClipPriority_None );
}
m_bInGame = bInGameNow;
@@ -85,11 +85,11 @@ void CTimeline::OnGameStateChange( EClientGameState eNewState )
// add a highlight marker every time the player wins
if ( eNewState == k_EClientGameWinner && SpaceWarClient()->BLocalPlayerWonLastGame() )
{
SteamTimeline()->AddTimelineEvent( "steam_attack", "Winner!", "You won a round!", 10, 0, 0, k_ETimelineEventClipPriority_Standard );
SteamTimeline()->AddInstantaneousTimelineEvent( "Winner!", "You won a round!", "steam_attack", 10, 0, k_ETimelineEventClipPriority_Standard );
}
else if ( eNewState == k_EClientGameDraw )
{
SteamTimeline()->AddTimelineEvent( "steam_defend", "Draw", "This round was a draw.", 5, 0, 0, k_ETimelineEventClipPriority_None );
SteamTimeline()->AddInstantaneousTimelineEvent( "Draw", "This round was a draw.", "steam_defend", 5, 0, k_ETimelineEventClipPriority_None );
}
}
@@ -113,7 +113,7 @@ void CTimeline::RunFrame()
// max string length is "95:00"
char rgchBuffer[ 6 ];
sprintf_safe( rgchBuffer, "%02d:00", unTimestampIndex * k_unMinutesBetweenTimestamps );
SteamTimeline()->SetTimelineStateDescription( rgchBuffer, 0 );
SteamTimeline()->SetTimelineTooltip( rgchBuffer, 0 );
m_unLastTimestampIndexDisplayed = unTimestampIndex;
}