Switch to Fabric events for processing chat

This commit is contained in:
shedaniel
2022-07-16 17:02:23 +08:00
parent 216556bab6
commit cf97a7f5ee
5 changed files with 27 additions and 122 deletions

View File

@@ -19,14 +19,14 @@
package dev.architectury.event.fabric;
import dev.architectury.event.EventResult;
import dev.architectury.event.events.client.ClientGuiEvent;
import dev.architectury.event.events.client.ClientLifecycleEvent;
import dev.architectury.event.events.client.ClientTickEvent;
import dev.architectury.event.events.client.ClientTooltipEvent;
import dev.architectury.event.events.common.CommandRegistrationEvent;
import dev.architectury.event.events.common.InteractionEvent;
import dev.architectury.event.events.common.LifecycleEvent;
import dev.architectury.event.events.common.TickEvent;
import dev.architectury.event.events.common.*;
import dev.architectury.impl.fabric.ChatComponentImpl;
import dev.architectury.impl.fabric.EventChatDecorator;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientLifecycleEvents;
@@ -40,6 +40,9 @@ import net.fabricmc.fabric.api.event.lifecycle.v1.ServerWorldEvents;
import net.fabricmc.fabric.api.event.player.AttackBlockCallback;
import net.fabricmc.fabric.api.event.player.UseBlockCallback;
import net.fabricmc.fabric.api.event.player.UseItemCallback;
import net.fabricmc.fabric.api.message.v1.ServerMessageDecoratorEvent;
import java.util.concurrent.CompletableFuture;
public class EventHandlerImpl {
@Environment(EnvType.CLIENT)
@@ -75,6 +78,20 @@ public class EventHandlerImpl {
UseItemCallback.EVENT.register((player, world, hand) -> InteractionEvent.RIGHT_CLICK_ITEM.invoker().click(player, hand).asMinecraft());
UseBlockCallback.EVENT.register((player, world, hand, hitResult) -> InteractionEvent.RIGHT_CLICK_BLOCK.invoker().click(player, hand, hitResult.getBlockPos(), hitResult.getDirection()).asMinecraft());
AttackBlockCallback.EVENT.register((player, world, hand, pos, face) -> InteractionEvent.LEFT_CLICK_BLOCK.invoker().click(player, hand, pos, face).asMinecraft());
ServerMessageDecoratorEvent.EVENT.register(ServerMessageDecoratorEvent.CONTENT_PHASE, (player, component) -> {
ChatEvent.ChatComponent chatComponent = new ChatComponentImpl(component, component);
EventResult result = ChatEvent.SERVER.invoker().process(player, chatComponent);
if (result.isPresent()) {
if (result.isFalse()) {
return CompletableFuture.completedFuture(EventChatDecorator.CANCELLING_COMPONENT);
} else {
return CompletableFuture.completedFuture(chatComponent.getFiltered());
}
}
return CompletableFuture.completedFuture(component);
});
}
@Environment(EnvType.SERVER)

View File

@@ -19,68 +19,8 @@
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 class EventChatDecorator {
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 CompletableFuture<Component> 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 CompletableFuture<FilteredText<Component>> decorateFiltered(@Nullable ServerPlayer player, FilteredText<Component> message) {
return parent.decorateFiltered(player, message).thenApply(newMessage -> {
FilteredText<Component> newContent = processor.process(player, newMessage);
if (!newContent.equals(newMessage)) {
return newContent;
}
return newMessage;
}).exceptionally(throwable -> {
throwable.printStackTrace();
return message;
});
}
@Override
public CompletableFuture<FilteredText<PlayerChatMessage>> decorateChat(@Nullable ServerPlayer player, FilteredText<Component> component, MessageSignature signature, boolean signedPreview) {
return parent.decorateChat(player, component, signature, signedPreview).thenApply(message -> {
FilteredText<Component> newComponent = processor.process(player, message.map(PlayerChatMessage::signedContent));
FilteredText<PlayerChatMessage> 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 {
FilteredText<Component> process(@Nullable ServerPlayer player, FilteredText<Component> text);
}
}

View File

@@ -1,55 +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;
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;
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<ChatDecorator> cir) {
ChatDecorator parent = cir.getReturnValue();
cir.setReturnValue(new EventChatDecorator(parent, (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 FilteredText.fullyFiltered(EventChatDecorator.CANCELLING_COMPONENT);
} else {
return new FilteredText<>(chatComponent.getRaw(), chatComponent.getFiltered());
}
}
return component;
}));
}
}

View File

@@ -44,7 +44,6 @@
"MixinInventory",
"MixinItemEntity",
"MixinLivingEntity",
"MixinMinecraftServer",
"MixinNaturalSpawner",
"MixinOcelot",
"MixinPatrolSpawner",

View File

@@ -66,7 +66,7 @@ public class DebugEvents {
if (message.getRaw().getString().contains("shit")) {
return EventResult.interruptFalse();
}
message.modifyBoth(component -> component.copy().withStyle(ChatFormatting.AQUA));
message.modifyBoth(component -> component.copy().withStyle(ChatFormatting.AQUA).append(" + new text"));
return EventResult.interruptTrue();
});
CommandPerformEvent.EVENT.register(event -> {
@@ -255,6 +255,10 @@ public class DebugEvents {
});
ClientChatEvent.PROCESS.register((message) -> {
TestMod.SINK.accept("Client chat sent: " + message.getMessage());
if (message.getMessage().contains("error")) {
message.setMessage("Error: " + message.getMessage());
return EventResult.interruptTrue();
}
return EventResult.pass();
});
ClientChatEvent.RECEIVED.register((type, message, sender) -> {