Lighting system

This commit is contained in:
2026-09-25 15:40:09 -03:00
parent 25f8c683bb
commit 4539898c58
12 changed files with 634 additions and 349 deletions
+14
View File
@@ -98,6 +98,16 @@ interface BlockStateVariant {
export const RENDER_LAYERS = ["solid", "cutout", "translucent"] as const;
export type RenderLayer = typeof RENDER_LAYERS[number];
// like minecraft: solid blocks stop light, everything else lets it through unless it says otherwise
export function block_light_opacity(block: BlockRegistry | undefined): number {
if (!block) return 0;
return block.light_opacity ?? ((block.render_layer ?? "solid") === "solid" ? 15 : 0);
}
export function block_light_emission(block: BlockRegistry | undefined): number {
return block?.light_emission ?? 0;
}
export interface BlockRegistry {
id: string;
textures: string | TextureSideTopBottom | TextureFront;
@@ -105,6 +115,10 @@ export interface BlockRegistry {
render_layer?: RenderLayer;
// hide faces between two of this block, like glass and water. defaults to true for translucent blocks
cull_same?: boolean;
// light level 0-15 it gives off
light_emission?: number;
// how much light going through it loses, 0-15. see block_light_opacity for the default
light_opacity?: number;
alpha?: number;
has_collision: boolean;
+12
View File
@@ -33,6 +33,8 @@ export interface BlockJson {
textures: BlockTextures;
render_layer?: RenderLayer;
cull_same?: boolean;
light_emission?: number;
light_opacity?: number;
// replaced by render_layer, true means translucent
transparent?: boolean;
alpha?: number;
@@ -89,6 +91,8 @@ export function block_to_json(block: BlockRegistry, has_item: boolean): BlockJso
const json: BlockJson = { id: block.id, textures: block.textures };
if (block.render_layer && block.render_layer !== "solid") json.render_layer = block.render_layer;
if (block.cull_same !== undefined) json.cull_same = block.cull_same;
if (block.light_emission !== undefined) json.light_emission = block.light_emission;
if (block.light_opacity !== undefined) json.light_opacity = block.light_opacity;
if (block.alpha !== undefined) json.alpha = block.alpha;
if (!block.has_collision) json.collision = false;
if (block.toughness !== undefined) {
@@ -114,6 +118,8 @@ export function block_from_json(json: BlockJson): { block: BlockRegistry; has_it
const render_layer = json.render_layer ?? (json.transparent ? "translucent" : undefined);
if (render_layer && render_layer !== "solid") block.render_layer = render_layer;
if (json.cull_same !== undefined) block.cull_same = json.cull_same;
if (json.light_emission !== undefined) block.light_emission = json.light_emission;
if (json.light_opacity !== undefined) block.light_opacity = json.light_opacity;
if (json.alpha !== undefined) block.alpha = json.alpha;
if (json.mining) {
block.toughness = json.mining.toughness;
@@ -258,6 +264,12 @@ export function validate_block(json: unknown): Problems {
if (json.render_layer !== undefined && !RENDER_LAYERS.includes(json.render_layer as RenderLayer)) {
problems.push(`render_layer must be one of ${RENDER_LAYERS.join(", ")}`);
}
for (const key of ["light_emission", "light_opacity"]) {
const value = json[key];
if (value !== undefined && (!Number.isInteger(value) || (value as number) < 0 || (value as number) > 15)) {
problems.push(`${key} must be a whole number from 0 to 15`);
}
}
for (const key of ["cull_same", "transparent", "collision", "item", "interactive", "replaceable"]) {
if (json[key] !== undefined && typeof json[key] !== "boolean") problems.push(`${key} must be true or false`);
}