From d496d4958e544e7f1e1c3f4984f23c13aefa94a8 Mon Sep 17 00:00:00 2001
From: RednedEpic <redned@retronixgames.x10host.com>
Date: Fri, 2 Aug 2019 22:38:09 -0500
Subject: [PATCH 01/10] Start work on entity translations

---
 .../org/geysermc/connector/entity/Entity.java | 135 +++++++++++++++
 .../connector/entity/PlayerEntity.java        |  96 +++++++++++
 .../connector/entity/type/EntityType.java     | 160 ++++++++++++++++++
 .../network/session/GeyserSession.java        |  13 +-
 .../network/session/cache/EntityCache.java    |  72 ++++++++
 .../geysermc/connector/utils/EntityUtils.java |  23 +++
 6 files changed, 498 insertions(+), 1 deletion(-)
 create mode 100644 connector/src/main/java/org/geysermc/connector/entity/Entity.java
 create mode 100644 connector/src/main/java/org/geysermc/connector/entity/PlayerEntity.java
 create mode 100644 connector/src/main/java/org/geysermc/connector/entity/type/EntityType.java
 create mode 100644 connector/src/main/java/org/geysermc/connector/network/session/cache/EntityCache.java
 create mode 100644 connector/src/main/java/org/geysermc/connector/utils/EntityUtils.java

diff --git a/connector/src/main/java/org/geysermc/connector/entity/Entity.java b/connector/src/main/java/org/geysermc/connector/entity/Entity.java
new file mode 100644
index 000000000..66d50fd3a
--- /dev/null
+++ b/connector/src/main/java/org/geysermc/connector/entity/Entity.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright (c) 2019 GeyserMC. http://geysermc.org
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * @author GeyserMC
+ * @link https://github.com/GeyserMC/Geyser
+ */
+
+package org.geysermc.connector.entity;
+
+import com.flowpowered.math.vector.Vector3f;
+import com.nukkitx.protocol.bedrock.data.Attribute;
+import com.nukkitx.protocol.bedrock.data.EntityData;
+import com.nukkitx.protocol.bedrock.data.EntityDataDictionary;
+import com.nukkitx.protocol.bedrock.packet.AddEntityPacket;
+import com.nukkitx.protocol.bedrock.packet.RemoveEntityPacket;
+import lombok.Getter;
+import lombok.Setter;
+import org.geysermc.connector.entity.type.EntityType;
+import org.geysermc.connector.network.session.GeyserSession;
+
+import java.util.HashMap;
+import java.util.Map;
+
+@Getter
+@Setter
+public class Entity {
+
+    protected long entityId;
+    protected long geyserId;
+
+    protected int dimension;
+
+    protected Vector3f position;
+    protected Vector3f motion;
+    protected Vector3f rotation;
+
+    protected int scale = 1;
+    protected float yaw;
+    protected float pitch;
+    protected boolean shouldMove;
+
+    protected EntityType entityType;
+
+    protected boolean valid;
+
+    protected Map<Integer, Attribute> attributes = new HashMap<Integer, Attribute>();
+
+    public Entity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
+        this.entityId = entityId;
+        this.geyserId = geyserId;
+        this.entityType = entityType;
+        this.position = position;
+        this.motion = motion;
+        this.rotation = rotation;
+
+        this.valid = false;
+        this.shouldMove = false;
+    }
+
+    public void spawnEntity(GeyserSession session) {
+        AddEntityPacket addEntityPacket = new AddEntityPacket();
+        addEntityPacket.setRuntimeEntityId(geyserId);
+        addEntityPacket.setUniqueEntityId(entityId);
+        addEntityPacket.setPosition(position);
+        addEntityPacket.setMotion(motion);
+        addEntityPacket.setRotation(rotation);
+        addEntityPacket.setEntityType(entityType.getType());
+
+        session.getUpstream().sendPacket(addEntityPacket);
+        valid = true;
+    }
+
+    public void despawnEntity(GeyserSession session) {
+        if (!valid)
+            return;
+
+        RemoveEntityPacket removeEntityPacket = new RemoveEntityPacket();
+        removeEntityPacket.setUniqueEntityId(entityId);
+        session.getUpstream().sendPacket(removeEntityPacket);
+    }
+
+    public void moveRelative(double relX, double relY, double relZ, float pitch, float yaw) {
+        if (relX == 0 && relY != 0 && relZ != 0 && yaw != 0 && pitch != 0)
+            return;
+
+        if (pitch != 0)
+            this.pitch = pitch;
+
+        if (yaw != 0)
+            this.yaw = yaw;
+
+        this.position = new Vector3f(position.getX() + relX, position.getX() + relY, position.getX() + relZ);
+        this.shouldMove = true;
+    }
+
+    public void moveAbsolute(Vector3f position, float pitch, float yaw) {
+        if (position.getX() == 0 && position.getX() != 0 && position.getX() != 0 && yaw != 0 && pitch != 0)
+            return;
+
+        this.position = position;
+        this.pitch = pitch;
+        this.yaw = yaw;
+        this.shouldMove = true;
+    }
+
+    protected EntityDataDictionary getMetadata() {
+        EntityDataDictionary dictionary = new EntityDataDictionary();
+        dictionary.put(EntityData.NAMETAG, "");
+        dictionary.put(EntityData.ENTITY_AGE, 0);
+        dictionary.put(EntityData.SCALE, 1f);
+        dictionary.put(EntityData.MAX_AIR, (short) 400);
+        dictionary.put(EntityData.AIR, (short) 0);
+        dictionary.put(EntityData.BOUNDING_BOX_HEIGHT, entityType.getHeight());
+        dictionary.put(EntityData.BOUNDING_BOX_WIDTH, entityType.getWidth());
+        return dictionary;
+    }
+}
diff --git a/connector/src/main/java/org/geysermc/connector/entity/PlayerEntity.java b/connector/src/main/java/org/geysermc/connector/entity/PlayerEntity.java
new file mode 100644
index 000000000..8797d20c3
--- /dev/null
+++ b/connector/src/main/java/org/geysermc/connector/entity/PlayerEntity.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2019 GeyserMC. http://geysermc.org
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * @author GeyserMC
+ * @link https://github.com/GeyserMC/Geyser
+ */
+
+package org.geysermc.connector.entity;
+
+import com.flowpowered.math.vector.Vector3f;
+import com.github.steveice10.mc.protocol.data.game.PlayerListEntry;
+import com.nukkitx.protocol.bedrock.data.EntityData;
+import com.nukkitx.protocol.bedrock.data.EntityDataDictionary;
+import com.nukkitx.protocol.bedrock.data.ItemData;
+import com.nukkitx.protocol.bedrock.packet.AddPlayerPacket;
+import com.nukkitx.protocol.bedrock.packet.MobArmorEquipmentPacket;
+import lombok.Getter;
+import lombok.Setter;
+import org.geysermc.connector.entity.type.EntityType;
+import org.geysermc.connector.network.session.GeyserSession;
+
+@Getter
+@Setter
+public class PlayerEntity extends Entity {
+
+    // This is the session linked to the player entity, can be null
+    private GeyserSession session;
+
+    private ItemData hand;
+
+    private ItemData helmet;
+    private ItemData chestplate;
+    private ItemData leggings;
+    private ItemData boots;
+
+    public PlayerEntity(GeyserSession session, long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
+        super(entityId, geyserId, entityType, position, motion, rotation);
+
+        this.session = session;
+    }
+
+    // TODO: Break this into an EquippableEntity class
+    public void updateEquipment(GeyserSession session) {
+        if (hand != null && helmet != null && chestplate != null && leggings != null )
+            return;
+
+        MobArmorEquipmentPacket armorEquipmentPacket = new MobArmorEquipmentPacket();
+        armorEquipmentPacket.setRuntimeEntityId(geyserId);
+        armorEquipmentPacket.setHelmet(helmet);
+        armorEquipmentPacket.setChestplate(chestplate);
+        armorEquipmentPacket.setLeggings(leggings);
+        armorEquipmentPacket.setBoots(boots);
+
+        session.getUpstream().sendPacket(armorEquipmentPacket);
+    }
+
+    @Override
+    public void spawnEntity(GeyserSession session) {
+        AddPlayerPacket addPlayerPacket = new AddPlayerPacket();
+        addPlayerPacket.setUniqueEntityId(geyserId);
+        addPlayerPacket.setUniqueEntityId(entityId);
+        addPlayerPacket.setUuid(this.session.getAuthenticationData().getUUID());
+        addPlayerPacket.setUsername(this.session.getAuthenticationData().getName());
+        addPlayerPacket.setPlatformChatId("");
+        addPlayerPacket.setPosition(position);
+        addPlayerPacket.setMotion(motion);
+        addPlayerPacket.setRotation(rotation);
+        addPlayerPacket.setHand(hand);
+        addPlayerPacket.getMetadata().putAll(getMetadata());
+        addPlayerPacket.setPlayerFlags(0);
+        addPlayerPacket.setCommandPermission(0);
+        addPlayerPacket.setWorldFlags(0);
+        addPlayerPacket.setPlayerPermission(0);
+        addPlayerPacket.setCustomFlags(0);
+        addPlayerPacket.setDeviceId("WIN10"); // TODO: Find this value
+        session.getUpstream().sendPacket(addPlayerPacket);
+    }
+}
diff --git a/connector/src/main/java/org/geysermc/connector/entity/type/EntityType.java b/connector/src/main/java/org/geysermc/connector/entity/type/EntityType.java
new file mode 100644
index 000000000..5525fb0e9
--- /dev/null
+++ b/connector/src/main/java/org/geysermc/connector/entity/type/EntityType.java
@@ -0,0 +1,160 @@
+/*
+ * Copyright (c) 2019 GeyserMC. http://geysermc.org
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * @author GeyserMC
+ * @link https://github.com/GeyserMC/Geyser
+ */
+
+package org.geysermc.connector.entity.type;
+
+import lombok.Getter;
+
+@Getter
+public enum EntityType {
+
+    CHICKEN(10, 0.7f, 0.4f),
+    COW(11, 1.4f, 0.9f),
+    PIG(12, 0.9f),
+    SHEEP(13, 1.3f, 0.9f),
+    WOLF(14, 0.85f, 0.6f),
+    VILLAGER(15, 1.8f, 0.6f, 0.6f, 1.62f),
+    MOOSHROOM(16, 1.4f, 0.9f),
+    SQUID(17, 0.8f),
+    RABBIT(18, 0.5f, 0.4f),
+    BAT(19, 0.9f, 0.5f),
+    IRON_GOLEM(20, 2.7f, 1.4f),
+    SNOW_GOLEM(21, 1.9f, 0.7f),
+    OCELOT(22, 0.35f, 0.3f),
+    HORSE(23, 1.6f, 1.3965f),
+    DONKEY(24, 1.6f, 1.3965f),
+    MULE(25, 1.6f, 1.3965f),
+    SKELETON_HORSE(26, 1.6f, 1.3965f),
+    ZOMBIE_HORSE(27, 1.6f, 1.3965f),
+    POLAR_BEAR(28, 1.4f, 1.3f),
+    LLAMA(29, 1.87f, 0.9f),
+    PARROT(30, 0.9f, 0.5f),
+    DOLPHIN(31, 0f), //TODO
+    ZOMBIE(32, 1.8f, 0.6f, 0.6f, 1.62f),
+    CREEPER(33, 1.7f, 0.6f, 0.6f, 1.62f),
+    SKELETON(34, 1.8f, 0.6f, 0.6f, 1.62f),
+    SPIDER(35, 0.9f, 1.4f, 1.4f, 1f),
+    ZOMBIE_PIGMAN(36, 1.8f, 0.6f, 0.6f, 1.62f),
+    SLIME(37, 0.51f),
+    ENDERMAN(38, 2.9f, 0.6f),
+    SILVERFISH(39, 0.3f, 0.4f),
+    CAVE_SPIDER(40, 0.5f, 0.7f),
+    GHAST(41, 4.0f),
+    MAGMA_CUBE(42, 0.51f),
+    BLAZE(43, 1.8f, 0.6f),
+    ZOMBIE_VILLAGER(44, 1.8f, 0.6f, 0.6f, 1.62f),
+    WITCH(45, 1.8f, 0.6f, 0.6f, 1.62f),
+    STRAY(46, 1.8f, 0.6f, 0.6f, 1.62f),
+    HUSK(47, 1.8f, 0.6f, 0.6f, 1.62f),
+    WITHER_SKELETON(48, 2.4f, 0.7f),
+    GUARDIAN(49, 0.85f),
+    ELDER_GUARDIAN(50, 1.9975f),
+    NPC(51, 1.8f, 0.6f, 0.6f, 1.62f),
+    WITHER(52, 3.5f, 0.9f),
+    ENDER_DRAGON(53, 4f, 13f),
+    SHULKER(54, 1f, 1f),
+    ENDERMITE(55, 0.3f, 0.4f),
+    AGENT(56, 0f),
+    VINDICATOR(57, 1.8f, 0.6f, 0.6f, 1.62f),
+    PILLAGER(114, 1.8f, 0.6f, 0.6f, 1.62f),
+    WANDERING_VILLAGER(118, 1.8f, 0.6f, 0.6f, 1.62f),
+    RAVAGER(59, 1.9f, 1.2f),
+
+    ARMOR_STAND(61, 0f),
+    TRIPOD_CAMERA(62, 0f),
+    PLAYER(63, 1.8f, 0.6f, 0.6f, 1.62f),
+    ITEM(64, 0.25f, 0.25f),
+    PRIMED_TNT(65, 0.98f, 0.98f),
+    FALLING_BLOCK(66, 0.98f, 0.98f),
+    MOVING_BLOCK(67, 0f),
+    EXPERIENCE_BOTTLE(68, 0.25f, 0.25f),
+    EXPERIENCE_ORB(69, 0f),
+    EYE_OF_ENDER(70, 0f),
+    ENDER_CRYSTAL(71, 0f),
+    FIREWORK_ROCKET(72, 0f),
+    TRIDENT(73, 0f),
+
+    SHULKER_BULLET(76, 0f),
+    FISHING_HOOK(77, 0f),
+    CHALKBOARD(78, 0f),
+    DRAGON_FIREBALL(79, 0f),
+    ARROW(80, 0.25f, 0.25f),
+    SNOWBALL(81, 0f),
+    EGG(82, 0f),
+    PAINTING(83, 0f),
+    MINECART(84, 0f),
+    LARGE_FIREBALL(85, 0f),
+    SPLASH_POTION(86, 0f),
+    ENDER_PEARL(87, 0f),
+    LEASH_KNOT(88, 0f),
+    WITHER_SKULL(89, 0f),
+    BOAT(90, 0.7f, 1.6f, 1.6f, 0.35f),
+    WITHER_SKULL_DANGEROUS(91, 0f),
+    LIGHTNING_BOLT(93, 0f),
+    SMALL_FIREBALL(94, 0f),
+    AREA_EFFECT_CLOUD(95, 0f),
+    HOPPER_MINECART(96, 0f),
+    TNT_MINECART(97, 0f),
+    CHEST_MINECART(98, 0f),
+
+    COMMAND_BLOCK_MINECART(100, 0f),
+    LINGERING_POTION(101, 0f),
+    LLAMA_SPIT(102, 0f),
+    EVOKER_FANGS(103, 0f),
+    EVOKER(104, 0f),
+    VEX(105, 0f),
+    ICE_BOMB(106, 0f),
+    BALLOON(107, 0f), //TODO
+    PUFFERFISH(108, 0.7f, 0.7f),
+    SALMON(109, 0.5f, 0.7f),
+    TROPICAL_FISH(111, 0.6f, 0.6f),
+    COD(112, 0.25f, 0.5f);
+
+    private final int type;
+    private final float height;
+    private final float width;
+    private final float length;
+    private final float offset;
+
+    EntityType(int type, float height) {
+        this(type, height, 0f);
+    }
+
+    EntityType(int type, float height, float width) {
+        this(type, height, width, width);
+    }
+
+    EntityType(int type, float height, float width, float length) {
+        this(type, height, width, length, 0f);
+    }
+
+    EntityType(int type, float height, float width, float length, float offset) {
+        this.type = type;
+        this.height = height;
+        this.width = width;
+        this.length = length;
+        this.offset = offset + 0.00001f;
+    }
+}
diff --git a/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java b/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java
index b7ca7a2f5..fbc11cb97 100644
--- a/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java
+++ b/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java
@@ -50,6 +50,9 @@ import org.geysermc.api.RemoteServer;
 import org.geysermc.api.session.AuthData;
 import org.geysermc.api.window.FormWindow;
 import org.geysermc.connector.GeyserConnector;
+import org.geysermc.connector.entity.PlayerEntity;
+import org.geysermc.connector.entity.type.EntityType;
+import org.geysermc.connector.network.session.cache.EntityCache;
 import org.geysermc.connector.network.session.cache.InventoryCache;
 import org.geysermc.connector.network.session.cache.ScoreboardCache;
 import org.geysermc.connector.network.session.cache.WindowCache;
