源战役客户端
Non puoi selezionare più di 25 argomenti Gli argomenti devono iniziare con una lettera o un numero, possono includere trattini ('-') e possono essere lunghi fino a 35 caratteri.
 
 
 
 
 

414 righe
12 KiB

BaseController = BaseController or BaseClass()
local BaseController = BaseController
local UserMsgAdapter = UserMsgAdapter
BaseController.request_protocals_list = Array.New()
BaseController.handle_protocals = {} --处理的指令列表
BaseController.is_delay_send_protocal = false
function BaseController:__init()
--销毁引用
local function onViewDestoryHandler(view)
self:clearViewQuoted(view)
end
self.clearViewQuoted_BindId = self:Bind(BaseView.DestroyEvent,onViewDestoryHandler)
end
function BaseController:RemoveCheckOutEvent()
end
function BaseController:EnableCheckoutClear(bool)
bool = bool == nil and true or bool
self.checkout_clear_view = bool
if bool then
self.view_list = {} --依附于该控制器的界面
setmetatable(self.view_list, {__mode = "v"}) --弱引用
--创建窗口
local function onViewCreateHandler(list)
self:addView(list)
end
self.CreateView_BindId = self:Bind(BaseView.CreateView,onViewCreateHandler)
local function close_view()
for k,v in pairs(self.view_list) do
v:Close()
end
self:RemoveCheckOutEvent()
end
self:Bind(EventName.CHANGE_ACCOUNT, close_view)
self:Bind(EventName.CHANGE_ROLE, close_view)
end
end
function BaseController:__delete()
if GlobalEventSystem then
if self.clearViewQuoted_BindId then
GlobalEventSystem:UnBind(self.clearViewQuoted_BindId)
self.clearViewQuoted_BindId = nil
end
if self.CreateView_BindId then
GlobalEventSystem:UnBind(self.CreateView_BindId)
self.CreateView_BindId = nil
end
end
if self.checkout_timer then
for k, timer_id in pairs(self.checkout_timer) do
GlobalTimerQuest:CancelQuest(timer_id)
end
self.checkout_timer = nil
end
end
function BaseController:addView(list)
if list and list[1] then
for k,v in pairs(self) do
if list[1] == v then
table.insert(self.view_list,v)
return
end
end
end
end
--清除view的引用
function BaseController:clearViewQuoted(view)
-- if self._class_type._source == view._source then
--只检测baseitem
local function checkBaseItem(table)
--判断纯队列 或者单个baseitem
if type(table) == "table" and (not table._class_type or table._class_type.Class_Type == "BaseItem" or table._is_uitabwindow) then
if (table._class_type and table._class_type.Class_Type == "BaseItem") or table._is_uitabwindow then
if not table._use_delete_method then
if table._is_uitabwindow then
GlobalEventSystem:Fire(LuaErrorModel.SEND_LUAERROR_MESSAGE,"BaseView没清除UITabWindow")
else
GlobalEventSystem:Fire(LuaErrorModel.SEND_LUAERROR_MESSAGE,view._class_type._source.."有baseitem没deleteMe " .. table._class_type._source)
end
end
else
for k, value in pairs(table) do
checkBaseItem(value)
end
end
end
return
end
for k,v in pairs(self) do
if view == v then
-- for p,value in pairs(view) do
-- if type(value) == "number" then
-- if EventSystem.checkHasUnBind(value) then
-- Alert.show(view._class_type._source.."有事件没解绑 "..p)
-- end
-- end
-- end
if not Application.isMobilePlatform then
for p,value in pairs(view) do
if type(value) == "table" and (not value._class_type or value._class_type.Class_Type == "BaseItem" or value._is_uitabwindow) then
checkBaseItem(value)
end
end
end
self[k] = nil
break
end
end
-- end
end
function BaseController:AddSendFmtCheckout(cmd, time, callback)
self.checkout_timer = self.checkout_timer or {}
local timer_id = self.checkout_timer[cmd]
if timer_id then
GlobalTimerQuest:CancelQuest(timer_id)
timer_id = nil
end
timer_id = GlobalTimerQuest:AddDelayQuest(callback,time)
self.checkout_timer[cmd] = timer_id
end
function BaseController:RemoveSendFmtCheckout(cmd)
if self.checkout_timer then
local timer_id = self.checkout_timer[cmd]
if timer_id then
GlobalTimerQuest:CancelQuest(timer_id)
self.checkout_timer[cmd] = nil
end
end
end
--[[@
功能: 注册一条协议的响应函数
参数:
id 协议号
func_name 继承ProtocalBase类的成员函数名称
返回值:
其它: 无
作者: raowei
]]
function BaseController:RegisterProtocal(id, func_name)
local register_func = nil
register_func = function(data_list)
local oper_func = self[func_name]
if oper_func then
oper_func(self, data_list)
end
if self.checkout_timer then
local timer_id = self.checkout_timer[id]
if timer_id then
GlobalTimerQuest:CancelQuest(timer_id)
self.checkout_timer[id] = nil
end
end
end
UserMsgAdapter.RegisterMsgOperate(id, register_func)
end
--[[@
功能: 根据格式化字符串发送协议内容到Game服
参数:
cmd 指令号 int
fmt_str 格式化字符串(说明请参照文件头部) string
... 发送到协议中的字段
返回值:
其它: 无
作者: raowei
]]
function BaseController.SendFmtFromDelayList(vo)
if vo == nil then return end
local cmd = vo.cmd
local fmt_str = vo.fmt_str
local arg_list = vo.args
UserMsgAdapter.WriteBegin(cmd)
if fmt_str ~= nil then
UserMsgAdapter.WriteFMT(fmt_str, unpack(vo.args))
end
UserMsgAdapter.SendToGame()
end
function BaseController:RegisterProtocal2(id, func)
UserMsgAdapter.RegisterMsgOperate(id, func)
end
function BaseController:SendFmtToGame(cmd, fmt_str, ...)
-- if cmd == 32007 or cmd == 12005 or cmd == 12002 or cmd == 61105 then
-- if not LoginModel:getInstance().show_loading_state or cmd == 32007 or cmd == 12005 or cmd == 12002 or cmd == 61105 then
-- BaseController.SendFmtFromDelayList(vo)
-- else
if ... and cmd ~= 12001 then--12001走路发的协议
print("send cmd log: ",cmd,fmt_str,...)
end
if BaseController.is_delay_send_protocal or BaseController.request_protocals_list:GetSize() > 0 then
local vo = {cmd = cmd, fmt_str = fmt_str, args = {...}}
BaseController.request_protocals_list:PushBack(vo)
else
UserMsgAdapter.SendAllFmtToGame(cmd, fmt_str, ...)
end
-- end
end
function BaseController:SendAllFmtToGame2(cmd, fmt_str, ...)
UserMsgAdapter.SendAllFmtToGame2(cmd, fmt_str, ...)
end
function BaseController.DelaySendFmtToGame()
if BaseController.request_protocals_list:GetSize() > 0 then
local vo = BaseController.request_protocals_list:PopFront()
UserMsgAdapter.SendAllFmtToGame(vo.cmd, vo.fmt_str, unpack(vo.args))
end
end
function BaseController:WriteBegin(cmd)
UserMsgAdapter.WriteBegin(cmd)
end
function BaseController:WriteFMT(fmt_str, ...)
UserMsgAdapter.WriteFMT(fmt_str, ...)
end
function BaseController:SendToGame()
UserMsgAdapter.SendToGame()
end
--[[@
功能: 从协议缓冲区按格式化字符串读取内容
参数:
fmt_str 格式化字符串(参见文件头部说明) string
返回值:
根据格式化字符串返回多个值
其它: 无
作者: raowei
]]
function BaseController:ReadFmt(fmt_str)
return UserMsgAdapter.ReadFmt(fmt_str)
end
--[[@
功能: 绑定事件
参数: 绑定的id,绑定的函数
返回值: 一个事件的handler
其它: 无
作者: raowei
]]
function BaseController:Bind(event_id, event_func,class_name)
return GlobalEventSystem:Bind(event_id,event_func,class_name)
end
--[[@
功能: 解除绑定事件
参数: 事件的handler
返回值: 无
其它: 无
作者: raowei
]]
function BaseController:UnBind( obj )
GlobalEventSystem:UnBind( obj )
end
--[[@
功能: 立即触发事件
参数: 绑定的id,绑定的函数
返回值: 绑定的id,传递的参数
其它: 无
作者: raowei
]]
function BaseController:Fire(event_id,...)
GlobalEventSystem:Fire( event_id ,...)
end
--[[@
功能: 下一帧触发事件
参数: 绑定的id,绑定的函数
返回值: 绑定的id,传递的参数
其它: 无
作者: raowei
]]
function BaseController:FireNextFrame(event_id,...)
GlobalEventSystem:FireNextFrame( event_id ,...)
end
--生成model的绑定请求协议的事件
local function BindReqEvent(self, id, req_event_data, register_func)
local req_event_failed_str = "req net proto " .. id .. " failed with fire event " .. req_event_data[1]
local function on_req( ... )
req_event_data[2] = req_event_data[2] or ""
local need_print = self.proto_info[id].show_print
local arge = {req_event_data[2], ...}
if need_print then
local arge_str = ""
if #arge > 0 then
for i,v in ipairs(arge) do
arge_str = arge_str.."[No."..(i)..":"..tostring(arge[i]).."] "
end
else
arge_str = "none arge"
end
print('Cat:BaseController.lua req net proto : '..id.." arges:", arge_str)
--网络协议的参数数量不对!比如"cii"就只需要传入3个,具体传了哪些见上条打印
local has_proto_field_desc = (arge[1] and type(arge[1])=="string")
local need_assert = has_proto_field_desc and (#arge[1] ~= #arge - 1)
if need_assert then
local error_str = req_event_failed_str..":proto fields num not match!"
assert(false, error_str)
end
end
if not self.proto_info[id].is_debug then
if self.proto_info[id].req_func then
table.remove(arge,1)
self.proto_info[id].req_func( self, unpack(arge))
else
self:SendFmtToGame(id, unpack(arge))
end
else
self.proto_info[id].req_arge = arge
register_func()
end
end
self.model:Bind(req_event_data[1], on_req)
end
--自动生成发送和收到网络协议的处理代码,注:之所以是local function就是不想外部调用
local function RegisterProtocalAndReqEvent(self, id, req_event_data)
local register_func = function()
local proto = self.proto_info[id]
if proto.handler_manual then
proto.handler_manual(self)
return
end
if proto.show_print then
assert(_G["SCMD"..id]~=nil, "cannot find SCMD"..id..".lua, have you generated this proto file yet?")
end
--Cat_Todo : 这里可以考虑用个协议对象池,这样就不需要频繁new协议对象了
local scmd = _G["SCMD"..id].New(not proto.is_debug)
if proto.is_debug and self.CreateDebugSCMD then
--如果该协议的is_debug属性为true,调用handler前将进入CreateDebugSCMD函数,在这里返回一个调试用的结构体模仿收到网络信息,之所以放在一个函数里处理是因为想删掉时可以方便点
scmd = self:CreateDebugSCMD(id, scmd, self.proto_info[id].req_arge)
end
if proto.show_print then
print("Cat:BaseController [start:handle"..id..(proto.is_debug and " Debug Model!" or "").."] scmd:", scmd)
PrintTable(scmd)
print("Cat:BaseController [end]")
end
-- local handler = proto.handler or self["Handle"..id]
if proto.handler then
proto.handler(self, scmd, id)
end
end
UserMsgAdapter.RegisterMsgOperate(id, register_func)
if req_event_data and req_event_data[1] then
BindReqEvent(self, id, req_event_data, register_func)
end
end
--[[说明:
本套做法好处:不再需要手写代码绑定Req请求协议的代码,且发送Req请求协议事件时可以传入收到回复协议的回调函数,所以不再需要触发和监听Ack收到协议的事件;调试代码集中在CreateDebugSCMD函数里方便管理;可以针对某协议开关调试和打印信息,show_print为true时除了打印请求和收到的协议内容,还会判定请求的协议内容是否有问题信息,建议前期开启方便定位bug
具体用法:配置proto_info:
)key值为协议id
)req_event_data会生成self.model的绑定事件,具体生成什么代码见BaseController,为nil就不生成;想请求该协议时可:
req_event_data第一个参数是事件名,后续参数可选,第二个参数必须为 协议内容的格式字符串
)handler就是收到后端回复时的处理函数,触发时机在CreateDebugSCMD之后
)handler_manual就是收到后端回复时的手写处理函数,会绕过部分功能比如CreateDebugSCMD
)req_func就是适应部分自己处理发协议的事件响应,没有的话就用默认方式发,有的话会返回{self, 内容}
)is_debug为true的话将不发送协议,直接回调收到协议的处理函数;
)show_print控制是否在请求和收到协议时打印相关信息
]]--
function BaseController:RegisterProtocalByCFG(proto_info)
self.proto_info = proto_info
self.ack_call_back = self.ack_call_back or {}
for k,v in pairs(self.proto_info) do
RegisterProtocalAndReqEvent(self, k, v.req_event_data)
end
end
--打开界面
function BaseController:OpenView( class_name, show, ... )
if show then
if not self[class_name] then
self[class_name] = _G[class_name].New()
end
if not self[class_name]:HasOpen() then
self[class_name]:Open(...)
end
else
if self[class_name] then
self[class_name]:Close(...)
end
end
end