Capture current mission, AI, map and administration development
Include the current addon, terrain integrations, tools, regression tests and recorded development evidence.
This commit is contained in:
@@ -4,21 +4,24 @@ from policy_harness import ROOT, body, run
|
||||
MODE = ROOT/'addons/core/Scripts/Game/ERR/00_Core/ERR_GameMode.c'
|
||||
SPAWN = ROOT/'addons/core/Scripts/Game/ERR/00_Core/ERR_SpawnLogic.c'
|
||||
def cpp(s):
|
||||
# Test mission scheduling inside the existing performance wrapper.
|
||||
s=s.replace('ServerTickMeasured(', 'ServerTick(').replace('System.', 'System::').replace('ERR_PerfMetric.', 'ERR_PerfMetric::').replace('int perfStamp;', 'int perfStamp=0;')
|
||||
s=s.replace('ERR_HQ.Event','ERR_HQ::Event').replace('protected ', '').replace('Replication.IsServer()', 'server').replace('Replication.BumpMe()', '(void)0')
|
||||
s=s.replace('array<int> connected = {};','std::vector<int> connected;').replace('connected.IsEmpty()', 'connected.empty()')
|
||||
s=s.replace('foreach (int id : connected)', 'for (int id : connected)')
|
||||
s=s.replace('ERR_PlayerLife life', 'Life* life').replace('SCR_PlayerController controller', 'Controller* controller').replace('PlayerController controller', 'Controller* controller')
|
||||
s=s.replace('SCR_PlayerController.Cast(', 'Controller::Cast(').replace('ERR_Phase.DEFEAT','5').replace('ERR_Phase.RADIO_SEARCH','2')
|
||||
for v in ('m_Roster','controller','life','m_Command','m_Extraction','m_RadioDefence','m_Recovery','GetGame()','GetWorld()','GetPlayerManager()'):
|
||||
for v in ('m_Performance','m_Roster','controller','life','m_Command','m_CivilianTraffic','m_Extraction','m_RadioDefence','m_Recovery','GetGame()','GetWorld()','GetPlayerManager()'):
|
||||
s=s.replace(v+'.', v+'->')
|
||||
return s
|
||||
methods='\n'.join(cpp(body(MODE,x)) for x in ('void InitialAdmissionStarted(', 'void InitialAdmissionExhausted(', 'protected bool InitialAdmissionsExhausted(', 'protected void ServerTick('))
|
||||
methods='\n'.join(cpp(body(MODE,x)) for x in ('void InitialAdmissionStarted(', 'void InitialAdmissionExhausted(', 'protected bool InitialAdmissionsExhausted(', 'protected void ServerTickMeasured('))
|
||||
run(r'''
|
||||
#include <cassert>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
bool server=true;
|
||||
template<class... T>void PrintFormat(const char*,T...){}
|
||||
struct Controller {void* actor=nullptr;void* GetControlledEntity(){return actor;}static Controller* Cast(Controller* c){return c;}void ERR_UpdateObserverServer(){}};
|
||||
struct Life {bool Connected=true,UsedLife=false;void* Actor=nullptr;};
|
||||
struct Roster {std::map<int,Life> lives;bool survivor=false;Life* Get(int id){auto i=lives.find(id);return i==lives.end()?nullptr:&i->second;}bool HasSurvivor(){return survivor;}};
|
||||
@@ -28,11 +31,15 @@ struct World {float now=0;float GetWorldTime(){return now;}} world;
|
||||
struct ERR_HQ {static void Event(std::string,std::string){}};
|
||||
struct Service {bool defeat=false;bool DefeatDue(float){return defeat;}void Tick(float=0){}void Maintain(float){}void Invoke(float){}};
|
||||
struct Exhausted {std::map<int,Controller*> values;void Remove(int id){values.erase(id);}void Set(int id,Controller* c){values[id]=c;}bool Contains(int id){return values.count(id);}Controller* Get(int id){return values.at(id);}};
|
||||
namespace System {int GetTickCount(){return 0;}}
|
||||
namespace ERR_PerfMetric {enum {MAINTENANCE,CIVILIANS,FORCES,OBSERVERS,HQ_TICK,LISTENERS};}
|
||||
struct Performance {int Mark(int,int stamp){return stamp;}void Stop(int){}};
|
||||
struct Mode {
|
||||
Performance* m_Performance=nullptr;
|
||||
void TickForces(float){}
|
||||
bool m_StartedPlayers=false;int m_Phase=1;float m_NoSurvivorsSince=-1;std::string m_EndReason;
|
||||
Exhausted m_ExhaustedInitialAdmissions;Roster roster;Roster* m_Roster=&roster;
|
||||
Service service,m_OnTick;Service *m_Extraction=&service,*m_RadioDefence=&service,*m_Recovery=&service,*m_Command=&service;
|
||||
Service service,m_OnTick;Service *m_Extraction=&service,*m_RadioDefence=&service,*m_Recovery=&service,*m_Command=&service,*m_CivilianTraffic=nullptr;
|
||||
World* GetWorld(){return &world;}bool Active(){return m_Phase>0&&m_Phase<5;}void Transition(int p){m_Phase=p;}bool RefreshRadioFeedback(){return false;}
|
||||
'''+methods+r'''
|
||||
};
|
||||
@@ -68,6 +75,20 @@ int main(){
|
||||
if(fault==0){server=false;}if(fault==1){f.m.m_Phase=0;}if(fault==2){f.m.m_Phase=5;}
|
||||
if(fault==3){f.m.m_StartedPlayers=true;}if(fault==4){game.players.connected[1]=&f.second;}if(fault==5){f.m.roster.lives.clear();}
|
||||
f.exhaust();assert(f.m.m_ExhaustedInitialAdmissions.values.empty());}
|
||||
// Empty server must retire a played round after the last reserved body expires.
|
||||
{Fixture f;f.m.m_StartedPlayers=true;f.m.roster.lives[1].UsedLife=true;
|
||||
game.players.connected.clear();f.m.roster.survivor=true;
|
||||
f.tick(900000);assert(f.m.Active()&&f.m.m_NoSurvivorsSince==-1);
|
||||
f.m.roster.survivor=false;f.tick(901000);assert(f.m.m_NoSurvivorsSince==901000);
|
||||
f.tick(930999);assert(f.m.Active());f.tick(931000);
|
||||
assert(!f.m.Active()&&f.m.m_EndReason=="No surviving prisoners remain.");}
|
||||
// A new empty round waits indefinitely; it must not restart in a loop.
|
||||
{Fixture f;game.players.connected.clear();f.tick(0);f.tick(36000000);
|
||||
assert(f.m.Active()&&f.m.m_NoSurvivorsSince==-1);}
|
||||
// A valid reservation/recovered survivor cancels a pending empty-server loss.
|
||||
{Fixture f;f.m.m_StartedPlayers=true;game.players.connected.clear();f.tick(0);
|
||||
f.m.roster.survivor=true;f.tick(29999);f.tick(60000);
|
||||
assert(f.m.Active()&&f.m.m_NoSurvivorsSince==-1);}
|
||||
// Existing actual first spawn changes participation; normal death grace is unchanged.
|
||||
{Fixture f;f.exhaust();f.m.InitialAdmissionStarted(1);f.m.m_StartedPlayers=true;f.m.roster.lives[1].UsedLife=true;f.m.roster.survivor=true;
|
||||
f.tick(30000);assert(f.m.m_NoSurvivorsSince==-1&&f.m.Active());f.m.roster.survivor=false;f.tick(31000);f.tick(61000);
|
||||
|
||||
Reference in New Issue
Block a user