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;
|