add: Persistent gamerule per world.

Signed-off-by: 秋雨落 <i@rain.cx>
This commit is contained in:
秋雨落 committed 2024-09-18 14:45:16 +08:00
1 parent a7e564d709
commit 40d3e8cf54
3 files changed
+63 -17

No files matched your search

@@ -1,7 +1,5 @@
package io.ib67.sfcraft.mixin.server.subserver; 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.SFCraft;
import io.ib67.sfcraft.module.RoomModule; import io.ib67.sfcraft.module.RoomModule;
import net.minecraft.registry.DynamicRegistryManager; import net.minecraft.registry.DynamicRegistryManager;
@@ -12,13 +10,11 @@ import net.minecraft.world.GameRules;
import net.minecraft.world.MutableWorldProperties; import net.minecraft.world.MutableWorldProperties;
import net.minecraft.world.World; import net.minecraft.world.World;
import net.minecraft.world.dimension.DimensionType; import net.minecraft.world.dimension.DimensionType;
import net.minecraft.world.level.LevelProperties;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Overwrite; import org.spongepowered.asm.mixin.Overwrite;
import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.Redirect;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import java.util.function.Supplier; import java.util.function.Supplier;
@@ -40,7 +36,7 @@ public abstract class WorldMixin {
int maxChainedNeighborUpdates, CallbackInfo ci) { int maxChainedNeighborUpdates, CallbackInfo ci) {
var id = registryRef.getValue(); var id = registryRef.getValue();
if (id.getNamespace().equals("sfcraft")) { // room if (id.getNamespace().equals("sfcraft")) { // room
customGameRule = SFCraft.getInjector().getInstance(RoomModule.class).readGameRuleForRoom(id); customGameRule = SFCraft.getInjector().getInstance(RoomModule.class).readGameRuleForRoom(registryRef);
} else { } else {
customGameRule = properties.getGameRules(); customGameRule = properties.getGameRules();
} }
@@ -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;
@@ -73,18 +74,13 @@ 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);
} }
} }
@Override
public void onDisable() {
//todo persistence of gameRulesPerRoom
}
private void registerCommand(CommandDispatcher<ServerCommandSource> serverCommandSourceCommandDispatcher, CommandRegistryAccess commandRegistryAccess, CommandManager.RegistrationEnvironment registrationEnvironment) { private void registerCommand(CommandDispatcher<ServerCommandSource> serverCommandSourceCommandDispatcher, CommandRegistryAccess commandRegistryAccess, CommandManager.RegistrationEnvironment registrationEnvironment) {
serverCommandSourceCommandDispatcher.register( serverCommandSourceCommandDispatcher.register(
LiteralArgumentBuilder.<ServerCommandSource>literal("reco") LiteralArgumentBuilder.<ServerCommandSource>literal("reco")
@@ -103,7 +99,7 @@ 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
@@ -160,9 +156,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) {
@@ -184,7 +178,7 @@ public class RoomModule extends ServerModule {
return uuidMapper.get(virtual); return uuidMapper.get(virtual);
} }
public GameRules readGameRuleForRoom(Identifier identifier){ public GameRules readGameRuleForRoom(RegistryKey<World> key){
return gameRulesPerRoom.computeIfAbsent(identifier, k -> new GameRules()); return RoomWorldDataLoader.get(serverSupplier.get().getWorld(key)).getGameRules();
} }
} }
@@ -0,0 +1,56 @@
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.util.Identifier;
import net.minecraft.world.GameRules;
import net.minecraft.world.PersistentState;
import java.util.Objects;
@Getter
public class RoomWorldDataLoader extends PersistentState {
private static final Identifier ID = Identifier.of("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, ID.toString());
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();
}
}