基于tolua的客户端框架

Lua框架

1、C#层可以实现解压、更新、资源管理、网络等模块,这里主要实现Lua层框架。启动流程一般为:检查解压、检查更新、初始化资源、加载Lua虚拟机,Lua框架初始化。Lua层使用MVC架构,入口为Main.lua。

2、这里使用插件middleclass.lua模拟类。

3、用到了一些注解,这些注解与lua语法没有任何关系,主要是为了更好的使用EmmyLua插件进行调试,具体含义可参考EmmyLua注解功能

local middleclass = require "3rd.middleclass"
--定义类--
function _G.class(name, super) 
    return middleclass(name, super)
end

入口

_G.Main={}
_G.MgrCenter = nil
require "Common/define"
require "Common/functions"
require "Common/protocol"
_G.LuaUtil=nil;

---@type ManagerCenter
local ManagerCenter=require("Common.ManagerCenter")

---@type NetworkManager
local netMgr=nil;
---@type CtrlManager
local ctrlMgr=nil;

---初始化框架
function Main.Initalize()
    Main.InitManager();
    log("lua init finish");
end 

function Main.InitManager()
    MgrCenter=ManagerCenter:new();
    MgrCenter:Initialize();
    LuaUtil=require("Common.LuaUtil")

    netMgr=MgrCenter:GetManager(ManagerNames.Network);
    ctrlMgr=MgrCenter:GetManager(ManagerNames.Ctrl);

    ctrlMgr:GetCtrl(UINames.Setting):InitSetting();     --基本设置加载
end

function Main.OnDispose()
    MgrCenter:OnDispose();
    MgrCenter=nil;
    netMgr=nil;
    ctrlMgr=nil;
end

---接收C#层发来的网络数据包
---@param proto string
---@param data table
function Main.OnReceived(proto,data)
    log(proto);
    netMgr:OnReceived(proto,data);
end

---@param uiCtrlName string
---@param active boolean
---@param onFinish function
function Main.ShowUI(uiCtrlName,active,onFinish)
    local ctrl=ctrlMgr:GetCtrl(uiCtrlName);
    if ctrl ==nil then
        logError("show ctrl was nil")
        return;
    end 
    
    ctrl:ShowUI(active,onFinish);
end

--显示showUICtrlName前先关闭closeuiCtrlName
---@param showUICtrlName string
---@param closeuiCtrlName string
---@param onFinish function
function Main.ShowUIClose(showUICtrlName,closeuiCtrlName,onFinish)
    local showCtrl=ctrlMgr:GetCtrl(showUICtrlName);
    local closeCtrl=ctrlMgr:GetCtrl(closeuiCtrlName);

    if showCtrl ==nil then
        logError("show ctrl was nil")
        return;
    elseif closeCtrl ==nil then
        logError("close ctrl was nil");
        return;
    end

    showCtrl:ShowUI(true,function()  --加载完毕后再卸载上一个UI
        closeCtrl:ShowUI(false,onFinish);
    end)
end

Main.Initalize();
Main.ShowUI(UINames.Login,true);

总管理器

---@type BaseManager
local BaseManager=require("Manager.BaseManager")
---@class ManagerCenter
local ManagerCenter = class("ManagerCenter",BaseManager)

function ManagerCenter:Initialize()
    BaseManager.Initialize(self);
    self.managers = {}
    --C# Manager--
    self:AddManager(ManagerNames.Resource, self:GetCSharpManager(ManagerNames.Resource))
    self:AddManager(ManagerNames.Socket, self:GetCSharpManager("NetworkManager"))
    self:AddManager(ManagerNames.Sound, self:GetCSharpManager(ManagerNames.Sound))
    self:AddManager(ManagerNames.Shader, self:GetCSharpManager(ManagerNames.Shader))

    --Lua Manager--
    self:AddManager(ManagerNames.Network, require "Manager.NetworkManager", true)
    self:AddManager(ManagerNames.Event, require "Manager.EventManager",true)
    self:AddManager(ManagerNames.Ctrl, require "Manager.CtrlManager", true)
    self:AddManager(ManagerNames.Module, require "Manager.ModuleManager", true)
    self:AddManager(ManagerNames.Handler, require "Manager.HandlerManager", true)
    self:AddManager(ManagerNames.Level, require "Manager.LevelManager", true)
    
    self:AddManager(ManagerNames.UI, require "Manager.UIManager", true)
    self:AddManager(ManagerNames.Panel, require "Manager.PanelManager", true)
    log('ManagerCenter:InitializeOK...')
end

