diff --git a/AriasServerUtils/ASUModSystem.cs b/AriasServerUtils/ASUModSystem.cs index 9a44786..84c74af 100644 --- a/AriasServerUtils/ASUModSystem.cs +++ b/AriasServerUtils/ASUModSystem.cs @@ -18,7 +18,7 @@ namespace AriasServerUtils { public static string MOD_ID = "ariasserverutils"; public static ASUModConfig config = new ASUModConfig(); - private static ICoreServerAPI API; + internal static ICoreServerAPI API; private static bool bDirty = false; internal static Dictionary backupInventory = new Dictionary(); @@ -79,6 +79,7 @@ namespace AriasServerUtils api.Event.PlayerDeath += OnPlayerDeath; api.Event.PlayerJoin += OnPlayerJoin; api.Event.PlayerDisconnect += OnPlayerDC; + api.Event.ChunkColumnLoaded += RTPFactory.ChunkColumnGenerated; //api.Event.PlayerLeave += OnPlayerDC; diff --git a/AriasServerUtils/EventHandler.cs b/AriasServerUtils/EventHandler.cs index 8a57802..1b5a646 100644 --- a/AriasServerUtils/EventHandler.cs +++ b/AriasServerUtils/EventHandler.cs @@ -74,29 +74,7 @@ namespace AriasServerUtils ServerUtilities.SendMessageTo(isp, Lang.Get($"{ServerUtilities.MOD_ID}:rtp-search")); - - PlayerPosition pPos = RTPFactory.GetRandomPosition(isp, maxDistance: maxDistance); - if (pPos == null) - { - ps.ActiveCooldowns.Add(CooldownType.RTP, (TimeUtil.DecodeTimeNotation(ServerUtilities.config.Cooldowns.Get(CooldownType.RTP)) / 2) + TimeUtil.GetUnixEpochTimestamp()); - ServerUtilities.MarkDirty(); - - ServerUtilities.SendMessageTo(isp, Lang.Get($"{ServerUtilities.MOD_ID}:rtp-fail")); - return TextCommandResult.Success(); - } - Vec2i origin = new((int)isp.Entity.Pos.X, (int)isp.Entity.Pos.Z); - Vec2i npos = new(pPos.X, pPos.Z); - - float distance = RTPFactory.GetDistance(origin, npos); - - pPos.Merge(isp.Entity); - - - ps.ActiveCooldowns.Add(CooldownType.RTP, TimeUtil.DecodeTimeNotation(ServerUtilities.config.Cooldowns.Get(CooldownType.RTP)) + TimeUtil.GetUnixEpochTimestamp()); - ServerUtilities.MarkDirty(); - - ServerUtilities.SendMessageTo(isp, Lang.Get($"{ServerUtilities.MOD_ID}:rtp", distance)); - + RTPFactory.TryRTP(isp, maxDistance: maxDistance); } return TextCommandResult.Success(); } diff --git a/AriasServerUtils/RTPFactory.cs b/AriasServerUtils/RTPFactory.cs index 8b27e92..42c0b51 100644 --- a/AriasServerUtils/RTPFactory.cs +++ b/AriasServerUtils/RTPFactory.cs @@ -1,9 +1,11 @@ using System; +using System.Collections.Generic; using System.Data; using System.Numerics; using AriasServerUtils; using Vintagestory.API.Common; using Vintagestory.API.Common.Entities; +using Vintagestory.API.Config; using Vintagestory.API.MathTools; using Vintagestory.API.Server; using Vintagestory.GameContent; @@ -11,6 +13,33 @@ using Vintagestory.GameContent; namespace AriasServerUtils; public class RTPFactory { + + private static List RTPCache = new(); + + /* + if (pPos == null) + { + ps.ActiveCooldowns.Add(CooldownType.RTP, (TimeUtil.DecodeTimeNotation(ServerUtilities.config.Cooldowns.Get(CooldownType.RTP)) / 2) + TimeUtil.GetUnixEpochTimestamp()); + ServerUtilities.MarkDirty(); + + ServerUtilities.SendMessageTo(isp, Lang.Get($"{ServerUtilities.MOD_ID}:rtp-fail")); + return TextCommandResult.Success(); + } + Vec2i origin = new((int)isp.Entity.Pos.X, (int)isp.Entity.Pos.Z); + Vec2i npos = new(pPos.X, pPos.Z); + + float distance = RTPFactory.GetDistance(origin, npos); + + pPos.Merge(isp.Entity); + + + ps.ActiveCooldowns.Add(CooldownType.RTP, TimeUtil.DecodeTimeNotation(ServerUtilities.config.Cooldowns.Get(CooldownType.RTP)) + TimeUtil.GetUnixEpochTimestamp()); + ServerUtilities.MarkDirty(); + + ServerUtilities.SendMessageTo(isp, Lang.Get($"{ServerUtilities.MOD_ID}:rtp", distance)); + + */ + /// /// This function searches for a safe position, honoring the max RTP distance in the global configuration /// @@ -23,8 +52,9 @@ public class RTPFactory BlockPos bPos = new BlockPos(isp.Entity.Pos.Dimension); IServerWorldAccessor iswa = isp.Entity.World as IServerWorldAccessor; - int tries = 1000; + int tries = 10000; PlayerPosition PPos = PlayerPosition.from(isp.Entity); + PlayerPosition original = PlayerPosition.from(isp.Entity); while (tries-- > 0) { @@ -41,11 +71,38 @@ public class RTPFactory Block lastAboveLast = null; Block lastBlock = null; Block curBlock; + // Ensure the chunk is loaded before accessing blocks + int chunkX = bPos.X / 32; + int chunkY = bPos.Y / 32; + int chunkZ = bPos.Z / 32; + var chunk = iswa.ChunkProvider.GetUnpackedChunkFast(chunkX, chunkY, chunkZ); + + if (chunk == null) + { + // Chunk doesn't exist, or isn't loaded. + // Teleport the player to the position up in the sky. That way the chunk does get loaded and we can proceed. + PPos.X = bPos.X; + PPos.Y = bPos.Y; + PPos.Z = bPos.Z; + + PPos.Merge(isp.Entity); + } // Scan downwards to find a valid landing spot for (int i = 255; i > 0; i--) { bPos.Y = i; + if (i / 32 != chunkY) + { + chunkY = i / 32; + chunk = iswa.ChunkProvider.GetUnpackedChunkFast(chunkX, chunkY, chunkZ); + if (chunk == null) + { + + PPos.Y = i; + PPos.Merge(isp.Entity); + } + } curBlock = iswa.BlockAccessor.GetBlock(bPos); if (curBlock.MatterState == EnumMatterState.Solid) @@ -58,6 +115,8 @@ public class RTPFactory PPos.Y = bPos.Y + 1; PPos.Z = bPos.Z; + ServerUtilities.SendMessageTo(isp, Lang.Get($"{ServerUtilities.MOD_ID}:rtp-found", tries)); + return PPos; } } @@ -67,11 +126,91 @@ public class RTPFactory } } + original.Merge(isp.Entity); + return null; // Return null if no valid position is found after retries } + + /// + /// This function will schedule a task to perform an RTP. + /// + /// Player to be teleported + /// Max distance +/- the current position. + public static void TryRTP(IServerPlayer isp, int maxDistance) + { + var data = new RTPData(isp, maxDistance, 1000, PlayerPosition.from(isp)); + RTPCache.Add(data); + } + public static float GetDistance(Vec2i pos1, Vec2i pos2) { return MathF.Sqrt(MathF.Pow(pos2.X - pos1.X, 2) + MathF.Pow(pos2.Y - pos1.Y, 2)); } + internal static void ChunkColumnGenerated(Vec2i chunkCoord, IWorldChunk[] chunks) + { + throw new NotImplementedException(); + } +} + +public class RTPData +{ + public IServerPlayer player; + public int NumTriesRemaining; + public int MaxDistance; + public PlayerPosition StartPosition; + + public RTPData(IServerPlayer isp, int maxDistance, int tries, PlayerPosition playerPosition) + { + MaxDistance = maxDistance; + player = isp; + NumTriesRemaining = tries; + StartPosition = playerPosition; + } + + public RTPPosition MakeNewPosition() + { + NumTriesRemaining--; + + return new RTPPosition((int)player.Entity.Pos.X, (int)player.Entity.Pos.Z, MaxDistance, player.Entity.Pos.Dimension); + } +} + +public class RTPPosition +{ + int x; + int y; + int z; + + int dimension; + + public RTPPosition(int x, int z, int maxDist, int dim) + { + int minX = x - maxDist; + int maxX = x + maxDist; + int minZ = z - maxDist; + int maxZ = z + maxDist; + + this.x = ServerUtilities.rng.Next(minX, maxX); + this.y = 1; + this.z = ServerUtilities.rng.Next(minZ, maxZ); + + this.dimension = dim; + } + + PlayerPosition GetPlayerPosition() + { + return new PlayerPosition + { + X = x, + Y = y, + Dimension = dimension, + Z = z + }; + } + + BlockPos GetBlockPos() + { + return new BlockPos(new Vec3i(x, y, z), dimension); + } } \ No newline at end of file diff --git a/AriasServerUtils/assets/ariasserverutils/lang/en.json b/AriasServerUtils/assets/ariasserverutils/lang/en.json index 4498f90..cda0fee 100644 --- a/AriasServerUtils/assets/ariasserverutils/lang/en.json +++ b/AriasServerUtils/assets/ariasserverutils/lang/en.json @@ -35,6 +35,7 @@ "rtp-search": "Searching for a random position...", "rtp": "You have been teleported [{0}] blocks away!", + "rtp-found": "Found a valid landing position after {0} tries.", "rtp-fail": "Giving up on RTP search. No valid position could be found. Try again later", "rtp-capped": "The distance you tried to go [{0}] is greater than the maximum allowable by the server [{1}]", diff --git a/AriasServerUtils/modinfo.json b/AriasServerUtils/modinfo.json index 82c5df4..3cf221e 100644 --- a/AriasServerUtils/modinfo.json +++ b/AriasServerUtils/modinfo.json @@ -3,8 +3,8 @@ "modid": "ariasserverutils", "name": "Aria's Server Utilities", "authors": ["zontreck"], - "description": "A collection of server utilities\n\nBuild Date: 03-07-2025 @ 12:25 PM MST", - "version": "1.0.6-dev.7", + "description": "A collection of server utilities\n\nBuild Date: 03-07-2025 @ 1:32 PM MST", + "version": "1.0.6-dev.8", "dependencies": { "game": "" }