diff options
Diffstat (limited to 'src/main/java/moe/nea/firmament/mixins')
37 files changed, 741 insertions, 133 deletions
diff --git a/src/main/java/moe/nea/firmament/mixins/AlwaysDisplayFirmamentClientCommandErrors.java b/src/main/java/moe/nea/firmament/mixins/AlwaysDisplayFirmamentClientCommandErrors.java new file mode 100644 index 0000000..59769c6 --- /dev/null +++ b/src/main/java/moe/nea/firmament/mixins/AlwaysDisplayFirmamentClientCommandErrors.java @@ -0,0 +1,18 @@ +package moe.nea.firmament.mixins; + +import com.llamalad7.mixinextras.injector.ModifyExpressionValue; +import com.llamalad7.mixinextras.sugar.Local; +import net.fabricmc.fabric.impl.command.client.ClientCommandInternals; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; + +@Mixin(ClientCommandInternals.class) +public class AlwaysDisplayFirmamentClientCommandErrors { + @ModifyExpressionValue(method = "executeCommand", at = @At(value = "INVOKE", target = "Lnet/fabricmc/fabric/impl/command/client/ClientCommandInternals;isIgnoredException(Lcom/mojang/brigadier/exceptions/CommandExceptionType;)Z")) + private static boolean markFirmamentExceptionsAsNotIgnores(boolean original, @Local(argsOnly = true) String command) { + if (command.startsWith("firm ") || command.equals("firm") || command.startsWith("firmament ") || command.equals("firmament")) { + return false; + } + return original; + } +} diff --git a/src/main/java/moe/nea/firmament/mixins/AppendRepoAsResourcePack.java b/src/main/java/moe/nea/firmament/mixins/AppendRepoAsResourcePack.java index 22ce991..d8e35d7 100644 --- a/src/main/java/moe/nea/firmament/mixins/AppendRepoAsResourcePack.java +++ b/src/main/java/moe/nea/firmament/mixins/AppendRepoAsResourcePack.java @@ -1,28 +1,34 @@ package moe.nea.firmament.mixins; +import com.llamalad7.mixinextras.sugar.Local; import moe.nea.firmament.repo.RepoModResourcePack; import net.fabricmc.fabric.api.resource.ModResourcePack; +import net.fabricmc.fabric.impl.resource.loader.ModResourcePackSorter; import net.fabricmc.fabric.impl.resource.loader.ModResourcePackUtil; +import net.fabricmc.loader.api.FabricLoader; import net.minecraft.resource.ResourceType; import org.jetbrains.annotations.Nullable; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; import java.util.List; @Mixin(ModResourcePackUtil.class) public class AppendRepoAsResourcePack { - @Inject(method = "appendModResourcePacks", at = @At("TAIL")) - private static void onAppendModResourcePack( - List<ModResourcePack> packs, - ResourceType type, - @Nullable String subPath, - CallbackInfo ci - ) { - RepoModResourcePack.Companion.append(packs); - } + @Inject( + method = "getModResourcePacks", + at = @At(value = "INVOKE", target = "Lnet/fabricmc/fabric/impl/resource/loader/ModResourcePackSorter;getPacks()Ljava/util/List;"), + require = 0 + ) + private static void onAppendModResourcePack( + FabricLoader fabricLoader, ResourceType type, @Nullable String subPath, CallbackInfoReturnable<List<ModResourcePack>> cir, + @Local ModResourcePackSorter sorter + ) { + RepoModResourcePack.Companion.append(sorter); + } } diff --git a/src/main/java/moe/nea/firmament/mixins/CopyChatPatch.java b/src/main/java/moe/nea/firmament/mixins/CopyChatPatch.java new file mode 100644 index 0000000..6996818 --- /dev/null +++ b/src/main/java/moe/nea/firmament/mixins/CopyChatPatch.java @@ -0,0 +1,44 @@ +package moe.nea.firmament.mixins; + +import moe.nea.firmament.features.chat.CopyChat; +import moe.nea.firmament.mixins.accessor.AccessorChatHud; +import moe.nea.firmament.util.ClipboardUtils; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.gui.hud.ChatHud; +import net.minecraft.client.gui.hud.ChatHudLine; +import net.minecraft.client.gui.screen.ChatScreen; +import net.minecraft.text.Text; +import net.minecraft.util.Formatting; +import net.minecraft.util.math.MathHelper; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; +import java.util.List; + +@Mixin(ChatScreen.class) +public class CopyChatPatch { + @Inject(method = "mouseClicked", at = @At("HEAD"), cancellable = true) + private void onRightClick(double mouseX, double mouseY, int button, CallbackInfoReturnable<Boolean> cir) throws NoSuchFieldException, IllegalAccessException { + if (button != 1 || !CopyChat.TConfig.INSTANCE.getCopyChat()) return; + MinecraftClient client = MinecraftClient.getInstance(); + ChatHud chatHud = client.inGameHud.getChatHud(); + int lineIndex = getChatLineIndex(chatHud, mouseY); + if (lineIndex < 0) return; + List<ChatHudLine.Visible> visible = ((AccessorChatHud) chatHud).getVisibleMessages_firmament(); + if (lineIndex >= visible.size()) return; + ChatHudLine.Visible line = visible.get(lineIndex); + String text = CopyChat.INSTANCE.orderedTextToString(line.content()); + ClipboardUtils.INSTANCE.setTextContent(text); + chatHud.addMessage(Text.literal("Copied: ").append(text).formatted(Formatting.GRAY)); + cir.setReturnValue(true); + cir.cancel(); + } + + @Unique + private int getChatLineIndex(ChatHud chatHud, double mouseY) { + double chatLineY = ((AccessorChatHud) chatHud).toChatLineY_firmament(mouseY); + return MathHelper.floor(chatLineY + ((AccessorChatHud) chatHud).getScrolledLines_firmament()); + } +} diff --git a/src/main/java/moe/nea/firmament/mixins/DisableHurtCam.java b/src/main/java/moe/nea/firmament/mixins/DisableHurtCam.java new file mode 100644 index 0000000..ed7a2d4 --- /dev/null +++ b/src/main/java/moe/nea/firmament/mixins/DisableHurtCam.java @@ -0,0 +1,18 @@ +package moe.nea.firmament.mixins; + +import com.llamalad7.mixinextras.injector.ModifyExpressionValue; +import moe.nea.firmament.features.fixes.Fixes; +import net.minecraft.client.render.GameRenderer; +import org.objectweb.asm.Opcodes; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; + +@Mixin(GameRenderer.class) +public class DisableHurtCam { + @ModifyExpressionValue(method = "tiltViewWhenHurt", at = @At(value = "FIELD", target = "Lnet/minecraft/entity/LivingEntity;hurtTime:I", opcode = Opcodes.GETFIELD)) + private int replaceHurtTime(int original) { + if (Fixes.TConfig.INSTANCE.getNoHurtCam()) + return 0; + return original; + } +} diff --git a/src/main/java/moe/nea/firmament/mixins/DispatchMouseInputEventsPatch.java b/src/main/java/moe/nea/firmament/mixins/DispatchMouseInputEventsPatch.java new file mode 100644 index 0000000..f1b07bb --- /dev/null +++ b/src/main/java/moe/nea/firmament/mixins/DispatchMouseInputEventsPatch.java @@ -0,0 +1,17 @@ +package moe.nea.firmament.mixins; + +import com.llamalad7.mixinextras.injector.v2.WrapWithCondition; +import moe.nea.firmament.events.WorldMouseMoveEvent; +import net.minecraft.client.Mouse; +import net.minecraft.client.network.ClientPlayerEntity; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; + +@Mixin(Mouse.class) +public class DispatchMouseInputEventsPatch { + @WrapWithCondition(method = "updateMouse", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/network/ClientPlayerEntity;changeLookDirection(DD)V")) + public boolean onRotatePlayer(ClientPlayerEntity instance, double deltaX, double deltaY) { + var event = WorldMouseMoveEvent.Companion.publish(new WorldMouseMoveEvent(deltaX, deltaY)); + return !event.getCancelled(); + } +} diff --git a/src/main/java/moe/nea/firmament/mixins/EntityUpdateEventListener.java b/src/main/java/moe/nea/firmament/mixins/EntityUpdateEventListener.java index c2d6e46..d956da9 100644 --- a/src/main/java/moe/nea/firmament/mixins/EntityUpdateEventListener.java +++ b/src/main/java/moe/nea/firmament/mixins/EntityUpdateEventListener.java @@ -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())); + } } diff --git a/src/main/java/moe/nea/firmament/mixins/FirmKeybindsInVanillaControlsPatch.java b/src/main/java/moe/nea/firmament/mixins/FirmKeybindsInVanillaControlsPatch.java index b386604..699d5b7 100644 --- a/src/main/java/moe/nea/firmament/mixins/FirmKeybindsInVanillaControlsPatch.java +++ b/src/main/java/moe/nea/firmament/mixins/FirmKeybindsInVanillaControlsPatch.java @@ -51,7 +51,7 @@ public class FirmKeybindsInVanillaControlsPatch { var config = FirmamentKeyBindings.INSTANCE.getKeyBindings().get(binding); if (config == null) return; resetButton.active = false; - editButton.setMessage(Text.translatable("firmament.keybinding.external", config.value.format())); + editButton.setMessage(Text.translatable("firmament.keybinding.external", config.getValue().format())); ci.cancel(); } diff --git a/src/main/java/moe/nea/firmament/mixins/HideStatusEffectsPatch.java b/src/main/java/moe/nea/firmament/mixins/HideStatusEffectsPatch.java new file mode 100644 index 0000000..c5af8b6 --- /dev/null +++ b/src/main/java/moe/nea/firmament/mixins/HideStatusEffectsPatch.java @@ -0,0 +1,29 @@ +package moe.nea.firmament.mixins; + +import com.llamalad7.mixinextras.injector.v2.WrapWithCondition; +import moe.nea.firmament.features.fixes.Fixes; +import net.minecraft.client.gui.DrawContext; +import net.minecraft.client.gui.screen.ingame.InventoryScreen; +import net.minecraft.client.gui.screen.ingame.StatusEffectsDisplay; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +@Mixin(InventoryScreen.class) +public abstract class HideStatusEffectsPatch { + @Shadow + public abstract boolean shouldHideStatusEffectHud(); + + @Inject(method = "shouldHideStatusEffectHud", at = @At("HEAD"), cancellable = true) + private void hideStatusEffects(CallbackInfoReturnable<Boolean> cir) { + cir.setReturnValue(!Fixes.TConfig.INSTANCE.getHidePotionEffects()); + } + + @WrapWithCondition(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/screen/ingame/StatusEffectsDisplay;drawStatusEffects(Lnet/minecraft/client/gui/DrawContext;IIF)V")) + private boolean conditionalRenderStatuses(StatusEffectsDisplay instance, DrawContext context, int mouseX, int mouseY, float tickDelta) { + return shouldHideStatusEffectHud() || !Fixes.TConfig.INSTANCE.getHidePotionEffects(); + } + +} diff --git a/src/main/java/moe/nea/firmament/mixins/HudRenderEventsPatch.java b/src/main/java/moe/nea/firmament/mixins/HudRenderEventsPatch.java index 85c0462..49e86fb 100644 --- a/src/main/java/moe/nea/firmament/mixins/HudRenderEventsPatch.java +++ b/src/main/java/moe/nea/firmament/mixins/HudRenderEventsPatch.java @@ -4,6 +4,7 @@ package moe.nea.firmament.mixins; import moe.nea.firmament.events.HotbarItemRenderEvent; import moe.nea.firmament.events.HudRenderEvent; +import moe.nea.firmament.features.fixes.Fixes; import net.minecraft.client.gui.DrawContext; import net.minecraft.client.gui.hud.InGameHud; import net.minecraft.client.render.RenderTickCounter; @@ -26,4 +27,10 @@ public class HudRenderEventsPatch { if (stack != null && !stack.isEmpty()) HotbarItemRenderEvent.Companion.publish(new HotbarItemRenderEvent(stack, context, x, y, tickCounter)); } + + @Inject(method = "renderStatusEffectOverlay", at = @At("HEAD"), cancellable = true) + public void hideStatusEffects(CallbackInfo ci) { + if (Fixes.TConfig.INSTANCE.getHidePotionEffectsHud()) ci.cancel(); + } + } diff --git a/src/main/java/moe/nea/firmament/mixins/KeyPressInWorldEventPatch.java b/src/main/java/moe/nea/firmament/mixins/KeyPressInWorldEventPatch.java index 48f3c23..d2b3f91 100644 --- a/src/main/java/moe/nea/firmament/mixins/KeyPressInWorldEventPatch.java +++ b/src/main/java/moe/nea/firmament/mixins/KeyPressInWorldEventPatch.java @@ -2,18 +2,19 @@ package moe.nea.firmament.mixins; +import com.llamalad7.mixinextras.injector.v2.WrapWithCondition; import moe.nea.firmament.events.WorldKeyboardEvent; import net.minecraft.client.Keyboard; +import net.minecraft.client.util.InputUtil; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @Mixin(Keyboard.class) public class KeyPressInWorldEventPatch { - @Inject(method = "onKey", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/option/KeyBinding;onKeyPressed(Lnet/minecraft/client/util/InputUtil$Key;)V")) - public void onKeyBoardInWorld(long window, int key, int scancode, int action, int modifiers, CallbackInfo ci) { - WorldKeyboardEvent.Companion.publish(new WorldKeyboardEvent(key, scancode, modifiers)); - } + @WrapWithCondition(method = "onKey", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/option/KeyBinding;onKeyPressed(Lnet/minecraft/client/util/InputUtil$Key;)V")) + public boolean onKeyBoardInWorld(InputUtil.Key key, long window, int _key, int scancode, int action, int modifiers) { + var event = WorldKeyboardEvent.Companion.publish(new WorldKeyboardEvent(_key, scancode, modifiers)); + return !event.getCancelled(); + } } diff --git a/src/main/java/moe/nea/firmament/mixins/LenientProfileComponentPatch.java b/src/main/java/moe/nea/firmament/mixins/LenientProfileComponentPatch.java deleted file mode 100644 index 76b34ba..0000000 --- a/src/main/java/moe/nea/firmament/mixins/LenientProfileComponentPatch.java +++ /dev/null @@ -1,25 +0,0 @@ - -package moe.nea.firmament.mixins; - -import com.llamalad7.mixinextras.injector.ModifyExpressionValue; -import com.mojang.serialization.Codec; -import com.mojang.serialization.DataResult; -import com.mojang.serialization.Lifecycle; -import com.mojang.util.UndashedUuid; -import moe.nea.firmament.util.json.FirmCodecs; -import net.minecraft.component.type.ProfileComponent; -import net.minecraft.util.Uuids; -import org.objectweb.asm.Opcodes; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; - -import java.util.UUID; - -@Mixin(ProfileComponent.class) -public class LenientProfileComponentPatch { - // lambda in RecordCodecBuilder.create for BASE_CODEC - @ModifyExpressionValue(method = "method_57508", at = @At(value = "FIELD", opcode = Opcodes.GETSTATIC, target = "Lnet/minecraft/util/Uuids;INT_STREAM_CODEC:Lcom/mojang/serialization/Codec;")) - private static Codec<UUID> onStaticInit(Codec<UUID> original) { - return FirmCodecs.UUID_LENIENT_PREFER_INT_STREAM; - } -} diff --git a/src/main/java/moe/nea/firmament/mixins/MinecraftInitLevelListener.java b/src/main/java/moe/nea/firmament/mixins/MinecraftInitLevelListener.java new file mode 100644 index 0000000..1673987 --- /dev/null +++ b/src/main/java/moe/nea/firmament/mixins/MinecraftInitLevelListener.java @@ -0,0 +1,26 @@ +package moe.nea.firmament.mixins; + +import moe.nea.firmament.util.mc.InitLevel; +import net.minecraft.client.MinecraftClient; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(MinecraftClient.class) +public class MinecraftInitLevelListener { + @Inject(method = "<init>", at = @At(value = "INVOKE", target = "Lcom/mojang/blaze3d/systems/RenderSystem;initBackendSystem()Lnet/minecraft/util/TimeSupplier$Nanoseconds;")) + private void onInitRenderBackend(CallbackInfo ci) { + InitLevel.bump(InitLevel.RENDER_INIT); + } + + @Inject(method = "<init>", at = @At(value = "INVOKE", target = "Lcom/mojang/blaze3d/systems/RenderSystem;initRenderer(JIZLjava/util/function/BiFunction;Z)V")) + private void onInitRender(CallbackInfo ci) { + InitLevel.bump(InitLevel.RENDER); + } + + @Inject(method = "<init>", at = @At(value = "TAIL")) + private void onFinishedLoading(CallbackInfo ci) { + InitLevel.bump(InitLevel.MAIN_MENU); + } +} diff --git a/src/main/java/moe/nea/firmament/mixins/MixinHandledScreen.java b/src/main/java/moe/nea/firmament/mixins/MixinHandledScreen.java index e607ba3..43aec40 100644 --- a/src/main/java/moe/nea/firmament/mixins/MixinHandledScreen.java +++ b/src/main/java/moe/nea/firmament/mixins/MixinHandledScreen.java @@ -4,8 +4,11 @@ package moe.nea.firmament.mixins; import com.llamalad7.mixinextras.injector.wrapoperation.Operation; import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; -import com.llamalad7.mixinextras.sugar.Local; -import moe.nea.firmament.events.*; +import moe.nea.firmament.events.HandledScreenClickEvent; +import moe.nea.firmament.events.HandledScreenForegroundEvent; +import moe.nea.firmament.events.HandledScreenKeyPressedEvent; +import moe.nea.firmament.events.IsSlotProtectedEvent; +import moe.nea.firmament.events.SlotRenderEvents; import net.minecraft.client.gui.DrawContext; import net.minecraft.client.gui.screen.ingame.HandledScreen; import net.minecraft.entity.player.PlayerInventory; @@ -22,9 +25,6 @@ import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; -import org.spongepowered.asm.mixin.injection.callback.LocalCapture; - -import java.util.Iterator; @Mixin(value = HandledScreen.class, priority = 990) public abstract class MixinHandledScreen<T extends ScreenHandler> { @@ -74,17 +74,17 @@ public abstract class MixinHandledScreen<T extends ScreenHandler> { public void onMouseClickedSlot(Slot slot, int slotId, int button, SlotActionType actionType, CallbackInfo ci) { if (slotId == -999 && getScreenHandler() != null && actionType == SlotActionType.PICKUP) { // -999 is code for "clicked outside the main window" ItemStack cursorStack = getScreenHandler().getCursorStack(); - if (cursorStack != null && IsSlotProtectedEvent.shouldBlockInteraction(slot, SlotActionType.THROW, cursorStack)) { + if (cursorStack != null && IsSlotProtectedEvent.shouldBlockInteraction(slot, SlotActionType.THROW, IsSlotProtectedEvent.MoveOrigin.INVENTORY_MOVE, cursorStack)) { ci.cancel(); return; } } - if (IsSlotProtectedEvent.shouldBlockInteraction(slot, actionType)) { + if (IsSlotProtectedEvent.shouldBlockInteraction(slot, actionType, IsSlotProtectedEvent.MoveOrigin.INVENTORY_MOVE)) { ci.cancel(); return; } if (actionType == SlotActionType.SWAP && 0 <= button && button < 9) { - if (IsSlotProtectedEvent.shouldBlockInteraction(new Slot(playerInventory, button, 0, 0), actionType)) { + if (IsSlotProtectedEvent.shouldBlockInteraction(new Slot(playerInventory, button, 0, 0), actionType, IsSlotProtectedEvent.MoveOrigin.INVENTORY_MOVE)) { ci.cancel(); } } diff --git a/src/main/java/moe/nea/firmament/mixins/MixinRecipeBookScreen.java b/src/main/java/moe/nea/firmament/mixins/MixinRecipeBookScreen.java new file mode 100644 index 0000000..2dbe738 --- /dev/null +++ b/src/main/java/moe/nea/firmament/mixins/MixinRecipeBookScreen.java @@ -0,0 +1,16 @@ +package moe.nea.firmament.mixins; + +import moe.nea.firmament.features.fixes.Fixes; +import net.minecraft.client.gui.screen.ingame.RecipeBookScreen; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(value = RecipeBookScreen.class, priority = 999) +public class MixinRecipeBookScreen { + @Inject(method = "addRecipeBook", at = @At("HEAD"), cancellable = true) + public void addRecipeBook(CallbackInfo ci) { + if (Fixes.TConfig.INSTANCE.getHideRecipeBook()) ci.cancel(); + } +} diff --git a/src/main/java/moe/nea/firmament/mixins/PlayerDropEventPatch.java b/src/main/java/moe/nea/firmament/mixins/PlayerDropEventPatch.java index 9a4626f..f07604e 100644 --- a/src/main/java/moe/nea/firmament/mixins/PlayerDropEventPatch.java +++ b/src/main/java/moe/nea/firmament/mixins/PlayerDropEventPatch.java @@ -14,15 +14,15 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; @Mixin(ClientPlayerEntity.class) public abstract class PlayerDropEventPatch extends PlayerEntity { - public PlayerDropEventPatch() { - super(null, null, 0, null); - } + public PlayerDropEventPatch() { + super(null, null, 0, null); + } - @Inject(method = "dropSelectedItem", at = @At("HEAD"), cancellable = true) - public void onDropSelectedItem(boolean entireStack, CallbackInfoReturnable<Boolean> cir) { - Slot fakeSlot = new Slot(getInventory(), getInventory().selectedSlot, 0, 0); - if (IsSlotProtectedEvent.shouldBlockInteraction(fakeSlot, SlotActionType.THROW)) { - cir.setReturnValue(false); - } - } + @Inject(method = "dropSelectedItem", at = @At("HEAD"), cancellable = true) + public void onDropSelectedItem(boolean entireStack, CallbackInfoReturnable<Boolean> cir) { + Slot fakeSlot = new Slot(getInventory(), getInventory().getSelectedSlot(), 0, 0); + if (IsSlotProtectedEvent.shouldBlockInteraction(fakeSlot, SlotActionType.THROW, IsSlotProtectedEvent.MoveOrigin.DROP_FROM_HOTBAR)) { + cir.setReturnValue(false); + } + } } diff --git a/src/main/java/moe/nea/firmament/mixins/PropertySignatureIgnorePatch.java b/src/main/java/moe/nea/firmament/mixins/PropertySignatureIgnorePatch.java deleted file mode 100644 index e7331c5..0000000 --- a/src/main/java/moe/nea/firmament/mixins/PropertySignatureIgnorePatch.java +++ /dev/null @@ -1,36 +0,0 @@ - - -package moe.nea.firmament.mixins; - -import com.mojang.authlib.properties.Property; -import moe.nea.firmament.features.fixes.Fixes; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; - -import java.security.PublicKey; - -@Mixin(value = Property.class, remap = false) -public class PropertySignatureIgnorePatch { - @Inject(method = "isSignatureValid", cancellable = true, at = @At("HEAD"), remap = false) - public void onValidateSignature(PublicKey publicKey, CallbackInfoReturnable<Boolean> cir) { - if (Fixes.TConfig.INSTANCE.getFixUnsignedPlayerSkins()) { - cir.setReturnValue(true); - } - } - - @Inject(method = "signature", cancellable = true, at = @At("HEAD"), remap = false) - public void returnEmptySignatureInsteadOfNull(CallbackInfoReturnable<String> cir) { - if (Fixes.TConfig.INSTANCE.getFixUnsignedPlayerSkins()) { - cir.setReturnValue(""); - } - } - - @Inject(method = "hasSignature", cancellable = true, at = @At("HEAD"), remap = false) - public void onHasSignature(CallbackInfoReturnable<Boolean> cir) { - if (Fixes.TConfig.INSTANCE.getFixUnsignedPlayerSkins()) { - cir.setReturnValue(true); - } - } -} diff --git a/src/main/java/moe/nea/firmament/mixins/SaveOriginalCommandTreePacket.java b/src/main/java/moe/nea/firmament/mixins/SaveOriginalCommandTreePacket.java new file mode 100644 index 0000000..2f2f188 --- /dev/null +++ b/src/main/java/moe/nea/firmament/mixins/SaveOriginalCommandTreePacket.java @@ -0,0 +1,17 @@ +package moe.nea.firmament.mixins; + +import moe.nea.firmament.features.chat.QuickCommands; +import net.minecraft.client.network.ClientPlayNetworkHandler; +import net.minecraft.network.packet.s2c.play.CommandTreeS2CPacket; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(ClientPlayNetworkHandler.class) +public class SaveOriginalCommandTreePacket { + @Inject(method = "onCommandTree", at = @At(value = "RETURN")) + private void saveUnmodifiedCommandTree(CommandTreeS2CPacket packet, CallbackInfo ci) { + QuickCommands.INSTANCE.setLastReceivedTreePacket(packet); + } +} diff --git a/src/main/java/moe/nea/firmament/mixins/SlotUpdateListener.java b/src/main/java/moe/nea/firmament/mixins/SlotUpdateListener.java index 06ecbd4..a4ae931 100644 --- a/src/main/java/moe/nea/firmament/mixins/SlotUpdateListener.java +++ b/src/main/java/moe/nea/firmament/mixins/SlotUpdateListener.java @@ -43,11 +43,11 @@ public abstract class SlotUpdateListener extends ClientCommonNetworkHandler { private void onMultiSlotUpdate(InventoryS2CPacket packet, CallbackInfo ci) { var player = this.client.player; assert player != null; - if (packet.getSyncId() == 0) { - PlayerInventoryUpdate.Companion.publish(new PlayerInventoryUpdate.Multi(packet.getContents())); - } else if (packet.getSyncId() == player.currentScreenHandler.syncId) { + if (packet.syncId() == 0) { + PlayerInventoryUpdate.Companion.publish(new PlayerInventoryUpdate.Multi(packet.contents())); + } else if (packet.syncId() == player.currentScreenHandler.syncId) { ChestInventoryUpdateEvent.Companion.publish( - new ChestInventoryUpdateEvent.Multi(packet.getContents()) + new ChestInventoryUpdateEvent.Multi(packet.contents()) ); } } diff --git a/src/main/java/moe/nea/firmament/mixins/SoundReceiveEventPatch.java b/src/main/java/moe/nea/firmament/mixins/SoundReceiveEventPatch.java index 5c52d70..b8cba80 100644 --- a/src/main/java/moe/nea/firmament/mixins/SoundReceiveEventPatch.java +++ b/src/main/java/moe/nea/firmament/mixins/SoundReceiveEventPatch.java @@ -1,30 +1,32 @@ package moe.nea.firmament.mixins; +import com.llamalad7.mixinextras.injector.v2.WrapWithCondition; import moe.nea.firmament.events.SoundReceiveEvent; import net.minecraft.client.network.ClientPlayNetworkHandler; -import net.minecraft.network.packet.s2c.play.PlaySoundS2CPacket; +import net.minecraft.client.world.ClientWorld; +import net.minecraft.entity.Entity; +import net.minecraft.registry.entry.RegistryEntry; +import net.minecraft.sound.SoundCategory; +import net.minecraft.sound.SoundEvent; import net.minecraft.util.math.Vec3d; +import org.jetbrains.annotations.Nullable; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @Mixin(ClientPlayNetworkHandler.class) public class SoundReceiveEventPatch { - @Inject(method = "onPlaySound", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/world/ClientWorld;playSound(Lnet/minecraft/entity/player/PlayerEntity;DDDLnet/minecraft/registry/entry/RegistryEntry;Lnet/minecraft/sound/SoundCategory;FFJ)V"), cancellable = true) - private void postEventWhenSoundIsPlayed(PlaySoundS2CPacket packet, CallbackInfo ci) { + @WrapWithCondition(method = "onPlaySound", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/world/ClientWorld;playSound(Lnet/minecraft/entity/Entity;DDDLnet/minecraft/registry/entry/RegistryEntry;Lnet/minecraft/sound/SoundCategory;FFJ)V")) + private boolean postEventWhenSoundIsPlayed(ClientWorld instance, @Nullable Entity source, double x, double y, double z, RegistryEntry<SoundEvent> sound, SoundCategory category, float volume, float pitch, long seed) { var event = new SoundReceiveEvent( - packet.getSound(), - packet.getCategory(), - new Vec3d(packet.getX(), packet.getY(), packet.getZ()), - packet.getPitch(), - packet.getVolume(), - packet.getSeed() + sound, + category, + new Vec3d(x,y,z), + pitch, + volume, + seed ); SoundReceiveEvent.Companion.publish(event); - if (event.getCancelled()) { - ci.cancel(); - } + return !event.getCancelled(); } } diff --git a/src/main/java/moe/nea/firmament/mixins/TolerateFirmamentTolerateRegistryOwners.java b/src/main/java/moe/nea/firmament/mixins/TolerateFirmamentTolerateRegistryOwners.java new file mode 100644 index 0000000..ac6f614 --- /dev/null +++ b/src/main/java/moe/nea/firmament/mixins/TolerateFirmamentTolerateRegistryOwners.java @@ -0,0 +1,18 @@ +package moe.nea.firmament.mixins; + +import moe.nea.firmament.util.mc.TolerantRegistriesOps; +import net.minecraft.registry.entry.RegistryEntryOwner; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +@Mixin(RegistryEntryOwner.class) +public interface TolerateFirmamentTolerateRegistryOwners<T> { + @Inject(method = "ownerEquals", at = @At("HEAD"), cancellable = true) + private void equalTolerantRegistryOwners(RegistryEntryOwner<T> other, CallbackInfoReturnable<Boolean> cir) { + if (other instanceof TolerantRegistriesOps.TolerantOwner<?>) { + cir.setReturnValue(true); + } + } +} diff --git a/src/main/java/moe/nea/firmament/mixins/WorldRenderLastEventPatch.java b/src/main/java/moe/nea/firmament/mixins/WorldRenderLastEventPatch.java index 847fb4d..3ed8c1b 100644 --- a/src/main/java/moe/nea/firmament/mixins/WorldRenderLastEventPatch.java +++ b/src/main/java/moe/nea/firmament/mixins/WorldRenderLastEventPatch.java @@ -2,11 +2,9 @@ package moe.nea.firmament.mixins; -import com.llamalad7.mixinextras.sugar.Local; import moe.nea.firmament.events.WorldRenderLastEvent; import net.minecraft.client.render.*; import net.minecraft.client.util.Handle; -import net.minecraft.client.util.ObjectAllocator; import net.minecraft.client.util.math.MatrixStack; import net.minecraft.util.profiler.Profiler; import org.joml.Matrix4f; @@ -31,12 +29,12 @@ public abstract class WorldRenderLastEventPatch { protected abstract void checkEmpty(MatrixStack matrices); @Inject(method = "method_62214", at = @At(value = "INVOKE", target = "Lnet/minecraft/util/profiler/Profiler;pop()V", shift = At.Shift.AFTER)) - public void onWorldRenderLast(Fog fog, RenderTickCounter tickCounter, Camera camera, Profiler profiler, Matrix4f matrix4f, Matrix4f matrix4f2, Handle handle, Handle handle2, Handle handle3, Handle handle4, boolean bl, Frustum frustum, Handle handle5, CallbackInfo ci) { + public void onWorldRenderLast(Fog fog, RenderTickCounter renderTickCounter, Camera camera, Profiler profiler, Matrix4f matrix4f, Matrix4f matrix4f2, Handle handle, Handle handle2, boolean bl, Frustum frustum, Handle handle3, Handle handle4, CallbackInfo ci) { var imm = this.bufferBuilders.getEntityVertexConsumers(); var stack = new MatrixStack(); // TODO: pre-cancel this event if F1 is active var event = new WorldRenderLastEvent( - stack, tickCounter, + stack, renderTickCounter, camera, imm ); diff --git a/src/main/java/moe/nea/firmament/mixins/accessor/AccessorChatHud.java b/src/main/java/moe/nea/firmament/mixins/accessor/AccessorChatHud.java index 72a72f0..d164aac 100644 --- a/src/main/java/moe/nea/firmament/mixins/accessor/AccessorChatHud.java +++ b/src/main/java/moe/nea/firmament/mixins/accessor/AccessorChatHud.java @@ -4,6 +4,7 @@ import net.minecraft.client.gui.hud.ChatHud; import net.minecraft.client.gui.hud.ChatHudLine; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.gen.Accessor; +import org.spongepowered.asm.mixin.gen.Invoker; import java.util.List; @@ -11,4 +12,13 @@ import java.util.List; public interface AccessorChatHud { @Accessor("messages") List<ChatHudLine> getMessages_firmament(); + + @Accessor("visibleMessages") + List<ChatHudLine.Visible> getVisibleMessages_firmament(); + + @Accessor("scrolledLines") + int getScrolledLines_firmament(); + + @Invoker("toChatLineY") + double toChatLineY_firmament(double y); } diff --git a/src/main/java/moe/nea/firmament/mixins/accessor/AccessorHandledScreen.java b/src/main/java/moe/nea/firmament/mixins/accessor/AccessorHandledScreen.java index 7ed04b1..f55ef4f 100644 --- a/src/main/java/moe/nea/firmament/mixins/accessor/AccessorHandledScreen.java +++ b/src/main/java/moe/nea/firmament/mixins/accessor/AccessorHandledScreen.java @@ -1,5 +1,3 @@ - - package moe.nea.firmament.mixins.accessor; import net.minecraft.client.gui.screen.ingame.HandledScreen; diff --git a/src/main/java/moe/nea/firmament/mixins/accessor/AccessorPlayerListHud.java b/src/main/java/moe/nea/firmament/mixins/accessor/AccessorPlayerListHud.java new file mode 100644 index 0000000..81ea0fd --- /dev/null +++ b/src/main/java/moe/nea/firmament/mixins/accessor/AccessorPlayerListHud.java @@ -0,0 +1,31 @@ +package moe.nea.firmament.mixins.accessor; + +import net.minecraft.client.gui.hud.PlayerListHud; +import net.minecraft.client.network.PlayerListEntry; +import net.minecraft.text.Text; +import org.jetbrains.annotations.Nullable; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; +import org.spongepowered.asm.mixin.gen.Invoker; + +import java.util.Comparator; +import java.util.List; + +@Mixin(PlayerListHud.class) +public interface AccessorPlayerListHud { + + @Accessor("ENTRY_ORDERING") + static Comparator<PlayerListEntry> getEntryOrdering() { + throw new AssertionError(); + } + + @Invoker("collectPlayerEntries") + List<PlayerListEntry> collectPlayerEntries_firmament(); + + @Accessor("footer") + @Nullable Text getFooter_firmament(); + + @Accessor("header") + @Nullable Text getHeader_firmament(); + +} diff --git a/src/main/java/moe/nea/firmament/mixins/accessor/AccessorWorldRenderer.java b/src/main/java/moe/nea/firmament/mixins/accessor/AccessorWorldRenderer.java new file mode 100644 index 0000000..8b25562 --- /dev/null +++ b/src/main/java/moe/nea/firmament/mixins/accessor/AccessorWorldRenderer.java @@ -0,0 +1,17 @@ +package moe.nea.firmament.mixins.accessor; + +import it.unimi.dsi.fastutil.longs.Long2ObjectMap; +import net.minecraft.client.render.WorldRenderer; +import net.minecraft.entity.player.BlockBreakingInfo; +import org.jetbrains.annotations.NotNull; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +import java.util.SortedSet; + +@Mixin(WorldRenderer.class) +public interface AccessorWorldRenderer { + @Accessor("blockBreakingProgressions") + @NotNull + Long2ObjectMap<SortedSet<BlockBreakingInfo>> getBlockBreakingProgressions_firmament(); +} diff --git a/src/main/java/moe/nea/firmament/mixins/feature/DisableSlotHighlights.java b/src/main/java/moe/nea/firmament/mixins/feature/DisableSlotHighlights.java new file mode 100644 index 0000000..0abed22 --- /dev/null +++ b/src/main/java/moe/nea/firmament/mixins/feature/DisableSlotHighlights.java @@ -0,0 +1,25 @@ +package moe.nea.firmament.mixins.feature; + +import moe.nea.firmament.features.fixes.Fixes; +import net.minecraft.component.DataComponentTypes; +import net.minecraft.item.ItemStack; +import net.minecraft.screen.slot.Slot; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +@Mixin(Slot.class) +public abstract class DisableSlotHighlights { + @Shadow + public abstract ItemStack getStack(); + + @Inject(method = "canBeHighlighted", at = @At("HEAD"), cancellable = true) + private void dontHighlight(CallbackInfoReturnable<Boolean> cir) { + if (!Fixes.TConfig.INSTANCE.getHideSlotHighlights()) return; + var display = getStack().get(DataComponentTypes.TOOLTIP_DISPLAY); + if (display != null && display.hideTooltip()) + cir.setReturnValue(false); + } +} diff --git a/src/main/java/moe/nea/firmament/mixins/feature/devcosmetics/CustomCapeFeatureRenderer.java b/src/main/java/moe/nea/firmament/mixins/feature/devcosmetics/CustomCapeFeatureRenderer.java new file mode 100644 index 0000000..5a92f89 --- /dev/null +++ b/src/main/java/moe/nea/firmament/mixins/feature/devcosmetics/CustomCapeFeatureRenderer.java @@ -0,0 +1,43 @@ +package moe.nea.firmament.mixins.feature.devcosmetics; + +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; +import com.llamalad7.mixinextras.sugar.Local; +import kotlin.Unit; +import moe.nea.firmament.features.misc.CustomCapes; +import net.minecraft.client.render.RenderLayer; +import net.minecraft.client.render.VertexConsumer; +import net.minecraft.client.render.VertexConsumerProvider; +import net.minecraft.client.render.entity.feature.CapeFeatureRenderer; +import net.minecraft.client.render.entity.feature.FeatureRenderer; +import net.minecraft.client.render.entity.feature.FeatureRendererContext; +import net.minecraft.client.render.entity.model.BipedEntityModel; +import net.minecraft.client.render.entity.model.PlayerEntityModel; +import net.minecraft.client.render.entity.state.PlayerEntityRenderState; +import net.minecraft.client.util.SkinTextures; +import net.minecraft.client.util.math.MatrixStack; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; + +@Mixin(CapeFeatureRenderer.class) +public abstract class CustomCapeFeatureRenderer extends FeatureRenderer<PlayerEntityRenderState, PlayerEntityModel> { + public CustomCapeFeatureRenderer(FeatureRendererContext<PlayerEntityRenderState, PlayerEntityModel> context) { + super(context); + } + + @WrapOperation( + method = "render(Lnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumerProvider;ILnet/minecraft/client/render/entity/state/PlayerEntityRenderState;FF)V", + at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/entity/model/BipedEntityModel;render(Lnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumer;II)V") + ) + private void onRender(BipedEntityModel instance, MatrixStack matrixStack, VertexConsumer vertexConsumer, int light, int overlay, Operation<Void> original, @Local PlayerEntityRenderState playerEntityRenderState, @Local SkinTextures skinTextures, @Local VertexConsumerProvider vertexConsumerProvider) { + CustomCapes.render( + playerEntityRenderState, + vertexConsumer, + RenderLayer.getEntitySolid(skinTextures.capeTexture()), + vertexConsumerProvider, + updatedConsumer -> { + original.call(instance, matrixStack, updatedConsumer, light, overlay); + return Unit.INSTANCE; + }); + } +} diff --git a/src/main/java/moe/nea/firmament/mixins/feature/devcosmetics/CustomCapeStorage.java b/src/main/java/moe/nea/firmament/mixins/feature/devcosmetics/CustomCapeStorage.java new file mode 100644 index 0000000..428d7ec --- /dev/null +++ b/src/main/java/moe/nea/firmament/mixins/feature/devcosmetics/CustomCapeStorage.java @@ -0,0 +1,23 @@ +package moe.nea.firmament.mixins.feature.devcosmetics; + +import moe.nea.firmament.features.misc.CustomCapes; +import net.minecraft.client.render.entity.state.PlayerEntityRenderState; +import org.jetbrains.annotations.Nullable; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; + +@Mixin(PlayerEntityRenderState.class) +public class CustomCapeStorage implements CustomCapes.CapeStorage { + @Unique + CustomCapes.CustomCape customCape; + + @Override + public CustomCapes.@Nullable CustomCape getCape_firmament() { + return customCape; + } + + @Override + public void setCape_firmament(CustomCapes.@Nullable CustomCape customCape) { + this.customCape = customCape; + } +} diff --git a/src/main/java/moe/nea/firmament/mixins/feature/devcosmetics/SaveCapeToPlayerEntityRenderState.java b/src/main/java/moe/nea/firmament/mixins/feature/devcosmetics/SaveCapeToPlayerEntityRenderState.java new file mode 100644 index 0000000..ae9c743 --- /dev/null +++ b/src/main/java/moe/nea/firmament/mixins/feature/devcosmetics/SaveCapeToPlayerEntityRenderState.java @@ -0,0 +1,19 @@ +package moe.nea.firmament.mixins.feature.devcosmetics; + +import moe.nea.firmament.features.misc.CustomCapes; +import net.minecraft.client.network.AbstractClientPlayerEntity; +import net.minecraft.client.render.entity.PlayerEntityRenderer; +import net.minecraft.client.render.entity.state.PlayerEntityRenderState; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(PlayerEntityRenderer.class) +public class SaveCapeToPlayerEntityRenderState { + @Inject(method = "updateRenderState(Lnet/minecraft/client/network/AbstractClientPlayerEntity;Lnet/minecraft/client/render/entity/state/PlayerEntityRenderState;F)V", + at = @At("TAIL")) + private void addCustomCape(AbstractClientPlayerEntity abstractClientPlayerEntity, PlayerEntityRenderState playerEntityRenderState, float f, CallbackInfo ci) { + CustomCapes.addCapeData(abstractClientPlayerEntity, playerEntityRenderState); + } +} diff --git a/src/main/java/moe/nea/firmament/mixins/render/entitytints/ChangeColorOfLivingEntities.java b/src/main/java/moe/nea/firmament/mixins/render/entitytints/ChangeColorOfLivingEntities.java new file mode 100644 index 0000000..2b96e5c --- /dev/null +++ b/src/main/java/moe/nea/firmament/mixins/render/entitytints/ChangeColorOfLivingEntities.java @@ -0,0 +1,62 @@ +package moe.nea.firmament.mixins.render.entitytints; + +import com.llamalad7.mixinextras.injector.ModifyReturnValue; +import com.llamalad7.mixinextras.sugar.Local; +import moe.nea.firmament.events.EntityRenderTintEvent; +import net.minecraft.client.render.VertexConsumerProvider; +import net.minecraft.client.render.entity.LivingEntityRenderer; +import net.minecraft.client.render.entity.model.EntityModel; +import net.minecraft.client.render.entity.state.LivingEntityRenderState; +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.entity.LivingEntity; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.ModifyArg; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +/** + * Applies various rendering modifications from {@link EntityRenderTintEvent} + */ +@Mixin(LivingEntityRenderer.class) +public class ChangeColorOfLivingEntities<T extends LivingEntity, S extends LivingEntityRenderState, M extends EntityModel<? super S>> { + @ModifyReturnValue(method = "getMixColor", at = @At("RETURN")) + private int changeColor(int original, @Local(argsOnly = true) S state) { + var tintState = EntityRenderTintEvent.HasTintRenderState.cast(state); + if (tintState.getHasTintOverride_firmament()) + return tintState.getTint_firmament(); + return original; + } + + @ModifyArg( + method = "getOverlay", + at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/OverlayTexture;getU(F)I"), + allow = 1 + ) + private static float modifyLightOverlay(float originalWhiteOffset, @Local(argsOnly = true) LivingEntityRenderState state) { + var tintState = EntityRenderTintEvent.HasTintRenderState.cast(state); + if (tintState.getHasTintOverride_firmament() || tintState.getOverlayTexture_firmament() != null) { + return 1F; // TODO: add interpolation percentage to render state extension + } + return originalWhiteOffset; + } + + @Inject(method = "render(Lnet/minecraft/client/render/entity/state/LivingEntityRenderState;Lnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumerProvider;I)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/util/math/MatrixStack;pop()V")) + private void afterRender(S livingEntityRenderState, MatrixStack matrixStack, VertexConsumerProvider vertexConsumerProvider, int i, CallbackInfo ci) { + var tintState = EntityRenderTintEvent.HasTintRenderState.cast(livingEntityRenderState); + var overlayTexture = tintState.getOverlayTexture_firmament(); + if (overlayTexture != null && vertexConsumerProvider instanceof VertexConsumerProvider.Immediate imm) { + imm.drawCurrentLayer(); + } + EntityRenderTintEvent.overlayOverride = null; + } + + @Inject(method = "render(Lnet/minecraft/client/render/entity/state/LivingEntityRenderState;Lnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumerProvider;I)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/util/math/MatrixStack;push()V")) + private void beforeRender(S livingEntityRenderState, MatrixStack matrixStack, VertexConsumerProvider vertexConsumerProvider, int i, CallbackInfo ci) { + var tintState = EntityRenderTintEvent.HasTintRenderState.cast(livingEntityRenderState); + var overlayTexture = tintState.getOverlayTexture_firmament(); + if (overlayTexture != null) { + EntityRenderTintEvent.overlayOverride = overlayTexture; + } + } +} diff --git a/src/main/java/moe/nea/firmament/mixins/render/entitytints/EntityRenderStateTint.java b/src/main/java/moe/nea/firmament/mixins/render/entitytints/EntityRenderStateTint.java new file mode 100644 index 0000000..1019027 --- /dev/null +++ b/src/main/java/moe/nea/firmament/mixins/render/entitytints/EntityRenderStateTint.java @@ -0,0 +1,55 @@ +package moe.nea.firmament.mixins.render.entitytints; + +import moe.nea.firmament.events.EntityRenderTintEvent; +import moe.nea.firmament.util.render.TintedOverlayTexture; +import net.minecraft.client.render.entity.state.EntityRenderState; +import org.jetbrains.annotations.Nullable; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; + +@Mixin(EntityRenderState.class) +public class EntityRenderStateTint implements EntityRenderTintEvent.HasTintRenderState { + @Unique + int tint = -1; + @Unique + TintedOverlayTexture overlayTexture; + @Unique + boolean hasTintOverride = false; + + @Override + public int getTint_firmament() { + return tint; + } + + @Override + public void setTint_firmament(int i) { + tint = i; + hasTintOverride = true; + } + + @Override + public boolean getHasTintOverride_firmament() { + return hasTintOverride; + } + + @Override + public void setHasTintOverride_firmament(boolean b) { + hasTintOverride = b; + } + + @Override + public void reset_firmament() { + hasTintOverride = false; + overlayTexture = null; + } + + @Override + public @Nullable TintedOverlayTexture getOverlayTexture_firmament() { + return overlayTexture; + } + + @Override + public void setOverlayTexture_firmament(@Nullable TintedOverlayTexture tintedOverlayTexture) { + this.overlayTexture = tintedOverlayTexture; + } +} diff --git a/src/main/java/moe/nea/firmament/mixins/render/entitytints/InjectIntoRenderState.java b/src/main/java/moe/nea/firmament/mixins/render/entitytints/InjectIntoRenderState.java new file mode 100644 index 0000000..7938340 --- /dev/null +++ b/src/main/java/moe/nea/firmament/mixins/render/entitytints/InjectIntoRenderState.java @@ -0,0 +1,30 @@ +package moe.nea.firmament.mixins.render.entitytints; + +import moe.nea.firmament.events.EntityRenderTintEvent; +import net.minecraft.client.render.entity.EntityRenderer; +import net.minecraft.client.render.entity.state.EntityRenderState; +import net.minecraft.entity.Entity; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +/** + * Dispatches {@link EntityRenderTintEvent} to collect additional render state used by {@link ChangeColorOfLivingEntities} + */ +@Mixin(EntityRenderer.class) +public class InjectIntoRenderState<T extends Entity, S extends EntityRenderState> { + + @Inject( + method = "updateRenderState", + at = @At("RETURN")) + private void onUpdateRenderState(T entity, S state, float tickDelta, CallbackInfo ci) { + var renderState = EntityRenderTintEvent.HasTintRenderState.cast(state); + renderState.reset_firmament(); + var tintEvent = new EntityRenderTintEvent( + entity, + renderState + ); + EntityRenderTintEvent.Companion.publish(tintEvent); + } +} diff --git a/src/main/java/moe/nea/firmament/mixins/render/entitytints/ReplaceOverlayTexture.java b/src/main/java/moe/nea/firmament/mixins/render/entitytints/ReplaceOverlayTexture.java new file mode 100644 index 0000000..61e5c65 --- /dev/null +++ b/src/main/java/moe/nea/firmament/mixins/render/entitytints/ReplaceOverlayTexture.java @@ -0,0 +1,24 @@ +package moe.nea.firmament.mixins.render.entitytints; + +import com.llamalad7.mixinextras.injector.ModifyExpressionValue; +import moe.nea.firmament.events.EntityRenderTintEvent; +import net.minecraft.client.render.OverlayTexture; +import net.minecraft.client.render.RenderLayer; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; + +/** + * Replaces the overlay texture used by rendering with the override specified in {@link EntityRenderTintEvent#overlayOverride} + */ +@Mixin(RenderLayer.Overlay.class) +public class ReplaceOverlayTexture { + @ModifyExpressionValue( + method = {"method_23555", "method_23556"}, + expect = 2, + at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/GameRenderer;getOverlayTexture()Lnet/minecraft/client/render/OverlayTexture;")) + private static OverlayTexture replaceOverlayTexture(OverlayTexture original) { + if (EntityRenderTintEvent.overlayOverride != null) + return EntityRenderTintEvent.overlayOverride; + return original; + } +} diff --git a/src/main/java/moe/nea/firmament/mixins/render/entitytints/UseOverlayableEquipmentRenderer.java b/src/main/java/moe/nea/firmament/mixins/render/entitytints/UseOverlayableEquipmentRenderer.java new file mode 100644 index 0000000..d9c174c --- /dev/null +++ b/src/main/java/moe/nea/firmament/mixins/render/entitytints/UseOverlayableEquipmentRenderer.java @@ -0,0 +1,34 @@ +package moe.nea.firmament.mixins.render.entitytints; + +import com.llamalad7.mixinextras.injector.ModifyExpressionValue; +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; +import moe.nea.firmament.events.EntityRenderTintEvent; +import net.minecraft.client.render.OverlayTexture; +import net.minecraft.client.render.RenderLayer; +import net.minecraft.client.render.entity.equipment.EquipmentRenderer; +import net.minecraft.util.Identifier; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; + +/** + * Patch to make {@link EquipmentRenderer} use a {@link RenderLayer} that allows uses Minecraft's overlay texture, if a {@link EntityRenderTintEvent#overlayOverride} is specified. + */ +@Mixin(EquipmentRenderer.class) +public class UseOverlayableEquipmentRenderer { + @WrapOperation(method = "render(Lnet/minecraft/client/render/entity/equipment/EquipmentModel$LayerType;Lnet/minecraft/registry/RegistryKey;Lnet/minecraft/client/model/Model;Lnet/minecraft/item/ItemStack;Lnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumerProvider;ILnet/minecraft/util/Identifier;)V", + at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/RenderLayer;getArmorCutoutNoCull(Lnet/minecraft/util/Identifier;)Lnet/minecraft/client/render/RenderLayer;")) + private RenderLayer replace(Identifier texture, Operation<RenderLayer> original) { + if (EntityRenderTintEvent.overlayOverride != null) + return RenderLayer.getEntityTranslucent(texture); + return original.call(texture); + } + + @ModifyExpressionValue(method = "render(Lnet/minecraft/client/render/entity/equipment/EquipmentModel$LayerType;Lnet/minecraft/registry/RegistryKey;Lnet/minecraft/client/model/Model;Lnet/minecraft/item/ItemStack;Lnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumerProvider;ILnet/minecraft/util/Identifier;)V", + at = @At(value = "FIELD", target = "Lnet/minecraft/client/render/OverlayTexture;DEFAULT_UV:I")) + private int replaceUvIndex(int original) { + if (EntityRenderTintEvent.overlayOverride != null) + return OverlayTexture.packUv(15, 10); // TODO: store this info in a global alongside overlayOverride + return original; + } +} diff --git a/src/main/java/moe/nea/firmament/mixins/render/entitytints/UseOverlayableHeadFeatureRenderer.java b/src/main/java/moe/nea/firmament/mixins/render/entitytints/UseOverlayableHeadFeatureRenderer.java new file mode 100644 index 0000000..07bc5cf --- /dev/null +++ b/src/main/java/moe/nea/firmament/mixins/render/entitytints/UseOverlayableHeadFeatureRenderer.java @@ -0,0 +1,25 @@ +package moe.nea.firmament.mixins.render.entitytints; + +import com.llamalad7.mixinextras.injector.ModifyExpressionValue; +import moe.nea.firmament.events.EntityRenderTintEvent; +import net.minecraft.client.render.OverlayTexture; +import net.minecraft.client.render.RenderLayer; +import net.minecraft.client.render.entity.feature.HeadFeatureRenderer; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; + +/** + * Patch to make {@link HeadFeatureRenderer} use a {@link RenderLayer} that allows uses Minecraft's overlay texture, if a {@link EntityRenderTintEvent#overlayOverride} is specified. + * @see UseOverlayableItemRenderer + */ +@Mixin(HeadFeatureRenderer.class) +public class UseOverlayableHeadFeatureRenderer { + + @ModifyExpressionValue(method = "render(Lnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumerProvider;ILnet/minecraft/client/render/entity/state/LivingEntityRenderState;FF)V", + at = @At(value = "FIELD", target = "Lnet/minecraft/client/render/OverlayTexture;DEFAULT_UV:I")) + private int replaceUvIndex(int original) { + if (EntityRenderTintEvent.overlayOverride != null) + return OverlayTexture.packUv(15, 10); // TODO: store this info in a global alongside overlayOverride + return original; + } +} diff --git a/src/main/java/moe/nea/firmament/mixins/render/entitytints/UseOverlayableItemRenderer.java b/src/main/java/moe/nea/firmament/mixins/render/entitytints/UseOverlayableItemRenderer.java new file mode 100644 index 0000000..620ab2c --- /dev/null +++ b/src/main/java/moe/nea/firmament/mixins/render/entitytints/UseOverlayableItemRenderer.java @@ -0,0 +1,25 @@ +package moe.nea.firmament.mixins.render.entitytints; + +import com.llamalad7.mixinextras.injector.ModifyExpressionValue; +import moe.nea.firmament.events.EntityRenderTintEvent; +import net.minecraft.client.render.OverlayTexture; +import net.minecraft.client.render.RenderLayer; +import net.minecraft.client.render.RenderPhase; +import net.minecraft.client.render.item.ItemRenderState; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; + +/** + * Patch to make {@link ItemRenderState} use a {@link RenderLayer} that allows uses Minecraft's overlay texture. + * + * @see UseOverlayableHeadFeatureRenderer + */ +@Mixin(ItemRenderState.LayerRenderState.class) +public class UseOverlayableItemRenderer { + @ModifyExpressionValue(method = "render", at = @At(value = "FIELD", target = "Lnet/minecraft/client/render/item/ItemRenderState$LayerRenderState;renderLayer:Lnet/minecraft/client/render/RenderLayer;")) + private RenderLayer replace(RenderLayer original) { + if (EntityRenderTintEvent.overlayOverride != null && original instanceof RenderLayer.MultiPhase multiPhase && multiPhase.phases.texture instanceof RenderPhase.Texture texture && texture.getId().isPresent()) + return RenderLayer.getEntityTranslucent(texture.getId().get()); + return original; + } +} diff --git a/src/main/java/moe/nea/firmament/mixins/render/entitytints/UseOverlayableSkullBlockEntityRenderer.java b/src/main/java/moe/nea/firmament/mixins/render/entitytints/UseOverlayableSkullBlockEntityRenderer.java new file mode 100644 index 0000000..9905af1 --- /dev/null +++ b/src/main/java/moe/nea/firmament/mixins/render/entitytints/UseOverlayableSkullBlockEntityRenderer.java @@ -0,0 +1,25 @@ +package moe.nea.firmament.mixins.render.entitytints; + +import com.llamalad7.mixinextras.injector.ModifyExpressionValue; +import moe.nea.firmament.events.EntityRenderTintEvent; +import net.minecraft.client.render.OverlayTexture; +import net.minecraft.client.render.RenderLayer; +import net.minecraft.client.render.block.entity.SkullBlockEntityRenderer; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; + +/** + * Patch to make {@link SkullBlockEntityRenderer} use a {@link RenderLayer} that allows uses Minecraft's overlay texture, if a {@link EntityRenderTintEvent#overlayOverride} is specified. + */ + +@Mixin(SkullBlockEntityRenderer.class) +public class UseOverlayableSkullBlockEntityRenderer { + @ModifyExpressionValue(method = "renderSkull", + at = @At(value = "FIELD", target = "Lnet/minecraft/client/render/OverlayTexture;DEFAULT_UV:I")) + private static int replaceUvIndex(int original) { + if (EntityRenderTintEvent.overlayOverride != null) + return OverlayTexture.packUv(15, 10); // TODO: store this info in a global alongside overlayOverride + return original; + } + +} |