diff --git a/common/src/main/java/dev/architectury/core/fluid/ArchitecturyFluidAttributes.java b/common/src/main/java/dev/architectury/core/fluid/ArchitecturyFluidAttributes.java index af9ca0cf..1943ecee 100644 --- a/common/src/main/java/dev/architectury/core/fluid/ArchitecturyFluidAttributes.java +++ b/common/src/main/java/dev/architectury/core/fluid/ArchitecturyFluidAttributes.java @@ -22,7 +22,6 @@ package dev.architectury.core.fluid; import dev.architectury.fluid.FluidStack; import net.minecraft.core.BlockPos; import net.minecraft.network.chat.Component; -import net.minecraft.network.chat.TranslatableComponent; import net.minecraft.resources.ResourceLocation; import net.minecraft.sounds.SoundEvent; import net.minecraft.world.item.Item; @@ -65,7 +64,7 @@ public interface ArchitecturyFluidAttributes { * @return the name */ default Component getName(@Nullable FluidStack stack) { - return new TranslatableComponent(getTranslationKey(stack)); + return Component.translatable(getTranslationKey(stack)); } /** diff --git a/common/src/main/java/dev/architectury/event/events/client/ClientChatEvent.java b/common/src/main/java/dev/architectury/event/events/client/ClientChatEvent.java index 5c126fa8..f289aba4 100644 --- a/common/src/main/java/dev/architectury/event/events/client/ClientChatEvent.java +++ b/common/src/main/java/dev/architectury/event/events/client/ClientChatEvent.java @@ -29,16 +29,14 @@ import net.minecraft.network.chat.ChatType; import net.minecraft.network.chat.Component; import org.jetbrains.annotations.Nullable; -import java.util.UUID; - @Environment(EnvType.CLIENT) public interface ClientChatEvent { /** - * @see Process#process(String) + * @see Process#process(ChatType, Component, ChatSender) */ Event PROCESS = EventFactory.createCompoundEventResult(); /** - * @see Received#process(ChatType, Component, UUID) + * @see Received#process(ChatType, Component, ChatSender) */ Event RECEIVED = EventFactory.createCompoundEventResult(); @@ -48,11 +46,11 @@ public interface ClientChatEvent { * Event to modify the chat message a clients sends. * Equivalent to Forge's {@code ClientChatEvent} event. * - * @param message The raw chat message the client wants to send. + * @param message The chat message the client wants to send. * @return A {@link CompoundEventResult} determining the outcome of the event, * if an outcome is set, the sent message is overridden. */ - CompoundEventResult process(String message); + CompoundEventResult process(ChatType chatType, Component message, @Nullable ChatSender sender); } @Environment(EnvType.CLIENT) 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 aead343c..348456bb 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 @@ -19,16 +19,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 net.minecraft.server.network.TextFilter; +import org.jetbrains.annotations.Nullable; public interface ChatEvent { /** - * @see Server#process(ServerPlayer, TextFilter.FilteredText, ChatComponent) + * @see Server#process(ServerPlayer, Component) */ Event SERVER = EventFactory.createEventResult(); @@ -37,22 +37,11 @@ public interface ChatEvent { * Invoked when the server receives a message from a client. * Equivalent to Forge's {@code ServerChatEvent} event. * - * @param player The player who has sent the message. - * @param message The raw message itself. + * @param player The player who has sent the message, or null. * @param component The message as component. - * @return A {@link EventResult} determining the outcome of the event, - * the execution of the vanilla message may be cancelled by the result. + * @return A {@link CompoundEventResult} determining the outcome of the event, + * if an outcome is set, the sent message is overridden. */ - EventResult process(ServerPlayer player, TextFilter.FilteredText message, ChatComponent component); - } - - interface ChatComponent { - Component getRaw(); - - Component getFiltered(); - - void setRaw(Component raw); - - void setFiltered(Component filtered); + CompoundEventResult process(@Nullable ServerPlayer player, Component component); } } diff --git a/fabric/src/main/java/dev/architectury/impl/fabric/ChatComponentImpl.java b/fabric/src/main/java/dev/architectury/impl/fabric/ChatComponentImpl.java deleted file mode 100644 index 75c36a40..00000000 --- a/fabric/src/main/java/dev/architectury/impl/fabric/ChatComponentImpl.java +++ /dev/null @@ -1,53 +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.impl.fabric; - -import dev.architectury.event.events.common.ChatEvent; -import net.minecraft.network.chat.Component; - -public class ChatComponentImpl implements ChatEvent.ChatComponent { - private Component raw; - private Component filtered; - - public ChatComponentImpl(Component raw, Component filtered) { - this.raw = raw; - this.filtered = filtered; - } - - @Override - public Component getRaw() { - return raw; - } - - @Override - public Component getFiltered() { - return filtered; - } - - @Override - public void setRaw(Component raw) { - this.raw = raw; - } - - @Override - public void setFiltered(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 new file mode 100644 index 00000000..6e115a75 --- /dev/null +++ b/fabric/src/main/java/dev/architectury/impl/fabric/EventChatDecorator.java @@ -0,0 +1,68 @@ +/* + * 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 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 org.jetbrains.annotations.Nullable; + +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; + private final ChatProcessor processor; + + public EventChatDecorator(ChatDecorator parent, ChatProcessor processor) { + this.parent = parent; + this.processor = processor; + } + + @Override + public Component decorate(@Nullable ServerPlayer player, Component component) { + return processor.process(player, parent.decorate(player, 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; + } + + @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; + } + + @FunctionalInterface + public interface ChatProcessor { + Component process(@Nullable ServerPlayer player, Component component); + } +} diff --git a/fabric/src/main/java/dev/architectury/mixin/fabric/MixinMinecraftServer.java b/fabric/src/main/java/dev/architectury/mixin/fabric/MixinMinecraftServer.java new file mode 100644 index 00000000..cf73819f --- /dev/null +++ b/fabric/src/main/java/dev/architectury/mixin/fabric/MixinMinecraftServer.java @@ -0,0 +1,51 @@ +/* + * 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; + +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.MinecraftServer; +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(MinecraftServer.class) +public class MixinMinecraftServer { + @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/java/dev/architectury/mixin/fabric/MixinServerGamePacketListenerImpl.java b/fabric/src/main/java/dev/architectury/mixin/fabric/MixinServerGamePacketListenerImpl.java index 02683d7d..3e9c9fb6 100644 --- a/fabric/src/main/java/dev/architectury/mixin/fabric/MixinServerGamePacketListenerImpl.java +++ b/fabric/src/main/java/dev/architectury/mixin/fabric/MixinServerGamePacketListenerImpl.java @@ -19,9 +19,10 @@ package dev.architectury.mixin.fabric; -import dev.architectury.event.events.common.ChatEvent; -import dev.architectury.impl.fabric.ChatComponentImpl; -import net.minecraft.network.chat.*; +import dev.architectury.impl.fabric.EventChatDecorator; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.MessageSignature; +import net.minecraft.network.chat.PlayerChatMessage; import net.minecraft.network.protocol.game.ServerboundChatPacket; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerPlayer; @@ -35,8 +36,6 @@ import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.LocalCapture; -import java.util.Objects; - @Mixin(ServerGamePacketListenerImpl.class) public abstract class MixinServerGamePacketListenerImpl { @Shadow @@ -51,34 +50,10 @@ public abstract class MixinServerGamePacketListenerImpl { @Inject(method = "handleChat(Lnet/minecraft/network/protocol/game/ServerboundChatPacket;Lnet/minecraft/server/network/TextFilter$FilteredText;)V", at = @At(value = "INVOKE", - target = "Lnet/minecraft/server/players/PlayerList;broadcastChatMessage(Lnet/minecraft/network/chat/SignedMessage;Lnet/minecraft/server/network/TextFilter$FilteredText;Lnet/minecraft/server/level/ServerPlayer;Lnet/minecraft/resources/ResourceKey;)V"), + 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) { - MutableComponent raw = Component.literal(message.getRaw()); - MutableComponent filtered = Component.literal(message.getFiltered()); - var chatComponent = new ChatComponentImpl(raw, filtered); - var process = ChatEvent.SERVER.invoker().process(this.player, message, chatComponent); - if (process.isEmpty()) return; - if (process.isFalse()) { - ci.cancel(); - } else if (!Objects.equals(chatComponent.getRaw(), raw) || !Objects.equals(chatComponent.getFiltered(), filtered)) { - MessageSignature messageSignature = packet.getSignature(this.player.getUUID()); - SignedMessage signedMessage = new SignedMessage(chatComponent.getRaw(), messageSignature); - - { - SignedMessage filteredMessage; - if (!chatComponent.getFiltered().getString().isEmpty()) { - filteredMessage = new SignedMessage(chatComponent.getFiltered(), MessageSignature.unsigned()); - } else { - filteredMessage = null; - } - - this.server.getPlayerList().broadcastChatMessage(signedMessage, (serverPlayer2) -> { - return player.shouldFilterMessageTo(serverPlayer2) ? filteredMessage : signedMessage; - }, player.asChatSender(), ChatType.CHAT); - } - - this.detectRateSpam(); + private void handleChat(ServerboundChatPacket packet, TextFilter.FilteredText message, CallbackInfo ci, Component component, MessageSignature signature, PlayerChatMessage chatMessage) { + if (chatMessage.serverContent().equals(EventChatDecorator.CANCELLING_COMPONENT)) { ci.cancel(); } } diff --git a/fabric/src/main/java/dev/architectury/mixin/fabric/client/MixinClientPacketListener.java b/fabric/src/main/java/dev/architectury/mixin/fabric/client/MixinClientPacketListener.java index 3df586e7..21a8e5ab 100644 --- a/fabric/src/main/java/dev/architectury/mixin/fabric/client/MixinClientPacketListener.java +++ b/fabric/src/main/java/dev/architectury/mixin/fabric/client/MixinClientPacketListener.java @@ -27,7 +27,14 @@ import net.minecraft.client.multiplayer.ClientLevel; import net.minecraft.client.multiplayer.ClientPacketListener; import net.minecraft.client.player.LocalPlayer; import net.minecraft.core.Registry; -import net.minecraft.network.protocol.game.*; +import net.minecraft.network.chat.ChatSender; +import net.minecraft.network.chat.ChatType; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.PlayerChatMessage; +import net.minecraft.network.protocol.game.ClientboundLoginPacket; +import net.minecraft.network.protocol.game.ClientboundRespawnPacket; +import net.minecraft.network.protocol.game.ClientboundSystemChatPacket; +import net.minecraft.network.protocol.game.ClientboundUpdateRecipesPacket; import net.minecraft.world.item.crafting.RecipeManager; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; @@ -36,6 +43,7 @@ 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.CallbackInfo; +import org.spongepowered.asm.mixin.injection.callback.LocalCapture; @Mixin(ClientPacketListener.class) public class MixinClientPacketListener { @@ -83,18 +91,17 @@ public class MixinClientPacketListener { } } - @Inject(method = "handlePlayerChat", at = @At(value = "INVOKE", + @Inject(method = "handlePlayerChat(Lnet/minecraft/network/chat/ChatType;Lnet/minecraft/network/chat/PlayerChatMessage;Lnet/minecraft/network/chat/ChatSender;)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/Gui;handlePlayerChat(Lnet/minecraft/network/chat/ChatType;Lnet/minecraft/network/chat/Component;Lnet/minecraft/network/chat/ChatSender;)V"), - cancellable = true) - private void handleChat(ClientboundPlayerChatPacket packet, CallbackInfo ci) { + cancellable = true, locals = LocalCapture.CAPTURE_FAILHARD) + private void handleChat(ChatType chatType, PlayerChatMessage playerChatMessage, ChatSender sender, CallbackInfo ci, boolean showSigned, Component component) { var registry = this.level.registryAccess().registryOrThrow(Registry.CHAT_TYPE_REGISTRY); - var chatType = packet.resolveType(registry); - var process = ClientChatEvent.RECEIVED.invoker().process(chatType, packet.content(), packet.sender()); + var process = ClientChatEvent.RECEIVED.invoker().process(chatType, component, sender); if (process.isEmpty()) return; if (process.isFalse()) { ci.cancel(); - } else if (process.object() != null && !process.object().equals(packet.content())) { - this.minecraft.gui.handlePlayerChat(chatType, packet.content(), packet.sender()); + } else if (process.object() != null && !process.object().equals(component)) { + this.minecraft.gui.handlePlayerChat(chatType, component, sender); ci.cancel(); } } diff --git a/fabric/src/main/java/dev/architectury/mixin/fabric/client/MixinGui.java b/fabric/src/main/java/dev/architectury/mixin/fabric/client/MixinGui.java new file mode 100644 index 00000000..cb5f35d4 --- /dev/null +++ b/fabric/src/main/java/dev/architectury/mixin/fabric/client/MixinGui.java @@ -0,0 +1,103 @@ +/* + * 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.client; + +import dev.architectury.event.events.client.ClientChatEvent; +import dev.architectury.impl.fabric.EventChatDecorator; +import net.minecraft.client.gui.Gui; +import net.minecraft.network.chat.ChatSender; +import net.minecraft.network.chat.ChatType; +import net.minecraft.network.chat.Component; +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.ModifyVariable; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(Gui.class) +public abstract class MixinGui { + @Unique + private ChatType chatType; + @Unique + private ChatSender chatSender; + + @Inject(method = "handlePlayerChat", at = @At(value = "HEAD")) + private void handleChatPre(ChatType chatType, Component component, ChatSender chatSender, CallbackInfo ci) { + this.chatType = chatType; + this.chatSender = chatSender; + } + + @ModifyVariable(method = "handlePlayerChat", at = @At("HEAD"), argsOnly = true, ordinal = 0) + private Component modifyMessage(Component message) { + if (chatType == null) { + chatType = null; + chatSender = null; + return message; + } + var process = ClientChatEvent.PROCESS.invoker().process(chatType, message, chatSender); + if (process.isPresent()) { + if (process.isFalse()) + return EventChatDecorator.CANCELLING_COMPONENT; + if (process.object() != null) + return process.object(); + } + return message; + } + + @Inject(method = "handlePlayerChat", at = @At(value = "INVOKE", + target = "Lnet/minecraft/client/Minecraft;isBlocked(Ljava/util/UUID;)Z", ordinal = 0), + cancellable = true) + private void handleChat(ChatType chatType, Component component, ChatSender chatSender, CallbackInfo ci) { + if (EventChatDecorator.CANCELLING_COMPONENT.equals(component)) { + ci.cancel(); + } + } + + @Inject(method = "handleSystemChat", at = @At(value = "HEAD")) + private void handleSystemChatPre(ChatType chatType, Component component, CallbackInfo ci) { + this.chatType = chatType; + } + + @ModifyVariable(method = "handleSystemChat", at = @At("HEAD"), argsOnly = true, ordinal = 0) + private Component modifySystemMessage(Component message) { + if (chatType == null) { + chatType = null; + return message; + } + var process = ClientChatEvent.PROCESS.invoker().process(chatType, message, null); + if (process.isPresent()) { + if (process.isFalse()) + return EventChatDecorator.CANCELLING_COMPONENT; + if (process.object() != null) + return process.object(); + } + return message; + } + + @Inject(method = "handleSystemChat", at = @At(value = "INVOKE", + target = "Lnet/minecraft/client/Options;hideMatchedNames()Lnet/minecraft/client/OptionInstance;"), + cancellable = true) + private void handleChat(ChatType chatType, Component component, CallbackInfo ci) { + if (EventChatDecorator.CANCELLING_COMPONENT.equals(component)) { + ci.cancel(); + } + } +} diff --git a/fabric/src/main/java/dev/architectury/mixin/fabric/client/MixinScreen.java b/fabric/src/main/java/dev/architectury/mixin/fabric/client/MixinScreen.java index 9d224783..e6903fd5 100644 --- a/fabric/src/main/java/dev/architectury/mixin/fabric/client/MixinScreen.java +++ b/fabric/src/main/java/dev/architectury/mixin/fabric/client/MixinScreen.java @@ -20,7 +20,6 @@ package dev.architectury.mixin.fabric.client; import com.mojang.blaze3d.vertex.PoseStack; -import dev.architectury.event.events.client.ClientChatEvent; import dev.architectury.event.events.client.ClientGuiEvent; import dev.architectury.event.events.client.ClientTooltipEvent; import dev.architectury.hooks.client.screen.ScreenAccess; @@ -86,18 +85,6 @@ public abstract class MixinScreen implements ScreenInputDelegate { ClientGuiEvent.INIT_POST.invoker().init((Screen) (Object) this, getAccess()); } - @ModifyVariable(method = "sendMessage(Ljava/lang/String;Z)V", at = @At("HEAD"), argsOnly = true, ordinal = 0) - private String modifyMessage(String message) { - var process = ClientChatEvent.PROCESS.invoker().process(message); - if (process.isPresent()) { - if (process.isFalse()) - return ""; - if (process.object() != null) - return process.object(); - } - return message; - } - @Inject(method = "renderTooltip(Lcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/world/item/ItemStack;II)V", at = @At("HEAD")) private void preRenderTooltipItem(PoseStack poseStack, ItemStack stack, int x, int y, CallbackInfo ci) { ClientTooltipEvent.additionalContexts().setItem(stack); 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 new file mode 100644 index 00000000..628c6e9c --- /dev/null +++ b/fabric/src/main/java/dev/architectury/mixin/fabric/server/MixinDedicatedServer.java @@ -0,0 +1,51 @@ +/* + * 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 0a6c3dba..e5a3571f 100644 --- a/fabric/src/main/resources/architectury.mixins.json +++ b/fabric/src/main/resources/architectury.mixins.json @@ -12,6 +12,7 @@ "client.MixinDebugScreenOverlay", "client.MixinEffectInstance", "client.MixinGameRenderer", + "client.MixinGui", "client.MixinIntegratedServer", "client.MixinKeyboardHandler", "client.MixinMinecraft", @@ -21,6 +22,7 @@ "client.MixinTextureAtlas" ], "mixins": [ + "server.MixinDedicatedServer", "BucketItemAccessor", "ExplosionPreInvoker", "HorseTameInvoker", @@ -41,6 +43,7 @@ "MixinInventory", "MixinItemEntity", "MixinLivingEntity", + "MixinMinecraftServer", "MixinNaturalSpawner", "MixinOcelot", "MixinPatrolSpawner", diff --git a/gradle.properties b/gradle.properties index c3d02840..368d4be1 100644 --- a/gradle.properties +++ b/gradle.properties @@ -3,8 +3,8 @@ org.gradle.daemon=false forgeEnabled=false -minecraft_version=22w18a -supported_version=22w18a +minecraft_version=22w19a +supported_version=22w19a cf_type=beta @@ -13,8 +13,8 @@ archives_base_name_snapshot=architectury-snapshot base_version=5.4 maven_group=dev.architectury -fabric_loader_version=0.14.3 -fabric_api_version=0.52.1+1.19 +fabric_loader_version=0.14.5 +fabric_api_version=0.52.2+1.19 mod_menu_version=3.1.0 forge_version=40.1.14 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 ce43c54a..b7dfcd7c 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 @@ -30,6 +30,7 @@ import dev.architectury.test.TestMod; import dev.architectury.utils.Env; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; +import net.minecraft.ChatFormatting; import net.minecraft.client.gui.screens.inventory.AnvilScreen; import net.minecraft.core.Position; import net.minecraft.core.Vec3i; @@ -60,9 +61,12 @@ public class DebugEvents { TestMod.SINK.accept(Optional.ofNullable(placer).map(Entity::getScoreboardName).orElse("null") + " places block at " + toShortString(pos) + logSide(world)); return EventResult.pass(); }); - ChatEvent.SERVER.register((player, message, component) -> { - TestMod.SINK.accept("Server chat received: " + message.getRaw()); - 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()); + } + return CompoundEventResult.interruptTrue(message.copy().withStyle(ChatFormatting.AQUA)); }); CommandPerformEvent.EVENT.register(event -> { TestMod.SINK.accept("Server command performed: " + event.getResults().getReader().getString()); @@ -248,8 +252,8 @@ public class DebugEvents { e.printStackTrace(); } }); - ClientChatEvent.PROCESS.register(message -> { - TestMod.SINK.accept("Client chat sent: " + message); + ClientChatEvent.PROCESS.register((type, message, sender) -> { + TestMod.SINK.accept("Client chat sent: " + message + " of type " + type.chat()); return CompoundEventResult.pass(); }); ClientChatEvent.RECEIVED.register((type, message, sender) -> { diff --git a/testmod-common/src/main/java/dev/architectury/test/registry/TestRegistries.java b/testmod-common/src/main/java/dev/architectury/test/registry/TestRegistries.java index ec8ce33b..461b0489 100644 --- a/testmod-common/src/main/java/dev/architectury/test/registry/TestRegistries.java +++ b/testmod-common/src/main/java/dev/architectury/test/registry/TestRegistries.java @@ -143,7 +143,7 @@ public class TestRegistries { // In example mod the forge class isn't being replaced, this is not required in mods depending on architectury return (LiquidBlock) Class.forName(!Platform.isForge() ? "dev.architectury.core.block.ArchitecturyLiquidBlock" : "dev.architectury.core.block.forge.imitator.ArchitecturyLiquidBlock") .getDeclaredConstructor(Supplier.class, BlockBehaviour.Properties.class) - .newInstance(TestRegistries.TEST_FLUID, BlockBehaviour.Properties.copy(Blocks.WATER).noCollission().strength(100.0F).noDrops()); + .newInstance(TestRegistries.TEST_FLUID, BlockBehaviour.Properties.copy(Blocks.WATER).noCollission().strength(100.0F).noLootTable()); } catch (InstantiationException | ClassNotFoundException | NoSuchMethodException | InvocationTargetException | IllegalAccessException e) { throw new RuntimeException(e); }