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:
@@ -0,0 +1,121 @@
|
||||
"""Execute the production editor handover; engine delivery is checked separately."""
|
||||
from policy_harness import ROOT, body, run
|
||||
|
||||
core = ROOT / 'addons/core/Scripts/Game/ERR/00_Core'
|
||||
method = body(core / 'ERR_TerrainTakeoverManagers.c', 'void ERR_SetTerrainModeEvents(')
|
||||
method = (method.replace('SCR_BaseGameMode mode', 'SCR_BaseGameMode* mode')
|
||||
.replace('mode.', 'mode->').replace('Replication.', 'Replication::'))
|
||||
run(r'''
|
||||
#include <cassert>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
namespace Replication {bool server=true; bool IsServer(){return server;}}
|
||||
void Print(const char*){}
|
||||
void ERR_StopTerrainEditorRetry(){}
|
||||
enum {OnPlayerRegistered=1,OnPlayerDisconnected,OnPlayerSpawn,OnPlayerKilled,OnPlayerDeleted,OnPlayerRoleChange};
|
||||
struct Invoker {
|
||||
std::vector<int> callbacks{99};
|
||||
void Remove(int cb){callbacks.erase(std::remove(callbacks.begin(),callbacks.end(),cb),callbacks.end());}
|
||||
void Insert(int cb){callbacks.push_back(cb);}
|
||||
int Count(int cb){return std::count(callbacks.begin(),callbacks.end(),cb);}
|
||||
};
|
||||
struct SCR_BaseGameMode {
|
||||
Invoker events[6];
|
||||
Invoker& GetOnPlayerRegistered(){return events[0];}
|
||||
Invoker& GetOnPostCompPlayerDisconnected(){return events[1];}
|
||||
Invoker& GetOnPlayerSpawned(){return events[2];}
|
||||
Invoker& GetOnPlayerKilled(){return events[3];}
|
||||
Invoker& GetOnPlayerDeleted(){return events[4];}
|
||||
Invoker& GetOnPlayerRoleChange(){return events[5];}
|
||||
};
|
||||
''' + method + r'''
|
||||
void check(SCR_BaseGameMode& mode,int expected){
|
||||
for(int i=0;i<6;i++){
|
||||
assert(mode.events[i].Count(i+1)==expected);
|
||||
assert(mode.events[i].Count(99)==1); // Preserve unrelated systems' listeners.
|
||||
}
|
||||
}
|
||||
int main(){
|
||||
SCR_BaseGameMode original,replacement;
|
||||
ERR_SetTerrainModeEvents(nullptr,true);
|
||||
ERR_SetTerrainModeEvents(&original,true);check(original,1);
|
||||
ERR_SetTerrainModeEvents(&original,false);check(original,0);
|
||||
ERR_SetTerrainModeEvents(&replacement,true);check(replacement,1);
|
||||
ERR_SetTerrainModeEvents(&replacement,true);check(replacement,1);
|
||||
Replication::server=false;
|
||||
ERR_SetTerrainModeEvents(&replacement,false);check(replacement,1);
|
||||
ERR_SetTerrainModeEvents(&original,true);check(original,0);
|
||||
Replication::server=true;
|
||||
ERR_SetTerrainModeEvents(&replacement,false);check(replacement,0);
|
||||
ERR_SetTerrainModeEvents(&replacement,false);check(replacement,0);
|
||||
ERR_SetTerrainModeEvents(&replacement,true);check(replacement,1);
|
||||
}
|
||||
''')
|
||||
|
||||
# Subscription transfer must precede deleting the old owner and replaying held admissions.
|
||||
takeover = core / 'ERR_TerrainTakeover.c'
|
||||
drain = body(takeover, 'protected void ERR_DrainTerrainMode(')
|
||||
create = body(takeover, 'protected void ERR_CreateTerrainMode(')
|
||||
assert drain.index('ERR_SetTerrainModeEvents(m_ERRTerrainOriginal, false)') < drain.index('DeleteEntityAndChildren')
|
||||
assert create.index('ERR_SetTerrainModeEvents(mode, true)') < create.index('ERR_StartTerrainTakeover') < create.index('mode.OnPlayerAuditSuccess')
|
||||
print('PASS: six editor listeners transferred idempotently, unrelated handlers retained, authority guard and lifecycle ordering')
|
||||
|
||||
# Execute the reconnect repair against missing/existing managers and native roles.
|
||||
repair = body(core/'ERR_TerrainTakeoverManagers.c', 'void ERR_ReconcileTerrainEditors(')
|
||||
repair = (repair.replace('ERR_GameMode mode','ERR_GameMode* mode').replace('PlayerManager players','PlayerManager* players')
|
||||
.replace('array<int> ids = {};','std::vector<int> ids;').replace('SCR_EditorManagerEntity editor','SCR_EditorManagerEntity* editor')
|
||||
.replace('IEntity body','IEntity* body').replace('foreach (','for ('))
|
||||
for name in ('mode','players','editor'):
|
||||
repair=repair.replace(name+'.',name+'->')
|
||||
for cls in ('Replication','ERR_GameMode','ERR_Actors','SCR_Global','LogLevel'):
|
||||
repair=repair.replace(cls+'.',cls+'::')
|
||||
repair=repair.replace('GetGame().','GetGame()->')
|
||||
run(r'''
|
||||
#include <cassert>
|
||||
#include <vector>
|
||||
namespace Replication {bool server=true;bool IsServer(){return server;}}
|
||||
struct IEntity{bool alive=true;};
|
||||
struct ERR_GameMode{inline static ERR_GameMode* current=nullptr;bool taken=true;static ERR_GameMode* Get(){return current;}bool ERR_TerrainTakenOver(){return taken;}};
|
||||
namespace SCR_Global{bool admin=false;bool IsAdmin(int){return admin;}}
|
||||
namespace ERR_Actors{bool Alive(IEntity* e){return e&&e->alive;}}
|
||||
namespace LogLevel{int WARNING=1;}
|
||||
template<class...T>void PrintFormat(const char*,T...){}
|
||||
struct SCR_EditorManagerEntity{int refresh=0;bool limited=true;void RecreateEditorModes(){refresh++;limited=!SCR_Global::admin;}bool IsLimited(){return limited;}bool CanOpen(){return !limited;}};
|
||||
struct PlayerManager{bool connected=true,controller=true;IEntity* body=nullptr;void GetPlayers(std::vector<int>& ids){ids={1};}bool IsPlayerConnected(int){return connected;}bool GetPlayerController(int){return controller;}IEntity* GetPlayerControlledEntity(int){return body;}};
|
||||
struct Game{PlayerManager players;PlayerManager* GetPlayerManager(){return &players;}}game;Game* GetGame(){return &game;}
|
||||
struct Core{SCR_EditorManagerEntity entity;bool exists=false;int created=0,spawns=0;SCR_EditorManagerEntity* GetEditorManager(int){return exists?&entity:nullptr;}void OnPlayerRegistered(int){created++;exists=true;}void OnPlayerSpawn(int,IEntity*){spawns++;}
|
||||
'''+repair+r'''
|
||||
};
|
||||
int main(){ERR_GameMode mode;ERR_GameMode::current=&mode;Core c;
|
||||
c.ERR_ReconcileTerrainEditors(&mode);assert(c.created==1&&c.entity.limited&&c.entity.refresh==1);
|
||||
SCR_Global::admin=true;IEntity body;game.players.body=&body;c.ERR_ReconcileTerrainEditors(&mode);assert(c.created==1&&!c.entity.limited&&c.spawns==1);
|
||||
SCR_Global::admin=false;body.alive=false;c.ERR_ReconcileTerrainEditors(&mode);assert(c.entity.limited&&c.spawns==1);
|
||||
game.players.connected=false;c.ERR_ReconcileTerrainEditors(&mode);assert(c.entity.refresh==3);
|
||||
game.players.connected=true;game.players.controller=false;c.ERR_ReconcileTerrainEditors(&mode);assert(c.entity.refresh==3);
|
||||
game.players.controller=true;Replication::server=false;c.ERR_ReconcileTerrainEditors(&mode);assert(c.entity.refresh==3);
|
||||
Replication::server=true;mode.taken=false;c.ERR_ReconcileTerrainEditors(&mode);assert(c.entity.refresh==3);
|
||||
mode.taken=true;ERR_GameMode::current=nullptr;c.ERR_ReconcileTerrainEditors(&mode);assert(c.entity.refresh==3);
|
||||
}
|
||||
''')
|
||||
assert create.index('mode.OnPlayerAuditSuccess') < create.index('ERR_ReconcileTerrainEditors(mode)')
|
||||
print('PASS: takeover reconnect creates only missing managers, restores native roles, never grants non-admin access, skips stale/disconnected/client states')
|
||||
|
||||
button = body(core/'ERR_ContentMenu.c','protected void ERR_RefreshGameMasterButton(').replace('protected ','')
|
||||
button=button.replace('ERR_GameMode.Get()','activeMode').replace('SCR_EditorManagerEntity.GetInstance()','instance').replace('SCR_EditorManagerEntity editor','Editor* editor').replace('editor.','editor->').replace('m_EditorUnlimitedOpenButton.','m_EditorUnlimitedOpenButton->')
|
||||
run(r'''
|
||||
#include <cassert>
|
||||
bool activeMode=true;struct Editor{bool limited=true,openable=false;bool IsLimited(){return limited;}bool CanOpen(){return openable;}};Editor* instance=nullptr;
|
||||
struct Button{bool enabled=false;void SetEnabled(bool b){enabled=b;}};
|
||||
struct Menu{Button* m_EditorUnlimitedOpenButton=nullptr;
|
||||
'''+button+r'''
|
||||
};
|
||||
int main(){Menu m;Button b;m.m_EditorUnlimitedOpenButton=&b;Editor e;instance=&e;
|
||||
m.ERR_RefreshGameMasterButton();assert(!b.enabled);
|
||||
e.limited=false;e.openable=true;m.ERR_RefreshGameMasterButton();assert(b.enabled); // Role arrives while menu is open.
|
||||
e.openable=false;m.ERR_RefreshGameMasterButton();assert(!b.enabled);
|
||||
e.openable=true;e.limited=true;m.ERR_RefreshGameMasterButton();assert(!b.enabled); // Revoked role.
|
||||
instance=nullptr;m.ERR_RefreshGameMasterButton();assert(!b.enabled);
|
||||
activeMode=false;b.enabled=true;m.ERR_RefreshGameMasterButton();assert(b.enabled); // Other scenarios unchanged.
|
||||
}
|
||||
''')
|
||||
print('PASS: Game Master button becomes enabled on native permission arrival and disabled on revocation; no permission bypass')
|
||||
Reference in New Issue
Block a user