Something went wrong. Try again.
Native control, inspection, UI automation and evidence capture for a running Witcher 3 process.
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102"""Optional owned background-mode ASI and a reversible 1080p windowed preset."""import hashlibimport jsonimport reimport subprocessimport timefrom pathlib import Path
from . import support
ROOT=Path(__file__).resolve().parent.parentSOURCE=ROOT/'native/PathBackground.cpp'BINARY=ROOT/'native/build/PathBackground.asi'RECEIPT=support.STATE_ROOT/'background-mode.json'TARGET=support.manage.GAME/'bin/x64_dx12/PathBackground.asi'SETTINGS=support.manage.DOCS/'dx12user.settings'COMPILER=support.manage.tool_path('toolchains/llvm-mingw-20261006-ucrt-ubuntu-22.04-x86_64/bin/x86_64-w64-mingw32-clang++')PRESET={'Resolution':'"1920x1080"','FullScreenMode':'0'}
def sha(path):return hashlib.sha256(Path(path).read_bytes()).hexdigest()
def viewport(raw,values=None): """Read/change only existing Viewport keys, preserving all other bytes.""" match=re.search(rb'(?m)^\[Viewport\]\r?\n(?:(?!^\[).)*',raw,re.S) if not match:raise ValueError('Missing Viewport section in DX12 settings') section=match.group();found={} for key in PRESET: pattern=rb'(?m)^('+key.encode()+rb'=)([^\r\n]*)(\r?\n|$)' rows=list(re.finditer(pattern,section)) if len(rows)!=1:raise ValueError('Expected exactly one Viewport '+key) found[key]=rows[0].group(2).decode() if values is not None: section=re.sub(pattern,lambda m:m.group(1)+values[key].encode()+m.group(3),section) return found if values is None else raw[:match.start()]+section+raw[match.end():]
def verify(): if not RECEIPT.exists(): if TARGET.exists():raise RuntimeError('Background ASI exists without an ownership receipt') return False receipt=json.loads(RECEIPT.read_text()) if receipt['state']=='disabled': if TARGET.exists():raise RuntimeError('Background ASI exists after recorded removal') return False if receipt['state']!='enabled':raise RuntimeError('Background setup is incomplete; inspect background-mode.json and retained backup') if not TARGET.exists() or sha(TARGET)!=receipt['binary_sha256']:raise RuntimeError('Background ASI differs from its ownership receipt') return True
def status(): enabled=verify();identity=None;loaded=False try: identity=support.process() loaded=any(str(TARGET) in line and int(line.split()[4])==TARGET.stat().st_ino for line in (Path('/proc')/str(identity['pid'])/'maps').read_text().splitlines()) if enabled else False except RuntimeError:pass settings=viewport(SETTINGS.read_bytes()) return dict(ok=True,enabled=enabled,mapped_in_game=loaded,process=identity,settings=settings,windowed=settings['FullScreenMode'] in ('0','1'),receipt=str(RECEIPT),semantics='Suppress main game window focus-loss handling; retain normal menu/lab pauses. Does not keep the OS focused on the game. Hidden keyboard/mouse events, key polling and cursor capture/warps are suppressed; native virtual-controller automation remains available.',qualification='Simulation continuity is live-tested separately from DLL mapping. Hidden-workspace presentation cadence is not a foreground performance benchmark.')
def enable(): support.manage.ensure_game_closed() if verify():return status() BINARY.parent.mkdir(exist_ok=True) subprocess.run([str(COMPILER),'-std=c++17','-O2','-shared','-static','-Wall','-Wextra','-Werror',str(SOURCE),'-luser32','-o',str(BINARY)],check=True) before=SETTINGS.read_bytes();previous=viewport(before);after=viewport(before,PRESET) folder=support.ARTIFACTS/('background-'+str(time.time_ns()));folder.mkdir() (folder/'dx12user.settings.before').write_bytes(before) receipt=dict(version=1,state='installing',path=str(TARGET),binary_sha256=sha(BINARY),source_sha256=sha(SOURCE),executable_sha256=sha(TARGET.parent/'witcher3.exe'),compiler=str(COMPILER),settings=str(SETTINGS),previous_viewport=previous,preset=PRESET,backup=str(folder/'dx12user.settings.before')) support.atomic_json(RECEIPT,receipt) try: # Exclusive creation: never replace a different mod or unowned file. with TARGET.open('xb') as f:f.write(BINARY.read_bytes()) SETTINGS.write_bytes(after) except Exception: if TARGET.exists() and sha(TARGET)==receipt['binary_sha256']:TARGET.unlink() if SETTINGS.read_bytes()==after:SETTINGS.write_bytes(before) receipt['state']='disabled';support.atomic_json(RECEIPT,receipt) raise receipt['state']='enabled';support.atomic_json(RECEIPT,receipt) return status()
def prepare_disable(): """Validate ownership and construct restoration without changing any files.""" if not verify():return None receipt=json.loads(RECEIPT.read_text());before=SETTINGS.read_bytes() if viewport(before)!=receipt['preset']:raise RuntimeError('Owned display options changed externally; inspect background-mode.json before restoring') after=viewport(before,receipt['previous_viewport']) return receipt,after
def disable(): support.manage.ensure_game_closed() prepared=prepare_disable() if prepared is None:return dict(ok=True,enabled=False,reason='already_disabled') receipt,after=prepared # Preserve independently changed graphics settings; restore only our two keys. SETTINGS.write_bytes(after);TARGET.unlink() receipt['state']='disabled';support.atomic_json(RECEIPT,receipt) return dict(ok=True,enabled=False,restored_viewport=receipt['previous_viewport'],other_settings_preserved=True)