getWatchableObjects() {
+ return Collections.unmodifiableMap(values);
+ }
+
+ public static class WatchableObject {
+
+ private int index;
+ private WatchableObjectType type;
+ private boolean optional;
+ private boolean isBitmask;
+ private int bitmask;
+
+ private Object value;
+
+ public WatchableObject(Object value, int index, WatchableObjectType type, boolean optional, boolean isBitmask, int bitmask) {
+ this.index = index;
+ this.type = type;
+ this.optional = optional;
+ this.isBitmask = isBitmask;
+ this.bitmask = bitmask;
+ this.value = value;
+ }
+
+ public WatchableObject(Object value, int index, WatchableObjectType type, boolean isBitmask, int bitmask) {
+ this(value, index, type, false, isBitmask, bitmask);
+ }
+
+ public WatchableObject(Object value, int index, WatchableObjectType type, boolean optional) {
+ this(value, index, type, optional, false, 0x00);
+ }
+
+ public WatchableObject(Object value, int index, WatchableObjectType type) {
+ this(value, index, type, false, false, 0x00);
+ }
+
+ public Object getValue() {
+ return value;
+ }
+
+ public void setValue(Object newValue) {
+ this.value = newValue;
+ }
+
+ public int getIndex() {
+ return index;
+ }
+
+ public WatchableObjectType getType() {
+ return type;
+ }
+
+ public boolean isOptional() {
+ return optional;
+ }
+
+ public boolean isBitmask() {
+ return isBitmask;
+ }
+
+ public int getBitmask() {
+ return bitmask;
+ }
+ }
+
+ @Retention(RetentionPolicy.RUNTIME)
+ @Target(ElementType.FIELD)
+ public static @interface WatchableField {
+ int MetadataIndex();
+ WatchableObjectType WatchableObjectType();
+ boolean IsOptional() default false;
+ boolean IsBitmask() default false;
+ int Bitmask() default 0x00;
+ }
+
+ public static enum WatchableObjectType {
+ BYTE(0),
+ VARINT(1, 17),
+ FLOAT(2),
+ STRING(3),
+ CHAT(4, 5),
+ SLOT(6),
+ BOOLEAN(7),
+ ROTATION(8),
+ POSITION(9, 10),
+ DIRECTION(11),
+ UUID(-1, 12),
+ BLOCKID(-1, 13),
+ NBT(14),
+ PARTICLE(15),
+ VILLAGER_DATA(16),
+ POSE(18);
+
+ int typeId;
+ int optionalTypeId;
+
+ WatchableObjectType(int typeId, int optionalTypeId) {
+ this.typeId = typeId;
+ this.optionalTypeId = optionalTypeId;
+ }
+
+ WatchableObjectType(int typeId) {
+ this(typeId, -1);
+ }
+
+ public int getTypeId() {
+ return typeId;
+ }
+
+ public int getOptionalTypeId() {
+ return optionalTypeId;
+ }
+ }
+
+}
diff --git a/src/main/java/com/loohp/limbo/Entity/Entity.java b/src/main/java/com/loohp/limbo/Entity/Entity.java
new file mode 100644
index 0000000..3181da7
--- /dev/null
+++ b/src/main/java/com/loohp/limbo/Entity/Entity.java
@@ -0,0 +1,283 @@
+package com.loohp.limbo.Entity;
+
+import java.util.UUID;
+
+import com.loohp.limbo.Limbo;
+import com.loohp.limbo.Entity.DataWatcher.WatchableField;
+import com.loohp.limbo.Entity.DataWatcher.WatchableObjectType;
+import com.loohp.limbo.Location.Location;
+import com.loohp.limbo.World.World;
+
+import net.md_5.bungee.api.chat.BaseComponent;
+import net.md_5.bungee.api.chat.TextComponent;
+
+public abstract class Entity {
+
+ @WatchableField(MetadataIndex = 0, WatchableObjectType = WatchableObjectType.BYTE, IsBitmask = true, Bitmask = 0x01)
+ protected boolean onFire = false;
+ @WatchableField(MetadataIndex = 0, WatchableObjectType = WatchableObjectType.BYTE, IsBitmask = true, Bitmask = 0x02)
+ protected boolean crouching = false;
+ @WatchableField(MetadataIndex = 0, WatchableObjectType = WatchableObjectType.BYTE, IsBitmask = true, Bitmask = 0x04)
+ protected boolean unused = false;
+ @WatchableField(MetadataIndex = 0, WatchableObjectType = WatchableObjectType.BYTE, IsBitmask = true, Bitmask = 0x08)
+ protected boolean sprinting = false;
+ @WatchableField(MetadataIndex = 0, WatchableObjectType = WatchableObjectType.BYTE, IsBitmask = true, Bitmask = 0x10)
+ protected boolean swimming = false;
+ @WatchableField(MetadataIndex = 0, WatchableObjectType = WatchableObjectType.BYTE, IsBitmask = true, Bitmask = 0x20)
+ protected boolean invisible = false;
+ @WatchableField(MetadataIndex = 0, WatchableObjectType = WatchableObjectType.BYTE, IsBitmask = true, Bitmask = 0x40)
+ protected boolean glowing = false;
+ @WatchableField(MetadataIndex = 0, WatchableObjectType = WatchableObjectType.BYTE, IsBitmask = true, Bitmask = 0x80)
+ protected boolean elytraFlying = false;
+ @WatchableField(MetadataIndex = 1, WatchableObjectType = WatchableObjectType.VARINT)
+ protected int air = 300;
+ @WatchableField(MetadataIndex = 2, WatchableObjectType = WatchableObjectType.CHAT, IsOptional = true)
+ protected BaseComponent[] customName = null;
+ @WatchableField(MetadataIndex = 3, WatchableObjectType = WatchableObjectType.BOOLEAN)
+ protected boolean customNameVisible = false;
+ @WatchableField(MetadataIndex = 4, WatchableObjectType = WatchableObjectType.BOOLEAN)
+ protected boolean silent = false;
+ @WatchableField(MetadataIndex = 5, WatchableObjectType = WatchableObjectType.BOOLEAN)
+ protected boolean noGravity = false;
+ @WatchableField(MetadataIndex = 6, WatchableObjectType = WatchableObjectType.POSE)
+ protected Pose pose = Pose.STANDING;
+
+ protected final EntityType type;
+
+ protected int entityId;
+ protected UUID uuid;
+ protected World world;
+ protected double x;
+ protected double y;
+ protected double z;
+ protected float yaw;
+ protected float pitch;
+
+ public Entity(EntityType type, int entityId, UUID uuid, World world, double x, double y, double z, float yaw, float pitch) {
+ this.type = type;
+ this.entityId = entityId;
+ this.uuid = uuid;
+ this.world = world;
+ this.x = x;
+ this.y = y;
+ this.z = z;
+ this.yaw = yaw;
+ this.pitch = pitch;
+ }
+
+ public Entity(EntityType type, UUID uuid, World world, double x, double y, double z, float yaw, float pitch) {
+ this(type, Limbo.getInstance().getNextEntityId(), uuid, world, x, y, z, yaw, pitch);
+ }
+
+ public Entity(EntityType type, World world, double x, double y, double z, float yaw, float pitch) {
+ this(type, Limbo.getInstance().getNextEntityId(), UUID.randomUUID(), world, x, y, z, yaw, pitch);
+ }
+
+ public Entity(EntityType type, UUID uuid, Location location) {
+ this(type, Limbo.getInstance().getNextEntityId(), uuid, location.getWorld(), location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch());
+ }
+
+ public Entity(EntityType type, Location location) {
+ this(type, Limbo.getInstance().getNextEntityId(), UUID.randomUUID(), location.getWorld(), location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch());
+ }
+
+ public EntityType getType() {
+ return type;
+ }
+
+ public Location getLocation() {
+ return new Location(world, x, y, z, yaw, pitch);
+ }
+
+ public void teleport(Location location) {
+ this.world = location.getWorld();
+ this.x = location.getX();
+ this.y = location.getY();
+ this.z = location.getZ();
+ this.yaw = location.getYaw();
+ this.pitch = location.getPitch();
+ }
+
+ public BaseComponent[] getCustomName() {
+ return customName;
+ }
+
+ public void setCustomName(String name) {
+ this.customName = name == null ? null : new BaseComponent[] {new TextComponent(name)};
+ }
+
+ public void setCustomName(BaseComponent component) {
+ this.customName = component == null ? null : new BaseComponent[] {component};
+ }
+
+ public void setCustomName(BaseComponent[] components) {
+ this.customName = components;
+ }
+
+ public boolean isOnFire() {
+ return onFire;
+ }
+
+ public void setOnFire(boolean onFire) {
+ this.onFire = onFire;
+ }
+
+ public boolean isCrouching() {
+ return crouching;
+ }
+
+ public void setCrouching(boolean crouching) {
+ this.crouching = crouching;
+ }
+
+ public boolean isSprinting() {
+ return sprinting;
+ }
+
+ public void setSprinting(boolean sprinting) {
+ this.sprinting = sprinting;
+ }
+
+ public boolean isSwimming() {
+ return swimming;
+ }
+
+ public void setSwimming(boolean swimming) {
+ this.swimming = swimming;
+ }
+
+ public boolean isInvisible() {
+ return invisible;
+ }
+
+ public void setInvisible(boolean invisible) {
+ this.invisible = invisible;
+ }
+
+ public boolean isGlowing() {
+ return glowing;
+ }
+
+ public void setGlowing(boolean glowing) {
+ this.glowing = glowing;
+ }
+
+ public boolean isElytraFlying() {
+ return elytraFlying;
+ }
+
+ public void setElytraFlying(boolean elytraFlying) {
+ this.elytraFlying = elytraFlying;
+ }
+
+ public int getAir() {
+ return air;
+ }
+
+ public void setAir(int air) {
+ this.air = air;
+ }
+
+ public boolean isCustomNameVisible() {
+ return customNameVisible;
+ }
+
+ public void setCustomNameVisible(boolean customNameVisible) {
+ this.customNameVisible = customNameVisible;
+ }
+
+ public boolean isSilent() {
+ return silent;
+ }
+
+ public void setSilent(boolean silent) {
+ this.silent = silent;
+ }
+
+ public boolean hasGravity() {
+ return !noGravity;
+ }
+
+ public void setGravity(boolean gravity) {
+ this.noGravity = !gravity;
+ }
+
+ public Pose getPose() {
+ return pose;
+ }
+
+ public void setPose(Pose pose) {
+ this.pose = pose;
+ }
+
+ public World getWorld() {
+ return world;
+ }
+
+ public void setWorld(World world) {
+ this.world = world;
+ }
+
+ public double getX() {
+ return x;
+ }
+
+ public void setX(double x) {
+ this.x = x;
+ }
+
+ public double getY() {
+ return y;
+ }
+
+ public void setY(double y) {
+ this.y = y;
+ }
+
+ public double getZ() {
+ return z;
+ }
+
+ public void setZ(double z) {
+ this.z = z;
+ }
+
+ public float getYaw() {
+ return yaw;
+ }
+
+ public void setYaw(float yaw) {
+ this.yaw = yaw;
+ }
+
+ public float getPitch() {
+ return pitch;
+ }
+
+ public void setPitch(float pitch) {
+ this.pitch = pitch;
+ }
+
+ public int getEntityId() {
+ return entityId;
+ }
+
+ public UUID getUniqueId() {
+ return uuid;
+ }
+
+ public boolean isValid() {
+ return world.getEntities().contains(this);
+ }
+
+ @SuppressWarnings("deprecation")
+ public void remove() {
+ Limbo.getInstance().getUnsafe().removeEntity(world, this);
+ }
+
+ @SuppressWarnings("deprecation")
+ public DataWatcher getDataWatcher() {
+ return Limbo.getInstance().getUnsafe().getDataWatcher(world, this);
+ }
+
+}
diff --git a/src/main/java/com/loohp/limbo/Entity/EntityType.java b/src/main/java/com/loohp/limbo/Entity/EntityType.java
new file mode 100644
index 0000000..9066a38
--- /dev/null
+++ b/src/main/java/com/loohp/limbo/Entity/EntityType.java
@@ -0,0 +1,395 @@
+package com.loohp.limbo.Entity;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import com.loohp.limbo.Utils.NamespacedKey;
+import com.loohp.limbo.Player.Player;
+
+public enum EntityType {
+
+ // These strings MUST match the strings in nms.EntityTypes and are case sensitive.
+ /**
+ * An item resting on the ground.
+ *
+ * Spawn with {@link World#dropItem(Location, ItemStack)} or {@link
+ * World#dropItemNaturally(Location, ItemStack)}
+ */
+ //DROPPED_ITEM("item", Item.class, 1, false),
+ /**
+ * An experience orb.
+ */
+ //EXPERIENCE_ORB("experience_orb", ExperienceOrb.class, 2),
+ /**
+ * @see AreaEffectCloud
+ */
+ //AREA_EFFECT_CLOUD("area_effect_cloud", AreaEffectCloud.class, 3),
+ /**
+ * @see ElderGuardian
+ */
+ //ELDER_GUARDIAN("elder_guardian", ElderGuardian.class, 4),
+ /**
+ * @see WitherSkeleton
+ */
+ //WITHER_SKELETON("wither_skeleton", WitherSkeleton.class, 5),
+ /**
+ * @see Stray
+ */
+ //STRAY("stray", Stray.class, 6),
+ /**
+ * A flying chicken egg.
+ */
+ //EGG("egg", Egg.class, 7),
+ /**
+ * A leash attached to a fencepost.
+ */
+ //LEASH_HITCH("leash_knot", LeashHitch.class, 8),
+ /**
+ * A painting on a wall.
+ */
+ //PAINTING("painting", Painting.class, 9),
+ /**
+ * An arrow projectile; may get stuck in the ground.
+ */
+ //ARROW("arrow", Arrow.class, 10),
+ /**
+ * A flying snowball.
+ */
+ //SNOWBALL("snowball", Snowball.class, 11),
+ /**
+ * A flying large fireball, as thrown by a Ghast for example.
+ */
+ //FIREBALL("fireball", LargeFireball.class, 12),
+ /**
+ * A flying small fireball, such as thrown by a Blaze or player.
+ */
+ //SMALL_FIREBALL("small_fireball", SmallFireball.class, 13),
+ /**
+ * A flying ender pearl.
+ */
+ //ENDER_PEARL("ender_pearl", EnderPearl.class, 14),
+ /**
+ * An ender eye signal.
+ */
+ //ENDER_SIGNAL("eye_of_ender", EnderSignal.class, 15),
+ /**
+ * A flying splash potion.
+ */
+ //SPLASH_POTION("potion", ThrownPotion.class, 16, false),
+ /**
+ * A flying experience bottle.
+ */
+ //THROWN_EXP_BOTTLE("experience_bottle", ThrownExpBottle.class, 17),
+ /**
+ * An item frame on a wall.
+ */
+ //ITEM_FRAME("item_frame", ItemFrame.class, 18),
+ /**
+ * A flying wither skull projectile.
+ */
+ //WITHER_SKULL("wither_skull", WitherSkull.class, 19),
+ /**
+ * Primed TNT that is about to explode.
+ */
+ //PRIMED_TNT("tnt", TNTPrimed.class, 20),
+ /**
+ * A block that is going to or is about to fall.
+ */
+ //FALLING_BLOCK("falling_block", FallingBlock.class, 21, false),
+ /**
+ * Internal representation of a Firework once it has been launched.
+ */
+ //FIREWORK("firework_rocket", Firework.class, 22, false),
+ /**
+ * @see Husk
+ */
+ //HUSK("husk", Husk.class, 23),
+ /**
+ * Like {@link #ARROW} but causes the {@link PotionEffectType#GLOWING} effect on all team members.
+ */
+ //SPECTRAL_ARROW("spectral_arrow", SpectralArrow.class, 24),
+ /**
+ * Bullet fired by {@link #SHULKER}.
+ */
+ //SHULKER_BULLET("shulker_bullet", ShulkerBullet.class, 25),
+ /**
+ * Like {@link #FIREBALL} but with added effects.
+ */
+ //DRAGON_FIREBALL("dragon_fireball", DragonFireball.class, 26),
+ /**
+ * @see ZombieVillager
+ */
+ //ZOMBIE_VILLAGER("zombie_villager", ZombieVillager.class, 27),
+ /**
+ * @see SkeletonHorse
+ */
+ //SKELETON_HORSE("skeleton_horse", SkeletonHorse.class, 28),
+ /**
+ * @see ZombieHorse
+ */
+ //ZOMBIE_HORSE("zombie_horse", ZombieHorse.class, 29),
+ /**
+ * Mechanical entity with an inventory for placing weapons / armor into.
+ */
+ ARMOR_STAND("armor_stand", ArmorStand.class, 1),
+ /**
+ * @see Donkey
+ */
+ //DONKEY("donkey", Donkey.class, 31),
+ /**
+ * @see Mule
+ */
+ //MULE("mule", Mule.class, 32),
+ /**
+ * @see EvokerFangs
+ */
+ //EVOKER_FANGS("evoker_fangs", EvokerFangs.class, 33),
+ /**
+ * @see Evoker
+ */
+ //EVOKER("evoker", Evoker.class, 34),
+ /**
+ * @see Vex
+ */
+ //VEX("vex", Vex.class, 35),
+ /**
+ * @see Vindicator
+ */
+ //VINDICATOR("vindicator", Vindicator.class, 36),
+ /**
+ * @see Illusioner
+ */
+ //ILLUSIONER("illusioner", Illusioner.class, 37),
+ /**
+ * @see CommandMinecart
+ */
+ //MINECART_COMMAND("command_block_minecart", CommandMinecart.class, 40),
+ /**
+ * A placed boat.
+ */
+ //BOAT("boat", Boat.class, 41),
+ /**
+ * @see RideableMinecart
+ */
+ //MINECART("minecart", RideableMinecart.class, 42),
+ /**
+ * @see StorageMinecart
+ */
+ //MINECART_CHEST("chest_minecart", StorageMinecart.class, 43),
+ /**
+ * @see PoweredMinecart
+ */
+ //MINECART_FURNACE("furnace_minecart", PoweredMinecart.class, 44),
+ /**
+ * @see ExplosiveMinecart
+ */
+ //MINECART_TNT("tnt_minecart", ExplosiveMinecart.class, 45),
+ /**
+ * @see HopperMinecart
+ */
+ //MINECART_HOPPER("hopper_minecart", HopperMinecart.class, 46),
+ /**
+ * @see SpawnerMinecart
+ */
+ //MINECART_MOB_SPAWNER("spawner_minecart", SpawnerMinecart.class, 47),
+ //CREEPER("creeper", Creeper.class, 50),
+ //SKELETON("skeleton", Skeleton.class, 51),
+ //SPIDER("spider", Spider.class, 52),
+ //GIANT("giant", Giant.class, 53),
+ //ZOMBIE("zombie", Zombie.class, 54),
+ //SLIME("slime", Slime.class, 55),
+ //GHAST("ghast", Ghast.class, 56),
+ //ZOMBIFIED_PIGLIN("zombified_piglin", PigZombie.class, 57),
+ //ENDERMAN("enderman", Enderman.class, 58),
+ //CAVE_SPIDER("cave_spider", CaveSpider.class, 59),
+ //SILVERFISH("silverfish", Silverfish.class, 60),
+ //BLAZE("blaze", Blaze.class, 61),
+ //MAGMA_CUBE("magma_cube", MagmaCube.class, 62),
+ //ENDER_DRAGON("ender_dragon", EnderDragon.class, 63),
+ //WITHER("wither", Wither.class, 64),
+ //BAT("bat", Bat.class, 65),
+ //WITCH("witch", Witch.class, 66),
+ //ENDERMITE("endermite", Endermite.class, 67),
+ //GUARDIAN("guardian", Guardian.class, 68),
+ //SHULKER("shulker", Shulker.class, 69),
+ //PIG("pig", Pig.class, 90),
+ //SHEEP("sheep", Sheep.class, 91),
+ //COW("cow", Cow.class, 92),
+ //CHICKEN("chicken", Chicken.class, 93),
+ //SQUID("squid", Squid.class, 94),
+ //WOLF("wolf", Wolf.class, 95),
+ //MUSHROOM_COW("mooshroom", MushroomCow.class, 96),
+ //SNOWMAN("snow_golem", Snowman.class, 97),
+ //OCELOT("ocelot", Ocelot.class, 98),
+ //IRON_GOLEM("iron_golem", IronGolem.class, 99),
+ //HORSE("horse", Horse.class, 100),
+ //RABBIT("rabbit", Rabbit.class, 101),
+ //POLAR_BEAR("polar_bear", PolarBear.class, 102),
+ //LLAMA("llama", Llama.class, 103),
+ //LLAMA_SPIT("llama_spit", LlamaSpit.class, 104),
+ //PARROT("parrot", Parrot.class, 105),
+ //VILLAGER("villager", Villager.class, 120),
+ //ENDER_CRYSTAL("end_crystal", EnderCrystal.class, 200),
+ //TURTLE("turtle", Turtle.class, -1),
+ //PHANTOM("phantom", Phantom.class, -1),
+ //TRIDENT("trident", Trident.class, -1),
+ //COD("cod", Cod.class, -1),
+ //SALMON("salmon", Salmon.class, -1),
+ //PUFFERFISH("pufferfish", PufferFish.class, -1),
+ //TROPICAL_FISH("tropical_fish", TropicalFish.class, -1),
+ //DROWNED("drowned", Drowned.class, -1),
+ //DOLPHIN("dolphin", Dolphin.class, -1),
+ //CAT("cat", Cat.class, -1),
+ //PANDA("panda", Panda.class, -1),
+ //PILLAGER("pillager", Pillager.class, -1),
+ //RAVAGER("ravager", Ravager.class, -1),
+ //TRADER_LLAMA("trader_llama", TraderLlama.class, -1),
+ //WANDERING_TRADER("wandering_trader", WanderingTrader.class, -1),
+ //FOX("fox", Fox.class, -1),
+ //BEE("bee", Bee.class, -1),
+ //HOGLIN("hoglin", Hoglin.class, -1),
+ //PIGLIN("piglin", Piglin.class, -1),
+ //STRIDER("strider", Strider.class, -1),
+ //ZOGLIN("zoglin", Zoglin.class, -1),
+ //PIGLIN_BRUTE("piglin_brute", PiglinBrute.class, -1),
+ /**
+ * A fishing line and bobber.
+ */
+ //FISHING_HOOK("fishing_bobber", FishHook.class, -1, false),
+ /**
+ * A bolt of lightning.
+ *
+ * Spawn with {@link World#strikeLightning(Location)}.
+ */
+ //LIGHTNING("lightning_bolt", LightningStrike.class, -1, false),
+ PLAYER("player", Player.class, 106, false),
+ /**
+ * An unknown entity without an Entity Class
+ */
+ UNKNOWN(null, null, -1, false);
+
+ private final String name;
+ private final Class extends Entity> clazz;
+ private final short typeId;
+ private final boolean independent;
+ private final boolean living;
+ private final NamespacedKey key;
+
+ private static final Map NAME_MAP = new HashMap<>();
+ private static final Map ID_MAP = new HashMap<>();
+
+ static {
+ for (EntityType type : values()) {
+ if (type.name != null) {
+ NAME_MAP.put(type.name.toLowerCase(java.util.Locale.ENGLISH), type);
+ }
+ if (type.typeId > 0) {
+ ID_MAP.put(type.typeId, type);
+ }
+ }
+
+ // Add legacy names
+ /*
+ NAME_MAP.put("xp_orb", EXPERIENCE_ORB);
+ NAME_MAP.put("eye_of_ender_signal", ENDER_SIGNAL);
+ NAME_MAP.put("xp_bottle", THROWN_EXP_BOTTLE);
+ NAME_MAP.put("fireworks_rocket", FIREWORK);
+ NAME_MAP.put("evocation_fangs", EVOKER_FANGS);
+ NAME_MAP.put("evocation_illager", EVOKER);
+ NAME_MAP.put("vindication_illager", VINDICATOR);
+ NAME_MAP.put("illusion_illager", ILLUSIONER);
+ NAME_MAP.put("commandblock_minecart", MINECART_COMMAND);
+ NAME_MAP.put("snowman", SNOWMAN);
+ NAME_MAP.put("villager_golem", IRON_GOLEM);
+ NAME_MAP.put("ender_crystal", ENDER_CRYSTAL);
+ NAME_MAP.put("zombie_pigman", ZOMBIFIED_PIGLIN);
+ */
+ }
+
+ private EntityType(String name, Class extends Entity> clazz, int typeId) {
+ this(name, clazz, typeId, true);
+ }
+
+ private EntityType(String name, Class extends Entity> clazz, int typeId, boolean independent) {
+ this.name = name;
+ this.clazz = clazz;
+ this.typeId = (short) typeId;
+ this.independent = independent;
+ this.living = clazz != null && LivingEntity.class.isAssignableFrom(clazz);
+ this.key = (name == null) ? null : NamespacedKey.minecraft(name);
+ }
+
+ /**
+ * Gets the entity type name.
+ *
+ * @return the entity type's name
+ * @deprecated Magic value
+ */
+ @Deprecated
+ public String getName() {
+ return name;
+ }
+
+ public NamespacedKey getKey() {
+ return key;
+ }
+
+ public Class extends Entity> getEntityClass() {
+ return clazz;
+ }
+
+ /**
+ * Gets the entity network type id.
+ *
+ * @return the network type id
+ */
+ public short getTypeId() {
+ return typeId;
+ }
+
+ /**
+ * Gets an entity type from its name.
+ *
+ * @param name the entity type's name
+ * @return the matching entity type or null
+ * @deprecated Magic value
+ */
+ @Deprecated
+ public static EntityType fromName(String name) {
+ if (name == null) {
+ return null;
+ }
+ return NAME_MAP.get(name.toLowerCase(java.util.Locale.ENGLISH));
+ }
+
+ /**
+ * Gets an entity from its id.
+ *
+ * @param id the raw type id
+ * @return the matching entity type or null
+ * @deprecated Magic value
+ */
+ @Deprecated
+ public static EntityType fromId(int id) {
+ if (id > Short.MAX_VALUE) {
+ return null;
+ }
+ return ID_MAP.get((short) id);
+ }
+
+ /**
+ * Some entities cannot be spawned using {@link
+ * World#spawnEntity(Location, EntityType)} or {@link
+ * World#spawn(Location, Class)}, usually because they require additional
+ * information in order to spawn.
+ *
+ * @return False if the entity type cannot be spawned
+ */
+ public boolean isSpawnable() {
+ return independent;
+ }
+
+ public boolean isAlive() {
+ return living;
+ }
+}
diff --git a/src/main/java/com/loohp/limbo/Entity/LivingEntity.java b/src/main/java/com/loohp/limbo/Entity/LivingEntity.java
new file mode 100644
index 0000000..223e1bf
--- /dev/null
+++ b/src/main/java/com/loohp/limbo/Entity/LivingEntity.java
@@ -0,0 +1,132 @@
+package com.loohp.limbo.Entity;
+
+import java.util.UUID;
+
+import com.loohp.limbo.Limbo;
+import com.loohp.limbo.Entity.DataWatcher.WatchableField;
+import com.loohp.limbo.Entity.DataWatcher.WatchableObjectType;
+import com.loohp.limbo.Inventory.EquipmentSlot;
+import com.loohp.limbo.Location.Location;
+import com.loohp.limbo.World.BlockPosition;
+import com.loohp.limbo.World.World;
+
+public abstract class LivingEntity extends Entity {
+
+ @WatchableField(MetadataIndex = 7, WatchableObjectType = WatchableObjectType.BYTE, IsBitmask = true, Bitmask = 0x01)
+ protected boolean handActive = false;
+ @WatchableField(MetadataIndex = 7, WatchableObjectType = WatchableObjectType.BYTE, IsBitmask = true, Bitmask = 0x02)
+ protected boolean activeHand = false; //false = main hand, true = off hand
+ @WatchableField(MetadataIndex = 7, WatchableObjectType = WatchableObjectType.BYTE, IsBitmask = true, Bitmask = 0x04)
+ protected boolean inRiptideSpinAttack = false;
+ @WatchableField(MetadataIndex = 8, WatchableObjectType = WatchableObjectType.FLOAT)
+ protected float health = 1.0F;
+ @WatchableField(MetadataIndex = 9, WatchableObjectType = WatchableObjectType.VARINT)
+ protected int potionEffectColor = 0;
+ @WatchableField(MetadataIndex = 10, WatchableObjectType = WatchableObjectType.BOOLEAN)
+ protected boolean potionEffectAmbient = false;
+ @WatchableField(MetadataIndex = 11, WatchableObjectType = WatchableObjectType.VARINT)
+ protected int arrowsInEntity = 0;
+ @WatchableField(MetadataIndex = 12, WatchableObjectType = WatchableObjectType.VARINT)
+ protected int absorption = 0;
+ @WatchableField(MetadataIndex = 13, WatchableObjectType = WatchableObjectType.POSITION, IsOptional = true)
+ protected BlockPosition sleepingLocation = null;
+
+ public LivingEntity(EntityType type, int entityId, UUID uuid, World world, double x, double y, double z, float yaw, float pitch) {
+ super(type, entityId, uuid, world, x, y, z, yaw, pitch);
+ }
+
+ public LivingEntity(EntityType type, UUID uuid, World world, double x, double y, double z, float yaw, float pitch) {
+ this(type, Limbo.getInstance().getNextEntityId(), uuid, world, x, y, z, yaw, pitch);
+ }
+
+ public LivingEntity(EntityType type, World world, double x, double y, double z, float yaw, float pitch) {
+ this(type, Limbo.getInstance().getNextEntityId(), UUID.randomUUID(), world, x, y, z, yaw, pitch);
+ }
+
+ public LivingEntity(EntityType type, UUID uuid, Location location) {
+ this(type, Limbo.getInstance().getNextEntityId(), uuid, location.getWorld(), location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch());
+ }
+
+ public LivingEntity(EntityType type, Location location) {
+ this(type, Limbo.getInstance().getNextEntityId(), UUID.randomUUID(), location.getWorld(), location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch());
+ }
+
+ public boolean isHandActive() {
+ return handActive;
+ }
+
+ public void setHandActive(boolean handActive) {
+ this.handActive = handActive;
+ }
+
+ public EquipmentSlot getActiveHand() {
+ return activeHand ? EquipmentSlot.OFFHAND : EquipmentSlot.MAINHAND;
+ }
+
+ public void setActiveHand(EquipmentSlot activeHand) {
+ if (activeHand.equals(EquipmentSlot.MAINHAND)) {
+ this.activeHand = false;
+ } else if (activeHand.equals(EquipmentSlot.OFFHAND)) {
+ this.activeHand = true;
+ } else {
+ throw new IllegalArgumentException("Invalid EquipmentSlot " + activeHand.toString());
+ }
+ }
+
+ public boolean isInRiptideSpinAttack() {
+ return inRiptideSpinAttack;
+ }
+
+ public void setInRiptideSpinAttack(boolean inRiptideSpinAttack) {
+ this.inRiptideSpinAttack = inRiptideSpinAttack;
+ }
+
+ public float getHealth() {
+ return health;
+ }
+
+ public void setHealth(float health) {
+ this.health = health;
+ }
+
+ public int getPotionEffectColor() {
+ return potionEffectColor;
+ }
+
+ public void setPotionEffectColor(int potionEffectColor) {
+ this.potionEffectColor = potionEffectColor;
+ }
+
+ public boolean isPotionEffectAmbient() {
+ return potionEffectAmbient;
+ }
+
+ public void setPotionEffectAmbient(boolean potionEffectAmbient) {
+ this.potionEffectAmbient = potionEffectAmbient;
+ }
+
+ public int getArrowsInEntity() {
+ return arrowsInEntity;
+ }
+
+ public void setArrowsInEntity(int arrowsInEntity) {
+ this.arrowsInEntity = arrowsInEntity;
+ }
+
+ public int getAbsorption() {
+ return absorption;
+ }
+
+ public void setAbsorption(int absorption) {
+ this.absorption = absorption;
+ }
+
+ public BlockPosition getSleepingLocation() {
+ return sleepingLocation;
+ }
+
+ public void setSleepingLocation(BlockPosition sleepingLocation) {
+ this.sleepingLocation = sleepingLocation;
+ }
+
+}
diff --git a/src/main/java/com/loohp/limbo/Entity/Pose.java b/src/main/java/com/loohp/limbo/Entity/Pose.java
new file mode 100644
index 0000000..ca125b8
--- /dev/null
+++ b/src/main/java/com/loohp/limbo/Entity/Pose.java
@@ -0,0 +1,34 @@
+package com.loohp.limbo.Entity;
+
+public enum Pose {
+
+ STANDING(0),
+ FALL_FLYING(1),
+ SLEEPING(2),
+ SWIMMING(3),
+ SPIN_ATTACK(4),
+ SNEAKING(5),
+ DYING(6);
+
+ private static final Pose[] VALUES = values();
+
+ private int id;
+
+ Pose(int id) {
+ this.id = id;
+ }
+
+ public int getId() {
+ return id;
+ }
+
+ public static Pose fromId(int id) {
+ for (Pose pose : VALUES) {
+ if (id == pose.id) {
+ return pose;
+ }
+ }
+ return null;
+ }
+
+}
diff --git a/src/main/java/com/loohp/limbo/File/FileConfiguration.java b/src/main/java/com/loohp/limbo/File/FileConfiguration.java
index b27435d..56a13b4 100644
--- a/src/main/java/com/loohp/limbo/File/FileConfiguration.java
+++ b/src/main/java/com/loohp/limbo/File/FileConfiguration.java
@@ -3,9 +3,12 @@ package com.loohp.limbo.File;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
+import java.io.IOException;
import java.io.InputStream;
+import java.io.InputStreamReader;
import java.io.PrintWriter;
-import java.io.UnsupportedEncodingException;
+import java.io.Reader;
+import java.io.StringWriter;
import java.nio.charset.StandardCharsets;
import java.util.LinkedHashMap;
import java.util.Map;
@@ -18,32 +21,36 @@ import com.loohp.limbo.Utils.YamlOrder;
public class FileConfiguration {
- File file;
-
- Map mapping;
- String header;
+ private Map mapping;
+ private String header;
public FileConfiguration(File file) throws FileNotFoundException {
- this.file = file;
if (file.exists()) {
- reloadConfig();
+ reloadConfig(new InputStreamReader(new FileInputStream(file), StandardCharsets.UTF_8));
} else {
mapping = new LinkedHashMap<>();
}
}
- @Deprecated
public FileConfiguration(InputStream input){
- reloadConfig(input);
+ reloadConfig(new InputStreamReader(input, StandardCharsets.UTF_8));
}
- public FileConfiguration reloadConfig() throws FileNotFoundException {
- return reloadConfig(new FileInputStream(file));
+ public FileConfiguration(Reader reader){
+ reloadConfig(reader);
}
- private FileConfiguration reloadConfig(InputStream input) {
+ public FileConfiguration reloadConfig(File file) throws FileNotFoundException {
+ return reloadConfig(new InputStreamReader(new FileInputStream(file), StandardCharsets.UTF_8));
+ }
+
+ public FileConfiguration reloadConfig(InputStream input) {
+ return reloadConfig(new InputStreamReader(input, StandardCharsets.UTF_8));
+ }
+
+ public FileConfiguration reloadConfig(Reader reader) {
Yaml yml = new Yaml();
- mapping = yml.load(input);
+ mapping = yml.load(reader);
return this;
}
@@ -87,7 +94,29 @@ public class FileConfiguration {
}
}
- public void saveConfig(File file) throws FileNotFoundException, UnsupportedEncodingException {
+ public String saveToString() throws IOException {
+ DumperOptions options = new DumperOptions();
+ options.setIndent(2);
+ options.setPrettyFlow(true);
+ options.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK);
+ Representer customRepresenter = new Representer();
+ YamlOrder customProperty = new YamlOrder();
+ customRepresenter.setPropertyUtils(customProperty);
+ Yaml yaml = new Yaml(customRepresenter, options);
+
+ StringWriter writer = new StringWriter();
+ PrintWriter pw = new PrintWriter(writer);
+ if (header != null) {
+ pw.println("#" + header.replace("\n", "\n#"));
+ }
+ yaml.dump(mapping, pw);
+ pw.flush();
+ pw.close();
+
+ return writer.toString();
+ }
+
+ public void saveConfig(File file) throws IOException {
DumperOptions options = new DumperOptions();
options.setIndent(2);
options.setPrettyFlow(true);
diff --git a/src/main/java/com/loohp/limbo/File/ServerProperties.java b/src/main/java/com/loohp/limbo/File/ServerProperties.java
index dc80abf..4f3fee8 100644
--- a/src/main/java/com/loohp/limbo/File/ServerProperties.java
+++ b/src/main/java/com/loohp/limbo/File/ServerProperties.java
@@ -4,6 +4,10 @@ import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.PrintWriter;
+import java.nio.charset.StandardCharsets;
+import java.util.Map.Entry;
import java.util.Optional;
import java.util.Properties;
@@ -16,29 +20,44 @@ import com.loohp.limbo.Utils.NamespacedKey;
import com.loohp.limbo.World.World;
public class ServerProperties {
+
+ public static final String COMMENT = "For explaination of what each of the options does, please visit:\nhttps://github.com/LOOHP/Limbo/blob/master/src/main/resources/server.properties";
- File file;
- int maxPlayers;
- int serverPort;
- String serverIp;
- NamespacedKey levelName;
- String schemFileName;
- NamespacedKey levelDimension;
- GameMode defaultGamemode;
- Location worldSpawn;
- boolean reducedDebugInfo;
- boolean allowFlight;
- String motdJson;
- String versionString;
- int protocol;
- boolean bungeecord;
+ private File file;
+ private int maxPlayers;
+ private int serverPort;
+ private String serverIp;
+ private NamespacedKey levelName;
+ private String schemFileName;
+ private NamespacedKey levelDimension;
+ private GameMode defaultGamemode;
+ private Location worldSpawn;
+ private boolean reducedDebugInfo;
+ private boolean allowFlight;
+ private String motdJson;
+ private String versionString;
+ private int protocol;
+ private boolean bungeecord;
+ private int viewDistance;
+ private double ticksPerSecond;
Optional favicon;
public ServerProperties(File file) throws IOException {
this.file = file;
+
+ Properties def = new Properties();
+ def.load(new InputStreamReader(getClass().getClassLoader().getResourceAsStream("server.properties"), StandardCharsets.UTF_8));
+
Properties prop = new Properties();
- prop.load(new FileInputStream(file));
+ prop.load(new InputStreamReader(new FileInputStream(file), StandardCharsets.UTF_8));
+
+ for (Entry