Files
EscapistsReintroduced/tests/test_terrain_support_stations.py
2026-10-30 18:56:57 +01:00

64 lines
5.3 KiB
Python

"""Execute station handover with native manager/world boundaries doubled."""
from policy_harness import ROOT, body, run
p=ROOT/'addons/core/Scripts/Game/ERR/00_Core/ERR_TerrainSupportStations.c'
def cpp(signature):
s=body(p,signature)
for a,b in [('int restored;', 'int restored=0;'),('protected ',''),('override ',''),('SCR_SupportStationManagerComponent manager','Manager* manager'),('SCR_SupportStationManagerComponent original','Manager* original'),('array<SCR_BaseSupportStationComponent> stations','Array<Station*>& stations'),('array<SCR_BaseSupportStationComponent> registered','Array<Station*>* registered'),('foreach (SCR_BaseSupportStationComponent station : registered)','for (Station* station : *registered)'),('foreach (SCR_BaseSupportStationComponent station : m_ERRTerrainSupportStations)','for (Station* station : m_ERRTerrainSupportStations)'),('IEntity owner','Owner* owner'),('station.', 'station->'),('manager.', 'manager->'),('original.', 'original->'),('owner.', 'owner->'),('GetGame().', 'GetGame()->'),('EDamageState.DESTROYED','2'),('super.', 'Base::')]: s=s.replace(a,b)
return s
run(r'''
#include <cassert>
#include <algorithm>
#include <vector>
struct Station;struct Manager;struct Game;
template<class T>struct Array:std::vector<T>{using std::vector<T>::vector;void Clear(){this->clear();}void Insert(T v){this->push_back(v);}bool Contains(T v){return std::find(this->begin(),this->end(),v)!=this->end();}};
struct World{} world,otherWorld;
struct Owner{World* world=&::world;World* GetWorld(){return world;}};
struct Base{int cleaned=0;void OnBeforeWorldCleanup(){cleaned++;}void ERR_TerrainStationRestored(Manager*){}};
template<class...T>void PrintFormat(T...){}
struct Game:Base{Array<Station*> m_ERRTerrainSupportStations;World* GetWorld(){return &world;}
void ERR_CaptureTerrainSupportStations(Manager*);
void ERR_RestoreTerrainSupportStations(Manager*);
void OnBeforeWorldCleanup();
} game;
Game* current=&game;Game* GetGame(){return current;}
struct Station:Base{Owner own;Owner* owner=&own;int m_eCurrentDamageState=0;bool ranged=true;
bool m_ERRItemStationInitialized=true;Manager* m_ERRItemStationManager=nullptr;
Owner* GetOwner(){return owner;}bool UsesRange(){return ranged;}
'''+cpp('bool ERR_CanRestoreTerrainStation(')+cpp('override void ERR_TerrainStationRestored(')+r'''
};
struct Map{std::vector<Array<Station*>*> lists;int Count(){return lists.size();}Array<Station*>* GetElement(int i){return lists[i];}};
struct Manager{Map m_mSupportStations;Array<Station*> accepted;void AddSupportStation(Station* s){if(!accepted.Contains(s))accepted.Insert(s);}
'''+cpp('void ERR_CollectTerrainStations(')+r'''
};
'''+cpp('void ERR_CaptureTerrainSupportStations(').replace('void ERR_', 'void Game::ERR_',1)+cpp('void ERR_RestoreTerrainSupportStations(').replace('void ERR_', 'void Game::ERR_',1)+cpp('override protected void OnBeforeWorldCleanup(').replace('void OnBefore','void Game::OnBefore',1)+r'''
int main(){
Station pump,item,destroyed,deleted,offWorld,nonRanged;
Manager old,replacement;
destroyed.m_eCurrentDamageState=2;deleted.owner=nullptr;offWorld.own.world=&otherWorld;nonRanged.ranged=false;
pump.m_ERRItemStationManager=&old;item.m_ERRItemStationManager=&old;
Array<Station*> fuel{&pump,&destroyed,nullptr,&deleted,&offWorld};
Array<Station*> repair{&item,&pump,&nonRanged};old.m_mSupportStations.lists={&fuel,&repair,nullptr};
game.ERR_CaptureTerrainSupportStations(&old);assert(game.m_ERRTerrainSupportStations.size()==6);
// The removed registry can disappear; the captured list is independent.
fuel.Clear();repair.Clear();
replacement.AddSupportStation(&item); // initialization races must not duplicate entries
game.ERR_RestoreTerrainSupportStations(&replacement);
assert(replacement.accepted.size()==2&&replacement.accepted.Contains(&pump)&&replacement.accepted.Contains(&item));
assert(pump.m_ERRItemStationManager==&replacement&&item.m_ERRItemStationManager==&replacement);
assert(game.m_ERRTerrainSupportStations.empty());
game.ERR_RestoreTerrainSupportStations(&replacement);assert(replacement.accepted.size()==2);
game.m_ERRTerrainSupportStations.Insert(&pump);game.ERR_RestoreTerrainSupportStations(nullptr);assert(game.m_ERRTerrainSupportStations.size()==1);
game.OnBeforeWorldCleanup();assert(game.m_ERRTerrainSupportStations.empty()&&game.cleaned==1);
game.m_ERRTerrainSupportStations.Insert(&pump);game.ERR_CaptureTerrainSupportStations(nullptr);assert(game.m_ERRTerrainSupportStations.empty());
current=nullptr;assert(!pump.ERR_CanRestoreTerrainStation());current=&game;
}
''')
core=p.parent
server=body(core/'ERR_TerrainTakeover.c','protected void ERR_StopOriginalTerrainMode(') if 'protected void ERR_StopOriginalTerrainMode(' in (core/'ERR_TerrainTakeover.c').read_text() else (core/'ERR_TerrainTakeover.c').read_text()
assert server.index('ERR_CaptureTerrainSupportStations(')<server.index('m_ERRTerrainOriginal.OnGameEnd()')
client=body(core/'ERR_TerrainTakeoverClient.c','void ERR_BeginClientTerrainTakeover(')
assert client.index('ERR_CaptureTerrainSupportStations(')<client.index('mode.OnGameEnd()')
init=body(p,'override void OnPostInit(')
assert 'ERR_TerrainTakeoverMode.Cast(owner) && GetInstance() == this' in init
print('PASS: support registrations survive takeover on both peers, deduplicate, skip invalid stations, update item cleanup and clear on world teardown')