LambdAurora

Modding Interfaces

Go back to index

As a modder you might need to interact more directly with LambDynamicLights' API through Java interfaces.

There interfaces will allow you to:

  • register new entity luminance providers for use in entity lighting JSON files;
  • query lighting of an item or an entity;
  • or bypass the JSON files and directly register item or entity lighting through registration events.

Table of Content

  1. Getting Started
  2. Register an Entity Luminance Provider
  3. Query Dynamic Light Values
  4. Listen for Item or Entity Lighting Registration
  5. Add Custom Dynamic Light Sources

Getting Started

If you haven't already followed the steps to set up your Gradle buildscript, please head back to the section For Mod Development Environments of the main page to do so.

Once you have the LambDynamicLights API in your development environment we can start by setting up the basics.

This API's design uses Fabric's entrypoint philosophy which allows declaring that one part of your code will be initialized directly by LambDynamicLights. This design allows mod-loaders to not depend on an initialization order.
This design choice should be upheld by NeoForge ports as well, even if not the convention in that ecosystem.

For multi-loader modders: the API is multi-loader! This means you can directly add it to your common project, and it should work as-is.

Let's create our own LambDynamicLights initializer as follows:

public class YourModDynamicLightsInitializer implements DynamicLightsInitializer {
	@Override
	void onInitializeDynamicLights(
		DynamicLightsContext context
	) {
		// Code related to dynamic lighting here.
	}
}

On its own, this initializer won't do much. The code to execute when LambDynamicLights is present will be in the onInitializeDynamicLights method, which gives two arguments: the item light source manager, and the entity light source manager. Both of these objects will allow you to query values or add registration listeners.

But this Java code isn't enough for the initializer to be known by LambDynamicLights, we also need to declare the initializer in your mod's manifest file.

On Fabric, this translates into adding in the entrypoints field of your fabric.mod.json file the following:

	"entrypoints": {
		"lambdynlights:initializer": [
			"<package>.YourModDynamicLightsInitializer"
		]
	}

On NeoForge, this translates into adding in the modproperties table of your neoforge.mods.toml file the following:

[[mods]]
# Stuff

[modproperties.${mod_id}]
	"lambdynlights:initializer" = "<package>.YourModDynamicLightsInitializer"
Keep in mind that LambDynamicLights is a client-side mod, this means you will not have access to the API on the server, and code in your dynamic lights initializer will not be executed either.

Register an Entity Luminance Provider

Entity luminance providers are composed of a method to compute the luminance given an entity and of a Codec which allows the luminance provider to be used in entity lighting JSON files.

To make our own, let's start by creating a new class:

public record CustomEntityLuminance(boolean invert) implements EntityLuminance {
	// The Codec of this entity luminance provider,
	// this describes how to parse the JSON file.
	public static final MapCodec<CustomEntityLuminance> CODEC = RecordCodecBuilder.mapCodec(
			instance -> instance.group(
				Codec.BOOL.fieldOf("invert").forGetter(CustomEntityLuminance::invert)
			).apply(instance, CustomEntityLuminance::new)
	);

	@Override
	public Type type() {
		// This is the registered type of this entity luminance provider.
		// We will modify the initializer to reflect this.
		return YourModDynamicLightsInitializer.CUSTOM_ENTITY_LUMINANCE;
	}

	@Override
	public @Range(from = 0, to = 15) int getLuminance(
		ItemLightSourceManager itemLightSourceManager,
		Entity entity
	) {
		// Here we compute the luminance the given entity should emit.
		// We also have access to the item light source manager,
		// in case our luminance depends on the luminance of an item.
		boolean isNight = this.invert ? entity.level().isDay() : entity.level().isNight();

		return isNight ? 10 : 0;
	}
}

We have created the luminance provider implementation, now we have to register it in the initializer:

public class YourModDynamicLightsInitializer implements DynamicLightsInitializer {

	public static final EntityLuminance.Type CUSTOM_ENTITY_LUMINANCE
		= EntityLuminance.Type.register(
			Identifier.of("<your namespace>", "custom"),
			CustomEntityLuminance.CODEC
		);

	// Initializer code
}

Now that it is registered we can use it in any JSON file with this snippet:

{
	"type": "<your namespace>:custom",
	"invert": false
}

If your luminance provider doesn't take any arguments and only is a singleton, we can simplify the code and get rid of the Codec altogether:

public final class ConstantEntityLuminance implements EntityLuminance {
	// The singleton instance.
	public static final ConstantEntityLuminance INSTANCE = new ConstantEntityLuminance();

	private ConstantEntityLuminance() {}

	@Override
	public Type type() {
		// This is the registered type of this entity luminance provider.
		return YourModDynamicLightsInitializer.CONSTANT;
	}

	@Override
	public @Range(from = 0, to = 15) int getLuminance(
		ItemLightSourceManager itemLightSourceManager,
		Entity entity
	) {
		return 5;
	}
}

// And in your initializer file:
public class YourModDynamicLightsInitializer implements DynamicLightsInitializer {

	public static final EntityLuminance.Type CONSTANT
		= EntityLuminance.Type.registerSimple(
			Identifier.of("<your namespace>", "custom"),
			ConstantEntityLuminance.INSTANCE
		);

	// Initializer code
}

Query Dynamic Light Values

You might have noticed the DynamicLightsContext object earlier, this gives access to the dynamic lighting context which allows to query the dynamic light value of a given item or a given entity:

int lightOfTorch = context.itemLightSourceManager().getLuminance(
		new ItemStack(Items.TORCH), 
		/* submerged in water */ false
	);

Entity cow = /* get a cow */;
int lightOfCow = context.entityLightSourceManager().getLuminance(cow);

It is currently not possible to query the dynamic light value of a precise position in the world from the API.

Listen for Item or Entity Lighting Registration

If for some reason the JSON way doesn't fit your use-case, it is possible to register the same data through Java code:

context.itemLightSourceManager().onRegisterEvent().register(context -> {
	// You have registry access through context.registryAccess()
	
	// Register item lighting with any of the context.register() overloads.
	context.register(Items.ALLIUM, 5);
});

context.entityLightSourceManager().onRegisterEvent().register(context -> {
	// You have registry access through context.registryAccess()
	
	// Register entity lighting with any of the context.register() overloads.
	context.register(EntityType.ARMADILLO,
		new ItemDerivedEntityLuminance(
			new ItemStack(Items.TORCH),
			/* include rain? */ false,
			Optional.empty()
		)
	);
});

For those familiar with Fabric-style events, while this API is multi-loader, it is using the Yumi Commons Event framework, which is based off the Fabric event framework. This means it can be used similarly, and it will let you order your listeners if needed.

Add Custom Dynamic Light Sources

Work-in-Progress

Sorry but this part of the documentation is currently work-in-progress.

However, the mod provides Javadocs about this feature so it's not impossible to figure it out. Additionally, you can submit GitHub issues or seek support on the Discord server if needed.