diff --git a/README.md b/README.md index be26d23..6e9b5b3 100644 --- a/README.md +++ b/README.md @@ -124,14 +124,20 @@ the top or underside of one of its blocks. Insert a bound Linking or Descriptive Book to activate it; the book remains visible on the receptacle. A Linking Book aimed at its own dimension still opens a visual portal, but travel requires Intra Linking. -Sky writing includes eight color pages and a Static Sky page. Multiple sky-color -pages blend their colors, tinting the Age sky, book preview, and the fallback -surface of portals linked there. Multiple celestial-color pages blend for the -next written sun or moon. An Age may have no suns or moons at all; -Static Sky animates the sky with television-like noise. Sun and Moon pages add +Sky writing has shared Red, Green, Blue, White, and Black pages plus 25 D'ni +number pages (0–24). Put colors before a Sky, Sun, or Moon page to color that +target; trailing colors tint the sky. A number immediately before a color sets +its strength to number × 10. Without a number, a color gets a seeded random +strength from 0–24. RGB contributions add in any order, White brightens all +channels, Black subtracts from all channels, and omitted channels remain zero. +The resulting sky color also tints book previews and fallback portal surfaces. +An Age may have no suns or moons at all; Static Sky animates with fine-grained +television-like noise. Sun and Moon pages add independent bodies; preceding color, size, angle, period, phase, and direction pages configure the next body. The third and each subsequent sun add increasing -instability. Newly generated page-free Ages also choose a deterministic sky, +instability. Overlapping moon and sun discs produce an eclipse: the moon darkens, +the sun's color brightens at close alignment, and world and sky lighting dim. +Newly generated page-free Ages also choose a deterministic sky, color, and celestial arrangement from their Age seed; older saved Ages retain their previous sky. diff --git a/dev images/Pasted image (2).png b/dev images/Pasted image (2).png deleted file mode 100644 index 3bcb9ae..0000000 Binary files a/dev images/Pasted image (2).png and /dev/null differ diff --git a/dev images/Pasted image.png b/dev images/Pasted image.png new file mode 100644 index 0000000..5ff9f55 Binary files /dev/null and b/dev images/Pasted image.png differ diff --git a/gradle.properties b/gradle.properties index b2894e0..231477f 100644 --- a/gradle.properties +++ b/gradle.properties @@ -36,7 +36,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.6.8.7 +mod_version=0.6.8.10 immersive_portals_version=6.0.7 terrablender_version=4.1.0.8 serene_seasons_version_id=pHEgQQUE diff --git a/src/main/java/net/dnorberg/rivencraft/book/AgeEnvironmentCompiler.java b/src/main/java/net/dnorberg/rivencraft/book/AgeEnvironmentCompiler.java index 82eb609..8f116a5 100644 --- a/src/main/java/net/dnorberg/rivencraft/book/AgeEnvironmentCompiler.java +++ b/src/main/java/net/dnorberg/rivencraft/book/AgeEnvironmentCompiler.java @@ -108,11 +108,7 @@ public final class AgeEnvironmentCompiler { /** An authored color is fixed; -1 means the biome or selected vanilla sky supplies it. */ public static int skyColor(AgeGenerationPlan plan) { - if (plan == null) return -1; - return AgeSkyProfile.mixColors(plan.activeSymbols().stream() - .filter(symbol -> symbol.semantics().role() == SymbolSemantics.Role.SKY_COLOR) - .map(symbol -> ((SymbolSemantics.ChoiceValue) symbol.semantics().value()).id()) - .map(AgeSkyProfile::color).toList()); + return AgeSkyProfile.authoredSkyColor(plan); } public static int selectedSkyColor(AgeGenerationPlan plan, ResourceLocation fallback, int biomeSkyColor) { diff --git a/src/main/java/net/dnorberg/rivencraft/book/AgeGenerationPlan.java b/src/main/java/net/dnorberg/rivencraft/book/AgeGenerationPlan.java index d16e993..b847b11 100644 --- a/src/main/java/net/dnorberg/rivencraft/book/AgeGenerationPlan.java +++ b/src/main/java/net/dnorberg/rivencraft/book/AgeGenerationPlan.java @@ -188,7 +188,7 @@ public record AgeGenerationPlan(int version, long ageSeed, OrderedWriting writin String raw = item.getString("Value"); SymbolSemantics.Value value = switch (role) { case TERRAIN, BIOME, BLOCK, FEATURE -> new SymbolSemantics.ResourceValue(ResourceLocation.parse(raw)); - case PERIOD_MODIFIER, ANGLE_MODIFIER, PHASE_MODIFIER, SIZE_MODIFIER -> + case PERIOD_MODIFIER, ANGLE_MODIFIER, PHASE_MODIFIER, SIZE_MODIFIER, COLOR_NUMBER -> new SymbolSemantics.NumberValue(Double.parseDouble(raw)); default -> new SymbolSemantics.ChoiceValue(raw); }; diff --git a/src/main/java/net/dnorberg/rivencraft/book/AgePersistenceGameTests.java b/src/main/java/net/dnorberg/rivencraft/book/AgePersistenceGameTests.java index 3bc3559..8dff0a2 100644 --- a/src/main/java/net/dnorberg/rivencraft/book/AgePersistenceGameTests.java +++ b/src/main/java/net/dnorberg/rivencraft/book/AgePersistenceGameTests.java @@ -125,9 +125,9 @@ public final class AgePersistenceGameTests { new AgeReference(UUID.randomUUID(), "Stable Writing"), stable); AgeDefinition defectiveAge = AgeRegistrySavedData.resolveOrCreate(helper.getLevel(), new AgeReference(UUID.randomUUID(), "Defective Writing"), defective); - helper.assertValueEqual(stableAge.instability().score(), 0, + helper.assertValueEqual(nonCelestialInstability(stableAge), 0, "Missing seeded branches do not add instability"); - helper.assertValueEqual(defectiveAge.instability().score(), 600, + helper.assertValueEqual(nonCelestialInstability(defectiveAge), 600, "Out-of-order and repeated terrain pages each add their saved penalty"); helper.assertTrue(defectiveAge.instability().breakdown().stream() .anyMatch(part -> part.reason().equals("duplicate") && part.pageIndex() == 3), @@ -184,9 +184,9 @@ public final class AgePersistenceGameTests { new AgeReference(UUID.randomUUID(), "Three " + structure), structureWriting(structure, 3)); AgeDefinition four = AgeRegistrySavedData.resolveOrCreate(helper.getLevel(), new AgeReference(UUID.randomUUID(), "Four " + structure), structureWriting(structure, 4)); - helper.assertValueEqual(three.instability().score(), 0, + helper.assertValueEqual(nonCelestialInstability(three), 0, "The first three " + structure + " pages retain Legacy's zero cost"); - helper.assertValueEqual(four.instability().score(), 100, + helper.assertValueEqual(nonCelestialInstability(four), 100, "The fourth " + structure + " page must add Legacy's 100-point cost"); helper.assertTrue(four.instability().breakdown().stream().anyMatch(part -> part.reason().equals("excess_" + structure) && part.pageIndex() == 8), @@ -216,7 +216,7 @@ public final class AgePersistenceGameTests { )); AgeDefinition bright = AgeRegistrySavedData.resolveOrCreate(helper.getLevel(), new AgeReference(UUID.randomUUID(), "Double Bright"), duplicateBright); - helper.assertValueEqual(bright.instability().score(), 1500, + helper.assertValueEqual(nonCelestialInstability(bright), 1500, "Each Bright Lighting page costs 500 and the extra controller costs another 500"); helper.assertValueEqual(bright.instability().breakdown().stream() .filter(part -> part.reason().equals("bright_lighting")).count(), 2L, @@ -420,6 +420,13 @@ public final class AgePersistenceGameTests { helper.succeed(); } + /** Isolate the writing-cost assertion from seed-completed extra-sun instability. */ + private static int nonCelestialInstability(AgeDefinition age) { + return age.instability().breakdown().stream() + .filter(part -> !part.reason().equals("extra_sun")) + .mapToInt(AgeInstability.Contribution::points).sum(); + } + private static CompoundTag entry( UUID id, String name, diff --git a/src/main/java/net/dnorberg/rivencraft/book/AgeSkyProfile.java b/src/main/java/net/dnorberg/rivencraft/book/AgeSkyProfile.java index 56b896f..52a56d6 100644 --- a/src/main/java/net/dnorberg/rivencraft/book/AgeSkyProfile.java +++ b/src/main/java/net/dnorberg/rivencraft/book/AgeSkyProfile.java @@ -48,7 +48,7 @@ public record AgeSkyProfile(Style style, int color, List bodies) { public static AgeSkyProfile compile(AgeGenerationPlan plan, AgeTraits traits) { if (plan == null) return new AgeSkyProfile(Style.INHERITED, -1, List.of()); Style style = Style.INHERITED; - int color = AgeEnvironmentCompiler.skyColor(plan); + int color = authoredSkyColor(plan); boolean customBodies = hasCustomCelestials(plan); List bodies = new ArrayList<>(); Set active = new HashSet<>(plan.activeSymbolIndices()); @@ -58,18 +58,32 @@ public record AgeSkyProfile(Style style, int color, List bodies) { float phase = seeded.celestialPhase(); float size = 1.0F; List bodyColors = new ArrayList<>(); + ColorAccumulator pendingColors = new ColorAccumulator(); + Integer colorMultiplier = null; boolean clockwise = true; for (AgeGenerationPlan.ResolvedSymbol symbol : plan.symbols()) { if (!active.contains(symbol.index())) continue; SymbolSemantics semantics = symbol.semantics(); + if (semantics.role() != SymbolSemantics.Role.COLOR + && semantics.role() != SymbolSemantics.Role.COLOR_NUMBER) colorMultiplier = null; switch (semantics.role()) { - case SKY -> style = switch (((SymbolSemantics.ChoiceValue) semantics.value()).id()) { - case "overworld" -> Style.OVERWORLD; - case "nether" -> Style.NETHER; - case "end" -> Style.END; - case "static" -> Style.STATIC; - default -> throw new IllegalArgumentException("Unknown sky style"); - }; + case SKY -> { + pendingColors.clear(); + style = switch (((SymbolSemantics.ChoiceValue) semantics.value()).id()) { + case "overworld" -> Style.OVERWORLD; + case "nether" -> Style.NETHER; + case "end" -> Style.END; + case "static" -> Style.STATIC; + default -> throw new IllegalArgumentException("Unknown sky style"); + }; + } + case COLOR_NUMBER -> colorMultiplier = (int) ((SymbolSemantics.NumberValue) + semantics.value()).amount(); + case COLOR -> { + pendingColors.add(((SymbolSemantics.ChoiceValue) semantics.value()).id(), + colorMultiplier == null ? randomColorNumber(plan.ageSeed(), symbol.index()) : colorMultiplier); + colorMultiplier = null; + } case PERIOD_MODIFIER -> period = ((SymbolSemantics.NumberValue) semantics.value()).amount(); case ANGLE_MODIFIER -> angle = (float) ((SymbolSemantics.NumberValue) semantics.value()).amount(); case PHASE_MODIFIER -> phase = (float) (((SymbolSemantics.NumberValue) semantics.value()).amount() / 360.0D); @@ -80,7 +94,8 @@ public record AgeSkyProfile(Style style, int color, List bodies) { .id().equals("clockwise"); case CELESTIAL -> { String choice = ((SymbolSemantics.ChoiceValue) semantics.value()).id(); - int bodyColor = bodyColors.isEmpty() ? 0xFFFFFF : mixColors(bodyColors); + int bodyColor = pendingColors.written() ? pendingColors.rgb() + : bodyColors.isEmpty() ? 0 : mixColors(bodyColors); if (choice.equals("normal_time")) { if (customBodies) { bodies.add(new Body(Kind.SUN, bodyColor, size, angle, period, phase, clockwise)); @@ -96,6 +111,7 @@ public record AgeSkyProfile(Style style, int color, List bodies) { phase = seeded.celestialPhase(); size = 1.0F; bodyColors.clear(); + pendingColors.clear(); clockwise = true; } default -> { } @@ -124,6 +140,74 @@ public record AgeSkyProfile(Style style, int color, List bodies) { | (int) ((blue + count / 2) / count); } + /** Shared color pages affect the next Sky or celestial page; trailing colors tint the sky. */ + public static int authoredSkyColor(AgeGenerationPlan plan) { + if (plan == null) return -1; + ColorAccumulator pending = new ColorAccumulator(); + Integer multiplier = null; + int skyColor = -1; + List legacyColors = new ArrayList<>(); + Set active = new HashSet<>(plan.activeSymbolIndices()); + for (AgeGenerationPlan.ResolvedSymbol symbol : plan.symbols()) { + if (!active.contains(symbol.index())) continue; + SymbolSemantics semantics = symbol.semantics(); + if (semantics.role() != SymbolSemantics.Role.COLOR + && semantics.role() != SymbolSemantics.Role.COLOR_NUMBER) multiplier = null; + switch (semantics.role()) { + case COLOR_NUMBER -> multiplier = (int) ((SymbolSemantics.NumberValue) semantics.value()).amount(); + case COLOR -> { + pending.add(((SymbolSemantics.ChoiceValue) semantics.value()).id(), + multiplier == null ? randomColorNumber(plan.ageSeed(), symbol.index()) : multiplier); + multiplier = null; + } + case SKY -> { + if (pending.written()) skyColor = pending.rgb(); + pending.clear(); + } + case CELESTIAL -> pending.clear(); + case SKY_COLOR -> legacyColors.add(color( + ((SymbolSemantics.ChoiceValue) semantics.value()).id())); + default -> { } + } + } + if (pending.written()) skyColor = pending.rgb(); + return skyColor != -1 ? skyColor : mixColors(legacyColors); + } + + private static int randomColorNumber(long ageSeed, int pageIndex) { + return new Random(ageSeed ^ (0x9E3779B97F4A7C15L * (pageIndex + 1L))).nextInt(25); + } + + private static final class ColorAccumulator { + private int red; + private int green; + private int blue; + private boolean written; + + void add(String color, int multiplier) { + int amount = multiplier * 10; + written = true; + switch (color) { + case "red" -> red += amount; + case "green" -> green += amount; + case "blue" -> blue += amount; + case "white" -> { red += amount; green += amount; blue += amount; } + case "black" -> { red -= amount; green -= amount; blue -= amount; } + default -> throw new IllegalArgumentException("Unknown shared color " + color); + } + } + + boolean written() { return written; } + + int rgb() { + return clamp(red) << 16 | clamp(green) << 8 | clamp(blue); + } + + void clear() { red = green = blue = 0; written = false; } + + private static int clamp(int channel) { return Math.max(0, Math.min(255, channel)); } + } + private static int randomColor(Random random) { int count = 1 + random.nextInt(3); List colors = new ArrayList<>(count); @@ -132,12 +216,30 @@ public record AgeSkyProfile(Style style, int color, List bodies) { } public static boolean hasCustomCelestials(AgeGenerationPlan plan) { - return plan != null && plan.activeSymbols().stream().anyMatch(symbol -> + return plan != null && (hasColorForCelestial(plan) || plan.activeSymbols().stream().anyMatch(symbol -> symbol.semantics().role() == SymbolSemantics.Role.CELESTIAL && !((SymbolSemantics.ChoiceValue) symbol.semantics().value()).id().equals("normal_time") || symbol.semantics().role() == SymbolSemantics.Role.CELESTIAL_COLOR || symbol.semantics().role() == SymbolSemantics.Role.SIZE_MODIFIER - || symbol.semantics().role() == SymbolSemantics.Role.DIRECTION_MODIFIER); + || symbol.semantics().role() == SymbolSemantics.Role.DIRECTION_MODIFIER)); + } + + private static boolean hasColorForCelestial(AgeGenerationPlan plan) { + Set active = new HashSet<>(plan.activeSymbolIndices()); + boolean pending = false; + for (AgeGenerationPlan.ResolvedSymbol symbol : plan.symbols()) { + if (!active.contains(symbol.index())) continue; + switch (symbol.semantics().role()) { + case COLOR -> pending = true; + case SKY -> pending = false; + case CELESTIAL -> { + if (pending) return true; + pending = false; + } + default -> { } + } + } + return false; } public boolean custom() { @@ -154,12 +256,53 @@ public record AgeSkyProfile(Style style, int color, List bodies) { / (24000.0D * body.period()) + body.phase(); float altitude = (float) Math.cos(orbit * Math.PI * 2.0D); if (altitude <= 0.0F) continue; - if (body.kind() == Kind.SUN) sunlight += altitude; + if (body.kind() == Kind.SUN) sunlight += altitude * (1.0F - 0.85F * eclipseFor(body, dayTime)); else moonlight += altitude * 0.18F; } return Math.min(1.0F, sunlight > 0.0F ? sunlight : moonlight); } + /** Disc overlap in the rendered sky, from first contact (0) to centered alignment (1). */ + public float eclipseFor(Body body, double dayTime) { + float strongest = 0.0F; + net.minecraft.world.phys.Vec3 bodyDirection = direction(body, dayTime); + for (Body other : bodies) { + if (other.kind() == body.kind()) continue; + double dot = Math.max(-1.0D, Math.min(1.0D, + bodyDirection.dot(direction(other, dayTime)))); + double separation = Math.acos(dot); + // The outer 32x32 quad is only glow. The opaque body occupies its + // central 8x8 pixels, so contact must use one quarter of its size. + double radius = Math.atan((body.kind() == Kind.SUN ? 30.0D : 20.0D) + * body.size() * 0.25D / 100.0D) + + Math.atan((other.kind() == Kind.SUN ? 30.0D : 20.0D) + * other.size() * 0.25D / 100.0D); + if (radius > 0.0D) strongest = Math.max(strongest, + (float) Math.max(0.0D, 1.0D - separation / radius)); + } + return strongest; + } + + public float eclipseAt(double dayTime) { + float strongest = 0.0F; + for (Body body : bodies) { + if (body.kind() == Kind.SUN && direction(body, dayTime).y > 0.0D) + strongest = Math.max(strongest, eclipseFor(body, dayTime)); + } + return strongest; + } + + private static net.minecraft.world.phys.Vec3 direction(Body body, double dayTime) { + double orbit = body.period() == 0.0D ? body.phase() + : (body.clockwise() ? 1.0D : -1.0D) * dayTime + / (24000.0D * body.period()) + body.phase(); + double tilt = orbit * Math.PI * 2.0D; + double bearing = Math.toRadians(body.angle()); + double lateral = Math.sin(tilt); + return new net.minecraft.world.phys.Vec3( + Math.sin(bearing) * lateral, Math.cos(tilt), Math.cos(bearing) * lateral); + } + public static int color(String name) { return switch (name) { case "red" -> COLORS[0]; diff --git a/src/main/java/net/dnorberg/rivencraft/book/EnvironmentWritingGameTests.java b/src/main/java/net/dnorberg/rivencraft/book/EnvironmentWritingGameTests.java index 3fa92d2..ec2b893 100644 --- a/src/main/java/net/dnorberg/rivencraft/book/EnvironmentWritingGameTests.java +++ b/src/main/java/net/dnorberg/rivencraft/book/EnvironmentWritingGameTests.java @@ -52,10 +52,11 @@ public final class EnvironmentWritingGameTests { public static void environmentPagesEnterCreativeAndJeiFeed(GameTestHelper helper) { Set expected = Set.of( "lighting/normal", "lighting/dark", "lighting/bright", - "sky/overworld", "sky/nether", "sky/end", "sky/static", "sky_color/purple", + "sky/overworld", "sky/nether", "sky/end", "sky/static", "color/red", "color/green", + "color/blue", "color/black", "color/white", "number/0", "number/24", "weather/normal", "weather/fast", "weather/slow", "weather/off", "weather/always", "weather/storm", "celestial/normal_time", "celestial/sun", - "celestial/moon", "celestial_color/red", "size/large", "angle/east", + "celestial/moon", "size/large", "angle/east", "direction/clockwise", "direction/counterclockwise", "season/no_seasons", "season/seasons", "season/eternal_winter", "season/eternal_summer", "season/eternal_fall", "season/eternal_spring", @@ -69,6 +70,9 @@ public final class EnvironmentWritingGameTests { helper.assertTrue(PageItem.bundledCreativeSymbols().containsAll(expected) && creative.containsAll(expected), "Every supported environment page must enter the creative index JEI also consumes"); + helper.assertValueEqual(PageItem.bundledCreativeSymbols().stream() + .filter(path -> path.startsWith("number/")).count(), 25L, + "Creative and JEI must expose all 25 D'ni number pages"); for (String path : expected) { var id = ResourceLocation.fromNamespaceAndPath("rivencraft", path); helper.assertTrue(SymbolCatalog.isKnown(new SymbolReference(id)) @@ -140,8 +144,8 @@ public final class EnvironmentWritingGameTests { @GameTest(template = "empty") public static void authoredStaticSkyColorSurvivesWritingAndFeedsPreview(GameTestHelper helper) { OrderedWriting writing = new OrderedWriting(List.of( - WritingEntry.linkPanel(), page("terrain/standard"), page("sky/static"), - page("sky_color/purple"), page("celestial/normal_time"))); + WritingEntry.linkPanel(), page("terrain/standard"), page("number/20"), + page("color/blue"), page("sky/static"), page("celestial/normal_time"))); AgeTraits seeded = AgeTraits.select(44L); AgeGenerationPlan plan = AgeGenerationPlan.compile(writing, 44L, AgeGenerationProfiles.STANDARD, seeded, helper.getLevel().registryAccess()); @@ -152,15 +156,15 @@ public final class EnvironmentWritingGameTests { "The static sky must select Rivencraft's custom renderer"); helper.assertValueEqual(AgeEnvironmentCompiler.selectedSkyColor(plan, BuiltinDimensionTypes.OVERWORLD_EFFECTS, 0xFF77AAFF), - 0x9870B9, "The authored color must tint the sky and preview consistently"); + 0x0000C8, "The authored color must tint the sky and preview consistently"); AgeGenerationPlan restored = AgeGenerationPlan.load(plan.save()); helper.assertTrue(AgeEnvironmentCompiler.staticSky(restored), "A saved Age must retain its static sky choice"); - helper.assertValueEqual(AgeEnvironmentCompiler.skyColor(restored), 0x9870B9, + helper.assertValueEqual(AgeEnvironmentCompiler.skyColor(restored), 0x0000C8, "A saved Age must retain its sky color choice"); AgeGenerationPlan coloredEnd = AgeGenerationPlan.compile(new OrderedWriting(List.of( - WritingEntry.linkPanel(), page("terrain/standard"), page("sky/end"), - page("sky_color/red"), page("celestial/normal_time"))), + WritingEntry.linkPanel(), page("terrain/standard"), page("number/15"), + page("color/red"), page("sky/end"), page("celestial/normal_time"))), 45L, AgeGenerationProfiles.STANDARD, AgeTraits.select(45L), helper.getLevel().registryAccess()); helper.assertValueEqual(AgeEnvironmentCompiler.skyEffects(coloredEnd, @@ -169,9 +173,10 @@ public final class EnvironmentWritingGameTests { "A color page must make non-Overworld skies renderable by the custom sky effect"); helper.assertValueEqual(AgeEnvironmentCompiler.selectedSkyColor(coloredEnd, BuiltinDimensionTypes.OVERWORLD_EFFECTS, 0xFF77AAFF), - 0xB74A50, "A color page must override the selected sky type's default tint"); + 0x960000, "A color page must override the selected sky type's default tint"); helper.assertTrue(PageItem.bundledCreativeSymbols().contains("sky/static") - && PageItem.bundledCreativeSymbols().contains("sky_color/purple"), + && PageItem.bundledCreativeSymbols().contains("color/blue") + && PageItem.bundledCreativeSymbols().contains("number/24"), "New sky pages must be available through the Creative and JEI page catalog"); helper.succeed(); } @@ -179,18 +184,17 @@ public final class EnvironmentWritingGameTests { @GameTest(template = "empty") public static void skyAndCelestialColorsBlendWithoutRequiringBodies(GameTestHelper helper) { OrderedWriting writing = new OrderedWriting(List.of( - WritingEntry.linkPanel(), page("terrain/standard"), page("sky/overworld"), - page("sky_color/red"), page("sky_color/blue"), - page("celestial_color/yellow"), page("celestial_color/blue"), page("celestial/sun"))); + WritingEntry.linkPanel(), page("terrain/standard"), + page("number/10"), page("color/red"), page("number/5"), page("color/blue"), + page("sky/overworld"), page("number/12"), page("color/green"), + page("number/7"), page("color/blue"), page("celestial/sun"))); helper.assertTrue(WritingGrammar.parse(writing).canCreate(), "Two sky colors and two colors for one sun must be valid writing"); AgeTraits traits = AgeTraits.select(46L); AgeGenerationPlan plan = AgeGenerationPlan.compile(writing, 46L, AgeGenerationProfiles.STANDARD, traits, helper.getLevel().registryAccess()); - int skyColor = AgeSkyProfile.mixColors(List.of( - AgeSkyProfile.color("red"), AgeSkyProfile.color("blue"))); - int sunColor = AgeSkyProfile.mixColors(List.of( - AgeSkyProfile.color("yellow"), AgeSkyProfile.color("blue"))); + int skyColor = 0x640032; + int sunColor = 0x007846; helper.assertValueEqual(AgeEnvironmentCompiler.skyColor(plan), skyColor, "Sky color pages must blend without discarding either page"); AgeSkyProfile profile = AgeSkyProfile.compile(plan, traits); @@ -206,6 +210,58 @@ public final class EnvironmentWritingGameTests { helper.succeed(); } + @GameTest(template = "empty") + public static void colorNumbersUseDniDigitsAndMissingChannelsRemainZero(GameTestHelper helper) { + OrderedWriting writing = new OrderedWriting(List.of( + WritingEntry.linkPanel(), page("number/12"), page("color/red"), + page("number/5"), page("color/white"), page("number/3"), page("color/black"), + page("sky/overworld"))); + AgeGenerationPlan plan = AgeGenerationPlan.compile(writing, 49L, + AgeGenerationProfiles.STANDARD, AgeTraits.select(49L), helper.getLevel().registryAccess()); + helper.assertValueEqual(AgeEnvironmentCompiler.skyColor(plan), 0x8C1414, + "White adds and Black subtracts from every channel; missing green and blue start at zero"); + helper.assertValueEqual(AgeEnvironmentCompiler.skyColor(AgeGenerationPlan.load(plan.save())), 0x8C1414, + "D'ni color multipliers must remain frozen in a saved Age plan"); + + OrderedWriting unnumbered = new OrderedWriting(List.of( + WritingEntry.linkPanel(), page("color/green"), page("sky/overworld"))); + AgeGenerationPlan randomPlan = AgeGenerationPlan.compile(unnumbered, 50L, + AgeGenerationProfiles.STANDARD, AgeTraits.select(50L), helper.getLevel().registryAccess()); + int color = AgeEnvironmentCompiler.skyColor(randomPlan); + helper.assertTrue((color & 0xFF00FF) == 0 && ((color >> 8) & 255) <= 240 + && ((color >> 8) & 255) % 10 == 0, + "An unnumbered color gets one seeded base-25 digit and leaves omitted channels at zero"); + helper.assertValueEqual(AgeEnvironmentCompiler.skyColor(AgeGenerationPlan.load(randomPlan.save())), color, + "A random color digit must not change when an Age is reloaded"); + helper.succeed(); + } + + @GameTest(template = "empty") + public static void alignedMoonEclipsesSunAndDimsLight(GameTestHelper helper) { + AgeSkyProfile.Body sun = new AgeSkyProfile.Body(AgeSkyProfile.Kind.SUN, + 0xCC8844, 1.0F, 0.0F, 1.0D, 0.0F, true); + AgeSkyProfile.Body moon = new AgeSkyProfile.Body(AgeSkyProfile.Kind.MOON, + 0xFFFFFF, 1.0F, 0.0F, 1.0D, 0.0F, true); + AgeSkyProfile clear = new AgeSkyProfile(AgeSkyProfile.Style.OVERWORLD, 0x6688AA, List.of(sun)); + AgeSkyProfile eclipse = new AgeSkyProfile(AgeSkyProfile.Style.OVERWORLD, 0x6688AA, + List.of(sun, moon)); + helper.assertValueEqual(eclipse.eclipseAt(0.0D), 1.0F, + "Centered sun and moon must produce a full eclipse"); + helper.assertTrue(eclipse.lightAt(0.0D) < clear.lightAt(0.0D), + "An eclipse must dim world skylight, not just the rendered sprites"); + AgeSkyProfile separated = new AgeSkyProfile(AgeSkyProfile.Style.OVERWORLD, 0x6688AA, + List.of(sun, new AgeSkyProfile.Body(AgeSkyProfile.Kind.MOON, + 0xFFFFFF, 1.0F, 0.0F, 1.0D, 0.5F, true))); + helper.assertValueEqual(separated.eclipseAt(0.0D), 0.0F, + "A moon on the far side of the sky must not eclipse the sun"); + AgeSkyProfile glowOnlyOverlap = new AgeSkyProfile(AgeSkyProfile.Style.OVERWORLD, 0x6688AA, + List.of(sun, new AgeSkyProfile.Body(AgeSkyProfile.Kind.MOON, + 0xFFFFFF, 1.0F, 0.0F, 1.0D, 0.04F, true))); + helper.assertValueEqual(glowOnlyOverlap.eclipseAt(0.0D), 0.0F, + "Overlapping glows must not count as an eclipse before the opaque discs touch"); + helper.succeed(); + } + @GameTest(template = "empty") public static void randomAndAuthoredCelestialsKeepIndependentOrbits(GameTestHelper helper) { AgeTraits traits = AgeTraits.select(12345L); @@ -217,7 +273,7 @@ public final class EnvironmentWritingGameTests { "Random Ages must obey the same celestial limits as authored Ages"); OrderedWriting writing = new OrderedWriting(List.of( WritingEntry.linkPanel(), page("terrain/standard"), page("sky/end"), - page("angle/east"), page("direction/counterclockwise"), page("celestial_color/red"), + page("angle/east"), page("direction/counterclockwise"), page("number/24"), page("color/red"), page("size/large"), page("period/half"), page("celestial/sun"), page("direction/clockwise"), page("celestial/moon"))); AgeGenerationPlan plan = AgeGenerationPlan.compile(writing, 12345L, AgeGenerationProfiles.STANDARD, diff --git a/src/main/java/net/dnorberg/rivencraft/client/RivencraftSkyEffects.java b/src/main/java/net/dnorberg/rivencraft/client/RivencraftSkyEffects.java index 3fb3b70..23de6ae 100644 --- a/src/main/java/net/dnorberg/rivencraft/client/RivencraftSkyEffects.java +++ b/src/main/java/net/dnorberg/rivencraft/client/RivencraftSkyEffects.java @@ -1,6 +1,7 @@ package net.dnorberg.rivencraft.client; import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.platform.GlStateManager; import com.mojang.blaze3d.vertex.BufferBuilder; import com.mojang.blaze3d.vertex.BufferUploader; import com.mojang.blaze3d.vertex.DefaultVertexFormat; @@ -22,6 +23,7 @@ import net.minecraft.resources.ResourceLocation; /** An authored sky can use vanilla celestial rendering or Legacy-style moving TV static. */ public final class RivencraftSkyEffects extends DimensionSpecialEffects { private static final int GRID = 16; + private static final int STATIC_GRID = 48; private static final float RADIUS = 100.0F; private static final ResourceLocation SUN = ResourceLocation.withDefaultNamespace("textures/environment/sun.png"); private static final ResourceLocation MOON = ResourceLocation.withDefaultNamespace("textures/environment/moon_phases.png"); @@ -62,6 +64,8 @@ public final class RivencraftSkyEffects extends DimensionSpecialEffects { case STATIC -> 0x929292; default -> level.getBiome(camera.getBlockPosition()).value().getSkyColor(); }; + double time = level.getDayTime() + partialTick; + float eclipseShade = 1.0F - 0.65F * sky.eclipseAt(time); RenderSystem.depthMask(false); RenderSystem.disableCull(); @@ -70,20 +74,21 @@ public final class RivencraftSkyEffects extends DimensionSpecialEffects { FogRenderer.setupNoFog(); BufferBuilder vertices = Tesselator.getInstance().begin( VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_COLOR); + int grid = sky.style() == AgeSkyProfile.Style.STATIC ? STATIC_GRID : GRID; for (int axis = 0; axis < 3; axis++) { for (int sign : new int[]{-1, 1}) { - for (int x = 0; x < GRID; x++) { - for (int y = 0; y < GRID; y++) { + for (int x = 0; x < grid; x++) { + for (int y = 0; y < grid; y++) { int noise = sky.style() == AgeSkyProfile.Style.STATIC ? 65 + random.nextInt(160) : 255; - int red = ((tint >> 16) & 255) * noise / 255; - int green = ((tint >> 8) & 255) * noise / 255; - int blue = (tint & 255) * noise / 255; + int red = (int) (((tint >> 16) & 255) * noise / 255.0F * eclipseShade); + int green = (int) (((tint >> 8) & 255) * noise / 255.0F * eclipseShade); + int blue = (int) ((tint & 255) * noise / 255.0F * eclipseShade); int color = 0xFF000000 | red << 16 | green << 8 | blue; - float left = -RADIUS + x * (2 * RADIUS / GRID); - float right = -RADIUS + (x + 1) * (2 * RADIUS / GRID); - float bottom = -RADIUS + y * (2 * RADIUS / GRID); - float top = -RADIUS + (y + 1) * (2 * RADIUS / GRID); + float left = -RADIUS + x * (2 * RADIUS / grid); + float right = -RADIUS + (x + 1) * (2 * RADIUS / grid); + float bottom = -RADIUS + y * (2 * RADIUS / grid); + float top = -RADIUS + (y + 1) * (2 * RADIUS / grid); vertex(vertices, matrix, axis, sign, left, bottom, color); vertex(vertices, matrix, axis, sign, right, bottom, color); vertex(vertices, matrix, axis, sign, right, top, color); @@ -96,8 +101,11 @@ public final class RivencraftSkyEffects extends DimensionSpecialEffects { if (!sky.bodies().isEmpty()) { RenderSystem.enableBlend(); RenderSystem.defaultBlendFunc(); - double time = level.getGameTime() + partialTick; - for (AgeSkyProfile.Body body : sky.bodies()) drawBody(pose, body, time); + // Draw suns first so an aligned moon can pass visibly in front of them. + for (AgeSkyProfile.Body body : sky.bodies()) + if (body.kind() == AgeSkyProfile.Kind.SUN) drawBody(pose, body, time, sky.eclipseFor(body, time)); + for (AgeSkyProfile.Body body : sky.bodies()) + if (body.kind() == AgeSkyProfile.Kind.MOON) drawBody(pose, body, time, sky.eclipseFor(body, time)); RenderSystem.disableBlend(); } setupFog.run(); @@ -106,7 +114,7 @@ public final class RivencraftSkyEffects extends DimensionSpecialEffects { return true; } - private static void drawBody(PoseStack pose, AgeSkyProfile.Body body, double time) { + private static void drawBody(PoseStack pose, AgeSkyProfile.Body body, double time, float eclipse) { pose.pushPose(); pose.mulPose(Axis.YP.rotationDegrees(body.angle())); double orbit = body.period() == 0 ? body.phase() @@ -115,24 +123,52 @@ public final class RivencraftSkyEffects extends DimensionSpecialEffects { pose.mulPose(Axis.XP.rotationDegrees((float) (orbit * 360.0D))); float size = (body.kind() == AgeSkyProfile.Kind.SUN ? 30.0F : 20.0F) * body.size(); int color = body.color(); + float red = ((color >> 16) & 255) / 255.0F; + float green = ((color >> 8) & 255) / 255.0F; + float blue = (color & 255) / 255.0F; + if (body.kind() == AgeSkyProfile.Kind.MOON) { + red *= 1.0F - eclipse; + green *= 1.0F - eclipse; + blue *= 1.0F - eclipse; + } else { + float corona = (float) Math.pow(eclipse, 8.0D) * 0.8F; + red += (1.0F - red) * corona; + green += (1.0F - green) * corona; + blue += (1.0F - blue) * corona; + } RenderSystem.setShader(GameRenderer::getPositionTexShader); RenderSystem.setShaderTexture(0, body.kind() == AgeSkyProfile.Kind.SUN ? SUN : MOON); - RenderSystem.setShaderColor(((color >> 16) & 255) / 255.0F, - ((color >> 8) & 255) / 255.0F, (color & 255) / 255.0F, 1.0F); + // Vanilla's sun/moon atlases have opaque dark pixels around the bright center. + // Additive blending makes those pixels invisible while retaining the halo. + RenderSystem.blendFunc(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE); + RenderSystem.setShaderColor(red, green, blue, + body.kind() == AgeSkyProfile.Kind.SUN ? 0.84F : 0.88F + 0.12F * eclipse); float uMax = body.kind() == AgeSkyProfile.Kind.SUN ? 1.0F : 0.25F; float vMax = body.kind() == AgeSkyProfile.Kind.SUN ? 1.0F : 0.5F; - BufferBuilder vertices = Tesselator.getInstance().begin(VertexFormat.Mode.QUADS, - DefaultVertexFormat.POSITION_TEX); - Matrix4f matrix = pose.last().pose(); - vertices.addVertex(matrix, -size, RADIUS - 1.0F, -size).setUv(0.0F, 0.0F); - vertices.addVertex(matrix, size, RADIUS - 1.0F, -size).setUv(uMax, 0.0F); - vertices.addVertex(matrix, size, RADIUS - 1.0F, size).setUv(uMax, vMax); - vertices.addVertex(matrix, -size, RADIUS - 1.0F, size).setUv(0.0F, vMax); - BufferUploader.drawWithShader(vertices.buildOrThrow()); + drawTexturedQuad(pose.last().pose(), -size, size, 0.0F, uMax, 0.0F, vMax); + + // The 8x8 center of each 32x32 sprite is the actual body. Draw it last + // with ordinary alpha blending and full opacity so the sky and other + // celestial glows cannot show through it, including during an eclipse. + RenderSystem.defaultBlendFunc(); + RenderSystem.setShaderColor(red, green, blue, 1.0F); + drawTexturedQuad(pose.last().pose(), -size * 0.25F, size * 0.25F, + uMax * 0.375F, uMax * 0.625F, vMax * 0.375F, vMax * 0.625F); RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F); pose.popPose(); } + private static void drawTexturedQuad(Matrix4f matrix, float min, float max, + float uMin, float uMax, float vMin, float vMax) { + BufferBuilder vertices = Tesselator.getInstance().begin(VertexFormat.Mode.QUADS, + DefaultVertexFormat.POSITION_TEX); + vertices.addVertex(matrix, min, RADIUS - 1.0F, min).setUv(uMin, vMin); + vertices.addVertex(matrix, max, RADIUS - 1.0F, min).setUv(uMax, vMin); + vertices.addVertex(matrix, max, RADIUS - 1.0F, max).setUv(uMax, vMax); + vertices.addVertex(matrix, min, RADIUS - 1.0F, max).setUv(uMin, vMax); + BufferUploader.drawWithShader(vertices.buildOrThrow()); + } + private static void vertex(BufferBuilder vertices, Matrix4f matrix, int axis, int sign, float x, float y, int color) { float fixed = sign * RADIUS; diff --git a/src/main/java/net/dnorberg/rivencraft/client/SymbolPageTextures.java b/src/main/java/net/dnorberg/rivencraft/client/SymbolPageTextures.java index 4609632..910b421 100644 --- a/src/main/java/net/dnorberg/rivencraft/client/SymbolPageTextures.java +++ b/src/main/java/net/dnorberg/rivencraft/client/SymbolPageTextures.java @@ -138,6 +138,17 @@ public final class SymbolPageTextures { y * base.getHeight() / SIZE)); } } + String numberPath = id.getPath().startsWith("number/") + ? id.getPath().substring("number/".length()) : ""; + if (id.getNamespace().equals(Rivencraft.MOD_ID) + && numberPath.matches("(?:[0-9]|1[0-9]|2[0-4])")) { + int digit = Integer.parseInt(numberPath); + int glyphSize = item ? GLYPH * ITEM_SYMBOL_SIZE / ICON_SIZE : GLYPH; + int origin = item ? scaleForItem(38) : 38; + for (int component : SymbolNumerals.componentsForDigit(digit)) + blendComponent(image, component, origin, origin, glyphSize); + return image; + } String[] words = poem.isBlank() ? generatedWords(id) : poem.split(" "); int[] offsetsX = {38, 77, 38, 0}; int[] offsetsY = {0, 38, 77, 38}; @@ -146,18 +157,22 @@ public final class SymbolPageTextures { int originX = item ? scaleForItem(offsetsX[word]) : offsetsX[word]; int originY = item ? scaleForItem(offsetsY[word]) : offsetsY[word]; for (int component : glyphs(words[word])) { - for (int y = 0; y < glyphSize; y++) for (int x = 0; x < glyphSize; x++) { - int pixel = components.getPixelRGBA((component % 8) * 64 + x * 64 / glyphSize, - (component / 8) * 64 + y * 64 / glyphSize); - int alpha = pixel >>> 24; - if (alpha != 0) image.blendPixel(originX + x, originY + y, - (alpha << 24) | 0x001A212B); - } + blendComponent(image, component, originX, originY, glyphSize); } } return image; } + private static void blendComponent(NativeImage image, int component, int originX, int originY, int glyphSize) { + for (int y = 0; y < glyphSize; y++) for (int x = 0; x < glyphSize; x++) { + int pixel = components.getPixelRGBA((component % 8) * 64 + x * 64 / glyphSize, + (component / 8) * 64 + y * 64 / glyphSize); + int alpha = pixel >>> 24; + if (alpha != 0) image.blendPixel(originX + x, originY + y, + (alpha << 24) | 0x001A212B); + } + } + private static int scaleForItem(int coordinate) { return SIZE / 2 + Math.round((coordinate - SIZE / 2F) * ITEM_SYMBOL_SIZE / ICON_SIZE); } diff --git a/src/main/java/net/dnorberg/rivencraft/event/AgeCelestialAngleSync.java b/src/main/java/net/dnorberg/rivencraft/event/AgeCelestialAngleSync.java index 8fda11d..15ff1dc 100644 --- a/src/main/java/net/dnorberg/rivencraft/event/AgeCelestialAngleSync.java +++ b/src/main/java/net/dnorberg/rivencraft/event/AgeCelestialAngleSync.java @@ -8,6 +8,7 @@ import net.dnorberg.rivencraft.network.AgeCelestialAnglePayload; import net.minecraft.server.level.ServerPlayer; import net.neoforged.neoforge.event.entity.player.PlayerEvent; import net.neoforged.neoforge.network.PacketDistributor; +import net.neoforged.neoforge.network.registration.NetworkRegistry; /** Sends saved celestial angles when a client joins or enters an Age. */ public final class AgeCelestialAngleSync { @@ -34,6 +35,8 @@ public final class AgeCelestialAngleSync { } public static void send(ServerPlayer player, AgeDefinition age) { + // GameTest mock players (and clients without this channel) cannot receive this payload. + if (!NetworkRegistry.hasChannel(player.connection, AgeCelestialAnglePayload.TYPE.id())) return; PacketDistributor.sendToPlayer(player, new AgeCelestialAnglePayload( AgeDimensionService.dimensionKey(age), age.traits().celestialAngle(), AgeSkyProfile.forAge(age))); diff --git a/src/main/java/net/dnorberg/rivencraft/registry/ModCreativeTabs.java b/src/main/java/net/dnorberg/rivencraft/registry/ModCreativeTabs.java index 8be925c..fecdef8 100644 --- a/src/main/java/net/dnorberg/rivencraft/registry/ModCreativeTabs.java +++ b/src/main/java/net/dnorberg/rivencraft/registry/ModCreativeTabs.java @@ -58,7 +58,7 @@ public final class ModCreativeTabs { .build()); private static final List CATEGORY_ORDER = List.of( - "terrain", "biome", "cave_biome", "biome_generation", "weather", "season", "lighting", "sky", "celestial", "block", "fluid", "feature", "environment", "corrupted"); + "terrain", "biome", "cave_biome", "biome_generation", "weather", "season", "lighting", "sky", "color", "number", "celestial", "block", "fluid", "feature", "environment", "corrupted"); public static final Map> SYMBOL_PAGES = registerSymbolPageTabs(); diff --git a/src/main/java/net/dnorberg/rivencraft/writing/SymbolSemantics.java b/src/main/java/net/dnorberg/rivencraft/writing/SymbolSemantics.java index 3e42e0f..a07ebe6 100644 --- a/src/main/java/net/dnorberg/rivencraft/writing/SymbolSemantics.java +++ b/src/main/java/net/dnorberg/rivencraft/writing/SymbolSemantics.java @@ -80,6 +80,8 @@ public record SymbolSemantics(Role role, Value value) { SKY("sky", Kind.CHOICE, "overworld", "nether", "end", "static"), SKY_COLOR("sky_color", Kind.CHOICE, "red", "orange", "yellow", "green", "blue", "purple", "white", "black"), + COLOR("color", Kind.CHOICE, "red", "green", "blue", "black", "white"), + COLOR_NUMBER("color_number", Kind.NUMBER), WEATHER("weather", Kind.CHOICE, "normal", "fast", "slow", "off", "always", "cloudy", "rain", "snow", "storm"), SEASON("season", Kind.CHOICE, @@ -116,6 +118,8 @@ public record SymbolSemantics(Role role, Value value) { return switch (this) { case PERIOD_MODIFIER -> number.amount() >= 0.0 && number.amount() <= 2.0; case SIZE_MODIFIER -> number.amount() >= 0.25 && number.amount() <= 3.0; + case COLOR_NUMBER -> number.amount() >= 0.0 && number.amount() <= 24.0 + && number.amount() == Math.floor(number.amount()); case ANGLE_MODIFIER, PHASE_MODIFIER -> number.amount() >= 0.0 && number.amount() < 360.0; default -> false; }; @@ -127,6 +131,7 @@ public record SymbolSemantics(Role role, Value value) { case CHOICE -> "one of " + choices.stream().sorted().toList(); case NUMBER -> this == PERIOD_MODIFIER ? "a finite number in [0, 2]" : this == SIZE_MODIFIER ? "a finite number in [0.25, 3]" + : this == COLOR_NUMBER ? "an integer D'ni digit in [0, 24]" : "a finite number in [0, 360) degrees"; }; } diff --git a/src/main/java/net/dnorberg/rivencraft/writing/WritingGrammar.java b/src/main/java/net/dnorberg/rivencraft/writing/WritingGrammar.java index 267b990..f7b3aed 100644 --- a/src/main/java/net/dnorberg/rivencraft/writing/WritingGrammar.java +++ b/src/main/java/net/dnorberg/rivencraft/writing/WritingGrammar.java @@ -45,6 +45,7 @@ public final class WritingGrammar { int lastStage = -1; int biomeCount = 0; ParsedSymbol pendingBlock = null; + ParsedSymbol pendingColorNumber = null; for (int index = 0; index < writing.entries().size(); index++) { WritingEntry entry = writing.entries().get(index); if (entry.kind() == WritingEntry.Kind.LINK_PANEL) { @@ -73,6 +74,18 @@ public final class WritingGrammar { Role role = semantics.orElseThrow().role(); ParsedSymbol parsed = new ParsedSymbol(index, reference, semantics.orElseThrow()); symbols.add(parsed); + if (pendingColorNumber != null && role != Role.COLOR && role != Role.COLOR_NUMBER) { + diagnostics.add(new Diagnostic(Code.MISPLACED_MODIFIER, pendingColorNumber.index(), + "A number page must be immediately followed by a color page")); + pendingColorNumber = null; + } + if (role == Role.COLOR_NUMBER) { + if (pendingColorNumber != null) diagnostics.add(new Diagnostic(Code.MISPLACED_MODIFIER, + pendingColorNumber.index(), "A number page must be immediately followed by a color page")); + pendingColorNumber = parsed; + } else if (role == Role.COLOR) { + pendingColorNumber = null; + } if (modifier(role)) { // Legacy modifier pages pop and combine an earlier modifier of the same // kind. Only the final pending value can be left dangling. @@ -115,13 +128,15 @@ public final class WritingGrammar { } if (role == Role.BIOME) biomeCount++; int stage = stage(role); - if (stage < lastStage && !modifier(role)) { + if (stage < lastStage && !modifier(role) && role != Role.COLOR && role != Role.COLOR_NUMBER) { diagnostics.add(new Diagnostic(Code.OUT_OF_ORDER, index, "Move this " + role.id() + " page before later grammar categories")); - } else { + } else if (role != Role.COLOR && role != Role.COLOR_NUMBER) { lastStage = stage; } } + if (pendingColorNumber != null) diagnostics.add(new Diagnostic(Code.DANGLING_MODIFIER, + pendingColorNumber.index(), "A number page must be followed by a color page")); if (panels == 0) diagnostics.add(new Diagnostic(Code.MISSING_PANEL, -1, "Add a Link Panel as the first page")); for (ParsedSymbol dangling : pendingModifiers.values()) { @@ -183,6 +198,7 @@ public final class WritingGrammar { case SEASON -> 4; case LIGHTING -> 5; case SKY, SKY_COLOR -> 6; + case COLOR, COLOR_NUMBER -> 6; case PERIOD_MODIFIER, ANGLE_MODIFIER, PHASE_MODIFIER, SIZE_MODIFIER, CELESTIAL_COLOR, DIRECTION_MODIFIER -> 7; case CELESTIAL -> 8; diff --git a/src/main/resources/assets/rivencraft/lang/en_us.json b/src/main/resources/assets/rivencraft/lang/en_us.json index c854865..20bc7ec 100644 --- a/src/main/resources/assets/rivencraft/lang/en_us.json +++ b/src/main/resources/assets/rivencraft/lang/en_us.json @@ -225,22 +225,42 @@ "symbol.rivencraft.sky.end.description": "Use the End sky and dark preview background.", "symbol.rivencraft.sky.static": "Static Sky", "symbol.rivencraft.sky.static.description": "Fill the sky with shifting television static.", - "symbol.rivencraft.sky_color.red": "Red Sky Color", - "symbol.rivencraft.sky_color.red.description": "Tint the sky and linked portal red.", - "symbol.rivencraft.sky_color.orange": "Orange Sky Color", - "symbol.rivencraft.sky_color.orange.description": "Tint the sky and linked portal orange.", - "symbol.rivencraft.sky_color.yellow": "Yellow Sky Color", - "symbol.rivencraft.sky_color.yellow.description": "Tint the sky and linked portal yellow.", - "symbol.rivencraft.sky_color.green": "Green Sky Color", - "symbol.rivencraft.sky_color.green.description": "Tint the sky and linked portal green.", - "symbol.rivencraft.sky_color.blue": "Blue Sky Color", - "symbol.rivencraft.sky_color.blue.description": "Tint the sky and linked portal blue.", - "symbol.rivencraft.sky_color.purple": "Purple Sky Color", - "symbol.rivencraft.sky_color.purple.description": "Tint the sky and linked portal purple.", - "symbol.rivencraft.sky_color.white": "White Sky Color", - "symbol.rivencraft.sky_color.white.description": "Tint the sky and linked portal white.", - "symbol.rivencraft.sky_color.black": "Black Sky Color", - "symbol.rivencraft.sky_color.black.description": "Tint the sky and linked portal near-black.", + "symbol.rivencraft.color.red": "Red Color", + "symbol.rivencraft.color.red.description": "Add red to the next Sky, Sun, or Moon. A number page directly before this page sets its strength.", + "symbol.rivencraft.color.green": "Green Color", + "symbol.rivencraft.color.green.description": "Add green to the next Sky, Sun, or Moon. A number page directly before this page sets its strength.", + "symbol.rivencraft.color.blue": "Blue Color", + "symbol.rivencraft.color.blue.description": "Add blue to the next Sky, Sun, or Moon. A number page directly before this page sets its strength.", + "symbol.rivencraft.color.white": "White Color", + "symbol.rivencraft.color.white.description": "Add equal brightness to red, green, and blue in the next Sky, Sun, or Moon.", + "symbol.rivencraft.color.black": "Black Color", + "symbol.rivencraft.color.black.description": "Subtract equal brightness from red, green, and blue in the next Sky, Sun, or Moon.", + "symbol.rivencraft.number.0": "D'ni 0", + "symbol.rivencraft.number.1": "D'ni 1", + "symbol.rivencraft.number.2": "D'ni 2", + "symbol.rivencraft.number.3": "D'ni 3", + "symbol.rivencraft.number.4": "D'ni 4", + "symbol.rivencraft.number.5": "D'ni 5", + "symbol.rivencraft.number.6": "D'ni 6", + "symbol.rivencraft.number.7": "D'ni 7", + "symbol.rivencraft.number.8": "D'ni 8", + "symbol.rivencraft.number.9": "D'ni 9", + "symbol.rivencraft.number.10": "D'ni 10", + "symbol.rivencraft.number.11": "D'ni 11", + "symbol.rivencraft.number.12": "D'ni 12", + "symbol.rivencraft.number.13": "D'ni 13", + "symbol.rivencraft.number.14": "D'ni 14", + "symbol.rivencraft.number.15": "D'ni 15", + "symbol.rivencraft.number.16": "D'ni 16", + "symbol.rivencraft.number.17": "D'ni 17", + "symbol.rivencraft.number.18": "D'ni 18", + "symbol.rivencraft.number.19": "D'ni 19", + "symbol.rivencraft.number.20": "D'ni 20", + "symbol.rivencraft.number.21": "D'ni 21", + "symbol.rivencraft.number.22": "D'ni 22", + "symbol.rivencraft.number.23": "D'ni 23", + "symbol.rivencraft.number.24": "D'ni 24", + "symbol.rivencraft.number.description": "Set the next color page to this D'ni number times 10. Without a number page, the Age chooses a random number from 0 to 24.", "symbol.rivencraft.weather.normal": "Normal Weather", "symbol.rivencraft.weather.normal.description": "Use the normal weather cycle.", "symbol.rivencraft.weather.fast": "Fast Weather", @@ -271,22 +291,6 @@ "symbol.rivencraft.celestial.sun.description": "Add one independently moving sun to the sky.", "symbol.rivencraft.celestial.moon": "Moon", "symbol.rivencraft.celestial.moon.description": "Add one independently moving moon to the sky.", - "symbol.rivencraft.celestial_color.red": "Red Celestial", - "symbol.rivencraft.celestial_color.red.description": "Color the next sun or moon red.", - "symbol.rivencraft.celestial_color.orange": "Orange Celestial", - "symbol.rivencraft.celestial_color.orange.description": "Color the next sun or moon orange.", - "symbol.rivencraft.celestial_color.yellow": "Yellow Celestial", - "symbol.rivencraft.celestial_color.yellow.description": "Color the next sun or moon yellow.", - "symbol.rivencraft.celestial_color.green": "Green Celestial", - "symbol.rivencraft.celestial_color.green.description": "Color the next sun or moon green.", - "symbol.rivencraft.celestial_color.blue": "Blue Celestial", - "symbol.rivencraft.celestial_color.blue.description": "Color the next sun or moon blue.", - "symbol.rivencraft.celestial_color.purple": "Purple Celestial", - "symbol.rivencraft.celestial_color.purple.description": "Color the next sun or moon purple.", - "symbol.rivencraft.celestial_color.white": "White Celestial", - "symbol.rivencraft.celestial_color.white.description": "Color the next sun or moon white.", - "symbol.rivencraft.celestial_color.black": "Black Celestial", - "symbol.rivencraft.celestial_color.black.description": "Blend black into the next sun or moon's color.", "symbol.rivencraft.size.small": "Small Celestial", "symbol.rivencraft.size.small.description": "Halve the apparent size of the next sun or moon.", "symbol.rivencraft.size.normal": "Normal Celestial Size", @@ -436,6 +440,8 @@ "itemGroup.rivencraft.pages.season": "Rivencraft Season Pages", "itemGroup.rivencraft.pages.lighting": "Rivencraft Lighting Pages", "itemGroup.rivencraft.pages.sky": "Rivencraft Sky Pages", + "itemGroup.rivencraft.pages.color": "Rivencraft Color Pages", + "itemGroup.rivencraft.pages.number": "Rivencraft Number Pages", "itemGroup.rivencraft.pages.celestial": "Rivencraft Celestial Pages", "itemGroup.rivencraft.pages.block": "Rivencraft Block Pages", "itemGroup.rivencraft.pages.fluid": "Rivencraft Fluid Pages", diff --git a/src/main/resources/data/rivencraft/rivencraft/symbols/celestial_color/black.json b/src/main/resources/data/rivencraft/rivencraft/symbols/celestial_color/black.json deleted file mode 100644 index d0b0d3c..0000000 --- a/src/main/resources/data/rivencraft/rivencraft/symbols/celestial_color/black.json +++ /dev/null @@ -1 +0,0 @@ -{"schema_version":2,"name":"symbol.rivencraft.celestial_color.black","description":"symbol.rivencraft.celestial_color.black.description","category":"rivencraft:celestial","semantics":{"role":"celestial_color","value":"black"},"poem":"Transform Black Illuminate Motion"} diff --git a/src/main/resources/data/rivencraft/rivencraft/symbols/celestial_color/blue.json b/src/main/resources/data/rivencraft/rivencraft/symbols/celestial_color/blue.json deleted file mode 100644 index 96b6dc9..0000000 --- a/src/main/resources/data/rivencraft/rivencraft/symbols/celestial_color/blue.json +++ /dev/null @@ -1 +0,0 @@ -{"schema_version":2,"name":"symbol.rivencraft.celestial_color.blue","description":"symbol.rivencraft.celestial_color.blue.description","category":"rivencraft:celestial","semantics":{"role":"celestial_color","value":"blue"},"poem":"Transform Blue Illuminate Motion"} diff --git a/src/main/resources/data/rivencraft/rivencraft/symbols/celestial_color/green.json b/src/main/resources/data/rivencraft/rivencraft/symbols/celestial_color/green.json deleted file mode 100644 index 446e47b..0000000 --- a/src/main/resources/data/rivencraft/rivencraft/symbols/celestial_color/green.json +++ /dev/null @@ -1 +0,0 @@ -{"schema_version":2,"name":"symbol.rivencraft.celestial_color.green","description":"symbol.rivencraft.celestial_color.green.description","category":"rivencraft:celestial","semantics":{"role":"celestial_color","value":"green"},"poem":"Transform Green Illuminate Motion"} diff --git a/src/main/resources/data/rivencraft/rivencraft/symbols/celestial_color/orange.json b/src/main/resources/data/rivencraft/rivencraft/symbols/celestial_color/orange.json deleted file mode 100644 index 8eacabb..0000000 --- a/src/main/resources/data/rivencraft/rivencraft/symbols/celestial_color/orange.json +++ /dev/null @@ -1 +0,0 @@ -{"schema_version":2,"name":"symbol.rivencraft.celestial_color.orange","description":"symbol.rivencraft.celestial_color.orange.description","category":"rivencraft:celestial","semantics":{"role":"celestial_color","value":"orange"},"poem":"Transform Orange Illuminate Motion"} diff --git a/src/main/resources/data/rivencraft/rivencraft/symbols/celestial_color/purple.json b/src/main/resources/data/rivencraft/rivencraft/symbols/celestial_color/purple.json deleted file mode 100644 index fea732b..0000000 --- a/src/main/resources/data/rivencraft/rivencraft/symbols/celestial_color/purple.json +++ /dev/null @@ -1 +0,0 @@ -{"schema_version":2,"name":"symbol.rivencraft.celestial_color.purple","description":"symbol.rivencraft.celestial_color.purple.description","category":"rivencraft:celestial","semantics":{"role":"celestial_color","value":"purple"},"poem":"Transform Purple Illuminate Motion"} diff --git a/src/main/resources/data/rivencraft/rivencraft/symbols/celestial_color/red.json b/src/main/resources/data/rivencraft/rivencraft/symbols/celestial_color/red.json deleted file mode 100644 index 27e83cc..0000000 --- a/src/main/resources/data/rivencraft/rivencraft/symbols/celestial_color/red.json +++ /dev/null @@ -1 +0,0 @@ -{"schema_version":2,"name":"symbol.rivencraft.celestial_color.red","description":"symbol.rivencraft.celestial_color.red.description","category":"rivencraft:celestial","semantics":{"role":"celestial_color","value":"red"},"poem":"Transform Red Illuminate Motion"} diff --git a/src/main/resources/data/rivencraft/rivencraft/symbols/celestial_color/white.json b/src/main/resources/data/rivencraft/rivencraft/symbols/celestial_color/white.json deleted file mode 100644 index e77160b..0000000 --- a/src/main/resources/data/rivencraft/rivencraft/symbols/celestial_color/white.json +++ /dev/null @@ -1 +0,0 @@ -{"schema_version":2,"name":"symbol.rivencraft.celestial_color.white","description":"symbol.rivencraft.celestial_color.white.description","category":"rivencraft:celestial","semantics":{"role":"celestial_color","value":"white"},"poem":"Transform White Illuminate Motion"} diff --git a/src/main/resources/data/rivencraft/rivencraft/symbols/celestial_color/yellow.json b/src/main/resources/data/rivencraft/rivencraft/symbols/celestial_color/yellow.json deleted file mode 100644 index 9195db9..0000000 --- a/src/main/resources/data/rivencraft/rivencraft/symbols/celestial_color/yellow.json +++ /dev/null @@ -1 +0,0 @@ -{"schema_version":2,"name":"symbol.rivencraft.celestial_color.yellow","description":"symbol.rivencraft.celestial_color.yellow.description","category":"rivencraft:celestial","semantics":{"role":"celestial_color","value":"yellow"},"poem":"Transform Yellow Illuminate Motion"} diff --git a/src/main/resources/data/rivencraft/rivencraft/symbols/color/black.json b/src/main/resources/data/rivencraft/rivencraft/symbols/color/black.json new file mode 100644 index 0000000..052cbcd --- /dev/null +++ b/src/main/resources/data/rivencraft/rivencraft/symbols/color/black.json @@ -0,0 +1 @@ +{"schema_version":2,"name":"symbol.rivencraft.color.black","description":"symbol.rivencraft.color.black.description","category":"rivencraft:color","semantics":{"role":"color","value":"black"},"poem":"Ethereal Black Transform Balance"} diff --git a/src/main/resources/data/rivencraft/rivencraft/symbols/color/blue.json b/src/main/resources/data/rivencraft/rivencraft/symbols/color/blue.json new file mode 100644 index 0000000..0da6f3a --- /dev/null +++ b/src/main/resources/data/rivencraft/rivencraft/symbols/color/blue.json @@ -0,0 +1 @@ +{"schema_version":2,"name":"symbol.rivencraft.color.blue","description":"symbol.rivencraft.color.blue.description","category":"rivencraft:color","semantics":{"role":"color","value":"blue"},"poem":"Ethereal Blue Transform Balance"} diff --git a/src/main/resources/data/rivencraft/rivencraft/symbols/color/green.json b/src/main/resources/data/rivencraft/rivencraft/symbols/color/green.json new file mode 100644 index 0000000..2803027 --- /dev/null +++ b/src/main/resources/data/rivencraft/rivencraft/symbols/color/green.json @@ -0,0 +1 @@ +{"schema_version":2,"name":"symbol.rivencraft.color.green","description":"symbol.rivencraft.color.green.description","category":"rivencraft:color","semantics":{"role":"color","value":"green"},"poem":"Ethereal Green Transform Balance"} diff --git a/src/main/resources/data/rivencraft/rivencraft/symbols/color/red.json b/src/main/resources/data/rivencraft/rivencraft/symbols/color/red.json new file mode 100644 index 0000000..cee3390 --- /dev/null +++ b/src/main/resources/data/rivencraft/rivencraft/symbols/color/red.json @@ -0,0 +1 @@ +{"schema_version":2,"name":"symbol.rivencraft.color.red","description":"symbol.rivencraft.color.red.description","category":"rivencraft:color","semantics":{"role":"color","value":"red"},"poem":"Ethereal Red Transform Balance"} diff --git a/src/main/resources/data/rivencraft/rivencraft/symbols/color/white.json b/src/main/resources/data/rivencraft/rivencraft/symbols/color/white.json new file mode 100644 index 0000000..3bbb62d --- /dev/null +++ b/src/main/resources/data/rivencraft/rivencraft/symbols/color/white.json @@ -0,0 +1 @@ +{"schema_version":2,"name":"symbol.rivencraft.color.white","description":"symbol.rivencraft.color.white.description","category":"rivencraft:color","semantics":{"role":"color","value":"white"},"poem":"Ethereal White Transform Balance"} diff --git a/src/main/resources/data/rivencraft/rivencraft/symbols/number/0.json b/src/main/resources/data/rivencraft/rivencraft/symbols/number/0.json new file mode 100644 index 0000000..ae18eef --- /dev/null +++ b/src/main/resources/data/rivencraft/rivencraft/symbols/number/0.json @@ -0,0 +1 @@ +{"schema_version":2,"name":"symbol.rivencraft.number.0","description":"symbol.rivencraft.number.description","category":"rivencraft:number","semantics":{"role":"color_number","value":0},"poem":"Transform Time System Balance"} diff --git a/src/main/resources/data/rivencraft/rivencraft/symbols/number/1.json b/src/main/resources/data/rivencraft/rivencraft/symbols/number/1.json new file mode 100644 index 0000000..037bd28 --- /dev/null +++ b/src/main/resources/data/rivencraft/rivencraft/symbols/number/1.json @@ -0,0 +1 @@ +{"schema_version":2,"name":"symbol.rivencraft.number.1","description":"symbol.rivencraft.number.description","category":"rivencraft:number","semantics":{"role":"color_number","value":1},"poem":"Transform Time System Balance"} diff --git a/src/main/resources/data/rivencraft/rivencraft/symbols/number/10.json b/src/main/resources/data/rivencraft/rivencraft/symbols/number/10.json new file mode 100644 index 0000000..a0759a3 --- /dev/null +++ b/src/main/resources/data/rivencraft/rivencraft/symbols/number/10.json @@ -0,0 +1 @@ +{"schema_version":2,"name":"symbol.rivencraft.number.10","description":"symbol.rivencraft.number.description","category":"rivencraft:number","semantics":{"role":"color_number","value":10},"poem":"Transform Time System Balance"} diff --git a/src/main/resources/data/rivencraft/rivencraft/symbols/number/11.json b/src/main/resources/data/rivencraft/rivencraft/symbols/number/11.json new file mode 100644 index 0000000..6ab2bf6 --- /dev/null +++ b/src/main/resources/data/rivencraft/rivencraft/symbols/number/11.json @@ -0,0 +1 @@ +{"schema_version":2,"name":"symbol.rivencraft.number.11","description":"symbol.rivencraft.number.description","category":"rivencraft:number","semantics":{"role":"color_number","value":11},"poem":"Transform Time System Balance"} diff --git a/src/main/resources/data/rivencraft/rivencraft/symbols/number/12.json b/src/main/resources/data/rivencraft/rivencraft/symbols/number/12.json new file mode 100644 index 0000000..2135df2 --- /dev/null +++ b/src/main/resources/data/rivencraft/rivencraft/symbols/number/12.json @@ -0,0 +1 @@ +{"schema_version":2,"name":"symbol.rivencraft.number.12","description":"symbol.rivencraft.number.description","category":"rivencraft:number","semantics":{"role":"color_number","value":12},"poem":"Transform Time System Balance"} diff --git a/src/main/resources/data/rivencraft/rivencraft/symbols/number/13.json b/src/main/resources/data/rivencraft/rivencraft/symbols/number/13.json new file mode 100644 index 0000000..4ed3d96 --- /dev/null +++ b/src/main/resources/data/rivencraft/rivencraft/symbols/number/13.json @@ -0,0 +1 @@ +{"schema_version":2,"name":"symbol.rivencraft.number.13","description":"symbol.rivencraft.number.description","category":"rivencraft:number","semantics":{"role":"color_number","value":13},"poem":"Transform Time System Balance"} diff --git a/src/main/resources/data/rivencraft/rivencraft/symbols/number/14.json b/src/main/resources/data/rivencraft/rivencraft/symbols/number/14.json new file mode 100644 index 0000000..149834b --- /dev/null +++ b/src/main/resources/data/rivencraft/rivencraft/symbols/number/14.json @@ -0,0 +1 @@ +{"schema_version":2,"name":"symbol.rivencraft.number.14","description":"symbol.rivencraft.number.description","category":"rivencraft:number","semantics":{"role":"color_number","value":14},"poem":"Transform Time System Balance"} diff --git a/src/main/resources/data/rivencraft/rivencraft/symbols/number/15.json b/src/main/resources/data/rivencraft/rivencraft/symbols/number/15.json new file mode 100644 index 0000000..86ddb12 --- /dev/null +++ b/src/main/resources/data/rivencraft/rivencraft/symbols/number/15.json @@ -0,0 +1 @@ +{"schema_version":2,"name":"symbol.rivencraft.number.15","description":"symbol.rivencraft.number.description","category":"rivencraft:number","semantics":{"role":"color_number","value":15},"poem":"Transform Time System Balance"} diff --git a/src/main/resources/data/rivencraft/rivencraft/symbols/number/16.json b/src/main/resources/data/rivencraft/rivencraft/symbols/number/16.json new file mode 100644 index 0000000..a6916b0 --- /dev/null +++ b/src/main/resources/data/rivencraft/rivencraft/symbols/number/16.json @@ -0,0 +1 @@ +{"schema_version":2,"name":"symbol.rivencraft.number.16","description":"symbol.rivencraft.number.description","category":"rivencraft:number","semantics":{"role":"color_number","value":16},"poem":"Transform Time System Balance"} diff --git a/src/main/resources/data/rivencraft/rivencraft/symbols/number/17.json b/src/main/resources/data/rivencraft/rivencraft/symbols/number/17.json new file mode 100644 index 0000000..e9ca846 --- /dev/null +++ b/src/main/resources/data/rivencraft/rivencraft/symbols/number/17.json @@ -0,0 +1 @@ +{"schema_version":2,"name":"symbol.rivencraft.number.17","description":"symbol.rivencraft.number.description","category":"rivencraft:number","semantics":{"role":"color_number","value":17},"poem":"Transform Time System Balance"} diff --git a/src/main/resources/data/rivencraft/rivencraft/symbols/number/18.json b/src/main/resources/data/rivencraft/rivencraft/symbols/number/18.json new file mode 100644 index 0000000..92b3ae5 --- /dev/null +++ b/src/main/resources/data/rivencraft/rivencraft/symbols/number/18.json @@ -0,0 +1 @@ +{"schema_version":2,"name":"symbol.rivencraft.number.18","description":"symbol.rivencraft.number.description","category":"rivencraft:number","semantics":{"role":"color_number","value":18},"poem":"Transform Time System Balance"} diff --git a/src/main/resources/data/rivencraft/rivencraft/symbols/number/19.json b/src/main/resources/data/rivencraft/rivencraft/symbols/number/19.json new file mode 100644 index 0000000..a02d5b5 --- /dev/null +++ b/src/main/resources/data/rivencraft/rivencraft/symbols/number/19.json @@ -0,0 +1 @@ +{"schema_version":2,"name":"symbol.rivencraft.number.19","description":"symbol.rivencraft.number.description","category":"rivencraft:number","semantics":{"role":"color_number","value":19},"poem":"Transform Time System Balance"} diff --git a/src/main/resources/data/rivencraft/rivencraft/symbols/number/2.json b/src/main/resources/data/rivencraft/rivencraft/symbols/number/2.json new file mode 100644 index 0000000..734585e --- /dev/null +++ b/src/main/resources/data/rivencraft/rivencraft/symbols/number/2.json @@ -0,0 +1 @@ +{"schema_version":2,"name":"symbol.rivencraft.number.2","description":"symbol.rivencraft.number.description","category":"rivencraft:number","semantics":{"role":"color_number","value":2},"poem":"Transform Time System Balance"} diff --git a/src/main/resources/data/rivencraft/rivencraft/symbols/number/20.json b/src/main/resources/data/rivencraft/rivencraft/symbols/number/20.json new file mode 100644 index 0000000..461b8ba --- /dev/null +++ b/src/main/resources/data/rivencraft/rivencraft/symbols/number/20.json @@ -0,0 +1 @@ +{"schema_version":2,"name":"symbol.rivencraft.number.20","description":"symbol.rivencraft.number.description","category":"rivencraft:number","semantics":{"role":"color_number","value":20},"poem":"Transform Time System Balance"} diff --git a/src/main/resources/data/rivencraft/rivencraft/symbols/number/21.json b/src/main/resources/data/rivencraft/rivencraft/symbols/number/21.json new file mode 100644 index 0000000..f914de9 --- /dev/null +++ b/src/main/resources/data/rivencraft/rivencraft/symbols/number/21.json @@ -0,0 +1 @@ +{"schema_version":2,"name":"symbol.rivencraft.number.21","description":"symbol.rivencraft.number.description","category":"rivencraft:number","semantics":{"role":"color_number","value":21},"poem":"Transform Time System Balance"} diff --git a/src/main/resources/data/rivencraft/rivencraft/symbols/number/22.json b/src/main/resources/data/rivencraft/rivencraft/symbols/number/22.json new file mode 100644 index 0000000..9562aa9 --- /dev/null +++ b/src/main/resources/data/rivencraft/rivencraft/symbols/number/22.json @@ -0,0 +1 @@ +{"schema_version":2,"name":"symbol.rivencraft.number.22","description":"symbol.rivencraft.number.description","category":"rivencraft:number","semantics":{"role":"color_number","value":22},"poem":"Transform Time System Balance"} diff --git a/src/main/resources/data/rivencraft/rivencraft/symbols/number/23.json b/src/main/resources/data/rivencraft/rivencraft/symbols/number/23.json new file mode 100644 index 0000000..57d961e --- /dev/null +++ b/src/main/resources/data/rivencraft/rivencraft/symbols/number/23.json @@ -0,0 +1 @@ +{"schema_version":2,"name":"symbol.rivencraft.number.23","description":"symbol.rivencraft.number.description","category":"rivencraft:number","semantics":{"role":"color_number","value":23},"poem":"Transform Time System Balance"} diff --git a/src/main/resources/data/rivencraft/rivencraft/symbols/number/24.json b/src/main/resources/data/rivencraft/rivencraft/symbols/number/24.json new file mode 100644 index 0000000..994fcfa --- /dev/null +++ b/src/main/resources/data/rivencraft/rivencraft/symbols/number/24.json @@ -0,0 +1 @@ +{"schema_version":2,"name":"symbol.rivencraft.number.24","description":"symbol.rivencraft.number.description","category":"rivencraft:number","semantics":{"role":"color_number","value":24},"poem":"Transform Time System Balance"} diff --git a/src/main/resources/data/rivencraft/rivencraft/symbols/number/3.json b/src/main/resources/data/rivencraft/rivencraft/symbols/number/3.json new file mode 100644 index 0000000..f4bcd8c --- /dev/null +++ b/src/main/resources/data/rivencraft/rivencraft/symbols/number/3.json @@ -0,0 +1 @@ +{"schema_version":2,"name":"symbol.rivencraft.number.3","description":"symbol.rivencraft.number.description","category":"rivencraft:number","semantics":{"role":"color_number","value":3},"poem":"Transform Time System Balance"} diff --git a/src/main/resources/data/rivencraft/rivencraft/symbols/number/4.json b/src/main/resources/data/rivencraft/rivencraft/symbols/number/4.json new file mode 100644 index 0000000..88dcedb --- /dev/null +++ b/src/main/resources/data/rivencraft/rivencraft/symbols/number/4.json @@ -0,0 +1 @@ +{"schema_version":2,"name":"symbol.rivencraft.number.4","description":"symbol.rivencraft.number.description","category":"rivencraft:number","semantics":{"role":"color_number","value":4},"poem":"Transform Time System Balance"} diff --git a/src/main/resources/data/rivencraft/rivencraft/symbols/number/5.json b/src/main/resources/data/rivencraft/rivencraft/symbols/number/5.json new file mode 100644 index 0000000..5c59dc4 --- /dev/null +++ b/src/main/resources/data/rivencraft/rivencraft/symbols/number/5.json @@ -0,0 +1 @@ +{"schema_version":2,"name":"symbol.rivencraft.number.5","description":"symbol.rivencraft.number.description","category":"rivencraft:number","semantics":{"role":"color_number","value":5},"poem":"Transform Time System Balance"} diff --git a/src/main/resources/data/rivencraft/rivencraft/symbols/number/6.json b/src/main/resources/data/rivencraft/rivencraft/symbols/number/6.json new file mode 100644 index 0000000..808ca43 --- /dev/null +++ b/src/main/resources/data/rivencraft/rivencraft/symbols/number/6.json @@ -0,0 +1 @@ +{"schema_version":2,"name":"symbol.rivencraft.number.6","description":"symbol.rivencraft.number.description","category":"rivencraft:number","semantics":{"role":"color_number","value":6},"poem":"Transform Time System Balance"} diff --git a/src/main/resources/data/rivencraft/rivencraft/symbols/number/7.json b/src/main/resources/data/rivencraft/rivencraft/symbols/number/7.json new file mode 100644 index 0000000..5687876 --- /dev/null +++ b/src/main/resources/data/rivencraft/rivencraft/symbols/number/7.json @@ -0,0 +1 @@ +{"schema_version":2,"name":"symbol.rivencraft.number.7","description":"symbol.rivencraft.number.description","category":"rivencraft:number","semantics":{"role":"color_number","value":7},"poem":"Transform Time System Balance"} diff --git a/src/main/resources/data/rivencraft/rivencraft/symbols/number/8.json b/src/main/resources/data/rivencraft/rivencraft/symbols/number/8.json new file mode 100644 index 0000000..de6249d --- /dev/null +++ b/src/main/resources/data/rivencraft/rivencraft/symbols/number/8.json @@ -0,0 +1 @@ +{"schema_version":2,"name":"symbol.rivencraft.number.8","description":"symbol.rivencraft.number.description","category":"rivencraft:number","semantics":{"role":"color_number","value":8},"poem":"Transform Time System Balance"} diff --git a/src/main/resources/data/rivencraft/rivencraft/symbols/number/9.json b/src/main/resources/data/rivencraft/rivencraft/symbols/number/9.json new file mode 100644 index 0000000..e071072 --- /dev/null +++ b/src/main/resources/data/rivencraft/rivencraft/symbols/number/9.json @@ -0,0 +1 @@ +{"schema_version":2,"name":"symbol.rivencraft.number.9","description":"symbol.rivencraft.number.description","category":"rivencraft:number","semantics":{"role":"color_number","value":9},"poem":"Transform Time System Balance"} diff --git a/src/main/resources/data/rivencraft/rivencraft/symbols/sky_color/black.json b/src/main/resources/data/rivencraft/rivencraft/symbols/sky_color/black.json deleted file mode 100644 index b0f51b2..0000000 --- a/src/main/resources/data/rivencraft/rivencraft/symbols/sky_color/black.json +++ /dev/null @@ -1 +0,0 @@ -{"schema_version":2,"name":"symbol.rivencraft.sky_color.black","description":"symbol.rivencraft.sky_color.black.description","category":"rivencraft:sky","semantics":{"role":"sky_color","value":"black"},"poem":"Ethereal Black Sky Balance"} diff --git a/src/main/resources/data/rivencraft/rivencraft/symbols/sky_color/blue.json b/src/main/resources/data/rivencraft/rivencraft/symbols/sky_color/blue.json deleted file mode 100644 index 347377a..0000000 --- a/src/main/resources/data/rivencraft/rivencraft/symbols/sky_color/blue.json +++ /dev/null @@ -1 +0,0 @@ -{"schema_version":2,"name":"symbol.rivencraft.sky_color.blue","description":"symbol.rivencraft.sky_color.blue.description","category":"rivencraft:sky","semantics":{"role":"sky_color","value":"blue"},"poem":"Ethereal Blue Sky Balance"} diff --git a/src/main/resources/data/rivencraft/rivencraft/symbols/sky_color/green.json b/src/main/resources/data/rivencraft/rivencraft/symbols/sky_color/green.json deleted file mode 100644 index 2619acc..0000000 --- a/src/main/resources/data/rivencraft/rivencraft/symbols/sky_color/green.json +++ /dev/null @@ -1 +0,0 @@ -{"schema_version":2,"name":"symbol.rivencraft.sky_color.green","description":"symbol.rivencraft.sky_color.green.description","category":"rivencraft:sky","semantics":{"role":"sky_color","value":"green"},"poem":"Ethereal Green Sky Balance"} diff --git a/src/main/resources/data/rivencraft/rivencraft/symbols/sky_color/orange.json b/src/main/resources/data/rivencraft/rivencraft/symbols/sky_color/orange.json deleted file mode 100644 index 8f291d1..0000000 --- a/src/main/resources/data/rivencraft/rivencraft/symbols/sky_color/orange.json +++ /dev/null @@ -1 +0,0 @@ -{"schema_version":2,"name":"symbol.rivencraft.sky_color.orange","description":"symbol.rivencraft.sky_color.orange.description","category":"rivencraft:sky","semantics":{"role":"sky_color","value":"orange"},"poem":"Ethereal Orange Sky Balance"} diff --git a/src/main/resources/data/rivencraft/rivencraft/symbols/sky_color/purple.json b/src/main/resources/data/rivencraft/rivencraft/symbols/sky_color/purple.json deleted file mode 100644 index f6a4451..0000000 --- a/src/main/resources/data/rivencraft/rivencraft/symbols/sky_color/purple.json +++ /dev/null @@ -1 +0,0 @@ -{"schema_version":2,"name":"symbol.rivencraft.sky_color.purple","description":"symbol.rivencraft.sky_color.purple.description","category":"rivencraft:sky","semantics":{"role":"sky_color","value":"purple"},"poem":"Ethereal Purple Sky Balance"} diff --git a/src/main/resources/data/rivencraft/rivencraft/symbols/sky_color/red.json b/src/main/resources/data/rivencraft/rivencraft/symbols/sky_color/red.json deleted file mode 100644 index ef0b764..0000000 --- a/src/main/resources/data/rivencraft/rivencraft/symbols/sky_color/red.json +++ /dev/null @@ -1 +0,0 @@ -{"schema_version":2,"name":"symbol.rivencraft.sky_color.red","description":"symbol.rivencraft.sky_color.red.description","category":"rivencraft:sky","semantics":{"role":"sky_color","value":"red"},"poem":"Ethereal Red Sky Balance"} diff --git a/src/main/resources/data/rivencraft/rivencraft/symbols/sky_color/white.json b/src/main/resources/data/rivencraft/rivencraft/symbols/sky_color/white.json deleted file mode 100644 index 257ff6d..0000000 --- a/src/main/resources/data/rivencraft/rivencraft/symbols/sky_color/white.json +++ /dev/null @@ -1 +0,0 @@ -{"schema_version":2,"name":"symbol.rivencraft.sky_color.white","description":"symbol.rivencraft.sky_color.white.description","category":"rivencraft:sky","semantics":{"role":"sky_color","value":"white"},"poem":"Ethereal White Sky Balance"} diff --git a/src/main/resources/data/rivencraft/rivencraft/symbols/sky_color/yellow.json b/src/main/resources/data/rivencraft/rivencraft/symbols/sky_color/yellow.json deleted file mode 100644 index d34aab8..0000000 --- a/src/main/resources/data/rivencraft/rivencraft/symbols/sky_color/yellow.json +++ /dev/null @@ -1 +0,0 @@ -{"schema_version":2,"name":"symbol.rivencraft.sky_color.yellow","description":"symbol.rivencraft.sky_color.yellow.description","category":"rivencraft:sky","semantics":{"role":"sky_color","value":"yellow"},"poem":"Ethereal Yellow Sky Balance"}