genesis

Implementation Guide: Creating Celestials

Implementation Guide: Creating Celestials


Genesis allows you to add custom stars and planets (celestials) to the solar system through JSON configuration files or programmatically through code.

Setup

Datapack Setup

Celestial configurations are stored in JSON files within your datapack’s system_config directory:

data/
└── <namespace>/
    └── system_config/
        └── <filename>.json

Examples:

You can have multiple JSON files - all celestials from all files will be loaded and registered.

Basic JSON Structure:

{
  "celestials": [
    {
      "ID": "namespace:celestial_id",
      "type": "namespace:type_id",
      "size": 1.0,
      "gravity": 1.0,
      "transformProvider": {
        "type": "provider_type",
        ...
      }
    }
  ]
}

Code Setup

Genesis provides an event-based system for registering celestials. Subscribe to the event during your mod’s initialization:

import shipwrights.genesis.GenesisMod;
import shipwrights.genesis.space.registry.SpaceRegistry;

public class YourMod {
    public static void init() {
        GenesisMod.onRegisterCelestialsEvent(YourMod::registerCelestials);
    }

    private static void registerCelestials(SpaceRegistry.RegisterCelestialsEvent event) {
        // Register your celestials here
    }
}

Location in Genesis source: src/main/java/shipwrights/genesis/GenesisMod.java:88-90


Creating Your First Celestial: A Simple Star

Let’s create a star at the center of your solar system. Stars are celestial bodies that emit light and affect day/night cycles on orbiting bodies.

In Datapacks

{
  "celestials": [
    {
      "ID": "mymod:sun",
      "type": "genesis:star",
      "size": 15.0,
      "gravity": 1.0,
      "transformProvider": {
        "type": "genesis:static",
        "x": 0.0,
        "y": 0.0,
        "z": 0.0
      }
    }
  ]
}

In Code

import net.minecraft.resources.ResourceLocation;
import shipwrights.genesis.space.Celestial;
import shipwrights.genesis.space.type.CelestialType;
import shipwrights.genesis.space.transformProvider.StaticTransformProvider;

private static void registerCelestials(SpaceRegistry.RegisterCelestialsEvent event) {
    // Create a static transform at the origin
    StaticTransformProvider sunTransform = new StaticTransformProvider(0, 0, 0);

    // Create the star celestial
    Celestial sun = new Celestial(
        sunTransform,
        ResourceLocation.parse("mymod:sun"),
        CelestialType.get(ResourceLocation.parse("genesis:star")),
        15.0,   // Large size
        1.0    // Standard gravity
    );

    // Register it
    event.accept(sun);
}

Explanation


Creating an Orbiting Planet

Now let’s add a planet that orbits around your sun. Planets use the orbiting transform provider to move in a circular orbit around a parent celestial.

In Datapacks

{
  "celestials": [
    {
      "ID": "mymod:sun",
      "type": "genesis:star",
      "size": 15.0,
      "gravity": 1.0,
      "transformProvider": {
        "type": "genesis:static",
        "x": 0.0,
        "y": 0.0,
        "z": 0.0
      }
    },
    {
      "ID": "mymod:earth",
      "type": "genesis:body",
      "size": 1.0,
      "gravity": 1.0,
      "transformProvider": {
        "type": "genesis:orbiting",
        "parentID": "mymod:sun",
        "seed": 12345,
        "orbitDistance": 1.0,
        "orbitTime": 1.0
      }
    }
  ]
}

In Code

private static void registerCelestials(SpaceRegistry.RegisterCelestialsEvent event) {
    // Register the sun first (same as previous example)
    StaticTransformProvider sunTransform = new StaticTransformProvider(0, 0, 0);
    Celestial sun = new Celestial(
        sunTransform,
        ResourceLocation.parse("mymod:sun"),
        CelestialType.get(ResourceLocation.parse("genesis:star")),
        15.0, 1.0
    );
    event.accept(sun);

    // Create an orbiting planet
    OrbitingTransformProvider planetTransform = new OrbitingTransformProvider(
        ResourceLocation.parse("mymod:sun"),  // parentID
        12345,      // seed
        1.0,        // orbitDistance multiplier
        1.0,        // orbitTime multiplier
        1.0         // dayLength multiplier
    );

    Celestial planet = new Celestial(
        planetTransform,
        ResourceLocation.parse("mymod:earth"),
        CelestialType.get(ResourceLocation.parse("genesis:body")),
        1.0,    // Earth-sized
        1.0     // Earth gravity
    );
    event.accept(planet);
}

