(update) Merge pull request #26 from saltedfishclub/per-world-gamerules
per world gamerules
This commit is contained in:
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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": {
|
||||||
|
|||||||
Reference in new issue
Block a user