Files
shacraft-core/scripts/lighting_reference.java
T
Emil c7e86663d8
MVP checks / mvp (push) Waiting to run
Expand voxel gameplay, lighting, full-height streaming and world imports
Add shared Rust/WASM physics, worker meshing and diagnostics, 64-chunk full-height streaming, atlas texture support, and baseline world import. Document the current implementation and include the supplied in-game lobby screenshot.
2026-09-17 02:10:53 +03:00

130 lines
8.3 KiB
Java

// Copyright Shacraft contributors. MIT OR Apache-2.0.
// Extract factual lighting properties through the pinned runtime's public API.
import java.nio.file.*;
import java.util.*;
import com.google.gson.*;
import net.minecraft.SharedConstants;
import net.minecraft.server.Bootstrap;
import net.minecraft.core.Direction;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.resources.Identifier;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
import net.minecraft.world.level.lighting.LightEngine;
import net.minecraft.world.phys.shapes.Shapes;
import net.minecraft.world.phys.shapes.VoxelShape;
class lighting_reference {
static String canonical(BlockState state) {
String id=BuiltInRegistries.BLOCK.getKey(state.getBlock()).toString();
var properties=new TreeMap<String,String>();
for(var property:state.getProperties())
properties.put(property.getName(),state.getValue(property).toString().toLowerCase(Locale.ROOT));
return id+(properties.isEmpty()?"":"["+String.join(",",properties.entrySet().stream().map(e->e.getKey()+"="+e.getValue()).toList())+"]");
}
static JsonArray boxes(VoxelShape shape) {
var result=new JsonArray();
for(var box:shape.toAabbs()) {
var coordinates=new JsonArray();
for(double value:new double[]{box.minX,box.minY,box.minZ,box.maxX,box.maxY,box.maxZ})coordinates.add(value);
result.add(coordinates);
}
return result;
}
static BlockState state(String name) {
return BuiltInRegistries.BLOCK.getValue(Identifier.parse("minecraft:"+name)).defaultBlockState();
}
static JsonObject properties(BlockState state) {
var result=new JsonObject();
result.addProperty("minecraft_id",Block.getId(state));
result.addProperty("state",canonical(state));
result.addProperty("emission",state.getLightEmission());
result.addProperty("dampening",state.getLightDampening());
result.addProperty("can_occlude",state.canOcclude());
result.addProperty("use_shape",state.useShapeForLightOcclusion());
result.addProperty("propagates_skylight_down",state.propagatesSkylightDown());
result.add("occlusion",boxes(state.canOcclude()&&state.useShapeForLightOcclusion()?state.getOcclusionShape():Shapes.empty()));
return result;
}
static JsonObject crossing(BlockState from,BlockState to,Direction direction) {
var result=new JsonObject();
result.addProperty("from",canonical(from)); result.addProperty("to",canonical(to));
result.addProperty("direction",direction.getName());
result.addProperty("block_dampening",LightEngine.getLightDampeningInto(from,to,direction,Math.max(1,to.getLightDampening())));
result.addProperty("sky_column_dampening",LightEngine.getLightDampeningInto(from,to,direction,to.getLightDampening()));
return result;
}
public static void main(String[] args) throws Exception {
SharedConstants.tryDetectVersion(); Bootstrap.bootStrap();
var root=new JsonObject(); root.addProperty("version","26.2");
var states=new JsonArray(); var shapeTable=new JsonArray(); var shapes=new HashMap<String,Integer>();
var defaults=new JsonObject(); var blocks=new JsonObject(); var schemas=new JsonArray();
var schemaIds=new HashMap<String,Integer>();
// Block state IDs are the same IDs already recorded by catalog generation.
var byId=new TreeMap<Integer,BlockState>();
for(var block:BuiltInRegistries.BLOCK) {
String name=BuiltInRegistries.BLOCK.getKey(block).toString();
defaults.addProperty(name,Block.getId(block.defaultBlockState()));
var possible=block.getStateDefinition().getPossibleStates();
int first=possible.stream().mapToInt(Block::getId).min().orElseThrow();
var schema=new JsonArray();
for(var property:block.getStateDefinition().getProperties()) {
var item=new JsonArray(); item.add(property.getName());
var values=new JsonArray();
for(var value:property.getPossibleValues())values.add(value.toString().toLowerCase(Locale.ROOT));
item.add(values); schema.add(item);
}
for(var state:possible) {
byId.put(Block.getId(state),state);
int offset=0;
for(var property:block.getStateDefinition().getProperties()) {
var values=new ArrayList<>(property.getPossibleValues());
offset=offset*values.size()+values.indexOf(state.getValue(property));
}
if(first+offset!=Block.getId(state))throw new IllegalStateException("Non-contiguous state schema: "+canonical(state));
}
String schemaKey=schema.toString();
if(!schemaIds.containsKey(schemaKey)) { schemaIds.put(schemaKey,schemas.size()); schemas.add(schema); }
var definition=new JsonArray(); definition.add(first); definition.add(Block.getId(block.defaultBlockState()));
definition.add(schemaIds.get(schemaKey)); blocks.add(name,definition);
}
for(var entry:byId.entrySet()) {
var state=entry.getValue();
var occlusion=boxes(state.canOcclude()&&state.useShapeForLightOcclusion()?state.getOcclusionShape():Shapes.empty());
String key=occlusion.toString();
if(!shapes.containsKey(key)) { shapes.put(key,shapeTable.size());shapeTable.add(occlusion); }
var record=new JsonArray(); record.add(entry.getKey()); record.add(state.getLightDampening());
record.add(shapes.get(key)); record.add(state.getLightEmission());
record.add(state.canOcclude()); record.add(state.useShapeForLightOcclusion());
record.add(state.propagatesSkylightDown()); states.add(record);
}
root.add("states",states); root.add("shapes",shapeTable); root.add("defaults",defaults);
root.add("blocks",blocks); root.add("schemas",schemas);
root.addProperty("state_columns","minecraft_id,dampening,occlusion_shape_id,emission,can_occlude,use_shape,propagates_skylight_down");
var examples=new JsonArray();
for(String name:List.of("air","stone","glass","tinted_glass","white_stained_glass","glass_pane","ice","packed_ice","blue_ice","water","lava","oak_leaves","azalea_leaves","oak_slab","oak_stairs","oak_trapdoor","oak_door","snow","snow_block","torch","wall_torch","redstone_torch","soul_torch","glowstone","sea_lantern","redstone_lamp","lantern","jack_o_lantern","light","sculk_sensor","copper_bulb","copper_grate"))
examples.add(properties(state(name)));
examples.add(properties(Blocks.REDSTONE_LAMP.defaultBlockState().setValue(BlockStateProperties.LIT,true)));
examples.add(properties(Blocks.OAK_SLAB.defaultBlockState().setValue(BlockStateProperties.SLAB_TYPE,net.minecraft.world.level.block.state.properties.SlabType.TOP)));
examples.add(properties(Blocks.OAK_SLAB.defaultBlockState().setValue(BlockStateProperties.SLAB_TYPE,net.minecraft.world.level.block.state.properties.SlabType.DOUBLE)));
examples.add(properties(Blocks.OAK_SLAB.defaultBlockState().setValue(BlockStateProperties.WATERLOGGED,true)));
root.add("examples",examples);
var crossings=new JsonArray(); var air=Blocks.AIR.defaultBlockState();
for(String name:List.of("stone","glass","tinted_glass","ice","water","oak_leaves","oak_slab","oak_stairs","glowstone","sea_lantern"))
for(Direction direction:Direction.values())crossings.add(crossing(air,state(name),direction));
var slab=Blocks.OAK_SLAB.defaultBlockState();
var top=slab.setValue(BlockStateProperties.SLAB_TYPE,net.minecraft.world.level.block.state.properties.SlabType.TOP);
for(Direction direction:Direction.values()) {
crossings.add(crossing(slab,top,direction));
crossings.add(crossing(top,slab,direction));
crossings.add(crossing(state("glowstone"),air,direction));
}
root.add("crossings",crossings);
root.addProperty("measurement_scope","Public original Java 26.2 block-state light properties and LightEngine.getLightDampeningInto calls. Effective shape is empty unless canOcclude and useShapeForLightOcclusion are both true. Crossings measure directional shape blocking and target attenuation, not a full running light engine or skylight source map.");
Files.writeString(Path.of(args[0]),new GsonBuilder().create().toJson(root)+"\n");
System.out.println("Measured "+states.size()+" states, "+shapeTable.size()+" effective shapes, "+examples.size()+" examples and "+crossings.size()+" directional crossings.");
}
}