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

444 lines
16 KiB
Lua

---@class BP_PoisonSystem_C:AActor
---@field DefaultSceneRoot USceneComponent
---@field InnerClass UClass
---@field OuterClass UClass
---@field CenterActorClass UClass
--Edit Below--
require("Script.Blueprint.XinHaoQuan.PoisonConfig")
local BP_PoisonSystem = {};
PoisonCircleState = PoisonCircleState or {
NON_START = 1, -- 未开始
PREPARE = 2, -- 准备开始,此时已经设置显示了
RUNNING = 3, -- 正在运行中
ENDED = 4, -- 结束了
};
--- 设置为未开始
BP_PoisonSystem.CurrState = PoisonCircleState.NON_START;
BP_PoisonSystem.CachedState = PoisonCircleState.NON_START;
--- 配置选项
BP_PoisonSystem.ConfigIndex = 1;
---@type table<int32, CircleConfigItem> 存一份的配置
BP_PoisonSystem.Config = {};
--- 外圈索引
BP_PoisonSystem.OuterIndex = 1;
--- 内圈索引
BP_PoisonSystem.InnerIndex = 2;
---@type BP_Poison_Outer_C 外层的 Actor
BP_PoisonSystem.OuterActor = nil;
---@type BP_Poison_Inner_C 内层的 Actor
BP_PoisonSystem.InnerActor = nil;
---@type table<int32, AActor> 中心点Actor 列表
BP_PoisonSystem.CenterActors = {};
--- 选择的中心点索引
BP_PoisonSystem.SelectCenterIndex = 0;
--- 记录一下开始移动的起始时间
BP_PoisonSystem.StartRunningTime = 0;
BP_PoisonSystem.CachedStartRunningTime = 0;
function BP_PoisonSystem:ReceiveBeginPlay()
self.SuperClass.ReceiveBeginPlay(self);
UGCLogSystem.Log("[BP_PoisonSystem:ReceiveBeginPlay] 执行")
UGCEventSystem.AddListener(EventTypes.MapLoadFinish, self.OnClientAlready, self);
end
---@param InIndex int32 状态索引
---@return string 状态名称
function BP_PoisonSystem:GetPoisonCircleStateName(InIndex)
for i, v in pairs(PoisonCircleState) do if v == InIndex then return i; end end
return '';
end
function BP_PoisonSystem:ReceiveTick(DeltaTime)
self.SuperClass.ReceiveTick(self, DeltaTime);
local CurrTime = UGCGameSystem.GameState:GetServerTime();
if CurrTime == nil then return end
if self.CachedState == PoisonCircleState.RUNNING or self.CurrState == PoisonCircleState.RUNNING then
if self.StartRunningTime > 0 then
local MoveTime = self.Config[self.OuterIndex].MoveTime
if CurrTime - self.StartRunningTime >= MoveTime then
if UGCGameSystem.IsServer() then
self.OuterIndex = self.InnerIndex;
if self.InnerIndex < table.getCount(self.Config) then
self.InnerIndex = self.InnerIndex + 1;
self:ChangeState(PoisonCircleState.PREPARE);
DOREPONCE(self, "InnerIndex");
self:SetActorCenterAndRadius_Internal(self.InnerActor, self.Config, self.InnerIndex)
else
self:ChangeState(PoisonCircleState.ENDED);
end
self:SetActorCenterAndRadius_Internal(self.OuterActor, self.Config, self.OuterIndex)
DOREPONCE(self, "OuterIndex");
self:StartPoison();
else
self:SetActorCenterAndRadius_Internal(self.OuterActor, self.Config, self.OuterIndex + 1)
if self.Config[self.InnerIndex + 1] == nil then
self.CachedState = PoisonCircleState.ENDED;
else
self.CachedState = PoisonCircleState.PREPARE;
self:SetActorCenterAndRadius_Internal(self.InnerActor, self.Config, self.InnerIndex + 1)
end
end
else
local TimeInterval = CurrTime - self.CachedStartRunningTime;
local Rate = TimeInterval / self.Config[self.OuterIndex].MoveTime
local TargetVec = VectorHelper.Sub(self.Config[self.InnerIndex].Center, self.Config[self.OuterIndex].Center)
local TargetLoc = VectorHelper.Add(self.Config[self.OuterIndex].Center, VectorHelper.MulNumber(TargetVec, Rate))
self:FindOuterInnerActor();
self.OuterActor:K2_SetActorLocation(TargetLoc);
local r = ((self.Config[self.InnerIndex].Radius - self.Config[self.OuterIndex].Radius) * Rate) + self.Config[self.OuterIndex].Radius
--UGCLogSystem.Log("[BP_PoisonSystem:ReceiveTick] r = %s", tostring(r))
self:SetTheActorSize(self.OuterActor, r);
end
end
elseif self.CurrState == PoisonCircleState.PREPARE then
end
self:TakePoisonDamage(DeltaTime);
end
--[[
function BP_PoisonSystem:ReceiveEndPlay()
self.SuperClass.ReceiveEndPlay(self);
end
--]]
function BP_PoisonSystem:GetReplicatedProperties()
return { "CurrState", "Lazy" }
, { "OuterIndex", "Lazy" }
, { "InnerIndex", "Lazy" }
, { "ConfigIndex", "Lazy" }
, { "StartRunningTime", "Lazy" }
, { "Config", "Lazy" }
end
function BP_PoisonSystem:OnRep_StartRunningTime()
UGCLogSystem.Log("[BP_PoisonSystem:OnRep_StartRunningTime] StartRunningTime = %s", tostring(self.StartRunningTime));
if self.StartRunningTime > 0 then self.CachedStartRunningTime = self.StartRunningTime; end
end
--[[
function BP_PoisonSystem:GetAvailableServerRPCs()
return
end
--]]
function BP_PoisonSystem:OnClientAlready()
UGCLogSystem.Log("[BP_PoisonSystem:OnClientAlready] 执行")
if UGCGameSystem.IsServer() then
if self.ConfigIndex == 0 then
self.ConfigIndex = 1;
DOREPONCE(self, "ConfigIndex");
end
self:FillConfig(true);
self:CheckPoisonConfig();
-- 设置到对应位置
--UE.RespawnAllPlayer(2);
else
self:ShowCircle(false);
end
end
---
function BP_PoisonSystem:StartPoison(InDelay, InCurrTime)
if self.CurrState == PoisonCircleState.ENDED then return end
if self.CurrState == PoisonCircleState.NON_START then self:ChangeState(PoisonCircleState.PREPARE); end
-- 显示出来
UGCLogSystem.Log("[BP_PoisonSystem:StartPoison] OuterIndex = %d, InnerIndex = %d", self.OuterIndex, self.InnerIndex);
local Delay = InDelay;
if UGCGameSystem.IsServer() then
if self.OuterIndex == 1 then
self:FillConfig(false);
end
Delay = self.Config[self.OuterIndex].Delay;
if self.Config[self.InnerIndex] == nil then self.InnerIndex = self.OuterIndex; end
local CurrTime = UGCGameSystem.GameState:GetServerTime()
self.StartRunningTime = CurrTime + Delay;
self.CachedStartRunningTime = self.StartRunningTime;
DOREPONCE(self, "StartRunningTime");
if self.OuterIndex == self.InnerIndex then
self:ChangeState(PoisonCircleState.ENDED);
return ;
else
UnrealNetwork.CallUnrealRPC_Multicast(self, "StartPoison", Delay, CurrTime);
end
else
if UGCGameSystem.GameState.RoundInfo.RoundState <= RoundState.InRound then
UITool.ShowTips("安全区还有 %s 秒开始刷新", tostring(InDelay));
end
self.CachedStartRunningTime = InDelay + InCurrTime;
end
UGCEventSystem.SetTimer(self, function()
if UGCGameSystem.IsServer() then
self:ChangeState(PoisonCircleState.RUNNING);
else
if UGCGameSystem.GameState.RoundInfo.RoundState == RoundState.InRound then
UITool.ShowTips("安全区开始刷新");
end
end
end, Delay);
end
function BP_PoisonSystem:FindCenters()
self.CenterActors = {};
UE.FindActorsByClass(self.CenterActorClass, self.CenterActors, function(InIndex, InActor)
if InActor:ActorHasTag("Poison") then return InActor.Index; end
return false;
end)
UGCLogSystem.LogTree(string.format("[BP_PoisonSystem:FindCenters] self.CenterActors ="), self.CenterActors)
end
--- 设置配置索引
function BP_PoisonSystem:SetConfigIndex(InIndex)
self.ConfigIndex = InIndex;
self:ResetPoison(true);
self:CheckPoisonConfig();
DOREPONCE(self, "ConfigIndex");
--self:FindOuterInnerActor();
if self.OuterActor then self.OuterActor:InitOuterPoison(); end
end
--- 重置毒圈系统
function BP_PoisonSystem:ResetPoison(IsForce)
self:ChangeState(PoisonCircleState.NON_START);
self.OuterIndex = 1;
self.InnerIndex = 2;
self.CachedState = PoisonCircleState.NON_START;
self.SelectCenterIndex = 0;
PoisonConfig.SelectIndex = -1;
self:FillConfig(true);
DOREPONCE(self, "OuterIndex");
DOREPONCE(self, "InnerIndex");
end
function BP_PoisonSystem:OnRep_InnerIndex()
if table.isEmpty(self.Config) then return ; end
if self.InnerActor == nil then return end
self:SetActorCenterAndRadius_Internal(self.InnerActor, self.Config, self.InnerIndex);
end
function BP_PoisonSystem:OnRep_OuterIndex()
if table.isEmpty(self.Config) then return ; end
if self.OuterActor == nil then return end
self:SetActorCenterAndRadius_Internal(self.OuterActor, self.Config, self.OuterIndex);
end
function BP_PoisonSystem:ChangeState(InState)
self.CurrState = InState;
self.CachedState = InState;
UGCLogSystem.Log("[BP_PoisonSystem:ChangeState] CurrState = %s", self:GetPoisonCircleStateName(InState));
DOREPONCE(self, "CurrState");
end
function BP_PoisonSystem:OnRep_CurrState()
UGCLogSystem.Log("[BP_PoisonSystem:OnRep_CurrState] CurrState = %d", self.CurrState);
if self.CurrState == PoisonCircleState.ENDED then
self:SetActorCenterAndRadius(#self.Config, #self.Config, self.Config);
end
self.CachedState = self.CurrState;
self:ShowCircle(self.CachedState ~= PoisonCircleState.NON_START);
end
--- 服务器找到即可,到时候在类里面进行设置
function BP_PoisonSystem:FindOuterInnerActor()
if self.InnerActor == nil then self.InnerActor = UE.FindActorByClass(self.InnerClass); end
if self.OuterActor == nil then self.OuterActor = UE.FindActorByClass(self.OuterClass); end
end
function BP_PoisonSystem:ShowCircle(IsShow)
--if self.OuterActor then self.OuterActor:SetShowCircle(IsShow); end
--if self.InnerActor then self.InnerActor:SetShowCircle(IsShow); end
end
---@param InActor AActor
---@param InIndex int32
function BP_PoisonSystem:SetTheActorLocation(InActor, InIndex)
InActor:K2_SetActorLocation(InIndex);
end
---@param InActor AActor
---@param InSize FVector
function BP_PoisonSystem:SetTheActorSize(InActor, InSize)
InActor:SetActorScale3D({ X = InSize, Y = InSize, Z = 1 });
end
--- 随机选择中心点
function BP_PoisonSystem:RandomSelectCenter()
if table.isEmpty(self.CenterActors) then self:FindCenters(); end
local TotalCount = table.getCount(self.CenterActors)
if TotalCount == 0 then return ; end
self.SelectCenterIndex = math.random(TotalCount);
PoisonConfig.SelectIndex = self.SelectCenterIndex;
UGCLogSystem.Log("[BP_PoisonSystem:RandomSelectCenter] self.SelectCenterIndex = %d", self.SelectCenterIndex);
-- 通知可以重生玩家了
end
---@param IsForce bool 是否是强制重置
function BP_PoisonSystem:FillConfig(IsForce)
if table.isEmpty(self.Config) then
UGCLogSystem.Log("[BP_PoisonSystem:FillConfig] self.ConfigIndex = %s", tostring(self.ConfigIndex))
self.Config = TableHelper.DeepCopyTable(PoisonConfig.CircleConfig[self.ConfigIndex]);
end
if IsForce == false and (self:CheckPoisonCenter() == true) then return ; end
if table.isEmpty(self.CenterActors) then self:FindCenters(); end
if self.SelectCenterIndex == 0 then self:RandomSelectCenter(); end
if self.SelectCenterIndex == 0 then return ; end
local Actor = self.CenterActors[self.SelectCenterIndex];
UGCLogSystem.Log("[BP_PoisonSystem:FillConfig] Index = %s, Actor = %s", tostring(self.SelectCenterIndex), UE.GetName(Actor));
if Actor == nil then return ; end
local FirstLocation = Actor:K2_GetActorLocation();
local BigRadius = 0;
for i = 1, table.getCount(self.Config) do
local Item = self.Config[i];
if Item == nil then return ; end
if IsForce or table.isEmpty(Item.Center) then
if i == 1 then
Item.Center = VectorHelper.ToLuaTable(FirstLocation);
else
Item.Center = math.randomCircleInCircle(FirstLocation, BigRadius * 100, Item.Radius * 100);
end
end
FirstLocation = VectorHelper.ToLuaTable(Item.Center);
BigRadius = Item.Radius;
end
UGCLogSystem.LogTree(string.format("[BP_PoisonSystem:FillConfig] self.Config ="), self.Config)
DOREPONCE(self, "Config");
end
---@return bool 是否所有中心点都就绪
function BP_PoisonSystem:CheckPoisonCenter()
for i, v in pairs(self.Config) do
if table.isEmpty(v.Center) then return false; end
end
return true;
end
--- 检查一下配置
function BP_PoisonSystem:CheckPoisonConfig(InConfigIndex, InConfig)
if UGCGameSystem.IsServer() then
for i, v in pairs(UGCGameSystem.GetAllPlayerController()) do
UnrealNetwork.CallUnrealRPC(v, self, "Client_CheckPoisonConfig", self.ConfigIndex, self.Config);
end
DOREPONCE(self, "Config");
end
self:SetActorCenterAndRadius(self.InnerIndex, self.OuterIndex, self.Config);
end
function BP_PoisonSystem:Client_CheckPoisonConfig(InIndex, InConfig)
self:SetActorCenterAndRadius(self.InnerIndex, self.OuterIndex, InConfig);
end
function BP_PoisonSystem:OnRep_Config()
if table.isEmpty(self.Config) then return end
PoisonConfig.CircleConfig[self.ConfigIndex] = self.Config;
self:Client_CheckPoisonConfig(self.ConfigIndex, self.Config);
end
function BP_PoisonSystem:SetActorCenterAndRadius(InInner, InOuter, InConfig)
if table.isEmpty(InConfig) then return ; end
self:FindOuterInnerActor();
self:SetActorCenterAndRadius_Internal(self.InnerActor, InConfig, InInner - (InConfig[InInner] and 0 or 1));
self:SetActorCenterAndRadius_Internal(self.OuterActor, InConfig, InOuter);
end
---@private
function BP_PoisonSystem:SetActorCenterAndRadius_Internal(InActor, InConfig, InIndex)
self:FindOuterInnerActor();
local Item = InConfig[InIndex]
if table.isEmpty(Item) or table.isEmpty(Item.Center) then
if table.isEmpty(Item.Center) then UGCLogSystem.Log("[BP_PoisonSystem:SetActorCenterAndRadius_Internal] Center 此时为空") end
return ;
end
UGCLogSystem.Log("[BP_PoisonSystem:SetActorCenterAndRadius_Internal] Item = %s", VectorHelper.ToString(Item.Center));
local Center = VectorHelper.ToLuaTable(Item.Center);
UGCLogSystem.LogTree(string.format("[BP_PoisonSystem:SetActorCenterAndRadius_Internal] Center ="), Center)
self:SetTheActorLocation(InActor, Center);
self:SetTheActorSize(InActor, Item.Radius);
end
---@return float
function BP_PoisonSystem:GetPoisonRadius()
return self.OuterActor:GetActorScale3D().X;
end
BP_PoisonSystem.CurrCountTime = 0;
BP_PoisonSystem.ConstCurrCountTime = 0.75;
--- 执行伤害
function BP_PoisonSystem:TakePoisonDamage(InDeltaTime)
if self.CurrState == PoisonCircleState.NON_START then return ; end
if not UGCGameSystem.IsServer() then return end
-- 检查是否存在 Outer Actor
if self.OuterActor ~= nil and UE.IsValid(self.OuterActor) then
self.CurrCountTime = self.CurrCountTime + InDeltaTime;
if self.CurrCountTime >= self.ConstCurrCountTime then
self.CurrCountTime = self.CurrCountTime - self.ConstCurrCountTime;
local Radius = self:GetPoisonRadius();
for i, v in pairs(UGCGameSystem.GetAllPlayerPawn()) do
local Dis = VectorHelper.GetActorDis2D(self.OuterActor, v);
if UE.IsValid(v) and v:IsAlive() and Dis > Radius * 100 then
local Damage = self.Config[self.OuterIndex].Damage * self.ConstCurrCountTime;
UGCLogSystem.Log("[BP_PoisonSystem:TakePoisonDamage] Damage = %s", Damage);
UGCGameSystem.ApplyDamage(v, Damage, nil, self, EDamageType.PoisonDamage);
end
end
end
else
-- 加载 Outer
self:FindOuterInnerActor();
end
end
---@return PoisonCircleState
function BP_PoisonSystem:GetCurrState() return self.CurrState; end
---@return float
function BP_PoisonSystem:GetPlayedTime() return UGCGameSystem.GameState:GetServerTime() - self.CachedStartRunningTime; end
--- 获取刷新的时间,前面的是现在已经刷新的时候,后面的是总刷新时间
---@return float, float
function BP_PoisonSystem:GetRefreshTime()
local MoveTime = self.Config[self.OuterIndex].MoveTime;
local PlayedTime = self:GetPlayedTime();
return PlayedTime > MoveTime and MoveTime or PlayedTime, MoveTime;
end
--- 获取在圈内的所有玩家
---@param InTable table<int32, UGCPlayerPawn_C> out
---@return table<int32, UGCPlayerPawn_C>
function BP_PoisonSystem:GetPawnsInCircle(InTable)
if InTable == nil then InTable = {}; end
for i, v in pairs(UGCGameSystem.GetAllPlayerPawn()) do
if v:IsAlive() then
if VectorHelper.GetActorDis2D(v, self.OuterActor) <= self:GetPoisonRadius() then table.insert(InTable, v); end
end
end
return InTable;
end
--- 获取在圈外的所有玩家
---@param InTable table<int32, UGCPlayerPawn_C> out
---@return table<int32, UGCPlayerPawn_C>
function BP_PoisonSystem:GetPawnsOutCircle(InTable)
if InTable == nil then InTable = {}; end
for i, v in pairs(UGCGameSystem.GetAllPlayerPawn()) do
if v:IsAlive() then
if VectorHelper.GetActorDis2D(v, self.OuterActor) > self:GetPoisonRadius() then table.insert(InTable, v); end
end
end
return InTable;
end
function BP_PoisonSystem:GetOuterActor()
if self.OuterActor == nil then self:FindOuterInnerActor(); end
return self.OuterActor;
end
function BP_PoisonSystem:GetInnerActor()
if self.InnerActor == nil then self:FindOuterInnerActor(); end
return self.InnerActor;
end
return BP_PoisonSystem;