Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package net.onelitefeather.cygnus.common.dimension;

import net.kyori.adventure.key.Key;
import net.minestom.server.MinecraftServer;
import net.minestom.server.particle.Particle;
import net.minestom.server.registry.RegistryKey;
import net.minestom.server.world.DimensionType;
import net.minestom.server.world.attribute.AmbientParticle;
import net.minestom.server.world.attribute.EnvironmentAttribute;
import org.jetbrains.annotations.Contract;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.List;

/**
* Small factory class to create custom {@link RegistryKey<DimensionType>} instances from custom dimension presets.
*
* @author Joltra
* @version 1.0.0
* @since 2.6.6
*/
public final class DimensionFactory {

private static final Logger LOGGER = LoggerFactory.getLogger(DimensionFactory.class);

private DimensionFactory() {
throw new UnsupportedOperationException();
}

public static void registerAll() {
for (StaticDimensionPreset value : StaticDimensionPreset.getValues()) {
RegistryKey<DimensionType> dimensionType = create(value);
LOGGER.info("Registered dimension preset: {}", dimensionType.key());
}
}

/**
* Creates a new dimension type based on the given preset.
*
* @param preset which should be created
* @return the created dimension type
*/
@Contract(value = "_ -> new", pure = true)
public static RegistryKey<DimensionType> create(DimensionPreset preset) {
DimensionType type = DimensionType.builder()
.setAttribute(EnvironmentAttribute.FOG_START_DISTANCE, preset.fogStartDistance())
.setAttribute(EnvironmentAttribute.FOG_END_DISTANCE, preset.fogEndDistance())
.setAttribute(EnvironmentAttribute.SKY_FOG_END_DISTANCE, preset.skyFogEndDistance())
.setAttribute(EnvironmentAttribute.FOG_COLOR, preset.fogColor())
.setAttribute(EnvironmentAttribute.SKY_COLOR, preset.skyColor())
.setAttribute(EnvironmentAttribute.SKY_LIGHT_COLOR, preset.skyLightColor())
.setAttribute(EnvironmentAttribute.SKY_LIGHT_FACTOR, preset.skyLightFactor())
.setAttribute(EnvironmentAttribute.AMBIENT_PARTICLES, List.of(
new AmbientParticle(Particle.SOUL, 0.01f),
new AmbientParticle(Particle.SOUL_FIRE_FLAME, 0.001f)
))
.setAttribute(EnvironmentAttribute.SUN_ANGLE, 180f)
.setAttribute(EnvironmentAttribute.MOON_ANGLE, 180f)
.defaultClock(DimensionType.OVERWORLD.asValue().defaultClock())
.build();
return MinecraftServer.getDimensionTypeRegistry().register(Key.key("cygnus", preset.getKey()), type);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package net.onelitefeather.cygnus.common.dimension;

import net.kyori.adventure.util.RGBLike;


/**
* Describes which preset values are required for a custom Dimension in Minestom.
* It contains only data about the fog and sky colors, and nothing else.
* If you also want to adjust your biome, that is an additional step that is not covered here.
*
* @author thEvilReaper
* @version 1.0.0
* @since 2.6.6
*/
public interface DimensionPreset {

/**
* A short, unique, lowercase identifier for this preset, used wherever
* the preset needs to be referenced by name instead of by object
* reference, e.g. in configs or when registering the dimension.
*/
String getKey();

/**
* The color of the fog itself.
*/
RGBLike fogColor();

/**
* The color of the light that appears to come down from the sky.
*/
RGBLike skyLightColor();

/**
* The sky's own background color.
*/
RGBLike skyColor();

/**
* How strongly sky-light affects the dimension. Higher values feel
* brighter and more open; values near zero feel dim and enclosed even
* without much fog.
*/
float skyLightFactor();

/**
* The distance at which fog starts to become noticeable.
*/
float fogStartDistance();

/**
* The distance beyond which the fog is fully opaque.
*/
float fogEndDistance();

/**
* Like {@link #fogEndDistance()}, but for the sky-colored fog seen at
* the horizon rather than the regular ground fog.
*/
float skyFogEndDistance();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
package net.onelitefeather.cygnus.common.dimension;

import net.kyori.adventure.util.RGBLike;
import net.onelitefeather.cygnus.common.util.ColorUtil;

import java.util.Random;

/**
* A {@link DimensionPreset} that is generated deterministically from a seed.
* <p>
* The same seed always produces the same atmosphere, making these presets
* suitable for procedural worlds while keeping their appearance consistent
* across sessions.
*
* @version 1.0.0
* @since 2.6.6
* @author theEvilReaper
*/
public record SeedDimensionPreset(
String key,
RGBLike fogColor,
RGBLike skyLightColor,
RGBLike skyColor,
float skyLightFactor,
float fogStartDistance,
float fogEndDistance,
float skyFogEndDistance
) implements DimensionPreset {

// Parameter bounds derived from the predefined DimensionPreset values.
// Keeping generated presets within these ranges prevents atmospheres
// from becoming excessively bright, dark, or foggy.
private static final float MIN_SKY_LIGHT_FACTOR = 0.002f;
private static final float MAX_SKY_LIGHT_FACTOR = 0.06f;

private static final float MIN_FOG_START = 0f;
private static final float MAX_FOG_START = 64f;

private static final float MIN_FOG_END = 24f;
private static final float MAX_FOG_END = 384f;

private static final float MIN_SKY_FOG_END = 16f;
private static final float MAX_SKY_FOG_END = 256f;

/**
* Creates a deterministic dimension preset from the given seed.
* <p>
* The seed determines both the base hue and a density value. The density
* controls visibility, lighting, and color intensity, while small hue
* offsets keep the fog, skylight, and sky colors visually related.
*
* @param seed any stable seed, such as a world seed or hashed dimension name
* @return the generated dimension preset
*/
public static SeedDimensionPreset fromSeed(long seed) {
Random random = new Random(seed);

float hue = random.nextFloat() * 360f;
float density = random.nextFloat(); // 0 = open/bright, 1 = dense/dark

float skyLightFactor = lerp(MAX_SKY_LIGHT_FACTOR, MIN_SKY_LIGHT_FACTOR, density);
float fogStartDistance = lerp(MAX_FOG_START, MIN_FOG_START, density);
float fogEndDistance = lerp(MAX_FOG_END, MIN_FOG_END, density);
float skyFogEndDistance = lerp(MAX_SKY_FOG_END, MIN_SKY_FOG_END, density);

float fogHue = hue;
float skyLightHue = wrapHue(hue + 8f);
float skyHue = wrapHue(hue - 6f);

RGBLike fogColor = ColorUtil.hsl(
fogHue,
lerp(0.55f, 0.25f, density),
lerp(0.42f, 0.14f, density)
);

RGBLike skyLightColor = ColorUtil.hsl(
skyLightHue,
lerp(0.75f, 0.45f, density),
lerp(0.72f, 0.32f, density)
);

RGBLike skyColor = ColorUtil.hsl(
skyHue,
lerp(0.55f, 0.35f, density),
lerp(0.16f, 0.03f, density)
);

String key = "seed_" + Long.toHexString(seed);

return new SeedDimensionPreset(
key,
fogColor,
skyLightColor,
skyColor,
skyLightFactor,
fogStartDistance,
fogEndDistance,
skyFogEndDistance
);
}

/**
* Performs linear interpolation between {@code a} and {@code b}.
*/
private static float lerp(float a, float b, float t) {
return a + (b - a) * t;
}

/**
* Wraps a hue into the {@code [0, 360)} range.
*/
private static float wrapHue(float hue) {
float h = hue % 360f;
return h < 0f ? h + 360f : h;
}

/**
* Adapts the record component accessor to the {@link DimensionPreset}
* naming convention.
*/
@Override
public String getKey() {
return key;
}
}
Loading
Loading