(update) Merge pull request #26 from saltedfishclub/per-world-gamerules

per world gamerules
This commit is contained in:
iceBear67 authored and GitHub committed 2024-09-18 15:06:17 +08:00
commit 6a50489eff
6 files changed
+131 -8

No files matched your search

@@ -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<ServerCommandSource> 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.
}
}
@@ -0,0 +1,30 @@
package io.ib67.sfcraft.mixin.server.subserver;
import io.ib67.sfcraft.SFCraft;
import io.ib67.sfcraft.module.RoomModule;
import net.minecraft.registry.RegistryKey;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.world.GameRules;
import net.minecraft.world.World;
import org.spongepowered.asm.mixin.*;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(World.class)
public abstract class WorldMixin {
@Shadow public abstract boolean isClient();
@Shadow @Final private RegistryKey<World> registryKey;
@Unique private GameRules sfcraft$customGameRule;
@Inject(method = "getGameRules", at = @At("HEAD"), cancellable = true)
private void beforeGetGameRules(CallbackInfoReturnable<GameRules> cir) {
if (!isClient() && registryKey.getValue().getNamespace().equals("sfcraft")) {
if (sfcraft$customGameRule == null) {
sfcraft$customGameRule = SFCraft.getInjector().getInstance(RoomModule.class).readGameRuleForRoom((ServerWorld) (Object) this);
}
cir.setReturnValue(sfcraft$customGameRule);
}
}
}
@@ -10,6 +10,7 @@ import io.ib67.sfcraft.config.SFConfig;
import io.ib67.sfcraft.inject.MinecraftServerSupplier; import io.ib67.sfcraft.inject.MinecraftServerSupplier;
import io.ib67.sfcraft.room.RequestedRoom; import io.ib67.sfcraft.room.RequestedRoom;
import io.ib67.sfcraft.registry.RoomRegistry; import io.ib67.sfcraft.registry.RoomRegistry;
import io.ib67.sfcraft.room.data.RoomWorldDataLoader;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled; import io.netty.buffer.Unpooled;
import lombok.SneakyThrows; import lombok.SneakyThrows;
@@ -24,12 +25,14 @@ import net.minecraft.registry.RegistryKey;
import net.minecraft.server.command.CommandManager; import net.minecraft.server.command.CommandManager;
import net.minecraft.server.command.ServerCommandSource; import net.minecraft.server.command.ServerCommandSource;
import net.minecraft.server.world.ChunkTicketType; import net.minecraft.server.world.ChunkTicketType;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.text.Text; import net.minecraft.text.Text;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
import net.minecraft.util.Pair; import net.minecraft.util.Pair;
import net.minecraft.util.Unit; import net.minecraft.util.Unit;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.ChunkPos; import net.minecraft.util.math.ChunkPos;
import net.minecraft.world.GameRules;
import net.minecraft.world.World; import net.minecraft.world.World;
import org.apache.commons.lang3.RandomStringUtils; import org.apache.commons.lang3.RandomStringUtils;
@@ -59,6 +62,7 @@ public class RoomModule extends ServerModule {
private Key key; private Key key;
private final List<Pair<RegistryKey<World>, BlockPos>> pregenQueue = new ArrayList<>(); private final List<Pair<RegistryKey<World>, BlockPos>> pregenQueue = new ArrayList<>();
private final Map<UUID, GameProfile> uuidMapper = new ConcurrentHashMap<>(); private final Map<UUID, GameProfile> uuidMapper = new ConcurrentHashMap<>();
private final Map<Identifier, GameRules> gameRulesPerRoom = new HashMap<>();
@Override @Override
public void onInitialize() { public void onInitialize() {
@@ -71,7 +75,7 @@ public class RoomModule extends ServerModule {
for (Pair<RegistryKey<World>, BlockPos> registryKeyBlockPosPair : pregenQueue) { for (Pair<RegistryKey<World>, BlockPos> registryKeyBlockPosPair : pregenQueue) {
var world = serverSupplier.get().getWorld(registryKeyBlockPosPair.getLeft()); var world = serverSupplier.get().getWorld(registryKeyBlockPosPair.getLeft());
if (world == null) { if (world == null) {
log.warn("Cannot find world " + registryKeyBlockPosPair.getLeft()); log.warn("Cannot find world {}", registryKeyBlockPosPair.getLeft());
continue; continue;
} }
world.getChunkManager().addTicket(ChunkTicketType.START, new ChunkPos(registryKeyBlockPosPair.getRight()), 64, Unit.INSTANCE); world.getChunkManager().addTicket(ChunkTicketType.START, new ChunkPos(registryKeyBlockPosPair.getRight()), 64, Unit.INSTANCE);
@@ -96,18 +100,18 @@ public class RoomModule extends ServerModule {
networkHandler.send(new StoreCookieS2CPacket(ROOM_COOKIE, EMPTY), PacketCallbacks.always(() -> { networkHandler.send(new StoreCookieS2CPacket(ROOM_COOKIE, EMPTY), PacketCallbacks.always(() -> {
networkHandler.sendPacket(new ServerTransferS2CPacket(config.domain, serverSupplier.get().getServerPort())); networkHandler.sendPacket(new ServerTransferS2CPacket(config.domain, serverSupplier.get().getServerPort()));
})); }));
return 0; return 1;
} }
@SneakyThrows @SneakyThrows
public byte[] encrypt(byte[] b) { byte[] encrypt(byte[] b) {
var cipher = Cipher.getInstance("AES"); var cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, key); cipher.init(Cipher.ENCRYPT_MODE, key);
return cipher.doFinal(b); return cipher.doFinal(b);
} }
@SneakyThrows @SneakyThrows
public byte[] decrypt(byte[] b) { byte[] decrypt(byte[] b) {
var cipher = Cipher.getInstance("AES"); var cipher = Cipher.getInstance("AES");
cipher.init(Cipher.DECRYPT_MODE, key); cipher.init(Cipher.DECRYPT_MODE, key);
return cipher.doFinal(b); return cipher.doFinal(b);
@@ -153,9 +157,7 @@ public class RoomModule extends ServerModule {
private static SecretKey getKeyFromPassword(String password, String salt) { private static SecretKey getKeyFromPassword(String password, String salt) {
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256"); SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
KeySpec spec = new PBEKeySpec(password.toCharArray(), salt.getBytes(), 65536, 256); KeySpec spec = new PBEKeySpec(password.toCharArray(), salt.getBytes(), 65536, 256);
SecretKey secret = new SecretKeySpec(factory.generateSecret(spec) return new SecretKeySpec(factory.generateSecret(spec).getEncoded(), "AES");
.getEncoded(), "AES");
return secret;
} }
public void enqueuePregen(RegistryKey<World> world, BlockPos spawnPos) { public void enqueuePregen(RegistryKey<World> world, BlockPos spawnPos) {
@@ -176,4 +178,8 @@ public class RoomModule extends ServerModule {
public GameProfile devirtualize(UUID virtual) { public GameProfile devirtualize(UUID virtual) {
return uuidMapper.get(virtual); return uuidMapper.get(virtual);
} }
public GameRules readGameRuleForRoom(ServerWorld world){
return RoomWorldDataLoader.get(world).getGameRules();
}
} }
@@ -38,7 +38,8 @@ import java.util.Set;
public class CreativeRoomModule extends ServerModule { public class CreativeRoomModule extends ServerModule {
private static final Set<String> ALLOWED_VANILLA_COMMANDS = Set.of( private static final Set<String> ALLOWED_VANILLA_COMMANDS = Set.of(
"minecraft.command.weather", "minecraft.command.weather",
"minecraft.command.time"); "minecraft.command.time",
"minecraft.command.gamerule");
@Inject @Inject
private RoomRegistry roomRegistry; private RoomRegistry roomRegistry;
@Inject @Inject
@@ -0,0 +1,55 @@
package io.ib67.sfcraft.room.data;
import com.mojang.serialization.Dynamic;
import lombok.Getter;
import net.minecraft.datafixer.DataFixTypes;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.nbt.NbtOps;
import net.minecraft.registry.RegistryWrapper;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.world.GameRules;
import net.minecraft.world.PersistentState;
import java.util.Objects;
@Getter
public class RoomWorldDataLoader extends PersistentState {
private static final String NAME = "sfcraft_room_data";
private static final Type<RoomWorldDataLoader> TYPE = new Type<>(RoomWorldDataLoader::new, RoomWorldDataLoader::readNbt, DataFixTypes.LEVEL);
private static final String TAG_GAME_RULES = "gameRules";
private final GameRules gameRules;
public RoomWorldDataLoader() {
this(new GameRules());
}
public RoomWorldDataLoader(GameRules gameRules) {
this.gameRules = gameRules;
}
public static RoomWorldDataLoader get(ServerWorld world) {
Objects.requireNonNull(world);
var state = world.getPersistentStateManager().getOrCreate(TYPE, NAME);
state.markDirty();
return state;
}
@Override
public NbtCompound writeNbt(NbtCompound nbt, RegistryWrapper.WrapperLookup registry) {
nbt.put(TAG_GAME_RULES, gameRules.toNbt());
return nbt;
}
private static RoomWorldDataLoader readNbt(NbtCompound nbt, RegistryWrapper.WrapperLookup registry) {
if (nbt.contains(TAG_GAME_RULES)) {
var c = nbt.getCompound(TAG_GAME_RULES);
var dynamic = new Dynamic<>(NbtOps.INSTANCE, c);
var rule = new GameRules(dynamic);
return new RoomWorldDataLoader(rule);
}
return new RoomWorldDataLoader();
}
}
+2
View File
@@ -34,6 +34,8 @@
"server.subserver.PlayerSaveHandlerMixin", "server.subserver.PlayerSaveHandlerMixin",
"server.subserver.ServerPlayerEntityMixin", "server.subserver.ServerPlayerEntityMixin",
"server.subserver.PlayerListS2CPacket$EntryMixin", "server.subserver.PlayerListS2CPacket$EntryMixin",
"server.subserver.WorldMixin",
"server.subserver.GameRuleCommandMixin",
"server.optimize.LivingEntityMixin" "server.optimize.LivingEntityMixin"
], ],
"injectors": { "injectors": {