---@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> 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 {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 = 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 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;