From 6bd6d22651207f521605bdc7dfc2d7ee5c4acfbe Mon Sep 17 00:00:00 2001 From: Felix Cravic Date: Sat, 5 Dec 2020 01:36:06 +0100 Subject: [PATCH] Added EntityCreature#switchEntityType --- .../net/minestom/server/entity/Entity.java | 2 +- .../server/entity/EntityCreature.java | 75 ++++++++++++++----- 2 files changed, 57 insertions(+), 20 deletions(-) diff --git a/src/main/java/net/minestom/server/entity/Entity.java b/src/main/java/net/minestom/server/entity/Entity.java index 804e671b3..0af415975 100644 --- a/src/main/java/net/minestom/server/entity/Entity.java +++ b/src/main/java/net/minestom/server/entity/Entity.java @@ -103,7 +103,7 @@ public abstract class Entity implements Viewable, EventHandler, DataContainer, P private final Set passengers = new CopyOnWriteArraySet<>(); private long lastUpdate; - private final EntityType entityType; + protected EntityType entityType; // UNSAFE to change, modify at your own risk // Network synchronization, send the absolute position of the entity each X milliseconds private static final UpdateOption SYNCHRONIZATION_COOLDOWN = new UpdateOption(1500, TimeUnit.MILLISECOND); diff --git a/src/main/java/net/minestom/server/entity/EntityCreature.java b/src/main/java/net/minestom/server/entity/EntityCreature.java index af1b24285..93a0d6305 100644 --- a/src/main/java/net/minestom/server/entity/EntityCreature.java +++ b/src/main/java/net/minestom/server/entity/EntityCreature.java @@ -21,7 +21,9 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.ArrayList; +import java.util.HashSet; import java.util.List; +import java.util.Set; import java.util.function.Supplier; public abstract class EntityCreature extends LivingEntity implements NavigableEntity { @@ -40,6 +42,11 @@ public abstract class EntityCreature extends LivingEntity implements NavigableEn private Entity target; + /** + * Lock used to support #switchEntityType + */ + private Object entityTypeLock = new Object(); + // Equipments private ItemStack mainHandItem; private ItemStack offHandItem; @@ -148,33 +155,63 @@ public abstract class EntityCreature extends LivingEntity implements NavigableEn @Override public boolean addViewer(@NotNull Player player) { - final boolean result = super.addViewer(player); + synchronized (entityTypeLock) { + final boolean result = super.addViewer(player); - final PlayerConnection playerConnection = player.getPlayerConnection(); + final PlayerConnection playerConnection = player.getPlayerConnection(); - EntityMovementPacket entityMovementPacket = new EntityMovementPacket(); - entityMovementPacket.entityId = getEntityId(); + EntityMovementPacket entityMovementPacket = new EntityMovementPacket(); + entityMovementPacket.entityId = getEntityId(); - SpawnLivingEntityPacket spawnLivingEntityPacket = new SpawnLivingEntityPacket(); - spawnLivingEntityPacket.entityId = getEntityId(); - spawnLivingEntityPacket.entityUuid = getUuid(); - spawnLivingEntityPacket.entityType = getEntityType().getId(); - spawnLivingEntityPacket.position = getPosition(); - spawnLivingEntityPacket.headPitch = 0; + SpawnLivingEntityPacket spawnLivingEntityPacket = new SpawnLivingEntityPacket(); + spawnLivingEntityPacket.entityId = getEntityId(); + spawnLivingEntityPacket.entityUuid = getUuid(); + spawnLivingEntityPacket.entityType = getEntityType().getId(); + spawnLivingEntityPacket.position = getPosition(); + spawnLivingEntityPacket.headPitch = 0; - playerConnection.sendPacket(entityMovementPacket); - playerConnection.sendPacket(spawnLivingEntityPacket); - playerConnection.sendPacket(getVelocityPacket()); - playerConnection.sendPacket(getMetadataPacket()); + playerConnection.sendPacket(entityMovementPacket); + playerConnection.sendPacket(spawnLivingEntityPacket); + playerConnection.sendPacket(getVelocityPacket()); + playerConnection.sendPacket(getMetadataPacket()); - // Equipments synchronization - syncEquipments(playerConnection); + // Equipments synchronization + syncEquipments(playerConnection); - if (hasPassenger()) { - playerConnection.sendPacket(getPassengersPacket()); + if (hasPassenger()) { + playerConnection.sendPacket(getPassengersPacket()); + } + + return result; } + } - return result; + @Override + public boolean removeViewer(@NotNull Player player) { + synchronized (entityTypeLock) { + return super.removeViewer(player); + } + } + + /** + * Changes the entity type of this entity. + *

+ * Works by changing the internal entity type field and by calling {@link #removeViewer(Player)} + * followed by {@link #addViewer(Player)} to all current viewers. + *

+ * Be aware that this only change the visual of the entity, the {@link net.minestom.server.collision.BoundingBox} + * will not be modified. + * + * @param entityType the new entity type + */ + public void switchEntityType(@NotNull EntityType entityType) { + synchronized (entityTypeLock) { + this.entityType = entityType; + + Set viewers = new HashSet<>(getViewers()); + getViewers().forEach(this::removeViewer); + viewers.forEach(this::addViewer); + } } /**