UGCProjects/GodOfWar/Script/Blueprint/PlaceItems/BP_PlaceModeManager.lua
2025-01-04 23:00:19 +08:00

763 lines
32 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.

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