From f0a7979f689cc84f8e85e23d3b4511cea05b5738 Mon Sep 17 00:00:00 2001 From: IceCoffee <1249993110@qq.com> Date: Sat, 14 Sep 2024 09:05:49 +0800 Subject: [PATCH 01/14] --- src/SdtdServerKit/Commands/RemoveEntity.cs | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/src/SdtdServerKit/Commands/RemoveEntity.cs b/src/SdtdServerKit/Commands/RemoveEntity.cs index 3c4401c..79e3df0 100644 --- a/src/SdtdServerKit/Commands/RemoveEntity.cs +++ b/src/SdtdServerKit/Commands/RemoveEntity.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace SdtdServerKit.Commands +namespace SdtdServerKit.Commands { /// /// Remove Entity @@ -27,8 +21,8 @@ public override string getDescription() public override string getHelp() { return "Removes an entity from the game\n" + - "Usage: ty-re \n" + - "Usage: rem "; + "Usage: ty-re {EntityId}\n" + + "Usage: ty-RemoveEntity {EntityId}"; } /// From ab5e688f1835c7af157a64e4b2b055f25fbc05fe Mon Sep 17 00:00:00 2001 From: IceCoffee <1249993110@qq.com> Date: Sun, 15 Sep 2024 12:48:31 +0800 Subject: [PATCH 02/14] Add color chat function and optimize the message sender name logic In `CHANGELOG.md`, add color chat function, support custom player name color and text color, support using variable `{PlayerName}` to customize title. In addition, add automatic zombie cleanup function, support custom global chat server name and private chat server name. In `GlobalMessage.cs`, add references to `SdtdServerKit.Managers` and `SdtdServerKit.Models`. Modify the sender name logic when sending global messages, give priority to the sender name in the parameter, if not provided, use the global server name in the configuration, if still empty, use the localized default name. In `SayToPlayer.cs`, add references to `SdtdServerKit.Managers`. Modify the sender name logic when sending private messages, give priority to the sender name in the parameter, if not provided, use the private chat server name in the configuration, if still empty, use the localized default name. In `ServerController.cs`, removed the logic for checking and setting the sender name when sending global and private messages, as this is already handled in the `GlobalMessage` and `SayToPlayer` classes. --- CHANGELOG.md | 2 +- src/SdtdServerKit/Commands/GlobalMessage.cs | 21 +++++++++++++++++-- src/SdtdServerKit/Commands/SayToPlayer.cs | 20 ++++++++++++++++-- .../WebApi/Controllers/ServerController.cs | 8 ------- 4 files changed, 38 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ff2ddb2..21fa0b6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ ## 10.41 (2024-09-13) ### New Features -- Added color chat function, supports customizing player name color and text color, supports using variable {PlayerName} to customize title +- Added color chat function, supports customizing player name color and text color, supports using variable `{PlayerName}` to customize title - Added automatic zombie cleanup function - Supports customizing global chat server name and whisper chat server name diff --git a/src/SdtdServerKit/Commands/GlobalMessage.cs b/src/SdtdServerKit/Commands/GlobalMessage.cs index 711c0dc..b4b0185 100644 --- a/src/SdtdServerKit/Commands/GlobalMessage.cs +++ b/src/SdtdServerKit/Commands/GlobalMessage.cs @@ -1,4 +1,7 @@ -namespace SdtdServerKit.Commands +using SdtdServerKit.Managers; +using SdtdServerKit.Models; + +namespace SdtdServerKit.Commands { /// /// Sends a message to all connected clients. @@ -53,7 +56,21 @@ public override void Execute(List args, CommandSenderInfo _senderInfo) } string message = args[0]; - string senderName = args.Count > 1 ? args[1] : Localization.Get("xuiChatServer", false); + string senderName; + if (args.Count > 1) + { + senderName = args[1]; + } + else + { + senderName = ConfigManager.GlobalSettings.GlobalServerName; + } + + if (string.IsNullOrEmpty(senderName)) + { + senderName = Localization.Get("xuiChatServer", false); + } + message = global::Utils.CreateGameMessage(senderName, message); GameManager.Instance.ChatMessageServer( diff --git a/src/SdtdServerKit/Commands/SayToPlayer.cs b/src/SdtdServerKit/Commands/SayToPlayer.cs index 0d6b44f..ab2a321 100644 --- a/src/SdtdServerKit/Commands/SayToPlayer.cs +++ b/src/SdtdServerKit/Commands/SayToPlayer.cs @@ -1,4 +1,6 @@ -namespace SdtdServerKit.Commands +using SdtdServerKit.Managers; + +namespace SdtdServerKit.Commands { /// /// Send a message to a single player. @@ -66,7 +68,21 @@ public override void Execute(List args, CommandSenderInfo senderInfo) } string message = args[1]; - string senderName = args.Count > 2 ? args[2] : Localization.Get("xuiChatServer", false); + string senderName; + if (args.Count > 2) + { + senderName = args[2]; + } + else + { + senderName = ConfigManager.GlobalSettings.WhisperServerName; + } + + if (string.IsNullOrEmpty(senderName)) + { + senderName = Localization.Get("xuiChatServer", false); + } + message = global::Utils.CreateGameMessage(senderName, message); GameManager.Instance.ChatMessageServer( diff --git a/src/SdtdServerKit/WebApi/Controllers/ServerController.cs b/src/SdtdServerKit/WebApi/Controllers/ServerController.cs index 96aa7b7..12d9a98 100644 --- a/src/SdtdServerKit/WebApi/Controllers/ServerController.cs +++ b/src/SdtdServerKit/WebApi/Controllers/ServerController.cs @@ -251,10 +251,6 @@ public IEnumerable GiveItem([FromBody]GiveItem giveItemEntry) [Route(nameof(SendGlobalMessage))] public IEnumerable SendGlobalMessage([FromBody] GlobalMessage globalMessage) { - if (string.IsNullOrEmpty(globalMessage.SenderName)) - { - globalMessage.SenderName = ConfigManager.GlobalSettings.GlobalServerName; - } return Utils.SendGlobalMessage(globalMessage); } @@ -265,10 +261,6 @@ public IEnumerable SendGlobalMessage([FromBody] GlobalMessage globalMess [Route(nameof(SendPrivateMessage))] public IEnumerable SendPrivateMessage([FromBody] PrivateMessage privateMessage) { - if (string.IsNullOrEmpty(privateMessage.SenderName)) - { - privateMessage.SenderName = ConfigManager.GlobalSettings.WhisperServerName; - } return Utils.SendPrivateMessage(privateMessage); } From 1f0c242529cf868e6e979258a6a2571d391a6436 Mon Sep 17 00:00:00 2001 From: IceCoffee <1249993110@qq.com> Date: Wed, 18 Sep 2024 11:13:31 +0800 Subject: [PATCH 03/14] Added LastLogin property and translated the comment to English In the `ClaimOwner.cs` file: - Changed the comment "Is it activated" to "Claim Active". - Added a new property `LastLogin` to record the last login time, and added the corresponding comment "Last Login". - Changed the comment "Territory Stone Coordinate Collection" to "Claim Positions". In the `LandClaimsController.cs` file: - When creating the `claimOwner` object, added the assignment to the `LastLogin` property, and initialized it with `persistentPlayerData.LastLogin`. These changes are mainly to add the record of the player's last login time, and the existing comments are translated to English to improve the readability and internationalization support of the code. --- src/SdtdServerKit/Models/ClaimOwner.cs | 9 +++++++-- .../WebApi/Controllers/LandClaimsController.cs | 1 + 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/SdtdServerKit/Models/ClaimOwner.cs b/src/SdtdServerKit/Models/ClaimOwner.cs index 561a776..2dea478 100644 --- a/src/SdtdServerKit/Models/ClaimOwner.cs +++ b/src/SdtdServerKit/Models/ClaimOwner.cs @@ -6,12 +6,17 @@ public class ClaimOwner : PlayerBase { /// - /// 是否激活 + /// Claim Active /// public bool ClaimActive { get; set; } /// - /// 领地石坐标集合 + /// Last Login + /// + public DateTime LastLogin { get; set; } + + /// + /// Claim Positions /// public IEnumerable ClaimPositions { get; set; } } diff --git a/src/SdtdServerKit/WebApi/Controllers/LandClaimsController.cs b/src/SdtdServerKit/WebApi/Controllers/LandClaimsController.cs index 1666f55..510616a 100644 --- a/src/SdtdServerKit/WebApi/Controllers/LandClaimsController.cs +++ b/src/SdtdServerKit/WebApi/Controllers/LandClaimsController.cs @@ -35,6 +35,7 @@ public IHttpActionResult GetLandClaim(string playerId) PlayerName = persistentPlayerData.PlayerName.DisplayName, ClaimActive = GameManager.Instance.World.IsLandProtectionValidForPlayer(persistentPlayerData), ClaimPositions = persistentPlayerData.LPBlocks.ToPositions(), + LastLogin = persistentPlayerData.LastLogin }; return Ok(claimOwner); From 925a9bdb0ba4da0250da12b42130b53a3dbce7ac Mon Sep 17 00:00:00 2001 From: IceCoffee <1249993110@qq.com> Date: Thu, 19 Sep 2024 09:46:24 +0800 Subject: [PATCH 04/14] Added new methods and classes, adjusted command order, updated initialization Added a new static method `ContainsCaseInsensitive` in `ConsoleCmdBase.cs` to check whether the specified name is contained in the parameter list (case-insensitive). Adjusted the order of commands returned by the `getCommands` method in `RestartServer.cs`, putting `"ty-RestartServer"` before `"ty-rs"`. Added the `LastLogin` field to the initialization of `LandClaims` in `LandClaimsController.cs`. Added a `ChunkHelper` class in `ChunkHelper.cs`, which provides some helper methods for forcing the reload of a specified chunk. Added a `RenderPrefab` class in `RenderPrefab.cs`, which provides the function of rendering prefabs at a specified location, and includes detailed command usage instructions and implementation logic. --- src/SdtdServerKit/ChunkHelper.cs | 40 +++ src/SdtdServerKit/Commands/ConsoleCmdBase.cs | 20 ++ src/SdtdServerKit/Commands/RenderPrefab.cs | 251 ++++++++++++++++++ src/SdtdServerKit/Commands/RestartServer.cs | 2 +- .../Controllers/LandClaimsController.cs | 1 + 5 files changed, 313 insertions(+), 1 deletion(-) create mode 100644 src/SdtdServerKit/ChunkHelper.cs create mode 100644 src/SdtdServerKit/Commands/RenderPrefab.cs diff --git a/src/SdtdServerKit/ChunkHelper.cs b/src/SdtdServerKit/ChunkHelper.cs new file mode 100644 index 0000000..c6415c1 --- /dev/null +++ b/src/SdtdServerKit/ChunkHelper.cs @@ -0,0 +1,40 @@ +using SdtdServerKit.Managers; + +namespace SdtdServerKit +{ + /// + /// Provides a set of helper methods for chunks. + /// + public static class ChunkHelper + { + /// + /// Forces the reload of the specified chunks. + /// + /// + public static void ForceReload(IEnumerable chunks) + { + var managedPlayers = LivePlayerManager.GetAll(); + Parallel.ForEach(managedPlayers, managedPlayer => + { + foreach (var chunk in chunks) + { + try + { + var chunkPosition = chunk.GetWorldPos(); + var playerPosition = managedPlayer.EntityPlayer.GetPosition(); + if (Math.Abs(playerPosition.x - chunkPosition.x) < 200F && Math.Abs(playerPosition.z - chunkPosition.z) < 200F) + { + managedPlayer.ClientInfo.SendPackage(NetPackageManager.GetPackage().Setup(chunk, true)); + } + } + catch (Exception) + { + // CustomLogger.Warn(ex, "Error in ChunkHelper.ForceReload"); + } + } + }); + + ConnectionManager.Instance.FlushClientSendQueues(); + } + } +} diff --git a/src/SdtdServerKit/Commands/ConsoleCmdBase.cs b/src/SdtdServerKit/Commands/ConsoleCmdBase.cs index ebdd4cb..80073ea 100644 --- a/src/SdtdServerKit/Commands/ConsoleCmdBase.cs +++ b/src/SdtdServerKit/Commands/ConsoleCmdBase.cs @@ -23,5 +23,25 @@ protected virtual void Log(string line, params object[] args) { SdtdConsole.Instance.Output(CustomLogger.Prefix + string.Format(line, args)); } + + /// + /// Checks if the arguments contain the specified name. + /// + /// + /// + /// + /// + protected static bool ContainsCaseInsensitive(List args, string name, int startIndex = 0) + { + for (int i = startIndex; i < args.Count; i++) + { + if (string.Equals(args[i], name, StringComparison.OrdinalIgnoreCase)) + { + return true; + } + } + + return false; + } } } \ No newline at end of file diff --git a/src/SdtdServerKit/Commands/RenderPrefab.cs b/src/SdtdServerKit/Commands/RenderPrefab.cs new file mode 100644 index 0000000..9009a11 --- /dev/null +++ b/src/SdtdServerKit/Commands/RenderPrefab.cs @@ -0,0 +1,251 @@ +using SdtdServerKit.Managers; +using System.Drawing; +using UniLinq; + +namespace SdtdServerKit.Commands +{ + /// + /// Renders a Prefab on given location. + /// + public class RenderPrefab : ConsoleCmdBase + { + /// + /// + /// + /// + public override string getDescription() + { + return "Renders a Prefab on given location."; + } + + /// + /// + /// + /// + public override string getHelp() + { + return "Usage:\n" + + " 1. ty-RenderPrefab {prefabFileName} {x} {y} {z} [noSleepers] [addToRWG]\n" + + " 2. ty-RenderPrefab {prefabFileName} {x} {y} {z} {rot} [noSleepers] [addToRWG]\n" + + " 3. ty-RenderPrefab {prefabFileName} [noSleepers] [addToRWG]\n" + + " 4. ty-RenderPrefab {prefabFileName} {rot} [noSleepers] [addToRWG]\n" + + " 5. ty-RenderPrefab {prefabFileName} {rot} {depth} [noSleepers] [addToRWG]\n" + + "1. Render prefab on {x} {y} {z} location\n" + + "2. Render prefab on {x} {y} {z} location with rot\n" + + "3. Render prefab on your position\n" + + "4. Render prefab on your position with rot\n" + + "5. Render prefab on your position with rot and y deslocated (depth blocks)\n" + + "NOTE: {rot} means rotate the prefab to the left, must be equal to 0=0°, 1=90°, 2=180° or 3=270°\n" + + "NOTE: Sleeper control is ONLY possible on prefabs that are present in prefabs.xml (world folder) that is used to create the map (RWG).\n" + + "NOTE: Use parameter \"addToRWG\" to permanently add this prefab to the current RWG world. Can be reset like any other RWG prefab and will still be in world after a wipe. Will cause re-download of world for clients!"; + } + + /// + /// + /// + /// + public override string[] getCommands() + { + return new string[] + { + "ty-RenderPrefab", + "ty-rp", + "ty-brender" + }; + } + + /// + /// + /// + /// + public override void Execute(List args, CommandSenderInfo senderInfo) + { + try + { + if (args.Count < 1 || args.Count > 7) + { + Log($"ERR: Wrong number of arguments, expected 1 to 7, found {args.Count}."); + Log(this.GetHelp()); + return; + } + + bool addToRWG = ContainsCaseInsensitive(args, "addtorwg"); + bool noSleepers = ContainsCaseInsensitive(args, "nosleepers"); + if (addToRWG) + { + args.RemoveAll(i => string.Equals(i, "addtorwg", StringComparison.OrdinalIgnoreCase)); + } + if (noSleepers) + { + args.RemoveAll(i => string.Equals(i, "nosleepers", StringComparison.OrdinalIgnoreCase)); + } + + string prefabFileName = args[0]; + int x; + int y; + int z; + int rot = 0; + + if (args.Count == 4) + { + x = int.Parse(args[1]); + y = int.Parse(args[2]); + z = int.Parse(args[3]); + } + else if(args.Count == 5) + { + x = int.Parse(args[1]); + y = int.Parse(args[2]); + z = int.Parse(args[3]); + rot = int.Parse(args[4]); + } + else + { + var remoteClientInfo = senderInfo.RemoteClientInfo; + if (remoteClientInfo == null) + { + Log("ERR: This command can be only sent by player in game."); + return; + } + if (LivePlayerManager.TryGetByEntityId(remoteClientInfo.entityId, out var managedPlayer) == false) + { + Log("ERR: Unable to get your position"); + return; + } + + var playerBlockPosition = managedPlayer!.EntityPlayer.GetBlockPosition(); + x = playerBlockPosition.x; + y = playerBlockPosition.y; + z = playerBlockPosition.z; + + if(args.Count == 2) + { + rot = int.Parse(args[1]); + if (rot < 0 || rot > 3) + { + Log("ERR: Invalid rotation parameter. It need to be 0,1,2 or 3."); + return; + } + } + else if (args.Count == 3) + { + int depth = int.Parse(args[2]); + y += depth; + } + } + + var prefab = new Prefab(); + if (prefab.Load(prefabFileName, true, true, false, false) == false) + { + // Runtime load from LocalPrefabs + var dir = new DirectoryInfo(Path.Combine(LaunchPrefs.UserDataFolder.Value, "LocalPrefabs")); + Log("Try loading prefab from " + dir.FullName); + var abstractedLocation = new PathAbstractions.AbstractedLocation(PathAbstractions.EAbstractedLocationType.UserDataPath, prefabFileName, dir.FullName, null, prefabFileName, ".tts", true, null); + if (prefab.Load(abstractedLocation, true, true, false, false) == false) + { + Log("ERR: Unable to load prefab " + prefabFileName); + return; + } + } + + Log("Rendering..., please wait."); + + prefab.bCopyAirBlocks = true; + y += prefab.yOffset; + prefab.RotateY(true, rot); + var prefabSize = prefab.size; + + var chunkSet = new HashSet(); + for (int i = 0; i < prefabSize.x; i++) + { + for (int j = 0; j < prefabSize.z; j++) + { + for (int k = 0; k < prefabSize.y; k++) + { + if (GameManager.Instance.World.IsChunkAreaLoaded(x + i, y + k, z + j) == false) + { + Log("ERR: The prefab is too far away. Chunk not loaded on that area."); + return; + } + + var chunk = (Chunk)GameManager.Instance.World.GetChunkFromWorldPos(x + i, y + k, z + j); + chunkSet.Add(chunk); + } + } + } + + //var prefab2 = new Prefab(new Vector3i(prefabSize.x, prefabSize.y, prefabSize.z)); + //prefab2.bCopyAirBlocks = true; + //prefab2.copyFromWorld(GameManager.Instance.World, new Vector3i(x, y, z), new Vector3i(x + prefabSize.x, y + prefabSize.y, z + prefabSize.z)); + if (noSleepers) + { + prefab.SleeperVolumes = new List(); + } + prefab.CopyIntoLocal(GameManager.Instance.World.ChunkCache, new Vector3i(x, y, z), true, true, FastTags.none); + + ChunkHelper.ForceReload(chunkSet); + + var stabilityCalculator = new StabilityCalculator(); + stabilityCalculator.Init(GameManager.Instance.World); + for (int l = 0; l < prefabSize.x; l++) + { + for (int m = 0; m < prefabSize.z; m++) + { + for (int n = 0; n < prefabSize.y; n++) + { + if (GameManager.Instance.World.GetBlock(x + l, y + n, z + m).Equals(BlockValue.Air) == false) + { + var vector3i = new Vector3i(x + l, y + n, z + m); + stabilityCalculator.BlockPlacedAt(vector3i, false); + } + } + } + } + stabilityCalculator.Cleanup(); + + if (addToRWG) + { + var dynamicPrefabDecorator = GameManager.Instance.GetDynamicPrefabDecorator(); + var prefabInstance = new PrefabInstance(dynamicPrefabDecorator.GetNextId(), prefab.location, new Vector3i(x, y, z), (byte)prefab.GetLocalRotation(), prefab, 0) + { + bPrefabCopiedIntoWorld = true + }; + dynamicPrefabDecorator.GetDynamicPrefabs().Add(prefabInstance); + dynamicPrefabDecorator.GetPOIPrefabs().Add(prefabInstance); + dynamicPrefabDecorator.Save(PathAbstractions.WorldsSearchPaths.GetLocation(GameManager.Instance.World.ChunkCache.Name, null, null).FullPath); + //if (senderInfo.RemoteClientInfo == null) + //{ + // PrefabUndo.setUndo("server_", prefab2, new Vector3i(x, y, z), prefabInstance.id); + //} + //else + //{ + // PrefabUndo.setUndo(senderInfo.RemoteClientInfo.entityId.ToString() ?? "", prefab2, new Vector3i(x, y, z), prefabInstance.id); + //} + } + //else if (senderInfo.RemoteClientInfo == null) + //{ + // PrefabUndo.setUndo("server_", prefab2, new Vector3i(x, y, z), -1); + //} + //else + //{ + // PrefabUndo.setUndo(senderInfo.RemoteClientInfo.entityId.ToString() ?? "", prefab2, new Vector3i(x, y, z), -1); + //} + Log(string.Concat(new string[] + { + "Prefab ", + prefabFileName, + " loaded at ", + x.ToString(), + " ", + y.ToString(), + " ", + z.ToString() + })); + } + catch (Exception ex) + { + Log("Error in RenderPrefab.Execute" + Environment.NewLine + ex.ToString()); + } + } + } +} diff --git a/src/SdtdServerKit/Commands/RestartServer.cs b/src/SdtdServerKit/Commands/RestartServer.cs index 5744510..bd23a94 100644 --- a/src/SdtdServerKit/Commands/RestartServer.cs +++ b/src/SdtdServerKit/Commands/RestartServer.cs @@ -27,7 +27,7 @@ public override string getHelp() /// public override string[] getCommands() { - return new[] { "ty-rs", "ty-RestartServer" }; + return new[] { "ty-RestartServer", "ty-rs" }; } /// diff --git a/src/SdtdServerKit/WebApi/Controllers/LandClaimsController.cs b/src/SdtdServerKit/WebApi/Controllers/LandClaimsController.cs index 510616a..a690af9 100644 --- a/src/SdtdServerKit/WebApi/Controllers/LandClaimsController.cs +++ b/src/SdtdServerKit/WebApi/Controllers/LandClaimsController.cs @@ -64,6 +64,7 @@ public LandClaims GetLandClaims() PlayerName = persistentPlayerData.PlayerName.DisplayName, ClaimActive = GameManager.Instance.World.IsLandProtectionValidForPlayer(persistentPlayerData), ClaimPositions = persistentPlayerData.LPBlocks.ToPositions(), + LastLogin = persistentPlayerData.LastLogin }); } } From 4842cccb229bfb9c1c1deff858b1ec89b56a1e28 Mon Sep 17 00:00:00 2001 From: IceCoffee <1249993110@qq.com> Date: Thu, 19 Sep 2024 16:16:44 +0800 Subject: [PATCH 05/14] --- src/SdtdServerKit/Commands/GlobalMessage.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/SdtdServerKit/Commands/GlobalMessage.cs b/src/SdtdServerKit/Commands/GlobalMessage.cs index b4b0185..26e426b 100644 --- a/src/SdtdServerKit/Commands/GlobalMessage.cs +++ b/src/SdtdServerKit/Commands/GlobalMessage.cs @@ -36,9 +36,9 @@ public override string[] getCommands() { return new string[] { - "ty-GlobalMessage", - "ty-gm", - "ty-say" + "ty-GlobalMessage", + "ty-gm", + "ty-say" }; } From fa837e0d1e8d55988859ee43fb3d57b3a898e5ef Mon Sep 17 00:00:00 2001 From: IceCoffee <1249993110@qq.com> Date: Thu, 19 Sep 2024 16:17:10 +0800 Subject: [PATCH 06/14] Added new methods and undo functionality, refactored logging and command handling Added several new methods in `ChunkHelper.cs`: - `GetChunksInArea`: Get chunks in a specified area. - `CalculateStability`: Calculates stability in a specified area. - `AddPrefabToRWG`: Adds a prefab to a randomly generated world. - `RemovePrefabFromRWG`: Removes a prefab from a randomly generated world. In `RenderPrefab.cs`: - Added logging to show if it is executed in the main thread. - Refactored the processing logic of command parameters. - Replaced the original logic with new methods in `ChunkHelper`. - Added `UndoPrefab.SetUndo` method for setting undo operations. Added `UndoPrefab.cs` file: - Defined the `UndoPrefab` class for undoing the last prefab command. - Implemented cache management for related methods and undo operations. --- src/SdtdServerKit/ChunkHelper.cs | 102 ++++++++++ src/SdtdServerKit/Commands/RenderPrefab.cs | 122 ++++------- src/SdtdServerKit/Commands/UndoPrefab.cs | 223 +++++++++++++++++++++ 3 files changed, 365 insertions(+), 82 deletions(-) create mode 100644 src/SdtdServerKit/Commands/UndoPrefab.cs diff --git a/src/SdtdServerKit/ChunkHelper.cs b/src/SdtdServerKit/ChunkHelper.cs index c6415c1..32aeb11 100644 --- a/src/SdtdServerKit/ChunkHelper.cs +++ b/src/SdtdServerKit/ChunkHelper.cs @@ -1,4 +1,5 @@ using SdtdServerKit.Managers; +using static SaveDataPrefsFile; namespace SdtdServerKit { @@ -36,5 +37,106 @@ public static void ForceReload(IEnumerable chunks) ConnectionManager.Instance.FlushClientSendQueues(); } + + /// + /// Get chunks in area. + /// + /// + /// + public static IEnumerable GetChunksInArea(Vector3i offsetPosition, Vector3i prefabSize) + { + var chunkSet = new HashSet(); + for (int i = 0; i < prefabSize.x; i++) + { + for (int j = 0; j < prefabSize.z; j++) + { + for (int k = 0; k < prefabSize.y; k++) + { + int x = offsetPosition.x + i; + int y = offsetPosition.y + k; + int z = offsetPosition.z + j; + if (GameManager.Instance.World.IsChunkAreaLoaded(x, y, z) == false) + { + throw new Exception("The prefab is too far away. Chunk not loaded on that area."); + } + + var chunk = (Chunk)GameManager.Instance.World.GetChunkFromWorldPos(x, y, z); + chunkSet.Add(chunk); + } + } + } + + return chunkSet; + } + + /// + /// Calculate stability + /// + /// + /// + public static void CalculateStability(Vector3i offsetPosition, Vector3i prefabSize) + { + var stabilityCalculator = new StabilityCalculator(); + stabilityCalculator.Init(GameManager.Instance.World); + for (int i = 0; i < prefabSize.x; i++) + { + for (int j = 0; j < prefabSize.z; j++) + { + for (int k = 0; k < prefabSize.y; k++) + { + var vector3i = new Vector3i(offsetPosition.x + i, offsetPosition.y + k, offsetPosition.z + j); + if (GameManager.Instance.World.GetBlock(vector3i).Equals(BlockValue.Air) == false) + { + stabilityCalculator.BlockPlacedAt(vector3i, false); + } + } + } + } + stabilityCalculator.Cleanup(); + } + + /// + /// Add prefab to RWG + /// + /// + /// + /// Prefab instance id + public static int AddPrefabToRWG(Prefab prefab, Vector3i offsetPosition) + { + var dynamicPrefabDecorator = GameManager.Instance.GetDynamicPrefabDecorator(); + int prefabInstanceId = dynamicPrefabDecorator.GetNextId(); + var prefabInstance = new PrefabInstance(prefabInstanceId, prefab.location, offsetPosition, (byte)prefab.GetLocalRotation(), prefab, 0) + { + bPrefabCopiedIntoWorld = true + }; + dynamicPrefabDecorator.GetDynamicPrefabs().Add(prefabInstance); + dynamicPrefabDecorator.GetPOIPrefabs().Add(prefabInstance); + dynamicPrefabDecorator.Save(PathAbstractions.WorldsSearchPaths.GetLocation(GameManager.Instance.World.ChunkCache.Name, null, null).FullPath); + return prefabInstanceId; + } + + /// + /// Remove prefab from RWG + /// + /// + /// + public static bool RemovePrefabFromRWG(int prefabInstanceId) + { + var dynamicPrefabDecorator = GameManager.Instance.GetDynamicPrefabDecorator(); + var dynamicPrefabs = dynamicPrefabDecorator.GetDynamicPrefabs(); + var POIPrefabs = dynamicPrefabDecorator.GetPOIPrefabs(); + foreach (var prefabInstance in dynamicPrefabs) + { + if (prefabInstance != null && prefabInstance.id == prefabInstanceId) + { + dynamicPrefabs.Remove(prefabInstance); + POIPrefabs.Remove(prefabInstance); + dynamicPrefabDecorator.Save(PathAbstractions.WorldsSearchPaths.GetLocation(GameManager.Instance.World.ChunkCache.Name, null, null).FullPath); + return true; + } + } + + return false; + } } } diff --git a/src/SdtdServerKit/Commands/RenderPrefab.cs b/src/SdtdServerKit/Commands/RenderPrefab.cs index 9009a11..ee79f39 100644 --- a/src/SdtdServerKit/Commands/RenderPrefab.cs +++ b/src/SdtdServerKit/Commands/RenderPrefab.cs @@ -62,6 +62,9 @@ public override void Execute(List args, CommandSenderInfo senderInfo) { try { + CustomLogger.Warn("Is Main: " + ThreadManager.IsMainThread()); + var remoteClientInfo = senderInfo.RemoteClientInfo; + if (args.Count < 1 || args.Count > 7) { Log($"ERR: Wrong number of arguments, expected 1 to 7, found {args.Count}."); @@ -101,7 +104,6 @@ public override void Execute(List args, CommandSenderInfo senderInfo) } else { - var remoteClientInfo = senderInfo.RemoteClientInfo; if (remoteClientInfo == null) { Log("ERR: This command can be only sent by player in game."); @@ -118,7 +120,7 @@ public override void Execute(List args, CommandSenderInfo senderInfo) y = playerBlockPosition.y; z = playerBlockPosition.z; - if(args.Count == 2) + if(args.Count >= 2) { rot = int.Parse(args[1]); if (rot < 0 || rot > 3) @@ -126,15 +128,19 @@ public override void Execute(List args, CommandSenderInfo senderInfo) Log("ERR: Invalid rotation parameter. It need to be 0,1,2 or 3."); return; } - } - else if (args.Count == 3) - { - int depth = int.Parse(args[2]); - y += depth; + + if (args.Count == 3) + { + int depth = int.Parse(args[2]); + y += depth; + } } } - var prefab = new Prefab(); + var prefab = new Prefab() + { + bCopyAirBlocks = true + }; if (prefab.Load(prefabFileName, true, true, false, false) == false) { // Runtime load from LocalPrefabs @@ -150,97 +156,49 @@ public override void Execute(List args, CommandSenderInfo senderInfo) Log("Rendering..., please wait."); - prefab.bCopyAirBlocks = true; y += prefab.yOffset; prefab.RotateY(true, rot); + var prefabSize = prefab.size; + var offsetPosition = new Vector3i(x, y, z); - var chunkSet = new HashSet(); - for (int i = 0; i < prefabSize.x; i++) + IEnumerable? chunks; + try { - for (int j = 0; j < prefabSize.z; j++) - { - for (int k = 0; k < prefabSize.y; k++) - { - if (GameManager.Instance.World.IsChunkAreaLoaded(x + i, y + k, z + j) == false) - { - Log("ERR: The prefab is too far away. Chunk not loaded on that area."); - return; - } - - var chunk = (Chunk)GameManager.Instance.World.GetChunkFromWorldPos(x + i, y + k, z + j); - chunkSet.Add(chunk); - } - } + chunks = ChunkHelper.GetChunksInArea(offsetPosition, prefabSize); + } + catch (Exception ex) + { + Log("ERR: " + ex.Message); + return; } - //var prefab2 = new Prefab(new Vector3i(prefabSize.x, prefabSize.y, prefabSize.z)); - //prefab2.bCopyAirBlocks = true; - //prefab2.copyFromWorld(GameManager.Instance.World, new Vector3i(x, y, z), new Vector3i(x + prefabSize.x, y + prefabSize.y, z + prefabSize.z)); + var oldPrefab = new Prefab(prefabSize) + { + bCopyAirBlocks = true + }; + oldPrefab.copyFromWorld(GameManager.Instance.World, offsetPosition, new Vector3i(x + prefabSize.x, y + prefabSize.y, z + prefabSize.z)); + if (noSleepers) { prefab.SleeperVolumes = new List(); } - prefab.CopyIntoLocal(GameManager.Instance.World.ChunkCache, new Vector3i(x, y, z), true, true, FastTags.none); + prefab.CopyIntoLocal(GameManager.Instance.World.ChunkCache, offsetPosition, true, true, FastTags.none); - ChunkHelper.ForceReload(chunkSet); + ChunkHelper.ForceReload(chunks); - var stabilityCalculator = new StabilityCalculator(); - stabilityCalculator.Init(GameManager.Instance.World); - for (int l = 0; l < prefabSize.x; l++) - { - for (int m = 0; m < prefabSize.z; m++) - { - for (int n = 0; n < prefabSize.y; n++) - { - if (GameManager.Instance.World.GetBlock(x + l, y + n, z + m).Equals(BlockValue.Air) == false) - { - var vector3i = new Vector3i(x + l, y + n, z + m); - stabilityCalculator.BlockPlacedAt(vector3i, false); - } - } - } - } - stabilityCalculator.Cleanup(); + ChunkHelper.CalculateStability(offsetPosition, prefabSize); + int prefabInstanceId = -1; if (addToRWG) { - var dynamicPrefabDecorator = GameManager.Instance.GetDynamicPrefabDecorator(); - var prefabInstance = new PrefabInstance(dynamicPrefabDecorator.GetNextId(), prefab.location, new Vector3i(x, y, z), (byte)prefab.GetLocalRotation(), prefab, 0) - { - bPrefabCopiedIntoWorld = true - }; - dynamicPrefabDecorator.GetDynamicPrefabs().Add(prefabInstance); - dynamicPrefabDecorator.GetPOIPrefabs().Add(prefabInstance); - dynamicPrefabDecorator.Save(PathAbstractions.WorldsSearchPaths.GetLocation(GameManager.Instance.World.ChunkCache.Name, null, null).FullPath); - //if (senderInfo.RemoteClientInfo == null) - //{ - // PrefabUndo.setUndo("server_", prefab2, new Vector3i(x, y, z), prefabInstance.id); - //} - //else - //{ - // PrefabUndo.setUndo(senderInfo.RemoteClientInfo.entityId.ToString() ?? "", prefab2, new Vector3i(x, y, z), prefabInstance.id); - //} + prefabInstanceId = ChunkHelper.AddPrefabToRWG(prefab, offsetPosition); } - //else if (senderInfo.RemoteClientInfo == null) - //{ - // PrefabUndo.setUndo("server_", prefab2, new Vector3i(x, y, z), -1); - //} - //else - //{ - // PrefabUndo.setUndo(senderInfo.RemoteClientInfo.entityId.ToString() ?? "", prefab2, new Vector3i(x, y, z), -1); - //} - Log(string.Concat(new string[] - { - "Prefab ", - prefabFileName, - " loaded at ", - x.ToString(), - " ", - y.ToString(), - " ", - z.ToString() - })); + + int entityId = remoteClientInfo == null ? -1 : remoteClientInfo.entityId; + UndoPrefab.SetUndo(entityId, oldPrefab, offsetPosition, prefabInstanceId); + + Log($"Prefab {prefabFileName} loaded at {offsetPosition}"); } catch (Exception ex) { diff --git a/src/SdtdServerKit/Commands/UndoPrefab.cs b/src/SdtdServerKit/Commands/UndoPrefab.cs new file mode 100644 index 0000000..d47ec70 --- /dev/null +++ b/src/SdtdServerKit/Commands/UndoPrefab.cs @@ -0,0 +1,223 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using UniLinq; + +namespace SdtdServerKit.Commands +{ + /// + /// Undo last prefab command. + /// + public class UndoPrefab : ConsoleCmdBase + { + /// + /// + /// + /// + public override string getDescription() + { + return "Undo last prefab command."; + } + + /// + /// + /// + /// + public override string getHelp() + { + return "Usage:\n" + + " 1. ty-UndoPrefab\n" + + "1. Undo prefabs command. Works with RenderPrefab, FillBlock, ReplaceBlock and DuplicateArea\n" + + "NOTE: By default the size of undo history ise set to 1. You can change the undo history size using \"setundosize\"\n"; + } + + /// + /// + /// + /// + public override string[] getCommands() + { + return new string[] + { + "ty-UndoPrefab", + "ty-undo", + "ty-up" + }; + } + + /// + /// + /// + /// + public override void Execute(List args, CommandSenderInfo senderInfo) + { + try + { + var remoteClientInfo = senderInfo.RemoteClientInfo; + int entityId = remoteClientInfo == null ? -1 : remoteClientInfo.entityId; + + var undoPrefab = GetUndoPrefab(entityId); + if (undoPrefab == null) + { + Log("ERR: Unable to undo the last prefab command."); + } + else + { + var prefab = undoPrefab.Prefab; + int prefabInstanceId = undoPrefab.PrefabInstanceId; + var prefabSize = prefab.size; + var offsetPosition = undoPrefab.OffsetPosition; + + IEnumerable? chunks; + try + { + chunks = ChunkHelper.GetChunksInArea(offsetPosition, prefabSize); + } + catch (Exception ex) + { + Log("ERR: " + ex.Message); + return; + } + + foreach (var chunk in chunks) + { + chunk.GetSleeperVolumes().Clear(); + } + + prefab.CopyIntoLocal(GameManager.Instance.World.ChunkCache, offsetPosition, true, true, FastTags.none); + + ChunkHelper.ForceReload(chunks); + + ChunkHelper.CalculateStability(offsetPosition, prefabSize); + + CheckEntityInArea(offsetPosition.x, offsetPosition.z, offsetPosition.x + prefab.size.x, offsetPosition.z + prefab.size.z); + + if (prefabInstanceId > 0) + { + if (ChunkHelper.RemovePrefabFromRWG(prefabInstanceId)) + { + Log("Found undoBrender with \"addToRWG\". Removed prefab with PrefabInstanceId={0} from Randomgen World.", prefabInstanceId); + } + } + + Log($"Prefab Undone at {offsetPosition}"); + } + } + catch (Exception ex) + { + Log("Error in UndoPrefab.Execute" + Environment.NewLine + ex.ToString()); + } + } + + private void CheckEntityInArea(int x1, int z1, int x2, int z2) + { + // Ensures x1 is the smaller value, x2 is the larger value, and so are z1 and z2. + if (x2 < x1) + { + (x1, x2) = (x2, x1); + } + if (z2 < z1) + { + (z1, z2) = (z2, z1); + } + + var beRemoves = new List(); + try + { + foreach (var entity in GameManager.Instance.World.Entities.list) + { + if (entity is EntityAlive entityAlive && entityAlive.IsAlive() && entityAlive is EntityEnemy) // EntityClass.list[entityAlive.entityClass].bIsEnemyEntity + { + // Checks if an entity is within a specified region + var vector3i = new Vector3i(entityAlive.GetPosition()); + if (vector3i.x > x1 && vector3i.x < x2 && vector3i.z > z1 && vector3i.z < z2) + { + beRemoves.Add(entityAlive); + } + } + } + + foreach (EntityAlive entityAlive in beRemoves) + { + GameManager.Instance.World.RemoveEntity(entityAlive.entityId, EnumRemoveEntityReason.Killed); + } + } + catch (Exception ex) + { + Log("Error in UndoPrefab.CheckEntityInArea" + Environment.NewLine + ex.ToString()); + } + } + + internal static UndoPrefabObj? GetUndoPrefab(int entityId) + { + if (_prefabCache.IsValueCreated == false + || _prefabCache.Value.TryGetValue(entityId, out var list) == false + || list.Count == 0) + { + return null; + } + + var obj = list[0]; + list.RemoveAt(0); + return obj; + } + + internal static void SetUndo(int entityId, Prefab prefab, Vector3i offsetPosition, int prefabInstanceId) + { + if (_prefabCache.Value.TryGetValue(entityId, out var list) == false) + { + list = new List(); + _prefabCache.Value.Add(entityId, list); + } + + if (list.Count >= _maxUndoHistorySize) + { + list.RemoveAt(list.Count - 1); + } + + var item = new UndoPrefabObj(prefab, offsetPosition, prefabInstanceId); + list.Insert(0, item); + } + + private static int _maxUndoHistorySize = 1; + private static readonly Lazy>> _prefabCache = new Lazy>>(); + + internal static void SetMaxUndoHistorySize(int maxUndoHistorySize, int entityId) + { + if(maxUndoHistorySize <= 0 && _prefabCache.IsValueCreated) + { + if (entityId == -1) + { + _prefabCache.Value.Clear(); + } + else + { + _prefabCache.Value.Remove(entityId); + } + } + else + { + _maxUndoHistorySize = maxUndoHistorySize; + } + } + + internal class UndoPrefabObj + { + public UndoPrefabObj(Prefab prefab, Vector3i offsetPosition, int prefabInstanceId) + { + this.Prefab = prefab; + this.OffsetPosition = offsetPosition; + this.PrefabInstanceId = prefabInstanceId; + + // Clear sleeper volumes + prefab.SleeperVolumes.Clear(); + } + + public Prefab Prefab { get; set; } + public Vector3i OffsetPosition { get; set; } + public int PrefabInstanceId { get; set; } + } + } +} From 0e6b8250b34a2a56a7d76e15e4229a4dd00fc90b Mon Sep 17 00:00:00 2001 From: IceCoffee <1249993110@qq.com> Date: Thu, 19 Sep 2024 16:24:08 +0800 Subject: [PATCH 07/14] Refactor code to optimize entity removal logic MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In `ChunkHelper.cs` file: - Removed `using static SaveDataPrefsFile;` statement. - Added `RemoveEntityInArea` method to remove entities in a specified area. - Ensure that the values ​​of `x1` and `x2` as well as `z1` and `z2` are in ascending order. - Iterate over all entities in the game world, check and remove hostile and alive entities in a specified area. In `RenderPrefab.cs` file: - Removed `using System.Drawing;` and `using UniLinq;` statements. In the `UndoPrefab.cs` file: - Removed several `using` statements, including `using System;`, `using System.Collections.Generic;`, `using System.Linq;`, `using System.Text;`, and `using System.Threading.Tasks;`. - Moved the functionality of the `CheckEntityInArea` method to the `RemoveEntityInArea` method in the `ChunkHelper` class and called the new method. - Deleted the original `CheckEntityInArea` method. --- src/SdtdServerKit/ChunkHelper.cs | 41 ++++++++++++++++- src/SdtdServerKit/Commands/RenderPrefab.cs | 2 - src/SdtdServerKit/Commands/UndoPrefab.cs | 52 ++-------------------- 3 files changed, 43 insertions(+), 52 deletions(-) diff --git a/src/SdtdServerKit/ChunkHelper.cs b/src/SdtdServerKit/ChunkHelper.cs index 32aeb11..f2090c9 100644 --- a/src/SdtdServerKit/ChunkHelper.cs +++ b/src/SdtdServerKit/ChunkHelper.cs @@ -1,5 +1,4 @@ using SdtdServerKit.Managers; -using static SaveDataPrefsFile; namespace SdtdServerKit { @@ -95,6 +94,46 @@ public static void CalculateStability(Vector3i offsetPosition, Vector3i prefabSi stabilityCalculator.Cleanup(); } + /// + /// Remove entity in area. + /// + /// + /// + /// + /// + public static void RemoveEntityInArea(int x1, int z1, int x2, int z2) + { + // Ensures x1 is the smaller value, x2 is the larger value, and so are z1 and z2. + if (x2 < x1) + { + (x1, x2) = (x2, x1); + } + if (z2 < z1) + { + (z1, z2) = (z2, z1); + } + + var beRemoves = new List(); + + foreach (var entity in GameManager.Instance.World.Entities.list) + { + if (entity is EntityAlive entityAlive && entityAlive.IsAlive() && entityAlive is EntityEnemy) // EntityClass.list[entityAlive.entityClass].bIsEnemyEntity + { + // Checks if an entity is within a specified region + var vector3i = new Vector3i(entityAlive.GetPosition()); + if (vector3i.x > x1 && vector3i.x < x2 && vector3i.z > z1 && vector3i.z < z2) + { + beRemoves.Add(entityAlive); + } + } + } + + foreach (EntityAlive entityAlive in beRemoves) + { + GameManager.Instance.World.RemoveEntity(entityAlive.entityId, EnumRemoveEntityReason.Killed); + } + } + /// /// Add prefab to RWG /// diff --git a/src/SdtdServerKit/Commands/RenderPrefab.cs b/src/SdtdServerKit/Commands/RenderPrefab.cs index ee79f39..612e149 100644 --- a/src/SdtdServerKit/Commands/RenderPrefab.cs +++ b/src/SdtdServerKit/Commands/RenderPrefab.cs @@ -1,6 +1,4 @@ using SdtdServerKit.Managers; -using System.Drawing; -using UniLinq; namespace SdtdServerKit.Commands { diff --git a/src/SdtdServerKit/Commands/UndoPrefab.cs b/src/SdtdServerKit/Commands/UndoPrefab.cs index d47ec70..8de3999 100644 --- a/src/SdtdServerKit/Commands/UndoPrefab.cs +++ b/src/SdtdServerKit/Commands/UndoPrefab.cs @@ -1,11 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using UniLinq; - -namespace SdtdServerKit.Commands +namespace SdtdServerKit.Commands { /// /// Undo last prefab command. @@ -92,7 +85,7 @@ public override void Execute(List args, CommandSenderInfo senderInfo) ChunkHelper.CalculateStability(offsetPosition, prefabSize); - CheckEntityInArea(offsetPosition.x, offsetPosition.z, offsetPosition.x + prefab.size.x, offsetPosition.z + prefab.size.z); + ChunkHelper.RemoveEntityInArea(offsetPosition.x, offsetPosition.z, offsetPosition.x + prefab.size.x, offsetPosition.z + prefab.size.z); if (prefabInstanceId > 0) { @@ -109,46 +102,7 @@ public override void Execute(List args, CommandSenderInfo senderInfo) { Log("Error in UndoPrefab.Execute" + Environment.NewLine + ex.ToString()); } - } - - private void CheckEntityInArea(int x1, int z1, int x2, int z2) - { - // Ensures x1 is the smaller value, x2 is the larger value, and so are z1 and z2. - if (x2 < x1) - { - (x1, x2) = (x2, x1); - } - if (z2 < z1) - { - (z1, z2) = (z2, z1); - } - - var beRemoves = new List(); - try - { - foreach (var entity in GameManager.Instance.World.Entities.list) - { - if (entity is EntityAlive entityAlive && entityAlive.IsAlive() && entityAlive is EntityEnemy) // EntityClass.list[entityAlive.entityClass].bIsEnemyEntity - { - // Checks if an entity is within a specified region - var vector3i = new Vector3i(entityAlive.GetPosition()); - if (vector3i.x > x1 && vector3i.x < x2 && vector3i.z > z1 && vector3i.z < z2) - { - beRemoves.Add(entityAlive); - } - } - } - - foreach (EntityAlive entityAlive in beRemoves) - { - GameManager.Instance.World.RemoveEntity(entityAlive.entityId, EnumRemoveEntityReason.Killed); - } - } - catch (Exception ex) - { - Log("Error in UndoPrefab.CheckEntityInArea" + Environment.NewLine + ex.ToString()); - } - } + } internal static UndoPrefabObj? GetUndoPrefab(int entityId) { From 5b2ef4e3f09aa9aa05842c58814e17a8eb550da0 Mon Sep 17 00:00:00 2001 From: IceCoffee <1249993110@qq.com> Date: Thu, 19 Sep 2024 16:48:28 +0800 Subject: [PATCH 08/14] Refactoring and extending the undo operation function In the `RenderPrefab.cs` and `UndoPrefab.cs` files, the reference to `senderInfo.RemoteClientInfo` was removed, and the `senderInfo.GetEntityId()` method was used to obtain the `entityId`. In `UndoPrefab.cs`, the `GetMaxUndoHistorySize` method was added. Added the `SetUndoSize.cs` file, which defines the `SetUndoSize` command, which is used to set or get the history size of the undo operation. Added the `CommandSenderInfoExtension.cs` file, which defines the `GetEntityId` extension method, which is used to obtain the `entityId` from the `CommandSenderInfo` object. --- src/SdtdServerKit/Commands/RenderPrefab.cs | 11 +-- src/SdtdServerKit/Commands/SetUndoSize.cs | 80 +++++++++++++++++++ src/SdtdServerKit/Commands/UndoPrefab.cs | 11 +-- .../Extensions/CommandSenderInfoExtension.cs | 19 +++++ 4 files changed, 109 insertions(+), 12 deletions(-) create mode 100644 src/SdtdServerKit/Commands/SetUndoSize.cs create mode 100644 src/SdtdServerKit/Extensions/CommandSenderInfoExtension.cs diff --git a/src/SdtdServerKit/Commands/RenderPrefab.cs b/src/SdtdServerKit/Commands/RenderPrefab.cs index 612e149..1f3a68d 100644 --- a/src/SdtdServerKit/Commands/RenderPrefab.cs +++ b/src/SdtdServerKit/Commands/RenderPrefab.cs @@ -55,14 +55,11 @@ public override string[] getCommands() /// /// /// - /// public override void Execute(List args, CommandSenderInfo senderInfo) { try { CustomLogger.Warn("Is Main: " + ThreadManager.IsMainThread()); - var remoteClientInfo = senderInfo.RemoteClientInfo; - if (args.Count < 1 || args.Count > 7) { Log($"ERR: Wrong number of arguments, expected 1 to 7, found {args.Count}."); @@ -102,12 +99,13 @@ public override void Execute(List args, CommandSenderInfo senderInfo) } else { - if (remoteClientInfo == null) + int entityId = senderInfo.GetEntityId(); + if (entityId == -1) { Log("ERR: This command can be only sent by player in game."); return; } - if (LivePlayerManager.TryGetByEntityId(remoteClientInfo.entityId, out var managedPlayer) == false) + if (LivePlayerManager.TryGetByEntityId(entityId, out var managedPlayer) == false) { Log("ERR: Unable to get your position"); return; @@ -193,8 +191,7 @@ public override void Execute(List args, CommandSenderInfo senderInfo) prefabInstanceId = ChunkHelper.AddPrefabToRWG(prefab, offsetPosition); } - int entityId = remoteClientInfo == null ? -1 : remoteClientInfo.entityId; - UndoPrefab.SetUndo(entityId, oldPrefab, offsetPosition, prefabInstanceId); + UndoPrefab.SetUndo(senderInfo.GetEntityId(), oldPrefab, offsetPosition, prefabInstanceId); Log($"Prefab {prefabFileName} loaded at {offsetPosition}"); } diff --git a/src/SdtdServerKit/Commands/SetUndoSize.cs b/src/SdtdServerKit/Commands/SetUndoSize.cs new file mode 100644 index 0000000..2cf6713 --- /dev/null +++ b/src/SdtdServerKit/Commands/SetUndoSize.cs @@ -0,0 +1,80 @@ +namespace SdtdServerKit.Commands +{ + /// + /// Set the size of history on UndoPrefab operation. + /// + public class SetUndoSize : ConsoleCmdBase + { + /// + /// + /// + /// + public override string getDescription() + { + return "Set the size of history on UndoPrefab operation"; + } + + /// + /// + /// + /// + public override string getHelp() + { + return "Usage:\n" + + " 1. ty-SetUndoSize {size}\n" + + " 2. ty-SetUndoSize\n" + + "1. Sets the setundosize history size. If the size is less than or equal to 0, the history prefab of the current active session will be cleared. If this command is executed on a dedicated server, the history prefab of all clients will be cleared.\n" + + "2. Gets the setundosize history size\n"; + } + + /// + /// + /// + /// + public override string[] getCommands() + { + return new string[] + { + "ty-SetUndoSize", + "ty-suz", + "setundosize" + }; + } + + /// + /// + /// + public override void Execute(List args, CommandSenderInfo senderInfo) + { + try + { + if (args.Count == 0) + { + Log("Undo history size is " + UndoPrefab.GetMaxUndoHistorySize()); + } + else + { + if (int.TryParse(args[0], out int value) == false) + { + Log("ERR: Invalid undo history size. It must be a number."); + return; + } + + UndoPrefab.SetMaxUndoHistorySize(value, senderInfo.GetEntityId()); + if(value > 0) + { + Log("Undo history size set to " + value); + } + else + { + Log("Undo history cleared."); + } + } + } + catch (Exception ex) + { + Log("Error in RenderPrefab.SetUndoSize" + Environment.NewLine + ex.ToString()); + } + } + } +} diff --git a/src/SdtdServerKit/Commands/UndoPrefab.cs b/src/SdtdServerKit/Commands/UndoPrefab.cs index 8de3999..a518d65 100644 --- a/src/SdtdServerKit/Commands/UndoPrefab.cs +++ b/src/SdtdServerKit/Commands/UndoPrefab.cs @@ -43,15 +43,11 @@ public override string[] getCommands() /// /// /// - /// public override void Execute(List args, CommandSenderInfo senderInfo) { try { - var remoteClientInfo = senderInfo.RemoteClientInfo; - int entityId = remoteClientInfo == null ? -1 : remoteClientInfo.entityId; - - var undoPrefab = GetUndoPrefab(entityId); + var undoPrefab = GetUndoPrefab(senderInfo.GetEntityId()); if (undoPrefab == null) { Log("ERR: Unable to undo the last prefab command."); @@ -157,6 +153,11 @@ internal static void SetMaxUndoHistorySize(int maxUndoHistorySize, int entityId) } } + internal static int GetMaxUndoHistorySize() + { + return _maxUndoHistorySize; + } + internal class UndoPrefabObj { public UndoPrefabObj(Prefab prefab, Vector3i offsetPosition, int prefabInstanceId) diff --git a/src/SdtdServerKit/Extensions/CommandSenderInfoExtension.cs b/src/SdtdServerKit/Extensions/CommandSenderInfoExtension.cs new file mode 100644 index 0000000..8ac3ad9 --- /dev/null +++ b/src/SdtdServerKit/Extensions/CommandSenderInfoExtension.cs @@ -0,0 +1,19 @@ +namespace SdtdServerKit.Extensions +{ + /// + /// Extension methods for CommandSenderInfo. + /// + public static class CommandSenderInfoExtension + { + /// + /// Get the EntityId of the sender. + /// + /// + /// + public static int GetEntityId(this CommandSenderInfo senderInfo) + { + var remoteClientInfo = senderInfo.RemoteClientInfo; + return remoteClientInfo == null ? -1 : remoteClientInfo.entityId; + } + } +} From d566f281ab1aec027c00d4441c74175440c7ca84 Mon Sep 17 00:00:00 2001 From: IceCoffee <1249993110@qq.com> Date: Thu, 19 Sep 2024 17:13:34 +0800 Subject: [PATCH 09/14] Refactored namespaces and updated utility classes Moved `ChunkHelper` class from `SdtdServerKit` namespace to `SdtdServerKit.Utilities` namespace and reintroduced `SdtdServerKit.Managers`. In `GarbageCollection` class, changed the return value of `getDescription` method. Changed from "Garbage collection" to "Use the framework's own methods for garbage collection.". In `GlobalUsings.cs` file, added `global using SdtdServerKit.Utilities;`. Deleted `Utils` class and all its methods, including methods for getting the number of items in a player's backpack, giving items to a player, checking if there are zombies around a player, determining if two players are friends, getting the player's position, teleporting a player, sending a global message, sending a private message, executing a console command, getting the number of days left in a blood moon, formatting command arguments, and getting localized strings. Added a new namespace `SdtdServerKit.Utilities`. Added several static methods in the `Utils` class: `GetPlayerInventoryStackCount`, `GiveItem`, `ZombieCheck`, `IsFriend`, `GetPlayerPosition`, `TeleportPlayer`, `SendGlobalMessage`, `SendPrivateMessage`, `ExecuteConsoleCommand`, `DaysRemaining`, `FormatCommandArgs`, `GetLocalization`. --- src/SdtdServerKit/Commands/GarbageCollection.cs | 2 +- src/SdtdServerKit/GlobalUsings.cs | 1 + src/SdtdServerKit/{ => Utilities}/ChunkHelper.cs | 2 +- src/SdtdServerKit/{ => Utilities}/Utils.cs | 10 +++++----- 4 files changed, 8 insertions(+), 7 deletions(-) rename src/SdtdServerKit/{ => Utilities}/ChunkHelper.cs (99%) rename src/SdtdServerKit/{ => Utilities}/Utils.cs (95%) diff --git a/src/SdtdServerKit/Commands/GarbageCollection.cs b/src/SdtdServerKit/Commands/GarbageCollection.cs index 34219cd..0c5bc14 100644 --- a/src/SdtdServerKit/Commands/GarbageCollection.cs +++ b/src/SdtdServerKit/Commands/GarbageCollection.cs @@ -10,7 +10,7 @@ public class GarbageCollection : ConsoleCmdBase /// public override string getDescription() { - return "Garbage collection"; + return "Use the framework's own methods for garbage collection."; } /// diff --git a/src/SdtdServerKit/GlobalUsings.cs b/src/SdtdServerKit/GlobalUsings.cs index 749b55c..db18937 100644 --- a/src/SdtdServerKit/GlobalUsings.cs +++ b/src/SdtdServerKit/GlobalUsings.cs @@ -1,4 +1,5 @@ global using SdtdServerKit.Models; +global using SdtdServerKit.Utilities; global using SdtdServerKit.Constants; global using SdtdServerKit.Extensions; global using IceCoffee.Common.Extensions; diff --git a/src/SdtdServerKit/ChunkHelper.cs b/src/SdtdServerKit/Utilities/ChunkHelper.cs similarity index 99% rename from src/SdtdServerKit/ChunkHelper.cs rename to src/SdtdServerKit/Utilities/ChunkHelper.cs index f2090c9..c33455f 100644 --- a/src/SdtdServerKit/ChunkHelper.cs +++ b/src/SdtdServerKit/Utilities/ChunkHelper.cs @@ -1,6 +1,6 @@ using SdtdServerKit.Managers; -namespace SdtdServerKit +namespace SdtdServerKit.Utilities { /// /// Provides a set of helper methods for chunks. diff --git a/src/SdtdServerKit/Utils.cs b/src/SdtdServerKit/Utilities/Utils.cs similarity index 95% rename from src/SdtdServerKit/Utils.cs rename to src/SdtdServerKit/Utilities/Utils.cs index d198691..3d7f23e 100644 --- a/src/SdtdServerKit/Utils.cs +++ b/src/SdtdServerKit/Utilities/Utils.cs @@ -1,4 +1,4 @@ -namespace SdtdServerKit +namespace SdtdServerKit.Utilities { /// /// 工具类 @@ -15,7 +15,7 @@ public static class Utils public static int GetPlayerInventoryStackCount(string playerId, string itemName) { var userId = PlatformUserIdentifierAbs.FromCombinedString(playerId); - if(userId == null) + if (userId == null) { throw new Exception("Invalid player id."); } @@ -93,7 +93,7 @@ public static bool IsFriend(int entityId, int anotherEntityId) /// public static Position GetPlayerPosition(int entityId) { - if(GameManager.Instance.World.Players.dict.TryGetValue(entityId, out EntityPlayer player)) + if (GameManager.Instance.World.Players.dict.TryGetValue(entityId, out EntityPlayer player)) { return player.position.ToPosition(); } @@ -101,7 +101,7 @@ public static Position GetPlayerPosition(int entityId) var clientInfo = ConnectionManager.Instance.Clients.ForEntityId(entityId); if (clientInfo != null) { - if(GameManager.Instance.GetPersistentPlayerList().Players.TryGetValue(clientInfo.InternalId, out PersistentPlayerData persistentPlayerData)) + if (GameManager.Instance.GetPersistentPlayerList().Players.TryGetValue(clientInfo.InternalId, out PersistentPlayerData persistentPlayerData)) { return persistentPlayerData.Position.ToPosition(); } @@ -142,7 +142,7 @@ public static IEnumerable TeleportPlayer(string originPlayerIdOrName, st /// public static IEnumerable SendGlobalMessage(GlobalMessage globalMessage) { - string cmd = string.Format("ty-say {0} {1}", + string cmd = string.Format("ty-say {0} {1}", FormatCommandArgs(globalMessage.Message), FormatCommandArgs(globalMessage.SenderName)); return ExecuteConsoleCommand(cmd); From 4ac3fc3ac079a0f76734d54220d1118a95a71ae6 Mon Sep 17 00:00:00 2001 From: IceCoffee <1249993110@qq.com> Date: Thu, 19 Sep 2024 19:34:42 +0800 Subject: [PATCH 10/14] Refactoring and fixes: Update Utils references and logic adjustments - Replaced `Utils` methods in multiple files with `Utilities.Utils` methods. - In `UndoPrefab.cs`, adjusted the logic of the `SetMaxUndoHistorySize` method, removed the `entityId` check and optimized the `_prefabCache` cleanup. - In `ChunkHelper.cs`, modified the exception message text. --- src/SdtdServerKit/Commands/SetUndoSize.cs | 2 +- src/SdtdServerKit/Commands/UndoPrefab.cs | 17 ++++++++++------- .../Extensions/PlayerDataFileExtension.cs | 2 +- src/SdtdServerKit/Functions/FunctionBase.cs | 4 ++-- src/SdtdServerKit/Functions/GameStore.cs | 4 ++-- src/SdtdServerKit/Functions/GlobalSettings.cs | 10 +++++----- src/SdtdServerKit/Functions/PointsSystem.cs | 4 ++-- src/SdtdServerKit/Functions/TeleportCity.cs | 6 +++--- src/SdtdServerKit/Functions/TeleportFriend.cs | 10 +++++----- src/SdtdServerKit/Functions/TeleportHome.cs | 8 ++++---- src/SdtdServerKit/Functions/VipGift.cs | 4 ++-- src/SdtdServerKit/Hooks/ChatMessageHook.cs | 4 ++-- src/SdtdServerKit/Triggers/SkyChangeTrigger.cs | 4 ++-- src/SdtdServerKit/Utilities/ChunkHelper.cs | 2 +- .../WebApi/Controllers/AdminsController.cs | 2 +- .../WebApi/Controllers/BlacklistController.cs | 2 +- .../WebApi/Controllers/ItemBlocksController.cs | 2 +- .../Controllers/LocalizationController.cs | 2 +- .../WebApi/Controllers/MapController.cs | 2 +- .../Controllers/PlayerSkillsController.cs | 8 ++++---- .../WebApi/Controllers/ServerController.cs | 8 ++++---- .../WebApi/Controllers/WhitelistController.cs | 2 +- 22 files changed, 56 insertions(+), 53 deletions(-) diff --git a/src/SdtdServerKit/Commands/SetUndoSize.cs b/src/SdtdServerKit/Commands/SetUndoSize.cs index 2cf6713..48aa854 100644 --- a/src/SdtdServerKit/Commands/SetUndoSize.cs +++ b/src/SdtdServerKit/Commands/SetUndoSize.cs @@ -36,7 +36,7 @@ public override string[] getCommands() return new string[] { "ty-SetUndoSize", - "ty-suz", + "ty-sus", "setundosize" }; } diff --git a/src/SdtdServerKit/Commands/UndoPrefab.cs b/src/SdtdServerKit/Commands/UndoPrefab.cs index a518d65..0301029 100644 --- a/src/SdtdServerKit/Commands/UndoPrefab.cs +++ b/src/SdtdServerKit/Commands/UndoPrefab.cs @@ -136,15 +136,18 @@ internal static void SetUndo(int entityId, Prefab prefab, Vector3i offsetPositio internal static void SetMaxUndoHistorySize(int maxUndoHistorySize, int entityId) { - if(maxUndoHistorySize <= 0 && _prefabCache.IsValueCreated) + if(maxUndoHistorySize <= 0) { - if (entityId == -1) + if (_prefabCache.IsValueCreated) { - _prefabCache.Value.Clear(); - } - else - { - _prefabCache.Value.Remove(entityId); + if (entityId == -1) + { + _prefabCache.Value.Clear(); + } + else + { + _prefabCache.Value.Remove(entityId); + } } } else diff --git a/src/SdtdServerKit/Extensions/PlayerDataFileExtension.cs b/src/SdtdServerKit/Extensions/PlayerDataFileExtension.cs index 04c5684..207079f 100644 --- a/src/SdtdServerKit/Extensions/PlayerDataFileExtension.cs +++ b/src/SdtdServerKit/Extensions/PlayerDataFileExtension.cs @@ -168,7 +168,7 @@ private static void ProcessParts(ItemValue[] parts, InvItem item, int entityId, InvItem item = new InvItem() { ItemName = name, - LocalizationName = Utils.GetLocalization(name, language), + LocalizationName = Utilities.Utils.GetLocalization(name, language), Count = count, MaxStackAllowed = itemClass.Stacknumber.Value, Quality = quality, diff --git a/src/SdtdServerKit/Functions/FunctionBase.cs b/src/SdtdServerKit/Functions/FunctionBase.cs index 41aebec..3f7a148 100644 --- a/src/SdtdServerKit/Functions/FunctionBase.cs +++ b/src/SdtdServerKit/Functions/FunctionBase.cs @@ -148,7 +148,7 @@ protected virtual void OnSettingsChanged() /// protected void SendGlobalMessage(string message) { - Utils.SendGlobalMessage(new GlobalMessage() + Utilities.Utils.SendGlobalMessage(new GlobalMessage() { Message = message, SenderName = ConfigManager.GlobalSettings.GlobalServerName @@ -163,7 +163,7 @@ protected void SendGlobalMessage(string message) /// protected void SendMessageToPlayer(string playerIdOrName, string message) { - Utils.SendPrivateMessage(new PrivateMessage() + Utilities.Utils.SendPrivateMessage(new PrivateMessage() { TargetPlayerIdOrName = playerIdOrName, Message = message, diff --git a/src/SdtdServerKit/Functions/GameStore.cs b/src/SdtdServerKit/Functions/GameStore.cs index 26f77bf..a7c6403 100644 --- a/src/SdtdServerKit/Functions/GameStore.cs +++ b/src/SdtdServerKit/Functions/GameStore.cs @@ -69,13 +69,13 @@ protected override async Task OnChatCmd(string message, ManagedPlayer mana var itemList = await _itemListRepository.GetListByGoodsIdAsync(goods.Id); foreach (var item in itemList) { - Utils.GiveItem(playerId, item.ItemName, item.Count, item.Quality, item.Durability); + Utilities.Utils.GiveItem(playerId, item.ItemName, item.Count, item.Quality, item.Durability); } var commandList = await _commandListRepository.GetListByGoodsIdAsync(goods.Id); foreach (var item in commandList) { - Utils.ExecuteConsoleCommand(FormatCmd(item.Command, managedPlayer, goods), item.InMainThread); + Utilities.Utils.ExecuteConsoleCommand(FormatCmd(item.Command, managedPlayer, goods), item.InMainThread); } SendMessageToPlayer(playerId, FormatCmd(Settings.BuySuccessTip, managedPlayer, goods)); diff --git a/src/SdtdServerKit/Functions/GlobalSettings.cs b/src/SdtdServerKit/Functions/GlobalSettings.cs index 91bef7b..f403387 100644 --- a/src/SdtdServerKit/Functions/GlobalSettings.cs +++ b/src/SdtdServerKit/Functions/GlobalSettings.cs @@ -46,7 +46,7 @@ private void OnEntitySpawned(EntityInfo entityInfo) } if(zombies > Settings.AutoZombieCleanupThreshold) { - Utils.ExecuteConsoleCommand("ty-RemoveEntity " + entityInfo.EntityId, true); + Utilities.Utils.ExecuteConsoleCommand("ty-RemoveEntity " + entityInfo.EntityId, true); CustomLogger.Info($"Auto zombie cleanup triggered, the entity: {entityInfo.EntityName} was removed."); } } @@ -105,7 +105,7 @@ private void BlockFamilySharingAccount(ClientInfo clientInfo) if (clientInfo.PlatformId is UserIdentifierSteam userIdentifierSteam && userIdentifierSteam.OwnerId.Equals(userIdentifierSteam) == false) { - Utils.ExecuteConsoleCommand("kick " + clientInfo.entityId + " \"Family sharing account is not allowed to join the server!\""); + Utilities.Utils.ExecuteConsoleCommand("kick " + clientInfo.entityId + " \"Family sharing account is not allowed to join the server!\""); } } @@ -129,7 +129,7 @@ private async void AutoRestart() } } - Utils.ExecuteConsoleCommand("ty-rs", true); + Utilities.Utils.ExecuteConsoleCommand("ty-rs", true); } } @@ -153,7 +153,7 @@ private void OnPlayerSpawnedInWorld(SpawnedPlayer player) { if (string.IsNullOrEmpty(command) == false) { - Utils.ExecuteConsoleCommand(FormatCmd(command, player), true); + Utilities.Utils.ExecuteConsoleCommand(FormatCmd(command, player), true); } } } @@ -171,7 +171,7 @@ private void OnEntityKilled(KilledEntity entity) { if (string.IsNullOrEmpty(command) == false) { - Utils.ExecuteConsoleCommand(FormatCmd(command, player), true); + Utilities.Utils.ExecuteConsoleCommand(FormatCmd(command, player), true); } } } diff --git a/src/SdtdServerKit/Functions/PointsSystem.cs b/src/SdtdServerKit/Functions/PointsSystem.cs index d2a7430..5ac95be 100644 --- a/src/SdtdServerKit/Functions/PointsSystem.cs +++ b/src/SdtdServerKit/Functions/PointsSystem.cs @@ -91,14 +91,14 @@ protected override async Task OnChatCmd(string message, ManagedPlayer play return true; } const string currencyName = "casinoCoin"; - int currencyAmount = Utils.GetPlayerInventoryStackCount(playerId, currencyName); + int currencyAmount = Utilities.Utils.GetPlayerInventoryStackCount(playerId, currencyName); if (currencyAmount <= 0) { SendMessageToPlayer(playerId, base.FormatCmd(Settings.ExchangeFailureTip, player)); return true; } - Utils.ExecuteConsoleCommand($"ty-rpi {playerId} {currencyName}"); + Utilities.Utils.ExecuteConsoleCommand($"ty-rpi {playerId} {currencyName}"); int increasePoints = (int)Math.Round(currencyAmount * Settings.CurrencyToPointsExchangeRate); await _pointsInfoRepository.ChangePointsAsync(playerId, increasePoints); diff --git a/src/SdtdServerKit/Functions/TeleportCity.cs b/src/SdtdServerKit/Functions/TeleportCity.cs index 2a2c0c3..b818a68 100644 --- a/src/SdtdServerKit/Functions/TeleportCity.cs +++ b/src/SdtdServerKit/Functions/TeleportCity.cs @@ -80,7 +80,7 @@ protected override async Task OnChatCmd(string message, ManagedPlayer mana if(ConfigManager.GlobalSettings.TeleZombieCheck && GameManager.Instance.World.Players.dict.TryGetValue(managedPlayer.EntityId, out EntityPlayer player)) { - if (Utils.ZombieCheck(player)) + if (Utilities.Utils.ZombieCheck(player)) { SendMessageToPlayer(playerId, ConfigManager.GlobalSettings.TeleDisableTip); return true; @@ -88,7 +88,7 @@ protected override async Task OnChatCmd(string message, ManagedPlayer mana } await _pointsInfoRepository.ChangePointsAsync(playerId, -cityPosition.PointsRequired); - Utils.TeleportPlayer(managedPlayer.EntityId.ToString(), cityPosition.Position, cityPosition.ViewDirection); + Utilities.Utils.TeleportPlayer(managedPlayer.EntityId.ToString(), cityPosition.Position, cityPosition.ViewDirection); SendGlobalMessage(FormatCmd(Settings.TeleSuccessTip, managedPlayer, cityPosition)); await _teleRecordRepository.InsertAsync(new T_TeleRecord() @@ -96,7 +96,7 @@ await _teleRecordRepository.InsertAsync(new T_TeleRecord() CreatedAt = DateTime.Now, PlayerId = playerId, PlayerName = managedPlayer.PlayerName, - OriginPosition = Utils.GetPlayerPosition(managedPlayer.EntityId).ToString(), + OriginPosition = Utilities.Utils.GetPlayerPosition(managedPlayer.EntityId).ToString(), TargetPosition = cityPosition.Position, TargetType = TeleTargetType.City.ToString(), TargetName = cityPosition.CityName diff --git a/src/SdtdServerKit/Functions/TeleportFriend.cs b/src/SdtdServerKit/Functions/TeleportFriend.cs index ea4cc59..a7849c0 100644 --- a/src/SdtdServerKit/Functions/TeleportFriend.cs +++ b/src/SdtdServerKit/Functions/TeleportFriend.cs @@ -83,7 +83,7 @@ private async Task Tele(ManagedPlayer managedPlayer, ManagedPlayer targetPlayer) await _pointsRepository.ChangePointsAsync(srcPlayerId, -Settings.PointsRequired); - Utils.TeleportPlayer(managedPlayer.EntityId.ToString(), targetPlayer.EntityId.ToString()); + Utilities.Utils.TeleportPlayer(managedPlayer.EntityId.ToString(), targetPlayer.EntityId.ToString()); string messageToPlayer = FormatCmd(Settings.TeleSuccessTip, managedPlayer, targetName); SendMessageToPlayer(srcPlayerId, messageToPlayer); SendMessageToPlayer(targetPlayer.PlayerId, messageToPlayer); @@ -95,8 +95,8 @@ await _teleRecordRepository.InsertAsync(new T_TeleRecord() PlayerName = managedPlayer.PlayerName, TargetName = targetName, TargetType = TeleTargetType.Friend.ToString(), - OriginPosition = Utils.GetPlayerPosition(managedPlayer.EntityId).ToString(), - TargetPosition = Utils.GetPlayerPosition(targetPlayer.EntityId).ToString(), + OriginPosition = Utilities.Utils.GetPlayerPosition(managedPlayer.EntityId).ToString(), + TargetPosition = Utilities.Utils.GetPlayerPosition(targetPlayer.EntityId).ToString(), }); CustomLogger.Info("Player: {0}, entityId: {1}, teleported to: {2}", managedPlayer.PlayerName, managedPlayer.EntityId, targetName); @@ -139,14 +139,14 @@ protected override async Task OnChatCmd(string message, ManagedPlayer mana if (ConfigManager.GlobalSettings.TeleZombieCheck && GameManager.Instance.World.Players.dict.TryGetValue(managedPlayer.EntityId, out EntityPlayer player)) { - if (Utils.ZombieCheck(player)) + if (Utilities.Utils.ZombieCheck(player)) { SendMessageToPlayer(playerId, ConfigManager.GlobalSettings.TeleDisableTip); return true; } } - if (Settings.IsFriendBypass && Utils.IsFriend(managedPlayer.EntityId, targetPlayer.EntityId)) + if (Settings.IsFriendBypass && Utilities.Utils.IsFriend(managedPlayer.EntityId, targetPlayer.EntityId)) { await Tele(managedPlayer, targetPlayer); } diff --git a/src/SdtdServerKit/Functions/TeleportHome.cs b/src/SdtdServerKit/Functions/TeleportHome.cs index 71c0ae1..0538729 100644 --- a/src/SdtdServerKit/Functions/TeleportHome.cs +++ b/src/SdtdServerKit/Functions/TeleportHome.cs @@ -59,7 +59,7 @@ protected override async Task OnChatCmd(string message, ManagedPlayer mana else { var entity = await _homeLocationRepository.GetByPlayerIdAndHomeNameAsync(playerId, homeName); - string position = Utils.GetPlayerPosition(managedPlayer.EntityId).ToString(); + string position = Utilities.Utils.GetPlayerPosition(managedPlayer.EntityId).ToString(); // new home postion if (entity == null) { @@ -149,7 +149,7 @@ protected override async Task OnChatCmd(string message, ManagedPlayer mana if (ConfigManager.GlobalSettings.TeleZombieCheck && GameManager.Instance.World.Players.dict.TryGetValue(managedPlayer.EntityId, out EntityPlayer player)) { - if (Utils.ZombieCheck(player)) + if (Utilities.Utils.ZombieCheck(player)) { SendMessageToPlayer(playerId, ConfigManager.GlobalSettings.TeleDisableTip); return true; @@ -157,7 +157,7 @@ protected override async Task OnChatCmd(string message, ManagedPlayer mana } await _pointsRepository.ChangePointsAsync(playerId, -Settings.PointsRequiredForTele); - Utils.TeleportPlayer(managedPlayer.EntityId.ToString(), entity.Position); + Utilities.Utils.TeleportPlayer(managedPlayer.EntityId.ToString(), entity.Position); SendGlobalMessage(FormatCmd(Settings.TeleSuccessTip, managedPlayer, entity)); await _teleRecordRepository.InsertAsync(new T_TeleRecord() @@ -165,7 +165,7 @@ await _teleRecordRepository.InsertAsync(new T_TeleRecord() CreatedAt = DateTime.Now, PlayerId = playerId, PlayerName = managedPlayer.PlayerName, - OriginPosition = Utils.GetPlayerPosition(managedPlayer.EntityId).ToString(), + OriginPosition = Utilities.Utils.GetPlayerPosition(managedPlayer.EntityId).ToString(), TargetPosition = entity.Position, TargetType = TeleTargetType.Home.ToString(), TargetName = entity.HomeName diff --git a/src/SdtdServerKit/Functions/VipGift.cs b/src/SdtdServerKit/Functions/VipGift.cs index 4e42965..9935d5f 100644 --- a/src/SdtdServerKit/Functions/VipGift.cs +++ b/src/SdtdServerKit/Functions/VipGift.cs @@ -44,13 +44,13 @@ protected override async Task OnChatCmd(string message, ManagedPlayer mana var itemList = await _itemListRepository.GetListByVipGiftIdAsync(vipGift.Id); foreach (var item in itemList) { - Utils.GiveItem(playerId, item.ItemName, item.Count, item.Quality, item.Durability); + Utilities.Utils.GiveItem(playerId, item.ItemName, item.Count, item.Quality, item.Durability); } var commandList = await _commandListRepository.GetListByVipGiftIdAsync(vipGift.Id); foreach (var item in commandList) { - Utils.ExecuteConsoleCommand(FormatCmd(item.Command, managedPlayer, vipGift), item.InMainThread); + Utilities.Utils.ExecuteConsoleCommand(FormatCmd(item.Command, managedPlayer, vipGift), item.InMainThread); } vipGift.ClaimState = true; diff --git a/src/SdtdServerKit/Hooks/ChatMessageHook.cs b/src/SdtdServerKit/Hooks/ChatMessageHook.cs index 8c5c720..fdb5c34 100644 --- a/src/SdtdServerKit/Hooks/ChatMessageHook.cs +++ b/src/SdtdServerKit/Hooks/ChatMessageHook.cs @@ -55,7 +55,7 @@ private static async Task HandleChatCmd(ChatHook chatHook, string cmd, Man { CustomLogger.Error(ex, "Error in ChatMessageHook.HandleChatMessage"); - Utils.SendPrivateMessage(new PrivateMessage() + Utilities.Utils.SendPrivateMessage(new PrivateMessage() { Message = ConfigManager.GlobalSettings.HandleChatMessageError, //SenderName = ConfigManager.GlobalSettings.ServerName, @@ -131,7 +131,7 @@ internal static async Task OnChatMessage(ChatMessage chatMessage) { CustomLogger.Error(ex, "Error in ChatMessageHook.OnChatMessage"); - Utils.SendPrivateMessage(new PrivateMessage() + Utilities.Utils.SendPrivateMessage(new PrivateMessage() { Message = ConfigManager.GlobalSettings.HandleChatMessageError, TargetPlayerIdOrName = chatMessage.PlayerId!, diff --git a/src/SdtdServerKit/Triggers/SkyChangeTrigger.cs b/src/SdtdServerKit/Triggers/SkyChangeTrigger.cs index 6503040..0f712c2 100644 --- a/src/SdtdServerKit/Triggers/SkyChangeTrigger.cs +++ b/src/SdtdServerKit/Triggers/SkyChangeTrigger.cs @@ -47,7 +47,7 @@ public static void Callback() { ModEventHub.OnSkyChanged(new SkyChanged() { - BloodMoonDaysRemaining = Utils.DaysRemaining(days), + BloodMoonDaysRemaining = Utilities.Utils.DaysRemaining(days), DawnHour = world.DawnHour, DuskHour = world.DuskHour, SkyChangeEventType = SkyChangeEventType.Dusk @@ -60,7 +60,7 @@ public static void Callback() { ModEventHub.OnSkyChanged(new SkyChanged() { - BloodMoonDaysRemaining = Utils.DaysRemaining(days), + BloodMoonDaysRemaining = Utilities.Utils.DaysRemaining(days), DawnHour = world.DawnHour, DuskHour = world.DuskHour, SkyChangeEventType = SkyChangeEventType.Dawn diff --git a/src/SdtdServerKit/Utilities/ChunkHelper.cs b/src/SdtdServerKit/Utilities/ChunkHelper.cs index c33455f..702bb27 100644 --- a/src/SdtdServerKit/Utilities/ChunkHelper.cs +++ b/src/SdtdServerKit/Utilities/ChunkHelper.cs @@ -56,7 +56,7 @@ public static IEnumerable GetChunksInArea(Vector3i offsetPosition, Vector int z = offsetPosition.z + j; if (GameManager.Instance.World.IsChunkAreaLoaded(x, y, z) == false) { - throw new Exception("The prefab is too far away. Chunk not loaded on that area."); + throw new Exception("The prefab is too far away or target area is not loaded. Chunk not loaded on that area."); } var chunk = (Chunk)GameManager.Instance.World.GetChunkFromWorldPos(x, y, z); diff --git a/src/SdtdServerKit/WebApi/Controllers/AdminsController.cs b/src/SdtdServerKit/WebApi/Controllers/AdminsController.cs index c8c7d8d..e58d4bf 100644 --- a/src/SdtdServerKit/WebApi/Controllers/AdminsController.cs +++ b/src/SdtdServerKit/WebApi/Controllers/AdminsController.cs @@ -20,7 +20,7 @@ public IEnumerable AddAdmins([FromBody, Required, MinLength(1)] AdminEnt var executeResult = new List(); foreach (var item in admins) { - string command = $"admin add {item.PlayerId} {item.PermissionLevel} {Utils.FormatCommandArgs(item.DisplayName)}"; + string command = $"admin add {item.PlayerId} {item.PermissionLevel} {Utilities.Utils.FormatCommandArgs(item.DisplayName)}"; var result = SdtdConsole.Instance.ExecuteSync(command, ModApi.CmdExecuteDelegate); executeResult.AddRange(result); } diff --git a/src/SdtdServerKit/WebApi/Controllers/BlacklistController.cs b/src/SdtdServerKit/WebApi/Controllers/BlacklistController.cs index 4212aa9..d22417f 100644 --- a/src/SdtdServerKit/WebApi/Controllers/BlacklistController.cs +++ b/src/SdtdServerKit/WebApi/Controllers/BlacklistController.cs @@ -20,7 +20,7 @@ public IEnumerable AddBlacklist([FromBody, Required, MinLength(1)] Black var executeResult = new List(); foreach (var item in blacklist) { - string command = $"ban add {item.PlayerId} {(int)(item.BannedUntil - DateTime.Now).TotalMinutes} minutes {Utils.FormatCommandArgs(item.Reason)} {Utils.FormatCommandArgs(item.DisplayName)}"; + string command = $"ban add {item.PlayerId} {(int)(item.BannedUntil - DateTime.Now).TotalMinutes} minutes {Utilities.Utils.FormatCommandArgs(item.Reason)} {Utilities.Utils.FormatCommandArgs(item.DisplayName)}"; var result = SdtdConsole.Instance.ExecuteSync(command, ModApi.CmdExecuteDelegate); executeResult.AddRange(result); } diff --git a/src/SdtdServerKit/WebApi/Controllers/ItemBlocksController.cs b/src/SdtdServerKit/WebApi/Controllers/ItemBlocksController.cs index b78d37d..83defa0 100644 --- a/src/SdtdServerKit/WebApi/Controllers/ItemBlocksController.cs +++ b/src/SdtdServerKit/WebApi/Controllers/ItemBlocksController.cs @@ -81,7 +81,7 @@ public Paged GetItemBlocks([FromUri] ItemBlockQuery model) continue; } - string localizationName = Utils.GetLocalization(itemName, language); + string localizationName = Utilities.Utils.GetLocalization(itemName, language); if (string.IsNullOrEmpty(keyword) == false) { if (itemName.IndexOf(keyword, StringComparison.OrdinalIgnoreCase) == -1 diff --git a/src/SdtdServerKit/WebApi/Controllers/LocalizationController.cs b/src/SdtdServerKit/WebApi/Controllers/LocalizationController.cs index 11ce435..446555a 100644 --- a/src/SdtdServerKit/WebApi/Controllers/LocalizationController.cs +++ b/src/SdtdServerKit/WebApi/Controllers/LocalizationController.cs @@ -41,7 +41,7 @@ public IHttpActionResult GetLocalization(Language language) [ResponseType(typeof(string))] public IHttpActionResult GetLocalization(string key, [FromUri]Language language, [FromUri] bool caseInsensitive = false) { - return Ok(Utils.GetLocalization(key, language, caseInsensitive)); + return Ok(Utilities.Utils.GetLocalization(key, language, caseInsensitive)); } /// diff --git a/src/SdtdServerKit/WebApi/Controllers/MapController.cs b/src/SdtdServerKit/WebApi/Controllers/MapController.cs index b5cd2a5..4f0778b 100644 --- a/src/SdtdServerKit/WebApi/Controllers/MapController.cs +++ b/src/SdtdServerKit/WebApi/Controllers/MapController.cs @@ -60,7 +60,7 @@ public IHttpActionResult MapTile(int z, int x, int y) [Route("RenderFullMap")] public IHttpActionResult RenderFullMap() { - var result = Utils.ExecuteConsoleCommand("visitmap full"); + var result = Utilities.Utils.ExecuteConsoleCommand("visitmap full"); return Ok(result); } diff --git a/src/SdtdServerKit/WebApi/Controllers/PlayerSkillsController.cs b/src/SdtdServerKit/WebApi/Controllers/PlayerSkillsController.cs index b0eaedf..e95d3f4 100644 --- a/src/SdtdServerKit/WebApi/Controllers/PlayerSkillsController.cs +++ b/src/SdtdServerKit/WebApi/Controllers/PlayerSkillsController.cs @@ -60,8 +60,8 @@ private static List GetPlayerSkills(Progression progression, Langua var playerSkill = new PlayerSkill() { Name = item.Name, - LocalizationName = Utils.GetLocalization(item.NameKey, language, true), - LocalizationDesc = Utils.GetLocalization(item.DescKey, language, true), + LocalizationName = Utilities.Utils.GetLocalization(item.NameKey, language, true), + LocalizationDesc = Utilities.Utils.GetLocalization(item.DescKey, language, true), //LocalizationLongDesc = Utils.GetLocalization(item.LongDescKey, language, true), Level = progressionValue.Level, MinLevel = item.MinLevel, @@ -88,8 +88,8 @@ private static List GetChildren(Progression progression, Progressio var childPlayerSkill = new PlayerSkill() { Name = child.Name, - LocalizationName = Utils.GetLocalization(child.NameKey, language, true), - LocalizationDesc = Utils.GetLocalization(child.DescKey, language, true), + LocalizationName = Utilities.Utils.GetLocalization(child.NameKey, language, true), + LocalizationDesc = Utilities.Utils.GetLocalization(child.DescKey, language, true), //LocalizationLongDesc = Utils.GetLocalization(child.LongDescKey, language, true), Level = childProgressionValue.Level, MinLevel = child.MinLevel, diff --git a/src/SdtdServerKit/WebApi/Controllers/ServerController.cs b/src/SdtdServerKit/WebApi/Controllers/ServerController.cs index 12d9a98..20a2f8e 100644 --- a/src/SdtdServerKit/WebApi/Controllers/ServerController.cs +++ b/src/SdtdServerKit/WebApi/Controllers/ServerController.cs @@ -28,7 +28,7 @@ public class ServerController : ApiController [Route(nameof(ExecuteConsoleCommand))] public IEnumerable ExecuteConsoleCommand([FromUri] string command, [FromUri] bool inMainThread = false) { - return Utils.ExecuteConsoleCommand(command, inMainThread); + return Utilities.Utils.ExecuteConsoleCommand(command, inMainThread); } /// @@ -235,7 +235,7 @@ public JObject GameInfo() public IEnumerable GiveItem([FromBody]GiveItem giveItemEntry) { string cmd = string.Format("ty-gi {0} {1} {2} {3} {4}", - Utils.FormatCommandArgs(giveItemEntry.TargetPlayerIdOrName), + Utilities.Utils.FormatCommandArgs(giveItemEntry.TargetPlayerIdOrName), giveItemEntry.ItemName, giveItemEntry.Count, giveItemEntry.Quality, @@ -251,7 +251,7 @@ public IEnumerable GiveItem([FromBody]GiveItem giveItemEntry) [Route(nameof(SendGlobalMessage))] public IEnumerable SendGlobalMessage([FromBody] GlobalMessage globalMessage) { - return Utils.SendGlobalMessage(globalMessage); + return Utilities.Utils.SendGlobalMessage(globalMessage); } /// @@ -261,7 +261,7 @@ public IEnumerable SendGlobalMessage([FromBody] GlobalMessage globalMess [Route(nameof(SendPrivateMessage))] public IEnumerable SendPrivateMessage([FromBody] PrivateMessage privateMessage) { - return Utils.SendPrivateMessage(privateMessage); + return Utilities.Utils.SendPrivateMessage(privateMessage); } /// diff --git a/src/SdtdServerKit/WebApi/Controllers/WhitelistController.cs b/src/SdtdServerKit/WebApi/Controllers/WhitelistController.cs index b670f83..4b1c50e 100644 --- a/src/SdtdServerKit/WebApi/Controllers/WhitelistController.cs +++ b/src/SdtdServerKit/WebApi/Controllers/WhitelistController.cs @@ -20,7 +20,7 @@ public IEnumerable AddWhitelist([FromBody, Required, MinLength(1)] White var executeResult = new List(); foreach (var item in whitelist) { - string command = $"whitelist add {item.PlayerId} {Utils.FormatCommandArgs(item.DisplayName)}"; + string command = $"whitelist add {item.PlayerId} {Utilities.Utils.FormatCommandArgs(item.DisplayName)}"; var result = SdtdConsole.Instance.ExecuteSync(command, ModApi.CmdExecuteDelegate); executeResult.AddRange(result); } From 2fd251205028938dad14a242526e5765f67a1a3a Mon Sep 17 00:00:00 2001 From: IceCoffee <1249993110@qq.com> Date: Sat, 21 Sep 2024 22:47:20 +0800 Subject: [PATCH 11/14] Rename and refactor RenderPrefab class to PlacePrefab Rename `RenderPrefab` class to `PlacePrefab` and refactor and improve: - Delete `RenderPrefab` class in `RenderPrefab.cs` file. - Add new `PlacePrefab` class in `PlacePrefab.cs` file, add support for accurate loading of prefab files and runtime search directory, and improve help information. - Fix error log information in `SetUndoSize.cs` file, change "RenderPrefab.SetUndoSize" to "SetUndoSize.Execute". - Fix help information in `UndoPrefab.cs` file, change "RenderPrefab" to "PlacePrefab". --- .../{RenderPrefab.cs => PlacePrefab.cs} | 60 +++++++++++-------- src/SdtdServerKit/Commands/SetUndoSize.cs | 2 +- src/SdtdServerKit/Commands/UndoPrefab.cs | 2 +- 3 files changed, 38 insertions(+), 26 deletions(-) rename src/SdtdServerKit/Commands/{RenderPrefab.cs => PlacePrefab.cs} (75%) diff --git a/src/SdtdServerKit/Commands/RenderPrefab.cs b/src/SdtdServerKit/Commands/PlacePrefab.cs similarity index 75% rename from src/SdtdServerKit/Commands/RenderPrefab.cs rename to src/SdtdServerKit/Commands/PlacePrefab.cs index 1f3a68d..498372d 100644 --- a/src/SdtdServerKit/Commands/RenderPrefab.cs +++ b/src/SdtdServerKit/Commands/PlacePrefab.cs @@ -3,9 +3,9 @@ namespace SdtdServerKit.Commands { /// - /// Renders a Prefab on given location. + /// Places a Prefab on given location. /// - public class RenderPrefab : ConsoleCmdBase + public class PlacePrefab : ConsoleCmdBase { /// /// @@ -13,7 +13,7 @@ public class RenderPrefab : ConsoleCmdBase /// public override string getDescription() { - return "Renders a Prefab on given location."; + return "Places a Prefab on given location."; } /// @@ -23,19 +23,21 @@ public override string getDescription() public override string getHelp() { return "Usage:\n" + - " 1. ty-RenderPrefab {prefabFileName} {x} {y} {z} [noSleepers] [addToRWG]\n" + - " 2. ty-RenderPrefab {prefabFileName} {x} {y} {z} {rot} [noSleepers] [addToRWG]\n" + - " 3. ty-RenderPrefab {prefabFileName} [noSleepers] [addToRWG]\n" + - " 4. ty-RenderPrefab {prefabFileName} {rot} [noSleepers] [addToRWG]\n" + - " 5. ty-RenderPrefab {prefabFileName} {rot} {depth} [noSleepers] [addToRWG]\n" + - "1. Render prefab on {x} {y} {z} location\n" + - "2. Render prefab on {x} {y} {z} location with rot\n" + - "3. Render prefab on your position\n" + - "4. Render prefab on your position with rot\n" + - "5. Render prefab on your position with rot and y deslocated (depth blocks)\n" + + " 1. ty-PlacePrefab {prefabFileName} {x} {y} {z} [noSleepers] [addToRWG]\n" + + " 2. ty-PlacePrefab {prefabFileName} {x} {y} {z} {rot} [noSleepers] [addToRWG]\n" + + " 3. ty-PlacePrefab {prefabFileName} [noSleepers] [addToRWG]\n" + + " 4. ty-PlacePrefab {prefabFileName} {rot} [noSleepers] [addToRWG]\n" + + " 5. ty-PlacePrefab {prefabFileName} {rot} {depth} [noSleepers] [addToRWG]\n" + + "1. Places a prefab on {x} {y} {z} location\n" + + "2. Places a prefab on {x} {y} {z} location with rot\n" + + "3. Places a prefab on your position\n" + + "4. Places a prefab on your position with rot\n" + + "5. Places a prefab on your position with rot and y deslocated (depth blocks)\n" + "NOTE: {rot} means rotate the prefab to the left, must be equal to 0=0°, 1=90°, 2=180° or 3=270°\n" + "NOTE: Sleeper control is ONLY possible on prefabs that are present in prefabs.xml (world folder) that is used to create the map (RWG).\n" + - "NOTE: Use parameter \"addToRWG\" to permanently add this prefab to the current RWG world. Can be reset like any other RWG prefab and will still be in world after a wipe. Will cause re-download of world for clients!"; + "NOTE: Use parameter \"addToRWG\" to permanently add this prefab to the current RWG world. Can be reset like any other RWG prefab and will still be in world after a wipe. Will cause re-download of world for clients!\n" + + "NOTE: Runtime search and load from {UserDataFolder}/LocalPrefabs\n" + + "NOTE: If {prefabFileName} is a full file name that actually exists, it will be loaded exactly"; } /// @@ -46,9 +48,8 @@ public override string[] getCommands() { return new string[] { - "ty-RenderPrefab", - "ty-rp", - "ty-brender" + "ty-PlacePrefab", + "ty-pp" }; } @@ -79,6 +80,19 @@ public override void Execute(List args, CommandSenderInfo senderInfo) } string prefabFileName = args[0]; + string? runtimeSearchDir = null; + bool isExactlyLoad = File.Exists(prefabFileName); + if (isExactlyLoad) + { + prefabFileName = Path.GetFileNameWithoutExtension(prefabFileName); + runtimeSearchDir = Path.GetDirectoryName(prefabFileName); + } + else + { + var dir = new DirectoryInfo(Path.Combine(LaunchPrefs.UserDataFolder.Value, "LocalPrefabs")); + runtimeSearchDir = dir.FullName; + } + int x; int y; int z; @@ -137,12 +151,10 @@ public override void Execute(List args, CommandSenderInfo senderInfo) { bCopyAirBlocks = true }; - if (prefab.Load(prefabFileName, true, true, false, false) == false) + if (isExactlyLoad || prefab.Load(prefabFileName, true, true, false, false) == false) { - // Runtime load from LocalPrefabs - var dir = new DirectoryInfo(Path.Combine(LaunchPrefs.UserDataFolder.Value, "LocalPrefabs")); - Log("Try loading prefab from " + dir.FullName); - var abstractedLocation = new PathAbstractions.AbstractedLocation(PathAbstractions.EAbstractedLocationType.UserDataPath, prefabFileName, dir.FullName, null, prefabFileName, ".tts", true, null); + Log("Try loading prefab from " + runtimeSearchDir); + var abstractedLocation = new PathAbstractions.AbstractedLocation(PathAbstractions.EAbstractedLocationType.UserDataPath, prefabFileName, runtimeSearchDir, null, prefabFileName, ".tts", true, null); if (prefab.Load(abstractedLocation, true, true, false, false) == false) { Log("ERR: Unable to load prefab " + prefabFileName); @@ -177,7 +189,7 @@ public override void Execute(List args, CommandSenderInfo senderInfo) if (noSleepers) { - prefab.SleeperVolumes = new List(); + prefab.SleeperVolumes.Clear(); } prefab.CopyIntoLocal(GameManager.Instance.World.ChunkCache, offsetPosition, true, true, FastTags.none); @@ -197,7 +209,7 @@ public override void Execute(List args, CommandSenderInfo senderInfo) } catch (Exception ex) { - Log("Error in RenderPrefab.Execute" + Environment.NewLine + ex.ToString()); + Log("Error in PlacePrefab.Execute" + Environment.NewLine + ex.ToString()); } } } diff --git a/src/SdtdServerKit/Commands/SetUndoSize.cs b/src/SdtdServerKit/Commands/SetUndoSize.cs index 48aa854..15f4f66 100644 --- a/src/SdtdServerKit/Commands/SetUndoSize.cs +++ b/src/SdtdServerKit/Commands/SetUndoSize.cs @@ -73,7 +73,7 @@ public override void Execute(List args, CommandSenderInfo senderInfo) } catch (Exception ex) { - Log("Error in RenderPrefab.SetUndoSize" + Environment.NewLine + ex.ToString()); + Log("Error in SetUndoSize.Execute" + Environment.NewLine + ex.ToString()); } } } diff --git a/src/SdtdServerKit/Commands/UndoPrefab.cs b/src/SdtdServerKit/Commands/UndoPrefab.cs index 0301029..637fb9c 100644 --- a/src/SdtdServerKit/Commands/UndoPrefab.cs +++ b/src/SdtdServerKit/Commands/UndoPrefab.cs @@ -22,7 +22,7 @@ public override string getHelp() { return "Usage:\n" + " 1. ty-UndoPrefab\n" + - "1. Undo prefabs command. Works with RenderPrefab, FillBlock, ReplaceBlock and DuplicateArea\n" + + "1. Undo prefabs command. Works with PlacePrefab, FillBlock, ReplaceBlock and DuplicateArea\n" + "NOTE: By default the size of undo history ise set to 1. You can change the undo history size using \"setundosize\"\n"; } From fe44b3cfb1f368353b883a7ce60be4196897177f Mon Sep 17 00:00:00 2001 From: IceCoffee <1249993110@qq.com> Date: Sun, 22 Sep 2024 14:40:52 +0800 Subject: [PATCH 12/14] Rename variables and add new functions and classes Renamed `prefabFileName` to `prefabName` in `PlacePrefab.cs` and updated related code and log output. Updated help information in `UndoPrefab.cs` to support undoing prefabs by ID, added methods to get the undo history list, and changed the default undo history size. Added `SdtdServerKit.Models` namespace and corresponding classes in `AvailablePrefab.cs`, `PrefabPlace.cs`, `Rotation.cs`, and `UndoHistory.cs`. Added `SdtdServerKit.WebApi.Controllers` namespace and API endpoints in `PrefabController.cs`. --- src/SdtdServerKit/Commands/PlacePrefab.cs | 18 +-- src/SdtdServerKit/Commands/UndoPrefab.cs | 45 ++++++-- src/SdtdServerKit/Models/AvailablePrefab.cs | 38 ++++++ src/SdtdServerKit/Models/PrefabPlace.cs | 33 ++++++ src/SdtdServerKit/Models/Rotation.cs | 28 +++++ src/SdtdServerKit/Models/UndoHistory.cs | 28 +++++ .../WebApi/Controllers/PrefabController.cs | 109 ++++++++++++++++++ 7 files changed, 281 insertions(+), 18 deletions(-) create mode 100644 src/SdtdServerKit/Models/AvailablePrefab.cs create mode 100644 src/SdtdServerKit/Models/PrefabPlace.cs create mode 100644 src/SdtdServerKit/Models/Rotation.cs create mode 100644 src/SdtdServerKit/Models/UndoHistory.cs create mode 100644 src/SdtdServerKit/WebApi/Controllers/PrefabController.cs diff --git a/src/SdtdServerKit/Commands/PlacePrefab.cs b/src/SdtdServerKit/Commands/PlacePrefab.cs index 498372d..c3fe90c 100644 --- a/src/SdtdServerKit/Commands/PlacePrefab.cs +++ b/src/SdtdServerKit/Commands/PlacePrefab.cs @@ -79,13 +79,13 @@ public override void Execute(List args, CommandSenderInfo senderInfo) args.RemoveAll(i => string.Equals(i, "nosleepers", StringComparison.OrdinalIgnoreCase)); } - string prefabFileName = args[0]; + string prefabName = args[0]; string? runtimeSearchDir = null; - bool isExactlyLoad = File.Exists(prefabFileName); + bool isExactlyLoad = File.Exists(prefabName); if (isExactlyLoad) { - prefabFileName = Path.GetFileNameWithoutExtension(prefabFileName); - runtimeSearchDir = Path.GetDirectoryName(prefabFileName); + prefabName = Path.GetFileNameWithoutExtension(prefabName); + runtimeSearchDir = Path.GetDirectoryName(prefabName); } else { @@ -151,13 +151,13 @@ public override void Execute(List args, CommandSenderInfo senderInfo) { bCopyAirBlocks = true }; - if (isExactlyLoad || prefab.Load(prefabFileName, true, true, false, false) == false) + if (isExactlyLoad || prefab.Load(prefabName, true, true, false, false) == false) { Log("Try loading prefab from " + runtimeSearchDir); - var abstractedLocation = new PathAbstractions.AbstractedLocation(PathAbstractions.EAbstractedLocationType.UserDataPath, prefabFileName, runtimeSearchDir, null, prefabFileName, ".tts", true, null); + var abstractedLocation = new PathAbstractions.AbstractedLocation(PathAbstractions.EAbstractedLocationType.UserDataPath, prefabName, runtimeSearchDir, null, prefabName, ".tts", true, null); if (prefab.Load(abstractedLocation, true, true, false, false) == false) { - Log("ERR: Unable to load prefab " + prefabFileName); + Log("ERR: Unable to load prefab " + prefabName); return; } } @@ -203,9 +203,9 @@ public override void Execute(List args, CommandSenderInfo senderInfo) prefabInstanceId = ChunkHelper.AddPrefabToRWG(prefab, offsetPosition); } - UndoPrefab.SetUndo(senderInfo.GetEntityId(), oldPrefab, offsetPosition, prefabInstanceId); + UndoPrefab.SetUndo(senderInfo.GetEntityId(), oldPrefab, prefabName, offsetPosition, prefabInstanceId); - Log($"Prefab {prefabFileName} loaded at {offsetPosition}"); + Log($"Prefab {prefabName} loaded at {offsetPosition}"); } catch (Exception ex) { diff --git a/src/SdtdServerKit/Commands/UndoPrefab.cs b/src/SdtdServerKit/Commands/UndoPrefab.cs index 637fb9c..0b0aa9a 100644 --- a/src/SdtdServerKit/Commands/UndoPrefab.cs +++ b/src/SdtdServerKit/Commands/UndoPrefab.cs @@ -22,8 +22,10 @@ public override string getHelp() { return "Usage:\n" + " 1. ty-UndoPrefab\n" + + " 2. ty-UndoPrefab {id}\n" + "1. Undo prefabs command. Works with PlacePrefab, FillBlock, ReplaceBlock and DuplicateArea\n" + - "NOTE: By default the size of undo history ise set to 1. You can change the undo history size using \"setundosize\"\n"; + "2. Undo prefabs command by specifying id.\n" + + "NOTE: By default the size of undo history ise set to 10. You can change the undo history size using \"setundosize\"\n"; } /// @@ -47,7 +49,13 @@ public override void Execute(List args, CommandSenderInfo senderInfo) { try { - var undoPrefab = GetUndoPrefab(senderInfo.GetEntityId()); + if (args.Count == 0 || int.TryParse(args[0], out int id) == false) + { + id = 0; + } + + var undoPrefab = GetUndoPrefab(senderInfo.GetEntityId(), id); + if (undoPrefab == null) { Log("ERR: Unable to undo the last prefab command."); @@ -100,7 +108,7 @@ public override void Execute(List args, CommandSenderInfo senderInfo) } } - internal static UndoPrefabObj? GetUndoPrefab(int entityId) + internal static UndoPrefabObj? GetUndoPrefab(int entityId, int id = 0) { if (_prefabCache.IsValueCreated == false || _prefabCache.Value.TryGetValue(entityId, out var list) == false @@ -109,12 +117,17 @@ public override void Execute(List args, CommandSenderInfo senderInfo) return null; } - var obj = list[0]; - list.RemoveAt(0); + if(id < 0 || id >= list.Count) + { + return null; + } + + var obj = list[id]; + list.RemoveAt(id); return obj; } - internal static void SetUndo(int entityId, Prefab prefab, Vector3i offsetPosition, int prefabInstanceId) + internal static void SetUndo(int entityId, Prefab prefab, string prefabName, Vector3i offsetPosition, int prefabInstanceId) { if (_prefabCache.Value.TryGetValue(entityId, out var list) == false) { @@ -127,11 +140,21 @@ internal static void SetUndo(int entityId, Prefab prefab, Vector3i offsetPositio list.RemoveAt(list.Count - 1); } - var item = new UndoPrefabObj(prefab, offsetPosition, prefabInstanceId); + var item = new UndoPrefabObj(prefab, prefabName, offsetPosition, prefabInstanceId); list.Insert(0, item); } - private static int _maxUndoHistorySize = 1; + internal static List? GetUndoHistoryList(int entityId = -1) + { + if (_prefabCache.IsValueCreated == false || _prefabCache.Value.TryGetValue(entityId, out var list) == false) + { + return null; + } + + return list; + } + + private static int _maxUndoHistorySize = 10; private static readonly Lazy>> _prefabCache = new Lazy>>(); internal static void SetMaxUndoHistorySize(int maxUndoHistorySize, int entityId) @@ -163,18 +186,22 @@ internal static int GetMaxUndoHistorySize() internal class UndoPrefabObj { - public UndoPrefabObj(Prefab prefab, Vector3i offsetPosition, int prefabInstanceId) + public UndoPrefabObj(Prefab prefab, string prefabName, Vector3i offsetPosition, int prefabInstanceId) { this.Prefab = prefab; this.OffsetPosition = offsetPosition; this.PrefabInstanceId = prefabInstanceId; + this.PrefabName = prefabName; + this.CreatedAt = DateTime.Now; // Clear sleeper volumes prefab.SleeperVolumes.Clear(); } public Prefab Prefab { get; set; } + public string PrefabName { get; set; } public Vector3i OffsetPosition { get; set; } + public DateTime CreatedAt { get; set; } public int PrefabInstanceId { get; set; } } } diff --git a/src/SdtdServerKit/Models/AvailablePrefab.cs b/src/SdtdServerKit/Models/AvailablePrefab.cs new file mode 100644 index 0000000..d71313c --- /dev/null +++ b/src/SdtdServerKit/Models/AvailablePrefab.cs @@ -0,0 +1,38 @@ +namespace SdtdServerKit.Models +{ + /// + /// Represents a loaded prefab. + /// + public class AvailablePrefab + { + /// + /// Gets or sets the name of the prefab. + /// + public string PrefabName { get; set; } + + /// + /// Gets or sets the full path of the prefab. + /// + public string FullPath { get; set; } + + ///// + ///// Gets or sets the size of the prefab. + ///// + //public string Size { get; set; } + + ///// + ///// Gets or sets the tags of the prefab. + ///// + //public string Tags { get; set; } + + ///// + ///// Gets or sets the theme tags of the prefab. + ///// + //public string ThemeTags { get; set; } + + ///// + ///// Gets or sets the Y offset of the prefab. + ///// + //public int YOffset { get; set; } + } +} diff --git a/src/SdtdServerKit/Models/PrefabPlace.cs b/src/SdtdServerKit/Models/PrefabPlace.cs new file mode 100644 index 0000000..9cc5146 --- /dev/null +++ b/src/SdtdServerKit/Models/PrefabPlace.cs @@ -0,0 +1,33 @@ +namespace SdtdServerKit.Models +{ + /// + /// Represents a prefab placement. + /// + public class PrefabPlace + { + /// + /// Gets or sets the name of the prefab file. + /// + public string PrefabFileName { get; set; } = null!; + + /// + /// Gets or sets the position of the prefab. + /// + public Position Position { get; set; } + + /// + /// Gets or sets the rotation of the prefab. + /// + public Rotation Rotation { get; set; } + + /// + /// Gets or sets a value indicating whether sleepers are disabled in the prefab. + /// + public bool NoSleepers { get; set; } + + /// + /// Gets or sets a value indicating whether the prefab should be added to the random world generation. + /// + public bool AddToRWG { get; set; } + } +} diff --git a/src/SdtdServerKit/Models/Rotation.cs b/src/SdtdServerKit/Models/Rotation.cs new file mode 100644 index 0000000..28700ea --- /dev/null +++ b/src/SdtdServerKit/Models/Rotation.cs @@ -0,0 +1,28 @@ +namespace SdtdServerKit.Models +{ + /// + /// Represents the rotation of an object. + /// + public enum Rotation + { + /// + /// No rotation. + /// + Rot0 = 0, + + /// + /// 90 degrees rotation. + /// + Rot90 = 1, + + /// + /// 180 degrees rotation. + /// + Rot180 = 2, + + /// + /// 270 degrees rotation. + /// + Rot270 = 3 + } +} diff --git a/src/SdtdServerKit/Models/UndoHistory.cs b/src/SdtdServerKit/Models/UndoHistory.cs new file mode 100644 index 0000000..8a9854b --- /dev/null +++ b/src/SdtdServerKit/Models/UndoHistory.cs @@ -0,0 +1,28 @@ +namespace SdtdServerKit.Models +{ + /// + /// Represents the undo history of an action. + /// + public class UndoHistory + { + /// + /// Gets or sets the ID of the undo history. + /// + public int Id { get; set; } + + /// + /// Gets or sets the name of the prefab associated with the undo history. + /// + public string PrefabName { get; set; } + + /// + /// Gets or sets the position of the undo history. + /// + public Position Position { get; set; } + + /// + /// Gets or sets the creation date and time of the undo history. + /// + public DateTime CreatedAt { get; set; } + } +} diff --git a/src/SdtdServerKit/WebApi/Controllers/PrefabController.cs b/src/SdtdServerKit/WebApi/Controllers/PrefabController.cs new file mode 100644 index 0000000..e8d785a --- /dev/null +++ b/src/SdtdServerKit/WebApi/Controllers/PrefabController.cs @@ -0,0 +1,109 @@ +using SdtdServerKit.Commands; +using System; +using System.Drawing; +using WorldGenerationEngineFinal; +using static XUiC_CharacterFrameWindow; + +namespace SdtdServerKit.WebApi.Controllers +{ + /// + /// Prefab + /// + [Authorize] + [RoutePrefix("api/Prefab")] + public class PrefabController : ApiController + { + /// + /// Get all available prefabs. + /// + /// + [HttpGet] + [Route(nameof(AvailablePrefabs))] + public IEnumerable AvailablePrefabs() + { + var result = new List(); + foreach (var item in PathAbstractions.PrefabsSearchPaths.GetAvailablePathsList()) + { + result.Add(new AvailablePrefab() + { + PrefabName = item.Name, + FullPath = item.FullPath, + }); + } + + //foreach (var item in PrefabManager.AllPrefabDatas.Values) + //{ + // string prefabName = item.Name; + // string fullPath = item.location.FullPath; + // string size = item.size.ToString(); + // string tags = item.Tags.ToString(); + // string themeTags = item.ThemeTags.ToString(); + // int yOffset = item.yOffset; + //} + + //result.Sort((a, b) => a.PrefabName.CompareTo(b.PrefabName)); + return result; + } + + /// + /// Place prefab. + /// + /// + [HttpPost] + [Route(nameof(PlacePrefab))] + public IEnumerable PlacePrefab([FromBody] PrefabPlace model) + { + string cmd = $"ty-PlacePrefab \"{model.PrefabFileName}\" {model.Position} {(int)model.Rotation}"; + if(model.NoSleepers) + { + cmd += " noSleepers"; + } + if(model.AddToRWG) + { + cmd += " addToRWG"; + } + + return Utilities.Utils.ExecuteConsoleCommand(cmd, true); + } + + /// + /// Get undo history. + /// + /// + [HttpGet] + [Route(nameof(UndoHistory))] + public IEnumerable UndoHistory() + { + var list = Commands.UndoPrefab.GetUndoHistoryList(); + if(list == null) + { + return Enumerable.Empty(); + } + + var result = new List(); + for (int i = 0; i < list.Count; i++) + { + result.Add(new UndoHistory + { + Id = i, + PrefabName = list[i].PrefabName, + Position = list[i].OffsetPosition.ToPosition(), + CreatedAt = list[i].CreatedAt + }); + } + + return result; + } + + /// + /// Undo prefab. + /// + /// + [HttpPut] + [Route(nameof(UndoPrefab) + "/{id:int}")] + public IEnumerable UndoPrefab(int id) + { + return Utilities.Utils.ExecuteConsoleCommand($"ty-UndoPrefab {id}", true); + } + } +} From 15a51e7bd42b912c255f6ca93508f65bffe0b924 Mon Sep 17 00:00:00 2001 From: IceCoffee <1249993110@qq.com> Date: Sun, 22 Sep 2024 17:55:20 +0800 Subject: [PATCH 13/14] Refactor Prefab related code, add paging and search functions In the `AvailablePrefab.cs` file, rename the `PrefabName` property to `Name` and change its type to a nullable type `string?`. At the same time, add a new nullable type `string?` property `LocalizationName`. Change the type of the `FullPath` property to a nullable type `string?`. In the `PrefabController.cs` file, remove unnecessary `using` statements. Change the return type of the `AvailablePrefabs` method from `IEnumerable` to `Paged`, and add paging and search functions. In the `AvailablePrefabQuery.cs` file, add a new class `AvailablePrefabQuery` to handle paging and search query parameters. --- src/SdtdServerKit/Commands/PlacePrefab.cs | 4 +- src/SdtdServerKit/Models/AvailablePrefab.cs | 9 ++++- .../Models/AvailablePrefabQuery.cs | 35 +++++++++++++++++ .../WebApi/Controllers/PrefabController.cs | 38 +++++++++++++------ 4 files changed, 70 insertions(+), 16 deletions(-) create mode 100644 src/SdtdServerKit/Models/AvailablePrefabQuery.cs diff --git a/src/SdtdServerKit/Commands/PlacePrefab.cs b/src/SdtdServerKit/Commands/PlacePrefab.cs index c3fe90c..8bd5e6b 100644 --- a/src/SdtdServerKit/Commands/PlacePrefab.cs +++ b/src/SdtdServerKit/Commands/PlacePrefab.cs @@ -60,7 +60,7 @@ public override void Execute(List args, CommandSenderInfo senderInfo) { try { - CustomLogger.Warn("Is Main: " + ThreadManager.IsMainThread()); + //CustomLogger.Warn("Is Main: " + ThreadManager.IsMainThread()); if (args.Count < 1 || args.Count > 7) { Log($"ERR: Wrong number of arguments, expected 1 to 7, found {args.Count}."); @@ -84,8 +84,8 @@ public override void Execute(List args, CommandSenderInfo senderInfo) bool isExactlyLoad = File.Exists(prefabName); if (isExactlyLoad) { - prefabName = Path.GetFileNameWithoutExtension(prefabName); runtimeSearchDir = Path.GetDirectoryName(prefabName); + prefabName = Path.GetFileNameWithoutExtension(prefabName); } else { diff --git a/src/SdtdServerKit/Models/AvailablePrefab.cs b/src/SdtdServerKit/Models/AvailablePrefab.cs index d71313c..ea2ea44 100644 --- a/src/SdtdServerKit/Models/AvailablePrefab.cs +++ b/src/SdtdServerKit/Models/AvailablePrefab.cs @@ -8,12 +8,17 @@ public class AvailablePrefab /// /// Gets or sets the name of the prefab. /// - public string PrefabName { get; set; } + public string? Name { get; set; } + + /// + /// Gets or sets the localization name of the prefab. + /// + public string? LocalizationName { get; set; } /// /// Gets or sets the full path of the prefab. /// - public string FullPath { get; set; } + public string? FullPath { get; set; } ///// ///// Gets or sets the size of the prefab. diff --git a/src/SdtdServerKit/Models/AvailablePrefabQuery.cs b/src/SdtdServerKit/Models/AvailablePrefabQuery.cs new file mode 100644 index 0000000..5eb7856 --- /dev/null +++ b/src/SdtdServerKit/Models/AvailablePrefabQuery.cs @@ -0,0 +1,35 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace SdtdServerKit.Models +{ + public class AvailablePrefabQuery + { + /// + /// 页码 + /// + [DefaultValue(1)] + public int PageNumber { get; set; } = 1; + + /// + /// 每页数量, 值小于 0 时返回所有记录 + /// + [DefaultValue(10)] + public int PageSize { get; set; } = 10; + + /// + /// 语言 + /// + [DefaultValue(Language.English)] + public Language Language { get; set; } = Language.English; + + /// + /// 搜索关键词 + /// + public string? Keyword { get; set; } + } +} diff --git a/src/SdtdServerKit/WebApi/Controllers/PrefabController.cs b/src/SdtdServerKit/WebApi/Controllers/PrefabController.cs index e8d785a..042fc14 100644 --- a/src/SdtdServerKit/WebApi/Controllers/PrefabController.cs +++ b/src/SdtdServerKit/WebApi/Controllers/PrefabController.cs @@ -1,10 +1,4 @@ -using SdtdServerKit.Commands; -using System; -using System.Drawing; -using WorldGenerationEngineFinal; -using static XUiC_CharacterFrameWindow; - -namespace SdtdServerKit.WebApi.Controllers +namespace SdtdServerKit.WebApi.Controllers { /// /// Prefab @@ -19,17 +13,37 @@ public class PrefabController : ApiController /// [HttpGet] [Route(nameof(AvailablePrefabs))] - public IEnumerable AvailablePrefabs() + public Paged AvailablePrefabs([FromUri] AvailablePrefabQuery model) { - var result = new List(); + var list = new List(); foreach (var item in PathAbstractions.PrefabsSearchPaths.GetAvailablePathsList()) { - result.Add(new AvailablePrefab() + string name = item.Name; + string localizationName = Utilities.Utils.GetLocalization(name, model.Language, true); + string fullPath = item.FullPath; + + string? keyword = model.Keyword; + if (string.IsNullOrEmpty(keyword) == false) + { + if(name.IndexOf(keyword, StringComparison.OrdinalIgnoreCase) == -1 && + localizationName.IndexOf(keyword, StringComparison.OrdinalIgnoreCase) == -1) + { + continue; + } + } + + list.Add(new AvailablePrefab() { - PrefabName = item.Name, - FullPath = item.FullPath, + Name = name, + LocalizationName = localizationName, + FullPath = fullPath, }); } + + int pageSize = model.PageSize; + var items = pageSize < 0 ? list : list.Skip((model.PageNumber - 1) * pageSize).Take(pageSize); + var result = new Paged(items, list.Count); + //foreach (var item in PrefabManager.AllPrefabDatas.Values) //{ From 525538f2ae02a2febe28b9cef06c4be28b3cd2b3 Mon Sep 17 00:00:00 2001 From: IceCoffee <1249993110@qq.com> Date: Sun, 22 Sep 2024 22:44:49 +0800 Subject: [PATCH 14/14] --- CHANGELOG.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 21fa0b6..9441899 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,13 @@ +## 10.42 (2024-09-22) +### New Features +- Added commands for placing prefabs, undo prefab, and set undo history size, enter `help ty-PlacePrefab` in the console to view details +- Added a simple web ui for placing prefabs +- Add the last time the owner was online under the territory stone information on the GPS map + +### Notable Changes +- Update GameIcon font size + + ## 10.41 (2024-09-13) ### New Features - Added color chat function, supports customizing player name color and text color, supports using variable `{PlayerName}` to customize title