KBEngine 房间示例创建脚本调用解读

    首先放个房间示例的资源路径https://github.com/u3dkbe/kbengine_unity3d_balls

    这个例子很简单,客户端点击登录按钮后即进入场景,同时生成大量NPC。鼠标点击可移动吃分。不过这里只关心脚本涉及初始化这块。kbengine的服务器用python写脚本,各种系统回调以及自己写的回调夹杂在一起,不熟悉会相当很晕。。所以写这个也权当笔记。。。

    首先客户端向服务端发送登录消息后,服务端自动检测默认设置为帐号属性的类(这个DEMO里面是Avatar)。然后自动调用Avatar BASE部分的初始化代码。初始化完成后,会调用一个回调函数:onEnitiesEnabled。这个回调是引擎接口,只需要往里面添加自己的代码就好。demo在这个回调里面,利用全局参数获得大厅HALL的指针,调用了enterRoom函数。

def onEntitiesEnabled(self):
		"""
		KBEngine method.
		该entity被正式激活为可使用, 此时entity已经建立了client对应实体, 可以在此创建它的
		cell部分。
		"""
		INFO_MSG("Avatar[%i] entities enable. mailbox:%s" % (self.id, self.client))
		
		# 如果销毁玩家计时器已经开启了,此处玩家又上线了那么应该取消计时器
		if self._destroyTimer > 0:
			self.delTimer(self._destroyTimer)
			self._destroyTimer = 0
			
		# 如果玩家存在cell, 说明已经在地图中了, 因此不需要再次进入地图
		if self.cell is None:
			# 玩家上线了或者重登陆了, 此处告诉大厅,玩家请求登陆到游戏地图中
			KBEngine.globalData["Halls"].enterRoom(self, self.cellData["position"], self.cellData["direction"], self.roomKey)

    那这个HALL类是哪里来的呢?其实是在引擎初始化脚本里面。当启动服务器时,调用了KBEngine的base部分的引擎接口onBaseAppReady。在这个回调里面通过KBEngine.createBaseLocally函数创建了HALL类。


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")))

	# 安装监视器
	Watcher.setup()
	
	if isBootstrap:
		# 创建大厅
		KBEngine.createBaseLocally( "Halls", {} )

    回到HALL.enterRoom这个函数来,通过调用findRoom来寻找房间,这个函数查找是否存在已有的房间,若不存在的话则通过KBEngine.createBaseAnywhere异步创建Room类。随后判断,如果房间异步创建还未成功,则先把要加入房间的avatar信息保存下来。

def enterRoom(self, entityMailbox, position, direction, roomKey):
		"""
		defined method.
		请求进入某个Room中
		"""
		roomDatas = self.findRoom(roomKey, True)

		roomDatas["PlayerCount"] += 1
		
		roomMailbox = roomDatas["roomMailbox"]
		if roomMailbox is not None:
			roomMailbox.enterRoom(entityMailbox, position, direction)
		else:
			DEBUG_MSG("Halls::enterRoom: space %i creating..., enter entityID=%i" % (roomDatas["roomKey"], entityMailbox.id))
			roomDatas["enterRoomReqs"].append((entityMailbox, position, direction))

def findRoom(self, roomKey, notFoundCreate = False):
		"""
		查找一个指定房间,如果找不到允许创建一个新的
		"""
		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

			self.lastNewRoomKey = KBEngine.genUUID64()
			
			# 将房间base实体创建在任意baseapp上
			# 此处的字典参数中可以对实体进行提前def属性赋值
			KBEngine.createBaseAnywhere("Room", \
									{
									"roomKey" : self.lastNewRoomKey,	\
									}, \
									Functor.Functor(self.onRoomCreatedCB, self.lastNewRoomKey))
			
			roomDatas = {"roomMailbox" : None, "PlayerCount": 0, "enterRoomReqs" : [], "roomKey" : self.lastNewRoomKey}
			self.rooms[self.lastNewRoomKey] = roomDatas
			return roomDatas

		return roomDatas


    Room被异步调用创建后,首先是base部分的初始化。demo在这个初始化代码里面调用了createInNewSpace函数,异步创建Room的cell部分。Room cell部分的创建成功后,会调用Base部分的回调函数onGetCell。demo在这个回调函数里面,调用了HALL.onRoomGetCell,而这个函数利用先前保存的avatar信息,调用avatar.creatCellEntity来创建avatar的cell部分。avatar cell创建成功后同样会调用BASE部分的onGetCell回调。至此,avatar正式加入场景。看到这里,有没有觉得一堆回调让人很晕。。。

def onGetCell(self):
		"""
		KBEngine method.
		entity的cell部分实体被创建成功
		"""
		DEBUG_MSG("Room::onGetCell: %i" % self.id)
		KBEngine.globalData["Halls"].onRoomGetCell(self, self.roomKey)
def onRoomGetCell(self, roomMailbox, roomKey):
		"""
		defined method.
		Room的cell创建好了
		"""
		self.rooms[roomKey]["roomMailbox"] = roomMailbox

		# space已经创建好了, 现在可以将之前请求进入的玩家全部丢到cell地图中
		for infos in self.rooms[roomKey]["enterRoomReqs"]:
			entityMailbox = infos[0]
			entityMailbox.createCell(roomMailbox.cell)
			
		self.rooms[roomKey]["enterRoomReqs"] = []
def createCell(self, space):
		"""
		defined method.
		创建cell实体
		"""
		self.createCellEntity(space)

    avatar只是我们控制的角色,那那些NPC是怎么加入场景的呢?在ROOM的cell部分的初始化代码里,利用addTimer加入了一个定时器。这个定时器干嘛的呢?通过定期回调onTimer,调用了room cell部分的balanceMass函数,通过KBEngine.createEntity函数生成了大量的NPC。所以这里demo其实是演示了一个通过定时器,避免同时大量创建物体NPC的办法,减轻服务器压力。

def onTimer(self, id, userArg):
		"""
		KBEngine method.
		使用addTimer后, 当时间到达则该接口被调用
		@param id		: addTimer 的返回值ID
		@param userArg	: addTimer 最后一个参数所给入的数据
		"""
		if TIMER_TYPE_DESTROY == userArg:
			self.onDestroyTimer()
		elif TIMER_TYPE_BALANCE_MASS == userArg:
			self.balanceMass()


你可能感兴趣的:(Unity,KBEngine)