Include the current addon, terrain integrations, tools, regression tests and recorded development evidence.
44 lines
5.3 KiB
Python
44 lines
5.3 KiB
Python
from pathlib import Path
|
|
import sys,os,json,subprocess,time,shutil,signal,hashlib
|
|
ROOT=Path('/home/jakub/devel/escapistsrereintroduced');sys.path.insert(0,str(ROOT/'tools'))
|
|
from external_addons import policy,prepare_profile
|
|
runtime=Path('/tmp/erri-takeover-dedicated-runtime');source=Path('/tmp/erri-takeover-radio-missing-source');run=Path('/tmp/erri-takeover-radio-missing');run.mkdir()
|
|
shutil.copytree('/tmp/erri-takeover-pair-source29',source)
|
|
p=source/'Scripts/Game/ERR/00_Core/ERR_ZTerrainManagerProof.c'
|
|
p.write_text(p.read_text().split('class ERR_PairRestartProof')[0])
|
|
(source/'Scripts/Game/ERR/00_Core/ERR_TerrainValidationProbe.c').write_text('modded class ArmaReforgerScripted\n{\n protected RadioManagerEntity m_ERRRadioFixtureOriginal;\n protected bool m_ERRRadioFixtureDone;\n protected override void OnWorldPostProcess(World world)\n {\n SCR_BaseGameMode mode = SCR_BaseGameMode.Cast(GetGameMode());\n ChimeraWorld chimera = ChimeraWorld.CastFrom(world);\n RadioManagerEntity radio;\n if (chimera) radio = chimera.GetRadioManager();\n if (Replication.IsServer() && mode && !ERR_GameMode.Cast(mode) && radio)\n {\n m_ERRRadioFixtureOriginal = radio;\n SCR_EntityHelper.DeleteEntityAndChildren(radio);\n PrintFormat("ERR RADIO FIXTURE SETUP: missing parent=%1", radio && radio.GetParent() == mode);\n }\n super.OnWorldPostProcess(world);\n }\n override void OnUpdate(BaseWorld world, float timeslice)\n {\n super.OnUpdate(world, timeslice);\n ERR_GameMode mode = ERR_GameMode.Get();\n if (m_ERRRadioFixtureDone || !mode || !mode.Active()) return;\n m_ERRRadioFixtureDone = true;\n ChimeraWorld chimera = ChimeraWorld.CastFrom(world);\n RadioManagerEntity radio = chimera.GetRadioManager();\n bool ok = radio && !radio.GetParent() && !m_ERRRadioFixtureOriginal;\n PrintFormat("ERR RADIO FIXTURE RESULT: missing ok=%1 radio=%2", ok, radio);\n }\n}\n')
|
|
steam=Path.home()/'.local/share/Steam';game=steam/'steamapps/common/Arma Reforger';addons=run/'addons';addons.mkdir()
|
|
prepare_profile(addons,steam/'steamapps/compatdata/1874880/pfx/drive_c/users/steamuser/Documents/My Games/ArmaReforger/addons',policy(ROOT),run/'external-cache.json')
|
|
(addons/'ERR_Core').symlink_to('/tmp/source',target_is_directory=True)
|
|
(addons/'Nogova').symlink_to('/home/jakub/devel/gabreta/addons/NogovaReforger',target_is_directory=True)
|
|
if not (runtime/'addons').exists():(runtime/'addons').symlink_to(game/'addons',target_is_directory=True)
|
|
for name in ('profile','home','tmp'):(run/name).mkdir()
|
|
config={'bindAddress':'127.0.0.1','bindPort':22991,'game':{'name':'Private terrain takeover test','password':'private-local-probe','scenarioId':'{469880DFE1B48F95}Missions/Nogova_TerrainTest.conf','maxPlayers':8,'visible':False,'supportedPlatforms':['PLATFORM_PC'],'gameProperties':{'battlEye':False,'missionHeader':{'m_bERR_EnableEscape':True,'m_sERR_Airfields':'1525 5075','m_eSaveTypes':0}}}}
|
|
(run/'server.json').write_text(json.dumps(config,indent=2))
|
|
exe=['/tmp/runtime/ArmaReforgerServer','-server','{469880DFE1B48F95}Missions/Nogova_TerrainTest.conf','-errTerrainTakeover','1','-errAirfields','1525 5075','-profile','/tmp/work/profile','-addonsDir','/tmp/work/addons','-addons','2528466DE220D91C,70C981A53E02B64F','-noBackend','-bindIP','127.0.0.1','-bindPort','22991','-maxFPS','30','-logconsole','-noSound','-noSplash','-noThrow','-disableCrashReporter']
|
|
from dedicated_native import PROBE
|
|
(run/'network_probe.py').write_text(PROBE)
|
|
cmd=['bwrap','--unshare-net','--unshare-pid','--unshare-ipc','--unshare-uts','--die-with-parent','--cap-drop','ALL','--clearenv','--ro-bind','/','/','--tmpfs','/tmp','--proc','/proc','--dev','/dev','--ro-bind',str(runtime),'/tmp/runtime','--bind',str(source),'/tmp/source','--bind',str(run),'/tmp/work','--setenv','HOME','/tmp/work/home','--setenv','TMPDIR','/tmp/work/tmp','--setenv','PATH','/usr/bin:/bin','--setenv','LANG','C.UTF-8','--chdir','/tmp/runtime','/usr/bin/python3','/tmp/work/network_probe.py',os.readlink('/proc/self/ns/net'),*exe]
|
|
(run/'command.json').write_text(json.dumps(cmd,indent=2))
|
|
(run/'source-before.json').write_text(json.dumps({str(p.relative_to(source)):hashlib.sha256(p.read_bytes()).hexdigest() for p in source.rglob('*') if p.is_file() and p.name!='resourceDatabase.rdb'},indent=2))
|
|
child=None;started=time.time();reason='deadline'
|
|
with (run/'stdout.log').open('w') as log:
|
|
try:
|
|
child=subprocess.Popen(cmd,stdout=log,stderr=subprocess.STDOUT,start_new_session=True)
|
|
while time.time()-started<180:
|
|
if child.poll() is not None:reason='process-exit';break
|
|
logs=sorted((run/'profile/logs').glob('logs_*/console.log'))
|
|
if logs:
|
|
s=logs[-1].read_text(errors='replace')
|
|
if 'ERR RADIO FIXTURE RESULT: missing ok=1' in s:reason='mission-started';break
|
|
if 'ERR RADIO FIXTURE RESULT: missing ok=0' in s or 'terrain takeover failed' in s or "Can't compile" in s or 'Unable to initialize the game' in s:reason='startup-failed';break
|
|
time.sleep(1)
|
|
finally:
|
|
if child and child.poll() is None:
|
|
os.killpg(child.pid,signal.SIGTERM)
|
|
try:child.wait(timeout=10)
|
|
except subprocess.TimeoutExpired:os.killpg(child.pid,signal.SIGKILL);child.wait(timeout=5)
|
|
result={'reason':reason,'exit_code':child.returncode if child else None,'supervisor_reaped':child is not None and child.poll() is not None,'seconds':round(time.time()-started,2)}
|
|
(run/'result.json').write_text(json.dumps(result,indent=2));print(result)
|
|
print(run)
|