Fix convoy coordination, AI combat and spectator recovery
This commit is contained in:
@@ -0,0 +1,80 @@
|
||||
"""Execute production input dispatch and recovery with native camera/editor doubles."""
|
||||
from policy_harness import ROOT,body,run
|
||||
p=ROOT/'addons/core/Scripts/Game/ERR/00_Core/ERR_Observer.c'
|
||||
s=body(p,'protected void ERR_UpdateRecoveryCamera(').replace('protected ','').replace('ERR_GameMode mode','ERR_GameMode* mode').replace('null','nullptr')
|
||||
for name in ('ERR_Actors','SCR_EditorManagerEntity','LogLevel'):
|
||||
s=s.replace(name+'.',name+'::')
|
||||
for name in ('SCR_EditorManagerEntity','CameraManager','CameraBase'):
|
||||
s=s.replace(name+' ',name+'* ')
|
||||
for name in ('mode','editor','manager'):
|
||||
s=s.replace(name+'.',name+'->')
|
||||
s=s.replace('GetGame().','GetGame()->').replace('GetWorld().','GetWorld()->')
|
||||
run(r'''#include <cassert>
|
||||
struct Actor {bool alive=true,conscious=true;};using IEntity=Actor*;
|
||||
struct ERR_Actors {static bool Alive(IEntity a){return a&&a->alive;}static bool CanFight(IEntity a){return Alive(a)&&a->conscious;}};
|
||||
struct ERR_GameMode {bool active=true;bool Active(){return active;}};
|
||||
struct SCR_EditorManagerEntity {bool opened=false,canClose=true;int closes=0;static SCR_EditorManagerEntity* current;static SCR_EditorManagerEntity* GetInstance(){return current;}bool IsOpened(){return opened;}void Close(bool){closes++;if(canClose)opened=false;}} editor;
|
||||
SCR_EditorManagerEntity* SCR_EditorManagerEntity::current=&editor;
|
||||
struct CameraBase{} player,other;
|
||||
struct CameraManager {CameraBase* current=&other;int sets=0;void SetCamera(CameraBase* c){current=c;sets++;}CameraBase* CurrentCamera(){return current;}} manager;
|
||||
struct World {float now=0;float GetWorldTime(){return now;}} world;
|
||||
struct Game {World* GetWorld(){return &world;}CameraManager* GetCameraManager(){return &manager;}} game;
|
||||
Game* GetGame(){return &game;}namespace LogLevel {enum{WARNING};}int warnings=0;void Print(const char*,int){warnings++;}
|
||||
struct Controller {
|
||||
IEntity controlled=nullptr,m_ERRRecoveryBody=nullptr;float m_ERRRecoveryDeadline=-1;CameraBase* camera=&player;
|
||||
IEntity GetControlledEntity(){return controlled;}CameraBase* GetPlayerCamera(){return camera;}
|
||||
'''+s+r'''
|
||||
};
|
||||
int main(){
|
||||
ERR_GameMode mode;Actor body,replacement;Controller c;c.controlled=&body;
|
||||
// Healthy admins retain their camera: restoration belongs only to recovery.
|
||||
c.ERR_UpdateRecoveryCamera(&mode);assert(manager.sets==0&&editor.closes==0);
|
||||
body.conscious=false;c.ERR_UpdateRecoveryCamera(&mode);assert(c.m_ERRRecoveryBody==&body&&manager.sets==0);
|
||||
// Recovery works with NO observer-camera instance and a different active camera.
|
||||
editor.opened=true;body.conscious=true;c.ERR_UpdateRecoveryCamera(&mode);
|
||||
assert(editor.closes==1&&!editor.opened&&manager.current==&player&&!c.m_ERRRecoveryBody);
|
||||
manager.current=&other;c.ERR_UpdateRecoveryCamera(&mode);assert(manager.current==&other); // no permanent camera lock
|
||||
// An asynchronously closing editor retains the pending recovery; next tick completes.
|
||||
body.conscious=false;c.ERR_UpdateRecoveryCamera(&mode);body.conscious=true;editor.opened=true;editor.canClose=false;
|
||||
c.ERR_UpdateRecoveryCamera(&mode);assert(c.m_ERRRecoveryBody==&body);
|
||||
editor.canClose=true;c.ERR_UpdateRecoveryCamera(&mode);assert(!c.m_ERRRecoveryBody&&manager.current==&player);
|
||||
// Wait for late camera creation, then return once.
|
||||
body.conscious=false;c.ERR_UpdateRecoveryCamera(&mode);body.conscious=true;c.camera=nullptr;
|
||||
c.ERR_UpdateRecoveryCamera(&mode);assert(c.m_ERRRecoveryBody==&body);
|
||||
c.camera=&player;c.ERR_UpdateRecoveryCamera(&mode);assert(!c.m_ERRRecoveryBody);
|
||||
// Refused editor close is bounded, warning instead of permanently stealing input.
|
||||
body.conscious=false;c.ERR_UpdateRecoveryCamera(&mode);body.conscious=true;editor.opened=true;editor.canClose=false;
|
||||
c.ERR_UpdateRecoveryCamera(&mode);world.now=10001;c.ERR_UpdateRecoveryCamera(&mode);assert(!c.m_ERRRecoveryBody&&warnings==1);
|
||||
editor.opened=false;editor.canClose=true;
|
||||
// Changed possession / stopped round must not return a stale casualty's camera.
|
||||
body.conscious=false;c.ERR_UpdateRecoveryCamera(&mode);c.controlled=&replacement;int before=manager.sets;
|
||||
c.ERR_UpdateRecoveryCamera(&mode);assert(!c.m_ERRRecoveryBody&&manager.sets==before);
|
||||
c.controlled=&body;c.ERR_UpdateRecoveryCamera(&mode);mode.active=false;body.conscious=true;
|
||||
c.ERR_UpdateRecoveryCamera(&mode);assert(!c.m_ERRRecoveryBody&&manager.sets==before);
|
||||
}
|
||||
''')
|
||||
input_body=body(p,'void Input(').replace('SCR_PlayerController controller = SCR_PlayerController.Cast(GetGame().GetPlayerController());','SCR_PlayerController* controller = &pc;').replace('controller.','controller->').replace('ERR_ObserverRules.','ERR_ObserverRules::')
|
||||
run(r'''#include <cassert>
|
||||
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;
|
||||
'''+input_body+r'''
|
||||
};
|
||||
int main(){
|
||||
Follow f;f.Input(true,true,false,false);assert(pc.calls==1&&pc.direction==-1);
|
||||
f.Input(true,true,false,false);assert(pc.calls==1);
|
||||
f.Input(true,false,false,false);f.Input(true,false,true,false);assert(pc.calls==2&&pc.direction==1);
|
||||
f.Input(true,true,true,false);assert(pc.calls==2);
|
||||
f.Input(false,false,false,true);f.Input(true,false,false,true);assert(!f.m_PlayerView); // menu-held Enter
|
||||
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);
|
||||
}
|
||||
''')
|
||||
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')
|
||||
Reference in New Issue
Block a user