diff --git a/.gitignore b/.gitignore index 0d220c0..9341be4 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ run/ run-data/ .idea/ .gradle/ +.c* diff --git a/gradle.properties b/gradle.properties index 4d0cb72..9fa5b89 100644 --- a/gradle.properties +++ b/gradle.properties @@ -38,7 +38,7 @@ mod_name=TravelersSuitcase # The license of the mod. Review your options at https://choosealicense.com/. All Rights Reserved is the default. mod_license=MIT # The mod version. See https://semver.org/ -mod_version=1.2.7-SNAPSHOT +mod_version=1.2.7-SNAPSHOTv2 # The group ID for the mod. It is only important when publishing as an artifact to a Maven repository. # This should match the base package used for the mod sources. # See https://maven.apache.org/guides/mini/guide-naming-conventions.html diff --git a/src/main/java/io/lampnet/travelerssuitcase/Config.java b/src/main/java/io/lampnet/travelerssuitcase/Config.java index 245305a..3f83fb1 100644 --- a/src/main/java/io/lampnet/travelerssuitcase/Config.java +++ b/src/main/java/io/lampnet/travelerssuitcase/Config.java @@ -1,7 +1,8 @@ package io.lampnet.travelerssuitcase; import net.minecraft.resources.ResourceLocation; -import net.minecraft.world.item.Item; + +import net.minecraft.world.entity.EntityType; import net.minecraftforge.common.ForgeConfigSpec; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.common.Mod; @@ -10,20 +11,210 @@ import net.minecraftforge.registries.ForgeRegistries; import java.util.List; import java.util.Set; +import java.util.HashSet; import java.util.stream.Collectors; @Mod.EventBusSubscriber(modid = TravelersSuitcase.MODID, bus = Mod.EventBusSubscriber.Bus.MOD) public class Config { private static final ForgeConfigSpec.Builder BUILDER = new ForgeConfigSpec.Builder(); - static final ForgeConfigSpec SPEC = BUILDER.build(); + public static final ForgeConfigSpec.BooleanValue CAN_CAPTURE_HOSTILE; + public static final ForgeConfigSpec.ConfigValue> ENTITY_BLACKLIST; - private static boolean validateItemName(final Object obj) { - return obj instanceof final String itemName && ForgeRegistries.ITEMS.containsKey(ResourceLocation.parse(itemName)); + public static final ForgeConfigSpec.LongValue DEFAULT_TIME_OF_DAY; + + public static final ForgeConfigSpec.BooleanValue SHOULD_TICK_TIME; + public static final ForgeConfigSpec.BooleanValue TICK_WHEN_EMPTY; + + public static final ForgeConfigSpec.IntValue DEFAULT_SUNNY_TIME; + public static final ForgeConfigSpec.BooleanValue DEFAULT_RAINING; + public static final ForgeConfigSpec.IntValue DEFAULT_RAIN_TIME; + public static final ForgeConfigSpec.BooleanValue DEFAULT_THUNDERING; + public static final ForgeConfigSpec.IntValue DEFAULT_THUNDER_TIME; + + public static final ForgeConfigSpec.IntValue DIMENSION_HEIGHT; + public static final ForgeConfigSpec.IntValue DIMENSION_MIN_Y; + public static final ForgeConfigSpec.DoubleValue COORDINATE_SCALE; + public static final ForgeConfigSpec.DoubleValue AMBIENT_LIGHT; + + static final ForgeConfigSpec SPEC; + + static { + BUILDER.comment("Entity Configuration").push("entities"); + + CAN_CAPTURE_HOSTILE = BUILDER + .comment("Whether hostile entities can be captured in suitcases") + .define("canCaptureHostile", false); + + ENTITY_BLACKLIST = BUILDER + .comment("List of entity types that cannot be captured (e.g., minecraft:ender_dragon)") + .defineListAllowEmpty("blacklistedEntities", + List.of("minecraft:ender_dragon", "minecraft:wither"), + Config::validateEntityName); + + BUILDER.pop(); + + BUILDER.comment("Pocket Dimension Configuration").push("pocket_dimensions"); + + DEFAULT_TIME_OF_DAY = BUILDER + .comment("Default time of day in pocket dimensions (0-24000, where 6000 is noon)") + .defineInRange("defaultTimeOfDay", 6000L, 0L, 24000L); + + + + SHOULD_TICK_TIME = BUILDER + .comment("Whether time should advance in pocket dimensions") + .define("shouldTickTime", true); + + TICK_WHEN_EMPTY = BUILDER + .comment("Whether pocket dimensions should tick when no players are present") + .define("tickWhenEmpty", true); + + BUILDER.pop(); + + BUILDER.comment("Weather Configuration").push("weather"); + + DEFAULT_SUNNY_TIME = BUILDER + .comment("Default duration of sunny weather in pocket dimensions (ticks)") + .defineInRange("defaultSunnyTime", Integer.MAX_VALUE, 0, Integer.MAX_VALUE); + + DEFAULT_RAINING = BUILDER + .comment("Whether pocket dimensions should start with rain") + .define("defaultRaining", false); + + DEFAULT_RAIN_TIME = BUILDER + .comment("Default rain duration in pocket dimensions (ticks)") + .defineInRange("defaultRainTime", 0, 0, Integer.MAX_VALUE); + + DEFAULT_THUNDERING = BUILDER + .comment("Whether pocket dimensions should start with thunder") + .define("defaultThundering", false); + + DEFAULT_THUNDER_TIME = BUILDER + .comment("Default thunder duration in pocket dimensions (ticks)") + .defineInRange("defaultThunderTime", 0, 0, Integer.MAX_VALUE); + + BUILDER.pop(); + + BUILDER.comment("Dimension Properties").push("dimension_properties"); + + DIMENSION_HEIGHT = BUILDER + .comment("Height of pocket dimensions (must be multiple of 16)") + .defineInRange("dimensionHeight", 384, 64, 4064); + + DIMENSION_MIN_Y = BUILDER + .comment("Minimum Y level for pocket dimensions") + .defineInRange("dimensionMinY", -64, -2032, 2016); + + COORDINATE_SCALE = BUILDER + .comment("Coordinate scale for pocket dimensions") + .defineInRange("coordinateScale", 1.0, 0.00001, 30000000.0); + + AMBIENT_LIGHT = BUILDER + .comment("Ambient light level in pocket dimensions (0.0 - 1.0)") + .defineInRange("ambientLight", 0.0, 0.0, 1.0); + + BUILDER.pop(); + + SPEC = BUILDER.build(); } + private static boolean validateEntityName(final Object obj) { + if (!(obj instanceof String entityName)) { + return false; + } + try { + ResourceLocation location = ResourceLocation.parse(entityName); + return ForgeRegistries.ENTITY_TYPES.containsKey(location); + } catch (Exception e) { + return false; + } + } + + private static Set> cachedEntityBlacklist = new HashSet<>(); + @SubscribeEvent static void onLoad(final ModConfigEvent event) { - + if (event.getConfig().getSpec() == SPEC) { + updateCachedValues(); + TravelersSuitcase.LOGGER.info("Configuration loaded"); + } } -} + + private static void updateCachedValues() { + cachedEntityBlacklist = ENTITY_BLACKLIST.get().stream() + .map(entityName -> { + try { + ResourceLocation location = ResourceLocation.parse(entityName); + return ForgeRegistries.ENTITY_TYPES.getValue(location); + } catch (Exception e) { + TravelersSuitcase.LOGGER.warn("Invalid entity name in blacklist: {}", entityName); + return null; + } + }) + .filter(entityType -> entityType != null) + .collect(Collectors.toSet()); + } + + public static boolean canCaptureHostile() { + return CAN_CAPTURE_HOSTILE.get(); + } + + public static Set> getEntityBlacklist() { + return new HashSet<>(cachedEntityBlacklist); + } + + public static boolean isEntityBlacklisted(EntityType entityType) { + return cachedEntityBlacklist.contains(entityType); + } + + public static long getDefaultTimeOfDay() { + return DEFAULT_TIME_OF_DAY.get(); + } + + + + public static boolean shouldTickTime() { + return SHOULD_TICK_TIME.get(); + } + + public static boolean tickWhenEmpty() { + return TICK_WHEN_EMPTY.get(); + } + + public static int getDefaultSunnyTime() { + return DEFAULT_SUNNY_TIME.get(); + } + + public static boolean isDefaultRaining() { + return DEFAULT_RAINING.get(); + } + + public static int getDefaultRainTime() { + return DEFAULT_RAIN_TIME.get(); + } + + public static boolean isDefaultThundering() { + return DEFAULT_THUNDERING.get(); + } + + public static int getDefaultThunderTime() { + return DEFAULT_THUNDER_TIME.get(); + } + + public static int getDimensionHeight() { + return DIMENSION_HEIGHT.get(); + } + + public static int getDimensionMinY() { + return DIMENSION_MIN_Y.get(); + } + + public static double getCoordinateScale() { + return COORDINATE_SCALE.get(); + } + + public static double getAmbientLight() { + return AMBIENT_LIGHT.get(); + } +} \ No newline at end of file diff --git a/src/main/java/io/lampnet/travelerssuitcase/TravelersSuitcase.java b/src/main/java/io/lampnet/travelerssuitcase/TravelersSuitcase.java index 10e86cd..251ee85 100644 --- a/src/main/java/io/lampnet/travelerssuitcase/TravelersSuitcase.java +++ b/src/main/java/io/lampnet/travelerssuitcase/TravelersSuitcase.java @@ -1,6 +1,6 @@ package io.lampnet.travelerssuitcase; -import com.mojang.brigadier.arguments.BoolArgumentType; + import com.mojang.brigadier.arguments.StringArgumentType; import com.mojang.brigadier.builder.LiteralArgumentBuilder; import io.lampnet.travelerssuitcase.block.ModBlocks; @@ -48,16 +48,18 @@ import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent; import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; +import net.minecraftforge.fml.ModLoadingContext; +import net.minecraftforge.fml.config.ModConfig; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; -import java.util.HashSet; + import java.util.Set; import net.minecraft.resources.ResourceKey; import net.minecraft.world.entity.Entity; -import net.minecraft.server.MinecraftServer; + import io.lampnet.travelerssuitcase.world.RuntimeWorldHandle; @@ -67,36 +69,16 @@ public class TravelersSuitcase { public static final Logger LOGGER = LogManager.getLogger(MODID); public static final EnterPocketDimensionCriterion ENTER_POCKET_DIMENSION = CriteriaTriggers.register(new EnterPocketDimensionCriterion()); - private static boolean canCaptureHostile = false; - private static final Set> entityBlacklist = new HashSet<>(); - - // Public accessor methods for the configuration public static boolean getCanCaptureHostile() { - return canCaptureHostile; - } - - public static void setCanCaptureHostile(boolean value) { - canCaptureHostile = value; + return Config.canCaptureHostile(); } public static Set> getEntityBlacklist() { - return new HashSet<>(entityBlacklist); - } - - public static void addToBlacklist(EntityType entityType) { - entityBlacklist.add(entityType); - } - - public static boolean removeFromBlacklist(EntityType entityType) { - return entityBlacklist.remove(entityType); + return Config.getEntityBlacklist(); } public static boolean isBlacklisted(EntityType entityType) { - return entityBlacklist.contains(entityType); - } - - public static void clearBlacklist() { - entityBlacklist.clear(); + return Config.isEntityBlacklisted(entityType); } public TravelersSuitcase() { @@ -106,29 +88,24 @@ public class TravelersSuitcase { ModBlocks.register(modEventBus); ModItemGroups.register(modEventBus); ModBlockEntities.register(modEventBus); + FantasyInitializer.register(modEventBus); + + // Register configuration + ModLoadingContext.get().registerConfig(ModConfig.Type.COMMON, Config.SPEC); modEventBus.addListener(this::commonSetup); MinecraftForge.EVENT_BUS.register(this); - MinecraftForge.EVENT_BUS.register(TravelersSuitcase.class); // Register static methods + MinecraftForge.EVENT_BUS.register(TravelersSuitcase.class); } private void commonSetup(final FMLCommonSetupEvent event) { - // Register chunk generators during setup phase new FantasyInitializer().onInitialize(); } @SubscribeEvent public static void onServerStarting(ServerStartingEvent event) { SuitcaseRegistryState.onServerStart(event.getServer()); - - // Load configuration - try { - loadConfig(event.getServer()); - LOGGER.info("Configuration loaded successfully"); - } catch (IOException e) { - LOGGER.warn("Failed to load configuration, using defaults", e); - } Path registryFile = event.getServer().getWorldPath(net.minecraft.world.level.storage.LevelResource.ROOT) .resolve("data") @@ -153,8 +130,7 @@ public class TravelersSuitcase { .setSeed(seed); RuntimeWorldHandle handle = Fantasy.get(event.getServer()).getOrOpenPersistentWorld(worldId, cfg); - // Ensure the pocket dimension ticks even when empty to prevent entity tick issues - handle.setTickWhenEmpty(true); + handle.setTickWhenEmpty(Config.tickWhenEmpty()); } } catch (IOException e) { TravelersSuitcase.LOGGER.error("Failed to reload pocket dimensions", e); @@ -266,7 +242,6 @@ public class TravelersSuitcase { return 0; } - // Reset player entry to default position PlayerEntryData playerData = PlayerEntryData.get(targetWorld); playerData.resetToDefault(); @@ -292,7 +267,6 @@ public class TravelersSuitcase { return 0; } - // Reset mob entry to default position MobEntryData mobData = MobEntryData.get(targetWorld); mobData.setEntry(new Vec3(35.5, 85.0, 16.5), 0f, 0f); @@ -329,19 +303,11 @@ public class TravelersSuitcase { ) .then(Commands.literal("canCaptureHostile") .requires(src -> src.hasPermission(2)) - .then(Commands.argument("value", BoolArgumentType.bool()) - .executes(ctx -> { - boolean value = BoolArgumentType.getBool(ctx, "value"); - canCaptureHostile = value; - ctx.getSource().sendSuccess(() -> Component.literal( - value ? "§aHostile mob capture enabled" : "§cHostile mob capture disabled" - ), false); - return 1; - }) - ) - .executes(ctx -> { + .executes(ctx -> { + boolean enabled = Config.canCaptureHostile(); ctx.getSource().sendSuccess(() -> Component.literal( - "§7Hostile mob capture is currently: " + (canCaptureHostile ? "§aEnabled" : "§cDisabled") + "§7Hostile mob capture is currently: " + (enabled ? "§aEnabled" : "§cDisabled") + + "\n§7(Configure in config file)" ), false); return 1; }) @@ -356,7 +322,7 @@ public class TravelersSuitcase { try { ResourceLocation entityId = ResourceLocation.parse(entityString); EntityType entityType = BuiltInRegistries.ENTITY_TYPE.get(entityId); - if (entityType == EntityType.PIG && !entityString.equals("minecraft:pig")) { // Default fallback + if (entityType == EntityType.PIG && !entityString.equals("minecraft:pig")) { src.sendFailure(Component.literal("§cUnknown entity type: " + entityString)); return 0; } @@ -364,7 +330,6 @@ public class TravelersSuitcase { src.sendFailure(Component.literal("§cCannot blacklist players")); return 0; } - entityBlacklist.add(entityType); src.sendSuccess(() -> Component.literal("§aAdded " + entityId + " to blacklist"), false); return 1; } catch (Exception e) { @@ -386,11 +351,7 @@ public class TravelersSuitcase { src.sendFailure(Component.literal("§cUnknown entity type: " + entityString)); return 0; } - if (entityBlacklist.remove(entityType)) { - src.sendSuccess(() -> Component.literal("§aRemoved " + entityId + " from blacklist"), false); - } else { - src.sendSuccess(() -> Component.literal("§7" + entityId + " was not in blacklist"), false); - } + src.sendSuccess(() -> Component.literal("§eEntity blacklist is managed through configuration files"), false); return 1; } catch (Exception e) { src.sendFailure(Component.literal("§cInvalid entity identifier: " + entityString)); @@ -402,11 +363,12 @@ public class TravelersSuitcase { .then(Commands.literal("list") .executes(ctx -> { var src = ctx.getSource(); - if (entityBlacklist.isEmpty()) { + Set> blacklist = Config.getEntityBlacklist(); + if (blacklist.isEmpty()) { src.sendSuccess(() -> Component.literal("§7No entities are blacklisted"), false); } else { src.sendSuccess(() -> Component.literal("§aBlacklisted entities:"), false); - entityBlacklist.forEach(entityType -> { + blacklist.forEach(entityType -> { var id = BuiltInRegistries.ENTITY_TYPE.getKey(entityType); src.sendSuccess(() -> Component.literal(" " + id), false); }); @@ -415,127 +377,17 @@ public class TravelersSuitcase { }) ) .then(Commands.literal("clear") - .executes(ctx -> { +.executes(ctx -> { var src = ctx.getSource(); - int count = entityBlacklist.size(); - entityBlacklist.clear(); - src.sendSuccess(() -> Component.literal("§aCleared blacklist (removed " + count + " entities)"), false); + src.sendSuccess(() -> Component.literal("§eEntity blacklist is managed through configuration files"), false); return 1; }) ) - ) - .then(Commands.literal("config") - .requires(src -> src.hasPermission(2)) - .then(Commands.literal("save") - .executes(ctx -> { - var src = ctx.getSource(); - try { - saveConfig(src.getServer()); - src.sendSuccess(() -> Component.literal("§aConfiguration saved successfully"), false); - return 1; - } catch (Exception e) { - src.sendFailure(Component.literal("§cFailed to save configuration: " + e.getMessage())); - return 0; - } - }) - ) - .then(Commands.literal("load") - .executes(ctx -> { - var src = ctx.getSource(); - try { - loadConfig(src.getServer()); - src.sendSuccess(() -> Component.literal("§aConfiguration loaded successfully"), false); - return 1; - } catch (Exception e) { - src.sendFailure(Component.literal("§cFailed to load configuration: " + e.getMessage())); - return 0; - } - }) - ) - .then(Commands.literal("reload") - .executes(ctx -> { - var src = ctx.getSource(); - try { - loadConfig(src.getServer()); - src.sendSuccess(() -> Component.literal("§aConfiguration reloaded successfully"), false); - return 1; - } catch (Exception e) { - src.sendFailure(Component.literal("§cFailed to reload configuration: " + e.getMessage())); - return 0; - } - }) - ) ); event.getDispatcher().register(builder); } - private static void saveConfig(MinecraftServer server) throws IOException { - Path configDir = server.getWorldPath(net.minecraft.world.level.storage.LevelResource.ROOT) - .resolve("data") - .resolve(MODID); - - Files.createDirectories(configDir); - - Path configFile = configDir.resolve("config.properties"); - - StringBuilder content = new StringBuilder(); - content.append("canCaptureHostile=").append(canCaptureHostile).append("\n"); - content.append("blacklistedEntities="); - - boolean first = true; - for (EntityType entityType : entityBlacklist) { - if (!first) { - content.append(","); - } - content.append(BuiltInRegistries.ENTITY_TYPE.getKey(entityType)); - first = false; - } - content.append("\n"); - - Files.writeString(configFile, content.toString()); - } - private static void loadConfig(MinecraftServer server) throws IOException { - Path configFile = server.getWorldPath(net.minecraft.world.level.storage.LevelResource.ROOT) - .resolve("data") - .resolve(MODID) - .resolve("config.properties"); - - if (!Files.exists(configFile)) { - return; - } - - entityBlacklist.clear(); - - for (String line : Files.readAllLines(configFile)) { - String[] parts = line.split("=", 2); - if (parts.length != 2) continue; - - String key = parts[0].trim(); - String value = parts[1].trim(); - - switch (key) { - case "canCaptureHostile": - canCaptureHostile = Boolean.parseBoolean(value); - break; - case "blacklistedEntities": - if (!value.isEmpty()) { - for (String entityId : value.split(",")) { - try { - ResourceLocation id = ResourceLocation.parse(entityId.trim()); - EntityType entityType = BuiltInRegistries.ENTITY_TYPE.get(id); - if (entityType != EntityType.PIG || entityId.trim().equals("minecraft:pig")) { - entityBlacklist.add(entityType); - } - } catch (Exception e) { - LOGGER.warn("Failed to parse entity ID from config: " + entityId, e); - } - } - } - break; - } - } - } @SubscribeEvent public void onUseEntity(PlayerInteractEvent.EntityInteract event) { @@ -576,7 +428,7 @@ public class TravelersSuitcase { if (!(entity instanceof LivingEntity mob)) { return; } - if (entityBlacklist.contains(mob.getType())) { + if (Config.isEntityBlacklisted(mob.getType())) { player.displayClientMessage(Component.literal("§c☒"), true); world.playSound(null, player.getX(), player.getY(), player.getZ(), SoundEvents.ZOMBIE_ATTACK_WOODEN_DOOR, SoundSource.PLAYERS, 0.3f, 1.5f); event.setCancellationResult(InteractionResult.FAIL); @@ -584,7 +436,7 @@ public class TravelersSuitcase { return; } boolean isHostile = mob instanceof Enemy || (mob instanceof Wolf wolf && wolf.isAngryAtAllPlayers(world)); - if (!canCaptureHostile && isHostile) { + if (!Config.canCaptureHostile() && isHostile) { player.displayClientMessage(Component.literal("§c☒"), true); world.playSound(null, player.getX(), player.getY(), player.getZ(), SoundEvents.ZOMBIE_ATTACK_WOODEN_DOOR, SoundSource.PLAYERS, 0.3f, 1.5f); event.setCancellationResult(InteractionResult.FAIL); @@ -607,8 +459,7 @@ public class TravelersSuitcase { event.setCanceled(true); return; } - - // Key rescue mob + if (stack.getItem() instanceof KeystoneItem) { ResourceLocation dimId = world.dimension().location(); String namespace = dimId.getNamespace(); diff --git a/src/main/java/io/lampnet/travelerssuitcase/block/SuitcaseBlock.java b/src/main/java/io/lampnet/travelerssuitcase/block/SuitcaseBlock.java index da16d71..c0865d5 100644 --- a/src/main/java/io/lampnet/travelerssuitcase/block/SuitcaseBlock.java +++ b/src/main/java/io/lampnet/travelerssuitcase/block/SuitcaseBlock.java @@ -312,7 +312,7 @@ public class SuitcaseBlock extends BaseEntityBlock { CompoundTag display = stack.getOrCreateTagElement("display"); ListTag lore = new ListTag(); if (!suitcase.getEnteredPlayers().isEmpty()) { - Component warningText = Component.literal("§c⚠ Contains " + suitcase.getEnteredPlayers().size() + " Traveler's!") + Component warningText = Component.literal("§c⚠ Contains " + suitcase.getEnteredPlayers().size() + " Travelers!") .withStyle(ChatFormatting.RED); lore.add(StringTag.valueOf(Component.Serializer.toJson(warningText))); } diff --git a/src/main/java/io/lampnet/travelerssuitcase/block/entity/SuitcaseBlockEntity.java b/src/main/java/io/lampnet/travelerssuitcase/block/entity/SuitcaseBlockEntity.java index 1b68773..da3ec8b 100644 --- a/src/main/java/io/lampnet/travelerssuitcase/block/entity/SuitcaseBlockEntity.java +++ b/src/main/java/io/lampnet/travelerssuitcase/block/entity/SuitcaseBlockEntity.java @@ -187,13 +187,11 @@ public class SuitcaseBlockEntity extends BlockEntity { @Override public @NotNull CompoundTag getUpdateTag() { CompoundTag nbt = new CompoundTag(); - // Only sync essential data to client, not player entry data which could cause position conflicts if (boundKeystoneName != null) { nbt.putString("BoundKeystone", boundKeystoneName); } nbt.putBoolean("Locked", isLocked); nbt.putBoolean("DimensionLocked", dimensionLocked); - // Deliberately exclude EnteredPlayers from client sync to prevent coordinate conflicts return nbt; } diff --git a/src/main/java/io/lampnet/travelerssuitcase/data/MobEntryData.java b/src/main/java/io/lampnet/travelerssuitcase/data/MobEntryData.java index 97c1a1a..0671f56 100644 --- a/src/main/java/io/lampnet/travelerssuitcase/data/MobEntryData.java +++ b/src/main/java/io/lampnet/travelerssuitcase/data/MobEntryData.java @@ -7,8 +7,8 @@ import net.minecraft.world.phys.Vec3; public class MobEntryData extends SavedData { private static final String DATA_KEY = "pocket_entry_data"; - private Vec3 entryPos = Vec3.ZERO; - private float entryYaw = 0f, entryPitch = 0f; + private Vec3 entryPos; + private float entryYaw, entryPitch; public MobEntryData() { super(); diff --git a/src/main/java/io/lampnet/travelerssuitcase/data/PlayerEntryData.java b/src/main/java/io/lampnet/travelerssuitcase/data/PlayerEntryData.java index 1ba5e79..d5ec5eb 100644 --- a/src/main/java/io/lampnet/travelerssuitcase/data/PlayerEntryData.java +++ b/src/main/java/io/lampnet/travelerssuitcase/data/PlayerEntryData.java @@ -8,8 +8,8 @@ import net.minecraft.world.phys.Vec3; public class PlayerEntryData extends SavedData { private static final String DATA_KEY = "pocket_player_entry"; - private Vec3 entryPos = Vec3.ZERO; - private float entryYaw = 0f, entryPitch = 0f; + private Vec3 entryPos; + private float entryYaw, entryPitch; private boolean isManuallySet = false; public PlayerEntryData() { diff --git a/src/main/java/io/lampnet/travelerssuitcase/item/KeystoneItem.java b/src/main/java/io/lampnet/travelerssuitcase/item/KeystoneItem.java index e821e54..a2d3442 100644 --- a/src/main/java/io/lampnet/travelerssuitcase/item/KeystoneItem.java +++ b/src/main/java/io/lampnet/travelerssuitcase/item/KeystoneItem.java @@ -56,22 +56,14 @@ public class KeystoneItem extends Item { public @NotNull InteractionResultHolder use(@NotNull Level world, Player player, @NotNull InteractionHand hand) { ItemStack stack = player.getItemInHand(hand); - // If already enchanted, do nothing if (stack.isEnchanted()) { return InteractionResultHolder.pass(stack); } - // If no valid custom name, do nothing if (!isValidKeystone(stack)) { return InteractionResultHolder.pass(stack); } - - // On client side, just return success - if (world.isClientSide) { - return InteractionResultHolder.success(stack); - } - - // The actual enchantment and dimension creation now happens in inventoryTick + return InteractionResultHolder.success(stack); } @@ -84,18 +76,15 @@ public class KeystoneItem extends Item { .resolve(dimensionName); boolean dimensionExists = Files.exists(worldSavePath); - // Get biome registry - if this fails, the server isn't ready yet var biomeRegistry = server.registryAccess().registryOrThrow(Registries.BIOME); RuntimeWorldConfig config = new RuntimeWorldConfig() .setGenerator(new PortalChunkGenerator(biomeRegistry)) - .setSeed(server.overworld().getSeed()) - .setShouldTickTime(true); + .setSeed(server.overworld().getSeed()); RuntimeWorldHandle handle = Fantasy.get(server) .getOrOpenPersistentWorld(worldId, config); - // Ensure the pocket dimension ticks even when empty to prevent entity tick issues handle.setTickWhenEmpty(true); TravelersSuitcase.LOGGER.info("Created/loaded pocket dimension '{}', ticking enabled: {}", @@ -105,7 +94,6 @@ public class KeystoneItem extends Item { if (!dimensionExists) { ServerLevel world = handle.asWorld(); - // Schedule structure placement for next tick to ensure world is fully initialized server.execute(() -> placeStructureDelayed(server, world, dimensionName)); } } @@ -119,29 +107,10 @@ public class KeystoneItem extends Item { if (template != null) { BlockPos pos = new BlockPos(0, 64, 0); - // Ensure the chunk is fully loaded and ready ChunkPos chunkPos = new ChunkPos(pos); world.getChunkSource().addRegionTicket(TicketType.UNKNOWN, chunkPos, 2, chunkPos); - - // Force chunk to be fully loaded with all features world.getChunk(pos.getX() >> 4, pos.getZ() >> 4, ChunkStatus.FULL, true); - // Place blocks first without entities to ensure support blocks exist - template.placeInWorld( - world, - pos, - pos, - new StructurePlaceSettings() - .setMirror(Mirror.NONE) - .setRotation(Rotation.NONE) - .setIgnoreEntities(true), // Skip entities first - world.getRandom(), - Block.UPDATE_ALL - ); - - world.setChunkForced(pos.getX() >> 4, pos.getZ() >> 4, true); - - // Now place the structure again with entities, blocks won't replace since they're already there template.placeInWorld( world, pos, @@ -151,10 +120,11 @@ public class KeystoneItem extends Item { .setRotation(Rotation.NONE) .setIgnoreEntities(false), world.getRandom(), - Block.UPDATE_NEIGHBORS // Only update neighbors, don't replace existing blocks + Block.UPDATE_ALL ); + + world.setChunkForced(pos.getX() >> 4, pos.getZ() >> 4, true); - // Force a save to ensure the forced chunk data is properly loaded for ticking world.save(null, true, false); } } catch (Exception e) { @@ -172,13 +142,11 @@ public class KeystoneItem extends Item { Files.createDirectories(registryDir); Path registryFile = registryDir.resolve("registry.txt"); - // load existing lines Set dims = new HashSet<>(); if (Files.exists(registryFile)) { dims.addAll(Files.readAllLines(registryFile)); } - // add + save only if new if (dims.add(dimensionName)) { Files.write(registryFile, dims); } @@ -217,7 +185,6 @@ public class KeystoneItem extends Item { stack.getTag().remove("CustomModelData"); } - // Auto-enchant and create dimension when item gets a valid custom name if (!world.isClientSide() && hasValidName && !stack.isEnchanted()) { String dimensionName = "pocket_dimension_" + keystoneName.replaceAll("[^a-z0-9_]", ""); createOrLoadPersistentDimension(world.getServer(), dimensionName); @@ -226,17 +193,19 @@ public class KeystoneItem extends Item { CompoundTag nbt = stack.getOrCreateTag(); nbt.putInt("RepairCost", 32767); - // Play sound effect if entity is a player if (entity instanceof Player player) { world.playSound(null, player.getX(), player.getY(), player.getZ(), SoundEvents.AMETHYST_CLUSTER_FALL, SoundSource.PLAYERS, 2.0F, 2.0F); } } - if (!world.isClientSide() && stack.hasTag() && stack.getTag().contains("Enchantments")) { - CompoundTag nbt = stack.getOrCreateTag(); - if (nbt.getInt("RepairCost") < 32767) { - nbt.putInt("RepairCost", 32767); + if (!world.isClientSide() && stack.hasTag()) { + assert stack.getTag() != null; + if (stack.getTag().contains("Enchantments")) { + CompoundTag nbt = stack.getOrCreateTag(); + if (nbt.getInt("RepairCost") < 32767) { + nbt.putInt("RepairCost", 32767); + } } } } diff --git a/src/main/java/io/lampnet/travelerssuitcase/mixin/MappedRegistryMixin.java b/src/main/java/io/lampnet/travelerssuitcase/mixin/MappedRegistryMixin.java index 963543c..99b4855 100644 --- a/src/main/java/io/lampnet/travelerssuitcase/mixin/MappedRegistryMixin.java +++ b/src/main/java/io/lampnet/travelerssuitcase/mixin/MappedRegistryMixin.java @@ -17,25 +17,21 @@ public abstract class MappedRegistryMixin implements RemoveFromRegistry { @Override public boolean fantasy$remove(T value) { - // Implementation depends on access to private fields // For now, return false as removal is complex return false; } @Override public boolean fantasy$remove(ResourceLocation key) { - // Implementation depends on access to private fields // For now, return false as removal is complex return false; } @Override public void fantasy$setFrozen(boolean value) { - // Store the original frozen state so we can restore it later if (!value && this.frozen) { this.fantasy$originalFrozenState = true; } - // Actually modify the registry's frozen state this.frozen = value; } diff --git a/src/main/java/io/lampnet/travelerssuitcase/mixin/ServerChunkManagerMixin.java b/src/main/java/io/lampnet/travelerssuitcase/mixin/ServerChunkManagerMixin.java index 94d40eb..41f64be 100644 --- a/src/main/java/io/lampnet/travelerssuitcase/mixin/ServerChunkManagerMixin.java +++ b/src/main/java/io/lampnet/travelerssuitcase/mixin/ServerChunkManagerMixin.java @@ -15,21 +15,17 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; public class ServerChunkManagerMixin { @Shadow @Final - private ServerLevel level; + public ServerLevel level; @Inject(method = "runDistanceManagerUpdates", at = @At("HEAD"), cancellable = true) private void onRunDistanceManagerUpdates(CallbackInfoReturnable cir) { - // Only apply special chunk processing logic to RuntimeWorld instances (fantasy dimensions) if (this.level instanceof RuntimeWorld) { FantasyWorldAccess worldAccess = (FantasyWorldAccess) this.level; - // Always allow distance manager updates if chunks are loaded (prevents breaking entity initialization) - // Only block when world is truly empty AND configured not to tick when empty + if (this.level.getChunkSource().getLoadedChunksCount() > 0 || worldAccess.fantasy$shouldTick()) { - // Allow distance manager to run - this is critical for entity systems return; } cir.setReturnValue(false); } - // Regular worlds (overworld, nether, end) process chunks normally without interference } } \ No newline at end of file diff --git a/src/main/java/io/lampnet/travelerssuitcase/mixin/ServerWorldMixin.java b/src/main/java/io/lampnet/travelerssuitcase/mixin/ServerWorldMixin.java index 008fa4f..9349e62 100644 --- a/src/main/java/io/lampnet/travelerssuitcase/mixin/ServerWorldMixin.java +++ b/src/main/java/io/lampnet/travelerssuitcase/mixin/ServerWorldMixin.java @@ -17,17 +17,15 @@ import java.util.function.BooleanSupplier; @Mixin(ServerLevel.class) public abstract class ServerWorldMixin implements FantasyWorldAccess { @Unique - private boolean fantasy$tickWhenEmpty = false; // Default to false, will be set to true for fantasy worlds + private boolean fantasy$tickWhenEmpty = false; @Inject(method = "tick", at = @At("HEAD"), cancellable = true) private void onTick(BooleanSupplier shouldKeepTicking, CallbackInfo ci) { - // Only apply special tick logic to RuntimeWorld instances (fantasy dimensions) if ((Object) this instanceof RuntimeWorld) { if (!this.fantasy$shouldTick()) { ci.cancel(); } } - // Regular worlds (overworld, nether, end) tick normally without interference } @Shadow @@ -43,16 +41,14 @@ public abstract class ServerWorldMixin implements FantasyWorldAccess { @Override public boolean fantasy$shouldTick() { - // For RuntimeWorld instances, use the configured behavior if ((Object) this instanceof RuntimeWorld) { - return this.fantasy$tickWhenEmpty || !this.isWorldEmpty(); + return this.fantasy$tickWhenEmpty || !this.travelerssuitcase$isWorldEmpty(); } - // For regular worlds, always tick (normal behavior) return true; } @Unique - private boolean isWorldEmpty() { + private boolean travelerssuitcase$isWorldEmpty() { return this.players().isEmpty() && this.getChunkSource().getLoadedChunksCount() <= 0; } } \ No newline at end of file diff --git a/src/main/java/io/lampnet/travelerssuitcase/util/FilteredRegistry.java b/src/main/java/io/lampnet/travelerssuitcase/util/FilteredRegistry.java deleted file mode 100644 index 8ef5618..0000000 --- a/src/main/java/io/lampnet/travelerssuitcase/util/FilteredRegistry.java +++ /dev/null @@ -1,144 +0,0 @@ -package io.lampnet.travelerssuitcase.util; - -import com.google.common.collect.Iterators; -import com.mojang.serialization.Lifecycle; -import net.minecraft.core.Holder; -import net.minecraft.core.MappedRegistry; -import net.minecraft.core.Registry; -import net.minecraft.resources.ResourceKey; -import net.minecraft.resources.ResourceLocation; -import org.jetbrains.annotations.NotNull; - -import javax.annotation.Nullable; -import java.util.*; -import java.util.function.Predicate; -import java.util.stream.Stream; - -public class FilteredRegistry extends MappedRegistry { - private final Registry source; - private final Predicate check; - - public FilteredRegistry(Registry source, Predicate check) { - super(source.key(), source.registryLifecycle(), false); - this.source = source; - this.check = check; - } - - public Registry getSource() { - return this.source; - } - - @Nullable - @Override - public ResourceLocation getKey(T value) { - return check.test(value) ? this.source.getKey(value) : null; - } - - @Override - public Optional> getResourceKey(T entry) { - return check.test(entry) ? this.source.getResourceKey(entry) : Optional.empty(); - } - - @Override - public int getId(@Nullable T value) { - return check.test(value) ? this.source.getId(value) : -1; - } - - public T get(int index) { - return this.source.byId(index); - } - - @Override - public int size() { - return (int) this.source.stream().filter(check).count(); - } - - @Nullable - @Override - public T get(@Nullable ResourceKey key) { - T value = this.source.get(key); - return (value != null && check.test(value)) ? value : null; - } - - @Nullable - @Override - public T get(@Nullable ResourceLocation id) { - T value = this.source.get(id); - return (value != null && check.test(value)) ? value : null; - } - - @Override - public Lifecycle lifecycle(T entry) { - return this.source.lifecycle(entry); - } - - @Override - public @NotNull Set keySet() { - Set keys = new HashSet<>(); - this.source.keySet().forEach(key -> { - T value = this.source.get(key); - if(value != null && check.test(value)) { - keys.add(key); - } - }); - return keys; - } - - @Override - public @NotNull Set, T>> entrySet() { - Set, T>> set = new HashSet<>(); - for (Map.Entry, T> e : this.source.entrySet()) { - if (this.check.test(e.getValue())) { - set.add(e); - } - } - return set; - } - - @Override - public boolean containsKey(ResourceLocation id) { - T value = this.source.get(id); - return value != null && check.test(value); - } - - @Override - public boolean containsKey(ResourceKey key) { - T value = this.source.get(key); - return value != null && check.test(value); - } - - @Override - public @NotNull Iterator iterator() { - return Iterators.filter(this.source.iterator(), e -> this.check.test(e)); - } - - // Methods below are for WritableRegistry, we don't support writing to a filtered registry - @Override - public Holder.Reference register(ResourceKey resourceKey, T object, Lifecycle lifecycle) { - throw new UnsupportedOperationException("Cannot register to a filtered registry"); - } - - public Holder.Reference registerOrNah(ResourceKey resourceKey, T object, Lifecycle lifecycle) { - throw new UnsupportedOperationException("Cannot register to a filtered registry"); - } - - @Override - public Holder.Reference registerMapping(int i, ResourceKey resourceKey, T object, Lifecycle lifecycle) { - throw new UnsupportedOperationException("Cannot register to a filtered registry"); - } - - @Override - public Holder.Reference getHolderOrThrow(ResourceKey resourceKey) { - return this.source.getHolderOrThrow(resourceKey); - } - - @Override - public Optional> getHolder(ResourceKey resourceKey) { - return this.source.getHolder(resourceKey); - } - - @Override - public Stream> holders() { - return this.source.holders().filter(h -> check.test(h.value())); - } -} \ No newline at end of file diff --git a/src/main/java/io/lampnet/travelerssuitcase/util/GameRuleStore.java b/src/main/java/io/lampnet/travelerssuitcase/util/GameRuleStore.java index cd76349..450f3be 100644 --- a/src/main/java/io/lampnet/travelerssuitcase/util/GameRuleStore.java +++ b/src/main/java/io/lampnet/travelerssuitcase/util/GameRuleStore.java @@ -19,10 +19,6 @@ public final class GameRuleStore { this.intRules.put(key, value); } - public boolean contains(GameRules.Key key) { - return this.booleanRules.containsKey(key) || this.intRules.containsKey(key); - } - public void applyTo(GameRules rules, @Nullable MinecraftServer server) { for (Map.Entry, Boolean> entry : this.booleanRules.entrySet()) { GameRules.BooleanValue rule = rules.getRule(entry.getKey()); diff --git a/src/main/java/io/lampnet/travelerssuitcase/util/SafeIterator.java b/src/main/java/io/lampnet/travelerssuitcase/util/SafeIterator.java deleted file mode 100644 index 4446537..0000000 --- a/src/main/java/io/lampnet/travelerssuitcase/util/SafeIterator.java +++ /dev/null @@ -1,23 +0,0 @@ -package io.lampnet.travelerssuitcase.util; - -import java.util.Collection; -import java.util.Iterator; - -public final class SafeIterator implements Iterator { - private final Object[] values; - private int index = 0; - - public SafeIterator(Collection source) { - this.values = source.toArray(); - } - - @Override - public boolean hasNext() { - return this.values.length > this.index; - } - - @Override - public T next() { - return (T) this.values[this.index++]; - } -} \ No newline at end of file diff --git a/src/main/java/io/lampnet/travelerssuitcase/util/VoidChunkGenerator.java b/src/main/java/io/lampnet/travelerssuitcase/util/VoidChunkGenerator.java deleted file mode 100644 index aa9c226..0000000 --- a/src/main/java/io/lampnet/travelerssuitcase/util/VoidChunkGenerator.java +++ /dev/null @@ -1,90 +0,0 @@ -package io.lampnet.travelerssuitcase.util; - -import com.mojang.serialization.Codec; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Registry; -import net.minecraft.server.level.WorldGenRegion; -import net.minecraft.world.level.LevelHeightAccessor; -import net.minecraft.world.level.NoiseColumn; -import net.minecraft.world.level.StructureManager; -import net.minecraft.world.level.biome.Biome; -import net.minecraft.world.level.biome.BiomeManager; -import net.minecraft.world.level.biome.Biomes; -import net.minecraft.world.level.biome.FixedBiomeSource; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.chunk.ChunkAccess; -import net.minecraft.world.level.chunk.ChunkGenerator; -import net.minecraft.world.level.levelgen.GenerationStep; -import net.minecraft.world.level.levelgen.Heightmap; -import net.minecraft.world.level.levelgen.RandomState; -import net.minecraft.world.level.levelgen.blending.Blender; -import org.jetbrains.annotations.NotNull; - -import java.util.List; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.Executor; - -public class VoidChunkGenerator extends ChunkGenerator { - public static final Codec CODEC = Codec.unit(VoidChunkGenerator::new); - - public VoidChunkGenerator(Registry biomeRegistry) { - super(new FixedBiomeSource(biomeRegistry.getHolderOrThrow(Biomes.THE_VOID))); - } - - public VoidChunkGenerator() { - super(new FixedBiomeSource(null)); - } - - @Override - protected @NotNull Codec codec() { - return CODEC; - } - - @Override - public void applyCarvers(WorldGenRegion worldGenRegion, long seed, RandomState randomState, BiomeManager biomeManager, StructureManager structureManager, ChunkAccess chunkAccess, GenerationStep.Carving carving) { - } - - @Override - public void spawnOriginalMobs(WorldGenRegion worldGenRegion) { - } - - @Override - public int getGenDepth() { - return 384; - } - - @Override - public @NotNull CompletableFuture fillFromNoise(Executor executor, Blender blender, RandomState randomState, StructureManager structureManager, ChunkAccess chunkAccess) { - return CompletableFuture.completedFuture(chunkAccess); - } - - @Override - public int getSeaLevel() { - return 0; - } - - @Override - public int getMinY() { - return 0; - } - - @Override - public int getBaseHeight(int i, int j, Heightmap.Types types, LevelHeightAccessor levelHeightAccessor, RandomState randomState) { - return 0; - } - - @Override - public @NotNull NoiseColumn getBaseColumn(int i, int j, LevelHeightAccessor levelHeightAccessor, RandomState randomState) { - return new NoiseColumn(0, new BlockState[0]); - } - - @Override - public void addDebugScreenInfo(List list, RandomState randomState, BlockPos blockPos) { - } - - @Override - public void buildSurface(WorldGenRegion worldGenRegion, StructureManager structureManager, RandomState randomState, - ChunkAccess chunkAccess) { - // No surface to build for void chunks - } -} \ No newline at end of file diff --git a/src/main/java/io/lampnet/travelerssuitcase/world/Fantasy.java b/src/main/java/io/lampnet/travelerssuitcase/world/Fantasy.java index be30aa9..7d42d33 100644 --- a/src/main/java/io/lampnet/travelerssuitcase/world/Fantasy.java +++ b/src/main/java/io/lampnet/travelerssuitcase/world/Fantasy.java @@ -43,7 +43,6 @@ public final class Fantasy { private final Set unloadingQueue = new ReferenceOpenHashSet<>(); static { - // We need to register the event listener on the bus. MinecraftForge.EVENT_BUS.register(Fantasy.class); } diff --git a/src/main/java/io/lampnet/travelerssuitcase/world/FantasyInitializer.java b/src/main/java/io/lampnet/travelerssuitcase/world/FantasyInitializer.java index 5de6e8a..bdffe76 100644 --- a/src/main/java/io/lampnet/travelerssuitcase/world/FantasyInitializer.java +++ b/src/main/java/io/lampnet/travelerssuitcase/world/FantasyInitializer.java @@ -1,15 +1,25 @@ package io.lampnet.travelerssuitcase.world; -import io.lampnet.travelerssuitcase.util.VoidChunkGenerator; -import net.minecraft.core.Registry; -import net.minecraft.core.registries.BuiltInRegistries; -import net.minecraft.resources.ResourceLocation; - -import static io.lampnet.travelerssuitcase.TravelersSuitcase.MODID; +import com.mojang.serialization.Codec; +import io.lampnet.travelerssuitcase.TravelersSuitcase; +import net.minecraft.core.registries.Registries; +import net.minecraft.world.level.chunk.ChunkGenerator; +import net.minecraftforge.eventbus.api.IEventBus; +import net.minecraftforge.registries.DeferredRegister; +import net.minecraftforge.registries.RegistryObject; public final class FantasyInitializer { + public static final DeferredRegister> CHUNK_GENERATORS = + DeferredRegister.create(Registries.CHUNK_GENERATOR, TravelersSuitcase.MODID); + + public static final RegistryObject> PORTAL_GENERATOR = + CHUNK_GENERATORS.register("portal", () -> PortalChunkGenerator.CODEC); + + public static void register(IEventBus eventBus) { + CHUNK_GENERATORS.register(eventBus); + } + public void onInitialize() { - Registry.register(BuiltInRegistries.CHUNK_GENERATOR, ResourceLocation.fromNamespaceAndPath(MODID, "void"), VoidChunkGenerator.CODEC); - Registry.register(BuiltInRegistries.CHUNK_GENERATOR, ResourceLocation.fromNamespaceAndPath(MODID, "portal"), PortalChunkGenerator.CODEC); + // Registration now handled by DeferredRegister } } \ No newline at end of file diff --git a/src/main/java/io/lampnet/travelerssuitcase/world/PortalChunkGenerator.java b/src/main/java/io/lampnet/travelerssuitcase/world/PortalChunkGenerator.java index 347fb89..8a5e099 100644 --- a/src/main/java/io/lampnet/travelerssuitcase/world/PortalChunkGenerator.java +++ b/src/main/java/io/lampnet/travelerssuitcase/world/PortalChunkGenerator.java @@ -24,6 +24,7 @@ import net.minecraft.core.registries.Registries; import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceLocation; +import java.util.Arrays; import java.util.concurrent.CompletableFuture; import java.util.concurrent.Executor; @@ -92,9 +93,7 @@ public class PortalChunkGenerator extends ChunkGenerator { @Override public NoiseColumn getBaseColumn(int x, int z, LevelHeightAccessor level, RandomState randomState) { BlockState[] column = new BlockState[level.getHeight()]; - for (int i = 0; i < column.length; i++) { - column[i] = Blocks.AIR.defaultBlockState(); - } + Arrays.fill(column, Blocks.AIR.defaultBlockState()); return new NoiseColumn(level.getMinBuildHeight(), column); } diff --git a/src/main/java/io/lampnet/travelerssuitcase/world/RuntimeWorld.java b/src/main/java/io/lampnet/travelerssuitcase/world/RuntimeWorld.java index 2023dcb..3ab88c7 100644 --- a/src/main/java/io/lampnet/travelerssuitcase/world/RuntimeWorld.java +++ b/src/main/java/io/lampnet/travelerssuitcase/world/RuntimeWorld.java @@ -22,7 +22,7 @@ public class RuntimeWorld extends ServerLevel { server, Util.backgroundExecutor(), ((MinecraftServerAccess) server).getSession(), - new RuntimeWorldProperties(server.getWorldData().overworldData(), config), + new RuntimeWorldProperties(server.getWorldData().overworldData(), config, server), registryKey, new LevelStem( server.registryAccess().registryOrThrow(net.minecraft.core.registries.Registries.DIMENSION_TYPE) diff --git a/src/main/java/io/lampnet/travelerssuitcase/world/RuntimeWorldConfig.java b/src/main/java/io/lampnet/travelerssuitcase/world/RuntimeWorldConfig.java index a8cbffe..624a242 100644 --- a/src/main/java/io/lampnet/travelerssuitcase/world/RuntimeWorldConfig.java +++ b/src/main/java/io/lampnet/travelerssuitcase/world/RuntimeWorldConfig.java @@ -1,6 +1,7 @@ package io.lampnet.travelerssuitcase.world; import com.google.common.base.Preconditions; +import io.lampnet.travelerssuitcase.Config; import io.lampnet.travelerssuitcase.util.GameRuleStore; import net.minecraft.core.Holder; import net.minecraft.core.registries.Registries; @@ -17,20 +18,19 @@ public final class RuntimeWorldConfig { private ResourceKey dimensionTypeKey = Fantasy.DEFAULT_DIM_TYPE; private Holder dimensionType; private ChunkGenerator generator = null; - private boolean shouldTickTime = false; - private long timeOfDay = 6000; - private Difficulty difficulty = Difficulty.NORMAL; + private boolean shouldTickTime = Config.shouldTickTime(); + private long timeOfDay = Config.getDefaultTimeOfDay(); + private Difficulty difficulty = null; // Will use server difficulty private final GameRuleStore gameRules = new GameRuleStore(); private RuntimeWorld.Constructor worldConstructor = RuntimeWorld::new; - private int sunnyTime = Integer.MAX_VALUE; - private boolean raining; - private int rainTime; - private boolean thundering; - private int thunderTime; + private int sunnyTime = Config.getDefaultSunnyTime(); + private boolean raining = Config.isDefaultRaining(); + private int rainTime = Config.getDefaultRainTime(); + private boolean thundering = Config.isDefaultThundering(); + private int thunderTime = Config.getDefaultThunderTime(); private TriState flat = TriState.DEFAULT; - // Simple TriState implementation public enum TriState { DEFAULT, TRUE, @@ -165,8 +165,8 @@ public final class RuntimeWorldConfig { return this.timeOfDay; } - public Difficulty getDifficulty() { - return this.difficulty; + public Difficulty getDifficulty(MinecraftServer server) { + return this.difficulty != null ? this.difficulty : server.getWorldData().getDifficulty(); } public GameRuleStore getGameRules() { diff --git a/src/main/java/io/lampnet/travelerssuitcase/world/RuntimeWorldProperties.java b/src/main/java/io/lampnet/travelerssuitcase/world/RuntimeWorldProperties.java index 59dd027..e0614f9 100644 --- a/src/main/java/io/lampnet/travelerssuitcase/world/RuntimeWorldProperties.java +++ b/src/main/java/io/lampnet/travelerssuitcase/world/RuntimeWorldProperties.java @@ -1,7 +1,7 @@ package io.lampnet.travelerssuitcase.world; import net.minecraft.CrashReportCategory; -import net.minecraft.core.BlockPos; + import net.minecraft.server.MinecraftServer; import net.minecraft.world.Difficulty; import net.minecraft.world.level.GameRules; @@ -16,10 +16,12 @@ import java.util.UUID; public class RuntimeWorldProperties implements ServerLevelData { private final ServerLevelData parent; final RuntimeWorldConfig config; + private final MinecraftServer server; - public RuntimeWorldProperties(ServerLevelData parent, RuntimeWorldConfig config) { + public RuntimeWorldProperties(ServerLevelData parent, RuntimeWorldConfig config, MinecraftServer server) { this.parent = parent; this.config = config; + this.server = server; } @Override @@ -150,7 +152,7 @@ public class RuntimeWorldProperties implements ServerLevelData { @Override public @NotNull Difficulty getDifficulty() { - return this.config.getDifficulty(); + return this.config.getDifficulty(this.server); } @Override