Public Access
1 parent
733028b943
commit
73dec80ae6
6 files changed
+139
-7
No files matched your search
@@ -15,18 +15,20 @@ public record AgeDefinition(
|
||||
int generationVersion,
|
||||
long createdGameTime,
|
||||
ResourceLocation dimensionId,
|
||||
BlockPos spawn
|
||||
BlockPos spawn,
|
||||
AgeTraits traits
|
||||
) {
|
||||
public static final ResourceLocation RANDOM_VANILLA_PROFILE = ResourceLocation.fromNamespaceAndPath(
|
||||
Rivencraft.MOD_ID, "random_vanilla"
|
||||
);
|
||||
public static final int CURRENT_GENERATION_VERSION = 2;
|
||||
public static final int CURRENT_GENERATION_VERSION = 3;
|
||||
|
||||
public AgeDefinition {
|
||||
Objects.requireNonNull(id, "id");
|
||||
Objects.requireNonNull(name, "name");
|
||||
Objects.requireNonNull(generationProfile, "generationProfile");
|
||||
Objects.requireNonNull(dimensionId, "dimensionId");
|
||||
Objects.requireNonNull(traits, "traits");
|
||||
}
|
||||
|
||||
public static ResourceLocation dimensionId(UUID ageId) {
|
||||
@@ -57,6 +59,6 @@ public record AgeDefinition(
|
||||
|
||||
public AgeDefinition withSpawn(BlockPos spawn) {
|
||||
return new AgeDefinition(id, name, seed, generationProfile, generationVersion,
|
||||
createdGameTime, dimensionId, spawn.immutable());
|
||||
createdGameTime, dimensionId, spawn.immutable(), traits);
|
||||
}
|
||||
}
|
||||
@@ -28,6 +28,13 @@ public final class AgeRegistrySavedData extends SavedData {
|
||||
private static final String SPAWN_X_TAG = "SpawnX";
|
||||
private static final String SPAWN_Y_TAG = "SpawnY";
|
||||
private static final String SPAWN_Z_TAG = "SpawnZ";
|
||||
private static final String TRAITS_TAG = "Traits";
|
||||
private static final String BIOME_DISTRIBUTION_TAG = "BiomeDistribution";
|
||||
private static final String LIGHTING_TAG = "Lighting";
|
||||
private static final String WEATHER_TAG = "Weather";
|
||||
private static final String CELESTIAL_PERIOD_TAG = "CelestialPeriod";
|
||||
private static final String CELESTIAL_ANGLE_TAG = "CelestialAngle";
|
||||
private static final String CELESTIAL_PHASE_TAG = "CelestialPhase";
|
||||
private static final Factory<AgeRegistrySavedData> FACTORY = new Factory<>(
|
||||
AgeRegistrySavedData::new,
|
||||
AgeRegistrySavedData::load,
|
||||
@@ -88,7 +95,8 @@ public final class AgeRegistrySavedData extends SavedData {
|
||||
AgeDefinition.CURRENT_GENERATION_VERSION,
|
||||
createdGameTime,
|
||||
dimensionId,
|
||||
null
|
||||
null,
|
||||
AgeTraits.select(seed)
|
||||
);
|
||||
ages.put(created.id(), created);
|
||||
setDirty();
|
||||
@@ -123,7 +131,8 @@ public final class AgeRegistrySavedData extends SavedData {
|
||||
entry.contains(VERSION_TAG) ? entry.getInt(VERSION_TAG) : 1,
|
||||
entry.getLong(CREATED_TIME_TAG),
|
||||
dimensionId,
|
||||
spawn
|
||||
spawn,
|
||||
readTraits(entry)
|
||||
));
|
||||
}
|
||||
return data;
|
||||
@@ -148,12 +157,40 @@ public final class AgeRegistrySavedData extends SavedData {
|
||||
entry.putInt(SPAWN_Y_TAG, age.spawn().getY());
|
||||
entry.putInt(SPAWN_Z_TAG, age.spawn().getZ());
|
||||
}
|
||||
CompoundTag traits = new CompoundTag();
|
||||
traits.putString(BIOME_DISTRIBUTION_TAG, age.traits().biomeDistribution().name());
|
||||
traits.putString(LIGHTING_TAG, age.traits().lighting().name());
|
||||
traits.putString(WEATHER_TAG, age.traits().weather().name());
|
||||
traits.putDouble(CELESTIAL_PERIOD_TAG, age.traits().celestialPeriod());
|
||||
traits.putFloat(CELESTIAL_ANGLE_TAG, age.traits().celestialAngle());
|
||||
traits.putFloat(CELESTIAL_PHASE_TAG, age.traits().celestialPhase());
|
||||
entry.put(TRAITS_TAG, traits);
|
||||
serializedAges.add(entry);
|
||||
});
|
||||
tag.put(AGES_TAG, serializedAges);
|
||||
return tag;
|
||||
}
|
||||
|
||||
private static AgeTraits readTraits(CompoundTag age) {
|
||||
if (!age.contains(TRAITS_TAG, CompoundTag.TAG_COMPOUND)) {
|
||||
return AgeTraits.LEGACY_DEFAULTS;
|
||||
}
|
||||
CompoundTag traits = age.getCompound(TRAITS_TAG);
|
||||
AgeTraits defaults = AgeTraits.LEGACY_DEFAULTS;
|
||||
try {
|
||||
return new AgeTraits(
|
||||
AgeTraits.parseOrDefault(traits.getString(BIOME_DISTRIBUTION_TAG), defaults.biomeDistribution()),
|
||||
AgeTraits.parseOrDefault(traits.getString(LIGHTING_TAG), defaults.lighting()),
|
||||
AgeTraits.parseOrDefault(traits.getString(WEATHER_TAG), defaults.weather()),
|
||||
traits.contains(CELESTIAL_PERIOD_TAG) ? traits.getDouble(CELESTIAL_PERIOD_TAG) : defaults.celestialPeriod(),
|
||||
traits.contains(CELESTIAL_ANGLE_TAG) ? traits.getFloat(CELESTIAL_ANGLE_TAG) : defaults.celestialAngle(),
|
||||
traits.contains(CELESTIAL_PHASE_TAG) ? traits.getFloat(CELESTIAL_PHASE_TAG) : defaults.celestialPhase()
|
||||
);
|
||||
} catch (IllegalArgumentException exception) {
|
||||
return defaults;
|
||||
}
|
||||
}
|
||||
|
||||
private static String normalizedName(String name) {
|
||||
String normalized = name.strip();
|
||||
return normalized.isEmpty() ? "Unnamed Age" : normalized;
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
package net.dnorberg.rivencraft.book;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
/** Immutable random-Age traits selected once from the Age seed. */
|
||||
public record AgeTraits(
|
||||
BiomeDistribution biomeDistribution,
|
||||
Lighting lighting,
|
||||
Weather weather,
|
||||
double celestialPeriod,
|
||||
float celestialAngle,
|
||||
float celestialPhase
|
||||
) {
|
||||
public static final double MIN_CELESTIAL_PERIOD = 0.2D;
|
||||
public static final double MAX_CELESTIAL_PERIOD = 2.0D;
|
||||
public static final float MIN_CELESTIAL_ANGLE = 0.0F;
|
||||
public static final float MAX_CELESTIAL_ANGLE = 360.0F;
|
||||
public static final float MIN_CELESTIAL_PHASE = 0.0F;
|
||||
public static final float MAX_CELESTIAL_PHASE = 1.0F;
|
||||
|
||||
public static final AgeTraits LEGACY_DEFAULTS = new AgeTraits(
|
||||
BiomeDistribution.NATIVE, Lighting.NORMAL, Weather.NORMAL,
|
||||
1.0D, 0.0F, 0.0F
|
||||
);
|
||||
|
||||
public AgeTraits {
|
||||
if (biomeDistribution == null || lighting == null || weather == null) {
|
||||
throw new IllegalArgumentException("Age trait choices cannot be null");
|
||||
}
|
||||
if (celestialPeriod < MIN_CELESTIAL_PERIOD || celestialPeriod > MAX_CELESTIAL_PERIOD) {
|
||||
throw new IllegalArgumentException("Celestial period is outside the legacy range");
|
||||
}
|
||||
if (celestialAngle < MIN_CELESTIAL_ANGLE || celestialAngle >= MAX_CELESTIAL_ANGLE) {
|
||||
throw new IllegalArgumentException("Celestial angle is outside the legacy range");
|
||||
}
|
||||
if (celestialPhase < MIN_CELESTIAL_PHASE || celestialPhase >= MAX_CELESTIAL_PHASE) {
|
||||
throw new IllegalArgumentException("Celestial phase is outside the legacy range");
|
||||
}
|
||||
}
|
||||
|
||||
public static AgeTraits select(long seed) {
|
||||
Random random = new Random(seed ^ 0x524956454E435241L);
|
||||
return new AgeTraits(
|
||||
randomChoice(random, BiomeDistribution.values()),
|
||||
randomChoice(random, Lighting.values()),
|
||||
randomChoice(random, Weather.values()),
|
||||
MIN_CELESTIAL_PERIOD
|
||||
+ random.nextDouble() * (MAX_CELESTIAL_PERIOD - MIN_CELESTIAL_PERIOD),
|
||||
random.nextFloat() * MAX_CELESTIAL_ANGLE,
|
||||
random.nextFloat()
|
||||
);
|
||||
}
|
||||
|
||||
public static <E extends Enum<E>> E parseOrDefault(String value, E fallback) {
|
||||
try {
|
||||
@SuppressWarnings("unchecked")
|
||||
Class<E> type = (Class<E>) fallback.getDeclaringClass();
|
||||
return Enum.valueOf(type, value);
|
||||
} catch (IllegalArgumentException exception) {
|
||||
return fallback;
|
||||
}
|
||||
}
|
||||
|
||||
private static <E> E randomChoice(Random random, E[] values) {
|
||||
return values[random.nextInt(values.length)];
|
||||
}
|
||||
|
||||
public enum BiomeDistribution {
|
||||
NATIVE, SINGLE, TILED, GRID, TINY, SMALL, MEDIUM, LARGE, HUGE
|
||||
}
|
||||
|
||||
public enum Lighting {
|
||||
NORMAL, DARK, BRIGHT
|
||||
}
|
||||
|
||||
public enum Weather {
|
||||
NORMAL, FAST, SLOW, OFF, ALWAYS, CLOUDY, RAIN, SNOW, STORM
|
||||
}
|
||||
}
|
||||
@@ -9,6 +9,7 @@ import net.dnorberg.rivencraft.book.AgeRegistrySavedData;
|
||||
import net.dnorberg.rivencraft.book.LinkTarget;
|
||||
import net.dnorberg.rivencraft.book.LinkingService;
|
||||
import net.dnorberg.rivencraft.book.AgeVisitSavedData;
|
||||
import net.dnorberg.rivencraft.book.AgeTraits;
|
||||
import net.dnorberg.rivencraft.item.DescriptiveBookItem;
|
||||
import net.dnorberg.rivencraft.item.LinkingBookItem;
|
||||
import net.dnorberg.rivencraft.registry.ModDataComponents;
|
||||
@@ -118,6 +119,11 @@ public final class LinkingGameTests {
|
||||
"A page-free book must select a supported legacy-inspired terrain profile");
|
||||
helper.assertValueEqual(first.generationVersion(), AgeDefinition.CURRENT_GENERATION_VERSION,
|
||||
"New Ages must record the current generation algorithm version");
|
||||
helper.assertValueEqual(first.traits(), AgeTraits.select(first.seed()),
|
||||
"A page-free book must persist the deterministic traits selected from its seed");
|
||||
helper.assertTrue(first.traits().celestialPeriod() >= AgeTraits.MIN_CELESTIAL_PERIOD
|
||||
&& first.traits().celestialPeriod() <= AgeTraits.MAX_CELESTIAL_PERIOD,
|
||||
"The celestial period must remain inside Mystcraft Legacy's random range");
|
||||
helper.assertTrue(first.seed() != another.seed(), "Distinct Age UUIDs must receive distinct random seeds");
|
||||
helper.succeed();
|
||||
}
|
||||
@@ -158,7 +164,8 @@ public final class LinkingGameTests {
|
||||
net.minecraft.resources.ResourceLocation.fromNamespaceAndPath(
|
||||
Rivencraft.MOD_ID, "gametest/" + profile.getPath() + "_" + id
|
||||
),
|
||||
null
|
||||
null,
|
||||
AgeTraits.select(id.getMostSignificantBits())
|
||||
);
|
||||
var level = AgeDimensionService.ensureLoaded(helper.getLevel().getServer(), definition);
|
||||
helper.assertTrue(level != null, "The " + profile + " profile must load a runtime dimension");
|
||||
|
||||
Reference in new issue
Block a user