From 8bb5e167200568bde2febd9ee2d55c8b5fc49f7f Mon Sep 17 00:00:00 2001 From: Dustin Norberg Date: Tue, 22 Sep 2026 16:37:33 -0400 Subject: [PATCH] Apply persisted Age celestial timing --- docs/PORTING.md | 8 ++++++++ gradle.properties | 2 +- .../dnorberg/rivencraft/book/AgeDefinition.java | 2 +- .../rivencraft/book/AgeDimensionService.java | 17 ++++++++++++++++- .../rivencraft/gametest/LinkingGameTests.java | 3 +++ 5 files changed, 29 insertions(+), 3 deletions(-) diff --git a/docs/PORTING.md b/docs/PORTING.md index ecfac0b..5d93d41 100644 --- a/docs/PORTING.md +++ b/docs/PORTING.md @@ -291,6 +291,14 @@ Always, Cloudy, Rain, and Snow maintain non-thundering precipitation; Storm maintains rain and thunder. Minecraft still chooses rain versus snow from biome temperature, so dedicated Snow/Rain biome overrides remain future work. +Version 0.2.20.0 applies persisted celestial timing to each Age. The saved +period controls NeoForge's per-dimension clock rate, with a period of 1 matching +a vanilla 20-minute day, 0.2 running five times faster, and 2 running at half +speed. The saved phase sets the clock only during first-spawn initialization; +later loads continue from saved world time. Celestial angle remains persisted +for a future custom sky renderer because vanilla dimension data cannot rotate +the sun's render plane. + Version 0.2.14.0 restores the legacy Linking and Descriptive Book artwork for inventory items and gives each book its matching open-book texture when placed on a Book Stand. Return Linking Books created inside another Age also retain and diff --git a/gradle.properties b/gradle.properties index d8c1dbc..9c170fa 100644 --- a/gradle.properties +++ b/gradle.properties @@ -35,7 +35,7 @@ mod_name=Rivencraft # The license of the mod. Review your options at https://choosealicense.com/. All Rights Reserved is the default. mod_license=LGPL-3.0-or-later # The mod version. Rivencraft uses the x.y.z.b policy documented in README.md. -mod_version=0.2.19.0 +mod_version=0.2.20.0 immersive_portals_version=6.0.7 # 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. diff --git a/src/main/java/net/dnorberg/rivencraft/book/AgeDefinition.java b/src/main/java/net/dnorberg/rivencraft/book/AgeDefinition.java index e2f3631..4ff9189 100644 --- a/src/main/java/net/dnorberg/rivencraft/book/AgeDefinition.java +++ b/src/main/java/net/dnorberg/rivencraft/book/AgeDefinition.java @@ -21,7 +21,7 @@ public record AgeDefinition( public static final ResourceLocation RANDOM_VANILLA_PROFILE = ResourceLocation.fromNamespaceAndPath( Rivencraft.MOD_ID, "random_vanilla" ); - public static final int CURRENT_GENERATION_VERSION = 5; + public static final int CURRENT_GENERATION_VERSION = 6; public AgeDefinition { Objects.requireNonNull(id, "id"); diff --git a/src/main/java/net/dnorberg/rivencraft/book/AgeDimensionService.java b/src/main/java/net/dnorberg/rivencraft/book/AgeDimensionService.java index b45db4a..1298055 100644 --- a/src/main/java/net/dnorberg/rivencraft/book/AgeDimensionService.java +++ b/src/main/java/net/dnorberg/rivencraft/book/AgeDimensionService.java @@ -46,11 +46,14 @@ public final class AgeDimensionService { DynamicDimensionLoadCallback.register((server, loader) -> { ServerLevel overworld = server.overworld(); for (AgeDefinition age : AgeRegistrySavedData.get(overworld).definitions()) { - loader.loadDynamicDimension( + ServerLevel level = loader.loadDynamicDimension( age.dimensionId(), createGenerator(server, age), createDimensionType(age) ); + if (level != null) { + applyCelestialClock(level, age); + } } synchronizeImmersivePortals(server); }); @@ -65,6 +68,7 @@ public final class AgeDimensionService { BlockPos spawn = definition.spawn(); if (spawn == null) { + applyInitialCelestialPhase(level, definition); spawn = createSafeSpawn(level, definition); definition = AgeRegistrySavedData.get(level).setSpawn(definition.id(), spawn); } @@ -79,6 +83,7 @@ public final class AgeDimensionService { ResourceKey key = dimensionKey(definition); ServerLevel existing = server.getLevel(key); if (existing != null) { + applyCelestialClock(existing, definition); return existing; } @@ -91,11 +96,21 @@ public final class AgeDimensionService { if (loaded == null) { Rivencraft.LOGGER.error("Failed to load Age {} as {}", definition.id(), definition.dimensionId()); } else { + applyCelestialClock(loaded, definition); synchronizeImmersivePortals(server); } return loaded; } + private static void applyCelestialClock(ServerLevel level, AgeDefinition age) { + level.setDayTimePerTick((float)(1.0D / age.traits().celestialPeriod())); + } + + private static void applyInitialCelestialPhase(ServerLevel level, AgeDefinition age) { + long phaseTime = (long)(age.traits().celestialPhase() * Level.TICKS_PER_DAY); + level.setDayTime(phaseTime); + } + private static void synchronizeImmersivePortals(MinecraftServer server) { if (ModList.get().isLoaded("immersive_portals_core")) { ImmersivePortalsChunkLoaders.dimensionsChanged(server); diff --git a/src/main/java/net/dnorberg/rivencraft/gametest/LinkingGameTests.java b/src/main/java/net/dnorberg/rivencraft/gametest/LinkingGameTests.java index f03c3e7..ab9ed1d 100644 --- a/src/main/java/net/dnorberg/rivencraft/gametest/LinkingGameTests.java +++ b/src/main/java/net/dnorberg/rivencraft/gametest/LinkingGameTests.java @@ -186,6 +186,9 @@ public final class LinkingGameTests { ? 0.25F : 0.0F; helper.assertTrue(Math.abs(level.dimensionType().ambientLight() - expectedAmbientLight) < 0.0001F, "The runtime dimension must apply the persisted lighting trait"); + float expectedDaySpeed = (float)(1.0D / definition.traits().celestialPeriod()); + helper.assertTrue(Math.abs(level.getDayTimePerTick() - expectedDaySpeed) < 0.0001F, + "The runtime dimension must apply the persisted celestial period"); } helper.succeed(); }