35 lines
3.4 KiB
Python
35 lines
3.4 KiB
Python
from pathlib import Path
|
|
import hashlib,json
|
|
root=Path('Client/Assets/Scripts'); out=Path('CodexOutput/upserver/ReviewLifecycleTests')
|
|
def method(path, signature):
|
|
text=(root/path).read_text(encoding='utf-8-sig'); start=text.index(signature); opening=text.index('{',start); depth=1; end=opening+1
|
|
while depth:
|
|
depth+=(text[end]=='{')-(text[end]=='}'); end+=1
|
|
return text[start:end]
|
|
parts=[('GetUiSubject','Stages/FishingAct.cs',['async void GetUI()','async void NewEnterMap(PlayableDirector camera_timeline)','async Task OnCameraSpeedEvent()']),('ManagerSubject','Core/SoundMgr.cs',['public async Task Init(System.Action<float> progress)','public void Release()']),('ServiceSubject','Sound/SoundService.cs',['public async Task InitAsync(string mixerAddr','public void Release()'])]
|
|
generated='using System;using System.Linq;using System.Collections.Generic;using System.Threading;using System.Threading.Tasks;\n'
|
|
evidence=[]
|
|
for name,path,signatures in parts:
|
|
generated+=f'public partial class {name} {{\n'
|
|
for signature in signatures:
|
|
# SoundService also has an interface Release; select class suffix.
|
|
if name=='ServiceSubject' and signature=='public void Release()':
|
|
text=(root/path).read_text(encoding='utf-8-sig'); text=text[text.index('public class SoundService'):]
|
|
start=text.index(signature); opening=text.index('{',start); depth=1; end=opening+1
|
|
while depth: depth+=(text[end]=='{')-(text[end]=='}'); end+=1
|
|
raw=text[start:end]
|
|
else: raw=method(path,signature)
|
|
extracted=raw.replace('async void GetUI()', 'public async Task GetUI()').replace('async void NewEnterMap(', 'public async Task NewEnterMap(').replace('async Task OnCameraSpeedEvent()', 'public async Task OnCameraSpeedEvent()')
|
|
generated+=extracted+'\n'
|
|
evidence.append({'source':str(root/path),'signature':signature,'source_sha256':hashlib.sha256((root/path).read_bytes()).hexdigest(),'method_sha256':hashlib.sha256(raw.encode()).hexdigest(),'transformation':'async void -> public async Task only' if name=='GetUiSubject' else 'none'})
|
|
generated+='}\n'
|
|
stage_path='Stages/FishingStage.cs'; stage_text=(root/stage_path).read_text(encoding='utf-8-sig')
|
|
prefix=stage_text[stage_text.index('public override async Task StartAsync()'):stage_text.index('//GContext.Publish()')].replace('public override async Task StartAsync()', 'public async Task RunPrefix()')
|
|
stop=method(stage_path,'public override async Task Stop()')
|
|
destroy=method(stage_path,'protected override void OnDestroy()')
|
|
catch_start=stage_text.index('try { await base.StartAsync(); }'); catch_end=stage_text.index('//静默加载后续场景',catch_start); guard=stage_text[catch_start:catch_end]
|
|
generated+='public partial class StageSubject : StageBase {\n'+prefix+'Applied=true; }\n'+stop+'\n'+destroy+'\npublic async Task RunCatch(){ var loginLifetime=UserService.LoginLifetime;\n'+guard+'CatchCompleted=true; }\n}\n'
|
|
evidence.append({'source':str(root/stage_path),'source_sha256':hashlib.sha256((root/stage_path).read_bytes()).hexdigest(),'transformation':'StartAsync prefix ends before //GContext.Publish(); Stop and OnDestroy complete; actual base.StartAsync catch segment through next-scene comment; only wrapper names/assertion markers added'})
|
|
(out/'Generated.cs').write_text(generated,encoding='utf-8')
|
|
(out/'extraction.json').write_text(json.dumps(evidence,ensure_ascii=False,indent=2),encoding='utf-8')
|