重构 BiomesState, fix typo

This commit is contained in:
Tnze
2023-04-23 00:08:05 +08:00
parent de2996336c
commit 5f06fa6510
5 changed files with 139 additions and 100 deletions

View File

@ -1,83 +1,102 @@
package biome package biome
import "math/bits" import (
"errors"
"math/bits"
)
type Type int type Type int
func (t Type) MarshalText() (text []byte, err error) {
if t >= 0 && int(t) < len(biomesNames) {
return []byte(biomesNames[t]), nil
}
return nil, errors.New("invalid type")
}
func (t *Type) UnmarshalText(text []byte) error {
var ok bool
*t, ok = biomesIDs[string(text)]
if ok {
return nil
}
return errors.New("unknown type")
}
var ( var (
BitsPerBiome int BitsPerBiome int
BiomesIDs map[string]Type biomesIDs map[string]Type
BiomesNames = []string{ biomesNames = []string{
"the_void", "minecraft:the_void",
"plains", "minecraft:plains",
"sunflower_plains", "minecraft:sunflower_plains",
"snowy_plains", "minecraft:snowy_plains",
"ice_spikes", "minecraft:ice_spikes",
"desert", "minecraft:desert",
"swamp", "minecraft:swamp",
"mangrove_swamp", "minecraft:mangrove_swamp",
"forest", "minecraft:forest",
"flower_forest", "minecraft:flower_forest",
"birch_forest", "minecraft:birch_forest",
"dark_forest", "minecraft:dark_forest",
"old_growth_birch_forest", "minecraft:old_growth_birch_forest",
"old_growth_pine_taiga", "minecraft:old_growth_pine_taiga",
"old_growth_spruce_taiga", "minecraft:old_growth_spruce_taiga",
"taiga", "minecraft:taiga",
"snowy_taiga", "minecraft:snowy_taiga",
"savanna", "minecraft:savanna",
"savanna_plateau", "minecraft:savanna_plateau",
"windswept_hills", "minecraft:windswept_hills",
"windswept_gravelly_hills", "minecraft:windswept_gravelly_hills",
"windswept_forest", "minecraft:windswept_forest",
"windswept_savanna", "minecraft:windswept_savanna",
"jungle", "minecraft:jungle",
"sparse_jungle", "minecraft:sparse_jungle",
"bamboo_jungle", "minecraft:bamboo_jungle",
"badlands", "minecraft:badlands",
"eroded_badlands", "minecraft:eroded_badlands",
"wooded_badlands", "minecraft:wooded_badlands",
"meadow", "minecraft:meadow",
"grove", "minecraft:grove",
"snowy_slopes", "minecraft:snowy_slopes",
"frozen_peaks", "minecraft:frozen_peaks",
"jagged_peaks", "minecraft:jagged_peaks",
"stony_peaks", "minecraft:stony_peaks",
"river", "minecraft:river",
"frozen_river", "minecraft:frozen_river",
"beach", "minecraft:beach",
"snowy_beach", "minecraft:snowy_beach",
"stony_shore", "minecraft:stony_shore",
"warm_ocean", "minecraft:warm_ocean",
"lukewarm_ocean", "minecraft:lukewarm_ocean",
"deep_lukewarm_ocean", "minecraft:deep_lukewarm_ocean",
"ocean", "minecraft:ocean",
"deep_ocean", "minecraft:deep_ocean",
"cold_ocean", "minecraft:cold_ocean",
"deep_cold_ocean", "minecraft:deep_cold_ocean",
"frozen_ocean", "minecraft:frozen_ocean",
"deep_frozen_ocean", "minecraft:deep_frozen_ocean",
"mushroom_fields", "minecraft:mushroom_fields",
"dripstone_caves", "minecraft:dripstone_caves",
"lush_caves", "minecraft:lush_caves",
"deep_dark", "minecraft:deep_dark",
"nether_wastes", "minecraft:nether_wastes",
"warped_forest", "minecraft:warped_forest",
"crimson_forest", "minecraft:crimson_forest",
"soul_sand_valley", "minecraft:soul_sand_valley",
"basalt_deltas", "minecraft:basalt_deltas",
"the_end", "minecraft:the_end",
"end_highlands", "minecraft:end_highlands",
"end_midlands", "minecraft:end_midlands",
"small_end_islands", "minecraft:small_end_islands",
"end_barrens", "minecraft:end_barrens",
} }
) )
func init() { func init() {
BitsPerBiome = bits.Len(uint(len(BiomesNames))) BitsPerBiome = bits.Len(uint(len(biomesNames)))
BiomesIDs = make(map[string]Type, len(BiomesNames)) biomesIDs = make(map[string]Type, len(biomesNames))
for i, v := range BiomesNames { for i, v := range biomesNames {
BiomesIDs[v] = Type(i) biomesIDs[v] = Type(i)
} }
} }

