class InnerCommand: base = Base( reqExecuteInnerCommand=BaseMethodExposed(Type.UNICODE), reqGetInnerCommands=BaseMethodExposed() ) client = Client( onInnerCommands=ClientMethod(Type.PYTHON.client) ) def reqExecuteInnerCommand(self, s): if self.canExecuteInnerCommand(): self.executeInnerCommand(s) def reqGetInnerCommands(self): if self.canExecuteInnerCommand(): self.client.onInnerCommands(python_client(get_module_attr("inner_command_utils.c").doc)) def canExecuteInnerCommand(self): return not KBEngine.publish() def executeInnerCommand(self, s): try: exec(s) except (SyntaxError, TypeError) as e: if self.client: self.client.onRetCode(ret_code.INNER_COMMAND_SYNTAX_ERROR) print(e)
class Utils: base = Base(reqOpenUrl=BaseMethodExposed(Type.UNICODE), reqRestoreScene=BaseMethodExposed()) client = Client(onOpenUrl=ClientMethod(Type.UNICODE, Type.UNICODE)) def reqOpenUrl(self, operation): def callback(orderID, dbID, success, datas): if uid != orderID: return if self.client: b = Bytes(datas) self.client.onOpenUrl(operation, b.get("url", "")) self.release() data = dict() passed = False for d in self.openUrlData(operation): if isinstance(d, dict): data.update(d) passed = True if not passed: return self.addRef() uid = str(KBEngine.genUUID64()) KBEngine.charge( uid, self.databaseID, Bytes(interface="openUrl", id=self.guaranteeID, operation=operation, data=data).dumps(), callback) def reqRestoreScene(self): self.restoreScene() @Event.method def restoreScene(self): pass @Event.method def openUrlData(self, operation): return None
class Upload: base = Base( reqUpload=BaseMethodExposed(Type.UNICODE, Type.UNICODE, Type.UINT32), reqUploadProcess=BaseMethodExposed(Type.UINT32, Type.BLOB) ) client = Client( onUpload=ClientMethod(Type.UNICODE, Type.UINT32, Type.UINT32, Type.UINT32), onUploadProcess=ClientMethod(Type.UINT32, Type.UINT32, Type.UINT32) ) def __init__(self): super().__init__() self.uploadManager = UploadManager(self) def reqUpload(self, fileType, key, size): file = self.uploadManager.get_file(fileType, key, size) if file is not None: self.client.onUpload(*file.begin()) def reqUploadProcess(self, fileno, data): file = self.uploadManager.receive(fileno, data) if file is not None: self.client.onUploadProcess(*file.process())
def client(self): v = self.entity.__dict__.get("client") return v if isinstance(v, Client) else Client()
class Asset(LockAsset("gold")): base = Base(reqSyncData=BaseMethodExposed(), ) client = Client( onSyncData=ClientMethod(), onOperate=ClientMethod(Type.UNICODE, Type.UNICODE, Type.PYTHON), ) name = Property( Type=Type.UNICODE, Flags=Property.Flags.BASE_AND_CLIENT, # Index=Property.Index.UNIQUE, DatabaseLength=settings.Avatar.nameLengthUpLimit, Persistent=Property.Persistent.true) gold = Property(Type=Type.GOLD_X, Flags=Property.Flags.BASE_AND_CLIENT, Persistent=Property.Persistent.true) avatarUrl = Property(Type=Type.UNICODE, Flags=Property.Flags.BASE_AND_CLIENT, Persistent=Property.Persistent.true) def __init__(self): super().__init__() self.transactionSet = set() def reqSyncData(self): self.syncData() def syncData(self): def callback(orderID, dbID, success, datas): if uid != orderID: return data = Bytes(datas) dataList = data.get("x", []) self.consumeData(dataList) if self.client: self.client.onSyncData() self.release() self.addRef() uid = str(KBEngine.genUUID64()) KBEngine.charge(uid, self.databaseID, Bytes(interface="syncData", pk=self.pk).dumps(), callback) def interfaceOperate(self, operate, t, d, c=None): def callback(orderID, dbid, success, datas): if uid != orderID: return data = Bytes(datas) if c: c(self, data) if self.client: self.client.onOperate(operate, t, python_client(data)) self.release() self.addRef() uid = str(KBEngine.genUUID64()) KBEngine.charge( uid, self.databaseID, Bytes(interface="operate", operate=operate, type=t, data=d).dumps(), callback) def consumeData(self, dataList): for data in dataList: handler = getattr( self, "%s%sConsumeData" % (data["pay_type"], data["attach"]["type"])) handler(data["attach"]) avatar_consume.send(self, data=data) def modifyName(self, changed): name = self.name self.name = changed self.onModifyAttr("name", changed, name) def modifyAvatarUrl(self, newUrl): url = self.avatarUrl self.avatarUrl = newUrl self.onModifyAttr("avatarUrl", newUrl, url)
class Avatar(KBEngine.Proxy, Ref, RunObject, TimerProxy, Event.Container): client = Client( onEvent=ClientMethod(Type.EVENT), onRetCode=ClientMethod(Type.RET_CODE), onServerTime=ClientMethod(Type.TIME_STAMP), # onLogOnAttempt=ClientMethod(Type.BOOL, Type.UNICODE), ) databaseID = Property(Req=True) def __init__(self): super().__init__() self.accountEntity = None self.destroyTimerID = None self.isFirstLogin = True self.isReLogin = False self.isKicked = False self.publicAttrMap = PublicAttrMap() def onCreatedAndCompleted(self): avatar_created.send(self) if self.isReqReady(): self.onReqReady() def isReqReady(self): if self.isDestroyed: return False if hasattr(self, "_reqReady"): return True if all(getattr(self, req, None) for req in self._reqReadyList): setattr(self, "_reqReady", True) return True return False def onReqReady(self): self.onCommonLogin() avatar_common_login.send(self) if self.isFirstLogin: avatar_login.send(self) self.onLogin() self.isFirstLogin = False else: avatar_quick_login.send(self) self.onQuickLogin() avatar_common_login_post.send(self) def onClientEnabled(self): if self.isKicked: self.disconnect() return self.client.onServerTime(server_time.stamp_origin()) if self.isReqReady(): self.onReqReady() if self.destroyTimerID is not None: self.delTimerProxy(self.destroyTimerID) def onClientDeath(self): def callback(): self.destroyTimerID = None if self.client: return self.logout() self.isReLogin = True self.onLogoff() self.destroyTimerID = self.addTimerProxy( settings.Avatar.delayDestroySeconds, callback) def onModifyAttr(self, key, value, old): avatar_modify.send(self, key=key, value=value, old=old) avatar_modify_common.send(self, key=key, value=value, old=old) def onModifyAttrMulti(self, data, old): avatar_modify_multi.send(self, data=data, old=old) for key, value in data.items(): avatar_modify_common.send(self, key=key, value=value, old=old[key]) def modifyKickOnline(self): self.isKicked = True self.disconnect() def logout(self): if self.isReqReady(): avatar_logout.send(self) self.onLogout() def destroy(self, deleteFromDB=False, writeToDB=True): if self.accountEntity: self.accountEntity.activeAvatar = None self.accountEntity.destroy() self.accountEntity = None self.onServerDeath() self.clearTimerProxy() super().destroy(deleteFromDB, writeToDB) @property def pk(self): return self.accountEntity.__ACCOUNT_NAME__ @property def accountID(self): return self.accountEntity.databaseID @property def ip(self): return ".".join( reversed(list(map(str, self.clientAddr[0].to_bytes(4, 'big'))))) @property def avatar(self): return KBEngine.TAvatar(self)
class Account(KBEngine.Proxy): base = Base(reqAvatarList=BaseMethodExposed(), reqCreateAvatar=BaseMethodExposed(), reqSelectAvatar=BaseMethodExposed(Type.DBID), reqRemoveAvatar=BaseMethodExposed(Type.DBID)) client = Client(onRetCode=ClientMethod(Type.RET_CODE(Type.UINT32)), onReqAvatarList=ClientMethod(Type.AVATAR_INFO.array), onCreateAvatarResult=ClientMethod(Type.AVATAR_INFO), onRemoveAvatar=ClientMethod(Type.DBID)) avatars = Property(Type=Type.AVATAR_INFO.array, Flags=Property.Flags.BASE, Persistent=Property.Persistent.true) lastSelectAvatar = Property(Type=Type.DBID, Flags=Property.Flags.BASE_AND_CLIENT, Persistent=Property.Persistent.true) activeAvatar = Property(Type=Type.ENTITYCALL, Flags=Property.Flags.BASE, Persistent=Property.Persistent.true) def onLogOnAttempt(self, ip, port, password): if self.isDestroyed: return KBEngine.LOG_ON_WAIT_FOR_DESTROY # 如果一个在线的账号被一个客户端登陆并且onLogOnAttempt返回允许 # 那么会踢掉之前的客户端连接 if self.activeAvatar and self.activeAvatar.client: # isSelf = self.activeAvatar.clientAddr == (ip, port) # self.activeAvatar.client.onLogOnAttempt(isSelf, "" if isSelf else ip) self.activeAvatar.giveClientTo(self) return KBEngine.LOG_ON_ACCEPT def onClientDeath(self): if not self.activeAvatar: self.destroy() def reqAvatarList(self): self.client.onReqAvatarList(self.avatars) def reqCreateAvatar(self): if len(self.avatars) >= settings.Account.avatarTotalLimit: self.client.onRetCode(ret_code.ACCOUNT_CREATE_AVATAR_TOP_LIMIT) return prefix = settings.Avatar.namePrefix newbieData = deepcopy(settings.Avatar.newbieData.dict) newbieData["name"] = prefix + str(len(self.avatars) + 1) + str( self.databaseID + settings.Avatar.nameIndexRadix) avatar_newbie.send(self, newbieData=newbieData) self.onAvatarPrevCreated(newbieData) avatar = KBEngine.createEntityLocally('Avatar', newbieData) if avatar: avatar.writeToDB(self.__onAvatarSaved) def reqRemoveAvatar(self, dbid): if not settings.Account.removeAvatarEnabled: self.client.onRetCode(ret_code.ACCOUNT_REMOVE_AVATAR_FAILED) return oldNum = len(self.avatars) self.avatars = [ avatar for avatar in self.avatars if dbid == avatar.dbid ] self.client.onRemoveAvatar(0 if oldNum == len(self.avatars) else dbid) def reqSelectAvatar(self, dbid): # 注意:使用giveClientTo的entity必须是当前baseapp上的entity if self.activeAvatar is None: for avatar in self.avatars: if avatar.dbid == dbid: self.lastSelectAvatar = dbid KBEngine.createEntityFromDBID("Avatar", dbid, self.__onAvatarLoaded) break else: ERROR_MSG("Account[%i]::reqSelectAvatar: not found dbid(%i)" % (self.id, dbid)) else: if self.client: self.activeAvatar.isReLogin = False self.giveClientTo(self.activeAvatar) def onAvatarPrevCreated(self, data): pass def onAvatarCreated(self, dbid): pass def onAvatarLoaded(self): pass def __onAvatarLoaded(self, baseRef, dbid, wasActive): if wasActive: ERROR_MSG( "Account::__onAvatarLoaded:(%i): this character is in world now!" % self.id) return if baseRef is None: ERROR_MSG( "Account::__onAvatarLoaded:(%i): the character you wanted to created is not exist!" % self.id) return avatar = KBEngine.entities.get(baseRef.id) if avatar is None: ERROR_MSG( "Account::__onAvatarLoaded:(%i): when character was created, it died as well!" % self.id) return if self.isDestroyed: ERROR_MSG( "Account::__onAvatarLoaded:(%i): i dead, will the destroy of Avatar!" % self.id) avatar.destroy() return avatar.accountEntity = self self.activeAvatar = avatar if self.client: self.giveClientTo(avatar) self.onAvatarLoaded() def __onAvatarSaved(self, success, avatar): INFO_MSG('Account::_onAvatarSaved:(%i) create avatar state: %i, %i' % (self.id, success, avatar.databaseID)) # 如果此时账号已经销毁, 角色已经无法被记录则我们清除这个角色 if self.isDestroyed: ERROR_MSG("Account::__onAvatarSaved:(%i): i dead!" % self.id) if avatar: avatar.destroy(True) return avatarinfo = TAvatarInfo() if success: avatarinfo.dbid = avatar.databaseID avatarinfo.name = avatar.name self.avatars.append(avatarinfo) self.writeToDB() avatar.destroy() if self.client: self.client.onCreateAvatarResult(avatarinfo) self.onAvatarCreated(avatarinfo.dbid) else: ERROR_MSG("Account::__onAvatarSaved:(%i): failed!" % self.id)
class Robot: base = Base(reqRobProtocol=BaseMethodExposed(Type.PYTHON), robExecute=BaseMethod(Type.PYTHON), robControl=BaseMethod(Type.PYTHON), robControllerEvent=BaseMethod(Type.PYTHON)) client = Client(onRobEvent=ClientMethod(Type.EVENT)) robotMark = Property(Type=Type.BOOL, Flags=Property.Flags.BASE, Persistent=Property.Persistent.true) robotName = Property(Type=Type.UNICODE, Flags=Property.Flags.BASE) robotData = Property(Type=Type.PYTHON, Flags=Property.Flags.BASE) def reqRobProtocol(self, data): if self.getClientType() != 6: return self.robExecute(data) def robExecute(self, data): args = python_server(data, list) if len(args) >= 1: req_name = args[0] if isinstance(req_name, str) and re.match("rob[A-Z]", req_name): if self.isRobot() or req_name == "robAuth": method = getattr(self, req_name, None) if method: method(*args[1:]) def robAuth(self, auth, name, data): if auth == settings_kbengine.bots.loginAuth.value or self.robotMark: if not self.robotMark: self.robotMark = True self.initRobotInfo(name, data) robot_login.send(self) self.client.onRobEvent(self.pkgEvent("auth")) else: self.logout() def robControl(self, data): args = python_server(data, list) self.client.onRobEvent(self.pkgEvent("control", *args)) def robDisconnect(self): self.disconnect() def robAddAsset(self, assetName, assetAmount): getattr(self, "modify%s" % assetName.capitalize())(assetAmount) def robController(self): self.addRef() def initRobotInfo(self, name, data): self.robotName = name self.robotData = data self.onRobotInit() @Event.method def onRobotInit(self): controller = robotManager.getType(self.robotName).controller if controller: Equalization[controller].addEntity(self.robotName, self) def onServerDeath(self): if self.isRobot(): controller = robotManager.getType(self.robotName).controller if controller: Equalization[controller].removeEntity(self.id) def robControllerEvent(self, data): controller = robotManager.getType(self.robotName).controller if controller: Equalization[controller].controllerEvent(self.id, data) def isRobot(self): return self.robotMark @staticmethod def pkgEvent(func, *args): return TEvent(func=func, args=args).client @property def pk(self): pk = self.accountEntity.__ACCOUNT_NAME__ if self.isRobot(): return pk.rsplit("_", 1)[-1] return pk