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

217 lines
4.5 KiB
Ucode

Class DatabaseUdpLink extends UdpLink;
var string PendingLine;
var IpAddr A;
var ServerPerksMut Mut;
var array<StatsObject> ToSave;
var array<ServerStStats> PendingData;
var transient float NextReqTimer;
var bool bConnectionReady,bHasPendingLine;
var byte LoopCounter;
enum ENetID
{
ID_None,
ID_Open,
ID_RequestPassword,
ID_HeresPassword,
ID_ConnectionClosed,
ID_PasswordCorrect,
ID_NewPlayer,
ID_BadNewPlayer,
ID_SendPlayerData,
ID_UpdatePlayer,
ID_KeepAlive,
};
function PostBeginPlay()
{
Disable('Tick');
}
function BeginEvent()
{
Mut.SaveAllStats = SaveAllStats;
Mut.RequestStats = RequestStats;
ReceiveMode = RMODE_Event;
if( BindPort(Rand(8000)+8000,true)>0 )
Resolve(Mut.RemoteDatabaseURL);
}
event Resolved( IpAddr Addr )
{
A = Addr;
A.Port = Mut.RemotePort;
SendText(A,Chr(ENetID.ID_Open));
Enable('Tick');
NextReqTimer = Level.TimeSeconds+5.f;
}
function Tick( float Delta ) // Every 5 seconds, try to open connection again.
{
if( !bConnectionReady && NextReqTimer<Level.TimeSeconds )
{
NextReqTimer = Level.TimeSeconds+5.f;
SendText(A,Chr(ENetID.ID_Open));
}
}
event ReceivedText( IpAddr Addr, string Text )
{
local byte First;
if( bHasPendingLine )
{
if( Asc(Right(Text,1))!=10 )
PendingLine = PendingLine$Text;
else
{
ReceivedPlayerData(PendingLine$Left(Text,Len(Text)-1));
PendingLine = "";
bHasPendingLine = false;
}
return;
}
First = Asc(Left(Text,1));
Text = Mid(Text,1);
if( Mut.bDebugDatabase )
Level.Game.Broadcast(Self,"Receive "$GetEnum(enum'ENetID',First)$": "$Text);
switch( First )
{
case ENetID.ID_PasswordCorrect:
bConnectionReady = true;
break;
case ENetID.ID_RequestPassword:
bConnectionReady = false;
SendText(A,Chr(ENetID.ID_HeresPassword)$Mut.RemotePassword);
break;
case ENetID.ID_ConnectionClosed:
bConnectionReady = false;
SendText(A,Chr(ENetID.ID_Open));
break;
case ENetID.ID_KeepAlive:
SendText(A,Chr(ENetID.ID_KeepAlive));
break;
case ENetID.ID_NewPlayer:
ReceivedPlayerID(Text);
break;
case ENetID.ID_SendPlayerData:
if( Asc(Right(Text,1))!=10 )
{
PendingLine = Text;
bHasPendingLine = true;
break;
}
ReceivedPlayerData(Left(Text,Len(Text)-1));
break;
default:
}
}
function SaveAllStats()
{
local int i;
ToSave = Mut.ActiveStats;
for( i=0; i<ToSave.Length; ++i )
{
if( !ToSave[i].bStatsChanged )
ToSave.Remove(i--,1);
}
if( ToSave.Length>0 )
GoToState('SaveAll');
}
function RequestStats( ServerStStats Other )
{
local int i;
if( !bConnectionReady )
return;
SendText(A,Chr(ENetID.ID_NewPlayer)$Other.MyStatsObject.Name$"*"$Mut.GetSafeName(Other.PlayerOwner.PlayerReplicationInfo.PlayerName));
for( i=0; i<PendingData.Length; ++i )
if( PendingData[i]==Other )
return;
PendingData[PendingData.Length] = Other;
}
final function ReceivedPlayerID( string S )
{
local int i,RID;
i = InStr(S,"|");
RID = int(Left(S,i));
S = Mid(S,i+1);
for( i=0; i<PendingData.Length; ++i )
{
if( PendingData[i]==None )
PendingData.Remove(i--,1);
else if( S~=string(PendingData[i].MyStatsObject.Name) )
{
PendingData[i].SetID(RID);
break;
}
}
}
final function ReceivedPlayerData( string S )
{
local int i,RID;
i = InStr(S,"|");
RID = int(Left(S,i));
S = Mid(S,i+1);
for( i=0; i<PendingData.Length; ++i )
{
if( PendingData[i]==None )
PendingData.Remove(i--,1);
else if( RID==PendingData[i].GetID() )
{
PendingData[i].GetData(S);
PendingData.Remove(i,1);
break;
}
}
}
State SaveAll
{
function BeginState()
{
SetTimer(0.05,true);
}
function EndState()
{
SetTimer(0,false);
}
function Timer()
{
local StatsObject S;
local string Line;
if( !bConnectionReady )
return;
S = ToSave[0];
if( Mut.bDebugDatabase )
Level.Game.Broadcast(Self,"Send Player stats: "$S.Name$" ("$(ToSave.Length-1)$" remain)");
S.bStatsChanged = false;
Line = Chr(ENetID.ID_UpdatePlayer)$S.ID$"|"$S.GetSaveData()$Chr(10);
while( Len(Line)>512 )
{
SendText(A,Left(Line,512));
Line = Mid(Line,512);
}
SendText(A,Line);
ToSave.Remove(0,1);
if( ToSave.Length==0 )
GoToState('');
}
Begin:
while( ++LoopCounter<150 )
{
if( Level.bLevelChange ) // Delay mapchange until all stats are uploaded.
Level.NextSwitchCountdown = FMax(Level.NextSwitchCountdown,1.f);
Sleep(0.5);
}
}
defaultproperties
{
}