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:
2026-10-13 22:52:53 +02:00
parent a951a96edc
commit 6a667d8deb
8104 changed files with 2124945 additions and 2061 deletions
+25 -11
View File
@@ -8,19 +8,21 @@ source = ROOT/'addons/core/Scripts/Game/ERR/30_Map/ERRM_SharedMapComponent.c'
def adapt(signature):
text = body(source, signature).replace('protected ', '').replace('override ', '')
text = text.replace('MapConfiguration config', 'Config* config')
text = text.replace('IEntity owner', 'Entity* owner').replace('PlayerController playerController', 'PlayerController* playerController')
text = text.replace(' = null;', ' = nullptr;').replace('SCR_MapEntity.GetMapInstance()', 'Map::current')
text = text.replace('SCR_MapEntity.GetOnMapOpenComplete().Remove(OnMapRendererReady);', 'RemoveReadyListener();')
text = text.replace('GetGame().', 'GetGame()->').replace('GetCallqueue().', 'GetCallqueue()->')
for field in ['m_ESMMapEntity', 'm_ESMMapConfig', 'm_ESMRootWidget', 'm_ESMRenderTarget', 'playerController']:
for field in ['m_ESMMapEntity', 'm_ESMMapConfig', 'm_ESMRootWidget', 'm_ESMRenderTarget', 'm_ESMAtlas', 'playerController']:
text = text.replace(field+'.', field+'->')
for callback in ['TryCaptureMapSurface', 'CenterMapOnHolder', 'FinishMapCapture']:
for callback in ['TryCaptureMapSurface', 'CenterMapOnHolder', 'FinishMapCapture', 'PreserveNativeMapPriority']:
text = text.replace('.Remove('+callback+')', '.Remove(this, &Capture::'+callback+')')
text = text.replace('->Remove('+callback+')', '->Remove(this, &Capture::'+callback+')')
text = text.replace('CallLater('+callback+',', 'CallLater(this, &Capture::'+callback+',')
return text.replace('super.OnDelete(owner)', 'NativeDelete(owner)')
methods = '\n'.join(adapt(signature) for signature in [
'protected bool OwnsMapCapture(', 'protected void ReleaseMapCapture(',
'protected bool OwnsMapCapture(', 'protected void OnMapRendererReady(', 'protected void ReleaseMapCapture(',
'protected void FinishMapCapture(', 'protected void StopMapCapture(',
'protected void RestoreCharacterCamera(', 'protected override void OnDelete('])
run(r'''
@@ -28,7 +30,7 @@ run(r'''
#include <vector>
#include <algorithm>
struct Capture;struct Entity{};
struct Widget {bool enabled=true,removed=false;void SetEnabled(bool x){enabled=x;}void RemoveFromHierarchy(){removed=true;}};
struct Widget {bool enabled=true,visible=true,removed=false;void SetEnabled(bool x){enabled=x;}void SetVisible(bool x){visible=x;}void RemoveFromHierarchy(){removed=true;}};
struct Config {Widget* RootWidgetRef=nullptr;};
struct PlayerController {bool camera=false;int writes=0;void SetCharacterCameraRenderActive(bool x){camera=x;writes++;}};
struct Queue {
@@ -43,30 +45,33 @@ struct Map {static Map* current;bool opened=true;Config* config=nullptr;int clos
bool IsOpen(){return opened;}Config* GetMapConfig(){return config;}
void CloseMap(){closes++;opened=false;game.controller.SetCharacterCameraRenderActive(true);}
};Map* Map::current=nullptr;
struct Atlas {void Release(bool){}};
struct Capture {
Atlas* m_ESMAtlas=nullptr;
bool m_bESMInHand=true,m_bESMOwnsMapRenderer=false;
Map* m_ESMMapEntity=nullptr;Config* m_ESMMapConfig=nullptr;
Widget* m_ESMRootWidget=nullptr;Widget* m_ESMRenderTarget=nullptr;Entity* m_ESMCharacterOwner=nullptr;
static constexpr int MAP_RETRY_DELAY_MS=250;int completed=0,nativeDeletes=0;
void TryCaptureMapSurface(){}void CenterMapOnHolder(){}
static constexpr int MAP_RETRY_DELAY_MS=250,MAP_CAPTURE_DELAY_MS=500;bool readyListener=false;int centres=0;int completed=0,nativeDeletes=0,styleRestores=0;
void StopPaperInput(){}void RemoveReadyListener(){readyListener=false;}void TryCaptureMapSurface(){}void CenterMapOnHolder(){centres++;}void PreserveNativeMapPriority(){}
void RestorePaperMapStyle(){assert(OwnsMapCapture());styleRestores++;}
void CompleteMapModeSwitch(){completed++;}void NativeDelete(Entity*){nativeDeletes++;}
'''+methods+r'''
void Bind(Map& map,Config& config,Widget& root,Widget& target){
m_ESMMapEntity=&map;m_ESMMapConfig=&config;m_ESMRootWidget=&root;m_ESMRenderTarget=&target;
config.RootWidgetRef=&root;map.config=&config;map.opened=true;Map::current=&map;m_bESMOwnsMapRenderer=true;
readyListener=true;config.RootWidgetRef=&root;map.config=&config;map.opened=true;Map::current=&map;m_bESMOwnsMapRenderer=true;
}
};
int main(){Map map;Config mine,foreign;Widget root,target,foreignRoot;foreign.RootWidgetRef=&foreignRoot;
Capture normal;normal.Bind(map,mine,root,target);assert(normal.OwnsMapCapture());
normal.RestoreCharacterCamera();assert(game.controller.camera&&game.controller.writes==1);
normal.FinishMapCapture();assert(map.closes==1&&!target.enabled&&!normal.m_bESMOwnsMapRenderer&&!normal.m_ESMMapConfig&&normal.completed==1);
normal.FinishMapCapture();assert(map.closes==1&&normal.completed==1); // late duplicate has no authority
normal.FinishMapCapture();assert(map.closes==1&&!target.enabled&&!target.visible&&!normal.m_bESMOwnsMapRenderer&&!normal.m_ESMMapConfig&&normal.completed==1);
normal.FinishMapCapture();assert(map.closes==1&&normal.completed==1&&normal.styleRestores==1); // late duplicate has no authority
Capture replaced;replaced.Bind(map,mine,root,target);map.config=&foreign;game.controller.camera=false;
int writes=game.controller.writes,closes=map.closes;
replaced.RestoreCharacterCamera();assert(game.controller.writes==writes&&!game.controller.camera);
replaced.FinishMapCapture();assert(map.closes==closes&&map.opened&&replaced.completed==0&&!target.enabled);
assert(game.queue.Count(&replaced)==1); // defer vanilla focus until foreign UI closes
assert(game.queue.Count(&replaced)==1&&replaced.styleRestores==0); // defer vanilla focus until foreign UI closes
replaced.StopMapCapture();assert(game.queue.Count(&replaced)==0&&map.opened&&game.controller.writes==writes);
Capture reused;reused.Bind(map,mine,root,target);mine.RootWidgetRef=&foreignRoot;
@@ -83,6 +88,7 @@ int main(){Map map;Config mine,foreign;Widget root,target,foreignRoot;foreign.Ro
Capture owned,other;owned.Bind(map,mine,root,target);
game.queue.CallLater(&owned,&Capture::TryCaptureMapSurface,250,false);
game.queue.CallLater(&owned,&Capture::CenterMapOnHolder,100,false);
game.queue.CallLater(&owned,&Capture::PreserveNativeMapPriority,100,true);
game.queue.CallLater(&owned,&Capture::FinishMapCapture,500,false);
game.queue.CallLater(&other,&Capture::FinishMapCapture,500,false);
owned.OnDelete(nullptr);assert(game.queue.Count(&owned)==0&&game.queue.Count(&other)==1);
@@ -94,9 +100,17 @@ int main(){Map map;Config mine,foreign;Widget root,target,foreignRoot;foreign.Ro
writes=game.controller.writes;closes=map.closes;shuttingDown.OnDelete(nullptr);
assert(game.controller.writes==writes&&map.closes==closes&&shuttingDown.nativeDeletes==1);
currentGame=&game;
Capture waiting;waiting.Bind(map,mine,root,target);
game.queue.CallLater(&waiting,&Capture::FinishMapCapture,5000,false);
waiting.OnMapRendererReady(&foreign);assert(waiting.centres==0&&waiting.readyListener);
waiting.OnMapRendererReady(&mine);
assert(waiting.centres==1&&!waiting.readyListener&&game.queue.Count(&waiting)==1);
waiting.StopMapCapture();assert(!waiting.readyListener&&game.queue.Count(&waiting)==0);
Capture cancelled;cancelled.Bind(map,mine,root,target);cancelled.StopMapCapture();
cancelled.OnMapRendererReady(&mine);assert(cancelled.centres==0&&!cancelled.readyListener);
}
''')
center = body(source, 'protected void CenterMapOnHolder(')
center = body(source, 'protected void DrawSelectedPaperPage(')
assert center.index('!OwnsMapCapture()') < center.index('.ZoomPanSmooth(')
capture = body(source, 'protected void TryCaptureMapSurface(')
assert capture.index('m_ESMMapConfig = mapConfig;') < capture.index('.OpenMap(mapConfig)')