From aa969cc8219d5aa23ba5683075bd6f2148d63c55 Mon Sep 17 00:00:00 2001 From: LOOHP Date: Fri, 14 Aug 2020 18:54:32 +0800 Subject: [PATCH] Ignore empty console commands, added other stuff for future updates --- pom.xml | 6 + src/com/loohp/limbo/Console.java | 7 +- src/com/loohp/limbo/Limbo.java | 21 +- src/com/loohp/limbo/Location/Location.java | 425 ++++++++- src/com/loohp/limbo/Location/Vector.java | 852 ++++++++++++++++++ src/com/loohp/limbo/Player/Player.java | 17 +- src/com/loohp/limbo/Player/Unsafe.java | 20 + .../loohp/limbo/Server/ClientConnection.java | 5 +- .../Server/Packets/PacketPlayOutLogin.java | 2 +- .../Server/Packets/PacketPlayOutMapChunk.java | 15 +- .../Server/Packets/PacketPlayOutRespawn.java | 2 +- src/com/loohp/limbo/Unsafe.java | 32 + src/com/loohp/limbo/Utils/NamespacedKey.java | 4 +- .../loohp/limbo/Utils/NumberConversions.java | 124 +++ src/com/loohp/limbo/World/BlockState.java | 63 ++ .../loohp/limbo/World/DimensionRegistry.java | 38 +- src/com/loohp/limbo/World/Environment.java | 37 + src/com/loohp/limbo/World/Schematic.java | 1 - src/com/loohp/limbo/World/World.java | 74 +- 19 files changed, 1632 insertions(+), 113 deletions(-) create mode 100644 src/com/loohp/limbo/Location/Vector.java create mode 100644 src/com/loohp/limbo/Player/Unsafe.java create mode 100644 src/com/loohp/limbo/Unsafe.java create mode 100644 src/com/loohp/limbo/Utils/NumberConversions.java create mode 100644 src/com/loohp/limbo/World/BlockState.java create mode 100644 src/com/loohp/limbo/World/Environment.java diff --git a/pom.xml b/pom.xml index a251dda..e992e4c 100644 --- a/pom.xml +++ b/pom.xml @@ -89,6 +89,12 @@ bungeecord-chat 1.16-R0.3 + + jline + jline + 2.6 + compile + diff --git a/src/com/loohp/limbo/Console.java b/src/com/loohp/limbo/Console.java index 90a5a4d..29cefa9 100644 --- a/src/com/loohp/limbo/Console.java +++ b/src/com/loohp/limbo/Console.java @@ -88,8 +88,11 @@ public class Console implements CommandSender { BufferedReader reader = new BufferedReader(new InputStreamReader(in)); while (true) { try { - String[] input = CustomStringUtils.splitStringToArgs(reader.readLine()); - Limbo.getInstance().dispatchCommand(this, input); + String command = reader.readLine(); + if (command.length() > 0) { + String[] input = CustomStringUtils.splitStringToArgs(command); + Limbo.getInstance().dispatchCommand(this, input); + } } catch (IOException e) { e.printStackTrace(); } diff --git a/src/com/loohp/limbo/Limbo.java b/src/com/loohp/limbo/Limbo.java index 8f18c1e..e33efc9 100644 --- a/src/com/loohp/limbo/Limbo.java +++ b/src/com/loohp/limbo/Limbo.java @@ -47,9 +47,10 @@ import com.loohp.limbo.Server.Packets.PacketOut; import com.loohp.limbo.Utils.CustomStringUtils; import com.loohp.limbo.Utils.ImageUtils; import com.loohp.limbo.Utils.NetworkUtils; +import com.loohp.limbo.World.DimensionRegistry; +import com.loohp.limbo.World.Environment; import com.loohp.limbo.World.Schematic; import com.loohp.limbo.World.World; -import com.loohp.limbo.World.World.Environment; import net.md_5.bungee.api.chat.BaseComponent; import net.md_5.bungee.chat.ComponentSerializer; @@ -115,8 +116,13 @@ public class Limbo { private File internalDataFolder; + private DimensionRegistry dimensionRegistry; + public AtomicInteger entityIdCount = new AtomicInteger(); + @SuppressWarnings("deprecation") + private Unsafe unsafe = new Unsafe(); + @SuppressWarnings("unchecked") public Limbo() throws IOException, ParseException, NumberFormatException, ClassNotFoundException, InterruptedException { instance = this; @@ -227,6 +233,8 @@ public class Limbo { console.sendMessage("Loaded all " + mappingsCount + " packet id mappings!"); + dimensionRegistry = new DimensionRegistry(); + worlds.add(loadDefaultWorld()); Location spawn = properties.getWorldSpawn(); properties.setWorldSpawn(new Location(getWorld(properties.getLevelName().getKey()), spawn.getX(), spawn.getY(), spawn.getZ(), spawn.getYaw(), spawn.getPitch())); @@ -278,6 +286,15 @@ public class Limbo { console.run(); } + @Deprecated + public Unsafe getUnsafe() { + return unsafe; + } + + public DimensionRegistry getDimensionRegistry() { + return dimensionRegistry; + } + public String getServerImplementationVersion() { return serverImplementationVersion; } @@ -434,6 +451,8 @@ public class Limbo { e.printStackTrace(); } } + + console.sendMessage("Server closed"); console.logs.close(); System.exit(0); } diff --git a/src/com/loohp/limbo/Location/Location.java b/src/com/loohp/limbo/Location/Location.java index 325b503..60de412 100644 --- a/src/com/loohp/limbo/Location/Location.java +++ b/src/com/loohp/limbo/Location/Location.java @@ -1,8 +1,11 @@ package com.loohp.limbo.Location; +import com.loohp.limbo.Limbo; +import com.loohp.limbo.Utils.NumberConversions; +import com.loohp.limbo.World.BlockState; import com.loohp.limbo.World.World; -public class Location { +public class Location implements Cloneable { World world; double x; @@ -26,7 +29,23 @@ public class Location { @Override public Location clone() { - return new Location(this.world, this.x, this.y, this.z, this.yaw, this.pitch); + try { + return (Location) super.clone(); + } catch (CloneNotSupportedException e) { + throw new Error(e); + } + } + + public BlockState getBlockState() { + return world.getBlock((int) x,(int) y,(int) z); + } + + public void setBlockState(BlockState state) { + world.setBlock((int) x, (int) y, (int) z, state); + } + + public boolean isWorldLoaded() { + return Limbo.getInstance().getWorld(world.getName()) != null; } public World getWorld() { @@ -77,53 +96,373 @@ public class Location { this.pitch = pitch; } + /** + * Gets a unit-vector pointing in the direction that this Location is + * facing. + * + * @return a vector pointing the direction of this location's {@link + * #getPitch() pitch} and {@link #getYaw() yaw} + */ + public Vector getDirection() { + Vector vector = new Vector(); + + double rotX = this.getYaw(); + double rotY = this.getPitch(); + + vector.setY(-Math.sin(Math.toRadians(rotY))); + + double xz = Math.cos(Math.toRadians(rotY)); + + vector.setX(-xz * Math.sin(Math.toRadians(rotX))); + vector.setZ(xz * Math.cos(Math.toRadians(rotX))); + + return vector; + } + + /** + * Sets the {@link #getYaw() yaw} and {@link #getPitch() pitch} to point + * in the direction of the vector. + * + * @param vector the direction vector + * @return the same location + */ + public Location setDirection(Vector vector) { + /* + * Sin = Opp / Hyp + * Cos = Adj / Hyp + * Tan = Opp / Adj + * + * x = -Opp + * z = Adj + */ + final double _2PI = 2 * Math.PI; + final double x = vector.getX(); + final double z = vector.getZ(); + + if (x == 0 && z == 0) { + pitch = vector.getY() > 0 ? -90 : 90; + return this; + } + + double theta = Math.atan2(-x, z); + yaw = (float) Math.toDegrees((theta + _2PI) % _2PI); + + double x2 = NumberConversions.square(x); + double z2 = NumberConversions.square(z); + double xz = Math.sqrt(x2 + z2); + pitch = (float) Math.toDegrees(Math.atan(-vector.getY() / xz)); + + return this; + } + + /** + * Adds the location by another. + * + * @see Vector + * @param vec The other location + * @return the same location + * @throws IllegalArgumentException for differing worlds + */ + public Location add(Location vec) { + if (vec == null || vec.getWorld() != getWorld()) { + throw new IllegalArgumentException("Cannot add Locations of differing worlds"); + } + + x += vec.x; + y += vec.y; + z += vec.z; + return this; + } + + /** + * Adds the location by a vector. + * + * @see Vector + * @param vec Vector to use + * @return the same location + */ + public Location add(Vector vec) { + this.x += vec.getX(); + this.y += vec.getY(); + this.z += vec.getZ(); + return this; + } + + /** + * Adds the location by another. Not world-aware. + * + * @see Vector + * @param x X coordinate + * @param y Y coordinate + * @param z Z coordinate + * @return the same location + */ + public Location add(double x, double y, double z) { + this.x += x; + this.y += y; + this.z += z; + return this; + } + + /** + * Subtracts the location by another. + * + * @see Vector + * @param vec The other location + * @return the same location + * @throws IllegalArgumentException for differing worlds + */ + public Location subtract(Location vec) { + if (vec == null || vec.getWorld() != getWorld()) { + throw new IllegalArgumentException("Cannot add Locations of differing worlds"); + } + + x -= vec.x; + y -= vec.y; + z -= vec.z; + return this; + } + + /** + * Subtracts the location by a vector. + * + * @see Vector + * @param vec The vector to use + * @return the same location + */ + public Location subtract(Vector vec) { + this.x -= vec.getX(); + this.y -= vec.getY(); + this.z -= vec.getZ(); + return this; + } + + /** + * Subtracts the location by another. Not world-aware and + * orientation independent. + * + * @see Vector + * @param x X coordinate + * @param y Y coordinate + * @param z Z coordinate + * @return the same location + */ + public Location subtract(double x, double y, double z) { + this.x -= x; + this.y -= y; + this.z -= z; + return this; + } + + /** + * Gets the magnitude of the location, defined as sqrt(x^2+y^2+z^2). The + * value of this method is not cached and uses a costly square-root + * function, so do not repeatedly call this method to get the location's + * magnitude. NaN will be returned if the inner result of the sqrt() + * function overflows, which will be caused if the length is too long. Not + * world-aware and orientation independent. + * + * @return the magnitude + * @see Vector + */ + public double length() { + return Math.sqrt(NumberConversions.square(x) + NumberConversions.square(y) + NumberConversions.square(z)); + } + + /** + * Gets the magnitude of the location squared. Not world-aware and + * orientation independent. + * + * @return the magnitude + * @see Vector + */ + public double lengthSquared() { + return NumberConversions.square(x) + NumberConversions.square(y) + NumberConversions.square(z); + } + + /** + * Get the distance between this location and another. The value of this + * method is not cached and uses a costly square-root function, so do not + * repeatedly call this method to get the location's magnitude. NaN will + * be returned if the inner result of the sqrt() function overflows, which + * will be caused if the distance is too long. + * + * @param o The other location + * @return the distance + * @throws IllegalArgumentException for differing worlds + * @see Vector + */ + public double distance(Location o) { + return Math.sqrt(distanceSquared(o)); + } + + /** + * Get the squared distance between this location and another. + * + * @param o The other location + * @return the distance + * @throws IllegalArgumentException for differing worlds + * @see Vector + */ + public double distanceSquared(Location o) { + if (o == null) { + throw new IllegalArgumentException("Cannot measure distance to a null location"); + } else if (o.getWorld() == null || getWorld() == null) { + throw new IllegalArgumentException("Cannot measure distance to a null world"); + } else if (o.getWorld() != getWorld()) { + throw new IllegalArgumentException("Cannot measure distance between " + getWorld().getName() + " and " + o.getWorld().getName()); + } + + return NumberConversions.square(x - o.x) + NumberConversions.square(y - o.y) + NumberConversions.square(z - o.z); + } + + /** + * Performs scalar multiplication, multiplying all components with a + * scalar. Not world-aware. + * + * @param m The factor + * @return the same location + * @see Vector + */ + public Location multiply(double m) { + x *= m; + y *= m; + z *= m; + return this; + } + + /** + * Zero this location's components. Not world-aware. + * + * @return the same location + * @see Vector + */ + public Location zero() { + x = 0; + y = 0; + z = 0; + return this; + } + + /** + * Constructs a new {@link Vector} based on this Location + * + * @return New Vector containing the coordinates represented by this + * Location + */ + public Vector toVector() { + return new Vector(x, y, z); + } + + /** + * Check if each component of this Location is finite. + * + * @throws IllegalArgumentException if any component is not finite + */ + public void checkFinite() throws IllegalArgumentException { + NumberConversions.checkFinite(x, "x not finite"); + NumberConversions.checkFinite(y, "y not finite"); + NumberConversions.checkFinite(z, "z not finite"); + NumberConversions.checkFinite(pitch, "pitch not finite"); + NumberConversions.checkFinite(yaw, "yaw not finite"); + } + + /** + * Safely converts a double (location coordinate) to an int (block + * coordinate) + * + * @param loc Precise coordinate + * @return Block coordinate + */ + public static int locToBlock(double loc) { + return NumberConversions.floor(loc); + } + + /** + * Normalizes the given yaw angle to a value between +/-180 + * degrees. + * + * @param yaw the yaw in degrees + * @return the normalized yaw in degrees + * @see Location#getYaw() + */ + public static float normalizeYaw(float yaw) { + yaw %= 360.0f; + if (yaw >= 180.0f) { + yaw -= 360.0f; + } else if (yaw < -180.0f) { + yaw += 360.0f; + } + return yaw; + } + + /** + * Normalizes the given pitch angle to a value between +/-90 + * degrees. + * + * @param pitch the pitch in degrees + * @return the normalized pitch in degrees + * @see Location#getPitch() + */ + public static float normalizePitch(float pitch) { + if (pitch > 90.0f) { + pitch = 90.0f; + } else if (pitch < -90.0f) { + pitch = -90.0f; + } + return pitch; + } + @Override public String toString() { return "Location{" + "world=" + world + ",x=" + x + ",y=" + y + ",z=" + z + ",pitch=" + pitch + ",yaw=" + yaw + "}"; } @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + Float.floatToIntBits(pitch); - result = prime * result + ((world == null) ? 0 : world.hashCode()); - long temp; - temp = Double.doubleToLongBits(x); - result = prime * result + (int) (temp ^ (temp >>> 32)); - temp = Double.doubleToLongBits(y); - result = prime * result + (int) (temp ^ (temp >>> 32)); - result = prime * result + Float.floatToIntBits(yaw); - temp = Double.doubleToLongBits(z); - result = prime * result + (int) (temp ^ (temp >>> 32)); - return result; - } + public boolean equals(Object obj) { + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final Location other = (Location) obj; - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - Location other = (Location) obj; - if (Float.floatToIntBits(pitch) != Float.floatToIntBits(other.pitch)) - return false; - if (world == null) { - if (other.world != null) - return false; - } else if (!world.equals(other.world)) - return false; - if (Double.doubleToLongBits(x) != Double.doubleToLongBits(other.x)) - return false; - if (Double.doubleToLongBits(y) != Double.doubleToLongBits(other.y)) - return false; - if (Float.floatToIntBits(yaw) != Float.floatToIntBits(other.yaw)) - return false; - if (Double.doubleToLongBits(z) != Double.doubleToLongBits(other.z)) - return false; - return true; - } + World world = (this.world == null) ? null : this.world; + World otherWorld = (other.world == null) ? null : other.world; + if (world != otherWorld && (world == null || !world.equals(otherWorld))) { + return false; + } + if (Double.doubleToLongBits(this.x) != Double.doubleToLongBits(other.x)) { + return false; + } + if (Double.doubleToLongBits(this.y) != Double.doubleToLongBits(other.y)) { + return false; + } + if (Double.doubleToLongBits(this.z) != Double.doubleToLongBits(other.z)) { + return false; + } + if (Float.floatToIntBits(this.pitch) != Float.floatToIntBits(other.pitch)) { + return false; + } + if (Float.floatToIntBits(this.yaw) != Float.floatToIntBits(other.yaw)) { + return false; + } + return true; + } + + @Override + public int hashCode() { + int hash = 3; + + World world = (this.world == null) ? null : this.world; + hash = 19 * hash + (world != null ? world.hashCode() : 0); + hash = 19 * hash + (int) (Double.doubleToLongBits(this.x) ^ (Double.doubleToLongBits(this.x) >>> 32)); + hash = 19 * hash + (int) (Double.doubleToLongBits(this.y) ^ (Double.doubleToLongBits(this.y) >>> 32)); + hash = 19 * hash + (int) (Double.doubleToLongBits(this.z) ^ (Double.doubleToLongBits(this.z) >>> 32)); + hash = 19 * hash + Float.floatToIntBits(this.pitch); + hash = 19 * hash + Float.floatToIntBits(this.yaw); + return hash; + } } diff --git a/src/com/loohp/limbo/Location/Vector.java b/src/com/loohp/limbo/Location/Vector.java new file mode 100644 index 0000000..73d5927 --- /dev/null +++ b/src/com/loohp/limbo/Location/Vector.java @@ -0,0 +1,852 @@ +package com.loohp.limbo.Location; + +import java.util.Random; + +import com.google.common.base.Preconditions; +import com.google.common.primitives.Doubles; +import com.loohp.limbo.Utils.NumberConversions; +import com.loohp.limbo.World.World; + +/** + * Represents a mutable vector. Because the components of Vectors are mutable, + * storing Vectors long term may be dangerous if passing code modifies the + * Vector later. If you want to keep around a Vector, it may be wise to call + * clone() in order to get a copy. + */ +public class Vector implements Cloneable { + + private static Random random = new Random(); + + /** + * Threshold for fuzzy equals(). + */ + private static final double epsilon = 0.000001; + + protected double x; + protected double y; + protected double z; + + /** + * Construct the vector with all components as 0. + */ + public Vector() { + this.x = 0; + this.y = 0; + this.z = 0; + } + + /** + * Construct the vector with provided integer components. + * + * @param x X component + * @param y Y component + * @param z Z component + */ + public Vector(int x, int y, int z) { + this.x = x; + this.y = y; + this.z = z; + } + + /** + * Construct the vector with provided double components. + * + * @param x X component + * @param y Y component + * @param z Z component + */ + public Vector(double x, double y, double z) { + this.x = x; + this.y = y; + this.z = z; + } + + /** + * Construct the vector with provided float components. + * + * @param x X component + * @param y Y component + * @param z Z component + */ + public Vector(float x, float y, float z) { + this.x = x; + this.y = y; + this.z = z; + } + + /** + * Adds a vector to this one + * + * @param vec The other vector + * @return the same vector + */ + public Vector add(Vector vec) { + x += vec.x; + y += vec.y; + z += vec.z; + return this; + } + + /** + * Subtracts a vector from this one. + * + * @param vec The other vector + * @return the same vector + */ + public Vector subtract(Vector vec) { + x -= vec.x; + y -= vec.y; + z -= vec.z; + return this; + } + + /** + * Multiplies the vector by another. + * + * @param vec The other vector + * @return the same vector + */ + public Vector multiply(Vector vec) { + x *= vec.x; + y *= vec.y; + z *= vec.z; + return this; + } + + /** + * Divides the vector by another. + * + * @param vec The other vector + * @return the same vector + */ + public Vector divide(Vector vec) { + x /= vec.x; + y /= vec.y; + z /= vec.z; + return this; + } + + /** + * Copies another vector + * + * @param vec The other vector + * @return the same vector + */ + public Vector copy(Vector vec) { + x = vec.x; + y = vec.y; + z = vec.z; + return this; + } + + /** + * Gets the magnitude of the vector, defined as sqrt(x^2+y^2+z^2). The + * value of this method is not cached and uses a costly square-root + * function, so do not repeatedly call this method to get the vector's + * magnitude. NaN will be returned if the inner result of the sqrt() + * function overflows, which will be caused if the length is too long. + * + * @return the magnitude + */ + public double length() { + return Math.sqrt(NumberConversions.square(x) + NumberConversions.square(y) + NumberConversions.square(z)); + } + + /** + * Gets the magnitude of the vector squared. + * + * @return the magnitude + */ + public double lengthSquared() { + return NumberConversions.square(x) + NumberConversions.square(y) + NumberConversions.square(z); + } + + /** + * Get the distance between this vector and another. The value of this + * method is not cached and uses a costly square-root function, so do not + * repeatedly call this method to get the vector's magnitude. NaN will be + * returned if the inner result of the sqrt() function overflows, which + * will be caused if the distance is too long. + * + * @param o The other vector + * @return the distance + */ + public double distance(Vector o) { + return Math.sqrt(NumberConversions.square(x - o.x) + NumberConversions.square(y - o.y) + NumberConversions.square(z - o.z)); + } + + /** + * Get the squared distance between this vector and another. + * + * @param o The other vector + * @return the distance + */ + public double distanceSquared(Vector o) { + return NumberConversions.square(x - o.x) + NumberConversions.square(y - o.y) + NumberConversions.square(z - o.z); + } + + /** + * Gets the angle between this vector and another in radians. + * + * @param other The other vector + * @return angle in radians + */ + public float angle(Vector other) { + double dot = Doubles.constrainToRange(dot(other) / (length() * other.length()), -1.0, 1.0); + + return (float) Math.acos(dot); + } + + /** + * Sets this vector to the midpoint between this vector and another. + * + * @param other The other vector + * @return this same vector (now a midpoint) + */ + public Vector midpoint(Vector other) { + x = (x + other.x) / 2; + y = (y + other.y) / 2; + z = (z + other.z) / 2; + return this; + } + + /** + * Gets a new midpoint vector between this vector and another. + * + * @param other The other vector + * @return a new midpoint vector + */ + public Vector getMidpoint(Vector other) { + double x = (this.x + other.x) / 2; + double y = (this.y + other.y) / 2; + double z = (this.z + other.z) / 2; + return new Vector(x, y, z); + } + + /** + * Performs scalar multiplication, multiplying all components with a + * scalar. + * + * @param m The factor + * @return the same vector + */ + public Vector multiply(int m) { + x *= m; + y *= m; + z *= m; + return this; + } + + /** + * Performs scalar multiplication, multiplying all components with a + * scalar. + * + * @param m The factor + * @return the same vector + */ + public Vector multiply(double m) { + x *= m; + y *= m; + z *= m; + return this; + } + + /** + * Performs scalar multiplication, multiplying all components with a + * scalar. + * + * @param m The factor + * @return the same vector + */ + public Vector multiply(float m) { + x *= m; + y *= m; + z *= m; + return this; + } + + /** + * Calculates the dot product of this vector with another. The dot product + * is defined as x1*x2+y1*y2+z1*z2. The returned value is a scalar. + * + * @param other The other vector + * @return dot product + */ + public double dot(Vector other) { + return x * other.x + y * other.y + z * other.z; + } + + /** + * Calculates the cross product of this vector with another. The cross + * product is defined as: + * + * + * @param o The other vector + * @return the same vector + */ + public Vector crossProduct(Vector o) { + double newX = y * o.z - o.y * z; + double newY = z * o.x - o.z * x; + double newZ = x * o.y - o.x * y; + + x = newX; + y = newY; + z = newZ; + return this; + } + + /** + * Calculates the cross product of this vector with another without mutating + * the original. The cross product is defined as: + * + * + * @param o The other vector + * @return a new vector + */ + public Vector getCrossProduct(Vector o) { + double x = this.y * o.z - o.y * this.z; + double y = this.z * o.x - o.z * this.x; + double z = this.x * o.y - o.x * this.y; + return new Vector(x, y, z); + } + + /** + * Converts this vector to a unit vector (a vector with length of 1). + * + * @return the same vector + */ + public Vector normalize() { + double length = length(); + + x /= length; + y /= length; + z /= length; + + return this; + } + + /** + * Zero this vector's components. + * + * @return the same vector + */ + public Vector zero() { + x = 0; + y = 0; + z = 0; + return this; + } + + /** + * Converts each component of value -0.0 to 0.0. + * + * @return This vector. + */ + Vector normalizeZeros() { + if (x == -0.0D) x = 0.0D; + if (y == -0.0D) y = 0.0D; + if (z == -0.0D) z = 0.0D; + return this; + } + + /** + * Returns whether this vector is in an axis-aligned bounding box. + *

+ * The minimum and maximum vectors given must be truly the minimum and + * maximum X, Y and Z components. + * + * @param min Minimum vector + * @param max Maximum vector + * @return whether this vector is in the AABB + */ + public boolean isInAABB(Vector min, Vector max) { + return x >= min.x && x <= max.x && y >= min.y && y <= max.y && z >= min.z && z <= max.z; + } + + /** + * Returns whether this vector is within a sphere. + * + * @param origin Sphere origin. + * @param radius Sphere radius + * @return whether this vector is in the sphere + */ + public boolean isInSphere(Vector origin, double radius) { + return (NumberConversions.square(origin.x - x) + NumberConversions.square(origin.y - y) + NumberConversions.square(origin.z - z)) <= NumberConversions.square(radius); + } + + /** + * Returns if a vector is normalized + * + * @return whether the vector is normalised + */ + public boolean isNormalized() { + return Math.abs(this.lengthSquared() - 1) < getEpsilon(); + } + + /** + * Rotates the vector around the x axis. + *

+ * This piece of math is based on the standard rotation matrix for vectors + * in three dimensional space. This matrix can be found here: + * Rotation + * Matrix. + * + * @param angle the angle to rotate the vector about. This angle is passed + * in radians + * @return the same vector + */ + public Vector rotateAroundX(double angle) { + double angleCos = Math.cos(angle); + double angleSin = Math.sin(angle); + + double y = angleCos * getY() - angleSin * getZ(); + double z = angleSin * getY() + angleCos * getZ(); + return setY(y).setZ(z); + } + + /** + * Rotates the vector around the y axis. + *

+ * This piece of math is based on the standard rotation matrix for vectors + * in three dimensional space. This matrix can be found here: + * Rotation + * Matrix. + * + * @param angle the angle to rotate the vector about. This angle is passed + * in radians + * @return the same vector + */ + public Vector rotateAroundY(double angle) { + double angleCos = Math.cos(angle); + double angleSin = Math.sin(angle); + + double x = angleCos * getX() + angleSin * getZ(); + double z = -angleSin * getX() + angleCos * getZ(); + return setX(x).setZ(z); + } + + /** + * Rotates the vector around the z axis + *

+ * This piece of math is based on the standard rotation matrix for vectors + * in three dimensional space. This matrix can be found here: + * Rotation + * Matrix. + * + * @param angle the angle to rotate the vector about. This angle is passed + * in radians + * @return the same vector + */ + public Vector rotateAroundZ(double angle) { + double angleCos = Math.cos(angle); + double angleSin = Math.sin(angle); + + double x = angleCos * getX() - angleSin * getY(); + double y = angleSin * getX() + angleCos * getY(); + return setX(x).setY(y); + } + + /** + * Rotates the vector around a given arbitrary axis in 3 dimensional space. + * + *

+ * Rotation will follow the general Right-Hand-Rule, which means rotation + * will be counterclockwise when the axis is pointing towards the observer. + *

+ * This method will always make sure the provided axis is a unit vector, to + * not modify the length of the vector when rotating. If you are experienced + * with the scaling of a non-unit axis vector, you can use + * {@link Vector#rotateAroundNonUnitAxis(Vector, double)}. + * + * @param axis the axis to rotate the vector around. If the passed vector is + * not of length 1, it gets copied and normalized before using it for the + * rotation. Please use {@link Vector#normalize()} on the instance before + * passing it to this method + * @param angle the angle to rotate the vector around the axis + * @return the same vector + * @throws IllegalArgumentException if the provided axis vector instance is + * null + */ + public Vector rotateAroundAxis(Vector axis, double angle) throws IllegalArgumentException { + Preconditions.checkArgument(axis != null, "The provided axis vector was null"); + + return rotateAroundNonUnitAxis(axis.isNormalized() ? axis : axis.clone().normalize(), angle); + } + + /** + * Rotates the vector around a given arbitrary axis in 3 dimensional space. + * + *

+ * Rotation will follow the general Right-Hand-Rule, which means rotation + * will be counterclockwise when the axis is pointing towards the observer. + *

+ * Note that the vector length will change accordingly to the axis vector + * length. If the provided axis is not a unit vector, the rotated vector + * will not have its previous length. The scaled length of the resulting + * vector will be related to the axis vector. If you are not perfectly sure + * about the scaling of the vector, use + * {@link Vector#rotateAroundAxis(Vector, double)} + * + * @param axis the axis to rotate the vector around. + * @param angle the angle to rotate the vector around the axis + * @return the same vector + * @throws IllegalArgumentException if the provided axis vector instance is + * null + */ + public Vector rotateAroundNonUnitAxis(Vector axis, double angle) throws IllegalArgumentException { + Preconditions.checkArgument(axis != null, "The provided axis vector was null"); + + double x = getX(), y = getY(), z = getZ(); + double x2 = axis.getX(), y2 = axis.getY(), z2 = axis.getZ(); + + double cosTheta = Math.cos(angle); + double sinTheta = Math.sin(angle); + double dotProduct = this.dot(axis); + + double xPrime = x2 * dotProduct * (1d - cosTheta) + + x * cosTheta + + (-z2 * y + y2 * z) * sinTheta; + double yPrime = y2 * dotProduct * (1d - cosTheta) + + y * cosTheta + + (z2 * x - x2 * z) * sinTheta; + double zPrime = z2 * dotProduct * (1d - cosTheta) + + z * cosTheta + + (-y2 * x + x2 * y) * sinTheta; + + return setX(xPrime).setY(yPrime).setZ(zPrime); + } + + /** + * Gets the X component. + * + * @return The X component. + */ + public double getX() { + return x; + } + + /** + * Gets the floored value of the X component, indicating the block that + * this vector is contained with. + * + * @return block X + */ + public int getBlockX() { + return NumberConversions.floor(x); + } + + /** + * Gets the Y component. + * + * @return The Y component. + */ + public double getY() { + return y; + } + + /** + * Gets the floored value of the Y component, indicating the block that + * this vector is contained with. + * + * @return block y + */ + public int getBlockY() { + return NumberConversions.floor(y); + } + + /** + * Gets the Z component. + * + * @return The Z component. + */ + public double getZ() { + return z; + } + + /** + * Gets the floored value of the Z component, indicating the block that + * this vector is contained with. + * + * @return block z + */ + public int getBlockZ() { + return NumberConversions.floor(z); + } + + /** + * Set the X component. + * + * @param x The new X component. + * @return This vector. + */ + public Vector setX(int x) { + this.x = x; + return this; + } + + /** + * Set the X component. + * + * @param x The new X component. + * @return This vector. + */ + public Vector setX(double x) { + this.x = x; + return this; + } + + /** + * Set the X component. + * + * @param x The new X component. + * @return This vector. + */ + public Vector setX(float x) { + this.x = x; + return this; + } + + /** + * Set the Y component. + * + * @param y The new Y component. + * @return This vector. + */ + public Vector setY(int y) { + this.y = y; + return this; + } + + /** + * Set the Y component. + * + * @param y The new Y component. + * @return This vector. + */ + public Vector setY(double y) { + this.y = y; + return this; + } + + /** + * Set the Y component. + * + * @param y The new Y component. + * @return This vector. + */ + public Vector setY(float y) { + this.y = y; + return this; + } + + /** + * Set the Z component. + * + * @param z The new Z component. + * @return This vector. + */ + public Vector setZ(int z) { + this.z = z; + return this; + } + + /** + * Set the Z component. + * + * @param z The new Z component. + * @return This vector. + */ + public Vector setZ(double z) { + this.z = z; + return this; + } + + /** + * Set the Z component. + * + * @param z The new Z component. + * @return This vector. + */ + public Vector setZ(float z) { + this.z = z; + return this; + } + + /** + * Checks to see if two objects are equal. + *

+ * Only two Vectors can ever return true. This method uses a fuzzy match + * to account for floating point errors. The epsilon can be retrieved + * with epsilon. + */ + @Override + public boolean equals(Object obj) { + if (!(obj instanceof Vector)) { + return false; + } + + Vector other = (Vector) obj; + + return Math.abs(x - other.x) < epsilon && Math.abs(y - other.y) < epsilon && Math.abs(z - other.z) < epsilon && (this.getClass().equals(obj.getClass())); + } + + /** + * Returns a hash code for this vector + * + * @return hash code + */ + @Override + public int hashCode() { + int hash = 7; + + hash = 79 * hash + (int) (Double.doubleToLongBits(this.x) ^ (Double.doubleToLongBits(this.x) >>> 32)); + hash = 79 * hash + (int) (Double.doubleToLongBits(this.y) ^ (Double.doubleToLongBits(this.y) >>> 32)); + hash = 79 * hash + (int) (Double.doubleToLongBits(this.z) ^ (Double.doubleToLongBits(this.z) >>> 32)); + return hash; + } + + /** + * Get a new vector. + * + * @return vector + */ + @Override + public Vector clone() { + try { + return (Vector) super.clone(); + } catch (CloneNotSupportedException e) { + throw new Error(e); + } + } + + /** + * Returns this vector's components as x,y,z. + */ + @Override + public String toString() { + return x + "," + y + "," + z; + } + + /** + * Gets a Location version of this vector with yaw and pitch being 0. + * + * @param world The world to link the location to. + * @return the location + */ + public Location toLocation(World world) { + return new Location(world, x, y, z); + } + + /** + * Gets a Location version of this vector. + * + * @param world The world to link the location to. + * @param yaw The desired yaw. + * @param pitch The desired pitch. + * @return the location + */ + public Location toLocation(World world, float yaw, float pitch) { + return new Location(world, x, y, z, yaw, pitch); + } + + /** + * Get the block vector of this vector. + * + * @return A block vector. + public BlockVector toBlockVector() { + return new BlockVector(x, y, z); + } + */ + + /** + * Check if each component of this Vector is finite. + * + * @throws IllegalArgumentException if any component is not finite + */ + public void checkFinite() throws IllegalArgumentException { + NumberConversions.checkFinite(x, "x not finite"); + NumberConversions.checkFinite(y, "y not finite"); + NumberConversions.checkFinite(z, "z not finite"); + } + + /** + * Get the threshold used for equals(). + * + * @return The epsilon. + */ + public static double getEpsilon() { + return epsilon; + } + + /** + * Gets the minimum components of two vectors. + * + * @param v1 The first vector. + * @param v2 The second vector. + * @return minimum + */ + public static Vector getMinimum(Vector v1, Vector v2) { + return new Vector(Math.min(v1.x, v2.x), Math.min(v1.y, v2.y), Math.min(v1.z, v2.z)); + } + + /** + * Gets the maximum components of two vectors. + * + * @param v1 The first vector. + * @param v2 The second vector. + * @return maximum + */ + public static Vector getMaximum(Vector v1, Vector v2) { + return new Vector(Math.max(v1.x, v2.x), Math.max(v1.y, v2.y), Math.max(v1.z, v2.z)); + } + + /** + * Gets a random vector with components having a random value between 0 + * and 1. + * + * @return A random vector. + */ + public static Vector getRandom() { + return new Vector(random.nextDouble(), random.nextDouble(), random.nextDouble()); + } + + /* + @Override + public Map serialize() { + Map result = new LinkedHashMap(); + + result.put("x", getX()); + result.put("y", getY()); + result.put("z", getZ()); + + return result; + } + */ + /* + public static Vector deserialize(Map args) { + double x = 0; + double y = 0; + double z = 0; + + if (args.containsKey("x")) { + x = (Double) args.get("x"); + } + if (args.containsKey("y")) { + y = (Double) args.get("y"); + } + if (args.containsKey("z")) { + z = (Double) args.get("z"); + } + + return new Vector(x, y, z); + } + */ +} diff --git a/src/com/loohp/limbo/Player/Player.java b/src/com/loohp/limbo/Player/Player.java index 717002e..45a0ba8 100644 --- a/src/com/loohp/limbo/Player/Player.java +++ b/src/com/loohp/limbo/Player/Player.java @@ -13,7 +13,6 @@ import com.loohp.limbo.Server.Packets.PacketPlayOutGameState; import com.loohp.limbo.Server.Packets.PacketPlayOutPositionAndLook; import com.loohp.limbo.Server.Packets.PacketPlayOutRespawn; import com.loohp.limbo.Utils.GameMode; -import com.loohp.limbo.World.DimensionRegistry; import com.loohp.limbo.World.World; import net.md_5.bungee.api.chat.BaseComponent; @@ -26,9 +25,9 @@ public class Player implements CommandSender { private final String username; private final UUID uuid; - private GameMode gamemode; + protected GameMode gamemode; - private int entityId; + protected int entityId; private Location location; @@ -55,20 +54,10 @@ public class Player implements CommandSender { } this.gamemode = gamemode; } - - @Deprecated - public void setGamemodeSilent(GameMode gamemode) { - this.gamemode = gamemode; - } public World getWorld() { return location.clone().getWorld(); } - - @Deprecated - public void setEntityId(int entityId) { - this.entityId = entityId; - } public int getEntityId() { return entityId; @@ -105,7 +94,7 @@ public class Player implements CommandSender { public void teleport(Location location) { try { if (!this.location.getWorld().equals(location.getWorld())) { - PacketPlayOutRespawn respawn = new PacketPlayOutRespawn(location.getWorld(), DimensionRegistry.getCodec(), 0, gamemode, false, false, true); + PacketPlayOutRespawn respawn = new PacketPlayOutRespawn(location.getWorld(), Limbo.getInstance().getDimensionRegistry().getCodec(), 0, gamemode, false, false, true); clientConnection.sendPacket(respawn); } PacketPlayOutPositionAndLook positionLook = new PacketPlayOutPositionAndLook(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch(), 1); diff --git a/src/com/loohp/limbo/Player/Unsafe.java b/src/com/loohp/limbo/Player/Unsafe.java new file mode 100644 index 0000000..fe1c64f --- /dev/null +++ b/src/com/loohp/limbo/Player/Unsafe.java @@ -0,0 +1,20 @@ +package com.loohp.limbo.Player; + +import com.loohp.limbo.Utils.GameMode; + +@Deprecated +public class Unsafe { + + private Unsafe() {} + + @Deprecated + public void a(Player a, GameMode b) { + a.gamemode = b; + } + + @Deprecated + public void a(Player a, int b) { + a.entityId = b; + } + +} diff --git a/src/com/loohp/limbo/Server/ClientConnection.java b/src/com/loohp/limbo/Server/ClientConnection.java index 34f2450..094762e 100644 --- a/src/com/loohp/limbo/Server/ClientConnection.java +++ b/src/com/loohp/limbo/Server/ClientConnection.java @@ -63,7 +63,6 @@ import com.loohp.limbo.Utils.MojangAPIUtils; import com.loohp.limbo.Utils.MojangAPIUtils.SkinResponse; import com.loohp.limbo.Utils.NamespacedKey; import com.loohp.limbo.World.BlockPosition; -import com.loohp.limbo.World.DimensionRegistry; import com.loohp.limbo.World.World; import net.md_5.bungee.api.ChatColor; @@ -284,9 +283,9 @@ public class ClientConnection extends Thread { TimeUnit.MILLISECONDS.sleep(500); ServerProperties p = Limbo.getInstance().getServerProperties(); - PacketPlayOutLogin join = new PacketPlayOutLogin(player.getEntityId(), false, p.getDefaultGamemode(), Limbo.getInstance().getWorlds().stream().map(each -> new NamespacedKey(each.getName()).toString()).collect(Collectors.toList()).toArray(new String[Limbo.getInstance().getWorlds().size()]), DimensionRegistry.getCodec(), p.getWorldSpawn().getWorld(), 0, (byte) p.getMaxPlayers(), 8, p.isReducedDebugInfo(), true, false, true); + PacketPlayOutLogin join = new PacketPlayOutLogin(player.getEntityId(), false, p.getDefaultGamemode(), Limbo.getInstance().getWorlds().stream().map(each -> new NamespacedKey(each.getName()).toString()).collect(Collectors.toList()).toArray(new String[Limbo.getInstance().getWorlds().size()]), Limbo.getInstance().getDimensionRegistry().getCodec(), p.getWorldSpawn().getWorld(), 0, (byte) p.getMaxPlayers(), 8, p.isReducedDebugInfo(), true, false, true); sendPacket(join); - player.setGamemodeSilent(p.getDefaultGamemode()); + Limbo.getInstance().getUnsafe().setPlayerGameModeSilently(player, p.getDefaultGamemode()); Location s = p.getWorldSpawn(); diff --git a/src/com/loohp/limbo/Server/Packets/PacketPlayOutLogin.java b/src/com/loohp/limbo/Server/Packets/PacketPlayOutLogin.java index 43095e4..d95d93b 100644 --- a/src/com/loohp/limbo/Server/Packets/PacketPlayOutLogin.java +++ b/src/com/loohp/limbo/Server/Packets/PacketPlayOutLogin.java @@ -8,8 +8,8 @@ import java.nio.charset.StandardCharsets; import com.loohp.limbo.Utils.DataTypeIO; import com.loohp.limbo.Utils.GameMode; import com.loohp.limbo.Utils.NamespacedKey; +import com.loohp.limbo.World.Environment; import com.loohp.limbo.World.World; -import com.loohp.limbo.World.World.Environment; import net.querz.nbt.tag.CompoundTag; import net.querz.nbt.tag.ListTag; diff --git a/src/com/loohp/limbo/Server/Packets/PacketPlayOutMapChunk.java b/src/com/loohp/limbo/Server/Packets/PacketPlayOutMapChunk.java index a241173..9cc295d 100644 --- a/src/com/loohp/limbo/Server/Packets/PacketPlayOutMapChunk.java +++ b/src/com/loohp/limbo/Server/Packets/PacketPlayOutMapChunk.java @@ -7,8 +7,8 @@ import java.util.Iterator; import com.loohp.limbo.Utils.ChunkDataUtils; import com.loohp.limbo.Utils.DataTypeIO; +import com.loohp.limbo.World.Environment; import com.loohp.limbo.World.GeneratedBlockDataMappings; -import com.loohp.limbo.World.World.Environment; import net.querz.mca.Chunk; import net.querz.mca.Section; @@ -72,17 +72,14 @@ public class PacketPlayOutMapChunk extends PacketOut { DataTypeIO.writeVarInt(output, 1024); int biome; - switch (environment) { - case END: + if (environment.equals(Environment.END)) { biome = 9; //the_end - break; - case NETHER: + } else if (environment.equals(Environment.NETHER)) { biome = 8; //nether_waste - break; - case NORMAL: - default: + } else if (environment.equals(Environment.NORMAL)) { + biome = 1; //plains + } else { biome = 1; //plains - break; } for (int i = 0; i < 1024; i++) { DataTypeIO.writeVarInt(output, biome); diff --git a/src/com/loohp/limbo/Server/Packets/PacketPlayOutRespawn.java b/src/com/loohp/limbo/Server/Packets/PacketPlayOutRespawn.java index 7c39c55..ff275ee 100644 --- a/src/com/loohp/limbo/Server/Packets/PacketPlayOutRespawn.java +++ b/src/com/loohp/limbo/Server/Packets/PacketPlayOutRespawn.java @@ -8,8 +8,8 @@ import java.nio.charset.StandardCharsets; import com.loohp.limbo.Utils.DataTypeIO; import com.loohp.limbo.Utils.GameMode; import com.loohp.limbo.Utils.NamespacedKey; +import com.loohp.limbo.World.Environment; import com.loohp.limbo.World.World; -import com.loohp.limbo.World.World.Environment; import net.querz.nbt.tag.CompoundTag; import net.querz.nbt.tag.ListTag; diff --git a/src/com/loohp/limbo/Unsafe.java b/src/com/loohp/limbo/Unsafe.java new file mode 100644 index 0000000..8570188 --- /dev/null +++ b/src/com/loohp/limbo/Unsafe.java @@ -0,0 +1,32 @@ +package com.loohp.limbo; + +import java.lang.reflect.Constructor; + +import com.loohp.limbo.Player.Player; +import com.loohp.limbo.Utils.GameMode; + +@Deprecated +public class Unsafe { + + private com.loohp.limbo.Player.Unsafe playerUnsafe; + + protected Unsafe() { + try { + Constructor playerConstructor = com.loohp.limbo.Player.Unsafe.class.getDeclaredConstructor(); + playerConstructor.setAccessible(true); + playerUnsafe = playerConstructor.newInstance(); + playerConstructor.setAccessible(false); + } catch (Exception e) {e.printStackTrace();} + } + + @Deprecated + public void setPlayerGameModeSilently(Player player, GameMode mode) { + playerUnsafe.a(player, mode); + } + + @Deprecated + public void setPlayerEntityId(Player player, int entityId) { + playerUnsafe.a(player, entityId); + } + +} diff --git a/src/com/loohp/limbo/Utils/NamespacedKey.java b/src/com/loohp/limbo/Utils/NamespacedKey.java index c62e736..f89f559 100644 --- a/src/com/loohp/limbo/Utils/NamespacedKey.java +++ b/src/com/loohp/limbo/Utils/NamespacedKey.java @@ -2,8 +2,8 @@ package com.loohp.limbo.Utils; public class NamespacedKey { - String namespace; - String key; + private String namespace; + private String key; public NamespacedKey(String namespacedKey) { int index = namespacedKey.indexOf(":"); diff --git a/src/com/loohp/limbo/Utils/NumberConversions.java b/src/com/loohp/limbo/Utils/NumberConversions.java new file mode 100644 index 0000000..32cf5e1 --- /dev/null +++ b/src/com/loohp/limbo/Utils/NumberConversions.java @@ -0,0 +1,124 @@ +package com.loohp.limbo.Utils; + +/** + * Utils for casting number types to other number types + */ +public final class NumberConversions { + private NumberConversions() {} + + public static int floor(double num) { + final int floor = (int) num; + return floor == num ? floor : floor - (int) (Double.doubleToRawLongBits(num) >>> 63); + } + + public static int ceil(final double num) { + final int floor = (int) num; + return floor == num ? floor : floor + (int) (~Double.doubleToRawLongBits(num) >>> 63); + } + + public static int round(double num) { + return floor(num + 0.5d); + } + + public static double square(double num) { + return num * num; + } + + public static int toInt(Object object) { + if (object instanceof Number) { + return ((Number) object).intValue(); + } + + try { + return Integer.parseInt(object.toString()); + } catch (NumberFormatException e) { + } catch (NullPointerException e) { + } + return 0; + } + + public static float toFloat(Object object) { + if (object instanceof Number) { + return ((Number) object).floatValue(); + } + + try { + return Float.parseFloat(object.toString()); + } catch (NumberFormatException e) { + } catch (NullPointerException e) { + } + return 0; + } + + public static double toDouble(Object object) { + if (object instanceof Number) { + return ((Number) object).doubleValue(); + } + + try { + return Double.parseDouble(object.toString()); + } catch (NumberFormatException e) { + } catch (NullPointerException e) { + } + return 0; + } + + public static long toLong(Object object) { + if (object instanceof Number) { + return ((Number) object).longValue(); + } + + try { + return Long.parseLong(object.toString()); + } catch (NumberFormatException e) { + } catch (NullPointerException e) { + } + return 0; + } + + public static short toShort(Object object) { + if (object instanceof Number) { + return ((Number) object).shortValue(); + } + + try { + return Short.parseShort(object.toString()); + } catch (NumberFormatException e) { + } catch (NullPointerException e) { + } + return 0; + } + + public static byte toByte(Object object) { + if (object instanceof Number) { + return ((Number) object).byteValue(); + } + + try { + return Byte.parseByte(object.toString()); + } catch (NumberFormatException e) { + } catch (NullPointerException e) { + } + return 0; + } + + public static boolean isFinite(double d) { + return Math.abs(d) <= Double.MAX_VALUE; + } + + public static boolean isFinite(float f) { + return Math.abs(f) <= Float.MAX_VALUE; + } + + public static void checkFinite(double d, String message) { + if (!isFinite(d)) { + throw new IllegalArgumentException(message); + } + } + + public static void checkFinite(float d, String message) { + if (!isFinite(d)) { + throw new IllegalArgumentException(message); + } + } +} diff --git a/src/com/loohp/limbo/World/BlockState.java b/src/com/loohp/limbo/World/BlockState.java new file mode 100644 index 0000000..31bbcbf --- /dev/null +++ b/src/com/loohp/limbo/World/BlockState.java @@ -0,0 +1,63 @@ +package com.loohp.limbo.World; + +import java.util.HashMap; +import java.util.Map; +import java.util.Map.Entry; + +import com.loohp.limbo.Utils.NamespacedKey; + +import net.querz.nbt.tag.CompoundTag; +import net.querz.nbt.tag.StringTag; +import net.querz.nbt.tag.Tag; + +public class BlockState { + + private CompoundTag tag; + + public BlockState(CompoundTag tag) { + this.tag = tag; + } + + public CompoundTag toCompoundTag() { + return tag; + } + + public NamespacedKey getType() { + return new NamespacedKey(tag.getString("Name")); + } + + public void setType(NamespacedKey namespacedKey) { + tag.putString("Name", namespacedKey.toString()); + } + + public Map getProperties() { + Map mapping = new HashMap<>(); + for (Entry> entry : tag.getCompoundTag("Properties")) { + String key = entry.getKey(); + String value = ((StringTag) entry.getValue()).getValue(); + mapping.put(key, value); + } + return mapping; + } + + public String getProperty(String key) { + Tag value = tag.getCompoundTag("Properties").get(key); + return value == null ? null : ((StringTag) value).getValue(); + } + + public void setProperties(Map mapping) { + CompoundTag properties = new CompoundTag(); + for (Entry entry : mapping.entrySet()) { + String key = entry.getKey(); + String value = entry.getValue(); + properties.putString(key, value); + } + tag.put("Properties", properties); + } + + public void setProperty(String key, T value) { + CompoundTag properties = tag.getCompoundTag("Properties"); + properties.putString(key, ((T) value).toString()); + } + +} diff --git a/src/com/loohp/limbo/World/DimensionRegistry.java b/src/com/loohp/limbo/World/DimensionRegistry.java index bbff672..76559d2 100644 --- a/src/com/loohp/limbo/World/DimensionRegistry.java +++ b/src/com/loohp/limbo/World/DimensionRegistry.java @@ -17,37 +17,45 @@ import net.querz.nbt.tag.CompoundTag; public class DimensionRegistry { - public static CompoundTag defaultTag; - private static File reg; + private CompoundTag defaultTag; + private CompoundTag codec; + private File reg; - static { - String reg = "dimension_registry.json"; - File file = new File(Limbo.getInstance().getInternalDataFolder(), reg); + public DimensionRegistry() { + this.defaultTag = new CompoundTag(); + + String name = "dimension_registry.json"; + File file = new File(Limbo.getInstance().getInternalDataFolder(), name); if (!file.exists()) { - try (InputStream in = Limbo.class.getClassLoader().getResourceAsStream(reg)) { + try (InputStream in = Limbo.class.getClassLoader().getResourceAsStream(name)) { Files.copy(in, file.toPath()); } catch (IOException e) { e.printStackTrace(); } } - DimensionRegistry.reg = file; - - resetTag(); - } - - public static void resetTag() { - try { + this.reg = file; + + try { JSONObject json = (JSONObject) new JSONParser().parse(new FileReader(reg)); CompoundTag tag = CustomNBTUtils.getCompoundTagFromJson((JSONObject) json.get("value")); defaultTag = tag; + codec = defaultTag.clone(); } catch (IOException | ParseException e) { e.printStackTrace(); } } - public static CompoundTag getCodec() { - return defaultTag; + public File getFile() { + return reg; + } + + public void resetCodec() { + codec = defaultTag.clone(); + } + + public CompoundTag getCodec() { + return codec; } } diff --git a/src/com/loohp/limbo/World/Environment.java b/src/com/loohp/limbo/World/Environment.java new file mode 100644 index 0000000..152c928 --- /dev/null +++ b/src/com/loohp/limbo/World/Environment.java @@ -0,0 +1,37 @@ +package com.loohp.limbo.World; + +import com.loohp.limbo.Utils.NamespacedKey; + +public class Environment { + + public static final Environment NORMAL = new Environment(new NamespacedKey("minecraft:overworld")); + public static final Environment NETHER = new Environment(new NamespacedKey("minecraft:the_nether")); + public static final Environment END = new Environment(new NamespacedKey("minecraft:the_end")); + + public static Environment fromNamespacedKey(NamespacedKey key) { + if (key.equals(NORMAL.getNamespacedKey())) { + return NORMAL; + } else if (key.equals(NETHER.getNamespacedKey())) { + return NETHER; + } else if (key.equals(END.getNamespacedKey())) { + return END; + } + return null; + } + + public static Environment createCustom(NamespacedKey key) { + return new Environment(key); + } + + //========================= + + private NamespacedKey key; + + private Environment(NamespacedKey key) { + this.key = key; + } + + public NamespacedKey getNamespacedKey() { + return key; + } +} \ No newline at end of file diff --git a/src/com/loohp/limbo/World/Schematic.java b/src/com/loohp/limbo/World/Schematic.java index 1d5cbb1..f0c7908 100644 --- a/src/com/loohp/limbo/World/Schematic.java +++ b/src/com/loohp/limbo/World/Schematic.java @@ -5,7 +5,6 @@ import java.util.Iterator; import java.util.Map; import com.loohp.limbo.Utils.SchematicConvertionUtils; -import com.loohp.limbo.World.World.Environment; import net.querz.mca.Chunk; import net.querz.nbt.tag.CompoundTag; diff --git a/src/com/loohp/limbo/World/World.java b/src/com/loohp/limbo/World/World.java index 07cd009..4598e1f 100644 --- a/src/com/loohp/limbo/World/World.java +++ b/src/com/loohp/limbo/World/World.java @@ -1,6 +1,7 @@ package com.loohp.limbo.World; -import com.loohp.limbo.Utils.NamespacedKey; +import java.util.Arrays; + import com.loohp.limbo.Utils.SchematicConvertionUtils; import net.querz.mca.Chunk; @@ -42,7 +43,7 @@ public class World { } } - public void setBlock(int x, int y, int z, String blockdata) { + protected void setBlock(int x, int y, int z, String blockdata) { Chunk chunk = this.chunks[(x >> 4)][(z >> 4)]; if (chunk == null) { chunk = Chunk.newChunk(); @@ -51,6 +52,24 @@ public class World { CompoundTag block = SchematicConvertionUtils.toBlockTag(blockdata); chunk.setBlockStateAt(x, y, z, block, false); } + + public BlockState getBlock(int x, int y, int z) { + Chunk chunk = this.chunks[(x >> 4)][(z >> 4)]; + if (chunk == null) { + chunk = Chunk.newChunk(); + this.chunks[(x >> 4)][(z >> 4)] = chunk; + } + return new BlockState(chunk.getBlockStateAt(x % 16, y % 16, z % 16)); + } + + public void setBlock(int x, int y, int z, BlockState state) { + Chunk chunk = this.chunks[(x >> 4)][(z >> 4)]; + if (chunk == null) { + chunk = Chunk.newChunk(); + this.chunks[(x >> 4)][(z >> 4)] = chunk; + } + chunk.setBlockStateAt(x % 16, y % 16, z % 16, state.toCompoundTag(), false); + } public Chunk[][] getChunks() { return this.chunks; @@ -67,29 +86,42 @@ public class World { public Environment getEnvironment() { return environment; } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + Arrays.deepHashCode(chunks); + result = prime * result + ((environment == null) ? 0 : environment.hashCode()); + result = prime * result + ((name == null) ? 0 : name.hashCode()); + return result; + } - public enum Environment { - NORMAL(new NamespacedKey("minecraft:overworld")), - NETHER(new NamespacedKey("minecraft:the_nether")), - END(new NamespacedKey("minecraft:the_end")); - - NamespacedKey key; - - Environment(NamespacedKey key) { - this.key = key; + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; } - - public NamespacedKey getNamespacedKey() { - return key; + if (obj == null) { + return false; } - - public static Environment fromNamespacedKey(NamespacedKey key) { - for (Environment each : Environment.values()) { - if (each.getNamespacedKey().equals(key)) { - return each; - } + if (getClass() != obj.getClass()) { + return false; + } + World other = (World) obj; + if (!Arrays.deepEquals(chunks, other.chunks)) { + return false; + } + if (environment != other.environment) { + return false; + } + if (name == null) { + if (other.name != null) { + return false; } - return null; + } else if (!name.equals(other.name)) { + return false; } + return true; } }