Files
ft/CodexOutput/upserver/KVGameplayLoopTests/apply_r1.py

69 lines
10 KiB
Python

from pathlib import Path
import re
root=Path(__file__).resolve().parents[3]
scripts=root/'Client/Assets/Scripts'
def patch(rel, changes):
p=scripts/rel
b=p.read_bytes()
for old,new in changes:
new=new.replace('\n','\r\n').encode()
if b.count(new)==1: continue
pattern=b'\r?\n'.join(re.escape(s.encode()) for s in old.split('\n'))
matches=list(re.finditer(pattern,b))
assert len(matches)==1,(rel,old[:100],len(matches))
m=matches[0]; b=b[:m.start()]+new+b[m.end():]
p.write_bytes(b)
def branch(body): return '#if UNITY_EDITOR && !SERVICE_HOST\n'+body+'\n#endif\n'
loop='game.PlayerDataStorage.PlayerKVGameplayLoop'
patch('SubBoostrap.cs', [(' rootCtxGo.AddComponent<PlayFabMgr>();',branch(' '+loop+'.BeforeBootstrap();')+' rootCtxGo.AddComponent<PlayFabMgr>();')])
patch('Core/PlayFabMgr.cs', [
(' _instance = this;\n',' _instance = this;\n'+branch(' if(PlayerKVGameplayLoop.Enabled) return;')),
(' void InitBuffer()\n',branch(' internal void StartKVGameplayLoopSync()\n {\n if(!PlayerKVGameplayLoop.Ready || tokenSource!=null) return;\n tokenSource=new CancellationTokenSource();\n UpdateUserDataValue(tokenSource.Token);\n }\n internal void StopKVGameplayLoopSync()\n { tokenSource?.Cancel(); tokenSource?.Dispose(); tokenSource=null; }')+' void InitBuffer()\n'),
(' PlayerKVGameLoadGuard.RequireLegacyAllowed(PlayerKVGuardPoint.Compare);',branch(' if(PlayerKVGameplayLoop.Enabled) throw PlayerKVGameplayLoop.Stop("PF archive comparison is disabled in KV loop.");')+' PlayerKVGameLoadGuard.RequireLegacyAllowed(PlayerKVGuardPoint.Compare);'),
(' void OnApplicationPause(bool is_pause)\n {\n',' void OnApplicationPause(bool is_pause)\n {\n'+branch(' if(PlayerKVGameplayLoop.Enabled)\n {\n if(is_pause) { StopKVGameplayLoopSync(); _=PlayerKVGameplayLoop.FlushObservedAsync(); }\n else StartKVGameplayLoopSync();\n return;\n }')),
(' void OnApplicationQuit()\n {\n',' void OnApplicationQuit()\n {\n'+branch(' if(PlayerKVGameplayLoop.Enabled) { StopKVGameplayLoopSync(); _=PlayerKVGameplayLoop.CloseAsync(); return; }')),
(' void OnDestroy()\n {\n',' void OnDestroy()\n {\n'+branch(' if(PlayerKVGameplayLoop.Enabled) { StopKVGameplayLoopSync(); _=PlayerKVGameplayLoop.CloseAsync(); return; }')),
(' PlayerKVGameLoadGuard.RequireLegacyAllowed(PlayerKVGuardPoint.Update);',branch(' if(PlayerKVGameplayLoop.Enabled) { PlayerKVGameplayLoop.Write(key,data,remoteStore); return; }')+' PlayerKVGameLoadGuard.RequireLegacyAllowed(PlayerKVGuardPoint.Update);'),
(' PlayerKVGameLoadGuard.RequireLegacyAllowed(PlayerKVGuardPoint.ReadLocal);',branch(' if(PlayerKVGameplayLoop.Enabled) return PlayerKVGameplayLoop.Read(key);')+' PlayerKVGameLoadGuard.RequireLegacyAllowed(PlayerKVGuardPoint.ReadLocal);'),
(' private void SyncData()\n {\n',' private void SyncData()\n {\n'+branch(' if(PlayerKVGameplayLoop.Enabled) { _=PlayerKVGameplayLoop.FlushObservedAsync(); return; }')),
(' public async Task<bool> SyncDataImmidiate(string key, string data)\n {\n',' public async Task<bool> SyncDataImmidiate(string key, string data)\n {\n'+branch(' if(PlayerKVGameplayLoop.Enabled) throw PlayerKVGameplayLoop.Stop("Immediate/consuming saves are outside the equipment loop.");'))
])
patch('Services/UserService.cs',[
(' if (evt.SessionVersion != customServerMgr.SessionVersion) return;\n',' if (evt.SessionVersion != customServerMgr.SessionVersion) return;\n'+branch(' if('+loop+'.Enabled) { '+loop+'.Fault("API unauthorized; restart required."); return; }')),
(' private async Task<ELoginStep> LoginCore(Action<int> progress, int generation)\n {\n',' private async Task<ELoginStep> LoginCore(Action<int> progress, int generation)\n {\n'+branch(' if('+loop+'.Enabled) return await LoginKVGameplayLoopAsync(progress,generation);')),
(' GetUserData = true,', '#if UNITY_EDITOR && !SERVICE_HOST\n GetUserData = !'+loop+'.Enabled,\n#else\n GetUserData = true,\n#endif'),
(' InitData(playfabUserData, UserId);',branch(' if(!'+loop+'.Enabled)')+' InitData(playfabUserData, UserId);'),
(' customServerMgr.UseAccountSession(session);\n',' customServerMgr.UseAccountSession(session);\n'+branch(' if('+loop+'.Enabled) return true; // Identity is published only after all KV modules load.')),
(' public virtual void Logout()\n {\n',' public virtual void Logout()\n {\n'+branch(' if('+loop+'.Enabled) { _=StopKVGameplayLoopAsync(); return; }'))
])
patch('Services/AggUserService.cs',[
(' public override async Task<ELoginStep> Login(Action<int> progress, bool tryLoginByToken = true)\n {\n',' public override async Task<ELoginStep> Login(Action<int> progress, bool tryLoginByToken = true)\n {\n'+branch(' if('+loop+'.Enabled)\n {\n CustomId='+loop+'.Permit.PlayerId;\n OnInitData+=InitData;\n try { return await LoginWithBackend(progress,"kv-loop"); }\n finally { OnInitData-=InitData; }\n }'))
])
# KVLoad has CRLF source, and these edits leave the controlled SERVICE_HOST admission unchanged.
patch('Services/UserService.KVLoad.cs',[
(' internal bool RejectSaveBackend(string backend)\n {\n',' internal bool RejectSaveBackend(string backend)\n {\n'+branch(' if(PlayerKVGameplayLoop.Enabled && backend=="kv-loop" && !kvControlledInstance)\n { KVLastError=PlayerKVGameLoadError.None; return false; }')),
(' if(!kvControlledInstance || InternalId!=0 || apiSession!=null)',' bool admitted=kvControlledInstance, sessionAllowed=apiSession==null;\n'+branch(' admitted=admitted || KVLoopLoading;\n sessionAllowed=sessionAllowed || KVLoopLoading;')+' if(!admitted || InternalId!=0 || !sessionAllowed)'),
(' if(!kvControlledInstance || state==null || raw==null) throw new InvalidOperationException("Controlled login state required.");',' bool admitted=kvControlledInstance;\n'+branch(' admitted=admitted || KVLoopLoading;')+' if(!admitted || state==null || raw==null) throw new InvalidOperationException("Controlled login state required.");')
])
patch('Stages/LoginStage.cs',[
(' if (!LoadingScreen.isShowing())',branch(' if('+loop+'.Enabled) startActId="PFLoginAct";')+' if (!LoadingScreen.isShowing())')
])
patch('Stages/PFLoginAct.cs',[
(' var configCustomId = config.Get<string>("CustomID", string.Empty);',' var configCustomId = config.Get<string>("CustomID", string.Empty);\n'+branch(' if('+loop+'.Enabled) configCustomId='+loop+'.Permit.PlayerId;').rstrip('\n')),
(' if (step != ELoginStep.Done)\n {\n',' if (step != ELoginStep.Done)\n {\n'+branch(' if('+loop+'.Enabled) throw '+loop+'.Stop("Login failed; restart the Unity process before another attempt.");'))
])
patch('Stages/QuitAct.cs',[
(' public override async Task<bool> StartAsync()\n {\n',' public override async Task<bool> StartAsync()\n {\n'+branch(' if('+loop+'.Enabled) _='+loop+'.CloseAsync();')),
(' if(userService is PlayFabUserService kvUser) await kvUser.ObserveKVQuitAsync();',branch(' if('+loop+'.Enabled) await PlayerDataStorage.PlayerKVShutdownRegistry.Process.ObserveAsync(5000);\n else')+' if(userService is PlayFabUserService kvUser) await kvUser.ObserveKVQuitAsync();')
])
patch('DataCenter/DataCenter.PlayerData.cs',[
(' public void SavePlayerData(bool remote = true)\n {\n GContext.Publish<PlayerData>(this);',' public void SavePlayerData(bool remote = true)\n {\n GContext.Publish<PlayerData>(this);\n SerializeAndSavePlayerData(remote);\n }\n\n'+branch(' internal async System.Threading.Tasks.Task SetEquipRodIDForKVLoopAsync(int id)\n {\n var batch='+loop+'.BeginEquip();\n game.PlayerDataStorage.PlayerKVEditResult primary;\n try\n {\n using(batch)\n {\n equipRodID=id;\n GContext.container.Resolve<PlayerFishData>().SetRedPoint();\n GContext.Publish<PlayerData>(this);\n primary=SerializeAndSavePlayerData(true);\n }\n await '+loop+'.ConfirmEquipAsync(batch,primary);\n }\n catch(System.Exception e) { '+loop+'.Fault(e.Message); throw; }\n }')+' private game.PlayerDataStorage.PlayerKVEditResult SerializeAndSavePlayerData(bool remote)\n {'),
(' PlayFabMgr.Instance.UpdateUserDataValue("NewPlayerDataDic", Newtonsoft.Json.JsonConvert.SerializeObject(NewPlayerDataDic), remote);',branch(' if('+loop+'.Enabled) return '+loop+'.Write("NewPlayerDataDic",Newtonsoft.Json.JsonConvert.SerializeObject(NewPlayerDataDic),remote);')+' PlayFabMgr.Instance.UpdateUserDataValue("NewPlayerDataDic", Newtonsoft.Json.JsonConvert.SerializeObject(NewPlayerDataDic), remote);\n return null;')
])
patch('UI/Rod/FishingRodPanel_Level.cs',[
(' void OnClickEquip()\n', '#if UNITY_EDITOR && !SERVICE_HOST\n bool kvEquipInFlight;\n async void OnClickEquip()\n#else\n void OnClickEquip()\n#endif\n'),
(' GContext.container.Resolve<PlayerData>().SetEquipRodID(data.config.ID);',branch(' if('+loop+'.Enabled)\n {\n if(kvEquipInFlight) return;\n kvEquipInFlight=true;\n try { await GContext.container.Resolve<PlayerData>().SetEquipRodIDForKVLoopAsync(data.config.ID); }\n catch(System.Exception e) { Debug.LogException(e); return; }\n finally { kvEquipInFlight=false; }\n }\n else')+' GContext.container.Resolve<PlayerData>().SetEquipRodID(data.config.ID);')
])
print('R1 whitelist patches applied without normalizing source bytes.')