Skip to content

Commit

Permalink
refactor: use a light-way method to implement Chat module (better c…
Browse files Browse the repository at this point in the history
…ompatibility, slightly performance improvement)
  • Loading branch information
sakurawald committed Jul 15, 2024
1 parent fbd9f27 commit 95c8bef
Show file tree
Hide file tree
Showing 13 changed files with 154 additions and 102 deletions.
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
plugins {
id 'fabric-loom' version '1.6-SNAPSHOT'
id 'fabric-loom' version '1.6.+'
id 'maven-publish'
id "com.modrinth.minotaur" version "2.+"
}
Expand Down
5 changes: 3 additions & 2 deletions src/main/java/io/github/sakurawald/Fuji.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,13 @@

import java.nio.file.Path;

// TODO: playtime(every/for) rewards module
// TODO: rank module (track)

// TODO: custom tab list
// TODO: spawn module
// TODO: command warmup module
// TODO: tppos module
// TODO: playtime(every/for) rewards module
// TODO: rank module
// TODO: remove fabric-api dep
// TODO: invsee module
// TODO: condense module
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -458,7 +458,7 @@ public class Chat {
@Documentation("""
The server chat format for all players.
""")
public String format = "<#B1B2FF>[%fuji:player_playtime%\uD83D\uDD25 %fuji:player_mined%⛏ %fuji:player_placed%\uD83D\uDD33 %fuji:player_killed%\uD83D\uDDE1 %fuji:player_moved%\uD83C\uDF0D]<reset> <<dark_green><click:suggest_command:/msg %player% ><hover:show_text:\"Time: %fuji:date%<newline><italic>Click to Message\">%player:name%</hover></click></dark_green>> %message%";
public String format = "<#B1B2FF>[%fuji:player_playtime%\uD83D\uDD25 %fuji:player_mined%⛏ %fuji:player_placed%\uD83D\uDD33 %fuji:player_killed%\uD83D\uDDE1 %fuji:player_moved%\uD83C\uDF0D]<reset> <<dark_green><click:suggest_command:/msg %player:name% ><hover:show_text:\"Time: %fuji:date%<newline><italic>Click to Message\">%player:name%</hover></click></dark_green>> %message%";

public MentionPlayer mention_player = new MentionPlayer();
public History history = new History();
Expand Down Expand Up @@ -643,7 +643,7 @@ public class DeathLog {
- %fuji:player_playtime%
- %fuji:server_playtime%
You also use [the default available placeholders](https://placeholders.pb4.eu/user/default-placeholders/)
You can also use [the default available placeholders](https://placeholders.pb4.eu/user/default-placeholders/)
in anywhere. (Yeah, you can use `placeholder` in the `en_us.json` language file, it works)
""")
public class Placeholder {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,8 @@
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.text.Text;
import net.minecraft.util.Identifier;
import net.minecraft.util.WorldSavePath;
import org.jetbrains.annotations.NotNull;

import java.io.File;
import java.time.Duration;
import java.time.temporal.ChronoUnit;
import java.util.*;
Expand Down Expand Up @@ -298,7 +296,7 @@ public String resolvePatterns(String string) {
return string;
}

public Component parseChatComponent(ServerPlayerEntity player, String message) {
public Text parseText(ServerPlayerEntity player, String message) {
/* parse message */
message = resolvePatterns(message);
message = resolveMentionTag(message);
Expand All @@ -310,7 +308,7 @@ public Component parseChatComponent(ServerPlayerEntity player, String message) {

/* combine */
String string = format.replace("%message%", message);
return MessageUtil.ofComponent(player, false, string);
return MessageUtil.ofVomponent(player, false, string);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public class EnderChestDisplayGui extends DisplayGuiBuilder {

public EnderChestDisplayGui(Text title, ServerPlayerEntity serverPlayer) {
this.title = title;
serverPlayer.getEnderChestInventory().heldStacks.forEach(itemStack -> this.items.add(itemStack.copy()));
serverPlayer.getEnderChestInventory().getHeldStacks().forEach(itemStack -> this.items.add(itemStack.copy()));
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,14 @@
import net.fabricmc.loader.api.FabricLoader;
import net.kyori.adventure.text.Component;
import net.minecraft.command.CommandRegistryAccess;
import net.minecraft.network.message.MessageType;
import net.minecraft.registry.RegistryKey;
import net.minecraft.registry.RegistryKeys;
import net.minecraft.server.command.CommandManager;
import net.minecraft.server.command.ServerCommandSource;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.text.Text;
import net.minecraft.util.Identifier;


@Slf4j
Expand All @@ -30,10 +34,11 @@ private static int clearChat(CommandContext<ServerCommandSource> ctx) {
var source = ctx.getSource();
ServerPlayerEntity player = source.getPlayer();

RegistryKey<MessageType> nowMessageType = RegistryKey.of(RegistryKeys.MESSAGE_TYPE, Identifier.ofVanilla("chat.type.text"));

log.warn("now message type = {}", nowMessageType);


Text text = Placeholders.parseText(Text.literal("my name is %player:name%, and my placeholder is %fuji:my_placeholder%"), PlaceholderContext.of(player));
player.sendMessage(text);
return 1;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package io.github.sakurawald.module.mixin.chat;

import io.github.sakurawald.module.initializer.resource_world.interfaces.SimpleRegistryMixinInterface;
import io.github.sakurawald.module.mixin.resource_world.registry.SimpleRegistryMixin;
import lombok.extern.slf4j.Slf4j;
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents;
import net.minecraft.network.message.MessageType;
import net.minecraft.registry.*;
import net.minecraft.text.Decoration;
import net.minecraft.text.Style;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Coerce;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import org.spongepowered.asm.mixin.injection.callback.LocalCapture;

import java.util.List;
import java.util.Map;

@Mixin(value = RegistryLoader.class, priority = 900)
@Slf4j
public class RegistryLoaderMixin {

/**
* This amazing mixin is written by Patbox.
* And the source is inside: <a href="https://github.dev/Patbox/StyledChat/blob/1.21/src/main/java/eu/pb4/styledchat/mixin/MessageArgumentTypeMixin.java">
* Thanks to his great work.
* <p>
* I modified the code to override the vanilla MessageType.CHAT format.
*
* @see net.minecraft.registry.SimpleRegistry#add(net.minecraft.registry.RegistryKey, java.lang.Object, net.minecraft.registry.entry.RegistryEntryInfo)
*/
@Inject(method = "load(Lnet/minecraft/registry/RegistryLoader$RegistryLoadable;Lnet/minecraft/registry/DynamicRegistryManager;Ljava/util/List;)Lnet/minecraft/registry/DynamicRegistryManager$Immutable;"
, at = @At(value = "INVOKE", target = "Ljava/util/List;forEach(Ljava/util/function/Consumer;)V", ordinal = 0, shift = At.Shift.AFTER), locals = LocalCapture.CAPTURE_FAILEXCEPTION)
private static void styledChat$injectMessageTypes(@Coerce Object registryLoadable, DynamicRegistryManager dynamicRegistryManager, List<RegistryLoader.Entry<?>> entries, CallbackInfoReturnable<DynamicRegistryManager.Immutable> cir, Map map,
List<RegistryLoader.Loader<?>> loaders, RegistryOps.RegistryInfoGetter registryInfoGetter) {
Decoration firstDecoration = new Decoration("%s", List.of(Decoration.Parameter.CONTENT), Style.EMPTY);
Decoration secondDecoration = Decoration.ofChat("chat.type.text.narrate");

for (RegistryLoader.Loader<?> entry : loaders) {
MutableRegistry<?> registry = entry.comp_2246();
RegistryKey<? extends Registry<?>> registryKey = registry.getKey();

if (registryKey.equals(RegistryKeys.MESSAGE_TYPE)) {
Registry<MessageType> registryForMessageType = (Registry<MessageType>) registry;

// The code is tricky, we need to register it later to override the vanilla registerKey.
ServerLifecycleEvents.SERVER_STARTED.register(server -> {
SimpleRegistryMixinInterface<MessageType> ex = (SimpleRegistryMixinInterface<MessageType>) registry;
ex.fuji$setFrozen(false);
Registry.register(registryForMessageType, MessageType.CHAT, new MessageType(firstDecoration, secondDecoration));
ex.fuji$setFrozen(true);
});

}
}
}
}
Original file line number Diff line number Diff line change
@@ -1,23 +1,17 @@
package io.github.sakurawald.module.mixin.chat;

import io.github.sakurawald.Fuji;
import io.github.sakurawald.module.ModuleManager;
import io.github.sakurawald.module.initializer.chat.ChatInitializer;
import io.github.sakurawald.util.MessageUtil;
import lombok.extern.slf4j.Slf4j;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer;
import net.minecraft.network.message.MessageSignatureStorage;
import net.minecraft.network.message.SignedMessage;
import net.minecraft.server.network.ServerPlayNetworkHandler;
import net.minecraft.server.network.ServerPlayerEntity;
import org.spongepowered.asm.mixin.Final;
import net.minecraft.text.Text;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
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.ModifyVariable;

@Mixin(value = ServerPlayNetworkHandler.class, priority = 1001)
@Slf4j
Expand All @@ -28,18 +22,12 @@ public abstract class ServerGamePacketListenerImplMixin {
@Shadow
public ServerPlayerEntity player;

@Inject(method = "handleDecoratedMessage", at = @At(value = "HEAD"), cancellable = true)
public void handleChat(SignedMessage playerChatMessage, CallbackInfo ci) {
Component component = module.parseChatComponent(player, playerChatMessage.getContent().getString());
module.getChatHistory().add(component);

// info so that it can be seen in the console
Fuji.LOGGER.info(PlainTextComponentSerializer.plainText().serialize(component));
@ModifyVariable(method = "handleDecoratedMessage", at = @At(value = "HEAD"))
public SignedMessage handleChat(SignedMessage before) {
Text text = module.parseText(player, before.getContent().getString());
module.getChatHistory().add(text.asComponent());

for (ServerPlayerEntity serverPlayerEntity : Fuji.SERVER.getPlayerManager().getPlayerList()) {
serverPlayerEntity.sendMessage(component);
}

ci.cancel();
return before.withUnsignedContent(text);
}
}
49 changes: 26 additions & 23 deletions src/main/java/io/github/sakurawald/util/MessageUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,17 @@
import eu.pb4.placeholders.api.node.LiteralNode;
import eu.pb4.placeholders.api.node.TextNode;
import eu.pb4.placeholders.api.parsers.NodeParser;
import eu.pb4.placeholders.api.parsers.TagParser;
import eu.pb4.placeholders.api.parsers.tag.TagRegistry;
import eu.pb4.placeholders.api.parsers.tag.TextTag;
import eu.pb4.placeholders.impl.textparser.MergedParser;
import io.github.sakurawald.Fuji;
import io.github.sakurawald.config.Configs;
import io.github.sakurawald.config.handler.ResourceConfigHandler;
import lombok.Getter;
import lombok.experimental.UtilityClass;
import lombok.extern.slf4j.Slf4j;
import net.kyori.adventure.audience.Audience;
import net.kyori.adventure.platform.fabric.FabricServerAudiences;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.minimessage.MiniMessage;
import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.server.command.ServerCommandSource;
Expand All @@ -37,15 +35,16 @@
import java.util.List;
import java.util.Map;

import static eu.pb4.placeholders.api.Placeholders.DEFAULT_PLACEHOLDER_PARSER;

@UtilityClass
@Slf4j
public class MessageUtil {
private static final MergedParser MERGED_PARSER = new MergedParser(
new NodeParser[]{
DEFAULT_PLACEHOLDER_PARSER
, TagParser.QUICK_TEXT_WITH_STF
});
private static final NodeParser NODE_PARSER = NodeParser.builder()
.quickText()
.simplifiedTextFormat()
.globalPlaceholders()
.markdown()
.build();

private static final FabricServerAudiences adventure = FabricServerAudiences.of(Fuji.SERVER);
@Getter
private static final Map<String, String> player2lang = new HashMap<>();
Expand All @@ -63,8 +62,8 @@ public class MessageUtil {
true,
(nodes, data, parser) -> new LiteralNode("\n")
)

);

}

private static void writeDefaultLanguageFiles() {
Expand Down Expand Up @@ -147,7 +146,7 @@ public static void sendMessageToPlayerEntity(PlayerEntity player, String key, Ob
/* This is the core method to map `String` into `Component`.
* All methods that return `Vomponent` are converted from this method.
* */
public static @NotNull Component ofComponent(@Nullable Audience audience, boolean isKey, String keyOrString, Object... args) {
public static @NotNull Text ofVomponent(@Nullable Audience audience, boolean isKey, String keyOrString, Object... args) {
String string = isKey ? getString(audience, keyOrString, args) : keyOrString;

PlaceholderContext placeholderContext;
Expand All @@ -158,23 +157,15 @@ public static void sendMessageToPlayerEntity(PlayerEntity player, String key, Ob
}
ParserContext parserContext = ParserContext.of(PlaceholderContext.KEY, placeholderContext);

return MERGED_PARSER.parseText(TextNode.of(string), parserContext).asComponent();
}

public static @NotNull Component ofComponent(@Nullable Audience audience, String key, Object... args) {
return ofComponent(audience, true, key, args);
return NODE_PARSER.parseText(TextNode.of(string), parserContext);
}

public static @NotNull Text ofVomponent(@Nullable Audience audience, String key, Object... args) {
return toVomponent(ofComponent(audience, key, args));
return ofVomponent(audience, true, key, args);
}

public static @NotNull Text ofVomponent(String str, Object... args) {
return toVomponent(ofComponent(null, false, str, args));
}

public static @NotNull Text toVomponent(Component component) {
return adventure.toNative(component);
return ofVomponent(null, false, str, args);
}

public static List<Text> ofVomponents(@Nullable Audience audience, String key, Object... args) {
Expand All @@ -187,6 +178,18 @@ public static List<Text> ofVomponents(@Nullable Audience audience, String key, O
return ret;
}

public static @NotNull Text toVomponent(Component component) {
return adventure.toNative(component);
}

public static @NotNull Component ofComponent(@Nullable Audience audience, boolean isKey, String keyOrString, Object... args) {
return ofVomponent(audience, isKey, keyOrString, args).asComponent();
}

public static @NotNull Component ofComponent(@Nullable Audience audience, String key, Object... args) {
return ofComponent(audience, true, key, args);
}

public static void sendMessage(@NotNull Audience audience, String key, Object... args) {
audience.sendMessage(ofComponent(audience, key, args));
}
Expand Down
2 changes: 1 addition & 1 deletion src/main/resources/assets/fuji/lang/en_us.json
Original file line number Diff line number Diff line change
Expand Up @@ -177,5 +177,5 @@
"chat.xaero_waypoint_add": "Click to add a Xaero's minimap waypoint",
"chat.xaero_waypoint_add.command": "/xaero_waypoint_add:Waypoint:·:%d:%s:%d:0:false:0:Internal_%s_waypoints",
"realname": "<gold>Real name is %s",
"anti_build.disallow": "<red> This action is disallowed by anti build."
"anti_build.disallow": "<red>This action is disallowed by anti build."
}
2 changes: 1 addition & 1 deletion src/main/resources/assets/fuji/lang/zh_cn.json
Original file line number Diff line number Diff line change
Expand Up @@ -177,5 +177,5 @@
"chat.xaero_waypoint_add": "点击添加小地图路径点",
"chat.xaero_waypoint_add.command": "/xaero_waypoint_add:路径点:·:%d:%s:%d:0:false:0:Internal_%s_waypoints",
"realname": "<gold>玩家名称 %s",
"anti_build.disallow": "<red> 该操作被禁止"
"anti_build.disallow": "<red>该操作被禁止"
}
7 changes: 2 additions & 5 deletions src/main/resources/fuji.accesswidener
Original file line number Diff line number Diff line change
@@ -1,15 +1,12 @@
accessWidener v2 named

# accessible field net/minecraft/registry/entry/RegistryEntry$Reference value Ljava/lang/Object;

accessible method net/minecraft/server/world/ServerChunkManager getChunkHolder (J)Lnet/minecraft/server/world/ChunkHolder;

accessible method net/minecraft/util/UserCache$Entry getProfile ()Lcom/mojang/authlib/GameProfile;

accessible field net/minecraft/server/world/ChunkHolder UNLOADED_WORLD_CHUNK Lnet/minecraft/server/world/OptionalChunk;
accessible field net/minecraft/server/world/ChunkHolder UNLOADED_WORLD_CHUNK_FUTURE Ljava/util/concurrent/CompletableFuture;

accessible field net/minecraft/registry/entry/RegistryEntry$Reference value Ljava/lang/Object;

accessible field net/minecraft/server/MinecraftServer worlds Ljava/util/Map;
accessible field net/minecraft/server/MinecraftServer session Lnet/minecraft/world/level/storage/LevelStorage$Session;

accessible class net/minecraft/registry/RegistryLoader$Loader
Loading

0 comments on commit 95c8bef

Please sign in to comment.