function ManagerCenter:OnDispose()
    BaseManager.OnDispose(self);
    --C# Manager
    self:RemoveManager(ManagerNames.Resource)
    self:RemoveManager(ManagerNames.Socket)
    self:RemoveManager(ManagerNames.Sound)
    self:RemoveManager(ManagerNames.Shader)

    --C# Ext Manager--

    --Lua Manager--
    self:RemoveManager(ManagerNames.Network,true)
    self:RemoveManager(ManagerNames.Event,true)
    self:RemoveManager(ManagerNames.Ctrl,true)
    self:RemoveManager(ManagerNames.Module,true)
    self:RemoveManager(ManagerNames.Handler,true)
    self:RemoveManager(ManagerNames.Level, true)
    
    self:RemoveManager(ManagerNames.UI,true)
    self:RemoveManager(ManagerNames.Panel,true)
    log("ManagerCenter OnDispose...")
end

function ManagerCenter:AddManager(name, manager, isLuaMgr)
    if name == nil or manager == nil then
        logError('ManagerCenter:AddManager Error!! '..name..' was nil.')
        return
    end
    self.managers[name] = manager

    isLuaMgr = isLuaMgr or nil
    if isLuaMgr == true then
        if name == ManagerNames.Table then
            manager.Initialize()
        else
            manager:Initialize()
        end
    end
end

function ManagerCenter:GetManager(name)
    if name==nil then
        logError("the name is nil when get managered");
        return nil;
    end
    return self.managers[name]
end

function ManagerCenter:RemoveManager(name,isLuaMgr)
    local manager=table.removeKey(self.managers, name)
    if manager~=nil then
        isLuaMgr = isLuaMgr or nil
        if isLuaMgr==true then
            manager:OnDispose();
        end
        manager=nil;
    end
end

function ManagerCenter:GetCSharpManager(name)
    return LuaHelper.GetManager(name)
end

function ManagerCenter:GetExtManager(name)
    return LuaHelper.GetManager(name)
end

return ManagerCenter

UI管理

---@type BaseManager
local BaseManager=require("Manager.BaseManager")
---@class UIManager
local UIManager = class("UIManager",BaseManager)

function UIManager:Initialize()    --层级管理
    BaseManager.Initialize(self);
    self.MainCanvas=findByTag("UICanvas").transform;
    self.mLayers = {}

    self:InitUILayers()
    log('UIManager:InitializeOK...')
end

function UIManager:InitUILayers()
    self:CreateLayer('MapAbout', UILayer.MapAbout)
    self:CreateLayer('Fixed', UILayer.Fixed)
    self:CreateLayer('Common', UILayer.Common)
    self:CreateLayer('Movie', UILayer.Movie)
    self:CreateLayer('Effect', UILayer.Effect)
    self:CreateLayer('Top', UILayer.Top)
end

function UIManager:CreateLayer(name, layerType)
    local layerName = name..'_Layer'
    local layerObj = GameObject.New(layerName)
    layerObj.layer = LayerMask.NameToLayer("UI")
    layerObj.transform:SetParent(self.MainCanvas.transform,false)
    layerObj.transform.localScale = Vector3.one

    local rectType = typeof(RectTransform);
    local rect = layerObj:AddComponent(rectType)
    rect.anchorMin = Vector2.zero
    rect.anchorMax = Vector2.one
    rect.sizeDelta = Vector2.zero
    rect.anchoredPosition3D = Vector3.zero
    rect:SetSiblingIndex(layerType)

    self.mLayers[layerType] = layerObj
end

function UIManager:GetLayer(layerType)
    return self.mLayers[layerType]
end

return UIManager

---@type BaseManager
local BaseManager=require("Manager.BaseManager")
---@class PanelManager
local PanelManager = class("PanelManager",BaseManager)

UI资源管理

function PanelManager:Initialize() 
    BaseManager.Initialize(self);
    self.mPanels = {}
    self.mCtrls = {}
    self.resMgr = MgrCenter:GetManager(ManagerNames.Resource)
    ---@type UIManager
    self.uiMgr = MgrCenter:GetManager(ManagerNames.UI)

    log('PanelManager:InitializeOK...')
end

function PanelManager:OnDispose()
    BaseManager.OnDispose(self);
    --删除所有ctrl
    for abName,ctrl in pairs(self.mCtrls) do
        self:DestroyPanel(abName);
        self.mCtrls[abName]=nil;
    end
    self.mPanels=nil;
    self.resMgr=nil;
    self.uiMgr=nil;
end

---@param uiCtrlName string
---@return table
function PanelManager:GetPanelCtrl(uiCtrlName)
    return self.mCtrls[uiCtrlName]
end

