diff --git a/src/main/java/net/kyori/adventure/platform/fabric/impl/WrappedComponent.java b/src/main/java/net/kyori/adventure/platform/fabric/impl/WrappedComponent.java index 809264e9..2281f9bc 100644 --- a/src/main/java/net/kyori/adventure/platform/fabric/impl/WrappedComponent.java +++ b/src/main/java/net/kyori/adventure/platform/fabric/impl/WrappedComponent.java @@ -177,4 +177,17 @@ public Optional visit(final ContentConsumer visitor) { public net.kyori.adventure.text.@NotNull Component asComponent() { return this.wrapped; } + + @Override + public int hashCode() { + return this.deepConverted().hashCode(); + } + + @Override + public boolean equals(final Object obj) { + if (obj instanceof final WrappedComponent wrappedComponent) { + return this.wrapped().equals(wrappedComponent.wrapped()); + } + return this.deepConverted().equals(obj); + } } diff --git a/src/mixin/java/net/kyori/adventure/platform/fabric/impl/mixin/minecraft/network/chat/MutableComponentMixin.java b/src/mixin/java/net/kyori/adventure/platform/fabric/impl/mixin/minecraft/network/chat/MutableComponentMixin.java new file mode 100644 index 00000000..e8fefe9a --- /dev/null +++ b/src/mixin/java/net/kyori/adventure/platform/fabric/impl/mixin/minecraft/network/chat/MutableComponentMixin.java @@ -0,0 +1,41 @@ +/* + * This file is part of adventure-platform-fabric, licensed under the MIT License. + * + * Copyright (c) 2024 KyoriPowered + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package net.kyori.adventure.platform.fabric.impl.mixin.minecraft.network.chat; + +import net.kyori.adventure.platform.fabric.impl.WrappedComponent; +import net.minecraft.network.chat.MutableComponent; +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(MutableComponent.class) +abstract class MutableComponentMixin { + @Inject(method = "equals", at = @At("HEAD"), cancellable = true) + private void hookEquals(final Object other, final CallbackInfoReturnable cir) { + if (other instanceof final WrappedComponent wrapped) { + cir.setReturnValue(wrapped.equals(this)); + } + } +} diff --git a/src/mixin/resources/adventure-platform-fabric.mixins.json b/src/mixin/resources/adventure-platform-fabric.mixins.json index 3af927db..dcc7e0d1 100644 --- a/src/mixin/resources/adventure-platform-fabric.mixins.json +++ b/src/mixin/resources/adventure-platform-fabric.mixins.json @@ -16,6 +16,7 @@ "minecraft.network.chat.ComponentMixin$SerializerMixin", "minecraft.network.chat.ComponentSerializationMixin", "minecraft.network.chat.MessageSignatureMixin", + "minecraft.network.chat.MutableComponentMixin", "minecraft.network.chat.PlayerChatMessageMixin", "minecraft.network.protocol.game.ClientboundCommandsPacketMixin", "minecraft.network.protocol.game.ClientboundCommandsPacketMixin$ArgumentNodeStubMixin", diff --git a/src/test/java/net/kyori/adventure/platform/fabric/ComponentConversionTest.java b/src/test/java/net/kyori/adventure/platform/fabric/ComponentConversionTest.java index 9f4b48d9..1f08920f 100644 --- a/src/test/java/net/kyori/adventure/platform/fabric/ComponentConversionTest.java +++ b/src/test/java/net/kyori/adventure/platform/fabric/ComponentConversionTest.java @@ -37,6 +37,7 @@ import java.util.stream.Stream; import net.kyori.adventure.key.Key; import net.kyori.adventure.platform.fabric.impl.AdventureCommon; +import net.kyori.adventure.platform.fabric.impl.NonWrappingComponentSerializer; import net.kyori.adventure.platform.fabric.impl.WrappedComponent; import net.kyori.adventure.pointer.Pointered; import net.kyori.adventure.text.Component; @@ -114,6 +115,16 @@ void testSerializationEqualWhenWrappedNested(final Component input) { assertJsonTreesEqual(serializedNative, serialized); } + @TestOnComponents + void testComponentEquality(final Component input) { + final net.minecraft.network.chat.Component deepConverted = new NonWrappingComponentSerializer(BootstrappedTest::lookup).serialize(input); + final net.minecraft.network.chat.Component wrapped = this.toNativeWrapped(input); + final net.minecraft.network.chat.Component wrapped2 = this.toNativeWrapped(input); + assertEquals(wrapped, wrapped2, "two wrapped components should be equal"); + assertEquals(deepConverted, wrapped, "deep should equal wrapped"); + assertEquals(wrapped, deepConverted, "wrapped should equal deep"); + } + private static void assertJsonTreesEqual(final JsonElement expected, final JsonElement actual) { assertEquals(toStableString(expected), toStableString(actual)); }