#!/usr/bin/env python3 """Import supported legacy settings without modifying either source or an existing destination.""" import argparse,json,os,tempfile,sys from pathlib import Path SCHEMA={ 'reportIntervalSeconds':(10,5,60), 'supportSquadLimit':(4,0,8), 'responseRadiusMetres':(2000,500,5000), 'aiIntelChancePercent':(60,0,100), 'intelRevealChancePercent':(15,0,100), 'radioDefenceSeconds':(180,30,1800), 'startTimeMinutes':(840,0,1439), 'timeMultiplier':(1,1,24), 'startDateCode':(0,0,1501231), 'weatherProfile':(0,0,3), 'stingerChanceOneIn':(15,0,10000), } AI_KEYS=('reportIntervalSeconds','supportSquadLimit','responseRadiusMetres','stingerChanceOneIn') INTEL_KEYS=('aiIntelChancePercent','intelRevealChancePercent') def merge(ai=None,intel=None): result={key:spec[0] for key,spec in SCHEMA.items()};deferred=[] for label,data,keys in [('ai',ai,AI_KEYS),('intel',intel,INTEL_KEYS)]: if data is None:continue if not isinstance(data,dict):raise ValueError(label+' settings must be a JSON object') if 'configVersion' in data and (type(data['configVersion']) not in (int,float) or data['configVersion']!=1): raise ValueError(label+' configVersion must be 1') for key in keys: if key not in data:continue value=data[key];_,lo,hi=SCHEMA[key] if type(value) not in (int,float) or not lo<=value<=hi or int(value)!=value: raise ValueError(f'{key} must be an integer in [{lo},{hi}]') result[key]=int(value) deferred.extend(label+':'+key for key in data if key not in keys and key!='configVersion') return result,deferred def write_new(path,text): path=Path(path) with tempfile.NamedTemporaryFile(mode='w',dir=path.parent,prefix='.rereintroduced-',delete=False) as f: tmp=Path(f.name) try: f.write(text);f.flush();os.fsync(f.fileno()) # Atomic installation that cannot overwrite an existing file, even in a race. os.link(tmp,path) finally:tmp.unlink(missing_ok=True) def main(): p=argparse.ArgumentParser(description=__doc__) p.add_argument('--ai',type=Path,help='Read-only escapists-ai.json source') p.add_argument('--intel',type=Path,help='Read-only escapists-intel.json source') p.add_argument('--out',type=Path,help='New rereintroduced.json; omit to preview on stdout') a=p.parse_args() if not a.ai and not a.intel:p.error('Supply --ai and/or --intel') try: result,deferred=merge(json.loads(a.ai.read_text()) if a.ai else None,json.loads(a.intel.read_text()) if a.intel else None) text=json.dumps(result,indent=2,allow_nan=False)+'\n' if a.out:write_new(a.out,text) else:print(text,end='') if deferred:print('Settings awaiting controller migration (source files retained): '+', '.join(deferred),file=sys.stderr) except (ValueError,OSError) as e:p.error(str(e)) if __name__=='__main__':main()