Explanation


Adding a Moon

Moons orbit planets, not the sun. This creates a hierarchical orbital system where the moon follows the planet as it orbits.

In Datapacks

{
  "celestials": [
    {
      "ID": "mymod:sun",
      "type": "genesis:star",
      "size": 15.0,
      "gravity": 1.0,
      "transformProvider": {
        "type": "genesis:static",
        "x": 0.0,
        "y": 0.0,
        "z": 0.0
      }
    },
    {
      "ID": "mymod:earth",
      "type": "genesis:body",
      "size": 1.0,
      "gravity": 1.0,
      "transformProvider": {
        "type": "genesis:orbiting",
        "parentID": "mymod:sun",
        "seed": 12345,
        "orbitDistance": 1.0,
        "orbitTime": 1.0
      }
    },
    {
      "ID": "mymod:moon",
      "type": "genesis:body",
      "size": 0.3,
      "gravity": 0.1622,
      "transformProvider": {
        "type": "genesis:orbiting",
        "parentID": "mymod:earth",
        "seed": 67890,
        "orbitDistance": 0.05,
        "orbitTime": 0.005,
        "dayLength": 0.75
      }
    }
  ]
}

In Code

private static void registerCelestials(SpaceRegistry.RegisterCelestialsEvent event) {
    // Register sun (as above)
    // ...

    // Register planet (as above)
    // ...

    // Create a moon orbiting the planet
    OrbitingTransformProvider moonTransform = new OrbitingTransformProvider(
        ResourceLocation.parse("mymod:earth"),  // Orbit the planet, not the sun!
        67890,      // Different seed for different orbit
        0.05,       // Much closer orbit
        0.005,      // Much faster orbit
        0.75        // Slower day length
    );

    Celestial moon = new Celestial(
        moonTransform,
        ResourceLocation.parse("mymod:moon"),
        CelestialType.get(ResourceLocation.parse("genesis:body")),
        0.3,        // Smaller size
        0.1622      // Moon gravity (about 1/6 Earth)
    );
    event.accept(moon);
}

Explanation


Transform Providers

Transform providers control how a celestial moves and rotates over time. Genesis includes two built-in providers: static and orbiting.

Static Transform Provider

Use Case: For celestials that stay in one place, like a sun at the center of a solar system.

In Datapacks

Position Only:

"transformProvider": {
  "type": "genesis:static",
  "x": 0.0,
  "y": 0.0,
  "z": 0.0
}

Position with Rotation:

"transformProvider": {
  "type": "genesis:static",
  "x": 0.0,
  "y": 0.0,
  "z": 0.0,
  "xRot": 0.0,
  "yRot": 0.0,
  "zRot": 0.0
}

In Code

import shipwrights.genesis.space.transformProvider.StaticTransformProvider;

// Position only
StaticTransformProvider transform1 = new StaticTransformProvider(x, y, z);

// Position with rotation (radians)
StaticTransformProvider transform2 = new StaticTransformProvider(
    x, y, z,
    xRot, yRot, zRot
);

Property Reference

Field/Parameter Type Required Default Description
type String Yes - Must be "genesis:static"
x / first param Number/double Yes - X coordinate
y / second param Number/double Yes - Y coordinate
z / third param Number/double Yes - Z coordinate
xRot / fourth param Number/double No 0.0 Rotation around X-axis (radians)
yRot / fifth param Number/double No 0.0 Rotation around Y-axis (radians)
zRot / sixth param Number/double No 0.0 Rotation around Z-axis (radians)

Orbiting Transform Provider

Use Case: For celestials that orbit around a parent body, like planets orbiting a sun or moons orbiting a planet.

In Datapacks

"transformProvider": {
  "type": "genesis:orbiting",
  "parentID": "namespace:parent_celestial",
  "seed": 12345,
  "orbitDistance": 1.0,
  "orbitTime": 1.0,
  "dayLength": 1.0
}

In Code

import shipwrights.genesis.space.transformProvider.OrbitingTransformProvider;