@@ -72,6 +75,12 @@ public class GeyserSession implements PlayerSession, Player {
     @Getter
     private AuthData authenticationData;
 
+    @Getter
+    private PlayerEntity playerEntity;
+
+    @Getter
+    private EntityCache entityCache;
+
     @Getter
     private InventoryCache inventoryCache;
 
@@ -90,9 +99,11 @@ public class GeyserSession implements PlayerSession, Player {
         this.connector = connector;
         this.upstream = bedrockServerSession;
 
+        this.playerEntity = new PlayerEntity(this, 1, 1, EntityType.PLAYER, new Vector3f(0, 0, 0), new Vector3f(0, 0, 0), new Vector3f(0, 0, 0));
+
+        this.entityCache = new EntityCache(this);
         this.inventoryCache = new InventoryCache(this);
         this.windowCache = new WindowCache(this);
-
         this.scoreboardCache = new ScoreboardCache(this);
 
         this.loggedIn = false;
diff --git a/connector/src/main/java/org/geysermc/connector/network/session/cache/EntityCache.java b/connector/src/main/java/org/geysermc/connector/network/session/cache/EntityCache.java
new file mode 100644
index 000000000..e15d8c526
--- /dev/null
+++ b/connector/src/main/java/org/geysermc/connector/network/session/cache/EntityCache.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2019 GeyserMC. http://geysermc.org
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * @author GeyserMC
+ * @link https://github.com/GeyserMC/Geyser
+ */
+
+package org.geysermc.connector.network.session.cache;
+
+import com.flowpowered.math.vector.Vector3f;
+import com.github.steveice10.mc.protocol.packet.ingame.server.entity.spawn.ServerSpawnMobPacket;
+import lombok.Getter;
+import org.geysermc.api.Geyser;
+import org.geysermc.connector.console.GeyserLogger;
+import org.geysermc.connector.entity.Entity;
+import org.geysermc.connector.entity.type.EntityType;
+import org.geysermc.connector.network.session.GeyserSession;
+import org.geysermc.connector.utils.EntityUtils;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicLong;
+
+// Each session has its own EntityCache in the occasion that an entity packet is sent specifically
+// for that player (e.g. seeing vanished players from /vanish)
+public class EntityCache {
+
+    private GeyserSession session;
+
+    @Getter
+    private Map<Long, Entity> entities = new HashMap<Long, Entity>();
+
+    private AtomicLong nextEntityId = new AtomicLong(2L);
+
+    public EntityCache(GeyserSession session) {
+        this.session = session;
+    }
+
+    public Entity spawnEntity(ServerSpawnMobPacket packet) {
+        EntityType type = EntityUtils.toBedrockEntity(packet.getType());
+        if (type == null) {
+            GeyserLogger.DEFAULT.warning("Mob " + packet.getType() + " is not supported yet!");
+            return null;
+        }
+
+        Vector3f position = new Vector3f(packet.getX(), packet.getY(), packet.getZ());
+        Vector3f motion = new Vector3f(packet.getMotionX(), packet.getMotionY(), packet.getMotionZ());
+        Vector3f rotation = new Vector3f(packet.getPitch(), packet.getYaw(), packet.getHeadYaw());
+
+        Entity entity = new Entity(packet.getEntityId(), nextEntityId.incrementAndGet(), type, position, motion, rotation);
+        entity.moveAbsolute(position, packet.getPitch(), packet.getYaw());
+        return entities.put(entity.getGeyserId(), entity);
+    }
+}
diff --git a/connector/src/main/java/org/geysermc/connector/utils/EntityUtils.java b/connector/src/main/java/org/geysermc/connector/utils/EntityUtils.java
new file mode 100644
index 000000000..50b616ea5
--- /dev/null
+++ b/connector/src/main/java/org/geysermc/connector/utils/EntityUtils.java
@@ -0,0 +1,23 @@
+package org.geysermc.connector.utils;
+
+import com.github.steveice10.mc.protocol.data.game.entity.type.MobType;
+import org.geysermc.connector.entity.type.EntityType;
+
+public class EntityUtils {
+
+    public static MobType toJavaEntity(EntityType type) {
+        try {
+            return MobType.valueOf(type.name());
+        } catch (IllegalArgumentException ex) {
+            return null;
+        }
+    }
+
+    public static EntityType toBedrockEntity(MobType type) {
+        try {
+            return EntityType.valueOf(type.name());
+        } catch (IllegalArgumentException ex) {
+            return null;
+        }
+    }
+}

From c114e4d54176ae736dd84c328021cf56ea9d4d13 Mon Sep 17 00:00:00 2001
From: RednedEpic <redned@retronixgames.x10host.com>
Date: Sat, 3 Aug 2019 01:51:05 -0500
Subject: [PATCH 02/10] (A lot) more work on entities

---
 .../org/geysermc/connector/entity/Entity.java |  53 +++++---
 .../connector/entity/ExpOrbEntity.java        |  52 +++++++
 .../connector/entity/PlayerEntity.java        |  19 ++-
 .../network/session/GeyserSession.java        |  41 +++---
 .../network/session/cache/DataCache.java      |  37 +++++
 .../network/session/cache/EntityCache.java    |  46 ++++---
 .../network/translators/TranslatorsInit.java  |  36 ++++-
 .../java/JavaJoinGameTranslator.java          |   5 +-
 .../entity/JavaEntityDestroyTranslator.java   |   7 +-
 .../entity/JavaEntityHeadLookTranslator.java  |  56 ++++++++
 .../entity/JavaEntityMetadataTranslator.java  |  56 ++++++++
 .../JavaEntityPositionRotationTranslator.java |  28 ++--
 .../entity/JavaEntityPositionTranslator.java  |  28 ++--
 .../JavaEntityPropertiesTranslator.java       |  45 ++++++
 .../entity/JavaEntityRotationTranslator.java  |  60 ++++++++
 .../entity/JavaEntityTeleportTranslator.java  |  27 +++-
 .../entity/JavaEntityVelocityTranslator.java  |  14 +-
 .../JavaPlayerPositionRotationTranslator.java | 128 ++++++++++++++++++
 .../spawn/JavaSpawnExpOrbTranslator.java      |  40 +++++-
 .../JavaSpawnGlobalEntityTranslator.java      |  50 +++++++
 .../entity/spawn/JavaSpawnMobTranslator.java  |  59 ++++++++
 .../spawn/JavaSpawnObjectTranslator.java      |  63 +++++++++
 .../spawn/JavaSpawnPaintingTranslator.java    |  49 +++++++
 .../spawn/JavaSpawnPlayerTranslator.java      |  50 +++++++
 .../geysermc/connector/utils/EntityUtils.java |   9 ++
 .../org/geysermc/connector/utils/Toolbox.java |   6 -
 26 files changed, 953 insertions(+), 111 deletions(-)
 create mode 100644 connector/src/main/java/org/geysermc/connector/entity/ExpOrbEntity.java
 create mode 100644 connector/src/main/java/org/geysermc/connector/network/session/cache/DataCache.java
 create mode 100644 connector/src/main/java/org/geysermc/connector/network/translators/java/entity/JavaEntityHeadLookTranslator.java
 create mode 100644 connector/src/main/java/org/geysermc/connector/network/translators/java/entity/JavaEntityMetadataTranslator.java
 create mode 100644 connector/src/main/java/org/geysermc/connector/network/translators/java/entity/JavaEntityPropertiesTranslator.java
 create mode 100644 connector/src/main/java/org/geysermc/connector/network/translators/java/entity/JavaEntityRotationTranslator.java
 create mode 100644 connector/src/main/java/org/geysermc/connector/network/translators/java/entity/player/JavaPlayerPositionRotationTranslator.java
 create mode 100644 connector/src/main/java/org/geysermc/connector/network/translators/java/entity/spawn/JavaSpawnGlobalEntityTranslator.java
 create mode 100644 connector/src/main/java/org/geysermc/connector/network/translators/java/entity/spawn/JavaSpawnMobTranslator.java
 create mode 100644 connector/src/main/java/org/geysermc/connector/network/translators/java/entity/spawn/JavaSpawnObjectTranslator.java
 create mode 100644 connector/src/main/java/org/geysermc/connector/network/translators/java/entity/spawn/JavaSpawnPaintingTranslator.java
 create mode 100644 connector/src/main/java/org/geysermc/connector/network/translators/java/entity/spawn/JavaSpawnPlayerTranslator.java

diff --git a/connector/src/main/java/org/geysermc/connector/entity/Entity.java b/connector/src/main/java/org/geysermc/connector/entity/Entity.java
index 66d50fd3a..65ebe98f2 100644
--- a/connector/src/main/java/org/geysermc/connector/entity/Entity.java
+++ b/connector/src/main/java/org/geysermc/connector/entity/Entity.java
@@ -33,11 +33,14 @@ import com.nukkitx.protocol.bedrock.packet.AddEntityPacket;
 import com.nukkitx.protocol.bedrock.packet.RemoveEntityPacket;
 import lombok.Getter;
 import lombok.Setter;
+import org.geysermc.connector.console.GeyserLogger;
 import org.geysermc.connector.entity.type.EntityType;
 import org.geysermc.connector.network.session.GeyserSession;
 
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.Map;
+import java.util.Set;
 
 @Getter
 @Setter
@@ -50,18 +53,19 @@ public class Entity {
 
     protected Vector3f position;
     protected Vector3f motion;
+
+    // 1 - pitch, 2 - yaw, 3 - roll (head yaw)
     protected Vector3f rotation;
 
     protected int scale = 1;
-    protected float yaw;
-    protected float pitch;
-    protected boolean shouldMove;
+    protected boolean movePending;
 
     protected EntityType entityType;
 
     protected boolean valid;
 
-    protected Map<Integer, Attribute> attributes = new HashMap<Integer, Attribute>();
+    protected Set<Long> passengers = new HashSet<Long>();
+    protected Map<Attribute, Integer> attributes = new HashMap<Attribute, Integer>();
 
     public Entity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
         this.entityId = entityId;
@@ -72,20 +76,24 @@ public class Entity {
         this.rotation = rotation;
 
         this.valid = false;
-        this.shouldMove = false;
+        this.movePending = false;
     }
 
     public void spawnEntity(GeyserSession session) {
         AddEntityPacket addEntityPacket = new AddEntityPacket();
+        addEntityPacket.setIdentifier("minecraft:" + entityType.name().toLowerCase());
         addEntityPacket.setRuntimeEntityId(geyserId);
-        addEntityPacket.setUniqueEntityId(entityId);
+        addEntityPacket.setUniqueEntityId(geyserId);
         addEntityPacket.setPosition(position);
         addEntityPacket.setMotion(motion);
         addEntityPacket.setRotation(rotation);
         addEntityPacket.setEntityType(entityType.getType());
+        addEntityPacket.getMetadata().putAll(getMetadata());
 
-        session.getUpstream().sendPacket(addEntityPacket);
         valid = true;
+        session.getUpstream().sendPacket(addEntityPacket);
+
+        GeyserLogger.DEFAULT.debug("Spawned entity " + entityType + " at location " + position + " with id " + geyserId + " (java id " + entityId + ")");
     }
 
     public void despawnEntity(GeyserSession session) {
@@ -93,35 +101,38 @@ public class Entity {
             return;
 
         RemoveEntityPacket removeEntityPacket = new RemoveEntityPacket();
-        removeEntityPacket.setUniqueEntityId(entityId);
+        removeEntityPacket.setUniqueEntityId(geyserId);
         session.getUpstream().sendPacket(removeEntityPacket);
     }
 
     public void moveRelative(double relX, double relY, double relZ, float pitch, float yaw) {
-        if (relX == 0 && relY != 0 && relZ != 0 && yaw != 0 && pitch != 0)
+        moveRelative(relX, relY, relZ, new Vector3f(pitch, yaw, 0));
+    }
+
+    public void moveRelative(double relX, double relY, double relZ, Vector3f rotation) {
+        if (relX == 0 && relY != 0 && relZ != 0 && position.getX() == 0 && position.getY() == 0)
             return;
 
-        if (pitch != 0)
-            this.pitch = pitch;
-
-        if (yaw != 0)
-            this.yaw = yaw;
-
+        this.rotation = rotation;
         this.position = new Vector3f(position.getX() + relX, position.getX() + relY, position.getX() + relZ);
-        this.shouldMove = true;
+        this.movePending = true;
     }
 
     public void moveAbsolute(Vector3f position, float pitch, float yaw) {
-        if (position.getX() == 0 && position.getX() != 0 && position.getX() != 0 && yaw != 0 && pitch != 0)
+        moveAbsolute(position, new Vector3f(pitch, yaw, 0));
+    }
+
+    public void moveAbsolute(Vector3f position, Vector3f rotation) {
+        if (position.getX() == 0 && position.getX() != 0 && position.getX() != 0 && rotation.getX() == 0 && rotation.getY() == 0)
             return;
 
         this.position = position;
-        this.pitch = pitch;
-        this.yaw = yaw;
-        this.shouldMove = true;
+        this.rotation = rotation;
+        this.movePending = true;
     }
 
-    protected EntityDataDictionary getMetadata() {
+
+    public EntityDataDictionary getMetadata() {
         EntityDataDictionary dictionary = new EntityDataDictionary();
         dictionary.put(EntityData.NAMETAG, "");
         dictionary.put(EntityData.ENTITY_AGE, 0);
diff --git a/connector/src/main/java/org/geysermc/connector/entity/ExpOrbEntity.java b/connector/src/main/java/org/geysermc/connector/entity/ExpOrbEntity.java
new file mode 100644
index 000000000..036829e8a
--- /dev/null
+++ b/connector/src/main/java/org/geysermc/connector/entity/ExpOrbEntity.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2019 GeyserMC. http://geysermc.org
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * @author GeyserMC
+ * @link https://github.com/GeyserMC/Geyser
+ */
+
+package org.geysermc.connector.entity;
+
+import com.flowpowered.math.vector.Vector3f;
+import com.nukkitx.protocol.bedrock.packet.SpawnExperienceOrbPacket;
+import org.geysermc.connector.entity.type.EntityType;
+import org.geysermc.connector.network.session.GeyserSession;
+
+public class ExpOrbEntity extends Entity {
+
+    private int amount;
+
+    public ExpOrbEntity(int amount, long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
+        super(entityId, geyserId, entityType, position, motion, rotation);
+
+        this.amount = amount;
+    }
+
+    @Override
+    public void spawnEntity(GeyserSession session) {
+        SpawnExperienceOrbPacket spawnExpOrbPacket = new SpawnExperienceOrbPacket();
+        spawnExpOrbPacket.setPosition(position);
+        spawnExpOrbPacket.setAmount(amount);
+
+        valid = true;
+        session.getUpstream().sendPacket(spawnExpOrbPacket);
+    }
+}
diff --git a/connector/src/main/java/org/geysermc/connector/entity/PlayerEntity.java b/connector/src/main/java/org/geysermc/connector/entity/PlayerEntity.java
index 8797d20c3..eee33c177 100644
--- a/connector/src/main/java/org/geysermc/connector/entity/PlayerEntity.java
+++ b/connector/src/main/java/org/geysermc/connector/entity/PlayerEntity.java
@@ -37,12 +37,14 @@ import lombok.Setter;
 import org.geysermc.connector.entity.type.EntityType;
 import org.geysermc.connector.network.session.GeyserSession;
 
+import java.util.Random;
+import java.util.UUID;
+
 @Getter
 @Setter
 public class PlayerEntity extends Entity {
 
-    // This is the session linked to the player entity, can be null
-    private GeyserSession session;
+    private UUID uuid;
 
     private ItemData hand;
 
@@ -51,10 +53,10 @@ public class PlayerEntity extends Entity {
     private ItemData leggings;
     private ItemData boots;
 
-    public PlayerEntity(GeyserSession session, long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
+    public PlayerEntity(UUID uuid, long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
         super(entityId, geyserId, entityType, position, motion, rotation);
 
-        this.session = session;
+        this.uuid = uuid;
     }
 
     // TODO: Break this into an EquippableEntity class
@@ -76,9 +78,9 @@ public class PlayerEntity extends Entity {
     public void spawnEntity(GeyserSession session) {
         AddPlayerPacket addPlayerPacket = new AddPlayerPacket();
         addPlayerPacket.setUniqueEntityId(geyserId);
-        addPlayerPacket.setUniqueEntityId(entityId);
-        addPlayerPacket.setUuid(this.session.getAuthenticationData().getUUID());
-        addPlayerPacket.setUsername(this.session.getAuthenticationData().getName());
+        addPlayerPacket.setUniqueEntityId(geyserId);
+        addPlayerPacket.setUuid(uuid);
+        addPlayerPacket.setUsername("Player" + new Random().nextInt(1000) + 1); // TODO: Cache player list values and set it here
         addPlayerPacket.setPlatformChatId("");
         addPlayerPacket.setPosition(position);
         addPlayerPacket.setMotion(motion);
@@ -91,6 +93,9 @@ public class PlayerEntity extends Entity {
         addPlayerPacket.setPlayerPermission(0);
         addPlayerPacket.setCustomFlags(0);
         addPlayerPacket.setDeviceId("WIN10"); // TODO: Find this value
+        addPlayerPacket.getMetadata().putAll(getMetadata());
+
+        valid = true;
         session.getUpstream().sendPacket(addPlayerPacket);
     }
 }
diff --git a/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java b/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java
index fbc11cb97..2d0b03bf9 100644
--- a/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java
+++ b/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java
@@ -35,6 +35,7 @@ import com.github.steveice10.packetlib.event.session.ConnectedEvent;
 import com.github.steveice10.packetlib.event.session.DisconnectedEvent;
 import com.github.steveice10.packetlib.event.session.PacketReceivedEvent;
 import com.github.steveice10.packetlib.event.session.SessionAdapter;
+import com.github.steveice10.packetlib.packet.Packet;
 import com.github.steveice10.packetlib.tcp.TcpSessionFactory;
 import com.nukkitx.network.util.DisconnectReason;
 import com.nukkitx.protocol.PlayerSession;
@@ -45,6 +46,7 @@ import com.nukkitx.protocol.bedrock.packet.PlayStatusPacket;
 import com.nukkitx.protocol.bedrock.packet.StartGamePacket;
 import com.nukkitx.protocol.bedrock.packet.TextPacket;
 import lombok.Getter;
+import lombok.Setter;
 import org.geysermc.api.Player;
 import org.geysermc.api.RemoteServer;
 import org.geysermc.api.session.AuthData;
@@ -52,6 +54,7 @@ import org.geysermc.api.window.FormWindow;
 import org.geysermc.connector.GeyserConnector;
 import org.geysermc.connector.entity.PlayerEntity;
 import org.geysermc.connector.entity.type.EntityType;
+import org.geysermc.connector.network.session.cache.DataCache;
 import org.geysermc.connector.network.session.cache.EntityCache;
 import org.geysermc.connector.network.session.cache.InventoryCache;
 import org.geysermc.connector.network.session.cache.ScoreboardCache;
@@ -59,53 +62,48 @@ import org.geysermc.connector.network.session.cache.WindowCache;
 import org.geysermc.connector.network.translators.Registry;
 import org.geysermc.connector.utils.Toolbox;
 
+import java.util.UUID;
+
+@Getter
 public class GeyserSession implements PlayerSession, Player {
 
     private GeyserConnector connector;
-
-    @Getter
     private RemoteServer remoteServer;
-
-    @Getter
     private BedrockServerSession upstream;
 
-    @Getter
     private Client downstream;
 
-    @Getter
     private AuthData authenticationData;
 
-    @Getter
     private PlayerEntity playerEntity;
-
-    @Getter
     private EntityCache entityCache;
-
-    @Getter
     private InventoryCache inventoryCache;
-
-    @Getter
     private WindowCache windowCache;
-
-    @Getter
     private ScoreboardCache scoreboardCache;
 
-    @Getter
+    private DataCache<Packet> javaPacketCache;
+
     private boolean loggedIn;
 
+    @Setter
+    private boolean spawned;
+
     private boolean closed;
 
     public GeyserSession(GeyserConnector connector, BedrockServerSession bedrockServerSession) {
         this.connector = connector;
         this.upstream = bedrockServerSession;
 
-        this.playerEntity = new PlayerEntity(this, 1, 1, EntityType.PLAYER, new Vector3f(0, 0, 0), new Vector3f(0, 0, 0), new Vector3f(0, 0, 0));
+        this.playerEntity = new PlayerEntity(UUID.randomUUID(), 1, 1, EntityType.PLAYER, new Vector3f(0, 0, 0), new Vector3f(0, 0, 0), new Vector3f(0, 0, 0));
 
         this.entityCache = new EntityCache(this);
         this.inventoryCache = new InventoryCache(this);
         this.windowCache = new WindowCache(this);
         this.scoreboardCache = new ScoreboardCache(this);
 
+        this.javaPacketCache = new DataCache<Packet>();
+
+        this.spawned = false;
         this.loggedIn = false;
     }
 
@@ -145,6 +143,7 @@ public class GeyserSession implements PlayerSession, Player {
                 public void connected(ConnectedEvent event) {
                     loggedIn = true;
                     connector.getLogger().info(authenticationData.getName() + " (logged in as: " + protocol.getProfile().getName() + ")" + " has connected to remote java server on address " + remoteServer.getAddress());
+                    playerEntity.setUuid(protocol.getProfile().getId());
                 }
 
                 @Override
@@ -237,13 +236,13 @@ public class GeyserSession implements PlayerSession, Player {
 
     private void startGame() {
         StartGamePacket startGamePacket = new StartGamePacket();
-        startGamePacket.setUniqueEntityId(1); // TODO: Cache this value
-        startGamePacket.setRuntimeEntityId(1); // TODO: Cache this value
+        startGamePacket.setUniqueEntityId(1);
+        startGamePacket.setRuntimeEntityId(1);
         startGamePacket.setPlayerGamemode(0);
         startGamePacket.setPlayerPosition(new Vector3f(0, 0, 0));
         startGamePacket.setRotation(new Vector2f(1, 1));
 
-        startGamePacket.setSeed(1111);
+        startGamePacket.setSeed(0);
         startGamePacket.setDimensionId(0);
         startGamePacket.setGeneratorId(0);
         startGamePacket.setLevelGamemode(0);
@@ -274,7 +273,7 @@ public class GeyserSession implements PlayerSession, Player {
         startGamePacket.setFromWorldTemplate(false);
         startGamePacket.setWorldTemplateOptionLocked(false);
 
-        startGamePacket.setLevelId("oerjhii");
+        startGamePacket.setLevelId("world");
         startGamePacket.setWorldName("world");
         startGamePacket.setPremiumWorldTemplateId("00000000-0000-0000-0000-000000000000");
         startGamePacket.setCurrentTick(0);
diff --git a/connector/src/main/java/org/geysermc/connector/network/session/cache/DataCache.java b/connector/src/main/java/org/geysermc/connector/network/session/cache/DataCache.java
new file mode 100644
index 000000000..58d33a736
--- /dev/null
+++ b/connector/src/main/java/org/geysermc/connector/network/session/cache/DataCache.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2019 GeyserMC. http://geysermc.org
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * @author GeyserMC
+ * @link https://github.com/GeyserMC/Geyser
+ */
+
+package org.geysermc.connector.network.session.cache;
+
+import lombok.Getter;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class DataCache<T> {
+
+    @Getter
+    private Map<String, T> cachedValues = new HashMap<String, T>();
+}
diff --git a/connector/src/main/java/org/geysermc/connector/network/session/cache/EntityCache.java b/connector/src/main/java/org/geysermc/connector/network/session/cache/EntityCache.java
index e15d8c526..e2bf53c33 100644
--- a/connector/src/main/java/org/geysermc/connector/network/session/cache/EntityCache.java
+++ b/connector/src/main/java/org/geysermc/connector/network/session/cache/EntityCache.java
@@ -25,22 +25,18 @@
 
 package org.geysermc.connector.network.session.cache;
 
-import com.flowpowered.math.vector.Vector3f;
-import com.github.steveice10.mc.protocol.packet.ingame.server.entity.spawn.ServerSpawnMobPacket;
 import lombok.Getter;
-import org.geysermc.api.Geyser;
-import org.geysermc.connector.console.GeyserLogger;
 import org.geysermc.connector.entity.Entity;
-import org.geysermc.connector.entity.type.EntityType;
 import org.geysermc.connector.network.session.GeyserSession;
-import org.geysermc.connector.utils.EntityUtils;
 
 import java.util.HashMap;
 import java.util.Map;
 import java.util.concurrent.atomic.AtomicLong;
 
-// Each session has its own EntityCache in the occasion that an entity packet is sent specifically
-// for that player (e.g. seeing vanished players from /vanish)
+/**
+ * Each session has its own EntityCache in the occasion that an entity packet is sent specifically
+ * for that player (e.g. seeing vanished players from /vanish)
+ */
 public class EntityCache {
 
     private GeyserSession session;
@@ -48,25 +44,35 @@ public class EntityCache {
     @Getter
     private Map<Long, Entity> entities = new HashMap<Long, Entity>();
 
+    private Map<Long, Long> entityIdTranslations = new HashMap<Long, Long>();
+
+    @Getter
     private AtomicLong nextEntityId = new AtomicLong(2L);
 
     public EntityCache(GeyserSession session) {
         this.session = session;
     }
 
-    public Entity spawnEntity(ServerSpawnMobPacket packet) {
-        EntityType type = EntityUtils.toBedrockEntity(packet.getType());
-        if (type == null) {
-            GeyserLogger.DEFAULT.warning("Mob " + packet.getType() + " is not supported yet!");
-            return null;
-        }
+    public void spawnEntity(Entity entity) {
+        entity.moveAbsolute(entity.getPosition(), entity.getRotation().getX(), entity.getRotation().getY());
+        entityIdTranslations.put(entity.getEntityId(), entity.getGeyserId());
+        entities.put(entity.getGeyserId(), entity);
+        entity.spawnEntity(session);
+    }
 
-        Vector3f position = new Vector3f(packet.getX(), packet.getY(), packet.getZ());
-        Vector3f motion = new Vector3f(packet.getMotionX(), packet.getMotionY(), packet.getMotionZ());
-        Vector3f rotation = new Vector3f(packet.getPitch(), packet.getYaw(), packet.getHeadYaw());
+    public void removeEntity(Entity entity) {
+        if (entity == null)
+            return;
 
-        Entity entity = new Entity(packet.getEntityId(), nextEntityId.incrementAndGet(), type, position, motion, rotation);
-        entity.moveAbsolute(position, packet.getPitch(), packet.getYaw());
-        return entities.put(entity.getGeyserId(), entity);
+        entityIdTranslations.remove(entity.getGeyserId());
+        entity.despawnEntity(session);
+    }
+
+    public Entity getEntityByGeyserId(long geyserId) {
+        return entities.get(geyserId);
+    }
+
+    public Entity getEntityByJavaId(long javaId) {
+        return entities.get(entityIdTranslations.get(javaId));
     }
 }
diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/TranslatorsInit.java b/connector/src/main/java/org/geysermc/connector/network/translators/TranslatorsInit.java
index 4357f9f65..3ac7ee3a3 100644
--- a/connector/src/main/java/org/geysermc/connector/network/translators/TranslatorsInit.java
+++ b/connector/src/main/java/org/geysermc/connector/network/translators/TranslatorsInit.java
@@ -30,11 +30,21 @@ import com.github.steveice10.mc.protocol.packet.ingame.server.ServerChatPacket;
 import com.github.steveice10.mc.protocol.packet.ingame.server.ServerJoinGamePacket;
 import com.github.steveice10.mc.protocol.packet.ingame.server.ServerTitlePacket;
 import com.github.steveice10.mc.protocol.packet.ingame.server.entity.ServerEntityDestroyPacket;
+import com.github.steveice10.mc.protocol.packet.ingame.server.entity.ServerEntityHeadLookPacket;
+import com.github.steveice10.mc.protocol.packet.ingame.server.entity.ServerEntityMetadataPacket;
 import com.github.steveice10.mc.protocol.packet.ingame.server.entity.ServerEntityPositionPacket;
 import com.github.steveice10.mc.protocol.packet.ingame.server.entity.ServerEntityPositionRotationPacket;
+import com.github.steveice10.mc.protocol.packet.ingame.server.entity.ServerEntityPropertiesPacket;
+import com.github.steveice10.mc.protocol.packet.ingame.server.entity.ServerEntityRotationPacket;
 import com.github.steveice10.mc.protocol.packet.ingame.server.entity.ServerEntityTeleportPacket;
 import com.github.steveice10.mc.protocol.packet.ingame.server.entity.ServerEntityVelocityPacket;
+import com.github.steveice10.mc.protocol.packet.ingame.server.entity.player.ServerPlayerPositionRotationPacket;
 import com.github.steveice10.mc.protocol.packet.ingame.server.entity.spawn.ServerSpawnExpOrbPacket;
+import com.github.steveice10.mc.protocol.packet.ingame.server.entity.spawn.ServerSpawnGlobalEntityPacket;
+import com.github.steveice10.mc.protocol.packet.ingame.server.entity.spawn.ServerSpawnMobPacket;
+import com.github.steveice10.mc.protocol.packet.ingame.server.entity.spawn.ServerSpawnObjectPacket;
+import com.github.steveice10.mc.protocol.packet.ingame.server.entity.spawn.ServerSpawnPaintingPacket;
+import com.github.steveice10.mc.protocol.packet.ingame.server.entity.spawn.ServerSpawnPlayerPacket;
 import com.github.steveice10.mc.protocol.packet.ingame.server.window.ServerOpenWindowPacket;
 import com.github.steveice10.mc.protocol.packet.ingame.server.window.ServerSetSlotPacket;
 import com.github.steveice10.mc.protocol.packet.ingame.server.window.ServerWindowItemsPacket;
@@ -57,11 +67,21 @@ import org.geysermc.connector.network.translators.item.ItemTranslator;
 import org.geysermc.connector.network.translators.java.JavaChatTranslator;
 import org.geysermc.connector.network.translators.java.JavaJoinGameTranslator;
 import org.geysermc.connector.network.translators.java.entity.JavaEntityDestroyTranslator;
+import org.geysermc.connector.network.translators.java.entity.JavaEntityHeadLookTranslator;
+import org.geysermc.connector.network.translators.java.entity.JavaEntityMetadataTranslator;
 import org.geysermc.connector.network.translators.java.entity.JavaEntityPositionRotationTranslator;
 import org.geysermc.connector.network.translators.java.entity.JavaEntityPositionTranslator;
+import org.geysermc.connector.network.translators.java.entity.JavaEntityPropertiesTranslator;
+import org.geysermc.connector.network.translators.java.entity.JavaEntityRotationTranslator;
 import org.geysermc.connector.network.translators.java.entity.JavaEntityTeleportTranslator;
 import org.geysermc.connector.network.translators.java.entity.JavaEntityVelocityTranslator;
+import org.geysermc.connector.network.translators.java.entity.player.JavaPlayerPositionRotationTranslator;
 import org.geysermc.connector.network.translators.java.entity.spawn.JavaSpawnExpOrbTranslator;
+import org.geysermc.connector.network.translators.java.entity.spawn.JavaSpawnGlobalEntityTranslator;
+import org.geysermc.connector.network.translators.java.entity.spawn.JavaSpawnMobTranslator;
+import org.geysermc.connector.network.translators.java.entity.spawn.JavaSpawnObjectTranslator;
+import org.geysermc.connector.network.translators.java.entity.spawn.JavaSpawnPaintingTranslator;
+import org.geysermc.connector.network.translators.java.entity.spawn.JavaSpawnPlayerTranslator;
 import org.geysermc.connector.network.translators.java.world.JavaNotifyClientTranslator;
 import org.geysermc.connector.network.translators.java.window.JavaOpenWindowTranslator;
 import org.geysermc.connector.network.translators.java.window.JavaSetSlotTranslator;
@@ -104,13 +124,27 @@ public class TranslatorsInit {
         Registry.registerJava(ServerChatPacket.class, new JavaChatTranslator());
         Registry.registerJava(ServerTitlePacket.class, new JavaTitleTranslator());
         Registry.registerJava(ServerUpdateTimePacket.class, new JavaUpdateTimeTranslator());
+
         Registry.registerJava(ServerEntityPositionPacket.class, new JavaEntityPositionTranslator());
         Registry.registerJava(ServerEntityPositionRotationPacket.class, new JavaEntityPositionRotationTranslator());
         Registry.registerJava(ServerEntityTeleportPacket.class, new JavaEntityTeleportTranslator());
         Registry.registerJava(ServerEntityVelocityPacket.class, new JavaEntityVelocityTranslator());
+        Registry.registerJava(ServerEntityPropertiesPacket.class, new JavaEntityPropertiesTranslator());
+        Registry.registerJava(ServerEntityRotationPacket.class, new JavaEntityRotationTranslator());
+        Registry.registerJava(ServerEntityHeadLookPacket.class, new JavaEntityHeadLookTranslator());
+        Registry.registerJava(ServerEntityMetadataPacket.class, new JavaEntityMetadataTranslator());
+
+        Registry.registerJava(ServerSpawnExpOrbPacket.class, new JavaSpawnExpOrbTranslator());
+        Registry.registerJava(ServerSpawnGlobalEntityPacket.class, new JavaSpawnGlobalEntityTranslator());
+        Registry.registerJava(ServerSpawnMobPacket.class, new JavaSpawnMobTranslator());
+        Registry.registerJava(ServerSpawnObjectPacket.class, new JavaSpawnObjectTranslator());
+        Registry.registerJava(ServerSpawnPaintingPacket.class, new JavaSpawnPaintingTranslator());
+        Registry.registerJava(ServerSpawnPlayerPacket.class, new JavaSpawnPlayerTranslator());
+
+        Registry.registerJava(ServerPlayerPositionRotationPacket.class, new JavaPlayerPositionRotationTranslator());
+
         Registry.registerJava(ServerNotifyClientPacket.class, new JavaNotifyClientTranslator());
         Registry.registerJava(ServerEntityDestroyPacket.class, new JavaEntityDestroyTranslator());
-        Registry.registerJava(ServerSpawnExpOrbPacket.class, new JavaSpawnExpOrbTranslator());
         Registry.registerJava(ServerWindowItemsPacket.class, new JavaWindowItemsTranslator());
         Registry.registerJava(ServerOpenWindowPacket.class, new JavaOpenWindowTranslator());
         Registry.registerJava(ServerSetSlotPacket.class, new JavaSetSlotTranslator());
diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaJoinGameTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaJoinGameTranslator.java
index a43fd4a43..ec03f219c 100644
--- a/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaJoinGameTranslator.java
+++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaJoinGameTranslator.java
@@ -38,7 +38,7 @@ public class JavaJoinGameTranslator extends PacketTranslator<ServerJoinGamePacke
     @Override
     public void translate(ServerJoinGamePacket packet, GeyserSession session) {
         AdventureSettingsPacket bedrockPacket = new AdventureSettingsPacket();
-        bedrockPacket.setUniqueEntityId(packet.getEntityId());
+        bedrockPacket.setUniqueEntityId(session.getPlayerEntity().getGeyserId());
         session.getUpstream().sendPacketImmediately(bedrockPacket);
 
         Vector3f pos = new Vector3f(0, 0, 0);
@@ -52,10 +52,11 @@ public class JavaJoinGameTranslator extends PacketTranslator<ServerJoinGamePacke
                 data.setSubChunksLength(0);
 
                 data.setData(TranslatorsInit.EMPTY_LEVEL_CHUNK_DATA);
-
                 session.getUpstream().sendPacketImmediately(data);
 
             }
         }
+
+        session.getJavaPacketCache().getCachedValues().put("java_join_packet", packet);
     }
 }
diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/JavaEntityDestroyTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/JavaEntityDestroyTranslator.java
index a9885d330..ed741f95a 100644
--- a/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/JavaEntityDestroyTranslator.java
+++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/JavaEntityDestroyTranslator.java
@@ -27,6 +27,7 @@ package org.geysermc.connector.network.translators.java.entity;
 
 import com.github.steveice10.mc.protocol.packet.ingame.server.entity.ServerEntityDestroyPacket;
 import com.nukkitx.protocol.bedrock.packet.RemoveEntityPacket;
+import org.geysermc.connector.entity.Entity;
 import org.geysermc.connector.network.session.GeyserSession;
 import org.geysermc.connector.network.translators.PacketTranslator;
 
@@ -35,10 +36,8 @@ public class JavaEntityDestroyTranslator extends PacketTranslator<ServerEntityDe
     @Override
     public void translate(ServerEntityDestroyPacket packet, GeyserSession session) {
         for (int entityId : packet.getEntityIds()) {
-            RemoveEntityPacket removeEntityPacket = new RemoveEntityPacket();
-            removeEntityPacket.setUniqueEntityId(entityId);
-
-            session.getUpstream().sendPacket(removeEntityPacket);
+            Entity entity = session.getEntityCache().getEntityByJavaId(entityId);
+            session.getEntityCache().removeEntity(entity);
         }
     }
 }
diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/JavaEntityHeadLookTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/JavaEntityHeadLookTranslator.java
new file mode 100644
index 000000000..ed83f3b74
--- /dev/null
+++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/JavaEntityHeadLookTranslator.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2019 GeyserMC. http://geysermc.org
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * @author GeyserMC
+ * @link https://github.com/GeyserMC/Geyser
+ */
+
+package org.geysermc.connector.network.translators.java.entity;
+
+import com.flowpowered.math.vector.Vector3f;
+import com.github.steveice10.mc.protocol.packet.ingame.server.entity.ServerEntityHeadLookPacket;
+import com.nukkitx.protocol.bedrock.packet.MoveEntityAbsolutePacket;
+import org.geysermc.connector.entity.Entity;
+import org.geysermc.connector.network.session.GeyserSession;
+import org.geysermc.connector.network.translators.PacketTranslator;
+
+public class JavaEntityHeadLookTranslator extends PacketTranslator<ServerEntityHeadLookPacket> {
+
+    @Override
+    public void translate(ServerEntityHeadLookPacket packet, GeyserSession session) {
+        Entity entity = session.getEntityCache().getEntityByJavaId(packet.getEntityId());
+        if (packet.getEntityId() == session.getPlayerEntity().getEntityId()) {
+            entity = session.getPlayerEntity();
+        }
+        if (entity == null)
+            return;
+
+        entity.setRotation(new Vector3f(entity.getRotation().getX(), entity.getRotation().getY(), packet.getHeadYaw()));
+
+        MoveEntityAbsolutePacket moveEntityAbsolutePacket = new MoveEntityAbsolutePacket();
+        moveEntityAbsolutePacket.setRuntimeEntityId(entity.getGeyserId());
+        moveEntityAbsolutePacket.setRotation(entity.getRotation());
+        moveEntityAbsolutePacket.setPosition(entity.getPosition());
+        moveEntityAbsolutePacket.setOnGround(true);
+
+        session.getUpstream().sendPacket(moveEntityAbsolutePacket);
+    }
+}
diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/JavaEntityMetadataTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/JavaEntityMetadataTranslator.java
new file mode 100644
index 000000000..c0451eb7e
--- /dev/null
+++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/JavaEntityMetadataTranslator.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2019 GeyserMC. http://geysermc.org
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * @author GeyserMC
+ * @link https://github.com/GeyserMC/Geyser
+ */
+
+package org.geysermc.connector.network.translators.java.entity;
+
+import com.github.steveice10.mc.protocol.packet.ingame.server.entity.ServerEntityMetadataPacket;
+import com.nukkitx.protocol.bedrock.packet.SetEntityDataPacket;
+import org.geysermc.connector.entity.Entity;
+import org.geysermc.connector.network.session.GeyserSession;
+import org.geysermc.connector.network.translators.PacketTranslator;
+
+public class JavaEntityMetadataTranslator extends PacketTranslator<ServerEntityMetadataPacket> {
+
+    @Override
+    public void translate(ServerEntityMetadataPacket packet, GeyserSession session) {
+        Entity entity = session.getEntityCache().getEntityByJavaId(packet.getEntityId());
+        if (packet.getEntityId() == session.getPlayerEntity().getEntityId()) {
+            entity = session.getPlayerEntity();
+        }
+        if (entity == null)
+            return;
+
+        if (entity.isValid()) {
+            // TODO: Make this actually useful lol
+            SetEntityDataPacket entityDataPacket = new SetEntityDataPacket();
+            entityDataPacket.setRuntimeEntityId(entity.getGeyserId());
+            entityDataPacket.getMetadata().putAll(entity.getMetadata());
+
+            session.getUpstream().sendPacket(entityDataPacket);
+        } else {
+            entity.spawnEntity(session);
+        }
+    }
+}
diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/JavaEntityPositionRotationTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/JavaEntityPositionRotationTranslator.java
index 713a24323..e97c40dab 100644
--- a/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/JavaEntityPositionRotationTranslator.java
+++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/JavaEntityPositionRotationTranslator.java
@@ -25,9 +25,9 @@
 
 package org.geysermc.connector.network.translators.java.entity;
 
-import com.flowpowered.math.vector.Vector3f;
 import com.github.steveice10.mc.protocol.packet.ingame.server.entity.ServerEntityPositionRotationPacket;
 import com.nukkitx.protocol.bedrock.packet.MoveEntityAbsolutePacket;
+import org.geysermc.connector.entity.Entity;
 import org.geysermc.connector.network.session.GeyserSession;
 import org.geysermc.connector.network.translators.PacketTranslator;
 
@@ -35,13 +35,25 @@ public class JavaEntityPositionRotationTranslator extends PacketTranslator<Serve
 
     @Override
     public void translate(ServerEntityPositionRotationPacket packet, GeyserSession session) {
-        MoveEntityAbsolutePacket moveEntityPacket = new MoveEntityAbsolutePacket();
-        moveEntityPacket.setRuntimeEntityId(packet.getEntityId());
-        moveEntityPacket.setPosition(new Vector3f(packet.getMovementX(), packet.getMovementY(), packet.getMovementZ()));
-        moveEntityPacket.setRotation(new Vector3f(packet.getMovementX(), packet.getMovementY(), packet.getMovementZ()));
-        moveEntityPacket.setOnGround(true);
-        moveEntityPacket.setTeleported(false);
+        Entity entity = session.getEntityCache().getEntityByJavaId(packet.getEntityId());
+        if (packet.getEntityId() == session.getPlayerEntity().getEntityId()) {
+            entity = session.getPlayerEntity();
+        }
+        if (entity == null)
+            return;
 
-        session.getUpstream().sendPacket(moveEntityPacket);
+        entity.moveRelative(packet.getMovementX(), packet.getMovementY(), packet.getMovementZ(), packet.getPitch(), packet.getYaw());
+
+        if (entity.isMovePending()) {
+            MoveEntityAbsolutePacket moveEntityPacket = new MoveEntityAbsolutePacket();
+            moveEntityPacket.setRuntimeEntityId(entity.getGeyserId());
+            moveEntityPacket.setPosition(entity.getPosition());
+            moveEntityPacket.setRotation(entity.getRotation());
+            moveEntityPacket.setOnGround(packet.isOnGround());
+            moveEntityPacket.setTeleported(false);
+            entity.setMovePending(false);
+
+            session.getUpstream().sendPacket(moveEntityPacket);
+        }
     }
 }
diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/JavaEntityPositionTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/JavaEntityPositionTranslator.java
index a79b9d720..d20931885 100644
--- a/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/JavaEntityPositionTranslator.java
+++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/JavaEntityPositionTranslator.java
@@ -25,9 +25,9 @@
 
 package org.geysermc.connector.network.translators.java.entity;
 
-import com.flowpowered.math.vector.Vector3f;
 import com.github.steveice10.mc.protocol.packet.ingame.server.entity.ServerEntityPositionPacket;
 import com.nukkitx.protocol.bedrock.packet.MoveEntityAbsolutePacket;
+import org.geysermc.connector.entity.Entity;
 import org.geysermc.connector.network.session.GeyserSession;
 import org.geysermc.connector.network.translators.PacketTranslator;
 
@@ -35,13 +35,25 @@ public class JavaEntityPositionTranslator extends PacketTranslator<ServerEntityP
 
     @Override
     public void translate(ServerEntityPositionPacket packet, GeyserSession session) {
-        MoveEntityAbsolutePacket moveEntityPacket = new MoveEntityAbsolutePacket();
-        moveEntityPacket.setRuntimeEntityId(packet.getEntityId());
-        moveEntityPacket.setPosition(new Vector3f(packet.getMovementX(), packet.getMovementY(), packet.getMovementZ()));
-        moveEntityPacket.setRotation(new Vector3f(packet.getMovementX(), packet.getMovementY(), packet.getMovementZ()));
-        moveEntityPacket.setOnGround(packet.isOnGround());
-        moveEntityPacket.setTeleported(false);
+        Entity entity = session.getEntityCache().getEntityByJavaId(packet.getEntityId());
+        if (packet.getEntityId() == session.getPlayerEntity().getEntityId()) {
+            entity = session.getPlayerEntity();
+        }
+        if (entity == null)
+            return;
 
-        session.getUpstream().sendPacket(moveEntityPacket);
+        entity.moveRelative(packet.getMovementX(), packet.getMovementY(), packet.getMovementZ(), packet.getPitch(), packet.getYaw());
+
+        if (entity.isMovePending()) {
+            MoveEntityAbsolutePacket moveEntityPacket = new MoveEntityAbsolutePacket();
+            moveEntityPacket.setRuntimeEntityId(entity.getGeyserId());
+            moveEntityPacket.setPosition(entity.getPosition());
+            moveEntityPacket.setRotation(entity.getRotation());
+            moveEntityPacket.setOnGround(packet.isOnGround());
+            moveEntityPacket.setTeleported(false);
+            entity.setMovePending(false);
+
+            session.getUpstream().sendPacket(moveEntityPacket);
+        }
     }
 }
diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/JavaEntityPropertiesTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/JavaEntityPropertiesTranslator.java
new file mode 100644
index 000000000..068ff2794
--- /dev/null
+++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/JavaEntityPropertiesTranslator.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2019 GeyserMC. http://geysermc.org
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * @author GeyserMC
+ * @link https://github.com/GeyserMC/Geyser
+ */
+
+package org.geysermc.connector.network.translators.java.entity;
+
+import com.github.steveice10.mc.protocol.packet.ingame.server.entity.ServerEntityPropertiesPacket;
+import org.geysermc.connector.entity.Entity;
+import org.geysermc.connector.network.session.GeyserSession;
+import org.geysermc.connector.network.translators.PacketTranslator;
+
+public class JavaEntityPropertiesTranslator extends PacketTranslator<ServerEntityPropertiesPacket> {
+
+    @Override
+    public void translate(ServerEntityPropertiesPacket packet, GeyserSession session) {
+        Entity entity = session.getEntityCache().getEntityByJavaId(packet.getEntityId());
+        if (packet.getEntityId() == session.getPlayerEntity().getEntityId()) {
+            entity = session.getPlayerEntity();
+        }
+        if (entity == null)
+            return;
+
+    }
+}
diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/JavaEntityRotationTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/JavaEntityRotationTranslator.java
new file mode 100644
index 000000000..77ed8855e
--- /dev/null
+++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/JavaEntityRotationTranslator.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2019 GeyserMC. http://geysermc.org
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * @author GeyserMC
+ * @link https://github.com/GeyserMC/Geyser
+ */
+
+package org.geysermc.connector.network.translators.java.entity;
+
+import com.flowpowered.math.vector.Vector3f;
+import com.github.steveice10.mc.protocol.packet.ingame.server.entity.ServerEntityRotationPacket;
+import com.nukkitx.protocol.bedrock.packet.MoveEntityAbsolutePacket;
+import org.geysermc.connector.entity.Entity;
+import org.geysermc.connector.network.session.GeyserSession;
+import org.geysermc.connector.network.translators.PacketTranslator;
+
+public class JavaEntityRotationTranslator extends PacketTranslator<ServerEntityRotationPacket> {
+
+    @Override
+    public void translate(ServerEntityRotationPacket packet, GeyserSession session) {
+        Entity entity = session.getEntityCache().getEntityByJavaId(packet.getEntityId());
+        if (packet.getEntityId() == session.getPlayerEntity().getEntityId()) {
+            entity = session.getPlayerEntity();
+        }
+        if (entity == null)
+            return;
+
+        entity.moveRelative(packet.getMovementX(), packet.getMovementY(), packet.getMovementZ(), packet.getPitch(), packet.getYaw());
+
+        Vector3f rotation = new Vector3f(entity.getRotation().getX() / (360d / 256d), entity.getRotation().getY() / (360d / 256d),
+                entity.getRotation().getZ() / (360d / 256d));
+        if (entity.isMovePending()) {
+            MoveEntityAbsolutePacket moveEntityAbsolutePacket = new MoveEntityAbsolutePacket();
+            moveEntityAbsolutePacket.setRuntimeEntityId(entity.getGeyserId());
+            moveEntityAbsolutePacket.setPosition(entity.getPosition());
+            moveEntityAbsolutePacket.setRotation(rotation);
+            entity.setMovePending(false);
+
+            session.getUpstream().sendPacket(moveEntityAbsolutePacket);
+        }
+    }
+}
diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/JavaEntityTeleportTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/JavaEntityTeleportTranslator.java
index c5ec98fc0..eb7262d67 100644
--- a/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/JavaEntityTeleportTranslator.java
+++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/JavaEntityTeleportTranslator.java
@@ -28,6 +28,7 @@ package org.geysermc.connector.network.translators.java.entity;
 import com.flowpowered.math.vector.Vector3f;
 import com.github.steveice10.mc.protocol.packet.ingame.server.entity.ServerEntityTeleportPacket;
 import com.nukkitx.protocol.bedrock.packet.MoveEntityAbsolutePacket;
+import org.geysermc.connector.entity.Entity;
 import org.geysermc.connector.network.session.GeyserSession;
 import org.geysermc.connector.network.translators.PacketTranslator;
 
@@ -35,13 +36,25 @@ public class JavaEntityTeleportTranslator extends PacketTranslator<ServerEntityT
 
     @Override
     public void translate(ServerEntityTeleportPacket packet, GeyserSession session) {
-        MoveEntityAbsolutePacket moveEntityPacket = new MoveEntityAbsolutePacket();
-        moveEntityPacket.setRuntimeEntityId(packet.getEntityId());
-        moveEntityPacket.setPosition(new Vector3f(packet.getX(), packet.getY(), packet.getZ()));
-        moveEntityPacket.setRotation(new Vector3f(packet.getX(), packet.getY(), packet.getZ()));
-        moveEntityPacket.setOnGround(packet.isOnGround());
-        moveEntityPacket.setTeleported(true);
+        Entity entity = session.getEntityCache().getEntityByJavaId(packet.getEntityId());
+        if (packet.getEntityId() == session.getPlayerEntity().getEntityId()) {
+            entity = session.getPlayerEntity();
+        }
+        if (entity == null)
+            return;
 
-        session.getUpstream().sendPacket(moveEntityPacket);
+        entity.moveAbsolute(new Vector3f(packet.getX(), packet.getY(), packet.getZ()), packet.getPitch(), packet.getYaw());
+
+        if (entity.isMovePending()) {
+            MoveEntityAbsolutePacket moveEntityPacket = new MoveEntityAbsolutePacket();
+            moveEntityPacket.setRuntimeEntityId(entity.getGeyserId());
+            moveEntityPacket.setPosition(entity.getPosition());
+            moveEntityPacket.setRotation(entity.getRotation());
+            moveEntityPacket.setOnGround(packet.isOnGround());
+            moveEntityPacket.setTeleported(true);
+            entity.setMovePending(false);
+
+            session.getUpstream().sendPacket(moveEntityPacket);
+        }
     }
 }
diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/JavaEntityVelocityTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/JavaEntityVelocityTranslator.java
index ef96e2f50..b7dfe201f 100644
--- a/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/JavaEntityVelocityTranslator.java
+++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/JavaEntityVelocityTranslator.java
@@ -28,6 +28,7 @@ package org.geysermc.connector.network.translators.java.entity;
 import com.flowpowered.math.vector.Vector3f;
 import com.github.steveice10.mc.protocol.packet.ingame.server.entity.ServerEntityVelocityPacket;
 import com.nukkitx.protocol.bedrock.packet.SetEntityMotionPacket;
+import org.geysermc.connector.entity.Entity;
 import org.geysermc.connector.network.session.GeyserSession;
 import org.geysermc.connector.network.translators.PacketTranslator;
 
@@ -35,9 +36,18 @@ public class JavaEntityVelocityTranslator extends PacketTranslator<ServerEntityV
 
     @Override
     public void translate(ServerEntityVelocityPacket packet, GeyserSession session) {
+        Entity entity = session.getEntityCache().getEntityByJavaId(packet.getEntityId());
+        if (packet.getEntityId() == session.getPlayerEntity().getEntityId()) {
+            entity = session.getPlayerEntity();
+        }
+        if (entity == null)
+            return;
+
+        entity.setMotion(new Vector3f(packet.getMotionX(), packet.getMotionY(), packet.getMotionZ()));
+
         SetEntityMotionPacket entityMotionPacket = new SetEntityMotionPacket();
-        entityMotionPacket.setRuntimeEntityId(packet.getEntityId());
-        entityMotionPacket.setMotion(new Vector3f(packet.getMotionX(), packet.getMotionY(), packet.getMotionZ()));
+        entityMotionPacket.setRuntimeEntityId(entity.getGeyserId());
+        entityMotionPacket.setMotion(entity.getMotion());
 
         session.getUpstream().sendPacket(entityMotionPacket);
     }
diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/player/JavaPlayerPositionRotationTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/player/JavaPlayerPositionRotationTranslator.java
new file mode 100644
index 000000000..15f4e9b15
--- /dev/null
+++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/player/JavaPlayerPositionRotationTranslator.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2019 GeyserMC. http://geysermc.org
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * @author GeyserMC
+ * @link https://github.com/GeyserMC/Geyser
+ */
+
+package org.geysermc.connector.network.translators.java.entity.player;
+
+import com.flowpowered.math.vector.Vector2f;
+import com.flowpowered.math.vector.Vector3f;
+import com.flowpowered.math.vector.Vector3i;
+import com.github.steveice10.mc.protocol.packet.ingame.server.ServerJoinGamePacket;
+import com.github.steveice10.mc.protocol.packet.ingame.server.entity.player.ServerPlayerPositionRotationPacket;
+import com.nukkitx.protocol.bedrock.data.GamePublishSetting;
+import com.nukkitx.protocol.bedrock.data.GameRule;
+import com.nukkitx.protocol.bedrock.packet.MovePlayerPacket;
+import com.nukkitx.protocol.bedrock.packet.SetEntityDataPacket;
+import com.nukkitx.protocol.bedrock.packet.StartGamePacket;
+import org.geysermc.connector.entity.Entity;
+import org.geysermc.connector.network.session.GeyserSession;
+import org.geysermc.connector.network.translators.PacketTranslator;
+import org.geysermc.connector.utils.Toolbox;
+
+public class JavaPlayerPositionRotationTranslator extends PacketTranslator<ServerPlayerPositionRotationPacket> {
+
+    @Override
+    public void translate(ServerPlayerPositionRotationPacket packet, GeyserSession session) {
+        Entity entity = session.getPlayerEntity();
+        if (entity == null)
+            return;
+
+        if (!session.isLoggedIn())
+            return;
+
+        if (session.isSpawned())
+            return;
+
+        ServerJoinGamePacket javaPacket = (ServerJoinGamePacket) session.getJavaPacketCache().getCachedValues().remove("java_join_packet");
+
+        StartGamePacket startGamePacket = new StartGamePacket();
+        startGamePacket.setUniqueEntityId(entity.getEntityId());
+        startGamePacket.setRuntimeEntityId(entity.getEntityId());
+        startGamePacket.setPlayerGamemode(0);
+        startGamePacket.setPlayerPosition(new Vector3f(packet.getX(), packet.getY(), packet.getZ()));
+        startGamePacket.setRotation(new Vector2f(entity.getRotation().getX(), entity.getRotation().getY()));
+
+        startGamePacket.setSeed(0);
+        startGamePacket.setDimensionId(entity.getDimension());
+        startGamePacket.setGeneratorId(0);
+        startGamePacket.setLevelGamemode(javaPacket.getGameMode().ordinal());
+        startGamePacket.setDifficulty(1);
+        startGamePacket.setDefaultSpawn(new Vector3i(packet.getX(), packet.getY(), packet.getZ()));
+        startGamePacket.setAcheivementsDisabled(true);
+        startGamePacket.setTime(0);
+        startGamePacket.setEduLevel(false);
+        startGamePacket.setEduFeaturesEnabled(false);
+        startGamePacket.setRainLevel(0);
+        startGamePacket.setLightningLevel(0);
+        startGamePacket.setMultiplayerGame(true);
+        startGamePacket.setBroadcastingToLan(true);
+        startGamePacket.getGamerules().add(new GameRule<>("showcoordinates", true));
+        startGamePacket.setPlatformBroadcastMode(GamePublishSetting.PUBLIC);
+        startGamePacket.setXblBroadcastMode(GamePublishSetting.PUBLIC);
+        startGamePacket.setCommandsEnabled(true);
+        startGamePacket.setTexturePacksRequired(false);
+        startGamePacket.setBonusChestEnabled(false);
+        startGamePacket.setStartingWithMap(false);
+        startGamePacket.setTrustingPlayers(true);
+        startGamePacket.setDefaultPlayerPermission(1);
+        startGamePacket.setServerChunkTickRange(4);
+        startGamePacket.setBehaviorPackLocked(false);
+        startGamePacket.setResourcePackLocked(false);
+        startGamePacket.setFromLockedWorldTemplate(false);
+        startGamePacket.setUsingMsaGamertagsOnly(false);
+        startGamePacket.setFromWorldTemplate(false);
+        startGamePacket.setWorldTemplateOptionLocked(false);
+
+        startGamePacket.setLevelId("world");
+        startGamePacket.setWorldName("world");
+        startGamePacket.setPremiumWorldTemplateId("00000000-0000-0000-0000-000000000000");
+        startGamePacket.setCurrentTick(0);
+        startGamePacket.setEnchantmentSeed(0);
+        startGamePacket.setMultiplayerCorrelationId("");
+        startGamePacket.setCachedPalette(Toolbox.CACHED_PALLETE);
+        startGamePacket.setItemEntries(Toolbox.ITEMS);
+        session.getUpstream().sendPacket(startGamePacket);
+
+        entity.moveAbsolute(new Vector3f(packet.getX(), packet.getY(), packet.getZ()), packet.getPitch(), packet.getYaw());
+
+        SetEntityDataPacket entityDataPacket = new SetEntityDataPacket();
+        entityDataPacket.setRuntimeEntityId(entity.getGeyserId());
+        entityDataPacket.getMetadata().putAll(entity.getMetadata());
+
+        session.getUpstream().sendPacket(entityDataPacket);
+
+        MovePlayerPacket movePlayerPacket = new MovePlayerPacket();
+        movePlayerPacket.setRuntimeEntityId(entity.getGeyserId());
+        movePlayerPacket.setPosition(new Vector3f(packet.getX(), packet.getY(), packet.getZ()));
+        movePlayerPacket.setRotation(new Vector3f(packet.getPitch(), packet.getYaw(), 0));
+        movePlayerPacket.setMode(MovePlayerPacket.Mode.NORMAL);
+        movePlayerPacket.setOnGround(true);
+        entity.setMovePending(false);
+
+        session.getUpstream().sendPacket(movePlayerPacket);
+        session.setSpawned(true);
+
+        System.out.println("resent! " + packet.getX() + " " + packet.getY() + " " + packet.getZ());
+    }
+}
diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/spawn/JavaSpawnExpOrbTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/spawn/JavaSpawnExpOrbTranslator.java
index c7f754dce..324909572 100644
--- a/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/spawn/JavaSpawnExpOrbTranslator.java
+++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/spawn/JavaSpawnExpOrbTranslator.java
@@ -1,19 +1,51 @@
+/*
+ * Copyright (c) 2019 GeyserMC. http://geysermc.org
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * @author GeyserMC
+ * @link https://github.com/GeyserMC/Geyser
+ */
+
 package org.geysermc.connector.network.translators.java.entity.spawn;
 
 import com.flowpowered.math.vector.Vector3f;
 import com.github.steveice10.mc.protocol.packet.ingame.server.entity.spawn.ServerSpawnExpOrbPacket;
 import com.nukkitx.protocol.bedrock.packet.SpawnExperienceOrbPacket;
+import org.geysermc.connector.entity.Entity;
+import org.geysermc.connector.entity.ExpOrbEntity;
+import org.geysermc.connector.entity.type.EntityType;
 import org.geysermc.connector.network.session.GeyserSession;
 import org.geysermc.connector.network.translators.PacketTranslator;
+import org.geysermc.connector.utils.EntityUtils;
 
 public class JavaSpawnExpOrbTranslator extends PacketTranslator<ServerSpawnExpOrbPacket> {
 
     @Override
     public void translate(ServerSpawnExpOrbPacket packet, GeyserSession session) {
-        SpawnExperienceOrbPacket spawnExperienceOrbPacket = new SpawnExperienceOrbPacket();
-        spawnExperienceOrbPacket.setPosition(new Vector3f(packet.getX(), packet.getY(), packet.getZ()));
-        spawnExperienceOrbPacket.setAmount(packet.getExp());
+        Vector3f position = new Vector3f(packet.getX(), packet.getY(), packet.getZ());
+        Entity entity = new ExpOrbEntity(packet.getExp(), packet.getEntityId(), session.getEntityCache().getNextEntityId().incrementAndGet(),
+                EntityType.EXPERIENCE_ORB, position, new Vector3f(0, 0, 0), new Vector3f(0, 0, 0));
 
-        session.getUpstream().sendPacket(spawnExperienceOrbPacket);
+        if (entity == null)
+            return;
+
+        session.getEntityCache().spawnEntity(entity);
     }
 }
diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/spawn/JavaSpawnGlobalEntityTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/spawn/JavaSpawnGlobalEntityTranslator.java
new file mode 100644
index 000000000..cb6b9f126
--- /dev/null
+++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/spawn/JavaSpawnGlobalEntityTranslator.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2019 GeyserMC. http://geysermc.org
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * @author GeyserMC
+ * @link https://github.com/GeyserMC/Geyser
+ */
+
+package org.geysermc.connector.network.translators.java.entity.spawn;
+
+import com.flowpowered.math.vector.Vector3f;
+import com.github.steveice10.mc.protocol.packet.ingame.server.entity.spawn.ServerSpawnGlobalEntityPacket;
+import org.geysermc.connector.entity.Entity;
+import org.geysermc.connector.entity.type.EntityType;
+import org.geysermc.connector.network.session.GeyserSession;
+import org.geysermc.connector.network.translators.PacketTranslator;
+
+public class JavaSpawnGlobalEntityTranslator extends PacketTranslator<ServerSpawnGlobalEntityPacket> {
+
+    @Override
+    public void translate(ServerSpawnGlobalEntityPacket packet, GeyserSession session) {
+        Vector3f position = new Vector3f(packet.getX(), packet.getY(), packet.getZ());
+
+        // Currently GlobalEntityType only has a lightning bolt
+        Entity entity = new Entity(packet.getEntityId(), session.getEntityCache().getNextEntityId().incrementAndGet(),
+                EntityType.LIGHTNING_BOLT, position, new Vector3f(0, 0, 0), new Vector3f(0, 0, 0));
+
+        if (entity == null)
+            return;
+
+        session.getEntityCache().spawnEntity(entity);
+    }
+}
diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/spawn/JavaSpawnMobTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/spawn/JavaSpawnMobTranslator.java
new file mode 100644
index 000000000..93ff22a37
--- /dev/null
+++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/spawn/JavaSpawnMobTranslator.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2019 GeyserMC. http://geysermc.org
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * @author GeyserMC
+ * @link https://github.com/GeyserMC/Geyser
+ */
+
+package org.geysermc.connector.network.translators.java.entity.spawn;
+
+import com.flowpowered.math.vector.Vector3f;
+import com.github.steveice10.mc.protocol.packet.ingame.server.entity.spawn.ServerSpawnMobPacket;
+import org.geysermc.connector.console.GeyserLogger;
+import org.geysermc.connector.entity.Entity;
+import org.geysermc.connector.entity.type.EntityType;
+import org.geysermc.connector.network.session.GeyserSession;
+import org.geysermc.connector.network.translators.PacketTranslator;
+import org.geysermc.connector.utils.EntityUtils;
+
+public class JavaSpawnMobTranslator extends PacketTranslator<ServerSpawnMobPacket> {
+
+    @Override
+    public void translate(ServerSpawnMobPacket packet, GeyserSession session) {
+        Vector3f position = new Vector3f(packet.getX(), packet.getY(), packet.getZ());
+        Vector3f motion = new Vector3f(packet.getMotionX(), packet.getMotionY(), packet.getMotionZ());
+        Vector3f rotation = new Vector3f(packet.getPitch(), packet.getYaw(), packet.getHeadYaw());
+
+        EntityType type = EntityUtils.toBedrockEntity(packet.getType());
+        if (type == null) {
+            GeyserLogger.DEFAULT.warning("Entity type " + packet.getType() + " was null.");
+            return;
+        }
+
+        Entity entity = new Entity(packet.getEntityId(), session.getEntityCache().getNextEntityId().incrementAndGet(),
+                type, position, motion, rotation);
+
+        if (entity == null)
+            return;
+
+        session.getEntityCache().spawnEntity(entity);
+    }
+}
diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/spawn/JavaSpawnObjectTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/spawn/JavaSpawnObjectTranslator.java
new file mode 100644
index 000000000..a484d4a39
--- /dev/null
+++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/spawn/JavaSpawnObjectTranslator.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2019 GeyserMC. http://geysermc.org
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * @author GeyserMC
+ * @link https://github.com/GeyserMC/Geyser
+ */
+
+package org.geysermc.connector.network.translators.java.entity.spawn;
+
+import com.flowpowered.math.vector.Vector3f;
+import com.github.steveice10.mc.protocol.data.game.entity.type.object.ObjectType;
+import com.github.steveice10.mc.protocol.packet.ingame.server.entity.spawn.ServerSpawnObjectPacket;
+import org.geysermc.connector.console.GeyserLogger;
+import org.geysermc.connector.entity.Entity;
+import org.geysermc.connector.entity.type.EntityType;
+import org.geysermc.connector.network.session.GeyserSession;
+import org.geysermc.connector.network.translators.PacketTranslator;
+import org.geysermc.connector.utils.EntityUtils;
+
+public class JavaSpawnObjectTranslator extends PacketTranslator<ServerSpawnObjectPacket> {
+
+    @Override
+    public void translate(ServerSpawnObjectPacket packet, GeyserSession session) {
+        if (packet.getType() == ObjectType.ITEM_FRAME)
+            return;
+
+        Vector3f position = new Vector3f(packet.getX(), packet.getY(), packet.getZ());
+        Vector3f motion = new Vector3f(packet.getMotionX(), packet.getMotionY(), packet.getMotionZ());
+        Vector3f rotation = new Vector3f(packet.getPitch(), packet.getYaw(), 0);
+
+        EntityType type = EntityUtils.toBedrockEntity(packet.getType());
+        if (type == null) {
+            GeyserLogger.DEFAULT.warning("Entity type " + packet.getType() + " was null.");
+            return;
+        }
+
+        Entity entity = new Entity(packet.getEntityId(), session.getEntityCache().getNextEntityId().incrementAndGet(),
+                type, position, motion, rotation);
+
+        if (entity == null)
+            return;
+
+        session.getEntityCache().spawnEntity(entity);
+    }
+}
diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/spawn/JavaSpawnPaintingTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/spawn/JavaSpawnPaintingTranslator.java
new file mode 100644
index 000000000..d98e6c655
--- /dev/null
+++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/spawn/JavaSpawnPaintingTranslator.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2019 GeyserMC. http://geysermc.org
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * @author GeyserMC
+ * @link https://github.com/GeyserMC/Geyser
+ */
+
+package org.geysermc.connector.network.translators.java.entity.spawn;
+
+import com.flowpowered.math.vector.Vector3f;
+import com.github.steveice10.mc.protocol.packet.ingame.server.entity.spawn.ServerSpawnPaintingPacket;
+import org.geysermc.connector.entity.Entity;
+import org.geysermc.connector.entity.type.EntityType;
+import org.geysermc.connector.network.session.GeyserSession;
+import org.geysermc.connector.network.translators.PacketTranslator;
+
+public class JavaSpawnPaintingTranslator extends PacketTranslator<ServerSpawnPaintingPacket> {
+
+    @Override
+    public void translate(ServerSpawnPaintingPacket packet, GeyserSession session) {
+        Vector3f position = new Vector3f(packet.getPosition().getX(), packet.getPosition().getY(), packet.getPosition().getZ());
+
+        Entity entity = new Entity(packet.getEntityId(), session.getEntityCache().getNextEntityId().incrementAndGet(),
+                EntityType.PAINTING, position, new Vector3f(0, 0, 0), new Vector3f(0, 0, 0));
+
+        if (entity == null)
+            return;
+
+        session.getEntityCache().spawnEntity(entity);
+    }
+}
diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/spawn/JavaSpawnPlayerTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/spawn/JavaSpawnPlayerTranslator.java
new file mode 100644
index 000000000..628ded6b9
--- /dev/null
+++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/spawn/JavaSpawnPlayerTranslator.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2019 GeyserMC. http://geysermc.org
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * @author GeyserMC
+ * @link https://github.com/GeyserMC/Geyser
+ */
+
+package org.geysermc.connector.network.translators.java.entity.spawn;
+
+import com.flowpowered.math.vector.Vector3f;
+import com.github.steveice10.mc.protocol.packet.ingame.server.entity.spawn.ServerSpawnPlayerPacket;
+import org.geysermc.connector.entity.Entity;
+import org.geysermc.connector.entity.PlayerEntity;
+import org.geysermc.connector.entity.type.EntityType;
+import org.geysermc.connector.network.session.GeyserSession;
+import org.geysermc.connector.network.translators.PacketTranslator;
+
+public class JavaSpawnPlayerTranslator extends PacketTranslator<ServerSpawnPlayerPacket> {
+
+    @Override
+    public void translate(ServerSpawnPlayerPacket packet, GeyserSession session) {
+        Vector3f position = new Vector3f(packet.getX(), packet.getY(), packet.getZ());
+        Vector3f rotation = new Vector3f(packet.getPitch(), packet.getYaw(), 0);
+        Entity entity = new PlayerEntity(packet.getUUID(), packet.getEntityId(), session.getEntityCache().getNextEntityId().incrementAndGet(),
+                EntityType.EXPERIENCE_ORB, position, new Vector3f(0, 0, 0), rotation);
+
+        if (entity == null)
+            return;
+
+        session.getEntityCache().spawnEntity(entity);
+    }
+}
diff --git a/connector/src/main/java/org/geysermc/connector/utils/EntityUtils.java b/connector/src/main/java/org/geysermc/connector/utils/EntityUtils.java
index 50b616ea5..15c86d9b8 100644
--- a/connector/src/main/java/org/geysermc/connector/utils/EntityUtils.java
+++ b/connector/src/main/java/org/geysermc/connector/utils/EntityUtils.java
@@ -1,6 +1,7 @@
 package org.geysermc.connector.utils;
 
 import com.github.steveice10.mc.protocol.data.game.entity.type.MobType;
+import com.github.steveice10.mc.protocol.data.game.entity.type.object.ObjectType;
 import org.geysermc.connector.entity.type.EntityType;
 
 public class EntityUtils {
@@ -20,4 +21,12 @@ public class EntityUtils {
             return null;
         }
     }
+
+    public static EntityType toBedrockEntity(ObjectType type) {
+        try {
+            return EntityType.valueOf(type.name());
+        } catch (IllegalArgumentException ex) {
+            return null;
+        }
+    }
 }
diff --git a/connector/src/main/java/org/geysermc/connector/utils/Toolbox.java b/connector/src/main/java/org/geysermc/connector/utils/Toolbox.java
index 4386a4f4b..f8464c104 100644
--- a/connector/src/main/java/org/geysermc/connector/utils/Toolbox.java
+++ b/connector/src/main/java/org/geysermc/connector/utils/Toolbox.java
@@ -1,23 +1,17 @@
 package org.geysermc.connector.utils;
 
 import com.fasterxml.jackson.core.type.TypeReference;
-import com.fasterxml.jackson.core.util.DefaultPrettyPrinter;
 import com.fasterxml.jackson.databind.ObjectMapper;
-import com.fasterxml.jackson.databind.ObjectWriter;
 import com.nukkitx.network.VarInts;
 import com.nukkitx.protocol.bedrock.packet.StartGamePacket;
 import com.nukkitx.protocol.bedrock.v361.BedrockUtils;
 import io.netty.buffer.ByteBuf;
 import io.netty.buffer.Unpooled;
-import org.apache.logging.log4j.core.util.Patterns;
 import org.geysermc.connector.network.translators.item.BedrockItem;
-import org.geysermc.connector.network.translators.item.DyeColor;
 import org.geysermc.connector.network.translators.item.JavaItem;
 
-import java.io.File;
 import java.io.InputStream;
 import java.util.*;
-import java.util.regex.Pattern;
 
 public class Toolbox {
 

From 1d1cdd4f4204c2560d2d035df269d8fac8e206a8 Mon Sep 17 00:00:00 2001
From: RednedEpic <redned@retronixgames.x10host.com>
Date: Sat, 3 Aug 2019 01:56:54 -0500
Subject: [PATCH 03/10] Set Ipv4 port for BedrockPong

---
 .../geysermc/connector/network/ConnectorServerEventHandler.java  | 1 +
 1 file changed, 1 insertion(+)

diff --git a/connector/src/main/java/org/geysermc/connector/network/ConnectorServerEventHandler.java b/connector/src/main/java/org/geysermc/connector/network/ConnectorServerEventHandler.java
index 66db7e426..7bb6dfe91 100644
--- a/connector/src/main/java/org/geysermc/connector/network/ConnectorServerEventHandler.java
+++ b/connector/src/main/java/org/geysermc/connector/network/ConnectorServerEventHandler.java
@@ -93,6 +93,7 @@ public class ConnectorServerEventHandler implements BedrockServerEventHandler {
         c.setSubMotd(pong.getSubMotd());
         c.setPlayerCount(pong.getPlayerCount());
         c.setMaximumPlayerCount(pong.getMaximumPlayerCount());
+        c.setIpv4Port(config.getBedrock().getPort());
 
         return c;
 

From ebd1e502f2dcfa9483c151721e966a083aa5b964 Mon Sep 17 00:00:00 2001
From: Logicism <blazewalker462@protonmail.com>
Date: Sat, 3 Aug 2019 18:01:16 -0700
Subject: [PATCH 04/10] Add Gamemode Change and Titles Times Translator w/
 Scoreboard Registry

---
 .../network/translators/TranslatorsInit.java       |  9 +++++++++
 .../translators/java/JavaJoinGameTranslator.java   | 13 +++++++++++++
 .../translators/java/JavaTitleTranslator.java      |  9 +++++----
 .../java/world/JavaNotifyClientTranslator.java     | 14 ++++++++++++++
 .../network/translators/scoreboard/Scoreboard.java |  2 +-
 5 files changed, 42 insertions(+), 5 deletions(-)

diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/TranslatorsInit.java b/connector/src/main/java/org/geysermc/connector/network/translators/TranslatorsInit.java
index 4357f9f65..0144bfe92 100644
--- a/connector/src/main/java/org/geysermc/connector/network/translators/TranslatorsInit.java
+++ b/connector/src/main/java/org/geysermc/connector/network/translators/TranslatorsInit.java
@@ -35,6 +35,9 @@ import com.github.steveice10.mc.protocol.packet.ingame.server.entity.ServerEntit
 import com.github.steveice10.mc.protocol.packet.ingame.server.entity.ServerEntityTeleportPacket;
 import com.github.steveice10.mc.protocol.packet.ingame.server.entity.ServerEntityVelocityPacket;
 import com.github.steveice10.mc.protocol.packet.ingame.server.entity.spawn.ServerSpawnExpOrbPacket;
+import com.github.steveice10.mc.protocol.packet.ingame.server.scoreboard.ServerDisplayScoreboardPacket;
+import com.github.steveice10.mc.protocol.packet.ingame.server.scoreboard.ServerScoreboardObjectivePacket;
+import com.github.steveice10.mc.protocol.packet.ingame.server.scoreboard.ServerUpdateScorePacket;
 import com.github.steveice10.mc.protocol.packet.ingame.server.window.ServerOpenWindowPacket;
 import com.github.steveice10.mc.protocol.packet.ingame.server.window.ServerSetSlotPacket;
 import com.github.steveice10.mc.protocol.packet.ingame.server.window.ServerWindowItemsPacket;
@@ -62,6 +65,9 @@ import org.geysermc.connector.network.translators.java.entity.JavaEntityPosition
 import org.geysermc.connector.network.translators.java.entity.JavaEntityTeleportTranslator;
 import org.geysermc.connector.network.translators.java.entity.JavaEntityVelocityTranslator;
 import org.geysermc.connector.network.translators.java.entity.spawn.JavaSpawnExpOrbTranslator;
+import org.geysermc.connector.network.translators.java.scoreboard.JavaScoreboardDisplayTranslator;
+import org.geysermc.connector.network.translators.java.scoreboard.JavaScoreboardObjectiveTranslator;
+import org.geysermc.connector.network.translators.java.scoreboard.JavaUpdateScoreTranslator;
 import org.geysermc.connector.network.translators.java.world.JavaNotifyClientTranslator;
 import org.geysermc.connector.network.translators.java.window.JavaOpenWindowTranslator;
 import org.geysermc.connector.network.translators.java.window.JavaSetSlotTranslator;
@@ -114,6 +120,9 @@ public class TranslatorsInit {
         Registry.registerJava(ServerWindowItemsPacket.class, new JavaWindowItemsTranslator());
         Registry.registerJava(ServerOpenWindowPacket.class, new JavaOpenWindowTranslator());
         Registry.registerJava(ServerSetSlotPacket.class, new JavaSetSlotTranslator());
+        Registry.registerJava(ServerScoreboardObjectivePacket.class, new JavaScoreboardObjectiveTranslator());
+        Registry.registerJava(ServerDisplayScoreboardPacket.class, new JavaScoreboardDisplayTranslator());
+        Registry.registerJava(ServerUpdateScorePacket.class, new JavaUpdateScoreTranslator());
 
         Registry.registerBedrock(AnimatePacket.class, new BedrockAnimateTranslator());
         Registry.registerBedrock(CommandRequestPacket.class, new BedrockCommandRequestTranslator());
diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaJoinGameTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaJoinGameTranslator.java
index a43fd4a43..d44252233 100644
--- a/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaJoinGameTranslator.java
+++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaJoinGameTranslator.java
@@ -26,9 +26,11 @@
 package org.geysermc.connector.network.translators.java;
 
 import com.flowpowered.math.vector.Vector3f;
+import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode;
 import com.github.steveice10.mc.protocol.packet.ingame.server.ServerJoinGamePacket;
 import com.nukkitx.protocol.bedrock.packet.AdventureSettingsPacket;
 import com.nukkitx.protocol.bedrock.packet.LevelChunkPacket;
+import com.nukkitx.protocol.bedrock.packet.SetPlayerGameTypePacket;
 import org.geysermc.connector.network.session.GeyserSession;
 import org.geysermc.connector.network.translators.PacketTranslator;
 import org.geysermc.connector.network.translators.TranslatorsInit;
@@ -41,6 +43,17 @@ public class JavaJoinGameTranslator extends PacketTranslator<ServerJoinGamePacke
         bedrockPacket.setUniqueEntityId(packet.getEntityId());
         session.getUpstream().sendPacketImmediately(bedrockPacket);
 
+        int gamemode = 0;
+        if (packet.getGameMode().equals(GameMode.CREATIVE)) {
+            gamemode = 1;
+        } else if (packet.getGameMode().equals(GameMode.ADVENTURE)) {
+            gamemode = 2;
+        } else if (packet.getGameMode().equals(GameMode.SPECTATOR)) {
+            gamemode = 3;
+        }
+        SetPlayerGameTypePacket playerGameTypePacket = new SetPlayerGameTypePacket();
+        playerGameTypePacket.setGamemode(gamemode);
+
         Vector3f pos = new Vector3f(0, 0, 0);
         int chunkX = pos.getFloorX() >> 4;
         int chunkZ = pos.getFloorZ() >> 4;
diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaTitleTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaTitleTranslator.java
index c9239fe29..e3d9bbead 100644
--- a/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaTitleTranslator.java
+++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaTitleTranslator.java
@@ -54,12 +54,13 @@ public class JavaTitleTranslator extends PacketTranslator<ServerTitlePacket> {
                 titlePacket.setType(SetTitlePacket.Type.SET_ACTIONBAR_MESSAGE);
                 titlePacket.setText(packet.getActionBar().getFullText());
                 break;
+            case TIMES:
+                titlePacket.setFadeInTime(packet.getFadeIn());
+                titlePacket.setFadeOutTime(packet.getFadeOut());
+                titlePacket.setStayTime(packet.getStay());
+                break;
         }
 
-        titlePacket.setFadeInTime(packet.getFadeIn());
-        titlePacket.setFadeOutTime(packet.getFadeOut());
-        titlePacket.setStayTime(packet.getStay());
-
         session.getUpstream().sendPacket(titlePacket);
     }
 }
diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaNotifyClientTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaNotifyClientTranslator.java
index 65c25a1d3..8ef64503f 100644
--- a/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaNotifyClientTranslator.java
+++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaNotifyClientTranslator.java
@@ -26,8 +26,10 @@
 package org.geysermc.connector.network.translators.java.world;
 
 import com.flowpowered.math.vector.Vector3f;
+import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode;
 import com.github.steveice10.mc.protocol.packet.ingame.server.world.ServerNotifyClientPacket;
 import com.nukkitx.protocol.bedrock.packet.LevelEventPacket;
+import com.nukkitx.protocol.bedrock.packet.SetPlayerGameTypePacket;
 import org.geysermc.connector.network.session.GeyserSession;
 import org.geysermc.connector.network.translators.PacketTranslator;
 
@@ -54,6 +56,18 @@ public class JavaNotifyClientTranslator extends PacketTranslator<ServerNotifyCli
 
                 session.getUpstream().sendPacket(stopRainPacket);
                 break;
+            case CHANGE_GAMEMODE:
+                int gamemode = 0;
+                if (packet.getValue().equals(GameMode.CREATIVE)) {
+                    gamemode = 1;
+                } else if (packet.getValue().equals(GameMode.ADVENTURE)) {
+                    gamemode = 2;
+                } else if (packet.getValue().equals(GameMode.SPECTATOR)) {
+                    gamemode = 3;
+                }
+                SetPlayerGameTypePacket playerGameTypePacket = new SetPlayerGameTypePacket();
+                playerGameTypePacket.setGamemode(gamemode);
+                break;
             case ENTER_CREDITS:
                 // ShowCreditsPacket showCreditsPacket = new ShowCreditsPacket();
                 // showCreditsPacket.setStatus(ShowCreditsPacket.Status.START_CREDITS);
diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/scoreboard/Scoreboard.java b/connector/src/main/java/org/geysermc/connector/network/translators/scoreboard/Scoreboard.java
index 6388b6267..9fad79bbb 100644
--- a/connector/src/main/java/org/geysermc/connector/network/translators/scoreboard/Scoreboard.java
+++ b/connector/src/main/java/org/geysermc/connector/network/translators/scoreboard/Scoreboard.java
@@ -106,7 +106,7 @@ public class Scoreboard {
         displayObjectivePacket.setDisplayName(objective.getDisplayName());
         displayObjectivePacket.setCriteria("dummy");
         displayObjectivePacket.setDisplaySlot("sidebar");
-        displayObjectivePacket.setSortOrder(2);
+        displayObjectivePacket.setSortOrder(1);
         session.getUpstream().sendPacket(displayObjectivePacket);
 
         Map<String, Score> fakeMap = new HashMap<String, Score>();

From fc50242c47bf9cf3fe6bc458f229a4924dcaa889 Mon Sep 17 00:00:00 2001
From: Logicism <blazewalker462@protonmail.com>
Date: Sat, 3 Aug 2019 18:20:15 -0700
Subject: [PATCH 05/10] Fix Redudant Gamemode Code

---
 .../network/translators/java/JavaJoinGameTranslator.java | 9 +--------
 .../java/world/JavaNotifyClientTranslator.java           | 9 +--------
 2 files changed, 2 insertions(+), 16 deletions(-)

diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaJoinGameTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaJoinGameTranslator.java
index d44252233..7a5c47444 100644
--- a/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaJoinGameTranslator.java
+++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaJoinGameTranslator.java
@@ -43,14 +43,7 @@ public class JavaJoinGameTranslator extends PacketTranslator<ServerJoinGamePacke
         bedrockPacket.setUniqueEntityId(packet.getEntityId());
         session.getUpstream().sendPacketImmediately(bedrockPacket);
 
-        int gamemode = 0;
-        if (packet.getGameMode().equals(GameMode.CREATIVE)) {
-            gamemode = 1;
-        } else if (packet.getGameMode().equals(GameMode.ADVENTURE)) {
-            gamemode = 2;
-        } else if (packet.getGameMode().equals(GameMode.SPECTATOR)) {
-            gamemode = 3;
-        }
+        int gamemode = packet.getGameMode().ordinal();
         SetPlayerGameTypePacket playerGameTypePacket = new SetPlayerGameTypePacket();
         playerGameTypePacket.setGamemode(gamemode);
 
diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaNotifyClientTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaNotifyClientTranslator.java
index 8ef64503f..f94d726d5 100644
--- a/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaNotifyClientTranslator.java
+++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaNotifyClientTranslator.java
@@ -57,14 +57,7 @@ public class JavaNotifyClientTranslator extends PacketTranslator<ServerNotifyCli
                 session.getUpstream().sendPacket(stopRainPacket);
                 break;
             case CHANGE_GAMEMODE:
-                int gamemode = 0;
-                if (packet.getValue().equals(GameMode.CREATIVE)) {
-                    gamemode = 1;
-                } else if (packet.getValue().equals(GameMode.ADVENTURE)) {
-                    gamemode = 2;
-                } else if (packet.getValue().equals(GameMode.SPECTATOR)) {
-                    gamemode = 3;
-                }
+                int gamemode = ((GameMode) packet.getValue()).ordinal();
                 SetPlayerGameTypePacket playerGameTypePacket = new SetPlayerGameTypePacket();
                 playerGameTypePacket.setGamemode(gamemode);
                 break;

From 128769dee81356979de08b5a73d5ef2921f8afa6 Mon Sep 17 00:00:00 2001
From: RednedEpic <redned@retronixgames.x10host.com>
Date: Sat, 3 Aug 2019 22:24:53 -0500
Subject: [PATCH 06/10] Minor refactors and tweaks, update README

---
 README.md                                     |  9 +++-
 .../network/session/GeyserSession.java        |  7 ++-
 .../session/cache/ScoreboardCache.java        |  2 +-
 .../network/translators/TranslatorsInit.java  |  4 +-
 .../JavaDisplayScoreboardTranslator.java      | 46 +++++++++++++++++++
 .../JavaScoreboardDisplayTranslator.java      | 19 --------
 .../JavaScoreboardObjectiveTranslator.java    | 30 +++++++++++-
 .../JavaScoreboardTeamTranslator.java         | 17 -------
 .../java/scoreboard/JavaTeamTranslator.java   | 38 +++++++++++++++
 .../scoreboard/JavaUpdateScoreTranslator.java | 30 +++++++++++-
 .../translators => }/scoreboard/Score.java    |  2 +-
 .../scoreboard/Scoreboard.java                |  5 +-
 .../scoreboard/ScoreboardObjective.java       |  3 +-
 13 files changed, 161 insertions(+), 51 deletions(-)
 create mode 100644 connector/src/main/java/org/geysermc/connector/network/translators/java/scoreboard/JavaDisplayScoreboardTranslator.java
 delete mode 100644 connector/src/main/java/org/geysermc/connector/network/translators/java/scoreboard/JavaScoreboardDisplayTranslator.java
 delete mode 100644 connector/src/main/java/org/geysermc/connector/network/translators/java/scoreboard/JavaScoreboardTeamTranslator.java
 create mode 100644 connector/src/main/java/org/geysermc/connector/network/translators/java/scoreboard/JavaTeamTranslator.java
 rename connector/src/main/java/org/geysermc/connector/{network/translators => }/scoreboard/Score.java (96%)
 rename connector/src/main/java/org/geysermc/connector/{network/translators => }/scoreboard/Scoreboard.java (98%)
 rename connector/src/main/java/org/geysermc/connector/{network/translators => }/scoreboard/ScoreboardObjective.java (97%)

diff --git a/README.md b/README.md
index 17dabc0ac..0f171dcab 100644
--- a/README.md
+++ b/README.md
@@ -24,9 +24,14 @@ Links:
 - [x] Join detection from remote
 - [x] Online mode/auth support
 - [x] Chat/command support
+- [ ] Scoreboard
+  - [x] Objective-based scoreboards
+  - [ ] Team-based scoreboards
 - [ ] Inventory support
-- [ ] Movement support
-- [ ] Entity support
+  - [x] Inventory viewing
+  - [ ] Inventory movement (transactions)
+- [ ] Player movement support
+- [x] Entity support (experimental)
 - [ ] Chunks
 - [ ] Block break/place support
 
diff --git a/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java b/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java
index 2d0b03bf9..3d5140165 100644
--- a/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java
+++ b/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java
@@ -150,12 +150,13 @@ public class GeyserSession implements PlayerSession, Player {
                 public void disconnected(DisconnectedEvent event) {
                     loggedIn = false;
                     connector.getLogger().info(authenticationData.getName() + " has disconnected from remote java server on address " + remoteServer.getAddress() + " because of " + event.getReason());
-                    upstream.disconnect(event.getReason());
+                    disconnect(event.getReason());
                 }
 
                 @Override
                 public void packetReceived(PacketReceivedEvent event) {
-                    Registry.JAVA.translate(event.getPacket().getClass(), event.getPacket(), GeyserSession.this);
+                    if (!closed)
+                        Registry.JAVA.translate(event.getPacket().getClass(), event.getPacket(), GeyserSession.this);
                 }
             });
 
@@ -175,6 +176,8 @@ public class GeyserSession implements PlayerSession, Player {
                 upstream.disconnect(reason);
             }
         }
+
+        closed = true;
     }
 
     @Override
diff --git a/connector/src/main/java/org/geysermc/connector/network/session/cache/ScoreboardCache.java b/connector/src/main/java/org/geysermc/connector/network/session/cache/ScoreboardCache.java
index 01efa9693..147a5355d 100644
--- a/connector/src/main/java/org/geysermc/connector/network/session/cache/ScoreboardCache.java
+++ b/connector/src/main/java/org/geysermc/connector/network/session/cache/ScoreboardCache.java
@@ -29,7 +29,7 @@ import com.nukkitx.protocol.bedrock.packet.RemoveObjectivePacket;
 import lombok.Getter;
 import lombok.Setter;
 import org.geysermc.connector.network.session.GeyserSession;
-import org.geysermc.connector.network.translators.scoreboard.Scoreboard;
+import org.geysermc.connector.scoreboard.Scoreboard;
 
 public class ScoreboardCache {
 
diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/TranslatorsInit.java b/connector/src/main/java/org/geysermc/connector/network/translators/TranslatorsInit.java
index a5dc1ffcb..cacdf0904 100644
--- a/connector/src/main/java/org/geysermc/connector/network/translators/TranslatorsInit.java
+++ b/connector/src/main/java/org/geysermc/connector/network/translators/TranslatorsInit.java
@@ -85,7 +85,7 @@ import org.geysermc.connector.network.translators.java.entity.spawn.JavaSpawnMob
 import org.geysermc.connector.network.translators.java.entity.spawn.JavaSpawnObjectTranslator;
 import org.geysermc.connector.network.translators.java.entity.spawn.JavaSpawnPaintingTranslator;
 import org.geysermc.connector.network.translators.java.entity.spawn.JavaSpawnPlayerTranslator;
-import org.geysermc.connector.network.translators.java.scoreboard.JavaScoreboardDisplayTranslator;
+import org.geysermc.connector.network.translators.java.scoreboard.JavaDisplayScoreboardTranslator;
 import org.geysermc.connector.network.translators.java.scoreboard.JavaScoreboardObjectiveTranslator;
 import org.geysermc.connector.network.translators.java.scoreboard.JavaUpdateScoreTranslator;
 import org.geysermc.connector.network.translators.java.world.JavaNotifyClientTranslator;
@@ -155,7 +155,7 @@ public class TranslatorsInit {
         Registry.registerJava(ServerOpenWindowPacket.class, new JavaOpenWindowTranslator());
         Registry.registerJava(ServerSetSlotPacket.class, new JavaSetSlotTranslator());
         Registry.registerJava(ServerScoreboardObjectivePacket.class, new JavaScoreboardObjectiveTranslator());
-        Registry.registerJava(ServerDisplayScoreboardPacket.class, new JavaScoreboardDisplayTranslator());
+        Registry.registerJava(ServerDisplayScoreboardPacket.class, new JavaDisplayScoreboardTranslator());
         Registry.registerJava(ServerUpdateScorePacket.class, new JavaUpdateScoreTranslator());
 
         Registry.registerBedrock(AnimatePacket.class, new BedrockAnimateTranslator());
diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/scoreboard/JavaDisplayScoreboardTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/scoreboard/JavaDisplayScoreboardTranslator.java
new file mode 100644
index 000000000..429857aa3
--- /dev/null
+++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/scoreboard/JavaDisplayScoreboardTranslator.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2019 GeyserMC. http://geysermc.org
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * @author GeyserMC
+ * @link https://github.com/GeyserMC/Geyser
+ */
+
+package org.geysermc.connector.network.translators.java.scoreboard;
+
+import com.github.steveice10.mc.protocol.packet.ingame.server.scoreboard.ServerDisplayScoreboardPacket;
+import org.geysermc.connector.network.session.GeyserSession;
+import org.geysermc.connector.network.session.cache.ScoreboardCache;
+import org.geysermc.connector.network.translators.PacketTranslator;
+import org.geysermc.connector.scoreboard.Scoreboard;
+
+public class JavaDisplayScoreboardTranslator extends PacketTranslator<ServerDisplayScoreboardPacket> {
+
+    @Override
+    public void translate(ServerDisplayScoreboardPacket packet, GeyserSession session) {
+        try {
+            ScoreboardCache cache = session.getScoreboardCache();
+            Scoreboard scoreboard = new Scoreboard(session);
+            cache.setScoreboard(scoreboard);
+        } catch (Exception ex) {
+            ex.printStackTrace();
+        }
+    }
+}
diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/scoreboard/JavaScoreboardDisplayTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/scoreboard/JavaScoreboardDisplayTranslator.java
deleted file mode 100644
index db4eef2f2..000000000
--- a/connector/src/main/java/org/geysermc/connector/network/translators/java/scoreboard/JavaScoreboardDisplayTranslator.java
+++ /dev/null
@@ -1,19 +0,0 @@
-package org.geysermc.connector.network.translators.java.scoreboard;
-
-import com.github.steveice10.mc.protocol.packet.ingame.server.scoreboard.ServerDisplayScoreboardPacket;
-import org.geysermc.connector.network.session.GeyserSession;
-import org.geysermc.connector.network.session.cache.ScoreboardCache;
-import org.geysermc.connector.network.translators.PacketTranslator;
-import org.geysermc.connector.network.translators.scoreboard.Scoreboard;
-
-public class JavaScoreboardDisplayTranslator extends PacketTranslator<ServerDisplayScoreboardPacket> {
-    @Override
-    public void translate(ServerDisplayScoreboardPacket packet, GeyserSession session) {
-        try {
-            ScoreboardCache cache = session.getScoreboardCache();
-            Scoreboard scoreboard = new Scoreboard(session);
-        } catch (Exception ex) {
-            ex.printStackTrace();
-        }
-    }
-}
diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/scoreboard/JavaScoreboardObjectiveTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/scoreboard/JavaScoreboardObjectiveTranslator.java
index 7076d1c66..fb60217cd 100644
--- a/connector/src/main/java/org/geysermc/connector/network/translators/java/scoreboard/JavaScoreboardObjectiveTranslator.java
+++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/scoreboard/JavaScoreboardObjectiveTranslator.java
@@ -1,14 +1,40 @@
+/*
+ * Copyright (c) 2019 GeyserMC. http://geysermc.org
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * @author GeyserMC
+ * @link https://github.com/GeyserMC/Geyser
+ */
+
 package org.geysermc.connector.network.translators.java.scoreboard;
 
 import com.github.steveice10.mc.protocol.packet.ingame.server.scoreboard.ServerScoreboardObjectivePacket;
 import org.geysermc.connector.network.session.GeyserSession;
 import org.geysermc.connector.network.session.cache.ScoreboardCache;
 import org.geysermc.connector.network.translators.PacketTranslator;
-import org.geysermc.connector.network.translators.scoreboard.Scoreboard;
-import org.geysermc.connector.network.translators.scoreboard.ScoreboardObjective;
+import org.geysermc.connector.scoreboard.Scoreboard;
+import org.geysermc.connector.scoreboard.ScoreboardObjective;
 import org.geysermc.connector.utils.MessageUtils;
 
 public class JavaScoreboardObjectiveTranslator extends PacketTranslator<ServerScoreboardObjectivePacket> {
+
     @Override
     public void translate(ServerScoreboardObjectivePacket packet, GeyserSession session) {
         try {
diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/scoreboard/JavaScoreboardTeamTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/scoreboard/JavaScoreboardTeamTranslator.java
deleted file mode 100644
index 85845a4ff..000000000
--- a/connector/src/main/java/org/geysermc/connector/network/translators/java/scoreboard/JavaScoreboardTeamTranslator.java
+++ /dev/null
@@ -1,17 +0,0 @@
-package org.geysermc.connector.network.translators.java.scoreboard;
-
-import com.github.steveice10.mc.protocol.packet.ingame.server.scoreboard.ServerTeamPacket;
-import com.nukkitx.protocol.bedrock.packet.SetScorePacket;
-import org.geysermc.connector.network.session.GeyserSession;
-import org.geysermc.connector.network.session.cache.ScoreboardCache;
-import org.geysermc.connector.network.translators.PacketTranslator;
-import org.geysermc.connector.network.translators.scoreboard.Scoreboard;
-import org.geysermc.connector.network.translators.scoreboard.ScoreboardObjective;
-import org.geysermc.connector.utils.MessageUtils;
-
-public class JavaScoreboardTeamTranslator extends PacketTranslator<ServerTeamPacket> {
-    @Override
-    public void translate(ServerTeamPacket packet, GeyserSession session) {
-
-    }
-}
diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/scoreboard/JavaTeamTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/scoreboard/JavaTeamTranslator.java
new file mode 100644
index 000000000..aa364fef7
--- /dev/null
+++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/scoreboard/JavaTeamTranslator.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2019 GeyserMC. http://geysermc.org
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * @author GeyserMC
+ * @link https://github.com/GeyserMC/Geyser
+ */
+
+package org.geysermc.connector.network.translators.java.scoreboard;
+
+import com.github.steveice10.mc.protocol.packet.ingame.server.scoreboard.ServerTeamPacket;
+import org.geysermc.connector.network.session.GeyserSession;
+import org.geysermc.connector.network.translators.PacketTranslator;
+
+public class JavaTeamTranslator extends PacketTranslator<ServerTeamPacket> {
+
+    @Override
+    public void translate(ServerTeamPacket packet, GeyserSession session) {
+
+    }
+}
diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/scoreboard/JavaUpdateScoreTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/scoreboard/JavaUpdateScoreTranslator.java
index 3f67ed192..83b01ae02 100644
--- a/connector/src/main/java/org/geysermc/connector/network/translators/java/scoreboard/JavaUpdateScoreTranslator.java
+++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/scoreboard/JavaUpdateScoreTranslator.java
@@ -1,3 +1,28 @@
+/*
+ * Copyright (c) 2019 GeyserMC. http://geysermc.org
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * @author GeyserMC
+ * @link https://github.com/GeyserMC/Geyser
+ */
+
 package org.geysermc.connector.network.translators.java.scoreboard;
 
 import com.github.steveice10.mc.protocol.packet.ingame.server.scoreboard.ServerUpdateScorePacket;
@@ -5,10 +30,11 @@ import com.nukkitx.protocol.bedrock.packet.SetScorePacket;
 import org.geysermc.connector.network.session.GeyserSession;
 import org.geysermc.connector.network.session.cache.ScoreboardCache;
 import org.geysermc.connector.network.translators.PacketTranslator;
-import org.geysermc.connector.network.translators.scoreboard.Scoreboard;
-import org.geysermc.connector.network.translators.scoreboard.ScoreboardObjective;
+import org.geysermc.connector.scoreboard.Scoreboard;
+import org.geysermc.connector.scoreboard.ScoreboardObjective;
 
 public class JavaUpdateScoreTranslator extends PacketTranslator<ServerUpdateScorePacket> {
+
     @Override
     public void translate(ServerUpdateScorePacket packet, GeyserSession session) {
         try {
diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/scoreboard/Score.java b/connector/src/main/java/org/geysermc/connector/scoreboard/Score.java
similarity index 96%
rename from connector/src/main/java/org/geysermc/connector/network/translators/scoreboard/Score.java
rename to connector/src/main/java/org/geysermc/connector/scoreboard/Score.java
index 764d9bc7c..9535b0947 100644
--- a/connector/src/main/java/org/geysermc/connector/network/translators/scoreboard/Score.java
+++ b/connector/src/main/java/org/geysermc/connector/scoreboard/Score.java
@@ -23,7 +23,7 @@
  * @link https://github.com/GeyserMC/Geyser
  */
 
-package org.geysermc.connector.network.translators.scoreboard;
+package org.geysermc.connector.scoreboard;
 
 import com.nukkitx.protocol.bedrock.packet.SetScorePacket;
 import lombok.Getter;
diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/scoreboard/Scoreboard.java b/connector/src/main/java/org/geysermc/connector/scoreboard/Scoreboard.java
similarity index 98%
rename from connector/src/main/java/org/geysermc/connector/network/translators/scoreboard/Scoreboard.java
rename to connector/src/main/java/org/geysermc/connector/scoreboard/Scoreboard.java
index 9fad79bbb..6b6337993 100644
--- a/connector/src/main/java/org/geysermc/connector/network/translators/scoreboard/Scoreboard.java
+++ b/connector/src/main/java/org/geysermc/connector/scoreboard/Scoreboard.java
@@ -23,7 +23,7 @@
  * @link https://github.com/GeyserMC/Geyser
  */
 
-package org.geysermc.connector.network.translators.scoreboard;
+package org.geysermc.connector.scoreboard;
 
 import com.nukkitx.protocol.bedrock.data.ScoreInfo;
 import com.nukkitx.protocol.bedrock.packet.RemoveObjectivePacket;
@@ -97,6 +97,9 @@ public class Scoreboard {
     }
 
     public void onUpdate() {
+        if (objective == null)
+            return;
+
         RemoveObjectivePacket removeObjectivePacket = new RemoveObjectivePacket();
         removeObjectivePacket.setObjectiveId(objective.getObjectiveName());
         session.getUpstream().sendPacket(removeObjectivePacket);
diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/scoreboard/ScoreboardObjective.java b/connector/src/main/java/org/geysermc/connector/scoreboard/ScoreboardObjective.java
similarity index 97%
rename from connector/src/main/java/org/geysermc/connector/network/translators/scoreboard/ScoreboardObjective.java
rename to connector/src/main/java/org/geysermc/connector/scoreboard/ScoreboardObjective.java
index a140ff677..f90c474e5 100644
--- a/connector/src/main/java/org/geysermc/connector/network/translators/scoreboard/ScoreboardObjective.java
+++ b/connector/src/main/java/org/geysermc/connector/scoreboard/ScoreboardObjective.java
@@ -23,12 +23,11 @@
  * @link https://github.com/GeyserMC/Geyser
  */
 
-package org.geysermc.connector.network.translators.scoreboard;
+package org.geysermc.connector.scoreboard;
 
 import com.nukkitx.protocol.bedrock.packet.SetScorePacket;
 import lombok.Getter;
 import lombok.Setter;
-import org.geysermc.connector.console.GeyserLogger;
 
 import java.util.HashMap;
 import java.util.Map;

From 5be882b0405a49234c386db2c1084f4434c88d9c Mon Sep 17 00:00:00 2001
From: RednedEpic <redned@retronixgames.x10host.com>
Date: Sun, 4 Aug 2019 15:53:39 -0500
Subject: [PATCH 07/10] Fix wrong EntityType in JavaSpawnPlayerTranslator

---
 .../java/entity/spawn/JavaSpawnPlayerTranslator.java            | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/spawn/JavaSpawnPlayerTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/spawn/JavaSpawnPlayerTranslator.java
index 628ded6b9..838dadce3 100644
--- a/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/spawn/JavaSpawnPlayerTranslator.java
+++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/spawn/JavaSpawnPlayerTranslator.java
@@ -40,7 +40,7 @@ public class JavaSpawnPlayerTranslator extends PacketTranslator<ServerSpawnPlaye
         Vector3f position = new Vector3f(packet.getX(), packet.getY(), packet.getZ());
         Vector3f rotation = new Vector3f(packet.getPitch(), packet.getYaw(), 0);
         Entity entity = new PlayerEntity(packet.getUUID(), packet.getEntityId(), session.getEntityCache().getNextEntityId().incrementAndGet(),
-                EntityType.EXPERIENCE_ORB, position, new Vector3f(0, 0, 0), rotation);
+                EntityType.PLAYER, position, new Vector3f(0, 0, 0), rotation);
 
         if (entity == null)
             return;

From 9399296908454af87ba4c863f013559ad70de483 Mon Sep 17 00:00:00 2001
From: RednedEpic <redned@retronixgames.x10host.com>
Date: Sun, 4 Aug 2019 17:23:19 -0500
Subject: [PATCH 08/10] Fix NBT translations (for the most part)

---
 README.md                                     |  1 +
 .../translators/item/ItemTranslator.java      | 46 +++++++++----------
 2 files changed, 22 insertions(+), 25 deletions(-)

diff --git a/README.md b/README.md
index 0f171dcab..daab3c055 100644
--- a/README.md
+++ b/README.md
@@ -29,6 +29,7 @@ Links:
   - [ ] Team-based scoreboards
 - [ ] Inventory support
   - [x] Inventory viewing
+  - [x] NBT data (experimental)
   - [ ] Inventory movement (transactions)
 - [ ] Player movement support
 - [x] Entity support (experimental)
diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/item/ItemTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/item/ItemTranslator.java
index a1fd95179..4579c9faa 100644
--- a/connector/src/main/java/org/geysermc/connector/network/translators/item/ItemTranslator.java
+++ b/connector/src/main/java/org/geysermc/connector/network/translators/item/ItemTranslator.java
@@ -26,6 +26,7 @@
 package org.geysermc.connector.network.translators.item;
 
 import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack;
+import com.github.steveice10.mc.protocol.data.message.Message;
 import com.github.steveice10.opennbt.tag.builtin.ByteArrayTag;
 import com.github.steveice10.opennbt.tag.builtin.ByteTag;
 import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
@@ -40,6 +41,7 @@ import com.github.steveice10.opennbt.tag.builtin.ShortTag;
 import com.github.steveice10.opennbt.tag.builtin.StringTag;
 import com.github.steveice10.opennbt.tag.builtin.Tag;
 import com.nukkitx.protocol.bedrock.data.ItemData;
+import org.geysermc.connector.utils.MessageUtils;
 import org.geysermc.connector.utils.Remapper;
 import org.geysermc.connector.utils.Toolbox;
 
@@ -53,12 +55,10 @@ public class ItemTranslator {
     public ItemStack translateToJava(ItemData data) {
         JavaItem javaItem = getJavaItem(data);
 
-        // TODO: Fix NBT
-        // if (data.getTag() == null) {
-        //    return new ItemStack(javaItem.getId(), data.getCount());
-        // }
-        // return new ItemStack(javaItem.getId(), data.getCount(), translateToJavaNBT(data.getTag()));
-        return new ItemStack(javaItem.getId(), data.getCount());
+        if (data.getTag() == null) {
+            return new ItemStack(javaItem.getId(), data.getCount());
+        }
+        return new ItemStack(javaItem.getId(), data.getCount(), translateToJavaNBT(data.getTag()));
     }
 
     public ItemData translateToBedrock(ItemStack stack) {
@@ -68,13 +68,10 @@ public class ItemTranslator {
         }
 
         BedrockItem bedrockItem = getBedrockItem(stack);
-
-        // TODO: Fix NBT
-        //if (stack.getNBT() == null) {
-        //    return ItemData.of(bedrockItem.getId(), (short) bedrockItem.getData(), stack.getAmount());
-        // }
-        // return ItemData.of(bedrockItem.getId(), (short) bedrockItem.getData(), stack.getAmount(), translateToBedrockNBT(stack.getNBT()));
-        return ItemData.of(bedrockItem.getId(), (short) bedrockItem.getData(), stack.getAmount());
+        if (stack.getNBT() == null) {
+           return ItemData.of(bedrockItem.getId(), (short) bedrockItem.getData(), stack.getAmount());
+        }
+        return ItemData.of(bedrockItem.getId(), (short) bedrockItem.getData(), stack.getAmount(), translateToBedrockNBT(stack.getNBT()));
     }
 
     public BedrockItem getBedrockItem(ItemStack stack) {
@@ -284,24 +281,23 @@ public class ItemTranslator {
 
         if (tag instanceof StringTag) {
             StringTag stringTag = (StringTag) tag;
-            return new com.nukkitx.nbt.tag.StringTag(stringTag.getName(), stringTag.getValue());
+            return new com.nukkitx.nbt.tag.StringTag(stringTag.getName(), MessageUtils.getBedrockMessage(Message.fromString(stringTag.getValue())));
         }
 
         if (tag instanceof ListTag) {
             ListTag listTag = (ListTag) tag;
+            if (listTag.getName().equalsIgnoreCase("Lore")) {
+                List<com.nukkitx.nbt.tag.StringTag> tags = new ArrayList<>();
+                for (Object value : listTag.getValue()) {
+                    if (!(value instanceof Tag))
+                        continue;
 
-            List<com.nukkitx.nbt.tag.Tag> tags = new ArrayList<com.nukkitx.nbt.tag.Tag>();
-            for (Object value : listTag.getValue()) {
-                if (!(value instanceof Tag))
-                    continue;
-
-                Tag tagValue = (Tag) value;
-                com.nukkitx.nbt.tag.Tag bedrockTag = translateToBedrockNBT(tagValue);
-                if (bedrockTag != null)
-                    tags.add(bedrockTag);
+                    com.nukkitx.nbt.tag.StringTag bedrockTag = (com.nukkitx.nbt.tag.StringTag) translateToBedrockNBT((Tag) value);
+                    if (bedrockTag != null)
+                        tags.add(bedrockTag);
+                }
+                return new com.nukkitx.nbt.tag.ListTag<>(listTag.getName(), com.nukkitx.nbt.tag.StringTag.class, tags);
             }
-            // TODO: Fix unchecked call here
-            return new com.nukkitx.nbt.tag.ListTag(listTag.getName(), listTag.getElementType(), tags);
         }
 
         if (tag instanceof CompoundTag) {

From eaf57550e5f9227443a62f1aef471fba0408e46f Mon Sep 17 00:00:00 2001
From: RednedEpic <redned@retronixgames.x10host.com>
Date: Mon, 5 Aug 2019 15:16:45 -0500
Subject: [PATCH 09/10] Implement support for changing held item

---
 .../connector/inventory/Inventory.java        | 22 ++++++---
 .../connector/inventory/PlayerInventory.java  | 47 ++++++++++++++++++
 .../network/UpstreamPacketHandler.java        |  4 ++
 .../network/session/GeyserSession.java        | 10 +++-
 .../network/session/cache/InventoryCache.java |  3 --
 .../network/translators/TranslatorsInit.java  |  3 ++
 .../BedrockCommandRequestTranslator.java      |  1 -
 .../BedrockMobEquipmentTranslator.java        | 49 +++++++++++++++++++
 8 files changed, 126 insertions(+), 13 deletions(-)
 create mode 100644 connector/src/main/java/org/geysermc/connector/inventory/PlayerInventory.java
 create mode 100644 connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockMobEquipmentTranslator.java

diff --git a/connector/src/main/java/org/geysermc/connector/inventory/Inventory.java b/connector/src/main/java/org/geysermc/connector/inventory/Inventory.java
index ed988dcc1..801f670cd 100644
--- a/connector/src/main/java/org/geysermc/connector/inventory/Inventory.java
+++ b/connector/src/main/java/org/geysermc/connector/inventory/Inventory.java
@@ -33,32 +33,40 @@ import lombok.Setter;
 public class Inventory {
 
     @Getter
-    private int id;
+    protected int id;
 
     @Getter
     @Setter
-    private boolean open;
+    protected boolean open;
 
     @Getter
-    private WindowType windowType;
+    protected WindowType windowType;
 
     @Getter
-    private int size;
+    protected int size;
 
     @Getter
     @Setter
-    private String title;
+    protected String title;
 
     @Getter
     @Setter
-    private ItemStack[] items;
+    protected ItemStack[] items;
 
     public Inventory(int id, WindowType windowType, int size) {
+        this("Inventory", id, windowType, size);
+    }
+
+    public Inventory(String title, int id, WindowType windowType, int size) {
+        this.title = title;
         this.id = id;
         this.windowType = windowType;
         this.size = size;
 
-        this.title = "Inventory";
         this.items = new ItemStack[size];
     }
+
+    public ItemStack getItem(int slot) {
+        return items[slot];
+    }
 }
diff --git a/connector/src/main/java/org/geysermc/connector/inventory/PlayerInventory.java b/connector/src/main/java/org/geysermc/connector/inventory/PlayerInventory.java
new file mode 100644
index 000000000..424570b9e
--- /dev/null
+++ b/connector/src/main/java/org/geysermc/connector/inventory/PlayerInventory.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2019 GeyserMC. http://geysermc.org
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * @author GeyserMC
+ * @link https://github.com/GeyserMC/Geyser
+ */
+
+package org.geysermc.connector.inventory;
+
+import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack;
+import lombok.Getter;
+import lombok.Setter;
+
+public class PlayerInventory extends Inventory {
+
+    @Getter
+    @Setter
+    private int heldItemSlot;
+
+    public PlayerInventory() {
+        super(0, null, 45);
+
+        heldItemSlot = 0;
+    }
+
+    public ItemStack getItemInHand() {
+        return items[heldItemSlot];
+    }
+}
diff --git a/connector/src/main/java/org/geysermc/connector/network/UpstreamPacketHandler.java b/connector/src/main/java/org/geysermc/connector/network/UpstreamPacketHandler.java
index 7a0f46162..8b4c188ce 100644
--- a/connector/src/main/java/org/geysermc/connector/network/UpstreamPacketHandler.java
+++ b/connector/src/main/java/org/geysermc/connector/network/UpstreamPacketHandler.java
@@ -139,4 +139,8 @@ public class UpstreamPacketHandler extends LoggingPacketHandler {
         return translateAndDefault(packet);
     }
 
+    @Override
+    public boolean handle(MobEquipmentPacket packet) {
+        return translateAndDefault(packet);
+    }
 }
\ No newline at end of file
diff --git a/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java b/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java
index 3d5140165..3333d6502 100644
--- a/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java
+++ b/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java
@@ -54,6 +54,7 @@ import org.geysermc.api.window.FormWindow;
 import org.geysermc.connector.GeyserConnector;
 import org.geysermc.connector.entity.PlayerEntity;
 import org.geysermc.connector.entity.type.EntityType;
+import org.geysermc.connector.inventory.PlayerInventory;
 import org.geysermc.connector.network.session.cache.DataCache;
 import org.geysermc.connector.network.session.cache.EntityCache;
 import org.geysermc.connector.network.session.cache.InventoryCache;
@@ -76,6 +77,8 @@ public class GeyserSession implements PlayerSession, Player {
     private AuthData authenticationData;
 
     private PlayerEntity playerEntity;
+    private PlayerInventory inventory;
+
     private EntityCache entityCache;
     private InventoryCache inventoryCache;
     private WindowCache windowCache;
@@ -94,17 +97,20 @@ public class GeyserSession implements PlayerSession, Player {
         this.connector = connector;
         this.upstream = bedrockServerSession;
 
-        this.playerEntity = new PlayerEntity(UUID.randomUUID(), 1, 1, EntityType.PLAYER, new Vector3f(0, 0, 0), new Vector3f(0, 0, 0), new Vector3f(0, 0, 0));
-
         this.entityCache = new EntityCache(this);
         this.inventoryCache = new InventoryCache(this);
         this.windowCache = new WindowCache(this);
         this.scoreboardCache = new ScoreboardCache(this);
 
+        this.playerEntity = new PlayerEntity(UUID.randomUUID(), 1, 1, EntityType.PLAYER, new Vector3f(0, 0, 0), new Vector3f(0, 0, 0), new Vector3f(0, 0, 0));
+        this.inventory = new PlayerInventory();
+
         this.javaPacketCache = new DataCache<Packet>();
 
         this.spawned = false;
         this.loggedIn = false;
+
+        this.inventoryCache.getInventories().put(0, inventory);
     }
 
     public void connect(RemoteServer remoteServer) {
diff --git a/connector/src/main/java/org/geysermc/connector/network/session/cache/InventoryCache.java b/connector/src/main/java/org/geysermc/connector/network/session/cache/InventoryCache.java
index b6c8b501a..4eea1de2f 100644
--- a/connector/src/main/java/org/geysermc/connector/network/session/cache/InventoryCache.java
+++ b/connector/src/main/java/org/geysermc/connector/network/session/cache/InventoryCache.java
@@ -52,9 +52,6 @@ public class InventoryCache {
 
     public InventoryCache(GeyserSession session) {
         this.session = session;
-
-        // This is the player's inventory
-        inventories.put(0, new Inventory(0, null, 45));
     }
 
     public Inventory getPlayerInventory() {
diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/TranslatorsInit.java b/connector/src/main/java/org/geysermc/connector/network/translators/TranslatorsInit.java
index cacdf0904..0edcd59d4 100644
--- a/connector/src/main/java/org/geysermc/connector/network/translators/TranslatorsInit.java
+++ b/connector/src/main/java/org/geysermc/connector/network/translators/TranslatorsInit.java
@@ -59,10 +59,12 @@ import com.nukkitx.nbt.stream.NBTOutputStream;
 import com.nukkitx.nbt.tag.CompoundTag;
 import com.nukkitx.protocol.bedrock.packet.AnimatePacket;
 import com.nukkitx.protocol.bedrock.packet.CommandRequestPacket;
+import com.nukkitx.protocol.bedrock.packet.MobEquipmentPacket;
 import com.nukkitx.protocol.bedrock.packet.TextPacket;
 import lombok.Getter;
 import org.geysermc.connector.network.translators.bedrock.BedrockAnimateTranslator;
 import org.geysermc.connector.network.translators.bedrock.BedrockCommandRequestTranslator;
+import org.geysermc.connector.network.translators.bedrock.BedrockMobEquipmentTranslator;
 import org.geysermc.connector.network.translators.bedrock.BedrockTextTranslator;
 import org.geysermc.connector.network.translators.inventory.GenericInventoryTranslator;
 import org.geysermc.connector.network.translators.inventory.InventoryTranslator;
@@ -161,6 +163,7 @@ public class TranslatorsInit {
         Registry.registerBedrock(AnimatePacket.class, new BedrockAnimateTranslator());
         Registry.registerBedrock(CommandRequestPacket.class, new BedrockCommandRequestTranslator());
         Registry.registerBedrock(TextPacket.class, new BedrockTextTranslator());
+        Registry.registerBedrock(MobEquipmentPacket.class, new BedrockMobEquipmentTranslator());
 
         itemTranslator = new ItemTranslator();
 
diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockCommandRequestTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockCommandRequestTranslator.java
index c453c31a3..cc2ab4d07 100644
--- a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockCommandRequestTranslator.java
+++ b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockCommandRequestTranslator.java
@@ -23,7 +23,6 @@
  * @link https://github.com/GeyserMC/Geyser
  */
 
-
 package org.geysermc.connector.network.translators.bedrock;
 
 import com.github.steveice10.mc.protocol.packet.ingame.client.ClientChatPacket;
diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockMobEquipmentTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockMobEquipmentTranslator.java
new file mode 100644
index 000000000..7ae5a4ee0
--- /dev/null
+++ b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockMobEquipmentTranslator.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2019 GeyserMC. http://geysermc.org
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * @author GeyserMC
+ * @link https://github.com/GeyserMC/Geyser
+ */
+
+package org.geysermc.connector.network.translators.bedrock;
+
+import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerChangeHeldItemPacket;
+import com.nukkitx.protocol.bedrock.data.ContainerId;
+import com.nukkitx.protocol.bedrock.packet.MobEquipmentPacket;
+import org.geysermc.connector.network.session.GeyserSession;
+import org.geysermc.connector.network.translators.PacketTranslator;
+
+public class BedrockMobEquipmentTranslator extends PacketTranslator<MobEquipmentPacket> {
+
+    @Override
+    public void translate(MobEquipmentPacket packet, GeyserSession session) {
+        if (packet.getHotbarSlot() > 8)
+            return;
+
+        if (packet.getContainerId() != ContainerId.INVENTORY)
+            return;
+
+        session.getInventory().setHeldItemSlot(packet.getHotbarSlot());
+
+        ClientPlayerChangeHeldItemPacket changeHeldItemPacket = new ClientPlayerChangeHeldItemPacket(packet.getHotbarSlot());
+        session.getDownstream().getSession().send(changeHeldItemPacket);
+    }
+}

From c926c7d8fadb429639638414abe1a3ad304e8f4a Mon Sep 17 00:00:00 2001
From: RednedEpic <redned@retronixgames.x10host.com>
Date: Mon, 5 Aug 2019 15:30:56 -0500
Subject: [PATCH 10/10] Remove unnecessary duplicate of StartGamePacket

---
 .../network/session/GeyserSession.java        | 10 +--
 .../java/JavaJoinGameTranslator.java          |  1 +
 .../JavaPlayerPositionRotationTranslator.java | 68 ++++---------------
 3 files changed, 19 insertions(+), 60 deletions(-)

diff --git a/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java b/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java
index 3333d6502..74c4d14ab 100644
--- a/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java
+++ b/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java
@@ -245,15 +245,15 @@ public class GeyserSession implements PlayerSession, Player {
 
     private void startGame() {
         StartGamePacket startGamePacket = new StartGamePacket();
-        startGamePacket.setUniqueEntityId(1);
-        startGamePacket.setRuntimeEntityId(1);
+        startGamePacket.setUniqueEntityId(playerEntity.getGeyserId());
+        startGamePacket.setRuntimeEntityId(playerEntity.getGeyserId());
         startGamePacket.setPlayerGamemode(0);
-        startGamePacket.setPlayerPosition(new Vector3f(0, 0, 0));
+        startGamePacket.setPlayerPosition(new Vector3f(0, 69, 0));
         startGamePacket.setRotation(new Vector2f(1, 1));
 
         startGamePacket.setSeed(0);
-        startGamePacket.setDimensionId(0);
-        startGamePacket.setGeneratorId(0);
+        startGamePacket.setDimensionId(playerEntity.getDimension());
+        startGamePacket.setGeneratorId(1);
         startGamePacket.setLevelGamemode(0);
         startGamePacket.setDifficulty(1);
         startGamePacket.setDefaultSpawn(new Vector3i(0, 0, 0));
diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaJoinGameTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaJoinGameTranslator.java
index 81ff5639e..29c4b4b22 100644
--- a/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaJoinGameTranslator.java
+++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaJoinGameTranslator.java
@@ -46,6 +46,7 @@ public class JavaJoinGameTranslator extends PacketTranslator<ServerJoinGamePacke
         int gamemode = packet.getGameMode().ordinal();
         SetPlayerGameTypePacket playerGameTypePacket = new SetPlayerGameTypePacket();
         playerGameTypePacket.setGamemode(gamemode);
+        session.getUpstream().sendPacket(playerGameTypePacket);
 
         Vector3f pos = new Vector3f(0, 0, 0);
         int chunkX = pos.getFloorX() >> 4;
diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/player/JavaPlayerPositionRotationTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/player/JavaPlayerPositionRotationTranslator.java
index 15f4e9b15..65c5e3793 100644
--- a/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/player/JavaPlayerPositionRotationTranslator.java
+++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/player/JavaPlayerPositionRotationTranslator.java
@@ -25,20 +25,17 @@
 
 package org.geysermc.connector.network.translators.java.entity.player;
 
-import com.flowpowered.math.vector.Vector2f;
 import com.flowpowered.math.vector.Vector3f;
-import com.flowpowered.math.vector.Vector3i;
 import com.github.steveice10.mc.protocol.packet.ingame.server.ServerJoinGamePacket;
 import com.github.steveice10.mc.protocol.packet.ingame.server.entity.player.ServerPlayerPositionRotationPacket;
-import com.nukkitx.protocol.bedrock.data.GamePublishSetting;
-import com.nukkitx.protocol.bedrock.data.GameRule;
 import com.nukkitx.protocol.bedrock.packet.MovePlayerPacket;
+import com.nukkitx.protocol.bedrock.packet.PlayStatusPacket;
 import com.nukkitx.protocol.bedrock.packet.SetEntityDataPacket;
-import com.nukkitx.protocol.bedrock.packet.StartGamePacket;
+import com.nukkitx.protocol.bedrock.packet.SetPlayerGameTypePacket;
+import org.geysermc.connector.console.GeyserLogger;
 import org.geysermc.connector.entity.Entity;
 import org.geysermc.connector.network.session.GeyserSession;
 import org.geysermc.connector.network.translators.PacketTranslator;
-import org.geysermc.connector.utils.Toolbox;
 
 public class JavaPlayerPositionRotationTranslator extends PacketTranslator<ServerPlayerPositionRotationPacket> {
 
@@ -54,63 +51,24 @@ public class JavaPlayerPositionRotationTranslator extends PacketTranslator<Serve
         if (session.isSpawned())
             return;
 
-        ServerJoinGamePacket javaPacket = (ServerJoinGamePacket) session.getJavaPacketCache().getCachedValues().remove("java_join_packet");
+        ServerJoinGamePacket javaJoinPacket = (ServerJoinGamePacket) session.getJavaPacketCache().getCachedValues().remove("java_join_packet");
 
-        StartGamePacket startGamePacket = new StartGamePacket();
-        startGamePacket.setUniqueEntityId(entity.getEntityId());
-        startGamePacket.setRuntimeEntityId(entity.getEntityId());
-        startGamePacket.setPlayerGamemode(0);
-        startGamePacket.setPlayerPosition(new Vector3f(packet.getX(), packet.getY(), packet.getZ()));
-        startGamePacket.setRotation(new Vector2f(entity.getRotation().getX(), entity.getRotation().getY()));
-
-        startGamePacket.setSeed(0);
-        startGamePacket.setDimensionId(entity.getDimension());
-        startGamePacket.setGeneratorId(0);
-        startGamePacket.setLevelGamemode(javaPacket.getGameMode().ordinal());
-        startGamePacket.setDifficulty(1);
-        startGamePacket.setDefaultSpawn(new Vector3i(packet.getX(), packet.getY(), packet.getZ()));
-        startGamePacket.setAcheivementsDisabled(true);
-        startGamePacket.setTime(0);
-        startGamePacket.setEduLevel(false);
-        startGamePacket.setEduFeaturesEnabled(false);
-        startGamePacket.setRainLevel(0);
-        startGamePacket.setLightningLevel(0);
-        startGamePacket.setMultiplayerGame(true);
-        startGamePacket.setBroadcastingToLan(true);
-        startGamePacket.getGamerules().add(new GameRule<>("showcoordinates", true));
-        startGamePacket.setPlatformBroadcastMode(GamePublishSetting.PUBLIC);
-        startGamePacket.setXblBroadcastMode(GamePublishSetting.PUBLIC);
-        startGamePacket.setCommandsEnabled(true);
-        startGamePacket.setTexturePacksRequired(false);
-        startGamePacket.setBonusChestEnabled(false);
-        startGamePacket.setStartingWithMap(false);
-        startGamePacket.setTrustingPlayers(true);
-        startGamePacket.setDefaultPlayerPermission(1);
-        startGamePacket.setServerChunkTickRange(4);
-        startGamePacket.setBehaviorPackLocked(false);
-        startGamePacket.setResourcePackLocked(false);
-        startGamePacket.setFromLockedWorldTemplate(false);
-        startGamePacket.setUsingMsaGamertagsOnly(false);
-        startGamePacket.setFromWorldTemplate(false);
-        startGamePacket.setWorldTemplateOptionLocked(false);
-
-        startGamePacket.setLevelId("world");
-        startGamePacket.setWorldName("world");
-        startGamePacket.setPremiumWorldTemplateId("00000000-0000-0000-0000-000000000000");
-        startGamePacket.setCurrentTick(0);
-        startGamePacket.setEnchantmentSeed(0);
-        startGamePacket.setMultiplayerCorrelationId("");
-        startGamePacket.setCachedPalette(Toolbox.CACHED_PALLETE);
-        startGamePacket.setItemEntries(Toolbox.ITEMS);
-        session.getUpstream().sendPacket(startGamePacket);
+        PlayStatusPacket playStatus = new PlayStatusPacket();
+        playStatus.setStatus(PlayStatusPacket.Status.LOGIN_SUCCESS);
+        session.getUpstream().sendPacketImmediately(playStatus);
 
         entity.moveAbsolute(new Vector3f(packet.getX(), packet.getY(), packet.getZ()), packet.getPitch(), packet.getYaw());
 
+        SetPlayerGameTypePacket playerGameTypePacket = new SetPlayerGameTypePacket();
+        playerGameTypePacket.setGamemode(javaJoinPacket.getGameMode().ordinal());
+        session.getUpstream().sendPacket(playerGameTypePacket);
+
         SetEntityDataPacket entityDataPacket = new SetEntityDataPacket();
         entityDataPacket.setRuntimeEntityId(entity.getGeyserId());
         entityDataPacket.getMetadata().putAll(entity.getMetadata());
 
         session.getUpstream().sendPacket(entityDataPacket);
+        session.getPlayerEntity().setEntityId(javaJoinPacket.getEntityId());
 
         MovePlayerPacket movePlayerPacket = new MovePlayerPacket();
         movePlayerPacket.setRuntimeEntityId(entity.getGeyserId());
@@ -123,6 +81,6 @@ public class JavaPlayerPositionRotationTranslator extends PacketTranslator<Serve
         session.getUpstream().sendPacket(movePlayerPacket);
         session.setSpawned(true);
 
-        System.out.println("resent! " + packet.getX() + " " + packet.getY() + " " + packet.getZ());
+        GeyserLogger.DEFAULT.info("Spawned player at " + packet.getX() + " " + packet.getY() + " " + packet.getZ());
     }
 }