378 lines
12 KiB
Lua
378 lines
12 KiB
Lua
local BuffDir = 'Script.Blueprint.SceneObj.Buff.'
|
||
|
||
---@class FBuffManager
|
||
---@field OwnerBuffs table<EBuffType, table<int32, BuffScriptItem>>
|
||
---@field Owner AActor
|
||
---@field PreScript string
|
||
|
||
---@type FBuffManager
|
||
local BuffManager = {};
|
||
|
||
---@class FBuffItem
|
||
---@field BuffType EBuffType
|
||
---@field OwnerPlayerKey PlayerKey
|
||
---@field Owner FBuffManager
|
||
---@field BuffName string
|
||
---@field new fun(Params:table) 初始化函数
|
||
---@field Init fun(Params:table) 初始化函数
|
||
---@field Reset fun() 初始化函数
|
||
---@field AddBuff fun() 初始化函数
|
||
---@field RemoveBuff fun() 初始化函数
|
||
---@field UpdateBuff fun() 初始化函数
|
||
|
||
|
||
---@class BuffScriptItem Buff实例
|
||
---@field Buff FBuffItem
|
||
---@field Continue float
|
||
---@field Cooldown float
|
||
---@field StartTime float
|
||
---@field EndTime float
|
||
---@field State EBuffState
|
||
|
||
---@type table<EBuffType, table<PlayerKey, BuffScriptItem>>
|
||
BuffManager.OwnerBuffs = {};
|
||
-- Buff 的所有者
|
||
BuffManager.Owner = nil;
|
||
BuffManager.Config = nil;
|
||
BuffManager.PreScript = BuffDir .. 'Script.Buff_';
|
||
|
||
--- 创建一个实例
|
||
function BuffManager:new()
|
||
return setmetatable(
|
||
{
|
||
OwnerBuffs = {};
|
||
}, {
|
||
__index = self,
|
||
__metatable = self,
|
||
});
|
||
end
|
||
|
||
---S & C 初始化
|
||
function BuffManager:Init(InOwner)
|
||
self.Owner = InOwner;
|
||
-- 将永久的 Buff 加上,遍历所有的 Buff 检查哪些是固定添加的
|
||
self.Config = require(BuffDir .. 'BuffConfig');
|
||
UGCLogSystem.Log("[BuffManager:Init] 执行")
|
||
GlobalTickTool:AddTick(self, self.OnTick);
|
||
end
|
||
|
||
BuffManager.DeadRemoveBuffs = {};
|
||
|
||
function BuffManager:OnPlayerDead(DeadPlayerKey, KillerPlayerKey)
|
||
for BuffType, PlayersBuff in pairs(self.OwnerBuffs) do
|
||
if self.Config[BuffType].bRemoveDead then
|
||
if PlayersBuff[DeadPlayerKey] then
|
||
if self:HasBuff(BuffType, DeadPlayerKey) then
|
||
self:RemoveBuff(BuffType, DeadPlayerKey);
|
||
end
|
||
end
|
||
end
|
||
end
|
||
end
|
||
|
||
function BuffManager:HasBuff(BuffType, InPlayerKey)
|
||
local BuffItem = self:FindBuffItem(BuffType, InPlayerKey);
|
||
if BuffItem then
|
||
return BuffItem.State == EBuffState.Using;
|
||
end
|
||
return false;
|
||
end
|
||
|
||
---@param BuffType EBuffType
|
||
---@param InPlayerKey PlayerKey
|
||
---@vararg any 外部传参会传到实例里面
|
||
function BuffManager:AddBuff(BuffType, InPlayerKey, ...)
|
||
assert(BuffType ~= nil, "BuffType 不能为空")
|
||
assert(self.Config[BuffType] ~= nil, "BuffConfig 中必须有值")
|
||
local p = {...};
|
||
UGCLogSystem.LogTree(string.format("[BuffManager:AddBuff] p ="), p)
|
||
local AddSuccess = false;
|
||
-- 默认一个人同种 BUFF 只能有一个,如果有多个,那么使用传参进行操作,可以传入函数,然后在Buff 内部进行操作
|
||
if IsServer then
|
||
if not self:CanAddBuff(BuffType, InPlayerKey) then
|
||
UGCLogSystem.Log("[BuffManager:AddBuff] 无法添加")
|
||
GameState:ShowTipsUI("玩家 %s 技能 %s 还在冷却中", UE.GetPlayerName(InPlayerKey), self:GetBuffName(BuffType));
|
||
return false;
|
||
end
|
||
end
|
||
|
||
UGCLogSystem.Log("[BuffManager:AddBuff] 开始添加 Buff: %s", TableHelper.printEnum(EBuffType, BuffType));
|
||
local BuffItem = self:FindBuffItem(BuffType, InPlayerKey)
|
||
if BuffItem ~= nil then
|
||
UGCLogSystem.Log("[BuffManager:AddBuff] 往存在的 BuffItem 上添加:%s", tostring(InPlayerKey));
|
||
AddSuccess = self:AddBuff_Exist(BuffItem, InPlayerKey, ...);
|
||
else
|
||
UGCLogSystem.Log("[BuffManager:AddBuff] 新添加 BuffItem:%s", tostring(InPlayerKey));
|
||
AddSuccess = self:AddBuff_Raw(BuffType, InPlayerKey, ...);
|
||
end
|
||
|
||
if AddSuccess then
|
||
self:OnAddBuff(BuffType, InPlayerKey);
|
||
if IsServer then
|
||
if self:IsBuffForever(BuffType) then
|
||
self:SendRPC("Client_AddBuff", InPlayerKey, BuffType, EBuffState.Using, ...);
|
||
else
|
||
self:SendRPC("Client_AddBuff", InPlayerKey, BuffType, EBuffState.Using, {
|
||
StartTime = self.OwnerBuffs[BuffType][InPlayerKey].StartTime,
|
||
EndTime = self.OwnerBuffs[BuffType][InPlayerKey].EndTime,
|
||
}, ...);
|
||
end
|
||
end
|
||
else
|
||
UGCLogSystem.Log("[BuffManager:AddBuff] 玩家 %s 无法添加成功", tostring(InPlayerKey));
|
||
end
|
||
return AddSuccess;
|
||
end
|
||
|
||
function BuffManager:Register(BuffItem, InFuncName, DeadPlayerKey, KillPlayerKey)
|
||
|
||
end
|
||
|
||
function BuffManager:OnAddBuff(BuffType, InPlayerKey)
|
||
local Pawn = UGCGameSystem.GetPlayerPawnByPlayerKey(InPlayerKey);
|
||
if UE.IsValidPawn(Pawn) then
|
||
table.func(Pawn, "OnAddBuff", BuffType);
|
||
end
|
||
local PC = UGCGameSystem.GetPlayerControllerByPlayerKey(InPlayerKey);
|
||
if PC ~= nil and UE.IsValid(PC) then
|
||
table.func(PC, "OnAddBuff", BuffType);
|
||
end
|
||
end
|
||
|
||
function BuffManager:IsBuffForever(BuffType)
|
||
local Config = self.Config[BuffType];
|
||
return (Config.Cooldown == -1 and Config.Continue == -1) or (Config.Cooldown == nil and Config.Continue == nil);
|
||
end
|
||
|
||
---@param BuffItem BuffScriptItem
|
||
---@return bool
|
||
function BuffManager:AddBuff_Exist(BuffItem, InPlayerKey, ...)
|
||
BuffItem.StartTime = UE.GetServerTime();
|
||
BuffItem.EndTime = BuffItem.StartTime + BuffItem.Continue;
|
||
BuffItem.State = EBuffState.Using;
|
||
return table.func(BuffItem.Buff, "AddBuff", InPlayerKey, ...);
|
||
end
|
||
|
||
---@param BuffType EBuffType
|
||
---@param InPlayerKey PlayerKey
|
||
---@return bool
|
||
function BuffManager:AddBuff_Raw(BuffType, InPlayerKey, ...)
|
||
local BuffBase = require(self.PreScript .. self.Config[BuffType].Script);
|
||
local Buff = nil;
|
||
if table.hasFunc(BuffBase, "new") then
|
||
Buff = table.func(BuffBase, "new", ...);
|
||
else
|
||
Buff = setmetatable({}, {
|
||
__metatable = BuffBase;
|
||
__index = BuffBase;
|
||
});
|
||
end
|
||
|
||
self:InitBuff(Buff, BuffType, InPlayerKey);
|
||
|
||
local Continue = self.Config[BuffType].Continue;
|
||
if Continue == nil then Continue = 0; end
|
||
local Cooldown = self.Config[BuffType].Cooldown;
|
||
if Cooldown == nil then Cooldown = 0; end
|
||
local StartTime = UE.GetServerTime();
|
||
--UGCLogSystem.Log("[BuffManager:AddBuff_Raw] StartTime = %s", tostring(StartTime));
|
||
local Params = {...};
|
||
UGCLogSystem.LogTree(string.format("[BuffManager:AddBuff_Raw] Params ="), Params)
|
||
local AddSuccess = table.func(Buff, "AddBuff", InPlayerKey, ...);
|
||
if not AddSuccess then return false; end
|
||
-- 设置定时器然后增加
|
||
local Item = {
|
||
Buff = Buff,
|
||
Continue = Continue, -- 如果 Continue < 0 表示当前是无限执行的
|
||
Cooldown = Cooldown,
|
||
StartTime = StartTime,
|
||
EndTime = StartTime + Continue,
|
||
State = EBuffState.Using,
|
||
};
|
||
UGCLogSystem.Log("[BuffManager:AddBuff_Raw] BuffType = %s", TableHelper.printEnum(EBuffType, BuffType));
|
||
if self:IsBuffForever(BuffType) then
|
||
self.OwnerBuffs[BuffType] = Item;
|
||
else
|
||
if InPlayerKey then
|
||
if self.OwnerBuffs[BuffType] == nil then self.OwnerBuffs[BuffType] = {}; end
|
||
self.OwnerBuffs[BuffType][InPlayerKey] = Item;
|
||
end
|
||
end
|
||
UGCLogSystem.LogTree(string.format("[BuffManager:AddBuff_Raw] self.OwnerBuffs ="), self.OwnerBuffs)
|
||
return true;
|
||
end
|
||
|
||
---@param BuffType EBuffType
|
||
---@param InPlayerKey PlayerKey
|
||
---@param Buff BuffScriptItem
|
||
function BuffManager:InitBuff(Buff, BuffType, InPlayerKey)
|
||
if not self:IsBuffForever(BuffType) then
|
||
Buff.OwnerPlayerKey = InPlayerKey;
|
||
end
|
||
Buff.BuffType = BuffType;
|
||
--Buff.BuffName = self.Config[BuffType].Name;
|
||
if not table.isEmpty(self.Config[BuffType].Params) then
|
||
for i, v in pairs(self.Config[BuffType].Params) do Buff[i] = v; end
|
||
end
|
||
table.func(Buff, "Init", self.Config[BuffType].Params);
|
||
end
|
||
|
||
---@param BuffItem BuffScriptItem
|
||
function BuffManager:RemoveBuff_Internal(PlayerKey, BuffItem)
|
||
local Buff = BuffItem.Buff;
|
||
table.func(Buff, "RemoveBuff", PlayerKey);
|
||
-- 检查是否有冷却
|
||
if BuffItem.Cooldown > 0 then
|
||
BuffItem.State = EBuffState.Cooling;
|
||
BuffItem.StartTime = UE.GetServerTime();
|
||
BuffItem.EndTime = BuffItem.StartTime + BuffItem.Cooldown;
|
||
-- 发送 RPC
|
||
self:SendRPC("Client_AddBuff", BuffItem.Buff.OwnerPlayerKey, BuffItem.Buff.BuffType, EBuffState.Cooling, {
|
||
StartTime = self.OwnerBuffs[BuffItem.Buff.BuffType][BuffItem.Buff.OwnerPlayerKey].StartTime,
|
||
EndTime = self.OwnerBuffs[BuffItem.Buff.BuffType][BuffItem.Buff.OwnerPlayerKey].EndTime,
|
||
});
|
||
else
|
||
self:ResetBuff(BuffItem);
|
||
end
|
||
end
|
||
|
||
---@param BuffType EBuffType
|
||
---@param InPlayerKey PlayerKey
|
||
---@return bool
|
||
function BuffManager:RemoveBuff(BuffType, InPlayerKey)
|
||
local BuffItem = self:FindBuffItem(BuffType, InPlayerKey);
|
||
if BuffItem then
|
||
self:RemoveBuff_Internal(InPlayerKey, BuffItem);
|
||
return true;
|
||
end
|
||
return false;
|
||
end
|
||
|
||
--- 重置 Buff
|
||
---@param BuffItem BuffScriptItem
|
||
function BuffManager:ResetBuff(BuffItem)
|
||
BuffItem.State = EBuffState.None;
|
||
-- 执行初始化
|
||
if table.hasFunc(BuffItem.Buff, "Reset") then
|
||
table.func(BuffItem.Buff, "Reset", self.Config[BuffItem.Buff.BuffType].Params);
|
||
else
|
||
table.func(BuffItem.Buff, "Init", self.Config[BuffItem.Buff.BuffType].Params);
|
||
end
|
||
if IsServer then
|
||
self:SendRPC("Client_AddBuff", BuffItem.Buff.OwnerPlayerKey, BuffItem.Buff.BuffType, EBuffState.None);
|
||
end
|
||
end
|
||
|
||
---@param BuffType EBuffType
|
||
---@param InPlayerKey PlayerKey
|
||
---@return bool
|
||
function BuffManager:UpdateBuff(BuffType, InPlayerKey, ...)
|
||
local BuffItem = self:FindBuffItem(BuffType, InPlayerKey)
|
||
return table.func(BuffItem.Buff, "UpdateBuff", ...)
|
||
end
|
||
|
||
--- 发送 RPC
|
||
function BuffManager:SendRPC(InFuncName, InPlayerKey, BuffType, ...)
|
||
if IsServer then
|
||
UnrealNetwork.CallUnrealRPC_Multicast_Unreliable(self.Owner, "SendBuffRPC", InFuncName, InPlayerKey, BuffType, ...);
|
||
end
|
||
end
|
||
|
||
---@param BuffType EBuffType
|
||
---@param InPlayerKey PlayerKey
|
||
function BuffManager:FindBuffItem(BuffType, InPlayerKey)
|
||
local Table = self.OwnerBuffs;
|
||
if Table[BuffType] then
|
||
if self:IsBuffForever(BuffType) then return Table[BuffType]; end
|
||
if InPlayerKey == nil then return Table[BuffType]; end
|
||
return Table[BuffType][InPlayerKey];
|
||
end
|
||
return nil;
|
||
end
|
||
|
||
---@param BuffType EBuffType
|
||
---@param InPlayerKey PlayerKey
|
||
---@return bool
|
||
function BuffManager:CanAddBuff(BuffType, InPlayerKey)
|
||
if self:IsBuffForever(BuffType) then return true; end
|
||
local Buff = self:FindBuffItem(BuffType, InPlayerKey);
|
||
if Buff ~= nil then
|
||
-- 检查一下是否是
|
||
return Buff.State == EBuffState.None;
|
||
end
|
||
return true;
|
||
end
|
||
|
||
function BuffManager:OnTick(dt, st)
|
||
if IsServer then
|
||
for BuffType, PlayerBuffs in pairs(self.OwnerBuffs) do
|
||
if not self:IsBuffForever(BuffType) then
|
||
for PlayerKey, BuffItem in pairs(PlayerBuffs) do
|
||
if BuffItem.EndTime <= st then
|
||
if BuffItem.State == EBuffState.Using then
|
||
self:RemoveBuff_Internal(PlayerKey, BuffItem);
|
||
UGCLogSystem.LogTree(string.format("[BuffManager:OnTick] BuffItem Using"), BuffItem)
|
||
elseif BuffItem.State == EBuffState.Cooling then
|
||
UGCLogSystem.LogTree(string.format("[BuffManager:OnTick] BuffItem Cooling"), BuffItem)
|
||
self:ResetBuff(BuffItem);
|
||
end
|
||
end
|
||
end
|
||
end
|
||
end
|
||
end
|
||
end
|
||
|
||
if not UE_SERVER then
|
||
---@type table<EBuffType, table<PlayerKey, UParticleSystemComponent>>
|
||
BuffManager.PlayerParticles = {};
|
||
function BuffManager:Client_AddBuff(InPlayerKey, BuffType, State, ...)
|
||
if InPlayerKey == nil or BuffType == nil then return; end
|
||
--UGCEventSystem.SendEvent(EventTypes.PlayerUseBuff, InPlayerKey, BuffType, State, ...);
|
||
if State == EBuffState.Using then
|
||
self:AddBuff(BuffType, InPlayerKey, ...);
|
||
if self.Config[BuffType].Particle ~= nil and string.len(self.Config[BuffType].Particle) > 0 then
|
||
UE.AsyncLoadObject_Cached(self.Config[BuffType].Particle, function(TargetObject)
|
||
local Pawn = UGCGameSystem.GetPlayerPawnByPlayerKey(InPlayerKey);
|
||
if UE.IsValidPawn(Pawn) then
|
||
if self.PlayerParticles[BuffType] == nil then self.PlayerParticles[BuffType] = {}; end
|
||
self.PlayerParticles[BuffType][InPlayerKey] = GameplayStatics.SpawnEmitterAttached(TargetObject, Pawn.Mesh, "", VectorHelper.VectorZero(), Pawn:K2_GetActorRotation(), Pawn:GetActorScale3D(), EAttachLocation.SnapToTargetIncludingScale, true);
|
||
end
|
||
end);
|
||
end
|
||
else
|
||
if State == EBuffState.Cooling then
|
||
UGCLogSystem.Log("[BuffManager:Client_AddBuff] 移除")
|
||
self:RemoveBuff(BuffType, InPlayerKey);
|
||
elseif State == EBuffState.None then
|
||
UGCLogSystem.Log("[BuffManager:Client_AddBuff] 重置");
|
||
local BuffItem = self:FindBuffItem(BuffType, InPlayerKey);
|
||
self:ResetBuff(BuffItem);
|
||
end
|
||
if self.PlayerParticles[BuffType] then
|
||
local Item = self.PlayerParticles[BuffType][InPlayerKey]
|
||
if Item ~= nil and UE.IsValid(Item) then
|
||
Item:SetHiddenInGame(true, true);
|
||
end
|
||
end
|
||
end
|
||
end
|
||
|
||
---@param Image UImage
|
||
function BuffManager:ChangeBuffIcon(InBuffType, Image)
|
||
if Image == nil then return ; end
|
||
local Icon = self.Config[InBuffType].Icon;
|
||
if Icon ~= nil and string.len(Icon) > 0 then
|
||
UE.AsyncLoadObject_Cached(Icon, function(TargetObject)
|
||
UGCLogSystem.Log("[BuffManager:ChangeBuffIcon] 加载成功")
|
||
Image:SetBrushFromTexture(TargetObject);
|
||
end);
|
||
end
|
||
end
|
||
end
|
||
|
||
function BuffManager:GetBuffName(BuffType)
|
||
return self.Config[BuffType].Name;
|
||
end
|
||
|
||
return BuffManager; |