862 lines
32 KiB
Lua
862 lines
32 KiB
Lua
|
---@class BP_BuffManager_C:AActor
|
|||
|
---@field DefaultSceneRoot USceneComponent
|
|||
|
--Edit Below--
|
|||
|
---@type BP_BuffManager_C-
|
|||
|
|
|||
|
--require("Script.Blueprint.BUFF.BuffConfig")
|
|||
|
|
|||
|
BP_BuffManager = {
|
|||
|
--- BuffActiveList最后一次获取的ID
|
|||
|
BuffID = 1;
|
|||
|
--- 已require且Check成功后的Buff {BuffType = BuffInst, ...}
|
|||
|
BuffInsts = {};
|
|||
|
--- 已激活的Buff {BuffID = {PlayerKey = uint32, BuffType = BuffConfig.EBuffType, BuffArgs = {...}, ActiveTime = float}}}
|
|||
|
BuffActiveList = {};
|
|||
|
--- 拥有Tick函数的BuffInst {BuffType, ...}
|
|||
|
BuffInstWithTick = {};
|
|||
|
--- 玩家死亡自动清除Buff缓存
|
|||
|
bAutoClearPlayerBuffCache = true;
|
|||
|
--- 已绑定玩家死亡后清除函数的PlayerPawn {PlayerKey = uint32, ... }
|
|||
|
BoundPlayerDeath = {};
|
|||
|
--- 延迟移除Buff的Handle, 用于自动移除及修改Buff存在时间 {BuffID = {Handle = TimeHandle, Duration = float, EnablingTime = float), }
|
|||
|
BuffDurationHandles = {};
|
|||
|
|
|||
|
---缓存的 BuffType 数据
|
|||
|
---@type table<EBuffType, table<int32, AActor>>
|
|||
|
CachedInit = {};
|
|||
|
|
|||
|
-- 当前受到反馈的玩家 Key 的回调
|
|||
|
BenefitCallback = nil;
|
|||
|
};
|
|||
|
|
|||
|
function BP_BuffManager:GetReplicatedProperties()
|
|||
|
return
|
|||
|
"BuffInstWithTick"
|
|||
|
--, { "CachedInit", "Lazy" }
|
|||
|
end
|
|||
|
|
|||
|
--- Buff回调函数枚举
|
|||
|
BP_BuffManager.ECallBack = {
|
|||
|
---@param BuffTag any Buff的标签
|
|||
|
---@param PlayerKey uint32
|
|||
|
---@param BuffType uint32
|
|||
|
---@param BuffID uint32
|
|||
|
AddBuff = "CallBackAddBuff",
|
|||
|
---@param PlayerKey uint32
|
|||
|
---@param BuffType uint32
|
|||
|
---@param BuffID uint32
|
|||
|
RemoveBuff = "CallBackRemoveBuff",
|
|||
|
---@param PlayerKey uint32
|
|||
|
---@param BuffID uint32
|
|||
|
---@param Duration float
|
|||
|
---@param EnablingTime float
|
|||
|
---@param SendTime float
|
|||
|
BuffDurationUpdate = "CallBackBuffDurationUpdate",
|
|||
|
---@param BuffID uint32
|
|||
|
RemoveBuffDuration = "RemoveBuffDuration",
|
|||
|
---@param PlayerKey uint32
|
|||
|
ClearPlayerBuffCache = "ClearPlayerBuffCache",
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
--- 函数返回值枚举
|
|||
|
BP_BuffManager.EResult = {
|
|||
|
--- 成功
|
|||
|
Succeed = "Succeed";
|
|||
|
--- require 错误
|
|||
|
RequireError = "RequireError";
|
|||
|
--- Pawn无效
|
|||
|
PlayerPawnNotValid = "PlayerPawnNotValid";
|
|||
|
--- BuffID失效
|
|||
|
BuffIDIsNotValid = "BuffIDIsNotValid";
|
|||
|
--- BuffAction的ApplyBuff函数返回false,调用失败
|
|||
|
ApplyBuffFailure = "ApplyBuffFailure";
|
|||
|
--- 没有给Buff设置持续时间
|
|||
|
NotSetBuffDuration = "NotSetBuffDuration";
|
|||
|
--- BuffID与玩家PlayerKey不匹配
|
|||
|
BuffIDMismatch = "BuffIDMismatch";
|
|||
|
}
|
|||
|
|
|||
|
--- Buff检测枚举
|
|||
|
BP_BuffManager.ECheck = {
|
|||
|
--- Warn 应弹出警告
|
|||
|
Warn = 1;
|
|||
|
--- Error Buff无法使用执行
|
|||
|
Error = 2;
|
|||
|
}
|
|||
|
|
|||
|
--- BuffInst 检测表
|
|||
|
BP_BuffManager.CheckBuffInst = {
|
|||
|
--- 使用Buff ApplyBuff:function(ValidPawn:BP_PlayerPawn_C*, ...) --->ApplySucceed:bool
|
|||
|
["ApplyBuff"] = {type = "function", CheckType = BP_BuffManager.ECheck.Error};
|
|||
|
--- 移除Buff RemoveBuff:function(ValidPawn:BP_PlayerPawn_C*, ...)
|
|||
|
["RemoveBuff"] = {type = "function", CheckType = BP_BuffManager.ECheck.Warn};
|
|||
|
--- Tick函数 Tick:function(DeltaTime float)
|
|||
|
["Tick"] = {type = "function", CheckType = BP_BuffManager.ECheck.Warn};
|
|||
|
--- Buff描述 BuffDesc string
|
|||
|
["BuffDesc"] = {type = "string" , CheckType = BP_BuffManager.ECheck.Warn};
|
|||
|
--- Buff默认颜色 BuffColor table
|
|||
|
["BuffColor"] = {type = "table" , CheckType = BP_BuffManager.ECheck.Warn};
|
|||
|
--- Buff默认Icon路径 BuffIconPath string
|
|||
|
["BuffIconPath"] = {type = "string" , CheckType = BP_BuffManager.ECheck.Warn};
|
|||
|
--- Buff默认粒子路径 BuffParticlePath string
|
|||
|
["BuffParticlePath"] = {type = "string" , CheckType = BP_BuffManager.ECheck.Warn};
|
|||
|
--- 玩家死亡,回调,用于清除BuffAction实例中的PlayerKey缓存 PlayerDeathCallBack:function(PlayerKey uint32)
|
|||
|
["PlayerDeathCallBack"] = {type = "function", CheckType = BP_BuffManager.ECheck.Warn}
|
|||
|
}
|
|||
|
--- BuffManager单例
|
|||
|
BP_BuffManager.ManagerInst = nil
|
|||
|
|
|||
|
|
|||
|
|
|||
|
--- 获取单例BP_BuffManager
|
|||
|
--- 若BP_BuffManager为nil则SpawnActor,但是Spawn后需要隔帧调用,否则可能出现无法添加成功的情况
|
|||
|
---@return BP_BuffManager
|
|||
|
function BP_BuffManager.GetBuffManager()
|
|||
|
if BP_BuffManager.ManagerInst == nil then
|
|||
|
local AllBuffManager = GameplayStatics.GetAllActorsOfClass(UGCGameSystem.GameState, BP_BuffManager.GetManagerClass(), {})
|
|||
|
for k, v in pairs(AllBuffManager) do
|
|||
|
BP_BuffManager.ManagerInst = v
|
|||
|
break
|
|||
|
end
|
|||
|
if BP_BuffManager.ManagerInst == nil then
|
|||
|
BP_BuffManager.ManagerInst = UGCGameSystem.SpawnActor(UGCGameSystem.GameState, BP_BuffManager.GetManagerClass(), VectorHelper.VectorZero(), VectorHelper.RotZero(), VectorHelper.ScaleOne())
|
|||
|
--- BP_BuffManager.ManagerInst = ScriptGameplayStatics.SpawnActor(UGCGameSystem.GameState, BP_BuffManager.GetManagerClass(), VectorHelper.VectorZero(), VectorHelper.RotZero(), VectorHelper.ScaleOne());
|
|||
|
end
|
|||
|
end
|
|||
|
return BP_BuffManager.ManagerInst
|
|||
|
end
|
|||
|
|
|||
|
|
|||
|
--- 通过Require路径获取Buff文件名
|
|||
|
---@param requirePath string
|
|||
|
function BP_BuffManager.GetBuffFileNameFromBuffRequirePath(requirePath)
|
|||
|
local segments = {}
|
|||
|
for segment in requirePath:gmatch("[^%.]+") do
|
|||
|
table.insert(segments, segment)
|
|||
|
end
|
|||
|
|
|||
|
local fileName = segments[#segments]
|
|||
|
local fileNameWithoutExtension = fileName:match("(.+)%..+$") or fileName --- 去除后缀
|
|||
|
return fileNameWithoutExtension
|
|||
|
end
|
|||
|
|
|||
|
--- 获取BuffAction文件名(不含后缀),在BuffAction中调用
|
|||
|
function BP_BuffManager.GetBuffFileName()
|
|||
|
local info = debug.getinfo(2, "S")
|
|||
|
local filePath = info.source:sub(2)
|
|||
|
local fileName = filePath:match("^.+/(.+)$") or filePath:match("^.+\\(.+)$") --- 提取文件名部分
|
|||
|
local fileNameWithoutExtension = fileName:match("(.+)%..+$") or fileName --- 去除后缀
|
|||
|
return fileNameWithoutExtension
|
|||
|
end
|
|||
|
|
|||
|
--- 获取BP_BuffManager Class
|
|||
|
function BP_BuffManager.GetManagerClass()
|
|||
|
if BP_BuffManager.ManagerClass == nil then
|
|||
|
BP_BuffManager.ManagerClass = UE.LoadClass(UGCGameSystem.GetUGCResourcesFullPath('Asset/Blueprint/BUFF/BP_BuffManager.BP_BuffManager_C'))
|
|||
|
end
|
|||
|
return BP_BuffManager.ManagerClass
|
|||
|
end
|
|||
|
|
|||
|
function BP_BuffManager.SendBuffEvent(CallBackType, ...)
|
|||
|
UGCEventSystem.SendEvent(CallBackType, ...)
|
|||
|
UGCSendRPCSystem.RPCEvent(nil, CallBackType, ...)
|
|||
|
end
|
|||
|
|
|||
|
|
|||
|
--- 获取唯一BuffID
|
|||
|
---@return number
|
|||
|
function BP_BuffManager:GetNewBuffID()
|
|||
|
if self.BuffActiveList[self.BuffID] == nil then
|
|||
|
return self.BuffID
|
|||
|
end
|
|||
|
while self.BuffActiveList[self.BuffID] ~= nil or self.BuffID == 0 do
|
|||
|
self.BuffID = self.BuffID + 1
|
|||
|
end
|
|||
|
return self.BuffID
|
|||
|
end
|
|||
|
|
|||
|
function BP_BuffManager:ReceiveBeginPlay()
|
|||
|
|
|||
|
end
|
|||
|
|
|||
|
function BP_BuffManager:Init(InCb)
|
|||
|
-- 执行一下
|
|||
|
UGCLogSystem.Log("[BP_BuffManager:Init] 执行")
|
|||
|
for BuffType, Item in pairs(BuffConfig.BuffActionInfo) do
|
|||
|
if Item.EnableInit == true then
|
|||
|
-- 找到对应的 BuffInit
|
|||
|
local InitStr = string.gsub(Item.Path, "Action", "Init")
|
|||
|
local Init = require(InitStr);
|
|||
|
if Init ~= nil then
|
|||
|
UGCLogSystem.Log("[BP_BuffManager.Init] BuffType = %s", tostring(BuffType))
|
|||
|
Init:Init(BuffType);
|
|||
|
end
|
|||
|
end
|
|||
|
end
|
|||
|
|
|||
|
if InCb ~= nil then
|
|||
|
UGCLogSystem.Log("[BP_BuffManager:Init] 开始执行, Callback = %s", tostring(InCb));
|
|||
|
self.BenefitCallback = InCb;
|
|||
|
end
|
|||
|
end
|
|||
|
|
|||
|
-------------------------------------------- Apply Buff --------------------------------------------
|
|||
|
|
|||
|
--- 给玩家施加Buff
|
|||
|
---@param BuffTag any Buff的标签
|
|||
|
---@param PlayerKey uint32
|
|||
|
---@param BuffType EBuffType
|
|||
|
---@tparam ... any Buff所需要的参数
|
|||
|
---@vararg any
|
|||
|
---@return string,int BP_BuffManager.EResult, BuffID
|
|||
|
function BP_BuffManager:AddBuff(BuffTag, PlayerKey, BuffType, ...)
|
|||
|
UGCLogSystem.Log("[BP_BuffManager_AddBuff] BuffType:%s", tostring(BuffType))
|
|||
|
--- 判断PlayerKey
|
|||
|
local TargetPawnIsValid, TargetPawn = self:CheckPlayerKey(PlayerKey)
|
|||
|
if not TargetPawnIsValid then
|
|||
|
return BP_BuffManager.EResult.PlayerPawnNotValid
|
|||
|
end
|
|||
|
|
|||
|
return self:AddBuffFromPlayerPawn(BuffTag, TargetPawn, BuffType, ...)
|
|||
|
end
|
|||
|
|
|||
|
function BP_BuffManager:AddBuffFromPlayerPawn(BuffTag, TargetPawn, BuffType, ...)
|
|||
|
if not UE.IsValid(TargetPawn) then
|
|||
|
return BP_BuffManager.EResult.PlayerPawnNotValid
|
|||
|
end
|
|||
|
local PlayerKey = TargetPawn.PlayerKey
|
|||
|
local BuffID = self:GetNewBuffID()
|
|||
|
local BuffArgs = {...}
|
|||
|
|
|||
|
--- 检测Require Buff
|
|||
|
local BuffInst = self:RequireBuffAction(BuffType)
|
|||
|
if BuffInst == nil then
|
|||
|
return BP_BuffManager.EResult.RequireError
|
|||
|
end
|
|||
|
|
|||
|
if BuffInst['SetBuffType'] ~= nil and type(BuffInst['SetBuffType']) == 'function' then
|
|||
|
BuffInst['SetBuffType'](BuffInst, BuffType);
|
|||
|
end
|
|||
|
|
|||
|
--- Buff使用失败则返回
|
|||
|
local Table = {...};
|
|||
|
if not BuffInst:ApplyBuff(BuffTag, TargetPawn, ...) then
|
|||
|
return BP_BuffManager.EResult.ApplyBuffFailure
|
|||
|
end
|
|||
|
|
|||
|
local Players = BuffInst:GetBenefitPlayer();
|
|||
|
|
|||
|
if self.BenefitCallback ~= nil then
|
|||
|
self.BenefitCallback(TargetPawn.PlayerKey, Players, BuffType);
|
|||
|
end
|
|||
|
|
|||
|
--- 判断Buff是否需要Remove,不需要则不加入缓存列表
|
|||
|
local bBuffHasRemoveFunc, _ = self:CheckBuffInstRemoveBuffFunc(BuffInst)
|
|||
|
if bBuffHasRemoveFunc then
|
|||
|
self.BuffActiveList[BuffID] = {BuffTag = BuffTag, PlayerKey = PlayerKey, BuffType = BuffType, BuffArgs = BuffArgs, ActiveTime = BP_BuffManager.GetNowTime()}
|
|||
|
else
|
|||
|
BuffID = nil
|
|||
|
end
|
|||
|
|
|||
|
self:SpawnParticleToPlayPawn(TargetPawn.PlayerKey, Players, BuffType, true);
|
|||
|
|
|||
|
if not table.hasValue(self.BoundPlayerDeath, PlayerKey) then
|
|||
|
self.BoundPlayerDeath[#self.BoundPlayerDeath + 1] = PlayerKey
|
|||
|
self:BindPlayerDeath(TargetPawn)
|
|||
|
end
|
|||
|
|
|||
|
BP_BuffManager.SendBuffEvent(BP_BuffManager.ECallBack.AddBuff, BuffTag, PlayerKey, BuffType, BuffID)
|
|||
|
return BP_BuffManager.EResult.Succeed, BuffID
|
|||
|
end
|
|||
|
|
|||
|
--- 开启自动清除死亡玩家的Buff缓存
|
|||
|
---@param Enable:bool
|
|||
|
function BP_BuffManager:SetAutoClearPlayerBuffCache(Enable)
|
|||
|
if Enable ~= false or Enable ~= nil then
|
|||
|
self.bAutoClearPlayerBuffCache = true
|
|||
|
end
|
|||
|
self.bAutoClearPlayerBuffCache = false
|
|||
|
end
|
|||
|
|
|||
|
--- 绑定玩家死亡清除函数
|
|||
|
---@param ValidPawn:BP_PlayerPawn_C
|
|||
|
function BP_BuffManager:BindPlayerDeath(ValidPawn)
|
|||
|
if self.bAutoClearPlayerBuffCache then
|
|||
|
ValidPawn.OnDeath:Add(self.PlayerDeath, self)
|
|||
|
end
|
|||
|
end
|
|||
|
|
|||
|
|
|||
|
---@param DeadCharacter:ASTExtraCharacter
|
|||
|
---@param Killer:AController
|
|||
|
---@param DamageCauser:AActor
|
|||
|
---@param KillingHitInfo:FHitResult
|
|||
|
---@param KillingHitImpulseDir:FVector
|
|||
|
---@param KillingHitDamageTypeID int32
|
|||
|
---@param DamageTypeClass:USTExtraDamageType
|
|||
|
---@param IsHeadShotDamage:bool
|
|||
|
function BP_BuffManager:PlayerDeath(DeadCharacter, Killer, DamageCauser, KillingHitInfo, KillingHitImpulseDir, KillingHitDamageTypeID, DamageTypeClass, IsHeadShotDamage)
|
|||
|
local DeadPlayerKey = DeadCharacter.PlayerKey
|
|||
|
UGCLogSystem.Log("[BP_BuffManager_PlayerDeath] DeadPlayerKey:%s", tostring(DeadPlayerKey))
|
|||
|
|
|||
|
if table.hasValue(self.BoundPlayerDeath, DeadPlayerKey) then
|
|||
|
-- local OwnedBuffIDs = self:GetPlayerOwnedBuffs(DeadPlayerKey)
|
|||
|
local OwnedBuffIDs = BP_BuffManager.BuffFilter(DeadPlayerKey)
|
|||
|
local InstDoOnceCallBackFunc = {}
|
|||
|
for _, BuffID in pairs(OwnedBuffIDs) do
|
|||
|
local BuffType = self.BuffActiveList[BuffID].BuffType
|
|||
|
local BuffInst = self:RequireBuffAction(BuffType)
|
|||
|
if not table.hasValue(InstDoOnceCallBackFunc, BuffInst) then
|
|||
|
InstDoOnceCallBackFunc[#InstDoOnceCallBackFunc] = BuffInst
|
|||
|
if self:IndividualCheckPlayerDeathCallBackFunc(BuffInst) then
|
|||
|
BuffInst:PlayerDeathCallBack(DeadPlayerKey)
|
|||
|
end
|
|||
|
end
|
|||
|
end
|
|||
|
end
|
|||
|
table.removeValue(self.BoundPlayerDeath, DeadPlayerKey, true)
|
|||
|
self:ClearPlayerBuffCache(DeadPlayerKey)
|
|||
|
UGCLogSystem.Log("[BP_BuffManager_PlayerDeath] Finish")
|
|||
|
end
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
--- 设置Buff持续时间
|
|||
|
---@param BuffID int32
|
|||
|
---@param Duration float Duration <= 0 时,直接移除Buff
|
|||
|
---@return int32 EResult
|
|||
|
function BP_BuffManager:SetBuffDuration(BuffID, Duration)
|
|||
|
if not self:CheckBuffID(BuffID) then
|
|||
|
return BP_BuffManager.EResult.BuffIDIsNotValid
|
|||
|
end
|
|||
|
|
|||
|
self:RemoveBuffDuration(BuffID)
|
|||
|
---
|
|||
|
if Duration <= 0 then
|
|||
|
self:RemoveBuffFromBuffID(BuffID)
|
|||
|
return BP_BuffManager.EResult.Succeed
|
|||
|
end
|
|||
|
|
|||
|
local DurationHandle= UGCEventSystem.SetTimer(self, function ()
|
|||
|
self:RemoveBuffFromBuffID(BuffID)
|
|||
|
end, Duration);
|
|||
|
|
|||
|
local NowTime = BP_BuffManager.GetNowTime()
|
|||
|
self.BuffDurationHandles[BuffID] = {Handle = DurationHandle, Duration = Duration, EnablingTime = NowTime}
|
|||
|
BP_BuffManager.SendBuffEvent(BP_BuffManager.ECallBack.BuffDurationUpdate, BP_BuffManager.GetPlayerKeyOfTheBuffID(BuffID), BuffID, Duration, NowTime, NowTime)
|
|||
|
|
|||
|
return BP_BuffManager.EResult.Succeed
|
|||
|
end
|
|||
|
|
|||
|
|
|||
|
--- 添加Buff持续时间
|
|||
|
---@param BuffID int32
|
|||
|
---@param AddDuration float 可以为负值
|
|||
|
---@return int32 EResult
|
|||
|
function BP_BuffManager:AddBuffDuration(BuffID, AddDuration)
|
|||
|
if not self:CheckBuffID(BuffID) then
|
|||
|
return BP_BuffManager.EResult.BuffIDIsNotValid
|
|||
|
end
|
|||
|
|
|||
|
log_tree("[BP_BuffManager_AddBuffDuration] 1", self.BuffDurationHandles)
|
|||
|
|
|||
|
--- BuffID未添加持续时间,自动为其添加
|
|||
|
if self.BuffDurationHandles[BuffID] == nil then
|
|||
|
return self:SetBuffDuration(BuffID, AddDuration)
|
|||
|
end
|
|||
|
|
|||
|
UGCEventSystem.StopTimer(self.BuffDurationHandles[BuffID].Handle)
|
|||
|
local NewDuration = AddDuration + self.BuffDurationHandles[BuffID].Duration
|
|||
|
local NowTime = BP_BuffManager.GetNowTime()
|
|||
|
local NeedDuration = NewDuration - (NowTime - self.BuffDurationHandles[BuffID].EnablingTime)
|
|||
|
--- 若为减少Buff时间则判断是否达到移除时间
|
|||
|
if NeedDuration <= 0 then
|
|||
|
self:RemoveBuffFromBuffID(BuffID)
|
|||
|
else
|
|||
|
local DurationHandle= UGCEventSystem.SetTimer(
|
|||
|
self,
|
|||
|
function ()
|
|||
|
self:RemoveBuffFromBuffID(BuffID)
|
|||
|
end,
|
|||
|
NeedDuration
|
|||
|
)
|
|||
|
self.BuffDurationHandles[BuffID].Handle = DurationHandle
|
|||
|
self.BuffDurationHandles[BuffID].Duration = NewDuration
|
|||
|
|
|||
|
BP_BuffManager.SendBuffEvent(
|
|||
|
BP_BuffManager.ECallBack.BuffDurationUpdate,
|
|||
|
BP_BuffManager.GetPlayerKeyOfTheBuffID(BuffID),
|
|||
|
BuffID,
|
|||
|
self.BuffDurationHandles[BuffID].Duration,
|
|||
|
self.BuffDurationHandles[BuffID].EnablingTime,
|
|||
|
NowTime
|
|||
|
)
|
|||
|
|
|||
|
end
|
|||
|
|
|||
|
log_tree("[BP_BuffManager_AddBuffDuration] 2", self.BuffDurationHandles)
|
|||
|
|
|||
|
return self.EResult.Succeed
|
|||
|
end
|
|||
|
|
|||
|
--- 获取Buff持续时间
|
|||
|
--- @return int32, float EResult, Duration
|
|||
|
function BP_BuffManager:GetBuffDuration(BuffID)
|
|||
|
if not self:CheckBuffID(BuffID) then
|
|||
|
return BP_BuffManager.EResult.BuffIDIsNotValid, 0.
|
|||
|
end
|
|||
|
if self.BuffDurationHandles[BuffID] == nil then
|
|||
|
return BP_BuffManager.EResult.NotSetBuffDuration, 0.
|
|||
|
end
|
|||
|
return BP_BuffManager.EResult.Succeed, self.BuffDurationHandles[BuffID].Duration
|
|||
|
end
|
|||
|
|
|||
|
--- 获取Buff剩余持续时间
|
|||
|
--- @return int, float EResult, RemainingDuration
|
|||
|
function BP_BuffManager:GetBuffRemainingDuration(BuffID)
|
|||
|
if not self:CheckBuffID(BuffID) then
|
|||
|
return BP_BuffManager.EResult.BuffIDIsNotValid, 0.
|
|||
|
end
|
|||
|
if self.BuffDurationHandles[BuffID] == nil then
|
|||
|
return BP_BuffManager.EResult.NotSetBuffDuration, 0.
|
|||
|
end
|
|||
|
local NowTime = BP_BuffManager.GetNowTime()
|
|||
|
local EnablingTime = self.BuffDurationHandles[BuffID].EnablingTime
|
|||
|
local Duration = self.BuffDurationHandles[BuffID].Duration
|
|||
|
return BP_BuffManager.EResult.Succeed, Duration - (NowTime - EnablingTime)
|
|||
|
end
|
|||
|
|
|||
|
--- 关闭自动移除Buff的延迟句柄及删除信息缓存
|
|||
|
function BP_BuffManager:RemoveBuffDuration(BuffID)
|
|||
|
if self.BuffDurationHandles[BuffID] then
|
|||
|
UGCEventSystem.StopTimer(self.BuffDurationHandles[BuffID].Handle)
|
|||
|
self.BuffDurationHandles[BuffID] = nil
|
|||
|
UGCLogSystem.Log("[BP_BuffManager_RemoveBuffDuration] BuffDurationHandles[%d] Remove Succeed", BuffID)
|
|||
|
BP_BuffManager.SendBuffEvent(BP_BuffManager.ECallBack.RemoveBuffDuration, BuffID)
|
|||
|
|
|||
|
else
|
|||
|
UGCLogSystem.LogError("[BP_BuffManager_RemoveBuffDuration] BuffDurationHandles[%d] is nil", BuffID)
|
|||
|
end
|
|||
|
end
|
|||
|
|
|||
|
------------------------------------------ Apply Buff End ------------------------------------------
|
|||
|
|
|||
|
-------------------------------------------- Remove --------------------------------------------
|
|||
|
|
|||
|
--- 校验BuffID是否与PlayerKey匹配并移除该Buff
|
|||
|
---@param BuffID int32
|
|||
|
---@param PlayerKey uint32
|
|||
|
function BP_BuffManager:CheckRemoveBuffFromBuffID(BuffID, PlayerKey)
|
|||
|
if self:CheckBuffIDMatching(BuffID, PlayerKey) then
|
|||
|
return self:RemoveBuffFromBuffID(BuffID)
|
|||
|
end
|
|||
|
return BP_BuffManager.EResult.BuffIDMismatch
|
|||
|
end
|
|||
|
|
|||
|
--- 通过BuffID移除Buff
|
|||
|
---@param BuffID int32
|
|||
|
function BP_BuffManager:RemoveBuffFromBuffID(BuffID)
|
|||
|
local ActiveBuffInfo = self.BuffActiveList[BuffID]
|
|||
|
if ActiveBuffInfo == nil then
|
|||
|
UGCLogSystem.LogError("[BP_BuffManager_RemoveBuffFromBuffID] ActiveBuffInfo is nil")
|
|||
|
return BP_BuffManager.EResult.BuffIDIsNotValid
|
|||
|
end
|
|||
|
|
|||
|
local PawnIsValid, ValidPlayerPawn = self:CheckPlayerKey(ActiveBuffInfo.PlayerKey)
|
|||
|
if not PawnIsValid then
|
|||
|
return BP_BuffManager.EResult.PlayerPawnNotValid
|
|||
|
end
|
|||
|
|
|||
|
local BuffIsValid, BuffCacheData = self:CheckBuffID(BuffID)
|
|||
|
if not BuffIsValid then
|
|||
|
return BP_BuffManager.EResult.BuffIDIsNotValid
|
|||
|
end
|
|||
|
|
|||
|
local BuffInst = self:RequireBuffAction(BuffCacheData.BuffType)
|
|||
|
local bHasRemoveBuffFunc, RemoveBuffFunc = self:CheckBuffInstRemoveBuffFunc(BuffInst)
|
|||
|
if bHasRemoveBuffFunc then
|
|||
|
RemoveBuffFunc(BuffInst, BuffCacheData.BuffTag, ValidPlayerPawn, table.unpack(BuffCacheData.BuffArgs))
|
|||
|
end
|
|||
|
|
|||
|
self:RemoveBuffDuration(BuffID)
|
|||
|
|
|||
|
self.BuffActiveList[BuffID] = nil
|
|||
|
|
|||
|
BP_BuffManager.SendBuffEvent(BP_BuffManager.ECallBack.RemoveBuff, ActiveBuffInfo.PlayerKey, BuffCacheData.BuffType, BuffID)
|
|||
|
self:SpawnParticleToPlayPawn(ActiveBuffInfo.PlayerKey, nil, BuffCacheData.BuffType, false)
|
|||
|
return BP_BuffManager.EResult.Succeed
|
|||
|
end
|
|||
|
|
|||
|
--- 清除玩家Buff
|
|||
|
---@param ValidPlayerPawn:BP_PlayerPawn_C*
|
|||
|
---@param BuffID int
|
|||
|
function BP_BuffManager:ClearPlayerOwnedBuff(PlayerKey)
|
|||
|
-- local OwnedBuffIDs = self:GetPlayerOwnedBuffs(PlayerKey)
|
|||
|
local OwnedBuffIDs = BP_BuffManager.BuffFilter(PlayerKey)
|
|||
|
for _, BuffID in pairs(OwnedBuffIDs) do
|
|||
|
self:RemoveBuffFromBuffID(BuffID)
|
|||
|
end
|
|||
|
end
|
|||
|
|
|||
|
--- 清除玩家Buff缓存
|
|||
|
---@param PlayerKey uint32
|
|||
|
function BP_BuffManager:ClearPlayerBuffCache(PlayerKey)
|
|||
|
local RemoveBuffIDs = {}
|
|||
|
for BuffID, BuffParam in pairs(self.BuffActiveList) do
|
|||
|
if BuffParam.PlayerKey == PlayerKey then
|
|||
|
RemoveBuffIDs[#RemoveBuffIDs + 1] = BuffID
|
|||
|
end
|
|||
|
end
|
|||
|
|
|||
|
for _, BuffID in pairs(RemoveBuffIDs) do
|
|||
|
self:RemoveBuffDuration(BuffID)
|
|||
|
self.BuffActiveList[BuffID] = nil
|
|||
|
end
|
|||
|
|
|||
|
BP_BuffManager.SendBuffEvent(BP_BuffManager.ECallBack.ClearPlayerBuffCache, PlayerKey)
|
|||
|
end
|
|||
|
|
|||
|
------------------------------------------ Remove End ------------------------------------------
|
|||
|
|
|||
|
function BP_BuffManager:ReceiveTick(DeltaTime)
|
|||
|
self.SuperClass.ReceiveTick(self, DeltaTime);
|
|||
|
|
|||
|
for _, BuffType in pairs(self.BuffInstWithTick) do
|
|||
|
local BuffInst = self:RequireBuffAction(BuffType)
|
|||
|
BuffInst:Tick(DeltaTime)
|
|||
|
end
|
|||
|
end
|
|||
|
|
|||
|
|
|||
|
-------------------------------------------- Get --------------------------------------------
|
|||
|
|
|||
|
--- 获取Buff拥有者
|
|||
|
---@param BuffID int
|
|||
|
---@return PlayerKey uint
|
|||
|
function BP_BuffManager.GetBuffOwner(BuffID)
|
|||
|
local BuffManager = BP_BuffManager.GetBuffManager()
|
|||
|
if BuffManager then
|
|||
|
if BuffManager.BuffActiveList[BuffID] then
|
|||
|
return BuffManager.BuffActiveList[BuffID].PlayerKey
|
|||
|
end
|
|||
|
end
|
|||
|
return nil
|
|||
|
end
|
|||
|
|
|||
|
|
|||
|
|
|||
|
--- Buff 过滤
|
|||
|
---@param PlayerKey uint32
|
|||
|
---@param BuffType EBuffType
|
|||
|
---@param BuffTag any Buff的标签
|
|||
|
---@return table<int> {BuffID int, ...} BuffIDs
|
|||
|
function BP_BuffManager.BuffFilter(PlayerKey, BuffType, BuffTag)
|
|||
|
local BuffManager = BP_BuffManager.GetBuffManager()
|
|||
|
local ResetBuffIDs = {}
|
|||
|
if BuffManager then
|
|||
|
for BuffID, BuffParam in pairs(BuffManager.BuffActiveList) do
|
|||
|
if (BuffParam.PlayerKey == PlayerKey or PlayerKey == nil)
|
|||
|
and (BuffParam.BuffType == BuffType or BuffType == nil)
|
|||
|
and (BuffParam.BuffTag == BuffType or BuffTag == nil)
|
|||
|
then
|
|||
|
ResetBuffIDs[#ResetBuffIDs + 1] = BuffID
|
|||
|
end
|
|||
|
end
|
|||
|
end
|
|||
|
return ResetBuffIDs
|
|||
|
end
|
|||
|
|
|||
|
--- 通过BuffID获取其拥有者
|
|||
|
---@param BuffID int
|
|||
|
---@return PlayerKey uint32
|
|||
|
function BP_BuffManager.GetPlayerKeyOfTheBuffID(BuffID)
|
|||
|
local BuffManager = BP_BuffManager.GetBuffManager()
|
|||
|
if BuffManager then
|
|||
|
return (BuffManager.BuffActiveList[BuffID] ~= nil and BuffManager.BuffActiveList[BuffID].PlayerKey or -1)
|
|||
|
end
|
|||
|
return -1
|
|||
|
end
|
|||
|
|
|||
|
--- 获得BuffPath
|
|||
|
---@param BuffID int
|
|||
|
---@return EBuffType BuffConfig.EBuffType
|
|||
|
function BP_BuffManager.GetBuffTypeFromBuffID(BuffID)
|
|||
|
local BuffManager = BP_BuffManager.GetBuffManager()
|
|||
|
if BuffManager then
|
|||
|
if BuffManager.BuffActiveList[BuffID] then
|
|||
|
return BuffManager.BuffActiveList[BuffID].BuffType
|
|||
|
end
|
|||
|
end
|
|||
|
return nil
|
|||
|
end
|
|||
|
|
|||
|
--- 获取BuffAction默认主题参数
|
|||
|
---@param BuffType EBuffType
|
|||
|
---@param ParamName string
|
|||
|
function BP_BuffManager.GetBuffDefaultParam(BuffType, ParamName)
|
|||
|
local ParamInfo = BP_BuffManager.CheckBuffInst[ParamName]
|
|||
|
local BuffManager = BP_BuffManager.GetBuffManager()
|
|||
|
if BuffManager then
|
|||
|
if ParamInfo then
|
|||
|
local BuffInst = BuffManager:RequireBuffAction(BuffType)
|
|||
|
if BuffInst == nil then
|
|||
|
UGCLogSystem.LogError("[BP_BuffManager_GetBuffDefaultParam] BuffInst is nil. BuffType:%s", tostring(BuffType))
|
|||
|
return nil
|
|||
|
end
|
|||
|
if BuffInst[ParamName] == nil or type(BuffInst[ParamName]) ~= ParamInfo.type then
|
|||
|
UGCLogSystem.LogError("[BP_BuffManager_GetBuffDefaultParam] %s is not %s. BuffType:%s", ParamName, ParamInfo.type, tostring(BuffType))
|
|||
|
return nil
|
|||
|
end
|
|||
|
return BuffInst[ParamName]
|
|||
|
else
|
|||
|
UGCLogSystem.LogError("[BP_BuffManager_GetBuffDefaultParam] ParamInfo not have %s", tostring(ParamName))
|
|||
|
return nil
|
|||
|
end
|
|||
|
end
|
|||
|
return nil
|
|||
|
end
|
|||
|
|
|||
|
--- 获取当前时间
|
|||
|
---@return float NowTime
|
|||
|
function BP_BuffManager.GetNowTime()
|
|||
|
return KismetSystemLibrary.GetGameTimeInSeconds(UGCGameSystem.GameState)
|
|||
|
end
|
|||
|
|
|||
|
--- 通过Manager定义的BuffActionID获取BuffPath
|
|||
|
---@param BuffType EBuffType
|
|||
|
---@return string BuffPath
|
|||
|
function BP_BuffManager.GetBuffPathFromBuffType(BuffType)
|
|||
|
return BuffConfig.BuffActionInfo[BuffType].Path
|
|||
|
end
|
|||
|
|
|||
|
--- 通过BuffPath找BuffType 没有则返回 -1
|
|||
|
---@param BuffPath string
|
|||
|
function BP_BuffManager.GetBuffTypeFromBuffPath(BuffPath)
|
|||
|
for k, v in pairs(BuffConfig.BuffActionInfo) do
|
|||
|
if v.Path == BuffPath then
|
|||
|
return k
|
|||
|
end
|
|||
|
end
|
|||
|
return -1
|
|||
|
end
|
|||
|
|
|||
|
--- 通过BuffName找BuffType 没有则返回 -1
|
|||
|
---@param BuffName string
|
|||
|
function BP_BuffManager.GetBuffTypeFromBuffName(BuffName)
|
|||
|
for k, v in pairs(BuffConfig.BuffActionInfo) do
|
|||
|
if v.Name == BuffName then
|
|||
|
return k
|
|||
|
end
|
|||
|
end
|
|||
|
return -1
|
|||
|
end
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
------------------------------------------ Get End ------------------------------------------
|
|||
|
|
|||
|
-------------------------------------------- Check --------------------------------------------
|
|||
|
|
|||
|
--- 检测并返回Buff的RemoveBuff function
|
|||
|
---@return bool, function
|
|||
|
function BP_BuffManager:CheckBuffInstRemoveBuffFunc(BuffInst)
|
|||
|
return
|
|||
|
(BuffInst["RemoveBuff"] ~= nil and (type(BuffInst["RemoveBuff"]) == "function")),
|
|||
|
BuffInst["RemoveBuff"]
|
|||
|
end
|
|||
|
|
|||
|
--- 检查BuffID
|
|||
|
---@return bool, table<PlayerKey, EBuffType> {PlayerKey = uint32, BuffType = BuffConfig.EBuffType, BuffArgs = {...}} Succeed, BuffActive
|
|||
|
function BP_BuffManager:CheckBuffID(BuffID)
|
|||
|
return (BuffID ~= nil and self.BuffActiveList[BuffID] ~= nil), self.BuffActiveList[BuffID]
|
|||
|
end
|
|||
|
|
|||
|
--- 检查PlayerKey
|
|||
|
---@return bool, BP_PlayerPawn_C*
|
|||
|
function BP_BuffManager:CheckPlayerKey(PlayerKey)
|
|||
|
local TargetPawn = UGCGameSystem.GetPlayerPawnByPlayerKey(PlayerKey)
|
|||
|
if not UE.IsValid(TargetPawn) then
|
|||
|
self:ClearPlayerBuffCache(PlayerKey)
|
|||
|
return false, nil
|
|||
|
end
|
|||
|
return true, TargetPawn
|
|||
|
end
|
|||
|
|
|||
|
--- 单独检测BuffInst是否含有Tick函数
|
|||
|
function BP_BuffManager:IndividualCheckTickFunc(BuffInst)
|
|||
|
if BuffInst["Tick"] == nil or type(BuffInst["Tick"]) ~= "function" then
|
|||
|
return false
|
|||
|
end
|
|||
|
return true
|
|||
|
end
|
|||
|
|
|||
|
--- 单独检测BuffInst是否含有PlayerDeathCallBack函数
|
|||
|
function BP_BuffManager:IndividualCheckPlayerDeathCallBackFunc(BuffInst)
|
|||
|
if BuffInst["PlayerDeathCallBack"] == nil or type(BuffInst["PlayerDeathCallBack"]) ~= "function" then
|
|||
|
return false
|
|||
|
end
|
|||
|
return true
|
|||
|
end
|
|||
|
|
|||
|
--- 检测BuffID是否与玩家PlayerKey匹配
|
|||
|
---@param BuffID int32
|
|||
|
---@param PlayerKey uint32
|
|||
|
function BP_BuffManager:CheckBuffIDMatching(BuffID, PlayerKey)
|
|||
|
local BuffIDIsValid, BuffData = self:CheckBuffID(BuffID)
|
|||
|
|
|||
|
if not BuffIDIsValid then
|
|||
|
return false
|
|||
|
end
|
|||
|
|
|||
|
if BuffData.PlayerKey == PlayerKey then
|
|||
|
return true
|
|||
|
end
|
|||
|
|
|||
|
return false
|
|||
|
end
|
|||
|
|
|||
|
------------------------------------------ Check End ------------------------------------------
|
|||
|
|
|||
|
|
|||
|
|
|||
|
--- Require并检测BuffAction
|
|||
|
---@return BuffAction
|
|||
|
function BP_BuffManager:RequireBuffAction(BuffType)
|
|||
|
if self.BuffInsts[BuffType] == nil then
|
|||
|
local BuffPath = BP_BuffManager.GetBuffPathFromBuffType(BuffType)
|
|||
|
if BuffPath == nil then
|
|||
|
return nil
|
|||
|
end
|
|||
|
UGCLogSystem.Log("[BP_BuffManager_RequireBuffAction] RequireBuffPath:%s ", BuffPath)
|
|||
|
local BuffInst = require(BuffPath)
|
|||
|
if BuffInst == nil then
|
|||
|
UGCLogSystem.LogError("[BP_BuffManager_RequireBuffAction] Require Error")
|
|||
|
return nil
|
|||
|
end
|
|||
|
|
|||
|
for PropertyName, CheckTemp in pairs(BP_BuffManager.CheckBuffInst) do
|
|||
|
if BuffInst[PropertyName] == nil then
|
|||
|
if CheckTemp.CheckType == BP_BuffManager.ECheck.Error then
|
|||
|
UGCLogSystem.LogError("[BP_BuffManager_RequireBuffAction] Error BuffInst 没有%s, type:%s", PropertyName, CheckTemp.type)
|
|||
|
return nil
|
|||
|
elseif CheckTemp.CheckType == BP_BuffManager.ECheck.Warn then
|
|||
|
UGCLogSystem.Log("[BP_BuffManager_RequireBuffAction] Warning BuffInst 没有%s, type:%s", PropertyName, CheckTemp.type)
|
|||
|
end
|
|||
|
else
|
|||
|
if type(BuffInst[PropertyName]) ~= CheckTemp.type then
|
|||
|
if CheckTemp.CheckType == BP_BuffManager.ECheck.Error then
|
|||
|
UGCLogSystem.LogError("[BP_BuffManager_RequireBuffAction] Error BuffInst %s类型不匹配, type:%s", PropertyName, CheckTemp.type)
|
|||
|
return nil
|
|||
|
elseif CheckTemp.CheckType == BP_BuffManager.ECheck.Warn then
|
|||
|
UGCLogSystem.Log("[BP_BuffManager_RequireBuffAction] Warning BuffInst %s类型不匹配 type:%s", PropertyName, CheckTemp.type)
|
|||
|
end
|
|||
|
end
|
|||
|
end
|
|||
|
end
|
|||
|
|
|||
|
self.BuffInsts[BuffType] = BuffInst
|
|||
|
|
|||
|
if self:IndividualCheckTickFunc(self.BuffInsts[BuffType]) then
|
|||
|
self.BuffInstWithTick[#self.BuffInstWithTick + 1] = BuffType
|
|||
|
DOREPONCE(self, "BuffInstWithTick")
|
|||
|
end
|
|||
|
|
|||
|
end
|
|||
|
|
|||
|
return self.BuffInsts[BuffType]
|
|||
|
end
|
|||
|
|
|||
|
|
|||
|
|
|||
|
--- 服务器客户端均可调,触发BuffAction的TargetFuncName
|
|||
|
---@param TargetPlayerKey:[为uint32则单独发送], [为table{uint32, ...}则多个发送], [为nil则广播发送]. 若客户端调用则无视该参数
|
|||
|
---@param BuffName string Buff文件名,BuffAction代码中可使用BP_BuffManager.GetBuffFileName()获取
|
|||
|
---@param TargetFuncName string 目标BuffAction的函数名
|
|||
|
---@param ...:Args TargetFunc的输入参数
|
|||
|
function BP_BuffManager:BuffNotifyRPC(TargetPlayerKey, BuffName, TargetFuncName, ...)
|
|||
|
|
|||
|
UGCLogSystem.Log("[BP_BuffManager_BuffNotifyRPC] BuffName:%s", BuffName)
|
|||
|
|
|||
|
local BuffType = BP_BuffManager.GetBuffTypeFromBuffName(BuffName)
|
|||
|
if BuffType < 0 then
|
|||
|
UGCLogSystem.LogError("[BP_BuffManager_BuffNotifyRPC] BuffType < 0", tostring(BuffName))
|
|||
|
return
|
|||
|
end
|
|||
|
UGCLogSystem.Log("[BP_BuffManager_BuffNotifyRPC] BuffType:%d, FuncName:%s", BuffType, TargetFuncName)
|
|||
|
|
|||
|
UGCSendRPCSystem.ActorRPCNotify(TargetPlayerKey, self, "BuffRPC", BuffType, TargetFuncName, ...)
|
|||
|
|
|||
|
end
|
|||
|
|
|||
|
|
|||
|
function BP_BuffManager:BuffRPC(BuffType, TargetFuncName, ...)
|
|||
|
UGCLogSystem.Log("[BP_BuffManager_BuffRPC] BuffType:%d, FuncName:%s", BuffType, TargetFuncName)
|
|||
|
local BuffInst = self:RequireBuffAction(BuffType)
|
|||
|
if BuffInst then
|
|||
|
local BuffRPCFunc = BuffInst[TargetFuncName]
|
|||
|
if BuffRPCFunc ~= nil then
|
|||
|
if type(BuffRPCFunc) ~= "function" then
|
|||
|
UGCLogSystem.LogError("[BP_BuffManager_BuffRPC] BuffRPCFunc TypeError:%s", type(BuffRPCFunc))
|
|||
|
else
|
|||
|
BuffRPCFunc(BuffInst, ...)
|
|||
|
end
|
|||
|
else
|
|||
|
UGCLogSystem.LogError("[BP_BuffManager_BuffRPC] BuffRPCFunc is nil")
|
|||
|
end
|
|||
|
else
|
|||
|
UGCLogSystem.LogError("[BP_BuffManager_BuffRPC] BuffInst is nil, BuffType Type:%s, BuffType:%s", type(BuffType), tostring(BuffType))
|
|||
|
end
|
|||
|
end
|
|||
|
|
|||
|
----------------------------- RPC -----------------------------
|
|||
|
|
|||
|
--- 广播到玩家脚下生成粒子
|
|||
|
---@param PlayerKey PlayerKey 目标玩家
|
|||
|
---@param BuffType EBuffType 粒子路径
|
|||
|
function BP_BuffManager:SpawnParticleToPlayPawn(PlayerKey, BenefitPlayers, BuffType, IsShow)
|
|||
|
if UGCGameSystem.IsServer() then
|
|||
|
UGCSendRPCSystem.ActorRPCNotify(nil, self, "MulticastRPC_SpawnParticleAttachPlayer", PlayerKey, BenefitPlayers, BuffType, IsShow);
|
|||
|
else
|
|||
|
self:MulticastRPC_SpawnParticleAttachPlayer(PlayerKey, BenefitPlayers, BuffType, IsShow);
|
|||
|
end
|
|||
|
end
|
|||
|
|
|||
|
---@type table<BuffID, >
|
|||
|
BP_BuffManager.CachedParticle = {}
|
|||
|
|
|||
|
--- 广播到客户端,在玩家脚下生成粒子
|
|||
|
function BP_BuffManager:MulticastRPC_SpawnParticleAttachPlayer(PlayerKey, BenefitPlayers, BuffType, IsShow)
|
|||
|
UGCLogSystem.LogTree(string.format("[BP_BuffManager:MulticastRPC_SpawnParticleAttachPlayer] BenefitPlayers = "), BenefitPlayers);
|
|||
|
if BenefitPlayers == nil then return; end
|
|||
|
local ParticlePath = BuffConfig.BuffInfo[BuffType].ParticlePath;
|
|||
|
if table.isEmpty(self.ParticleTemplateList) then self.ParticleTemplateList = {}; end
|
|||
|
if self.ParticleTemplateList[ParticlePath] then
|
|||
|
for i, v in pairs(BenefitPlayers) do
|
|||
|
local TargetPawn = UGCGameSystem.GetPlayerPawnByPlayerKey(v);
|
|||
|
if TargetPawn and UE.IsValid(TargetPawn) then
|
|||
|
GameplayStatics.SpawnEmitterAttached(self.ParticleTemplateList[ParticlePath], TargetPawn.Mesh, "", VectorHelper.VectorZero(), VectorHelper.RotZero(), VectorHelper.ScaleOne(), EAttachLocation.SnapToTarget, false)
|
|||
|
end
|
|||
|
end
|
|||
|
else
|
|||
|
UE.AsyncLoadObject(ParticlePath, function(TargetObject)
|
|||
|
self.ParticleTemplateList[ParticlePath] = TargetObject;
|
|||
|
for i, v in pairs(BenefitPlayers) do
|
|||
|
local TargetPawn = UGCGameSystem.GetPlayerPawnByPlayerKey(v);
|
|||
|
GameplayStatics.SpawnEmitterAttached(TargetObject, TargetPawn.Mesh, "", VectorHelper.VectorZero(), VectorHelper.RotZero(), VectorHelper.ScaleOne(), EAttachLocation.SnapToTarget, false)
|
|||
|
end
|
|||
|
end)
|
|||
|
end
|
|||
|
end
|
|||
|
|
|||
|
--------------------------- RPC End ---------------------------
|
|||
|
|
|||
|
|
|||
|
function BP_BuffManager:GetAvailableServerRPCs()
|
|||
|
return
|
|||
|
-- "BuffRPC"
|
|||
|
end
|
|||
|
|
|||
|
return BP_BuffManager;
|