Merge owned systems into one addon while preserving resource identities. Gate player admission on the replicated prison scene, restore the original framed door, and hold enemy AI until escape. Correct scenario branding and author metadata, include publishing assets, and retain regression and native verification evidence.
105 lines
6.9 KiB
Python
105 lines
6.9 KiB
Python
"""Execute actual shared-map ownership/callback cleanup with explicit API doubles.
|
|
|
|
No Enforce compilation, rendering, remote client or multiplayer claim.
|
|
"""
|
|
import re
|
|
from policy_harness import ROOT, body, run
|
|
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('IEntity owner', 'Entity* owner').replace('PlayerController playerController', 'PlayerController* playerController')
|
|
text = text.replace(' = null;', ' = nullptr;').replace('SCR_MapEntity.GetMapInstance()', 'Map::current')
|
|
text = text.replace('GetGame().', 'GetGame()->').replace('GetCallqueue().', 'GetCallqueue()->')
|
|
for field in ['m_ESMMapEntity', 'm_ESMMapConfig', 'm_ESMRootWidget', 'm_ESMRenderTarget', 'playerController']:
|
|
text = text.replace(field+'.', field+'->')
|
|
for callback in ['TryCaptureMapSurface', 'CenterMapOnHolder', 'FinishMapCapture']:
|
|
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 void FinishMapCapture(', 'protected void StopMapCapture(',
|
|
'protected void RestoreCharacterCamera(', 'protected override void OnDelete('])
|
|
run(r'''
|
|
#include <cassert>
|
|
#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 Config {Widget* RootWidgetRef=nullptr;};
|
|
struct PlayerController {bool camera=false;int writes=0;void SetCharacterCameraRenderActive(bool x){camera=x;writes++;}};
|
|
struct Queue {
|
|
using Entry=std::pair<Capture*,void(Capture::*)()>;std::vector<Entry> pending;
|
|
void Remove(Capture* owner,void(Capture::*callback)()){pending.erase(std::remove(pending.begin(),pending.end(),Entry(owner,callback)),pending.end());}
|
|
void CallLater(Capture* owner,void(Capture::*callback)(),int,bool){pending.emplace_back(owner,callback);}
|
|
int Count(Capture* owner){return std::count_if(pending.begin(),pending.end(),[=](const Entry& e){return e.first==owner;});}
|
|
};
|
|
struct Game {Queue queue;PlayerController controller;Queue* GetCallqueue(){return &queue;}PlayerController* GetPlayerController(){return &controller;}};
|
|
Game game;Game* currentGame=&game;Game* GetGame(){return currentGame;}
|
|
struct Map {static Map* current;bool opened=true;Config* config=nullptr;int closes=0;
|
|
bool IsOpen(){return opened;}Config* GetMapConfig(){return config;}
|
|
void CloseMap(){closes++;opened=false;game.controller.SetCharacterCameraRenderActive(true);}
|
|
};Map* Map::current=nullptr;
|
|
struct Capture {
|
|
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(){}
|
|
void CompleteMapModeSwitch(){completed++;}void NativeDelete(Entity*){nativeDeletes++;}
|
|
'''+methods+r'''
|
|
void Bind(Map& map,Config& config,Widget& root,Widget& target){
|
|
m_ESMMapEntity=↦m_ESMMapConfig=&config;m_ESMRootWidget=&root;m_ESMRenderTarget=⌖
|
|
config.RootWidgetRef=&root;map.config=&config;map.opened=true;Map::current=↦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
|
|
|
|
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
|
|
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;
|
|
assert(map.config==reused.m_ESMMapConfig&&!reused.OwnsMapCapture()); // same native object was reused
|
|
reused.FinishMapCapture();assert(map.closes==closes&&reused.completed==0);reused.StopMapCapture();
|
|
|
|
Capture oldWorld;oldWorld.Bind(map,mine,root,target);Map newWorld;Map::current=&newWorld;
|
|
oldWorld.StopMapCapture();assert(map.closes==closes&&game.controller.writes==writes);
|
|
|
|
Capture spare;Widget spareRoot,spareTarget;spare.m_ESMRootWidget=&spareRoot;spare.m_ESMRenderTarget=&spareTarget;
|
|
spare.OnDelete(nullptr);assert(spare.nativeDeletes==1&&spareRoot.removed&&!spareTarget.enabled);
|
|
assert(game.controller.writes==writes&&!game.controller.camera&&map.closes==closes);
|
|
|
|
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::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);
|
|
assert(map.closes==closes+1&&!map.opened&&root.removed&&!target.enabled);
|
|
assert(owned.m_ESMMapEntity==nullptr&&owned.m_ESMMapConfig==nullptr&&owned.m_ESMRootWidget==nullptr&&owned.nativeDeletes==1);
|
|
owned.FinishMapCapture();assert(owned.completed==0&&map.closes==closes+1);
|
|
|
|
Capture shuttingDown;shuttingDown.Bind(map,mine,root,target);currentGame=nullptr;
|
|
writes=game.controller.writes;closes=map.closes;shuttingDown.OnDelete(nullptr);
|
|
assert(game.controller.writes==writes&&map.closes==closes&&shuttingDown.nativeDeletes==1);
|
|
currentGame=&game;
|
|
}
|
|
''')
|
|
center = body(source, 'protected void CenterMapOnHolder(')
|
|
assert center.index('!OwnsMapCapture()') < center.index('.ZoomPanSmooth(')
|
|
capture = body(source, 'protected void TryCaptureMapSurface(')
|
|
assert capture.index('m_ESMMapConfig = mapConfig;') < capture.index('.OpenMap(mapConfig)')
|
|
assert capture.index('if (!OwnsMapCapture())') < capture.index('RestoreCharacterCamera();')
|
|
print('PASS: actual shared-map callbacks bind exact map/config/root, preserve replacement UI/camera, defer focus, and remove only owned delayed work')
|