Files

63 lines
5.3 KiB
Python

"""Production server ledger and permit handshake with native owner RPC substituted."""
from policy_harness import ROOT,body,run
p=ROOT/'addons/core/Scripts/Game/ERR/00_Core/ERR_WelcomeIdentity.c'
claim=body(p,'bool Claim(').replace('m_Claimed.','m_Claimed.').replace('UUID identity','UUID identity')
methods='\n'.join(body(p,k) for k in ['bool ERR_WelcomePermit(', 'protected void ERR_RequestWelcomePermit(', 'protected void ERR_ReceiveWelcomePermit('])
methods=methods.replace('protected ', '').replace('ERR_GameMode mode','ERR_GameMode* mode').replace('ERR_PlayerLife life','ERR_PlayerLife* life').replace('null','nullptr')
for obj in ['mode','life']:methods=methods.replace(obj+'.',obj+'->')
for kind in ['ERR_GameMode','Replication','ERR_WelcomeVoiceRules']:methods=methods.replace(kind+'.',kind+'::')
methods=methods.replace('GetGame().','GetGame()->').replace('GetWorld().','GetWorld()->').replace('GetPlayerManager().','GetPlayerManager()->').replace('Players().','Players()->')
methods=methods.replace('Rpc(ERR_RequestWelcomePermit, serial)', 'SendRequest(serial)').replace('Rpc(ERR_ReceiveWelcomePermit, serial, m_ERRWelcomeServerGranted)', 'SendReply(serial, m_ERRWelcomeServerGranted)')
run(r'''
#include <cassert>
#include <set>
#include <string>
struct UUID {int value=0; bool IsNull(){return value==0;}bool operator<(UUID b)const{return value<b.value;}};
struct Claims {std::set<UUID> values;int Find(UUID id){return values.count(id)?0:-1;}int Count(){return values.size();}void Insert(UUID id){values.insert(id);}};
struct Ledger {Claims m_Claimed;
'''+claim+r'''
};
struct Controller;
struct ERR_PlayerLife {int ConnectionId=1;UUID AccountId{7};};
struct Roster {ERR_PlayerLife life;bool valid=true;ERR_PlayerLife* CurrentActor(bool actor){return actor&&valid?&life:nullptr;}};
struct ERR_GameMode {bool active=true,pending=false;std::string url="clip";Roster roster;static ERR_GameMode* current;static ERR_GameMode* Get(){return current;}
bool Active(){return active;}bool ERR_WelcomePending(){return pending;}std::string ERR_WelcomeVoiceURL(){return url;}Roster* Players(){return &roster;}};
ERR_GameMode* ERR_GameMode::current;
namespace Replication {bool server=true;bool IsServer(){return server;}}
struct ERR_WelcomeVoiceRules {static bool Source(std::string s){return !s.empty();}};
struct Game {Controller* owner=nullptr;Controller* canonical=nullptr;float now=1000;Ledger ledger;Controller* GetPlayerController(){return owner;}
Game* GetWorld(){return this;}Game* GetPlayerManager(){return this;}float GetWorldTime(){return now;}Controller* GetPlayerController(int){return canonical;}
bool ERR_ClaimWelcomeIdentity(UUID id){return ledger.Claim(id);}} game;
Game* GetGame(){return &game;}
struct Controller {
int m_ERRWelcomeSerial=0,m_ERRWelcomeDecision=0,m_ERRWelcomeServerSerial=0;bool m_ERRWelcomeServerGranted=false;
float m_ERRWelcomeRetry=0,m_ERRWelcomeServerReply=-1000;bool body=true,dropReply=false;int requests=0,replies=0;
bool GetControlledEntity(){return body;}
void SendRequest(int serial){requests++;ERR_RequestWelcomePermit(serial);}
void SendReply(int serial,bool granted){replies++;if(!dropReply)ERR_ReceiveWelcomePermit(serial,granted);}
'''+methods+r'''
};
int main(){
ERR_GameMode mode;ERR_GameMode::current=&mode;Controller first;game.owner=game.canonical=&first;
mode.url="";assert(!first.ERR_WelcomePermit(1));assert(game.ledger.m_Claimed.Count()==0);
game.now+=2001;mode.url="clip";mode.roster.valid=false;assert(!first.ERR_WelcomePermit(1));assert(game.ledger.m_Claimed.Count()==0);
game.now+=2001;mode.roster.valid=true;mode.pending=true;assert(!first.ERR_WelcomePermit(1));assert(game.ledger.m_Claimed.Count()==0);
game.now+=2001;mode.pending=false;first.dropReply=true;assert(!first.ERR_WelcomePermit(1));assert(game.ledger.m_Claimed.Count()==1);
assert(!first.ERR_WelcomePermit(1));int before=first.requests;
game.now+=2001;first.dropReply=false;assert(first.ERR_WelcomePermit(1));assert(first.requests==before+1); // idempotent retry
first.ERR_ReceiveWelcomePermit(0,false);assert(first.ERR_WelcomePermit(1)); // stale reply
Controller crashedClient;game.owner=game.canonical=&crashedClient;game.now+=2001;
assert(!crashedClient.ERR_WelcomePermit(1));assert(crashedClient.m_ERRWelcomeDecision==-1); // new process/controller, same account
before=crashedClient.requests;game.now+=9999;assert(!crashedClient.ERR_WelcomePermit(1));assert(crashedClient.requests==before);
Controller otherAccount;game.owner=game.canonical=&otherAccount;mode.roster.life.AccountId={8};assert(otherAccount.ERR_WelcomePermit(1));
// Reused IDs are scoped to authenticated account. A previous controller cannot claim a new account.
Controller stale;game.owner=&stale;game.now+=2001;assert(!stale.ERR_WelcomePermit(1));assert(game.ledger.m_Claimed.Count()==2);
game.owner=game.canonical=&crashedClient;mode.roster.life.AccountId={7};game.now+=2001;
assert(!crashedClient.ERR_WelcomePermit(2)); // round/client serial changes do not reset ledger
assert(!game.ledger.Claim(UUID{0}));
Ledger nextServer;assert(nextServer.Claim(UUID{7})); // actual server process restart starts a new session
Ledger capped;for(int i=1;i<=10000;i++)assert(capped.Claim(UUID{i}));assert(!capped.Claim(UUID{10001}));
}
''')
print('PASS: account greeting survives client/controller/round changes; owner validation, delayed readiness, idempotent retry, stale replies and bounded ledger')