From 5b11ac03c4acf29692799cb4be5ea42c1d1a2f8a Mon Sep 17 00:00:00 2001 From: SakuraWald <sakurawald@gmail.com> Date: Thu, 26 Oct 2023 16:57:33 +0800 Subject: [PATCH] refactor: rename ChatStyleModule -> ChatModule + refactor: Position.of() + add: ReplyModule + add: AfkModule + refactor: FlyModule + refactor: GodModule + refactor: rename ChatStyleModule -> ChatModule + --- .../github/sakurawald/config/ConfigGSON.java | 16 +++- .../sakurawald/mixin/afk/PlayerListMixin.java | 21 +++++ .../mixin/afk/ServerPlayerMixin.java | 84 +++++++++++++++++++ .../mixin/chat/PlayerListMixin.java | 4 +- .../ServerGamePacketListenerImplMixin.java | 4 +- .../teleport_warmup/ServerPlayerMixin.java | 3 +- .../sakurawald/module/afk/AfkModule.java | 83 ++++++++++++++++++ .../module/afk/ServerPlayerAccessor_afk.java | 12 +++ .../sakurawald/module/back/BackModule.java | 2 +- .../{ChatStyleModule.java => ChatModule.java} | 2 +- .../sakurawald/module/fly/FlyModule.java | 13 ++- .../sakurawald/module/god/GodModule.java | 13 +-- .../resource_world/ResourceWorldManager.java | 3 +- .../module/teleport_warmup/Position.java | 13 +++ .../github/sakurawald/util/MessageUtil.java | 1 + .../assets/sakurawald/lang/en_us.json | 7 +- .../assets/sakurawald/lang/zh_cn.json | 7 +- src/main/resources/sakurawald.mixins.json | 2 + 18 files changed, 261 insertions(+), 29 deletions(-) create mode 100755 src/main/java/io/github/sakurawald/mixin/afk/PlayerListMixin.java create mode 100644 src/main/java/io/github/sakurawald/mixin/afk/ServerPlayerMixin.java create mode 100644 src/main/java/io/github/sakurawald/module/afk/AfkModule.java create mode 100644 src/main/java/io/github/sakurawald/module/afk/ServerPlayerAccessor_afk.java rename src/main/java/io/github/sakurawald/module/chat/{ChatStyleModule.java => ChatModule.java} (99%) diff --git a/src/main/java/io/github/sakurawald/config/ConfigGSON.java b/src/main/java/io/github/sakurawald/config/ConfigGSON.java index b9ccfce11..cee2d8abc 100755 --- a/src/main/java/io/github/sakurawald/config/ConfigGSON.java +++ b/src/main/java/io/github/sakurawald/config/ConfigGSON.java @@ -62,6 +62,8 @@ public class Modules { public Fly fly = new Fly(); public God god = new God(); public Language language = new Language(); + public Reply reply = new Reply(); + public Afk afk = new Afk(); public class ResourceWorld { public boolean enable = false; @@ -386,9 +388,21 @@ public class Language { public boolean enable = false; } - public Reply reply = new Reply(); public class Reply { public boolean enable = false; } + + public class Afk { + + public boolean enable = false; + public String format = "<gray>[AFK] <reset>%player_display_name%"; + + public AfkChecker afk_checker = new AfkChecker(); + + public class AfkChecker { + public String cron = "* 0 0 ? * * *"; + public boolean kick_player = false; + } + } } } diff --git a/src/main/java/io/github/sakurawald/mixin/afk/PlayerListMixin.java b/src/main/java/io/github/sakurawald/mixin/afk/PlayerListMixin.java new file mode 100755 index 000000000..d68a3dbe2 --- /dev/null +++ b/src/main/java/io/github/sakurawald/mixin/afk/PlayerListMixin.java @@ -0,0 +1,21 @@ +package io.github.sakurawald.mixin.afk; + +import io.github.sakurawald.module.afk.ServerPlayerAccessor_afk; +import lombok.extern.slf4j.Slf4j; +import net.minecraft.network.Connection; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.server.players.PlayerList; +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.CallbackInfo; + +@Mixin(PlayerList.class) +@Slf4j +public abstract class PlayerListMixin { + @Inject(at = @At(value = "TAIL"), method = "placeNewPlayer") + private void $placeNewPlayer(Connection connection, ServerPlayer player, CallbackInfo info) { + ServerPlayerAccessor_afk afk_player = (ServerPlayerAccessor_afk) player; + afk_player.sakurawald$setLastLastActionTime(player.getLastActionTime()); + } +} diff --git a/src/main/java/io/github/sakurawald/mixin/afk/ServerPlayerMixin.java b/src/main/java/io/github/sakurawald/mixin/afk/ServerPlayerMixin.java new file mode 100644 index 000000000..a262f866a --- /dev/null +++ b/src/main/java/io/github/sakurawald/mixin/afk/ServerPlayerMixin.java @@ -0,0 +1,84 @@ +package io.github.sakurawald.mixin.afk; + +import io.github.sakurawald.config.ConfigManager; +import io.github.sakurawald.module.afk.ServerPlayerAccessor_afk; +import io.github.sakurawald.util.MessageUtil; +import lombok.extern.slf4j.Slf4j; +import net.kyori.adventure.text.TextReplacementConfig; +import net.minecraft.network.chat.Component; +import net.minecraft.network.protocol.game.ClientboundPlayerInfoUpdatePacket; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ServerPlayer; +import org.jetbrains.annotations.NotNull; +import org.spongepowered.asm.mixin.Final; +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.callback.CallbackInfoReturnable; + +import static io.github.sakurawald.util.MessageUtil.ofComponent; +import static io.github.sakurawald.util.MessageUtil.toVomponent; + +@Mixin(ServerPlayer.class) +@Slf4j +public abstract class ServerPlayerMixin implements ServerPlayerAccessor_afk { + + @Unique + private final ServerPlayer player = (ServerPlayer) (Object) this; + @Shadow + @Final + public MinecraftServer server; + @Unique + private boolean afk = false; + + @Unique + private long lastLastActionTime = 0; + + @Inject(method = "getTabListDisplayName", at = @At("HEAD"), cancellable = true) + public void getTabListDisplayName(CallbackInfoReturnable<Component> cir) { + ServerPlayerAccessor_afk accessor = (ServerPlayerAccessor_afk) player; + + if (accessor.sakurawald$isAfk()) { + cir.setReturnValue(Component.literal("afk " + player.getGameProfile().getName())); + net.kyori.adventure.text.@NotNull Component component = ofComponent(ConfigManager.configWrapper.instance().modules.afk.format) + .replaceText(TextReplacementConfig.builder().match("%player_display_name%").replacement(player.getDisplayName()).build()); + cir.setReturnValue(toVomponent(component)); + } else { + cir.setReturnValue(null); + } + } + + + @Inject(method = "resetLastActionTime", at = @At("HEAD")) + public void resetLastActionTime(CallbackInfo ci) { + if (sakurawald$isAfk()) { + sakurawald$setAfk(false); + MessageUtil.sendBroadcast("afk.off.broadcast", player.getGameProfile().getName()); + } + } + + @Override + public void sakurawald$setAfk(boolean flag) { + this.afk = flag; + this.server.getPlayerList().broadcastAll(new ClientboundPlayerInfoUpdatePacket(ClientboundPlayerInfoUpdatePacket.Action.UPDATE_DISPLAY_NAME, (ServerPlayer) (Object) this)); + } + + @Override + public boolean sakurawald$isAfk() { + return this.afk; + } + + @Override + public void sakurawald$setLastLastActionTime(long lastActionTime) { + this.lastLastActionTime = lastActionTime; + } + + @Override + public long sakurawald$getLastLastActionTime() { + return this.lastLastActionTime; + } + +} diff --git a/src/main/java/io/github/sakurawald/mixin/chat/PlayerListMixin.java b/src/main/java/io/github/sakurawald/mixin/chat/PlayerListMixin.java index e10c91ba0..0c799aa4c 100755 --- a/src/main/java/io/github/sakurawald/mixin/chat/PlayerListMixin.java +++ b/src/main/java/io/github/sakurawald/mixin/chat/PlayerListMixin.java @@ -1,7 +1,7 @@ package io.github.sakurawald.mixin.chat; import io.github.sakurawald.module.ModuleManager; -import io.github.sakurawald.module.chat.ChatStyleModule; +import io.github.sakurawald.module.chat.ChatModule; import io.github.sakurawald.util.CarpetUtil; import net.minecraft.network.Connection; import net.minecraft.server.level.ServerPlayer; @@ -16,7 +16,7 @@ public abstract class PlayerListMixin { @Unique - private static final ChatStyleModule module = ModuleManager.getOrNewInstance(ChatStyleModule.class); + private static final ChatModule module = ModuleManager.getOrNewInstance(ChatModule.class); @Inject(at = @At(value = "TAIL"), method = "placeNewPlayer") private void $placeNewPlayer(Connection connection, ServerPlayer player, CallbackInfo info) { diff --git a/src/main/java/io/github/sakurawald/mixin/chat/ServerGamePacketListenerImplMixin.java b/src/main/java/io/github/sakurawald/mixin/chat/ServerGamePacketListenerImplMixin.java index 8138d421c..f821c3923 100755 --- a/src/main/java/io/github/sakurawald/mixin/chat/ServerGamePacketListenerImplMixin.java +++ b/src/main/java/io/github/sakurawald/mixin/chat/ServerGamePacketListenerImplMixin.java @@ -1,7 +1,7 @@ package io.github.sakurawald.mixin.chat; import io.github.sakurawald.module.ModuleManager; -import io.github.sakurawald.module.chat.ChatStyleModule; +import io.github.sakurawald.module.chat.ChatModule; import net.minecraft.network.chat.PlayerChatMessage; import net.minecraft.server.level.ServerPlayer; import net.minecraft.server.network.ServerGamePacketListenerImpl; @@ -15,7 +15,7 @@ @Mixin(value = ServerGamePacketListenerImpl.class, priority = 1001) public abstract class ServerGamePacketListenerImplMixin { @Unique - private static final ChatStyleModule module = ModuleManager.getOrNewInstance(ChatStyleModule.class); + private static final ChatModule module = ModuleManager.getOrNewInstance(ChatModule.class); @Shadow public ServerPlayer player; diff --git a/src/main/java/io/github/sakurawald/mixin/teleport_warmup/ServerPlayerMixin.java b/src/main/java/io/github/sakurawald/mixin/teleport_warmup/ServerPlayerMixin.java index 9c12b2fb4..692bc7857 100755 --- a/src/main/java/io/github/sakurawald/mixin/teleport_warmup/ServerPlayerMixin.java +++ b/src/main/java/io/github/sakurawald/mixin/teleport_warmup/ServerPlayerMixin.java @@ -42,8 +42,7 @@ public abstract class ServerPlayerMixin implements ServerPlayerAccessor { if (!module.tickets.containsKey(playerName)) { module.tickets.put(playerName, new TeleportTicket(player - , new Position(player.level(), player.position().x, player.position().y, player.position().z, player.getYRot(), player.getXRot()) - , new Position(targetWorld, x, y, z, yaw, pitch), false)); + , Position.of(player), new Position(targetWorld, x, y, z, yaw, pitch), false)); ci.cancel(); return; } else { diff --git a/src/main/java/io/github/sakurawald/module/afk/AfkModule.java b/src/main/java/io/github/sakurawald/module/afk/AfkModule.java new file mode 100644 index 000000000..3bd0c1df6 --- /dev/null +++ b/src/main/java/io/github/sakurawald/module/afk/AfkModule.java @@ -0,0 +1,83 @@ +package io.github.sakurawald.module.afk; + +import com.mojang.brigadier.Command; +import com.mojang.brigadier.CommandDispatcher; +import com.mojang.brigadier.context.CommandContext; +import io.github.sakurawald.ServerMain; +import io.github.sakurawald.config.ConfigManager; +import io.github.sakurawald.module.AbstractModule; +import io.github.sakurawald.util.MessageUtil; +import io.github.sakurawald.util.ScheduleUtil; +import lombok.extern.slf4j.Slf4j; +import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback; +import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents; +import net.minecraft.commands.CommandBuildContext; +import net.minecraft.commands.CommandSourceStack; +import net.minecraft.commands.Commands; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ServerPlayer; +import org.quartz.Job; +import org.quartz.JobDataMap; +import org.quartz.JobExecutionContext; +import org.quartz.JobExecutionException; + +@Slf4j +public class AfkModule extends AbstractModule { + + @Override + public void onInitialize() { + CommandRegistrationCallback.EVENT.register(this::registerCommand); + ServerLifecycleEvents.SERVER_STARTED.register(this::registerScheduleTask); + } + + public void registerCommand(CommandDispatcher<CommandSourceStack> dispatcher, CommandBuildContext registryAccess, Commands.CommandSelection environment) { + dispatcher.register(Commands.literal("afk").executes(this::$afk)); + } + + @SuppressWarnings("SameReturnValue") + private int $afk(CommandContext<CommandSourceStack> ctx) { + ServerPlayer player = ctx.getSource().getPlayer(); + if (player == null) return Command.SINGLE_SUCCESS; + + boolean flag = !((ServerPlayerAccessor_afk) player).sakurawald$isAfk(); + ((ServerPlayerAccessor_afk) player).sakurawald$setAfk(flag); + + MessageUtil.sendMessage(player, flag ? "afk.on" : "afk.off"); + return Command.SINGLE_SUCCESS; + } + + public void registerScheduleTask(MinecraftServer server) { + ScheduleUtil.addJob(AfkCheckerJob.class, ConfigManager.configWrapper.instance().modules.afk.afk_checker.cron, new JobDataMap()); + } + + public static class AfkCheckerJob implements Job { + + @Override + public void execute(JobExecutionContext context) throws JobExecutionException { + for (ServerPlayer player : ServerMain.SERVER.getPlayerList().getPlayers()) { + ServerPlayerAccessor_afk afk_player = (ServerPlayerAccessor_afk) player; + + // get last action time + long lastActionTime = player.getLastActionTime(); + long lastLastActionTime = afk_player.sakurawald$getLastLastActionTime(); + afk_player.sakurawald$setLastLastActionTime(lastActionTime); + + // diff last action time + /* note: + when a player joins the server, + we'll set lastLastActionTime's initial value to Player#getLastActionTime(), + but there are a little difference even if you call Player#getLastActionTime() again + */ + if (lastActionTime - lastLastActionTime <= 3000) { + if (afk_player.sakurawald$isAfk()) continue; + + afk_player.sakurawald$setAfk(true); + MessageUtil.sendBroadcast("afk.on.broadcast", player.getGameProfile().getName()); + if (ConfigManager.configWrapper.instance().modules.afk.afk_checker.kick_player) { + player.connection.disconnect(MessageUtil.ofVomponent(player, "afk.kick")); + } + } + } + } + } +} diff --git a/src/main/java/io/github/sakurawald/module/afk/ServerPlayerAccessor_afk.java b/src/main/java/io/github/sakurawald/module/afk/ServerPlayerAccessor_afk.java new file mode 100644 index 000000000..afac4553c --- /dev/null +++ b/src/main/java/io/github/sakurawald/module/afk/ServerPlayerAccessor_afk.java @@ -0,0 +1,12 @@ +package io.github.sakurawald.module.afk; + +public interface ServerPlayerAccessor_afk { + + void sakurawald$setAfk(boolean flag); + + boolean sakurawald$isAfk(); + + void sakurawald$setLastLastActionTime(long lastActionTime); + + long sakurawald$getLastLastActionTime(); +} diff --git a/src/main/java/io/github/sakurawald/module/back/BackModule.java b/src/main/java/io/github/sakurawald/module/back/BackModule.java index f2bd1d321..8ae69a794 100755 --- a/src/main/java/io/github/sakurawald/module/back/BackModule.java +++ b/src/main/java/io/github/sakurawald/module/back/BackModule.java @@ -55,7 +55,7 @@ public void updatePlayer(ServerPlayer player) { || (player.level() == lastPos.getLevel() && player.position().distanceToSqr(lastPos.getX(), lastPos.getY(), lastPos.getZ()) > ignoreDistance * ignoreDistance) ) { player2lastPos.put(player.getGameProfile().getName(), - new Position(player.level(), player.position().x, player.position().y, player.position().z, player.getYRot(), player.getXRot())); + Position.of(player)); } } diff --git a/src/main/java/io/github/sakurawald/module/chat/ChatStyleModule.java b/src/main/java/io/github/sakurawald/module/chat/ChatModule.java similarity index 99% rename from src/main/java/io/github/sakurawald/module/chat/ChatStyleModule.java rename to src/main/java/io/github/sakurawald/module/chat/ChatModule.java index f38dbd11d..fd09ed9de 100755 --- a/src/main/java/io/github/sakurawald/module/chat/ChatStyleModule.java +++ b/src/main/java/io/github/sakurawald/module/chat/ChatModule.java @@ -45,7 +45,7 @@ @SuppressWarnings("UnstableApiUsage") @Slf4j -public class ChatStyleModule extends AbstractModule { +public class ChatModule extends AbstractModule { private final MiniMessage miniMessage = MiniMessage.builder().build(); private final MainStatsModule mainStatsModule = ModuleManager.getOrNewInstance(MainStatsModule.class); diff --git a/src/main/java/io/github/sakurawald/module/fly/FlyModule.java b/src/main/java/io/github/sakurawald/module/fly/FlyModule.java index a48d6d9c2..481a2038d 100644 --- a/src/main/java/io/github/sakurawald/module/fly/FlyModule.java +++ b/src/main/java/io/github/sakurawald/module/fly/FlyModule.java @@ -29,16 +29,15 @@ private int fly(CommandContext<CommandSourceStack> ctx) { ServerPlayer player = ctx.getSource().getPlayer(); if (player == null) return Command.SINGLE_SUCCESS; - boolean flag = player.getAbilities().mayfly; - player.getAbilities().mayfly = !flag; - if (flag) { + boolean flag = !player.getAbilities().mayfly; + player.getAbilities().mayfly = flag; + player.onUpdateAbilities(); + + if (!flag) { player.getAbilities().flying = false; - MessageUtil.sendMessage(player, "fly.off"); - } else { - MessageUtil.sendMessage(player, "fly.on"); } - player.onUpdateAbilities(); + MessageUtil.sendMessage(player, flag ? "fly.on" : "fly.off"); return Command.SINGLE_SUCCESS; } diff --git a/src/main/java/io/github/sakurawald/module/god/GodModule.java b/src/main/java/io/github/sakurawald/module/god/GodModule.java index 6d44692e2..885c5e4cb 100644 --- a/src/main/java/io/github/sakurawald/module/god/GodModule.java +++ b/src/main/java/io/github/sakurawald/module/god/GodModule.java @@ -29,16 +29,11 @@ private int god(CommandContext<CommandSourceStack> ctx) { ServerPlayer player = ctx.getSource().getPlayer(); if (player == null) return Command.SINGLE_SUCCESS; - boolean flag = player.getAbilities().invulnerable; - player.getAbilities().invulnerable = !flag; - - if (flag) { - MessageUtil.sendMessage(player, "god.off"); - } else { - MessageUtil.sendMessage(player, "god.on"); - } - + boolean flag = !player.getAbilities().invulnerable; + player.getAbilities().invulnerable = flag; player.onUpdateAbilities(); + + MessageUtil.sendMessage(player, flag ? "god.on" : "god.off"); return Command.SINGLE_SUCCESS; } diff --git a/src/main/java/io/github/sakurawald/module/resource_world/ResourceWorldManager.java b/src/main/java/io/github/sakurawald/module/resource_world/ResourceWorldManager.java index 96c9d6e9d..2cd627250 100755 --- a/src/main/java/io/github/sakurawald/module/resource_world/ResourceWorldManager.java +++ b/src/main/java/io/github/sakurawald/module/resource_world/ResourceWorldManager.java @@ -72,8 +72,7 @@ private static void kickPlayers(ServerLevel world) { if (teleportWarmupModule != null) { teleportWarmupModule.tickets.put(player.getGameProfile().getName(), new TeleportTicket(player - , new Position(world, player.getX(), player.getY(), player.getZ(), player.getYRot(), player.getXRot()) - , new Position(overworld, spawnPos.getX() + 0.5, spawnPos.getY() + 0.5, spawnPos.getZ() + 0.5, 0, 0) + , Position.of(player), new Position(overworld, spawnPos.getX() + 0.5, spawnPos.getY() + 0.5, spawnPos.getZ() + 0.5, 0, 0) , true)); } player.teleportTo(overworld, spawnPos.getX() + 0.5, spawnPos.getY(), spawnPos.getZ() + 0.5, overworld.getSharedSpawnAngle(), 0.0F); diff --git a/src/main/java/io/github/sakurawald/module/teleport_warmup/Position.java b/src/main/java/io/github/sakurawald/module/teleport_warmup/Position.java index 381cb780e..77ab60405 100755 --- a/src/main/java/io/github/sakurawald/module/teleport_warmup/Position.java +++ b/src/main/java/io/github/sakurawald/module/teleport_warmup/Position.java @@ -2,6 +2,7 @@ import lombok.AllArgsConstructor; import lombok.Data; +import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.level.Level; @Data @@ -14,4 +15,16 @@ public class Position { private float yaw; private float pitch; + + public static Position of(ServerPlayer player) { + return new Position(player.level(), player.getX(), player.getY(), player.getZ(), player.getYRot(), player.getXRot()); + } + + public double distanceToSqr(Position position) { + if (this.level != position.level) return Double.MAX_VALUE; + double x = this.x - position.x; + double y = this.y - position.y; + double z = this.z - position.z; + return x * x + y * y + z * z; + } } diff --git a/src/main/java/io/github/sakurawald/util/MessageUtil.java b/src/main/java/io/github/sakurawald/util/MessageUtil.java index c7132af07..c17982995 100755 --- a/src/main/java/io/github/sakurawald/util/MessageUtil.java +++ b/src/main/java/io/github/sakurawald/util/MessageUtil.java @@ -125,6 +125,7 @@ public static Component ofComponent(String str) { return miniMessage.deserialize(str); } + // todo: auto add keys in language public static net.minecraft.network.chat.Component ofVomponent(String str) { return toVomponent(ofComponent(str)); } diff --git a/src/main/resources/assets/sakurawald/lang/en_us.json b/src/main/resources/assets/sakurawald/lang/en_us.json index 2cd42bc62..cba56e60b 100755 --- a/src/main/resources/assets/sakurawald/lang/en_us.json +++ b/src/main/resources/assets/sakurawald/lang/en_us.json @@ -140,5 +140,10 @@ "fly.on": "<gold>Fly mode: on", "fly.off": "<gold>Fly mode: off", "god.on": "<gold>God mode: on", - "god.off": "<gold>God mode: off" + "god.off": "<gold>God mode: off", + "afk.on": "<gold>Afk mode: on", + "afk.off": "<gold>Afk mode: off", + "afk.on.broadcast": "<gold>Player %s is now afk", + "afk.off.broadcast": "<gold>Player %s is no longer afk", + "afk.kick": "<red>You have been kicked for being afk." } \ No newline at end of file diff --git a/src/main/resources/assets/sakurawald/lang/zh_cn.json b/src/main/resources/assets/sakurawald/lang/zh_cn.json index 20849f365..d317e61cd 100755 --- a/src/main/resources/assets/sakurawald/lang/zh_cn.json +++ b/src/main/resources/assets/sakurawald/lang/zh_cn.json @@ -140,5 +140,10 @@ "fly.on": "<gold>飞行模式: 启用", "fly.off": "<gold>飞行模式: 禁用", "god.on": "<gold>上帝模式: 启用", - "god.off": "<gold>上帝模式: 禁用" + "god.off": "<gold>上帝模式: 禁用", + "afk.on": "<gold>闲置模式: 启用", + "afk.off": "<gold>闲置模式: 禁用", + "afk.on.broadcast": "<gold>玩家 %s 暂时离开了", + "afk.off.broadcast": "<gold>玩家 %s 回来了", + "afk.kick": "<red>您已因长时间离开而被踢出" } \ No newline at end of file diff --git a/src/main/resources/sakurawald.mixins.json b/src/main/resources/sakurawald.mixins.json index 533d8ca4b..32bb5c165 100755 --- a/src/main/resources/sakurawald.mixins.json +++ b/src/main/resources/sakurawald.mixins.json @@ -4,6 +4,8 @@ "compatibilityLevel": "JAVA_17", "plugin": "io.github.sakurawald.mixin.MixinConfigPlugin", "mixins": [ + "afk.PlayerListMixin", + "afk.ServerPlayerMixin", "back.ServerPlayerMixin", "better_fake_player.PlayerCommandMixin", "better_fake_player.PlayerListMixin",