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