diff --git a/gradle.properties b/gradle.properties index 38370bf..85b076a 100644 --- a/gradle.properties +++ b/gradle.properties @@ -7,7 +7,7 @@ loader_version=0.14.21 #Fabric api fabric_version=0.83.0+1.20 # Mod Properties -mod_version=1.3.1 +mod_version=1.3.3 maven_group=org.samo_lego archives_base_name=healthcare # Dependencies diff --git a/src/main/java/org/samo_lego/healthcare/mixin/ServerPlayNetworkHandlerMixin_HealthTag.java b/src/main/java/org/samo_lego/healthcare/mixin/ServerPlayNetworkHandlerMixin_HealthTag.java index 6da5fc3..2d8456f 100644 --- a/src/main/java/org/samo_lego/healthcare/mixin/ServerPlayNetworkHandlerMixin_HealthTag.java +++ b/src/main/java/org/samo_lego/healthcare/mixin/ServerPlayNetworkHandlerMixin_HealthTag.java @@ -5,6 +5,8 @@ import net.minecraft.network.chat.Component; import net.minecraft.network.chat.MutableComponent; import net.minecraft.network.protocol.Packet; +import net.minecraft.network.protocol.game.ClientGamePacketListener; +import net.minecraft.network.protocol.game.ClientboundBundlePacket; import net.minecraft.network.protocol.game.ClientboundSetEntityDataPacket; import net.minecraft.network.syncher.SynchedEntityData; import net.minecraft.server.level.ServerPlayer; @@ -23,6 +25,7 @@ import java.util.ArrayList; import java.util.Collections; +import java.util.List; import java.util.Optional; import static org.samo_lego.healthcare.HealthCare.config; @@ -66,53 +69,85 @@ public abstract class ServerPlayNetworkHandlerMixin_HealthTag { cancellable = true ) private void onPacketSend(Packet sendPacket, PacketSendListener listener, CallbackInfo ci) { - if (sendPacket instanceof ClientboundSetEntityDataPacket packet && !this.hc_skipCheck) { - int id = packet.id(); - Entity entity = this.player.level().getEntity(id); - final var hb = ((HealthbarPreferences) this.player).healthcarePrefs(); - - if (entity instanceof LivingEntity living && - hb.enabled && - !(entity instanceof Player) && - !config.blacklistedEntities.contains(BuiltInRegistries.ENTITY_TYPE.getKey(entity.getType()).toString()) && - !entity.isInvisibleTo(player)) { - - var trackedValues = new ArrayList<>(packet.packedItems()); - - // Removing current custom name - var customName = trackedValues.stream().filter(value -> value.id() == 2).findFirst(); - - // Ensure name is visible only if mob is not too far away - boolean visible = (entity.distanceTo(player) < config.activationRange || entity.isCustomNameVisible()) && hb.alwaysVisible; - var visibleTag = SynchedEntityData.DataValue.create(EntityAccessor.getNAME_VISIBLE(), visible); - - float health = living.getHealth(); - float maxHealth = living.getMaxHealth(); - - MutableComponent name = Component.empty(); - if (customName.isPresent() && ((Optional) customName.get().value()).isPresent()) { - name = ((Optional) customName.get().value()).get().copy().append(" "); - } else if (entity.hasCustomName()) { - // @SpaceClouds42 saved me here, `.copy()` after getting custom name is essential! - name = entity.getCustomName().copy().append(" "); - } else if (hb.showType) { - name = Component.translatable(entity.getType().getDescriptionId()).append(" "); + Packet mutatedPacket = null; + + if (hc_skipCheck) + return; + + if (sendPacket instanceof ClientboundSetEntityDataPacket dataPacket) + mutatedPacket = TryMutatePacket(dataPacket); + else if (sendPacket instanceof ClientboundBundlePacket bundledPackets){ + List> packets = new ArrayList<>(); + boolean doMutate = false; + + for (var p : bundledPackets.subPackets()){ + if (p instanceof ClientboundSetEntityDataPacket dataPacket && (dataPacket=TryMutatePacket(dataPacket)) != null){ + doMutate = true; + packets.add(dataPacket); } + else + packets.add(p); + } - var healthbar = ((HealthbarPreferences) this.player).createHealthbarText(health, maxHealth); - var healthTag = SynchedEntityData.DataValue.create(EntityAccessor.getCUSTOM_NAME(), Optional.of(name.append(healthbar))); + if (doMutate) + mutatedPacket = new ClientboundBundlePacket(packets); + } - Collections.addAll(trackedValues, visibleTag, healthTag); + if (mutatedPacket != null) { + this.hc_skipCheck = true; + this.send(mutatedPacket, listener); + this.hc_skipCheck = false; + ci.cancel(); // cancel the original packet going out + } + } - // Create a new packet in order to not mess with other network handlers - // since same packet object is sent to every player - var trackerUpdatePacket = new ClientboundSetEntityDataPacket(id, trackedValues); + /** + * @return A new packet, or null if the original needed not be mutated. + */ + @Unique + private @Nullable ClientboundSetEntityDataPacket TryMutatePacket(ClientboundSetEntityDataPacket packet) { + int id = packet.id(); + Entity entity = this.player.level().getEntity(id); + final var hb = ((HealthbarPreferences) this.player).healthcarePrefs(); + + if (!hb.enabled + || !(entity instanceof LivingEntity living) + || entity instanceof Player + || config.blacklistedEntities.contains(BuiltInRegistries.ENTITY_TYPE.getKey(entity.getType()).toString()) + || entity.isInvisibleTo(player) + ) { + return null; + } - this.hc_skipCheck = true; - this.send(trackerUpdatePacket, listener); - this.hc_skipCheck = false; - ci.cancel(); // cancel the original packet going out - } + var trackedValues = new ArrayList<>(packet.packedItems()); + + // Removing current custom name + var customName = trackedValues.stream().filter(value -> value.id() == 2).findFirst(); + + // Ensure name is visible only if mob is not too far away + boolean visible = (entity.distanceTo(player) < config.activationRange || entity.isCustomNameVisible()) && hb.alwaysVisible; + var visibleTag = SynchedEntityData.DataValue.create(EntityAccessor.getNAME_VISIBLE(), visible); + + float health = living.getHealth(); + float maxHealth = living.getMaxHealth(); + + MutableComponent name = Component.empty(); + if (customName.isPresent() && ((Optional) customName.get().value()).isPresent()) { + name = ((Optional) customName.get().value()).get().copy().append(" "); + } else if (entity.hasCustomName()) { + // @SpaceClouds42 saved me here, `.copy()` after getting custom name is essential! + name = entity.getCustomName().copy().append(" "); + } else if (hb.showType) { + name = Component.translatable(entity.getType().getDescriptionId()).append(" "); } + + var healthbar = ((HealthbarPreferences) this.player).createHealthbarText(health, maxHealth); + var healthTag = SynchedEntityData.DataValue.create(EntityAccessor.getCUSTOM_NAME(), Optional.of(name.append(healthbar))); + + Collections.addAll(trackedValues, visibleTag, healthTag); + + // Create a new packet in order to not mess with other network handlers + // since same packet object is sent to every player + return new ClientboundSetEntityDataPacket(id, trackedValues); } }