UGCProjects/TwoOnTwo/Script/Blueprint/PlaceItems/BP_PlaceModeManager.lua

763 lines
32 KiB
Lua
Raw Normal View History

2025-01-04 23:00:19 +08:00
---@class BP_PlaceModeManager_C:AActor
---@field PointToWidget UWidgetComponent
---@field DefaultSceneRoot USceneComponent
require("Script.Blueprint.PlaceItems.PlacementModeConfig")
--Edit Below--
local BP_PlaceModeManager = {
-- 放置值
PlaceValue = 0;
-- 当前已放置的物体 {{Type = uint, ID = uint, Pos = {XYZ}, Rot = {RPY}}, ...}
PlacedItemCount = {};
-- 是否已开启放置模式
PlaceMode = PlacementModeConfig.EPlaceMode.None;
-- 当前是否为使用场景摄像机进行放置物体
bIsSceneCamera = false;
-- 所有放置物 {Type = {Actor*, ...}, ...}
AllPlaceItems = {};
-- 客户端预览放置的Actor
AllPreviewActor = {};
AddPreviewQuat = {X=0,Y=0,Z=0,W=1};
-- 所有可放置区间Actor
AllPlaceableAreaActors = {};
-- 预导入的地图 [PlayerKey] = Code
PreUsePlayerPlaceItemCode = {};
};
function BP_PlaceModeManager:GetReplicatedProperties()
return
"PlaceValue",
"PlacedItemCount"
end
-- OnRep --------------------------------------------------------------------------------------------
function BP_PlaceModeManager:OnRep_PlaceValue()
if self == nil then return end
UGCEventSystem.SendEvent(EventEnum.UpdatePlaceValue)
end
function BP_PlaceModeManager:OnRep_PlacedItemCount()
if self == nil then return end
UGCEventSystem.SendEvent(EventEnum.UpdatePlacedItemCount, self.PlacedItemCount)
end
-- OnRep End ----------------------------------------------------------------------------------------
function BP_PlaceModeManager:ReceiveBeginPlay()
self.SuperClass.ReceiveBeginPlay(self);
UGCLogSystem.Log("[BP_PlaceModeManager_ReceiveBeginPlay]")
self:UpdatePlaceableArea()
if UGCGameSystem.IsServer() then
self:InitAllPlaceItemsList()
if PlacementModeConfig.PlacingAttr.IsObjectPoolPlace then
self:SpawnPlaceItem()
end
else
self:SetPointToWidgetVis(false)
if PlacementModeConfig.IsPlaceMode() then
self:SpawnPreviewItem()
end
end
UGCLogSystem.Log("[BP_PlaceModeManager_ReceiveBeginPlay] Finish")
end
BP_PlaceModeManager.LastTraceTime = 0;
BP_PlaceModeManager.LastRemoveTraceTime = 0;
function BP_PlaceModeManager:ReceiveTick(DeltaTime)
self.SuperClass.ReceiveTick(self, DeltaTime);
if UGCGameSystem.IsServer() then
if self.PlaceMode ~= PlacementModeConfig.EPlaceMode.None then
self:TickUpdatePlaceValue()
end
else
if self:IsPlaceMode() then
self.LastTraceTime = self.LastTraceTime + DeltaTime
if self.LastTraceTime > PlacementModeConfig.PlacingAttr.CheckPosTimeInterval then
self.LastTraceTime = 0
-- 获取检测点位并预览
UGCLogSystem.Log("[BP_PlaceModeManager_ReceiveTick] CheckPlacePos")
self:CheckPlacePos()
end
elseif self:IsRemoveMode() then
self.LastRemoveTraceTime = self.LastRemoveTraceTime + DeltaTime
if self.LastRemoveTraceTime > PlacementModeConfig.PlacingAttr.CheckRemoveItemTimeInterval then
self.LastRemoveTraceTime = 0
-- 获取检测点位并预览
self:CheckRemoveItem()
end
end
end
end
function BP_PlaceModeManager:ReceiveEndPlay()
-- 销毁生成物
for i, v in pairs(self.AllPlaceItems) do
if UE.IsValid(v) then
v:K2_DestroyActor()
end
end
for i, v in pairs(self.AllPreviewActor) do
if UE.IsValid(v) then
v:K2_DestroyActor()
end
end
self.SuperClass.ReceiveEndPlay(self);
end
-- 生成函数 --------------------------------------------------------------------------------------------
--- 对象池生成放置物
function BP_PlaceModeManager:SpawnPlaceItem()
for Type, v in pairs(PlacementModeConfig.ItemInfo) do
self.AllPlaceItems[Type] = {}
local ItemClass = UE.LoadClass(v.ItemPath)
for i = 1, v.MaxCount do
local PlaceItemInst = UGCGameSystem.SpawnActor(self, ItemClass, PlacementModeConfig.PlacingAttr.SpawnPos, VectorHelper.RotZero(), VectorHelper.ScaleOne())
PlaceItemInst:SetPlaceItemType(Type)
self.AllPlaceItems[Type][i] = PlaceItemInst
end
end
end
--- 客户端生成预览物
function BP_PlaceModeManager:SpawnPreviewItem()
for Type, v in pairs(PlacementModeConfig.ItemInfo) do
self.AllPlaceItems[Type] = {}
local ItemClass = UE.LoadClass(v.PreviewItemPath)
self.AllPreviewActor[Type] = UGCGameSystem.SpawnActor(self, ItemClass, PlacementModeConfig.PlacingAttr.SpawnPos, VectorHelper.RotZero(), VectorHelper.ScaleOne())
end
end
--- 获取未使用的放置物 仅对象池生成模式有效
function BP_PlaceModeManager:GetUnPlaceItemFromItemType(PlaceItemType)
if self.AllPlaceItems[PlaceItemType] then
for i, v in pairs(self.AllPlaceItems[PlaceItemType]) do
if not v:GetIsPlaced() then
return v
end
end
end
return nil
end
-- 生成函数 End ----------------------------------------------------------------------------------------
--- 开启放置模式类型
---@param InPlaceMode EPlaceMode
function BP_PlaceModeManager:SetPlaceMode(InPlaceMode)
if self.PlaceMode ~= InPlaceMode then
self.PlaceMode = InPlaceMode
UGCEventSystem.SendEvent(EventEnum.PlaceModeChange, self.PlaceMode)
if self.PlaceMode == PlacementModeConfig.EPlaceMode.None then
self:SetPlaceItemType(-1)
self:SetPointToWidgetVis(false)
elseif self.PlaceMode == PlacementModeConfig.EPlaceMode.PlaceMode then
self:SetPlaceItemType(0)
self:SetPointToWidgetVis(false)
elseif self.PlaceMode == PlacementModeConfig.EPlaceMode.RemoveMode then
self:SetPlaceItemType(-1)
end
end
end
function BP_PlaceModeManager:IsPlaceMode()
return self.PlaceMode == PlacementModeConfig.EPlaceMode.PlaceMode
end
function BP_PlaceModeManager:IsRemoveMode()
return self.PlaceMode == PlacementModeConfig.EPlaceMode.RemoveMode
end
function BP_PlaceModeManager:GetPlacementModeType()
return self.PlaceMode
end
-- 客户端预览 放置和移除 ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--- 检测放置位置
function BP_PlaceModeManager:CheckPlacePos()
local PreviewActor = self:GetPreviewPlaceActor()
if UE.IsValid(PreviewActor) then
UGCLogSystem.Log("[BP_PlaceModeManager_CheckPlacePos]")
self.TargetUnitPos, self.TargetUnitRot = self:GetPlacingPos()
PreviewActor:PlaceItem(self.TargetUnitPos, self.TargetUnitRot)
UGCLogSystem.Log("[BP_PlaceModeManager_CheckPlacePos] TargetUnitPos:%s, TargetUnitRot:%s", VectorHelper.ToString(self.TargetUnitPos), VectorHelper.RotToString(self.TargetUnitRot))
if self:ClientPlaceCondition() then
PlacementModeConfig.SetCanPlace(true)
else
PlacementModeConfig.SetCanPlace(false)
end
else
UGCLogSystem.LogError("[BP_PlaceModeManager_CheckPlacePos] PreviewActor:%s is nil.", tostring(self.PlaceItemType))
end
end
--- 获取本地摄像机控制器Actor
function BP_PlaceModeManager:GetLocalCameraManager()
if not UE.IsValid(self.CameraManager) then
self.CameraManager = UGCSystemLibrary.GetLocalPlayerController().PlayerCameraManager
end
return self.CameraManager
end
--- Client
--- 获取预放置的点位
function BP_PlaceModeManager:GetPlacingPos()
if not UE.IsValid(self:GetLocalCameraManager()) then
return
end
local StartPos = self.CameraManager:K2_GetActorLocation()
local Dir = self.CameraManager:GetActorForwardVector()
local EndPos = VectorHelper.Add(StartPos, VectorHelper.MulNumber(Dir, PlacementModeConfig.PlacingAttr.TraceDis))
--- HitResult:FHitResult
local bSucceed, HitResult = TraceManager.LineTraceSingleForObjects(self, StartPos, EndPos, PlacementModeConfig.PlacingAttr.TraceObjType, {self:GetPreviewPlaceActor(), UGCSystemLibrary.GetLocalPlayerPawn()}, PlacementModeConfig.PlacingAttr.EnableDrawDebug)
--local bSucceed, HitResult = TraceManager.SphereTraceSingleForObjects(self, StartPos, EndPos, 20, PlacementModeConfig.PlacingAttr.TraceObjType, {self:GetPreviewPlaceActor(), UGCSystemLibrary.GetLocalPlayerPawn()}, PlacementModeConfig.PlacingAttr.EnableDrawDebug)
local ImpactPoint, ImpactNormal = HitResult.ImpactPoint, HitResult.ImpactNormal
if not bSucceed then
ImpactPoint = EndPos
end
local TargetRot
local TargetPos = ImpactPoint
local ImpactRot = KismetMathLibrary.MakeRotFromZ(ImpactNormal)
local PreviewPlaceActor = self:GetPreviewPlaceActor()
if not PreviewPlaceActor:GetIsRotateAlignment() then
TargetRot = QuatHelper.QuatToRot(self.AddPreviewQuat)
ImpactRot = VectorHelper.RotZero()
local AllVertexPreviewRelativePos = PreviewPlaceActor:GetAllVertexPreviewRelativePos(TargetRot)
-- UGCLogSystem.LogTree("[BP_PlaceModeManager_GetPlacingPos] AllVertexPreviewPos", AllVertexPreviewPos)
--if math.abs(ImpactNormal.Z - 1) > 0.01 and VectorHelper.Length2D(ImpactNormal) > 0.01 then
-- -- 只计算平面的距离
-- ImpactNormal.Z = 0
--
-- local MaxDis = 0;
-- for i, v in pairs(AllVertexPreviewRelativePos) do
-- local Dir2D = VectorHelper.MulNumber2D(v, -1)
-- local Dis2D = VectorHelper.Length2D(Dir2D)
-- --UGCLogSystem.Log("[BP_PlaceModeManager_GetPlacingPos] Dis2D:%s", tostring(Dis2D))
-- local CosVal = VectorHelper.CosineValue(Dir2D, ImpactNormal)
-- if CosVal > 0.1 then
-- MaxDis = math.max(MaxDis, CosVal * Dis2D)
-- end
-- end
-- --UGCLogSystem.Log("[BP_PlaceModeManager_GetPlacingPos] MaxDis:%s", tostring(MaxDis))
-- local UnitVectorImpactPoint = VectorHelper.MulNumber(ImpactNormal, 1. / VectorHelper.Length2D(ImpactNormal))
-- TargetPos = VectorHelper.Add(ImpactPoint, VectorHelper.MulNumber(UnitVectorImpactPoint, MaxDis))
--end
if math.abs(ImpactNormal.Z - 1) > 0.01 and VectorHelper.Length2D(ImpactNormal) > 0.01 then
local MaxDis = 0;
for i, v in pairs(AllVertexPreviewRelativePos) do
local PreDir = VectorHelper.MulNumber(v, -1)
local PreDis = VectorHelper.Length(PreDir)
local CosVal = VectorHelper.CosineValue(PreDir, ImpactNormal)
if CosVal > 0.1 then
MaxDis = math.max(MaxDis, CosVal * PreDis)
end
end
local UnitVectorImpactPoint = VectorHelper.MulNumber(ImpactNormal, 1. / VectorHelper.Length2D(ImpactNormal))
TargetPos = VectorHelper.Add(ImpactPoint, VectorHelper.MulNumber(UnitVectorImpactPoint, MaxDis))
end
else
TargetRot = QuatHelper.QuatToRot(QuatHelper.mul(QuatHelper.RotToQuat(ImpactRot), self.AddPreviewQuat))
end
return PlacementModeConfig.VectorToUnitVector(TargetPos), PlacementModeConfig.RotatorToUnitRotator(TargetRot)
end
--- Client
--- 获取指向的放置Actor
function BP_PlaceModeManager:CheckRemoveItem()
if not UE.IsValid(self:GetLocalCameraManager()) then
return
end
local StartPos = self.CameraManager:K2_GetActorLocation()
local Dir = self.CameraManager:GetActorForwardVector()
local EndPos = VectorHelper.Add(StartPos, VectorHelper.MulNumber(Dir, PlacementModeConfig.PlacingAttr.TraceRemoveDis))
local bSucceed, HitResult = TraceManager.LineTraceSingleForObjects(self, StartPos, EndPos, PlacementModeConfig.PlacingAttr.RemoveTraceObjType, {UGCSystemLibrary.GetLocalPlayerPawn()}, PlacementModeConfig.PlacingAttr.EnableDrawDebug)
if bSucceed then
local HitActor = HitResult.Actor:Get()
-- 判断标签或者类型
if HitActor:ActorHasTag(PlacementModeConfig.PlaceItemTag) or UE.IsA(HitActor, PlacementModeConfig.GetPlaceItemBaseClass()) then
self:SetPointToWidgetVis(true)
local PointPos
if PlacementModeConfig.ItemInfo[HitActor:GetPlaceItemType()].RemovePointToActor then
PointPos = HitActor:K2_GetActorLocation()
else
local Origin,BoxExtent = HitActor:GetActorBounds()
PointPos = Origin
end
self:SetPointToWidgetPos(PointPos)
self.TargetRemoveItem = HitActor
return HitActor
end
end
self:SetPointToWidgetVis(false)
self.TargetRemoveItem = nil
return nil
end
--- Client
--- 设置指向UI的显示
function BP_PlaceModeManager:SetPointToWidgetVis(IsShow)
if IsShow then
self.PointToWidget:GetUserWidgetObject():SetVisibility(ESlateVisibility.SelfHitTestInvisible)
else
self.PointToWidget:GetUserWidgetObject():SetVisibility(ESlateVisibility.Collapsed)
end
end
function BP_PlaceModeManager:SetPointToWidgetPos(InPos)
self.PointToWidget:K2_SetWorldLocation(InPos)
end
--- 获取当前预览放置物的Actor
function BP_PlaceModeManager:GetPreviewPlaceActor()
return self.AllPreviewActor[self.PlaceItemType]
end
--- 重置预览Actor的位置
function BP_PlaceModeManager:ResetPreviewActorPos()
local PreviewActor = self:GetPreviewPlaceActor()
if UE.IsValid(PreviewActor) then
PreviewActor:K2_SetActorLocation(PlacementModeConfig.PlacingAttr.SpawnPos)
end
end
--- 客户端设置当前预览放置物的类型
function BP_PlaceModeManager:SetPlaceItemType(InPlaceItemType)
self:ResetPreviewActorPos()
self.PlaceItemType = InPlaceItemType
UGCEventSystem.SendEvent(EventEnum.PlaceItemTypeIsChange, self.PlaceItemType)
end
function BP_PlaceModeManager:GetPlaceItemType()
return self.PlaceItemType
end
--- 设置旋转值
function BP_PlaceModeManager:SetAddPreviewQuat(InYaw)
self.AddPreviewQuat = QuatHelper.RotToQuat({Roll = 0, Pitch = 0, Yaw = InYaw})
end
--- 重置旋转
function BP_PlaceModeManager:ResetAddPreviewQuat()
self.AddPreviewQuat = QuatHelper.RotToQuat({Roll = 0, Pitch = 0, Yaw = 0})
end
-- 客户端预览 放置和移除 End ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- 放置 ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--- 客户端判断放置条件
---@return bool
function BP_PlaceModeManager:ClientPlaceCondition()
if self:GetPreviewPlaceActor():IsOverlappingPlayer() then
return false
end
local Pos = PlacementModeConfig.UnitVectorToVector(self.TargetUnitPos)
local LineOfDefense = PlacementModeConfig.GetSimpleLineOfDefense()
if UE.IsValid(LineOfDefense) then
local LineOfDefensePos = LineOfDefense:K2_GetActorLocation()
if math.abs(LineOfDefensePos.Z - Pos.Z) < PlacementModeConfig.PlacingAttr.LineOfDefenseHeight and VectorHelper.Length2D(VectorHelper.Sub2D(LineOfDefensePos, Pos)) < PlacementModeConfig.PlacingAttr.LineOfDefenseRadius then
return false
end
end
for i, v in pairs(self.AllPlaceableAreaActors) do
if v:InPlaceableArea(Pos) then
return true
end
end
return false
end
--- 获取玩家可放置某物体的数量
--function BP_PlaceModeManager:GetPlayerPlaceItemCount(PlayerKey, InItemType)
-- local ItemIncrement = ArchiveDataConfig.GetPlayerArchiveDataFromType(PlayerKey, ArchiveDataConfig.EArchiveType.ItemIncrement)
-- local ItemInfo = PlacementModeConfig.ItemInfo[InItemType]
-- if ItemIncrement and ItemIncrement[InItemType] then
-- return math.clamp(ItemIncrement[InItemType] + ItemInfo.InitialCount, 0, ItemInfo.MaxCount)
-- end
-- return ItemInfo.InitialCount
--end
--- 获取单人放置模式时的玩家PC
function BP_PlaceModeManager:GetSimplePlayerPC()
return UGCGameSystem.GetAllPlayerController()[1]
end
--- 服务器判断放置条件
---@return bool
function BP_PlaceModeManager:ServerPlaceCondition(InPlayerKey, InPlaceItemType, UnitPos, IgnoreQuantityLimit)
-- 舒服进行数量限制判断
if IgnoreQuantityLimit ~= true then
-- 放置量满足
if PlacementModeConfig.ItemInfo[InPlaceItemType].Cost + self:GetPlaceValue() > PlacementModeConfig.GetPlaceMaxValue(InPlayerKey) then
if PlacementModeConfig.IsPlaceMode() then
UGCSendRPCSystem.RPCEvent(InPlayerKey, EventEnum.AddTip, TipConfig.TipType.PlaceFailure, PlacementModeConfig.EPlaceCallback.InsufficientPlaceValue)
end
UGCLogSystem.LogError("[BP_PlaceModeManager_ServerPlaceCondition] 放置量不满足 目标放置量:%s, 玩家的可放置量:%s", tostring(PlacementModeConfig.ItemInfo[InPlaceItemType].Cost + self:GetPlaceValue()), tostring(PlacementModeConfig.GetPlaceMaxValue(InPlayerKey)))
return false
end
-- 满足放置数量
if #self.AllPlaceItems[InPlaceItemType] >= PlacementModeConfig.GetPlayerPlaceItemCount(InPlayerKey, InPlaceItemType) then
if PlacementModeConfig.IsPlaceMode() then
UGCSendRPCSystem.RPCEvent(InPlayerKey, EventEnum.AddTip, TipConfig.TipType.PlaceFailure, PlacementModeConfig.EPlaceCallback.InsufficientNumberOfItem)
end
UGCLogSystem.LogError("[BP_PlaceModeManager_ServerPlaceCondition] 物体可放置数量不满足 当前该问题数量:%s, 玩家的物体最大放置量:%s", tostring(#self.AllPlaceItems[InPlaceItemType]), tostring(#self.AllPlaceItems[InPlaceItemType]))
return false
end
end
if not PlacementModeConfig.IsPlaceMode() then
return true
end
-- 下方仅为放置模式才做的判断 -----------------------------------------------------------------------------------------------------
local IsInArea = false
local Pos = PlacementModeConfig.UnitVectorToVector(UnitPos)
-- 判断是否在防线范围内
local LineOfDefense = PlacementModeConfig.GetSimpleLineOfDefense()
if UE.IsValid(LineOfDefense) then
local LineOfDefensePos = LineOfDefense:K2_GetActorLocation()
if math.abs(LineOfDefensePos.Z - Pos.Z) < PlacementModeConfig.PlacingAttr.LineOfDefenseHeight and VectorHelper.Length2D(VectorHelper.Sub2D(LineOfDefensePos, Pos)) < PlacementModeConfig.PlacingAttr.LineOfDefenseRadius then
UGCSendRPCSystem.RPCEvent(InPlayerKey, EventEnum.AddTip, TipConfig.TipType.PlaceFailure, PlacementModeConfig.EPlaceCallback.LocationNotWithinRange)
return false
end
end
-- 判断是否在可放置范围内
for i, v in pairs(self.AllPlaceableAreaActors) do
if v:InPlaceableArea(Pos) then
IsInArea = true
break
end
end
if not IsInArea then
UGCSendRPCSystem.RPCEvent(InPlayerKey, EventEnum.AddTip, TipConfig.TipType.PlaceFailure, PlacementModeConfig.EPlaceCallback.LocationNotWithinRange)
return false
end
return true
end
--- 客户端调用放置操作
function BP_PlaceModeManager:ClientPlace()
if self:ClientPlaceCondition() then
UGCSendRPCSystem.ActorRPCNotify(nil, self, "ServerPlace", UGCSystemLibrary.GetLocalPlayerKey(), self.PlaceItemType, self.TargetUnitPos, self.TargetUnitRot)
else
-- Tip放置失败的提示
UGCEventSystem.SendEvent(EventEnum.AddTip, TipConfig.TipType.PlaceFailure, PlacementModeConfig.EPlaceCallback.LocationNotWithinRange)
end
end
--- 服务器调用放置操作
---@param IgnoreQuantityLimit 忽略数量限制
function BP_PlaceModeManager:ServerPlace(InPlayerKey, InPlaceItemType, InTargetUnitPos, InTargetUnitRot, IgnoreQuantityLimit)
UGCLogSystem.Log("[BP_PlaceModeManager_ServerPlace] InPlayerKey:%s, InPlaceItemType:%s", tostring(InPlayerKey), tostring(InPlaceItemType))
self.PlaceItemType, self.TargetUnitPos, self.TargetUnitRot = InPlaceItemType, InTargetUnitPos, InTargetUnitRot
if self:ServerPlaceCondition(InPlayerKey, self.PlaceItemType, self.TargetUnitPos, IgnoreQuantityLimit) then
if PlacementModeConfig.PlacingAttr.IsObjectPoolPlace then
local UnPlaceItem = self:GetUnPlaceItemFromItemType(self.PlaceItemType)
if UE.IsValid(UnPlaceItem) then
UnPlaceItem:PlaceItem(self.TargetUnitPos, self.TargetUnitRot)
UGCLogSystem.Log("[BP_PlaceModeManager_ServerPlace] Succeed 1111")
end
else
if self.AllPlaceItems[self.PlaceItemType] == nil then
self.AllPlaceItems[self.PlaceItemType] = {}
end
local ItemPath = PlacementModeConfig.ItemInfo[self.PlaceItemType].ItemPath
local ItemClass = UE.LoadClass(ItemPath)
local PlaceItemInst = UGCGameSystem.SpawnActor(self, ItemClass, PlacementModeConfig.UnitVectorToVector(self.TargetUnitPos), PlacementModeConfig.UnitRotatorToRotator(self.TargetUnitRot), VectorHelper.ScaleOne())
PlaceItemInst:PlaceItem(self.TargetUnitPos, self.TargetUnitRot)
self.AllPlaceItems[self.PlaceItemType][#self.AllPlaceItems[self.PlaceItemType] + 1] = PlaceItemInst
UGCLogSystem.Log("[BP_PlaceModeManager_ServerPlace] Succeed 2222")
end
self:AddPlacedItem(self.PlaceItemType)
end
end
-- 放置End ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- 移除 ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--- 客户端判断移除的条件
---@return bool
function BP_PlaceModeManager:ClientRemoveItemCondition()
return UE.IsValid(self.TargetRemoveItem)
end
--- 服务器判断移除条件
---@return bool
function BP_PlaceModeManager:ServerRemoveItemCondition(InRemoveItem)
-- 如果是对象池生成模式还需要判断该物体上方是否有玩家 不然服务器会崩溃
-- Warning: [LuaException] OnLogLuaStack: Assertion failed:!bCurrentBaseHadBeenStatic
-- LogLinux: Error: [GIsGuarded:1]appError called: Assertion failed: !bCurrentBaseHadBeenStatic [File:D:\CG026\Survive\Source\ShadowTrackerExtra\Character\STCharacterMovementComponent.cpp] [Line: 4383]
--
return UE.IsA(InRemoveItem, PlacementModeConfig.GetPlaceItemBaseClass())
end
function BP_PlaceModeManager:ClientRemoveItem()
if self:ClientRemoveItemCondition() then
UGCSendRPCSystem.ActorRPCNotify(nil, self, "ServerRemoveItem", self.TargetRemoveItem)
else
UGCLogSystem.LogError("[BP_PlaceModeManager_ClientRemoveItem]")
end
end
function BP_PlaceModeManager:ServerRemoveItem(InRemoveItem)
if self:ServerRemoveItemCondition(InRemoveItem) then
local ItemType = InRemoveItem:GetPlaceItemType()
self:RemovePlacedItem(ItemType)
if PlacementModeConfig.PlacingAttr.IsObjectPoolPlace == false then
table.removeValue(self.AllPlaceItems[ItemType], InRemoveItem, true)
end
InRemoveItem:RecoveryItem()
else
UGCLogSystem.LogError("[BP_PlaceModeManager_ServerRemoveItem]")
end
end
function BP_PlaceModeManager:RemoveItemFromType(InItemType)
if self.AllPlaceItems[InItemType] then
for i = #self.AllPlaceItems[InItemType], 1, -1 do
self:ServerRemoveItem(self.AllPlaceItems[InItemType][i])
end
end
end
function BP_PlaceModeManager:ClearItem()
UGCLogSystem.Log("[BP_PlaceModeManager_ClearItem]")
for i, v in pairs(self.AllPlaceItems) do
for _, ItemInst in pairs(v) do
ItemInst:RecoveryItem()
end
end
if PlacementModeConfig.PlacingAttr.IsObjectPoolPlace == false then
self:InitAllPlaceItemsList()
end
self.PlacedItemCount = {}
self:UpdatePlaceValue()
end
function BP_PlaceModeManager:InitAllPlaceItemsList()
for i, v in pairs(EPlaceItemType) do
self.AllPlaceItems[v] = {}
end
end
-- 移除End ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- 放置量参数设置 ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--- 增加放置量
function BP_PlaceModeManager:AddPlacedItem(PlaceItemType)
if self.PlacedItemCount[PlaceItemType] == nil then
self.PlacedItemCount[PlaceItemType] = 0
end
self.PlacedItemCount[PlaceItemType] = self.PlacedItemCount[PlaceItemType] + 1
self:UpdatePlaceValue()
end
--- 减少放置量
function BP_PlaceModeManager:RemovePlacedItem(PlaceItemType)
self.PlacedItemCount[PlaceItemType] = self.PlacedItemCount[PlaceItemType] - 1
if self.PlacedItemCount[PlaceItemType] < 0 then
UGCLogSystem.LogError("[BP_PlaceModeManager_RemovePlacedItem] PlaceItemType:%s 数量小于0", tostring(PlaceItemType))
self.PlacedItemCount[PlaceItemType] = 0
end
self:UpdatePlaceValue()
end
function BP_PlaceModeManager:GetPlacedItemNum(PlaceItemType)
if self.PlacedItemCount[PlaceItemType] then
return self.PlacedItemCount[PlaceItemType]
end
return 0
end
function BP_PlaceModeManager:UpdatePlaceValue()
self.PlaceValue = 0
for i, v in pairs(self.PlacedItemCount) do
self.PlaceValue = self.PlaceValue + PlacementModeConfig.ItemInfo[i].Cost * v
end
self.bPlaceValueIsChange = true
end
function BP_PlaceModeManager:ClientUpdatePlaceValue(InPlaceValue, InPlacedItemCount)
self.PlaceValue = InPlaceValue
self.PlacedItemCount = InPlacedItemCount
UGCEventSystem.SendEvent(EventEnum.UpdatePlaceValue)
UGCEventSystem.SendEvent(EventEnum.UpdatePlacedItemCount, self.PlacedItemCount)
end
function BP_PlaceModeManager:GetPlaceValue()
return self.PlaceValue
end
BP_PlaceModeManager.LastNotifyPlaceValueTime = 0
BP_PlaceModeManager.NotifyTimeInterval = 1
function BP_PlaceModeManager:TickUpdatePlaceValue(DeltaTime)
self.LastNotifyPlaceValueTime = self.LastNotifyPlaceValueTime + DeltaTime
if self.bPlaceValueIsChange and self.LastNotifyPlaceValueTime > self.NotifyTimeInterval then
self.LastNotifyPlaceValueTime = 0;
self.bPlaceValueIsChange = false
UGCSendRPCSystem.ActorRPCNotify(nil, self, "ClientUpdatePlaceValue", self.PlaceValue, self.PlacedItemCount)
end
end
-- 放置量参数设置 End ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- 导出/导入放置代码 ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- 导出
function BP_PlaceModeManager:ExportPlacementCode()
return PlacementModeConfig.PlaceCodeEncode(self:GetNowMap())
end
-- 导入
---@param IgnoreQuantityLimit 忽略数量限制 为true则忽略
function BP_PlaceModeManager:ImportPlacementCode(InPlayerKey, InCode, IgnoreQuantityLimit)
if not UGCGameSystem.IsServer() then return end
if PlacementModeConfig.IsPlaceMode() then
UGCGameSystem.SendModeCustomEvent("ResetAllPlayers")
end
local DecodeResType, MapType, PlaceItemInfo = PlacementModeConfig.PlaceCodeDecode(InCode)
if PlacementModeConfig.IsPlaceMode() then
UGCSendRPCSystem.RPCEvent(nil, EventEnum.ImportPlacementCallBack, DecodeResType)
end
if DecodeResType == PlacementModeConfig.EPlaceDecodeCallback.Succeed then
UGCLogSystem.LogTree("[BP_PlaceModeManager_ImportPlacementCode] PlaceItemInfo:", PlaceItemInfo)
self:ClearItem()
self:LoadMap(MapType)
-- PlaceItemInfo:PlaceItemType, UnitPos, UnitRot
for i, v in pairs(PlaceItemInfo) do
self:ServerPlace(InPlayerKey, v.PlaceItemType, v.UnitPos, v.UnitRot, IgnoreQuantityLimit)
end
end
end
--- 强行加载玩家预放置的信息
function BP_PlaceModeManager:ForcefullyImportMap(InPlayerKey)
if self.PreUsePlayerPlaceItemCode[InPlayerKey] then
-- 强行导入
self:ImportPlacementCode(InPlayerKey, self.PreUsePlayerPlaceItemCode[InPlayerKey], true)
-- 重置
self.PreUsePlayerPlaceItemCode[InPlayerKey] = nil
end
end
--- 预导入地图
function BP_PlaceModeManager:PreImportPlacementCode(InPlayerKey, InCode)
local bCanUse, PlaceCount, DecodeResType, PlaceItemInfo = PlacementModeConfig.CheckPlayerCanUsePlaceCode(InCode, InPlayerKey)
if DecodeResType == PlacementModeConfig.EPlaceDecodeCallback.Succeed then
if bCanUse then
self:ImportPlacementCode(InPlayerKey, InCode)
else
self.PreUsePlayerPlaceItemCode[InPlayerKey] = InCode
UGCSendRPCSystem.ActorRPCNotify(InPlayerKey, self, "ShowForcefullyImportSecondaryConfirmation")
end
else
if PlacementModeConfig.IsPlaceMode() then
UGCSendRPCSystem.RPCEvent(nil, EventEnum.ImportPlacementCallBack, DecodeResType)
end
end
end
--- 给玩家二次确认是否要强行导入不可用的地图,只能在放置模式下使用
function BP_PlaceModeManager:ShowForcefullyImportSecondaryConfirmation()
local SecondaryConfirmationWidget = WidgetManager:GetPanel(WidgetConfig.EUIType.SecondaryConfirmation)
SecondaryConfirmationWidget:SetTextInfo("该地图已超出您的使用限制,即使保存也无法正常使用。是否强行导入该地图?", "取消", "强行导入")
SecondaryConfirmationWidget:BindConfirmCallBack(function()
UGCSendRPCSystem.ActorRPCNotify(nil, self, "ForcefullyImportMap", UGCSystemLibrary.GetLocalPlayerKey())
end)
WidgetManager:ShowPanel(WidgetConfig.EUIType.SecondaryConfirmation, false)
end
function BP_PlaceModeManager:ImportPlacementCodeCallBack(InDecodeResType)
UGCEventSystem.SendEvent(EventEnum.AddTip, InDecodeResType)
end
--- 加载已保存的放置地图
function BP_PlaceModeManager:LoadSavedPlaceMap(LoadType, Index)
UGCLogSystem.Log("[BP_PlaceModeManager_LoadSavedPlaceMap] LoadType:%s, Index:%s", tostring(LoadType), tostring(Index))
if UGCGameSystem.IsServer() then
if LoadType == PlacementModeConfig.LoadPlaceItemsType.SavedMap then
local SavedMapList = ArchiveDataConfig.GetPlayerArchiveDataFromType(UGCSystemLibrary.GetLocalPlayerKey(), ArchiveDataConfig.EArchiveType.SavedMap)
if SavedMapList and SavedMapList[Index] then
self:ImportPlacementCode(self:GetSimplePlayerPC().PlayerKey, SavedMapList[Index].MapCode)
end
elseif LoadType == PlacementModeConfig.LoadPlaceItemsType.None then
self:ClearItem()
elseif LoadType == PlacementModeConfig.LoadPlaceItemsType.Default then
self:ImportPlacementCode(self:GetSimplePlayerPC().PlayerKey, PlacementModeConfig.MapInfo[self:GetNowMap()].DefaultPlaceCode)
end
else
UGCSendRPCSystem.ActorRPCNotify(nil, self, "LoadSavedPlaceMap", LoadType, Index)
end
end
-- 导出/导入放置代码 End ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- 地图 ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
function BP_PlaceModeManager:GetNowMap()
return PlacementModeConfig.PlaceMapType.RelicDefenseLine
end
function BP_PlaceModeManager:LoadMap(InMapType)
end
--- 更新可放置位置Actor
function BP_PlaceModeManager:UpdatePlaceableArea()
if self.PlaceableAreaClass == nil then
self.PlaceableAreaClass = UE.LoadClass(PlacementModeConfig.PlaceableAreaPath)
end
if self.PlaceableAreaClass then
self.AllPlaceableAreaActors = GameplayStatics.GetAllActorsOfClass(UGCGameSystem.GameState, self.PlaceableAreaClass)
end
end
-- 地图 End ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
return BP_PlaceModeManager;