PlacementModeConfig = PlacementModeConfig or {} require('Script.Common.ue_enum_custom') -- 放置模式ModeID PlacementModeConfig.PlaceModeID = 1002; -- 游玩模式ModeID PlacementModeConfig.PlayModeID = 1001; -- 当前编解码使用的版本 PlacementModeConfig.PlaceCodeVersion = 1; -- 当玩家没有保存地图的情况下使用默认地图 PlacementModeConfig.GlobalDefaultPlaceCode = "1141E0P0000021J0M0000021I0M0100021H0M0200021G0M0300021F0M0400021E0M0500021D0M0600021C0M0700021B0M0800021B0N0800021D0N0600021A0M0900021A0L0900000@0W0100001E0Q0100001D0L0100001E0M0100000@0E0100001E0L0100001E0O0100000@0F0100000@0G0100000@0H0100000@0Z0100000@0Y0100001E0N0100000@0X0100000@0V0100000@0I0100001E0R0100001E0S0100001D0S010001180N000001180Q0000011B0T0000011B0K00000"; -- 放置物带有的ActorTag PlacementModeConfig.PlaceItemTag = "PlaceItem" -- Path -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- Manager PlacementModeConfig.PlaceManagerPath = UGCGameSystem.GetUGCResourcesFullPath('Asset/Blueprint/PlaceItems/BP_PlaceModeManager.BP_PlaceModeManager_C') -- ItemBase PlacementModeConfig.PlaceItemBasePath = UGCGameSystem.GetUGCResourcesFullPath('Asset/Blueprint/PlaceItems/BP_PlaceItemBase.BP_PlaceItemBase_C') -- 跑图的阻挡体Actor PlacementModeConfig.PassagewayBlockPath = UGCGameSystem.GetUGCResourcesFullPath('Asset/Blueprint/SceneActor/PlaceMode/BP_PassagewayBlock.BP_PassagewayBlock_C') -- 可放置范围Actor PlacementModeConfig.PlaceableAreaPath = UGCGameSystem.GetUGCResourcesFullPath('Asset/Blueprint/SceneActor/PlaceMode/BP_PlaceableArea.BP_PlaceableArea_C') -- 预览材质 PlacementModeConfig.PreviewMatPath = UGCGameSystem.GetUGCResourcesFullPath('Asset/Material/PlaceMat/MAT_ClientPreview.MAT_ClientPreview') -- 防线路径 PlacementModeConfig.LineOfDefensePath = UGCGameSystem.GetUGCResourcesFullPath('Asset/Blueprint/SceneActor/PlaceMode/BP_LineOfDefense.BP_LineOfDefense_C') -- Path End ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- PlacementModeConfig.PlacingAttr = { -- 采用对象池放置时可以减少性能开销,但不能设置为不可移动因此不能攀爬 IsObjectPoolPlace = false; -- 放置时单位点之间的距离 PositionSpacing = 100; -- 设置旋转时的单位旋转间隔 RotationSpacing = 90; -- 初始位置(即未放置时的单位位置) SpawnPos = {X = 0, Y = 0, Z = -3000}; -- 保存的地图上限 MaxSavedMapNum = 6; -- 保存的放置物命名utf-8字符串长度限制 PlaceMapNameLengthLimit = 6; -- 代码长度上限 MaxPlaceCodeLen = 800; ----------------------------TraceParam -- 启用检测时的绘制 EnableDrawDebug = false; -- 检测位置的时间间隔 CheckPosTimeInterval = 0.0; -- 检测位置的距离 TraceDis = 2000; -- 检测移除Item的距离 TraceRemoveDis = 5000; -- 移除时检测位置的时间间隔 CheckRemoveItemTimeInterval = 0.2; -- 检测放置的碰撞类型 TraceObjType = {ECollisionChannel.ECC_WorldStatic, ECollisionChannel.ECC_WorldDynamic}; -- 检测移除的碰撞类型 RemoveTraceObjType = {ECollisionChannel.ECC_WorldStatic, ECollisionChannel.ECC_WorldDynamic,}; -- 可放置的颜色 CanPlaceColor = {R=0.000000,G=1.000000,B=0.838520,A=1.000000}; -- 不可放置的颜色 CanNotPlaceColor = {R=1.000000,G=0.000000,B=0.000000,A=1.000000}; ----------------------------TraceParam End ----------------------------PlaceValue -- 基础放置量 BasePlaceValue = 100; -- 最大放置量 MaxPlaceValue = 300; -- 每级增加放置量 LevelUpPlaceValue = 2; ----------------------------PlaceValue End ---------------------------- LineOfDefense -- 每名玩家需要通过防线的次数 NumOfPlayerBreakingThroughDefenseLine = 3; -- 击杀得分 KillAddScore = 2; -- 助攻得分 AssistAddScore = 1; -- 防守成功得分 DefendSucceedAddScore = 30; -- 进入防线得分 EnterDefenseLineAddScore = 10; -- 距离防线2D半径内不可放置物体 LineOfDefenseRadius = 300; -- 高度不能在防线范围内 LineOfDefenseHeight = 500; ---------------------------- LineOfDefense End -- Shop --------------------------------------------------------- ---------------------------- subscription ratio -- 金币兑换Exp的比例 RatioGoldToExp = 1; -- 金砖兑换金币的比例 RatioGoldBrickToGold = 10; -- 绿洲币兑换金砖比例 RatioOasisCoinToGoldBrick = 1; ---------------------------- subscription ratio End -- 金砖购买名 GoldBrickName = "GoldBrick"; -- 单次购买数量 BuyGoldBrickCount = 100; -- Shop --------------------------------------------------------- } -- Enum ---------------------------------------------------------------------------------------------- -- 放置模式类型 PlacementModeConfig.EPlaceMode = { None = 1; PlaceMode = 2; RemoveMode = 3; } -- 放置是否成功的回调类型 PlacementModeConfig.EPlaceCallback = { Succeed = 1; InsufficientPlaceValue = 2; InsufficientNumberOfItem = 3; LocationNotWithinRange = 4; } -- 加载已保存放置物的类型 PlacementModeConfig.LoadPlaceItemsType = { None = 0, Default = 1, SavedMap = 2, } -- 放置地图类型 PlacementModeConfig.PlaceMapType = { RelicDefenseLine = 1; } -- 得分类型 PlacementModeConfig.AddScoreType = { KillAddScore = 1; -- 击杀得分 AssistAddScore = 2; -- 助攻得分 DefendSucceedAddScore = 3; -- 防守成功得分 EnterDefenseLineAddScore = 4; -- 进入防线得分 Dead = 5; -- 玩家死亡 } -- 放置代码导入反馈类型 PlacementModeConfig.EPlaceDecodeCallback = { Succeed = 1; -- 导入成功 VersionError = 2; -- 版本代码出错 CodeLengthError = 3; -- 代码长度异常 MapCodeError = 4; -- 地图类型错误 PlacePosRangeError = 5; -- 放置点位不在范围内 CharRangeError = 5; -- 代码字符存在异常字符 PlaceItemTypeError = 6; -- 放置物类型异常 } -- 解锁物体类型 PlacementModeConfig.EUnlockType = { None = 1; Level = 2; Gold = 3; GoldBrick = 4; } -- Enum End ------------------------------------------------------------------------------------------ -- 放置失败的回调名 PlacementModeConfig.PlaceCallbackName = { [PlacementModeConfig.EPlaceCallback.Succeed] = "放置成功"; [PlacementModeConfig.EPlaceCallback.InsufficientPlaceValue] = "放置空间不足"; [PlacementModeConfig.EPlaceCallback.InsufficientNumberOfItem] = "物品数量不足"; [PlacementModeConfig.EPlaceCallback.LocationNotWithinRange] = "该位置不在可放置范围内"; } -- 地图信息 PlacementModeConfig.MapInfo = { [PlacementModeConfig.PlaceMapType.RelicDefenseLine] = { MapName = "遗迹防线"; -- 跑图测试的时间上限 BreakThroughTestTime = 20; MapPlacingRange = {X = 2000, Y = 2000, Z = 2000}; DefaultPlaceCode = "1141E0P0000021J0M0000021I0M0100021H0M0200021G0M0300021F0M0400021E0M0500021D0M0600021C0M0700021B0M0800021B0N0800021D0N0600021A0M0900021A0L0900000@0W0100001E0Q0100001D0L0100001E0M0100000@0E0100001E0L0100001E0O0100000@0F0100000@0G0100000@0H0100000@0Z0100000@0Y0100001E0N0100000@0X0100000@0V0100000@0I0100001E0R0100001E0S0100001D0S010001180N000001180Q0000011B0T0000011B0K00000"; } } -- Item PlacementModeConfig.ItemInfo = { [EPlaceItemType.SmallBunker] = { Name = "小型掩体"; Desc = "可以挡子弹或作为踏板。"; ItemPath = UGCGameSystem.GetUGCResourcesFullPath('Asset/Blueprint/PlaceItems/Items/SmallBunker/BP_SmallBunker.BP_SmallBunker_C'); PreviewItemPath = UGCGameSystem.GetUGCResourcesFullPath('Asset/Blueprint/PlaceItems/Items/SmallBunker/BP_Preview_SmallBunker.BP_Preview_SmallBunker_C'); SelectTex = UGCGameSystem.GetUGCResourcesFullPath('Asset/Texture/PlaceItem/T_SmallBunker.T_SmallBunker'); MaxCount = 50; InitialCount = 20; Cost = 2; RemovePointToActor = false; -- 若为true则移除指针指向Actor根位置,反之则指向边框的中心点 IncrementInfo = { UnlockType = PlacementModeConfig.EUnlockType.Gold; Cost = 500; }; UnlockInfo = { UnlockType = PlacementModeConfig.EUnlockType.None; } }, [EPlaceItemType.BigBunker] = { Name = "大型掩体"; Desc = "比小型掩体大很多,可以阻挡敌人前进,在无协助攀爬的情况下无法直接爬上去。"; ItemPath = UGCGameSystem.GetUGCResourcesFullPath('Asset/Blueprint/PlaceItems/Items/BigBanker/BP_BigBunker.BP_BigBunker_C'); PreviewItemPath = UGCGameSystem.GetUGCResourcesFullPath('Asset/Blueprint/PlaceItems/Items/BigBanker/BP_Preview_BigBunker.BP_Preview_BigBunker_C'); SelectTex = UGCGameSystem.GetUGCResourcesFullPath('Asset/Texture/PlaceItem/T_BigBunker.T_BigBunker'); MaxCount = 10; InitialCount = 4; Cost = 5; RemovePointToActor = false; -- 若为true则移除指针指向Actor根位置,反之则指向边框的中心点 IncrementInfo = { UnlockType = PlacementModeConfig.EUnlockType.Gold; Cost = 1000; }; UnlockInfo = { UnlockType = PlacementModeConfig.EUnlockType.None; } }, [EPlaceItemType.Slope] = { Name = "斜坡木板"; Desc = "可快速走到一定的高度。"; ItemPath = UGCGameSystem.GetUGCResourcesFullPath('Asset/Blueprint/PlaceItems/Items/Slope/BP_Slope.BP_Slope_C'); PreviewItemPath = UGCGameSystem.GetUGCResourcesFullPath('Asset/Blueprint/PlaceItems/Items/Slope/BP_Preview_Slope.BP_Preview_Slope_C'); SelectTex = UGCGameSystem.GetUGCResourcesFullPath('Asset/Texture/PlaceItem/T_Slope.T_Slope'); MaxCount = 40; InitialCount = 15; Cost = 2; RemovePointToActor = false; -- 若为true则移除指针指向Actor根位置,反之则指向边框的中心点 IncrementInfo = { UnlockType = PlacementModeConfig.EUnlockType.Gold; Cost = 500; }; UnlockInfo = { UnlockType = PlacementModeConfig.EUnlockType.None; } }, [EPlaceItemType.Launch] = { Name = "蹦床"; Desc = "弹射玩家到一定的高度。"; ItemPath = UGCGameSystem.GetUGCResourcesFullPath('Asset/Blueprint/PlaceItems/Items/Launch/BP_Launch.BP_Launch_C'); PreviewItemPath = UGCGameSystem.GetUGCResourcesFullPath('Asset/Blueprint/PlaceItems/Items/Launch/BP_Preview_Launch.BP_Preview_Launch_C'); SelectTex = UGCGameSystem.GetUGCResourcesFullPath('Asset/Texture/PlaceItem/T_Launch.T_Launch'); MaxCount = 4; InitialCount = 0; Cost = 10; RemovePointToActor = true; -- 若为true则移除指针指向Actor根位置,反之则指向边框的中心点 IncrementInfo = { UnlockType = PlacementModeConfig.EUnlockType.Gold; Cost = 1500; }; UnlockInfo = { UnlockType = PlacementModeConfig.EUnlockType.Level; Cost = 3; } }, [EPlaceItemType.LandMine] = { Name = "地雷"; Desc = "进攻玩家走入范围内会发生爆炸,造成80点伤害,10s冷却。"; ItemPath = UGCGameSystem.GetUGCResourcesFullPath('Asset/Blueprint/PlaceItems/Items/LandMine/BP_LandMine.BP_LandMine_C'); PreviewItemPath = UGCGameSystem.GetUGCResourcesFullPath('Asset/Blueprint/PlaceItems/Items/LandMine/BP_Preview_LandMine.BP_Preview_LandMine_C'); SelectTex = UGCGameSystem.GetUGCResourcesFullPath('Asset/Texture/PlaceItem/T_LandMine.T_LandMine'); MaxCount = 6; InitialCount = 1; Cost = 15; RemovePointToActor = true; -- 若为true则移除指针指向Actor根位置,反之则指向边框的中心点 IncrementInfo = { UnlockType = PlacementModeConfig.EUnlockType.Gold; Cost = 3000; }; UnlockInfo = { UnlockType = PlacementModeConfig.EUnlockType.None; }; -- 其他参数 Param = { Damage = 80; CoolingTime = 10;} }, [EPlaceItemType.Flamethrower] = { Name = "喷火装置"; Desc = "对范围8m内最近的敌人造成范围伤害。"; ItemPath = UGCGameSystem.GetUGCResourcesFullPath('Asset/Blueprint/PlaceItems/Items/Flamethrower/BP_Flamethrower.BP_Flamethrower_C'); PreviewItemPath = UGCGameSystem.GetUGCResourcesFullPath('Asset/Blueprint/PlaceItems/Items/Flamethrower/BP_Preview_Flamethrower.BP_Preview_Flamethrower_C'); SelectTex = UGCGameSystem.GetUGCResourcesFullPath('Asset/Texture/PlaceItem/T_Framethrower.T_Framethrower'); MaxCount = 2; InitialCount = 0; Cost = 20; RemovePointToActor = true; -- 若为true则移除指针指向Actor根位置,反之则指向边框的中心点 IncrementInfo = { UnlockType = PlacementModeConfig.EUnlockType.Gold; Cost = 5000; }; UnlockInfo = { UnlockType = PlacementModeConfig.EUnlockType.Level; Cost = 8; }; -- 其他参数 Param = { Damage = 10; } }, } -- 得分数值 PlacementModeConfig.ScoreVal = { [PlacementModeConfig.AddScoreType.KillAddScore] = 2; -- 击杀得分 [PlacementModeConfig.AddScoreType.AssistAddScore] = 1; -- 助攻得分 [PlacementModeConfig.AddScoreType.DefendSucceedAddScore] = 30; -- 防守成功得分 [PlacementModeConfig.AddScoreType.EnterDefenseLineAddScore] = 10; -- 进入防线得分 [PlacementModeConfig.AddScoreType.Dead] = 0; -- 玩家死亡 } -- 得分名称 PlacementModeConfig.AddScoreName = { [PlacementModeConfig.AddScoreType.KillAddScore] = "淘汰得分"; [PlacementModeConfig.AddScoreType.AssistAddScore] = "助攻得分"; [PlacementModeConfig.AddScoreType.DefendSucceedAddScore] = "防守成功"; [PlacementModeConfig.AddScoreType.EnterDefenseLineAddScore] = "突破得分"; } PlacementModeConfig.UnlockName = { [PlacementModeConfig.EUnlockType.None] = ""; [PlacementModeConfig.EUnlockType.Level] = "等级"; [PlacementModeConfig.EUnlockType.Gold] = "金币"; [PlacementModeConfig.EUnlockType.GoldBrick] = "金砖"; } -- Function ============================================================================================================================================================================================ --- 获取放置控制器Manager PlacementModeConfig.GetPlaceManager = function() if not UE.IsValid(PlacementModeConfig.PlaceManager) then PlacementModeConfig.PlaceManager = UGCSystemLibrary.GetUniqueInstanceFromPath(PlacementModeConfig.PlaceManagerPath) end return PlacementModeConfig.PlaceManager end --- 获取放置模式的父类Class PlacementModeConfig.GetPlaceItemBaseClass = function() if PlacementModeConfig.PlaceItemBaseClass == nil then PlacementModeConfig.PlaceItemBaseClass = UE.LoadClass(PlacementModeConfig.PlaceItemBasePath) end return PlacementModeConfig.PlaceItemBaseClass end --- 是否为放置模式 PlacementModeConfig.IsPlaceMode = function() return PlacementModeConfig.PlaceModeID == UGCMultiMode.GetModeID() end --- 通过当前在线的进攻玩家数,进行判断应该突破防线的次数 function PlacementModeConfig.GetNumOfBreakingThroughDefenseLine() local PCNum = #UGCGameSystem.GetAllPlayerController() return (PCNum - 1) * PlacementModeConfig.PlacingAttr.NumOfPlayerBreakingThroughDefenseLine end --- 获取放置物解锁条件信息 function PlacementModeConfig.GetPlaceItemUnlockInfo(PlaceItemType) local PlaceItemInfo = PlacementModeConfig.ItemInfo[PlaceItemType] if PlaceItemInfo then return PlaceItemInfo.UnlockInfo.UnlockType, PlaceItemInfo.UnlockInfo.Cost end end --- 获取放置物增量条件信息 function PlacementModeConfig.GetPlaceItemIncrementInfo(PlaceItemType) local PlaceItemInfo = PlacementModeConfig.ItemInfo[PlaceItemType] if PlaceItemInfo then return PlaceItemInfo.IncrementInfo.UnlockType, PlaceItemInfo.IncrementInfo.Cost end end --- 获取最大放置量 function PlacementModeConfig.GetPlaceMaxValue(InPlayerKey) local Exp = ArchiveDataConfig.GetPlayerArchiveDataFromType(InPlayerKey, ArchiveDataConfig.EArchiveType.Exp) Exp = Exp and Exp or 0 local Level = LevelConfig.GetLevel(Exp) return PlacementModeConfig.PlacingAttr.BasePlaceValue + (Level - 1) * PlacementModeConfig.PlacingAttr.LevelUpPlaceValue end --- 设置所有放置机关的激活 function PlacementModeConfig.ActiveAllPlaceItem(IsActive) local SceneAllPlaceItems = GameplayStatics.GetAllActorsOfClass(UGCGameSystem.GameState, PlacementModeConfig.GetPlaceItemBaseClass(), {}) for i, v in pairs(SceneAllPlaceItems) do v:SetActive(IsActive) end end --- 获取玩家可放置某物体的数量 function PlacementModeConfig.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 --- 获取放置代码中含有的物体数量 function PlacementModeConfig.GetPlaceCodeHaveItemCont(InCode) local PlaceItemCount = {} local DecodeResType, MapType, PlaceItemInfo = PlacementModeConfig.PlaceCodeDecode(InCode) if DecodeResType == PlacementModeConfig.EPlaceDecodeCallback.Succeed then for i, v in pairs(PlaceItemInfo) do if PlaceItemCount[v.PlaceItemType] then PlaceItemCount[v.PlaceItemType] = PlaceItemCount[v.PlaceItemType] + 1 else PlaceItemCount[v.PlaceItemType] = 1 end end end return DecodeResType, PlaceItemCount, PlaceItemInfo end --- 判断该代码是否满足该玩家可用的需求 ---@return CanUse, PlaceCount, DecodeResType function PlacementModeConfig.CheckPlayerCanUsePlaceCode(InCode, InPlayerKey) local DecodeResType, PlaceItemCount, PlaceItemInfo = PlacementModeConfig.GetPlaceCodeHaveItemCont(InCode) if DecodeResType == PlacementModeConfig.EPlaceDecodeCallback.Succeed then local PlaceCount = 0 local CanPlace = true for PlaceItemType, Count in pairs(PlaceItemCount) do if CanPlace and PlacementModeConfig.GetPlayerPlaceItemCount(InPlayerKey, PlaceItemType) < Count then CanPlace = false end PlaceCount = PlaceCount + PlacementModeConfig.ItemInfo[PlaceItemType].Cost * Count end if not CanPlace then return false, PlaceCount, DecodeResType, PlaceItemInfo end if PlaceCount > PlacementModeConfig.GetPlaceMaxValue(InPlayerKey) then return false, PlaceCount end return true, PlaceCount, DecodeResType, PlaceItemInfo end return false, 0, DecodeResType, PlaceItemInfo end function PlacementModeConfig.GetSimpleLineOfDefense() if not UE.IsValid(PlacementModeConfig.SimpleLineOfDefense) then PlacementModeConfig.SimpleLineOfDefense = UGCSystemLibrary.GetUniqueInstanceFromPath(PlacementModeConfig.LineOfDefensePath) end return PlacementModeConfig.SimpleLineOfDefense end -- 格式化坐标和旋转 ---------------------------------------------------------------------------------------------------------------------------------------------- ---@param Vec FVector PlacementModeConfig.VectorToUnitVector = function(Vec) return { X = KismetMathLibrary.Round(Vec.X / PlacementModeConfig.PlacingAttr.PositionSpacing), Y = KismetMathLibrary.Round(Vec.Y / PlacementModeConfig.PlacingAttr.PositionSpacing), Z = KismetMathLibrary.Round(Vec.Z / PlacementModeConfig.PlacingAttr.PositionSpacing), } end ---@param Vec FVector PlacementModeConfig.UnitVectorToVector = function(Vec) return { X = Vec.X * PlacementModeConfig.PlacingAttr.PositionSpacing, Y = Vec.Y * PlacementModeConfig.PlacingAttr.PositionSpacing, Z = Vec.Z * PlacementModeConfig.PlacingAttr.PositionSpacing, } end ---@param Rot FRotator PlacementModeConfig.RotatorToUnitRotator = function(Rot) return { Roll = KismetMathLibrary.Round((Rot.Roll % 360) / PlacementModeConfig.PlacingAttr.RotationSpacing), Pitch = KismetMathLibrary.Round((Rot.Pitch % 360) / PlacementModeConfig.PlacingAttr.RotationSpacing), Yaw = KismetMathLibrary.Round((Rot.Yaw % 360) / PlacementModeConfig.PlacingAttr.RotationSpacing), } end ---@param Rot FRotator PlacementModeConfig.UnitRotatorToRotator = function(Rot) return { Roll = Rot.Roll * PlacementModeConfig.PlacingAttr.RotationSpacing, Pitch = Rot.Pitch * PlacementModeConfig.PlacingAttr.RotationSpacing, Yaw = Rot.Yaw * PlacementModeConfig.PlacingAttr.RotationSpacing, } end -- 格式化坐标和旋转 End ------------------------------------------------------------------------------------------------------------------------------------------ -- 单例预览材质 ------------------------------------------------------------------------------------------------------------------------------------------------- --- 获取放置时的动态材质 function PlacementModeConfig.GetPreviewDynamicMat() if PlacementModeConfig.DynamicMaterial == nil then local PreviewMat = UE.LoadObject(PlacementModeConfig.PreviewMatPath) PlacementModeConfig.DynamicMaterial = KismetMaterialLibrary.CreateDynamicMaterialInstance(UGCGameSystem.GameState, PreviewMat); end return PlacementModeConfig.DynamicMaterial end --- 设置是否可放置 PlacementModeConfig.bCanPlace = true function PlacementModeConfig.SetCanPlace(InCanPlace) if InCanPlace ~= PlacementModeConfig.bCanPlace then PlacementModeConfig.bCanPlace = InCanPlace --- 设置预览放置物动态材质的颜色 if PlacementModeConfig.bCanPlace then PlacementModeConfig.GetPreviewDynamicMat():SetVectorParameterValue("Diff_Light", PlacementModeConfig.PlacingAttr.CanPlaceColor) else PlacementModeConfig.GetPreviewDynamicMat():SetVectorParameterValue("Diff_Light", PlacementModeConfig.PlacingAttr.CanNotPlaceColor) end end end -- 单例预览材质 End --------------------------------------------------------------------------------------------------------------------------------------------- -- 导出/导入放置代码 ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- --- 采用72进制作为编码 PlacementModeConfig.base72_chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz!@#$%^&*()" PlacementModeConfig.StrToBase72 = {["0"] = 0, ["1"] = 1, ["2"] = 2, ["3"] = 3, ["4"] = 4, ["5"] = 5, ["6"] = 6, ["7"] = 7, ["8"] = 8, ["9"] = 9, ["A"] = 10, ["B"] = 11, ["C"] = 12, ["D"] = 13, ["E"] = 14, ["F"] = 15, ["G"] = 16, ["H"] = 17, ["I"] = 18, ["J"] = 19, ["K"] = 20, ["L"] = 21, ["M"] = 22, ["N"] = 23, ["O"] = 24, ["P"] = 25, ["Q"] = 26, ["R"] = 27, ["S"] = 28, ["T"] = 29, ["U"] = 30, ["V"] = 31, ["W"] = 32, ["X"] = 33, ["Y"] = 34, ["Z"] = 35, ["a"] = 36, ["b"] = 37, ["c"] = 38, ["d"] = 39, ["e"] = 40, ["f"] = 41, ["g"] = 42, ["h"] = 43, ["i"] = 44, ["j"] = 45, ["k"] = 46, ["l"] = 47, ["m"] = 48, ["n"] = 49, ["o"] = 50, ["p"] = 51, ["q"] = 52, ["r"] = 53, ["s"] = 54, ["t"] = 55, ["u"] = 56, ["v"] = 57, ["w"] = 58, ["x"] = 59, ["y"] = 60, ["z"] = 61, ["!"] = 62, ["@"] = 63, ["#"] = 64, ["$"] = 65, ["%"] = 66, ["^"] = 67, ["&"] = 68, ["*"] = 69, ["("] = 70, [")"] = 71, } PlacementModeConfig.Base72ToStr = { [0] = "0", [1] = "1", [2] = "2", [3] = "3", [4] = "4", [5] = "5", [6] = "6", [7] = "7", [8] = "8", [9] = "9", [10] = "A", [11] = "B", [12] = "C", [13] = "D", [14] = "E", [15] = "F", [16] = "G", [17] = "H", [18] = "I", [19] = "J", [20] = "K", [21] = "L", [22] = "M", [23] = "N", [24] = "O", [25] = "P", [26] = "Q", [27] = "R", [28] = "S", [29] = "T", [30] = "U", [31] = "V", [32] = "W", [33] = "X", [34] = "Y", [35] = "Z", [36] = "a", [37] = "b", [38] = "c", [39] = "d", [40] = "e", [41] = "f", [42] = "g", [43] = "h", [44] = "i", [45] = "j", [46] = "k", [47] = "l", [48] = "m", [49] = "n", [50] = "o", [51] = "p", [52] = "q", [53] = "r", [54] = "s", [55] = "t", [56] = "u", [57] = "v", [58] = "w", [59] = "x", [60] = "y", [61] = "z", [62] = "!", [63] = "@", [64] = "#", [65] = "$", [66] = "%", [67] = "^", [68] = "&", [69] = "*", [70] = "(", [71] = ")", } -- 十进制转换为72进制的函数 ---@param n 十进制数 ---@param CompletingDigits 需要补全的数字,为nil则不补全 function PlacementModeConfig.DToBase72(n, CompletingDigits) local result = "" if n == 0 then result = "0" else local base = 72 -- UGCLogSystem.Log("[PlacementModeConfig_DToBase72] n:%s", tostring(n)) while n > 0 do local remainder = n % base -- UGCLogSystem.Log("[PlacementModeConfig_DToBase72]---- n:%s", tostring(n)) result = PlacementModeConfig.Base72ToStr[remainder] .. result n = math.floor(n / base) end end if CompletingDigits then while string.len(result) < CompletingDigits do result = "0" .. result end end return result end -- 72进制转换为十进制的函数 function PlacementModeConfig.base72ToD(base72Str) local Res = 0 local LenStr = string.len(base72Str) for i = 1, LenStr, 1 do local chr = string.sub(base72Str, LenStr - i + 1, LenStr - i + 1) Res = Res + PlacementModeConfig.StrToBase72[chr] * 72 ^ (i - 1) end -- 四舍五入 return math.floor(Res + 0.5) end function PlacementModeConfig.PlaceCodeEncode(InMapType) return PlacementModeConfig.PlaceCodeVersionFuncList[PlacementModeConfig.PlaceCodeVersion].Encode(InMapType) end --- 对放置代码进行验证并解码 ---@return " EPlaceDecodeCallback, MapType, PlaceItemInfo = {PlaceItemType = PlaceItemType, UnitPos = UnitPos, UnitRot = UnitRot}" function PlacementModeConfig.PlaceCodeDecode(PlaceCode) local CodeLen = string.len(PlaceCode) -- 检验字符范围是否在72个字符内 for i = 1, CodeLen do local CodeStr = string.sub(PlaceCode, i, i) if PlacementModeConfig.StrToBase72[CodeStr] == nil then return PlacementModeConfig.EPlaceDecodeCallback.CharRangeError end end -- 检验版本和地图的字符长度 if CodeLen < 2 or CodeLen > PlacementModeConfig.PlacingAttr.MaxPlaceCodeLen then return PlacementModeConfig.EPlaceDecodeCallback.CodeLengthError end local Version = PlacementModeConfig.StrToBase72[string.sub(PlaceCode, 1, 1)] local CodeFuncList = PlacementModeConfig.PlaceCodeVersionFuncList[Version] -- 检验版本是否出错 if CodeFuncList == nil then return PlacementModeConfig.EPlaceDecodeCallback.VersionError end return CodeFuncList.Decode(PlaceCode) end -- V1版本编码 --[[ 地图编号1位72进制 -- 占位1位 放置物(类型1位,位置信息6位(XYZ各2位),旋转信息3位(RPY各1位)) -- 占位10位 ]] function PlacementModeConfig.PlaceCodeEncode_V01(MapType) -- 编码版本 此函数版本为1 local ResString = PlacementModeConfig.Base72ToStr[1] -- 地图占1位 ResString = ResString .. PlacementModeConfig.Base72ToStr[MapType] -- 对场景中所有已激活的放置物进行编码 local SceneAllPlaceItems = GameplayStatics.GetAllActorsOfClass(UGCGameSystem.GameState, PlacementModeConfig.GetPlaceItemBaseClass(), {}) for i, v in pairs(SceneAllPlaceItems) do -- 判断该物体是否激活 if v:GetIsPlaced() then local AddStr = "" -- 编码物体类型 local ItemType = v:GetPlaceItemType() AddStr = AddStr .. PlacementModeConfig.DToBase72(ItemType) --UGCLogSystem.Log("[PlacementModeConfig_PlaceCodeEncode_V01]_1 ResString:%s", ResString) -- 编码物体位置和旋转 local Pos, Rot = v:GetPlacePosAndRot() --UGCLogSystem.LogTree("[PlacementModeConfig_PlaceCodeEncode_V01] Pos", Pos) --UGCLogSystem.LogTree("[PlacementModeConfig_PlaceCodeEncode_V01] Rot", Rot); AddStr = AddStr .. PlacementModeConfig.DToBase72(Pos.X, 2) AddStr = AddStr .. PlacementModeConfig.DToBase72(Pos.Y, 2) AddStr = AddStr .. PlacementModeConfig.DToBase72(Pos.Z, 2) --UGCLogSystem.Log("[PlacementModeConfig_PlaceCodeEncode_V01]_2 ResString:%s", ResString) AddStr = AddStr .. PlacementModeConfig.DToBase72(Rot.Roll) AddStr = AddStr .. PlacementModeConfig.DToBase72(Rot.Pitch) AddStr = AddStr .. PlacementModeConfig.DToBase72(Rot.Yaw) --UGCLogSystem.Log("[PlacementModeConfig_PlaceCodeEncode_V01]_3 ResString:%s", ResString) ResString = ResString .. AddStr UGCLogSystem.Log("[PlacementModeConfig_PlaceCodeEncode_V01]_4 Len:%d, AddStr:%s",string.len(AddStr), AddStr) UGCLogSystem.Log("[PlacementModeConfig_PlaceCodeEncode_V01]_5 Len:%d, ResString:%s",string.len(ResString), ResString) end end return ResString end -- V1版本解码 --[[ 地图编号1位72进制 -- 占位1位 放置物(类型1位,位置信息6位(XYZ各2位),旋转信息3位(RPY各1位)) -- 占位10位 ]] function PlacementModeConfig.PlaceCodeDecode_V01(PlaceCode) local LenPlaceCode = string.len(PlaceCode) UGCLogSystem.Log("[PlacementModeConfig_PlaceCodeDecode_V01] LenPlaceCode:%s", tostring(LenPlaceCode)) -- 验证长度 if ((LenPlaceCode - 2) % 10) ~= 0 then return PlacementModeConfig.EPlaceDecodeCallback.CodeLengthError end local Index = 2 local ReadCodeStr = function(InNum) local Res = string.sub(PlaceCode, Index, Index + (InNum - 1)) Index = Index + InNum return Res end local MapType = PlacementModeConfig.StrToBase72[ReadCodeStr(1)] -- 验证Map类型是否符合 if PlacementModeConfig.MapInfo[MapType] == nil then return PlacementModeConfig.EPlaceDecodeCallback.MapCodeError end -- 可放置范围 local MapPlacingRange = PlacementModeConfig.MapInfo[MapType].MapPlacingRange local ResPlaceItemInfo = {} for i = 1, math.floor((LenPlaceCode - 2) / 10 + 0.5) do local PlaceItemType = PlacementModeConfig.base72ToD(ReadCodeStr(1)) if PlacementModeConfig.ItemInfo[PlaceItemType] == nil then return PlacementModeConfig.EPlaceDecodeCallback.PlaceItemTypeError end local UnitX = PlacementModeConfig.base72ToD(ReadCodeStr(2)) local UnitY = PlacementModeConfig.base72ToD(ReadCodeStr(2)) local UnitZ = PlacementModeConfig.base72ToD(ReadCodeStr(2)) -- 检验放置范围是否异常 if UnitX > MapPlacingRange.X or UnitY > MapPlacingRange.Y or UnitZ > MapPlacingRange.Z then return PlacementModeConfig.EPlaceDecodeCallback.PlacePosRangeError end local UnitPos = {X = UnitX, Y = UnitY, Z = UnitZ} local UnitRot = { Roll = PlacementModeConfig.StrToBase72[ReadCodeStr(1)], Pitch = PlacementModeConfig.StrToBase72[ReadCodeStr(1)], Yaw = PlacementModeConfig.StrToBase72[ReadCodeStr(1)] } ResPlaceItemInfo[#ResPlaceItemInfo + 1] = {PlaceItemType = PlaceItemType, UnitPos = UnitPos, UnitRot = UnitRot} end return PlacementModeConfig.EPlaceDecodeCallback.Succeed, MapType, ResPlaceItemInfo end -- 开头为编码的版号 -- 占位1位 PlacementModeConfig.PlaceCodeVersionFuncList = { [1] = {Encode = PlacementModeConfig.PlaceCodeEncode_V01, Decode = PlacementModeConfig.PlaceCodeDecode_V01}, } -- 导出/导入放置代码 End ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------