OrbitingTransformProvider transform = new OrbitingTransformProvider(
    parentID,          // ResourceLocation - ID of parent celestial
    seed,              // int - deterministic random seed
    orbitDistance,     // double - multiplier (base: 15,000 blocks)
    orbitTime,         // double - multiplier (base: 4,608,000 ticks)
    dayLength          // double - multiplier (base: 24,000 ticks)
);

Property Reference

Field/Parameter Type Required Default Description
type String Yes - Must be "genesis:orbiting"
parentID / first param String/ResourceLocation Yes - ID of the celestial to orbit around
seed / second param Integer/int Yes - Random seed for orbital angles and rotation
orbitDistance / third param Number/double Yes - Orbit distance multiplier (base: 15,000 blocks)
orbitTime / fourth param Number/double Yes - Orbital period multiplier (base: 4,608,000 ticks)
dayLength / fifth param Number/double No 1.0 Day length multiplier (base: 24,000 ticks)

Understanding the Multipliers

The orbiting transform provider uses base constants that are multiplied by your values:

These base values are defined in the Celestial class as BASE_ORBIT_DISTANCE, BASE_ORBIT_TIME, and BASE_DAY_LENGTH.


Celestial Types

Celestial types define the behavioral properties and rendering of celestials. They determine whether a celestial emits light, casts shadows, and whether players can visit it.

Built-in Types

Genesis provides two built-in celestial types:

genesis:star

genesis:body

In Datapacks

Specify the type using its resource location ID:

{
  "ID": "mymod:sun",
  "type": "genesis:star",
  ...
}

or

{
  "ID": "mymod:earth",
  "type": "genesis:body",
  ...
}

In Code

Retrieve types using CelestialType.get():

import net.minecraft.resources.ResourceLocation;
import shipwrights.genesis.space.type.CelestialType;

// Star type - emits light, not visitable
CelestialType star = CelestialType.get(ResourceLocation.parse("genesis:star"));

// Body type - solid, visitable, casts shadows
CelestialType body = CelestialType.get(ResourceLocation.parse("genesis:body"));

Custom Types

For creating your own celestial types with custom rendering and behavior, see the Advanced Topics guide.


Understanding Properties

Every celestial has physical properties that define its size, gravity, and appearance. These properties work the same way in both datapacks and code.

Size

Description: Size multiplier on the base diameter of 96 blocks.

Examples:

Usage:

Gravity

Description: Gravity strength relative to Earth (1.0 = Earth gravity).

Examples:

Usage:

Color (RGB)

Description: Color components ranging from 0.0 to 1.0. Currently has limited use but will have future applications for rendering and effects.

Examples:

Usage:

Base Constants

Genesis defines several base constants used as multipliers throughout the system:

Constant Value Description
BASE_SIZE 96 blocks Base celestial diameter
BASE_ORBIT_DISTANCE 15,000 blocks Base orbital distance
BASE_ORBIT_TIME 4,608,000 ticks Base orbital period (≈ 64 hours)
BASE_DAY_LENGTH 24,000 ticks Base rotation period (20 minutes)

In Code: These are accessible as static fields on the Celestial class:

import shipwrights.genesis.space.Celestial;

double actualSize = sizeMultiplier * Celestial.BASE_SIZE;
double actualDistance = distanceMultiplier * Celestial.BASE_ORBIT_DISTANCE;

Textures

Note: This section applies to resource packs or mods (client-side assets). Textures work with celestials defined in either datapacks or code.

Custom textures can be added for celestial bodies using the genesis:body type (planets and moons). The planet renderer automatically looks for textures based on the celestial’s ID.

Texture Location

Important: Textures are client-side assets and must be added via a resource pack or mod (not a datapack). Your datapack provides the celestial configuration (JSON), while textures are provided separately through client-side resources.

Place PNG texture files in a resource pack or mod:

assets/<namespace>/textures/planets/<namespace>/<body_name>.png

Examples (in a resource pack or mod):

The texture path is automatically derived from the body’s ID. For a celestial with ID mymod:custom_planet, the renderer looks for:

assets/genesis/textures/planets/mymod/custom_planet.png

Workflow: Define your celestial in a datapack JSON (server-side), then add matching textures in a resource pack (client-side). If no texture is found, the body will be rendered using the RGB color values specified in the configuration.

Texture Layout