---@param ctrl table
---@param layer table
---@param abName string
---@param onAwake function
function PanelManager:CreatePanel(ctrl, layer, abName, onAwake)
    local panelName = abName.."Panel";
    local parent = self.uiMgr:GetLayer(layer).transform;
    self.mCtrls[abName] = ctrl;

    local abPath = "Prefabs/UI/"..abName.."/"..panelName;   --兼容AssetDatabase
    self.resMgr:LoadAssetAsync(abPath, { panelName }, typeof(GameObject), function(objs) 
        if objs ~= nil and objs[0] ~= nil then
            self:CreatePanelInternal(ctrl, panelName, objs[0], parent, onAwake)
        end
    end)
    log("CreatePanel::>>"..abName)
end

function PanelManager:CreatePanelInternal(ctrl, panelName, prefab, parent, onAwake)
    local gameObj = newObject(prefab)
    gameObj.name = panelName;
    gameObj.layer = LayerMask.NameToLayer("UI");
    gameObj.transform:SetParent(parent,false);

    local behaviour = gameObj:AddComponent(typeof(LuaBehaviour))
    ctrl:InitUI(behaviour)
    if onAwake ~= nil then
        onAwake(ctrl)
    end
    self.mPanels[panelName] = gameObj;      
end

---销毁UI
---@param abName string
function PanelManager:DestroyPanel(abName)
    local ctrl=self:ClosePanel(abName);

    local panelName = abName.."Panel";
    local removeGameObj = table.removeKey(self.mPanels, panelName)  
    if removeGameObj ~= nil then
        if ctrl~=nil then
            ctrl:OnDestroy();
        end
        destroy(removeGameObj);
    end
end

---关闭UI
---@param abName string
---@return any ctrl
function PanelManager:ClosePanel(abName)
    local ctrl = self.mCtrls[abName];
    if ctrl then
        ctrl:ShowUI(false);
    end
    return ctrl;
end

---关闭所有UI
function PanelManager:CloseAllPanel()
    for abName,ctrl in pairs(self.mCtrls) do
        ctrl:ShowUI(false);
    end
end
 
return PanelManager

UI控制层父类

---@class UIBaseCtrl
local UIBaseCtrl = class("UIBaseCtrl")
UIBaseCtrl.gameObject = nil
UIBaseCtrl.isUsing=false; 

---@param onAwake function InitUI之后调用
function UIBaseCtrl:Awake(onAwake)
    logError("not found ui contrller")
end

function UIBaseCtrl:Start() --初始化资源后调用一次
end

---PanelManager生成时调用
---@param behaviour table UI初始化
function UIBaseCtrl:InitUI(behaviour)
    self.behaviour = behaviour
    self.gameObject = behaviour.gameObject
    self.transform=behaviour.transform;
    self:InitUIBinder()
end

---显示或隐藏UI面板
---@param isShow boolean
---@param onFinish function
function UIBaseCtrl:ShowUI(isShow,onFinish)
    if isShow == nil or isShow == true then
        if isnil(self.gameObject) then  --未加载Panel
            self:Awake(function()   
                self:Start();
                self:OnOpen();
                if onFinish then
                    onFinish();
                end
            end)
        else
            self.gameObject:SetActive(true) --已加载过
            self:OnOpen();
            if onFinish then
                onFinish();
            end
        end
    else
        if not isnil(self.gameObject) then
            self.gameObject:SetActive(false)
            self:OnClose();
            if onFinish then
                onFinish();
            end
        else
            logWarn("the ui gameObject is nil when show ui false")
        end
    end
end

function UIBaseCtrl:InitUIBinder() --自动加载组件
    if isnil(self.gameObject) then 
        return
    end
    self.mPrefabVars = {}
    local prefabVar = self.gameObject:GetComponent('CPrefabVar')

    if not isnil(prefabVar) then
        local varData = prefabVar:GetVarArray()
        local iter = varData:GetEnumerator()
        while iter:MoveNext() do
            local varObj = iter.Current
            if not isnil(varObj) then
                table.insert(self.mPrefabVars, varObj.name)
                --print(self.gameObject.name, varObj.name, varObj.type)
                if varObj.type == VarType.GameObject then
                    self[varObj.name] = varObj.objValue
                elseif varObj.type == VarType.Transform then
                    self[varObj.name] = varObj.tranValue
                elseif varObj.type == VarType.Image then
                    self[varObj.name] = varObj.imgValue
                elseif varObj.type == VarType.Text then
                    self[varObj.name] = varObj.txtValue
                elseif varObj.type == VarType.Button then
                    self[varObj.name] = varObj.btnValue
                elseif varObj.type == VarType.TMP_InputField then
                    self[varObj.name] = varObj.inputValue
                elseif varObj.type == VarType.Toggle then
                    self[varObj.name] = varObj.toggleValue
                elseif varObj.type == VarType.Slider then
                    self[varObj.name] = varObj.sliderValue
                elseif varObj.type == VarType.CMultiProgressBar then
                    self[varObj.name] = varObj.multiProgreValue
                end
            end
        end
    end
