Implement multiplayer persistence and vanilla lighting
This commit is contained in:
parent
8f7cacf9d9
commit
cae06eb97e
47 changed files with 3784 additions and 465 deletions
113
internal/world/light_properties.go
Normal file
113
internal/world/light_properties.go
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
package world
|
||||
|
||||
import (
|
||||
_ "embed"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// lightPropertiesBinary is generated by tools/VanillaLightDump.java directly
|
||||
// from the 26.1.2 runtime block-state registry.
|
||||
//
|
||||
//go:embed light_properties.bin
|
||||
var lightPropertiesBinary []byte
|
||||
|
||||
var (
|
||||
blockOpacity [totalBlockStates]byte
|
||||
blockEmission [totalBlockStates]byte
|
||||
blockLightFlags [totalBlockStates]byte
|
||||
blockLightShape [totalBlockStates]uint16
|
||||
lightFaceShapes [][lightShapeBytes]byte
|
||||
)
|
||||
|
||||
const (
|
||||
lightPropertiesMagic = 0x52494f4c // RIOL
|
||||
lightPropertiesVersion = 1
|
||||
lightShapeBytes = 6 * 32 // six 16x16 face masks
|
||||
)
|
||||
|
||||
func init() {
|
||||
if err := decodeLightProperties(lightPropertiesBinary); err != nil {
|
||||
panic(fmt.Sprintf("world: decode vanilla light properties: %v", err))
|
||||
}
|
||||
}
|
||||
|
||||
func decodeLightProperties(data []byte) error {
|
||||
if len(data) < 16 {
|
||||
return fmt.Errorf("header is truncated")
|
||||
}
|
||||
if binary.BigEndian.Uint32(data[0:4]) != lightPropertiesMagic {
|
||||
return fmt.Errorf("invalid magic")
|
||||
}
|
||||
if version := binary.BigEndian.Uint32(data[4:8]); version != lightPropertiesVersion {
|
||||
return fmt.Errorf("unsupported version %d", version)
|
||||
}
|
||||
states := int(binary.BigEndian.Uint32(data[8:12]))
|
||||
shapes := int(binary.BigEndian.Uint32(data[12:16]))
|
||||
if states != totalBlockStates {
|
||||
return fmt.Errorf("state count %d, want %d", states, totalBlockStates)
|
||||
}
|
||||
want := 16 + states*5 + shapes*lightShapeBytes
|
||||
if len(data) != want {
|
||||
return fmt.Errorf("length %d, want %d", len(data), want)
|
||||
}
|
||||
|
||||
offset := 16
|
||||
for id := 0; id < states; id++ {
|
||||
blockOpacity[id] = data[offset]
|
||||
blockEmission[id] = data[offset+1]
|
||||
blockLightFlags[id] = data[offset+2]
|
||||
blockLightShape[id] = binary.BigEndian.Uint16(data[offset+3 : offset+5])
|
||||
if int(blockLightShape[id]) >= shapes {
|
||||
return fmt.Errorf("state %d references shape %d of %d", id, blockLightShape[id], shapes)
|
||||
}
|
||||
offset += 5
|
||||
}
|
||||
lightFaceShapes = make([][lightShapeBytes]byte, shapes)
|
||||
for i := range lightFaceShapes {
|
||||
copy(lightFaceShapes[i][:], data[offset:offset+lightShapeBytes])
|
||||
offset += lightShapeBytes
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func lightOpacity(state uint16) byte {
|
||||
if int(state) >= len(blockOpacity) {
|
||||
return 15
|
||||
}
|
||||
return blockOpacity[state]
|
||||
}
|
||||
|
||||
func lightEmission(state uint16) byte {
|
||||
if int(state) >= len(blockEmission) {
|
||||
return 0
|
||||
}
|
||||
return blockEmission[state]
|
||||
}
|
||||
|
||||
// lightShapeOccludes mirrors Shapes.faceShapeOccludes for the 1/16-resolution
|
||||
// face masks emitted from vanilla's VoxelShape data.
|
||||
func lightShapeOccludes(from, into uint16, direction int) bool {
|
||||
if direction < 0 || direction >= 6 {
|
||||
return false
|
||||
}
|
||||
var fromShape, intoShape [lightShapeBytes]byte
|
||||
// Vanilla substitutes an empty shape unless both flags are true. Ordinary
|
||||
// full cubes are handled by dampening; only shape-aware blocks (slabs,
|
||||
// stairs, etc.) participate in face occlusion.
|
||||
if int(from) < len(blockLightFlags) && blockLightFlags[from]&6 == 6 {
|
||||
fromShape = lightFaceShapes[blockLightShape[from]]
|
||||
}
|
||||
if int(into) < len(blockLightFlags) && blockLightFlags[into]&6 == 6 {
|
||||
intoShape = lightFaceShapes[blockLightShape[into]]
|
||||
}
|
||||
opposite := [...]int{1, 0, 3, 2, 5, 4}
|
||||
fromOffset := direction * 32
|
||||
intoOffset := opposite[direction] * 32
|
||||
for i := 0; i < 32; i++ {
|
||||
if fromShape[fromOffset+i]|intoShape[intoOffset+i] != 0xff {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue