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
+115 -2
View File
@@ -59,7 +59,7 @@ struct ERR_ObserverRules {
'''+body(p,'static int Cycle(')+body(p,'static bool Toggle(')+r'''
};
struct SCR_PlayerController {int calls=0,direction=0;void ERR_CycleObserver(int d){calls++;direction=d;}} pc;
struct Follow {bool m_LeftDown=false,m_RightDown=false,m_EnterDown=false,m_PlayerView=false;
struct Follow {bool m_LeftDown=false,m_RightDown=false,m_EnterDown=false,m_PlayerView=false;int m_InputResumeFrames=0;
'''+input_body+r'''
};
int main(){
@@ -71,10 +71,123 @@ int main(){
f.Input(true,false,false,false);f.Input(true,false,false,true);assert(f.m_PlayerView);
f.Input(true,false,false,true);assert(f.m_PlayerView);
f.Input(true,false,false,false);f.Input(true,false,false,true);assert(!f.m_PlayerView);
// Inactive chat context masks held keys as zero; submission must not become
// a new camera press when the context resumes (including its first zero frame).
f.Input(false,false,false,false);
f.Input(true,false,false,false);
f.Input(true,false,false,true);assert(!f.m_PlayerView);
f.Input(true,false,false,true);assert(!f.m_PlayerView);
f.Input(true,false,false,false);
f.Input(true,false,false,true);assert(f.m_PlayerView);
int before=pc.calls;
f.Input(false,false,false,false);
f.Input(true,false,false,false);
f.Input(true,true,false,false);f.Input(true,true,false,false);assert(pc.calls==before);
f.Input(true,false,false,false);f.Input(true,true,false,false);assert(pc.calls==before+1);
}
''')
# Execute the actual chat-manager state, capture helper, and pre-activation gate.
# Chat contexts expire independently of widget focus; open panels are authoritative.
def camera_ui_cpp(source):
import re
source=source.replace('override protected ', '').replace('super.', 'Base::').replace('null','nullptr')
# Enforce initializes local booleans to false; C++ otherwise leaves them undefined.
source=re.sub(r'\bbool (\w+);',r'bool \1=false;',source)
source=source.replace('GetGame().', 'GetGame()->').replace('GetInputManager().', 'GetInputManager()->').replace('GetWorkspace().', 'GetWorkspace()->')
for typ in ('SCR_ChatPanelManager','SCR_ChatPanel','EditBoxWidget','ERR_ObserverChatInput'):
source=source.replace(typ+'.',typ+'::')
source=source.replace('foreach (SCR_ChatPanel panel : m_aChatPanels)', 'for (SCR_ChatPanel panel : m_aChatPanels)')
pointer_names=[]
for typ in ('SCR_ChatPanelManager','SCR_ChatPanel','Widget','InputManager'):
pointer_names+=re.findall(r'\b'+typ+r' (\w+)',source)
source=re.sub(r'\b'+typ+r' (\w+)',typ+r'* \1',source)
for name in pointer_names:
source=re.sub(r'\b'+name+r'\.',name+'->',source)
source=source.replace('FindHandler(SCR_ChatPanel)', 'FindHandler()')
return source
manager_method=camera_ui_cpp(body(p,'bool ERR_HasOpenChatPanel('))
capture=camera_ui_cpp(body(p,'static bool Capture('))
gate=camera_ui_cpp(body(p,'override protected bool IsDisabledByMenu('))
ui_prelude=r'''#include <cassert>
#include <string>
#include <vector>
struct SCR_ChatPanel {bool open=false;bool IsOpen(){return open;}static SCR_ChatPanel*Cast(SCR_ChatPanel*p){return p;}};
struct Widget {Widget*parent=nullptr;bool edit=false;SCR_ChatPanel*handler=nullptr;Widget*GetParent(){return parent;}SCR_ChatPanel*FindHandler(){return handler;}};
struct EditBoxWidget {static Widget*Cast(Widget*w){return w&&w->edit?w:nullptr;}};
struct InputManager {bool chat=false;int renewals=0;
bool IsContextActive(const char*name){assert(std::string(name)=="ChatContext");return chat;}
void ActivateContext(const char*name,int durationMs){assert(std::string(name)=="ChatContext"&&durationMs==1);chat=true;renewals++;}
void Expire(){chat=false;}
} inputs;
struct Workspace {Widget*focus=nullptr;Widget*GetFocusedWidget(){return focus;}} workspace;
struct Game {InputManager*GetInputManager(){return &inputs;}Workspace*GetWorkspace(){return &workspace;}} game;
Game*GetGame(){return &game;}
struct SCR_ChatPanelManager {static SCR_ChatPanelManager*current;std::vector<SCR_ChatPanel*>m_aChatPanels;
static SCR_ChatPanelManager*GetInstance(){return current;}
'''+manager_method+r'''
} chatManager;
SCR_ChatPanelManager*SCR_ChatPanelManager::current=&chatManager;
struct ERR_ObserverChatInput {
'''+capture+r'''
};
struct Base {bool menu=false;bool IsDisabledByMenu(){return menu;}};
'''
ui_tests=r'''
int main(){
Camera c;SCR_ChatPanel registered,unregistered;
chatManager.m_aChatPanels={nullptr,&registered};
assert(!chatManager.ERR_HasOpenChatPanel());assert(!c.IsDisabledByMenu());assert(inputs.renewals==0);
// A dead observer can retain open chat after the native HUD stops renewing it.
// No focus or previously active context is required for registered open chat.
registered.open=true;assert(chatManager.ERR_HasOpenChatPanel());
assert(c.IsDisabledByMenu());assert(inputs.chat&&inputs.renewals==1);
inputs.Expire();assert(c.IsDisabledByMenu());assert(inputs.chat&&inputs.renewals==2);
// Native menus retain priority; a camera must not activate input behind them.
inputs.Expire();c.menu=true;assert(c.IsDisabledByMenu());assert(!inputs.chat&&inputs.renewals==2);c.menu=false;
registered.open=false;assert(!chatManager.ERR_HasOpenChatPanel());assert(!c.IsDisabledByMenu());
// An unregistered still-open panel is discoverable through focus ancestry.
Widget panelWidget,child,edit,ordinary;panelWidget.handler=&unregistered;child.parent=&panelWidget;
unregistered.open=true;workspace.focus=&child;
assert(c.IsDisabledByMenu());assert(inputs.chat&&inputs.renewals==3);
inputs.Expire();SCR_ChatPanelManager::current=nullptr;
assert(c.IsDisabledByMenu());assert(inputs.chat&&inputs.renewals==4);
// A closed panel cannot renew chat, even if it still owns focused widgets.
unregistered.open=false;inputs.Expire();assert(!c.IsDisabledByMenu());assert(inputs.renewals==4);
edit.edit=true;edit.parent=&panelWidget;workspace.focus=&edit;
assert(c.IsDisabledByMenu());assert(!inputs.chat&&inputs.renewals==4);
// Ordinary password/edit dialogs pause the camera without acquiring ChatContext.
edit.parent=nullptr;child.parent=&edit;workspace.focus=&child;
assert(c.IsDisabledByMenu());assert(!inputs.chat&&inputs.renewals==4);
workspace.focus=&ordinary;assert(!c.IsDisabledByMenu());workspace.focus=nullptr;
assert(!c.IsDisabledByMenu());SCR_ChatPanelManager::current=&chatManager;
// A residual native chat context still blocks the camera until it expires.
inputs.chat=true;assert(c.IsDisabledByMenu());assert(inputs.renewals==4);
inputs.Expire();assert(!c.IsDisabledByMenu());
// Integrate Capture with the production input edge/release state machine.
Follow f;registered.open=true;f.Input(!c.IsDisabledByMenu(),false,false,false);
registered.open=false;inputs.Expire();f.Input(!c.IsDisabledByMenu(),false,false,false);
f.Input(!c.IsDisabledByMenu(),false,false,true);f.Input(!c.IsDisabledByMenu(),false,false,true);
assert(!f.m_PlayerView); // submitting/holding Enter cannot become a camera toggle
f.Input(!c.IsDisabledByMenu(),false,false,false);f.Input(!c.IsDisabledByMenu(),false,false,true);assert(f.m_PlayerView);
registered.open=true;f.Input(!c.IsDisabledByMenu(),false,false,false);
registered.open=false;inputs.Expire();f.Input(!c.IsDisabledByMenu(),false,false,false);
f.Input(!c.IsDisabledByMenu(),true,false,false);assert(pc.calls==0);
f.Input(!c.IsDisabledByMenu(),false,false,false);f.Input(!c.IsDisabledByMenu(),true,false,false);assert(pc.calls==1);
}
'''
ui_follow=r'''
struct ERR_ObserverRules {
'''+body(p,'static int Cycle(')+body(p,'static bool Toggle(')+r'''
};
struct SCR_PlayerController {int calls=0,direction=0;void ERR_CycleObserver(int d){calls++;direction=d;}} pc;
struct Follow {bool m_LeftDown=false,m_RightDown=false,m_EnterDown=false,m_PlayerView=false;int m_InputResumeFrames=0;
'''+input_body+r'''
};
'''
run(ui_prelude+'struct Camera:Base {\n'+gate+'\n};\n'+ui_follow+ui_tests)
assert (ROOT/'addons/core/Prefabs/ERR/SpectatorCamera.et').read_text().startswith('ERR_ObserverCamera {')
config=(ROOT/'addons/core/Configs/ERR/ObserverInput.conf').read_text()
for key in ('KC_LEFT','KC_RIGHT','KC_RETURN','KC_NUMPADENTER'): assert f'keyboard:{key}' in config
assert 'chimeraInputCommon.conf' in config and 'ActionContext/ManualCameraContext.conf' in config
assert 'Debug.KeyState' not in p.read_text()
print('PASS: actual input dispatch, one press per edge, menu-held suppression; actual revival camera handoff with editor close/retry, missing camera, replacement body and stopped round')
print('PASS: actual open-chat capture/context renewal and camera/menu priority, text-entry isolation, held-key release; actual revival camera handoff with editor close/retry, missing camera, replacement body and stopped round')