rott/kf_sources/Engine/Classes/SteamStatsAndAchievementsBase.uc
2026-07-14 20:27:09 +07:00

270 lines
10 KiB
Ucode

//=============================================================================
// SteamStatsAndAchievementsBase
//=============================================================================
// Interface between Steam Stats/Achievements and RO/Mods
//=============================================================================
// Red Orchestra Source
// Copyright (C) 2003-2009 Tripwire Interactive LLC
// Created by Dayle Flowers
//=============================================================================
class SteamStatsAndAchievementsBase extends Actor
native;
struct native export SteamStatInt
{
var const int Value; // Value of this Stat(can be set by calling SetStatInt)
};
struct native export SteamStatFloat
{
var const float Value; // Value of this Stat(can be set by calling SetStatFloat)
};
// Steam updates an Averaging stat by adding SessionNumerator to the existing Numerator in the Steam Database and SessionDenominator
// to the existing Denominator in the Steam Database(which only exists on the client). These stats are only able to be grabbed as
// floats from Steam, but when the client sends the new Session Values Averages to Steam, the Steam Database does a full Numerator
// over Denominator calculation with the new Session Data. In short, this is not a reliable system for checking Achievements on the
// Server in real-time, as you only get the resulting Float *after* the client sends the data to Steam and the Steam Database has
// time to recalculate the new average. The latest Float Value is only valid in OnStatsAndAchievementsReady and should not be
// considered reliable outside of that function.
struct native export SteamStatAverage
{
var const float NumeratorValue; // Numerator Value of this Stat during this Session
var const float DenominatorValue; // Denominator Value of this Stat during this Session
};
// Set to true once we've pulled Stats from the Database(prevents Steam screwing up and erasing Stats in Single Player)
var bool bInitialized;
// Owner of these Stats and Achievements
var PlayerController PCOwner;
// Set to true by the Timer function to allow us to completely control replication
var bool bFlushStatsToClient;
// Number of seconds between sending Stats to client
var float FlushStatsToClientDelay;
// Steam Names
var array<string> SteamNameStat;
var array<string> SteamNameAchievement;
// Used to track if God Mode, weapon cheats, summoning, and others have ever been used
var bool bUsedCheats;
// Debug
var globalconfig bool bResetStats;
var globalconfig bool bDebugStats;
// Delegate callback for Stats and Achievements data initialization completion
delegate OnDataInitialized();
// Gets the Server ready to handle Stats
native final function bool Initialize(PlayerController MyOwner);
// Requests the Owner's Stats and Achievements from Steam(calls OnStatsAndAchievementsReady when completed)
native final function GetStatsAndAchievements();
// Functions to grab individual Stats and Achievements from Steam by name(generally done from the OnStatsAndAchievementsReady callback)
native final function GetStatInt(SteamStatInt Stat, string SteamName);
native final function GetStatFloat(SteamStatFloat Stat, string SteamName);
native final function float GetStatAverage(string SteamName);
native final function bool GetAchievementCompleted(string SteamName);
// Used to natively Initialize the const Stat Variables(Server-side only)
native final function InitStatInt(SteamStatInt Stat, int NewValue);
native final function InitStatFloat(SteamStatFloat Stat, float NewValue);
// Used to natively Set the const Stat Variables(Server-side only)
native final function SetStatInt(SteamStatInt Stat, int NewValue);
native final function SetStatFloat(SteamStatFloat Stat, float NewValue);
native final function SetStatAverage(SteamStatAverage Stat, float NewNumerator, float NewDenominator);
// Called to set bNetDirty which forces replication to the owning client at a preset interval
native final function SetNetDirty();
// Send the specified Int/Float/Stat to the Local Steam Client, not the Steam Database(Client-Side only)
// NOTE: For Average stats, we send Stat.Numerator - SavedStat.Numerator and Stat.Denominator - SavedStat.Denominator,
// because Steam is keeping a running total behind the scenes.
native final function FlushStatToSteamInt(SteamStatInt Stat, string SteamName);
native final function FlushStatToSteamFloat(SteamStatFloat Stat, string SteamName);
native final function FlushStatToSteamAverage(SteamStatAverage Stat, SteamStatAverage SavedStat, string SteamName);
native final function SetAchievementCompleted(string SteamName);
// Call after all Stats have been changed on the Client to send changed stats from the local Steam Client to the Steam Database
native final function FlushStatsToSteamDatabase();
// Returns the displayable information set in the SteamWork's Database
native final function GetAchievementDescription(string SteamName, out string DisplayName, out string Description);
native simulated final function bool DoPotato();
// Returns an integer representation of Owned Weapon DLC Packs
native final function int GetOwnedWeaponDLC();
// Determines whether or not this player owns a particular Weapon DLC AppID
simulated function bool PlayerOwnsWeaponDLC(int AppID);
native final function bool OwnsWeaponDLC(int AppID, SteamStatInt OwnedWeaponDLCStat);
// Opens the Steam Store page for the specified AppID
native final function PurchaseWeaponDLC(int AppID);
// Fetches the name of the specified Weapons DLC Pack
function string GetWeaponDLCPackName(int AppID);
// Opens the Steam Overlay directly to the Game's Steam Workshop page
native final function ShowWorkshopContent();
// Fetches a user ID for the owning PC
native final function string GetSteamUserID();
cpptext
{
#include "SteamStatsAndAchievementsBase.h"
}
replication
{
reliable if ( Role == ROLE_Authority )
bUsedCheats;
}
// Called via Client to Server function in PlayerController to start the FlushStatsToClient timing
function ServerSteamStatsAndAchievementsInitialized()
{
if ( bDebugStats )
log("STEAMSTATS: ServerSteamStatsAndAchievementsInitialized called");
bInitialized = true;
SetTimer(FlushStatsToClientDelay, false);
}
event PostBeginPlay()
{
PlayerDied();
}
// Overridden to Grab the Stats and Achievements from Steam on the Client
simulated event PostNetBeginPlay()
{
if ( Level.NetMode == NM_Client )
{
if ( bDebugStats )
log("STEAMSTATS: PostNetBeginPlay grabbing Stats - StatsObject="$self);
GetStatsAndAchievements();
PCOwner = Level.GetLocalPlayerController();
}
}
// Overridden in subclasses to send the Stats/Achievements that have changed to Steam
//simulated event PostNetReceive();
// Called at set interval to push all Stats to Client, then called again to reset
// NETWORK: Server only
event Timer()
{
// We use bFlushStatsToClient to control when things are sent
if ( !bFlushStatsToClient )
{
FlushStatsToClient();
}
// Soon after FlushStatsToClientw is called above, Timer gets called again to clear bFlushStatsToClient
else
{
bFlushStatsToClient = false;
SetTimer(FlushStatsToClientDelay, false);
}
}
// Called on Server(via Timer) to push all Stats to Client
// NETWORK: Server only
function FlushStatsToClient()
{
// if it's a local player, just send stuff off to Steam from here
if ( Level.NetMode == NM_Standalone || (Level.NetMode == NM_ListenServer && PCOwner == Level.GetLocalPlayerController()) )
{
PostNetReceive();
SetTimer(FlushStatsToClientDelay, false);
}
else
{
if ( bDebugStats )
log("STEAMSTATS: Flushing Stats to Client");
// Force Stats to be sent to Client immediately
NetUpdateTime = Level.TimeSeconds - 1.0;
bFlushStatsToClient = true;
SetNetDirty();
// Clear bFlushStatsToClient once completed
SetTimer(0.1, false);
}
}
// Event Callback for GetStatsAndAchievements call(Call PCOwner.ServerSteamStatsAndAchievementsInitialized when done)
// NETWORK: Client only
simulated event OnStatsAndAchievementsReady()
{
if ( PCOwner != none && PCOwner.PlayerReplicationInfo != none )
{
PCOwner.PlayerReplicationInfo.SteamStatsAndAchievements = self;
}
bInitialized = true;
PCOwner.ServerSteamStatsAndAchievementsInitialized();
OnDataInitialized();
}
// Called on Server to initialize Stats from Client replication, because Servers can't access Steam Stats directly
function InitializeSteamStatInt(int Index, int Value);
// Called on Server to initialize Stats from Client replication, because Servers can't access Steam Stats directly
function InitializeSteamStatFloat(int Index, float Value);
// Sets the specified Steam Achievement as completed; also, flushes all Stats and Achievements to the client
function SetSteamAchievementCompleted(int Index)
{
if( PCOwner.PlayerReplicationInfo.bOnlySpectator )
{
return;
}
if ( bDebugStats )
log("STEAMSTATS: SetSteamAchievementCompleted called - Name="$SteamNameAchievement[Index] @ "Player="$PCOwner.PlayerReplicationInfo.PlayerName);
FlushStatsToClient();
SetLocalAchievementCompleted(Index);
SetAchievementCompleted(SteamNameAchievement[Index]);
}
// Called from multiple locations on Client and Server to set Achievement booleans for later use
simulated event SetLocalAchievementCompleted(int Index);
// Called when the owner of this Stats Actor dies(used in subclasses to reset "in one life" stats)
function PlayerDied();
native function SteamAPICall(string callString);
function CheckEvents( Name EventName );
defaultproperties
{
FlushStatsToClientDelay=10.0
RemoteRole=ROLE_SimulatedProxy
bAlwaysRelevant=false
bOnlyRelevantToOwner=true
bOnlyDirtyReplication=true
bSkipActorPropertyReplication=true
bNetNotify=true
NetUpdateFrequency=5
bStatic=false
bNoDelete=false
bHidden=true
}