From f819cdb89332f1a473e441be798ba334d51f1810 Mon Sep 17 00:00:00 2001 From: LoJoSho Date: Sat, 1 Mar 2025 22:19:40 -0600 Subject: [PATCH 01/28] fix: playHurtAnimation not working on 1.19.4+ versions --- .../wrapper/WrapperLivingEntity.java | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperLivingEntity.java b/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperLivingEntity.java index df599ce..170f3d6 100644 --- a/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperLivingEntity.java +++ b/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperLivingEntity.java @@ -1,12 +1,15 @@ package me.tofaa.entitylib.wrapper; +import com.github.retrooper.packetevents.manager.server.ServerVersion; import com.github.retrooper.packetevents.protocol.entity.type.EntityType; import com.github.retrooper.packetevents.protocol.nbt.NBTCompound; import com.github.retrooper.packetevents.protocol.potion.PotionType; import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerEntityAnimation; import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerEntityEffect; +import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerHurtAnimation; import me.tofaa.entitylib.EntityLib; import me.tofaa.entitylib.meta.EntityMeta; +import me.tofaa.entitylib.utils.VersionUtil; import org.jetbrains.annotations.Nullable; import java.util.UUID; @@ -110,7 +113,29 @@ public class WrapperLivingEntity extends WrapperEntity{ sendAnimation(WrapperPlayServerEntityAnimation.EntityAnimationType.WAKE_UP); } + /** + * Plays the hurt animation of the entity. + * This method is deprecated and should use {@link #playHurtAnimation(int)} instead. + */ + @Deprecated public void playHurtAnimation() { + playHurtAnimation(0); + } + + /** + * Plays the hurt animation of the entity. + * @param yaw The yaw of the entity when the hurt animation is played. + * For any entity other than a player it's safe to simply put 0, as it's not used. + * The yaw is only used on 1.19.4+. + */ + public void playHurtAnimation(int yaw) { + // 1.19.4+ uses a different packet for hurt animation than previous versions + if (VersionUtil.isNewerThan(ServerVersion.V_1_19_4)) { + sendPacketToViewers( + new WrapperPlayServerHurtAnimation(getEntityId(), yaw) + ); + return; + } sendAnimation(WrapperPlayServerEntityAnimation.EntityAnimationType.HURT); } From 6fba8ea5fdc7880d1c62c3428f562fea2745b58b Mon Sep 17 00:00:00 2001 From: Tofaa2 Date: Wed, 5 Mar 2025 14:23:36 +0400 Subject: [PATCH 02/28] fix: ViewerEngine#untrack impl --- .../me/tofaa/entitylib/ve/ViewerEngine.java | 61 ++++++++++++++++++- 1 file changed, 60 insertions(+), 1 deletion(-) diff --git a/api/src/main/java/me/tofaa/entitylib/ve/ViewerEngine.java b/api/src/main/java/me/tofaa/entitylib/ve/ViewerEngine.java index b1036c7..17147dd 100644 --- a/api/src/main/java/me/tofaa/entitylib/ve/ViewerEngine.java +++ b/api/src/main/java/me/tofaa/entitylib/ve/ViewerEngine.java @@ -25,21 +25,56 @@ public class ViewerEngine { private final Set tracked; private final ViewerEngineListener listener; private Executor executor; + private boolean enabled = false; + /** + * Creates an instance of ViewerEngine + * It is recommended to specify explicitly the Executor that should be used. + */ public ViewerEngine() { + this(Executors.newSingleThreadExecutor()); + } + + /** + * Creates an instance of ViewerEngine with a specific executor. Depending on your rules one thread might not be enough + * @param executor The executor that is used to process entity tracking. + */ + public ViewerEngine(Executor executor) { this.globalRules = new CopyOnWriteArrayList<>(); this.tracked = Collections.newSetFromMap(new WeakHashMap<>()); - this.executor = Executors.newSingleThreadExecutor(); + this.executor = executor; this.listener = new ViewerEngineListener(this); } + /** + * Enables this viewer engine. + * Registers a viewer engine listener to handle tracking + */ public void enable() { + if (enabled) { + return; + } + enabled = true; EntityLib.getApi().getPacketEvents().getEventManager().registerListener(listener); } + + + /** + * Disables this viewer engine. + * Unregisters the viewer engine listener that handles tracking. + */ public void disable() { + if (!enabled) { + return; + } + enabled = false; EntityLib.getApi().getPacketEvents().getEventManager().unregisterListener(listener); } + /** + * Refreshes and updates every tracked by this viewer engine entities viewers to see if they follow the spawning rules. + * If they do not they will no longer see the entity; + */ public void refresh() { getTracked0().forEach(entity -> { for (UUID viewer : entity.getViewers()) { @@ -58,19 +93,40 @@ public class ViewerEngine { this.executor = executor; } + /** + * Tells this ViewerEngine to begin tracking a specific {@link WrapperEntity} + * @param entity the entity to begin tracking. + */ public void track(@NotNull WrapperEntity entity) { tracked.add(entity); } + /** + * Tells this ViewerEngine to stop tracking a specific {@link WrapperEntity} + * @param entity the entity to stop tracking. + */ + public void untrack(@NotNull WrapperEntity entity) { + tracked.remove(entity); + } + public void clearTracked() { tracked.clear(); } + /** + * Checks if a viewer/user validates every viewer rule handled by this viewer engine or not. + * @param user The user to check + * @param entity The entity that is getting its own viewer rules checked as well as the global defined one with {@link ViewerEngine#addViewerRule(ViewerRule)} + * @return true if the user passed and did not fail any rules, false otherwise + */ public boolean canSpawnFor(User user, WrapperEntity entity) { if (entity.getViewerRules().stream().anyMatch(rule -> rule.shouldSee(user))) return true; return globalRules.stream().anyMatch(rule -> rule.shouldSee(user)); } + /** + * Same as {@link ViewerEngine#canSpawnFor(User, WrapperEntity)} but with UUID instead of User + */ public boolean canSpawnFor(UUID userId, WrapperEntity entity) { User user = EntityLib.getApi().getPacketEvents().getProtocolManager().getUser( EntityLib.getApi().getPacketEvents().getProtocolManager().getChannel(userId) @@ -79,6 +135,9 @@ public class ViewerEngine { return canSpawnFor(user, entity); } + /** + * @return An unmodifiable view of the entities that are being tracked. + */ public @UnmodifiableView Collection getTracked() { return Collections.unmodifiableCollection(tracked); } From e181b979a07c2598a66b0e1fa32d8b8542dd5c96 Mon Sep 17 00:00:00 2001 From: Tofaa <82680183+Tofaa2@users.noreply.github.com> Date: Tue, 25 Mar 2025 20:29:05 +0400 Subject: [PATCH 03/28] publicize standalone platform constructor --- .../tofaa/entitylib/standalone/StandaloneEntityLibPlatform.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platforms/standalone/src/main/java/me/tofaa/entitylib/standalone/StandaloneEntityLibPlatform.java b/platforms/standalone/src/main/java/me/tofaa/entitylib/standalone/StandaloneEntityLibPlatform.java index f344e45..971eb56 100644 --- a/platforms/standalone/src/main/java/me/tofaa/entitylib/standalone/StandaloneEntityLibPlatform.java +++ b/platforms/standalone/src/main/java/me/tofaa/entitylib/standalone/StandaloneEntityLibPlatform.java @@ -10,7 +10,7 @@ public class StandaloneEntityLibPlatform extends AbstractPlatform { private StandaloneEntityLibApi api; - private StandaloneEntityLibPlatform() { + public StandaloneEntityLibPlatform() { super(null); } From 7298de0bb7575617a84db3fc7ebe19471cc36823 Mon Sep 17 00:00:00 2001 From: Tofaa2 Date: Mon, 31 Mar 2025 21:27:58 +0400 Subject: [PATCH 04/28] Use dyecolor and byte, remove old method --- .../meta/mobs/golem/ShulkerMeta.java | 19 +++++++++++--- .../tofaa/entitylib/version/ELVersionTask.kt | 26 ++++++++++++++++++- .../testentitylib/TestEntityLibPlugin.java | 2 ++ 3 files changed, 42 insertions(+), 5 deletions(-) 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 index 88617a9..01712e8 100644 --- 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 @@ -1,10 +1,12 @@ package me.tofaa.entitylib.meta.mobs.golem; +import com.github.retrooper.packetevents.protocol.color.DyeColor; 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 net.kyori.adventure.text.format.NamedTextColor; import java.util.Optional; @@ -13,6 +15,8 @@ public class ShulkerMeta extends MobMeta { public static final byte OFFSET = MobMeta.MAX_OFFSET; public static final byte MAX_OFFSET = OFFSET + 1; + private static final DyeColor[] DYE_COLORS = DyeColor.values(); + public ShulkerMeta(int entityId, Metadata metadata) { super(entityId, metadata); @@ -35,20 +39,27 @@ public class ShulkerMeta extends MobMeta { } public byte getShieldHeight() { - return super.metadata.getIndex(offset(OFFSET, 2), (byte) 0); + return super.metadata.getIndex(offset(OFFSET, 1), (byte) 0); } public void setShieldHeight(byte value) { - super.metadata.setIndex(offset(OFFSET, 2), EntityDataTypes.BYTE, value); + super.metadata.setIndex(offset(OFFSET, 1), EntityDataTypes.BYTE, value); } public byte getColor() { - return super.metadata.getIndex(offset(OFFSET, 3), (byte) 10); + return super.metadata.getIndex(offset(OFFSET, 2), (byte) 16); + } + + public DyeColor getColorEnum() { + return DYE_COLORS[getColor()]; } public void setColor(byte value) { - super.metadata.setIndex(offset(OFFSET, 3), EntityDataTypes.BYTE, value); + super.metadata.setIndex(offset(OFFSET, 2), EntityDataTypes.BYTE, value); } + public void setColor(DyeColor color) { + setColor((byte)color.ordinal()); + } } diff --git a/buildSrc/src/main/kotlin/me/tofaa/entitylib/version/ELVersionTask.kt b/buildSrc/src/main/kotlin/me/tofaa/entitylib/version/ELVersionTask.kt index c01ef12..1606cc1 100644 --- a/buildSrc/src/main/kotlin/me/tofaa/entitylib/version/ELVersionTask.kt +++ b/buildSrc/src/main/kotlin/me/tofaa/entitylib/version/ELVersionTask.kt @@ -40,7 +40,8 @@ abstract class ELVersionTask : DefaultTask() { * This file is generated by the auto-version task. Modifying it will have no effect. */ package $packageName; - + + import java.text.DateFormat; import com.github.retrooper.packetevents.util.PEVersion; public final class ELVersions { @@ -52,6 +53,29 @@ abstract class ELVersionTask : DefaultTask() { private ELVersions() { throw new IllegalStateException(); } + + public static class Version { + + private final long timestamp; + + public Version(long timestamp) { + this.timestamp = timestamp; + } + + public long getTimestamp() { + return timestamp; + } + + public String getTimestampFormatted() { + return DateFormat.getDateTimeInstance().format(new java.util.Date(timestamp)); + } + + public boolean isOlderThan(Version version) { + return this.timestamp < version.timestamp; + } + + } + } """.trimIndent()) } diff --git a/test-plugin/src/main/java/me/tofaa/testentitylib/TestEntityLibPlugin.java b/test-plugin/src/main/java/me/tofaa/testentitylib/TestEntityLibPlugin.java index a70b9c6..90af2e5 100644 --- a/test-plugin/src/main/java/me/tofaa/testentitylib/TestEntityLibPlugin.java +++ b/test-plugin/src/main/java/me/tofaa/testentitylib/TestEntityLibPlugin.java @@ -9,11 +9,13 @@ import org.bukkit.command.CommandMap; import org.bukkit.plugin.java.JavaPlugin; import java.lang.reflect.InvocationTargetException; +import java.text.DateFormat; public class TestEntityLibPlugin extends JavaPlugin { @Override public void onEnable() { + DateFormat.getDateTimeInstance().format(new java.util.Date(timestamp)); SpigotEntityLibPlatform platform = new SpigotEntityLibPlatform(this); APIConfig settings = new APIConfig(PacketEvents.getAPI()) From 53e4d917cd0389d7ac64c96f7f4d8b8ffc725caf Mon Sep 17 00:00:00 2001 From: Tofaa2 Date: Mon, 31 Mar 2025 21:35:44 +0400 Subject: [PATCH 05/28] Fix build error --- .../me/tofaa/entitylib/meta/MetaConverterRegistry.java | 1 - .../me/tofaa/entitylib/meta/mobs/golem/ShulkerMeta.java | 8 -------- api/src/main/java/me/tofaa/entitylib/ve/ViewerEngine.java | 1 + settings.gradle.kts | 2 +- 4 files changed, 2 insertions(+), 10 deletions(-) diff --git a/api/src/main/java/me/tofaa/entitylib/meta/MetaConverterRegistry.java b/api/src/main/java/me/tofaa/entitylib/meta/MetaConverterRegistry.java index bbdbf3f..96ebf30 100644 --- a/api/src/main/java/me/tofaa/entitylib/meta/MetaConverterRegistry.java +++ b/api/src/main/java/me/tofaa/entitylib/meta/MetaConverterRegistry.java @@ -1,7 +1,6 @@ package me.tofaa.entitylib.meta; import com.github.retrooper.packetevents.protocol.entity.type.EntityType; -import com.github.retrooper.packetevents.protocol.entity.type.EntityTypes; import me.tofaa.entitylib.meta.display.BlockDisplayMeta; import me.tofaa.entitylib.meta.display.ItemDisplayMeta; import me.tofaa.entitylib.meta.display.TextDisplayMeta; 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 index 01712e8..b41887c 100644 --- 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 @@ -30,14 +30,6 @@ public class ShulkerMeta extends MobMeta { 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, 1), (byte) 0); } diff --git a/api/src/main/java/me/tofaa/entitylib/ve/ViewerEngine.java b/api/src/main/java/me/tofaa/entitylib/ve/ViewerEngine.java index 17147dd..0d3630f 100644 --- a/api/src/main/java/me/tofaa/entitylib/ve/ViewerEngine.java +++ b/api/src/main/java/me/tofaa/entitylib/ve/ViewerEngine.java @@ -27,6 +27,7 @@ public class ViewerEngine { private Executor executor; private boolean enabled = false; + /** * Creates an instance of ViewerEngine * It is recommended to specify explicitly the Executor that should be used. diff --git a/settings.gradle.kts b/settings.gradle.kts index bf53135..b6f773a 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -34,7 +34,7 @@ include(":platforms:spigot") include(":platforms:velocity") include(":platforms:standalone") -if (!System.getenv("JITPACK").toBoolean()) { +if (System.getenv("PRIVATE").toBoolean()) { include("discord-bot") include(":code-gen") include(":test-plugin") From 0868a756179b496e88356a90188087717d86ebc0 Mon Sep 17 00:00:00 2001 From: Felipe Paschoal Bergamo <64669985+felipepasc@users.noreply.github.com> Date: Tue, 1 Apr 2025 10:43:55 -0300 Subject: [PATCH 06/28] feat: potion effect controller system --- .../entitylib/wrapper/WrapperEntity.java | 142 +++++---- .../wrapper/WrapperEntityPotionEffect.java | 275 ++++++++++++++++++ .../wrapper/WrapperLivingEntity.java | 100 ++++--- 3 files changed, 432 insertions(+), 85 deletions(-) create mode 100644 api/src/main/java/me/tofaa/entitylib/wrapper/WrapperEntityPotionEffect.java diff --git a/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperEntity.java b/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperEntity.java index a0c211f..ed5c58c 100644 --- a/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperEntity.java +++ b/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperEntity.java @@ -25,11 +25,10 @@ import java.util.concurrent.CopyOnWriteArrayList; import java.util.function.Consumer; public class WrapperEntity implements Tickable { - private final UUID uuid; private final int entityId; - private EntityType entityType; - private EntityMeta entityMeta; + private final EntityType entityType; + private final EntityMeta entityMeta; private boolean ticking; protected Location location; private Location preRidingLocation; @@ -62,6 +61,7 @@ public class WrapperEntity implements Tickable { public WrapperEntity(UUID uuid, EntityType entityType) { this(EntityLib.getPlatform().getEntityIdProvider().provide(uuid, entityType), uuid, entityType); } + public WrapperEntity(EntityType entityType) { this(EntityLib.getPlatform().getEntityUuidProvider().provide(entityType), entityType); } @@ -72,8 +72,10 @@ public class WrapperEntity implements Tickable { public boolean spawn(Location location, EntityContainer parent) { if (spawned) return false; + this.location = location; this.spawned = true; + sendPacketsToViewers( new WrapperPlayServerSpawnEntity( entityId, @@ -88,9 +90,14 @@ public class WrapperEntity implements Tickable { ), entityMeta.createPacket() ); + if (this instanceof WrapperLivingEntity) { - sendPacketsToViewers(((WrapperLivingEntity)this).getAttributes().createPacket()); + WrapperLivingEntity wrapperLivingEntity = (WrapperLivingEntity) this; + wrapperLivingEntity.createSpawnPackets().forEach(packetWrapper -> { + sendPacket(uuid, packetWrapper); + }); } + this.parent = parent; parent.addEntity(this); return true; @@ -101,7 +108,7 @@ public class WrapperEntity implements Tickable { return SpawnPacketProvider.GENERAL.provide(this); } - public boolean spawn(Location location) { + public boolean spawn(@NotNull Location location) { return spawn(location, EntityLib.getApi().getDefaultContainer()); } @@ -110,6 +117,7 @@ public class WrapperEntity implements Tickable { if (entityMeta instanceof ObjectData) { return ((ObjectData) entityMeta).getObjectData(); } + return 0; } @@ -117,6 +125,7 @@ public class WrapperEntity implements Tickable { public Optional createVeloPacket() { Optional velocity; double veloX = 0, veloY = 0, veloZ = 0; + if (entityMeta instanceof ObjectData) { ObjectData od = (ObjectData) entityMeta; if (od.requiresVelocityPacketAtSpawn()) { @@ -126,11 +135,13 @@ public class WrapperEntity implements Tickable { veloZ = veloPacket.getVelocity().getZ(); } } + if (veloX == 0 && veloY == 0 && veloZ == 0) { velocity = Optional.of(Vector3d.zero()); } else { velocity = Optional.of(new Vector3d(veloX, veloY, veloZ)); } + return velocity; } @@ -141,37 +152,37 @@ public class WrapperEntity implements Tickable { public void remove() { if (parent != null) { parent.removeEntity(this, true); - } - else { + } else { despawn(); } } public void despawn() { if (!spawned) return; + spawned = false; + if (this instanceof WrapperPlayer) { WrapperPlayer p = (WrapperPlayer) this; sendPacketsToViewers(p.tabListRemovePacket()); } + sendPacketToViewers(new WrapperPlayServerDestroyEntities(entityId)); } public void teleport(@NotNull Location location, boolean onGround) { - if (!spawned) { - return; - } + if (!spawned) return; + this.location = location; this.onGround = onGround; - sendPacketToViewers( - new WrapperPlayServerEntityTeleport( - entityId, - location.getPosition(), - location.getYaw(), - location.getPitch(), - onGround - ) - ); + + sendPacketToViewers(new WrapperPlayServerEntityTeleport( + entityId, + location.getPosition(), + location.getYaw(), + location.getPitch(), + onGround + )); } public void teleport(@NotNull Location location) { @@ -180,30 +191,40 @@ public class WrapperEntity implements Tickable { /** * Adds a viewer to the viewers set. The viewer will receive all packets and be informed of this addition + * * @param uuid the uuid of the user to add */ - public void addViewer(UUID uuid) { + public void addViewer(@NotNull UUID uuid) { if (!viewers.add(uuid)) { return; } + if (location == null) { if (EntityLib.getApi().getSettings().isDebugMode()) { EntityLib.getPlatform().getLogger().warning("Location is null for entity " + entityId + ". Cannot spawn."); } + return; } + if (spawned) { if (this instanceof WrapperPlayer) { WrapperPlayer p = (WrapperPlayer) this; sendPacket(uuid, p.tabListPacket()); } + sendPacket(uuid, createSpawnPacket()); sendPacket(uuid, entityMeta.createPacket()); sendPacket(uuid, createPassengerPacket()); + if (this instanceof WrapperLivingEntity) { - sendPacket(uuid, ((WrapperLivingEntity)this).getAttributes().createPacket()); + WrapperLivingEntity wrapperLivingEntity = (WrapperLivingEntity) this; + wrapperLivingEntity.createSpawnPackets().forEach(packetWrapper -> { + sendPacket(uuid, packetWrapper); + }); } } + if (EntityLib.getApi().getSettings().isDebugMode()) { EntityLib.getPlatform().getLogger().info("Added viewer " + uuid + " to entity " + entityId); } @@ -235,62 +256,70 @@ public class WrapperEntity implements Tickable { ); } - public void addViewer(User user) { + public void addViewer(@NotNull User user) { addViewer(user.getUUID()); } /** * Adds a viewer silently into the viewers set. The viewer will not receive any packets or be informed of this addition + * * @param uuid the uuid of the user to add */ - public void addViewerSilently(UUID uuid) { + public void addViewerSilently(@NotNull UUID uuid) { viewers.add(uuid); } /** * Adds a viewer silently into the viewers set. The viewer will not receive any packets or be informed of this addition + * * @param user the user to add */ - public void addViewerSilently(User user) { + public void addViewerSilently(@NotNull User user) { addViewerSilently(user.getUUID()); } /** * Removes a viewer from the viewers set of this entity. The viewer will be informed of this removal and will no longer receive any packets + * * @param uuid the uuid of the user to remove */ - public void removeViewer(UUID uuid) { + public void removeViewer(@NotNull UUID uuid) { if (!viewers.remove(uuid)) { return; } + if (this instanceof WrapperPlayer) { WrapperPlayer p = (WrapperPlayer) this; sendPacket(uuid, p.tabListRemovePacket()); } + sendPacket(uuid, new WrapperPlayServerDestroyEntities(entityId)); } /** * Removes a viewer from the viewers set of this entity. The viewer will be informed of this removal and will no longer receive any packets + * * @param user the user to remove */ - public void removeViewer(User user) { + public void removeViewer(@NotNull User user) { removeViewer(user.getUUID()); } /** * removes a viewer silently into the viewers set. The viewer will not receive any packets or be informed of this removal + * * @param uuid of the user to remove */ - public void removeViewerSilently(UUID uuid) { + public void removeViewerSilently(@NotNull UUID uuid) { viewers.remove(uuid); } /** * removes a viewer silently into the viewers set. The viewer will not receive any packets or be informed of this removal + * * @param user the user to remove */ - public void removeViewerSilently(User user) { + public void removeViewerSilently(@NotNull User user) { removeViewerSilently(user.getUUID()); } @@ -298,11 +327,11 @@ public class WrapperEntity implements Tickable { return onGround; } - public Vector3d getVelocity() { + public @NotNull Vector3d getVelocity() { return velocity; } - public void setVelocity(Vector3d velocity) { + public void setVelocity(@NotNull Vector3d velocity) { this.velocity = velocity; sendPacketToViewers(getVelocityPacket()); } @@ -331,7 +360,7 @@ public class WrapperEntity implements Tickable { return entityId; } - public EntityMeta getEntityMeta() { + public @NotNull EntityMeta getEntityMeta() { return entityMeta; } @@ -339,12 +368,12 @@ public class WrapperEntity implements Tickable { return metaClass.cast(entityMeta); } - public void consumeEntityMeta(@NotNull Class metaClass, Consumer consumer) { + public void consumeEntityMeta(@NotNull Class metaClass, @NotNull Consumer consumer) { T meta = getEntityMeta(metaClass); consumer.accept(meta); } - public void consumeMeta(Consumer consumer) { + public void consumeMeta(@NotNull Consumer consumer) { consumer.accept(entityMeta); } @@ -358,13 +387,14 @@ public class WrapperEntity implements Tickable { /** * Returns an unmodifiable set of the passengers of the entity. + * * @return the passengers of the entity */ - public Set getPassengers() { + public @NotNull Set getPassengers() { return Collections.unmodifiableSet(passengers); } - public WrapperEntity getRiding() { + public @Nullable WrapperEntity getRiding() { return EntityLib.getApi().getEntity(riding); } @@ -433,20 +463,22 @@ public class WrapperEntity implements Tickable { new WrapperPlayServerEntityRotation(entityId, yaw, pitch, onGround), new WrapperPlayServerEntityHeadLook(entityId, yaw) ); + this.location.setYaw(yaw); this.location.setPitch(pitch); } - public void rotateHead(Location location) { + public void rotateHead(@NotNull Location location) { rotateHead(location.getYaw(), location.getPitch()); } - public void rotateHead(WrapperEntity entity) { + public void rotateHead(@NotNull WrapperEntity entity) { rotateHead(entity.getLocation()); } public void refresh() { if (!spawned) return; + sendPacketsToViewers(entityMeta.createPacket(), createPassengerPacket()); } @@ -457,13 +489,12 @@ public class WrapperEntity implements Tickable { sendPacket(uuid, packet); sendPacket(uuid, new WrapperPlayServerBundle()); }); - } - else { + } else { viewers.forEach(uuid -> sendPacket(uuid, packet)); } } - public void sendPacketsToViewers(PacketWrapper... wrappers) { + public void sendPacketsToViewers(PacketWrapper @NotNull ... wrappers) { for (PacketWrapper wrapper : wrappers) { sendPacketToViewers(wrapper); } @@ -483,13 +514,16 @@ public class WrapperEntity implements Tickable { private static void sendPacket(UUID user, PacketWrapper wrapper) { if (wrapper == null) return; + Object channel = EntityLib.getApi().getPacketEvents().getProtocolManager().getChannel(user); if (channel == null) { if (EntityLib.getApi().getSettings().isDebugMode()) { EntityLib.getPlatform().getLogger().warning("Failed to send packet to " + user + " because the channel was null. They may be disconnected/not online."); } + return; } + EntityLib.getApi().getPacketEvents().getProtocolManager().sendPacket(channel, wrapper); } @@ -504,12 +538,14 @@ public class WrapperEntity implements Tickable { /** * Adds a passenger to the entity. The passenger will be visible to all viewers of the entity. + * * @param passenger the entity id of the passenger */ public void addPassenger(int passenger) { if (passengers.contains(passenger)) { throw new IllegalArgumentException("Passenger already exists"); } + passengers.add(passenger); sendPacketToViewers(createPassengerPacket()); WrapperEntity e = EntityLib.getApi().getEntity(passenger); @@ -533,9 +569,10 @@ public class WrapperEntity implements Tickable { /** * Adds multiple passengers to the entity. The passengers will be visible to all viewers of the entity. + * * @param passengers the entity ids of the passengers */ - public void addPassengers(int... passengers) { + public void addPassengers(int @NotNull ... passengers) { for (int passenger : passengers) { addPassenger(passenger); } @@ -543,17 +580,19 @@ public class WrapperEntity implements Tickable { /** * Adds a passenger to the entity. The passenger will be visible to all viewers of the entity. + * * @param passenger the wrapper entity passenger */ - public void addPassenger(WrapperEntity passenger) { + public void addPassenger(@NotNull WrapperEntity passenger) { addPassenger(passenger.getEntityId()); } /** * Adds multiple passengers to the entity. The passengers will be visible to all viewers of the entity. + * * @param passengers the wrapper entity passengers */ - public void addPassengers(WrapperEntity... passengers) { + public void addPassengers(WrapperEntity @NotNull ... passengers) { for (WrapperEntity passenger : passengers) { addPassenger(passenger); } @@ -561,12 +600,14 @@ public class WrapperEntity implements Tickable { /** * Removes a passenger from the entity. The passenger will be removed from the view of all viewers of the entity. + * * @param passenger the entity id of the passenger */ public void removePassenger(int passenger) { if (!passengers.contains(passenger)) { throw new IllegalArgumentException("Passenger does not exist"); } + passengers.remove(passenger); sendPacketToViewers(createPassengerPacket()); WrapperEntity e = EntityLib.getApi().getEntity(passenger); @@ -588,15 +629,16 @@ public class WrapperEntity implements Tickable { * @param passenger the passenger wrapper entity * @return true if the entity has the passenger, false otherwise */ - public boolean hasPassenger(WrapperEntity passenger) { + public boolean hasPassenger(@NotNull WrapperEntity passenger) { return hasPassenger(passenger.getEntityId()); } /** * Removes multiple passengers from the entity. The passengers will be removed from the view of all viewers of the entity. + * * @param passengers the entity ids of the passengers */ - public void removePassengers(int... passengers) { + public void removePassengers(int @NotNull ... passengers) { for (int passenger : passengers) { removePassenger(passenger); } @@ -604,17 +646,19 @@ public class WrapperEntity implements Tickable { /** * Removes a passenger from the entity. The passenger will be removed from the view of all viewers of the entity. + * * @param passenger the wrapper entity passenger */ - public void removePassenger(WrapperEntity passenger) { + public void removePassenger(@NotNull WrapperEntity passenger) { removePassenger(passenger.getEntityId()); } /** * Removes multiple passengers from the entity. The passengers will be removed from the view of all viewers of the entity. + * * @param passengers the wrapper entity passengers */ - public void removePassengers(WrapperEntity... passengers) { + public void removePassengers(WrapperEntity @NotNull ... passengers) { for (WrapperEntity passenger : passengers) { removePassenger(passenger); } @@ -631,11 +675,11 @@ public class WrapperEntity implements Tickable { return Collections.unmodifiableSet(viewers); } - public boolean hasViewer(UUID uuid) { + public boolean hasViewer(@NotNull UUID uuid) { return viewers.contains(uuid); } - public boolean hasViewer(User user) { + public boolean hasViewer(@NotNull User user) { return hasViewer(user.getUUID()); } diff --git a/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperEntityPotionEffect.java b/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperEntityPotionEffect.java new file mode 100644 index 0000000..f6c123f --- /dev/null +++ b/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperEntityPotionEffect.java @@ -0,0 +1,275 @@ +package me.tofaa.entitylib.wrapper; + +import com.github.retrooper.packetevents.protocol.nbt.NBTCompound; +import com.github.retrooper.packetevents.protocol.potion.PotionType; +import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerEntityEffect; +import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerRemoveEntityEffect; +import me.tofaa.entitylib.tick.Tickable; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; + +public class WrapperEntityPotionEffect implements Tickable { + private final WrapperLivingEntity entity; + private final Map effects = new ConcurrentHashMap<>(); + + private boolean notifyChanges = true; + private boolean ticking = true; + + public WrapperEntityPotionEffect(WrapperLivingEntity entity) { + this.entity = entity; + } + + /** + * @param type The type of the potion effect {@link com.github.retrooper.packetevents.protocol.potion.PotionTypes} + * @param amplifier The amplifier of the potion effect. The notchian client displays the number as (amplifier + 1) + * @param duration The duration of the potion effect in ticks, if set to -1 the client will display the effect as infinite + * @param ambient A + * @param visible A + * @param showIcons A + * @param factorData The factor data of the potion effect, if hasFactorData is false this will be ignored + */ + public void addPotionEffect( + PotionType type, + int amplifier, + int duration, + boolean ambient, + boolean visible, + boolean showIcons, + @Nullable NBTCompound factorData + ) { + this.effects.put(type, new WrapperPotionEffect( + type, + amplifier, + duration, + ambient, + visible, + showIcons, + factorData + )); + } + + /** + * @param type The type of the potion effect {@link com.github.retrooper.packetevents.protocol.potion.PotionTypes} + * @param amplifier The amplifier of the potion effect. The notchian client displays the number as (amplifier + 1) + * @param duration The duration of the potion effect in ticks, if set to -1 the client will display the effect as infinite + * @param flags The bit flags of the potion effect see: https://minecraft.wiki/w/Java_Edition_protocol#Entity_Effect + * @param factorData The factor data of the potion effect, if hasFactorData is false this will be ignored + */ + public void addPotionEffect( + PotionType type, + int amplifier, + int duration, + byte flags, + @Nullable NBTCompound factorData + ) { + BitSet flagsBitSet = BitSet.valueOf(new byte[]{flags}); + + boolean ambient = flagsBitSet.get(0); + boolean visible = flagsBitSet.get(1); + boolean icons = flagsBitSet.get(2); + + addPotionEffect(type, amplifier, duration, ambient, visible, icons, factorData); + } + + /** + * @param type The type of the potion effect {@link com.github.retrooper.packetevents.protocol.potion.PotionTypes} + * @param amplifier The amplifier of the potion effect. The notchian client displays the number as (amplifier + 1) + * @param duration The duration of the potion effect in ticks, if set to -1 the client will display the effect as infinite + * @param flags The bit flags of the potion effect see: https://minecraft.wiki/w/Java_Edition_protocol#Entity_Effect + * @param hasFactorData Whether the potion effect has factor data + * @param factorData The factor data of the potion effect, if hasFactorData is false this will be ignored + */ + public void addPotionEffect( + PotionType type, + int amplifier, + int duration, + byte flags, + boolean hasFactorData, + @Nullable NBTCompound factorData + ) { + addPotionEffect(type, amplifier, duration, flags, hasFactorData ? factorData : null); + } + + /** + * Adds a potion effect to the entity. + * EntityLib will not keep track of the potions you give or what you do with them, + * this simply sends the packet to the viewers of the entity. + * + * @param type The type of the potion effect {@link com.github.retrooper.packetevents.protocol.potion.PotionTypes} + * @param amplifier The amplifier of the potion effect. The notchian client displays the number as (amplifier + 1) + * @param duration The duration of the potion effect in ticks, if set to -1 the client will display the effect as infinite + * @param flags The bit flags of the potion effect see: https://minecraft.wiki/w/Java_Edition_protocol#Entity_Effect + */ + public void addPotionEffect( + PotionType type, + int amplifier, + int duration, + byte flags + ) { + addPotionEffect(type, amplifier, duration, flags, false, null); + } + + public void removePotionEffect(@NotNull PotionType potionType) { + if (this.effects.remove(potionType) != null) { + this.entity.sendPacketsToViewers(createRemoveEffectPacket(potionType)); + } + } + + public void clearPotionEffects() { + new ArrayList<>(this.effects.keySet()).forEach(this::removePotionEffect); + } + + public @NotNull List createEffectPackets() { + List packets = new ArrayList<>(); + + this.effects.forEach((potionType, effect) -> packets.add(createEffectPacket(effect))); + + return packets; + } + + public @NotNull WrapperPlayServerEntityEffect createEffectPacket(@NotNull WrapperPotionEffect effect) { + PotionType potionType = effect.getPotionType(); + int amplifier = effect.getAmplifier(); + int duration = effect.getDuration(); + boolean ambient = effect.isAmbient(); + boolean visible = effect.isVisible(); + boolean icons = effect.hasIcons(); + NBTCompound factorData = effect.getFactorData(); + long createdAt = effect.getCreatedAt(); + + int remainingDuration = duration; + if (duration != -1) { + long elapsedMillis = System.currentTimeMillis() - createdAt; + + int elapsedTicks = (int) (elapsedMillis / 50); + + remainingDuration = Math.max(duration - elapsedTicks, 0); + } + + WrapperPlayServerEntityEffect wrapperPlayServerEntityEffect = new WrapperPlayServerEntityEffect(0, null, 0, 0, (byte) 0); + + wrapperPlayServerEntityEffect.setEntityId(this.entity.getEntityId()); + wrapperPlayServerEntityEffect.setPotionType(potionType); + wrapperPlayServerEntityEffect.setEffectAmplifier(amplifier); + wrapperPlayServerEntityEffect.setEffectDurationTicks(remainingDuration); + wrapperPlayServerEntityEffect.setFactorData(factorData); + wrapperPlayServerEntityEffect.setAmbient(ambient); + wrapperPlayServerEntityEffect.setVisible(visible); + wrapperPlayServerEntityEffect.setShowIcon(icons); + + return wrapperPlayServerEntityEffect; + } + + public @NotNull WrapperPlayServerRemoveEntityEffect createRemoveEffectPacket(@NotNull PotionType potionType) { + return new WrapperPlayServerRemoveEntityEffect(this.entity.getEntityId(), potionType); + } + + public void refresh() { + if (notifyChanges) { + new ArrayList<>(this.effects.values()).forEach(effect -> { + WrapperPlayServerEntityEffect wrapperPlayServerEntityEffect = createEffectPacket(effect); + + this.entity.sendPacketsToViewers(wrapperPlayServerEntityEffect); + }); + } + } + + public boolean isNotifyingChanges() { + return notifyChanges; + } + + public void setNotifyChanges(boolean notifyChanges) { + this.notifyChanges = notifyChanges; + refresh(); + } + + @Override + public boolean isTicking() { + return this.ticking; + } + + @Override + public void setTicking(boolean ticking) { + this.ticking = ticking; + } + + @Override + public void tick(long time) { + Set toRemove = new HashSet<>(); + + this.effects.values().forEach(effect -> { + PotionType potionType = effect.getPotionType(); + + int duration = effect.getDuration(); + if (duration <= -1) return; // Infinity effect + + long createdAt = effect.getCreatedAt(); + + long elapsedMillis = time - createdAt; + + int elapsedTicks = (int) (elapsedMillis / 50); + + int remainingDuration = duration - elapsedTicks; + if (remainingDuration <= 0) toRemove.add(potionType); + }); + + toRemove.forEach(this::removePotionEffect); + } + + public static class WrapperPotionEffect { + private final PotionType potionType; + private final int amplifier; + private final int duration; + private final boolean ambient; + private final boolean visible; + private final boolean icons; + private final @Nullable NBTCompound factorData; + private final long createdAt; + + private WrapperPotionEffect(PotionType potionType, int amplifier, int duration, boolean ambient, boolean visible, boolean icons, @Nullable NBTCompound factorData) { + this.potionType = potionType; + this.amplifier = amplifier; + this.duration = duration; + this.ambient = ambient; + this.visible = visible; + this.icons = icons; + this.factorData = factorData; + this.createdAt = System.currentTimeMillis(); + } + + public PotionType getPotionType() { + return potionType; + } + + public int getAmplifier() { + return amplifier; + } + + public int getDuration() { + return duration; + } + + public boolean isAmbient() { + return ambient; + } + + public boolean isVisible() { + return visible; + } + + public boolean hasIcons() { + return icons; + } + + public @Nullable NBTCompound getFactorData() { + return factorData; + } + + public long getCreatedAt() { + return createdAt; + } + } +} diff --git a/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperLivingEntity.java b/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperLivingEntity.java index 170f3d6..465f840 100644 --- a/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperLivingEntity.java +++ b/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperLivingEntity.java @@ -4,25 +4,34 @@ import com.github.retrooper.packetevents.manager.server.ServerVersion; import com.github.retrooper.packetevents.protocol.entity.type.EntityType; import com.github.retrooper.packetevents.protocol.nbt.NBTCompound; import com.github.retrooper.packetevents.protocol.potion.PotionType; +import com.github.retrooper.packetevents.protocol.world.Location; +import com.github.retrooper.packetevents.wrapper.PacketWrapper; import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerEntityAnimation; import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerEntityEffect; +import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerEntityEquipment; import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerHurtAnimation; import me.tofaa.entitylib.EntityLib; +import me.tofaa.entitylib.container.EntityContainer; import me.tofaa.entitylib.meta.EntityMeta; import me.tofaa.entitylib.utils.VersionUtil; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.ArrayList; +import java.util.List; import java.util.UUID; -public class WrapperLivingEntity extends WrapperEntity{ - +public class WrapperLivingEntity extends WrapperEntity { private final WrapperEntityEquipment equipment; private final WrapperEntityAttributes attributes; + private final WrapperEntityPotionEffect potionEffect; public WrapperLivingEntity(int entityId, UUID uuid, EntityType entityType, EntityMeta entityMeta) { super(entityId, uuid, entityType, entityMeta); + this.equipment = new WrapperEntityEquipment(this); this.attributes = new WrapperEntityAttributes(this); + this.potionEffect = new WrapperEntityPotionEffect(this); } public WrapperLivingEntity(int entityId, UUID uuid, EntityType entityType) { @@ -36,6 +45,7 @@ public class WrapperLivingEntity extends WrapperEntity{ public WrapperLivingEntity(UUID uuid, EntityType entityType) { this(EntityLib.getPlatform().getEntityIdProvider().provide(uuid, entityType), uuid, entityType); } + public WrapperLivingEntity(EntityType entityType) { this(EntityLib.getPlatform().getEntityUuidProvider().provide(entityType), entityType); } @@ -43,60 +53,81 @@ public class WrapperLivingEntity extends WrapperEntity{ @Override public void refresh() { super.refresh(); - equipment.refresh(); - attributes.refresh(); + + this.equipment.refresh(); + this.potionEffect.refresh(); + this.attributes.refresh(); + } + + @Override + public void tick(long time) { + this.potionEffect.tick(time); + + super.tick(time); } public WrapperEntityAttributes getAttributes() { - return attributes; + return this.attributes; } + public WrapperEntityEquipment getEquipment() { + return this.equipment; + } + public WrapperEntityPotionEffect getPotionEffect() { + return this.potionEffect; + } + + public @NotNull List> createSpawnPackets() { + List> packets = new ArrayList<>(); + + packets.add(getAttributes().createPacket()); + packets.add(getEquipment().createPacket()); + packets.addAll(this.potionEffect.createEffectPackets()); + + return packets; + } /** * Adds a potion effect to the entity. * EntityLib will not keep track of the potions you give or what you do with them, * this simply sends the packet to the viewers of the entity. - * @param type The type of the potion effect {@link com.github.retrooper.packetevents.protocol.potion.PotionTypes} - * @param amplifier The amplifier of the potion effect. The notchian client displays the number as (amplifier + 1) - * @param duration The duration of the potion effect in ticks, if set to -1 the client will display the effect as infinite - * @param flags The bit flags of the potion effect see: https://wiki.vg/Protocol#Entity_Effect + * + * @param type The type of the potion effect {@link com.github.retrooper.packetevents.protocol.potion.PotionTypes} + * @param amplifier The amplifier of the potion effect. The notchian client displays the number as (amplifier + 1) + * @param duration The duration of the potion effect in ticks, if set to -1 the client will display the effect as infinite + * @param flags The bit flags of the potion effect see: + * https://minecraft.wiki/w/Java_Edition_protocol#Entity_Effect * @param hasFactorData Whether the potion effect has factor data - * @param factorData The factor data of the potion effect, if hasFactorData is false this will be ignored + * @param factorData The factor data of the potion effect, if hasFactorData is false this will be ignored */ public void addPotionEffect( - PotionType type, - int amplifier, - int duration, - byte flags, - boolean hasFactorData, - @Nullable NBTCompound factorData + PotionType type, + int amplifier, + int duration, + byte flags, + boolean hasFactorData, + @Nullable NBTCompound factorData ) { - sendPacketToViewers( - new WrapperPlayServerEntityEffect( - getEntityId(), - type, - amplifier, - duration, - flags - ) - ); + this.potionEffect.addPotionEffect(type, amplifier, duration, flags, hasFactorData, factorData); } /** * Adds a potion effect to the entity. * EntityLib will not keep track of the potions you give or what you do with them, * this simply sends the packet to the viewers of the entity. - * @param type The type of the potion effect {@link com.github.retrooper.packetevents.protocol.potion.PotionTypes} + * + * @param type The type of the potion effect {@link com.github.retrooper.packetevents.protocol.potion.PotionTypes} * @param amplifier The amplifier of the potion effect. The notchian client displays the number as (amplifier + 1) - * @param duration The duration of the potion effect in ticks, if set to -1 the client will display the effect as infinite - * @param flags The bit flags of the potion effect see: https://wiki.vg/Protocol#Entity_Effect + * @param duration The duration of the potion effect in ticks, if set to -1 the client will display the effect as infinite + * @param flags The bit flags of the potion effect see: + * https://minecraft.wiki/w/Java_Edition_protocol#Entity_Effect */ public void addPotionEffect( - PotionType type, - int amplifier, - int duration, - byte flags + PotionType type, + int amplifier, + int duration, + byte flags ) { addPotionEffect(type, amplifier, duration, flags, false, null); } @@ -124,6 +155,7 @@ public class WrapperLivingEntity extends WrapperEntity{ /** * Plays the hurt animation of the entity. + * * @param yaw The yaw of the entity when the hurt animation is played. * For any entity other than a player it's safe to simply put 0, as it's not used. * The yaw is only used on 1.19.4+. @@ -152,8 +184,4 @@ public class WrapperLivingEntity extends WrapperEntity{ new WrapperPlayServerEntityAnimation(getEntityId(), type) ); } - - public WrapperEntityEquipment getEquipment() { - return equipment; - } } From 35111c0149024926397c36036457df273571cfef Mon Sep 17 00:00:00 2001 From: Felipe Paschoal Bergamo <64669985+felipepasc@users.noreply.github.com> Date: Tue, 1 Apr 2025 11:25:33 -0300 Subject: [PATCH 07/28] fix(wrapper): streamline potion effect handling and packet creation --- .../entitylib/wrapper/WrapperEntity.java | 8 ++--- .../wrapper/WrapperEntityPotionEffect.java | 31 +++++++++++-------- 2 files changed, 20 insertions(+), 19 deletions(-) diff --git a/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperEntity.java b/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperEntity.java index ed5c58c..eb65d0c 100644 --- a/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperEntity.java +++ b/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperEntity.java @@ -93,9 +93,7 @@ public class WrapperEntity implements Tickable { if (this instanceof WrapperLivingEntity) { WrapperLivingEntity wrapperLivingEntity = (WrapperLivingEntity) this; - wrapperLivingEntity.createSpawnPackets().forEach(packetWrapper -> { - sendPacket(uuid, packetWrapper); - }); + wrapperLivingEntity.createSpawnPackets().forEach(packetWrapper -> sendPacket(uuid, packetWrapper)); } this.parent = parent; @@ -219,9 +217,7 @@ public class WrapperEntity implements Tickable { if (this instanceof WrapperLivingEntity) { WrapperLivingEntity wrapperLivingEntity = (WrapperLivingEntity) this; - wrapperLivingEntity.createSpawnPackets().forEach(packetWrapper -> { - sendPacket(uuid, packetWrapper); - }); + wrapperLivingEntity.createSpawnPackets().forEach(packetWrapper -> sendPacket(uuid, packetWrapper)); } } diff --git a/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperEntityPotionEffect.java b/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperEntityPotionEffect.java index f6c123f..50a2705 100644 --- a/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperEntityPotionEffect.java +++ b/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperEntityPotionEffect.java @@ -40,15 +40,11 @@ public class WrapperEntityPotionEffect implements Tickable { boolean showIcons, @Nullable NBTCompound factorData ) { - this.effects.put(type, new WrapperPotionEffect( - type, - amplifier, - duration, - ambient, - visible, - showIcons, - factorData - )); + WrapperPotionEffect effect = new WrapperPotionEffect(type, amplifier, duration, ambient, visible, showIcons, factorData); + + this.effects.put(type, effect); + + this.entity.sendPacketToViewers(createEffectPacket(effect)); } /** @@ -149,16 +145,25 @@ public class WrapperEntityPotionEffect implements Tickable { remainingDuration = Math.max(duration - elapsedTicks, 0); } - WrapperPlayServerEntityEffect wrapperPlayServerEntityEffect = new WrapperPlayServerEntityEffect(0, null, 0, 0, (byte) 0); + int flags = 0; + + flags |= ambient ? 1 : 0; // Bit 0 para ambient + flags |= visible ? (1 << 1) : 0; // Bit 1 para visible + flags |= icons ? (1 << 2) : 0; // Bit 2 para icons + + WrapperPlayServerEntityEffect wrapperPlayServerEntityEffect = new WrapperPlayServerEntityEffect( + 0, + null, + 0, + 0, + (byte) flags + ); wrapperPlayServerEntityEffect.setEntityId(this.entity.getEntityId()); wrapperPlayServerEntityEffect.setPotionType(potionType); wrapperPlayServerEntityEffect.setEffectAmplifier(amplifier); wrapperPlayServerEntityEffect.setEffectDurationTicks(remainingDuration); wrapperPlayServerEntityEffect.setFactorData(factorData); - wrapperPlayServerEntityEffect.setAmbient(ambient); - wrapperPlayServerEntityEffect.setVisible(visible); - wrapperPlayServerEntityEffect.setShowIcon(icons); return wrapperPlayServerEntityEffect; } From d7eda34611c2854aaac7863caac48b302c06437b Mon Sep 17 00:00:00 2001 From: Felipe Paschoal Bergamo <64669985+felipepasc@users.noreply.github.com> Date: Thu, 3 Apr 2025 00:02:49 -0300 Subject: [PATCH 08/28] feat: enhance EntityLib with packet dispatcher and server version check --- .../java/me/tofaa/entitylib/APIConfig.java | 9 +++++ .../java/me/tofaa/entitylib/EntityLibAPI.java | 8 +++-- .../me/tofaa/entitylib/meta/EntityMeta.java | 36 ++++++++++--------- .../entitylib/wrapper/WrapperEntity.java | 13 ++----- .../common/AbstractEntityLibAPI.java | 34 ++++++++++++++---- 5 files changed, 63 insertions(+), 37 deletions(-) diff --git a/api/src/main/java/me/tofaa/entitylib/APIConfig.java b/api/src/main/java/me/tofaa/entitylib/APIConfig.java index 3cba7e7..5f59c05 100644 --- a/api/src/main/java/me/tofaa/entitylib/APIConfig.java +++ b/api/src/main/java/me/tofaa/entitylib/APIConfig.java @@ -13,6 +13,7 @@ public final class APIConfig { private boolean platformLogger = false; private boolean bstats = true; private boolean forceBundle = false; + private boolean ignoreServerVersionVerify = false; public APIConfig(PacketEventsAPI packetEvents) { this.packetEvents = packetEvents; @@ -53,6 +54,11 @@ public final class APIConfig { return this; } + public @NotNull APIConfig ignoreServerVersionVerify() { + this.ignoreServerVersionVerify = true; + return this; + } + public boolean isDebugMode() { return debugMode; } @@ -83,4 +89,7 @@ public final class APIConfig { && EntityLib.getOptionalApi().get().getPacketEvents().getServerManager().getVersion().isNewerThanOrEquals(ServerVersion.V_1_19_4); } + public boolean shouldIgnoreServerVersionVerify() { + return ignoreServerVersionVerify; + } } diff --git a/api/src/main/java/me/tofaa/entitylib/EntityLibAPI.java b/api/src/main/java/me/tofaa/entitylib/EntityLibAPI.java index 663c368..4c3c66e 100644 --- a/api/src/main/java/me/tofaa/entitylib/EntityLibAPI.java +++ b/api/src/main/java/me/tofaa/entitylib/EntityLibAPI.java @@ -4,6 +4,7 @@ import com.github.retrooper.packetevents.PacketEventsAPI; import com.github.retrooper.packetevents.protocol.entity.type.EntityType; import com.github.retrooper.packetevents.protocol.player.UserProfile; import com.github.retrooper.packetevents.protocol.world.Location; +import com.github.retrooper.packetevents.wrapper.PacketWrapper; import me.tofaa.entitylib.container.EntityContainer; import me.tofaa.entitylib.tick.TickContainer; import me.tofaa.entitylib.wrapper.WrapperEntity; @@ -14,6 +15,8 @@ import org.jetbrains.annotations.Nullable; import java.util.Collection; import java.util.UUID; +import java.util.function.BiConsumer; +import java.util.function.Consumer; /** * Represents the API for EntityLib. @@ -55,7 +58,8 @@ public interface EntityLibAPI { */ void addTickContainer(@NotNull TickContainer tickContainer); - @NotNull - EntityContainer getDefaultContainer(); + @NotNull BiConsumer> getPacketDispatcher(); + + @NotNull EntityContainer getDefaultContainer(); } 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 ba03d99..d6907af 100644 --- a/api/src/main/java/me/tofaa/entitylib/meta/EntityMeta.java +++ b/api/src/main/java/me/tofaa/entitylib/meta/EntityMeta.java @@ -140,60 +140,60 @@ public class EntityMeta implements EntityMetadataProvider { } public short getAirTicks() { - return this.metadata.getIndex((byte)1, (short) 300); + return this.metadata.getIndex((byte) 1, (short) 300); } public void setAirTicks(short value) { - this.metadata.setIndex((byte)1, EntityDataTypes.SHORT, value); + this.metadata.setIndex((byte) 1, EntityDataTypes.SHORT, value); } public Component getCustomName() { - Optional component = this.metadata.getIndex((byte)2, Optional.empty()); + Optional component = this.metadata.getIndex((byte) 2, Optional.empty()); return component.orElse(null); } public void setCustomName(Component value) { - this.metadata.setIndex((byte)2, EntityDataTypes.OPTIONAL_ADV_COMPONENT, Optional.ofNullable(value)); + this.metadata.setIndex((byte) 2, EntityDataTypes.OPTIONAL_ADV_COMPONENT, Optional.ofNullable(value)); } public boolean isCustomNameVisible() { - return this.metadata.getIndex((byte)3, false); + return this.metadata.getIndex((byte) 3, false); } public void setCustomNameVisible(boolean value) { - this.metadata.setIndex((byte)3, EntityDataTypes.BOOLEAN, value); + this.metadata.setIndex((byte) 3, EntityDataTypes.BOOLEAN, value); } public boolean isSilent() { - return this.metadata.getIndex((byte)4, false); + return this.metadata.getIndex((byte) 4, false); } public void setSilent(boolean value) { - this.metadata.setIndex((byte)4, EntityDataTypes.BOOLEAN, value); + this.metadata.setIndex((byte) 4, EntityDataTypes.BOOLEAN, value); } public boolean hasNoGravity() { - return this.metadata.getIndex((byte)5, true); + return this.metadata.getIndex((byte) 5, true); } public void setHasNoGravity(boolean value) { - this.metadata.setIndex((byte)5, EntityDataTypes.BOOLEAN, value); + this.metadata.setIndex((byte) 5, EntityDataTypes.BOOLEAN, value); } public EntityPose getPose() { - return this.metadata.getIndex((byte)6, EntityPose.STANDING); + return this.metadata.getIndex((byte) 6, EntityPose.STANDING); } public void setPose(EntityPose value) { - this.metadata.setIndex((byte)6, EntityDataTypes.ENTITY_POSE, value); + this.metadata.setIndex((byte) 6, EntityDataTypes.ENTITY_POSE, value); } public int getTicksFrozenInPowderedSnow() { - return this.metadata.getIndex((byte)7, 0); + return this.metadata.getIndex((byte) 7, 0); } public void setTicksFrozenInPowderedSnow(int value) { - this.metadata.setIndex((byte)7, EntityDataTypes.INT, value); + this.metadata.setIndex((byte) 7, EntityDataTypes.INT, value); } public WrapperPlayServerEntityMetadata createPacket() { @@ -201,6 +201,7 @@ public class EntityMeta implements EntityMetadataProvider { } protected static void isVersionNewer(ServerVersion version) { + if (EntityLib.getApi().getSettings().shouldIgnoreServerVersionVerify()) return; if (EntityLib.getOptionalApi().isPresent()) { if (!EntityLib.getApi().getPacketEvents().getServerManager().getVersion().is(VersionComparison.NEWER_THAN, version)) { throw new InvalidVersionException("This method is only available for versions newer than " + version.name() + "."); @@ -228,7 +229,8 @@ public class EntityMeta implements EntityMetadataProvider { /** * Annoying java 8 not letting me do OFFSET + amount in the method call so this is a workaround - * @param value the value to offset + * + * @param value the value to offset * @param amount the amount to offset by * @return the offset value */ @@ -257,7 +259,7 @@ public class EntityMeta implements EntityMetadataProvider { } public void setMaskBit(int index, byte bit, boolean value) { - byte mask = getMask((byte)index); + byte mask = getMask((byte) index); boolean currentValue = (mask & bit) == bit; if (currentValue == value) { return; @@ -267,7 +269,7 @@ public class EntityMeta implements EntityMetadataProvider { } else { mask &= (byte) ~bit; } - setMask((byte)index, mask); + setMask((byte) index, mask); } @Override diff --git a/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperEntity.java b/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperEntity.java index eb65d0c..4206a79 100644 --- a/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperEntity.java +++ b/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperEntity.java @@ -509,18 +509,9 @@ public class WrapperEntity implements Tickable { } private static void sendPacket(UUID user, PacketWrapper wrapper) { - if (wrapper == null) return; - - Object channel = EntityLib.getApi().getPacketEvents().getProtocolManager().getChannel(user); - if (channel == null) { - if (EntityLib.getApi().getSettings().isDebugMode()) { - EntityLib.getPlatform().getLogger().warning("Failed to send packet to " + user + " because the channel was null. They may be disconnected/not online."); - } - - return; + if (wrapper != null) { + EntityLib.getApi().getPacketDispatcher().accept(user, wrapper); } - - EntityLib.getApi().getPacketEvents().getProtocolManager().sendPacket(channel, wrapper); } public boolean hasNoGravity() { diff --git a/common/src/main/java/me/tofaa/entitylib/common/AbstractEntityLibAPI.java b/common/src/main/java/me/tofaa/entitylib/common/AbstractEntityLibAPI.java index 5bb4f54..ba98c95 100644 --- a/common/src/main/java/me/tofaa/entitylib/common/AbstractEntityLibAPI.java +++ b/common/src/main/java/me/tofaa/entitylib/common/AbstractEntityLibAPI.java @@ -1,7 +1,9 @@ package me.tofaa.entitylib.common; import com.github.retrooper.packetevents.PacketEventsAPI; +import com.github.retrooper.packetevents.wrapper.PacketWrapper; import me.tofaa.entitylib.APIConfig; +import me.tofaa.entitylib.EntityLib; import me.tofaa.entitylib.EntityLibAPI; import me.tofaa.entitylib.Platform; import me.tofaa.entitylib.container.EntityContainer; @@ -10,22 +12,38 @@ import me.tofaa.entitylib.wrapper.WrapperEntity; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.*; +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.UUID; +import java.util.function.BiConsumer; public abstract class AbstractEntityLibAPI implements EntityLibAPI { - protected final Platform

platform; protected final PacketEventsAPI packetEvents; protected final APIConfig settings; protected final Collection> tickContainers; protected final EntityContainer defaultEntityContainer = EntityContainer.basic(); + protected final BiConsumer> packetDispatcher; protected AbstractEntityLibAPI(Platform

platform, APIConfig settings) { this.platform = platform; this.packetEvents = settings.getPacketEvents(); this.settings = settings; this.tickContainers = settings.shouldTickTickables() ? new HashSet<>() : Collections.emptyList(); + this.packetDispatcher = (user, wrapper) -> { + Object channel = EntityLib.getApi().getPacketEvents().getProtocolManager().getChannel(user); + if (channel == null) { + if (EntityLib.getApi().getSettings().isDebugMode()) { + EntityLib.getPlatform().getLogger().warning("Failed to send packet to " + user + " because the channel was null. They may be disconnected/not online."); + } + + return; + } + + EntityLib.getApi().getPacketEvents().getProtocolManager().sendPacket(channel, wrapper); + }; } @Override @@ -36,7 +54,6 @@ public abstract class AbstractEntityLibAPI implements EntityLibAPI { @Override public @Nullable WrapperEntity getEntity(@NotNull UUID uuid) { return defaultEntityContainer.getEntity(uuid); - } @Override @@ -49,9 +66,8 @@ public abstract class AbstractEntityLibAPI implements EntityLibAPI { return defaultEntityContainer; } - @NotNull @Override - public APIConfig getSettings() { + public @NotNull APIConfig getSettings() { return settings; } @@ -60,9 +76,13 @@ public abstract class AbstractEntityLibAPI implements EntityLibAPI { return packetEvents; } - @NotNull @Override - public Collection> getTickContainers() { + public @NotNull BiConsumer> getPacketDispatcher() { + return packetDispatcher; + } + + @Override + public @NotNull Collection> getTickContainers() { return tickContainers; } } From 9e7ecf310ea0f0e3cf650eda036187a2983d6857 Mon Sep 17 00:00:00 2001 From: Felipe Paschoal Bergamo <64669985+felipepasc@users.noreply.github.com> Date: Thu, 3 Apr 2025 00:03:40 -0300 Subject: [PATCH 09/28] feat(api): add setPacketDispatcher method to EntityLibAPI --- api/src/main/java/me/tofaa/entitylib/EntityLibAPI.java | 2 ++ .../me/tofaa/entitylib/common/AbstractEntityLibAPI.java | 8 +++++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/api/src/main/java/me/tofaa/entitylib/EntityLibAPI.java b/api/src/main/java/me/tofaa/entitylib/EntityLibAPI.java index 4c3c66e..44614fc 100644 --- a/api/src/main/java/me/tofaa/entitylib/EntityLibAPI.java +++ b/api/src/main/java/me/tofaa/entitylib/EntityLibAPI.java @@ -60,6 +60,8 @@ public interface EntityLibAPI { @NotNull BiConsumer> getPacketDispatcher(); + void setPacketDispatcher(@NotNull BiConsumer> packetDispatcher); + @NotNull EntityContainer getDefaultContainer(); } diff --git a/common/src/main/java/me/tofaa/entitylib/common/AbstractEntityLibAPI.java b/common/src/main/java/me/tofaa/entitylib/common/AbstractEntityLibAPI.java index ba98c95..d8577c9 100644 --- a/common/src/main/java/me/tofaa/entitylib/common/AbstractEntityLibAPI.java +++ b/common/src/main/java/me/tofaa/entitylib/common/AbstractEntityLibAPI.java @@ -25,7 +25,8 @@ public abstract class AbstractEntityLibAPI implements EntityLibAPI { protected final APIConfig settings; protected final Collection> tickContainers; protected final EntityContainer defaultEntityContainer = EntityContainer.basic(); - protected final BiConsumer> packetDispatcher; + + protected BiConsumer> packetDispatcher; protected AbstractEntityLibAPI(Platform

platform, APIConfig settings) { this.platform = platform; @@ -81,6 +82,11 @@ public abstract class AbstractEntityLibAPI implements EntityLibAPI { return packetDispatcher; } + @Override + public void setPacketDispatcher(@NotNull BiConsumer> packetDispatcher) { + this.packetDispatcher = packetDispatcher; + } + @Override public @NotNull Collection> getTickContainers() { return tickContainers; From d9aae45571d0536107860d66c37318dc63311e77 Mon Sep 17 00:00:00 2001 From: Tofaa2 Date: Wed, 9 Apr 2025 21:35:48 +0400 Subject: [PATCH 10/28] idk how to fix this --- .../java/me/tofaa/entitylib/meta/mobs/golem/ShulkerMeta.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 index b41887c..67f5132 100644 --- 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 @@ -23,11 +23,11 @@ public class ShulkerMeta extends MobMeta { } public Direction getAttachFace() { - return super.metadata.getIndex(OFFSET, Direction.DOWN); + return super.metadata.getIndex((byte)16, Direction.DOWN); } public void setAttachFace(Direction value) { - super.metadata.setIndex(OFFSET, EntityDataTypes.INT, value.ordinal()); + super.metadata.setIndex((byte)16, EntityDataTypes.INT, value.ordinal()); } public byte getShieldHeight() { From 5a5c7c8dc19ddc8b25d66e9d649c73bf0250c23b Mon Sep 17 00:00:00 2001 From: steve <50219120+steveb05@users.noreply.github.com> Date: Wed, 30 Apr 2025 13:54:54 +0200 Subject: [PATCH 11/28] fix: correct BaseHorseMeta inheritance and remove non-functional owner methods Inheriting from MobMeta caused incorrect metadata offsets for horses, leading to client disconnections when metadata packets were sent. Vanilla horses don't synchronize Owner UUID via metadata, making the previous owner methods non-functional client-side. Changing inheritance to AgeableMeta also enables baby horse functionality. --- .../meta/mobs/horse/BaseHorseMeta.java | 21 ++++--------------- 1 file changed, 4 insertions(+), 17 deletions(-) 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 index 1dd8637..f39cd7a 100644 --- 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 @@ -1,16 +1,12 @@ 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 me.tofaa.entitylib.meta.types.AgeableMeta; -import java.util.Optional; -import java.util.UUID; +public abstract class BaseHorseMeta extends AgeableMeta { -public abstract class BaseHorseMeta extends MobMeta { - - public static final byte OFFSET = MobMeta.MAX_OFFSET; - public static final byte MAX_OFFSET = OFFSET + 2; + public static final byte OFFSET = AgeableMeta.MAX_OFFSET; + public static final byte MAX_OFFSET = OFFSET + 1; private final static byte TAMED_BIT = 0x02; private final static byte SADDLED_BIT = 0x04; @@ -70,13 +66,4 @@ public abstract class BaseHorseMeta extends MobMeta { 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)); - } - } From 74871b38bbd222ba3b4bdc66b088d6ce11612e39 Mon Sep 17 00:00:00 2001 From: Bram Date: Thu, 1 May 2025 11:20:38 +0200 Subject: [PATCH 12/28] Fixed: Compile errors due to PacketEvents not being present during the test build phase --- api/build.gradle.kts | 1 + 1 file changed, 1 insertion(+) diff --git a/api/build.gradle.kts b/api/build.gradle.kts index 43334d1..bc0b925 100644 --- a/api/build.gradle.kts +++ b/api/build.gradle.kts @@ -9,6 +9,7 @@ dependencies { compileOnly(libs.bundles.adventure) compileOnly(libs.packetevents.api) + testCompileOnly(libs.packetevents.api) } tasks { From 9032d3305896eb7212322132702a45ae9ce9a3c0 Mon Sep 17 00:00:00 2001 From: Tofaa2 Date: Thu, 1 May 2025 13:41:36 +0400 Subject: [PATCH 13/28] GCI make create release step only available on head --- .github/workflows/dev-build-release.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/dev-build-release.yml b/.github/workflows/dev-build-release.yml index 237e53d..e0ba3da 100644 --- a/.github/workflows/dev-build-release.yml +++ b/.github/workflows/dev-build-release.yml @@ -39,6 +39,7 @@ jobs: run: chmod +x ./gradlew && ./gradlew build - name: Create Release + if: github.ref != 'refs/heads/master' uses: softprops/action-gh-release@v2 with: name: '${{ github.ref_name }}: ${{ github.event.head_commit.message }} (${{ github.sha }})' From 2e05530f363c190734c6cab15b5ff54c9f806ad6 Mon Sep 17 00:00:00 2001 From: Felipe Paschoal Bergamo <64669985+felipepasc@users.noreply.github.com> Date: Tue, 3 Jun 2025 18:37:58 -0300 Subject: [PATCH 14/28] Cleaned up the WrapperEntityPotionEffect class by removing --- .../java/me/tofaa/entitylib/APIConfig.java | 10 ---- .../me/tofaa/entitylib/meta/EntityMeta.java | 2 +- .../meta/display/TextDisplayMeta.java | 1 - .../wrapper/WrapperEntityPotionEffect.java | 55 +------------------ .../wrapper/WrapperLivingEntity.java | 9 +-- 5 files changed, 4 insertions(+), 73 deletions(-) diff --git a/api/src/main/java/me/tofaa/entitylib/APIConfig.java b/api/src/main/java/me/tofaa/entitylib/APIConfig.java index 5f59c05..4394618 100644 --- a/api/src/main/java/me/tofaa/entitylib/APIConfig.java +++ b/api/src/main/java/me/tofaa/entitylib/APIConfig.java @@ -13,7 +13,6 @@ public final class APIConfig { private boolean platformLogger = false; private boolean bstats = true; private boolean forceBundle = false; - private boolean ignoreServerVersionVerify = false; public APIConfig(PacketEventsAPI packetEvents) { this.packetEvents = packetEvents; @@ -54,11 +53,6 @@ public final class APIConfig { return this; } - public @NotNull APIConfig ignoreServerVersionVerify() { - this.ignoreServerVersionVerify = true; - return this; - } - public boolean isDebugMode() { return debugMode; } @@ -88,8 +82,4 @@ public final class APIConfig { && EntityLib.getOptionalApi().isPresent() && EntityLib.getOptionalApi().get().getPacketEvents().getServerManager().getVersion().isNewerThanOrEquals(ServerVersion.V_1_19_4); } - - public boolean shouldIgnoreServerVersionVerify() { - return ignoreServerVersionVerify; - } } 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 d6907af..8f99e4b 100644 --- a/api/src/main/java/me/tofaa/entitylib/meta/EntityMeta.java +++ b/api/src/main/java/me/tofaa/entitylib/meta/EntityMeta.java @@ -201,12 +201,12 @@ public class EntityMeta implements EntityMetadataProvider { } protected static void isVersionNewer(ServerVersion version) { - if (EntityLib.getApi().getSettings().shouldIgnoreServerVersionVerify()) return; if (EntityLib.getOptionalApi().isPresent()) { if (!EntityLib.getApi().getPacketEvents().getServerManager().getVersion().is(VersionComparison.NEWER_THAN, version)) { throw new InvalidVersionException("This method is only available for versions newer than " + version.name() + "."); } } + if (!PacketEvents.getAPI().getServerManager().getVersion().is(VersionComparison.NEWER_THAN, version)) { throw new InvalidVersionException("This method is only available for versions newer than " + version.name() + "."); } 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 index 85ef64e..7fb8f71 100644 --- a/api/src/main/java/me/tofaa/entitylib/meta/display/TextDisplayMeta.java +++ b/api/src/main/java/me/tofaa/entitylib/meta/display/TextDisplayMeta.java @@ -19,7 +19,6 @@ public class TextDisplayMeta extends AbstractDisplayMeta { super(entityId, metadata); } - public Component getText() { return metadata.getIndex(OFFSET, Component.empty()); } diff --git a/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperEntityPotionEffect.java b/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperEntityPotionEffect.java index 50a2705..2d47629 100644 --- a/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperEntityPotionEffect.java +++ b/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperEntityPotionEffect.java @@ -4,19 +4,17 @@ import com.github.retrooper.packetevents.protocol.nbt.NBTCompound; import com.github.retrooper.packetevents.protocol.potion.PotionType; import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerEntityEffect; import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerRemoveEntityEffect; -import me.tofaa.entitylib.tick.Tickable; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.*; import java.util.concurrent.ConcurrentHashMap; -public class WrapperEntityPotionEffect implements Tickable { +public class WrapperEntityPotionEffect { private final WrapperLivingEntity entity; private final Map effects = new ConcurrentHashMap<>(); private boolean notifyChanges = true; - private boolean ticking = true; public WrapperEntityPotionEffect(WrapperLivingEntity entity) { this.entity = entity; @@ -134,16 +132,6 @@ public class WrapperEntityPotionEffect implements Tickable { boolean visible = effect.isVisible(); boolean icons = effect.hasIcons(); NBTCompound factorData = effect.getFactorData(); - long createdAt = effect.getCreatedAt(); - - int remainingDuration = duration; - if (duration != -1) { - long elapsedMillis = System.currentTimeMillis() - createdAt; - - int elapsedTicks = (int) (elapsedMillis / 50); - - remainingDuration = Math.max(duration - elapsedTicks, 0); - } int flags = 0; @@ -162,7 +150,7 @@ public class WrapperEntityPotionEffect implements Tickable { wrapperPlayServerEntityEffect.setEntityId(this.entity.getEntityId()); wrapperPlayServerEntityEffect.setPotionType(potionType); wrapperPlayServerEntityEffect.setEffectAmplifier(amplifier); - wrapperPlayServerEntityEffect.setEffectDurationTicks(remainingDuration); + wrapperPlayServerEntityEffect.setEffectDurationTicks(duration); wrapperPlayServerEntityEffect.setFactorData(factorData); return wrapperPlayServerEntityEffect; @@ -191,39 +179,6 @@ public class WrapperEntityPotionEffect implements Tickable { refresh(); } - @Override - public boolean isTicking() { - return this.ticking; - } - - @Override - public void setTicking(boolean ticking) { - this.ticking = ticking; - } - - @Override - public void tick(long time) { - Set toRemove = new HashSet<>(); - - this.effects.values().forEach(effect -> { - PotionType potionType = effect.getPotionType(); - - int duration = effect.getDuration(); - if (duration <= -1) return; // Infinity effect - - long createdAt = effect.getCreatedAt(); - - long elapsedMillis = time - createdAt; - - int elapsedTicks = (int) (elapsedMillis / 50); - - int remainingDuration = duration - elapsedTicks; - if (remainingDuration <= 0) toRemove.add(potionType); - }); - - toRemove.forEach(this::removePotionEffect); - } - public static class WrapperPotionEffect { private final PotionType potionType; private final int amplifier; @@ -232,7 +187,6 @@ public class WrapperEntityPotionEffect implements Tickable { private final boolean visible; private final boolean icons; private final @Nullable NBTCompound factorData; - private final long createdAt; private WrapperPotionEffect(PotionType potionType, int amplifier, int duration, boolean ambient, boolean visible, boolean icons, @Nullable NBTCompound factorData) { this.potionType = potionType; @@ -242,7 +196,6 @@ public class WrapperEntityPotionEffect implements Tickable { this.visible = visible; this.icons = icons; this.factorData = factorData; - this.createdAt = System.currentTimeMillis(); } public PotionType getPotionType() { @@ -272,9 +225,5 @@ public class WrapperEntityPotionEffect implements Tickable { public @Nullable NBTCompound getFactorData() { return factorData; } - - public long getCreatedAt() { - return createdAt; - } } } diff --git a/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperLivingEntity.java b/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperLivingEntity.java index 465f840..290e557 100644 --- a/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperLivingEntity.java +++ b/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperLivingEntity.java @@ -59,13 +59,6 @@ public class WrapperLivingEntity extends WrapperEntity { this.attributes.refresh(); } - @Override - public void tick(long time) { - this.potionEffect.tick(time); - - super.tick(time); - } - public WrapperEntityAttributes getAttributes() { return this.attributes; } @@ -83,7 +76,7 @@ public class WrapperLivingEntity extends WrapperEntity { packets.add(getAttributes().createPacket()); packets.add(getEquipment().createPacket()); - packets.addAll(this.potionEffect.createEffectPackets()); + packets.addAll(getPotionEffect().createEffectPackets()); return packets; } From 1fc7a00ec73b727939f84317de1bd8dcaa7a47d7 Mon Sep 17 00:00:00 2001 From: Felipe Paschoal Bergamo <64669985+felipepasc@users.noreply.github.com> Date: Tue, 3 Jun 2025 18:53:19 -0300 Subject: [PATCH 15/28] fix: errors --- .../java/me/tofaa/entitylib/APIConfig.java | 1 + .../java/me/tofaa/entitylib/EntityLibAPI.java | 15 ++------ .../me/tofaa/entitylib/meta/EntityMeta.java | 35 +++++++++---------- .../meta/display/TextDisplayMeta.java | 1 + .../entitylib/wrapper/WrapperEntity.java | 13 +++++-- .../wrapper/WrapperEntityPotionEffect.java | 2 +- .../common/AbstractEntityLibAPI.java | 28 --------------- 7 files changed, 33 insertions(+), 62 deletions(-) diff --git a/api/src/main/java/me/tofaa/entitylib/APIConfig.java b/api/src/main/java/me/tofaa/entitylib/APIConfig.java index 4394618..3cba7e7 100644 --- a/api/src/main/java/me/tofaa/entitylib/APIConfig.java +++ b/api/src/main/java/me/tofaa/entitylib/APIConfig.java @@ -82,4 +82,5 @@ public final class APIConfig { && EntityLib.getOptionalApi().isPresent() && EntityLib.getOptionalApi().get().getPacketEvents().getServerManager().getVersion().isNewerThanOrEquals(ServerVersion.V_1_19_4); } + } diff --git a/api/src/main/java/me/tofaa/entitylib/EntityLibAPI.java b/api/src/main/java/me/tofaa/entitylib/EntityLibAPI.java index 44614fc..c6041f7 100644 --- a/api/src/main/java/me/tofaa/entitylib/EntityLibAPI.java +++ b/api/src/main/java/me/tofaa/entitylib/EntityLibAPI.java @@ -1,22 +1,14 @@ package me.tofaa.entitylib; import com.github.retrooper.packetevents.PacketEventsAPI; -import com.github.retrooper.packetevents.protocol.entity.type.EntityType; -import com.github.retrooper.packetevents.protocol.player.UserProfile; -import com.github.retrooper.packetevents.protocol.world.Location; -import com.github.retrooper.packetevents.wrapper.PacketWrapper; import me.tofaa.entitylib.container.EntityContainer; import me.tofaa.entitylib.tick.TickContainer; import me.tofaa.entitylib.wrapper.WrapperEntity; -import me.tofaa.entitylib.wrapper.WrapperPlayer; -import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.Collection; import java.util.UUID; -import java.util.function.BiConsumer; -import java.util.function.Consumer; /** * Represents the API for EntityLib. @@ -58,10 +50,7 @@ public interface EntityLibAPI { */ void addTickContainer(@NotNull TickContainer tickContainer); - @NotNull BiConsumer> getPacketDispatcher(); - - void setPacketDispatcher(@NotNull BiConsumer> packetDispatcher); - - @NotNull EntityContainer getDefaultContainer(); + @NotNull + EntityContainer getDefaultContainer(); } 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 8f99e4b..b628c8a 100644 --- a/api/src/main/java/me/tofaa/entitylib/meta/EntityMeta.java +++ b/api/src/main/java/me/tofaa/entitylib/meta/EntityMeta.java @@ -140,60 +140,60 @@ public class EntityMeta implements EntityMetadataProvider { } public short getAirTicks() { - return this.metadata.getIndex((byte) 1, (short) 300); + return this.metadata.getIndex((byte)1, (short) 300); } public void setAirTicks(short value) { - this.metadata.setIndex((byte) 1, EntityDataTypes.SHORT, value); + this.metadata.setIndex((byte)1, EntityDataTypes.SHORT, value); } public Component getCustomName() { - Optional component = this.metadata.getIndex((byte) 2, Optional.empty()); + Optional component = this.metadata.getIndex((byte)2, Optional.empty()); return component.orElse(null); } public void setCustomName(Component value) { - this.metadata.setIndex((byte) 2, EntityDataTypes.OPTIONAL_ADV_COMPONENT, Optional.ofNullable(value)); + this.metadata.setIndex((byte)2, EntityDataTypes.OPTIONAL_ADV_COMPONENT, Optional.ofNullable(value)); } public boolean isCustomNameVisible() { - return this.metadata.getIndex((byte) 3, false); + return this.metadata.getIndex((byte)3, false); } public void setCustomNameVisible(boolean value) { - this.metadata.setIndex((byte) 3, EntityDataTypes.BOOLEAN, value); + this.metadata.setIndex((byte)3, EntityDataTypes.BOOLEAN, value); } public boolean isSilent() { - return this.metadata.getIndex((byte) 4, false); + return this.metadata.getIndex((byte)4, false); } public void setSilent(boolean value) { - this.metadata.setIndex((byte) 4, EntityDataTypes.BOOLEAN, value); + this.metadata.setIndex((byte)4, EntityDataTypes.BOOLEAN, value); } public boolean hasNoGravity() { - return this.metadata.getIndex((byte) 5, true); + return this.metadata.getIndex((byte)5, true); } public void setHasNoGravity(boolean value) { - this.metadata.setIndex((byte) 5, EntityDataTypes.BOOLEAN, value); + this.metadata.setIndex((byte)5, EntityDataTypes.BOOLEAN, value); } public EntityPose getPose() { - return this.metadata.getIndex((byte) 6, EntityPose.STANDING); + return this.metadata.getIndex((byte)6, EntityPose.STANDING); } public void setPose(EntityPose value) { - this.metadata.setIndex((byte) 6, EntityDataTypes.ENTITY_POSE, value); + this.metadata.setIndex((byte)6, EntityDataTypes.ENTITY_POSE, value); } public int getTicksFrozenInPowderedSnow() { - return this.metadata.getIndex((byte) 7, 0); + return this.metadata.getIndex((byte)7, 0); } public void setTicksFrozenInPowderedSnow(int value) { - this.metadata.setIndex((byte) 7, EntityDataTypes.INT, value); + this.metadata.setIndex((byte)7, EntityDataTypes.INT, value); } public WrapperPlayServerEntityMetadata createPacket() { @@ -206,7 +206,6 @@ public class EntityMeta implements EntityMetadataProvider { throw new InvalidVersionException("This method is only available for versions newer than " + version.name() + "."); } } - if (!PacketEvents.getAPI().getServerManager().getVersion().is(VersionComparison.NEWER_THAN, version)) { throw new InvalidVersionException("This method is only available for versions newer than " + version.name() + "."); } @@ -230,7 +229,7 @@ public class EntityMeta implements EntityMetadataProvider { /** * Annoying java 8 not letting me do OFFSET + amount in the method call so this is a workaround * - * @param value the value to offset + * @param value the value to offset * @param amount the amount to offset by * @return the offset value */ @@ -259,7 +258,7 @@ public class EntityMeta implements EntityMetadataProvider { } public void setMaskBit(int index, byte bit, boolean value) { - byte mask = getMask((byte) index); + byte mask = getMask((byte)index); boolean currentValue = (mask & bit) == bit; if (currentValue == value) { return; @@ -269,7 +268,7 @@ public class EntityMeta implements EntityMetadataProvider { } else { mask &= (byte) ~bit; } - setMask((byte) index, mask); + setMask((byte)index, mask); } @Override 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 index 7fb8f71..85ef64e 100644 --- a/api/src/main/java/me/tofaa/entitylib/meta/display/TextDisplayMeta.java +++ b/api/src/main/java/me/tofaa/entitylib/meta/display/TextDisplayMeta.java @@ -19,6 +19,7 @@ public class TextDisplayMeta extends AbstractDisplayMeta { super(entityId, metadata); } + public Component getText() { return metadata.getIndex(OFFSET, Component.empty()); } diff --git a/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperEntity.java b/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperEntity.java index 4206a79..eb65d0c 100644 --- a/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperEntity.java +++ b/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperEntity.java @@ -509,9 +509,18 @@ public class WrapperEntity implements Tickable { } private static void sendPacket(UUID user, PacketWrapper wrapper) { - if (wrapper != null) { - EntityLib.getApi().getPacketDispatcher().accept(user, wrapper); + if (wrapper == null) return; + + Object channel = EntityLib.getApi().getPacketEvents().getProtocolManager().getChannel(user); + if (channel == null) { + if (EntityLib.getApi().getSettings().isDebugMode()) { + EntityLib.getPlatform().getLogger().warning("Failed to send packet to " + user + " because the channel was null. They may be disconnected/not online."); + } + + return; } + + EntityLib.getApi().getPacketEvents().getProtocolManager().sendPacket(channel, wrapper); } public boolean hasNoGravity() { diff --git a/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperEntityPotionEffect.java b/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperEntityPotionEffect.java index 2d47629..eecc52d 100644 --- a/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperEntityPotionEffect.java +++ b/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperEntityPotionEffect.java @@ -165,7 +165,7 @@ public class WrapperEntityPotionEffect { new ArrayList<>(this.effects.values()).forEach(effect -> { WrapperPlayServerEntityEffect wrapperPlayServerEntityEffect = createEffectPacket(effect); - this.entity.sendPacketsToViewers(wrapperPlayServerEntityEffect); + this.entity.sendPacketToViewers(wrapperPlayServerEntityEffect); }); } } diff --git a/common/src/main/java/me/tofaa/entitylib/common/AbstractEntityLibAPI.java b/common/src/main/java/me/tofaa/entitylib/common/AbstractEntityLibAPI.java index d8577c9..bfee9b4 100644 --- a/common/src/main/java/me/tofaa/entitylib/common/AbstractEntityLibAPI.java +++ b/common/src/main/java/me/tofaa/entitylib/common/AbstractEntityLibAPI.java @@ -1,9 +1,7 @@ package me.tofaa.entitylib.common; import com.github.retrooper.packetevents.PacketEventsAPI; -import com.github.retrooper.packetevents.wrapper.PacketWrapper; import me.tofaa.entitylib.APIConfig; -import me.tofaa.entitylib.EntityLib; import me.tofaa.entitylib.EntityLibAPI; import me.tofaa.entitylib.Platform; import me.tofaa.entitylib.container.EntityContainer; @@ -16,8 +14,6 @@ import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.UUID; -import java.util.function.BiConsumer; - public abstract class AbstractEntityLibAPI implements EntityLibAPI { protected final Platform

platform; @@ -26,25 +22,11 @@ public abstract class AbstractEntityLibAPI implements EntityLibAPI { protected final Collection> tickContainers; protected final EntityContainer defaultEntityContainer = EntityContainer.basic(); - protected BiConsumer> packetDispatcher; - protected AbstractEntityLibAPI(Platform

platform, APIConfig settings) { this.platform = platform; this.packetEvents = settings.getPacketEvents(); this.settings = settings; this.tickContainers = settings.shouldTickTickables() ? new HashSet<>() : Collections.emptyList(); - this.packetDispatcher = (user, wrapper) -> { - Object channel = EntityLib.getApi().getPacketEvents().getProtocolManager().getChannel(user); - if (channel == null) { - if (EntityLib.getApi().getSettings().isDebugMode()) { - EntityLib.getPlatform().getLogger().warning("Failed to send packet to " + user + " because the channel was null. They may be disconnected/not online."); - } - - return; - } - - EntityLib.getApi().getPacketEvents().getProtocolManager().sendPacket(channel, wrapper); - }; } @Override @@ -77,16 +59,6 @@ public abstract class AbstractEntityLibAPI implements EntityLibAPI { return packetEvents; } - @Override - public @NotNull BiConsumer> getPacketDispatcher() { - return packetDispatcher; - } - - @Override - public void setPacketDispatcher(@NotNull BiConsumer> packetDispatcher) { - this.packetDispatcher = packetDispatcher; - } - @Override public @NotNull Collection> getTickContainers() { return tickContainers; From 26cccce9a8d2a05e421999206fce70dc1699e3c7 Mon Sep 17 00:00:00 2001 From: Felipe Paschoal Bergamo <64669985+felipepasc@users.noreply.github.com> Date: Tue, 3 Jun 2025 18:54:38 -0300 Subject: [PATCH 16/28] fix(wrapper): refactor spawn packet sending method --- api/src/main/java/me/tofaa/entitylib/wrapper/WrapperEntity.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperEntity.java b/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperEntity.java index eb65d0c..e3e7041 100644 --- a/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperEntity.java +++ b/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperEntity.java @@ -93,7 +93,7 @@ public class WrapperEntity implements Tickable { if (this instanceof WrapperLivingEntity) { WrapperLivingEntity wrapperLivingEntity = (WrapperLivingEntity) this; - wrapperLivingEntity.createSpawnPackets().forEach(packetWrapper -> sendPacket(uuid, packetWrapper)); + wrapperLivingEntity.createSpawnPackets().forEach(this::sendPacketsToViewers); } this.parent = parent; From e89c0255457a9b802637da33b632224af8007425 Mon Sep 17 00:00:00 2001 From: Felipe Paschoal Bergamo <64669985+felipepasc@users.noreply.github.com> Date: Sat, 14 Jun 2025 02:12:43 -0300 Subject: [PATCH 17/28] fix(meta): remove ThrownTridentMeta registration from registry POTION --- .../main/java/me/tofaa/entitylib/meta/MetaConverterRegistry.java | 1 - 1 file changed, 1 deletion(-) diff --git a/api/src/main/java/me/tofaa/entitylib/meta/MetaConverterRegistry.java b/api/src/main/java/me/tofaa/entitylib/meta/MetaConverterRegistry.java index 96ebf30..ed8c106 100644 --- a/api/src/main/java/me/tofaa/entitylib/meta/MetaConverterRegistry.java +++ b/api/src/main/java/me/tofaa/entitylib/meta/MetaConverterRegistry.java @@ -124,7 +124,6 @@ final class MetaConverterRegistry { put(PILLAGER, PillagerMeta.class, PillagerMeta::new); put(PLAYER, PlayerMeta.class, PlayerMeta::new); put(POLAR_BEAR, PolarBearMeta.class, PolarBearMeta::new); - put(POTION, ThrownTridentMeta.class, ThrownTridentMeta::new); put(PRIMED_TNT, PrimedTntMeta.class, PrimedTntMeta::new); put(PUFFERFISH, PufferFishMeta.class, PufferFishMeta::new); put(RABBIT, RabbitMeta.class, RabbitMeta::new); From 8478e87a38ce369bc2841fbe61fe8a7f2b72d5d5 Mon Sep 17 00:00:00 2001 From: huanmeng-qwq <1871735932@qq.com> Date: Tue, 8 Jul 2025 02:00:05 +0800 Subject: [PATCH 18/28] fix: correct player spawn in 1.20.1- --- .../entitylib/wrapper/WrapperEntity.java | 14 ++------- .../entitylib/wrapper/WrapperPlayer.java | 30 +++++++++++++++---- 2 files changed, 26 insertions(+), 18 deletions(-) diff --git a/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperEntity.java b/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperEntity.java index e3e7041..40c8de9 100644 --- a/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperEntity.java +++ b/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperEntity.java @@ -77,17 +77,7 @@ public class WrapperEntity implements Tickable { this.spawned = true; sendPacketsToViewers( - new WrapperPlayServerSpawnEntity( - entityId, - Optional.of(this.uuid), - entityType, - location.getPosition(), - location.getPitch(), - location.getYaw(), - location.getYaw(), - getObjectData(), - createVeloPacket() - ), + createSpawnPacket(), entityMeta.createPacket() ); @@ -238,7 +228,7 @@ public class WrapperEntity implements Tickable { sendPacketToViewers(new WrapperPlayServerSystemChatMessage(true, message)); } - protected WrapperPlayServerSpawnEntity createSpawnPacket() { + protected PacketWrapper createSpawnPacket() { return new WrapperPlayServerSpawnEntity( entityId, Optional.of(this.uuid), diff --git a/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperPlayer.java b/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperPlayer.java index ad4e0cd..d5b020f 100644 --- a/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperPlayer.java +++ b/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperPlayer.java @@ -1,17 +1,22 @@ package me.tofaa.entitylib.wrapper; +import com.github.retrooper.packetevents.manager.server.ServerVersion; import com.github.retrooper.packetevents.protocol.entity.type.EntityTypes; -import com.github.retrooper.packetevents.protocol.player.*; -import com.github.retrooper.packetevents.protocol.world.Location; -import com.github.retrooper.packetevents.util.Vector3d; +import com.github.retrooper.packetevents.protocol.player.GameMode; +import com.github.retrooper.packetevents.protocol.player.TextureProperty; +import com.github.retrooper.packetevents.protocol.player.UserProfile; import com.github.retrooper.packetevents.wrapper.PacketWrapper; -import com.github.retrooper.packetevents.wrapper.play.server.*; +import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerDestroyEntities; +import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerPlayerInfoRemove; +import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerPlayerInfoUpdate; +import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerSpawnPlayer; import me.tofaa.entitylib.EntityLib; import me.tofaa.entitylib.meta.EntityMeta; +import java.util.EnumSet; +import java.util.List; +import java.util.UUID; import net.kyori.adventure.text.Component; -import java.util.*; - public class WrapperPlayer extends WrapperLivingEntity { private UserProfile profile; @@ -25,6 +30,19 @@ public class WrapperPlayer extends WrapperLivingEntity { this.profile = profile; } + @Override + protected PacketWrapper createSpawnPacket() { + if (EntityLib.getApi().getPacketEvents().getServerManager().getVersion().isOlderThanOrEquals(ServerVersion.V_1_20_1)) { + return new WrapperPlayServerSpawnPlayer( + getEntityId(), + profile.getUUID(), + getLocation(), + getEntityMeta().entityData() + ); + } + return super.createSpawnPacket(); + } + public WrapperPlayServerPlayerInfoUpdate tabListPacket() { EnumSet actions = EnumSet.of( WrapperPlayServerPlayerInfoUpdate.Action.ADD_PLAYER, From 8bc8bfb76a8926f3cf5443276ab4aab21da2a91c Mon Sep 17 00:00:00 2001 From: huanmeng-qwq <1871735932@qq.com> Date: Tue, 8 Jul 2025 02:35:47 +0800 Subject: [PATCH 19/28] feat: Add rotation packet handling after player spawn. --- .../me/tofaa/entitylib/wrapper/WrapperPlayer.java | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperPlayer.java b/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperPlayer.java index d5b020f..d50a91b 100644 --- a/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperPlayer.java +++ b/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperPlayer.java @@ -7,6 +7,8 @@ import com.github.retrooper.packetevents.protocol.player.TextureProperty; import com.github.retrooper.packetevents.protocol.player.UserProfile; import com.github.retrooper.packetevents.wrapper.PacketWrapper; import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerDestroyEntities; +import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerEntityHeadLook; +import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerEntityRotation; import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerPlayerInfoRemove; import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerPlayerInfoUpdate; import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerSpawnPlayer; @@ -16,6 +18,7 @@ import java.util.EnumSet; import java.util.List; import java.util.UUID; import net.kyori.adventure.text.Component; +import org.jetbrains.annotations.NotNull; public class WrapperPlayer extends WrapperLivingEntity { @@ -43,6 +46,14 @@ public class WrapperPlayer extends WrapperLivingEntity { return super.createSpawnPacket(); } + @Override + public @NotNull List> createSpawnPackets() { + final List> packets = super.createSpawnPackets(); + packets.add(new WrapperPlayServerEntityRotation(getEntityId(), getYaw(), getPitch(), isOnGround())); + packets.add(new WrapperPlayServerEntityHeadLook(getEntityId(), getYaw())); + return packets; + } + public WrapperPlayServerPlayerInfoUpdate tabListPacket() { EnumSet actions = EnumSet.of( WrapperPlayServerPlayerInfoUpdate.Action.ADD_PLAYER, From a4ce05886de33ae52a973a80e403d5638a346f50 Mon Sep 17 00:00:00 2001 From: Felipe Paschoal Bergamo <64669985+felipepasc@users.noreply.github.com> Date: Tue, 15 Jul 2025 22:40:24 -0300 Subject: [PATCH 20/28] fix(meta): update EntityData type to be generic in EntityMeta and Metadata --- .../java/me/tofaa/entitylib/meta/EntityMeta.java | 4 ++-- .../java/me/tofaa/entitylib/meta/Metadata.java | 14 +++++++------- libs.versions.toml | 8 ++++---- 3 files changed, 13 insertions(+), 13 deletions(-) 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 b628c8a..daa4379 100644 --- a/api/src/main/java/me/tofaa/entitylib/meta/EntityMeta.java +++ b/api/src/main/java/me/tofaa/entitylib/meta/EntityMeta.java @@ -272,12 +272,12 @@ public class EntityMeta implements EntityMetadataProvider { } @Override - public List entityData(ClientVersion clientVersion) { + public @NotNull List> entityData(@NotNull ClientVersion clientVersion) { return metadata.getEntries(); // TODO: Atm this is useless cause of the way the api works. Might change in the future } @Override - public List entityData() { + public @NotNull List> entityData() { return metadata.getEntries(); } diff --git a/api/src/main/java/me/tofaa/entitylib/meta/Metadata.java b/api/src/main/java/me/tofaa/entitylib/meta/Metadata.java index 5f91115..d93666f 100644 --- a/api/src/main/java/me/tofaa/entitylib/meta/Metadata.java +++ b/api/src/main/java/me/tofaa/entitylib/meta/Metadata.java @@ -19,8 +19,8 @@ public class Metadata { private final int entityId; private volatile boolean notifyAboutChanges = true; - private final HashMap notNotifiedChanges = new HashMap<>(); - private final ConcurrentHashMap metadataMap = new ConcurrentHashMap<>(); + private final HashMap> notNotifiedChanges = new HashMap<>(); + private final ConcurrentHashMap> metadataMap = new ConcurrentHashMap<>(); public Metadata(int entityId) { this.entityId = entityId; @@ -47,13 +47,13 @@ public class Metadata { } public T getIndex(byte index, @Nullable T defaultValue) { - EntityData value = this.metadataMap.get(index); + EntityData value = this.metadataMap.get(index); return value != null ? (T) value.getValue() : defaultValue; } public void setIndex(byte index, @NotNull EntityDataType dataType, T value) { - final EntityData entry = new EntityData(index, dataType, value); + final EntityData entry = new EntityData<>(index, dataType, value); this.metadataMap.put(index, entry); final Optional> optionalApi = EntityLib.getOptionalApi(); @@ -75,7 +75,7 @@ public class Metadata { return; } - List entries = null; + List> entries = null; synchronized (this.notNotifiedChanges) { this.notifyAboutChanges = notifyAboutChanges; if (notifyAboutChanges) { @@ -96,7 +96,7 @@ public class Metadata { } public void setMetaFromPacket(WrapperPlayServerEntityMetadata wrapper) { - for (EntityData data : wrapper.getEntityMetadata()) { + for (EntityData data : wrapper.getEntityMetadata()) { metadataMap.put((byte) data.getIndex(), data); } } @@ -105,7 +105,7 @@ public class Metadata { return notifyAboutChanges; } - @NotNull List getEntries() { + @NotNull List> getEntries() { return Collections.unmodifiableList(new ArrayList<>(metadataMap.values())); } diff --git a/libs.versions.toml b/libs.versions.toml index 4b2c87a..7b89472 100644 --- a/libs.versions.toml +++ b/libs.versions.toml @@ -1,8 +1,8 @@ [versions] -adventure = "4.16.0" -jetbrains-annotations = "24.0.0" -gson = "2.11.0" -packetevents = "2.7.0" +adventure = "4.22.0" +jetbrains-annotations = "26.0.2" +gson = "2.13.1" +packetevents = "2.9.1" paper = "1.21-R0.1-SNAPSHOT" velocity = "3.3.0-SNAPSHOT" run-paper = "2.3.0" From 6af48b98e72c6e53d8319a3456b42612b5239a1d Mon Sep 17 00:00:00 2001 From: OakLoaf Date: Fri, 18 Jul 2025 15:50:18 +0100 Subject: [PATCH 21/28] Cleaned up MetaConverterRegistry, added newer entities and implemented unused meta classes --- .../entitylib/meta/MetaConverterRegistry.java | 20 ++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/api/src/main/java/me/tofaa/entitylib/meta/MetaConverterRegistry.java b/api/src/main/java/me/tofaa/entitylib/meta/MetaConverterRegistry.java index ed8c106..9337123 100644 --- a/api/src/main/java/me/tofaa/entitylib/meta/MetaConverterRegistry.java +++ b/api/src/main/java/me/tofaa/entitylib/meta/MetaConverterRegistry.java @@ -49,9 +49,9 @@ final class MetaConverterRegistry { MetaConverterRegistry() { put(ABSTRACT_WIND_CHARGE, SmallFireballMeta.class, SmallFireballMeta::new); // TODO: Verify correctness put(AREA_EFFECT_CLOUD, AreaEffectCloudMeta.class, AreaEffectCloudMeta::new); + put(ALLAY, LivingEntityMeta.class, LivingEntityMeta::new); // TODO: Implement put(ARMADILLO, ArmadilloMeta.class, ArmadilloMeta::new); // TODO: Verify correctness put(ARMOR_STAND, ArmorStandMeta.class, ArmorStandMeta::new); - put(ALLAY, LivingEntityMeta.class, LivingEntityMeta::new); // TODO: Implement put(ARROW, ArrowMeta.class, ArrowMeta::new); put(AXOLOTL, AxolotlMeta.class, AxolotlMeta::new); put(BAT, BatMeta.class, BatMeta::new); @@ -68,8 +68,9 @@ final class MetaConverterRegistry { put(CHEST_MINECART, ChestMinecartMeta.class, ChestMinecartMeta::new); put(CHICKEN, ChickenMeta.class, ChickenMeta::new); put(COD, CodMeta.class, CodMeta::new); - put(COW, CowMeta.class, CowMeta::new); put(COMMAND_BLOCK_MINECART, CommandBlockMinecartMeta.class, CommandBlockMinecartMeta::new); + put(COW, CowMeta.class, CowMeta::new); + put(CREAKING, LivingEntityMeta.class, LivingEntityMeta::new); // TODO: Implement put(CREEPER, CreeperMeta.class, CreeperMeta::new); put(DOLPHIN, DolphinMeta.class, DolphinMeta::new); put(DONKEY, DonkeyMeta.class, DonkeyMeta::new); @@ -79,11 +80,12 @@ final class MetaConverterRegistry { put(ELDER_GUARDIAN, ElderGuardianMeta.class, ElderGuardianMeta::new); put(END_CRYSTAL, EndCrystalMeta.class, EndCrystalMeta::new); put(ENDER_DRAGON, EnderDragonMeta.class, EnderDragonMeta::new); + put(ENDER_PEARL, ThrownEnderPearlMeta.class, ThrownEnderPearlMeta::new); put(ENDERMAN, EndermanMeta.class, EndermanMeta::new); put(ENDERMITE, EndermiteMeta.class, EndermiteMeta::new); put(EVOKER, EvokerMeta.class, EvokerMeta::new); - put(EYE_OF_ENDER, EyeOfEnderMeta.class, EyeOfEnderMeta::new); put(EVOKER_FANGS, EvokerFangsMeta.class, EvokerFangsMeta::new); + put(EYE_OF_ENDER, EyeOfEnderMeta.class, EyeOfEnderMeta::new); put(FALLING_BLOCK, FallingBlockMeta.class, FallingBlockMeta::new); put(FIREBALL, LargeFireballMeta.class, LargeFireballMeta::new); // TODO: Verify correctness put(FIREWORK_ROCKET, FireworkRocketMeta.class, FireworkRocketMeta::new); @@ -91,11 +93,13 @@ final class MetaConverterRegistry { put(FOX, FoxMeta.class, FoxMeta::new); put(FROG, FrogMeta.class, FrogMeta::new); put(FURNACE_MINECART, FurnaceMinecartMeta.class, FurnaceMinecartMeta::new); + put(GHAST, GhastMeta.class, GhastMeta::new); put(GIANT, GiantMeta.class, GiantMeta::new); put(GLOW_ITEM_FRAME, GlowItemFrameMeta.class, GlowItemFrameMeta::new); put(GLOW_SQUID, GlowSquidMeta.class, GlowSquidMeta::new); put(GOAT, GoatMeta.class, GoatMeta::new); put(GUARDIAN, GuardianMeta.class, GuardianMeta::new); + put(HAPPY_GHAST, GhastMeta.class, GhastMeta::new); // TODO: Implement put(HOGLIN, HoglinMeta.class, HoglinMeta::new); put(HOPPER_MINECART, FurnaceMinecartMeta.class, FurnaceMinecartMeta::new); put(HORSE, HorseMeta.class, HorseMeta::new); @@ -103,34 +107,35 @@ final class MetaConverterRegistry { put(ILLUSIONER, IllusionerMeta.class, IllusionerMeta::new); put(INTERACTION, InteractionMeta.class, InteractionMeta::new); put(IRON_GOLEM, IronGolemMeta.class, IronGolemMeta::new); + put(ITEM, ItemEntityMeta.class, ItemEntityMeta::new); put(ITEM_DISPLAY, ItemDisplayMeta.class, ItemDisplayMeta::new); put(ITEM_FRAME, ItemFrameMeta.class, ItemFrameMeta::new); - put(ITEM, ItemEntityMeta.class, ItemEntityMeta::new); put(LEASH_KNOT, LeashKnotMeta.class, LeashKnotMeta::new); put(LIGHTNING_BOLT, LightningBoltMeta.class, LightningBoltMeta::new); put(LLAMA, LlamaMeta.class, LlamaMeta::new); put(LLAMA_SPIT, LlamaSpitMeta.class, LlamaSpitMeta::new); put(MAGMA_CUBE, MagmaCubeMeta.class, MagmaCubeMeta::new); put(MARKER, MarkerMeta.class, MarkerMeta::new); + put(MOOSHROOM, MooshroomMeta.class, MooshroomMeta::new); put(MULE, MuleMeta.class, MuleMeta::new); put(OCELOT, OcelotMeta.class, OcelotMeta::new); put(PAINTING, PaintingMeta.class, PaintingMeta::new); put(PANDA, PandaMeta.class, PandaMeta::new); - put(POTION, ThrownPotionMeta.class, ThrownPotionMeta::new); put(PARROT, ParrotMeta.class, ParrotMeta::new); + put(PHANTOM, PhantomMeta.class, PhantomMeta::new); put(PIG, PigMeta.class, PigMeta::new); put(PIGLIN, PiglinMeta.class, PiglinMeta::new); put(PIGLIN_BRUTE, PiglinBruteMeta.class, PiglinBruteMeta::new); put(PILLAGER, PillagerMeta.class, PillagerMeta::new); put(PLAYER, PlayerMeta.class, PlayerMeta::new); put(POLAR_BEAR, PolarBearMeta.class, PolarBearMeta::new); + put(POTION, ThrownPotionMeta.class, ThrownPotionMeta::new); put(PRIMED_TNT, PrimedTntMeta.class, PrimedTntMeta::new); put(PUFFERFISH, PufferFishMeta.class, PufferFishMeta::new); put(RABBIT, RabbitMeta.class, RabbitMeta::new); put(RAVAGER, RavagerMeta.class, RavagerMeta::new); put(SALMON, SalmonMeta.class, SalmonMeta::new); put(SHEEP, SheepMeta.class, SheepMeta::new); - put(SNOWBALL, SnowballMeta.class, SnowballMeta::new); put(SHULKER, ShulkerMeta.class, ShulkerMeta::new); put(SHULKER_BULLET, ShulkerBulletMeta.class, ShulkerBulletMeta::new); put(SILVERFISH, SilverfishMeta.class, SilverfishMeta::new); @@ -140,14 +145,15 @@ final class MetaConverterRegistry { put(SMALL_FIREBALL, SmallFireballMeta.class, SmallFireballMeta::new); put(SNIFFER, SnifferMeta.class, SnifferMeta::new); put(SNOW_GOLEM, SnowGolemMeta.class, SnowGolemMeta::new); + put(SNOWBALL, SnowballMeta.class, SnowballMeta::new); put(SPAWNER_MINECART, SpawnerMinecartMeta.class, SpawnerMinecartMeta::new); put(SPIDER, SpiderMeta.class, SpiderMeta::new); + put(SQUID, SquidMeta.class, SquidMeta::new); put(STRAY, StrayMeta.class, StrayMeta::new); put(STRIDER, StriderMeta.class, StriderMeta::new); put(TADPOLE, LivingEntityMeta.class, LivingEntityMeta::new); // TODO: Implement put(TEXT_DISPLAY, TextDisplayMeta.class, TextDisplayMeta::new); put(THROWN_EXP_BOTTLE, ThrownExpBottleMeta.class, ThrownExpBottleMeta::new); - put(ENDER_PEARL, ThrownEnderPearlMeta.class, ThrownEnderPearlMeta::new); put(TNT_MINECART, TntMinecartMeta.class, TntMinecartMeta::new); put(TRADER_LLAMA, TraderLlamaMeta.class, TraderLlamaMeta::new); put(TRIDENT, ThrownTridentMeta.class, ThrownTridentMeta::new); From 7ea339a69e4e28d7d9559bd9847b834b17e0c528 Mon Sep 17 00:00:00 2001 From: Felipe Paschoal Bergamo <64669985+felipepasc@users.noreply.github.com> Date: Sun, 20 Jul 2025 02:53:31 -0300 Subject: [PATCH 22/28] feat(meta): add TntMeta class and register in MetaConverterRegistry --- .../entitylib/meta/MetaConverterRegistry.java | 1 + .../tofaa/entitylib/meta/other/TntMeta.java | 31 +++++++++++++++++++ 2 files changed, 32 insertions(+) create mode 100644 api/src/main/java/me/tofaa/entitylib/meta/other/TntMeta.java diff --git a/api/src/main/java/me/tofaa/entitylib/meta/MetaConverterRegistry.java b/api/src/main/java/me/tofaa/entitylib/meta/MetaConverterRegistry.java index ed8c106..5d9e5d5 100644 --- a/api/src/main/java/me/tofaa/entitylib/meta/MetaConverterRegistry.java +++ b/api/src/main/java/me/tofaa/entitylib/meta/MetaConverterRegistry.java @@ -148,6 +148,7 @@ final class MetaConverterRegistry { put(TEXT_DISPLAY, TextDisplayMeta.class, TextDisplayMeta::new); put(THROWN_EXP_BOTTLE, ThrownExpBottleMeta.class, ThrownExpBottleMeta::new); put(ENDER_PEARL, ThrownEnderPearlMeta.class, ThrownEnderPearlMeta::new); + put(TNT, TntMeta.class, TntMeta::new); put(TNT_MINECART, TntMinecartMeta.class, TntMinecartMeta::new); put(TRADER_LLAMA, TraderLlamaMeta.class, TraderLlamaMeta::new); put(TRIDENT, ThrownTridentMeta.class, ThrownTridentMeta::new); diff --git a/api/src/main/java/me/tofaa/entitylib/meta/other/TntMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/other/TntMeta.java new file mode 100644 index 0000000..e79ed56 --- /dev/null +++ b/api/src/main/java/me/tofaa/entitylib/meta/other/TntMeta.java @@ -0,0 +1,31 @@ +package me.tofaa.entitylib.meta.other; + +import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes; +import com.github.retrooper.packetevents.protocol.world.states.type.StateTypes; +import me.tofaa.entitylib.meta.EntityMeta; +import me.tofaa.entitylib.meta.Metadata; + +public class TntMeta extends EntityMeta { + public static final byte OFFSET = EntityMeta.MAX_OFFSET; + public static final byte MAX_OFFSET = OFFSET + 2; + + public TntMeta(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); + } + + public int getBlockData() { + return super.metadata.getIndex(offset(OFFSET, 1), StateTypes.TNT.createBlockState().getGlobalId()); + } + + public void setBlockData(int blockData) { + super.metadata.setIndex(offset(OFFSET, 1), EntityDataTypes.BLOCK_STATE, blockData); + } +} From d69eeb3932f9ce4607b1024a85ce2d7092f31c2f Mon Sep 17 00:00:00 2001 From: Felipe Paschoal Bergamo <64669985+felipepasc@users.noreply.github.com> Date: Sun, 20 Jul 2025 02:54:16 -0300 Subject: [PATCH 23/28] feat(meta): add TntMeta class and register in MetaConverterRegistry --- .../main/java/me/tofaa/entitylib/meta/MetaConverterRegistry.java | 1 + 1 file changed, 1 insertion(+) diff --git a/api/src/main/java/me/tofaa/entitylib/meta/MetaConverterRegistry.java b/api/src/main/java/me/tofaa/entitylib/meta/MetaConverterRegistry.java index ed8c106..5d9e5d5 100644 --- a/api/src/main/java/me/tofaa/entitylib/meta/MetaConverterRegistry.java +++ b/api/src/main/java/me/tofaa/entitylib/meta/MetaConverterRegistry.java @@ -148,6 +148,7 @@ final class MetaConverterRegistry { put(TEXT_DISPLAY, TextDisplayMeta.class, TextDisplayMeta::new); put(THROWN_EXP_BOTTLE, ThrownExpBottleMeta.class, ThrownExpBottleMeta::new); put(ENDER_PEARL, ThrownEnderPearlMeta.class, ThrownEnderPearlMeta::new); + put(TNT, TntMeta.class, TntMeta::new); put(TNT_MINECART, TntMinecartMeta.class, TntMinecartMeta::new); put(TRADER_LLAMA, TraderLlamaMeta.class, TraderLlamaMeta::new); put(TRIDENT, ThrownTridentMeta.class, ThrownTridentMeta::new); From 3d803fd4d7991e63968f28a47861c270385fef3a Mon Sep 17 00:00:00 2001 From: Felipe Paschoal Bergamo <64669985+felipepasc@users.noreply.github.com> Date: Sun, 20 Jul 2025 05:03:06 -0300 Subject: [PATCH 24/28] feat: add missing metadata converters for entities ``` - Implemented converters for ALLAY, CREAKING, ENDER_PEARL, EVOKER_FANGS, GHAST, HAPPY_GHAST, ITEM, MOOSHROOM, PHANTOM, POTION, SNOWBALL, and SQUID. - Verified and updated converters for COW, and added TODO notes for correctness checks on certain entities. ``` --- .../entitylib/meta/MetaConverterRegistry.java | 22 ++++++++++++------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/api/src/main/java/me/tofaa/entitylib/meta/MetaConverterRegistry.java b/api/src/main/java/me/tofaa/entitylib/meta/MetaConverterRegistry.java index 5d9e5d5..bdbf82a 100644 --- a/api/src/main/java/me/tofaa/entitylib/meta/MetaConverterRegistry.java +++ b/api/src/main/java/me/tofaa/entitylib/meta/MetaConverterRegistry.java @@ -49,9 +49,9 @@ final class MetaConverterRegistry { MetaConverterRegistry() { put(ABSTRACT_WIND_CHARGE, SmallFireballMeta.class, SmallFireballMeta::new); // TODO: Verify correctness put(AREA_EFFECT_CLOUD, AreaEffectCloudMeta.class, AreaEffectCloudMeta::new); + put(ALLAY, LivingEntityMeta.class, LivingEntityMeta::new); // TODO: Implement put(ARMADILLO, ArmadilloMeta.class, ArmadilloMeta::new); // TODO: Verify correctness put(ARMOR_STAND, ArmorStandMeta.class, ArmorStandMeta::new); - put(ALLAY, LivingEntityMeta.class, LivingEntityMeta::new); // TODO: Implement put(ARROW, ArrowMeta.class, ArrowMeta::new); put(AXOLOTL, AxolotlMeta.class, AxolotlMeta::new); put(BAT, BatMeta.class, BatMeta::new); @@ -68,8 +68,9 @@ final class MetaConverterRegistry { put(CHEST_MINECART, ChestMinecartMeta.class, ChestMinecartMeta::new); put(CHICKEN, ChickenMeta.class, ChickenMeta::new); put(COD, CodMeta.class, CodMeta::new); - put(COW, CowMeta.class, CowMeta::new); put(COMMAND_BLOCK_MINECART, CommandBlockMinecartMeta.class, CommandBlockMinecartMeta::new); + put(COW, CowMeta.class, CowMeta::new); + put(CREAKING, LivingEntityMeta.class, LivingEntityMeta::new); // TODO: Implement put(CREEPER, CreeperMeta.class, CreeperMeta::new); put(DOLPHIN, DolphinMeta.class, DolphinMeta::new); put(DONKEY, DonkeyMeta.class, DonkeyMeta::new); @@ -79,11 +80,12 @@ final class MetaConverterRegistry { put(ELDER_GUARDIAN, ElderGuardianMeta.class, ElderGuardianMeta::new); put(END_CRYSTAL, EndCrystalMeta.class, EndCrystalMeta::new); put(ENDER_DRAGON, EnderDragonMeta.class, EnderDragonMeta::new); + put(ENDER_PEARL, ThrownEnderPearlMeta.class, ThrownEnderPearlMeta::new); put(ENDERMAN, EndermanMeta.class, EndermanMeta::new); put(ENDERMITE, EndermiteMeta.class, EndermiteMeta::new); put(EVOKER, EvokerMeta.class, EvokerMeta::new); - put(EYE_OF_ENDER, EyeOfEnderMeta.class, EyeOfEnderMeta::new); put(EVOKER_FANGS, EvokerFangsMeta.class, EvokerFangsMeta::new); + put(EYE_OF_ENDER, EyeOfEnderMeta.class, EyeOfEnderMeta::new); put(FALLING_BLOCK, FallingBlockMeta.class, FallingBlockMeta::new); put(FIREBALL, LargeFireballMeta.class, LargeFireballMeta::new); // TODO: Verify correctness put(FIREWORK_ROCKET, FireworkRocketMeta.class, FireworkRocketMeta::new); @@ -91,11 +93,13 @@ final class MetaConverterRegistry { put(FOX, FoxMeta.class, FoxMeta::new); put(FROG, FrogMeta.class, FrogMeta::new); put(FURNACE_MINECART, FurnaceMinecartMeta.class, FurnaceMinecartMeta::new); + put(GHAST, GhastMeta.class, GhastMeta::new); put(GIANT, GiantMeta.class, GiantMeta::new); put(GLOW_ITEM_FRAME, GlowItemFrameMeta.class, GlowItemFrameMeta::new); put(GLOW_SQUID, GlowSquidMeta.class, GlowSquidMeta::new); put(GOAT, GoatMeta.class, GoatMeta::new); put(GUARDIAN, GuardianMeta.class, GuardianMeta::new); + put(HAPPY_GHAST, GhastMeta.class, GhastMeta::new); // TODO: Implement put(HOGLIN, HoglinMeta.class, HoglinMeta::new); put(HOPPER_MINECART, FurnaceMinecartMeta.class, FurnaceMinecartMeta::new); put(HORSE, HorseMeta.class, HorseMeta::new); @@ -103,34 +107,35 @@ final class MetaConverterRegistry { put(ILLUSIONER, IllusionerMeta.class, IllusionerMeta::new); put(INTERACTION, InteractionMeta.class, InteractionMeta::new); put(IRON_GOLEM, IronGolemMeta.class, IronGolemMeta::new); + put(ITEM, ItemEntityMeta.class, ItemEntityMeta::new); put(ITEM_DISPLAY, ItemDisplayMeta.class, ItemDisplayMeta::new); put(ITEM_FRAME, ItemFrameMeta.class, ItemFrameMeta::new); - put(ITEM, ItemEntityMeta.class, ItemEntityMeta::new); put(LEASH_KNOT, LeashKnotMeta.class, LeashKnotMeta::new); put(LIGHTNING_BOLT, LightningBoltMeta.class, LightningBoltMeta::new); put(LLAMA, LlamaMeta.class, LlamaMeta::new); put(LLAMA_SPIT, LlamaSpitMeta.class, LlamaSpitMeta::new); put(MAGMA_CUBE, MagmaCubeMeta.class, MagmaCubeMeta::new); put(MARKER, MarkerMeta.class, MarkerMeta::new); + put(MOOSHROOM, MooshroomMeta.class, MooshroomMeta::new); put(MULE, MuleMeta.class, MuleMeta::new); put(OCELOT, OcelotMeta.class, OcelotMeta::new); put(PAINTING, PaintingMeta.class, PaintingMeta::new); put(PANDA, PandaMeta.class, PandaMeta::new); - put(POTION, ThrownPotionMeta.class, ThrownPotionMeta::new); put(PARROT, ParrotMeta.class, ParrotMeta::new); + put(PHANTOM, PhantomMeta.class, PhantomMeta::new); put(PIG, PigMeta.class, PigMeta::new); put(PIGLIN, PiglinMeta.class, PiglinMeta::new); put(PIGLIN_BRUTE, PiglinBruteMeta.class, PiglinBruteMeta::new); put(PILLAGER, PillagerMeta.class, PillagerMeta::new); put(PLAYER, PlayerMeta.class, PlayerMeta::new); put(POLAR_BEAR, PolarBearMeta.class, PolarBearMeta::new); + put(POTION, ThrownPotionMeta.class, ThrownPotionMeta::new); put(PRIMED_TNT, PrimedTntMeta.class, PrimedTntMeta::new); put(PUFFERFISH, PufferFishMeta.class, PufferFishMeta::new); put(RABBIT, RabbitMeta.class, RabbitMeta::new); put(RAVAGER, RavagerMeta.class, RavagerMeta::new); put(SALMON, SalmonMeta.class, SalmonMeta::new); put(SHEEP, SheepMeta.class, SheepMeta::new); - put(SNOWBALL, SnowballMeta.class, SnowballMeta::new); put(SHULKER, ShulkerMeta.class, ShulkerMeta::new); put(SHULKER_BULLET, ShulkerBulletMeta.class, ShulkerBulletMeta::new); put(SILVERFISH, SilverfishMeta.class, SilverfishMeta::new); @@ -140,14 +145,15 @@ final class MetaConverterRegistry { put(SMALL_FIREBALL, SmallFireballMeta.class, SmallFireballMeta::new); put(SNIFFER, SnifferMeta.class, SnifferMeta::new); put(SNOW_GOLEM, SnowGolemMeta.class, SnowGolemMeta::new); + put(SNOWBALL, SnowballMeta.class, SnowballMeta::new); put(SPAWNER_MINECART, SpawnerMinecartMeta.class, SpawnerMinecartMeta::new); put(SPIDER, SpiderMeta.class, SpiderMeta::new); + put(SQUID, SquidMeta.class, SquidMeta::new); put(STRAY, StrayMeta.class, StrayMeta::new); put(STRIDER, StriderMeta.class, StriderMeta::new); put(TADPOLE, LivingEntityMeta.class, LivingEntityMeta::new); // TODO: Implement put(TEXT_DISPLAY, TextDisplayMeta.class, TextDisplayMeta::new); put(THROWN_EXP_BOTTLE, ThrownExpBottleMeta.class, ThrownExpBottleMeta::new); - put(ENDER_PEARL, ThrownEnderPearlMeta.class, ThrownEnderPearlMeta::new); put(TNT, TntMeta.class, TntMeta::new); put(TNT_MINECART, TntMinecartMeta.class, TntMinecartMeta::new); put(TRADER_LLAMA, TraderLlamaMeta.class, TraderLlamaMeta::new); @@ -185,4 +191,4 @@ final class MetaConverterRegistry { return converters.getOrDefault(entityType, EntityMeta::new); } -} +} \ No newline at end of file From 56e64cde5b11ad7942f0dd0fc261323b973ea07f Mon Sep 17 00:00:00 2001 From: huanmeng-qwq <1871735932@qq.com> Date: Sun, 20 Jul 2025 18:51:40 +0800 Subject: [PATCH 25/28] feat: Add entity meta support for WrappedBlockState. --- .../entitylib/meta/display/BlockDisplayMeta.java | 9 +++++++++ .../entitylib/meta/mobs/monster/EndermanMeta.java | 14 +++++++++++++- .../entitylib/meta/other/FallingBlockMeta.java | 10 ++++++++++ .../me/tofaa/entitylib/meta/other/TntMeta.java | 11 +++++++++++ 4 files changed, 43 insertions(+), 1 deletion(-) 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 index 5d1ff50..70d45c3 100644 --- a/api/src/main/java/me/tofaa/entitylib/meta/display/BlockDisplayMeta.java +++ b/api/src/main/java/me/tofaa/entitylib/meta/display/BlockDisplayMeta.java @@ -1,6 +1,8 @@ package me.tofaa.entitylib.meta.display; +import com.github.retrooper.packetevents.PacketEvents; import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes; +import com.github.retrooper.packetevents.protocol.world.states.WrappedBlockState; import me.tofaa.entitylib.meta.Metadata; public class BlockDisplayMeta extends AbstractDisplayMeta { @@ -20,4 +22,11 @@ public class BlockDisplayMeta extends AbstractDisplayMeta { super.metadata.setIndex(OFFSET, EntityDataTypes.BLOCK_STATE, blockId); } + public WrappedBlockState getBlockState() { + return WrappedBlockState.getByGlobalId(PacketEvents.getAPI().getServerManager().getVersion().toClientVersion(), getBlockId()); + } + + public void setBlockState(WrappedBlockState blockState) { + setBlockId(blockState.getGlobalId()); + } } 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 index 0ba5c73..690386b 100644 --- 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 @@ -1,6 +1,8 @@ package me.tofaa.entitylib.meta.mobs.monster; +import com.github.retrooper.packetevents.PacketEvents; import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes; +import com.github.retrooper.packetevents.protocol.world.states.WrappedBlockState; import me.tofaa.entitylib.meta.Metadata; import me.tofaa.entitylib.meta.types.MobMeta; import org.jetbrains.annotations.Nullable; @@ -24,6 +26,16 @@ public class EndermanMeta extends MobMeta { super.metadata.setIndex(OFFSET, EntityDataTypes.OPTIONAL_INT, Optional.ofNullable(value)); } + public WrappedBlockState getCarriedBlockState() { + Integer carriedBlockID = getCarriedBlockID(); + if (carriedBlockID == null) return null; + return WrappedBlockState.getByGlobalId(PacketEvents.getAPI().getServerManager().getVersion().toClientVersion(), carriedBlockID); + } + + public void setCarriedBlockState(WrappedBlockState blockState) { + setCarriedBlockID(blockState.getGlobalId()); + } + public boolean isScreaming() { return super.metadata.getIndex(offset(OFFSET, 1), false); } @@ -33,7 +45,7 @@ public class EndermanMeta extends MobMeta { } public boolean isStaring() { - return super.metadata.getIndex(offset(OFFSET, 2), false); + return super.metadata.getIndex(offset(OFFSET, 2), false); } public void setStaring(boolean value) { 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 index ff556ff..6c1819b 100644 --- a/api/src/main/java/me/tofaa/entitylib/meta/other/FallingBlockMeta.java +++ b/api/src/main/java/me/tofaa/entitylib/meta/other/FallingBlockMeta.java @@ -1,6 +1,8 @@ package me.tofaa.entitylib.meta.other; +import com.github.retrooper.packetevents.PacketEvents; import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes; +import com.github.retrooper.packetevents.protocol.world.states.WrappedBlockState; import com.github.retrooper.packetevents.util.Vector3i; import me.tofaa.entitylib.meta.EntityMeta; import me.tofaa.entitylib.meta.Metadata; @@ -34,6 +36,14 @@ public class FallingBlockMeta extends EntityMeta implements ObjectData { this.blockStateId = blockStateId; } + public WrappedBlockState getBlockState() { + return WrappedBlockState.getByGlobalId(PacketEvents.getAPI().getServerManager().getVersion().toClientVersion(), getBlockStateId()); + } + + public void setBlockStateId(WrappedBlockState blockState) { + setBlockStateId(blockState.getGlobalId()); + } + @Override public int getObjectData() { return blockStateId; diff --git a/api/src/main/java/me/tofaa/entitylib/meta/other/TntMeta.java b/api/src/main/java/me/tofaa/entitylib/meta/other/TntMeta.java index e79ed56..ee155aa 100644 --- a/api/src/main/java/me/tofaa/entitylib/meta/other/TntMeta.java +++ b/api/src/main/java/me/tofaa/entitylib/meta/other/TntMeta.java @@ -1,6 +1,8 @@ package me.tofaa.entitylib.meta.other; +import com.github.retrooper.packetevents.PacketEvents; import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes; +import com.github.retrooper.packetevents.protocol.world.states.WrappedBlockState; import com.github.retrooper.packetevents.protocol.world.states.type.StateTypes; import me.tofaa.entitylib.meta.EntityMeta; import me.tofaa.entitylib.meta.Metadata; @@ -28,4 +30,13 @@ public class TntMeta extends EntityMeta { public void setBlockData(int blockData) { super.metadata.setIndex(offset(OFFSET, 1), EntityDataTypes.BLOCK_STATE, blockData); } + + public WrappedBlockState getBlockState() { + return WrappedBlockState.getByGlobalId(PacketEvents.getAPI().getServerManager().getVersion().toClientVersion(), getBlockData()); + } + + public void setBlockState(WrappedBlockState blockState) { + setBlockData(blockState.getGlobalId()); + } + } From 64021bb0dc109d81d04119d22756ffa81f828e88 Mon Sep 17 00:00:00 2001 From: huanmeng-qwq <1871735932@qq.com> Date: Sun, 20 Jul 2025 18:57:01 +0800 Subject: [PATCH 26/28] update --- .../me/tofaa/entitylib/meta/mobs/monster/EndermanMeta.java | 7 +++++-- .../me/tofaa/entitylib/meta/other/FallingBlockMeta.java | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) 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 index 690386b..bebef25 100644 --- 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 @@ -5,9 +5,8 @@ import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes; import com.github.retrooper.packetevents.protocol.world.states.WrappedBlockState; import me.tofaa.entitylib.meta.Metadata; import me.tofaa.entitylib.meta.types.MobMeta; -import org.jetbrains.annotations.Nullable; - import java.util.Optional; +import org.jetbrains.annotations.Nullable; public class EndermanMeta extends MobMeta { @@ -33,6 +32,10 @@ public class EndermanMeta extends MobMeta { } public void setCarriedBlockState(WrappedBlockState blockState) { + if (blockState == null) { + setCarriedBlockID(null); + return; + } setCarriedBlockID(blockState.getGlobalId()); } 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 index 6c1819b..c7e979a 100644 --- a/api/src/main/java/me/tofaa/entitylib/meta/other/FallingBlockMeta.java +++ b/api/src/main/java/me/tofaa/entitylib/meta/other/FallingBlockMeta.java @@ -40,7 +40,7 @@ public class FallingBlockMeta extends EntityMeta implements ObjectData { return WrappedBlockState.getByGlobalId(PacketEvents.getAPI().getServerManager().getVersion().toClientVersion(), getBlockStateId()); } - public void setBlockStateId(WrappedBlockState blockState) { + public void setBlockState(WrappedBlockState blockState) { setBlockStateId(blockState.getGlobalId()); } From 9ea8e9c1b4af2f740f317761fbb2de9a852ce71f Mon Sep 17 00:00:00 2001 From: huanmeng-qwq <1871735932@qq.com> Date: Mon, 21 Jul 2025 22:26:51 +0800 Subject: [PATCH 27/28] feat: Add user locale handling and metadata translation support --- .../java/me/tofaa/entitylib/EntityLibAPI.java | 2 ++ .../java/me/tofaa/entitylib/Platform.java | 13 +++++++ .../tofaa/entitylib/UserLocaleProvider.java | 8 +++++ .../me/tofaa/entitylib/utils/PacketUtil.java | 34 +++++++++++++++++++ .../entitylib/wrapper/WrapperEntity.java | 31 +++++++++++++---- .../common/AbstractEntityLibAPI.java | 6 ++++ 6 files changed, 88 insertions(+), 6 deletions(-) create mode 100644 api/src/main/java/me/tofaa/entitylib/UserLocaleProvider.java create mode 100644 api/src/main/java/me/tofaa/entitylib/utils/PacketUtil.java diff --git a/api/src/main/java/me/tofaa/entitylib/EntityLibAPI.java b/api/src/main/java/me/tofaa/entitylib/EntityLibAPI.java index c6041f7..77de149 100644 --- a/api/src/main/java/me/tofaa/entitylib/EntityLibAPI.java +++ b/api/src/main/java/me/tofaa/entitylib/EntityLibAPI.java @@ -53,4 +53,6 @@ public interface EntityLibAPI { @NotNull EntityContainer getDefaultContainer(); + @NotNull + UserLocaleProvider getUserLocaleProvider(); } diff --git a/api/src/main/java/me/tofaa/entitylib/Platform.java b/api/src/main/java/me/tofaa/entitylib/Platform.java index 62accad..fa75430 100644 --- a/api/src/main/java/me/tofaa/entitylib/Platform.java +++ b/api/src/main/java/me/tofaa/entitylib/Platform.java @@ -26,6 +26,13 @@ public interface Platform

{ */ @NotNull EntityUuidProvider getEntityUuidProvider(); + /** + * Gets the provider responsible for retrieving the locale of a user. + * + * @return a non-null {@link UserLocaleProvider} instance. + */ + @NotNull UserLocaleProvider getUserLocaleProvider(); + /** * Sets the entityId integer provider. This can be provided by a platform if needed. * @param provider the entityId integer provider. @@ -38,6 +45,12 @@ public interface Platform

{ */ void setEntityUuidProvider(@NotNull EntityUuidProvider provider); + /** + * Sets the provider responsible for retrieving the locale of a user. + * + * @param provider the {@link UserLocaleProvider} instance to be set. Must not be null. + */ + void setUserLocaleProvider(@NotNull UserLocaleProvider provider); /** * @return the logger EntityLib uses internally. diff --git a/api/src/main/java/me/tofaa/entitylib/UserLocaleProvider.java b/api/src/main/java/me/tofaa/entitylib/UserLocaleProvider.java new file mode 100644 index 0000000..54c542d --- /dev/null +++ b/api/src/main/java/me/tofaa/entitylib/UserLocaleProvider.java @@ -0,0 +1,8 @@ +package me.tofaa.entitylib; + +import java.util.Locale; +import java.util.UUID; + +public interface UserLocaleProvider { + Locale locale(UUID user); +} diff --git a/api/src/main/java/me/tofaa/entitylib/utils/PacketUtil.java b/api/src/main/java/me/tofaa/entitylib/utils/PacketUtil.java new file mode 100644 index 0000000..9e3b130 --- /dev/null +++ b/api/src/main/java/me/tofaa/entitylib/utils/PacketUtil.java @@ -0,0 +1,34 @@ +package me.tofaa.entitylib.utils; + +import com.github.retrooper.packetevents.protocol.entity.data.EntityData; +import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes; +import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerEntityMetadata; +import me.tofaa.entitylib.EntityLib; +import java.util.Locale; +import java.util.Optional; +import java.util.UUID; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.translation.GlobalTranslator; + +public class PacketUtil { + private PacketUtil() { + } + + public static void renderPacket(UUID user, WrapperPlayServerEntityMetadata metadata) { + Locale locale = EntityLib.getApi().getUserLocaleProvider().locale(user); + for (final EntityData entityData : metadata.getEntityMetadata()) { + if (entityData.getType() == EntityDataTypes.ADV_COMPONENT) { + Component component = (Component) entityData.getValue(); + final Component rendered = GlobalTranslator.render(component, locale); + ((EntityData) entityData).setValue(rendered); + } else if (entityData.getType() == EntityDataTypes.OPTIONAL_ADV_COMPONENT) { + final Optional optional = (Optional) entityData.getValue(); + if (optional.isPresent()) { + final Component component = optional.get(); + final Component rendered = GlobalTranslator.render(component, locale); + ((EntityData>) entityData).setValue(Optional.of(rendered)); + } + } + } + } +} diff --git a/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperEntity.java b/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperEntity.java index 40c8de9..1e37128 100644 --- a/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperEntity.java +++ b/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperEntity.java @@ -5,25 +5,39 @@ import com.github.retrooper.packetevents.protocol.player.User; import com.github.retrooper.packetevents.protocol.world.Location; import com.github.retrooper.packetevents.util.Vector3d; import com.github.retrooper.packetevents.wrapper.PacketWrapper; -import com.github.retrooper.packetevents.wrapper.play.server.*; +import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerBundle; +import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerDestroyEntities; +import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerEntityHeadLook; +import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerEntityMetadata; +import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerEntityRotation; +import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerEntityTeleport; +import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerEntityVelocity; +import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerSetPassengers; +import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerSpawnEntity; +import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerSystemChatMessage; import me.tofaa.entitylib.EntityLib; import me.tofaa.entitylib.container.EntityContainer; import me.tofaa.entitylib.meta.EntityMeta; import me.tofaa.entitylib.meta.types.ObjectData; import me.tofaa.entitylib.tick.Tickable; +import me.tofaa.entitylib.utils.PacketUtil; import me.tofaa.entitylib.ve.ViewerRule; import me.tofaa.entitylib.wrapper.spawning.SpawnPacketProvider; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Optional; +import java.util.Set; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.function.Consumer; import net.kyori.adventure.text.Component; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.UnmodifiableView; -import java.util.*; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.CopyOnWriteArrayList; -import java.util.function.Consumer; - public class WrapperEntity implements Tickable { private final UUID uuid; private final int entityId; @@ -510,6 +524,11 @@ public class WrapperEntity implements Tickable { return; } + // Special handling for entity metadata packets to support `GlobalTranslator` functionality and component rendering + if (wrapper instanceof WrapperPlayServerEntityMetadata) { + PacketUtil.renderPacket(user, (WrapperPlayServerEntityMetadata) wrapper); + } + EntityLib.getApi().getPacketEvents().getProtocolManager().sendPacket(channel, wrapper); } diff --git a/common/src/main/java/me/tofaa/entitylib/common/AbstractEntityLibAPI.java b/common/src/main/java/me/tofaa/entitylib/common/AbstractEntityLibAPI.java index bfee9b4..dd2922b 100644 --- a/common/src/main/java/me/tofaa/entitylib/common/AbstractEntityLibAPI.java +++ b/common/src/main/java/me/tofaa/entitylib/common/AbstractEntityLibAPI.java @@ -4,6 +4,7 @@ import com.github.retrooper.packetevents.PacketEventsAPI; import me.tofaa.entitylib.APIConfig; import me.tofaa.entitylib.EntityLibAPI; import me.tofaa.entitylib.Platform; +import me.tofaa.entitylib.UserLocaleProvider; import me.tofaa.entitylib.container.EntityContainer; import me.tofaa.entitylib.tick.TickContainer; import me.tofaa.entitylib.wrapper.WrapperEntity; @@ -63,4 +64,9 @@ public abstract class AbstractEntityLibAPI implements EntityLibAPI { public @NotNull Collection> getTickContainers() { return tickContainers; } + + @Override + public @NotNull UserLocaleProvider getUserLocaleProvider() { + return platform.getUserLocaleProvider(); + } } From acbb4383254828d7470773870aeefc5111c793e3 Mon Sep 17 00:00:00 2001 From: huanmeng-qwq <1871735932@qq.com> Date: Mon, 21 Jul 2025 22:50:10 +0800 Subject: [PATCH 28/28] feat: Introduce UserLocaleProvider implementation for Spigot, Velocity, and Standalone platforms --- .../spigot/SpigotEntityLibPlatform.java | 24 +++--- .../spigot/SpigotPlayerLocaleProvider.java | 73 +++++++++++++++++++ .../StandaloneEntityLibPlatform.java | 13 ++++ .../velocity/VelocityEntityLibPlatform.java | 12 +++ .../VelocityPlayerLocaleProvider.java | 20 +++++ 5 files changed, 132 insertions(+), 10 deletions(-) create mode 100644 platforms/spigot/src/main/java/me/tofaa/entitylib/spigot/SpigotPlayerLocaleProvider.java create mode 100644 platforms/velocity/src/main/java/me/tofaa/entitylib/velocity/VelocityPlayerLocaleProvider.java 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 6c9a2cc..34c7a7d 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 @@ -5,23 +5,17 @@ import io.github.retrooper.packetevents.bstats.bukkit.Metrics; import io.github.retrooper.packetevents.bstats.charts.SimplePie; import me.tofaa.entitylib.APIConfig; import me.tofaa.entitylib.EntityLib; +import me.tofaa.entitylib.UserLocaleProvider; import me.tofaa.entitylib.common.AbstractPlatform; -import me.tofaa.entitylib.utils.ConcurrentWeakIdentityHashMap; -import org.bukkit.Bukkit; -import org.bukkit.World; -import org.bukkit.entity.Entity; +import java.util.logging.Logger; import org.bukkit.plugin.Plugin; import org.bukkit.plugin.java.JavaPlugin; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.Map; -import java.util.logging.Logger; -import java.util.stream.Stream; public class SpigotEntityLibPlatform extends AbstractPlatform { private SpigotEntityLibAPI api; + private UserLocaleProvider userLocaleProvider = new SpigotPlayerLocaleProvider(); public SpigotEntityLibPlatform(@NotNull JavaPlugin plugin) { super(plugin); @@ -36,7 +30,7 @@ public class SpigotEntityLibPlatform extends AbstractPlatform { this.api.onLoad(); this.api.onEnable(); if (settings.shouldUseBstats()) { - PacketEventsAPI pe = (PacketEventsAPI)api.getPacketEvents(); + PacketEventsAPI pe = (PacketEventsAPI) api.getPacketEvents(); Metrics metrics = new Metrics(pe.getPlugin(), 21916); metrics.addCustomChart(new SimplePie("entitylib-version", () -> EntityLib.getVersion().toString())); } @@ -52,4 +46,14 @@ public class SpigotEntityLibPlatform extends AbstractPlatform { public String getName() { return "Spigot"; } + + @Override + public @NotNull UserLocaleProvider getUserLocaleProvider() { + return userLocaleProvider; + } + + @Override + public void setUserLocaleProvider(@NotNull final UserLocaleProvider provider) { + this.userLocaleProvider = provider; + } } diff --git a/platforms/spigot/src/main/java/me/tofaa/entitylib/spigot/SpigotPlayerLocaleProvider.java b/platforms/spigot/src/main/java/me/tofaa/entitylib/spigot/SpigotPlayerLocaleProvider.java new file mode 100644 index 0000000..a6d30ac --- /dev/null +++ b/platforms/spigot/src/main/java/me/tofaa/entitylib/spigot/SpigotPlayerLocaleProvider.java @@ -0,0 +1,73 @@ +package me.tofaa.entitylib.spigot; + +import me.tofaa.entitylib.UserLocaleProvider; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import java.util.Locale; +import java.util.UUID; +import java.util.function.Function; +import net.kyori.adventure.translation.Translator; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; + + +/** + * This implementation is based on code from the scoreboard-library project: + * LocaleProvider + * Modified and adapted for use in EntityLib. + */ +public class SpigotPlayerLocaleProvider implements UserLocaleProvider { + private static final Locale DEFAULT_LOCALE = Locale.US; + private static final Function provider = get(); + + @Override + public Locale locale(final UUID user) { + final Player player = Bukkit.getPlayer(user); + return player == null ? DEFAULT_LOCALE : provider.apply(player); + } + + private static @NotNull Function get() { + MethodHandles.Lookup lookup = MethodHandles.publicLookup(); + try { + MethodHandle adventureMethod = lookup.findVirtual(Player.class, "locale", MethodType.methodType(Locale.class)); + return player -> { + try { + return (Locale) adventureMethod.invokeExact(player); + } catch (Throwable e) { + throw new RuntimeException(e); + } + }; + } catch (IllegalAccessException | NoSuchMethodException ignored) { + } + + MethodType methodType = MethodType.methodType(String.class); + try { + MethodHandle legacySpigotMethod = lookup.findVirtual(Player.Spigot.class, "getLocale", methodType); + return player -> { + try { + Locale locale = Translator.parseLocale((String) legacySpigotMethod.invokeExact(player.spigot())); + return locale == null ? DEFAULT_LOCALE : locale; + } catch (Throwable e) { + throw new RuntimeException(e); + } + }; + } catch (IllegalAccessException | NoSuchMethodException ignored) { + } + + try { + MethodHandle legacyMethod = lookup.findVirtual(Player.class, "getLocale", methodType); + return player -> { + try { + Locale locale = Translator.parseLocale((String) legacyMethod.invokeExact(player)); + return locale == null ? DEFAULT_LOCALE : locale; + } catch (Throwable e) { + throw new RuntimeException(e); + } + }; + } catch (IllegalAccessException | NoSuchMethodException ignored) { + throw new RuntimeException("No way to get players locale found"); + } + } +} diff --git a/platforms/standalone/src/main/java/me/tofaa/entitylib/standalone/StandaloneEntityLibPlatform.java b/platforms/standalone/src/main/java/me/tofaa/entitylib/standalone/StandaloneEntityLibPlatform.java index 971eb56..b26e2e1 100644 --- a/platforms/standalone/src/main/java/me/tofaa/entitylib/standalone/StandaloneEntityLibPlatform.java +++ b/platforms/standalone/src/main/java/me/tofaa/entitylib/standalone/StandaloneEntityLibPlatform.java @@ -2,13 +2,16 @@ package me.tofaa.entitylib.standalone; import me.tofaa.entitylib.APIConfig; import me.tofaa.entitylib.EntityLibAPI; +import me.tofaa.entitylib.UserLocaleProvider; import me.tofaa.entitylib.common.AbstractPlatform; +import java.util.Locale; import org.jetbrains.annotations.NotNull; public class StandaloneEntityLibPlatform extends AbstractPlatform { private StandaloneEntityLibApi api; + private UserLocaleProvider userLocaleProvider = (user) -> Locale.US; public StandaloneEntityLibPlatform() { super(null); @@ -34,4 +37,14 @@ public class StandaloneEntityLibPlatform extends AbstractPlatform { public String getName() { return "Standalone"; } + + @Override + public @NotNull UserLocaleProvider getUserLocaleProvider() { + return userLocaleProvider; + } + + @Override + public void setUserLocaleProvider(@NotNull final UserLocaleProvider provider) { + this.userLocaleProvider = provider; + } } diff --git a/platforms/velocity/src/main/java/me/tofaa/entitylib/velocity/VelocityEntityLibPlatform.java b/platforms/velocity/src/main/java/me/tofaa/entitylib/velocity/VelocityEntityLibPlatform.java index 815441c..b0e96a9 100644 --- a/platforms/velocity/src/main/java/me/tofaa/entitylib/velocity/VelocityEntityLibPlatform.java +++ b/platforms/velocity/src/main/java/me/tofaa/entitylib/velocity/VelocityEntityLibPlatform.java @@ -9,6 +9,7 @@ import com.velocitypowered.api.proxy.ProxyServer; import io.github.retrooper.packetevents.velocity.factory.VelocityPacketEventsBuilder; import me.tofaa.entitylib.APIConfig; import me.tofaa.entitylib.EntityLibAPI; +import me.tofaa.entitylib.UserLocaleProvider; import me.tofaa.entitylib.common.AbstractPlatform; import org.jetbrains.annotations.NotNull; @@ -16,6 +17,7 @@ import java.util.logging.Logger; public class VelocityEntityLibPlatform extends AbstractPlatform { private VelocityEntityLibAPI api; + private UserLocaleProvider userLocaleProvider; private Object plugin; public VelocityEntityLibPlatform(Object plugin, ProxyServer handle) { @@ -54,4 +56,14 @@ public class VelocityEntityLibPlatform extends AbstractPlatform { public String getName() { return "Velocity"; } + + @Override + public @NotNull UserLocaleProvider getUserLocaleProvider() { + return userLocaleProvider; + } + + @Override + public void setUserLocaleProvider(final UserLocaleProvider userLocaleProvider) { + this.userLocaleProvider = userLocaleProvider; + } } diff --git a/platforms/velocity/src/main/java/me/tofaa/entitylib/velocity/VelocityPlayerLocaleProvider.java b/platforms/velocity/src/main/java/me/tofaa/entitylib/velocity/VelocityPlayerLocaleProvider.java new file mode 100644 index 0000000..5d9268a --- /dev/null +++ b/platforms/velocity/src/main/java/me/tofaa/entitylib/velocity/VelocityPlayerLocaleProvider.java @@ -0,0 +1,20 @@ +package me.tofaa.entitylib.velocity; + +import com.velocitypowered.api.proxy.Player; +import com.velocitypowered.api.proxy.ProxyServer; +import me.tofaa.entitylib.UserLocaleProvider; +import java.util.Locale; +import java.util.UUID; + +public class VelocityPlayerLocaleProvider implements UserLocaleProvider { + private final ProxyServer proxyServer; + + public VelocityPlayerLocaleProvider(final ProxyServer proxyServer) { + this.proxyServer = proxyServer; + } + + @Override + public Locale locale(final UUID user) { + return proxyServer.getPlayer(user).map(Player::getEffectiveLocale).orElse(Locale.US); + } +}