From f3fa16f6fcb2df104df9b032f9cfc2017406007b Mon Sep 17 00:00:00 2001 From: iceBear67 Date: Wed, 18 Sep 2024 10:52:22 +0800 Subject: [PATCH] add: per-world gamerules support for room. --- .../subserver/GameRuleCommandMixin.java | 29 ++++++++++ .../mixin/server/subserver/WorldMixin.java | 57 +++++++++++++++++++ .../io/ib67/sfcraft/module/RoomModule.java | 15 ++++- src/main/resources/sfcraft.mixins.json | 2 + 4 files changed, 101 insertions(+), 2 deletions(-) create mode 100644 src/main/java/io/ib67/sfcraft/mixin/server/subserver/GameRuleCommandMixin.java create mode 100644 src/main/java/io/ib67/sfcraft/mixin/server/subserver/WorldMixin.java diff --git a/src/main/java/io/ib67/sfcraft/mixin/server/subserver/GameRuleCommandMixin.java b/src/main/java/io/ib67/sfcraft/mixin/server/subserver/GameRuleCommandMixin.java new file mode 100644 index 0000000..b41c5f9 --- /dev/null +++ b/src/main/java/io/ib67/sfcraft/mixin/server/subserver/GameRuleCommandMixin.java @@ -0,0 +1,29 @@ +package io.ib67.sfcraft.mixin.server.subserver; + +import com.mojang.brigadier.context.CommandContext; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.command.GameRuleCommand; +import net.minecraft.server.command.ServerCommandSource; +import net.minecraft.world.GameRules; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +@Mixin(GameRuleCommand.class) +public abstract class GameRuleCommandMixin { + @Redirect(at = @At(value = "INVOKE", target = "Lnet/minecraft/server/MinecraftServer;getGameRules()Lnet/minecraft/world/GameRules;"), method = "executeSet") + private static GameRules sf$redirectSetForPerWorld(MinecraftServer instance, CommandContext context) { + return getGameRule(instance, context.getSource()); + } + + @Redirect(at = @At(value = "INVOKE", target = "Lnet/minecraft/server/MinecraftServer;getGameRules()Lnet/minecraft/world/GameRules;"), method = "executeQuery") + private static GameRules sf$redirectSetForPerWorld(MinecraftServer instance, ServerCommandSource context) { + return getGameRule(instance, context); + } + + private static GameRules getGameRule(MinecraftServer instance, ServerCommandSource source) { + var world = source.getWorld(); + if (world == null) return instance.getGameRules(); + return world.getGameRules(); // this is same as Server#getGameRule since one GameRules is shared across multiple worlds in vanilla. + } +} diff --git a/src/main/java/io/ib67/sfcraft/mixin/server/subserver/WorldMixin.java b/src/main/java/io/ib67/sfcraft/mixin/server/subserver/WorldMixin.java new file mode 100644 index 0000000..cc333e6 --- /dev/null +++ b/src/main/java/io/ib67/sfcraft/mixin/server/subserver/WorldMixin.java @@ -0,0 +1,57 @@ +package io.ib67.sfcraft.mixin.server.subserver; + +import com.llamalad7.mixinextras.sugar.Local; +import com.llamalad7.mixinextras.sugar.ref.LocalRef; +import io.ib67.sfcraft.SFCraft; +import io.ib67.sfcraft.module.RoomModule; +import net.minecraft.registry.DynamicRegistryManager; +import net.minecraft.registry.RegistryKey; +import net.minecraft.registry.entry.RegistryEntry; +import net.minecraft.util.profiler.Profiler; +import net.minecraft.world.GameRules; +import net.minecraft.world.MutableWorldProperties; +import net.minecraft.world.World; +import net.minecraft.world.dimension.DimensionType; +import net.minecraft.world.level.LevelProperties; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; +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.Redirect; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import java.util.function.Supplier; + +@Mixin(World.class) +public abstract class WorldMixin { + @Unique + private GameRules customGameRule; + + @Inject(at = @At("TAIL"), method = "") + private void sf$initCustomGameRule(MutableWorldProperties properties, + RegistryKey registryRef, + DynamicRegistryManager registryManager, + RegistryEntry dimensionEntry, + Supplier profiler, + boolean isClient, + boolean debugWorld, + long biomeAccess, + int maxChainedNeighborUpdates, CallbackInfo ci) { + var id = registryRef.getValue(); + if (id.getNamespace().equals("sfcraft")) { // room + customGameRule = SFCraft.getInjector().getInstance(RoomModule.class).readGameRuleForRoom(id); + } else { + customGameRule = properties.getGameRules(); + } + } + + /** + * @reason for per-world rules + * @author icybear + */ + @Overwrite + public GameRules getGameRules() { + return customGameRule; + } +} diff --git a/src/main/java/io/ib67/sfcraft/module/RoomModule.java b/src/main/java/io/ib67/sfcraft/module/RoomModule.java index d350a00..73e8189 100644 --- a/src/main/java/io/ib67/sfcraft/module/RoomModule.java +++ b/src/main/java/io/ib67/sfcraft/module/RoomModule.java @@ -30,6 +30,7 @@ import net.minecraft.util.Pair; import net.minecraft.util.Unit; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.ChunkPos; +import net.minecraft.world.GameRules; import net.minecraft.world.World; import org.apache.commons.lang3.RandomStringUtils; @@ -59,6 +60,7 @@ public class RoomModule extends ServerModule { private Key key; private final List, BlockPos>> pregenQueue = new ArrayList<>(); private final Map uuidMapper = new ConcurrentHashMap<>(); + private final Map gameRulesPerRoom = new HashMap<>(); @Override public void onInitialize() { @@ -78,6 +80,11 @@ public class RoomModule extends ServerModule { } } + @Override + public void onDisable() { + //todo persistence of gameRulesPerRoom + } + private void registerCommand(CommandDispatcher serverCommandSourceCommandDispatcher, CommandRegistryAccess commandRegistryAccess, CommandManager.RegistrationEnvironment registrationEnvironment) { serverCommandSourceCommandDispatcher.register( LiteralArgumentBuilder.literal("reco") @@ -100,14 +107,14 @@ public class RoomModule extends ServerModule { } @SneakyThrows - public byte[] encrypt(byte[] b) { + byte[] encrypt(byte[] b) { var cipher = Cipher.getInstance("AES"); cipher.init(Cipher.ENCRYPT_MODE, key); return cipher.doFinal(b); } @SneakyThrows - public byte[] decrypt(byte[] b) { + byte[] decrypt(byte[] b) { var cipher = Cipher.getInstance("AES"); cipher.init(Cipher.DECRYPT_MODE, key); return cipher.doFinal(b); @@ -176,4 +183,8 @@ public class RoomModule extends ServerModule { public GameProfile devirtualize(UUID virtual) { return uuidMapper.get(virtual); } + + public GameRules readGameRuleForRoom(Identifier identifier){ + return gameRulesPerRoom.computeIfAbsent(identifier, k -> new GameRules()); + } } diff --git a/src/main/resources/sfcraft.mixins.json b/src/main/resources/sfcraft.mixins.json index 4258779..e5c2636 100644 --- a/src/main/resources/sfcraft.mixins.json +++ b/src/main/resources/sfcraft.mixins.json @@ -34,6 +34,8 @@ "server.subserver.PlayerSaveHandlerMixin", "server.subserver.ServerPlayerEntityMixin", "server.subserver.PlayerListS2CPacket$EntryMixin", + "server.subserver.WorldMixin", + "server.subserver.GameRuleCommandMixin", "server.optimize.LivingEntityMixin" ], "injectors": {