您的位置:首页 > 移动开发 > Unity3D

kbengine 0.65 读unity3d demo的笔记

2015-07-28 16:50 549 查看
零:kbe大神本人的解析:http://bbs.kbengine.org/forum.php?mod=viewthread&tid=166

一、用unity3d v5.1.2打开,工程文件自动升级了,还可以运行,但左上角的server version和server script version不显示版本号了,更要命的是我不记得当时用unity3d v4.6.1打开的时候这两个值是不是有的,不管啦,不是很重要。

二、Scenes下有个start.unity,内附三个对象,Camera自然是摄像机了,完全没看懂这个摄像机对准了哪里。
  game_render和kbe_clientapp应该是create empty的component。
  game_render下挂了三个脚本,showFPS是用ongui在右上角显示fps,ui是显示登录和注册界面,world应该是显示主游戏画面。

三、ui.cs里,awake()里dontDestroyOnLoad(transform.gameObject),要求不销毁game_render,不知道为什么。
  start()里注册了多个kbe的事件处理函数,用的是kbengine.event.registerOut(),是out哦,不是in。在kbengine插件层的event.cs里是这么说明registerOut()的。“注册监听由kbe插件抛出的事件。通常由渲染表现层来注册“,渲染表现层自然是unity3d了,中间就是kbe插件,unity3d想跟kbe服务器沟通,自然得通过kbe插件来处理,但unity3d是不知道服务器的,他只知道kbe插件。渲染表现层通过事件和kbe插件层沟通,kbe插件向服务器发送数据,服务器返回事件给kbe插件层,kbe插件层再抛出来,渲染层再接收,所以是在ui.cs里写的registerOut()语句。
  然后loadLevel("login"),但不知道为什么要load() login.unity,因为该unity里面只有一个camera。
  ongui()里依据ui_state变量显示不同的ui,默认是0,所以显示loginUI,调用onLoginUI(),然后在左上角显示kbengine服务器和客户端的版本信息和其他出错信息。这里就是我上面说的server version等不显示版本号的地方。onLoginUI()里视点击的按钮不同,login或createAccount()。然后login和createAccount都kbengine.event.fireIn()消息出去了。注意这个fireIn(),上面提到的event.cs里对fireIn()的注释是这样的:“渲染表现层抛出事件,通常由kbe插件层来注册”,也是就是在ui.cs里直接调用fireIn(),由“in这个unity3d渲染表现层“向"out这个kbe插件层“发送event。kbe插件层的kbengine.cs里的installEvents()函数自己事先event.registerIn了createAccount,login,relogin_baseapp,_closeNetwork四个事件。所以渲染层ui.cs发给kbe插件层的login事件,直接由kbengine.cs的login()来处理了。

------以下可以不看,因为在kbe插件层的代码里转来转去,很烦,是用引擎不是拆解引擎,以后再研究吧
  而login()里又调用了kbengineapp.app.login_loginapp(true),login_loginapp(bool noconnect)在noconnect=true时应该是指未登录的情况下登录,则reset(),再_networkInterface.connectTo(),应该是连接服务器了,这里connectTo()有一个回调函数的参数onConnectTo_loginapp_callback,该函数根据currstate与服务器loginapp或baseapp握手。。如果是login_loginapp(false)就报错,返回一个错误信息。
  在_networkInterface.connectTo()里,先new socketk以测试能否连接服务器,用的是beginConnect再endConnect,之后kbe插件层registerIn一个_onConnectStatus事件用于监听由渲染层抛出该事件,而这个事件渲染层根本就没有fireIn抛出来过。然后_networkInterface.connectTo()自己在try beginConnect时,一旦catch exception 就fireIn _onConnectStatus事件,说明注册这个事件是为了kbe插件层自己服务的。另外几个关联的函数也会fireIn同一事件,之后在_onConnectStatus()中deregisterIn()注销掉。
  _onConnectStatus()除了注销所注册的事件,还会根据connect的状态state,new PacketReceiver,之后starRecv(),以及fireAll onConnectStatus事件,最后使用onConnectTo_loginapp_callback回调函数与服务器loginapp握手。
  说到这里已经很乱了,简单点吧,是用kbe,不要是拆kbe,直接看ui.cs里installEvents()里registerOut的事件就行了,其他不要看,反正到了上一步,已经fireAll一个onConnectStatus事件了,在ui.cs里也有对应的处理函数。但我没看到kbe插件层有对应的事件处理函数……  

  接下来就会在kbe插件层里转来转去,就不多说了,参看kbe大神自己的解析。上面我只分析到onConnectStatus事件就打止了。

  1: kbengine_unity3d_demo\Assets\Scripts\u3d_scripts\UI.cs, 向KBE层触发了登陆事件
  2: kbengine_unity3d_demo\Assets\Plugins\kbengine\kbengine_unity3d_plugins\KBEngine.cs, 插件触发登陆函数,并最终向loginapp发送了一个登陆包“Loginapp_login”(注,这是在hello()里发送的)

  服务端部分:
  1:服务端loginapp.cpp中“void Loginapp::login(Network::Channel* pChannel, MemoryStream& s)”被触发, 这个函数进行了一系列的检查,确定合法后向dbmgr发送一个登陆请求包“(*pBundle).newMessage(DbmgrInterface::onAccountLogin);”, dbmgr也会进行一系列的检查并将登陆结果返回到loginapp。
  1.1: loginapp得到dbmgr的登录合法结果后向baseappmgr发送了分配网关(baseapp)请求(registerPendingAccountToBaseapp), 通常是负载较低的一个baseapp进程.
  1.2:baseappmgr最终返回所分配的baseapp的ip地址等信息,loginapp将其转发给客户端(登录成功协议onLoginSuccessfully,包含baseapp的ip和端口信息)
  2: 客户端插件得到返回结果后调用KBEngineApp.cs->login_baseapp()函数开始正式登录到baseapp。
  3:baseapp收到登录请求
  进行了一系列的检查,包括:账号是否已经在线,是否可以在这里登录等等。
  当检查合法后,向dbmgr发送了一个查询账号信息的请求“DbmgrInterface::queryAccount”,dbmgr将查询到的账号数据(包括属性等)返回到baseapp, Baseapp:

