From 9e94991ec6e2642b2837781200a6e9ae5427f466 Mon Sep 17 00:00:00 2001 From: KJP12 Date: Sun, 9 Jan 2022 16:48:41 -0600 Subject: [PATCH] Allow configuration of what entities send health --- ...TrackerUpdateS2CPacketMixin_DataPatch.java | 24 +++---- .../samo_lego/golfiv/storage/GolfConfig.java | 72 ++++++++++++++++--- 2 files changed, 74 insertions(+), 22 deletions(-) diff --git a/src/main/java/org/samo_lego/golfiv/mixin/packets/EntityTrackerUpdateS2CPacketMixin_DataPatch.java b/src/main/java/org/samo_lego/golfiv/mixin/packets/EntityTrackerUpdateS2CPacketMixin_DataPatch.java index ab48976..b7b2a7b 100644 --- a/src/main/java/org/samo_lego/golfiv/mixin/packets/EntityTrackerUpdateS2CPacketMixin_DataPatch.java +++ b/src/main/java/org/samo_lego/golfiv/mixin/packets/EntityTrackerUpdateS2CPacketMixin_DataPatch.java @@ -4,10 +4,8 @@ import net.minecraft.entity.ItemEntity; import net.minecraft.entity.LivingEntity; import net.minecraft.entity.Saddleable; -import net.minecraft.entity.boss.WitherEntity; import net.minecraft.entity.data.DataTracker; import net.minecraft.entity.data.TrackedData; -import net.minecraft.entity.passive.IronGolemEntity; import net.minecraft.item.ItemStack; import net.minecraft.network.packet.s2c.play.EntityTrackerUpdateS2CPacket; import net.minecraft.util.math.MathHelper; @@ -53,26 +51,28 @@ public class EntityTrackerUpdateS2CPacketMixin_DataPatch { Entity entity = ((DataTrackerAccessor) tracker).getTrackedEntity(); - if (golfConfig.packet.removeHealthTags && entity instanceof LivingEntity && entity.isAlive() && !(entity instanceof Saddleable)) { + if (golfConfig.packet.removeHealthTags && entity instanceof LivingEntity livingEntity && entity.isAlive() && !(entity instanceof Saddleable)) { trackedValues.removeIf(trackedValue -> trackedValue.getData() == LIVING_ENTITY_HEALTH); trackedValues.removeIf(trackedValue -> trackedValue.getData() == PLAYER_ENTITY_ABSORPTION); - if (entity instanceof IronGolemEntity || entity instanceof WitherEntity) { - // Reinjects the health data aligned to quarters. - LivingEntity livingEntity = (LivingEntity) entity; + // This allows for iron golems to be visually broken, withers to have their shields, + // and wolves to show their health, while still spoofing the health to a variable degree. + // This is editable in GolfConfig as allowHealthTags. + if (golfConfig.packet.allowedHealthTags.containsKey(entity.getType())) { + float percentage = golfConfig.packet.allowedHealthTags.getFloat(entity.getType()); + float divider = livingEntity.getMaxHealth() * percentage; - // This takes away 1, divides by 25, floors, multiplies and add 1, - // spoofing health to be within 25 of the actual value. - // This allows for the iron golem to be visually broken, and for the wither to have its shield. - Float newHealth = MathHelper.floor((livingEntity.getHealth() - 1F) / 25F) * 25F + 1F; + // Shortcuts to livingEntity.getHealth on <= 1F. + Float newHealth = divider <= 1F ? livingEntity.getHealth() : + MathHelper.floor((livingEntity.getHealth() - 1F) / divider) * divider + 1F; DataTracker.Entry fakeEntry = new DataTracker.Entry<>(LIVING_ENTITY_HEALTH, newHealth); trackedValues.add(fakeEntry); } - } else if (golfConfig.packet.removeDroppedItemInfo && entity instanceof ItemEntity) { + } else if (golfConfig.packet.removeDroppedItemInfo && entity instanceof ItemEntity itemEntity) { boolean removed = trackedValues.removeIf(entry -> entry.getData() == ITEM_ENTITY_STACK); // Original item if (removed) { - ItemStack original = ((ItemEntity) entity).getStack(); + ItemStack original = itemEntity.getStack(); DataTracker.Entry fakeEntry = new DataTracker.Entry<>(ITEM_ENTITY_STACK, fakeStack(original, false)); trackedValues.add(fakeEntry); diff --git a/src/main/java/org/samo_lego/golfiv/storage/GolfConfig.java b/src/main/java/org/samo_lego/golfiv/storage/GolfConfig.java index 6515e88..b7ce3ed 100644 --- a/src/main/java/org/samo_lego/golfiv/storage/GolfConfig.java +++ b/src/main/java/org/samo_lego/golfiv/storage/GolfConfig.java @@ -2,15 +2,15 @@ import com.google.gson.Gson; import com.google.gson.GsonBuilder; +import com.google.gson.TypeAdapter; +import com.google.gson.annotations.JsonAdapter; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; +import it.unimi.dsi.fastutil.objects.Object2FloatMaps; +import it.unimi.dsi.fastutil.objects.Object2FloatOpenHashMap; +import net.minecraft.entity.EntityType; -import java.io.BufferedReader; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.OutputStreamWriter; -import java.io.Writer; +import java.io.*; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Arrays; @@ -112,16 +112,33 @@ public static class Packet { /** * Removes entity health data from packets * sent to client. - * + *

* Status: working. */ public boolean removeHealthTags = true; + public final String _comment_allowedHealthTags_1 = "// Allows health tags for certain entities."; + public final String _comment_allowedHealthTags_2 = "// This maps entity ID to percentage as decimal."; + + /** + * Entities that must have health sent to render correctly. + *

+ * K -> Entities to allow health of. + * V -> Increments by percentage of health to allow. + *

+ * Implied by default is 1F, or alive and dead. + */ + @JsonAdapter(UnnecessaryEntityTypeMapAdapter.class) + public Object2FloatOpenHashMap> allowedHealthTags = new Object2FloatOpenHashMap<>( + new EntityType[]{EntityType.WOLF, EntityType.WITHER, EntityType.IRON_GOLEM}, + new float[]{0F, 0.5F, 0.25F} + ); + /** * Removes entity equipment tags from * packets. Players will still see if item is enchanted, * but won't get the durability or stack size information. - * + *

* Status: working. */ public boolean removeEquipmentTags = true; @@ -250,4 +267,39 @@ public void saveConfig(File configFile) { logError("Problem occurred when saving config: " + e.getMessage()); } } + + /** + * Adapts {@link EntityType} between it and the identifier. + *

+ * Unnecessary, as map-level shouldn't be needed to begin with, + * yet arbitrary unforeseen restrictions require this anyways. + * + * @author KJP12 + */ + private static final class UnnecessaryEntityTypeMapAdapter extends TypeAdapter>> { + + @Override + public void write(JsonWriter out, Object2FloatOpenHashMap> value) throws IOException { + out.beginObject(); + var itr = Object2FloatMaps.fastIterator(value); + while (itr.hasNext()) { + var entry = itr.next(); + out.name(EntityType.getId(entry.getKey()).toString()); + out.value(entry.getFloatValue()); + } + out.endObject(); + } + + @Override + public Object2FloatOpenHashMap> read(JsonReader in) throws IOException { + in.beginObject(); + var map = new Object2FloatOpenHashMap>(); + while (in.hasNext()) { + map.put(EntityType.get(in.nextName()).orElseThrow(() -> new IOException("Invalid entity type.")), + (float) in.nextDouble()); + } + in.endObject(); + return map; + } + } }