Files
jakub 6a667d8deb Capture current mission, AI, map and administration development
Include the current addon, terrain integrations, tools, regression tests and recorded development evidence.
2026-10-13 22:52:53 +02:00

384 lines
24 KiB
Python

"""Execute takeover parsing and admission/readiness policy from production bodies.
Native startup and multiplayer replication require separate engine tests.
"""
from policy_harness import ROOT, body, run
core = ROOT/'addons/core/Scripts/Game/ERR/00_Core'
settings = core/'ERR_TerrainTakeoverSettings.c'
takeover = core/'ERR_TerrainTakeover.c'
def cpp(text):
return (text.replace('out float ', 'float& ')
.replace('array<vector> centres', 'Array<Vec>& centres')
.replace('array<string>', 'Array<string>')
.replace('foreach (string entry : entries)', 'for (string entry : entries)')
.replace('bool digit, dot;', 'bool digit=false, dot=false;')
.replace('"0123456789".IndexOf(', 'string("0123456789").IndexOf('))
run(r'''
#include <cassert>
#include <string>
#include <vector>
template<class T> struct Array:std::vector<T>{
using std::vector<T>::vector;
void Clear(){this->clear();} int Count(){return this->size();}
bool IsEmpty(){return this->empty();} void Insert(T v){this->push_back(v);}
};
struct string:std::string {
using std::string::string; string(std::string s):std::string(s){}
bool IsEmpty(){return empty();} int Length(){return size();}
string Substring(int a,int b){return substr(a,b);}
int IndexOf(string s){auto p=find(s);return p==npos?-1:int(p);}
float ToFloat(){return std::stof(*this);}
void TrimInPlace(){auto a=find_first_not_of(" \t\r\n"),b=find_last_not_of(" \t\r\n");*this=a==npos?"":substr(a,b-a+1);}
void Split(string delimiter,Array<string>& out,bool skipEmpty){
size_t start=0;while(true){auto end=find(delimiter,start);string part=substr(start,end==npos?npos:end-start);
if(!skipEmpty||!part.empty())out.Insert(part);
if(end==npos)break;
start=end+delimiter.size();
}
}
};
struct Vec{float x,y,z;}; Vec Vector(float x,float y,float z){return {x,y,z};}
''' + cpp(body(settings, 'static bool Coordinate(')) + cpp(body(settings, 'static bool ParseAirfields(')) +
body(takeover, 'static bool TimedOut(') + body(takeover, 'static bool MayDrain(') +
body(takeover, 'static bool MayCreate(') + body(takeover, 'static bool SameAdmission(') + r'''
int main(){
float value=0;
assert(Coordinate("-1000000",value)&&value==-1000000);
assert(Coordinate("42.75",value)&&value==42.75f);
for(string bad:{"", "-", ".", "-.", "nan", "inf", "1e4", "12x", "--1", "1.2.3", "1000001", "1 2", "12345678901234567"})assert(!Coordinate(bad,value));
Array<Vec> centres;
assert(ParseAirfields("1525 5075; -20.5 200",centres));
assert(centres.Count()==2&&centres[0].x==1525&&centres[0].z==5075&&centres[1].x==-20.5f);
assert(ParseAirfields(" 1 2 ",centres)&&centres.Count()==1);
assert(ParseAirfields("\t \n",centres)&&centres.IsEmpty());
for(string bad:{"1", "1 2 3", "1 2;", ";1 2", "1 2;;3 4", "1 2;bad 4", "1 2;nan inf", "1 2;3 4;5"}){
centres.Insert({9,0,9});assert(!ParseAirfields(bad,centres));assert(centres.IsEmpty());
}
string many="1 2";for(int i=1;i<16;i++)many+=";1 2";
assert(ParseAirfields(many,centres)&&centres.Count()==16);
many+=";1 2";assert(!ParseAirfields(many,centres)&&centres.IsEmpty());
assert(!TimedOut(9.999f)&&TimedOut(10)&&TimedOut(30));
assert(!MayDrain(.49f,true)&&MayDrain(.5f,true)&&!MayDrain(1,false));
assert(MayCreate(0,true)&&MayCreate(.49f,true)&&MayCreate(.5f,true)&&!MayCreate(1,false)&&!MayCreate(10,true));
assert(SameAdmission(true,true,true,true));
assert(!SameAdmission(false,true,true,true));
assert(!SameAdmission(true,false,true,true)); // Reused connection id, different controller.
assert(!SameAdmission(true,true,true,false)); // Account changed after audit.
assert(SameAdmission(true,true,false,false)); // No identity is manufactured: actual spawn logic still decides.
}
''')
# Lifecycle wiring is checked here; the world/manager lifecycle itself is native.
cleanup = body(takeover, 'override protected void OnBeforeWorldCleanup(')
assert cleanup.index('ERR_ResetTerrainTakeover()') < cleanup.index('super.OnBeforeWorldCleanup()')
reset = body(takeover, 'protected void ERR_ResetTerrainTakeover(')
for cleared in ('m_ERRTerrainAdmissions.Clear()', 'm_ERRTerrainAirfields.Clear()',
'm_ERRTerrainMarkerSlots.Clear()', 'm_ERRTerrainWorld = null',
'm_ERRTerrainOriginal = null', 'm_ERRTerrainElapsed = 0'):
assert cleared in reset
print('PASS: configured airport parsing, bounded readiness, stale admission rejection and cleanup wiring')
def settings_cpp(text):
return (text.replace('SCR_MissionHeader header', 'SCR_MissionHeader* header')
.replace('SCR_MissionHeader.Cast', 'SCR_MissionHeader::Cast')
.replace('GetGame().', 'GetGame()->').replace('header.', 'header->')
.replace('SCR_Global.', 'SCR_Global::').replace('System.', 'System::'))
run(r'''
#include <cassert>
#include <string>
#include <map>
using string=std::string;
struct SCR_MissionHeader {
bool m_bERR_EnableEscape=true; string m_sERR_Airfields;
static SCR_MissionHeader* Cast(SCR_MissionHeader* header){return header;}
} header;
struct Game {SCR_MissionHeader* current=&header;SCR_MissionHeader* GetMissionHeader(){return current;}} game;
Game* currentGame=&game;Game* GetGame(){return currentGame;}
namespace SCR_Global {bool edit=false;bool IsEditMode(){return edit;}}
namespace System {
std::map<string,string> cli;
bool GetCLIParam(string key,string& value){auto it=cli.find(key);if(it==cli.end())return false;value=it->second;return true;}
}
''' + settings_cpp(body(settings, 'static bool Enabled(')) +
settings_cpp(body(settings, 'static string Airfields(')) + r'''
int main(){
assert(Enabled()&&Airfields().empty()); // Installing Escape requires no header or CLI flags.
header.m_bERR_EnableEscape=false;assert(!Enabled());
for(string bad:{"0","true","yes","01",""}){System::cli["errTerrainTakeover"]=bad;assert(!Enabled());}
System::cli["errTerrainTakeover"]="1";System::cli["errAirfields"]="1525 5075";
assert(Enabled()&&Airfields()=="1525 5075");
SCR_Global::edit=true;assert(!Enabled());SCR_Global::edit=false;
currentGame=nullptr;assert(!Enabled());currentGame=&game;
game.current=nullptr;assert(Enabled());game.current=&header;
header.m_bERR_EnableEscape=true;header.m_sERR_Airfields="10 20";
System::cli["errTerrainTakeover"]="0";assert(!Enabled()); // Explicit opt-out wins over the default header.
System::cli.erase("errTerrainTakeover");assert(Enabled());
assert(Airfields()=="1525 5075"); // Explicit CLI coordinates win.
System::cli.erase("errAirfields");assert(Airfields()=="10 20");
header.m_sERR_Airfields="";assert(Airfields().empty());
game.current=nullptr;System::cli.clear();assert(Enabled()&&Airfields().empty());
}
''')
assert '[Attribute("1", desc: "Automatically start Escape' in settings.read_text()
startup = body(takeover, 'protected override void OnWorldPostProcess(')
assert '!ERR_GameMode.Get() && Replication.IsServer()' in startup
assert startup.index('ERR_PreflightTerrainTakeover()') < startup.index('saves.SetSavingAllowed(false)')
print('PASS: automatic default, explicit header/CLI opt-out, editor/authored-mode guards, optional airport override precedence and fresh-round saving guard')
client = core/'ERR_TerrainTakeoverClient.c'
managers = core/'ERR_TerrainTakeoverManagers.c'
# Execute singleton release bodies: delayed cleanup must not clear a new owner.
components = (
('SCR_EntityCatalogManagerComponent', 's_Instance', 'ERR_ReleaseClientCatalog'),
('SCR_AdditionalGameModeSettingsComponent', 's_Instance', 'ERR_ReleaseTerrainSingleton'),
('SCR_PerceivedFactionManagerComponent', 's_Instance', 'ERR_ReleaseTerrainSingleton'),
('SCR_PlayerListedAdminManagerComponent', 'm_Instance', 'ERR_ReleaseTerrainSingleton'),
('SCR_IdentityManagerComponent', 'm_sInstance', 'ERR_ReleaseTerrainSingleton'),
('SCR_ArsenalManagerComponent', 's_Instance', 'ERR_ReleaseTerrainSingleton'),
('SCR_GroupsManagerComponent', 's_Instance', 'ERR_ReleaseTerrainSingleton'),
('SCR_SupportStationManagerComponent', 's_Instance', 'ERR_ReleaseTerrainSingleton'),
('SCR_TaskFinishHistoryManagerComponent', 's_Instance', 'ERR_ReleaseTerrainSingleton'),
('SCR_TaskManagerUIComponent', 's_Instance', 'ERR_ReleaseTerrainSingleton'),
('SCR_TextsTaskManagerComponent', 's_Instance', 'ERR_ReleaseTerrainSingleton'),
)
release_cpp = '#include <cassert>\n'
release_cases = ''
for name, field, method in components:
owner_file = client if f'static void {method}({name} expected)' in client.read_text() else managers
method_body = body(owner_file, f'static void {method}({name} expected)')
method_body = method_body.replace(f'{name} expected', f'{name}* expected').replace('null', 'nullptr')
release_cpp += f'struct {name} {{inline static {name}* {field}=nullptr; {method_body}}};\n'
release_cases += f'''{{
{name} original, replacement;
{name}::{field}=&original;
{name}::{method}(&original); assert(!{name}::{field});
{name}::{field}=&replacement;
{name}::{method}(&original); assert({name}::{field}==&replacement);
{name}::{method}(nullptr); assert({name}::{field}==&replacement);
}}\n'''
run(release_cpp + 'int main(){' + release_cases + '}')
# Execute both ends of the prefix protocol and verify faction binding occurs
# before the base deserializer touches it. Outside takeover, leave it unchanged.
save = body(client, 'override bool RplSave(')
load = body(client, 'override bool RplLoad(')
def wire_cpp(text):
return (text.replace('override ', '').replace('ScriptBitWriter writer', 'ScriptBitWriter& writer')
.replace('ScriptBitReader reader', 'ScriptBitReader& reader')
.replace('super.', 'Base::').replace('GetGame().', 'GetGame()->'))
run(r'''
#include <cassert>
#include <vector>
struct Game {bool takeover=false;bool ERR_IsClientTerrainTakeover(){return takeover;}} game;
Game* GetGame(){return &game;}
struct ScriptBitWriter {std::vector<int> data;void WriteInt(int v){data.push_back(v);}};
struct ScriptBitReader {
std::vector<int> data;unsigned pos=0;
bool ReadInt(int& v){if(pos>=data.size())return false;v=data[pos++];return true;}
};
struct Base {
int m_iFactionIndex=3;bool m_ScrFaction=false;int bindCalls=0;bool baseCalled=false;
void SetFactionIndexBroadcast(int index){++bindCalls;m_ScrFaction=index>=0&&index<5;}
bool RplSave(ScriptBitWriter& writer){writer.WriteInt(12345);return true;}
bool RplLoad(ScriptBitReader& reader){baseCalled=true;assert(m_ScrFaction);int payload;return reader.ReadInt(payload)&&payload==12345;}
};
struct Delegate:Base {
''' + wire_cpp(save) + wire_cpp(load) + r'''
};
int main(){
Delegate server;ScriptBitWriter writer;assert(server.RplSave(writer));
assert((writer.data==std::vector<int>{3,12345}));
game.takeover=true;Delegate joining;ScriptBitReader reader{writer.data};
assert(joining.RplLoad(reader)&&joining.baseCalled&&joining.bindCalls==1&&reader.pos==2);
Delegate existing;existing.m_ScrFaction=true;ScriptBitReader existingReader{writer.data};
assert(existing.RplLoad(existingReader)&&existing.bindCalls==0);
game.takeover=false;Delegate normal;normal.m_ScrFaction=true;ScriptBitReader normalReader{writer.data};
assert(normal.RplLoad(normalReader)&&normal.bindCalls==0&&normalReader.pos==2);
game.takeover=true;Delegate truncated;ScriptBitReader empty;
assert(!truncated.RplLoad(empty)&&!truncated.baseCalled&&truncated.bindCalls==0);
Delegate invalid;ScriptBitReader bad{{999,12345}};
assert(!invalid.RplLoad(bad)&&!invalid.baseCalled);
}
''')
client_reset = body(client, 'override protected void OnBeforeWorldCleanup(')
for cleared in ('m_ERRClientTerrainTakeover = false', 'm_ERRClientOldManagers.Clear()',
'm_ERROldCatalog = null', 'm_ERROldSettings = null',
'm_ERROldPerceivedFaction = null', 'm_ERROldAdmins = null',
'm_ERROldIdentity = null', 'm_ERROldLoadoutId = EntityID.INVALID'):
assert client_reset.index(cleared) < client_reset.index('super.OnBeforeWorldCleanup()')
assert 'm_ERRTerrainRadio = null' in reset
assert 'm_ERRTerrainOldLoadoutId = EntityID.INVALID' in reset
for component in ('Arsenal', 'Groups', 'Support', 'TaskHistory', 'TaskUI', 'TaskTexts'):
assert f'm_ERROld{component} = null' in client_reset
print('PASS: singleton identity guards, paired faction deserialization and client world-cleanup wiring')
# Late native destructors can null the original caches after the new component
# exists. Each affected getter resolves only takeover owners directly, and keeps
# the original behavior for authored modes and during world cleanup.
for component in ('SCR_TaskFinishHistoryManagerComponent', 'SCR_TaskManagerUIComponent',
'SCR_TextsTaskManagerComponent', 'SCR_MapMarkerManagerComponent',
'SCR_RespawnSystemComponent'):
getter = body(managers, f'override static {component} GetInstance(')
getter = (getter.replace('override static ', 'static ')
.replace(f'{component} GetInstance', f'{component}* GetInstance')
.replace('ERR_TerrainTakeoverMode mode;', 'ERR_TerrainTakeoverMode* mode=nullptr;')
.replace('ERR_TerrainTakeoverMode.Cast', 'ERR_TerrainTakeoverMode::Cast')
.replace(f'{component}.Cast', f'{component}::Cast')
.replace(f'FindComponent({component})', 'FindComponent(0)')
.replace('GetGame().', 'GetGame()->').replace('mode.', 'mode->')
.replace('super.', 'Base::'))
run(r'''
#include <cassert>
struct Component {static Component* Cast(Component* v){return v;}};
''' + f'using {component}=Component;\n' + r'''
struct ERR_TerrainTakeoverMode {
bool takeover=false;Component* current=nullptr;
static ERR_TerrainTakeoverMode* Cast(ERR_TerrainTakeoverMode* m){return m&&m->takeover?m:nullptr;}
Component* FindComponent(int){return current;}
};
struct Game {ERR_TerrainTakeoverMode* mode=nullptr;ERR_TerrainTakeoverMode* GetGameMode(){return mode;}} game;
Game* activeGame=&game;Game* GetGame(){return activeGame;}
struct Base {inline static Component* cached=nullptr;static Component* GetInstance(){return cached;}};
struct Patched:Base {
''' + getter + r'''
};
int main(){
Component old, replacement;Base::cached=&old;
ERR_TerrainTakeoverMode mode;mode.current=&replacement;game.mode=&mode;
assert(Patched::GetInstance()==&old); // Ordinary mode preserves base behavior.
mode.takeover=true;assert(Patched::GetInstance()==&replacement);
Base::cached=nullptr;assert(Patched::GetInstance()==&replacement); // Old destructor ran.
mode.current=nullptr;assert(Patched::GetInstance()==nullptr); // Never return old components.
game.mode=nullptr;assert(Patched::GetInstance()==nullptr);
activeGame=nullptr;assert(Patched::GetInstance()==nullptr);
}
''')
print('PASS: task/map/respawn getters survive delayed old destruction and preserve ordinary-mode behavior')
# Native delivery dependencies must put managers below the mode and faction
# delegates below the faction manager. Test the actual node-link primitive with
# absent/aliased nodes and idempotent reuse of an existing correct relationship.
parent = body(managers, 'protected static bool Parent(')
parent = (parent.replace('protected static ', '').replace('IEntity entity', 'IEntity* entity')
.replace('IEntity parent', 'IEntity* parent').replace('RplComponent childRpl', 'RplComponent* childRpl')
.replace('RplComponent parentRpl', 'RplComponent* parentRpl')
.replace('RplNode childNode', 'RplNode* childNode').replace('RplNode parentNode', 'RplNode* parentNode')
.replace('SCR_EntityHelper.', 'SCR_EntityHelper::').replace('childRpl.', 'childRpl->')
.replace('parentRpl.', 'parentRpl->').replace('childNode.', 'childNode->'))
run(r'''
#include <cassert>
struct RplNode {RplNode* parent=nullptr;int changes=0;RplNode* GetParent(){return parent;}void SetParent(RplNode* p){parent=p;++changes;}};
struct RplComponent {RplNode* node=nullptr;RplNode* GetNode(){return node;}};
struct IEntity {RplComponent* rpl=nullptr;};
namespace SCR_EntityHelper {RplComponent* GetEntityRplComponent(IEntity* e){return e?e->rpl:nullptr;}}
''' + parent + r'''
int main(){
RplNode root, child, unrelated;RplComponent rootRpl{&root},childRpl{&child};
IEntity mode{&rootRpl}, manager{&childRpl}, empty;
assert(!Parent(nullptr,&mode)&&!Parent(&manager,nullptr)&&!Parent(&empty,&mode));
assert(!Parent(&mode,&mode));
assert(Parent(&manager,&mode)&&child.parent==&root&&child.changes==1);
assert(Parent(&manager,&mode)&&child.changes==1);
child.parent=&unrelated;assert(Parent(&manager,&mode)&&child.changes==2);
childRpl.node=nullptr;assert(!Parent(&manager,&mode));
}
''')
print('PASS: replication hierarchy refuses absent/aliased nodes and establishes delivery dependencies idempotently')
collect = body(managers, 'static void CollectDelegates(')
collect = (collect.replace('SCR_DelegateFactionManagerComponent manager', 'SCR_DelegateFactionManagerComponent* manager')
.replace('array<IEntity> entities', 'Entities& entities')
.replace('map<Faction, SCR_EditableFactionComponent> delegates = new map<Faction, SCR_EditableFactionComponent>();', 'Delegates delegates;')
.replace('SCR_EditableFactionComponent delegate', 'SCR_EditableFactionComponent* delegate')
.replace('manager.', 'manager->').replace('delegate.', 'delegate->'))
run(r'''
#include <cassert>
#include <vector>
#include <algorithm>
struct IEntity {};
struct SCR_EditableFactionComponent {IEntity* owner;IEntity* GetOwner(){return owner;}};
struct Delegates:std::vector<SCR_EditableFactionComponent*> {
int Count(){return size();}SCR_EditableFactionComponent* GetElement(int i){return at(i);}
};
struct Entities:std::vector<IEntity*> {
bool Contains(IEntity* p){return std::find(begin(),end(),p)!=end();}void Insert(IEntity* p){push_back(p);}
};
struct SCR_DelegateFactionManagerComponent {Delegates data;void GetFactionDelegates(Delegates& out){out=data;}};
''' + collect + r'''
int main(){
IEntity a,b;SCR_EditableFactionComponent da{&a},duplicate{&a},db{&b},deleted{nullptr};
SCR_DelegateFactionManagerComponent manager;manager.data={};
manager.data.insert(manager.data.end(),{&da,nullptr,&duplicate,&deleted,&db});
Entities entities;entities.push_back(&a);CollectDelegates(nullptr,entities);assert(entities.size()==1);
CollectDelegates(&manager,entities);assert(entities.size()==2&&entities[1]==&b);
CollectDelegates(&manager,entities);assert(entities.size()==2);
}
''')
print('PASS: standalone old faction delegates collected once, with null/deleted owners ignored')
# Main-menu world regression: actual startup body and enable policy.
"""Actual world-postprocess and enable policy: menu worlds never enter terrain preflight."""
from policy_harness import ROOT,body,run
from pathlib import Path
import os
P=Path(os.environ.get('ERR_TAKEOVER_SOURCE',ROOT/'addons/core/Scripts/Game/ERR/00_Core/ERR_TerrainTakeover.c'))
S=Path(os.environ.get('ERR_TAKEOVER_SETTINGS_SOURCE',ROOT/'addons/core/Scripts/Game/ERR/00_Core/ERR_TerrainTakeoverSettings.c'))
def cpp(s):
for a,b in [('protected ',''),('override ',''),('super.','Base::'),('World world','World* world'),('bool changingTerrain;','bool changingTerrain=false;'),('SaveGameManager saves','SaveGameManager* saves'),('SCR_MissionHeader header','SCR_MissionHeader* header'),('GetGame().','GetGame()->'),('header.','header->'),('saves.','saves->'),('null','nullptr')]:s=s.replace(a,b)
for name in ['ERR_TerrainTakeoverSettings','ERR_GameMode','Replication','SCR_BaseGameMode','SCR_MissionHeader','SCR_Global','System','ERR_TerrainTakeoverStage']:s=s.replace(name+'.',name+'::')
return s
run(r'''
#include <cassert>
#include <string>
#include <map>
#include <vector>
using string=std::string;
struct World{};
struct Mode {virtual ~Mode()=default;};
struct SCR_BaseGameMode:Mode {static SCR_BaseGameMode*Cast(Mode*m){return dynamic_cast<SCR_BaseGameMode*>(m);}};
struct ERR_GameMode:SCR_BaseGameMode{inline static ERR_GameMode*current=nullptr;static ERR_GameMode*Get(){return current;}};
struct SCR_MissionHeader{bool m_bERR_EnableEscape=true;static SCR_MissionHeader*Cast(SCR_MissionHeader*h){return h;}};
struct Game{bool changingTerrain=false;bool ERR_PrepareTerrainSelection(World*){return changingTerrain;}SCR_MissionHeader*header=nullptr;SCR_MissionHeader*GetMissionHeader(){return header;}}game;
Game*currentGame=&game;Game*GetGame(){return currentGame;}
namespace SCR_Global{bool edit=false;bool IsEditMode(){return edit;}}
namespace System{std::map<string,string>cli;bool GetCLIParam(string key,string&value){auto i=cli.find(key);if(i==cli.end())return false;value=i->second;return true;}}
namespace Replication{bool server=true;bool IsServer(){return server;}}
struct ERR_TerrainTakeoverSettings{
'''+cpp(body(S,'static bool Enabled('))+r'''
};
namespace ERR_TerrainTakeoverStage{enum Stage{INACTIVE,SETTLING,FAILED};}
struct SaveGameManager{int writes=0;bool allowed=true;void SetSavingAllowed(bool b){writes++;allowed=b;}};
struct Array{int Count(){return 0;}};
struct Base{int superCalls=0;World*superWorld=nullptr;void OnWorldPostProcess(World*w){superCalls++;superWorld=w;}};
struct App:Base{
Mode*mode=nullptr;World*m_ERRTerrainWorld=nullptr;SCR_BaseGameMode*m_ERRTerrainOriginal=nullptr;ERR_TerrainTakeoverStage::Stage m_ERRTerrainStage=ERR_TerrainTakeoverStage::INACTIVE;Array m_ERRTerrainAirfields;SaveGameManager saves;int resets=0,preflights=0,failures=0,prints=0;bool nativePrerequisites=true;
Mode*GetGameMode(){return mode;}SaveGameManager*GetSaveGameManager(){return &saves;}
void ERR_ResetTerrainTakeover(){resets++;m_ERRTerrainStage=ERR_TerrainTakeoverStage::INACTIVE;m_ERRTerrainWorld=nullptr;m_ERRTerrainOriginal=nullptr;}
bool ERR_PreflightTerrainTakeover(){preflights++;if(!m_ERRTerrainOriginal||!nativePrerequisites){failures++;m_ERRTerrainStage=ERR_TerrainTakeoverStage::FAILED;return false;}return true;}
void PrintFormat(const char*,int){prints++;}
'''+cpp(body(P,'protected override void OnWorldPostProcess('))+r'''
};
int main(){
World menu,world;SCR_BaseGameMode native;ERR_GameMode own;Mode unsupported;
// Actual Enabled defaults true without a header. A menu has no mode, not an unsupported scenario.
{App a;assert(ERR_TerrainTakeoverSettings::Enabled());a.OnWorldPostProcess(&menu);assert(a.superCalls==1&&a.superWorld==&menu);assert(a.resets==0&&a.preflights==0&&a.failures==0&&a.saves.writes==0&&!a.m_ERRTerrainWorld);}
// A mode-less callback must not erase an already retained operation either.
{App a;a.m_ERRTerrainStage=ERR_TerrainTakeoverStage::SETTLING;a.m_ERRTerrainWorld=&world;a.m_ERRTerrainOriginal=&native;a.OnWorldPostProcess(&menu);assert(a.superCalls==1&&a.resets==0&&a.preflights==0&&a.m_ERRTerrainStage==ERR_TerrainTakeoverStage::SETTLING&&a.m_ERRTerrainWorld==&world&&a.m_ERRTerrainOriginal==&native);}
{App a;a.mode=&native;a.OnWorldPostProcess(&world);assert(a.superCalls==1&&a.resets==1&&a.preflights==1&&!a.failures&&a.m_ERRTerrainOriginal==&native&&a.m_ERRTerrainWorld==&world&&a.m_ERRTerrainStage==ERR_TerrainTakeoverStage::SETTLING&&a.saves.writes==1&&!a.saves.allowed);}
// A pending terrain change must not race native manager teardown/replacement.
{game.changingTerrain=true;App a;a.mode=&native;a.OnWorldPostProcess(&world);assert(a.superCalls==1&&a.resets==0&&a.preflights==0&&a.saves.writes==0);game.changingTerrain=false;}
// Actual unsupported game modes still reach the diagnostic, preserving original scenario and saving.
{App a;a.mode=&unsupported;a.OnWorldPostProcess(&world);assert(a.superCalls==1&&a.resets==1&&a.preflights==1&&a.failures==1&&a.m_ERRTerrainStage==ERR_TerrainTakeoverStage::FAILED&&a.saves.writes==0&&a.saves.allowed);}
{App a;a.mode=&native;a.nativePrerequisites=false;a.OnWorldPostProcess(&world);assert(a.superCalls==1&&a.failures==1&&a.saves.writes==0);}
// Authored successor, client, editor and explicit disabled configurations keep original behavior.
for(int i=0;i<6;i++){App a;a.mode=&native;SCR_MissionHeader header;game.header=&header;if(i==0){ERR_GameMode::current=&own;a.mode=&own;}if(i==1)Replication::server=false;if(i==2)SCR_Global::edit=true;if(i==3)header.m_bERR_EnableEscape=false;if(i==4)System::cli["errTerrainTakeover"]="0";if(i==5)currentGame=nullptr;a.OnWorldPostProcess(&world);assert(a.superCalls==1&&a.resets==0&&a.preflights==0&&a.saves.writes==0);ERR_GameMode::current=nullptr;Replication::server=true;SCR_Global::edit=false;System::cli.clear();game.header=nullptr;currentGame=&game;}
// Explicit enabling never creates a mode for a menu; same app can later enter an ordinary scenario.
{System::cli["errTerrainTakeover"]="1";App a;a.OnWorldPostProcess(&menu);assert(!a.resets);a.mode=&native;a.OnWorldPostProcess(&world);assert(a.superCalls==2&&a.resets==1&&a.preflights==1&&a.saves.writes==1);System::cli.clear();}
}
''')
print('PASS: actual terrain takeover startup skips mode-less/menu worlds, always forwards super, retains eligible/unsupported/authored/client/editor semantics')