2025-01-04 23:00:19 +08:00

378 lines
12 KiB
Lua
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.

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;