diff --git a/common/build.gradle b/common/build.gradle index 71551a13..ca5594b7 100644 --- a/common/build.gradle +++ b/common/build.gradle @@ -9,7 +9,7 @@ dependencies { } architectury { - common(rootProject.forgeEnabled.toBoolean()) + common(rootProject.platforms.split(",")) } /** diff --git a/common/src/main/java/dev/architectury/event/events/common/ChatEvent.java b/common/src/main/java/dev/architectury/event/events/common/ChatEvent.java index 348456bb..43918ca8 100644 --- a/common/src/main/java/dev/architectury/event/events/common/ChatEvent.java +++ b/common/src/main/java/dev/architectury/event/events/common/ChatEvent.java @@ -22,13 +22,16 @@ package dev.architectury.event.events.common; import dev.architectury.event.CompoundEventResult; import dev.architectury.event.Event; import dev.architectury.event.EventFactory; +import dev.architectury.event.EventResult; import net.minecraft.network.chat.Component; import net.minecraft.server.level.ServerPlayer; import org.jetbrains.annotations.Nullable; +import java.util.function.Function; + public interface ChatEvent { /** - * @see Server#process(ServerPlayer, Component) + * @see Server#process(ServerPlayer, ChatComponent) */ Event SERVER = EventFactory.createEventResult(); @@ -39,9 +42,37 @@ public interface ChatEvent { * * @param player The player who has sent the message, or null. * @param component The message as component. - * @return A {@link CompoundEventResult} determining the outcome of the event, - * if an outcome is set, the sent message is overridden. + * @return A {@link EventResult} determining the outcome of the event, + * the execution of the vanilla message may be cancelled by the result. */ - CompoundEventResult process(@Nullable ServerPlayer player, Component component); + EventResult process(@Nullable ServerPlayer player, ChatComponent component); + } + + interface ChatComponent { + Component getRaw(); + + @Nullable + Component getFiltered(); + + void setRaw(Component raw); + + void setFiltered(@Nullable Component filtered); + + default void modifyRaw(Function function) { + setRaw(function.apply(getRaw())); + } + + default void modifyFiltered(Function function) { + Component filtered = getFiltered(); + + if (filtered != null) { + setFiltered(function.apply(filtered)); + } + } + + default void modifyBoth(Function function) { + modifyRaw(function); + modifyFiltered(function); + } } } diff --git a/fabric/src/main/java/dev/architectury/hooks/item/tool/fabric/HoeItemHooksImpl.java b/fabric/src/main/java/dev/architectury/hooks/item/tool/fabric/HoeItemHooksImpl.java index b1562249..2263be17 100644 --- a/fabric/src/main/java/dev/architectury/hooks/item/tool/fabric/HoeItemHooksImpl.java +++ b/fabric/src/main/java/dev/architectury/hooks/item/tool/fabric/HoeItemHooksImpl.java @@ -1,3 +1,22 @@ +/* + * This file is part of architectury. + * Copyright (C) 2020, 2021, 2022 architectury + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + package dev.architectury.hooks.item.tool.fabric; import com.google.common.collect.ImmutableMap; diff --git a/fabric/src/main/java/dev/architectury/impl/fabric/ChatComponentImpl.java b/fabric/src/main/java/dev/architectury/impl/fabric/ChatComponentImpl.java new file mode 100644 index 00000000..ad0a9ce4 --- /dev/null +++ b/fabric/src/main/java/dev/architectury/impl/fabric/ChatComponentImpl.java @@ -0,0 +1,58 @@ +/* + * This file is part of architectury. + * Copyright (C) 2020, 2021, 2022 architectury + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +package dev.architectury.impl.fabric; + +import dev.architectury.event.events.common.ChatEvent; +import net.minecraft.network.chat.Component; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.Nullable; + +@ApiStatus.Internal +public class ChatComponentImpl implements ChatEvent.ChatComponent { + private Component raw; + @Nullable + private Component filtered; + + public ChatComponentImpl(Component raw, @Nullable Component filtered) { + this.raw = raw; + this.filtered = filtered; + } + + @Override + public Component getRaw() { + return raw; + } + + @Override + @Nullable + public Component getFiltered() { + return filtered; + } + + @Override + public void setRaw(Component raw) { + this.raw = raw; + } + + @Override + public void setFiltered(@Nullable Component filtered) { + this.filtered = filtered; + } +} diff --git a/fabric/src/main/java/dev/architectury/impl/fabric/EventChatDecorator.java b/fabric/src/main/java/dev/architectury/impl/fabric/EventChatDecorator.java index 6e115a75..00ae7d10 100644 --- a/fabric/src/main/java/dev/architectury/impl/fabric/EventChatDecorator.java +++ b/fabric/src/main/java/dev/architectury/impl/fabric/EventChatDecorator.java @@ -19,13 +19,17 @@ package dev.architectury.impl.fabric; +import dev.architectury.event.events.common.ChatEvent; import net.minecraft.network.chat.ChatDecorator; import net.minecraft.network.chat.Component; import net.minecraft.network.chat.MessageSignature; import net.minecraft.network.chat.PlayerChatMessage; import net.minecraft.server.level.ServerPlayer; +import net.minecraft.server.network.FilteredText; import org.jetbrains.annotations.Nullable; +import java.util.concurrent.CompletableFuture; + public class EventChatDecorator implements ChatDecorator { public static final Component CANCELLING_COMPONENT = Component.literal("THIS SHOULDN'T BE DISPLAYED, ARCHITECTURY SPECIFIC STRING DO NOT IMITATE THIS"); private final ChatDecorator parent; @@ -37,32 +41,46 @@ public class EventChatDecorator implements ChatDecorator { } @Override - public Component decorate(@Nullable ServerPlayer player, Component component) { - return processor.process(player, parent.decorate(player, component)); + public CompletableFuture decorate(@Nullable ServerPlayer player, Component component) { + return parent.decorate(player, component).thenApply(c -> { + return processor.process(player, FilteredText.fullyFiltered(c)).raw(); + }).exceptionally(throwable -> { + throwable.printStackTrace(); + return component; + }); } @Override - public PlayerChatMessage decorate(@Nullable ServerPlayer player, Component component, MessageSignature signature, boolean signedPreview) { - PlayerChatMessage message = parent.decorate(player, component, signature, signedPreview); - Component newContent = processor.process(player, component); - if (!newContent.equals(component)) { - return !signedPreview ? PlayerChatMessage.signed(component, signature).withUnsignedContent(newContent) : PlayerChatMessage.signed(newContent, signature); - } - return message; + public CompletableFuture> decorateFiltered(@Nullable ServerPlayer player, FilteredText message) { + return parent.decorateFiltered(player, message).thenApply(newMessage -> { + FilteredText newContent = processor.process(player, newMessage); + if (!newContent.equals(newMessage)) { + return newContent; + } + return newMessage; + }).exceptionally(throwable -> { + throwable.printStackTrace(); + return message; + }); } @Override - public PlayerChatMessage decorate(@Nullable ServerPlayer player, PlayerChatMessage message) { - PlayerChatMessage newMessage = parent.decorate(player, message.signedContent(), message.signature(), false); - Component newContent = processor.process(player, message.signedContent()); - if (!newContent.equals(message.signedContent())) { - return PlayerChatMessage.signed(message.signedContent(), message.signature()).withUnsignedContent(newContent); - } - return message; + public CompletableFuture> decorateChat(@Nullable ServerPlayer player, FilteredText component, MessageSignature signature, boolean signedPreview) { + return parent.decorateChat(player, component, signature, signedPreview).thenApply(message -> { + FilteredText newComponent = processor.process(player, message.map(PlayerChatMessage::signedContent)); + FilteredText newMessage = PlayerChatMessage.filteredSigned(component, newComponent, signature, signedPreview); + if (!newMessage.equals(message)) { + return newMessage; + } + return message; + }).exceptionally(throwable -> { + throwable.printStackTrace(); + return PlayerChatMessage.filteredSigned(component, component, signature, signedPreview); + }); } @FunctionalInterface public interface ChatProcessor { - Component process(@Nullable ServerPlayer player, Component component); + FilteredText process(@Nullable ServerPlayer player, FilteredText text); } } diff --git a/fabric/src/main/java/dev/architectury/mixin/fabric/MixinMinecraftServer.java b/fabric/src/main/java/dev/architectury/mixin/fabric/MixinMinecraftServer.java index cf73819f..d7d18093 100644 --- a/fabric/src/main/java/dev/architectury/mixin/fabric/MixinMinecraftServer.java +++ b/fabric/src/main/java/dev/architectury/mixin/fabric/MixinMinecraftServer.java @@ -20,11 +20,14 @@ package dev.architectury.mixin.fabric; import dev.architectury.event.CompoundEventResult; +import dev.architectury.event.EventResult; import dev.architectury.event.events.common.ChatEvent; +import dev.architectury.impl.fabric.ChatComponentImpl; import dev.architectury.impl.fabric.EventChatDecorator; import net.minecraft.network.chat.ChatDecorator; import net.minecraft.network.chat.Component; import net.minecraft.server.MinecraftServer; +import net.minecraft.server.network.FilteredText; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; @@ -36,12 +39,13 @@ public class MixinMinecraftServer { private void getChatDecorator(CallbackInfoReturnable cir) { ChatDecorator parent = cir.getReturnValue(); cir.setReturnValue(new EventChatDecorator(parent, (player, component) -> { - CompoundEventResult result = ChatEvent.SERVER.invoker().process(player, component); + ChatEvent.ChatComponent chatComponent = new ChatComponentImpl(component.raw(), component.filtered()); + EventResult result = ChatEvent.SERVER.invoker().process(player, chatComponent); if (result.isPresent()) { if (result.isFalse()) { - return EventChatDecorator.CANCELLING_COMPONENT; - } else if (result.object() != null) { - return result.object(); + return FilteredText.fullyFiltered(EventChatDecorator.CANCELLING_COMPONENT); + } else { + return new FilteredText<>(chatComponent.getRaw(), chatComponent.getFiltered()); } } diff --git a/fabric/src/main/java/dev/architectury/mixin/fabric/MixinServerGamePacketListenerImpl.java b/fabric/src/main/java/dev/architectury/mixin/fabric/MixinServerGamePacketListenerImpl.java index 3e9c9fb6..2dcf63ad 100644 --- a/fabric/src/main/java/dev/architectury/mixin/fabric/MixinServerGamePacketListenerImpl.java +++ b/fabric/src/main/java/dev/architectury/mixin/fabric/MixinServerGamePacketListenerImpl.java @@ -26,6 +26,7 @@ import net.minecraft.network.chat.PlayerChatMessage; import net.minecraft.network.protocol.game.ServerboundChatPacket; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerPlayer; +import net.minecraft.server.network.FilteredText; import net.minecraft.server.network.ServerGamePacketListenerImpl; import net.minecraft.server.network.TextFilter; import org.spongepowered.asm.mixin.Final; @@ -48,11 +49,12 @@ public abstract class MixinServerGamePacketListenerImpl { @Shadow protected abstract void detectRateSpam(); - @Inject(method = "handleChat(Lnet/minecraft/network/protocol/game/ServerboundChatPacket;Lnet/minecraft/server/network/TextFilter$FilteredText;)V", + @Inject(method = "broadcastChatMessage", at = @At(value = "INVOKE", - target = "Lnet/minecraft/network/chat/PlayerChatMessage;verify(Lnet/minecraft/world/entity/player/ProfilePublicKey;)Z"), - cancellable = true, locals = LocalCapture.CAPTURE_FAILHARD) - private void handleChat(ServerboundChatPacket packet, TextFilter.FilteredText message, CallbackInfo ci, Component component, MessageSignature signature, PlayerChatMessage chatMessage) { + target = "Lnet/minecraft/network/chat/PlayerChatMessage;verify(Lnet/minecraft/server/level/ServerPlayer;)Z"), + cancellable = true) + private void handleChat(FilteredText filteredText, CallbackInfo ci) { + PlayerChatMessage chatMessage = filteredText.raw(); if (chatMessage.serverContent().equals(EventChatDecorator.CANCELLING_COMPONENT)) { ci.cancel(); } diff --git a/fabric/src/main/java/dev/architectury/mixin/fabric/server/MixinDedicatedServer.java b/fabric/src/main/java/dev/architectury/mixin/fabric/server/MixinDedicatedServer.java deleted file mode 100644 index 628c6e9c..00000000 --- a/fabric/src/main/java/dev/architectury/mixin/fabric/server/MixinDedicatedServer.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * This file is part of architectury. - * Copyright (C) 2020, 2021, 2022 architectury - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -package dev.architectury.mixin.fabric.server; - -import dev.architectury.event.CompoundEventResult; -import dev.architectury.event.events.common.ChatEvent; -import dev.architectury.impl.fabric.EventChatDecorator; -import net.minecraft.network.chat.ChatDecorator; -import net.minecraft.network.chat.Component; -import net.minecraft.server.dedicated.DedicatedServer; -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(DedicatedServer.class) -public class MixinDedicatedServer { - @Inject(method = "getChatDecorator", at = @At("RETURN"), cancellable = true) - private void getChatDecorator(CallbackInfoReturnable cir) { - ChatDecorator parent = cir.getReturnValue(); - cir.setReturnValue(new EventChatDecorator(parent, (player, component) -> { - CompoundEventResult result = ChatEvent.SERVER.invoker().process(player, component); - if (result.isPresent()) { - if (result.isFalse()) { - return EventChatDecorator.CANCELLING_COMPONENT; - } else if (result.object() != null) { - return result.object(); - } - } - - return component; - })); - } -} diff --git a/fabric/src/main/resources/architectury.mixins.json b/fabric/src/main/resources/architectury.mixins.json index e5a3571f..a5cdf04c 100644 --- a/fabric/src/main/resources/architectury.mixins.json +++ b/fabric/src/main/resources/architectury.mixins.json @@ -22,7 +22,6 @@ "client.MixinTextureAtlas" ], "mixins": [ - "server.MixinDedicatedServer", "BucketItemAccessor", "ExplosionPreInvoker", "HorseTameInvoker", diff --git a/gradle.properties b/gradle.properties index 368d4be1..59ff266e 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,10 +1,10 @@ org.gradle.jvmargs=-Xmx6G org.gradle.daemon=false -forgeEnabled=false +platforms=fabric -minecraft_version=22w19a -supported_version=22w19a +minecraft_version=1.19-pre1 +supported_version=1.19-pre1 cf_type=beta @@ -14,7 +14,7 @@ base_version=5.4 maven_group=dev.architectury fabric_loader_version=0.14.5 -fabric_api_version=0.52.2+1.19 +fabric_api_version=0.52.4+1.19 mod_menu_version=3.1.0 forge_version=40.1.14 diff --git a/testmod-common/build.gradle b/testmod-common/build.gradle index 94d51010..21d3a050 100644 --- a/testmod-common/build.gradle +++ b/testmod-common/build.gradle @@ -6,5 +6,5 @@ dependencies { } architectury { - common(rootProject.forgeEnabled.toBoolean()) + common(rootProject.platforms.split(",")) } diff --git a/testmod-common/src/main/java/dev/architectury/test/events/DebugEvents.java b/testmod-common/src/main/java/dev/architectury/test/events/DebugEvents.java index b7dfcd7c..35542a2a 100644 --- a/testmod-common/src/main/java/dev/architectury/test/events/DebugEvents.java +++ b/testmod-common/src/main/java/dev/architectury/test/events/DebugEvents.java @@ -62,11 +62,12 @@ public class DebugEvents { return EventResult.pass(); }); ChatEvent.SERVER.register((player, message) -> { - TestMod.SINK.accept("Server chat received: " + message); - if (message.getString().contains("shit")) { - return CompoundEventResult.interruptFalse(Component.empty()); + TestMod.SINK.accept("Server chat received: " + message.getRaw()); + if (message.getRaw().getString().contains("shit")) { + return EventResult.interruptFalse(); } - return CompoundEventResult.interruptTrue(message.copy().withStyle(ChatFormatting.AQUA)); + message.modifyBoth(component -> component.copy().withStyle(ChatFormatting.AQUA)); + return EventResult.interruptTrue(); }); CommandPerformEvent.EVENT.register(event -> { TestMod.SINK.accept("Server command performed: " + event.getResults().getReader().getString());