367 lines
12 KiB
Lua
367 lines
12 KiB
Lua
|
local Dir = "Script.Blueprint.SceneObj.Buff."
|
|||
|
|
|||
|
local BuffManager1 = {};
|
|||
|
|
|||
|
---@type table<PlayerKey, table<EBuffType, CustomBuffItem>>
|
|||
|
BuffManager1.Buffs = {};
|
|||
|
BuffManager1.PreScript = Dir .. "Script.Buff_";
|
|||
|
BuffManager1.Inits = {}; -- 初始化脚本存放地点
|
|||
|
BuffManager1.BuffTimes = {}; -- 初始化脚本存放地点
|
|||
|
|
|||
|
--- 初始化函数,
|
|||
|
function BuffManager1:Init(InOwner)
|
|||
|
-- 检查是否需要初始化操作,如果需要就在此初始化,比如呼吸回血
|
|||
|
self.Owner = InOwner;
|
|||
|
require('Script.Blueprint.SceneObj.Buff.BuffConfig')
|
|||
|
for i, v in pairs(BuffConfig) do
|
|||
|
if v.InitScript ~= nil then
|
|||
|
local Init = require(Dir .. 'Script.Init.BuffInit_' .. v.InitScript);
|
|||
|
self:SetParams(Init, i);
|
|||
|
self.Inits[i] = Init;
|
|||
|
table.func(Init, "Init", InOwner);
|
|||
|
end
|
|||
|
end
|
|||
|
GlobalTickTool:AddTick(self, self.OnTick);
|
|||
|
UGCLogSystem.Log("[BuffManager1:Init] 初始化成功")
|
|||
|
return true;
|
|||
|
end
|
|||
|
|
|||
|
function BuffManager1:SetParams(InItem, InBuffType)
|
|||
|
if not table.isEmpty(BuffConfig[InBuffType].Params) then
|
|||
|
for i, v in pairs(BuffConfig[InBuffType].Params) do
|
|||
|
InItem[i] = v; -- 拷贝一份
|
|||
|
end
|
|||
|
end
|
|||
|
InItem.BuffType = InBuffType;
|
|||
|
end
|
|||
|
|
|||
|
--- 添加 BUFF
|
|||
|
function BuffManager1:Add(InPlayerKey, InBuffType, ...)
|
|||
|
local Params = { ... };
|
|||
|
-- 查看里面有什么东西
|
|||
|
UGCLogSystem.LogTree(string.format("[BuffManager1:Add] Params ="), Params)
|
|||
|
if InBuffType == nil then return ; end
|
|||
|
assert(BuffConfig[InBuffType] ~= nil);
|
|||
|
local ServerTime = UE.GetServerTime();
|
|||
|
-- 服务器需要验证,查看玩家是否包含此 Buff
|
|||
|
local BuffItem = self:Get(InPlayerKey, InBuffType);
|
|||
|
if IsServer then
|
|||
|
if BuffItem then
|
|||
|
if BuffItem.State == EBuffState.Cooling then
|
|||
|
return false;
|
|||
|
elseif BuffItem.State == EBuffState.Using then
|
|||
|
return self:AddStack(InPlayerKey, InBuffType, ...);
|
|||
|
end
|
|||
|
end
|
|||
|
end
|
|||
|
-- 添加一个
|
|||
|
local Item = nil;
|
|||
|
if BuffItem then
|
|||
|
Item = BuffItem;
|
|||
|
else
|
|||
|
local ScriptBase = require(self.PreScript .. BuffConfig[InBuffType].Script);
|
|||
|
assert(ScriptBase ~= nil)
|
|||
|
if table.hasFunc(ScriptBase, 'new') then
|
|||
|
Item = table.func(ScriptBase, "new", InPlayerKey, ...)
|
|||
|
else
|
|||
|
Item = setmetatable({}, { __index = ScriptBase, __metatable = ScriptBase });
|
|||
|
end
|
|||
|
assert(Item ~= nil);
|
|||
|
self:SetParams(Item, InBuffType);
|
|||
|
-- 初始化操作
|
|||
|
table.func(Item, "Init");
|
|||
|
-- 在客户端生成
|
|||
|
local Continue = BuffConfig[InBuffType].Continue
|
|||
|
if Continue == nil then Continue = 0; end
|
|||
|
Item.Continue = Continue;
|
|||
|
Item.PlayerKey = InPlayerKey;
|
|||
|
local Cooldown = BuffConfig[InBuffType].Cooldown;
|
|||
|
if Cooldown == nil then Cooldown = 0; end
|
|||
|
Item.Cooldown = Cooldown;
|
|||
|
Item.OwnerManager = self;
|
|||
|
Item.BuffType = InBuffType;
|
|||
|
if not table.hasFunc(Item, "GetInit") then
|
|||
|
Item["GetInit"] = function(o) return o.OwnerManager:GetInit(o.BuffType); end
|
|||
|
end
|
|||
|
if self.Buffs[InPlayerKey] == nil then self.Buffs[InPlayerKey] = {}; end
|
|||
|
self.Buffs[InPlayerKey][InBuffType] = Item;
|
|||
|
Item.Stack = 0;
|
|||
|
Item.BuffStackTime = {};
|
|||
|
end
|
|||
|
Item.State = EBuffState.None;
|
|||
|
|
|||
|
-- 同步过去
|
|||
|
if IsServer then
|
|||
|
self:SendRPC("Add", InPlayerKey, InBuffType, ...); -- 获取服务器时间
|
|||
|
if Item.Continue < 0 or BuffConfig[InBuffType].bAuto then self:ApplyOne(InPlayerKey, InBuffType, ...) end
|
|||
|
else
|
|||
|
Item.Particle = BuffConfig[InBuffType].ClientInfo.Particle;
|
|||
|
Item['RemoveParticle'] = function(o)
|
|||
|
if type(o.Emitter) == 'table' then
|
|||
|
for i, Emitter in pairs(o.Emitter) do
|
|||
|
if Emitter and UE.IsValid(Emitter) then
|
|||
|
Emitter:SetHiddenInGame(true, true);
|
|||
|
Emitter:K2_DestroyComponent(Emitter);
|
|||
|
end
|
|||
|
end
|
|||
|
o.Emitter = {};
|
|||
|
elseif type(o.Emitter) ~= 'nil' then
|
|||
|
if o.Emitter and UE.IsValid(o.Emitter) then
|
|||
|
o.Emitter:SetHiddenInGame(true, true);
|
|||
|
o.Emitter:K2_DestroyComponent(o.Emitter);
|
|||
|
o.Emitter = nil;
|
|||
|
end
|
|||
|
end
|
|||
|
end
|
|||
|
Item['SpawnEmitterAttached'] = function(o, Pawn, Offset)
|
|||
|
o:RemoveParticle();
|
|||
|
local Emitter = UE.SpawnEmitterAttached(ObjectPath[o.Particle], Pawn, Offset);
|
|||
|
return Emitter
|
|||
|
end
|
|||
|
Item['SpawnEmitterAtLocation'] = function(o, Location)
|
|||
|
o:RemoveParticle();
|
|||
|
o.Emitter = UE.SpawnEmitterAtLocation(ObjectPath[o.Particle], Location);
|
|||
|
end
|
|||
|
end
|
|||
|
return true;
|
|||
|
end
|
|||
|
|
|||
|
--- 只有正在执行的时候可以添加,否则不可以添加
|
|||
|
function BuffManager1:AddStack(InPlayerKey, InBuffType, ...)
|
|||
|
return false;
|
|||
|
--local BuffItem = self:Get(InPlayerKey, InBuffType);
|
|||
|
--if BuffItem.Stack == nil or BuffItem.Stack >= BuffConfig[BuffItem.BuffType].MaxStack then return false, EBuffErrorType.OverStack; end
|
|||
|
--BuffItem.Stack = BuffItem.Stack + 1;
|
|||
|
--table.insert(BuffItem.BuffStackTime, UE.GetServerTime() + self:GetBuffContinue(InBuffType));
|
|||
|
--table.func(BuffItem, "AddStack", ...);-- 可以直接拿到 Stack 进行使用
|
|||
|
--if IsServer then
|
|||
|
-- self:SendRPC("AddStack", InPlayerKey, InBuffType, ...);
|
|||
|
--end
|
|||
|
--return true;
|
|||
|
end
|
|||
|
|
|||
|
--- 执行玩家身上所有的 BUFF
|
|||
|
function BuffManager1:Apply(InPlayerKey, ...)
|
|||
|
-- 查看是否有 Buff
|
|||
|
if table.isEmpty(self.Buffs[InPlayerKey]) then return false; end
|
|||
|
self:PrintBuff("Apply")
|
|||
|
local ServerTime = UE.GetServerTime();
|
|||
|
local Ret = false;
|
|||
|
for BuffType, BuffItem in pairs(self.Buffs[InPlayerKey]) do
|
|||
|
if (self:GetBuffContinue(BuffType) < 0) then
|
|||
|
UGCLogSystem.LogError("[BuffManager1:Apply] [WARNING] 在执行一个永久执行的 Buff:%s", TableHelper.printEnum(EBuffState, BuffType));
|
|||
|
end
|
|||
|
-- 只要有一个 true 就是 true
|
|||
|
if self:DoApply(InPlayerKey, BuffType, ...) then Ret = true; end
|
|||
|
end
|
|||
|
if IsServer then
|
|||
|
self:SendRPC("Apply", InPlayerKey, ...);
|
|||
|
end
|
|||
|
return Ret;
|
|||
|
end
|
|||
|
|
|||
|
function BuffManager1:DoApply(InPlayerKey, InBuffType, ...)
|
|||
|
local BuffItem = self:Get(InPlayerKey, InBuffType);
|
|||
|
if BuffItem == nil then return false; end
|
|||
|
local HitType = BuffConfig[InBuffType].HitType;
|
|||
|
UGCLogSystem.Log("[BuffManager1:DoApply] State = %s", TableHelper.printEnum(EBuffState, BuffItem.State));
|
|||
|
if BuffItem.State ~= EBuffState.Cooling then
|
|||
|
local Params = {};
|
|||
|
if HitType & EBuffHitType.Self ~= 0 then
|
|||
|
local Pawn = UGCGameSystem.GetPlayerPawnByPlayerKey(InPlayerKey);
|
|||
|
if UE.IsValidPawn(Pawn) then
|
|||
|
table.insert(Params, Pawn);
|
|||
|
end
|
|||
|
end
|
|||
|
if HitType & EBuffHitType.Location ~= 0 or HitType & EBuffHitType.Pawn ~= 0 then
|
|||
|
local Param = { ... };
|
|||
|
if not table.isEmpty(Param) then
|
|||
|
table.insert(Params, ...);
|
|||
|
end
|
|||
|
end
|
|||
|
if HitType & EBuffHitType.AllEnemy ~= 0 then
|
|||
|
UE.ForeachEnemyTeam(InPlayerKey, function(Pawn)
|
|||
|
table.insert(Params, Pawn);
|
|||
|
end)
|
|||
|
end
|
|||
|
if HitType & EBuffHitType.AllFriend ~= 0 then
|
|||
|
UE.ForeachSelfTeam(InPlayerKey, function(Pawn)
|
|||
|
table.insert(Params, Pawn);
|
|||
|
end, true);
|
|||
|
end
|
|||
|
local Success = false;
|
|||
|
if BuffItem.State == EBuffState.None then
|
|||
|
BuffItem.Params = Params;
|
|||
|
Success = BuffItem:AddBuff(table.unpackTable(Params));
|
|||
|
if BuffItem.Continue >= 0 then
|
|||
|
table.insert(BuffItem.BuffStackTime, UE.GetServerTime() + self:GetBuffContinue(InBuffType));
|
|||
|
end
|
|||
|
else
|
|||
|
Success = self:AddStack(InPlayerKey, InBuffType, table.unpackTable(Params));
|
|||
|
end
|
|||
|
BuffItem.State = EBuffState.Using;
|
|||
|
BuffItem.Stack = BuffItem.Stack + 1;
|
|||
|
if IsServer then
|
|||
|
else
|
|||
|
--if BuffConfig[InBuffType]. then end
|
|||
|
end
|
|||
|
return Success;
|
|||
|
end
|
|||
|
return false;
|
|||
|
end
|
|||
|
|
|||
|
function BuffManager1:ApplyOne(InPlayerKey, InBuffType, ...)
|
|||
|
self:PrintBuff("ApplyOne")
|
|||
|
if IsServer then
|
|||
|
self:SendRPC("ApplyOne", InPlayerKey, InBuffType, ...);
|
|||
|
end
|
|||
|
return self:DoApply(InPlayerKey, InBuffType, ...)
|
|||
|
end
|
|||
|
|
|||
|
function BuffManager1:OnTick(dt, st)
|
|||
|
for PlayerKey, PlayerList in pairs(self.Buffs) do
|
|||
|
for BuffType, BuffItem in pairs(PlayerList) do
|
|||
|
table.func(BuffItem, "Tick", dt, st);
|
|||
|
if IsServer then
|
|||
|
local StackTime = BuffItem.BuffStackTime
|
|||
|
if (not table.isEmpty(StackTime)) then
|
|||
|
-- 前多少个移除
|
|||
|
local RemoveIndex = 0;
|
|||
|
for i = 1, #StackTime do
|
|||
|
if StackTime[i] <= st then
|
|||
|
RemoveIndex = i;
|
|||
|
break ;
|
|||
|
end
|
|||
|
end
|
|||
|
if RemoveIndex > 0 then
|
|||
|
UGCLogSystem.LogTree(string.format("[BuffManager1:OnTick] StackTime 111"), StackTime);
|
|||
|
for i = 1, RemoveIndex do
|
|||
|
table.remove(StackTime, 1);
|
|||
|
BuffItem.Stack = BuffItem.Stack - 1;
|
|||
|
table.func(BuffItem, "RemoveStack");
|
|||
|
end
|
|||
|
UGCLogSystem.LogTree(string.format("[BuffManager1:OnTick] StackTime 222"), StackTime);
|
|||
|
end
|
|||
|
if table.isEmpty(BuffItem.BuffStackTime) and BuffItem.State == EBuffState.Using and (self:GetBuffContinue(BuffType) >= 0) then
|
|||
|
-- 执行移除
|
|||
|
UGCLogSystem.LogTree(string.format("[BuffManager1:OnTick] StackTime 333"), StackTime);
|
|||
|
self:Remove(PlayerKey, BuffType);
|
|||
|
end
|
|||
|
end
|
|||
|
end
|
|||
|
end
|
|||
|
end
|
|||
|
end
|
|||
|
|
|||
|
function BuffManager1:Has(InPlayerKey, InBuffType)
|
|||
|
local BuffItem = self:Get(InPlayerKey, InBuffType);
|
|||
|
return BuffItem ~= nil;
|
|||
|
end
|
|||
|
|
|||
|
function BuffManager1:CanAdd(InPlayerKey, InBuffType)
|
|||
|
local BuffItem = self:Get(InPlayerKey, InBuffType);
|
|||
|
if BuffItem == nil then return true end
|
|||
|
return BuffItem.State ~= EBuffState.Cooling;
|
|||
|
end
|
|||
|
|
|||
|
--- 移除 Buff
|
|||
|
function BuffManager1:Remove(InPlayerKey, InBuffType, ...)
|
|||
|
UGCLogSystem.Log("[BuffManager1:Remove] BuffType = %s", TableHelper.printEnum(EBuffType, InBuffType));
|
|||
|
if self.Buffs[InPlayerKey] == nil then return ; end
|
|||
|
self:PrintBuff("Remove");
|
|||
|
local Params = { ... };
|
|||
|
local BuffItem = self.Buffs[InPlayerKey][InBuffType]
|
|||
|
if BuffItem then
|
|||
|
table.func(BuffItem, "RemoveBuff", table.unpackTable(BuffItem.Params));
|
|||
|
BuffItem.State = EBuffState.Cooling; -- 延迟中
|
|||
|
end
|
|||
|
if IsServer then self:SendRPC("Remove", InPlayerKey, InBuffType, ...); end
|
|||
|
local Cooldown = BuffItem.Cooldown;
|
|||
|
if Cooldown == nil then Cooldown = 0; end
|
|||
|
UGCLogSystem.Log("[BuffManager1:Remove] Cooldown = %f", Cooldown)
|
|||
|
if Cooldown >= 0 then
|
|||
|
GlobalTickTool:AddTick(self, function() end, 0, nil, Cooldown, function(o)
|
|||
|
o:Reset(InPlayerKey, InBuffType, table.unpackTable(Params)); -- 如果完全不想要的话,可以直接 Clear
|
|||
|
end);
|
|||
|
end
|
|||
|
end
|
|||
|
|
|||
|
function BuffManager1:RemoveAll(InPlayerKey)
|
|||
|
|
|||
|
end
|
|||
|
|
|||
|
--- 清除这个
|
|||
|
function BuffManager1:Clear(InPlayerKey, InBuffType, ...)
|
|||
|
UGCLogSystem.Log("[BuffManager1:Clear] InBuffType = %s", TableHelper.printEnum(EBuffType, InBuffType));
|
|||
|
if self.Buffs[InPlayerKey] == nil then return ; end
|
|||
|
local BuffItem = self.Buffs[InPlayerKey][InBuffType]
|
|||
|
if BuffItem then
|
|||
|
table.func(BuffItem, "Clear", InPlayerKey, ...);
|
|||
|
BuffItem.State = EBuffState.None; -- 设置为空
|
|||
|
end
|
|||
|
if IsServer then
|
|||
|
self:SendRPC("Clear", InPlayerKey, InBuffType, ...);
|
|||
|
end
|
|||
|
self.Buffs[InPlayerKey][InBuffType] = nil;
|
|||
|
end
|
|||
|
|
|||
|
function BuffManager1:Reset(InPlayerKey, InBuffType, ...)
|
|||
|
self:PrintBuff("Reset")
|
|||
|
if self.Buffs[InPlayerKey] == nil then return ; end
|
|||
|
local BuffItem = self.Buffs[InPlayerKey][InBuffType];
|
|||
|
if BuffItem then
|
|||
|
table.func(BuffItem, "Reset", InPlayerKey, ...)
|
|||
|
BuffItem.State = EBuffState.None;
|
|||
|
end
|
|||
|
if IsServer then
|
|||
|
self:SendRPC("Reset", InPlayerKey, InBuffType, ...);
|
|||
|
end
|
|||
|
if BuffConfig[InBuffType].bAutoDestroy then
|
|||
|
self.Buffs[InPlayerKey][InBuffType] = nil;
|
|||
|
end
|
|||
|
end
|
|||
|
|
|||
|
function BuffManager1:PrintBuff(fmt, ...)
|
|||
|
UGCLogSystem.Log("[BuffManager1:PrintBuff] [%0.2f]" .. fmt, UE.GetServerTime(), ...)
|
|||
|
end
|
|||
|
|
|||
|
function BuffManager1:GetInit(InBuffType)
|
|||
|
return self.Inits[InBuffType];
|
|||
|
end
|
|||
|
|
|||
|
--- 获取 BuffItem
|
|||
|
---@param InPlayerKey PlayerKey
|
|||
|
---@param InBuffType EBuffType
|
|||
|
function BuffManager1:Get(InPlayerKey, InBuffType)
|
|||
|
if self.Buffs[InPlayerKey] == nil then return nil; end
|
|||
|
return self.Buffs[InPlayerKey][InBuffType];
|
|||
|
end
|
|||
|
|
|||
|
function BuffManager1:SendRPC(InFuncName, InPlayerKey, InBuffType, ...)
|
|||
|
if IsServer then
|
|||
|
UnrealNetwork.CallUnrealRPC_Multicast(self.Owner, "SendBuffRPC", InFuncName, InPlayerKey, InBuffType, ...);
|
|||
|
else
|
|||
|
-- 最好不要使用 客户端 的,一般情况下也用不到
|
|||
|
UnrealNetwork.CallUnrealRPC(LocalPlayerController, self.Owner, "SendBuffRPC", InFuncName, InPlayerKey, InBuffType, ...);
|
|||
|
end
|
|||
|
end
|
|||
|
|
|||
|
function BuffManager1:GetBuffContinue(InBuffType)
|
|||
|
local Continue = BuffConfig[InBuffType].Continue
|
|||
|
if Continue == nil then return 0; end
|
|||
|
return Continue;
|
|||
|
end
|
|||
|
|
|||
|
function BuffManager1:PrintBuffs()
|
|||
|
UGCLogSystem.LogTree(string.format("[BuffManager1:PrintBuffs] Buffs ="), self.Buffs)
|
|||
|
end
|
|||
|
|
|||
|
function BuffManager1:IsBuffActive(InBuffType)
|
|||
|
local Config = BuffConfig[InBuffType]
|
|||
|
if Config then
|
|||
|
return not Config.bAuto
|
|||
|
end
|
|||
|
return false
|
|||
|
end
|
|||
|
|
|||
|
return BuffManager1;
|