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 {
+ /**
+ * 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
{
@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 the event type.
- */
- void registerListener(Class eventClass, Consumer 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 {
- ResourceLocation getPacketEventsWorld();
+ @NotNull T spawnEntity(@NotNull Class wrapperClass, @NotNull EntityType entityType, @NotNull Location location);
+ @NotNull WrapperEntity spawnEntity(@NotNull EntityType entityType, @NotNull Location location);
+
+ @NotNull T spawnEntity(@NotNull T entity, @NotNull Location location);
+
+ @NotNull T cloneEntity(@NotNull Object platformEntity, @NotNull Location location);
+
+ @NotNull Collection 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 The type of {@link EntityLibEvent}
+ */
+ void addListener(@NotNull EventListener listener);
+
+ /**
+ * Adds a listener to the EventBus.
+ * @param eventClass The events class
+ * @param consumer The consumer for the event.
+ * @param The type of {@link EntityLibEvent}
+ */
+ void addListener(@NotNull Class eventClass, @NotNull Consumer consumer);
+
+ /**
+ * Removes a listener from the EventBus.
+ * @param listener the listener object.
+ * @param The type of {@link EntityLibEvent}
+ */
+ void removeListener(@NotNull EventListener 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 The type of {@link 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 The type of {@link EntityLibEvent}
+ */
+ void call(@NotNull T event, @NotNull Consumer 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 void addListener(@NotNull EventListener listener) {
+ if (listeners.containsKey(listener.getEventClass())) {
+ listeners.put(listener.getEventClass(), new HashSet<>());
+ }
+ ((HashSet) listeners.get(listener.getEventClass())).add(listener);
+ }
+
+ @Override
+ public void addListener(@NotNull Class eventClass, @NotNull Consumer consumer) {
+ addListener(EventListener.generateListener(eventClass, consumer));
+
+ }
+
+ @Override
+ public void removeListener(@NotNull EventListener listener) {
+ if (listeners.containsKey(listener.getEventClass())) {
+ ((HashSet) listeners.get(listener.getEventClass())).remove(listener);
+ }
+ }
+
+ @Override
+ public @NotNull T call(@NotNull T event) {
+ executor.execute(() -> dispatchEvent(event));
+ return event;
+ }
+
+
+ private void dispatchEvent(T event) {
+ if (!listeners.containsKey(event.getClass())) return;
+ HashSet> consumers = (HashSet>) listeners.get(event.getClass());
+ consumers.forEach(consumer -> consumer.handle(event));
+ }
+
+
+ @Override
+ public void call(@NotNull T event, @NotNull Consumer 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 void addListener(@NotNull EventListener listener) {
+ if (listeners.containsKey(listener.getEventClass())) {
+ listeners.put(listener.getEventClass(), new HashSet<>());
+ }
+ ((HashSet) listeners.get(listener.getEventClass())).add(listener);
+ }
+
+ @Override
+ public void addListener(@NotNull Class eventClass, @NotNull Consumer consumer) {
+ addListener(EventListener.generateListener(eventClass, consumer));
+ }
+
+ @Override
+ public void removeListener(@NotNull EventListener listener) {
+ if (listeners.containsKey(listener.getEventClass())) {
+ ((HashSet) listeners.get(listener.getEventClass())).remove(listener);
+ }
+ }
+
+ @Override
+ public @NotNull T call(@NotNull T event) {
+ if (!listeners.containsKey(event.getClass())) return event;
+ HashSet> consumers = (HashSet>) 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 {
+
+ @NotNull Class getEventClass();
+
+ void handle(@NotNull E event);
+
+ public static EventListener generateListener(Class eventClass, Consumer consumer) {
+ return new EventListener() {
+ @Override
+ public @NotNull Class 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 metaMap = new ConcurrentHashMap<>();
+
+ public static @NotNull BiFunction 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 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> converters = new HashMap<>();
+ private final Map> 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 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 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 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 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 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 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 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 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 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 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 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 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 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.
+ *
+ *
+ * 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.
+ *
+ * The {@link WrapperEntityCreature} can be inherited to create custom entities.
+ *
+ */
+public class WrapperEntityCreature extends WrapperLivingEntity {
+
+ private final Set 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.
+ *
+ * The AIGroup will be updated every tick.
+ *
+ *
+ * @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 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 = 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.
+ *
+ * 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.
+ *
+ */
+ 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 goalSelectors = new GoalSelectorList(this);
+ private GoalSelector currentGoalSelector;
+
+ public @NotNull Collection 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 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.
+ *
+ * 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 {
+
+ 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 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 minimalLookTimeSupplier;
+ private final Function 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 minimalLookTimeSupplier,
+ @NotNull Function 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 implements EntityLibAPI {
+
+ protected final Platform platform;
+ protected final PacketEventsAPI> packetEvents;
+ protected final APISettings settings;
+ protected final Collection> tickContainers;
+
+ protected AbstractEntityLibAPI(Platform 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> 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 implements Platform
{
+
+
+ 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 implements WorldWrapper {
+
+ private final Map entities;
+ private final Map 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 @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 @NotNull T spawnEntity(Class 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 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 {
+public class SpigotEntityLibAPI extends AbstractEntityLibAPI {
- private final SpigotEntityLibPlatform platform;
- private final PacketEventsAPI> packetEvents;
- private final APISettings settings;
- private Collection> 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 {
}
- @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 wrapWorld(World world) {
+ return new SpigotWorld(world);
}
- @Override
- public PacketEventsAPI> getPacketEvents() {
- return packetEvents;
- }
-
- @Override
- public Collection> 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 {
}
+
}
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 {
+public class SpigotEntityLibPlatform extends AbstractPlatform {
- 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 void registerListener(Class eventClass, Consumer 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 {
+
+
+ SpigotWorld(World world) {
+ super(world.getUID(), world, SpigotConversionUtil.fromBukkitWorld(world));
+ }
+
+
+ @Override
+ public @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 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 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: