-
Notifications
You must be signed in to change notification settings - Fork 0
Resource Pack Colours
Any block can be given a light colour with a JSON file, including blocks this mod has no knowledge of. The same format colours entities, items and lights that belong to no block at all. The colours shipped for vanilla live in files of exactly the same kind and may be overridden the same way.
An entry colours a light that already exists. It never creates one and never changes how bright it is or how far it reaches. A block that emits no light stays dark whatever colour is written for it, and brightness comes from the block's light level, or from LambDynamicLights for anything that is not a placed block.
Coloured light is off by default. Nothing in any file has an effect until enableColoredLight is on, in config/contraptionlights-client.toml or in Sodium's Video Settings.
assets/<namespace>/contraptionlights/light_colors/<name>.json
Every namespace is scanned and every file in that directory is read, so a mod may ship one inside its own jar with no dependency on Contraption Lights and no coordination. The file name is not significant. Resource packs override in the usual order, and F3+T applies changes without a restart.
Each file is an object with a values array.
{
"values": [
{ "block": "#examplemod:cage_lamps", "color": "warm" },
{ "block": "examplemod:blue_cage_lamp", "color": "#30FFFF" },
{ "block": "examplemod:red_cage_lamp",
"from_texture": "examplemod:block/cage_lamp/bulb_red" },
{ "block": "minecraft:trial_spawner", "state": { "ominous": "true" }, "color": "#33D9FF" }
]
}That file gives a family of caged lamps a warm glow and then overrides two of them, one with an explicit colour and one by naming the texture of the bulb inside the cage for measurement. The final entry colours an ominous trial spawner without affecting an ordinary one.
required_mods sits beside values and names the mods the file's entries depend on. If any of them is absent the file is ignored in full, silently.
The gate is all or nothing, and it is applied before a single entry is read. No entry from that file is loaded, not even one naming a vanilla block, so entries that must survive a missing mod belong in a separate file. When every listed mod is present the file is read exactly as any other, and an unknown id in it is still an error.
{
"required_mods": ["examplemod", "othermod"],
"values": [
{ "block": "examplemod:lamp", "color": "#30FFFF" }
]
}This is what allows one mod or pack to carry colours for many others: one file per mod, each naming what its entries need, and the files for absent mods do nothing. Without it, an entry naming a block from a mod that is not installed is reported as an unknown block, since a typo and an absent mod are otherwise indistinguishable.
Two mods are named above because a block may exist only when both are present, one mod registering it for integration with the other.
Every entry names exactly one target, and naming two is an error.
| Target | Colours |
|---|---|
block |
A placed block, a block on a contraption, a block held or dropped as an item. |
entity |
An entity that emits light itself. See entities and items. |
item |
An item held, dropped or framed. See entities and items. |
behavior |
A light originating from no block at all. See lights with no block. |
special |
A light belonging to none of the above. See special lights. |
block, entity and item each accept #namespace:tag in place of an id to match a tag. An unknown id is an error; an unknown tag is not, since the tag may belong to a mod that is absent.
| Field | Required | Meaning |
|---|---|---|
color |
one of these two |
#RRGGBB or #RGB, the keywords warm or white, the keyword rainbow, or a cycle object. See cycling colours. |
from_texture |
one of these two | A texture id to measure in place of an explicit colour, for cases where the emissive sprite is known but its colour is not. Averaged by the procedure in derivation from a texture, so a largely grey sprite resolves to white. block entries only. |
state |
no | Restricts the entry to blocks whose blockstate properties hold these values. Values are written as strings, numbers and booleans included. block entries only. |
condition |
no | Restricts the entry to a setting being enabled. The only condition is colorful_candles. block entries only. |
emission |
no | Which of two lit items an entity holds decides its colour. 1 to 15, default 8. item entries only. |
priority |
no | Breaks ties between entries of equal specificity. Higher wins, default 0. |
A colour is either six hex digits or three, each of the three standing for a repeated pair, so #F80 and #FF8800 are the same colour. The leading # is optional. Three digits are enough for any colour the mod can store, the light being quantised to four bits a channel.
Only the hue is used, and the value is normalised as it is read, so #884422 and #FF8844 are stored identically. See a colour is a hue.
Where several entries match one block, the most specific wins.
| Entry | Specificity |
|---|---|
Block id with state
|
3 |
| Block id | 2 |
Tag with state
|
1 |
| Tag | 0 |
This is what prevents the two named lamps above from being overridden by the tag they belong to. Entries of equal specificity are settled by the higher priority, and entries of equal priority by whichever loaded last, which follows resource pack order. A block matched by nothing falls through to texture derivation.
Specificity is determined by the shape of an entry, not by the number of properties state names. One property and four properties are equally specific, so priority is the only way to separate two entries that both name state on the same block.
entity and item entries rank the same way with one step fewer, an id beating a tag, then priority, then load order.
A light that travels with an entity or an item takes its colour from an entry naming entity or item in place of block. These cover everything LambDynamicLights lights the world from that is not a placed block: a blaze, a dropped glow berry, a lava bucket in hand, a spectral arrow in flight, an item in a frame.
These lights exist only where LambDynamicLights is installed, that being what lights the world from an entity or an item, and only for the entities and items it already treats as light sources. An entry for anything else is loaded and simply never consulted, since there is no light to colour.
{
"values": [
{ "entity": "examplemod:will_o_wisp", "color": "#8CFFC8" },
{ "entity": "#examplemod:spirits", "color": "#8CFFC8" },
{ "item": "examplemod:ember_shard", "color": "#FF7A2E", "emission": 11 }
]
}An entity holding a lit item glows the colour of that item, and its own entity entry applies when nothing it holds is lit. Where more than one lit item is carried, counting both hands and the armour slots, the higher emission decides the colour. That is the only thing emission does: how bright the light is and how far it reaches remain LambDynamicLights' decision.
{
"values": [
{ "item": "examplemod:ember_shard", "color": "#FF7A2E", "emission": 11 },
{ "item": "examplemod:frost_lantern", "color": "#9CE8FF", "emission": 14 }
]
}A player carrying both glows pale blue, the lantern's 14 beating the shard's 11, and swapping the two numbers makes the same player glow orange. Either one alone decides the colour on its own, whatever its emission.
The ember shard also loses to a plain torch, whose 14 is the torch block's own light level. An item with no entry that places a light-emitting block takes both its colour and its rank from that block, so a torch needs nothing written for it, and emission exists for items that light the world without being blocks, where there is no block light level to compare.
A special entry colours a light belonging to no block, entity or item in particular. The only one is burning, the flames on any entity that is on fire, which outranks everything else about that entity.
{
"values": [
{ "special": "burning", "color": "#FF7024" }
]
}A color of rainbow moves a block through the spectrum. An object defines an arbitrary cycle.
{
"values": [
{ "block": "examplemod:disco_lamp", "color": "rainbow" },
{ "block": "examplemod:hearth", "color": { "cycle": ["#FF7B2E", "#FF3C00"], "period": 60 } }
]
}| Field | Default | Meaning |
|---|---|---|
cycle |
required | The colours to move between, in order, looping back to the first. Two colours produce a fade back and forth. |
period |
200 | Ticks per full loop. Must be at least 1. |
The colour is the only thing that moves. Brightness is constant, which is what allows the change with no chunk rebuild, and a cycling light blends with fixed lights and with the other cycle exactly as two fixed lights do.
Two cycles may be loaded at once. Any number of blocks may share either, and blocks sharing a cycle move together, in step. Two entries count as the same cycle when their colours and their period are both identical, so rainbow used a hundred times still occupies one slot. A third distinct cycle is loaded at the average of its own colours instead of moving, and a log line names the block it belonged to.
Any target may cycle. Blocks, entities, items, behaviour lights and burning all take a cycle in place of a fixed color, and all of them draw on the same two slots.
The animatedLightColors setting disables all of this, holding every cycling light at the average of its own colours.
A mod may light the world through LambDynamicLights with no glowing block behind it: a flashlight, a searchlight, a beam. These glow warm by default, and an entry with behavior in place of block assigns one a colour.
{
"values": [
{ "behavior": "*", "color": "#FFEEDD" },
{ "behavior": "com.example.mod.light.FlashlightBehavior", "color": "white" }
]
}The target is * for every such light at once, or the fully qualified Java class name of one of them, which the mod that adds it will know. A named class takes precedence over *, and ties are settled by priority then load order.
Only color and priority apply. A behaviour entry may not use from_texture, there being no model to read, and may not also carry block. Cycles are available here and occupy the same two slots.
A rejected entry never fails the reload. It is skipped individually, the log names the file and the fault, and an on-screen message reports how many were dropped. A blockstate property or value that does not exist is reported the same way, with the valid names listed.
Rejection cases:
- An unknown block, entity type or item id, so that a typo does not silently do nothing.
required_modsnever makes such an id acceptable, it removes the situation instead, by dropping the whole file before any id is looked up. - A
statenaming a property the block does not have, or a value that property cannot take. - An entry with neither
colornorfrom_texture, or with nocolorwherefrom_texturedoes not apply. - A
colorthat is not six or three hex digits, a keyword, or a cycle object. - A
periodof zero or less. - An
emissionoutside 1 to 15. - An unknown
condition, or an unknownspecial. - A
behaviorthat is neither*nor a string containing a dot, since it cannot be a class name. - An entry naming two targets, or using a field that its target does not accept.
A required_mods that is not an array is a fault in the file rather than in one entry, and drops the file with a line in the log.