763 lines
32 KiB
Lua
763 lines
32 KiB
Lua
---@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; |