Public Access
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
24b60706b0 |
No files matched your search
@@ -77,6 +77,9 @@ view. Without either integration, Rivencraft uses its built-in animated linking
|
|||||||
panel. Clients can set `book_preview.mode` in
|
panel. Clients can set `book_preview.mode` in
|
||||||
`rivencraft-client.toml` to `AUTO`, `IMMERSIVE_PORTALS`, `PONDER`, or `LEGACY`.
|
`rivencraft-client.toml` to `AUTO`, `IMMERSIVE_PORTALS`, `PONDER`, or `LEGACY`.
|
||||||
Unavailable optional renderers safely fall back to `LEGACY`.
|
Unavailable optional renderers safely fall back to `LEGACY`.
|
||||||
|
The complete backend matrix, supported combinations, cleanup behavior, and
|
||||||
|
known upstream limits are documented in
|
||||||
|
[docs/PREVIEW_COMPATIBILITY.md](docs/PREVIEW_COMPATIBILITY.md).
|
||||||
|
|
||||||
## Build and run
|
## Build and run
|
||||||
|
|
||||||
|
|||||||
+3
-1
@@ -53,7 +53,9 @@ documented in [AGE_PROFILES.md](AGE_PROFILES.md).
|
|||||||
The core mod must remain usable without Create, Ponder, or Immersive Portals.
|
The core mod must remain usable without Create, Ponder, or Immersive Portals.
|
||||||
The built-in legacy animation is the dependency-free destination preview.
|
The built-in legacy animation is the dependency-free destination preview.
|
||||||
Optional preview modes may use Create/Ponder snapshots or Immersive Portals
|
Optional preview modes may use Create/Ponder snapshots or Immersive Portals
|
||||||
live rendering when their dependencies are installed.
|
live rendering when their dependencies are installed. The tested selection
|
||||||
|
matrix and integration boundaries are documented in
|
||||||
|
[PREVIEW_COMPATIBILITY.md](PREVIEW_COMPATIBILITY.md).
|
||||||
|
|
||||||
The writing system and Age grammar will build on the existing page-free Age
|
The writing system and Age grammar will build on the existing page-free Age
|
||||||
path. Page-free books remain a useful deterministic fallback and test fixture
|
path. Page-free books remain a useful deterministic fallback and test fixture
|
||||||
|
|||||||
@@ -0,0 +1,78 @@
|
|||||||
|
# Destination preview compatibility
|
||||||
|
|
||||||
|
Rivencraft has three destination preview backends. The selected backend is a
|
||||||
|
client presentation detail; the server validates travel and Age generation is
|
||||||
|
independent of every preview integration.
|
||||||
|
|
||||||
|
## Selection matrix
|
||||||
|
|
||||||
|
Set `book_preview.mode` in `rivencraft-client.toml`.
|
||||||
|
|
||||||
|
| Configured mode | Immersive Portals installed | Create/Ponder installed | Selected backend |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| `AUTO` | yes | either | Immersive Portals |
|
||||||
|
| `AUTO` | no | yes | Ponder snapshot |
|
||||||
|
| `AUTO` | no | no | built-in legacy animation |
|
||||||
|
| `IMMERSIVE_PORTALS` | yes | either | Immersive Portals |
|
||||||
|
| `IMMERSIVE_PORTALS` | no | either | built-in legacy animation |
|
||||||
|
| `PONDER` | either | yes | Ponder snapshot |
|
||||||
|
| `PONDER` | either | no | built-in legacy animation |
|
||||||
|
| `LEGACY` | either | either | built-in legacy animation |
|
||||||
|
|
||||||
|
Explicit optional modes fall back directly to `LEGACY`. They do not silently
|
||||||
|
select the other optional integration. GameTests exercise every row and every
|
||||||
|
dependency-presence permutation.
|
||||||
|
|
||||||
|
## Book behavior
|
||||||
|
|
||||||
|
Held Linking and Descriptive Books render the selected backend in the preview
|
||||||
|
panel. Immersive Portals additionally exposes **Explore**: the player remains
|
||||||
|
at the opening position, mouse look controls the remote camera, and
|
||||||
|
right-click returns to the standard book view.
|
||||||
|
|
||||||
|
Books on a Book Stand use the same preview panel, but Explore is disabled so
|
||||||
|
the player cannot move away and leave a remote preview session owned by the
|
||||||
|
stand screen. Closing either screen releases its server chunk loader. Linking,
|
||||||
|
disconnecting, unloading the destination Age, and stopping the server also
|
||||||
|
release affected loaders.
|
||||||
|
|
||||||
|
The Immersive Portals backend force-loads the initial 3 by 3 destination area
|
||||||
|
before registering its wider preview chunk loader. The Ponder backend clears
|
||||||
|
the previous snapshot before applying replacement block data. The live backend
|
||||||
|
clears its framebuffer on each render and restores the Minecraft viewport
|
||||||
|
afterward. These rules prevent stale snapshot frames and book UI elements from
|
||||||
|
being captured in the preview.
|
||||||
|
|
||||||
|
## Supported combinations and upstream limits
|
||||||
|
|
||||||
|
The compatibility baseline is Minecraft 1.21.1, NeoForge 21.1.251, Create
|
||||||
|
6.0.10, and Immersive Portals 6.0.7. Core Age generation and the `LEGACY`
|
||||||
|
backend run without Create or Immersive Portals; the headless GameTest server
|
||||||
|
uses that dependency-free path.
|
||||||
|
|
||||||
|
Immersive Portals 6.0.7 is incompatible with Sodium 0.8.13 for Minecraft
|
||||||
|
1.21.1: its Sodium compatibility mixin references the removed
|
||||||
|
`OcclusionCuller.Visitor` class and crashes while entering a world. Sodium
|
||||||
|
0.6.13 avoids that specific mixin failure. This compatibility boundary belongs
|
||||||
|
to Immersive Portals and Sodium, before Rivencraft's preview code runs.
|
||||||
|
|
||||||
|
Immersive Portals reports that some Create contraptions can be invisible when
|
||||||
|
the two mods are installed together. Rivencraft does not replace either mod's
|
||||||
|
world or contraption renderer, so this remains an upstream rendering limit.
|
||||||
|
The `PONDER` or `LEGACY` mode is the supported fallback when live rendering is
|
||||||
|
unstable in a particular graphics or mod configuration.
|
||||||
|
|
||||||
|
## Release verification
|
||||||
|
|
||||||
|
For preview-related releases:
|
||||||
|
|
||||||
|
1. Run `./gradlew runGameTestServer` to verify the complete selection matrix,
|
||||||
|
core Age creation, persistence, and travel without optional renderers.
|
||||||
|
2. Open held Linking and Descriptive Books once with each available backend.
|
||||||
|
3. Open both book types from a Book Stand and confirm Explore is disabled.
|
||||||
|
4. With Immersive Portals, enter and leave Explore, travel between dimensions,
|
||||||
|
close the screen, and disconnect; confirm destination chunks render and no
|
||||||
|
preview loader remains active.
|
||||||
|
5. With Ponder, reopen different destinations and confirm the previous
|
||||||
|
snapshot does not bleed into the next one.
|
||||||
|
|
||||||
+1
-1
@@ -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.
|
# 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
|
mod_license=LGPL-3.0-or-later
|
||||||
# The mod version. Rivencraft uses the x.y.z.b policy documented in README.md.
|
# The mod version. Rivencraft uses the x.y.z.b policy documented in README.md.
|
||||||
mod_version=0.2.28.0
|
mod_version=0.2.29.0
|
||||||
immersive_portals_version=6.0.7
|
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.
|
# 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.
|
# This should match the base package used for the mod sources.
|
||||||
|
|||||||
+2
-24
@@ -1,44 +1,22 @@
|
|||||||
package net.dnorberg.rivencraft.client.preview;
|
package net.dnorberg.rivencraft.client.preview;
|
||||||
|
|
||||||
import net.dnorberg.rivencraft.config.RivencraftClientConfig;
|
import net.dnorberg.rivencraft.config.RivencraftClientConfig;
|
||||||
|
import net.dnorberg.rivencraft.compat.PreviewBackendSelector;
|
||||||
import net.neoforged.fml.ModList;
|
import net.neoforged.fml.ModList;
|
||||||
|
|
||||||
/** Selects the configured destination preview while keeping optional integrations optional. */
|
/** Selects the configured destination preview while keeping optional integrations optional. */
|
||||||
public final class DestinationPreviewRenderers {
|
public final class DestinationPreviewRenderers {
|
||||||
private enum Backend {
|
|
||||||
IMMERSIVE_PORTALS,
|
|
||||||
PONDER,
|
|
||||||
LEGACY
|
|
||||||
}
|
|
||||||
|
|
||||||
private DestinationPreviewRenderers() {
|
private DestinationPreviewRenderers() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static DestinationPreviewRenderer create() {
|
public static DestinationPreviewRenderer create() {
|
||||||
boolean ponderAvailable = ModList.get().isLoaded("create");
|
boolean ponderAvailable = ModList.get().isLoaded("create");
|
||||||
// The mode and priority are established before the optional IP renderer
|
|
||||||
// lands, so selecting it currently follows the documented safe fallback.
|
|
||||||
boolean immersivePortalsAvailable = ModList.get().isLoaded("immersive_portals_core");
|
boolean immersivePortalsAvailable = ModList.get().isLoaded("immersive_portals_core");
|
||||||
return switch (selectBackend(
|
return switch (PreviewBackendSelector.select(
|
||||||
RivencraftClientConfig.previewMode(), immersivePortalsAvailable, ponderAvailable)) {
|
RivencraftClientConfig.previewMode(), immersivePortalsAvailable, ponderAvailable)) {
|
||||||
case IMMERSIVE_PORTALS -> new ImmersivePortalsDestinationPreviewRenderer();
|
case IMMERSIVE_PORTALS -> new ImmersivePortalsDestinationPreviewRenderer();
|
||||||
case PONDER -> new PonderDestinationPreviewRenderer();
|
case PONDER -> new PonderDestinationPreviewRenderer();
|
||||||
case LEGACY -> new LegacyDestinationPreviewRenderer();
|
case LEGACY -> new LegacyDestinationPreviewRenderer();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Backend selectBackend(
|
|
||||||
RivencraftClientConfig.PreviewMode mode,
|
|
||||||
boolean immersivePortalsAvailable,
|
|
||||||
boolean ponderAvailable
|
|
||||||
) {
|
|
||||||
return switch (mode) {
|
|
||||||
case AUTO -> immersivePortalsAvailable
|
|
||||||
? Backend.IMMERSIVE_PORTALS
|
|
||||||
: ponderAvailable ? Backend.PONDER : Backend.LEGACY;
|
|
||||||
case IMMERSIVE_PORTALS -> immersivePortalsAvailable ? Backend.IMMERSIVE_PORTALS : Backend.LEGACY;
|
|
||||||
case PONDER -> ponderAvailable ? Backend.PONDER : Backend.LEGACY;
|
|
||||||
case LEGACY -> Backend.LEGACY;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
package net.dnorberg.rivencraft.compat;
|
||||||
|
|
||||||
|
import net.dnorberg.rivencraft.config.RivencraftClientConfig;
|
||||||
|
|
||||||
|
/** Pure selection policy for optional destination preview integrations. */
|
||||||
|
public final class PreviewBackendSelector {
|
||||||
|
public enum Backend {
|
||||||
|
IMMERSIVE_PORTALS,
|
||||||
|
PONDER,
|
||||||
|
LEGACY
|
||||||
|
}
|
||||||
|
|
||||||
|
private PreviewBackendSelector() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Backend select(
|
||||||
|
RivencraftClientConfig.PreviewMode mode,
|
||||||
|
boolean immersivePortalsAvailable,
|
||||||
|
boolean ponderAvailable
|
||||||
|
) {
|
||||||
|
return switch (mode) {
|
||||||
|
case AUTO -> immersivePortalsAvailable
|
||||||
|
? Backend.IMMERSIVE_PORTALS
|
||||||
|
: ponderAvailable ? Backend.PONDER : Backend.LEGACY;
|
||||||
|
case IMMERSIVE_PORTALS -> immersivePortalsAvailable ? Backend.IMMERSIVE_PORTALS : Backend.LEGACY;
|
||||||
|
case PONDER -> ponderAvailable ? Backend.PONDER : Backend.LEGACY;
|
||||||
|
case LEGACY -> Backend.LEGACY;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -12,6 +12,8 @@ import net.dnorberg.rivencraft.book.LinkTarget;
|
|||||||
import net.dnorberg.rivencraft.book.LinkingService;
|
import net.dnorberg.rivencraft.book.LinkingService;
|
||||||
import net.dnorberg.rivencraft.book.AgeVisitSavedData;
|
import net.dnorberg.rivencraft.book.AgeVisitSavedData;
|
||||||
import net.dnorberg.rivencraft.book.AgeTraits;
|
import net.dnorberg.rivencraft.book.AgeTraits;
|
||||||
|
import net.dnorberg.rivencraft.compat.PreviewBackendSelector;
|
||||||
|
import net.dnorberg.rivencraft.config.RivencraftClientConfig;
|
||||||
import net.dnorberg.rivencraft.item.DescriptiveBookItem;
|
import net.dnorberg.rivencraft.item.DescriptiveBookItem;
|
||||||
import net.dnorberg.rivencraft.item.LinkingBookItem;
|
import net.dnorberg.rivencraft.item.LinkingBookItem;
|
||||||
import net.dnorberg.rivencraft.registry.ModDataComponents;
|
import net.dnorberg.rivencraft.registry.ModDataComponents;
|
||||||
@@ -40,6 +42,53 @@ public final class LinkingGameTests {
|
|||||||
private LinkingGameTests() {
|
private LinkingGameTests() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@GameTest(template = "empty")
|
||||||
|
public static void previewBackendSelectionCoversOptionalDependencyMatrix(GameTestHelper helper) {
|
||||||
|
assertPreviewBackend(helper, RivencraftClientConfig.PreviewMode.AUTO, true, true,
|
||||||
|
PreviewBackendSelector.Backend.IMMERSIVE_PORTALS);
|
||||||
|
assertPreviewBackend(helper, RivencraftClientConfig.PreviewMode.AUTO, true, false,
|
||||||
|
PreviewBackendSelector.Backend.IMMERSIVE_PORTALS);
|
||||||
|
assertPreviewBackend(helper, RivencraftClientConfig.PreviewMode.AUTO, false, true,
|
||||||
|
PreviewBackendSelector.Backend.PONDER);
|
||||||
|
assertPreviewBackend(helper, RivencraftClientConfig.PreviewMode.AUTO, false, false,
|
||||||
|
PreviewBackendSelector.Backend.LEGACY);
|
||||||
|
|
||||||
|
for (boolean ponderAvailable : new boolean[] {false, true}) {
|
||||||
|
assertPreviewBackend(helper, RivencraftClientConfig.PreviewMode.IMMERSIVE_PORTALS, true,
|
||||||
|
ponderAvailable, PreviewBackendSelector.Backend.IMMERSIVE_PORTALS);
|
||||||
|
assertPreviewBackend(helper, RivencraftClientConfig.PreviewMode.IMMERSIVE_PORTALS, false,
|
||||||
|
ponderAvailable, PreviewBackendSelector.Backend.LEGACY);
|
||||||
|
}
|
||||||
|
for (boolean immersivePortalsAvailable : new boolean[] {false, true}) {
|
||||||
|
assertPreviewBackend(helper, RivencraftClientConfig.PreviewMode.PONDER,
|
||||||
|
immersivePortalsAvailable, true, PreviewBackendSelector.Backend.PONDER);
|
||||||
|
assertPreviewBackend(helper, RivencraftClientConfig.PreviewMode.PONDER,
|
||||||
|
immersivePortalsAvailable, false, PreviewBackendSelector.Backend.LEGACY);
|
||||||
|
}
|
||||||
|
for (boolean immersivePortalsAvailable : new boolean[] {false, true}) {
|
||||||
|
for (boolean ponderAvailable : new boolean[] {false, true}) {
|
||||||
|
assertPreviewBackend(helper, RivencraftClientConfig.PreviewMode.LEGACY,
|
||||||
|
immersivePortalsAvailable, ponderAvailable, PreviewBackendSelector.Backend.LEGACY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
helper.succeed();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void assertPreviewBackend(
|
||||||
|
GameTestHelper helper,
|
||||||
|
RivencraftClientConfig.PreviewMode mode,
|
||||||
|
boolean immersivePortalsAvailable,
|
||||||
|
boolean ponderAvailable,
|
||||||
|
PreviewBackendSelector.Backend expected
|
||||||
|
) {
|
||||||
|
helper.assertValueEqual(
|
||||||
|
PreviewBackendSelector.select(mode, immersivePortalsAvailable, ponderAvailable),
|
||||||
|
expected,
|
||||||
|
mode + " selection with Immersive Portals=" + immersivePortalsAvailable
|
||||||
|
+ " and Ponder=" + ponderAvailable
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
@GameTest(template = "empty")
|
@GameTest(template = "empty")
|
||||||
public static void dataPackAgeProfilesResolveRegisteredResources(GameTestHelper helper) {
|
public static void dataPackAgeProfilesResolveRegisteredResources(GameTestHelper helper) {
|
||||||
var registries = helper.getLevel().registryAccess();
|
var registries = helper.getLevel().registryAccess();
|
||||||
|
|||||||
Reference in new issue
Block a user