--[[ BatchAgent:提供USE_BATCH_MODE的嵌入方法 BatchAgentEnv:USE_BATCH_MODE所使用的指令 --]] local LuaUpdater = require('Main/LuaUpdater') local EventSystem = require('Event/EventSystem') local BatchEventSystem = EventSystem.CreateEventSystem() local BatchAgent = {} local private = {} local BatchMsgFuncEnv = setmetatable({}, {__index = _G}) local OptType = { ["Clicked"] = "OnButtonClicked", ["ValueChanged"] = "OnValueChanged", ["CellClicked"] = "OnCellClicked", ["CellValueChanged"] = "OnCellValueChanged", ["CellSelect"] = "OnCellSelect", ["ScrollRectMoveToCell"] = "ScrollRectMoveToCell", } local LastMsgCheckTime = 0 local RecordFile = nil local LastOptTime = -1 local WatcherState = { curMsgCounter = 0, msgCounter = 0, judgeBatchMessageIsRun = false, } --region ********* agent ********* function BatchAgent.GetShardInfo() if DEF.batch_sid then local name = tostring(tonumber(GameAppInfo.Global_ProductId) * 10000 + DEF.batch_sid) local serverList = MDL.Login.GetServerList() for i, data in ipairs(serverList) do if data["name"] == name then return data end end end end function BatchAgent.RegisterBatchUIEvent(viewName, view) BatchEventSystem.Regist(viewName, private.HandleUIFunc, view) end function BatchAgent.UnRegisterBatchUIEvent(viewName, view) BatchEventSystem.UnRegist(viewName, private.HandleUIFunc, view) end -- 类型转换 local function FcompTypeChange(fcomp) local num = tonumber(fcomp) if num then return num else return fcomp end end --为了支持子界面中的控件,例如fcomp = {'subView', 'btn_ok'}可以用于查找self.subView.btn_ok local function GetCompBy(root, fcomp) local comp = root if type(fcomp) == 'table' then for i, v in ipairs(fcomp) do comp = comp[FcompTypeChange(v)] end else comp = comp[FcompTypeChange(fcomp)] end return comp end function private.HandleUIFunc(selfView, fcomp, funcName, ...) local comp = GetCompBy(selfView, fcomp) if not comp then return end if funcName == 'SetInputText' then comp.text = select(1, ...) elseif funcName == OptType.CellClicked or funcName == OptType.CellSelect or funcName == OptType.CellValueChanged or funcName == OptType.ScrollRectMoveToCell then local index = select(1, ...) local target = select(2, ...) if funcName == OptType.ScrollRectMoveToCell then if comp.SrollToCell then comp:SrollToCell(index, 2500) end else local func = selfView[funcName] if not func then return end local cellTb = comp:GetCellTableByIndex(index) local targetComp = GetCompBy(cellTb, target) if funcName == OptType.CellValueChanged then func(selfView, comp, index, cellTb, targetComp, select(3, ...)) else func(selfView, comp, index, cellTb, targetComp, comp:GetCellDataByIndex(index)) end end else local func = selfView[funcName] if not func then return end if funcName == OptType.ValueChanged then local value = select(1, ...) if comp.SelectIndex and type(value) == "number" then comp:SelectIndex(value) else func(selfView, comp, ...) end else func(selfView, comp, ...) end end end function private.JudgeBatchMessage(dt, ts) local curMsgCounter = WatcherState.curMsgCounter if DEF.batch_uid and curMsgCounter < WatcherState.msgCounter then if ts - LastMsgCheckTime < 1 then return end -- 因为文件变化是异步监听,可能导致操作数变化值不为1,所以添加了1秒延迟 local filename = string.format("%s/%s_%d", DEF.batch_uid, DEF.batch_uid, curMsgCounter) local file = io.open(filename) if file then local msg = file:read("*a") file:close() local func = loadstring(msg, 'batch_message') if func then --添加BatchMessage的运行环境,避免对全局表造成污染 setfenv(func, BatchMsgFuncEnv) pcall(func) os.remove(filename) -- 修改操作数计算 WatcherState.curMsgCounter = curMsgCounter + 1 if WatcherState.curMsgCounter == WatcherState.msgCounter then LuaUpdater.StopRealTimeUpdate(private.JudgeBatchMessage) WatcherState.judgeBatchMessageIsRun = false LastMsgCheckTime = 0 -- 如果当前剩余操做全部处理完,则将时间置空,下一次不会等延迟 else LastMsgCheckTime = ts -- 如果当前剩余操作没有处理完,则下一次处理操作延迟1秒 end else print('handle batch message failed', msg) end end end end -- 拼接parameter,方便下面字符串转换 local function JointParameter(parameter) local num = tonumber(parameter) if num then return num else return string.format("'%s'", parameter) end end -- 解析ExportRoot,将list转换成字符转 local function ParseExportRoot(exportRootList) if #exportRootList == 1 then return JointParameter(exportRootList[1]) else local clickStr = "{" for _, v in ipairs(exportRootList) do clickStr = clickStr .. JointParameter(v) .. "," end clickStr = clickStr .. "}" return clickStr end end local function FindExportRoot(parent, comp, tb) if parent == comp then return parent end if type(parent) ~= "table" then return nil end if parent.gameObject == nil and parent.cell == nil then return nil end local obj = nil for k, v in pairs(parent) do obj = FindExportRoot(v, comp, tb) if obj then table.insert(tb, 1, k) break end end return obj end local function SetRecordStr(optType, ui, targetPath, value, index, cellTargetPath, _interval) if not RecordFile then return end local interval = 0 if _interval ~= nil and type(_interval) == "number" then interval = _interval else local interval = LastOptTime < 0 and 0 or UTL.Time.GetLocalTimestamp() - LastOptTime LastOptTime = UTL.Time.GetLocalTimestamp() end if interval <= 0 then interval = 1 end if optType == OptType.Clicked then RecordFile:write(string.format("\n\t{\n\t\toptType = '%s',\n\t\tui = %s,\n\t\ttargetPath = %s,\n\t\tinterval = %s,\n\t},", optType, ui, targetPath, interval)) elseif optType == OptType.ValueChanged then RecordFile:write(string.format("\n\t{\n\t\toptType = '%s',\n\t\tui = %s,\n\t\ttargetPath = %s,\n\t\tvalue = %s,\n\t\tinterval = %s,\n\t},", optType, ui, targetPath, value, interval)) elseif optType == OptType.CellClicked or optType == OptType.CellSelect or optType == OptType.ScrollRectMoveToCell then RecordFile:write(string.format("\n\t{\n\t\toptType = '%s',\n\t\tui = %s,\n\t\ttargetPath = %s,\n\t\tindex = %s,\n\t\tcellTargetPath = %s,\n\t\tinterval = %s,\n\t},", optType, ui, targetPath, index, cellTargetPath, interval)) elseif optType == OptType.CellValueChanged then RecordFile:write(string.format("\n\t{\n\t\toptType = '%s',\n\t\tui = %s,\n\t\ttargetPath = %s,\n\t\tindex = %s,\n\t\tcellTargetPath = %s,\n\t\tvalue = %s,\n\t\tinterval = %s,\n\t},", optType, ui, targetPath, index, cellTargetPath, value, interval)) end end ---- UIView函数替换 ----- local function RecordClickedFunc(view, comp) local exportRootList = {} FindExportRoot(view, comp, exportRootList) SetRecordStr(OptType.Clicked, JointParameter(view.__viewClassPath), ParseExportRoot(exportRootList)) end local function RecordValueChangedFunc(view, comp, value) local exportRootList = {} FindExportRoot(view, comp, exportRootList) SetRecordStr(OptType.ValueChanged, JointParameter(view.__viewClassPath), ParseExportRoot(exportRootList), value) end local function RecordCellClickedFunc(view, scrollRect, index, cellTable, target) local exportRootList, targetExportRootList = {}, {} FindExportRoot(view, scrollRect, exportRootList) if cellTable.cell.gameObject == target.gameObject then table.insert(targetExportRootList, "cell") else FindExportRoot(cellTable, target, targetExportRootList) end -- 先移动 SetRecordStr(OptType.ScrollRectMoveToCell, JointParameter(view.__viewClassPath), ParseExportRoot(exportRootList), nil, index, ParseExportRoot(targetExportRootList)) -- 再点击 需要给移动留出足够的时间 所以强行给予3秒的限制 SetRecordStr(OptType.CellClicked, JointParameter(view.__viewClassPath), ParseExportRoot(exportRootList), nil, index, ParseExportRoot(targetExportRootList), 3) end local function RecordCellValueChangedFunc(view, scrollRect, index, cellTable, target, value) local exportRootList, targetExportRootList = {}, {} FindExportRoot(view, scrollRect, exportRootList) if cellTable.cell.gameObject == target.gameObject then table.insert(targetExportRootList, "cell") else FindExportRoot(cellTable, target, targetExportRootList) end -- 先移动 SetRecordStr(OptType.ScrollRectMoveToCell, JointParameter(view.__viewClassPath), ParseExportRoot(exportRootList), nil, index, ParseExportRoot(targetExportRootList)) -- 再赋值 需要给移动留出足够的时间 所以强行给予3秒的限制 SetRecordStr(OptType.CellValueChanged, JointParameter(view.__viewClassPath), ParseExportRoot(exportRootList), value, index, ParseExportRoot(targetExportRootList), 3) end local function RecordCellSelectFunc(view, scrollRect, index, cellTable, target) local exportRootList, targetExportRootList = {}, {} FindExportRoot(view, scrollRect, exportRootList) if cellTable.cell.gameObject == target.gameObject then table.insert(targetExportRootList, "cell") else FindExportRoot(cellTable, target, targetExportRootList) end -- 先移动 SetRecordStr(OptType.ScrollRectMoveToCell, JointParameter(view.__viewClassPath), ParseExportRoot(exportRootList), nil, index, ParseExportRoot(targetExportRootList)) -- 再赋值 需要给移动留出足够的时间 所以强行给予3秒的限制 SetRecordStr(OptType.CellSelect, JointParameter(view.__viewClassPath), ParseExportRoot(exportRootList), nil, index, ParseExportRoot(targetExportRootList), 3) end local function ReplaceUIViewFunc() local UIView = require("View/UIView") local viewEntryFunc = UIView.ViewEntryFunc -- 替换点击函数 type = 6 -- 替换vlchange函数 type = 7 -- 替换OnLoopScrollEvent函数 type = 10,LSEvent_OnCellClicked:{...} 第一个参数 type = 5、LSEvent_OnCellValueChanged:{...} 第一个参数 type = 7 CSExt.SetViewEntryFunc(function(view, funcType, ...) if RecordFile then if funcType == 6 then -- 向OnButtonClicked点击函数(type = 6)注入方法 local comp = select(1, ...) RecordClickedFunc(view, comp) elseif funcType == 7 then -- 向OnValueChanged函数(type = 7)注入方法 local comp, value = select(1, ...) RecordValueChangedFunc(view, comp, value) elseif funcType == 10 then -- 向OnLoopScrollEvent函数(type = 10)注入方法 local lsEventType = select(1, ...) if lsEventType == 4 then -- 向OnLoopScrollEvent函数中 LSEvent_OnCellSelect(lsEventType = 4)注入方法 local scrollRect, index, cellTable, target = select(2, ...) RecordCellSelectFunc(view, scrollRect, index, cellTable, target) elseif lsEventType == 5 then -- 向OnLoopScrollEvent函数中 LSEvent_OnCellClicked(lsEventType = 5)注入方法 local scrollRect, index, cellTable, target = select(2, ...) RecordCellClickedFunc(view, scrollRect, index, cellTable, target) elseif lsEventType == 7 then -- 向OnLoopScrollEvent函数中 LSEvent_OnCellValueChanged(lsEventType = 7)注入方法 local scrollRect, index, cellTable, target, value = select(2, ...) RecordCellValueChangedFunc(view, scrollRect, index, cellTable, target, value) end end end viewEntryFunc(view, funcType, ...) end) end local function UpdateWatcherState(addMsgCounter) WatcherState.msgCounter = WatcherState.msgCounter + addMsgCounter if WatcherState.judgeBatchMessageIsRun then return end WatcherState.judgeBatchMessageIsRun = true LuaUpdater.StartRealTimeUpdate(private.JudgeBatchMessage) end do --模块的初始化 BatchAgentHelper.WatcherStart(DEF.batch_uid, string.format("%s_*", DEF.batch_uid), UpdateWatcherState) GameAppInfo.ResetProductId(DEF.batch_pid or GameAppInfo.Global_ProductId) AppInfo.packageType = DEF.batch_rid or AppInfo.packageType AppInfo.marketVersion = DEF.batch_mid or AppInfo.marketVersion GameAppInfo.Global_PackageType = AppInfo.packageType ReplaceUIViewFunc() end --endregion agent --region ********* 指令列表 ********* function BatchMsgFuncEnv.enter(levelId) AuxUtil.EnterBattleID(levelId); CTL.HomeMain.OpenPreBattleSceneUI(); end function BatchMsgFuncEnv.findpath(levelId, px, pz) NotSyncBattleSetter.FindPathByPos(levelId, px, pz, false, nil, LuaConst.ETownFindPathType.CHAT, true) end function BatchMsgFuncEnv.moveto(px, pz) SystemManager.AutoFindPathInTown(LogicUpdateManager._curEntity, FP.newV2(px, pz), FP.Const.Two) end function BatchMsgFuncEnv.stopmoveto() SystemManager.StopAutoFightPathInTown(LogicUpdateManager._curEntity) end function BatchMsgFuncEnv.movedir(dx, dz) dx = dx or 0 dz = dz or 1 EventSystem.Dispatch(EventID.UI_KeyboardControl_MoveDir, dx, dz) end function BatchMsgFuncEnv.stopmovedir() EventSystem.Dispatch(EventID.UI_KeyboardControl_MoveRelease) end function BatchMsgFuncEnv.attack(key) EventSystem.Dispatch(EventID.UI_KeyboardControl_Skill_Press, key) end function BatchMsgFuncEnv.stopattack(key) EventSystem.Dispatch(EventID.UI_KeyboardControl_Skill_Release, key) end function BatchMsgFuncEnv.openui(ui,context) local uiName = Const_UI_Lua.UIEnum[ui] or ui if uiName then if UIManager.IsViewOpened(uiName) then UIManager.CloseView(uiName) end UIManager.OpenView(uiName, context) end end function BatchMsgFuncEnv.closeui(ui) local uiName = Const_UI_Lua.UIEnum[ui] or ui if uiName then UIManager.CloseView(uiName) end end function BatchMsgFuncEnv.uiclickbtn(ui, fcomp) local uiName = Const_UI_Lua.UIEnum[ui] or ui if uiName then BatchEventSystem.Dispatch(uiName, fcomp, OptType.Clicked) end end function BatchMsgFuncEnv.uichangeval(ui, fcomp, value) local uiName = Const_UI_Lua.UIEnum[ui] or ui if uiName then BatchEventSystem.Dispatch(uiName, fcomp, OptType.ValueChanged, value) end end function BatchMsgFuncEnv.uicellclick(ui, loopcomp, index, target) local uiName = Const_UI_Lua.UIEnum[ui] or ui if uiName then BatchEventSystem.Dispatch(uiName, loopcomp, OptType.CellClicked, index, target) end end function BatchMsgFuncEnv.uicellchangeval(ui, loopcomp, index, target, value) local uiName = Const_UI_Lua.UIEnum[ui] or ui if uiName then BatchEventSystem.Dispatch(uiName, loopcomp, OptType.CellValueChanged, index, target, value) end end function BatchMsgFuncEnv.uicellselect(ui, loopcomp, index, target) local uiName = Const_UI_Lua.UIEnum[ui] or ui if uiName then BatchEventSystem.Dispatch(uiName, loopcomp, OptType.CellSelect, index, target) end end function BatchMsgFuncEnv.uiscrollrectmovetocell(ui, loopcomp, index, target) local uiName = Const_UI_Lua.UIEnum[ui] or ui if uiName then BatchEventSystem.Dispatch(uiName, loopcomp, OptType.ScrollRectMoveToCell, index, target) end end function BatchMsgFuncEnv.ui_trigger_event(ui, fcomp, eventName, px, py, dx, dy) local uiName = Const_UI_Lua.UIEnum[ui] or ui if uiName then local eventData = { position = Vector2.New(px,py), delta = Vector2.New(dx,dy) } BatchEventSystem.Dispatch(uiName, fcomp, eventName, eventData) end end function BatchMsgFuncEnv.uisetinputtext(ui, fcomp, value) local uiName = Const_UI_Lua.UIEnum[ui] or ui if uiName then BatchEventSystem.Dispatch(uiName, fcomp, "SetInputText", value) end end function BatchMsgFuncEnv.usecheat(cmdMsg) MDL.Cheat.Send(cmdMsg) end -- 开启录制时创建文件 function BatchMsgFuncEnv.startrecord() CTL.Tips.AddTipsMsg("开启录制") local filePath = UTL.Time.OsDateOriginal("batch_record_%Y%m%d_%H%M%S.txt") RecordFile = io.open(filePath, "w+") RecordFile:close() RecordFile = io.open(filePath, "a+") RecordFile:write("return {") LastOptTime = -1 end -- 关闭录制时写入文件 function BatchMsgFuncEnv.endrecord() if not RecordFile then return end RecordFile:write("\n}") RecordFile:close() RecordFile = nil CTL.Tips.AddTipsMsg("关闭录制,同时保存录制文件") end --endregion 指令列表 return BatchAgent