Files
rtdd/behavior_pack_v8jz0zSR/Script_NeteaseModousIY5aSF/BlueFoxTools/SpecialFunciton/BlueFoxRuckSackEngine.py
T

661 lines
26 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# coding=utf-8
from BlueFoxSystem import BlueFoxClientSystem
from ControllableUi.Animation import MoveToPos
from ..ItemTools import IsSameItem, GetItemBaseInfoSafely, GetItemDurabilityPercent, DeclareItemAnyNum, IsItemDict
from ..OtherTools import Mount, FixList
from ..ScreenTools import ScreenTools
from ..ToolsConfig import *
class SlotOffset(dict):
def __getitem__(self, item):
return super(SlotOffset, self).get(item, 0)
@Mount(BlueFoxClientSystem)
class RucksackScreen(baseScreen):
flyingItemRender = None
slotOffset = SlotOffset()
flyingMoveControl = None # type:MoveToPos
blueFoxClient = BlueFoxClientSystem if 0 else None
def __init__(self, name_spase, ui_key, param, items=None, customData=None, flyingPanelPath=None):
super(RucksackScreen, self).__init__(name_spase, ui_key, param)
self._selectSlot = -1
self.__itemNum = [] # 物品数量
self.__itemD = [] # (目前,总) 耐久度
self.__itemId = [] # 物品ID
self.__isItemNone = [] # 是否为缺失物品
self.flyingItem = {} # 跟随鼠标的物品
self.moveControls = []
self.exchangeLock = False
self.items = items # 所有物品
if self.items is None: self.items = [] # type:List[Dict]
self.customData = customData # 自定义数据
self.gridIndex = {}
self.flyingPanelPath = flyingPanelPath
self.offsetSlot = {}
self._selectSlot = -1
@property
def selectSlot(self):
return self._selectSlot
@selectSlot.setter
def selectSlot(self, index):
self._selectSlot = index
def GetStartAndFinalIndex(self, collectName):
"""
获取起止索引段
:param collectName:
:return:
"""
offsetKey = self.offsetSlot.keys()
offsetKey.sort()
offset = self.slotOffset[collectName]
if offset == offsetKey[-1]: return offset, len(self.items)
for index in range(len(offsetKey) - 1):
if offset == offsetKey[index]: return offset, offsetKey[index + 1]
def RecalculateOffsetSlot(self):
"""
重新计算OffsetSlot
:return:
"""
self.offsetSlot = {}
for _ in self.slotOffset.items(): self.offsetSlot[_[1]] = _[0]
def PrintSlotName(self):
offsetKey = self.offsetSlot.keys()
offsetKey.sort()
for _ in offsetKey:
print (_, self.offsetSlot[_])
print '--------------'
def AddSlot(self, slotName, gridPath, items, dim, refresh=True):
"""
增加槽位,需要在Create函数执行之前绑定所需的connectionName
:param slotName: 槽位名称
:param refresh: 是否刷新数据
:param gridPath: 网格路径
:param items: 物品集
:param dim: 网格尺寸
:return:
"""
if slotName in self.slotOffset: return
self.InitSlot(slotName, gridPath, items, dim)
self.InitItemData() if refresh else 0
def DelSlot(self, slotName, refresh=True):
"""
删除槽位,包括items,slotOffset,offsetSlot
:param slotName:槽位名称
:param refresh: 是否刷新数据
:return:
"""
if not slotName in self.slotOffset: return
offsetKey = self.offsetSlot.keys()
offsetKey.sort()
startAndEndIndex = self.GetStartAndFinalIndex(slotName)
oldOffset = startAndEndIndex[0]
size = startAndEndIndex[1] - startAndEndIndex[0]
del self.items[startAndEndIndex[0]: startAndEndIndex[1]]
del self.offsetSlot[oldOffset]
del self.slotOffset[slotName]
del self.gridIndex[slotName]
for index in offsetKey[::-1]:
if oldOffset < index: self.slotOffset[self.offsetSlot[index]] = index - size
self.RecalculateOffsetSlot()
self.InitItemData() if refresh else 0
# ------------------------------ init ------------------------------
def InitItemDataOne(self, slot, slotName, item):
"""
对某个槽位进行初始化,需要在InitData之后调用
"""
if item:
itemInfo = GetItemBaseInfoSafely(item)
self.__itemNum[slot] = item['count']
self.__itemId[slot] = itemInfo['id_aux']
self.__itemD[slot] = GetItemDurabilityPercent(item, itemInfo)
self.__isItemNone[slot] = False
else:
self.__itemNum[slot] = 0
self.__itemD[slot] = (0.0, 0.0)
self.__itemId[slot] = 0
self.__isItemNone[slot] = False
def InitItemData(self):
"""
依据当前items初始化显示所需的物品数据
:return:
"""
self.moveControls = [None for _ in self.items]
self.__itemNum = [0 for _ in self.items]
self.__itemD = [(0.0, 0.0) for _ in self.items]
self.__itemId = [0 for _ in self.items]
self.__isItemNone = [False for _ in self.items]
offsets = self.offsetSlot.keys()
offsets.sort()
for offsetIndex in range(len(offsets[:-1])):
for index in range(offsets[offsetIndex], offsets[offsetIndex + 1]):
if not IsItemDict(self.items[index]): self.items[index] = {}
self.InitItemDataOne(index, self.offsetSlot[offsets[offsetIndex]], self.items[index])
for index in range(offsets[-1], len(self.items)):
if not IsItemDict(self.items[index]): self.items[index] = {}
self.InitItemDataOne(index, self.offsetSlot[offsets[-1]], self.items[index])
def InitFlyingPanel(self, path):
self.flyingItemRender = self.GetBaseUIControl(path).asItemRenderer()
self.flyingMoveControl = MoveToPos(self.flyingItemRender, 0.1)
def InitSlot(self, slotName, gridPath, items, dimension):
"""
初始化物品槽
:param dimension: 物品槽网格的尺寸
:param items: 物品槽内的物品
:param slotName:物品槽名称
:param gridPath:物品槽的网格路径
:return:
"""
items = FixList(items, dimension[0] * dimension[1], {})
self.GetBaseUIControl(gridPath).asGrid().SetGridDimension(tuple(dimension))
self.gridIndex[slotName] = gridPath
offset = len(self.items)
self.slotOffset[slotName] = offset
self.offsetSlot[offset] = slotName
self.items += items
self.BindingAll(slotName)
# ------------------------------ init ------------------------------
def PlayerInvItemChanged(self, args):
"""
玩家背包服务端主动发生改变时触发
"""
self.SetUiVisibleInfo(args['item'], args['slot'])
def Create(self):
self.blueFoxClient.ListenForEvent(
MOD_NAME, 'BlueFoxServerSystem', 'PlayerInvItemChanged', self, self.PlayerInvItemChanged
)
def Destroy(self):
self.blueFoxClient.UnListenForEvent(
MOD_NAME, 'BlueFoxServerSystem', 'PlayerInvItemChanged', self, self.PlayerInvItemChanged
)
playerId = clientApi.GetLocalPlayerId()
x, y, z = clientCompFactory.CreatePos(playerId).GetFootPos()
rot = clientCompFactory.CreateRot(playerId).GetRot()
rx, ry, rz = clientApi.GetDirFromRot(rot)
self.blueFoxClient.NotifyToServer('RucksackScreenClosed', {
'posDim': (
(x + rx * 0.3, y + 1.08, z + rz * 0.3), clientCompFactory.CreateGame(LevelId).GetCurrentDimension()
), 'playerRot': rot
})
for moveControl in self.moveControls: moveControl.Finish() if moveControl else 0
def ItemCellGridInit(self, gridPath, collectionName):
"""
物品槽网格初始化时触发
:param gridPath:网格路径
:param collectionName:集合名称
:return:
"""
pass
def BindingAll(self, collectionName):
bindingFunc = ScreenTools.CollectionViewBinder
bindingBool = viewBinder.BF_BindBool
bindingInt = viewBinder.BF_BindInt
bindingFloat = viewBinder.BF_BindFloat
bindingString = viewBinder.BF_BindString
bindingFunc(bindingBool, collectionName, '#item_num_visible', self.ItemsNumVisible) # 是否显示物品数量文字
bindingFunc(bindingString, collectionName, '#item_num', self.ItemsNum) # 显示物品数量
bindingFunc(bindingBool, collectionName, '#select_visible', self.SelectVisible) # 是否显示物品槽选择
bindingFunc(bindingInt, collectionName, '#item_id_aux', self.RenderItems) # 显示物品
bindingFunc(bindingBool, collectionName, '#item_durability_visible', self.ItemsDurabilityVisible) # 是否显示物品耐久度条
bindingFunc(
bindingFloat, collectionName, '#item_durability_total_amount', self.ItemsDurabilityTotal
) # 物品耐久度条总量
bindingFunc(
bindingFloat, collectionName, '#item_durability_current_amount', self.ItemsDurabilityCurrent
) # 物品耐久度条当前量
bindingFunc(bindingBool, collectionName, '#item_none_visible', self.ItemsNone) # 是否显示缺失物品背景
bindingFunc(bindingBool, collectionName, '#item_cell_init', self.ItemCellInit) # 初始化时触发
# --------------------- bindings ---------------------
def GetGirdPath(self, collectionName):
return self.gridIndex[collectionName]
def ItemCellInit(self, collectionName, index):
"""
初始化时触发,无需任何返回值
:param collectionName:集合名称
:param index:在网格内的索引值
:return:
"""
if not index: self.ItemCellGridInit(self.GetGirdPath(collectionName), collectionName)
def ItemsNumVisible(self, collectionName, index):
index = index + self.slotOffset.get(collectionName, 0)
return self.__itemNum[index] > 1 if index < self.__itemNum.__len__() else False
def ItemsNum(self, collectionName, index):
index = index + self.slotOffset.get(collectionName, 0)
return str(self.__itemNum[index]) if index < self.__itemNum.__len__() else ''
def SelectVisible(self, collectionName, index):
index = index + self.slotOffset.get(collectionName, 0)
return index == self.selectSlot
def RenderItems(self, collectionName, index):
index = index + self.slotOffset.get(collectionName, 0)
return self.__itemId[index] if index < self.__itemId.__len__() else 0
def ItemsDurabilityVisible(self, collectionName, index):
index = index + self.slotOffset.get(collectionName, 0)
if index >= self.__itemD.__len__():
return False
info = self.__itemD[index]
return info[0] != info[1] and info[1] > 0
def ItemsDurabilityTotal(self, collectionName, index):
index = index + self.slotOffset.get(collectionName, 0)
return self.__itemD[index][1] if index < self.__itemD.__len__() else 0.0
def ItemsDurabilityCurrent(self, collectionName, index):
index = index + self.slotOffset.get(collectionName, 0)
return self.__itemD[index][0] if index < self.__itemD.__len__() else 0.0
def ItemsNone(self, collectionName, index):
index = index + self.slotOffset.get(collectionName, 0)
return self.__isItemNone[index] if index < self.__isItemNone.__len__() else False
# --------------------- bindings ---------------------
def SetNoneItem(self, slot, itemDict):
"""
将某个槽位设置为缺少物品
:param slot:
:param itemDict:
:return:
"""
itemInfo = GetItemBaseInfoSafely(itemDict)
self.__itemNum[slot] = itemDict['count']
self.__itemD[slot] = GetItemDurabilityPercent(itemDict, itemInfo)
self.__itemId[slot] = itemInfo['id_aux']
self.__isItemNone[slot] = True
self.items[slot] = {}
def NoticeServerChangeItem(self, slot, itemDict, itemOperate):
self.blueFoxClient.NotifyToServer(
'ChangeItem', {
'slot': slot, 'item': itemDict, 'itemOperate': itemOperate,
'posDim': None, 'posType': self.GetOffsetNameByIndex(slot),
'startSlot': self.GetOffsetStartIndex(slot)
}
)
def NoticeServerSpawnItemEntities(self, itemDict):
playerId = clientApi.GetLocalPlayerId()
x, y, z = clientCompFactory.CreatePos(playerId).GetFootPos()
self.blueFoxClient.NotifyToServer("SpawnItemEntity", {
'posDim': (
(x, y + 1.6, z), clientCompFactory.CreateGame(LevelId).GetCurrentDimension()
), 'item': itemDict,
'playerRot': clientCompFactory.CreateRot(playerId).GetRot()
})
def SetItem(self, slot, itemDict=None, noticeServer=True):
"""
设置某个槽位, 不论是否物品为空, 返回原本物品
:param noticeServer:
:param itemDict:
:param slot:
:return:
"""
return self.SetUiItem(slot, itemDict, noticeServer) if itemDict else self.SetUiItemNone(slot, noticeServer)
def SetItemAbs(self, slot, itemDict=None, noticeServer=False):
"""
设置某个槽位, 不论是否物品为空
:param noticeServer:
:param itemDict:
:param slot:
:return:
"""
self.SetUiItemAbs(slot, itemDict, noticeServer) if itemDict else self.SetUiItemNone(slot, noticeServer)
def SetUiItemNone(self, slot, noticeServer=None):
"""
将某个槽位设置为空,返回原本物品
:param noticeServer:
:param slot:
:return:
"""
originItem = self.items[slot]
self.SetUiItemAbs(slot, {}, noticeServer)
return originItem
def SetUiItemAbs(self, slot, destinationItem, noticeServer=True, itemOperate=None):
"""
设置某一个槽位的物品, 不返回任何物品及合并
:param itemOperate: 物品操作,用于服务端操作
:param noticeServer: 是否通知服务端,默认发送
:param slot:设置槽位
:param destinationItem:目标物品字典
:return:
"""
destinationItemInfo = GetItemBaseInfoSafely(destinationItem)
self.__itemNum[slot] = destinationItem.get('count', 0)
self.__itemD[slot] = GetItemDurabilityPercent(destinationItem, destinationItemInfo)
self.__itemId[slot] = destinationItemInfo.get('id_aux', 0)
self.__isItemNone[slot] = False
self.items[slot] = destinationItem
self.NoticeServerChangeItem(slot, destinationItem, itemOperate) if noticeServer else 0
def SetUiItem(self, slot, destinationItem, noticeServer=True):
"""
设置某一个槽位的物品,返回原本物品如果不可合并或者合并后多出的物品
:param noticeServer: 是否通知服务端
:param slot:设置槽位
:param destinationItem:目标物品字典
:return:
"""
originItem = self.items[slot]
originItemInfo = GetItemBaseInfoSafely(destinationItem)
if IsSameItem(originItem, destinationItem):
if originItem['count'] + destinationItem['count'] <= originItemInfo['maxStackSize']:
destinationItem['count'] += originItem['count']
originItem = {}
else:
originItem['count'] += destinationItem['count'] - originItemInfo['maxStackSize']
destinationItem['count'] = originItemInfo['maxStackSize']
self.SetUiItemAbs(slot, destinationItem, noticeServer)
return originItem
def SetUiVisibleInfo(self, itemDict, slot):
"""
设置物品,通常用于服务端主动设置物品,此接口不会发送ChangeItem事件
:param itemDict:物品信息字典
:param slot:设置槽位
:return:
"""
self.SetUiItemAbs(slot, itemDict, False)
def GetOffsetNameByIndex(self, index):
"""
通过index获取偏移名称
:param index:
:return:
"""
offsetKey = self.offsetSlot.keys()
offsetKey.sort()
offset = offsetKey[-1]
for _ in range(offsetKey.__len__() - 1):
if offsetKey[_] <= index < offsetKey[_ + 1]:
return self.offsetSlot[offsetKey[_]]
return self.offsetSlot[offset]
def GetOffsetStartIndex(self, index):
"""
通过index获取偏移起始index
:param index:
:return:
"""
offsetKey = self.offsetSlot.keys()
offsetKey.sort()
offset = offsetKey[-1]
for _ in range(offsetKey.__len__() - 1):
if offsetKey[_] <= index < offsetKey[_ + 1]:
return offsetKey[_]
return offsetKey[-1]
def GetItemCellByIndex(self, index):
"""
通过槽位获取itemCell的路径
:param index:槽位编号
:return:
"""
offset = self.GetOffsetStartIndex(index)
return self.gridIndex[self.offsetSlot[offset]] + '/item_cell{}'.format(index - offset + 1)
# 以下三个方法是pe背包槽位交互模式
def FlyingMoveFinish(self, slot):
"""
pe下槽位发生物品堆叠时, flyRender动画完成时触发
:return:
"""
self.flyingItemRender.SetVisible(False) if self.flyingItemRender else 0
self.NoticeServerChangeItem(
slot, self.flyingItem,
ItemOperate.ExchangeFlying(
slot - self.GetOffsetStartIndex(slot), self.GetOffsetNameByIndex(slot)
)
)
self.flyingItem = {}
def ExchangeFinish(self, slot, destinationSlot):
"""
pe下槽位发生物品交换时, 动画完成时触发
:param destinationSlot: 与其交换的槽位
:param slot: 槽位
:return:
"""
deSlotName = self.GetOffsetNameByIndex(destinationSlot)
deSlotOffset = destinationSlot - self.GetOffsetStartIndex(destinationSlot)
fromSlotName = self.GetOffsetNameByIndex(slot)
fromSlotOffset = slot - self.GetOffsetStartIndex(slot)
originItem = self.items[slot]
destinationItem = self.items[destinationSlot]
self.SetUiItemAbs(slot, destinationItem, False)
deSlot = self.slotOffset[deSlotName] + deSlotOffset
if deSlotName not in self.slotOffset or deSlot >= len(self.items):
self.flyingItem = originItem
else:
self.SetUiItemAbs(deSlot, originItem, False)
self.NoticeServerChangeItem(slot, {}, ItemOperate.Exchange(
fromSlotOffset, fromSlotName,
deSlotOffset, deSlotName
))
self.flyingItem = {}
def StackFinish(self, slot, destinationSlot):
"""
pe下槽位发生物品堆叠时, slot动画完成时触发
:param slot: 槽位
:param destinationSlot: 与其交换的槽位
:return:
"""
orSlotName = self.GetOffsetNameByIndex(slot)
orSlotOffset = slot - self.GetOffsetStartIndex(slot)
deSlotName = self.GetOffsetNameByIndex(destinationSlot)
deSlotOffset = destinationSlot - self.GetOffsetStartIndex(destinationSlot)
self.flyingItem = self.SetItem(destinationSlot, self.items[slot], False)
orSlot = self.slotOffset[orSlotName] + orSlotOffset
if orSlotName not in self.slotOffset or orSlot >= len(self.items):
self.flyingItem = {}
else:
self.SetItemAbs(slot, self.flyingItem, False)
self.flyingItem = {}
self.flyingItemRender.SetVisible(False, False) if self.flyingItemRender else 0
self.NoticeServerChangeItem(slot, {}, ItemOperate.Merge(
orSlotOffset, orSlotName, deSlotOffset, deSlotName
))
@staticmethod
def SetUiItemForItemRender(render, itemDict):
"""
使用itemDict设置物品渲染
:param render:itemRender
:param itemDict:需要设置的物品字典
:return:
"""
if not itemDict:
render.SetVisible(False)
return
render.SetUiItem(
itemDict.get('newItemName', 'minecraft:air'), itemDict.get('newAuxValue', 0),
(itemDict.get('enchantData', []) + itemDict.get('modEnchantData', [])).__len__() > 0,
itemDict.get('userData', None)
)
def PcDown(self, selectSlot):
"""
电脑点击物品槽触发
:param selectSlot:槽位
:return:
"""
oldItem = self.items[selectSlot]
if self.flyingItem is None: self.flyingItem = {}
self.SetUiItemAbs(
selectSlot, self.flyingItem, True,
ItemOperate.ExchangeFlying(
selectSlot - self.GetOffsetStartIndex(selectSlot), self.GetOffsetNameByIndex(selectSlot)
)
)
self.flyingItem = oldItem
if self.flyingItemRender:
self.SetUiItemForItemRender(
self.flyingItemRender, self.flyingItem
) if self.flyingItem else self.flyingItemRender.SetVisible(False, False)
def GetSlotAnimationState(self, originSlot, destinationSlot):
"""
pe模式下, 交换物品时根据槽位确认动画形式
:param originSlot:先前选择槽位
:param destinationSlot:后选择槽位
:return:先前, 后选择, flyingItem
"""
originItem = self.items[originSlot]
destinationItem = self.items[destinationSlot]
itemInfo = GetItemBaseInfoSafely(originItem)
if IsSameItem(originItem, destinationItem):
if originItem['count'] + destinationItem['count'] < itemInfo['maxStackSize']:
return True, False, False
elif destinationItem['count'] == itemInfo['maxStackSize']:
return True, True, False
else:
return False, False, True
return True, True, False
def GetPeFlyingItem(self, originSlot, destinationSlot):
"""
在pe模式下, 获取flyingItem
:param originSlot: 现物品槽位
:param destinationSlot: 目标物品槽位
:return:
"""
itemInfo = GetItemBaseInfoSafely(self.items[originSlot])
maxStack = (itemInfo or {}).get('maxStackSize') or 64
itemDict1, itemDict2 = DeclareItemAnyNum(
self.items[originSlot], maxStack - self.items[destinationSlot]['count'])
self.SetItemAbs(originSlot, itemDict1)
return itemDict2
def DeliverItem(self, originSlot, destinationSlot):
"""
以动画形式从origin向destination传递物品
:param originSlot:起源物品槽位
:param destinationSlot:目标物品槽位
:return:
"""
ox, oy = self.GetAbsPos(self.GetItemCellByIndex(originSlot) + '/item_cell/item_renderer')
dx, dy = self.GetAbsPos(self.GetItemCellByIndex(destinationSlot) + '/item_cell/item_renderer')
_, __, ___ = self.GetSlotAnimationState(originSlot, destinationSlot)
if _:
self.moveControls[originSlot].StartMove(
(dx - ox, dy - oy), self.ExchangeFinish if __ else self.StackFinish, originSlot, destinationSlot
)
if __:
self.moveControls[destinationSlot].StartMove(
(-dx + ox, -dy + oy), lambda: None
)
if ___:
self.SetUiItemForItemRender(self.flyingItemRender, self.items[originSlot]) if self.flyingItemRender else 0
self.flyingItemRender.SetVisible(True) if self.flyingItemRender else 0
self.flyingMoveControl.ResetInitialPos((ox, oy))
self.flyingMoveControl.StartMove(
(dx, dy), self.StackFinish, originSlot, destinationSlot
)
def PeDown(self, selectSlot):
"""
手机点击物品槽触发
:param selectSlot:槽位
:return:
"""
if self.selectSlot == selectSlot:
self.selectSlot = -1
return
else:
if self.selectSlot is not -1:
if self.items[self.selectSlot]:
self.DeliverItem(self.selectSlot, selectSlot)
self.selectSlot = -1
return
if self.items[selectSlot]:
self.selectSlot = selectSlot
self.flyingItemRender.SetPosition(
self.GetAbsPos(self.GetItemCellByIndex(selectSlot) + '/item_cell/item_renderer')
) if self.flyingItemRender else 0
self.flyingMoveControl.ResetInitialPos()
@viewBinder.binding(viewBinder.BF_ButtonClickUp, '#item_cell_touch')
def ButtonUp(self, args):
"""
物品槽被点击会触发无论电脑或者手机
:param args:与普通的按钮回调参数一致
:return:
"""
touchIndex = args['#collection_index'] + self.slotOffset.get(args['#collection_name'], 0)
self.CreateItemRenderMoveControl(touchIndex)
self.PeDown(touchIndex) if Platform else self.PcDown(touchIndex)
def CreateItemRenderMoveControl(self, slot):
"""
创建物品渲染的移动动画控制器
:param slot:
:return:
"""
if self.moveControls[slot] is None:
itemCell = self.GetBaseUIControl(self.GetItemCellByIndex(slot))
self.moveControls[slot] = MoveToPos(
itemCell.GetChildByName('item_cell').GetChildByName('item_renderer'), 0.1
)
def GetAbsPos(self, path):
"""
获取元素的绝对坐标
:param path:路径
:return:绝对坐标, xy
"""
control = self.GetBaseUIControl(path)
return control.GetGlobalPosition() if control else (0, 0)
@viewBinder.binding(viewBinder.BF_BindInt, '#main.gametick')
def GameTick(self):
if clientCompFactory and not Platform and self.flyingItemRender and self.flyingItem:
x, y = clientCompFactory.CreateActorMotion(clientApi.GetLocalPlayerId()).GetMousePosition()
self.flyingItemRender.SetPosition((x - 9, y - 9))
self.flyingItemRender.SetVisible(self.flyingItem, False)
for moveControl in self.moveControls:
moveControl.Refresh() if moveControl else 0
self.flyingMoveControl.Refresh() if self.flyingMoveControl else 0
def CreateItemEntityIfFlyItem(self):
"""
创建跟随鼠标的物品
:return:
"""
if self.flyingItem: self.NoticeServerSpawnItemEntities(self.flyingItem)