View File

@ -195,7 +195,7 @@ func (b *BitStorage) WriteTo(w io.Writer) (int64, error) {
} }
// Fix recalculate BitStorage internal values for given bits. // Fix recalculate BitStorage internal values for given bits.
// Typically, you should call this method after ReadFrom is called, internal data is changed. // Typically, you should call this method after ReadFrom is called, which cause internal data is changed.
func (b *BitStorage) Fix(bits int) error { func (b *BitStorage) Fix(bits int) error {
if bits == 0 { if bits == 0 {
b.mask = 0 b.mask = 0

View File

@ -7,9 +7,7 @@ import (
"io" "io"
"math/bits" "math/bits"
"strconv" "strconv"
"strings"
"github.com/Tnze/go-mc/level/biome"
"github.com/Tnze/go-mc/level/block" "github.com/Tnze/go-mc/level/block"
"github.com/Tnze/go-mc/nbt" "github.com/Tnze/go-mc/nbt"
pk "github.com/Tnze/go-mc/net/packet" pk "github.com/Tnze/go-mc/net/packet"
@ -59,7 +57,12 @@ func EmptyChunk(secs int) *Chunk {
return &Chunk{ return &Chunk{
Sections: sections, Sections: sections,
HeightMaps: HeightMaps{ HeightMaps: HeightMaps{
MotionBlocking: NewBitStorage(bits.Len(uint(secs)*16), 16*16, nil), WorldSurfaceWG: NewBitStorage(bits.Len(uint(secs)*16+1), 16*16, nil),
WorldSurface: NewBitStorage(bits.Len(uint(secs)*16+1), 16*16, nil),
OceanFloorWG: NewBitStorage(bits.Len(uint(secs)*16+1), 16*16, nil),
OceanFloor: NewBitStorage(bits.Len(uint(secs)*16+1), 16*16, nil),
MotionBlocking: NewBitStorage(bits.Len(uint(secs)*16+1), 16*16, nil),
MotionBlockingNoLeaves: NewBitStorage(bits.Len(uint(secs)*16+1), 16*16, nil),
}, },
Status: StatusEmpty, Status: StatusEmpty,
} }
@ -145,13 +148,12 @@ func readStatesPalette(palette []save.BlockState, data []uint64) (paletteData *P
return return
} }
func readBiomesPalette(palette []string, data []uint64) (*PaletteContainer[BiomesState], error) { func readBiomesPalette(palette []save.BiomeState, data []uint64) (*PaletteContainer[BiomesState], error) {
biomesRawPalette := make([]BiomesState, len(palette)) biomesRawPalette := make([]BiomesState, len(palette))
var ok bool
for i, v := range palette { for i, v := range palette {
biomesRawPalette[i], ok = biome.BiomesIDs[strings.TrimPrefix(v, "minecraft:")] err := biomesRawPalette[i].UnmarshalText([]byte(v))
if !ok { if err != nil {
return nil, fmt.Errorf("unknown biomes: %s", v) return nil, err
} }
} }
return NewBiomesPaletteContainerWithData(4*4*4, data, biomesRawPalette), nil return NewBiomesPaletteContainerWithData(4*4*4, data, biomesRawPalette), nil
@ -180,7 +182,10 @@ func ChunkToSave(c *Chunk, dst *save.Chunk) (err error) {
if err != nil { if err != nil {
return return
} }
biomes.Palette, biomes.Data = writeBiomesPalette(v.Biomes) biomes.Palette, biomes.Data, err = writeBiomesPalette(v.Biomes)
if err != nil {
return
}
s.SkyLight = v.SkyLight s.SkyLight = v.SkyLight
s.BlockLight = v.BlockLight s.BlockLight = v.BlockLight
} }
@ -198,6 +203,7 @@ func ChunkToSave(c *Chunk, dst *save.Chunk) (err error) {
func writeStatesPalette(paletteData *PaletteContainer[BlocksState]) (palette []save.BlockState, data []uint64, err error) { func writeStatesPalette(paletteData *PaletteContainer[BlocksState]) (palette []save.BlockState, data []uint64, err error) {
rawPalette := paletteData.palette.export() rawPalette := paletteData.palette.export()
palette = make([]save.BlockState, len(rawPalette)) palette = make([]save.BlockState, len(rawPalette))
var buffer bytes.Buffer var buffer bytes.Buffer
for i, v := range rawPalette { for i, v := range rawPalette {
b := block.StateList[v] b := block.StateList[v]
@ -213,19 +219,27 @@ func writeStatesPalette(paletteData *PaletteContainer[BlocksState]) (palette []s
return return
} }
} }
data = append(data, paletteData.data.Raw()...)
data = make([]uint64, len(paletteData.data.Raw()))
copy(data, paletteData.data.Raw())
return return
} }
func writeBiomesPalette(paletteData *PaletteContainer[BiomesState]) (palette []string, data []uint64) { func writeBiomesPalette(paletteData *PaletteContainer[BiomesState]) (palette []save.BiomeState, data []uint64, err error) {
rawPalette := paletteData.palette.export() rawPalette := paletteData.palette.export()
palette = make([]string, len(rawPalette)) palette = make([]save.BiomeState, len(rawPalette))
for i, v := range rawPalette {
palette[i] = biome.BiomesNames[v]
}
data = append(data, paletteData.data.Raw()...)
var biomeID []byte
for i, v := range rawPalette {
biomeID, err = v.MarshalText()
if err != nil {
return
}
palette[i] = save.BiomeState(biomeID)
}
data = make([]uint64, len(paletteData.data.Raw()))
copy(data, paletteData.data.Raw())
return return
} }

View File

@ -9,8 +9,11 @@ import (
) )
// RawMessage stores the raw binary data of NBT. // RawMessage stores the raw binary data of NBT.
// This is usable if you want to store an unknown NBT data and parse it later. // This is usable if you want to store an unknown NBT data and use it later.
// Notice that this struct doesn't store the tag name. To convert RawMessage to valid NBT binary value: //
// Notice that this struct doesn't store the root tag name.
//
// To convert RawMessage to valid NBT binary value:
// Encoder.Encode(RawMessage, Name) = []byte{ Type (1 byte) | n (2 byte) | Name (n byte) | Data}. // Encoder.Encode(RawMessage, Name) = []byte{ Type (1 byte) | n (2 byte) | Name (n byte) | Data}.
type RawMessage struct { type RawMessage struct {
Type byte Type byte

View File

@ -34,23 +34,24 @@ type Chunk struct {
type Section struct { type Section struct {
Y int8 Y int8
BlockStates struct { BlockStates PaletteContainer[BlockState] `nbt:"block_states"`
Palette []BlockState `nbt:"palette"` Biomes PaletteContainer[BiomeState] `nbt:"biomes"`
Data []uint64 `nbt:"data"`
} `nbt:"block_states"`
Biomes struct {
Palette []string `nbt:"palette"`
Data []uint64 `nbt:"data"`
} `nbt:"biomes"`
SkyLight []byte SkyLight []byte
BlockLight []byte BlockLight []byte
} }
type PaletteContainer[T any] struct {
Palette []T `nbt:"palette"`
Data []uint64 `nbt:"data"`
}
type BlockState struct { type BlockState struct {
Name string Name string
Properties nbt.RawMessage Properties nbt.RawMessage
} }
type BiomeState string
// Load read column data from []byte // Load read column data from []byte
func (c *Chunk) Load(data []byte) (err error) { func (c *Chunk) Load(data []byte) (err error) {
var r io.Reader = bytes.NewReader(data[1:]) var r io.Reader = bytes.NewReader(data[1:])
@ -87,6 +88,8 @@ func (c *Chunk) Data(compressingType byte) ([]byte, error) {
w = gzip.NewWriter(&buff) w = gzip.NewWriter(&buff)
case 2: case 2:
w = zlib.NewWriter(&buff) w = zlib.NewWriter(&buff)
case 3:
w = &buff
} }
err := nbt.NewEncoder(w).Encode(c, "") err := nbt.NewEncoder(w).Encode(c, "")
return buff.Bytes(), err return buff.Bytes(), err