|
|
|
|
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
|