-
Notifications
You must be signed in to change notification settings - Fork 0
Java API
A resource pack entry matches on the block and its blockstate, so a colour held anywhere else cannot be expressed: a lamp holding a dyed bulb, a colour stored in a block entity, a colour read from an attached machine. A mod supplies those from Java.
The API is the package xyz.atmerek.contraptionlights.api in its entirety. Nothing else in the mod is API, and everything else may move without notice.
Contraption Lights publishes no maven, so the jar goes on the compile classpath directly. It is required at compile time only.
dependencies {
compileOnly files("libs/contraption-lights-neoforge-1.21.1-<version>.jar")
}The dependency is declared optional, so the dependent mod still loads without it:
[[dependencies.yourmod]]
modId = "contraptionlights"
type = "optional"
ordering = "NONE"
side = "CLIENT"Every reference to the API must be confined to a single class, reached only after a presence check. Loading a class links the types it names, so a check written inside the class that uses the API executes too late and raises NoClassDefFoundError first.
if (ModList.get().isLoaded("contraptionlights")) {
MyLightColors.register();
}ContraptionLightsApi.registerLightColor(MY_LAMP.get(), (level, pos, state) -> {
if (level.getBlockEntity(pos) instanceof MyLampBlockEntity lamp) {
return lamp.getGlowColor();
}
return LightColorProvider.PASS;
});Registration belongs in client setup, after the block registry is populated.
| Call | Effect |
|---|---|
registerLightColor(Block, LightColorProvider) |
Colours one block. |
registerLightColor(LightColorProvider) |
Consulted for every light-emitting block, after any provider registered for that block in particular. |
lightColorChanged(Level, BlockPos) |
Redraws that position immediately. Optional; see colour changes. |
int lightColor(BlockGetter level, BlockPos pos, BlockState state);
default int lightColor(BlockState state, @Nullable CompoundTag nbt) {
return PASS;
}The return is 0xRRGGBB, or PASS to decline and defer to the ordinary lookup. PASS is 0, which is why pure black cannot be returned: it would be indistinguishable from declining, and a black light has no meaning.
Only the hue of the return is used. It is normalised so its brightest channel is full, and the block's light level determines range. The value does not pass through the saturation boost applied during texture derivation, a returned colour being authoritative.
The second method is consulted in place of the first when the block is riding a Create contraption, where no live block entity exists and only saved data is available. It defaults to PASS, so a block on a moving contraption falls back to its palette colour unless the method is implemented.
Providers are consulted in reverse registration order, most recent first, with per-block providers before catch-all ones. The first to return anything other than PASS wins.
A cycling entry for the same block outranks a provider, the cycle being resolved before any provider is consulted. Every other palette entry ranks below. See resolution order.
Called from the chunk building threads. A provider must be thread safe, must not modify the world, and must return quickly. It is invoked once per light-emitting block per section rebuild, which makes it a hot path: a map lookup and a field read is the appropriate shape, traversing a structure is not.
The position may not be loaded. Reading a block entity being replaced on another thread can throw. A provider that throws is logged once and then treated as PASS for that block, so a fault degrades to a wrong colour rather than a crash. That is a backstop, not a substitute for handling the case.
The colour must be stable. A colour that moves of its own accord forces a rebuild of the surrounding chunk each time the change is observed. Moving colours belong in a JSON cycle, which changes colour with no rebuild at all.
Colour only. A provider determines the colour of a light, never its brightness or its existence. A light level held in block entity data is a separate mechanism, served by the auxiliary light manager rather than by this API.
A change to block entity data is not a block change, so nothing would ordinarily redraw the surrounding chunk and the light would retain its previous colour.
No action is required for that. Every position at which a provider supplied a colour is recorded and rechecked approximately once a second; when the answer differs, the surrounding sections are redrawn. The recheck is spread across ticks, and positions whose block has changed or stopped emitting are dropped as they are visited.
lightColorChanged(level, pos) makes a change immediate rather than within a second. It is intended for the site that already handles the change, and costs nothing when the colour turns out to be unchanged.
A provider is consulted for a placed block, and for a block riding a Create contraption through the second method. Light originating from an item never reaches a provider: an item held in hand, in an item frame, or lying on the ground resolves from the block form of that item, with no position and no block entity to read. Such a light takes its colour from the palette, so a block whose colour lives in block data glows its palette colour while carried and its provider colour once placed.
There is no means of unregistering. A provider registered during client setup persists for the session, which is the only lifetime intended for it.