def get_pet_enemies_around(eid, radius, except_entity=False): """ 获取区域内的敌方entity列表 """ comp = serverApi.GetEngineCompFactory().CreateGame(eid) filters = { "any_of": [ { "subject": "other", "test": "is_family", "value": "enemy" }, { "subject": "other", "test": "is_family", "value": "monster" }, { "subject": "other", "test": "is_family", "value": "mob" }, ] } entity_ids = comp.GetEntitiesAround(eid, radius, filters) if except_entity: if eid in entity_ids: entity_ids.remove(eid) return entity_ids
def OnKillPlayer(self, args): """ OnKillPlayerEvent的回调函数,回应客户端的请求,杀死进入黑洞半径的玩家 """ comp = serverApi.GetEngineCompFactory().CreateGame( serverApi.GetLevelId()) comp.KillEntity(args['playerId'])
def OnShowDeleteSuccessMsg(self, args): """ OnShowDeleteSuccessMsgEvent事件的回调函数,响应删除按钮的请求,在左上角打印输出“黑洞已经全部清除”的消息 """ comp = serverApi.GetEngineCompFactory().CreateMsg( self.dict['playerId']) comp.NotifyOneMessage(self.dict['playerId'], "黑洞已经全部清除!", "§4") # 取消两个定时器 if self.msg_timer and self.func_timer: comp = serverApi.GetEngineCompFactory().CreateGame( serverApi.GetLevelId()) comp.CancelTimer(self.func_timer) comp.CancelTimer(self.msg_timer) self.message_switch = False self.last_message_switch = False
def show_message(self, entity_id, time): """ 左上角提示玩家黑洞启动倒计时信息 """ if time: # 10s后执行功能,在聊天框显示倒计时,倒计时刷新速度1s一次 comp = serverApi.GetEngineCompFactory().CreateMsg(entity_id) comp.NotifyOneMessage(entity_id, "注意,黑洞将在%ds后启动,请立即离开" % time, "§4")
def createSimpleBomb(self, playerId, bulletId, pos): ''' 创建一次爆炸,带火且影响方块 :param playerId: :param bulletId: :param pos: :return: ''' comp = serverApi.GetEngineCompFactory().CreateExplosion(playerService.getLevelId()) comp.CreateExplosion(pos, 2, True, True, bulletId, playerId)
def onBulletHit(self, data): playerId = data['srcId'] bulletId = data['id'] if "ENTITY" == data['hitTargetType']: pos = (data['x'], data['y'], data['z']) else: pos = (data['blockPosX'], data['blockPosY'], data['blockPosZ']) comp = serverApi.GetEngineCompFactory().CreateEngineType(bulletId) if str(comp.GetEngineTypeStr()) == 'peacegun:boom': bulletService.createSimpleBomb(playerId, bulletId, pos)
def add_block_item_listen_for_use_event(block_name): """ 增加blockName方块对ServerBlockUseEvent事件的脚本层监听 1.19 调整 去掉增加原版方块监听ServerBlockUseEvent事件时同步到客户端的功能 :param block_name: str 方块名称,格式:namespace:name:AuxValue,其中namespace:name:*匹配所有的方块数据值AuxValue :return: bool 是否增加成功 """ block_use_event_white_list_comp = serverApi.GetEngineCompFactory().CreateBlockUseEventWhiteList(level_id) return block_use_event_white_list_comp.AddBlockItemListenForUseEvent(block_name)
def get_motion(entity_id): """ 获取生物(含玩家)的瞬时移动方向向量 1.18 新增 获取生物的瞬时移动方向向量 :param entity_id: :return: tuple(int,int,int) 瞬时移动方向向量,异常时返回None """ motion_comp = serverApi.GetEngineCompFactory().CreateActorMotion(entity_id) return motion_comp.GetMotion()
def clear_and_create_block(self, playerId, blockPos): """ 将指定位置方块替换为空气,在其位置创建/掉落原实体方块 """ # 此处playerId为block的设置者 comp = serverApi.GetEngineCompFactory().CreateBlockInfo(playerId) # 获取操作前的指定位置的所有方块信息 old_blockDict = comp.GetBlockNew(blockPos) # 不对空气方块进行操作 if old_blockDict['name'] != 'minecraft:air': # 方式一:使用此方式可能会直接破坏掉一些方块,导致实际生成的掉落物比真正的少 blockDict = {'name': 'minecraft:air'} comp.SetBlockNew(blockPos, blockDict, 1)
def set_motion(entity_id, motion): """ 设置生物(不含玩家)的瞬时移动方向向量 # rot 和 世界坐标系关系 # ^ x -90° # | # 180°/-180 ----------> z 0° # | 90° 1.18 新增 设置生物瞬时移动方向向量 :param entity_id: :param motion: tuple(float,float,float) 世界坐标系下的向量,该方向为世界坐标系下的向量,以x,z,y三个轴的正方向为正值。 可以通过当前生物的rot组件判断目前玩家面向的方向,可在开发模式下打开F3观察数值变化。 :return: bool 设置是否成功 """ motion_comp = serverApi.GetEngineCompFactory().CreateActorMotion(entity_id) return motion_comp.SetMotion(motion)
def createSimpleBoom(self, playerId, pos, direct, **kwargs): ''' 创建一个炸弹 :param playerId: :param pos: :param direct: :param kwargs: :return: ''' boomComp = serverApi.GetEngineCompFactory().CreateProjectile(playerService.getLevelId()) param = { 'position': pos, 'direction': direct, 'power': 3 } if kwargs: param.update(kwargs) boomId = boomComp.CreateProjectileEntity(playerId, "peacegun:boom", param)
def createSimpleBullet(self, playerId, pos, direct, **kwargs): ''' 创建一个子弹 :param playerId: :param pos: :param direct: :return: ''' bulletComp = serverApi.GetEngineCompFactory().CreateProjectile(playerService.getLevelId()) param = { 'position': pos, 'direction': direct, 'power': 3, 'damage': 10 } if kwargs: param.update(kwargs) bulletId = bulletComp.CreateProjectileEntity(playerId, "peacegun:bullet", param)
# coding=utf-8 import mod.server.extraServerApi as serverApi from tutorialScripts.common.Service import Service # 获取组件工厂,用来创建组件 compFactory = serverApi.GetEngineCompFactory() class PlayerService(Service): def getLevelId(self): ''' 获取当前Server的世界id :return: ''' return serverApi.GetLevelId() def getPlayerPosition(self, playerId): ''' 获取玩家位置 :param playerId: :return: ''' posComp = compFactory.CreatePos(playerId) return posComp.GetPos() def getPlayerDirect(self, playerId): ''' 获取玩家朝向 :param playerId: :return:
def biology_attract(self, player_id, x, y, z): # 使用服务端组件GetEntitiesInSquareArea获取指定范围内实体ID levelId = serverApi.GetLevelId() comp = serverApi.GetEngineCompFactory().CreateGame(levelId) # 正方形范围起始位置(正式用) startPos = ((x - self.attract_radius), (y - self.attract_radius), (z - (math.sqrt(2) * self.attract_radius))) # 正方形范围结束位置(正式用) endPos = ((x + self.attract_radius), (y + self.attract_radius), (z + (math.sqrt(2) * self.attract_radius))) # print '========= attract_radius =', self.attract_radius # 测试用吸收半径 # r = 18 # startPos = ((x - r / 2), (y - r / 2), (z - (math.sqrt(2) * r / 2))) # endPos = ((x + r / 2), (y + r / 2), (z + (math.sqrt(2) * r / 2))) # 获取到的指定正方形范围内所有entityId entity_ids = comp.GetEntitiesInSquareArea(None, startPos, endPos, 0) # 将吸收范围内的所有实体ID存入成员变量中 self.entity_ids = entity_ids # print '------------------------------------------------------------------------ l = ', len(entity_ids) # print '-----------------------------> attract =', len(entity_ids) for entityId in entity_ids: # 对范围内实体进行区分,将生物实体和掉落物实体a区分开,分别进行向量位移计算 type_comp = serverApi.GetEngineCompFactory().CreateEngineType( entityId) # 获取实体类型 entityType = type_comp.GetEngineType() # 过滤 if not entityType: continue # 获取实体位置坐标 comp = serverApi.GetEngineCompFactory().CreatePos(entityId) entityPos = comp.GetPos() if entityPos: entityPosX = entityPos[0] entityPosY = entityPos[1] entityPosZ = entityPos[2] # 下面代码实现功能:将黑洞吸收半径范围内的实体吸引过来 if entityType and entityType == 64: # 掉落物实体的向量移动逻辑(最后需要写成可变化的) # SetPos接口------------------------ comp.SetPos( ((float(x - entityPosX) / 800 * 3) + entityPosX, (float(y - 3 - entityPosY) / 50 * 3) + entityPosY, (float(z - entityPosZ) / 800 * 3) + entityPosZ)) pos_z = (float(x - entityPosX) / 800 * 3, float(y - entityPosY) / 800 * 3, float(z - entityPosZ) / 800 * 3) # set_motion接口------------------------ set_motion(entityId, pos_z) # comp.SetPos(((float(x - entityPosX) / 200) + entityPosX, # (float(y - 2 - entityPosY) / 50) + entityPosY, # (float(z - entityPosZ) / 200) + entityPosZ)) # pos_z = (float(x - entityPosX) / 200, float(y - entityPosY) / 200, float(z - entityPosZ) / 200) # set_motion(entityId, pos_z) else: # 非掉落物实体的向量移动逻辑(最后需要写成可变化的) # SetPos接口------------------------ # comp.SetPos(((float(x - entityPosX) / 200) + entityPosX, # (float(y - entityPosY) / 200) + entityPosY, # (float(z - entityPosZ) / 200) + entityPosZ)) # comp.SetPos(((float(x - entityPosX) / 500) + entityPosX, # (float(y - entityPosY) / 500) + entityPosY, # (float(z - entityPosZ) / 500) + entityPosZ)) # set_motion接口------------------------ # pos_z = (float(x - entityPosX) / 200, float(y - entityPosY) / 200, float(z - entityPosZ) / 200) # set_motion(entityId, pos_z) pos_z = (float(x - entityPosX) / 300, float(y - entityPosY) / 300, float(z - entityPosZ) / 300) set_motion(entityId, pos_z) # 下面代码实现功能:杀死进入黑洞半径大小范围内的实体 # 获取黑洞吸收半径范围内所有生物到黑洞中心的距离 num = (x - entityPosX)**2 + (y - entityPosY)**2 + ( z - entityPosZ)**2 # 开平方,获取生物到黑洞中心的距离 distance = math.sqrt(num) # 杀死进入黑洞半径范围内的实体 if distance <= self.radius: levelId = serverApi.GetLevelId() comp = serverApi.GetEngineCompFactory().CreateGame(levelId) # ret = comp.KillEntity(entityId) ret = self.DestroyEntity(entityId) if ret: self.kill_count += 1 # print '------------------------------------------------------------- kill =', self.kill_count # --------------- 此处写黑洞效果随吸收的实体数的变化逻辑 --------------- # if self.kill_count != 0 and self.kill_count % 200 == 0: # 计算出吸收半径的圆和黑洞杀死半径的圆之间的体积的一半,作为黑洞扩增的吸收物品件数条件 # limit_count = (2 * math.pi * (self.attract_radius**3 - (self.radius - 3)**3)) / 3 # print '-----------------------> limit_count =', limit_count if self.kill_count != 0 and self.kill_count % ( ((2 + self.change_count) * 100 * self.change_count)) == 0: # if self.kill_count != 0 and self.kill_count % 300 == 0: # 使扩增倍数加1(使后续扩增条件均是初始条件的一倍) self.change_count += 1 # 设置半径变化(每次扩增1格) self.radius += 1 # --------begin---------- 创建事件数据,广播自定义事件,通知客户端修改黑洞序列帧特效大小 eventData = self.CreateEventData() eventData['scale'] = self.radius self.BroadcastToAllClient( modConfig.SetSfxScaleEvent, eventData) # --------over---------- # 设置吸收半径(每次扩大为原半径大小的三倍;注意:原半径每次扩增1格) self.attract_radius = self.radius * 3 # 调用函数往存储位置坐标的list中添加新坐标,以便在tick中继续销毁方块创建掉落物 self.set_new_block_range_add( self.attract_radius, self.dict['x'], self.dict['y'], self.dict['z'])
def show_last_message(self, entity_id): """ 最后1秒倒计时后,展示 “黑洞正在吸收周围物品。。。” 信息 """ comp = serverApi.GetEngineCompFactory().CreateMsg(entity_id) comp.NotifyOneMessage(entity_id, "黑洞正在吸收周围物品...", "§4")
def OnServerItemUseOnEvent(self, args): """ ServerItemUseOnEvent 的回调函数 玩家在对方块使用物品之前服务端抛出的事件。注:如果需要取消物品的使用需要同时在ClientItemUseOnEvent和ServerItemUseOnEvent中将ret设置为True才能正确取消。 """ # 获取玩家物品,支持获取背包,盔甲栏,副手以及主手物品 comp = serverApi.GetEngineCompFactory().CreateItem(args['entityId']) item_dict = comp.GetPlayerItem( serverApi.GetMinecraftEnum().ItemPosType.CARRIED, 0) # 如果玩家手持物品为黑洞制造器,则进行相关操作 if item_dict['itemName'] == 'black_hole:black_hole_create': # 创建事件数据 evenData = self.CreateEventData() evenData["playerId"] = args["entityId"] evenData['x'] = args["x"] evenData['y'] = args["y"] evenData['z'] = args["z"] evenData['blockName'] = args['blockName'] # 将数据存入全局变量,供其他函数调用 self.dict['playerId'] = args["entityId"] self.dict['x'] = args["x"] self.dict['y'] = args["y"] self.dict['z'] = args["z"] self.dict['blockName'] = args['blockName'] # 取消两个定时器 if self.msg_timer and self.func_timer: comp = serverApi.GetEngineCompFactory().CreateGame( serverApi.GetLevelId()) comp.CancelTimer(self.func_timer) comp.CancelTimer(self.msg_timer) self.message_switch = False self.last_message_switch = False # ---------------------------------- 初始化数据 -------------------------------- # 恢复倒数时初始数据为10(避免二次创建黑洞,倒计时读数错误) self.test = 10 # 重新关闭tick执行的函数 self.flag = False # 将黑洞相关数据初始化 self.count = 0 # 用来计数销毁的实体 self.kill_count = 0 self.tick_count = 0 # 黑洞默认初始半径 = 3 self.radius = 3 # 黑洞初始吸收速度参数(此并非速度,而是控制速度的相关参数;通过控制移动向量大小以达到控制吸收速度的效果) self.speed_param = 200 # 吸收半径(注意: 最开始需要在此默认数值基础上再进行操作) # self.attract_radius = 18 self.attract_radius = self.radius * 3 # 存储待删除的坐标的list self.coordinate_list = [] self.time_count = 0 # 初始化扩增倍数 self.change_count = 1 # ---------------------------------- 初始化数据 -------------------------------- # 延时启动黑洞之前,通知客户端关闭吸引开关 # 防止之前创建过一次黑洞,再次创建黑洞并延时启动时,玩家会被之前黑洞继续吸引并杀死 # 广播事件,通知客户端关闭吸引开关 data = self.CreateEventData() data['ar'] = self.attract_radius # 随便传的事件数据 self.BroadcastToAllClient(modConfig.CloseAttractSwitchEvent, data) # 创建黑洞特效 # 广播CreateEffectEvent事件通知客户端创建特效 self.BroadcastToAllClient(modConfig.CreateEffectEvent, evenData) # 打开在tick中执行的函数开关,在聊天框显示倒计时,倒计时刷新速度1s一次,10s后执行功能并关闭消息提示 self.message_switch = True self.last_message_switch = True # 延时10秒启动黑洞的相关功能 comp = serverApi.GetEngineCompFactory().CreateGame( serverApi.GetLevelId()) self.func_timer = comp.AddTimer(11.0, self.block_hole_ready, args) # comp.AddTimer(1.0, self.block_hole_ready, args) # 测试用 # 延时到倒计时10秒结束后,打印黑洞正在吸收物品的提示信息 self.msg_timer = comp.AddTimer(12.0, self.last_message_func)