From 54a730754f6cedbb9ff6f6c07b4b10062c38ea59 Mon Sep 17 00:00:00 2001
From: Tofaa <82680183+Tofaa2@users.noreply.github.com>
Date: Mon, 22 Jan 2024 23:42:27 +0300
Subject: [PATCH 01/19] add wrapper world

---
 .idea/gradle.xml                              |  1 +
 .idea/workspace.xml                           | 17 +++++--------
 api/build.gradle                              | 19 ++++++++++++++
 settings.gradle                               |  1 +
 .../me/tofaa/entitylib/EntityLibPlatform.java | 15 +++++++++++
 .../java/me/tofaa/entitylib/WrapperWorld.java | 25 +++++++++++++++++++
 6 files changed, 67 insertions(+), 11 deletions(-)
 create mode 100644 api/build.gradle
 create mode 100644 src/main/java/me/tofaa/entitylib/EntityLibPlatform.java
 create mode 100644 src/main/java/me/tofaa/entitylib/WrapperWorld.java

diff --git a/.idea/gradle.xml b/.idea/gradle.xml
index 784391e..3feea6d 100644
--- a/.idea/gradle.xml
+++ b/.idea/gradle.xml
@@ -8,6 +8,7 @@
         <option name="modules">
           <set>
             <option value="$PROJECT_DIR$" />
+            <option value="$PROJECT_DIR$/api" />
             <option value="$PROJECT_DIR$/test-plugin" />
           </set>
         </option>
diff --git a/.idea/workspace.xml b/.idea/workspace.xml
index addaac9..0c3487f 100644
--- a/.idea/workspace.xml
+++ b/.idea/workspace.xml
@@ -5,16 +5,11 @@
   </component>
   <component name="ChangeListManager">
     <list default="true" id="9d5d9b6f-43c8-41a4-bb42-a66ffc96c9b0" name="Changes" comment="">
+      <change afterPath="$PROJECT_DIR$/src/main/java/me/tofaa/entitylib/EntityLibPlatform.java" afterDir="false" />
+      <change afterPath="$PROJECT_DIR$/src/main/java/me/tofaa/entitylib/WrapperWorld.java" afterDir="false" />
+      <change beforePath="$PROJECT_DIR$/.idea/gradle.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/gradle.xml" afterDir="false" />
       <change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
-      <change beforePath="$PROJECT_DIR$/src/main/java/me/tofaa/entitylib/meta/EntityMeta.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/me/tofaa/entitylib/meta/EntityMeta.java" afterDir="false" />
-      <change beforePath="$PROJECT_DIR$/src/main/java/me/tofaa/entitylib/meta/display/BlockDisplayMeta.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/me/tofaa/entitylib/meta/display/BlockDisplayMeta.java" afterDir="false" />
-      <change beforePath="$PROJECT_DIR$/src/main/java/me/tofaa/entitylib/meta/display/ItemDisplayMeta.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/me/tofaa/entitylib/meta/display/ItemDisplayMeta.java" afterDir="false" />
-      <change beforePath="$PROJECT_DIR$/src/main/java/me/tofaa/entitylib/meta/display/TextDisplayMeta.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/me/tofaa/entitylib/meta/display/TextDisplayMeta.java" afterDir="false" />
-      <change beforePath="$PROJECT_DIR$/src/main/java/me/tofaa/entitylib/meta/types/DisplayMeta.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/me/tofaa/entitylib/meta/types/DisplayMeta.java" afterDir="false" />
-      <change beforePath="$PROJECT_DIR$/test-plugin/build.gradle" beforeDir="false" afterPath="$PROJECT_DIR$/test-plugin/build.gradle" afterDir="false" />
-      <change beforePath="$PROJECT_DIR$/test-plugin/src/main/java/me/tofaa/entitylib/TestCommand.java" beforeDir="false" afterPath="$PROJECT_DIR$/test-plugin/src/main/java/me/tofaa/entitylib/TestCommand.java" afterDir="false" />
-      <change beforePath="$PROJECT_DIR$/test-plugin/src/main/java/me/tofaa/entitylib/TestDisplayCommand.java" beforeDir="false" afterPath="$PROJECT_DIR$/test-plugin/src/main/java/me/tofaa/entitylib/TestDisplayCommand.java" afterDir="false" />
-      <change beforePath="$PROJECT_DIR$/test-plugin/src/main/resources/plugin.yml" beforeDir="false" afterPath="$PROJECT_DIR$/test-plugin/src/main/resources/plugin.yml" afterDir="false" />
+      <change beforePath="$PROJECT_DIR$/settings.gradle" beforeDir="false" afterPath="$PROJECT_DIR$/settings.gradle" afterDir="false" />
     </list>
     <option name="SHOW_DIALOG" value="false" />
     <option name="HIGHLIGHT_CONFLICTS" value="true" />
@@ -84,7 +79,7 @@
     "RunOnceActivity.OpenProjectViewOnStart": "true",
     "RunOnceActivity.ShowReadmeOnStart": "true",
     "WebServerToolWindowFactoryState": "false",
-    "git-widget-placeholder": "master",
+    "git-widget-placeholder": "feat/platform-api",
     "ignore.virus.scanning.warn.message": "true",
     "jdk.selected.JAVA_MODULE": "corretto-17",
     "kotlin-language-version-configured": "true",
@@ -238,7 +233,7 @@
         <line-breakpoint enabled="true" type="java-method">
           <url>file://$PROJECT_DIR$/src/main/java/me/tofaa/entitylib/meta/types/DisplayMeta.java</url>
           <line>153</line>
-          <properties class="me.tofaa.entitylib.meta.types.DisplayMeta" method="setShadowRadius">
+          <properties class="me.tofaa.entitylib.meta.types.DisplayMeta">
             <option name="EMULATED" value="true" />
             <option name="WATCH_EXIT" value="false" />
           </properties>
diff --git a/api/build.gradle b/api/build.gradle
new file mode 100644
index 0000000..18d60d6
--- /dev/null
+++ b/api/build.gradle
@@ -0,0 +1,19 @@
+plugins {
+    id 'java'
+}
+
+group = 'me.tofaa.entitylib'
+version = '1.0-SNAPSHOT'
+
+repositories {
+    mavenCentral()
+}
+
+dependencies {
+    testImplementation platform('org.junit:junit-bom:5.9.1')
+    testImplementation 'org.junit.jupiter:junit-jupiter'
+}
+
+test {
+    useJUnitPlatform()
+}
\ No newline at end of file
diff --git a/settings.gradle b/settings.gradle
index a756887..81e87e9 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -1,3 +1,4 @@
 rootProject.name = 'EntityLib'
 include 'test-plugin'
+include 'api'
 
diff --git a/src/main/java/me/tofaa/entitylib/EntityLibPlatform.java b/src/main/java/me/tofaa/entitylib/EntityLibPlatform.java
new file mode 100644
index 0000000..2901424
--- /dev/null
+++ b/src/main/java/me/tofaa/entitylib/EntityLibPlatform.java
@@ -0,0 +1,15 @@
+package me.tofaa.entitylib;
+
+import com.github.retrooper.packetevents.PacketEventsAPI;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.UUID;
+
+public interface EntityLibPlatform<W> {
+
+    @NotNull PacketEventsAPI<?> getPacketEvents();
+
+    @NotNull WrapperWorld<W> createWorld(UUID uuid, String name);
+
+
+}
diff --git a/src/main/java/me/tofaa/entitylib/WrapperWorld.java b/src/main/java/me/tofaa/entitylib/WrapperWorld.java
new file mode 100644
index 0000000..5ed747c
--- /dev/null
+++ b/src/main/java/me/tofaa/entitylib/WrapperWorld.java
@@ -0,0 +1,25 @@
+package me.tofaa.entitylib;
+
+import me.tofaa.entitylib.entity.WrapperEntity;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.UUID;
+
+/**
+ * A platform independent wrapper for a "world" object.
+ * @param <W> The generic takes the actual world handle used by the platform.
+ */
+public interface WrapperWorld<W> {
+
+    @NotNull UUID getUuid();
+
+    @NotNull String getName();
+
+    @Nullable WrapperEntity getEntity(@NotNull UUID uuid);
+
+    @Nullable WrapperEntity getEntity(int entityId);
+
+    @NotNull W getHandle();
+
+}

From 3091083821b8a7a6642c7ff0b9599e1f79e5a7cf Mon Sep 17 00:00:00 2001
From: Tofaa <82680183+Tofaa2@users.noreply.github.com>
Date: Fri, 26 Jan 2024 13:17:38 +0400
Subject: [PATCH 02/19] rewrite to a more platformized structure.

---
 .idea/workspace.xml                           |  71 +++---
 api/build.gradle                              |  11 +-
 .../java/me/tofaa/entitylib/APISettings.java  | 100 ++++++++
 .../java/me/tofaa/entitylib/EntityLib.java    |  28 +++
 .../java/me/tofaa/entitylib/EntityLibAPI.java |  43 ++++
 .../java/me/tofaa/entitylib/Platform.java     |  53 +++++
 .../java/me/tofaa/entitylib/WorldWrapper.java |  19 ++
 .../tofaa/entitylib/event/EntityLibEvent.java |  13 ++
 .../event/UserReceiveMetaUpdateEvent.java     |  29 +++
 .../extras/InvalidVersionException.java       |  23 ++
 .../me/tofaa/entitylib/meta/EntityMeta.java   | 221 ++++++++++++++++++
 .../me/tofaa/entitylib/meta/Metadata.java     |  45 ++++
 .../tofaa/entitylib/tick/TickContainer.java   |  72 ++++++
 .../me/tofaa/entitylib/tick/Tickable.java     |   7 +
 build.gradle                                  |   6 +
 platforms/spigot/build.gradle                 |  15 ++
 .../entitylib/spigot/SpigotEntityLibAPI.java  |  98 ++++++++
 .../spigot/SpigotEntityLibPlatform.java       |  65 ++++++
 settings.gradle                               |   2 +
 .../me/tofaa/entitylib/meta/Metadata.java     |   1 -
 20 files changed, 888 insertions(+), 34 deletions(-)
 create mode 100644 api/src/main/java/me/tofaa/entitylib/APISettings.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/EntityLib.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/EntityLibAPI.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/Platform.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/WorldWrapper.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/event/EntityLibEvent.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/event/UserReceiveMetaUpdateEvent.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/extras/InvalidVersionException.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/EntityMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/Metadata.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/tick/TickContainer.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/tick/Tickable.java
 create mode 100644 platforms/spigot/build.gradle
 create mode 100644 platforms/spigot/src/main/java/me/tofaa/entitylib/spigot/SpigotEntityLibAPI.java
 create mode 100644 platforms/spigot/src/main/java/me/tofaa/entitylib/spigot/SpigotEntityLibPlatform.java

diff --git a/.idea/workspace.xml b/.idea/workspace.xml
index 0c3487f..cd26f29 100644
--- a/.idea/workspace.xml
+++ b/.idea/workspace.xml
@@ -5,11 +5,20 @@
   </component>
   <component name="ChangeListManager">
     <list default="true" id="9d5d9b6f-43c8-41a4-bb42-a66ffc96c9b0" name="Changes" comment="">
-      <change afterPath="$PROJECT_DIR$/src/main/java/me/tofaa/entitylib/EntityLibPlatform.java" afterDir="false" />
-      <change afterPath="$PROJECT_DIR$/src/main/java/me/tofaa/entitylib/WrapperWorld.java" afterDir="false" />
-      <change beforePath="$PROJECT_DIR$/.idea/gradle.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/gradle.xml" afterDir="false" />
+      <change afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/EntityLib.java" afterDir="false" />
+      <change afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/EntityLibAPI.java" afterDir="false" />
+      <change afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/Platform.java" afterDir="false" />
+      <change afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/WorldWrapper.java" afterDir="false" />
+      <change afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/event/EntityLibEvent.java" afterDir="false" />
+      <change afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/event/UserReceiveMetaUpdateEvent.java" afterDir="false" />
+      <change afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/extras/InvalidVersionException.java" afterDir="false" />
+      <change afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/meta/EntityMeta.java" afterDir="false" />
+      <change afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/meta/Metadata.java" afterDir="false" />
+      <change afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/tick/TickContainer.java" afterDir="false" />
       <change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
-      <change beforePath="$PROJECT_DIR$/settings.gradle" beforeDir="false" afterPath="$PROJECT_DIR$/settings.gradle" afterDir="false" />
+      <change beforePath="$PROJECT_DIR$/api/build.gradle" beforeDir="false" afterPath="$PROJECT_DIR$/api/build.gradle" afterDir="false" />
+      <change beforePath="$PROJECT_DIR$/build.gradle" beforeDir="false" afterPath="$PROJECT_DIR$/build.gradle" afterDir="false" />
+      <change beforePath="$PROJECT_DIR$/src/main/java/me/tofaa/entitylib/meta/Metadata.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/me/tofaa/entitylib/meta/Metadata.java" afterDir="false" />
     </list>
     <option name="SHOW_DIALOG" value="false" />
     <option name="HIGHLIGHT_CONFLICTS" value="true" />
@@ -72,30 +81,34 @@
     <option name="showExcludedFiles" value="false" />
     <option name="showLibraryContents" value="true" />
   </component>
-  <component name="PropertiesComponent"><![CDATA[{
-  "keyToString": {
-    "Gradle.Build EntityLib.executor": "Run",
-    "Gradle.EntityLib:test-plugin [runServer].executor": "Run",
-    "RunOnceActivity.OpenProjectViewOnStart": "true",
-    "RunOnceActivity.ShowReadmeOnStart": "true",
-    "WebServerToolWindowFactoryState": "false",
-    "git-widget-placeholder": "feat/platform-api",
-    "ignore.virus.scanning.warn.message": "true",
-    "jdk.selected.JAVA_MODULE": "corretto-17",
-    "kotlin-language-version-configured": "true",
-    "last_opened_file_path": "D:/Github/EntityLib",
-    "node.js.detected.package.eslint": "true",
-    "node.js.detected.package.tslint": "true",
-    "node.js.selected.package.eslint": "(autodetect)",
-    "node.js.selected.package.tslint": "(autodetect)",
-    "nodejs_package_manager_path": "npm",
-    "project.structure.last.edited": "Modules",
-    "project.structure.proportion": "0.0",
-    "project.structure.side.proportion": "0.0",
-    "settings.editor.selected.configurable": "preferences.pluginManager",
-    "vue.rearranger.settings.migration": "true"
+  <component name="PropertiesComponent">{
+  &quot;keyToString&quot;: {
+    &quot;Downloaded.Files.Path.Enabled&quot;: &quot;false&quot;,
+    &quot;Gradle.Build EntityLib.executor&quot;: &quot;Run&quot;,
+    &quot;Gradle.EntityLib:test-plugin [runServer].executor&quot;: &quot;Run&quot;,
+    &quot;Repository.Attach.Annotations&quot;: &quot;false&quot;,
+    &quot;Repository.Attach.JavaDocs&quot;: &quot;false&quot;,
+    &quot;Repository.Attach.Sources&quot;: &quot;false&quot;,
+    &quot;RunOnceActivity.OpenProjectViewOnStart&quot;: &quot;true&quot;,
+    &quot;RunOnceActivity.ShowReadmeOnStart&quot;: &quot;true&quot;,
+    &quot;WebServerToolWindowFactoryState&quot;: &quot;false&quot;,
+    &quot;git-widget-placeholder&quot;: &quot;feat/platform-api&quot;,
+    &quot;ignore.virus.scanning.warn.message&quot;: &quot;true&quot;,
+    &quot;jdk.selected.JAVA_MODULE&quot;: &quot;corretto-17&quot;,
+    &quot;kotlin-language-version-configured&quot;: &quot;true&quot;,
+    &quot;last_opened_file_path&quot;: &quot;D:/Github/EntityLib&quot;,
+    &quot;node.js.detected.package.eslint&quot;: &quot;true&quot;,
+    &quot;node.js.detected.package.tslint&quot;: &quot;true&quot;,
+    &quot;node.js.selected.package.eslint&quot;: &quot;(autodetect)&quot;,
+    &quot;node.js.selected.package.tslint&quot;: &quot;(autodetect)&quot;,
+    &quot;nodejs_package_manager_path&quot;: &quot;npm&quot;,
+    &quot;project.structure.last.edited&quot;: &quot;Modules&quot;,
+    &quot;project.structure.proportion&quot;: &quot;0.0&quot;,
+    &quot;project.structure.side.proportion&quot;: &quot;0.0&quot;,
+    &quot;settings.editor.selected.configurable&quot;: &quot;preferences.pluginManager&quot;,
+    &quot;vue.rearranger.settings.migration&quot;: &quot;true&quot;
   }
-}]]></component>
+}</component>
   <component name="RecentsManager">
     <key name="CopyFile.RECENT_KEYS">
       <recent name="D:\Github\EntityLib\test-plugin" />
@@ -216,6 +229,10 @@
       <workItem from="1705578156456" duration="78000" />
       <workItem from="1705636302508" duration="7111000" />
       <workItem from="1705951390204" duration="3936000" />
+      <workItem from="1705984769972" duration="76000" />
+      <workItem from="1706183895216" duration="664000" />
+      <workItem from="1706187926445" duration="4339000" />
+      <workItem from="1706248178234" duration="1973000" />
     </task>
     <servers />
   </component>
diff --git a/api/build.gradle b/api/build.gradle
index 18d60d6..3e5d186 100644
--- a/api/build.gradle
+++ b/api/build.gradle
@@ -1,5 +1,6 @@
 plugins {
     id 'java'
+    id 'java-library'
 }
 
 group = 'me.tofaa.entitylib'
@@ -10,10 +11,8 @@ repositories {
 }
 
 dependencies {
-    testImplementation platform('org.junit:junit-bom:5.9.1')
-    testImplementation 'org.junit.jupiter:junit-jupiter'
-}
+    api 'org.jetbrains:annotations:24.0.0'
 
-test {
-    useJUnitPlatform()
-}
\ No newline at end of file
+    compileOnlyApi(adventureDependencies)
+    compileOnlyApi 'com.github.retrooper.packetevents:api:2.2.0'
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/APISettings.java b/api/src/main/java/me/tofaa/entitylib/APISettings.java
new file mode 100644
index 0000000..01b5d17
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/APISettings.java
@@ -0,0 +1,100 @@
+package me.tofaa.entitylib;
+
+import com.github.retrooper.packetevents.PacketEventsAPI;
+import com.google.gson.JsonArray;
+import com.google.gson.JsonParser;
+import org.jetbrains.annotations.NotNull;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.net.URL;
+
+public final class APISettings {
+
+    private boolean debugMode = false;
+    private boolean checkForUpdates = false;
+    private boolean tickTickables = false;
+    private PacketEventsAPI<?> packetEvents;
+    private boolean platformLogger = false;
+
+    public APISettings(PacketEventsAPI<?> packetEvents) {
+        this.packetEvents = packetEvents;
+    }
+
+    public boolean requiresUpdate() throws IOException {
+        if (!checkForUpdates) return false;
+        String urlString = "https://api.github.com/repos/Tofaa2/EntityLib/releases/latest";
+        String version = EntityLib.getVersion();
+
+        URL url = new URL(urlString);
+        JsonParser json = new JsonParser();
+        InputStream stream = url.openStream();
+        JsonArray array = json.parse(new InputStreamReader(stream)).getAsJsonArray();
+        String latest = array.get(0).getAsJsonObject().get("tag_name").getAsString();
+
+        stream.close();
+        return !version.equalsIgnoreCase(latest);
+    }
+
+    public @NotNull APISettings usePlatformLogger() {
+        this.platformLogger = true;
+        return this;
+    }
+
+    public @NotNull APISettings usePlatformLogger(boolean platformLogger) {
+        this.platformLogger = platformLogger;
+        return this;
+    }
+
+    public @NotNull APISettings debugMode(boolean debugMode) {
+        this.debugMode = debugMode;
+        return this;
+    }
+
+    public @NotNull APISettings checkForUpdates() {
+        this.checkForUpdates = true;
+        return this;
+    }
+
+    public @NotNull APISettings tickTickables() {
+        this.tickTickables = true;
+        return this;
+    }
+
+    public @NotNull APISettings debugMode() {
+        this.debugMode = true;
+        return this;
+    }
+
+    public @NotNull APISettings checkForUpdates(boolean checkForUpdates) {
+        this.checkForUpdates = checkForUpdates;
+        return this;
+    }
+
+    public @NotNull APISettings tickTickables(boolean tickTickables) {
+        this.tickTickables = tickTickables;
+        return this;
+    }
+
+    public boolean isDebugMode() {
+        return debugMode;
+    }
+
+    public boolean shouldCheckForUpdate() {
+        return checkForUpdates;
+    }
+
+    public boolean shouldTickTickables() {
+        return tickTickables;
+    }
+
+    public PacketEventsAPI<?> getPacketEvents() {
+        return packetEvents;
+    }
+
+    public boolean shouldUsePlatformLogger() {
+        return platformLogger;
+    }
+
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/EntityLib.java b/api/src/main/java/me/tofaa/entitylib/EntityLib.java
new file mode 100644
index 0000000..453b99e
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/EntityLib.java
@@ -0,0 +1,28 @@
+package me.tofaa.entitylib;
+
+public final class EntityLib {
+
+    private EntityLib() {}
+
+    private static String version = "1.2.0-SNAPSHOT";
+    private static Platform platform;
+    private static EntityLibAPI api;
+
+    public static void init(Platform<?> platform, APISettings settings) {
+        EntityLib.platform = platform;
+        platform.setupApi(settings);
+        api = platform.getAPI();
+    }
+
+    public static EntityLibAPI<?, ?> getApi() {
+        return api;
+    }
+
+    public static Platform<?> getPlatform() {
+        return platform;
+    }
+
+    public static String getVersion() {
+        return version;
+    }
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/EntityLibAPI.java b/api/src/main/java/me/tofaa/entitylib/EntityLibAPI.java
new file mode 100644
index 0000000..6355aba
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/EntityLibAPI.java
@@ -0,0 +1,43 @@
+package me.tofaa.entitylib;
+
+import com.github.retrooper.packetevents.PacketEventsAPI;
+import me.tofaa.entitylib.tick.TickContainer;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Collection;
+
+/**
+ * Represents the API for EntityLib.
+ * Handles the loading, enabling, and disabling of the API. And handles platform specific creation of EntityLib content.
+ * @param <W> The {@link WorldWrapper}'s param type for the platform specific World.
+ * @param <T> The {@link TickContainer}'s param type for the platform specific TickContainer.
+ */
+public interface EntityLibAPI<W, T> {
+
+    PacketEventsAPI<?> getPacketEvents();
+
+    void onLoad();
+
+    void onEnable();
+
+    @NotNull APISettings getSettings();
+
+
+    /**
+     * If a platform supports ticking
+     * this method should be responsible for setting up the {@link me.tofaa.entitylib.tick.TickContainer}'s.
+     */
+    void setupTickingContainers();
+
+
+    /**
+     * @return An unmodifiable collection of TickContainers.
+     */
+    @NotNull Collection<TickContainer<?, T>> getTickContainers();
+
+    /**
+     * Adds a TickContainer to the API. Automatically starts ticking it.
+     * @param tickContainer the TickContainer to add.
+     */
+    void addTickContainer(@NotNull TickContainer<?, T> tickContainer);
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/Platform.java b/api/src/main/java/me/tofaa/entitylib/Platform.java
new file mode 100644
index 0000000..caa366a
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/Platform.java
@@ -0,0 +1,53 @@
+package me.tofaa.entitylib;
+
+import me.tofaa.entitylib.event.EntityLibEvent;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.function.Consumer;
+import java.util.logging.Logger;
+
+/**
+ * A generic representation of a platform that EntityLib is running on.
+ * @param <P> The platform handle, for Spigot this would be a JavaPlugin. etc etc.
+ */
+public interface Platform<P> {
+
+
+    /**
+     * @return the logger EntityLib uses internally.
+     */
+    @NotNull Logger getLogger();
+
+    /**
+     * Sends an event to the platform. Platform implementations should handle the event accordingly.
+     * @param event the event to send.
+     */
+    void sendEvent(EntityLibEvent event);
+
+    /**
+     * Registers a listener for the given event class, the handle will be called when the event is sent.
+     * @param eventClass the event class to listen for.
+     * @param handle the handle to call when the event is sent.
+     * @param <T> the event type.
+     */
+    <T extends EntityLibEvent> void registerListener(Class<T> eventClass, Consumer<T> handle);
+
+    /**
+     * Sets up the API for the platform. This method should be called automatically by the platform. Don't call it yourself.
+     * @param settings
+     */
+    void setupApi(@NotNull APISettings settings);
+
+    /**
+     * @return The API instance.
+     */
+    EntityLibAPI<?, ?> getAPI();
+
+    /**
+     * @return the platforms name.
+     */
+    String getName();
+
+    @NotNull P getHandle();
+
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/WorldWrapper.java b/api/src/main/java/me/tofaa/entitylib/WorldWrapper.java
new file mode 100644
index 0000000..1cfdb45
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/WorldWrapper.java
@@ -0,0 +1,19 @@
+package me.tofaa.entitylib;
+
+import com.github.retrooper.packetevents.protocol.world.states.WrappedBlockState;
+import com.github.retrooper.packetevents.resources.ResourceLocation;
+
+/**
+ * Represents a platform specific world.
+ * These are not needed at all times, and should exclusively be used when an Entity needs to be
+ * aware of its surroundings.
+ * @param <W> The platform specific World type.
+ */
+public interface WorldWrapper<W> {
+
+    ResourceLocation getPacketEventsWorld();
+
+    WrappedBlockState getBlock(int x, int y, int z);
+
+    W getHandle();
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/event/EntityLibEvent.java b/api/src/main/java/me/tofaa/entitylib/event/EntityLibEvent.java
new file mode 100644
index 0000000..8f3e66c
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/event/EntityLibEvent.java
@@ -0,0 +1,13 @@
+package me.tofaa.entitylib.event;
+
+public interface EntityLibEvent {
+
+    boolean isCancelled();
+
+    void setCancelled(boolean cancelled);
+
+    default boolean isAsync() {
+        return false;
+    }
+
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/event/UserReceiveMetaUpdateEvent.java b/api/src/main/java/me/tofaa/entitylib/event/UserReceiveMetaUpdateEvent.java
new file mode 100644
index 0000000..40df9cd
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/event/UserReceiveMetaUpdateEvent.java
@@ -0,0 +1,29 @@
+package me.tofaa.entitylib.event;
+
+import com.github.retrooper.packetevents.protocol.player.User;
+import me.tofaa.entitylib.meta.EntityMeta;
+
+public final class UserReceiveMetaUpdateEvent implements EntityLibEvent {
+
+    private final User user;
+    private boolean cancelled;
+    private EntityMeta meta;
+
+    public UserReceiveMetaUpdateEvent(User user) {
+        this.user = user;
+    }
+
+    public User getUser() {
+        return user;
+    }
+
+    @Override
+    public boolean isCancelled() {
+        return false;
+    }
+
+    @Override
+    public void setCancelled(boolean cancelled) {
+
+    }
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/extras/InvalidVersionException.java b/api/src/main/java/me/tofaa/entitylib/extras/InvalidVersionException.java
new file mode 100644
index 0000000..a6d0964
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/extras/InvalidVersionException.java
@@ -0,0 +1,23 @@
+package me.tofaa.entitylib.extras;
+
+public class InvalidVersionException extends RuntimeException {
+
+    public InvalidVersionException() {
+    }
+
+    public InvalidVersionException(String message) {
+        super(message);
+    }
+
+    public InvalidVersionException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    public InvalidVersionException(Throwable cause) {
+        super(cause);
+    }
+
+    public InvalidVersionException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
+        super(message, cause, enableSuppression, writableStackTrace);
+    }
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/EntityMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/EntityMeta.java
new file mode 100644
index 0000000..bab0c11
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/EntityMeta.java
@@ -0,0 +1,221 @@
+package me.tofaa.entitylib.meta;
+
+import com.github.retrooper.packetevents.manager.server.ServerVersion;
+import com.github.retrooper.packetevents.manager.server.VersionComparison;
+import com.github.retrooper.packetevents.protocol.entity.data.EntityData;
+import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
+import com.github.retrooper.packetevents.protocol.entity.data.EntityMetadataProvider;
+import com.github.retrooper.packetevents.protocol.entity.pose.EntityPose;
+import com.github.retrooper.packetevents.protocol.player.ClientVersion;
+import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerEntityMetadata;
+import me.tofaa.entitylib.EntityLib;
+import me.tofaa.entitylib.extras.InvalidVersionException;
+import net.kyori.adventure.text.Component;
+
+import java.util.List;
+
+public class EntityMeta implements EntityMetadataProvider {
+
+    public static final byte OFFSET = 0;
+    public static final byte MAX_OFFSET = OFFSET + 8;
+
+    private final static byte ON_FIRE_BIT = 0x01;
+    private final static byte CROUCHING_BIT = 0x02;
+    private final static byte SPRINTING_BIT = 0x08;
+    private final static byte SWIMMING_BIT = 0x10;
+    private final static byte INVISIBLE_BIT = 0x20;
+    private final static byte HAS_GLOWING_EFFECT_BIT = 0x40;
+    private final static byte FLYING_WITH_ELYTRA_BIT = (byte) 0x80;
+
+    protected final int entityId;
+    protected final Metadata metadata;
+
+    public EntityMeta(int entityId, Metadata metadata) {
+        this.entityId = entityId;
+        this.metadata = metadata;
+    }
+
+    public boolean isOnFire() {
+        return getMaskBit(OFFSET, ON_FIRE_BIT);
+    }
+
+    public void setOnFire(boolean value) {
+        setMaskBit(OFFSET, ON_FIRE_BIT, value);
+    }
+
+    public boolean isSneaking() {
+        return getMaskBit(OFFSET, CROUCHING_BIT);
+    }
+
+    public void setSneaking(boolean value) {
+        setMaskBit(OFFSET, CROUCHING_BIT, value);
+    }
+
+    public boolean isSprinting() {
+        return getMaskBit(OFFSET, SPRINTING_BIT);
+    }
+
+    public void setSprinting(boolean value) {
+        setMaskBit(OFFSET, SPRINTING_BIT, value);
+    }
+
+    public boolean isInvisible() {
+        return getMaskBit(OFFSET, INVISIBLE_BIT);
+    }
+
+    public void setInvisible(boolean value) {
+        setMaskBit(OFFSET, INVISIBLE_BIT, value);
+    }
+
+    public short getAirTicks() {
+        return this.metadata.getIndex((byte) 1, (short) 300);
+    }
+
+    public void setAirTicks(short value) {
+        this.metadata.setIndex((byte) 1, EntityDataTypes.SHORT, value);
+    }
+
+    public Component getCustomName() {
+        return this.metadata.getIndex(offset(OFFSET, 2), null);
+    }
+
+    public void setCustomName(Component value) {
+        this.metadata.setIndex(offset(OFFSET, 2), EntityDataTypes.ADV_COMPONENT, value);
+    }
+
+    public boolean isCustomNameVisible() {
+        return this.metadata.getIndex(offset(OFFSET, 3), false);
+    }
+
+    public void setCustomNameVisible(boolean value) {
+        this.metadata.setIndex(offset(OFFSET, 3), EntityDataTypes.BOOLEAN, value);
+    }
+
+    public boolean hasGlowingEffect() {
+        return getMaskBit(OFFSET, HAS_GLOWING_EFFECT_BIT);
+    }
+
+    public boolean isSwimming() {
+        return getMaskBit(OFFSET, SWIMMING_BIT);
+    }
+
+    public void setSwimming(boolean value) {
+        setMaskBit(OFFSET, SWIMMING_BIT, value);
+    }
+
+    public void setHasGlowingEffect(boolean value) {
+        setMaskBit(OFFSET, HAS_GLOWING_EFFECT_BIT, value);
+    }
+
+    public boolean isFlyingWithElytra() {
+        return getMaskBit(OFFSET, FLYING_WITH_ELYTRA_BIT);
+    }
+
+    public void setFlyingWithElytra(boolean value) {
+        setMaskBit(OFFSET, FLYING_WITH_ELYTRA_BIT, value);
+    }
+
+    public boolean isSilent() {
+        return this.metadata.getIndex((byte) 4, false);
+    }
+
+    public void setSilent(boolean value) {
+        this.metadata.setIndex((byte) 4, EntityDataTypes.BOOLEAN, value);
+    }
+
+    public boolean isHasNoGravity() {
+        return this.metadata.getIndex(offset(OFFSET, 5), true);
+    }
+
+    public void setHasNoGravity(boolean value) {
+        this.metadata.setIndex(offset(OFFSET, 5), EntityDataTypes.BOOLEAN, value);
+    }
+
+    public EntityPose getPose() {
+        return this.metadata.getIndex(offset(OFFSET, 6), EntityPose.STANDING);
+    }
+
+    public void setPose(EntityPose value) {
+        this.metadata.setIndex(offset(OFFSET, 6), EntityDataTypes.ENTITY_POSE, value);
+    }
+
+    public int getTicksFrozenInPowderedSnow() {
+        return this.metadata.getIndex(offset(OFFSET, 7), 0);
+    }
+
+    public void setTicksFrozenInPowderedSnow(int value) {
+        this.metadata.setIndex(offset(OFFSET, 7), EntityDataTypes.INT, value);
+    }
+
+    public WrapperPlayServerEntityMetadata createPacket() {
+        return metadata.createPacket();
+    }
+
+    protected static void isVersionOlder(ServerVersion version) {
+        if (!EntityLib.getApi().getPacketEvents().getServerManager().getVersion().is(VersionComparison.OLDER_THAN, version)) {
+            throw new InvalidVersionException("This method is only available for versions older than " + version.name() + ".");
+        }
+    }
+
+    protected static void isVersionNewer(ServerVersion version) {
+        if (!EntityLib.getApi().getPacketEvents().getServerManager().getVersion().is(VersionComparison.NEWER_THAN, version)) {
+            throw new InvalidVersionException("This method is only available for versions newer than " + version.name() + ".");
+        }
+    }
+
+    protected static boolean isVersion(ServerVersion version, VersionComparison comparison) {
+        return EntityLib.getApi().getPacketEvents().getServerManager().getVersion().is(comparison, version);
+    }
+
+    protected static boolean isVersion(ServerVersion version) {
+        return EntityLib.getApi().getPacketEvents().getServerManager().getVersion().is(VersionComparison.EQUALS, version);
+    }
+
+    /**
+     * Annoying java 8 not letting me do OFFSET + amount in the method call so this is a workaround
+     * @param value the value to offset
+     * @param amount the amount to offset by
+     * @return the offset value
+     */
+    protected static byte offset(byte value, int amount) {
+        return (byte) (value + amount);
+    }
+
+    protected byte getMask(byte index) {
+        return this.metadata.getIndex(index, (byte) 0);
+    }
+
+    protected void setMask(byte index, byte mask) {
+        this.metadata.setIndex(index, EntityDataTypes.BYTE, mask);
+    }
+
+    protected boolean getMaskBit(byte index, byte bit) {
+        return (getMask(index) & bit) == bit;
+    }
+
+    protected void setMaskBit(int index, byte bit, boolean value) {
+        byte mask = getMask((byte)index);
+        boolean currentValue = (mask & bit) == bit;
+        if (currentValue == value) {
+            return;
+        }
+        if (value) {
+            mask |= bit;
+        } else {
+            mask &= (byte) ~bit;
+        }
+        setMask((byte)index, mask);
+    }
+
+    @Override
+    public List<EntityData> entityData(ClientVersion clientVersion) {
+        return metadata.getEntries(); // TODO: Atm this is useless cause of the way the api works. Might change in the future
+    }
+
+    @Override
+    public List<EntityData> entityData() {
+        return metadata.getEntries();
+    }
+
+
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/Metadata.java b/api/src/main/java/me/tofaa/entitylib/meta/Metadata.java
new file mode 100644
index 0000000..cc4c681
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/Metadata.java
@@ -0,0 +1,45 @@
+package me.tofaa.entitylib.meta;
+
+import com.github.retrooper.packetevents.protocol.entity.data.EntityData;
+import com.github.retrooper.packetevents.protocol.entity.data.EntityDataType;
+import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerEntityMetadata;
+import me.tofaa.entitylib.EntityLib;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+@SuppressWarnings("unchecked")
+public class Metadata {
+
+    private final Map<Byte, EntityData> metadataMap = new ConcurrentHashMap<>();
+    private final int entityId;
+
+    public Metadata(int entityId) {
+        this.entityId = entityId;
+    }
+
+    public <T> T getIndex(byte index, @Nullable T defaultValue) {
+        EntityData entityData = metadataMap.get(index);
+        if (entityData == null) return defaultValue;
+        if (entityData.getValue() == null) return defaultValue;
+        return (T) entityData.getValue();
+    }
+
+    public <T> void setIndex(byte index, @NotNull EntityDataType<T> dataType, T value) {
+        EntityData data = new EntityData(index, dataType, value);
+        this.metadataMap.put(index, data);
+    }
+
+    @NotNull List<EntityData> getEntries() {
+        return new ArrayList<>(metadataMap.values());
+    }
+
+    public WrapperPlayServerEntityMetadata createPacket() {
+        return new WrapperPlayServerEntityMetadata(entityId, getEntries());
+    }
+
+}
\ No newline at end of file
diff --git a/api/src/main/java/me/tofaa/entitylib/tick/TickContainer.java b/api/src/main/java/me/tofaa/entitylib/tick/TickContainer.java
new file mode 100644
index 0000000..f1b856f
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/tick/TickContainer.java
@@ -0,0 +1,72 @@
+package me.tofaa.entitylib.tick;
+
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * Represents a storage/container for {@link Tickable}s.
+ * @param <T> The type of {@link Tickable} to store.
+ * @param <H> If a platform enforces a specific method of ticking, this type represents the handler for that method.
+ */
+public abstract class TickContainer<T extends Tickable, H> {
+
+    private final Set<T> tickables = new HashSet<>();
+    private H handle;
+
+    /**
+     * @return The {@link Tickable}s stored in this container. This collection is immutable
+     */
+    public @NotNull Collection<T> getTickables() {
+        return Collections.unmodifiableCollection(tickables);
+    }
+
+    /**
+     * Adds a {@link Tickable} to this container.
+     * @param tickable The {@link Tickable} to add.
+     * @return {@code true} if the {@link Tickable} was added, {@code false} otherwise.
+     */
+    public boolean addTickable(@NotNull T tickable) {
+        return tickables.add(tickable);
+    }
+
+    /**
+     * Removes a {@link Tickable} from this container.
+     * @param tickable The {@link Tickable} to remove.
+     * @return {@code true} if the {@link Tickable} was removed, {@code false} otherwise.
+     */
+    public boolean removeTickable(T tickable) {
+        return tickables.remove(tickable);
+    }
+
+    /**
+     * Ticks all {@link Tickable}s in this container, this method can be overriden to provide a custom implementation.
+     * @param time The current time in milliseconds, incase the {@link Tickable} needs to know the current time.
+     */
+    public void tick(long time) {
+        for (T tickable : tickables) {
+            tickable.tick(time);
+        }
+    }
+
+    /**
+     * @return The handler for this container.
+     */
+    public @NotNull H getHandle() {
+        return handle;
+    }
+
+    /**
+     * Sets the handler for this container. This method is only used internally.
+     * @param handle The handler to set.
+     */
+    @ApiStatus.Internal
+    public void setHandle(@NotNull H handle) {
+        this.handle = handle;
+    }
+
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/tick/Tickable.java b/api/src/main/java/me/tofaa/entitylib/tick/Tickable.java
new file mode 100644
index 0000000..11dd41b
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/tick/Tickable.java
@@ -0,0 +1,7 @@
+package me.tofaa.entitylib.tick;
+
+public interface Tickable {
+
+    void tick(long time);
+
+}
diff --git a/build.gradle b/build.gradle
index 1958f2c..555b4ab 100644
--- a/build.gradle
+++ b/build.gradle
@@ -5,6 +5,12 @@ plugins {
 
 allprojects {
 
+    project.ext.adventureVersion = '4.15.0'
+    project.ext.adventureDependencies=["net.kyori:adventure-api:${adventureVersion}",
+                                       "net.kyori:adventure-text-serializer-gson:${adventureVersion}",
+                                       "net.kyori:adventure-text-serializer-legacy:${adventureVersion}",
+                                       "net.kyori:adventure-nbt:${adventureVersion}"]
+
     apply plugin: 'java'
 
     group = 'me.tofaa.entitylib'
diff --git a/platforms/spigot/build.gradle b/platforms/spigot/build.gradle
new file mode 100644
index 0000000..90169d6
--- /dev/null
+++ b/platforms/spigot/build.gradle
@@ -0,0 +1,15 @@
+plugins {
+    id 'java'
+}
+
+group = 'me.tofaa.entitylib'
+version = '1.0-SNAPSHOT'
+
+repositories {
+    mavenCentral()
+}
+
+dependencies {
+    implementation(project(":api"))
+    implementation('org.spigotmc:spigot-api:1.20.1-R0.1-SNAPSHOT')
+}
diff --git a/platforms/spigot/src/main/java/me/tofaa/entitylib/spigot/SpigotEntityLibAPI.java b/platforms/spigot/src/main/java/me/tofaa/entitylib/spigot/SpigotEntityLibAPI.java
new file mode 100644
index 0000000..5f2222e
--- /dev/null
+++ b/platforms/spigot/src/main/java/me/tofaa/entitylib/spigot/SpigotEntityLibAPI.java
@@ -0,0 +1,98 @@
+package me.tofaa.entitylib.spigot;
+
+import com.github.retrooper.packetevents.PacketEventsAPI;
+import me.tofaa.entitylib.APISettings;
+import me.tofaa.entitylib.EntityLibAPI;
+import me.tofaa.entitylib.tick.TickContainer;
+import org.bukkit.Bukkit;
+import org.bukkit.World;
+import org.bukkit.scheduler.BukkitTask;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.logging.Level;
+
+public class SpigotEntityLibAPI implements EntityLibAPI<World, BukkitTask> {
+
+    private final SpigotEntityLibPlatform platform;
+    private final PacketEventsAPI<?> packetEvents;
+    private final APISettings settings;
+    private Collection<TickContainer<?, BukkitTask>> tickContainers;
+
+    SpigotEntityLibAPI(SpigotEntityLibPlatform platform, APISettings settings) {
+        this.platform = platform;
+        this.packetEvents = settings.getPacketEvents();
+        this.settings = settings;
+    }
+
+    @Override
+    public void onLoad() {
+        this.tickContainers = settings.shouldTickTickables() ? new HashSet<>() : Collections.EMPTY_SET;
+    }
+
+    @Override
+    public void onEnable() {
+
+    }
+
+    @NotNull @Override
+    public APISettings getSettings() {
+        return settings;
+    }
+
+    @Override
+    public void setupTickingContainers() {
+        if (!getSettings().shouldTickTickables()) {
+            if (getSettings().isDebugMode()) {
+                platform.getLogger().log(Level.CONFIG, "Skipping ticking containers as it is disabled in the settings.");
+            }
+            return;
+        }
+
+        if (getSettings().isDebugMode()) {
+            platform.getLogger().log(Level.CONFIG, "Setting up ticking containers...");
+        }
+        if (tickContainers.isEmpty()) {
+            if (getSettings().isDebugMode()) {
+                platform.getLogger().log(Level.CONFIG, "No tick containers found.");
+            }
+            return;
+        }
+
+        if (getSettings().isDebugMode()) {
+            platform.getLogger().log(Level.CONFIG, "Found " + tickContainers.size() + " tick containers.");
+        }
+
+        tickContainers.forEach(this::registerNewTickContainer);
+    }
+
+    @Override
+    public PacketEventsAPI<?> getPacketEvents() {
+        return packetEvents;
+    }
+
+    @Override
+    public Collection<TickContainer<?, BukkitTask>> getTickContainers() {
+        return tickContainers;
+    }
+
+    @Override
+    public void addTickContainer(@NotNull TickContainer<?, BukkitTask> tickContainer) {
+        tickContainers.add(tickContainer);
+        registerNewTickContainer(tickContainer);
+    }
+
+    public void registerNewTickContainer(TickContainer<?, BukkitTask> tickContainer) {
+
+        if (getSettings().isDebugMode()) {
+            platform.getLogger().log(Level.CONFIG, "Registering new tick container...");
+        }
+        getTickContainers().add(tickContainer);
+        BukkitTask task = Bukkit.getScheduler().runTaskTimerAsynchronously(platform.getHandle(), () -> tickContainer.tick(System.currentTimeMillis()), 1L, 1L);
+        tickContainer.setHandle(task);
+    }
+
+
+}
diff --git a/platforms/spigot/src/main/java/me/tofaa/entitylib/spigot/SpigotEntityLibPlatform.java b/platforms/spigot/src/main/java/me/tofaa/entitylib/spigot/SpigotEntityLibPlatform.java
new file mode 100644
index 0000000..c719df0
--- /dev/null
+++ b/platforms/spigot/src/main/java/me/tofaa/entitylib/spigot/SpigotEntityLibPlatform.java
@@ -0,0 +1,65 @@
+package me.tofaa.entitylib.spigot;
+
+import me.tofaa.entitylib.APISettings;
+import me.tofaa.entitylib.EntityLibAPI;
+import me.tofaa.entitylib.Platform;
+import me.tofaa.entitylib.event.EntityLibEvent;
+import me.tofaa.entitylib.tick.TickContainer;
+import org.bukkit.Bukkit;
+import org.bukkit.plugin.java.JavaPlugin;
+import org.bukkit.scheduler.BukkitTask;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Collection;
+import java.util.function.Consumer;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+public class SpigotEntityLibPlatform implements Platform<JavaPlugin> {
+
+    private final JavaPlugin plugin;
+    private SpigotEntityLibAPI api;
+    private Logger logger;
+
+    public SpigotEntityLibPlatform(@NotNull JavaPlugin plugin) {
+        this.plugin = plugin;
+    }
+
+    @Override
+    public void setupApi(@NotNull APISettings settings) {
+        this.logger = settings.shouldUsePlatformLogger() ? plugin.getLogger() : Logger.getLogger("EntityLib");
+        this.api = new SpigotEntityLibAPI(this, settings);
+        this.api.onLoad();
+        this.api.onEnable();
+    }
+
+    @Override
+    public @NotNull Logger getLogger() {
+        return logger;
+    }
+
+    @Override
+    public void sendEvent(EntityLibEvent event) {
+
+    }
+
+    @Override
+    public <T extends EntityLibEvent> void registerListener(Class<T> eventClass, Consumer<T> handle) {
+
+    }
+
+    @Override
+    public EntityLibAPI getAPI() {
+        return api;
+    }
+
+    @Override
+    public @NotNull JavaPlugin getHandle() {
+        return plugin;
+    }
+
+    @Override
+    public String getName() {
+        return "Spigot";
+    }
+}
diff --git a/settings.gradle b/settings.gradle
index 81e87e9..5426790 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -1,4 +1,6 @@
 rootProject.name = 'EntityLib'
 include 'test-plugin'
 include 'api'
+include 'platforms:spigot'
+findProject(':platforms:spigot')?.name = 'spigot'
 
diff --git a/src/main/java/me/tofaa/entitylib/meta/Metadata.java b/src/main/java/me/tofaa/entitylib/meta/Metadata.java
index 8dd0d57..bcb0f7f 100644
--- a/src/main/java/me/tofaa/entitylib/meta/Metadata.java
+++ b/src/main/java/me/tofaa/entitylib/meta/Metadata.java
@@ -9,7 +9,6 @@ import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
 import java.util.ArrayList;
-import java.util.Collections;
 import java.util.List;
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;

From 9cc097aab25f5287a14b5d5ce2c3eedd214adfee Mon Sep 17 00:00:00 2001
From: Tofaa <82680183+Tofaa2@users.noreply.github.com>
Date: Sat, 27 Jan 2024 12:18:34 +0400
Subject: [PATCH 03/19] report meta and entity creation

---
 .idea/gradle.xml                              |   3 +
 .idea/workspace.xml                           | 139 +++++++---
 .../java/me/tofaa/entitylib/APISettings.java  |  30 +--
 .../me/tofaa/entitylib/EntityIdProvider.java  |  23 ++
 .../java/me/tofaa/entitylib/EntityLib.java    |  20 +-
 .../java/me/tofaa/entitylib/EntityLibAPI.java |  20 +-
 .../tofaa/entitylib/EntityUuidProvider.java   |  21 ++
 .../java/me/tofaa/entitylib/Platform.java     |  40 ++-
 .../java/me/tofaa/entitylib/WorldWrapper.java |  47 +++-
 .../tofaa/entitylib/event/EntityLibEvent.java |   5 -
 .../me/tofaa/entitylib/event/EventBus.java    |  61 +++++
 .../tofaa/entitylib/event/EventBusAsync.java  |  60 +++++
 .../tofaa/entitylib/event/EventBusSync.java   |  43 +++
 .../tofaa/entitylib/event/EventListener.java  |  27 ++
 .../UserReceiveMetaUpdateEvent.java           |   3 +-
 .../entitylib/extras/CoordinateUtil.java      |  38 +++
 .../entitylib/extras/VersionChecker.java      |  17 ++
 .../me/tofaa/entitylib/meta/EntityMeta.java   |  30 +++
 .../entitylib/meta/MetaConverterRegistry.java | 175 ++++++++++++
 .../me/tofaa/entitylib/meta/UsedVersion.java  |   9 +
 .../entitylib/meta/VersionCompatCheck.java    |  15 ++
 .../meta/display/AbstractDisplayMeta.java     | 255 ++++++++++++++++++
 .../meta/display/BlockDisplayMeta.java        |  23 ++
 .../meta/display/ItemDisplayMeta.java         |  47 ++++
 .../meta/display/TextDisplayMeta.java         |  94 +++++++
 .../me/tofaa/entitylib/meta/mobs/BatMeta.java |  26 ++
 .../me/tofaa/entitylib/meta/mobs/BeeMeta.java |  52 ++++
 .../tofaa/entitylib/meta/mobs/DonkeyMeta.java |  14 +
 .../me/tofaa/entitylib/meta/mobs/FoxMeta.java | 119 ++++++++
 .../tofaa/entitylib/meta/mobs/FrogMeta.java   |  46 ++++
 .../tofaa/entitylib/meta/mobs/GoatMeta.java   |  25 ++
 .../tofaa/entitylib/meta/mobs/HoglinMeta.java |  26 ++
 .../tofaa/entitylib/meta/mobs/OcelotMeta.java |  27 ++
 .../tofaa/entitylib/meta/mobs/PandaMeta.java  | 109 ++++++++
 .../entitylib/meta/mobs/PolarBearMeta.java    |  24 ++
 .../entitylib/meta/mobs/SnifferMeta.java      |  33 +++
 .../entitylib/meta/mobs/StriderMeta.java      |  41 +++
 .../meta/mobs/cuboid/MagmaCubeMeta.java       |  13 +
 .../entitylib/meta/mobs/cuboid/SlimeMeta.java |  23 ++
 .../meta/mobs/golem/IronGolemMeta.java        |  26 ++
 .../meta/mobs/golem/ShulkerMeta.java          |  54 ++++
 .../meta/mobs/golem/SnowGolemMeta.java        |  25 ++
 .../meta/mobs/horse/BaseHorseMeta.java        |  82 ++++++
 .../meta/mobs/horse/ChestedHorseMeta.java     |  24 ++
 .../entitylib/meta/mobs/horse/DonkeyMeta.java |  14 +
 .../entitylib/meta/mobs/horse/HorseMeta.java  |  87 ++++++
 .../entitylib/meta/mobs/horse/LlamaMeta.java  |  48 ++++
 .../entitylib/meta/mobs/horse/MuleMeta.java   |  13 +
 .../meta/mobs/horse/SkeletonHorseMeta.java    |  13 +
 .../meta/mobs/horse/TraderLlamaMeta.java      |  14 +
 .../meta/mobs/horse/ZombieHorseMeta.java      |  13 +
 .../meta/mobs/minecart/BaseMinecartMeta.java  |  62 +++++
 .../meta/mobs/minecart/ChestMinecartMeta.java |  19 ++
 .../minecart/CommandBlockMinecartMeta.java    |  38 +++
 .../mobs/minecart/FurnaceMinecartMeta.java    |  26 ++
 .../mobs/minecart/HopperMinecartMeta.java     |  18 ++
 .../meta/mobs/minecart/MinecartMeta.java      |  18 ++
 .../mobs/minecart/SpawnerMinecartMeta.java    |  19 ++
 .../meta/mobs/minecart/TntMinecartMeta.java   |  18 ++
 .../meta/mobs/monster/BlazeMeta.java          |  26 ++
 .../meta/mobs/monster/CaveSpiderMeta.java     |  13 +
 .../meta/mobs/monster/CreeperMeta.java        |  49 ++++
 .../meta/mobs/monster/ElderGuardianMeta.java  |  13 +
 .../meta/mobs/monster/EndermanMeta.java       |  44 +++
 .../meta/mobs/monster/EndermiteMeta.java      |  14 +
 .../meta/mobs/monster/GhastMeta.java          |  25 ++
 .../meta/mobs/monster/GiantMeta.java          |  13 +
 .../meta/mobs/monster/GuardianMeta.java       |  36 +++
 .../meta/mobs/monster/PhantomMeta.java        |  24 ++
 .../meta/mobs/monster/SilverfishMeta.java     |  14 +
 .../meta/mobs/monster/SpiderMeta.java         |  27 ++
 .../entitylib/meta/mobs/monster/VexMeta.java  |  25 ++
 .../meta/mobs/monster/WitherMeta.java         |  55 ++++
 .../meta/mobs/monster/ZoglinMeta.java         |  28 ++
 .../mobs/monster/piglin/BasePiglinMeta.java   |  25 ++
 .../mobs/monster/piglin/PiglinBruteMeta.java  |  13 +
 .../meta/mobs/monster/piglin/PiglinMeta.java  |  43 +++
 .../meta/mobs/monster/raider/EvokerMeta.java  |  13 +
 .../mobs/monster/raider/IllusionerMeta.java   |  13 +
 .../mobs/monster/raider/PillagerMeta.java     |  14 +
 .../meta/mobs/monster/raider/RaiderMeta.java  |  25 ++
 .../meta/mobs/monster/raider/RavagerMeta.java |  14 +
 .../raider/SpellcasterIllagerMeta.java        |  13 +
 .../mobs/monster/raider/VindicatorMeta.java   |  13 +
 .../meta/mobs/monster/raider/WitchMeta.java   |  23 ++
 .../mobs/monster/skeleton/SkeletonMeta.java   |  14 +
 .../meta/mobs/monster/skeleton/StrayMeta.java |  11 +
 .../monster/skeleton/WitherSkeletonMeta.java  |  12 +
 .../meta/mobs/monster/zombie/DrownedMeta.java |  12 +
 .../meta/mobs/monster/zombie/HuskMeta.java    |  13 +
 .../meta/mobs/monster/zombie/ZombieMeta.java  |  35 +++
 .../monster/zombie/ZombieVillagerMeta.java    |  43 +++
 .../monster/zombie/ZombifiedPiglinMeta.java   |  13 +
 .../meta/mobs/passive/ChickenMeta.java        |  14 +
 .../entitylib/meta/mobs/passive/CowMeta.java  |  14 +
 .../meta/mobs/passive/MooshroomMeta.java      |  33 +++
 .../entitylib/meta/mobs/passive/PigMeta.java  |  34 +++
 .../meta/mobs/passive/RabbitMeta.java         |  46 ++++
 .../meta/mobs/passive/SheepMeta.java          |  43 +++
 .../meta/mobs/passive/TurtleMeta.java         |  66 +++++
 .../entitylib/meta/mobs/tameable/CatMeta.java |  72 +++++
 .../meta/mobs/tameable/ParrotMeta.java        |  38 +++
 .../meta/mobs/tameable/WolfMeta.java          |  40 +++
 .../meta/mobs/villager/BaseVillagerMeta.java  |  24 ++
 .../meta/mobs/villager/VillagerMeta.java      |  81 ++++++
 .../mobs/villager/WanderingTraderMeta.java    |  13 +
 .../meta/mobs/water/AxolotlMeta.java          |  50 ++++
 .../meta/mobs/water/BaseFishMeta.java         |  25 ++
 .../entitylib/meta/mobs/water/CodMeta.java    |  13 +
 .../meta/mobs/water/DolphinMeta.java          |  43 +++
 .../meta/mobs/water/GlowSquidMeta.java        |  24 ++
 .../meta/mobs/water/PufferFishMeta.java       |  32 +++
 .../entitylib/meta/mobs/water/SalmonMeta.java |   9 +
 .../entitylib/meta/mobs/water/SquidMeta.java  |  14 +
 .../meta/mobs/water/TropicalFishMeta.java     | 128 +++++++++
 .../meta/other/AreaEffectCloudMeta.java       |  40 +++
 .../entitylib/meta/other/ArmorStandMeta.java  | 110 ++++++++
 .../tofaa/entitylib/meta/other/BoatMeta.java  |  86 ++++++
 .../entitylib/meta/other/EndCrystalMeta.java  |  36 +++
 .../entitylib/meta/other/EnderDragonMeta.java |  43 +++
 .../entitylib/meta/other/EvokerFangsMeta.java |  14 +
 .../meta/other/FallingBlockMeta.java          |  46 ++++
 .../meta/other/FireworkRocketMeta.java        |  50 ++++
 .../entitylib/meta/other/FishingHookMeta.java |  53 ++++
 .../meta/other/GlowItemFrameMeta.java         |  13 +
 .../entitylib/meta/other/InteractionMeta.java |  41 +++
 .../entitylib/meta/other/ItemFrameMeta.java   |  74 +++++
 .../entitylib/meta/other/LeashKnotMeta.java   |  14 +
 .../meta/other/LightningBoltMeta.java         |  14 +
 .../entitylib/meta/other/LlamaSpitMeta.java   |  25 ++
 .../entitylib/meta/other/MarkerMeta.java      |  14 +
 .../entitylib/meta/other/PaintingMeta.java    | 120 +++++++++
 .../entitylib/meta/other/PrimedTntMeta.java   |  23 ++
 .../entitylib/meta/projectile/ArrowMeta.java  |  47 ++++
 .../meta/projectile/BaseArrowMeta.java        |  48 ++++
 .../meta/projectile/DragonFireballMeta.java   |  38 +++
 .../meta/projectile/EyeOfEnderMeta.java       |  20 ++
 .../meta/projectile/ItemEntityMeta.java       |  26 ++
 .../meta/projectile/LargeFireballMeta.java    |  39 +++
 .../meta/projectile/ShulkerBulletMeta.java    |  25 ++
 .../meta/projectile/SmallFireballMeta.java    |  43 +++
 .../meta/projectile/SnowballMeta.java         |  19 ++
 .../meta/projectile/SpectralArrowMeta.java    |  37 +++
 .../meta/projectile/ThrownEggMeta.java        |  20 ++
 .../meta/projectile/ThrownEnderPearlMeta.java |  19 ++
 .../meta/projectile/ThrownExpBottleMeta.java  |  19 ++
 .../meta/projectile/ThrownPotionMeta.java     |  17 ++
 .../meta/projectile/ThrownTridentMeta.java    |  31 +++
 .../meta/projectile/WitherSkullMeta.java      |  50 ++++
 .../entitylib/meta/types/AgeableMeta.java     |  23 ++
 .../entitylib/meta/types/DisplayMeta.java     | 255 ++++++++++++++++++
 .../meta/types/ItemContainerMeta.java         |  27 ++
 .../meta/types/LivingEntityMeta.java          | 119 ++++++++
 .../tofaa/entitylib/meta/types/MobMeta.java   |  49 ++++
 .../entitylib/meta/types/ObjectData.java      |   9 +
 .../entitylib/meta/types/PlayerMeta.java      | 148 ++++++++++
 .../entitylib/meta/types/ProjectileMeta.java  |  10 +
 .../entitylib/meta/types/TameableMeta.java    |  46 ++++
 .../entitylib/meta/types/WaterMobMeta.java    |  13 +
 .../entitylib/wrapper/WrapperEntity.java      | 204 ++++++++++++++
 .../wrapper/WrapperEntityCreature.java        |  75 ++++++
 .../wrapper/WrapperEntityEquipment.java       | 119 ++++++++
 .../wrapper/WrapperExperienceOrbEntity.java   |  70 +++++
 .../wrapper/WrapperLivingEntity.java          |  16 ++
 .../tofaa/entitylib/wrapper/ai/AIGroup.java   |  70 +++++
 .../entitylib/wrapper/ai/GoalSelector.java    |  85 ++++++
 .../wrapper/ai/GoalSelectorList.java          |  55 ++++
 .../ai/goals/RandomHeadMovementGoal.java      |  81 ++++++
 common/build.gradle                           |  15 ++
 .../common/AbstractEntityLibAPI.java          |  44 +++
 .../entitylib/common/AbstractPlatform.java    |  76 ++++++
 .../common/AbstractWorldWrapper.java          | 102 +++++++
 platforms/spigot/build.gradle                 |   6 +-
 .../entitylib/spigot/SpigotEntityLibAPI.java  |  69 ++---
 .../spigot/SpigotEntityLibPlatform.java       |  42 +--
 .../tofaa/entitylib/spigot/SpigotWorld.java   |  28 ++
 settings.gradle                               |   1 +
 test-plugin/build.gradle                      |   2 +-
 .../me/tofaa/entitylib/EntityLibPlugin.java   |  32 ---
 .../entitylib/SpawnClickableFrogCommand.java  |  53 ----
 .../java/me/tofaa/entitylib/TestCommand.java  |  49 ----
 .../tofaa/entitylib/TestDisplayCommand.java   |  95 -------
 .../me/tofaa/entitylib/TestEntityCommand.java |  60 -----
 .../testentitylib/TestEntityLibPlugin.java    |  24 ++
 test-plugin/src/main/resources/plugin.yml     |   2 +-
 185 files changed, 7102 insertions(+), 464 deletions(-)
 create mode 100644 api/src/main/java/me/tofaa/entitylib/EntityIdProvider.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/EntityUuidProvider.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/event/EventBus.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/event/EventBusAsync.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/event/EventBusSync.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/event/EventListener.java
 rename api/src/main/java/me/tofaa/entitylib/event/{ => types}/UserReceiveMetaUpdateEvent.java (86%)
 create mode 100644 api/src/main/java/me/tofaa/entitylib/extras/CoordinateUtil.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/extras/VersionChecker.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/MetaConverterRegistry.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/UsedVersion.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/VersionCompatCheck.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/display/AbstractDisplayMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/display/BlockDisplayMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/display/ItemDisplayMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/display/TextDisplayMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/mobs/BatMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/mobs/BeeMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/mobs/DonkeyMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/mobs/FoxMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/mobs/FrogMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/mobs/GoatMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/mobs/HoglinMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/mobs/OcelotMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/mobs/PandaMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/mobs/PolarBearMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/mobs/SnifferMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/mobs/StriderMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/mobs/cuboid/MagmaCubeMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/mobs/cuboid/SlimeMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/mobs/golem/IronGolemMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/mobs/golem/ShulkerMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/mobs/golem/SnowGolemMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/mobs/horse/BaseHorseMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/mobs/horse/ChestedHorseMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/mobs/horse/DonkeyMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/mobs/horse/HorseMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/mobs/horse/LlamaMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/mobs/horse/MuleMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/mobs/horse/SkeletonHorseMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/mobs/horse/TraderLlamaMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/mobs/horse/ZombieHorseMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/mobs/minecart/BaseMinecartMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/mobs/minecart/ChestMinecartMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/mobs/minecart/CommandBlockMinecartMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/mobs/minecart/FurnaceMinecartMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/mobs/minecart/HopperMinecartMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/mobs/minecart/MinecartMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/mobs/minecart/SpawnerMinecartMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/mobs/minecart/TntMinecartMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/BlazeMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/CaveSpiderMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/CreeperMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/ElderGuardianMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/EndermanMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/EndermiteMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/GhastMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/GiantMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/GuardianMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/PhantomMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/SilverfishMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/SpiderMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/VexMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/WitherMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/ZoglinMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/piglin/BasePiglinMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/piglin/PiglinBruteMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/piglin/PiglinMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/raider/EvokerMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/raider/IllusionerMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/raider/PillagerMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/raider/RaiderMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/raider/RavagerMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/raider/SpellcasterIllagerMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/raider/VindicatorMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/raider/WitchMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/skeleton/SkeletonMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/skeleton/StrayMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/skeleton/WitherSkeletonMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/zombie/DrownedMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/zombie/HuskMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/zombie/ZombieMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/zombie/ZombieVillagerMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/zombie/ZombifiedPiglinMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/mobs/passive/ChickenMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/mobs/passive/CowMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/mobs/passive/MooshroomMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/mobs/passive/PigMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/mobs/passive/RabbitMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/mobs/passive/SheepMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/mobs/passive/TurtleMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/mobs/tameable/CatMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/mobs/tameable/ParrotMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/mobs/tameable/WolfMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/mobs/villager/BaseVillagerMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/mobs/villager/VillagerMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/mobs/villager/WanderingTraderMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/mobs/water/AxolotlMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/mobs/water/BaseFishMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/mobs/water/CodMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/mobs/water/DolphinMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/mobs/water/GlowSquidMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/mobs/water/PufferFishMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/mobs/water/SalmonMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/mobs/water/SquidMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/mobs/water/TropicalFishMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/other/AreaEffectCloudMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/other/ArmorStandMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/other/BoatMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/other/EndCrystalMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/other/EnderDragonMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/other/EvokerFangsMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/other/FallingBlockMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/other/FireworkRocketMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/other/FishingHookMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/other/GlowItemFrameMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/other/InteractionMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/other/ItemFrameMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/other/LeashKnotMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/other/LightningBoltMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/other/LlamaSpitMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/other/MarkerMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/other/PaintingMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/other/PrimedTntMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/projectile/ArrowMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/projectile/BaseArrowMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/projectile/DragonFireballMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/projectile/EyeOfEnderMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/projectile/ItemEntityMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/projectile/LargeFireballMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/projectile/ShulkerBulletMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/projectile/SmallFireballMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/projectile/SnowballMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/projectile/SpectralArrowMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/projectile/ThrownEggMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/projectile/ThrownEnderPearlMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/projectile/ThrownExpBottleMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/projectile/ThrownPotionMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/projectile/ThrownTridentMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/projectile/WitherSkullMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/types/AgeableMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/types/DisplayMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/types/ItemContainerMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/types/LivingEntityMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/types/MobMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/types/ObjectData.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/types/PlayerMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/types/ProjectileMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/types/TameableMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/types/WaterMobMeta.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/wrapper/WrapperEntity.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/wrapper/WrapperEntityCreature.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/wrapper/WrapperEntityEquipment.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/wrapper/WrapperExperienceOrbEntity.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/wrapper/WrapperLivingEntity.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/wrapper/ai/AIGroup.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/wrapper/ai/GoalSelector.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/wrapper/ai/GoalSelectorList.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/wrapper/ai/goals/RandomHeadMovementGoal.java
 create mode 100644 common/build.gradle
 create mode 100644 common/src/main/java/me/tofaa/entitylib/common/AbstractEntityLibAPI.java
 create mode 100644 common/src/main/java/me/tofaa/entitylib/common/AbstractPlatform.java
 create mode 100644 common/src/main/java/me/tofaa/entitylib/common/AbstractWorldWrapper.java
 create mode 100644 platforms/spigot/src/main/java/me/tofaa/entitylib/spigot/SpigotWorld.java
 delete mode 100644 test-plugin/src/main/java/me/tofaa/entitylib/EntityLibPlugin.java
 delete mode 100644 test-plugin/src/main/java/me/tofaa/entitylib/SpawnClickableFrogCommand.java
 delete mode 100644 test-plugin/src/main/java/me/tofaa/entitylib/TestCommand.java
 delete mode 100644 test-plugin/src/main/java/me/tofaa/entitylib/TestDisplayCommand.java
 delete mode 100644 test-plugin/src/main/java/me/tofaa/entitylib/TestEntityCommand.java
 create mode 100644 test-plugin/src/main/java/me/tofaa/testentitylib/TestEntityLibPlugin.java

diff --git a/.idea/gradle.xml b/.idea/gradle.xml
index 3feea6d..2ca8717 100644
--- a/.idea/gradle.xml
+++ b/.idea/gradle.xml
@@ -9,6 +9,9 @@
           <set>
             <option value="$PROJECT_DIR$" />
             <option value="$PROJECT_DIR$/api" />
+            <option value="$PROJECT_DIR$/common" />
+            <option value="$PROJECT_DIR$/platforms" />
+            <option value="$PROJECT_DIR$/platforms/spigot" />
             <option value="$PROJECT_DIR$/test-plugin" />
           </set>
         </option>
diff --git a/.idea/workspace.xml b/.idea/workspace.xml
index cd26f29..5d77931 100644
--- a/.idea/workspace.xml
+++ b/.idea/workspace.xml
@@ -5,20 +5,49 @@
   </component>
   <component name="ChangeListManager">
     <list default="true" id="9d5d9b6f-43c8-41a4-bb42-a66ffc96c9b0" name="Changes" comment="">
-      <change afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/EntityLib.java" afterDir="false" />
-      <change afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/EntityLibAPI.java" afterDir="false" />
-      <change afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/Platform.java" afterDir="false" />
-      <change afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/WorldWrapper.java" afterDir="false" />
-      <change afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/event/EntityLibEvent.java" afterDir="false" />
-      <change afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/event/UserReceiveMetaUpdateEvent.java" afterDir="false" />
-      <change afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/extras/InvalidVersionException.java" afterDir="false" />
-      <change afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/meta/EntityMeta.java" afterDir="false" />
-      <change afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/meta/Metadata.java" afterDir="false" />
-      <change afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/tick/TickContainer.java" afterDir="false" />
+      <change afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/EntityIdProvider.java" afterDir="false" />
+      <change afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/EntityUuidProvider.java" afterDir="false" />
+      <change afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/event/EventBus.java" afterDir="false" />
+      <change afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/event/EventBusAsync.java" afterDir="false" />
+      <change afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/event/EventBusSync.java" afterDir="false" />
+      <change afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/event/EventListener.java" afterDir="false" />
+      <change afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/extras/VersionChecker.java" afterDir="false" />
+      <change afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/meta/MetaConverterRegistry.java" afterDir="false" />
+      <change afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/meta/UsedVersion.java" afterDir="false" />
+      <change afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/meta/VersionCompatCheck.java" afterDir="false" />
+      <change afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/meta/display/AbstractDisplayMeta.java" afterDir="false" />
+      <change afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/meta/display/BlockDisplayMeta.java" afterDir="false" />
+      <change afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/meta/display/ItemDisplayMeta.java" afterDir="false" />
+      <change afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/meta/display/TextDisplayMeta.java" afterDir="false" />
+      <change afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperEntity.java" afterDir="false" />
+      <change afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperEntityEquipment.java" afterDir="false" />
+      <change afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperLivingEntity.java" afterDir="false" />
+      <change afterPath="$PROJECT_DIR$/common/src/main/java/me/tofaa/entitylib/common/AbstractEntityLibAPI.java" afterDir="false" />
+      <change afterPath="$PROJECT_DIR$/common/src/main/java/me/tofaa/entitylib/common/AbstractPlatform.java" afterDir="false" />
+      <change afterPath="$PROJECT_DIR$/common/src/main/java/me/tofaa/entitylib/common/AbstractWorldWrapper.java" afterDir="false" />
+      <change afterPath="$PROJECT_DIR$/platforms/spigot/src/main/java/me/tofaa/entitylib/spigot/SpigotWorld.java" afterDir="false" />
+      <change afterPath="$PROJECT_DIR$/test-plugin/src/main/java/me/tofaa/testentitylib/TestEntityLibPlugin.java" afterDir="false" />
+      <change beforePath="$PROJECT_DIR$/.idea/gradle.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/gradle.xml" afterDir="false" />
       <change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
-      <change beforePath="$PROJECT_DIR$/api/build.gradle" beforeDir="false" afterPath="$PROJECT_DIR$/api/build.gradle" afterDir="false" />
-      <change beforePath="$PROJECT_DIR$/build.gradle" beforeDir="false" afterPath="$PROJECT_DIR$/build.gradle" afterDir="false" />
-      <change beforePath="$PROJECT_DIR$/src/main/java/me/tofaa/entitylib/meta/Metadata.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/me/tofaa/entitylib/meta/Metadata.java" afterDir="false" />
+      <change beforePath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/APISettings.java" beforeDir="false" afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/APISettings.java" afterDir="false" />
+      <change beforePath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/EntityLib.java" beforeDir="false" afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/EntityLib.java" afterDir="false" />
+      <change beforePath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/EntityLibAPI.java" beforeDir="false" afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/EntityLibAPI.java" afterDir="false" />
+      <change beforePath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/Platform.java" beforeDir="false" afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/Platform.java" afterDir="false" />
+      <change beforePath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/WorldWrapper.java" beforeDir="false" afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/WorldWrapper.java" afterDir="false" />
+      <change beforePath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/event/EntityLibEvent.java" beforeDir="false" afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/event/EntityLibEvent.java" afterDir="false" />
+      <change beforePath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/event/UserReceiveMetaUpdateEvent.java" beforeDir="false" afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/event/types/UserReceiveMetaUpdateEvent.java" afterDir="false" />
+      <change beforePath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/meta/EntityMeta.java" beforeDir="false" afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/meta/EntityMeta.java" afterDir="false" />
+      <change beforePath="$PROJECT_DIR$/platforms/spigot/build.gradle" beforeDir="false" afterPath="$PROJECT_DIR$/platforms/spigot/build.gradle" afterDir="false" />
+      <change beforePath="$PROJECT_DIR$/platforms/spigot/src/main/java/me/tofaa/entitylib/spigot/SpigotEntityLibAPI.java" beforeDir="false" afterPath="$PROJECT_DIR$/platforms/spigot/src/main/java/me/tofaa/entitylib/spigot/SpigotEntityLibAPI.java" afterDir="false" />
+      <change beforePath="$PROJECT_DIR$/platforms/spigot/src/main/java/me/tofaa/entitylib/spigot/SpigotEntityLibPlatform.java" beforeDir="false" afterPath="$PROJECT_DIR$/platforms/spigot/src/main/java/me/tofaa/entitylib/spigot/SpigotEntityLibPlatform.java" afterDir="false" />
+      <change beforePath="$PROJECT_DIR$/settings.gradle" beforeDir="false" afterPath="$PROJECT_DIR$/settings.gradle" afterDir="false" />
+      <change beforePath="$PROJECT_DIR$/test-plugin/build.gradle" beforeDir="false" afterPath="$PROJECT_DIR$/test-plugin/build.gradle" afterDir="false" />
+      <change beforePath="$PROJECT_DIR$/test-plugin/src/main/java/me/tofaa/entitylib/EntityLibPlugin.java" beforeDir="false" />
+      <change beforePath="$PROJECT_DIR$/test-plugin/src/main/java/me/tofaa/entitylib/SpawnClickableFrogCommand.java" beforeDir="false" />
+      <change beforePath="$PROJECT_DIR$/test-plugin/src/main/java/me/tofaa/entitylib/TestCommand.java" beforeDir="false" />
+      <change beforePath="$PROJECT_DIR$/test-plugin/src/main/java/me/tofaa/entitylib/TestDisplayCommand.java" beforeDir="false" />
+      <change beforePath="$PROJECT_DIR$/test-plugin/src/main/java/me/tofaa/entitylib/TestEntityCommand.java" beforeDir="false" />
+      <change beforePath="$PROJECT_DIR$/test-plugin/src/main/resources/plugin.yml" beforeDir="false" afterPath="$PROJECT_DIR$/test-plugin/src/main/resources/plugin.yml" afterDir="false" />
     </list>
     <option name="SHOW_DIALOG" value="false" />
     <option name="HIGHLIGHT_CONFLICTS" value="true" />
@@ -81,40 +110,64 @@
     <option name="showExcludedFiles" value="false" />
     <option name="showLibraryContents" value="true" />
   </component>
-  <component name="PropertiesComponent">{
-  &quot;keyToString&quot;: {
-    &quot;Downloaded.Files.Path.Enabled&quot;: &quot;false&quot;,
-    &quot;Gradle.Build EntityLib.executor&quot;: &quot;Run&quot;,
-    &quot;Gradle.EntityLib:test-plugin [runServer].executor&quot;: &quot;Run&quot;,
-    &quot;Repository.Attach.Annotations&quot;: &quot;false&quot;,
-    &quot;Repository.Attach.JavaDocs&quot;: &quot;false&quot;,
-    &quot;Repository.Attach.Sources&quot;: &quot;false&quot;,
-    &quot;RunOnceActivity.OpenProjectViewOnStart&quot;: &quot;true&quot;,
-    &quot;RunOnceActivity.ShowReadmeOnStart&quot;: &quot;true&quot;,
-    &quot;WebServerToolWindowFactoryState&quot;: &quot;false&quot;,
-    &quot;git-widget-placeholder&quot;: &quot;feat/platform-api&quot;,
-    &quot;ignore.virus.scanning.warn.message&quot;: &quot;true&quot;,
-    &quot;jdk.selected.JAVA_MODULE&quot;: &quot;corretto-17&quot;,
-    &quot;kotlin-language-version-configured&quot;: &quot;true&quot;,
-    &quot;last_opened_file_path&quot;: &quot;D:/Github/EntityLib&quot;,
-    &quot;node.js.detected.package.eslint&quot;: &quot;true&quot;,
-    &quot;node.js.detected.package.tslint&quot;: &quot;true&quot;,
-    &quot;node.js.selected.package.eslint&quot;: &quot;(autodetect)&quot;,
-    &quot;node.js.selected.package.tslint&quot;: &quot;(autodetect)&quot;,
-    &quot;nodejs_package_manager_path&quot;: &quot;npm&quot;,
-    &quot;project.structure.last.edited&quot;: &quot;Modules&quot;,
-    &quot;project.structure.proportion&quot;: &quot;0.0&quot;,
-    &quot;project.structure.side.proportion&quot;: &quot;0.0&quot;,
-    &quot;settings.editor.selected.configurable&quot;: &quot;preferences.pluginManager&quot;,
-    &quot;vue.rearranger.settings.migration&quot;: &quot;true&quot;
+  <component name="PropertiesComponent"><![CDATA[{
+  "keyToString": {
+    "Downloaded.Files.Path.Enabled": "false",
+    "Gradle.Build EntityLib.executor": "Run",
+    "Gradle.EntityLib [dependencies].executor": "Run",
+    "Gradle.EntityLib:test-plugin [runServer].executor": "Run",
+    "Repository.Attach.Annotations": "false",
+    "Repository.Attach.JavaDocs": "false",
+    "Repository.Attach.Sources": "false",
+    "RunOnceActivity.OpenProjectViewOnStart": "true",
+    "RunOnceActivity.ShowReadmeOnStart": "true",
+    "WebServerToolWindowFactoryState": "false",
+    "git-widget-placeholder": "feat/platform-api",
+    "ignore.virus.scanning.warn.message": "true",
+    "jdk.selected.JAVA_MODULE": "corretto-17",
+    "kotlin-language-version-configured": "true",
+    "last_opened_file_path": "D:/Github/EntityLib/api/src/main/java/me/tofaa/entitylib/meta",
+    "node.js.detected.package.eslint": "true",
+    "node.js.detected.package.tslint": "true",
+    "node.js.selected.package.eslint": "(autodetect)",
+    "node.js.selected.package.tslint": "(autodetect)",
+    "nodejs_package_manager_path": "npm",
+    "project.structure.last.edited": "Modules",
+    "project.structure.proportion": "0.15",
+    "project.structure.side.proportion": "0.2",
+    "settings.editor.selected.configurable": "preferences.pluginManager",
+    "vue.rearranger.settings.migration": "true"
   }
-}</component>
+}]]></component>
   <component name="RecentsManager">
     <key name="CopyFile.RECENT_KEYS">
+      <recent name="D:\Github\EntityLib\api\src\main\java\me\tofaa\entitylib\meta" />
       <recent name="D:\Github\EntityLib\test-plugin" />
     </key>
   </component>
-  <component name="RunManager" selected="Gradle.EntityLib:test-plugin [runServer]">
+  <component name="RunManager" selected="Gradle.EntityLib [dependencies]">
+    <configuration name="EntityLib [dependencies]" type="GradleRunConfiguration" factoryName="Gradle" temporary="true">
+      <ExternalSystemSettings>
+        <option name="executionName" />
+        <option name="externalProjectPath" value="$PROJECT_DIR$" />
+        <option name="externalSystemIdString" value="GRADLE" />
+        <option name="scriptParameters" />
+        <option name="taskDescriptions">
+          <list />
+        </option>
+        <option name="taskNames">
+          <list>
+            <option value="dependencies" />
+          </list>
+        </option>
+        <option name="vmOptions" />
+      </ExternalSystemSettings>
+      <ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
+      <ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
+      <DebugAllEnabled>false</DebugAllEnabled>
+      <RunAsTest>false</RunAsTest>
+      <method v="2" />
+    </configuration>
     <configuration name="EntityLib:test-plugin [runServer]" type="GradleRunConfiguration" factoryName="Gradle" temporary="true">
       <ExternalSystemSettings>
         <option name="executionName" />
@@ -183,6 +236,7 @@
     </configuration>
     <recent_temporary>
       <list>
+        <item itemvalue="Gradle.EntityLib [dependencies]" />
         <item itemvalue="Gradle.EntityLib:test-plugin [runServer]" />
         <item itemvalue="Gradle.PE-EntityMeta [compileTestJava]" />
         <item itemvalue="Gradle.EntityLib:test-plugin [shadowJar]" />
@@ -232,7 +286,8 @@
       <workItem from="1705984769972" duration="76000" />
       <workItem from="1706183895216" duration="664000" />
       <workItem from="1706187926445" duration="4339000" />
-      <workItem from="1706248178234" duration="1973000" />
+      <workItem from="1706248178234" duration="17096000" />
+      <workItem from="1706284605696" duration="11691000" />
     </task>
     <servers />
   </component>
diff --git a/api/src/main/java/me/tofaa/entitylib/APISettings.java b/api/src/main/java/me/tofaa/entitylib/APISettings.java
index 01b5d17..17823db 100644
--- a/api/src/main/java/me/tofaa/entitylib/APISettings.java
+++ b/api/src/main/java/me/tofaa/entitylib/APISettings.java
@@ -12,11 +12,13 @@ import java.net.URL;
 
 public final class APISettings {
 
+    private final PacketEventsAPI<?> packetEvents;
     private boolean debugMode = false;
     private boolean checkForUpdates = false;
     private boolean tickTickables = false;
-    private PacketEventsAPI<?> packetEvents;
     private boolean platformLogger = false;
+    private boolean useAsyncEvents = false;
+    private boolean defaultCommands = false;
 
     public APISettings(PacketEventsAPI<?> packetEvents) {
         this.packetEvents = packetEvents;
@@ -42,16 +44,6 @@ public final class APISettings {
         return this;
     }
 
-    public @NotNull APISettings usePlatformLogger(boolean platformLogger) {
-        this.platformLogger = platformLogger;
-        return this;
-    }
-
-    public @NotNull APISettings debugMode(boolean debugMode) {
-        this.debugMode = debugMode;
-        return this;
-    }
-
     public @NotNull APISettings checkForUpdates() {
         this.checkForUpdates = true;
         return this;
@@ -67,16 +59,20 @@ public final class APISettings {
         return this;
     }
 
-    public @NotNull APISettings checkForUpdates(boolean checkForUpdates) {
-        this.checkForUpdates = checkForUpdates;
+    public @NotNull APISettings registerDefaultCommands() {
+        this.defaultCommands = true;
         return this;
     }
 
-    public @NotNull APISettings tickTickables(boolean tickTickables) {
-        this.tickTickables = tickTickables;
+    public @NotNull APISettings useAsyncEvents() {
+        this.useAsyncEvents = true;
         return this;
     }
 
+    public boolean shouldRegisterDefaultCommands() {
+        return defaultCommands;
+    }
+
     public boolean isDebugMode() {
         return debugMode;
     }
@@ -97,4 +93,8 @@ public final class APISettings {
         return platformLogger;
     }
 
+    public boolean shouldUseAsyncEvents() {
+        return useAsyncEvents;
+    }
+
 }
diff --git a/api/src/main/java/me/tofaa/entitylib/EntityIdProvider.java b/api/src/main/java/me/tofaa/entitylib/EntityIdProvider.java
new file mode 100644
index 0000000..b2f3a83
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/EntityIdProvider.java
@@ -0,0 +1,23 @@
+package me.tofaa.entitylib;
+
+import com.github.retrooper.packetevents.protocol.entity.type.EntityType;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.UUID;
+import java.util.concurrent.atomic.AtomicInteger;
+
+public interface EntityIdProvider {
+
+    int provide(@NotNull UUID entityUUID, @NotNull EntityType entityType);
+
+    class DefaultEntityIdProvider implements EntityIdProvider {
+
+        private final AtomicInteger integer = new AtomicInteger();
+
+        @Override
+        public int provide(@NotNull UUID entityUUID, @NotNull EntityType entityType) {
+            return integer.incrementAndGet();
+        }
+    }
+
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/EntityLib.java b/api/src/main/java/me/tofaa/entitylib/EntityLib.java
index 453b99e..ff57c07 100644
--- a/api/src/main/java/me/tofaa/entitylib/EntityLib.java
+++ b/api/src/main/java/me/tofaa/entitylib/EntityLib.java
@@ -1,10 +1,12 @@
 package me.tofaa.entitylib;
 
+import java.io.IOException;
+import java.util.logging.Level;
+
 public final class EntityLib {
 
     private EntityLib() {}
 
-    private static String version = "1.2.0-SNAPSHOT";
     private static Platform platform;
     private static EntityLibAPI api;
 
@@ -12,6 +14,20 @@ public final class EntityLib {
         EntityLib.platform = platform;
         platform.setupApi(settings);
         api = platform.getAPI();
+        if (api.getSettings().shouldCheckForUpdate()) {
+            try {
+                if (api.getSettings().isDebugMode()) {
+                    platform.getLogger().log(Level.CONFIG, "Checking for updates...");
+                }
+                if (api.getSettings().requiresUpdate()) {
+                    platform.getLogger().log(Level.WARNING, "You are using an outdated version of EntityLib. Please take a look at the Github releases page.");
+                }
+
+            }
+            catch (IOException e) {
+                platform.getLogger().log(Level.WARNING, e, () -> "EntityLib failed to check for updates.");
+            }
+        }
     }
 
     public static EntityLibAPI<?, ?> getApi() {
@@ -23,6 +39,6 @@ public final class EntityLib {
     }
 
     public static String getVersion() {
-        return version;
+        return "1.2.0-SNAPSHOT";
     }
 }
diff --git a/api/src/main/java/me/tofaa/entitylib/EntityLibAPI.java b/api/src/main/java/me/tofaa/entitylib/EntityLibAPI.java
index 6355aba..7067141 100644
--- a/api/src/main/java/me/tofaa/entitylib/EntityLibAPI.java
+++ b/api/src/main/java/me/tofaa/entitylib/EntityLibAPI.java
@@ -5,6 +5,7 @@ import me.tofaa.entitylib.tick.TickContainer;
 import org.jetbrains.annotations.NotNull;
 
 import java.util.Collection;
+import java.util.UUID;
 
 /**
  * Represents the API for EntityLib.
@@ -14,21 +15,28 @@ import java.util.Collection;
  */
 public interface EntityLibAPI<W, T> {
 
+
+
+    /**
+     * @return The {@link PacketEventsAPI} that EntityLib uses.
+     */
     PacketEventsAPI<?> getPacketEvents();
 
     void onLoad();
 
     void onEnable();
 
-    @NotNull APISettings getSettings();
-
+    /**
+     * Creates a wrapped world for the platform specific world.
+     * @param world The platform specific world handle.
+     * @return A wrapped world.
+     */
+    @NotNull WorldWrapper<W> wrapWorld(W world);
 
     /**
-     * If a platform supports ticking
-     * this method should be responsible for setting up the {@link me.tofaa.entitylib.tick.TickContainer}'s.
+     * @return The {@link APISettings} for the API.
      */
-    void setupTickingContainers();
-
+    @NotNull APISettings getSettings();
 
     /**
      * @return An unmodifiable collection of TickContainers.
diff --git a/api/src/main/java/me/tofaa/entitylib/EntityUuidProvider.java b/api/src/main/java/me/tofaa/entitylib/EntityUuidProvider.java
new file mode 100644
index 0000000..4937514
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/EntityUuidProvider.java
@@ -0,0 +1,21 @@
+package me.tofaa.entitylib;
+
+import com.github.retrooper.packetevents.protocol.entity.type.EntityType;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.UUID;
+
+public interface EntityUuidProvider {
+
+    @NotNull UUID provide(EntityType entityType);
+
+
+    class DefaultEntityUuidProvider implements EntityUuidProvider {
+
+        @Override
+        public @NotNull UUID provide(EntityType entityType) {
+            return UUID.randomUUID();
+        }
+    }
+
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/Platform.java b/api/src/main/java/me/tofaa/entitylib/Platform.java
index caa366a..5b5436a 100644
--- a/api/src/main/java/me/tofaa/entitylib/Platform.java
+++ b/api/src/main/java/me/tofaa/entitylib/Platform.java
@@ -1,6 +1,7 @@
 package me.tofaa.entitylib;
 
 import me.tofaa.entitylib.event.EntityLibEvent;
+import me.tofaa.entitylib.event.EventBus;
 import org.jetbrains.annotations.NotNull;
 
 import java.util.function.Consumer;
@@ -12,6 +13,30 @@ import java.util.logging.Logger;
  */
 public interface Platform<P> {
 
+    /**
+     * Gets the entityId integer provider. This can be provided by a platform if needed.
+     * @return the entityId integer provider.
+     */
+    @NotNull EntityIdProvider getEntityIdProvider();
+
+    /**
+     * Gets the UUID provider for entities. This can be provided by a platform if needed.
+     * @return the UUID provider for entities.
+     */
+    @NotNull EntityUuidProvider getEntityUuidProvider();
+
+    /**
+     * Sets the entityId integer provider. This can be provided by a platform if needed.
+     * @param provider the entityId integer provider.
+     */
+    void setEntityIdProvider(@NotNull EntityIdProvider provider);
+
+    /**
+     * Sets the UUID provider for entities. This can be provided by a platform if needed.
+     * @param provider
+     */
+    void setEntityUuidProvider(@NotNull EntityUuidProvider provider);
+
 
     /**
      * @return the logger EntityLib uses internally.
@@ -19,18 +44,11 @@ public interface Platform<P> {
     @NotNull Logger getLogger();
 
     /**
-     * Sends an event to the platform. Platform implementations should handle the event accordingly.
-     * @param event the event to send.
+     * Gets the event bus for the platform.
+     * WARNING: If you have {@link APISettings#shouldUseAsyncEvents()} set to true, cast this to {@link EventBus.Async} when handling cancelled events.
+     * @return
      */
-    void sendEvent(EntityLibEvent event);
-
-    /**
-     * Registers a listener for the given event class, the handle will be called when the event is sent.
-     * @param eventClass the event class to listen for.
-     * @param handle the handle to call when the event is sent.
-     * @param <T> the event type.
-     */
-    <T extends EntityLibEvent> void registerListener(Class<T> eventClass, Consumer<T> handle);
+    @NotNull EventBus getEventBus();
 
     /**
      * Sets up the API for the platform. This method should be called automatically by the platform. Don't call it yourself.
diff --git a/api/src/main/java/me/tofaa/entitylib/WorldWrapper.java b/api/src/main/java/me/tofaa/entitylib/WorldWrapper.java
index 1cfdb45..76d809a 100644
--- a/api/src/main/java/me/tofaa/entitylib/WorldWrapper.java
+++ b/api/src/main/java/me/tofaa/entitylib/WorldWrapper.java
@@ -1,7 +1,15 @@
 package me.tofaa.entitylib;
 
+import com.github.retrooper.packetevents.protocol.entity.type.EntityType;
+import com.github.retrooper.packetevents.protocol.world.Dimension;
+import com.github.retrooper.packetevents.protocol.world.Location;
 import com.github.retrooper.packetevents.protocol.world.states.WrappedBlockState;
-import com.github.retrooper.packetevents.resources.ResourceLocation;
+import me.tofaa.entitylib.wrapper.WrapperEntity;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.Collection;
+import java.util.UUID;
 
 /**
  * Represents a platform specific world.
@@ -11,9 +19,42 @@ import com.github.retrooper.packetevents.resources.ResourceLocation;
  */
 public interface WorldWrapper<W> {
 
-    ResourceLocation getPacketEventsWorld();
+    @NotNull <T extends WrapperEntity> T spawnEntity(@NotNull Class<T> wrapperClass, @NotNull EntityType entityType, @NotNull Location location);
 
+    @NotNull WrapperEntity spawnEntity(@NotNull EntityType entityType, @NotNull Location location);
+
+    @NotNull <T extends WrapperEntity> T spawnEntity(@NotNull T entity, @NotNull Location location);
+
+    @NotNull <T extends WrapperEntity> T cloneEntity(@NotNull Object platformEntity, @NotNull Location location);
+
+    @NotNull Collection<WrapperEntity> getEntities();
+
+    @Nullable WrapperEntity getEntity(int id);
+
+    @Nullable WrapperEntity getEntity(@NotNull UUID uuid);
+
+
+    /**
+     * Gets the block at the specified coordinates. Depending on the platforms implementation, this method may be slow.
+     * @param x The x coordinate.
+     * @param y The y coordinate.
+     * @param z The z coordinate.
+     * @return The packetevents WrappedBlockState at the specified coordinates.
+     */
     WrappedBlockState getBlock(int x, int y, int z);
 
-    W getHandle();
+    /**
+     * @return the packetevents Dimension of the world.
+     */
+    @NotNull Dimension getDimension();
+
+    /**
+     * @return the world's UUID.
+     */
+    @NotNull UUID getUuid();
+
+    /**
+     * @return the platform specific World.
+     */
+    @NotNull W getHandle();
 }
diff --git a/api/src/main/java/me/tofaa/entitylib/event/EntityLibEvent.java b/api/src/main/java/me/tofaa/entitylib/event/EntityLibEvent.java
index 8f3e66c..0a22a30 100644
--- a/api/src/main/java/me/tofaa/entitylib/event/EntityLibEvent.java
+++ b/api/src/main/java/me/tofaa/entitylib/event/EntityLibEvent.java
@@ -5,9 +5,4 @@ public interface EntityLibEvent {
     boolean isCancelled();
 
     void setCancelled(boolean cancelled);
-
-    default boolean isAsync() {
-        return false;
-    }
-
 }
diff --git a/api/src/main/java/me/tofaa/entitylib/event/EventBus.java b/api/src/main/java/me/tofaa/entitylib/event/EventBus.java
new file mode 100644
index 0000000..d9ab18f
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/event/EventBus.java
@@ -0,0 +1,61 @@
+package me.tofaa.entitylib.event;
+
+import org.jetbrains.annotations.NotNull;
+
+import java.util.function.Consumer;
+
+/**
+ * A basic EventBus for scheduling and handling {@link EntityLibEvent}
+ */
+public interface EventBus {
+
+    static @NotNull EventBus newBus(boolean async) {
+        return async ? new EventBusAsync() : new EventBusSync();
+    }
+
+    /**
+     * Adds a listener to the EventBus.
+     * @param listener The listener object
+     * @param <T> The type of {@link EntityLibEvent}
+     */
+    <T extends EntityLibEvent> void addListener(@NotNull EventListener<T> listener);
+
+    /**
+     * Adds a listener to the EventBus.
+     * @param eventClass The events class
+     * @param consumer The consumer for the event.
+     * @param <T> The type of {@link EntityLibEvent}
+     */
+    <T extends EntityLibEvent> void addListener(@NotNull Class<T> eventClass, @NotNull Consumer<T> consumer);
+
+    /**
+     * Removes a listener from the EventBus.
+     * @param listener the listener object.
+     * @param <T> The type of {@link EntityLibEvent}
+     */
+    <T extends EntityLibEvent> void removeListener(@NotNull EventListener<T> listener);
+
+    /**
+     * Calls the event and processes all the attached {@link EventListener} for the event.
+     * If your bus is async, rather than using this, use {@link Async#call(EntityLibEvent, Consumer)} to avoid any race conditions.
+     * @param event the event object to process handlers for.
+     * @return the same event object, but already modified.
+     * @param <T> The type of {@link EntityLibEvent}
+     */
+    <T extends EntityLibEvent> @NotNull T call(@NotNull T event);
+
+
+    interface Async extends EventBus {
+
+        /**
+         * A safer way to handle and process an event. Does exactly what {@link EventBus#call(EntityLibEvent)} does but allows you to attach a callback, rather than working with it yourself,
+         * the callback is executed on the thread this is called, and not the main thread.
+         * @param event the event object to process handlers for.
+         * @param completionCallback the callback handled after the event is consumed async
+         * @param <T> The type of {@link EntityLibEvent}
+         */
+        <T extends EntityLibEvent> void call(@NotNull T event, @NotNull Consumer<T> completionCallback);
+
+    }
+
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/event/EventBusAsync.java b/api/src/main/java/me/tofaa/entitylib/event/EventBusAsync.java
new file mode 100644
index 0000000..60608d5
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/event/EventBusAsync.java
@@ -0,0 +1,60 @@
+package me.tofaa.entitylib.event;
+
+import org.jetbrains.annotations.NotNull;
+
+import java.util.HashSet;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+import java.util.function.Consumer;
+
+final class EventBusAsync implements EventBus.Async {
+
+    private final Map listeners = new ConcurrentHashMap();
+    private final ThreadPoolExecutor executor = new ThreadPoolExecutor(1, 4, 60, TimeUnit.SECONDS, new LinkedBlockingQueue<>());
+
+    @Override
+    public <T extends EntityLibEvent> void addListener(@NotNull EventListener<T> listener) {
+        if (listeners.containsKey(listener.getEventClass())) {
+            listeners.put(listener.getEventClass(), new HashSet<>());
+        }
+        ((HashSet) listeners.get(listener.getEventClass())).add(listener);
+    }
+
+    @Override
+    public <T extends EntityLibEvent> void addListener(@NotNull Class<T> eventClass, @NotNull Consumer<T> consumer) {
+        addListener(EventListener.generateListener(eventClass, consumer));
+
+    }
+
+    @Override
+    public <T extends EntityLibEvent> void removeListener(@NotNull EventListener<T> listener) {
+        if (listeners.containsKey(listener.getEventClass())) {
+            ((HashSet) listeners.get(listener.getEventClass())).remove(listener);
+        }
+    }
+
+    @Override
+    public <T extends EntityLibEvent> @NotNull T call(@NotNull T event) {
+        executor.execute(() -> dispatchEvent(event));
+        return event;
+    }
+
+
+    private <T extends EntityLibEvent> void dispatchEvent(T event) {
+        if (!listeners.containsKey(event.getClass())) return;
+        HashSet<EventListener<T>> consumers = (HashSet<EventListener<T>>) listeners.get(event.getClass());
+        consumers.forEach(consumer -> consumer.handle(event));
+    }
+
+
+    @Override
+    public <T extends EntityLibEvent> void call(@NotNull T event, @NotNull Consumer<T> completionCallback) {
+        executor.execute(() -> {
+            dispatchEvent(event);
+            completionCallback.accept(event);
+        });
+    }
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/event/EventBusSync.java b/api/src/main/java/me/tofaa/entitylib/event/EventBusSync.java
new file mode 100644
index 0000000..4ca6b53
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/event/EventBusSync.java
@@ -0,0 +1,43 @@
+package me.tofaa.entitylib.event;
+
+
+import org.jetbrains.annotations.NotNull;
+
+import java.util.HashSet;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.function.Consumer;
+
+@SuppressWarnings("unchecked")
+class EventBusSync implements EventBus {
+
+    private final Map listeners = new ConcurrentHashMap();
+
+    @Override
+    public <T extends EntityLibEvent> void addListener(@NotNull EventListener<T> listener) {
+        if (listeners.containsKey(listener.getEventClass())) {
+            listeners.put(listener.getEventClass(), new HashSet<>());
+        }
+        ((HashSet) listeners.get(listener.getEventClass())).add(listener);
+    }
+
+    @Override
+    public <T extends EntityLibEvent> void addListener(@NotNull Class<T> eventClass, @NotNull Consumer<T> consumer) {
+        addListener(EventListener.generateListener(eventClass, consumer));
+    }
+
+    @Override
+    public <T extends EntityLibEvent> void removeListener(@NotNull EventListener<T> listener) {
+        if (listeners.containsKey(listener.getEventClass())) {
+            ((HashSet) listeners.get(listener.getEventClass())).remove(listener);
+        }
+    }
+
+    @Override
+    public <T extends EntityLibEvent> @NotNull T call(@NotNull T event) {
+        if (!listeners.containsKey(event.getClass())) return event;
+        HashSet<EventListener<T>> consumers = (HashSet<EventListener<T>>) listeners.get(event.getClass());
+        consumers.forEach(consumer -> consumer.handle(event));
+        return event;
+    }
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/event/EventListener.java b/api/src/main/java/me/tofaa/entitylib/event/EventListener.java
new file mode 100644
index 0000000..8cf6c01
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/event/EventListener.java
@@ -0,0 +1,27 @@
+package me.tofaa.entitylib.event;
+
+import org.jetbrains.annotations.NotNull;
+
+import java.util.function.Consumer;
+
+public interface EventListener<E extends EntityLibEvent> {
+
+    @NotNull Class<E> getEventClass();
+
+    void handle(@NotNull E event);
+
+    public static <T extends EntityLibEvent> EventListener<T> generateListener(Class<T> eventClass, Consumer<T> consumer) {
+        return new EventListener<T>() {
+            @Override
+            public @NotNull Class<T> getEventClass() {
+                return eventClass;
+            }
+
+            @Override
+            public void handle(@NotNull T event) {
+                consumer.accept(event);
+            }
+        };
+    }
+
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/event/UserReceiveMetaUpdateEvent.java b/api/src/main/java/me/tofaa/entitylib/event/types/UserReceiveMetaUpdateEvent.java
similarity index 86%
rename from api/src/main/java/me/tofaa/entitylib/event/UserReceiveMetaUpdateEvent.java
rename to api/src/main/java/me/tofaa/entitylib/event/types/UserReceiveMetaUpdateEvent.java
index 40df9cd..5b5d64f 100644
--- a/api/src/main/java/me/tofaa/entitylib/event/UserReceiveMetaUpdateEvent.java
+++ b/api/src/main/java/me/tofaa/entitylib/event/types/UserReceiveMetaUpdateEvent.java
@@ -1,6 +1,7 @@
-package me.tofaa.entitylib.event;
+package me.tofaa.entitylib.event.types;
 
 import com.github.retrooper.packetevents.protocol.player.User;
+import me.tofaa.entitylib.event.EntityLibEvent;
 import me.tofaa.entitylib.meta.EntityMeta;
 
 public final class UserReceiveMetaUpdateEvent implements EntityLibEvent {
diff --git a/api/src/main/java/me/tofaa/entitylib/extras/CoordinateUtil.java b/api/src/main/java/me/tofaa/entitylib/extras/CoordinateUtil.java
new file mode 100644
index 0000000..25e5c39
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/extras/CoordinateUtil.java
@@ -0,0 +1,38 @@
+package me.tofaa.entitylib.extras;
+
+import com.github.retrooper.packetevents.protocol.world.Location;
+import com.github.retrooper.packetevents.util.Vector3d;
+
+public final class CoordinateUtil {
+
+    private CoordinateUtil() {}
+
+    public static Location withDirection(Location location, Vector3d direction) {
+        /*
+         * Sin = Opp / Hyp
+         * Cos = Adj / Hyp
+         * Tan = Opp / Adj
+         *
+         * x = -Opp
+         * z = Adj
+         */
+        final double x = direction.getX();
+        final double z = direction.getZ();
+        if (x == 0 && z == 0) {
+            float pitch = direction.getY() > 0 ? -90f : 90f;
+            return new Location(location.getX(), location.getY(), location.getZ(), location.getYaw(), pitch);
+        }
+        final double theta = Math.atan2(-x, z);
+        final double xz = Math.sqrt(square(x) + square(z));
+        final double _2PI = 2 * Math.PI;
+
+        return new Location(location.getX(), location.getY(), location.getZ(),
+                (float) Math.toDegrees((theta + _2PI) % _2PI),
+                (float) Math.toDegrees(Math.atan(-direction.getY() / xz)));
+    }
+
+    public static double square(double in) {
+        return in * in;
+    }
+
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/extras/VersionChecker.java b/api/src/main/java/me/tofaa/entitylib/extras/VersionChecker.java
new file mode 100644
index 0000000..c381d52
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/extras/VersionChecker.java
@@ -0,0 +1,17 @@
+package me.tofaa.entitylib.extras;
+
+import com.github.retrooper.packetevents.manager.server.ServerVersion;
+import me.tofaa.entitylib.EntityLib;
+
+public final class VersionChecker {
+
+    private VersionChecker() {}
+
+
+    public static void verifyVersion(ServerVersion version, String message) {
+        if (!version.isNewerThanOrEquals(EntityLib.getApi().getPacketEvents().getServerManager().getVersion())) {
+            throw new InvalidVersionException(message);
+        }
+    }
+
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/EntityMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/EntityMeta.java
index bab0c11..d00132f 100644
--- a/api/src/main/java/me/tofaa/entitylib/meta/EntityMeta.java
+++ b/api/src/main/java/me/tofaa/entitylib/meta/EntityMeta.java
@@ -6,16 +6,46 @@ import com.github.retrooper.packetevents.protocol.entity.data.EntityData;
 import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
 import com.github.retrooper.packetevents.protocol.entity.data.EntityMetadataProvider;
 import com.github.retrooper.packetevents.protocol.entity.pose.EntityPose;
+import com.github.retrooper.packetevents.protocol.entity.type.EntityType;
 import com.github.retrooper.packetevents.protocol.player.ClientVersion;
 import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerEntityMetadata;
 import me.tofaa.entitylib.EntityLib;
 import me.tofaa.entitylib.extras.InvalidVersionException;
 import net.kyori.adventure.text.Component;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
 
 import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.function.BiFunction;
+import java.util.function.Function;
 
 public class EntityMeta implements EntityMetadataProvider {
 
+    private static final MetaConverterRegistry registry = new MetaConverterRegistry();
+    private static final Map<Integer, EntityMeta> metaMap = new ConcurrentHashMap<>();
+
+    public static @NotNull BiFunction<Integer, Metadata, EntityMeta> getConverter(EntityType entityType) {
+        return registry.get(entityType);
+    }
+
+    public static @NotNull Class<? extends EntityMeta> getMetaClass(EntityType entityType) {
+        return registry.getMetaClass(entityType);
+    }
+
+    public static @NotNull EntityMeta createMeta(int entityId, EntityType entityType) {
+        Metadata metadata = new Metadata(entityId);
+        BiFunction<Integer, Metadata, EntityMeta> converter = getConverter(entityType);
+        EntityMeta entityMeta = converter.apply(entityId, metadata);
+        metaMap.put(entityId, entityMeta);
+        return entityMeta;
+    }
+
+    public static @Nullable EntityMeta getMeta(int entityId) {
+        return metaMap.get(entityId);
+    }
+
     public static final byte OFFSET = 0;
     public static final byte MAX_OFFSET = OFFSET + 8;
 
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/MetaConverterRegistry.java b/api/src/main/java/me/tofaa/entitylib/meta/MetaConverterRegistry.java
new file mode 100644
index 0000000..8aacac4
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/MetaConverterRegistry.java
@@ -0,0 +1,175 @@
+package me.tofaa.entitylib.meta;
+
+import com.github.retrooper.packetevents.protocol.entity.type.EntityType;
+import me.tofaa.entitylib.meta.EntityMeta;
+import me.tofaa.entitylib.meta.Metadata;
+import me.tofaa.entitylib.meta.display.BlockDisplayMeta;
+import me.tofaa.entitylib.meta.display.ItemDisplayMeta;
+import me.tofaa.entitylib.meta.display.TextDisplayMeta;
+import me.tofaa.entitylib.meta.mobs.*;
+import me.tofaa.entitylib.meta.mobs.DonkeyMeta;
+import me.tofaa.entitylib.meta.mobs.cuboid.MagmaCubeMeta;
+import me.tofaa.entitylib.meta.mobs.cuboid.SlimeMeta;
+import me.tofaa.entitylib.meta.mobs.golem.IronGolemMeta;
+import me.tofaa.entitylib.meta.mobs.golem.ShulkerMeta;
+import me.tofaa.entitylib.meta.mobs.golem.SnowGolemMeta;
+import me.tofaa.entitylib.meta.mobs.horse.*;
+import me.tofaa.entitylib.meta.mobs.monster.*;
+import me.tofaa.entitylib.meta.mobs.monster.piglin.PiglinBruteMeta;
+import me.tofaa.entitylib.meta.mobs.monster.piglin.PiglinMeta;
+import me.tofaa.entitylib.meta.mobs.monster.raider.*;
+import me.tofaa.entitylib.meta.mobs.monster.skeleton.SkeletonMeta;
+import me.tofaa.entitylib.meta.mobs.monster.skeleton.StrayMeta;
+import me.tofaa.entitylib.meta.mobs.monster.skeleton.WitherSkeletonMeta;
+import me.tofaa.entitylib.meta.mobs.monster.zombie.*;
+import me.tofaa.entitylib.meta.mobs.passive.*;
+import me.tofaa.entitylib.meta.mobs.water.*;
+import me.tofaa.entitylib.meta.mobs.minecart.*;
+import me.tofaa.entitylib.meta.mobs.tameable.CatMeta;
+import me.tofaa.entitylib.meta.mobs.tameable.ParrotMeta;
+import me.tofaa.entitylib.meta.mobs.tameable.WolfMeta;
+import me.tofaa.entitylib.meta.mobs.villager.VillagerMeta;
+import me.tofaa.entitylib.meta.mobs.villager.WanderingTraderMeta;
+import me.tofaa.entitylib.meta.other.*;
+import me.tofaa.entitylib.meta.projectile.*;
+import me.tofaa.entitylib.meta.types.PlayerMeta;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.function.BiFunction;
+
+import static com.github.retrooper.packetevents.protocol.entity.type.EntityTypes.*;
+
+@SuppressWarnings("unchecked")
+final class MetaConverterRegistry {
+
+    private final Map<EntityType, BiFunction<Integer, Metadata, EntityMeta>> converters = new HashMap<>();
+    private final Map<EntityType, Class<? extends EntityMeta>> metaClasses = new HashMap<>();
+
+    MetaConverterRegistry() {
+        put(SNIFFER, SnifferMeta.class, SnifferMeta::new);
+        put(INTERACTION, InteractionMeta.class, InteractionMeta::new);
+        put(BLOCK_DISPLAY, BlockDisplayMeta.class, BlockDisplayMeta::new);
+        put(ITEM_DISPLAY, ItemDisplayMeta.class, ItemDisplayMeta::new);
+        put(TEXT_DISPLAY, TextDisplayMeta.class, TextDisplayMeta::new);
+        put(AREA_EFFECT_CLOUD, AreaEffectCloudMeta.class, AreaEffectCloudMeta::new);
+        put(ARMOR_STAND, ArmorStandMeta.class, ArmorStandMeta::new);
+        put(BOAT, BoatMeta.class, BoatMeta::new);
+        put(DRAGON_FIREBALL, DragonFireballMeta.class, DragonFireballMeta::new);
+        put(END_CRYSTAL, EndCrystalMeta.class, EndCrystalMeta::new);
+        put(ENDER_DRAGON, EnderDragonMeta.class, EnderDragonMeta::new);
+        put(EVOKER_FANGS, EvokerFangsMeta.class, EvokerFangsMeta::new);
+        put(FALLING_BLOCK, FallingBlockMeta.class, FallingBlockMeta::new);
+        put(FIREWORK_ROCKET, FireworkRocketMeta.class, FireworkRocketMeta::new);
+        put(FISHING_BOBBER, FishingHookMeta.class, FishingHookMeta::new);
+        put(GLOW_ITEM_FRAME, GlowItemFrameMeta.class, GlowItemFrameMeta::new);
+        put(ITEM_FRAME, ItemFrameMeta.class, ItemFrameMeta::new);
+        put(LEASH_KNOT, LeashKnotMeta.class, LeashKnotMeta::new);
+        put(LIGHTNING_BOLT, LightningBoltMeta.class, LightningBoltMeta::new);
+        put(LLAMA_SPIT, LlamaSpitMeta.class, LlamaSpitMeta::new);
+        put(MARKER, MarkerMeta.class, MarkerMeta::new);
+        put(PAINTING, PaintingMeta.class, PaintingMeta::new);
+        put(PRIMED_TNT, PrimedTntMeta.class, PrimedTntMeta::new);
+        put(WITHER_SKULL, WitherSkullMeta.class, WitherSkullMeta::new);
+        put(ZOGLIN, ZoglinMeta.class, ZoglinMeta::new);
+        put(WITHER, WitherMeta.class, WitherMeta::new);
+        put(VEX, VexMeta.class, VexMeta::new);
+        put(SPIDER, SpiderMeta.class, SpiderMeta::new);
+        put(SILVERFISH, SilverfishMeta.class, SilverfishMeta::new);
+        put(GUARDIAN, GuardianMeta.class, GuardianMeta::new);
+        put(GIANT, GiantMeta.class, GiantMeta::new);
+        put(ENDERMITE, EndermiteMeta.class, EndermiteMeta::new);
+        put(ENDERMITE, EndermiteMeta.class, EndermiteMeta::new);
+        put(ELDER_GUARDIAN, ElderGuardianMeta.class, ElderGuardianMeta::new);
+        put(CREEPER, CreeperMeta.class, CreeperMeta::new);
+        put(CAVE_SPIDER, CaveSpiderMeta.class, CaveSpiderMeta::new);
+        put(BLAZE, BlazeMeta.class, BlazeMeta::new);
+        put(PIGLIN, PiglinMeta.class, PiglinMeta::new);
+        put(PIGLIN_BRUTE, PiglinBruteMeta.class, PiglinBruteMeta::new);
+        put(EVOKER, EvokerMeta.class, EvokerMeta::new);
+        put(ILLUSIONER, IllusionerMeta.class, IllusionerMeta::new);
+        put(PILLAGER, PillagerMeta.class, PillagerMeta::new);
+        put(RAVAGER, RavagerMeta.class, RavagerMeta::new);
+        put(VINDICATOR, VindicatorMeta.class, VindicatorMeta::new);
+        put(WITCH, WitchMeta.class, WitchMeta::new);
+        put(SKELETON, SkeletonMeta.class, SkeletonMeta::new);
+        put(STRAY, StrayMeta.class, StrayMeta::new);
+        put(WITHER_SKELETON, WitherSkeletonMeta.class, WitherSkeletonMeta::new);
+        put(DROWNED, DrownedMeta.class, DrownedMeta::new);
+        put(HUSK, HuskMeta.class, HuskMeta::new);
+        put(ZOMBIE, ZombieMeta.class, ZombieMeta::new);
+        put(ZOMBIE_VILLAGER, ZombieVillagerMeta.class, ZombieVillagerMeta::new);
+        put(ZOMBIFIED_PIGLIN, ZombifiedPiglinMeta.class, ZombifiedPiglinMeta::new);
+        put(AXOLOTL, AxolotlMeta.class, AxolotlMeta::new);
+        put(COD, CodMeta.class, CodMeta::new);
+        put(DOLPHIN, DolphinMeta.class, DolphinMeta::new);
+        put(GLOW_SQUID, GlowSquidMeta.class, GlowSquidMeta::new);
+        put(PUFFERFISH, PufferFishMeta.class, PufferFishMeta::new);
+        put(SALMON, SalmonMeta.class, SalmonMeta::new);
+        put(TROPICAL_FISH, TropicalFishMeta.class, TropicalFishMeta::new);
+        put(ARROW, ArrowMeta.class, ArrowMeta::new);
+        put(VILLAGER, VillagerMeta.class, VillagerMeta::new);
+        put(WANDERING_TRADER, WanderingTraderMeta.class, WanderingTraderMeta::new);
+        put(CHEST_MINECART, ChestMinecartMeta.class, ChestMinecartMeta::new);
+        put(COMMAND_BLOCK_MINECART, CommandBlockMinecartMeta.class, CommandBlockMinecartMeta::new);
+        put(COMMAND_BLOCK_MINECART, CommandBlockMinecartMeta.class, CommandBlockMinecartMeta::new);
+        put(FURNACE_MINECART, FurnaceMinecartMeta.class, FurnaceMinecartMeta::new);
+        put(HOPPER_MINECART, FurnaceMinecartMeta.class, FurnaceMinecartMeta::new);
+        put(SPAWNER_MINECART, SpawnerMinecartMeta.class, SpawnerMinecartMeta::new);
+        put(TNT_MINECART, TntMinecartMeta.class, TntMinecartMeta::new);
+        put(PLAYER, PlayerMeta.class, PlayerMeta::new);
+        put(THROWN_EXP_BOTTLE, ThrownExpBottleMeta.class, ThrownExpBottleMeta::new);
+        put(EGG, ThrownEggMeta.class, ThrownEggMeta::new);
+        put(TRIDENT, ThrownTridentMeta.class, ThrownTridentMeta::new);
+        put(POTION, ThrownTridentMeta.class, ThrownTridentMeta::new);
+        put(SMALL_FIREBALL, SmallFireballMeta.class, SmallFireballMeta::new);
+        put(PIG, PigMeta.class, PigMeta::new);
+        put(COW, CowMeta.class, CowMeta::new);
+        put(CHICKEN, ChickenMeta.class, ChickenMeta::new);
+        put(BEE, BeeMeta.class, BeeMeta::new);
+        put(TURTLE, TurtleMeta.class, TurtleMeta::new);
+        put(DONKEY, DonkeyMeta.class, DonkeyMeta::new);
+        put(SHEEP, SheepMeta.class, SheepMeta::new);
+        put(RABBIT, RabbitMeta.class, RabbitMeta::new);
+        put(POLAR_BEAR, PolarBearMeta.class, PolarBearMeta::new);
+        put(OCELOT, OcelotMeta.class, OcelotMeta::new );
+        put(PANDA, PandaMeta.class, PandaMeta::new);
+        put(STRIDER, StriderMeta.class, StriderMeta::new);
+        put(FOX, FoxMeta.class, FoxMeta::new);
+        put(FROG, FrogMeta.class, FrogMeta::new);
+        put(GOAT, GoatMeta.class, GoatMeta::new);
+        put(HOGLIN, HoglinMeta.class, HoglinMeta::new);
+        put(CAT, CatMeta.class, CatMeta::new);
+        put(PARROT, ParrotMeta.class, ParrotMeta::new);
+        put(WOLF, WolfMeta.class, WolfMeta::new);
+        put(DONKEY, DonkeyMeta.class, DonkeyMeta::new);
+        put(HORSE, HorseMeta.class, HorseMeta::new);
+        put(LLAMA, LlamaMeta.class, LlamaMeta::new);
+        put(MULE, MuleMeta.class, MuleMeta::new);
+        put(SKELETON_HORSE, SkeletonHorseMeta.class, SkeletonHorseMeta::new);
+        put(ZOMBIE_HORSE, ZombieHorseMeta.class, ZombieHorseMeta::new);
+        put(SLIME, SlimeMeta.class, SlimeMeta::new);
+        put(MAGMA_CUBE, MagmaCubeMeta.class, MagmaCubeMeta::new);
+        put(SHULKER_BULLET, ShulkerBulletMeta.class, ShulkerBulletMeta::new);
+        put(TRADER_LLAMA, TraderLlamaMeta.class, TraderLlamaMeta::new);
+        put(BAT, BatMeta.class, BatMeta::new);
+        put(IRON_GOLEM, IronGolemMeta.class, IronGolemMeta::new);
+        put(SHULKER, ShulkerMeta.class, ShulkerMeta::new);
+        put(SNOW_GOLEM, SnowGolemMeta.class, SnowGolemMeta::new);
+    }
+
+    private void put(EntityType entityType, Class<? extends EntityMeta> metaClass, BiFunction<Integer, Metadata, EntityMeta> function) {
+        converters.put(entityType, function);
+        metaClasses.put(entityType, metaClass);
+    }
+
+    public Class<? extends EntityMeta> getMetaClass(EntityType entityType) {
+        return metaClasses.getOrDefault(entityType, EntityMeta.class);
+    }
+
+    public @NotNull BiFunction<Integer, Metadata, EntityMeta> get(EntityType entityType) {
+        return converters.getOrDefault(entityType, EntityMeta::new);
+    }
+
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/UsedVersion.java b/api/src/main/java/me/tofaa/entitylib/meta/UsedVersion.java
new file mode 100644
index 0000000..d0bbd32
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/UsedVersion.java
@@ -0,0 +1,9 @@
+package me.tofaa.entitylib.meta;
+
+import com.github.retrooper.packetevents.manager.server.ServerVersion;
+
+public @interface UsedVersion {
+
+    ServerVersion[] value();
+
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/VersionCompatCheck.java b/api/src/main/java/me/tofaa/entitylib/meta/VersionCompatCheck.java
new file mode 100644
index 0000000..9bc5281
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/VersionCompatCheck.java
@@ -0,0 +1,15 @@
+package me.tofaa.entitylib.meta;
+
+import com.github.retrooper.packetevents.manager.server.ServerVersion;
+import com.github.retrooper.packetevents.manager.server.VersionComparison;
+import me.tofaa.entitylib.EntityLib;
+
+public final class VersionCompatCheck  {
+
+    private VersionCompatCheck() {}
+
+    static boolean isVersion(ServerVersion version) {
+        return version.is(VersionComparison.EQUALS, EntityLib.getApi().getPacketEvents().getServerManager().getVersion());
+    }
+
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/display/AbstractDisplayMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/display/AbstractDisplayMeta.java
new file mode 100644
index 0000000..7d9ba52
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/display/AbstractDisplayMeta.java
@@ -0,0 +1,255 @@
+package me.tofaa.entitylib.meta.display;
+
+import com.github.retrooper.packetevents.manager.server.ServerVersion;
+import com.github.retrooper.packetevents.manager.server.VersionComparison;
+import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
+import com.github.retrooper.packetevents.util.Quaternion4f;
+import com.github.retrooper.packetevents.util.Vector3f;
+import me.tofaa.entitylib.meta.EntityMeta;
+import me.tofaa.entitylib.meta.Metadata;
+
+public abstract class AbstractDisplayMeta extends EntityMeta {
+
+    public static final byte OFFSET = EntityMeta.MAX_OFFSET;
+    public static final byte MAX_OFFSET;
+    static {
+        if (isVersion(ServerVersion.V_1_20_2, VersionComparison.NEWER_THAN_OR_EQUALS)) {
+            MAX_OFFSET =  OFFSET + 15;
+        }
+        else {
+            MAX_OFFSET = OFFSET + 14;
+        }
+    }
+
+    public AbstractDisplayMeta(int entityId, Metadata metadata) {
+        super(entityId, metadata);
+        isVersionNewer(ServerVersion.V_1_19_3);
+    }
+
+    public int getInterpolationDelay() {
+        return super.metadata.getIndex(OFFSET, 0);
+    }
+
+    public void setInterpolationDelay(int value) {
+        super.metadata.setIndex(OFFSET, EntityDataTypes.INT, value);
+    }
+
+    public int getTransformationInterpolationDuration() {
+        return super.metadata.getIndex(offset(OFFSET, 1), 0);
+    }
+
+    public void setTransformationInterpolationDuration(int value) {
+        super.metadata.setIndex(offset(OFFSET, 1), EntityDataTypes.INT, value);
+    }
+
+    public int getPositionRotationInterpolationDuration() {
+        return super.metadata.getIndex(offset(OFFSET, 2), 0);
+    }
+
+    public void setPositionRotationInterpolationDuration(int value) {
+        super.metadata.setIndex(offset(OFFSET, 2), EntityDataTypes.INT, value);
+    }
+
+    public Vector3f getTranslation() {
+        byte offset = offset(OFFSET, 3);
+        if (isVersion(ServerVersion.V_1_20_2, VersionComparison.OLDER_THAN)) {
+            offset = offset(OFFSET, 2);
+        }
+        return super.metadata.getIndex(offset, Vector3f.zero());
+    }
+
+    public void setTranslation(Vector3f value) {
+        byte offset = offset(OFFSET, 3);
+        if (isVersion(ServerVersion.V_1_20_2, VersionComparison.OLDER_THAN)) {
+            offset = offset(OFFSET, 2);
+        }
+        super.metadata.setIndex(offset, EntityDataTypes.VECTOR3F, value);
+    }
+
+    public Vector3f getScale() {
+        byte offset = offset(OFFSET, 4);
+        if (isVersion(ServerVersion.V_1_20_2, VersionComparison.OLDER_THAN)) {
+            offset = offset(OFFSET, 3);
+        }
+        return super.metadata.getIndex(offset, new Vector3f(1.0f, 1.0f, 1.0f));
+    }
+
+    public void setScale(Vector3f value) {
+        byte offset = offset(OFFSET, 4);
+        if (isVersion(ServerVersion.V_1_20_2, VersionComparison.OLDER_THAN)) {
+            offset = offset(OFFSET, 3);
+        }
+        super.metadata.setIndex(offset, EntityDataTypes.VECTOR3F, value);
+    }
+
+    public Quaternion4f getLeftRotation() {
+        byte offset = offset(OFFSET, 5);
+        if (isVersion(ServerVersion.V_1_20_2, VersionComparison.OLDER_THAN)) {
+            offset = offset(OFFSET, 4);
+        }
+        return super.metadata.getIndex(offset, new Quaternion4f(0.0f, 0.0f, 0.0f, 1.0f));
+    }
+
+    public void setLeftRotation(Quaternion4f value) {
+        byte offset = offset(OFFSET, 5);
+        if (isVersion(ServerVersion.V_1_20_2, VersionComparison.OLDER_THAN)) {
+            offset = offset(OFFSET, 4);
+        }
+        super.metadata.setIndex(offset, EntityDataTypes.QUATERNION, value);
+    }
+
+    public Quaternion4f getRightRotation() {
+        byte offset = offset(OFFSET, 6);
+        if (isVersion(ServerVersion.V_1_20_2, VersionComparison.OLDER_THAN)) {
+            offset = offset(OFFSET, 5);
+        }
+        return super.metadata.getIndex(offset, new Quaternion4f(0.0f, 0.0f, 0.0f, 1.0f));
+    }
+
+    public void setRightRotation(Quaternion4f value) {
+        byte offset = offset(OFFSET, 6);
+        if (isVersion(ServerVersion.V_1_20_2, VersionComparison.OLDER_THAN)) {
+            offset = offset(OFFSET, 5);
+        }
+        super.metadata.setIndex(offset, EntityDataTypes.QUATERNION, value);
+    }
+
+    public BillboardConstraints getBillboardConstraints() {
+        byte offset = offset(OFFSET, 7);
+        if (isVersion(ServerVersion.V_1_20_2, VersionComparison.OLDER_THAN)) {
+            offset = offset(OFFSET, 6);
+        }
+        return BillboardConstraints.VALUES[super.metadata.getIndex(offset, (byte) 0)];
+    }
+
+    public void setBillboardConstraints(BillboardConstraints value) {
+        byte offset = offset(OFFSET, 7);
+        if (isVersion(ServerVersion.V_1_20_2, VersionComparison.OLDER_THAN)) {
+            offset = offset(OFFSET, 6);
+        }
+        super.metadata.setIndex(offset, EntityDataTypes.BYTE, (byte) value.ordinal());
+    }
+
+    //(blockLight << 4 | skyLight << 20)
+    public int getBrightnessOverride() {
+        byte offset = offset(OFFSET, 8);
+        if (isVersion(ServerVersion.V_1_20_2, VersionComparison.OLDER_THAN)) {
+            offset = offset(OFFSET, 7);
+        }
+        return super.metadata.getIndex(offset, -1);
+    }
+
+    public void setBrightnessOverride(int value) {
+        byte offset = offset(OFFSET, 8);
+        if (isVersion(ServerVersion.V_1_20_2, VersionComparison.OLDER_THAN)) {
+            offset = offset(OFFSET, 7);
+        }
+        super.metadata.setIndex(offset, EntityDataTypes.INT, value);
+    }
+
+    public float getViewRange() {
+        byte offset = offset(OFFSET, 9);
+        if (isVersion(ServerVersion.V_1_20_2, VersionComparison.OLDER_THAN)) {
+            offset = offset(OFFSET, 8);
+        }
+        return super.metadata.getIndex(offset, 1.0f);
+    }
+
+    public void setViewRange(float value) {
+        byte offset = offset(OFFSET, 9);
+        if (isVersion(ServerVersion.V_1_20_2, VersionComparison.OLDER_THAN)) {
+            offset = offset(OFFSET, 8);
+        }
+        super.metadata.setIndex(offset, EntityDataTypes.FLOAT, value);
+    }
+
+    public float getShadowRadius() {
+        byte offset = offset(OFFSET, 10);
+        if (isVersion(ServerVersion.V_1_20_2, VersionComparison.OLDER_THAN)) {
+            offset = offset(OFFSET, 9);
+        }
+        return super.metadata.getIndex(offset, 0.0f);
+    }
+
+    public void setShadowRadius(float value) {
+        byte offset = offset(OFFSET, 10);
+        if (isVersion(ServerVersion.V_1_20_2, VersionComparison.OLDER_THAN)) {
+            offset = offset(OFFSET, 9);
+        }
+        super.metadata.setIndex(offset, EntityDataTypes.FLOAT, value);
+    }
+
+    public float getShadowStrength() {
+        byte offset = offset(OFFSET, 11);
+        if (isVersion(ServerVersion.V_1_20_2, VersionComparison.OLDER_THAN)) {
+            offset = offset(OFFSET, 10);
+        }
+        return super.metadata.getIndex(offset, 1.0f);
+    }
+
+    public void setShadowStrength(float value) {
+        byte offset = offset(OFFSET, 11);
+        if (isVersion(ServerVersion.V_1_20_2, VersionComparison.OLDER_THAN)) {
+            offset = offset(OFFSET, 10);
+        }
+        super.metadata.setIndex(offset, EntityDataTypes.FLOAT, value);
+    }
+
+    public float getWidth() {
+        byte offset = offset(OFFSET, 12);
+        if (isVersion(ServerVersion.V_1_20_2, VersionComparison.OLDER_THAN)) {
+            offset = offset(OFFSET, 11);
+        }
+        return super.metadata.getIndex(offset, 0.0f);
+    }
+
+    public void setWidth(float value) {
+        byte offset = offset(OFFSET, 12);
+        if (isVersion(ServerVersion.V_1_20_2, VersionComparison.OLDER_THAN)) {
+            offset = offset(OFFSET, 11);
+        }
+        super.metadata.setIndex(offset, EntityDataTypes.FLOAT, value);
+    }
+
+    public float getHeight() {
+        byte offset = offset(OFFSET, 13);
+        if (isVersion(ServerVersion.V_1_20_2, VersionComparison.OLDER_THAN)) {
+            offset = offset(OFFSET, 12);
+        }
+        return super.metadata.getIndex(offset, 0.0f);
+    }
+
+    public void setHeight(float value) {
+        byte offset = offset(OFFSET, 13);
+        if (isVersion(ServerVersion.V_1_20_2, VersionComparison.OLDER_THAN)) {
+            offset = offset(OFFSET, 12);
+        }
+        super.metadata.setIndex(offset, EntityDataTypes.FLOAT, value);
+    }
+
+    public int getGlowColorOverride() {
+        byte offset = offset(OFFSET, 14);
+        if (isVersion(ServerVersion.V_1_20_2, VersionComparison.OLDER_THAN)) {
+            offset = offset(OFFSET, 13);
+        }
+        return super.metadata.getIndex(offset, -1);
+    }
+
+    public void setGlowColorOverride(int value) {
+        byte offset = offset(OFFSET, 14);
+        if (isVersion(ServerVersion.V_1_20_2, VersionComparison.OLDER_THAN)) {
+            offset = offset(OFFSET, 13);
+        }
+        super.metadata.setIndex(offset, EntityDataTypes.INT, value);
+    }
+
+    public enum BillboardConstraints {
+        FIXED,
+        VERTICAL,
+        HORIZONTAL,
+        CENTER;
+
+        private static final BillboardConstraints[] VALUES = values();
+    }
+
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/display/BlockDisplayMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/display/BlockDisplayMeta.java
new file mode 100644
index 0000000..45a077a
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/display/BlockDisplayMeta.java
@@ -0,0 +1,23 @@
+package me.tofaa.entitylib.meta.display;
+
+import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
+import me.tofaa.entitylib.meta.Metadata;
+
+public class BlockDisplayMeta extends AbstractDisplayMeta {
+
+    public static final byte OFFSET = AbstractDisplayMeta.MAX_OFFSET;
+    public static final byte MAX_OFFSET = offset(OFFSET, 1);
+
+    public BlockDisplayMeta(int entityId, Metadata metadata) {
+        super(entityId, metadata);
+    }
+
+    public int getBlockId() {
+        return super.metadata.getIndex(OFFSET, 0);
+    }
+
+    public void setBlockId(int blockId) {
+        super.metadata.setIndex(OFFSET, EntityDataTypes.INT, blockId);
+    }
+
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/display/ItemDisplayMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/display/ItemDisplayMeta.java
new file mode 100644
index 0000000..7668dfc
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/display/ItemDisplayMeta.java
@@ -0,0 +1,47 @@
+package me.tofaa.entitylib.meta.display;
+
+import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
+import com.github.retrooper.packetevents.protocol.item.ItemStack;
+import me.tofaa.entitylib.meta.Metadata;
+
+public class ItemDisplayMeta extends AbstractDisplayMeta {
+
+    public static final byte OFFSET = AbstractDisplayMeta.MAX_OFFSET;
+    public static final byte MAX_OFFSET = offset(OFFSET, 1);
+
+    public ItemDisplayMeta(int entityId, Metadata metadata) {
+        super(entityId, metadata);
+    }
+
+    public ItemStack getItem() {
+        return super.metadata.getIndex(OFFSET, ItemStack.EMPTY);
+    }
+
+    public void setItem(ItemStack itemStack) {
+        super.metadata.setIndex(OFFSET, EntityDataTypes.ITEMSTACK, itemStack);
+    }
+
+    public DisplayType getDisplayType() {
+        return DisplayType.VALUES[super.metadata.getIndex(offset(OFFSET, 1), 0)];
+    }
+
+    public void setDisplayType(DisplayType displayType) {
+        super.metadata.setIndex(offset(OFFSET, 1), EntityDataTypes.BYTE, (byte) displayType.ordinal());
+    }
+
+    public enum DisplayType {
+        NONE,
+        THIRD_PERSON_LEFT_HAND,
+        THIRD_PERSON_RIGHT_HAND,
+        FIRST_PERSON_LEFT_HAND,
+        FIRST_PERSON_RIGHT_HAND,
+        HEAD,
+        GUI,
+        GROUND,
+        FIXED;
+
+        private static final DisplayType[] VALUES = values();
+    }
+
+}
+
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/display/TextDisplayMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/display/TextDisplayMeta.java
new file mode 100644
index 0000000..85ef64e
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/display/TextDisplayMeta.java
@@ -0,0 +1,94 @@
+package me.tofaa.entitylib.meta.display;
+
+import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
+import me.tofaa.entitylib.meta.Metadata;
+import net.kyori.adventure.text.Component;
+
+public class TextDisplayMeta extends AbstractDisplayMeta {
+
+    public static final byte OFFSET = AbstractDisplayMeta.MAX_OFFSET;
+    public static final byte MAX_OFFSET = offset(OFFSET, 5);
+
+    private static final byte SHADOW = 1;
+    private static final byte SEE_THROUGH = 2;
+    private static final byte USE_DEFAULT_BACKGROUND = 4;
+    private static final byte ALIGN_LEFT = 8;
+    private static final byte ALIGN_RIGHT = 16;
+
+    public TextDisplayMeta(int entityId, Metadata metadata) {
+        super(entityId, metadata);
+    }
+
+
+    public Component getText() {
+        return metadata.getIndex(OFFSET, Component.empty());
+    }
+
+    public void setText(Component component) {
+        metadata.setIndex(OFFSET, EntityDataTypes.ADV_COMPONENT, component);
+    }
+
+    public int getLineWidth() {
+        return metadata.getIndex(offset(OFFSET, 1), 200);
+    }
+
+    public void setLineWidth(int value) {
+        metadata.setIndex(offset(OFFSET, 1), EntityDataTypes.INT, value);
+    }
+
+    public int getBackgroundColor() {
+        return metadata.getIndex(offset(OFFSET, 2), 0);
+    }
+
+    public void setBackgroundColor(int value) {
+        metadata.setIndex(offset(OFFSET, 2), EntityDataTypes.INT, value);
+    }
+
+    public byte getTextOpacity() {
+        return metadata.getIndex(offset(OFFSET, 3), (byte) -1);
+    }
+
+    public void setTextOpacity(byte value) {
+        metadata.setIndex(offset(OFFSET, 3), EntityDataTypes.BYTE, value);
+    }
+
+    public boolean isShadow() {
+        return getMaskBit(offset(OFFSET, 4), SHADOW);
+    }
+
+    public void setShadow(boolean value) {
+        setMaskBit(offset(OFFSET, 4), SHADOW, value);
+    }
+
+    public boolean isSeeThrough() {
+        return getMaskBit(offset(OFFSET, 4), SEE_THROUGH);
+    }
+
+    public void setSeeThrough(boolean value) {
+        setMaskBit(offset(OFFSET, 4), SEE_THROUGH, value);
+    }
+
+    public boolean isUseDefaultBackground() {
+        return getMaskBit(offset(OFFSET, 4), USE_DEFAULT_BACKGROUND);
+    }
+
+    public void setUseDefaultBackground(boolean value) {
+        setMaskBit(offset(OFFSET, 4), USE_DEFAULT_BACKGROUND, value);
+    }
+
+    public boolean isAlignLeft() {
+        return getMaskBit(offset(OFFSET, 4), ALIGN_LEFT);
+    }
+
+    public void setAlignLeft(boolean value) {
+        setMaskBit(OFFSET + 4, ALIGN_LEFT, value);
+    }
+
+    public boolean isAlignRight() {
+        return getMaskBit(offset(OFFSET, 4), ALIGN_RIGHT);
+    }
+
+    public void setAlignRight(boolean value) {
+        setMaskBit(offset(OFFSET, 4), ALIGN_RIGHT, value);
+    }
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/mobs/BatMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/mobs/BatMeta.java
new file mode 100644
index 0000000..e98f8e3
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/mobs/BatMeta.java
@@ -0,0 +1,26 @@
+package me.tofaa.entitylib.meta.mobs;
+
+import me.tofaa.entitylib.meta.Metadata;
+import me.tofaa.entitylib.meta.types.MobMeta;
+
+public class BatMeta extends MobMeta {
+
+    public static final byte OFFSET = MobMeta.MAX_OFFSET;
+    public static final byte MAX_OFFSET = OFFSET + 0;
+
+    private final static byte IS_HANGING_BIT = 0x01;
+
+    public BatMeta(int entityId, Metadata metadata) {
+        super(entityId, metadata);
+    }
+
+    public boolean isHanging() {
+        return getMaskBit(OFFSET, IS_HANGING_BIT);
+    }
+
+    public void setHanging(boolean value) {
+        setMaskBit(OFFSET, IS_HANGING_BIT, value);
+    }
+
+
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/mobs/BeeMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/mobs/BeeMeta.java
new file mode 100644
index 0000000..80258fa
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/mobs/BeeMeta.java
@@ -0,0 +1,52 @@
+package me.tofaa.entitylib.meta.mobs;
+
+import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
+import me.tofaa.entitylib.meta.Metadata;
+import me.tofaa.entitylib.meta.types.AgeableMeta;
+
+public class BeeMeta extends AgeableMeta {
+
+    public static final byte OFFSET = AgeableMeta.MAX_OFFSET;
+    public static final byte MAX_OFFSET = OFFSET + 2;
+
+    private final static byte ANGRY_BIT = 0x02;
+    private final static byte HAS_STUNG_BIT = 0x04;
+    private final static byte HAS_NECTAR_BIT = 0x08;
+
+    public BeeMeta(int entityId, Metadata metadata) {
+        super(entityId, metadata);
+    }
+
+    public boolean isAngry() {
+        return getMaskBit(OFFSET, ANGRY_BIT);
+    }
+
+    public void setAngry(boolean value) {
+        setMaskBit(OFFSET, ANGRY_BIT, value);
+    }
+
+    public boolean hasStung() {
+        return getMaskBit(OFFSET, HAS_STUNG_BIT);
+    }
+
+    public void setHasStung(boolean value) {
+        setMaskBit(OFFSET, HAS_STUNG_BIT, value);
+    }
+
+    public boolean hasNectar() {
+        return getMaskBit(OFFSET, HAS_NECTAR_BIT);
+    }
+
+    public void setHasNectar(boolean value) {
+        setMaskBit(OFFSET, HAS_NECTAR_BIT, value);
+    }
+
+    public int getAngerTicks() {
+        return super.metadata.getIndex(offset(OFFSET,1), 0);
+    }
+
+    public void setAngerTicks(int value) {
+        super.metadata.setIndex(offset(OFFSET,1), EntityDataTypes.INT, value);
+    }
+
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/mobs/DonkeyMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/mobs/DonkeyMeta.java
new file mode 100644
index 0000000..a494061
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/mobs/DonkeyMeta.java
@@ -0,0 +1,14 @@
+package me.tofaa.entitylib.meta.mobs;
+
+import me.tofaa.entitylib.meta.Metadata;
+import me.tofaa.entitylib.meta.types.AgeableMeta;
+
+public class DonkeyMeta extends AgeableMeta {
+
+    public static final byte OFFSET = AgeableMeta.MAX_OFFSET;
+    public static final byte MAX_OFFSET = OFFSET + 0;
+
+    public DonkeyMeta(int entityId, Metadata metadata) {
+        super(entityId, metadata);
+    }
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/mobs/FoxMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/mobs/FoxMeta.java
new file mode 100644
index 0000000..c0f7a3f
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/mobs/FoxMeta.java
@@ -0,0 +1,119 @@
+package me.tofaa.entitylib.meta.mobs;
+
+import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
+import me.tofaa.entitylib.meta.Metadata;
+import me.tofaa.entitylib.meta.types.AgeableMeta;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.Optional;
+import java.util.UUID;
+
+public class FoxMeta extends AgeableMeta {
+
+    public static final byte OFFSET = AgeableMeta.MAX_OFFSET;
+    public static final byte MAX_OFFSET = OFFSET+ 4;
+
+    private final static byte SITTING_BIT = 0x01;
+    private final static byte CROUCHING_BIT = 0x04;
+    private final static byte INTERESTED_BIT = 0x08;
+    private final static byte POUNCING_BIT = 0x10;
+    private final static byte SLEEPING_BIT = 0x20;
+    private final static byte FACEPLANTED_BIT = 0x40;
+    private final static byte DEFENDING_BIT = (byte) 0x80;
+
+
+    public FoxMeta(int entityId, Metadata metadata) {
+        super(entityId, metadata);
+    }
+
+    @NotNull
+    public Type getType() {
+        return Type.VALUES[super.metadata.getIndex(OFFSET, 0)];
+    }
+
+    public void setType(@NotNull Type type) {
+        super.metadata.setIndex(OFFSET, EntityDataTypes.INT, type.ordinal());
+    }
+
+    public boolean isSitting() {
+        return getMaskBit(offset(OFFSET, 1), SITTING_BIT);
+    }
+
+    public void setSitting(boolean value) {
+        setMaskBit(offset(OFFSET, 1), SITTING_BIT, value);
+    }
+
+    public boolean isFoxSneaking() {
+        return getMaskBit(offset(OFFSET, 1), CROUCHING_BIT);
+    }
+
+    public void setFoxSneaking(boolean value) {
+        setMaskBit(offset(OFFSET, 1), CROUCHING_BIT, value);
+    }
+
+    public boolean isInterested() {
+        return getMaskBit(offset(OFFSET, 1), INTERESTED_BIT);
+    }
+
+    public void setInterested(boolean value) {
+        setMaskBit(offset(OFFSET, 1), INTERESTED_BIT, value);
+    }
+
+    public boolean isPouncing() {
+        return getMaskBit(offset(OFFSET, 1), POUNCING_BIT);
+    }
+
+    public void setPouncing(boolean value) {
+        setMaskBit(offset(OFFSET, 1), POUNCING_BIT, value);
+    }
+
+    public boolean isSleeping() {
+        return getMaskBit(offset(OFFSET, 1), SLEEPING_BIT);
+    }
+
+    public void setSleeping(boolean value) {
+        setMaskBit(offset(OFFSET, 1), SLEEPING_BIT, value);
+    }
+
+    public boolean isFaceplanted() {
+        return getMaskBit(offset(OFFSET, 1), FACEPLANTED_BIT);
+    }
+
+    public void setFaceplanted(boolean value) {
+        setMaskBit(offset(OFFSET, 1), FACEPLANTED_BIT, value);
+    }
+
+    public boolean isDefending() {
+        return getMaskBit(offset(OFFSET, 1), DEFENDING_BIT);
+    }
+
+    public void setDefending(boolean value) {
+        setMaskBit(offset(OFFSET, 1), DEFENDING_BIT, value);
+    }
+
+    public Optional<UUID> getFirstUUID() {
+        return super.metadata.getIndex(offset(OFFSET, 2), Optional.empty());
+    }
+
+    public void setFirstUUID(@Nullable UUID value) {
+        super.metadata.setIndex(offset(OFFSET, 2), EntityDataTypes.OPTIONAL_UUID, Optional.of(value));
+    }
+
+    public Optional<UUID> getSecondUUID() {
+        return super.metadata.getIndex(offset(OFFSET, 3), Optional.empty());
+    }
+
+    public void setSecondUUID(@Nullable UUID value) {
+        super.metadata.setIndex(offset(OFFSET, 3), EntityDataTypes.OPTIONAL_UUID, Optional.of(value));
+    }
+
+    public enum Type {
+        RED,
+        SNOW;
+
+        private final static Type[] VALUES = values();
+    }
+
+
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/mobs/FrogMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/mobs/FrogMeta.java
new file mode 100644
index 0000000..876614d
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/mobs/FrogMeta.java
@@ -0,0 +1,46 @@
+package me.tofaa.entitylib.meta.mobs;
+
+import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
+import me.tofaa.entitylib.meta.Metadata;
+import me.tofaa.entitylib.meta.types.AgeableMeta;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Optional;
+
+public class FrogMeta extends AgeableMeta {
+
+    public static final byte OFFSET = AgeableMeta.MAX_OFFSET;
+    public static final byte MAX_OFFSET = OFFSET + 2;
+
+
+    public FrogMeta(int entityId, Metadata metadata) {
+        super(entityId, metadata);
+    }
+
+
+    public @NotNull Variant getVariant() {
+        return super.metadata.getIndex(OFFSET, Variant.TEMPERATE);
+    }
+
+    public void setVariant(@NotNull Variant value) {
+        super.metadata.setIndex(OFFSET, EntityDataTypes.FROG_VARIANT, value.ordinal());
+    }
+
+    public Optional<Integer> getTongueTarget() {
+        return super.metadata.getIndex(offset(OFFSET, 1), Optional.empty());
+    }
+
+    public void setTongueTarget(int value) {
+        super.metadata.setIndex(offset(OFFSET, 1), EntityDataTypes.OPTIONAL_INT, Optional.of(value));
+    }
+
+
+    public enum Variant {
+        TEMPERATE,
+        WARM,
+        COLD;
+
+        private final static FrogMeta.Variant[] VALUES = values();
+    }
+
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/mobs/GoatMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/mobs/GoatMeta.java
new file mode 100644
index 0000000..0fb05b9
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/mobs/GoatMeta.java
@@ -0,0 +1,25 @@
+package me.tofaa.entitylib.meta.mobs;
+
+import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
+import me.tofaa.entitylib.meta.Metadata;
+import me.tofaa.entitylib.meta.types.AgeableMeta;
+
+public class GoatMeta extends AgeableMeta {
+
+    public static final byte OFFSET = AgeableMeta.MAX_OFFSET;
+    public static final byte MAX_OFFSET = OFFSET + 1;
+
+
+    public GoatMeta(int entityId, Metadata metadata) {
+        super(entityId, metadata);
+    }
+
+    public boolean isScreaming() {
+        return metadata.getIndex(OFFSET, false);
+    }
+
+    public void setScreaming(boolean screaming) {
+        metadata.setIndex(OFFSET, EntityDataTypes.BOOLEAN, screaming);
+    }
+
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/mobs/HoglinMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/mobs/HoglinMeta.java
new file mode 100644
index 0000000..5c3c4bc
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/mobs/HoglinMeta.java
@@ -0,0 +1,26 @@
+package me.tofaa.entitylib.meta.mobs;
+
+import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
+import me.tofaa.entitylib.meta.Metadata;
+import me.tofaa.entitylib.meta.types.AgeableMeta;
+
+public class HoglinMeta extends AgeableMeta {
+
+    public static final byte OFFSET = AgeableMeta.MAX_OFFSET;
+    public static final byte MAX_OFFSET = OFFSET + 1;
+
+    public HoglinMeta(int entityId, Metadata metadata) {
+        super(entityId, metadata);
+    }
+
+
+    public boolean isImmuneToZombification() {
+        return super.metadata.getIndex(OFFSET, false);
+    }
+
+    public void setImmuneToZombification(boolean value) {
+        super.metadata.setIndex(OFFSET, EntityDataTypes.BOOLEAN, value);
+    }
+
+
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/mobs/OcelotMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/mobs/OcelotMeta.java
new file mode 100644
index 0000000..7e93470
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/mobs/OcelotMeta.java
@@ -0,0 +1,27 @@
+package me.tofaa.entitylib.meta.mobs;
+
+import com.github.retrooper.packetevents.manager.server.ServerVersion;
+import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
+import me.tofaa.entitylib.meta.Metadata;
+import me.tofaa.entitylib.meta.types.AgeableMeta;
+
+public class OcelotMeta extends AgeableMeta {
+
+    public static final byte OFFSET = AgeableMeta.MAX_OFFSET;
+    public static final byte MAX_OFFSET = OFFSET + 1;
+
+    public OcelotMeta(int entityId, Metadata metadata) {
+        super(entityId, metadata);
+    }
+
+    public boolean isTrusting() {
+        isVersionNewer(ServerVersion.V_1_14);
+        return super.metadata.getIndex(OFFSET, false);
+    }
+
+    public void setTrusting(boolean value) {
+        isVersionNewer(ServerVersion.V_1_14);
+        super.metadata.setIndex(OFFSET, EntityDataTypes.BOOLEAN, value);
+    }
+
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/mobs/PandaMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/mobs/PandaMeta.java
new file mode 100644
index 0000000..957c3ae
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/mobs/PandaMeta.java
@@ -0,0 +1,109 @@
+package me.tofaa.entitylib.meta.mobs;
+
+import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
+import me.tofaa.entitylib.meta.Metadata;
+import me.tofaa.entitylib.meta.types.AgeableMeta;
+import org.jetbrains.annotations.NotNull;
+
+public class PandaMeta extends AgeableMeta {
+
+    public static final byte OFFSET = AgeableMeta.MAX_OFFSET;
+    public static final byte MAX_OFFSET = OFFSET + 6;
+
+    private final static byte SNEEZING_BIT = 0x02;
+    private final static byte ROLLING_BIT = 0x04;
+    private final static byte SITTING_BIT = 0x08;
+    private final static byte ON_BACK_BIT = 0x10;
+
+    public PandaMeta(int entityId, Metadata metadata) {
+        super(entityId, metadata);
+    }
+
+    public int getBreedTimer() {
+        return super.metadata.getIndex(OFFSET, 0);
+    }
+
+    public void setBreedTimer(int value) {
+        super.metadata.setIndex(OFFSET, EntityDataTypes.INT, value);
+    }
+
+    public int getSneezeTimer() {
+        return super.metadata.getIndex(offset(OFFSET,1), 0);
+    }
+
+    public void setSneezeTimer(int value) {
+        super.metadata.setIndex(offset(OFFSET,1), EntityDataTypes.INT, value);
+    }
+
+    public int getEatTimer() {
+        return super.metadata.getIndex(offset(OFFSET,2), 0);
+    }
+
+    public void setEatTimer(int value) {
+        super.metadata.setIndex(offset(OFFSET,2), EntityDataTypes.INT, value);
+    }
+
+    @NotNull
+    public Gene getMainGene() {
+        return Gene.VALUES[super.metadata.getIndex(offset(OFFSET,3), (byte) 0)];
+    }
+
+    public void setMainGene(@NotNull Gene value) {
+        super.metadata.setIndex(offset(OFFSET,3), EntityDataTypes.BYTE, (byte) value.ordinal());
+    }
+
+    @NotNull
+    public Gene getHiddenGene() {
+        return Gene.VALUES[super.metadata.getIndex(offset(OFFSET,4), (byte) 0)];
+    }
+
+    public void setHiddenGene(@NotNull Gene value) {
+        super.metadata.setIndex(offset(OFFSET,4), EntityDataTypes.BYTE, (byte) value.ordinal());
+    }
+
+    public boolean isSneezing() {
+        return getMaskBit(offset(OFFSET,5), SNEEZING_BIT);
+    }
+
+    public void setSneezing(boolean value) {
+        setMaskBit(offset(OFFSET,5), SNEEZING_BIT, value);
+    }
+
+    public boolean isRolling() {
+        return getMaskBit(offset(OFFSET,5), ROLLING_BIT);
+    }
+
+    public void setRolling(boolean value) {
+        setMaskBit(offset(OFFSET,5), ROLLING_BIT, value);
+    }
+
+    public boolean isSitting() {
+        return getMaskBit(offset(OFFSET,5), SITTING_BIT);
+    }
+
+    public void setSitting(boolean value) {
+        setMaskBit(offset(OFFSET,5), SITTING_BIT, value);
+    }
+
+    public boolean isOnBack() {
+        return getMaskBit(offset(OFFSET,5), ON_BACK_BIT);
+    }
+
+    public void setOnBack(boolean value) {
+        setMaskBit(offset(OFFSET,5), ON_BACK_BIT, value);
+    }
+
+    public enum Gene {
+        NORMAL,
+        AGGRESSIVE,
+        LAZY,
+        WORRIED,
+        PLAYFUL,
+        WEAK,
+        BROWN;
+
+        private final static Gene[] VALUES = values();
+    }
+
+
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/mobs/PolarBearMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/mobs/PolarBearMeta.java
new file mode 100644
index 0000000..78d03c6
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/mobs/PolarBearMeta.java
@@ -0,0 +1,24 @@
+package me.tofaa.entitylib.meta.mobs;
+
+import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
+import me.tofaa.entitylib.meta.Metadata;
+import me.tofaa.entitylib.meta.types.AgeableMeta;
+
+public class PolarBearMeta extends AgeableMeta {
+
+    public static final byte OFFSET = AgeableMeta.MAX_OFFSET;
+    public static final byte MAX_OFFSET = OFFSET + 1;
+
+    public PolarBearMeta(int entityId, Metadata metadata) {
+        super(entityId, metadata);
+    }
+
+    public boolean isStandingUp() {
+        return super.metadata.getIndex(OFFSET, false);
+    }
+
+    public void setStandingUp(boolean value) {
+        super.metadata.setIndex(OFFSET, EntityDataTypes.BOOLEAN, value);
+    }
+
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/mobs/SnifferMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/mobs/SnifferMeta.java
new file mode 100644
index 0000000..2d0c571
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/mobs/SnifferMeta.java
@@ -0,0 +1,33 @@
+package me.tofaa.entitylib.meta.mobs;
+
+import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
+import com.github.retrooper.packetevents.protocol.entity.sniffer.SnifferState;
+import me.tofaa.entitylib.meta.Metadata;
+import me.tofaa.entitylib.meta.types.AgeableMeta;
+
+public class SnifferMeta extends AgeableMeta {
+
+    public static final byte OFFSET = AgeableMeta.MAX_OFFSET;
+    public static final byte MAX_OFFSET = OFFSET + 1;
+
+    public SnifferMeta(int entityId, Metadata metadata) {
+        super(entityId, metadata);
+    }
+
+    public SnifferState getState() {
+        return metadata.getIndex(OFFSET, SnifferState.IDLING);
+    }
+
+    public void setState(SnifferState state) {
+        super.metadata.setIndex(OFFSET, EntityDataTypes.SNIFFER_STATE, state);
+    }
+
+    public int getDropSeedAtTick() {
+        return metadata.getIndex(offset(OFFSET, 1), 0);
+    }
+
+    public void setDropSeedAtTick(int tick) {
+        super.metadata.setIndex(offset(OFFSET, 1), EntityDataTypes.INT, tick);
+    }
+
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/mobs/StriderMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/mobs/StriderMeta.java
new file mode 100644
index 0000000..b3bb11c
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/mobs/StriderMeta.java
@@ -0,0 +1,41 @@
+package me.tofaa.entitylib.meta.mobs;
+
+import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
+import me.tofaa.entitylib.meta.Metadata;
+import me.tofaa.entitylib.meta.types.AgeableMeta;
+
+public class StriderMeta extends AgeableMeta {
+
+    public static final byte OFFSET = AgeableMeta.MAX_OFFSET;
+    public static final byte MAX_OFFSET = OFFSET + 3;
+
+    public StriderMeta(int entityId, Metadata metadata) {
+        super(entityId, metadata);
+    }
+
+
+    public int getTimeToBoost() {
+        return super.metadata.getIndex(OFFSET, 0);
+    }
+
+    public void setTimeToBoost(int value) {
+        super.metadata.setIndex(OFFSET, EntityDataTypes.INT, value);
+    }
+
+    public boolean isShaking() {
+        return super.metadata.getIndex(offset(OFFSET,1), false);
+    }
+
+    public void setShaking(boolean value) {
+        super.metadata.setIndex(offset(OFFSET, 1), EntityDataTypes.BOOLEAN, value);
+    }
+
+    public boolean isHasSaddle() {
+        return super.metadata.getIndex(offset(OFFSET, 2), false);
+    }
+
+    public void setHasSaddle(boolean value) {
+        super.metadata.setIndex(offset(OFFSET, 2), EntityDataTypes.BOOLEAN, value);
+    }
+
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/mobs/cuboid/MagmaCubeMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/mobs/cuboid/MagmaCubeMeta.java
new file mode 100644
index 0000000..f2e96d1
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/mobs/cuboid/MagmaCubeMeta.java
@@ -0,0 +1,13 @@
+package me.tofaa.entitylib.meta.mobs.cuboid;
+
+import me.tofaa.entitylib.meta.Metadata;
+
+public class MagmaCubeMeta extends SlimeMeta {
+
+    public static final byte OFFSET = SlimeMeta.MAX_OFFSET;
+    public static final byte MAX_OFFSET = OFFSET + 0;
+
+    public MagmaCubeMeta(int entityId, Metadata metadata) {
+        super(entityId, metadata);
+    }
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/mobs/cuboid/SlimeMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/mobs/cuboid/SlimeMeta.java
new file mode 100644
index 0000000..ff6ed74
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/mobs/cuboid/SlimeMeta.java
@@ -0,0 +1,23 @@
+package me.tofaa.entitylib.meta.mobs.cuboid;
+
+import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
+import me.tofaa.entitylib.meta.Metadata;
+import me.tofaa.entitylib.meta.types.MobMeta;
+
+public class SlimeMeta extends MobMeta {
+    public static final byte OFFSET = MobMeta.MAX_OFFSET;
+    public static final byte MAX_OFFSET = OFFSET + 1;
+
+    public SlimeMeta(int entityId, Metadata metadata) {
+        super(entityId, metadata);
+    }
+
+    public int getSize() {
+        return super.metadata.getIndex(OFFSET, 0);
+    }
+
+    public void setSize(int value) {
+        super.metadata.setIndex(OFFSET, EntityDataTypes.INT, value);
+    }
+
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/mobs/golem/IronGolemMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/mobs/golem/IronGolemMeta.java
new file mode 100644
index 0000000..55e83ca
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/mobs/golem/IronGolemMeta.java
@@ -0,0 +1,26 @@
+package me.tofaa.entitylib.meta.mobs.golem;
+
+import me.tofaa.entitylib.meta.Metadata;
+import me.tofaa.entitylib.meta.types.MobMeta;
+
+public class IronGolemMeta extends MobMeta {
+
+    public static final byte OFFSET = MobMeta.MAX_OFFSET;
+    public static final byte MAX_OFFSET = OFFSET + 1;
+
+    private final static byte PLAYER_CREATED_BIT = 0x01;
+
+    public IronGolemMeta(int entityId, Metadata metadata) {
+        super(entityId, metadata);
+    }
+
+    public boolean isPlayerCreated() {
+        return getMaskBit(OFFSET, PLAYER_CREATED_BIT);
+    }
+
+    public void setPlayerCreated(boolean value) {
+        setMaskBit(OFFSET, PLAYER_CREATED_BIT, value);
+    }
+
+
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/mobs/golem/ShulkerMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/mobs/golem/ShulkerMeta.java
new file mode 100644
index 0000000..88617a9
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/mobs/golem/ShulkerMeta.java
@@ -0,0 +1,54 @@
+package me.tofaa.entitylib.meta.mobs.golem;
+
+import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
+import com.github.retrooper.packetevents.protocol.world.Direction;
+import com.github.retrooper.packetevents.util.Vector3i;
+import me.tofaa.entitylib.meta.Metadata;
+import me.tofaa.entitylib.meta.types.MobMeta;
+
+import java.util.Optional;
+
+public class ShulkerMeta extends MobMeta {
+
+    public static final byte OFFSET = MobMeta.MAX_OFFSET;
+    public static final byte MAX_OFFSET = OFFSET + 1;
+
+
+    public ShulkerMeta(int entityId, Metadata metadata) {
+        super(entityId, metadata);
+    }
+
+    public Direction getAttachFace() {
+        return super.metadata.getIndex(OFFSET, Direction.DOWN);
+    }
+
+    public void setAttachFace(Direction value) {
+        super.metadata.setIndex(OFFSET, EntityDataTypes.INT, value.ordinal());
+    }
+
+    public Optional<Vector3i> getAttachmentPosition() {
+        return super.metadata.getIndex(offset(OFFSET, 1), Optional.empty());
+    }
+
+    public void setAttachmentPosition(Vector3i value) {
+        super.metadata.setIndex(offset(OFFSET, 1), EntityDataTypes.OPTIONAL_BLOCK_POSITION, Optional.of(value));
+    }
+
+    public byte getShieldHeight() {
+        return super.metadata.getIndex(offset(OFFSET, 2), (byte) 0);
+    }
+
+    public void setShieldHeight(byte value) {
+        super.metadata.setIndex(offset(OFFSET, 2), EntityDataTypes.BYTE, value);
+    }
+
+    public byte getColor() {
+        return super.metadata.getIndex(offset(OFFSET, 3), (byte) 10);
+    }
+
+    public void setColor(byte value) {
+        super.metadata.setIndex(offset(OFFSET, 3), EntityDataTypes.BYTE, value);
+    }
+
+
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/mobs/golem/SnowGolemMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/mobs/golem/SnowGolemMeta.java
new file mode 100644
index 0000000..d2bb5a5
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/mobs/golem/SnowGolemMeta.java
@@ -0,0 +1,25 @@
+package me.tofaa.entitylib.meta.mobs.golem;
+
+import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
+import me.tofaa.entitylib.meta.Metadata;
+import me.tofaa.entitylib.meta.types.MobMeta;
+
+public class SnowGolemMeta extends MobMeta {
+
+    public static final byte OFFSET = MobMeta.MAX_OFFSET;
+    public static final byte MAX_OFFSET = OFFSET + 1;
+
+    public SnowGolemMeta(int entityId, Metadata metadata) {
+        super(entityId, metadata);
+    }
+
+    public boolean isHasPumpkinHat() {
+        return super.metadata.getIndex(OFFSET, (byte) 0x10) == (byte) 0x10;
+    }
+
+    public void setHasPumpkinHat(boolean value) {
+        byte var = value ? (byte) 0x10 : (byte) 0x00;
+        super.metadata.setIndex(OFFSET, EntityDataTypes.BYTE, var);
+    }
+
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/mobs/horse/BaseHorseMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/mobs/horse/BaseHorseMeta.java
new file mode 100644
index 0000000..1dd8637
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/mobs/horse/BaseHorseMeta.java
@@ -0,0 +1,82 @@
+package me.tofaa.entitylib.meta.mobs.horse;
+
+import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
+import me.tofaa.entitylib.meta.Metadata;
+import me.tofaa.entitylib.meta.types.MobMeta;
+
+import java.util.Optional;
+import java.util.UUID;
+
+public abstract class BaseHorseMeta extends MobMeta {
+
+    public static final byte OFFSET = MobMeta.MAX_OFFSET;
+    public static final byte MAX_OFFSET = OFFSET + 2;
+
+    private final static byte TAMED_BIT = 0x02;
+    private final static byte SADDLED_BIT = 0x04;
+    private final static byte HAS_BRED_BIT = 0x08;
+    private final static byte EATING_BIT = 0x10;
+    private final static byte REARING_BIT = 0x20;
+    private final static byte MOUTH_OPEN_BIT = 0x40;
+
+    protected BaseHorseMeta(int entityId, Metadata metadata) {
+        super(entityId, metadata);
+    }
+
+    public boolean isTamed() {
+        return getMaskBit(OFFSET, TAMED_BIT);
+    }
+
+    public void setTamed(boolean value) {
+        setMaskBit(OFFSET, TAMED_BIT, value);
+    }
+
+    public boolean isSaddled() {
+        return getMaskBit(OFFSET, SADDLED_BIT);
+    }
+
+    public void setSaddled(boolean value) {
+        setMaskBit(OFFSET, SADDLED_BIT, value);
+    }
+
+    public boolean isHasBred() {
+        return getMaskBit(OFFSET, HAS_BRED_BIT);
+    }
+
+    public void setHasBred(boolean value) {
+        setMaskBit(OFFSET, HAS_BRED_BIT, value);
+    }
+
+    public boolean isEating() {
+        return getMaskBit(OFFSET, EATING_BIT);
+    }
+
+    public void setEating(boolean value) {
+        setMaskBit(OFFSET, EATING_BIT, value);
+    }
+
+    public boolean isRearing() {
+        return getMaskBit(OFFSET, REARING_BIT);
+    }
+
+    public void setRearing(boolean value) {
+        setMaskBit(OFFSET, REARING_BIT, value);
+    }
+
+    public boolean isMouthOpen() {
+        return getMaskBit(OFFSET, MOUTH_OPEN_BIT);
+    }
+
+    public void setMouthOpen(boolean value) {
+        setMaskBit(OFFSET, MOUTH_OPEN_BIT, value);
+    }
+
+    public Optional<UUID> getOwner() {
+        return super.metadata.getIndex(offset(OFFSET, 1), Optional.empty());
+    }
+
+    public void setOwner(UUID value) {
+        super.metadata.setIndex(offset(OFFSET, 1), EntityDataTypes.OPTIONAL_UUID, Optional.of(value));
+    }
+
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/mobs/horse/ChestedHorseMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/mobs/horse/ChestedHorseMeta.java
new file mode 100644
index 0000000..596d443
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/mobs/horse/ChestedHorseMeta.java
@@ -0,0 +1,24 @@
+package me.tofaa.entitylib.meta.mobs.horse;
+
+import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
+import me.tofaa.entitylib.meta.Metadata;
+
+public class ChestedHorseMeta extends BaseHorseMeta {
+
+    public static final byte OFFSET = BaseHorseMeta.MAX_OFFSET;
+    public static final byte MAX_OFFSET = OFFSET + 1;
+
+    public ChestedHorseMeta(int entityId, Metadata metadata) {
+        super(entityId, metadata);
+    }
+
+    public boolean isHasChest() {
+        return super.metadata.getIndex(OFFSET, false);
+    }
+
+    public void setHasChest(boolean value) {
+        super.metadata.setIndex(OFFSET, EntityDataTypes.BOOLEAN, value);
+    }
+
+
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/mobs/horse/DonkeyMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/mobs/horse/DonkeyMeta.java
new file mode 100644
index 0000000..d398ced
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/mobs/horse/DonkeyMeta.java
@@ -0,0 +1,14 @@
+package me.tofaa.entitylib.meta.mobs.horse;
+
+import me.tofaa.entitylib.meta.Metadata;
+import me.tofaa.entitylib.meta.types.MobMeta;
+
+public class DonkeyMeta  extends ChestedHorseMeta{
+
+    public static final byte OFFSET = MobMeta.MAX_OFFSET;
+    public static final byte MAX_OFFSET = OFFSET + 0;
+
+    public DonkeyMeta(int entityId, Metadata metadata) {
+        super(entityId, metadata);
+    }
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/mobs/horse/HorseMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/mobs/horse/HorseMeta.java
new file mode 100644
index 0000000..246aeb7
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/mobs/horse/HorseMeta.java
@@ -0,0 +1,87 @@
+package me.tofaa.entitylib.meta.mobs.horse;
+
+import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
+import me.tofaa.entitylib.meta.Metadata;
+import org.jetbrains.annotations.NotNull;
+
+public class HorseMeta extends BaseHorseMeta {
+
+    public static final byte OFFSET = BaseHorseMeta.MAX_OFFSET;
+    public static final byte MAX_OFFSET = OFFSET + 1;
+
+    public HorseMeta(int entityId, Metadata metadata) {
+        super(entityId, metadata);
+    }
+
+    public Variant getVariant() {
+        return getVariantFromID(super.metadata.getIndex(OFFSET, 0));
+    }
+
+    public void setVariant(Variant variant) {
+        super.metadata.setIndex(OFFSET, EntityDataTypes.INT, getVariantID(variant.marking, variant.color));
+    }
+
+    public static int getVariantID(@NotNull Marking marking, @NotNull Color color) {
+        return (marking.ordinal() << 8) + color.ordinal();
+    }
+
+    public static Variant getVariantFromID(int variantID) {
+        return new Variant(
+                Marking.VALUES[variantID >> 8],
+                Color.VALUES[variantID & 0xFF]
+        );
+    }
+
+    public static class Variant {
+
+        private Marking marking;
+        private Color color;
+
+        public Variant(@NotNull Marking marking, @NotNull Color color) {
+            this.marking = marking;
+            this.color = color;
+        }
+
+        @NotNull
+        public Marking getMarking() {
+            return this.marking;
+        }
+
+        public void setMarking(@NotNull Marking marking) {
+            this.marking = marking;
+        }
+
+        @NotNull
+        public Color getColor() {
+            return this.color;
+        }
+
+        public void setColor(@NotNull Color color) {
+            this.color = color;
+        }
+
+    }
+
+    public enum Marking {
+        NONE,
+        WHITE,
+        WHITE_FIELD,
+        WHITE_DOTS,
+        BLACK_DOTS;
+
+        private final static Marking[] VALUES = values();
+    }
+
+    public enum Color {
+        WHITE,
+        CREAMY,
+        CHESTNUT,
+        BROWN,
+        BLACK,
+        GRAY,
+        DARK_BROWN;
+
+        private final static Color[] VALUES = values();
+    }
+
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/mobs/horse/LlamaMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/mobs/horse/LlamaMeta.java
new file mode 100644
index 0000000..053848e
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/mobs/horse/LlamaMeta.java
@@ -0,0 +1,48 @@
+package me.tofaa.entitylib.meta.mobs.horse;
+
+import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
+import me.tofaa.entitylib.meta.Metadata;
+
+public class LlamaMeta extends ChestedHorseMeta{
+
+    public static final byte OFFSET = ChestedHorseMeta.MAX_OFFSET;
+    public static final byte MAX_OFFSET = OFFSET + 3;
+
+    public LlamaMeta(int entityId, Metadata metadata) {
+        super(entityId, metadata);
+    }
+
+    public int getStrength() {
+        return super.metadata.getIndex(OFFSET, 0);
+    }
+
+    public void setStrength(int value) {
+        super.metadata.setIndex(OFFSET, EntityDataTypes.INT, value);
+    }
+
+    public int getCarpetColor() {
+        return super.metadata.getIndex(offset(OFFSET, 1), -1);
+    }
+
+    public void setCarpetColor(int value) {
+        super.metadata.setIndex(offset(OFFSET, 1), EntityDataTypes.INT, value);
+    }
+
+    public Variant getVariant() {
+        return Variant.VALUES[super.metadata.getIndex(offset(OFFSET, 2), 0)];
+    }
+
+    public void setVariant(Variant value) {
+        super.metadata.setIndex(offset(OFFSET, 2), EntityDataTypes.INT, value.ordinal());
+    }
+
+    public enum Variant {
+        CREAMY,
+        WHITE,
+        BROWN,
+        GRAY;
+
+        private final static Variant[] VALUES = values();
+    }
+
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/mobs/horse/MuleMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/mobs/horse/MuleMeta.java
new file mode 100644
index 0000000..f5c6b4e
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/mobs/horse/MuleMeta.java
@@ -0,0 +1,13 @@
+package me.tofaa.entitylib.meta.mobs.horse;
+
+import me.tofaa.entitylib.meta.Metadata;
+
+public class MuleMeta extends ChestedHorseMeta{
+
+    public static final byte OFFSET = ChestedHorseMeta.MAX_OFFSET;
+    public static final byte MAX_OFFSET = OFFSET + 0;
+
+    public MuleMeta(int entityId, Metadata metadata) {
+        super(entityId, metadata);
+    }
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/mobs/horse/SkeletonHorseMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/mobs/horse/SkeletonHorseMeta.java
new file mode 100644
index 0000000..fb4d1c4
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/mobs/horse/SkeletonHorseMeta.java
@@ -0,0 +1,13 @@
+package me.tofaa.entitylib.meta.mobs.horse;
+
+import me.tofaa.entitylib.meta.Metadata;
+
+public class SkeletonHorseMeta extends BaseHorseMeta {
+
+    public static final byte OFFSET = BaseHorseMeta.MAX_OFFSET;
+    public static final byte MAX_OFFSET = OFFSET + 0;
+
+    public SkeletonHorseMeta(int entityId, Metadata metadata) {
+        super(entityId, metadata);
+    }
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/mobs/horse/TraderLlamaMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/mobs/horse/TraderLlamaMeta.java
new file mode 100644
index 0000000..a4d101d
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/mobs/horse/TraderLlamaMeta.java
@@ -0,0 +1,14 @@
+package me.tofaa.entitylib.meta.mobs.horse;
+
+import me.tofaa.entitylib.meta.EntityMeta;
+import me.tofaa.entitylib.meta.Metadata;
+
+public class TraderLlamaMeta extends EntityMeta {
+
+    public static final byte OFFSET = EntityMeta.MAX_OFFSET;
+    public static final byte MAX_OFFSET = OFFSET + 0;
+
+    public TraderLlamaMeta(int entityId, Metadata metadata) {
+        super(entityId, metadata);
+    }
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/mobs/horse/ZombieHorseMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/mobs/horse/ZombieHorseMeta.java
new file mode 100644
index 0000000..b0c42f1
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/mobs/horse/ZombieHorseMeta.java
@@ -0,0 +1,13 @@
+package me.tofaa.entitylib.meta.mobs.horse;
+
+import me.tofaa.entitylib.meta.Metadata;
+
+public class ZombieHorseMeta extends BaseHorseMeta {
+
+    public static final byte OFFSET = BaseHorseMeta.MAX_OFFSET;
+    public static final byte MAX_OFFSET = OFFSET + 0;
+
+    public ZombieHorseMeta(int entityId, Metadata metadata) {
+        super(entityId, metadata);
+    }
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/mobs/minecart/BaseMinecartMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/mobs/minecart/BaseMinecartMeta.java
new file mode 100644
index 0000000..8f17929
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/mobs/minecart/BaseMinecartMeta.java
@@ -0,0 +1,62 @@
+package me.tofaa.entitylib.meta.mobs.minecart;
+
+import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
+import me.tofaa.entitylib.meta.EntityMeta;
+import me.tofaa.entitylib.meta.Metadata;
+import me.tofaa.entitylib.meta.types.ObjectData;
+
+public abstract class BaseMinecartMeta extends EntityMeta implements ObjectData {
+
+    public static final byte OFFSET = EntityMeta.MAX_OFFSET;
+    public static final byte MAX_OFFSET = OFFSET + 6;
+
+    protected BaseMinecartMeta(int entityId, Metadata metadata) {
+        super(entityId, metadata);
+    }
+
+    public int getShakingPower() {
+        return super.metadata.getIndex(OFFSET, 0);
+    }
+
+    public void setShakingPower(int value) {
+        super.metadata.setIndex(OFFSET, EntityDataTypes.INT, value);
+    }
+
+    public int getShakingDirection() {
+        return super.metadata.getIndex(offset(OFFSET, 1), 1);
+    }
+
+    public void setShakingDirection(int value) {
+        super.metadata.setIndex(offset(OFFSET, 1), EntityDataTypes.INT, value);
+    }
+
+    public float getShakingMultiplier() {
+        return super.metadata.getIndex(offset(OFFSET, 2), 0F);
+    }
+
+    public void setShakingMultiplier(float value) {
+        super.metadata.setIndex(offset(OFFSET, 2), EntityDataTypes.FLOAT, value);
+    }
+
+    public int getCustomBlockIdAndDamage() {
+        return super.metadata.getIndex(offset(OFFSET, 3), 0);
+    }
+
+    public void setCustomBlockIdAndDamage(int value) {
+        super.metadata.setIndex(offset(OFFSET, 3), EntityDataTypes.INT, value);
+    }
+
+    // in 16th of a block
+    public int getCustomBlockYPosition() {
+        return super.metadata.getIndex(offset(OFFSET, 4), 6);
+    }
+
+    public void setCustomBlockYPosition(int value) {
+        super.metadata.setIndex(offset(OFFSET, 4), EntityDataTypes.INT, value);
+    }
+
+    @Override
+    public boolean requiresVelocityPacketAtSpawn() {
+        return true;
+    }
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/mobs/minecart/ChestMinecartMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/mobs/minecart/ChestMinecartMeta.java
new file mode 100644
index 0000000..b3d0b7a
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/mobs/minecart/ChestMinecartMeta.java
@@ -0,0 +1,19 @@
+package me.tofaa.entitylib.meta.mobs.minecart;
+
+import me.tofaa.entitylib.meta.Metadata;
+
+public class ChestMinecartMeta extends BaseMinecartMeta{
+
+    public static final byte OFFSET = BaseMinecartMeta.MAX_OFFSET;
+    public static final byte MAX_OFFSET = OFFSET + 0;
+
+
+    public ChestMinecartMeta(int entityId, Metadata metadata) {
+        super(entityId, metadata);
+    }
+
+    @Override
+    public int getObjectData() {
+        return 1;
+    }
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/mobs/minecart/CommandBlockMinecartMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/mobs/minecart/CommandBlockMinecartMeta.java
new file mode 100644
index 0000000..10459d2
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/mobs/minecart/CommandBlockMinecartMeta.java
@@ -0,0 +1,38 @@
+package me.tofaa.entitylib.meta.mobs.minecart;
+
+import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
+import me.tofaa.entitylib.meta.Metadata;
+import net.kyori.adventure.text.Component;
+import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
+import org.jetbrains.annotations.NotNull;
+
+public class CommandBlockMinecartMeta extends BaseMinecartMeta{
+
+    public static final byte OFFSET = BaseMinecartMeta.MAX_OFFSET;
+    public static final byte MAX_OFFSET = OFFSET + 2;
+
+    public CommandBlockMinecartMeta(int entityId, Metadata metadata) {
+        super(entityId, metadata);
+    }
+
+    public @NotNull String getCommand() {
+        return super.metadata.getIndex(OFFSET, "");
+    }
+
+    public void setCommand(@NotNull String value) {
+        super.metadata.setIndex(OFFSET, EntityDataTypes.STRING, value);
+    }
+
+    public @NotNull Component getLastOutput() {
+        return super.metadata.getIndex(offset(OFFSET, 1), Component.empty());
+    }
+
+    public void setLastOutput(@NotNull Component value) {
+        super.metadata.setIndex(offset(OFFSET, 1), EntityDataTypes.COMPONENT, GsonComponentSerializer.gson().serialize(value));
+    }
+
+    @Override
+    public int getObjectData() {
+        return 6;
+    }
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/mobs/minecart/FurnaceMinecartMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/mobs/minecart/FurnaceMinecartMeta.java
new file mode 100644
index 0000000..9f745bb
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/mobs/minecart/FurnaceMinecartMeta.java
@@ -0,0 +1,26 @@
+package me.tofaa.entitylib.meta.mobs.minecart;
+
+import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
+import me.tofaa.entitylib.meta.Metadata;
+
+public class FurnaceMinecartMeta extends BaseMinecartMeta {
+
+    public static final byte OFFSET = BaseMinecartMeta.MAX_OFFSET;
+    public static final byte MAX_OFFSET = OFFSET + 1;
+
+    public FurnaceMinecartMeta(int entityId, Metadata metadata) {
+        super(entityId, metadata);
+    }
+
+    public boolean isHasFuel() {
+        return super.metadata.getIndex(OFFSET, false);
+    }
+
+    public void setHasFuel(boolean value) {
+        super.metadata.setIndex(OFFSET, EntityDataTypes.BOOLEAN, value);
+    }
+
+    @Override
+    public int getObjectData() {
+        return 2;    }
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/mobs/minecart/HopperMinecartMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/mobs/minecart/HopperMinecartMeta.java
new file mode 100644
index 0000000..ac8a4fb
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/mobs/minecart/HopperMinecartMeta.java
@@ -0,0 +1,18 @@
+package me.tofaa.entitylib.meta.mobs.minecart;
+
+import me.tofaa.entitylib.meta.Metadata;
+
+public class HopperMinecartMeta extends BaseMinecartMeta {
+
+    public static final byte OFFSET = BaseMinecartMeta.MAX_OFFSET;
+    public static final byte MAX_OFFSET = OFFSET + 0;
+
+    public HopperMinecartMeta(int entityId, Metadata metadata) {
+        super(entityId, metadata);
+    }
+
+    @Override
+    public int getObjectData() {
+        return 5;
+    }
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/mobs/minecart/MinecartMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/mobs/minecart/MinecartMeta.java
new file mode 100644
index 0000000..3c43de7
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/mobs/minecart/MinecartMeta.java
@@ -0,0 +1,18 @@
+package me.tofaa.entitylib.meta.mobs.minecart;
+
+import me.tofaa.entitylib.meta.Metadata;
+
+public class MinecartMeta extends BaseMinecartMeta {
+
+    public static final byte OFFSET = BaseMinecartMeta.MAX_OFFSET;
+    public static final byte MAX_OFFSET = OFFSET + 0;
+
+    public MinecartMeta(int entityId, Metadata metadata) {
+        super(entityId, metadata);
+    }
+
+    @Override
+    public int getObjectData() {
+        return 0;
+    }
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/mobs/minecart/SpawnerMinecartMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/mobs/minecart/SpawnerMinecartMeta.java
new file mode 100644
index 0000000..8e3a7e8
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/mobs/minecart/SpawnerMinecartMeta.java
@@ -0,0 +1,19 @@
+package me.tofaa.entitylib.meta.mobs.minecart;
+
+import me.tofaa.entitylib.meta.Metadata;
+
+public class SpawnerMinecartMeta extends BaseMinecartMeta {
+
+    public static final byte OFFSET = BaseMinecartMeta.MAX_OFFSET;
+    public static final byte MAX_OFFSET = OFFSET + 0;
+
+    public SpawnerMinecartMeta(int entityId, Metadata metadata) {
+        super(entityId, metadata);
+    }
+
+    @Override
+    public int getObjectData() {
+        return 4;
+    }
+
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/mobs/minecart/TntMinecartMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/mobs/minecart/TntMinecartMeta.java
new file mode 100644
index 0000000..9ceca9b
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/mobs/minecart/TntMinecartMeta.java
@@ -0,0 +1,18 @@
+package me.tofaa.entitylib.meta.mobs.minecart;
+
+import me.tofaa.entitylib.meta.Metadata;
+
+public class TntMinecartMeta extends BaseMinecartMeta{
+
+    public static final byte OFFSET = BaseMinecartMeta.MAX_OFFSET;
+    public static final byte MAX_OFFSET = OFFSET + 0;
+
+    public TntMinecartMeta(int entityId, Metadata metadata) {
+        super(entityId, metadata);
+    }
+
+    @Override
+    public int getObjectData() {
+        return 3;
+    }
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/BlazeMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/BlazeMeta.java
new file mode 100644
index 0000000..3e45084
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/BlazeMeta.java
@@ -0,0 +1,26 @@
+package me.tofaa.entitylib.meta.mobs.monster;
+
+import me.tofaa.entitylib.meta.Metadata;
+import me.tofaa.entitylib.meta.types.MobMeta;
+
+public class BlazeMeta extends MobMeta {
+
+    public static final byte OFFSET = MobMeta.MAX_OFFSET;
+    public static final byte MAX_OFFSET = OFFSET + 1;
+
+    private final static byte ON_FIRE_BIT = 0x01;
+
+    public BlazeMeta(int entityId, Metadata metadata) {
+        super(entityId, metadata);
+    }
+
+    public boolean isOnFire() {
+        return getMaskBit(OFFSET, ON_FIRE_BIT);
+    }
+
+    public void setOnFire(boolean value) {
+        setMaskBit(OFFSET, ON_FIRE_BIT, value);
+    }
+
+
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/CaveSpiderMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/CaveSpiderMeta.java
new file mode 100644
index 0000000..73eab25
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/CaveSpiderMeta.java
@@ -0,0 +1,13 @@
+package me.tofaa.entitylib.meta.mobs.monster;
+
+import me.tofaa.entitylib.meta.Metadata;
+
+public class CaveSpiderMeta extends SpiderMeta{
+
+    public static final byte OFFSET = SpiderMeta.MAX_OFFSET;
+    public static final byte MAX_OFFSET = OFFSET + 0;
+
+    public CaveSpiderMeta(int entityId, Metadata metadata) {
+        super(entityId, metadata);
+    }
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/CreeperMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/CreeperMeta.java
new file mode 100644
index 0000000..3867cc9
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/CreeperMeta.java
@@ -0,0 +1,49 @@
+package me.tofaa.entitylib.meta.mobs.monster;
+
+import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
+import me.tofaa.entitylib.meta.Metadata;
+import me.tofaa.entitylib.meta.types.MobMeta;
+import org.jetbrains.annotations.NotNull;
+
+public class CreeperMeta extends MobMeta {
+
+    public static final byte OFFSET = MobMeta.MAX_OFFSET;
+    public static final byte MAX_OFFSET = OFFSET + 3;
+
+    public CreeperMeta(int entityId, Metadata metadata) {
+        super(entityId, metadata);
+    }
+
+    @NotNull
+    public State getState() {
+        int id = super.metadata.getIndex(OFFSET, -1);
+        return id == -1 ? State.IDLE : State.FUSE;
+    }
+
+    public void setState(@NotNull State value) {
+        super.metadata.setIndex(OFFSET, EntityDataTypes.INT, value == State.IDLE ? -1 : 1);
+    }
+
+    public boolean isCharged() {
+        return super.metadata.getIndex(offset(OFFSET, 1), false);
+    }
+
+    public void setCharged(boolean value) {
+        super.metadata.setIndex(offset(OFFSET, 1), EntityDataTypes.BOOLEAN, value);
+    }
+
+    public boolean isIgnited() {
+        return super.metadata.getIndex(offset(OFFSET, 2), false);
+    }
+
+    public void setIgnited(boolean value) {
+        super.metadata.setIndex(offset(OFFSET, 2), EntityDataTypes.BOOLEAN, value);
+    }
+
+    public enum State {
+        IDLE,
+        FUSE
+    }
+
+
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/ElderGuardianMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/ElderGuardianMeta.java
new file mode 100644
index 0000000..f292b68
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/ElderGuardianMeta.java
@@ -0,0 +1,13 @@
+package me.tofaa.entitylib.meta.mobs.monster;
+
+import me.tofaa.entitylib.meta.Metadata;
+
+public class ElderGuardianMeta extends GuardianMeta{
+
+    public static final byte OFFSET = GuardianMeta.MAX_OFFSET;
+    public static final byte MAX_OFFSET = OFFSET + 0;
+
+    public ElderGuardianMeta(int entityId, Metadata metadata) {
+        super(entityId, metadata);
+    }
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/EndermanMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/EndermanMeta.java
new file mode 100644
index 0000000..0ba5c73
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/EndermanMeta.java
@@ -0,0 +1,44 @@
+package me.tofaa.entitylib.meta.mobs.monster;
+
+import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
+import me.tofaa.entitylib.meta.Metadata;
+import me.tofaa.entitylib.meta.types.MobMeta;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.Optional;
+
+public class EndermanMeta extends MobMeta {
+
+    public static final byte OFFSET = MobMeta.MAX_OFFSET;
+    public static final byte MAX_OFFSET = OFFSET + 3;
+
+    public EndermanMeta(int entityId, Metadata metadata) {
+        super(entityId, metadata);
+    }
+
+    public Integer getCarriedBlockID() {
+        return super.metadata.getIndex(OFFSET, null);
+    }
+
+    public void setCarriedBlockID(@Nullable Integer value) {
+        super.metadata.setIndex(OFFSET, EntityDataTypes.OPTIONAL_INT, Optional.ofNullable(value));
+    }
+
+    public boolean isScreaming() {
+        return super.metadata.getIndex(offset(OFFSET, 1), false);
+    }
+
+    public void setScreaming(boolean value) {
+        super.metadata.setIndex(offset(OFFSET, 1), EntityDataTypes.BOOLEAN, value);
+    }
+
+    public boolean isStaring() {
+        return super.metadata.getIndex(offset(OFFSET, 2),  false);
+    }
+
+    public void setStaring(boolean value) {
+        super.metadata.setIndex(offset(OFFSET, 2), EntityDataTypes.BOOLEAN, value);
+    }
+
+
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/EndermiteMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/EndermiteMeta.java
new file mode 100644
index 0000000..4ff42c9
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/EndermiteMeta.java
@@ -0,0 +1,14 @@
+package me.tofaa.entitylib.meta.mobs.monster;
+
+import me.tofaa.entitylib.meta.Metadata;
+import me.tofaa.entitylib.meta.types.MobMeta;
+
+public class EndermiteMeta extends MobMeta {
+
+    public static final byte OFFSET = MobMeta.MAX_OFFSET;
+    public static final byte MAX_OFFSET = OFFSET + 0;
+
+    public EndermiteMeta(int entityId, Metadata metadata) {
+        super(entityId, metadata);
+    }
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/GhastMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/GhastMeta.java
new file mode 100644
index 0000000..5192227
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/GhastMeta.java
@@ -0,0 +1,25 @@
+package me.tofaa.entitylib.meta.mobs.monster;
+
+import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
+import me.tofaa.entitylib.meta.Metadata;
+import me.tofaa.entitylib.meta.types.MobMeta;
+
+public class GhastMeta extends MobMeta {
+
+    public static final byte OFFSET = MobMeta.MAX_OFFSET;
+    public static final byte MAX_OFFSET = OFFSET + 1;
+
+    public GhastMeta(int entityId, Metadata metadata) {
+        super(entityId, metadata);
+    }
+
+
+    public boolean isAttacking() {
+        return super.metadata.getIndex(OFFSET, false);
+    }
+
+    public void setAttacking(boolean value) {
+        super.metadata.setIndex(OFFSET, EntityDataTypes.BOOLEAN, value);
+    }
+
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/GiantMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/GiantMeta.java
new file mode 100644
index 0000000..1d00514
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/GiantMeta.java
@@ -0,0 +1,13 @@
+package me.tofaa.entitylib.meta.mobs.monster;
+
+import me.tofaa.entitylib.meta.Metadata;
+import me.tofaa.entitylib.meta.types.MobMeta;
+
+public class GiantMeta extends MobMeta {
+    public static final byte OFFSET = MobMeta.MAX_OFFSET;
+    public static final byte MAX_OFFSET = OFFSET + 0;
+
+    public GiantMeta(int entityId, Metadata metadata) {
+        super(entityId, metadata);
+    }
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/GuardianMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/GuardianMeta.java
new file mode 100644
index 0000000..39ef78a
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/GuardianMeta.java
@@ -0,0 +1,36 @@
+package me.tofaa.entitylib.meta.mobs.monster;
+
+import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
+import me.tofaa.entitylib.meta.Metadata;
+import me.tofaa.entitylib.meta.types.MobMeta;
+
+public class GuardianMeta extends MobMeta {
+
+    public static final byte OFFSET = MobMeta.MAX_OFFSET;
+    public static final byte MAX_OFFSET = OFFSET + 2;
+
+    private int target = -1;
+
+    public GuardianMeta(int entityId, Metadata metadata) {
+        super(entityId, metadata);
+    }
+
+    public boolean isRetractingSpikes() {
+        return super.metadata.getIndex(OFFSET, false);
+    }
+
+    public void setRetractingSpikes(boolean retractingSpikes) {
+        super.metadata.setIndex(OFFSET, EntityDataTypes.BOOLEAN, retractingSpikes);
+    }
+
+    public int getTarget() {
+        return this.target;
+    }
+
+    public void setTarget(int target) {
+        this.target = target;
+        super.metadata.setIndex(offset(OFFSET, 1), EntityDataTypes.INT, target == -1 ? 0 : target);
+    }
+
+
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/PhantomMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/PhantomMeta.java
new file mode 100644
index 0000000..11641ff
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/PhantomMeta.java
@@ -0,0 +1,24 @@
+package me.tofaa.entitylib.meta.mobs.monster;
+
+import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
+import me.tofaa.entitylib.meta.Metadata;
+import me.tofaa.entitylib.meta.types.MobMeta;
+
+public class PhantomMeta extends MobMeta {
+
+    public static final byte OFFSET = MobMeta.MAX_OFFSET;
+    public static final byte MAX_OFFSET = OFFSET + 1;
+
+    public PhantomMeta(int entityId, Metadata metadata) {
+        super(entityId, metadata);
+    }
+
+    public int getSize() {
+        return super.metadata.getIndex(OFFSET, 0);
+    }
+
+    public void setSize(int value) {
+        super.metadata.setIndex(OFFSET, EntityDataTypes.INT, value);
+    }
+
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/SilverfishMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/SilverfishMeta.java
new file mode 100644
index 0000000..19e3789
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/SilverfishMeta.java
@@ -0,0 +1,14 @@
+package me.tofaa.entitylib.meta.mobs.monster;
+
+import me.tofaa.entitylib.meta.Metadata;
+import me.tofaa.entitylib.meta.types.MobMeta;
+
+public class SilverfishMeta extends MobMeta {
+    public static final byte OFFSET = MobMeta.MAX_OFFSET;
+    public static final byte MAX_OFFSET = OFFSET + 0;
+
+
+    public SilverfishMeta(int entityId, Metadata metadata) {
+        super(entityId, metadata);
+    }
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/SpiderMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/SpiderMeta.java
new file mode 100644
index 0000000..13b0de0
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/SpiderMeta.java
@@ -0,0 +1,27 @@
+package me.tofaa.entitylib.meta.mobs.monster;
+
+import me.tofaa.entitylib.meta.Metadata;
+import me.tofaa.entitylib.meta.types.MobMeta;
+
+public class SpiderMeta extends MobMeta {
+
+    public static final byte OFFSET = MobMeta.MAX_OFFSET;
+    public static final byte MAX_OFFSET = OFFSET + 1;
+
+    private final static byte CLIMBING_BIT = 0x01;
+
+
+    public SpiderMeta(int entityId, Metadata metadata) {
+        super(entityId, metadata);
+    }
+
+    public boolean isClimbing() {
+        return getMaskBit(OFFSET, CLIMBING_BIT);
+    }
+
+    public void setClimbing(boolean value) {
+        setMaskBit(OFFSET, CLIMBING_BIT, value);
+    }
+
+
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/VexMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/VexMeta.java
new file mode 100644
index 0000000..ea8835d
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/VexMeta.java
@@ -0,0 +1,25 @@
+package me.tofaa.entitylib.meta.mobs.monster;
+
+import me.tofaa.entitylib.meta.Metadata;
+import me.tofaa.entitylib.meta.types.MobMeta;
+
+public class VexMeta extends MobMeta {
+
+    public static final byte OFFSET = MobMeta.MAX_OFFSET;
+    public static final byte MAX_OFFSET = OFFSET + 1;
+
+    private final static byte ATTACKING_BIT = 0x01;
+
+    public VexMeta(int entityId, Metadata metadata) {
+        super(entityId, metadata);
+    }
+
+    public boolean isAttacking() {
+        return getMaskBit(OFFSET, ATTACKING_BIT);
+    }
+
+    public void setAttacking(boolean value) {
+        setMaskBit(OFFSET, ATTACKING_BIT, value);
+    }
+
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/WitherMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/WitherMeta.java
new file mode 100644
index 0000000..2f8c861
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/WitherMeta.java
@@ -0,0 +1,55 @@
+package me.tofaa.entitylib.meta.mobs.monster;
+
+import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
+import me.tofaa.entitylib.meta.Metadata;
+import me.tofaa.entitylib.meta.types.MobMeta;
+
+public class WitherMeta extends MobMeta {
+
+    public static final byte OFFSET = MobMeta.MAX_OFFSET;
+    public static final byte MAX_OFFSET = OFFSET + 4;
+
+    private int centerHead = -1;
+    private int leftHead = -1;
+    private int rightHead = -1;
+
+    public WitherMeta(int entityId, Metadata metadata) {
+        super(entityId, metadata);
+    }
+
+    public void setCenterHead(int centerHead) {
+        this.centerHead = centerHead;
+        super.metadata.setIndex(offset(OFFSET,0), EntityDataTypes.INT, centerHead == -1 ? 0 : centerHead);
+    }
+
+    public void setLeftHead(int leftHead) {
+        this.leftHead = leftHead;
+        super.metadata.setIndex(offset(OFFSET,1), EntityDataTypes.INT, leftHead == -1 ? 0 : leftHead);
+    }
+
+    public void setRightHead(int rightHead) {
+        this.rightHead = rightHead;
+        super.metadata.setIndex(offset(OFFSET,2), EntityDataTypes.INT, rightHead == -1 ? 0 : rightHead);
+    }
+
+    public int getCenterHead() {
+        return centerHead;
+    }
+
+    public int getLeftHead() {
+        return leftHead;
+    }
+
+    public int getRightHead() {
+        return rightHead;
+    }
+
+    public int getInvulnerableTime() {
+        return super.metadata.getIndex(offset(OFFSET, 3), 0);
+    }
+
+    public void setInvulnerableTime(int value) {
+        super.metadata.setIndex(offset(OFFSET, 3), EntityDataTypes.INT, value);
+    }
+
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/ZoglinMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/ZoglinMeta.java
new file mode 100644
index 0000000..0df787f
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/ZoglinMeta.java
@@ -0,0 +1,28 @@
+package me.tofaa.entitylib.meta.mobs.monster;
+
+import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
+import me.tofaa.entitylib.meta.Metadata;
+import me.tofaa.entitylib.meta.types.MobMeta;
+
+public class ZoglinMeta extends MobMeta {
+
+    public static final byte OFFSET = MobMeta.MAX_OFFSET;
+    public static final byte MAX_OFFSET = OFFSET + 1;
+
+    public ZoglinMeta(int entityId, Metadata metadata) {
+        super(entityId, metadata);
+    }
+
+
+    public boolean isBaby() {
+        return super.metadata.getIndex(OFFSET, false);
+    }
+
+    public void setBaby(boolean value) {
+        if (isBaby() == value) {
+            return;
+        }
+        super.metadata.setIndex(OFFSET, EntityDataTypes.BOOLEAN, value);
+    }
+
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/piglin/BasePiglinMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/piglin/BasePiglinMeta.java
new file mode 100644
index 0000000..2aef4e9
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/piglin/BasePiglinMeta.java
@@ -0,0 +1,25 @@
+package me.tofaa.entitylib.meta.mobs.monster.piglin;
+
+import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
+import me.tofaa.entitylib.meta.Metadata;
+import me.tofaa.entitylib.meta.types.MobMeta;
+
+public abstract class BasePiglinMeta extends MobMeta {
+
+    public static final byte OFFSET = MobMeta.MAX_OFFSET;
+    public static final byte MAX_OFFSET = OFFSET + 1;
+
+    protected BasePiglinMeta(int entityId, Metadata metadata) {
+        super(entityId, metadata);
+    }
+
+    public boolean isImmuneToZombification() {
+        return super.metadata.getIndex(OFFSET, false);
+    }
+
+    public void setImmuneToZombification(boolean value) {
+        super.metadata.setIndex(OFFSET, EntityDataTypes.BOOLEAN, value);
+    }
+
+
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/piglin/PiglinBruteMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/piglin/PiglinBruteMeta.java
new file mode 100644
index 0000000..9fe68b6
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/piglin/PiglinBruteMeta.java
@@ -0,0 +1,13 @@
+package me.tofaa.entitylib.meta.mobs.monster.piglin;
+
+import me.tofaa.entitylib.meta.Metadata;
+
+public class PiglinBruteMeta extends BasePiglinMeta{
+
+    public static final byte OFFSET = BasePiglinMeta.MAX_OFFSET;
+    public static final byte MAX_OFFSET = OFFSET + 0;
+
+    public PiglinBruteMeta(int entityId, Metadata metadata) {
+        super(entityId, metadata);
+    }
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/piglin/PiglinMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/piglin/PiglinMeta.java
new file mode 100644
index 0000000..04747f3
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/piglin/PiglinMeta.java
@@ -0,0 +1,43 @@
+package me.tofaa.entitylib.meta.mobs.monster.piglin;
+
+import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
+import me.tofaa.entitylib.meta.Metadata;
+
+public class PiglinMeta extends BasePiglinMeta{
+
+    public static final byte OFFSET = BasePiglinMeta.MAX_OFFSET;
+    public static final byte MAX_OFFSET = OFFSET + 3;
+
+    public PiglinMeta(int entityId, Metadata metadata) {
+        super(entityId, metadata);
+    }
+
+    public boolean isBaby() {
+        return super.metadata.getIndex(OFFSET, false);
+    }
+
+    public void setBaby(boolean value) {
+        if (isBaby() == value) {
+            return;
+        }
+        super.metadata.setIndex(OFFSET, EntityDataTypes.BOOLEAN, value);
+    }
+
+    public boolean isChargingCrossbow() {
+        return super.metadata.getIndex(offset(OFFSET, 1), false);
+    }
+
+    public void setChargingCrossbow(boolean value) {
+        super.metadata.setIndex(offset(OFFSET, 1), EntityDataTypes.BOOLEAN, value);
+    }
+
+    public boolean isDancing() {
+        return super.metadata.getIndex(offset(OFFSET, 2), false);
+    }
+
+    public void setDancing(boolean value) {
+        super.metadata.setIndex(offset(OFFSET, 2), EntityDataTypes.BOOLEAN, value);
+    }
+
+
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/raider/EvokerMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/raider/EvokerMeta.java
new file mode 100644
index 0000000..0f68113
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/raider/EvokerMeta.java
@@ -0,0 +1,13 @@
+package me.tofaa.entitylib.meta.mobs.monster.raider;
+
+import me.tofaa.entitylib.meta.Metadata;
+
+public class EvokerMeta extends SpellcasterIllagerMeta {
+
+    public static final byte OFFSET = SpellcasterIllagerMeta.MAX_OFFSET;
+    public static final byte MAX_OFFSET = OFFSET + 0;
+
+    public EvokerMeta(int entityId, Metadata metadata) {
+        super(entityId, metadata);
+    }
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/raider/IllusionerMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/raider/IllusionerMeta.java
new file mode 100644
index 0000000..07ec254
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/raider/IllusionerMeta.java
@@ -0,0 +1,13 @@
+package me.tofaa.entitylib.meta.mobs.monster.raider;
+
+import me.tofaa.entitylib.meta.Metadata;
+
+public class IllusionerMeta extends SpellcasterIllagerMeta {
+
+    public static final byte OFFSET = SpellcasterIllagerMeta.MAX_OFFSET;
+    public static final byte MAX_OFFSET = OFFSET + 0;
+
+    public IllusionerMeta(int entityId, Metadata metadata) {
+        super(entityId, metadata);
+    }
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/raider/PillagerMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/raider/PillagerMeta.java
new file mode 100644
index 0000000..83264ef
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/raider/PillagerMeta.java
@@ -0,0 +1,14 @@
+package me.tofaa.entitylib.meta.mobs.monster.raider;
+
+import me.tofaa.entitylib.meta.Metadata;
+
+public class PillagerMeta extends RaiderMeta{
+
+    public static final byte OFFSET = RaiderMeta.MAX_OFFSET;
+    public static final byte MAX_OFFSET = OFFSET + 0;
+
+
+    public PillagerMeta(int entityId, Metadata metadata) {
+        super(entityId, metadata);
+    }
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/raider/RaiderMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/raider/RaiderMeta.java
new file mode 100644
index 0000000..563fe01
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/raider/RaiderMeta.java
@@ -0,0 +1,25 @@
+package me.tofaa.entitylib.meta.mobs.monster.raider;
+
+import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
+import me.tofaa.entitylib.meta.Metadata;
+import me.tofaa.entitylib.meta.types.MobMeta;
+
+public class RaiderMeta extends MobMeta {
+
+    public static final byte OFFSET = MobMeta.MAX_OFFSET;
+    public static final byte MAX_OFFSET = OFFSET + 1;
+
+    public RaiderMeta(int entityId, Metadata metadata) {
+        super(entityId, metadata);
+    }
+
+    public boolean isCelebrating() {
+        return super.metadata.getIndex(OFFSET, false);
+    }
+
+    public void setCelebrating(boolean value) {
+        super.metadata.setIndex(OFFSET, EntityDataTypes.BOOLEAN, value);
+    }
+
+
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/raider/RavagerMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/raider/RavagerMeta.java
new file mode 100644
index 0000000..63549a6
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/raider/RavagerMeta.java
@@ -0,0 +1,14 @@
+package me.tofaa.entitylib.meta.mobs.monster.raider;
+
+import me.tofaa.entitylib.meta.Metadata;
+
+public class RavagerMeta extends RaiderMeta {
+
+    public static final byte OFFSET = RaiderMeta.MAX_OFFSET;
+    public static final byte MAX_OFFSET = OFFSET + 0;
+
+
+    public RavagerMeta(int entityId, Metadata metadata) {
+        super(entityId, metadata);
+    }
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/raider/SpellcasterIllagerMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/raider/SpellcasterIllagerMeta.java
new file mode 100644
index 0000000..493d361
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/raider/SpellcasterIllagerMeta.java
@@ -0,0 +1,13 @@
+package me.tofaa.entitylib.meta.mobs.monster.raider;
+
+import me.tofaa.entitylib.meta.Metadata;
+
+public class SpellcasterIllagerMeta extends RaiderMeta{
+
+    public static final byte OFFSET = RaiderMeta.MAX_OFFSET;
+    public static final byte MAX_OFFSET = OFFSET + 1;
+
+    public SpellcasterIllagerMeta(int entityId, Metadata metadata) {
+        super(entityId, metadata);
+    }
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/raider/VindicatorMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/raider/VindicatorMeta.java
new file mode 100644
index 0000000..ee79027
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/raider/VindicatorMeta.java
@@ -0,0 +1,13 @@
+package me.tofaa.entitylib.meta.mobs.monster.raider;
+
+import me.tofaa.entitylib.meta.Metadata;
+
+public class VindicatorMeta extends RaiderMeta{
+
+    public static final byte OFFSET = RaiderMeta.MAX_OFFSET;
+    public static final byte MAX_OFFSET = OFFSET + 0;
+
+    public VindicatorMeta(int entityId, Metadata metadata) {
+        super(entityId, metadata);
+    }
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/raider/WitchMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/raider/WitchMeta.java
new file mode 100644
index 0000000..808d8fd
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/raider/WitchMeta.java
@@ -0,0 +1,23 @@
+package me.tofaa.entitylib.meta.mobs.monster.raider;
+
+import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
+import me.tofaa.entitylib.meta.Metadata;
+
+public class WitchMeta extends RaiderMeta {
+
+    public static final byte OFFSET = RaiderMeta.MAX_OFFSET;
+    public static final byte MAX_OFFSET = OFFSET + 1;
+
+    public WitchMeta(int entityId, Metadata metadata) {
+        super(entityId, metadata);
+    }
+
+    public boolean isDrinkingPotion() {
+        return super.metadata.getIndex(OFFSET, false);
+    }
+
+    public void setDrinkingPotion(boolean value) {
+        super.metadata.setIndex(OFFSET, EntityDataTypes.BOOLEAN, value);
+    }
+
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/skeleton/SkeletonMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/skeleton/SkeletonMeta.java
new file mode 100644
index 0000000..d675179
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/skeleton/SkeletonMeta.java
@@ -0,0 +1,14 @@
+package me.tofaa.entitylib.meta.mobs.monster.skeleton;
+
+import me.tofaa.entitylib.meta.Metadata;
+import me.tofaa.entitylib.meta.types.MobMeta;
+
+public class SkeletonMeta extends MobMeta {
+
+    public static final byte OFFSET = MobMeta.MAX_OFFSET;
+    public static final byte MAX_OFFSET = OFFSET + 0;
+
+    public SkeletonMeta(int entityId, Metadata metadata) {
+        super(entityId, metadata);
+    }
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/skeleton/StrayMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/skeleton/StrayMeta.java
new file mode 100644
index 0000000..a514fde
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/skeleton/StrayMeta.java
@@ -0,0 +1,11 @@
+package me.tofaa.entitylib.meta.mobs.monster.skeleton;
+
+import me.tofaa.entitylib.meta.Metadata;
+
+public class StrayMeta extends SkeletonMeta{
+
+
+    public StrayMeta(int entityId, Metadata metadata) {
+        super(entityId, metadata);
+    }
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/skeleton/WitherSkeletonMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/skeleton/WitherSkeletonMeta.java
new file mode 100644
index 0000000..9d6e9ea
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/skeleton/WitherSkeletonMeta.java
@@ -0,0 +1,12 @@
+package me.tofaa.entitylib.meta.mobs.monster.skeleton;
+
+import me.tofaa.entitylib.meta.Metadata;
+
+public class WitherSkeletonMeta extends SkeletonMeta {
+    public static final byte OFFSET = SkeletonMeta.MAX_OFFSET;
+    public static final byte MAX_OFFSET = OFFSET + 0;
+
+    public WitherSkeletonMeta(int entityId, Metadata metadata) {
+        super(entityId, metadata);
+    }
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/zombie/DrownedMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/zombie/DrownedMeta.java
new file mode 100644
index 0000000..1c07800
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/zombie/DrownedMeta.java
@@ -0,0 +1,12 @@
+package me.tofaa.entitylib.meta.mobs.monster.zombie;
+
+import me.tofaa.entitylib.meta.Metadata;
+
+public class DrownedMeta extends ZombieMeta {
+
+    public static final byte OFFSET = ZombieMeta.MAX_OFFSET;
+    public static final byte MAX_OFFSET = OFFSET + 0;
+    public DrownedMeta(int entityId, Metadata metadata) {
+        super(entityId, metadata);
+    }
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/zombie/HuskMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/zombie/HuskMeta.java
new file mode 100644
index 0000000..f986fca
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/zombie/HuskMeta.java
@@ -0,0 +1,13 @@
+package me.tofaa.entitylib.meta.mobs.monster.zombie;
+
+import me.tofaa.entitylib.meta.Metadata;
+
+public class HuskMeta extends ZombieMeta {
+
+    public static final byte OFFSET = ZombieMeta.MAX_OFFSET;
+    public static final byte MAX_OFFSET = OFFSET + 0;
+
+    public HuskMeta(int entityId, Metadata metadata) {
+        super(entityId, metadata);
+    }
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/zombie/ZombieMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/zombie/ZombieMeta.java
new file mode 100644
index 0000000..856d907
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/zombie/ZombieMeta.java
@@ -0,0 +1,35 @@
+package me.tofaa.entitylib.meta.mobs.monster.zombie;
+
+import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
+import me.tofaa.entitylib.meta.Metadata;
+import me.tofaa.entitylib.meta.types.MobMeta;
+
+public class ZombieMeta extends MobMeta {
+
+    public static final byte OFFSET = MobMeta.MAX_OFFSET;
+    public static final byte MAX_OFFSET = OFFSET + 3;
+
+    public ZombieMeta(int entityId, Metadata metadata) {
+        super(entityId, metadata);
+    }
+
+    public boolean isBaby() {
+        return super.metadata.getIndex(OFFSET, false);
+    }
+
+    public void setBaby(boolean value) {
+        if (isBaby() == value) {
+            return;
+        }
+        super.metadata.setIndex(OFFSET, EntityDataTypes.BOOLEAN, value);
+    }
+
+    public boolean isBecomingDrowned() {
+        return super.metadata.getIndex(offset(OFFSET, 2), false);
+    }
+
+    public void setBecomingDrowned(boolean value) {
+        super.metadata.setIndex(offset(OFFSET, 2), EntityDataTypes.BOOLEAN, value);
+    }
+
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/zombie/ZombieVillagerMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/zombie/ZombieVillagerMeta.java
new file mode 100644
index 0000000..c7416c5
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/zombie/ZombieVillagerMeta.java
@@ -0,0 +1,43 @@
+package me.tofaa.entitylib.meta.mobs.monster.zombie;
+
+import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
+import com.github.retrooper.packetevents.protocol.entity.villager.VillagerData;
+import com.github.retrooper.packetevents.protocol.entity.villager.profession.VillagerProfessions;
+import com.github.retrooper.packetevents.protocol.entity.villager.type.VillagerTypes;
+import me.tofaa.entitylib.meta.Metadata;
+import me.tofaa.entitylib.meta.mobs.villager.VillagerMeta;
+
+public class ZombieVillagerMeta extends ZombieMeta {
+
+    public static final byte OFFSET = ZombieMeta.MAX_OFFSET;
+    public static final byte MAX_OFFSET = OFFSET + 2;
+
+    public ZombieVillagerMeta(int entityId, Metadata metadata) {
+        super(entityId, metadata);
+    }
+
+    public boolean isConverting() {
+        return super.metadata.getIndex(OFFSET, false);
+    }
+
+    public void setConverting(boolean value) {
+        super.metadata.setIndex(OFFSET, EntityDataTypes.BOOLEAN, value);
+    }
+
+    public VillagerData getVillagerData() {
+        int[] data = super.metadata.getIndex(offset(OFFSET, 1), null);
+        if (data == null) {
+            return new VillagerData(VillagerTypes.PLAINS, VillagerProfessions.NONE, VillagerMeta.Level.NOVICE.ordinal());
+        }
+        return new VillagerData(VillagerMeta.TYPES[data[0]], VillagerMeta.PROFESSIONS[data[1]], VillagerMeta.Level.VALUES[data[2] - 1].ordinal());
+    }
+
+    public void setVillagerData(VillagerData data) {
+        super.metadata.setIndex(offset(OFFSET, 1), EntityDataTypes.VILLAGER_DATA, new VillagerData(
+                data.getType().getId(),
+                data.getProfession().getId(),
+                data.getLevel() + 1
+        ));
+    }
+
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/zombie/ZombifiedPiglinMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/zombie/ZombifiedPiglinMeta.java
new file mode 100644
index 0000000..f6794e5
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/mobs/monster/zombie/ZombifiedPiglinMeta.java
@@ -0,0 +1,13 @@
+package me.tofaa.entitylib.meta.mobs.monster.zombie;
+
+import me.tofaa.entitylib.meta.Metadata;
+
+public class ZombifiedPiglinMeta extends ZombieMeta {
+
+    public static final byte OFFSET = ZombieMeta.MAX_OFFSET;
+    public static final byte MAX_OFFSET = OFFSET + 0;
+
+    public ZombifiedPiglinMeta(int entityId, Metadata metadata) {
+        super(entityId, metadata);
+    }
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/mobs/passive/ChickenMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/mobs/passive/ChickenMeta.java
new file mode 100644
index 0000000..a410b29
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/mobs/passive/ChickenMeta.java
@@ -0,0 +1,14 @@
+package me.tofaa.entitylib.meta.mobs.passive;
+
+import me.tofaa.entitylib.meta.Metadata;
+import me.tofaa.entitylib.meta.types.AgeableMeta;
+
+public class ChickenMeta extends AgeableMeta {
+
+    public static final byte OFFSET = AgeableMeta.MAX_OFFSET;
+    public static final byte MAX_OFFSET = OFFSET + 0;
+
+    public ChickenMeta(int entityId, Metadata metadata) {
+        super(entityId, metadata);
+    }
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/mobs/passive/CowMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/mobs/passive/CowMeta.java
new file mode 100644
index 0000000..135162b
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/mobs/passive/CowMeta.java
@@ -0,0 +1,14 @@
+package me.tofaa.entitylib.meta.mobs.passive;
+
+import me.tofaa.entitylib.meta.Metadata;
+import me.tofaa.entitylib.meta.types.AgeableMeta;
+
+public class CowMeta extends AgeableMeta {
+
+    public static final byte OFFSET = AgeableMeta.MAX_OFFSET;
+    public static final byte MAX_OFFSET = OFFSET + 0;
+
+    public CowMeta(int entityId, Metadata metadata) {
+        super(entityId, metadata);
+    }
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/mobs/passive/MooshroomMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/mobs/passive/MooshroomMeta.java
new file mode 100644
index 0000000..074763a
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/mobs/passive/MooshroomMeta.java
@@ -0,0 +1,33 @@
+package me.tofaa.entitylib.meta.mobs.passive;
+
+import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
+import me.tofaa.entitylib.meta.Metadata;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Locale;
+
+public class MooshroomMeta extends CowMeta{
+
+    public static final byte OFFSET = CowMeta.MAX_OFFSET;
+    public static final byte MAX_OFFSET = OFFSET + 1;
+
+    public MooshroomMeta(int entityId, Metadata metadata) {
+        super(entityId, metadata);
+    }
+
+    @NotNull
+    public Variant getVariant() {
+        return Variant.valueOf(super.metadata.getIndex(OFFSET, "red").toUpperCase(Locale.ROOT));
+    }
+
+    public void setVariant(@NotNull Variant value) {
+        super.metadata.setIndex(OFFSET, EntityDataTypes.STRING, value.name().toLowerCase(Locale.ROOT));
+    }
+
+    public enum Variant {
+        RED,
+        BROWN
+    }
+
+
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/mobs/passive/PigMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/mobs/passive/PigMeta.java
new file mode 100644
index 0000000..86f973c
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/mobs/passive/PigMeta.java
@@ -0,0 +1,34 @@
+package me.tofaa.entitylib.meta.mobs.passive;
+
+import com.github.retrooper.packetevents.manager.server.ServerVersion;
+import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
+import me.tofaa.entitylib.meta.Metadata;
+import me.tofaa.entitylib.meta.types.AgeableMeta;
+
+public class PigMeta extends AgeableMeta {
+
+    public static final byte OFFSET = AgeableMeta.MAX_OFFSET;
+    public static final byte MAX_OFFSET = OFFSET + 2;
+
+    public PigMeta(int entityId, Metadata metadata) {
+        super(entityId, metadata);
+    }
+
+    public boolean hasSaddle() {
+        return super.metadata.getIndex(OFFSET, false);
+    }
+
+    public void setHasSaddle(boolean value) {
+        super.metadata.setIndex(OFFSET, EntityDataTypes.BOOLEAN, value);
+    }
+
+    public int getTimeToBoost() {
+        isVersionNewer(ServerVersion.V_1_16);
+        return super.metadata.getIndex(offset(OFFSET,1), 0);
+    }
+
+    public void setTimeToBoost(int value) {
+        isVersionNewer(ServerVersion.V_1_16);
+        super.metadata.setIndex(offset(OFFSET,1), EntityDataTypes.INT, value);
+    }
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/mobs/passive/RabbitMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/mobs/passive/RabbitMeta.java
new file mode 100644
index 0000000..2e3c68b
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/mobs/passive/RabbitMeta.java
@@ -0,0 +1,46 @@
+package me.tofaa.entitylib.meta.mobs.passive;
+
+import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
+import me.tofaa.entitylib.meta.Metadata;
+import me.tofaa.entitylib.meta.types.AgeableMeta;
+import org.jetbrains.annotations.NotNull;
+
+public class RabbitMeta extends AgeableMeta {
+
+    public static final byte OFFSET = AgeableMeta.MAX_OFFSET;
+    public static final byte MAX_OFFSET = OFFSET + 1;
+
+
+    public RabbitMeta(int entityId, Metadata metadata) {
+        super(entityId, metadata);
+    }
+
+    public @NotNull Type getType() {
+        int id = super.metadata.getIndex(OFFSET, 0);
+        if (id == 99) {
+            return Type.KILLER_BUNNY;
+        }
+        return Type.VALUES[id];
+    }
+
+    public void setType(@NotNull Type value) {
+        int id = value == Type.KILLER_BUNNY ? 99 : value.ordinal();
+        super.metadata.setIndex(OFFSET, EntityDataTypes.INT, id);
+    }
+
+
+    public enum Type {
+        BROWN,
+        WHITE,
+        BLACK,
+        BLACK_AND_WHITE,
+        GOLD,
+        SALT_AND_PEPPER,
+        KILLER_BUNNY;
+
+        private final static Type[] VALUES = values();
+    }
+
+
+
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/mobs/passive/SheepMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/mobs/passive/SheepMeta.java
new file mode 100644
index 0000000..00f7505
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/mobs/passive/SheepMeta.java
@@ -0,0 +1,43 @@
+package me.tofaa.entitylib.meta.mobs.passive;
+
+import me.tofaa.entitylib.meta.Metadata;
+import me.tofaa.entitylib.meta.types.AgeableMeta;
+
+public class SheepMeta extends AgeableMeta {
+
+    public static final byte OFFSET = AgeableMeta.MAX_OFFSET;
+    public static final byte MAX_OFFSET = OFFSET + 1;
+
+
+    private final static byte COLOR_BITS = 0x0F;
+    private final static byte SHEARED_BIT = 0x10;
+
+    public SheepMeta(int entityId, Metadata metadata) {
+        super(entityId, metadata);
+    }
+
+    public int getColor() {
+        return getMask(OFFSET) & COLOR_BITS;
+    }
+
+    public void setColor(byte color) {
+        byte before = getMask(OFFSET);
+        byte mask = before;
+        mask &= ~COLOR_BITS;
+        mask |= (color & COLOR_BITS);
+        if (mask != before) {
+            setMask(OFFSET, mask);
+        }
+    }
+
+    public boolean isSheared() {
+        return getMaskBit(OFFSET, SHEARED_BIT);
+    }
+
+    public void setSheared(boolean value) {
+        setMaskBit(OFFSET, SHEARED_BIT, value);
+    }
+
+
+
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/mobs/passive/TurtleMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/mobs/passive/TurtleMeta.java
new file mode 100644
index 0000000..136be80
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/mobs/passive/TurtleMeta.java
@@ -0,0 +1,66 @@
+package me.tofaa.entitylib.meta.mobs.passive;
+
+import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
+import com.github.retrooper.packetevents.util.Vector3i;
+import me.tofaa.entitylib.meta.Metadata;
+import me.tofaa.entitylib.meta.types.AgeableMeta;
+
+public class TurtleMeta extends AgeableMeta {
+
+    public static final byte OFFSET = AgeableMeta.MAX_OFFSET;
+    public static final byte MAX_OFFSET = OFFSET + 6;
+
+    public TurtleMeta(int entityId, Metadata metadata) {
+        super(entityId, metadata);
+    }
+
+
+    public Vector3i getHomePosition() {
+        return super.metadata.getIndex(OFFSET, Vector3i.zero());
+    }
+
+    public void setBlockPosition(Vector3i value) {
+        super.metadata.setIndex(OFFSET, EntityDataTypes.BLOCK_POSITION, value);
+    }
+
+    public boolean hasEgg() {
+        return super.metadata.getIndex(offset(OFFSET,1), false);
+    }
+
+    public void setHasEgg(boolean value) {
+        super.metadata.setIndex(offset(OFFSET,1), EntityDataTypes.BOOLEAN, value);
+    }
+
+    public boolean isLayingEgg() {
+        return super.metadata.getIndex(offset(OFFSET,2), false);
+    }
+
+    public void setLayingEgg(boolean value) {
+        super.metadata.setIndex(offset(OFFSET,2), EntityDataTypes.BOOLEAN, value);
+    }
+
+    public  Vector3i getTravelPosition() {
+        return super.metadata.getIndex(offset(OFFSET,3), Vector3i.zero());
+    }
+
+    public void setTravelPosition(Vector3i value) {
+        super.metadata.setIndex(offset(OFFSET,3), EntityDataTypes.BLOCK_POSITION, value);
+    }
+
+    public boolean isGoingHome() {
+        return super.metadata.getIndex(offset(OFFSET,4), false);
+    }
+
+    public void setGoingHome(boolean value) {
+        super.metadata.setIndex(offset(OFFSET,4), EntityDataTypes.BOOLEAN, value);
+    }
+
+    public boolean isTravelling() {
+        return super.metadata.getIndex(offset(OFFSET,5), false);
+    }
+
+    public void setTravelling(boolean value) {
+        super.metadata.setIndex(offset(OFFSET,4), EntityDataTypes.BOOLEAN, value);
+    }
+
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/mobs/tameable/CatMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/mobs/tameable/CatMeta.java
new file mode 100644
index 0000000..2dde774
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/mobs/tameable/CatMeta.java
@@ -0,0 +1,72 @@
+package me.tofaa.entitylib.meta.mobs.tameable;
+
+import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
+import com.github.retrooper.packetevents.protocol.entity.type.EntityTypes;
+import me.tofaa.entitylib.extras.DyeColor;
+import me.tofaa.entitylib.meta.Metadata;
+import me.tofaa.entitylib.meta.types.TameableMeta;
+import net.kyori.adventure.text.format.NamedTextColor;
+import org.jetbrains.annotations.NotNull;
+
+public class CatMeta extends TameableMeta {
+
+    public static final byte OFFSET = TameableMeta.MAX_OFFSET;
+    public static final byte MAX_OFFSET = OFFSET + 4;
+
+    private static final DyeColor[] COLORS = DyeColor.values();
+
+    public CatMeta(int entityId, Metadata metadata) {
+        super(entityId, metadata);
+    }
+
+    @NotNull
+    public CatMeta.Variant getVariant() {
+        return super.metadata.getIndex(OFFSET, Variant.BLACK);
+    }
+
+    public void setVariant(@NotNull CatMeta.Variant value) {
+        super.metadata.setIndex(OFFSET, EntityDataTypes.CAT_VARIANT, value.ordinal());
+    }
+
+    public boolean isLying() {
+        return super.metadata.getIndex(offset(OFFSET, 1), false);
+    }
+
+    public void setLying(boolean value) {
+        super.metadata.setIndex(offset(OFFSET, 1), EntityDataTypes.BOOLEAN, value);
+    }
+
+    public boolean isRelaxed() {
+        return super.metadata.getIndex(offset(OFFSET, 2), false);
+    }
+
+    public void setRelaxed(boolean value) {
+        super.metadata.setIndex(offset(OFFSET, 2), EntityDataTypes.BOOLEAN, value);
+    }
+
+    public @NotNull DyeColor getCollarColor() {
+        return COLORS[super.metadata.getIndex(offset(OFFSET, 3), DyeColor.RED.ordinal())];
+    }
+
+    public void setCollarColor(@NotNull DyeColor value) {
+        super.metadata.setIndex(offset(OFFSET, 3), EntityDataTypes.INT, value.ordinal());
+    }
+
+
+    public enum Variant {
+        TABBY,
+        BLACK,
+        RED,
+        SIAMESE,
+        BRITISH_SHORTHAIR,
+        CALICO,
+        PERSIAN,
+        RAGDOLL,
+        WHITE,
+        JELLIE,
+        ALL_BLACK;
+
+        private static final Variant[] VALUES = values();
+    }
+
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/mobs/tameable/ParrotMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/mobs/tameable/ParrotMeta.java
new file mode 100644
index 0000000..6e62668
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/mobs/tameable/ParrotMeta.java
@@ -0,0 +1,38 @@
+package me.tofaa.entitylib.meta.mobs.tameable;
+
+import com.github.retrooper.packetevents.manager.server.ServerVersion;
+import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
+import me.tofaa.entitylib.meta.Metadata;
+import me.tofaa.entitylib.meta.types.TameableMeta;
+import org.jetbrains.annotations.NotNull;
+
+public class ParrotMeta extends TameableMeta {
+
+    public static final byte OFFSET = TameableMeta.MAX_OFFSET;
+    public static final byte MAX_OFFSET = OFFSET + 1;
+
+    public ParrotMeta(int entityId, Metadata metadata) {
+        super(entityId, metadata);
+        isVersionNewer(ServerVersion.V_1_14);
+    }
+
+    @NotNull
+    public Color getColor() {
+        return Color.VALUES[super.metadata.getIndex(OFFSET, 0)];
+    }
+
+    public void setColor(@NotNull Color value) {
+        super.metadata.setIndex(OFFSET, EntityDataTypes.INT, value.ordinal());
+    }
+
+    public enum Color {
+        RED_BLUE,
+        BLUE,
+        GREEN,
+        YELLOW_BLUE,
+        GREY;
+
+        private final static Color[] VALUES = values();
+    }
+
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/mobs/tameable/WolfMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/mobs/tameable/WolfMeta.java
new file mode 100644
index 0000000..e051e6f
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/mobs/tameable/WolfMeta.java
@@ -0,0 +1,40 @@
+package me.tofaa.entitylib.meta.mobs.tameable;
+
+import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
+import me.tofaa.entitylib.meta.Metadata;
+import me.tofaa.entitylib.meta.types.TameableMeta;
+
+public class WolfMeta extends TameableMeta {
+
+    public static final byte OFFSET = TameableMeta.MAX_OFFSET;
+    public static final byte MAX_OFFSET = OFFSET + 3;
+
+    public WolfMeta(int entityId, Metadata metadata) {
+        super(entityId, metadata);
+    }
+
+    public boolean isBegging() {
+        return super.metadata.getIndex(OFFSET, false);
+    }
+
+    public void setBegging(boolean value) {
+        super.metadata.setIndex(OFFSET, EntityDataTypes.BOOLEAN, value);
+    }
+
+    public int getCollarColor() {
+        return super.metadata.getIndex(offset(OFFSET, 1), 14);
+    }
+
+    public void setCollarColor(int value) {
+        super.metadata.setIndex(offset(OFFSET, 1), EntityDataTypes.INT, value);
+    }
+
+    public int getAngerTime() {
+        return super.metadata.getIndex(offset(OFFSET, 2), 0);
+    }
+
+    public void setAngerTime(int value) {
+        super.metadata.setIndex(offset(OFFSET, 2), EntityDataTypes.INT, value);
+    }
+
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/mobs/villager/BaseVillagerMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/mobs/villager/BaseVillagerMeta.java
new file mode 100644
index 0000000..c5a24fc
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/mobs/villager/BaseVillagerMeta.java
@@ -0,0 +1,24 @@
+package me.tofaa.entitylib.meta.mobs.villager;
+
+import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
+import me.tofaa.entitylib.meta.Metadata;
+import me.tofaa.entitylib.meta.types.AgeableMeta;
+
+public class BaseVillagerMeta extends AgeableMeta {
+
+    public static final byte OFFSET = AgeableMeta.MAX_OFFSET;
+    public static final byte MAX_OFFSET = OFFSET + 1;
+
+    public BaseVillagerMeta(int entityId, Metadata metadata) {
+        super(entityId, metadata);
+    }
+
+    public int getHeadShakeTimer() {
+        return super.metadata.getIndex(OFFSET, 0);
+    }
+
+    public void setHeadShakeTimer(int value) {
+        super.metadata.setIndex(OFFSET, EntityDataTypes.INT, value);
+    }
+
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/mobs/villager/VillagerMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/mobs/villager/VillagerMeta.java
new file mode 100644
index 0000000..37011fa
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/mobs/villager/VillagerMeta.java
@@ -0,0 +1,81 @@
+package me.tofaa.entitylib.meta.mobs.villager;
+
+import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
+import com.github.retrooper.packetevents.protocol.entity.villager.VillagerData;
+import com.github.retrooper.packetevents.protocol.entity.villager.profession.VillagerProfession;
+import com.github.retrooper.packetevents.protocol.entity.villager.profession.VillagerProfessions;
+import com.github.retrooper.packetevents.protocol.entity.villager.type.VillagerType;
+import com.github.retrooper.packetevents.protocol.entity.villager.type.VillagerTypes;
+import me.tofaa.entitylib.meta.Metadata;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+
+public class VillagerMeta extends BaseVillagerMeta {
+
+    public static final byte OFFSET = BaseVillagerMeta.MAX_OFFSET;
+    public static final byte MAX_OFFSET = OFFSET + 1;
+
+    @ApiStatus.Internal
+    public static final VillagerType[] TYPES = new VillagerType[] {
+            VillagerTypes.DESERT,
+            VillagerTypes.JUNGLE,
+            VillagerTypes.PLAINS,
+            VillagerTypes.SAVANNA,
+            VillagerTypes.SNOW,
+            VillagerTypes.SWAMP,
+            VillagerTypes.TAIGA
+    };
+
+    @ApiStatus.Internal
+    public static final VillagerProfession[] PROFESSIONS = new VillagerProfession[] {
+            VillagerProfessions.NONE,
+            VillagerProfessions.ARMORER,
+            VillagerProfessions.BUTCHER,
+            VillagerProfessions.CARTOGRAPHER,
+            VillagerProfessions.CLERIC,
+            VillagerProfessions.FARMER,
+            VillagerProfessions.FISHERMAN,
+            VillagerProfessions.FLETCHER,
+            VillagerProfessions.LEATHERWORKER,
+            VillagerProfessions.LIBRARIAN,
+            VillagerProfessions.MASON,
+            VillagerProfessions.NITWIT,
+            VillagerProfessions.SHEPHERD,
+            VillagerProfessions.TOOLSMITH,
+            VillagerProfessions.WEAPONSMITH
+    };
+
+    public VillagerMeta(int entityId, Metadata metadata) {
+        super(entityId, metadata);
+    }
+
+    @NotNull
+    public VillagerData getVillagerData() {
+        int[] data = super.metadata.getIndex(OFFSET, null);
+        if (data == null) {
+            return new VillagerData(VillagerTypes.PLAINS, VillagerProfessions.NONE, Level.NOVICE.ordinal());
+        }
+        return new VillagerData(TYPES[data[0]], PROFESSIONS[data[1]], Level.VALUES[data[2] - 1].ordinal());
+    }
+
+    public void setVillagerData(@NotNull VillagerData data) {
+        super.metadata.setIndex(OFFSET, EntityDataTypes.VILLAGER_DATA, new VillagerData(
+                data.getType().getId(),
+                data.getProfession().getId(),
+                data.getLevel()
+        ));
+    }
+
+
+    public enum Level {
+        NOVICE,
+        APPRENTICE,
+        JOURNEYMAN,
+        EXPERT,
+        MASTER;
+
+        public final static Level[] VALUES = values();
+    }
+
+
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/mobs/villager/WanderingTraderMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/mobs/villager/WanderingTraderMeta.java
new file mode 100644
index 0000000..7ce92d5
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/mobs/villager/WanderingTraderMeta.java
@@ -0,0 +1,13 @@
+package me.tofaa.entitylib.meta.mobs.villager;
+
+import me.tofaa.entitylib.meta.Metadata;
+
+public class WanderingTraderMeta extends VillagerMeta{
+
+    public static final byte OFFSET = VillagerMeta.MAX_OFFSET;
+    public static final byte MAX_OFFSET = OFFSET + 0;
+
+    public WanderingTraderMeta(int entityId, Metadata metadata) {
+        super(entityId, metadata);
+    }
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/mobs/water/AxolotlMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/mobs/water/AxolotlMeta.java
new file mode 100644
index 0000000..74b1a6f
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/mobs/water/AxolotlMeta.java
@@ -0,0 +1,50 @@
+package me.tofaa.entitylib.meta.mobs.water;
+
+import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
+import me.tofaa.entitylib.meta.Metadata;
+import me.tofaa.entitylib.meta.types.WaterMobMeta;
+
+public class AxolotlMeta extends WaterMobMeta {
+
+    public static final byte OFFSET = WaterMobMeta.MAX_OFFSET;
+    public static final byte MAX_OFFSET = OFFSET + 3;
+
+    public AxolotlMeta(int entityId, Metadata metadata) {
+        super(entityId, metadata);
+    }
+
+    public Variant getVariant() {
+        return Variant.VALUES[super.metadata.getIndex(OFFSET, 0)];
+    }
+
+    public void setVariant(Variant variant) {
+        metadata.setIndex(OFFSET, EntityDataTypes.INT, variant.ordinal());
+    }
+
+    public boolean isPlayingDead() {
+        return metadata.getIndex(offset(OFFSET, 1), false);
+    }
+
+    public void setPlayingDead(boolean playingDead) {
+        metadata.setIndex(offset(OFFSET, 1), EntityDataTypes.BOOLEAN, playingDead);
+    }
+
+    public boolean isFromBucket() {
+        return metadata.getIndex(offset(OFFSET, 2), false);
+    }
+
+    public void setFromBucket(boolean fromBucket) {
+        metadata.setIndex(offset(OFFSET, 2), EntityDataTypes.BOOLEAN, fromBucket);
+    }
+
+    public enum Variant {
+        LUCY,
+        WILD,
+        GOLD,
+        CYAN,
+        BLUE;
+
+        private final static AxolotlMeta.Variant[] VALUES = values();
+    }
+
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/mobs/water/BaseFishMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/mobs/water/BaseFishMeta.java
new file mode 100644
index 0000000..76e3f7a
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/mobs/water/BaseFishMeta.java
@@ -0,0 +1,25 @@
+package me.tofaa.entitylib.meta.mobs.water;
+
+import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
+import me.tofaa.entitylib.meta.Metadata;
+import me.tofaa.entitylib.meta.types.WaterMobMeta;
+
+public class BaseFishMeta extends WaterMobMeta {
+
+    public static final byte OFFSET = WaterMobMeta.MAX_OFFSET;
+    public static final byte MAX_OFFSET = OFFSET + 1;
+
+    public BaseFishMeta(int entityId, Metadata metadata) {
+        super(entityId, metadata);
+    }
+
+
+    public boolean isFromBucket() {
+        return super.metadata.getIndex(OFFSET, false);
+    }
+
+    public void setFromBucket(boolean value) {
+        super.metadata.setIndex(OFFSET, EntityDataTypes.BOOLEAN, value);
+    }
+
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/mobs/water/CodMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/mobs/water/CodMeta.java
new file mode 100644
index 0000000..fc5ce2d
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/mobs/water/CodMeta.java
@@ -0,0 +1,13 @@
+package me.tofaa.entitylib.meta.mobs.water;
+
+import me.tofaa.entitylib.meta.Metadata;
+
+public class CodMeta extends BaseFishMeta{
+
+    public static final byte OFFSET = BaseFishMeta.MAX_OFFSET;
+    public static final byte MAX_OFFSET = OFFSET + 0;
+
+    public CodMeta(int entityId, Metadata metadata) {
+        super(entityId, metadata);
+    }
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/mobs/water/DolphinMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/mobs/water/DolphinMeta.java
new file mode 100644
index 0000000..c875e1d
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/mobs/water/DolphinMeta.java
@@ -0,0 +1,43 @@
+package me.tofaa.entitylib.meta.mobs.water;
+
+import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
+import com.github.retrooper.packetevents.util.Vector3i;
+import me.tofaa.entitylib.meta.Metadata;
+import me.tofaa.entitylib.meta.types.WaterMobMeta;
+import org.jetbrains.annotations.NotNull;
+
+public class DolphinMeta extends WaterMobMeta {
+
+    public static final byte OFFSET = WaterMobMeta.MAX_OFFSET;
+    public static final byte MAX_OFFSET = OFFSET + 3;
+
+    public DolphinMeta(int entityId, Metadata metadata) {
+        super(entityId, metadata);
+    }
+
+    @NotNull
+    public Vector3i getTreasurePosition() {
+        return super.metadata.getIndex(OFFSET, Vector3i.zero());
+    }
+
+    public void setTreasurePosition(@NotNull Vector3i value) {
+        super.metadata.setIndex(OFFSET, EntityDataTypes.BLOCK_POSITION, value);
+    }
+
+    public boolean isCanFindTreasure() {
+        return super.metadata.getIndex(offset(OFFSET, 1), false);
+    }
+
+    public void setCanFindTreasure(boolean value) {
+        super.metadata.setIndex(offset(OFFSET, 1), EntityDataTypes.BOOLEAN, value);
+    }
+
+    public boolean isHasFish() {
+        return super.metadata.getIndex(offset(OFFSET, 2), false);
+    }
+
+    public void setHasFish(boolean value) {
+        super.metadata.setIndex(offset(OFFSET, 2), EntityDataTypes.BOOLEAN, value);
+    }
+
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/mobs/water/GlowSquidMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/mobs/water/GlowSquidMeta.java
new file mode 100644
index 0000000..d6115b4
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/mobs/water/GlowSquidMeta.java
@@ -0,0 +1,24 @@
+package me.tofaa.entitylib.meta.mobs.water;
+
+import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
+import me.tofaa.entitylib.meta.Metadata;
+
+public class GlowSquidMeta extends SquidMeta {
+
+    public static final byte OFFSET = SquidMeta.MAX_OFFSET;
+    public static final byte MAX_OFFSET = OFFSET + 1;
+
+    public GlowSquidMeta(int entityId, Metadata metadata) {
+        super(entityId, metadata);
+    }
+
+    public int getDarkTicksRemaining() {
+        return metadata.getIndex(OFFSET, 0);
+    }
+
+    public void setDarkTicksRemaining(int ticks) {
+        metadata.setIndex(OFFSET, EntityDataTypes.INT, ticks);
+    }
+
+
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/mobs/water/PufferFishMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/mobs/water/PufferFishMeta.java
new file mode 100644
index 0000000..84180e9
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/mobs/water/PufferFishMeta.java
@@ -0,0 +1,32 @@
+package me.tofaa.entitylib.meta.mobs.water;
+
+import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
+import me.tofaa.entitylib.meta.Metadata;
+
+public class PufferFishMeta extends BaseFishMeta {
+
+    public static final byte OFFSET = BaseFishMeta.MAX_OFFSET;
+    public static final byte MAX_OFFSET = OFFSET + 1;
+
+    public PufferFishMeta(int entityId, Metadata metadata) {
+        super(entityId, metadata);
+    }
+
+    public State getState() {
+        return State.VALUES[super.metadata.getIndex(OFFSET, 0)];
+    }
+
+    public void setState(State state) {
+        super.metadata.setIndex(OFFSET, EntityDataTypes.INT, state.ordinal());
+    }
+
+
+    public enum State {
+        UNPUFFED,
+        SEMI_PUFFED,
+        FULLY_PUFFED;
+
+        private final static State[] VALUES = values();
+    }
+
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/mobs/water/SalmonMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/mobs/water/SalmonMeta.java
new file mode 100644
index 0000000..2c74f0d
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/mobs/water/SalmonMeta.java
@@ -0,0 +1,9 @@
+package me.tofaa.entitylib.meta.mobs.water;
+
+import me.tofaa.entitylib.meta.Metadata;
+
+public class SalmonMeta extends BaseFishMeta{
+    public SalmonMeta(int entityId, Metadata metadata) {
+        super(entityId, metadata);
+    }
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/mobs/water/SquidMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/mobs/water/SquidMeta.java
new file mode 100644
index 0000000..9c99af2
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/mobs/water/SquidMeta.java
@@ -0,0 +1,14 @@
+package me.tofaa.entitylib.meta.mobs.water;
+
+import me.tofaa.entitylib.meta.Metadata;
+import me.tofaa.entitylib.meta.types.WaterMobMeta;
+
+public class SquidMeta extends WaterMobMeta {
+
+    public static final byte OFFSET = WaterMobMeta.MAX_OFFSET;
+    public static final byte MAX_OFFSET = OFFSET + 0;
+
+    public SquidMeta(int entityId, Metadata metadata) {
+        super(entityId, metadata);
+    }
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/mobs/water/TropicalFishMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/mobs/water/TropicalFishMeta.java
new file mode 100644
index 0000000..1392827
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/mobs/water/TropicalFishMeta.java
@@ -0,0 +1,128 @@
+package me.tofaa.entitylib.meta.mobs.water;
+
+import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
+import me.tofaa.entitylib.meta.Metadata;
+import me.tofaa.entitylib.meta.types.ObjectData;
+import org.jetbrains.annotations.NotNull;
+
+public class TropicalFishMeta extends BaseFishMeta implements ObjectData {
+
+    public static final byte OFFSET = BaseFishMeta.MAX_OFFSET;
+    public static final byte MAX_OFFSET = OFFSET + 1;
+
+    public TropicalFishMeta(int entityId, Metadata metadata) {
+        super(entityId, metadata);
+    }
+
+    public Variant getVariant() {
+        return getVariantFromID(super.metadata.getIndex(OFFSET, 0));
+    }
+
+    public void setVariant(Variant variant) {
+        super.metadata.setIndex(OFFSET, EntityDataTypes.INT, getVariantID(variant));
+    }
+
+    public static int getVariantID(Variant variant) {
+        int id = 0;
+        id |= variant.patternColor;
+        id <<= 8;
+        id |= variant.bodyColor;
+        id <<= 8;
+        id |= variant.pattern.ordinal();
+        id <<= 8;
+        id |= variant.type.ordinal();
+        return id;
+    }
+
+    public static Variant getVariantFromID(int variantID) {
+        Type type = Type.VALUES[variantID & 0xFF];
+        variantID >>= 8;
+        Pattern pattern = Pattern.VALUES[variantID & 0xFF];
+        variantID >>= 8;
+        byte bodyColor = (byte) (variantID & 0xFF);
+        variantID >>= 8;
+        byte patternColor = (byte) (variantID & 0xFF);
+        return new Variant(type, pattern, bodyColor, patternColor);
+    }
+
+    @Override
+    public int getObjectData() {
+        // TODO: returns Entity ID of the owner (???)
+        return 0;
+    }
+
+    @Override
+    public boolean requiresVelocityPacketAtSpawn() {
+        return false;
+    }
+
+    public static class Variant {
+
+        private Type type;
+        private Pattern pattern;
+        private byte bodyColor;
+        private byte patternColor;
+
+        public Variant(@NotNull Type type, @NotNull Pattern pattern, byte bodyColor, byte patternColor) {
+            this.type = type;
+            this.pattern = pattern;
+            this.bodyColor = bodyColor;
+            this.patternColor = patternColor;
+        }
+
+        @NotNull
+        public Type getType() {
+            return this.type;
+        }
+
+        public void setType(@NotNull Type type) {
+            this.type = type;
+        }
+
+        @NotNull
+        public Pattern getPattern() {
+            return this.pattern;
+        }
+
+        public void setPattern(@NotNull Pattern pattern) {
+            this.pattern = pattern;
+        }
+
+        public byte getBodyColor() {
+            return this.bodyColor;
+        }
+
+        public void setBodyColor(byte bodyColor) {
+            this.bodyColor = bodyColor;
+        }
+
+        public byte getPatternColor() {
+            return this.patternColor;
+        }
+
+        public void setPatternColor(byte patternColor) {
+            this.patternColor = patternColor;
+        }
+    }
+
+    public enum Type {
+        SMALL,
+        LARGE,
+        INVISIBLE;
+
+        private final static Type[] VALUES = values();
+    }
+
+    public enum Pattern {
+        KOB, // FLOPPER for LARGE fish
+        SUNSTREAK, // STRIPEY for LARGE fish
+        SNOOPER, // GLITTER for LARGE fish
+        DASHER, // BLOCKFISH for LARGE fish
+        BRINELY, // BETTY for LARGE fish
+        SPOTTY, // CLAYFISH for LARGE fish
+        NONE;
+
+        private final static Pattern[] VALUES = values();
+    }
+
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/other/AreaEffectCloudMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/other/AreaEffectCloudMeta.java
new file mode 100644
index 0000000..19e3564
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/other/AreaEffectCloudMeta.java
@@ -0,0 +1,40 @@
+package me.tofaa.entitylib.meta.other;
+
+import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
+import me.tofaa.entitylib.meta.EntityMeta;
+import me.tofaa.entitylib.meta.Metadata;
+
+public class AreaEffectCloudMeta extends EntityMeta {
+
+    public static final byte OFFSET = EntityMeta.MAX_OFFSET;
+    public static final byte MAX_OFFSET = OFFSET + 4;
+
+    public AreaEffectCloudMeta(int entityId, Metadata metadata) {
+        super(entityId, metadata);
+    }
+
+    public float getRadius() {
+        return super.metadata.getIndex(OFFSET, .5F);
+    }
+
+    public void setRadius(float value) {
+        super.metadata.setIndex(OFFSET, EntityDataTypes.FLOAT, value);
+    }
+
+    public int getColor() {
+        return super.metadata.getIndex(offset(OFFSET, 1), 0);
+    }
+
+    public void setColor(int value) {
+        super.metadata.setIndex(offset(OFFSET, 1), EntityDataTypes.INT, value);
+    }
+
+    public boolean isSinglePoint() {
+        return super.metadata.getIndex(offset(OFFSET, 2), false);
+    }
+
+    public void setSinglePoint(boolean value) {
+        super.metadata.setIndex(offset(OFFSET, 2), EntityDataTypes.BOOLEAN, value);
+    }
+
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/other/ArmorStandMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/other/ArmorStandMeta.java
new file mode 100644
index 0000000..75520c9
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/other/ArmorStandMeta.java
@@ -0,0 +1,110 @@
+package me.tofaa.entitylib.meta.other;
+
+import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
+import com.github.retrooper.packetevents.util.Vector3f;
+import me.tofaa.entitylib.meta.Metadata;
+import me.tofaa.entitylib.meta.types.LivingEntityMeta;
+import org.jetbrains.annotations.NotNull;
+
+public class ArmorStandMeta extends LivingEntityMeta {
+
+    public static final byte OFFSET = LivingEntityMeta.MAX_OFFSET;
+    public static final byte MAX_OFFSET = OFFSET + 7;
+
+    private final static byte IS_SMALL_BIT = 0x01;
+    private final static byte HAS_ARMS_BIT = 0x04;
+    private final static byte HAS_NO_BASE_PLATE_BIT = 0x08;
+    private final static byte IS_MARKER_BIT = 0x10;
+
+    public ArmorStandMeta(int entityId, Metadata metadata) {
+        super(entityId, metadata);
+    }
+
+    public boolean isSmall() {
+        return getMaskBit(OFFSET, IS_SMALL_BIT);
+    }
+
+    public void setSmall(boolean value) {
+        setMaskBit(OFFSET, IS_SMALL_BIT, value);
+    }
+
+    public boolean isHasArms() {
+        return getMaskBit(OFFSET, HAS_ARMS_BIT);
+    }
+
+    public void setHasArms(boolean value) {
+        setMaskBit(OFFSET, HAS_ARMS_BIT, value);
+    }
+
+    public boolean isHasNoBasePlate() {
+        return getMaskBit(OFFSET, HAS_NO_BASE_PLATE_BIT);
+    }
+
+    public void setHasNoBasePlate(boolean value) {
+        setMaskBit(OFFSET, HAS_NO_BASE_PLATE_BIT, value);
+    }
+
+    public boolean isMarker() {
+        return getMaskBit(OFFSET, IS_MARKER_BIT);
+    }
+
+    public void setMarker(boolean value) {
+        setMaskBit(OFFSET, IS_MARKER_BIT, value);
+    }
+
+    @NotNull
+    public Vector3f getHeadRotation() {
+        return super.metadata.getIndex(offset(OFFSET, 1), Vector3f.zero());
+    }
+
+    public void setHeadRotation(@NotNull Vector3f value) {
+        super.metadata.setIndex(offset(OFFSET, 1), EntityDataTypes.ROTATION, value);
+    }
+
+    @NotNull
+    public Vector3f getBodyRotation() {
+        return super.metadata.getIndex(offset(OFFSET, 2), Vector3f.zero());
+    }
+
+    public void setBodyRotation(@NotNull Vector3f value) {
+        super.metadata.setIndex(offset(OFFSET, 2), EntityDataTypes.ROTATION, value);
+    }
+
+    @NotNull
+    public Vector3f getLeftArmRotation() {
+        return super.metadata.getIndex(offset(OFFSET, 3), new Vector3f(-10f, 0f, -10f));
+    }
+
+    public void setLeftArmRotation(@NotNull Vector3f value) {
+        super.metadata.setIndex(offset(OFFSET, 3), EntityDataTypes.ROTATION, value);
+    }
+
+    @NotNull
+    public Vector3f getRightArmRotation() {
+        return super.metadata.getIndex(offset(OFFSET, 4), new Vector3f(-15f, 0f, 10f));
+    }
+
+    public void setRightArmRotation(@NotNull Vector3f value) {
+        super.metadata.setIndex(offset(OFFSET, 4), EntityDataTypes.ROTATION, value);
+    }
+
+    @NotNull
+    public Vector3f getLeftLegRotation() {
+        return super.metadata.getIndex(offset(OFFSET, 5), new Vector3f(-1f, 0f, -1f));
+    }
+
+    public void setLeftLegRotation(@NotNull Vector3f value) {
+        super.metadata.setIndex(offset(OFFSET, 5), EntityDataTypes.ROTATION, value);
+    }
+
+    @NotNull
+    public Vector3f getRightLegRotation() {
+        return super.metadata.getIndex(offset(OFFSET, 6), new Vector3f(1f, 0f, 1f));
+    }
+
+    public void setRightLegRotation(@NotNull Vector3f value) {
+        super.metadata.setIndex(offset(OFFSET, 6), EntityDataTypes.ROTATION, value);
+    }
+
+
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/other/BoatMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/other/BoatMeta.java
new file mode 100644
index 0000000..a69efbb
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/other/BoatMeta.java
@@ -0,0 +1,86 @@
+package me.tofaa.entitylib.meta.other;
+
+import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
+import me.tofaa.entitylib.meta.EntityMeta;
+import me.tofaa.entitylib.meta.Metadata;
+import org.jetbrains.annotations.NotNull;
+
+public class BoatMeta extends EntityMeta {
+
+    public static final byte OFFSET = EntityMeta.MAX_OFFSET;
+    public static final byte MAX_OFFSET = OFFSET + 7;
+
+    public BoatMeta(int entityId, Metadata metadata) {
+        super(entityId, metadata);
+    }
+
+    public int getTimeSinceLastHit() {
+        return super.metadata.getIndex(OFFSET, 0);
+    }
+
+    public void setTimeSinceLastHit(int value) {
+        super.metadata.setIndex(OFFSET, EntityDataTypes.INT, value);
+    }
+
+    public int getForwardDirection() {
+        return super.metadata.getIndex(offset(OFFSET, 1), 1);
+    }
+
+    public void setForwardDirection(int value) {
+        super.metadata.setIndex(offset(OFFSET, 1), EntityDataTypes.INT, value);
+    }
+
+    public float getDamageTaken() {
+        return super.metadata.getIndex(offset(OFFSET, 2), 0);
+    }
+
+    public void setDamageTaken(float value) {
+        super.metadata.setIndex(offset(OFFSET, 2), EntityDataTypes.FLOAT, value);
+    }
+
+    @NotNull
+    public Type getType() {
+        return Type.VALUES[super.metadata.getIndex(offset(OFFSET, 3), 0)];
+    }
+
+    public void setType(@NotNull Type value) {
+        super.metadata.setIndex(offset(OFFSET, 3), EntityDataTypes.INT, value.ordinal());
+    }
+
+    public boolean isLeftPaddleTurning() {
+        return super.metadata.getIndex(offset(OFFSET, 4), false);
+    }
+
+    public void setLeftPaddleTurning(boolean value) {
+        super.metadata.setIndex(offset(OFFSET, 4), EntityDataTypes.BOOLEAN, value);
+    }
+
+    public boolean isRightPaddleTurning() {
+        return super.metadata.getIndex(offset(OFFSET, 5), false);
+    }
+
+    public void setRightPaddleTurning(boolean value) {
+        super.metadata.setIndex(offset(OFFSET, 5), EntityDataTypes.BOOLEAN, value);
+    }
+
+    public int getSplashTimer() {
+        return super.metadata.getIndex(offset(OFFSET, 6), 0);
+    }
+
+    public void setSplashTimer(int value) {
+        super.metadata.setIndex(offset(OFFSET, 6), EntityDataTypes.INT, value);
+    }
+
+    public enum Type {
+        OAK,
+        SPRUCE,
+        BIRCH,
+        JUNGLE,
+        ACACIA,
+        DARK_OAK;
+
+        private final static Type[] VALUES = values();
+    }
+
+
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/other/EndCrystalMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/other/EndCrystalMeta.java
new file mode 100644
index 0000000..c7e09f1
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/other/EndCrystalMeta.java
@@ -0,0 +1,36 @@
+package me.tofaa.entitylib.meta.other;
+
+import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
+import com.github.retrooper.packetevents.util.Vector3i;
+import me.tofaa.entitylib.meta.EntityMeta;
+import me.tofaa.entitylib.meta.Metadata;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.Optional;
+
+public class EndCrystalMeta extends EntityMeta {
+
+    public static final byte OFFSET = EntityMeta.MAX_OFFSET;
+    public static final byte MAX_OFFSET = OFFSET + 2;
+
+    public EndCrystalMeta(int entityId, Metadata metadata) {
+        super(entityId, metadata);
+    }
+
+    public @Nullable Optional<Vector3i> getBeamTarget() {
+        return super.metadata.getIndex(OFFSET, Optional.empty());
+    }
+
+    public void setBeamTarget(@Nullable Vector3i value) {
+        super.metadata.setIndex(OFFSET, EntityDataTypes.OPTIONAL_BLOCK_POSITION, Optional.ofNullable(value));
+    }
+
+    public boolean isShowingBottom() {
+        return super.metadata.getIndex(offset(OFFSET, 1), true);
+    }
+
+    public void setShowingBottom(boolean value) {
+        super.metadata.setIndex(offset(OFFSET, 1), EntityDataTypes.BOOLEAN, value);
+    }
+
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/other/EnderDragonMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/other/EnderDragonMeta.java
new file mode 100644
index 0000000..e505bb1
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/other/EnderDragonMeta.java
@@ -0,0 +1,43 @@
+package me.tofaa.entitylib.meta.other;
+
+import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
+import me.tofaa.entitylib.meta.Metadata;
+import me.tofaa.entitylib.meta.types.MobMeta;
+import org.jetbrains.annotations.NotNull;
+
+public class EnderDragonMeta extends MobMeta {
+
+    public static final byte OFFSET = MobMeta.MAX_OFFSET;
+    public static final byte MAX_OFFSET = OFFSET + 0;
+
+
+    public EnderDragonMeta(int entityId, Metadata metadata) {
+        super(entityId, metadata);
+    }
+
+    @NotNull
+    public Phase getPhase() {
+        return Phase.VALUES[super.metadata.getIndex(OFFSET, 0)];
+    }
+
+    public void setPhase(@NotNull Phase value) {
+        super.metadata.setIndex(OFFSET, EntityDataTypes.INT, value.ordinal());
+    }
+
+    public enum Phase {
+        CIRCLING,
+        STRAFING,
+        FLYING_TO_THE_PORTAL,
+        LANDING_ON_THE_PORTAL,
+        TAKING_OFF_FROM_THE_PORTAL,
+        BREATH_ATTACK,
+        LOOKING_FOR_BREATH_ATTACK_PLAYER,
+        ROAR,
+        CHARGING_PLAYER,
+        FLYING_TO_THE_PORTAL_TO_DIE,
+        HOVERING_WITHOUT_AI;
+
+        private final static Phase[] VALUES = values();
+    }
+
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/other/EvokerFangsMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/other/EvokerFangsMeta.java
new file mode 100644
index 0000000..6d09c26
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/other/EvokerFangsMeta.java
@@ -0,0 +1,14 @@
+package me.tofaa.entitylib.meta.other;
+
+import me.tofaa.entitylib.meta.EntityMeta;
+import me.tofaa.entitylib.meta.Metadata;
+
+public class EvokerFangsMeta extends EntityMeta {
+
+    public static final byte OFFSET = EntityMeta.MAX_OFFSET;
+    public static final byte MAX_OFFSET = OFFSET + 0;
+
+    public EvokerFangsMeta(int entityId, Metadata metadata) {
+        super(entityId, metadata);
+    }
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/other/FallingBlockMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/other/FallingBlockMeta.java
new file mode 100644
index 0000000..ff556ff
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/other/FallingBlockMeta.java
@@ -0,0 +1,46 @@
+package me.tofaa.entitylib.meta.other;
+
+import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
+import com.github.retrooper.packetevents.util.Vector3i;
+import me.tofaa.entitylib.meta.EntityMeta;
+import me.tofaa.entitylib.meta.Metadata;
+import me.tofaa.entitylib.meta.types.ObjectData;
+
+public class FallingBlockMeta extends EntityMeta implements ObjectData {
+
+    public static final byte OFFSET = EntityMeta.MAX_OFFSET;
+    public static final byte MAX_OFFSET = OFFSET + 1;
+
+    private int blockStateId;
+
+    public FallingBlockMeta(int entityId, Metadata metadata) {
+        super(entityId, metadata);
+    }
+
+    public Vector3i getSpawnPosition() {
+        return super.metadata.getIndex(OFFSET, Vector3i.zero());
+    }
+
+    public void setSpawnPosition(Vector3i value) {
+        super.metadata.setIndex(OFFSET, EntityDataTypes.BLOCK_POSITION, value);
+    }
+
+
+    public int getBlockStateId() {
+        return blockStateId;
+    }
+
+    public void setBlockStateId(int blockStateId) {
+        this.blockStateId = blockStateId;
+    }
+
+    @Override
+    public int getObjectData() {
+        return blockStateId;
+    }
+
+    @Override
+    public boolean requiresVelocityPacketAtSpawn() {
+        return false;
+    }
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/other/FireworkRocketMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/other/FireworkRocketMeta.java
new file mode 100644
index 0000000..76b36a5
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/other/FireworkRocketMeta.java
@@ -0,0 +1,50 @@
+package me.tofaa.entitylib.meta.other;
+
+import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
+import com.github.retrooper.packetevents.protocol.item.ItemStack;
+import me.tofaa.entitylib.meta.EntityMeta;
+import me.tofaa.entitylib.meta.Metadata;
+import me.tofaa.entitylib.meta.types.ProjectileMeta;
+
+import java.util.Optional;
+
+public class FireworkRocketMeta extends EntityMeta implements ProjectileMeta {
+
+    public static final byte OFFSET = EntityMeta.MAX_OFFSET;
+    public static final byte MAX_OFFSET = OFFSET + 3;
+
+    private int shooter = -1;
+
+    public FireworkRocketMeta(int entityId, Metadata metadata) {
+        super(entityId, metadata);
+    }
+
+    public ItemStack getFireworkItem() {
+        return super.metadata.getIndex(OFFSET, ItemStack.EMPTY);
+    }
+
+    public void setFireworkItem(ItemStack value) {
+        super.metadata.setIndex(OFFSET, EntityDataTypes.ITEMSTACK, value);
+    }
+
+
+    public boolean isShotAtAngle() {
+        return super.metadata.getIndex(offset(OFFSET, 2), false);
+    }
+
+    public void setShotAtAngle(boolean value) {
+        super.metadata.setIndex(offset(OFFSET, 2), EntityDataTypes.BOOLEAN, value);
+    }
+
+    @Override
+    public int getShooter() {
+        return shooter;
+    }
+
+    @Override
+    public void setShooter(int entityId) {
+        this.shooter = entityId;
+        Optional<Integer> optional = Optional.ofNullable(entityId == -1 ? null : entityId);
+        super.metadata.setIndex(offset(OFFSET, 1), EntityDataTypes.OPTIONAL_INT, optional);
+    }
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/other/FishingHookMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/other/FishingHookMeta.java
new file mode 100644
index 0000000..61f3242
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/other/FishingHookMeta.java
@@ -0,0 +1,53 @@
+package me.tofaa.entitylib.meta.other;
+
+import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
+import me.tofaa.entitylib.meta.EntityMeta;
+import me.tofaa.entitylib.meta.Metadata;
+import me.tofaa.entitylib.meta.types.ObjectData;
+
+import java.util.Optional;
+
+public class FishingHookMeta extends EntityMeta implements ObjectData {
+
+    public static final byte OFFSET = EntityMeta.MAX_OFFSET;
+    public static final byte MAX_OFFSET = OFFSET + 2;
+
+    private int shooterId;
+    private int hookedId;
+
+    public FishingHookMeta(int entityId, Metadata metadata) {
+        super(entityId, metadata);
+    }
+
+    public boolean isCatchable() {
+        return super.metadata.getIndex(offset(OFFSET, 1), false);
+    }
+
+    public void setCatchable(boolean value) {
+        super.metadata.setIndex(offset(OFFSET, 1), EntityDataTypes.BOOLEAN, value);
+    }
+
+    public int getHookedEntity() {
+        return hookedId;
+    }
+
+    public void setShooter(int entityId) {
+        this.shooterId = entityId;
+    }
+
+    public void setHookedEntity(int entityId) {
+        this.hookedId = entityId;
+        super.metadata.setIndex(OFFSET, EntityDataTypes.INT, entityId == -1 ? 0 : entityId + 1);
+    }
+
+    @Override
+    public int getObjectData() {
+        return shooterId != -1 ? shooterId : 0;
+    }
+
+    @Override
+    public boolean requiresVelocityPacketAtSpawn() {
+        return false;
+    }
+
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/other/GlowItemFrameMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/other/GlowItemFrameMeta.java
new file mode 100644
index 0000000..96fc2d7
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/other/GlowItemFrameMeta.java
@@ -0,0 +1,13 @@
+package me.tofaa.entitylib.meta.other;
+
+import me.tofaa.entitylib.meta.Metadata;
+
+public class GlowItemFrameMeta extends ItemFrameMeta {
+
+    public static final byte OFFSET = ItemFrameMeta.MAX_OFFSET;
+    public static final byte MAX_OFFSET = OFFSET + 0;
+
+    public GlowItemFrameMeta(int entityId, Metadata metadata) {
+        super(entityId, metadata);
+    }
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/other/InteractionMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/other/InteractionMeta.java
new file mode 100644
index 0000000..77318f9
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/other/InteractionMeta.java
@@ -0,0 +1,41 @@
+package me.tofaa.entitylib.meta.other;
+
+import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
+import me.tofaa.entitylib.meta.EntityMeta;
+import me.tofaa.entitylib.meta.Metadata;
+
+public class InteractionMeta extends EntityMeta {
+
+    public static final byte OFFSET = EntityMeta.MAX_OFFSET;
+    public static final byte MAX_OFFSET = OFFSET + 3;
+
+    public InteractionMeta(int entityId, Metadata metadata) {
+        super(entityId, metadata);
+    }
+
+    public float getWidth() {
+        return super.metadata.getIndex(OFFSET, 1.0F);
+    }
+
+    public void setWidth(float value) {
+        super.metadata.setIndex(OFFSET, EntityDataTypes.FLOAT, value);
+    }
+
+    public float getHeight() {
+        return super.metadata.getIndex(offset(OFFSET, 1), 1.0F);
+    }
+
+    public void setHeight(float value) {
+        super.metadata.setIndex(offset(OFFSET, 1), EntityDataTypes.FLOAT, value);
+    }
+
+    public boolean isResponsive() {
+        return super.metadata.getIndex(offset(OFFSET, 2), false);
+    }
+
+    public void setResponsive(boolean value) {
+        super.metadata.setIndex(offset(OFFSET, 2), EntityDataTypes.BOOLEAN, value);
+    }
+
+
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/other/ItemFrameMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/other/ItemFrameMeta.java
new file mode 100644
index 0000000..ad15d4c
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/other/ItemFrameMeta.java
@@ -0,0 +1,74 @@
+package me.tofaa.entitylib.meta.other;
+
+import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
+import com.github.retrooper.packetevents.protocol.item.ItemStack;
+import me.tofaa.entitylib.extras.Rotation;
+import me.tofaa.entitylib.meta.EntityMeta;
+import me.tofaa.entitylib.meta.Metadata;
+import me.tofaa.entitylib.meta.types.ObjectData;
+import org.jetbrains.annotations.NotNull;
+
+public class ItemFrameMeta extends EntityMeta implements ObjectData {
+
+    public static final byte OFFSET = EntityMeta.MAX_OFFSET;
+    public static final byte MAX_OFFSET = OFFSET + 2;
+
+    private Orientation orientation = Orientation.DOWN;
+
+    public ItemFrameMeta(int entityId, Metadata metadata) {
+        super(entityId, metadata);
+    }
+
+    @NotNull
+    public ItemStack getItem() {
+        return super.metadata.getIndex(OFFSET, ItemStack.EMPTY);
+    }
+
+    public void setItem(@NotNull ItemStack value) {
+        super.metadata.setIndex(OFFSET, EntityDataTypes.ITEMSTACK, value);
+    }
+
+    @NotNull
+    public Rotation getRotation() {
+        return Rotation.values()[super.metadata.getIndex(offset(OFFSET, 1), 0)];
+    }
+
+    public void setRotation(@NotNull Rotation value) {
+        super.metadata.setIndex(offset(OFFSET, 1), EntityDataTypes.INT, value.ordinal());
+    }
+
+    @NotNull
+    public Orientation getOrientation() {
+        return this.orientation;
+    }
+
+    /**
+     * Sets orientation of the item frame.
+     * This is possible only before spawn packet is sent.
+     *
+     * @param orientation the orientation of the item frame.
+     */
+    public void setOrientation(@NotNull Orientation orientation) {
+        this.orientation = orientation;
+    }
+
+    @Override
+    public int getObjectData() {
+        return this.orientation.ordinal();
+    }
+
+    @Override
+    public boolean requiresVelocityPacketAtSpawn() {
+        return false;
+    }
+
+    public enum Orientation {
+        DOWN,
+        UP,
+        NORTH,
+        SOUTH,
+        WEST,
+        EAST
+    }
+
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/other/LeashKnotMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/other/LeashKnotMeta.java
new file mode 100644
index 0000000..551bfde
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/other/LeashKnotMeta.java
@@ -0,0 +1,14 @@
+package me.tofaa.entitylib.meta.other;
+
+import me.tofaa.entitylib.meta.EntityMeta;
+import me.tofaa.entitylib.meta.Metadata;
+
+public class LeashKnotMeta extends EntityMeta {
+
+    public static final byte OFFSET = EntityMeta.MAX_OFFSET;
+    public static final byte MAX_OFFSET = OFFSET + 0;
+
+    public LeashKnotMeta(int entityId, Metadata metadata) {
+        super(entityId, metadata);
+    }
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/other/LightningBoltMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/other/LightningBoltMeta.java
new file mode 100644
index 0000000..36b2fdc
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/other/LightningBoltMeta.java
@@ -0,0 +1,14 @@
+package me.tofaa.entitylib.meta.other;
+
+import me.tofaa.entitylib.meta.EntityMeta;
+import me.tofaa.entitylib.meta.Metadata;
+
+public class LightningBoltMeta extends EntityMeta {
+
+    public static final byte OFFSET = EntityMeta.MAX_OFFSET;
+    public static final byte MAX_OFFSET = OFFSET + 0;
+
+    public LightningBoltMeta(int entityId, Metadata metadata) {
+        super(entityId, metadata);
+    }
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/other/LlamaSpitMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/other/LlamaSpitMeta.java
new file mode 100644
index 0000000..1f386e0
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/other/LlamaSpitMeta.java
@@ -0,0 +1,25 @@
+package me.tofaa.entitylib.meta.other;
+
+import me.tofaa.entitylib.meta.EntityMeta;
+import me.tofaa.entitylib.meta.Metadata;
+import me.tofaa.entitylib.meta.types.ObjectData;
+
+public class LlamaSpitMeta extends EntityMeta implements ObjectData {
+    public static final byte OFFSET = EntityMeta.MAX_OFFSET;
+    public static final byte MAX_OFFSET = OFFSET + 0;
+
+    public LlamaSpitMeta(int entityId, Metadata metadata) {
+        super(entityId, metadata);
+    }
+
+
+    @Override
+    public int getObjectData() {
+        return 0;
+    }
+
+    @Override
+    public boolean requiresVelocityPacketAtSpawn() {
+        return true;
+    }
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/other/MarkerMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/other/MarkerMeta.java
new file mode 100644
index 0000000..2656e23
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/other/MarkerMeta.java
@@ -0,0 +1,14 @@
+package me.tofaa.entitylib.meta.other;
+
+import me.tofaa.entitylib.meta.EntityMeta;
+import me.tofaa.entitylib.meta.Metadata;
+
+public class MarkerMeta extends EntityMeta {
+
+    public static final byte OFFSET = EntityMeta.MAX_OFFSET;
+    public static final byte MAX_OFFSET = OFFSET + 0;
+
+    public MarkerMeta(int entityId, Metadata metadata) {
+        super(entityId, metadata);
+    }
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/other/PaintingMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/other/PaintingMeta.java
new file mode 100644
index 0000000..cd0e64c
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/other/PaintingMeta.java
@@ -0,0 +1,120 @@
+package me.tofaa.entitylib.meta.other;
+
+import com.github.retrooper.packetevents.protocol.world.Direction;
+import me.tofaa.entitylib.meta.EntityMeta;
+import me.tofaa.entitylib.meta.Metadata;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Locale;
+
+/**
+ * TODO
+ */
+public class PaintingMeta extends EntityMeta {
+
+    public static final byte OFFSET = EntityMeta.MAX_OFFSET;
+    public static final byte MAX_OFFSET = OFFSET + 0;
+
+    private Direction direction = Direction.SOUTH;
+    private Type type = Type.KEBAB;
+
+    public PaintingMeta(int entityId, Metadata metadata) {
+        super(entityId, metadata);
+    }
+
+    @NotNull
+    public Type getType() {
+        return type;
+    }
+
+    public void setType(@NotNull Type type) {
+        this.type = type;
+    }
+
+    @NotNull
+    public Direction getDirection() {
+        return direction;
+    }
+
+    public void setDirection(@NotNull Direction direction) {
+        if (direction == Direction.UP || direction == Direction.DOWN) {
+            throw new IllegalArgumentException("Direction cannot be up or down");
+        }
+        this.direction = direction;
+    }
+
+
+
+    public enum Type {
+        KEBAB(0, 0, 16, 16),
+        AZTEC(16, 0, 16, 16),
+        ALBAN(32, 0, 16, 16),
+        AZTEC2(48, 0, 16, 16),
+        BOMB(64, 0, 16, 16),
+        PLANT(80, 0, 16, 16),
+        WASTELAND(96, 0, 16, 16),
+        POOL(0, 32, 32, 16),
+        COURBET(32, 32, 32, 16),
+        SEA(64, 32, 32, 16),
+        SUNSET(96, 32, 32, 16),
+        CREEBET(128, 32, 32, 16),
+        WANDERER(0, 64, 16, 32),
+        GRAHAM(16, 64, 16, 32),
+        MATCH(0, 128, 32, 32),
+        BUST(32, 128, 32, 32),
+        STAGE(64, 128, 32, 32),
+        VOID(96, 128, 32, 32),
+        SKULL_AND_ROSES("skull_and_roses", 128, 128, 32, 32),
+        WITHER(160, 128, 32, 32),
+        FIGHTERS(0, 96, 64, 32),
+        POINTER(0, 192, 64, 64),
+        PIGSCENE(64, 192, 64, 64),
+        BURNING_SKULL(128, 192, 64, 64),
+        SKELETON(192, 64, 64, 48),
+        DONKEY_KONG(192, 112, 64, 48);
+
+        private final String name;
+        private final int x;
+        private final int y;
+        private final int width;
+        private final int height;
+
+        Type(String name, int x, int y, int width, int height) {
+            this.name = name;
+            this.x = x;
+            this.y = y;
+            this.width = width;
+            this.height = height;
+        }
+
+        Type(int x, int y, int width, int height) {
+            this.name = "minecraft:" + name().toLowerCase(Locale.ROOT);
+            this.x = x;
+            this.y = y;
+            this.width = width;
+            this.height = height;
+        }
+
+        public String getName() {
+            return this.name;
+        }
+
+        public int getX() {
+            return this.x;
+        }
+
+        public int getY() {
+            return this.y;
+        }
+
+        public int getWidth() {
+            return this.width;
+        }
+
+        public int getHeight() {
+            return this.height;
+        }
+
+    }
+
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/other/PrimedTntMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/other/PrimedTntMeta.java
new file mode 100644
index 0000000..0f87fa0
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/other/PrimedTntMeta.java
@@ -0,0 +1,23 @@
+package me.tofaa.entitylib.meta.other;
+
+import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
+import me.tofaa.entitylib.meta.EntityMeta;
+import me.tofaa.entitylib.meta.Metadata;
+
+public class PrimedTntMeta extends EntityMeta {
+    public static final byte OFFSET = EntityMeta.MAX_OFFSET;
+    public static final byte MAX_OFFSET = OFFSET + 1;
+
+
+    public PrimedTntMeta(int entityId, Metadata metadata) {
+        super(entityId, metadata);
+    }
+
+    public int getFuseTime() {
+        return super.metadata.getIndex(OFFSET, 80);
+    }
+
+    public void setFuseTime(int value) {
+        super.metadata.setIndex(OFFSET, EntityDataTypes.INT, value);
+    }
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/projectile/ArrowMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/projectile/ArrowMeta.java
new file mode 100644
index 0000000..1a9d9a9
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/projectile/ArrowMeta.java
@@ -0,0 +1,47 @@
+package me.tofaa.entitylib.meta.projectile;
+
+import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
+import me.tofaa.entitylib.meta.Metadata;
+import me.tofaa.entitylib.meta.types.ObjectData;
+import me.tofaa.entitylib.meta.types.ProjectileMeta;
+
+public class ArrowMeta extends BaseArrowMeta implements ProjectileMeta, ObjectData {
+
+    public static final byte OFFSET = BaseArrowMeta.MAX_OFFSET;
+    public static final byte MAX_OFFSET = OFFSET + 1;
+
+    private int shooterId = -1;
+
+    public ArrowMeta(int entityId, Metadata metadata) {
+        super(entityId, metadata);
+    }
+
+    public int getColor() {
+        return super.metadata.getIndex(OFFSET, -1);
+    }
+
+    public void setColor(int value) {
+        super.metadata.setIndex(OFFSET, EntityDataTypes.INT, value);
+    }
+
+    @Override
+    public int getShooter() {
+        return shooterId;
+    }
+
+    @Override
+    public void setShooter(int entityId) {
+        this.shooterId = entityId;
+    }
+
+
+    @Override
+    public int getObjectData() {
+        return this.shooterId == -1 ? 0 : this.shooterId + 1;
+    }
+
+    @Override
+    public boolean requiresVelocityPacketAtSpawn() {
+        return true;
+    }
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/projectile/BaseArrowMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/projectile/BaseArrowMeta.java
new file mode 100644
index 0000000..def5833
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/projectile/BaseArrowMeta.java
@@ -0,0 +1,48 @@
+package me.tofaa.entitylib.meta.projectile;
+
+import com.github.retrooper.packetevents.manager.server.ServerVersion;
+import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
+import me.tofaa.entitylib.meta.EntityMeta;
+import me.tofaa.entitylib.meta.Metadata;
+
+public class BaseArrowMeta extends EntityMeta {
+
+    public static final byte OFFSET = EntityMeta.MAX_OFFSET;
+    public static final byte MAX_OFFSET = OFFSET + 2;
+
+    private final static byte CRITICAL_BIT = 0x01;
+    private final static byte NO_CLIP_BIT = 0x02;
+
+    public BaseArrowMeta(int entityId, Metadata metadata) {
+        super(entityId, metadata);
+    }
+
+    public boolean isCritical() {
+        return getMaskBit(OFFSET, CRITICAL_BIT);
+    }
+
+    public void setCritical(boolean value) {
+        setMaskBit(OFFSET, CRITICAL_BIT, value);
+    }
+
+    public boolean isNoClip() {
+        isVersionNewer(ServerVersion.V_1_9);
+        return getMaskBit(OFFSET, NO_CLIP_BIT);
+    }
+
+    public void setNoClip(boolean value) {
+        isVersionNewer(ServerVersion.V_1_9);
+        setMaskBit(OFFSET, NO_CLIP_BIT, value);
+    }
+
+    public int getPierceLevel() {
+        isVersionNewer(ServerVersion.V_1_14);
+        return super.metadata.getIndex(offset(OFFSET,1), 0);
+    }
+
+    public void setPierceLevel(int value) {
+        isVersionNewer(ServerVersion.V_1_14);
+        super.metadata.setIndex(offset(OFFSET,1), EntityDataTypes.INT, value);
+    }
+
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/projectile/DragonFireballMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/projectile/DragonFireballMeta.java
new file mode 100644
index 0000000..19d05f9
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/projectile/DragonFireballMeta.java
@@ -0,0 +1,38 @@
+package me.tofaa.entitylib.meta.projectile;
+
+import me.tofaa.entitylib.meta.EntityMeta;
+import me.tofaa.entitylib.meta.Metadata;
+import me.tofaa.entitylib.meta.types.ObjectData;
+import me.tofaa.entitylib.meta.types.ProjectileMeta;
+
+public class DragonFireballMeta extends EntityMeta implements ProjectileMeta, ObjectData {
+
+    public static final byte OFFSET = EntityMeta.MAX_OFFSET;
+    public static final byte MAX_OFFSET = OFFSET + 0;
+
+    private int shooter = -1;
+
+    public DragonFireballMeta(int entityId, Metadata metadata) {
+        super(entityId, metadata);
+    }
+
+    @Override
+    public int getObjectData() {
+        return this.shooter == -1 ? 0 : this.shooter;
+    }
+
+    @Override
+    public boolean requiresVelocityPacketAtSpawn() {
+        return true;
+    }
+
+    @Override
+    public int getShooter() {
+        return shooter;
+    }
+
+    @Override
+    public void setShooter(int entityId) {
+        this.shooter = entityId;
+    }
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/projectile/EyeOfEnderMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/projectile/EyeOfEnderMeta.java
new file mode 100644
index 0000000..3689fd4
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/projectile/EyeOfEnderMeta.java
@@ -0,0 +1,20 @@
+package me.tofaa.entitylib.meta.projectile;
+
+import com.github.retrooper.packetevents.protocol.item.ItemStack;
+import com.github.retrooper.packetevents.protocol.item.type.ItemTypes;
+import me.tofaa.entitylib.meta.Metadata;
+import me.tofaa.entitylib.meta.types.ItemContainerMeta;
+
+public class EyeOfEnderMeta extends ItemContainerMeta {
+
+
+    public static final byte OFFSET = ItemContainerMeta.MAX_OFFSET;
+    public static final byte MAX_OFFSET = OFFSET + 0;
+
+    public static final ItemStack EYE_OF_ENDER = ItemStack.builder().type(ItemTypes.ENDER_EYE).build();
+
+    public EyeOfEnderMeta(int entityId, Metadata metadata) {
+        super(entityId, metadata, EYE_OF_ENDER);
+    }
+
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/projectile/ItemEntityMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/projectile/ItemEntityMeta.java
new file mode 100644
index 0000000..f3f884a
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/projectile/ItemEntityMeta.java
@@ -0,0 +1,26 @@
+package me.tofaa.entitylib.meta.projectile;
+
+import com.github.retrooper.packetevents.protocol.item.ItemStack;
+import me.tofaa.entitylib.meta.Metadata;
+import me.tofaa.entitylib.meta.types.ItemContainerMeta;
+import me.tofaa.entitylib.meta.types.ObjectData;
+
+public class ItemEntityMeta extends ItemContainerMeta implements ObjectData {
+
+    public static final byte OFFSET = ItemContainerMeta.MAX_OFFSET;
+    public static final byte MAX_OFFSET = OFFSET + 0;
+
+    protected ItemEntityMeta(int entityId, Metadata metadata) {
+        super(entityId, metadata, ItemStack.EMPTY);
+    }
+
+    @Override
+    public int getObjectData() {
+        return 1;
+    }
+
+    @Override
+    public boolean requiresVelocityPacketAtSpawn() {
+        return true;
+    }
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/projectile/LargeFireballMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/projectile/LargeFireballMeta.java
new file mode 100644
index 0000000..2308527
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/projectile/LargeFireballMeta.java
@@ -0,0 +1,39 @@
+package me.tofaa.entitylib.meta.projectile;
+
+import com.github.retrooper.packetevents.protocol.item.ItemStack;
+import me.tofaa.entitylib.meta.Metadata;
+import me.tofaa.entitylib.meta.types.ItemContainerMeta;
+import me.tofaa.entitylib.meta.types.ObjectData;
+import me.tofaa.entitylib.meta.types.ProjectileMeta;
+
+public class LargeFireballMeta extends ItemContainerMeta implements ObjectData, ProjectileMeta {
+    public static final byte OFFSET = ItemContainerMeta.MAX_OFFSET;
+    public static final byte MAX_OFFSET = OFFSET + 0;
+
+    private int shooterId = -1;
+
+    public LargeFireballMeta(int entityId, Metadata meta) {
+        super(entityId, meta, ItemStack.EMPTY);
+    }
+
+    @Override
+    public int getObjectData() {
+        return this.shooterId == -1 ? 0 : this.shooterId;
+    }
+
+    @Override
+    public boolean requiresVelocityPacketAtSpawn() {
+        return true;
+    }
+
+    @Override
+    public int getShooter() {
+        return shooterId;
+    }
+
+    @Override
+    public void setShooter(int entityId) {
+        this.shooterId = entityId;
+    }
+
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/projectile/ShulkerBulletMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/projectile/ShulkerBulletMeta.java
new file mode 100644
index 0000000..a0925b8
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/projectile/ShulkerBulletMeta.java
@@ -0,0 +1,25 @@
+package me.tofaa.entitylib.meta.projectile;
+
+import me.tofaa.entitylib.meta.EntityMeta;
+import me.tofaa.entitylib.meta.Metadata;
+import me.tofaa.entitylib.meta.types.ObjectData;
+
+public class ShulkerBulletMeta extends EntityMeta implements ObjectData {
+
+    public static final byte OFFSET = EntityMeta.MAX_OFFSET;
+    public static final byte MAX_OFFSET = OFFSET + 0;
+
+    public ShulkerBulletMeta(int entityId, Metadata metadata) {
+        super(entityId, metadata);
+    }
+
+    @Override
+    public int getObjectData() {
+        return 0;
+    }
+
+    @Override
+    public boolean requiresVelocityPacketAtSpawn() {
+        return true;
+    }
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/projectile/SmallFireballMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/projectile/SmallFireballMeta.java
new file mode 100644
index 0000000..513cb17
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/projectile/SmallFireballMeta.java
@@ -0,0 +1,43 @@
+package me.tofaa.entitylib.meta.projectile;
+
+import com.github.retrooper.packetevents.protocol.item.ItemStack;
+import com.github.retrooper.packetevents.protocol.item.type.ItemTypes;
+import me.tofaa.entitylib.meta.Metadata;
+import me.tofaa.entitylib.meta.types.ItemContainerMeta;
+import me.tofaa.entitylib.meta.types.ObjectData;
+import me.tofaa.entitylib.meta.types.ProjectileMeta;
+
+public class SmallFireballMeta extends ItemContainerMeta implements ObjectData, ProjectileMeta {
+
+
+    public static final byte OFFSET = ItemContainerMeta.MAX_OFFSET;
+    public static final byte MAX_OFFSET = OFFSET + 0;
+
+    public static final ItemStack SMALL_FIREBALL = ItemStack.builder().type(ItemTypes.FIRE_CHARGE).build();
+
+    private int shooterId = -1;
+
+    public SmallFireballMeta(int entityId, Metadata meta) {
+        super(entityId, meta, SMALL_FIREBALL);
+    }
+
+    @Override
+    public int getObjectData() {
+        return this.shooterId == -1 ? 0 : this.shooterId;
+    }
+
+    @Override
+    public boolean requiresVelocityPacketAtSpawn() {
+        return true;
+    }
+
+    @Override
+    public int getShooter() {
+        return shooterId;
+    }
+
+    @Override
+    public void setShooter(int entityId) {
+        this.shooterId = entityId;
+    }
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/projectile/SnowballMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/projectile/SnowballMeta.java
new file mode 100644
index 0000000..cdee6be
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/projectile/SnowballMeta.java
@@ -0,0 +1,19 @@
+package me.tofaa.entitylib.meta.projectile;
+
+import com.github.retrooper.packetevents.protocol.item.ItemStack;
+import com.github.retrooper.packetevents.protocol.item.type.ItemTypes;
+import me.tofaa.entitylib.meta.Metadata;
+import me.tofaa.entitylib.meta.types.ItemContainerMeta;
+
+public class SnowballMeta extends ItemContainerMeta {
+
+    public static final byte OFFSET = ItemContainerMeta.MAX_OFFSET;
+    public static final byte MAX_OFFSET = OFFSET + 0;
+
+    public static final ItemStack SNOWBALL = ItemStack.builder().type(ItemTypes.SNOWBALL).build();
+
+    public SnowballMeta(int entityId, Metadata metadata) {
+        super(entityId, metadata, SNOWBALL);
+    }
+
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/projectile/SpectralArrowMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/projectile/SpectralArrowMeta.java
new file mode 100644
index 0000000..314ee83
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/projectile/SpectralArrowMeta.java
@@ -0,0 +1,37 @@
+package me.tofaa.entitylib.meta.projectile;
+
+import me.tofaa.entitylib.meta.Metadata;
+import me.tofaa.entitylib.meta.types.ObjectData;
+import me.tofaa.entitylib.meta.types.ProjectileMeta;
+
+public class SpectralArrowMeta extends BaseArrowMeta implements ProjectileMeta, ObjectData {
+
+    public static final byte OFFSET = BaseArrowMeta.MAX_OFFSET;
+    public static final byte MAX_OFFSET = OFFSET + 0;
+
+    private int shooterId = -1;
+
+    public SpectralArrowMeta(int entityId, Metadata metadata) {
+        super(entityId, metadata);
+    }
+
+    @Override
+    public int getObjectData() {
+        return this.shooterId == -1 ? 0 : this.shooterId + 1;
+    }
+
+    @Override
+    public boolean requiresVelocityPacketAtSpawn() {
+        return true;
+    }
+
+    @Override
+    public int getShooter() {
+        return shooterId;
+    }
+
+    @Override
+    public void setShooter(int entityId) {
+        this.shooterId = entityId;
+    }
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/projectile/ThrownEggMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/projectile/ThrownEggMeta.java
new file mode 100644
index 0000000..84eeaa0
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/projectile/ThrownEggMeta.java
@@ -0,0 +1,20 @@
+package me.tofaa.entitylib.meta.projectile;
+
+import com.github.retrooper.packetevents.protocol.item.ItemStack;
+import com.github.retrooper.packetevents.protocol.item.type.ItemTypes;
+import me.tofaa.entitylib.meta.Metadata;
+import me.tofaa.entitylib.meta.types.ItemContainerMeta;
+
+public class ThrownEggMeta extends ItemContainerMeta {
+
+
+    public static final byte OFFSET = ItemContainerMeta.MAX_OFFSET;
+    public static final byte MAX_OFFSET = OFFSET + 0;
+
+    private static final ItemStack EGG = ItemStack.builder().type(ItemTypes.EGG).build();
+
+    public ThrownEggMeta(int entityId, Metadata metadata) {
+        super(entityId, metadata, EGG);
+    }
+
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/projectile/ThrownEnderPearlMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/projectile/ThrownEnderPearlMeta.java
new file mode 100644
index 0000000..c75a441
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/projectile/ThrownEnderPearlMeta.java
@@ -0,0 +1,19 @@
+package me.tofaa.entitylib.meta.projectile;
+
+import com.github.retrooper.packetevents.protocol.item.ItemStack;
+import com.github.retrooper.packetevents.protocol.item.type.ItemTypes;
+import me.tofaa.entitylib.meta.Metadata;
+import me.tofaa.entitylib.meta.types.ItemContainerMeta;
+
+public class ThrownEnderPearlMeta extends ItemContainerMeta {
+
+    public static final byte OFFSET = ItemContainerMeta.MAX_OFFSET;
+    public static final byte MAX_OFFSET = OFFSET + 0;
+
+    private static final ItemStack ENDER_PEARL = ItemStack.builder().type(ItemTypes.ENDER_PEARL).build();
+
+    public ThrownEnderPearlMeta(int entityId, Metadata metadata) {
+        super(entityId, metadata, ENDER_PEARL);
+    }
+
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/projectile/ThrownExpBottleMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/projectile/ThrownExpBottleMeta.java
new file mode 100644
index 0000000..d3058bb
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/projectile/ThrownExpBottleMeta.java
@@ -0,0 +1,19 @@
+package me.tofaa.entitylib.meta.projectile;
+
+import com.github.retrooper.packetevents.protocol.item.ItemStack;
+import com.github.retrooper.packetevents.protocol.item.type.ItemTypes;
+import me.tofaa.entitylib.meta.Metadata;
+import me.tofaa.entitylib.meta.types.ItemContainerMeta;
+
+public class ThrownExpBottleMeta extends ItemContainerMeta {
+
+    public static final byte OFFSET = ItemContainerMeta.MAX_OFFSET;
+    public static final byte MAX_OFFSET = OFFSET + 0;
+
+    private static final ItemStack EXP_BOTTLE = ItemStack.builder().type(ItemTypes.EXPERIENCE_BOTTLE).build();
+
+    public ThrownExpBottleMeta(int entityId, Metadata metadata) {
+        super(entityId, metadata, EXP_BOTTLE);
+    }
+
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/projectile/ThrownPotionMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/projectile/ThrownPotionMeta.java
new file mode 100644
index 0000000..b2514fd
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/projectile/ThrownPotionMeta.java
@@ -0,0 +1,17 @@
+package me.tofaa.entitylib.meta.projectile;
+
+import com.github.retrooper.packetevents.protocol.item.ItemStack;
+import me.tofaa.entitylib.meta.Metadata;
+import me.tofaa.entitylib.meta.types.ItemContainerMeta;
+
+public class ThrownPotionMeta extends ItemContainerMeta {
+
+    public static final byte OFFSET = ItemContainerMeta.MAX_OFFSET;
+    public static final byte MAX_OFFSET = OFFSET + 0;
+
+    public ThrownPotionMeta(int entityId, Metadata metadata) {
+        super(entityId, metadata, ItemStack.EMPTY);
+    }
+
+
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/projectile/ThrownTridentMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/projectile/ThrownTridentMeta.java
new file mode 100644
index 0000000..8f77723
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/projectile/ThrownTridentMeta.java
@@ -0,0 +1,31 @@
+package me.tofaa.entitylib.meta.projectile;
+
+import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
+import me.tofaa.entitylib.meta.Metadata;
+
+public class ThrownTridentMeta extends BaseArrowMeta{
+
+    public static final byte OFFSET = BaseArrowMeta.MAX_OFFSET;
+    public static final byte MAX_OFFSET = OFFSET + 2;
+
+    public ThrownTridentMeta(int entityId, Metadata metadata) {
+        super(entityId, metadata);
+    }
+
+    public int getLoyaltyLevel() {
+        return super.metadata.getIndex(OFFSET, 0);
+    }
+
+    public void setLoyaltyLevel(int value) {
+        super.metadata.setIndex(OFFSET, EntityDataTypes.INT, value);
+    }
+
+    public boolean isHasEnchantmentGlint() {
+        return super.metadata.getIndex(offset(OFFSET,1), false);
+    }
+
+    public void setHasEnchantmentGlint(boolean value) {
+        super.metadata.setIndex(offset(OFFSET,1), EntityDataTypes.BOOLEAN, value);
+    }
+
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/projectile/WitherSkullMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/projectile/WitherSkullMeta.java
new file mode 100644
index 0000000..985a274
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/projectile/WitherSkullMeta.java
@@ -0,0 +1,50 @@
+package me.tofaa.entitylib.meta.projectile;
+
+import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
+import me.tofaa.entitylib.meta.EntityMeta;
+import me.tofaa.entitylib.meta.Metadata;
+import me.tofaa.entitylib.meta.types.ObjectData;
+import me.tofaa.entitylib.meta.types.ProjectileMeta;
+
+public class WitherSkullMeta extends EntityMeta implements ObjectData, ProjectileMeta {
+
+    public static final byte OFFSET = EntityMeta.MAX_OFFSET;
+    public static final byte MAX_OFFSET = OFFSET + 1;
+
+    private int shooter = -1;
+
+    public WitherSkullMeta(int entityId, Metadata metadata) {
+        super(entityId, metadata);
+    }
+
+
+    public boolean isInvulnerable() {
+        return super.metadata.getIndex(OFFSET, false);
+    }
+
+    public void setInvulnerable(boolean value) {
+        super.metadata.setIndex(OFFSET, EntityDataTypes.BOOLEAN, value);
+    }
+
+
+
+    @Override
+    public int getObjectData() {
+        return this.shooter == -1 ? 0 : this.shooter;
+    }
+
+    @Override
+    public boolean requiresVelocityPacketAtSpawn() {
+        return true;
+    }
+
+    @Override
+    public int getShooter() {
+        return shooter;
+    }
+
+    @Override
+    public void setShooter(int entityId) {
+        this.shooter = entityId;
+    }
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/types/AgeableMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/types/AgeableMeta.java
new file mode 100644
index 0000000..a2868aa
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/types/AgeableMeta.java
@@ -0,0 +1,23 @@
+package me.tofaa.entitylib.meta.types;
+
+import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
+import me.tofaa.entitylib.meta.Metadata;
+
+public class AgeableMeta extends MobMeta {
+
+    public static final byte OFFSET = MobMeta.MAX_OFFSET;
+    public static final byte MAX_OFFSET = OFFSET + 1;
+
+    public AgeableMeta(int entityId, Metadata metadata) {
+        super(entityId, metadata);
+    }
+
+    public boolean isBaby() {
+        return super.metadata.getIndex(OFFSET, false);
+    }
+
+    public void setBaby(boolean value) {
+        super.metadata.setIndex(OFFSET, EntityDataTypes.BOOLEAN, value);
+    }
+
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/types/DisplayMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/types/DisplayMeta.java
new file mode 100644
index 0000000..c3a56a4
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/types/DisplayMeta.java
@@ -0,0 +1,255 @@
+package me.tofaa.entitylib.meta.types;
+
+import com.github.retrooper.packetevents.manager.server.ServerVersion;
+import com.github.retrooper.packetevents.manager.server.VersionComparison;
+import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
+import com.github.retrooper.packetevents.util.Quaternion4f;
+import com.github.retrooper.packetevents.util.Vector3f;
+import me.tofaa.entitylib.meta.EntityMeta;
+import me.tofaa.entitylib.meta.Metadata;
+
+public class DisplayMeta extends EntityMeta {
+
+    public static final byte OFFSET = EntityMeta.MAX_OFFSET;
+    public static final byte MAX_OFFSET;
+    static {
+        if (isVersion(ServerVersion.V_1_20_2, VersionComparison.NEWER_THAN_OR_EQUALS)) {
+            MAX_OFFSET =  OFFSET + 15;
+        }
+        else {
+            MAX_OFFSET = OFFSET + 14;
+        }
+    }
+
+    public DisplayMeta(int entityId, Metadata metadata) {
+        super(entityId, metadata);
+        isVersionNewer(ServerVersion.V_1_19_3);
+    }
+
+    public int getInterpolationDelay() {
+        return super.metadata.getIndex(OFFSET, 0);
+    }
+
+    public void setInterpolationDelay(int value) {
+        super.metadata.setIndex(OFFSET, EntityDataTypes.INT, value);
+    }
+
+    public int getTransformationInterpolationDuration() {
+        return super.metadata.getIndex(offset(OFFSET, 1), 0);
+    }
+
+    public void setTransformationInterpolationDuration(int value) {
+        super.metadata.setIndex(offset(OFFSET, 1), EntityDataTypes.INT, value);
+    }
+
+    public int getPositionRotationInterpolationDuration() {
+        return super.metadata.getIndex(offset(OFFSET, 2), 0);
+    }
+
+    public void setPositionRotationInterpolationDuration(int value) {
+        super.metadata.setIndex(offset(OFFSET, 2), EntityDataTypes.INT, value);
+    }
+
+    public Vector3f getTranslation() {
+        byte offset = offset(OFFSET, 3);
+        if (isVersion(ServerVersion.V_1_20_2, VersionComparison.OLDER_THAN)) {
+            offset = offset(OFFSET, 2);
+        }
+        return super.metadata.getIndex(offset, Vector3f.zero());
+    }
+
+    public void setTranslation(Vector3f value) {
+        byte offset = offset(OFFSET, 3);
+        if (isVersion(ServerVersion.V_1_20_2, VersionComparison.OLDER_THAN)) {
+            offset = offset(OFFSET, 2);
+        }
+        super.metadata.setIndex(offset, EntityDataTypes.VECTOR3F, value);
+    }
+
+    public Vector3f getScale() {
+        byte offset = offset(OFFSET, 4);
+        if (isVersion(ServerVersion.V_1_20_2, VersionComparison.OLDER_THAN)) {
+            offset = offset(OFFSET, 3);
+        }
+        return super.metadata.getIndex(offset, new Vector3f(1.0f, 1.0f, 1.0f));
+    }
+
+    public void setScale(Vector3f value) {
+        byte offset = offset(OFFSET, 4);
+        if (isVersion(ServerVersion.V_1_20_2, VersionComparison.OLDER_THAN)) {
+            offset = offset(OFFSET, 3);
+        }
+        super.metadata.setIndex(offset, EntityDataTypes.VECTOR3F, value);
+    }
+
+    public Quaternion4f getLeftRotation() {
+        byte offset = offset(OFFSET, 5);
+        if (isVersion(ServerVersion.V_1_20_2, VersionComparison.OLDER_THAN)) {
+            offset = offset(OFFSET, 4);
+        }
+        return super.metadata.getIndex(offset, new Quaternion4f(0.0f, 0.0f, 0.0f, 1.0f));
+    }
+
+    public void setLeftRotation(Quaternion4f value) {
+        byte offset = offset(OFFSET, 5);
+        if (isVersion(ServerVersion.V_1_20_2, VersionComparison.OLDER_THAN)) {
+            offset = offset(OFFSET, 4);
+        }
+        super.metadata.setIndex(offset, EntityDataTypes.QUATERNION, value);
+    }
+
+    public Quaternion4f getRightRotation() {
+        byte offset = offset(OFFSET, 6);
+        if (isVersion(ServerVersion.V_1_20_2, VersionComparison.OLDER_THAN)) {
+            offset = offset(OFFSET, 5);
+        }
+        return super.metadata.getIndex(offset, new Quaternion4f(0.0f, 0.0f, 0.0f, 1.0f));
+    }
+
+    public void setRightRotation(Quaternion4f value) {
+        byte offset = offset(OFFSET, 6);
+        if (isVersion(ServerVersion.V_1_20_2, VersionComparison.OLDER_THAN)) {
+            offset = offset(OFFSET, 5);
+        }
+        super.metadata.setIndex(offset, EntityDataTypes.QUATERNION, value);
+    }
+
+    public BillboardConstraints getBillboardConstraints() {
+        byte offset = offset(OFFSET, 7);
+        if (isVersion(ServerVersion.V_1_20_2, VersionComparison.OLDER_THAN)) {
+            offset = offset(OFFSET, 6);
+        }
+        return BillboardConstraints.VALUES[super.metadata.getIndex(offset, (byte) 0)];
+    }
+
+    public void setBillboardConstraints(BillboardConstraints value) {
+        byte offset = offset(OFFSET, 7);
+        if (isVersion(ServerVersion.V_1_20_2, VersionComparison.OLDER_THAN)) {
+            offset = offset(OFFSET, 6);
+        }
+        super.metadata.setIndex(offset, EntityDataTypes.BYTE, (byte) value.ordinal());
+    }
+
+    //(blockLight << 4 | skyLight << 20)
+    public int getBrightnessOverride() {
+        byte offset = offset(OFFSET, 8);
+        if (isVersion(ServerVersion.V_1_20_2, VersionComparison.OLDER_THAN)) {
+            offset = offset(OFFSET, 7);
+        }
+        return super.metadata.getIndex(offset, -1);
+    }
+
+    public void setBrightnessOverride(int value) {
+        byte offset = offset(OFFSET, 8);
+        if (isVersion(ServerVersion.V_1_20_2, VersionComparison.OLDER_THAN)) {
+            offset = offset(OFFSET, 7);
+        }
+        super.metadata.setIndex(offset, EntityDataTypes.INT, value);
+    }
+
+    public float getViewRange() {
+        byte offset = offset(OFFSET, 9);
+        if (isVersion(ServerVersion.V_1_20_2, VersionComparison.OLDER_THAN)) {
+            offset = offset(OFFSET, 8);
+        }
+        return super.metadata.getIndex(offset, 1.0f);
+    }
+
+    public void setViewRange(float value) {
+        byte offset = offset(OFFSET, 9);
+        if (isVersion(ServerVersion.V_1_20_2, VersionComparison.OLDER_THAN)) {
+            offset = offset(OFFSET, 8);
+        }
+        super.metadata.setIndex(offset, EntityDataTypes.FLOAT, value);
+    }
+
+    public float getShadowRadius() {
+        byte offset = offset(OFFSET, 10);
+        if (isVersion(ServerVersion.V_1_20_2, VersionComparison.OLDER_THAN)) {
+            offset = offset(OFFSET, 9);
+        }
+        return super.metadata.getIndex(offset, 0.0f);
+    }
+
+    public void setShadowRadius(float value) {
+        byte offset = offset(OFFSET, 10);
+        if (isVersion(ServerVersion.V_1_20_2, VersionComparison.OLDER_THAN)) {
+            offset = offset(OFFSET, 9);
+        }
+        super.metadata.setIndex(offset, EntityDataTypes.FLOAT, value);
+    }
+
+    public float getShadowStrength() {
+        byte offset = offset(OFFSET, 11);
+        if (isVersion(ServerVersion.V_1_20_2, VersionComparison.OLDER_THAN)) {
+            offset = offset(OFFSET, 10);
+        }
+        return super.metadata.getIndex(offset, 1.0f);
+    }
+
+    public void setShadowStrength(float value) {
+        byte offset = offset(OFFSET, 11);
+        if (isVersion(ServerVersion.V_1_20_2, VersionComparison.OLDER_THAN)) {
+            offset = offset(OFFSET, 10);
+        }
+        super.metadata.setIndex(offset, EntityDataTypes.FLOAT, value);
+    }
+
+    public float getWidth() {
+        byte offset = offset(OFFSET, 12);
+        if (isVersion(ServerVersion.V_1_20_2, VersionComparison.OLDER_THAN)) {
+            offset = offset(OFFSET, 11);
+        }
+        return super.metadata.getIndex(offset, 0.0f);
+    }
+
+    public void setWidth(float value) {
+        byte offset = offset(OFFSET, 12);
+        if (isVersion(ServerVersion.V_1_20_2, VersionComparison.OLDER_THAN)) {
+            offset = offset(OFFSET, 11);
+        }
+        super.metadata.setIndex(offset, EntityDataTypes.FLOAT, value);
+    }
+
+    public float getHeight() {
+        byte offset = offset(OFFSET, 13);
+        if (isVersion(ServerVersion.V_1_20_2, VersionComparison.OLDER_THAN)) {
+            offset = offset(OFFSET, 12);
+        }
+        return super.metadata.getIndex(offset, 0.0f);
+    }
+
+    public void setHeight(float value) {
+        byte offset = offset(OFFSET, 13);
+        if (isVersion(ServerVersion.V_1_20_2, VersionComparison.OLDER_THAN)) {
+            offset = offset(OFFSET, 12);
+        }
+        super.metadata.setIndex(offset, EntityDataTypes.FLOAT, value);
+    }
+
+    public int getGlowColorOverride() {
+        byte offset = offset(OFFSET, 14);
+        if (isVersion(ServerVersion.V_1_20_2, VersionComparison.OLDER_THAN)) {
+            offset = offset(OFFSET, 13);
+        }
+        return super.metadata.getIndex(offset, -1);
+    }
+
+    public void setGlowColorOverride(int value) {
+        byte offset = offset(OFFSET, 14);
+        if (isVersion(ServerVersion.V_1_20_2, VersionComparison.OLDER_THAN)) {
+            offset = offset(OFFSET, 13);
+        }
+        super.metadata.setIndex(offset, EntityDataTypes.INT, value);
+    }
+
+    public enum BillboardConstraints {
+        FIXED,
+        VERTICAL,
+        HORIZONTAL,
+        CENTER;
+
+        private static final BillboardConstraints[] VALUES = values();
+    }
+
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/types/ItemContainerMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/types/ItemContainerMeta.java
new file mode 100644
index 0000000..7d0f87b
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/types/ItemContainerMeta.java
@@ -0,0 +1,27 @@
+package me.tofaa.entitylib.meta.types;
+
+import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
+import com.github.retrooper.packetevents.protocol.item.ItemStack;
+import me.tofaa.entitylib.meta.EntityMeta;
+import me.tofaa.entitylib.meta.Metadata;
+
+public abstract class ItemContainerMeta extends EntityMeta {
+    public static final byte OFFSET = EntityMeta.MAX_OFFSET;
+    public static final byte MAX_OFFSET = OFFSET + 1;
+
+    private final ItemStack baseItem;
+
+    protected ItemContainerMeta(int entityId, Metadata metadata, ItemStack baseItem) {
+        super(entityId, metadata);
+        this.baseItem = baseItem;
+    }
+
+    public ItemStack getItem() {
+        return super.metadata.getIndex(OFFSET, baseItem);
+    }
+
+    public void setItem(ItemStack value) {
+        super.metadata.setIndex(OFFSET, EntityDataTypes.ITEMSTACK, value);
+    }
+
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/types/LivingEntityMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/types/LivingEntityMeta.java
new file mode 100644
index 0000000..448c3cd
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/types/LivingEntityMeta.java
@@ -0,0 +1,119 @@
+package me.tofaa.entitylib.meta.types;
+
+import com.github.retrooper.packetevents.manager.server.ServerVersion;
+import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
+import com.github.retrooper.packetevents.protocol.player.HumanoidArm;
+import com.github.retrooper.packetevents.util.Vector3i;
+import me.tofaa.entitylib.meta.EntityMeta;
+import me.tofaa.entitylib.meta.Metadata;
+
+import java.util.Optional;
+
+public class LivingEntityMeta extends EntityMeta {
+    public static final byte OFFSET = EntityMeta.MAX_OFFSET;
+    public static final byte MAX_OFFSET = OFFSET + 7;
+
+    private final static byte IS_HAND_ACTIVE_BIT = 0x01;
+    private final static byte ACTIVE_HAND_BIT = 0x02;
+    private final static byte IS_IN_SPIN_ATTACK_BIT = 0x04;
+
+    public LivingEntityMeta(int entityId, Metadata metadata) {
+        super(entityId, metadata);
+    }
+
+
+    public float getHealth() {
+        return super.metadata.getIndex(offset(OFFSET,1), 1F);
+    }
+
+
+    public int getPotionEffectColor() {
+        isVersionNewer(ServerVersion.V_1_9);
+        return super.metadata.getIndex(offset(OFFSET,2), 0);
+    }
+
+    public void setPotionEffectColor(int value) {
+        isVersionNewer(ServerVersion.V_1_9);
+        super.metadata.setIndex(offset(OFFSET,2), EntityDataTypes.INT, value);
+    }
+
+    public void setPotionEffectColor(int red, int green, int blue) {
+        isVersionNewer(ServerVersion.V_1_9);
+        setPotionEffectColor(red << 16 + green << 8 + blue);
+    }
+
+    public boolean isPotionEffectAmbient() {
+        isVersionNewer(ServerVersion.V_1_9);
+        return super.metadata.getIndex(offset(OFFSET,3), false);
+    }
+
+    public void setPotionEffectAmbient(boolean value) {
+        isVersionNewer(ServerVersion.V_1_9);
+        super.metadata.setIndex(offset(OFFSET,3), EntityDataTypes.BOOLEAN, value);
+    }
+
+    public int getArrowCount() {
+        isVersionNewer(ServerVersion.V_1_9);
+        return super.metadata.getIndex(offset(OFFSET,4), 0);
+    }
+
+    public void setArrowCount(int value) {
+        isVersionNewer(ServerVersion.V_1_9);
+        super.metadata.setIndex(offset(OFFSET,4), EntityDataTypes.INT, value);
+    }
+
+    public void setHealth(float value) {
+        super.metadata.setIndex(offset(OFFSET,1), EntityDataTypes.FLOAT, value);
+    }
+
+    public HumanoidArm getActiveHand() {
+        isVersionNewer(ServerVersion.V_1_9);
+        return getMaskBit(OFFSET, ACTIVE_HAND_BIT) ? HumanoidArm.LEFT : HumanoidArm.RIGHT;
+    }
+
+    public void setActiveHand(HumanoidArm value) {
+        isVersionNewer(ServerVersion.V_1_9);
+        setMaskBit(OFFSET, ACTIVE_HAND_BIT, value == HumanoidArm.LEFT);
+    }
+
+    public boolean isInRiptideSpinAttack() {
+        isVersionNewer(ServerVersion.V_1_13);
+        return getMaskBit(OFFSET, IS_IN_SPIN_ATTACK_BIT);
+    }
+
+    public void setInRiptideSpinAttack(boolean value) {
+        isVersionNewer(ServerVersion.V_1_13);
+        setMaskBit(OFFSET, IS_IN_SPIN_ATTACK_BIT, value);
+    }
+
+    public Optional<Vector3i> getBedPosition() {
+        isVersionNewer(ServerVersion.V_1_14);
+        return super.metadata.getIndex(offset(OFFSET,6), Optional.empty());
+    }
+
+    public void setBedPosition(Vector3i value) {
+        isVersionNewer(ServerVersion.V_1_14);
+        super.metadata.setIndex(offset(OFFSET,6), EntityDataTypes.OPTIONAL_BLOCK_POSITION, value == null ? Optional.empty() : Optional.of(value));
+    }
+
+    public int getBeeStingerCount() {
+        isVersionNewer(ServerVersion.V_1_15);
+        return super.metadata.getIndex(offset(OFFSET,5), 0);
+    }
+
+    public void setBeeStingerCount(int value) {
+        isVersionNewer(ServerVersion.V_1_15);
+        super.metadata.setIndex(offset(OFFSET,5), EntityDataTypes.INT, value);
+    }
+
+    public boolean isHandActive() {
+        isVersionNewer(ServerVersion.V_1_15);
+        return getMaskBit(OFFSET, IS_HAND_ACTIVE_BIT);
+    }
+
+    public void setHandActive(boolean value) {
+        isVersionNewer(ServerVersion.V_1_15);
+        setMaskBit(OFFSET, IS_HAND_ACTIVE_BIT, value);
+    }
+
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/types/MobMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/types/MobMeta.java
new file mode 100644
index 0000000..82310ef
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/types/MobMeta.java
@@ -0,0 +1,49 @@
+package me.tofaa.entitylib.meta.types;
+
+import com.github.retrooper.packetevents.manager.server.ServerVersion;
+import me.tofaa.entitylib.meta.EntityMeta;
+import me.tofaa.entitylib.meta.Metadata;
+
+public class MobMeta extends LivingEntityMeta {
+
+    public static final byte OFFSET = LivingEntityMeta.MAX_OFFSET;
+    public static final byte MAX_OFFSET = OFFSET + 1;
+
+    private final static byte NO_AI_BIT = 0x01;
+    private final static byte IS_LEFT_HANDED_BIT = 0x02;
+    private final static byte IS_AGGRESSIVE_BIT = 0x04;
+
+
+    public MobMeta(int entityId, Metadata metadata) {
+        super(entityId, metadata);
+    }
+
+    public boolean isNoAi() {
+        return getMaskBit(OFFSET, NO_AI_BIT);
+    }
+
+    public void setNoAi(boolean value) {
+        setMaskBit(OFFSET, NO_AI_BIT, value);
+    }
+
+    public boolean isLeftHanded() {
+        EntityMeta.isVersionNewer(ServerVersion.V_1_9);
+        return getMaskBit(OFFSET, IS_LEFT_HANDED_BIT);
+    }
+
+    public void setLeftHanded(boolean value) {
+        EntityMeta.isVersionNewer(ServerVersion.V_1_9);
+        setMaskBit(OFFSET, IS_LEFT_HANDED_BIT, value);
+    }
+
+    public boolean isAggressive() {
+        EntityMeta.isVersionNewer(ServerVersion.V_1_14);
+        return getMaskBit(OFFSET, IS_AGGRESSIVE_BIT);
+    }
+
+    public void setAggressive(boolean value) {
+        EntityMeta.isVersionNewer(ServerVersion.V_1_14);
+        setMaskBit(OFFSET, IS_AGGRESSIVE_BIT, value);
+    }
+
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/types/ObjectData.java b/api/src/main/java/me/tofaa/entitylib/meta/types/ObjectData.java
new file mode 100644
index 0000000..9d6785e
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/types/ObjectData.java
@@ -0,0 +1,9 @@
+package me.tofaa.entitylib.meta.types;
+
+public interface ObjectData {
+
+    int getObjectData();
+
+    boolean requiresVelocityPacketAtSpawn();
+
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/types/PlayerMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/types/PlayerMeta.java
new file mode 100644
index 0000000..d03ab31
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/types/PlayerMeta.java
@@ -0,0 +1,148 @@
+package me.tofaa.entitylib.meta.types;
+
+import com.github.retrooper.packetevents.manager.server.ServerVersion;
+import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
+import com.github.retrooper.packetevents.protocol.nbt.NBTCompound;
+import me.tofaa.entitylib.EntityLib;
+import me.tofaa.entitylib.meta.EntityMeta;
+import me.tofaa.entitylib.meta.Metadata;
+import org.jetbrains.annotations.Nullable;
+
+public class PlayerMeta extends LivingEntityMeta {
+
+    public static final byte OFFSET = LivingEntityMeta.MAX_OFFSET;
+    public static final byte MAX_OFFSET = OFFSET + 1;
+
+    private final static byte CAPE_BIT = 0x01;
+    private final static byte JACKET_BIT = 0x02;
+    private final static byte LEFT_SLEEVE_BIT = 0x04;
+    private final static byte RIGHT_SLEEVE_BIT = 0x08;
+    private final static byte LEFT_LEG_BIT = 0x10;
+    private final static byte RIGHT_LEG_BIT = 0x20;
+    private final static byte HAT_BIT = 0x40;
+
+    public PlayerMeta(int entityId, Metadata metadata) {
+        super(entityId, metadata);
+    }
+
+    public float getAdditionalHearts() {
+        return super.metadata.getIndex(OFFSET, 0F);
+    }
+
+    public void setAdditionalHearts(float value) {
+        super.metadata.setIndex(OFFSET, EntityDataTypes.FLOAT, value);
+    }
+
+    public int getScore() {
+        return super.metadata.getIndex(offset(OFFSET,1), 0);
+    }
+
+    public void setScore(int value) {
+        super.metadata.setIndex(offset(OFFSET,1), EntityDataTypes.INT, value);
+    }
+
+    public boolean isCapeEnabled() {
+        isVersionNewer(ServerVersion.V_1_9);
+        return getMaskBit(offset(OFFSET,2), CAPE_BIT);
+    }
+
+    public void setCapeEnabled(boolean value) {
+        isVersionNewer(ServerVersion.V_1_9);
+        setMaskBit(offset(OFFSET,2), CAPE_BIT, value);
+    }
+
+    public boolean isJacketEnabled() {
+        isVersionNewer(ServerVersion.V_1_9);
+        return getMaskBit(offset(OFFSET,2), JACKET_BIT);
+    }
+
+    public void setJacketEnabled(boolean value) {
+        isVersionNewer(ServerVersion.V_1_9);
+        setMaskBit(offset(OFFSET,2), JACKET_BIT, value);
+    }
+
+    public boolean isLeftSleeveEnabled() {
+        isVersionNewer(ServerVersion.V_1_9);
+        return getMaskBit(offset(OFFSET,2), LEFT_SLEEVE_BIT);
+    }
+
+    public void setLeftSleeveEnabled(boolean value) {
+        isVersionNewer(ServerVersion.V_1_9);
+        setMaskBit(offset(OFFSET,2), LEFT_SLEEVE_BIT, value);
+    }
+
+    public boolean isRightSleeveEnabled() {
+        isVersionNewer(ServerVersion.V_1_9);
+        return getMaskBit(offset(OFFSET,2), RIGHT_SLEEVE_BIT);
+    }
+
+    public void setRightSleeveEnabled(boolean value) {
+        isVersionNewer(ServerVersion.V_1_9);
+        setMaskBit(offset(OFFSET,2), RIGHT_SLEEVE_BIT, value);
+    }
+
+    public boolean isLeftLegEnabled() {
+        isVersionNewer(ServerVersion.V_1_9);
+        return getMaskBit(offset(OFFSET,2), LEFT_LEG_BIT);
+    }
+
+    public void setLeftLegEnabled(boolean value) {
+        isVersionNewer(ServerVersion.V_1_9);
+        setMaskBit(offset(OFFSET,2), LEFT_LEG_BIT, value);
+    }
+
+    public boolean isRightLegEnabled() {
+        isVersionNewer(ServerVersion.V_1_9);
+        return getMaskBit(offset(OFFSET,2), RIGHT_LEG_BIT);
+    }
+
+    public void setRightLegEnabled(boolean value) {
+        isVersionNewer(ServerVersion.V_1_9);
+        setMaskBit(offset(OFFSET,2), RIGHT_LEG_BIT, value);
+    }
+
+    public boolean isHatEnabled() {
+        isVersionNewer(ServerVersion.V_1_9);
+        return getMaskBit(offset(OFFSET,2), HAT_BIT);
+    }
+
+    public void setHatEnabled(boolean value) {
+        isVersionNewer(ServerVersion.V_1_9);
+        setMaskBit(offset(OFFSET,2), HAT_BIT, value);
+    }
+
+    public boolean isRightHandMain() {
+        if (EntityLib.getApi().getPacketEvents().getServerManager().getVersion().isOlderThan(ServerVersion.V_1_9)) {
+            return true;
+        }
+        return super.metadata.getIndex(offset(OFFSET,3), (byte) 1) == (byte) 1;
+    }
+
+    public void setRightHandMain(boolean value) {
+        if (EntityLib.getApi().getPacketEvents().getServerManager().getVersion().isOlderThan(ServerVersion.V_1_9)) {
+            return;
+        }
+        super.metadata.setIndex(offset(OFFSET,3), EntityDataTypes.BYTE, (byte) (value ? 1 : 0));
+    }
+
+    public @Nullable NBTCompound getLeftShoulderData() {
+        isVersionNewer(ServerVersion.V_1_11);
+        return super.metadata.getIndex(offset(OFFSET,4), null);
+    }
+
+    public void setLeftShoulderData(@Nullable NBTCompound value) {
+        if (value == null) value = new NBTCompound();
+        super.metadata.setIndex(offset(OFFSET,4), EntityDataTypes.NBT, value);
+    }
+
+    public @Nullable NBTCompound getRightShoulderData() {
+        isVersionNewer(ServerVersion.V_1_11);
+        return super.metadata.getIndex(offset(OFFSET,5), null);
+    }
+
+    public void setRightShoulderData(@Nullable NBTCompound value) {
+        if (value == null) value = new NBTCompound();
+        super.metadata.setIndex(offset(OFFSET,5), EntityDataTypes.NBT, value);
+    }
+
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/types/ProjectileMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/types/ProjectileMeta.java
new file mode 100644
index 0000000..2560967
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/types/ProjectileMeta.java
@@ -0,0 +1,10 @@
+package me.tofaa.entitylib.meta.types;
+
+
+public interface ProjectileMeta  {
+
+    int getShooter();
+
+    void setShooter(int entityId);
+
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/types/TameableMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/types/TameableMeta.java
new file mode 100644
index 0000000..0db1569
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/types/TameableMeta.java
@@ -0,0 +1,46 @@
+package me.tofaa.entitylib.meta.types;
+
+import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
+import me.tofaa.entitylib.meta.Metadata;
+
+import java.util.Optional;
+import java.util.UUID;
+
+public class TameableMeta extends AgeableMeta{
+
+    public static final byte OFFSET = AgeableMeta.MAX_OFFSET;
+    public static final byte MAX_OFFSET = OFFSET + 2;
+
+    private final static byte SITTING_BIT = 0x01;
+    private final static byte TAMED_BIT = 0x04;
+
+    public TameableMeta(int entityId, Metadata metadata) {
+        super(entityId, metadata);
+    }
+
+
+    public boolean isSitting() {
+        return getMaskBit(OFFSET, SITTING_BIT);
+    }
+
+    public void setSitting(boolean value) {
+        setMaskBit(OFFSET, SITTING_BIT, value);
+    }
+
+    public boolean isTamed() {
+        return getMaskBit(OFFSET, TAMED_BIT);
+    }
+
+    public void setTamed(boolean value) {
+        setMaskBit(OFFSET, TAMED_BIT, value);
+    }
+
+    public Optional<UUID> getOwner() {
+        return super.metadata.getIndex(offset(OFFSET, 1), Optional.empty());
+    }
+
+    public void setOwner(UUID value) {
+        super.metadata.setIndex(offset(OFFSET, 1), EntityDataTypes.OPTIONAL_UUID, Optional.ofNullable(value));
+    }
+
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/types/WaterMobMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/types/WaterMobMeta.java
new file mode 100644
index 0000000..5b99469
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/types/WaterMobMeta.java
@@ -0,0 +1,13 @@
+package me.tofaa.entitylib.meta.types;
+
+import me.tofaa.entitylib.meta.Metadata;
+
+public class WaterMobMeta extends MobMeta {
+
+    public static final byte OFFSET = MobMeta.MAX_OFFSET;
+    public static final byte MAX_OFFSET = OFFSET + 0;
+
+    public WaterMobMeta(int entityId, Metadata metadata) {
+        super(entityId, metadata);
+    }
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperEntity.java b/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperEntity.java
new file mode 100644
index 0000000..32e33d6
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperEntity.java
@@ -0,0 +1,204 @@
+package me.tofaa.entitylib.wrapper;
+
+import com.github.retrooper.packetevents.protocol.entity.type.EntityType;
+import com.github.retrooper.packetevents.protocol.player.User;
+import com.github.retrooper.packetevents.protocol.world.Location;
+import com.github.retrooper.packetevents.util.Vector3d;
+import com.github.retrooper.packetevents.wrapper.PacketWrapper;
+import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerDestroyEntities;
+import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerEntityRotation;
+import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerEntityVelocity;
+import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerSpawnEntity;
+import me.tofaa.entitylib.EntityLib;
+import me.tofaa.entitylib.meta.EntityMeta;
+import me.tofaa.entitylib.tick.Tickable;
+import org.jetbrains.annotations.NotNull;
+
+import javax.swing.text.html.parser.Entity;
+import java.util.Collections;
+import java.util.Optional;
+import java.util.Set;
+import java.util.UUID;
+
+public class WrapperEntity implements Tickable {
+
+    private final UUID uuid;
+    private final int entityId;
+
+    private EntityType entityType;
+    private EntityMeta entityMeta;
+    private Location location;
+    private Set<UUID> viewers;
+    private boolean onGround;
+    private boolean spawned;
+    private Vector3d velocity;
+
+
+    public WrapperEntity(int entityId, UUID uuid, EntityType entityType, EntityMeta entityMeta) {
+        this.entityId = entityId;
+        this.uuid = uuid;
+        this.entityType = entityType;
+        this.entityMeta = entityMeta;
+    }
+
+    public void spawn() {}
+
+    public void despawn() {}
+
+    public void teleport(@NotNull Location location) {
+        this.location = location;
+
+    }
+
+    public boolean addViewer(UUID uuid) {
+        if (!viewers.add(uuid)) {
+            return false;
+        }
+        if (!spawned) return false;
+        WrapperPlayServerSpawnEntity packet = new WrapperPlayServerSpawnEntity(
+                entityId,
+                Optional.of(this.uuid),
+                entityType,
+                location.getPosition(),
+                location.getPitch(),
+                location.getYaw(),
+                location.getYaw(),
+                0,
+                Optional.empty()
+        );
+        sendPacket(uuid, packet);
+        sendPacket(uuid, entityMeta.createPacket());
+        return true;
+    }
+
+    public void addViewer(User user) {
+        addViewer(user.getUUID());
+    }
+
+    public void removeViewer(UUID uuid) {
+        if (!viewers.remove(uuid)) {
+            return;
+        }
+        sendPacket(uuid, new WrapperPlayServerDestroyEntities(entityId));
+    }
+
+    public boolean isOnGround() {
+        return onGround;
+    }
+
+    public Vector3d getVelocity() {
+        return velocity;
+    }
+
+    public void setVelocity(Vector3d velocity) {
+        this.velocity = velocity;
+        sendPacketToViewers(getVelocityPacket());
+    }
+
+    public double getX() {
+        return location.getX();
+    }
+
+    public double getY() {
+        return location.getY();
+    }
+
+    public double getZ() {
+        return location.getZ();
+    }
+
+    public float getYaw() {
+        return location.getYaw();
+    }
+
+    public float getPitch() {
+        return location.getPitch();
+    }
+
+    public int getEntityId() {
+        return entityId;
+    }
+
+    public EntityMeta getEntityMeta() {
+        return entityMeta;
+    }
+
+    public UUID getUuid() {
+        return uuid;
+    }
+
+    public EntityType getEntityType() {
+        return entityType;
+    }
+
+
+    private WrapperPlayServerEntityVelocity getVelocityPacket() {
+        Vector3d velocity = this.velocity.multiply(8000.0f / 20.0f);
+        return new WrapperPlayServerEntityVelocity(entityId, velocity);
+    }
+
+    public boolean hasVelocity() {
+        if (isOnGround()) {
+            // if the entity is on the ground and only "moves" downwards, it does not have a velocity.
+            return Double.compare(velocity.x, 0) != 0 || Double.compare(velocity.z, 0) != 0 || velocity.y > 0;
+        } else {
+            // The entity does not have velocity if the velocity is zero
+            return !velocity.equals(Vector3d.zero());
+        }
+    }
+
+    public void rotateHead(float yaw, float pitch) {
+        sendPacketToViewers(
+                new WrapperPlayServerEntityRotation(entityId, yaw, pitch, onGround)
+        );
+    }
+
+    public void rotateHead(Location location) {
+        rotateHead(location.getYaw(), location.getPitch());
+    }
+
+    public void rotateHead(WrapperEntity entity) {
+        rotateHead(entity.getLocation());
+    }
+
+    public void refresh() {
+        if (!spawned) return;
+        sendPacketToViewers(entityMeta.createPacket());
+    }
+
+    public void sendPacketToViewers(PacketWrapper<?> packet) {
+        viewers.forEach(uuid -> sendPacket(uuid, packet));
+    }
+
+    public void sendPacketsToViewers(PacketWrapper<?>... wrappers) {
+        for (PacketWrapper<?> wrapper : wrappers) {
+            sendPacketToViewers(wrapper);
+        }
+    }
+
+    private static void sendPacket(UUID user, PacketWrapper<?> wrapper) {
+        EntityLib.getApi().getPacketEvents().getProtocolManager().sendPacket(EntityLib.getApi().getPacketEvents().getProtocolManager().getChannel(user), wrapper);
+    }
+
+    public boolean hasNoGravity() {
+        return entityMeta.isHasNoGravity();
+    }
+
+    public void setHasNoGravity(boolean hasNoGravity) {
+        entityMeta.setHasNoGravity(hasNoGravity);
+        refresh();
+    }
+
+    public @NotNull Set<UUID> getViewers() {
+        return Collections.unmodifiableSet(viewers);
+    }
+
+    public Location getLocation() {
+        return location;
+    }
+
+    @Override
+    public void tick(long time) {
+
+    }
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperEntityCreature.java b/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperEntityCreature.java
new file mode 100644
index 0000000..b797dfa
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperEntityCreature.java
@@ -0,0 +1,75 @@
+package me.tofaa.entitylib.wrapper;
+
+import com.github.retrooper.packetevents.protocol.entity.type.EntityType;
+import me.tofaa.entitylib.meta.EntityMeta;
+import me.tofaa.entitylib.wrapper.ai.AIGroup;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.UUID;
+
+/**
+ * Represents a {@link WrapperEntity} with goals, AI and pathfinding.
+ * <p>
+ *     <br>
+ *     Creature entities require some sort of ticking mechanism on your server to work properly. They need to be dynamically updated every tick.
+ *     Goal and Target selectors are grouped into AIGroups, which are then added to the entity. The AIGroups are then updated every tick.
+ *     <br>
+ *     The {@link WrapperEntityCreature} can be inherited to create custom entities.
+ * </p>
+ */
+public class WrapperEntityCreature extends WrapperLivingEntity {
+
+    private final Set<AIGroup> aiGroups;
+
+    public WrapperEntityCreature(int entityId, @NotNull UUID uuid, EntityType entityType, EntityMeta meta) {
+        super(entityId, uuid, entityType, meta);
+        this.aiGroups = new HashSet<>();
+    }
+
+    @Override
+    public void tick(long time) {
+        super.tick(time);
+        aiGroups.forEach(aiGroup -> aiGroup.update(time));
+    }
+
+    /**
+     * Adds an {@link AIGroup} to the entity.
+     * <p>
+     * The AIGroup will be updated every tick.
+     * </p>
+     *
+     * @param aiGroup The AIGroup to add.
+     */
+    public void addAIGroup(AIGroup aiGroup) {
+        aiGroups.add(aiGroup);
+    }
+
+    /**
+     * Removes an {@link AIGroup} from the entity.
+     *
+     * @param aiGroup The AIGroup to remove.
+     */
+    public void removeAIGroup(AIGroup aiGroup) {
+        aiGroups.remove(aiGroup);
+    }
+
+    /**
+     * Removes all {@link AIGroup}s from the entity.
+     */
+    public void clearAIGroups() {
+        aiGroups.clear();
+    }
+
+    /**
+     * Gets the {@link AIGroup}s of the entity.
+     *
+     * @return The AIGroups of the entity.
+     */
+    public Set<AIGroup> getAIGroups() {
+        return Collections.unmodifiableSet(aiGroups);
+    }
+
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperEntityEquipment.java b/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperEntityEquipment.java
new file mode 100644
index 0000000..99b9a67
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperEntityEquipment.java
@@ -0,0 +1,119 @@
+package me.tofaa.entitylib.wrapper;
+
+import com.github.retrooper.packetevents.manager.server.ServerVersion;
+import com.github.retrooper.packetevents.protocol.item.ItemStack;
+import com.github.retrooper.packetevents.protocol.player.Equipment;
+import com.github.retrooper.packetevents.protocol.player.EquipmentSlot;
+import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerEntityEquipment;
+import me.tofaa.entitylib.EntityLib;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import static me.tofaa.entitylib.extras.VersionChecker.verifyVersion;
+
+public class WrapperEntityEquipment {
+
+    private static final EquipmentSlot[] EQUIPMENT_SLOTS = EquipmentSlot.values();
+
+    private final WrapperLivingEntity entity;
+
+
+    // 0 = main hand, 1 = offhand, 2 = boots, 3 = leggings, 4 = chestplate, 5 = helmet
+    private final ItemStack[] equipment = new ItemStack[6];
+
+    public WrapperEntityEquipment(WrapperLivingEntity entity) {
+        this.entity = entity;
+        Arrays.fill(equipment, ItemStack.EMPTY);
+    }
+
+    public void setHelmet(@NotNull ItemStack itemStack) {
+        equipment[5] = itemStack;
+        refresh();
+    }
+
+    public void setChestplate(@NotNull ItemStack itemStack) {
+        equipment[4] = itemStack;
+        refresh();
+    }
+
+    public void setLeggings(@NotNull ItemStack itemStack) {
+        equipment[3] = itemStack;
+        refresh();
+    }
+
+    public void setBoots(@NotNull ItemStack itemStack) {
+        equipment[2] = itemStack;
+        refresh();
+    }
+
+    public void setMainHand(@NotNull ItemStack itemStack) {
+        equipment[0] = itemStack;
+        refresh();
+    }
+
+    public void setOffhand(@NotNull ItemStack itemStack) {
+        verifyVersion(ServerVersion.V_1_9, "Offhand is only supported on 1.9+");
+        equipment[1] = itemStack;
+        refresh();
+    }
+
+    public void setItem(@NotNull EquipmentSlot slot, @NotNull ItemStack itemStack) {
+        equipment[slot.ordinal()]  = itemStack;
+        refresh();
+    }
+
+    public @NotNull ItemStack getItem(@NotNull EquipmentSlot slot) {
+        ItemStack itemStack = equipment[slot.ordinal()];
+        if (itemStack == null) {
+            return ItemStack.EMPTY;
+        }
+        return itemStack;
+    }
+
+    public @NotNull ItemStack getHelmet() {
+        return getItem(EquipmentSlot.HELMET);
+    }
+
+    public @NotNull ItemStack getChestplate() {
+        return getItem(EquipmentSlot.CHEST_PLATE);
+    }
+
+    public @NotNull ItemStack getLeggings() {
+        return getItem(EquipmentSlot.LEGGINGS);
+    }
+
+    public @NotNull ItemStack getBoots() {
+        return getItem(EquipmentSlot.BOOTS);
+    }
+
+    public @NotNull ItemStack getMainHand() {
+        return getItem(EquipmentSlot.MAIN_HAND);
+    }
+
+    public @NotNull ItemStack getOffhand() {
+        verifyVersion(ServerVersion.V_1_9, "Offhand is only supported on 1.9+");
+        return getItem(EquipmentSlot.OFF_HAND);
+    }
+
+    public WrapperPlayServerEntityEquipment createPacket() {
+        List<Equipment> equipment = new ArrayList<>();
+        for (int i = 0; i < this.equipment.length; i++) {
+            ItemStack itemStack = this.equipment[i];
+            if (itemStack == null || itemStack.equals(ItemStack.EMPTY)) continue;
+            equipment.add(new Equipment(EQUIPMENT_SLOTS[i], itemStack));
+        }
+        return new WrapperPlayServerEntityEquipment(
+                entity.getEntityId(),
+                equipment
+        );
+    }
+
+
+    public void refresh() {
+        this.entity.sendPacketToViewers(createPacket());
+    }
+
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperExperienceOrbEntity.java b/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperExperienceOrbEntity.java
new file mode 100644
index 0000000..c880847
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperExperienceOrbEntity.java
@@ -0,0 +1,70 @@
+package me.tofaa.entitylib.wrapper;
+
+import com.github.retrooper.packetevents.protocol.entity.type.EntityType;
+import com.github.retrooper.packetevents.protocol.world.Location;
+import com.github.retrooper.packetevents.util.Vector3d;
+import me.tofaa.entitylib.meta.EntityMeta;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.UUID;
+
+public class WrapperExperienceOrbEntity extends WrapperEntity {
+
+    private short experience;
+    private Location slideTowards;
+
+    public WrapperExperienceOrbEntity(int entityId, @NotNull UUID uuid, EntityType entityType, EntityMeta meta) {
+        super(entityId, uuid, entityType, meta);
+    }
+
+    /**
+     * Applies a slight slide motion towards the given location.
+     * <p>
+     *     For this to work, this method needs to be called every tick until the entity reaches the location.
+     *     We don't have ticking or updating in this library, so you'll have to do it yourself.
+     *     This is an attempt to mimmick the vanilla behavior.
+     * </p>
+     */
+    public void updateSliding() {
+        if (hasNoGravity()) {
+            setVelocity(getVelocity().add(0, -0.3f, 0));
+        }
+
+        double d = 8.0;
+        Vector3d distance = new Vector3d(slideTowards.getX() - getX(), slideTowards.getY() - getY(), slideTowards.getZ() - getZ());
+        double length = distance.length();
+        if (length < 8.0) {
+            double f = 1 - (length / 8);
+            setVelocity(getVelocity().add(distance.normalize().multiply(f * f * 0.1)));
+        }
+        float g = 0.98f;
+        if (this.isOnGround()) {
+            g = 0.6f * 0.98f;
+        }
+        setVelocity(getVelocity().multiply(g, 0.98f, g));
+        if (isOnGround()) {
+            setVelocity(getVelocity().multiply(1, -0.9f, 1));
+        }
+    }
+
+    public Location getSlideTowards() {
+        return slideTowards;
+    }
+
+    public void setSlideTowards(Location slideTowards) {
+        this.slideTowards = slideTowards;
+    }
+
+    public short getExperience() {
+        return experience;
+    }
+
+
+
+    public void setExperience(short experience) {
+        getViewers().forEach(this::removeViewer);
+        this.experience = experience;
+        getViewers().forEach(this::addViewer);
+    }
+
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperLivingEntity.java b/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperLivingEntity.java
new file mode 100644
index 0000000..835be99
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperLivingEntity.java
@@ -0,0 +1,16 @@
+package me.tofaa.entitylib.wrapper;
+
+import com.github.retrooper.packetevents.protocol.entity.type.EntityType;
+import me.tofaa.entitylib.meta.EntityMeta;
+
+import java.util.UUID;
+
+public class WrapperLivingEntity extends WrapperEntity{
+
+
+
+
+    public WrapperLivingEntity(int entityId, UUID uuid, EntityType entityType, EntityMeta entityMeta) {
+        super(entityId, uuid, entityType, entityMeta);
+    }
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/wrapper/ai/AIGroup.java b/api/src/main/java/me/tofaa/entitylib/wrapper/ai/AIGroup.java
new file mode 100644
index 0000000..99992b5
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/wrapper/ai/AIGroup.java
@@ -0,0 +1,70 @@
+package me.tofaa.entitylib.wrapper.ai;
+
+import me.tofaa.entitylib.tick.Tickable;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.Collection;
+import java.util.List;
+
+public class AIGroup implements Tickable {
+
+    private final List<GoalSelector> goalSelectors = new GoalSelectorList(this);
+    private GoalSelector currentGoalSelector;
+
+    public @NotNull Collection<GoalSelector> getGoalSelectors() {
+        return goalSelectors;
+    }
+
+    public @Nullable GoalSelector getCurrentGoal() {
+        return currentGoalSelector;
+    }
+
+    /**
+     * Adds a goal selector to the end of the list. Might be potentially unsafe to use after the entity has been spawned.
+     *
+     * @param goalSelector the goal selector to add
+     */
+    public void addGoalSelector(@NotNull GoalSelector goalSelector) {
+        this.goalSelectors.add(goalSelector);
+    }
+
+    public void setCurrentGoal(@Nullable GoalSelector goalSelector) {
+        if (goalSelector != null && goalSelector.getAIGroup() != this) {
+            throw new IllegalArgumentException("GoalSelector is not in this AIGroup");
+        }
+        currentGoalSelector = goalSelector;
+    }
+
+    @Override
+    public void tick(long time) {
+        GoalSelector currentGoalSelector = getCurrentGoal();
+
+        if (currentGoalSelector != null && currentGoalSelector.shouldEnd()) {
+            currentGoalSelector.end();
+            currentGoalSelector = null;
+            setCurrentGoal(null);
+        }
+
+        for (GoalSelector selector : getGoalSelectors()) {
+            if (selector == currentGoalSelector) {
+                break;
+            }
+            if (selector.shouldStart()) {
+                if (currentGoalSelector != null) {
+                    currentGoalSelector.end();
+                }
+                currentGoalSelector = selector;
+                setCurrentGoal(currentGoalSelector);
+                currentGoalSelector.start();
+                break;
+            }
+        }
+
+        if (currentGoalSelector != null) {
+            currentGoalSelector.tick(time);
+        }
+    }
+
+
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/wrapper/ai/GoalSelector.java b/api/src/main/java/me/tofaa/entitylib/wrapper/ai/GoalSelector.java
new file mode 100644
index 0000000..e6bbf3d
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/wrapper/ai/GoalSelector.java
@@ -0,0 +1,85 @@
+package me.tofaa.entitylib.wrapper.ai;
+
+import me.tofaa.entitylib.wrapper.WrapperEntityCreature;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.lang.ref.WeakReference;
+
+/**
+ * Goals represent tasks that a {@link me.tofaa.entitylib.wrapper.WrapperEntityCreature} can perform.
+ */
+public abstract class GoalSelector {
+
+    private WeakReference<AIGroup> aiGroupRef;
+    protected WrapperEntityCreature entity;
+
+    public GoalSelector(WrapperEntityCreature entity) {
+        this.entity = entity;
+    }
+
+    /**
+     * Whether this {@link GoalSelector} should start.
+     *
+     * @return true to start
+     */
+    public abstract boolean shouldStart();
+
+    /**
+     * Starts this {@link GoalSelector}.
+     */
+    public abstract void start();
+
+    /**
+     * Called every tick when this {@link GoalSelector} is running.
+     *
+     * @param time the time of the update in milliseconds
+     */
+    public abstract void tick(long time);
+
+    /**
+     * Whether this {@link GoalSelector} should end.
+     *
+     * @return true to end
+     */
+    public abstract boolean shouldEnd();
+
+    /**
+     * Ends this {@link GoalSelector}.
+     */
+    public abstract void end();
+
+
+    /**
+     * Gets the entity behind the goal selector.
+     *
+     * @return the entity
+     */
+    @NotNull
+    public WrapperEntityCreature getEntityCreature() {
+        return entity;
+    }
+
+    /**
+     * Changes the entity affected by the goal selector.
+     * <p>
+     * WARNING: this does not add the goal selector to {@code entityCreature},
+     * this only change the internal entity AI group's field. Be sure to remove the goal from
+     * the previous entity AI group and add it to the new one using {@link AIGroup#getGoalSelectors()}.
+     *
+     * @param entity the new affected entity
+     */
+    public void setEntityCreature(@NotNull WrapperEntityCreature entity) {
+        this.entity = entity;
+    }
+
+    void setAIGroup(@NotNull AIGroup group) {
+        this.aiGroupRef = new WeakReference<>(group);
+    }
+
+    @Nullable
+    protected AIGroup getAIGroup() {
+        return this.aiGroupRef.get();
+    }
+
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/wrapper/ai/GoalSelectorList.java b/api/src/main/java/me/tofaa/entitylib/wrapper/ai/GoalSelectorList.java
new file mode 100644
index 0000000..9971945
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/wrapper/ai/GoalSelectorList.java
@@ -0,0 +1,55 @@
+package me.tofaa.entitylib.wrapper.ai;
+
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.function.UnaryOperator;
+
+final class GoalSelectorList extends ArrayList<GoalSelector> {
+
+    final AIGroup aiGroup;
+
+    GoalSelectorList(AIGroup aiGroup) {
+        this.aiGroup = aiGroup;
+    }
+
+    @Override
+    public GoalSelector set(int index, GoalSelector element) {
+        element.setAIGroup(aiGroup);
+        return super.set(index, element);
+    }
+
+    @Override
+    public boolean add(GoalSelector element) {
+        element.setAIGroup(aiGroup);
+        return super.add(element);
+    }
+
+    @Override
+    public void add(int index, GoalSelector element) {
+        element.setAIGroup(aiGroup);
+        super.add(index, element);
+    }
+
+    @Override
+    public boolean addAll(Collection<? extends GoalSelector> c) {
+        c.forEach(goalSelector -> goalSelector.setAIGroup(aiGroup));
+        return super.addAll(c);
+    }
+
+    @Override
+    public boolean addAll(int index, Collection<? extends GoalSelector> c) {
+        c.forEach(goalSelector -> goalSelector.setAIGroup(aiGroup));
+        return super.addAll(index, c);
+    }
+
+    @Override
+    public void replaceAll(UnaryOperator<GoalSelector> operator) {
+        super.replaceAll(goalSelector -> {
+            goalSelector = operator.apply(goalSelector);
+            goalSelector.setAIGroup(aiGroup);
+            return goalSelector;
+        });
+    }
+
+}
\ No newline at end of file
diff --git a/api/src/main/java/me/tofaa/entitylib/wrapper/ai/goals/RandomHeadMovementGoal.java b/api/src/main/java/me/tofaa/entitylib/wrapper/ai/goals/RandomHeadMovementGoal.java
new file mode 100644
index 0000000..973151c
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/wrapper/ai/goals/RandomHeadMovementGoal.java
@@ -0,0 +1,81 @@
+package me.tofaa.entitylib.wrapper.ai.goals;
+
+import com.github.retrooper.packetevents.util.Vector3d;
+import me.tofaa.entitylib.extras.CoordinateUtil;
+import me.tofaa.entitylib.wrapper.WrapperEntityCreature;
+import me.tofaa.entitylib.wrapper.ai.GoalSelector;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Random;
+import java.util.function.Function;
+import java.util.function.Supplier;
+
+public class RandomHeadMovementGoal extends GoalSelector {
+
+    private static final Random RANDOM = new Random();
+    private final int chancePerTick;
+    private final Supplier<Integer> minimalLookTimeSupplier;
+    private final Function<WrapperEntityCreature, Vector3d> randomDirectionFunction;
+    private Vector3d lookDirection;
+    private int lookTime = 0;
+
+    public RandomHeadMovementGoal(WrapperEntityCreature entityCreature, int chancePerTick) {
+        this(entityCreature, chancePerTick,
+                // These two functions act similarly enough to how MC randomly looks around.
+                // Look in one direction for at most 40 ticks and at minimum 20 ticks.
+                () -> 20 + RANDOM.nextInt(20),
+                // Look at a random block
+                (creature) -> {
+                    final double n = Math.PI * 2 * RANDOM.nextDouble();
+                    return new Vector3d(
+                            (float) Math.cos(n),
+                            0,
+                            (float) Math.sin(n)
+                    );
+                });
+    }
+
+    /**
+     * @param entityCreature          Creature that should randomly look around.
+     * @param chancePerTick           The chance (per tick) that the entity looks around. Setting this to N would mean there is a 1 in N chance.
+     * @param minimalLookTimeSupplier A supplier that returns the minimal amount of time an entity looks in a direction.
+     * @param randomDirectionFunction A function that returns a random vector that the entity will look in/at.
+     */
+    public RandomHeadMovementGoal(
+            WrapperEntityCreature entityCreature,
+            int chancePerTick,
+            @NotNull Supplier<Integer> minimalLookTimeSupplier,
+            @NotNull Function<WrapperEntityCreature, Vector3d> randomDirectionFunction) {
+        super(entityCreature);
+        this.chancePerTick = chancePerTick;
+        this.minimalLookTimeSupplier = minimalLookTimeSupplier;
+        this.randomDirectionFunction = randomDirectionFunction;
+    }
+
+    @Override
+    public boolean shouldStart() {
+        return RANDOM.nextInt(chancePerTick) == 0;
+    }
+
+    @Override
+    public void start() {
+        lookTime = minimalLookTimeSupplier.get();
+        lookDirection = randomDirectionFunction.apply(entity);
+    }
+
+    @Override
+    public void tick(long time) {
+        --lookTime;
+        entity.teleport(CoordinateUtil.withDirection(entity.getLocation(), lookDirection));
+    }
+
+    @Override
+    public boolean shouldEnd() {
+        return this.lookTime < 0;
+    }
+
+    @Override
+    public void end() {
+
+    }
+}
diff --git a/common/build.gradle b/common/build.gradle
new file mode 100644
index 0000000..4cb63f2
--- /dev/null
+++ b/common/build.gradle
@@ -0,0 +1,15 @@
+plugins {
+    id 'java'
+    id 'java-library'
+}
+
+group = 'org.example'
+version = '1.0-SNAPSHOT'
+
+repositories {
+    mavenCentral()
+}
+
+dependencies {
+    api(project(":api"))
+}
diff --git a/common/src/main/java/me/tofaa/entitylib/common/AbstractEntityLibAPI.java b/common/src/main/java/me/tofaa/entitylib/common/AbstractEntityLibAPI.java
new file mode 100644
index 0000000..97e35da
--- /dev/null
+++ b/common/src/main/java/me/tofaa/entitylib/common/AbstractEntityLibAPI.java
@@ -0,0 +1,44 @@
+package me.tofaa.entitylib.common;
+
+import com.github.retrooper.packetevents.PacketEventsAPI;
+import me.tofaa.entitylib.APISettings;
+import me.tofaa.entitylib.EntityLibAPI;
+import me.tofaa.entitylib.Platform;
+import me.tofaa.entitylib.tick.TickContainer;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+
+public abstract class AbstractEntityLibAPI<P, W, T> implements EntityLibAPI<W, T> {
+
+    protected final Platform<P> platform;
+    protected final PacketEventsAPI<?> packetEvents;
+    protected final APISettings settings;
+    protected final Collection<TickContainer<?, T>> tickContainers;
+
+    protected AbstractEntityLibAPI(Platform<P> platform, APISettings settings) {
+        this.platform = platform;
+        this.packetEvents = settings.getPacketEvents();
+        this.settings = settings;
+        this.tickContainers = settings.shouldTickTickables() ? new HashSet<>() : Collections.emptyList();
+    }
+
+    @NotNull
+    @Override
+    public APISettings getSettings() {
+        return settings;
+    }
+
+    @Override
+    public PacketEventsAPI<?> getPacketEvents() {
+        return packetEvents;
+    }
+
+    @NotNull
+    @Override
+    public Collection<TickContainer<?, T>> getTickContainers() {
+        return tickContainers;
+    }
+}
diff --git a/common/src/main/java/me/tofaa/entitylib/common/AbstractPlatform.java b/common/src/main/java/me/tofaa/entitylib/common/AbstractPlatform.java
new file mode 100644
index 0000000..a218723
--- /dev/null
+++ b/common/src/main/java/me/tofaa/entitylib/common/AbstractPlatform.java
@@ -0,0 +1,76 @@
+package me.tofaa.entitylib.common;
+
+import me.tofaa.entitylib.APISettings;
+import me.tofaa.entitylib.EntityIdProvider;
+import me.tofaa.entitylib.EntityUuidProvider;
+import me.tofaa.entitylib.Platform;
+import me.tofaa.entitylib.event.EventBus;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.logging.Logger;
+
+public abstract class AbstractPlatform<P> implements Platform<P> {
+
+
+    protected final P handle;
+    protected Logger logger;
+    private EventBus eventBus;
+    private EntityIdProvider entityIdProvider;
+    private EntityUuidProvider entityUuidProvider;
+
+    public AbstractPlatform(P handle) {
+        this.handle = handle;
+        this.entityIdProvider = new EntityIdProvider.DefaultEntityIdProvider();
+        this.entityUuidProvider = new EntityUuidProvider.DefaultEntityUuidProvider();
+    }
+
+
+    @Override
+    public void setupApi(@NotNull APISettings settings) {
+        this.eventBus = EventBus.newBus(settings.shouldUseAsyncEvents());
+        this.entityIdProvider = new EntityIdProvider.DefaultEntityIdProvider();
+        this.entityUuidProvider = new EntityUuidProvider.DefaultEntityUuidProvider();
+
+
+    }
+
+    @NotNull
+    @Override
+    public Logger getLogger() {
+        return logger;
+    }
+
+    @NotNull
+    @Override
+    public EntityIdProvider getEntityIdProvider() {
+        return entityIdProvider;
+    }
+
+    @NotNull
+    @Override
+    public EntityUuidProvider getEntityUuidProvider() {
+        return entityUuidProvider;
+    }
+
+    @Override
+    public void setEntityIdProvider(EntityIdProvider entityIdProvider) {
+        this.entityIdProvider = entityIdProvider;
+    }
+
+    @Override
+    public void setEntityUuidProvider(EntityUuidProvider entityUuidProvider) {
+        this.entityUuidProvider = entityUuidProvider;
+    }
+
+    @NotNull
+    @Override
+    public EventBus getEventBus() {
+        return eventBus;
+    }
+
+    @NotNull
+    @Override
+    public P getHandle() {
+        return handle;
+    }
+}
diff --git a/common/src/main/java/me/tofaa/entitylib/common/AbstractWorldWrapper.java b/common/src/main/java/me/tofaa/entitylib/common/AbstractWorldWrapper.java
new file mode 100644
index 0000000..2fbaa67
--- /dev/null
+++ b/common/src/main/java/me/tofaa/entitylib/common/AbstractWorldWrapper.java
@@ -0,0 +1,102 @@
+package me.tofaa.entitylib.common;
+
+import com.github.retrooper.packetevents.protocol.entity.type.EntityType;
+import com.github.retrooper.packetevents.protocol.world.Dimension;
+import com.github.retrooper.packetevents.protocol.world.Location;
+import me.tofaa.entitylib.EntityLib;
+import me.tofaa.entitylib.WorldWrapper;
+import me.tofaa.entitylib.meta.EntityMeta;
+import me.tofaa.entitylib.meta.types.LivingEntityMeta;
+import me.tofaa.entitylib.wrapper.WrapperEntity;
+import me.tofaa.entitylib.wrapper.WrapperLivingEntity;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Map;
+import java.util.UUID;
+import java.util.concurrent.ConcurrentHashMap;
+
+public abstract class AbstractWorldWrapper<W> implements WorldWrapper<W> {
+
+    private final Map<UUID, WrapperEntity> entities;
+    private final Map<Integer, WrapperEntity> entitiesById;
+    private final Dimension dimension;
+    private final UUID worldId;
+    private final W handle;
+
+    public AbstractWorldWrapper(UUID worldId, W handle, Dimension dimension) {
+        this.worldId = worldId;
+        this.handle = handle;
+        this.dimension = dimension;
+        this.entities = new ConcurrentHashMap<>();
+        this.entitiesById = Collections.emptyMap();
+    }
+
+
+    @Override
+    public <T extends WrapperEntity> @NotNull T spawnEntity(@NotNull T entity, @NotNull Location location) {
+        entity.teleport(location);
+        entity.spawn();
+        entities.put(entity.getUuid(), entity);
+        entitiesById.put(entity.getEntityId(), entity);
+        return entity;
+    }
+
+    @Override
+    public <T extends WrapperEntity> @NotNull T spawnEntity(Class<T> wrapperClass, @NotNull EntityType entityType, @NotNull Location location) {
+        UUID uuid = EntityLib.getPlatform().getEntityUuidProvider().provide(entityType);
+        while (entities.containsKey(uuid)) {
+            uuid = EntityLib.getPlatform().getEntityUuidProvider().provide(entityType);
+        }
+        int entityId = EntityLib.getPlatform().getEntityIdProvider().provide(uuid, entityType);
+        while (entitiesById.containsKey(entityId)) {
+            entityId = EntityLib.getPlatform().getEntityIdProvider().provide(uuid, entityType);
+        }
+        EntityMeta meta = EntityMeta.createMeta(entityId, entityType);
+        WrapperEntity e;
+        if (meta instanceof LivingEntityMeta) {
+            e = new WrapperLivingEntity(entityId, uuid, entityType, meta);
+        }
+        else {
+            e = new WrapperEntity(entityId, uuid, entityType, meta);
+        }
+        return spawnEntity(wrapperClass.cast(e), location);
+    }
+
+    @Override
+    public @NotNull WrapperEntity spawnEntity(@NotNull EntityType entityType, @NotNull Location location) {
+        return spawnEntity(WrapperEntity.class, entityType, location);
+    }
+
+    @Override @Nullable
+    public WrapperEntity getEntity(@NotNull UUID uuid) {
+        return entities.get(uuid);
+    }
+
+    @Override @Nullable
+    public WrapperEntity getEntity(int id) {
+        return entitiesById.get(id);
+    }
+
+    @Override @NotNull
+    public Collection<WrapperEntity> getEntities() {
+        return Collections.unmodifiableCollection(entities.values());
+    }
+
+    @NotNull @Override
+    public Dimension getDimension() {
+        return dimension;
+    }
+
+    @Override @NotNull
+    public UUID getUuid() {
+        return worldId;
+    }
+
+    @NotNull @Override
+    public W getHandle() {
+        return handle;
+    }
+}
diff --git a/platforms/spigot/build.gradle b/platforms/spigot/build.gradle
index 90169d6..f74503b 100644
--- a/platforms/spigot/build.gradle
+++ b/platforms/spigot/build.gradle
@@ -1,5 +1,6 @@
 plugins {
     id 'java'
+    id 'java-library'
 }
 
 group = 'me.tofaa.entitylib'
@@ -10,6 +11,7 @@ repositories {
 }
 
 dependencies {
-    implementation(project(":api"))
-    implementation('org.spigotmc:spigot-api:1.20.1-R0.1-SNAPSHOT')
+    api(project(":common"))
+    compileOnly('com.github.retrooper.packetevents:spigot:2.0.2')
+    compileOnly('org.spigotmc:spigot-api:1.20.1-R0.1-SNAPSHOT')
 }
diff --git a/platforms/spigot/src/main/java/me/tofaa/entitylib/spigot/SpigotEntityLibAPI.java b/platforms/spigot/src/main/java/me/tofaa/entitylib/spigot/SpigotEntityLibAPI.java
index 5f2222e..a629b70 100644
--- a/platforms/spigot/src/main/java/me/tofaa/entitylib/spigot/SpigotEntityLibAPI.java
+++ b/platforms/spigot/src/main/java/me/tofaa/entitylib/spigot/SpigotEntityLibAPI.java
@@ -3,33 +3,31 @@ package me.tofaa.entitylib.spigot;
 import com.github.retrooper.packetevents.PacketEventsAPI;
 import me.tofaa.entitylib.APISettings;
 import me.tofaa.entitylib.EntityLibAPI;
+import me.tofaa.entitylib.WorldWrapper;
+import me.tofaa.entitylib.common.AbstractEntityLibAPI;
+import me.tofaa.entitylib.event.EventBus;
 import me.tofaa.entitylib.tick.TickContainer;
 import org.bukkit.Bukkit;
 import org.bukkit.World;
+import org.bukkit.plugin.java.JavaPlugin;
 import org.bukkit.scheduler.BukkitTask;
 import org.jetbrains.annotations.NotNull;
 
 import java.util.Collection;
 import java.util.Collections;
 import java.util.HashSet;
+import java.util.UUID;
 import java.util.logging.Level;
 
-public class SpigotEntityLibAPI implements EntityLibAPI<World, BukkitTask> {
+public class SpigotEntityLibAPI extends AbstractEntityLibAPI<JavaPlugin, World, BukkitTask> {
 
-    private final SpigotEntityLibPlatform platform;
-    private final PacketEventsAPI<?> packetEvents;
-    private final APISettings settings;
-    private Collection<TickContainer<?, BukkitTask>> tickContainers;
 
     SpigotEntityLibAPI(SpigotEntityLibPlatform platform, APISettings settings) {
-        this.platform = platform;
-        this.packetEvents = settings.getPacketEvents();
-        this.settings = settings;
+        super(platform, settings);
     }
 
     @Override
     public void onLoad() {
-        this.tickContainers = settings.shouldTickTickables() ? new HashSet<>() : Collections.EMPTY_SET;
     }
 
     @Override
@@ -37,56 +35,22 @@ public class SpigotEntityLibAPI implements EntityLibAPI<World, BukkitTask> {
 
     }
 
-    @NotNull @Override
-    public APISettings getSettings() {
-        return settings;
-    }
-
     @Override
-    public void setupTickingContainers() {
-        if (!getSettings().shouldTickTickables()) {
-            if (getSettings().isDebugMode()) {
-                platform.getLogger().log(Level.CONFIG, "Skipping ticking containers as it is disabled in the settings.");
-            }
-            return;
-        }
-
-        if (getSettings().isDebugMode()) {
-            platform.getLogger().log(Level.CONFIG, "Setting up ticking containers...");
-        }
-        if (tickContainers.isEmpty()) {
-            if (getSettings().isDebugMode()) {
-                platform.getLogger().log(Level.CONFIG, "No tick containers found.");
-            }
-            return;
-        }
-
-        if (getSettings().isDebugMode()) {
-            platform.getLogger().log(Level.CONFIG, "Found " + tickContainers.size() + " tick containers.");
-        }
-
-        tickContainers.forEach(this::registerNewTickContainer);
+    public @NotNull WorldWrapper<World> wrapWorld(World world) {
+        return new SpigotWorld(world);
     }
 
-    @Override
-    public PacketEventsAPI<?> getPacketEvents() {
-        return packetEvents;
-    }
-
-    @Override
-    public Collection<TickContainer<?, BukkitTask>> getTickContainers() {
-        return tickContainers;
-    }
 
     @Override
     public void addTickContainer(@NotNull TickContainer<?, BukkitTask> tickContainer) {
+        if (!settings.shouldTickTickables()) {
+            if (settings.isDebugMode()) {
+                platform.getLogger().log(Level.WARNING, "Tried to add a TickContainer when ticking tickables is disabled!");
+            }
+            return;
+        }
         tickContainers.add(tickContainer);
-        registerNewTickContainer(tickContainer);
-    }
-
-    public void registerNewTickContainer(TickContainer<?, BukkitTask> tickContainer) {
-
-        if (getSettings().isDebugMode()) {
+        if (settings.isDebugMode()) {
             platform.getLogger().log(Level.CONFIG, "Registering new tick container...");
         }
         getTickContainers().add(tickContainer);
@@ -95,4 +59,5 @@ public class SpigotEntityLibAPI implements EntityLibAPI<World, BukkitTask> {
     }
 
 
+
 }
diff --git a/platforms/spigot/src/main/java/me/tofaa/entitylib/spigot/SpigotEntityLibPlatform.java b/platforms/spigot/src/main/java/me/tofaa/entitylib/spigot/SpigotEntityLibPlatform.java
index c719df0..378fb33 100644
--- a/platforms/spigot/src/main/java/me/tofaa/entitylib/spigot/SpigotEntityLibPlatform.java
+++ b/platforms/spigot/src/main/java/me/tofaa/entitylib/spigot/SpigotEntityLibPlatform.java
@@ -1,63 +1,37 @@
 package me.tofaa.entitylib.spigot;
 
 import me.tofaa.entitylib.APISettings;
+import me.tofaa.entitylib.EntityIdProvider;
 import me.tofaa.entitylib.EntityLibAPI;
 import me.tofaa.entitylib.Platform;
-import me.tofaa.entitylib.event.EntityLibEvent;
-import me.tofaa.entitylib.tick.TickContainer;
-import org.bukkit.Bukkit;
+import me.tofaa.entitylib.common.AbstractPlatform;
+import me.tofaa.entitylib.event.EventBus;
 import org.bukkit.plugin.java.JavaPlugin;
-import org.bukkit.scheduler.BukkitTask;
 import org.jetbrains.annotations.NotNull;
-
-import java.util.Collection;
-import java.util.function.Consumer;
-import java.util.logging.Level;
 import java.util.logging.Logger;
 
-public class SpigotEntityLibPlatform implements Platform<JavaPlugin> {
+public class SpigotEntityLibPlatform extends AbstractPlatform<JavaPlugin> {
 
-    private final JavaPlugin plugin;
     private SpigotEntityLibAPI api;
-    private Logger logger;
-
     public SpigotEntityLibPlatform(@NotNull JavaPlugin plugin) {
-        this.plugin = plugin;
+        super(plugin);
     }
 
     @Override
     public void setupApi(@NotNull APISettings settings) {
-        this.logger = settings.shouldUsePlatformLogger() ? plugin.getLogger() : Logger.getLogger("EntityLib");
+        super.setupApi(settings);
+        this.logger = settings.shouldUsePlatformLogger() ? handle.getLogger() : Logger.getLogger("EntityLib");
         this.api = new SpigotEntityLibAPI(this, settings);
         this.api.onLoad();
         this.api.onEnable();
     }
 
-    @Override
-    public @NotNull Logger getLogger() {
-        return logger;
-    }
 
     @Override
-    public void sendEvent(EntityLibEvent event) {
-
-    }
-
-    @Override
-    public <T extends EntityLibEvent> void registerListener(Class<T> eventClass, Consumer<T> handle) {
-
-    }
-
-    @Override
-    public EntityLibAPI getAPI() {
+    public EntityLibAPI<?, ?> getAPI() {
         return api;
     }
 
-    @Override
-    public @NotNull JavaPlugin getHandle() {
-        return plugin;
-    }
-
     @Override
     public String getName() {
         return "Spigot";
diff --git a/platforms/spigot/src/main/java/me/tofaa/entitylib/spigot/SpigotWorld.java b/platforms/spigot/src/main/java/me/tofaa/entitylib/spigot/SpigotWorld.java
new file mode 100644
index 0000000..cecd18e
--- /dev/null
+++ b/platforms/spigot/src/main/java/me/tofaa/entitylib/spigot/SpigotWorld.java
@@ -0,0 +1,28 @@
+package me.tofaa.entitylib.spigot;
+
+import com.github.retrooper.packetevents.protocol.world.Location;
+import com.github.retrooper.packetevents.protocol.world.states.WrappedBlockState;
+import io.github.retrooper.packetevents.util.SpigotConversionUtil;
+import me.tofaa.entitylib.common.AbstractWorldWrapper;
+import me.tofaa.entitylib.wrapper.WrapperEntity;
+import org.bukkit.World;
+import org.jetbrains.annotations.NotNull;
+
+public class SpigotWorld extends AbstractWorldWrapper<World> {
+
+
+    SpigotWorld(World world) {
+        super(world.getUID(), world, SpigotConversionUtil.fromBukkitWorld(world));
+    }
+
+
+    @Override
+    public <T extends WrapperEntity> @NotNull T cloneEntity(@NotNull Object platformEntity, @NotNull Location location) {
+        return null;
+    }
+
+    @Override
+    public WrappedBlockState getBlock(int x, int y, int z) {
+        return SpigotConversionUtil.fromBukkitBlockData(getHandle().getBlockData(new org.bukkit.Location(getHandle(), x, y, z)));
+    }
+}
diff --git a/settings.gradle b/settings.gradle
index 5426790..43b0bdd 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -3,4 +3,5 @@ include 'test-plugin'
 include 'api'
 include 'platforms:spigot'
 findProject(':platforms:spigot')?.name = 'spigot'
+include 'common'
 
diff --git a/test-plugin/build.gradle b/test-plugin/build.gradle
index f8a7b47..a9755f2 100644
--- a/test-plugin/build.gradle
+++ b/test-plugin/build.gradle
@@ -27,7 +27,7 @@ repositories {
 dependencies {
     compileOnly('org.spigotmc:spigot-api:1.20.1-R0.1-SNAPSHOT')
     compileOnly('com.github.retrooper.packetevents:spigot:2.0.2')
-    implementation project(':')
+    implementation(project(":platforms:spigot"))
 }
 
 tasks {
diff --git a/test-plugin/src/main/java/me/tofaa/entitylib/EntityLibPlugin.java b/test-plugin/src/main/java/me/tofaa/entitylib/EntityLibPlugin.java
deleted file mode 100644
index 90bdea9..0000000
--- a/test-plugin/src/main/java/me/tofaa/entitylib/EntityLibPlugin.java
+++ /dev/null
@@ -1,32 +0,0 @@
-package me.tofaa.entitylib;
-
-import com.github.retrooper.packetevents.PacketEvents;
-import com.github.retrooper.packetevents.protocol.player.InteractionHand;
-import com.github.retrooper.packetevents.protocol.player.User;
-import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientInteractEntity;
-import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerCloseWindow;
-import me.tofaa.entitylib.entity.EntityInteractionProcessor;
-import me.tofaa.entitylib.entity.WrapperEntity;
-import org.bukkit.plugin.java.JavaPlugin;
-import org.jetbrains.annotations.NotNull;
-
-public final class EntityLibPlugin extends JavaPlugin {
-
-    static EntityLibPlugin instance;
-
-    @Override
-    public void onEnable() {
-        EntityLib.init(PacketEvents.getAPI());
-        EntityLib.enableEntityInteractions();
-        EntityLib.setInteractionProcessor((entity, action, hand, user) -> user.sendMessage("Hello World"));
-
-        TestDisplayCommand testDisplayCommand = new TestDisplayCommand();
-        getCommand("testdisplay").setExecutor(testDisplayCommand);
-        getCommand("testdisplay").setTabCompleter(testDisplayCommand);
-
-        getCommand("testapi").setExecutor(new TestCommand());
-        getCommand("testentity").setExecutor(new TestEntityCommand());
-        getCommand("spawnclickablefrog").setExecutor(new SpawnClickableFrogCommand());
-        instance = this;
-    }
-}
diff --git a/test-plugin/src/main/java/me/tofaa/entitylib/SpawnClickableFrogCommand.java b/test-plugin/src/main/java/me/tofaa/entitylib/SpawnClickableFrogCommand.java
deleted file mode 100644
index 54c72ff..0000000
--- a/test-plugin/src/main/java/me/tofaa/entitylib/SpawnClickableFrogCommand.java
+++ /dev/null
@@ -1,53 +0,0 @@
-package me.tofaa.entitylib;
-
-import com.github.retrooper.packetevents.protocol.entity.type.EntityTypes;
-import io.github.retrooper.packetevents.util.SpigotConversionUtil;
-import me.tofaa.entitylib.entity.WrapperEntity;
-import me.tofaa.entitylib.meta.mobs.FrogMeta;
-import net.kyori.adventure.text.Component;
-import org.bukkit.Bukkit;
-import org.bukkit.command.Command;
-import org.bukkit.command.CommandExecutor;
-import org.bukkit.command.CommandSender;
-import org.bukkit.entity.Player;
-import org.bukkit.scheduler.BukkitTask;
-import org.jetbrains.annotations.NotNull;
-
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Random;
-import java.util.UUID;
-
-public class SpawnClickableFrogCommand implements CommandExecutor {
-
-    private final Map<WrapperEntity, BukkitTask> updateTasks = new HashMap<>();
-    private final FrogMeta.Variant[] variants = FrogMeta.Variant.values();
-
-    @Override
-    public boolean onCommand(@NotNull CommandSender commandSender, @NotNull Command command, @NotNull String s, @NotNull String[] strings) {
-        Player player = (Player) commandSender;
-        WrapperEntity e = EntityLib.createEntity(UUID.randomUUID(), EntityTypes.TEXT_DISPLAY);
-        FrogMeta meta = (FrogMeta) e.getMeta();
-        meta.setHasGlowingEffect(true);
-        meta.setCustomNameVisible(true);
-        meta.setCustomName(Component.text("CLICK ME!"));
-        updateTasks.put(e, Bukkit.getScheduler().runTaskTimerAsynchronously(
-                EntityLibPlugin.instance,
-                new Runnable() {
-                    int i = 0;
-                    Random random = new Random();
-
-                    @Override
-                    public void run() {
-                        if (!e.hasSpawned()) return;
-                        int r = random.nextInt(2);
-                        meta.setVariant(variants[r]);
-                        meta.setCustomName(Component.text("CLICKED: " + i + " TIMES"));
-                    }
-                },
-                20, 20));
-        e.addViewer(player.getUniqueId());
-        e.spawn(SpigotConversionUtil.fromBukkitLocation(player.getLocation()));
-        return false;
-    }
-}
diff --git a/test-plugin/src/main/java/me/tofaa/entitylib/TestCommand.java b/test-plugin/src/main/java/me/tofaa/entitylib/TestCommand.java
deleted file mode 100644
index 60d4267..0000000
--- a/test-plugin/src/main/java/me/tofaa/entitylib/TestCommand.java
+++ /dev/null
@@ -1,49 +0,0 @@
-package me.tofaa.entitylib;
-
-import com.github.retrooper.packetevents.protocol.entity.type.EntityTypes;
-import com.github.retrooper.packetevents.protocol.world.Location;
-import io.github.retrooper.packetevents.util.SpigotConversionUtil;
-import me.tofaa.entitylib.entity.WrapperEntity;
-import org.bukkit.command.Command;
-import org.bukkit.command.CommandExecutor;
-import org.bukkit.command.CommandSender;
-import org.bukkit.entity.Player;
-import org.jetbrains.annotations.NotNull;
-
-import java.util.UUID;
-
-public class TestCommand implements CommandExecutor {
-
-    private WrapperEntity base, passenger;
-
-    @Override
-    public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
-        if (!(sender instanceof Player)) return false;
-        Player player = (Player) sender;
-
-        if (base != null) {
-            if (base.hasPassenger(passenger)) {
-                base.removePassenger(passenger);
-                player.sendMessage("Removed");
-                return true;
-            }
-        }
-        else {
-            base = EntityLib.createEntity(UUID.randomUUID(), EntityTypes.SHEEP);
-            passenger = EntityLib.createEntity(UUID.randomUUID(), EntityTypes.SKELETON);
-        }
-
-        Location location = SpigotConversionUtil.fromBukkitLocation(player.getLocation());
-        Location pass = new Location(location.getX() + 1, location.getY(), location.getZ(), location.getYaw(), location.getPitch());
-
-        base.addViewer(player.getUniqueId());
-        passenger.addViewer(player.getUniqueId());
-        base.spawn(location);
-        passenger.spawn(pass);
-        base.addPassenger(player.getEntityId());
-        player.sendMessage("Spawned");
-
-        return true;
-    }
-
-}
diff --git a/test-plugin/src/main/java/me/tofaa/entitylib/TestDisplayCommand.java b/test-plugin/src/main/java/me/tofaa/entitylib/TestDisplayCommand.java
deleted file mode 100644
index b003f08..0000000
--- a/test-plugin/src/main/java/me/tofaa/entitylib/TestDisplayCommand.java
+++ /dev/null
@@ -1,95 +0,0 @@
-package me.tofaa.entitylib;
-
-import com.github.retrooper.packetevents.protocol.entity.type.EntityTypes;
-import com.github.retrooper.packetevents.protocol.item.ItemStack;
-import com.github.retrooper.packetevents.protocol.item.type.ItemTypes;
-import com.github.retrooper.packetevents.protocol.world.Location;
-import com.github.retrooper.packetevents.util.Vector3d;
-import com.github.retrooper.packetevents.util.Vector3f;
-import io.github.retrooper.packetevents.util.SpigotConversionUtil;
-import me.tofaa.entitylib.entity.WrapperEntity;
-import me.tofaa.entitylib.meta.display.BlockDisplayMeta;
-import me.tofaa.entitylib.meta.display.ItemDisplayMeta;
-import me.tofaa.entitylib.meta.display.TextDisplayMeta;
-import me.tofaa.entitylib.meta.types.DisplayMeta;
-import net.kyori.adventure.text.Component;
-import org.bukkit.Material;
-import org.bukkit.command.Command;
-import org.bukkit.command.CommandExecutor;
-import org.bukkit.command.CommandSender;
-import org.bukkit.command.TabCompleter;
-import org.bukkit.entity.Player;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-import java.util.Arrays;
-import java.util.List;
-import java.util.UUID;
-
-public class TestDisplayCommand implements CommandExecutor, TabCompleter {
-
-    @Override
-    public boolean onCommand(@NotNull CommandSender commandSender, @NotNull Command command, @NotNull String s, @NotNull String[] strings) {
-        if (strings.length == 0) return false;
-        String type = strings[0];
-        Player player = (Player) commandSender;
-        switch (type) {
-            case "block":
-                block(player);
-                break;
-            case "text":
-                text(player);
-                break;
-            case "item":
-                item(player);
-                break;
-        }
-        return false;
-    }
-
-
-
-    private void block(Player player) {
-        WrapperEntity e = EntityLib.createEntity(UUID.randomUUID(), EntityTypes.BLOCK_DISPLAY);
-        BlockDisplayMeta meta = (BlockDisplayMeta) e.getMeta();
-        meta.setHasGlowingEffect(true);
-        meta.setBlockId(SpigotConversionUtil.fromBukkitBlockData(Material.ACACIA_LOG.createBlockData()).getGlobalId());
-        meta.setBillboardConstraints(DisplayMeta.BillboardConstraints.CENTER);
-        meta.setScale(new Vector3f(2, 2, 2));
-        e.addViewer(player.getUniqueId());
-        e.spawn(fromPlayer(player));
-    }
-
-    private void text(Player player) {
-        WrapperEntity e = EntityLib.createEntity(UUID.randomUUID(), EntityTypes.TEXT_DISPLAY);
-        TextDisplayMeta meta = (TextDisplayMeta) e.getMeta();
-        meta.setHasGlowingEffect(true);
-        meta.setText(Component.text("Hello World!"));
-        meta.setBillboardConstraints(DisplayMeta.BillboardConstraints.CENTER);
-        meta.setTranslation(new Vector3f(4.0f, 0.0f, 0.0f));
-        meta.setScale(new Vector3f(2, 2, 2));
-        e.addViewer(player.getUniqueId());
-        e.spawn(fromPlayer(player));
-    }
-
-    private void item(Player player) {
-        WrapperEntity e = EntityLib.createEntity(UUID.randomUUID(), EntityTypes.ITEM_DISPLAY);
-        ItemDisplayMeta meta = (ItemDisplayMeta) e.getMeta();
-        meta.setDisplayType(ItemDisplayMeta.DisplayType.FIRST_PERSON_LEFT_HAND);
-        meta.setItem(ItemStack.builder()
-                .type(ItemTypes.ACACIA_BOAT).build()
-        );
-        e.addViewer(player.getUniqueId());
-        e.spawn(fromPlayer(player));
-    }
-
-    private static Location fromPlayer(Player player) {
-        return new Location(player.getLocation().getX(), player.getLocation().getY() + 2, player.getLocation().getZ(), 0f, 0f);
-    }
-
-    @Nullable
-    @Override
-    public List<String> onTabComplete(@NotNull CommandSender commandSender, @NotNull Command command, @NotNull String s, @NotNull String[] strings) {
-        return strings.length == 1 ? Arrays.asList("block", "text", "item") : null;
-    }
-}
diff --git a/test-plugin/src/main/java/me/tofaa/entitylib/TestEntityCommand.java b/test-plugin/src/main/java/me/tofaa/entitylib/TestEntityCommand.java
deleted file mode 100644
index beeb1c6..0000000
--- a/test-plugin/src/main/java/me/tofaa/entitylib/TestEntityCommand.java
+++ /dev/null
@@ -1,60 +0,0 @@
-package me.tofaa.entitylib;
-
-import com.github.retrooper.packetevents.protocol.entity.type.EntityTypes;
-import io.github.retrooper.packetevents.util.SpigotConversionUtil;
-import me.tofaa.entitylib.entity.WrapperEntityEquipment;
-import me.tofaa.entitylib.entity.WrapperLivingEntity;
-import me.tofaa.entitylib.meta.EntityMeta;
-import net.kyori.adventure.text.Component;
-import org.bukkit.command.Command;
-import org.bukkit.command.CommandExecutor;
-import org.bukkit.command.CommandSender;
-import org.bukkit.entity.Player;
-import org.bukkit.inventory.ItemStack;
-import org.jetbrains.annotations.NotNull;
-
-import java.util.UUID;
-
-public class TestEntityCommand implements CommandExecutor {
-
-    private WrapperLivingEntity entity;
-
-    @Override
-    public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
-        if (!(sender instanceof Player )) return false;
-        Player player = (Player) sender;
-        if (entity == null) {
-            entity = (WrapperLivingEntity) EntityLib.createEntity(UUID.randomUUID(), EntityTypes.ZOMBIE);
-            if (entity == null) {
-                player.sendMessage("idk");
-                return false;
-            }
-            entity.addViewer(player.getUniqueId());
-            entity.spawn(SpigotConversionUtil.fromBukkitLocation(player.getLocation()));
-        }
-        equipItems(player);
-        EntityMeta meta = entity.getMeta();
-
-        meta.setCustomNameVisible(!meta.isCustomNameVisible());
-        meta.setCustomName(Component.text("test"));
-
-        entity.refresh();
-        return false;
-    }
-
-    private void equipItems(Player player) {
-        ItemStack held = player.getInventory().getItemInMainHand();
-        ItemStack helmet = player.getInventory().getHelmet();
-        ItemStack chestplate = player.getInventory().getChestplate();
-        ItemStack leggings = player.getInventory().getLeggings();
-        ItemStack boots = player.getInventory().getBoots();
-        WrapperEntityEquipment equipment = entity.getEquipment();
-
-        if (helmet != null && !helmet.getType().isAir()) equipment.setHelmet(SpigotConversionUtil.fromBukkitItemStack(helmet));
-        if (chestplate != null && !chestplate.getType().isAir()) equipment.setChestplate(SpigotConversionUtil.fromBukkitItemStack(chestplate));
-        if (leggings != null && !leggings.getType().isAir()) equipment.setLeggings(SpigotConversionUtil.fromBukkitItemStack(leggings));
-        if (boots != null && !boots.getType().isAir()) equipment.setBoots(SpigotConversionUtil.fromBukkitItemStack(boots));
-        if (!held.getType().isAir()) equipment.setMainHand(SpigotConversionUtil.fromBukkitItemStack(held));
-    }
-
-}
diff --git a/test-plugin/src/main/java/me/tofaa/testentitylib/TestEntityLibPlugin.java b/test-plugin/src/main/java/me/tofaa/testentitylib/TestEntityLibPlugin.java
new file mode 100644
index 0000000..fe15bc5
--- /dev/null
+++ b/test-plugin/src/main/java/me/tofaa/testentitylib/TestEntityLibPlugin.java
@@ -0,0 +1,24 @@
+package me.tofaa.testentitylib;
+
+import com.github.retrooper.packetevents.PacketEvents;
+import com.github.retrooper.packetevents.PacketEventsAPI;
+import me.tofaa.entitylib.APISettings;
+import me.tofaa.entitylib.EntityLib;
+import me.tofaa.entitylib.spigot.SpigotEntityLibPlatform;
+import org.bukkit.plugin.java.JavaPlugin;
+
+public class TestEntityLibPlugin extends JavaPlugin {
+
+
+    @Override
+    public void onEnable() {
+
+        SpigotEntityLibPlatform platform = new SpigotEntityLibPlatform(this);
+        APISettings settings = new APISettings(PacketEvents.getAPI())
+                .debugMode()
+                .tickTickables()
+                .usePlatformLogger();
+
+        EntityLib.init(platform, settings);
+    }
+}
diff --git a/test-plugin/src/main/resources/plugin.yml b/test-plugin/src/main/resources/plugin.yml
index 6fbc2c9..df284e5 100644
--- a/test-plugin/src/main/resources/plugin.yml
+++ b/test-plugin/src/main/resources/plugin.yml
@@ -2,7 +2,7 @@ name: EntityLibPlugin
 version: 1.0.0
 depend:
   - packetevents
-main: me.tofaa.entitylib.EntityLibPlugin
+main: me.tofaa.testentitylib.TestEntityLibPlugin
 api-version: "1.19"
 commands:
   testapi:

From 522e31ef12a344b0190351b6ca64ee5fe16f34dd Mon Sep 17 00:00:00 2001
From: Tofaa <82680183+Tofaa2@users.noreply.github.com>
Date: Sun, 28 Jan 2024 17:41:34 +0400
Subject: [PATCH 04/19] fix up some things

---
 .idea/workspace.xml                           | 99 +++++++------------
 .../{APISettings.java => APIConfig.java}      | 16 +--
 .../java/me/tofaa/entitylib/EntityLib.java    |  2 +-
 .../java/me/tofaa/entitylib/EntityLibAPI.java |  5 +-
 .../java/me/tofaa/entitylib/Platform.java     |  6 +-
 .../common/AbstractEntityLibAPI.java          |  8 +-
 .../entitylib/common/AbstractPlatform.java    |  4 +-
 .../entitylib/spigot/SpigotEntityLibAPI.java  | 11 +--
 .../spigot/SpigotEntityLibPlatform.java       |  7 +-
 .../testentitylib/TestEntityLibPlugin.java    |  5 +-
 10 files changed, 59 insertions(+), 104 deletions(-)
 rename api/src/main/java/me/tofaa/entitylib/{APISettings.java => APIConfig.java} (84%)

diff --git a/.idea/workspace.xml b/.idea/workspace.xml
index 5d77931..aa331ae 100644
--- a/.idea/workspace.xml
+++ b/.idea/workspace.xml
@@ -5,49 +5,16 @@
   </component>
   <component name="ChangeListManager">
     <list default="true" id="9d5d9b6f-43c8-41a4-bb42-a66ffc96c9b0" name="Changes" comment="">
-      <change afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/EntityIdProvider.java" afterDir="false" />
-      <change afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/EntityUuidProvider.java" afterDir="false" />
-      <change afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/event/EventBus.java" afterDir="false" />
-      <change afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/event/EventBusAsync.java" afterDir="false" />
-      <change afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/event/EventBusSync.java" afterDir="false" />
-      <change afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/event/EventListener.java" afterDir="false" />
-      <change afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/extras/VersionChecker.java" afterDir="false" />
-      <change afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/meta/MetaConverterRegistry.java" afterDir="false" />
-      <change afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/meta/UsedVersion.java" afterDir="false" />
-      <change afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/meta/VersionCompatCheck.java" afterDir="false" />
-      <change afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/meta/display/AbstractDisplayMeta.java" afterDir="false" />
-      <change afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/meta/display/BlockDisplayMeta.java" afterDir="false" />
-      <change afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/meta/display/ItemDisplayMeta.java" afterDir="false" />
-      <change afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/meta/display/TextDisplayMeta.java" afterDir="false" />
-      <change afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperEntity.java" afterDir="false" />
-      <change afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperEntityEquipment.java" afterDir="false" />
-      <change afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperLivingEntity.java" afterDir="false" />
-      <change afterPath="$PROJECT_DIR$/common/src/main/java/me/tofaa/entitylib/common/AbstractEntityLibAPI.java" afterDir="false" />
-      <change afterPath="$PROJECT_DIR$/common/src/main/java/me/tofaa/entitylib/common/AbstractPlatform.java" afterDir="false" />
-      <change afterPath="$PROJECT_DIR$/common/src/main/java/me/tofaa/entitylib/common/AbstractWorldWrapper.java" afterDir="false" />
-      <change afterPath="$PROJECT_DIR$/platforms/spigot/src/main/java/me/tofaa/entitylib/spigot/SpigotWorld.java" afterDir="false" />
-      <change afterPath="$PROJECT_DIR$/test-plugin/src/main/java/me/tofaa/testentitylib/TestEntityLibPlugin.java" afterDir="false" />
-      <change beforePath="$PROJECT_DIR$/.idea/gradle.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/gradle.xml" afterDir="false" />
       <change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
-      <change beforePath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/APISettings.java" beforeDir="false" afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/APISettings.java" afterDir="false" />
+      <change beforePath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/APISettings.java" beforeDir="false" afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/APIConfig.java" afterDir="false" />
       <change beforePath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/EntityLib.java" beforeDir="false" afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/EntityLib.java" afterDir="false" />
       <change beforePath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/EntityLibAPI.java" beforeDir="false" afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/EntityLibAPI.java" afterDir="false" />
       <change beforePath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/Platform.java" beforeDir="false" afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/Platform.java" afterDir="false" />
-      <change beforePath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/WorldWrapper.java" beforeDir="false" afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/WorldWrapper.java" afterDir="false" />
-      <change beforePath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/event/EntityLibEvent.java" beforeDir="false" afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/event/EntityLibEvent.java" afterDir="false" />
-      <change beforePath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/event/UserReceiveMetaUpdateEvent.java" beforeDir="false" afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/event/types/UserReceiveMetaUpdateEvent.java" afterDir="false" />
-      <change beforePath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/meta/EntityMeta.java" beforeDir="false" afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/meta/EntityMeta.java" afterDir="false" />
-      <change beforePath="$PROJECT_DIR$/platforms/spigot/build.gradle" beforeDir="false" afterPath="$PROJECT_DIR$/platforms/spigot/build.gradle" afterDir="false" />
+      <change beforePath="$PROJECT_DIR$/common/src/main/java/me/tofaa/entitylib/common/AbstractEntityLibAPI.java" beforeDir="false" afterPath="$PROJECT_DIR$/common/src/main/java/me/tofaa/entitylib/common/AbstractEntityLibAPI.java" afterDir="false" />
+      <change beforePath="$PROJECT_DIR$/common/src/main/java/me/tofaa/entitylib/common/AbstractPlatform.java" beforeDir="false" afterPath="$PROJECT_DIR$/common/src/main/java/me/tofaa/entitylib/common/AbstractPlatform.java" afterDir="false" />
       <change beforePath="$PROJECT_DIR$/platforms/spigot/src/main/java/me/tofaa/entitylib/spigot/SpigotEntityLibAPI.java" beforeDir="false" afterPath="$PROJECT_DIR$/platforms/spigot/src/main/java/me/tofaa/entitylib/spigot/SpigotEntityLibAPI.java" afterDir="false" />
       <change beforePath="$PROJECT_DIR$/platforms/spigot/src/main/java/me/tofaa/entitylib/spigot/SpigotEntityLibPlatform.java" beforeDir="false" afterPath="$PROJECT_DIR$/platforms/spigot/src/main/java/me/tofaa/entitylib/spigot/SpigotEntityLibPlatform.java" afterDir="false" />
-      <change beforePath="$PROJECT_DIR$/settings.gradle" beforeDir="false" afterPath="$PROJECT_DIR$/settings.gradle" afterDir="false" />
-      <change beforePath="$PROJECT_DIR$/test-plugin/build.gradle" beforeDir="false" afterPath="$PROJECT_DIR$/test-plugin/build.gradle" afterDir="false" />
-      <change beforePath="$PROJECT_DIR$/test-plugin/src/main/java/me/tofaa/entitylib/EntityLibPlugin.java" beforeDir="false" />
-      <change beforePath="$PROJECT_DIR$/test-plugin/src/main/java/me/tofaa/entitylib/SpawnClickableFrogCommand.java" beforeDir="false" />
-      <change beforePath="$PROJECT_DIR$/test-plugin/src/main/java/me/tofaa/entitylib/TestCommand.java" beforeDir="false" />
-      <change beforePath="$PROJECT_DIR$/test-plugin/src/main/java/me/tofaa/entitylib/TestDisplayCommand.java" beforeDir="false" />
-      <change beforePath="$PROJECT_DIR$/test-plugin/src/main/java/me/tofaa/entitylib/TestEntityCommand.java" beforeDir="false" />
-      <change beforePath="$PROJECT_DIR$/test-plugin/src/main/resources/plugin.yml" beforeDir="false" afterPath="$PROJECT_DIR$/test-plugin/src/main/resources/plugin.yml" afterDir="false" />
+      <change beforePath="$PROJECT_DIR$/test-plugin/src/main/java/me/tofaa/testentitylib/TestEntityLibPlugin.java" beforeDir="false" afterPath="$PROJECT_DIR$/test-plugin/src/main/java/me/tofaa/testentitylib/TestEntityLibPlugin.java" afterDir="false" />
     </list>
     <option name="SHOW_DIALOG" value="false" />
     <option name="HIGHLIGHT_CONFLICTS" value="true" />
@@ -110,35 +77,35 @@
     <option name="showExcludedFiles" value="false" />
     <option name="showLibraryContents" value="true" />
   </component>
-  <component name="PropertiesComponent"><![CDATA[{
-  "keyToString": {
-    "Downloaded.Files.Path.Enabled": "false",
-    "Gradle.Build EntityLib.executor": "Run",
-    "Gradle.EntityLib [dependencies].executor": "Run",
-    "Gradle.EntityLib:test-plugin [runServer].executor": "Run",
-    "Repository.Attach.Annotations": "false",
-    "Repository.Attach.JavaDocs": "false",
-    "Repository.Attach.Sources": "false",
-    "RunOnceActivity.OpenProjectViewOnStart": "true",
-    "RunOnceActivity.ShowReadmeOnStart": "true",
-    "WebServerToolWindowFactoryState": "false",
-    "git-widget-placeholder": "feat/platform-api",
-    "ignore.virus.scanning.warn.message": "true",
-    "jdk.selected.JAVA_MODULE": "corretto-17",
-    "kotlin-language-version-configured": "true",
-    "last_opened_file_path": "D:/Github/EntityLib/api/src/main/java/me/tofaa/entitylib/meta",
-    "node.js.detected.package.eslint": "true",
-    "node.js.detected.package.tslint": "true",
-    "node.js.selected.package.eslint": "(autodetect)",
-    "node.js.selected.package.tslint": "(autodetect)",
-    "nodejs_package_manager_path": "npm",
-    "project.structure.last.edited": "Modules",
-    "project.structure.proportion": "0.15",
-    "project.structure.side.proportion": "0.2",
-    "settings.editor.selected.configurable": "preferences.pluginManager",
-    "vue.rearranger.settings.migration": "true"
+  <component name="PropertiesComponent">{
+  &quot;keyToString&quot;: {
+    &quot;Downloaded.Files.Path.Enabled&quot;: &quot;false&quot;,
+    &quot;Gradle.Build EntityLib.executor&quot;: &quot;Run&quot;,
+    &quot;Gradle.EntityLib [dependencies].executor&quot;: &quot;Run&quot;,
+    &quot;Gradle.EntityLib:test-plugin [runServer].executor&quot;: &quot;Run&quot;,
+    &quot;Repository.Attach.Annotations&quot;: &quot;false&quot;,
+    &quot;Repository.Attach.JavaDocs&quot;: &quot;false&quot;,
+    &quot;Repository.Attach.Sources&quot;: &quot;false&quot;,
+    &quot;RunOnceActivity.OpenProjectViewOnStart&quot;: &quot;true&quot;,
+    &quot;RunOnceActivity.ShowReadmeOnStart&quot;: &quot;true&quot;,
+    &quot;WebServerToolWindowFactoryState&quot;: &quot;false&quot;,
+    &quot;git-widget-placeholder&quot;: &quot;feat/platform-api&quot;,
+    &quot;ignore.virus.scanning.warn.message&quot;: &quot;true&quot;,
+    &quot;jdk.selected.JAVA_MODULE&quot;: &quot;corretto-17&quot;,
+    &quot;kotlin-language-version-configured&quot;: &quot;true&quot;,
+    &quot;last_opened_file_path&quot;: &quot;D:/Github/EntityLib/api/src/main/java/me/tofaa/entitylib/meta&quot;,
+    &quot;node.js.detected.package.eslint&quot;: &quot;true&quot;,
+    &quot;node.js.detected.package.tslint&quot;: &quot;true&quot;,
+    &quot;node.js.selected.package.eslint&quot;: &quot;(autodetect)&quot;,
+    &quot;node.js.selected.package.tslint&quot;: &quot;(autodetect)&quot;,
+    &quot;nodejs_package_manager_path&quot;: &quot;npm&quot;,
+    &quot;project.structure.last.edited&quot;: &quot;Modules&quot;,
+    &quot;project.structure.proportion&quot;: &quot;0.15&quot;,
+    &quot;project.structure.side.proportion&quot;: &quot;0.2&quot;,
+    &quot;settings.editor.selected.configurable&quot;: &quot;preferences.pluginManager&quot;,
+    &quot;vue.rearranger.settings.migration&quot;: &quot;true&quot;
   }
-}]]></component>
+}</component>
   <component name="RecentsManager">
     <key name="CopyFile.RECENT_KEYS">
       <recent name="D:\Github\EntityLib\api\src\main\java\me\tofaa\entitylib\meta" />
@@ -288,6 +255,8 @@
       <workItem from="1706187926445" duration="4339000" />
       <workItem from="1706248178234" duration="17096000" />
       <workItem from="1706284605696" duration="11691000" />
+      <workItem from="1706371324325" duration="1187000" />
+      <workItem from="1706443875388" duration="3245000" />
     </task>
     <servers />
   </component>
diff --git a/api/src/main/java/me/tofaa/entitylib/APISettings.java b/api/src/main/java/me/tofaa/entitylib/APIConfig.java
similarity index 84%
rename from api/src/main/java/me/tofaa/entitylib/APISettings.java
rename to api/src/main/java/me/tofaa/entitylib/APIConfig.java
index 17823db..b9f09f8 100644
--- a/api/src/main/java/me/tofaa/entitylib/APISettings.java
+++ b/api/src/main/java/me/tofaa/entitylib/APIConfig.java
@@ -10,7 +10,7 @@ import java.io.InputStream;
 import java.io.InputStreamReader;
 import java.net.URL;
 
-public final class APISettings {
+public final class APIConfig {
 
     private final PacketEventsAPI<?> packetEvents;
     private boolean debugMode = false;
@@ -20,7 +20,7 @@ public final class APISettings {
     private boolean useAsyncEvents = false;
     private boolean defaultCommands = false;
 
-    public APISettings(PacketEventsAPI<?> packetEvents) {
+    public APIConfig(PacketEventsAPI<?> packetEvents) {
         this.packetEvents = packetEvents;
     }
 
@@ -39,32 +39,32 @@ public final class APISettings {
         return !version.equalsIgnoreCase(latest);
     }
 
-    public @NotNull APISettings usePlatformLogger() {
+    public @NotNull APIConfig usePlatformLogger() {
         this.platformLogger = true;
         return this;
     }
 
-    public @NotNull APISettings checkForUpdates() {
+    public @NotNull APIConfig checkForUpdates() {
         this.checkForUpdates = true;
         return this;
     }
 
-    public @NotNull APISettings tickTickables() {
+    public @NotNull APIConfig tickTickables() {
         this.tickTickables = true;
         return this;
     }
 
-    public @NotNull APISettings debugMode() {
+    public @NotNull APIConfig debugMode() {
         this.debugMode = true;
         return this;
     }
 
-    public @NotNull APISettings registerDefaultCommands() {
+    public @NotNull APIConfig registerDefaultCommands() {
         this.defaultCommands = true;
         return this;
     }
 
-    public @NotNull APISettings useAsyncEvents() {
+    public @NotNull APIConfig useAsyncEvents() {
         this.useAsyncEvents = true;
         return this;
     }
diff --git a/api/src/main/java/me/tofaa/entitylib/EntityLib.java b/api/src/main/java/me/tofaa/entitylib/EntityLib.java
index ff57c07..9e9d77e 100644
--- a/api/src/main/java/me/tofaa/entitylib/EntityLib.java
+++ b/api/src/main/java/me/tofaa/entitylib/EntityLib.java
@@ -10,7 +10,7 @@ public final class EntityLib {
     private static Platform platform;
     private static EntityLibAPI api;
 
-    public static void init(Platform<?> platform, APISettings settings) {
+    public static void init(Platform<?> platform, APIConfig settings) {
         EntityLib.platform = platform;
         platform.setupApi(settings);
         api = platform.getAPI();
diff --git a/api/src/main/java/me/tofaa/entitylib/EntityLibAPI.java b/api/src/main/java/me/tofaa/entitylib/EntityLibAPI.java
index 7067141..0b6380d 100644
--- a/api/src/main/java/me/tofaa/entitylib/EntityLibAPI.java
+++ b/api/src/main/java/me/tofaa/entitylib/EntityLibAPI.java
@@ -5,7 +5,6 @@ import me.tofaa.entitylib.tick.TickContainer;
 import org.jetbrains.annotations.NotNull;
 
 import java.util.Collection;
-import java.util.UUID;
 
 /**
  * Represents the API for EntityLib.
@@ -34,9 +33,9 @@ public interface EntityLibAPI<W, T> {
     @NotNull WorldWrapper<W> wrapWorld(W world);
 
     /**
-     * @return The {@link APISettings} for the API.
+     * @return The {@link APIConfig} for the API.
      */
-    @NotNull APISettings getSettings();
+    @NotNull APIConfig getSettings();
 
     /**
      * @return An unmodifiable collection of TickContainers.
diff --git a/api/src/main/java/me/tofaa/entitylib/Platform.java b/api/src/main/java/me/tofaa/entitylib/Platform.java
index 5b5436a..2c80033 100644
--- a/api/src/main/java/me/tofaa/entitylib/Platform.java
+++ b/api/src/main/java/me/tofaa/entitylib/Platform.java
@@ -1,10 +1,8 @@
 package me.tofaa.entitylib;
 
-import me.tofaa.entitylib.event.EntityLibEvent;
 import me.tofaa.entitylib.event.EventBus;
 import org.jetbrains.annotations.NotNull;
 
-import java.util.function.Consumer;
 import java.util.logging.Logger;
 
 /**
@@ -45,7 +43,7 @@ public interface Platform<P> {
 
     /**
      * Gets the event bus for the platform.
-     * WARNING: If you have {@link APISettings#shouldUseAsyncEvents()} set to true, cast this to {@link EventBus.Async} when handling cancelled events.
+     * WARNING: If you have {@link APIConfig#shouldUseAsyncEvents()} set to true, cast this to {@link EventBus.Async} when handling cancelled events.
      * @return
      */
     @NotNull EventBus getEventBus();
@@ -54,7 +52,7 @@ public interface Platform<P> {
      * Sets up the API for the platform. This method should be called automatically by the platform. Don't call it yourself.
      * @param settings
      */
-    void setupApi(@NotNull APISettings settings);
+    void setupApi(@NotNull APIConfig settings);
 
     /**
      * @return The API instance.
diff --git a/common/src/main/java/me/tofaa/entitylib/common/AbstractEntityLibAPI.java b/common/src/main/java/me/tofaa/entitylib/common/AbstractEntityLibAPI.java
index 97e35da..65e375b 100644
--- a/common/src/main/java/me/tofaa/entitylib/common/AbstractEntityLibAPI.java
+++ b/common/src/main/java/me/tofaa/entitylib/common/AbstractEntityLibAPI.java
@@ -1,7 +1,7 @@
 package me.tofaa.entitylib.common;
 
 import com.github.retrooper.packetevents.PacketEventsAPI;
-import me.tofaa.entitylib.APISettings;
+import me.tofaa.entitylib.APIConfig;
 import me.tofaa.entitylib.EntityLibAPI;
 import me.tofaa.entitylib.Platform;
 import me.tofaa.entitylib.tick.TickContainer;
@@ -15,10 +15,10 @@ public abstract class AbstractEntityLibAPI<P, W, T> implements EntityLibAPI<W, T
 
     protected final Platform<P> platform;
     protected final PacketEventsAPI<?> packetEvents;
-    protected final APISettings settings;
+    protected final APIConfig settings;
     protected final Collection<TickContainer<?, T>> tickContainers;
 
-    protected AbstractEntityLibAPI(Platform<P> platform, APISettings settings) {
+    protected AbstractEntityLibAPI(Platform<P> platform, APIConfig settings) {
         this.platform = platform;
         this.packetEvents = settings.getPacketEvents();
         this.settings = settings;
@@ -27,7 +27,7 @@ public abstract class AbstractEntityLibAPI<P, W, T> implements EntityLibAPI<W, T
 
     @NotNull
     @Override
-    public APISettings getSettings() {
+    public APIConfig getSettings() {
         return settings;
     }
 
diff --git a/common/src/main/java/me/tofaa/entitylib/common/AbstractPlatform.java b/common/src/main/java/me/tofaa/entitylib/common/AbstractPlatform.java
index a218723..a2700e1 100644
--- a/common/src/main/java/me/tofaa/entitylib/common/AbstractPlatform.java
+++ b/common/src/main/java/me/tofaa/entitylib/common/AbstractPlatform.java
@@ -1,6 +1,6 @@
 package me.tofaa.entitylib.common;
 
-import me.tofaa.entitylib.APISettings;
+import me.tofaa.entitylib.APIConfig;
 import me.tofaa.entitylib.EntityIdProvider;
 import me.tofaa.entitylib.EntityUuidProvider;
 import me.tofaa.entitylib.Platform;
@@ -26,7 +26,7 @@ public abstract class AbstractPlatform<P> implements Platform<P> {
 
 
     @Override
-    public void setupApi(@NotNull APISettings settings) {
+    public void setupApi(@NotNull APIConfig settings) {
         this.eventBus = EventBus.newBus(settings.shouldUseAsyncEvents());
         this.entityIdProvider = new EntityIdProvider.DefaultEntityIdProvider();
         this.entityUuidProvider = new EntityUuidProvider.DefaultEntityUuidProvider();
diff --git a/platforms/spigot/src/main/java/me/tofaa/entitylib/spigot/SpigotEntityLibAPI.java b/platforms/spigot/src/main/java/me/tofaa/entitylib/spigot/SpigotEntityLibAPI.java
index a629b70..d6143e6 100644
--- a/platforms/spigot/src/main/java/me/tofaa/entitylib/spigot/SpigotEntityLibAPI.java
+++ b/platforms/spigot/src/main/java/me/tofaa/entitylib/spigot/SpigotEntityLibAPI.java
@@ -1,11 +1,8 @@
 package me.tofaa.entitylib.spigot;
 
-import com.github.retrooper.packetevents.PacketEventsAPI;
-import me.tofaa.entitylib.APISettings;
-import me.tofaa.entitylib.EntityLibAPI;
+import me.tofaa.entitylib.APIConfig;
 import me.tofaa.entitylib.WorldWrapper;
 import me.tofaa.entitylib.common.AbstractEntityLibAPI;
-import me.tofaa.entitylib.event.EventBus;
 import me.tofaa.entitylib.tick.TickContainer;
 import org.bukkit.Bukkit;
 import org.bukkit.World;
@@ -13,16 +10,12 @@ import org.bukkit.plugin.java.JavaPlugin;
 import org.bukkit.scheduler.BukkitTask;
 import org.jetbrains.annotations.NotNull;
 
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.UUID;
 import java.util.logging.Level;
 
 public class SpigotEntityLibAPI extends AbstractEntityLibAPI<JavaPlugin, World, BukkitTask> {
 
 
-    SpigotEntityLibAPI(SpigotEntityLibPlatform platform, APISettings settings) {
+    SpigotEntityLibAPI(SpigotEntityLibPlatform platform, APIConfig settings) {
         super(platform, settings);
     }
 
diff --git a/platforms/spigot/src/main/java/me/tofaa/entitylib/spigot/SpigotEntityLibPlatform.java b/platforms/spigot/src/main/java/me/tofaa/entitylib/spigot/SpigotEntityLibPlatform.java
index 378fb33..919fa12 100644
--- a/platforms/spigot/src/main/java/me/tofaa/entitylib/spigot/SpigotEntityLibPlatform.java
+++ b/platforms/spigot/src/main/java/me/tofaa/entitylib/spigot/SpigotEntityLibPlatform.java
@@ -1,11 +1,8 @@
 package me.tofaa.entitylib.spigot;
 
-import me.tofaa.entitylib.APISettings;
-import me.tofaa.entitylib.EntityIdProvider;
+import me.tofaa.entitylib.APIConfig;
 import me.tofaa.entitylib.EntityLibAPI;
-import me.tofaa.entitylib.Platform;
 import me.tofaa.entitylib.common.AbstractPlatform;
-import me.tofaa.entitylib.event.EventBus;
 import org.bukkit.plugin.java.JavaPlugin;
 import org.jetbrains.annotations.NotNull;
 import java.util.logging.Logger;
@@ -18,7 +15,7 @@ public class SpigotEntityLibPlatform extends AbstractPlatform<JavaPlugin> {
     }
 
     @Override
-    public void setupApi(@NotNull APISettings settings) {
+    public void setupApi(@NotNull APIConfig settings) {
         super.setupApi(settings);
         this.logger = settings.shouldUsePlatformLogger() ? handle.getLogger() : Logger.getLogger("EntityLib");
         this.api = new SpigotEntityLibAPI(this, settings);
diff --git a/test-plugin/src/main/java/me/tofaa/testentitylib/TestEntityLibPlugin.java b/test-plugin/src/main/java/me/tofaa/testentitylib/TestEntityLibPlugin.java
index fe15bc5..4b1e4eb 100644
--- a/test-plugin/src/main/java/me/tofaa/testentitylib/TestEntityLibPlugin.java
+++ b/test-plugin/src/main/java/me/tofaa/testentitylib/TestEntityLibPlugin.java
@@ -1,8 +1,7 @@
 package me.tofaa.testentitylib;
 
 import com.github.retrooper.packetevents.PacketEvents;
-import com.github.retrooper.packetevents.PacketEventsAPI;
-import me.tofaa.entitylib.APISettings;
+import me.tofaa.entitylib.APIConfig;
 import me.tofaa.entitylib.EntityLib;
 import me.tofaa.entitylib.spigot.SpigotEntityLibPlatform;
 import org.bukkit.plugin.java.JavaPlugin;
@@ -14,7 +13,7 @@ public class TestEntityLibPlugin extends JavaPlugin {
     public void onEnable() {
 
         SpigotEntityLibPlatform platform = new SpigotEntityLibPlatform(this);
-        APISettings settings = new APISettings(PacketEvents.getAPI())
+        APIConfig settings = new APIConfig(PacketEvents.getAPI())
                 .debugMode()
                 .tickTickables()
                 .usePlatformLogger();

From 3183a3140de986edd84a447388353ef85301cf57 Mon Sep 17 00:00:00 2001
From: Tofaa <82680183+Tofaa2@users.noreply.github.com>
Date: Mon, 29 Jan 2024 13:19:45 +0400
Subject: [PATCH 05/19] let the entities be aware of their world

---
 .idea/workspace.xml                           |  20 +-
 .../java/me/tofaa/entitylib/WorldWrapper.java |   1 +
 .../entitylib/meta/CompatibilityIndex.java    |   9 +
 .../me/tofaa/entitylib/meta/UsedVersion.java  |   9 -
 .../entitylib/meta/VersionCompatCheck.java    |  15 -
 .../me/tofaa/entitylib/tick/Tickable.java     |  15 +
 .../entitylib/wrapper/WrapperEntity.java      | 259 ++++++++++++++++--
 .../ai/goals/RandomHeadMovementGoal.java      |   2 +-
 .../common/AbstractWorldWrapper.java          |   3 +-
 9 files changed, 280 insertions(+), 53 deletions(-)
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/CompatibilityIndex.java
 delete mode 100644 api/src/main/java/me/tofaa/entitylib/meta/UsedVersion.java
 delete mode 100644 api/src/main/java/me/tofaa/entitylib/meta/VersionCompatCheck.java

diff --git a/.idea/workspace.xml b/.idea/workspace.xml
index aa331ae..d31bff8 100644
--- a/.idea/workspace.xml
+++ b/.idea/workspace.xml
@@ -5,16 +5,15 @@
   </component>
   <component name="ChangeListManager">
     <list default="true" id="9d5d9b6f-43c8-41a4-bb42-a66ffc96c9b0" name="Changes" comment="">
+      <change afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/meta/CompatibilityIndex.java" afterDir="false" />
       <change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
-      <change beforePath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/APISettings.java" beforeDir="false" afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/APIConfig.java" afterDir="false" />
-      <change beforePath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/EntityLib.java" beforeDir="false" afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/EntityLib.java" afterDir="false" />
-      <change beforePath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/EntityLibAPI.java" beforeDir="false" afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/EntityLibAPI.java" afterDir="false" />
-      <change beforePath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/Platform.java" beforeDir="false" afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/Platform.java" afterDir="false" />
-      <change beforePath="$PROJECT_DIR$/common/src/main/java/me/tofaa/entitylib/common/AbstractEntityLibAPI.java" beforeDir="false" afterPath="$PROJECT_DIR$/common/src/main/java/me/tofaa/entitylib/common/AbstractEntityLibAPI.java" afterDir="false" />
-      <change beforePath="$PROJECT_DIR$/common/src/main/java/me/tofaa/entitylib/common/AbstractPlatform.java" beforeDir="false" afterPath="$PROJECT_DIR$/common/src/main/java/me/tofaa/entitylib/common/AbstractPlatform.java" afterDir="false" />
-      <change beforePath="$PROJECT_DIR$/platforms/spigot/src/main/java/me/tofaa/entitylib/spigot/SpigotEntityLibAPI.java" beforeDir="false" afterPath="$PROJECT_DIR$/platforms/spigot/src/main/java/me/tofaa/entitylib/spigot/SpigotEntityLibAPI.java" afterDir="false" />
-      <change beforePath="$PROJECT_DIR$/platforms/spigot/src/main/java/me/tofaa/entitylib/spigot/SpigotEntityLibPlatform.java" beforeDir="false" afterPath="$PROJECT_DIR$/platforms/spigot/src/main/java/me/tofaa/entitylib/spigot/SpigotEntityLibPlatform.java" afterDir="false" />
-      <change beforePath="$PROJECT_DIR$/test-plugin/src/main/java/me/tofaa/testentitylib/TestEntityLibPlugin.java" beforeDir="false" afterPath="$PROJECT_DIR$/test-plugin/src/main/java/me/tofaa/testentitylib/TestEntityLibPlugin.java" afterDir="false" />
+      <change beforePath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/WorldWrapper.java" beforeDir="false" afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/WorldWrapper.java" afterDir="false" />
+      <change beforePath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/meta/UsedVersion.java" beforeDir="false" />
+      <change beforePath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/meta/VersionCompatCheck.java" beforeDir="false" />
+      <change beforePath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/tick/Tickable.java" beforeDir="false" afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/tick/Tickable.java" afterDir="false" />
+      <change beforePath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperEntity.java" beforeDir="false" afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperEntity.java" afterDir="false" />
+      <change beforePath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/wrapper/ai/goals/RandomHeadMovementGoal.java" beforeDir="false" afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/wrapper/ai/goals/RandomHeadMovementGoal.java" afterDir="false" />
+      <change beforePath="$PROJECT_DIR$/common/src/main/java/me/tofaa/entitylib/common/AbstractWorldWrapper.java" beforeDir="false" afterPath="$PROJECT_DIR$/common/src/main/java/me/tofaa/entitylib/common/AbstractWorldWrapper.java" afterDir="false" />
     </list>
     <option name="SHOW_DIALOG" value="false" />
     <option name="HIGHLIGHT_CONFLICTS" value="true" />
@@ -256,7 +255,8 @@
       <workItem from="1706248178234" duration="17096000" />
       <workItem from="1706284605696" duration="11691000" />
       <workItem from="1706371324325" duration="1187000" />
-      <workItem from="1706443875388" duration="3245000" />
+      <workItem from="1706443875388" duration="4827000" />
+      <workItem from="1706513591682" duration="2661000" />
     </task>
     <servers />
   </component>
diff --git a/api/src/main/java/me/tofaa/entitylib/WorldWrapper.java b/api/src/main/java/me/tofaa/entitylib/WorldWrapper.java
index 76d809a..d421c35 100644
--- a/api/src/main/java/me/tofaa/entitylib/WorldWrapper.java
+++ b/api/src/main/java/me/tofaa/entitylib/WorldWrapper.java
@@ -4,6 +4,7 @@ import com.github.retrooper.packetevents.protocol.entity.type.EntityType;
 import com.github.retrooper.packetevents.protocol.world.Dimension;
 import com.github.retrooper.packetevents.protocol.world.Location;
 import com.github.retrooper.packetevents.protocol.world.states.WrappedBlockState;
+import me.tofaa.entitylib.tick.TickContainer;
 import me.tofaa.entitylib.wrapper.WrapperEntity;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/CompatibilityIndex.java b/api/src/main/java/me/tofaa/entitylib/meta/CompatibilityIndex.java
new file mode 100644
index 0000000..2683859
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/CompatibilityIndex.java
@@ -0,0 +1,9 @@
+package me.tofaa.entitylib.meta;
+
+import com.github.retrooper.packetevents.protocol.entity.data.EntityDataType;
+
+public interface CompatibilityIndex {
+
+    byte getOffSet(byte latestOffset, EntityDataType<?> type);
+
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/UsedVersion.java b/api/src/main/java/me/tofaa/entitylib/meta/UsedVersion.java
deleted file mode 100644
index d0bbd32..0000000
--- a/api/src/main/java/me/tofaa/entitylib/meta/UsedVersion.java
+++ /dev/null
@@ -1,9 +0,0 @@
-package me.tofaa.entitylib.meta;
-
-import com.github.retrooper.packetevents.manager.server.ServerVersion;
-
-public @interface UsedVersion {
-
-    ServerVersion[] value();
-
-}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/VersionCompatCheck.java b/api/src/main/java/me/tofaa/entitylib/meta/VersionCompatCheck.java
deleted file mode 100644
index 9bc5281..0000000
--- a/api/src/main/java/me/tofaa/entitylib/meta/VersionCompatCheck.java
+++ /dev/null
@@ -1,15 +0,0 @@
-package me.tofaa.entitylib.meta;
-
-import com.github.retrooper.packetevents.manager.server.ServerVersion;
-import com.github.retrooper.packetevents.manager.server.VersionComparison;
-import me.tofaa.entitylib.EntityLib;
-
-public final class VersionCompatCheck  {
-
-    private VersionCompatCheck() {}
-
-    static boolean isVersion(ServerVersion version) {
-        return version.is(VersionComparison.EQUALS, EntityLib.getApi().getPacketEvents().getServerManager().getVersion());
-    }
-
-}
diff --git a/api/src/main/java/me/tofaa/entitylib/tick/Tickable.java b/api/src/main/java/me/tofaa/entitylib/tick/Tickable.java
index 11dd41b..4b38f89 100644
--- a/api/src/main/java/me/tofaa/entitylib/tick/Tickable.java
+++ b/api/src/main/java/me/tofaa/entitylib/tick/Tickable.java
@@ -2,6 +2,21 @@ package me.tofaa.entitylib.tick;
 
 public interface Tickable {
 
+    /**
+     * @return if the entity is ticking.
+     */
+    boolean isTicking();
+
+    /**
+     * Sets the entities ticking status, incase you want to stop ticking for a moment then continue
+     * @param ticking if the entity should tick.
+     */
+    void setTicking(boolean ticking);
+
+    /**
+     * Ticks this entity. This method will not be called if {@link #isTicking()} returns false.
+     * @param time the current time in milliseconds.
+     */
     void tick(long time);
 
 }
diff --git a/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperEntity.java b/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperEntity.java
index 32e33d6..8bf058e 100644
--- a/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperEntity.java
+++ b/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperEntity.java
@@ -2,52 +2,106 @@ package me.tofaa.entitylib.wrapper;
 
 import com.github.retrooper.packetevents.protocol.entity.type.EntityType;
 import com.github.retrooper.packetevents.protocol.player.User;
+import com.github.retrooper.packetevents.protocol.world.BoundingBox;
 import com.github.retrooper.packetevents.protocol.world.Location;
 import com.github.retrooper.packetevents.util.Vector3d;
 import com.github.retrooper.packetevents.wrapper.PacketWrapper;
-import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerDestroyEntities;
-import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerEntityRotation;
-import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerEntityVelocity;
-import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerSpawnEntity;
+import com.github.retrooper.packetevents.wrapper.play.server.*;
 import me.tofaa.entitylib.EntityLib;
+import me.tofaa.entitylib.WorldWrapper;
 import me.tofaa.entitylib.meta.EntityMeta;
+import me.tofaa.entitylib.meta.types.ObjectData;
 import me.tofaa.entitylib.tick.Tickable;
+import org.jetbrains.annotations.ApiStatus;
 import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
 
 import javax.swing.text.html.parser.Entity;
-import java.util.Collections;
-import java.util.Optional;
-import java.util.Set;
-import java.util.UUID;
+import java.util.*;
 
 public class WrapperEntity implements Tickable {
 
     private final UUID uuid;
     private final int entityId;
-
     private EntityType entityType;
     private EntityMeta entityMeta;
+    private boolean ticking;
     private Location location;
+    private Location preRidingLocation;
     private Set<UUID> viewers;
     private boolean onGround;
     private boolean spawned;
     private Vector3d velocity;
-
+    private int riding = -1;
+    private Set<Integer> passengers = new HashSet<>();
+    private WorldWrapper<?> world;
 
     public WrapperEntity(int entityId, UUID uuid, EntityType entityType, EntityMeta entityMeta) {
         this.entityId = entityId;
         this.uuid = uuid;
         this.entityType = entityType;
         this.entityMeta = entityMeta;
+        this.ticking = true;
     }
 
-    public void spawn() {}
-
-    public void despawn() {}
-
-    public void teleport(@NotNull Location location) {
+    public boolean spawn(WorldWrapper<?> world, Location location) {
+        if (spawned) return false;
         this.location = location;
+        this.world = world;
+        this.spawned = true;
+        int data = 0;
+        Optional<Vector3d> velocity;
+        double veloX = 0, veloY = 0, veloZ = 0;
+        if (entityMeta instanceof ObjectData) {
+            ObjectData od = (ObjectData) entityMeta;
+            data = od.getObjectData();
+            if (od.requiresVelocityPacketAtSpawn()) {
+                final WrapperPlayServerEntityVelocity veloPacket = getVelocityPacket();
+                veloX = veloPacket.getVelocity().getX();
+                veloY = veloPacket.getVelocity().getY();
+                veloZ = veloPacket.getVelocity().getZ();
+            }
+        }
+        if (veloX == 0 && veloY == 0 && veloZ == 0) {
+            velocity = Optional.empty();
+        } else {
+            velocity = Optional.of(new Vector3d(veloX, veloY, veloZ));
+        }
+        sendPacketToViewers(
+                new WrapperPlayServerSpawnEntity(
+                        entityId,
+                        Optional.of(this.uuid),
+                        entityType,
+                        location.getPosition(),
+                        location.getPitch(),
+                        location.getYaw(),
+                        location.getYaw(),
+                        data,
+                        velocity
+                )
+        );
+        sendPacketToViewers(entityMeta.createPacket());
+        return true;
+    }
 
+    public void despawn() {
+        if (!spawned) return;
+        spawned = false;
+        sendPacketToViewers(new WrapperPlayServerDestroyEntities(entityId));
+    }
+
+    public void teleport(WorldWrapper<?> world, @NotNull Location location) {
+        this.location = location;
+        this.world = world;
+        sendPacketToViewers(
+                new WrapperPlayServerEntityTeleport(
+                        entityId,
+                        location.getPosition(),
+                        location.getYaw(),
+                        location.getPitch(),
+                        onGround
+                )
+        );
     }
 
     public boolean addViewer(UUID uuid) {
@@ -131,12 +185,44 @@ public class WrapperEntity implements Tickable {
         return entityType;
     }
 
+    /**
+     * Returns an unmodifiable set of the passengers of the entity.
+     * @return the passengers of the entity
+     */
+    public Set<Integer> getPassengers() {
+        return Collections.unmodifiableSet(passengers);
+    }
+
+    public WrapperEntity getRiding() {
+        return world.getEntity(riding);
+    }
+
+
+
+    protected WrapperPlayServerSetPassengers createPassengerPacket() {
+        return new WrapperPlayServerSetPassengers(entityId, passengers.stream().mapToInt(i -> i).toArray());
+    }
+
 
     private WrapperPlayServerEntityVelocity getVelocityPacket() {
         Vector3d velocity = this.velocity.multiply(8000.0f / 20.0f);
         return new WrapperPlayServerEntityVelocity(entityId, velocity);
     }
 
+    public boolean isSpawned() {
+        return spawned;
+    }
+
+    @Override
+    public boolean isTicking() {
+        return ticking;
+    }
+
+    @Override
+    public void setTicking(boolean ticking) {
+        this.ticking = ticking;
+    }
+
     public boolean hasVelocity() {
         if (isOnGround()) {
             // if the entity is on the ground and only "moves" downwards, it does not have a velocity.
@@ -189,6 +275,135 @@ public class WrapperEntity implements Tickable {
         refresh();
     }
 
+    /**
+     * Adds a passenger to the entity. The passenger will be visible to all viewers of the entity.
+     * @param passenger the entity id of the passenger
+     */
+    public void addPassenger(int passenger) {
+        if (passengers.contains(passenger)) {
+            throw new IllegalArgumentException("Passenger already exists");
+        }
+        passengers.add(passenger);
+        sendPacketToViewers(createPassengerPacket());
+        WrapperEntity e = world.getEntity(passenger);
+        if (e != null) {
+            e.riding = this.entityId;
+            e.preRidingLocation = e.location;
+        }
+    }
+
+    public @Nullable Location getPreRidingLocation() {
+        return preRidingLocation;
+    }
+
+    /**
+     * @return the entity id of the entity that the entity is riding, -1 if the entity is not riding
+     */
+    public int getRidingId() {
+        return riding;
+    }
+
+
+    /**
+     * Adds multiple passengers to the entity. The passengers will be visible to all viewers of the entity.
+     * @param passengers the entity ids of the passengers
+     */
+    public void addPassengers(int... passengers) {
+        for (int passenger : passengers) {
+            addPassenger(passenger);
+        }
+    }
+
+    /**
+     * Adds a passenger to the entity. The passenger will be visible to all viewers of the entity.
+     * @param passenger the wrapper entity passenger
+     */
+    public void addPassenger(WrapperEntity passenger) {
+        addPassenger(passenger.getEntityId());
+    }
+
+    /**
+     * Adds multiple passengers to the entity. The passengers will be visible to all viewers of the entity.
+     * @param passengers the wrapper entity passengers
+     */
+    public void addPassengers(WrapperEntity... passengers) {
+        for (WrapperEntity passenger : passengers) {
+            addPassenger(passenger);
+        }
+    }
+
+    /**
+     * Removes a passenger from the entity. The passenger will be removed from the view of all viewers of the entity.
+     * @param passenger the entity id of the passenger
+     */
+    public void removePassenger(int passenger) {
+        if (!passengers.contains(passenger)) {
+            throw new IllegalArgumentException("Passenger does not exist");
+        }
+        passengers.remove(passenger);
+        sendPacketToViewers(createPassengerPacket());
+        WrapperEntity e = world.getEntity(passenger);
+        if (e != null) {
+            e.riding = -1;
+            e.teleport(world, e.preRidingLocation);
+        }
+    }
+
+    public WorldWrapper<?> getWorld() {
+        return world;
+    }
+
+    /**
+     * @param passenger the entity id of the passenger
+     * @return true if the entity has the passenger, false otherwise
+     */
+    public boolean hasPassenger(int passenger) {
+        return passengers.contains(passenger);
+    }
+
+    /**
+     * @param passenger the passenger wrapper entity
+     * @return true if the entity has the passenger, false otherwise
+     */
+    public boolean hasPassenger(WrapperEntity passenger) {
+        return hasPassenger(passenger.getEntityId());
+    }
+
+    /**
+     * Removes multiple passengers from the entity. The passengers will be removed from the view of all viewers of the entity.
+     * @param passengers the entity ids of the passengers
+     */
+    public void removePassengers(int... passengers) {
+        for (int passenger : passengers) {
+            removePassenger(passenger);
+        }
+    }
+
+    /**
+     * Removes a passenger from the entity. The passenger will be removed from the view of all viewers of the entity.
+     * @param passenger the wrapper entity passenger
+     */
+    public void removePassenger(WrapperEntity passenger) {
+        removePassenger(passenger.getEntityId());
+    }
+
+    /**
+     * Removes multiple passengers from the entity. The passengers will be removed from the view of all viewers of the entity.
+     * @param passengers the wrapper entity passengers
+     */
+    public void removePassengers(WrapperEntity... passengers) {
+        for (WrapperEntity passenger : passengers) {
+            removePassenger(passenger);
+        }
+    }
+
+    /**
+     * @return true if the entity has passengers, false otherwise
+     */
+    public boolean isRiding() {
+        return riding != -1;
+    }
+
     public @NotNull Set<UUID> getViewers() {
         return Collections.unmodifiableSet(viewers);
     }
@@ -199,6 +414,18 @@ public class WrapperEntity implements Tickable {
 
     @Override
     public void tick(long time) {
-
+        if (isRiding()) {
+            WrapperEntity riding = getRiding();
+            if (riding != null) {
+                Location l = riding.getLocation();
+                location = new Location(
+                        l.getX(),
+                        l.getY() + 1,
+                        l.getZ(),
+                        l.getYaw(),
+                        l.getPitch()
+                );
+            }
+        }
     }
 }
diff --git a/api/src/main/java/me/tofaa/entitylib/wrapper/ai/goals/RandomHeadMovementGoal.java b/api/src/main/java/me/tofaa/entitylib/wrapper/ai/goals/RandomHeadMovementGoal.java
index 973151c..af8868b 100644
--- a/api/src/main/java/me/tofaa/entitylib/wrapper/ai/goals/RandomHeadMovementGoal.java
+++ b/api/src/main/java/me/tofaa/entitylib/wrapper/ai/goals/RandomHeadMovementGoal.java
@@ -66,7 +66,7 @@ public class RandomHeadMovementGoal extends GoalSelector {
     @Override
     public void tick(long time) {
         --lookTime;
-        entity.teleport(CoordinateUtil.withDirection(entity.getLocation(), lookDirection));
+        entity.teleport(entity.getWorld(), CoordinateUtil.withDirection(entity.getLocation(), lookDirection));
     }
 
     @Override
diff --git a/common/src/main/java/me/tofaa/entitylib/common/AbstractWorldWrapper.java b/common/src/main/java/me/tofaa/entitylib/common/AbstractWorldWrapper.java
index 2fbaa67..b8515e3 100644
--- a/common/src/main/java/me/tofaa/entitylib/common/AbstractWorldWrapper.java
+++ b/common/src/main/java/me/tofaa/entitylib/common/AbstractWorldWrapper.java
@@ -37,8 +37,7 @@ public abstract class AbstractWorldWrapper<W> implements WorldWrapper<W> {
 
     @Override
     public <T extends WrapperEntity> @NotNull T spawnEntity(@NotNull T entity, @NotNull Location location) {
-        entity.teleport(location);
-        entity.spawn();
+        entity.spawn(this, location);
         entities.put(entity.getUuid(), entity);
         entitiesById.put(entity.getEntityId(), entity);
         return entity;

From e22a057bff0c23e6134e97aad1fa68c0a148d56a Mon Sep 17 00:00:00 2001
From: Tofaa <82680183+Tofaa2@users.noreply.github.com>
Date: Wed, 31 Jan 2024 17:46:25 +0400
Subject: [PATCH 06/19] push some codegen boilerplate

---
 .idea/gradle.xml                              |   1 +
 .idea/workspace.xml                           | 102 ++++++++-----
 .../java/me/tofaa/entitylib/EntityLib.java    |   2 +-
 .../java/me/tofaa/entitylib/WorldWrapper.java |   2 +
 .../me/tofaa/entitylib/meta/Metadata.java     |   1 -
 .../entitylib/wrapper/WrapperEntity.java      |  53 ++++++-
 .../ai/goals/RandomHeadMovementGoal.java      |   2 +-
 .../entitylib/wrapper/hologram/Hologram.java  |  70 +++++++++
 .../wrapper/hologram/LegacyHologram.java      | 140 ++++++++++++++++++
 .../wrapper/hologram/ModernHologram.java      |  98 ++++++++++++
 code-gen/build.gradle                         |  20 +++
 .../java/me/tofaa/entitylib/codegen/Main.java | 114 ++++++++++++++
 .../me/tofaa/entitylib/codegen/MetaClass.java |  34 +++++
 .../tofaa/entitylib/codegen/MetaMethod.java   |  65 ++++++++
 code-gen/src/main/resources/EntityMeta.json   |  15 ++
 .../common/AbstractEntityLibAPI.java          |   2 +
 .../common/AbstractWorldWrapper.java          |   7 +
 settings.gradle                               |   1 +
 .../java/me/tofaa/entitylib/EntityLib.java    |   2 +-
 .../testentitylib/TestEntityLibPlugin.java    |  34 ++++-
 20 files changed, 724 insertions(+), 41 deletions(-)
 create mode 100644 api/src/main/java/me/tofaa/entitylib/wrapper/hologram/Hologram.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/wrapper/hologram/LegacyHologram.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/wrapper/hologram/ModernHologram.java
 create mode 100644 code-gen/build.gradle
 create mode 100644 code-gen/src/main/java/me/tofaa/entitylib/codegen/Main.java
 create mode 100644 code-gen/src/main/java/me/tofaa/entitylib/codegen/MetaClass.java
 create mode 100644 code-gen/src/main/java/me/tofaa/entitylib/codegen/MetaMethod.java
 create mode 100644 code-gen/src/main/resources/EntityMeta.json

diff --git a/.idea/gradle.xml b/.idea/gradle.xml
index 2ca8717..228b351 100644
--- a/.idea/gradle.xml
+++ b/.idea/gradle.xml
@@ -9,6 +9,7 @@
           <set>
             <option value="$PROJECT_DIR$" />
             <option value="$PROJECT_DIR$/api" />
+            <option value="$PROJECT_DIR$/code-gen" />
             <option value="$PROJECT_DIR$/common" />
             <option value="$PROJECT_DIR$/platforms" />
             <option value="$PROJECT_DIR$/platforms/spigot" />
diff --git a/.idea/workspace.xml b/.idea/workspace.xml
index d31bff8..a04b889 100644
--- a/.idea/workspace.xml
+++ b/.idea/workspace.xml
@@ -5,15 +5,25 @@
   </component>
   <component name="ChangeListManager">
     <list default="true" id="9d5d9b6f-43c8-41a4-bb42-a66ffc96c9b0" name="Changes" comment="">
-      <change afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/meta/CompatibilityIndex.java" afterDir="false" />
+      <change afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/wrapper/hologram/Hologram.java" afterDir="false" />
+      <change afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/wrapper/hologram/LegacyHologram.java" afterDir="false" />
+      <change afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/wrapper/hologram/ModernHologram.java" afterDir="false" />
+      <change afterPath="$PROJECT_DIR$/code-gen/src/main/java/me/tofaa/entitylib/codegen/Main.java" afterDir="false" />
+      <change afterPath="$PROJECT_DIR$/code-gen/src/main/java/me/tofaa/entitylib/codegen/MetaClass.java" afterDir="false" />
+      <change afterPath="$PROJECT_DIR$/code-gen/src/main/java/me/tofaa/entitylib/codegen/MetaMethod.java" afterDir="false" />
+      <change afterPath="$PROJECT_DIR$/code-gen/src/main/resources/EntityMeta.json" afterDir="false" />
+      <change beforePath="$PROJECT_DIR$/.idea/gradle.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/gradle.xml" afterDir="false" />
       <change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
+      <change beforePath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/EntityLib.java" beforeDir="false" afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/EntityLib.java" afterDir="false" />
       <change beforePath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/WorldWrapper.java" beforeDir="false" afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/WorldWrapper.java" afterDir="false" />
-      <change beforePath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/meta/UsedVersion.java" beforeDir="false" />
-      <change beforePath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/meta/VersionCompatCheck.java" beforeDir="false" />
-      <change beforePath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/tick/Tickable.java" beforeDir="false" afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/tick/Tickable.java" afterDir="false" />
+      <change beforePath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/meta/Metadata.java" beforeDir="false" afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/meta/Metadata.java" afterDir="false" />
       <change beforePath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperEntity.java" beforeDir="false" afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperEntity.java" afterDir="false" />
       <change beforePath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/wrapper/ai/goals/RandomHeadMovementGoal.java" beforeDir="false" afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/wrapper/ai/goals/RandomHeadMovementGoal.java" afterDir="false" />
+      <change beforePath="$PROJECT_DIR$/common/src/main/java/me/tofaa/entitylib/common/AbstractEntityLibAPI.java" beforeDir="false" afterPath="$PROJECT_DIR$/common/src/main/java/me/tofaa/entitylib/common/AbstractEntityLibAPI.java" afterDir="false" />
       <change beforePath="$PROJECT_DIR$/common/src/main/java/me/tofaa/entitylib/common/AbstractWorldWrapper.java" beforeDir="false" afterPath="$PROJECT_DIR$/common/src/main/java/me/tofaa/entitylib/common/AbstractWorldWrapper.java" afterDir="false" />
+      <change beforePath="$PROJECT_DIR$/settings.gradle" beforeDir="false" afterPath="$PROJECT_DIR$/settings.gradle" afterDir="false" />
+      <change beforePath="$PROJECT_DIR$/src/main/java/me/tofaa/entitylib/EntityLib.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/me/tofaa/entitylib/EntityLib.java" afterDir="false" />
+      <change beforePath="$PROJECT_DIR$/test-plugin/src/main/java/me/tofaa/testentitylib/TestEntityLibPlugin.java" beforeDir="false" afterPath="$PROJECT_DIR$/test-plugin/src/main/java/me/tofaa/testentitylib/TestEntityLibPlugin.java" afterDir="false" />
     </list>
     <option name="SHOW_DIALOG" value="false" />
     <option name="HIGHLIGHT_CONFLICTS" value="true" />
@@ -76,42 +86,56 @@
     <option name="showExcludedFiles" value="false" />
     <option name="showLibraryContents" value="true" />
   </component>
-  <component name="PropertiesComponent">{
-  &quot;keyToString&quot;: {
-    &quot;Downloaded.Files.Path.Enabled&quot;: &quot;false&quot;,
-    &quot;Gradle.Build EntityLib.executor&quot;: &quot;Run&quot;,
-    &quot;Gradle.EntityLib [dependencies].executor&quot;: &quot;Run&quot;,
-    &quot;Gradle.EntityLib:test-plugin [runServer].executor&quot;: &quot;Run&quot;,
-    &quot;Repository.Attach.Annotations&quot;: &quot;false&quot;,
-    &quot;Repository.Attach.JavaDocs&quot;: &quot;false&quot;,
-    &quot;Repository.Attach.Sources&quot;: &quot;false&quot;,
-    &quot;RunOnceActivity.OpenProjectViewOnStart&quot;: &quot;true&quot;,
-    &quot;RunOnceActivity.ShowReadmeOnStart&quot;: &quot;true&quot;,
-    &quot;WebServerToolWindowFactoryState&quot;: &quot;false&quot;,
-    &quot;git-widget-placeholder&quot;: &quot;feat/platform-api&quot;,
-    &quot;ignore.virus.scanning.warn.message&quot;: &quot;true&quot;,
-    &quot;jdk.selected.JAVA_MODULE&quot;: &quot;corretto-17&quot;,
-    &quot;kotlin-language-version-configured&quot;: &quot;true&quot;,
-    &quot;last_opened_file_path&quot;: &quot;D:/Github/EntityLib/api/src/main/java/me/tofaa/entitylib/meta&quot;,
-    &quot;node.js.detected.package.eslint&quot;: &quot;true&quot;,
-    &quot;node.js.detected.package.tslint&quot;: &quot;true&quot;,
-    &quot;node.js.selected.package.eslint&quot;: &quot;(autodetect)&quot;,
-    &quot;node.js.selected.package.tslint&quot;: &quot;(autodetect)&quot;,
-    &quot;nodejs_package_manager_path&quot;: &quot;npm&quot;,
-    &quot;project.structure.last.edited&quot;: &quot;Modules&quot;,
-    &quot;project.structure.proportion&quot;: &quot;0.15&quot;,
-    &quot;project.structure.side.proportion&quot;: &quot;0.2&quot;,
-    &quot;settings.editor.selected.configurable&quot;: &quot;preferences.pluginManager&quot;,
-    &quot;vue.rearranger.settings.migration&quot;: &quot;true&quot;
+  <component name="PropertiesComponent"><![CDATA[{
+  "keyToString": {
+    "Downloaded.Files.Path.Enabled": "false",
+    "Gradle.Build EntityLib.executor": "Run",
+    "Gradle.EntityLib [dependencies].executor": "Run",
+    "Gradle.EntityLib:code-gen [:code-gen:Main.main()].executor": "Run",
+    "Gradle.EntityLib:test-plugin [runServer].executor": "Run",
+    "Repository.Attach.Annotations": "false",
+    "Repository.Attach.JavaDocs": "false",
+    "Repository.Attach.Sources": "false",
+    "RunOnceActivity.OpenProjectViewOnStart": "true",
+    "RunOnceActivity.ShowReadmeOnStart": "true",
+    "WebServerToolWindowFactoryState": "false",
+    "git-widget-placeholder": "feat/platform-api",
+    "ignore.virus.scanning.warn.message": "true",
+    "jdk.selected.JAVA_MODULE": "corretto-17",
+    "kotlin-language-version-configured": "true",
+    "last_opened_file_path": "D:/Github/EntityLib/api/src/main/java/me/tofaa/entitylib/meta",
+    "node.js.detected.package.eslint": "true",
+    "node.js.detected.package.tslint": "true",
+    "node.js.selected.package.eslint": "(autodetect)",
+    "node.js.selected.package.tslint": "(autodetect)",
+    "nodejs_package_manager_path": "npm",
+    "project.structure.last.edited": "Project",
+    "project.structure.proportion": "0.15",
+    "project.structure.side.proportion": "0.2",
+    "settings.editor.selected.configurable": "preferences.pluginManager",
+    "vue.rearranger.settings.migration": "true"
   }
-}</component>
+}]]></component>
   <component name="RecentsManager">
     <key name="CopyFile.RECENT_KEYS">
       <recent name="D:\Github\EntityLib\api\src\main\java\me\tofaa\entitylib\meta" />
       <recent name="D:\Github\EntityLib\test-plugin" />
     </key>
   </component>
-  <component name="RunManager" selected="Gradle.EntityLib [dependencies]">
+  <component name="RunManager" selected="Application.Main">
+    <configuration name="Main" type="Application" factoryName="Application" temporary="true" nameIsGenerated="true">
+      <option name="MAIN_CLASS_NAME" value="me.tofaa.entitylib.codegen.Main" />
+      <module name="EntityLib.code-gen.main" />
+      <extension name="coverage">
+        <pattern>
+          <option name="PATTERN" value="me.tofaa.entitylib.codegen.*" />
+          <option name="ENABLED" value="true" />
+        </pattern>
+      </extension>
+      <method v="2">
+        <option name="Make" enabled="true" />
+      </method>
+    </configuration>
     <configuration name="EntityLib [dependencies]" type="GradleRunConfiguration" factoryName="Gradle" temporary="true">
       <ExternalSystemSettings>
         <option name="executionName" />
@@ -202,6 +226,7 @@
     </configuration>
     <recent_temporary>
       <list>
+        <item itemvalue="Application.Main" />
         <item itemvalue="Gradle.EntityLib [dependencies]" />
         <item itemvalue="Gradle.EntityLib:test-plugin [runServer]" />
         <item itemvalue="Gradle.PE-EntityMeta [compileTestJava]" />
@@ -256,7 +281,11 @@
       <workItem from="1706284605696" duration="11691000" />
       <workItem from="1706371324325" duration="1187000" />
       <workItem from="1706443875388" duration="4827000" />
-      <workItem from="1706513591682" duration="2661000" />
+      <workItem from="1706513591682" duration="8659000" />
+      <workItem from="1706592660140" duration="89000" />
+      <workItem from="1706601592145" duration="1670000" />
+      <workItem from="1706614921404" duration="10508000" />
+      <workItem from="1706696719616" duration="4783000" />
     </task>
     <servers />
   </component>
@@ -271,6 +300,11 @@
           <line>6787</line>
           <option name="timeStamp" value="1" />
         </line-breakpoint>
+        <line-breakpoint enabled="true" type="java-line">
+          <url>file://$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/wrapper/hologram/LegacyHologram.java</url>
+          <line>37</line>
+          <option name="timeStamp" value="3" />
+        </line-breakpoint>
         <line-breakpoint enabled="true" type="java-method">
           <url>file://$PROJECT_DIR$/src/main/java/me/tofaa/entitylib/meta/types/DisplayMeta.java</url>
           <line>153</line>
diff --git a/api/src/main/java/me/tofaa/entitylib/EntityLib.java b/api/src/main/java/me/tofaa/entitylib/EntityLib.java
index 9e9d77e..bc21eb1 100644
--- a/api/src/main/java/me/tofaa/entitylib/EntityLib.java
+++ b/api/src/main/java/me/tofaa/entitylib/EntityLib.java
@@ -30,7 +30,7 @@ public final class EntityLib {
         }
     }
 
-    public static EntityLibAPI<?, ?> getApi() {
+    public static <W, T> EntityLibAPI<W, T> getApi() {
         return api;
     }
 
diff --git a/api/src/main/java/me/tofaa/entitylib/WorldWrapper.java b/api/src/main/java/me/tofaa/entitylib/WorldWrapper.java
index d421c35..7578c8f 100644
--- a/api/src/main/java/me/tofaa/entitylib/WorldWrapper.java
+++ b/api/src/main/java/me/tofaa/entitylib/WorldWrapper.java
@@ -35,6 +35,8 @@ public interface WorldWrapper<W> {
     @Nullable WrapperEntity getEntity(@NotNull UUID uuid);
 
 
+    void removeEntity(WrapperEntity entity);
+
     /**
      * Gets the block at the specified coordinates. Depending on the platforms implementation, this method may be slow.
      * @param x The x coordinate.
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/Metadata.java b/api/src/main/java/me/tofaa/entitylib/meta/Metadata.java
index cc4c681..532472a 100644
--- a/api/src/main/java/me/tofaa/entitylib/meta/Metadata.java
+++ b/api/src/main/java/me/tofaa/entitylib/meta/Metadata.java
@@ -3,7 +3,6 @@ package me.tofaa.entitylib.meta;
 import com.github.retrooper.packetevents.protocol.entity.data.EntityData;
 import com.github.retrooper.packetevents.protocol.entity.data.EntityDataType;
 import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerEntityMetadata;
-import me.tofaa.entitylib.EntityLib;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
diff --git a/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperEntity.java b/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperEntity.java
index 8bf058e..407059b 100644
--- a/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperEntity.java
+++ b/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperEntity.java
@@ -42,6 +42,7 @@ public class WrapperEntity implements Tickable {
         this.entityType = entityType;
         this.entityMeta = entityMeta;
         this.ticking = true;
+        this.viewers = new HashSet<>();
     }
 
     public boolean spawn(WorldWrapper<?> world, Location location) {
@@ -84,15 +85,23 @@ public class WrapperEntity implements Tickable {
         return true;
     }
 
+    public void remove() {
+        world.removeEntity(this);
+    }
+
     public void despawn() {
         if (!spawned) return;
         spawned = false;
         sendPacketToViewers(new WrapperPlayServerDestroyEntities(entityId));
     }
 
-    public void teleport(WorldWrapper<?> world, @NotNull Location location) {
+    public void teleport(WorldWrapper<?> world, @NotNull Location location, boolean onGround) {
+        if (!spawned) {
+            return;
+        }
         this.location = location;
         this.world = world;
+        this.onGround = onGround;
         sendPacketToViewers(
                 new WrapperPlayServerEntityTeleport(
                         entityId,
@@ -104,6 +113,10 @@ public class WrapperEntity implements Tickable {
         );
     }
 
+    public void teleport(WorldWrapper<?> world, @NotNull Location location) {
+        teleport(world, location, onGround);
+    }
+
     public boolean addViewer(UUID uuid) {
         if (!viewers.add(uuid)) {
             return false;
@@ -129,6 +142,22 @@ public class WrapperEntity implements Tickable {
         addViewer(user.getUUID());
     }
 
+    /**
+     * Adds a viewer silently into the viewers set. The viewer will not receive any packets or be informed of this addition
+     * @param uuid the uuid of the user to add
+     */
+    public void addViewerSilently(UUID uuid) {
+        viewers.add(uuid);
+    }
+
+    /**
+     * Adds a viewer silently into the viewers set. The viewer will not receive any packets or be informed of this addition
+     * @param user the user to add
+     */
+    public void addViewerSilently(User user) {
+        addViewerSilently(user.getUUID());
+    }
+
     public void removeViewer(UUID uuid) {
         if (!viewers.remove(uuid)) {
             return;
@@ -136,6 +165,26 @@ public class WrapperEntity implements Tickable {
         sendPacket(uuid, new WrapperPlayServerDestroyEntities(entityId));
     }
 
+    public void removeViewer(User user) {
+        removeViewer(user.getUUID());
+    }
+
+    /**
+     * removes a viewer silently into the viewers set. The viewer will not receive any packets or be informed of this removal
+     * @param uuid of the user to remove
+     */
+    public void removeViewerSilently(UUID uuid) {
+        viewers.remove(uuid);
+    }
+
+    /**
+     * removes a viewer silently into the viewers set. The viewer will not receive any packets or be informed of this removal
+     * @param user the user to remove
+     */
+    public void removeViewerSilently(User user) {
+        removeViewerSilently(user.getUUID());
+    }
+
     public boolean isOnGround() {
         return onGround;
     }
@@ -345,7 +394,7 @@ public class WrapperEntity implements Tickable {
         WrapperEntity e = world.getEntity(passenger);
         if (e != null) {
             e.riding = -1;
-            e.teleport(world, e.preRidingLocation);
+            e.teleport(world, e.preRidingLocation, e.onGround);
         }
     }
 
diff --git a/api/src/main/java/me/tofaa/entitylib/wrapper/ai/goals/RandomHeadMovementGoal.java b/api/src/main/java/me/tofaa/entitylib/wrapper/ai/goals/RandomHeadMovementGoal.java
index af8868b..a69b925 100644
--- a/api/src/main/java/me/tofaa/entitylib/wrapper/ai/goals/RandomHeadMovementGoal.java
+++ b/api/src/main/java/me/tofaa/entitylib/wrapper/ai/goals/RandomHeadMovementGoal.java
@@ -66,7 +66,7 @@ public class RandomHeadMovementGoal extends GoalSelector {
     @Override
     public void tick(long time) {
         --lookTime;
-        entity.teleport(entity.getWorld(), CoordinateUtil.withDirection(entity.getLocation(), lookDirection));
+        entity.teleport(entity.getWorld(), CoordinateUtil.withDirection(entity.getLocation(), lookDirection), entity.isOnGround());
     }
 
     @Override
diff --git a/api/src/main/java/me/tofaa/entitylib/wrapper/hologram/Hologram.java b/api/src/main/java/me/tofaa/entitylib/wrapper/hologram/Hologram.java
new file mode 100644
index 0000000..5d684f6
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/wrapper/hologram/Hologram.java
@@ -0,0 +1,70 @@
+package me.tofaa.entitylib.wrapper.hologram;
+
+import com.github.retrooper.packetevents.protocol.world.Location;
+import com.github.retrooper.packetevents.util.Vector3f;
+import me.tofaa.entitylib.WorldWrapper;
+import me.tofaa.entitylib.meta.display.TextDisplayMeta;
+import me.tofaa.entitylib.meta.types.DisplayMeta;
+import net.kyori.adventure.text.Component;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.List;
+import java.util.function.Consumer;
+
+public interface Hologram<W> {
+
+    static <C> Hologram.@NotNull Legacy<C> legacy(@NotNull WorldWrapper<C> world, @NotNull Location location) {
+        return new LegacyHologram<>(world, location);
+    }
+
+    static <C> Hologram.@NotNull Legacy<C> legacy(@NotNull WorldWrapper<C> world, @NotNull Location location, List<Component> lines) {
+        return new LegacyHologram<>(world, location, lines);
+    }
+
+
+    @NotNull Location getLocation();
+
+    @NotNull WorldWrapper<W> getWorld();
+
+    void show();
+
+    void hide();
+
+    void teleport(Location location);
+
+    @Nullable Component getLine(int index);
+
+    int length();
+
+    void setLine(int index, @Nullable Component line);
+
+    void addLine(@Nullable Component line);
+
+    interface Modern<W> extends Hologram<W> {
+
+        // I got too lazy
+        void setModifier(@NotNull Consumer<TextDisplayMeta> consumer);
+
+    }
+    interface Legacy<W> extends Hologram<W> {
+
+        float getLineOffset(boolean marker);
+
+        void setLineOffset(boolean marker, float value);
+
+        default float getLineOffset() {
+            return getLineOffset(false);
+        }
+
+        default void setLineOffset(float value) {
+            setLineOffset(false, value);
+        }
+
+        boolean isMarker();
+
+        void setMarker(boolean marker);
+
+    }
+
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/wrapper/hologram/LegacyHologram.java b/api/src/main/java/me/tofaa/entitylib/wrapper/hologram/LegacyHologram.java
new file mode 100644
index 0000000..d885fa7
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/wrapper/hologram/LegacyHologram.java
@@ -0,0 +1,140 @@
+package me.tofaa.entitylib.wrapper.hologram;
+
+import com.github.retrooper.packetevents.protocol.entity.type.EntityTypes;
+import com.github.retrooper.packetevents.protocol.world.Location;
+import com.github.retrooper.packetevents.util.Vector3d;
+import me.tofaa.entitylib.EntityLib;
+import me.tofaa.entitylib.WorldWrapper;
+import me.tofaa.entitylib.meta.other.ArmorStandMeta;
+import me.tofaa.entitylib.wrapper.WrapperEntity;
+import net.kyori.adventure.text.Component;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.ArrayList;
+import java.util.List;
+
+final class LegacyHologram<W> implements Hologram.Legacy<W> {
+
+    private Location location;
+    private WorldWrapper<W> world;
+    private List<WrapperEntity> lines = new ArrayList<>(3);
+    private float lineOffset = -0.9875f;
+    private float markerOffset = -0.40625f;
+    private boolean marker;
+
+    LegacyHologram(@NotNull WorldWrapper<W> world, @NotNull Location location) {
+        this.world = world;
+        this.location = location;
+    }
+
+    LegacyHologram(@NotNull WorldWrapper<W> world, @NotNull Location location, List<Component> lines) {
+        this(world, location);
+        for (Component line : lines) {
+            addLine(line);
+        }
+    }
+
+    @Override
+    public boolean isMarker() {
+        return marker;
+    }
+
+    @Override
+    public void setMarker(boolean marker) {
+        this.marker = true;
+        if (lines.isEmpty()) return;
+        teleport(location); // refresh
+    }
+
+    @Override
+    public void show() {
+        for (WrapperEntity line : lines) {
+            line.spawn(world, location);
+        }
+        teleport(location);
+    }
+
+    @Override
+    public void hide() {
+        for (WrapperEntity line : lines) {
+            line.despawn();
+        }
+    }
+
+    @Override
+    public void teleport(Location location) {
+        this.location = location;
+        // reversed order
+        for (int i = lines.size() -1; i >= 0; i--) {
+            WrapperEntity line = lines.get(i);
+            double y;
+            if (marker) {
+                y = location.getY() + markerOffset;
+            } else {
+                y = location.getY() + (i * lineOffset);
+            }
+            ArmorStandMeta meta = (ArmorStandMeta) line.getEntityMeta();
+            meta.setMarker(marker);
+            Location l = new Location(location.getX(), y, location.getZ(), location.getYaw(), location.getPitch());
+            line.teleport(world, l, false);
+        }
+    }
+
+    @Override
+    public @Nullable Component getLine(int index) {
+        if (index < 0 || index >= lines.size()) {
+            return null;
+        }
+        return lines.get(index).getEntityMeta().getCustomName();
+    }
+
+    @Override
+    public void setLine(int index, @Nullable Component line) {
+        WrapperEntity e = world.spawnEntity(EntityTypes.ARMOR_STAND, location);
+        ArmorStandMeta meta = (ArmorStandMeta) e.getEntityMeta();
+        meta.setCustomName(line);
+        meta.setCustomNameVisible(true);
+        meta.setInvisible(true);
+        meta.setHasNoGravity(true);
+        meta.setSmall(true);
+        meta.setMarker(marker);
+        this.lines.set(index, e);
+        e.spawn(world, location);
+        teleport(location);
+    }
+
+    @Override
+    public void addLine(@Nullable Component line) {
+        setLine(lines.size(), line);
+    }
+
+    @Override
+    public float getLineOffset(boolean marker) {
+        return marker ? markerOffset : lineOffset;
+    }
+
+    @Override
+    public int length() {
+        return lines.size();
+    }
+
+    @Override
+    public void setLineOffset(boolean marker, float value) {
+        if (marker) {
+            markerOffset = value;
+        } else {
+            lineOffset = value;
+        }
+    }
+
+    @Override
+    public @NotNull Location getLocation() {
+        return location;
+    }
+
+    @Override
+    public @NotNull WorldWrapper<W> getWorld() {
+        return world;
+    }
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/wrapper/hologram/ModernHologram.java b/api/src/main/java/me/tofaa/entitylib/wrapper/hologram/ModernHologram.java
new file mode 100644
index 0000000..028fe51
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/wrapper/hologram/ModernHologram.java
@@ -0,0 +1,98 @@
+package me.tofaa.entitylib.wrapper.hologram;
+
+import com.github.retrooper.packetevents.protocol.entity.type.EntityTypes;
+import com.github.retrooper.packetevents.protocol.world.Location;
+import me.tofaa.entitylib.WorldWrapper;
+import me.tofaa.entitylib.meta.display.TextDisplayMeta;
+import me.tofaa.entitylib.meta.other.ArmorStandMeta;
+import me.tofaa.entitylib.wrapper.WrapperEntity;
+import net.kyori.adventure.text.Component;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.function.Consumer;
+
+final class ModernHologram<W> implements Hologram.Modern<W> {
+
+    private Location location;
+    private WorldWrapper<W> world;
+    private List<WrapperEntity> lines = new ArrayList<>(3);
+    private Consumer<TextDisplayMeta> modifier;
+
+    @Override
+    public void show() {
+        for (WrapperEntity line : lines) {
+            line.spawn(world, location);
+        }
+        teleport(location);
+    }
+
+    @Override
+    public void hide() {
+        for (WrapperEntity line : lines) {
+            line.despawn();
+        }
+    }
+
+    @Override
+    public void teleport(Location location) {
+        this.location = location;
+        if (lines.isEmpty()) return;
+        WrapperEntity first = lines.get(0);
+        first.teleport(world, location);
+        for (WrapperEntity e : lines) {
+            if (e.getUuid().equals(first.getUuid())) continue;
+            first.addPassenger(e);
+        }
+    }
+
+    @Override
+    public @Nullable Component getLine(int index) {
+        if (index < 0 || index >= lines.size()) {
+            return null;
+        }
+        return lines.get(index).getEntityMeta().getCustomName();
+    }
+
+    @Override
+    public void setLine(int index, @Nullable Component line) {
+        WrapperEntity e = world.spawnEntity(EntityTypes.TEXT_DISPLAY, location);
+        TextDisplayMeta meta = (TextDisplayMeta) e.getEntityMeta();
+        meta.setInvisible(true);
+        meta.setHasNoGravity(true);
+        meta.setText(line);
+        this.modifier.accept(meta);
+        this.lines.set(index, e);
+        e.spawn(world, location);
+        teleport(location);
+    }
+
+    @Override
+    public void addLine(@Nullable Component line) {
+        setLine(lines.size(), line);
+    }
+
+
+    @Override
+    public int length() {
+        return lines.size();
+    }
+
+    @Override
+    public @NotNull Location getLocation() {
+        return location;
+    }
+
+    @Override
+    public @NotNull WorldWrapper<W> getWorld() {
+        return world;
+    }
+
+
+    @Override
+    public void setModifier(@NotNull Consumer<TextDisplayMeta> consumer) {
+        this.modifier = consumer;
+    }
+}
diff --git a/code-gen/build.gradle b/code-gen/build.gradle
new file mode 100644
index 0000000..e6439d3
--- /dev/null
+++ b/code-gen/build.gradle
@@ -0,0 +1,20 @@
+plugins {
+    id 'java'
+}
+
+
+// jdk 17
+sourceCompatibility = JavaVersion.VERSION_17
+targetCompatibility = JavaVersion.VERSION_17
+
+
+repositories {
+    mavenCentral()
+}
+
+dependencies {
+    implementation 'com.google.code.gson:gson:2.10.1'
+    implementation 'com.squareup:javapoet:1.13.0'
+    implementation 'com.github.retrooper.packetevents:api:2.2.0'
+    implementation 'org.jetbrains:annotations:24.0.0'
+}
diff --git a/code-gen/src/main/java/me/tofaa/entitylib/codegen/Main.java b/code-gen/src/main/java/me/tofaa/entitylib/codegen/Main.java
new file mode 100644
index 0000000..4cbb5bb
--- /dev/null
+++ b/code-gen/src/main/java/me/tofaa/entitylib/codegen/Main.java
@@ -0,0 +1,114 @@
+package me.tofaa.entitylib.codegen;
+
+import com.github.retrooper.packetevents.protocol.entity.data.EntityData;
+import com.github.retrooper.packetevents.protocol.entity.data.EntityDataType;
+import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerEntityMetadata;
+import com.google.gson.reflect.TypeToken;
+import com.squareup.javapoet.*;
+import org.jetbrains.annotations.NotNull;
+
+import javax.lang.model.element.Modifier;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+public final class Main {
+
+    private Main() {}
+
+    public static void main(String[] args) throws IOException {
+        createMetadataClass();
+        List<MetaClass> metaClasses = new ArrayList<>();
+
+        // test
+
+
+    }
+
+    private static void writeClass(MetaClass metaClass) {
+        File file = new File("src/main/java");
+        TypeSpec typeSpec = metaClass.create();
+        JavaFile javaFile = JavaFile.builder("me.tofaa.entitylib.meta", typeSpec).build();
+        try {
+            FileWriter fileWriter = new FileWriter(file);
+            javaFile.writeTo(fileWriter);
+        }
+        catch (IOException e)  {
+            throw new RuntimeException(e);
+        }
+    }
+
+    private static void createMetadataClass() {
+
+        TypeSpec.Builder builder = builder("me.tofaa.entitylib.meta", "Metadata");
+        builder.addField(int.class, "entityId", Modifier.PRIVATE, Modifier.FINAL);
+        builder.addField(TypeToken.getParameterized(Map.class, Byte.class, EntityDataType.class).getType(), "metadataMap", Modifier.PRIVATE, Modifier.FINAL);
+
+        MethodSpec.Builder constructor = MethodSpec.constructorBuilder()
+                .addModifiers(Modifier.PUBLIC)
+                .addCode("this.entityId = entityId;\n")
+                .addCode("this.metadataMap = new ConcurrentHashMap<>();\n")
+                .addParameter(int.class, "entityId");
+
+        MethodSpec.Builder getIndex = MethodSpec.methodBuilder("getIndex")
+                .addModifiers(Modifier.PUBLIC)
+                .addTypeVariable(TypeVariableName.get("T"))
+                .addParameter(byte.class, "index")
+                .addParameter(TypeVariableName.get("T"), "defaultValue")
+                .returns(TypeVariableName.get("T"))
+                .addCode("EntityData entityData = metadataMap.get(index);\n")
+                .addCode("if (entityData == null) return defaultValue;\n")
+                .addCode("if (entityData.getValue() == null) return defaultValue;\n")
+                .addCode("return (T) entityData.getValue();\n");
+
+        MethodSpec.Builder setIndex = MethodSpec.methodBuilder("setIndex")
+                .addModifiers(Modifier.PUBLIC)
+                .addTypeVariable(TypeVariableName.get("T"))
+                .addParameter(byte.class, "index")
+                .addParameter(EntityDataType.class, "dataType")
+                .addParameter(TypeVariableName.get("T"), "value")
+                .addCode("EntityData data = new EntityData(index, dataType, value);\n")
+                .addCode("this.metadataMap.put(index, data);\n");
+
+        MethodSpec.Builder getEntries = MethodSpec.methodBuilder("getEntries")
+                .addModifiers(Modifier.PUBLIC)
+                .returns(TypeToken.getParameterized(List.class, EntityData.class).getType())
+                .addCode("return new ArrayList<>(metadataMap.values());\n")
+                .addAnnotation(NotNull.class);
+
+        MethodSpec.Builder createPacket = MethodSpec.methodBuilder("createPacket")
+                .addModifiers(Modifier.PUBLIC)
+                .returns(WrapperPlayServerEntityMetadata.class)
+                .addCode("return new WrapperPlayServerEntityMetadata(entityId, getEntries());\n")
+                .addAnnotation(NotNull.class);
+
+        builder.addMethod(constructor.build());
+        builder.addMethod(getIndex.build());
+        builder.addMethod(setIndex.build());
+        builder.addMethod(getEntries.build());
+        builder.addMethod(createPacket.build());
+
+        File file = new File("src/main/java");
+        JavaFile javaFile = JavaFile.builder("me.tofaa.entitylib.meta", builder.build()).build();
+        try {
+            FileWriter fileWriter = new FileWriter(file);
+            javaFile.writeTo(fileWriter);
+        }
+        catch (IOException e)  {
+            throw new RuntimeException(e);
+        }
+    }
+
+    // Include comment in generated code
+    public static TypeSpec.Builder builder(String packageName, String className) {
+        return TypeSpec.classBuilder(ClassName.get(packageName, className))
+                .addModifiers(Modifier.PUBLIC)
+                .addJavadoc("AUTOGENERATED CODE BY ENTITYLIB CODEGEN\n")
+                .addJavadoc("DO NOT EDIT\n");
+    }
+
+
+}
diff --git a/code-gen/src/main/java/me/tofaa/entitylib/codegen/MetaClass.java b/code-gen/src/main/java/me/tofaa/entitylib/codegen/MetaClass.java
new file mode 100644
index 0000000..0f84713
--- /dev/null
+++ b/code-gen/src/main/java/me/tofaa/entitylib/codegen/MetaClass.java
@@ -0,0 +1,34 @@
+package me.tofaa.entitylib.codegen;
+
+import com.squareup.javapoet.ClassName;
+import com.squareup.javapoet.TypeSpec;
+
+import java.util.List;
+
+import static me.tofaa.entitylib.codegen.Main.builder;
+
+public record MetaClass(
+        String name,
+        String extendsClass,
+        List<MetaMethod> methods
+) {
+
+
+    public TypeSpec create() {
+        String split[] = name.split(":");
+        String packageName = split[0];
+        String className = split[1];
+
+        TypeSpec.Builder builder = builder(packageName, className);
+        if (extendsClass != null) {
+            String[] extendsSplit = extendsClass.split(":");
+            builder.superclass(ClassName.get(extendsSplit[0], extendsSplit[1]));
+        }
+        for (MetaMethod method : methods) {
+            builder.addMethods(method.create());
+        }
+        return builder.build();
+    }
+
+
+}
diff --git a/code-gen/src/main/java/me/tofaa/entitylib/codegen/MetaMethod.java b/code-gen/src/main/java/me/tofaa/entitylib/codegen/MetaMethod.java
new file mode 100644
index 0000000..90ecc37
--- /dev/null
+++ b/code-gen/src/main/java/me/tofaa/entitylib/codegen/MetaMethod.java
@@ -0,0 +1,65 @@
+package me.tofaa.entitylib.codegen;
+
+import com.squareup.javapoet.ClassName;
+import com.squareup.javapoet.MethodSpec;
+
+import javax.lang.model.element.Modifier;
+import java.util.List;
+
+public record MetaMethod(
+        String name,
+        String returnType,
+        String defaultReturn,
+        String dataType,
+        List<VersionCheck> versionChecks
+) {
+
+    public List<MethodSpec> create() {
+        String[] nameSplit = name.split(":");
+        String[] returnSplit = returnType.split(":");
+        String namePackage = nameSplit[0];
+        String nameClass = nameSplit[1];
+        String returnPackage = returnSplit[0];
+        String returnClass = returnSplit[1];
+
+        String methodBasedName = nameClass.substring(0, 1).toUpperCase() + nameClass.substring(1);
+
+        /* offset calculator first */
+        MethodSpec.Builder calculator = MethodSpec.methodBuilder(
+                "calculate" + methodBasedName + "Offset")
+                .addModifiers(Modifier.PRIVATE, Modifier.STATIC)
+                .addParameter(int.class, "version");
+        for (VersionCheck check : versionChecks) {
+            calculator.beginControlFlow("if (version >= $L && version <= $L)", check.from(), check.to());
+            calculator.addStatement("return $L", check.offset());
+            calculator.endControlFlow();
+        }
+        // throw exception if version is not in range
+        calculator.addStatement("throw new IllegalArgumentException(\"Version \" + version + \" is not in range\")");
+
+        String versionVariable = "byte offset = calculate" + methodBasedName + "Offset(EntityLib.getApi().getPacketEvents().getServerManager().getVersion().getProtocolVersion())";
+
+        /* getter method spec. No params */
+        MethodSpec.Builder getter = MethodSpec.methodBuilder("get" + methodBasedName)
+                .addModifiers(Modifier.PUBLIC)
+                .returns(ClassName.get(returnPackage, returnClass))
+                .addStatement(versionVariable)
+                .addStatement("return metadata.getIndex(" + "offset," + defaultReturn);
+
+        MethodSpec.Builder setter = MethodSpec.methodBuilder("set" + methodBasedName)
+                .addModifiers(Modifier.PUBLIC)
+                .returns(void.class)
+                .addParameter(ClassName.get(returnPackage, returnClass), "value")
+                .addStatement(versionVariable)
+                .addStatement("metadata.setIndex(" + "offset, " + dataType + ", " + "value");
+
+        return List.of(
+                calculator.build(),
+                getter.build(),
+                setter.build()
+        );
+    }
+
+    public record VersionCheck(int from, int to, byte offset) {}
+
+}
diff --git a/code-gen/src/main/resources/EntityMeta.json b/code-gen/src/main/resources/EntityMeta.json
new file mode 100644
index 0000000..a74d07b
--- /dev/null
+++ b/code-gen/src/main/resources/EntityMeta.json
@@ -0,0 +1,15 @@
+{
+  "class-id": "me.tofaa.entitylib.codegen:User",
+  "methods": [
+
+    {
+      "name": "getUsername",
+      "return-type": "java.lang.String",
+      "parameters": [
+
+      ]
+    }
+
+
+  ]
+}
\ No newline at end of file
diff --git a/common/src/main/java/me/tofaa/entitylib/common/AbstractEntityLibAPI.java b/common/src/main/java/me/tofaa/entitylib/common/AbstractEntityLibAPI.java
index 65e375b..2433496 100644
--- a/common/src/main/java/me/tofaa/entitylib/common/AbstractEntityLibAPI.java
+++ b/common/src/main/java/me/tofaa/entitylib/common/AbstractEntityLibAPI.java
@@ -1,7 +1,9 @@
 package me.tofaa.entitylib.common;
 
+import com.github.retrooper.packetevents.PacketEvents;
 import com.github.retrooper.packetevents.PacketEventsAPI;
 import me.tofaa.entitylib.APIConfig;
+import me.tofaa.entitylib.EntityLib;
 import me.tofaa.entitylib.EntityLibAPI;
 import me.tofaa.entitylib.Platform;
 import me.tofaa.entitylib.tick.TickContainer;
diff --git a/common/src/main/java/me/tofaa/entitylib/common/AbstractWorldWrapper.java b/common/src/main/java/me/tofaa/entitylib/common/AbstractWorldWrapper.java
index b8515e3..f203954 100644
--- a/common/src/main/java/me/tofaa/entitylib/common/AbstractWorldWrapper.java
+++ b/common/src/main/java/me/tofaa/entitylib/common/AbstractWorldWrapper.java
@@ -43,6 +43,13 @@ public abstract class AbstractWorldWrapper<W> implements WorldWrapper<W> {
         return entity;
     }
 
+    @Override
+    public void removeEntity(WrapperEntity entity) {
+        entity.despawn();
+        this.entities.remove(entity.getUuid());
+        this.entitiesById.remove(entity.getEntityId());
+    }
+
     @Override
     public <T extends WrapperEntity> @NotNull T spawnEntity(Class<T> wrapperClass, @NotNull EntityType entityType, @NotNull Location location) {
         UUID uuid = EntityLib.getPlatform().getEntityUuidProvider().provide(entityType);
diff --git a/settings.gradle b/settings.gradle
index 43b0bdd..6b9d5fb 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -4,4 +4,5 @@ include 'api'
 include 'platforms:spigot'
 findProject(':platforms:spigot')?.name = 'spigot'
 include 'common'
+include 'code-gen'
 
diff --git a/src/main/java/me/tofaa/entitylib/EntityLib.java b/src/main/java/me/tofaa/entitylib/EntityLib.java
index f536679..b04d0a0 100644
--- a/src/main/java/me/tofaa/entitylib/EntityLib.java
+++ b/src/main/java/me/tofaa/entitylib/EntityLib.java
@@ -281,7 +281,7 @@ public final class EntityLib {
 
     /**
      * Sets the entity id provider to the given one.
-     * @param entityIdProvider the entity id provider. The default implementation can be found at {@link EntityIdProvider#simple()}
+     * @param entityIdProvider the entity id provider. The default implementation can be found at {@link me.tofaa.entitylib.entity.EntityIdProvider#simple()}
      */
     public static void setEntityIdProvider(EntityIdProvider entityIdProvider) {
         EntityLib.entityIdProvider = entityIdProvider;
diff --git a/test-plugin/src/main/java/me/tofaa/testentitylib/TestEntityLibPlugin.java b/test-plugin/src/main/java/me/tofaa/testentitylib/TestEntityLibPlugin.java
index 4b1e4eb..054a5b5 100644
--- a/test-plugin/src/main/java/me/tofaa/testentitylib/TestEntityLibPlugin.java
+++ b/test-plugin/src/main/java/me/tofaa/testentitylib/TestEntityLibPlugin.java
@@ -1,12 +1,29 @@
 package me.tofaa.testentitylib;
 
 import com.github.retrooper.packetevents.PacketEvents;
+import com.github.retrooper.packetevents.protocol.entity.type.EntityType;
+import com.github.retrooper.packetevents.protocol.entity.type.EntityTypes;
+import io.github.retrooper.packetevents.util.SpigotConversionUtil;
 import me.tofaa.entitylib.APIConfig;
 import me.tofaa.entitylib.EntityLib;
+import me.tofaa.entitylib.EntityLibAPI;
+import me.tofaa.entitylib.WorldWrapper;
 import me.tofaa.entitylib.spigot.SpigotEntityLibPlatform;
+import me.tofaa.entitylib.wrapper.WrapperEntity;
+import org.bukkit.World;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.Listener;
+import org.bukkit.event.player.PlayerToggleSneakEvent;
 import org.bukkit.plugin.java.JavaPlugin;
+import org.bukkit.scheduler.BukkitTask;
 
-public class TestEntityLibPlugin extends JavaPlugin {
+public class TestEntityLibPlugin extends JavaPlugin implements Listener {
+
+
+    private EntityLibAPI<World, BukkitTask> api;
+    private WrapperEntity e;
+    private WorldWrapper<World> world;
 
 
     @Override
@@ -19,5 +36,20 @@ public class TestEntityLibPlugin extends JavaPlugin {
                 .usePlatformLogger();
 
         EntityLib.init(platform, settings);
+        api = EntityLib.getApi();
+        getServer().getPluginManager().registerEvents(this, this);
     }
+
+    @EventHandler
+    public void onCrouch(PlayerToggleSneakEvent event) {
+        Player player = event.getPlayer();
+        if (e != null) {
+            e.remove();
+            e = null;
+        }
+        world = api.wrapWorld(player.getWorld());
+        e = world.spawnEntity(EntityTypes.CHICKEN, SpigotConversionUtil.fromBukkitLocation(player.getLocation()));
+
+    }
+
 }

From d6c695a3539de00329246aab51c6168d3654eb2f Mon Sep 17 00:00:00 2001
From: Tofaa <82680183+Tofaa2@users.noreply.github.com>
Date: Thu, 1 Feb 2024 14:55:05 +0400
Subject: [PATCH 07/19] some fixes

---
 .idea/workspace.xml                           | 81 +++++++----------
 .../me/tofaa/entitylib/EntityIdProvider.java  |  2 +-
 .../entitylib/wrapper/WrapperEntity.java      | 10 +-
 code-gen/build.gradle                         |  9 ++
 .../java/me/tofaa/entitylib/codegen/Main.java | 91 ++++---------------
 .../me/tofaa/entitylib/codegen/MetaClass.java |  4 +
 .../tofaa/entitylib/codegen/MetaMethod.java   | 30 +++---
 .../entitylib/codegen/MetadataClass.java      | 86 ++++++++++++++++++
 .../tofaa/entitylib/codegen/VersionCheck.java |  4 +
 9 files changed, 178 insertions(+), 139 deletions(-)
 create mode 100644 code-gen/src/main/java/me/tofaa/entitylib/codegen/MetadataClass.java
 create mode 100644 code-gen/src/main/java/me/tofaa/entitylib/codegen/VersionCheck.java

diff --git a/.idea/workspace.xml b/.idea/workspace.xml
index a04b889..13d1c14 100644
--- a/.idea/workspace.xml
+++ b/.idea/workspace.xml
@@ -5,25 +5,14 @@
   </component>
   <component name="ChangeListManager">
     <list default="true" id="9d5d9b6f-43c8-41a4-bb42-a66ffc96c9b0" name="Changes" comment="">
-      <change afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/wrapper/hologram/Hologram.java" afterDir="false" />
-      <change afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/wrapper/hologram/LegacyHologram.java" afterDir="false" />
-      <change afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/wrapper/hologram/ModernHologram.java" afterDir="false" />
-      <change afterPath="$PROJECT_DIR$/code-gen/src/main/java/me/tofaa/entitylib/codegen/Main.java" afterDir="false" />
-      <change afterPath="$PROJECT_DIR$/code-gen/src/main/java/me/tofaa/entitylib/codegen/MetaClass.java" afterDir="false" />
-      <change afterPath="$PROJECT_DIR$/code-gen/src/main/java/me/tofaa/entitylib/codegen/MetaMethod.java" afterDir="false" />
-      <change afterPath="$PROJECT_DIR$/code-gen/src/main/resources/EntityMeta.json" afterDir="false" />
-      <change beforePath="$PROJECT_DIR$/.idea/gradle.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/gradle.xml" afterDir="false" />
+      <change afterPath="$PROJECT_DIR$/code-gen/src/main/java/me/tofaa/entitylib/codegen/MetadataClass.java" afterDir="false" />
+      <change afterPath="$PROJECT_DIR$/code-gen/src/main/java/me/tofaa/entitylib/codegen/VersionCheck.java" afterDir="false" />
       <change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
-      <change beforePath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/EntityLib.java" beforeDir="false" afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/EntityLib.java" afterDir="false" />
-      <change beforePath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/WorldWrapper.java" beforeDir="false" afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/WorldWrapper.java" afterDir="false" />
-      <change beforePath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/meta/Metadata.java" beforeDir="false" afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/meta/Metadata.java" afterDir="false" />
       <change beforePath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperEntity.java" beforeDir="false" afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperEntity.java" afterDir="false" />
-      <change beforePath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/wrapper/ai/goals/RandomHeadMovementGoal.java" beforeDir="false" afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/wrapper/ai/goals/RandomHeadMovementGoal.java" afterDir="false" />
-      <change beforePath="$PROJECT_DIR$/common/src/main/java/me/tofaa/entitylib/common/AbstractEntityLibAPI.java" beforeDir="false" afterPath="$PROJECT_DIR$/common/src/main/java/me/tofaa/entitylib/common/AbstractEntityLibAPI.java" afterDir="false" />
-      <change beforePath="$PROJECT_DIR$/common/src/main/java/me/tofaa/entitylib/common/AbstractWorldWrapper.java" beforeDir="false" afterPath="$PROJECT_DIR$/common/src/main/java/me/tofaa/entitylib/common/AbstractWorldWrapper.java" afterDir="false" />
-      <change beforePath="$PROJECT_DIR$/settings.gradle" beforeDir="false" afterPath="$PROJECT_DIR$/settings.gradle" afterDir="false" />
-      <change beforePath="$PROJECT_DIR$/src/main/java/me/tofaa/entitylib/EntityLib.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/me/tofaa/entitylib/EntityLib.java" afterDir="false" />
-      <change beforePath="$PROJECT_DIR$/test-plugin/src/main/java/me/tofaa/testentitylib/TestEntityLibPlugin.java" beforeDir="false" afterPath="$PROJECT_DIR$/test-plugin/src/main/java/me/tofaa/testentitylib/TestEntityLibPlugin.java" afterDir="false" />
+      <change beforePath="$PROJECT_DIR$/code-gen/build.gradle" beforeDir="false" afterPath="$PROJECT_DIR$/code-gen/build.gradle" afterDir="false" />
+      <change beforePath="$PROJECT_DIR$/code-gen/src/main/java/me/tofaa/entitylib/codegen/Main.java" beforeDir="false" afterPath="$PROJECT_DIR$/code-gen/src/main/java/me/tofaa/entitylib/codegen/Main.java" afterDir="false" />
+      <change beforePath="$PROJECT_DIR$/code-gen/src/main/java/me/tofaa/entitylib/codegen/MetaClass.java" beforeDir="false" afterPath="$PROJECT_DIR$/code-gen/src/main/java/me/tofaa/entitylib/codegen/MetaClass.java" afterDir="false" />
+      <change beforePath="$PROJECT_DIR$/code-gen/src/main/java/me/tofaa/entitylib/codegen/MetaMethod.java" beforeDir="false" afterPath="$PROJECT_DIR$/code-gen/src/main/java/me/tofaa/entitylib/codegen/MetaMethod.java" afterDir="false" />
     </list>
     <option name="SHOW_DIALOG" value="false" />
     <option name="HIGHLIGHT_CONFLICTS" value="true" />
@@ -86,36 +75,36 @@
     <option name="showExcludedFiles" value="false" />
     <option name="showLibraryContents" value="true" />
   </component>
-  <component name="PropertiesComponent"><![CDATA[{
-  "keyToString": {
-    "Downloaded.Files.Path.Enabled": "false",
-    "Gradle.Build EntityLib.executor": "Run",
-    "Gradle.EntityLib [dependencies].executor": "Run",
-    "Gradle.EntityLib:code-gen [:code-gen:Main.main()].executor": "Run",
-    "Gradle.EntityLib:test-plugin [runServer].executor": "Run",
-    "Repository.Attach.Annotations": "false",
-    "Repository.Attach.JavaDocs": "false",
-    "Repository.Attach.Sources": "false",
-    "RunOnceActivity.OpenProjectViewOnStart": "true",
-    "RunOnceActivity.ShowReadmeOnStart": "true",
-    "WebServerToolWindowFactoryState": "false",
-    "git-widget-placeholder": "feat/platform-api",
-    "ignore.virus.scanning.warn.message": "true",
-    "jdk.selected.JAVA_MODULE": "corretto-17",
-    "kotlin-language-version-configured": "true",
-    "last_opened_file_path": "D:/Github/EntityLib/api/src/main/java/me/tofaa/entitylib/meta",
-    "node.js.detected.package.eslint": "true",
-    "node.js.detected.package.tslint": "true",
-    "node.js.selected.package.eslint": "(autodetect)",
-    "node.js.selected.package.tslint": "(autodetect)",
-    "nodejs_package_manager_path": "npm",
-    "project.structure.last.edited": "Project",
-    "project.structure.proportion": "0.15",
-    "project.structure.side.proportion": "0.2",
-    "settings.editor.selected.configurable": "preferences.pluginManager",
-    "vue.rearranger.settings.migration": "true"
+  <component name="PropertiesComponent">{
+  &quot;keyToString&quot;: {
+    &quot;Downloaded.Files.Path.Enabled&quot;: &quot;false&quot;,
+    &quot;Gradle.Build EntityLib.executor&quot;: &quot;Run&quot;,
+    &quot;Gradle.EntityLib [dependencies].executor&quot;: &quot;Run&quot;,
+    &quot;Gradle.EntityLib:code-gen [:code-gen:Main.main()].executor&quot;: &quot;Run&quot;,
+    &quot;Gradle.EntityLib:test-plugin [runServer].executor&quot;: &quot;Run&quot;,
+    &quot;Repository.Attach.Annotations&quot;: &quot;false&quot;,
+    &quot;Repository.Attach.JavaDocs&quot;: &quot;false&quot;,
+    &quot;Repository.Attach.Sources&quot;: &quot;false&quot;,
+    &quot;RunOnceActivity.OpenProjectViewOnStart&quot;: &quot;true&quot;,
+    &quot;RunOnceActivity.ShowReadmeOnStart&quot;: &quot;true&quot;,
+    &quot;WebServerToolWindowFactoryState&quot;: &quot;false&quot;,
+    &quot;git-widget-placeholder&quot;: &quot;feat/platform-api&quot;,
+    &quot;ignore.virus.scanning.warn.message&quot;: &quot;true&quot;,
+    &quot;jdk.selected.JAVA_MODULE&quot;: &quot;corretto-17&quot;,
+    &quot;kotlin-language-version-configured&quot;: &quot;true&quot;,
+    &quot;last_opened_file_path&quot;: &quot;D:/Github/EntityLib/api/src/main/java/me/tofaa/entitylib/meta&quot;,
+    &quot;node.js.detected.package.eslint&quot;: &quot;true&quot;,
+    &quot;node.js.detected.package.tslint&quot;: &quot;true&quot;,
+    &quot;node.js.selected.package.eslint&quot;: &quot;(autodetect)&quot;,
+    &quot;node.js.selected.package.tslint&quot;: &quot;(autodetect)&quot;,
+    &quot;nodejs_package_manager_path&quot;: &quot;npm&quot;,
+    &quot;project.structure.last.edited&quot;: &quot;Project&quot;,
+    &quot;project.structure.proportion&quot;: &quot;0.15&quot;,
+    &quot;project.structure.side.proportion&quot;: &quot;0.2&quot;,
+    &quot;settings.editor.selected.configurable&quot;: &quot;preferences.pluginManager&quot;,
+    &quot;vue.rearranger.settings.migration&quot;: &quot;true&quot;
   }
-}]]></component>
+}</component>
   <component name="RecentsManager">
     <key name="CopyFile.RECENT_KEYS">
       <recent name="D:\Github\EntityLib\api\src\main\java\me\tofaa\entitylib\meta" />
diff --git a/api/src/main/java/me/tofaa/entitylib/EntityIdProvider.java b/api/src/main/java/me/tofaa/entitylib/EntityIdProvider.java
index b2f3a83..2dc3a17 100644
--- a/api/src/main/java/me/tofaa/entitylib/EntityIdProvider.java
+++ b/api/src/main/java/me/tofaa/entitylib/EntityIdProvider.java
@@ -12,7 +12,7 @@ public interface EntityIdProvider {
 
     class DefaultEntityIdProvider implements EntityIdProvider {
 
-        private final AtomicInteger integer = new AtomicInteger();
+        private final AtomicInteger integer = new AtomicInteger(100000);
 
         @Override
         public int provide(@NotNull UUID entityUUID, @NotNull EntityType entityType) {
diff --git a/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperEntity.java b/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperEntity.java
index 407059b..3790363 100644
--- a/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperEntity.java
+++ b/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperEntity.java
@@ -117,11 +117,14 @@ public class WrapperEntity implements Tickable {
         teleport(world, location, onGround);
     }
 
-    public boolean addViewer(UUID uuid) {
+    /**
+     * Adds a viewer to the viewers set. The viewer will receive all packets and be informed of this addition
+     * @param uuid the uuid of the user to add
+     */
+    public void addViewer(UUID uuid) {
         if (!viewers.add(uuid)) {
-            return false;
+            return;
         }
-        if (!spawned) return false;
         WrapperPlayServerSpawnEntity packet = new WrapperPlayServerSpawnEntity(
                 entityId,
                 Optional.of(this.uuid),
@@ -135,7 +138,6 @@ public class WrapperEntity implements Tickable {
         );
         sendPacket(uuid, packet);
         sendPacket(uuid, entityMeta.createPacket());
-        return true;
     }
 
     public void addViewer(User user) {
diff --git a/code-gen/build.gradle b/code-gen/build.gradle
index e6439d3..f3f728c 100644
--- a/code-gen/build.gradle
+++ b/code-gen/build.gradle
@@ -12,6 +12,15 @@ repositories {
     mavenCentral()
 }
 
+// adding autogenerated sources to the main source set
+sourceSets {
+    main {
+        java {
+            srcDirs += 'autogenerated'
+        }
+    }
+}
+
 dependencies {
     implementation 'com.google.code.gson:gson:2.10.1'
     implementation 'com.squareup:javapoet:1.13.0'
diff --git a/code-gen/src/main/java/me/tofaa/entitylib/codegen/Main.java b/code-gen/src/main/java/me/tofaa/entitylib/codegen/Main.java
index 4cbb5bb..4a912e7 100644
--- a/code-gen/src/main/java/me/tofaa/entitylib/codegen/Main.java
+++ b/code-gen/src/main/java/me/tofaa/entitylib/codegen/Main.java
@@ -1,106 +1,53 @@
 package me.tofaa.entitylib.codegen;
 
-import com.github.retrooper.packetevents.protocol.entity.data.EntityData;
-import com.github.retrooper.packetevents.protocol.entity.data.EntityDataType;
-import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerEntityMetadata;
-import com.google.gson.reflect.TypeToken;
-import com.squareup.javapoet.*;
-import org.jetbrains.annotations.NotNull;
+import com.squareup.javapoet.ClassName;
+import com.squareup.javapoet.JavaFile;
+import com.squareup.javapoet.TypeSpec;
 
 import javax.lang.model.element.Modifier;
 import java.io.File;
-import java.io.FileWriter;
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.List;
-import java.util.Map;
+
+import static me.tofaa.entitylib.codegen.MetadataClass.createMetadataClass;
 
 public final class Main {
 
     private Main() {}
+    static final File OUT = new File("./code-gen/autogenerated/");
+    static {
+        if (!OUT.exists()) {
+            OUT.mkdirs();
+        }
+        if (!OUT.isDirectory()) {
+            OUT.delete();
+            OUT.mkdirs();
+        }
+    }
 
     public static void main(String[] args) throws IOException {
         createMetadataClass();
         List<MetaClass> metaClasses = new ArrayList<>();
 
         // test
+        MetaMethod method = new MetaMethod("username", String.class, "\"\"", "EntityDataType.STRING", List.of(new VersionCheck(47, 47, (byte) 0)));
+        MetaClass obj = new MetaClass("me.tofaa.entitylib.meta:EntityMeta", null, List.of(method));
 
-
+        writeClass(obj);
     }
 
     private static void writeClass(MetaClass metaClass) {
-        File file = new File("src/main/java");
         TypeSpec typeSpec = metaClass.create();
         JavaFile javaFile = JavaFile.builder("me.tofaa.entitylib.meta", typeSpec).build();
         try {
-            FileWriter fileWriter = new FileWriter(file);
-            javaFile.writeTo(fileWriter);
+            javaFile.writeToPath(OUT.toPath());
         }
         catch (IOException e)  {
             throw new RuntimeException(e);
         }
     }
 
-    private static void createMetadataClass() {
-
-        TypeSpec.Builder builder = builder("me.tofaa.entitylib.meta", "Metadata");
-        builder.addField(int.class, "entityId", Modifier.PRIVATE, Modifier.FINAL);
-        builder.addField(TypeToken.getParameterized(Map.class, Byte.class, EntityDataType.class).getType(), "metadataMap", Modifier.PRIVATE, Modifier.FINAL);
-
-        MethodSpec.Builder constructor = MethodSpec.constructorBuilder()
-                .addModifiers(Modifier.PUBLIC)
-                .addCode("this.entityId = entityId;\n")
-                .addCode("this.metadataMap = new ConcurrentHashMap<>();\n")
-                .addParameter(int.class, "entityId");
-
-        MethodSpec.Builder getIndex = MethodSpec.methodBuilder("getIndex")
-                .addModifiers(Modifier.PUBLIC)
-                .addTypeVariable(TypeVariableName.get("T"))
-                .addParameter(byte.class, "index")
-                .addParameter(TypeVariableName.get("T"), "defaultValue")
-                .returns(TypeVariableName.get("T"))
-                .addCode("EntityData entityData = metadataMap.get(index);\n")
-                .addCode("if (entityData == null) return defaultValue;\n")
-                .addCode("if (entityData.getValue() == null) return defaultValue;\n")
-                .addCode("return (T) entityData.getValue();\n");
-
-        MethodSpec.Builder setIndex = MethodSpec.methodBuilder("setIndex")
-                .addModifiers(Modifier.PUBLIC)
-                .addTypeVariable(TypeVariableName.get("T"))
-                .addParameter(byte.class, "index")
-                .addParameter(EntityDataType.class, "dataType")
-                .addParameter(TypeVariableName.get("T"), "value")
-                .addCode("EntityData data = new EntityData(index, dataType, value);\n")
-                .addCode("this.metadataMap.put(index, data);\n");
-
-        MethodSpec.Builder getEntries = MethodSpec.methodBuilder("getEntries")
-                .addModifiers(Modifier.PUBLIC)
-                .returns(TypeToken.getParameterized(List.class, EntityData.class).getType())
-                .addCode("return new ArrayList<>(metadataMap.values());\n")
-                .addAnnotation(NotNull.class);
-
-        MethodSpec.Builder createPacket = MethodSpec.methodBuilder("createPacket")
-                .addModifiers(Modifier.PUBLIC)
-                .returns(WrapperPlayServerEntityMetadata.class)
-                .addCode("return new WrapperPlayServerEntityMetadata(entityId, getEntries());\n")
-                .addAnnotation(NotNull.class);
-
-        builder.addMethod(constructor.build());
-        builder.addMethod(getIndex.build());
-        builder.addMethod(setIndex.build());
-        builder.addMethod(getEntries.build());
-        builder.addMethod(createPacket.build());
-
-        File file = new File("src/main/java");
-        JavaFile javaFile = JavaFile.builder("me.tofaa.entitylib.meta", builder.build()).build();
-        try {
-            FileWriter fileWriter = new FileWriter(file);
-            javaFile.writeTo(fileWriter);
-        }
-        catch (IOException e)  {
-            throw new RuntimeException(e);
-        }
-    }
 
     // Include comment in generated code
     public static TypeSpec.Builder builder(String packageName, String className) {
diff --git a/code-gen/src/main/java/me/tofaa/entitylib/codegen/MetaClass.java b/code-gen/src/main/java/me/tofaa/entitylib/codegen/MetaClass.java
index 0f84713..1755889 100644
--- a/code-gen/src/main/java/me/tofaa/entitylib/codegen/MetaClass.java
+++ b/code-gen/src/main/java/me/tofaa/entitylib/codegen/MetaClass.java
@@ -23,6 +23,10 @@ public record MetaClass(
         if (extendsClass != null) {
             String[] extendsSplit = extendsClass.split(":");
             builder.superclass(ClassName.get(extendsSplit[0], extendsSplit[1]));
+
+            builder.addField(int.class, "entityId");
+            builder.addField(ClassName.get("me.tofaa.entitylib.meta", "Metadata"), "metadata");
+
         }
         for (MetaMethod method : methods) {
             builder.addMethods(method.create());
diff --git a/code-gen/src/main/java/me/tofaa/entitylib/codegen/MetaMethod.java b/code-gen/src/main/java/me/tofaa/entitylib/codegen/MetaMethod.java
index 90ecc37..cd82db7 100644
--- a/code-gen/src/main/java/me/tofaa/entitylib/codegen/MetaMethod.java
+++ b/code-gen/src/main/java/me/tofaa/entitylib/codegen/MetaMethod.java
@@ -1,32 +1,28 @@
 package me.tofaa.entitylib.codegen;
 
-import com.squareup.javapoet.ClassName;
 import com.squareup.javapoet.MethodSpec;
+import com.squareup.javapoet.TypeName;
 
 import javax.lang.model.element.Modifier;
+import java.lang.reflect.Type;
 import java.util.List;
 
 public record MetaMethod(
         String name,
-        String returnType,
+        Type returnType,
         String defaultReturn,
         String dataType,
         List<VersionCheck> versionChecks
 ) {
 
     public List<MethodSpec> create() {
-        String[] nameSplit = name.split(":");
-        String[] returnSplit = returnType.split(":");
-        String namePackage = nameSplit[0];
-        String nameClass = nameSplit[1];
-        String returnPackage = returnSplit[0];
-        String returnClass = returnSplit[1];
 
-        String methodBasedName = nameClass.substring(0, 1).toUpperCase() + nameClass.substring(1);
+        String methodBasedName = name.substring(0, 1).toUpperCase() + name.substring(1);
 
         /* offset calculator first */
         MethodSpec.Builder calculator = MethodSpec.methodBuilder(
                 "calculate" + methodBasedName + "Offset")
+                .returns(byte.class)
                 .addModifiers(Modifier.PRIVATE, Modifier.STATIC)
                 .addParameter(int.class, "version");
         for (VersionCheck check : versionChecks) {
@@ -40,18 +36,22 @@ public record MetaMethod(
         String versionVariable = "byte offset = calculate" + methodBasedName + "Offset(EntityLib.getApi().getPacketEvents().getServerManager().getVersion().getProtocolVersion())";
 
         /* getter method spec. No params */
-        MethodSpec.Builder getter = MethodSpec.methodBuilder("get" + methodBasedName)
+        String getterName = "get";
+        if (returnType == TypeName.BOOLEAN) {
+            getterName = "is";
+        }
+        MethodSpec.Builder getter = MethodSpec.methodBuilder(getterName + methodBasedName)
                 .addModifiers(Modifier.PUBLIC)
-                .returns(ClassName.get(returnPackage, returnClass))
+                .returns(returnType)
                 .addStatement(versionVariable)
-                .addStatement("return metadata.getIndex(" + "offset," + defaultReturn);
+                .addStatement("return metadata.getIndex(" + "offset," + defaultReturn + ");");
 
         MethodSpec.Builder setter = MethodSpec.methodBuilder("set" + methodBasedName)
                 .addModifiers(Modifier.PUBLIC)
                 .returns(void.class)
-                .addParameter(ClassName.get(returnPackage, returnClass), "value")
+                .addParameter(returnType, "value")
                 .addStatement(versionVariable)
-                .addStatement("metadata.setIndex(" + "offset, " + dataType + ", " + "value");
+                .addStatement("metadata.setIndex(" + "offset, " + dataType + ", " + "value" + ");");
 
         return List.of(
                 calculator.build(),
@@ -60,6 +60,4 @@ public record MetaMethod(
         );
     }
 
-    public record VersionCheck(int from, int to, byte offset) {}
-
 }
diff --git a/code-gen/src/main/java/me/tofaa/entitylib/codegen/MetadataClass.java b/code-gen/src/main/java/me/tofaa/entitylib/codegen/MetadataClass.java
new file mode 100644
index 0000000..ad99b37
--- /dev/null
+++ b/code-gen/src/main/java/me/tofaa/entitylib/codegen/MetadataClass.java
@@ -0,0 +1,86 @@
+package me.tofaa.entitylib.codegen;
+
+import com.github.retrooper.packetevents.protocol.entity.data.EntityData;
+import com.github.retrooper.packetevents.protocol.entity.data.EntityDataType;
+import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerEntityMetadata;
+import com.google.gson.reflect.TypeToken;
+import com.squareup.javapoet.JavaFile;
+import com.squareup.javapoet.MethodSpec;
+import com.squareup.javapoet.TypeSpec;
+import com.squareup.javapoet.TypeVariableName;
+import org.jetbrains.annotations.NotNull;
+
+import javax.lang.model.element.Modifier;
+import java.io.IOException;
+import java.util.List;
+import java.util.Map;
+
+import static me.tofaa.entitylib.codegen.Main.OUT;
+import static me.tofaa.entitylib.codegen.Main.builder;
+
+public final class MetadataClass {
+
+    private MetadataClass() {
+
+    }
+    public static void createMetadataClass() {
+
+        TypeSpec.Builder builder = builder("me.tofaa.entitylib.meta", "Metadata");
+        builder.addField(int.class, "entityId", Modifier.PRIVATE, Modifier.FINAL);
+        builder.addField(TypeToken.getParameterized(Map.class, Byte.class, EntityData.class).getType(), "metadataMap", Modifier.PRIVATE, Modifier.FINAL);
+        MethodSpec.Builder constructor = MethodSpec.constructorBuilder()
+                .addModifiers(Modifier.PUBLIC)
+                .addCode("this.entityId = entityId;\n")
+                .addCode("this.metadataMap = new java.util.concurrent.ConcurrentHashMap<>();\n")
+                .addParameter(int.class, "entityId");
+
+        MethodSpec.Builder getIndex = MethodSpec.methodBuilder("getIndex")
+                .addModifiers(Modifier.PUBLIC)
+                .addTypeVariable(TypeVariableName.get("T"))
+                .addParameter(byte.class, "index")
+                .addParameter(TypeVariableName.get("T"), "defaultValue")
+                .returns(TypeVariableName.get("T"))
+                .addCode("EntityData entityData = metadataMap.get(index);\n")
+                .addCode("if (entityData == null) return defaultValue;\n")
+                .addCode("if (entityData.getValue() == null) return defaultValue;\n")
+                .addCode("return (T) entityData.getValue();\n");
+
+        MethodSpec.Builder setIndex = MethodSpec.methodBuilder("setIndex")
+                .addModifiers(Modifier.PUBLIC)
+                .addTypeVariable(TypeVariableName.get("T"))
+                .addParameter(byte.class, "index")
+                .addParameter(EntityDataType.class, "dataType")
+                .addParameter(TypeVariableName.get("T"), "value")
+                .addCode("EntityData data = new EntityData(index, dataType, value);\n")
+                .addCode("this.metadataMap.put(index, data);\n");
+
+        MethodSpec.Builder getEntries = MethodSpec.methodBuilder("getEntries")
+                .addModifiers(Modifier.PUBLIC)
+                .returns(TypeToken.getParameterized(List.class, EntityData.class).getType())
+                .addCode("return new java.util.ArrayList<>(metadataMap.values());\n")
+                .addAnnotation(NotNull.class);
+
+        MethodSpec.Builder createPacket = MethodSpec.methodBuilder("createPacket")
+                .addModifiers(Modifier.PUBLIC)
+                .returns(WrapperPlayServerEntityMetadata.class)
+                .addCode("return new WrapperPlayServerEntityMetadata(entityId, getEntries());\n")
+                .addAnnotation(NotNull.class);
+
+        builder.addMethod(constructor.build());
+        builder.addMethod(getIndex.build());
+        builder.addMethod(setIndex.build());
+        builder.addMethod(getEntries.build());
+        builder.addMethod(createPacket.build());
+
+        JavaFile javaFile = JavaFile.builder("me.tofaa.entitylib.meta", builder.build()).build();
+        try {
+            javaFile.writeToPath(OUT.toPath());
+        }
+        catch (IOException e)  {
+            throw new RuntimeException(e);
+        }
+    }
+
+
+
+}
diff --git a/code-gen/src/main/java/me/tofaa/entitylib/codegen/VersionCheck.java b/code-gen/src/main/java/me/tofaa/entitylib/codegen/VersionCheck.java
new file mode 100644
index 0000000..1120db8
--- /dev/null
+++ b/code-gen/src/main/java/me/tofaa/entitylib/codegen/VersionCheck.java
@@ -0,0 +1,4 @@
+package me.tofaa.entitylib.codegen;
+
+public record VersionCheck(int from, int to, byte offset) {
+}

From 6c56f28a7c139b590adb30b5f59cd4e786ba8c4c Mon Sep 17 00:00:00 2001
From: Tofaa <82680183+Tofaa2@users.noreply.github.com>
Date: Fri, 2 Feb 2024 00:59:32 +0400
Subject: [PATCH 08/19] commit code generation steps

---
 .idea/workspace.xml                           |  16 +-
 .../tofaa/entitylib/EntityUuidProvider.java   |   1 +
 .../entitylib/meta/CompatibilityIndex.java    |   9 -
 .../me/tofaa/entitylib/meta/EntityMeta.java   |  48 +--
 .../entitylib/meta/MetaOffsetConverter.java   | 259 +++++++++++++
 code-gen/build.gradle                         |   9 -
 .../java/me/tofaa/entitylib/codegen/Main.java |  78 ++--
 .../me/tofaa/entitylib/codegen/MetaClass.java |  38 --
 .../tofaa/entitylib/codegen/MetaMethod.java   |  63 ----
 .../tofaa/entitylib/codegen/MetaOffset.java   |   4 +
 .../entitylib/codegen/MetadataClass.java      |  86 -----
 .../tofaa/entitylib/codegen/TypeHolder.java   |   4 +
 code-gen/src/main/resources/EntityMeta.json   |  15 -
 .../src/main/resources/offset-calculator.json | 347 ++++++++++++++++++
 .../testentitylib/TestEntityLibPlugin.java    |   6 +-
 15 files changed, 701 insertions(+), 282 deletions(-)
 delete mode 100644 api/src/main/java/me/tofaa/entitylib/meta/CompatibilityIndex.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/MetaOffsetConverter.java
 delete mode 100644 code-gen/src/main/java/me/tofaa/entitylib/codegen/MetaClass.java
 delete mode 100644 code-gen/src/main/java/me/tofaa/entitylib/codegen/MetaMethod.java
 create mode 100644 code-gen/src/main/java/me/tofaa/entitylib/codegen/MetaOffset.java
 delete mode 100644 code-gen/src/main/java/me/tofaa/entitylib/codegen/MetadataClass.java
 create mode 100644 code-gen/src/main/java/me/tofaa/entitylib/codegen/TypeHolder.java
 delete mode 100644 code-gen/src/main/resources/EntityMeta.json
 create mode 100644 code-gen/src/main/resources/offset-calculator.json

diff --git a/.idea/workspace.xml b/.idea/workspace.xml
index 13d1c14..19d8f43 100644
--- a/.idea/workspace.xml
+++ b/.idea/workspace.xml
@@ -5,14 +5,19 @@
   </component>
   <component name="ChangeListManager">
     <list default="true" id="9d5d9b6f-43c8-41a4-bb42-a66ffc96c9b0" name="Changes" comment="">
-      <change afterPath="$PROJECT_DIR$/code-gen/src/main/java/me/tofaa/entitylib/codegen/MetadataClass.java" afterDir="false" />
-      <change afterPath="$PROJECT_DIR$/code-gen/src/main/java/me/tofaa/entitylib/codegen/VersionCheck.java" afterDir="false" />
+      <change afterPath="$PROJECT_DIR$/code-gen/src/main/java/me/tofaa/entitylib/codegen/MetaOffset.java" afterDir="false" />
+      <change afterPath="$PROJECT_DIR$/code-gen/src/main/java/me/tofaa/entitylib/codegen/TypeHolder.java" afterDir="false" />
+      <change afterPath="$PROJECT_DIR$/code-gen/src/main/resources/offset-calculator.json" afterDir="false" />
       <change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
-      <change beforePath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperEntity.java" beforeDir="false" afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperEntity.java" afterDir="false" />
+      <change beforePath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/EntityUuidProvider.java" beforeDir="false" afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/EntityUuidProvider.java" afterDir="false" />
+      <change beforePath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/meta/CompatibilityIndex.java" beforeDir="false" />
+      <change beforePath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/meta/EntityMeta.java" beforeDir="false" afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/meta/EntityMeta.java" afterDir="false" />
       <change beforePath="$PROJECT_DIR$/code-gen/build.gradle" beforeDir="false" afterPath="$PROJECT_DIR$/code-gen/build.gradle" afterDir="false" />
       <change beforePath="$PROJECT_DIR$/code-gen/src/main/java/me/tofaa/entitylib/codegen/Main.java" beforeDir="false" afterPath="$PROJECT_DIR$/code-gen/src/main/java/me/tofaa/entitylib/codegen/Main.java" afterDir="false" />
-      <change beforePath="$PROJECT_DIR$/code-gen/src/main/java/me/tofaa/entitylib/codegen/MetaClass.java" beforeDir="false" afterPath="$PROJECT_DIR$/code-gen/src/main/java/me/tofaa/entitylib/codegen/MetaClass.java" afterDir="false" />
-      <change beforePath="$PROJECT_DIR$/code-gen/src/main/java/me/tofaa/entitylib/codegen/MetaMethod.java" beforeDir="false" afterPath="$PROJECT_DIR$/code-gen/src/main/java/me/tofaa/entitylib/codegen/MetaMethod.java" afterDir="false" />
+      <change beforePath="$PROJECT_DIR$/code-gen/src/main/java/me/tofaa/entitylib/codegen/MetaClass.java" beforeDir="false" />
+      <change beforePath="$PROJECT_DIR$/code-gen/src/main/java/me/tofaa/entitylib/codegen/MetaMethod.java" beforeDir="false" />
+      <change beforePath="$PROJECT_DIR$/code-gen/src/main/java/me/tofaa/entitylib/codegen/MetadataClass.java" beforeDir="false" />
+      <change beforePath="$PROJECT_DIR$/code-gen/src/main/resources/EntityMeta.json" beforeDir="false" />
     </list>
     <option name="SHOW_DIALOG" value="false" />
     <option name="HIGHLIGHT_CONFLICTS" value="true" />
@@ -275,6 +280,7 @@
       <workItem from="1706601592145" duration="1670000" />
       <workItem from="1706614921404" duration="10508000" />
       <workItem from="1706696719616" duration="4783000" />
+      <workItem from="1706784821835" duration="5673000" />
     </task>
     <servers />
   </component>
diff --git a/api/src/main/java/me/tofaa/entitylib/EntityUuidProvider.java b/api/src/main/java/me/tofaa/entitylib/EntityUuidProvider.java
index 4937514..bbd1f85 100644
--- a/api/src/main/java/me/tofaa/entitylib/EntityUuidProvider.java
+++ b/api/src/main/java/me/tofaa/entitylib/EntityUuidProvider.java
@@ -16,6 +16,7 @@ public interface EntityUuidProvider {
         public @NotNull UUID provide(EntityType entityType) {
             return UUID.randomUUID();
         }
+
     }
 
 }
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/CompatibilityIndex.java b/api/src/main/java/me/tofaa/entitylib/meta/CompatibilityIndex.java
deleted file mode 100644
index 2683859..0000000
--- a/api/src/main/java/me/tofaa/entitylib/meta/CompatibilityIndex.java
+++ /dev/null
@@ -1,9 +0,0 @@
-package me.tofaa.entitylib.meta;
-
-import com.github.retrooper.packetevents.protocol.entity.data.EntityDataType;
-
-public interface CompatibilityIndex {
-
-    byte getOffSet(byte latestOffset, EntityDataType<?> type);
-
-}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/EntityMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/EntityMeta.java
index d00132f..5150aa5 100644
--- a/api/src/main/java/me/tofaa/entitylib/meta/EntityMeta.java
+++ b/api/src/main/java/me/tofaa/entitylib/meta/EntityMeta.java
@@ -97,30 +97,6 @@ public class EntityMeta implements EntityMetadataProvider {
         setMaskBit(OFFSET, INVISIBLE_BIT, value);
     }
 
-    public short getAirTicks() {
-        return this.metadata.getIndex((byte) 1, (short) 300);
-    }
-
-    public void setAirTicks(short value) {
-        this.metadata.setIndex((byte) 1, EntityDataTypes.SHORT, value);
-    }
-
-    public Component getCustomName() {
-        return this.metadata.getIndex(offset(OFFSET, 2), null);
-    }
-
-    public void setCustomName(Component value) {
-        this.metadata.setIndex(offset(OFFSET, 2), EntityDataTypes.ADV_COMPONENT, value);
-    }
-
-    public boolean isCustomNameVisible() {
-        return this.metadata.getIndex(offset(OFFSET, 3), false);
-    }
-
-    public void setCustomNameVisible(boolean value) {
-        this.metadata.setIndex(offset(OFFSET, 3), EntityDataTypes.BOOLEAN, value);
-    }
-
     public boolean hasGlowingEffect() {
         return getMaskBit(OFFSET, HAS_GLOWING_EFFECT_BIT);
     }
@@ -145,6 +121,30 @@ public class EntityMeta implements EntityMetadataProvider {
         setMaskBit(OFFSET, FLYING_WITH_ELYTRA_BIT, value);
     }
 
+    public short getAirTicks() {
+        return this.metadata.getIndex((byte) 1, (short) 300);
+    }
+
+    public void setAirTicks(short value) {
+        this.metadata.setIndex((byte) 1, EntityDataTypes.SHORT, value);
+    }
+
+    public Component getCustomName() {
+        return this.metadata.getIndex(offset(OFFSET, 2), null);
+    }
+
+    public void setCustomName(Component value) {
+        this.metadata.setIndex(offset(OFFSET, 2), EntityDataTypes.ADV_COMPONENT, value);
+    }
+
+    public boolean isCustomNameVisible() {
+        return this.metadata.getIndex(offset(OFFSET, 3), false);
+    }
+
+    public void setCustomNameVisible(boolean value) {
+        this.metadata.setIndex(offset(OFFSET, 3), EntityDataTypes.BOOLEAN, value);
+    }
+
     public boolean isSilent() {
         return this.metadata.getIndex((byte) 4, false);
     }
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/MetaOffsetConverter.java b/api/src/main/java/me/tofaa/entitylib/meta/MetaOffsetConverter.java
new file mode 100644
index 0000000..0848013
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/meta/MetaOffsetConverter.java
@@ -0,0 +1,259 @@
+// This class is generated by code-gen module. Do not edit manually.
+//
+package me.tofaa.entitylib.meta;
+
+import static me.tofaa.entitylib.EntityLib.getApi;
+
+import org.jetbrains.annotations.ApiStatus;
+
+@ApiStatus.Internal
+@SuppressWarnings("unused")
+public final class MetaOffsetConverter {
+    private MetaOffsetConverter() {
+    }
+
+    public static byte airTicksOffset() {
+        int protocolVersion = getApi().getPacketEvents().getServerManager().getVersion().getProtocolVersion();
+        if (protocolVersion >= 47 && protocolVersion <= 47) {
+            return 1;
+        }
+        throw new RuntimeException("Unknown protocol version for this method");
+    }
+
+    public static byte customNameOffset() {
+        int protocolVersion = getApi().getPacketEvents().getServerManager().getVersion().getProtocolVersion();
+        if (protocolVersion >= 47 && protocolVersion <= 765) {
+            return 2;
+        }
+        throw new RuntimeException("Unknown protocol version for this method");
+    }
+
+    public static byte customNameVisibleOffset() {
+        int protocolVersion = getApi().getPacketEvents().getServerManager().getVersion().getProtocolVersion();
+        if (protocolVersion >= 47 && protocolVersion <= 765) {
+            return 3;
+        }
+        throw new RuntimeException("Unknown protocol version for this method");
+    }
+
+    public static byte silentOffset() {
+        int protocolVersion = getApi().getPacketEvents().getServerManager().getVersion().getProtocolVersion();
+        if (protocolVersion >= 47 && protocolVersion <= 765) {
+            return 4;
+        }
+        throw new RuntimeException("Unknown protocol version for this method");
+    }
+
+    public static byte hasNoGravityOffset() {
+        int protocolVersion = getApi().getPacketEvents().getServerManager().getVersion().getProtocolVersion();
+        if (protocolVersion >= 47 && protocolVersion <= 765) {
+            return 5;
+        }
+        throw new RuntimeException("Unknown protocol version for this method");
+    }
+
+    public static byte poseOffset() {
+        int protocolVersion = getApi().getPacketEvents().getServerManager().getVersion().getProtocolVersion();
+        if (protocolVersion >= 47 && protocolVersion <= 765) {
+            return 6;
+        }
+        throw new RuntimeException("Unknown protocol version for this method");
+    }
+
+    public static byte ticksFrozenInPowderedSnowOffset() {
+        int protocolVersion = getApi().getPacketEvents().getServerManager().getVersion().getProtocolVersion();
+        if (protocolVersion >= 47 && protocolVersion <= 765) {
+            return 7;
+        }
+        throw new RuntimeException("Unknown protocol version for this method");
+    }
+
+    public static byte interpolationDelayOffset() {
+        int protocolVersion = getApi().getPacketEvents().getServerManager().getVersion().getProtocolVersion();
+        if (protocolVersion >= 762 && protocolVersion <= 765) {
+            return 8;
+        }
+        throw new RuntimeException("Unknown protocol version for this method");
+    }
+
+    public static byte transformationDurationOffset() {
+        int protocolVersion = getApi().getPacketEvents().getServerManager().getVersion().getProtocolVersion();
+        if (protocolVersion >= 762 && protocolVersion <= 765) {
+            return 9;
+        }
+        throw new RuntimeException("Unknown protocol version for this method");
+    }
+
+    public static byte positionRotationInterpolationDurationOffset() {
+        int protocolVersion = getApi().getPacketEvents().getServerManager().getVersion().getProtocolVersion();
+        if (protocolVersion >= 764 && protocolVersion <= 765) {
+            return 10;
+        }
+        throw new RuntimeException("Unknown protocol version for this method");
+    }
+
+    public static byte translationOffset() {
+        int protocolVersion = getApi().getPacketEvents().getServerManager().getVersion().getProtocolVersion();
+        if (protocolVersion >= 764 && protocolVersion <= 765) {
+            return 11;
+        }
+        if (protocolVersion >= 762 && protocolVersion <= 763) {
+            return 10;
+        }
+        throw new RuntimeException("Unknown protocol version for this method");
+    }
+
+    public static byte scaleOffset() {
+        int protocolVersion = getApi().getPacketEvents().getServerManager().getVersion().getProtocolVersion();
+        if (protocolVersion >= 764 && protocolVersion <= 765) {
+            return 12;
+        }
+        if (protocolVersion >= 762 && protocolVersion <= 763) {
+            return 11;
+        }
+        throw new RuntimeException("Unknown protocol version for this method");
+    }
+
+    public static byte leftRotationOffset() {
+        int protocolVersion = getApi().getPacketEvents().getServerManager().getVersion().getProtocolVersion();
+        if (protocolVersion >= 764 && protocolVersion <= 765) {
+            return 13;
+        }
+        if (protocolVersion >= 762 && protocolVersion <= 763) {
+            return 12;
+        }
+        throw new RuntimeException("Unknown protocol version for this method");
+    }
+
+    public static byte rightRotationOffset() {
+        int protocolVersion = getApi().getPacketEvents().getServerManager().getVersion().getProtocolVersion();
+        if (protocolVersion >= 764 && protocolVersion <= 765) {
+            return 14;
+        }
+        if (protocolVersion >= 762 && protocolVersion <= 763) {
+            return 13;
+        }
+        throw new RuntimeException("Unknown protocol version for this method");
+    }
+
+    public static byte billboardConstraintsOffset() {
+        int protocolVersion = getApi().getPacketEvents().getServerManager().getVersion().getProtocolVersion();
+        if (protocolVersion >= 764 && protocolVersion <= 765) {
+            return 15;
+        }
+        if (protocolVersion >= 762 && protocolVersion <= 763) {
+            return 14;
+        }
+        throw new RuntimeException("Unknown protocol version for this method");
+    }
+
+    public static byte brightnessOverrideOffset() {
+        int protocolVersion = getApi().getPacketEvents().getServerManager().getVersion().getProtocolVersion();
+        if (protocolVersion >= 764 && protocolVersion <= 765) {
+            return 16;
+        }
+        if (protocolVersion >= 762 && protocolVersion <= 763) {
+            return 15;
+        }
+        throw new RuntimeException("Unknown protocol version for this method");
+    }
+
+    public static byte viewRangeOffset() {
+        int protocolVersion = getApi().getPacketEvents().getServerManager().getVersion().getProtocolVersion();
+        if (protocolVersion >= 764 && protocolVersion <= 765) {
+            return 17;
+        }
+        if (protocolVersion >= 762 && protocolVersion <= 763) {
+            return 16;
+        }
+        throw new RuntimeException("Unknown protocol version for this method");
+    }
+
+    public static byte shadowRadiusOffset() {
+        int protocolVersion = getApi().getPacketEvents().getServerManager().getVersion().getProtocolVersion();
+        if (protocolVersion >= 764 && protocolVersion <= 765) {
+            return 18;
+        }
+        if (protocolVersion >= 762 && protocolVersion <= 763) {
+            return 17;
+        }
+        throw new RuntimeException("Unknown protocol version for this method");
+    }
+
+    public static byte shadowStrengthOffset() {
+        int protocolVersion = getApi().getPacketEvents().getServerManager().getVersion().getProtocolVersion();
+        if (protocolVersion >= 764 && protocolVersion <= 765) {
+            return 19;
+        }
+        if (protocolVersion >= 762 && protocolVersion <= 763) {
+            return 18;
+        }
+        throw new RuntimeException("Unknown protocol version for this method");
+    }
+
+    public static byte widthOffset() {
+        int protocolVersion = getApi().getPacketEvents().getServerManager().getVersion().getProtocolVersion();
+        if (protocolVersion >= 764 && protocolVersion <= 765) {
+            return 20;
+        }
+        if (protocolVersion >= 762 && protocolVersion <= 763) {
+            return 19;
+        }
+        throw new RuntimeException("Unknown protocol version for this method");
+    }
+
+    public static byte heightOffset() {
+        int protocolVersion = getApi().getPacketEvents().getServerManager().getVersion().getProtocolVersion();
+        if (protocolVersion >= 764 && protocolVersion <= 765) {
+            return 21;
+        }
+        if (protocolVersion >= 762 && protocolVersion <= 763) {
+            return 20;
+        }
+        throw new RuntimeException("Unknown protocol version for this method");
+    }
+
+    public static byte glowColorOverrideOffset() {
+        int protocolVersion = getApi().getPacketEvents().getServerManager().getVersion().getProtocolVersion();
+        if (protocolVersion >= 764 && protocolVersion <= 765) {
+            return 22;
+        }
+        if (protocolVersion >= 762 && protocolVersion <= 763) {
+            return 21;
+        }
+        throw new RuntimeException("Unknown protocol version for this method");
+    }
+
+    public static byte blockIdOffset() {
+        int protocolVersion = getApi().getPacketEvents().getServerManager().getVersion().getProtocolVersion();
+        if (protocolVersion >= 764 && protocolVersion <= 765) {
+            return 23;
+        }
+        if (protocolVersion >= 762 && protocolVersion <= 763) {
+            return 22;
+        }
+        throw new RuntimeException("Unknown protocol version for this method");
+    }
+
+    public static byte itemOffset() {
+        int protocolVersion = getApi().getPacketEvents().getServerManager().getVersion().getProtocolVersion();
+        if (protocolVersion >= 764 && protocolVersion <= 765) {
+            return 24;
+        }
+        if (protocolVersion >= 762 && protocolVersion <= 763) {
+            return 23;
+        }
+        throw new RuntimeException("Unknown protocol version for this method");
+    }
+
+    public static byte displayTypeOffset() {
+        int protocolVersion = getApi().getPacketEvents().getServerManager().getVersion().getProtocolVersion();
+        if (protocolVersion >= 764 && protocolVersion <= 765) {
+            return 25;
+        }
+        if (protocolVersion >= 762 && protocolVersion <= 763) {
+            return 24;
+        }
+        throw new RuntimeException("Unknown protocol version for this method");
+    }
+}
diff --git a/code-gen/build.gradle b/code-gen/build.gradle
index f3f728c..e6439d3 100644
--- a/code-gen/build.gradle
+++ b/code-gen/build.gradle
@@ -12,15 +12,6 @@ repositories {
     mavenCentral()
 }
 
-// adding autogenerated sources to the main source set
-sourceSets {
-    main {
-        java {
-            srcDirs += 'autogenerated'
-        }
-    }
-}
-
 dependencies {
     implementation 'com.google.code.gson:gson:2.10.1'
     implementation 'com.squareup:javapoet:1.13.0'
diff --git a/code-gen/src/main/java/me/tofaa/entitylib/codegen/Main.java b/code-gen/src/main/java/me/tofaa/entitylib/codegen/Main.java
index 4a912e7..4567f29 100644
--- a/code-gen/src/main/java/me/tofaa/entitylib/codegen/Main.java
+++ b/code-gen/src/main/java/me/tofaa/entitylib/codegen/Main.java
@@ -1,21 +1,21 @@
 package me.tofaa.entitylib.codegen;
 
-import com.squareup.javapoet.ClassName;
-import com.squareup.javapoet.JavaFile;
-import com.squareup.javapoet.TypeSpec;
+import com.google.gson.FieldNamingPolicy;
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import com.squareup.javapoet.*;
+import org.jetbrains.annotations.ApiStatus;
 
 import javax.lang.model.element.Modifier;
 import java.io.File;
 import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
-
-import static me.tofaa.entitylib.codegen.MetadataClass.createMetadataClass;
+import java.io.InputStream;
+import java.io.InputStreamReader;
 
 public final class Main {
 
     private Main() {}
-    static final File OUT = new File("./code-gen/autogenerated/");
+    private static final File OUT = new File("./api/src/main/java");
     static {
         if (!OUT.exists()) {
             OUT.mkdirs();
@@ -27,34 +27,50 @@ public final class Main {
     }
 
     public static void main(String[] args) throws IOException {
-        createMetadataClass();
-        List<MetaClass> metaClasses = new ArrayList<>();
 
-        // test
-        MetaMethod method = new MetaMethod("username", String.class, "\"\"", "EntityDataType.STRING", List.of(new VersionCheck(47, 47, (byte) 0)));
-        MetaClass obj = new MetaClass("me.tofaa.entitylib.meta:EntityMeta", null, List.of(method));
+        TypeSpec.Builder baseBuilder = TypeSpec.classBuilder(ClassName.get("me.tofaa.entitylib.meta", "MetaOffsetConverter"))
+                .addModifiers(Modifier.PUBLIC, Modifier.FINAL)
+                .addAnnotation(ApiStatus.Internal.class)
+                .addAnnotation(AnnotationSpec.builder(SuppressWarnings.class).addMember("value", "$S", "unused").build())
+                .addMethod(MethodSpec.constructorBuilder().addModifiers(Modifier.PRIVATE).build());
 
-        writeClass(obj);
-    }
-
-    private static void writeClass(MetaClass metaClass) {
-        TypeSpec typeSpec = metaClass.create();
-        JavaFile javaFile = JavaFile.builder("me.tofaa.entitylib.meta", typeSpec).build();
-        try {
-            javaFile.writeToPath(OUT.toPath());
+        Gson gson = new GsonBuilder().setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_DASHES).create();
+        InputStream stream = Main.class.getResourceAsStream("/offset-calculator.json");
+        if (stream == null) {
+            throw new RuntimeException("offset-calculator.json not found");
         }
-        catch (IOException e)  {
-            throw new RuntimeException(e);
+        InputStreamReader reader = new InputStreamReader(stream);
+        TypeHolder[] types = gson.fromJson(reader, TypeHolder[].class);
+        for (TypeHolder type : types) {
+            System.out.println("Generating type" + type.className());
+
+            for (MetaOffset offset : type.offsets()) {
+
+                MethodSpec.Builder method = MethodSpec.methodBuilder(offset.name() + "Offset")
+                        .addModifiers(Modifier.PUBLIC, Modifier.STATIC)
+                        .returns(byte.class);
+
+                String version = "int protocolVersion = getApi().getPacketEvents().getServerManager().getVersion().getProtocolVersion()";
+                method.addStatement(version);
+                for (VersionCheck check : offset.checks()) {
+                    method.beginControlFlow("if (protocolVersion >= $L && protocolVersion <= $L)", check.to(), check.from());
+                    method.addStatement("return $L", check.offset());
+                    method.endControlFlow();
+                }
+                method.addStatement("throw new RuntimeException(\"Unknown protocol version for this method\")");
+                baseBuilder.addMethod(method.build());
+            }
         }
-    }
 
-
-    // Include comment in generated code
-    public static TypeSpec.Builder builder(String packageName, String className) {
-        return TypeSpec.classBuilder(ClassName.get(packageName, className))
-                .addModifiers(Modifier.PUBLIC)
-                .addJavadoc("AUTOGENERATED CODE BY ENTITYLIB CODEGEN\n")
-                .addJavadoc("DO NOT EDIT\n");
+        TypeSpec base = baseBuilder.build();
+        System.out.println("Writing to file");
+        JavaFile file = JavaFile.builder("me.tofaa.entitylib.meta", base)
+                .addStaticImport(ClassName.get("me.tofaa.entitylib", "EntityLib"), "getApi")
+                .addFileComment("This class is generated by code-gen module. Do not edit manually.\n")
+                .indent("    ")
+                .skipJavaLangImports(true)
+                .build();
+        file.writeTo(OUT);
     }
 
 
diff --git a/code-gen/src/main/java/me/tofaa/entitylib/codegen/MetaClass.java b/code-gen/src/main/java/me/tofaa/entitylib/codegen/MetaClass.java
deleted file mode 100644
index 1755889..0000000
--- a/code-gen/src/main/java/me/tofaa/entitylib/codegen/MetaClass.java
+++ /dev/null
@@ -1,38 +0,0 @@
-package me.tofaa.entitylib.codegen;
-
-import com.squareup.javapoet.ClassName;
-import com.squareup.javapoet.TypeSpec;
-
-import java.util.List;
-
-import static me.tofaa.entitylib.codegen.Main.builder;
-
-public record MetaClass(
-        String name,
-        String extendsClass,
-        List<MetaMethod> methods
-) {
-
-
-    public TypeSpec create() {
-        String split[] = name.split(":");
-        String packageName = split[0];
-        String className = split[1];
-
-        TypeSpec.Builder builder = builder(packageName, className);
-        if (extendsClass != null) {
-            String[] extendsSplit = extendsClass.split(":");
-            builder.superclass(ClassName.get(extendsSplit[0], extendsSplit[1]));
-
-            builder.addField(int.class, "entityId");
-            builder.addField(ClassName.get("me.tofaa.entitylib.meta", "Metadata"), "metadata");
-
-        }
-        for (MetaMethod method : methods) {
-            builder.addMethods(method.create());
-        }
-        return builder.build();
-    }
-
-
-}
diff --git a/code-gen/src/main/java/me/tofaa/entitylib/codegen/MetaMethod.java b/code-gen/src/main/java/me/tofaa/entitylib/codegen/MetaMethod.java
deleted file mode 100644
index cd82db7..0000000
--- a/code-gen/src/main/java/me/tofaa/entitylib/codegen/MetaMethod.java
+++ /dev/null
@@ -1,63 +0,0 @@
-package me.tofaa.entitylib.codegen;
-
-import com.squareup.javapoet.MethodSpec;
-import com.squareup.javapoet.TypeName;
-
-import javax.lang.model.element.Modifier;
-import java.lang.reflect.Type;
-import java.util.List;
-
-public record MetaMethod(
-        String name,
-        Type returnType,
-        String defaultReturn,
-        String dataType,
-        List<VersionCheck> versionChecks
-) {
-
-    public List<MethodSpec> create() {
-
-        String methodBasedName = name.substring(0, 1).toUpperCase() + name.substring(1);
-
-        /* offset calculator first */
-        MethodSpec.Builder calculator = MethodSpec.methodBuilder(
-                "calculate" + methodBasedName + "Offset")
-                .returns(byte.class)
-                .addModifiers(Modifier.PRIVATE, Modifier.STATIC)
-                .addParameter(int.class, "version");
-        for (VersionCheck check : versionChecks) {
-            calculator.beginControlFlow("if (version >= $L && version <= $L)", check.from(), check.to());
-            calculator.addStatement("return $L", check.offset());
-            calculator.endControlFlow();
-        }
-        // throw exception if version is not in range
-        calculator.addStatement("throw new IllegalArgumentException(\"Version \" + version + \" is not in range\")");
-
-        String versionVariable = "byte offset = calculate" + methodBasedName + "Offset(EntityLib.getApi().getPacketEvents().getServerManager().getVersion().getProtocolVersion())";
-
-        /* getter method spec. No params */
-        String getterName = "get";
-        if (returnType == TypeName.BOOLEAN) {
-            getterName = "is";
-        }
-        MethodSpec.Builder getter = MethodSpec.methodBuilder(getterName + methodBasedName)
-                .addModifiers(Modifier.PUBLIC)
-                .returns(returnType)
-                .addStatement(versionVariable)
-                .addStatement("return metadata.getIndex(" + "offset," + defaultReturn + ");");
-
-        MethodSpec.Builder setter = MethodSpec.methodBuilder("set" + methodBasedName)
-                .addModifiers(Modifier.PUBLIC)
-                .returns(void.class)
-                .addParameter(returnType, "value")
-                .addStatement(versionVariable)
-                .addStatement("metadata.setIndex(" + "offset, " + dataType + ", " + "value" + ");");
-
-        return List.of(
-                calculator.build(),
-                getter.build(),
-                setter.build()
-        );
-    }
-
-}
diff --git a/code-gen/src/main/java/me/tofaa/entitylib/codegen/MetaOffset.java b/code-gen/src/main/java/me/tofaa/entitylib/codegen/MetaOffset.java
new file mode 100644
index 0000000..5cb106f
--- /dev/null
+++ b/code-gen/src/main/java/me/tofaa/entitylib/codegen/MetaOffset.java
@@ -0,0 +1,4 @@
+package me.tofaa.entitylib.codegen;
+
+public record MetaOffset(String name, VersionCheck[] checks) {
+}
diff --git a/code-gen/src/main/java/me/tofaa/entitylib/codegen/MetadataClass.java b/code-gen/src/main/java/me/tofaa/entitylib/codegen/MetadataClass.java
deleted file mode 100644
index ad99b37..0000000
--- a/code-gen/src/main/java/me/tofaa/entitylib/codegen/MetadataClass.java
+++ /dev/null
@@ -1,86 +0,0 @@
-package me.tofaa.entitylib.codegen;
-
-import com.github.retrooper.packetevents.protocol.entity.data.EntityData;
-import com.github.retrooper.packetevents.protocol.entity.data.EntityDataType;
-import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerEntityMetadata;
-import com.google.gson.reflect.TypeToken;
-import com.squareup.javapoet.JavaFile;
-import com.squareup.javapoet.MethodSpec;
-import com.squareup.javapoet.TypeSpec;
-import com.squareup.javapoet.TypeVariableName;
-import org.jetbrains.annotations.NotNull;
-
-import javax.lang.model.element.Modifier;
-import java.io.IOException;
-import java.util.List;
-import java.util.Map;
-
-import static me.tofaa.entitylib.codegen.Main.OUT;
-import static me.tofaa.entitylib.codegen.Main.builder;
-
-public final class MetadataClass {
-
-    private MetadataClass() {
-
-    }
-    public static void createMetadataClass() {
-
-        TypeSpec.Builder builder = builder("me.tofaa.entitylib.meta", "Metadata");
-        builder.addField(int.class, "entityId", Modifier.PRIVATE, Modifier.FINAL);
-        builder.addField(TypeToken.getParameterized(Map.class, Byte.class, EntityData.class).getType(), "metadataMap", Modifier.PRIVATE, Modifier.FINAL);
-        MethodSpec.Builder constructor = MethodSpec.constructorBuilder()
-                .addModifiers(Modifier.PUBLIC)
-                .addCode("this.entityId = entityId;\n")
-                .addCode("this.metadataMap = new java.util.concurrent.ConcurrentHashMap<>();\n")
-                .addParameter(int.class, "entityId");
-
-        MethodSpec.Builder getIndex = MethodSpec.methodBuilder("getIndex")
-                .addModifiers(Modifier.PUBLIC)
-                .addTypeVariable(TypeVariableName.get("T"))
-                .addParameter(byte.class, "index")
-                .addParameter(TypeVariableName.get("T"), "defaultValue")
-                .returns(TypeVariableName.get("T"))
-                .addCode("EntityData entityData = metadataMap.get(index);\n")
-                .addCode("if (entityData == null) return defaultValue;\n")
-                .addCode("if (entityData.getValue() == null) return defaultValue;\n")
-                .addCode("return (T) entityData.getValue();\n");
-
-        MethodSpec.Builder setIndex = MethodSpec.methodBuilder("setIndex")
-                .addModifiers(Modifier.PUBLIC)
-                .addTypeVariable(TypeVariableName.get("T"))
-                .addParameter(byte.class, "index")
-                .addParameter(EntityDataType.class, "dataType")
-                .addParameter(TypeVariableName.get("T"), "value")
-                .addCode("EntityData data = new EntityData(index, dataType, value);\n")
-                .addCode("this.metadataMap.put(index, data);\n");
-
-        MethodSpec.Builder getEntries = MethodSpec.methodBuilder("getEntries")
-                .addModifiers(Modifier.PUBLIC)
-                .returns(TypeToken.getParameterized(List.class, EntityData.class).getType())
-                .addCode("return new java.util.ArrayList<>(metadataMap.values());\n")
-                .addAnnotation(NotNull.class);
-
-        MethodSpec.Builder createPacket = MethodSpec.methodBuilder("createPacket")
-                .addModifiers(Modifier.PUBLIC)
-                .returns(WrapperPlayServerEntityMetadata.class)
-                .addCode("return new WrapperPlayServerEntityMetadata(entityId, getEntries());\n")
-                .addAnnotation(NotNull.class);
-
-        builder.addMethod(constructor.build());
-        builder.addMethod(getIndex.build());
-        builder.addMethod(setIndex.build());
-        builder.addMethod(getEntries.build());
-        builder.addMethod(createPacket.build());
-
-        JavaFile javaFile = JavaFile.builder("me.tofaa.entitylib.meta", builder.build()).build();
-        try {
-            javaFile.writeToPath(OUT.toPath());
-        }
-        catch (IOException e)  {
-            throw new RuntimeException(e);
-        }
-    }
-
-
-
-}
diff --git a/code-gen/src/main/java/me/tofaa/entitylib/codegen/TypeHolder.java b/code-gen/src/main/java/me/tofaa/entitylib/codegen/TypeHolder.java
new file mode 100644
index 0000000..7391f9f
--- /dev/null
+++ b/code-gen/src/main/java/me/tofaa/entitylib/codegen/TypeHolder.java
@@ -0,0 +1,4 @@
+package me.tofaa.entitylib.codegen;
+
+public record TypeHolder(String className, MetaOffset[] offsets) {
+}
diff --git a/code-gen/src/main/resources/EntityMeta.json b/code-gen/src/main/resources/EntityMeta.json
deleted file mode 100644
index a74d07b..0000000
--- a/code-gen/src/main/resources/EntityMeta.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
-  "class-id": "me.tofaa.entitylib.codegen:User",
-  "methods": [
-
-    {
-      "name": "getUsername",
-      "return-type": "java.lang.String",
-      "parameters": [
-
-      ]
-    }
-
-
-  ]
-}
\ No newline at end of file
diff --git a/code-gen/src/main/resources/offset-calculator.json b/code-gen/src/main/resources/offset-calculator.json
new file mode 100644
index 0000000..414516a
--- /dev/null
+++ b/code-gen/src/main/resources/offset-calculator.json
@@ -0,0 +1,347 @@
+[
+  {
+    "class-name": "EntityMeta",
+    "offsets": [
+      {
+        "name": "airTicks",
+        "checks": [
+          {
+            "from": 47,
+            "to": 47,
+            "offset": 1
+          }
+        ]
+      },
+      {
+        "name": "customName",
+        "checks": [
+          {
+            "from": 765,
+            "to": 47,
+            "offset": 2
+          }
+        ]
+      },
+      {
+        "name": "customNameVisible",
+        "checks": [
+          {
+            "from": 765,
+            "to": 47,
+            "offset": 3
+          }
+        ]
+      },
+      {
+        "name": "silent",
+        "checks": [
+          {
+            "from": 765,
+            "to": 47,
+            "offset": 4
+          }
+        ]
+      },
+      {
+        "name": "hasNoGravity",
+        "checks": [
+          {
+            "from": 765,
+            "to": 47,
+            "offset": 5
+          }
+        ]
+      },
+      {
+        "name": "pose",
+        "checks": [
+          {
+            "from": 765,
+            "to": 47,
+            "offset": 6
+          }
+        ]
+      },
+      {
+        "name": "ticksFrozenInPowderedSnow",
+        "checks": [
+          {
+            "from": 765,
+            "to": 47,
+            "offset": 7
+          }
+        ]
+      }
+    ]
+  },
+  {
+    "class-name": "AbstractDisplayMeta",
+    "offsets": [
+      {
+        "name": "interpolationDelay",
+        "checks": [
+          {
+            "from": 765,
+            "to": 762,
+            "offset": 8
+          }
+        ]
+      },
+      {
+        "name": "transformationDuration",
+        "checks": [
+          {
+            "from": 765,
+            "to": 762,
+            "offset": 9
+          }
+        ]
+      },
+      {
+        "name": "positionRotationInterpolationDuration",
+        "checks": [
+          {
+            "from": 765,
+            "to": 764,
+            "offset": 10
+          }
+        ]
+      },
+      {
+        "name": "translation",
+        "checks": [
+          {
+            "from": 765,
+            "to": 764,
+            "offset": 11
+          },
+          {
+            "from": 763,
+            "to": 762,
+            "offset": 10
+          }
+        ]
+      },
+      {
+        "name": "scale",
+        "checks": [
+          {
+            "from": 765,
+            "to": 764,
+            "offset": 12
+          },
+          {
+            "from": 763,
+            "to": 762,
+            "offset": 11
+          }
+        ]
+      },
+      {
+        "name": "leftRotation",
+        "checks": [
+          {
+            "from": 765,
+            "to": 764,
+            "offset": 13
+          },
+          {
+            "from": 763,
+            "to": 762,
+            "offset": 12
+          }
+        ]
+      },
+      {
+        "name": "rightRotation",
+        "checks": [
+          {
+            "from": 765,
+            "to": 764,
+            "offset": 14
+          },
+          {
+            "from": 763,
+            "to": 762,
+            "offset": 13
+          }
+        ]
+      },
+      {
+        "name": "billboardConstraints",
+        "checks": [
+          {
+            "from": 765,
+            "to": 764,
+            "offset": 15
+          },
+          {
+            "from": 763,
+            "to": 762,
+            "offset": 14
+          }
+        ]
+      },
+      {
+        "name": "brightnessOverride",
+        "checks": [
+          {
+            "from": 765,
+            "to": 764,
+            "offset": 16
+          },
+          {
+            "from": 763,
+            "to": 762,
+            "offset": 15
+          }
+        ]
+      },
+      {
+        "name": "viewRange",
+        "checks": [
+          {
+            "from": 765,
+            "to": 764,
+            "offset": 17
+          },
+          {
+            "from": 763,
+            "to": 762,
+            "offset": 16
+          }
+        ]
+      },
+      {
+        "name": "shadowRadius",
+        "checks": [
+          {
+            "from": 765,
+            "to": 764,
+            "offset": 18
+          },
+          {
+            "from": 763,
+            "to": 762,
+            "offset": 17
+          }
+        ]
+      },
+      {
+        "name": "shadowStrength",
+        "checks": [
+          {
+            "from": 765,
+            "to": 764,
+            "offset": 19
+          },
+          {
+            "from": 763,
+            "to": 762,
+            "offset": 18
+          }
+        ]
+      },
+      {
+        "name": "width",
+        "checks": [
+          {
+            "from": 765,
+            "to": 764,
+            "offset": 20
+          },
+          {
+            "from": 763,
+            "to": 762,
+            "offset": 19
+          }
+        ]
+      },
+      {
+        "name": "height",
+        "checks": [
+          {
+            "from": 765,
+            "to": 764,
+            "offset": 21
+          },
+          {
+            "from": 763,
+            "to": 762,
+            "offset": 20
+          }
+        ]
+      },
+      {
+        "name": "glowColorOverride",
+        "checks": [
+          {
+            "from": 765,
+            "to": 764,
+            "offset": 22
+          },
+          {
+            "from": 763,
+            "to": 762,
+            "offset": 21
+          }
+        ]
+      }
+    ]
+  },
+  {
+    "class-name": "BlockDisplayMeta",
+    "offsets": [
+      {
+        "name": "blockId",
+        "checks": [
+          {
+            "from": 765,
+            "to": 764,
+            "offset": 23
+          },
+          {
+            "from": 763,
+            "to": 762,
+            "offset": 22
+          }
+        ]
+      }
+    ]
+  },
+  {
+    "class-name": "ItemDisplay",
+    "offsets": [
+      {
+        "name": "item",
+        "checks": [
+          {
+            "from": 765,
+            "to": 764,
+            "offset": 24
+          },
+          {
+            "from": 763,
+            "to": 762,
+            "offset": 23
+          }
+        ]
+      },
+      {
+        "name": "displayType",
+        "checks": [
+          {
+            "from": 765,
+            "to": 764,
+            "offset": 25
+          },
+          {
+            "from": 763,
+            "to": 762,
+            "offset": 24
+          }
+        ]
+      }
+    ]
+  }
+]
\ No newline at end of file
diff --git a/test-plugin/src/main/java/me/tofaa/testentitylib/TestEntityLibPlugin.java b/test-plugin/src/main/java/me/tofaa/testentitylib/TestEntityLibPlugin.java
index 054a5b5..812523d 100644
--- a/test-plugin/src/main/java/me/tofaa/testentitylib/TestEntityLibPlugin.java
+++ b/test-plugin/src/main/java/me/tofaa/testentitylib/TestEntityLibPlugin.java
@@ -8,6 +8,7 @@ import me.tofaa.entitylib.APIConfig;
 import me.tofaa.entitylib.EntityLib;
 import me.tofaa.entitylib.EntityLibAPI;
 import me.tofaa.entitylib.WorldWrapper;
+import me.tofaa.entitylib.meta.mobs.passive.ChickenMeta;
 import me.tofaa.entitylib.spigot.SpigotEntityLibPlatform;
 import me.tofaa.entitylib.wrapper.WrapperEntity;
 import org.bukkit.World;
@@ -25,7 +26,6 @@ public class TestEntityLibPlugin extends JavaPlugin implements Listener {
     private WrapperEntity e;
     private WorldWrapper<World> world;
 
-
     @Override
     public void onEnable() {
 
@@ -49,7 +49,9 @@ public class TestEntityLibPlugin extends JavaPlugin implements Listener {
         }
         world = api.wrapWorld(player.getWorld());
         e = world.spawnEntity(EntityTypes.CHICKEN, SpigotConversionUtil.fromBukkitLocation(player.getLocation()));
-
+        ChickenMeta meta = (ChickenMeta) e.getEntityMeta();
+        meta.setBaby(!meta.isBaby());
+        meta.setHasGlowingEffect(!meta.hasGlowingEffect());
     }
 
 }

From ae21d857408452714fc0f84d70083730da650641 Mon Sep 17 00:00:00 2001
From: Tofaa <82680183+Tofaa2@users.noreply.github.com>
Date: Mon, 5 Feb 2024 23:09:12 +0400
Subject: [PATCH 09/19] fix broken protocol values

---
 .idea/workspace.xml                           | 50 +++++++----
 .../java/me/tofaa/entitylib/APIConfig.java    |  2 +
 .../me/tofaa/entitylib/EntityIdProvider.java  |  5 ++
 .../java/me/tofaa/entitylib/extras/Color.java | 55 ++++++++++++
 .../me/tofaa/entitylib/extras/DyeColor.java   | 85 +++++++++++++++++++
 .../me/tofaa/entitylib/extras/Rotation.java   | 38 +++++++++
 .../entitylib/meta/mobs/tameable/CatMeta.java |  3 +-
 .../tofaa/entitylib/tick/TickContainer.java   |  4 +-
 .../wrapper/WrapperEntityCreature.java        |  2 +-
 .../tofaa/entitylib/wrapper/ai/AIGroup.java   | 11 +++
 .../common/AbstractWorldWrapper.java          |  2 +-
 test-plugin/build.gradle                      |  2 +-
 .../testentitylib/TestEntityLibPlugin.java    |  9 +-
 13 files changed, 241 insertions(+), 27 deletions(-)
 create mode 100644 api/src/main/java/me/tofaa/entitylib/extras/Color.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/extras/DyeColor.java
 create mode 100644 api/src/main/java/me/tofaa/entitylib/extras/Rotation.java

diff --git a/.idea/workspace.xml b/.idea/workspace.xml
index 19d8f43..fcc317b 100644
--- a/.idea/workspace.xml
+++ b/.idea/workspace.xml
@@ -5,19 +5,17 @@
   </component>
   <component name="ChangeListManager">
     <list default="true" id="9d5d9b6f-43c8-41a4-bb42-a66ffc96c9b0" name="Changes" comment="">
-      <change afterPath="$PROJECT_DIR$/code-gen/src/main/java/me/tofaa/entitylib/codegen/MetaOffset.java" afterDir="false" />
-      <change afterPath="$PROJECT_DIR$/code-gen/src/main/java/me/tofaa/entitylib/codegen/TypeHolder.java" afterDir="false" />
-      <change afterPath="$PROJECT_DIR$/code-gen/src/main/resources/offset-calculator.json" afterDir="false" />
+      <change afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/extras/Color.java" afterDir="false" />
+      <change afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/extras/DyeColor.java" afterDir="false" />
+      <change afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/extras/Rotation.java" afterDir="false" />
       <change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
-      <change beforePath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/EntityUuidProvider.java" beforeDir="false" afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/EntityUuidProvider.java" afterDir="false" />
-      <change beforePath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/meta/CompatibilityIndex.java" beforeDir="false" />
-      <change beforePath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/meta/EntityMeta.java" beforeDir="false" afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/meta/EntityMeta.java" afterDir="false" />
-      <change beforePath="$PROJECT_DIR$/code-gen/build.gradle" beforeDir="false" afterPath="$PROJECT_DIR$/code-gen/build.gradle" afterDir="false" />
-      <change beforePath="$PROJECT_DIR$/code-gen/src/main/java/me/tofaa/entitylib/codegen/Main.java" beforeDir="false" afterPath="$PROJECT_DIR$/code-gen/src/main/java/me/tofaa/entitylib/codegen/Main.java" afterDir="false" />
-      <change beforePath="$PROJECT_DIR$/code-gen/src/main/java/me/tofaa/entitylib/codegen/MetaClass.java" beforeDir="false" />
-      <change beforePath="$PROJECT_DIR$/code-gen/src/main/java/me/tofaa/entitylib/codegen/MetaMethod.java" beforeDir="false" />
-      <change beforePath="$PROJECT_DIR$/code-gen/src/main/java/me/tofaa/entitylib/codegen/MetadataClass.java" beforeDir="false" />
-      <change beforePath="$PROJECT_DIR$/code-gen/src/main/resources/EntityMeta.json" beforeDir="false" />
+      <change beforePath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/APIConfig.java" beforeDir="false" afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/APIConfig.java" afterDir="false" />
+      <change beforePath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/meta/mobs/tameable/CatMeta.java" beforeDir="false" afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/meta/mobs/tameable/CatMeta.java" afterDir="false" />
+      <change beforePath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperEntityCreature.java" beforeDir="false" afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperEntityCreature.java" afterDir="false" />
+      <change beforePath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/wrapper/ai/AIGroup.java" beforeDir="false" afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/wrapper/ai/AIGroup.java" afterDir="false" />
+      <change beforePath="$PROJECT_DIR$/common/src/main/java/me/tofaa/entitylib/common/AbstractWorldWrapper.java" beforeDir="false" afterPath="$PROJECT_DIR$/common/src/main/java/me/tofaa/entitylib/common/AbstractWorldWrapper.java" afterDir="false" />
+      <change beforePath="$PROJECT_DIR$/test-plugin/build.gradle" beforeDir="false" afterPath="$PROJECT_DIR$/test-plugin/build.gradle" afterDir="false" />
+      <change beforePath="$PROJECT_DIR$/test-plugin/src/main/java/me/tofaa/testentitylib/TestEntityLibPlugin.java" beforeDir="false" afterPath="$PROJECT_DIR$/test-plugin/src/main/java/me/tofaa/testentitylib/TestEntityLibPlugin.java" afterDir="false" />
     </list>
     <option name="SHOW_DIALOG" value="false" />
     <option name="HIGHLIGHT_CONFLICTS" value="true" />
@@ -48,6 +46,24 @@
                 <item name="" type="6a2764b6:ExternalProjectsStructure$RootNode" />
                 <item name="EntityLib" type="f1a62948:ProjectNode" />
               </path>
+              <path>
+                <item name="" type="6a2764b6:ExternalProjectsStructure$RootNode" />
+                <item name="EntityLib" type="f1a62948:ProjectNode" />
+                <item name="test-plugin" type="2d1252cf:ModuleNode" />
+              </path>
+              <path>
+                <item name="" type="6a2764b6:ExternalProjectsStructure$RootNode" />
+                <item name="EntityLib" type="f1a62948:ProjectNode" />
+                <item name="test-plugin" type="2d1252cf:ModuleNode" />
+                <item name="Tasks" type="e4a08cd1:TasksNode" />
+              </path>
+              <path>
+                <item name="" type="6a2764b6:ExternalProjectsStructure$RootNode" />
+                <item name="EntityLib" type="f1a62948:ProjectNode" />
+                <item name="test-plugin" type="2d1252cf:ModuleNode" />
+                <item name="Tasks" type="e4a08cd1:TasksNode" />
+                <item name="run paper" type="c8890929:TasksNode$1" />
+              </path>
             </expand>
             <select />
           </tree_state>
@@ -97,7 +113,7 @@
     &quot;ignore.virus.scanning.warn.message&quot;: &quot;true&quot;,
     &quot;jdk.selected.JAVA_MODULE&quot;: &quot;corretto-17&quot;,
     &quot;kotlin-language-version-configured&quot;: &quot;true&quot;,
-    &quot;last_opened_file_path&quot;: &quot;D:/Github/EntityLib/api/src/main/java/me/tofaa/entitylib/meta&quot;,
+    &quot;last_opened_file_path&quot;: &quot;D:/Github/EntityLib/api/src/main/java/me/tofaa/entitylib/extras&quot;,
     &quot;node.js.detected.package.eslint&quot;: &quot;true&quot;,
     &quot;node.js.detected.package.tslint&quot;: &quot;true&quot;,
     &quot;node.js.selected.package.eslint&quot;: &quot;(autodetect)&quot;,
@@ -112,11 +128,12 @@
 }</component>
   <component name="RecentsManager">
     <key name="CopyFile.RECENT_KEYS">
+      <recent name="D:\Github\EntityLib\api\src\main\java\me\tofaa\entitylib\extras" />
       <recent name="D:\Github\EntityLib\api\src\main\java\me\tofaa\entitylib\meta" />
       <recent name="D:\Github\EntityLib\test-plugin" />
     </key>
   </component>
-  <component name="RunManager" selected="Application.Main">
+  <component name="RunManager" selected="Gradle.EntityLib:test-plugin [runServer]">
     <configuration name="Main" type="Application" factoryName="Application" temporary="true" nameIsGenerated="true">
       <option name="MAIN_CLASS_NAME" value="me.tofaa.entitylib.codegen.Main" />
       <module name="EntityLib.code-gen.main" />
@@ -220,9 +237,9 @@
     </configuration>
     <recent_temporary>
       <list>
+        <item itemvalue="Gradle.EntityLib:test-plugin [runServer]" />
         <item itemvalue="Application.Main" />
         <item itemvalue="Gradle.EntityLib [dependencies]" />
-        <item itemvalue="Gradle.EntityLib:test-plugin [runServer]" />
         <item itemvalue="Gradle.PE-EntityMeta [compileTestJava]" />
         <item itemvalue="Gradle.EntityLib:test-plugin [shadowJar]" />
       </list>
@@ -280,7 +297,8 @@
       <workItem from="1706601592145" duration="1670000" />
       <workItem from="1706614921404" duration="10508000" />
       <workItem from="1706696719616" duration="4783000" />
-      <workItem from="1706784821835" duration="5673000" />
+      <workItem from="1706784821835" duration="7882000" />
+      <workItem from="1706858181164" duration="925000" />
     </task>
     <servers />
   </component>
diff --git a/api/src/main/java/me/tofaa/entitylib/APIConfig.java b/api/src/main/java/me/tofaa/entitylib/APIConfig.java
index b9f09f8..648644c 100644
--- a/api/src/main/java/me/tofaa/entitylib/APIConfig.java
+++ b/api/src/main/java/me/tofaa/entitylib/APIConfig.java
@@ -3,6 +3,7 @@ package me.tofaa.entitylib;
 import com.github.retrooper.packetevents.PacketEventsAPI;
 import com.google.gson.JsonArray;
 import com.google.gson.JsonParser;
+import org.jetbrains.annotations.Blocking;
 import org.jetbrains.annotations.NotNull;
 
 import java.io.IOException;
@@ -24,6 +25,7 @@ public final class APIConfig {
         this.packetEvents = packetEvents;
     }
 
+    @Blocking
     public boolean requiresUpdate() throws IOException {
         if (!checkForUpdates) return false;
         String urlString = "https://api.github.com/repos/Tofaa2/EntityLib/releases/latest";
diff --git a/api/src/main/java/me/tofaa/entitylib/EntityIdProvider.java b/api/src/main/java/me/tofaa/entitylib/EntityIdProvider.java
index 2dc3a17..1426684 100644
--- a/api/src/main/java/me/tofaa/entitylib/EntityIdProvider.java
+++ b/api/src/main/java/me/tofaa/entitylib/EntityIdProvider.java
@@ -6,6 +6,11 @@ import org.jetbrains.annotations.NotNull;
 import java.util.UUID;
 import java.util.concurrent.atomic.AtomicInteger;
 
+/**
+ * Represents a int provider that gives an id for each entity created. When using EntityLib with platform specific entities (Such as bukkit entities), make sure the id's do not
+ * conflict with the platform's entity id's.
+ * {@link DefaultEntityIdProvider} is a default implementation of this interface.
+ */
 public interface EntityIdProvider {
 
     int provide(@NotNull UUID entityUUID, @NotNull EntityType entityType);
diff --git a/api/src/main/java/me/tofaa/entitylib/extras/Color.java b/api/src/main/java/me/tofaa/entitylib/extras/Color.java
new file mode 100644
index 0000000..8feba87
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/extras/Color.java
@@ -0,0 +1,55 @@
+package me.tofaa.entitylib.extras;
+
+import net.kyori.adventure.util.RGBLike;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Range;
+
+public final class Color implements RGBLike {
+
+    private static final int BIT_MASK = 0xFF;
+
+    private final int red, green, blue;
+
+    public Color(@Range(from = 0L, to = 255L) int red, @Range(from = 0L, to = 255L) int green, @Range(from = 0L, to = 255L) int blue) {
+        this.red = red;
+        this.green = green;
+        this.blue = blue;
+    }
+
+    public Color(int rgb) {
+        this((rgb >> 16) & BIT_MASK, (rgb >> 8) & BIT_MASK, rgb & BIT_MASK);
+    }
+
+    public @NotNull Color withRed(@Range(from = 0L, to = 255L) int red) {
+        return new Color(red, green, blue);
+    }
+
+    public @NotNull Color withGreen(@Range(from = 0L, to = 255L) int green) {
+        return new Color(red, green, blue);
+    }
+
+    public @NotNull Color withBlue(@Range(from = 0L, to = 255L) int blue) {
+        return new Color(red, green, blue);
+    }
+
+    public int asRGB() {
+        int rgb = red;
+        rgb = (rgb << 8) + green;
+        return (rgb << 8) + blue;
+    }
+
+    @Override
+    public @Range(from = 0L, to = 255L) int red() {
+        return red;
+    }
+
+    @Override
+    public @Range(from = 0L, to = 255L) int green() {
+        return green;
+    }
+
+    @Override
+    public @Range(from = 0L, to = 255L) int blue() {
+        return blue;
+    }
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/extras/DyeColor.java b/api/src/main/java/me/tofaa/entitylib/extras/DyeColor.java
new file mode 100644
index 0000000..798036f
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/extras/DyeColor.java
@@ -0,0 +1,85 @@
+package me.tofaa.entitylib.extras;
+
+import net.kyori.adventure.util.RGBLike;
+import org.jetbrains.annotations.NotNull;
+
+public enum DyeColor implements RGBLike {
+    WHITE(new Color(0xf9fffe), new Color(0xffffff), new Color(0xf0f0f0), 8),
+
+    ORANGE(new Color(0xf9801d), new Color(0xff681f), new Color(0xeb8844), 15),
+
+    MAGENTA(new Color(0xc74ebd), new Color(0xff00ff), new Color(0xc354cd), 16),
+
+    LIGHT_BLUE(new Color(0x3ab3da), new Color(0x9ac0cd), new Color(0x6689d3), 17),
+
+    YELLOW(new Color(0xfed83d), new Color(0xffff00), new Color(0xdecf2a), 18),
+
+    LIME(new Color(0x80c71f), new Color(0xbfff00), new Color(0x41cd34), 19),
+
+    PINK(new Color(0xf38baa), new Color(0xff69b4), new Color(0xd88198), 20),
+
+    GRAY(new Color(0x474f52), new Color(0x808080), new Color(0x434343), 21),
+
+    LIGHT_GRAY(new Color(0x9d9d97), new Color(0xd3d3d3), new Color(0xababab), 22),
+
+    CYAN(new Color(0x169c9c), new Color(0xffff), new Color(0x287697), 23),
+
+    PURPLE(new Color(0x8932b8), new Color(0xa020f0), new Color(0x7b2fbe), 24),
+
+    BLUE(new Color(0x3c44aa), new Color(0xff), new Color(0x253192), 25),
+
+    BROWN(new Color(0x835432), new Color(0x8b4513), new Color(0x51301a), 26),
+
+    GREEN(new Color(0x5e7c16), new Color(0xff00), new Color(0x3b511a), 27),
+
+    RED(new Color(0xb02e26), new Color(0xff0000), new Color(0xb3312c), 28),
+
+    BLACK(new Color(0x1d1d21), new Color(0x0), new Color(0x1e1b1b), 29);
+
+    private final Color textureDiffuseColor;
+
+    private final Color textColor;
+
+    private final Color fireworkColor;
+
+    private final int mapColorId;
+
+    DyeColor(@NotNull Color textureDiffuseColor, @NotNull Color textColor,
+             @NotNull Color fireworkColor, int mapColorId) {
+        this.textureDiffuseColor = textureDiffuseColor;
+        this.textColor = textColor;
+        this.fireworkColor = fireworkColor;
+        this.mapColorId = mapColorId;
+    }
+
+    public @NotNull Color color() {
+        return this.textureDiffuseColor;
+    }
+
+    public @NotNull Color textColor() {
+        return this.textColor;
+    }
+
+    public @NotNull Color fireworkColor() {
+        return this.fireworkColor;
+    }
+
+    @Override
+    public int red() {
+        return this.textureDiffuseColor.red();
+    }
+
+    @Override
+    public int green() {
+        return this.textureDiffuseColor.green();
+    }
+
+    @Override
+    public int blue() {
+        return this.textureDiffuseColor.blue();
+    }
+
+    public int mapColorId() {
+        return this.mapColorId;
+    }
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/extras/Rotation.java b/api/src/main/java/me/tofaa/entitylib/extras/Rotation.java
new file mode 100644
index 0000000..b05b61e
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/extras/Rotation.java
@@ -0,0 +1,38 @@
+package me.tofaa.entitylib.extras;
+
+public enum Rotation {
+
+    /**
+     * No rotation
+     */
+    NONE,
+    /**
+     * Rotated clockwise by 45 degrees
+     */
+    CLOCKWISE_45,
+    /**
+     * Rotated clockwise by 90 degrees
+     */
+    CLOCKWISE,
+    /**
+     * Rotated clockwise by 135 degrees
+     */
+    CLOCKWISE_135,
+    /**
+     * Flipped upside-down, a 180-degree rotation
+     */
+    FLIPPED,
+    /**
+     * Flipped upside-down + 45-degree rotation
+     */
+    FLIPPED_45,
+    /**
+     * Rotated counter-clockwise by 90 degrees
+     */
+    COUNTER_CLOCKWISE,
+    /**
+     * Rotated counter-clockwise by 45 degrees
+     */
+    COUNTER_CLOCKWISE_45;
+
+}
\ No newline at end of file
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/mobs/tameable/CatMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/mobs/tameable/CatMeta.java
index 2dde774..5dae395 100644
--- a/api/src/main/java/me/tofaa/entitylib/meta/mobs/tameable/CatMeta.java
+++ b/api/src/main/java/me/tofaa/entitylib/meta/mobs/tameable/CatMeta.java
@@ -1,11 +1,10 @@
 package me.tofaa.entitylib.meta.mobs.tameable;
 
 import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
-import com.github.retrooper.packetevents.protocol.entity.type.EntityTypes;
 import me.tofaa.entitylib.extras.DyeColor;
 import me.tofaa.entitylib.meta.Metadata;
 import me.tofaa.entitylib.meta.types.TameableMeta;
-import net.kyori.adventure.text.format.NamedTextColor;
+
 import org.jetbrains.annotations.NotNull;
 
 public class CatMeta extends TameableMeta {
diff --git a/api/src/main/java/me/tofaa/entitylib/tick/TickContainer.java b/api/src/main/java/me/tofaa/entitylib/tick/TickContainer.java
index f1b856f..0d9b880 100644
--- a/api/src/main/java/me/tofaa/entitylib/tick/TickContainer.java
+++ b/api/src/main/java/me/tofaa/entitylib/tick/TickContainer.java
@@ -9,11 +9,11 @@ import java.util.HashSet;
 import java.util.Set;
 
 /**
- * Represents a storage/container for {@link Tickable}s.
+ * Represents a storage/container for {@link Tickable}s. This class is extendable in case you want to provide custom logic and/or methods.
  * @param <T> The type of {@link Tickable} to store.
  * @param <H> If a platform enforces a specific method of ticking, this type represents the handler for that method.
  */
-public abstract class TickContainer<T extends Tickable, H> {
+public class TickContainer<T extends Tickable, H> {
 
     private final Set<T> tickables = new HashSet<>();
     private H handle;
diff --git a/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperEntityCreature.java b/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperEntityCreature.java
index b797dfa..6771d15 100644
--- a/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperEntityCreature.java
+++ b/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperEntityCreature.java
@@ -32,7 +32,7 @@ public class WrapperEntityCreature extends WrapperLivingEntity {
     @Override
     public void tick(long time) {
         super.tick(time);
-        aiGroups.forEach(aiGroup -> aiGroup.update(time));
+        aiGroups.forEach(aiGroup -> aiGroup.tick(time));
     }
 
     /**
diff --git a/api/src/main/java/me/tofaa/entitylib/wrapper/ai/AIGroup.java b/api/src/main/java/me/tofaa/entitylib/wrapper/ai/AIGroup.java
index 99992b5..6818b65 100644
--- a/api/src/main/java/me/tofaa/entitylib/wrapper/ai/AIGroup.java
+++ b/api/src/main/java/me/tofaa/entitylib/wrapper/ai/AIGroup.java
@@ -11,6 +11,7 @@ public class AIGroup implements Tickable {
 
     private final List<GoalSelector> goalSelectors = new GoalSelectorList(this);
     private GoalSelector currentGoalSelector;
+    private boolean ticking = true;
 
     public @NotNull Collection<GoalSelector> getGoalSelectors() {
         return goalSelectors;
@@ -36,6 +37,16 @@ public class AIGroup implements Tickable {
         currentGoalSelector = goalSelector;
     }
 
+    @Override
+    public boolean isTicking() {
+        return ticking;
+    }
+
+    @Override
+    public void setTicking(boolean ticking) {
+        this.ticking = ticking;
+    }
+
     @Override
     public void tick(long time) {
         GoalSelector currentGoalSelector = getCurrentGoal();
diff --git a/common/src/main/java/me/tofaa/entitylib/common/AbstractWorldWrapper.java b/common/src/main/java/me/tofaa/entitylib/common/AbstractWorldWrapper.java
index f203954..0bb678c 100644
--- a/common/src/main/java/me/tofaa/entitylib/common/AbstractWorldWrapper.java
+++ b/common/src/main/java/me/tofaa/entitylib/common/AbstractWorldWrapper.java
@@ -31,7 +31,7 @@ public abstract class AbstractWorldWrapper<W> implements WorldWrapper<W> {
         this.handle = handle;
         this.dimension = dimension;
         this.entities = new ConcurrentHashMap<>();
-        this.entitiesById = Collections.emptyMap();
+        this.entitiesById = new ConcurrentHashMap<>();
     }
 
 
diff --git a/test-plugin/build.gradle b/test-plugin/build.gradle
index a9755f2..29dc72d 100644
--- a/test-plugin/build.gradle
+++ b/test-plugin/build.gradle
@@ -32,6 +32,6 @@ dependencies {
 
 tasks {
     runServer {
-        minecraftVersion("1.19.4")
+        minecraftVersion("1.20.4")
     }
 }
\ No newline at end of file
diff --git a/test-plugin/src/main/java/me/tofaa/testentitylib/TestEntityLibPlugin.java b/test-plugin/src/main/java/me/tofaa/testentitylib/TestEntityLibPlugin.java
index 812523d..849ec69 100644
--- a/test-plugin/src/main/java/me/tofaa/testentitylib/TestEntityLibPlugin.java
+++ b/test-plugin/src/main/java/me/tofaa/testentitylib/TestEntityLibPlugin.java
@@ -1,7 +1,6 @@
 package me.tofaa.testentitylib;
 
 import com.github.retrooper.packetevents.PacketEvents;
-import com.github.retrooper.packetevents.protocol.entity.type.EntityType;
 import com.github.retrooper.packetevents.protocol.entity.type.EntityTypes;
 import io.github.retrooper.packetevents.util.SpigotConversionUtil;
 import me.tofaa.entitylib.APIConfig;
@@ -43,15 +42,17 @@ public class TestEntityLibPlugin extends JavaPlugin implements Listener {
     @EventHandler
     public void onCrouch(PlayerToggleSneakEvent event) {
         Player player = event.getPlayer();
-        if (e != null) {
-            e.remove();
-            e = null;
+        if (e == null) {
+            world = api.wrapWorld(player.getWorld());
+            e = world.spawnEntity(EntityTypes.CHICKEN, SpigotConversionUtil.fromBukkitLocation(player.getLocation()));
         }
         world = api.wrapWorld(player.getWorld());
         e = world.spawnEntity(EntityTypes.CHICKEN, SpigotConversionUtil.fromBukkitLocation(player.getLocation()));
         ChickenMeta meta = (ChickenMeta) e.getEntityMeta();
         meta.setBaby(!meta.isBaby());
         meta.setHasGlowingEffect(!meta.hasGlowingEffect());
+
+        e.addViewer(player.getUniqueId());
     }
 
 }

From 5130a65a0f10535214cc41cfb961e4e5037d9bd8 Mon Sep 17 00:00:00 2001
From: Tofaa <82680183+Tofaa2@users.noreply.github.com>
Date: Tue, 6 Feb 2024 00:30:05 +0400
Subject: [PATCH 10/19] more stuff

---
 .idea/workspace.xml                           | 17 ++---
 .../java/me/tofaa/entitylib/EntityLibAPI.java |  2 +
 .../java/me/tofaa/entitylib/utils/Check.java  | 64 +++++++++++++++++++
 .../entitylib/wrapper/WrapperEntity.java      | 20 ++++++
 .../entitylib/wrapper/hologram/Hologram.java  |  1 -
 .../entitylib/spigot/ExtraConversionUtil.java | 23 +++++++
 .../tofaa/entitylib/spigot/SpigotWorld.java   | 35 +++++++++-
 7 files changed, 150 insertions(+), 12 deletions(-)
 create mode 100644 api/src/main/java/me/tofaa/entitylib/utils/Check.java
 create mode 100644 platforms/spigot/src/main/java/me/tofaa/entitylib/spigot/ExtraConversionUtil.java

diff --git a/.idea/workspace.xml b/.idea/workspace.xml
index fcc317b..d305e06 100644
--- a/.idea/workspace.xml
+++ b/.idea/workspace.xml
@@ -5,17 +5,13 @@
   </component>
   <component name="ChangeListManager">
     <list default="true" id="9d5d9b6f-43c8-41a4-bb42-a66ffc96c9b0" name="Changes" comment="">
-      <change afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/extras/Color.java" afterDir="false" />
-      <change afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/extras/DyeColor.java" afterDir="false" />
-      <change afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/extras/Rotation.java" afterDir="false" />
+      <change afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/utils/Check.java" afterDir="false" />
+      <change afterPath="$PROJECT_DIR$/platforms/spigot/src/main/java/me/tofaa/entitylib/spigot/ExtraConversionUtil.java" afterDir="false" />
       <change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
-      <change beforePath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/APIConfig.java" beforeDir="false" afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/APIConfig.java" afterDir="false" />
-      <change beforePath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/meta/mobs/tameable/CatMeta.java" beforeDir="false" afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/meta/mobs/tameable/CatMeta.java" afterDir="false" />
-      <change beforePath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperEntityCreature.java" beforeDir="false" afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperEntityCreature.java" afterDir="false" />
-      <change beforePath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/wrapper/ai/AIGroup.java" beforeDir="false" afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/wrapper/ai/AIGroup.java" afterDir="false" />
-      <change beforePath="$PROJECT_DIR$/common/src/main/java/me/tofaa/entitylib/common/AbstractWorldWrapper.java" beforeDir="false" afterPath="$PROJECT_DIR$/common/src/main/java/me/tofaa/entitylib/common/AbstractWorldWrapper.java" afterDir="false" />
-      <change beforePath="$PROJECT_DIR$/test-plugin/build.gradle" beforeDir="false" afterPath="$PROJECT_DIR$/test-plugin/build.gradle" afterDir="false" />
-      <change beforePath="$PROJECT_DIR$/test-plugin/src/main/java/me/tofaa/testentitylib/TestEntityLibPlugin.java" beforeDir="false" afterPath="$PROJECT_DIR$/test-plugin/src/main/java/me/tofaa/testentitylib/TestEntityLibPlugin.java" afterDir="false" />
+      <change beforePath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/EntityLibAPI.java" beforeDir="false" afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/EntityLibAPI.java" afterDir="false" />
+      <change beforePath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperEntity.java" beforeDir="false" afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperEntity.java" afterDir="false" />
+      <change beforePath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/wrapper/hologram/Hologram.java" beforeDir="false" afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/wrapper/hologram/Hologram.java" afterDir="false" />
+      <change beforePath="$PROJECT_DIR$/platforms/spigot/src/main/java/me/tofaa/entitylib/spigot/SpigotWorld.java" beforeDir="false" afterPath="$PROJECT_DIR$/platforms/spigot/src/main/java/me/tofaa/entitylib/spigot/SpigotWorld.java" afterDir="false" />
     </list>
     <option name="SHOW_DIALOG" value="false" />
     <option name="HIGHLIGHT_CONFLICTS" value="true" />
@@ -299,6 +295,7 @@
       <workItem from="1706696719616" duration="4783000" />
       <workItem from="1706784821835" duration="7882000" />
       <workItem from="1706858181164" duration="925000" />
+      <workItem from="1707159905372" duration="3391000" />
     </task>
     <servers />
   </component>
diff --git a/api/src/main/java/me/tofaa/entitylib/EntityLibAPI.java b/api/src/main/java/me/tofaa/entitylib/EntityLibAPI.java
index 0b6380d..5276ee7 100644
--- a/api/src/main/java/me/tofaa/entitylib/EntityLibAPI.java
+++ b/api/src/main/java/me/tofaa/entitylib/EntityLibAPI.java
@@ -2,6 +2,7 @@ package me.tofaa.entitylib;
 
 import com.github.retrooper.packetevents.PacketEventsAPI;
 import me.tofaa.entitylib.tick.TickContainer;
+import me.tofaa.entitylib.wrapper.WrapperEntity;
 import org.jetbrains.annotations.NotNull;
 
 import java.util.Collection;
@@ -25,6 +26,7 @@ public interface EntityLibAPI<W, T> {
 
     void onEnable();
 
+
     /**
      * Creates a wrapped world for the platform specific world.
      * @param world The platform specific world handle.
diff --git a/api/src/main/java/me/tofaa/entitylib/utils/Check.java b/api/src/main/java/me/tofaa/entitylib/utils/Check.java
new file mode 100644
index 0000000..82816ea
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/utils/Check.java
@@ -0,0 +1,64 @@
+package me.tofaa.entitylib.utils;
+
+import org.jetbrains.annotations.Contract;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.text.MessageFormat;
+import java.util.Objects;
+
+/**
+ * Convenient class to check for common exceptions. Taken from <a href="https://minestom.net/">Minestom</a>
+ */
+public final class Check {
+
+    private Check() {}
+
+    @Contract("null, _ -> fail")
+    public static void notNull(@Nullable Object object, @NotNull String reason) {
+        if (Objects.isNull(object)) {
+            throw new NullPointerException(reason);
+        }
+    }
+
+    @Contract("null, _, _ -> fail")
+    public static void notNull(@Nullable Object object, @NotNull String reason, Object... arguments) {
+        if (Objects.isNull(object)) {
+            throw new NullPointerException(MessageFormat.format(reason, arguments));
+        }
+    }
+
+    @Contract("true, _ -> fail")
+    public static void argCondition(boolean condition, @NotNull String reason) {
+        if (condition) {
+            throw new IllegalArgumentException(reason);
+        }
+    }
+
+    @Contract("true, _, _ -> fail")
+    public static void argCondition(boolean condition, @NotNull String reason, Object... arguments) {
+        if (condition) {
+            throw new IllegalArgumentException(MessageFormat.format(reason, arguments));
+        }
+    }
+
+    @Contract("_ -> fail")
+    public static void fail(@NotNull String reason) {
+        throw new IllegalArgumentException(reason);
+    }
+
+    @Contract("true, _ -> fail")
+    public static void stateCondition(boolean condition, @NotNull String reason) {
+        if (condition) {
+            throw new IllegalStateException(reason);
+        }
+    }
+
+    @Contract("true, _, _ -> fail")
+    public static void stateCondition(boolean condition, @NotNull String reason, Object... arguments) {
+        if (condition) {
+            throw new IllegalStateException(MessageFormat.format(reason, arguments));
+        }
+    }
+
+}
\ No newline at end of file
diff --git a/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperEntity.java b/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperEntity.java
index 3790363..ddc4fda 100644
--- a/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperEntity.java
+++ b/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperEntity.java
@@ -45,6 +45,10 @@ public class WrapperEntity implements Tickable {
         this.viewers = new HashSet<>();
     }
 
+    public boolean spawn(Location location) {
+        return spawn(null, location);
+    }
+
     public boolean spawn(WorldWrapper<?> world, Location location) {
         if (spawned) return false;
         this.location = location;
@@ -117,6 +121,14 @@ public class WrapperEntity implements Tickable {
         teleport(world, location, onGround);
     }
 
+    public void teleport(@NotNull Location location, boolean onGround) {
+        teleport(null, location, onGround);
+    }
+
+    public void teleport(@NotNull Location location) {
+        teleport(null, location, onGround);
+    }
+
     /**
      * Adds a viewer to the viewers set. The viewer will receive all packets and be informed of this addition
      * @param uuid the uuid of the user to add
@@ -160,6 +172,10 @@ public class WrapperEntity implements Tickable {
         addViewerSilently(user.getUUID());
     }
 
+    /**
+     * Removes a viewer from the viewers set of this entity. The viewer will be informed of this removal and will no longer receive any packets
+     * @param UUID the uuid of the user to remove
+     */
     public void removeViewer(UUID uuid) {
         if (!viewers.remove(uuid)) {
             return;
@@ -167,6 +183,10 @@ public class WrapperEntity implements Tickable {
         sendPacket(uuid, new WrapperPlayServerDestroyEntities(entityId));
     }
 
+    /**
+     * Removes a viewer from the viewers set of this entity. The viewer will be informed of this removal and will no longer receive any packets
+     * @param user the user to remove
+     */
     public void removeViewer(User user) {
         removeViewer(user.getUUID());
     }
diff --git a/api/src/main/java/me/tofaa/entitylib/wrapper/hologram/Hologram.java b/api/src/main/java/me/tofaa/entitylib/wrapper/hologram/Hologram.java
index 5d684f6..a2bc891 100644
--- a/api/src/main/java/me/tofaa/entitylib/wrapper/hologram/Hologram.java
+++ b/api/src/main/java/me/tofaa/entitylib/wrapper/hologram/Hologram.java
@@ -22,7 +22,6 @@ public interface Hologram<W> {
         return new LegacyHologram<>(world, location, lines);
     }
 
-
     @NotNull Location getLocation();
 
     @NotNull WorldWrapper<W> getWorld();
diff --git a/platforms/spigot/src/main/java/me/tofaa/entitylib/spigot/ExtraConversionUtil.java b/platforms/spigot/src/main/java/me/tofaa/entitylib/spigot/ExtraConversionUtil.java
new file mode 100644
index 0000000..75e554d
--- /dev/null
+++ b/platforms/spigot/src/main/java/me/tofaa/entitylib/spigot/ExtraConversionUtil.java
@@ -0,0 +1,23 @@
+package me.tofaa.entitylib.spigot;
+
+import com.github.retrooper.packetevents.protocol.entity.pose.EntityPose;
+import com.github.retrooper.packetevents.protocol.player.HumanoidArm;
+import org.bukkit.entity.Pose;
+import org.bukkit.inventory.MainHand;
+
+public final class ExtraConversionUtil {
+
+    private ExtraConversionUtil() {
+
+    }
+
+    public static EntityPose fromBukkitPose(Pose pose) {
+        return EntityPose.values()[pose.ordinal()];
+    }
+
+    public static HumanoidArm fromBukkitHand(MainHand hand) {
+        if (hand == MainHand.RIGHT) return HumanoidArm.RIGHT;
+        return HumanoidArm.LEFT;
+    }
+
+}
diff --git a/platforms/spigot/src/main/java/me/tofaa/entitylib/spigot/SpigotWorld.java b/platforms/spigot/src/main/java/me/tofaa/entitylib/spigot/SpigotWorld.java
index cecd18e..f01c7b5 100644
--- a/platforms/spigot/src/main/java/me/tofaa/entitylib/spigot/SpigotWorld.java
+++ b/platforms/spigot/src/main/java/me/tofaa/entitylib/spigot/SpigotWorld.java
@@ -4,8 +4,17 @@ import com.github.retrooper.packetevents.protocol.world.Location;
 import com.github.retrooper.packetevents.protocol.world.states.WrappedBlockState;
 import io.github.retrooper.packetevents.util.SpigotConversionUtil;
 import me.tofaa.entitylib.common.AbstractWorldWrapper;
+import me.tofaa.entitylib.meta.EntityMeta;
+import me.tofaa.entitylib.meta.types.LivingEntityMeta;
+import me.tofaa.entitylib.meta.types.PlayerMeta;
+import me.tofaa.entitylib.utils.Check;
 import me.tofaa.entitylib.wrapper.WrapperEntity;
+import net.kyori.adventure.text.Component;
+import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
 import org.bukkit.World;
+import org.bukkit.entity.Entity;
+import org.bukkit.entity.LivingEntity;
+import org.bukkit.entity.Player;
 import org.jetbrains.annotations.NotNull;
 
 public class SpigotWorld extends AbstractWorldWrapper<World> {
@@ -18,7 +27,31 @@ public class SpigotWorld extends AbstractWorldWrapper<World> {
 
     @Override
     public <T extends WrapperEntity> @NotNull T cloneEntity(@NotNull Object platformEntity, @NotNull Location location) {
-        return null;
+        Check.stateCondition(!(platformEntity instanceof Entity), "Entity must be a Bukkit entity");
+        Entity e = (Entity) platformEntity;
+        EntityMeta meta = EntityMeta.createMeta(e.getEntityId(), SpigotConversionUtil.fromBukkitEntityType(e.getType()));
+        meta.setHasNoGravity(!e.hasGravity());
+        meta.setCustomNameVisible(e.isCustomNameVisible());
+        meta.setCustomName(LegacyComponentSerializer.legacyAmpersand().deserialize(e.getCustomName()));
+        meta.setPose(ExtraConversionUtil.fromBukkitPose(e.getPose()));
+        meta.setOnFire(e.getFireTicks() > 0);
+        meta.setSilent(e.isSilent());
+        meta.setHasGlowingEffect(e.isGlowing());
+        if (e instanceof LivingEntity) {
+            LivingEntity le = (LivingEntity) e;
+            LivingEntityMeta lm = (LivingEntityMeta) meta;
+            lm.setHealth((float) le.getHealth());
+            lm.setFlyingWithElytra(le.isGliding());
+        }
+        if (e instanceof Player) {
+            Player p = (Player) e;
+            PlayerMeta pm = (PlayerMeta) meta;
+            pm.setSneaking(p.isSneaking());
+            pm.setSprinting(p.isSprinting());
+            pm.setSwimming(p.isSwimming());
+            pm.setActiveHand(ExtraConversionUtil.fromBukkitHand(p.getMainHand()));
+        }
+        return null; // TODO;
     }
 
     @Override

From e2ca79b069a1759e8a2b93e7f58d09ab75eec154 Mon Sep 17 00:00:00 2001
From: Tofaa <82680183+Tofaa2@users.noreply.github.com>
Date: Tue, 6 Feb 2024 13:20:15 +0400
Subject: [PATCH 11/19] add player implementation

---
 .idea/workspace.xml                           |  9 +-
 .../entitylib/wrapper/WrapperEntity.java      | 13 +--
 .../wrapper/WrapperExperienceOrbEntity.java   |  4 +-
 .../entitylib/wrapper/WrapperPlayer.java      | 82 +++++++++++++++++++
 .../common/AbstractWorldWrapper.java          |  6 ++
 5 files changed, 98 insertions(+), 16 deletions(-)
 create mode 100644 api/src/main/java/me/tofaa/entitylib/wrapper/WrapperPlayer.java

diff --git a/.idea/workspace.xml b/.idea/workspace.xml
index d305e06..4139f29 100644
--- a/.idea/workspace.xml
+++ b/.idea/workspace.xml
@@ -5,13 +5,11 @@
   </component>
   <component name="ChangeListManager">
     <list default="true" id="9d5d9b6f-43c8-41a4-bb42-a66ffc96c9b0" name="Changes" comment="">
-      <change afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/utils/Check.java" afterDir="false" />
-      <change afterPath="$PROJECT_DIR$/platforms/spigot/src/main/java/me/tofaa/entitylib/spigot/ExtraConversionUtil.java" afterDir="false" />
+      <change afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperPlayer.java" afterDir="false" />
       <change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
-      <change beforePath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/EntityLibAPI.java" beforeDir="false" afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/EntityLibAPI.java" afterDir="false" />
       <change beforePath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperEntity.java" beforeDir="false" afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperEntity.java" afterDir="false" />
-      <change beforePath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/wrapper/hologram/Hologram.java" beforeDir="false" afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/wrapper/hologram/Hologram.java" afterDir="false" />
-      <change beforePath="$PROJECT_DIR$/platforms/spigot/src/main/java/me/tofaa/entitylib/spigot/SpigotWorld.java" beforeDir="false" afterPath="$PROJECT_DIR$/platforms/spigot/src/main/java/me/tofaa/entitylib/spigot/SpigotWorld.java" afterDir="false" />
+      <change beforePath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperExperienceOrbEntity.java" beforeDir="false" afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperExperienceOrbEntity.java" afterDir="false" />
+      <change beforePath="$PROJECT_DIR$/common/src/main/java/me/tofaa/entitylib/common/AbstractWorldWrapper.java" beforeDir="false" afterPath="$PROJECT_DIR$/common/src/main/java/me/tofaa/entitylib/common/AbstractWorldWrapper.java" afterDir="false" />
     </list>
     <option name="SHOW_DIALOG" value="false" />
     <option name="HIGHLIGHT_CONFLICTS" value="true" />
@@ -296,6 +294,7 @@
       <workItem from="1706784821835" duration="7882000" />
       <workItem from="1706858181164" duration="925000" />
       <workItem from="1707159905372" duration="3391000" />
+      <workItem from="1707210065718" duration="1026000" />
     </task>
     <servers />
   </component>
diff --git a/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperEntity.java b/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperEntity.java
index ddc4fda..2402c85 100644
--- a/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperEntity.java
+++ b/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperEntity.java
@@ -28,12 +28,12 @@ public class WrapperEntity implements Tickable {
     private boolean ticking;
     private Location location;
     private Location preRidingLocation;
-    private Set<UUID> viewers;
+    private final Set<UUID> viewers;
     private boolean onGround;
     private boolean spawned;
     private Vector3d velocity;
     private int riding = -1;
-    private Set<Integer> passengers = new HashSet<>();
+    private final Set<Integer> passengers;
     private WorldWrapper<?> world;
 
     public WrapperEntity(int entityId, UUID uuid, EntityType entityType, EntityMeta entityMeta) {
@@ -43,10 +43,7 @@ public class WrapperEntity implements Tickable {
         this.entityMeta = entityMeta;
         this.ticking = true;
         this.viewers = new HashSet<>();
-    }
-
-    public boolean spawn(Location location) {
-        return spawn(null, location);
+        this.passengers = new HashSet<>();
     }
 
     public boolean spawn(WorldWrapper<?> world, Location location) {
@@ -125,10 +122,6 @@ public class WrapperEntity implements Tickable {
         teleport(null, location, onGround);
     }
 
-    public void teleport(@NotNull Location location) {
-        teleport(null, location, onGround);
-    }
-
     /**
      * Adds a viewer to the viewers set. The viewer will receive all packets and be informed of this addition
      * @param uuid the uuid of the user to add
diff --git a/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperExperienceOrbEntity.java b/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperExperienceOrbEntity.java
index c880847..27b38b8 100644
--- a/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperExperienceOrbEntity.java
+++ b/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperExperienceOrbEntity.java
@@ -25,7 +25,9 @@ public class WrapperExperienceOrbEntity extends WrapperEntity {
      *     This is an attempt to mimmick the vanilla behavior.
      * </p>
      */
-    public void updateSliding() {
+    @Override
+    public void tick(long time) {
+        super.tick(time);
         if (hasNoGravity()) {
             setVelocity(getVelocity().add(0, -0.3f, 0));
         }
diff --git a/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperPlayer.java b/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperPlayer.java
new file mode 100644
index 0000000..d7d1c57
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperPlayer.java
@@ -0,0 +1,82 @@
+package me.tofaa.entitylib.wrapper;
+
+import com.github.retrooper.packetevents.protocol.entity.type.EntityType;
+import com.github.retrooper.packetevents.protocol.player.*;
+import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerPlayerInfo;
+import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerPlayerInfoRemove;
+import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerPlayerInfoUpdate;
+import me.tofaa.entitylib.meta.EntityMeta;
+import net.kyori.adventure.text.Component;
+
+import java.util.List;
+
+public class WrapperPlayer extends WrapperLivingEntity {
+
+    private final UserProfile profile;
+    private GameMode gameMode = GameMode.CREATIVE;
+    private Component displayName;
+
+
+    public WrapperPlayer(UserProfile profile,  int entityId, EntityType entityType, EntityMeta entityMeta) {
+        super(entityId, profile.getUUID(), entityType, entityMeta);
+        this.profile = profile;
+    }
+
+
+    public void setGameMode(GameMode gameMode) {
+        this.gameMode = gameMode;
+        sendPacketsToViewers(new WrapperPlayServerPlayerInfo(
+                WrapperPlayServerPlayerInfo.Action.UPDATE_GAME_MODE,
+                new WrapperPlayServerPlayerInfo.PlayerData(displayName, profile, gameMode, null, -1)));
+    }
+
+    public void setDisplayName(Component displayName) {
+        this.displayName = displayName;
+        sendPacketsToViewers(new WrapperPlayServerPlayerInfo(
+                WrapperPlayServerPlayerInfo.Action.UPDATE_DISPLAY_NAME,
+                new WrapperPlayServerPlayerInfo.PlayerData(displayName, profile, gameMode, null, -1)));
+    }
+
+    public Component getDisplayName() {
+        return displayName;
+    }
+
+    public String getUsername() {
+        return profile.getName();
+    }
+
+    public List<TextureProperty> getTextureProperties() {
+        return profile.getTextureProperties();
+    }
+
+    public GameMode getGameMode() {
+        return gameMode;
+    }
+
+    @Override
+    public void addViewer(User user) {
+        super.addViewer(user);
+        user.sendPacket(createAddPacket());
+    }
+
+    @Override
+    public void removeViewer(User user) {
+        super.removeViewer(user);
+        user.sendPacket(createRemovePacket());
+    }
+
+    private WrapperPlayServerPlayerInfoUpdate createAddPacket() {
+        return new WrapperPlayServerPlayerInfoUpdate(
+                WrapperPlayServerPlayerInfoUpdate.Action.ADD_PLAYER,
+                new WrapperPlayServerPlayerInfoUpdate.PlayerInfo(
+                        profile,
+                        true, -1, gameMode, null, null
+                )
+        );
+    }
+
+    private WrapperPlayServerPlayerInfoRemove createRemovePacket() {
+        return new WrapperPlayServerPlayerInfoRemove(getUuid());
+    }
+
+}
diff --git a/common/src/main/java/me/tofaa/entitylib/common/AbstractWorldWrapper.java b/common/src/main/java/me/tofaa/entitylib/common/AbstractWorldWrapper.java
index 0bb678c..4cd4b0a 100644
--- a/common/src/main/java/me/tofaa/entitylib/common/AbstractWorldWrapper.java
+++ b/common/src/main/java/me/tofaa/entitylib/common/AbstractWorldWrapper.java
@@ -6,8 +6,11 @@ import com.github.retrooper.packetevents.protocol.world.Location;
 import me.tofaa.entitylib.EntityLib;
 import me.tofaa.entitylib.WorldWrapper;
 import me.tofaa.entitylib.meta.EntityMeta;
+import me.tofaa.entitylib.meta.projectile.ThrownExpBottleMeta;
 import me.tofaa.entitylib.meta.types.LivingEntityMeta;
+import me.tofaa.entitylib.meta.types.PlayerMeta;
 import me.tofaa.entitylib.wrapper.WrapperEntity;
+import me.tofaa.entitylib.wrapper.WrapperExperienceOrbEntity;
 import me.tofaa.entitylib.wrapper.WrapperLivingEntity;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
@@ -65,6 +68,9 @@ public abstract class AbstractWorldWrapper<W> implements WorldWrapper<W> {
         if (meta instanceof LivingEntityMeta) {
             e = new WrapperLivingEntity(entityId, uuid, entityType, meta);
         }
+        else if (meta instanceof ThrownExpBottleMeta) {
+            e = new WrapperExperienceOrbEntity(entityId, uuid, entityType, meta);
+        }
         else {
             e = new WrapperEntity(entityId, uuid, entityType, meta);
         }

From ad50de2caef9297efabea21be020ca907248a9cc Mon Sep 17 00:00:00 2001
From: Tofaa <82680183+Tofaa2@users.noreply.github.com>
Date: Tue, 6 Feb 2024 13:23:35 +0400
Subject: [PATCH 12/19] finish up world work

---
 .idea/workspace.xml                           |  8 +++-----
 .../java/me/tofaa/entitylib/WorldWrapper.java |  4 ++++
 .../entitylib/wrapper/WrapperPlayer.java      |  6 ++++--
 .../common/AbstractWorldWrapper.java          | 19 +++++++++++++++++++
 4 files changed, 30 insertions(+), 7 deletions(-)

diff --git a/.idea/workspace.xml b/.idea/workspace.xml
index 4139f29..5913b97 100644
--- a/.idea/workspace.xml
+++ b/.idea/workspace.xml
@@ -5,10 +5,8 @@
   </component>
   <component name="ChangeListManager">
     <list default="true" id="9d5d9b6f-43c8-41a4-bb42-a66ffc96c9b0" name="Changes" comment="">
-      <change afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperPlayer.java" afterDir="false" />
-      <change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
-      <change beforePath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperEntity.java" beforeDir="false" afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperEntity.java" afterDir="false" />
-      <change beforePath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperExperienceOrbEntity.java" beforeDir="false" afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperExperienceOrbEntity.java" afterDir="false" />
+      <change beforePath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/WorldWrapper.java" beforeDir="false" afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/WorldWrapper.java" afterDir="false" />
+      <change beforePath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperPlayer.java" beforeDir="false" afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperPlayer.java" afterDir="false" />
       <change beforePath="$PROJECT_DIR$/common/src/main/java/me/tofaa/entitylib/common/AbstractWorldWrapper.java" beforeDir="false" afterPath="$PROJECT_DIR$/common/src/main/java/me/tofaa/entitylib/common/AbstractWorldWrapper.java" afterDir="false" />
     </list>
     <option name="SHOW_DIALOG" value="false" />
@@ -294,7 +292,7 @@
       <workItem from="1706784821835" duration="7882000" />
       <workItem from="1706858181164" duration="925000" />
       <workItem from="1707159905372" duration="3391000" />
-      <workItem from="1707210065718" duration="1026000" />
+      <workItem from="1707210065718" duration="1328000" />
     </task>
     <servers />
   </component>
diff --git a/api/src/main/java/me/tofaa/entitylib/WorldWrapper.java b/api/src/main/java/me/tofaa/entitylib/WorldWrapper.java
index 7578c8f..b3d0ae3 100644
--- a/api/src/main/java/me/tofaa/entitylib/WorldWrapper.java
+++ b/api/src/main/java/me/tofaa/entitylib/WorldWrapper.java
@@ -1,11 +1,13 @@
 package me.tofaa.entitylib;
 
 import com.github.retrooper.packetevents.protocol.entity.type.EntityType;
+import com.github.retrooper.packetevents.protocol.player.UserProfile;
 import com.github.retrooper.packetevents.protocol.world.Dimension;
 import com.github.retrooper.packetevents.protocol.world.Location;
 import com.github.retrooper.packetevents.protocol.world.states.WrappedBlockState;
 import me.tofaa.entitylib.tick.TickContainer;
 import me.tofaa.entitylib.wrapper.WrapperEntity;
+import me.tofaa.entitylib.wrapper.WrapperPlayer;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
@@ -20,6 +22,8 @@ import java.util.UUID;
  */
 public interface WorldWrapper<W> {
 
+    @NotNull WrapperPlayer spawnPlayer(UserProfile profile, Location location);
+
     @NotNull <T extends WrapperEntity> T spawnEntity(@NotNull Class<T> wrapperClass, @NotNull EntityType entityType, @NotNull Location location);
 
     @NotNull WrapperEntity spawnEntity(@NotNull EntityType entityType, @NotNull Location location);
diff --git a/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperPlayer.java b/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperPlayer.java
index d7d1c57..7b35b3f 100644
--- a/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperPlayer.java
+++ b/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperPlayer.java
@@ -1,10 +1,12 @@
 package me.tofaa.entitylib.wrapper;
 
 import com.github.retrooper.packetevents.protocol.entity.type.EntityType;
+import com.github.retrooper.packetevents.protocol.entity.type.EntityTypes;
 import com.github.retrooper.packetevents.protocol.player.*;
 import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerPlayerInfo;
 import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerPlayerInfoRemove;
 import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerPlayerInfoUpdate;
+import me.tofaa.entitylib.EntityLib;
 import me.tofaa.entitylib.meta.EntityMeta;
 import net.kyori.adventure.text.Component;
 
@@ -17,8 +19,8 @@ public class WrapperPlayer extends WrapperLivingEntity {
     private Component displayName;
 
 
-    public WrapperPlayer(UserProfile profile,  int entityId, EntityType entityType, EntityMeta entityMeta) {
-        super(entityId, profile.getUUID(), entityType, entityMeta);
+    public WrapperPlayer(UserProfile profile, int entityId) {
+        super(entityId, profile.getUUID(), EntityTypes.PLAYER, EntityMeta.createMeta(entityId, EntityTypes.PLAYER));
         this.profile = profile;
     }
 
diff --git a/common/src/main/java/me/tofaa/entitylib/common/AbstractWorldWrapper.java b/common/src/main/java/me/tofaa/entitylib/common/AbstractWorldWrapper.java
index 4cd4b0a..b7a29fd 100644
--- a/common/src/main/java/me/tofaa/entitylib/common/AbstractWorldWrapper.java
+++ b/common/src/main/java/me/tofaa/entitylib/common/AbstractWorldWrapper.java
@@ -1,6 +1,8 @@
 package me.tofaa.entitylib.common;
 
 import com.github.retrooper.packetevents.protocol.entity.type.EntityType;
+import com.github.retrooper.packetevents.protocol.entity.type.EntityTypes;
+import com.github.retrooper.packetevents.protocol.player.UserProfile;
 import com.github.retrooper.packetevents.protocol.world.Dimension;
 import com.github.retrooper.packetevents.protocol.world.Location;
 import me.tofaa.entitylib.EntityLib;
@@ -12,6 +14,7 @@ import me.tofaa.entitylib.meta.types.PlayerMeta;
 import me.tofaa.entitylib.wrapper.WrapperEntity;
 import me.tofaa.entitylib.wrapper.WrapperExperienceOrbEntity;
 import me.tofaa.entitylib.wrapper.WrapperLivingEntity;
+import me.tofaa.entitylib.wrapper.WrapperPlayer;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
@@ -37,6 +40,22 @@ public abstract class AbstractWorldWrapper<W> implements WorldWrapper<W> {
         this.entitiesById = new ConcurrentHashMap<>();
     }
 
+    @Override
+    public @NotNull WrapperPlayer spawnPlayer(UserProfile profile, Location location) {
+        if (getEntity(profile.getUUID()) != null) {
+            throw new IllegalArgumentException("Entity with UUID " + profile.getUUID() + " already exists in this world.");
+        }
+
+        int id = EntityLib.getPlatform().getEntityIdProvider().provide(profile.getUUID(), EntityTypes.PLAYER);
+        while (entitiesById.containsKey(id)) {
+            id = EntityLib.getPlatform().getEntityIdProvider().provide(profile.getUUID(), EntityTypes.PLAYER);
+        }
+        WrapperPlayer player = new WrapperPlayer(profile, id);
+        player.spawn(this, location);
+        entities.put(player.getUuid(), player);
+        entitiesById.put(player.getEntityId(), player);
+        return player;
+    }
 
     @Override
     public <T extends WrapperEntity> @NotNull T spawnEntity(@NotNull T entity, @NotNull Location location) {

From 2d76a9eac8f8d4a1c393c072ac421ea964077dcb Mon Sep 17 00:00:00 2001
From: Tofaa <82680183+Tofaa2@users.noreply.github.com>
Date: Tue, 6 Feb 2024 21:44:02 +0400
Subject: [PATCH 13/19] Introduce changes notification for meta

Introduces a system to avoid spam sending metadata packets by stopping sending, changing the metadata, then sending it all at once
---
 .idea/workspace.xml                           |  20 +-
 .../java/me/tofaa/entitylib/EntityLibAPI.java |  22 +
 .../me/tofaa/entitylib/meta/EntityMeta.java   |  41 +-
 .../entitylib/meta/MetaOffsetConverter.java   | 580 ++++++++++++------
 .../me/tofaa/entitylib/meta/Metadata.java     |  73 ++-
 .../entitylib/wrapper/WrapperEntity.java      |   2 +-
 .../java/me/tofaa/entitylib/codegen/Main.java |   8 +-
 .../src/main/resources/offset-calculator.json | 238 ++++++-
 .../common/AbstractEntityLibAPI.java          |  21 +
 .../common/AbstractWorldWrapper.java          |   3 +
 .../spigot/SpigotEntityLibPlatform.java       |   2 +-
 .../testentitylib/TestEntityLibPlugin.java    |  28 +-
 test-plugin/src/main/resources/plugin.yml     |  12 +-
 13 files changed, 792 insertions(+), 258 deletions(-)

diff --git a/.idea/workspace.xml b/.idea/workspace.xml
index 5913b97..3f14df4 100644
--- a/.idea/workspace.xml
+++ b/.idea/workspace.xml
@@ -5,9 +5,19 @@
   </component>
   <component name="ChangeListManager">
     <list default="true" id="9d5d9b6f-43c8-41a4-bb42-a66ffc96c9b0" name="Changes" comment="">
-      <change beforePath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/WorldWrapper.java" beforeDir="false" afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/WorldWrapper.java" afterDir="false" />
-      <change beforePath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperPlayer.java" beforeDir="false" afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperPlayer.java" afterDir="false" />
+      <change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
+      <change beforePath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/EntityLibAPI.java" beforeDir="false" afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/EntityLibAPI.java" afterDir="false" />
+      <change beforePath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/meta/EntityMeta.java" beforeDir="false" afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/meta/EntityMeta.java" afterDir="false" />
+      <change beforePath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/meta/MetaOffsetConverter.java" beforeDir="false" afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/meta/MetaOffsetConverter.java" afterDir="false" />
+      <change beforePath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/meta/Metadata.java" beforeDir="false" afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/meta/Metadata.java" afterDir="false" />
+      <change beforePath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperEntity.java" beforeDir="false" afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperEntity.java" afterDir="false" />
+      <change beforePath="$PROJECT_DIR$/code-gen/src/main/java/me/tofaa/entitylib/codegen/Main.java" beforeDir="false" afterPath="$PROJECT_DIR$/code-gen/src/main/java/me/tofaa/entitylib/codegen/Main.java" afterDir="false" />
+      <change beforePath="$PROJECT_DIR$/code-gen/src/main/resources/offset-calculator.json" beforeDir="false" afterPath="$PROJECT_DIR$/code-gen/src/main/resources/offset-calculator.json" afterDir="false" />
+      <change beforePath="$PROJECT_DIR$/common/src/main/java/me/tofaa/entitylib/common/AbstractEntityLibAPI.java" beforeDir="false" afterPath="$PROJECT_DIR$/common/src/main/java/me/tofaa/entitylib/common/AbstractEntityLibAPI.java" afterDir="false" />
       <change beforePath="$PROJECT_DIR$/common/src/main/java/me/tofaa/entitylib/common/AbstractWorldWrapper.java" beforeDir="false" afterPath="$PROJECT_DIR$/common/src/main/java/me/tofaa/entitylib/common/AbstractWorldWrapper.java" afterDir="false" />
+      <change beforePath="$PROJECT_DIR$/platforms/spigot/src/main/java/me/tofaa/entitylib/spigot/SpigotEntityLibPlatform.java" beforeDir="false" afterPath="$PROJECT_DIR$/platforms/spigot/src/main/java/me/tofaa/entitylib/spigot/SpigotEntityLibPlatform.java" afterDir="false" />
+      <change beforePath="$PROJECT_DIR$/test-plugin/src/main/java/me/tofaa/testentitylib/TestEntityLibPlugin.java" beforeDir="false" afterPath="$PROJECT_DIR$/test-plugin/src/main/java/me/tofaa/testentitylib/TestEntityLibPlugin.java" afterDir="false" />
+      <change beforePath="$PROJECT_DIR$/test-plugin/src/main/resources/plugin.yml" beforeDir="false" afterPath="$PROJECT_DIR$/test-plugin/src/main/resources/plugin.yml" afterDir="false" />
     </list>
     <option name="SHOW_DIALOG" value="false" />
     <option name="HIGHLIGHT_CONFLICTS" value="true" />
@@ -95,6 +105,7 @@
     &quot;Gradle.EntityLib [dependencies].executor&quot;: &quot;Run&quot;,
     &quot;Gradle.EntityLib:code-gen [:code-gen:Main.main()].executor&quot;: &quot;Run&quot;,
     &quot;Gradle.EntityLib:test-plugin [runServer].executor&quot;: &quot;Run&quot;,
+    &quot;Gradle.EntityLib:test-plugin [shadowJar].executor&quot;: &quot;Run&quot;,
     &quot;Repository.Attach.Annotations&quot;: &quot;false&quot;,
     &quot;Repository.Attach.JavaDocs&quot;: &quot;false&quot;,
     &quot;Repository.Attach.Sources&quot;: &quot;false&quot;,
@@ -230,10 +241,10 @@
     <recent_temporary>
       <list>
         <item itemvalue="Gradle.EntityLib:test-plugin [runServer]" />
+        <item itemvalue="Gradle.EntityLib:test-plugin [shadowJar]" />
         <item itemvalue="Application.Main" />
         <item itemvalue="Gradle.EntityLib [dependencies]" />
         <item itemvalue="Gradle.PE-EntityMeta [compileTestJava]" />
-        <item itemvalue="Gradle.EntityLib:test-plugin [shadowJar]" />
       </list>
     </recent_temporary>
   </component>
@@ -292,7 +303,8 @@
       <workItem from="1706784821835" duration="7882000" />
       <workItem from="1706858181164" duration="925000" />
       <workItem from="1707159905372" duration="3391000" />
-      <workItem from="1707210065718" duration="1328000" />
+      <workItem from="1707210065718" duration="4823000" />
+      <workItem from="1707219870641" duration="4868000" />
     </task>
     <servers />
   </component>
diff --git a/api/src/main/java/me/tofaa/entitylib/EntityLibAPI.java b/api/src/main/java/me/tofaa/entitylib/EntityLibAPI.java
index 5276ee7..d2227bf 100644
--- a/api/src/main/java/me/tofaa/entitylib/EntityLibAPI.java
+++ b/api/src/main/java/me/tofaa/entitylib/EntityLibAPI.java
@@ -3,7 +3,9 @@ package me.tofaa.entitylib;
 import com.github.retrooper.packetevents.PacketEventsAPI;
 import me.tofaa.entitylib.tick.TickContainer;
 import me.tofaa.entitylib.wrapper.WrapperEntity;
+import org.jetbrains.annotations.ApiStatus;
 import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
 
 import java.util.Collection;
 
@@ -26,6 +28,26 @@ public interface EntityLibAPI<W, T> {
 
     void onEnable();
 
+    /**
+     * Attempts to search and find an entity across all wrapped worlds. This only works on EntityLib entities.
+     * @param entityId the entity id of the entity
+     * @return the entity if one is found, null otherwise.
+     */
+    @Nullable WrapperEntity findEntity(int entityId);
+
+    /**
+     * Mainly internal method to register the {@link WrapperEntity} to EntitLib cache, all {@link WorldWrapper}'s do this automatically
+     * @param entity
+     */
+    @ApiStatus.Internal
+    void globalRegisterEntity(@NotNull WrapperEntity entity);
+
+    /**
+     * Mainly internal method to unregister the {@link WrapperEntity} to EntitLib cache, all {@link WorldWrapper}'s do this automatically
+     * @param entity
+     */
+    void globalUnregisterEntity(@NotNull WrapperEntity entity);
+
 
     /**
      * Creates a wrapped world for the platform specific world.
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/EntityMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/EntityMeta.java
index 5150aa5..0957521 100644
--- a/api/src/main/java/me/tofaa/entitylib/meta/EntityMeta.java
+++ b/api/src/main/java/me/tofaa/entitylib/meta/EntityMeta.java
@@ -19,7 +19,8 @@ import java.util.List;
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.function.BiFunction;
-import java.util.function.Function;
+
+import static me.tofaa.entitylib.meta.MetaOffsetConverter.EntityMetaOffsets.*;
 
 public class EntityMeta implements EntityMetadataProvider {
 
@@ -65,6 +66,14 @@ public class EntityMeta implements EntityMetadataProvider {
         this.metadata = metadata;
     }
 
+    public void setNotifyAboutChanges(boolean notifyAboutChanges) {
+        metadata.setNotifyAboutChanges(notifyAboutChanges);
+    }
+
+    public boolean isNotifyingChanges() {
+        return metadata.isNotifyingChanges();
+    }
+
     public boolean isOnFire() {
         return getMaskBit(OFFSET, ON_FIRE_BIT);
     }
@@ -122,59 +131,59 @@ public class EntityMeta implements EntityMetadataProvider {
     }
 
     public short getAirTicks() {
-        return this.metadata.getIndex((byte) 1, (short) 300);
+        return this.metadata.getIndex(airTicksOffset(), (short) 300);
     }
 
     public void setAirTicks(short value) {
-        this.metadata.setIndex((byte) 1, EntityDataTypes.SHORT, value);
+        this.metadata.setIndex(airTicksOffset(), EntityDataTypes.SHORT, value);
     }
 
     public Component getCustomName() {
-        return this.metadata.getIndex(offset(OFFSET, 2), null);
+        return this.metadata.getIndex(customNameOffset(), null);
     }
 
     public void setCustomName(Component value) {
-        this.metadata.setIndex(offset(OFFSET, 2), EntityDataTypes.ADV_COMPONENT, value);
+        this.metadata.setIndex(customNameOffset(), EntityDataTypes.ADV_COMPONENT, value);
     }
 
     public boolean isCustomNameVisible() {
-        return this.metadata.getIndex(offset(OFFSET, 3), false);
+        return this.metadata.getIndex(customNameVisibleOffset(), false);
     }
 
     public void setCustomNameVisible(boolean value) {
-        this.metadata.setIndex(offset(OFFSET, 3), EntityDataTypes.BOOLEAN, value);
+        this.metadata.setIndex(customNameVisibleOffset(), EntityDataTypes.BOOLEAN, value);
     }
 
     public boolean isSilent() {
-        return this.metadata.getIndex((byte) 4, false);
+        return this.metadata.getIndex(silentOffset(), false);
     }
 
     public void setSilent(boolean value) {
-        this.metadata.setIndex((byte) 4, EntityDataTypes.BOOLEAN, value);
+        this.metadata.setIndex(silentOffset(), EntityDataTypes.BOOLEAN, value);
     }
 
-    public boolean isHasNoGravity() {
-        return this.metadata.getIndex(offset(OFFSET, 5), true);
+    public boolean hasNoGravity() {
+        return this.metadata.getIndex(hasNoGravityOffset(), true);
     }
 
     public void setHasNoGravity(boolean value) {
-        this.metadata.setIndex(offset(OFFSET, 5), EntityDataTypes.BOOLEAN, value);
+        this.metadata.setIndex(hasNoGravityOffset(), EntityDataTypes.BOOLEAN, value);
     }
 
     public EntityPose getPose() {
-        return this.metadata.getIndex(offset(OFFSET, 6), EntityPose.STANDING);
+        return this.metadata.getIndex(poseOffset(), EntityPose.STANDING);
     }
 
     public void setPose(EntityPose value) {
-        this.metadata.setIndex(offset(OFFSET, 6), EntityDataTypes.ENTITY_POSE, value);
+        this.metadata.setIndex(poseOffset(), EntityDataTypes.ENTITY_POSE, value);
     }
 
     public int getTicksFrozenInPowderedSnow() {
-        return this.metadata.getIndex(offset(OFFSET, 7), 0);
+        return this.metadata.getIndex(ticksFrozenInPowderedSnowOffset(), 0);
     }
 
     public void setTicksFrozenInPowderedSnow(int value) {
-        this.metadata.setIndex(offset(OFFSET, 7), EntityDataTypes.INT, value);
+        this.metadata.setIndex(ticksFrozenInPowderedSnowOffset(), EntityDataTypes.INT, value);
     }
 
     public WrapperPlayServerEntityMetadata createPacket() {
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/MetaOffsetConverter.java b/api/src/main/java/me/tofaa/entitylib/meta/MetaOffsetConverter.java
index 0848013..aaae37b 100644
--- a/api/src/main/java/me/tofaa/entitylib/meta/MetaOffsetConverter.java
+++ b/api/src/main/java/me/tofaa/entitylib/meta/MetaOffsetConverter.java
@@ -10,250 +10,426 @@ import org.jetbrains.annotations.ApiStatus;
 @SuppressWarnings("unused")
 public final class MetaOffsetConverter {
     private MetaOffsetConverter() {
+
     }
 
-    public static byte airTicksOffset() {
-        int protocolVersion = getApi().getPacketEvents().getServerManager().getVersion().getProtocolVersion();
-        if (protocolVersion >= 47 && protocolVersion <= 47) {
-            return 1;
+    public static final class EntityMetaOffsets {
+        public static byte airTicksOffset() {
+            int protocolVersion = getApi().getPacketEvents().getServerManager().getVersion().getProtocolVersion();
+            if (protocolVersion >= 47 && protocolVersion <= 765) {
+                return 1;
+            }
+            throw new RuntimeException("Unknown protocol version for this method");
+        }
+
+        public static byte customNameOffset() {
+            int protocolVersion = getApi().getPacketEvents().getServerManager().getVersion().getProtocolVersion();
+            if (protocolVersion >= 47 && protocolVersion <= 765) {
+                return 2;
+            }
+            throw new RuntimeException("Unknown protocol version for this method");
+        }
+
+        public static byte customNameVisibleOffset() {
+            int protocolVersion = getApi().getPacketEvents().getServerManager().getVersion().getProtocolVersion();
+            if (protocolVersion >= 47 && protocolVersion <= 765) {
+                return 3;
+            }
+            throw new RuntimeException("Unknown protocol version for this method");
+        }
+
+        public static byte silentOffset() {
+            int protocolVersion = getApi().getPacketEvents().getServerManager().getVersion().getProtocolVersion();
+            if (protocolVersion >= 47 && protocolVersion <= 765) {
+                return 4;
+            }
+            throw new RuntimeException("Unknown protocol version for this method");
+        }
+
+        public static byte hasNoGravityOffset() {
+            int protocolVersion = getApi().getPacketEvents().getServerManager().getVersion().getProtocolVersion();
+            if (protocolVersion >= 47 && protocolVersion <= 765) {
+                return 5;
+            }
+            throw new RuntimeException("Unknown protocol version for this method");
+        }
+
+        public static byte poseOffset() {
+            int protocolVersion = getApi().getPacketEvents().getServerManager().getVersion().getProtocolVersion();
+            if (protocolVersion >= 47 && protocolVersion <= 765) {
+                return 6;
+            }
+            throw new RuntimeException("Unknown protocol version for this method");
+        }
+
+        public static byte ticksFrozenInPowderedSnowOffset() {
+            int protocolVersion = getApi().getPacketEvents().getServerManager().getVersion().getProtocolVersion();
+            if (protocolVersion >= 47 && protocolVersion <= 765) {
+                return 7;
+            }
+            throw new RuntimeException("Unknown protocol version for this method");
         }
-        throw new RuntimeException("Unknown protocol version for this method");
     }
 
-    public static byte customNameOffset() {
-        int protocolVersion = getApi().getPacketEvents().getServerManager().getVersion().getProtocolVersion();
-        if (protocolVersion >= 47 && protocolVersion <= 765) {
-            return 2;
+    public static final class AbstractDisplayMetaOffsets {
+        public static byte interpolationDelayOffset() {
+            int protocolVersion = getApi().getPacketEvents().getServerManager().getVersion().getProtocolVersion();
+            if (protocolVersion >= 762 && protocolVersion <= 765) {
+                return 8;
+            }
+            throw new RuntimeException("Unknown protocol version for this method");
+        }
+
+        public static byte transformationDurationOffset() {
+            int protocolVersion = getApi().getPacketEvents().getServerManager().getVersion().getProtocolVersion();
+            if (protocolVersion >= 762 && protocolVersion <= 765) {
+                return 9;
+            }
+            throw new RuntimeException("Unknown protocol version for this method");
+        }
+
+        public static byte positionRotationInterpolationDurationOffset() {
+            int protocolVersion = getApi().getPacketEvents().getServerManager().getVersion().getProtocolVersion();
+            if (protocolVersion >= 764 && protocolVersion <= 765) {
+                return 10;
+            }
+            throw new RuntimeException("Unknown protocol version for this method");
+        }
+
+        public static byte translationOffset() {
+            int protocolVersion = getApi().getPacketEvents().getServerManager().getVersion().getProtocolVersion();
+            if (protocolVersion >= 764 && protocolVersion <= 765) {
+                return 11;
+            }
+            if (protocolVersion >= 762 && protocolVersion <= 763) {
+                return 10;
+            }
+            throw new RuntimeException("Unknown protocol version for this method");
+        }
+
+        public static byte scaleOffset() {
+            int protocolVersion = getApi().getPacketEvents().getServerManager().getVersion().getProtocolVersion();
+            if (protocolVersion >= 764 && protocolVersion <= 765) {
+                return 12;
+            }
+            if (protocolVersion >= 762 && protocolVersion <= 763) {
+                return 11;
+            }
+            throw new RuntimeException("Unknown protocol version for this method");
+        }
+
+        public static byte leftRotationOffset() {
+            int protocolVersion = getApi().getPacketEvents().getServerManager().getVersion().getProtocolVersion();
+            if (protocolVersion >= 764 && protocolVersion <= 765) {
+                return 13;
+            }
+            if (protocolVersion >= 762 && protocolVersion <= 763) {
+                return 12;
+            }
+            throw new RuntimeException("Unknown protocol version for this method");
+        }
+
+        public static byte rightRotationOffset() {
+            int protocolVersion = getApi().getPacketEvents().getServerManager().getVersion().getProtocolVersion();
+            if (protocolVersion >= 764 && protocolVersion <= 765) {
+                return 14;
+            }
+            if (protocolVersion >= 762 && protocolVersion <= 763) {
+                return 13;
+            }
+            throw new RuntimeException("Unknown protocol version for this method");
+        }
+
+        public static byte billboardConstraintsOffset() {
+            int protocolVersion = getApi().getPacketEvents().getServerManager().getVersion().getProtocolVersion();
+            if (protocolVersion >= 764 && protocolVersion <= 765) {
+                return 15;
+            }
+            if (protocolVersion >= 762 && protocolVersion <= 763) {
+                return 14;
+            }
+            throw new RuntimeException("Unknown protocol version for this method");
+        }
+
+        public static byte brightnessOverrideOffset() {
+            int protocolVersion = getApi().getPacketEvents().getServerManager().getVersion().getProtocolVersion();
+            if (protocolVersion >= 764 && protocolVersion <= 765) {
+                return 16;
+            }
+            if (protocolVersion >= 762 && protocolVersion <= 763) {
+                return 15;
+            }
+            throw new RuntimeException("Unknown protocol version for this method");
+        }
+
+        public static byte viewRangeOffset() {
+            int protocolVersion = getApi().getPacketEvents().getServerManager().getVersion().getProtocolVersion();
+            if (protocolVersion >= 764 && protocolVersion <= 765) {
+                return 17;
+            }
+            if (protocolVersion >= 762 && protocolVersion <= 763) {
+                return 16;
+            }
+            throw new RuntimeException("Unknown protocol version for this method");
+        }
+
+        public static byte shadowRadiusOffset() {
+            int protocolVersion = getApi().getPacketEvents().getServerManager().getVersion().getProtocolVersion();
+            if (protocolVersion >= 764 && protocolVersion <= 765) {
+                return 18;
+            }
+            if (protocolVersion >= 762 && protocolVersion <= 763) {
+                return 17;
+            }
+            throw new RuntimeException("Unknown protocol version for this method");
+        }
+
+        public static byte shadowStrengthOffset() {
+            int protocolVersion = getApi().getPacketEvents().getServerManager().getVersion().getProtocolVersion();
+            if (protocolVersion >= 764 && protocolVersion <= 765) {
+                return 19;
+            }
+            if (protocolVersion >= 762 && protocolVersion <= 763) {
+                return 18;
+            }
+            throw new RuntimeException("Unknown protocol version for this method");
+        }
+
+        public static byte widthOffset() {
+            int protocolVersion = getApi().getPacketEvents().getServerManager().getVersion().getProtocolVersion();
+            if (protocolVersion >= 764 && protocolVersion <= 765) {
+                return 20;
+            }
+            if (protocolVersion >= 762 && protocolVersion <= 763) {
+                return 19;
+            }
+            throw new RuntimeException("Unknown protocol version for this method");
+        }
+
+        public static byte heightOffset() {
+            int protocolVersion = getApi().getPacketEvents().getServerManager().getVersion().getProtocolVersion();
+            if (protocolVersion >= 764 && protocolVersion <= 765) {
+                return 21;
+            }
+            if (protocolVersion >= 762 && protocolVersion <= 763) {
+                return 20;
+            }
+            throw new RuntimeException("Unknown protocol version for this method");
+        }
+
+        public static byte glowColorOverrideOffset() {
+            int protocolVersion = getApi().getPacketEvents().getServerManager().getVersion().getProtocolVersion();
+            if (protocolVersion >= 764 && protocolVersion <= 765) {
+                return 22;
+            }
+            if (protocolVersion >= 762 && protocolVersion <= 763) {
+                return 21;
+            }
+            throw new RuntimeException("Unknown protocol version for this method");
         }
-        throw new RuntimeException("Unknown protocol version for this method");
     }
 
-    public static byte customNameVisibleOffset() {
-        int protocolVersion = getApi().getPacketEvents().getServerManager().getVersion().getProtocolVersion();
-        if (protocolVersion >= 47 && protocolVersion <= 765) {
-            return 3;
+    public static final class BlockDisplayMetaOffsets {
+        public static byte blockIdOffset() {
+            int protocolVersion = getApi().getPacketEvents().getServerManager().getVersion().getProtocolVersion();
+            if (protocolVersion >= 764 && protocolVersion <= 765) {
+                return 23;
+            }
+            if (protocolVersion >= 762 && protocolVersion <= 763) {
+                return 22;
+            }
+            throw new RuntimeException("Unknown protocol version for this method");
         }
-        throw new RuntimeException("Unknown protocol version for this method");
     }
 
-    public static byte silentOffset() {
-        int protocolVersion = getApi().getPacketEvents().getServerManager().getVersion().getProtocolVersion();
-        if (protocolVersion >= 47 && protocolVersion <= 765) {
-            return 4;
+    public static final class ItemDisplayMetaOffsets {
+        public static byte itemOffset() {
+            int protocolVersion = getApi().getPacketEvents().getServerManager().getVersion().getProtocolVersion();
+            if (protocolVersion >= 764 && protocolVersion <= 765) {
+                return 24;
+            }
+            if (protocolVersion >= 762 && protocolVersion <= 763) {
+                return 23;
+            }
+            throw new RuntimeException("Unknown protocol version for this method");
+        }
+
+        public static byte displayTypeOffset() {
+            int protocolVersion = getApi().getPacketEvents().getServerManager().getVersion().getProtocolVersion();
+            if (protocolVersion >= 764 && protocolVersion <= 765) {
+                return 25;
+            }
+            if (protocolVersion >= 762 && protocolVersion <= 763) {
+                return 24;
+            }
+            throw new RuntimeException("Unknown protocol version for this method");
         }
-        throw new RuntimeException("Unknown protocol version for this method");
     }
 
-    public static byte hasNoGravityOffset() {
-        int protocolVersion = getApi().getPacketEvents().getServerManager().getVersion().getProtocolVersion();
-        if (protocolVersion >= 47 && protocolVersion <= 765) {
-            return 5;
+    public static final class TextDisplayMetaOffsets {
+        public static byte textOffset() {
+            int protocolVersion = getApi().getPacketEvents().getServerManager().getVersion().getProtocolVersion();
+            if (protocolVersion >= 764 && protocolVersion <= 765) {
+                return 26;
+            }
+            if (protocolVersion >= 762 && protocolVersion <= 763) {
+                return 25;
+            }
+            throw new RuntimeException("Unknown protocol version for this method");
         }
-        throw new RuntimeException("Unknown protocol version for this method");
-    }
 
-    public static byte poseOffset() {
-        int protocolVersion = getApi().getPacketEvents().getServerManager().getVersion().getProtocolVersion();
-        if (protocolVersion >= 47 && protocolVersion <= 765) {
-            return 6;
+        public static byte textColorOffset() {
+            int protocolVersion = getApi().getPacketEvents().getServerManager().getVersion().getProtocolVersion();
+            if (protocolVersion >= 764 && protocolVersion <= 765) {
+                return 27;
+            }
+            if (protocolVersion >= 762 && protocolVersion <= 763) {
+                return 26;
+            }
+            throw new RuntimeException("Unknown protocol version for this method");
         }
-        throw new RuntimeException("Unknown protocol version for this method");
-    }
 
-    public static byte ticksFrozenInPowderedSnowOffset() {
-        int protocolVersion = getApi().getPacketEvents().getServerManager().getVersion().getProtocolVersion();
-        if (protocolVersion >= 47 && protocolVersion <= 765) {
-            return 7;
+        public static byte textBackgroundColorOffset() {
+            int protocolVersion = getApi().getPacketEvents().getServerManager().getVersion().getProtocolVersion();
+            if (protocolVersion >= 764 && protocolVersion <= 765) {
+                return 28;
+            }
+            if (protocolVersion >= 762 && protocolVersion <= 763) {
+                return 27;
+            }
+            throw new RuntimeException("Unknown protocol version for this method");
         }
-        throw new RuntimeException("Unknown protocol version for this method");
-    }
 
-    public static byte interpolationDelayOffset() {
-        int protocolVersion = getApi().getPacketEvents().getServerManager().getVersion().getProtocolVersion();
-        if (protocolVersion >= 762 && protocolVersion <= 765) {
-            return 8;
+        public static byte textBackgroundOffset() {
+            int protocolVersion = getApi().getPacketEvents().getServerManager().getVersion().getProtocolVersion();
+            if (protocolVersion >= 764 && protocolVersion <= 765) {
+                return 29;
+            }
+            if (protocolVersion >= 762 && protocolVersion <= 763) {
+                return 28;
+            }
+            throw new RuntimeException("Unknown protocol version for this method");
         }
-        throw new RuntimeException("Unknown protocol version for this method");
-    }
 
-    public static byte transformationDurationOffset() {
-        int protocolVersion = getApi().getPacketEvents().getServerManager().getVersion().getProtocolVersion();
-        if (protocolVersion >= 762 && protocolVersion <= 765) {
-            return 9;
+        public static byte textScaleOffset() {
+            int protocolVersion = getApi().getPacketEvents().getServerManager().getVersion().getProtocolVersion();
+            if (protocolVersion >= 764 && protocolVersion <= 765) {
+                return 30;
+            }
+            if (protocolVersion >= 762 && protocolVersion <= 763) {
+                return 29;
+            }
+            throw new RuntimeException("Unknown protocol version for this method");
         }
-        throw new RuntimeException("Unknown protocol version for this method");
-    }
 
-    public static byte positionRotationInterpolationDurationOffset() {
-        int protocolVersion = getApi().getPacketEvents().getServerManager().getVersion().getProtocolVersion();
-        if (protocolVersion >= 764 && protocolVersion <= 765) {
-            return 10;
+        public static byte textAlignmentOffset() {
+            int protocolVersion = getApi().getPacketEvents().getServerManager().getVersion().getProtocolVersion();
+            if (protocolVersion >= 764 && protocolVersion <= 765) {
+                return 31;
+            }
+            if (protocolVersion >= 762 && protocolVersion <= 763) {
+                return 30;
+            }
+            throw new RuntimeException("Unknown protocol version for this method");
         }
-        throw new RuntimeException("Unknown protocol version for this method");
-    }
 
-    public static byte translationOffset() {
-        int protocolVersion = getApi().getPacketEvents().getServerManager().getVersion().getProtocolVersion();
-        if (protocolVersion >= 764 && protocolVersion <= 765) {
-            return 11;
+        public static byte lineWidthOffset() {
+            int protocolVersion = getApi().getPacketEvents().getServerManager().getVersion().getProtocolVersion();
+            if (protocolVersion >= 764 && protocolVersion <= 765) {
+                return 32;
+            }
+            if (protocolVersion >= 762 && protocolVersion <= 763) {
+                return 31;
+            }
+            throw new RuntimeException("Unknown protocol version for this method");
         }
-        if (protocolVersion >= 762 && protocolVersion <= 763) {
-            return 10;
-        }
-        throw new RuntimeException("Unknown protocol version for this method");
-    }
 
-    public static byte scaleOffset() {
-        int protocolVersion = getApi().getPacketEvents().getServerManager().getVersion().getProtocolVersion();
-        if (protocolVersion >= 764 && protocolVersion <= 765) {
-            return 12;
+        public static byte backgroundColorOffset() {
+            int protocolVersion = getApi().getPacketEvents().getServerManager().getVersion().getProtocolVersion();
+            if (protocolVersion >= 764 && protocolVersion <= 765) {
+                return 33;
+            }
+            if (protocolVersion >= 762 && protocolVersion <= 763) {
+                return 32;
+            }
+            throw new RuntimeException("Unknown protocol version for this method");
         }
-        if (protocolVersion >= 762 && protocolVersion <= 763) {
-            return 11;
-        }
-        throw new RuntimeException("Unknown protocol version for this method");
-    }
 
-    public static byte leftRotationOffset() {
-        int protocolVersion = getApi().getPacketEvents().getServerManager().getVersion().getProtocolVersion();
-        if (protocolVersion >= 764 && protocolVersion <= 765) {
-            return 13;
+        public static byte textOpacityOffset() {
+            int protocolVersion = getApi().getPacketEvents().getServerManager().getVersion().getProtocolVersion();
+            if (protocolVersion >= 764 && protocolVersion <= 765) {
+                return 34;
+            }
+            if (protocolVersion >= 762 && protocolVersion <= 763) {
+                return 33;
+            }
+            throw new RuntimeException("Unknown protocol version for this method");
         }
-        if (protocolVersion >= 762 && protocolVersion <= 763) {
-            return 12;
-        }
-        throw new RuntimeException("Unknown protocol version for this method");
-    }
 
-    public static byte rightRotationOffset() {
-        int protocolVersion = getApi().getPacketEvents().getServerManager().getVersion().getProtocolVersion();
-        if (protocolVersion >= 764 && protocolVersion <= 765) {
-            return 14;
+        public static byte shadowOffset() {
+            int protocolVersion = getApi().getPacketEvents().getServerManager().getVersion().getProtocolVersion();
+            if (protocolVersion >= 764 && protocolVersion <= 765) {
+                return 35;
+            }
+            if (protocolVersion >= 762 && protocolVersion <= 763) {
+                return 34;
+            }
+            throw new RuntimeException("Unknown protocol version for this method");
         }
-        if (protocolVersion >= 762 && protocolVersion <= 763) {
-            return 13;
-        }
-        throw new RuntimeException("Unknown protocol version for this method");
-    }
 
-    public static byte billboardConstraintsOffset() {
-        int protocolVersion = getApi().getPacketEvents().getServerManager().getVersion().getProtocolVersion();
-        if (protocolVersion >= 764 && protocolVersion <= 765) {
-            return 15;
+        public static byte seeThroughOffset() {
+            int protocolVersion = getApi().getPacketEvents().getServerManager().getVersion().getProtocolVersion();
+            if (protocolVersion >= 764 && protocolVersion <= 765) {
+                return 36;
+            }
+            if (protocolVersion >= 762 && protocolVersion <= 763) {
+                return 35;
+            }
+            throw new RuntimeException("Unknown protocol version for this method");
         }
-        if (protocolVersion >= 762 && protocolVersion <= 763) {
-            return 14;
-        }
-        throw new RuntimeException("Unknown protocol version for this method");
-    }
 
-    public static byte brightnessOverrideOffset() {
-        int protocolVersion = getApi().getPacketEvents().getServerManager().getVersion().getProtocolVersion();
-        if (protocolVersion >= 764 && protocolVersion <= 765) {
-            return 16;
+        public static byte useDefaultBackgroundOffset() {
+            int protocolVersion = getApi().getPacketEvents().getServerManager().getVersion().getProtocolVersion();
+            if (protocolVersion >= 764 && protocolVersion <= 765) {
+                return 37;
+            }
+            if (protocolVersion >= 762 && protocolVersion <= 763) {
+                return 36;
+            }
+            throw new RuntimeException("Unknown protocol version for this method");
         }
-        if (protocolVersion >= 762 && protocolVersion <= 763) {
-            return 15;
-        }
-        throw new RuntimeException("Unknown protocol version for this method");
-    }
 
-    public static byte viewRangeOffset() {
-        int protocolVersion = getApi().getPacketEvents().getServerManager().getVersion().getProtocolVersion();
-        if (protocolVersion >= 764 && protocolVersion <= 765) {
-            return 17;
+        public static byte allighnLeftOffset() {
+            int protocolVersion = getApi().getPacketEvents().getServerManager().getVersion().getProtocolVersion();
+            if (protocolVersion >= 764 && protocolVersion <= 765) {
+                return 38;
+            }
+            if (protocolVersion >= 762 && protocolVersion <= 763) {
+                return 37;
+            }
+            throw new RuntimeException("Unknown protocol version for this method");
         }
-        if (protocolVersion >= 762 && protocolVersion <= 763) {
-            return 16;
-        }
-        throw new RuntimeException("Unknown protocol version for this method");
-    }
 
-    public static byte shadowRadiusOffset() {
-        int protocolVersion = getApi().getPacketEvents().getServerManager().getVersion().getProtocolVersion();
-        if (protocolVersion >= 764 && protocolVersion <= 765) {
-            return 18;
+        public static byte allighnRightOffset() {
+            int protocolVersion = getApi().getPacketEvents().getServerManager().getVersion().getProtocolVersion();
+            if (protocolVersion >= 764 && protocolVersion <= 765) {
+                return 39;
+            }
+            if (protocolVersion >= 762 && protocolVersion <= 763) {
+                return 38;
+            }
+            throw new RuntimeException("Unknown protocol version for this method");
         }
-        if (protocolVersion >= 762 && protocolVersion <= 763) {
-            return 17;
-        }
-        throw new RuntimeException("Unknown protocol version for this method");
-    }
 
-    public static byte shadowStrengthOffset() {
-        int protocolVersion = getApi().getPacketEvents().getServerManager().getVersion().getProtocolVersion();
-        if (protocolVersion >= 764 && protocolVersion <= 765) {
-            return 19;
+        public static byte allighnCenterOffset() {
+            int protocolVersion = getApi().getPacketEvents().getServerManager().getVersion().getProtocolVersion();
+            if (protocolVersion >= 764 && protocolVersion <= 765) {
+                return 40;
+            }
+            if (protocolVersion >= 762 && protocolVersion <= 763) {
+                return 39;
+            }
+            throw new RuntimeException("Unknown protocol version for this method");
         }
-        if (protocolVersion >= 762 && protocolVersion <= 763) {
-            return 18;
-        }
-        throw new RuntimeException("Unknown protocol version for this method");
-    }
-
-    public static byte widthOffset() {
-        int protocolVersion = getApi().getPacketEvents().getServerManager().getVersion().getProtocolVersion();
-        if (protocolVersion >= 764 && protocolVersion <= 765) {
-            return 20;
-        }
-        if (protocolVersion >= 762 && protocolVersion <= 763) {
-            return 19;
-        }
-        throw new RuntimeException("Unknown protocol version for this method");
-    }
-
-    public static byte heightOffset() {
-        int protocolVersion = getApi().getPacketEvents().getServerManager().getVersion().getProtocolVersion();
-        if (protocolVersion >= 764 && protocolVersion <= 765) {
-            return 21;
-        }
-        if (protocolVersion >= 762 && protocolVersion <= 763) {
-            return 20;
-        }
-        throw new RuntimeException("Unknown protocol version for this method");
-    }
-
-    public static byte glowColorOverrideOffset() {
-        int protocolVersion = getApi().getPacketEvents().getServerManager().getVersion().getProtocolVersion();
-        if (protocolVersion >= 764 && protocolVersion <= 765) {
-            return 22;
-        }
-        if (protocolVersion >= 762 && protocolVersion <= 763) {
-            return 21;
-        }
-        throw new RuntimeException("Unknown protocol version for this method");
-    }
-
-    public static byte blockIdOffset() {
-        int protocolVersion = getApi().getPacketEvents().getServerManager().getVersion().getProtocolVersion();
-        if (protocolVersion >= 764 && protocolVersion <= 765) {
-            return 23;
-        }
-        if (protocolVersion >= 762 && protocolVersion <= 763) {
-            return 22;
-        }
-        throw new RuntimeException("Unknown protocol version for this method");
-    }
-
-    public static byte itemOffset() {
-        int protocolVersion = getApi().getPacketEvents().getServerManager().getVersion().getProtocolVersion();
-        if (protocolVersion >= 764 && protocolVersion <= 765) {
-            return 24;
-        }
-        if (protocolVersion >= 762 && protocolVersion <= 763) {
-            return 23;
-        }
-        throw new RuntimeException("Unknown protocol version for this method");
-    }
-
-    public static byte displayTypeOffset() {
-        int protocolVersion = getApi().getPacketEvents().getServerManager().getVersion().getProtocolVersion();
-        if (protocolVersion >= 764 && protocolVersion <= 765) {
-            return 25;
-        }
-        if (protocolVersion >= 762 && protocolVersion <= 763) {
-            return 24;
-        }
-        throw new RuntimeException("Unknown protocol version for this method");
     }
 }
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/Metadata.java b/api/src/main/java/me/tofaa/entitylib/meta/Metadata.java
index 532472a..da5adbf 100644
--- a/api/src/main/java/me/tofaa/entitylib/meta/Metadata.java
+++ b/api/src/main/java/me/tofaa/entitylib/meta/Metadata.java
@@ -3,38 +3,91 @@ package me.tofaa.entitylib.meta;
 import com.github.retrooper.packetevents.protocol.entity.data.EntityData;
 import com.github.retrooper.packetevents.protocol.entity.data.EntityDataType;
 import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerEntityMetadata;
+import me.tofaa.entitylib.EntityLib;
+import me.tofaa.entitylib.wrapper.WrapperEntity;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+import java.util.*;
 import java.util.concurrent.ConcurrentHashMap;
 
 @SuppressWarnings("unchecked")
 public class Metadata {
 
-    private final Map<Byte, EntityData> metadataMap = new ConcurrentHashMap<>();
     private final int entityId;
+    private EntityData[] entries = new EntityData[0];
+    private volatile Map<Integer, EntityData> entryMap = null;
+    private volatile boolean notifyChanges = true;
+    private final Map<Byte, EntityData> notNotifiedChanges = new HashMap<>();
 
     public Metadata(int entityId) {
         this.entityId = entityId;
     }
 
     public <T> T getIndex(byte index, @Nullable T defaultValue) {
-        EntityData entityData = metadataMap.get(index);
-        if (entityData == null) return defaultValue;
-        if (entityData.getValue() == null) return defaultValue;
-        return (T) entityData.getValue();
+        final EntityData[] entries = this.entries;
+        if (index < 0 || index >= entries.length) {
+            return defaultValue;
+        }
+        final EntityData entry = entries[index];
+        if (entry == null) return defaultValue;
+        if (entry.getValue() == null) return defaultValue;
+        return (T) entry.getValue();
     }
 
     public <T> void setIndex(byte index, @NotNull EntityDataType<T> dataType, T value) {
+
+        EntityData[] entries = this.entries;
+        if (index >= entries.length) {
+            final int newLength = Math.max(entries.length * 2, index + 1);
+            this.entries = entries = Arrays.copyOf(entries, newLength);
+        }
+
         EntityData data = new EntityData(index, dataType, value);
-        this.metadataMap.put(index, data);
+        entries[index] = data;
+        this.entryMap = null;
+
+        final WrapperEntity entity = EntityLib.getApi().findEntity(entityId);
+        if (entity == null || entity.isSpawned()) return; // Not EntityLib entity then, the user must send the packet manually. OR not spawned.
+        if (!this.notifyChanges) {
+            synchronized (this.notNotifiedChanges) {
+                this.notNotifiedChanges.put(index, data);
+            }
+        }
+        else {
+            entity.sendPacketToViewers(createPacket());
+        }
+    }
+
+    public void setNotifyAboutChanges(boolean value) {
+        if (this.notifyChanges == value) {
+            return;
+        }
+        if (!notifyChanges) {
+            return; // cache;
+        }
+        final WrapperEntity entity = EntityLib.getApi().findEntity(entityId);
+        if (entity == null || entity.isSpawned()) return;
+        Map<Byte, EntityData> entries;
+        synchronized (this.notNotifiedChanges) {
+            Map<Byte, EntityData> awaitingChanges = this.notNotifiedChanges;
+            if (awaitingChanges.isEmpty()) return;
+            entries = Collections.unmodifiableMap(awaitingChanges);
+            awaitingChanges.clear();
+        }
+        entity.sendPacketsToViewers(new WrapperPlayServerEntityMetadata(entityId, new ArrayList<>(entries.values())));
+    }
+
+
+    public boolean isNotifyingChanges() {
+        return notifyChanges;
     }
 
     @NotNull List<EntityData> getEntries() {
-        return new ArrayList<>(metadataMap.values());
+        return Collections.unmodifiableList(Arrays.asList(entries));
     }
 
     public WrapperPlayServerEntityMetadata createPacket() {
diff --git a/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperEntity.java b/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperEntity.java
index 2402c85..d1078fc 100644
--- a/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperEntity.java
+++ b/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperEntity.java
@@ -331,7 +331,7 @@ public class WrapperEntity implements Tickable {
     }
 
     public boolean hasNoGravity() {
-        return entityMeta.isHasNoGravity();
+        return entityMeta.hasNoGravity();
     }
 
     public void setHasNoGravity(boolean hasNoGravity) {
diff --git a/code-gen/src/main/java/me/tofaa/entitylib/codegen/Main.java b/code-gen/src/main/java/me/tofaa/entitylib/codegen/Main.java
index 4567f29..def0633 100644
--- a/code-gen/src/main/java/me/tofaa/entitylib/codegen/Main.java
+++ b/code-gen/src/main/java/me/tofaa/entitylib/codegen/Main.java
@@ -44,6 +44,10 @@ public final class Main {
         for (TypeHolder type : types) {
             System.out.println("Generating type" + type.className());
 
+            TypeSpec.Builder typeBuilder = TypeSpec.classBuilder(type.className() + "Offsets")
+                    .addModifiers(Modifier.PUBLIC, Modifier.FINAL, Modifier.STATIC)
+                    .addMethod(MethodSpec.constructorBuilder().addModifiers(Modifier.PRIVATE).build());
+
             for (MetaOffset offset : type.offsets()) {
 
                 MethodSpec.Builder method = MethodSpec.methodBuilder(offset.name() + "Offset")
@@ -58,10 +62,12 @@ public final class Main {
                     method.endControlFlow();
                 }
                 method.addStatement("throw new RuntimeException(\"Unknown protocol version for this method\")");
-                baseBuilder.addMethod(method.build());
+                typeBuilder.addMethod(method.build());
             }
+            baseBuilder.addType(typeBuilder.build());
         }
 
+
         TypeSpec base = baseBuilder.build();
         System.out.println("Writing to file");
         JavaFile file = JavaFile.builder("me.tofaa.entitylib.meta", base)
diff --git a/code-gen/src/main/resources/offset-calculator.json b/code-gen/src/main/resources/offset-calculator.json
index 414516a..079092b 100644
--- a/code-gen/src/main/resources/offset-calculator.json
+++ b/code-gen/src/main/resources/offset-calculator.json
@@ -6,7 +6,7 @@
         "name": "airTicks",
         "checks": [
           {
-            "from": 47,
+            "from": 765,
             "to": 47,
             "offset": 1
           }
@@ -74,6 +74,9 @@
       }
     ]
   },
+
+
+
   {
     "class-name": "AbstractDisplayMeta",
     "offsets": [
@@ -310,7 +313,7 @@
     ]
   },
   {
-    "class-name": "ItemDisplay",
+    "class-name": "ItemDisplayMeta",
     "offsets": [
       {
         "name": "item",
@@ -343,5 +346,236 @@
         ]
       }
     ]
+  },
+  {
+    "class-name": "TextDisplayMeta",
+    "offsets": [
+      {
+        "name": "text",
+        "checks": [
+          {
+            "from": 765,
+            "to": 764,
+            "offset": 26
+          },
+          {
+            "from": 763,
+            "to": 762,
+            "offset": 25
+          }
+        ]
+      },
+      {
+        "name": "textColor",
+        "checks": [
+          {
+            "from": 765,
+            "to": 764,
+            "offset": 27
+          },
+          {
+            "from": 763,
+            "to": 762,
+            "offset": 26
+          }
+        ]
+      },
+      {
+        "name": "textBackgroundColor",
+        "checks": [
+          {
+            "from": 765,
+            "to": 764,
+            "offset": 28
+          },
+          {
+            "from": 763,
+            "to": 762,
+            "offset": 27
+          }
+        ]
+      },
+      {
+        "name": "textBackground",
+        "checks": [
+          {
+            "from": 765,
+            "to": 764,
+            "offset": 29
+          },
+          {
+            "from": 763,
+            "to": 762,
+            "offset": 28
+          }
+        ]
+      },
+      {
+        "name": "textScale",
+        "checks": [
+          {
+            "from": 765,
+            "to": 764,
+            "offset": 30
+          },
+          {
+            "from": 763,
+            "to": 762,
+            "offset": 29
+          }
+        ]
+      },
+      {
+        "name": "textAlignment",
+        "checks": [
+          {
+            "from": 765,
+            "to": 764,
+            "offset": 31
+          },
+          {
+            "from": 763,
+            "to": 762,
+            "offset": 30
+          }
+        ]
+      },
+      {
+        "name": "lineWidth",
+        "checks": [
+          {
+            "from": 765,
+            "to": 764,
+            "offset": 32
+          },
+          {
+            "from": 763,
+            "to": 762,
+            "offset": 31
+          }
+        ]
+      },
+      {
+        "name": "backgroundColor",
+        "checks": [
+          {
+            "from": 765,
+            "to": 764,
+            "offset": 33
+          },
+          {
+            "from": 763,
+            "to": 762,
+            "offset": 32
+          }
+        ]
+      },
+      {
+          "name": "textOpacity",
+          "checks": [
+            {
+                "from": 765,
+                "to": 764,
+                "offset": 34
+            },
+            {
+                "from": 763,
+                "to": 762,
+                "offset": 33
+            }
+            ]
+      },
+      {
+        "name": "shadow",
+        "checks": [
+          {
+            "from": 765,
+            "to": 764,
+            "offset": 35
+          },
+          {
+            "from": 763,
+            "to": 762,
+            "offset": 34
+          }
+        ]
+      },
+      {
+        "name": "seeThrough",
+        "checks": [
+          {
+            "from": 765,
+            "to": 764,
+            "offset": 36
+          },
+          {
+            "from": 763,
+            "to": 762,
+            "offset": 35
+          }
+        ]
+      },
+        {
+            "name": "useDefaultBackground",
+            "checks": [
+            {
+                "from": 765,
+                "to": 764,
+                "offset": 37
+            },
+            {
+                "from": 763,
+                "to": 762,
+                "offset": 36
+            }
+            ]
+      },
+      {
+        "name": "allighnLeft",
+        "checks": [
+          {
+            "from": 765,
+            "to": 764,
+            "offset": 38
+          },
+          {
+            "from": 763,
+            "to": 762,
+            "offset": 37
+          }
+        ]
+      },
+      {
+        "name": "allighnRight",
+        "checks": [
+          {
+            "from": 765,
+            "to": 764,
+            "offset": 39
+          },
+          {
+            "from": 763,
+            "to": 762,
+            "offset": 38
+          }
+        ]
+      },
+      {
+        "name": "allighnCenter",
+        "checks": [
+          {
+            "from": 765,
+            "to": 764,
+            "offset": 40
+          },
+          {
+            "from": 763,
+            "to": 762,
+            "offset": 39
+          }
+        ]
+      }
+    ]
+
   }
 ]
\ No newline at end of file
diff --git a/common/src/main/java/me/tofaa/entitylib/common/AbstractEntityLibAPI.java b/common/src/main/java/me/tofaa/entitylib/common/AbstractEntityLibAPI.java
index 2433496..0f20a0e 100644
--- a/common/src/main/java/me/tofaa/entitylib/common/AbstractEntityLibAPI.java
+++ b/common/src/main/java/me/tofaa/entitylib/common/AbstractEntityLibAPI.java
@@ -7,11 +7,15 @@ import me.tofaa.entitylib.EntityLib;
 import me.tofaa.entitylib.EntityLibAPI;
 import me.tofaa.entitylib.Platform;
 import me.tofaa.entitylib.tick.TickContainer;
+import me.tofaa.entitylib.wrapper.WrapperEntity;
 import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
 
 import java.util.Collection;
 import java.util.Collections;
 import java.util.HashSet;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
 
 public abstract class AbstractEntityLibAPI<P, W, T> implements EntityLibAPI<W, T> {
 
@@ -19,6 +23,7 @@ public abstract class AbstractEntityLibAPI<P, W, T> implements EntityLibAPI<W, T
     protected final PacketEventsAPI<?> packetEvents;
     protected final APIConfig settings;
     protected final Collection<TickContainer<?, T>> tickContainers;
+    protected final Map<Integer, WrapperEntity> globalEntityMap = new ConcurrentHashMap<>();
 
     protected AbstractEntityLibAPI(Platform<P> platform, APIConfig settings) {
         this.platform = platform;
@@ -27,6 +32,22 @@ public abstract class AbstractEntityLibAPI<P, W, T> implements EntityLibAPI<W, T
         this.tickContainers = settings.shouldTickTickables() ? new HashSet<>() : Collections.emptyList();
     }
 
+    @Override
+    public @Nullable WrapperEntity findEntity(int entityId) {
+        return globalEntityMap.get(entityId);
+    }
+
+    @Override
+    public void globalRegisterEntity(WrapperEntity entity) {
+        if (globalEntityMap.containsKey(entity.getEntityId())) throw new IllegalArgumentException("Entity with that Id is already registered and present");
+        globalEntityMap.put(entity.getEntityId(), entity);
+    }
+
+    @Override
+    public void globalUnregisterEntity(@NotNull WrapperEntity entity) {
+        globalEntityMap.remove(entity.getEntityId());
+    }
+
     @NotNull
     @Override
     public APIConfig getSettings() {
diff --git a/common/src/main/java/me/tofaa/entitylib/common/AbstractWorldWrapper.java b/common/src/main/java/me/tofaa/entitylib/common/AbstractWorldWrapper.java
index b7a29fd..311c176 100644
--- a/common/src/main/java/me/tofaa/entitylib/common/AbstractWorldWrapper.java
+++ b/common/src/main/java/me/tofaa/entitylib/common/AbstractWorldWrapper.java
@@ -54,6 +54,7 @@ public abstract class AbstractWorldWrapper<W> implements WorldWrapper<W> {
         player.spawn(this, location);
         entities.put(player.getUuid(), player);
         entitiesById.put(player.getEntityId(), player);
+        EntityLib.getApi().globalRegisterEntity(player);
         return player;
     }
 
@@ -62,6 +63,7 @@ public abstract class AbstractWorldWrapper<W> implements WorldWrapper<W> {
         entity.spawn(this, location);
         entities.put(entity.getUuid(), entity);
         entitiesById.put(entity.getEntityId(), entity);
+        EntityLib.getApi().globalRegisterEntity(entity);
         return entity;
     }
 
@@ -70,6 +72,7 @@ public abstract class AbstractWorldWrapper<W> implements WorldWrapper<W> {
         entity.despawn();
         this.entities.remove(entity.getUuid());
         this.entitiesById.remove(entity.getEntityId());
+        EntityLib.getApi().globalUnregisterEntity(entity);
     }
 
     @Override
diff --git a/platforms/spigot/src/main/java/me/tofaa/entitylib/spigot/SpigotEntityLibPlatform.java b/platforms/spigot/src/main/java/me/tofaa/entitylib/spigot/SpigotEntityLibPlatform.java
index 919fa12..fd509b0 100644
--- a/platforms/spigot/src/main/java/me/tofaa/entitylib/spigot/SpigotEntityLibPlatform.java
+++ b/platforms/spigot/src/main/java/me/tofaa/entitylib/spigot/SpigotEntityLibPlatform.java
@@ -25,7 +25,7 @@ public class SpigotEntityLibPlatform extends AbstractPlatform<JavaPlugin> {
 
 
     @Override
-    public EntityLibAPI<?, ?> getAPI() {
+    public SpigotEntityLibAPI getAPI() {
         return api;
     }
 
diff --git a/test-plugin/src/main/java/me/tofaa/testentitylib/TestEntityLibPlugin.java b/test-plugin/src/main/java/me/tofaa/testentitylib/TestEntityLibPlugin.java
index 849ec69..b583bb0 100644
--- a/test-plugin/src/main/java/me/tofaa/testentitylib/TestEntityLibPlugin.java
+++ b/test-plugin/src/main/java/me/tofaa/testentitylib/TestEntityLibPlugin.java
@@ -8,20 +8,25 @@ import me.tofaa.entitylib.EntityLib;
 import me.tofaa.entitylib.EntityLibAPI;
 import me.tofaa.entitylib.WorldWrapper;
 import me.tofaa.entitylib.meta.mobs.passive.ChickenMeta;
+import me.tofaa.entitylib.spigot.SpigotEntityLibAPI;
 import me.tofaa.entitylib.spigot.SpigotEntityLibPlatform;
 import me.tofaa.entitylib.wrapper.WrapperEntity;
 import org.bukkit.World;
+import org.bukkit.command.Command;
+import org.bukkit.command.CommandExecutor;
+import org.bukkit.command.CommandSender;
 import org.bukkit.entity.Player;
 import org.bukkit.event.EventHandler;
 import org.bukkit.event.Listener;
 import org.bukkit.event.player.PlayerToggleSneakEvent;
 import org.bukkit.plugin.java.JavaPlugin;
 import org.bukkit.scheduler.BukkitTask;
+import org.jetbrains.annotations.NotNull;
 
-public class TestEntityLibPlugin extends JavaPlugin implements Listener {
+public class TestEntityLibPlugin extends JavaPlugin implements CommandExecutor {
 
 
-    private EntityLibAPI<World, BukkitTask> api;
+    private SpigotEntityLibAPI api;
     private WrapperEntity e;
     private WorldWrapper<World> world;
 
@@ -35,24 +40,27 @@ public class TestEntityLibPlugin extends JavaPlugin implements Listener {
                 .usePlatformLogger();
 
         EntityLib.init(platform, settings);
-        api = EntityLib.getApi();
-        getServer().getPluginManager().registerEvents(this, this);
+        api = platform.getAPI();
+        getCommand("testapi").setExecutor(this);
     }
 
-    @EventHandler
-    public void onCrouch(PlayerToggleSneakEvent event) {
-        Player player = event.getPlayer();
+    @Override
+    public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
+        if (!(sender instanceof Player)) return false;
+        Player player = (Player) sender;
         if (e == null) {
             world = api.wrapWorld(player.getWorld());
             e = world.spawnEntity(EntityTypes.CHICKEN, SpigotConversionUtil.fromBukkitLocation(player.getLocation()));
+            e.addViewer(player.getUniqueId());
+            player.sendMessage("Spawned");
         }
-        world = api.wrapWorld(player.getWorld());
-        e = world.spawnEntity(EntityTypes.CHICKEN, SpigotConversionUtil.fromBukkitLocation(player.getLocation()));
         ChickenMeta meta = (ChickenMeta) e.getEntityMeta();
         meta.setBaby(!meta.isBaby());
         meta.setHasGlowingEffect(!meta.hasGlowingEffect());
+        meta.setHasNoGravity(!meta.hasNoGravity());
 
-        e.addViewer(player.getUniqueId());
+        player.sendMessage("Updated");
+        return true;
     }
 
 }
diff --git a/test-plugin/src/main/resources/plugin.yml b/test-plugin/src/main/resources/plugin.yml
index df284e5..8c23a0e 100644
--- a/test-plugin/src/main/resources/plugin.yml
+++ b/test-plugin/src/main/resources/plugin.yml
@@ -6,15 +6,5 @@ main: me.tofaa.testentitylib.TestEntityLibPlugin
 api-version: "1.19"
 commands:
   testapi:
-    description: Test PEEntityMeta API
-    usage: /<command>
-
-  testentity:
-    description: Test PEEntity API
-    usage: /<command>
-  testdisplay:
-    description: Test PEDisplay API
-    usage: /<command>
-  spawnclickablefrog:
-    description: Spawn a clickable frog
+    description: Test EntityLib API
     usage: /<command>
\ No newline at end of file

From 2eaaca878e7dc0e741307a9bc5291e224e427e82 Mon Sep 17 00:00:00 2001
From: Tofaa <82680183+Tofaa2@users.noreply.github.com>
Date: Thu, 8 Feb 2024 14:02:18 +0400
Subject: [PATCH 14/19] fix bug + add notification system to equipment too

---
 .idea/workspace.xml                              | 15 ++++-----------
 .../java/me/tofaa/entitylib/meta/Metadata.java   |  2 +-
 .../tofaa/entitylib/wrapper/WrapperEntity.java   | 10 +++++++++-
 .../wrapper/WrapperEntityEquipment.java          | 16 ++++++++++++++--
 4 files changed, 28 insertions(+), 15 deletions(-)

diff --git a/.idea/workspace.xml b/.idea/workspace.xml
index 3f14df4..57f7120 100644
--- a/.idea/workspace.xml
+++ b/.idea/workspace.xml
@@ -6,18 +6,9 @@
   <component name="ChangeListManager">
     <list default="true" id="9d5d9b6f-43c8-41a4-bb42-a66ffc96c9b0" name="Changes" comment="">
       <change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
-      <change beforePath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/EntityLibAPI.java" beforeDir="false" afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/EntityLibAPI.java" afterDir="false" />
-      <change beforePath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/meta/EntityMeta.java" beforeDir="false" afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/meta/EntityMeta.java" afterDir="false" />
-      <change beforePath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/meta/MetaOffsetConverter.java" beforeDir="false" afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/meta/MetaOffsetConverter.java" afterDir="false" />
       <change beforePath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/meta/Metadata.java" beforeDir="false" afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/meta/Metadata.java" afterDir="false" />
       <change beforePath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperEntity.java" beforeDir="false" afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperEntity.java" afterDir="false" />
-      <change beforePath="$PROJECT_DIR$/code-gen/src/main/java/me/tofaa/entitylib/codegen/Main.java" beforeDir="false" afterPath="$PROJECT_DIR$/code-gen/src/main/java/me/tofaa/entitylib/codegen/Main.java" afterDir="false" />
-      <change beforePath="$PROJECT_DIR$/code-gen/src/main/resources/offset-calculator.json" beforeDir="false" afterPath="$PROJECT_DIR$/code-gen/src/main/resources/offset-calculator.json" afterDir="false" />
-      <change beforePath="$PROJECT_DIR$/common/src/main/java/me/tofaa/entitylib/common/AbstractEntityLibAPI.java" beforeDir="false" afterPath="$PROJECT_DIR$/common/src/main/java/me/tofaa/entitylib/common/AbstractEntityLibAPI.java" afterDir="false" />
-      <change beforePath="$PROJECT_DIR$/common/src/main/java/me/tofaa/entitylib/common/AbstractWorldWrapper.java" beforeDir="false" afterPath="$PROJECT_DIR$/common/src/main/java/me/tofaa/entitylib/common/AbstractWorldWrapper.java" afterDir="false" />
-      <change beforePath="$PROJECT_DIR$/platforms/spigot/src/main/java/me/tofaa/entitylib/spigot/SpigotEntityLibPlatform.java" beforeDir="false" afterPath="$PROJECT_DIR$/platforms/spigot/src/main/java/me/tofaa/entitylib/spigot/SpigotEntityLibPlatform.java" afterDir="false" />
-      <change beforePath="$PROJECT_DIR$/test-plugin/src/main/java/me/tofaa/testentitylib/TestEntityLibPlugin.java" beforeDir="false" afterPath="$PROJECT_DIR$/test-plugin/src/main/java/me/tofaa/testentitylib/TestEntityLibPlugin.java" afterDir="false" />
-      <change beforePath="$PROJECT_DIR$/test-plugin/src/main/resources/plugin.yml" beforeDir="false" afterPath="$PROJECT_DIR$/test-plugin/src/main/resources/plugin.yml" afterDir="false" />
+      <change beforePath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperEntityEquipment.java" beforeDir="false" afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperEntityEquipment.java" afterDir="false" />
     </list>
     <option name="SHOW_DIALOG" value="false" />
     <option name="HIGHLIGHT_CONFLICTS" value="true" />
@@ -304,7 +295,9 @@
       <workItem from="1706858181164" duration="925000" />
       <workItem from="1707159905372" duration="3391000" />
       <workItem from="1707210065718" duration="4823000" />
-      <workItem from="1707219870641" duration="4868000" />
+      <workItem from="1707219870641" duration="5522000" />
+      <workItem from="1707300688189" duration="1512000" />
+      <workItem from="1707381529971" duration="921000" />
     </task>
     <servers />
   </component>
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/Metadata.java b/api/src/main/java/me/tofaa/entitylib/meta/Metadata.java
index da5adbf..971e2c8 100644
--- a/api/src/main/java/me/tofaa/entitylib/meta/Metadata.java
+++ b/api/src/main/java/me/tofaa/entitylib/meta/Metadata.java
@@ -83,7 +83,7 @@ public class Metadata {
 
 
     public boolean isNotifyingChanges() {
-        return notifyChanges;
+        return notifyChanges; 
     }
 
     @NotNull List<EntityData> getEntries() {
diff --git a/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperEntity.java b/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperEntity.java
index d1078fc..4472f04 100644
--- a/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperEntity.java
+++ b/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperEntity.java
@@ -327,7 +327,15 @@ public class WrapperEntity implements Tickable {
     }
 
     private static void sendPacket(UUID user, PacketWrapper<?> wrapper) {
-        EntityLib.getApi().getPacketEvents().getProtocolManager().sendPacket(EntityLib.getApi().getPacketEvents().getProtocolManager().getChannel(user), wrapper);
+
+        Object channel = EntityLib.getApi().getPacketEvents().getProtocolManager().getChannel(user);
+        if (channel == null) {
+            if (EntityLib.getApi().getSettings().isDebugMode()) {
+                EntityLib.getPlatform().getLogger().warning("Failed to send packet to " + user + " because the channel was null. They may be disconnected/not online.");
+            }
+            return;
+        }
+        EntityLib.getApi().getPacketEvents().getProtocolManager().sendPacket(channel, wrapper);
     }
 
     public boolean hasNoGravity() {
diff --git a/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperEntityEquipment.java b/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperEntityEquipment.java
index 99b9a67..9b2aa8f 100644
--- a/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperEntityEquipment.java
+++ b/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperEntityEquipment.java
@@ -19,7 +19,7 @@ public class WrapperEntityEquipment {
     private static final EquipmentSlot[] EQUIPMENT_SLOTS = EquipmentSlot.values();
 
     private final WrapperLivingEntity entity;
-
+    private boolean notifyChanges = true;
 
     // 0 = main hand, 1 = offhand, 2 = boots, 3 = leggings, 4 = chestplate, 5 = helmet
     private final ItemStack[] equipment = new ItemStack[6];
@@ -113,7 +113,19 @@ public class WrapperEntityEquipment {
 
 
     public void refresh() {
-        this.entity.sendPacketToViewers(createPacket());
+        if (notifyChanges) {
+            this.entity.sendPacketToViewers(createPacket());
+        }
     }
 
+    public boolean isNotifyingChanges() {
+        return notifyChanges;
+    }
+
+    public void setNotifyChanges(boolean notifyChanges) {
+        this.notifyChanges = notifyChanges;
+        if (notifyChanges) {
+            refresh();
+        }
+    }
 }

From 82f0b54aba4844ca7d591553f995aaa009e1c66e Mon Sep 17 00:00:00 2001
From: Tofaa <82680183+Tofaa2@users.noreply.github.com>
Date: Sat, 17 Feb 2024 14:24:43 +0400
Subject: [PATCH 15/19] finish spigot cloning

---
 .../tofaa/entitylib/event/EventListener.java  |  2 +-
 .../event/types/UserRefreshEntityEvent.java   | 36 +++++++++++++++++++
 .../me/tofaa/entitylib/meta/EntityMeta.java   | 14 +++-----
 .../me/tofaa/entitylib/meta/Metadata.java     |  5 ---
 .../common/AbstractEntityLibAPI.java          |  7 +---
 .../entitylib/spigot/ExtraConversionUtil.java | 16 +++++++++
 .../tofaa/entitylib/spigot/SpigotWorld.java   | 27 ++++++++++++--
 7 files changed, 83 insertions(+), 24 deletions(-)
 create mode 100644 api/src/main/java/me/tofaa/entitylib/event/types/UserRefreshEntityEvent.java

diff --git a/api/src/main/java/me/tofaa/entitylib/event/EventListener.java b/api/src/main/java/me/tofaa/entitylib/event/EventListener.java
index 8cf6c01..f58dddc 100644
--- a/api/src/main/java/me/tofaa/entitylib/event/EventListener.java
+++ b/api/src/main/java/me/tofaa/entitylib/event/EventListener.java
@@ -10,7 +10,7 @@ public interface EventListener<E extends EntityLibEvent> {
 
     void handle(@NotNull E event);
 
-    public static <T extends EntityLibEvent> EventListener<T> generateListener(Class<T> eventClass, Consumer<T> consumer) {
+    static <T extends EntityLibEvent> EventListener<T> generateListener(Class<T> eventClass, Consumer<T> consumer) {
         return new EventListener<T>() {
             @Override
             public @NotNull Class<T> getEventClass() {
diff --git a/api/src/main/java/me/tofaa/entitylib/event/types/UserRefreshEntityEvent.java b/api/src/main/java/me/tofaa/entitylib/event/types/UserRefreshEntityEvent.java
new file mode 100644
index 0000000..9276cf2
--- /dev/null
+++ b/api/src/main/java/me/tofaa/entitylib/event/types/UserRefreshEntityEvent.java
@@ -0,0 +1,36 @@
+package me.tofaa.entitylib.event.types;
+
+import com.github.retrooper.packetevents.protocol.player.User;
+import me.tofaa.entitylib.event.EntityLibEvent;
+import me.tofaa.entitylib.wrapper.WrapperEntity;
+
+public class UserRefreshEntityEvent implements EntityLibEvent {
+
+    private final User user;
+    private final WrapperEntity entity;
+    private boolean cancelled;
+
+    public UserRefreshEntityEvent(User user, WrapperEntity entity) {
+        this.user = user;
+        this.entity = entity;
+    }
+
+    public User getUser() {
+        return user;
+    }
+
+
+    public WrapperEntity getEntity() {
+        return entity;
+    }
+
+    @Override
+    public boolean isCancelled() {
+        return cancelled;
+    }
+
+    @Override
+    public void setCancelled(boolean cancelled) {
+        this.cancelled = cancelled;
+    }
+}
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/EntityMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/EntityMeta.java
index 0957521..145cc8b 100644
--- a/api/src/main/java/me/tofaa/entitylib/meta/EntityMeta.java
+++ b/api/src/main/java/me/tofaa/entitylib/meta/EntityMeta.java
@@ -190,12 +190,6 @@ public class EntityMeta implements EntityMetadataProvider {
         return metadata.createPacket();
     }
 
-    protected static void isVersionOlder(ServerVersion version) {
-        if (!EntityLib.getApi().getPacketEvents().getServerManager().getVersion().is(VersionComparison.OLDER_THAN, version)) {
-            throw new InvalidVersionException("This method is only available for versions older than " + version.name() + ".");
-        }
-    }
-
     protected static void isVersionNewer(ServerVersion version) {
         if (!EntityLib.getApi().getPacketEvents().getServerManager().getVersion().is(VersionComparison.NEWER_THAN, version)) {
             throw new InvalidVersionException("This method is only available for versions newer than " + version.name() + ".");
@@ -220,19 +214,19 @@ public class EntityMeta implements EntityMetadataProvider {
         return (byte) (value + amount);
     }
 
-    protected byte getMask(byte index) {
+    public byte getMask(byte index) {
         return this.metadata.getIndex(index, (byte) 0);
     }
 
-    protected void setMask(byte index, byte mask) {
+    public void setMask(byte index, byte mask) {
         this.metadata.setIndex(index, EntityDataTypes.BYTE, mask);
     }
 
-    protected boolean getMaskBit(byte index, byte bit) {
+    public boolean getMaskBit(byte index, byte bit) {
         return (getMask(index) & bit) == bit;
     }
 
-    protected void setMaskBit(int index, byte bit, boolean value) {
+    public void setMaskBit(int index, byte bit, boolean value) {
         byte mask = getMask((byte)index);
         boolean currentValue = (mask & bit) == bit;
         if (currentValue == value) {
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/Metadata.java b/api/src/main/java/me/tofaa/entitylib/meta/Metadata.java
index 971e2c8..5d27853 100644
--- a/api/src/main/java/me/tofaa/entitylib/meta/Metadata.java
+++ b/api/src/main/java/me/tofaa/entitylib/meta/Metadata.java
@@ -7,12 +7,7 @@ import me.tofaa.entitylib.EntityLib;
 import me.tofaa.entitylib.wrapper.WrapperEntity;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
-
-import java.lang.invoke.MethodHandle;
-import java.lang.invoke.MethodHandles;
-import java.lang.invoke.VarHandle;
 import java.util.*;
-import java.util.concurrent.ConcurrentHashMap;
 
 @SuppressWarnings("unchecked")
 public class Metadata {
diff --git a/common/src/main/java/me/tofaa/entitylib/common/AbstractEntityLibAPI.java b/common/src/main/java/me/tofaa/entitylib/common/AbstractEntityLibAPI.java
index 0f20a0e..aca7871 100644
--- a/common/src/main/java/me/tofaa/entitylib/common/AbstractEntityLibAPI.java
+++ b/common/src/main/java/me/tofaa/entitylib/common/AbstractEntityLibAPI.java
@@ -1,9 +1,7 @@
 package me.tofaa.entitylib.common;
 
-import com.github.retrooper.packetevents.PacketEvents;
 import com.github.retrooper.packetevents.PacketEventsAPI;
 import me.tofaa.entitylib.APIConfig;
-import me.tofaa.entitylib.EntityLib;
 import me.tofaa.entitylib.EntityLibAPI;
 import me.tofaa.entitylib.Platform;
 import me.tofaa.entitylib.tick.TickContainer;
@@ -11,10 +9,7 @@ import me.tofaa.entitylib.wrapper.WrapperEntity;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Map;
+import java.util.*;
 import java.util.concurrent.ConcurrentHashMap;
 
 public abstract class AbstractEntityLibAPI<P, W, T> implements EntityLibAPI<W, T> {
diff --git a/platforms/spigot/src/main/java/me/tofaa/entitylib/spigot/ExtraConversionUtil.java b/platforms/spigot/src/main/java/me/tofaa/entitylib/spigot/ExtraConversionUtil.java
index 75e554d..6f9eaf9 100644
--- a/platforms/spigot/src/main/java/me/tofaa/entitylib/spigot/ExtraConversionUtil.java
+++ b/platforms/spigot/src/main/java/me/tofaa/entitylib/spigot/ExtraConversionUtil.java
@@ -2,8 +2,17 @@ package me.tofaa.entitylib.spigot;
 
 import com.github.retrooper.packetevents.protocol.entity.pose.EntityPose;
 import com.github.retrooper.packetevents.protocol.player.HumanoidArm;
+import com.github.retrooper.packetevents.protocol.player.TextureProperty;
+import com.github.retrooper.packetevents.protocol.player.UserProfile;
+import org.bukkit.entity.Player;
 import org.bukkit.entity.Pose;
 import org.bukkit.inventory.MainHand;
+import org.bukkit.profile.PlayerProfile;
+import org.bukkit.profile.PlayerTextures;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.UUID;
 
 public final class ExtraConversionUtil {
 
@@ -11,6 +20,13 @@ public final class ExtraConversionUtil {
 
     }
 
+    public static UserProfile fromBukkitPlayerProfile(PlayerProfile player) {
+        UUID uuid = player.getUniqueId();
+        String name = player.getName();
+        // TODO: Textures
+        return new UserProfile(uuid, name, Collections.emptyList());
+    }
+
     public static EntityPose fromBukkitPose(Pose pose) {
         return EntityPose.values()[pose.ordinal()];
     }
diff --git a/platforms/spigot/src/main/java/me/tofaa/entitylib/spigot/SpigotWorld.java b/platforms/spigot/src/main/java/me/tofaa/entitylib/spigot/SpigotWorld.java
index f01c7b5..2d57f89 100644
--- a/platforms/spigot/src/main/java/me/tofaa/entitylib/spigot/SpigotWorld.java
+++ b/platforms/spigot/src/main/java/me/tofaa/entitylib/spigot/SpigotWorld.java
@@ -1,14 +1,18 @@
 package me.tofaa.entitylib.spigot;
 
+import com.github.retrooper.packetevents.protocol.entity.type.EntityType;
 import com.github.retrooper.packetevents.protocol.world.Location;
 import com.github.retrooper.packetevents.protocol.world.states.WrappedBlockState;
 import io.github.retrooper.packetevents.util.SpigotConversionUtil;
+import me.tofaa.entitylib.EntityLib;
 import me.tofaa.entitylib.common.AbstractWorldWrapper;
 import me.tofaa.entitylib.meta.EntityMeta;
 import me.tofaa.entitylib.meta.types.LivingEntityMeta;
 import me.tofaa.entitylib.meta.types.PlayerMeta;
 import me.tofaa.entitylib.utils.Check;
 import me.tofaa.entitylib.wrapper.WrapperEntity;
+import me.tofaa.entitylib.wrapper.WrapperLivingEntity;
+import me.tofaa.entitylib.wrapper.WrapperPlayer;
 import net.kyori.adventure.text.Component;
 import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
 import org.bukkit.World;
@@ -17,6 +21,8 @@ import org.bukkit.entity.LivingEntity;
 import org.bukkit.entity.Player;
 import org.jetbrains.annotations.NotNull;
 
+import java.util.UUID;
+
 public class SpigotWorld extends AbstractWorldWrapper<World> {
 
 
@@ -29,7 +35,8 @@ public class SpigotWorld extends AbstractWorldWrapper<World> {
     public <T extends WrapperEntity> @NotNull T cloneEntity(@NotNull Object platformEntity, @NotNull Location location) {
         Check.stateCondition(!(platformEntity instanceof Entity), "Entity must be a Bukkit entity");
         Entity e = (Entity) platformEntity;
-        EntityMeta meta = EntityMeta.createMeta(e.getEntityId(), SpigotConversionUtil.fromBukkitEntityType(e.getType()));
+        EntityType type = SpigotConversionUtil.fromBukkitEntityType(e.getType());
+        EntityMeta meta = EntityMeta.createMeta(e.getEntityId(), type);
         meta.setHasNoGravity(!e.hasGravity());
         meta.setCustomNameVisible(e.isCustomNameVisible());
         meta.setCustomName(LegacyComponentSerializer.legacyAmpersand().deserialize(e.getCustomName()));
@@ -51,7 +58,23 @@ public class SpigotWorld extends AbstractWorldWrapper<World> {
             pm.setSwimming(p.isSwimming());
             pm.setActiveHand(ExtraConversionUtil.fromBukkitHand(p.getMainHand()));
         }
-        return null; // TODO;
+        WrapperEntity entity;
+        int id = EntityLib.getPlatform().getEntityIdProvider().provide(e.getUniqueId(), type);
+        UUID uuid = e.getUniqueId();
+        if (meta instanceof PlayerMeta) {
+            Player p = (Player) e;
+            entity = new WrapperPlayer(ExtraConversionUtil.fromBukkitPlayerProfile(p.getPlayerProfile()), id);
+        }
+        else if (meta instanceof LivingEntityMeta) {
+            entity = new WrapperLivingEntity(id, uuid, type, meta);
+        }
+        else {
+            entity = new WrapperEntity(id, uuid, type, meta);
+        }
+        if (entity == null) {
+            throw new IllegalArgumentException("Could not clone entity");
+        }
+        return (T) this.spawnEntity(entity, location);
     }
 
     @Override

From aae644def1069c0ed5c71ae3cd888e9706cac1f5 Mon Sep 17 00:00:00 2001
From: Tofaa <82680183+Tofaa2@users.noreply.github.com>
Date: Sat, 17 Feb 2024 19:02:27 +0400
Subject: [PATCH 16/19] Complete rewrite hopefully

---
 .../java/me/tofaa/entitylib/EntityLibAPI.java |  46 +-
 .../java/me/tofaa/entitylib/WorldWrapper.java |  67 ---
 .../entitylib/wrapper/WrapperEntity.java      |  37 +-
 .../entitylib/wrapper/hologram/Hologram.java  |  12 +-
 .../wrapper/hologram/LegacyHologram.java      |  24 +-
 .../wrapper/hologram/ModernHologram.java      |  17 +-
 .../common/AbstractEntityLibAPI.java          |  90 +++-
 .../common/AbstractWorldWrapper.java          | 136 ------
 .../entitylib/spigot/SpigotEntityLibAPI.java  |  65 ++-
 .../tofaa/entitylib/spigot/SpigotWorld.java   |  84 ----
 src/.gitignore                                |  42 --
 .../java/me/tofaa/entitylib/EntityLib.java    | 316 --------------
 .../me/tofaa/entitylib/EntityLibPlatform.java |  15 -
 .../entitylib/MetaConverterRegistry.java      | 175 --------
 .../java/me/tofaa/entitylib/Tickable.java     |  12 -
 .../me/tofaa/entitylib/TickingContainer.java  |  22 -
 .../java/me/tofaa/entitylib/WrapperWorld.java |  25 --
 .../entitylib/entity/EntityIdProvider.java    |  20 -
 .../entity/EntityInteractionProcessor.java    |  18 -
 .../tofaa/entitylib/entity/WrapperEntity.java | 394 ------------------
 .../entity/WrapperEntityCreature.java         |  82 ----
 .../entity/WrapperEntityEquipment.java        | 117 ------
 .../entity/WrapperExperienceOrbEntity.java    |  68 ---
 .../entitylib/entity/WrapperLivingEntity.java |  58 ---
 .../me/tofaa/entitylib/entity/ai/AIGroup.java |  75 ----
 .../entitylib/entity/ai/GoalSelector.java     |  85 ----
 .../entitylib/entity/ai/GoalSelectorList.java |  54 ---
 .../ai/goals/RandomHeadMovementGoal.java      |  81 ----
 .../exception/InvalidVersionException.java    |  23 -
 .../java/me/tofaa/entitylib/extras/Color.java |  56 ---
 .../entitylib/extras/CoordinateUtil.java      |  38 --
 .../me/tofaa/entitylib/extras/DyeColor.java   |  85 ----
 .../me/tofaa/entitylib/extras/Rotation.java   |  38 --
 .../me/tofaa/entitylib/meta/EntityMeta.java   | 220 ----------
 .../me/tofaa/entitylib/meta/Metadata.java     |  55 ---
 .../meta/display/BlockDisplayMeta.java        |  24 --
 .../meta/display/ItemDisplayMeta.java         |  47 ---
 .../meta/display/TextDisplayMeta.java         |  95 -----
 .../me/tofaa/entitylib/meta/mobs/BatMeta.java |  26 --
 .../me/tofaa/entitylib/meta/mobs/BeeMeta.java |  52 ---
 .../tofaa/entitylib/meta/mobs/DonkeyMeta.java |  14 -
 .../me/tofaa/entitylib/meta/mobs/FoxMeta.java | 119 ------
 .../tofaa/entitylib/meta/mobs/FrogMeta.java   |  46 --
 .../tofaa/entitylib/meta/mobs/GoatMeta.java   |  25 --
 .../tofaa/entitylib/meta/mobs/HoglinMeta.java |  26 --
 .../tofaa/entitylib/meta/mobs/OcelotMeta.java |  27 --
 .../tofaa/entitylib/meta/mobs/PandaMeta.java  | 109 -----
 .../entitylib/meta/mobs/PolarBearMeta.java    |  24 --
 .../entitylib/meta/mobs/SnifferMeta.java      |  33 --
 .../entitylib/meta/mobs/StriderMeta.java      |  41 --
 .../meta/mobs/cuboid/MagmaCubeMeta.java       |  13 -
 .../entitylib/meta/mobs/cuboid/SlimeMeta.java |  23 -
 .../meta/mobs/golem/IronGolemMeta.java        |  26 --
 .../meta/mobs/golem/ShulkerMeta.java          |  54 ---
 .../meta/mobs/golem/SnowGolemMeta.java        |  25 --
 .../meta/mobs/horse/BaseHorseMeta.java        |  82 ----
 .../meta/mobs/horse/ChestedHorseMeta.java     |  24 --
 .../entitylib/meta/mobs/horse/DonkeyMeta.java |  14 -
 .../entitylib/meta/mobs/horse/HorseMeta.java  |  87 ----
 .../entitylib/meta/mobs/horse/LlamaMeta.java  |  48 ---
 .../entitylib/meta/mobs/horse/MuleMeta.java   |  13 -
 .../meta/mobs/horse/SkeletonHorseMeta.java    |  13 -
 .../meta/mobs/horse/TraderLlamaMeta.java      |  14 -
 .../meta/mobs/horse/ZombieHorseMeta.java      |  13 -
 .../meta/mobs/minecart/BaseMinecartMeta.java  |  62 ---
 .../meta/mobs/minecart/ChestMinecartMeta.java |  19 -
 .../minecart/CommandBlockMinecartMeta.java    |  38 --
 .../mobs/minecart/FurnaceMinecartMeta.java    |  26 --
 .../mobs/minecart/HopperMinecartMeta.java     |  18 -
 .../meta/mobs/minecart/MinecartMeta.java      |  18 -
 .../mobs/minecart/SpawnerMinecartMeta.java    |  19 -
 .../meta/mobs/minecart/TntMinecartMeta.java   |  18 -
 .../meta/mobs/monster/BlazeMeta.java          |  26 --
 .../meta/mobs/monster/CaveSpiderMeta.java     |  13 -
 .../meta/mobs/monster/CreeperMeta.java        |  49 ---
 .../meta/mobs/monster/ElderGuardianMeta.java  |  13 -
 .../meta/mobs/monster/EndermanMeta.java       |  44 --
 .../meta/mobs/monster/EndermiteMeta.java      |  14 -
 .../meta/mobs/monster/GhastMeta.java          |  25 --
 .../meta/mobs/monster/GiantMeta.java          |  13 -
 .../meta/mobs/monster/GuardianMeta.java       |  36 --
 .../meta/mobs/monster/PhantomMeta.java        |  24 --
 .../meta/mobs/monster/SilverfishMeta.java     |  14 -
 .../meta/mobs/monster/SpiderMeta.java         |  27 --
 .../entitylib/meta/mobs/monster/VexMeta.java  |  25 --
 .../meta/mobs/monster/WitherMeta.java         |  55 ---
 .../meta/mobs/monster/ZoglinMeta.java         |  28 --
 .../mobs/monster/piglin/BasePiglinMeta.java   |  25 --
 .../mobs/monster/piglin/PiglinBruteMeta.java  |  13 -
 .../meta/mobs/monster/piglin/PiglinMeta.java  |  43 --
 .../meta/mobs/monster/raider/EvokerMeta.java  |  13 -
 .../mobs/monster/raider/IllusionerMeta.java   |  13 -
 .../mobs/monster/raider/PillagerMeta.java     |  14 -
 .../meta/mobs/monster/raider/RaiderMeta.java  |  25 --
 .../meta/mobs/monster/raider/RavagerMeta.java |  14 -
 .../raider/SpellcasterIllagerMeta.java        |  13 -
 .../mobs/monster/raider/VindicatorMeta.java   |  13 -
 .../meta/mobs/monster/raider/WitchMeta.java   |  23 -
 .../mobs/monster/skeleton/SkeletonMeta.java   |  14 -
 .../meta/mobs/monster/skeleton/StrayMeta.java |  11 -
 .../monster/skeleton/WitherSkeletonMeta.java  |  12 -
 .../meta/mobs/monster/zombie/DrownedMeta.java |  12 -
 .../meta/mobs/monster/zombie/HuskMeta.java    |  13 -
 .../meta/mobs/monster/zombie/ZombieMeta.java  |  35 --
 .../monster/zombie/ZombieVillagerMeta.java    |  43 --
 .../monster/zombie/ZombifiedPiglinMeta.java   |  13 -
 .../meta/mobs/passive/ChickenMeta.java        |  14 -
 .../entitylib/meta/mobs/passive/CowMeta.java  |  14 -
 .../meta/mobs/passive/MooshroomMeta.java      |  33 --
 .../entitylib/meta/mobs/passive/PigMeta.java  |  34 --
 .../meta/mobs/passive/RabbitMeta.java         |  46 --
 .../meta/mobs/passive/SheepMeta.java          |  43 --
 .../meta/mobs/passive/TurtleMeta.java         |  66 ---
 .../entitylib/meta/mobs/tameable/CatMeta.java |  72 ----
 .../meta/mobs/tameable/ParrotMeta.java        |  38 --
 .../meta/mobs/tameable/WolfMeta.java          |  40 --
 .../meta/mobs/villager/BaseVillagerMeta.java  |  24 --
 .../meta/mobs/villager/VillagerMeta.java      |  81 ----
 .../mobs/villager/WanderingTraderMeta.java    |  13 -
 .../meta/mobs/water/AxolotlMeta.java          |  50 ---
 .../meta/mobs/water/BaseFishMeta.java         |  25 --
 .../entitylib/meta/mobs/water/CodMeta.java    |  13 -
 .../meta/mobs/water/DolphinMeta.java          |  43 --
 .../meta/mobs/water/GlowSquidMeta.java        |  24 --
 .../meta/mobs/water/PufferFishMeta.java       |  32 --
 .../entitylib/meta/mobs/water/SalmonMeta.java |   9 -
 .../entitylib/meta/mobs/water/SquidMeta.java  |  14 -
 .../meta/mobs/water/TropicalFishMeta.java     | 128 ------
 .../meta/other/AreaEffectCloudMeta.java       |  40 --
 .../entitylib/meta/other/ArmorStandMeta.java  | 110 -----
 .../tofaa/entitylib/meta/other/BoatMeta.java  |  86 ----
 .../entitylib/meta/other/EndCrystalMeta.java  |  36 --
 .../entitylib/meta/other/EnderDragonMeta.java |  43 --
 .../entitylib/meta/other/EvokerFangsMeta.java |  14 -
 .../meta/other/FallingBlockMeta.java          |  46 --
 .../meta/other/FireworkRocketMeta.java        |  50 ---
 .../entitylib/meta/other/FishingHookMeta.java |  53 ---
 .../meta/other/GlowItemFrameMeta.java         |  13 -
 .../entitylib/meta/other/InteractionMeta.java |  41 --
 .../entitylib/meta/other/ItemFrameMeta.java   |  74 ----
 .../entitylib/meta/other/LeashKnotMeta.java   |  14 -
 .../meta/other/LightningBoltMeta.java         |  14 -
 .../entitylib/meta/other/LlamaSpitMeta.java   |  25 --
 .../entitylib/meta/other/MarkerMeta.java      |  14 -
 .../entitylib/meta/other/PaintingMeta.java    | 120 ------
 .../entitylib/meta/other/PrimedTntMeta.java   |  23 -
 .../entitylib/meta/projectile/ArrowMeta.java  |  47 ---
 .../meta/projectile/BaseArrowMeta.java        |  48 ---
 .../meta/projectile/DragonFireballMeta.java   |  38 --
 .../meta/projectile/EyeOfEnderMeta.java       |  20 -
 .../meta/projectile/ItemEntityMeta.java       |  26 --
 .../meta/projectile/LargeFireballMeta.java    |  39 --
 .../meta/projectile/ShulkerBulletMeta.java    |  25 --
 .../meta/projectile/SmallFireballMeta.java    |  43 --
 .../meta/projectile/SnowballMeta.java         |  19 -
 .../meta/projectile/SpectralArrowMeta.java    |  37 --
 .../meta/projectile/ThrownEggMeta.java        |  20 -
 .../meta/projectile/ThrownEnderPearlMeta.java |  19 -
 .../meta/projectile/ThrownExpBottleMeta.java  |  19 -
 .../meta/projectile/ThrownPotionMeta.java     |  17 -
 .../meta/projectile/ThrownTridentMeta.java    |  31 --
 .../meta/projectile/WitherSkullMeta.java      |  50 ---
 .../entitylib/meta/types/AgeableMeta.java     |  23 -
 .../entitylib/meta/types/DisplayMeta.java     | 255 ------------
 .../meta/types/ItemContainerMeta.java         |  27 --
 .../meta/types/LivingEntityMeta.java          | 119 ------
 .../tofaa/entitylib/meta/types/MobMeta.java   |  49 ---
 .../entitylib/meta/types/ObjectData.java      |   9 -
 .../entitylib/meta/types/PlayerMeta.java      | 148 -------
 .../entitylib/meta/types/ProjectileMeta.java  |  10 -
 .../entitylib/meta/types/TameableMeta.java    |  46 --
 .../entitylib/meta/types/WaterMobMeta.java    |  13 -
 .../testentitylib/TestEntityLibPlugin.java    |  10 +-
 173 files changed, 189 insertions(+), 7585 deletions(-)
 delete mode 100644 api/src/main/java/me/tofaa/entitylib/WorldWrapper.java
 delete mode 100644 common/src/main/java/me/tofaa/entitylib/common/AbstractWorldWrapper.java
 delete mode 100644 platforms/spigot/src/main/java/me/tofaa/entitylib/spigot/SpigotWorld.java
 delete mode 100644 src/.gitignore
 delete mode 100644 src/main/java/me/tofaa/entitylib/EntityLib.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/EntityLibPlatform.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/MetaConverterRegistry.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/Tickable.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/TickingContainer.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/WrapperWorld.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/entity/EntityIdProvider.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/entity/EntityInteractionProcessor.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/entity/WrapperEntity.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/entity/WrapperEntityCreature.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/entity/WrapperEntityEquipment.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/entity/WrapperExperienceOrbEntity.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/entity/WrapperLivingEntity.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/entity/ai/AIGroup.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/entity/ai/GoalSelector.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/entity/ai/GoalSelectorList.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/entity/ai/goals/RandomHeadMovementGoal.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/exception/InvalidVersionException.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/extras/Color.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/extras/CoordinateUtil.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/extras/DyeColor.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/extras/Rotation.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/EntityMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/Metadata.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/display/BlockDisplayMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/display/ItemDisplayMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/display/TextDisplayMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/mobs/BatMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/mobs/BeeMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/mobs/DonkeyMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/mobs/FoxMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/mobs/FrogMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/mobs/GoatMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/mobs/HoglinMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/mobs/OcelotMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/mobs/PandaMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/mobs/PolarBearMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/mobs/SnifferMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/mobs/StriderMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/mobs/cuboid/MagmaCubeMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/mobs/cuboid/SlimeMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/mobs/golem/IronGolemMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/mobs/golem/ShulkerMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/mobs/golem/SnowGolemMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/mobs/horse/BaseHorseMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/mobs/horse/ChestedHorseMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/mobs/horse/DonkeyMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/mobs/horse/HorseMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/mobs/horse/LlamaMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/mobs/horse/MuleMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/mobs/horse/SkeletonHorseMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/mobs/horse/TraderLlamaMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/mobs/horse/ZombieHorseMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/mobs/minecart/BaseMinecartMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/mobs/minecart/ChestMinecartMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/mobs/minecart/CommandBlockMinecartMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/mobs/minecart/FurnaceMinecartMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/mobs/minecart/HopperMinecartMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/mobs/minecart/MinecartMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/mobs/minecart/SpawnerMinecartMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/mobs/minecart/TntMinecartMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/mobs/monster/BlazeMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/mobs/monster/CaveSpiderMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/mobs/monster/CreeperMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/mobs/monster/ElderGuardianMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/mobs/monster/EndermanMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/mobs/monster/EndermiteMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/mobs/monster/GhastMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/mobs/monster/GiantMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/mobs/monster/GuardianMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/mobs/monster/PhantomMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/mobs/monster/SilverfishMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/mobs/monster/SpiderMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/mobs/monster/VexMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/mobs/monster/WitherMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/mobs/monster/ZoglinMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/mobs/monster/piglin/BasePiglinMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/mobs/monster/piglin/PiglinBruteMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/mobs/monster/piglin/PiglinMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/mobs/monster/raider/EvokerMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/mobs/monster/raider/IllusionerMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/mobs/monster/raider/PillagerMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/mobs/monster/raider/RaiderMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/mobs/monster/raider/RavagerMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/mobs/monster/raider/SpellcasterIllagerMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/mobs/monster/raider/VindicatorMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/mobs/monster/raider/WitchMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/mobs/monster/skeleton/SkeletonMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/mobs/monster/skeleton/StrayMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/mobs/monster/skeleton/WitherSkeletonMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/mobs/monster/zombie/DrownedMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/mobs/monster/zombie/HuskMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/mobs/monster/zombie/ZombieMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/mobs/monster/zombie/ZombieVillagerMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/mobs/monster/zombie/ZombifiedPiglinMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/mobs/passive/ChickenMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/mobs/passive/CowMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/mobs/passive/MooshroomMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/mobs/passive/PigMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/mobs/passive/RabbitMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/mobs/passive/SheepMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/mobs/passive/TurtleMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/mobs/tameable/CatMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/mobs/tameable/ParrotMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/mobs/tameable/WolfMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/mobs/villager/BaseVillagerMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/mobs/villager/VillagerMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/mobs/villager/WanderingTraderMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/mobs/water/AxolotlMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/mobs/water/BaseFishMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/mobs/water/CodMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/mobs/water/DolphinMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/mobs/water/GlowSquidMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/mobs/water/PufferFishMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/mobs/water/SalmonMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/mobs/water/SquidMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/mobs/water/TropicalFishMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/other/AreaEffectCloudMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/other/ArmorStandMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/other/BoatMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/other/EndCrystalMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/other/EnderDragonMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/other/EvokerFangsMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/other/FallingBlockMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/other/FireworkRocketMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/other/FishingHookMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/other/GlowItemFrameMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/other/InteractionMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/other/ItemFrameMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/other/LeashKnotMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/other/LightningBoltMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/other/LlamaSpitMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/other/MarkerMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/other/PaintingMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/other/PrimedTntMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/projectile/ArrowMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/projectile/BaseArrowMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/projectile/DragonFireballMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/projectile/EyeOfEnderMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/projectile/ItemEntityMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/projectile/LargeFireballMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/projectile/ShulkerBulletMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/projectile/SmallFireballMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/projectile/SnowballMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/projectile/SpectralArrowMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/projectile/ThrownEggMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/projectile/ThrownEnderPearlMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/projectile/ThrownExpBottleMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/projectile/ThrownPotionMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/projectile/ThrownTridentMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/projectile/WitherSkullMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/types/AgeableMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/types/DisplayMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/types/ItemContainerMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/types/LivingEntityMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/types/MobMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/types/ObjectData.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/types/PlayerMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/types/ProjectileMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/types/TameableMeta.java
 delete mode 100644 src/main/java/me/tofaa/entitylib/meta/types/WaterMobMeta.java

diff --git a/api/src/main/java/me/tofaa/entitylib/EntityLibAPI.java b/api/src/main/java/me/tofaa/entitylib/EntityLibAPI.java
index d2227bf..2ce726a 100644
--- a/api/src/main/java/me/tofaa/entitylib/EntityLibAPI.java
+++ b/api/src/main/java/me/tofaa/entitylib/EntityLibAPI.java
@@ -1,23 +1,25 @@
 package me.tofaa.entitylib;
 
 import com.github.retrooper.packetevents.PacketEventsAPI;
+import com.github.retrooper.packetevents.protocol.entity.type.EntityType;
+import com.github.retrooper.packetevents.protocol.player.UserProfile;
+import com.github.retrooper.packetevents.protocol.world.Location;
 import me.tofaa.entitylib.tick.TickContainer;
 import me.tofaa.entitylib.wrapper.WrapperEntity;
+import me.tofaa.entitylib.wrapper.WrapperPlayer;
 import org.jetbrains.annotations.ApiStatus;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
 import java.util.Collection;
+import java.util.UUID;
 
 /**
  * Represents the API for EntityLib.
  * Handles the loading, enabling, and disabling of the API. And handles platform specific creation of EntityLib content.
- * @param <W> The {@link WorldWrapper}'s param type for the platform specific World.
  * @param <T> The {@link TickContainer}'s param type for the platform specific TickContainer.
  */
-public interface EntityLibAPI<W, T> {
-
-
+public interface EntityLibAPI<T> {
 
     /**
      * @return The {@link PacketEventsAPI} that EntityLib uses.
@@ -28,33 +30,23 @@ public interface EntityLibAPI<W, T> {
 
     void onEnable();
 
-    /**
-     * Attempts to search and find an entity across all wrapped worlds. This only works on EntityLib entities.
-     * @param entityId the entity id of the entity
-     * @return the entity if one is found, null otherwise.
-     */
-    @Nullable WrapperEntity findEntity(int entityId);
+    @NotNull WrapperPlayer spawnPlayer(UserProfile profile, Location location);
 
-    /**
-     * Mainly internal method to register the {@link WrapperEntity} to EntitLib cache, all {@link WorldWrapper}'s do this automatically
-     * @param entity
-     */
-    @ApiStatus.Internal
-    void globalRegisterEntity(@NotNull WrapperEntity entity);
+    @NotNull <T extends WrapperEntity> T spawnEntity(@NotNull Class<T> wrapperClass, @NotNull EntityType entityType, @NotNull Location location);
 
-    /**
-     * Mainly internal method to unregister the {@link WrapperEntity} to EntitLib cache, all {@link WorldWrapper}'s do this automatically
-     * @param entity
-     */
-    void globalUnregisterEntity(@NotNull WrapperEntity entity);
+    @NotNull WrapperEntity spawnEntity(@NotNull EntityType entityType, @NotNull Location location);
 
+    @NotNull <T extends WrapperEntity> T spawnEntity(@NotNull T entity, @NotNull Location location);
 
-    /**
-     * Creates a wrapped world for the platform specific world.
-     * @param world The platform specific world handle.
-     * @return A wrapped world.
-     */
-    @NotNull WorldWrapper<W> wrapWorld(W world);
+    @NotNull <T extends WrapperEntity> T cloneEntity(@NotNull Object platformEntity, @NotNull Location location);
+
+    @Nullable WrapperEntity getEntity(int id);
+
+    @Nullable WrapperEntity getEntity(@NotNull UUID uuid);
+
+    void removeEntity(WrapperEntity entity);
+
+    @NotNull Collection<WrapperEntity> getAllEntities();
 
     /**
      * @return The {@link APIConfig} for the API.
diff --git a/api/src/main/java/me/tofaa/entitylib/WorldWrapper.java b/api/src/main/java/me/tofaa/entitylib/WorldWrapper.java
deleted file mode 100644
index b3d0ae3..0000000
--- a/api/src/main/java/me/tofaa/entitylib/WorldWrapper.java
+++ /dev/null
@@ -1,67 +0,0 @@
-package me.tofaa.entitylib;
-
-import com.github.retrooper.packetevents.protocol.entity.type.EntityType;
-import com.github.retrooper.packetevents.protocol.player.UserProfile;
-import com.github.retrooper.packetevents.protocol.world.Dimension;
-import com.github.retrooper.packetevents.protocol.world.Location;
-import com.github.retrooper.packetevents.protocol.world.states.WrappedBlockState;
-import me.tofaa.entitylib.tick.TickContainer;
-import me.tofaa.entitylib.wrapper.WrapperEntity;
-import me.tofaa.entitylib.wrapper.WrapperPlayer;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-import java.util.Collection;
-import java.util.UUID;
-
-/**
- * Represents a platform specific world.
- * These are not needed at all times, and should exclusively be used when an Entity needs to be
- * aware of its surroundings.
- * @param <W> The platform specific World type.
- */
-public interface WorldWrapper<W> {
-
-    @NotNull WrapperPlayer spawnPlayer(UserProfile profile, Location location);
-
-    @NotNull <T extends WrapperEntity> T spawnEntity(@NotNull Class<T> wrapperClass, @NotNull EntityType entityType, @NotNull Location location);
-
-    @NotNull WrapperEntity spawnEntity(@NotNull EntityType entityType, @NotNull Location location);
-
-    @NotNull <T extends WrapperEntity> T spawnEntity(@NotNull T entity, @NotNull Location location);
-
-    @NotNull <T extends WrapperEntity> T cloneEntity(@NotNull Object platformEntity, @NotNull Location location);
-
-    @NotNull Collection<WrapperEntity> getEntities();
-
-    @Nullable WrapperEntity getEntity(int id);
-
-    @Nullable WrapperEntity getEntity(@NotNull UUID uuid);
-
-
-    void removeEntity(WrapperEntity entity);
-
-    /**
-     * Gets the block at the specified coordinates. Depending on the platforms implementation, this method may be slow.
-     * @param x The x coordinate.
-     * @param y The y coordinate.
-     * @param z The z coordinate.
-     * @return The packetevents WrappedBlockState at the specified coordinates.
-     */
-    WrappedBlockState getBlock(int x, int y, int z);
-
-    /**
-     * @return the packetevents Dimension of the world.
-     */
-    @NotNull Dimension getDimension();
-
-    /**
-     * @return the world's UUID.
-     */
-    @NotNull UUID getUuid();
-
-    /**
-     * @return the platform specific World.
-     */
-    @NotNull W getHandle();
-}
diff --git a/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperEntity.java b/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperEntity.java
index 4472f04..0ce32de 100644
--- a/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperEntity.java
+++ b/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperEntity.java
@@ -2,21 +2,17 @@ package me.tofaa.entitylib.wrapper;
 
 import com.github.retrooper.packetevents.protocol.entity.type.EntityType;
 import com.github.retrooper.packetevents.protocol.player.User;
-import com.github.retrooper.packetevents.protocol.world.BoundingBox;
 import com.github.retrooper.packetevents.protocol.world.Location;
 import com.github.retrooper.packetevents.util.Vector3d;
 import com.github.retrooper.packetevents.wrapper.PacketWrapper;
 import com.github.retrooper.packetevents.wrapper.play.server.*;
 import me.tofaa.entitylib.EntityLib;
-import me.tofaa.entitylib.WorldWrapper;
 import me.tofaa.entitylib.meta.EntityMeta;
 import me.tofaa.entitylib.meta.types.ObjectData;
 import me.tofaa.entitylib.tick.Tickable;
-import org.jetbrains.annotations.ApiStatus;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
-import javax.swing.text.html.parser.Entity;
 import java.util.*;
 
 public class WrapperEntity implements Tickable {
@@ -34,7 +30,6 @@ public class WrapperEntity implements Tickable {
     private Vector3d velocity;
     private int riding = -1;
     private final Set<Integer> passengers;
-    private WorldWrapper<?> world;
 
     public WrapperEntity(int entityId, UUID uuid, EntityType entityType, EntityMeta entityMeta) {
         this.entityId = entityId;
@@ -46,10 +41,9 @@ public class WrapperEntity implements Tickable {
         this.passengers = new HashSet<>();
     }
 
-    public boolean spawn(WorldWrapper<?> world, Location location) {
+    public boolean spawn(Location location) {
         if (spawned) return false;
         this.location = location;
-        this.world = world;
         this.spawned = true;
         int data = 0;
         Optional<Vector3d> velocity;
@@ -87,7 +81,7 @@ public class WrapperEntity implements Tickable {
     }
 
     public void remove() {
-        world.removeEntity(this);
+        EntityLib.getApi().removeEntity(this);
     }
 
     public void despawn() {
@@ -96,12 +90,11 @@ public class WrapperEntity implements Tickable {
         sendPacketToViewers(new WrapperPlayServerDestroyEntities(entityId));
     }
 
-    public void teleport(WorldWrapper<?> world, @NotNull Location location, boolean onGround) {
+    public void teleport(@NotNull Location location, boolean onGround) {
         if (!spawned) {
             return;
         }
         this.location = location;
-        this.world = world;
         this.onGround = onGround;
         sendPacketToViewers(
                 new WrapperPlayServerEntityTeleport(
@@ -114,12 +107,8 @@ public class WrapperEntity implements Tickable {
         );
     }
 
-    public void teleport(WorldWrapper<?> world, @NotNull Location location) {
-        teleport(world, location, onGround);
-    }
-
-    public void teleport(@NotNull Location location, boolean onGround) {
-        teleport(null, location, onGround);
+    public void teleport(@NotNull Location location) {
+        teleport(location, onGround);
     }
 
     /**
@@ -167,7 +156,7 @@ public class WrapperEntity implements Tickable {
 
     /**
      * Removes a viewer from the viewers set of this entity. The viewer will be informed of this removal and will no longer receive any packets
-     * @param UUID the uuid of the user to remove
+     * @param uuid the uuid of the user to remove
      */
     public void removeViewer(UUID uuid) {
         if (!viewers.remove(uuid)) {
@@ -258,11 +247,9 @@ public class WrapperEntity implements Tickable {
     }
 
     public WrapperEntity getRiding() {
-        return world.getEntity(riding);
+        return EntityLib.getApi().getEntity(riding);
     }
 
-
-
     protected WrapperPlayServerSetPassengers createPassengerPacket() {
         return new WrapperPlayServerSetPassengers(entityId, passengers.stream().mapToInt(i -> i).toArray());
     }
@@ -357,7 +344,7 @@ public class WrapperEntity implements Tickable {
         }
         passengers.add(passenger);
         sendPacketToViewers(createPassengerPacket());
-        WrapperEntity e = world.getEntity(passenger);
+        WrapperEntity e = EntityLib.getApi().getEntity(passenger);
         if (e != null) {
             e.riding = this.entityId;
             e.preRidingLocation = e.location;
@@ -414,17 +401,13 @@ public class WrapperEntity implements Tickable {
         }
         passengers.remove(passenger);
         sendPacketToViewers(createPassengerPacket());
-        WrapperEntity e = world.getEntity(passenger);
+        WrapperEntity e = EntityLib.getApi().getEntity(passenger);
         if (e != null) {
             e.riding = -1;
-            e.teleport(world, e.preRidingLocation, e.onGround);
+            e.teleport(e.preRidingLocation, e.onGround);
         }
     }
 
-    public WorldWrapper<?> getWorld() {
-        return world;
-    }
-
     /**
      * @param passenger the entity id of the passenger
      * @return true if the entity has the passenger, false otherwise
diff --git a/api/src/main/java/me/tofaa/entitylib/wrapper/hologram/Hologram.java b/api/src/main/java/me/tofaa/entitylib/wrapper/hologram/Hologram.java
index a2bc891..0e05cd4 100644
--- a/api/src/main/java/me/tofaa/entitylib/wrapper/hologram/Hologram.java
+++ b/api/src/main/java/me/tofaa/entitylib/wrapper/hologram/Hologram.java
@@ -1,10 +1,7 @@
 package me.tofaa.entitylib.wrapper.hologram;
 
 import com.github.retrooper.packetevents.protocol.world.Location;
-import com.github.retrooper.packetevents.util.Vector3f;
-import me.tofaa.entitylib.WorldWrapper;
 import me.tofaa.entitylib.meta.display.TextDisplayMeta;
-import me.tofaa.entitylib.meta.types.DisplayMeta;
 import net.kyori.adventure.text.Component;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
@@ -14,17 +11,16 @@ import java.util.function.Consumer;
 
 public interface Hologram<W> {
 
-    static <C> Hologram.@NotNull Legacy<C> legacy(@NotNull WorldWrapper<C> world, @NotNull Location location) {
-        return new LegacyHologram<>(world, location);
+    static <C> Hologram.@NotNull Legacy<C> legacy(@NotNull Location location) {
+        return new LegacyHologram<>(location);
     }
 
-    static <C> Hologram.@NotNull Legacy<C> legacy(@NotNull WorldWrapper<C> world, @NotNull Location location, List<Component> lines) {
-        return new LegacyHologram<>(world, location, lines);
+    static <C> Hologram.@NotNull Legacy<C> legacy(@NotNull Location location, List<Component> lines) {
+        return new LegacyHologram<>(location, lines);
     }
 
     @NotNull Location getLocation();
 
-    @NotNull WorldWrapper<W> getWorld();
 
     void show();
 
diff --git a/api/src/main/java/me/tofaa/entitylib/wrapper/hologram/LegacyHologram.java b/api/src/main/java/me/tofaa/entitylib/wrapper/hologram/LegacyHologram.java
index d885fa7..c501a3d 100644
--- a/api/src/main/java/me/tofaa/entitylib/wrapper/hologram/LegacyHologram.java
+++ b/api/src/main/java/me/tofaa/entitylib/wrapper/hologram/LegacyHologram.java
@@ -2,9 +2,7 @@ package me.tofaa.entitylib.wrapper.hologram;
 
 import com.github.retrooper.packetevents.protocol.entity.type.EntityTypes;
 import com.github.retrooper.packetevents.protocol.world.Location;
-import com.github.retrooper.packetevents.util.Vector3d;
 import me.tofaa.entitylib.EntityLib;
-import me.tofaa.entitylib.WorldWrapper;
 import me.tofaa.entitylib.meta.other.ArmorStandMeta;
 import me.tofaa.entitylib.wrapper.WrapperEntity;
 import net.kyori.adventure.text.Component;
@@ -17,19 +15,17 @@ import java.util.List;
 final class LegacyHologram<W> implements Hologram.Legacy<W> {
 
     private Location location;
-    private WorldWrapper<W> world;
     private List<WrapperEntity> lines = new ArrayList<>(3);
     private float lineOffset = -0.9875f;
     private float markerOffset = -0.40625f;
     private boolean marker;
 
-    LegacyHologram(@NotNull WorldWrapper<W> world, @NotNull Location location) {
-        this.world = world;
+    LegacyHologram(@NotNull Location location) {
         this.location = location;
     }
 
-    LegacyHologram(@NotNull WorldWrapper<W> world, @NotNull Location location, List<Component> lines) {
-        this(world, location);
+    LegacyHologram(@NotNull Location location, List<Component> lines) {
+        this(location);
         for (Component line : lines) {
             addLine(line);
         }
@@ -50,7 +46,7 @@ final class LegacyHologram<W> implements Hologram.Legacy<W> {
     @Override
     public void show() {
         for (WrapperEntity line : lines) {
-            line.spawn(world, location);
+            line.spawn(location);
         }
         teleport(location);
     }
@@ -66,7 +62,7 @@ final class LegacyHologram<W> implements Hologram.Legacy<W> {
     public void teleport(Location location) {
         this.location = location;
         // reversed order
-        for (int i = lines.size() -1; i >= 0; i--) {
+        for (int i = lines.size() - 1; i >= 0; i--) {
             WrapperEntity line = lines.get(i);
             double y;
             if (marker) {
@@ -77,7 +73,7 @@ final class LegacyHologram<W> implements Hologram.Legacy<W> {
             ArmorStandMeta meta = (ArmorStandMeta) line.getEntityMeta();
             meta.setMarker(marker);
             Location l = new Location(location.getX(), y, location.getZ(), location.getYaw(), location.getPitch());
-            line.teleport(world, l, false);
+            line.teleport(l, false);
         }
     }
 
@@ -91,7 +87,7 @@ final class LegacyHologram<W> implements Hologram.Legacy<W> {
 
     @Override
     public void setLine(int index, @Nullable Component line) {
-        WrapperEntity e = world.spawnEntity(EntityTypes.ARMOR_STAND, location);
+        WrapperEntity e = EntityLib.getApi().spawnEntity(EntityTypes.ARMOR_STAND, location);
         ArmorStandMeta meta = (ArmorStandMeta) e.getEntityMeta();
         meta.setCustomName(line);
         meta.setCustomNameVisible(true);
@@ -100,7 +96,7 @@ final class LegacyHologram<W> implements Hologram.Legacy<W> {
         meta.setSmall(true);
         meta.setMarker(marker);
         this.lines.set(index, e);
-        e.spawn(world, location);
+        e.spawn(location);
         teleport(location);
     }
 
@@ -133,8 +129,4 @@ final class LegacyHologram<W> implements Hologram.Legacy<W> {
         return location;
     }
 
-    @Override
-    public @NotNull WorldWrapper<W> getWorld() {
-        return world;
-    }
 }
diff --git a/api/src/main/java/me/tofaa/entitylib/wrapper/hologram/ModernHologram.java b/api/src/main/java/me/tofaa/entitylib/wrapper/hologram/ModernHologram.java
index 028fe51..5c35552 100644
--- a/api/src/main/java/me/tofaa/entitylib/wrapper/hologram/ModernHologram.java
+++ b/api/src/main/java/me/tofaa/entitylib/wrapper/hologram/ModernHologram.java
@@ -2,9 +2,8 @@ package me.tofaa.entitylib.wrapper.hologram;
 
 import com.github.retrooper.packetevents.protocol.entity.type.EntityTypes;
 import com.github.retrooper.packetevents.protocol.world.Location;
-import me.tofaa.entitylib.WorldWrapper;
+import me.tofaa.entitylib.EntityLib;
 import me.tofaa.entitylib.meta.display.TextDisplayMeta;
-import me.tofaa.entitylib.meta.other.ArmorStandMeta;
 import me.tofaa.entitylib.wrapper.WrapperEntity;
 import net.kyori.adventure.text.Component;
 import org.jetbrains.annotations.NotNull;
@@ -17,14 +16,13 @@ import java.util.function.Consumer;
 final class ModernHologram<W> implements Hologram.Modern<W> {
 
     private Location location;
-    private WorldWrapper<W> world;
     private List<WrapperEntity> lines = new ArrayList<>(3);
     private Consumer<TextDisplayMeta> modifier;
 
     @Override
     public void show() {
         for (WrapperEntity line : lines) {
-            line.spawn(world, location);
+            line.spawn(location);
         }
         teleport(location);
     }
@@ -41,7 +39,7 @@ final class ModernHologram<W> implements Hologram.Modern<W> {
         this.location = location;
         if (lines.isEmpty()) return;
         WrapperEntity first = lines.get(0);
-        first.teleport(world, location);
+        first.teleport(location);
         for (WrapperEntity e : lines) {
             if (e.getUuid().equals(first.getUuid())) continue;
             first.addPassenger(e);
@@ -58,14 +56,14 @@ final class ModernHologram<W> implements Hologram.Modern<W> {
 
     @Override
     public void setLine(int index, @Nullable Component line) {
-        WrapperEntity e = world.spawnEntity(EntityTypes.TEXT_DISPLAY, location);
+        WrapperEntity e = EntityLib.getApi().spawnEntity(EntityTypes.TEXT_DISPLAY, location);
         TextDisplayMeta meta = (TextDisplayMeta) e.getEntityMeta();
         meta.setInvisible(true);
         meta.setHasNoGravity(true);
         meta.setText(line);
         this.modifier.accept(meta);
         this.lines.set(index, e);
-        e.spawn(world, location);
+        e.spawn(location);
         teleport(location);
     }
 
@@ -85,11 +83,6 @@ final class ModernHologram<W> implements Hologram.Modern<W> {
         return location;
     }
 
-    @Override
-    public @NotNull WorldWrapper<W> getWorld() {
-        return world;
-    }
-
 
     @Override
     public void setModifier(@NotNull Consumer<TextDisplayMeta> consumer) {
diff --git a/common/src/main/java/me/tofaa/entitylib/common/AbstractEntityLibAPI.java b/common/src/main/java/me/tofaa/entitylib/common/AbstractEntityLibAPI.java
index aca7871..d6ab72d 100644
--- a/common/src/main/java/me/tofaa/entitylib/common/AbstractEntityLibAPI.java
+++ b/common/src/main/java/me/tofaa/entitylib/common/AbstractEntityLibAPI.java
@@ -1,24 +1,37 @@
 package me.tofaa.entitylib.common;
 
 import com.github.retrooper.packetevents.PacketEventsAPI;
+import com.github.retrooper.packetevents.protocol.entity.type.EntityType;
+import com.github.retrooper.packetevents.protocol.entity.type.EntityTypes;
+import com.github.retrooper.packetevents.protocol.player.UserProfile;
+import com.github.retrooper.packetevents.protocol.world.Location;
 import me.tofaa.entitylib.APIConfig;
+import me.tofaa.entitylib.EntityLib;
 import me.tofaa.entitylib.EntityLibAPI;
 import me.tofaa.entitylib.Platform;
+import me.tofaa.entitylib.meta.EntityMeta;
+import me.tofaa.entitylib.meta.projectile.ThrownExpBottleMeta;
+import me.tofaa.entitylib.meta.types.LivingEntityMeta;
 import me.tofaa.entitylib.tick.TickContainer;
 import me.tofaa.entitylib.wrapper.WrapperEntity;
+import me.tofaa.entitylib.wrapper.WrapperExperienceOrbEntity;
+import me.tofaa.entitylib.wrapper.WrapperLivingEntity;
+import me.tofaa.entitylib.wrapper.WrapperPlayer;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
 import java.util.*;
 import java.util.concurrent.ConcurrentHashMap;
 
-public abstract class AbstractEntityLibAPI<P, W, T> implements EntityLibAPI<W, T> {
+public abstract class AbstractEntityLibAPI<P, T> implements EntityLibAPI<T> {
 
     protected final Platform<P> platform;
     protected final PacketEventsAPI<?> packetEvents;
     protected final APIConfig settings;
     protected final Collection<TickContainer<?, T>> tickContainers;
     protected final Map<Integer, WrapperEntity> globalEntityMap = new ConcurrentHashMap<>();
+    protected final Map<Integer, WrapperEntity> entitiesById = new ConcurrentHashMap<>();
+    protected final Map<UUID, WrapperEntity> entities = new ConcurrentHashMap<>();
 
     protected AbstractEntityLibAPI(Platform<P> platform, APIConfig settings) {
         this.platform = platform;
@@ -27,20 +40,81 @@ public abstract class AbstractEntityLibAPI<P, W, T> implements EntityLibAPI<W, T
         this.tickContainers = settings.shouldTickTickables() ? new HashSet<>() : Collections.emptyList();
     }
 
+
     @Override
-    public @Nullable WrapperEntity findEntity(int entityId) {
-        return globalEntityMap.get(entityId);
+    public @NotNull WrapperPlayer spawnPlayer(UserProfile profile, Location location) {
+        if (getEntity(profile.getUUID()) != null) {
+            throw new IllegalArgumentException("Entity with UUID " + profile.getUUID() + " already exists in this world.");
+        }
+
+        int id = EntityLib.getPlatform().getEntityIdProvider().provide(profile.getUUID(), EntityTypes.PLAYER);
+        while (entitiesById.containsKey(id)) {
+            id = EntityLib.getPlatform().getEntityIdProvider().provide(profile.getUUID(), EntityTypes.PLAYER);
+        }
+        WrapperPlayer player = new WrapperPlayer(profile, id);
+        player.spawn(location);
+        entities.put(player.getUuid(), player);
+        entitiesById.put(player.getEntityId(), player);
+        return player;
     }
 
     @Override
-    public void globalRegisterEntity(WrapperEntity entity) {
-        if (globalEntityMap.containsKey(entity.getEntityId())) throw new IllegalArgumentException("Entity with that Id is already registered and present");
-        globalEntityMap.put(entity.getEntityId(), entity);
+    public <T1 extends WrapperEntity> @NotNull T1 spawnEntity(@NotNull T1 entity, @NotNull Location location) {
+        entity.spawn(location);
+        entities.put(entity.getUuid(), entity);
+        entitiesById.put(entity.getEntityId(), entity);
+        return entity;
     }
 
     @Override
-    public void globalUnregisterEntity(@NotNull WrapperEntity entity) {
-        globalEntityMap.remove(entity.getEntityId());
+    public void removeEntity(WrapperEntity entity) {
+        entity.despawn();
+        this.entities.remove(entity.getUuid());
+        this.entitiesById.remove(entity.getEntityId());
+    }
+
+    @Override
+    public <T1 extends WrapperEntity> @NotNull T1 spawnEntity(@NotNull Class<T1> wrapperClass, @NotNull EntityType entityType, @NotNull Location location) {
+        UUID uuid = EntityLib.getPlatform().getEntityUuidProvider().provide(entityType);
+        while (entities.containsKey(uuid)) {
+            uuid = EntityLib.getPlatform().getEntityUuidProvider().provide(entityType);
+        }
+        int entityId = EntityLib.getPlatform().getEntityIdProvider().provide(uuid, entityType);
+        while (entitiesById.containsKey(entityId)) {
+            entityId = EntityLib.getPlatform().getEntityIdProvider().provide(uuid, entityType);
+        }
+        EntityMeta meta = EntityMeta.createMeta(entityId, entityType);
+        WrapperEntity e;
+        if (meta instanceof LivingEntityMeta) {
+            e = new WrapperLivingEntity(entityId, uuid, entityType, meta);
+        }
+        else if (meta instanceof ThrownExpBottleMeta) {
+            e = new WrapperExperienceOrbEntity(entityId, uuid, entityType, meta);
+        }
+        else {
+            e = new WrapperEntity(entityId, uuid, entityType, meta);
+        }
+        return spawnEntity(wrapperClass.cast(e), location);
+    }
+
+    @Override
+    public @NotNull WrapperEntity spawnEntity(@NotNull EntityType entityType, @NotNull Location location) {
+        return spawnEntity(WrapperEntity.class, entityType, location);
+    }
+
+    @Override
+    public @Nullable WrapperEntity getEntity(int id) {
+        return entitiesById.get(id);
+    }
+
+    @Override
+    public @Nullable WrapperEntity getEntity(@NotNull UUID uuid) {
+        return entities.get(uuid);
+    }
+
+    @Override
+    public @NotNull Collection<WrapperEntity> getAllEntities() {
+        return Collections.unmodifiableCollection(entities.values());
     }
 
     @NotNull
diff --git a/common/src/main/java/me/tofaa/entitylib/common/AbstractWorldWrapper.java b/common/src/main/java/me/tofaa/entitylib/common/AbstractWorldWrapper.java
deleted file mode 100644
index 311c176..0000000
--- a/common/src/main/java/me/tofaa/entitylib/common/AbstractWorldWrapper.java
+++ /dev/null
@@ -1,136 +0,0 @@
-package me.tofaa.entitylib.common;
-
-import com.github.retrooper.packetevents.protocol.entity.type.EntityType;
-import com.github.retrooper.packetevents.protocol.entity.type.EntityTypes;
-import com.github.retrooper.packetevents.protocol.player.UserProfile;
-import com.github.retrooper.packetevents.protocol.world.Dimension;
-import com.github.retrooper.packetevents.protocol.world.Location;
-import me.tofaa.entitylib.EntityLib;
-import me.tofaa.entitylib.WorldWrapper;
-import me.tofaa.entitylib.meta.EntityMeta;
-import me.tofaa.entitylib.meta.projectile.ThrownExpBottleMeta;
-import me.tofaa.entitylib.meta.types.LivingEntityMeta;
-import me.tofaa.entitylib.meta.types.PlayerMeta;
-import me.tofaa.entitylib.wrapper.WrapperEntity;
-import me.tofaa.entitylib.wrapper.WrapperExperienceOrbEntity;
-import me.tofaa.entitylib.wrapper.WrapperLivingEntity;
-import me.tofaa.entitylib.wrapper.WrapperPlayer;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Map;
-import java.util.UUID;
-import java.util.concurrent.ConcurrentHashMap;
-
-public abstract class AbstractWorldWrapper<W> implements WorldWrapper<W> {
-
-    private final Map<UUID, WrapperEntity> entities;
-    private final Map<Integer, WrapperEntity> entitiesById;
-    private final Dimension dimension;
-    private final UUID worldId;
-    private final W handle;
-
-    public AbstractWorldWrapper(UUID worldId, W handle, Dimension dimension) {
-        this.worldId = worldId;
-        this.handle = handle;
-        this.dimension = dimension;
-        this.entities = new ConcurrentHashMap<>();
-        this.entitiesById = new ConcurrentHashMap<>();
-    }
-
-    @Override
-    public @NotNull WrapperPlayer spawnPlayer(UserProfile profile, Location location) {
-        if (getEntity(profile.getUUID()) != null) {
-            throw new IllegalArgumentException("Entity with UUID " + profile.getUUID() + " already exists in this world.");
-        }
-
-        int id = EntityLib.getPlatform().getEntityIdProvider().provide(profile.getUUID(), EntityTypes.PLAYER);
-        while (entitiesById.containsKey(id)) {
-            id = EntityLib.getPlatform().getEntityIdProvider().provide(profile.getUUID(), EntityTypes.PLAYER);
-        }
-        WrapperPlayer player = new WrapperPlayer(profile, id);
-        player.spawn(this, location);
-        entities.put(player.getUuid(), player);
-        entitiesById.put(player.getEntityId(), player);
-        EntityLib.getApi().globalRegisterEntity(player);
-        return player;
-    }
-
-    @Override
-    public <T extends WrapperEntity> @NotNull T spawnEntity(@NotNull T entity, @NotNull Location location) {
-        entity.spawn(this, location);
-        entities.put(entity.getUuid(), entity);
-        entitiesById.put(entity.getEntityId(), entity);
-        EntityLib.getApi().globalRegisterEntity(entity);
-        return entity;
-    }
-
-    @Override
-    public void removeEntity(WrapperEntity entity) {
-        entity.despawn();
-        this.entities.remove(entity.getUuid());
-        this.entitiesById.remove(entity.getEntityId());
-        EntityLib.getApi().globalUnregisterEntity(entity);
-    }
-
-    @Override
-    public <T extends WrapperEntity> @NotNull T spawnEntity(Class<T> wrapperClass, @NotNull EntityType entityType, @NotNull Location location) {
-        UUID uuid = EntityLib.getPlatform().getEntityUuidProvider().provide(entityType);
-        while (entities.containsKey(uuid)) {
-            uuid = EntityLib.getPlatform().getEntityUuidProvider().provide(entityType);
-        }
-        int entityId = EntityLib.getPlatform().getEntityIdProvider().provide(uuid, entityType);
-        while (entitiesById.containsKey(entityId)) {
-            entityId = EntityLib.getPlatform().getEntityIdProvider().provide(uuid, entityType);
-        }
-        EntityMeta meta = EntityMeta.createMeta(entityId, entityType);
-        WrapperEntity e;
-        if (meta instanceof LivingEntityMeta) {
-            e = new WrapperLivingEntity(entityId, uuid, entityType, meta);
-        }
-        else if (meta instanceof ThrownExpBottleMeta) {
-            e = new WrapperExperienceOrbEntity(entityId, uuid, entityType, meta);
-        }
-        else {
-            e = new WrapperEntity(entityId, uuid, entityType, meta);
-        }
-        return spawnEntity(wrapperClass.cast(e), location);
-    }
-
-    @Override
-    public @NotNull WrapperEntity spawnEntity(@NotNull EntityType entityType, @NotNull Location location) {
-        return spawnEntity(WrapperEntity.class, entityType, location);
-    }
-
-    @Override @Nullable
-    public WrapperEntity getEntity(@NotNull UUID uuid) {
-        return entities.get(uuid);
-    }
-
-    @Override @Nullable
-    public WrapperEntity getEntity(int id) {
-        return entitiesById.get(id);
-    }
-
-    @Override @NotNull
-    public Collection<WrapperEntity> getEntities() {
-        return Collections.unmodifiableCollection(entities.values());
-    }
-
-    @NotNull @Override
-    public Dimension getDimension() {
-        return dimension;
-    }
-
-    @Override @NotNull
-    public UUID getUuid() {
-        return worldId;
-    }
-
-    @NotNull @Override
-    public W getHandle() {
-        return handle;
-    }
-}
diff --git a/platforms/spigot/src/main/java/me/tofaa/entitylib/spigot/SpigotEntityLibAPI.java b/platforms/spigot/src/main/java/me/tofaa/entitylib/spigot/SpigotEntityLibAPI.java
index d6143e6..f32b86c 100644
--- a/platforms/spigot/src/main/java/me/tofaa/entitylib/spigot/SpigotEntityLibAPI.java
+++ b/platforms/spigot/src/main/java/me/tofaa/entitylib/spigot/SpigotEntityLibAPI.java
@@ -1,18 +1,33 @@
 package me.tofaa.entitylib.spigot;
 
+import com.github.retrooper.packetevents.protocol.entity.type.EntityType;
+import com.github.retrooper.packetevents.protocol.world.Location;
+import io.github.retrooper.packetevents.util.SpigotConversionUtil;
 import me.tofaa.entitylib.APIConfig;
-import me.tofaa.entitylib.WorldWrapper;
+import me.tofaa.entitylib.EntityLib;
 import me.tofaa.entitylib.common.AbstractEntityLibAPI;
+import me.tofaa.entitylib.meta.EntityMeta;
+import me.tofaa.entitylib.meta.types.LivingEntityMeta;
+import me.tofaa.entitylib.meta.types.PlayerMeta;
 import me.tofaa.entitylib.tick.TickContainer;
+import me.tofaa.entitylib.utils.Check;
+import me.tofaa.entitylib.wrapper.WrapperEntity;
+import me.tofaa.entitylib.wrapper.WrapperLivingEntity;
+import me.tofaa.entitylib.wrapper.WrapperPlayer;
+import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
 import org.bukkit.Bukkit;
 import org.bukkit.World;
+import org.bukkit.entity.Entity;
+import org.bukkit.entity.LivingEntity;
+import org.bukkit.entity.Player;
 import org.bukkit.plugin.java.JavaPlugin;
 import org.bukkit.scheduler.BukkitTask;
 import org.jetbrains.annotations.NotNull;
 
+import java.util.UUID;
 import java.util.logging.Level;
 
-public class SpigotEntityLibAPI extends AbstractEntityLibAPI<JavaPlugin, World, BukkitTask> {
+public class SpigotEntityLibAPI extends AbstractEntityLibAPI<JavaPlugin, BukkitTask> {
 
 
     SpigotEntityLibAPI(SpigotEntityLibPlatform platform, APIConfig settings) {
@@ -29,11 +44,51 @@ public class SpigotEntityLibAPI extends AbstractEntityLibAPI<JavaPlugin, World,
     }
 
     @Override
-    public @NotNull WorldWrapper<World> wrapWorld(World world) {
-        return new SpigotWorld(world);
+    public <T extends WrapperEntity> @NotNull T cloneEntity(@NotNull Object platformEntity, @NotNull Location location) {
+        Check.stateCondition(!(platformEntity instanceof Entity), "Entity must be a Bukkit entity");
+        Entity e = (Entity) platformEntity;
+        EntityType type = SpigotConversionUtil.fromBukkitEntityType(e.getType());
+        EntityMeta meta = EntityMeta.createMeta(e.getEntityId(), type);
+        meta.setHasNoGravity(!e.hasGravity());
+        meta.setCustomNameVisible(e.isCustomNameVisible());
+        meta.setCustomName(LegacyComponentSerializer.legacyAmpersand().deserialize(e.getCustomName()));
+        meta.setPose(ExtraConversionUtil.fromBukkitPose(e.getPose()));
+        meta.setOnFire(e.getFireTicks() > 0);
+        meta.setSilent(e.isSilent());
+        meta.setHasGlowingEffect(e.isGlowing());
+        if (e instanceof LivingEntity) {
+            LivingEntity le = (LivingEntity) e;
+            LivingEntityMeta lm = (LivingEntityMeta) meta;
+            lm.setHealth((float) le.getHealth());
+            lm.setFlyingWithElytra(le.isGliding());
+        }
+        if (e instanceof Player) {
+            Player p = (Player) e;
+            PlayerMeta pm = (PlayerMeta) meta;
+            pm.setSneaking(p.isSneaking());
+            pm.setSprinting(p.isSprinting());
+            pm.setSwimming(p.isSwimming());
+            pm.setActiveHand(ExtraConversionUtil.fromBukkitHand(p.getMainHand()));
+        }
+        WrapperEntity entity;
+        int id = EntityLib.getPlatform().getEntityIdProvider().provide(e.getUniqueId(), type);
+        UUID uuid = e.getUniqueId();
+        if (meta instanceof PlayerMeta) {
+            Player p = (Player) e;
+            entity = new WrapperPlayer(ExtraConversionUtil.fromBukkitPlayerProfile(p.getPlayerProfile()), id);
+        }
+        else if (meta instanceof LivingEntityMeta) {
+            entity = new WrapperLivingEntity(id, uuid, type, meta);
+        }
+        else {
+            entity = new WrapperEntity(id, uuid, type, meta);
+        }
+        if (entity == null) {
+            throw new IllegalArgumentException("Could not clone entity");
+        }
+        return (T) this.spawnEntity(entity, location);
     }
 
-
     @Override
     public void addTickContainer(@NotNull TickContainer<?, BukkitTask> tickContainer) {
         if (!settings.shouldTickTickables()) {
diff --git a/platforms/spigot/src/main/java/me/tofaa/entitylib/spigot/SpigotWorld.java b/platforms/spigot/src/main/java/me/tofaa/entitylib/spigot/SpigotWorld.java
deleted file mode 100644
index 2d57f89..0000000
--- a/platforms/spigot/src/main/java/me/tofaa/entitylib/spigot/SpigotWorld.java
+++ /dev/null
@@ -1,84 +0,0 @@
-package me.tofaa.entitylib.spigot;
-
-import com.github.retrooper.packetevents.protocol.entity.type.EntityType;
-import com.github.retrooper.packetevents.protocol.world.Location;
-import com.github.retrooper.packetevents.protocol.world.states.WrappedBlockState;
-import io.github.retrooper.packetevents.util.SpigotConversionUtil;
-import me.tofaa.entitylib.EntityLib;
-import me.tofaa.entitylib.common.AbstractWorldWrapper;
-import me.tofaa.entitylib.meta.EntityMeta;
-import me.tofaa.entitylib.meta.types.LivingEntityMeta;
-import me.tofaa.entitylib.meta.types.PlayerMeta;
-import me.tofaa.entitylib.utils.Check;
-import me.tofaa.entitylib.wrapper.WrapperEntity;
-import me.tofaa.entitylib.wrapper.WrapperLivingEntity;
-import me.tofaa.entitylib.wrapper.WrapperPlayer;
-import net.kyori.adventure.text.Component;
-import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
-import org.bukkit.World;
-import org.bukkit.entity.Entity;
-import org.bukkit.entity.LivingEntity;
-import org.bukkit.entity.Player;
-import org.jetbrains.annotations.NotNull;
-
-import java.util.UUID;
-
-public class SpigotWorld extends AbstractWorldWrapper<World> {
-
-
-    SpigotWorld(World world) {
-        super(world.getUID(), world, SpigotConversionUtil.fromBukkitWorld(world));
-    }
-
-
-    @Override
-    public <T extends WrapperEntity> @NotNull T cloneEntity(@NotNull Object platformEntity, @NotNull Location location) {
-        Check.stateCondition(!(platformEntity instanceof Entity), "Entity must be a Bukkit entity");
-        Entity e = (Entity) platformEntity;
-        EntityType type = SpigotConversionUtil.fromBukkitEntityType(e.getType());
-        EntityMeta meta = EntityMeta.createMeta(e.getEntityId(), type);
-        meta.setHasNoGravity(!e.hasGravity());
-        meta.setCustomNameVisible(e.isCustomNameVisible());
-        meta.setCustomName(LegacyComponentSerializer.legacyAmpersand().deserialize(e.getCustomName()));
-        meta.setPose(ExtraConversionUtil.fromBukkitPose(e.getPose()));
-        meta.setOnFire(e.getFireTicks() > 0);
-        meta.setSilent(e.isSilent());
-        meta.setHasGlowingEffect(e.isGlowing());
-        if (e instanceof LivingEntity) {
-            LivingEntity le = (LivingEntity) e;
-            LivingEntityMeta lm = (LivingEntityMeta) meta;
-            lm.setHealth((float) le.getHealth());
-            lm.setFlyingWithElytra(le.isGliding());
-        }
-        if (e instanceof Player) {
-            Player p = (Player) e;
-            PlayerMeta pm = (PlayerMeta) meta;
-            pm.setSneaking(p.isSneaking());
-            pm.setSprinting(p.isSprinting());
-            pm.setSwimming(p.isSwimming());
-            pm.setActiveHand(ExtraConversionUtil.fromBukkitHand(p.getMainHand()));
-        }
-        WrapperEntity entity;
-        int id = EntityLib.getPlatform().getEntityIdProvider().provide(e.getUniqueId(), type);
-        UUID uuid = e.getUniqueId();
-        if (meta instanceof PlayerMeta) {
-            Player p = (Player) e;
-            entity = new WrapperPlayer(ExtraConversionUtil.fromBukkitPlayerProfile(p.getPlayerProfile()), id);
-        }
-        else if (meta instanceof LivingEntityMeta) {
-            entity = new WrapperLivingEntity(id, uuid, type, meta);
-        }
-        else {
-            entity = new WrapperEntity(id, uuid, type, meta);
-        }
-        if (entity == null) {
-            throw new IllegalArgumentException("Could not clone entity");
-        }
-        return (T) this.spawnEntity(entity, location);
-    }
-
-    @Override
-    public WrappedBlockState getBlock(int x, int y, int z) {
-        return SpigotConversionUtil.fromBukkitBlockData(getHandle().getBlockData(new org.bukkit.Location(getHandle(), x, y, z)));
-    }
-}
diff --git a/src/.gitignore b/src/.gitignore
deleted file mode 100644
index b63da45..0000000
--- a/src/.gitignore
+++ /dev/null
@@ -1,42 +0,0 @@
-.gradle
-build/
-!gradle/wrapper/gradle-wrapper.jar
-!**/src/main/**/build/
-!**/src/test/**/build/
-
-### IntelliJ IDEA ###
-.idea/modules.xml
-.idea/jarRepositories.xml
-.idea/compiler.xml
-.idea/libraries/
-*.iws
-*.iml
-*.ipr
-out/
-!**/src/main/**/out/
-!**/src/test/**/out/
-
-### Eclipse ###
-.apt_generated
-.classpath
-.factorypath
-.project
-.settings
-.springBeans
-.sts4-cache
-bin/
-!**/src/main/**/bin/
-!**/src/test/**/bin/
-
-### NetBeans ###
-/nbproject/private/
-/nbbuild/
-/dist/
-/nbdist/
-/.nb-gradle/
-
-### VS Code ###
-.vscode/
-
-### Mac OS ###
-.DS_Store
\ No newline at end of file
diff --git a/src/main/java/me/tofaa/entitylib/EntityLib.java b/src/main/java/me/tofaa/entitylib/EntityLib.java
deleted file mode 100644
index b04d0a0..0000000
--- a/src/main/java/me/tofaa/entitylib/EntityLib.java
+++ /dev/null
@@ -1,316 +0,0 @@
-package me.tofaa.entitylib;
-
-import com.github.retrooper.packetevents.PacketEventsAPI;
-import com.github.retrooper.packetevents.event.PacketListenerAbstract;
-import com.github.retrooper.packetevents.event.PacketReceiveEvent;
-import com.github.retrooper.packetevents.manager.server.ServerVersion;
-import com.github.retrooper.packetevents.protocol.entity.type.EntityType;
-import com.github.retrooper.packetevents.protocol.entity.type.EntityTypes;
-import com.github.retrooper.packetevents.protocol.packettype.PacketType;
-import com.github.retrooper.packetevents.protocol.player.InteractionHand;
-import com.github.retrooper.packetevents.protocol.player.User;
-import com.github.retrooper.packetevents.wrapper.PacketWrapper;
-import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientInteractEntity;
-import me.tofaa.entitylib.entity.*;
-import me.tofaa.entitylib.exception.InvalidVersionException;
-import me.tofaa.entitylib.meta.EntityMeta;
-import me.tofaa.entitylib.meta.Metadata;
-import me.tofaa.entitylib.meta.types.LivingEntityMeta;
-import org.jetbrains.annotations.ApiStatus;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-import java.util.HashMap;
-import java.util.Map;
-import java.util.UUID;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.function.BiFunction;
-
-/**
- * Base API class for EntityLib, contains all the methods to interact with the library.
- * <p>
- *     Initialization should be done before PacketEvents. After PE is initialized, call {@link EntityLib#init(PacketEventsAPI)} to initialize EntityLib.
- *     <br>
- *     To enable entity interactions, call {@link EntityLib#enableEntityInteractions()}. these will help you interact with a {@link WrapperEntity} object.
- *     <br>
- *     By default, EntityLib does not persistently store data, this is planned for a future feature but for now you must store your own data if you want it to persist after restart.
- * <p>
- */
-public final class EntityLib {
-
-    private EntityLib() {}
-    private static final HashMap<Integer, EntityMeta> metadata = new HashMap<>();
-    private static final Map<UUID, WrapperEntity> entities = new ConcurrentHashMap<>();
-    private static final Map<Integer, WrapperEntity> entitiesById = new ConcurrentHashMap<>();
-    private static EntityInteractionProcessor interactionProcessor;
-    private static boolean initialized = false;
-    private static PacketEventsAPI<?> packetEvents;
-    private static MetaConverterRegistry metaRegistry;
-    private static EntityIdProvider entityIdProvider = EntityIdProvider.simple();
-
-    /**
-     * Initialize EntityLib.
-     * <p>
-     *     This method should be called after PacketEvents is initialized.
-     *     Loads the internal metadata converter registry and sets the library usable
-     * </p>
-     * @param packetEvents PacketEventsAPI instance
-     */
-    public static void init(@NotNull PacketEventsAPI<?> packetEvents) {
-        if (initialized) {
-            throw new IllegalStateException("EntityLib is already initialized");
-        }
-        initialized = true;
-        EntityLib.packetEvents = packetEvents;
-        if (!packetEvents.isInitialized()) {
-            initialized = false;
-            throw new IllegalStateException("PacketEvents is not initialized");
-        }
-        metaRegistry = new MetaConverterRegistry();
-    }
-
-    /**
-     * Enable entity interactions.
-     * <p>
-     *     Enables entity interactions to be handled by EntityLib, rather than the developer.
-     *     <br>
-     *     This will register a PacketEvents listener for {@link PacketType.Play.Client#INTERACT_ENTITY} and call {@link EntityInteractionProcessor#process(WrapperEntity, WrapperPlayClientInteractEntity.InteractAction, InteractionHand, User)}.
-     *     <br>
-     *     To set the interaction processor, call {@link EntityLib#setInteractionProcessor(EntityInteractionProcessor)}.
-     * </p>
-     */
-    public static void enableEntityInteractions() {
-        checkInit();
-        packetEvents.getEventManager().registerListener(new PacketListenerAbstract() {
-            @Override
-            public void onPacketReceive(PacketReceiveEvent event) {
-                if (interactionProcessor == null) return;
-                if (event.getPacketType() != PacketType.Play.Client.INTERACT_ENTITY) return;
-                WrapperPlayClientInteractEntity packet = new WrapperPlayClientInteractEntity(event);
-                WrapperEntity entity = getEntity(packet.getEntityId());
-                if (entity == null) return;
-                interactionProcessor.process(
-                        entity, packet.getAction(), packet.getHand(), event.getUser()
-                );
-            }
-        });
-    }
-
-    /**
-     * @param entityId the entity id
-     * @return the entity with the given id, or null if an entity with that id does not exist
-     */
-    public static @Nullable WrapperEntity getEntity(int entityId) {
-        checkInit();
-        return entitiesById.get(entityId);
-    }
-
-    /**
-     * @param uuid the entity uuid
-     * @return the entity with the given uuid, or null if an entity with that uuid does not exist
-     */
-    public static @Nullable WrapperEntity getEntity(UUID uuid) {
-        checkInit();
-        return entities.get(uuid);
-    }
-
-    /**
-     * Registers a custom entity to EntityLib. This exists to allow developers to extend {@link WrapperEntity} and its subclasses simply and define their own logic.
-     * <p>
-     *     This method DOES NOT create a new entity, it simply registers the entity to EntityLib.
-     *     To construct a {@link WrapperEntity} you need to call {@link EntityLib#createMeta(int, EntityType)} and pass the created metadata to the constructor of the entity.
-     *     <br>
-     *     This method will throw a RuntimeException if an entity with the given uuid or id already exists.
-     *     <br>
-     *     The entity is not modified in any way, simply stored internally for it to be accessible thru {@link EntityLib#getEntity(UUID)} and {@link EntityLib#getEntity(int)}.
-     *     </p>
-     * @param entity the entity to register
-     * @return the same entity passed.
-     * @param <T> instance of WrapperEntity, used to infer its type.
-     */
-    public static @NotNull <T extends WrapperEntity> T register(@NotNull T entity) {
-        checkInit();
-        if (entities.containsKey(entity.getUuid())) throw new RuntimeException("An entity with that uuid already exists");
-        if (entitiesById.containsKey(entity.getEntityId())) throw new RuntimeException("An entity with that id already exists");
-        entities.put(entity.getUuid(), entity);
-        entitiesById.put(entity.getEntityId(), entity);
-        return entity;
-    }
-
-    /**
-     * Creates a new WrapperEntity with the given UUID and EntityType.
-     * This method will automatically create a new EntityMeta for the entity and keeps track of it internally.
-     * To get the entity, use {@link EntityLib#getEntity(UUID)} or {@link EntityLib#getEntity(int)}.
-     * <p>
-     * In theoretically impossible cases, this method may return null.
-     * @param uuid the entity uuid
-     * @param entityType the entity type
-     * @return the created entity, or null if the entity could not be created
-     */
-    public static @NotNull WrapperEntity createEntity(int entityId, UUID uuid, EntityType entityType) {
-        checkInit();
-        if (entities.containsKey(uuid)) throw new RuntimeException("An entity with that uuid already exists");
-        if (entitiesById.containsKey(entityId)) throw new RuntimeException("An entity with that id already exists");
-        EntityMeta meta = createMeta(entityId, entityType);
-        WrapperEntity entity;
-        if (meta instanceof LivingEntityMeta) {
-            entity = new WrapperLivingEntity(entityId, uuid, entityType, meta);
-        }
-        else if (entityType == EntityTypes.EXPERIENCE_ORB) {
-            entity = new WrapperExperienceOrbEntity(entityId, uuid, entityType, meta);
-        }
-        else {
-            entity = new WrapperEntity(entityId, uuid, entityType, meta);
-        }
-        entities.put(uuid, entity);
-        entitiesById.put(entityId, entity);
-        return entity;
-    }
-
-    public static @NotNull WrapperEntity createEntity(@NotNull UUID uuid, EntityType entityType) {
-        return createEntity(entityIdProvider.provide(), uuid, entityType);
-    }
-
-    public static @NotNull WrapperEntityCreature createEntityCreature(int entityId, @NotNull UUID uuid, @NotNull EntityType entityType) {
-        checkInit();
-        if (entities.containsKey(uuid)) throw new RuntimeException("An entity with that uuid already exists");
-        if (entitiesById.containsKey(entityId)) throw new RuntimeException("An entity with that id already exists");
-        EntityMeta meta = createMeta(entityId, entityType);
-        if (!(meta instanceof LivingEntityMeta)) {
-            throw new RuntimeException("Entity type " + entityType + " is not a living entity, EntityCreature requires a living entity");
-        }
-        WrapperEntityCreature entity = new WrapperEntityCreature(entityId, uuid, entityType, meta);
-        entities.put(uuid, entity);
-        entitiesById.put(entityId, entity);
-        return entity;
-    }
-
-    public static @NotNull WrapperEntityCreature createEntityCreature(@NotNull UUID uuid, @NotNull EntityType entityType) {
-        return createEntityCreature(entityIdProvider.provide(), uuid, entityType);
-    }
-
-    /**
-     * @param entityId the entity id
-     * @return the metadata of the entity with the given id. If the entity does not exist, this method will return null.
-     */
-    public static @Nullable EntityMeta getMeta(int entityId) {
-        checkInit();
-        return metadata.get(entityId);
-    }
-
-    /**
-     * @param entityId the entity id
-     * @param metaClass the metadata class to cast to
-     * @return the metadata of the entity with the given id, cast to the given class. If the entity does not exist, this method will return null.
-     * @param <T> the metadata class
-     */
-    public static <T extends EntityMeta> @Nullable T getMeta(int entityId, Class<T> metaClass) {
-        checkInit();
-        EntityMeta meta = metadata.get(entityId);
-        if (meta == null) {
-            return null;
-        }
-        if (metaClass.isAssignableFrom(meta.getClass())) {
-            return (T) meta;
-        }
-        return null;
-    }
-
-    /**
-     * Creates a new EntityMeta for the given entity id and type, these are stored internally and can be retrieved using {@link EntityLib#getMeta(int)}.
-     * @param entityId the entity id
-     * @param entityType the entity type
-     * @return the created EntityMeta
-     */
-    public static @NotNull EntityMeta createMeta(int entityId, EntityType entityType) {
-        checkInit();
-        Metadata m = new Metadata(entityId);
-        BiFunction<Integer, Metadata, EntityMeta> function = metaRegistry.get(entityType);
-        EntityMeta meta = function.apply(entityId, m);
-        metadata.put(entityId, meta);
-        return meta;
-    }
-
-    /**
-     * Creates a new EntityMeta for an entity, these are stored internally and can be retrieved using {@link EntityLib#getMeta(int)}.
-     * @param entity the entity
-     * @return the created EntityMeta
-     */
-    public static EntityMeta createMeta(WrapperEntity entity) {
-        return createMeta(entity.getEntityId(), entity.getEntityType());
-    }
-
-    /**
-     * @param entityType the entity type
-     * @return the metadata class of the given entity type
-     * @param <T> gets the appropriate metadata class for the given entity type
-     */
-    public static <T extends EntityMeta> Class<T> getMetaClassOf(EntityType entityType) {
-        return metaRegistry.getMetaClass(entityType);
-    }
-
-    /**
-     * @return the packet events api instance that was used to initialize EntityLib
-     */
-    public static PacketEventsAPI<?> getPacketEvents() {
-        checkInit();
-        return packetEvents;
-    }
-
-    /**
-     * @return the specified interaction processor, or null if none is specified
-     */
-    public static @Nullable EntityInteractionProcessor getInteractionProcessor() {
-        return interactionProcessor;
-    }
-
-    /**
-     * Sets the interaction processor to the given one.
-     * @param interactionProcessor the interaction processor
-     */
-    public static void setInteractionProcessor(EntityInteractionProcessor interactionProcessor) {
-        EntityLib.interactionProcessor = interactionProcessor;
-    }
-
-    /**
-     * @return the entity id provider
-     */
-    public static EntityIdProvider getEntityIdProvider() {
-        return entityIdProvider;
-    }
-
-    /**
-     * Sets the entity id provider to the given one.
-     * @param entityIdProvider the entity id provider. The default implementation can be found at {@link me.tofaa.entitylib.entity.EntityIdProvider#simple()}
-     */
-    public static void setEntityIdProvider(EntityIdProvider entityIdProvider) {
-        EntityLib.entityIdProvider = entityIdProvider;
-    }
-
-    /**
-     * Another internal method to verify the server version is supported. Safe to use externally as its purpose is simple and to avoid code duplication
-     */
-    @ApiStatus.Internal
-    public static void verifyVersion(ServerVersion supported, String msg) {
-        if (packetEvents.getServerManager().getVersion().isOlderThan(supported)) {
-            throw new InvalidVersionException(msg);
-        }
-    }
-
-    /**
-     * A primarily internal method to send a packet wrapper to a User from the users UUID. This is useful for methods in {@link WrapperEntity}. Safe to use externally as its purpose is simple and to avoid code duplication
-     * @param user the user uuid
-     * @param wrapper  the packet wrapper
-     */
-    @ApiStatus.Internal
-    public static void sendPacket(UUID user, PacketWrapper<?> wrapper) {
-        checkInit();
-        packetEvents.getProtocolManager().sendPacket(packetEvents.getProtocolManager().getChannel(user), wrapper);
-    }
-
-    private static void checkInit() {
-        if (!initialized) {
-            throw new IllegalStateException("EntityLib is not initialized");
-        }
-    }
-}
diff --git a/src/main/java/me/tofaa/entitylib/EntityLibPlatform.java b/src/main/java/me/tofaa/entitylib/EntityLibPlatform.java
deleted file mode 100644
index 2901424..0000000
--- a/src/main/java/me/tofaa/entitylib/EntityLibPlatform.java
+++ /dev/null
@@ -1,15 +0,0 @@
-package me.tofaa.entitylib;
-
-import com.github.retrooper.packetevents.PacketEventsAPI;
-import org.jetbrains.annotations.NotNull;
-
-import java.util.UUID;
-
-public interface EntityLibPlatform<W> {
-
-    @NotNull PacketEventsAPI<?> getPacketEvents();
-
-    @NotNull WrapperWorld<W> createWorld(UUID uuid, String name);
-
-
-}
diff --git a/src/main/java/me/tofaa/entitylib/MetaConverterRegistry.java b/src/main/java/me/tofaa/entitylib/MetaConverterRegistry.java
deleted file mode 100644
index dc41653..0000000
--- a/src/main/java/me/tofaa/entitylib/MetaConverterRegistry.java
+++ /dev/null
@@ -1,175 +0,0 @@
-package me.tofaa.entitylib;
-
-import com.github.retrooper.packetevents.protocol.entity.type.EntityType;
-import me.tofaa.entitylib.meta.EntityMeta;
-import me.tofaa.entitylib.meta.Metadata;
-import me.tofaa.entitylib.meta.display.BlockDisplayMeta;
-import me.tofaa.entitylib.meta.display.ItemDisplayMeta;
-import me.tofaa.entitylib.meta.display.TextDisplayMeta;
-import me.tofaa.entitylib.meta.mobs.*;
-import me.tofaa.entitylib.meta.mobs.DonkeyMeta;
-import me.tofaa.entitylib.meta.mobs.cuboid.MagmaCubeMeta;
-import me.tofaa.entitylib.meta.mobs.cuboid.SlimeMeta;
-import me.tofaa.entitylib.meta.mobs.golem.IronGolemMeta;
-import me.tofaa.entitylib.meta.mobs.golem.ShulkerMeta;
-import me.tofaa.entitylib.meta.mobs.golem.SnowGolemMeta;
-import me.tofaa.entitylib.meta.mobs.horse.*;
-import me.tofaa.entitylib.meta.mobs.monster.*;
-import me.tofaa.entitylib.meta.mobs.monster.piglin.PiglinBruteMeta;
-import me.tofaa.entitylib.meta.mobs.monster.piglin.PiglinMeta;
-import me.tofaa.entitylib.meta.mobs.monster.raider.*;
-import me.tofaa.entitylib.meta.mobs.monster.skeleton.SkeletonMeta;
-import me.tofaa.entitylib.meta.mobs.monster.skeleton.StrayMeta;
-import me.tofaa.entitylib.meta.mobs.monster.skeleton.WitherSkeletonMeta;
-import me.tofaa.entitylib.meta.mobs.monster.zombie.*;
-import me.tofaa.entitylib.meta.mobs.passive.*;
-import me.tofaa.entitylib.meta.mobs.water.*;
-import me.tofaa.entitylib.meta.mobs.minecart.*;
-import me.tofaa.entitylib.meta.mobs.tameable.CatMeta;
-import me.tofaa.entitylib.meta.mobs.tameable.ParrotMeta;
-import me.tofaa.entitylib.meta.mobs.tameable.WolfMeta;
-import me.tofaa.entitylib.meta.mobs.villager.VillagerMeta;
-import me.tofaa.entitylib.meta.mobs.villager.WanderingTraderMeta;
-import me.tofaa.entitylib.meta.other.*;
-import me.tofaa.entitylib.meta.projectile.*;
-import me.tofaa.entitylib.meta.types.PlayerMeta;
-import org.jetbrains.annotations.NotNull;
-
-import java.util.HashMap;
-import java.util.Map;
-import java.util.function.BiFunction;
-
-import static com.github.retrooper.packetevents.protocol.entity.type.EntityTypes.*;
-
-@SuppressWarnings("unchecked")
-final class MetaConverterRegistry {
-
-    private final Map<EntityType, BiFunction<Integer, Metadata, EntityMeta>> converters = new HashMap<>();
-    private final Map<EntityType, Class<? extends EntityMeta>> metaClasses = new HashMap<>();
-
-    MetaConverterRegistry() {
-        put(SNIFFER, SnifferMeta.class, SnifferMeta::new);
-        put(INTERACTION, InteractionMeta.class, InteractionMeta::new);
-        put(BLOCK_DISPLAY, BlockDisplayMeta.class, BlockDisplayMeta::new);
-        put(ITEM_DISPLAY, ItemDisplayMeta.class, ItemDisplayMeta::new);
-        put(TEXT_DISPLAY, TextDisplayMeta.class, TextDisplayMeta::new);
-        put(AREA_EFFECT_CLOUD, AreaEffectCloudMeta.class, AreaEffectCloudMeta::new);
-        put(ARMOR_STAND, ArmorStandMeta.class, ArmorStandMeta::new);
-        put(BOAT, BoatMeta.class, BoatMeta::new);
-        put(DRAGON_FIREBALL, DragonFireballMeta.class, DragonFireballMeta::new);
-        put(END_CRYSTAL, EndCrystalMeta.class, EndCrystalMeta::new);
-        put(ENDER_DRAGON, EnderDragonMeta.class, EnderDragonMeta::new);
-        put(EVOKER_FANGS, EvokerFangsMeta.class, EvokerFangsMeta::new);
-        put(FALLING_BLOCK, FallingBlockMeta.class, FallingBlockMeta::new);
-        put(FIREWORK_ROCKET, FireworkRocketMeta.class, FireworkRocketMeta::new);
-        put(FISHING_BOBBER, FishingHookMeta.class, FishingHookMeta::new);
-        put(GLOW_ITEM_FRAME, GlowItemFrameMeta.class, GlowItemFrameMeta::new);
-        put(ITEM_FRAME, ItemFrameMeta.class, ItemFrameMeta::new);
-        put(LEASH_KNOT, LeashKnotMeta.class, LeashKnotMeta::new);
-        put(LIGHTNING_BOLT, LightningBoltMeta.class, LightningBoltMeta::new);
-        put(LLAMA_SPIT, LlamaSpitMeta.class, LlamaSpitMeta::new);
-        put(MARKER, MarkerMeta.class, MarkerMeta::new);
-        put(PAINTING, PaintingMeta.class, PaintingMeta::new);
-        put(PRIMED_TNT, PrimedTntMeta.class, PrimedTntMeta::new);
-        put(WITHER_SKULL, WitherSkullMeta.class, WitherSkullMeta::new);
-        put(ZOGLIN, ZoglinMeta.class, ZoglinMeta::new);
-        put(WITHER, WitherMeta.class, WitherMeta::new);
-        put(VEX, VexMeta.class, VexMeta::new);
-        put(SPIDER, SpiderMeta.class, SpiderMeta::new);
-        put(SILVERFISH, SilverfishMeta.class, SilverfishMeta::new);
-        put(GUARDIAN, GuardianMeta.class, GuardianMeta::new);
-        put(GIANT, GiantMeta.class, GiantMeta::new);
-        put(ENDERMITE, EndermiteMeta.class, EndermiteMeta::new);
-        put(ENDERMITE, EndermiteMeta.class, EndermiteMeta::new);
-        put(ELDER_GUARDIAN, ElderGuardianMeta.class, ElderGuardianMeta::new);
-        put(CREEPER, CreeperMeta.class, CreeperMeta::new);
-        put(CAVE_SPIDER, CaveSpiderMeta.class, CaveSpiderMeta::new);
-        put(BLAZE, BlazeMeta.class, BlazeMeta::new);
-        put(PIGLIN, PiglinMeta.class, PiglinMeta::new);
-        put(PIGLIN_BRUTE, PiglinBruteMeta.class, PiglinBruteMeta::new);
-        put(EVOKER, EvokerMeta.class, EvokerMeta::new);
-        put(ILLUSIONER, IllusionerMeta.class, IllusionerMeta::new);
-        put(PILLAGER, PillagerMeta.class, PillagerMeta::new);
-        put(RAVAGER, RavagerMeta.class, RavagerMeta::new);
-        put(VINDICATOR, VindicatorMeta.class, VindicatorMeta::new);
-        put(WITCH, WitchMeta.class, WitchMeta::new);
-        put(SKELETON, SkeletonMeta.class, SkeletonMeta::new);
-        put(STRAY, StrayMeta.class, StrayMeta::new);
-        put(WITHER_SKELETON, WitherSkeletonMeta.class, WitherSkeletonMeta::new);
-        put(DROWNED, DrownedMeta.class, DrownedMeta::new);
-        put(HUSK, HuskMeta.class, HuskMeta::new);
-        put(ZOMBIE, ZombieMeta.class, ZombieMeta::new);
-        put(ZOMBIE_VILLAGER, ZombieVillagerMeta.class, ZombieVillagerMeta::new);
-        put(ZOMBIFIED_PIGLIN, ZombifiedPiglinMeta.class, ZombifiedPiglinMeta::new);
-        put(AXOLOTL, AxolotlMeta.class, AxolotlMeta::new);
-        put(COD, CodMeta.class, CodMeta::new);
-        put(DOLPHIN, DolphinMeta.class, DolphinMeta::new);
-        put(GLOW_SQUID, GlowSquidMeta.class, GlowSquidMeta::new);
-        put(PUFFERFISH, PufferFishMeta.class, PufferFishMeta::new);
-        put(SALMON, SalmonMeta.class, SalmonMeta::new);
-        put(TROPICAL_FISH, TropicalFishMeta.class, TropicalFishMeta::new);
-        put(ARROW, ArrowMeta.class, ArrowMeta::new);
-        put(VILLAGER, VillagerMeta.class, VillagerMeta::new);
-        put(WANDERING_TRADER, WanderingTraderMeta.class, WanderingTraderMeta::new);
-        put(CHEST_MINECART, ChestMinecartMeta.class, ChestMinecartMeta::new);
-        put(COMMAND_BLOCK_MINECART, CommandBlockMinecartMeta.class, CommandBlockMinecartMeta::new);
-        put(COMMAND_BLOCK_MINECART, CommandBlockMinecartMeta.class, CommandBlockMinecartMeta::new);
-        put(FURNACE_MINECART, FurnaceMinecartMeta.class, FurnaceMinecartMeta::new);
-        put(HOPPER_MINECART, FurnaceMinecartMeta.class, FurnaceMinecartMeta::new);
-        put(SPAWNER_MINECART, SpawnerMinecartMeta.class, SpawnerMinecartMeta::new);
-        put(TNT_MINECART, TntMinecartMeta.class, TntMinecartMeta::new);
-        put(PLAYER, PlayerMeta.class, PlayerMeta::new);
-        put(THROWN_EXP_BOTTLE, ThrownExpBottleMeta.class, ThrownExpBottleMeta::new);
-        put(EGG, ThrownEggMeta.class, ThrownEggMeta::new);
-        put(TRIDENT, ThrownTridentMeta.class, ThrownTridentMeta::new);
-        put(POTION, ThrownTridentMeta.class, ThrownTridentMeta::new);
-        put(SMALL_FIREBALL, SmallFireballMeta.class, SmallFireballMeta::new);
-        put(PIG, PigMeta.class, PigMeta::new);
-        put(COW, CowMeta.class, CowMeta::new);
-        put(CHICKEN, ChickenMeta.class, ChickenMeta::new);
-        put(BEE, BeeMeta.class, BeeMeta::new);
-        put(TURTLE, TurtleMeta.class, TurtleMeta::new);
-        put(DONKEY, DonkeyMeta.class, DonkeyMeta::new);
-        put(SHEEP, SheepMeta.class, SheepMeta::new);
-        put(RABBIT, RabbitMeta.class, RabbitMeta::new);
-        put(POLAR_BEAR, PolarBearMeta.class, PolarBearMeta::new);
-        put(OCELOT, OcelotMeta.class, OcelotMeta::new );
-        put(PANDA, PandaMeta.class, PandaMeta::new);
-        put(STRIDER, StriderMeta.class, StriderMeta::new);
-        put(FOX, FoxMeta.class, FoxMeta::new);
-        put(FROG, FrogMeta.class, FrogMeta::new);
-        put(GOAT, GoatMeta.class, GoatMeta::new);
-        put(HOGLIN, HoglinMeta.class, HoglinMeta::new);
-        put(CAT, CatMeta.class, CatMeta::new);
-        put(PARROT, ParrotMeta.class, ParrotMeta::new);
-        put(WOLF, WolfMeta.class, WolfMeta::new);
-        put(DONKEY, DonkeyMeta.class, DonkeyMeta::new);
-        put(HORSE, HorseMeta.class, HorseMeta::new);
-        put(LLAMA, LlamaMeta.class, LlamaMeta::new);
-        put(MULE, MuleMeta.class, MuleMeta::new);
-        put(SKELETON_HORSE, SkeletonHorseMeta.class, SkeletonHorseMeta::new);
-        put(ZOMBIE_HORSE, ZombieHorseMeta.class, ZombieHorseMeta::new);
-        put(SLIME, SlimeMeta.class, SlimeMeta::new);
-        put(MAGMA_CUBE, MagmaCubeMeta.class, MagmaCubeMeta::new);
-        put(SHULKER_BULLET, ShulkerBulletMeta.class, ShulkerBulletMeta::new);
-        put(TRADER_LLAMA, TraderLlamaMeta.class, TraderLlamaMeta::new);
-        put(BAT, BatMeta.class, BatMeta::new);
-        put(IRON_GOLEM, IronGolemMeta.class, IronGolemMeta::new);
-        put(SHULKER, ShulkerMeta.class, ShulkerMeta::new);
-        put(SNOW_GOLEM, SnowGolemMeta.class, SnowGolemMeta::new);
-    }
-
-    private void put(EntityType entityType, Class<? extends EntityMeta> metaClass, BiFunction<Integer, Metadata, EntityMeta> function) {
-        converters.put(entityType, function);
-        metaClasses.put(entityType, metaClass);
-    }
-
-    public <T extends EntityMeta> Class<T> getMetaClass(EntityType entityType) {
-        return (Class<T>) metaClasses.get(entityType);
-    }
-
-    public @NotNull BiFunction<Integer, Metadata, EntityMeta> get(EntityType entityType) {
-        return converters.getOrDefault(entityType, EntityMeta::new);
-    }
-
-}
diff --git a/src/main/java/me/tofaa/entitylib/Tickable.java b/src/main/java/me/tofaa/entitylib/Tickable.java
deleted file mode 100644
index b1690f0..0000000
--- a/src/main/java/me/tofaa/entitylib/Tickable.java
+++ /dev/null
@@ -1,12 +0,0 @@
-package me.tofaa.entitylib;
-
-public interface Tickable {
-
-    /** Internal method for actual logic ticking, if you want to add custom logic to your entity, override {@link #tick(long)} instead. */
-    default void update(long time) {
-
-    }
-
-    void tick(long time);
-
-}
diff --git a/src/main/java/me/tofaa/entitylib/TickingContainer.java b/src/main/java/me/tofaa/entitylib/TickingContainer.java
deleted file mode 100644
index 535608b..0000000
--- a/src/main/java/me/tofaa/entitylib/TickingContainer.java
+++ /dev/null
@@ -1,22 +0,0 @@
-package me.tofaa.entitylib;
-
-/**
- * A container that can hold and tick {@link Tickable}s.
- * This is for specific users to extend if they want ticking functionality.
- *
- */
-public interface TickingContainer {
-
-    void addTickable(Tickable tickable);
-
-    void removeTickable(Tickable tickable);
-
-    default void update(long time) {
-        for (Tickable tickable : getTickables()) {
-            tickable.update(time);
-        }
-    }
-
-    Iterable<Tickable> getTickables();
-
-}
diff --git a/src/main/java/me/tofaa/entitylib/WrapperWorld.java b/src/main/java/me/tofaa/entitylib/WrapperWorld.java
deleted file mode 100644
index 5ed747c..0000000
--- a/src/main/java/me/tofaa/entitylib/WrapperWorld.java
+++ /dev/null
@@ -1,25 +0,0 @@
-package me.tofaa.entitylib;
-
-import me.tofaa.entitylib.entity.WrapperEntity;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-import java.util.UUID;
-
-/**
- * A platform independent wrapper for a "world" object.
- * @param <W> The generic takes the actual world handle used by the platform.
- */
-public interface WrapperWorld<W> {
-
-    @NotNull UUID getUuid();
-
-    @NotNull String getName();
-
-    @Nullable WrapperEntity getEntity(@NotNull UUID uuid);
-
-    @Nullable WrapperEntity getEntity(int entityId);
-
-    @NotNull W getHandle();
-
-}
diff --git a/src/main/java/me/tofaa/entitylib/entity/EntityIdProvider.java b/src/main/java/me/tofaa/entitylib/entity/EntityIdProvider.java
deleted file mode 100644
index b461786..0000000
--- a/src/main/java/me/tofaa/entitylib/entity/EntityIdProvider.java
+++ /dev/null
@@ -1,20 +0,0 @@
-package me.tofaa.entitylib.entity;
-
-import java.util.concurrent.atomic.AtomicInteger;
-
-@FunctionalInterface
-public interface EntityIdProvider {
-
-    static EntityIdProvider simple() {
-        return new EntityIdProvider() {
-            private final AtomicInteger atomicInteger = new AtomicInteger(0);
-            @Override
-            public int provide() {
-                return atomicInteger.incrementAndGet();
-            }
-        };
-    }
-
-
-    int provide();
-}
diff --git a/src/main/java/me/tofaa/entitylib/entity/EntityInteractionProcessor.java b/src/main/java/me/tofaa/entitylib/entity/EntityInteractionProcessor.java
deleted file mode 100644
index 5eb6c79..0000000
--- a/src/main/java/me/tofaa/entitylib/entity/EntityInteractionProcessor.java
+++ /dev/null
@@ -1,18 +0,0 @@
-package me.tofaa.entitylib.entity;
-
-import com.github.retrooper.packetevents.protocol.player.InteractionHand;
-import com.github.retrooper.packetevents.protocol.player.User;
-import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientInteractEntity;
-import org.jetbrains.annotations.NotNull;
-
-@FunctionalInterface
-public interface EntityInteractionProcessor {
-
-    void process(
-        @NotNull WrapperEntity entity,
-        @NotNull WrapperPlayClientInteractEntity.InteractAction action,
-        @NotNull InteractionHand hand,
-        @NotNull User user
-    );
-
-}
diff --git a/src/main/java/me/tofaa/entitylib/entity/WrapperEntity.java b/src/main/java/me/tofaa/entitylib/entity/WrapperEntity.java
deleted file mode 100644
index 83c583e..0000000
--- a/src/main/java/me/tofaa/entitylib/entity/WrapperEntity.java
+++ /dev/null
@@ -1,394 +0,0 @@
-package me.tofaa.entitylib.entity;
-
-import com.github.retrooper.packetevents.protocol.entity.type.EntityType;
-import com.github.retrooper.packetevents.protocol.player.User;
-import com.github.retrooper.packetevents.protocol.world.Location;
-import com.github.retrooper.packetevents.util.Vector3d;
-import com.github.retrooper.packetevents.wrapper.PacketWrapper;
-import com.github.retrooper.packetevents.wrapper.play.server.*;
-import me.tofaa.entitylib.EntityLib;
-import me.tofaa.entitylib.Tickable;
-import me.tofaa.entitylib.meta.EntityMeta;
-import me.tofaa.entitylib.meta.types.ObjectData;
-import org.jetbrains.annotations.NotNull;
-import java.util.*;
-
-public class WrapperEntity implements Tickable {
-    private final EntityType entityType;
-    private final int entityId;
-    private final Optional<UUID> uuid;
-    private final EntityMeta meta;
-    private final Set<UUID> viewers = new HashSet<>();
-    private Location location;
-    private boolean onGround;
-    private boolean spawned;
-    protected Vector3d velocity = Vector3d.zero();
-    private int riding = -1;
-    private Set<Integer> passengers = new HashSet<>();
-
-    public WrapperEntity(int entityId, @NotNull UUID uuid, EntityType entityType, EntityMeta meta) {
-        this.uuid = Optional.of(uuid);
-        this.entityType = entityType;
-        this.meta = meta;
-        this.entityId = entityId;
-    }
-
-    public void refresh() {
-        if (!spawned) return;
-        sendPacketToViewers(meta.createPacket());
-    }
-
-    /**
-     * Adds a passenger to the entity. The passenger will be visible to all viewers of the entity.
-     * @param passenger the entity id of the passenger
-     */
-    public void addPassenger(int passenger) {
-        if (passengers.contains(passenger)) {
-            throw new IllegalArgumentException("Passenger already exists");
-        }
-        passengers.add(passenger);
-        sendPacketToViewers(createPassengerPacket());
-        WrapperEntity e = EntityLib.getEntity(passenger);
-        if (e != null) {
-            e.riding = this.entityId;
-        }
-    }
-
-    /**
-     * Adds multiple passengers to the entity. The passengers will be visible to all viewers of the entity.
-     * @param passengers the entity ids of the passengers
-     */
-    public void addPassengers(int... passengers) {
-        for (int passenger : passengers) {
-            addPassenger(passenger);
-        }
-    }
-
-    /**
-     * Adds a passenger to the entity. The passenger will be visible to all viewers of the entity.
-     * @param passenger the wrapper entity passenger
-     */
-    public void addPassenger(WrapperEntity passenger) {
-        addPassenger(passenger.getEntityId());
-    }
-
-    /**
-     * Adds multiple passengers to the entity. The passengers will be visible to all viewers of the entity.
-     * @param passengers the wrapper entity passengers
-     */
-    public void addPassengers(WrapperEntity... passengers) {
-        for (WrapperEntity passenger : passengers) {
-            addPassenger(passenger);
-        }
-    }
-
-    /**
-     * Removes a passenger from the entity. The passenger will be removed from the view of all viewers of the entity.
-     * @param passenger the entity id of the passenger
-     */
-    public void removePassenger(int passenger) {
-        if (!passengers.contains(passenger)) {
-            throw new IllegalArgumentException("Passenger does not exist");
-        }
-        passengers.remove(passenger);
-        sendPacketToViewers(createPassengerPacket());
-        WrapperEntity e = EntityLib.getEntity(passenger);
-        if (e != null) {
-            e.riding = -1;
-            e.teleport(e.getLocation());
-        }
-    }
-
-    /**
-     * @param passenger the entity id of the passenger
-     * @return true if the entity has the passenger, false otherwise
-     */
-    public boolean hasPassenger(int passenger) {
-        return passengers.contains(passenger);
-    }
-
-    /**
-     * @param passenger the passenger wrapper entity
-     * @return true if the entity has the passenger, false otherwise
-     */
-    public boolean hasPassenger(WrapperEntity passenger) {
-        return hasPassenger(passenger.getEntityId());
-    }
-
-    /**
-     * Removes multiple passengers from the entity. The passengers will be removed from the view of all viewers of the entity.
-     * @param passengers the entity ids of the passengers
-     */
-    public void removePassengers(int... passengers) {
-        for (int passenger : passengers) {
-            removePassenger(passenger);
-        }
-    }
-
-    /**
-     * Removes a passenger from the entity. The passenger will be removed from the view of all viewers of the entity.
-     * @param passenger the wrapper entity passenger
-     */
-    public void removePassenger(WrapperEntity passenger) {
-        removePassenger(passenger.getEntityId());
-    }
-
-    /**
-     * Removes multiple passengers from the entity. The passengers will be removed from the view of all viewers of the entity.
-     * @param passengers the wrapper entity passengers
-     */
-    public void removePassengers(WrapperEntity... passengers) {
-        for (WrapperEntity passenger : passengers) {
-            removePassenger(passenger);
-        }
-    }
-
-    /**
-     * @return true if the entity has passengers, false otherwise
-     */
-    public boolean isRiding() {
-        return riding != -1;
-    }
-
-    /**
-     * Clears all passengers from the entity. The passengers will be removed from the view of all viewers of the entity.
-     */
-    public void clearPassengers() {
-        if (passengers.isEmpty()) return;
-        passengers.clear();
-        sendPacketToViewers(createPassengerPacket());
-    }
-
-    /**
-     * @return the entity id of the entity that the entity is riding, -1 if the entity is not riding
-     */
-    public int getRidingId() {
-        return riding;
-    }
-
-    protected WrapperPlayServerSetPassengers createPassengerPacket() {
-        return new WrapperPlayServerSetPassengers(entityId, passengers.stream().mapToInt(i -> i).toArray());
-    }
-
-    public boolean spawn(Location location) {
-        if (spawned) return false;
-        this.location = location;
-        this.spawned = true;
-        int data = 0;
-        Optional<Vector3d> velocity;
-        double veloX = 0, veloY = 0, veloZ = 0;
-        if (meta instanceof ObjectData) {
-            ObjectData od = (ObjectData) meta;
-            data = od.getObjectData();
-            if (od.requiresVelocityPacketAtSpawn()) {
-                final WrapperPlayServerEntityVelocity veloPacket = getVelocityPacket();
-                veloX = veloPacket.getVelocity().getX();
-                veloY = veloPacket.getVelocity().getY();
-                veloZ = veloPacket.getVelocity().getZ();
-            }
-        }
-        if (veloX == 0 && veloY == 0 && veloZ == 0) {
-            velocity = Optional.empty();
-        } else {
-            velocity = Optional.of(new Vector3d(veloX, veloY, veloZ));
-        }
-        sendPacketToViewers(
-                new WrapperPlayServerSpawnEntity(
-                        entityId,
-                        this.uuid,
-                        entityType,
-                        location.getPosition(),
-                        location.getPitch(),
-                        location.getYaw(),
-                        location.getYaw(),
-                        data,
-                        velocity
-                )
-        );
-        sendPacketToViewers(meta.createPacket());
-        return true;
-    }
-
-    public boolean hasNoGravity() {
-        return meta.isHasNoGravity();
-    }
-
-    public void setHasNoGravity(boolean hasNoGravity) {
-        meta.setHasNoGravity(hasNoGravity);
-        refresh();
-    }
-
-    public void rotateHead(float yaw, float pitch) {
-        sendPacketToViewers(
-                new WrapperPlayServerEntityRotation(entityId, yaw, pitch, onGround)
-        );
-    }
-
-    public void rotateHead(Location location) {
-        rotateHead(location.getYaw(), location.getPitch());
-    }
-
-    public void rotateHead(WrapperEntity entity) {
-        rotateHead(entity.getLocation());
-    }
-
-    /**
-     * Desyncs if the entity is riding some other entity. TODO: fix. This is a temporary solution.
-     * @return the location of the entity
-     */
-    public Location getLocation() {
-        if (isRiding()) {
-            WrapperEntity riding = EntityLib.getEntity(this.riding);
-            assert riding != null;
-            return riding.getLocation();
-        }
-
-        return new Location(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch());
-    }
-
-    public void remove() {
-        if (!spawned) return;
-        spawned = false;
-        sendPacketToViewers(new WrapperPlayServerDestroyEntities(entityId));
-    }
-
-    public void teleport(Location location, boolean onGround) {
-        this.location = location;
-        this.onGround = onGround;
-        sendPacketToViewers(
-                new WrapperPlayServerEntityTeleport(entityId, location, onGround)
-        );
-    }
-
-    public @NotNull Collection<UUID> getViewers() {
-        return Collections.unmodifiableCollection(viewers);
-    }
-
-    public void teleport(Location location) {
-        teleport(location, true);
-    }
-
-    public void sendPacketToViewers(PacketWrapper<?> packet) {
-        viewers.forEach(uuid -> EntityLib.sendPacket(uuid, packet));
-    }
-
-    public void sendPacketsToViewers(PacketWrapper<?>... wrappers) {
-        for (PacketWrapper<?> wrapper : wrappers) {
-            sendPacketToViewers(wrapper);
-        }
-    }
-
-    public boolean addViewer(UUID uuid) {
-        if (!viewers.add(uuid)) {
-            return false;
-        }
-        if (!spawned) return false;
-        WrapperPlayServerSpawnEntity packet = new WrapperPlayServerSpawnEntity(
-                entityId,
-                this.uuid,
-                entityType,
-                location.getPosition(),
-                location.getPitch(),
-                location.getYaw(),
-                location.getYaw(),
-                0,
-                Optional.empty()
-        );
-        EntityLib.sendPacket(uuid, packet);
-        EntityLib.sendPacket(uuid, meta.createPacket());
-        return true;
-    }
-
-    public void addViewer(User user) {
-        addViewer(user.getUUID());
-    }
-
-    public void removeViewer(UUID uuid) {
-        if (!viewers.remove(uuid)) {
-            return;
-        }
-        EntityLib.sendPacket(uuid, new WrapperPlayServerDestroyEntities(entityId));
-    }
-
-    public EntityMeta getMeta() {
-        return meta;
-    }
-
-    public UUID getUuid() {
-        return uuid.get();
-    }
-
-    public EntityType getEntityType() {
-        return entityType;
-    }
-
-    public int getEntityId() {
-        return entityId;
-    }
-
-    public <T extends EntityMeta> Class<T> getMetaClass() {
-        return EntityLib.getMetaClassOf(entityType);
-    }
-
-    public boolean hasSpawned() {
-        return spawned;
-    }
-
-    public boolean hasVelocity() {
-        if (isOnGround()) {
-            // if the entity is on the ground and only "moves" downwards, it does not have a velocity.
-            return Double.compare(velocity.x, 0) != 0 || Double.compare(velocity.z, 0) != 0 || velocity.y > 0;
-        } else {
-            // The entity does not have velocity if the velocity is zero
-            return !velocity.equals(Vector3d.zero());
-        }
-    }
-
-    public boolean isOnGround() {
-        return onGround;
-    }
-
-    public Vector3d getVelocity() {
-        return velocity;
-    }
-
-    public void setVelocity(Vector3d velocity) {
-        this.velocity = velocity;
-        sendPacketToViewers(getVelocityPacket());
-    }
-
-    public double getX() {
-        return location.getX();
-    }
-
-    public double getY() {
-        return location.getY();
-    }
-
-    public double getZ() {
-        return location.getZ();
-    }
-
-    public float getYaw() {
-        return location.getYaw();
-    }
-
-    public float getPitch() {
-        return location.getPitch();
-    }
-
-    private WrapperPlayServerEntityVelocity getVelocityPacket() {
-        Vector3d velocity = this.velocity.multiply(8000.0f / 20.0f);
-        return new WrapperPlayServerEntityVelocity(entityId, velocity);
-    }
-
-    @Override
-    public void update(long time) {
-        tick(time);
-    }
-
-    @Override
-    public void tick(long time) {
-
-    }
-}
diff --git a/src/main/java/me/tofaa/entitylib/entity/WrapperEntityCreature.java b/src/main/java/me/tofaa/entitylib/entity/WrapperEntityCreature.java
deleted file mode 100644
index ba079d8..0000000
--- a/src/main/java/me/tofaa/entitylib/entity/WrapperEntityCreature.java
+++ /dev/null
@@ -1,82 +0,0 @@
-package me.tofaa.entitylib.entity;
-
-import com.github.retrooper.packetevents.protocol.entity.type.EntityType;
-import me.tofaa.entitylib.entity.ai.AIGroup;
-import me.tofaa.entitylib.meta.EntityMeta;
-import me.tofaa.entitylib.EntityLib;
-import org.jetbrains.annotations.NotNull;
-
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Set;
-import java.util.UUID;
-
-/**
- * Represents a {@link WrapperEntity} with goals, AI and pathfinding.
- * <p>
- *     To create a new {@link WrapperEntityCreature} use {@link EntityLib#createEntityCreature(int, UUID, EntityType)} or {@link EntityLib#createEntityCreature(UUID, EntityType)}.
- *     <br>
- *     Creature entities require some sort of ticking mechanism on your server to work properly. They need to be dynamically updated every tick.
- *     Goal and Target selectors are grouped into AIGroups, which are then added to the entity. The AIGroups are then updated every tick.
- *     <br>
- *     The {@link WrapperEntityCreature} can be inherited to create custom entities.
- * </p>
- */
-public class WrapperEntityCreature extends WrapperLivingEntity {
-
-    private final Set<AIGroup> aiGroups;
-
-    public WrapperEntityCreature(int entityId, @NotNull UUID uuid, EntityType entityType, EntityMeta meta) {
-        super(entityId, uuid, entityType, meta);
-        this.aiGroups = new HashSet<>();
-    }
-
-    @Override
-    public void update(long time) {
-        super.update(time);
-        aiGroups.forEach(aiGroup -> aiGroup.update(time));
-    }
-
-    @Override
-    public void kill() {
-        super.kill();
-    }
-
-    /**
-     * Adds an {@link AIGroup} to the entity.
-     * <p>
-     * The AIGroup will be updated every tick.
-     * </p>
-     *
-     * @param aiGroup The AIGroup to add.
-     */
-    public void addAIGroup(AIGroup aiGroup) {
-        aiGroups.add(aiGroup);
-    }
-
-    /**
-     * Removes an {@link AIGroup} from the entity.
-     *
-     * @param aiGroup The AIGroup to remove.
-     */
-    public void removeAIGroup(AIGroup aiGroup) {
-        aiGroups.remove(aiGroup);
-    }
-
-    /**
-     * Removes all {@link AIGroup}s from the entity.
-     */
-    public void clearAIGroups() {
-        aiGroups.clear();
-    }
-
-    /**
-     * Gets the {@link AIGroup}s of the entity.
-     *
-     * @return The AIGroups of the entity.
-     */
-    public Set<AIGroup> getAIGroups() {
-        return Collections.unmodifiableSet(aiGroups);
-    }
-
-}
diff --git a/src/main/java/me/tofaa/entitylib/entity/WrapperEntityEquipment.java b/src/main/java/me/tofaa/entitylib/entity/WrapperEntityEquipment.java
deleted file mode 100644
index e829114..0000000
--- a/src/main/java/me/tofaa/entitylib/entity/WrapperEntityEquipment.java
+++ /dev/null
@@ -1,117 +0,0 @@
-package me.tofaa.entitylib.entity;
-
-import com.github.retrooper.packetevents.manager.server.ServerVersion;
-import com.github.retrooper.packetevents.protocol.item.ItemStack;
-import com.github.retrooper.packetevents.protocol.player.Equipment;
-import com.github.retrooper.packetevents.protocol.player.EquipmentSlot;
-import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerEntityEquipment;
-import me.tofaa.entitylib.EntityLib;
-import org.jetbrains.annotations.NotNull;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
-public class WrapperEntityEquipment {
-
-    private static final EquipmentSlot[] EQUIPMENT_SLOTS = EquipmentSlot.values();
-
-    private final WrapperLivingEntity entity;
-
-
-    // 0 = main hand, 1 = offhand, 2 = boots, 3 = leggings, 4 = chestplate, 5 = helmet
-    private final ItemStack[] equipment = new ItemStack[6];
-
-    public WrapperEntityEquipment(WrapperLivingEntity entity) {
-        this.entity = entity;
-        Arrays.fill(equipment, ItemStack.EMPTY);
-    }
-
-    public void setHelmet(@NotNull ItemStack itemStack) {
-        equipment[5] = itemStack;
-        refresh();
-    }
-
-    public void setChestplate(@NotNull ItemStack itemStack) {
-        equipment[4] = itemStack;
-        refresh();
-    }
-
-    public void setLeggings(@NotNull ItemStack itemStack) {
-        equipment[3] = itemStack;
-        refresh();
-    }
-
-    public void setBoots(@NotNull ItemStack itemStack) {
-        equipment[2] = itemStack;
-        refresh();
-    }
-
-    public void setMainHand(@NotNull ItemStack itemStack) {
-        equipment[0] = itemStack;
-        refresh();
-    }
-
-    public void setOffhand(@NotNull ItemStack itemStack) {
-        EntityLib.verifyVersion(ServerVersion.V_1_9, "Offhand is only supported on 1.9+");
-        equipment[1] = itemStack;
-        refresh();
-    }
-
-    public void setItem(@NotNull EquipmentSlot slot, @NotNull ItemStack itemStack) {
-        equipment[slot.ordinal()]  = itemStack;
-        refresh();
-    }
-
-    public @NotNull ItemStack getItem(@NotNull EquipmentSlot slot) {
-        ItemStack itemStack = equipment[slot.ordinal()];
-        if (itemStack == null) {
-            return ItemStack.EMPTY;
-        }
-        return itemStack;
-    }
-
-    public @NotNull ItemStack getHelmet() {
-        return getItem(EquipmentSlot.HELMET);
-    }
-
-    public @NotNull ItemStack getChestplate() {
-        return getItem(EquipmentSlot.CHEST_PLATE);
-    }
-
-    public @NotNull ItemStack getLeggings() {
-        return getItem(EquipmentSlot.LEGGINGS);
-    }
-
-    public @NotNull ItemStack getBoots() {
-        return getItem(EquipmentSlot.BOOTS);
-    }
-
-    public @NotNull ItemStack getMainHand() {
-        return getItem(EquipmentSlot.MAIN_HAND);
-    }
-
-    public @NotNull ItemStack getOffhand() {
-        EntityLib.verifyVersion(ServerVersion.V_1_9, "Offhand is only supported on 1.9+");
-        return getItem(EquipmentSlot.OFF_HAND);
-    }
-
-    public WrapperPlayServerEntityEquipment createPacket() {
-        List<Equipment> equipment = new ArrayList<>();
-        for (int i = 0; i < this.equipment.length; i++) {
-            ItemStack itemStack = this.equipment[i];
-            if (itemStack == null || itemStack.equals(ItemStack.EMPTY)) continue;
-            equipment.add(new Equipment(EQUIPMENT_SLOTS[i], itemStack));
-        }
-        return new WrapperPlayServerEntityEquipment(
-                entity.getEntityId(),
-                equipment
-        );
-    }
-
-
-    public void refresh() {
-        this.entity.sendPacketToViewers(createPacket());
-    }
-
-}
diff --git a/src/main/java/me/tofaa/entitylib/entity/WrapperExperienceOrbEntity.java b/src/main/java/me/tofaa/entitylib/entity/WrapperExperienceOrbEntity.java
deleted file mode 100644
index 8ee2ba1..0000000
--- a/src/main/java/me/tofaa/entitylib/entity/WrapperExperienceOrbEntity.java
+++ /dev/null
@@ -1,68 +0,0 @@
-package me.tofaa.entitylib.entity;
-
-import com.github.retrooper.packetevents.protocol.entity.type.EntityType;
-import com.github.retrooper.packetevents.protocol.world.Location;
-import com.github.retrooper.packetevents.util.Vector3d;
-import me.tofaa.entitylib.meta.EntityMeta;
-import org.jetbrains.annotations.NotNull;
-
-import java.util.UUID;
-
-public class WrapperExperienceOrbEntity extends WrapperEntity {
-
-    private short experience;
-    private Location slideTowards;
-
-    public WrapperExperienceOrbEntity(int entityId, @NotNull UUID uuid, EntityType entityType, EntityMeta meta) {
-        super(entityId, uuid, entityType, meta);
-    }
-
-    /**
-     * Applies a slight slide motion towards the given location.
-     * <p>
-     *     For this to work, this method needs to be called every tick until the entity reaches the location.
-     *     We don't have ticking or updating in this library, so you'll have to do it yourself.
-     *     This is an attempt to mimmick the vanilla behavior.
-     * </p>
-     */
-    public void updateSliding() {
-        if (hasNoGravity()) {
-            setVelocity(getVelocity().add(0, -0.3f, 0));
-        }
-
-        double d = 8.0;
-        Vector3d distance = new Vector3d(slideTowards.getX() - getX(), slideTowards.getY() - getY(), slideTowards.getZ() - getZ());
-        double length = distance.length();
-        if (length < 8.0) {
-            double f = 1 - (length / 8);
-            setVelocity(getVelocity().add(distance.normalize().multiply(f * f * 0.1)));
-        }
-        float g = 0.98f;
-        if (this.isOnGround()) {
-            g = 0.6f * 0.98f;
-        }
-        setVelocity(getVelocity().multiply(g, 0.98f, g));
-        if (isOnGround()) {
-            setVelocity(getVelocity().multiply(1, -0.9f, 1));
-        }
-    }
-
-    public Location getSlideTowards() {
-        return slideTowards;
-    }
-
-    public void setSlideTowards(Location slideTowards) {
-        this.slideTowards = slideTowards;
-    }
-
-    public short getExperience() {
-        return experience;
-    }
-
-    public void setExperience(short experience) {
-        getViewers().forEach(this::removeViewer);
-        this.experience = experience;
-        getViewers().forEach(this::addViewer);
-    }
-
-}
diff --git a/src/main/java/me/tofaa/entitylib/entity/WrapperLivingEntity.java b/src/main/java/me/tofaa/entitylib/entity/WrapperLivingEntity.java
deleted file mode 100644
index 54c5e5e..0000000
--- a/src/main/java/me/tofaa/entitylib/entity/WrapperLivingEntity.java
+++ /dev/null
@@ -1,58 +0,0 @@
-package me.tofaa.entitylib.entity;
-
-import com.github.retrooper.packetevents.protocol.entity.type.EntityType;
-import com.github.retrooper.packetevents.util.Vector3d;
-import com.github.retrooper.packetevents.util.Vector3f;
-import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerEntityStatus;
-import me.tofaa.entitylib.meta.EntityMeta;
-import me.tofaa.entitylib.meta.types.LivingEntityMeta;
-import org.jetbrains.annotations.NotNull;
-
-import java.util.UUID;
-
-public class WrapperLivingEntity extends WrapperEntity{
-
-    private final WrapperEntityEquipment equipment;
-    private float maxHealth;
-
-    public WrapperLivingEntity(int entityId, @NotNull UUID uuid, EntityType entityType, EntityMeta meta) {
-        super(entityId, uuid, entityType, meta);
-        this.equipment = new WrapperEntityEquipment(this);
-    }
-
-
-    public void kill() {
-        sendStatus((byte) 3);
-        setHealth(0);
-        this.velocity = Vector3d.zero();
-    }
-
-    public void sendStatus(byte status) {
-        sendPacketsToViewers(new WrapperPlayServerEntityStatus(getEntityId(), status));
-    }
-
-    public float getHealth() {
-        return getMeta().getHealth();
-    }
-
-    public void setHealth(float health) {
-        getMeta().setHealth(Math.min(Math.max(health, 0), getMaxHealth()));
-    }
-
-    public float getMaxHealth() {
-        return maxHealth;
-    }
-
-    public void setMaxHealth(float maxHealth) {
-        this.maxHealth = maxHealth;
-    }
-
-    public WrapperEntityEquipment getEquipment() {
-        return equipment;
-    }
-
-    @Override
-    public LivingEntityMeta getMeta() {
-        return (LivingEntityMeta) super.getMeta();
-    }
-}
diff --git a/src/main/java/me/tofaa/entitylib/entity/ai/AIGroup.java b/src/main/java/me/tofaa/entitylib/entity/ai/AIGroup.java
deleted file mode 100644
index 8159247..0000000
--- a/src/main/java/me/tofaa/entitylib/entity/ai/AIGroup.java
+++ /dev/null
@@ -1,75 +0,0 @@
-package me.tofaa.entitylib.entity.ai;
-
-import me.tofaa.entitylib.Tickable;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-import java.util.Collection;
-import java.util.List;
-
-public class AIGroup implements Tickable {
-
-    private final List<GoalSelector> goalSelectors = new GoalSelectorList(this);
-    private GoalSelector currentGoalSelector;
-
-    public @NotNull Collection<GoalSelector> getGoalSelectors() {
-        return goalSelectors;
-    }
-
-    public @Nullable GoalSelector getCurrentGoal() {
-        return currentGoalSelector;
-    }
-
-    /**
-     * Adds a goal selector to the end of the list. Might be potentially unsafe to use after the entity has been spawned.
-     *
-     * @param goalSelector the goal selector to add
-     */
-    public void addGoalSelector(@NotNull GoalSelector goalSelector) {
-        this.goalSelectors.add(goalSelector);
-    }
-
-    public void setCurrentGoal(@Nullable GoalSelector goalSelector) {
-        if (goalSelector != null && goalSelector.getAIGroup() != this) {
-            throw new IllegalArgumentException("GoalSelector is not in this AIGroup");
-        }
-        currentGoalSelector = goalSelector;
-    }
-
-    @Override
-    public void update(long time) {
-        GoalSelector currentGoalSelector = getCurrentGoal();
-
-        if (currentGoalSelector != null && currentGoalSelector.shouldEnd()) {
-            currentGoalSelector.end();
-            currentGoalSelector = null;
-            setCurrentGoal(null);
-        }
-
-        for (GoalSelector selector : getGoalSelectors()) {
-            if (selector == currentGoalSelector) {
-                break;
-            }
-            if (selector.shouldStart()) {
-                if (currentGoalSelector != null) {
-                    currentGoalSelector.end();
-                }
-                currentGoalSelector = selector;
-                setCurrentGoal(currentGoalSelector);
-                currentGoalSelector.start();
-                break;
-            }
-        }
-
-        if (currentGoalSelector != null) {
-            currentGoalSelector.tick(time);
-        }
-        tick(time);
-    }
-
-    @Override
-    public void tick(long time) {
-
-    }
-
-}
diff --git a/src/main/java/me/tofaa/entitylib/entity/ai/GoalSelector.java b/src/main/java/me/tofaa/entitylib/entity/ai/GoalSelector.java
deleted file mode 100644
index 37e7875..0000000
--- a/src/main/java/me/tofaa/entitylib/entity/ai/GoalSelector.java
+++ /dev/null
@@ -1,85 +0,0 @@
-package me.tofaa.entitylib.entity.ai;
-
-import me.tofaa.entitylib.entity.WrapperEntityCreature;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-import java.lang.ref.WeakReference;
-
-/**
- * Goals represent tasks that a {@link me.tofaa.entitylib.entity.WrapperEntityCreature} can perform.
- */
-public abstract class GoalSelector {
-
-    private WeakReference<AIGroup> aiGroupRef;
-    protected WrapperEntityCreature entity;
-
-    public GoalSelector(WrapperEntityCreature entity) {
-        this.entity = entity;
-    }
-
-    /**
-     * Whether this {@link GoalSelector} should start.
-     *
-     * @return true to start
-     */
-    public abstract boolean shouldStart();
-
-    /**
-     * Starts this {@link GoalSelector}.
-     */
-    public abstract void start();
-
-    /**
-     * Called every tick when this {@link GoalSelector} is running.
-     *
-     * @param time the time of the update in milliseconds
-     */
-    public abstract void tick(long time);
-
-    /**
-     * Whether this {@link GoalSelector} should end.
-     *
-     * @return true to end
-     */
-    public abstract boolean shouldEnd();
-
-    /**
-     * Ends this {@link GoalSelector}.
-     */
-    public abstract void end();
-
-
-    /**
-     * Gets the entity behind the goal selector.
-     *
-     * @return the entity
-     */
-    @NotNull
-    public WrapperEntityCreature getEntityCreature() {
-        return entity;
-    }
-
-    /**
-     * Changes the entity affected by the goal selector.
-     * <p>
-     * WARNING: this does not add the goal selector to {@code entityCreature},
-     * this only change the internal entity AI group's field. Be sure to remove the goal from
-     * the previous entity AI group and add it to the new one using {@link AIGroup#getGoalSelectors()}.
-     *
-     * @param entity the new affected entity
-     */
-    public void setEntityCreature(@NotNull WrapperEntityCreature entity) {
-        this.entity = entity;
-    }
-
-    void setAIGroup(@NotNull AIGroup group) {
-        this.aiGroupRef = new WeakReference<>(group);
-    }
-
-    @Nullable
-    protected AIGroup getAIGroup() {
-        return this.aiGroupRef.get();
-    }
-
-}
diff --git a/src/main/java/me/tofaa/entitylib/entity/ai/GoalSelectorList.java b/src/main/java/me/tofaa/entitylib/entity/ai/GoalSelectorList.java
deleted file mode 100644
index b783262..0000000
--- a/src/main/java/me/tofaa/entitylib/entity/ai/GoalSelectorList.java
+++ /dev/null
@@ -1,54 +0,0 @@
-package me.tofaa.entitylib.entity.ai;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.function.UnaryOperator;
-
-final class GoalSelectorList extends ArrayList<GoalSelector> {
-
-    final AIGroup aiGroup;
-
-    GoalSelectorList(AIGroup aiGroup) {
-        this.aiGroup = aiGroup;
-    }
-
-    @Override
-    public GoalSelector set(int index, GoalSelector element) {
-        element.setAIGroup(aiGroup);
-        return super.set(index, element);
-    }
-
-    @Override
-    public boolean add(GoalSelector element) {
-        element.setAIGroup(aiGroup);
-        return super.add(element);
-    }
-
-    @Override
-    public void add(int index, GoalSelector element) {
-        element.setAIGroup(aiGroup);
-        super.add(index, element);
-    }
-
-    @Override
-    public boolean addAll(Collection<? extends GoalSelector> c) {
-        c.forEach(goalSelector -> goalSelector.setAIGroup(aiGroup));
-        return super.addAll(c);
-    }
-
-    @Override
-    public boolean addAll(int index, Collection<? extends GoalSelector> c) {
-        c.forEach(goalSelector -> goalSelector.setAIGroup(aiGroup));
-        return super.addAll(index, c);
-    }
-
-    @Override
-    public void replaceAll(UnaryOperator<GoalSelector> operator) {
-        super.replaceAll(goalSelector -> {
-            goalSelector = operator.apply(goalSelector);
-            goalSelector.setAIGroup(aiGroup);
-            return goalSelector;
-        });
-    }
-
-}
\ No newline at end of file
diff --git a/src/main/java/me/tofaa/entitylib/entity/ai/goals/RandomHeadMovementGoal.java b/src/main/java/me/tofaa/entitylib/entity/ai/goals/RandomHeadMovementGoal.java
deleted file mode 100644
index e085ace..0000000
--- a/src/main/java/me/tofaa/entitylib/entity/ai/goals/RandomHeadMovementGoal.java
+++ /dev/null
@@ -1,81 +0,0 @@
-package me.tofaa.entitylib.entity.ai.goals;
-
-import com.github.retrooper.packetevents.util.Vector3d;
-import me.tofaa.entitylib.entity.WrapperEntityCreature;
-import me.tofaa.entitylib.entity.ai.GoalSelector;
-import me.tofaa.entitylib.extras.CoordinateUtil;
-import org.jetbrains.annotations.NotNull;
-
-import java.util.Random;
-import java.util.function.Function;
-import java.util.function.Supplier;
-
-public class RandomHeadMovementGoal extends GoalSelector {
-
-    private static final Random RANDOM = new Random();
-    private final int chancePerTick;
-    private final Supplier<Integer> minimalLookTimeSupplier;
-    private final Function<WrapperEntityCreature, Vector3d> randomDirectionFunction;
-    private Vector3d lookDirection;
-    private int lookTime = 0;
-
-    public RandomHeadMovementGoal(WrapperEntityCreature entityCreature, int chancePerTick) {
-        this(entityCreature, chancePerTick,
-                // These two functions act similarly enough to how MC randomly looks around.
-                // Look in one direction for at most 40 ticks and at minimum 20 ticks.
-                () -> 20 + RANDOM.nextInt(20),
-                // Look at a random block
-                (creature) -> {
-                    final double n = Math.PI * 2 * RANDOM.nextDouble();
-                    return new Vector3d(
-                            (float) Math.cos(n),
-                            0,
-                            (float) Math.sin(n)
-                    );
-                });
-    }
-
-    /**
-     * @param entityCreature          Creature that should randomly look around.
-     * @param chancePerTick           The chance (per tick) that the entity looks around. Setting this to N would mean there is a 1 in N chance.
-     * @param minimalLookTimeSupplier A supplier that returns the minimal amount of time an entity looks in a direction.
-     * @param randomDirectionFunction A function that returns a random vector that the entity will look in/at.
-     */
-    public RandomHeadMovementGoal(
-            WrapperEntityCreature entityCreature,
-            int chancePerTick,
-            @NotNull Supplier<Integer> minimalLookTimeSupplier,
-            @NotNull Function<WrapperEntityCreature, Vector3d> randomDirectionFunction) {
-        super(entityCreature);
-        this.chancePerTick = chancePerTick;
-        this.minimalLookTimeSupplier = minimalLookTimeSupplier;
-        this.randomDirectionFunction = randomDirectionFunction;
-    }
-
-    @Override
-    public boolean shouldStart() {
-        return RANDOM.nextInt(chancePerTick) == 0;
-    }
-
-    @Override
-    public void start() {
-        lookTime = minimalLookTimeSupplier.get();
-        lookDirection = randomDirectionFunction.apply(entity);
-    }
-
-    @Override
-    public void tick(long time) {
-        --lookTime;
-        entity.teleport(CoordinateUtil.withDirection(entity.getLocation(), lookDirection));
-    }
-
-    @Override
-    public boolean shouldEnd() {
-        return this.lookTime < 0;
-    }
-
-    @Override
-    public void end() {
-
-    }
-}
diff --git a/src/main/java/me/tofaa/entitylib/exception/InvalidVersionException.java b/src/main/java/me/tofaa/entitylib/exception/InvalidVersionException.java
deleted file mode 100644
index 70ff2c7..0000000
--- a/src/main/java/me/tofaa/entitylib/exception/InvalidVersionException.java
+++ /dev/null
@@ -1,23 +0,0 @@
-package me.tofaa.entitylib.exception;
-
-public class InvalidVersionException extends RuntimeException {
-
-    public InvalidVersionException() {
-    }
-
-    public InvalidVersionException(String message) {
-        super(message);
-    }
-
-    public InvalidVersionException(String message, Throwable cause) {
-        super(message, cause);
-    }
-
-    public InvalidVersionException(Throwable cause) {
-        super(cause);
-    }
-
-    public InvalidVersionException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
-        super(message, cause, enableSuppression, writableStackTrace);
-    }
-}
diff --git a/src/main/java/me/tofaa/entitylib/extras/Color.java b/src/main/java/me/tofaa/entitylib/extras/Color.java
deleted file mode 100644
index 1403d39..0000000
--- a/src/main/java/me/tofaa/entitylib/extras/Color.java
+++ /dev/null
@@ -1,56 +0,0 @@
-package me.tofaa.entitylib.extras;
-
-import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerAttachEntity;
-import net.kyori.adventure.util.RGBLike;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Range;
-
-public final class Color implements RGBLike {
-
-    private static final int BIT_MASK = 0xFF;
-
-    private final int red, green, blue;
-
-    public Color(@Range(from = 0L, to = 255L) int red, @Range(from = 0L, to = 255L) int green, @Range(from = 0L, to = 255L) int blue) {
-        this.red = red;
-        this.green = green;
-        this.blue = blue;
-    }
-
-    public Color(int rgb) {
-        this((rgb >> 16) & BIT_MASK, (rgb >> 8) & BIT_MASK, rgb & BIT_MASK);
-    }
-
-    public @NotNull Color withRed(@Range(from = 0L, to = 255L) int red) {
-        return new Color(red, green, blue);
-    }
-
-    public @NotNull Color withGreen(@Range(from = 0L, to = 255L) int green) {
-        return new Color(red, green, blue);
-    }
-
-    public @NotNull Color withBlue(@Range(from = 0L, to = 255L) int blue) {
-        return new Color(red, green, blue);
-    }
-
-    public int asRGB() {
-        int rgb = red;
-        rgb = (rgb << 8) + green;
-        return (rgb << 8) + blue;
-    }
-
-    @Override
-    public @Range(from = 0L, to = 255L) int red() {
-        return red;
-    }
-
-    @Override
-    public @Range(from = 0L, to = 255L) int green() {
-        return green;
-    }
-
-    @Override
-    public @Range(from = 0L, to = 255L) int blue() {
-        return blue;
-    }
-}
diff --git a/src/main/java/me/tofaa/entitylib/extras/CoordinateUtil.java b/src/main/java/me/tofaa/entitylib/extras/CoordinateUtil.java
deleted file mode 100644
index 25e5c39..0000000
--- a/src/main/java/me/tofaa/entitylib/extras/CoordinateUtil.java
+++ /dev/null
@@ -1,38 +0,0 @@
-package me.tofaa.entitylib.extras;
-
-import com.github.retrooper.packetevents.protocol.world.Location;
-import com.github.retrooper.packetevents.util.Vector3d;
-
-public final class CoordinateUtil {
-
-    private CoordinateUtil() {}
-
-    public static Location withDirection(Location location, Vector3d direction) {
-        /*
-         * Sin = Opp / Hyp
-         * Cos = Adj / Hyp
-         * Tan = Opp / Adj
-         *
-         * x = -Opp
-         * z = Adj
-         */
-        final double x = direction.getX();
-        final double z = direction.getZ();
-        if (x == 0 && z == 0) {
-            float pitch = direction.getY() > 0 ? -90f : 90f;
-            return new Location(location.getX(), location.getY(), location.getZ(), location.getYaw(), pitch);
-        }
-        final double theta = Math.atan2(-x, z);
-        final double xz = Math.sqrt(square(x) + square(z));
-        final double _2PI = 2 * Math.PI;
-
-        return new Location(location.getX(), location.getY(), location.getZ(),
-                (float) Math.toDegrees((theta + _2PI) % _2PI),
-                (float) Math.toDegrees(Math.atan(-direction.getY() / xz)));
-    }
-
-    public static double square(double in) {
-        return in * in;
-    }
-
-}
diff --git a/src/main/java/me/tofaa/entitylib/extras/DyeColor.java b/src/main/java/me/tofaa/entitylib/extras/DyeColor.java
deleted file mode 100644
index 798036f..0000000
--- a/src/main/java/me/tofaa/entitylib/extras/DyeColor.java
+++ /dev/null
@@ -1,85 +0,0 @@
-package me.tofaa.entitylib.extras;
-
-import net.kyori.adventure.util.RGBLike;
-import org.jetbrains.annotations.NotNull;
-
-public enum DyeColor implements RGBLike {
-    WHITE(new Color(0xf9fffe), new Color(0xffffff), new Color(0xf0f0f0), 8),
-
-    ORANGE(new Color(0xf9801d), new Color(0xff681f), new Color(0xeb8844), 15),
-
-    MAGENTA(new Color(0xc74ebd), new Color(0xff00ff), new Color(0xc354cd), 16),
-
-    LIGHT_BLUE(new Color(0x3ab3da), new Color(0x9ac0cd), new Color(0x6689d3), 17),
-
-    YELLOW(new Color(0xfed83d), new Color(0xffff00), new Color(0xdecf2a), 18),
-
-    LIME(new Color(0x80c71f), new Color(0xbfff00), new Color(0x41cd34), 19),
-
-    PINK(new Color(0xf38baa), new Color(0xff69b4), new Color(0xd88198), 20),
-
-    GRAY(new Color(0x474f52), new Color(0x808080), new Color(0x434343), 21),
-
-    LIGHT_GRAY(new Color(0x9d9d97), new Color(0xd3d3d3), new Color(0xababab), 22),
-
-    CYAN(new Color(0x169c9c), new Color(0xffff), new Color(0x287697), 23),
-
-    PURPLE(new Color(0x8932b8), new Color(0xa020f0), new Color(0x7b2fbe), 24),
-
-    BLUE(new Color(0x3c44aa), new Color(0xff), new Color(0x253192), 25),
-
-    BROWN(new Color(0x835432), new Color(0x8b4513), new Color(0x51301a), 26),
-
-    GREEN(new Color(0x5e7c16), new Color(0xff00), new Color(0x3b511a), 27),
-
-    RED(new Color(0xb02e26), new Color(0xff0000), new Color(0xb3312c), 28),
-
-    BLACK(new Color(0x1d1d21), new Color(0x0), new Color(0x1e1b1b), 29);
-
-    private final Color textureDiffuseColor;
-
-    private final Color textColor;
-
-    private final Color fireworkColor;
-
-    private final int mapColorId;
-
-    DyeColor(@NotNull Color textureDiffuseColor, @NotNull Color textColor,
-             @NotNull Color fireworkColor, int mapColorId) {
-        this.textureDiffuseColor = textureDiffuseColor;
-        this.textColor = textColor;
-        this.fireworkColor = fireworkColor;
-        this.mapColorId = mapColorId;
-    }
-
-    public @NotNull Color color() {
-        return this.textureDiffuseColor;
-    }
-
-    public @NotNull Color textColor() {
-        return this.textColor;
-    }
-
-    public @NotNull Color fireworkColor() {
-        return this.fireworkColor;
-    }
-
-    @Override
-    public int red() {
-        return this.textureDiffuseColor.red();
-    }
-
-    @Override
-    public int green() {
-        return this.textureDiffuseColor.green();
-    }
-
-    @Override
-    public int blue() {
-        return this.textureDiffuseColor.blue();
-    }
-
-    public int mapColorId() {
-        return this.mapColorId;
-    }
-}
diff --git a/src/main/java/me/tofaa/entitylib/extras/Rotation.java b/src/main/java/me/tofaa/entitylib/extras/Rotation.java
deleted file mode 100644
index b05b61e..0000000
--- a/src/main/java/me/tofaa/entitylib/extras/Rotation.java
+++ /dev/null
@@ -1,38 +0,0 @@
-package me.tofaa.entitylib.extras;
-
-public enum Rotation {
-
-    /**
-     * No rotation
-     */
-    NONE,
-    /**
-     * Rotated clockwise by 45 degrees
-     */
-    CLOCKWISE_45,
-    /**
-     * Rotated clockwise by 90 degrees
-     */
-    CLOCKWISE,
-    /**
-     * Rotated clockwise by 135 degrees
-     */
-    CLOCKWISE_135,
-    /**
-     * Flipped upside-down, a 180-degree rotation
-     */
-    FLIPPED,
-    /**
-     * Flipped upside-down + 45-degree rotation
-     */
-    FLIPPED_45,
-    /**
-     * Rotated counter-clockwise by 90 degrees
-     */
-    COUNTER_CLOCKWISE,
-    /**
-     * Rotated counter-clockwise by 45 degrees
-     */
-    COUNTER_CLOCKWISE_45;
-
-}
\ No newline at end of file
diff --git a/src/main/java/me/tofaa/entitylib/meta/EntityMeta.java b/src/main/java/me/tofaa/entitylib/meta/EntityMeta.java
deleted file mode 100644
index c759d5c..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/EntityMeta.java
+++ /dev/null
@@ -1,220 +0,0 @@
-package me.tofaa.entitylib.meta;
-
-import com.github.retrooper.packetevents.manager.server.ServerVersion;
-import com.github.retrooper.packetevents.manager.server.VersionComparison;
-import com.github.retrooper.packetevents.protocol.entity.data.EntityData;
-import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
-import com.github.retrooper.packetevents.protocol.entity.data.EntityMetadataProvider;
-import com.github.retrooper.packetevents.protocol.entity.pose.EntityPose;
-import com.github.retrooper.packetevents.protocol.player.ClientVersion;
-import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerEntityMetadata;
-import me.tofaa.entitylib.EntityLib;
-import me.tofaa.entitylib.exception.InvalidVersionException;
-import net.kyori.adventure.text.Component;
-import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
-
-import java.util.List;
-
-public class EntityMeta implements EntityMetadataProvider {
-
-    public static final byte OFFSET = 0;
-    public static final byte MAX_OFFSET = OFFSET + 8;
-
-    private final static byte ON_FIRE_BIT = 0x01;
-    private final static byte CROUCHING_BIT = 0x02;
-    private final static byte SPRINTING_BIT = 0x08;
-    private final static byte SWIMMING_BIT = 0x10;
-    private final static byte INVISIBLE_BIT = 0x20;
-    private final static byte HAS_GLOWING_EFFECT_BIT = 0x40;
-    private final static byte FLYING_WITH_ELYTRA_BIT = (byte) 0x80;
-
-    protected final int entityId;
-    protected final Metadata metadata;
-
-    public EntityMeta(int entityId, Metadata metadata) {
-        this.entityId = entityId;
-        this.metadata = metadata;
-    }
-
-    public boolean isOnFire() {
-        return getMaskBit(OFFSET, ON_FIRE_BIT);
-    }
-
-    public void setOnFire(boolean value) {
-        setMaskBit(OFFSET, ON_FIRE_BIT, value);
-    }
-
-    public boolean isSneaking() {
-        return getMaskBit(OFFSET, CROUCHING_BIT);
-    }
-
-    public void setSneaking(boolean value) {
-        setMaskBit(OFFSET, CROUCHING_BIT, value);
-    }
-
-    public boolean isSprinting() {
-        return getMaskBit(OFFSET, SPRINTING_BIT);
-    }
-
-    public void setSprinting(boolean value) {
-        setMaskBit(OFFSET, SPRINTING_BIT, value);
-    }
-
-    public boolean isInvisible() {
-        return getMaskBit(OFFSET, INVISIBLE_BIT);
-    }
-
-    public void setInvisible(boolean value) {
-        setMaskBit(OFFSET, INVISIBLE_BIT, value);
-    }
-
-    public short getAirTicks() {
-        return this.metadata.getIndex((byte) 1, (short) 300);
-    }
-
-    public void setAirTicks(short value) {
-        this.metadata.setIndex((byte) 1, EntityDataTypes.SHORT, value);
-    }
-
-    public Component getCustomName() {
-        return this.metadata.getIndex(offset(OFFSET, 2), null);
-    }
-
-    public void setCustomName(Component value) {
-        this.metadata.setIndex(offset(OFFSET, 2), EntityDataTypes.ADV_COMPONENT, value);
-    }
-
-    public boolean isCustomNameVisible() {
-        return this.metadata.getIndex(offset(OFFSET, 3), false);
-    }
-
-    public void setCustomNameVisible(boolean value) {
-        this.metadata.setIndex(offset(OFFSET, 3), EntityDataTypes.BOOLEAN, value);
-    }
-
-    public boolean hasGlowingEffect() {
-        return getMaskBit(OFFSET, HAS_GLOWING_EFFECT_BIT);
-    }
-
-    public boolean isSwimming() {
-        return getMaskBit(OFFSET, SWIMMING_BIT);
-    }
-
-    public void setSwimming(boolean value) {
-        setMaskBit(OFFSET, SWIMMING_BIT, value);
-    }
-
-    public void setHasGlowingEffect(boolean value) {
-        setMaskBit(OFFSET, HAS_GLOWING_EFFECT_BIT, value);
-    }
-
-    public boolean isFlyingWithElytra() {
-        return getMaskBit(OFFSET, FLYING_WITH_ELYTRA_BIT);
-    }
-
-    public void setFlyingWithElytra(boolean value) {
-        setMaskBit(OFFSET, FLYING_WITH_ELYTRA_BIT, value);
-    }
-
-    public boolean isSilent() {
-        return this.metadata.getIndex((byte) 4, false);
-    }
-
-    public void setSilent(boolean value) {
-        this.metadata.setIndex((byte) 4, EntityDataTypes.BOOLEAN, value);
-    }
-
-    public boolean isHasNoGravity() {
-        return this.metadata.getIndex(offset(OFFSET, 5), true);
-    }
-
-    public void setHasNoGravity(boolean value) {
-        this.metadata.setIndex(offset(OFFSET, 5), EntityDataTypes.BOOLEAN, value);
-    }
-
-    public EntityPose getPose() {
-        return this.metadata.getIndex(offset(OFFSET, 6), EntityPose.STANDING);
-    }
-
-    public void setPose(EntityPose value) {
-        this.metadata.setIndex(offset(OFFSET, 6), EntityDataTypes.ENTITY_POSE, value);
-    }
-
-    public int getTicksFrozenInPowderedSnow() {
-        return this.metadata.getIndex(offset(OFFSET, 7), 0);
-    }
-
-    public void setTicksFrozenInPowderedSnow(int value) {
-        this.metadata.setIndex(offset(OFFSET, 7), EntityDataTypes.INT, value);
-    }
-
-    public WrapperPlayServerEntityMetadata createPacket() {
-        return metadata.createPacket();
-    }
-
-    protected static void isVersionOlder(ServerVersion version) {
-        if (!EntityLib.getPacketEvents().getServerManager().getVersion().is(VersionComparison.OLDER_THAN, version)) {
-            throw new InvalidVersionException("This method is only available for versions older than " + version.name() + ".");
-        }
-    }
-
-    protected static void isVersionNewer(ServerVersion version) {
-        if (!EntityLib.getPacketEvents().getServerManager().getVersion().is(VersionComparison.NEWER_THAN, version)) {
-            throw new InvalidVersionException("This method is only available for versions newer than " + version.name() + ".");
-        }
-    }
-
-    protected static boolean isVersion(ServerVersion version, VersionComparison comparison) {
-        return EntityLib.getPacketEvents().getServerManager().getVersion().is(comparison, version);
-    }
-
-    protected static boolean isVersion(ServerVersion version) {
-        return EntityLib.getPacketEvents().getServerManager().getVersion().is(VersionComparison.EQUALS, version);
-    }
-
-    /**
-     * Annoying java 8 not letting me do OFFSET + amount in the method call so this is a workaround
-     * @param value the value to offset
-     * @param amount the amount to offset by
-     * @return the offset value
-     */
-    protected static byte offset(byte value, int amount) {
-        return (byte) (value + amount);
-    }
-
-    protected byte getMask(byte index) {
-        return this.metadata.getIndex(index, (byte) 0);
-    }
-
-    protected void setMask(byte index, byte mask) {
-        this.metadata.setIndex(index, EntityDataTypes.BYTE, mask);
-    }
-
-    protected boolean getMaskBit(byte index, byte bit) {
-        return (getMask(index) & bit) == bit;
-    }
-
-    protected void setMaskBit(int index, byte bit, boolean value) {
-        byte mask = getMask((byte)index);
-        boolean currentValue = (mask & bit) == bit;
-        if (currentValue == value) {
-            return;
-        }
-        if (value) {
-            mask |= bit;
-        } else {
-            mask &= (byte) ~bit;
-        }
-        setMask((byte)index, mask);
-    }
-
-    @Override
-    public List<EntityData> entityData(ClientVersion clientVersion) {
-        return metadata.getEntries(); // TODO: Atm this is useless cause of the way the api works. Might change in the future
-    }
-
-    @Override
-    public List<EntityData> entityData() {
-        return metadata.getEntries();
-    }
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/Metadata.java b/src/main/java/me/tofaa/entitylib/meta/Metadata.java
deleted file mode 100644
index bcb0f7f..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/Metadata.java
+++ /dev/null
@@ -1,55 +0,0 @@
-package me.tofaa.entitylib.meta;
-
-import com.github.retrooper.packetevents.protocol.entity.data.EntityData;
-import com.github.retrooper.packetevents.protocol.entity.data.EntityDataType;
-import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerEntityMetadata;
-import me.tofaa.entitylib.EntityLib;
-import me.tofaa.entitylib.entity.WrapperEntity;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-
-@SuppressWarnings("unchecked")
-public class Metadata {
-
-    private final Map<Byte, EntityData> metadataMap = new ConcurrentHashMap<>();
-    private final int entityId;
-
-    public Metadata(int entityId) {
-        this.entityId = entityId;
-    }
-
-    public <T> T getIndex(byte index, @Nullable T defaultValue) {
-        EntityData entityData = metadataMap.get(index);
-        if (entityData == null) return defaultValue;
-        if (entityData.getValue() == null) return defaultValue;
-        return (T) entityData.getValue();
-    }
-
-    public <T> void setIndex(byte index, @NotNull EntityDataType<T> dataType, T value) {
-        EntityData data = new EntityData(index, dataType, value);
-        this.metadataMap.put(index, data);
-        WrapperEntity e = EntityLib.getEntity(entityId);
-        if (e != null && e.hasSpawned()) {
-            e.sendPacketToViewers(
-                    new WrapperPlayServerEntityMetadata(
-                            entityId,
-                            getEntries()
-                    )
-            );
-        }
-    }
-
-    @NotNull List<EntityData> getEntries() {
-        return new ArrayList<>(metadataMap.values());
-    }
-
-    public WrapperPlayServerEntityMetadata createPacket() {
-        return new WrapperPlayServerEntityMetadata(entityId, getEntries());
-    }
-
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/display/BlockDisplayMeta.java b/src/main/java/me/tofaa/entitylib/meta/display/BlockDisplayMeta.java
deleted file mode 100644
index 80cf218..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/display/BlockDisplayMeta.java
+++ /dev/null
@@ -1,24 +0,0 @@
-package me.tofaa.entitylib.meta.display;
-
-import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
-import me.tofaa.entitylib.meta.Metadata;
-import me.tofaa.entitylib.meta.types.DisplayMeta;
-
-public class BlockDisplayMeta extends DisplayMeta {
-
-    public static final byte OFFSET = DisplayMeta.MAX_OFFSET;
-    public static final byte MAX_OFFSET = offset(OFFSET, 1);
-
-    public BlockDisplayMeta(int entityId, Metadata metadata) {
-        super(entityId, metadata);
-    }
-
-    public int getBlockId() {
-        return super.metadata.getIndex(OFFSET, 0);
-    }
-
-    public void setBlockId(int blockId) {
-        super.metadata.setIndex(OFFSET, EntityDataTypes.INT, blockId);
-    }
-
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/display/ItemDisplayMeta.java b/src/main/java/me/tofaa/entitylib/meta/display/ItemDisplayMeta.java
deleted file mode 100644
index eee43fe..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/display/ItemDisplayMeta.java
+++ /dev/null
@@ -1,47 +0,0 @@
-package me.tofaa.entitylib.meta.display;
-
-import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
-import com.github.retrooper.packetevents.protocol.item.ItemStack;
-import me.tofaa.entitylib.meta.Metadata;
-import me.tofaa.entitylib.meta.types.DisplayMeta;
-
-public class ItemDisplayMeta extends DisplayMeta {
-
-    public static final byte OFFSET = DisplayMeta.MAX_OFFSET;
-    public static final byte MAX_OFFSET = offset(OFFSET, 1);
-
-    public ItemDisplayMeta(int entityId, Metadata metadata) {
-        super(entityId, metadata);
-    }
-
-    public ItemStack getItem() {
-        return super.metadata.getIndex(OFFSET, ItemStack.EMPTY);
-    }
-
-    public void setItem(ItemStack itemStack) {
-        super.metadata.setIndex(OFFSET, EntityDataTypes.ITEMSTACK, itemStack);
-    }
-
-    public DisplayType getDisplayType() {
-        return DisplayType.VALUES[super.metadata.getIndex(offset(OFFSET, 1), 0)];
-    }
-
-    public void setDisplayType(DisplayType displayType) {
-        super.metadata.setIndex(offset(OFFSET, 1), EntityDataTypes.BYTE, (byte) displayType.ordinal());
-    }
-
-    public enum DisplayType {
-        NONE,
-        THIRD_PERSON_LEFT_HAND,
-        THIRD_PERSON_RIGHT_HAND,
-        FIRST_PERSON_LEFT_HAND,
-        FIRST_PERSON_RIGHT_HAND,
-        HEAD,
-        GUI,
-        GROUND,
-        FIXED;
-
-        private static final DisplayType[] VALUES = values();
-    }
-
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/display/TextDisplayMeta.java b/src/main/java/me/tofaa/entitylib/meta/display/TextDisplayMeta.java
deleted file mode 100644
index 314323b..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/display/TextDisplayMeta.java
+++ /dev/null
@@ -1,95 +0,0 @@
-package me.tofaa.entitylib.meta.display;
-
-import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
-import me.tofaa.entitylib.meta.Metadata;
-import me.tofaa.entitylib.meta.types.DisplayMeta;
-import net.kyori.adventure.text.Component;
-
-public class TextDisplayMeta extends DisplayMeta {
-
-    public static final byte OFFSET = DisplayMeta.MAX_OFFSET;
-    public static final byte MAX_OFFSET = offset(OFFSET, 5);
-
-    private static final byte SHADOW = 1;
-    private static final byte SEE_THROUGH = 2;
-    private static final byte USE_DEFAULT_BACKGROUND = 4;
-    private static final byte ALIGN_LEFT = 8;
-    private static final byte ALIGN_RIGHT = 16;
-
-    public TextDisplayMeta(int entityId, Metadata metadata) {
-        super(entityId, metadata);
-    }
-
-
-    public Component getText() {
-        return metadata.getIndex(OFFSET, Component.empty());
-    }
-
-    public void setText(Component component) {
-        metadata.setIndex(OFFSET, EntityDataTypes.ADV_COMPONENT, component);
-    }
-
-    public int getLineWidth() {
-        return metadata.getIndex(offset(OFFSET, 1), 200);
-    }
-
-    public void setLineWidth(int value) {
-        metadata.setIndex(offset(OFFSET, 1), EntityDataTypes.INT, value);
-    }
-
-    public int getBackgroundColor() {
-        return metadata.getIndex(offset(OFFSET, 2), 0);
-    }
-
-    public void setBackgroundColor(int value) {
-        metadata.setIndex(offset(OFFSET, 2), EntityDataTypes.INT, value);
-    }
-
-    public byte getTextOpacity() {
-        return metadata.getIndex(offset(OFFSET, 3), (byte) -1);
-    }
-
-    public void setTextOpacity(byte value) {
-        metadata.setIndex(offset(OFFSET, 3), EntityDataTypes.BYTE, value);
-    }
-
-    public boolean isShadow() {
-        return getMaskBit(offset(OFFSET, 4), SHADOW);
-    }
-
-    public void setShadow(boolean value) {
-        setMaskBit(offset(OFFSET, 4), SHADOW, value);
-    }
-
-    public boolean isSeeThrough() {
-        return getMaskBit(offset(OFFSET, 4), SEE_THROUGH);
-    }
-
-    public void setSeeThrough(boolean value) {
-        setMaskBit(offset(OFFSET, 4), SEE_THROUGH, value);
-    }
-
-    public boolean isUseDefaultBackground() {
-        return getMaskBit(offset(OFFSET, 4), USE_DEFAULT_BACKGROUND);
-    }
-
-    public void setUseDefaultBackground(boolean value) {
-        setMaskBit(offset(OFFSET, 4), USE_DEFAULT_BACKGROUND, value);
-    }
-
-    public boolean isAlignLeft() {
-        return getMaskBit(offset(OFFSET, 4), ALIGN_LEFT);
-    }
-
-    public void setAlignLeft(boolean value) {
-        setMaskBit(OFFSET + 4, ALIGN_LEFT, value);
-    }
-
-    public boolean isAlignRight() {
-        return getMaskBit(offset(OFFSET, 4), ALIGN_RIGHT);
-    }
-
-    public void setAlignRight(boolean value) {
-        setMaskBit(offset(OFFSET, 4), ALIGN_RIGHT, value);
-    }
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/mobs/BatMeta.java b/src/main/java/me/tofaa/entitylib/meta/mobs/BatMeta.java
deleted file mode 100644
index e98f8e3..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/mobs/BatMeta.java
+++ /dev/null
@@ -1,26 +0,0 @@
-package me.tofaa.entitylib.meta.mobs;
-
-import me.tofaa.entitylib.meta.Metadata;
-import me.tofaa.entitylib.meta.types.MobMeta;
-
-public class BatMeta extends MobMeta {
-
-    public static final byte OFFSET = MobMeta.MAX_OFFSET;
-    public static final byte MAX_OFFSET = OFFSET + 0;
-
-    private final static byte IS_HANGING_BIT = 0x01;
-
-    public BatMeta(int entityId, Metadata metadata) {
-        super(entityId, metadata);
-    }
-
-    public boolean isHanging() {
-        return getMaskBit(OFFSET, IS_HANGING_BIT);
-    }
-
-    public void setHanging(boolean value) {
-        setMaskBit(OFFSET, IS_HANGING_BIT, value);
-    }
-
-
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/mobs/BeeMeta.java b/src/main/java/me/tofaa/entitylib/meta/mobs/BeeMeta.java
deleted file mode 100644
index 80258fa..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/mobs/BeeMeta.java
+++ /dev/null
@@ -1,52 +0,0 @@
-package me.tofaa.entitylib.meta.mobs;
-
-import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
-import me.tofaa.entitylib.meta.Metadata;
-import me.tofaa.entitylib.meta.types.AgeableMeta;
-
-public class BeeMeta extends AgeableMeta {
-
-    public static final byte OFFSET = AgeableMeta.MAX_OFFSET;
-    public static final byte MAX_OFFSET = OFFSET + 2;
-
-    private final static byte ANGRY_BIT = 0x02;
-    private final static byte HAS_STUNG_BIT = 0x04;
-    private final static byte HAS_NECTAR_BIT = 0x08;
-
-    public BeeMeta(int entityId, Metadata metadata) {
-        super(entityId, metadata);
-    }
-
-    public boolean isAngry() {
-        return getMaskBit(OFFSET, ANGRY_BIT);
-    }
-
-    public void setAngry(boolean value) {
-        setMaskBit(OFFSET, ANGRY_BIT, value);
-    }
-
-    public boolean hasStung() {
-        return getMaskBit(OFFSET, HAS_STUNG_BIT);
-    }
-
-    public void setHasStung(boolean value) {
-        setMaskBit(OFFSET, HAS_STUNG_BIT, value);
-    }
-
-    public boolean hasNectar() {
-        return getMaskBit(OFFSET, HAS_NECTAR_BIT);
-    }
-
-    public void setHasNectar(boolean value) {
-        setMaskBit(OFFSET, HAS_NECTAR_BIT, value);
-    }
-
-    public int getAngerTicks() {
-        return super.metadata.getIndex(offset(OFFSET,1), 0);
-    }
-
-    public void setAngerTicks(int value) {
-        super.metadata.setIndex(offset(OFFSET,1), EntityDataTypes.INT, value);
-    }
-
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/mobs/DonkeyMeta.java b/src/main/java/me/tofaa/entitylib/meta/mobs/DonkeyMeta.java
deleted file mode 100644
index a494061..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/mobs/DonkeyMeta.java
+++ /dev/null
@@ -1,14 +0,0 @@
-package me.tofaa.entitylib.meta.mobs;
-
-import me.tofaa.entitylib.meta.Metadata;
-import me.tofaa.entitylib.meta.types.AgeableMeta;
-
-public class DonkeyMeta extends AgeableMeta {
-
-    public static final byte OFFSET = AgeableMeta.MAX_OFFSET;
-    public static final byte MAX_OFFSET = OFFSET + 0;
-
-    public DonkeyMeta(int entityId, Metadata metadata) {
-        super(entityId, metadata);
-    }
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/mobs/FoxMeta.java b/src/main/java/me/tofaa/entitylib/meta/mobs/FoxMeta.java
deleted file mode 100644
index c0f7a3f..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/mobs/FoxMeta.java
+++ /dev/null
@@ -1,119 +0,0 @@
-package me.tofaa.entitylib.meta.mobs;
-
-import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
-import me.tofaa.entitylib.meta.Metadata;
-import me.tofaa.entitylib.meta.types.AgeableMeta;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-import java.util.Optional;
-import java.util.UUID;
-
-public class FoxMeta extends AgeableMeta {
-
-    public static final byte OFFSET = AgeableMeta.MAX_OFFSET;
-    public static final byte MAX_OFFSET = OFFSET+ 4;
-
-    private final static byte SITTING_BIT = 0x01;
-    private final static byte CROUCHING_BIT = 0x04;
-    private final static byte INTERESTED_BIT = 0x08;
-    private final static byte POUNCING_BIT = 0x10;
-    private final static byte SLEEPING_BIT = 0x20;
-    private final static byte FACEPLANTED_BIT = 0x40;
-    private final static byte DEFENDING_BIT = (byte) 0x80;
-
-
-    public FoxMeta(int entityId, Metadata metadata) {
-        super(entityId, metadata);
-    }
-
-    @NotNull
-    public Type getType() {
-        return Type.VALUES[super.metadata.getIndex(OFFSET, 0)];
-    }
-
-    public void setType(@NotNull Type type) {
-        super.metadata.setIndex(OFFSET, EntityDataTypes.INT, type.ordinal());
-    }
-
-    public boolean isSitting() {
-        return getMaskBit(offset(OFFSET, 1), SITTING_BIT);
-    }
-
-    public void setSitting(boolean value) {
-        setMaskBit(offset(OFFSET, 1), SITTING_BIT, value);
-    }
-
-    public boolean isFoxSneaking() {
-        return getMaskBit(offset(OFFSET, 1), CROUCHING_BIT);
-    }
-
-    public void setFoxSneaking(boolean value) {
-        setMaskBit(offset(OFFSET, 1), CROUCHING_BIT, value);
-    }
-
-    public boolean isInterested() {
-        return getMaskBit(offset(OFFSET, 1), INTERESTED_BIT);
-    }
-
-    public void setInterested(boolean value) {
-        setMaskBit(offset(OFFSET, 1), INTERESTED_BIT, value);
-    }
-
-    public boolean isPouncing() {
-        return getMaskBit(offset(OFFSET, 1), POUNCING_BIT);
-    }
-
-    public void setPouncing(boolean value) {
-        setMaskBit(offset(OFFSET, 1), POUNCING_BIT, value);
-    }
-
-    public boolean isSleeping() {
-        return getMaskBit(offset(OFFSET, 1), SLEEPING_BIT);
-    }
-
-    public void setSleeping(boolean value) {
-        setMaskBit(offset(OFFSET, 1), SLEEPING_BIT, value);
-    }
-
-    public boolean isFaceplanted() {
-        return getMaskBit(offset(OFFSET, 1), FACEPLANTED_BIT);
-    }
-
-    public void setFaceplanted(boolean value) {
-        setMaskBit(offset(OFFSET, 1), FACEPLANTED_BIT, value);
-    }
-
-    public boolean isDefending() {
-        return getMaskBit(offset(OFFSET, 1), DEFENDING_BIT);
-    }
-
-    public void setDefending(boolean value) {
-        setMaskBit(offset(OFFSET, 1), DEFENDING_BIT, value);
-    }
-
-    public Optional<UUID> getFirstUUID() {
-        return super.metadata.getIndex(offset(OFFSET, 2), Optional.empty());
-    }
-
-    public void setFirstUUID(@Nullable UUID value) {
-        super.metadata.setIndex(offset(OFFSET, 2), EntityDataTypes.OPTIONAL_UUID, Optional.of(value));
-    }
-
-    public Optional<UUID> getSecondUUID() {
-        return super.metadata.getIndex(offset(OFFSET, 3), Optional.empty());
-    }
-
-    public void setSecondUUID(@Nullable UUID value) {
-        super.metadata.setIndex(offset(OFFSET, 3), EntityDataTypes.OPTIONAL_UUID, Optional.of(value));
-    }
-
-    public enum Type {
-        RED,
-        SNOW;
-
-        private final static Type[] VALUES = values();
-    }
-
-
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/mobs/FrogMeta.java b/src/main/java/me/tofaa/entitylib/meta/mobs/FrogMeta.java
deleted file mode 100644
index 876614d..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/mobs/FrogMeta.java
+++ /dev/null
@@ -1,46 +0,0 @@
-package me.tofaa.entitylib.meta.mobs;
-
-import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
-import me.tofaa.entitylib.meta.Metadata;
-import me.tofaa.entitylib.meta.types.AgeableMeta;
-import org.jetbrains.annotations.NotNull;
-
-import java.util.Optional;
-
-public class FrogMeta extends AgeableMeta {
-
-    public static final byte OFFSET = AgeableMeta.MAX_OFFSET;
-    public static final byte MAX_OFFSET = OFFSET + 2;
-
-
-    public FrogMeta(int entityId, Metadata metadata) {
-        super(entityId, metadata);
-    }
-
-
-    public @NotNull Variant getVariant() {
-        return super.metadata.getIndex(OFFSET, Variant.TEMPERATE);
-    }
-
-    public void setVariant(@NotNull Variant value) {
-        super.metadata.setIndex(OFFSET, EntityDataTypes.FROG_VARIANT, value.ordinal());
-    }
-
-    public Optional<Integer> getTongueTarget() {
-        return super.metadata.getIndex(offset(OFFSET, 1), Optional.empty());
-    }
-
-    public void setTongueTarget(int value) {
-        super.metadata.setIndex(offset(OFFSET, 1), EntityDataTypes.OPTIONAL_INT, Optional.of(value));
-    }
-
-
-    public enum Variant {
-        TEMPERATE,
-        WARM,
-        COLD;
-
-        private final static FrogMeta.Variant[] VALUES = values();
-    }
-
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/mobs/GoatMeta.java b/src/main/java/me/tofaa/entitylib/meta/mobs/GoatMeta.java
deleted file mode 100644
index 0fb05b9..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/mobs/GoatMeta.java
+++ /dev/null
@@ -1,25 +0,0 @@
-package me.tofaa.entitylib.meta.mobs;
-
-import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
-import me.tofaa.entitylib.meta.Metadata;
-import me.tofaa.entitylib.meta.types.AgeableMeta;
-
-public class GoatMeta extends AgeableMeta {
-
-    public static final byte OFFSET = AgeableMeta.MAX_OFFSET;
-    public static final byte MAX_OFFSET = OFFSET + 1;
-
-
-    public GoatMeta(int entityId, Metadata metadata) {
-        super(entityId, metadata);
-    }
-
-    public boolean isScreaming() {
-        return metadata.getIndex(OFFSET, false);
-    }
-
-    public void setScreaming(boolean screaming) {
-        metadata.setIndex(OFFSET, EntityDataTypes.BOOLEAN, screaming);
-    }
-
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/mobs/HoglinMeta.java b/src/main/java/me/tofaa/entitylib/meta/mobs/HoglinMeta.java
deleted file mode 100644
index 5c3c4bc..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/mobs/HoglinMeta.java
+++ /dev/null
@@ -1,26 +0,0 @@
-package me.tofaa.entitylib.meta.mobs;
-
-import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
-import me.tofaa.entitylib.meta.Metadata;
-import me.tofaa.entitylib.meta.types.AgeableMeta;
-
-public class HoglinMeta extends AgeableMeta {
-
-    public static final byte OFFSET = AgeableMeta.MAX_OFFSET;
-    public static final byte MAX_OFFSET = OFFSET + 1;
-
-    public HoglinMeta(int entityId, Metadata metadata) {
-        super(entityId, metadata);
-    }
-
-
-    public boolean isImmuneToZombification() {
-        return super.metadata.getIndex(OFFSET, false);
-    }
-
-    public void setImmuneToZombification(boolean value) {
-        super.metadata.setIndex(OFFSET, EntityDataTypes.BOOLEAN, value);
-    }
-
-
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/mobs/OcelotMeta.java b/src/main/java/me/tofaa/entitylib/meta/mobs/OcelotMeta.java
deleted file mode 100644
index 7e93470..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/mobs/OcelotMeta.java
+++ /dev/null
@@ -1,27 +0,0 @@
-package me.tofaa.entitylib.meta.mobs;
-
-import com.github.retrooper.packetevents.manager.server.ServerVersion;
-import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
-import me.tofaa.entitylib.meta.Metadata;
-import me.tofaa.entitylib.meta.types.AgeableMeta;
-
-public class OcelotMeta extends AgeableMeta {
-
-    public static final byte OFFSET = AgeableMeta.MAX_OFFSET;
-    public static final byte MAX_OFFSET = OFFSET + 1;
-
-    public OcelotMeta(int entityId, Metadata metadata) {
-        super(entityId, metadata);
-    }
-
-    public boolean isTrusting() {
-        isVersionNewer(ServerVersion.V_1_14);
-        return super.metadata.getIndex(OFFSET, false);
-    }
-
-    public void setTrusting(boolean value) {
-        isVersionNewer(ServerVersion.V_1_14);
-        super.metadata.setIndex(OFFSET, EntityDataTypes.BOOLEAN, value);
-    }
-
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/mobs/PandaMeta.java b/src/main/java/me/tofaa/entitylib/meta/mobs/PandaMeta.java
deleted file mode 100644
index 957c3ae..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/mobs/PandaMeta.java
+++ /dev/null
@@ -1,109 +0,0 @@
-package me.tofaa.entitylib.meta.mobs;
-
-import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
-import me.tofaa.entitylib.meta.Metadata;
-import me.tofaa.entitylib.meta.types.AgeableMeta;
-import org.jetbrains.annotations.NotNull;
-
-public class PandaMeta extends AgeableMeta {
-
-    public static final byte OFFSET = AgeableMeta.MAX_OFFSET;
-    public static final byte MAX_OFFSET = OFFSET + 6;
-
-    private final static byte SNEEZING_BIT = 0x02;
-    private final static byte ROLLING_BIT = 0x04;
-    private final static byte SITTING_BIT = 0x08;
-    private final static byte ON_BACK_BIT = 0x10;
-
-    public PandaMeta(int entityId, Metadata metadata) {
-        super(entityId, metadata);
-    }
-
-    public int getBreedTimer() {
-        return super.metadata.getIndex(OFFSET, 0);
-    }
-
-    public void setBreedTimer(int value) {
-        super.metadata.setIndex(OFFSET, EntityDataTypes.INT, value);
-    }
-
-    public int getSneezeTimer() {
-        return super.metadata.getIndex(offset(OFFSET,1), 0);
-    }
-
-    public void setSneezeTimer(int value) {
-        super.metadata.setIndex(offset(OFFSET,1), EntityDataTypes.INT, value);
-    }
-
-    public int getEatTimer() {
-        return super.metadata.getIndex(offset(OFFSET,2), 0);
-    }
-
-    public void setEatTimer(int value) {
-        super.metadata.setIndex(offset(OFFSET,2), EntityDataTypes.INT, value);
-    }
-
-    @NotNull
-    public Gene getMainGene() {
-        return Gene.VALUES[super.metadata.getIndex(offset(OFFSET,3), (byte) 0)];
-    }
-
-    public void setMainGene(@NotNull Gene value) {
-        super.metadata.setIndex(offset(OFFSET,3), EntityDataTypes.BYTE, (byte) value.ordinal());
-    }
-
-    @NotNull
-    public Gene getHiddenGene() {
-        return Gene.VALUES[super.metadata.getIndex(offset(OFFSET,4), (byte) 0)];
-    }
-
-    public void setHiddenGene(@NotNull Gene value) {
-        super.metadata.setIndex(offset(OFFSET,4), EntityDataTypes.BYTE, (byte) value.ordinal());
-    }
-
-    public boolean isSneezing() {
-        return getMaskBit(offset(OFFSET,5), SNEEZING_BIT);
-    }
-
-    public void setSneezing(boolean value) {
-        setMaskBit(offset(OFFSET,5), SNEEZING_BIT, value);
-    }
-
-    public boolean isRolling() {
-        return getMaskBit(offset(OFFSET,5), ROLLING_BIT);
-    }
-
-    public void setRolling(boolean value) {
-        setMaskBit(offset(OFFSET,5), ROLLING_BIT, value);
-    }
-
-    public boolean isSitting() {
-        return getMaskBit(offset(OFFSET,5), SITTING_BIT);
-    }
-
-    public void setSitting(boolean value) {
-        setMaskBit(offset(OFFSET,5), SITTING_BIT, value);
-    }
-
-    public boolean isOnBack() {
-        return getMaskBit(offset(OFFSET,5), ON_BACK_BIT);
-    }
-
-    public void setOnBack(boolean value) {
-        setMaskBit(offset(OFFSET,5), ON_BACK_BIT, value);
-    }
-
-    public enum Gene {
-        NORMAL,
-        AGGRESSIVE,
-        LAZY,
-        WORRIED,
-        PLAYFUL,
-        WEAK,
-        BROWN;
-
-        private final static Gene[] VALUES = values();
-    }
-
-
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/mobs/PolarBearMeta.java b/src/main/java/me/tofaa/entitylib/meta/mobs/PolarBearMeta.java
deleted file mode 100644
index 78d03c6..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/mobs/PolarBearMeta.java
+++ /dev/null
@@ -1,24 +0,0 @@
-package me.tofaa.entitylib.meta.mobs;
-
-import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
-import me.tofaa.entitylib.meta.Metadata;
-import me.tofaa.entitylib.meta.types.AgeableMeta;
-
-public class PolarBearMeta extends AgeableMeta {
-
-    public static final byte OFFSET = AgeableMeta.MAX_OFFSET;
-    public static final byte MAX_OFFSET = OFFSET + 1;
-
-    public PolarBearMeta(int entityId, Metadata metadata) {
-        super(entityId, metadata);
-    }
-
-    public boolean isStandingUp() {
-        return super.metadata.getIndex(OFFSET, false);
-    }
-
-    public void setStandingUp(boolean value) {
-        super.metadata.setIndex(OFFSET, EntityDataTypes.BOOLEAN, value);
-    }
-
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/mobs/SnifferMeta.java b/src/main/java/me/tofaa/entitylib/meta/mobs/SnifferMeta.java
deleted file mode 100644
index 2d0c571..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/mobs/SnifferMeta.java
+++ /dev/null
@@ -1,33 +0,0 @@
-package me.tofaa.entitylib.meta.mobs;
-
-import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
-import com.github.retrooper.packetevents.protocol.entity.sniffer.SnifferState;
-import me.tofaa.entitylib.meta.Metadata;
-import me.tofaa.entitylib.meta.types.AgeableMeta;
-
-public class SnifferMeta extends AgeableMeta {
-
-    public static final byte OFFSET = AgeableMeta.MAX_OFFSET;
-    public static final byte MAX_OFFSET = OFFSET + 1;
-
-    public SnifferMeta(int entityId, Metadata metadata) {
-        super(entityId, metadata);
-    }
-
-    public SnifferState getState() {
-        return metadata.getIndex(OFFSET, SnifferState.IDLING);
-    }
-
-    public void setState(SnifferState state) {
-        super.metadata.setIndex(OFFSET, EntityDataTypes.SNIFFER_STATE, state);
-    }
-
-    public int getDropSeedAtTick() {
-        return metadata.getIndex(offset(OFFSET, 1), 0);
-    }
-
-    public void setDropSeedAtTick(int tick) {
-        super.metadata.setIndex(offset(OFFSET, 1), EntityDataTypes.INT, tick);
-    }
-
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/mobs/StriderMeta.java b/src/main/java/me/tofaa/entitylib/meta/mobs/StriderMeta.java
deleted file mode 100644
index b3bb11c..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/mobs/StriderMeta.java
+++ /dev/null
@@ -1,41 +0,0 @@
-package me.tofaa.entitylib.meta.mobs;
-
-import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
-import me.tofaa.entitylib.meta.Metadata;
-import me.tofaa.entitylib.meta.types.AgeableMeta;
-
-public class StriderMeta extends AgeableMeta {
-
-    public static final byte OFFSET = AgeableMeta.MAX_OFFSET;
-    public static final byte MAX_OFFSET = OFFSET + 3;
-
-    public StriderMeta(int entityId, Metadata metadata) {
-        super(entityId, metadata);
-    }
-
-
-    public int getTimeToBoost() {
-        return super.metadata.getIndex(OFFSET, 0);
-    }
-
-    public void setTimeToBoost(int value) {
-        super.metadata.setIndex(OFFSET, EntityDataTypes.INT, value);
-    }
-
-    public boolean isShaking() {
-        return super.metadata.getIndex(offset(OFFSET,1), false);
-    }
-
-    public void setShaking(boolean value) {
-        super.metadata.setIndex(offset(OFFSET, 1), EntityDataTypes.BOOLEAN, value);
-    }
-
-    public boolean isHasSaddle() {
-        return super.metadata.getIndex(offset(OFFSET, 2), false);
-    }
-
-    public void setHasSaddle(boolean value) {
-        super.metadata.setIndex(offset(OFFSET, 2), EntityDataTypes.BOOLEAN, value);
-    }
-
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/mobs/cuboid/MagmaCubeMeta.java b/src/main/java/me/tofaa/entitylib/meta/mobs/cuboid/MagmaCubeMeta.java
deleted file mode 100644
index f2e96d1..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/mobs/cuboid/MagmaCubeMeta.java
+++ /dev/null
@@ -1,13 +0,0 @@
-package me.tofaa.entitylib.meta.mobs.cuboid;
-
-import me.tofaa.entitylib.meta.Metadata;
-
-public class MagmaCubeMeta extends SlimeMeta {
-
-    public static final byte OFFSET = SlimeMeta.MAX_OFFSET;
-    public static final byte MAX_OFFSET = OFFSET + 0;
-
-    public MagmaCubeMeta(int entityId, Metadata metadata) {
-        super(entityId, metadata);
-    }
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/mobs/cuboid/SlimeMeta.java b/src/main/java/me/tofaa/entitylib/meta/mobs/cuboid/SlimeMeta.java
deleted file mode 100644
index ff6ed74..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/mobs/cuboid/SlimeMeta.java
+++ /dev/null
@@ -1,23 +0,0 @@
-package me.tofaa.entitylib.meta.mobs.cuboid;
-
-import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
-import me.tofaa.entitylib.meta.Metadata;
-import me.tofaa.entitylib.meta.types.MobMeta;
-
-public class SlimeMeta extends MobMeta {
-    public static final byte OFFSET = MobMeta.MAX_OFFSET;
-    public static final byte MAX_OFFSET = OFFSET + 1;
-
-    public SlimeMeta(int entityId, Metadata metadata) {
-        super(entityId, metadata);
-    }
-
-    public int getSize() {
-        return super.metadata.getIndex(OFFSET, 0);
-    }
-
-    public void setSize(int value) {
-        super.metadata.setIndex(OFFSET, EntityDataTypes.INT, value);
-    }
-
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/mobs/golem/IronGolemMeta.java b/src/main/java/me/tofaa/entitylib/meta/mobs/golem/IronGolemMeta.java
deleted file mode 100644
index 55e83ca..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/mobs/golem/IronGolemMeta.java
+++ /dev/null
@@ -1,26 +0,0 @@
-package me.tofaa.entitylib.meta.mobs.golem;
-
-import me.tofaa.entitylib.meta.Metadata;
-import me.tofaa.entitylib.meta.types.MobMeta;
-
-public class IronGolemMeta extends MobMeta {
-
-    public static final byte OFFSET = MobMeta.MAX_OFFSET;
-    public static final byte MAX_OFFSET = OFFSET + 1;
-
-    private final static byte PLAYER_CREATED_BIT = 0x01;
-
-    public IronGolemMeta(int entityId, Metadata metadata) {
-        super(entityId, metadata);
-    }
-
-    public boolean isPlayerCreated() {
-        return getMaskBit(OFFSET, PLAYER_CREATED_BIT);
-    }
-
-    public void setPlayerCreated(boolean value) {
-        setMaskBit(OFFSET, PLAYER_CREATED_BIT, value);
-    }
-
-
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/mobs/golem/ShulkerMeta.java b/src/main/java/me/tofaa/entitylib/meta/mobs/golem/ShulkerMeta.java
deleted file mode 100644
index 88617a9..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/mobs/golem/ShulkerMeta.java
+++ /dev/null
@@ -1,54 +0,0 @@
-package me.tofaa.entitylib.meta.mobs.golem;
-
-import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
-import com.github.retrooper.packetevents.protocol.world.Direction;
-import com.github.retrooper.packetevents.util.Vector3i;
-import me.tofaa.entitylib.meta.Metadata;
-import me.tofaa.entitylib.meta.types.MobMeta;
-
-import java.util.Optional;
-
-public class ShulkerMeta extends MobMeta {
-
-    public static final byte OFFSET = MobMeta.MAX_OFFSET;
-    public static final byte MAX_OFFSET = OFFSET + 1;
-
-
-    public ShulkerMeta(int entityId, Metadata metadata) {
-        super(entityId, metadata);
-    }
-
-    public Direction getAttachFace() {
-        return super.metadata.getIndex(OFFSET, Direction.DOWN);
-    }
-
-    public void setAttachFace(Direction value) {
-        super.metadata.setIndex(OFFSET, EntityDataTypes.INT, value.ordinal());
-    }
-
-    public Optional<Vector3i> getAttachmentPosition() {
-        return super.metadata.getIndex(offset(OFFSET, 1), Optional.empty());
-    }
-
-    public void setAttachmentPosition(Vector3i value) {
-        super.metadata.setIndex(offset(OFFSET, 1), EntityDataTypes.OPTIONAL_BLOCK_POSITION, Optional.of(value));
-    }
-
-    public byte getShieldHeight() {
-        return super.metadata.getIndex(offset(OFFSET, 2), (byte) 0);
-    }
-
-    public void setShieldHeight(byte value) {
-        super.metadata.setIndex(offset(OFFSET, 2), EntityDataTypes.BYTE, value);
-    }
-
-    public byte getColor() {
-        return super.metadata.getIndex(offset(OFFSET, 3), (byte) 10);
-    }
-
-    public void setColor(byte value) {
-        super.metadata.setIndex(offset(OFFSET, 3), EntityDataTypes.BYTE, value);
-    }
-
-
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/mobs/golem/SnowGolemMeta.java b/src/main/java/me/tofaa/entitylib/meta/mobs/golem/SnowGolemMeta.java
deleted file mode 100644
index d2bb5a5..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/mobs/golem/SnowGolemMeta.java
+++ /dev/null
@@ -1,25 +0,0 @@
-package me.tofaa.entitylib.meta.mobs.golem;
-
-import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
-import me.tofaa.entitylib.meta.Metadata;
-import me.tofaa.entitylib.meta.types.MobMeta;
-
-public class SnowGolemMeta extends MobMeta {
-
-    public static final byte OFFSET = MobMeta.MAX_OFFSET;
-    public static final byte MAX_OFFSET = OFFSET + 1;
-
-    public SnowGolemMeta(int entityId, Metadata metadata) {
-        super(entityId, metadata);
-    }
-
-    public boolean isHasPumpkinHat() {
-        return super.metadata.getIndex(OFFSET, (byte) 0x10) == (byte) 0x10;
-    }
-
-    public void setHasPumpkinHat(boolean value) {
-        byte var = value ? (byte) 0x10 : (byte) 0x00;
-        super.metadata.setIndex(OFFSET, EntityDataTypes.BYTE, var);
-    }
-
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/mobs/horse/BaseHorseMeta.java b/src/main/java/me/tofaa/entitylib/meta/mobs/horse/BaseHorseMeta.java
deleted file mode 100644
index 1dd8637..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/mobs/horse/BaseHorseMeta.java
+++ /dev/null
@@ -1,82 +0,0 @@
-package me.tofaa.entitylib.meta.mobs.horse;
-
-import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
-import me.tofaa.entitylib.meta.Metadata;
-import me.tofaa.entitylib.meta.types.MobMeta;
-
-import java.util.Optional;
-import java.util.UUID;
-
-public abstract class BaseHorseMeta extends MobMeta {
-
-    public static final byte OFFSET = MobMeta.MAX_OFFSET;
-    public static final byte MAX_OFFSET = OFFSET + 2;
-
-    private final static byte TAMED_BIT = 0x02;
-    private final static byte SADDLED_BIT = 0x04;
-    private final static byte HAS_BRED_BIT = 0x08;
-    private final static byte EATING_BIT = 0x10;
-    private final static byte REARING_BIT = 0x20;
-    private final static byte MOUTH_OPEN_BIT = 0x40;
-
-    protected BaseHorseMeta(int entityId, Metadata metadata) {
-        super(entityId, metadata);
-    }
-
-    public boolean isTamed() {
-        return getMaskBit(OFFSET, TAMED_BIT);
-    }
-
-    public void setTamed(boolean value) {
-        setMaskBit(OFFSET, TAMED_BIT, value);
-    }
-
-    public boolean isSaddled() {
-        return getMaskBit(OFFSET, SADDLED_BIT);
-    }
-
-    public void setSaddled(boolean value) {
-        setMaskBit(OFFSET, SADDLED_BIT, value);
-    }
-
-    public boolean isHasBred() {
-        return getMaskBit(OFFSET, HAS_BRED_BIT);
-    }
-
-    public void setHasBred(boolean value) {
-        setMaskBit(OFFSET, HAS_BRED_BIT, value);
-    }
-
-    public boolean isEating() {
-        return getMaskBit(OFFSET, EATING_BIT);
-    }
-
-    public void setEating(boolean value) {
-        setMaskBit(OFFSET, EATING_BIT, value);
-    }
-
-    public boolean isRearing() {
-        return getMaskBit(OFFSET, REARING_BIT);
-    }
-
-    public void setRearing(boolean value) {
-        setMaskBit(OFFSET, REARING_BIT, value);
-    }
-
-    public boolean isMouthOpen() {
-        return getMaskBit(OFFSET, MOUTH_OPEN_BIT);
-    }
-
-    public void setMouthOpen(boolean value) {
-        setMaskBit(OFFSET, MOUTH_OPEN_BIT, value);
-    }
-
-    public Optional<UUID> getOwner() {
-        return super.metadata.getIndex(offset(OFFSET, 1), Optional.empty());
-    }
-
-    public void setOwner(UUID value) {
-        super.metadata.setIndex(offset(OFFSET, 1), EntityDataTypes.OPTIONAL_UUID, Optional.of(value));
-    }
-
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/mobs/horse/ChestedHorseMeta.java b/src/main/java/me/tofaa/entitylib/meta/mobs/horse/ChestedHorseMeta.java
deleted file mode 100644
index 596d443..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/mobs/horse/ChestedHorseMeta.java
+++ /dev/null
@@ -1,24 +0,0 @@
-package me.tofaa.entitylib.meta.mobs.horse;
-
-import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
-import me.tofaa.entitylib.meta.Metadata;
-
-public class ChestedHorseMeta extends BaseHorseMeta {
-
-    public static final byte OFFSET = BaseHorseMeta.MAX_OFFSET;
-    public static final byte MAX_OFFSET = OFFSET + 1;
-
-    public ChestedHorseMeta(int entityId, Metadata metadata) {
-        super(entityId, metadata);
-    }
-
-    public boolean isHasChest() {
-        return super.metadata.getIndex(OFFSET, false);
-    }
-
-    public void setHasChest(boolean value) {
-        super.metadata.setIndex(OFFSET, EntityDataTypes.BOOLEAN, value);
-    }
-
-
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/mobs/horse/DonkeyMeta.java b/src/main/java/me/tofaa/entitylib/meta/mobs/horse/DonkeyMeta.java
deleted file mode 100644
index d398ced..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/mobs/horse/DonkeyMeta.java
+++ /dev/null
@@ -1,14 +0,0 @@
-package me.tofaa.entitylib.meta.mobs.horse;
-
-import me.tofaa.entitylib.meta.Metadata;
-import me.tofaa.entitylib.meta.types.MobMeta;
-
-public class DonkeyMeta  extends ChestedHorseMeta{
-
-    public static final byte OFFSET = MobMeta.MAX_OFFSET;
-    public static final byte MAX_OFFSET = OFFSET + 0;
-
-    public DonkeyMeta(int entityId, Metadata metadata) {
-        super(entityId, metadata);
-    }
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/mobs/horse/HorseMeta.java b/src/main/java/me/tofaa/entitylib/meta/mobs/horse/HorseMeta.java
deleted file mode 100644
index 246aeb7..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/mobs/horse/HorseMeta.java
+++ /dev/null
@@ -1,87 +0,0 @@
-package me.tofaa.entitylib.meta.mobs.horse;
-
-import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
-import me.tofaa.entitylib.meta.Metadata;
-import org.jetbrains.annotations.NotNull;
-
-public class HorseMeta extends BaseHorseMeta {
-
-    public static final byte OFFSET = BaseHorseMeta.MAX_OFFSET;
-    public static final byte MAX_OFFSET = OFFSET + 1;
-
-    public HorseMeta(int entityId, Metadata metadata) {
-        super(entityId, metadata);
-    }
-
-    public Variant getVariant() {
-        return getVariantFromID(super.metadata.getIndex(OFFSET, 0));
-    }
-
-    public void setVariant(Variant variant) {
-        super.metadata.setIndex(OFFSET, EntityDataTypes.INT, getVariantID(variant.marking, variant.color));
-    }
-
-    public static int getVariantID(@NotNull Marking marking, @NotNull Color color) {
-        return (marking.ordinal() << 8) + color.ordinal();
-    }
-
-    public static Variant getVariantFromID(int variantID) {
-        return new Variant(
-                Marking.VALUES[variantID >> 8],
-                Color.VALUES[variantID & 0xFF]
-        );
-    }
-
-    public static class Variant {
-
-        private Marking marking;
-        private Color color;
-
-        public Variant(@NotNull Marking marking, @NotNull Color color) {
-            this.marking = marking;
-            this.color = color;
-        }
-
-        @NotNull
-        public Marking getMarking() {
-            return this.marking;
-        }
-
-        public void setMarking(@NotNull Marking marking) {
-            this.marking = marking;
-        }
-
-        @NotNull
-        public Color getColor() {
-            return this.color;
-        }
-
-        public void setColor(@NotNull Color color) {
-            this.color = color;
-        }
-
-    }
-
-    public enum Marking {
-        NONE,
-        WHITE,
-        WHITE_FIELD,
-        WHITE_DOTS,
-        BLACK_DOTS;
-
-        private final static Marking[] VALUES = values();
-    }
-
-    public enum Color {
-        WHITE,
-        CREAMY,
-        CHESTNUT,
-        BROWN,
-        BLACK,
-        GRAY,
-        DARK_BROWN;
-
-        private final static Color[] VALUES = values();
-    }
-
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/mobs/horse/LlamaMeta.java b/src/main/java/me/tofaa/entitylib/meta/mobs/horse/LlamaMeta.java
deleted file mode 100644
index 053848e..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/mobs/horse/LlamaMeta.java
+++ /dev/null
@@ -1,48 +0,0 @@
-package me.tofaa.entitylib.meta.mobs.horse;
-
-import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
-import me.tofaa.entitylib.meta.Metadata;
-
-public class LlamaMeta extends ChestedHorseMeta{
-
-    public static final byte OFFSET = ChestedHorseMeta.MAX_OFFSET;
-    public static final byte MAX_OFFSET = OFFSET + 3;
-
-    public LlamaMeta(int entityId, Metadata metadata) {
-        super(entityId, metadata);
-    }
-
-    public int getStrength() {
-        return super.metadata.getIndex(OFFSET, 0);
-    }
-
-    public void setStrength(int value) {
-        super.metadata.setIndex(OFFSET, EntityDataTypes.INT, value);
-    }
-
-    public int getCarpetColor() {
-        return super.metadata.getIndex(offset(OFFSET, 1), -1);
-    }
-
-    public void setCarpetColor(int value) {
-        super.metadata.setIndex(offset(OFFSET, 1), EntityDataTypes.INT, value);
-    }
-
-    public Variant getVariant() {
-        return Variant.VALUES[super.metadata.getIndex(offset(OFFSET, 2), 0)];
-    }
-
-    public void setVariant(Variant value) {
-        super.metadata.setIndex(offset(OFFSET, 2), EntityDataTypes.INT, value.ordinal());
-    }
-
-    public enum Variant {
-        CREAMY,
-        WHITE,
-        BROWN,
-        GRAY;
-
-        private final static Variant[] VALUES = values();
-    }
-
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/mobs/horse/MuleMeta.java b/src/main/java/me/tofaa/entitylib/meta/mobs/horse/MuleMeta.java
deleted file mode 100644
index f5c6b4e..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/mobs/horse/MuleMeta.java
+++ /dev/null
@@ -1,13 +0,0 @@
-package me.tofaa.entitylib.meta.mobs.horse;
-
-import me.tofaa.entitylib.meta.Metadata;
-
-public class MuleMeta extends ChestedHorseMeta{
-
-    public static final byte OFFSET = ChestedHorseMeta.MAX_OFFSET;
-    public static final byte MAX_OFFSET = OFFSET + 0;
-
-    public MuleMeta(int entityId, Metadata metadata) {
-        super(entityId, metadata);
-    }
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/mobs/horse/SkeletonHorseMeta.java b/src/main/java/me/tofaa/entitylib/meta/mobs/horse/SkeletonHorseMeta.java
deleted file mode 100644
index fb4d1c4..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/mobs/horse/SkeletonHorseMeta.java
+++ /dev/null
@@ -1,13 +0,0 @@
-package me.tofaa.entitylib.meta.mobs.horse;
-
-import me.tofaa.entitylib.meta.Metadata;
-
-public class SkeletonHorseMeta extends BaseHorseMeta {
-
-    public static final byte OFFSET = BaseHorseMeta.MAX_OFFSET;
-    public static final byte MAX_OFFSET = OFFSET + 0;
-
-    public SkeletonHorseMeta(int entityId, Metadata metadata) {
-        super(entityId, metadata);
-    }
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/mobs/horse/TraderLlamaMeta.java b/src/main/java/me/tofaa/entitylib/meta/mobs/horse/TraderLlamaMeta.java
deleted file mode 100644
index a4d101d..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/mobs/horse/TraderLlamaMeta.java
+++ /dev/null
@@ -1,14 +0,0 @@
-package me.tofaa.entitylib.meta.mobs.horse;
-
-import me.tofaa.entitylib.meta.EntityMeta;
-import me.tofaa.entitylib.meta.Metadata;
-
-public class TraderLlamaMeta extends EntityMeta {
-
-    public static final byte OFFSET = EntityMeta.MAX_OFFSET;
-    public static final byte MAX_OFFSET = OFFSET + 0;
-
-    public TraderLlamaMeta(int entityId, Metadata metadata) {
-        super(entityId, metadata);
-    }
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/mobs/horse/ZombieHorseMeta.java b/src/main/java/me/tofaa/entitylib/meta/mobs/horse/ZombieHorseMeta.java
deleted file mode 100644
index b0c42f1..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/mobs/horse/ZombieHorseMeta.java
+++ /dev/null
@@ -1,13 +0,0 @@
-package me.tofaa.entitylib.meta.mobs.horse;
-
-import me.tofaa.entitylib.meta.Metadata;
-
-public class ZombieHorseMeta extends BaseHorseMeta {
-
-    public static final byte OFFSET = BaseHorseMeta.MAX_OFFSET;
-    public static final byte MAX_OFFSET = OFFSET + 0;
-
-    public ZombieHorseMeta(int entityId, Metadata metadata) {
-        super(entityId, metadata);
-    }
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/mobs/minecart/BaseMinecartMeta.java b/src/main/java/me/tofaa/entitylib/meta/mobs/minecart/BaseMinecartMeta.java
deleted file mode 100644
index 8f17929..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/mobs/minecart/BaseMinecartMeta.java
+++ /dev/null
@@ -1,62 +0,0 @@
-package me.tofaa.entitylib.meta.mobs.minecart;
-
-import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
-import me.tofaa.entitylib.meta.EntityMeta;
-import me.tofaa.entitylib.meta.Metadata;
-import me.tofaa.entitylib.meta.types.ObjectData;
-
-public abstract class BaseMinecartMeta extends EntityMeta implements ObjectData {
-
-    public static final byte OFFSET = EntityMeta.MAX_OFFSET;
-    public static final byte MAX_OFFSET = OFFSET + 6;
-
-    protected BaseMinecartMeta(int entityId, Metadata metadata) {
-        super(entityId, metadata);
-    }
-
-    public int getShakingPower() {
-        return super.metadata.getIndex(OFFSET, 0);
-    }
-
-    public void setShakingPower(int value) {
-        super.metadata.setIndex(OFFSET, EntityDataTypes.INT, value);
-    }
-
-    public int getShakingDirection() {
-        return super.metadata.getIndex(offset(OFFSET, 1), 1);
-    }
-
-    public void setShakingDirection(int value) {
-        super.metadata.setIndex(offset(OFFSET, 1), EntityDataTypes.INT, value);
-    }
-
-    public float getShakingMultiplier() {
-        return super.metadata.getIndex(offset(OFFSET, 2), 0F);
-    }
-
-    public void setShakingMultiplier(float value) {
-        super.metadata.setIndex(offset(OFFSET, 2), EntityDataTypes.FLOAT, value);
-    }
-
-    public int getCustomBlockIdAndDamage() {
-        return super.metadata.getIndex(offset(OFFSET, 3), 0);
-    }
-
-    public void setCustomBlockIdAndDamage(int value) {
-        super.metadata.setIndex(offset(OFFSET, 3), EntityDataTypes.INT, value);
-    }
-
-    // in 16th of a block
-    public int getCustomBlockYPosition() {
-        return super.metadata.getIndex(offset(OFFSET, 4), 6);
-    }
-
-    public void setCustomBlockYPosition(int value) {
-        super.metadata.setIndex(offset(OFFSET, 4), EntityDataTypes.INT, value);
-    }
-
-    @Override
-    public boolean requiresVelocityPacketAtSpawn() {
-        return true;
-    }
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/mobs/minecart/ChestMinecartMeta.java b/src/main/java/me/tofaa/entitylib/meta/mobs/minecart/ChestMinecartMeta.java
deleted file mode 100644
index b3d0b7a..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/mobs/minecart/ChestMinecartMeta.java
+++ /dev/null
@@ -1,19 +0,0 @@
-package me.tofaa.entitylib.meta.mobs.minecart;
-
-import me.tofaa.entitylib.meta.Metadata;
-
-public class ChestMinecartMeta extends BaseMinecartMeta{
-
-    public static final byte OFFSET = BaseMinecartMeta.MAX_OFFSET;
-    public static final byte MAX_OFFSET = OFFSET + 0;
-
-
-    public ChestMinecartMeta(int entityId, Metadata metadata) {
-        super(entityId, metadata);
-    }
-
-    @Override
-    public int getObjectData() {
-        return 1;
-    }
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/mobs/minecart/CommandBlockMinecartMeta.java b/src/main/java/me/tofaa/entitylib/meta/mobs/minecart/CommandBlockMinecartMeta.java
deleted file mode 100644
index 10459d2..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/mobs/minecart/CommandBlockMinecartMeta.java
+++ /dev/null
@@ -1,38 +0,0 @@
-package me.tofaa.entitylib.meta.mobs.minecart;
-
-import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
-import me.tofaa.entitylib.meta.Metadata;
-import net.kyori.adventure.text.Component;
-import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
-import org.jetbrains.annotations.NotNull;
-
-public class CommandBlockMinecartMeta extends BaseMinecartMeta{
-
-    public static final byte OFFSET = BaseMinecartMeta.MAX_OFFSET;
-    public static final byte MAX_OFFSET = OFFSET + 2;
-
-    public CommandBlockMinecartMeta(int entityId, Metadata metadata) {
-        super(entityId, metadata);
-    }
-
-    public @NotNull String getCommand() {
-        return super.metadata.getIndex(OFFSET, "");
-    }
-
-    public void setCommand(@NotNull String value) {
-        super.metadata.setIndex(OFFSET, EntityDataTypes.STRING, value);
-    }
-
-    public @NotNull Component getLastOutput() {
-        return super.metadata.getIndex(offset(OFFSET, 1), Component.empty());
-    }
-
-    public void setLastOutput(@NotNull Component value) {
-        super.metadata.setIndex(offset(OFFSET, 1), EntityDataTypes.COMPONENT, GsonComponentSerializer.gson().serialize(value));
-    }
-
-    @Override
-    public int getObjectData() {
-        return 6;
-    }
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/mobs/minecart/FurnaceMinecartMeta.java b/src/main/java/me/tofaa/entitylib/meta/mobs/minecart/FurnaceMinecartMeta.java
deleted file mode 100644
index 9f745bb..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/mobs/minecart/FurnaceMinecartMeta.java
+++ /dev/null
@@ -1,26 +0,0 @@
-package me.tofaa.entitylib.meta.mobs.minecart;
-
-import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
-import me.tofaa.entitylib.meta.Metadata;
-
-public class FurnaceMinecartMeta extends BaseMinecartMeta {
-
-    public static final byte OFFSET = BaseMinecartMeta.MAX_OFFSET;
-    public static final byte MAX_OFFSET = OFFSET + 1;
-
-    public FurnaceMinecartMeta(int entityId, Metadata metadata) {
-        super(entityId, metadata);
-    }
-
-    public boolean isHasFuel() {
-        return super.metadata.getIndex(OFFSET, false);
-    }
-
-    public void setHasFuel(boolean value) {
-        super.metadata.setIndex(OFFSET, EntityDataTypes.BOOLEAN, value);
-    }
-
-    @Override
-    public int getObjectData() {
-        return 2;    }
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/mobs/minecart/HopperMinecartMeta.java b/src/main/java/me/tofaa/entitylib/meta/mobs/minecart/HopperMinecartMeta.java
deleted file mode 100644
index ac8a4fb..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/mobs/minecart/HopperMinecartMeta.java
+++ /dev/null
@@ -1,18 +0,0 @@
-package me.tofaa.entitylib.meta.mobs.minecart;
-
-import me.tofaa.entitylib.meta.Metadata;
-
-public class HopperMinecartMeta extends BaseMinecartMeta {
-
-    public static final byte OFFSET = BaseMinecartMeta.MAX_OFFSET;
-    public static final byte MAX_OFFSET = OFFSET + 0;
-
-    public HopperMinecartMeta(int entityId, Metadata metadata) {
-        super(entityId, metadata);
-    }
-
-    @Override
-    public int getObjectData() {
-        return 5;
-    }
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/mobs/minecart/MinecartMeta.java b/src/main/java/me/tofaa/entitylib/meta/mobs/minecart/MinecartMeta.java
deleted file mode 100644
index 3c43de7..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/mobs/minecart/MinecartMeta.java
+++ /dev/null
@@ -1,18 +0,0 @@
-package me.tofaa.entitylib.meta.mobs.minecart;
-
-import me.tofaa.entitylib.meta.Metadata;
-
-public class MinecartMeta extends BaseMinecartMeta {
-
-    public static final byte OFFSET = BaseMinecartMeta.MAX_OFFSET;
-    public static final byte MAX_OFFSET = OFFSET + 0;
-
-    public MinecartMeta(int entityId, Metadata metadata) {
-        super(entityId, metadata);
-    }
-
-    @Override
-    public int getObjectData() {
-        return 0;
-    }
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/mobs/minecart/SpawnerMinecartMeta.java b/src/main/java/me/tofaa/entitylib/meta/mobs/minecart/SpawnerMinecartMeta.java
deleted file mode 100644
index 8e3a7e8..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/mobs/minecart/SpawnerMinecartMeta.java
+++ /dev/null
@@ -1,19 +0,0 @@
-package me.tofaa.entitylib.meta.mobs.minecart;
-
-import me.tofaa.entitylib.meta.Metadata;
-
-public class SpawnerMinecartMeta extends BaseMinecartMeta {
-
-    public static final byte OFFSET = BaseMinecartMeta.MAX_OFFSET;
-    public static final byte MAX_OFFSET = OFFSET + 0;
-
-    public SpawnerMinecartMeta(int entityId, Metadata metadata) {
-        super(entityId, metadata);
-    }
-
-    @Override
-    public int getObjectData() {
-        return 4;
-    }
-
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/mobs/minecart/TntMinecartMeta.java b/src/main/java/me/tofaa/entitylib/meta/mobs/minecart/TntMinecartMeta.java
deleted file mode 100644
index 9ceca9b..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/mobs/minecart/TntMinecartMeta.java
+++ /dev/null
@@ -1,18 +0,0 @@
-package me.tofaa.entitylib.meta.mobs.minecart;
-
-import me.tofaa.entitylib.meta.Metadata;
-
-public class TntMinecartMeta extends BaseMinecartMeta{
-
-    public static final byte OFFSET = BaseMinecartMeta.MAX_OFFSET;
-    public static final byte MAX_OFFSET = OFFSET + 0;
-
-    public TntMinecartMeta(int entityId, Metadata metadata) {
-        super(entityId, metadata);
-    }
-
-    @Override
-    public int getObjectData() {
-        return 3;
-    }
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/mobs/monster/BlazeMeta.java b/src/main/java/me/tofaa/entitylib/meta/mobs/monster/BlazeMeta.java
deleted file mode 100644
index 3e45084..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/mobs/monster/BlazeMeta.java
+++ /dev/null
@@ -1,26 +0,0 @@
-package me.tofaa.entitylib.meta.mobs.monster;
-
-import me.tofaa.entitylib.meta.Metadata;
-import me.tofaa.entitylib.meta.types.MobMeta;
-
-public class BlazeMeta extends MobMeta {
-
-    public static final byte OFFSET = MobMeta.MAX_OFFSET;
-    public static final byte MAX_OFFSET = OFFSET + 1;
-
-    private final static byte ON_FIRE_BIT = 0x01;
-
-    public BlazeMeta(int entityId, Metadata metadata) {
-        super(entityId, metadata);
-    }
-
-    public boolean isOnFire() {
-        return getMaskBit(OFFSET, ON_FIRE_BIT);
-    }
-
-    public void setOnFire(boolean value) {
-        setMaskBit(OFFSET, ON_FIRE_BIT, value);
-    }
-
-
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/mobs/monster/CaveSpiderMeta.java b/src/main/java/me/tofaa/entitylib/meta/mobs/monster/CaveSpiderMeta.java
deleted file mode 100644
index 73eab25..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/mobs/monster/CaveSpiderMeta.java
+++ /dev/null
@@ -1,13 +0,0 @@
-package me.tofaa.entitylib.meta.mobs.monster;
-
-import me.tofaa.entitylib.meta.Metadata;
-
-public class CaveSpiderMeta extends SpiderMeta{
-
-    public static final byte OFFSET = SpiderMeta.MAX_OFFSET;
-    public static final byte MAX_OFFSET = OFFSET + 0;
-
-    public CaveSpiderMeta(int entityId, Metadata metadata) {
-        super(entityId, metadata);
-    }
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/mobs/monster/CreeperMeta.java b/src/main/java/me/tofaa/entitylib/meta/mobs/monster/CreeperMeta.java
deleted file mode 100644
index 3867cc9..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/mobs/monster/CreeperMeta.java
+++ /dev/null
@@ -1,49 +0,0 @@
-package me.tofaa.entitylib.meta.mobs.monster;
-
-import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
-import me.tofaa.entitylib.meta.Metadata;
-import me.tofaa.entitylib.meta.types.MobMeta;
-import org.jetbrains.annotations.NotNull;
-
-public class CreeperMeta extends MobMeta {
-
-    public static final byte OFFSET = MobMeta.MAX_OFFSET;
-    public static final byte MAX_OFFSET = OFFSET + 3;
-
-    public CreeperMeta(int entityId, Metadata metadata) {
-        super(entityId, metadata);
-    }
-
-    @NotNull
-    public State getState() {
-        int id = super.metadata.getIndex(OFFSET, -1);
-        return id == -1 ? State.IDLE : State.FUSE;
-    }
-
-    public void setState(@NotNull State value) {
-        super.metadata.setIndex(OFFSET, EntityDataTypes.INT, value == State.IDLE ? -1 : 1);
-    }
-
-    public boolean isCharged() {
-        return super.metadata.getIndex(offset(OFFSET, 1), false);
-    }
-
-    public void setCharged(boolean value) {
-        super.metadata.setIndex(offset(OFFSET, 1), EntityDataTypes.BOOLEAN, value);
-    }
-
-    public boolean isIgnited() {
-        return super.metadata.getIndex(offset(OFFSET, 2), false);
-    }
-
-    public void setIgnited(boolean value) {
-        super.metadata.setIndex(offset(OFFSET, 2), EntityDataTypes.BOOLEAN, value);
-    }
-
-    public enum State {
-        IDLE,
-        FUSE
-    }
-
-
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/mobs/monster/ElderGuardianMeta.java b/src/main/java/me/tofaa/entitylib/meta/mobs/monster/ElderGuardianMeta.java
deleted file mode 100644
index f292b68..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/mobs/monster/ElderGuardianMeta.java
+++ /dev/null
@@ -1,13 +0,0 @@
-package me.tofaa.entitylib.meta.mobs.monster;
-
-import me.tofaa.entitylib.meta.Metadata;
-
-public class ElderGuardianMeta extends GuardianMeta{
-
-    public static final byte OFFSET = GuardianMeta.MAX_OFFSET;
-    public static final byte MAX_OFFSET = OFFSET + 0;
-
-    public ElderGuardianMeta(int entityId, Metadata metadata) {
-        super(entityId, metadata);
-    }
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/mobs/monster/EndermanMeta.java b/src/main/java/me/tofaa/entitylib/meta/mobs/monster/EndermanMeta.java
deleted file mode 100644
index 0ba5c73..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/mobs/monster/EndermanMeta.java
+++ /dev/null
@@ -1,44 +0,0 @@
-package me.tofaa.entitylib.meta.mobs.monster;
-
-import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
-import me.tofaa.entitylib.meta.Metadata;
-import me.tofaa.entitylib.meta.types.MobMeta;
-import org.jetbrains.annotations.Nullable;
-
-import java.util.Optional;
-
-public class EndermanMeta extends MobMeta {
-
-    public static final byte OFFSET = MobMeta.MAX_OFFSET;
-    public static final byte MAX_OFFSET = OFFSET + 3;
-
-    public EndermanMeta(int entityId, Metadata metadata) {
-        super(entityId, metadata);
-    }
-
-    public Integer getCarriedBlockID() {
-        return super.metadata.getIndex(OFFSET, null);
-    }
-
-    public void setCarriedBlockID(@Nullable Integer value) {
-        super.metadata.setIndex(OFFSET, EntityDataTypes.OPTIONAL_INT, Optional.ofNullable(value));
-    }
-
-    public boolean isScreaming() {
-        return super.metadata.getIndex(offset(OFFSET, 1), false);
-    }
-
-    public void setScreaming(boolean value) {
-        super.metadata.setIndex(offset(OFFSET, 1), EntityDataTypes.BOOLEAN, value);
-    }
-
-    public boolean isStaring() {
-        return super.metadata.getIndex(offset(OFFSET, 2),  false);
-    }
-
-    public void setStaring(boolean value) {
-        super.metadata.setIndex(offset(OFFSET, 2), EntityDataTypes.BOOLEAN, value);
-    }
-
-
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/mobs/monster/EndermiteMeta.java b/src/main/java/me/tofaa/entitylib/meta/mobs/monster/EndermiteMeta.java
deleted file mode 100644
index 4ff42c9..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/mobs/monster/EndermiteMeta.java
+++ /dev/null
@@ -1,14 +0,0 @@
-package me.tofaa.entitylib.meta.mobs.monster;
-
-import me.tofaa.entitylib.meta.Metadata;
-import me.tofaa.entitylib.meta.types.MobMeta;
-
-public class EndermiteMeta extends MobMeta {
-
-    public static final byte OFFSET = MobMeta.MAX_OFFSET;
-    public static final byte MAX_OFFSET = OFFSET + 0;
-
-    public EndermiteMeta(int entityId, Metadata metadata) {
-        super(entityId, metadata);
-    }
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/mobs/monster/GhastMeta.java b/src/main/java/me/tofaa/entitylib/meta/mobs/monster/GhastMeta.java
deleted file mode 100644
index 5192227..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/mobs/monster/GhastMeta.java
+++ /dev/null
@@ -1,25 +0,0 @@
-package me.tofaa.entitylib.meta.mobs.monster;
-
-import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
-import me.tofaa.entitylib.meta.Metadata;
-import me.tofaa.entitylib.meta.types.MobMeta;
-
-public class GhastMeta extends MobMeta {
-
-    public static final byte OFFSET = MobMeta.MAX_OFFSET;
-    public static final byte MAX_OFFSET = OFFSET + 1;
-
-    public GhastMeta(int entityId, Metadata metadata) {
-        super(entityId, metadata);
-    }
-
-
-    public boolean isAttacking() {
-        return super.metadata.getIndex(OFFSET, false);
-    }
-
-    public void setAttacking(boolean value) {
-        super.metadata.setIndex(OFFSET, EntityDataTypes.BOOLEAN, value);
-    }
-
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/mobs/monster/GiantMeta.java b/src/main/java/me/tofaa/entitylib/meta/mobs/monster/GiantMeta.java
deleted file mode 100644
index 1d00514..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/mobs/monster/GiantMeta.java
+++ /dev/null
@@ -1,13 +0,0 @@
-package me.tofaa.entitylib.meta.mobs.monster;
-
-import me.tofaa.entitylib.meta.Metadata;
-import me.tofaa.entitylib.meta.types.MobMeta;
-
-public class GiantMeta extends MobMeta {
-    public static final byte OFFSET = MobMeta.MAX_OFFSET;
-    public static final byte MAX_OFFSET = OFFSET + 0;
-
-    public GiantMeta(int entityId, Metadata metadata) {
-        super(entityId, metadata);
-    }
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/mobs/monster/GuardianMeta.java b/src/main/java/me/tofaa/entitylib/meta/mobs/monster/GuardianMeta.java
deleted file mode 100644
index 39ef78a..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/mobs/monster/GuardianMeta.java
+++ /dev/null
@@ -1,36 +0,0 @@
-package me.tofaa.entitylib.meta.mobs.monster;
-
-import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
-import me.tofaa.entitylib.meta.Metadata;
-import me.tofaa.entitylib.meta.types.MobMeta;
-
-public class GuardianMeta extends MobMeta {
-
-    public static final byte OFFSET = MobMeta.MAX_OFFSET;
-    public static final byte MAX_OFFSET = OFFSET + 2;
-
-    private int target = -1;
-
-    public GuardianMeta(int entityId, Metadata metadata) {
-        super(entityId, metadata);
-    }
-
-    public boolean isRetractingSpikes() {
-        return super.metadata.getIndex(OFFSET, false);
-    }
-
-    public void setRetractingSpikes(boolean retractingSpikes) {
-        super.metadata.setIndex(OFFSET, EntityDataTypes.BOOLEAN, retractingSpikes);
-    }
-
-    public int getTarget() {
-        return this.target;
-    }
-
-    public void setTarget(int target) {
-        this.target = target;
-        super.metadata.setIndex(offset(OFFSET, 1), EntityDataTypes.INT, target == -1 ? 0 : target);
-    }
-
-
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/mobs/monster/PhantomMeta.java b/src/main/java/me/tofaa/entitylib/meta/mobs/monster/PhantomMeta.java
deleted file mode 100644
index 11641ff..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/mobs/monster/PhantomMeta.java
+++ /dev/null
@@ -1,24 +0,0 @@
-package me.tofaa.entitylib.meta.mobs.monster;
-
-import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
-import me.tofaa.entitylib.meta.Metadata;
-import me.tofaa.entitylib.meta.types.MobMeta;
-
-public class PhantomMeta extends MobMeta {
-
-    public static final byte OFFSET = MobMeta.MAX_OFFSET;
-    public static final byte MAX_OFFSET = OFFSET + 1;
-
-    public PhantomMeta(int entityId, Metadata metadata) {
-        super(entityId, metadata);
-    }
-
-    public int getSize() {
-        return super.metadata.getIndex(OFFSET, 0);
-    }
-
-    public void setSize(int value) {
-        super.metadata.setIndex(OFFSET, EntityDataTypes.INT, value);
-    }
-
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/mobs/monster/SilverfishMeta.java b/src/main/java/me/tofaa/entitylib/meta/mobs/monster/SilverfishMeta.java
deleted file mode 100644
index 19e3789..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/mobs/monster/SilverfishMeta.java
+++ /dev/null
@@ -1,14 +0,0 @@
-package me.tofaa.entitylib.meta.mobs.monster;
-
-import me.tofaa.entitylib.meta.Metadata;
-import me.tofaa.entitylib.meta.types.MobMeta;
-
-public class SilverfishMeta extends MobMeta {
-    public static final byte OFFSET = MobMeta.MAX_OFFSET;
-    public static final byte MAX_OFFSET = OFFSET + 0;
-
-
-    public SilverfishMeta(int entityId, Metadata metadata) {
-        super(entityId, metadata);
-    }
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/mobs/monster/SpiderMeta.java b/src/main/java/me/tofaa/entitylib/meta/mobs/monster/SpiderMeta.java
deleted file mode 100644
index 13b0de0..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/mobs/monster/SpiderMeta.java
+++ /dev/null
@@ -1,27 +0,0 @@
-package me.tofaa.entitylib.meta.mobs.monster;
-
-import me.tofaa.entitylib.meta.Metadata;
-import me.tofaa.entitylib.meta.types.MobMeta;
-
-public class SpiderMeta extends MobMeta {
-
-    public static final byte OFFSET = MobMeta.MAX_OFFSET;
-    public static final byte MAX_OFFSET = OFFSET + 1;
-
-    private final static byte CLIMBING_BIT = 0x01;
-
-
-    public SpiderMeta(int entityId, Metadata metadata) {
-        super(entityId, metadata);
-    }
-
-    public boolean isClimbing() {
-        return getMaskBit(OFFSET, CLIMBING_BIT);
-    }
-
-    public void setClimbing(boolean value) {
-        setMaskBit(OFFSET, CLIMBING_BIT, value);
-    }
-
-
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/mobs/monster/VexMeta.java b/src/main/java/me/tofaa/entitylib/meta/mobs/monster/VexMeta.java
deleted file mode 100644
index ea8835d..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/mobs/monster/VexMeta.java
+++ /dev/null
@@ -1,25 +0,0 @@
-package me.tofaa.entitylib.meta.mobs.monster;
-
-import me.tofaa.entitylib.meta.Metadata;
-import me.tofaa.entitylib.meta.types.MobMeta;
-
-public class VexMeta extends MobMeta {
-
-    public static final byte OFFSET = MobMeta.MAX_OFFSET;
-    public static final byte MAX_OFFSET = OFFSET + 1;
-
-    private final static byte ATTACKING_BIT = 0x01;
-
-    public VexMeta(int entityId, Metadata metadata) {
-        super(entityId, metadata);
-    }
-
-    public boolean isAttacking() {
-        return getMaskBit(OFFSET, ATTACKING_BIT);
-    }
-
-    public void setAttacking(boolean value) {
-        setMaskBit(OFFSET, ATTACKING_BIT, value);
-    }
-
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/mobs/monster/WitherMeta.java b/src/main/java/me/tofaa/entitylib/meta/mobs/monster/WitherMeta.java
deleted file mode 100644
index 2f8c861..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/mobs/monster/WitherMeta.java
+++ /dev/null
@@ -1,55 +0,0 @@
-package me.tofaa.entitylib.meta.mobs.monster;
-
-import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
-import me.tofaa.entitylib.meta.Metadata;
-import me.tofaa.entitylib.meta.types.MobMeta;
-
-public class WitherMeta extends MobMeta {
-
-    public static final byte OFFSET = MobMeta.MAX_OFFSET;
-    public static final byte MAX_OFFSET = OFFSET + 4;
-
-    private int centerHead = -1;
-    private int leftHead = -1;
-    private int rightHead = -1;
-
-    public WitherMeta(int entityId, Metadata metadata) {
-        super(entityId, metadata);
-    }
-
-    public void setCenterHead(int centerHead) {
-        this.centerHead = centerHead;
-        super.metadata.setIndex(offset(OFFSET,0), EntityDataTypes.INT, centerHead == -1 ? 0 : centerHead);
-    }
-
-    public void setLeftHead(int leftHead) {
-        this.leftHead = leftHead;
-        super.metadata.setIndex(offset(OFFSET,1), EntityDataTypes.INT, leftHead == -1 ? 0 : leftHead);
-    }
-
-    public void setRightHead(int rightHead) {
-        this.rightHead = rightHead;
-        super.metadata.setIndex(offset(OFFSET,2), EntityDataTypes.INT, rightHead == -1 ? 0 : rightHead);
-    }
-
-    public int getCenterHead() {
-        return centerHead;
-    }
-
-    public int getLeftHead() {
-        return leftHead;
-    }
-
-    public int getRightHead() {
-        return rightHead;
-    }
-
-    public int getInvulnerableTime() {
-        return super.metadata.getIndex(offset(OFFSET, 3), 0);
-    }
-
-    public void setInvulnerableTime(int value) {
-        super.metadata.setIndex(offset(OFFSET, 3), EntityDataTypes.INT, value);
-    }
-
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/mobs/monster/ZoglinMeta.java b/src/main/java/me/tofaa/entitylib/meta/mobs/monster/ZoglinMeta.java
deleted file mode 100644
index 0df787f..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/mobs/monster/ZoglinMeta.java
+++ /dev/null
@@ -1,28 +0,0 @@
-package me.tofaa.entitylib.meta.mobs.monster;
-
-import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
-import me.tofaa.entitylib.meta.Metadata;
-import me.tofaa.entitylib.meta.types.MobMeta;
-
-public class ZoglinMeta extends MobMeta {
-
-    public static final byte OFFSET = MobMeta.MAX_OFFSET;
-    public static final byte MAX_OFFSET = OFFSET + 1;
-
-    public ZoglinMeta(int entityId, Metadata metadata) {
-        super(entityId, metadata);
-    }
-
-
-    public boolean isBaby() {
-        return super.metadata.getIndex(OFFSET, false);
-    }
-
-    public void setBaby(boolean value) {
-        if (isBaby() == value) {
-            return;
-        }
-        super.metadata.setIndex(OFFSET, EntityDataTypes.BOOLEAN, value);
-    }
-
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/mobs/monster/piglin/BasePiglinMeta.java b/src/main/java/me/tofaa/entitylib/meta/mobs/monster/piglin/BasePiglinMeta.java
deleted file mode 100644
index 2aef4e9..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/mobs/monster/piglin/BasePiglinMeta.java
+++ /dev/null
@@ -1,25 +0,0 @@
-package me.tofaa.entitylib.meta.mobs.monster.piglin;
-
-import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
-import me.tofaa.entitylib.meta.Metadata;
-import me.tofaa.entitylib.meta.types.MobMeta;
-
-public abstract class BasePiglinMeta extends MobMeta {
-
-    public static final byte OFFSET = MobMeta.MAX_OFFSET;
-    public static final byte MAX_OFFSET = OFFSET + 1;
-
-    protected BasePiglinMeta(int entityId, Metadata metadata) {
-        super(entityId, metadata);
-    }
-
-    public boolean isImmuneToZombification() {
-        return super.metadata.getIndex(OFFSET, false);
-    }
-
-    public void setImmuneToZombification(boolean value) {
-        super.metadata.setIndex(OFFSET, EntityDataTypes.BOOLEAN, value);
-    }
-
-
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/mobs/monster/piglin/PiglinBruteMeta.java b/src/main/java/me/tofaa/entitylib/meta/mobs/monster/piglin/PiglinBruteMeta.java
deleted file mode 100644
index 9fe68b6..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/mobs/monster/piglin/PiglinBruteMeta.java
+++ /dev/null
@@ -1,13 +0,0 @@
-package me.tofaa.entitylib.meta.mobs.monster.piglin;
-
-import me.tofaa.entitylib.meta.Metadata;
-
-public class PiglinBruteMeta extends BasePiglinMeta{
-
-    public static final byte OFFSET = BasePiglinMeta.MAX_OFFSET;
-    public static final byte MAX_OFFSET = OFFSET + 0;
-
-    public PiglinBruteMeta(int entityId, Metadata metadata) {
-        super(entityId, metadata);
-    }
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/mobs/monster/piglin/PiglinMeta.java b/src/main/java/me/tofaa/entitylib/meta/mobs/monster/piglin/PiglinMeta.java
deleted file mode 100644
index 04747f3..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/mobs/monster/piglin/PiglinMeta.java
+++ /dev/null
@@ -1,43 +0,0 @@
-package me.tofaa.entitylib.meta.mobs.monster.piglin;
-
-import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
-import me.tofaa.entitylib.meta.Metadata;
-
-public class PiglinMeta extends BasePiglinMeta{
-
-    public static final byte OFFSET = BasePiglinMeta.MAX_OFFSET;
-    public static final byte MAX_OFFSET = OFFSET + 3;
-
-    public PiglinMeta(int entityId, Metadata metadata) {
-        super(entityId, metadata);
-    }
-
-    public boolean isBaby() {
-        return super.metadata.getIndex(OFFSET, false);
-    }
-
-    public void setBaby(boolean value) {
-        if (isBaby() == value) {
-            return;
-        }
-        super.metadata.setIndex(OFFSET, EntityDataTypes.BOOLEAN, value);
-    }
-
-    public boolean isChargingCrossbow() {
-        return super.metadata.getIndex(offset(OFFSET, 1), false);
-    }
-
-    public void setChargingCrossbow(boolean value) {
-        super.metadata.setIndex(offset(OFFSET, 1), EntityDataTypes.BOOLEAN, value);
-    }
-
-    public boolean isDancing() {
-        return super.metadata.getIndex(offset(OFFSET, 2), false);
-    }
-
-    public void setDancing(boolean value) {
-        super.metadata.setIndex(offset(OFFSET, 2), EntityDataTypes.BOOLEAN, value);
-    }
-
-
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/mobs/monster/raider/EvokerMeta.java b/src/main/java/me/tofaa/entitylib/meta/mobs/monster/raider/EvokerMeta.java
deleted file mode 100644
index 0f68113..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/mobs/monster/raider/EvokerMeta.java
+++ /dev/null
@@ -1,13 +0,0 @@
-package me.tofaa.entitylib.meta.mobs.monster.raider;
-
-import me.tofaa.entitylib.meta.Metadata;
-
-public class EvokerMeta extends SpellcasterIllagerMeta {
-
-    public static final byte OFFSET = SpellcasterIllagerMeta.MAX_OFFSET;
-    public static final byte MAX_OFFSET = OFFSET + 0;
-
-    public EvokerMeta(int entityId, Metadata metadata) {
-        super(entityId, metadata);
-    }
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/mobs/monster/raider/IllusionerMeta.java b/src/main/java/me/tofaa/entitylib/meta/mobs/monster/raider/IllusionerMeta.java
deleted file mode 100644
index 07ec254..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/mobs/monster/raider/IllusionerMeta.java
+++ /dev/null
@@ -1,13 +0,0 @@
-package me.tofaa.entitylib.meta.mobs.monster.raider;
-
-import me.tofaa.entitylib.meta.Metadata;
-
-public class IllusionerMeta extends SpellcasterIllagerMeta {
-
-    public static final byte OFFSET = SpellcasterIllagerMeta.MAX_OFFSET;
-    public static final byte MAX_OFFSET = OFFSET + 0;
-
-    public IllusionerMeta(int entityId, Metadata metadata) {
-        super(entityId, metadata);
-    }
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/mobs/monster/raider/PillagerMeta.java b/src/main/java/me/tofaa/entitylib/meta/mobs/monster/raider/PillagerMeta.java
deleted file mode 100644
index 83264ef..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/mobs/monster/raider/PillagerMeta.java
+++ /dev/null
@@ -1,14 +0,0 @@
-package me.tofaa.entitylib.meta.mobs.monster.raider;
-
-import me.tofaa.entitylib.meta.Metadata;
-
-public class PillagerMeta extends RaiderMeta{
-
-    public static final byte OFFSET = RaiderMeta.MAX_OFFSET;
-    public static final byte MAX_OFFSET = OFFSET + 0;
-
-
-    public PillagerMeta(int entityId, Metadata metadata) {
-        super(entityId, metadata);
-    }
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/mobs/monster/raider/RaiderMeta.java b/src/main/java/me/tofaa/entitylib/meta/mobs/monster/raider/RaiderMeta.java
deleted file mode 100644
index 563fe01..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/mobs/monster/raider/RaiderMeta.java
+++ /dev/null
@@ -1,25 +0,0 @@
-package me.tofaa.entitylib.meta.mobs.monster.raider;
-
-import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
-import me.tofaa.entitylib.meta.Metadata;
-import me.tofaa.entitylib.meta.types.MobMeta;
-
-public class RaiderMeta extends MobMeta {
-
-    public static final byte OFFSET = MobMeta.MAX_OFFSET;
-    public static final byte MAX_OFFSET = OFFSET + 1;
-
-    public RaiderMeta(int entityId, Metadata metadata) {
-        super(entityId, metadata);
-    }
-
-    public boolean isCelebrating() {
-        return super.metadata.getIndex(OFFSET, false);
-    }
-
-    public void setCelebrating(boolean value) {
-        super.metadata.setIndex(OFFSET, EntityDataTypes.BOOLEAN, value);
-    }
-
-
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/mobs/monster/raider/RavagerMeta.java b/src/main/java/me/tofaa/entitylib/meta/mobs/monster/raider/RavagerMeta.java
deleted file mode 100644
index 63549a6..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/mobs/monster/raider/RavagerMeta.java
+++ /dev/null
@@ -1,14 +0,0 @@
-package me.tofaa.entitylib.meta.mobs.monster.raider;
-
-import me.tofaa.entitylib.meta.Metadata;
-
-public class RavagerMeta extends RaiderMeta {
-
-    public static final byte OFFSET = RaiderMeta.MAX_OFFSET;
-    public static final byte MAX_OFFSET = OFFSET + 0;
-
-
-    public RavagerMeta(int entityId, Metadata metadata) {
-        super(entityId, metadata);
-    }
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/mobs/monster/raider/SpellcasterIllagerMeta.java b/src/main/java/me/tofaa/entitylib/meta/mobs/monster/raider/SpellcasterIllagerMeta.java
deleted file mode 100644
index 493d361..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/mobs/monster/raider/SpellcasterIllagerMeta.java
+++ /dev/null
@@ -1,13 +0,0 @@
-package me.tofaa.entitylib.meta.mobs.monster.raider;
-
-import me.tofaa.entitylib.meta.Metadata;
-
-public class SpellcasterIllagerMeta extends RaiderMeta{
-
-    public static final byte OFFSET = RaiderMeta.MAX_OFFSET;
-    public static final byte MAX_OFFSET = OFFSET + 1;
-
-    public SpellcasterIllagerMeta(int entityId, Metadata metadata) {
-        super(entityId, metadata);
-    }
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/mobs/monster/raider/VindicatorMeta.java b/src/main/java/me/tofaa/entitylib/meta/mobs/monster/raider/VindicatorMeta.java
deleted file mode 100644
index ee79027..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/mobs/monster/raider/VindicatorMeta.java
+++ /dev/null
@@ -1,13 +0,0 @@
-package me.tofaa.entitylib.meta.mobs.monster.raider;
-
-import me.tofaa.entitylib.meta.Metadata;
-
-public class VindicatorMeta extends RaiderMeta{
-
-    public static final byte OFFSET = RaiderMeta.MAX_OFFSET;
-    public static final byte MAX_OFFSET = OFFSET + 0;
-
-    public VindicatorMeta(int entityId, Metadata metadata) {
-        super(entityId, metadata);
-    }
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/mobs/monster/raider/WitchMeta.java b/src/main/java/me/tofaa/entitylib/meta/mobs/monster/raider/WitchMeta.java
deleted file mode 100644
index 808d8fd..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/mobs/monster/raider/WitchMeta.java
+++ /dev/null
@@ -1,23 +0,0 @@
-package me.tofaa.entitylib.meta.mobs.monster.raider;
-
-import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
-import me.tofaa.entitylib.meta.Metadata;
-
-public class WitchMeta extends RaiderMeta {
-
-    public static final byte OFFSET = RaiderMeta.MAX_OFFSET;
-    public static final byte MAX_OFFSET = OFFSET + 1;
-
-    public WitchMeta(int entityId, Metadata metadata) {
-        super(entityId, metadata);
-    }
-
-    public boolean isDrinkingPotion() {
-        return super.metadata.getIndex(OFFSET, false);
-    }
-
-    public void setDrinkingPotion(boolean value) {
-        super.metadata.setIndex(OFFSET, EntityDataTypes.BOOLEAN, value);
-    }
-
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/mobs/monster/skeleton/SkeletonMeta.java b/src/main/java/me/tofaa/entitylib/meta/mobs/monster/skeleton/SkeletonMeta.java
deleted file mode 100644
index d675179..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/mobs/monster/skeleton/SkeletonMeta.java
+++ /dev/null
@@ -1,14 +0,0 @@
-package me.tofaa.entitylib.meta.mobs.monster.skeleton;
-
-import me.tofaa.entitylib.meta.Metadata;
-import me.tofaa.entitylib.meta.types.MobMeta;
-
-public class SkeletonMeta extends MobMeta {
-
-    public static final byte OFFSET = MobMeta.MAX_OFFSET;
-    public static final byte MAX_OFFSET = OFFSET + 0;
-
-    public SkeletonMeta(int entityId, Metadata metadata) {
-        super(entityId, metadata);
-    }
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/mobs/monster/skeleton/StrayMeta.java b/src/main/java/me/tofaa/entitylib/meta/mobs/monster/skeleton/StrayMeta.java
deleted file mode 100644
index a514fde..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/mobs/monster/skeleton/StrayMeta.java
+++ /dev/null
@@ -1,11 +0,0 @@
-package me.tofaa.entitylib.meta.mobs.monster.skeleton;
-
-import me.tofaa.entitylib.meta.Metadata;
-
-public class StrayMeta extends SkeletonMeta{
-
-
-    public StrayMeta(int entityId, Metadata metadata) {
-        super(entityId, metadata);
-    }
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/mobs/monster/skeleton/WitherSkeletonMeta.java b/src/main/java/me/tofaa/entitylib/meta/mobs/monster/skeleton/WitherSkeletonMeta.java
deleted file mode 100644
index 9d6e9ea..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/mobs/monster/skeleton/WitherSkeletonMeta.java
+++ /dev/null
@@ -1,12 +0,0 @@
-package me.tofaa.entitylib.meta.mobs.monster.skeleton;
-
-import me.tofaa.entitylib.meta.Metadata;
-
-public class WitherSkeletonMeta extends SkeletonMeta {
-    public static final byte OFFSET = SkeletonMeta.MAX_OFFSET;
-    public static final byte MAX_OFFSET = OFFSET + 0;
-
-    public WitherSkeletonMeta(int entityId, Metadata metadata) {
-        super(entityId, metadata);
-    }
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/mobs/monster/zombie/DrownedMeta.java b/src/main/java/me/tofaa/entitylib/meta/mobs/monster/zombie/DrownedMeta.java
deleted file mode 100644
index 1c07800..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/mobs/monster/zombie/DrownedMeta.java
+++ /dev/null
@@ -1,12 +0,0 @@
-package me.tofaa.entitylib.meta.mobs.monster.zombie;
-
-import me.tofaa.entitylib.meta.Metadata;
-
-public class DrownedMeta extends ZombieMeta {
-
-    public static final byte OFFSET = ZombieMeta.MAX_OFFSET;
-    public static final byte MAX_OFFSET = OFFSET + 0;
-    public DrownedMeta(int entityId, Metadata metadata) {
-        super(entityId, metadata);
-    }
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/mobs/monster/zombie/HuskMeta.java b/src/main/java/me/tofaa/entitylib/meta/mobs/monster/zombie/HuskMeta.java
deleted file mode 100644
index f986fca..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/mobs/monster/zombie/HuskMeta.java
+++ /dev/null
@@ -1,13 +0,0 @@
-package me.tofaa.entitylib.meta.mobs.monster.zombie;
-
-import me.tofaa.entitylib.meta.Metadata;
-
-public class HuskMeta extends ZombieMeta {
-
-    public static final byte OFFSET = ZombieMeta.MAX_OFFSET;
-    public static final byte MAX_OFFSET = OFFSET + 0;
-
-    public HuskMeta(int entityId, Metadata metadata) {
-        super(entityId, metadata);
-    }
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/mobs/monster/zombie/ZombieMeta.java b/src/main/java/me/tofaa/entitylib/meta/mobs/monster/zombie/ZombieMeta.java
deleted file mode 100644
index 856d907..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/mobs/monster/zombie/ZombieMeta.java
+++ /dev/null
@@ -1,35 +0,0 @@
-package me.tofaa.entitylib.meta.mobs.monster.zombie;
-
-import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
-import me.tofaa.entitylib.meta.Metadata;
-import me.tofaa.entitylib.meta.types.MobMeta;
-
-public class ZombieMeta extends MobMeta {
-
-    public static final byte OFFSET = MobMeta.MAX_OFFSET;
-    public static final byte MAX_OFFSET = OFFSET + 3;
-
-    public ZombieMeta(int entityId, Metadata metadata) {
-        super(entityId, metadata);
-    }
-
-    public boolean isBaby() {
-        return super.metadata.getIndex(OFFSET, false);
-    }
-
-    public void setBaby(boolean value) {
-        if (isBaby() == value) {
-            return;
-        }
-        super.metadata.setIndex(OFFSET, EntityDataTypes.BOOLEAN, value);
-    }
-
-    public boolean isBecomingDrowned() {
-        return super.metadata.getIndex(offset(OFFSET, 2), false);
-    }
-
-    public void setBecomingDrowned(boolean value) {
-        super.metadata.setIndex(offset(OFFSET, 2), EntityDataTypes.BOOLEAN, value);
-    }
-
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/mobs/monster/zombie/ZombieVillagerMeta.java b/src/main/java/me/tofaa/entitylib/meta/mobs/monster/zombie/ZombieVillagerMeta.java
deleted file mode 100644
index c7416c5..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/mobs/monster/zombie/ZombieVillagerMeta.java
+++ /dev/null
@@ -1,43 +0,0 @@
-package me.tofaa.entitylib.meta.mobs.monster.zombie;
-
-import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
-import com.github.retrooper.packetevents.protocol.entity.villager.VillagerData;
-import com.github.retrooper.packetevents.protocol.entity.villager.profession.VillagerProfessions;
-import com.github.retrooper.packetevents.protocol.entity.villager.type.VillagerTypes;
-import me.tofaa.entitylib.meta.Metadata;
-import me.tofaa.entitylib.meta.mobs.villager.VillagerMeta;
-
-public class ZombieVillagerMeta extends ZombieMeta {
-
-    public static final byte OFFSET = ZombieMeta.MAX_OFFSET;
-    public static final byte MAX_OFFSET = OFFSET + 2;
-
-    public ZombieVillagerMeta(int entityId, Metadata metadata) {
-        super(entityId, metadata);
-    }
-
-    public boolean isConverting() {
-        return super.metadata.getIndex(OFFSET, false);
-    }
-
-    public void setConverting(boolean value) {
-        super.metadata.setIndex(OFFSET, EntityDataTypes.BOOLEAN, value);
-    }
-
-    public VillagerData getVillagerData() {
-        int[] data = super.metadata.getIndex(offset(OFFSET, 1), null);
-        if (data == null) {
-            return new VillagerData(VillagerTypes.PLAINS, VillagerProfessions.NONE, VillagerMeta.Level.NOVICE.ordinal());
-        }
-        return new VillagerData(VillagerMeta.TYPES[data[0]], VillagerMeta.PROFESSIONS[data[1]], VillagerMeta.Level.VALUES[data[2] - 1].ordinal());
-    }
-
-    public void setVillagerData(VillagerData data) {
-        super.metadata.setIndex(offset(OFFSET, 1), EntityDataTypes.VILLAGER_DATA, new VillagerData(
-                data.getType().getId(),
-                data.getProfession().getId(),
-                data.getLevel() + 1
-        ));
-    }
-
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/mobs/monster/zombie/ZombifiedPiglinMeta.java b/src/main/java/me/tofaa/entitylib/meta/mobs/monster/zombie/ZombifiedPiglinMeta.java
deleted file mode 100644
index f6794e5..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/mobs/monster/zombie/ZombifiedPiglinMeta.java
+++ /dev/null
@@ -1,13 +0,0 @@
-package me.tofaa.entitylib.meta.mobs.monster.zombie;
-
-import me.tofaa.entitylib.meta.Metadata;
-
-public class ZombifiedPiglinMeta extends ZombieMeta {
-
-    public static final byte OFFSET = ZombieMeta.MAX_OFFSET;
-    public static final byte MAX_OFFSET = OFFSET + 0;
-
-    public ZombifiedPiglinMeta(int entityId, Metadata metadata) {
-        super(entityId, metadata);
-    }
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/mobs/passive/ChickenMeta.java b/src/main/java/me/tofaa/entitylib/meta/mobs/passive/ChickenMeta.java
deleted file mode 100644
index a410b29..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/mobs/passive/ChickenMeta.java
+++ /dev/null
@@ -1,14 +0,0 @@
-package me.tofaa.entitylib.meta.mobs.passive;
-
-import me.tofaa.entitylib.meta.Metadata;
-import me.tofaa.entitylib.meta.types.AgeableMeta;
-
-public class ChickenMeta extends AgeableMeta {
-
-    public static final byte OFFSET = AgeableMeta.MAX_OFFSET;
-    public static final byte MAX_OFFSET = OFFSET + 0;
-
-    public ChickenMeta(int entityId, Metadata metadata) {
-        super(entityId, metadata);
-    }
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/mobs/passive/CowMeta.java b/src/main/java/me/tofaa/entitylib/meta/mobs/passive/CowMeta.java
deleted file mode 100644
index 135162b..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/mobs/passive/CowMeta.java
+++ /dev/null
@@ -1,14 +0,0 @@
-package me.tofaa.entitylib.meta.mobs.passive;
-
-import me.tofaa.entitylib.meta.Metadata;
-import me.tofaa.entitylib.meta.types.AgeableMeta;
-
-public class CowMeta extends AgeableMeta {
-
-    public static final byte OFFSET = AgeableMeta.MAX_OFFSET;
-    public static final byte MAX_OFFSET = OFFSET + 0;
-
-    public CowMeta(int entityId, Metadata metadata) {
-        super(entityId, metadata);
-    }
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/mobs/passive/MooshroomMeta.java b/src/main/java/me/tofaa/entitylib/meta/mobs/passive/MooshroomMeta.java
deleted file mode 100644
index 074763a..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/mobs/passive/MooshroomMeta.java
+++ /dev/null
@@ -1,33 +0,0 @@
-package me.tofaa.entitylib.meta.mobs.passive;
-
-import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
-import me.tofaa.entitylib.meta.Metadata;
-import org.jetbrains.annotations.NotNull;
-
-import java.util.Locale;
-
-public class MooshroomMeta extends CowMeta{
-
-    public static final byte OFFSET = CowMeta.MAX_OFFSET;
-    public static final byte MAX_OFFSET = OFFSET + 1;
-
-    public MooshroomMeta(int entityId, Metadata metadata) {
-        super(entityId, metadata);
-    }
-
-    @NotNull
-    public Variant getVariant() {
-        return Variant.valueOf(super.metadata.getIndex(OFFSET, "red").toUpperCase(Locale.ROOT));
-    }
-
-    public void setVariant(@NotNull Variant value) {
-        super.metadata.setIndex(OFFSET, EntityDataTypes.STRING, value.name().toLowerCase(Locale.ROOT));
-    }
-
-    public enum Variant {
-        RED,
-        BROWN
-    }
-
-
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/mobs/passive/PigMeta.java b/src/main/java/me/tofaa/entitylib/meta/mobs/passive/PigMeta.java
deleted file mode 100644
index 86f973c..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/mobs/passive/PigMeta.java
+++ /dev/null
@@ -1,34 +0,0 @@
-package me.tofaa.entitylib.meta.mobs.passive;
-
-import com.github.retrooper.packetevents.manager.server.ServerVersion;
-import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
-import me.tofaa.entitylib.meta.Metadata;
-import me.tofaa.entitylib.meta.types.AgeableMeta;
-
-public class PigMeta extends AgeableMeta {
-
-    public static final byte OFFSET = AgeableMeta.MAX_OFFSET;
-    public static final byte MAX_OFFSET = OFFSET + 2;
-
-    public PigMeta(int entityId, Metadata metadata) {
-        super(entityId, metadata);
-    }
-
-    public boolean hasSaddle() {
-        return super.metadata.getIndex(OFFSET, false);
-    }
-
-    public void setHasSaddle(boolean value) {
-        super.metadata.setIndex(OFFSET, EntityDataTypes.BOOLEAN, value);
-    }
-
-    public int getTimeToBoost() {
-        isVersionNewer(ServerVersion.V_1_16);
-        return super.metadata.getIndex(offset(OFFSET,1), 0);
-    }
-
-    public void setTimeToBoost(int value) {
-        isVersionNewer(ServerVersion.V_1_16);
-        super.metadata.setIndex(offset(OFFSET,1), EntityDataTypes.INT, value);
-    }
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/mobs/passive/RabbitMeta.java b/src/main/java/me/tofaa/entitylib/meta/mobs/passive/RabbitMeta.java
deleted file mode 100644
index 2e3c68b..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/mobs/passive/RabbitMeta.java
+++ /dev/null
@@ -1,46 +0,0 @@
-package me.tofaa.entitylib.meta.mobs.passive;
-
-import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
-import me.tofaa.entitylib.meta.Metadata;
-import me.tofaa.entitylib.meta.types.AgeableMeta;
-import org.jetbrains.annotations.NotNull;
-
-public class RabbitMeta extends AgeableMeta {
-
-    public static final byte OFFSET = AgeableMeta.MAX_OFFSET;
-    public static final byte MAX_OFFSET = OFFSET + 1;
-
-
-    public RabbitMeta(int entityId, Metadata metadata) {
-        super(entityId, metadata);
-    }
-
-    public @NotNull Type getType() {
-        int id = super.metadata.getIndex(OFFSET, 0);
-        if (id == 99) {
-            return Type.KILLER_BUNNY;
-        }
-        return Type.VALUES[id];
-    }
-
-    public void setType(@NotNull Type value) {
-        int id = value == Type.KILLER_BUNNY ? 99 : value.ordinal();
-        super.metadata.setIndex(OFFSET, EntityDataTypes.INT, id);
-    }
-
-
-    public enum Type {
-        BROWN,
-        WHITE,
-        BLACK,
-        BLACK_AND_WHITE,
-        GOLD,
-        SALT_AND_PEPPER,
-        KILLER_BUNNY;
-
-        private final static Type[] VALUES = values();
-    }
-
-
-
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/mobs/passive/SheepMeta.java b/src/main/java/me/tofaa/entitylib/meta/mobs/passive/SheepMeta.java
deleted file mode 100644
index 00f7505..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/mobs/passive/SheepMeta.java
+++ /dev/null
@@ -1,43 +0,0 @@
-package me.tofaa.entitylib.meta.mobs.passive;
-
-import me.tofaa.entitylib.meta.Metadata;
-import me.tofaa.entitylib.meta.types.AgeableMeta;
-
-public class SheepMeta extends AgeableMeta {
-
-    public static final byte OFFSET = AgeableMeta.MAX_OFFSET;
-    public static final byte MAX_OFFSET = OFFSET + 1;
-
-
-    private final static byte COLOR_BITS = 0x0F;
-    private final static byte SHEARED_BIT = 0x10;
-
-    public SheepMeta(int entityId, Metadata metadata) {
-        super(entityId, metadata);
-    }
-
-    public int getColor() {
-        return getMask(OFFSET) & COLOR_BITS;
-    }
-
-    public void setColor(byte color) {
-        byte before = getMask(OFFSET);
-        byte mask = before;
-        mask &= ~COLOR_BITS;
-        mask |= (color & COLOR_BITS);
-        if (mask != before) {
-            setMask(OFFSET, mask);
-        }
-    }
-
-    public boolean isSheared() {
-        return getMaskBit(OFFSET, SHEARED_BIT);
-    }
-
-    public void setSheared(boolean value) {
-        setMaskBit(OFFSET, SHEARED_BIT, value);
-    }
-
-
-
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/mobs/passive/TurtleMeta.java b/src/main/java/me/tofaa/entitylib/meta/mobs/passive/TurtleMeta.java
deleted file mode 100644
index 136be80..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/mobs/passive/TurtleMeta.java
+++ /dev/null
@@ -1,66 +0,0 @@
-package me.tofaa.entitylib.meta.mobs.passive;
-
-import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
-import com.github.retrooper.packetevents.util.Vector3i;
-import me.tofaa.entitylib.meta.Metadata;
-import me.tofaa.entitylib.meta.types.AgeableMeta;
-
-public class TurtleMeta extends AgeableMeta {
-
-    public static final byte OFFSET = AgeableMeta.MAX_OFFSET;
-    public static final byte MAX_OFFSET = OFFSET + 6;
-
-    public TurtleMeta(int entityId, Metadata metadata) {
-        super(entityId, metadata);
-    }
-
-
-    public Vector3i getHomePosition() {
-        return super.metadata.getIndex(OFFSET, Vector3i.zero());
-    }
-
-    public void setBlockPosition(Vector3i value) {
-        super.metadata.setIndex(OFFSET, EntityDataTypes.BLOCK_POSITION, value);
-    }
-
-    public boolean hasEgg() {
-        return super.metadata.getIndex(offset(OFFSET,1), false);
-    }
-
-    public void setHasEgg(boolean value) {
-        super.metadata.setIndex(offset(OFFSET,1), EntityDataTypes.BOOLEAN, value);
-    }
-
-    public boolean isLayingEgg() {
-        return super.metadata.getIndex(offset(OFFSET,2), false);
-    }
-
-    public void setLayingEgg(boolean value) {
-        super.metadata.setIndex(offset(OFFSET,2), EntityDataTypes.BOOLEAN, value);
-    }
-
-    public  Vector3i getTravelPosition() {
-        return super.metadata.getIndex(offset(OFFSET,3), Vector3i.zero());
-    }
-
-    public void setTravelPosition(Vector3i value) {
-        super.metadata.setIndex(offset(OFFSET,3), EntityDataTypes.BLOCK_POSITION, value);
-    }
-
-    public boolean isGoingHome() {
-        return super.metadata.getIndex(offset(OFFSET,4), false);
-    }
-
-    public void setGoingHome(boolean value) {
-        super.metadata.setIndex(offset(OFFSET,4), EntityDataTypes.BOOLEAN, value);
-    }
-
-    public boolean isTravelling() {
-        return super.metadata.getIndex(offset(OFFSET,5), false);
-    }
-
-    public void setTravelling(boolean value) {
-        super.metadata.setIndex(offset(OFFSET,4), EntityDataTypes.BOOLEAN, value);
-    }
-
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/mobs/tameable/CatMeta.java b/src/main/java/me/tofaa/entitylib/meta/mobs/tameable/CatMeta.java
deleted file mode 100644
index 2dde774..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/mobs/tameable/CatMeta.java
+++ /dev/null
@@ -1,72 +0,0 @@
-package me.tofaa.entitylib.meta.mobs.tameable;
-
-import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
-import com.github.retrooper.packetevents.protocol.entity.type.EntityTypes;
-import me.tofaa.entitylib.extras.DyeColor;
-import me.tofaa.entitylib.meta.Metadata;
-import me.tofaa.entitylib.meta.types.TameableMeta;
-import net.kyori.adventure.text.format.NamedTextColor;
-import org.jetbrains.annotations.NotNull;
-
-public class CatMeta extends TameableMeta {
-
-    public static final byte OFFSET = TameableMeta.MAX_OFFSET;
-    public static final byte MAX_OFFSET = OFFSET + 4;
-
-    private static final DyeColor[] COLORS = DyeColor.values();
-
-    public CatMeta(int entityId, Metadata metadata) {
-        super(entityId, metadata);
-    }
-
-    @NotNull
-    public CatMeta.Variant getVariant() {
-        return super.metadata.getIndex(OFFSET, Variant.BLACK);
-    }
-
-    public void setVariant(@NotNull CatMeta.Variant value) {
-        super.metadata.setIndex(OFFSET, EntityDataTypes.CAT_VARIANT, value.ordinal());
-    }
-
-    public boolean isLying() {
-        return super.metadata.getIndex(offset(OFFSET, 1), false);
-    }
-
-    public void setLying(boolean value) {
-        super.metadata.setIndex(offset(OFFSET, 1), EntityDataTypes.BOOLEAN, value);
-    }
-
-    public boolean isRelaxed() {
-        return super.metadata.getIndex(offset(OFFSET, 2), false);
-    }
-
-    public void setRelaxed(boolean value) {
-        super.metadata.setIndex(offset(OFFSET, 2), EntityDataTypes.BOOLEAN, value);
-    }
-
-    public @NotNull DyeColor getCollarColor() {
-        return COLORS[super.metadata.getIndex(offset(OFFSET, 3), DyeColor.RED.ordinal())];
-    }
-
-    public void setCollarColor(@NotNull DyeColor value) {
-        super.metadata.setIndex(offset(OFFSET, 3), EntityDataTypes.INT, value.ordinal());
-    }
-
-
-    public enum Variant {
-        TABBY,
-        BLACK,
-        RED,
-        SIAMESE,
-        BRITISH_SHORTHAIR,
-        CALICO,
-        PERSIAN,
-        RAGDOLL,
-        WHITE,
-        JELLIE,
-        ALL_BLACK;
-
-        private static final Variant[] VALUES = values();
-    }
-
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/mobs/tameable/ParrotMeta.java b/src/main/java/me/tofaa/entitylib/meta/mobs/tameable/ParrotMeta.java
deleted file mode 100644
index 6e62668..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/mobs/tameable/ParrotMeta.java
+++ /dev/null
@@ -1,38 +0,0 @@
-package me.tofaa.entitylib.meta.mobs.tameable;
-
-import com.github.retrooper.packetevents.manager.server.ServerVersion;
-import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
-import me.tofaa.entitylib.meta.Metadata;
-import me.tofaa.entitylib.meta.types.TameableMeta;
-import org.jetbrains.annotations.NotNull;
-
-public class ParrotMeta extends TameableMeta {
-
-    public static final byte OFFSET = TameableMeta.MAX_OFFSET;
-    public static final byte MAX_OFFSET = OFFSET + 1;
-
-    public ParrotMeta(int entityId, Metadata metadata) {
-        super(entityId, metadata);
-        isVersionNewer(ServerVersion.V_1_14);
-    }
-
-    @NotNull
-    public Color getColor() {
-        return Color.VALUES[super.metadata.getIndex(OFFSET, 0)];
-    }
-
-    public void setColor(@NotNull Color value) {
-        super.metadata.setIndex(OFFSET, EntityDataTypes.INT, value.ordinal());
-    }
-
-    public enum Color {
-        RED_BLUE,
-        BLUE,
-        GREEN,
-        YELLOW_BLUE,
-        GREY;
-
-        private final static Color[] VALUES = values();
-    }
-
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/mobs/tameable/WolfMeta.java b/src/main/java/me/tofaa/entitylib/meta/mobs/tameable/WolfMeta.java
deleted file mode 100644
index e051e6f..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/mobs/tameable/WolfMeta.java
+++ /dev/null
@@ -1,40 +0,0 @@
-package me.tofaa.entitylib.meta.mobs.tameable;
-
-import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
-import me.tofaa.entitylib.meta.Metadata;
-import me.tofaa.entitylib.meta.types.TameableMeta;
-
-public class WolfMeta extends TameableMeta {
-
-    public static final byte OFFSET = TameableMeta.MAX_OFFSET;
-    public static final byte MAX_OFFSET = OFFSET + 3;
-
-    public WolfMeta(int entityId, Metadata metadata) {
-        super(entityId, metadata);
-    }
-
-    public boolean isBegging() {
-        return super.metadata.getIndex(OFFSET, false);
-    }
-
-    public void setBegging(boolean value) {
-        super.metadata.setIndex(OFFSET, EntityDataTypes.BOOLEAN, value);
-    }
-
-    public int getCollarColor() {
-        return super.metadata.getIndex(offset(OFFSET, 1), 14);
-    }
-
-    public void setCollarColor(int value) {
-        super.metadata.setIndex(offset(OFFSET, 1), EntityDataTypes.INT, value);
-    }
-
-    public int getAngerTime() {
-        return super.metadata.getIndex(offset(OFFSET, 2), 0);
-    }
-
-    public void setAngerTime(int value) {
-        super.metadata.setIndex(offset(OFFSET, 2), EntityDataTypes.INT, value);
-    }
-
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/mobs/villager/BaseVillagerMeta.java b/src/main/java/me/tofaa/entitylib/meta/mobs/villager/BaseVillagerMeta.java
deleted file mode 100644
index c5a24fc..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/mobs/villager/BaseVillagerMeta.java
+++ /dev/null
@@ -1,24 +0,0 @@
-package me.tofaa.entitylib.meta.mobs.villager;
-
-import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
-import me.tofaa.entitylib.meta.Metadata;
-import me.tofaa.entitylib.meta.types.AgeableMeta;
-
-public class BaseVillagerMeta extends AgeableMeta {
-
-    public static final byte OFFSET = AgeableMeta.MAX_OFFSET;
-    public static final byte MAX_OFFSET = OFFSET + 1;
-
-    public BaseVillagerMeta(int entityId, Metadata metadata) {
-        super(entityId, metadata);
-    }
-
-    public int getHeadShakeTimer() {
-        return super.metadata.getIndex(OFFSET, 0);
-    }
-
-    public void setHeadShakeTimer(int value) {
-        super.metadata.setIndex(OFFSET, EntityDataTypes.INT, value);
-    }
-
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/mobs/villager/VillagerMeta.java b/src/main/java/me/tofaa/entitylib/meta/mobs/villager/VillagerMeta.java
deleted file mode 100644
index 37011fa..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/mobs/villager/VillagerMeta.java
+++ /dev/null
@@ -1,81 +0,0 @@
-package me.tofaa.entitylib.meta.mobs.villager;
-
-import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
-import com.github.retrooper.packetevents.protocol.entity.villager.VillagerData;
-import com.github.retrooper.packetevents.protocol.entity.villager.profession.VillagerProfession;
-import com.github.retrooper.packetevents.protocol.entity.villager.profession.VillagerProfessions;
-import com.github.retrooper.packetevents.protocol.entity.villager.type.VillagerType;
-import com.github.retrooper.packetevents.protocol.entity.villager.type.VillagerTypes;
-import me.tofaa.entitylib.meta.Metadata;
-import org.jetbrains.annotations.ApiStatus;
-import org.jetbrains.annotations.NotNull;
-
-public class VillagerMeta extends BaseVillagerMeta {
-
-    public static final byte OFFSET = BaseVillagerMeta.MAX_OFFSET;
-    public static final byte MAX_OFFSET = OFFSET + 1;
-
-    @ApiStatus.Internal
-    public static final VillagerType[] TYPES = new VillagerType[] {
-            VillagerTypes.DESERT,
-            VillagerTypes.JUNGLE,
-            VillagerTypes.PLAINS,
-            VillagerTypes.SAVANNA,
-            VillagerTypes.SNOW,
-            VillagerTypes.SWAMP,
-            VillagerTypes.TAIGA
-    };
-
-    @ApiStatus.Internal
-    public static final VillagerProfession[] PROFESSIONS = new VillagerProfession[] {
-            VillagerProfessions.NONE,
-            VillagerProfessions.ARMORER,
-            VillagerProfessions.BUTCHER,
-            VillagerProfessions.CARTOGRAPHER,
-            VillagerProfessions.CLERIC,
-            VillagerProfessions.FARMER,
-            VillagerProfessions.FISHERMAN,
-            VillagerProfessions.FLETCHER,
-            VillagerProfessions.LEATHERWORKER,
-            VillagerProfessions.LIBRARIAN,
-            VillagerProfessions.MASON,
-            VillagerProfessions.NITWIT,
-            VillagerProfessions.SHEPHERD,
-            VillagerProfessions.TOOLSMITH,
-            VillagerProfessions.WEAPONSMITH
-    };
-
-    public VillagerMeta(int entityId, Metadata metadata) {
-        super(entityId, metadata);
-    }
-
-    @NotNull
-    public VillagerData getVillagerData() {
-        int[] data = super.metadata.getIndex(OFFSET, null);
-        if (data == null) {
-            return new VillagerData(VillagerTypes.PLAINS, VillagerProfessions.NONE, Level.NOVICE.ordinal());
-        }
-        return new VillagerData(TYPES[data[0]], PROFESSIONS[data[1]], Level.VALUES[data[2] - 1].ordinal());
-    }
-
-    public void setVillagerData(@NotNull VillagerData data) {
-        super.metadata.setIndex(OFFSET, EntityDataTypes.VILLAGER_DATA, new VillagerData(
-                data.getType().getId(),
-                data.getProfession().getId(),
-                data.getLevel()
-        ));
-    }
-
-
-    public enum Level {
-        NOVICE,
-        APPRENTICE,
-        JOURNEYMAN,
-        EXPERT,
-        MASTER;
-
-        public final static Level[] VALUES = values();
-    }
-
-
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/mobs/villager/WanderingTraderMeta.java b/src/main/java/me/tofaa/entitylib/meta/mobs/villager/WanderingTraderMeta.java
deleted file mode 100644
index 7ce92d5..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/mobs/villager/WanderingTraderMeta.java
+++ /dev/null
@@ -1,13 +0,0 @@
-package me.tofaa.entitylib.meta.mobs.villager;
-
-import me.tofaa.entitylib.meta.Metadata;
-
-public class WanderingTraderMeta extends VillagerMeta{
-
-    public static final byte OFFSET = VillagerMeta.MAX_OFFSET;
-    public static final byte MAX_OFFSET = OFFSET + 0;
-
-    public WanderingTraderMeta(int entityId, Metadata metadata) {
-        super(entityId, metadata);
-    }
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/mobs/water/AxolotlMeta.java b/src/main/java/me/tofaa/entitylib/meta/mobs/water/AxolotlMeta.java
deleted file mode 100644
index 74b1a6f..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/mobs/water/AxolotlMeta.java
+++ /dev/null
@@ -1,50 +0,0 @@
-package me.tofaa.entitylib.meta.mobs.water;
-
-import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
-import me.tofaa.entitylib.meta.Metadata;
-import me.tofaa.entitylib.meta.types.WaterMobMeta;
-
-public class AxolotlMeta extends WaterMobMeta {
-
-    public static final byte OFFSET = WaterMobMeta.MAX_OFFSET;
-    public static final byte MAX_OFFSET = OFFSET + 3;
-
-    public AxolotlMeta(int entityId, Metadata metadata) {
-        super(entityId, metadata);
-    }
-
-    public Variant getVariant() {
-        return Variant.VALUES[super.metadata.getIndex(OFFSET, 0)];
-    }
-
-    public void setVariant(Variant variant) {
-        metadata.setIndex(OFFSET, EntityDataTypes.INT, variant.ordinal());
-    }
-
-    public boolean isPlayingDead() {
-        return metadata.getIndex(offset(OFFSET, 1), false);
-    }
-
-    public void setPlayingDead(boolean playingDead) {
-        metadata.setIndex(offset(OFFSET, 1), EntityDataTypes.BOOLEAN, playingDead);
-    }
-
-    public boolean isFromBucket() {
-        return metadata.getIndex(offset(OFFSET, 2), false);
-    }
-
-    public void setFromBucket(boolean fromBucket) {
-        metadata.setIndex(offset(OFFSET, 2), EntityDataTypes.BOOLEAN, fromBucket);
-    }
-
-    public enum Variant {
-        LUCY,
-        WILD,
-        GOLD,
-        CYAN,
-        BLUE;
-
-        private final static AxolotlMeta.Variant[] VALUES = values();
-    }
-
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/mobs/water/BaseFishMeta.java b/src/main/java/me/tofaa/entitylib/meta/mobs/water/BaseFishMeta.java
deleted file mode 100644
index 76e3f7a..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/mobs/water/BaseFishMeta.java
+++ /dev/null
@@ -1,25 +0,0 @@
-package me.tofaa.entitylib.meta.mobs.water;
-
-import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
-import me.tofaa.entitylib.meta.Metadata;
-import me.tofaa.entitylib.meta.types.WaterMobMeta;
-
-public class BaseFishMeta extends WaterMobMeta {
-
-    public static final byte OFFSET = WaterMobMeta.MAX_OFFSET;
-    public static final byte MAX_OFFSET = OFFSET + 1;
-
-    public BaseFishMeta(int entityId, Metadata metadata) {
-        super(entityId, metadata);
-    }
-
-
-    public boolean isFromBucket() {
-        return super.metadata.getIndex(OFFSET, false);
-    }
-
-    public void setFromBucket(boolean value) {
-        super.metadata.setIndex(OFFSET, EntityDataTypes.BOOLEAN, value);
-    }
-
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/mobs/water/CodMeta.java b/src/main/java/me/tofaa/entitylib/meta/mobs/water/CodMeta.java
deleted file mode 100644
index fc5ce2d..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/mobs/water/CodMeta.java
+++ /dev/null
@@ -1,13 +0,0 @@
-package me.tofaa.entitylib.meta.mobs.water;
-
-import me.tofaa.entitylib.meta.Metadata;
-
-public class CodMeta extends BaseFishMeta{
-
-    public static final byte OFFSET = BaseFishMeta.MAX_OFFSET;
-    public static final byte MAX_OFFSET = OFFSET + 0;
-
-    public CodMeta(int entityId, Metadata metadata) {
-        super(entityId, metadata);
-    }
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/mobs/water/DolphinMeta.java b/src/main/java/me/tofaa/entitylib/meta/mobs/water/DolphinMeta.java
deleted file mode 100644
index c875e1d..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/mobs/water/DolphinMeta.java
+++ /dev/null
@@ -1,43 +0,0 @@
-package me.tofaa.entitylib.meta.mobs.water;
-
-import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
-import com.github.retrooper.packetevents.util.Vector3i;
-import me.tofaa.entitylib.meta.Metadata;
-import me.tofaa.entitylib.meta.types.WaterMobMeta;
-import org.jetbrains.annotations.NotNull;
-
-public class DolphinMeta extends WaterMobMeta {
-
-    public static final byte OFFSET = WaterMobMeta.MAX_OFFSET;
-    public static final byte MAX_OFFSET = OFFSET + 3;
-
-    public DolphinMeta(int entityId, Metadata metadata) {
-        super(entityId, metadata);
-    }
-
-    @NotNull
-    public Vector3i getTreasurePosition() {
-        return super.metadata.getIndex(OFFSET, Vector3i.zero());
-    }
-
-    public void setTreasurePosition(@NotNull Vector3i value) {
-        super.metadata.setIndex(OFFSET, EntityDataTypes.BLOCK_POSITION, value);
-    }
-
-    public boolean isCanFindTreasure() {
-        return super.metadata.getIndex(offset(OFFSET, 1), false);
-    }
-
-    public void setCanFindTreasure(boolean value) {
-        super.metadata.setIndex(offset(OFFSET, 1), EntityDataTypes.BOOLEAN, value);
-    }
-
-    public boolean isHasFish() {
-        return super.metadata.getIndex(offset(OFFSET, 2), false);
-    }
-
-    public void setHasFish(boolean value) {
-        super.metadata.setIndex(offset(OFFSET, 2), EntityDataTypes.BOOLEAN, value);
-    }
-
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/mobs/water/GlowSquidMeta.java b/src/main/java/me/tofaa/entitylib/meta/mobs/water/GlowSquidMeta.java
deleted file mode 100644
index d6115b4..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/mobs/water/GlowSquidMeta.java
+++ /dev/null
@@ -1,24 +0,0 @@
-package me.tofaa.entitylib.meta.mobs.water;
-
-import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
-import me.tofaa.entitylib.meta.Metadata;
-
-public class GlowSquidMeta extends SquidMeta {
-
-    public static final byte OFFSET = SquidMeta.MAX_OFFSET;
-    public static final byte MAX_OFFSET = OFFSET + 1;
-
-    public GlowSquidMeta(int entityId, Metadata metadata) {
-        super(entityId, metadata);
-    }
-
-    public int getDarkTicksRemaining() {
-        return metadata.getIndex(OFFSET, 0);
-    }
-
-    public void setDarkTicksRemaining(int ticks) {
-        metadata.setIndex(OFFSET, EntityDataTypes.INT, ticks);
-    }
-
-
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/mobs/water/PufferFishMeta.java b/src/main/java/me/tofaa/entitylib/meta/mobs/water/PufferFishMeta.java
deleted file mode 100644
index 84180e9..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/mobs/water/PufferFishMeta.java
+++ /dev/null
@@ -1,32 +0,0 @@
-package me.tofaa.entitylib.meta.mobs.water;
-
-import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
-import me.tofaa.entitylib.meta.Metadata;
-
-public class PufferFishMeta extends BaseFishMeta {
-
-    public static final byte OFFSET = BaseFishMeta.MAX_OFFSET;
-    public static final byte MAX_OFFSET = OFFSET + 1;
-
-    public PufferFishMeta(int entityId, Metadata metadata) {
-        super(entityId, metadata);
-    }
-
-    public State getState() {
-        return State.VALUES[super.metadata.getIndex(OFFSET, 0)];
-    }
-
-    public void setState(State state) {
-        super.metadata.setIndex(OFFSET, EntityDataTypes.INT, state.ordinal());
-    }
-
-
-    public enum State {
-        UNPUFFED,
-        SEMI_PUFFED,
-        FULLY_PUFFED;
-
-        private final static State[] VALUES = values();
-    }
-
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/mobs/water/SalmonMeta.java b/src/main/java/me/tofaa/entitylib/meta/mobs/water/SalmonMeta.java
deleted file mode 100644
index 2c74f0d..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/mobs/water/SalmonMeta.java
+++ /dev/null
@@ -1,9 +0,0 @@
-package me.tofaa.entitylib.meta.mobs.water;
-
-import me.tofaa.entitylib.meta.Metadata;
-
-public class SalmonMeta extends BaseFishMeta{
-    public SalmonMeta(int entityId, Metadata metadata) {
-        super(entityId, metadata);
-    }
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/mobs/water/SquidMeta.java b/src/main/java/me/tofaa/entitylib/meta/mobs/water/SquidMeta.java
deleted file mode 100644
index 9c99af2..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/mobs/water/SquidMeta.java
+++ /dev/null
@@ -1,14 +0,0 @@
-package me.tofaa.entitylib.meta.mobs.water;
-
-import me.tofaa.entitylib.meta.Metadata;
-import me.tofaa.entitylib.meta.types.WaterMobMeta;
-
-public class SquidMeta extends WaterMobMeta {
-
-    public static final byte OFFSET = WaterMobMeta.MAX_OFFSET;
-    public static final byte MAX_OFFSET = OFFSET + 0;
-
-    public SquidMeta(int entityId, Metadata metadata) {
-        super(entityId, metadata);
-    }
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/mobs/water/TropicalFishMeta.java b/src/main/java/me/tofaa/entitylib/meta/mobs/water/TropicalFishMeta.java
deleted file mode 100644
index 1392827..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/mobs/water/TropicalFishMeta.java
+++ /dev/null
@@ -1,128 +0,0 @@
-package me.tofaa.entitylib.meta.mobs.water;
-
-import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
-import me.tofaa.entitylib.meta.Metadata;
-import me.tofaa.entitylib.meta.types.ObjectData;
-import org.jetbrains.annotations.NotNull;
-
-public class TropicalFishMeta extends BaseFishMeta implements ObjectData {
-
-    public static final byte OFFSET = BaseFishMeta.MAX_OFFSET;
-    public static final byte MAX_OFFSET = OFFSET + 1;
-
-    public TropicalFishMeta(int entityId, Metadata metadata) {
-        super(entityId, metadata);
-    }
-
-    public Variant getVariant() {
-        return getVariantFromID(super.metadata.getIndex(OFFSET, 0));
-    }
-
-    public void setVariant(Variant variant) {
-        super.metadata.setIndex(OFFSET, EntityDataTypes.INT, getVariantID(variant));
-    }
-
-    public static int getVariantID(Variant variant) {
-        int id = 0;
-        id |= variant.patternColor;
-        id <<= 8;
-        id |= variant.bodyColor;
-        id <<= 8;
-        id |= variant.pattern.ordinal();
-        id <<= 8;
-        id |= variant.type.ordinal();
-        return id;
-    }
-
-    public static Variant getVariantFromID(int variantID) {
-        Type type = Type.VALUES[variantID & 0xFF];
-        variantID >>= 8;
-        Pattern pattern = Pattern.VALUES[variantID & 0xFF];
-        variantID >>= 8;
-        byte bodyColor = (byte) (variantID & 0xFF);
-        variantID >>= 8;
-        byte patternColor = (byte) (variantID & 0xFF);
-        return new Variant(type, pattern, bodyColor, patternColor);
-    }
-
-    @Override
-    public int getObjectData() {
-        // TODO: returns Entity ID of the owner (???)
-        return 0;
-    }
-
-    @Override
-    public boolean requiresVelocityPacketAtSpawn() {
-        return false;
-    }
-
-    public static class Variant {
-
-        private Type type;
-        private Pattern pattern;
-        private byte bodyColor;
-        private byte patternColor;
-
-        public Variant(@NotNull Type type, @NotNull Pattern pattern, byte bodyColor, byte patternColor) {
-            this.type = type;
-            this.pattern = pattern;
-            this.bodyColor = bodyColor;
-            this.patternColor = patternColor;
-        }
-
-        @NotNull
-        public Type getType() {
-            return this.type;
-        }
-
-        public void setType(@NotNull Type type) {
-            this.type = type;
-        }
-
-        @NotNull
-        public Pattern getPattern() {
-            return this.pattern;
-        }
-
-        public void setPattern(@NotNull Pattern pattern) {
-            this.pattern = pattern;
-        }
-
-        public byte getBodyColor() {
-            return this.bodyColor;
-        }
-
-        public void setBodyColor(byte bodyColor) {
-            this.bodyColor = bodyColor;
-        }
-
-        public byte getPatternColor() {
-            return this.patternColor;
-        }
-
-        public void setPatternColor(byte patternColor) {
-            this.patternColor = patternColor;
-        }
-    }
-
-    public enum Type {
-        SMALL,
-        LARGE,
-        INVISIBLE;
-
-        private final static Type[] VALUES = values();
-    }
-
-    public enum Pattern {
-        KOB, // FLOPPER for LARGE fish
-        SUNSTREAK, // STRIPEY for LARGE fish
-        SNOOPER, // GLITTER for LARGE fish
-        DASHER, // BLOCKFISH for LARGE fish
-        BRINELY, // BETTY for LARGE fish
-        SPOTTY, // CLAYFISH for LARGE fish
-        NONE;
-
-        private final static Pattern[] VALUES = values();
-    }
-
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/other/AreaEffectCloudMeta.java b/src/main/java/me/tofaa/entitylib/meta/other/AreaEffectCloudMeta.java
deleted file mode 100644
index 19e3564..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/other/AreaEffectCloudMeta.java
+++ /dev/null
@@ -1,40 +0,0 @@
-package me.tofaa.entitylib.meta.other;
-
-import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
-import me.tofaa.entitylib.meta.EntityMeta;
-import me.tofaa.entitylib.meta.Metadata;
-
-public class AreaEffectCloudMeta extends EntityMeta {
-
-    public static final byte OFFSET = EntityMeta.MAX_OFFSET;
-    public static final byte MAX_OFFSET = OFFSET + 4;
-
-    public AreaEffectCloudMeta(int entityId, Metadata metadata) {
-        super(entityId, metadata);
-    }
-
-    public float getRadius() {
-        return super.metadata.getIndex(OFFSET, .5F);
-    }
-
-    public void setRadius(float value) {
-        super.metadata.setIndex(OFFSET, EntityDataTypes.FLOAT, value);
-    }
-
-    public int getColor() {
-        return super.metadata.getIndex(offset(OFFSET, 1), 0);
-    }
-
-    public void setColor(int value) {
-        super.metadata.setIndex(offset(OFFSET, 1), EntityDataTypes.INT, value);
-    }
-
-    public boolean isSinglePoint() {
-        return super.metadata.getIndex(offset(OFFSET, 2), false);
-    }
-
-    public void setSinglePoint(boolean value) {
-        super.metadata.setIndex(offset(OFFSET, 2), EntityDataTypes.BOOLEAN, value);
-    }
-
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/other/ArmorStandMeta.java b/src/main/java/me/tofaa/entitylib/meta/other/ArmorStandMeta.java
deleted file mode 100644
index 75520c9..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/other/ArmorStandMeta.java
+++ /dev/null
@@ -1,110 +0,0 @@
-package me.tofaa.entitylib.meta.other;
-
-import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
-import com.github.retrooper.packetevents.util.Vector3f;
-import me.tofaa.entitylib.meta.Metadata;
-import me.tofaa.entitylib.meta.types.LivingEntityMeta;
-import org.jetbrains.annotations.NotNull;
-
-public class ArmorStandMeta extends LivingEntityMeta {
-
-    public static final byte OFFSET = LivingEntityMeta.MAX_OFFSET;
-    public static final byte MAX_OFFSET = OFFSET + 7;
-
-    private final static byte IS_SMALL_BIT = 0x01;
-    private final static byte HAS_ARMS_BIT = 0x04;
-    private final static byte HAS_NO_BASE_PLATE_BIT = 0x08;
-    private final static byte IS_MARKER_BIT = 0x10;
-
-    public ArmorStandMeta(int entityId, Metadata metadata) {
-        super(entityId, metadata);
-    }
-
-    public boolean isSmall() {
-        return getMaskBit(OFFSET, IS_SMALL_BIT);
-    }
-
-    public void setSmall(boolean value) {
-        setMaskBit(OFFSET, IS_SMALL_BIT, value);
-    }
-
-    public boolean isHasArms() {
-        return getMaskBit(OFFSET, HAS_ARMS_BIT);
-    }
-
-    public void setHasArms(boolean value) {
-        setMaskBit(OFFSET, HAS_ARMS_BIT, value);
-    }
-
-    public boolean isHasNoBasePlate() {
-        return getMaskBit(OFFSET, HAS_NO_BASE_PLATE_BIT);
-    }
-
-    public void setHasNoBasePlate(boolean value) {
-        setMaskBit(OFFSET, HAS_NO_BASE_PLATE_BIT, value);
-    }
-
-    public boolean isMarker() {
-        return getMaskBit(OFFSET, IS_MARKER_BIT);
-    }
-
-    public void setMarker(boolean value) {
-        setMaskBit(OFFSET, IS_MARKER_BIT, value);
-    }
-
-    @NotNull
-    public Vector3f getHeadRotation() {
-        return super.metadata.getIndex(offset(OFFSET, 1), Vector3f.zero());
-    }
-
-    public void setHeadRotation(@NotNull Vector3f value) {
-        super.metadata.setIndex(offset(OFFSET, 1), EntityDataTypes.ROTATION, value);
-    }
-
-    @NotNull
-    public Vector3f getBodyRotation() {
-        return super.metadata.getIndex(offset(OFFSET, 2), Vector3f.zero());
-    }
-
-    public void setBodyRotation(@NotNull Vector3f value) {
-        super.metadata.setIndex(offset(OFFSET, 2), EntityDataTypes.ROTATION, value);
-    }
-
-    @NotNull
-    public Vector3f getLeftArmRotation() {
-        return super.metadata.getIndex(offset(OFFSET, 3), new Vector3f(-10f, 0f, -10f));
-    }
-
-    public void setLeftArmRotation(@NotNull Vector3f value) {
-        super.metadata.setIndex(offset(OFFSET, 3), EntityDataTypes.ROTATION, value);
-    }
-
-    @NotNull
-    public Vector3f getRightArmRotation() {
-        return super.metadata.getIndex(offset(OFFSET, 4), new Vector3f(-15f, 0f, 10f));
-    }
-
-    public void setRightArmRotation(@NotNull Vector3f value) {
-        super.metadata.setIndex(offset(OFFSET, 4), EntityDataTypes.ROTATION, value);
-    }
-
-    @NotNull
-    public Vector3f getLeftLegRotation() {
-        return super.metadata.getIndex(offset(OFFSET, 5), new Vector3f(-1f, 0f, -1f));
-    }
-
-    public void setLeftLegRotation(@NotNull Vector3f value) {
-        super.metadata.setIndex(offset(OFFSET, 5), EntityDataTypes.ROTATION, value);
-    }
-
-    @NotNull
-    public Vector3f getRightLegRotation() {
-        return super.metadata.getIndex(offset(OFFSET, 6), new Vector3f(1f, 0f, 1f));
-    }
-
-    public void setRightLegRotation(@NotNull Vector3f value) {
-        super.metadata.setIndex(offset(OFFSET, 6), EntityDataTypes.ROTATION, value);
-    }
-
-
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/other/BoatMeta.java b/src/main/java/me/tofaa/entitylib/meta/other/BoatMeta.java
deleted file mode 100644
index a69efbb..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/other/BoatMeta.java
+++ /dev/null
@@ -1,86 +0,0 @@
-package me.tofaa.entitylib.meta.other;
-
-import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
-import me.tofaa.entitylib.meta.EntityMeta;
-import me.tofaa.entitylib.meta.Metadata;
-import org.jetbrains.annotations.NotNull;
-
-public class BoatMeta extends EntityMeta {
-
-    public static final byte OFFSET = EntityMeta.MAX_OFFSET;
-    public static final byte MAX_OFFSET = OFFSET + 7;
-
-    public BoatMeta(int entityId, Metadata metadata) {
-        super(entityId, metadata);
-    }
-
-    public int getTimeSinceLastHit() {
-        return super.metadata.getIndex(OFFSET, 0);
-    }
-
-    public void setTimeSinceLastHit(int value) {
-        super.metadata.setIndex(OFFSET, EntityDataTypes.INT, value);
-    }
-
-    public int getForwardDirection() {
-        return super.metadata.getIndex(offset(OFFSET, 1), 1);
-    }
-
-    public void setForwardDirection(int value) {
-        super.metadata.setIndex(offset(OFFSET, 1), EntityDataTypes.INT, value);
-    }
-
-    public float getDamageTaken() {
-        return super.metadata.getIndex(offset(OFFSET, 2), 0);
-    }
-
-    public void setDamageTaken(float value) {
-        super.metadata.setIndex(offset(OFFSET, 2), EntityDataTypes.FLOAT, value);
-    }
-
-    @NotNull
-    public Type getType() {
-        return Type.VALUES[super.metadata.getIndex(offset(OFFSET, 3), 0)];
-    }
-
-    public void setType(@NotNull Type value) {
-        super.metadata.setIndex(offset(OFFSET, 3), EntityDataTypes.INT, value.ordinal());
-    }
-
-    public boolean isLeftPaddleTurning() {
-        return super.metadata.getIndex(offset(OFFSET, 4), false);
-    }
-
-    public void setLeftPaddleTurning(boolean value) {
-        super.metadata.setIndex(offset(OFFSET, 4), EntityDataTypes.BOOLEAN, value);
-    }
-
-    public boolean isRightPaddleTurning() {
-        return super.metadata.getIndex(offset(OFFSET, 5), false);
-    }
-
-    public void setRightPaddleTurning(boolean value) {
-        super.metadata.setIndex(offset(OFFSET, 5), EntityDataTypes.BOOLEAN, value);
-    }
-
-    public int getSplashTimer() {
-        return super.metadata.getIndex(offset(OFFSET, 6), 0);
-    }
-
-    public void setSplashTimer(int value) {
-        super.metadata.setIndex(offset(OFFSET, 6), EntityDataTypes.INT, value);
-    }
-
-    public enum Type {
-        OAK,
-        SPRUCE,
-        BIRCH,
-        JUNGLE,
-        ACACIA,
-        DARK_OAK;
-
-        private final static Type[] VALUES = values();
-    }
-
-
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/other/EndCrystalMeta.java b/src/main/java/me/tofaa/entitylib/meta/other/EndCrystalMeta.java
deleted file mode 100644
index c7e09f1..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/other/EndCrystalMeta.java
+++ /dev/null
@@ -1,36 +0,0 @@
-package me.tofaa.entitylib.meta.other;
-
-import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
-import com.github.retrooper.packetevents.util.Vector3i;
-import me.tofaa.entitylib.meta.EntityMeta;
-import me.tofaa.entitylib.meta.Metadata;
-import org.jetbrains.annotations.Nullable;
-
-import java.util.Optional;
-
-public class EndCrystalMeta extends EntityMeta {
-
-    public static final byte OFFSET = EntityMeta.MAX_OFFSET;
-    public static final byte MAX_OFFSET = OFFSET + 2;
-
-    public EndCrystalMeta(int entityId, Metadata metadata) {
-        super(entityId, metadata);
-    }
-
-    public @Nullable Optional<Vector3i> getBeamTarget() {
-        return super.metadata.getIndex(OFFSET, Optional.empty());
-    }
-
-    public void setBeamTarget(@Nullable Vector3i value) {
-        super.metadata.setIndex(OFFSET, EntityDataTypes.OPTIONAL_BLOCK_POSITION, Optional.ofNullable(value));
-    }
-
-    public boolean isShowingBottom() {
-        return super.metadata.getIndex(offset(OFFSET, 1), true);
-    }
-
-    public void setShowingBottom(boolean value) {
-        super.metadata.setIndex(offset(OFFSET, 1), EntityDataTypes.BOOLEAN, value);
-    }
-
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/other/EnderDragonMeta.java b/src/main/java/me/tofaa/entitylib/meta/other/EnderDragonMeta.java
deleted file mode 100644
index e505bb1..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/other/EnderDragonMeta.java
+++ /dev/null
@@ -1,43 +0,0 @@
-package me.tofaa.entitylib.meta.other;
-
-import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
-import me.tofaa.entitylib.meta.Metadata;
-import me.tofaa.entitylib.meta.types.MobMeta;
-import org.jetbrains.annotations.NotNull;
-
-public class EnderDragonMeta extends MobMeta {
-
-    public static final byte OFFSET = MobMeta.MAX_OFFSET;
-    public static final byte MAX_OFFSET = OFFSET + 0;
-
-
-    public EnderDragonMeta(int entityId, Metadata metadata) {
-        super(entityId, metadata);
-    }
-
-    @NotNull
-    public Phase getPhase() {
-        return Phase.VALUES[super.metadata.getIndex(OFFSET, 0)];
-    }
-
-    public void setPhase(@NotNull Phase value) {
-        super.metadata.setIndex(OFFSET, EntityDataTypes.INT, value.ordinal());
-    }
-
-    public enum Phase {
-        CIRCLING,
-        STRAFING,
-        FLYING_TO_THE_PORTAL,
-        LANDING_ON_THE_PORTAL,
-        TAKING_OFF_FROM_THE_PORTAL,
-        BREATH_ATTACK,
-        LOOKING_FOR_BREATH_ATTACK_PLAYER,
-        ROAR,
-        CHARGING_PLAYER,
-        FLYING_TO_THE_PORTAL_TO_DIE,
-        HOVERING_WITHOUT_AI;
-
-        private final static Phase[] VALUES = values();
-    }
-
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/other/EvokerFangsMeta.java b/src/main/java/me/tofaa/entitylib/meta/other/EvokerFangsMeta.java
deleted file mode 100644
index 6d09c26..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/other/EvokerFangsMeta.java
+++ /dev/null
@@ -1,14 +0,0 @@
-package me.tofaa.entitylib.meta.other;
-
-import me.tofaa.entitylib.meta.EntityMeta;
-import me.tofaa.entitylib.meta.Metadata;
-
-public class EvokerFangsMeta extends EntityMeta {
-
-    public static final byte OFFSET = EntityMeta.MAX_OFFSET;
-    public static final byte MAX_OFFSET = OFFSET + 0;
-
-    public EvokerFangsMeta(int entityId, Metadata metadata) {
-        super(entityId, metadata);
-    }
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/other/FallingBlockMeta.java b/src/main/java/me/tofaa/entitylib/meta/other/FallingBlockMeta.java
deleted file mode 100644
index ff556ff..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/other/FallingBlockMeta.java
+++ /dev/null
@@ -1,46 +0,0 @@
-package me.tofaa.entitylib.meta.other;
-
-import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
-import com.github.retrooper.packetevents.util.Vector3i;
-import me.tofaa.entitylib.meta.EntityMeta;
-import me.tofaa.entitylib.meta.Metadata;
-import me.tofaa.entitylib.meta.types.ObjectData;
-
-public class FallingBlockMeta extends EntityMeta implements ObjectData {
-
-    public static final byte OFFSET = EntityMeta.MAX_OFFSET;
-    public static final byte MAX_OFFSET = OFFSET + 1;
-
-    private int blockStateId;
-
-    public FallingBlockMeta(int entityId, Metadata metadata) {
-        super(entityId, metadata);
-    }
-
-    public Vector3i getSpawnPosition() {
-        return super.metadata.getIndex(OFFSET, Vector3i.zero());
-    }
-
-    public void setSpawnPosition(Vector3i value) {
-        super.metadata.setIndex(OFFSET, EntityDataTypes.BLOCK_POSITION, value);
-    }
-
-
-    public int getBlockStateId() {
-        return blockStateId;
-    }
-
-    public void setBlockStateId(int blockStateId) {
-        this.blockStateId = blockStateId;
-    }
-
-    @Override
-    public int getObjectData() {
-        return blockStateId;
-    }
-
-    @Override
-    public boolean requiresVelocityPacketAtSpawn() {
-        return false;
-    }
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/other/FireworkRocketMeta.java b/src/main/java/me/tofaa/entitylib/meta/other/FireworkRocketMeta.java
deleted file mode 100644
index 76b36a5..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/other/FireworkRocketMeta.java
+++ /dev/null
@@ -1,50 +0,0 @@
-package me.tofaa.entitylib.meta.other;
-
-import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
-import com.github.retrooper.packetevents.protocol.item.ItemStack;
-import me.tofaa.entitylib.meta.EntityMeta;
-import me.tofaa.entitylib.meta.Metadata;
-import me.tofaa.entitylib.meta.types.ProjectileMeta;
-
-import java.util.Optional;
-
-public class FireworkRocketMeta extends EntityMeta implements ProjectileMeta {
-
-    public static final byte OFFSET = EntityMeta.MAX_OFFSET;
-    public static final byte MAX_OFFSET = OFFSET + 3;
-
-    private int shooter = -1;
-
-    public FireworkRocketMeta(int entityId, Metadata metadata) {
-        super(entityId, metadata);
-    }
-
-    public ItemStack getFireworkItem() {
-        return super.metadata.getIndex(OFFSET, ItemStack.EMPTY);
-    }
-
-    public void setFireworkItem(ItemStack value) {
-        super.metadata.setIndex(OFFSET, EntityDataTypes.ITEMSTACK, value);
-    }
-
-
-    public boolean isShotAtAngle() {
-        return super.metadata.getIndex(offset(OFFSET, 2), false);
-    }
-
-    public void setShotAtAngle(boolean value) {
-        super.metadata.setIndex(offset(OFFSET, 2), EntityDataTypes.BOOLEAN, value);
-    }
-
-    @Override
-    public int getShooter() {
-        return shooter;
-    }
-
-    @Override
-    public void setShooter(int entityId) {
-        this.shooter = entityId;
-        Optional<Integer> optional = Optional.ofNullable(entityId == -1 ? null : entityId);
-        super.metadata.setIndex(offset(OFFSET, 1), EntityDataTypes.OPTIONAL_INT, optional);
-    }
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/other/FishingHookMeta.java b/src/main/java/me/tofaa/entitylib/meta/other/FishingHookMeta.java
deleted file mode 100644
index 61f3242..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/other/FishingHookMeta.java
+++ /dev/null
@@ -1,53 +0,0 @@
-package me.tofaa.entitylib.meta.other;
-
-import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
-import me.tofaa.entitylib.meta.EntityMeta;
-import me.tofaa.entitylib.meta.Metadata;
-import me.tofaa.entitylib.meta.types.ObjectData;
-
-import java.util.Optional;
-
-public class FishingHookMeta extends EntityMeta implements ObjectData {
-
-    public static final byte OFFSET = EntityMeta.MAX_OFFSET;
-    public static final byte MAX_OFFSET = OFFSET + 2;
-
-    private int shooterId;
-    private int hookedId;
-
-    public FishingHookMeta(int entityId, Metadata metadata) {
-        super(entityId, metadata);
-    }
-
-    public boolean isCatchable() {
-        return super.metadata.getIndex(offset(OFFSET, 1), false);
-    }
-
-    public void setCatchable(boolean value) {
-        super.metadata.setIndex(offset(OFFSET, 1), EntityDataTypes.BOOLEAN, value);
-    }
-
-    public int getHookedEntity() {
-        return hookedId;
-    }
-
-    public void setShooter(int entityId) {
-        this.shooterId = entityId;
-    }
-
-    public void setHookedEntity(int entityId) {
-        this.hookedId = entityId;
-        super.metadata.setIndex(OFFSET, EntityDataTypes.INT, entityId == -1 ? 0 : entityId + 1);
-    }
-
-    @Override
-    public int getObjectData() {
-        return shooterId != -1 ? shooterId : 0;
-    }
-
-    @Override
-    public boolean requiresVelocityPacketAtSpawn() {
-        return false;
-    }
-
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/other/GlowItemFrameMeta.java b/src/main/java/me/tofaa/entitylib/meta/other/GlowItemFrameMeta.java
deleted file mode 100644
index 96fc2d7..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/other/GlowItemFrameMeta.java
+++ /dev/null
@@ -1,13 +0,0 @@
-package me.tofaa.entitylib.meta.other;
-
-import me.tofaa.entitylib.meta.Metadata;
-
-public class GlowItemFrameMeta extends ItemFrameMeta {
-
-    public static final byte OFFSET = ItemFrameMeta.MAX_OFFSET;
-    public static final byte MAX_OFFSET = OFFSET + 0;
-
-    public GlowItemFrameMeta(int entityId, Metadata metadata) {
-        super(entityId, metadata);
-    }
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/other/InteractionMeta.java b/src/main/java/me/tofaa/entitylib/meta/other/InteractionMeta.java
deleted file mode 100644
index 77318f9..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/other/InteractionMeta.java
+++ /dev/null
@@ -1,41 +0,0 @@
-package me.tofaa.entitylib.meta.other;
-
-import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
-import me.tofaa.entitylib.meta.EntityMeta;
-import me.tofaa.entitylib.meta.Metadata;
-
-public class InteractionMeta extends EntityMeta {
-
-    public static final byte OFFSET = EntityMeta.MAX_OFFSET;
-    public static final byte MAX_OFFSET = OFFSET + 3;
-
-    public InteractionMeta(int entityId, Metadata metadata) {
-        super(entityId, metadata);
-    }
-
-    public float getWidth() {
-        return super.metadata.getIndex(OFFSET, 1.0F);
-    }
-
-    public void setWidth(float value) {
-        super.metadata.setIndex(OFFSET, EntityDataTypes.FLOAT, value);
-    }
-
-    public float getHeight() {
-        return super.metadata.getIndex(offset(OFFSET, 1), 1.0F);
-    }
-
-    public void setHeight(float value) {
-        super.metadata.setIndex(offset(OFFSET, 1), EntityDataTypes.FLOAT, value);
-    }
-
-    public boolean isResponsive() {
-        return super.metadata.getIndex(offset(OFFSET, 2), false);
-    }
-
-    public void setResponsive(boolean value) {
-        super.metadata.setIndex(offset(OFFSET, 2), EntityDataTypes.BOOLEAN, value);
-    }
-
-
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/other/ItemFrameMeta.java b/src/main/java/me/tofaa/entitylib/meta/other/ItemFrameMeta.java
deleted file mode 100644
index ad15d4c..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/other/ItemFrameMeta.java
+++ /dev/null
@@ -1,74 +0,0 @@
-package me.tofaa.entitylib.meta.other;
-
-import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
-import com.github.retrooper.packetevents.protocol.item.ItemStack;
-import me.tofaa.entitylib.extras.Rotation;
-import me.tofaa.entitylib.meta.EntityMeta;
-import me.tofaa.entitylib.meta.Metadata;
-import me.tofaa.entitylib.meta.types.ObjectData;
-import org.jetbrains.annotations.NotNull;
-
-public class ItemFrameMeta extends EntityMeta implements ObjectData {
-
-    public static final byte OFFSET = EntityMeta.MAX_OFFSET;
-    public static final byte MAX_OFFSET = OFFSET + 2;
-
-    private Orientation orientation = Orientation.DOWN;
-
-    public ItemFrameMeta(int entityId, Metadata metadata) {
-        super(entityId, metadata);
-    }
-
-    @NotNull
-    public ItemStack getItem() {
-        return super.metadata.getIndex(OFFSET, ItemStack.EMPTY);
-    }
-
-    public void setItem(@NotNull ItemStack value) {
-        super.metadata.setIndex(OFFSET, EntityDataTypes.ITEMSTACK, value);
-    }
-
-    @NotNull
-    public Rotation getRotation() {
-        return Rotation.values()[super.metadata.getIndex(offset(OFFSET, 1), 0)];
-    }
-
-    public void setRotation(@NotNull Rotation value) {
-        super.metadata.setIndex(offset(OFFSET, 1), EntityDataTypes.INT, value.ordinal());
-    }
-
-    @NotNull
-    public Orientation getOrientation() {
-        return this.orientation;
-    }
-
-    /**
-     * Sets orientation of the item frame.
-     * This is possible only before spawn packet is sent.
-     *
-     * @param orientation the orientation of the item frame.
-     */
-    public void setOrientation(@NotNull Orientation orientation) {
-        this.orientation = orientation;
-    }
-
-    @Override
-    public int getObjectData() {
-        return this.orientation.ordinal();
-    }
-
-    @Override
-    public boolean requiresVelocityPacketAtSpawn() {
-        return false;
-    }
-
-    public enum Orientation {
-        DOWN,
-        UP,
-        NORTH,
-        SOUTH,
-        WEST,
-        EAST
-    }
-
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/other/LeashKnotMeta.java b/src/main/java/me/tofaa/entitylib/meta/other/LeashKnotMeta.java
deleted file mode 100644
index 551bfde..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/other/LeashKnotMeta.java
+++ /dev/null
@@ -1,14 +0,0 @@
-package me.tofaa.entitylib.meta.other;
-
-import me.tofaa.entitylib.meta.EntityMeta;
-import me.tofaa.entitylib.meta.Metadata;
-
-public class LeashKnotMeta extends EntityMeta {
-
-    public static final byte OFFSET = EntityMeta.MAX_OFFSET;
-    public static final byte MAX_OFFSET = OFFSET + 0;
-
-    public LeashKnotMeta(int entityId, Metadata metadata) {
-        super(entityId, metadata);
-    }
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/other/LightningBoltMeta.java b/src/main/java/me/tofaa/entitylib/meta/other/LightningBoltMeta.java
deleted file mode 100644
index 36b2fdc..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/other/LightningBoltMeta.java
+++ /dev/null
@@ -1,14 +0,0 @@
-package me.tofaa.entitylib.meta.other;
-
-import me.tofaa.entitylib.meta.EntityMeta;
-import me.tofaa.entitylib.meta.Metadata;
-
-public class LightningBoltMeta extends EntityMeta {
-
-    public static final byte OFFSET = EntityMeta.MAX_OFFSET;
-    public static final byte MAX_OFFSET = OFFSET + 0;
-
-    public LightningBoltMeta(int entityId, Metadata metadata) {
-        super(entityId, metadata);
-    }
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/other/LlamaSpitMeta.java b/src/main/java/me/tofaa/entitylib/meta/other/LlamaSpitMeta.java
deleted file mode 100644
index 1f386e0..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/other/LlamaSpitMeta.java
+++ /dev/null
@@ -1,25 +0,0 @@
-package me.tofaa.entitylib.meta.other;
-
-import me.tofaa.entitylib.meta.EntityMeta;
-import me.tofaa.entitylib.meta.Metadata;
-import me.tofaa.entitylib.meta.types.ObjectData;
-
-public class LlamaSpitMeta extends EntityMeta implements ObjectData {
-    public static final byte OFFSET = EntityMeta.MAX_OFFSET;
-    public static final byte MAX_OFFSET = OFFSET + 0;
-
-    public LlamaSpitMeta(int entityId, Metadata metadata) {
-        super(entityId, metadata);
-    }
-
-
-    @Override
-    public int getObjectData() {
-        return 0;
-    }
-
-    @Override
-    public boolean requiresVelocityPacketAtSpawn() {
-        return true;
-    }
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/other/MarkerMeta.java b/src/main/java/me/tofaa/entitylib/meta/other/MarkerMeta.java
deleted file mode 100644
index 2656e23..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/other/MarkerMeta.java
+++ /dev/null
@@ -1,14 +0,0 @@
-package me.tofaa.entitylib.meta.other;
-
-import me.tofaa.entitylib.meta.EntityMeta;
-import me.tofaa.entitylib.meta.Metadata;
-
-public class MarkerMeta extends EntityMeta {
-
-    public static final byte OFFSET = EntityMeta.MAX_OFFSET;
-    public static final byte MAX_OFFSET = OFFSET + 0;
-
-    public MarkerMeta(int entityId, Metadata metadata) {
-        super(entityId, metadata);
-    }
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/other/PaintingMeta.java b/src/main/java/me/tofaa/entitylib/meta/other/PaintingMeta.java
deleted file mode 100644
index cd0e64c..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/other/PaintingMeta.java
+++ /dev/null
@@ -1,120 +0,0 @@
-package me.tofaa.entitylib.meta.other;
-
-import com.github.retrooper.packetevents.protocol.world.Direction;
-import me.tofaa.entitylib.meta.EntityMeta;
-import me.tofaa.entitylib.meta.Metadata;
-import org.jetbrains.annotations.NotNull;
-
-import java.util.Locale;
-
-/**
- * TODO
- */
-public class PaintingMeta extends EntityMeta {
-
-    public static final byte OFFSET = EntityMeta.MAX_OFFSET;
-    public static final byte MAX_OFFSET = OFFSET + 0;
-
-    private Direction direction = Direction.SOUTH;
-    private Type type = Type.KEBAB;
-
-    public PaintingMeta(int entityId, Metadata metadata) {
-        super(entityId, metadata);
-    }
-
-    @NotNull
-    public Type getType() {
-        return type;
-    }
-
-    public void setType(@NotNull Type type) {
-        this.type = type;
-    }
-
-    @NotNull
-    public Direction getDirection() {
-        return direction;
-    }
-
-    public void setDirection(@NotNull Direction direction) {
-        if (direction == Direction.UP || direction == Direction.DOWN) {
-            throw new IllegalArgumentException("Direction cannot be up or down");
-        }
-        this.direction = direction;
-    }
-
-
-
-    public enum Type {
-        KEBAB(0, 0, 16, 16),
-        AZTEC(16, 0, 16, 16),
-        ALBAN(32, 0, 16, 16),
-        AZTEC2(48, 0, 16, 16),
-        BOMB(64, 0, 16, 16),
-        PLANT(80, 0, 16, 16),
-        WASTELAND(96, 0, 16, 16),
-        POOL(0, 32, 32, 16),
-        COURBET(32, 32, 32, 16),
-        SEA(64, 32, 32, 16),
-        SUNSET(96, 32, 32, 16),
-        CREEBET(128, 32, 32, 16),
-        WANDERER(0, 64, 16, 32),
-        GRAHAM(16, 64, 16, 32),
-        MATCH(0, 128, 32, 32),
-        BUST(32, 128, 32, 32),
-        STAGE(64, 128, 32, 32),
-        VOID(96, 128, 32, 32),
-        SKULL_AND_ROSES("skull_and_roses", 128, 128, 32, 32),
-        WITHER(160, 128, 32, 32),
-        FIGHTERS(0, 96, 64, 32),
-        POINTER(0, 192, 64, 64),
-        PIGSCENE(64, 192, 64, 64),
-        BURNING_SKULL(128, 192, 64, 64),
-        SKELETON(192, 64, 64, 48),
-        DONKEY_KONG(192, 112, 64, 48);
-
-        private final String name;
-        private final int x;
-        private final int y;
-        private final int width;
-        private final int height;
-
-        Type(String name, int x, int y, int width, int height) {
-            this.name = name;
-            this.x = x;
-            this.y = y;
-            this.width = width;
-            this.height = height;
-        }
-
-        Type(int x, int y, int width, int height) {
-            this.name = "minecraft:" + name().toLowerCase(Locale.ROOT);
-            this.x = x;
-            this.y = y;
-            this.width = width;
-            this.height = height;
-        }
-
-        public String getName() {
-            return this.name;
-        }
-
-        public int getX() {
-            return this.x;
-        }
-
-        public int getY() {
-            return this.y;
-        }
-
-        public int getWidth() {
-            return this.width;
-        }
-
-        public int getHeight() {
-            return this.height;
-        }
-
-    }
-
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/other/PrimedTntMeta.java b/src/main/java/me/tofaa/entitylib/meta/other/PrimedTntMeta.java
deleted file mode 100644
index 0f87fa0..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/other/PrimedTntMeta.java
+++ /dev/null
@@ -1,23 +0,0 @@
-package me.tofaa.entitylib.meta.other;
-
-import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
-import me.tofaa.entitylib.meta.EntityMeta;
-import me.tofaa.entitylib.meta.Metadata;
-
-public class PrimedTntMeta extends EntityMeta {
-    public static final byte OFFSET = EntityMeta.MAX_OFFSET;
-    public static final byte MAX_OFFSET = OFFSET + 1;
-
-
-    public PrimedTntMeta(int entityId, Metadata metadata) {
-        super(entityId, metadata);
-    }
-
-    public int getFuseTime() {
-        return super.metadata.getIndex(OFFSET, 80);
-    }
-
-    public void setFuseTime(int value) {
-        super.metadata.setIndex(OFFSET, EntityDataTypes.INT, value);
-    }
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/projectile/ArrowMeta.java b/src/main/java/me/tofaa/entitylib/meta/projectile/ArrowMeta.java
deleted file mode 100644
index 1a9d9a9..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/projectile/ArrowMeta.java
+++ /dev/null
@@ -1,47 +0,0 @@
-package me.tofaa.entitylib.meta.projectile;
-
-import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
-import me.tofaa.entitylib.meta.Metadata;
-import me.tofaa.entitylib.meta.types.ObjectData;
-import me.tofaa.entitylib.meta.types.ProjectileMeta;
-
-public class ArrowMeta extends BaseArrowMeta implements ProjectileMeta, ObjectData {
-
-    public static final byte OFFSET = BaseArrowMeta.MAX_OFFSET;
-    public static final byte MAX_OFFSET = OFFSET + 1;
-
-    private int shooterId = -1;
-
-    public ArrowMeta(int entityId, Metadata metadata) {
-        super(entityId, metadata);
-    }
-
-    public int getColor() {
-        return super.metadata.getIndex(OFFSET, -1);
-    }
-
-    public void setColor(int value) {
-        super.metadata.setIndex(OFFSET, EntityDataTypes.INT, value);
-    }
-
-    @Override
-    public int getShooter() {
-        return shooterId;
-    }
-
-    @Override
-    public void setShooter(int entityId) {
-        this.shooterId = entityId;
-    }
-
-
-    @Override
-    public int getObjectData() {
-        return this.shooterId == -1 ? 0 : this.shooterId + 1;
-    }
-
-    @Override
-    public boolean requiresVelocityPacketAtSpawn() {
-        return true;
-    }
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/projectile/BaseArrowMeta.java b/src/main/java/me/tofaa/entitylib/meta/projectile/BaseArrowMeta.java
deleted file mode 100644
index def5833..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/projectile/BaseArrowMeta.java
+++ /dev/null
@@ -1,48 +0,0 @@
-package me.tofaa.entitylib.meta.projectile;
-
-import com.github.retrooper.packetevents.manager.server.ServerVersion;
-import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
-import me.tofaa.entitylib.meta.EntityMeta;
-import me.tofaa.entitylib.meta.Metadata;
-
-public class BaseArrowMeta extends EntityMeta {
-
-    public static final byte OFFSET = EntityMeta.MAX_OFFSET;
-    public static final byte MAX_OFFSET = OFFSET + 2;
-
-    private final static byte CRITICAL_BIT = 0x01;
-    private final static byte NO_CLIP_BIT = 0x02;
-
-    public BaseArrowMeta(int entityId, Metadata metadata) {
-        super(entityId, metadata);
-    }
-
-    public boolean isCritical() {
-        return getMaskBit(OFFSET, CRITICAL_BIT);
-    }
-
-    public void setCritical(boolean value) {
-        setMaskBit(OFFSET, CRITICAL_BIT, value);
-    }
-
-    public boolean isNoClip() {
-        isVersionNewer(ServerVersion.V_1_9);
-        return getMaskBit(OFFSET, NO_CLIP_BIT);
-    }
-
-    public void setNoClip(boolean value) {
-        isVersionNewer(ServerVersion.V_1_9);
-        setMaskBit(OFFSET, NO_CLIP_BIT, value);
-    }
-
-    public int getPierceLevel() {
-        isVersionNewer(ServerVersion.V_1_14);
-        return super.metadata.getIndex(offset(OFFSET,1), 0);
-    }
-
-    public void setPierceLevel(int value) {
-        isVersionNewer(ServerVersion.V_1_14);
-        super.metadata.setIndex(offset(OFFSET,1), EntityDataTypes.INT, value);
-    }
-
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/projectile/DragonFireballMeta.java b/src/main/java/me/tofaa/entitylib/meta/projectile/DragonFireballMeta.java
deleted file mode 100644
index 19d05f9..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/projectile/DragonFireballMeta.java
+++ /dev/null
@@ -1,38 +0,0 @@
-package me.tofaa.entitylib.meta.projectile;
-
-import me.tofaa.entitylib.meta.EntityMeta;
-import me.tofaa.entitylib.meta.Metadata;
-import me.tofaa.entitylib.meta.types.ObjectData;
-import me.tofaa.entitylib.meta.types.ProjectileMeta;
-
-public class DragonFireballMeta extends EntityMeta implements ProjectileMeta, ObjectData {
-
-    public static final byte OFFSET = EntityMeta.MAX_OFFSET;
-    public static final byte MAX_OFFSET = OFFSET + 0;
-
-    private int shooter = -1;
-
-    public DragonFireballMeta(int entityId, Metadata metadata) {
-        super(entityId, metadata);
-    }
-
-    @Override
-    public int getObjectData() {
-        return this.shooter == -1 ? 0 : this.shooter;
-    }
-
-    @Override
-    public boolean requiresVelocityPacketAtSpawn() {
-        return true;
-    }
-
-    @Override
-    public int getShooter() {
-        return shooter;
-    }
-
-    @Override
-    public void setShooter(int entityId) {
-        this.shooter = entityId;
-    }
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/projectile/EyeOfEnderMeta.java b/src/main/java/me/tofaa/entitylib/meta/projectile/EyeOfEnderMeta.java
deleted file mode 100644
index 3689fd4..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/projectile/EyeOfEnderMeta.java
+++ /dev/null
@@ -1,20 +0,0 @@
-package me.tofaa.entitylib.meta.projectile;
-
-import com.github.retrooper.packetevents.protocol.item.ItemStack;
-import com.github.retrooper.packetevents.protocol.item.type.ItemTypes;
-import me.tofaa.entitylib.meta.Metadata;
-import me.tofaa.entitylib.meta.types.ItemContainerMeta;
-
-public class EyeOfEnderMeta extends ItemContainerMeta {
-
-
-    public static final byte OFFSET = ItemContainerMeta.MAX_OFFSET;
-    public static final byte MAX_OFFSET = OFFSET + 0;
-
-    public static final ItemStack EYE_OF_ENDER = ItemStack.builder().type(ItemTypes.ENDER_EYE).build();
-
-    public EyeOfEnderMeta(int entityId, Metadata metadata) {
-        super(entityId, metadata, EYE_OF_ENDER);
-    }
-
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/projectile/ItemEntityMeta.java b/src/main/java/me/tofaa/entitylib/meta/projectile/ItemEntityMeta.java
deleted file mode 100644
index f3f884a..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/projectile/ItemEntityMeta.java
+++ /dev/null
@@ -1,26 +0,0 @@
-package me.tofaa.entitylib.meta.projectile;
-
-import com.github.retrooper.packetevents.protocol.item.ItemStack;
-import me.tofaa.entitylib.meta.Metadata;
-import me.tofaa.entitylib.meta.types.ItemContainerMeta;
-import me.tofaa.entitylib.meta.types.ObjectData;
-
-public class ItemEntityMeta extends ItemContainerMeta implements ObjectData {
-
-    public static final byte OFFSET = ItemContainerMeta.MAX_OFFSET;
-    public static final byte MAX_OFFSET = OFFSET + 0;
-
-    protected ItemEntityMeta(int entityId, Metadata metadata) {
-        super(entityId, metadata, ItemStack.EMPTY);
-    }
-
-    @Override
-    public int getObjectData() {
-        return 1;
-    }
-
-    @Override
-    public boolean requiresVelocityPacketAtSpawn() {
-        return true;
-    }
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/projectile/LargeFireballMeta.java b/src/main/java/me/tofaa/entitylib/meta/projectile/LargeFireballMeta.java
deleted file mode 100644
index 2308527..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/projectile/LargeFireballMeta.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package me.tofaa.entitylib.meta.projectile;
-
-import com.github.retrooper.packetevents.protocol.item.ItemStack;
-import me.tofaa.entitylib.meta.Metadata;
-import me.tofaa.entitylib.meta.types.ItemContainerMeta;
-import me.tofaa.entitylib.meta.types.ObjectData;
-import me.tofaa.entitylib.meta.types.ProjectileMeta;
-
-public class LargeFireballMeta extends ItemContainerMeta implements ObjectData, ProjectileMeta {
-    public static final byte OFFSET = ItemContainerMeta.MAX_OFFSET;
-    public static final byte MAX_OFFSET = OFFSET + 0;
-
-    private int shooterId = -1;
-
-    public LargeFireballMeta(int entityId, Metadata meta) {
-        super(entityId, meta, ItemStack.EMPTY);
-    }
-
-    @Override
-    public int getObjectData() {
-        return this.shooterId == -1 ? 0 : this.shooterId;
-    }
-
-    @Override
-    public boolean requiresVelocityPacketAtSpawn() {
-        return true;
-    }
-
-    @Override
-    public int getShooter() {
-        return shooterId;
-    }
-
-    @Override
-    public void setShooter(int entityId) {
-        this.shooterId = entityId;
-    }
-
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/projectile/ShulkerBulletMeta.java b/src/main/java/me/tofaa/entitylib/meta/projectile/ShulkerBulletMeta.java
deleted file mode 100644
index a0925b8..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/projectile/ShulkerBulletMeta.java
+++ /dev/null
@@ -1,25 +0,0 @@
-package me.tofaa.entitylib.meta.projectile;
-
-import me.tofaa.entitylib.meta.EntityMeta;
-import me.tofaa.entitylib.meta.Metadata;
-import me.tofaa.entitylib.meta.types.ObjectData;
-
-public class ShulkerBulletMeta extends EntityMeta implements ObjectData {
-
-    public static final byte OFFSET = EntityMeta.MAX_OFFSET;
-    public static final byte MAX_OFFSET = OFFSET + 0;
-
-    public ShulkerBulletMeta(int entityId, Metadata metadata) {
-        super(entityId, metadata);
-    }
-
-    @Override
-    public int getObjectData() {
-        return 0;
-    }
-
-    @Override
-    public boolean requiresVelocityPacketAtSpawn() {
-        return true;
-    }
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/projectile/SmallFireballMeta.java b/src/main/java/me/tofaa/entitylib/meta/projectile/SmallFireballMeta.java
deleted file mode 100644
index 513cb17..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/projectile/SmallFireballMeta.java
+++ /dev/null
@@ -1,43 +0,0 @@
-package me.tofaa.entitylib.meta.projectile;
-
-import com.github.retrooper.packetevents.protocol.item.ItemStack;
-import com.github.retrooper.packetevents.protocol.item.type.ItemTypes;
-import me.tofaa.entitylib.meta.Metadata;
-import me.tofaa.entitylib.meta.types.ItemContainerMeta;
-import me.tofaa.entitylib.meta.types.ObjectData;
-import me.tofaa.entitylib.meta.types.ProjectileMeta;
-
-public class SmallFireballMeta extends ItemContainerMeta implements ObjectData, ProjectileMeta {
-
-
-    public static final byte OFFSET = ItemContainerMeta.MAX_OFFSET;
-    public static final byte MAX_OFFSET = OFFSET + 0;
-
-    public static final ItemStack SMALL_FIREBALL = ItemStack.builder().type(ItemTypes.FIRE_CHARGE).build();
-
-    private int shooterId = -1;
-
-    public SmallFireballMeta(int entityId, Metadata meta) {
-        super(entityId, meta, SMALL_FIREBALL);
-    }
-
-    @Override
-    public int getObjectData() {
-        return this.shooterId == -1 ? 0 : this.shooterId;
-    }
-
-    @Override
-    public boolean requiresVelocityPacketAtSpawn() {
-        return true;
-    }
-
-    @Override
-    public int getShooter() {
-        return shooterId;
-    }
-
-    @Override
-    public void setShooter(int entityId) {
-        this.shooterId = entityId;
-    }
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/projectile/SnowballMeta.java b/src/main/java/me/tofaa/entitylib/meta/projectile/SnowballMeta.java
deleted file mode 100644
index cdee6be..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/projectile/SnowballMeta.java
+++ /dev/null
@@ -1,19 +0,0 @@
-package me.tofaa.entitylib.meta.projectile;
-
-import com.github.retrooper.packetevents.protocol.item.ItemStack;
-import com.github.retrooper.packetevents.protocol.item.type.ItemTypes;
-import me.tofaa.entitylib.meta.Metadata;
-import me.tofaa.entitylib.meta.types.ItemContainerMeta;
-
-public class SnowballMeta extends ItemContainerMeta {
-
-    public static final byte OFFSET = ItemContainerMeta.MAX_OFFSET;
-    public static final byte MAX_OFFSET = OFFSET + 0;
-
-    public static final ItemStack SNOWBALL = ItemStack.builder().type(ItemTypes.SNOWBALL).build();
-
-    public SnowballMeta(int entityId, Metadata metadata) {
-        super(entityId, metadata, SNOWBALL);
-    }
-
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/projectile/SpectralArrowMeta.java b/src/main/java/me/tofaa/entitylib/meta/projectile/SpectralArrowMeta.java
deleted file mode 100644
index 314ee83..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/projectile/SpectralArrowMeta.java
+++ /dev/null
@@ -1,37 +0,0 @@
-package me.tofaa.entitylib.meta.projectile;
-
-import me.tofaa.entitylib.meta.Metadata;
-import me.tofaa.entitylib.meta.types.ObjectData;
-import me.tofaa.entitylib.meta.types.ProjectileMeta;
-
-public class SpectralArrowMeta extends BaseArrowMeta implements ProjectileMeta, ObjectData {
-
-    public static final byte OFFSET = BaseArrowMeta.MAX_OFFSET;
-    public static final byte MAX_OFFSET = OFFSET + 0;
-
-    private int shooterId = -1;
-
-    public SpectralArrowMeta(int entityId, Metadata metadata) {
-        super(entityId, metadata);
-    }
-
-    @Override
-    public int getObjectData() {
-        return this.shooterId == -1 ? 0 : this.shooterId + 1;
-    }
-
-    @Override
-    public boolean requiresVelocityPacketAtSpawn() {
-        return true;
-    }
-
-    @Override
-    public int getShooter() {
-        return shooterId;
-    }
-
-    @Override
-    public void setShooter(int entityId) {
-        this.shooterId = entityId;
-    }
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/projectile/ThrownEggMeta.java b/src/main/java/me/tofaa/entitylib/meta/projectile/ThrownEggMeta.java
deleted file mode 100644
index 84eeaa0..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/projectile/ThrownEggMeta.java
+++ /dev/null
@@ -1,20 +0,0 @@
-package me.tofaa.entitylib.meta.projectile;
-
-import com.github.retrooper.packetevents.protocol.item.ItemStack;
-import com.github.retrooper.packetevents.protocol.item.type.ItemTypes;
-import me.tofaa.entitylib.meta.Metadata;
-import me.tofaa.entitylib.meta.types.ItemContainerMeta;
-
-public class ThrownEggMeta extends ItemContainerMeta {
-
-
-    public static final byte OFFSET = ItemContainerMeta.MAX_OFFSET;
-    public static final byte MAX_OFFSET = OFFSET + 0;
-
-    private static final ItemStack EGG = ItemStack.builder().type(ItemTypes.EGG).build();
-
-    public ThrownEggMeta(int entityId, Metadata metadata) {
-        super(entityId, metadata, EGG);
-    }
-
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/projectile/ThrownEnderPearlMeta.java b/src/main/java/me/tofaa/entitylib/meta/projectile/ThrownEnderPearlMeta.java
deleted file mode 100644
index c75a441..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/projectile/ThrownEnderPearlMeta.java
+++ /dev/null
@@ -1,19 +0,0 @@
-package me.tofaa.entitylib.meta.projectile;
-
-import com.github.retrooper.packetevents.protocol.item.ItemStack;
-import com.github.retrooper.packetevents.protocol.item.type.ItemTypes;
-import me.tofaa.entitylib.meta.Metadata;
-import me.tofaa.entitylib.meta.types.ItemContainerMeta;
-
-public class ThrownEnderPearlMeta extends ItemContainerMeta {
-
-    public static final byte OFFSET = ItemContainerMeta.MAX_OFFSET;
-    public static final byte MAX_OFFSET = OFFSET + 0;
-
-    private static final ItemStack ENDER_PEARL = ItemStack.builder().type(ItemTypes.ENDER_PEARL).build();
-
-    public ThrownEnderPearlMeta(int entityId, Metadata metadata) {
-        super(entityId, metadata, ENDER_PEARL);
-    }
-
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/projectile/ThrownExpBottleMeta.java b/src/main/java/me/tofaa/entitylib/meta/projectile/ThrownExpBottleMeta.java
deleted file mode 100644
index d3058bb..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/projectile/ThrownExpBottleMeta.java
+++ /dev/null
@@ -1,19 +0,0 @@
-package me.tofaa.entitylib.meta.projectile;
-
-import com.github.retrooper.packetevents.protocol.item.ItemStack;
-import com.github.retrooper.packetevents.protocol.item.type.ItemTypes;
-import me.tofaa.entitylib.meta.Metadata;
-import me.tofaa.entitylib.meta.types.ItemContainerMeta;
-
-public class ThrownExpBottleMeta extends ItemContainerMeta {
-
-    public static final byte OFFSET = ItemContainerMeta.MAX_OFFSET;
-    public static final byte MAX_OFFSET = OFFSET + 0;
-
-    private static final ItemStack EXP_BOTTLE = ItemStack.builder().type(ItemTypes.EXPERIENCE_BOTTLE).build();
-
-    public ThrownExpBottleMeta(int entityId, Metadata metadata) {
-        super(entityId, metadata, EXP_BOTTLE);
-    }
-
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/projectile/ThrownPotionMeta.java b/src/main/java/me/tofaa/entitylib/meta/projectile/ThrownPotionMeta.java
deleted file mode 100644
index b2514fd..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/projectile/ThrownPotionMeta.java
+++ /dev/null
@@ -1,17 +0,0 @@
-package me.tofaa.entitylib.meta.projectile;
-
-import com.github.retrooper.packetevents.protocol.item.ItemStack;
-import me.tofaa.entitylib.meta.Metadata;
-import me.tofaa.entitylib.meta.types.ItemContainerMeta;
-
-public class ThrownPotionMeta extends ItemContainerMeta {
-
-    public static final byte OFFSET = ItemContainerMeta.MAX_OFFSET;
-    public static final byte MAX_OFFSET = OFFSET + 0;
-
-    public ThrownPotionMeta(int entityId, Metadata metadata) {
-        super(entityId, metadata, ItemStack.EMPTY);
-    }
-
-
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/projectile/ThrownTridentMeta.java b/src/main/java/me/tofaa/entitylib/meta/projectile/ThrownTridentMeta.java
deleted file mode 100644
index 8f77723..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/projectile/ThrownTridentMeta.java
+++ /dev/null
@@ -1,31 +0,0 @@
-package me.tofaa.entitylib.meta.projectile;
-
-import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
-import me.tofaa.entitylib.meta.Metadata;
-
-public class ThrownTridentMeta extends BaseArrowMeta{
-
-    public static final byte OFFSET = BaseArrowMeta.MAX_OFFSET;
-    public static final byte MAX_OFFSET = OFFSET + 2;
-
-    public ThrownTridentMeta(int entityId, Metadata metadata) {
-        super(entityId, metadata);
-    }
-
-    public int getLoyaltyLevel() {
-        return super.metadata.getIndex(OFFSET, 0);
-    }
-
-    public void setLoyaltyLevel(int value) {
-        super.metadata.setIndex(OFFSET, EntityDataTypes.INT, value);
-    }
-
-    public boolean isHasEnchantmentGlint() {
-        return super.metadata.getIndex(offset(OFFSET,1), false);
-    }
-
-    public void setHasEnchantmentGlint(boolean value) {
-        super.metadata.setIndex(offset(OFFSET,1), EntityDataTypes.BOOLEAN, value);
-    }
-
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/projectile/WitherSkullMeta.java b/src/main/java/me/tofaa/entitylib/meta/projectile/WitherSkullMeta.java
deleted file mode 100644
index 985a274..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/projectile/WitherSkullMeta.java
+++ /dev/null
@@ -1,50 +0,0 @@
-package me.tofaa.entitylib.meta.projectile;
-
-import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
-import me.tofaa.entitylib.meta.EntityMeta;
-import me.tofaa.entitylib.meta.Metadata;
-import me.tofaa.entitylib.meta.types.ObjectData;
-import me.tofaa.entitylib.meta.types.ProjectileMeta;
-
-public class WitherSkullMeta extends EntityMeta implements ObjectData, ProjectileMeta {
-
-    public static final byte OFFSET = EntityMeta.MAX_OFFSET;
-    public static final byte MAX_OFFSET = OFFSET + 1;
-
-    private int shooter = -1;
-
-    public WitherSkullMeta(int entityId, Metadata metadata) {
-        super(entityId, metadata);
-    }
-
-
-    public boolean isInvulnerable() {
-        return super.metadata.getIndex(OFFSET, false);
-    }
-
-    public void setInvulnerable(boolean value) {
-        super.metadata.setIndex(OFFSET, EntityDataTypes.BOOLEAN, value);
-    }
-
-
-
-    @Override
-    public int getObjectData() {
-        return this.shooter == -1 ? 0 : this.shooter;
-    }
-
-    @Override
-    public boolean requiresVelocityPacketAtSpawn() {
-        return true;
-    }
-
-    @Override
-    public int getShooter() {
-        return shooter;
-    }
-
-    @Override
-    public void setShooter(int entityId) {
-        this.shooter = entityId;
-    }
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/types/AgeableMeta.java b/src/main/java/me/tofaa/entitylib/meta/types/AgeableMeta.java
deleted file mode 100644
index a2868aa..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/types/AgeableMeta.java
+++ /dev/null
@@ -1,23 +0,0 @@
-package me.tofaa.entitylib.meta.types;
-
-import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
-import me.tofaa.entitylib.meta.Metadata;
-
-public class AgeableMeta extends MobMeta {
-
-    public static final byte OFFSET = MobMeta.MAX_OFFSET;
-    public static final byte MAX_OFFSET = OFFSET + 1;
-
-    public AgeableMeta(int entityId, Metadata metadata) {
-        super(entityId, metadata);
-    }
-
-    public boolean isBaby() {
-        return super.metadata.getIndex(OFFSET, false);
-    }
-
-    public void setBaby(boolean value) {
-        super.metadata.setIndex(OFFSET, EntityDataTypes.BOOLEAN, value);
-    }
-
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/types/DisplayMeta.java b/src/main/java/me/tofaa/entitylib/meta/types/DisplayMeta.java
deleted file mode 100644
index c3a56a4..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/types/DisplayMeta.java
+++ /dev/null
@@ -1,255 +0,0 @@
-package me.tofaa.entitylib.meta.types;
-
-import com.github.retrooper.packetevents.manager.server.ServerVersion;
-import com.github.retrooper.packetevents.manager.server.VersionComparison;
-import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
-import com.github.retrooper.packetevents.util.Quaternion4f;
-import com.github.retrooper.packetevents.util.Vector3f;
-import me.tofaa.entitylib.meta.EntityMeta;
-import me.tofaa.entitylib.meta.Metadata;
-
-public class DisplayMeta extends EntityMeta {
-
-    public static final byte OFFSET = EntityMeta.MAX_OFFSET;
-    public static final byte MAX_OFFSET;
-    static {
-        if (isVersion(ServerVersion.V_1_20_2, VersionComparison.NEWER_THAN_OR_EQUALS)) {
-            MAX_OFFSET =  OFFSET + 15;
-        }
-        else {
-            MAX_OFFSET = OFFSET + 14;
-        }
-    }
-
-    public DisplayMeta(int entityId, Metadata metadata) {
-        super(entityId, metadata);
-        isVersionNewer(ServerVersion.V_1_19_3);
-    }
-
-    public int getInterpolationDelay() {
-        return super.metadata.getIndex(OFFSET, 0);
-    }
-
-    public void setInterpolationDelay(int value) {
-        super.metadata.setIndex(OFFSET, EntityDataTypes.INT, value);
-    }
-
-    public int getTransformationInterpolationDuration() {
-        return super.metadata.getIndex(offset(OFFSET, 1), 0);
-    }
-
-    public void setTransformationInterpolationDuration(int value) {
-        super.metadata.setIndex(offset(OFFSET, 1), EntityDataTypes.INT, value);
-    }
-
-    public int getPositionRotationInterpolationDuration() {
-        return super.metadata.getIndex(offset(OFFSET, 2), 0);
-    }
-
-    public void setPositionRotationInterpolationDuration(int value) {
-        super.metadata.setIndex(offset(OFFSET, 2), EntityDataTypes.INT, value);
-    }
-
-    public Vector3f getTranslation() {
-        byte offset = offset(OFFSET, 3);
-        if (isVersion(ServerVersion.V_1_20_2, VersionComparison.OLDER_THAN)) {
-            offset = offset(OFFSET, 2);
-        }
-        return super.metadata.getIndex(offset, Vector3f.zero());
-    }
-
-    public void setTranslation(Vector3f value) {
-        byte offset = offset(OFFSET, 3);
-        if (isVersion(ServerVersion.V_1_20_2, VersionComparison.OLDER_THAN)) {
-            offset = offset(OFFSET, 2);
-        }
-        super.metadata.setIndex(offset, EntityDataTypes.VECTOR3F, value);
-    }
-
-    public Vector3f getScale() {
-        byte offset = offset(OFFSET, 4);
-        if (isVersion(ServerVersion.V_1_20_2, VersionComparison.OLDER_THAN)) {
-            offset = offset(OFFSET, 3);
-        }
-        return super.metadata.getIndex(offset, new Vector3f(1.0f, 1.0f, 1.0f));
-    }
-
-    public void setScale(Vector3f value) {
-        byte offset = offset(OFFSET, 4);
-        if (isVersion(ServerVersion.V_1_20_2, VersionComparison.OLDER_THAN)) {
-            offset = offset(OFFSET, 3);
-        }
-        super.metadata.setIndex(offset, EntityDataTypes.VECTOR3F, value);
-    }
-
-    public Quaternion4f getLeftRotation() {
-        byte offset = offset(OFFSET, 5);
-        if (isVersion(ServerVersion.V_1_20_2, VersionComparison.OLDER_THAN)) {
-            offset = offset(OFFSET, 4);
-        }
-        return super.metadata.getIndex(offset, new Quaternion4f(0.0f, 0.0f, 0.0f, 1.0f));
-    }
-
-    public void setLeftRotation(Quaternion4f value) {
-        byte offset = offset(OFFSET, 5);
-        if (isVersion(ServerVersion.V_1_20_2, VersionComparison.OLDER_THAN)) {
-            offset = offset(OFFSET, 4);
-        }
-        super.metadata.setIndex(offset, EntityDataTypes.QUATERNION, value);
-    }
-
-    public Quaternion4f getRightRotation() {
-        byte offset = offset(OFFSET, 6);
-        if (isVersion(ServerVersion.V_1_20_2, VersionComparison.OLDER_THAN)) {
-            offset = offset(OFFSET, 5);
-        }
-        return super.metadata.getIndex(offset, new Quaternion4f(0.0f, 0.0f, 0.0f, 1.0f));
-    }
-
-    public void setRightRotation(Quaternion4f value) {
-        byte offset = offset(OFFSET, 6);
-        if (isVersion(ServerVersion.V_1_20_2, VersionComparison.OLDER_THAN)) {
-            offset = offset(OFFSET, 5);
-        }
-        super.metadata.setIndex(offset, EntityDataTypes.QUATERNION, value);
-    }
-
-    public BillboardConstraints getBillboardConstraints() {
-        byte offset = offset(OFFSET, 7);
-        if (isVersion(ServerVersion.V_1_20_2, VersionComparison.OLDER_THAN)) {
-            offset = offset(OFFSET, 6);
-        }
-        return BillboardConstraints.VALUES[super.metadata.getIndex(offset, (byte) 0)];
-    }
-
-    public void setBillboardConstraints(BillboardConstraints value) {
-        byte offset = offset(OFFSET, 7);
-        if (isVersion(ServerVersion.V_1_20_2, VersionComparison.OLDER_THAN)) {
-            offset = offset(OFFSET, 6);
-        }
-        super.metadata.setIndex(offset, EntityDataTypes.BYTE, (byte) value.ordinal());
-    }
-
-    //(blockLight << 4 | skyLight << 20)
-    public int getBrightnessOverride() {
-        byte offset = offset(OFFSET, 8);
-        if (isVersion(ServerVersion.V_1_20_2, VersionComparison.OLDER_THAN)) {
-            offset = offset(OFFSET, 7);
-        }
-        return super.metadata.getIndex(offset, -1);
-    }
-
-    public void setBrightnessOverride(int value) {
-        byte offset = offset(OFFSET, 8);
-        if (isVersion(ServerVersion.V_1_20_2, VersionComparison.OLDER_THAN)) {
-            offset = offset(OFFSET, 7);
-        }
-        super.metadata.setIndex(offset, EntityDataTypes.INT, value);
-    }
-
-    public float getViewRange() {
-        byte offset = offset(OFFSET, 9);
-        if (isVersion(ServerVersion.V_1_20_2, VersionComparison.OLDER_THAN)) {
-            offset = offset(OFFSET, 8);
-        }
-        return super.metadata.getIndex(offset, 1.0f);
-    }
-
-    public void setViewRange(float value) {
-        byte offset = offset(OFFSET, 9);
-        if (isVersion(ServerVersion.V_1_20_2, VersionComparison.OLDER_THAN)) {
-            offset = offset(OFFSET, 8);
-        }
-        super.metadata.setIndex(offset, EntityDataTypes.FLOAT, value);
-    }
-
-    public float getShadowRadius() {
-        byte offset = offset(OFFSET, 10);
-        if (isVersion(ServerVersion.V_1_20_2, VersionComparison.OLDER_THAN)) {
-            offset = offset(OFFSET, 9);
-        }
-        return super.metadata.getIndex(offset, 0.0f);
-    }
-
-    public void setShadowRadius(float value) {
-        byte offset = offset(OFFSET, 10);
-        if (isVersion(ServerVersion.V_1_20_2, VersionComparison.OLDER_THAN)) {
-            offset = offset(OFFSET, 9);
-        }
-        super.metadata.setIndex(offset, EntityDataTypes.FLOAT, value);
-    }
-
-    public float getShadowStrength() {
-        byte offset = offset(OFFSET, 11);
-        if (isVersion(ServerVersion.V_1_20_2, VersionComparison.OLDER_THAN)) {
-            offset = offset(OFFSET, 10);
-        }
-        return super.metadata.getIndex(offset, 1.0f);
-    }
-
-    public void setShadowStrength(float value) {
-        byte offset = offset(OFFSET, 11);
-        if (isVersion(ServerVersion.V_1_20_2, VersionComparison.OLDER_THAN)) {
-            offset = offset(OFFSET, 10);
-        }
-        super.metadata.setIndex(offset, EntityDataTypes.FLOAT, value);
-    }
-
-    public float getWidth() {
-        byte offset = offset(OFFSET, 12);
-        if (isVersion(ServerVersion.V_1_20_2, VersionComparison.OLDER_THAN)) {
-            offset = offset(OFFSET, 11);
-        }
-        return super.metadata.getIndex(offset, 0.0f);
-    }
-
-    public void setWidth(float value) {
-        byte offset = offset(OFFSET, 12);
-        if (isVersion(ServerVersion.V_1_20_2, VersionComparison.OLDER_THAN)) {
-            offset = offset(OFFSET, 11);
-        }
-        super.metadata.setIndex(offset, EntityDataTypes.FLOAT, value);
-    }
-
-    public float getHeight() {
-        byte offset = offset(OFFSET, 13);
-        if (isVersion(ServerVersion.V_1_20_2, VersionComparison.OLDER_THAN)) {
-            offset = offset(OFFSET, 12);
-        }
-        return super.metadata.getIndex(offset, 0.0f);
-    }
-
-    public void setHeight(float value) {
-        byte offset = offset(OFFSET, 13);
-        if (isVersion(ServerVersion.V_1_20_2, VersionComparison.OLDER_THAN)) {
-            offset = offset(OFFSET, 12);
-        }
-        super.metadata.setIndex(offset, EntityDataTypes.FLOAT, value);
-    }
-
-    public int getGlowColorOverride() {
-        byte offset = offset(OFFSET, 14);
-        if (isVersion(ServerVersion.V_1_20_2, VersionComparison.OLDER_THAN)) {
-            offset = offset(OFFSET, 13);
-        }
-        return super.metadata.getIndex(offset, -1);
-    }
-
-    public void setGlowColorOverride(int value) {
-        byte offset = offset(OFFSET, 14);
-        if (isVersion(ServerVersion.V_1_20_2, VersionComparison.OLDER_THAN)) {
-            offset = offset(OFFSET, 13);
-        }
-        super.metadata.setIndex(offset, EntityDataTypes.INT, value);
-    }
-
-    public enum BillboardConstraints {
-        FIXED,
-        VERTICAL,
-        HORIZONTAL,
-        CENTER;
-
-        private static final BillboardConstraints[] VALUES = values();
-    }
-
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/types/ItemContainerMeta.java b/src/main/java/me/tofaa/entitylib/meta/types/ItemContainerMeta.java
deleted file mode 100644
index 7d0f87b..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/types/ItemContainerMeta.java
+++ /dev/null
@@ -1,27 +0,0 @@
-package me.tofaa.entitylib.meta.types;
-
-import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
-import com.github.retrooper.packetevents.protocol.item.ItemStack;
-import me.tofaa.entitylib.meta.EntityMeta;
-import me.tofaa.entitylib.meta.Metadata;
-
-public abstract class ItemContainerMeta extends EntityMeta {
-    public static final byte OFFSET = EntityMeta.MAX_OFFSET;
-    public static final byte MAX_OFFSET = OFFSET + 1;
-
-    private final ItemStack baseItem;
-
-    protected ItemContainerMeta(int entityId, Metadata metadata, ItemStack baseItem) {
-        super(entityId, metadata);
-        this.baseItem = baseItem;
-    }
-
-    public ItemStack getItem() {
-        return super.metadata.getIndex(OFFSET, baseItem);
-    }
-
-    public void setItem(ItemStack value) {
-        super.metadata.setIndex(OFFSET, EntityDataTypes.ITEMSTACK, value);
-    }
-
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/types/LivingEntityMeta.java b/src/main/java/me/tofaa/entitylib/meta/types/LivingEntityMeta.java
deleted file mode 100644
index 448c3cd..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/types/LivingEntityMeta.java
+++ /dev/null
@@ -1,119 +0,0 @@
-package me.tofaa.entitylib.meta.types;
-
-import com.github.retrooper.packetevents.manager.server.ServerVersion;
-import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
-import com.github.retrooper.packetevents.protocol.player.HumanoidArm;
-import com.github.retrooper.packetevents.util.Vector3i;
-import me.tofaa.entitylib.meta.EntityMeta;
-import me.tofaa.entitylib.meta.Metadata;
-
-import java.util.Optional;
-
-public class LivingEntityMeta extends EntityMeta {
-    public static final byte OFFSET = EntityMeta.MAX_OFFSET;
-    public static final byte MAX_OFFSET = OFFSET + 7;
-
-    private final static byte IS_HAND_ACTIVE_BIT = 0x01;
-    private final static byte ACTIVE_HAND_BIT = 0x02;
-    private final static byte IS_IN_SPIN_ATTACK_BIT = 0x04;
-
-    public LivingEntityMeta(int entityId, Metadata metadata) {
-        super(entityId, metadata);
-    }
-
-
-    public float getHealth() {
-        return super.metadata.getIndex(offset(OFFSET,1), 1F);
-    }
-
-
-    public int getPotionEffectColor() {
-        isVersionNewer(ServerVersion.V_1_9);
-        return super.metadata.getIndex(offset(OFFSET,2), 0);
-    }
-
-    public void setPotionEffectColor(int value) {
-        isVersionNewer(ServerVersion.V_1_9);
-        super.metadata.setIndex(offset(OFFSET,2), EntityDataTypes.INT, value);
-    }
-
-    public void setPotionEffectColor(int red, int green, int blue) {
-        isVersionNewer(ServerVersion.V_1_9);
-        setPotionEffectColor(red << 16 + green << 8 + blue);
-    }
-
-    public boolean isPotionEffectAmbient() {
-        isVersionNewer(ServerVersion.V_1_9);
-        return super.metadata.getIndex(offset(OFFSET,3), false);
-    }
-
-    public void setPotionEffectAmbient(boolean value) {
-        isVersionNewer(ServerVersion.V_1_9);
-        super.metadata.setIndex(offset(OFFSET,3), EntityDataTypes.BOOLEAN, value);
-    }
-
-    public int getArrowCount() {
-        isVersionNewer(ServerVersion.V_1_9);
-        return super.metadata.getIndex(offset(OFFSET,4), 0);
-    }
-
-    public void setArrowCount(int value) {
-        isVersionNewer(ServerVersion.V_1_9);
-        super.metadata.setIndex(offset(OFFSET,4), EntityDataTypes.INT, value);
-    }
-
-    public void setHealth(float value) {
-        super.metadata.setIndex(offset(OFFSET,1), EntityDataTypes.FLOAT, value);
-    }
-
-    public HumanoidArm getActiveHand() {
-        isVersionNewer(ServerVersion.V_1_9);
-        return getMaskBit(OFFSET, ACTIVE_HAND_BIT) ? HumanoidArm.LEFT : HumanoidArm.RIGHT;
-    }
-
-    public void setActiveHand(HumanoidArm value) {
-        isVersionNewer(ServerVersion.V_1_9);
-        setMaskBit(OFFSET, ACTIVE_HAND_BIT, value == HumanoidArm.LEFT);
-    }
-
-    public boolean isInRiptideSpinAttack() {
-        isVersionNewer(ServerVersion.V_1_13);
-        return getMaskBit(OFFSET, IS_IN_SPIN_ATTACK_BIT);
-    }
-
-    public void setInRiptideSpinAttack(boolean value) {
-        isVersionNewer(ServerVersion.V_1_13);
-        setMaskBit(OFFSET, IS_IN_SPIN_ATTACK_BIT, value);
-    }
-
-    public Optional<Vector3i> getBedPosition() {
-        isVersionNewer(ServerVersion.V_1_14);
-        return super.metadata.getIndex(offset(OFFSET,6), Optional.empty());
-    }
-
-    public void setBedPosition(Vector3i value) {
-        isVersionNewer(ServerVersion.V_1_14);
-        super.metadata.setIndex(offset(OFFSET,6), EntityDataTypes.OPTIONAL_BLOCK_POSITION, value == null ? Optional.empty() : Optional.of(value));
-    }
-
-    public int getBeeStingerCount() {
-        isVersionNewer(ServerVersion.V_1_15);
-        return super.metadata.getIndex(offset(OFFSET,5), 0);
-    }
-
-    public void setBeeStingerCount(int value) {
-        isVersionNewer(ServerVersion.V_1_15);
-        super.metadata.setIndex(offset(OFFSET,5), EntityDataTypes.INT, value);
-    }
-
-    public boolean isHandActive() {
-        isVersionNewer(ServerVersion.V_1_15);
-        return getMaskBit(OFFSET, IS_HAND_ACTIVE_BIT);
-    }
-
-    public void setHandActive(boolean value) {
-        isVersionNewer(ServerVersion.V_1_15);
-        setMaskBit(OFFSET, IS_HAND_ACTIVE_BIT, value);
-    }
-
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/types/MobMeta.java b/src/main/java/me/tofaa/entitylib/meta/types/MobMeta.java
deleted file mode 100644
index 82310ef..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/types/MobMeta.java
+++ /dev/null
@@ -1,49 +0,0 @@
-package me.tofaa.entitylib.meta.types;
-
-import com.github.retrooper.packetevents.manager.server.ServerVersion;
-import me.tofaa.entitylib.meta.EntityMeta;
-import me.tofaa.entitylib.meta.Metadata;
-
-public class MobMeta extends LivingEntityMeta {
-
-    public static final byte OFFSET = LivingEntityMeta.MAX_OFFSET;
-    public static final byte MAX_OFFSET = OFFSET + 1;
-
-    private final static byte NO_AI_BIT = 0x01;
-    private final static byte IS_LEFT_HANDED_BIT = 0x02;
-    private final static byte IS_AGGRESSIVE_BIT = 0x04;
-
-
-    public MobMeta(int entityId, Metadata metadata) {
-        super(entityId, metadata);
-    }
-
-    public boolean isNoAi() {
-        return getMaskBit(OFFSET, NO_AI_BIT);
-    }
-
-    public void setNoAi(boolean value) {
-        setMaskBit(OFFSET, NO_AI_BIT, value);
-    }
-
-    public boolean isLeftHanded() {
-        EntityMeta.isVersionNewer(ServerVersion.V_1_9);
-        return getMaskBit(OFFSET, IS_LEFT_HANDED_BIT);
-    }
-
-    public void setLeftHanded(boolean value) {
-        EntityMeta.isVersionNewer(ServerVersion.V_1_9);
-        setMaskBit(OFFSET, IS_LEFT_HANDED_BIT, value);
-    }
-
-    public boolean isAggressive() {
-        EntityMeta.isVersionNewer(ServerVersion.V_1_14);
-        return getMaskBit(OFFSET, IS_AGGRESSIVE_BIT);
-    }
-
-    public void setAggressive(boolean value) {
-        EntityMeta.isVersionNewer(ServerVersion.V_1_14);
-        setMaskBit(OFFSET, IS_AGGRESSIVE_BIT, value);
-    }
-
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/types/ObjectData.java b/src/main/java/me/tofaa/entitylib/meta/types/ObjectData.java
deleted file mode 100644
index 9d6785e..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/types/ObjectData.java
+++ /dev/null
@@ -1,9 +0,0 @@
-package me.tofaa.entitylib.meta.types;
-
-public interface ObjectData {
-
-    int getObjectData();
-
-    boolean requiresVelocityPacketAtSpawn();
-
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/types/PlayerMeta.java b/src/main/java/me/tofaa/entitylib/meta/types/PlayerMeta.java
deleted file mode 100644
index 21b1fc0..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/types/PlayerMeta.java
+++ /dev/null
@@ -1,148 +0,0 @@
-package me.tofaa.entitylib.meta.types;
-
-import com.github.retrooper.packetevents.manager.server.ServerVersion;
-import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
-import com.github.retrooper.packetevents.protocol.nbt.NBTCompound;
-import me.tofaa.entitylib.EntityLib;
-import me.tofaa.entitylib.meta.EntityMeta;
-import me.tofaa.entitylib.meta.Metadata;
-import org.jetbrains.annotations.Nullable;
-
-public class PlayerMeta extends LivingEntityMeta {
-
-    public static final byte OFFSET = LivingEntityMeta.MAX_OFFSET;
-    public static final byte MAX_OFFSET = OFFSET + 1;
-
-    private final static byte CAPE_BIT = 0x01;
-    private final static byte JACKET_BIT = 0x02;
-    private final static byte LEFT_SLEEVE_BIT = 0x04;
-    private final static byte RIGHT_SLEEVE_BIT = 0x08;
-    private final static byte LEFT_LEG_BIT = 0x10;
-    private final static byte RIGHT_LEG_BIT = 0x20;
-    private final static byte HAT_BIT = 0x40;
-
-    public PlayerMeta(int entityId, Metadata metadata) {
-        super(entityId, metadata);
-    }
-
-    public float getAdditionalHearts() {
-        return super.metadata.getIndex(OFFSET, 0F);
-    }
-
-    public void setAdditionalHearts(float value) {
-        super.metadata.setIndex(OFFSET, EntityDataTypes.FLOAT, value);
-    }
-
-    public int getScore() {
-        return super.metadata.getIndex(offset(OFFSET,1), 0);
-    }
-
-    public void setScore(int value) {
-        super.metadata.setIndex(offset(OFFSET,1), EntityDataTypes.INT, value);
-    }
-
-    public boolean isCapeEnabled() {
-        isVersionNewer(ServerVersion.V_1_9);
-        return getMaskBit(offset(OFFSET,2), CAPE_BIT);
-    }
-
-    public void setCapeEnabled(boolean value) {
-        isVersionNewer(ServerVersion.V_1_9);
-        setMaskBit(offset(OFFSET,2), CAPE_BIT, value);
-    }
-
-    public boolean isJacketEnabled() {
-        isVersionNewer(ServerVersion.V_1_9);
-        return getMaskBit(offset(OFFSET,2), JACKET_BIT);
-    }
-
-    public void setJacketEnabled(boolean value) {
-        isVersionNewer(ServerVersion.V_1_9);
-        setMaskBit(offset(OFFSET,2), JACKET_BIT, value);
-    }
-
-    public boolean isLeftSleeveEnabled() {
-        isVersionNewer(ServerVersion.V_1_9);
-        return getMaskBit(offset(OFFSET,2), LEFT_SLEEVE_BIT);
-    }
-
-    public void setLeftSleeveEnabled(boolean value) {
-        isVersionNewer(ServerVersion.V_1_9);
-        setMaskBit(offset(OFFSET,2), LEFT_SLEEVE_BIT, value);
-    }
-
-    public boolean isRightSleeveEnabled() {
-        isVersionNewer(ServerVersion.V_1_9);
-        return getMaskBit(offset(OFFSET,2), RIGHT_SLEEVE_BIT);
-    }
-
-    public void setRightSleeveEnabled(boolean value) {
-        isVersionNewer(ServerVersion.V_1_9);
-        setMaskBit(offset(OFFSET,2), RIGHT_SLEEVE_BIT, value);
-    }
-
-    public boolean isLeftLegEnabled() {
-        isVersionNewer(ServerVersion.V_1_9);
-        return getMaskBit(offset(OFFSET,2), LEFT_LEG_BIT);
-    }
-
-    public void setLeftLegEnabled(boolean value) {
-        isVersionNewer(ServerVersion.V_1_9);
-        setMaskBit(offset(OFFSET,2), LEFT_LEG_BIT, value);
-    }
-
-    public boolean isRightLegEnabled() {
-        isVersionNewer(ServerVersion.V_1_9);
-        return getMaskBit(offset(OFFSET,2), RIGHT_LEG_BIT);
-    }
-
-    public void setRightLegEnabled(boolean value) {
-        isVersionNewer(ServerVersion.V_1_9);
-        setMaskBit(offset(OFFSET,2), RIGHT_LEG_BIT, value);
-    }
-
-    public boolean isHatEnabled() {
-        isVersionNewer(ServerVersion.V_1_9);
-        return getMaskBit(offset(OFFSET,2), HAT_BIT);
-    }
-
-    public void setHatEnabled(boolean value) {
-        isVersionNewer(ServerVersion.V_1_9);
-        setMaskBit(offset(OFFSET,2), HAT_BIT, value);
-    }
-
-    public boolean isRightHandMain() {
-        if (EntityLib.getPacketEvents().getServerManager().getVersion().isOlderThan(ServerVersion.V_1_9)) {
-            return true;
-        }
-        return super.metadata.getIndex(offset(OFFSET,3), (byte) 1) == (byte) 1;
-    }
-
-    public void setRightHandMain(boolean value) {
-        if (EntityLib.getPacketEvents().getServerManager().getVersion().isOlderThan(ServerVersion.V_1_9)) {
-            return;
-        }
-        super.metadata.setIndex(offset(OFFSET,3), EntityDataTypes.BYTE, (byte) (value ? 1 : 0));
-    }
-
-    public @Nullable NBTCompound getLeftShoulderData() {
-        isVersionNewer(ServerVersion.V_1_11);
-        return super.metadata.getIndex(offset(OFFSET,4), null);
-    }
-
-    public void setLeftShoulderData(@Nullable NBTCompound value) {
-        if (value == null) value = new NBTCompound();
-        super.metadata.setIndex(offset(OFFSET,4), EntityDataTypes.NBT, value);
-    }
-
-    public @Nullable NBTCompound getRightShoulderData() {
-        isVersionNewer(ServerVersion.V_1_11);
-        return super.metadata.getIndex(offset(OFFSET,5), null);
-    }
-
-    public void setRightShoulderData(@Nullable NBTCompound value) {
-        if (value == null) value = new NBTCompound();
-        super.metadata.setIndex(offset(OFFSET,5), EntityDataTypes.NBT, value);
-    }
-
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/types/ProjectileMeta.java b/src/main/java/me/tofaa/entitylib/meta/types/ProjectileMeta.java
deleted file mode 100644
index 2560967..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/types/ProjectileMeta.java
+++ /dev/null
@@ -1,10 +0,0 @@
-package me.tofaa.entitylib.meta.types;
-
-
-public interface ProjectileMeta  {
-
-    int getShooter();
-
-    void setShooter(int entityId);
-
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/types/TameableMeta.java b/src/main/java/me/tofaa/entitylib/meta/types/TameableMeta.java
deleted file mode 100644
index 0db1569..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/types/TameableMeta.java
+++ /dev/null
@@ -1,46 +0,0 @@
-package me.tofaa.entitylib.meta.types;
-
-import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
-import me.tofaa.entitylib.meta.Metadata;
-
-import java.util.Optional;
-import java.util.UUID;
-
-public class TameableMeta extends AgeableMeta{
-
-    public static final byte OFFSET = AgeableMeta.MAX_OFFSET;
-    public static final byte MAX_OFFSET = OFFSET + 2;
-
-    private final static byte SITTING_BIT = 0x01;
-    private final static byte TAMED_BIT = 0x04;
-
-    public TameableMeta(int entityId, Metadata metadata) {
-        super(entityId, metadata);
-    }
-
-
-    public boolean isSitting() {
-        return getMaskBit(OFFSET, SITTING_BIT);
-    }
-
-    public void setSitting(boolean value) {
-        setMaskBit(OFFSET, SITTING_BIT, value);
-    }
-
-    public boolean isTamed() {
-        return getMaskBit(OFFSET, TAMED_BIT);
-    }
-
-    public void setTamed(boolean value) {
-        setMaskBit(OFFSET, TAMED_BIT, value);
-    }
-
-    public Optional<UUID> getOwner() {
-        return super.metadata.getIndex(offset(OFFSET, 1), Optional.empty());
-    }
-
-    public void setOwner(UUID value) {
-        super.metadata.setIndex(offset(OFFSET, 1), EntityDataTypes.OPTIONAL_UUID, Optional.ofNullable(value));
-    }
-
-}
diff --git a/src/main/java/me/tofaa/entitylib/meta/types/WaterMobMeta.java b/src/main/java/me/tofaa/entitylib/meta/types/WaterMobMeta.java
deleted file mode 100644
index 5b99469..0000000
--- a/src/main/java/me/tofaa/entitylib/meta/types/WaterMobMeta.java
+++ /dev/null
@@ -1,13 +0,0 @@
-package me.tofaa.entitylib.meta.types;
-
-import me.tofaa.entitylib.meta.Metadata;
-
-public class WaterMobMeta extends MobMeta {
-
-    public static final byte OFFSET = MobMeta.MAX_OFFSET;
-    public static final byte MAX_OFFSET = OFFSET + 0;
-
-    public WaterMobMeta(int entityId, Metadata metadata) {
-        super(entityId, metadata);
-    }
-}
diff --git a/test-plugin/src/main/java/me/tofaa/testentitylib/TestEntityLibPlugin.java b/test-plugin/src/main/java/me/tofaa/testentitylib/TestEntityLibPlugin.java
index b583bb0..32046b3 100644
--- a/test-plugin/src/main/java/me/tofaa/testentitylib/TestEntityLibPlugin.java
+++ b/test-plugin/src/main/java/me/tofaa/testentitylib/TestEntityLibPlugin.java
@@ -5,8 +5,6 @@ import com.github.retrooper.packetevents.protocol.entity.type.EntityTypes;
 import io.github.retrooper.packetevents.util.SpigotConversionUtil;
 import me.tofaa.entitylib.APIConfig;
 import me.tofaa.entitylib.EntityLib;
-import me.tofaa.entitylib.EntityLibAPI;
-import me.tofaa.entitylib.WorldWrapper;
 import me.tofaa.entitylib.meta.mobs.passive.ChickenMeta;
 import me.tofaa.entitylib.spigot.SpigotEntityLibAPI;
 import me.tofaa.entitylib.spigot.SpigotEntityLibPlatform;
@@ -16,11 +14,7 @@ import org.bukkit.command.Command;
 import org.bukkit.command.CommandExecutor;
 import org.bukkit.command.CommandSender;
 import org.bukkit.entity.Player;
-import org.bukkit.event.EventHandler;
-import org.bukkit.event.Listener;
-import org.bukkit.event.player.PlayerToggleSneakEvent;
 import org.bukkit.plugin.java.JavaPlugin;
-import org.bukkit.scheduler.BukkitTask;
 import org.jetbrains.annotations.NotNull;
 
 public class TestEntityLibPlugin extends JavaPlugin implements CommandExecutor {
@@ -28,7 +22,6 @@ public class TestEntityLibPlugin extends JavaPlugin implements CommandExecutor {
 
     private SpigotEntityLibAPI api;
     private WrapperEntity e;
-    private WorldWrapper<World> world;
 
     @Override
     public void onEnable() {
@@ -49,8 +42,7 @@ public class TestEntityLibPlugin extends JavaPlugin implements CommandExecutor {
         if (!(sender instanceof Player)) return false;
         Player player = (Player) sender;
         if (e == null) {
-            world = api.wrapWorld(player.getWorld());
-            e = world.spawnEntity(EntityTypes.CHICKEN, SpigotConversionUtil.fromBukkitLocation(player.getLocation()));
+            e = api.spawnEntity(EntityTypes.CHICKEN, SpigotConversionUtil.fromBukkitLocation(player.getLocation()));
             e.addViewer(player.getUniqueId());
             player.sendMessage("Spawned");
         }

From b1800486f3672286f630f89fac2b6790fb4440eb Mon Sep 17 00:00:00 2001
From: Tofaa <82680183+Tofaa2@users.noreply.github.com>
Date: Sat, 17 Feb 2024 19:04:32 +0400
Subject: [PATCH 17/19] fix stuff

---
 api/src/main/java/me/tofaa/entitylib/EntityLib.java     | 2 +-
 api/src/main/java/me/tofaa/entitylib/meta/Metadata.java | 4 ++--
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/api/src/main/java/me/tofaa/entitylib/EntityLib.java b/api/src/main/java/me/tofaa/entitylib/EntityLib.java
index bc21eb1..1870081 100644
--- a/api/src/main/java/me/tofaa/entitylib/EntityLib.java
+++ b/api/src/main/java/me/tofaa/entitylib/EntityLib.java
@@ -30,7 +30,7 @@ public final class EntityLib {
         }
     }
 
-    public static <W, T> EntityLibAPI<W, T> getApi() {
+    public static <T> EntityLibAPI<T> getApi() {
         return api;
     }
 
diff --git a/api/src/main/java/me/tofaa/entitylib/meta/Metadata.java b/api/src/main/java/me/tofaa/entitylib/meta/Metadata.java
index 5d27853..5e34240 100644
--- a/api/src/main/java/me/tofaa/entitylib/meta/Metadata.java
+++ b/api/src/main/java/me/tofaa/entitylib/meta/Metadata.java
@@ -45,7 +45,7 @@ public class Metadata {
         entries[index] = data;
         this.entryMap = null;
 
-        final WrapperEntity entity = EntityLib.getApi().findEntity(entityId);
+        final WrapperEntity entity = EntityLib.getApi().getEntity(entityId);
         if (entity == null || entity.isSpawned()) return; // Not EntityLib entity then, the user must send the packet manually. OR not spawned.
         if (!this.notifyChanges) {
             synchronized (this.notNotifiedChanges) {
@@ -64,7 +64,7 @@ public class Metadata {
         if (!notifyChanges) {
             return; // cache;
         }
-        final WrapperEntity entity = EntityLib.getApi().findEntity(entityId);
+        final WrapperEntity entity = EntityLib.getApi().getEntity(entityId);
         if (entity == null || entity.isSpawned()) return;
         Map<Byte, EntityData> entries;
         synchronized (this.notNotifiedChanges) {

From fa7c833ac5f5dd39b046e25b98935483da37a374 Mon Sep 17 00:00:00 2001
From: Tofaa <82680183+Tofaa2@users.noreply.github.com>
Date: Sat, 17 Feb 2024 19:06:57 +0400
Subject: [PATCH 18/19] fully remove world api, not needed

---
 .gitignore                                                      | 2 ++
 api/src/main/java/me/tofaa/entitylib/Platform.java              | 2 +-
 .../entitylib/wrapper/ai/goals/RandomHeadMovementGoal.java      | 2 +-
 3 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/.gitignore b/.gitignore
index b63da45..657fb60 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,7 @@
 .gradle
 build/
+.idea
+run
 !gradle/wrapper/gradle-wrapper.jar
 !**/src/main/**/build/
 !**/src/test/**/build/
diff --git a/api/src/main/java/me/tofaa/entitylib/Platform.java b/api/src/main/java/me/tofaa/entitylib/Platform.java
index 2c80033..3094a56 100644
--- a/api/src/main/java/me/tofaa/entitylib/Platform.java
+++ b/api/src/main/java/me/tofaa/entitylib/Platform.java
@@ -57,7 +57,7 @@ public interface Platform<P> {
     /**
      * @return The API instance.
      */
-    EntityLibAPI<?, ?> getAPI();
+    EntityLibAPI<?> getAPI();
 
     /**
      * @return the platforms name.
diff --git a/api/src/main/java/me/tofaa/entitylib/wrapper/ai/goals/RandomHeadMovementGoal.java b/api/src/main/java/me/tofaa/entitylib/wrapper/ai/goals/RandomHeadMovementGoal.java
index a69b925..4105d43 100644
--- a/api/src/main/java/me/tofaa/entitylib/wrapper/ai/goals/RandomHeadMovementGoal.java
+++ b/api/src/main/java/me/tofaa/entitylib/wrapper/ai/goals/RandomHeadMovementGoal.java
@@ -66,7 +66,7 @@ public class RandomHeadMovementGoal extends GoalSelector {
     @Override
     public void tick(long time) {
         --lookTime;
-        entity.teleport(entity.getWorld(), CoordinateUtil.withDirection(entity.getLocation(), lookDirection), entity.isOnGround());
+        entity.teleport(CoordinateUtil.withDirection(entity.getLocation(), lookDirection), entity.isOnGround());
     }
 
     @Override

From 88c6ce35d4b068d0cb59b0e505f058db205686c6 Mon Sep 17 00:00:00 2001
From: Tofaa <82680183+Tofaa2@users.noreply.github.com>
Date: Sat, 17 Feb 2024 19:13:42 +0400
Subject: [PATCH 19/19] cleanup

---
 .gitignore               | 2 ++
 api/build.gradle         | 2 +-
 test-plugin/build.gradle | 3 +++
 3 files changed, 6 insertions(+), 1 deletion(-)

diff --git a/.gitignore b/.gitignore
index 657fb60..e2b0212 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,6 +2,8 @@
 build/
 .idea
 run
+test-plugin/build
+test-plugin/run
 !gradle/wrapper/gradle-wrapper.jar
 !**/src/main/**/build/
 !**/src/test/**/build/
diff --git a/api/build.gradle b/api/build.gradle
index 3e5d186..229c589 100644
--- a/api/build.gradle
+++ b/api/build.gradle
@@ -14,5 +14,5 @@ dependencies {
     api 'org.jetbrains:annotations:24.0.0'
 
     compileOnlyApi(adventureDependencies)
-    compileOnlyApi 'com.github.retrooper.packetevents:api:2.2.0'
+    compileOnlyApi 'com.github.retrooper.packetevents:api:2.2.1'
 }
diff --git a/test-plugin/build.gradle b/test-plugin/build.gradle
index 29dc72d..69caf37 100644
--- a/test-plugin/build.gradle
+++ b/test-plugin/build.gradle
@@ -33,5 +33,8 @@ dependencies {
 tasks {
     runServer {
         minecraftVersion("1.20.4")
+        downloadPlugins {
+            modrinth("packetevents", "2.2.1")
+        }
     }
 }
\ No newline at end of file