diff --git a/Assets/Plugins/kbengine/kbengine_unity3d_plugins/KBEngine.cs b/Assets/Plugins/kbengine/kbengine_unity3d_plugins/KBEngine.cs index d35654cf..e98a4984 100644 --- a/Assets/Plugins/kbengine/kbengine_unity3d_plugins/KBEngine.cs +++ b/Assets/Plugins/kbengine/kbengine_unity3d_plugins/KBEngine.cs @@ -1,2476 +1,2476 @@ -namespace KBEngine -{ - using UnityEngine; - using System; - using System.Collections; - using System.Collections.Generic; - using System.Text; - using System.Threading; - using System.Text.RegularExpressions; - - using MessageID = System.UInt16; - using MessageLength = System.UInt16; - - /* - 这是KBEngine插件的核心模块 - 包括网络创建、持久化协议、entities的管理、以及引起对外可调用接口。 - - 一些可以参考的地方: - http://kbengine.github.io/docs/programming/clientsdkprogramming.html - http://kbengine.github.io/docs/programming/kbe_message_format.html - - http://kbengine.github.io/cn/docs/programming/clientsdkprogramming.html - http://kbengine.github.io/cn/docs/programming/kbe_message_format.html - */ - public class KBEngineApp - { - public static KBEngineApp app = null; - private NetworkInterface _networkInterface = null; - - KBEngineArgs _args = null; - - // 客户端的类别 - // http://kbengine.github.io/docs/programming/clientsdkprogramming.html - // http://kbengine.github.io/cn/docs/programming/clientsdkprogramming.html - public enum CLIENT_TYPE - { - // Mobile(Phone, Pad) - CLIENT_TYPE_MOBILE = 1, - - // Windows Application program - CLIENT_TYPE_WIN = 2, - - // Linux Application program - CLIENT_TYPE_LINUX = 3, - - // Mac Application program - CLIENT_TYPE_MAC = 4, - - // Web,HTML5,Flash - CLIENT_TYPE_BROWSER = 5, - - // bots - CLIENT_TYPE_BOTS = 6, - - // Mini-Client - CLIENT_TYPE_MINI = 7, - }; - - //加密通信类型 - public enum NETWORK_ENCRYPT_TYPE - { - //无加密 - ENCRYPT_TYPE_NONE = 0, - - //Blowfish - ENCRYPT_TYPE_BLOWFISH = 1, - }; - - public string username = "kbengine"; - public string password = "123456"; - - // 服务端分配的baseapp地址 - public string baseappIP = ""; - public UInt16 baseappPort = 0; - - // 当前状态 - public string currserver = ""; - public string currstate = ""; - - // 服务端下行以及客户端上行用于登录时处理的账号绑定的二进制信息 - // 该信息由用户自己进行扩展 - private byte[] _serverdatas = new byte[0]; - private byte[] _clientdatas = new byte[0]; - - // 通信协议加密,blowfish协议 - private byte[] _encryptedKey = new byte[0]; - - // 服务端与客户端的版本号以及协议MD5 - public string serverVersion = ""; - public string clientVersion = "1.3.4"; - public string serverScriptVersion = ""; - public string clientScriptVersion = "0.1.0"; - public string serverProtocolMD5 = "13AF19B0A958067AEB2BC4ED1CD3B46F"; - public string serverEntitydefMD5 = "2B445B443EFC9427000733CD39EB2700"; - - // 当前玩家的实体id与实体类别 - public UInt64 entity_uuid = 0; - public Int32 entity_id = 0; - public string entity_type = ""; - - private List _controlledEntities = new List(); - - // 当前服务端最后一次同步过来的玩家位置 - private Vector3 _entityServerPos = new Vector3(0f, 0f, 0f); - - // space的数据,具体看API手册关于spaceData - // https://github.com/kbengine/kbengine/tree/master/docs/api - private Dictionary _spacedatas = new Dictionary(); - - // 所有实体都保存于这里, 请参看API手册关于entities部分 - // https://github.com/kbengine/kbengine/tree/master/docs/api - public Dictionary entities = new Dictionary(); - - // 在玩家View范围小于256个实体时我们可以通过一字节索引来找到entity - private List _entityIDAliasIDList = new List(); - private Dictionary _bufferedCreateEntityMessages = new Dictionary(); - - // 所有服务端错误码对应的错误描述 - private ServerErrorDescrs _serverErrs = new ServerErrorDescrs(); - - private System.DateTime _lastTickTime = System.DateTime.Now; - private System.DateTime _lastTickCBTime = System.DateTime.Now; - private System.DateTime _lastUpdateToServerTime = System.DateTime.Now; - - //上传玩家信息到服务器间隔,单位毫秒 - private float _updatePlayerToServerPeroid = 100.0f; - private const int _1MS_TO_100NS = 10000; - - //加密过滤器 - private EncryptionFilter _filter = null; - - // 玩家当前所在空间的id, 以及空间对应的资源 - public UInt32 spaceID = 0; - public string spaceResPath = ""; - public bool isLoadedGeometry = false; - - // 按照标准,每个客户端部分都应该包含这个属性 - public const string component = "client"; - - public KBEngineApp(KBEngineArgs args) - { - if (app != null) - throw new Exception("Only one instance of KBEngineApp!"); - - app = this; - Event.outEventsImmediately = !args.isMultiThreads; - - initialize(args); - } - - public static KBEngineApp getSingleton() - { - if(KBEngineApp.app == null) - { - throw new Exception("Please create KBEngineApp!"); - } - - return KBEngineApp.app; - } - - public virtual bool initialize(KBEngineArgs args) - { - _args = args; - _updatePlayerToServerPeroid = (float)_args.syncPlayerMS; - - EntityDef.init(); - - initNetwork(); - - // 注册事件 - installEvents(); - - return true; - } - - void initNetwork() - { - _filter = null; - Messages.init(); - _networkInterface = new NetworkInterface(); - } - - void installEvents() - { - Event.registerIn(EventInTypes.createAccount, this, "createAccount"); - Event.registerIn(EventInTypes.login, this, "login"); - Event.registerIn(EventInTypes.logout, this, "logout"); - Event.registerIn(EventInTypes.reloginBaseapp, this, "reloginBaseapp"); - Event.registerIn(EventInTypes.resetPassword, this, "resetPassword"); - Event.registerIn(EventInTypes.bindAccountEmail, this, "bindAccountEmail"); - Event.registerIn(EventInTypes.newPassword, this, "newPassword"); - - // 内部事件 - Event.registerIn("_closeNetwork", this, "_closeNetwork"); - } - - public KBEngineArgs getInitArgs() - { - return _args; - } - - public virtual void destroy() - { - Dbg.WARNING_MSG("KBEngine::destroy()"); - - if(currserver == "baseapp") - logout(); - - reset(); - KBEngine.Event.deregisterIn(this); - resetMessages(); - - KBEngineApp.app = null; - } - - public NetworkInterface networkInterface() - { - return _networkInterface; - } - - public byte[] serverdatas() - { - return _serverdatas; - } - - public void entityServerPos(Vector3 pos) - { - _entityServerPos = pos; - } - - public void resetMessages() - { - _serverErrs.Clear(); - Messages.clear(); - EntityDef.reset(); - - Entity.clear(); - Dbg.DEBUG_MSG("KBEngine::resetMessages()"); - } - - public virtual void reset() - { - KBEngine.Event.clearFiredEvents(); - - clearEntities(true); - - currserver = ""; - currstate = ""; - _serverdatas = new byte[0]; - serverVersion = ""; - serverScriptVersion = ""; - - entity_uuid = 0; - entity_id = 0; - entity_type = ""; - - _entityIDAliasIDList.Clear(); - _bufferedCreateEntityMessages.Clear(); - - _lastTickTime = System.DateTime.Now; - _lastTickCBTime = System.DateTime.Now; - _lastUpdateToServerTime = System.DateTime.Now; - - spaceID = 0; - spaceResPath = ""; - isLoadedGeometry = false; - - if (_networkInterface != null) - _networkInterface.reset(); - - _filter = null; - _networkInterface = new NetworkInterface(); - - _spacedatas.Clear(); - } - - public static bool validEmail(string strEmail) - { - return Regex.IsMatch(strEmail, @"^([\w-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.) - |(([\w-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$"); - } - - /* - 插件的主循环处理函数 - */ - public virtual void process() - { - // 处理网络 - if (_networkInterface != null) - _networkInterface.process(); - - // 处理外层抛入的事件 - Event.processInEvents(); - - // 向服务端发送心跳以及同步角色信息到服务端 - sendTick(); - } - - /* - 当前玩家entity - */ - public Entity player() - { - Entity e; - if(entities.TryGetValue(entity_id, out e)) - return e; - - return null; - } - - public void _closeNetwork(NetworkInterface networkInterface) - { - networkInterface.close(); - } - - /* - 向服务端发送心跳以及同步角色信息到服务端 - */ - public void sendTick() - { - if(_networkInterface == null || _networkInterface.connected == false) - return; - - TimeSpan span = DateTime.Now - _lastTickTime; - - // 更新玩家的位置与朝向到服务端 - updatePlayerToServer(); - - if(_args.serverHeartbeatTick > 0 && span.Seconds > _args.serverHeartbeatTick) - { - span = _lastTickCBTime - _lastTickTime; - - // 如果心跳回调接收时间小于心跳发送时间,说明没有收到回调 - // 此时应该通知客户端掉线了 - if(span.Seconds < 0) - { - Dbg.ERROR_MSG("sendTick: Receive appTick timeout!"); - _networkInterface.close(); - return; - } - - Message Loginapp_onClientActiveTickMsg = null; - Message Baseapp_onClientActiveTickMsg = null; - - Messages.messages.TryGetValue("Loginapp_onClientActiveTick", out Loginapp_onClientActiveTickMsg); - Messages.messages.TryGetValue("Baseapp_onClientActiveTick", out Baseapp_onClientActiveTickMsg); - - if(currserver == "loginapp") - { - if(Loginapp_onClientActiveTickMsg != null) - { - Bundle bundle = Bundle.createObject(); - bundle.newMessage(Messages.messages["Loginapp_onClientActiveTick"]); - bundle.send(_networkInterface); - } - } - else - { - if(Baseapp_onClientActiveTickMsg != null) - { - Bundle bundle = Bundle.createObject(); - bundle.newMessage(Messages.messages["Baseapp_onClientActiveTick"]); - bundle.send(_networkInterface); - } - } - - _lastTickTime = System.DateTime.Now; - } - } - - /* - 服务器心跳回调 - */ - public void Client_onAppActiveTickCB() - { - _lastTickCBTime = System.DateTime.Now; - } - - /* - 与服务端握手,与任何一个进程连接之后应该第一时间进行握手 - */ - public void hello() - { - Bundle bundle = Bundle.createObject(); - if(currserver == "loginapp") - bundle.newMessage(Messages.messages["Loginapp_hello"]); - else - bundle.newMessage(Messages.messages["Baseapp_hello"]); - - _filter = null; - - if (_args.networkEncryptType == NETWORK_ENCRYPT_TYPE.ENCRYPT_TYPE_BLOWFISH) - { - _filter = new BlowfishFilter(); - _encryptedKey = ((BlowfishFilter)_filter).key(); - _networkInterface.setFilter(null); - } - - bundle.writeString(clientVersion); - bundle.writeString(clientScriptVersion); - bundle.writeBlob(_encryptedKey); - bundle.send(_networkInterface); - } - - /* - 握手之后服务端的回调 - */ - public void Client_onHelloCB(MemoryStream stream) - { - string str_serverVersion = stream.readString(); - serverScriptVersion = stream.readString(); - string currentServerProtocolMD5 = stream.readString(); - string currentServerEntitydefMD5 = stream.readString(); - Int32 ctype = stream.readInt32(); - - Dbg.DEBUG_MSG("KBEngine::Client_onHelloCB: verInfo(" + str_serverVersion - + "), scriptVersion("+ serverScriptVersion + "), srvProtocolMD5("+ serverProtocolMD5 - + "), srvEntitydefMD5("+ serverEntitydefMD5 + "), + ctype(" + ctype + ")!"); - - if(str_serverVersion != "Getting") - { - serverVersion = str_serverVersion; - - /* - if(serverProtocolMD5 != currentServerProtocolMD5) - { - Dbg.ERROR_MSG("Client_onHelloCB: digest not match! serverProtocolMD5=" + serverProtocolMD5 + "(server: " + currentServerProtocolMD5 + ")"); - Event.fireAll(EventOutTypes.onVersionNotMatch, clientVersion, serverVersion); - return; - } - */ - - if (serverEntitydefMD5 != currentServerEntitydefMD5) - { - Dbg.ERROR_MSG("Client_onHelloCB: digest not match! serverEntitydefMD5=" + serverEntitydefMD5 + "(server: " + currentServerEntitydefMD5 + ")"); - Event.fireAll(EventOutTypes.onVersionNotMatch, clientVersion, serverVersion); - return; - } - } - - if (_args.networkEncryptType == NETWORK_ENCRYPT_TYPE.ENCRYPT_TYPE_BLOWFISH) - { - _networkInterface.setFilter(_filter); - _filter = null; - } - - - onServerDigest(); - - if(currserver == "baseapp") - { - onLogin_baseapp(); - } - else - { - onLogin_loginapp(); - } - } - - /* - 服务端错误描述导入了 - */ - public void Client_onImportServerErrorsDescr(MemoryStream stream) - { - // 无需实现,已由插件生成静态代码 - } - - /* - 从服务端返回的二进制流导入客户端消息协议 - */ - public void Client_onImportClientMessages(MemoryStream stream) - { - // 无需实现,已由插件生成静态代码 - } - - /* - 从服务端返回的二进制流导入客户端消息协议 - */ - public void Client_onImportClientEntityDef(MemoryStream stream) - { - // 无需实现,已由插件生成静态代码 - } - - public void Client_onImportClientSDK(MemoryStream stream) - { - int remainingFiles = 0; - remainingFiles = stream.readInt32(); - - string fileName; - fileName = stream.readString(); - - int fileSize = 0; - fileSize = stream.readInt32(); - - byte[] fileDatas = new byte[0]; - fileDatas = stream.readBlob(); - - Event.fireIn("onImportClientSDK", remainingFiles, fileName, fileSize, fileDatas); - } - - /* - 引擎版本不匹配 - */ - public void Client_onVersionNotMatch(MemoryStream stream) - { - serverVersion = stream.readString(); - - Dbg.ERROR_MSG("Client_onVersionNotMatch: verInfo=" + clientVersion + "(server: " + serverVersion + ")"); - Event.fireAll(EventOutTypes.onVersionNotMatch, clientVersion, serverVersion); - } - - /* - 脚本版本不匹配 - */ - public void Client_onScriptVersionNotMatch(MemoryStream stream) - { - serverScriptVersion = stream.readString(); - - Dbg.ERROR_MSG("Client_onScriptVersionNotMatch: verInfo=" + clientScriptVersion + "(server: " + serverScriptVersion + ")"); - Event.fireAll(EventOutTypes.onScriptVersionNotMatch, clientScriptVersion, serverScriptVersion); - } - - /* - 被服务端踢出 - */ - public void Client_onKicked(UInt16 failedcode) - { - Dbg.DEBUG_MSG("Client_onKicked: failedcode=" + failedcode + "(" + serverErr(failedcode) + ")"); - Event.fireAll(EventOutTypes.onKicked, failedcode); - } - - /* - 登录到服务端,必须登录完成loginapp与网关(baseapp),登录流程才算完毕 - */ - public void login(string username, string password, byte[] datas) - { - KBEngineApp.app.username = username; - KBEngineApp.app.password = password; - KBEngineApp.app._clientdatas = datas; - - KBEngineApp.app.login_loginapp(true); - } - - /* - 登录到服务端(loginapp), 登录成功后还必须登录到网关(baseapp)登录流程才算完毕 - */ - public void login_loginapp(bool noconnect) - { - if(noconnect) - { - reset(); - _networkInterface.connectTo(_args.ip, _args.port, onConnectTo_loginapp_callback, null); - } - else - { - Dbg.DEBUG_MSG("KBEngine::login_loginapp(): send login! username=" + username); - Bundle bundle = Bundle.createObject(); - bundle.newMessage(Messages.messages["Loginapp_login"]); - bundle.writeInt8((sbyte)_args.clientType); - bundle.writeBlob(KBEngineApp.app._clientdatas); - bundle.writeString(username); - bundle.writeString(password); - bundle.send(_networkInterface); - } - } - - private void onConnectTo_loginapp_callback(string ip, int port, bool success, object userData) - { - _lastTickCBTime = System.DateTime.Now; - - if(!success) - { - Dbg.ERROR_MSG(string.Format("KBEngine::login_loginapp(): connect {0}:{1} error!", ip, port)); - return; - } - - currserver = "loginapp"; - currstate = "login"; - - Dbg.DEBUG_MSG(string.Format("KBEngine::login_loginapp(): connect {0}:{1} success!", ip, port)); - - hello(); - } - - private void onLogin_loginapp() - { - _lastTickCBTime = System.DateTime.Now; - login_loginapp(false); - } - - /* - 登录到服务端,登录到网关(baseapp) - */ - public void login_baseapp(bool noconnect) - { - if(noconnect) - { - Event.fireOut(EventOutTypes.onLoginBaseapp); - - _networkInterface.reset(); - _networkInterface = new NetworkInterface(); - _networkInterface.connectTo(baseappIP, baseappPort, onConnectTo_baseapp_callback, null); - } - else - { - Bundle bundle = Bundle.createObject(); - bundle.newMessage(Messages.messages["Baseapp_loginBaseapp"]); - bundle.writeString(username); - bundle.writeString(password); - bundle.send(_networkInterface); - } - } - - private void onConnectTo_baseapp_callback(string ip, int port, bool success, object userData) - { - _lastTickCBTime = System.DateTime.Now; - - if(!success) - { - Dbg.ERROR_MSG(string.Format("KBEngine::login_baseapp(): connect {0}:{1} error!", ip, port)); - return; - } - - currserver = "baseapp"; - currstate = ""; - - Dbg.DEBUG_MSG(string.Format("KBEngine::login_baseapp(): connect {0}:{1} success!", ip, port)); - - hello(); - } - - private void onLogin_baseapp() - { - _lastTickCBTime = System.DateTime.Now; - login_baseapp(false); - } - - /* - 重登录到网关(baseapp) - 一些移动类应用容易掉线,可以使用该功能快速的重新与服务端建立通信 - */ - public void reloginBaseapp() - { - _lastTickTime = System.DateTime.Now; - _lastTickCBTime = System.DateTime.Now; - - if(_networkInterface.valid()) - return; - - Event.fireAll(EventOutTypes.onReloginBaseapp); - _networkInterface.connectTo(baseappIP, baseappPort, onReConnectTo_baseapp_callback, null); - } - - private void onReConnectTo_baseapp_callback(string ip, int port, bool success, object userData) - { - if(!success) - { - Dbg.ERROR_MSG(string.Format("KBEngine::reloginBaseapp(): connect {0}:{1} error!", ip, port)); - return; - } - - Dbg.DEBUG_MSG(string.Format("KBEngine::relogin_baseapp(): connect {0}:{1} success!", ip, port)); - - Bundle bundle = Bundle.createObject(); - bundle.newMessage(Messages.messages["Baseapp_reloginBaseapp"]); - bundle.writeString(username); - bundle.writeString(password); - bundle.writeUint64(entity_uuid); - bundle.writeInt32(entity_id); - bundle.send(_networkInterface); - - _lastTickCBTime = System.DateTime.Now; - } - - /* - 登出baseapp - */ - public void logout() - { - Bundle bundle = Bundle.createObject(); - bundle.newMessage(Messages.messages["Baseapp_logoutBaseapp"]); - bundle.writeUint64(entity_uuid); - bundle.writeInt32(entity_id); - bundle.send(_networkInterface); - } - - /* - 通过错误id得到错误描述 - */ - public string serverErr(UInt16 id) - { - return _serverErrs.serverErrStr(id); - } - - public void onOpenLoginapp_resetpassword() - { - Dbg.DEBUG_MSG("KBEngine::onOpenLoginapp_resetpassword: successfully!"); - currserver = "loginapp"; - currstate = "resetpassword"; - _lastTickCBTime = System.DateTime.Now; - - resetpassword_loginapp(false); - } - - /* - 重置密码, 通过loginapp - */ - public void resetPassword(string username) - { - KBEngineApp.app.username = username; - resetpassword_loginapp(true); - } - - /* - 重置密码, 通过loginapp - */ - public void resetpassword_loginapp(bool noconnect) - { - if(noconnect) - { - reset(); - _networkInterface.connectTo(_args.ip, _args.port, onConnectTo_resetpassword_callback, null); - } - else - { - Bundle bundle = Bundle.createObject(); - bundle.newMessage(Messages.messages["Loginapp_reqAccountResetPassword"]); - bundle.writeString(username); - bundle.send(_networkInterface); - } - } - - private void onConnectTo_resetpassword_callback(string ip, int port, bool success, object userData) - { - _lastTickCBTime = System.DateTime.Now; - - if(!success) - { - Dbg.ERROR_MSG(string.Format("KBEngine::resetpassword_loginapp(): connect {0}:{1} error!", ip, port)); - return; - } - - Dbg.DEBUG_MSG(string.Format("KBEngine::resetpassword_loginapp(): connect {0}:{1} success!", ip, port)); - onOpenLoginapp_resetpassword(); - } - - public void Client_onReqAccountResetPasswordCB(UInt16 failcode) - { - if(failcode != 0) - { - Dbg.ERROR_MSG("KBEngine::Client_onReqAccountResetPasswordCB: " + username + " failed! code=" + failcode + "(" + serverErr(failcode) + ")!"); - return; - } - - Dbg.DEBUG_MSG("KBEngine::Client_onReqAccountResetPasswordCB: " + username + " success!"); - } - - /* - 绑定Email,通过baseapp - */ - public void bindAccountEmail(string emailAddress) - { - Bundle bundle = Bundle.createObject(); - bundle.newMessage(Messages.messages["Baseapp_reqAccountBindEmail"]); - bundle.writeInt32(entity_id); - bundle.writeString(password); - bundle.writeString(emailAddress); - bundle.send(_networkInterface); - } - - public void Client_onReqAccountBindEmailCB(UInt16 failcode) - { - if(failcode != 0) - { - Dbg.ERROR_MSG("KBEngine::Client_onReqAccountBindEmailCB: " + username + " failed! code=" + failcode + "(" + serverErr(failcode) + ")!"); - return; - } - - Dbg.DEBUG_MSG("KBEngine::Client_onReqAccountBindEmailCB: " + username + " success!"); - } - - /* - 设置新密码,通过baseapp, 必须玩家登录在线操作所以是baseapp。 - */ - public void newPassword(string old_password, string new_password) - { - Bundle bundle = Bundle.createObject(); - bundle.newMessage(Messages.messages["Baseapp_reqAccountNewPassword"]); - bundle.writeInt32(entity_id); - bundle.writeString(old_password); - bundle.writeString(new_password); - bundle.send(_networkInterface); - } - - public void Client_onReqAccountNewPasswordCB(UInt16 failcode) - { - if(failcode != 0) - { - Dbg.ERROR_MSG("KBEngine::Client_onReqAccountNewPasswordCB: " + username + " failed! code=" + failcode + "(" + serverErr(failcode) + ")!"); - return; - } - - Dbg.DEBUG_MSG("KBEngine::Client_onReqAccountNewPasswordCB: " + username + " success!"); - } - - public void createAccount(string username, string password, byte[] datas) - { - KBEngineApp.app.username = username; - KBEngineApp.app.password = password; - KBEngineApp.app._clientdatas = datas; - - KBEngineApp.app.createAccount_loginapp(true); - } - - /* - 创建账号,通过loginapp - */ - public void createAccount_loginapp(bool noconnect) - { - if(noconnect) - { - reset(); - _networkInterface.connectTo(_args.ip, _args.port, onConnectTo_createAccount_callback, null); - } - else - { - Bundle bundle = Bundle.createObject(); - bundle.newMessage(Messages.messages["Loginapp_reqCreateAccount"]); - bundle.writeString(username); - bundle.writeString(password); - bundle.writeBlob(KBEngineApp.app._clientdatas); - bundle.send(_networkInterface); - } - } - - public void onOpenLoginapp_createAccount() - { - Dbg.DEBUG_MSG("KBEngine::onOpenLoginapp_createAccount: successfully!"); - currserver = "loginapp"; - currstate = "createAccount"; - _lastTickCBTime = System.DateTime.Now; - - createAccount_loginapp(false); - } - - private void onConnectTo_createAccount_callback(string ip, int port, bool success, object userData) - { - _lastTickCBTime = System.DateTime.Now; - - if(!success) - { - Dbg.ERROR_MSG(string.Format("KBEngine::createAccount_loginapp(): connect {0}:{1} error!", ip, port)); - return; - } - - Dbg.DEBUG_MSG(string.Format("KBEngine::createAccount_loginapp(): connect {0}:{1} success!", ip, port)); - onOpenLoginapp_createAccount(); - } - - /* - 获得了服务端摘要信息, 摘要包括协议MD5, entitydefMD5 - */ - public void onServerDigest() - { - } - - /* - 登录loginapp失败了 - */ - public void Client_onLoginFailed(MemoryStream stream) - { - UInt16 failedcode = stream.readUint16(); - _serverdatas = stream.readBlob(); - Dbg.ERROR_MSG("KBEngine::Client_onLoginFailed: failedcode(" + failedcode + ":" + serverErr(failedcode) + "), datas(" + _serverdatas.Length + ")!"); - Event.fireAll(EventOutTypes.onLoginFailed, failedcode); - } - - /* - 登录loginapp成功了 - */ - public void Client_onLoginSuccessfully(MemoryStream stream) - { - var accountName = stream.readString(); - username = accountName; - baseappIP = stream.readString(); - baseappPort = stream.readUint16(); - _serverdatas = stream.readBlob(); - - Dbg.DEBUG_MSG("KBEngine::Client_onLoginSuccessfully: accountName(" + accountName + "), addr(" + - baseappIP + ":" + baseappPort + "), datas(" + _serverdatas.Length + ")!"); - - login_baseapp(true); - } - - /* - 登录baseapp失败了 - */ - public void Client_onLoginBaseappFailed(UInt16 failedcode) - { - Dbg.ERROR_MSG("KBEngine::Client_onLoginBaseappFailed: failedcode=" + failedcode + "("+ serverErr(failedcode) + ")!"); - Event.fireAll(EventOutTypes.onLoginBaseappFailed, failedcode); - } - - /* - 重登录baseapp失败了 - */ - public void Client_onReloginBaseappFailed(UInt16 failedcode) - { - Dbg.ERROR_MSG("KBEngine::Client_onReloginBaseappFailed: failedcode=" + failedcode + "(" + serverErr(failedcode) + ")!"); - Event.fireAll(EventOutTypes.onReloginBaseappFailed, failedcode); - } - - /* - 登录baseapp成功了 - */ - public void Client_onReloginBaseappSuccessfully(MemoryStream stream) - { - entity_uuid = stream.readUint64(); - Dbg.DEBUG_MSG("KBEngine::Client_onReloginBaseappSuccessfully: name(" + username + ")!"); - Event.fireAll(EventOutTypes.onReloginBaseappSuccessfully); - } - - /* - 服务端通知创建一个角色 - */ - public void Client_onCreatedProxies(UInt64 rndUUID, Int32 eid, string entityType) - { - Dbg.DEBUG_MSG("KBEngine::Client_onCreatedProxies: eid(" + eid + "), entityType(" + entityType + ")!"); - - entity_uuid = rndUUID; - entity_id = eid; - entity_type = entityType; - - if(!this.entities.ContainsKey(eid)) - { - ScriptModule module = null; - if(!EntityDef.moduledefs.TryGetValue(entityType, out module)) - { - Dbg.ERROR_MSG("KBEngine::Client_onCreatedProxies: not found module(" + entityType + ")!"); - return; - } - - Type runclass = module.entityScript; - if(runclass == null) - return; - - Entity entity = (Entity)Activator.CreateInstance(runclass); - entity.id = eid; - entity.className = entityType; - entity.onGetBase(); - - entities[eid] = entity; - - MemoryStream entityMessage = null; - _bufferedCreateEntityMessages.TryGetValue(eid, out entityMessage); - - if(entityMessage != null) - { - Client_onUpdatePropertys(entityMessage); - _bufferedCreateEntityMessages.Remove(eid); - entityMessage.reclaimObject(); - } - - entity.__init__(); - entity.inited = true; - - if(_args.isOnInitCallPropertysSetMethods) - entity.callPropertysSetMethods(); - } - else - { - MemoryStream entityMessage = null; - _bufferedCreateEntityMessages.TryGetValue(eid, out entityMessage); - - if(entityMessage != null) - { - Client_onUpdatePropertys(entityMessage); - _bufferedCreateEntityMessages.Remove(eid); - entityMessage.reclaimObject(); - } - } - } - - public Entity findEntity(Int32 entityID) - { - Entity entity = null; - - if(!entities.TryGetValue(entityID, out entity)) - { - return null; - } - - return entity; - } - - /* - 通过流数据获得View实体的ID - */ - public Int32 getViewEntityIDFromStream(MemoryStream stream) - { - if (!_args.useAliasEntityID) - return stream.readInt32(); - - Int32 id = 0; - if(_entityIDAliasIDList.Count > 255) - { - id = stream.readInt32(); - } - else - { - byte aliasID = stream.readUint8(); - - // 如果为0且客户端上一步是重登陆或者重连操作并且服务端entity在断线期间一直处于在线状态 - // 则可以忽略这个错误, 因为cellapp可能一直在向baseapp发送同步消息, 当客户端重连上时未等 - // 服务端初始化步骤开始则收到同步信息, 此时这里就会出错。 - if(_entityIDAliasIDList.Count <= aliasID) - return 0; - - id = _entityIDAliasIDList[aliasID]; - } - - return id; - } - - /* - 服务端使用优化的方式更新实体属性数据 - */ - public void Client_onUpdatePropertysOptimized(MemoryStream stream) - { - Int32 eid = getViewEntityIDFromStream(stream); - onUpdatePropertys_(eid, stream); - } - - /* - 服务端更新实体属性数据 - */ - public void Client_onUpdatePropertys(MemoryStream stream) - { - Int32 eid = stream.readInt32(); - onUpdatePropertys_(eid, stream); - } - - public void onUpdatePropertys_(Int32 eid, MemoryStream stream) - { - Entity entity = null; - - if(!entities.TryGetValue(eid, out entity)) - { - MemoryStream entityMessage = null; - if(_bufferedCreateEntityMessages.TryGetValue(eid, out entityMessage)) - { - Dbg.ERROR_MSG("KBEngine::Client_onUpdatePropertys: entity(" + eid + ") not found!"); - return; - } - - MemoryStream stream1 = MemoryStream.createObject(); - stream1.wpos = stream.wpos; - stream1.rpos = stream.rpos - 4; - Array.Copy(stream.data(), stream1.data(), stream.data().Length); - _bufferedCreateEntityMessages[eid] = stream1; - return; - } - - ScriptModule sm = EntityDef.moduledefs[entity.className]; - Dictionary pdatas = sm.idpropertys; - - while(stream.length() > 0) - { - UInt16 utype = 0; - - if(sm.usePropertyDescrAlias) - { - utype = stream.readUint8(); - } - else - { - utype = stream.readUint16(); - } - - Property propertydata = pdatas[utype]; - entity.onUpdatePropertys(propertydata, stream); - - // Dbg.DEBUG_MSG("KBEngine::Client_onUpdatePropertys: " + entity.className + "(id=" + eid + " " + - // propertydata.name + "=" + val + "), hasSetMethod=" + setmethod + "!"); - } - } - - /* - 服务端使用优化的方式调用实体方法 - */ - public void Client_onRemoteMethodCallOptimized(MemoryStream stream) - { - Int32 eid = getViewEntityIDFromStream(stream); - onRemoteMethodCall_(eid, stream); - } - - /* - 服务端调用实体方法 - */ - public void Client_onRemoteMethodCall(MemoryStream stream) - { - Int32 eid = stream.readInt32(); - onRemoteMethodCall_(eid, stream); - } - - public void onRemoteMethodCall_(Int32 eid, MemoryStream stream) - { - Entity entity = null; - - if(!entities.TryGetValue(eid, out entity)) - { - Dbg.ERROR_MSG("KBEngine::Client_onRemoteMethodCall: entity(" + eid + ") not found!"); - return; - } - - UInt16 methodUtype = 0; - ScriptModule sm = EntityDef.moduledefs[entity.className]; - - if(sm.useMethodDescrAlias) - methodUtype = stream.readUint8(); - else - methodUtype = stream.readUint16(); - - Method methoddata = null; - - try - { - methoddata = sm.idmethods[methodUtype]; - } - catch (Exception e) - { - Dbg.ERROR_MSG("KBEngine::Client_onRemoteMethodCall: " + entity.className + "(" + eid + "), methodUtype(" + methodUtype + ")!\nerror=" + e.ToString()); - return; - } - - // Dbg.DEBUG_MSG("KBEngine::Client_onRemoteMethodCall: " + entity.className + "." + methoddata.name); - - entity.onRemoteMethodCall(methoddata, stream); - } - - /* - 服务端通知一个实体进入了世界(如果实体是当前玩家则玩家第一次在一个space中创建了, 如果是其他实体则是其他实体进入了玩家的View) - */ - public void Client_onEntityEnterWorld(MemoryStream stream) - { - Int32 eid = stream.readInt32(); - if(entity_id > 0 && entity_id != eid) - _entityIDAliasIDList.Add(eid); - - UInt16 uentityType; - if(EntityDef.idmoduledefs.Count > 255) - uentityType = stream.readUint16(); - else - uentityType = stream.readUint8(); - - sbyte isOnGround = 1; - - if(stream.length() > 0) - isOnGround = stream.readInt8(); - - string entityType = EntityDef.idmoduledefs[uentityType].name; - // Dbg.DEBUG_MSG("KBEngine::Client_onEntityEnterWorld: " + entityType + "(" + eid + "), spaceID(" + KBEngineApp.app.spaceID + ")!"); - - Entity entity = null; - - if(!entities.TryGetValue(eid, out entity)) - { - MemoryStream entityMessage = null; - if(!_bufferedCreateEntityMessages.TryGetValue(eid, out entityMessage)) - { - Dbg.ERROR_MSG("KBEngine::Client_onEntityEnterWorld: entity(" + eid + ") not found!"); - return; - } - - ScriptModule module = null; - if(!EntityDef.moduledefs.TryGetValue(entityType, out module)) - { - Dbg.ERROR_MSG("KBEngine::Client_onEntityEnterWorld: not found module(" + entityType + ")!"); - } - - Type runclass = module.entityScript; - if(runclass == null) - return; - - entity = (Entity)Activator.CreateInstance(runclass); - entity.id = eid; - entity.className = entityType; - entity.onGetCell(); - - entities[eid] = entity; - - Client_onUpdatePropertys(entityMessage); - _bufferedCreateEntityMessages.Remove(eid); - entityMessage.reclaimObject(); - - entity.isOnGround = isOnGround > 0; - entity.onDirectionChanged(entity.direction); - entity.onPositionChanged(entity.position); - - entity.__init__(); - entity.inited = true; - entity.inWorld = true; - entity.enterWorld(); - - if(_args.isOnInitCallPropertysSetMethods) - entity.callPropertysSetMethods(); - } - else - { - if(!entity.inWorld) - { - // 安全起见, 这里清空一下 - // 如果服务端上使用giveClientTo切换控制权 - // 之前的实体已经进入世界, 切换后的实体也进入世界, 这里可能会残留之前那个实体进入世界的信息 - _entityIDAliasIDList.Clear(); - clearEntities(false); - entities[entity.id] = entity; - - entity.onGetCell(); - - entity.onDirectionChanged(entity.direction); - entity.onPositionChanged(entity.position); - - _entityServerPos = entity.position; - entity.isOnGround = isOnGround > 0; - entity.inWorld = true; - entity.enterWorld(); - - if(_args.isOnInitCallPropertysSetMethods) - entity.callPropertysSetMethods(); - } - } - } - - /* - 服务端使用优化的方式通知一个实体离开了世界(如果实体是当前玩家则玩家离开了space, 如果是其他实体则是其他实体离开了玩家的View) - */ - public void Client_onEntityLeaveWorldOptimized(MemoryStream stream) - { - Int32 eid = getViewEntityIDFromStream(stream); - KBEngineApp.app.Client_onEntityLeaveWorld(eid); - } - - /* - 服务端通知一个实体离开了世界(如果实体是当前玩家则玩家离开了space, 如果是其他实体则是其他实体离开了玩家的View) - */ - public void Client_onEntityLeaveWorld(Int32 eid) - { - Entity entity = null; - - if(!entities.TryGetValue(eid, out entity)) - { - Dbg.ERROR_MSG("KBEngine::Client_onEntityLeaveWorld: entity(" + eid + ") not found!"); - return; - } - - if(entity.inWorld) - entity.leaveWorld(); - - if(entity_id == eid) - { - clearSpace(false); - entity.onLoseCell(); - } - else - { - if(_controlledEntities.Remove(entity)) - Event.fireOut(EventOutTypes.onLoseControlledEntity, entity); - - entities.Remove(eid); - entity.onDestroy(); - _entityIDAliasIDList.Remove(eid); - } - } - - /* - 服务端通知当前玩家进入了一个新的space - */ - public void Client_onEntityEnterSpace(MemoryStream stream) - { - Int32 eid = stream.readInt32(); - spaceID = stream.readUint32(); - - sbyte isOnGround = 1; - - if(stream.length() > 0) - isOnGround = stream.readInt8(); - - Entity entity = null; - - if(!entities.TryGetValue(eid, out entity)) - { - Dbg.ERROR_MSG("KBEngine::Client_onEntityEnterSpace: entity(" + eid + ") not found!"); - return; - } - - entity.isOnGround = isOnGround > 0; - _entityServerPos = entity.position; - entity.enterSpace(); - } - - /* - 服务端通知当前玩家离开了space - */ - public void Client_onEntityLeaveSpace(Int32 eid) - { - Entity entity = null; - - if(!entities.TryGetValue(eid, out entity)) - { - Dbg.ERROR_MSG("KBEngine::Client_onEntityLeaveSpace: entity(" + eid + ") not found!"); - return; - } - - entity.leaveSpace(); - clearSpace(false); - } - - /* - 账号创建返回结果 - */ - public void Client_onCreateAccountResult(MemoryStream stream) - { - UInt16 retcode = stream.readUint16(); - byte[] datas = stream.readBlob(); - - Event.fireOut(EventOutTypes.onCreateAccountResult, retcode, datas); - - if(retcode != 0) - { - Dbg.WARNING_MSG("KBEngine::Client_onCreateAccountResult: " + username + " create is failed! code=" + retcode + "!"); - return; - } - - Dbg.DEBUG_MSG("KBEngine::Client_onCreateAccountResult: " + username + " create is successfully!"); - } - - /* - 告诉客户端:你当前负责(或取消)控制谁的位移同步 - */ - public void Client_onControlEntity(Int32 eid, sbyte isControlled) - { - Entity entity = null; - - if (!entities.TryGetValue(eid, out entity)) - { - Dbg.ERROR_MSG("KBEngine::Client_onControlEntity: entity(" + eid + ") not found!"); - return; - } - - var isCont = isControlled != 0; - if (isCont) - { - // 如果被控制者是玩家自己,那表示玩家自己被其它人控制了 - // 所以玩家自己不应该进入这个被控制列表 - if (player().id != entity.id) - { - _controlledEntities.Add(entity); - } - } - else - { - _controlledEntities.Remove(entity); - } - - entity.isControlled = isCont; - - try - { - entity.onControlled(isCont); - Event.fireOut(EventOutTypes.onControlled, entity, isCont); - } - catch (Exception e) - { - Dbg.ERROR_MSG(string.Format("KBEngine::Client_onControlEntity: entity id = '{0}', is controlled = '{1}', error = '{1}'", eid, isCont, e)); - } - } - - /* - 更新当前玩家的位置与朝向到服务端, 可以通过开关_syncPlayerMS关闭这个机制 - */ - public void updatePlayerToServer() - { - if(_updatePlayerToServerPeroid <= 0.01f || spaceID == 0) - { - return; - } - - var now = DateTime.Now; - TimeSpan span = now - _lastUpdateToServerTime; - - if (span.Ticks < _updatePlayerToServerPeroid * _1MS_TO_100NS) - return; - - Entity playerEntity = player(); - if (playerEntity == null || playerEntity.inWorld == false || playerEntity.isControlled) - return; - - _lastUpdateToServerTime = now - (span - TimeSpan.FromTicks(Convert.ToInt64(_updatePlayerToServerPeroid * _1MS_TO_100NS))); - - Vector3 position = playerEntity.position; - Vector3 direction = playerEntity.direction; - - bool posHasChanged = Vector3.Distance(playerEntity._entityLastLocalPos, position) > 0.001f; - bool dirHasChanged = Vector3.Distance(playerEntity._entityLastLocalDir, direction) > 0.001f; - - if(posHasChanged || dirHasChanged) - { - playerEntity._entityLastLocalPos = position; - playerEntity._entityLastLocalDir = direction; - - Bundle bundle = Bundle.createObject(); - bundle.newMessage(Messages.messages["Baseapp_onUpdateDataFromClient"]); - bundle.writeFloat(position.x); - bundle.writeFloat(position.y); - bundle.writeFloat(position.z); - - double x = ((double)direction.x / 360 * (System.Math.PI * 2)); - double y = ((double)direction.y / 360 * (System.Math.PI * 2)); - double z = ((double)direction.z / 360 * (System.Math.PI * 2)); - - // 根据弧度转角度公式会出现负数 - // unity会自动转化到0~360度之间,这里需要做一个还原 - if(x - System.Math.PI > 0.0) - x -= System.Math.PI * 2; - - if(y - System.Math.PI > 0.0) - y -= System.Math.PI * 2; - - if(z - System.Math.PI > 0.0) - z -= System.Math.PI * 2; - - bundle.writeFloat((float)x); - bundle.writeFloat((float)y); - bundle.writeFloat((float)z); - bundle.writeUint8((Byte)(playerEntity.isOnGround == true ? 1 : 0)); - bundle.writeUint32(spaceID); - bundle.send(_networkInterface); - } - - // 开始同步所有被控制了的entity的位置 - for (int i = 0; i < _controlledEntities.Count; ++i) - { - var entity = _controlledEntities[i]; - position = entity.position; - direction = entity.direction; - - posHasChanged = Vector3.Distance(entity._entityLastLocalPos, position) > 0.001f; - dirHasChanged = Vector3.Distance(entity._entityLastLocalDir, direction) > 0.001f; - - if (posHasChanged || dirHasChanged) - { - entity._entityLastLocalPos = position; - entity._entityLastLocalDir = direction; - - Bundle bundle = Bundle.createObject(); - bundle.newMessage(Messages.messages["Baseapp_onUpdateDataFromClientForControlledEntity"]); - bundle.writeInt32(entity.id); - bundle.writeFloat(position.x); - bundle.writeFloat(position.y); - bundle.writeFloat(position.z); - - double x = ((double)direction.x / 360 * (System.Math.PI * 2)); - double y = ((double)direction.y / 360 * (System.Math.PI * 2)); - double z = ((double)direction.z / 360 * (System.Math.PI * 2)); - - // 根据弧度转角度公式会出现负数 - // unity会自动转化到0~360度之间,这里需要做一个还原 - if(x - System.Math.PI > 0.0) - x -= System.Math.PI * 2; - - if(y - System.Math.PI > 0.0) - y -= System.Math.PI * 2; - - if(z - System.Math.PI > 0.0) - z -= System.Math.PI * 2; - - bundle.writeFloat((float)x); - bundle.writeFloat((float)y); - bundle.writeFloat((float)z); - bundle.writeUint8((Byte)(entity.isOnGround == true ? 1 : 0)); - bundle.writeUint32(spaceID); - bundle.send(_networkInterface); - } - } - } - - /* - 当前space添加了关于几何等信息的映射资源 - 客户端可以通过这个资源信息来加载对应的场景 - */ - public void addSpaceGeometryMapping(UInt32 uspaceID, string respath) - { - Dbg.DEBUG_MSG("KBEngine::addSpaceGeometryMapping: spaceID(" + uspaceID + "), respath(" + respath + ")!"); - - isLoadedGeometry = true; - spaceID = uspaceID; - spaceResPath = respath; - Event.fireOut(EventOutTypes.addSpaceGeometryMapping, spaceResPath); - } - - public void clearSpace(bool isall) - { - _entityIDAliasIDList.Clear(); - _spacedatas.Clear(); - clearEntities(isall); - isLoadedGeometry = false; - spaceID = 0; - } - - public void clearEntities(bool isall) - { - _controlledEntities.Clear(); - - if (!isall) - { - Entity entity = player(); - - foreach (KeyValuePair dic in entities) - { - if(dic.Key == entity.id) - continue; - - if(dic.Value.inWorld) - dic.Value.leaveWorld(); - - dic.Value.onDestroy(); - } - - entities.Clear(); - entities[entity.id] = entity; - } - else - { - foreach (KeyValuePair dic in entities) - { - if(dic.Value.inWorld) - dic.Value.leaveWorld(); - - dic.Value.onDestroy(); - } - - entities.Clear(); - } - } - - /* - 服务端初始化客户端的spacedata, spacedata请参考API - */ - public void Client_initSpaceData(MemoryStream stream) - { - clearSpace(false); - spaceID = stream.readUint32(); - - while(stream.length() > 0) - { - string key = stream.readString(); - string val = stream.readString(); - Client_setSpaceData(spaceID, key, val); - } - - Dbg.DEBUG_MSG("KBEngine::Client_initSpaceData: spaceID(" + spaceID + "), size(" + _spacedatas.Count + ")!"); - } - - /* - 服务端设置客户端的spacedata, spacedata请参考API - */ - public void Client_setSpaceData(UInt32 spaceID, string key, string value) - { - Dbg.DEBUG_MSG("KBEngine::Client_setSpaceData: spaceID(" + spaceID + "), key(" + key + "), value(" + value + ")!"); - _spacedatas[key] = value; - - if(key == "_mapping") - addSpaceGeometryMapping(spaceID, value); - - Event.fireOut(EventOutTypes.onSetSpaceData, spaceID, key, value); - } - - /* - 服务端删除客户端的spacedata, spacedata请参考API - */ - public void Client_delSpaceData(UInt32 spaceID, string key) - { - Dbg.DEBUG_MSG("KBEngine::Client_delSpaceData: spaceID(" + spaceID + "), key(" + key + ")"); - _spacedatas.Remove(key); - Event.fireOut(EventOutTypes.onDelSpaceData, spaceID, key); - } - - public string getSpaceData(string key) - { - string val = ""; - - if(!_spacedatas.TryGetValue(key, out val)) - { - return ""; - } - - return val; - } - - /* - 服务端通知强制销毁一个实体 - */ - public void Client_onEntityDestroyed(Int32 eid) - { - Dbg.DEBUG_MSG("KBEngine::Client_onEntityDestroyed: entity(" + eid + ")"); - - Entity entity = null; - - if(!entities.TryGetValue(eid, out entity)) - { - Dbg.ERROR_MSG("KBEngine::Client_onEntityDestroyed: entity(" + eid + ") not found!"); - return; - } - - if(entity.inWorld) - { - if(entity_id == eid) - clearSpace(false); - - entity.leaveWorld(); - } - - if(_controlledEntities.Remove(entity)) - Event.fireOut(EventOutTypes.onLoseControlledEntity, entity); - - entities.Remove(eid); - entity.onDestroy(); - } - - /* - 服务端更新玩家的基础位置, 客户端以这个基础位置加上便宜值计算出玩家周围实体的坐标 - */ - public void Client_onUpdateBasePos(float x, float y, float z) - { - _entityServerPos.x = x; - _entityServerPos.y = y; - _entityServerPos.z = z; - - var entity = player(); - if (entity != null && entity.isControlled) - { - entity.position.Set(_entityServerPos.x, _entityServerPos.y, _entityServerPos.z); - Event.fireOut(EventOutTypes.updatePosition, entity); - entity.onUpdateVolatileData(); - } - } - - public void Client_onUpdateBasePosXZ(float x, float z) - { - _entityServerPos.x = x; - _entityServerPos.z = z; - - var entity = player(); - if (entity != null && entity.isControlled) - { - entity.position.x = _entityServerPos.x; - entity.position.z = _entityServerPos.z; - Event.fireOut(EventOutTypes.updatePosition, entity); - entity.onUpdateVolatileData(); - } - } - - public void Client_onUpdateBaseDir(MemoryStream stream) - { - float yaw, pitch, roll; - yaw = stream.readFloat() * 360 / ((float)System.Math.PI * 2); - pitch = stream.readFloat() * 360 / ((float)System.Math.PI * 2); - roll = stream.readFloat() * 360 / ((float)System.Math.PI * 2); - - var entity = player(); - if (entity != null && entity.isControlled) - { - entity.direction.Set(roll, pitch, yaw); - Event.fireOut(EventOutTypes.set_direction, entity); - entity.onUpdateVolatileData(); - } - } - - public void Client_onUpdateData(MemoryStream stream) - { - Int32 eid = getViewEntityIDFromStream(stream); - Entity entity = null; - - if(!entities.TryGetValue(eid, out entity)) - { - Dbg.ERROR_MSG("KBEngine::Client_onUpdateData: entity(" + eid + ") not found!"); - return; - } - } - - /* - 服务端强制设置了玩家的坐标 - 例如:在服务端使用avatar.position=(0,0,0), 或者玩家位置与速度异常时会强制拉回到一个位置 - */ - public void Client_onSetEntityPosAndDir(MemoryStream stream) - { - Int32 eid = stream.readInt32(); - Entity entity = null; - - if(!entities.TryGetValue(eid, out entity)) - { - Dbg.ERROR_MSG("KBEngine::Client_onSetEntityPosAndDir: entity(" + eid + ") not found!"); - return; - } - - Vector3 old_position = new Vector3(entity.position.x, entity.position.y, entity.position.z); - Vector3 old_direction = new Vector3(entity.direction.x, entity.direction.y, entity.direction.z); - - entity.position.x = stream.readFloat(); - entity.position.y = stream.readFloat(); - entity.position.z = stream.readFloat(); - - entity.direction.x = stream.readFloat(); - entity.direction.y = stream.readFloat(); - entity.direction.z = stream.readFloat(); - - entity._entityLastLocalPos = entity.position; - entity._entityLastLocalDir = entity.direction; - - entity.onDirectionChanged(old_direction); - entity.onPositionChanged(old_position); - } - - public void Client_onUpdateData_ypr(MemoryStream stream) - { - Int32 eid = getViewEntityIDFromStream(stream); - - float y = stream.readFloat(); - float p = stream.readFloat(); - float r = stream.readFloat(); - - _updateVolatileData(eid, KBEMath.KBE_FLT_MAX, KBEMath.KBE_FLT_MAX, KBEMath.KBE_FLT_MAX, y, p, r, -1, false); - } - - public void Client_onUpdateData_yp(MemoryStream stream) - { - Int32 eid = getViewEntityIDFromStream(stream); - - float y = stream.readFloat(); - float p = stream.readFloat(); - - _updateVolatileData(eid, KBEMath.KBE_FLT_MAX, KBEMath.KBE_FLT_MAX, KBEMath.KBE_FLT_MAX, y, p, KBEMath.KBE_FLT_MAX, -1, false); - } - - public void Client_onUpdateData_yr(MemoryStream stream) - { - Int32 eid = getViewEntityIDFromStream(stream); - - float y = stream.readFloat(); - float r = stream.readFloat(); - - _updateVolatileData(eid, KBEMath.KBE_FLT_MAX, KBEMath.KBE_FLT_MAX, KBEMath.KBE_FLT_MAX, y, KBEMath.KBE_FLT_MAX, r, -1, false); - } - - public void Client_onUpdateData_pr(MemoryStream stream) - { - Int32 eid = getViewEntityIDFromStream(stream); - - float p = stream.readFloat(); - float r = stream.readFloat(); - - _updateVolatileData(eid, KBEMath.KBE_FLT_MAX, KBEMath.KBE_FLT_MAX, KBEMath.KBE_FLT_MAX, KBEMath.KBE_FLT_MAX, p, r, -1, false); - } - - public void Client_onUpdateData_y(MemoryStream stream) - { - Int32 eid = getViewEntityIDFromStream(stream); - - float y = stream.readFloat(); - - _updateVolatileData(eid, KBEMath.KBE_FLT_MAX, KBEMath.KBE_FLT_MAX, KBEMath.KBE_FLT_MAX, y, KBEMath.KBE_FLT_MAX, KBEMath.KBE_FLT_MAX, -1, false); - } - - public void Client_onUpdateData_p(MemoryStream stream) - { - Int32 eid = getViewEntityIDFromStream(stream); - - float p = stream.readFloat(); - - _updateVolatileData(eid, KBEMath.KBE_FLT_MAX, KBEMath.KBE_FLT_MAX, KBEMath.KBE_FLT_MAX, KBEMath.KBE_FLT_MAX, p, KBEMath.KBE_FLT_MAX, -1, false); - } - - public void Client_onUpdateData_r(MemoryStream stream) - { - Int32 eid = getViewEntityIDFromStream(stream); - - float r = stream.readFloat(); - - _updateVolatileData(eid, KBEMath.KBE_FLT_MAX, KBEMath.KBE_FLT_MAX, KBEMath.KBE_FLT_MAX, KBEMath.KBE_FLT_MAX, KBEMath.KBE_FLT_MAX, r, -1, false); - } - - public void Client_onUpdateData_xz(MemoryStream stream) - { - Int32 eid = getViewEntityIDFromStream(stream); - - float x = stream.readFloat(); - float z = stream.readFloat(); - - _updateVolatileData(eid, x, KBEMath.KBE_FLT_MAX, z, KBEMath.KBE_FLT_MAX, KBEMath.KBE_FLT_MAX, KBEMath.KBE_FLT_MAX, 1, false); - } - - public void Client_onUpdateData_xz_ypr(MemoryStream stream) - { - Int32 eid = getViewEntityIDFromStream(stream); - - float x = stream.readFloat(); - float z = stream.readFloat(); - - float y = stream.readFloat(); - float p = stream.readFloat(); - float r = stream.readFloat(); - - _updateVolatileData(eid, x, KBEMath.KBE_FLT_MAX, z, y, p, r, 1, false); - } - - public void Client_onUpdateData_xz_yp(MemoryStream stream) - { - Int32 eid = getViewEntityIDFromStream(stream); - - float x = stream.readFloat(); - float z = stream.readFloat(); - - float y = stream.readFloat(); - float p = stream.readFloat(); - - _updateVolatileData(eid, x, KBEMath.KBE_FLT_MAX, z, y, p, KBEMath.KBE_FLT_MAX, 1, false); - } - - public void Client_onUpdateData_xz_yr(MemoryStream stream) - { - Int32 eid = getViewEntityIDFromStream(stream); - - float x = stream.readFloat(); - float z = stream.readFloat(); - - float y = stream.readFloat(); - float r = stream.readFloat(); - - _updateVolatileData(eid, x, KBEMath.KBE_FLT_MAX, z, y, KBEMath.KBE_FLT_MAX, r, 1, false); - } - - public void Client_onUpdateData_xz_pr(MemoryStream stream) - { - Int32 eid = getViewEntityIDFromStream(stream); - - float x = stream.readFloat(); - float z = stream.readFloat(); - - float p = stream.readFloat(); - float r = stream.readFloat(); - - _updateVolatileData(eid, x, KBEMath.KBE_FLT_MAX, z, KBEMath.KBE_FLT_MAX, p, r, 1, false); - } - - public void Client_onUpdateData_xz_y(MemoryStream stream) - { - Int32 eid = getViewEntityIDFromStream(stream); - - float x = stream.readFloat(); - float z = stream.readFloat(); - - float yaw = stream.readFloat(); - - _updateVolatileData(eid, x, KBEMath.KBE_FLT_MAX, z, yaw, KBEMath.KBE_FLT_MAX, KBEMath.KBE_FLT_MAX, 1, false); - } - - public void Client_onUpdateData_xz_p(MemoryStream stream) - { - Int32 eid = getViewEntityIDFromStream(stream); - - float x = stream.readFloat(); - float z = stream.readFloat(); - - float p = stream.readFloat(); - - _updateVolatileData(eid, x, KBEMath.KBE_FLT_MAX, z, KBEMath.KBE_FLT_MAX, p, KBEMath.KBE_FLT_MAX, 1, false); - } - - public void Client_onUpdateData_xz_r(MemoryStream stream) - { - Int32 eid = getViewEntityIDFromStream(stream); - - float x = stream.readFloat(); - float z = stream.readFloat(); - - float r = stream.readFloat(); - - _updateVolatileData(eid, x, KBEMath.KBE_FLT_MAX, z, KBEMath.KBE_FLT_MAX, KBEMath.KBE_FLT_MAX, r, 1, false); - } - - public void Client_onUpdateData_xyz(MemoryStream stream) - { - Int32 eid = getViewEntityIDFromStream(stream); - - float x = stream.readFloat(); - float y = stream.readFloat(); - float z = stream.readFloat(); - - _updateVolatileData(eid, x, y, z, KBEMath.KBE_FLT_MAX, KBEMath.KBE_FLT_MAX, KBEMath.KBE_FLT_MAX, 0, false); - } - - public void Client_onUpdateData_xyz_ypr(MemoryStream stream) - { - Int32 eid = getViewEntityIDFromStream(stream); - - float x = stream.readFloat(); - float y = stream.readFloat(); - float z = stream.readFloat(); - - float yaw = stream.readFloat(); - float p = stream.readFloat(); - float r = stream.readFloat(); - - _updateVolatileData(eid, x, y, z, yaw, p, r, 0, false); - } - - public void Client_onUpdateData_xyz_yp(MemoryStream stream) - { - Int32 eid = getViewEntityIDFromStream(stream); - - float x = stream.readFloat(); - float y = stream.readFloat(); - float z = stream.readFloat(); - - float yaw = stream.readFloat(); - float p = stream.readFloat(); - - _updateVolatileData(eid, x, y, z, yaw, p, KBEMath.KBE_FLT_MAX, 0, false); - } - - public void Client_onUpdateData_xyz_yr(MemoryStream stream) - { - Int32 eid = getViewEntityIDFromStream(stream); - - float x = stream.readFloat(); - float y = stream.readFloat(); - float z = stream.readFloat(); - - float yaw = stream.readFloat(); - float r = stream.readFloat(); - - _updateVolatileData(eid, x, y, z, yaw, KBEMath.KBE_FLT_MAX, r, 0, false); - } - - public void Client_onUpdateData_xyz_pr(MemoryStream stream) - { - Int32 eid = getViewEntityIDFromStream(stream); - - float x = stream.readFloat(); - float y = stream.readFloat(); - float z = stream.readFloat(); - - float p = stream.readFloat(); - float r = stream.readFloat(); - - _updateVolatileData(eid, x, y, z, KBEMath.KBE_FLT_MAX, p, r, 0, false); - } - - public void Client_onUpdateData_xyz_y(MemoryStream stream) - { - Int32 eid = getViewEntityIDFromStream(stream); - - float x = stream.readFloat(); - float y = stream.readFloat(); - float z = stream.readFloat(); - - float yaw = stream.readFloat(); - - _updateVolatileData(eid, x, y, z, yaw, KBEMath.KBE_FLT_MAX, KBEMath.KBE_FLT_MAX, 0, false); - } - - public void Client_onUpdateData_xyz_p(MemoryStream stream) - { - Int32 eid = getViewEntityIDFromStream(stream); - - float x = stream.readFloat(); - float y = stream.readFloat(); - float z = stream.readFloat(); - - float p = stream.readFloat(); - - _updateVolatileData(eid, x, y, z, KBEMath.KBE_FLT_MAX, p, KBEMath.KBE_FLT_MAX, 0, false); - } - - public void Client_onUpdateData_xyz_r(MemoryStream stream) - { - Int32 eid = getViewEntityIDFromStream(stream); - - float x = stream.readFloat(); - float y = stream.readFloat(); - float z = stream.readFloat(); - - float r = stream.readFloat(); - - _updateVolatileData(eid, x, y, z, KBEMath.KBE_FLT_MAX, KBEMath.KBE_FLT_MAX, r, 0, false); - } - - public void Client_onUpdateData_ypr_optimized(MemoryStream stream) - { - Int32 eid = getViewEntityIDFromStream(stream); - - SByte y = stream.readInt8(); - SByte p = stream.readInt8(); - SByte r = stream.readInt8(); - - _updateVolatileData(eid, KBEMath.KBE_FLT_MAX, KBEMath.KBE_FLT_MAX, KBEMath.KBE_FLT_MAX, y, p, r, -1, true); - } - - public void Client_onUpdateData_yp_optimized(MemoryStream stream) - { - Int32 eid = getViewEntityIDFromStream(stream); - - SByte y = stream.readInt8(); - SByte p = stream.readInt8(); - - _updateVolatileData(eid, KBEMath.KBE_FLT_MAX, KBEMath.KBE_FLT_MAX, KBEMath.KBE_FLT_MAX, y, p, KBEMath.KBE_FLT_MAX, -1, true); - } - - public void Client_onUpdateData_yr_optimized(MemoryStream stream) - { - Int32 eid = getViewEntityIDFromStream(stream); - - SByte y = stream.readInt8(); - SByte r = stream.readInt8(); - - _updateVolatileData(eid, KBEMath.KBE_FLT_MAX, KBEMath.KBE_FLT_MAX, KBEMath.KBE_FLT_MAX, y, KBEMath.KBE_FLT_MAX, r, -1, true); - } - - public void Client_onUpdateData_pr_optimized(MemoryStream stream) - { - Int32 eid = getViewEntityIDFromStream(stream); - - SByte p = stream.readInt8(); - SByte r = stream.readInt8(); - - _updateVolatileData(eid, KBEMath.KBE_FLT_MAX, KBEMath.KBE_FLT_MAX, KBEMath.KBE_FLT_MAX, KBEMath.KBE_FLT_MAX, p, r, -1, true); - } - - public void Client_onUpdateData_y_optimized(MemoryStream stream) - { - Int32 eid = getViewEntityIDFromStream(stream); - - SByte y = stream.readInt8(); - - _updateVolatileData(eid, KBEMath.KBE_FLT_MAX, KBEMath.KBE_FLT_MAX, KBEMath.KBE_FLT_MAX, y, KBEMath.KBE_FLT_MAX, KBEMath.KBE_FLT_MAX, -1, true); - } - - public void Client_onUpdateData_p_optimized(MemoryStream stream) - { - Int32 eid = getViewEntityIDFromStream(stream); - - SByte p = stream.readInt8(); - - _updateVolatileData(eid, KBEMath.KBE_FLT_MAX, KBEMath.KBE_FLT_MAX, KBEMath.KBE_FLT_MAX, KBEMath.KBE_FLT_MAX, p, KBEMath.KBE_FLT_MAX, -1, true); - } - - public void Client_onUpdateData_r_optimized(MemoryStream stream) - { - Int32 eid = getViewEntityIDFromStream(stream); - - SByte r = stream.readInt8(); - - _updateVolatileData(eid, KBEMath.KBE_FLT_MAX, KBEMath.KBE_FLT_MAX, KBEMath.KBE_FLT_MAX, KBEMath.KBE_FLT_MAX, KBEMath.KBE_FLT_MAX, r, -1, true); - } - - public void Client_onUpdateData_xz_optimized(MemoryStream stream) - { - Int32 eid = getViewEntityIDFromStream(stream); - - Vector2 xz = stream.readPackXZ(); - - _updateVolatileData(eid, xz[0], KBEMath.KBE_FLT_MAX, xz[1], KBEMath.KBE_FLT_MAX, KBEMath.KBE_FLT_MAX, KBEMath.KBE_FLT_MAX, 1, true); - } - - public void Client_onUpdateData_xz_ypr_optimized(MemoryStream stream) - { - Int32 eid = getViewEntityIDFromStream(stream); - - Vector2 xz = stream.readPackXZ(); - - SByte y = stream.readInt8(); - SByte p = stream.readInt8(); - SByte r = stream.readInt8(); - - _updateVolatileData(eid, xz[0], KBEMath.KBE_FLT_MAX, xz[1], y, p, r, 1, true); - } - - public void Client_onUpdateData_xz_yp_optimized(MemoryStream stream) - { - Int32 eid = getViewEntityIDFromStream(stream); - - Vector2 xz = stream.readPackXZ(); - - SByte y = stream.readInt8(); - SByte p = stream.readInt8(); - - _updateVolatileData(eid, xz[0], KBEMath.KBE_FLT_MAX, xz[1], y, p, KBEMath.KBE_FLT_MAX, 1, true); - } - - public void Client_onUpdateData_xz_yr_optimized(MemoryStream stream) - { - Int32 eid = getViewEntityIDFromStream(stream); - - Vector2 xz = stream.readPackXZ(); - - SByte y = stream.readInt8(); - SByte r = stream.readInt8(); - - _updateVolatileData(eid, xz[0], KBEMath.KBE_FLT_MAX, xz[1], y, KBEMath.KBE_FLT_MAX, r, 1, true); - } - - public void Client_onUpdateData_xz_pr_optimized(MemoryStream stream) - { - Int32 eid = getViewEntityIDFromStream(stream); - - Vector2 xz = stream.readPackXZ(); - - SByte p = stream.readInt8(); - SByte r = stream.readInt8(); - - _updateVolatileData(eid, xz[0], KBEMath.KBE_FLT_MAX, xz[1], KBEMath.KBE_FLT_MAX, p, r, 1, true); - } - - public void Client_onUpdateData_xz_y_optimized(MemoryStream stream) - { - Int32 eid = getViewEntityIDFromStream(stream); - Vector2 xz = stream.readPackXZ(); - SByte yaw = stream.readInt8(); - _updateVolatileData(eid, xz[0], KBEMath.KBE_FLT_MAX, xz[1], yaw, KBEMath.KBE_FLT_MAX, KBEMath.KBE_FLT_MAX, 1, true); - } - - public void Client_onUpdateData_xz_p_optimized(MemoryStream stream) - { - Int32 eid = getViewEntityIDFromStream(stream); - - Vector2 xz = stream.readPackXZ(); - - SByte p = stream.readInt8(); - - _updateVolatileData(eid, xz[0], KBEMath.KBE_FLT_MAX, xz[1], KBEMath.KBE_FLT_MAX, p, KBEMath.KBE_FLT_MAX, 1, true); - } - - public void Client_onUpdateData_xz_r_optimized(MemoryStream stream) - { - Int32 eid = getViewEntityIDFromStream(stream); - - Vector2 xz = stream.readPackXZ(); - - SByte r = stream.readInt8(); - - _updateVolatileData(eid, xz[0], KBEMath.KBE_FLT_MAX, xz[1], KBEMath.KBE_FLT_MAX, KBEMath.KBE_FLT_MAX, r, 1, true); - } - - public void Client_onUpdateData_xyz_optimized(MemoryStream stream) - { - Int32 eid = getViewEntityIDFromStream(stream); - - Vector2 xz = stream.readPackXZ(); - float y = stream.readPackY(); - - _updateVolatileData(eid, xz[0], y, xz[1], KBEMath.KBE_FLT_MAX, KBEMath.KBE_FLT_MAX, KBEMath.KBE_FLT_MAX, 0, true); - } - - public void Client_onUpdateData_xyz_ypr_optimized(MemoryStream stream) - { - Int32 eid = getViewEntityIDFromStream(stream); - - Vector2 xz = stream.readPackXZ(); - float y = stream.readPackY(); - - SByte yaw = stream.readInt8(); - SByte p = stream.readInt8(); - SByte r = stream.readInt8(); - - _updateVolatileData(eid, xz[0], y, xz[1], yaw, p, r, 0, true); - } - - public void Client_onUpdateData_xyz_yp_optimized(MemoryStream stream) - { - Int32 eid = getViewEntityIDFromStream(stream); - - Vector2 xz = stream.readPackXZ(); - float y = stream.readPackY(); - - SByte yaw = stream.readInt8(); - SByte p = stream.readInt8(); - - _updateVolatileData(eid, xz[0], y, xz[1], yaw, p, KBEMath.KBE_FLT_MAX, 0, true); - } - - public void Client_onUpdateData_xyz_yr_optimized(MemoryStream stream) - { - Int32 eid = getViewEntityIDFromStream(stream); - - Vector2 xz = stream.readPackXZ(); - float y = stream.readPackY(); - - SByte yaw = stream.readInt8(); - SByte r = stream.readInt8(); - - _updateVolatileData(eid, xz[0], y, xz[1], yaw, KBEMath.KBE_FLT_MAX, r, 0, true); - } - - public void Client_onUpdateData_xyz_pr_optimized(MemoryStream stream) - { - Int32 eid = getViewEntityIDFromStream(stream); - - Vector2 xz = stream.readPackXZ(); - float y = stream.readPackY(); - - SByte p = stream.readInt8(); - SByte r = stream.readInt8(); - - _updateVolatileData(eid, xz[0], y, xz[1], KBEMath.KBE_FLT_MAX, p, r, 0, true); - } - - public void Client_onUpdateData_xyz_y_optimized(MemoryStream stream) - { - Int32 eid = getViewEntityIDFromStream(stream); - - Vector2 xz = stream.readPackXZ(); - float y = stream.readPackY(); - - SByte yaw = stream.readInt8(); - _updateVolatileData(eid, xz[0], y, xz[1], yaw, KBEMath.KBE_FLT_MAX, KBEMath.KBE_FLT_MAX, 0, true); - } - - public void Client_onUpdateData_xyz_p_optimized(MemoryStream stream) - { - Int32 eid = getViewEntityIDFromStream(stream); - - Vector2 xz = stream.readPackXZ(); - float y = stream.readPackY(); - - SByte p = stream.readInt8(); - - _updateVolatileData(eid, xz[0], y, xz[1], KBEMath.KBE_FLT_MAX, p, KBEMath.KBE_FLT_MAX, 0, true); - } - - public void Client_onUpdateData_xyz_r_optimized(MemoryStream stream) - { - Int32 eid = getViewEntityIDFromStream(stream); - - Vector2 xz = stream.readPackXZ(); - float y = stream.readPackY(); - - SByte r = stream.readInt8(); - - _updateVolatileData(eid, xz[0], y, xz[1], KBEMath.KBE_FLT_MAX, KBEMath.KBE_FLT_MAX, r, 0, true); - } - - private void _updateVolatileData(Int32 entityID, float x, float y, float z, float yaw, float pitch, float roll, sbyte isOnGround, bool isOptimized) - { - Entity entity = null; - - if(!entities.TryGetValue(entityID, out entity)) - { - // 如果为0且客户端上一步是重登陆或者重连操作并且服务端entity在断线期间一直处于在线状态 - // 则可以忽略这个错误, 因为cellapp可能一直在向baseapp发送同步消息, 当客户端重连上时未等 - // 服务端初始化步骤开始则收到同步信息, 此时这里就会出错。 - Dbg.ERROR_MSG("KBEngine::_updateVolatileData: entity(" + entityID + ") not found!"); - return; - } - - // 小于0不设置 - if(isOnGround >= 0) - { - entity.isOnGround = (isOnGround > 0); - } - - bool changeDirection = false; - - if(roll != KBEMath.KBE_FLT_MAX) - { - changeDirection = true; - entity.direction.x = KBEMath.int82angle((SByte)roll, false) * 360 / ((float)System.Math.PI * 2); - } - - if(pitch != KBEMath.KBE_FLT_MAX) - { - changeDirection = true; - entity.direction.y = KBEMath.int82angle((SByte)pitch, false) * 360 / ((float)System.Math.PI * 2); - } - - if(yaw != KBEMath.KBE_FLT_MAX) - { - changeDirection = true; - entity.direction.z = KBEMath.int82angle((SByte)yaw, false) * 360 / ((float)System.Math.PI * 2); - } - - bool done = false; - if(changeDirection == true) - { - Event.fireOut(EventOutTypes.set_direction, entity); - done = true; - } - - bool positionChanged = x != KBEMath.KBE_FLT_MAX || y != KBEMath.KBE_FLT_MAX || z != KBEMath.KBE_FLT_MAX; - if (x == KBEMath.KBE_FLT_MAX) x = 0.0f; - if (y == KBEMath.KBE_FLT_MAX) y = 0.0f; - if (z == KBEMath.KBE_FLT_MAX) z = 0.0f; - - if(positionChanged) - { - Vector3 pos = isOptimized ? new Vector3(x + _entityServerPos.x, y + _entityServerPos.y, z + _entityServerPos.z) : new Vector3(x, y, z); - - entity.position = pos; - done = true; - Event.fireOut(EventOutTypes.updatePosition, entity); - } - - if(done) - entity.onUpdateVolatileData(); - } - - /* - 服务端通知流数据下载开始 - 请参考API手册关于onStreamDataStarted - */ - public void Client_onStreamDataStarted(Int16 id, UInt32 datasize, string descr) - { - Event.fireOut(EventOutTypes.onStreamDataStarted, id, datasize, descr); - } - - public void Client_onStreamDataRecv(MemoryStream stream) - { - Int16 resID = stream.readInt16(); - byte[] datas = stream.readBlob(); - Event.fireOut(EventOutTypes.onStreamDataRecv, resID, datas); - } - - public void Client_onStreamDataCompleted(Int16 id) - { - Event.fireOut(EventOutTypes.onStreamDataCompleted, id); - } - } - - - public class KBEngineAppThread : KBEngineApp - { - /* - KBEngine处理线程 - */ - public class KBEThread - { - - KBEngineApp app_; - public bool over = false; - - public KBEThread(KBEngineApp app) - { - this.app_ = app; - } - - public void run() - { - Dbg.INFO_MSG("KBEThread::run()"); - over = false; - - try - { - this.app_.process(); - } - catch (Exception e) - { - Dbg.ERROR_MSG(e.ToString()); - } - - over = true; - Dbg.INFO_MSG("KBEThread::end()"); - } - } - - private Thread _t = null; - public KBEThread kbethread = null; - - // 主循环频率 - public static int threadUpdateHZ = 10; - - // 主循环周期ms 优化去掉循环中做除法 - private static float threadUpdatePeriod = 1000f / threadUpdateHZ; - - // 插件是否退出 - private bool _isbreak = false; - - private System.DateTime _lasttime = System.DateTime.Now; - - public KBEngineAppThread(KBEngineArgs args) : - base(args) - { - } - - public override bool initialize(KBEngineArgs args) - { - base.initialize(args); - - KBEngineAppThread.threadUpdateHZ = args.threadUpdateHZ; - threadUpdatePeriod = 1000f / threadUpdateHZ; - - kbethread = new KBEThread(this); - _t = new Thread(new ThreadStart(kbethread.run)); - _t.Start(); - - return true; - } - - public override void reset() - { - _isbreak = false; - _lasttime = System.DateTime.Now; - - base.reset(); - } - - /* - 插件退出处理 - */ - public void breakProcess() - { - _isbreak = true; - } - - public bool isbreak() - { - return _isbreak; - } - - public override void process() - { - while(!isbreak()) - { - base.process(); - _thread_wait(); - } - - Dbg.WARNING_MSG("KBEngineAppThread::process(): break!"); - } - - /* - 防止占满CPU, 需要让线程等待一会 - */ - void _thread_wait() - { - TimeSpan span = DateTime.Now - _lasttime; - - int diff = (int)(threadUpdatePeriod - span.TotalMilliseconds); - - if(diff < 0) - diff = 0; - - System.Threading.Thread.Sleep(diff); - _lasttime = DateTime.Now; - } - - public override void destroy() - { - Dbg.WARNING_MSG("KBEngineAppThread::destroy()"); - breakProcess(); - - int i = 0; - while(!kbethread.over && i < 50) - { - Thread.Sleep(100); - i += 1; - } - - if(_t != null) - _t.Abort(); - - _t = null; - - base.destroy(); - } - } -} +namespace KBEngine +{ + using UnityEngine; + using System; + using System.Collections; + using System.Collections.Generic; + using System.Text; + using System.Threading; + using System.Text.RegularExpressions; + + using MessageID = System.UInt16; + using MessageLength = System.UInt16; + + /* + 这是KBEngine插件的核心模块 + 包括网络创建、持久化协议、entities的管理、以及引起对外可调用接口。 + + 一些可以参考的地方: + http://kbengine.github.io/docs/programming/clientsdkprogramming.html + http://kbengine.github.io/docs/programming/kbe_message_format.html + + http://kbengine.github.io/cn/docs/programming/clientsdkprogramming.html + http://kbengine.github.io/cn/docs/programming/kbe_message_format.html + */ + public class KBEngineApp + { + public static KBEngineApp app = null; + private NetworkInterface _networkInterface = null; + + KBEngineArgs _args = null; + + // 客户端的类别 + // http://kbengine.github.io/docs/programming/clientsdkprogramming.html + // http://kbengine.github.io/cn/docs/programming/clientsdkprogramming.html + public enum CLIENT_TYPE + { + // Mobile(Phone, Pad) + CLIENT_TYPE_MOBILE = 1, + + // Windows Application program + CLIENT_TYPE_WIN = 2, + + // Linux Application program + CLIENT_TYPE_LINUX = 3, + + // Mac Application program + CLIENT_TYPE_MAC = 4, + + // Web,HTML5,Flash + CLIENT_TYPE_BROWSER = 5, + + // bots + CLIENT_TYPE_BOTS = 6, + + // Mini-Client + CLIENT_TYPE_MINI = 7, + }; + + //加密通信类型 + public enum NETWORK_ENCRYPT_TYPE + { + //无加密 + ENCRYPT_TYPE_NONE = 0, + + //Blowfish + ENCRYPT_TYPE_BLOWFISH = 1, + }; + + public string username = "kbengine"; + public string password = "123456"; + + // 服务端分配的baseapp地址 + public string baseappIP = ""; + public UInt16 baseappPort = 0; + + // 当前状态 + public string currserver = ""; + public string currstate = ""; + + // 服务端下行以及客户端上行用于登录时处理的账号绑定的二进制信息 + // 该信息由用户自己进行扩展 + private byte[] _serverdatas = new byte[0]; + private byte[] _clientdatas = new byte[0]; + + // 通信协议加密,blowfish协议 + private byte[] _encryptedKey = new byte[0]; + + // 服务端与客户端的版本号以及协议MD5 + public string serverVersion = ""; + public string clientVersion = "1.3.6"; + public string serverScriptVersion = ""; + public string clientScriptVersion = "0.1.0"; + public string serverProtocolMD5 = "13AF19B0A958067AEB2BC4ED1CD3B46F"; + public string serverEntitydefMD5 = "2B445B443EFC9427000733CD39EB2700"; + + // 当前玩家的实体id与实体类别 + public UInt64 entity_uuid = 0; + public Int32 entity_id = 0; + public string entity_type = ""; + + private List _controlledEntities = new List(); + + // 当前服务端最后一次同步过来的玩家位置 + private Vector3 _entityServerPos = new Vector3(0f, 0f, 0f); + + // space的数据,具体看API手册关于spaceData + // https://github.com/kbengine/kbengine/tree/master/docs/api + private Dictionary _spacedatas = new Dictionary(); + + // 所有实体都保存于这里, 请参看API手册关于entities部分 + // https://github.com/kbengine/kbengine/tree/master/docs/api + public Dictionary entities = new Dictionary(); + + // 在玩家View范围小于256个实体时我们可以通过一字节索引来找到entity + private List _entityIDAliasIDList = new List(); + private Dictionary _bufferedCreateEntityMessages = new Dictionary(); + + // 所有服务端错误码对应的错误描述 + private ServerErrorDescrs _serverErrs = new ServerErrorDescrs(); + + private System.DateTime _lastTickTime = System.DateTime.Now; + private System.DateTime _lastTickCBTime = System.DateTime.Now; + private System.DateTime _lastUpdateToServerTime = System.DateTime.Now; + + //上传玩家信息到服务器间隔,单位毫秒 + private float _updatePlayerToServerPeroid = 100.0f; + private const int _1MS_TO_100NS = 10000; + + //加密过滤器 + private EncryptionFilter _filter = null; + + // 玩家当前所在空间的id, 以及空间对应的资源 + public UInt32 spaceID = 0; + public string spaceResPath = ""; + public bool isLoadedGeometry = false; + + // 按照标准,每个客户端部分都应该包含这个属性 + public const string component = "client"; + + public KBEngineApp(KBEngineArgs args) + { + if (app != null) + throw new Exception("Only one instance of KBEngineApp!"); + + app = this; + Event.outEventsImmediately = !args.isMultiThreads; + + initialize(args); + } + + public static KBEngineApp getSingleton() + { + if(KBEngineApp.app == null) + { + throw new Exception("Please create KBEngineApp!"); + } + + return KBEngineApp.app; + } + + public virtual bool initialize(KBEngineArgs args) + { + _args = args; + _updatePlayerToServerPeroid = (float)_args.syncPlayerMS; + + EntityDef.init(); + + initNetwork(); + + // 注册事件 + installEvents(); + + return true; + } + + void initNetwork() + { + _filter = null; + Messages.init(); + _networkInterface = new NetworkInterface(); + } + + void installEvents() + { + Event.registerIn(EventInTypes.createAccount, this, "createAccount"); + Event.registerIn(EventInTypes.login, this, "login"); + Event.registerIn(EventInTypes.logout, this, "logout"); + Event.registerIn(EventInTypes.reloginBaseapp, this, "reloginBaseapp"); + Event.registerIn(EventInTypes.resetPassword, this, "resetPassword"); + Event.registerIn(EventInTypes.bindAccountEmail, this, "bindAccountEmail"); + Event.registerIn(EventInTypes.newPassword, this, "newPassword"); + + // 内部事件 + Event.registerIn("_closeNetwork", this, "_closeNetwork"); + } + + public KBEngineArgs getInitArgs() + { + return _args; + } + + public virtual void destroy() + { + Dbg.WARNING_MSG("KBEngine::destroy()"); + + if(currserver == "baseapp") + logout(); + + reset(); + KBEngine.Event.deregisterIn(this); + resetMessages(); + + KBEngineApp.app = null; + } + + public NetworkInterface networkInterface() + { + return _networkInterface; + } + + public byte[] serverdatas() + { + return _serverdatas; + } + + public void entityServerPos(Vector3 pos) + { + _entityServerPos = pos; + } + + public void resetMessages() + { + _serverErrs.Clear(); + Messages.clear(); + EntityDef.reset(); + + Entity.clear(); + Dbg.DEBUG_MSG("KBEngine::resetMessages()"); + } + + public virtual void reset() + { + KBEngine.Event.clearFiredEvents(); + + clearEntities(true); + + currserver = ""; + currstate = ""; + _serverdatas = new byte[0]; + serverVersion = ""; + serverScriptVersion = ""; + + entity_uuid = 0; + entity_id = 0; + entity_type = ""; + + _entityIDAliasIDList.Clear(); + _bufferedCreateEntityMessages.Clear(); + + _lastTickTime = System.DateTime.Now; + _lastTickCBTime = System.DateTime.Now; + _lastUpdateToServerTime = System.DateTime.Now; + + spaceID = 0; + spaceResPath = ""; + isLoadedGeometry = false; + + if (_networkInterface != null) + _networkInterface.reset(); + + _filter = null; + _networkInterface = new NetworkInterface(); + + _spacedatas.Clear(); + } + + public static bool validEmail(string strEmail) + { + return Regex.IsMatch(strEmail, @"^([\w-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.) + |(([\w-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$"); + } + + /* + 插件的主循环处理函数 + */ + public virtual void process() + { + // 处理网络 + if (_networkInterface != null) + _networkInterface.process(); + + // 处理外层抛入的事件 + Event.processInEvents(); + + // 向服务端发送心跳以及同步角色信息到服务端 + sendTick(); + } + + /* + 当前玩家entity + */ + public Entity player() + { + Entity e; + if(entities.TryGetValue(entity_id, out e)) + return e; + + return null; + } + + public void _closeNetwork(NetworkInterface networkInterface) + { + networkInterface.close(); + } + + /* + 向服务端发送心跳以及同步角色信息到服务端 + */ + public void sendTick() + { + if(_networkInterface == null || _networkInterface.connected == false) + return; + + TimeSpan span = DateTime.Now - _lastTickTime; + + // 更新玩家的位置与朝向到服务端 + updatePlayerToServer(); + + if(_args.serverHeartbeatTick > 0 && span.Seconds > _args.serverHeartbeatTick) + { + span = _lastTickCBTime - _lastTickTime; + + // 如果心跳回调接收时间小于心跳发送时间,说明没有收到回调 + // 此时应该通知客户端掉线了 + if(span.Seconds < 0) + { + Dbg.ERROR_MSG("sendTick: Receive appTick timeout!"); + _networkInterface.close(); + return; + } + + Message Loginapp_onClientActiveTickMsg = null; + Message Baseapp_onClientActiveTickMsg = null; + + Messages.messages.TryGetValue("Loginapp_onClientActiveTick", out Loginapp_onClientActiveTickMsg); + Messages.messages.TryGetValue("Baseapp_onClientActiveTick", out Baseapp_onClientActiveTickMsg); + + if(currserver == "loginapp") + { + if(Loginapp_onClientActiveTickMsg != null) + { + Bundle bundle = Bundle.createObject(); + bundle.newMessage(Messages.messages["Loginapp_onClientActiveTick"]); + bundle.send(_networkInterface); + } + } + else + { + if(Baseapp_onClientActiveTickMsg != null) + { + Bundle bundle = Bundle.createObject(); + bundle.newMessage(Messages.messages["Baseapp_onClientActiveTick"]); + bundle.send(_networkInterface); + } + } + + _lastTickTime = System.DateTime.Now; + } + } + + /* + 服务器心跳回调 + */ + public void Client_onAppActiveTickCB() + { + _lastTickCBTime = System.DateTime.Now; + } + + /* + 与服务端握手,与任何一个进程连接之后应该第一时间进行握手 + */ + public void hello() + { + Bundle bundle = Bundle.createObject(); + if(currserver == "loginapp") + bundle.newMessage(Messages.messages["Loginapp_hello"]); + else + bundle.newMessage(Messages.messages["Baseapp_hello"]); + + _filter = null; + + if (_args.networkEncryptType == NETWORK_ENCRYPT_TYPE.ENCRYPT_TYPE_BLOWFISH) + { + _filter = new BlowfishFilter(); + _encryptedKey = ((BlowfishFilter)_filter).key(); + _networkInterface.setFilter(null); + } + + bundle.writeString(clientVersion); + bundle.writeString(clientScriptVersion); + bundle.writeBlob(_encryptedKey); + bundle.send(_networkInterface); + } + + /* + 握手之后服务端的回调 + */ + public void Client_onHelloCB(MemoryStream stream) + { + string str_serverVersion = stream.readString(); + serverScriptVersion = stream.readString(); + string currentServerProtocolMD5 = stream.readString(); + string currentServerEntitydefMD5 = stream.readString(); + Int32 ctype = stream.readInt32(); + + Dbg.DEBUG_MSG("KBEngine::Client_onHelloCB: verInfo(" + str_serverVersion + + "), scriptVersion("+ serverScriptVersion + "), srvProtocolMD5("+ serverProtocolMD5 + + "), srvEntitydefMD5("+ serverEntitydefMD5 + "), + ctype(" + ctype + ")!"); + + if(str_serverVersion != "Getting") + { + serverVersion = str_serverVersion; + + /* + if(serverProtocolMD5 != currentServerProtocolMD5) + { + Dbg.ERROR_MSG("Client_onHelloCB: digest not match! serverProtocolMD5=" + serverProtocolMD5 + "(server: " + currentServerProtocolMD5 + ")"); + Event.fireAll(EventOutTypes.onVersionNotMatch, clientVersion, serverVersion); + return; + } + */ + + if (serverEntitydefMD5 != currentServerEntitydefMD5) + { + Dbg.ERROR_MSG("Client_onHelloCB: digest not match! serverEntitydefMD5=" + serverEntitydefMD5 + "(server: " + currentServerEntitydefMD5 + ")"); + Event.fireAll(EventOutTypes.onVersionNotMatch, clientVersion, serverVersion); + return; + } + } + + if (_args.networkEncryptType == NETWORK_ENCRYPT_TYPE.ENCRYPT_TYPE_BLOWFISH) + { + _networkInterface.setFilter(_filter); + _filter = null; + } + + + onServerDigest(); + + if(currserver == "baseapp") + { + onLogin_baseapp(); + } + else + { + onLogin_loginapp(); + } + } + + /* + 服务端错误描述导入了 + */ + public void Client_onImportServerErrorsDescr(MemoryStream stream) + { + // 无需实现,已由插件生成静态代码 + } + + /* + 从服务端返回的二进制流导入客户端消息协议 + */ + public void Client_onImportClientMessages(MemoryStream stream) + { + // 无需实现,已由插件生成静态代码 + } + + /* + 从服务端返回的二进制流导入客户端消息协议 + */ + public void Client_onImportClientEntityDef(MemoryStream stream) + { + // 无需实现,已由插件生成静态代码 + } + + public void Client_onImportClientSDK(MemoryStream stream) + { + int remainingFiles = 0; + remainingFiles = stream.readInt32(); + + string fileName; + fileName = stream.readString(); + + int fileSize = 0; + fileSize = stream.readInt32(); + + byte[] fileDatas = new byte[0]; + fileDatas = stream.readBlob(); + + Event.fireIn("onImportClientSDK", remainingFiles, fileName, fileSize, fileDatas); + } + + /* + 引擎版本不匹配 + */ + public void Client_onVersionNotMatch(MemoryStream stream) + { + serverVersion = stream.readString(); + + Dbg.ERROR_MSG("Client_onVersionNotMatch: verInfo=" + clientVersion + "(server: " + serverVersion + ")"); + Event.fireAll(EventOutTypes.onVersionNotMatch, clientVersion, serverVersion); + } + + /* + 脚本版本不匹配 + */ + public void Client_onScriptVersionNotMatch(MemoryStream stream) + { + serverScriptVersion = stream.readString(); + + Dbg.ERROR_MSG("Client_onScriptVersionNotMatch: verInfo=" + clientScriptVersion + "(server: " + serverScriptVersion + ")"); + Event.fireAll(EventOutTypes.onScriptVersionNotMatch, clientScriptVersion, serverScriptVersion); + } + + /* + 被服务端踢出 + */ + public void Client_onKicked(UInt16 failedcode) + { + Dbg.DEBUG_MSG("Client_onKicked: failedcode=" + failedcode + "(" + serverErr(failedcode) + ")"); + Event.fireAll(EventOutTypes.onKicked, failedcode); + } + + /* + 登录到服务端,必须登录完成loginapp与网关(baseapp),登录流程才算完毕 + */ + public void login(string username, string password, byte[] datas) + { + KBEngineApp.app.username = username; + KBEngineApp.app.password = password; + KBEngineApp.app._clientdatas = datas; + + KBEngineApp.app.login_loginapp(true); + } + + /* + 登录到服务端(loginapp), 登录成功后还必须登录到网关(baseapp)登录流程才算完毕 + */ + public void login_loginapp(bool noconnect) + { + if(noconnect) + { + reset(); + _networkInterface.connectTo(_args.ip, _args.port, onConnectTo_loginapp_callback, null); + } + else + { + Dbg.DEBUG_MSG("KBEngine::login_loginapp(): send login! username=" + username); + Bundle bundle = Bundle.createObject(); + bundle.newMessage(Messages.messages["Loginapp_login"]); + bundle.writeInt8((sbyte)_args.clientType); + bundle.writeBlob(KBEngineApp.app._clientdatas); + bundle.writeString(username); + bundle.writeString(password); + bundle.send(_networkInterface); + } + } + + private void onConnectTo_loginapp_callback(string ip, int port, bool success, object userData) + { + _lastTickCBTime = System.DateTime.Now; + + if(!success) + { + Dbg.ERROR_MSG(string.Format("KBEngine::login_loginapp(): connect {0}:{1} error!", ip, port)); + return; + } + + currserver = "loginapp"; + currstate = "login"; + + Dbg.DEBUG_MSG(string.Format("KBEngine::login_loginapp(): connect {0}:{1} success!", ip, port)); + + hello(); + } + + private void onLogin_loginapp() + { + _lastTickCBTime = System.DateTime.Now; + login_loginapp(false); + } + + /* + 登录到服务端,登录到网关(baseapp) + */ + public void login_baseapp(bool noconnect) + { + if(noconnect) + { + Event.fireOut(EventOutTypes.onLoginBaseapp); + + _networkInterface.reset(); + _networkInterface = new NetworkInterface(); + _networkInterface.connectTo(baseappIP, baseappPort, onConnectTo_baseapp_callback, null); + } + else + { + Bundle bundle = Bundle.createObject(); + bundle.newMessage(Messages.messages["Baseapp_loginBaseapp"]); + bundle.writeString(username); + bundle.writeString(password); + bundle.send(_networkInterface); + } + } + + private void onConnectTo_baseapp_callback(string ip, int port, bool success, object userData) + { + _lastTickCBTime = System.DateTime.Now; + + if(!success) + { + Dbg.ERROR_MSG(string.Format("KBEngine::login_baseapp(): connect {0}:{1} error!", ip, port)); + return; + } + + currserver = "baseapp"; + currstate = ""; + + Dbg.DEBUG_MSG(string.Format("KBEngine::login_baseapp(): connect {0}:{1} success!", ip, port)); + + hello(); + } + + private void onLogin_baseapp() + { + _lastTickCBTime = System.DateTime.Now; + login_baseapp(false); + } + + /* + 重登录到网关(baseapp) + 一些移动类应用容易掉线,可以使用该功能快速的重新与服务端建立通信 + */ + public void reloginBaseapp() + { + _lastTickTime = System.DateTime.Now; + _lastTickCBTime = System.DateTime.Now; + + if(_networkInterface.valid()) + return; + + Event.fireAll(EventOutTypes.onReloginBaseapp); + _networkInterface.connectTo(baseappIP, baseappPort, onReConnectTo_baseapp_callback, null); + } + + private void onReConnectTo_baseapp_callback(string ip, int port, bool success, object userData) + { + if(!success) + { + Dbg.ERROR_MSG(string.Format("KBEngine::reloginBaseapp(): connect {0}:{1} error!", ip, port)); + return; + } + + Dbg.DEBUG_MSG(string.Format("KBEngine::relogin_baseapp(): connect {0}:{1} success!", ip, port)); + + Bundle bundle = Bundle.createObject(); + bundle.newMessage(Messages.messages["Baseapp_reloginBaseapp"]); + bundle.writeString(username); + bundle.writeString(password); + bundle.writeUint64(entity_uuid); + bundle.writeInt32(entity_id); + bundle.send(_networkInterface); + + _lastTickCBTime = System.DateTime.Now; + } + + /* + 登出baseapp + */ + public void logout() + { + Bundle bundle = Bundle.createObject(); + bundle.newMessage(Messages.messages["Baseapp_logoutBaseapp"]); + bundle.writeUint64(entity_uuid); + bundle.writeInt32(entity_id); + bundle.send(_networkInterface); + } + + /* + 通过错误id得到错误描述 + */ + public string serverErr(UInt16 id) + { + return _serverErrs.serverErrStr(id); + } + + public void onOpenLoginapp_resetpassword() + { + Dbg.DEBUG_MSG("KBEngine::onOpenLoginapp_resetpassword: successfully!"); + currserver = "loginapp"; + currstate = "resetpassword"; + _lastTickCBTime = System.DateTime.Now; + + resetpassword_loginapp(false); + } + + /* + 重置密码, 通过loginapp + */ + public void resetPassword(string username) + { + KBEngineApp.app.username = username; + resetpassword_loginapp(true); + } + + /* + 重置密码, 通过loginapp + */ + public void resetpassword_loginapp(bool noconnect) + { + if(noconnect) + { + reset(); + _networkInterface.connectTo(_args.ip, _args.port, onConnectTo_resetpassword_callback, null); + } + else + { + Bundle bundle = Bundle.createObject(); + bundle.newMessage(Messages.messages["Loginapp_reqAccountResetPassword"]); + bundle.writeString(username); + bundle.send(_networkInterface); + } + } + + private void onConnectTo_resetpassword_callback(string ip, int port, bool success, object userData) + { + _lastTickCBTime = System.DateTime.Now; + + if(!success) + { + Dbg.ERROR_MSG(string.Format("KBEngine::resetpassword_loginapp(): connect {0}:{1} error!", ip, port)); + return; + } + + Dbg.DEBUG_MSG(string.Format("KBEngine::resetpassword_loginapp(): connect {0}:{1} success!", ip, port)); + onOpenLoginapp_resetpassword(); + } + + public void Client_onReqAccountResetPasswordCB(UInt16 failcode) + { + if(failcode != 0) + { + Dbg.ERROR_MSG("KBEngine::Client_onReqAccountResetPasswordCB: " + username + " failed! code=" + failcode + "(" + serverErr(failcode) + ")!"); + return; + } + + Dbg.DEBUG_MSG("KBEngine::Client_onReqAccountResetPasswordCB: " + username + " success!"); + } + + /* + 绑定Email,通过baseapp + */ + public void bindAccountEmail(string emailAddress) + { + Bundle bundle = Bundle.createObject(); + bundle.newMessage(Messages.messages["Baseapp_reqAccountBindEmail"]); + bundle.writeInt32(entity_id); + bundle.writeString(password); + bundle.writeString(emailAddress); + bundle.send(_networkInterface); + } + + public void Client_onReqAccountBindEmailCB(UInt16 failcode) + { + if(failcode != 0) + { + Dbg.ERROR_MSG("KBEngine::Client_onReqAccountBindEmailCB: " + username + " failed! code=" + failcode + "(" + serverErr(failcode) + ")!"); + return; + } + + Dbg.DEBUG_MSG("KBEngine::Client_onReqAccountBindEmailCB: " + username + " success!"); + } + + /* + 设置新密码,通过baseapp, 必须玩家登录在线操作所以是baseapp。 + */ + public void newPassword(string old_password, string new_password) + { + Bundle bundle = Bundle.createObject(); + bundle.newMessage(Messages.messages["Baseapp_reqAccountNewPassword"]); + bundle.writeInt32(entity_id); + bundle.writeString(old_password); + bundle.writeString(new_password); + bundle.send(_networkInterface); + } + + public void Client_onReqAccountNewPasswordCB(UInt16 failcode) + { + if(failcode != 0) + { + Dbg.ERROR_MSG("KBEngine::Client_onReqAccountNewPasswordCB: " + username + " failed! code=" + failcode + "(" + serverErr(failcode) + ")!"); + return; + } + + Dbg.DEBUG_MSG("KBEngine::Client_onReqAccountNewPasswordCB: " + username + " success!"); + } + + public void createAccount(string username, string password, byte[] datas) + { + KBEngineApp.app.username = username; + KBEngineApp.app.password = password; + KBEngineApp.app._clientdatas = datas; + + KBEngineApp.app.createAccount_loginapp(true); + } + + /* + 创建账号,通过loginapp + */ + public void createAccount_loginapp(bool noconnect) + { + if(noconnect) + { + reset(); + _networkInterface.connectTo(_args.ip, _args.port, onConnectTo_createAccount_callback, null); + } + else + { + Bundle bundle = Bundle.createObject(); + bundle.newMessage(Messages.messages["Loginapp_reqCreateAccount"]); + bundle.writeString(username); + bundle.writeString(password); + bundle.writeBlob(KBEngineApp.app._clientdatas); + bundle.send(_networkInterface); + } + } + + public void onOpenLoginapp_createAccount() + { + Dbg.DEBUG_MSG("KBEngine::onOpenLoginapp_createAccount: successfully!"); + currserver = "loginapp"; + currstate = "createAccount"; + _lastTickCBTime = System.DateTime.Now; + + createAccount_loginapp(false); + } + + private void onConnectTo_createAccount_callback(string ip, int port, bool success, object userData) + { + _lastTickCBTime = System.DateTime.Now; + + if(!success) + { + Dbg.ERROR_MSG(string.Format("KBEngine::createAccount_loginapp(): connect {0}:{1} error!", ip, port)); + return; + } + + Dbg.DEBUG_MSG(string.Format("KBEngine::createAccount_loginapp(): connect {0}:{1} success!", ip, port)); + onOpenLoginapp_createAccount(); + } + + /* + 获得了服务端摘要信息, 摘要包括协议MD5, entitydefMD5 + */ + public void onServerDigest() + { + } + + /* + 登录loginapp失败了 + */ + public void Client_onLoginFailed(MemoryStream stream) + { + UInt16 failedcode = stream.readUint16(); + _serverdatas = stream.readBlob(); + Dbg.ERROR_MSG("KBEngine::Client_onLoginFailed: failedcode(" + failedcode + ":" + serverErr(failedcode) + "), datas(" + _serverdatas.Length + ")!"); + Event.fireAll(EventOutTypes.onLoginFailed, failedcode, _serverdatas); + } + + /* + 登录loginapp成功了 + */ + public void Client_onLoginSuccessfully(MemoryStream stream) + { + var accountName = stream.readString(); + username = accountName; + baseappIP = stream.readString(); + baseappPort = stream.readUint16(); + _serverdatas = stream.readBlob(); + + Dbg.DEBUG_MSG("KBEngine::Client_onLoginSuccessfully: accountName(" + accountName + "), addr(" + + baseappIP + ":" + baseappPort + "), datas(" + _serverdatas.Length + ")!"); + + login_baseapp(true); + } + + /* + 登录baseapp失败了 + */ + public void Client_onLoginBaseappFailed(UInt16 failedcode) + { + Dbg.ERROR_MSG("KBEngine::Client_onLoginBaseappFailed: failedcode=" + failedcode + "("+ serverErr(failedcode) + ")!"); + Event.fireAll(EventOutTypes.onLoginBaseappFailed, failedcode); + } + + /* + 重登录baseapp失败了 + */ + public void Client_onReloginBaseappFailed(UInt16 failedcode) + { + Dbg.ERROR_MSG("KBEngine::Client_onReloginBaseappFailed: failedcode=" + failedcode + "(" + serverErr(failedcode) + ")!"); + Event.fireAll(EventOutTypes.onReloginBaseappFailed, failedcode); + } + + /* + 登录baseapp成功了 + */ + public void Client_onReloginBaseappSuccessfully(MemoryStream stream) + { + entity_uuid = stream.readUint64(); + Dbg.DEBUG_MSG("KBEngine::Client_onReloginBaseappSuccessfully: name(" + username + ")!"); + Event.fireAll(EventOutTypes.onReloginBaseappSuccessfully); + } + + /* + 服务端通知创建一个角色 + */ + public void Client_onCreatedProxies(UInt64 rndUUID, Int32 eid, string entityType) + { + Dbg.DEBUG_MSG("KBEngine::Client_onCreatedProxies: eid(" + eid + "), entityType(" + entityType + ")!"); + + entity_uuid = rndUUID; + entity_id = eid; + entity_type = entityType; + + if(!this.entities.ContainsKey(eid)) + { + ScriptModule module = null; + if(!EntityDef.moduledefs.TryGetValue(entityType, out module)) + { + Dbg.ERROR_MSG("KBEngine::Client_onCreatedProxies: not found module(" + entityType + ")!"); + return; + } + + Type runclass = module.entityScript; + if(runclass == null) + return; + + Entity entity = (Entity)Activator.CreateInstance(runclass); + entity.id = eid; + entity.className = entityType; + entity.onGetBase(); + + entities[eid] = entity; + + MemoryStream entityMessage = null; + _bufferedCreateEntityMessages.TryGetValue(eid, out entityMessage); + + if(entityMessage != null) + { + Client_onUpdatePropertys(entityMessage); + _bufferedCreateEntityMessages.Remove(eid); + entityMessage.reclaimObject(); + } + + entity.__init__(); + entity.inited = true; + + if(_args.isOnInitCallPropertysSetMethods) + entity.callPropertysSetMethods(); + } + else + { + MemoryStream entityMessage = null; + _bufferedCreateEntityMessages.TryGetValue(eid, out entityMessage); + + if(entityMessage != null) + { + Client_onUpdatePropertys(entityMessage); + _bufferedCreateEntityMessages.Remove(eid); + entityMessage.reclaimObject(); + } + } + } + + public Entity findEntity(Int32 entityID) + { + Entity entity = null; + + if(!entities.TryGetValue(entityID, out entity)) + { + return null; + } + + return entity; + } + + /* + 通过流数据获得View实体的ID + */ + public Int32 getViewEntityIDFromStream(MemoryStream stream) + { + if (!_args.useAliasEntityID) + return stream.readInt32(); + + Int32 id = 0; + if(_entityIDAliasIDList.Count > 255) + { + id = stream.readInt32(); + } + else + { + byte aliasID = stream.readUint8(); + + // 如果为0且客户端上一步是重登陆或者重连操作并且服务端entity在断线期间一直处于在线状态 + // 则可以忽略这个错误, 因为cellapp可能一直在向baseapp发送同步消息, 当客户端重连上时未等 + // 服务端初始化步骤开始则收到同步信息, 此时这里就会出错。 + if(_entityIDAliasIDList.Count <= aliasID) + return 0; + + id = _entityIDAliasIDList[aliasID]; + } + + return id; + } + + /* + 服务端使用优化的方式更新实体属性数据 + */ + public void Client_onUpdatePropertysOptimized(MemoryStream stream) + { + Int32 eid = getViewEntityIDFromStream(stream); + onUpdatePropertys_(eid, stream); + } + + /* + 服务端更新实体属性数据 + */ + public void Client_onUpdatePropertys(MemoryStream stream) + { + Int32 eid = stream.readInt32(); + onUpdatePropertys_(eid, stream); + } + + public void onUpdatePropertys_(Int32 eid, MemoryStream stream) + { + Entity entity = null; + + if(!entities.TryGetValue(eid, out entity)) + { + MemoryStream entityMessage = null; + if(_bufferedCreateEntityMessages.TryGetValue(eid, out entityMessage)) + { + Dbg.ERROR_MSG("KBEngine::Client_onUpdatePropertys: entity(" + eid + ") not found!"); + return; + } + + MemoryStream stream1 = MemoryStream.createObject(); + stream1.wpos = stream.wpos; + stream1.rpos = stream.rpos - 4; + Array.Copy(stream.data(), stream1.data(), stream.data().Length); + _bufferedCreateEntityMessages[eid] = stream1; + return; + } + + ScriptModule sm = EntityDef.moduledefs[entity.className]; + Dictionary pdatas = sm.idpropertys; + + while(stream.length() > 0) + { + UInt16 utype = 0; + + if(sm.usePropertyDescrAlias) + { + utype = stream.readUint8(); + } + else + { + utype = stream.readUint16(); + } + + Property propertydata = pdatas[utype]; + entity.onUpdatePropertys(propertydata, stream); + + // Dbg.DEBUG_MSG("KBEngine::Client_onUpdatePropertys: " + entity.className + "(id=" + eid + " " + + // propertydata.name + "=" + val + "), hasSetMethod=" + setmethod + "!"); + } + } + + /* + 服务端使用优化的方式调用实体方法 + */ + public void Client_onRemoteMethodCallOptimized(MemoryStream stream) + { + Int32 eid = getViewEntityIDFromStream(stream); + onRemoteMethodCall_(eid, stream); + } + + /* + 服务端调用实体方法 + */ + public void Client_onRemoteMethodCall(MemoryStream stream) + { + Int32 eid = stream.readInt32(); + onRemoteMethodCall_(eid, stream); + } + + public void onRemoteMethodCall_(Int32 eid, MemoryStream stream) + { + Entity entity = null; + + if(!entities.TryGetValue(eid, out entity)) + { + Dbg.ERROR_MSG("KBEngine::Client_onRemoteMethodCall: entity(" + eid + ") not found!"); + return; + } + + UInt16 methodUtype = 0; + ScriptModule sm = EntityDef.moduledefs[entity.className]; + + if(sm.useMethodDescrAlias) + methodUtype = stream.readUint8(); + else + methodUtype = stream.readUint16(); + + Method methoddata = null; + + try + { + methoddata = sm.idmethods[methodUtype]; + } + catch (Exception e) + { + Dbg.ERROR_MSG("KBEngine::Client_onRemoteMethodCall: " + entity.className + "(" + eid + "), methodUtype(" + methodUtype + ")!\nerror=" + e.ToString()); + return; + } + + // Dbg.DEBUG_MSG("KBEngine::Client_onRemoteMethodCall: " + entity.className + "." + methoddata.name); + + entity.onRemoteMethodCall(methoddata, stream); + } + + /* + 服务端通知一个实体进入了世界(如果实体是当前玩家则玩家第一次在一个space中创建了, 如果是其他实体则是其他实体进入了玩家的View) + */ + public void Client_onEntityEnterWorld(MemoryStream stream) + { + Int32 eid = stream.readInt32(); + if(entity_id > 0 && entity_id != eid) + _entityIDAliasIDList.Add(eid); + + UInt16 uentityType; + if(EntityDef.idmoduledefs.Count > 255) + uentityType = stream.readUint16(); + else + uentityType = stream.readUint8(); + + sbyte isOnGround = 1; + + if(stream.length() > 0) + isOnGround = stream.readInt8(); + + string entityType = EntityDef.idmoduledefs[uentityType].name; + // Dbg.DEBUG_MSG("KBEngine::Client_onEntityEnterWorld: " + entityType + "(" + eid + "), spaceID(" + KBEngineApp.app.spaceID + ")!"); + + Entity entity = null; + + if(!entities.TryGetValue(eid, out entity)) + { + MemoryStream entityMessage = null; + if(!_bufferedCreateEntityMessages.TryGetValue(eid, out entityMessage)) + { + Dbg.ERROR_MSG("KBEngine::Client_onEntityEnterWorld: entity(" + eid + ") not found!"); + return; + } + + ScriptModule module = null; + if(!EntityDef.moduledefs.TryGetValue(entityType, out module)) + { + Dbg.ERROR_MSG("KBEngine::Client_onEntityEnterWorld: not found module(" + entityType + ")!"); + } + + Type runclass = module.entityScript; + if(runclass == null) + return; + + entity = (Entity)Activator.CreateInstance(runclass); + entity.id = eid; + entity.className = entityType; + entity.onGetCell(); + + entities[eid] = entity; + + Client_onUpdatePropertys(entityMessage); + _bufferedCreateEntityMessages.Remove(eid); + entityMessage.reclaimObject(); + + entity.isOnGround = isOnGround > 0; + entity.onDirectionChanged(entity.direction); + entity.onPositionChanged(entity.position); + + entity.__init__(); + entity.inited = true; + entity.inWorld = true; + entity.enterWorld(); + + if(_args.isOnInitCallPropertysSetMethods) + entity.callPropertysSetMethods(); + } + else + { + if(!entity.inWorld) + { + // 安全起见, 这里清空一下 + // 如果服务端上使用giveClientTo切换控制权 + // 之前的实体已经进入世界, 切换后的实体也进入世界, 这里可能会残留之前那个实体进入世界的信息 + _entityIDAliasIDList.Clear(); + clearEntities(false); + entities[entity.id] = entity; + + entity.onGetCell(); + + entity.onDirectionChanged(entity.direction); + entity.onPositionChanged(entity.position); + + _entityServerPos = entity.position; + entity.isOnGround = isOnGround > 0; + entity.inWorld = true; + entity.enterWorld(); + + if(_args.isOnInitCallPropertysSetMethods) + entity.callPropertysSetMethods(); + } + } + } + + /* + 服务端使用优化的方式通知一个实体离开了世界(如果实体是当前玩家则玩家离开了space, 如果是其他实体则是其他实体离开了玩家的View) + */ + public void Client_onEntityLeaveWorldOptimized(MemoryStream stream) + { + Int32 eid = getViewEntityIDFromStream(stream); + KBEngineApp.app.Client_onEntityLeaveWorld(eid); + } + + /* + 服务端通知一个实体离开了世界(如果实体是当前玩家则玩家离开了space, 如果是其他实体则是其他实体离开了玩家的View) + */ + public void Client_onEntityLeaveWorld(Int32 eid) + { + Entity entity = null; + + if(!entities.TryGetValue(eid, out entity)) + { + Dbg.ERROR_MSG("KBEngine::Client_onEntityLeaveWorld: entity(" + eid + ") not found!"); + return; + } + + if(entity.inWorld) + entity.leaveWorld(); + + if(entity_id == eid) + { + clearSpace(false); + entity.onLoseCell(); + } + else + { + if(_controlledEntities.Remove(entity)) + Event.fireOut(EventOutTypes.onLoseControlledEntity, entity); + + entities.Remove(eid); + entity.onDestroy(); + _entityIDAliasIDList.Remove(eid); + } + } + + /* + 服务端通知当前玩家进入了一个新的space + */ + public void Client_onEntityEnterSpace(MemoryStream stream) + { + Int32 eid = stream.readInt32(); + spaceID = stream.readUint32(); + + sbyte isOnGround = 1; + + if(stream.length() > 0) + isOnGround = stream.readInt8(); + + Entity entity = null; + + if(!entities.TryGetValue(eid, out entity)) + { + Dbg.ERROR_MSG("KBEngine::Client_onEntityEnterSpace: entity(" + eid + ") not found!"); + return; + } + + entity.isOnGround = isOnGround > 0; + _entityServerPos = entity.position; + entity.enterSpace(); + } + + /* + 服务端通知当前玩家离开了space + */ + public void Client_onEntityLeaveSpace(Int32 eid) + { + Entity entity = null; + + if(!entities.TryGetValue(eid, out entity)) + { + Dbg.ERROR_MSG("KBEngine::Client_onEntityLeaveSpace: entity(" + eid + ") not found!"); + return; + } + + entity.leaveSpace(); + clearSpace(false); + } + + /* + 账号创建返回结果 + */ + public void Client_onCreateAccountResult(MemoryStream stream) + { + UInt16 retcode = stream.readUint16(); + byte[] datas = stream.readBlob(); + + Event.fireOut(EventOutTypes.onCreateAccountResult, retcode, datas); + + if(retcode != 0) + { + Dbg.WARNING_MSG("KBEngine::Client_onCreateAccountResult: " + username + " create is failed! code=" + retcode + "!"); + return; + } + + Dbg.DEBUG_MSG("KBEngine::Client_onCreateAccountResult: " + username + " create is successfully!"); + } + + /* + 告诉客户端:你当前负责(或取消)控制谁的位移同步 + */ + public void Client_onControlEntity(Int32 eid, sbyte isControlled) + { + Entity entity = null; + + if (!entities.TryGetValue(eid, out entity)) + { + Dbg.ERROR_MSG("KBEngine::Client_onControlEntity: entity(" + eid + ") not found!"); + return; + } + + var isCont = isControlled != 0; + if (isCont) + { + // 如果被控制者是玩家自己,那表示玩家自己被其它人控制了 + // 所以玩家自己不应该进入这个被控制列表 + if (player().id != entity.id) + { + _controlledEntities.Add(entity); + } + } + else + { + _controlledEntities.Remove(entity); + } + + entity.isControlled = isCont; + + try + { + entity.onControlled(isCont); + Event.fireOut(EventOutTypes.onControlled, entity, isCont); + } + catch (Exception e) + { + Dbg.ERROR_MSG(string.Format("KBEngine::Client_onControlEntity: entity id = '{0}', is controlled = '{1}', error = '{1}'", eid, isCont, e)); + } + } + + /* + 更新当前玩家的位置与朝向到服务端, 可以通过开关_syncPlayerMS关闭这个机制 + */ + public void updatePlayerToServer() + { + if(_updatePlayerToServerPeroid <= 0.01f || spaceID == 0) + { + return; + } + + var now = DateTime.Now; + TimeSpan span = now - _lastUpdateToServerTime; + + if (span.Ticks < _updatePlayerToServerPeroid * _1MS_TO_100NS) + return; + + Entity playerEntity = player(); + if (playerEntity == null || playerEntity.inWorld == false || playerEntity.isControlled) + return; + + _lastUpdateToServerTime = now - (span - TimeSpan.FromTicks(Convert.ToInt64(_updatePlayerToServerPeroid * _1MS_TO_100NS))); + + Vector3 position = playerEntity.position; + Vector3 direction = playerEntity.direction; + + bool posHasChanged = Vector3.Distance(playerEntity._entityLastLocalPos, position) > 0.001f; + bool dirHasChanged = Vector3.Distance(playerEntity._entityLastLocalDir, direction) > 0.001f; + + if(posHasChanged || dirHasChanged) + { + playerEntity._entityLastLocalPos = position; + playerEntity._entityLastLocalDir = direction; + + Bundle bundle = Bundle.createObject(); + bundle.newMessage(Messages.messages["Baseapp_onUpdateDataFromClient"]); + bundle.writeFloat(position.x); + bundle.writeFloat(position.y); + bundle.writeFloat(position.z); + + double x = ((double)direction.x / 360 * (System.Math.PI * 2)); + double y = ((double)direction.y / 360 * (System.Math.PI * 2)); + double z = ((double)direction.z / 360 * (System.Math.PI * 2)); + + // 根据弧度转角度公式会出现负数 + // unity会自动转化到0~360度之间,这里需要做一个还原 + if(x - System.Math.PI > 0.0) + x -= System.Math.PI * 2; + + if(y - System.Math.PI > 0.0) + y -= System.Math.PI * 2; + + if(z - System.Math.PI > 0.0) + z -= System.Math.PI * 2; + + bundle.writeFloat((float)x); + bundle.writeFloat((float)y); + bundle.writeFloat((float)z); + bundle.writeUint8((Byte)(playerEntity.isOnGround == true ? 1 : 0)); + bundle.writeUint32(spaceID); + bundle.send(_networkInterface); + } + + // 开始同步所有被控制了的entity的位置 + for (int i = 0; i < _controlledEntities.Count; ++i) + { + var entity = _controlledEntities[i]; + position = entity.position; + direction = entity.direction; + + posHasChanged = Vector3.Distance(entity._entityLastLocalPos, position) > 0.001f; + dirHasChanged = Vector3.Distance(entity._entityLastLocalDir, direction) > 0.001f; + + if (posHasChanged || dirHasChanged) + { + entity._entityLastLocalPos = position; + entity._entityLastLocalDir = direction; + + Bundle bundle = Bundle.createObject(); + bundle.newMessage(Messages.messages["Baseapp_onUpdateDataFromClientForControlledEntity"]); + bundle.writeInt32(entity.id); + bundle.writeFloat(position.x); + bundle.writeFloat(position.y); + bundle.writeFloat(position.z); + + double x = ((double)direction.x / 360 * (System.Math.PI * 2)); + double y = ((double)direction.y / 360 * (System.Math.PI * 2)); + double z = ((double)direction.z / 360 * (System.Math.PI * 2)); + + // 根据弧度转角度公式会出现负数 + // unity会自动转化到0~360度之间,这里需要做一个还原 + if(x - System.Math.PI > 0.0) + x -= System.Math.PI * 2; + + if(y - System.Math.PI > 0.0) + y -= System.Math.PI * 2; + + if(z - System.Math.PI > 0.0) + z -= System.Math.PI * 2; + + bundle.writeFloat((float)x); + bundle.writeFloat((float)y); + bundle.writeFloat((float)z); + bundle.writeUint8((Byte)(entity.isOnGround == true ? 1 : 0)); + bundle.writeUint32(spaceID); + bundle.send(_networkInterface); + } + } + } + + /* + 当前space添加了关于几何等信息的映射资源 + 客户端可以通过这个资源信息来加载对应的场景 + */ + public void addSpaceGeometryMapping(UInt32 uspaceID, string respath) + { + Dbg.DEBUG_MSG("KBEngine::addSpaceGeometryMapping: spaceID(" + uspaceID + "), respath(" + respath + ")!"); + + isLoadedGeometry = true; + spaceID = uspaceID; + spaceResPath = respath; + Event.fireOut(EventOutTypes.addSpaceGeometryMapping, spaceResPath); + } + + public void clearSpace(bool isall) + { + _entityIDAliasIDList.Clear(); + _spacedatas.Clear(); + clearEntities(isall); + isLoadedGeometry = false; + spaceID = 0; + } + + public void clearEntities(bool isall) + { + _controlledEntities.Clear(); + + if (!isall) + { + Entity entity = player(); + + foreach (KeyValuePair dic in entities) + { + if(dic.Key == entity.id) + continue; + + if(dic.Value.inWorld) + dic.Value.leaveWorld(); + + dic.Value.onDestroy(); + } + + entities.Clear(); + entities[entity.id] = entity; + } + else + { + foreach (KeyValuePair dic in entities) + { + if(dic.Value.inWorld) + dic.Value.leaveWorld(); + + dic.Value.onDestroy(); + } + + entities.Clear(); + } + } + + /* + 服务端初始化客户端的spacedata, spacedata请参考API + */ + public void Client_initSpaceData(MemoryStream stream) + { + clearSpace(false); + spaceID = stream.readUint32(); + + while(stream.length() > 0) + { + string key = stream.readString(); + string val = stream.readString(); + Client_setSpaceData(spaceID, key, val); + } + + Dbg.DEBUG_MSG("KBEngine::Client_initSpaceData: spaceID(" + spaceID + "), size(" + _spacedatas.Count + ")!"); + } + + /* + 服务端设置客户端的spacedata, spacedata请参考API + */ + public void Client_setSpaceData(UInt32 spaceID, string key, string value) + { + Dbg.DEBUG_MSG("KBEngine::Client_setSpaceData: spaceID(" + spaceID + "), key(" + key + "), value(" + value + ")!"); + _spacedatas[key] = value; + + if(key == "_mapping") + addSpaceGeometryMapping(spaceID, value); + + Event.fireOut(EventOutTypes.onSetSpaceData, spaceID, key, value); + } + + /* + 服务端删除客户端的spacedata, spacedata请参考API + */ + public void Client_delSpaceData(UInt32 spaceID, string key) + { + Dbg.DEBUG_MSG("KBEngine::Client_delSpaceData: spaceID(" + spaceID + "), key(" + key + ")"); + _spacedatas.Remove(key); + Event.fireOut(EventOutTypes.onDelSpaceData, spaceID, key); + } + + public string getSpaceData(string key) + { + string val = ""; + + if(!_spacedatas.TryGetValue(key, out val)) + { + return ""; + } + + return val; + } + + /* + 服务端通知强制销毁一个实体 + */ + public void Client_onEntityDestroyed(Int32 eid) + { + Dbg.DEBUG_MSG("KBEngine::Client_onEntityDestroyed: entity(" + eid + ")"); + + Entity entity = null; + + if(!entities.TryGetValue(eid, out entity)) + { + Dbg.ERROR_MSG("KBEngine::Client_onEntityDestroyed: entity(" + eid + ") not found!"); + return; + } + + if(entity.inWorld) + { + if(entity_id == eid) + clearSpace(false); + + entity.leaveWorld(); + } + + if(_controlledEntities.Remove(entity)) + Event.fireOut(EventOutTypes.onLoseControlledEntity, entity); + + entities.Remove(eid); + entity.onDestroy(); + } + + /* + 服务端更新玩家的基础位置, 客户端以这个基础位置加上便宜值计算出玩家周围实体的坐标 + */ + public void Client_onUpdateBasePos(float x, float y, float z) + { + _entityServerPos.x = x; + _entityServerPos.y = y; + _entityServerPos.z = z; + + var entity = player(); + if (entity != null && entity.isControlled) + { + entity.position.Set(_entityServerPos.x, _entityServerPos.y, _entityServerPos.z); + Event.fireOut(EventOutTypes.updatePosition, entity); + entity.onUpdateVolatileData(); + } + } + + public void Client_onUpdateBasePosXZ(float x, float z) + { + _entityServerPos.x = x; + _entityServerPos.z = z; + + var entity = player(); + if (entity != null && entity.isControlled) + { + entity.position.x = _entityServerPos.x; + entity.position.z = _entityServerPos.z; + Event.fireOut(EventOutTypes.updatePosition, entity); + entity.onUpdateVolatileData(); + } + } + + public void Client_onUpdateBaseDir(MemoryStream stream) + { + float yaw, pitch, roll; + yaw = stream.readFloat() * 360 / ((float)System.Math.PI * 2); + pitch = stream.readFloat() * 360 / ((float)System.Math.PI * 2); + roll = stream.readFloat() * 360 / ((float)System.Math.PI * 2); + + var entity = player(); + if (entity != null && entity.isControlled) + { + entity.direction.Set(roll, pitch, yaw); + Event.fireOut(EventOutTypes.set_direction, entity); + entity.onUpdateVolatileData(); + } + } + + public void Client_onUpdateData(MemoryStream stream) + { + Int32 eid = getViewEntityIDFromStream(stream); + Entity entity = null; + + if(!entities.TryGetValue(eid, out entity)) + { + Dbg.ERROR_MSG("KBEngine::Client_onUpdateData: entity(" + eid + ") not found!"); + return; + } + } + + /* + 服务端强制设置了玩家的坐标 + 例如:在服务端使用avatar.position=(0,0,0), 或者玩家位置与速度异常时会强制拉回到一个位置 + */ + public void Client_onSetEntityPosAndDir(MemoryStream stream) + { + Int32 eid = stream.readInt32(); + Entity entity = null; + + if(!entities.TryGetValue(eid, out entity)) + { + Dbg.ERROR_MSG("KBEngine::Client_onSetEntityPosAndDir: entity(" + eid + ") not found!"); + return; + } + + Vector3 old_position = new Vector3(entity.position.x, entity.position.y, entity.position.z); + Vector3 old_direction = new Vector3(entity.direction.x, entity.direction.y, entity.direction.z); + + entity.position.x = stream.readFloat(); + entity.position.y = stream.readFloat(); + entity.position.z = stream.readFloat(); + + entity.direction.x = stream.readFloat(); + entity.direction.y = stream.readFloat(); + entity.direction.z = stream.readFloat(); + + entity._entityLastLocalPos = entity.position; + entity._entityLastLocalDir = entity.direction; + + entity.onDirectionChanged(old_direction); + entity.onPositionChanged(old_position); + } + + public void Client_onUpdateData_ypr(MemoryStream stream) + { + Int32 eid = getViewEntityIDFromStream(stream); + + float y = stream.readFloat(); + float p = stream.readFloat(); + float r = stream.readFloat(); + + _updateVolatileData(eid, KBEMath.KBE_FLT_MAX, KBEMath.KBE_FLT_MAX, KBEMath.KBE_FLT_MAX, y, p, r, -1, false); + } + + public void Client_onUpdateData_yp(MemoryStream stream) + { + Int32 eid = getViewEntityIDFromStream(stream); + + float y = stream.readFloat(); + float p = stream.readFloat(); + + _updateVolatileData(eid, KBEMath.KBE_FLT_MAX, KBEMath.KBE_FLT_MAX, KBEMath.KBE_FLT_MAX, y, p, KBEMath.KBE_FLT_MAX, -1, false); + } + + public void Client_onUpdateData_yr(MemoryStream stream) + { + Int32 eid = getViewEntityIDFromStream(stream); + + float y = stream.readFloat(); + float r = stream.readFloat(); + + _updateVolatileData(eid, KBEMath.KBE_FLT_MAX, KBEMath.KBE_FLT_MAX, KBEMath.KBE_FLT_MAX, y, KBEMath.KBE_FLT_MAX, r, -1, false); + } + + public void Client_onUpdateData_pr(MemoryStream stream) + { + Int32 eid = getViewEntityIDFromStream(stream); + + float p = stream.readFloat(); + float r = stream.readFloat(); + + _updateVolatileData(eid, KBEMath.KBE_FLT_MAX, KBEMath.KBE_FLT_MAX, KBEMath.KBE_FLT_MAX, KBEMath.KBE_FLT_MAX, p, r, -1, false); + } + + public void Client_onUpdateData_y(MemoryStream stream) + { + Int32 eid = getViewEntityIDFromStream(stream); + + float y = stream.readFloat(); + + _updateVolatileData(eid, KBEMath.KBE_FLT_MAX, KBEMath.KBE_FLT_MAX, KBEMath.KBE_FLT_MAX, y, KBEMath.KBE_FLT_MAX, KBEMath.KBE_FLT_MAX, -1, false); + } + + public void Client_onUpdateData_p(MemoryStream stream) + { + Int32 eid = getViewEntityIDFromStream(stream); + + float p = stream.readFloat(); + + _updateVolatileData(eid, KBEMath.KBE_FLT_MAX, KBEMath.KBE_FLT_MAX, KBEMath.KBE_FLT_MAX, KBEMath.KBE_FLT_MAX, p, KBEMath.KBE_FLT_MAX, -1, false); + } + + public void Client_onUpdateData_r(MemoryStream stream) + { + Int32 eid = getViewEntityIDFromStream(stream); + + float r = stream.readFloat(); + + _updateVolatileData(eid, KBEMath.KBE_FLT_MAX, KBEMath.KBE_FLT_MAX, KBEMath.KBE_FLT_MAX, KBEMath.KBE_FLT_MAX, KBEMath.KBE_FLT_MAX, r, -1, false); + } + + public void Client_onUpdateData_xz(MemoryStream stream) + { + Int32 eid = getViewEntityIDFromStream(stream); + + float x = stream.readFloat(); + float z = stream.readFloat(); + + _updateVolatileData(eid, x, KBEMath.KBE_FLT_MAX, z, KBEMath.KBE_FLT_MAX, KBEMath.KBE_FLT_MAX, KBEMath.KBE_FLT_MAX, 1, false); + } + + public void Client_onUpdateData_xz_ypr(MemoryStream stream) + { + Int32 eid = getViewEntityIDFromStream(stream); + + float x = stream.readFloat(); + float z = stream.readFloat(); + + float y = stream.readFloat(); + float p = stream.readFloat(); + float r = stream.readFloat(); + + _updateVolatileData(eid, x, KBEMath.KBE_FLT_MAX, z, y, p, r, 1, false); + } + + public void Client_onUpdateData_xz_yp(MemoryStream stream) + { + Int32 eid = getViewEntityIDFromStream(stream); + + float x = stream.readFloat(); + float z = stream.readFloat(); + + float y = stream.readFloat(); + float p = stream.readFloat(); + + _updateVolatileData(eid, x, KBEMath.KBE_FLT_MAX, z, y, p, KBEMath.KBE_FLT_MAX, 1, false); + } + + public void Client_onUpdateData_xz_yr(MemoryStream stream) + { + Int32 eid = getViewEntityIDFromStream(stream); + + float x = stream.readFloat(); + float z = stream.readFloat(); + + float y = stream.readFloat(); + float r = stream.readFloat(); + + _updateVolatileData(eid, x, KBEMath.KBE_FLT_MAX, z, y, KBEMath.KBE_FLT_MAX, r, 1, false); + } + + public void Client_onUpdateData_xz_pr(MemoryStream stream) + { + Int32 eid = getViewEntityIDFromStream(stream); + + float x = stream.readFloat(); + float z = stream.readFloat(); + + float p = stream.readFloat(); + float r = stream.readFloat(); + + _updateVolatileData(eid, x, KBEMath.KBE_FLT_MAX, z, KBEMath.KBE_FLT_MAX, p, r, 1, false); + } + + public void Client_onUpdateData_xz_y(MemoryStream stream) + { + Int32 eid = getViewEntityIDFromStream(stream); + + float x = stream.readFloat(); + float z = stream.readFloat(); + + float yaw = stream.readFloat(); + + _updateVolatileData(eid, x, KBEMath.KBE_FLT_MAX, z, yaw, KBEMath.KBE_FLT_MAX, KBEMath.KBE_FLT_MAX, 1, false); + } + + public void Client_onUpdateData_xz_p(MemoryStream stream) + { + Int32 eid = getViewEntityIDFromStream(stream); + + float x = stream.readFloat(); + float z = stream.readFloat(); + + float p = stream.readFloat(); + + _updateVolatileData(eid, x, KBEMath.KBE_FLT_MAX, z, KBEMath.KBE_FLT_MAX, p, KBEMath.KBE_FLT_MAX, 1, false); + } + + public void Client_onUpdateData_xz_r(MemoryStream stream) + { + Int32 eid = getViewEntityIDFromStream(stream); + + float x = stream.readFloat(); + float z = stream.readFloat(); + + float r = stream.readFloat(); + + _updateVolatileData(eid, x, KBEMath.KBE_FLT_MAX, z, KBEMath.KBE_FLT_MAX, KBEMath.KBE_FLT_MAX, r, 1, false); + } + + public void Client_onUpdateData_xyz(MemoryStream stream) + { + Int32 eid = getViewEntityIDFromStream(stream); + + float x = stream.readFloat(); + float y = stream.readFloat(); + float z = stream.readFloat(); + + _updateVolatileData(eid, x, y, z, KBEMath.KBE_FLT_MAX, KBEMath.KBE_FLT_MAX, KBEMath.KBE_FLT_MAX, 0, false); + } + + public void Client_onUpdateData_xyz_ypr(MemoryStream stream) + { + Int32 eid = getViewEntityIDFromStream(stream); + + float x = stream.readFloat(); + float y = stream.readFloat(); + float z = stream.readFloat(); + + float yaw = stream.readFloat(); + float p = stream.readFloat(); + float r = stream.readFloat(); + + _updateVolatileData(eid, x, y, z, yaw, p, r, 0, false); + } + + public void Client_onUpdateData_xyz_yp(MemoryStream stream) + { + Int32 eid = getViewEntityIDFromStream(stream); + + float x = stream.readFloat(); + float y = stream.readFloat(); + float z = stream.readFloat(); + + float yaw = stream.readFloat(); + float p = stream.readFloat(); + + _updateVolatileData(eid, x, y, z, yaw, p, KBEMath.KBE_FLT_MAX, 0, false); + } + + public void Client_onUpdateData_xyz_yr(MemoryStream stream) + { + Int32 eid = getViewEntityIDFromStream(stream); + + float x = stream.readFloat(); + float y = stream.readFloat(); + float z = stream.readFloat(); + + float yaw = stream.readFloat(); + float r = stream.readFloat(); + + _updateVolatileData(eid, x, y, z, yaw, KBEMath.KBE_FLT_MAX, r, 0, false); + } + + public void Client_onUpdateData_xyz_pr(MemoryStream stream) + { + Int32 eid = getViewEntityIDFromStream(stream); + + float x = stream.readFloat(); + float y = stream.readFloat(); + float z = stream.readFloat(); + + float p = stream.readFloat(); + float r = stream.readFloat(); + + _updateVolatileData(eid, x, y, z, KBEMath.KBE_FLT_MAX, p, r, 0, false); + } + + public void Client_onUpdateData_xyz_y(MemoryStream stream) + { + Int32 eid = getViewEntityIDFromStream(stream); + + float x = stream.readFloat(); + float y = stream.readFloat(); + float z = stream.readFloat(); + + float yaw = stream.readFloat(); + + _updateVolatileData(eid, x, y, z, yaw, KBEMath.KBE_FLT_MAX, KBEMath.KBE_FLT_MAX, 0, false); + } + + public void Client_onUpdateData_xyz_p(MemoryStream stream) + { + Int32 eid = getViewEntityIDFromStream(stream); + + float x = stream.readFloat(); + float y = stream.readFloat(); + float z = stream.readFloat(); + + float p = stream.readFloat(); + + _updateVolatileData(eid, x, y, z, KBEMath.KBE_FLT_MAX, p, KBEMath.KBE_FLT_MAX, 0, false); + } + + public void Client_onUpdateData_xyz_r(MemoryStream stream) + { + Int32 eid = getViewEntityIDFromStream(stream); + + float x = stream.readFloat(); + float y = stream.readFloat(); + float z = stream.readFloat(); + + float r = stream.readFloat(); + + _updateVolatileData(eid, x, y, z, KBEMath.KBE_FLT_MAX, KBEMath.KBE_FLT_MAX, r, 0, false); + } + + public void Client_onUpdateData_ypr_optimized(MemoryStream stream) + { + Int32 eid = getViewEntityIDFromStream(stream); + + SByte y = stream.readInt8(); + SByte p = stream.readInt8(); + SByte r = stream.readInt8(); + + _updateVolatileData(eid, KBEMath.KBE_FLT_MAX, KBEMath.KBE_FLT_MAX, KBEMath.KBE_FLT_MAX, y, p, r, -1, true); + } + + public void Client_onUpdateData_yp_optimized(MemoryStream stream) + { + Int32 eid = getViewEntityIDFromStream(stream); + + SByte y = stream.readInt8(); + SByte p = stream.readInt8(); + + _updateVolatileData(eid, KBEMath.KBE_FLT_MAX, KBEMath.KBE_FLT_MAX, KBEMath.KBE_FLT_MAX, y, p, KBEMath.KBE_FLT_MAX, -1, true); + } + + public void Client_onUpdateData_yr_optimized(MemoryStream stream) + { + Int32 eid = getViewEntityIDFromStream(stream); + + SByte y = stream.readInt8(); + SByte r = stream.readInt8(); + + _updateVolatileData(eid, KBEMath.KBE_FLT_MAX, KBEMath.KBE_FLT_MAX, KBEMath.KBE_FLT_MAX, y, KBEMath.KBE_FLT_MAX, r, -1, true); + } + + public void Client_onUpdateData_pr_optimized(MemoryStream stream) + { + Int32 eid = getViewEntityIDFromStream(stream); + + SByte p = stream.readInt8(); + SByte r = stream.readInt8(); + + _updateVolatileData(eid, KBEMath.KBE_FLT_MAX, KBEMath.KBE_FLT_MAX, KBEMath.KBE_FLT_MAX, KBEMath.KBE_FLT_MAX, p, r, -1, true); + } + + public void Client_onUpdateData_y_optimized(MemoryStream stream) + { + Int32 eid = getViewEntityIDFromStream(stream); + + SByte y = stream.readInt8(); + + _updateVolatileData(eid, KBEMath.KBE_FLT_MAX, KBEMath.KBE_FLT_MAX, KBEMath.KBE_FLT_MAX, y, KBEMath.KBE_FLT_MAX, KBEMath.KBE_FLT_MAX, -1, true); + } + + public void Client_onUpdateData_p_optimized(MemoryStream stream) + { + Int32 eid = getViewEntityIDFromStream(stream); + + SByte p = stream.readInt8(); + + _updateVolatileData(eid, KBEMath.KBE_FLT_MAX, KBEMath.KBE_FLT_MAX, KBEMath.KBE_FLT_MAX, KBEMath.KBE_FLT_MAX, p, KBEMath.KBE_FLT_MAX, -1, true); + } + + public void Client_onUpdateData_r_optimized(MemoryStream stream) + { + Int32 eid = getViewEntityIDFromStream(stream); + + SByte r = stream.readInt8(); + + _updateVolatileData(eid, KBEMath.KBE_FLT_MAX, KBEMath.KBE_FLT_MAX, KBEMath.KBE_FLT_MAX, KBEMath.KBE_FLT_MAX, KBEMath.KBE_FLT_MAX, r, -1, true); + } + + public void Client_onUpdateData_xz_optimized(MemoryStream stream) + { + Int32 eid = getViewEntityIDFromStream(stream); + + Vector2 xz = stream.readPackXZ(); + + _updateVolatileData(eid, xz[0], KBEMath.KBE_FLT_MAX, xz[1], KBEMath.KBE_FLT_MAX, KBEMath.KBE_FLT_MAX, KBEMath.KBE_FLT_MAX, 1, true); + } + + public void Client_onUpdateData_xz_ypr_optimized(MemoryStream stream) + { + Int32 eid = getViewEntityIDFromStream(stream); + + Vector2 xz = stream.readPackXZ(); + + SByte y = stream.readInt8(); + SByte p = stream.readInt8(); + SByte r = stream.readInt8(); + + _updateVolatileData(eid, xz[0], KBEMath.KBE_FLT_MAX, xz[1], y, p, r, 1, true); + } + + public void Client_onUpdateData_xz_yp_optimized(MemoryStream stream) + { + Int32 eid = getViewEntityIDFromStream(stream); + + Vector2 xz = stream.readPackXZ(); + + SByte y = stream.readInt8(); + SByte p = stream.readInt8(); + + _updateVolatileData(eid, xz[0], KBEMath.KBE_FLT_MAX, xz[1], y, p, KBEMath.KBE_FLT_MAX, 1, true); + } + + public void Client_onUpdateData_xz_yr_optimized(MemoryStream stream) + { + Int32 eid = getViewEntityIDFromStream(stream); + + Vector2 xz = stream.readPackXZ(); + + SByte y = stream.readInt8(); + SByte r = stream.readInt8(); + + _updateVolatileData(eid, xz[0], KBEMath.KBE_FLT_MAX, xz[1], y, KBEMath.KBE_FLT_MAX, r, 1, true); + } + + public void Client_onUpdateData_xz_pr_optimized(MemoryStream stream) + { + Int32 eid = getViewEntityIDFromStream(stream); + + Vector2 xz = stream.readPackXZ(); + + SByte p = stream.readInt8(); + SByte r = stream.readInt8(); + + _updateVolatileData(eid, xz[0], KBEMath.KBE_FLT_MAX, xz[1], KBEMath.KBE_FLT_MAX, p, r, 1, true); + } + + public void Client_onUpdateData_xz_y_optimized(MemoryStream stream) + { + Int32 eid = getViewEntityIDFromStream(stream); + Vector2 xz = stream.readPackXZ(); + SByte yaw = stream.readInt8(); + _updateVolatileData(eid, xz[0], KBEMath.KBE_FLT_MAX, xz[1], yaw, KBEMath.KBE_FLT_MAX, KBEMath.KBE_FLT_MAX, 1, true); + } + + public void Client_onUpdateData_xz_p_optimized(MemoryStream stream) + { + Int32 eid = getViewEntityIDFromStream(stream); + + Vector2 xz = stream.readPackXZ(); + + SByte p = stream.readInt8(); + + _updateVolatileData(eid, xz[0], KBEMath.KBE_FLT_MAX, xz[1], KBEMath.KBE_FLT_MAX, p, KBEMath.KBE_FLT_MAX, 1, true); + } + + public void Client_onUpdateData_xz_r_optimized(MemoryStream stream) + { + Int32 eid = getViewEntityIDFromStream(stream); + + Vector2 xz = stream.readPackXZ(); + + SByte r = stream.readInt8(); + + _updateVolatileData(eid, xz[0], KBEMath.KBE_FLT_MAX, xz[1], KBEMath.KBE_FLT_MAX, KBEMath.KBE_FLT_MAX, r, 1, true); + } + + public void Client_onUpdateData_xyz_optimized(MemoryStream stream) + { + Int32 eid = getViewEntityIDFromStream(stream); + + Vector2 xz = stream.readPackXZ(); + float y = stream.readPackY(); + + _updateVolatileData(eid, xz[0], y, xz[1], KBEMath.KBE_FLT_MAX, KBEMath.KBE_FLT_MAX, KBEMath.KBE_FLT_MAX, 0, true); + } + + public void Client_onUpdateData_xyz_ypr_optimized(MemoryStream stream) + { + Int32 eid = getViewEntityIDFromStream(stream); + + Vector2 xz = stream.readPackXZ(); + float y = stream.readPackY(); + + SByte yaw = stream.readInt8(); + SByte p = stream.readInt8(); + SByte r = stream.readInt8(); + + _updateVolatileData(eid, xz[0], y, xz[1], yaw, p, r, 0, true); + } + + public void Client_onUpdateData_xyz_yp_optimized(MemoryStream stream) + { + Int32 eid = getViewEntityIDFromStream(stream); + + Vector2 xz = stream.readPackXZ(); + float y = stream.readPackY(); + + SByte yaw = stream.readInt8(); + SByte p = stream.readInt8(); + + _updateVolatileData(eid, xz[0], y, xz[1], yaw, p, KBEMath.KBE_FLT_MAX, 0, true); + } + + public void Client_onUpdateData_xyz_yr_optimized(MemoryStream stream) + { + Int32 eid = getViewEntityIDFromStream(stream); + + Vector2 xz = stream.readPackXZ(); + float y = stream.readPackY(); + + SByte yaw = stream.readInt8(); + SByte r = stream.readInt8(); + + _updateVolatileData(eid, xz[0], y, xz[1], yaw, KBEMath.KBE_FLT_MAX, r, 0, true); + } + + public void Client_onUpdateData_xyz_pr_optimized(MemoryStream stream) + { + Int32 eid = getViewEntityIDFromStream(stream); + + Vector2 xz = stream.readPackXZ(); + float y = stream.readPackY(); + + SByte p = stream.readInt8(); + SByte r = stream.readInt8(); + + _updateVolatileData(eid, xz[0], y, xz[1], KBEMath.KBE_FLT_MAX, p, r, 0, true); + } + + public void Client_onUpdateData_xyz_y_optimized(MemoryStream stream) + { + Int32 eid = getViewEntityIDFromStream(stream); + + Vector2 xz = stream.readPackXZ(); + float y = stream.readPackY(); + + SByte yaw = stream.readInt8(); + _updateVolatileData(eid, xz[0], y, xz[1], yaw, KBEMath.KBE_FLT_MAX, KBEMath.KBE_FLT_MAX, 0, true); + } + + public void Client_onUpdateData_xyz_p_optimized(MemoryStream stream) + { + Int32 eid = getViewEntityIDFromStream(stream); + + Vector2 xz = stream.readPackXZ(); + float y = stream.readPackY(); + + SByte p = stream.readInt8(); + + _updateVolatileData(eid, xz[0], y, xz[1], KBEMath.KBE_FLT_MAX, p, KBEMath.KBE_FLT_MAX, 0, true); + } + + public void Client_onUpdateData_xyz_r_optimized(MemoryStream stream) + { + Int32 eid = getViewEntityIDFromStream(stream); + + Vector2 xz = stream.readPackXZ(); + float y = stream.readPackY(); + + SByte r = stream.readInt8(); + + _updateVolatileData(eid, xz[0], y, xz[1], KBEMath.KBE_FLT_MAX, KBEMath.KBE_FLT_MAX, r, 0, true); + } + + private void _updateVolatileData(Int32 entityID, float x, float y, float z, float yaw, float pitch, float roll, sbyte isOnGround, bool isOptimized) + { + Entity entity = null; + + if(!entities.TryGetValue(entityID, out entity)) + { + // 如果为0且客户端上一步是重登陆或者重连操作并且服务端entity在断线期间一直处于在线状态 + // 则可以忽略这个错误, 因为cellapp可能一直在向baseapp发送同步消息, 当客户端重连上时未等 + // 服务端初始化步骤开始则收到同步信息, 此时这里就会出错。 + Dbg.ERROR_MSG("KBEngine::_updateVolatileData: entity(" + entityID + ") not found!"); + return; + } + + // 小于0不设置 + if(isOnGround >= 0) + { + entity.isOnGround = (isOnGround > 0); + } + + bool changeDirection = false; + + if(roll != KBEMath.KBE_FLT_MAX) + { + changeDirection = true; + entity.direction.x = isOptimized ? KBEMath.int82angle((SByte)roll, false) * 360 / ((float)System.Math.PI * 2) : roll; + } + + if(pitch != KBEMath.KBE_FLT_MAX) + { + changeDirection = true; + entity.direction.y = isOptimized ? KBEMath.int82angle((SByte)pitch, false) * 360 / ((float)System.Math.PI * 2) : pitch; + } + + if(yaw != KBEMath.KBE_FLT_MAX) + { + changeDirection = true; + entity.direction.z = isOptimized ? KBEMath.int82angle((SByte)yaw, false) * 360 / ((float)System.Math.PI * 2) : yaw; + } + + bool done = false; + if(changeDirection == true) + { + Event.fireOut(EventOutTypes.set_direction, entity); + done = true; + } + + bool positionChanged = x != KBEMath.KBE_FLT_MAX || y != KBEMath.KBE_FLT_MAX || z != KBEMath.KBE_FLT_MAX; + if (x == KBEMath.KBE_FLT_MAX) x = isOptimized ? 0.0f : entity.position.x; + if (y == KBEMath.KBE_FLT_MAX) y = isOptimized ? 0.0f : entity.position.y; + if (z == KBEMath.KBE_FLT_MAX) z = isOptimized ? 0.0f : entity.position.z; + + if(positionChanged) + { + Vector3 pos = isOptimized ? new Vector3(x + _entityServerPos.x, y + _entityServerPos.y, z + _entityServerPos.z) : new Vector3(x, y, z); + + entity.position = pos; + done = true; + Event.fireOut(EventOutTypes.updatePosition, entity); + } + + if(done) + entity.onUpdateVolatileData(); + } + + /* + 服务端通知流数据下载开始 + 请参考API手册关于onStreamDataStarted + */ + public void Client_onStreamDataStarted(Int16 id, UInt32 datasize, string descr) + { + Event.fireOut(EventOutTypes.onStreamDataStarted, id, datasize, descr); + } + + public void Client_onStreamDataRecv(MemoryStream stream) + { + Int16 resID = stream.readInt16(); + byte[] datas = stream.readBlob(); + Event.fireOut(EventOutTypes.onStreamDataRecv, resID, datas); + } + + public void Client_onStreamDataCompleted(Int16 id) + { + Event.fireOut(EventOutTypes.onStreamDataCompleted, id); + } + } + + + public class KBEngineAppThread : KBEngineApp + { + /* + KBEngine处理线程 + */ + public class KBEThread + { + + KBEngineApp app_; + public bool over = false; + + public KBEThread(KBEngineApp app) + { + this.app_ = app; + } + + public void run() + { + Dbg.INFO_MSG("KBEThread::run()"); + over = false; + + try + { + this.app_.process(); + } + catch (Exception e) + { + Dbg.ERROR_MSG(e.ToString()); + } + + over = true; + Dbg.INFO_MSG("KBEThread::end()"); + } + } + + private Thread _t = null; + public KBEThread kbethread = null; + + // 主循环频率 + public static int threadUpdateHZ = 10; + + // 主循环周期ms 优化去掉循环中做除法 + private static float threadUpdatePeriod = 1000f / threadUpdateHZ; + + // 插件是否退出 + private bool _isbreak = false; + + private System.DateTime _lasttime = System.DateTime.Now; + + public KBEngineAppThread(KBEngineArgs args) : + base(args) + { + } + + public override bool initialize(KBEngineArgs args) + { + base.initialize(args); + + KBEngineAppThread.threadUpdateHZ = args.threadUpdateHZ; + threadUpdatePeriod = 1000f / threadUpdateHZ; + + kbethread = new KBEThread(this); + _t = new Thread(new ThreadStart(kbethread.run)); + _t.Start(); + + return true; + } + + public override void reset() + { + _isbreak = false; + _lasttime = System.DateTime.Now; + + base.reset(); + } + + /* + 插件退出处理 + */ + public void breakProcess() + { + _isbreak = true; + } + + public bool isbreak() + { + return _isbreak; + } + + public override void process() + { + while(!isbreak()) + { + base.process(); + _thread_wait(); + } + + Dbg.WARNING_MSG("KBEngineAppThread::process(): break!"); + } + + /* + 防止占满CPU, 需要让线程等待一会 + */ + void _thread_wait() + { + TimeSpan span = DateTime.Now - _lasttime; + + int diff = (int)(threadUpdatePeriod - span.TotalMilliseconds); + + if(diff < 0) + diff = 0; + + System.Threading.Thread.Sleep(diff); + _lasttime = DateTime.Now; + } + + public override void destroy() + { + Dbg.WARNING_MSG("KBEngineAppThread::destroy()"); + breakProcess(); + + int i = 0; + while(!kbethread.over && i < 50) + { + Thread.Sleep(100); + i += 1; + } + + if(_t != null) + _t.Abort(); + + _t = null; + + base.destroy(); + } + } +} diff --git a/Assets/Plugins/kbengine/kbengine_unity3d_plugins/NetworkInterface.cs b/Assets/Plugins/kbengine/kbengine_unity3d_plugins/NetworkInterface.cs index d588d233..8ea7cb41 100644 --- a/Assets/Plugins/kbengine/kbengine_unity3d_plugins/NetworkInterface.cs +++ b/Assets/Plugins/kbengine/kbengine_unity3d_plugins/NetworkInterface.cs @@ -1,251 +1,251 @@ -namespace KBEngine -{ - using UnityEngine; - using System; - using System.Net.Sockets; - using System.Net; - using System.Collections; - using System.Collections.Generic; - using System.Text; - using System.Text.RegularExpressions; - using System.Threading; - using System.Runtime.Remoting.Messaging; - - using MessageID = System.UInt16; - using MessageLength = System.UInt16; - - /// - /// 网络模块 - /// 处理连接、收发数据 - /// - public class NetworkInterface - { - public delegate void AsyncConnectMethod(ConnectState state); - public const int TCP_PACKET_MAX = 1460; - public delegate void ConnectCallback(string ip, int port, bool success, object userData); - - protected Socket _socket = null; - protected EncryptionFilter _filter = null; - PacketReceiver _packetReceiver = null; - PacketSender _packetSender = null; - - public bool connected = false; - - public class ConnectState - { - // for connect - public string connectIP = ""; - public int connectPort = 0; - public ConnectCallback connectCB = null; - public object userData = null; - public Socket socket = null; - public NetworkInterface networkInterface = null; - public string error = ""; - } - - public NetworkInterface() - { - reset(); - } - - ~NetworkInterface() - { - Dbg.DEBUG_MSG("NetworkInterface::~NetworkInterface(), destructed!!!"); - reset(); - } - - public virtual Socket sock() - { - return _socket; - } - - public void reset() - { - _packetReceiver = null; - _packetSender = null; - _filter = null; - connected = false; - - if(_socket != null) - { - if(_socket.RemoteEndPoint != null) - Dbg.DEBUG_MSG(string.Format("NetworkInterface::reset(), close socket from '{0}'", _socket.RemoteEndPoint.ToString())); - - _socket.Close(0); - _socket = null; - } - } - - - public void close() - { - if(_socket != null) - { - _socket.Close(0); - _socket = null; - Event.fireAll(EventOutTypes.onDisconnected); - } - - _socket = null; - connected = false; - } - - public virtual PacketReceiver packetReceiver() - { - return _packetReceiver; - } - - public virtual bool valid() - { - return ((_socket != null) && (_socket.Connected == true)); - } - - public void _onConnectionState(ConnectState state) - { - KBEngine.Event.deregisterIn(this); - - bool success = (state.error == "" && valid()); - if (success) - { - Dbg.DEBUG_MSG(string.Format("NetworkInterface::_onConnectionState(), connect to {0} is success!", state.socket.RemoteEndPoint.ToString())); - _packetReceiver = new PacketReceiver(this); - _packetReceiver.startRecv(); - connected = true; - } - else - { - reset(); - Dbg.ERROR_MSG(string.Format("NetworkInterface::_onConnectionState(), connect error! ip: {0}:{1}, err: {2}", state.connectIP, state.connectPort, state.error)); - } - - Event.fireAll(EventOutTypes.onConnectionState, success); - - if (state.connectCB != null) - state.connectCB(state.connectIP, state.connectPort, success, state.userData); - } - - private static void connectCB(IAsyncResult ar) - { - ConnectState state = null; - - try - { - // Retrieve the socket from the state object. - state = (ConnectState) ar.AsyncState; - - // Complete the connection. - state.socket.EndConnect(ar); - - Event.fireIn("_onConnectionState", new object[] { state }); - } - catch (Exception e) - { - state.error = e.ToString(); - Event.fireIn("_onConnectionState", new object[] { state }); - } - } - - /// - /// 在非主线程执行:连接服务器 - /// - private void _asyncConnect(ConnectState state) - { - Dbg.DEBUG_MSG(string.Format("NetWorkInterface::_asyncConnect(), will connect to '{0}:{1}' ...", state.connectIP, state.connectPort)); - try - { - state.socket.Connect(state.connectIP, state.connectPort); - } - catch (Exception e) - { - Dbg.ERROR_MSG(string.Format("NetWorkInterface::_asyncConnect(), connect to '{0}:{1}' fault! error = '{2}'", state.connectIP, state.connectPort, e)); - state.error = e.ToString(); - } - } - - /// - /// 在非主线程执行:连接服务器结果回调 - /// - private void _asyncConnectCB(IAsyncResult ar) - { - ConnectState state = (ConnectState)ar.AsyncState; - AsyncResult result = (AsyncResult)ar; - AsyncConnectMethod caller = (AsyncConnectMethod)result.AsyncDelegate; - - Dbg.DEBUG_MSG(string.Format("NetWorkInterface::_asyncConnectCB(), connect to '{0}:{1}' finish. error = '{2}'", state.connectIP, state.connectPort, state.error)); - - // Call EndInvoke to retrieve the results. - caller.EndInvoke(ar); - Event.fireIn("_onConnectionState", new object[] { state }); - } - - public void connectTo(string ip, int port, ConnectCallback callback, object userData) - { - if (valid()) - throw new InvalidOperationException("Have already connected!"); - - if (!(new Regex(@"((?:(?:25[0-5]|2[0-4]\d|((1\d{2})|([1-9]?\d)))\.){3}(?:25[0-5]|2[0-4]\d|((1\d{2})|([1-9]?\d))))")).IsMatch(ip)) - { - IPHostEntry ipHost = Dns.GetHostEntry(ip); - ip = ipHost.AddressList[0].ToString(); - } - - // Security.PrefetchSocketPolicy(ip, 843); - _socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); - _socket.SetSocketOption(System.Net.Sockets.SocketOptionLevel.Socket, SocketOptionName.ReceiveBuffer, KBEngineApp.app.getInitArgs().getRecvBufferSize() * 2); - _socket.SetSocketOption(System.Net.Sockets.SocketOptionLevel.Socket, SocketOptionName.SendBuffer, KBEngineApp.app.getInitArgs().getSendBufferSize() * 2); - _socket.NoDelay = true; - //_socket.Blocking = false; - - ConnectState state = new ConnectState(); - state.connectIP = ip; - state.connectPort = port; - state.connectCB = callback; - state.userData = userData; - state.socket = _socket; - state.networkInterface = this; - - Dbg.DEBUG_MSG("connect to " + ip + ":" + port + " ..."); - connected = false; - - // 先注册一个事件回调,该事件在当前线程触发 - Event.registerIn("_onConnectionState", this, "_onConnectionState"); - - var v = new AsyncConnectMethod(this._asyncConnect); - v.BeginInvoke(state, new AsyncCallback(this._asyncConnectCB), state); - } - - public bool send(MemoryStream stream) - { - if (!valid()) - { - throw new ArgumentException("invalid socket!"); - } - - if (_packetSender == null) - _packetSender = new PacketSender(this); - - if (_filter != null) - return _filter.send(_packetSender, stream); - - return _packetSender.send(stream); - } - - public void process() - { - if (!valid()) - return; - - if (_packetReceiver != null) - _packetReceiver.process(); - } - public EncryptionFilter fileter() - { - return _filter; - } - - public void setFilter(EncryptionFilter filter) - { - _filter = filter; - } - } -} +namespace KBEngine +{ + using UnityEngine; + using System; + using System.Net.Sockets; + using System.Net; + using System.Collections; + using System.Collections.Generic; + using System.Text; + using System.Text.RegularExpressions; + using System.Threading; + + using MessageID = System.UInt16; + using MessageLength = System.UInt16; + + /// + /// 网络模块 + /// 处理连接、收发数据 + /// + public class NetworkInterface + { + public delegate void AsyncConnectMethod(ConnectState state); + public const int TCP_PACKET_MAX = 1460; + public delegate void ConnectCallback(string ip, int port, bool success, object userData); + + protected Socket _socket = null; + protected EncryptionFilter _filter = null; + PacketReceiver _packetReceiver = null; + PacketSender _packetSender = null; + + public bool connected = false; + + public class ConnectState + { + // for connect + public string connectIP = ""; + public int connectPort = 0; + public ConnectCallback connectCB = null; + public AsyncConnectMethod caller = null; + public object userData = null; + public Socket socket = null; + public NetworkInterface networkInterface = null; + public string error = ""; + } + + public NetworkInterface() + { + reset(); + } + + ~NetworkInterface() + { + Dbg.DEBUG_MSG("NetworkInterface::~NetworkInterface(), destructed!!!"); + reset(); + } + + public virtual Socket sock() + { + return _socket; + } + + public void reset() + { + _packetReceiver = null; + _packetSender = null; + _filter = null; + connected = false; + + if(_socket != null) + { + if(_socket.RemoteEndPoint != null) + Dbg.DEBUG_MSG(string.Format("NetworkInterface::reset(), close socket from '{0}'", _socket.RemoteEndPoint.ToString())); + + _socket.Close(0); + _socket = null; + } + } + + + public void close() + { + if(_socket != null) + { + _socket.Close(0); + _socket = null; + Event.fireAll(EventOutTypes.onDisconnected); + } + + _socket = null; + connected = false; + } + + public virtual PacketReceiver packetReceiver() + { + return _packetReceiver; + } + + public virtual bool valid() + { + return ((_socket != null) && (_socket.Connected == true)); + } + + public void _onConnectionState(ConnectState state) + { + KBEngine.Event.deregisterIn(this); + + bool success = (state.error == "" && valid()); + if (success) + { + Dbg.DEBUG_MSG(string.Format("NetworkInterface::_onConnectionState(), connect to {0} is success!", state.socket.RemoteEndPoint.ToString())); + _packetReceiver = new PacketReceiver(this); + _packetReceiver.startRecv(); + connected = true; + } + else + { + reset(); + Dbg.ERROR_MSG(string.Format("NetworkInterface::_onConnectionState(), connect error! ip: {0}:{1}, err: {2}", state.connectIP, state.connectPort, state.error)); + } + + Event.fireAll(EventOutTypes.onConnectionState, success); + + if (state.connectCB != null) + state.connectCB(state.connectIP, state.connectPort, success, state.userData); + } + + private static void connectCB(IAsyncResult ar) + { + ConnectState state = null; + + try + { + // Retrieve the socket from the state object. + state = (ConnectState) ar.AsyncState; + + // Complete the connection. + state.socket.EndConnect(ar); + + Event.fireIn("_onConnectionState", new object[] { state }); + } + catch (Exception e) + { + state.error = e.ToString(); + Event.fireIn("_onConnectionState", new object[] { state }); + } + } + + /// + /// 在非主线程执行:连接服务器 + /// + private void _asyncConnect(ConnectState state) + { + Dbg.DEBUG_MSG(string.Format("NetWorkInterface::_asyncConnect(), will connect to '{0}:{1}' ...", state.connectIP, state.connectPort)); + try + { + state.socket.Connect(state.connectIP, state.connectPort); + } + catch (Exception e) + { + Dbg.ERROR_MSG(string.Format("NetWorkInterface::_asyncConnect(), connect to '{0}:{1}' fault! error = '{2}'", state.connectIP, state.connectPort, e)); + state.error = e.ToString(); + } + } + + /// + /// 在非主线程执行:连接服务器结果回调 + /// + private void _asyncConnectCB(IAsyncResult ar) + { + ConnectState state = (ConnectState)ar.AsyncState; + + Dbg.DEBUG_MSG(string.Format("NetWorkInterface::_asyncConnectCB(), connect to '{0}:{1}' finish. error = '{2}'", state.connectIP, state.connectPort, state.error)); + + // Call EndInvoke to retrieve the results. + state.caller.EndInvoke(ar); + Event.fireIn("_onConnectionState", new object[] { state }); + } + + public void connectTo(string ip, int port, ConnectCallback callback, object userData) + { + if (valid()) + throw new InvalidOperationException("Have already connected!"); + + if (!(new Regex(@"((?:(?:25[0-5]|2[0-4]\d|((1\d{2})|([1-9]?\d)))\.){3}(?:25[0-5]|2[0-4]\d|((1\d{2})|([1-9]?\d))))")).IsMatch(ip)) + { + IPHostEntry ipHost = Dns.GetHostEntry(ip); + ip = ipHost.AddressList[0].ToString(); + } + + // Security.PrefetchSocketPolicy(ip, 843); + _socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); + _socket.SetSocketOption(System.Net.Sockets.SocketOptionLevel.Socket, SocketOptionName.ReceiveBuffer, KBEngineApp.app.getInitArgs().getRecvBufferSize() * 2); + _socket.SetSocketOption(System.Net.Sockets.SocketOptionLevel.Socket, SocketOptionName.SendBuffer, KBEngineApp.app.getInitArgs().getSendBufferSize() * 2); + _socket.NoDelay = true; + //_socket.Blocking = false; + + AsyncConnectMethod asyncConnectMethod = new AsyncConnectMethod(this._asyncConnect); + + ConnectState state = new ConnectState(); + state.connectIP = ip; + state.connectPort = port; + state.connectCB = callback; + state.userData = userData; + state.socket = _socket; + state.networkInterface = this; + state.caller = asyncConnectMethod; + + Dbg.DEBUG_MSG("connect to " + ip + ":" + port + " ..."); + connected = false; + + // 先注册一个事件回调,该事件在当前线程触发 + Event.registerIn("_onConnectionState", this, "_onConnectionState"); + + asyncConnectMethod.BeginInvoke(state, new AsyncCallback(this._asyncConnectCB), state); + } + + public bool send(MemoryStream stream) + { + if (!valid()) + { + throw new ArgumentException("invalid socket!"); + } + + if (_packetSender == null) + _packetSender = new PacketSender(this); + + if (_filter != null) + return _filter.send(_packetSender, stream); + + return _packetSender.send(stream); + } + + public void process() + { + if (!valid()) + return; + + if (_packetReceiver != null) + _packetReceiver.process(); + } + public EncryptionFilter fileter() + { + return _filter; + } + + public void setFilter(EncryptionFilter filter) + { + _filter = filter; + } + } +} diff --git a/Assets/Plugins/kbengine/kbengine_unity3d_plugins/PacketReceiver.cs b/Assets/Plugins/kbengine/kbengine_unity3d_plugins/PacketReceiver.cs index c1d17b50..53810307 100644 --- a/Assets/Plugins/kbengine/kbengine_unity3d_plugins/PacketReceiver.cs +++ b/Assets/Plugins/kbengine/kbengine_unity3d_plugins/PacketReceiver.cs @@ -1,193 +1,198 @@ -namespace KBEngine -{ - using System; - using System.Net.Sockets; - using System.Net; - using System.Collections; - using System.Collections.Generic; - using System.Text; - using System.Text.RegularExpressions; - using System.Threading; - using System.Runtime.Remoting.Messaging; - - using MessageID = System.UInt16; - using MessageLength = System.UInt16; - - /* - 包接收模块(与服务端网络部分的名称对应) - 处理网络数据的接收 - */ - public class PacketReceiver - { - public delegate void AsyncReceiveMethod(); - - private MessageReader messageReader = null; - private NetworkInterface _networkInterface = null; - - private byte[] _buffer; - - // socket向缓冲区写的起始位置 - int _wpos = 0; - - // 主线程读取数据的起始位置 - int _rpos = 0; - - public PacketReceiver(NetworkInterface networkInterface) - { - _init(networkInterface); - } - - ~PacketReceiver() - { - Dbg.DEBUG_MSG("PacketReceiver::~PacketReceiver(), destroyed!"); - } - - void _init(NetworkInterface networkInterface) - { - _networkInterface = networkInterface; - _buffer = new byte[KBEngineApp.app.getInitArgs().RECV_BUFFER_MAX]; - - messageReader = new MessageReader(); - } - - public NetworkInterface networkInterface() - { - return _networkInterface; - } - - public void process() - { - int t_wpos = Interlocked.Add(ref _wpos, 0); - - if (_rpos < t_wpos) - { - if (_networkInterface.fileter() != null) - { - _networkInterface.fileter().recv(messageReader, _buffer, (UInt32)_rpos, (UInt32)(t_wpos - _rpos)); - } - else - { - messageReader.process(_buffer, (UInt32)_rpos, (UInt32)(t_wpos - _rpos)); - } - - Interlocked.Exchange(ref _rpos, t_wpos); - } - else if (t_wpos < _rpos) - { - if (_networkInterface.fileter() != null) - { - _networkInterface.fileter().recv(messageReader, _buffer, (UInt32)_rpos, (UInt32)(_buffer.Length - _rpos)); - _networkInterface.fileter().recv(messageReader, _buffer, (UInt32)0, (UInt32)t_wpos); - } - else - { - messageReader.process(_buffer, (UInt32)_rpos, (UInt32)(_buffer.Length - _rpos)); - messageReader.process(_buffer, (UInt32)0, (UInt32)t_wpos); - } - - Interlocked.Exchange(ref _rpos, t_wpos); - } - else - { - // 没有可读数据 - } - } - - int _free() - { - int t_rpos = Interlocked.Add(ref _rpos, 0); - - if (_wpos == _buffer.Length) - { - if (t_rpos == 0) - { - return 0; - } - - Interlocked.Exchange(ref _wpos, 0); - } - - if (t_rpos <= _wpos) - { - return _buffer.Length - _wpos; - } - - return t_rpos - _wpos - 1; - } - - public void startRecv() - { - - var v = new AsyncReceiveMethod(this._asyncReceive); - v.BeginInvoke(new AsyncCallback(_onRecv), null); - } - - private void _asyncReceive() - { - if (_networkInterface == null || !_networkInterface.valid()) - { - Dbg.WARNING_MSG("PacketReceiver::_asyncReceive(): network interface invalid!"); - return; - } - - var socket = _networkInterface.sock(); - - while (true) - { - // 必须有空间可写,否则我们阻塞在线程中直到有空间为止 - int first = 0; - int space = _free(); - - while (space == 0) - { - if (first > 0) - { - if (first > 1000) - { - Dbg.ERROR_MSG("PacketReceiver::_asyncReceive(): no space!"); - Event.fireIn("_closeNetwork", new object[] { _networkInterface }); - return; - } - - Dbg.WARNING_MSG("PacketReceiver::_asyncReceive(): waiting for space, Please adjust 'RECV_BUFFER_MAX'! retries=" + first); - System.Threading.Thread.Sleep(5); - } - - first += 1; - space = _free(); - } - - int bytesRead = 0; - try - { - bytesRead = socket.Receive(_buffer, _wpos, space, 0); - } - catch (SocketException se) - { - Dbg.ERROR_MSG(string.Format("PacketReceiver::_asyncReceive(): receive error, disconnect from '{0}'! error = '{1}'", socket.RemoteEndPoint, se)); - Event.fireIn("_closeNetwork", new object[] { _networkInterface }); - return; - } - - if (bytesRead > 0) - { - // 更新写位置 - Interlocked.Add(ref _wpos, bytesRead); - } - else - { - Dbg.WARNING_MSG(string.Format("PacketReceiver::_asyncReceive(): receive 0 bytes, disconnect from '{0}'!", socket.RemoteEndPoint)); - Event.fireIn("_closeNetwork", new object[] { _networkInterface }); - return; - } - } - } - - private void _onRecv(IAsyncResult ar) - { - AsyncResult result = (AsyncResult)ar; - AsyncReceiveMethod caller = (AsyncReceiveMethod)result.AsyncDelegate; - caller.EndInvoke(ar); - } - } -} +namespace KBEngine +{ + using System; + using System.Net.Sockets; + using System.Net; + using System.Collections; + using System.Collections.Generic; + using System.Text; + using System.Text.RegularExpressions; + using System.Threading; + + using MessageID = System.UInt16; + using MessageLength = System.UInt16; + + /* + 包接收模块(与服务端网络部分的名称对应) + 处理网络数据的接收 + */ + public class PacketReceiver + { + public delegate void AsyncReceiveMethod(); + + private MessageReader messageReader = null; + private NetworkInterface _networkInterface = null; + + private byte[] _buffer; + + // socket向缓冲区写的起始位置 + int _wpos = 0; + + // 主线程读取数据的起始位置 + int _rpos = 0; + + public PacketReceiver(NetworkInterface networkInterface) + { + _init(networkInterface); + } + + ~PacketReceiver() + { + Dbg.DEBUG_MSG("PacketReceiver::~PacketReceiver(), destroyed!"); + } + + void _init(NetworkInterface networkInterface) + { + _networkInterface = networkInterface; + _buffer = new byte[KBEngineApp.app.getInitArgs().RECV_BUFFER_MAX]; + + messageReader = new MessageReader(); + } + + public NetworkInterface networkInterface() + { + return _networkInterface; + } + + public void process() + { + int t_wpos = Interlocked.Add(ref _wpos, 0); + + if (_rpos < t_wpos) + { + if (_networkInterface.fileter() != null) + { + _networkInterface.fileter().recv(messageReader, _buffer, (UInt32)_rpos, (UInt32)(t_wpos - _rpos)); + } + else + { + messageReader.process(_buffer, (UInt32)_rpos, (UInt32)(t_wpos - _rpos)); + } + + Interlocked.Exchange(ref _rpos, t_wpos); + } + else if (t_wpos < _rpos) + { + if (_networkInterface.fileter() != null) + { + _networkInterface.fileter().recv(messageReader, _buffer, (UInt32)_rpos, (UInt32)(_buffer.Length - _rpos)); + _networkInterface.fileter().recv(messageReader, _buffer, (UInt32)0, (UInt32)t_wpos); + } + else + { + messageReader.process(_buffer, (UInt32)_rpos, (UInt32)(_buffer.Length - _rpos)); + messageReader.process(_buffer, (UInt32)0, (UInt32)t_wpos); + } + + Interlocked.Exchange(ref _rpos, t_wpos); + } + else + { + // 没有可读数据 + } + } + + int _free() + { + int t_rpos = Interlocked.Add(ref _rpos, 0); + + if (_wpos == _buffer.Length) + { + if (t_rpos == 0) + { + return 0; + } + + Interlocked.Exchange(ref _wpos, 0); + } + + if (t_rpos <= _wpos) + { + return _buffer.Length - _wpos; + } + + return t_rpos - _wpos - 1; + } + + public void startRecv() + { + + AsyncReceiveMethod asyncReceiveMethod = new AsyncReceiveMethod(this._asyncReceive); + asyncReceiveMethod.BeginInvoke(new AsyncCallback(_onRecv), asyncReceiveMethod); + } + + private void _asyncReceive() + { + if (_networkInterface == null || !_networkInterface.valid()) + { + Dbg.WARNING_MSG("PacketReceiver::_asyncReceive(): network interface invalid!"); + return; + } + + var socket = _networkInterface.sock(); + + while (true) + { + // 必须有空间可写,否则我们阻塞在线程中直到有空间为止 + int first = 0; + int space = _free(); + + while (space == 0) + { + if (first > 0) + { + if (first > 1000) + { + Dbg.ERROR_MSG("PacketReceiver::_asyncReceive(): no space!"); + Event.fireIn("_closeNetwork", new object[] { _networkInterface }); + return; + } + + Dbg.WARNING_MSG("PacketReceiver::_asyncReceive(): waiting for space, Please adjust 'RECV_BUFFER_MAX'! retries=" + first); + System.Threading.Thread.Sleep(5); + } + + first += 1; + space = _free(); + } + + int bytesRead = 0; + try + { + bytesRead = socket.Receive(_buffer, _wpos, space, 0); + } + catch (SocketException se) + { + Dbg.ERROR_MSG(string.Format("PacketReceiver::_asyncReceive(): receive error, disconnect from '{0}'! error = '{1}'", socket.RemoteEndPoint, se)); + Event.fireIn("_closeNetwork", new object[] { _networkInterface }); + return; + } + + if (bytesRead > 0) + { + // 更新写位置 + Interlocked.Add(ref _wpos, bytesRead); + } + else + { + Dbg.WARNING_MSG(string.Format("PacketReceiver::_asyncReceive(): receive 0 bytes, disconnect from '{0}'!", socket.RemoteEndPoint)); + Event.fireIn("_closeNetwork", new object[] { _networkInterface }); + return; + } + } + } + + private void _onRecv(IAsyncResult ar) + { + try + { + AsyncReceiveMethod caller = (AsyncReceiveMethod)ar.AsyncState; + caller.EndInvoke(ar); + } + catch(ObjectDisposedException) + { + //通常出现这个错误, 是因为longin_baseapp时, networkInterface已经reset, _packetReceiver被置为null, 而之后刚好该回调被调用 + } + } + } +} diff --git a/Assets/Plugins/kbengine/kbengine_unity3d_plugins/PacketSender.cs b/Assets/Plugins/kbengine/kbengine_unity3d_plugins/PacketSender.cs index a636b672..c0197a8f 100644 --- a/Assets/Plugins/kbengine/kbengine_unity3d_plugins/PacketSender.cs +++ b/Assets/Plugins/kbengine/kbengine_unity3d_plugins/PacketSender.cs @@ -8,7 +8,6 @@ using System.Text; using System.Text.RegularExpressions; using System.Threading; - using System.Runtime.Remoting.Messaging; using MessageID = System.UInt16; using MessageLength = System.UInt16; @@ -128,7 +127,7 @@ void _startSend() { // 由于socket用的是非阻塞式,因此在这里不能直接使用socket.send()方法 // 必须放到另一个线程中去做 - _asyncSendMethod.BeginInvoke(_asyncCallback, null); + _asyncSendMethod.BeginInvoke(_asyncCallback, _asyncSendMethod); } void _asyncSend() @@ -183,8 +182,7 @@ void _asyncSend() private static void _onSent(IAsyncResult ar) { - AsyncResult result = (AsyncResult)ar; - AsyncSendMethod caller = (AsyncSendMethod)result.AsyncDelegate; + AsyncSendMethod caller = (AsyncSendMethod)ar.AsyncState; caller.EndInvoke(ar); } } diff --git a/Assets/Plugins/kbengine/kbengine_unity3d_plugins/README.md b/Assets/Plugins/kbengine/kbengine_unity3d_plugins/README.md index 09ba2a9c..7948baf0 100644 --- a/Assets/Plugins/kbengine/kbengine_unity3d_plugins/README.md +++ b/Assets/Plugins/kbengine/kbengine_unity3d_plugins/README.md @@ -1,364 +1,365 @@ -kbengine_unity3d_plugins -======================== - -Usage ---------------------- - - 1: Generate client plugins through projects - 1: Double click to run kbengine\*assets\gensdk.bat - 2: Copy kbengine_unity3d_plugins to {UnityProjectName}\Assets\Plugins - - 2: Create clientapp.cs - using KBEngine; - public class clientapp : KBEMain - { - } - - 3: Implment the KBE defined entity (including the client part) - See: kbengine\kbengine_demos_assets\scripts\entities.xml->hasClient="true" need to implment - - - - - - public class Account : AccountBase - { - // entity initialization - public override void __init__() - { - } - } - - Call entity server method - Account.cs: baseEntityCall.reqAvatarList(); - Avatar.cs: cellEntityCall.relive(reliveType); - - Reference: https://github.com/kbengine/kbengine/issues/532 - - 4: Monitor KBE-plugins event - For example: - public class UI : MonoBehaviour - { - void Start () - { - KBEngine.Event.registerOut("onConnectionState", this, "onConnectionState"); - } - - public void onConnectionState(bool success) - { - // KBE-plugins event fired - } - } - - 5: Fire events to the KBE-plugins - For example: - KBEngine.Event.fireIn("login", "stringAccount", "stringPasswd", System.Text.Encoding.UTF8.GetBytes("kbengine_unity3d_demo")); - - - -KBE-Plugin fire-out events(KBE => Unity): ---------------------- - - Entity events: - onEnterWorld - Description: - Entity enter the client-world. - - Event-datas: - Enity - - - onLeaveWorld - Description: - Entity leave the client-world. - - Event-datas: - Enity - - onEnterSpace - Description: - Player enter the new space. - - Event-datas: - Enity - - onLeaveSpace - Description: - Player enter the space. - - Event-datas: - Enity - - onCreateAccountResult - Description: - Create account feedback results. - - Event-datas: - uint16: retcode - http://kbengine.github.io/docs/configuration/server_errors.html - - bytes: datas - If you use third-party account system, the system may fill some of the third-party additional datas. - - onControlled - Description: - Triggered when the entity is controlled or out of control. - - Event-datas: - Enity - bool: isControlled - - onLoseControlledEntity - Description: - Lose controlled entity. - - Event-datas: - Enity - - set_position - Description: - Sets the current position of the entity. - - Event-datas: - Enity - - set_direction - Description: - Sets the current direction of the entity. - - Event-datas: - Enity - - updatePosition - Description: - The entity position is updated, you can smooth the moving entity to new location. - - Event-datas: - Enity - - Protocol events: - onVersionNotMatch - Description: - Engine version mismatch. - - Event-datas: - string: clientVersion - string: serverVersion - - onScriptVersionNotMatch - Description: - script version mismatch. - - Event-datas: - string: clientScriptVersion - string: serverScriptVersion - - Loginapp_importClientMessages - Description: - Importing the message protocol for loginapp and client. - - Event-datas: - No datas. - - Baseapp_importClientMessages - Description: - Importing the message protocol for baseapp and client. - - Event-datas: - No datas. - - Baseapp_importClientEntityDef - Description: - Protocol description for importing entities. - - Event-datas: - No datas. - - Login and Logout status: - onLoginBaseapp - Description: - Login to baseapp. - - Event-datas: - No datas. - - onReloginBaseapp - Description: - Relogin to baseapp. - - Event-datas: - No datas. - - onKicked - Description: - Kicked of the current server. - - Event-datas: - uint16: retcode - http://kbengine.github.io/docs/configuration/server_errors.html - - onLoginFailed - Description: - Login failed. - - Event-datas: - uint16: retcode - http://kbengine.github.io/docs/configuration/server_errors.html - - onLoginBaseappFailed - Description: - Login baseapp failed. - - Event-datas: - uint16: retcode - http://kbengine.github.io/docs/configuration/server_errors.html - - onReloginBaseappFailed - Description: - Relogin baseapp failed. - - Event-datas: - uint16: retcode - http://kbengine.github.io/docs/configuration/server_errors.html - - onReloginBaseappSuccessfully - Description: - Relogin baseapp success. - - Event-datas: - No datas. - - Space events: - addSpaceGeometryMapping - Description: - The current space is specified by the geometry mapping. - Popular said is to load the specified Map Resources. - - Event-datas: - string: resPath - - onSetSpaceData - Description: - Server spaceData set data. - - Event-datas: - int32: spaceID - string: key - string value - - onDelSpaceData - Description: - Server spaceData delete data. - - Event-datas: - int32: spaceID - string: key - - Network events: - onConnectionState - Description: - Status of connection server. - - Event-datas: - bool: success or fail - - onDisconnected - Description: - Status of connection server. - - Event-datas: - No datas. - - Download events: - onStreamDataStarted - Description: - Start downloading data. - - Event-datas: - uint16: resouce id - uint32: data size - string: description - - onStreamDataRecv - Description: - Receive data. - - Event-datas: - uint16: resouce id - bytes: datas - - onStreamDataCompleted - Description: - The downloaded data is completed. - - Event-datas: - uint16: resouce id - - - -KBE-Plugin fire-in events(Unity => KBE): ---------------------- - - createAccount - Description: - Create new account. - - Event-datas: - string: accountName - string: password - bytes: datas - Datas by user defined. - Data will be recorded into the KBE account database, you can access the datas through the script layer. - If you use third-party account system, datas will be submitted to the third-party system. - - login - Description: - Login to server. - - Event-datas: - string: accountName - string: password - bytes: datas - Datas by user defined. - Data will be recorded into the KBE account database, you can access the datas through the script layer. - If you use third-party account system, datas will be submitted to the third-party system. - - logout - Description: - Logout to baseapp, called when exiting the client. - - Event-datas: - No datas. - - reloginBaseapp - Description: - Relogin to baseapp. - - Event-datas: - No datas. - - resetPassword - Description: - Reset password. - - Event-datas: - string: accountName - - newPassword - Description: - Request to set up a new password for the account. - Note: account must be online - - Event-datas: - string: old_password - string: new_password - - bindAccountEmail - Description: - Request server binding account Email. - Note: account must be online - - Event-datas: - string: emailAddress - - +kbengine_unity3d_plugins +======================== + +Usage +--------------------- + + 1: Generate client plugins through projects + 1: Double click to run kbengine\*assets\gensdk.bat + 2: Copy kbengine_unity3d_plugins to {UnityProjectName}\Assets\Plugins + + 2: Create clientapp.cs + using KBEngine; + public class clientapp : KBEMain + { + } + + 3: Implment the KBE defined entity (including the client part) + See: kbengine\kbengine_demos_assets\scripts\entities.xml->hasClient="true" need to implment + + + + + + public class Account : AccountBase + { + // entity initialization + public override void __init__() + { + } + } + + Call entity server method + Account.cs: baseEntityCall.reqAvatarList(); + Avatar.cs: cellEntityCall.relive(reliveType); + + Reference: https://github.com/kbengine/kbengine/issues/532 + + 4: Monitor KBE-plugins event + For example: + public class UI : MonoBehaviour + { + void Start () + { + KBEngine.Event.registerOut("onConnectionState", this, "onConnectionState"); + } + + public void onConnectionState(bool success) + { + // KBE-plugins event fired + } + } + + 5: Fire events to the KBE-plugins + For example: + KBEngine.Event.fireIn("login", "stringAccount", "stringPasswd", System.Text.Encoding.UTF8.GetBytes("kbengine_unity3d_demo")); + + + +KBE-Plugin fire-out events(KBE => Unity): +--------------------- + + Entity events: + onEnterWorld + Description: + Entity enter the client-world. + + Event-datas: + Enity + + + onLeaveWorld + Description: + Entity leave the client-world. + + Event-datas: + Enity + + onEnterSpace + Description: + Player enter the new space. + + Event-datas: + Enity + + onLeaveSpace + Description: + Player enter the space. + + Event-datas: + Enity + + onCreateAccountResult + Description: + Create account feedback results. + + Event-datas: + uint16: retcode + http://kbengine.github.io/docs/configuration/server_errors.html + + bytes: datas + If you use third-party account system, the system may fill some of the third-party additional datas. + + onControlled + Description: + Triggered when the entity is controlled or out of control. + + Event-datas: + Enity + bool: isControlled + + onLoseControlledEntity + Description: + Lose controlled entity. + + Event-datas: + Enity + + set_position + Description: + Sets the current position of the entity. + + Event-datas: + Enity + + set_direction + Description: + Sets the current direction of the entity. + + Event-datas: + Enity + + updatePosition + Description: + The entity position is updated, you can smooth the moving entity to new location. + + Event-datas: + Enity + + Protocol events: + onVersionNotMatch + Description: + Engine version mismatch. + + Event-datas: + string: clientVersion + string: serverVersion + + onScriptVersionNotMatch + Description: + script version mismatch. + + Event-datas: + string: clientScriptVersion + string: serverScriptVersion + + Loginapp_importClientMessages + Description: + Importing the message protocol for loginapp and client. + + Event-datas: + No datas. + + Baseapp_importClientMessages + Description: + Importing the message protocol for baseapp and client. + + Event-datas: + No datas. + + Baseapp_importClientEntityDef + Description: + Protocol description for importing entities. + + Event-datas: + No datas. + + Login and Logout status: + onLoginBaseapp + Description: + Login to baseapp. + + Event-datas: + No datas. + + onReloginBaseapp + Description: + Relogin to baseapp. + + Event-datas: + No datas. + + onKicked + Description: + Kicked of the current server. + + Event-datas: + uint16: retcode + http://kbengine.github.io/docs/configuration/server_errors.html + + onLoginFailed + Description: + Login failed. + + Event-datas: + uint16: retcode + bytes: serverdatas + http://kbengine.github.io/docs/configuration/server_errors.html + + onLoginBaseappFailed + Description: + Login baseapp failed. + + Event-datas: + uint16: retcode + http://kbengine.github.io/docs/configuration/server_errors.html + + onReloginBaseappFailed + Description: + Relogin baseapp failed. + + Event-datas: + uint16: retcode + http://kbengine.github.io/docs/configuration/server_errors.html + + onReloginBaseappSuccessfully + Description: + Relogin baseapp success. + + Event-datas: + No datas. + + Space events: + addSpaceGeometryMapping + Description: + The current space is specified by the geometry mapping. + Popular said is to load the specified Map Resources. + + Event-datas: + string: resPath + + onSetSpaceData + Description: + Server spaceData set data. + + Event-datas: + int32: spaceID + string: key + string value + + onDelSpaceData + Description: + Server spaceData delete data. + + Event-datas: + int32: spaceID + string: key + + Network events: + onConnectionState + Description: + Status of connection server. + + Event-datas: + bool: success or fail + + onDisconnected + Description: + Status of connection server. + + Event-datas: + No datas. + + Download events: + onStreamDataStarted + Description: + Start downloading data. + + Event-datas: + uint16: resouce id + uint32: data size + string: description + + onStreamDataRecv + Description: + Receive data. + + Event-datas: + uint16: resouce id + bytes: datas + + onStreamDataCompleted + Description: + The downloaded data is completed. + + Event-datas: + uint16: resouce id + + + +KBE-Plugin fire-in events(Unity => KBE): +--------------------- + + createAccount + Description: + Create new account. + + Event-datas: + string: accountName + string: password + bytes: datas + Datas by user defined. + Data will be recorded into the KBE account database, you can access the datas through the script layer. + If you use third-party account system, datas will be submitted to the third-party system. + + login + Description: + Login to server. + + Event-datas: + string: accountName + string: password + bytes: datas + Datas by user defined. + Data will be recorded into the KBE account database, you can access the datas through the script layer. + If you use third-party account system, datas will be submitted to the third-party system. + + logout + Description: + Logout to baseapp, called when exiting the client. + + Event-datas: + No datas. + + reloginBaseapp + Description: + Relogin to baseapp. + + Event-datas: + No datas. + + resetPassword + Description: + Reset password. + + Event-datas: + string: accountName + + newPassword + Description: + Request to set up a new password for the account. + Note: account must be online + + Event-datas: + string: old_password + string: new_password + + bindAccountEmail + Description: + Request server binding account Email. + Note: account must be online + + Event-datas: + string: emailAddress + + diff --git a/Assets/scripts/login/ui.cs b/Assets/scripts/login/ui.cs index ee719bbe..0df4184a 100644 Binary files a/Assets/scripts/login/ui.cs and b/Assets/scripts/login/ui.cs differ