using System; using System.Data; using System.Numerics; using AriasServerUtils; using Vintagestory.API.Common; using Vintagestory.API.Common.Entities; using Vintagestory.API.MathTools; using Vintagestory.API.Server; using Vintagestory.GameContent; public class RTPFactory { /// /// This function searches for a safe position, honoring the max RTP distance in the global configuration /// /// The player to be teleported /// A random position +/- max distance from current position. public static PlayerPosition GetRandomPosition(IServerPlayer isp) { Random rng = new Random(); EntityPos vPos = isp.Entity.Pos; BlockPos bPos = new BlockPos(isp.Entity.Pos.Dimension); IServerWorldAccessor iswa = isp.Entity.World as IServerWorldAccessor; int tries = 10; PlayerPosition PPos = PlayerPosition.from(isp.Entity); while (tries-- > 0) { // Generate random X and Z within max RTP distance bPos.X = (int)vPos.X + rng.Next(-ServerUtilities.config.MaxRTPBlockDistance, ServerUtilities.config.MaxRTPBlockDistance); bPos.Z = (int)vPos.Z + rng.Next(-ServerUtilities.config.MaxRTPBlockDistance, ServerUtilities.config.MaxRTPBlockDistance); bPos.Y = 255; Block lastAboveLast = null; Block lastBlock = null; Block curBlock; // Scan downwards to find a valid landing spot for (int i = 255; i > 25; i--) { bPos.Y = i; curBlock = iswa.BlockAccessor.GetBlock(bPos); if (curBlock.MatterState == EnumMatterState.Solid) { if (lastBlock != null && lastBlock.BlockMaterial == EnumBlockMaterial.Air && lastAboveLast != null && lastAboveLast.BlockMaterial == EnumBlockMaterial.Air) { // Found a valid spot: curBlock is solid, lastBlock & lastAboveLast are gas (air) PPos.X = bPos.X; PPos.Y = bPos.Y + 1; PPos.Z = bPos.Z; return PPos; } } lastAboveLast = lastBlock; lastBlock = curBlock; } } return null; // Return null if no valid position is found after retries } 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)); } }