nQueryAccountCBFromDbmgr
  当函数结果为合法时,根据配置中定义的账号实体脚本名称“g_serverConfig.getDBMgr().dbAccountEntityScriptType”创建了Account实体, 同时还创建了一个clientMailbox,账号实体中调用clientMailbox->方法()即可与客户端通讯了。
  Account实体被创建后, 首先__init__被调用, 接着onEntitiesEnabled被调用, 此时实体正式可用了。
  账号登陆成功后, 客户端Account.cs中会调用__init__() -> baseCall("reqAvatarList");来请求获得角色列表,
UI.cs中onReqAvatarList得到结果。

  大概了解一下流程即可,登录算是涉及到大部分的kbe模块了,说复杂也是,要简单就直接看demo里的代码。反正返回一个事件,处理就行了。

-----以上可以不看,很乱,而且没写完,说了个大概。

  最终……返回一个onLoginSuccessfully事件就ui_state=1,并loadLevel("selavatars")了,selavatars就一个camera啊,什么都没有,这什么鬼……说不是很懂unity3d会被人笑么?FCK……看起来应该是ui.cs附加在game_render上,而game_render是dontdestroyonload的,同时ui.cs里又有ongui(),所以就是load其他空的.unity,还是可以看到ui.cs里gui出来的画面。同时返回的onReqAvatarList事件附带avatarList,赋值给ui_avatarList,这样登录后就可以选择已创建的角色。如果没有创建过角色,那就新建一个ui_avatarList,并指向kbengineapp.app.player().avatars,之后可以新建角色。这里player()返回的是一个Entity,
  现在ui_state=1后,ongui()就开始onSelAvatarUI()了,使用kbengine.accout来选择角色,loadLevel("world"),并ui_stae=2,这样就跑到onWorldUI()那里去了。
  onWorldUI()里一开始是检查showReliveGUI的值,如果为真就放置一个复活按钮,然后fireIn relive事件。然后gameobject.fine player(clone),显示其坐标,然后就没了。我都不知道怎么进入游戏界面的,而且这个relive事件谁来处理啊?
  找了一圈,在scripts/kbe_scripts下找到了avatars.cs里面registerIn relive,这就奇怪了。看了kbe的文档,说是plugins下的cs文件是KBEngine插件层代码(包含了网络消息处理、客户端实体维护、与服务端对接层),scripts/u3d_scripts是客户端UI等表现层代码,scripts/kbe_scripts是客户端逻辑脚本层,按道理来讲,不应该有客户端逻辑脚本层这类东西,因为表现层只要和插件层沟通就行了,于是作者在https://github.com/kbengine/kbengine_unity3d_demo/blob/master/Assets/Scripts/kbe_scripts/README.md 里面就解释了这个问题:

  

请注意,如果KBEngine插件使用的是多线程模式,kbe_scripts默认在子线程处理,请不要和u3d_scripts直接交互,应该通过KBE提供的事件机制交互。

