refactor block state handling and storage initialization in litematic structures

This commit is contained in:
adman
2026-05-03 22:26:02 +02:00
parent 47180bf650
commit 3b1b436ecf
+44 -61
View File
@@ -3,7 +3,6 @@ package litematic
import ( import (
"errors" "errors"
"io" "io"
"math"
"os" "os"
"strings" "strings"
"unsafe" "unsafe"
@@ -11,13 +10,31 @@ import (
"github.com/admin-else/strom/data" "github.com/admin-else/strom/data"
"github.com/admin-else/strom/level" "github.com/admin-else/strom/level"
"github.com/admin-else/strom/nbt" "github.com/admin-else/strom/nbt"
"github.com/admin-else/strom/util"
"github.com/go-viper/mapstructure/v2" "github.com/go-viper/mapstructure/v2"
) )
var OutOfBoundsErr = errors.New("out of bounds")
const mcNamespaced = "minecraft:"
type Position struct { type Position struct {
X, Y, Z int32 X, Y, Z int32
} }
func (p Position) FixNegatives() Position {
if p.X < 0 {
p.X *= -1
}
if p.Y < 0 {
p.Y *= -1
}
if p.Z < 0 {
p.Z *= -1
}
return p
}
type MetaData struct { type MetaData struct {
Author string Author string
Description string Description string
@@ -40,12 +57,11 @@ type Region struct {
Size Position Size Position
BlockStatePalette []BlockState BlockStatePalette []BlockState
BlockStates []int64 BlockStates []int64
*level.Storage
} }
func (r *Region) GetBlockAt(x, y, z int32) (name string, properties map[string]string, err error) { func (s *Structure) GetBlockAt(region string, x, y, z int32) (stateId int32, err error) {
r := s.Regions[region]
// this is probably fine
uintSlice := unsafe.Slice((*uint64)(unsafe.Pointer(unsafe.SliceData(r.BlockStates))), len(r.BlockStates))
if r.Size.X < 0 { if r.Size.X < 0 {
r.Size.X *= -1 r.Size.X *= -1
} }
@@ -61,15 +77,7 @@ func (r *Region) GetBlockAt(x, y, z int32) (name string, properties map[string]s
return return
} }
i := x + z*r.Size.X + y*r.Size.X*r.Size.Z i := x + z*r.Size.X + y*r.Size.X*r.Size.Z
bpe := int32(math.Ceil(math.Log2(float64(len(r.BlockStatePalette))))) stateId, err = r.Get(i)
i = level.GetEntryFromLongs(uintSlice, i, bpe)
if i >= int32(len(r.BlockStatePalette)) {
err = BlockStateNotInPalletErr
return
}
block := r.BlockStatePalette[i]
name = block.Name
properties = block.Properties
return return
} }
@@ -83,7 +91,7 @@ type File struct {
type Structure struct { type Structure struct {
File File
BlockStatePalletRealized map[string][]int32 Version string
} }
func LoadFromPath(path string) (s *Structure, err error) { func LoadFromPath(path string) (s *Structure, err error) {
@@ -114,57 +122,32 @@ func Load(v any) (s *Structure, err error) {
if err != nil { if err != nil {
return return
} }
s.BlockStatePalletRealized = make(map[string][]int32) s.Version = ret.MinecraftVersion
for k, r := range s.Regions { for k, region := range s.Regions {
s.BlockStatePalletRealized[k] = make([]int32, len(r.BlockStatePalette)) palette := make([]int32, len(region.BlockStatePalette))
for i, b := range r.BlockStatePalette { for i, b := range region.BlockStatePalette {
var stateId int32 var paletteEntry int32
stateId, err = data.StateIdFromBlocKAndStateMap(ret.MinecraftVersion, strings.TrimPrefix(b.Name, "minecraft:"), b.Properties) paletteEntry, err = data.StateIdFromBlocKAndStateMap(s.Version, strings.TrimPrefix(b.Name, mcNamespaced), b.Properties)
if err != nil { if err != nil {
return return
} }
s.BlockStatePalletRealized[k][i] = stateId palette[i] = paletteEntry
} }
sizeFixed := region.Size.FixNegatives()
l := sizeFixed.X * sizeFixed.Y * sizeFixed.Z
bpe := util.BpeByNum(float64(len(region.BlockStatePalette)))
uintSlice := unsafe.Slice((*uint64)(unsafe.Pointer(unsafe.SliceData(region.BlockStates))), len(region.BlockStates))
region.Storage, err = level.StorageFormat{
AvailableBpes: []uint8{bpe},
BiggestDirect: false,
Len: l,
}.Import(uintSlice, bpe, palette)
if err != nil {
return
}
s.Regions[k] = region
} }
return
}
var BlockStateNotInPalletErr = errors.New("block state not in pallet")
var OutOfBoundsErr = errors.New("out of bounds")
var RegionNotInFileErr = errors.New("region not in file")
func (s *Structure) GetBlockAt(name string, x, y, z int32) (blockState int32, err error) {
r, ok := s.Regions[name]
if !ok {
err = RegionNotInFileErr
return
}
uintSlice := make([]uint64, len(r.BlockStates))
for i, v := range r.BlockStates {
uintSlice[i] = uint64(v)
}
if r.Size.X < 0 {
r.Size.X *= -1
}
if r.Size.Y < 0 {
r.Size.Y *= -1
}
if r.Size.Z < 0 {
r.Size.Z *= -1
}
if x >= r.Size.X || y >= r.Size.Y || z >= r.Size.Z {
err = OutOfBoundsErr
return
}
i := x + z*r.Size.X + y*r.Size.X*r.Size.Z
bpe := int32(math.Ceil(math.Log2(float64(len(r.BlockStatePalette)))))
i = level.GetEntryFromLongs(uintSlice, i, bpe)
mapSlice := s.BlockStatePalletRealized[name]
if i >= int32(len(mapSlice)) {
err = BlockStateNotInPalletErr
return
}
blockState = mapSlice[i]
return return
} }