feat: Add dye logger for armor stands

This commit is contained in:
Linnea Gräf
2025-03-15 17:52:35 +01:00
parent ce2e4f48d4
commit 03cf4e465c
5 changed files with 92 additions and 28 deletions

View File

@@ -12,6 +12,7 @@ import net.minecraft.entity.Entity;
import net.minecraft.entity.LivingEntity;
import net.minecraft.network.ClientConnection;
import net.minecraft.network.packet.s2c.play.EntityAttributesS2CPacket;
import net.minecraft.network.packet.s2c.play.EntityEquipmentUpdateS2CPacket;
import net.minecraft.network.packet.s2c.play.EntityTrackerUpdateS2CPacket;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
@@ -22,21 +23,26 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(ClientPlayNetworkHandler.class)
public abstract class EntityUpdateEventListener extends ClientCommonNetworkHandler {
@Shadow
private ClientWorld world;
@Shadow
private ClientWorld world;
protected EntityUpdateEventListener(MinecraftClient client, ClientConnection connection, ClientConnectionState connectionState) {
super(client, connection, connectionState);
}
protected EntityUpdateEventListener(MinecraftClient client, ClientConnection connection, ClientConnectionState connectionState) {
super(client, connection, connectionState);
}
@Inject(method = "onEntityAttributes", at = @At("TAIL"))
private void onAttributeUpdate(EntityAttributesS2CPacket packet, CallbackInfo ci) {
EntityUpdateEvent.Companion.publish(new EntityUpdateEvent.AttributeUpdate(
(LivingEntity) world.getEntityById(packet.getEntityId()), packet.getEntries()));
}
@Inject(method = "onEntityEquipmentUpdate", at = @At(value = "INVOKE", target = "Ljava/util/List;forEach(Ljava/util/function/Consumer;)V", shift = At.Shift.AFTER))
private void onEquipmentUpdate(EntityEquipmentUpdateS2CPacket packet, CallbackInfo ci, @Local LivingEntity entity) {
EntityUpdateEvent.Companion.publish(new EntityUpdateEvent.EquipmentUpdate(entity, packet.getEquipmentList()));
}
@Inject(method = "onEntityTrackerUpdate", at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/data/DataTracker;writeUpdatedEntries(Ljava/util/List;)V", shift = At.Shift.AFTER))
private void onEntityTracker(EntityTrackerUpdateS2CPacket packet, CallbackInfo ci, @Local Entity entity) {
EntityUpdateEvent.Companion.publish(new EntityUpdateEvent.TrackedDataUpdate(entity, packet.trackedValues()));
}
@Inject(method = "onEntityAttributes", at = @At("TAIL"))
private void onAttributeUpdate(EntityAttributesS2CPacket packet, CallbackInfo ci) {
EntityUpdateEvent.Companion.publish(new EntityUpdateEvent.AttributeUpdate(
(LivingEntity) world.getEntityById(packet.getEntityId()), packet.getEntries()));
}
@Inject(method = "onEntityTrackerUpdate", at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/data/DataTracker;writeUpdatedEntries(Ljava/util/List;)V", shift = At.Shift.AFTER))
private void onEntityTracker(EntityTrackerUpdateS2CPacket packet, CallbackInfo ci, @Local Entity entity) {
EntityUpdateEvent.Companion.publish(new EntityUpdateEvent.TrackedDataUpdate(entity, packet.trackedValues()));
}
}

View File

@@ -120,9 +120,8 @@ object Firmament {
@JvmStatic
fun onClientInitialize() {
FeatureManager.subscribeEvents()
var tick = 0
ClientTickEvents.END_CLIENT_TICK.register(ClientTickEvents.EndTick { instance ->
TickEvent.publish(TickEvent(tick++))
TickEvent.publish(TickEvent(MC.currentTick++))
})
IDataHolder.registerEvents()
RepoManager.initialize()

View File

@@ -1,9 +1,11 @@
package moe.nea.firmament.events
import com.mojang.datafixers.util.Pair
import net.minecraft.entity.Entity
import net.minecraft.entity.EquipmentSlot
import net.minecraft.entity.LivingEntity
import net.minecraft.entity.data.DataTracker
import net.minecraft.item.ItemStack
import net.minecraft.network.packet.s2c.play.EntityAttributesS2CPacket
/**
@@ -13,19 +15,24 @@ import net.minecraft.network.packet.s2c.play.EntityAttributesS2CPacket
* *after* the values have been applied to the entity.
*/
sealed class EntityUpdateEvent : FirmamentEvent() {
companion object : FirmamentEventBus<EntityUpdateEvent>()
companion object : FirmamentEventBus<EntityUpdateEvent>()
abstract val entity: Entity
abstract val entity: Entity
data class AttributeUpdate(
override val entity: LivingEntity,
val attributes: List<EntityAttributesS2CPacket.Entry>,
) : EntityUpdateEvent()
data class AttributeUpdate(
override val entity: LivingEntity,
val attributes: List<EntityAttributesS2CPacket.Entry>,
) : EntityUpdateEvent()
data class TrackedDataUpdate(
override val entity: Entity,
val trackedValues: List<DataTracker.SerializedEntry<*>>,
) : EntityUpdateEvent()
data class TrackedDataUpdate(
override val entity: Entity,
val trackedValues: List<DataTracker.SerializedEntry<*>>,
) : EntityUpdateEvent()
// TODO: onEntityPassengersSet, onEntityAttach?, onEntityEquipmentUpdate, onEntityStatusEffect
data class EquipmentUpdate(
override val entity: Entity,
val newEquipment: List<Pair<EquipmentSlot, ItemStack>>,
) : EntityUpdateEvent()
// TODO: onEntityPassengersSet, onEntityAttach?, onEntityStatusEffect
}

View File

@@ -0,0 +1,51 @@
package moe.nea.firmament.features.debug
import net.minecraft.component.DataComponentTypes
import net.minecraft.entity.Entity
import moe.nea.firmament.annotations.Subscribe
import moe.nea.firmament.commands.thenExecute
import moe.nea.firmament.commands.thenLiteral
import moe.nea.firmament.events.CommandEvent
import moe.nea.firmament.events.EntityUpdateEvent
import moe.nea.firmament.util.MC
import moe.nea.firmament.util.skyBlockId
import moe.nea.firmament.util.tr
object AnimatedClothingScanner {
var observedEntity: Entity? = null
@OptIn(ExperimentalStdlibApi::class)
@Subscribe
fun onUpdate(event: EntityUpdateEvent) {
if (event.entity != observedEntity) return
if (event is EntityUpdateEvent.EquipmentUpdate) {
event.newEquipment.forEach {
val id = it.second.skyBlockId?.neuItem
val colour = it.second.get(DataComponentTypes.DYED_COLOR)
?.rgb?.toHexString(HexFormat.UpperCase)
?.let { " #$it" } ?: ""
MC.sendChat(tr("firmament.fitstealer.update",
"[FIT CHECK][${MC.currentTick}] ${it.first.asString()} => ${id}${colour}"))
}
}
}
@Subscribe
fun onSubCommand(event: CommandEvent.SubCommand) {
event.subcommand("dev") {
thenLiteral("stealthisfit") {
thenExecute {
observedEntity =
if (observedEntity == null) MC.instance.targetedEntity else null
MC.sendChat(
observedEntity?.let {
tr("firmament.fitstealer.targeted", "Observing the equipment of ${it.name}.")
} ?: tr("firmament.fitstealer.targetlost", "No longer logging equipment."),
)
}
}
}
}
}

View File

@@ -113,6 +113,7 @@ object MC {
val defaultRegistries: RegistryWrapper.WrapperLookup by lazy { BuiltinRegistries.createWrapperLookup() }
inline val currentOrDefaultRegistries get() = currentRegistries ?: defaultRegistries
val defaultItems: RegistryWrapper.Impl<Item> by lazy { defaultRegistries.getOrThrow(RegistryKeys.ITEM) }
var currentTick = 0
var lastWorld: World? = null
get() {
field = world ?: field