MVP checks / mvp (push) Waiting to run
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.
130 lines
8.3 KiB
Java
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.");
|
|
}
|
|
}
|