pre cw with probe and a bunch script to read game behavior
This commit is contained in:
1 parent
5120219ae2
commit
da8a32f60d
310 files changed
+219693
-872
No files matched your search
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,30 @@
|
||||
-- Inspect only the named Peak module and configuration loader; no state writes.
|
||||
do
|
||||
local s=_G.__gacPeakCycleSchema1 or {phase=0,index=0};_G.__gacPeakCycleSchema1=s
|
||||
local function log(v)CS.UnityEngine.Debug.Log('[GAC_PEAK_CYCLE_SCHEMA] '..tostring(v))end
|
||||
if s.phase<3 then
|
||||
local ok,err=pcall(function()
|
||||
local flags=CS.System.Enum.ToObject(typeof(CS.System.Reflection.BindingFlags),60)
|
||||
if s.phase==0 then
|
||||
local m=CS.RPG.Client.GlobalVars.s_ModuleManager.ChallengePeakModule
|
||||
s.module=m;s.fields=m:GetType():GetFields(flags);log('MODULE '..tostring(m:GetType()));s.phase=1
|
||||
end
|
||||
if s.phase==1 then
|
||||
for i=s.index,math.min(s.index+15,s.fields.Length-1)do
|
||||
local f=s.fields[i];log('FIELD '..f.Name..' '..tostring(f.FieldType))
|
||||
if not f.IsStatic and (f.Name:lower():find('cycle') or f.Name:lower():find('settle') or f.Name:lower():find('result')) then
|
||||
local good,v=pcall(function()return f:GetValue(s.module)end);if good then log('VALUE '..f.Name..' '..tostring(v))end
|
||||
end
|
||||
end
|
||||
s.index=s.index+16;if s.index>=s.fields.Length then s.phase=2;s.index=0;s.methods=typeof(CS.RPG.GameCore.GameCoreConfigLoader):GetMethods(flags)end
|
||||
elseif s.phase==2 then
|
||||
for i=s.index,math.min(s.index+127,s.methods.Length-1)do
|
||||
local m=s.methods[i];if m.Name:find('ChallengePeak',1,true)then log('LOADER '..tostring(m))end
|
||||
end
|
||||
s.index=s.index+128;if s.index>=s.methods.Length then s.phase=3;log('END')end
|
||||
end
|
||||
end)
|
||||
if not ok then s.phase=3;log('ERROR '..tostring(err))end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
do
|
||||
local s=_G.__gacPeakNativeData1 or {phase=1,index=0};_G.__gacPeakNativeData1=s
|
||||
local function log(v)CS.UnityEngine.Debug.Log('[GAC_PEAK_NATIVE_DATA] '..tostring(v))end
|
||||
if s.phase<=3 then
|
||||
local ok,err=pcall(function()
|
||||
local flags=CS.System.Enum.ToObject(typeof(CS.System.Reflection.BindingFlags),60)
|
||||
if s.phase==1 then
|
||||
local obj=CS.RPG.Client.GlobalVars.s_ModuleManager.BattleModule.LastBattleStatistic
|
||||
local methods=obj:GetType():GetMethods(flags)
|
||||
for i=s.index,math.min(s.index+31,methods.Length-1)do log('STATS_METHOD '..tostring(methods[i]))end
|
||||
s.index=s.index+32;if s.index>=methods.Length then s.phase=2;s.index=0 end
|
||||
elseif s.phase==2 then
|
||||
if not s.obj then
|
||||
s.obj=CS.RPG.Client.GlobalVars.s_ModuleManager.ChallengePeakModule:GetChallengePeakBoss(104)
|
||||
s.type=s.obj:GetType();s.fields=s.type:GetFields(flags);log('PEAK_TYPE '..tostring(s.type))
|
||||
end
|
||||
for i=s.index,math.min(s.index+15,s.fields.Length-1)do
|
||||
local f=s.fields[i];log('PEAK_FIELD '..f.Name..' '..tostring(f.FieldType))
|
||||
if not f.IsStatic and (f.Name:lower():find('target')or f.FieldType.IsPrimitive)then
|
||||
local good,v=pcall(function()return f:GetValue(s.obj)end);if good then log('PEAK_VALUE '..f.Name..' '..tostring(v))end
|
||||
end
|
||||
end
|
||||
s.index=s.index+16;if s.index>=s.fields.Length then
|
||||
if s.type.BaseType and s.type.BaseType.Name=='ChallengePeak' then s.type=s.type.BaseType;s.fields=s.type:GetFields(flags);s.index=0;log('PEAK_BASE '..tostring(s.type))else s.phase=3;s.index=0 end
|
||||
end
|
||||
else
|
||||
local t=typeof(CS.RPG.GameCore.ChallengePeakTargetConfigRow)
|
||||
local fields=t:GetFields(flags);for i=0,math.min(fields.Length-1,23)do log('TARGET_FIELD '..fields[i].Name..' '..tostring(fields[i].FieldType))end
|
||||
s.phase=4;log('END')
|
||||
end
|
||||
end)
|
||||
if not ok then s.phase=4;log('ERROR '..tostring(err))end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
do
|
||||
if not _G.__gacPeakTargetRows1 then
|
||||
_G.__gacPeakTargetRows1=true
|
||||
local function log(v)CS.UnityEngine.Debug.Log('[GAC_PEAK_TARGET_ROWS] '..tostring(v))end
|
||||
local ok,err=pcall(function()
|
||||
local ids={3000,3001,3002,3003,3004,3005,3007}
|
||||
for _,id in ipairs(ids)do
|
||||
local row=CS.RPG.GameCore.BattleTargetExcelTable.dataDict[id]
|
||||
if row==nil then error('Missing BattleTarget '..id)end
|
||||
log('ROW '..CS.Newtonsoft.Json.JsonConvert.SerializeObject(row))
|
||||
end
|
||||
log('END')
|
||||
end)
|
||||
if not ok then log('ERROR '..tostring(err))end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
do
|
||||
if not _G.__gacPeakTargetsExport1 then
|
||||
_G.__gacPeakTargetsExport1=true
|
||||
local function log(v)CS.UnityEngine.Debug.Log('[GAC_PEAK_TARGETS] '..tostring(v))end
|
||||
local ok,err=pcall(function()
|
||||
local flags=CS.System.Enum.ToObject(typeof(CS.System.Reflection.BindingFlags),60)
|
||||
local obj=CS.RPG.Client.GlobalVars.s_ModuleManager.ChallengePeakModule:GetChallengePeakBoss(104)
|
||||
for _,name in ipairs({'_Meta','_BossMeta'})do
|
||||
local f=obj:GetType():GetField(name,flags);if f then log('META '..name..' '..CS.Newtonsoft.Json.JsonConvert.SerializeObject(f:GetValue(obj)))end
|
||||
end
|
||||
local targets=obj:GetType():GetField('_Targets',flags):GetValue(obj)
|
||||
log('COUNT '..targets.Count)
|
||||
for i=0,math.min(targets.Count-1,15)do
|
||||
local target=targets[i];local fields=target:GetType():GetFields(flags)
|
||||
for j=0,fields.Length-1 do
|
||||
local f=fields[j];log('FIELD '..f.Name..' '..tostring(f.FieldType))
|
||||
if f.Name:find('Meta')then log('ROW '..CS.Newtonsoft.Json.JsonConvert.SerializeObject(f:GetValue(target)))end
|
||||
end
|
||||
end
|
||||
end)
|
||||
if not ok then log('ERROR '..tostring(err))end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
-- Read-only active-season lookup from the native named constant table.
|
||||
do
|
||||
if not _G.__gacCwActiveSeason1 then
|
||||
_G.__gacCwActiveSeason1=true
|
||||
local function log(v)CS.UnityEngine.Debug.Log('[GAC_CW_ACTIVE] '..tostring(v))end
|
||||
local ok,err=pcall(function()
|
||||
local constants=CS.RPG.GameCore.ConstValueCommonExcelTable
|
||||
local seasonID=constants.GetData('GridFight_Season_ID').Value.IntValue
|
||||
local subSeasonID=constants.GetData('GridFight_Sub_Season_ID').Value.IntValue
|
||||
log('IDS '..seasonID..' '..subSeasonID)
|
||||
local module=CS.RPG.Client.GlobalVars.s_ModuleManager.GridFightModule
|
||||
local season=module:GetSeason(seasonID,subSeasonID)
|
||||
local flags=CS.System.Enum.ToObject(typeof(CS.System.Reflection.BindingFlags),60)
|
||||
local invoke=CS.System.Enum.ToObject(typeof(CS.System.Reflection.BindingFlags),0)
|
||||
local args=CS.System.Array.CreateInstance(typeof(CS.System.Object),0)
|
||||
local row=season:GetType():GetMethod('get__Meta',flags):Invoke(season,invoke,nil,args,nil)
|
||||
log('SEASON_ROW '..CS.Newtonsoft.Json.JsonConvert.SerializeObject(row))
|
||||
local configs=season.SeasonDivision.SeasonDivisionConfigs
|
||||
log('DIVISIONS '..configs.Count)
|
||||
_G.__gacCwActiveDivisionExport={configs=configs,index=0}
|
||||
end)
|
||||
if not ok then log('ERROR '..tostring(err))end
|
||||
end
|
||||
local state=_G.__gacCwActiveDivisionExport
|
||||
if state and not state.done then
|
||||
local function log(v)CS.UnityEngine.Debug.Log('[GAC_CW_ACTIVE_DIVISIONS] '..tostring(v))end
|
||||
local ok,err=pcall(function()
|
||||
if state.index==0 then log('BEGIN count='..state.configs.Count)end
|
||||
for i=state.index,math.min(state.index+7,state.configs.Count-1)do
|
||||
local row=state.configs[i]
|
||||
log('ROW {"ID":'..row.ID..',"SeasonID":'..row.SeasonID..',"DivisionLevel":'..row.DivisionLevel..',"Progress":'..row.Progress..',"IsPromotion":'..tostring(row.IsPromotion)..'}')
|
||||
end
|
||||
state.index=state.index+8
|
||||
if state.index>=state.configs.Count then log('END');state.done=true end
|
||||
end)
|
||||
if not ok then log('ERROR '..tostring(err));state.done=true end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,23 @@
|
||||
-- Read the active stage's flat Excel row, not its scene/level graph.
|
||||
do
|
||||
if _G.__gacCwActiveStageRow2 then return end
|
||||
local log=function(v)CS.UnityEngine.Debug.Log('[GAC_CW_ACTIVE_STAGE_ROW] '..tostring(v))end
|
||||
local ok,err=pcall(function()
|
||||
local flags=CS.System.Enum.ToObject(typeof(CS.System.Reflection.BindingFlags),60)
|
||||
local session=CS.RPG.Client.GlobalVars.s_ModuleManager.GridFightModule.CurGameSession
|
||||
if not session then return end
|
||||
local fields=session:GetType():GetFields(flags)
|
||||
for i=0,math.min(fields.Length-1,63)do
|
||||
local field=fields[i]
|
||||
if field.FieldType.FullName=='RPG.Client.GridFightStage'then
|
||||
local stage=field:GetValue(session);if not stage or not stage.CurNode then return end
|
||||
local id=stage.CurNode.StageID
|
||||
local row=CS.RPG.GameCore.StageExcelTable.GetData(id)
|
||||
local text=tostring(CS.Newtonsoft.Json.JsonConvert.SerializeObject(row))
|
||||
if #text>32768 then error('Stage row exceeds capture bound')end
|
||||
log('DIFFICULTY base='..stage:GetBaseDiffAddLv()..' all='..stage:GetAllDiffAddLv()..' current='..stage:GetCurrentMonsterDiffAddLv());log('ROW '..id..' '..text);_G.__gacCwActiveStageRow2=true;return
|
||||
end
|
||||
end
|
||||
end)
|
||||
if not ok then log('ERROR '..tostring(err));_G.__gacCwActiveStageRow2=true end
|
||||
end
|
||||
@@ -0,0 +1,23 @@
|
||||
-- Read the active stage's flat Excel row, not its scene/level graph.
|
||||
do
|
||||
if _G.__gacCwActiveStageRow1 then return end
|
||||
local log=function(v)CS.UnityEngine.Debug.Log('[GAC_CW_ACTIVE_STAGE_ROW] '..tostring(v))end
|
||||
local ok,err=pcall(function()
|
||||
local flags=CS.System.Enum.ToObject(typeof(CS.System.Reflection.BindingFlags),60)
|
||||
local session=CS.RPG.Client.GlobalVars.s_ModuleManager.GridFightModule.CurGameSession
|
||||
if not session then return end
|
||||
local fields=session:GetType():GetFields(flags)
|
||||
for i=0,math.min(fields.Length-1,63)do
|
||||
local field=fields[i]
|
||||
if field.FieldType.FullName=='RPG.Client.GridFightStage'then
|
||||
local stage=field:GetValue(session);if not stage or not stage.CurNode then return end
|
||||
local id=stage.CurNode.StageID
|
||||
local row=CS.RPG.GameCore.StageExcelTable.GetData(id)
|
||||
local text=tostring(CS.Newtonsoft.Json.JsonConvert.SerializeObject(row))
|
||||
if #text>32768 then error('Stage row exceeds capture bound')end
|
||||
log('ROW '..id..' '..text);_G.__gacCwActiveStageRow1=true;return
|
||||
end
|
||||
end
|
||||
end)
|
||||
if not ok then log('ERROR '..tostring(err));_G.__gacCwActiveStageRow1=true end
|
||||
end
|
||||
@@ -0,0 +1,25 @@
|
||||
-- Read existing augment wrappers; one row per heartbeat, no gameplay mutations.
|
||||
do
|
||||
_G.__gacCwAugmentsExport1=_G.__gacCwAugmentsExport1 or {index=0}
|
||||
local s=_G.__gacCwAugmentsExport1;if s.done then return end
|
||||
local log=function(v)CS.UnityEngine.Debug.Log('[GAC_CW_AUGMENTS] '..tostring(v))end
|
||||
local ok,err=pcall(function()
|
||||
local flags=CS.System.Enum.ToObject(typeof(CS.System.Reflection.BindingFlags),60)
|
||||
if not s.rows then s.rows=CS.RPG.Client.GlobalVars.s_ModuleManager.GridFightModule:GetHandBookAllAugmentItemData();if s.rows.Count>1024 then error('augment capture bound exceeded')end;log('BEGIN count='..s.rows.Count)end
|
||||
for batch=1,4 do
|
||||
if s.index>=s.rows.Count then s.done=true;log('END');return end
|
||||
local wrapper=s.rows[s.index];local t=wrapper:GetType();local row=nil
|
||||
for depth=1,4 do
|
||||
if not t then break end
|
||||
local fs=t:GetFields(flags)
|
||||
for j=0,math.min(fs.Length-1,47)do if fs[j].FieldType.FullName=='RPG.GameCore.GridFightAugmentConfigRow' then row=fs[j]:GetValue(wrapper);break end end
|
||||
if row then break end;t=t.BaseType
|
||||
end
|
||||
if not row then error('augment wrapper row unavailable')end
|
||||
local text=CS.Newtonsoft.Json.JsonConvert.SerializeObject(row);if #text>32768 then error('augment row exceeds capture bound')end
|
||||
log('ROW '..text);s.index=s.index+1
|
||||
end
|
||||
end)
|
||||
if not ok then log('ERROR '..tostring(err));s.done=true end
|
||||
end
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
-- Read the initialized CW entry state once, without requesting or changing it.
|
||||
do
|
||||
if not _G.__gacCwBootstrapStatus1 then
|
||||
_G.__gacCwBootstrapStatus1=true
|
||||
local function log(v)CS.UnityEngine.Debug.Log('[GAC_CW_BOOTSTRAP] '..tostring(v))end
|
||||
local ok,err=pcall(function()
|
||||
local module=CS.RPG.Client.GlobalVars.s_ModuleManager.GridFightModule
|
||||
log('SEASON '..module.SeasonID..' SUBSEASON '..module.SubSeasonID)
|
||||
log('DIVISION '..module.DivisionInfo.CurDivisionID)
|
||||
log('CUR_GAME '..tostring(module.CurGameSession))
|
||||
log('EXP_LINE '..tostring(module.ExpLineRewardData))
|
||||
end)
|
||||
if not ok then log('ERROR '..tostring(err))end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,23 @@
|
||||
-- Existing handbook wrapper metadata only, one inheritance level per heartbeat.
|
||||
do
|
||||
local s=_G.__gacCwCampSchema1 or {};_G.__gacCwCampSchema1=s
|
||||
if s.done then return end
|
||||
local log=function(v)CS.UnityEngine.Debug.Log('[GAC_CW_CAMP_SCHEMA] '..tostring(v))end
|
||||
local ok,err=pcall(function()
|
||||
local flags=CS.System.Enum.ToObject(typeof(CS.System.Reflection.BindingFlags),60)
|
||||
local manager=CS.RPG.Client.GlobalVars.s_GamePhaseManager
|
||||
local phase=manager and typeof(CS.RPG.Client.GamePhaseManager):GetField('_CurrentPhase',flags):GetValue(manager)
|
||||
if not phase or typeof(CS.RPG.Client.BattleGamePhase):IsInstanceOfType(phase)then return end
|
||||
if not s.initialized then
|
||||
local rows=CS.RPG.Client.GlobalVars.s_ModuleManager.GridFightModule:GetAllMonsterCampData()
|
||||
if not rows or rows.Count==0 then return end
|
||||
log('COUNT '..rows.Count);s.type=rows[0]:GetType();s.depth=0;s.initialized=true
|
||||
end
|
||||
local t=s.type;if not t or s.depth>=4 then s.done=true;log('END');return end
|
||||
log('TYPE '..t.FullName)
|
||||
local fs=t:GetFields(flags);for i=0,math.min(fs.Length-1,47)do log('FIELD '..tostring(fs[i]))end
|
||||
local ps=t:GetProperties(flags);for i=0,math.min(ps.Length-1,47)do log('PROPERTY '..tostring(ps[i]))end
|
||||
s.type=t.BaseType;s.depth=s.depth+1
|
||||
end)
|
||||
if not ok then log('ERROR '..tostring(err));s.done=true end
|
||||
end
|
||||
@@ -0,0 +1,32 @@
|
||||
-- Read-only CW discovery. Copy into scripts/ only for one capture, then remove.
|
||||
-- Restrict reflection to ModuleManager and the matching GridFight module.
|
||||
do
|
||||
if not _G.__gacCwDiscovery1 then
|
||||
_G.__gacCwDiscovery1=true
|
||||
local function log(v) CS.UnityEngine.Debug.Log('[GAC_CW_DISCOVERY] '..tostring(v)) end
|
||||
local ok,err=pcall(function()
|
||||
local flags=CS.System.Enum.ToObject(typeof(CS.System.Reflection.BindingFlags),60)
|
||||
local manager=CS.RPG.Client.GlobalVars.s_ModuleManager
|
||||
local fields=manager:GetType():GetFields(flags)
|
||||
for i=0,fields.Length-1 do
|
||||
local f=fields[i]
|
||||
if tostring(f.Name):find('GridFight') or tostring(f.FieldType):find('GridFight') then
|
||||
log('MODULE '..tostring(f))
|
||||
local module=f:GetValue(manager)
|
||||
if module then
|
||||
local t=module:GetType()
|
||||
local fs=t:GetFields(flags)
|
||||
for j=0,math.min(fs.Length-1,100) do log('FIELD '..tostring(fs[j])) end
|
||||
local ms=t:GetMethods(flags)
|
||||
for j=0,math.min(ms.Length-1,180) do
|
||||
local m=ms[j]
|
||||
if m.DeclaringType==t then log('METHOD '..tostring(m)) end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
log('DONE')
|
||||
end)
|
||||
if not ok then log('ERROR '..tostring(err)) end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,18 @@
|
||||
-- One named CW component per heartbeat, metadata only.
|
||||
do
|
||||
local names={'GridFightDivisionLevelConfig','GridFightDivisionStageConfig','GridFightRoleShop','GridFightStage','GridFightPlayer'}
|
||||
_G.__gacCwComponents=_G.__gacCwComponents or 1
|
||||
local index=_G.__gacCwComponents
|
||||
if index<=#names then
|
||||
_G.__gacCwComponents=index+1
|
||||
local function log(v)CS.UnityEngine.Debug.Log('[GAC_CW_COMPONENT] '..tostring(v))end
|
||||
local ok,err=pcall(function()
|
||||
local flags=CS.System.Enum.ToObject(typeof(CS.System.Reflection.BindingFlags),60)
|
||||
local t=typeof(CS.RPG.Client[names[index]])
|
||||
log('TYPE '..tostring(t))
|
||||
local fs=t:GetFields(flags);for i=0,fs.Length-1 do log('FIELD '..tostring(fs[i]))end
|
||||
local ms=t:GetMethods(flags);for i=0,ms.Length-1 do if ms[i].DeclaringType==t then log('METHOD '..tostring(ms[i]))end end
|
||||
end)
|
||||
if not ok then log('ERROR '..tostring(err))end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,19 @@
|
||||
-- Named constructors and one known method token; no instances are created.
|
||||
do
|
||||
if not _G.__gacCwConfigConstructor1 then
|
||||
_G.__gacCwConfigConstructor1=true
|
||||
local function log(v)CS.UnityEngine.Debug.Log('[GAC_CW_CONFIG_CTOR] '..tostring(v))end
|
||||
local flags=CS.System.Enum.ToObject(typeof(CS.System.Reflection.BindingFlags),60)
|
||||
local names={'GridFightRoleConfig','GridFightStageRoute','GridFightStageNode','GridFightPlayer'}
|
||||
for _,name in ipairs(names)do
|
||||
local t=typeof(CS.RPG.Client[name])
|
||||
local constructors=t:GetConstructors(flags)
|
||||
for i=0,constructors.Length-1 do log('CTOR '..name..' '..tostring(constructors[i])..' TOKEN '..constructors[i].MetadataToken)end
|
||||
end
|
||||
local ok,value=pcall(function()
|
||||
local token=101276529 -- Previously captured GridFightModule.GetSeason token.
|
||||
return typeof(CS.RPG.Client.GridFightModule).Module:ResolveMethod(token)
|
||||
end)
|
||||
log('RESOLVE_KNOWN '..tostring(ok)..' '..tostring(value))
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,23 @@
|
||||
-- Read-only named CW table discovery, one type per heartbeat.
|
||||
do
|
||||
local names={'GridFightSeasonModuleConfigRow','GridFightDivisionConfigRow','GridFightDivisionLevelConfigRow','GridFightTutorialStageConfigRow','GridFightRoleConfigRow','GridFightShopLevelConfigRow','GridFightConstValueRow'}
|
||||
_G.__gacCwConfigIndex=_G.__gacCwConfigIndex or 1
|
||||
local index=_G.__gacCwConfigIndex
|
||||
if index<=#names then
|
||||
_G.__gacCwConfigIndex=index+1
|
||||
local function log(v)CS.UnityEngine.Debug.Log('[GAC_CW_CONFIG] '..tostring(v))end
|
||||
local ok,err=pcall(function()
|
||||
local flags=CS.System.Enum.ToObject(typeof(CS.System.Reflection.BindingFlags),60)
|
||||
local t=typeof(CS.RPG.GameCore[names[index]])
|
||||
log('TYPE '..tostring(t))
|
||||
local fields=t:GetFields(flags)
|
||||
for i=0,fields.Length-1 do log('FIELD '..tostring(fields[i]))end
|
||||
local methods=t:GetMethods(flags)
|
||||
for i=0,methods.Length-1 do
|
||||
local m=methods[i]
|
||||
if m.DeclaringType==t then log('METHOD '..tostring(m)) end
|
||||
end
|
||||
end)
|
||||
if not ok then log('ERROR '..names[index]..' '..tostring(err))end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,28 @@
|
||||
-- Follow only the known CW wrapper's registered configuration delegate.
|
||||
-- One delegate's metadata per heartbeat; no delegate or graph is invoked.
|
||||
do
|
||||
local names={'GridFightTutorialStageConfig','GridFightDivisionStageConfig'}
|
||||
_G.__gacCwConfigProvider1=_G.__gacCwConfigProvider1 or 1
|
||||
local n=_G.__gacCwConfigProvider1
|
||||
if n<=#names then
|
||||
_G.__gacCwConfigProvider1=n+1
|
||||
local log=function(v)CS.UnityEngine.Debug.Log('[GAC_CW_PROVIDER] '..tostring(v))end
|
||||
local ok,err=pcall(function()
|
||||
local flags=CS.System.Enum.ToObject(typeof(CS.System.Reflection.BindingFlags),60)
|
||||
local wrapper=typeof(CS.RPG.Client[names[n]])
|
||||
local callback=wrapper:GetField('GetConfigImpl',flags):GetValue(nil)
|
||||
local method=callback.Method
|
||||
log('DELEGATE '..names[n]..' '..tostring(method)..' TOKEN '..method.MetadataToken)
|
||||
local owner=method.DeclaringType
|
||||
log('OWNER '..owner.FullName..' ASSEMBLY '..owner.Assembly.FullName)
|
||||
local fs=owner:GetFields(flags)
|
||||
for i=0,math.min(fs.Length-1,47)do log('FIELD '..tostring(fs[i]))end
|
||||
local ms=owner:GetMethods(flags)
|
||||
for i=0,math.min(ms.Length-1,47)do
|
||||
if ms[i].DeclaringType==owner then log('METHOD '..tostring(ms[i]))end
|
||||
end
|
||||
end)
|
||||
if not ok then log('ERROR '..tostring(err))end
|
||||
if n==#names then log('END')end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,24 @@
|
||||
-- Exact table names inferred from captured *ConfigRow names and the existing
|
||||
-- GameCore *ExcelTable naming convention. At most one named type per heartbeat.
|
||||
do
|
||||
local names={'GridFightSeasonModuleConfigExcelTable','GridFightRoleConfigExcelTable','GridFightStageRouteConfigExcelTable','GridFightPlayerLevelConfigExcelTable'}
|
||||
_G.__gacCwConfigTables2=_G.__gacCwConfigTables2 or 1
|
||||
local index=_G.__gacCwConfigTables2
|
||||
if index<=#names then
|
||||
_G.__gacCwConfigTables2=index+1
|
||||
local function log(v)CS.UnityEngine.Debug.Log('[GAC_CW_CONFIG_TABLE] '..tostring(v))end
|
||||
local flags=CS.System.Enum.ToObject(typeof(CS.System.Reflection.BindingFlags),60)
|
||||
local assembly=typeof(CS.RPG.GameCore.GridFightRoleConfigRow).Assembly
|
||||
if index==1 then log('ROW_ASSEMBLY '..tostring(assembly));log('MODULE_ASSEMBLY '..tostring(typeof(CS.RPG.Client.GridFightModule).Assembly))end
|
||||
local t=assembly:GetType('RPG.GameCore.'..names[index])
|
||||
log('TYPE '..names[index]..' '..tostring(t))
|
||||
if t then
|
||||
local methods=t:GetMethods(flags)
|
||||
for i=0,math.min(methods.Length-1,31)do
|
||||
if methods[i].DeclaringType==t then log('METHOD '..tostring(methods[i]))end
|
||||
end
|
||||
local fields=t:GetFields(flags)
|
||||
for i=0,math.min(fields.Length-1,31)do log('FIELD '..tostring(fields[i]))end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,22 @@
|
||||
-- Read only named constant tables, bounded to 64 rows per heartbeat.
|
||||
do
|
||||
_G.__gacCwConstants=_G.__gacCwConstants or {tableIndex=1}
|
||||
local state=_G.__gacCwConstants
|
||||
local tables={'ConstValueCommonExcelTable','ConstValueClientExcelTable'}
|
||||
if state.tableIndex<=#tables then
|
||||
local function log(v)CS.UnityEngine.Debug.Log('[GAC_CW_CONSTANT] '..tostring(v))end
|
||||
local ok,err=pcall(function()
|
||||
if not state.iterator then state.iterator=CS.RPG.GameCore[tables[state.tableIndex]].dataDict:GetEnumerator()end
|
||||
for i=1,64 do
|
||||
if not state.iterator:MoveNext()then
|
||||
log('END '..tables[state.tableIndex]);state.iterator=nil;state.tableIndex=state.tableIndex+1;return
|
||||
end
|
||||
local row=state.iterator.Current.Value
|
||||
if tostring(row.ConstValueName):lower():find('gridfight') then
|
||||
log('ROW '..tables[state.tableIndex]..' '..CS.Newtonsoft.Json.JsonConvert.SerializeObject(row))
|
||||
end
|
||||
end
|
||||
end)
|
||||
if not ok then log('ERROR '..tostring(err));state.iterator=nil;state.tableIndex=state.tableIndex+1 end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,25 @@
|
||||
-- Named shared score-reward state used by the CW points timer.
|
||||
do
|
||||
if not _G.__gacCwCycleReward1 then
|
||||
_G.__gacCwCycleReward1=true
|
||||
local function log(v)CS.UnityEngine.Debug.Log('[GAC_CW_CYCLE_REWARD] '..tostring(v))end
|
||||
local ok,err=pcall(function()
|
||||
local flags=CS.System.Enum.ToObject(typeof(CS.System.Reflection.BindingFlags),60)
|
||||
for _,name in ipairs({'GridfightExpLineRewardData'})do
|
||||
local t=typeof(CS.RPG.Client[name])
|
||||
log('TYPE '..tostring(t))
|
||||
local fields=t:GetFields(flags)
|
||||
for i=0,fields.Length-1 do log('FIELD '..tostring(fields[i]))end
|
||||
local methods=t:GetMethods(flags)
|
||||
for i=0,math.min(methods.Length-1,63)do
|
||||
local m=methods[i]
|
||||
if m.DeclaringType==t then log('METHOD '..tostring(m)..' TOKEN '..m.MetadataToken)end
|
||||
end
|
||||
end
|
||||
local t=typeof(CS.GAAMBBFPCHB)
|
||||
local ps=t:GetProperties(flags)
|
||||
for i=0,ps.Length-1 do log('WIRE_PROPERTY '..tostring(ps[i]))end
|
||||
end)
|
||||
if not ok then log('ERROR '..tostring(err))end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,54 @@
|
||||
-- Capture existing division stage/level rows only; no constructors or loaders.
|
||||
-- At most two dictionary rows per heartbeat and no work during Battle.
|
||||
do
|
||||
_G.__gacCwDivisionRows1=_G.__gacCwDivisionRows1 or {table=1,index=0}
|
||||
local s=_G.__gacCwDivisionRows1
|
||||
if s.done then return end
|
||||
local flags=CS.System.Enum.ToObject(typeof(CS.System.Reflection.BindingFlags),60)
|
||||
local manager=CS.RPG.Client.GlobalVars.s_GamePhaseManager
|
||||
local phase=manager and typeof(CS.RPG.Client.GamePhaseManager):GetField('_CurrentPhase',flags):GetValue(manager)
|
||||
if not phase or typeof(CS.RPG.Client.BattleGamePhase):IsInstanceOfType(phase)then return end
|
||||
local names={'DivisionStageConfigs','DivisionLevelConfigs'}
|
||||
local log=function(v)CS.UnityEngine.Debug.Log('[GAC_CW_DIVISION_ROWS] '..tostring(v))end
|
||||
local ok,err=pcall(function()
|
||||
if not s.iterator then
|
||||
local module=CS.RPG.Client.GlobalVars.s_ModuleManager.GridFightModule
|
||||
local rows=module[names[s.table]]
|
||||
if rows.Count>1024 then error('Division row count exceeds bound')end
|
||||
s.iterator=rows:GetEnumerator();s.count=0;s.expected=rows.Count
|
||||
log('BEGIN '..names[s.table]..' count='..rows.Count)
|
||||
end
|
||||
for batch=1,2 do
|
||||
if not s.iterator:MoveNext()then
|
||||
if s.count~=s.expected then error('Division table changed during capture')end
|
||||
log('END '..names[s.table]..' count='..s.count)
|
||||
s.iterator=nil;s.table=s.table+1
|
||||
if s.table>#names then s.done=true;log('END')end
|
||||
return
|
||||
end
|
||||
local row=s.iterator.Current.Value
|
||||
local t=row:GetType()
|
||||
local fields=t:GetFields(flags)
|
||||
if s.count==0 then
|
||||
log('TYPE '..t.FullName)
|
||||
for i=0,math.min(fields.Length-1,47)do log('FIELD '..tostring(fields[i]))end
|
||||
end
|
||||
local captured=0
|
||||
for i=0,math.min(fields.Length-1,47)do
|
||||
local f=fields[i]
|
||||
if not f.IsStatic and f.FieldType.FullName:find('RPG.GameCore.',1,true)==1 then
|
||||
local value=f:GetValue(row)
|
||||
if value then
|
||||
local encoded=CS.Newtonsoft.Json.JsonConvert.SerializeObject(value)
|
||||
if #encoded>65536 then error('Raw division row exceeds output bound')end
|
||||
log('ROW '..names[s.table]..' '..f.FieldType.FullName..' '..encoded)
|
||||
captured=captured+1
|
||||
end
|
||||
end
|
||||
end
|
||||
if captured==0 then log('NO_ROW '..names[s.table]..' '..s.count)end
|
||||
s.count=s.count+1
|
||||
end
|
||||
end)
|
||||
if not ok then s.done=true;s.iterator=nil;log('ERROR '..tostring(err))end
|
||||
end
|
||||
@@ -0,0 +1,23 @@
|
||||
-- Export already loaded native CW division configs, eight rows per heartbeat.
|
||||
do
|
||||
_G.__gacCwDivisions=_G.__gacCwDivisions or {index=0}
|
||||
local state=_G.__gacCwDivisions
|
||||
if not state.done then
|
||||
local function log(v)CS.UnityEngine.Debug.Log('[GAC_CW_DIVISIONS] '..tostring(v))end
|
||||
local ok,err=pcall(function()
|
||||
local module=CS.RPG.Client.GlobalVars.s_ModuleManager.GridFightModule
|
||||
local flags=CS.System.Enum.ToObject(typeof(CS.System.Reflection.BindingFlags),60)
|
||||
local first=typeof(CS.RPG.Client.GridFightModule):GetField('FirstSeasonID',flags):GetValue(nil)
|
||||
local season=module:GetSeason(first,nil)
|
||||
local configs=season.SeasonDivision.SeasonDivisionConfigs
|
||||
if state.index==0 then log('BEGIN count='..configs.Count)end
|
||||
for i=state.index,math.min(state.index+7,configs.Count-1) do
|
||||
local row=configs[i]
|
||||
log('ROW {"ID":'..row.ID..',"SeasonID":'..row.SeasonID..',"DivisionLevel":'..row.DivisionLevel..',"Progress":'..row.Progress..',"IsPromotion":'..tostring(row.IsPromotion)..'}')
|
||||
end
|
||||
state.index=state.index+8
|
||||
if state.index>=configs.Count then state.done=true;log('END')end
|
||||
end)
|
||||
if not ok then log('ERROR '..tostring(err));state.done=true end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,36 @@
|
||||
-- Substitute __ENTRANCE_ROW__ from the matching exported MapEntrance row.
|
||||
-- Read RuntimeFloor/RuntimeGroup data, never load or execute a level graph.
|
||||
do
|
||||
local input=__ENTRANCE_ROW__
|
||||
local function log(v)CS.UnityEngine.Debug.Log('[GAC_CW_ENTRANCE_RES] '..tostring(v))end
|
||||
if not _G.__gacCwEntranceRes1 then
|
||||
_G.__gacCwEntranceRes1=true
|
||||
local ok,err=pcall(function()
|
||||
local nativeID=CS.RPG.GameCore.ConstValueCommonExcelTable.GetData('GridFight_EntranceID').Value.IntValue
|
||||
if nativeID~=input.ID then error('Entrance row differs from native CW constant')end
|
||||
local floor=CS.RPG.GameCore.GameCoreConfigLoader.LoadRtLevelFloorInfo(CS.RPG.Client.MapDef.GetRtFloorInfoPath(input.PlaneID,input.FloorID))
|
||||
log('BEGIN entry='..input.ID..' groups='..floor.GroupInstanceList.Length..' start_group='..input.StartGroupID..' anchor='..input.StartAnchorID)
|
||||
_G.__gacCwEntranceResRows={floor=floor,index=0}
|
||||
end)
|
||||
if not ok then log('ERROR '..tostring(err))end
|
||||
end
|
||||
local state=_G.__gacCwEntranceResRows
|
||||
if state and not state.done then
|
||||
local ok,err=pcall(function()
|
||||
local floor=state.floor
|
||||
for i=state.index,math.min(state.index+15,floor.GroupInstanceList.Length-1)do
|
||||
local g=floor.GroupInstanceList[i]
|
||||
local c=floor.GroupInstanceCommonMap[g.ID]
|
||||
log('GROUP '..g.ID..' path='..tostring(g.GroupPath)..' deleted='..tostring(g.IsDelete)..' common_deleted='..tostring(c and c.IsDelete)..' side='..tostring(c and c.LoadSide))
|
||||
if g.ID==input.StartGroupID then
|
||||
log('START_TRANSFORM '..CS.Newtonsoft.Json.JsonConvert.SerializeObject(g))
|
||||
local r=CS.RPG.GameCore.GameCoreConfigLoader.LoadRtLevelGroupInfo(g.GroupPath)
|
||||
log('START_GROUP '..CS.Newtonsoft.Json.JsonConvert.SerializeObject(r))
|
||||
end
|
||||
end
|
||||
state.index=state.index+16
|
||||
if state.index>=floor.GroupInstanceList.Length then log('END');state.done=true end
|
||||
end)
|
||||
if not ok then log('ERROR '..tostring(err));state.done=true end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,24 @@
|
||||
-- Exact CW entry methods only, metadata in bounded batches; no game action.
|
||||
do
|
||||
local flags=CS.System.Enum.ToObject(typeof(CS.System.Reflection.BindingFlags),60)
|
||||
local manager=CS.RPG.Client.GlobalVars.s_GamePhaseManager
|
||||
local phase=manager and typeof(CS.RPG.Client.GamePhaseManager):GetField('_CurrentPhase',flags):GetValue(manager)
|
||||
if not phase or typeof(CS.RPG.Client.BattleGamePhase):IsInstanceOfType(phase)then return end
|
||||
_G.__gacCwEntryHandles20261020=_G.__gacCwEntryHandles20261020 or {index=0}
|
||||
local s=_G.__gacCwEntryHandles20261020
|
||||
if s.done then return end
|
||||
local log=function(v)CS.UnityEngine.Debug.Log('[GAC_CW_ENTRY_HANDLE] '..tostring(v))end
|
||||
local ok,err=pcall(function()
|
||||
if not s.methods then s.methods=typeof(CS.RPG.Client.GridFightModule):GetMethods(flags)end
|
||||
for i=s.index,math.min(s.index+23,s.methods.Length-1)do
|
||||
local m=s.methods[i]
|
||||
local n=m.Name:lower()
|
||||
if n:find('startgame') or n:find('resumegame') or n:find('starttutorial') or n:find('preload') then
|
||||
log('METHOD '..tostring(m)..' HANDLE '..tostring(m.MethodHandle.Value))
|
||||
end
|
||||
end
|
||||
s.index=s.index+24
|
||||
if s.index>=s.methods.Length then s.done=true;log('END')end
|
||||
end)
|
||||
if not ok then s.done=true;log('ERROR '..tostring(err))end
|
||||
end
|
||||
@@ -0,0 +1,38 @@
|
||||
-- Export bytecode of named, already-loaded Lua UI methods. No function calls.
|
||||
do
|
||||
local targets={
|
||||
{'Ui.GridFight.Entrance.S2.GridFightS2EntrancePage','_on_load'},
|
||||
{'Ui.GridFight.Entrance.S2.GridFightS2EntrancePage','_setup_view'},
|
||||
{'Ui.GridFight.Entrance.S2.GridFightS2EntrancePage','_try_show_tutorial'},
|
||||
{'Ui.GridFight.Entrance.S2.GridFightS2EntrancePage','_start_action'},
|
||||
}
|
||||
_G.__gacCwEntryLuaExport1=_G.__gacCwEntryLuaExport1 or {index=1}
|
||||
local state=_G.__gacCwEntryLuaExport1
|
||||
if state.index<=#targets then
|
||||
local function log(v)CS.UnityEngine.Debug.Log('[GAC_CW_ENTRY_LUA] '..tostring(v))end
|
||||
local target=targets[state.index]
|
||||
local ok,err=pcall(function()
|
||||
if not state.bytes then
|
||||
local class=package.loaded[target[1]]
|
||||
local fn=class and class[target[2]]
|
||||
if type(fn)~='function' then error('Named UI method is not loaded')end
|
||||
local data=string.dump(fn)
|
||||
if #data>131072 then error('Bytecode exceeds export bound')end
|
||||
state.bytes=data;state.offset=1
|
||||
log('BEGIN '..target[1]..'.'..target[2]..' bytes='..#data)
|
||||
for i=1,16 do
|
||||
local name,value=debug.getupvalue(fn,i)
|
||||
if not name then break end
|
||||
log('UPVALUE '..name..' '..type(value))
|
||||
end
|
||||
end
|
||||
local piece=state.bytes:sub(state.offset,state.offset+1023)
|
||||
local hex={}
|
||||
for i=1,#piece do hex[i]=string.format('%02x',piece:byte(i))end
|
||||
log('HEX '..table.concat(hex))
|
||||
state.offset=state.offset+#piece
|
||||
if state.offset>#state.bytes then log('END');state.bytes=nil;state.index=state.index+1 end
|
||||
end)
|
||||
if not ok then log('ERROR '..tostring(err));state.bytes=nil;state.index=state.index+1 end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,13 @@
|
||||
-- Named read-only UI predicates. No Start/Open/Sync/Set method is invoked.
|
||||
do
|
||||
if not _G.__gacCwEntryPredicates1 then
|
||||
_G.__gacCwEntryPredicates1=true
|
||||
local function log(v)CS.UnityEngine.Debug.Log('[GAC_CW_ENTRY_PREDICATE] '..tostring(v))end
|
||||
local module=CS.RPG.Client.GlobalVars.s_ModuleManager.GridFightModule
|
||||
for _,name in ipairs({'ShouldStartCurrentSeasonTutorial','IsFinishedTutorialThisSeason','ShouldLatestSeasonUIShowTutorialVersion','ShouldShowDivisionInfo'})do
|
||||
local ok,value=pcall(function()return module[name](module)end)
|
||||
log(name..' '..tostring(ok)..' '..tostring(value))
|
||||
end
|
||||
log('LAST_TUTORIAL_SEASON '..module.PlayerProfile.LastTutorialFinishedSeasonID)
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,30 @@
|
||||
-- Bounded read-only entry-state inspection. No UI calls or gameplay writes.
|
||||
do
|
||||
if not _G.__gacCwEntryState2 then
|
||||
_G.__gacCwEntryState2=true
|
||||
local function log(v)CS.UnityEngine.Debug.Log('[GAC_CW_ENTRY_STATE] '..tostring(v))end
|
||||
local ok,err=pcall(function()
|
||||
local flags=CS.System.Enum.ToObject(typeof(CS.System.Reflection.BindingFlags),60)
|
||||
local module=CS.RPG.Client.GlobalVars.s_ModuleManager.GridFightModule
|
||||
local t=module:GetType()
|
||||
for _,name in ipairs({'SeasonID','SubSeasonID','CurGame','PlayerProfile','TutorialStageConfigs'})do
|
||||
local good,value=pcall(function()return module[name]end)
|
||||
log('VALUE '..name..' '..tostring(good)..' '..tostring(value))
|
||||
end
|
||||
local names={'CheckUnlock','ShouldStartCurrentSeasonTutorial','_ShouldStartFirstSeasonTutorial','IsFinishedTutorialThisSeason','_StartTutorialLevel','_GetTutorialProgressID','StartGame','_GetTutorialStageConfig'}
|
||||
for _,name in ipairs(names)do
|
||||
local m=t:GetMethod(name,flags)
|
||||
log('METHOD '..tostring(m)..' TOKEN '..tostring(m and m.MetadataToken))
|
||||
end
|
||||
local route=typeof(CS.RPG.Client.GridFightStageRoute)
|
||||
local constructors=route:GetConstructors(flags)
|
||||
for i=0,constructors.Length-1 do log('ROUTE_CTOR '..tostring(constructors[i])..' TOKEN '..constructors[i].MetadataToken)end
|
||||
local methods=route:GetMethods(flags)
|
||||
for i=0,math.min(methods.Length-1,31)do
|
||||
local m=methods[i]
|
||||
if m.DeclaringType==route then log('ROUTE_METHOD '..tostring(m)..' TOKEN '..m.MetadataToken)end
|
||||
end
|
||||
end)
|
||||
if not ok then log('ERROR '..tostring(err))end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,28 @@
|
||||
-- Named CW entry/sync targets only; metadata, no invocation or patching.
|
||||
do
|
||||
if _G.__gacCwEntrySyncHandles20261020 then return end
|
||||
local flags=CS.System.Enum.ToObject(typeof(CS.System.Reflection.BindingFlags),60)
|
||||
local manager=CS.RPG.Client.GlobalVars.s_GamePhaseManager
|
||||
local phase=manager and typeof(CS.RPG.Client.GamePhaseManager):GetField('_CurrentPhase',flags):GetValue(manager)
|
||||
if not phase or typeof(CS.RPG.Client.BattleGamePhase):IsInstanceOfType(phase)then return end
|
||||
_G.__gacCwEntrySyncHandles20261020=true
|
||||
local log=function(v)CS.UnityEngine.Debug.Log('[GAC_CW_ENTRY_SYNC_HANDLE] '..tostring(v))end
|
||||
local ok,err=pcall(function()
|
||||
local a=typeof(CS.RPG.Client.GridFightModule).Assembly
|
||||
local targets={
|
||||
{'RPG.Client.GridFightModule','_OnGridFightGetDataScRsp'},
|
||||
{'RPG.Client.GridFightModule','_SyncCurGame'},
|
||||
{'RPG.Client.GridFightGameSession','Sync'},
|
||||
{'RPG.Client.GridFightGameSession','_SyncInternal'},
|
||||
{'RPG.Client.GridFightModule','_OnGridFightSyncUpdateResultScNotify'},
|
||||
{'RPG.Client.GridFightRoleShop','Sync'},
|
||||
{'RPG.Client.GridFightModule','_RecoverOldSession'}
|
||||
}
|
||||
for _,item in ipairs(targets)do
|
||||
local t=a:GetType(item[1]);local m=t and t:GetMethod(item[2],flags)
|
||||
if m then log(item[1]..' '..item[2]..' '..tostring(m.MethodHandle.Value)..' '..tostring(m))else log('MISSING '..item[1]..' '..item[2])end
|
||||
end
|
||||
log('END')
|
||||
end)
|
||||
if not ok then log('ERROR '..tostring(err))end
|
||||
end
|
||||
@@ -0,0 +1,23 @@
|
||||
-- Existing handbook wrapper metadata only, one inheritance level per heartbeat.
|
||||
do
|
||||
local s=_G.__gacCwEquipmentSchema2 or {};_G.__gacCwEquipmentSchema2=s
|
||||
if s.done then return end
|
||||
local log=function(v)CS.UnityEngine.Debug.Log('[GAC_CW_EQUIP_CONFIG_SCHEMA] '..tostring(v))end
|
||||
local ok,err=pcall(function()
|
||||
local flags=CS.System.Enum.ToObject(typeof(CS.System.Reflection.BindingFlags),60)
|
||||
local manager=CS.RPG.Client.GlobalVars.s_GamePhaseManager
|
||||
local phase=manager and typeof(CS.RPG.Client.GamePhaseManager):GetField('_CurrentPhase',flags):GetValue(manager)
|
||||
if not phase or typeof(CS.RPG.Client.BattleGamePhase):IsInstanceOfType(phase)then return end
|
||||
if not s.initialized then
|
||||
local rows=CS.RPG.Client.GlobalVars.s_ModuleManager.GridFightModule:GetHandBookAllEquipItemData()
|
||||
if not rows or rows.Count==0 then return end
|
||||
log('COUNT '..rows.Count);local first=nil;for i=0,math.min(rows.Count-1,255)do if rows[i].IsEquipment then first=rows[i].EquipConfig;break end end;if not first then error('no initialized equipment wrapper')end;s.type=first:GetType();s.depth=0;s.initialized=true
|
||||
end
|
||||
local t=s.type;if not t or s.depth>=4 then s.done=true;log('END');return end
|
||||
log('TYPE '..t.FullName)
|
||||
local fs=t:GetFields(flags);for i=0,math.min(fs.Length-1,47)do log('FIELD '..tostring(fs[i]))end
|
||||
local ps=t:GetProperties(flags);for i=0,math.min(ps.Length-1,47)do log('PROPERTY '..tostring(ps[i]))end
|
||||
s.type=t.BaseType;s.depth=s.depth+1
|
||||
end)
|
||||
if not ok then log('ERROR '..tostring(err));s.done=true end
|
||||
end
|
||||
@@ -0,0 +1,31 @@
|
||||
-- Four initialized handbook entries per heartbeat. Never runs in Battle.
|
||||
do
|
||||
local s=_G.__gacCwEquipmentExport1 or {index=0};_G.__gacCwEquipmentExport1=s
|
||||
if s.done then return end
|
||||
local log=function(v)CS.UnityEngine.Debug.Log('[GAC_CW_EQUIPMENT] '..tostring(v))end
|
||||
local ok,err=pcall(function()
|
||||
local flags=CS.System.Enum.ToObject(typeof(CS.System.Reflection.BindingFlags),60)
|
||||
local manager=CS.RPG.Client.GlobalVars.s_GamePhaseManager
|
||||
local phase=manager and typeof(CS.RPG.Client.GamePhaseManager):GetField('_CurrentPhase',flags):GetValue(manager)
|
||||
if not phase or typeof(CS.RPG.Client.BattleGamePhase):IsInstanceOfType(phase)then return end
|
||||
if not s.rows then
|
||||
s.rows=CS.RPG.Client.GlobalVars.s_ModuleManager.GridFightModule:GetHandBookAllEquipItemData()
|
||||
if not s.rows or s.rows.Count>1024 then error('handbook bound exceeded')end
|
||||
log('BEGIN '..s.rows.Count)
|
||||
end
|
||||
local json=function(v)return tostring(CS.Newtonsoft.Json.JsonConvert.SerializeObject(v))end
|
||||
for batch=1,4 do
|
||||
if s.index>=s.rows.Count then s.done=true;log('END');return end
|
||||
local wrapper=s.rows[s.index];s.index=s.index+1
|
||||
if wrapper.IsEquipment then
|
||||
local c=wrapper.EquipConfig
|
||||
local text='{"ItemID":'..c.ItemID..',"BaseItemID":'..c.BaseItemID..',"NeedEquipSlot":'..tostring(c.NeedEquipSlot)..',"EquipType":'..CS.System.Convert.ToUInt32(c.EquipType)..',"EquipCategory":'..CS.System.Convert.ToUInt32(c.EquipCategory)..',"EquipFunc":'..CS.System.Convert.ToUInt32(c.EquipFunc)..',"DressRule":'..CS.System.Convert.ToUInt32(c.DressRule)..',"AbilityName":'..json(c.AbilityName)..',"GeneralPropertyList":'..json(c.GeneralPropertyList)..',"AbilityParamList":'..json(c.AbilityParamList)..',"EquipFuncParamList":'..json(c.EquipFuncParamList)..',"DressRuleParamList":'..json(c.DressRuleParamList)..'}'
|
||||
if #text>32768 then error('equipment row exceeds bound')end
|
||||
log('ROW '..text)
|
||||
else
|
||||
log('OTHER '..s.index..' '..wrapper.ItemConfig:GetType().FullName)
|
||||
end
|
||||
end
|
||||
end)
|
||||
if not ok then log('ERROR '..tostring(err));s.done=true end
|
||||
end
|
||||
@@ -0,0 +1,20 @@
|
||||
-- Existing handbook wrapper metadata only, one inheritance level per heartbeat.
|
||||
do
|
||||
local s=_G.__gacCwEquipmentSchema1 or {};_G.__gacCwEquipmentSchema1=s
|
||||
if s.done then return end
|
||||
local log=function(v)CS.UnityEngine.Debug.Log('[GAC_CW_EQUIP_SCHEMA] '..tostring(v))end
|
||||
local ok,err=pcall(function()
|
||||
local flags=CS.System.Enum.ToObject(typeof(CS.System.Reflection.BindingFlags),60)
|
||||
if not s.initialized then
|
||||
local rows=CS.RPG.Client.GlobalVars.s_ModuleManager.GridFightModule:GetHandBookAllEquipItemData()
|
||||
if not rows or rows.Count==0 then return end
|
||||
log('COUNT '..rows.Count);s.type=rows[0]:GetType();s.depth=0;s.initialized=true
|
||||
end
|
||||
local t=s.type;if not t or s.depth>=4 then s.done=true;log('END');return end
|
||||
log('TYPE '..t.FullName)
|
||||
local fs=t:GetFields(flags);for i=0,math.min(fs.Length-1,47)do log('FIELD '..tostring(fs[i]))end
|
||||
local ps=t:GetProperties(flags);for i=0,math.min(ps.Length-1,47)do log('PROPERTY '..tostring(ps[i]))end
|
||||
s.type=t.BaseType;s.depth=s.depth+1
|
||||
end)
|
||||
if not ok then log('ERROR '..tostring(err));s.done=true end
|
||||
end
|
||||
@@ -0,0 +1,33 @@
|
||||
-- Read named Excel tables from the assembly that owns the captured Row type.
|
||||
-- At most sixteen plain configuration rows per heartbeat; no graph loads.
|
||||
do
|
||||
local names={'GridFightStageRouteConfigExcelTable'}
|
||||
_G.__gacCwExcelExport1=_G.__gacCwExcelExport1 or {table=1,count=0}
|
||||
local state=_G.__gacCwExcelExport1
|
||||
if state.table<=#names then
|
||||
local function log(v)CS.UnityEngine.Debug.Log('[GAC_CW_EXCEL] '..tostring(v))end
|
||||
local ok,err=pcall(function()
|
||||
if not state.iterator then
|
||||
local assembly=typeof(CS.RPG.GameCore.GridFightRoleConfigRow).Assembly
|
||||
local t=assembly:GetType('RPG.GameCore.'..names[state.table])
|
||||
if not t then error('Named table missing from Row assembly')end
|
||||
local flags=CS.System.Enum.ToObject(typeof(CS.System.Reflection.BindingFlags),60)
|
||||
local getter=t:GetProperty('dataDict',flags):GetGetMethod(true)
|
||||
local rows=getter:Invoke(nil,CS.System.Enum.ToObject(typeof(CS.System.Reflection.BindingFlags),0),nil,CS.System.Array.CreateInstance(typeof(CS.System.Object),0),nil)
|
||||
if rows.Count>20000 then error('Table exceeds capture bound')end
|
||||
state.iterator=rows:GetEnumerator();state.expected=rows.Count;state.count=0
|
||||
log('BEGIN '..names[state.table]..' count='..rows.Count)
|
||||
end
|
||||
for i=1,16 do
|
||||
if not state.iterator:MoveNext()then
|
||||
if state.count~=state.expected then error('Table changed during capture')end
|
||||
log('END '..names[state.table]..' count='..state.count)
|
||||
state.iterator=nil;state.table=state.table+1;return
|
||||
end
|
||||
log('ROW '..names[state.table]..' '..CS.Newtonsoft.Json.JsonConvert.SerializeObject(state.iterator.Current.Value))
|
||||
state.count=state.count+1
|
||||
end
|
||||
end)
|
||||
if not ok then log('ERROR '..names[state.table]..' '..tostring(err));state.iterator=nil;state.table=state.table+1 end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,29 @@
|
||||
-- Read only the exact CW FirstPlay template through its typed config reader.
|
||||
-- No level graph loader, task execution, session mutation or HTTP call.
|
||||
do
|
||||
local flags=CS.System.Enum.ToObject(typeof(CS.System.Reflection.BindingFlags),60)
|
||||
local manager=CS.RPG.Client.GlobalVars.s_GamePhaseManager
|
||||
local phase=manager and typeof(CS.RPG.Client.GamePhaseManager):GetField('_CurrentPhase',flags):GetValue(manager)
|
||||
if not phase or typeof(CS.RPG.Client.BattleGamePhase):IsInstanceOfType(phase)then return end
|
||||
_G.__gacCwFirstPlayTemplate20261020=_G.__gacCwFirstPlayTemplate20261020 or {index=1}
|
||||
local s=_G.__gacCwFirstPlayTemplate20261020
|
||||
if s.done then return end
|
||||
local log=function(v)CS.UnityEngine.Debug.Log('[GAC_CW_FIRSTPLAY_TEMPLATE] '..tostring(v))end
|
||||
local ok,err=pcall(function()
|
||||
if not s.text then
|
||||
local rule=CS.RPG.GameCore.ConstValueCommonExcelTable.GetData('GridFight_FirstPlay_JsonPath')
|
||||
if not rule or not rule.Value.IsString then error('FirstPlay path is absent')end
|
||||
local value=CS.RPG.GameCore.GameCoreConfigLoader.LoadGridFightStageTemplateConfig(rule.Value.StringValue)
|
||||
if not value then error('Typed FirstPlay template reader returned nil')end
|
||||
s.text=tostring(CS.Newtonsoft.Json.JsonConvert.SerializeObject(value))
|
||||
if #s.text>1048576 then error('FirstPlay template exceeds capture bound')end
|
||||
log('BEGIN bytes='..#s.text)
|
||||
end
|
||||
if s.index>#s.text then s.done=true;s.text=nil;log('END');return end
|
||||
local finish=math.min(s.index+4095,#s.text)
|
||||
while finish<#s.text and string.byte(s.text,finish+1)>=128 and string.byte(s.text,finish+1)<192 do finish=finish-1 end
|
||||
log('CHUNK '..s.index..' '..CS.Newtonsoft.Json.JsonConvert.SerializeObject(s.text:sub(s.index,finish)))
|
||||
s.index=finish+1
|
||||
end)
|
||||
if not ok then s.done=true;s.text=nil;log('ERROR '..tostring(err))end
|
||||
end
|
||||
@@ -0,0 +1,51 @@
|
||||
-- Encode isolated protobuf objects to map obfuscated backing fields to tags.
|
||||
-- No objects are synced into a game module or sent as network responses.
|
||||
do
|
||||
local names={'NIHNGPKHEPC','BEEFLEJAOCN','BCCIJHPLJOJ','OHMDHKGAEMM'}
|
||||
_G.__gacCwGameplayScalar1=_G.__gacCwGameplayScalar1 or {index=1,field=0}
|
||||
local state=_G.__gacCwGameplayScalar1
|
||||
if state.index<=#names then
|
||||
local function log(v)CS.UnityEngine.Debug.Log('[GAC_CW_SCALAR_WIRE] '..tostring(v))end
|
||||
local ok,err=pcall(function()
|
||||
local flags=CS.System.Enum.ToObject(typeof(CS.System.Reflection.BindingFlags),60)
|
||||
local t=typeof(CS[names[state.index]])
|
||||
local fields=t:GetFields(flags)
|
||||
local count=0
|
||||
for i=state.field,fields.Length-1 do
|
||||
state.field=i+1
|
||||
local f=fields[i]
|
||||
if not f.IsStatic and f.FieldType==typeof(CS.System.UInt32) then
|
||||
local obj=CS.System.Activator.CreateInstance(t)
|
||||
local typed=CS.System.Array.CreateInstance(typeof(CS.System.UInt32),1);typed[0]=1
|
||||
local boxed=CS.System.Array.CreateInstance(typeof(CS.System.Object),2);boxed[0]=obj
|
||||
CS.System.Array.Copy(typed,0,boxed,1,1)
|
||||
local setters=f:GetType():GetMethods(flags)
|
||||
local setter=nil
|
||||
for j=0,setters.Length-1 do
|
||||
if setters[j].Name=='SetValue' and setters[j]:GetParameters().Length==2 then setter=setters[j];break end
|
||||
end
|
||||
if not setter then error('FieldInfo.SetValue overload missing')end
|
||||
local invoke=CS.System.Enum.ToObject(typeof(CS.System.Reflection.BindingFlags),0)
|
||||
setter:Invoke(f,invoke,nil,boxed,nil)
|
||||
local bytes=CS.Google.Protobuf.MessageExtensions.ToByteArray(obj)
|
||||
log('FIELD '..names[state.index]..' '..f.Name..' '..CS.System.BitConverter.ToString(bytes))
|
||||
local properties=t:GetProperties(flags)
|
||||
local empty=CS.System.Array.CreateInstance(typeof(CS.System.Object),0)
|
||||
for j=0,properties.Length-1 do
|
||||
local p=properties[j]
|
||||
if p.PropertyType==typeof(CS.System.UInt32) then
|
||||
local getter=p:GetGetMethod(true)
|
||||
if getter and not getter.IsStatic and getter:Invoke(obj,invoke,nil,empty,nil)==1 then
|
||||
log('GETTER '..names[state.index]..' '..f.Name..' '..p.Name..' '..getter.MetadataToken); CS.UnityEngine.Debug.Log('[GAC_CW_METHOD_TOKEN] METHOD '..names[state.index]..' '..getter.Name..' '..getter.MetadataToken)
|
||||
end
|
||||
end
|
||||
end
|
||||
count=count+1;if count>=2 then return end
|
||||
end
|
||||
end
|
||||
log('END '..names[state.index]);state.index=state.index+1;state.field=0
|
||||
end)
|
||||
if not ok then log('ERROR '..tostring(err));state.index=state.index+1;state.field=0 end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
-- Inspect the named CW GameRef configuration API only; never send HTTP calls.
|
||||
do
|
||||
if not _G.__gacCwGameRefSchema1 then
|
||||
_G.__gacCwGameRefSchema1=true
|
||||
local log=function(v)CS.UnityEngine.Debug.Log('[GAC_CW_GAMEREF_SCHEMA] '..tostring(v))end
|
||||
local t=typeof(CS.RPG.Client.GridFightGameRef)
|
||||
local flags=CS.System.Enum.ToObject(typeof(CS.System.Reflection.BindingFlags),60)
|
||||
local fs=t:GetFields(flags)
|
||||
for i=0,math.min(fs.Length-1,47)do log('FIELD '..tostring(fs[i]))end
|
||||
local ms=t:GetMethods(flags)
|
||||
for i=0,math.min(ms.Length-1,63)do
|
||||
if ms[i].DeclaringType==t then log('METHOD '..tostring(ms[i]))end
|
||||
end
|
||||
log('END')
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,26 @@
|
||||
-- Inspect the active Guide page's Lua state; no UI actions or module writes.
|
||||
do
|
||||
if not _G.__gacCwGuide1 then
|
||||
_G.__gacCwGuide1=true
|
||||
local function log(v)CS.UnityEngine.Debug.Log('[GAC_CW_GUIDE] '..tostring(v))end
|
||||
local ok,err=pcall(function()
|
||||
local ui=CS.RPG.Client.GlobalVars.s_UIManager
|
||||
local names=ui:GetAllPageNames()
|
||||
for i=0,names.Count-1 do
|
||||
local name=tostring(names[i])
|
||||
if name:find('Handbook') or name:find('Guide') or name:find('DailyMission') then
|
||||
log('PAGE '..name)
|
||||
local page=ui:GetPageByName(name)
|
||||
if page then
|
||||
local lua=page.LuaTable
|
||||
if type(lua)=='table' then
|
||||
local n=0
|
||||
for k,v in pairs(lua)do log('FIELD '..tostring(k)..' '..type(v)..' '..tostring(v));n=n+1;if n>=60 then break end end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
||||
if not ok then log('ERROR '..tostring(err))end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,11 @@
|
||||
-- Read only the initialized handbook getter, six calls maximum, paused in Battle.
|
||||
do
|
||||
_G.__gacCwHandbookPulse5=_G.__gacCwHandbookPulse5 or 0
|
||||
if _G.__gacCwHandbookPulse5>=6 then return end
|
||||
local flags=CS.System.Enum.ToObject(typeof(CS.System.Reflection.BindingFlags),60)
|
||||
local manager=CS.RPG.Client.GlobalVars.s_GamePhaseManager
|
||||
local phase=manager and typeof(CS.RPG.Client.GamePhaseManager):GetField('_CurrentPhase',flags):GetValue(manager)
|
||||
if not phase or typeof(CS.RPG.Client.BattleGamePhase):IsInstanceOfType(phase)then return end
|
||||
_G.__gacCwHandbookPulse5=_G.__gacCwHandbookPulse5+1
|
||||
CS.RPG.Client.GlobalVars.s_ModuleManager.GridFightModule:GetHandBookAllRoleConfig()
|
||||
end
|
||||
@@ -0,0 +1,59 @@
|
||||
-- Capture initialized default/OtherRoles wrappers only, after the user's round.
|
||||
-- Keep outside scripts until capture is requested. Never create roles or alter stars.
|
||||
-- A BattleGamePhase pauses all table work; queue construction handles four
|
||||
-- handbook family per heartbeat, then encoding handles at most two roles.
|
||||
do
|
||||
_G.__gacCwVariants2=_G.__gacCwVariants2 or {family=0,index=1,queue={}}
|
||||
local s=_G.__gacCwVariants2
|
||||
if not s.done then
|
||||
local flags=CS.System.Enum.ToObject(typeof(CS.System.Reflection.BindingFlags),60)
|
||||
local phaseField=typeof(CS.RPG.Client.GamePhaseManager):GetField('_CurrentPhase',flags)
|
||||
local manager=CS.RPG.Client.GlobalVars.s_GamePhaseManager
|
||||
local phase=manager and phaseField:GetValue(manager)
|
||||
local log=function(v)CS.UnityEngine.Debug.Log('[GAC_CW_ROLE_VARIANTS] '..tostring(v))end
|
||||
if not phase or typeof(CS.RPG.Client.BattleGamePhase):IsInstanceOfType(phase)then
|
||||
if not s.paused then log('WAIT phase='..tostring(phase and phase:GetType().FullName));s.paused=true end
|
||||
return
|
||||
end
|
||||
if s.paused then log('RESUME');s.paused=false end
|
||||
local ok,err=pcall(function()
|
||||
if not s.families then
|
||||
s.families=CS.RPG.Client.GlobalVars.s_ModuleManager.GridFightModule:GetHandBookAllRoleConfig()
|
||||
if s.families.Count>1024 then error('Handbook family count exceeds capture bound')end
|
||||
log('QUEUE families='..s.families.Count)
|
||||
end
|
||||
if s.family<s.families.Count then
|
||||
for batch=1,4 do
|
||||
if s.family>=s.families.Count then break end
|
||||
local family=s.families[s.family]
|
||||
s.queue[#s.queue+1]={role=family.DefaultRole,parent=family.ID,origin='DefaultRole'}
|
||||
local others=family.OtherRoles
|
||||
if others then
|
||||
if others.Count>32 then error('Handbook variant count exceeds capture bound')end
|
||||
for i=0,others.Count-1 do s.queue[#s.queue+1]={role=others[i],parent=family.ID,origin='OtherRoles'}end
|
||||
end
|
||||
s.family=s.family+1
|
||||
end
|
||||
return
|
||||
end
|
||||
if not s.begun then s.begun=true;log('BEGIN count='..#s.queue)end
|
||||
for n=1,2 do
|
||||
local entry=s.queue[s.index]
|
||||
if not entry then s.done=true;log('END');s.queue=nil;return end
|
||||
local role=entry.role
|
||||
local config=role.RoleConfig
|
||||
local row=config:GetType():GetField('_Row',flags):GetValue(config)
|
||||
local starConfig=role.StarConfig
|
||||
local starRow=starConfig:GetType():GetField('_Row',flags):GetValue(starConfig)
|
||||
local servantRow=starConfig:GetType():GetField('_ServantStarRow',flags):GetValue(starConfig)
|
||||
local text='ROW {"ParentID":'..entry.parent..',"Origin":"'..entry.origin..'","Config":'..CS.Newtonsoft.Json.JsonConvert.SerializeObject(row)
|
||||
..',"Price":'..config.Price..',"MaxStar":'..config.MaxStar..',"Star":'..role.Star..',"SellPrice":'..role.SellPrice
|
||||
..',"StarConfig":'..CS.Newtonsoft.Json.JsonConvert.SerializeObject(starRow)..',"ServantStarConfig":'..CS.Newtonsoft.Json.JsonConvert.SerializeObject(servantRow)..'}'
|
||||
if #text>65536 then error('Role variant row exceeds output bound')end
|
||||
log(text)
|
||||
s.index=s.index+1
|
||||
end
|
||||
end)
|
||||
if not ok then log('ERROR '..tostring(err));s.done=true;s.queue=nil end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,38 @@
|
||||
-- Read initialized CW configuration caches, not gameplay actions.
|
||||
do
|
||||
if not _G.__gacCwInitializedConfigs1 then
|
||||
_G.__gacCwInitializedConfigs1=true
|
||||
local function log(v)CS.UnityEngine.Debug.Log('[GAC_CW_INITIALIZED] '..tostring(v))end
|
||||
local ok,err=pcall(function()
|
||||
local flags=CS.System.Enum.ToObject(typeof(CS.System.Reflection.BindingFlags),60)
|
||||
local module=CS.RPG.Client.GlobalVars.s_ModuleManager.GridFightModule
|
||||
for _,name in ipairs({'_RoleConfigByID','_RoleConfigByAvatarIDAndSeasonID'})do
|
||||
local dict=module:GetType():GetField(name,flags):GetValue(module)
|
||||
log('CACHE '..name..' '..dict.Count)
|
||||
end
|
||||
local list=module.DivisionInfo:GetStagesShown(false)
|
||||
log('STAGES '..list.Count)
|
||||
_G.__gacCwStageConfigsExport={rows=list,index=0}
|
||||
for _,name in ipairs({'GridFightRoleConfig','GridFightHandbookRole','GridFightStageRoute'})do
|
||||
local t=typeof(CS.RPG.Client[name]);log('TYPE '..tostring(t))
|
||||
local fs=t:GetFields(flags);for i=0,fs.Length-1 do log('FIELD '..tostring(fs[i]))end
|
||||
local ps=t:GetProperties(flags);for i=0,ps.Length-1 do log('PROPERTY '..tostring(ps[i]))end
|
||||
end
|
||||
end)
|
||||
if not ok then log('ERROR '..tostring(err))end
|
||||
end
|
||||
local state=_G.__gacCwStageConfigsExport
|
||||
if state and not state.done then
|
||||
local function log(v)CS.UnityEngine.Debug.Log('[GAC_CW_STAGE_CONFIG] '..tostring(v))end
|
||||
local ok,err=pcall(function()
|
||||
if state.index==0 then log('BEGIN count='..state.rows.Count)end
|
||||
for i=state.index,math.min(state.index+1,state.rows.Count-1)do
|
||||
local r=state.rows[i]
|
||||
log('ROW {"ID":'..r.ID..',"EnemyHardLevel":'..r.EnemyHardLevel..',"Exp":'..r.Exp..',"WeeklyScore":'..r.WeeklyScore..',"OverChargeExp":'..r.OverChargeExp..',"OverChargeWeeklyScore":'..r.OverChargeWeeklyScore..',"ScoreRule":'..r.ScoreRule..',"OCScoreRule":'..r.OCScoreRule..',"EnvironmentBuffList":'..CS.Newtonsoft.Json.JsonConvert.SerializeObject(r.EnvironmentBuffList)..'}')
|
||||
end
|
||||
state.index=state.index+2
|
||||
if state.index>=state.rows.Count then log('END');state.done=true end
|
||||
end)
|
||||
if not ok then log('ERROR '..tostring(err));state.done=true end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,27 @@
|
||||
-- One named serializer type, bounded metadata only; no invocation or hooks.
|
||||
do
|
||||
_G.__gacCwJsonMethod3=_G.__gacCwJsonMethod3 or {offset=0}
|
||||
local s=_G.__gacCwJsonMethod3
|
||||
if s.done then return end
|
||||
local flags=CS.System.Enum.ToObject(typeof(CS.System.Reflection.BindingFlags),60)
|
||||
local manager=CS.RPG.Client.GlobalVars.s_GamePhaseManager
|
||||
local phase=manager and typeof(CS.RPG.Client.GamePhaseManager):GetField('_CurrentPhase',flags):GetValue(manager)
|
||||
if not phase or typeof(CS.RPG.Client.BattleGamePhase):IsInstanceOfType(phase)then return end
|
||||
local t=typeof(CS.Newtonsoft.Json.JsonConvert)
|
||||
local methods=t:GetMethods(flags)
|
||||
local log=function(v)CS.UnityEngine.Debug.Log('[GAC_CW_JSON_METHOD] '..tostring(v))end
|
||||
for i=s.offset,math.min(s.offset+31,methods.Length-1)do
|
||||
local m=methods[i]
|
||||
if m.IsStatic and m.Name=='SerializeObject' then
|
||||
local ps=m:GetParameters()
|
||||
if ps.Length==1 and ps[0].ParameterType==typeof(CS.System.Object) then
|
||||
log('METHOD '..tostring(m)..' TOKEN '..m.MetadataToken)
|
||||
log('TOKEN_ROW [GAC_CW_METHOD_TOKEN] METHOD Newtonsoft.Json.JsonConvert SerializeObject_OneObject '..m.MetadataToken)
|
||||
local good,handle=pcall(function()return tostring(m.MethodHandle.Value)end)
|
||||
log('HANDLE '..tostring(good)..' '..tostring(handle))
|
||||
end
|
||||
end
|
||||
end
|
||||
s.offset=s.offset+32
|
||||
if s.offset>=methods.Length then s.done=true;log('END')end
|
||||
end
|
||||
@@ -0,0 +1,34 @@
|
||||
-- Metadata only, one exact CW type per heartbeat, paused during Battle.
|
||||
do
|
||||
local names={'RPG.Client.GridFightPlayer','RPG.Client.GridFightPlayerLevelConfig','RPG.GameCore.GridFightPlayerLevelConfig','RPG.Client.GridFightStageNodeTemplateConfig','RPG.GameCore.GridFightStageNodeTemplateConfig'}
|
||||
_G.__gacCwLevelSchema1=_G.__gacCwLevelSchema1 or {index=1,offset=0}
|
||||
local s=_G.__gacCwLevelSchema1
|
||||
if s.index>#names then return end
|
||||
local flags=CS.System.Enum.ToObject(typeof(CS.System.Reflection.BindingFlags),60)
|
||||
local manager=CS.RPG.Client.GlobalVars.s_GamePhaseManager
|
||||
local phase=manager and typeof(CS.RPG.Client.GamePhaseManager):GetField('_CurrentPhase',flags):GetValue(manager)
|
||||
if not phase or typeof(CS.RPG.Client.BattleGamePhase):IsInstanceOfType(phase) then return end
|
||||
local log=function(v)CS.UnityEngine.Debug.Log('[GAC_CW_LEVEL_SCHEMA] '..tostring(v))end
|
||||
local ok,err=pcall(function()
|
||||
if not s.type then
|
||||
local a=typeof(CS.RPG.Client.GridFightModule).Assembly
|
||||
local b=typeof(CS.RPG.GameCore.GridFightRoleConfigRow).Assembly
|
||||
s.type=a:GetType(names[s.index]) or b:GetType(names[s.index])
|
||||
log('TYPE '..names[s.index]..' '..tostring(s.type))
|
||||
if not s.type then s.index=s.index+1;return end
|
||||
local fs=s.type:GetFields(flags)
|
||||
for i=0,math.min(fs.Length-1,63) do log('FIELD '..tostring(fs[i]))end
|
||||
local ctors=s.type:GetConstructors(flags)
|
||||
for i=0,math.min(ctors.Length-1,15)do log('CTOR '..tostring(ctors[i]))end
|
||||
s.methods=s.type:GetMethods(flags)
|
||||
end
|
||||
for i=s.offset,math.min(s.offset+31,s.methods.Length-1)do
|
||||
local m=s.methods[i]
|
||||
if m.DeclaringType==s.type then log('METHOD '..tostring(m)..' TOKEN '..m.MetadataToken)end
|
||||
end
|
||||
s.offset=s.offset+32
|
||||
if s.offset>=s.methods.Length then s.type=nil;s.methods=nil;s.offset=0;s.index=s.index+1 end
|
||||
end)
|
||||
if not ok then log('ERROR '..tostring(err));s.type=nil;s.methods=nil;s.offset=0;s.index=s.index+1 end
|
||||
if s.index>#names then log('END')end
|
||||
end
|
||||
@@ -0,0 +1,39 @@
|
||||
-- Bounded, read-only inspection of the active CW team container.
|
||||
do
|
||||
if _G.__gacCwBoardState2 then return end
|
||||
local session=CS.RPG.Client.GlobalVars.s_ModuleManager.GridFightModule.CurGameSession
|
||||
if not session then return end
|
||||
_G.__gacCwBoardState2=true
|
||||
local log=function(v)CS.UnityEngine.Debug.Log('[GAC_CW_BOARD_STATE] '..tostring(v))end
|
||||
local ok,err=pcall(function()
|
||||
local flags=CS.System.Enum.ToObject(typeof(CS.System.Reflection.BindingFlags),60)
|
||||
local fields=session:GetType():GetFields(flags)
|
||||
for i=0,math.min(fields.Length-1,63)do
|
||||
local field=fields[i]
|
||||
if field.Name:lower():find('team')then
|
||||
local team=field:GetValue(session)
|
||||
if team then
|
||||
local fs=team:GetType():GetFields(flags)
|
||||
for j=0,math.min(fs.Length-1,31)do
|
||||
local f=fs[j];local value=f:GetValue(team)
|
||||
if f.Name:lower():find('role')then
|
||||
log('TEAM '..tostring(f)..' = '..tostring(value))
|
||||
if value then
|
||||
local inner=value:GetType():GetFields(flags)
|
||||
for k=0,math.min(inner.Length-1,15)do local x=inner[k];local v=x:GetValue(value)
|
||||
log('CONTAINER '..tostring(x)..' = '..tostring(v))
|
||||
if v then pcall(function()
|
||||
local en=v:GetEnumerator();local n=0
|
||||
while n<6 and en:MoveNext()do n=n+1;log('ENTRY '..tostring(en.Current))end
|
||||
end)end
|
||||
end
|
||||
pcall(function()local en=value:GetEnumerator();local n=0;while n<6 and en:MoveNext()do n=n+1;log('VALUE '..tostring(en.Current))end end)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
||||
if not ok then log('ERROR '..tostring(err))end
|
||||
end
|
||||
@@ -0,0 +1,25 @@
|
||||
-- Read current CW role/player containers only; no game action.
|
||||
do
|
||||
if _G.__gacCwLiveRoleState1 then return end;_G.__gacCwLiveRoleState1=true
|
||||
local log=function(v)CS.UnityEngine.Debug.Log('[GAC_CW_LIVE_ROLES] '..tostring(v))end
|
||||
local ok,err=pcall(function()
|
||||
local flags=CS.System.Enum.ToObject(typeof(CS.System.Reflection.BindingFlags),60)
|
||||
local session=CS.RPG.Client.GlobalVars.s_ModuleManager.GridFightModule.CurGameSession
|
||||
if not session then log('NO_SESSION');return end
|
||||
log('SESSION '..session:GetType().FullName)
|
||||
local t=session:GetType();local fs=t:GetFields(flags)
|
||||
for i=0,math.min(fs.Length-1,95)do
|
||||
local f=fs[i];local n=f.Name:lower()
|
||||
if n:find('role') or n:find('player') or n:find('team') or n:find('shop')then
|
||||
local v=f:GetValue(session);log('FIELD '..tostring(f)..' VALUE '..tostring(v))
|
||||
if v then
|
||||
local vt=v:GetType();local fields=vt:GetFields(flags)
|
||||
for j=0,math.min(fields.Length-1,63)do local x=fields[j];local xn=x.Name:lower();if xn:find('role') or xn:find('count') or xn:find('level') or xn:find('gold') then
|
||||
local z=x:GetValue(v);local count=nil;if z then pcall(function()count=z.Count end)end;log('INNER '..tostring(x)..' VALUE '..tostring(z)..' COUNT '..tostring(count))
|
||||
end end
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
||||
if not ok then log('ERROR '..tostring(err))end
|
||||
end
|
||||
@@ -0,0 +1,22 @@
|
||||
-- Read loaded CW Lua modules only. Do not require modules or invoke UI code.
|
||||
do
|
||||
if not _G.__gacCwLoadedLua1 then
|
||||
_G.__gacCwLoadedLua1=true
|
||||
local function log(v)CS.UnityEngine.Debug.Log('[GAC_CW_LOADED_LUA] '..tostring(v))end
|
||||
local n=0
|
||||
for name,value in pairs(package.loaded)do
|
||||
if tostring(name):lower():find('gridfight')then
|
||||
log('MODULE '..tostring(name)..' TYPE '..type(value))
|
||||
if tostring(name):lower():find('entrance') and type(value)=='table' then
|
||||
local count=0
|
||||
for k,v in pairs(value)do
|
||||
if type(v)=='function' then local info=debug.getinfo(v,'S');log('FUNCTION '..tostring(k)..' '..tostring(info and info.source))end
|
||||
count=count+1;if count>=64 then break end
|
||||
end
|
||||
end
|
||||
n=n+1;if n>=64 then break end
|
||||
end
|
||||
end
|
||||
log('END '..n)
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,20 @@
|
||||
-- Inspect only the known GameCoreConfigLoader, bounded method metadata batches.
|
||||
-- This never invokes a loader, including any level-graph loader.
|
||||
do
|
||||
_G.__gacCwLoaderMethods1=_G.__gacCwLoaderMethods1 or {index=0}
|
||||
local state=_G.__gacCwLoaderMethods1
|
||||
if not state.done then
|
||||
local function log(v)CS.UnityEngine.Debug.Log('[GAC_CW_LOADER_METHOD] '..tostring(v))end
|
||||
local flags=CS.System.Enum.ToObject(typeof(CS.System.Reflection.BindingFlags),60)
|
||||
if not state.methods then
|
||||
state.methods=typeof(CS.RPG.GameCore.GameCoreConfigLoader):GetMethods(flags)
|
||||
log('BEGIN '..state.methods.Length)
|
||||
end
|
||||
for i=state.index,math.min(state.index+63,state.methods.Length-1)do
|
||||
local m=state.methods[i]
|
||||
if m.Name:lower():find('gridfight')then log('METHOD '..tostring(m))end
|
||||
end
|
||||
state.index=state.index+64
|
||||
if state.index>=state.methods.Length then state.done=true;log('END')end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,24 @@
|
||||
-- Loaded floor metadata only, 32 group names per heartbeat.
|
||||
do
|
||||
local input=__ENTRANCE_ROW__
|
||||
local function log(v)CS.UnityEngine.Debug.Log('[GAC_CW_LOBBY_NAMES] '..tostring(v))end
|
||||
_G.__gacCwLobbyNames1=_G.__gacCwLobbyNames1 or {index=0}
|
||||
local state=_G.__gacCwLobbyNames1
|
||||
if not state.done then
|
||||
local ok,err=pcall(function()
|
||||
if not state.floor then
|
||||
local entry=CS.RPG.GameCore.ConstValueCommonExcelTable.GetData('GridFight_EntranceID').Value.IntValue
|
||||
if entry~=input.ID then error('CW entry mismatch')end
|
||||
state.floor=CS.RPG.GameCore.GameCoreConfigLoader.LoadRtLevelFloorInfo(CS.RPG.Client.MapDef.GetRtFloorInfoPath(input.PlaneID,input.FloorID))
|
||||
log('BEGIN '..state.floor.GroupInstanceList.Length)
|
||||
end
|
||||
for i=state.index,math.min(state.index+31,state.floor.GroupInstanceList.Length-1)do
|
||||
local g=state.floor.GroupInstanceList[i]
|
||||
log('GROUP '..g.ID..' '..tostring(g.Name))
|
||||
end
|
||||
state.index=state.index+32
|
||||
if state.index>=state.floor.GroupInstanceList.Length then state.done=true;log('END')end
|
||||
end)
|
||||
if not ok then state.done=true;log('ERROR '..tostring(err))end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,88 @@
|
||||
"""Inspect explicit runtime-resolved getter RVAs, never search an assembly's types."""
|
||||
import argparse
|
||||
import hashlib
|
||||
import json
|
||||
import pathlib
|
||||
import struct
|
||||
from capstone import Cs, CS_ARCH_X86, CS_MODE_64, CS_OP_MEM, CS_OP_REG
|
||||
|
||||
def main():
|
||||
p = argparse.ArgumentParser(description=__doc__)
|
||||
p.add_argument('--binary', type=pathlib.Path, required=True)
|
||||
p.add_argument('--handles', type=pathlib.Path, required=True)
|
||||
p.add_argument('--output', type=pathlib.Path, required=True)
|
||||
args = p.parse_args()
|
||||
data = args.binary.read_bytes()
|
||||
pe = struct.unpack_from('<I', data, 0x3c)[0]
|
||||
if data[:2] != b'MZ' or data[pe:pe+4] != b'PE\0\0':
|
||||
raise SystemExit('Expected PE image')
|
||||
count = struct.unpack_from('<H', data, pe+6)[0]
|
||||
optional_size = struct.unpack_from('<H', data, pe+20)[0]
|
||||
sections = [struct.unpack_from('<IIII', data, pe+24+optional_size+i*40+8) for i in range(count)]
|
||||
def offset(rva, size):
|
||||
for _, start, length, raw in sections:
|
||||
if start <= rva and rva+size <= start+length:
|
||||
return raw+rva-start
|
||||
raise ValueError('RVA range outside raw PE sections')
|
||||
exception_rva, exception_size = struct.unpack_from('<II', data, pe+24+112+3*8)
|
||||
base = offset(exception_rva, exception_size)
|
||||
bounds = [struct.unpack_from('<III', data, off)[:2] for off in range(base, base+exception_size, 12)]
|
||||
decoder = Cs(CS_ARCH_X86, CS_MODE_64)
|
||||
decoder.detail = True
|
||||
rows = []
|
||||
for item in json.loads(args.handles.read_text(encoding='utf-8-sig')):
|
||||
rva = int(item['rva'], 0)
|
||||
matching = [(b, e) for b, e in bounds if b == rva and e-b <= 65536]
|
||||
if not item['executable']:
|
||||
raise SystemExit('Getter handle is not executable')
|
||||
if len(matching) == 1:
|
||||
_, end = matching[0]
|
||||
boundary = 'AMD64 exception table'
|
||||
else:
|
||||
# AMD64 leaf getters can omit unwind entries. Admit only a tiny
|
||||
# straight-line load/return sequence, without calls or branches.
|
||||
leaf = list(decoder.disasm(data[offset(rva,64):offset(rva,64)+64],rva))
|
||||
first_ret = next((i for i,x in enumerate(leaf) if x.mnemonic=='ret'),None)
|
||||
if first_ret is None or first_ret>8 or any(x.mnemonic not in ('mov','movzx','movss','ret','nop','endbr64') for x in leaf[:first_ret+1]):
|
||||
rows.append({**item,'direct_return_loads':[],'limitation':'No exception entry or proven straight-line leaf getter'})
|
||||
continue
|
||||
end = leaf[first_ret].address+leaf[first_ret].size
|
||||
boundary = 'Runtime method entry, straight-line leaf return'
|
||||
instructions = list(decoder.disasm(data[offset(rva,end-rva):offset(rva,end-rva)+end-rva],rva))
|
||||
loads = []
|
||||
aliases = {'rcx'}
|
||||
for i, ins in enumerate(instructions):
|
||||
# A later dereference into _NodeParam must not be mistaken for
|
||||
# an offset on this. Track overwritten registers and call clobbers.
|
||||
before = set(aliases)
|
||||
if ins.mnemonic == 'call':
|
||||
aliases.difference_update({'rax','rcx','rdx','r8','r9','r10','r11'})
|
||||
if ins.operands and ins.operands[0].type == CS_OP_REG:
|
||||
dest = ins.reg_name(ins.operands[0].reg)
|
||||
if ins.mnemonic == 'mov' and len(ins.operands)==2 and ins.operands[1].type==CS_OP_REG and ins.reg_name(ins.operands[1].reg) in before:
|
||||
aliases.add(dest)
|
||||
elif ins.mnemonic not in ('cmp','test','push'):
|
||||
aliases.discard(dest)
|
||||
if ins.mnemonic not in ('mov', 'movzx', 'movss') or len(ins.operands) != 2:
|
||||
continue
|
||||
src = ins.operands[1]
|
||||
if src.type != CS_OP_MEM or src.mem.index or ins.reg_name(src.mem.base) not in before:
|
||||
continue
|
||||
if ins.reg_name(ins.operands[0].reg) not in ('eax', 'rax', 'xmm0'):
|
||||
continue
|
||||
after = instructions[i+1:i+7]
|
||||
epilogue = []
|
||||
for following in after:
|
||||
epilogue.append(following)
|
||||
if following.mnemonic == 'ret':
|
||||
break
|
||||
if not epilogue or epilogue[-1].mnemonic != 'ret' or any(x.mnemonic not in ('add','pop','ret','nop') for x in epilogue):
|
||||
continue
|
||||
loads.append({'offset':src.mem.disp,'size':src.size,'instruction':f'{ins.address:x}: {ins.mnemonic} {ins.op_str}'})
|
||||
rows.append({**item,'boundary':boundary,'direct_return_loads':loads})
|
||||
args.output.write_text(json.dumps({'assembly_sha256':hashlib.sha256(data).hexdigest(),
|
||||
'scope':'Explicit named runtime getter handles; direct baseline return loads only, not computed getter semantics',
|
||||
'getters':rows},indent=2)+'\n',encoding='utf-8')
|
||||
print(f'Inspected {len(rows)} named getters; {sum(len(x["direct_return_loads"])==1 for x in rows)} have a unique direct return load')
|
||||
|
||||
if __name__ == '__main__': main()
|
||||
@@ -0,0 +1,25 @@
|
||||
-- Targeted read-only access to the native season metadata getter.
|
||||
do
|
||||
if not _G.__gacCwMeta1 then
|
||||
_G.__gacCwMeta1=true
|
||||
local function log(v)CS.UnityEngine.Debug.Log('[GAC_CW_META] '..tostring(v))end
|
||||
local ok,err=pcall(function()
|
||||
local flags=CS.System.Enum.ToObject(typeof(CS.System.Reflection.BindingFlags),60)
|
||||
local invoke=CS.System.Enum.ToObject(typeof(CS.System.Reflection.BindingFlags),0)
|
||||
local args=CS.System.Array.CreateInstance(typeof(CS.System.Object),0)
|
||||
local module=CS.RPG.Client.GlobalVars.s_ModuleManager.GridFightModule
|
||||
local first=typeof(CS.RPG.Client.GridFightModule):GetField('FirstSeasonID',flags):GetValue(nil)
|
||||
local season=module:GetSeason(first,nil)
|
||||
local meta=season:GetType():GetMethod('get__Meta',flags):Invoke(season,invoke,nil,args,nil)
|
||||
log('SEASON_ROW '..CS.Newtonsoft.Json.JsonConvert.SerializeObject(meta))
|
||||
local method=module:GetType():GetMethod('_SyncSeason',flags)
|
||||
local handle=method.MethodHandle
|
||||
local getter=handle:GetType():GetMethod('GetFunctionPointer',flags)
|
||||
if getter then
|
||||
local pointer=getter:Invoke(handle,invoke,nil,args,nil)
|
||||
log('SYNC_SEASON_POINTER '..tostring(pointer))
|
||||
end
|
||||
end)
|
||||
if not ok then log('ERROR '..tostring(err))end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,23 @@
|
||||
-- Named CW types only, at most 64 method tokens per heartbeat.
|
||||
do
|
||||
local names={'RPG.Client.GridFightModule','AMEEHIIPMFP','CKPOBLIFMGN','MPIMAEMCEFH','RPG.Client.GridFightTalent','RPG.Client.GridFightPlayerProfile','RPG.Client.GridFightGameSession','RPG.Client.GridFightPlayer'}
|
||||
_G.__gacCwMethodTokens=_G.__gacCwMethodTokens or {index=1,method=0}
|
||||
local state=_G.__gacCwMethodTokens
|
||||
if state.index<=#names then
|
||||
local function log(v)CS.UnityEngine.Debug.Log('[GAC_CW_METHOD_TOKEN] '..tostring(v))end
|
||||
local ok,err=pcall(function()
|
||||
local flags=CS.System.Enum.ToObject(typeof(CS.System.Reflection.BindingFlags),60)
|
||||
local assembly=typeof(CS.RPG.Client.GridFightModule).Assembly
|
||||
local t=assembly:GetType(names[state.index])
|
||||
if not t then t=typeof(CS[names[state.index]])end
|
||||
local methods=t:GetMethods(flags)
|
||||
for i=state.method,math.min(state.method+63,methods.Length-1)do
|
||||
local m=methods[i]
|
||||
if m.DeclaringType==t then log('METHOD '..names[state.index]..' '..m.Name..' '..m.MetadataToken)end
|
||||
end
|
||||
state.method=state.method+64
|
||||
if state.method>=methods.Length then log('END '..names[state.index]);state.index=state.index+1;state.method=0 end
|
||||
end)
|
||||
if not ok then log('ERROR '..names[state.index]..' '..tostring(err));state.index=state.index+1;state.method=0 end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,34 @@
|
||||
-- Read only named CW stage/node metadata, one object per heartbeat.
|
||||
do
|
||||
local state=_G.__gacCwNodeBattleSchema5 or {index=1};_G.__gacCwNodeBattleSchema5=state
|
||||
if state.done then return end
|
||||
local log=function(v)CS.UnityEngine.Debug.Log('[GAC_CW_MONSTER_BASE] '..tostring(v))end
|
||||
local ok,err=pcall(function()
|
||||
local flags=CS.System.Enum.ToObject(typeof(CS.System.Reflection.BindingFlags),60)
|
||||
local session=CS.RPG.Client.GlobalVars.s_ModuleManager.GridFightModule.CurGameSession
|
||||
if not session then return end
|
||||
if not state.objects then
|
||||
local fields=session:GetType():GetFields(flags)
|
||||
for i=0,math.min(fields.Length-1,63)do
|
||||
local f=fields[i]
|
||||
if f.FieldType.FullName=='RPG.Client.GridFightStage'then
|
||||
local stage=f:GetValue(session)
|
||||
if stage and stage.CurNode then state.objects={stage.CurMonsterStageData.HighestTierMonster.BaseData};log('COORD '..stage.RouteID..'/'..stage.ChapterID..'/'..stage.SectionID..' LEVEL '..stage.CurMonsterLevel);local row=stage.CurNode:GetType():GetProperty('_PenaltyRuleConfigRow',flags):GetValue(stage.CurNode,nil);if row then log('PENALTY_JSON '..CS.Newtonsoft.Json.JsonConvert.SerializeObject(row))end end
|
||||
end
|
||||
end
|
||||
if not state.objects then return end
|
||||
end
|
||||
local value=state.objects[state.index];if not value then log('END');state.done=true;return end
|
||||
state.index=state.index+1
|
||||
local t=value:GetType();log('TYPE '..t.FullName)
|
||||
local fs=t:GetFields(flags)
|
||||
for i=0,math.min(fs.Length-1,47)do log('FIELD '..tostring(fs[i]))end
|
||||
local ps=t:GetProperties(flags)
|
||||
for i=0,math.min(ps.Length-1,47)do log('PROPERTY '..tostring(ps[i]))end
|
||||
local ms=t:GetMethods(flags)
|
||||
for i=0,math.min(ms.Length-1,95)do if ms[i].DeclaringType==t then log('METHOD '..tostring(ms[i]))end end
|
||||
if state.index==2 then log('END');state.done=true end
|
||||
end)
|
||||
if not ok then log('ERROR '..tostring(err));state.done=true end
|
||||
end
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
-- Existing CW handbook monster configurations only, two rows per heartbeat.
|
||||
-- No battle/level/graph loader, player object, or scene change is invoked.
|
||||
do
|
||||
_G.__gacCwCampExport1=_G.__gacCwCampExport1 or {index=0}
|
||||
local s=_G.__gacCwCampExport1
|
||||
if s.done then return end
|
||||
local flags=CS.System.Enum.ToObject(typeof(CS.System.Reflection.BindingFlags),60)
|
||||
local manager=CS.RPG.Client.GlobalVars.s_GamePhaseManager
|
||||
local phase=manager and typeof(CS.RPG.Client.GamePhaseManager):GetField('_CurrentPhase',flags):GetValue(manager)
|
||||
if not phase or typeof(CS.RPG.Client.BattleGamePhase):IsInstanceOfType(phase)then return end
|
||||
local log=function(v)CS.UnityEngine.Debug.Log('[GAC_CW_MONSTER_CAMP] '..tostring(v))end
|
||||
local good,err=pcall(function()
|
||||
if not s.rows then
|
||||
s.rows=CS.RPG.Client.GlobalVars.s_ModuleManager.GridFightModule:GetAllMonsterCampData()
|
||||
if s.rows.Count>2048 then error('Monster camp count exceeds capture bound')end
|
||||
s.expected=s.rows.Count
|
||||
log('BEGIN count='..s.expected)
|
||||
if s.expected>0 then
|
||||
local t=s.rows[0]:GetType()
|
||||
s.fields=t:GetFields(flags)
|
||||
log('TYPE '..t.FullName)
|
||||
for i=0,math.min(s.fields.Length-1,63)do log('FIELD '..tostring(s.fields[i]))end
|
||||
end
|
||||
end
|
||||
for batch=1,2 do
|
||||
if s.index>=s.expected then s.done=true;s.rows=nil;s.fields=nil;log('END');return end
|
||||
local object=s.rows[s.index]
|
||||
local pieces={}
|
||||
for i=0,math.min(s.fields.Length-1,63)do
|
||||
local f=s.fields[i]
|
||||
if not f.IsStatic and (f.FieldType.IsPrimitive or f.FieldType.IsEnum or f.FieldType==typeof(CS.System.String) or f.FieldType.FullName:find('RPG.GameCore.',1,true)==1)then
|
||||
local value=f:GetValue(object)
|
||||
pieces[#pieces+1]=CS.Newtonsoft.Json.JsonConvert.SerializeObject(f.Name)..':'..CS.Newtonsoft.Json.JsonConvert.SerializeObject(value)
|
||||
end
|
||||
end
|
||||
local text='{'..table.concat(pieces,',')..'}'
|
||||
if #text>65536 then error('Monster camp row exceeds capture bound')end
|
||||
log('ROW '..text)
|
||||
s.index=s.index+1
|
||||
end
|
||||
end)
|
||||
if not good then s.done=true;s.rows=nil;s.fields=nil;log('ERROR '..tostring(err))end
|
||||
end
|
||||
@@ -0,0 +1,34 @@
|
||||
-- Read only named CW stage/node metadata, one object per heartbeat.
|
||||
do
|
||||
local state=_G.__gacCwNodeBattleSchema4 or {index=1};_G.__gacCwNodeBattleSchema4=state
|
||||
if state.done then return end
|
||||
local log=function(v)CS.UnityEngine.Debug.Log('[GAC_CW_MONSTER_DETAIL] '..tostring(v))end
|
||||
local ok,err=pcall(function()
|
||||
local flags=CS.System.Enum.ToObject(typeof(CS.System.Reflection.BindingFlags),60)
|
||||
local session=CS.RPG.Client.GlobalVars.s_ModuleManager.GridFightModule.CurGameSession
|
||||
if not session then return end
|
||||
if not state.objects then
|
||||
local fields=session:GetType():GetFields(flags)
|
||||
for i=0,math.min(fields.Length-1,63)do
|
||||
local f=fields[i]
|
||||
if f.FieldType.FullName=='RPG.Client.GridFightStage'then
|
||||
local stage=f:GetValue(session)
|
||||
if stage and stage.CurNode then state.objects={stage.CurMonsterStageData.HighestTierMonster};log('COORD '..stage.RouteID..'/'..stage.ChapterID..'/'..stage.SectionID..' LEVEL '..stage.CurMonsterLevel);local row=stage.CurNode:GetType():GetProperty('_PenaltyRuleConfigRow',flags):GetValue(stage.CurNode,nil);if row then log('PENALTY_JSON '..CS.Newtonsoft.Json.JsonConvert.SerializeObject(row))end end
|
||||
end
|
||||
end
|
||||
if not state.objects then return end
|
||||
end
|
||||
local value=state.objects[state.index];if not value then log('END');state.done=true;return end
|
||||
state.index=state.index+1
|
||||
local t=value:GetType();log('TYPE '..t.FullName)
|
||||
local fs=t:GetFields(flags)
|
||||
for i=0,math.min(fs.Length-1,47)do log('FIELD '..tostring(fs[i]))end
|
||||
local ps=t:GetProperties(flags)
|
||||
for i=0,math.min(ps.Length-1,47)do log('PROPERTY '..tostring(ps[i]))end
|
||||
local ms=t:GetMethods(flags)
|
||||
for i=0,math.min(ms.Length-1,95)do if ms[i].DeclaringType==t then log('METHOD '..tostring(ms[i]))end end
|
||||
if state.index==2 then log('END');state.done=true end
|
||||
end)
|
||||
if not ok then log('ERROR '..tostring(err));state.done=true end
|
||||
end
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
-- Named groups selected from a completed floor-name capture, two per heartbeat.
|
||||
-- This only reads configuration; graph paths are serialized, never executed.
|
||||
do
|
||||
local input=__ENTRANCE_ROW__
|
||||
local targets=__GROUP_IDS__
|
||||
local function log(v)CS.UnityEngine.Debug.Log('[GAC_CW_NAMED_GROUPS] '..tostring(v))end
|
||||
_G.__gacCwNamedGroups3=_G.__gacCwNamedGroups3 or {index=1}
|
||||
local state=_G.__gacCwNamedGroups3
|
||||
if not state.done then
|
||||
local ok,err=pcall(function()
|
||||
if not state.floor then
|
||||
state.floor=CS.RPG.GameCore.GameCoreConfigLoader.LoadRtLevelFloorInfo(CS.RPG.Client.MapDef.GetRtFloorInfoPath(input.PlaneID,input.FloorID))
|
||||
log('BEGIN '..#targets)
|
||||
for i=0,math.min(state.floor.DimensionList.Length-1,3)do
|
||||
log('SAVED '..CS.Newtonsoft.Json.JsonConvert.SerializeObject(state.floor.DimensionList[i].SavedValues))
|
||||
end
|
||||
end
|
||||
for j=state.index,math.min(state.index+1,#targets)do
|
||||
local found=false
|
||||
for i=0,state.floor.GroupInstanceList.Length-1 do
|
||||
local g=state.floor.GroupInstanceList[i]
|
||||
if g.ID==targets[j] then
|
||||
found=true
|
||||
local r=CS.RPG.GameCore.GameCoreConfigLoader.LoadRtLevelGroupInfo(g.GroupPath)
|
||||
local function json(v)return CS.Newtonsoft.Json.JsonConvert.SerializeObject(v)end
|
||||
local props={}
|
||||
if r.PropList then for k=0,r.PropList.Length-1 do
|
||||
local p=r.PropList[k]
|
||||
local yaw=g.RotY*math.pi/180
|
||||
local pos=string.format('{"x":%d,"y":%d,"z":%d}',math.floor((g.PosX+p.PosX*math.cos(yaw)+p.PosZ*math.sin(yaw))*1000+0.5),math.floor((g.PosY+p.PosY)*1000+0.5),math.floor((g.PosZ-p.PosX*math.sin(yaw)+p.PosZ*math.cos(yaw))*1000+0.5))
|
||||
local rot=string.format('{"x":0,"y":%d,"z":0}',math.floor((g.RotY+p.RotY)*1000+0.5))
|
||||
props[#props+1]='{"id":'..p.ID..',"prop_id":'..p.PropID..',"state":'..CS.System.Convert.ToUInt32(p.State)..',"pos":'..pos..',"rot":'..rot..',"deleted":'..tostring(p.IsDelete)..',"client_only":'..tostring(p.IsClientOnly)..',"initial":'..tostring(p.LoadOnInitial)..',"state_configs":'..json(p.StateConfigs)..',"value_source":'..json(p.ValueSource)..',"init_graph":'..json(p.InitLevelGraph)..'}'
|
||||
end end
|
||||
log('GROUP '..g.ID..' {"name":'..json(r.GroupName)..',"initial":'..tostring(r.LoadOnInitial)..',"load_condition":'..json(r.LoadCondition)..',"unload_condition":'..json(r.UnloadCondition)..',"saved_value_condition":'..json(r.SavedValueCondition)..',"system_unlock_condition":'..json(r.SystemUnlockCondition)..',"properties":'..json(r.GroupPropertyMap)..',"graph":'..json(r.LevelGraph)..',"tags":'..json(r.TagContainer)..',"props":['..table.concat(props,',')..']}')
|
||||
break
|
||||
end
|
||||
end
|
||||
if not found then error('Named group missing: '..targets[j])end
|
||||
end
|
||||
state.index=state.index+2
|
||||
if state.index>#targets then state.done=true;log('END')end
|
||||
end)
|
||||
if not ok then state.done=true;log('ERROR '..tostring(err))end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,27 @@
|
||||
// Native table getter used by GridFightStageNode._RefreshCachedFields with
|
||||
// the route node's ChapterID. Source hash and function bounds are retained in
|
||||
// cw-chapter-table-getter.asm. Run only on the managed handbook caller thread.
|
||||
const ids = globalThis.CW_CHAPTER_IDS;
|
||||
if (!Array.isArray(ids) || ids.length === 0 || ids.length > 128 || ids.some(x=>!Number.isInteger(x)||x<=0)) throw Error('Supply captured route chapter IDs');
|
||||
const m = Process.getModuleByName('GameAssembly.dll');
|
||||
const bytes = Array.from(new Uint8Array(m.base.add(0x1de40ce0).readByteArray(5)));
|
||||
if (bytes.join(',') !== [0x56,0x48,0x83,0xec,0x60].join(',')) throw Error('Chapter getter prefix mismatch');
|
||||
const read = new NativeFunction(m.base.add(0x1de40ce0),'pointer',['uint32','pointer']);
|
||||
const serialize = new NativeFunction(m.base.add(0x1d3efb60),'pointer',['pointer','pointer']);
|
||||
let index=0, done=false;
|
||||
Interceptor.attach(m.base.add(0xdb5f860), {onLeave() {
|
||||
if(done)return;
|
||||
try {
|
||||
const key=ids[index++], row=read(key,ptr(0));
|
||||
if(row.isNull())throw Error('Missing chapter row '+key);
|
||||
const encoded=serialize(row,ptr(0));
|
||||
if(encoded.isNull())throw Error('Serializer returned null');
|
||||
const length=encoded.add(0x10).readS32();
|
||||
if(length<2||length>65536)throw Error('Chapter row exceeds capture bound');
|
||||
const json=encoded.add(0x14).readUtf16String(length), parsed=JSON.parse(json);
|
||||
if(parsed.ChapterID!==key && parsed.ID!==key)throw Error('Chapter row identity differs: '+Object.keys(parsed).join(','));
|
||||
send({kind:'ROW',key,json,thread:Process.getCurrentThreadId()});
|
||||
if(index===ids.length){done=true;send({kind:'END',count:ids.length});}
|
||||
}catch(e){done=true;send({kind:'ERROR',error:String(e)});}
|
||||
}});
|
||||
send({kind:'BEGIN',count:ids.length});
|
||||
@@ -0,0 +1,55 @@
|
||||
// Research-only, source assembly SHA256:
|
||||
// c5e02e6e984f7e5577c78b995a8efeee2d06ee22e67d484ad5e859c8bf21e144.
|
||||
// PE exception table proves both entry RVAs. No dictionary/schema writes.
|
||||
// Query one named Excel table on a managed caller's thread, at most two rows
|
||||
// per handbook call. Its native getter can lazily initialize this Excel table;
|
||||
// the verified loader only reads table rows, and no level graph is invoked.
|
||||
const plan = globalThis.CW_CAPTURE_PLAN;
|
||||
if (!plan || !Number.isInteger(plan.maxLevel) || plan.maxLevel <= 0 || plan.maxLevel > 256) {
|
||||
throw new Error('Supply the captured default maximum player level');
|
||||
}
|
||||
const module = Process.getModuleByName('GameAssembly.dll');
|
||||
const check = (rva, expected) => {
|
||||
const actual = Array.from(new Uint8Array(module.base.add(rva).readByteArray(expected.length)));
|
||||
if (actual.some((v, i) => v !== expected[i])) throw new Error('Native entry bytes differ from captured assembly');
|
||||
};
|
||||
check(0xdb5f860, [0x55,0x41,0x56,0x56,0x57,0x53]);
|
||||
check(0x1e3a7880, [0x56,0x48,0x83,0xec,0x60,0x89,0xce]);
|
||||
// RuntimeMethodHandle.Value + 8 resolved this exact serializer entry; the
|
||||
// earlier metadata-token match was a different function and is not used.
|
||||
check(0x1d3efb60, [0x56,0x57,0x48,0x83,0xec,0x28]);
|
||||
let next = 1, done = false;
|
||||
const readLevel = new NativeFunction(module.base.add(0x1e3a7880), 'pointer', ['uint32', 'pointer']);
|
||||
const serialize = new NativeFunction(module.base.add(0x1d3efb60), 'pointer', ['pointer', 'pointer']);
|
||||
const hook = Interceptor.attach(module.base.add(0xdb5f860), {
|
||||
onLeave() {
|
||||
if (done) return;
|
||||
try {
|
||||
if (next === 1) send({kind:'TABLE_STATE', initiallyLoaded:module.base.add(0x9869370).readU8() === 1});
|
||||
for (let n = 0; n < 2 && next <= plan.maxLevel; n++) {
|
||||
const level = next++;
|
||||
const row = readLevel(level, ptr(0));
|
||||
if (row.isNull()) throw new Error('Native player level row is missing: ' + level);
|
||||
const record = {
|
||||
PlayerLevel: row.add(0x2c).readU32(), LevelUpExp: row.add(0x20).readU32(),
|
||||
Rarity1Weight: row.add(0x1c).readU32(), Rarity2Weight: row.add(0x28).readU32(),
|
||||
Rarity3Weight: row.add(0x18).readU32(), Rarity4Weight: row.add(0x30).readU32(),
|
||||
Rarity5Weight: row.add(0x24).readU32(), AvatarMaxNumber: row.add(0x34).readU32()
|
||||
};
|
||||
if (record.PlayerLevel !== level) throw new Error('Row layout/identity mismatch at level ' + level);
|
||||
const encoded = serialize(row, ptr(0));
|
||||
if (encoded.isNull()) throw new Error('Native serializer returned null');
|
||||
const length = encoded.add(0x10).readS32();
|
||||
if (length < 2 || length > 65536) throw new Error('Serialized level row exceeds capture bound');
|
||||
const json = encoded.add(0x14).readUtf16String(length);
|
||||
const parsed = JSON.parse(json);
|
||||
for (const key of Object.keys(record)) {
|
||||
if (parsed[key] !== record[key]) throw new Error('Serialized row disagrees with scalar layout: '+key);
|
||||
}
|
||||
send({kind:'ROW', json, thread:Process.getCurrentThreadId()});
|
||||
}
|
||||
if (next > plan.maxLevel) { done = true; send({kind:'END', count:plan.maxLevel}); }
|
||||
} catch (e) { done = true; send({kind:'ERROR', error:String(e)}); }
|
||||
}
|
||||
});
|
||||
send({kind:'BEGIN', count:plan.maxLevel, scope:'native player-level full rows serialized on managed caller thread'});
|
||||
@@ -0,0 +1,81 @@
|
||||
"""Locate named Client method token checks in a supplied PE (read only).
|
||||
|
||||
The correlation was observed for GridFightModule.GetSeason and _SyncSeason in
|
||||
this Client: the native check loads the low 24 bits of MetadataToken into ECX
|
||||
before a direct call. Report candidate sites; do not infer function boundaries
|
||||
or claim that every candidate is a method implementation.
|
||||
"""
|
||||
import argparse
|
||||
import hashlib
|
||||
import json
|
||||
import pathlib
|
||||
import re
|
||||
import struct
|
||||
|
||||
|
||||
def executable_sections(data):
|
||||
if data[:2] != b"MZ":
|
||||
raise ValueError("Expected a PE image")
|
||||
pe = struct.unpack_from("<I", data, 0x3c)[0]
|
||||
if data[pe:pe + 4] != b"PE\0\0":
|
||||
raise ValueError("Invalid PE signature")
|
||||
count = struct.unpack_from("<H", data, pe + 6)[0]
|
||||
optional_size = struct.unpack_from("<H", data, pe + 20)[0]
|
||||
sections = []
|
||||
for index in range(count):
|
||||
offset = pe + 24 + optional_size + index * 40
|
||||
virtual_size, rva, raw_size, raw = struct.unpack_from("<IIII", data, offset + 8)
|
||||
characteristics = struct.unpack_from("<I", data, offset + 36)[0]
|
||||
if characteristics & 0x20000000: # IMAGE_SCN_MEM_EXECUTE in the PE schema.
|
||||
if raw + raw_size > len(data):
|
||||
raise ValueError("Truncated executable section")
|
||||
sections.append((rva, data[raw:raw + raw_size]))
|
||||
return sections
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument("--assembly", type=pathlib.Path, required=True)
|
||||
parser.add_argument("--tokens", type=pathlib.Path, required=True)
|
||||
parser.add_argument("--output", type=pathlib.Path, required=True)
|
||||
args = parser.parse_args()
|
||||
data = args.assembly.read_bytes()
|
||||
sections = executable_sections(data)
|
||||
methods, by_check = {}, {}
|
||||
for line in args.tokens.read_text(encoding="utf-8-sig").splitlines():
|
||||
match = re.search(r"\[GAC_CW_METHOD_TOKEN\] METHOD (\S+) (\S+) (\d+)$", line)
|
||||
if not match:
|
||||
continue
|
||||
token = int(match[3])
|
||||
name = match[1] + "." + match[2] + "#" + hex(token)
|
||||
if token & 0xff000000 != 0x06000000: # ECMA-335 MethodDef token table.
|
||||
raise SystemExit("Not a MethodDef token: " + name)
|
||||
methods[name] = {"metadata_token": hex(token), "check_id": hex(token & 0x00ffffff), "candidate_sites": []}
|
||||
by_check.setdefault(token & 0x00ffffff, []).append(name)
|
||||
if not methods:
|
||||
raise SystemExit("No captured method tokens found")
|
||||
# One section pass, rather than rereading a large executable for every
|
||||
# captured method. The byte pattern is deliberately only a candidate.
|
||||
pattern = re.compile(rb"(?=\xb9(.{4})\xe8(.{4}))", re.S)
|
||||
for section_rva, section in sections:
|
||||
for match in pattern.finditer(section):
|
||||
check_id = struct.unpack("<I", match[1])[0]
|
||||
if check_id not in by_check:
|
||||
continue
|
||||
call_rva = section_rva + match.start() + 5
|
||||
target = call_rva + 5 + struct.unpack("<i", match[2])[0]
|
||||
for name in by_check[check_id]:
|
||||
methods[name]["candidate_sites"].append({"check_rva": hex(section_rva + match.start()), "call_target_rva": hex(target)})
|
||||
output = {
|
||||
"assembly_sha256": hashlib.sha256(data).hexdigest(),
|
||||
"token_capture_sha256": hashlib.sha256(args.tokens.read_bytes()).hexdigest(),
|
||||
"limitation": "Candidate token-check sites only; no inferred function start or gameplay semantics",
|
||||
"methods": methods,
|
||||
}
|
||||
args.output.parent.mkdir(parents=True, exist_ok=True)
|
||||
args.output.write_text(json.dumps(output, indent=2) + "\n", encoding="utf-8")
|
||||
print(f"{len(methods)} named methods; {sum(bool(v['candidate_sites']) for v in methods.values())} with candidate native sites")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,33 @@
|
||||
-- Read only named CW stage/node metadata, one object per heartbeat.
|
||||
do
|
||||
local state=_G.__gacCwNodeBattleSchema1 or {index=1};_G.__gacCwNodeBattleSchema1=state
|
||||
if state.done then return end
|
||||
local log=function(v)CS.UnityEngine.Debug.Log('[GAC_CW_NODE_BATTLE] '..tostring(v))end
|
||||
local ok,err=pcall(function()
|
||||
local flags=CS.System.Enum.ToObject(typeof(CS.System.Reflection.BindingFlags),60)
|
||||
local session=CS.RPG.Client.GlobalVars.s_ModuleManager.GridFightModule.CurGameSession
|
||||
if not session then return end
|
||||
if not state.objects then
|
||||
local fields=session:GetType():GetFields(flags)
|
||||
for i=0,math.min(fields.Length-1,63)do
|
||||
local f=fields[i]
|
||||
if f.FieldType.FullName=='RPG.Client.GridFightStage'then
|
||||
local stage=f:GetValue(session)
|
||||
if stage and stage.CurNode then state.objects={stage,stage.CurNode}end
|
||||
end
|
||||
end
|
||||
if not state.objects then return end
|
||||
end
|
||||
local value=state.objects[state.index];if not value then log('END');state.done=true;return end
|
||||
state.index=state.index+1
|
||||
local t=value:GetType();log('TYPE '..t.FullName)
|
||||
local fs=t:GetFields(flags)
|
||||
for i=0,math.min(fs.Length-1,47)do log('FIELD '..tostring(fs[i]))end
|
||||
local ps=t:GetProperties(flags)
|
||||
for i=0,math.min(ps.Length-1,47)do log('PROPERTY '..tostring(ps[i]))end
|
||||
local ms=t:GetMethods(flags)
|
||||
for i=0,math.min(ms.Length-1,95)do if ms[i].DeclaringType==t then log('METHOD '..tostring(ms[i]))end end
|
||||
if state.index==3 then log('END');state.done=true end
|
||||
end)
|
||||
if not ok then log('ERROR '..tostring(err));state.done=true end
|
||||
end
|
||||
@@ -0,0 +1,34 @@
|
||||
-- Read only named CW stage/node metadata, one object per heartbeat.
|
||||
do
|
||||
local state=_G.__gacCwNodeBattleSchema3 or {index=1};_G.__gacCwNodeBattleSchema3=state
|
||||
if state.done then return end
|
||||
local log=function(v)CS.UnityEngine.Debug.Log('[GAC_CW_ENEMY_DETAIL] '..tostring(v))end
|
||||
local ok,err=pcall(function()
|
||||
local flags=CS.System.Enum.ToObject(typeof(CS.System.Reflection.BindingFlags),60)
|
||||
local session=CS.RPG.Client.GlobalVars.s_ModuleManager.GridFightModule.CurGameSession
|
||||
if not session then return end
|
||||
if not state.objects then
|
||||
local fields=session:GetType():GetFields(flags)
|
||||
for i=0,math.min(fields.Length-1,63)do
|
||||
local f=fields[i]
|
||||
if f.FieldType.FullName=='RPG.Client.GridFightStage'then
|
||||
local stage=f:GetValue(session)
|
||||
if stage and stage.CurNode then state.objects={stage.CurMonsterStageData};log('COORD '..stage.RouteID..'/'..stage.ChapterID..'/'..stage.SectionID..' LEVEL '..stage.CurMonsterLevel);local row=stage.CurNode:GetType():GetProperty('_PenaltyRuleConfigRow',flags):GetValue(stage.CurNode,nil);if row then log('PENALTY_JSON '..CS.Newtonsoft.Json.JsonConvert.SerializeObject(row))end end
|
||||
end
|
||||
end
|
||||
if not state.objects then return end
|
||||
end
|
||||
local value=state.objects[state.index];if not value then log('END');state.done=true;return end
|
||||
state.index=state.index+1
|
||||
local t=value:GetType().BaseType;log('TYPE '..t.FullName)
|
||||
local fs=t:GetFields(flags)
|
||||
for i=0,math.min(fs.Length-1,47)do log('FIELD '..tostring(fs[i]))end
|
||||
local ps=t:GetProperties(flags)
|
||||
for i=0,math.min(ps.Length-1,47)do log('PROPERTY '..tostring(ps[i]))end
|
||||
local ms=t:GetMethods(flags)
|
||||
for i=0,math.min(ms.Length-1,95)do if ms[i].DeclaringType==t then log('METHOD '..tostring(ms[i]))end end
|
||||
if state.index==2 then log('END');state.done=true end
|
||||
end)
|
||||
if not ok then log('ERROR '..tostring(err));state.done=true end
|
||||
end
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
-- Read only named CW stage/node metadata, one object per heartbeat.
|
||||
do
|
||||
local state=_G.__gacCwNodeBattleSchema2 or {index=1};_G.__gacCwNodeBattleSchema2=state
|
||||
if state.done then return end
|
||||
local log=function(v)CS.UnityEngine.Debug.Log('[GAC_CW_NODE_ENEMY] '..tostring(v))end
|
||||
local ok,err=pcall(function()
|
||||
local flags=CS.System.Enum.ToObject(typeof(CS.System.Reflection.BindingFlags),60)
|
||||
local session=CS.RPG.Client.GlobalVars.s_ModuleManager.GridFightModule.CurGameSession
|
||||
if not session then return end
|
||||
if not state.objects then
|
||||
local fields=session:GetType():GetFields(flags)
|
||||
for i=0,math.min(fields.Length-1,63)do
|
||||
local f=fields[i]
|
||||
if f.FieldType.FullName=='RPG.Client.GridFightStage'then
|
||||
local stage=f:GetValue(session)
|
||||
if stage and stage.CurNode then state.objects={stage.CurMonsterStageData};log('COORD '..stage.RouteID..'/'..stage.ChapterID..'/'..stage.SectionID..' LEVEL '..stage.CurMonsterLevel);local row=stage.CurNode:GetType():GetProperty('_PenaltyRuleConfigRow',flags):GetValue(stage.CurNode,nil);if row then log('PENALTY_JSON '..CS.Newtonsoft.Json.JsonConvert.SerializeObject(row))end end
|
||||
end
|
||||
end
|
||||
if not state.objects then return end
|
||||
end
|
||||
local value=state.objects[state.index];if not value then log('END');state.done=true;return end
|
||||
state.index=state.index+1
|
||||
local t=value:GetType();log('TYPE '..t.FullName)
|
||||
local fs=t:GetFields(flags)
|
||||
for i=0,math.min(fs.Length-1,47)do log('FIELD '..tostring(fs[i]))end
|
||||
local ps=t:GetProperties(flags)
|
||||
for i=0,math.min(ps.Length-1,47)do log('PROPERTY '..tostring(ps[i]))end
|
||||
local ms=t:GetMethods(flags)
|
||||
for i=0,math.min(ms.Length-1,95)do if ms[i].DeclaringType==t then log('METHOD '..tostring(ms[i]))end end
|
||||
if state.index==2 then log('END');state.done=true end
|
||||
end)
|
||||
if not ok then log('ERROR '..tostring(err));state.done=true end
|
||||
end
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
-- One named enum, bounded plain metadata. No scene/gameplay changes.
|
||||
do
|
||||
if not _G.__gacCwNodeEnum1 then
|
||||
_G.__gacCwNodeEnum1=true
|
||||
local log=function(v)CS.UnityEngine.Debug.Log('[GAC_CW_NODE_ENUM] '..tostring(v))end
|
||||
local good,err=pcall(function()
|
||||
local t=typeof(CS.RPG.GameCore.GridFightNodeType)
|
||||
local names=CS.System.Enum.GetNames(t)
|
||||
if names.Length>128 then error('Enum exceeds capture bound')end
|
||||
log('BEGIN count='..names.Length)
|
||||
for i=0,names.Length-1 do log('ROW {"name":"'..names[i]..'","value":'..CS.System.Convert.ToInt32(CS.System.Enum.Parse(t,names[i]))..'}')end
|
||||
log('END')
|
||||
end)
|
||||
if not good then log('ERROR '..tostring(err))end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,33 @@
|
||||
-- Getters on four named CW types only; sixteen metadata entries per heartbeat.
|
||||
-- No getter invocation, object construction, or gameplay mutation.
|
||||
do
|
||||
local names={'OHMDHKGAEMM','BCCIJHPLJOJ','RPG.Client.GridFightStageNode','NIHNGPKHEPC'}
|
||||
_G.__gacCwNodeHandles1=_G.__gacCwNodeHandles1 or {type=1,offset=0}
|
||||
local s=_G.__gacCwNodeHandles1
|
||||
if s.type>#names then return end
|
||||
local flags=CS.System.Enum.ToObject(typeof(CS.System.Reflection.BindingFlags),60)
|
||||
local manager=CS.RPG.Client.GlobalVars.s_GamePhaseManager
|
||||
local phase=manager and typeof(CS.RPG.Client.GamePhaseManager):GetField('_CurrentPhase',flags):GetValue(manager)
|
||||
if not phase or typeof(CS.RPG.Client.BattleGamePhase):IsInstanceOfType(phase)then return end
|
||||
local log=function(v)CS.UnityEngine.Debug.Log('[GAC_CW_PROPERTY_HANDLE] '..tostring(v))end
|
||||
local good,err=pcall(function()
|
||||
if not s.properties then
|
||||
local a=typeof(CS.RPG.Client.GridFightModule).Assembly
|
||||
local t=a:GetType(names[s.type])
|
||||
if not t then t=typeof(CS[names[s.type]])end
|
||||
s.properties=t:GetProperties(flags)
|
||||
end
|
||||
for i=s.offset,math.min(s.offset+15,s.properties.Length-1)do
|
||||
local p=s.properties[i]
|
||||
local getter=p:GetGetMethod(true)
|
||||
if getter and not getter.IsStatic and p:GetIndexParameters().Length==0 and
|
||||
(p.PropertyType.IsPrimitive or p.PropertyType.IsEnum)then
|
||||
log('GETTER '..names[s.type]..' '..p.Name..' '..tostring(getter.MethodHandle.Value)..' '..p.PropertyType.FullName)
|
||||
end
|
||||
end
|
||||
s.offset=s.offset+16
|
||||
if s.offset>=s.properties.Length then s.properties=nil;s.offset=0;s.type=s.type+1 end
|
||||
end)
|
||||
if not good then log('ERROR '..tostring(err));s.properties=nil;s.offset=0;s.type=s.type+1 end
|
||||
if s.type>#names then log('END')end
|
||||
end
|
||||
@@ -0,0 +1,17 @@
|
||||
-- Named stage-node metadata only; no node instances or game sessions created.
|
||||
do
|
||||
if not _G.__gacCwNodeSchema1 then
|
||||
_G.__gacCwNodeSchema1=true
|
||||
local function log(v)CS.UnityEngine.Debug.Log('[GAC_CW_NODE_SCHEMA] '..tostring(v))end
|
||||
local flags=CS.System.Enum.ToObject(typeof(CS.System.Reflection.BindingFlags),60)
|
||||
local t=typeof(CS.RPG.Client.GridFightStageNode)
|
||||
local fields=t:GetFields(flags)
|
||||
for i=0,fields.Length-1 do log('FIELD '..tostring(fields[i]))end
|
||||
local ps=t:GetProperties(flags)
|
||||
for i=0,ps.Length-1 do log('PROPERTY '..tostring(ps[i]))end
|
||||
local methods=t:GetMethods(flags)
|
||||
for i=0,math.min(methods.Length-1,63)do
|
||||
if methods[i].DeclaringType==t then log('METHOD '..tostring(methods[i]))end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,31 @@
|
||||
-- Named Spotlight config and active session metadata, no actions/loaders.
|
||||
do
|
||||
local s=_G.__gacCwSpotlightSchema3 or {index=1};_G.__gacCwSpotlightSchema3=s
|
||||
if s.done then return end
|
||||
local log=function(v)CS.UnityEngine.Debug.Log('[GAC_CW_PENDING_TRACK_SCHEMA] '..tostring(v))end
|
||||
local ok,err=pcall(function()
|
||||
local flags=CS.System.Enum.ToObject(typeof(CS.System.Reflection.BindingFlags),60)
|
||||
local manager=CS.RPG.Client.GlobalVars.s_GamePhaseManager
|
||||
local phase=manager and typeof(CS.RPG.Client.GamePhaseManager):GetField('_CurrentPhase',flags):GetValue(manager)
|
||||
if not phase or typeof(CS.RPG.Client.BattleGamePhase):IsInstanceOfType(phase)then return end
|
||||
local module=CS.RPG.Client.GlobalVars.s_ModuleManager.GridFightModule
|
||||
if not s.objects then
|
||||
local session=module.CurGameSession;if not session then return end;local families=module:GetHandBookAllRoleConfig();s.objects={session.Track.EquipTrackData,families[0].DefaultRole};s.extra=typeof(CS.RPG.Client.GridFightSpotLightSelectAction)
|
||||
end
|
||||
local object=s.objects[s.index];if not object and s.index~=3 then s.done=true;log('END');return end
|
||||
s.index=s.index+1
|
||||
local t=object and object:GetType() or s.extra;log('TYPE '..t.FullName)
|
||||
local fs=t:GetFields(flags)
|
||||
for i=0,math.min(fs.Length-1,63)do
|
||||
log('FIELD '..tostring(fs[i]))
|
||||
if false and tostring(fs[i].FieldType.FullName):find('Row$')then
|
||||
local row=fs[i]:GetValue(object);if row then log('ROW '..CS.Newtonsoft.Json.JsonConvert.SerializeObject(row))end
|
||||
end
|
||||
end
|
||||
local ps=t:GetProperties(flags);for i=0,math.min(ps.Length-1,63)do log('PROPERTY '..tostring(ps[i]))end
|
||||
local ms=t:GetMethods(flags)
|
||||
for i=0,math.min(ms.Length-1,127)do if ms[i].DeclaringType==t then log('METHOD '..tostring(ms[i]))end end
|
||||
if s.index==4 then s.done=true;log('END')end
|
||||
end)
|
||||
if not ok then log('ERROR '..tostring(err));s.done=true end
|
||||
end
|
||||
@@ -0,0 +1,15 @@
|
||||
-- Field declaration metadata for the one CW player protobuf type.
|
||||
-- No instances are read or modified.
|
||||
do
|
||||
if not _G.__gacCwPlayerProtoFields1 then
|
||||
_G.__gacCwPlayerProtoFields1=true
|
||||
local log=function(v)CS.UnityEngine.Debug.Log('[GAC_CW_PLAYER_FIELDS] '..tostring(v))end
|
||||
local t=typeof(CS.NIHNGPKHEPC)
|
||||
local flags=CS.System.Enum.ToObject(typeof(CS.System.Reflection.BindingFlags),60)
|
||||
local fs=t:GetFields(flags)
|
||||
for i=0,math.min(fs.Length-1,95)do
|
||||
if not fs[i].IsStatic then log('FIELD '..i..' '..fs[i].Name..' '..fs[i].FieldType.FullName)end
|
||||
end
|
||||
log('END')
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,15 @@
|
||||
-- Bounded metadata for the currently selected CW portal data only.
|
||||
do
|
||||
if _G.__gacCwPortalSchema1 then return end
|
||||
_G.__gacCwPortalSchema1=true
|
||||
local log=function(s)CS.UnityEngine.Debug.Log('[GAC_CW_PORTAL_SCHEMA] '..tostring(s))end
|
||||
local ok,err=pcall(function()
|
||||
local flags=CS.System.Enum.ToObject(typeof(CS.System.Reflection.BindingFlags),60)
|
||||
local t=typeof(CS.RPG.Client.GridFightPortalData)
|
||||
local fs=t:GetFields(flags)
|
||||
for i=0,math.min(fs.Length-1,31)do log('FIELD '..tostring(fs[i]))end
|
||||
local ps=t:GetProperties(flags)
|
||||
for i=0,math.min(ps.Length-1,31)do log('PROPERTY '..tostring(ps[i]))end
|
||||
end)
|
||||
if not ok then log('ERROR '..tostring(err))end
|
||||
end
|
||||
@@ -0,0 +1,14 @@
|
||||
-- Explicit CW portal table names only, one metadata target per heartbeat.
|
||||
do
|
||||
_G.__gacCwPortalTable1=_G.__gacCwPortalTable1 or 1
|
||||
local names={'GridFightPortalBuffExcelTable','GridFightPortalBuffConfigExcelTable','GridFightPortalBuffRow','GridFightPortalBuffConfigRow'}
|
||||
local i=_G.__gacCwPortalTable1;if i>#names then return end;_G.__gacCwPortalTable1=i+1
|
||||
local log=function(s)CS.UnityEngine.Debug.Log('[GAC_CW_PORTAL_TABLE] '..tostring(s))end
|
||||
local ok,err=pcall(function()
|
||||
local flags=CS.System.Enum.ToObject(typeof(CS.System.Reflection.BindingFlags),60)
|
||||
local a=typeof(CS.RPG.GameCore.GridFightRoleConfigRow).Assembly
|
||||
local t=a:GetType('RPG.GameCore.'..names[i]);log('TYPE '..names[i]..' '..tostring(t));if not t then return end
|
||||
local ms=t:GetMethods(flags);for j=0,math.min(ms.Length-1,31)do if ms[j].DeclaringType==t then log('METHOD '..tostring(ms[j]))end end
|
||||
end)
|
||||
if not ok then log('ERROR '..tostring(err))end
|
||||
end
|
||||
@@ -0,0 +1,25 @@
|
||||
-- Read existing portal wrappers; one row per heartbeat, no gameplay mutations.
|
||||
do
|
||||
_G.__gacCwPortalsExport1=_G.__gacCwPortalsExport1 or {index=0}
|
||||
local s=_G.__gacCwPortalsExport1;if s.done then return end
|
||||
local log=function(v)CS.UnityEngine.Debug.Log('[GAC_CW_PORTALS] '..tostring(v))end
|
||||
local ok,err=pcall(function()
|
||||
local flags=CS.System.Enum.ToObject(typeof(CS.System.Reflection.BindingFlags),60)
|
||||
if not s.rows then s.rows=CS.RPG.Client.GlobalVars.s_ModuleManager.GridFightModule:GetHandBookAllPortalData();if s.rows.Count>1024 then error('portal capture bound exceeded')end;log('BEGIN count='..s.rows.Count)end
|
||||
for batch=1,4 do
|
||||
if s.index>=s.rows.Count then s.done=true;log('END');return end
|
||||
local wrapper=s.rows[s.index];local t=wrapper:GetType();local row=nil
|
||||
for depth=1,4 do
|
||||
if not t then break end
|
||||
local fs=t:GetFields(flags)
|
||||
for j=0,math.min(fs.Length-1,47)do if fs[j].FieldType.FullName=='RPG.GameCore.GridFightPortalBuffConfigRow' then row=fs[j]:GetValue(wrapper);break end end
|
||||
if row then break end;t=t.BaseType
|
||||
end
|
||||
if not row then error('portal wrapper row unavailable')end
|
||||
local text=CS.Newtonsoft.Json.JsonConvert.SerializeObject(row);if #text>32768 then error('portal row exceeds capture bound')end
|
||||
log('ROW '..text);s.index=s.index+1
|
||||
end
|
||||
end)
|
||||
if not ok then log('ERROR '..tostring(err));s.done=true end
|
||||
end
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
-- Metadata only on the exact provider type declared by the CW module field.
|
||||
-- No preload, graph, HTTP or gameplay method is invoked.
|
||||
do
|
||||
if not _G.__gacCwPreloadMeta2 then
|
||||
_G.__gacCwPreloadMeta2=true
|
||||
local log=function(v)CS.UnityEngine.Debug.Log('[GAC_CW_PRELOAD_META] '..tostring(v))end
|
||||
local flags=CS.System.Enum.ToObject(typeof(CS.System.Reflection.BindingFlags),60)
|
||||
local field=typeof(CS.RPG.Client.GridFightModule):GetField('_SessionPreloadProvider',flags)
|
||||
local module=CS.RPG.Client.GlobalVars.s_ModuleManager.GridFightModule
|
||||
local object=field:GetValue(module)
|
||||
if not object then log('OBJECT nil');return end
|
||||
local t=object:GetType()
|
||||
log('TYPE '..t.FullName)
|
||||
local fs=t:GetFields(flags)
|
||||
for i=0,math.min(fs.Length-1,31)do log('FIELD '..tostring(fs[i]))end
|
||||
local ms=t:GetMethods(flags)
|
||||
for i=0,math.min(ms.Length-1,63)do
|
||||
if ms[i].DeclaringType==t then log('METHOD '..tostring(ms[i]))end
|
||||
end
|
||||
local ps=t:GetProperties(flags)
|
||||
for i=0,math.min(ps.Length-1,31)do log('PROPERTY '..tostring(ps[i]))end
|
||||
log('END')
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,25 @@
|
||||
-- One previously captured method token through reflection, not a type scan.
|
||||
do
|
||||
if not _G.__gacCwResolveToken1 then
|
||||
_G.__gacCwResolveToken1=true
|
||||
local function log(v)CS.UnityEngine.Debug.Log('[GAC_CW_RESOLVE_TOKEN] '..tostring(v))end
|
||||
local ok,err=pcall(function()
|
||||
local owner=typeof(CS.RPG.Client.GridFightModule).Module
|
||||
local flags=CS.System.Enum.ToObject(typeof(CS.System.Reflection.BindingFlags),60)
|
||||
local methods=owner:GetType():GetMethods(flags)
|
||||
local method=nil
|
||||
for i=0,methods.Length-1 do
|
||||
local m=methods[i]
|
||||
if m.Name=='ResolveMethod' and m:GetParameters().Length==1 then method=m;break end
|
||||
end
|
||||
if not method then error('ResolveMethod is absent from Module reflection metadata')end
|
||||
local typed=CS.System.Array.CreateInstance(typeof(CS.System.Int32),1)
|
||||
typed[0]=101276529 -- Captured GridFightModule.GetSeason.
|
||||
local args=CS.System.Array.CreateInstance(typeof(CS.System.Object),1)
|
||||
CS.System.Array.Copy(typed,0,args,0,1)
|
||||
local result=method:Invoke(owner,CS.System.Enum.ToObject(typeof(CS.System.Reflection.BindingFlags),0),nil,args,nil)
|
||||
log('RESULT '..tostring(result))
|
||||
end)
|
||||
if not ok then log('ERROR '..tostring(err))end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,40 @@
|
||||
-- Existing handbook role configs; read four star rows per heartbeat. No role
|
||||
-- creation, Star assignment, gameplay action or scene loader. Pauses in Battle.
|
||||
do
|
||||
local s=_G.__gacCwRoleStars1 or {family=0,variant=0,star=1,count=0};_G.__gacCwRoleStars1=s
|
||||
if s.done then return end
|
||||
local log=function(v)CS.UnityEngine.Debug.Log('[GAC_CW_ROLE_STARS] '..tostring(v))end
|
||||
local ok,err=pcall(function()
|
||||
local flags=CS.System.Enum.ToObject(typeof(CS.System.Reflection.BindingFlags),60)
|
||||
local manager=CS.RPG.Client.GlobalVars.s_GamePhaseManager
|
||||
local phase=manager and typeof(CS.RPG.Client.GamePhaseManager):GetField('_CurrentPhase',flags):GetValue(manager)
|
||||
if not phase or typeof(CS.RPG.Client.BattleGamePhase):IsInstanceOfType(phase)then return end
|
||||
if not s.families then
|
||||
s.families=CS.RPG.Client.GlobalVars.s_ModuleManager.GridFightModule:GetHandBookAllRoleConfig()
|
||||
if s.families.Count>1024 then error('role family bound exceeded')end
|
||||
log('BEGIN families='..s.families.Count)
|
||||
end
|
||||
for batch=1,4 do
|
||||
if s.family>=s.families.Count then s.done=true;log('END count='..s.count);return end
|
||||
local family=s.families[s.family]
|
||||
local role=s.variant==0 and family.DefaultRole or family.OtherRoles[s.variant-1]
|
||||
local config=role.RoleConfig
|
||||
if config.MaxStar>16 then error('role star bound exceeded')end
|
||||
local star=config:GetStarConfig(s.star)
|
||||
if star then
|
||||
local row=star:GetType():GetField('_Row',flags):GetValue(star)
|
||||
local servant=star:GetType():GetField('_ServantStarRow',flags):GetValue(star)
|
||||
local text='{"ID":'..config.ID..',"Star":'..s.star..',"StarConfig":'..CS.Newtonsoft.Json.JsonConvert.SerializeObject(row)..',"ServantStarConfig":'..CS.Newtonsoft.Json.JsonConvert.SerializeObject(servant)..'}'
|
||||
if #text>65536 then error('role star row exceeds bound')end
|
||||
log('ROW '..text);s.count=s.count+1
|
||||
else log('MISSING '..config.ID..' '..s.star)end
|
||||
s.star=s.star+1
|
||||
if s.star>config.MaxStar then
|
||||
s.star=1;s.variant=s.variant+1
|
||||
local otherCount=family.OtherRoles and family.OtherRoles.Count or 0
|
||||
if s.variant>otherCount then s.variant=0;s.family=s.family+1 end
|
||||
end
|
||||
end
|
||||
end)
|
||||
if not ok then log('ERROR '..tostring(err));s.done=true end
|
||||
end
|
||||
@@ -0,0 +1,25 @@
|
||||
-- Read-only native handbook role configs, four rows per heartbeat.
|
||||
do
|
||||
_G.__gacCwRolesExport2=_G.__gacCwRolesExport2 or {index=0}
|
||||
local state=_G.__gacCwRolesExport2
|
||||
if not state.done then
|
||||
local function log(v)CS.UnityEngine.Debug.Log('[GAC_CW_ROLES] '..tostring(v))end
|
||||
local ok,err=pcall(function()
|
||||
local module=CS.RPG.Client.GlobalVars.s_ModuleManager.GridFightModule
|
||||
if not state.rows then
|
||||
state.rows=module:GetHandBookAllRoleConfig()
|
||||
log('BEGIN count='..state.rows.Count)
|
||||
end
|
||||
for i=state.index,math.min(state.index+3,state.rows.Count-1)do
|
||||
local r=state.rows[i]
|
||||
local flags=CS.System.Enum.ToObject(typeof(CS.System.Reflection.BindingFlags),60)
|
||||
local config=r.RoleConfig
|
||||
local row=config:GetType():GetField('_Row',flags):GetValue(config)
|
||||
log('ROW {"Config":'..CS.Newtonsoft.Json.JsonConvert.SerializeObject(row)..',"Price":'..config.Price..',"MaxStar":'..config.MaxStar..',"DefaultStar":'..r.Star..',"DefaultSellPrice":'..r.SellPrice..'}')
|
||||
end
|
||||
state.index=state.index+4
|
||||
if state.index>=state.rows.Count then state.done=true;log('END')end
|
||||
end)
|
||||
if not ok then log('ERROR '..tostring(err));state.done=true end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,24 @@
|
||||
-- Read only metadata on explicitly identified native row types.
|
||||
-- One type per heartbeat, capped at 48 members per category.
|
||||
do
|
||||
local names={'GridFightRoleConfigRow','GridFightPlayerLevelConfigRow','GridFightSeasonModuleConfigRow','GridFightStageNodeDisplayConfigRow'}
|
||||
_G.__gacCwRowAccessors1=_G.__gacCwRowAccessors1 or 1
|
||||
local index=_G.__gacCwRowAccessors1
|
||||
if index<=#names then
|
||||
_G.__gacCwRowAccessors1=index+1
|
||||
local log=function(v)CS.UnityEngine.Debug.Log('[GAC_CW_ROW_ACCESSORS] '..tostring(v))end
|
||||
local flags=CS.System.Enum.ToObject(typeof(CS.System.Reflection.BindingFlags),60)
|
||||
local assembly=typeof(CS.RPG.GameCore.GridFightRoleConfigRow).Assembly
|
||||
local t=assembly:GetType('RPG.GameCore.'..names[index])
|
||||
log('TYPE '..names[index]..' '..tostring(t))
|
||||
if t then
|
||||
local fields=t:GetFields(flags)
|
||||
for i=0,math.min(fields.Length-1,47)do log('FIELD '..tostring(fields[i]))end
|
||||
local methods=t:GetMethods(flags)
|
||||
for i=0,math.min(methods.Length-1,47)do
|
||||
if methods[i].DeclaringType==t then log('METHOD '..tostring(methods[i]))end
|
||||
end
|
||||
end
|
||||
if index==#names then log('END')end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,18 @@
|
||||
-- Named row metadata attributes only; constructors are not executed.
|
||||
do
|
||||
local names={'GridFightPlayerLevelConfigRow','GridFightTutorialStageConfigRow'}
|
||||
_G.__gacCwRowAttributes1=_G.__gacCwRowAttributes1 or 1
|
||||
local i=_G.__gacCwRowAttributes1
|
||||
if i<=#names then
|
||||
_G.__gacCwRowAttributes1=i+1
|
||||
local log=function(v)CS.UnityEngine.Debug.Log('[GAC_CW_ROW_ATTRIBUTES] '..tostring(v))end
|
||||
local ok,err=pcall(function()
|
||||
local t=typeof(CS.RPG.GameCore[names[i]])
|
||||
log('TYPE '..t.FullName..' BASE '..tostring(t.BaseType)..' DECLARING '..tostring(t.DeclaringType))
|
||||
local attrs=t:GetCustomAttributesData()
|
||||
for j=0,math.min(attrs.Count-1,15)do log('ATTRIBUTE '..tostring(attrs[j]))end
|
||||
end)
|
||||
if not ok then log('ERROR '..tostring(err))end
|
||||
if i==#names then log('END')end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,25 @@
|
||||
-- Metadata only, one explicitly named CW configuration type per heartbeat.
|
||||
do
|
||||
local names={'RPG.Client.GridFightRoleStarConfig','RPG.Client.GridFightMonsterBattleStageData','RPG.Client.GridFightMonsterStageData','RPG.Client.GridFightGamePlayResConfig','RPG.GameCore.GridFightStageNodeTemplateConfigRow','RPG.GameCore.GridFightStageNodeConfigRow'}
|
||||
_G.__gacCwRunConfigSchema1=_G.__gacCwRunConfigSchema1 or 1
|
||||
local index=_G.__gacCwRunConfigSchema1
|
||||
if index<=#names then
|
||||
_G.__gacCwRunConfigSchema1=index+1
|
||||
local log=function(v)CS.UnityEngine.Debug.Log('[GAC_CW_RUN_CONFIG_SCHEMA] '..tostring(v))end
|
||||
local flags=CS.System.Enum.ToObject(typeof(CS.System.Reflection.BindingFlags),60)
|
||||
local assemblies={typeof(CS.RPG.Client.GridFightModule).Assembly,typeof(CS.RPG.GameCore.GridFightRoleConfigRow).Assembly}
|
||||
local t=assemblies[1]:GetType(names[index]) or assemblies[2]:GetType(names[index])
|
||||
log('TYPE '..names[index]..' '..tostring(t))
|
||||
if t then
|
||||
local fs=t:GetFields(flags)
|
||||
for i=0,math.min(fs.Length-1,47)do log('FIELD '..tostring(fs[i]))end
|
||||
local ps=t:GetProperties(flags)
|
||||
for i=0,math.min(ps.Length-1,47)do log('PROPERTY '..tostring(ps[i]))end
|
||||
local ms=t:GetMethods(flags)
|
||||
for i=0,math.min(ms.Length-1,47)do
|
||||
if ms[i].DeclaringType==t then log('METHOD '..tostring(ms[i]))end
|
||||
end
|
||||
end
|
||||
if index==#names then log('END')end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,32 @@
|
||||
-- Named runtime method handles only; one method per heartbeat, no invocation.
|
||||
do
|
||||
local targets={
|
||||
{'RPG.Client.GridFightModule','_StartTutorialLevel'},
|
||||
{'RPG.Client.GridFightStageNode','_RefreshCachedFields'},
|
||||
{'RPG.Client.GridFightStageNode','UpdateRouteNode'},
|
||||
{'RPG.Client.GridFightGameSession','Sync'},
|
||||
{'RPG.GameCore.GameCoreConfigLoader','LoadJsonConfig'},
|
||||
{'RPG.GameCore.GameCoreConfigLoader','LoadGridFightStageTemplateConfig'}
|
||||
}
|
||||
_G.__gacCwRunHandles1=_G.__gacCwRunHandles1 or 1
|
||||
local index=_G.__gacCwRunHandles1
|
||||
if index>#targets then return end
|
||||
local flags=CS.System.Enum.ToObject(typeof(CS.System.Reflection.BindingFlags),60)
|
||||
local manager=CS.RPG.Client.GlobalVars.s_GamePhaseManager
|
||||
local phase=manager and typeof(CS.RPG.Client.GamePhaseManager):GetField('_CurrentPhase',flags):GetValue(manager)
|
||||
if not phase or typeof(CS.RPG.Client.BattleGamePhase):IsInstanceOfType(phase)then return end
|
||||
_G.__gacCwRunHandles1=index+1
|
||||
local log=function(v)CS.UnityEngine.Debug.Log('[GAC_CW_RUN_HANDLE] '..tostring(v))end
|
||||
local good,result=pcall(function()
|
||||
local name,method=targets[index][1],targets[index][2]
|
||||
local a=typeof(CS.RPG.Client.GridFightModule).Assembly
|
||||
local b=typeof(CS.RPG.GameCore.GridFightRoleConfigRow).Assembly
|
||||
local t=a:GetType(name) or b:GetType(name)
|
||||
if not t then return name..' TYPE_MISSING' end
|
||||
local m=t:GetMethod(method,flags)
|
||||
if not m then return name..' '..method..' METHOD_MISSING' end
|
||||
return name..' '..method..' '..tostring(m.MethodHandle.Value)..' signature='..tostring(m)
|
||||
end)
|
||||
log(tostring(good)..' '..tostring(result))
|
||||
if index==#targets then log('END')end
|
||||
end
|
||||
@@ -0,0 +1,31 @@
|
||||
-- Named Spotlight config and active session metadata, no actions/loaders.
|
||||
do
|
||||
local s=_G.__gacCwSpotlightSchema2 or {index=1};_G.__gacCwSpotlightSchema2=s
|
||||
if s.done then return end
|
||||
local log=function(v)CS.UnityEngine.Debug.Log('[GAC_CW_RUNTIME_SCHEMA] '..tostring(v))end
|
||||
local ok,err=pcall(function()
|
||||
local flags=CS.System.Enum.ToObject(typeof(CS.System.Reflection.BindingFlags),60)
|
||||
local manager=CS.RPG.Client.GlobalVars.s_GamePhaseManager
|
||||
local phase=manager and typeof(CS.RPG.Client.GamePhaseManager):GetField('_CurrentPhase',flags):GetValue(manager)
|
||||
if not phase or typeof(CS.RPG.Client.BattleGamePhase):IsInstanceOfType(phase)then return end
|
||||
local module=CS.RPG.Client.GlobalVars.s_ModuleManager.GridFightModule
|
||||
if not s.objects then
|
||||
local session=module.CurGameSession;if not session then return end;local families=module:GetHandBookAllRoleConfig();local role=families[0].DefaultRole;s.objects={session.SpotLight,session.Track,role.RoleConfig,role.StarConfig}
|
||||
end
|
||||
local object=s.objects[s.index];if not object then s.done=true;log('END');return end
|
||||
s.index=s.index+1
|
||||
local t=object:GetType();log('TYPE '..t.FullName)
|
||||
local fs=t:GetFields(flags)
|
||||
for i=0,math.min(fs.Length-1,63)do
|
||||
log('FIELD '..tostring(fs[i]))
|
||||
if false and tostring(fs[i].FieldType.FullName):find('Row$')then
|
||||
local row=fs[i]:GetValue(object);if row then log('ROW '..CS.Newtonsoft.Json.JsonConvert.SerializeObject(row))end
|
||||
end
|
||||
end
|
||||
local ps=t:GetProperties(flags);for i=0,math.min(ps.Length-1,63)do log('PROPERTY '..tostring(ps[i]))end
|
||||
local ms=t:GetMethods(flags)
|
||||
for i=0,math.min(ms.Length-1,127)do if ms[i].DeclaringType==t then log('METHOD '..tostring(ms[i]))end end
|
||||
if s.index==5 then s.done=true;log('END')end
|
||||
end)
|
||||
if not ok then log('ERROR '..tostring(err));s.done=true end
|
||||
end
|
||||
@@ -0,0 +1,17 @@
|
||||
-- Inspect the enum used by a captured CW room condition; no value changes.
|
||||
do
|
||||
if not _G.__gacCwSavedCondition1 then
|
||||
_G.__gacCwSavedCondition1=true
|
||||
local function log(v)CS.UnityEngine.Debug.Log('[GAC_CW_SAVED_CONDITION] '..tostring(v))end
|
||||
local ok,err=pcall(function()
|
||||
local r=CS.RPG.GameCore.GameCoreConfigLoader.LoadRtLevelGroupInfo(__GROUP_PATH__)
|
||||
local condition=r.SavedValueCondition.Conditions[0]
|
||||
local flags=CS.System.Enum.ToObject(typeof(CS.System.Reflection.BindingFlags),60)
|
||||
local t=condition:GetType():GetField('Operation',flags).FieldType
|
||||
log('TYPE '..tostring(t))
|
||||
local names=CS.System.Enum.GetNames(t)
|
||||
for i=0,names.Length-1 do log('ENUM '..names[i]..' '..CS.System.Convert.ToInt32(CS.System.Enum.Parse(t,names[i])))end
|
||||
end)
|
||||
if not ok then log('ERROR '..tostring(err))end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,50 @@
|
||||
-- Encode isolated protobuf objects to map obfuscated backing fields to tags.
|
||||
-- No objects are synced into a game module or sent as network responses.
|
||||
do
|
||||
local names={'AMEEHIIPMFP','CKPOBLIFMGN','MPIMAEMCEFH'}
|
||||
_G.__gacCwScalarWire3=_G.__gacCwScalarWire3 or {index=1,field=0}
|
||||
local state=_G.__gacCwScalarWire3
|
||||
if state.index<=#names then
|
||||
local function log(v)CS.UnityEngine.Debug.Log('[GAC_CW_SCALAR_WIRE] '..tostring(v))end
|
||||
local ok,err=pcall(function()
|
||||
local flags=CS.System.Enum.ToObject(typeof(CS.System.Reflection.BindingFlags),60)
|
||||
local t=typeof(CS[names[state.index]])
|
||||
local fields=t:GetFields(flags)
|
||||
local count=0
|
||||
for i=state.field,fields.Length-1 do
|
||||
state.field=i+1
|
||||
local f=fields[i]
|
||||
if not f.IsStatic and f.FieldType==typeof(CS.System.UInt32) then
|
||||
local obj=CS.System.Activator.CreateInstance(t)
|
||||
local typed=CS.System.Array.CreateInstance(typeof(CS.System.UInt32),1);typed[0]=1
|
||||
local boxed=CS.System.Array.CreateInstance(typeof(CS.System.Object),2);boxed[0]=obj
|
||||
CS.System.Array.Copy(typed,0,boxed,1,1)
|
||||
local setters=f:GetType():GetMethods(flags)
|
||||
local setter=nil
|
||||
for j=0,setters.Length-1 do
|
||||
if setters[j].Name=='SetValue' and setters[j]:GetParameters().Length==2 then setter=setters[j];break end
|
||||
end
|
||||
if not setter then error('FieldInfo.SetValue overload missing')end
|
||||
local invoke=CS.System.Enum.ToObject(typeof(CS.System.Reflection.BindingFlags),0)
|
||||
setter:Invoke(f,invoke,nil,boxed,nil)
|
||||
local bytes=CS.Google.Protobuf.MessageExtensions.ToByteArray(obj)
|
||||
log('FIELD '..names[state.index]..' '..f.Name..' '..CS.System.BitConverter.ToString(bytes))
|
||||
local properties=t:GetProperties(flags)
|
||||
local empty=CS.System.Array.CreateInstance(typeof(CS.System.Object),0)
|
||||
for j=0,properties.Length-1 do
|
||||
local p=properties[j]
|
||||
if p.PropertyType==typeof(CS.System.UInt32) then
|
||||
local getter=p:GetGetMethod(true)
|
||||
if getter and not getter.IsStatic and getter:Invoke(obj,invoke,nil,empty,nil)==1 then
|
||||
log('GETTER '..names[state.index]..' '..f.Name..' '..p.Name..' '..getter.MetadataToken)
|
||||
end
|
||||
end
|
||||
end
|
||||
count=count+1;if count>=2 then return end
|
||||
end
|
||||
end
|
||||
log('END '..names[state.index]);state.index=state.index+1;state.field=0
|
||||
end)
|
||||
if not ok then log('ERROR '..tostring(err));state.index=state.index+1;state.field=0 end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,28 @@
|
||||
-- CW-only, read-only reflection, one named type per heartbeat.
|
||||
do
|
||||
local names={'GridFightModule','GridFightPlayerProfile','GridFightDivisionInfo','GridFightSeason','GridFightGameSession','GridFightGameRef','GridFightDivisionConfig','GridFightTutorialStageConfig'}
|
||||
_G.__gacCwSchemaIndex=_G.__gacCwSchemaIndex or 1
|
||||
local index=_G.__gacCwSchemaIndex
|
||||
if index<=#names then
|
||||
_G.__gacCwSchemaIndex=index+1
|
||||
local function log(v)CS.UnityEngine.Debug.Log('[GAC_CW_SCHEMA] '..tostring(v))end
|
||||
local ok,err=pcall(function()
|
||||
local flags=CS.System.Enum.ToObject(typeof(CS.System.Reflection.BindingFlags),60)
|
||||
local ns=CS.RPG.Client
|
||||
local t=typeof(ns[names[index]])
|
||||
log('TYPE '..tostring(t))
|
||||
local fields=t:GetFields(flags)
|
||||
for i=0,fields.Length-1 do log('FIELD '..tostring(fields[i]))end
|
||||
local methods=t:GetMethods(flags)
|
||||
for i=0,methods.Length-1 do
|
||||
local m=methods[i]
|
||||
if m.DeclaringType==t then
|
||||
local n=tostring(m.Name)
|
||||
if names[index]~='GridFightModule' or n:find('Data') or n:find('Sync') or n:find('Season') or n:find('Config') or n:find('GamePlay') then log('METHOD '..tostring(m)) end
|
||||
end
|
||||
end
|
||||
log('END '..names[index])
|
||||
end)
|
||||
if not ok then log('ERROR '..names[index]..' '..tostring(err))end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,33 @@
|
||||
-- Named season/time getters and MonoRemainTimer metadata only.
|
||||
do
|
||||
if not _G.__gacCwSeasonTimer1 then
|
||||
_G.__gacCwSeasonTimer1=true
|
||||
local function log(v)CS.UnityEngine.Debug.Log('[GAC_CW_SEASON_TIMER] '..tostring(v))end
|
||||
local ok,err=pcall(function()
|
||||
local module=CS.RPG.Client.GlobalVars.s_ModuleManager.GridFightModule
|
||||
local season=module:GetSeason(module.SeasonID,module.SubSeasonID)
|
||||
local flags=CS.System.Enum.ToObject(typeof(CS.System.Reflection.BindingFlags),60)
|
||||
local t=season:GetType()
|
||||
local methods=t:GetMethods(flags)
|
||||
for i=0,methods.Length-1 do
|
||||
local m=methods[i]
|
||||
if m.DeclaringType==t then log('METHOD '..tostring(m)..' TOKEN '..m.MetadataToken)end
|
||||
end
|
||||
local ps=t:GetProperties(flags)
|
||||
for i=0,ps.Length-1 do
|
||||
local p=ps[i]
|
||||
log('PROPERTY '..tostring(p))
|
||||
local scalar=tostring(p.PropertyType.FullName)
|
||||
if scalar=='System.Int64' or scalar=='System.UInt32' or scalar=='System.Boolean' or scalar=='System.Double' then
|
||||
local getter=p:GetGetMethod(true)
|
||||
local good,value=pcall(function()return getter:Invoke(season,CS.System.Enum.ToObject(typeof(CS.System.Reflection.BindingFlags),0),nil,CS.System.Array.CreateInstance(typeof(CS.System.Object),0),nil)end)
|
||||
log('VALUE '..p.Name..' '..tostring(good)..' '..tostring(value))
|
||||
end
|
||||
end
|
||||
local timer=typeof(CS.RPG.Client.MonoRemainTimer)
|
||||
local fields=timer:GetFields(flags)
|
||||
for i=0,fields.Length-1 do log('TIMER_FIELD '..tostring(fields[i]))end
|
||||
end)
|
||||
if not ok then log('ERROR '..tostring(err))end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,35 @@
|
||||
-- Read only the active CW player's rules and current node's penalty row.
|
||||
-- No new sessions, scene loaders, game actions or assembly scans.
|
||||
do
|
||||
local state=_G.__gacCwSettlementRules1 or {};_G.__gacCwSettlementRules1=state
|
||||
if state.done then return end
|
||||
local log=function(v)CS.UnityEngine.Debug.Log('[GAC_CW_SETTLEMENT_RULE] '..tostring(v))end
|
||||
local ok,err=pcall(function()
|
||||
local flags=CS.System.Enum.ToObject(typeof(CS.System.Reflection.BindingFlags),60)
|
||||
local session=CS.RPG.Client.GlobalVars.s_ModuleManager.GridFightModule.CurGameSession
|
||||
if not session then return end
|
||||
if not state.initialized then
|
||||
local fields=session:GetType():GetFields(flags)
|
||||
for i=0,math.min(fields.Length-1,63)do
|
||||
local f=fields[i];local name=f.FieldType.FullName
|
||||
if name=='RPG.Client.GridFightPlayer'then
|
||||
local player=f:GetValue(session);if player then state.rules=player:GetVictoryRules();state.index=0;log('VICTORY_COUNT '..state.rules.Count)end
|
||||
elseif name=='RPG.Client.GridFightStage'then
|
||||
local stage=f:GetValue(session);local node=stage and stage.CurNode
|
||||
if node then
|
||||
local row=node:GetType():GetProperty('_PenaltyRuleConfigRow',flags):GetValue(node,nil)
|
||||
if row then log('PENALTY_JSON '..CS.Newtonsoft.Json.JsonConvert.SerializeObject(row))end
|
||||
end
|
||||
end
|
||||
end
|
||||
state.initialized=true
|
||||
end
|
||||
if state.rules then
|
||||
for _=1,2 do
|
||||
if state.index>=state.rules.Count then log('END');state.done=true;return end
|
||||
log('VICTORY_JSON '..CS.Newtonsoft.Json.JsonConvert.SerializeObject(state.rules[state.index]));state.index=state.index+1
|
||||
end
|
||||
else log('NO_PLAYER_RULES');state.done=true end
|
||||
end)
|
||||
if not ok then log('ERROR '..tostring(err));state.done=true end
|
||||
end
|
||||
@@ -0,0 +1,26 @@
|
||||
-- Named settlement-rule metadata only, one target per heartbeat, no loaders.
|
||||
do
|
||||
local flags=CS.System.Enum.ToObject(typeof(CS.System.Reflection.BindingFlags),60)
|
||||
local targets={
|
||||
{'RPG.GameCore.GridFightPenaltyRuleConfigExcelTable',true},
|
||||
{'RPG.GameCore.GridFightPenaltyRuleExcelTable',true},
|
||||
{'RPG.GameCore.GridFightPenaltyRuleConfigRow',true},
|
||||
{'RPG.GameCore.GridFightPenaltyRuleRow',true},
|
||||
{'RPG.Client.GridFightVictoryCountRule',false},
|
||||
{'RPG.Client.GridFightPenaltyRule',false}
|
||||
}
|
||||
_G.__gacCwSettlementSchema1=_G.__gacCwSettlementSchema1 or 1
|
||||
local i=_G.__gacCwSettlementSchema1;if i>#targets then return end;_G.__gacCwSettlementSchema1=i+1
|
||||
local log=function(v)CS.UnityEngine.Debug.Log('[GAC_CW_SETTLEMENT_SCHEMA] '..tostring(v))end
|
||||
local ok,err=pcall(function()
|
||||
local item=targets[i];local assembly=item[2] and typeof(CS.RPG.GameCore.GridFightRoleConfigRow).Assembly or typeof(CS.RPG.Client.GridFightModule).Assembly
|
||||
local t=assembly:GetType(item[1]);log('TYPE '..item[1]..' '..tostring(t));if not t then return end
|
||||
local fs=t:GetFields(flags);for j=0,math.min(fs.Length-1,31)do if i~=6 then log('FIELD '..tostring(fs[j]))end end
|
||||
local ms=t:GetMethods(flags)
|
||||
for j=0,math.min(ms.Length-1,31)do local m=ms[j]
|
||||
if m.DeclaringType==t then log('METHOD '..tostring(m)..' HANDLE '..tostring(m.MethodHandle.Value))end
|
||||
end
|
||||
end)
|
||||
if not ok then log('ERROR '..tostring(err))end
|
||||
if i==#targets then log('END')end
|
||||
end
|
||||
@@ -0,0 +1,40 @@
|
||||
-- Two named shop classes plus primitive protobuf getters; metadata only.
|
||||
do
|
||||
local names={'RPG.Client.GridFightShopGood','RPG.Client.GridFightShopRole','POCJDMMANBM','HDEIAANGMDB','BOPHDCKJMMN'}
|
||||
_G.__gacCwShopGoodMeta1=_G.__gacCwShopGoodMeta1 or 1
|
||||
local index=_G.__gacCwShopGoodMeta1
|
||||
if index>#names then return end
|
||||
local flags=CS.System.Enum.ToObject(typeof(CS.System.Reflection.BindingFlags),60)
|
||||
local manager=CS.RPG.Client.GlobalVars.s_GamePhaseManager
|
||||
local phase=manager and typeof(CS.RPG.Client.GamePhaseManager):GetField('_CurrentPhase',flags):GetValue(manager)
|
||||
if not phase or typeof(CS.RPG.Client.BattleGamePhase):IsInstanceOfType(phase)then return end
|
||||
_G.__gacCwShopGoodMeta1=index+1
|
||||
local log=function(v)CS.UnityEngine.Debug.Log('[GAC_CW_SHOP_GOOD_META] '..tostring(v))end
|
||||
local good,err=pcall(function()
|
||||
local a=typeof(CS.RPG.Client.GridFightModule).Assembly
|
||||
local t=a:GetType(names[index])
|
||||
if not t then t=typeof(CS[names[index]])end
|
||||
log('TYPE '..names[index])
|
||||
if index<=2 then
|
||||
local fields=t:GetFields(flags)
|
||||
for i=0,math.min(fields.Length-1,47)do log('FIELD '..tostring(fields[i]))end
|
||||
local ctors=t:GetConstructors(flags)
|
||||
for i=0,math.min(ctors.Length-1,15)do log('CTOR '..tostring(ctors[i])..' '..tostring(ctors[i].MethodHandle.Value))end
|
||||
local methods=t:GetMethods(flags)
|
||||
for i=0,math.min(methods.Length-1,63)do
|
||||
local m=methods[i]
|
||||
if m.DeclaringType==t then log('METHOD '..tostring(m)..' '..tostring(m.MethodHandle.Value))end
|
||||
end
|
||||
end
|
||||
local props=t:GetProperties(flags)
|
||||
for i=0,math.min(props.Length-1,47)do
|
||||
local p=props[i]
|
||||
local getter=p:GetGetMethod(true)
|
||||
if getter and not getter.IsStatic and p:GetIndexParameters().Length==0 and (p.PropertyType.IsPrimitive or p.PropertyType.IsEnum)then
|
||||
log('GETTER '..names[index]..' '..p.Name..' '..tostring(getter.MethodHandle.Value)..' '..p.PropertyType.FullName)
|
||||
end
|
||||
end
|
||||
end)
|
||||
if not good then log('ERROR '..tostring(err))end
|
||||
if index==#names then log('END')end
|
||||
end
|
||||
@@ -0,0 +1,30 @@
|
||||
-- Exact shop/protobuf getters and two named constructors; metadata only.
|
||||
do
|
||||
local names={'POCJDMMANBM','HDEIAANGMDB','BOPHDCKJMMN','RPG.Client.GridFightShopGood','RPG.Client.GridFightShopRole','RPG.Client.GridFightRoleShop'}
|
||||
_G.__gacCwShopHandles1=_G.__gacCwShopHandles1 or {type=1,offset=0}
|
||||
local s=_G.__gacCwShopHandles1
|
||||
if s.type>#names then return end
|
||||
local flags=CS.System.Enum.ToObject(typeof(CS.System.Reflection.BindingFlags),60)
|
||||
local manager=CS.RPG.Client.GlobalVars.s_GamePhaseManager
|
||||
local phase=manager and typeof(CS.RPG.Client.GamePhaseManager):GetField('_CurrentPhase',flags):GetValue(manager)
|
||||
if not phase or typeof(CS.RPG.Client.BattleGamePhase):IsInstanceOfType(phase)then return end
|
||||
local log=function(v)CS.UnityEngine.Debug.Log('[GAC_CW_SHOP_HANDLE] '..tostring(v))end
|
||||
local good,err=pcall(function()
|
||||
if not s.properties then
|
||||
local t=typeof(CS.RPG.Client.GridFightModule).Assembly:GetType(names[s.type])
|
||||
if not t then t=typeof(CS[names[s.type]])end
|
||||
s.properties=t:GetProperties(flags)
|
||||
end
|
||||
for i=s.offset,math.min(s.offset+15,s.properties.Length-1)do
|
||||
local p=s.properties[i]
|
||||
local getter=p:GetGetMethod(true)
|
||||
if getter and not getter.IsStatic and p:GetIndexParameters().Length==0 then
|
||||
log('GETTER '..names[s.type]..' '..p.Name..' '..tostring(getter.MethodHandle.Value)..' '..p.PropertyType.FullName)
|
||||
end
|
||||
end
|
||||
s.offset=s.offset+16
|
||||
if s.offset>=s.properties.Length then s.properties=nil;s.offset=0;s.type=s.type+1 end
|
||||
end)
|
||||
if not good then log('ERROR '..tostring(err));s.properties=nil;s.offset=0;s.type=s.type+1 end
|
||||
if s.type>#names then log('END')end
|
||||
end
|
||||
@@ -0,0 +1,29 @@
|
||||
-- One named shop/protobuf type per heartbeat; metadata only, paused in Battle.
|
||||
do
|
||||
local names={'RPG.Client.GridFightRoleShop','POCJDMMANBM','HDEIAANGMDB','BOPHDCKJMMN'}
|
||||
_G.__gacCwShopSchema1=_G.__gacCwShopSchema1 or 1
|
||||
local index=_G.__gacCwShopSchema1
|
||||
if index>#names then return end
|
||||
local flags=CS.System.Enum.ToObject(typeof(CS.System.Reflection.BindingFlags),60)
|
||||
local manager=CS.RPG.Client.GlobalVars.s_GamePhaseManager
|
||||
local phase=manager and typeof(CS.RPG.Client.GamePhaseManager):GetField('_CurrentPhase',flags):GetValue(manager)
|
||||
if not phase or typeof(CS.RPG.Client.BattleGamePhase):IsInstanceOfType(phase)then return end
|
||||
_G.__gacCwShopSchema1=index+1
|
||||
local log=function(v)CS.UnityEngine.Debug.Log('[GAC_CW_SHOP_SCHEMA] '..tostring(v))end
|
||||
local good,err=pcall(function()
|
||||
local a=typeof(CS.RPG.Client.GridFightModule).Assembly
|
||||
local t=a:GetType(names[index])
|
||||
if not t then t=typeof(CS[names[index]])end
|
||||
log('TYPE '..names[index])
|
||||
local fields=t:GetFields(flags)
|
||||
for i=0,math.min(fields.Length-1,47)do log('FIELD '..tostring(fields[i]))end
|
||||
local properties=t:GetProperties(flags)
|
||||
for i=0,math.min(properties.Length-1,47)do log('PROPERTY '..tostring(properties[i]))end
|
||||
if index==1 then
|
||||
local m=t:GetMethod('Sync',flags)
|
||||
if m then log('HANDLE '..names[index]..' Sync '..tostring(m.MethodHandle.Value)..' '..tostring(m))end
|
||||
end
|
||||
end)
|
||||
if not good then log('ERROR '..tostring(err))end
|
||||
if index==#names then log('END')end
|
||||
end
|
||||
@@ -0,0 +1,19 @@
|
||||
-- Named Spotlight types only; metadata and handles, one type per heartbeat.
|
||||
do
|
||||
local s=_G.__gacCwBindingSchema1 or {index=1};_G.__gacCwBindingSchema1=s
|
||||
if s.done then return end
|
||||
local log=function(x)CS.UnityEngine.Debug.Log('[GAC_CW_SPOT_BINDING] '..tostring(x))end
|
||||
local ok,err=pcall(function()
|
||||
local flags=CS.System.Enum.ToObject(typeof(CS.System.Reflection.BindingFlags),60)
|
||||
local manager=CS.RPG.Client.GlobalVars.s_GamePhaseManager
|
||||
local phase=manager and typeof(CS.RPG.Client.GamePhaseManager):GetField('_CurrentPhase',flags):GetValue(manager)
|
||||
if not phase or typeof(CS.RPG.Client.BattleGamePhase):IsInstanceOfType(phase)then return end
|
||||
local names={'ACNDKIFJLJC','RPG.Client.GridFightSpotLightBinding','RPG.GameCore.GridFightSpotLightSelectConfigRow','RPG.GameCore.GridFightSpotLightRefreshConfigRow'}
|
||||
local name=names[s.index];if not name then s.done=true;log('END');return end;s.index=s.index+1
|
||||
local a=typeof(CS.RPG.Client.GridFightModule).Assembly;local b=typeof(CS.RPG.GameCore.GridFightRoleConfigRow).Assembly
|
||||
local t=a:GetType(name) or b:GetType(name);log('TYPE '..name..' '..tostring(t));if not t then return end
|
||||
local fields=t:GetFields(flags);for i=0,math.min(fields.Length-1,47)do log('FIELD '..tostring(fields[i]))end
|
||||
local methods=t:GetMethods(flags);for i=0,math.min(methods.Length-1,95)do local m=methods[i];if m.DeclaringType==t then log('METHOD '..tostring(m)..' HANDLE '..tostring(m.MethodHandle.Value))end end
|
||||
end)
|
||||
if not ok then s.done=true;log('ERROR '..tostring(err))end
|
||||
end
|
||||
@@ -0,0 +1,21 @@
|
||||
-- Four initialized handbook rows per heartbeat, pauses in Battle.
|
||||
do
|
||||
local s=_G.__gacCwSpotRows1 or {index=0};_G.__gacCwSpotRows1=s
|
||||
if s.done then return end
|
||||
local log=function(x)CS.UnityEngine.Debug.Log('[GAC_CW_SPOT_ROWS] '..tostring(x))end
|
||||
local ok,err=pcall(function()
|
||||
local flags=CS.System.Enum.ToObject(typeof(CS.System.Reflection.BindingFlags),60)
|
||||
local manager=CS.RPG.Client.GlobalVars.s_GamePhaseManager
|
||||
local phase=manager and typeof(CS.RPG.Client.GamePhaseManager):GetField('_CurrentPhase',flags):GetValue(manager)
|
||||
if not phase or typeof(CS.RPG.Client.BattleGamePhase):IsInstanceOfType(phase)then return end
|
||||
if not s.rows then s.rows=CS.RPG.Client.GlobalVars.s_ModuleManager.GridFightModule:GetHandBookAllSpotLightData();if s.rows.Count>512 then error('bound exceeded')end;log('BEGIN '..s.rows.Count)end
|
||||
for batch=1,4 do
|
||||
if s.index>=s.rows.Count then s.done=true;log('END');return end
|
||||
local c=s.rows[s.index];s.index=s.index+1
|
||||
local row=c:GetType():GetField('_Row',flags):GetValue(c)
|
||||
local text=tostring(CS.Newtonsoft.Json.JsonConvert.SerializeObject(row));if #text>32768 then error('row bound exceeded')end
|
||||
log('ROW '..text)
|
||||
end
|
||||
end)
|
||||
if not ok then s.done=true;log('ERROR '..tostring(err))end
|
||||
end
|
||||
@@ -0,0 +1,24 @@
|
||||
-- Named protobuf/accessor metadata only, maximum 24 getters per heartbeat.
|
||||
do
|
||||
local s=_G.__gacCwSpotGetters2 or {index=1,offset=0};_G.__gacCwSpotGetters2=s
|
||||
if s.done then return end
|
||||
local log=function(x)CS.UnityEngine.Debug.Log('[GAC_CW_SPOT_GETTER] '..tostring(x))end
|
||||
local ok,err=pcall(function()
|
||||
local flags=CS.System.Enum.ToObject(typeof(CS.System.Reflection.BindingFlags),60)
|
||||
local manager=CS.RPG.Client.GlobalVars.s_GamePhaseManager
|
||||
local phase=manager and typeof(CS.RPG.Client.GamePhaseManager):GetField('_CurrentPhase',flags):GetValue(manager)
|
||||
if not phase or typeof(CS.RPG.Client.BattleGamePhase):IsInstanceOfType(phase)then return end
|
||||
local types={typeof(CS.BDLBHJGNCFM),typeof(CS.HLHHLIGPNOM),typeof(CS.FMBACDOFCAL),typeof(CS.RPG.Client.GridFightSpotLightSelectAction)}
|
||||
local t=types[s.index];if not t then s.done=true;log('END');return end
|
||||
if s.offset==0 then
|
||||
log('TYPE '..t.FullName)
|
||||
if s.index<=3 then local fs=t:GetFields(flags);for i=0,math.min(fs.Length-1,31)do log('FIELD '..tostring(fs[i]))end end
|
||||
end
|
||||
local ms=t:GetMethods(flags)
|
||||
for i=s.offset,math.min(s.offset+23,ms.Length-1)do
|
||||
local m=ms[i];if (s.index<=3 or m.Name:sub(1,4)=='get_') and m.DeclaringType==t then log('METHOD '..t.FullName..'.'..m.Name..' HANDLE '..tostring(m.MethodHandle.Value)..' SIGNATURE '..tostring(m))end
|
||||
end
|
||||
s.offset=s.offset+24;if s.offset>=ms.Length then s.offset=0;s.index=s.index+1 end
|
||||
end)
|
||||
if not ok then s.done=true;log('ERROR '..tostring(err))end
|
||||
end
|
||||
@@ -0,0 +1,23 @@
|
||||
-- Named methods only; read metadata, four types at most, no gameplay actions.
|
||||
do
|
||||
local s=_G.__gacCwSpotHandles2 or {index=1};_G.__gacCwSpotHandles2=s
|
||||
if s.done then return end
|
||||
local log=function(x)CS.UnityEngine.Debug.Log('[GAC_CW_SPOT_HANDLE] '..tostring(x))end
|
||||
local ok,err=pcall(function()
|
||||
local flags=CS.System.Enum.ToObject(typeof(CS.System.Reflection.BindingFlags),60)
|
||||
local manager=CS.RPG.Client.GlobalVars.s_GamePhaseManager
|
||||
local phase=manager and typeof(CS.RPG.Client.GamePhaseManager):GetField('_CurrentPhase',flags):GetValue(manager)
|
||||
if not phase or typeof(CS.RPG.Client.BattleGamePhase):IsInstanceOfType(phase)then return end
|
||||
local types={typeof(CS.RPG.Client.GridFightEquipTrackData),typeof(CS.RPG.Client.GridFightSpotLightSelectAction),typeof(CS.RPG.Client.GridFightSpotLightManager)}
|
||||
local t=types[s.index];if not t then s.done=true;log('END');return end
|
||||
local methods=t:GetMethods(flags)
|
||||
for i=0,math.min(methods.Length-1,127)do
|
||||
local m=methods[i]
|
||||
if m.DeclaringType==t and (m.Name=='AddEquipTrack' or m.Name=='RemoveEquipTrack' or m.Name=='_AddTrackToLastAndSend' or m.Name=='SelectCandidate' or m.Name=='Select' or m.Name=='ReturnPreparation')then
|
||||
log('METHOD '..t.FullName..'.'..m.Name..' HANDLE '..tostring(m.MethodHandle.Value)..' TOKEN '..m.MetadataToken)
|
||||
end
|
||||
end
|
||||
s.index=s.index+1
|
||||
end)
|
||||
if not ok then s.done=true;log('ERROR '..tostring(err))end
|
||||
end
|
||||
@@ -0,0 +1,33 @@
|
||||
-- Named Spotlight config and active session metadata, no actions/loaders.
|
||||
do
|
||||
local s=_G.__gacCwSpotlightSchema1 or {index=1};_G.__gacCwSpotlightSchema1=s
|
||||
if s.done then return end
|
||||
local log=function(v)CS.UnityEngine.Debug.Log('[GAC_CW_SPOTLIGHT_SCHEMA] '..tostring(v))end
|
||||
local ok,err=pcall(function()
|
||||
local flags=CS.System.Enum.ToObject(typeof(CS.System.Reflection.BindingFlags),60)
|
||||
local manager=CS.RPG.Client.GlobalVars.s_GamePhaseManager
|
||||
local phase=manager and typeof(CS.RPG.Client.GamePhaseManager):GetField('_CurrentPhase',flags):GetValue(manager)
|
||||
if not phase or typeof(CS.RPG.Client.BattleGamePhase):IsInstanceOfType(phase)then return end
|
||||
local module=CS.RPG.Client.GlobalVars.s_ModuleManager.GridFightModule
|
||||
if not s.objects then
|
||||
local rows=module:GetHandBookAllSpotLightData();log('COUNT '..rows.Count)
|
||||
if rows.Count==0 then error('Spotlight handbook is empty')end
|
||||
s.objects={rows[0],module.CurGameSession}
|
||||
end
|
||||
local object=s.objects[s.index];if not object then s.done=true;log('END');return end
|
||||
s.index=s.index+1
|
||||
local t=object:GetType();log('TYPE '..t.FullName)
|
||||
local fs=t:GetFields(flags)
|
||||
for i=0,math.min(fs.Length-1,63)do
|
||||
log('FIELD '..tostring(fs[i]))
|
||||
if s.index==2 and tostring(fs[i].FieldType.FullName):find('Row$')then
|
||||
local row=fs[i]:GetValue(object);if row then log('ROW '..CS.Newtonsoft.Json.JsonConvert.SerializeObject(row))end
|
||||
end
|
||||
end
|
||||
local ps=t:GetProperties(flags);for i=0,math.min(ps.Length-1,63)do log('PROPERTY '..tostring(ps[i]))end
|
||||
local ms=t:GetMethods(flags)
|
||||
for i=0,math.min(ms.Length-1,127)do if ms[i].DeclaringType==t then log('METHOD '..tostring(ms[i]))end end
|
||||
if s.index==3 then s.done=true;log('END')end
|
||||
end)
|
||||
if not ok then log('ERROR '..tostring(err));s.done=true end
|
||||
end
|
||||
@@ -0,0 +1,21 @@
|
||||
-- Encode isolated protobuf setters only. Never sync objects into game modules.
|
||||
do
|
||||
local s=_G.__gacCwSpotWire1 or {index=1};_G.__gacCwSpotWire1=s
|
||||
if s.done then return end
|
||||
local log=function(x)CS.UnityEngine.Debug.Log('[GAC_CW_SPOT_WIRE] '..tostring(x))end
|
||||
local ok,err=pcall(function()
|
||||
local cases={
|
||||
{'BDLBHJGNCFM','MOCGEAKBAIC',true},{'BDLBHJGNCFM','PBNPEIJAFIH',true},{'BDLBHJGNCFM','JPIFFOMPOHI',1},
|
||||
{'BDLBHJGNCFM','GJPPJLCBCCO',1},{'BDLBHJGNCFM','IHLAAFILILO',1},{'BDLBHJGNCFM','NFLMNAJGOHP',1},{'BDLBHJGNCFM','ADDNPPLJGOL',true},
|
||||
{'FMBACDOFCAL','NHNGGGEBOAC',1},{'FMBACDOFCAL','CKPDGGDDPLB',1},{'FMBACDOFCAL','EODGHOPFDCJ',1},{'FMBACDOFCAL','APPPOHDNCFL',1},{'FMBACDOFCAL','OKLMNCNNIKF',true}
|
||||
}
|
||||
for n=1,2 do
|
||||
local row=cases[s.index];if not row then s.done=true;log('END');return end
|
||||
local obj=CS.System.Activator.CreateInstance(typeof(CS[row[1]]))
|
||||
obj[row[2]](obj,row[3])
|
||||
log(row[1]..'.'..row[2]..' '..CS.System.BitConverter.ToString(CS.Google.Protobuf.MessageExtensions.ToByteArray(obj)))
|
||||
s.index=s.index+1
|
||||
end
|
||||
end)
|
||||
if not ok then s.done=true;log('ERROR '..tostring(err))end
|
||||
end
|
||||
@@ -0,0 +1,24 @@
|
||||
-- Named CW types only, at most 64 method tokens per heartbeat.
|
||||
do
|
||||
local names={'RPG.Client.GridFightStage','RPG.Client.GridFightStageRoute','RPG.Client.GridFightStageNode'}
|
||||
_G.__gacCwStageTokens1=_G.__gacCwStageTokens1 or {index=1,method=0}
|
||||
local state=_G.__gacCwStageTokens1
|
||||
if state.index<=#names then
|
||||
local function log(v)CS.UnityEngine.Debug.Log('[GAC_CW_METHOD_TOKEN] '..tostring(v))end
|
||||
local ok,err=pcall(function()
|
||||
local flags=CS.System.Enum.ToObject(typeof(CS.System.Reflection.BindingFlags),60)
|
||||
local assembly=typeof(CS.RPG.Client.GridFightModule).Assembly
|
||||
local t=assembly:GetType(names[state.index])
|
||||
if not t then t=typeof(CS[names[state.index]])end
|
||||
local methods=t:GetMethods(flags)
|
||||
for i=state.method,math.min(state.method+63,methods.Length-1)do
|
||||
local m=methods[i]
|
||||
if m.DeclaringType==t then log('METHOD '..names[state.index]..' '..m.Name..' '..m.MetadataToken)end
|
||||
end
|
||||
state.method=state.method+64
|
||||
if state.method>=methods.Length then log('END '..names[state.index]);state.index=state.index+1;state.method=0 end
|
||||
end)
|
||||
if not ok then log('ERROR '..names[state.index]..' '..tostring(err));state.index=state.index+1;state.method=0 end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
-- Encode isolated protobuf objects to map obfuscated backing fields to tags.
|
||||
-- No objects are synced into a game module or sent as network responses.
|
||||
do
|
||||
local names={'GridFightStartGamePlayCsReq'}
|
||||
_G.__gacCwStartWire1=_G.__gacCwStartWire1 or {index=1,field=0}
|
||||
local state=_G.__gacCwStartWire1
|
||||
if state.index<=#names then
|
||||
local function log(v)CS.UnityEngine.Debug.Log('[GAC_CW_START_WIRE] '..tostring(v))end
|
||||
local ok,err=pcall(function()
|
||||
local flags=CS.System.Enum.ToObject(typeof(CS.System.Reflection.BindingFlags),60)
|
||||
local t=typeof(CS[names[state.index]])
|
||||
local fields=t:GetFields(flags)
|
||||
local count=0
|
||||
for i=state.field,fields.Length-1 do
|
||||
state.field=i+1
|
||||
local f=fields[i]
|
||||
if not f.IsStatic and f.FieldType==typeof(CS.System.UInt32) then
|
||||
local obj=CS.System.Activator.CreateInstance(t)
|
||||
local typed=CS.System.Array.CreateInstance(typeof(CS.System.UInt32),1);typed[0]=1
|
||||
local boxed=CS.System.Array.CreateInstance(typeof(CS.System.Object),2);boxed[0]=obj
|
||||
CS.System.Array.Copy(typed,0,boxed,1,1)
|
||||
local setters=f:GetType():GetMethods(flags)
|
||||
local setter=nil
|
||||
for j=0,setters.Length-1 do
|
||||
if setters[j].Name=='SetValue' and setters[j]:GetParameters().Length==2 then setter=setters[j];break end
|
||||
end
|
||||
if not setter then error('FieldInfo.SetValue overload missing')end
|
||||
local invoke=CS.System.Enum.ToObject(typeof(CS.System.Reflection.BindingFlags),0)
|
||||
setter:Invoke(f,invoke,nil,boxed,nil)
|
||||
local bytes=CS.Google.Protobuf.MessageExtensions.ToByteArray(obj)
|
||||
log('FIELD '..names[state.index]..' '..f.Name..' '..CS.System.BitConverter.ToString(bytes))
|
||||
local properties=t:GetProperties(flags)
|
||||
local empty=CS.System.Array.CreateInstance(typeof(CS.System.Object),0)
|
||||
for j=0,properties.Length-1 do
|
||||
local p=properties[j]
|
||||
if p.PropertyType==typeof(CS.System.UInt32) then
|
||||
local getter=p:GetGetMethod(true)
|
||||
if getter and not getter.IsStatic and getter:Invoke(obj,invoke,nil,empty,nil)==1 then
|
||||
log('GETTER '..names[state.index]..' '..f.Name..' '..p.Name..' '..getter.MetadataToken)
|
||||
end
|
||||
end
|
||||
end
|
||||
count=count+1;if count>=2 then return end
|
||||
end
|
||||
end
|
||||
log('END '..names[state.index]);state.index=state.index+1;state.field=0
|
||||
end)
|
||||
if not ok then log('ERROR '..tostring(err));state.index=state.index+1;state.field=0 end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
-- Look up two exact table names across loaded assemblies, never enumerate types.
|
||||
-- Eight exact-name lookups per heartbeat; no type enumeration or loader.
|
||||
do
|
||||
_G.__gacCwTableAssembly2=_G.__gacCwTableAssembly2 or {index=0}
|
||||
local s=_G.__gacCwTableAssembly2
|
||||
if not s.done then
|
||||
local flags=CS.System.Enum.ToObject(typeof(CS.System.Reflection.BindingFlags),60)
|
||||
local manager=CS.RPG.Client.GlobalVars.s_GamePhaseManager
|
||||
local phase=manager and typeof(CS.RPG.Client.GamePhaseManager):GetField('_CurrentPhase',flags):GetValue(manager)
|
||||
if not phase or typeof(CS.RPG.Client.BattleGamePhase):IsInstanceOfType(phase) then return end
|
||||
local log=function(v)CS.UnityEngine.Debug.Log('[GAC_CW_TABLE_ASSEMBLY] '..tostring(v))end
|
||||
if not s.assemblies then
|
||||
s.assemblies=CS.System.AppDomain.CurrentDomain:GetAssemblies()
|
||||
if s.assemblies.Length>256 then log('ERROR Assembly count exceeds capture bound');s.done=true;return end
|
||||
log('BEGIN count='..s.assemblies.Length)
|
||||
end
|
||||
for batch=1,8 do
|
||||
if s.index<s.assemblies.Length then
|
||||
local assembly=s.assemblies[s.index]
|
||||
log('ASSEMBLY '..assembly.FullName)
|
||||
for _,name in ipairs({'RPG.GameCore.GridFightPlayerLevelConfigExcelTable','RPG.GameCore.GridFightRoleConfigExcelTable'})do
|
||||
local t=assembly:GetType(name)
|
||||
if t then log('FOUND '..name..' '..assembly.FullName)end
|
||||
end
|
||||
s.index=s.index+1
|
||||
else s.done=true;log('END');return end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,41 @@
|
||||
-- Current loaded props only; table IDs substituted from captured room config.
|
||||
do
|
||||
local ids=__PROP_IDS__
|
||||
local function log(v)CS.UnityEngine.Debug.Log('[GAC_CW_TABLE_STATE] '..tostring(v))end
|
||||
_G.__gacCwTableState2=_G.__gacCwTableState2 or {index=0,hits=0}
|
||||
local state=_G.__gacCwTableState2
|
||||
if not state.done then
|
||||
local ok,err=pcall(function()
|
||||
local flags=CS.System.Enum.ToObject(typeof(CS.System.Reflection.BindingFlags),60)
|
||||
if not state.rows then
|
||||
local map=CS.RPG.Client.GlobalVars.s_ModuleManager.AdventureModule.MapDef
|
||||
local collection=map.AllMapEntityDefs
|
||||
state.rows=collection:GetType():GetField('BPPKNKJBABP',flags):GetValue(collection)
|
||||
log('BEGIN '..state.rows.Count)
|
||||
for _,id in ipairs(ids)do
|
||||
local row=CS.RPG.GameCore.PropExcelTable.GetData(id)
|
||||
log('PROP_ROW '..row.ID..' path='..tostring(row.JsonPath)..' states='..CS.Newtonsoft.Json.JsonConvert.SerializeObject(row.PropStateList))
|
||||
end
|
||||
end
|
||||
for i=state.index,math.min(state.index+31,state.rows.Count-1)do
|
||||
local p=state.rows[i]
|
||||
for _,id in ipairs(ids)do if p.PropID==id then
|
||||
state.hits=state.hits+1
|
||||
log('MATCH '..p.PropID)
|
||||
for _,name in ipairs({'ID','GroupID','InstID','EntityID','PropState','State','IsActive','IsClientOnly','IsLoaded','IsDelete'})do
|
||||
local good,value=pcall(function()return p[name]end)
|
||||
if good and type(value)~='userdata' and type(value)~='table' then log('VALUE '..name..' '..tostring(value))end
|
||||
end
|
||||
local methods=p:GetType():GetMethods(flags)
|
||||
for j=0,methods.Length-1 do
|
||||
local m=methods[j]
|
||||
if m.DeclaringType==p:GetType() and (m.Name:find('State')or m.Name:find('Entity')or m.Name:find('Active'))then log('METHOD '..tostring(m))end
|
||||
end
|
||||
end end
|
||||
end
|
||||
state.index=state.index+32
|
||||
if state.index>=state.rows.Count then state.done=true;log('END hits='..state.hits)end
|
||||
end)
|
||||
if not ok then state.done=true;log('ERROR '..tostring(err))end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,27 @@
|
||||
-- Metadata of named CW configuration types only, one type per heartbeat.
|
||||
-- No config loader is invoked and no Client run/module state is changed.
|
||||
do
|
||||
local names={'GridFightStageTemplateConfig','GridFightBattleTemplate','GridFightWaveInfo','GridFightWaveMonsterEntry','GridFightWaveMonsterInfo','GridFightStageNodeDisplayConfigExcelTable'}
|
||||
_G.__gacCwTemplateSchema1=_G.__gacCwTemplateSchema1 or {index=1,assembly=1}
|
||||
local s=_G.__gacCwTemplateSchema1
|
||||
if s.index<=#names then
|
||||
local log=function(v) CS.UnityEngine.Debug.Log('[GAC_CW_TEMPLATE_SCHEMA] '..tostring(v)) end
|
||||
local assemblies={typeof(CS.RPG.GameCore.GridFightRoleConfigRow).Assembly,typeof(CS.RPG.GameCore.GameCoreConfigLoader).Assembly}
|
||||
local t=assemblies[s.assembly]:GetType('RPG.GameCore.'..names[s.index])
|
||||
local flags=CS.System.Enum.ToObject(typeof(CS.System.Reflection.BindingFlags),60)
|
||||
log('TYPE '..names[s.index]..' assembly='..s.assembly..' '..tostring(t))
|
||||
if t then
|
||||
local fields=t:GetFields(flags)
|
||||
for i=0,math.min(fields.Length-1,47) do log('FIELD '..tostring(fields[i])) end
|
||||
local props=t:GetProperties(flags)
|
||||
for i=0,math.min(props.Length-1,47) do log('PROPERTY '..tostring(props[i])) end
|
||||
local methods=t:GetMethods(flags)
|
||||
for i=0,math.min(methods.Length-1,47) do
|
||||
if methods[i].DeclaringType==t then log('METHOD '..tostring(methods[i])) end
|
||||
end
|
||||
end
|
||||
s.assembly=s.assembly+1
|
||||
if s.assembly>#assemblies then s.assembly=1;s.index=s.index+1 end
|
||||
if s.index>#names then log('END') end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,23 @@
|
||||
-- Inspect text/config loader metadata on one known type in bounded batches.
|
||||
-- No loader or callback is invoked.
|
||||
do
|
||||
_G.__gacCwTextLoader1=_G.__gacCwTextLoader1 or {index=0}
|
||||
local s=_G.__gacCwTextLoader1
|
||||
if not s.done then
|
||||
local log=function(v)CS.UnityEngine.Debug.Log('[GAC_CW_TEXT_LOADER] '..tostring(v))end
|
||||
local flags=CS.System.Enum.ToObject(typeof(CS.System.Reflection.BindingFlags),60)
|
||||
if not s.methods then
|
||||
local t=typeof(CS.RPG.GameCore.GameCoreConfigLoader)
|
||||
s.methods=t:GetMethods(flags)
|
||||
local fields=t:GetFields(flags)
|
||||
for i=0,math.min(fields.Length-1,31)do log('FIELD '..tostring(fields[i]))end
|
||||
end
|
||||
for i=s.index,math.min(s.index+63,s.methods.Length-1)do
|
||||
local m=s.methods[i]
|
||||
local name=m.Name:lower()
|
||||
if m.ReturnType==typeof(CS.System.String) or name:find('text') or name:find('json') then log('METHOD '..tostring(m))end
|
||||
end
|
||||
s.index=s.index+64
|
||||
if s.index>=s.methods.Length then s.done=true;log('END')end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,32 @@
|
||||
-- Export identified scalar tutorial rules from initialized native wrappers.
|
||||
-- One wrapper per heartbeat. Does not start tutorials or load any JsonPath.
|
||||
do
|
||||
_G.__gacCwTutorialConfig1=_G.__gacCwTutorialConfig1 or {count=0}
|
||||
local s=_G.__gacCwTutorialConfig1
|
||||
if not s.done then
|
||||
local log=function(v)CS.UnityEngine.Debug.Log('[GAC_CW_TUTORIAL_CONFIG] '..tostring(v))end
|
||||
local ok,err=pcall(function()
|
||||
if not s.iterator then
|
||||
local rows=CS.RPG.Client.GlobalVars.s_ModuleManager.GridFightModule.TutorialStageConfigs
|
||||
if rows.Count>64 then error('Tutorial count exceeds capture bound')end
|
||||
s.iterator=rows:GetEnumerator();s.expected=rows.Count;log('BEGIN count='..s.expected)
|
||||
end
|
||||
if s.iterator:MoveNext()then
|
||||
local pair=s.iterator.Current
|
||||
local row=pair.Value
|
||||
local values={'"ID":'..pair.Key}
|
||||
for _,name in ipairs({'DivisionID','RewardQuest','ForbiddenBattleFailChapterID','ForbiddenSellRoleBeforeChapterId','ForbiddenSellRoleBeforeSectionId','HasMonsterReveal','HasPortal','HasInitialSupply','HasRouteShow','HasEquipRecommendShow','HasBossToastShow','UseTrialAvatar'})do
|
||||
values[#values+1]='"'..name..'":'..tostring(row[name])
|
||||
end
|
||||
for _,name in ipairs({'ForbiddenSellRoleDict','ForbiddenAutoOpenShopNodeList'})do
|
||||
values[#values+1]='"'..name..'":'..CS.Newtonsoft.Json.JsonConvert.SerializeObject(row[name])
|
||||
end
|
||||
log('ROW {'..table.concat(values,',')..'}');s.count=s.count+1
|
||||
else
|
||||
if s.count~=s.expected then error('Tutorial table changed')end
|
||||
s.done=true;log('END')
|
||||
end
|
||||
end)
|
||||
if not ok then log('ERROR '..tostring(err));s.done=true end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,32 @@
|
||||
-- Parse only the exact native FirstPlay JSON through the plain JSON reader.
|
||||
-- Does not call LoadLevelGraphConfig, execute tasks, or start a game session.
|
||||
-- Output is bounded to one 4096-byte JSON-escaped chunk per heartbeat.
|
||||
do
|
||||
_G.__gacCwTutorialJson1=_G.__gacCwTutorialJson1 or {index=1}
|
||||
local s=_G.__gacCwTutorialJson1
|
||||
if not s.done then
|
||||
local log=function(v)CS.UnityEngine.Debug.Log('[GAC_CW_TUTORIAL_JSON] '..tostring(v))end
|
||||
local ok,err=pcall(function()
|
||||
if not s.text then
|
||||
local rule=CS.RPG.GameCore.ConstValueCommonExcelTable.GetData('GridFight_FirstPlay_JsonPath')
|
||||
if not rule or not rule.Value.IsString then error('Native tutorial JSON path missing')end
|
||||
s.path=rule.Value.StringValue
|
||||
local node=CS.RPG.GameCore.GameCoreConfigLoader.LoadJsonConfig(s.path)
|
||||
if not node then error('Plain JSON reader returned nil')end
|
||||
s.text=tostring(node:ToString())
|
||||
if #s.text>1048576 then error('Tutorial JSON exceeds capture bound')end
|
||||
log('BEGIN path='..s.path..' bytes='..#s.text)
|
||||
end
|
||||
if s.index<=#s.text then
|
||||
-- JSON configuration is emitted as escaped text to preserve chunk content.
|
||||
local finish=math.min(s.index+4095,#s.text)
|
||||
while finish<#s.text and string.byte(s.text,finish+1)>=128 and string.byte(s.text,finish+1)<192 do finish=finish-1 end
|
||||
log('CHUNK '..s.index..' '..CS.Newtonsoft.Json.JsonConvert.SerializeObject(s.text:sub(s.index,finish)))
|
||||
s.index=finish+1
|
||||
else
|
||||
log('END bytes='..#s.text);s.text=nil;s.done=true
|
||||
end
|
||||
end)
|
||||
if not ok then log('ERROR '..tostring(err));s.done=true;s.text=nil end
|
||||
end
|
||||
end
|
||||
Loaded 100 of 310 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user