diff --git a/src/main/java/io/ib67/sfcraft/Helper.java b/src/main/java/io/ib67/sfcraft/Helper.java index 6311710..1f0022c 100644 --- a/src/main/java/io/ib67/sfcraft/Helper.java +++ b/src/main/java/io/ib67/sfcraft/Helper.java @@ -28,4 +28,8 @@ public class Helper { } return null; } + + public static int fromRgb(int r, int g, int b) { + return ((r & 0x0ff) << 16) | ((g & 0x0ff) << 8) | (b & 0x0ff); + } } diff --git a/src/main/java/io/ib67/sfcraft/SFCraft.java b/src/main/java/io/ib67/sfcraft/SFCraft.java index 5eef8e9..774b58b 100644 --- a/src/main/java/io/ib67/sfcraft/SFCraft.java +++ b/src/main/java/io/ib67/sfcraft/SFCraft.java @@ -7,6 +7,7 @@ import com.mojang.brigadier.builder.LiteralArgumentBuilder; import com.mojang.brigadier.builder.RequiredArgumentBuilder; import io.ib67.sfcraft.config.SFConfig; import io.ib67.sfcraft.geoip.GeoIPService; +import io.ib67.sfcraft.message.SFMessageDecorator; import io.ib67.sfcraft.registry.event.RandomEventRegistry; import io.ib67.sfcraft.event.SFRandomEventRegistry; import lombok.Getter; @@ -16,6 +17,7 @@ import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback; import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents; import net.fabricmc.fabric.api.networking.v1.ServerPlayConnectionEvents; import net.minecraft.command.CommandRegistryAccess; +import net.minecraft.network.message.MessageDecorator; import net.minecraft.server.MinecraftServer; import net.minecraft.server.command.CommandManager; import net.minecraft.server.command.ServerCommandSource; @@ -42,6 +44,8 @@ public class SFCraft implements ModInitializer { private String updateLog; @Getter private RandomEventRegistry randomEventRegistry; + @Getter + private MessageDecorator messageDecorator; @Override @SneakyThrows @@ -56,15 +60,22 @@ public class SFCraft implements ModInitializer { motd = loadMotd(); updateLog = loadUpdateLog(); geoIPService = new GeoIPService(); - this.setupRandomEvents(); + + randomEventRegistry = setupRandomEvents(); + messageDecorator = setupMessageDecorator(); ServerPlayConnectionEvents.JOIN.register(listener::onPlayerJoin); CommandRegistrationCallback.EVENT.register(this::registerCommands); ServerLifecycleEvents.SERVER_STARTED.register(this::onServerStarted); + } - private void setupRandomEvents() { - randomEventRegistry = new SFRandomEventRegistry(); + private MessageDecorator setupMessageDecorator() { + return new SFMessageDecorator(); + } + + private SFRandomEventRegistry setupRandomEvents() { + return new SFRandomEventRegistry(); } private void onServerStarted(MinecraftServer minecraftServer) { @@ -135,5 +146,4 @@ public class SFCraft implements ModInitializer { .executes(handler::listOffline) ); } - } diff --git a/src/main/java/io/ib67/sfcraft/event/SFRandomEventRegistry.java b/src/main/java/io/ib67/sfcraft/event/SFRandomEventRegistry.java index 48b94b3..72d695a 100644 --- a/src/main/java/io/ib67/sfcraft/event/SFRandomEventRegistry.java +++ b/src/main/java/io/ib67/sfcraft/event/SFRandomEventRegistry.java @@ -10,7 +10,7 @@ public class SFRandomEventRegistry extends SimpleRandomEventRegistry { registerEvent(LongNightEvent::new, World.OVERWORLD , world -> !LongNightEvent.isRunning() && world.getTimeOfDay() % 24000 == 18000 - && world.getRandom().nextBetween(0,100) < 15); // At midnight + && world.getRandom().nextBetween(0,100) < 5); // At midnight registerEvent(DawnAfterLongNightEvent::new, World.OVERWORLD , world -> world.getTimeOfDay() % 22200 == 0); // At dawn } diff --git a/src/main/java/io/ib67/sfcraft/message/SFMessageDecorator.java b/src/main/java/io/ib67/sfcraft/message/SFMessageDecorator.java new file mode 100644 index 0000000..abb44ea --- /dev/null +++ b/src/main/java/io/ib67/sfcraft/message/SFMessageDecorator.java @@ -0,0 +1,9 @@ +package io.ib67.sfcraft.message; + +import io.ib67.sfcraft.message.feature.SendLocationFeature; + +public class SFMessageDecorator extends SimpleMessageDecorator { + public SFMessageDecorator() { + registerDecorator(new SendLocationFeature()); + } +} diff --git a/src/main/java/io/ib67/sfcraft/message/SimpleMessageDecorator.java b/src/main/java/io/ib67/sfcraft/message/SimpleMessageDecorator.java new file mode 100644 index 0000000..bf9c398 --- /dev/null +++ b/src/main/java/io/ib67/sfcraft/message/SimpleMessageDecorator.java @@ -0,0 +1,29 @@ +package io.ib67.sfcraft.message; + +import net.minecraft.network.message.MessageDecorator; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.text.Text; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.List; + +public class SimpleMessageDecorator implements MessageDecorator { + protected final List decorators = new ArrayList<>(); + + protected SimpleMessageDecorator() { + + } + + protected void registerDecorator(MessageDecorator decorator) { + decorators.add(decorator); + } + + @Override + public Text decorate(@Nullable ServerPlayerEntity sender, Text message) { + for (MessageDecorator decorator : decorators) { + message = decorator.decorate(sender, message); + } + return message; + } +} diff --git a/src/main/java/io/ib67/sfcraft/message/feature/SendLocationFeature.java b/src/main/java/io/ib67/sfcraft/message/feature/SendLocationFeature.java new file mode 100644 index 0000000..3b138e6 --- /dev/null +++ b/src/main/java/io/ib67/sfcraft/message/feature/SendLocationFeature.java @@ -0,0 +1,59 @@ +package io.ib67.sfcraft.message.feature; + +import io.ib67.sfcraft.Helper; +import net.minecraft.network.message.MessageDecorator; +import net.minecraft.registry.RegistryKey; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.text.ClickEvent; +import net.minecraft.text.Text; +import net.minecraft.world.World; +import org.jetbrains.annotations.Nullable; + +public class SendLocationFeature implements MessageDecorator { + @Override + public Text decorate(@Nullable ServerPlayerEntity sender, Text message) { + var text = message.getLiteralString().trim(); + if (text == null) { + return message; + } + if (text.trim().equals(".xyz")) { + return generateLocText(sender); + } + var result = Text.literal(""); + var head = 0; + var i = text.indexOf(".xyz"); + while (i != -1) { + result.append(text.substring(0, i).trim()); + result.append(generateLocText(sender)); + head = i + 4; + i = text.indexOf(".xyz", head + 1); + } + result.append(text.substring(head).trim()); + return result; + } + + private static Text generateLocText(ServerPlayerEntity sender) { + if (sender == null) return Text.of(" (invalid position) "); + var x = sender.getBlockPos().getX(); + var y = sender.getBlockPos().getY(); + var z = sender.getBlockPos().getZ(); + var key = sender.getServerWorld().getRegistryKey(); + var world = translate(key); + return Text + .literal(" " + x + ", " + y + ", " + z + world + " ") + .withColor(Helper.fromRgb(63, 254, 254)) + .styled(style -> style.withClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/gps " + key + " " + x + " " + y + " " + z))); + } + + private static String translate(RegistryKey registryKey) { + if (registryKey == World.END) { + return " (末地)"; + } else if (registryKey == World.NETHER) { + return " (地狱)"; + } else if (registryKey == World.OVERWORLD) { + return ""; + } else { + return " (未知)"; + } + } +} diff --git a/src/main/java/io/ib67/sfcraft/mixin/server/ServerPlayNetworkHandlerMixin.java b/src/main/java/io/ib67/sfcraft/mixin/server/ServerPlayNetworkHandlerMixin.java new file mode 100644 index 0000000..c3105ca --- /dev/null +++ b/src/main/java/io/ib67/sfcraft/mixin/server/ServerPlayNetworkHandlerMixin.java @@ -0,0 +1,27 @@ +package io.ib67.sfcraft.mixin.server; + +import io.ib67.sfcraft.SFCraft; +import net.minecraft.network.message.MessageChainTaskQueue; +import net.minecraft.network.message.MessageDecorator; +import net.minecraft.network.message.SignedMessage; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.network.ServerPlayNetworkHandler; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; +import org.spongepowered.asm.mixin.injection.*; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import java.util.concurrent.CompletableFuture; +import java.util.function.Consumer; + +@Mixin(ServerPlayNetworkHandler.class) +public abstract class ServerPlayNetworkHandlerMixin { + /** + * @author icybear + * @reason small method, provide custom one + */ + @Redirect(method = "method_44900", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/MinecraftServer;getMessageDecorator()Lnet/minecraft/network/message/MessageDecorator;")) + public MessageDecorator getMessageDecorator(MinecraftServer instance) { + return SFCraft.getInstance().getMessageDecorator(); + } +} diff --git a/src/main/resources/sfcraft.mixins.json b/src/main/resources/sfcraft.mixins.json index 4373c16..f2353fd 100644 --- a/src/main/resources/sfcraft.mixins.json +++ b/src/main/resources/sfcraft.mixins.json @@ -8,6 +8,7 @@ "client": [ ], "server": [ + "server.ServerPlayNetworkHandlerMixin", "server.bridge.ServerWorldBridge", "server.SleepManagerMixin", "server.ServerWorldMixin",