diff --git a/src/main/java/net/minecraft/world/WorldServer.java b/src/main/java/net/minecraft/world/WorldServer.java index e146766..689a3e5 100644 --- a/src/main/java/net/minecraft/world/WorldServer.java +++ b/src/main/java/net/minecraft/world/WorldServer.java @@ -73,6 +73,7 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import org.ultramine.server.WorldBorder; import org.ultramine.server.WorldsConfig.WorldConfig; import org.ultramine.server.WorldsConfig.WorldConfig.Settings.WorldTime; import org.ultramine.server.chunk.ChunkHash; @@ -965,6 +966,7 @@ private static final boolean isServer = FMLCommonHandler.instance().getSide().isServer(); private WorldConfig config; + private WorldBorder border; @SideOnly(Side.SERVER) private MobSpawnManager mobSpawner; @@ -1029,6 +1031,7 @@ public void setConfig(WorldConfig config) { this.config = config; + this.border = new WorldBorder(config.borders); if(isServer && config.mobSpawn.spawnEngine == WorldConfig.MobSpawn.MobSpawnEngine.NEW) { if(mobSpawner == null) @@ -1052,4 +1055,9 @@ { return config.chunkLoading.enableChunkLoaders; } + + public WorldBorder getBorder() + { + return border; + } } \ No newline at end of file diff --git a/src/main/java/org/ultramine/server/UMEventHandler.java b/src/main/java/org/ultramine/server/UMEventHandler.java index 615c485..5628b25 100644 --- a/src/main/java/org/ultramine/server/UMEventHandler.java +++ b/src/main/java/org/ultramine/server/UMEventHandler.java @@ -17,6 +17,8 @@ import net.minecraft.util.ChatComponentText; import net.minecraft.util.ChatComponentTranslation; import net.minecraft.util.EnumChatFormatting; +import net.minecraft.util.MathHelper; +import net.minecraft.world.ChunkPosition; import net.minecraft.world.WorldServer; import static net.minecraft.util.EnumChatFormatting.*; import net.minecraftforge.event.ServerChatEvent; @@ -103,6 +105,22 @@ } } + @SubscribeEvent + public void onPlayerTick(TickEvent.PlayerTickEvent e) + { + if(e.phase == TickEvent.Phase.END && e.side.isServer()) + { + EntityPlayerMP player = (EntityPlayerMP)e.player; + int x = MathHelper.floor_double(player.posX); + int z = MathHelper.floor_double(player.posZ); + if(!player.getServerForPlayer().getBorder().isInsideBorder(x, z)) + { + ChunkPosition pos = player.getServerForPlayer().getBorder().correctPosition(x, z); + player.playerNetServerHandler.setPlayerLocation(pos.chunkPosX, player.lastTickPosY, pos.chunkPosZ, player.rotationYaw, player.rotationPitch); + } + } + } + private static void broadcastMessage(String msg) { ChatComponentText msgcomp = new ChatComponentText(msg); diff --git a/src/main/java/org/ultramine/server/WorldBorder.java b/src/main/java/org/ultramine/server/WorldBorder.java new file mode 100644 index 0000000..3050955 --- /dev/null +++ b/src/main/java/org/ultramine/server/WorldBorder.java @@ -0,0 +1,138 @@ +package org.ultramine.server; + +import net.minecraft.util.MathHelper; +import net.minecraft.world.ChunkPosition; + +import org.ultramine.server.WorldsConfig.WorldConfig.Border; + +public class WorldBorder +{ + private final OneBorder[] borders; + + public WorldBorder(Border[] brds) + { + if(brds == null) + { + borders = new OneBorder[0]; + } + else + { + borders = new OneBorder[brds.length]; + for(int i = 0; i < brds.length; i++) + { + Border brd = brds[i]; + borders[i] = new OneBorder(brd.x, brd.z, brd.radius, brd.round); + } + } + } + + public boolean isInsideBorder(int x, int z) + { + for(OneBorder brd : borders) + if(brd.isInsideBorder(x, z)) + return true; + + return false; + } + + public boolean isChunkInsideBorder(int cx, int cz) + { + return isInsideBorder(cx << 4, cz << 4); + } + + public ChunkPosition correctPosition(int x, int z) + { + OneBorder found = null; + int min = Integer.MAX_VALUE; + for(OneBorder brd : borders) + { + int nmin = Math.min(Math.abs(brd.minX - x), Math.abs(brd.maxX - x)) * Math.min(Math.abs(brd.minZ - z), Math.abs(brd.maxZ - z)); + if(nmin < min) + { + min = nmin; + found = brd; + } + } + + return found.correctPosition(x, z); + } + + private static class OneBorder + { + private final int x; + private final int z; + private final int radius; + private final boolean round; + + private final int maxX; + private final int minX; + private final int maxZ; + private final int minZ; + private final int radiusSquared; + private final int definiteSquare; + + public OneBorder(int x, int z, int radius, boolean round) + { + this.x = x; + this.z = z; + this.radius = radius; + this.round = round; + + this.maxX = x + radius; + this.minX = x - radius; + this.maxZ = z + radius; + this.minZ = z - radius; + this.radiusSquared = radius * radius; + this.definiteSquare = (int)Math.sqrt(.5 * this.radiusSquared); + } + + public boolean isInsideBorder(int xLoc, int zLoc) + { + if (!round) + { + return !(xLoc < minX || xLoc > maxX || zLoc < minZ || zLoc > maxZ); + } + else + { + int X = Math.abs(x - xLoc); + int Z = Math.abs(z - zLoc); + + if (X < definiteSquare && Z < definiteSquare) + return true; // Definitely inside + else if (X >= radius || Z >= radius) + return false; // Definitely outside + else if (X * X + Z * Z < radiusSquared) + return true; // After further calculation, inside + else + return false; // Apparently outside, then + } + } + + public ChunkPosition correctPosition(int xLoc, int zLoc) + { + if (!round) + { + if (xLoc <= minX) + xLoc = minX + 1; + else if (xLoc >= maxX) + xLoc = maxX - 1; + if (zLoc <= minZ) + zLoc = minZ + 1; + else if (zLoc >= maxZ) + zLoc = maxZ - 1; + } + else + { + double dX = xLoc - x; + double dZ = zLoc - z; + double dU = Math.sqrt(dX * dX + dZ * dZ); //distance of the untransformed point from the center + double dT = Math.sqrt((dX * dX + dZ * dZ) / radiusSquared); //distance of the transformed point from the center + double f = (1 / dT - 2 / dU); //"correction" factor for the distances + xLoc = x + MathHelper.floor_double(dX * f); + zLoc = z + MathHelper.floor_double(dZ * f); + } + + return new ChunkPosition(xLoc, 0, zLoc); + } + } +} diff --git a/src/main/java/org/ultramine/server/WorldsConfig.java b/src/main/java/org/ultramine/server/WorldsConfig.java index 7c05e24..e54d60a 100644 --- a/src/main/java/org/ultramine/server/WorldsConfig.java +++ b/src/main/java/org/ultramine/server/WorldsConfig.java @@ -14,6 +14,7 @@ public Generation generation; public MobSpawn mobSpawn; public Settings settings; + public Border[] borders; public ChunkLoading chunkLoading; public LoadBalancer loadBalancer; @@ -87,6 +88,14 @@ } } + public static class Border + { + public int x; + public int z; + public int radius; + public boolean round; + } + public static class ChunkLoading { public int viewDistance = 10; diff --git a/src/main/resources/org/ultramine/defaults/defaultworlds.yml b/src/main/resources/org/ultramine/defaults/defaultworlds.yml index ba550ce..cc4a1ab 100644 --- a/src/main/resources/org/ultramine/defaults/defaultworlds.yml +++ b/src/main/resources/org/ultramine/defaults/defaultworlds.yml @@ -53,6 +53,7 @@ useIsolatedPlayerData: false respawnOnWarp: null reconnectOnWarp: null + borders: [] chunkLoading: &global_cl viewDistance: 10 chunkUpdateRadius: 7