end

function UIBaseCtrl:ClearUIBinder()
    if self.mPrefabVars ~= nil then
        for _, value in ipairs(self.mPrefabVars) do
            self[value] = nil
        end
        self.mPrefabVars = nil
    end
end

function UIBaseCtrl:OnDestroy()
    self:ClearUIBinder()
    self.behaviour=nil;
    self.gameObject=nil;
    self.transform=nil;
end

function UIBaseCtrl:OnOpen()
    self.isUsing=true;
    log(self.gameObject.name.." on open");
end

function UIBaseCtrl:OnClose()
    self.isUsing=false;
    log(self.gameObject.name.." on close");
end

return UIBaseCtrl

登录页面控制

---@type UIBaseCtrl
local UIBaseCtrl = require "UIController/UIBaseCtrl"
---@class UILoginCtrl
local UILoginCtrl=class("UILoginCtrl",UIBaseCtrl)

---@param onAwake function
function UILoginCtrl:Awake(onAwake)
    ---@type PanelManager
    self.panelMgr=MgrCenter:GetManager(ManagerNames.Panel)
    ---@type UserModule
    self.userModule=MgrCenter:GetManager(ManagerNames.Module):GetModule(ModuleNames.User);

    self.panelMgr:CreatePanel(self, UILayer.Fixed, UINames.Login, function()
        onAwake();

        self:InitUserSetting();
        if self["toggle_autoLogin"].isOn==true and self["toggle_rememberPsd"].isOn==true then   --自动登录
            self:RequestLogin();
        end
    end)
    log("UILoginCtrl.Awake--->>")
end

function UILoginCtrl:OnDestroy()
    UIBaseCtrl.OnDestroy(self);
    self.panelMgr=nil;
    self.userModule=nil;
end

function UILoginCtrl:OnOpen()
    UIBaseCtrl.OnOpen(self);

    self:InitUserSetting();
    self.behaviour:AddClick(self["btn_login"],self,self.RequestLogin)

    self.behaviour:AddClick(self["btn_register"],self,function()
        Main.ShowUIClose(UINames.Register,UINames.Login)
    end)
end

function UILoginCtrl:OnClose()
    UIBaseCtrl.OnClose(self);

    self.behaviour:RemoveClick(self.btn_login);
    self:SavaUserSettings();
end

function UILoginCtrl:RequestLogin()
    local txt_account=self["input_user"].text;
    local txt_password=self["input_password"].text;

    self.userModule:ReqLogin(txt_account,txt_password);
end

function UILoginCtrl:ResponseLogin(respLogin)
    if respLogin.resultCode==ResultCode.Success then
        Main.ShowUIClose(UINames.Lobby,UINames.Login);

        NativeIDList.userId=respLogin.userId;
    else
        LuaUtil.LoadHint("登录失败!",HintType.Warning);
        logWarn("login faild");
    end
end


function UILoginCtrl:InitUserSetting()
    local account=PlayerPrefs.GetString("account");--存在记录,自动填入账号
    if account~=nil then  
        self["input_user"].text=account;
        self["input_password"].text=PlayerPrefs.GetString("password");
    end

    local autoLogin=PlayerPrefs.GetInt("autoLogin");    --自动登录设置显示
    if autoLogin==nil or autoLogin==0 then
        self["toggle_autoLogin"].isOn=false;
    else
        self["toggle_autoLogin"].isOn=true;
    end

    local remeberPsd=PlayerPrefs.GetInt("remeberPsd");  --记住密码设置显示
    if remeberPsd==nil or remeberPsd==0 then
        self["toggle_rememberPsd"].isOn=false;
    else
        self["toggle_rememberPsd"].isOn=true;
    end
end

function UILoginCtrl:SavaUserSettings()
    PlayerPrefs.SetString("account",self["input_user"].text);   --保存账号

    if self["toggle_autoLogin"].isOn then
        PlayerPrefs.SetInt("autoLogin",1);  --自动登录设置
    else
        PlayerPrefs.SetInt("autoLogin",0); 
    end

    if self["toggle_rememberPsd"].isOn then
        PlayerPrefs.SetInt("remeberPsd",1);  --保存密码设置
        PlayerPrefs.SetString("password",self["input_password"].text);
    else
        PlayerPrefs.SetInt("remeberPsd",0); 
        PlayerPrefs.SetString("password","");
    end
end

return UILoginCtrl

你可能感兴趣的:(基于tolua的客户端框架)