def requestAccountLogin(loginName, password, datas): """ KBEngine method. 请求登陆账号 @param loginName: 客户端请求时所提交的名称 @type loginName: string @param password: 密码 @type password: string @param datas: 客户端请求时所附带的数据,可将数据转发第三方平台 @type datas: bytes """ INFO_MSG('requestAccountLogin: registerName=%s' % (loginName)) commitName = loginName # 默认账号名就是提交时的名 realAccountName = commitName # 此处可通过http等手段将请求提交至第三方平台,平台返回的数据也可放入datas # datas将会回调至客户端 KBEngine.accountLoginResponse(commitName, realAccountName, datas, KBEngine.SERVER_SUCCESS)
def onRequestAccountLogin(loginName, password, datas): """ KBEngine method. 请求登陆账号回调 @param loginName: 客户端请求时所提交的名称 @type loginName: string @param password: 密码 @type password: string @param datas: 客户端请求时所附带的数据,可将数据转发第三方平台 @type datas: bytes """ INFO_MSG("onRequestAccountLogin: registerName=%s" % (loginName)) commitName = loginName # 默认账号名就是提交时的名 realAccountName = commitName # 此处可通过http等手段将请求提交至第三方平台,平台返回的数据也可放入datas # datas将会回调至客户端 # 如果使用http访问,因为interfaces是单线程的,同步http访问容易卡住主线程,建议使用 # KBEngine.registerReadFileDescriptor()和KBEngine.registerWriteFileDescriptor()结合 # tornado异步访问。也可以结合socket模拟http的方式与平台交互。 # 如果返回码为KBEngine.SERVER_ERR_LOCAL_PROCESSING则表示验证登陆成功,但dbmgr需要检查账号密码,KBEngine.SERVER_SUCCESS则无需再检查密码 KBEngine.accountLoginResponse(commitName, realAccountName, datas, KBEngine.SERVER_ERR_LOCAL_PROCESSING)
def update(self): DEBUG_MSG("%s::update: %i" % (self.__class__.__name__, self.id)) if self.isDestroyed: return KBEngine.callback(1, self.update) # 如果自己已经死亡了,那么延时一下复活 if self.isState(GlobalDefine.ENTITY_STATE_DEAD): if self.reliveTime == -1: self.reliveTime = random.randint(1, 10) elif self.reliveTime > 0: self.reliveTime -= 1 else: self.cell.relive(1) return else: self.reliveTime = -1 self.updateTest() if self.testType == 1: self.testAttackTarget() elif self.testType == 2: self.testTeleport() else: self.moveToPoint( self.calcRandomWalkPosition(), self.velocity, 0.0, 0, True, True )
def onReqAvatarList(self, infos): """ define method. """ DEBUG_MSG("Account:onReqAvatarList::%s" % (infos)) self.avatars = infos KBEngine.fireEvent("update_avatars", self.avatars)
def onRequestCreateAccount(registerName, password, datas): """ KBEngine method. 请求创建账号回调 @param registerName: 客户端请求时所提交的名称 @type registerName: string @param password: 密码 @type password: string @param datas: 客户端请求时所附带的数据,可将数据转发第三方平台 @type datas: bytes """ INFO_MSG("onRequestCreateAccount: registerName=%s" % (registerName)) commitName = registerName # 默认账号名就是提交时的名 realAccountName = commitName # 此处可通过http等手段将请求提交至第三方平台,平台返回的数据也可放入datas # datas将会回调至客户端 # 如果使用http访问,因为interfaces是单线程的,同步http访问容易卡住主线程,建议使用 # KBEngine.registerReadFileDescriptor()和KBEngine.registerWriteFileDescriptor()结合 # tornado异步访问。也可以结合socket模拟http的方式与平台交互。 KBEngine.createAccountResponse(commitName, realAccountName, datas, KBEngine.SERVER_SUCCESS)
def onBecomePlayer( self ): """ KBEngine method. 当这个entity被引擎定义为角色时被调用 """ DEBUG_MSG("%s::onBecomePlayer: %i" % (self.__class__.__name__, self.id)) KBEngine.callback(1, self.update)
def createSpawnPointDatas(self): """ """ res = r"scripts\data\spawnpoints\%s_spawnpoints.xml" % self.spaceResName if(len(self.spaceResName) == 0 or not KBEngine.hasRes(res)): return res = KBEngine.getResFullPath(res) tree = etree.parse(res) root = tree.getroot() DEBUG_MSG("Space::createSpawnPointDatas: %s" % (res)) for child in root: position = child[0][0] direction = child[0][1] scaleNode = child[0][2] scale = int(((float(scaleNode[0].text) + float(scaleNode[1].text) + float(scaleNode[2].text)) / 3.0) * 10) self.tmpCreateEntityDatas.append([int(child.attrib['name']), \ (float(position[0].text), float(position[1].text), float(position[2].text)), \ (float(direction[0].text) * ((math.pi * 2) / 360), float(direction[1].text) * ((math.pi * 2) / 360), float(direction[2].text) * ((math.pi * 2) / 360)), \ scale, \ ])
def createSpawnPointDatas(self): """ """ res = r"scripts\data\spawnpoints\%s_spawnpoints.xml" % (self.spaceResName.replace("\\", "/").split("/")[-1]) if(len(self.spaceResName) == 0 or not KBEngine.hasRes(res)): return res = KBEngine.getResFullPath(res) tree = etree.parse(res) root = tree.getroot() DEBUG_MSG("Space::createSpawnPointDatas: %s" % (res)) for child in root: positionNode = child[0][0] directionNode = child[0][1] scaleNode = child[0][2] scale = int(((float(scaleNode[0].text) + float(scaleNode[1].text) + float(scaleNode[2].text)) / 3.0) * 10) position = (float(positionNode[0].text), float(positionNode[1].text), float(positionNode[2].text)) direction = [float(directionNode[0].text) / 360 * (math.pi * 2), float(directionNode[1].text) / 360 * (math.pi * 2), float(directionNode[2].text) / 360 * (math.pi * 2)] if direction[0] - math.pi > 0.0: direction[0] -= math.pi * 2 if direction[1] - math.pi > 0.0: direction[1] -= math.pi * 2 if direction[2] - math.pi > 0.0: direction[2] -= math.pi * 2 self.tmpCreateEntityDatas.append([int(child.attrib['name']), \ position, \ direction, \ scale, \ ])
def onBootStart(self, bootstrapIdx): """ virtual method. 被引导时触发 """ if bootstrapIdx == 1: # 创建spacemanager KBEngine.createBaseLocally( "Spaces", {} )
def onAutoLoadEntityCreate(entityType, dbid): """ KBEngine method. 自动加载的entity创建方法,引擎允许脚本层重新实现实体的创建,如果脚本不实现这个方法 引擎底层使用createBaseAnywhereFromDBID来创建实体 """ INFO_MSG('onAutoLoadEntityCreate: entityType=%s, dbid=%i' % (entityType, dbid)) KBEngine.createBaseAnywhereFromDBID(entityType, dbid)
def set_HP_Max(self, oldValue): """ Property method. 服务器设置了属性 """ DEBUG_MSG("%s::set_HP_Max: %i changed:%s->%s" % (self.getScriptName(), self.id, oldValue, self.HP_Max)) KBEngine.fireEvent("set_HP_Max", json.dumps((self.id, self.HP_Max)))
def set_modelScale(self, oldValue): """ Property method. 服务器设置了modelNumber属性 """ DEBUG_MSG("%s::set_modelScale: %i changed:%s->%s" % (self.getScriptName(), self.id, oldValue, self.modelScale)) KBEngine.fireEvent("set_modelScale", self.id, self.modelScale)
def set_modelID(self, oldValue): """ Property method. 服务器设置了modelNumber属性 """ DEBUG_MSG("%s::set_modelID: %i changed:%s->%s" % (self.getScriptName(), self.id, oldValue, self.modelID)) # 通知表现层改变表现 KBEngine.fireEvent("set_modelID", json.dumps((self.id, self.modelID)))
def set_name(self, oldValue): """ Property method. 服务器设置了name属性 """ DEBUG_MSG("%s::set_name: %i changed:%s->%s" % (self.getScriptName(), self.id, oldValue, self.name)) # 通知表现层改变表现 KBEngine.fireEvent("set_name", self.id, self.name)
def onLoginAppReady(): """ KBEngine method. interfaces已经准备好了 """ INFO_MSG('onLoginAppReady: bootstrapGroupIndex=%s, bootstrapGlobalIndex=%s' % \ (os.getenv("KBE_BOOTIDX_GROUP"), os.getenv("KBE_BOOTIDX_GLOBAL"))) KBEngine.addTimer(0.01, 1.0, onTick)
def recvDamage(self, attackerID, skillID, damageType, damage): """ defined. """ DEBUG_MSG("%s::recvDamage: %i attackerID=%i, skillID=%i, damageType=%i, damage=%i" % \ (self.getScriptName(), self.id, attackerID, skillID, damageType, damage)) # 通知表现层改变表现 KBEngine.fireEvent("recvDamage", self.id, attackerID, skillID, damageType, damage)
def start(self, addr, port): """ virtual method. """ self._socket = socket.socket() self._socket.bind((addr, port)) self._socket.listen(10) KBEngine.registerReadFileDescriptor(self._socket.fileno(), self.onRecv)
def __init__(self): KBEngine.Entity.__init__(self) GameObject.__init__(self) resPath = d_spaces.datas.get(self.spaceUType)['resPath'] KBEngine.addSpaceGeometryMapping(self.spaceID, None, resPath) DEBUG_MSG('created space[%d] entityID = %i, res = %s.' % (self.spaceUType, self.id, resPath)) KBEngine.globalData["space_%i" % self.spaceID] = self.base
def onInterfaceAppReady(): """ KBEngine method. interfaces已经准备好了 """ INFO_MSG('onInterfaceAppReady: bootstrapGroupIndex=%s, bootstrapGlobalIndex=%s' % \ (os.getenv("KBE_BOOTIDX_GROUP"), os.getenv("KBE_BOOTIDX_GLOBAL"))) KBEngine.addTimer(0.01, 1.0, onTick) g_poller.start("localhost", 30040)
def createSpace(self, spaceKey, context): """ """ context = copy.copy(context) spaceData = d_spaces.datas.get(self._utype) KBEngine.createBaseAnywhere( spaceData["entityType"], {"spaceUType": self._utype, "spaceKey": spaceKey, "context": context}, Functor.Functor(self.onSpaceCreatedCB, spaceKey), )
def onBaseAppReady(bootstrapIdx): """ KBEngine method. baseapp已经准备好了 @param isBootstrap: 是否是第一个baseapp启动 @type isBootstrap: bool """ DEBUG_MSG('baseapp准备完毕! bootstrapIdx=%s' % bootstrapIdx) if bootstrapIdx == 1: # 创建spacemanager KBEngine.createBaseLocally( "Spaces", {} )
def onCreateAvatarResult(self, retcode, info): """ define method. """ DEBUG_MSG("Account:onCreateAvatarResult::%s, retcode=%i" % (info, retcode)) if info[0] == 0: # "dbid" DEBUG_MSG("Account:onCreateAvatarResult::avatar full.") return self.avatars[info[0]] = info KBEngine.fireEvent("update_avatars", self.avatars)
def fireEvent(self, evtName): firedatas = "" if evtName == "update_avatars": dctinfo = copy.deepcopy(dict(self.avatars)) for info in dctinfo.values(): for data in info[4].values(): data[1] = "" firedatas = json.dumps(dctinfo) KBEngine.fireEvent(evtName, firedatas)
def __init__(self): KBEngine.Entity.__init__(self) GameObject.__init__(self) # 一个space代表的是一个抽象的空间,这里向这个抽象的空间添加了几何资源数据,如果数据是3D场景的 # 该space中使用navigate寻路使用的是3D的API,如果是2D的几何数据navigate使用的是astar寻路 resPath = d_spaces.datas.get(self.spaceUType)['resPath'] KBEngine.addSpaceGeometryMapping(self.spaceID, None, resPath) DEBUG_MSG('created space[%d] entityID = %i, res = %s.' % (self.spaceUType, self.id, resPath)) KBEngine.globalData["space_%i" % self.spaceID] = self.base
def onEnterSpace(self): """ KBEngine method. 这个entity进入了一个新的space """ DEBUG_MSG("%s::onEnterSpace: %i" % (self.__class__.__name__, self.id)) # 注意:由于PlayerAvatar是引擎底层强制由Avatar转换过来,__init__并不会再调用 # 这里手动进行初始化一下 self.__init__() self.spawnPosition = Math.Vector3( self.position ) KBEngine.callback(1, self.updateMove)
def onBaseAppReady(bootstrapIdx): """ KBEngine method. baseapp已经准备好了 @param isBootstrap: 是否是第一个baseapp启动 @type isBootstrap: bool """ INFO_MSG('onBaseAppReady: bootstrapIdx=%s' % bootstrapIdx) KBEngine.addWatcher("scripts/countPlayers", "UINT32", countPlayers) if bootstrapIdx == 1: # 创建spacemanager KBEngine.createBaseLocally( "Spaces", {} )
def kbengine_onEvent(eventID, args): """ KBEngine method. app发出的事件 @param args: 自行约定 """ DEBUG_MSG("kbengine_onEvent:: eventID = %s, args=%s" % (str(eventID), str(args))) if eventID == "reset": kbesystem.eventMgr.fire("reset", 0) elif eventID == "relive": if KBEngine.player() != None: KBEngine.player().relive()
def onBaseAppReady(bootstrapIdx): """ KBEngine method. baseapp已经准备好了 @param bootstrapIdx: 当前baseapp的启动顺序 @type bootstrapIdx: INT32 """ INFO_MSG('onBaseAppReady: bootstrapIdx=%s' % bootstrapIdx) KBEngine.addWatcher("players", "UINT32", countPlayers) if bootstrapIdx == 1: # 创建spacemanager KBEngine.createBaseLocally( "Spaces", {} )
def __init__(self): GameObject.__init__(self) resPath = d_spaces.datas.get(self.spaceUType)["resPath"] if resPath == "": resPath = "../../res/Media/Scenes/Scene1" KBEngine.addSpaceGeometryMapping(self.spaceID, None, resPath) else: KBEngine.addSpaceGeometryMapping(self.spaceID, None, resPath) DEBUG_MSG("created space[%d] entityID = %i, res = %s." % (self.spaceUType, self.id, resPath)) KBEngine.globalData["space_%i" % self.spaceID] = self.base
def createSpace(self, spaceKey, context): """ """ if spaceKey <= 0: spaceKey = KBEngine.genUUID64() context = copy.copy(context) spaceData = d_spaces.datas.get(self._utype) KBEngine.createBaseAnywhere(spaceData["entityType"], \ {"spaceUType" : self._utype, \ "spaceKey" : spaceKey, \ "context" : context, \ }, \ Functor.Functor(self.onSpaceCreatedCB, spaceKey))
def insertDatabaseCallBack(result, num, error): if error is not None: ERROR_MSG("Space[%i].sendMailByDBID %i insertDatabaseCallBack Fail." % (self.id, dbid)) return DEBUG_MSG("Space[%i] insertDatabaseCallBack %i -- %i %s success." % (self.id, dbid, num, str(result))) def queryDatabaseCallBack(result, num, error): if error is not None: ERROR_MSG("Space[%i].sendMailByDBID %i queryDatabaseCallBack Fail." % (self.id, dbid)) return if len(result) != 1: ERROR_MSG("Space[%i].sendMailByDBID %i queryDatabaseCallBack result:%s is error." % (self.id, dbid, str(result))) return for item in mail["attachment"]: KBEngine.executeRawDatabaseCommand("INSERT INTO "+switch.DB_NAME+".tbl_Avatar_mailList_attachment (parentID, sm_itemId, sm_count) VALUES(%i, %i, %i);" % (int(result[0][0]), item["itemId"], item["count"]), None) KBEngine.executeRawDatabaseCommand("SELECT `id` FROM "+switch.DB_NAME+".tbl_Avatar_mailList WHERE sm_mid = %i;" % mail["mid"], queryDatabaseCallBack)
def __init__(self): BaseEntity.__init__(self) self.sportDict = {} table_daily_sports = h1global.rc.sportDict[const.SPORT_DAILY] for k in table_daily_sports: DEBUG_MSG(table_daily_sports[k]) sportId = table_daily_sports[k]['id'] self.sportDict[sportId] = KBEngine.createBaseLocally( "SportDaily", {'sportId': sportId}) x42.SportDailyStub = self
def onGetCell(self): """ entity的cell部分被创建成功 """ DEBUG_MSG("Scene[%i]::onGetCell: " % self.id) props = { "name": "MyFirstEntity", "position": (1.7, 0, 0) # 为了和Account实体在空间中的位置不重叠,这里设置一个差别 } entity = KBEngine.createEntityLocally("FirstEntity", props) self.loginToScene(entity)
def onCmdGetChanllengeMember(self, param): selfRank = param["selfRank"] playerMB = param["playerMB"] rankNum = 3 down = 1000 if selfRank > 1000: down = selfRank - 100 elif selfRank > 500 and selfRank <= 1000: down = selfRank - 20 elif selfRank > 200 and selfRank <= 500: down = selfRank - 15 elif selfRank > 50 and selfRank <= 200: down = selfRank - 10 elif selfRank > 10 and selfRank <= 50: down = selfRank - 8 elif selfRank > 1 and selfRank <= 10: down = selfRank - 5 # 注意判断下限 top = selfRank - 1 sql = "select sm_dbid,sm_rank,sm_isRobot from tbl_ArenaRow where sm_rank between " + str( down) + " and " + str(top) + " ORDER BY rand() LIMIT " + str( rankNum) ERROR_MSG("=========slq== " + sql) @util.dbDeco def queryResult(result, rownum, error): if result is None: return param = [] for i in range(len(result)): dbid = int(result[i][0]) rank = int(result[i][1]) isRobot = int(result[i][2]) item = {"dbid": dbid, "rank": rank, "isRobot": isRobot} param.append(item) playerMB.onPlayerMgrCmd("onArenaMgrQueryResult", param) KBEngine.executeRawDatabaseCommand(sql, queryResult)
def onRecv(self, task, sock, file_no): if sock.fileno() == file_no: t_id = self._write_timer.pop(file_no, None) if t_id: self.cancel_timer(t_id) try: # INFO_MSG('------------- onRecv ------------ {} {}'.format(task[0], task[2])) resp = HTTPResponse(sock) if task and task[2]: resp.begin() if resp.getcode() / 100 == 2: decode = resp.read().decode('utf-8') task[2](decode) else: task[2](None) except: self.logsError() finally: KBEngine.deregisterReadFileDescriptor(file_no) if not sock._closed: sock.close()
def onRequestCharge(ordersID, entityDBID, datas): """ KBEngine method. 请求计费回调 @param ordersID: 订单的ID @type ordersID: uint64 @param entityDBID: 提交订单的实体DBID @type entityDBID: uint64 @param datas: 客户端请求时所附带的数据,可将数据转发第三方平台 @type datas: bytes """ INFO_MSG('onRequestCharge: entityDBID=%s, entityDBID=%s' % (ordersID, entityDBID)) # 此处可通过http等手段将请求提交至第三方平台,平台返回的数据也可放入datas # datas将会回调至baseapp的订单回调中,具体参考API手册charge # 如果使用http访问,因为interfaces是单线程的,同步http访问容易卡住主线程,建议使用 # KBEngine.urlopen("https://www.baidu.com",onHttpCallback)异步访问。也可以结合异步socket的方式与平台交互(参考Poller.py)。 KBEngine.chargeResponse(ordersID, datas, KBEngine.SERVER_SUCCESS)
def createCardEntity(self, cardID, pos='KZ'): DEBUG_MSG('Avatar.cell::createCardEntity: [%i] cardID[%i] pos:[%s]' % ( self.id, cardID, pos)) params = { 'cardID': cardID, 'pos': pos, "battlefiled": self.battlefiled, 'avatar': self, 'playerID': self.playerID } e=KBEngine.createEntity('card',self.spaceID,tuple(self.position),tuple(self.direction),params) self.cardEntityList.append(e)
def setup(signal, sender): indexes, conf = Equalization.getBaseIndexInfo("http_utils") if sender.groupIndex in indexes: KBEngine.setAppFlags( KBEngine.APP_FLAGS_NOT_PARTCIPATING_LOAD_BALANCING) server = HTTPServerAsync() index = indexes.index(sender.groupIndex) info = conf[index] ip = "" if info["externalIP"]: ip = settings_kbengine.baseapp.externalAddress.value if not ip: ip = internal_ip_address() port = info["port"] xml_conf = settings_kbengine.apps.http_utils ip = xml_conf.ip.value or ip port = xml_conf.port.value or port server.listen(ip, port) plugins.plugins.load_all_module("http_servers") http_setup.send(server, conf=dict(ip=ip, port=port)) print("Starting development server at http://%s:%s" % (ip, port))
def selectAvatarGame(self): """ exposed. 客户端选择某个角色进行游戏 """ DEBUG_MSG("Account[%i].selectAvatarGame:. self.activeAvatar=%s" % (self.id, self.activeAvatar)) # 注意:使用giveClientTo的entity必须是当前baseapp上的entity if self.activeAvatar is None: if len(self.characters) <= 0: ERROR_MSG("Account[%i]::selectAvatarGame: not found " % (self.id)) else: for dbid in self.characters.keys(): self.lastSelCharacter = dbid KBEngine.createEntityFromDBID("Avatar", dbid, self.__onAvatarCreated) break else: self.giveClientTo(self.activeAvatar)
def onCmdGetArenaPlayerInfo(self, param): rank = param["rank"] playerMB = param["playerMB"] @util.dbDeco def getPlayerInfo(result, rownum, error): if result is None: return param = [] for i in range(len(result)): dbid = int(result[i][0]) isRobot = int(result[i][1]) item = {"dbid": dbid, "isRobot": isRobot} param.append(item) playerMB.onPlayerMgrCmd("onGetArenaPlayerInfo", param) sql = "select sm_dbid,sm_isRobot from tbl_ArenaRow where sm_rank = " + str( rank) KBEngine.executeRawDatabaseCommand(sql, getPlayerInfo)
def callback(uid, content): avt = x42.GW.avatars.get(uid) if content[0] != '{': DEBUG_MSG(content) if avt: avt.showTip("摩卡不足") return if avt and avt.isDestroyed == False: avt.gameLeft = const.WEEK_SPORT_GAME_NUM self.joinSuccess(avt) else: sql = "UPDATE tbl_Avatar set sm_left_games = {} where sm_userId = {}".format( const.WEEK_SPORT_GAME_NUM, uid) def update_cb(result, num, insert_id, error): if error: ERROR_MSG( "update gameLeft for player-{} failed!".format( uid)) KBEngine.executeRawDatabaseCommand(sql, update_cb)
def reqCreateAvatar(self, context): """ 根据前端类别给出出生点 UNKNOWN_CLIENT_COMPONENT_TYPE = 0, CLIENT_TYPE_MOBILE = 1, // 手机类 CLIENT_TYPE_PC = 2, // pc, 一般都是exe客户端 CLIENT_TYPE_BROWSER = 3, // web应用, html5,flash CLIENT_TYPE_BOTS = 4, // bots CLIENT_TYPE_MINI = 5, // 微型客户端 """ props = { "name": self.__ACCOUNT_NAME__, "uuid": KBEngine.genUUID64(), "gender": random.randint(0, 1), "lastLoginTime": time.time(), "accountName": self.__ACCOUNT_NAME__, } DEBUG_MSG('Account(%i)::reqCreateAvatar: %i' % (self.id, 0)) avatar = KBEngine.createBaseLocally("Avatar", props) if avatar: avatar.writeToDB(self._onCharacterSaved)
def reqGiveLand(self, DBID, LandID): INFO_MSG("reqGiveLand:%i,%i" % (DBID, LandID)) #判断是否已经有这个块土地 Maxid = len(self.LandData) if LandID > Maxid or LandID == 1: self.client.onGiveLand('没有这块土地') return -1 #土地有种子也不能送 LandInfo = self.GetLandInfo(LandID) if LandInfo['ItemType'] != 0: self.client.onGiveLand('种植中的土地不能赠送') return -2 if LandInfo['LandType'] == 0: self.client.onGiveLand('未购买') return -3 self.BuildGenerator('CallFriendGiveLand') KBEngine.createEntityFromDBID( "Account", DBID, Functor.Functor(self.CallFriendGiveLand, LandInfo)) return 0
def ReqRemoveRole(self, Name): """ 客户端请求删除一个角色,此处使用角色名来选择,可能不太严谨,之后可以增加或修改为根据ID来选择 """ DEBUG_MSG("PtAccount[%i].ReqRemoveRole: %s" % (self.id, Name)) # 数据库Id Dbid = -1 for key, info in self.RoleList.items(): # 如果角色存在, 保存key到数据库Id if info[1] == Name: Dbid = key break # 如果Dbid为负, 说明不存在对应角色, 直接返回 if Dbid == -1: return # 从数据库生成该角色, 生成该角色后,再调用该角色的destroy(True)从数据库删除 KBEngine.createEntityFromDBID("PtRole", Dbid, self._OnRoleRemoved)
def onBaseAppReady(isBootstrap): """ KBEngine method. baseapp已经准备好了 @param isBootstrap: 是否为第一个启动的baseapp @type isBootstrap: BOOL """ INFO_MSG('onBaseAppReady: isBootstrap=%s, appID=%s, bootstrapGroupIndex=%s, bootstrapGlobalIndex=%s' % \ (isBootstrap, os.getenv("KBE_COMPONENTID"), os.getenv("KBE_BOOTIDX_GROUP"), os.getenv("KBE_BOOTIDX_GLOBAL"))) # if isBootstrap: # # 第一个baseapp就绪时,创建FirstEntity # props = { # "name": "MyFirstEntity" # } # KBEngine.createEntityLocally("FirstEntity", props) if isBootstrap: # 第一个baseapp就绪时,创建一个Scene实体 KBEngine.createEntityLocally("Scene", {})
def insert(self, callback, *args, **kwargs): """ 向数据库插入一条记录。 def callback(success, insertid): pass """ kw = list(args) + list(kwargs.items()) fieldNames = [] fieldValues = [] fieldValuesP = [] for k, v in kw: fieldNames.append(self.meta.fields[k].db_column) fieldValues.append(v) fieldValuesP.append("%s") cmd = "insert into {} ( {} ) values ( {} )".format( self.meta.db_table, ", ".join(fieldNames), ", ".join(fieldValuesP)) cmd = MysqlUtility.makeSafeSql(cmd, fieldValues) #DEBUG_MSG( "%s::insert(), %s" % (self.__class__.__name__, cmd) ) KBEngine.executeRawDatabaseCommand( cmd, functools.partial(self._insert_callback, cmd, callback))
def onEntitiesEnabled(self): """ KBEngine method. 该entity被正式激活为可使用, 此时entity已经建立了client对应实体, 可以在此创建它的 cell部分。 """ DEBUG_MSG(self.avatarDBIDList) INFO_MSG("account[%i] entities enable. mailbox:%s" % (self.id, self.client)) if self.avatarDBID == 0: self.avatar = KBEngine.createBaseLocally("Avatar", {}) if self.avatar: self.avatar.accountEntity = self self.avatar.cellData["position"] = (120.4, 0.44, 90.6) self.avatar.cellData["direction"] = (0.0, 0.0, 0.0) self.avatar.cellData["entityName"] = self.__ACCOUNT_NAME__ self.avatar.writeToDB(self._onAvatarSaved) self.giveClientTo(self.avatar) else: KBEngine.createBaseFromDBID("Avatar", self.avatarDBID, self.__onAvatarCreateCB)
def reqCreateAvatar(self, roleType, name): """ exposed. 客户端请求创建一个角色 """ avatarinfo = TAvatarInfos() avatarinfo.extend([0, "", 0, 0, TAvatarData().createFromDict({"param1" : 0, "param2" :b''})]) """ if name in all_avatar_names: retcode = 2 self.client.onCreateAvatarResult(retcode, avatarinfo) return """ if len(self.characters) >= 3: DEBUG_MSG("Account[%i].reqCreateAvatar:%s. character=%s.\n" % (self.id, name, self.characters)) self.client.onCreateAvatarResult(3, avatarinfo) return """ 根据前端类别给出出生点 UNKNOWN_CLIENT_COMPONENT_TYPE = 0, CLIENT_TYPE_MOBILE = 1, // 手机类 CLIENT_TYPE_PC = 2, // pc, 一般都是exe客户端 CLIENT_TYPE_BROWSER = 3, // web应用, html5,flash CLIENT_TYPE_BOTS = 4, // bots CLIENT_TYPE_MINI = 5, // 微型客户端 """ spaceUType = 1 if self.getClientType() == 2: spaceUType = 2 elif self.getClientType() == 5: spaceUType = 3 else: spaceUType = 1 spaceData = d_spaces.datas.get(spaceUType) props = { "name" : name, "roleType" : roleType, "level" : 1, "spaceUType" : spaceUType, "direction" : (0, 0, d_avatar_inittab.datas[roleType]["spawnYaw"]), "position" : spaceData.get("spawnPos", (0,0,0)) } avatar = KBEngine.createBaseLocally('Avatar', props) if avatar: avatar.writeToDB(self._onCharacterSaved) DEBUG_MSG("Account[%i].reqCreateAvatar:%s. spaceUType=%i, spawnPos=%s.\n" % (self.id, name, avatar.cellData["spaceUType"], spaceData.get("spawnPos", (0,0,0))))
def callback(content): if content is None: DEBUG_MSG( "createRoom callback error: content is None, user id {}". format(self.userId)) self.createRoomFailed(const.CREATE_FAILED_NET_SERVER_ERROR) return try: DEBUG_MSG("cards response: {}".format(content)) if content[0] != '{': self.createRoomFailed(const.CREATE_FAILED_NET_SERVER_ERROR) return data = json.loads(content) card_cost, diamond_cost = switch.calc_cost( game_round, pay_mode) if not KBEngine.globalData[ "GameWorld"].free_play and card_cost > data[ "card"] and diamond_cost > data["diamond"]: self.createRoomFailed(const.CREATE_FAILED_NO_ENOUGH_CARDS) return # @formatter:off params = { 'owner_uid': self.userId, 'king_num': 1, 'player_num': 4, 'game_round': game_round, 'pay_mode': pay_mode, 'lucky_num': lucky_num, 'hand_prepare': hand_prepare, 'room_type': room_type, } # @formatter:on KBEngine.createBaseAnywhere("GameRoom", params, self.createRoomCallback) except: err, msg, stack = sys.exc_info() DEBUG_MSG( "createRoom callback error:{} , exc_info: {} ,{}".format( content, err, msg)) self.createRoomFailed(const.CREATE_FAILED_OTHER)
def onRequestAccountLogin(loginName, password, datas): """ KBEngine method. 请求登陆账号回调 @param loginName: 客户端请求时所提交的名称 @type loginName: string @param password: 密码 @type password: string @param datas: 客户端请求时所附带的数据,可将数据转发第三方平台 @type datas: bytes """ INFO_MSG('onRequestAccountLogin: registerName=%s' % (loginName)) commitName = loginName # 默认账号名就是提交时的名 realAccountName = commitName # 此处可通过http等手段将请求提交至第三方平台,平台返回的数据也可放入datas # datas将会回调至客户端 # 如果使用http访问,因为interfaces是单线程的,同步http访问容易卡住主线程,建议使用 # KBEngine.registerReadFileDescriptor()和KBEngine.registerWriteFileDescriptor()结合 # tornado异步访问。也可以结合socket模拟http的方式与平台交互。 # 如果返回码为KBEngine.SERVER_ERR_LOCAL_PROCESSING则表示验证登陆成功,但dbmgr需要检查账号密码,KBEngine.SERVER_SUCCESS则无需再检查密码 if "test" in commitName: KBEngine.accountLoginResponse(commitName, realAccountName, datas, KBEngine.SERVER_ERR_LOCAL_PROCESSING) else: import urllib.request as urllib import json print(urllib) res = json.loads( urllib.urlopen( "http://ncf.cz-studio.cn/check-user/?user_email={user}&user_password={pw}" .format(user=loginName, pw=password)).read().decode('utf-8')) if res['passport'] == "1": realAccountName = res['username'] if res['usertype'] in ["8", "9"]: KBEngine.accountLoginResponse(commitName, realAccountName, datas, KBEngine.SERVER_SUCCESS) else: KBEngine.accountLoginResponse( commitName, realAccountName, datas, KBEngine.SERVER_ERR_ACCOUNT_NOT_ACTIVATED) else: KBEngine.accountLoginResponse(commitName, realAccountName, datas, KBEngine.SERVER_ERR_NAME_PASSWORD)
def _nextPlayer(self): if self.curCid == 0: self.curCid = random.randint(1, len(self.players)) self.firstCid = self.curCid self.players[self.curCid].first = 1 KBEngine.setSpaceData(self.spaceID, "firstCid", str(self.firstCid)) else: for i in range(0, 5): tCid = (self.curCid + i) % 5 + 1 if tCid in self.players: if self.players[tCid].stateC == ROOM_STATE_INGAME: self.curCid = tCid break #计算回合数 if self.firstCid == self.curCid: self.curRound += 1 KBEngine.setSpaceData(self.spaceID, "curRound", str(self.curRound)) # 重置房间时间 self.curRoomtime = self.roomtime self._removeUserArgTimer(0) self._addUserArgTimer(1, 1, ACTION_ROOM_NEXT) data = {} data["curCid"] = self.curCid data["curDizhu"] = self.curDizhu data["curRoomtime"] = self.curRoomtime data_json = json.dumps(data) KBEngine.setSpaceData(self.spaceID, "ACTION_ROOM_NEXT", data_json)
def reqCreateRoom(self, entityCall, name, intro, password): """ 请求创建房间 """ DEBUG_MSG("Hall::reqCreateRoom:name:%s,intro:%s,password:%s" % (name, intro, password)) if name == "": return 31 if intro == "": return 32 self.newRoomKey = KBEngine.genUUID64() KBEngine.createEntityAnywhere("Room", \ { "roomKey" : self.newRoomKey, "name" : name, "intro" : intro, "password" : password }, \ Functor.Functor(self.onRoomCreatedCB, self.newRoomKey)) if password == "": hasPassword = 1 else: hasPassword = 2 roomDatas = { "roomEntityCall": None, "playerCount": 0, "roomKey": self.newRoomKey, "name": name, "intro": intro, "password": password, "isPlaying": 1, "hasPassword": hasPassword, "enterRoomReqs": [] } self.rooms[self.newRoomKey] = roomDatas DEBUG_MSG("Hall::reqCreateRoom:rooms:%s" % self.rooms) entityCall.reqJoinRoom(self.newRoomKey, password)
def findRoom(self, roomKey, notFoundCreate=False): """ 查找一个指定房间,如果找不到允许创建一个新的 """ DEBUG_MSG("Halls::findRoom : roomKey=%i notFoundCreate=%i" % (roomKey, notFoundCreate)) roomDatas = self.rooms.get(roomKey) # 如果房间没有创建,则将其创建 if not roomDatas: if not notFoundCreate: return FIND_ROOM_NOT_FOUND # 如果最后创建的房间没有满员,则使用最后创建的房间key,否则产生一个新的房间唯一Key roomDatas = self.rooms.get(self.lastNewRoomKey) if roomDatas is not None and roomDatas[ "PlayerCount"] < GameConfigs.ROOM_MAX_PLAYER: return roomDatas #生成一个64位的唯一id,作为房间的id self.lastNewRoomKey = KBEngine.genUUID64() # 将房间base实体创建在任意baseapp上 # 此处的字典参数中可以对实体进行提前def属性赋值 KBEngine.createEntityAnywhere("Room", \ { "roomKey" : self.lastNewRoomKey, \ }, \ Functor.Functor(self.onRoomCreatedCB, self.lastNewRoomKey)) roomDatas = { "roomEntityCall": None, "PlayerCount": 0, "enterRoomReqs": [], "roomKey": self.lastNewRoomKey } self.rooms[self.lastNewRoomKey] = roomDatas return roomDatas return roomDatas
def selectAvatarGame(self, dbid): """ exposed. 客户端选择某个角色进行游戏 """ DEBUG_MSG("Account[%i].selectAvatarGame:%i. self.activeAvatar=%s" % (self.id, dbid, self.activeAvatar)) # 注意:使用giveClientTo的entity必须是当前baseapp上的entity if self.activeAvatar is None: if dbid in self.characters: self.lastSelCharacter = dbid # 由于需要从数据库加载角色,因此是一个异步过程,加载成功或者失败会调用__onAvatarCreated接口 # 当角色创建好之后,account会调用giveClientTo将客户端控制权(可理解为网络连接与某个实体的绑定)切换到Avatar身上, # 之后客户端各种输入输出都通过服务器上这个Avatar来代理,任何proxy实体获得控制权都会调用onClientEnabled # Avatar继承了Teleport,Teleport.onClientEnabled会将玩家创建在具体的场景中 KBEngine.createEntityFromDBID("Avatar", dbid, self.__onAvatarCreated) else: ERROR_MSG("Account[%i]::selectAvatarGame: not found dbid(%i)" % (self.id, dbid)) else: self.giveClientTo(self.activeAvatar)
def _dbCmdCreateTblCB(resultCollect, num, errorInfo): DEBUG_MSG(errorInfo) if errorInfo is None: bigWorld = KBEngine.createBaseLocally("BigWorld", {}) if bigWorld: DEBUG_MSG("create bigWorld success") bigWorld.writeToDB(_bigWorldSavedCB) # KBEngine.executeRawDatabaseCommand("INSERT INTO mini_Spaces VALUES ('BigWorld', 0)", # _dbCmdInsertBigWorldCB) else: ERROR_MSG("create bigWorld failed") else: ERROR_MSG("create tbl failed")
def insert_many(self, datas, cb=None, table=None): """ insert 多个 :param cb: 回调,它有两个参数 (insert_id, error) :param table: 可选的表名 :param datas: 是一个 list """ _table = self._get_table(table) if not datas: WARNING_MSG("insert_many, datas is none. return") return data = datas[0] field_keys = list(data.keys()) field_keys_format = [] for key in field_keys: field_type = self.model.__fields__.get(key) # 字符串需要带个引号包起来 if issubclass(field_type, (STRING, JSON)): DEBUG_MSG("field key: %s" % key) field_keys_format.append("'{%s}'" % key) else: field_keys_format.append("{%s}" % key) multi_values = [] for data in datas: for key in field_keys: data[key] = self.model.__fields__.get(key).dumps(data[key]) multi_values.append("({fields_value})".format( fields_value=",".join(field_keys_format)).format(**data)) values_phase = ",".join(multi_values) sql = "INSERT INTO {table} ({fields}) VALUES {multi_values}".format( table=_table, fields=",".join(field_keys), multi_values=values_phase) DEBUG_MSG("DML::insert_many, sql[%s]" % sql) KBEngine.executeRawDatabaseCommand( sql, Functor(self._insert_cb, cb, datas, _table, sql))
def findRoom(self, roomKey, notFoundCreate = False): roomDatas = self.rooms.get(roomKey) if not roomDatas: if not notFoundCreate: return FIND_ROOM_NOT_FOUND roomDatas = self.rooms.get(self.lastNewRoomKey) if roomDatas is not None: return roomDatas self.lastNewRoomKey = KBEngine.genUUID64() KBEngine.createEntityAnywhere("Room", \ {"roomKey" : self.lastNewRoomKey,}, \ Functor.Functor(self.onRoomCreatedCB, self.lastNewRoomKey)) roomDatas = {"roomEntityCall":None, "PlayerCount": 0, "enterRoomReqs" : [], "roomKey" : self.lastNewRoomKey} self.rooms[self.lastNewRoomKey] = roomDatas return roomDatas return roomDatas
def sqlcallback(result, row, insertid, errstr): global newInfoList if errstr: # 输出错误信息 ERROR_MSG("updateFriendsMessage[%i].reqChangeName:[%s]" % (self.id, errstr)) self.client.reqChangeNameCall(errstr) elif len(result) > 0: newInfoList.append({ 'dbid': int(result[0][0]), "name": result[0][2].decode("utf-8"), "level": int(result[0][3]), "status": False, "icon": int(result[0][4]) }) self.DbidToIndex[int(result[0][0])] = len(newInfoList) - 1 #回调完毕 if len(newInfoList) == len(self.Friend_list): for oneInfo in newInfoList: # 检查该DBID对应实体是否检出 也就是是否在线 KBEngine.lookUpEntityByDBID("Account", oneInfo['dbid'], lookUpEntityCallBack)
def _createRoom(self, roomType, avList): """ 创建房间 参数1:房间类型 参数2:房间内玩家列表 """ param = { # 大厅信息 'masterHalls': self, 'masterHallsName': self.hallsName, # 房间基本属性 'roomID': 100000, 'roomType': roomType, 'roomName': 'gobangRoom', 'gameID': self.gameID, # 房间内玩家 'maxPlayerCount': 2, 'playerList': avList, } KBEngine.createEntityAnywhere('gobangRoom', param)
def xiaCiYiDingSkill(self, entityId): ''' 重写下次一定技能 ''' if self.BattleFieldCell.isFinished == True: return Skills.xiaCiYiDingSkill(self, entityId) if self.goldNum >= self.xiaCiYiDingGold: self.goldNum -= self.xiaCiYiDingGold else: DEBUG_MSG("Avatar[%i] :: xiaCiYiDingSkill : 金币(%i)不足" % (self.id, self.goldNum)) return acceptAvatarCell = self.BattleFieldCell.cellAvatars[entityId] params = { "launchID": self.id, "acceptID": acceptAvatarCell.id, "followAvatarCell": acceptAvatarCell, } KBEngine.createEntity('XiaCiYiDingProp', self.BattleFieldCell.spaceID, (0.0, 0.0, 0.0), acceptAvatarCell.direction, params)