这个文件夹(kbe_scripts)中的脚本类似于KBEngine资产库中(https://github.com/kbengine/kbengine_demos_assets)scripts/client文件夹的Python逻辑脚本。 KBEngine的理想环境是都使用Python实现游戏逻辑,https://github.com/kbengine/kbengine_demos_assets中scripts之下存在client、base、cell三个文件夹分别对应client、baseapp、cellapp进程的逻辑。 https://github.com/kbengine/kbengine_ogre_demo例子演示了KBE的理想环境,客户端插件(kbengine.dll封装的client_lib)由C++编写,自带了Python解释器与entitydef的分析模块还有网络与消息协议处理等等, 由C++插件驱动scripts/client中的脚本逻辑。

但这种理想环境在Unity3d中无法很好的实现,因此实现了轻量级的Unity3d专用插件(协议与entitydef由服务端网络导入),在Unity3d中使用主流的C#来完成客户端部分的脚本逻辑, 此时KBEngine资产库可以不需要client文件夹。如果没有scripts/client文件夹需要注意一些事项http://www.kbengine.org/cn/docs/configuration/entities.html。

  表示没看明白,是不是想说unity3d实现不了那个客户端插件kbengine.dll,所以就只好把以源码的形式提供了plugins下的一大堆cs当作unity3d专用插件?同时KBEngine资产库下的scripts下面没有client文件夹,被demo工程的scripts/kbe_scripts给代替了?那么问题来了,这个完成客户端部分的脚本逻辑?到底我要完成哪部分?从文件上来看,有account.cs,avatar.cs,clientapp.cs,gate.cs,monstercs,npc.cs等,看来这些是要我们实现的……而本来这部分应该用python写在服务器端的……心好累……

四、world.cs
  游戏界面是由world.cs来处理的,但是没有看到ui.cs里有跳转的语句,如果loadLevel算的话……实际上ui.cs里根本不需要跳转到world.cs里去,world.cs自带update,直接就执行了……好吧,先不要在意这些逻辑上的问题,本来就是demo,再说,有些场景也要预先载入的。然后update就createPlayer(),接着监听空格键和鼠标左键,以fireIn jump和useTargetSkill,这两个事件在scripts/kbe_scripts/avatars.cs里被registerIn,relive事件也是如此,这就是上面说的client代码的部分实现,本来是放在服务器的client目录下的,结果unity3d实现不了,只好放到客户端这边来了……好无语。但这是没办法的事情。

接下来就是client端和world.cs的汪洋大海……

实在看不下去了,去kbe论坛请教kbe大神……没回应

突然想起有部分源码哦,直接在修改那几个register,fire函数,里面增加了Debug.Log,联系kbe自身的log,大概了解了一些。

kbe引擎自己的初始化过程就不说了,直接说他们之间的事件交流,重点在unity3d这一层发出收到了什么

在KBEngine.KBEngineApp:installEvents()里registerIn createAccount, login, relogin_baseapp, _closeNetwork四条事件

然后又是一系列位于KBEngineApp内的流程

接着在ui:installEvents()里 registerOut 一堆事件,这里不写了

接着world:installEvents()里 registerOut一堆事件,略之

登录时,ui:login() fireIn login,KBEngine.login()接收处理

之后 KBEngine.networkinterface registerin _onConnectStatus这个只用于kbe插件层的事件,怎么走我就不说了

最后 客户端client代码组的kbengine.account fireout onLoginsuccessfully事件,这就是要处理的

account 是在__init__()中fireout onloginsuccessfully事件的,说明此时玩家的帐户实体已建立,接下来调用baseCall("reqAvatarList"),这是插件层Entity.cs的一个成员函数,里面会生成一个baseMailbox并postMail,会调用服务器scripts/base/Account.py里的 def reqAvatarList(),python苦手,看不太懂,里面有一句 self.client.onReqAvatarList(self.characters),结果调用的是client代码组的Account.cs里的onReqAvatarList(),看结果已经返回了帐户里的角色组,最终由ui.cs里的onReqAvatarList()来处理。

……

我有一种日狗的感觉,总之不用管上面的,直接处理onReqAvatarList事件就行了。

登录后,执行avatar.cs,registerIn relive, useTargetskill, jump三个事件,fireOut onAvatarEnterWorld,onEnterworld, set_hp_max, set_mp_max, set_position, se_direction, onenterspace等一系列事件(中间报错说onEnterspace未找到,不知道什么意思)

这里小结一下。

一、unity3d的这个demo,有两层,一层是unity3d的代码组成的渲染表现层,一层是kbe插件层,这两层之间通过事件交互。

二、但demo下还有一个kbe_scripts,这是因为unity3d没办法实现和orge那样一个kbengine.dll的插件,只能提供源码方式的插件,这就是demo下的plugins目录里的代码,而这个kbe_scripts代表的是服务器里的client代码,却不能放在服务器,结果只好放在客户端了,等于服务器client,base他们之间的交互,变成了客户端kbe_scripts和服务器base他们之间的交互,我日……这架构。不过作者也说了,没办法,只能这么实现。

三、目前只要关注那些事件的走向就行了,kbe里面怎么走的,先不管,一个引擎不要用得这么麻烦
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: