diff --git a/common/src/main/java/com/deathmotion/antihealthindicator/cache/EntityCache.java b/common/src/main/java/com/deathmotion/antihealthindicator/cache/EntityCache.java index a507fa7..7315423 100644 --- a/common/src/main/java/com/deathmotion/antihealthindicator/cache/EntityCache.java +++ b/common/src/main/java/com/deathmotion/antihealthindicator/cache/EntityCache.java @@ -27,22 +27,25 @@ import lombok.Getter; import lombok.NonNull; -import java.util.Map; import java.util.Optional; import java.util.concurrent.ConcurrentHashMap; @Getter public class EntityCache { private final AHIPlayer player; - private final ConcurrentHashMap cache; private final EntityTracker entityTracker; private final VehicleTracker vehicleTracker; + private final ConcurrentHashMap cache; + private final ConcurrentHashMap passengerIndex; + public EntityCache(AHIPlayer player) { this.player = player; - this.cache = new ConcurrentHashMap<>(); this.entityTracker = new EntityTracker(player, this); this.vehicleTracker = new VehicleTracker(player, this); + + this.cache = new ConcurrentHashMap<>(); + this.passengerIndex = new ConcurrentHashMap<>(); } public void onPacketSend(PacketSendEvent event) { @@ -55,25 +58,45 @@ public Optional getCachedEntity(int entityId) { } public Optional getVehicleData(int entityId) { - return getCachedEntity(entityId) - .filter(entityData -> entityData instanceof RidableEntity) - .map(entityData -> (RidableEntity) entityData); + CachedEntity entity = cache.get(entityId); + if (entity instanceof RidableEntity) { + return Optional.of((RidableEntity) entity); + } + return Optional.empty(); } public void addLivingEntity(int entityId, @NonNull CachedEntity cachedEntity) { cache.put(entityId, cachedEntity); + if (cachedEntity instanceof RidableEntity) { + RidableEntity ridable = (RidableEntity) cachedEntity; + // Populate the secondary index based on its current passenger ID. + passengerIndex.put(ridable.getPassengerId(), entityId); + } } public void removeEntity(int entityId) { - cache.remove(entityId); + CachedEntity removed = cache.remove(entityId); + if (removed instanceof RidableEntity) { + RidableEntity ridable = (RidableEntity) removed; + // Remove from secondary index. + passengerIndex.remove(ridable.getPassengerId()); + } } public void resetUserCache() { cache.clear(); + passengerIndex.clear(); } - public void updateVehiclePassenger(int entityId, int passengerId) { - getVehicleData(entityId).ifPresent(ridableEntityData -> ridableEntityData.setPassengerId(passengerId)); + public void updateVehiclePassenger(int entityId, int newPassengerId) { + getVehicleData(entityId).ifPresent(ridableEntity -> { + int oldPassengerId = ridableEntity.getPassengerId(); + if (oldPassengerId != newPassengerId) { + passengerIndex.remove(oldPassengerId); + ridableEntity.setPassengerId(newPassengerId); + passengerIndex.put(newPassengerId, entityId); + } + }); } public float getVehicleHealth(int entityId) { @@ -81,7 +104,9 @@ public float getVehicleHealth(int entityId) { } public boolean isUserPassenger(int entityId) { - return getVehicleData(entityId).map(ridableEntityData -> ridableEntityData.getPassengerId() == player.user.getEntityId()).orElse(false); + return getVehicleData(entityId) + .map(ridableEntity -> ridableEntity.getPassengerId() == player.user.getEntityId()) + .orElse(false); } public int getPassengerId(int entityId) { @@ -89,10 +114,6 @@ public int getPassengerId(int entityId) { } public int getEntityIdByPassengerId(int passengerId) { - return cache.entrySet().stream() - .filter(entry -> entry.getValue() instanceof RidableEntity && ((RidableEntity) entry.getValue()).getPassengerId() == passengerId) - .map(Map.Entry::getKey) - .findFirst() - .orElse(0); + return passengerIndex.getOrDefault(passengerId, 0); } -} \ No newline at end of file +} diff --git a/common/src/main/java/com/deathmotion/antihealthindicator/cache/trackers/VehicleTracker.java b/common/src/main/java/com/deathmotion/antihealthindicator/cache/trackers/VehicleTracker.java index 8f0076c..ca6c8f6 100644 --- a/common/src/main/java/com/deathmotion/antihealthindicator/cache/trackers/VehicleTracker.java +++ b/common/src/main/java/com/deathmotion/antihealthindicator/cache/trackers/VehicleTracker.java @@ -37,9 +37,6 @@ import java.util.Collections; import java.util.List; -/** - * Listens for VehicleState events and manages the caching of various entity state details. - */ public class VehicleTracker { private final AHIPlayer player; private final EntityCache entityCache; @@ -52,12 +49,12 @@ public VehicleTracker(AHIPlayer player, EntityCache entityCache) { } public void onPacketSend(PacketSendEvent event) { - final Settings settings = configManager.getSettings(); - if (!settings.getEntityData().isEnabled()) return; - if (settings.getEntityData().isPlayersOnly()) return; - - final PacketTypeCommon type = event.getPacketType(); + Settings settings = configManager.getSettings(); + if (!settings.getEntityData().isEnabled() || settings.getEntityData().isPlayersOnly()) { + return; + } + PacketTypeCommon type = event.getPacketType(); if (PacketType.Play.Server.SET_PASSENGERS == type) { handlePassengers(new WrapperPlayServerSetPassengers(event)); } else if (PacketType.Play.Server.ATTACH_ENTITY == type) { @@ -65,40 +62,77 @@ public void onPacketSend(PacketSendEvent event) { } } + /** + * Processes SET_PASSENGERS packets. + */ private void handlePassengers(WrapperPlayServerSetPassengers packet) { - int entityId = packet.getEntityId(); - if (entityId == player.user.getEntityId() || !isValidVehicle(entityId)) return; + int vehicleId = packet.getEntityId(); + if (!shouldProcess(vehicleId)) { + return; + } int[] passengers = packet.getPassengers(); if (passengers.length > 0) { - updatePassengerState(entityId, passengers[0], true); + // If there are passengers, update with the first one. + updatePassengerState(vehicleId, passengers[0], true); } else { - int passengerId = entityCache.getPassengerId(entityId); - updatePassengerState(entityId, passengerId, false); + // If no passengers are present, consider the vehicle empty. + int currentPassenger = entityCache.getPassengerId(vehicleId); + updatePassengerState(vehicleId, currentPassenger, false); } } + /** + * Processes ATTACH_ENTITY packets. + */ private void handleAttachEntity(WrapperPlayServerAttachEntity packet) { - int entityId = packet.getHoldingId(); - if (entityId == player.user.getEntityId() || !isValidVehicle(entityId)) return; + int vehicleId = packet.getHoldingId(); + if (!shouldProcess(vehicleId)) { + return; + } int passengerId = packet.getAttachedId(); - if (entityId > 0) { - updatePassengerState(entityId, passengerId, true); + if (vehicleId > 0) { + updatePassengerState(vehicleId, passengerId, true); } else { - int reversedEntityId = entityCache.getEntityIdByPassengerId(passengerId); - updatePassengerState(reversedEntityId, passengerId, false); + int cachedVehicleId = entityCache.getEntityIdByPassengerId(passengerId); + updatePassengerState(cachedVehicleId, passengerId, false); } } + /** + * Updates the passenger state in the cache and, when applicable, sends a vehicle health update. + * + * @param vehicleId the id of the vehicle entity. + * @param passengerId the id of the passenger. + * @param entering true if the passenger is entering, false if leaving. + */ private void updatePassengerState(int vehicleId, int passengerId, boolean entering) { + // Update the cached passenger state (use -1 for leaving). entityCache.updateVehiclePassenger(vehicleId, entering ? passengerId : -1); + // If a passenger is entering or the player's entity is involved, send a health update. if (entering || player.user.getEntityId() == passengerId) { float healthValue = entering ? entityCache.getVehicleHealth(vehicleId) : 0.5F; sendVehicleHealthUpdate(vehicleId, healthValue); } } + /** + * Determines whether a given entity id should be processed. + * + * @param entityId the entity id to check. + * @return true if it is not the player and represents a valid rideable vehicle. + */ + private boolean shouldProcess(int entityId) { + return entityId != player.user.getEntityId() && isValidVehicle(entityId); + } + + /** + * Checks if the entity is a valid rideable vehicle. + * + * @param entityId the entity id. + * @return true if the entity is present in the cache and is rideable. + */ private boolean isValidVehicle(int entityId) { return entityCache.getCachedEntity(entityId) .map(CachedEntity::getEntityType) @@ -106,8 +140,14 @@ private boolean isValidVehicle(int entityId) { .orElse(false); } - private void sendVehicleHealthUpdate(int vehicleId, float healthValue) { - AHIPlatform.getInstance().getScheduler().runAsyncTask((o) -> { + /** + * Sends an asynchronous vehicle health update to the client. + * + * @param vehicleId the vehicle entity id. + * @param healthValue the health value. + */ + private void sendVehicleHealthUpdate(final int vehicleId, final float healthValue) { + AHIPlatform.getInstance().getScheduler().runAsyncTask(task -> { List metadata = Collections.singletonList( new EntityData( player.metadataIndex.HEALTH, @@ -115,8 +155,7 @@ private void sendVehicleHealthUpdate(int vehicleId, float healthValue) { healthValue ) ); - player.user.sendPacketSilently(new WrapperPlayServerEntityMetadata(vehicleId, metadata)); }); } -} \ No newline at end of file +}