Planet and moon textures use a cube map layout arranged in a 3×2 grid. The texture should be divided into 6 equal sections representing the faces of a cube:

Top Row (upper half of texture):

Bottom Row (lower half of texture):

┌─────────┬─────────┬─────────┐
│  North  │  West   │  South  │  ← Top row
├─────────┼─────────┼─────────┤
│  East   │  Down   │   Up    │  ← Bottom row
└─────────┴─────────┴─────────┘

Texture Guidelines

When creating your texture:


Querying Celestials

Note: This section is specific to code/mod development.

Once celestials are registered, you can retrieve and query them using the SpaceRegistry class.

Getting a Specific Celestial

import shipwrights.genesis.space.registry.SpaceRegistry;
import shipwrights.genesis.space.Celestial;
import net.minecraft.resources.ResourceLocation;

// Get a specific celestial by ID
Celestial sun = SpaceRegistry.get(ResourceLocation.parse("genesis:sun"));

Getting All Celestials

import java.util.List;

// Get all registered celestials
List<Celestial> allCelestials = SpaceRegistry.getAll();

Filtering Celestials by Type

// Get all stars
List<Celestial> stars = SpaceRegistry.getWhere(type ->
    type.castsLight()
);

// Get all visitable bodies (planets and moons)
List<Celestial> planets = SpaceRegistry.getWhere(type ->
    type.isVisitable()
);

// Get celestials of a specific type
List<Celestial> bodies = SpaceRegistry.getWhere(type ->
    type.getID().equals(ResourceLocation.parse("genesis:body"))
);

Complete Example: Genesis Solar System

Here’s the complete default solar system that comes with Genesis, showing how everything comes together.

In Datapacks

From builtin.json:

{
  "celestials": [
    {
      "ID": "genesis:sun",
      "type": "genesis:star",
      "size": 15.0,
      "gravity": 1.0,
      "transformProvider": {
        "type": "genesis:static",
        "x": 0.0,
        "y": 0.0,
        "z": 0.0
      }
    },
    {
      "ID": "minecraft:overworld",
      "type": "genesis:body",
      "size": 1.0,
      "gravity": 1.0,
      "transformProvider": {
        "type": "genesis:orbiting",
        "parentID": "genesis:sun",
        "seed": 12345,
        "orbitDistance": 1.0,
        "orbitTime": 1.0
      }
    },
    {
      "ID": "genesis:moon",
      "type": "genesis:body",
      "size": 0.3,
      "gravity": 0.1622,
      "transformProvider": {
        "type": "genesis:orbiting",
        "parentID": "minecraft:overworld",
        "seed": 67890,
        "orbitDistance": 0.05,
        "orbitTime": 0.005,
        "dayLength": 0.75
      }
    }
  ]
}

This creates:

In Code (Equivalent)

private static void registerCelestials(SpaceRegistry.RegisterCelestialsEvent event) {
    // Sun
    StaticTransformProvider sunTransform = new StaticTransformProvider(0, 0, 0);
    Celestial sun = new Celestial(
        sunTransform,
        ResourceLocation.parse("genesis:sun"),
        CelestialType.get(ResourceLocation.parse("genesis:star")),
        15.0, 1.0,
        1.0f, 1.0f, 1.0f
    );
    event.accept(sun);

    // Overworld
    OrbitingTransformProvider overworldTransform = new OrbitingTransformProvider(
        ResourceLocation.parse("genesis:sun"),
        12345, 1.0, 1.0, 1.0
    );
    Celestial overworld = new Celestial(
        overworldTransform,
        ResourceLocation.parse("minecraft:overworld"),
        CelestialType.get(ResourceLocation.parse("genesis:body")),
        1.0, 1.0,
        0.8f, 0.8f, 0.8f
    );
    event.accept(overworld);

    // Moon
    OrbitingTransformProvider moonTransform = new OrbitingTransformProvider(
        ResourceLocation.parse("minecraft:overworld"),
        67890, 0.05, 0.005, 0.75
    );
    Celestial moon = new Celestial(
        moonTransform,
        ResourceLocation.parse("genesis:moon"),
        CelestialType.get(ResourceLocation.parse("genesis:body")),
        0.3, 0.1622,
        0.7f, 0.7f, 0.7f
    );
    event.accept(moon);
}

Next Steps