initial commit
This commit is contained in:
53
internal/block_states.go
Normal file
53
internal/block_states.go
Normal file
@@ -0,0 +1,53 @@
|
||||
package internal
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/df-mc/worldupgrader/blockupgrader"
|
||||
"sort"
|
||||
"strings"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// StateHash is a struct that may be used as a map key for block states. It contains the name of the block state
|
||||
// and an encoded version of the properties.
|
||||
type StateHash struct {
|
||||
Name, Properties string
|
||||
}
|
||||
|
||||
// HashState produces a hash for the block properties held by the blockState.
|
||||
func HashState(state blockupgrader.BlockState) StateHash {
|
||||
if state.Properties == nil {
|
||||
return StateHash{Name: state.Name}
|
||||
}
|
||||
keys := make([]string, 0, len(state.Properties))
|
||||
for k := range state.Properties {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
sort.Slice(keys, func(i, j int) bool {
|
||||
return keys[i] < keys[j]
|
||||
})
|
||||
|
||||
var b strings.Builder
|
||||
for _, k := range keys {
|
||||
switch v := state.Properties[k].(type) {
|
||||
case bool:
|
||||
if v {
|
||||
b.WriteByte(1)
|
||||
} else {
|
||||
b.WriteByte(0)
|
||||
}
|
||||
case uint8:
|
||||
b.WriteByte(v)
|
||||
case int32:
|
||||
a := *(*[4]byte)(unsafe.Pointer(&v))
|
||||
b.Write(a[:])
|
||||
case string:
|
||||
b.WriteString(v)
|
||||
default:
|
||||
// If block encoding is broken, we want to find out as soon as possible. This saves a lot of time
|
||||
// debugging in-game.
|
||||
panic(fmt.Sprintf("invalid block property type %T for property %v", v, k))
|
||||
}
|
||||
}
|
||||
return StateHash{Name: state.Name, Properties: b.String()}
|
||||
}
|
||||
119
internal/chunk/chunk.go
Normal file
119
internal/chunk/chunk.go
Normal file
@@ -0,0 +1,119 @@
|
||||
package chunk
|
||||
|
||||
import (
|
||||
"github.com/df-mc/dragonfly/server/block/cube"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// Chunk is a segment in the world with a size of 16x16x256 blocks. A chunk contains multiple sub chunks
|
||||
// and stores other information such as biomes.
|
||||
// It is not safe to call methods on Chunk simultaneously from multiple goroutines.
|
||||
type Chunk struct {
|
||||
sync.Mutex
|
||||
// r holds the (vertical) range of the Chunk. It includes both the minimum and maximum coordinates.
|
||||
r cube.Range
|
||||
// air is the runtime ID of air.
|
||||
air uint32
|
||||
// sub holds all sub chunks part of the chunk. The pointers held by the array are nil if no sub chunk is
|
||||
// allocated at the indices.
|
||||
sub []*SubChunk
|
||||
// biomes is an array of biome IDs. There is one biome ID for every column in the chunk.
|
||||
biomes []*PalettedStorage
|
||||
}
|
||||
|
||||
// New initialises a new chunk and returns it, so that it may be used.
|
||||
func New(air uint32, r cube.Range) *Chunk {
|
||||
n := (r.Height() >> 4) + 1
|
||||
sub, biomes := make([]*SubChunk, n), make([]*PalettedStorage, n)
|
||||
for i := 0; i < n; i++ {
|
||||
sub[i] = NewSubChunk(air)
|
||||
biomes[i] = emptyStorage(0)
|
||||
}
|
||||
return &Chunk{r: r, air: air, sub: sub, biomes: biomes}
|
||||
}
|
||||
|
||||
// Range returns the cube.Range of the Chunk as passed to New.
|
||||
func (chunk *Chunk) Range() cube.Range {
|
||||
return chunk.r
|
||||
}
|
||||
|
||||
// Sub returns a list of all sub chunks present in the chunk.
|
||||
func (chunk *Chunk) Sub() []*SubChunk {
|
||||
return chunk.sub
|
||||
}
|
||||
|
||||
// Block returns the runtime ID of the block at a given x, y and z in a chunk at the given layer. If no
|
||||
// sub chunk exists at the given y, the block is assumed to be air.
|
||||
func (chunk *Chunk) Block(x uint8, y int16, z uint8, layer uint8) uint32 {
|
||||
sub := chunk.subChunk(y)
|
||||
if sub.Empty() || uint8(len(sub.storages)) <= layer {
|
||||
return chunk.air
|
||||
}
|
||||
return sub.storages[layer].At(x, uint8(y), z)
|
||||
}
|
||||
|
||||
// SetBlock sets the runtime ID of a block at a given x, y and z in a chunk at the given layer. If no
|
||||
// SubChunk exists at the given y, a new SubChunk is created and the block is set.
|
||||
func (chunk *Chunk) SetBlock(x uint8, y int16, z uint8, layer uint8, block uint32) {
|
||||
sub := chunk.sub[chunk.subIndex(y)]
|
||||
if uint8(len(sub.storages)) <= layer && block == chunk.air {
|
||||
// Air was set at n layer, but there were less than n layers, so there already was air there.
|
||||
// Don't do anything with this, just return.
|
||||
return
|
||||
}
|
||||
sub.Layer(layer).Set(x, uint8(y), z, block)
|
||||
}
|
||||
|
||||
// BiomeSub returns a list of all biome sub chunks present in the chunk.
|
||||
func (chunk *Chunk) BiomeSub() []*PalettedStorage {
|
||||
return chunk.biomes
|
||||
}
|
||||
|
||||
// Biome returns the biome ID at a specific column in the chunk.
|
||||
func (chunk *Chunk) Biome(x uint8, y int16, z uint8) uint32 {
|
||||
return chunk.biomes[chunk.subIndex(y)].At(x, uint8(y), z)
|
||||
}
|
||||
|
||||
// SetBiome sets the biome ID at a specific column in the chunk.
|
||||
func (chunk *Chunk) SetBiome(x uint8, y int16, z uint8, biome uint32) {
|
||||
chunk.biomes[chunk.subIndex(y)].Set(x, uint8(y), z, biome)
|
||||
}
|
||||
|
||||
// HighestBlock iterates from the highest non-empty sub chunk downwards to find the Y value of the highest
|
||||
// non-air block at an x and z. If no blocks are present in the column, 0 is returned.
|
||||
func (chunk *Chunk) HighestBlock(x, z uint8) int16 {
|
||||
for index := int16(len(chunk.sub) - 1); index >= 0; index-- {
|
||||
if sub := chunk.sub[index]; !sub.Empty() {
|
||||
for y := 15; y >= 0; y-- {
|
||||
if rid := sub.storages[0].At(x, uint8(y), z); rid != chunk.air {
|
||||
return int16(y) | chunk.subY(index)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return int16(chunk.r[0])
|
||||
}
|
||||
|
||||
// Compact compacts the chunk as much as possible, getting rid of any sub chunks that are empty, and compacts
|
||||
// all storages in the sub chunks to occupy as little space as possible.
|
||||
// Compact should be called right before the chunk is saved in order to optimise the storage space.
|
||||
func (chunk *Chunk) Compact() {
|
||||
for i := range chunk.sub {
|
||||
chunk.sub[i].compact()
|
||||
}
|
||||
}
|
||||
|
||||
// subChunk finds the correct SubChunk in the Chunk by a Y value.
|
||||
func (chunk *Chunk) subChunk(y int16) *SubChunk {
|
||||
return chunk.sub[chunk.subIndex(y)]
|
||||
}
|
||||
|
||||
// subIndex returns the sub chunk Y index matching the y value passed.
|
||||
func (chunk *Chunk) subIndex(y int16) int16 {
|
||||
return (y - int16(chunk.r[0])) >> 4
|
||||
}
|
||||
|
||||
// subY returns the sub chunk Y value matching the index passed.
|
||||
func (chunk *Chunk) subY(index int16) int16 {
|
||||
return (index << 4) + int16(chunk.r[0])
|
||||
}
|
||||
145
internal/chunk/decode.go
Normal file
145
internal/chunk/decode.go
Normal file
@@ -0,0 +1,145 @@
|
||||
package chunk
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"github.com/df-mc/dragonfly/server/block/cube"
|
||||
)
|
||||
|
||||
// NetworkDecode decodes the network serialised data passed into a Chunk if successful. If not, the chunk
|
||||
// returned is nil and the error non-nil.
|
||||
// The sub chunk count passed must be that found in the LevelChunk packet.
|
||||
// noinspection GoUnusedExportedFunction
|
||||
func NetworkDecode(air uint32, buf *bytes.Buffer, count int, oldFormat bool, r cube.Range, pse Encoding, pe PaletteEncoding) (*Chunk, error) {
|
||||
var (
|
||||
c = New(air, r)
|
||||
err error
|
||||
)
|
||||
for i := 0; i < count; i++ {
|
||||
index := uint8(i)
|
||||
if oldFormat {
|
||||
index += 4
|
||||
}
|
||||
c.sub[index], err = DecodeSubChunk(air, r, buf, &index, NetworkEncoding, pse, pe)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if oldFormat {
|
||||
// Read the old biomes.
|
||||
biomes := make([]byte, 256)
|
||||
if _, err := buf.Read(biomes); err != nil {
|
||||
return nil, fmt.Errorf("error reading biomes: %w", err)
|
||||
}
|
||||
|
||||
// Make our 2D biomes 3D.
|
||||
for x := 0; x < 16; x++ {
|
||||
for z := 0; z < 16; z++ {
|
||||
id := biomes[(x&15)|(z&15)<<4]
|
||||
for y := r.Min(); y <= r.Max(); y++ {
|
||||
c.SetBiome(uint8(x), int16(y), uint8(z), uint32(id))
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
var last *PalettedStorage
|
||||
for i := 0; i < len(c.sub); i++ {
|
||||
b, err := decodePalettedStorage(buf, NetworkEncoding, pse, BiomePaletteEncoding)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if b == nil {
|
||||
// b == nil means this paletted storage had the flag pointing to the previous one. It basically means we should
|
||||
// inherit whatever palette we decoded last.
|
||||
if i == 0 {
|
||||
// This should never happen and there is no way to handle this.
|
||||
return nil, fmt.Errorf("first biome storage pointed to previous one")
|
||||
}
|
||||
b = last
|
||||
} else {
|
||||
last = b
|
||||
}
|
||||
c.biomes[i] = b
|
||||
}
|
||||
}
|
||||
return c, nil
|
||||
}
|
||||
|
||||
// DecodeSubChunk decodes a SubChunk from a bytes.Buffer. The Encoding passed defines how the block storages of the
|
||||
// SubChunk are decoded.
|
||||
func DecodeSubChunk(air uint32, r cube.Range, buf *bytes.Buffer, index *byte, e Encoding, pse Encoding, pe PaletteEncoding) (*SubChunk, error) {
|
||||
ver, err := buf.ReadByte()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error reading version: %w", err)
|
||||
}
|
||||
sub := NewSubChunk(air)
|
||||
switch ver {
|
||||
default:
|
||||
return nil, fmt.Errorf("unknown sub chunk version %v: can't decode", ver)
|
||||
case 1:
|
||||
// Version 1 only has one layer for each sub chunk, but uses the format with palettes.
|
||||
storage, err := decodePalettedStorage(buf, e, pse, pe)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sub.storages = append(sub.storages, storage)
|
||||
case 8, 9:
|
||||
// Version 8 allows up to 256 layers for one sub chunk.
|
||||
storageCount, err := buf.ReadByte()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error reading storage count: %w", err)
|
||||
}
|
||||
if ver == 9 {
|
||||
uIndex, err := buf.ReadByte()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error reading subchunk index: %w", err)
|
||||
}
|
||||
// The index as written here isn't the actual index of the subchunk within the chunk. Rather, it is the Y
|
||||
// value of the subchunk. This means that we need to translate it to an index.
|
||||
*index = uint8(int8(uIndex) - int8(r[0]>>4))
|
||||
}
|
||||
sub.storages = make([]*PalettedStorage, storageCount)
|
||||
|
||||
for i := byte(0); i < storageCount; i++ {
|
||||
sub.storages[i], err = decodePalettedStorage(buf, e, pse, pe)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
return sub, nil
|
||||
}
|
||||
|
||||
// decodePalettedStorage decodes a PalettedStorage from a bytes.Buffer. The Encoding passed is used to read either a
|
||||
// network or disk block storage.
|
||||
func decodePalettedStorage(buf *bytes.Buffer, e Encoding, pse Encoding, pe PaletteEncoding) (*PalettedStorage, error) {
|
||||
blockSize, err := buf.ReadByte()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error reading block size: %w", err)
|
||||
}
|
||||
if e == NetworkEncoding && blockSize&1 != 1 {
|
||||
e = pse
|
||||
}
|
||||
|
||||
blockSize >>= 1
|
||||
if blockSize == 0x7f {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
size := paletteSize(blockSize)
|
||||
uint32Count := size.uint32s()
|
||||
|
||||
uint32s := make([]uint32, uint32Count)
|
||||
byteCount := uint32Count * 4
|
||||
|
||||
data := buf.Next(byteCount)
|
||||
if len(data) != byteCount {
|
||||
return nil, fmt.Errorf("cannot read paletted storage (size=%v) %T: not enough block data present: expected %v bytes, got %v", blockSize, pe, byteCount, len(data))
|
||||
}
|
||||
for i := 0; i < uint32Count; i++ {
|
||||
// Explicitly don't use the binary package to greatly improve performance of reading the uint32s.
|
||||
uint32s[i] = uint32(data[i*4]) | uint32(data[i*4+1])<<8 | uint32(data[i*4+2])<<16 | uint32(data[i*4+3])<<24
|
||||
}
|
||||
p, err := e.DecodePalette(buf, paletteSize(blockSize), pe)
|
||||
return newPalettedStorage(uint32s, p), err
|
||||
}
|
||||
92
internal/chunk/encode.go
Normal file
92
internal/chunk/encode.go
Normal file
@@ -0,0 +1,92 @@
|
||||
package chunk
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"github.com/df-mc/dragonfly/server/block/cube"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// pool is used to pool byte buffers used for encoding chunks.
|
||||
var pool = sync.Pool{
|
||||
New: func() any {
|
||||
return bytes.NewBuffer(make([]byte, 0, 1024))
|
||||
},
|
||||
}
|
||||
|
||||
func NetworkEncode(air uint32, c *Chunk, oldFormat bool, pe PaletteEncoding) ([]byte, error) {
|
||||
buf := pool.Get().(*bytes.Buffer)
|
||||
for i := 0; i < len(c.sub); i++ {
|
||||
_, _ = buf.Write(EncodeSubChunk(c.sub[i], NetworkEncoding, pe, SubChunkVersion8, c.r, i))
|
||||
}
|
||||
if oldFormat {
|
||||
biomes := make([]byte, 256)
|
||||
|
||||
// Make our 3D biomes 2D.
|
||||
for x := uint8(0); x < 16; x++ {
|
||||
for z := uint8(0); z < 16; z++ {
|
||||
biomes[(x&15)|(z&15)<<4] = byte(c.Biome(x, c.HighestBlock(x, z), z))
|
||||
}
|
||||
}
|
||||
_, _ = buf.Write(biomes)
|
||||
} else {
|
||||
_, _ = buf.Write(EncodeBiomes(c, NetworkEncoding))
|
||||
}
|
||||
|
||||
return buf.Bytes(), nil
|
||||
}
|
||||
|
||||
// EncodeSubChunk encodes a sub-chunk from a chunk into bytes. An Encoding may be passed to encode either for network or
|
||||
// disk purposed, the most notable difference being that the network encoding generally uses varints and no NBT.
|
||||
func EncodeSubChunk(s *SubChunk, e Encoding, pe PaletteEncoding, subChunkVer subChunkVersion, r cube.Range, ind int) []byte {
|
||||
buf := pool.Get().(*bytes.Buffer)
|
||||
defer func() {
|
||||
buf.Reset()
|
||||
pool.Put(buf)
|
||||
}()
|
||||
|
||||
subChunkVer.EncodeHeader(buf, s, r, ind)
|
||||
for _, storage := range s.storages {
|
||||
encodePalettedStorage(buf, storage, nil, e, pe)
|
||||
}
|
||||
sub := make([]byte, buf.Len())
|
||||
_, _ = buf.Read(sub)
|
||||
return sub
|
||||
}
|
||||
|
||||
// EncodeBiomes encodes the biomes of a chunk into bytes. An Encoding may be passed to encode either for network or
|
||||
// disk purposed, the most notable difference being that the network encoding generally uses varints and no NBT.
|
||||
func EncodeBiomes(c *Chunk, e Encoding) []byte {
|
||||
buf := pool.Get().(*bytes.Buffer)
|
||||
defer func() {
|
||||
buf.Reset()
|
||||
pool.Put(buf)
|
||||
}()
|
||||
|
||||
var previous *PalettedStorage
|
||||
for _, b := range c.biomes {
|
||||
encodePalettedStorage(buf, b, previous, e, BiomePaletteEncoding)
|
||||
previous = b
|
||||
}
|
||||
biomes := make([]byte, buf.Len())
|
||||
_, _ = buf.Read(biomes)
|
||||
return biomes
|
||||
}
|
||||
|
||||
// encodePalettedStorage encodes a PalettedStorage into a bytes.Buffer. The Encoding passed is used to write the Palette
|
||||
// of the PalettedStorage.
|
||||
func encodePalettedStorage(buf *bytes.Buffer, storage, previous *PalettedStorage, e Encoding, pe PaletteEncoding) {
|
||||
if storage.Equal(previous) {
|
||||
_, _ = buf.Write([]byte{0x7f<<1 | e.Network()})
|
||||
return
|
||||
}
|
||||
b := make([]byte, len(storage.indices)*4+1)
|
||||
b[0] = byte(storage.bitsPerIndex<<1) | e.Network()
|
||||
|
||||
for i, v := range storage.indices {
|
||||
// Explicitly don't use the binary package to greatly improve performance of writing the uint32s.
|
||||
b[i*4+1], b[i*4+2], b[i*4+3], b[i*4+4] = byte(v), byte(v>>8), byte(v>>16), byte(v>>24)
|
||||
}
|
||||
_, _ = buf.Write(b)
|
||||
|
||||
e.EncodePalette(buf, storage.palette, pe)
|
||||
}
|
||||
193
internal/chunk/encoding.go
Normal file
193
internal/chunk/encoding.go
Normal file
@@ -0,0 +1,193 @@
|
||||
package chunk
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"github.com/akmalfairuz/legacy-version/mapping"
|
||||
"strings"
|
||||
|
||||
"github.com/df-mc/dragonfly/server/block/cube"
|
||||
"github.com/df-mc/worldupgrader/blockupgrader"
|
||||
"github.com/sandertv/gophertunnel/minecraft/nbt"
|
||||
"github.com/sandertv/gophertunnel/minecraft/protocol"
|
||||
)
|
||||
|
||||
const (
|
||||
// SubChunkVersion is the current version of the written sub chunks, specifying the format they are
|
||||
// written on disk and over network.
|
||||
SubChunkVersion = 9
|
||||
)
|
||||
|
||||
type (
|
||||
// Encoding is an encoding type used for Chunk encoding. Implementations of this interface are DiskEncoding and
|
||||
// NetworkEncoding, which can be used to encode a Chunk to an intermediate disk or network representation respectively.
|
||||
Encoding interface {
|
||||
EncodePalette(buf *bytes.Buffer, p *Palette, e PaletteEncoding)
|
||||
DecodePalette(buf *bytes.Buffer, blockSize paletteSize, e PaletteEncoding) (*Palette, error)
|
||||
Network() byte
|
||||
}
|
||||
// PaletteEncoding is an encoding type used for Chunk encoding. It is used to encode different types of palettes
|
||||
// (for example, blocks or biomes) differently.
|
||||
PaletteEncoding interface {
|
||||
Encode(buf *bytes.Buffer, v uint32)
|
||||
Decode(buf *bytes.Buffer) (uint32, error)
|
||||
}
|
||||
// Encoding is an encoding type used for Chunk encoding. Implementations of this interface are DiskEncoding and
|
||||
// NetworkEncoding, which can be used to encode a Chunk to an intermediate disk or network representation respectively.
|
||||
subChunkVersion interface {
|
||||
EncodeHeader(buf *bytes.Buffer, s *SubChunk, r cube.Range, ind int)
|
||||
}
|
||||
)
|
||||
|
||||
var (
|
||||
// SubChunkVersion9 subChunkVersion9
|
||||
SubChunkVersion9 subChunkVersion9
|
||||
// SubChunkVersion8 subChunkVersion8
|
||||
SubChunkVersion8 subChunkVersion8
|
||||
|
||||
// NetworkEncoding is the Encoding used for sending a Chunk over network. It does not use NBT and writes varints.
|
||||
NetworkEncoding networkEncoding
|
||||
// BiomePaletteEncoding is the paletteEncoding used for encoding a palette of biomes.
|
||||
BiomePaletteEncoding biomePaletteEncoding
|
||||
)
|
||||
|
||||
// networkEncoding implements the Chunk encoding for sending over network.
|
||||
type networkEncoding struct{}
|
||||
|
||||
func (networkEncoding) Network() byte { return 1 }
|
||||
func (networkEncoding) EncodePalette(buf *bytes.Buffer, p *Palette, _ PaletteEncoding) {
|
||||
if p.size != 0 {
|
||||
_ = protocol.WriteVarint32(buf, int32(p.Len()))
|
||||
}
|
||||
for _, val := range p.values {
|
||||
_ = protocol.WriteVarint32(buf, int32(val))
|
||||
}
|
||||
}
|
||||
func (networkEncoding) DecodePalette(buf *bytes.Buffer, blockSize paletteSize, _ PaletteEncoding) (*Palette, error) {
|
||||
var paletteCount int32 = 1
|
||||
if blockSize != 0 {
|
||||
if err := protocol.Varint32(buf, &paletteCount); err != nil {
|
||||
return nil, fmt.Errorf("error reading palette entry count: %w", err)
|
||||
}
|
||||
if paletteCount <= 0 {
|
||||
return nil, fmt.Errorf("invalid palette entry count %v", paletteCount)
|
||||
}
|
||||
}
|
||||
|
||||
blocks, temp := make([]uint32, paletteCount), int32(0)
|
||||
for i := int32(0); i < paletteCount; i++ {
|
||||
if err := protocol.Varint32(buf, &temp); err != nil {
|
||||
return nil, fmt.Errorf("error decoding palette entry: %w", err)
|
||||
}
|
||||
blocks[i] = uint32(temp)
|
||||
}
|
||||
return &Palette{values: blocks, size: blockSize}, nil
|
||||
}
|
||||
|
||||
// biomePaletteEncoding implements the encoding of biome palettes to disk.
|
||||
type biomePaletteEncoding struct{}
|
||||
|
||||
func (biomePaletteEncoding) Encode(buf *bytes.Buffer, v uint32) {
|
||||
_ = binary.Write(buf, binary.LittleEndian, v)
|
||||
}
|
||||
func (biomePaletteEncoding) Decode(buf *bytes.Buffer) (uint32, error) {
|
||||
var v uint32
|
||||
return v, binary.Read(buf, binary.LittleEndian, &v)
|
||||
}
|
||||
|
||||
// BlockPaletteEncoding implements the encoding of block palettes to disk.
|
||||
type BlockPaletteEncoding struct {
|
||||
block mapping.Block
|
||||
version int32
|
||||
}
|
||||
|
||||
// NewBlockPaletteEncoding returns a new BlockPaletteEncoding using the block and version passed.
|
||||
func NewBlockPaletteEncoding(block mapping.Block, version int32) BlockPaletteEncoding {
|
||||
return BlockPaletteEncoding{block: block, version: version}
|
||||
}
|
||||
|
||||
func (b BlockPaletteEncoding) Encode(buf *bytes.Buffer, v uint32) {
|
||||
// Get the block state registered with the runtime IDs we have in the palette of the block storage
|
||||
// as we need the name and data value to store.
|
||||
state, _ := b.block.RuntimeIDToState(v)
|
||||
_ = nbt.NewEncoderWithEncoding(buf, nbt.LittleEndian).Encode(blockupgrader.BlockState{Name: state.Name, Properties: state.Properties, Version: b.version})
|
||||
}
|
||||
func (b BlockPaletteEncoding) Decode(buf *bytes.Buffer) (uint32, error) {
|
||||
var e blockupgrader.BlockState
|
||||
if err := nbt.NewDecoderWithEncoding(buf, nbt.LittleEndian).Decode(&e); err != nil {
|
||||
return 0, fmt.Errorf("error decoding block palette entry: %w", err)
|
||||
}
|
||||
v, ok := b.block.StateToRuntimeID(e)
|
||||
if !ok {
|
||||
return 0, fmt.Errorf("cannot get runtime ID of block state %v{%+v}", e.Name, e.Properties)
|
||||
}
|
||||
return v, nil
|
||||
}
|
||||
|
||||
// NewNetworkPersistentEncoding returns a new NetworkPersistentEncoding using the block and version passed.
|
||||
func NewNetworkPersistentEncoding(block mapping.Block, version int32) NetworkPersistentEncoding {
|
||||
return NetworkPersistentEncoding{block: block, version: version}
|
||||
}
|
||||
|
||||
// NetworkPersistentEncoding implements the Chunk encoding for sending over network with a persistent palette.
|
||||
type NetworkPersistentEncoding struct {
|
||||
block mapping.Block
|
||||
version int32
|
||||
}
|
||||
|
||||
func (n NetworkPersistentEncoding) Network() byte { return 1 }
|
||||
func (n NetworkPersistentEncoding) EncodePalette(buf *bytes.Buffer, p *Palette, _ PaletteEncoding) {
|
||||
if p.size != 0 {
|
||||
_ = protocol.WriteVarint32(buf, int32(p.Len()))
|
||||
}
|
||||
|
||||
enc := nbt.NewEncoderWithEncoding(buf, nbt.NetworkLittleEndian)
|
||||
for _, val := range p.values {
|
||||
state, _ := n.block.RuntimeIDToState(val)
|
||||
_ = enc.Encode(blockupgrader.BlockState{Name: strings.TrimPrefix("minecraft:", state.Name), Properties: state.Properties, Version: n.version})
|
||||
}
|
||||
}
|
||||
func (n NetworkPersistentEncoding) DecodePalette(buf *bytes.Buffer, blockSize paletteSize, _ PaletteEncoding) (*Palette, error) {
|
||||
var paletteCount int32 = 1
|
||||
if blockSize != 0 {
|
||||
err := protocol.Varint32(buf, &paletteCount)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if paletteCount <= 0 {
|
||||
return nil, fmt.Errorf("invalid palette entry count %v", paletteCount)
|
||||
}
|
||||
}
|
||||
|
||||
blocks := make([]blockupgrader.BlockState, paletteCount)
|
||||
dec := nbt.NewDecoderWithEncoding(buf, nbt.NetworkLittleEndian)
|
||||
for i := int32(0); i < paletteCount; i++ {
|
||||
if err := dec.Decode(&blocks[i]); err != nil {
|
||||
return nil, fmt.Errorf("error decoding block state: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
var ok bool
|
||||
palette, temp := newPalette(blockSize, make([]uint32, paletteCount)), uint32(0)
|
||||
for i, b := range blocks {
|
||||
temp, ok = n.block.StateToRuntimeID(blockupgrader.BlockState{Name: "minecraft:" + b.Name, Properties: b.Properties, Version: n.version})
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("cannot get runtime ID of block state %v{%+v}", b.Name, b.Properties)
|
||||
}
|
||||
palette.values[i] = temp
|
||||
}
|
||||
return palette, nil
|
||||
}
|
||||
|
||||
type subChunkVersion8 struct{}
|
||||
|
||||
func (subChunkVersion8) EncodeHeader(buf *bytes.Buffer, s *SubChunk, _ cube.Range, _ int) {
|
||||
_, _ = buf.Write([]byte{8, byte(len(s.storages))})
|
||||
}
|
||||
|
||||
type subChunkVersion9 struct{}
|
||||
|
||||
func (subChunkVersion9) EncodeHeader(buf *bytes.Buffer, s *SubChunk, r cube.Range, ind int) {
|
||||
_, _ = buf.Write([]byte{SubChunkVersion, byte(len(s.storages)), uint8(ind + (r[0] >> 4))})
|
||||
}
|
||||
131
internal/chunk/palette.go
Normal file
131
internal/chunk/palette.go
Normal file
@@ -0,0 +1,131 @@
|
||||
package chunk
|
||||
|
||||
import (
|
||||
"math"
|
||||
)
|
||||
|
||||
// paletteSize is the size of a palette. It indicates the amount of bits occupied per value stored.
|
||||
type paletteSize byte
|
||||
|
||||
// Palette is a palette of values that every PalettedStorage has. Storages hold 'pointers' to indices
|
||||
// in this palette.
|
||||
type Palette struct {
|
||||
last uint32
|
||||
lastIndex int16
|
||||
size paletteSize
|
||||
|
||||
// values is a map of values. A PalettedStorage points to the index to this value.
|
||||
values []uint32
|
||||
}
|
||||
|
||||
// newPalette returns a new Palette with size and a slice of added values.
|
||||
func newPalette(size paletteSize, values []uint32) *Palette {
|
||||
return &Palette{size: size, values: values, last: math.MaxUint32}
|
||||
}
|
||||
|
||||
// Len returns the amount of unique values in the Palette.
|
||||
func (palette *Palette) Len() int {
|
||||
return len(palette.values)
|
||||
}
|
||||
|
||||
// Add adds a values to the Palette. It does not first check if the value was already set in the Palette.
|
||||
// The index at which the value was added is returned. Another bool is returned indicating if the Palette
|
||||
// was resized as a result of adding the value.
|
||||
func (palette *Palette) Add(v uint32) (index int16, resize bool) {
|
||||
i := int16(len(palette.values))
|
||||
palette.values = append(palette.values, v)
|
||||
|
||||
if palette.needsResize() {
|
||||
palette.increaseSize()
|
||||
return i, true
|
||||
}
|
||||
return i, false
|
||||
}
|
||||
|
||||
// Replace calls the function passed for each value present in the Palette. The value returned by the
|
||||
// function replaces the value present at the index of the value passed.
|
||||
func (palette *Palette) Replace(f func(v uint32) uint32) {
|
||||
// Reset last runtime ID as it now has a different offset.
|
||||
palette.last = math.MaxUint32
|
||||
for index, v := range palette.values {
|
||||
palette.values[index] = f(v)
|
||||
}
|
||||
}
|
||||
|
||||
// Index loops through the values of the Palette and looks for the index of the given value. If the value could
|
||||
// not be found, -1 is returned.
|
||||
func (palette *Palette) Index(runtimeID uint32) int16 {
|
||||
if runtimeID == palette.last {
|
||||
// Fast path out.
|
||||
return palette.lastIndex
|
||||
}
|
||||
// Slow path in a separate function allows for inlining the fast path.
|
||||
return palette.indexSlow(runtimeID)
|
||||
}
|
||||
|
||||
// indexSlow searches the index of a value in the Palette's values by iterating through the Palette's values.
|
||||
func (palette *Palette) indexSlow(runtimeID uint32) int16 {
|
||||
l := len(palette.values)
|
||||
for i := 0; i < l; i++ {
|
||||
if palette.values[i] == runtimeID {
|
||||
palette.last = runtimeID
|
||||
v := int16(i)
|
||||
palette.lastIndex = v
|
||||
return v
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
// Value returns the value in the Palette at a specific index.
|
||||
func (palette *Palette) Value(i uint16) uint32 {
|
||||
return palette.values[i]
|
||||
}
|
||||
|
||||
// needsResize checks if the Palette, and with it the holding PalettedStorage, needs to be resized to a bigger
|
||||
// size.
|
||||
func (palette *Palette) needsResize() bool {
|
||||
return len(palette.values) > (1 << palette.size)
|
||||
}
|
||||
|
||||
var sizes = [...]paletteSize{0, 1, 2, 3, 4, 5, 6, 8, 16}
|
||||
var offsets = [...]int{0: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 8: 7, 16: 8}
|
||||
|
||||
// increaseSize increases the size of the Palette to the next palette size.
|
||||
func (palette *Palette) increaseSize() {
|
||||
palette.size = sizes[offsets[palette.size]+1]
|
||||
}
|
||||
|
||||
// padded returns true if the Palette size is 3, 5 or 6.
|
||||
func (p paletteSize) padded() bool {
|
||||
return p == 3 || p == 5 || p == 6
|
||||
}
|
||||
|
||||
// paletteSizeFor finds a suitable paletteSize for the amount of values passed n.
|
||||
func paletteSizeFor(n int) paletteSize {
|
||||
for _, size := range sizes {
|
||||
if n <= (1 << size) {
|
||||
return size
|
||||
}
|
||||
}
|
||||
// Should never happen.
|
||||
return 0
|
||||
}
|
||||
|
||||
// uint32s returns the amount of uint32s needed to represent a storage with this palette size.
|
||||
func (p paletteSize) uint32s() (n int) {
|
||||
uint32Count := 0
|
||||
if p != 0 {
|
||||
// indicesPerUint32 is the amount of indices that may be stored in a single uint32.
|
||||
indicesPerUint32 := 32 / int(p)
|
||||
// uint32Count is the amount of uint32s required to store all indices: 4096 indices need to be stored in
|
||||
// total.
|
||||
uint32Count = 4096 / indicesPerUint32
|
||||
}
|
||||
if p.padded() {
|
||||
// We've got one of the padded sizes, so the storage has another uint32 to be able to store
|
||||
// every index.
|
||||
uint32Count++
|
||||
}
|
||||
return uint32Count
|
||||
}
|
||||
200
internal/chunk/paletted_storage.go
Normal file
200
internal/chunk/paletted_storage.go
Normal file
@@ -0,0 +1,200 @@
|
||||
package chunk
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"reflect"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
const (
|
||||
// uint32ByteSize is the amount of bytes in a uint32.
|
||||
uint32ByteSize = 4
|
||||
// uint32BitSize is the amount of bits in a uint32.
|
||||
uint32BitSize = uint32ByteSize * 8
|
||||
)
|
||||
|
||||
// PalettedStorage is a storage of 4096 blocks encoded in a variable amount of uint32s, storages may have values
|
||||
// with a bit size per block of 0, 1, 2, 3, 4, 5, 6, 8 or 16 bits.
|
||||
// 3 of these formats have additional padding in every uint32 and an additional uint32 at the end, to cater
|
||||
// for the blocks that don't fit. This padding is present when the storage has a block size of 3, 5 or 6
|
||||
// bytes.
|
||||
// Methods on PalettedStorage must not be called simultaneously from multiple goroutines.
|
||||
type PalettedStorage struct {
|
||||
// bitsPerIndex is the amount of bits required to store one block. The number increases as the block
|
||||
// storage holds more unique block states.
|
||||
bitsPerIndex uint16
|
||||
// filledBitsPerIndex returns the amount of blocks that are actually filled per uint32.
|
||||
filledBitsPerIndex uint16
|
||||
// indexMask is the equivalent of 1 << bitsPerIndex - 1.
|
||||
indexMask uint32
|
||||
|
||||
// indicesStart holds an unsafe.Pointer to the first byte in the indices slice below.
|
||||
indicesStart unsafe.Pointer
|
||||
|
||||
// Palette holds all block runtime IDs that the indices in the indices slice point to. These runtime IDs
|
||||
// point to block states.
|
||||
palette *Palette
|
||||
|
||||
// indices contains all indices in the PalettedStorage. This slice has a variable size, but may not be changed
|
||||
// unless the whole PalettedStorage is resized, including the Palette.
|
||||
indices []uint32
|
||||
}
|
||||
|
||||
// newPalettedStorage creates a new block storage using the uint32 slice as the indices and the palette passed.
|
||||
// The bits per block are calculated using the length of the uint32 slice.
|
||||
func newPalettedStorage(indices []uint32, palette *Palette) *PalettedStorage {
|
||||
var (
|
||||
bitsPerIndex = uint16(len(indices) / uint32BitSize / uint32ByteSize)
|
||||
indexMask = (uint32(1) << bitsPerIndex) - 1
|
||||
indicesStart = (unsafe.Pointer)((*reflect.SliceHeader)(unsafe.Pointer(&indices)).Data)
|
||||
filledBitsPerIndex uint16
|
||||
)
|
||||
if bitsPerIndex != 0 {
|
||||
filledBitsPerIndex = uint32BitSize / bitsPerIndex * bitsPerIndex
|
||||
}
|
||||
return &PalettedStorage{filledBitsPerIndex: filledBitsPerIndex, indexMask: indexMask, indicesStart: indicesStart, bitsPerIndex: bitsPerIndex, indices: indices, palette: palette}
|
||||
}
|
||||
|
||||
// emptyStorage creates a PalettedStorage filled completely with a value v.
|
||||
func emptyStorage(v uint32) *PalettedStorage {
|
||||
return newPalettedStorage([]uint32{}, newPalette(0, []uint32{v}))
|
||||
}
|
||||
|
||||
// Palette returns the Palette of the PalettedStorage.
|
||||
func (storage *PalettedStorage) Palette() *Palette {
|
||||
return storage.palette
|
||||
}
|
||||
|
||||
// At returns the value of the PalettedStorage at a given x, y and z.
|
||||
func (storage *PalettedStorage) At(x, y, z byte) uint32 {
|
||||
return storage.palette.Value(storage.paletteIndex(x&15, y&15, z&15))
|
||||
}
|
||||
|
||||
// Set sets a value at a specific x, y and z. The Palette and PalettedStorage are expanded
|
||||
// automatically to make space for the value, should that be needed.
|
||||
func (storage *PalettedStorage) Set(x, y, z byte, v uint32) {
|
||||
index := storage.palette.Index(v)
|
||||
if index == -1 {
|
||||
// The runtime ID was not yet available in the palette. We add it, then check if the block storage
|
||||
// needs to be resized for the palette pointers to fit.
|
||||
index = storage.addNew(v)
|
||||
}
|
||||
storage.setPaletteIndex(x&15, y&15, z&15, uint16(index))
|
||||
}
|
||||
|
||||
// Equal checks if two PalettedStorages are equal value wise. False is returned
|
||||
// if either of the storages are nil.
|
||||
func (storage *PalettedStorage) Equal(other *PalettedStorage) bool {
|
||||
if storage == nil || other == nil {
|
||||
return false
|
||||
}
|
||||
if len(storage.indices) == 0 || len(other.indices) == 0 || storage.palette.values[0] == 0 || other.palette.values[0] == 0 {
|
||||
return false
|
||||
}
|
||||
indicesA := unsafe.Slice((*byte)(unsafe.Pointer(&storage.indices[0])), len(storage.indices)*4)
|
||||
indicesB := unsafe.Slice((*byte)(unsafe.Pointer(&other.indices[0])), len(other.indices)*4)
|
||||
if !bytes.Equal(indicesA, indicesB) {
|
||||
return false
|
||||
}
|
||||
paletteA := unsafe.Slice((*byte)(unsafe.Pointer(&storage.palette.values[0])), len(storage.palette.values)*4)
|
||||
paletteB := unsafe.Slice((*byte)(unsafe.Pointer(&other.palette.values[0])), len(other.palette.values)*4)
|
||||
return bytes.Equal(paletteA, paletteB)
|
||||
}
|
||||
|
||||
// addNew adds a new value to the PalettedStorage's Palette and returns its index. If needed, the storage is resized.
|
||||
func (storage *PalettedStorage) addNew(v uint32) int16 {
|
||||
index, resize := storage.palette.Add(v)
|
||||
if resize {
|
||||
storage.resize(storage.palette.size)
|
||||
}
|
||||
return index
|
||||
}
|
||||
|
||||
// paletteIndex looks up the Palette index at a given x, y and z value in the PalettedStorage. This palette
|
||||
// index is not the value at this offset, but merely an index in the Palette pointing to a value.
|
||||
func (storage *PalettedStorage) paletteIndex(x, y, z byte) uint16 {
|
||||
if storage.bitsPerIndex == 0 {
|
||||
// Unfortunately our default logic cannot deal with 0 bits per index, meaning we'll have to special case
|
||||
// this. This comes with a little performance hit, but it seems to be the only way to go. An alternative would
|
||||
// be not to have 0 bits per block storages in memory, but that would cause a strongly increased memory usage
|
||||
// by biomes.
|
||||
return 0
|
||||
}
|
||||
offset := ((uint16(x) << 8) | (uint16(z) << 4) | uint16(y)) * storage.bitsPerIndex
|
||||
uint32Offset, bitOffset := offset/storage.filledBitsPerIndex, offset%storage.filledBitsPerIndex
|
||||
|
||||
w := *(*uint32)(unsafe.Pointer(uintptr(storage.indicesStart) + uintptr(uint32Offset<<2)))
|
||||
return uint16((w >> bitOffset) & storage.indexMask)
|
||||
}
|
||||
|
||||
// setPaletteIndex sets the palette index at a given x, y and z to paletteIndex. This index should point
|
||||
// to a value in the PalettedStorage's Palette.
|
||||
func (storage *PalettedStorage) setPaletteIndex(x, y, z byte, i uint16) {
|
||||
if storage.bitsPerIndex == 0 {
|
||||
return
|
||||
}
|
||||
offset := ((uint16(x) << 8) | (uint16(z) << 4) | uint16(y)) * storage.bitsPerIndex
|
||||
uint32Offset, bitOffset := offset/storage.filledBitsPerIndex, offset%storage.filledBitsPerIndex
|
||||
|
||||
ptr := (*uint32)(unsafe.Pointer(uintptr(storage.indicesStart) + uintptr(uint32Offset<<2)))
|
||||
*ptr = (*ptr &^ (storage.indexMask << bitOffset)) | (uint32(i) << bitOffset)
|
||||
}
|
||||
|
||||
// resize changes the size of a PalettedStorage to newPaletteSize. A new PalettedStorage is constructed,
|
||||
// and all values available in the current storage are set in their appropriate locations in the
|
||||
// new storage.
|
||||
func (storage *PalettedStorage) resize(newPaletteSize paletteSize) {
|
||||
if newPaletteSize == paletteSize(storage.bitsPerIndex) {
|
||||
return // Don't resize if the size is already equal.
|
||||
}
|
||||
// Construct a new storage and set all values in there manually. We can't easily do this in a better
|
||||
// way, because all values will be at a different index with a different length.
|
||||
newStorage := newPalettedStorage(make([]uint32, newPaletteSize.uint32s()), storage.palette)
|
||||
for x := byte(0); x < 16; x++ {
|
||||
for y := byte(0); y < 16; y++ {
|
||||
for z := byte(0); z < 16; z++ {
|
||||
newStorage.setPaletteIndex(x, y, z, storage.paletteIndex(x, y, z))
|
||||
}
|
||||
}
|
||||
}
|
||||
// Set the new storage.
|
||||
*storage = *newStorage
|
||||
}
|
||||
|
||||
// compact clears unused indexes in the palette by scanning for usages in the PalettedStorage. This is a
|
||||
// relatively heavy task which should only happen right before the sub chunk holding this PalettedStorage is
|
||||
// saved to disk. compact also shrinks the palette size if possible.
|
||||
func (storage *PalettedStorage) compact() {
|
||||
usedIndices := make([]bool, storage.palette.Len())
|
||||
for x := byte(0); x < 16; x++ {
|
||||
for y := byte(0); y < 16; y++ {
|
||||
for z := byte(0); z < 16; z++ {
|
||||
usedIndices[storage.paletteIndex(x, y, z)] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
newRuntimeIDs := make([]uint32, 0, len(usedIndices))
|
||||
conversion := make([]uint16, len(usedIndices))
|
||||
|
||||
for index, set := range usedIndices {
|
||||
if set {
|
||||
conversion[index] = uint16(len(newRuntimeIDs))
|
||||
newRuntimeIDs = append(newRuntimeIDs, storage.palette.values[index])
|
||||
}
|
||||
}
|
||||
// Construct a new storage and set all values in there manually. We can't easily do this in a better
|
||||
// way, because all values will be at a different index with a different length.
|
||||
size := paletteSizeFor(len(newRuntimeIDs))
|
||||
newStorage := newPalettedStorage(make([]uint32, size.uint32s()), newPalette(size, newRuntimeIDs))
|
||||
|
||||
for x := byte(0); x < 16; x++ {
|
||||
for y := byte(0); y < 16; y++ {
|
||||
for z := byte(0); z < 16; z++ {
|
||||
// Replace all usages of the old palette indexes with the new indexes using the map we
|
||||
// produced earlier.
|
||||
newStorage.setPaletteIndex(x, y, z, conversion[storage.paletteIndex(x, y, z)])
|
||||
}
|
||||
}
|
||||
}
|
||||
*storage = *newStorage
|
||||
}
|
||||
66
internal/chunk/sub_chunk.go
Normal file
66
internal/chunk/sub_chunk.go
Normal file
@@ -0,0 +1,66 @@
|
||||
package chunk
|
||||
|
||||
// SubChunk is a cube of blocks located in a chunk. It has a size of 16x16x16 blocks and forms part of a stack
|
||||
// that forms a Chunk.
|
||||
type SubChunk struct {
|
||||
air uint32
|
||||
storages []*PalettedStorage
|
||||
blockLight []uint8
|
||||
skyLight []uint8
|
||||
}
|
||||
|
||||
// NewSubChunk creates a new sub chunk. All sub chunks should be created through this function
|
||||
func NewSubChunk(air uint32) *SubChunk {
|
||||
return &SubChunk{air: air}
|
||||
}
|
||||
|
||||
// Empty checks if the SubChunk is considered empty. This is the case if the SubChunk has 0 block storages or if it has
|
||||
// a single one that is completely filled with air.
|
||||
func (sub *SubChunk) Empty() bool {
|
||||
return len(sub.storages) == 0 || (len(sub.storages) == 1 && len(sub.storages[0].palette.values) == 1 && sub.storages[0].palette.values[0] == sub.air)
|
||||
}
|
||||
|
||||
// Layer returns a certain block storage/layer from a sub chunk. If no storage at the layer exists, the layer
|
||||
// is created, as well as all layers between the current highest layer and the new highest layer.
|
||||
func (sub *SubChunk) Layer(layer uint8) *PalettedStorage {
|
||||
for uint8(len(sub.storages)) <= layer {
|
||||
// Keep appending to storages until the requested layer is achieved. Makes working with new layers
|
||||
// much easier.
|
||||
sub.storages = append(sub.storages, emptyStorage(sub.air))
|
||||
}
|
||||
return sub.storages[layer]
|
||||
}
|
||||
|
||||
// Layers returns all layers in the sub chunk. This method may also return an empty slice.
|
||||
func (sub *SubChunk) Layers() []*PalettedStorage {
|
||||
return sub.storages
|
||||
}
|
||||
|
||||
// Block returns the runtime ID of the block located at the given X, Y and Z. X, Y and Z must be in a
|
||||
// range of 0-15.
|
||||
func (sub *SubChunk) Block(x, y, z byte, layer uint8) uint32 {
|
||||
if uint8(len(sub.storages)) <= layer {
|
||||
return sub.air
|
||||
}
|
||||
return sub.storages[layer].At(x, y, z)
|
||||
}
|
||||
|
||||
// SetBlock sets the given block runtime ID at the given X, Y and Z. X, Y and Z must be in a range of 0-15.
|
||||
func (sub *SubChunk) SetBlock(x, y, z byte, layer uint8, block uint32) {
|
||||
sub.Layer(layer).Set(x, y, z, block)
|
||||
}
|
||||
|
||||
// Compact cleans the garbage from all block storages that sub chunk contains, so that they may be
|
||||
// cleanly written to a database.
|
||||
func (sub *SubChunk) compact() {
|
||||
newStorages := make([]*PalettedStorage, 0, len(sub.storages))
|
||||
for _, storage := range sub.storages {
|
||||
storage.compact()
|
||||
if len(storage.palette.values) == 1 && storage.palette.values[0] == sub.air {
|
||||
// If the palette has only air in it, it means the storage is empty, so we can ignore it.
|
||||
continue
|
||||
}
|
||||
newStorages = append(newStorages, storage)
|
||||
}
|
||||
sub.storages = newStorages
|
||||
}
|
||||
481
internal/item/1.12.0_item_id_to_block_id_map.json
Normal file
481
internal/item/1.12.0_item_id_to_block_id_map.json
Normal file
@@ -0,0 +1,481 @@
|
||||
{
|
||||
"minecraft:acacia_button": "minecraft:acacia_button",
|
||||
"minecraft:acacia_fence_gate": "minecraft:acacia_fence_gate",
|
||||
"minecraft:acacia_pressure_plate": "minecraft:acacia_pressure_plate",
|
||||
"minecraft:acacia_stairs": "minecraft:acacia_stairs",
|
||||
"minecraft:acacia_standing_sign": "minecraft:acacia_standing_sign",
|
||||
"minecraft:acacia_trapdoor": "minecraft:acacia_trapdoor",
|
||||
"minecraft:acacia_wall_sign": "minecraft:acacia_wall_sign",
|
||||
"minecraft:activator_rail": "minecraft:activator_rail",
|
||||
"minecraft:andesite_stairs": "minecraft:andesite_stairs",
|
||||
"minecraft:anvil": "minecraft:anvil",
|
||||
"minecraft:bamboo": "minecraft:bamboo",
|
||||
"minecraft:bamboo_sapling": "minecraft:bamboo_sapling",
|
||||
"minecraft:barrel": "minecraft:barrel",
|
||||
"minecraft:barrier": "minecraft:barrier",
|
||||
"minecraft:beacon": "minecraft:beacon",
|
||||
"minecraft:bedrock": "minecraft:bedrock",
|
||||
"minecraft:bell": "minecraft:bell",
|
||||
"minecraft:birch_button": "minecraft:birch_button",
|
||||
"minecraft:birch_fence_gate": "minecraft:birch_fence_gate",
|
||||
"minecraft:birch_pressure_plate": "minecraft:birch_pressure_plate",
|
||||
"minecraft:birch_stairs": "minecraft:birch_stairs",
|
||||
"minecraft:birch_standing_sign": "minecraft:birch_standing_sign",
|
||||
"minecraft:birch_trapdoor": "minecraft:birch_trapdoor",
|
||||
"minecraft:birch_wall_sign": "minecraft:birch_wall_sign",
|
||||
"minecraft:black_glazed_terracotta": "minecraft:black_glazed_terracotta",
|
||||
"minecraft:blast_furnace": "minecraft:blast_furnace",
|
||||
"minecraft:blue_glazed_terracotta": "minecraft:blue_glazed_terracotta",
|
||||
"minecraft:blue_ice": "minecraft:blue_ice",
|
||||
"minecraft:bone_block": "minecraft:bone_block",
|
||||
"minecraft:bookshelf": "minecraft:bookshelf",
|
||||
"minecraft:brewingstandblock": "minecraft:brewing_stand",
|
||||
"minecraft:brick_block": "minecraft:brick_block",
|
||||
"minecraft:brick_stairs": "minecraft:brick_stairs",
|
||||
"minecraft:brown_glazed_terracotta": "minecraft:brown_glazed_terracotta",
|
||||
"minecraft:brown_mushroom": "minecraft:brown_mushroom",
|
||||
"minecraft:brown_mushroom_block": "minecraft:brown_mushroom_block",
|
||||
"minecraft:bubble_column": "minecraft:bubble_column",
|
||||
"minecraft:cactus": "minecraft:cactus",
|
||||
"minecraft:carpet": "minecraft:carpet",
|
||||
"minecraft:carrots": "minecraft:carrots",
|
||||
"minecraft:cartography_table": "minecraft:cartography_table",
|
||||
"minecraft:carved_pumpkin": "minecraft:carved_pumpkin",
|
||||
"minecraft:chain_command_block": "minecraft:chain_command_block",
|
||||
"minecraft:chemical_heat": "minecraft:chemical_heat",
|
||||
"minecraft:chemistry_table": "minecraft:chemistry_table",
|
||||
"minecraft:chest": "minecraft:chest",
|
||||
"minecraft:chorus_flower": "minecraft:chorus_flower",
|
||||
"minecraft:chorus_plant": "minecraft:chorus_plant",
|
||||
"minecraft:clay": "minecraft:clay",
|
||||
"minecraft:coal_block": "minecraft:coal_block",
|
||||
"minecraft:coal_ore": "minecraft:coal_ore",
|
||||
"minecraft:cobblestone": "minecraft:cobblestone",
|
||||
"minecraft:cobblestone_wall": "minecraft:cobblestone_wall",
|
||||
"minecraft:cocoa": "minecraft:cocoa",
|
||||
"minecraft:colored_torch_bp": "minecraft:colored_torch_bp",
|
||||
"minecraft:colored_torch_rg": "minecraft:colored_torch_rg",
|
||||
"minecraft:command_block": "minecraft:command_block",
|
||||
"minecraft:composter": "minecraft:composter",
|
||||
"minecraft:concrete": "minecraft:concrete",
|
||||
"minecraft:concrete_powder": "minecraft:concretePowder",
|
||||
"minecraft:conduit": "minecraft:conduit",
|
||||
"minecraft:coral": "minecraft:coral",
|
||||
"minecraft:coral_block": "minecraft:coral_block",
|
||||
"minecraft:coral_fan": "minecraft:coral_fan",
|
||||
"minecraft:coral_fan_dead": "minecraft:coral_fan_dead",
|
||||
"minecraft:coral_fan_hang": "minecraft:coral_fan_hang",
|
||||
"minecraft:coral_fan_hang2": "minecraft:coral_fan_hang2",
|
||||
"minecraft:coral_fan_hang3": "minecraft:coral_fan_hang3",
|
||||
"minecraft:crafting_table": "minecraft:crafting_table",
|
||||
"minecraft:cyan_glazed_terracotta": "minecraft:cyan_glazed_terracotta",
|
||||
"minecraft:dark_oak_button": "minecraft:dark_oak_button",
|
||||
"minecraft:dark_oak_fence_gate": "minecraft:dark_oak_fence_gate",
|
||||
"minecraft:dark_oak_pressure_plate": "minecraft:dark_oak_pressure_plate",
|
||||
"minecraft:dark_oak_stairs": "minecraft:dark_oak_stairs",
|
||||
"minecraft:dark_oak_trapdoor": "minecraft:dark_oak_trapdoor",
|
||||
"minecraft:dark_prismarine_stairs": "minecraft:dark_prismarine_stairs",
|
||||
"minecraft:darkoak_standing_sign": "minecraft:darkoak_standing_sign",
|
||||
"minecraft:darkoak_wall_sign": "minecraft:darkoak_wall_sign",
|
||||
"minecraft:daylight_detector": "minecraft:daylight_detector",
|
||||
"minecraft:daylight_detector_inverted": "minecraft:daylight_detector_inverted",
|
||||
"minecraft:deadbush": "minecraft:deadbush",
|
||||
"minecraft:detector_rail": "minecraft:detector_rail",
|
||||
"minecraft:diamond_block": "minecraft:diamond_block",
|
||||
"minecraft:diamond_ore": "minecraft:diamond_ore",
|
||||
"minecraft:diorite_stairs": "minecraft:diorite_stairs",
|
||||
"minecraft:dirt": "minecraft:dirt",
|
||||
"minecraft:dispenser": "minecraft:dispenser",
|
||||
"minecraft:double_plant": "minecraft:double_plant",
|
||||
"minecraft:double_stone_slab": "minecraft:stone_slab",
|
||||
"minecraft:double_stone_slab2": "minecraft:stone_slab2",
|
||||
"minecraft:double_stone_slab3": "minecraft:stone_slab3",
|
||||
"minecraft:double_stone_slab4": "minecraft:stone_slab4",
|
||||
"minecraft:double_wooden_slab": "minecraft:double_wooden_slab",
|
||||
"minecraft:dragon_egg": "minecraft:dragon_egg",
|
||||
"minecraft:dried_kelp_block": "minecraft:dried_kelp_block",
|
||||
"minecraft:dropper": "minecraft:dropper",
|
||||
"minecraft:element_0": "minecraft:element_0",
|
||||
"minecraft:element_1": "minecraft:element_1",
|
||||
"minecraft:element_10": "minecraft:element_10",
|
||||
"minecraft:element_100": "minecraft:element_100",
|
||||
"minecraft:element_101": "minecraft:element_101",
|
||||
"minecraft:element_102": "minecraft:element_102",
|
||||
"minecraft:element_103": "minecraft:element_103",
|
||||
"minecraft:element_104": "minecraft:element_104",
|
||||
"minecraft:element_105": "minecraft:element_105",
|
||||
"minecraft:element_106": "minecraft:element_106",
|
||||
"minecraft:element_107": "minecraft:element_107",
|
||||
"minecraft:element_108": "minecraft:element_108",
|
||||
"minecraft:element_109": "minecraft:element_109",
|
||||
"minecraft:element_11": "minecraft:element_11",
|
||||
"minecraft:element_110": "minecraft:element_110",
|
||||
"minecraft:element_111": "minecraft:element_111",
|
||||
"minecraft:element_112": "minecraft:element_112",
|
||||
"minecraft:element_113": "minecraft:element_113",
|
||||
"minecraft:element_114": "minecraft:element_114",
|
||||
"minecraft:element_115": "minecraft:element_115",
|
||||
"minecraft:element_116": "minecraft:element_116",
|
||||
"minecraft:element_117": "minecraft:element_117",
|
||||
"minecraft:element_118": "minecraft:element_118",
|
||||
"minecraft:element_12": "minecraft:element_12",
|
||||
"minecraft:element_13": "minecraft:element_13",
|
||||
"minecraft:element_14": "minecraft:element_14",
|
||||
"minecraft:element_15": "minecraft:element_15",
|
||||
"minecraft:element_16": "minecraft:element_16",
|
||||
"minecraft:element_17": "minecraft:element_17",
|
||||
"minecraft:element_18": "minecraft:element_18",
|
||||
"minecraft:element_19": "minecraft:element_19",
|
||||
"minecraft:element_2": "minecraft:element_2",
|
||||
"minecraft:element_20": "minecraft:element_20",
|
||||
"minecraft:element_21": "minecraft:element_21",
|
||||
"minecraft:element_22": "minecraft:element_22",
|
||||
"minecraft:element_23": "minecraft:element_23",
|
||||
"minecraft:element_24": "minecraft:element_24",
|
||||
"minecraft:element_25": "minecraft:element_25",
|
||||
"minecraft:element_26": "minecraft:element_26",
|
||||
"minecraft:element_27": "minecraft:element_27",
|
||||
"minecraft:element_28": "minecraft:element_28",
|
||||
"minecraft:element_29": "minecraft:element_29",
|
||||
"minecraft:element_3": "minecraft:element_3",
|
||||
"minecraft:element_30": "minecraft:element_30",
|
||||
"minecraft:element_31": "minecraft:element_31",
|
||||
"minecraft:element_32": "minecraft:element_32",
|
||||
"minecraft:element_33": "minecraft:element_33",
|
||||
"minecraft:element_34": "minecraft:element_34",
|
||||
"minecraft:element_35": "minecraft:element_35",
|
||||
"minecraft:element_36": "minecraft:element_36",
|
||||
"minecraft:element_37": "minecraft:element_37",
|
||||
"minecraft:element_38": "minecraft:element_38",
|
||||
"minecraft:element_39": "minecraft:element_39",
|
||||
"minecraft:element_4": "minecraft:element_4",
|
||||
"minecraft:element_40": "minecraft:element_40",
|
||||
"minecraft:element_41": "minecraft:element_41",
|
||||
"minecraft:element_42": "minecraft:element_42",
|
||||
"minecraft:element_43": "minecraft:element_43",
|
||||
"minecraft:element_44": "minecraft:element_44",
|
||||
"minecraft:element_45": "minecraft:element_45",
|
||||
"minecraft:element_46": "minecraft:element_46",
|
||||
"minecraft:element_47": "minecraft:element_47",
|
||||
"minecraft:element_48": "minecraft:element_48",
|
||||
"minecraft:element_49": "minecraft:element_49",
|
||||
"minecraft:element_5": "minecraft:element_5",
|
||||
"minecraft:element_50": "minecraft:element_50",
|
||||
"minecraft:element_51": "minecraft:element_51",
|
||||
"minecraft:element_52": "minecraft:element_52",
|
||||
"minecraft:element_53": "minecraft:element_53",
|
||||
"minecraft:element_54": "minecraft:element_54",
|
||||
"minecraft:element_55": "minecraft:element_55",
|
||||
"minecraft:element_56": "minecraft:element_56",
|
||||
"minecraft:element_57": "minecraft:element_57",
|
||||
"minecraft:element_58": "minecraft:element_58",
|
||||
"minecraft:element_59": "minecraft:element_59",
|
||||
"minecraft:element_6": "minecraft:element_6",
|
||||
"minecraft:element_60": "minecraft:element_60",
|
||||
"minecraft:element_61": "minecraft:element_61",
|
||||
"minecraft:element_62": "minecraft:element_62",
|
||||
"minecraft:element_63": "minecraft:element_63",
|
||||
"minecraft:element_64": "minecraft:element_64",
|
||||
"minecraft:element_65": "minecraft:element_65",
|
||||
"minecraft:element_66": "minecraft:element_66",
|
||||
"minecraft:element_67": "minecraft:element_67",
|
||||
"minecraft:element_68": "minecraft:element_68",
|
||||
"minecraft:element_69": "minecraft:element_69",
|
||||
"minecraft:element_7": "minecraft:element_7",
|
||||
"minecraft:element_70": "minecraft:element_70",
|
||||
"minecraft:element_71": "minecraft:element_71",
|
||||
"minecraft:element_72": "minecraft:element_72",
|
||||
"minecraft:element_73": "minecraft:element_73",
|
||||
"minecraft:element_74": "minecraft:element_74",
|
||||
"minecraft:element_75": "minecraft:element_75",
|
||||
"minecraft:element_76": "minecraft:element_76",
|
||||
"minecraft:element_77": "minecraft:element_77",
|
||||
"minecraft:element_78": "minecraft:element_78",
|
||||
"minecraft:element_79": "minecraft:element_79",
|
||||
"minecraft:element_8": "minecraft:element_8",
|
||||
"minecraft:element_80": "minecraft:element_80",
|
||||
"minecraft:element_81": "minecraft:element_81",
|
||||
"minecraft:element_82": "minecraft:element_82",
|
||||
"minecraft:element_83": "minecraft:element_83",
|
||||
"minecraft:element_84": "minecraft:element_84",
|
||||
"minecraft:element_85": "minecraft:element_85",
|
||||
"minecraft:element_86": "minecraft:element_86",
|
||||
"minecraft:element_87": "minecraft:element_87",
|
||||
"minecraft:element_88": "minecraft:element_88",
|
||||
"minecraft:element_89": "minecraft:element_89",
|
||||
"minecraft:element_9": "minecraft:element_9",
|
||||
"minecraft:element_90": "minecraft:element_90",
|
||||
"minecraft:element_91": "minecraft:element_91",
|
||||
"minecraft:element_92": "minecraft:element_92",
|
||||
"minecraft:element_93": "minecraft:element_93",
|
||||
"minecraft:element_94": "minecraft:element_94",
|
||||
"minecraft:element_95": "minecraft:element_95",
|
||||
"minecraft:element_96": "minecraft:element_96",
|
||||
"minecraft:element_97": "minecraft:element_97",
|
||||
"minecraft:element_98": "minecraft:element_98",
|
||||
"minecraft:element_99": "minecraft:element_99",
|
||||
"minecraft:emerald_block": "minecraft:emerald_block",
|
||||
"minecraft:emerald_ore": "minecraft:emerald_ore",
|
||||
"minecraft:enchanting_table": "minecraft:enchanting_table",
|
||||
"minecraft:end_brick_stairs": "minecraft:end_brick_stairs",
|
||||
"minecraft:end_bricks": "minecraft:end_bricks",
|
||||
"minecraft:end_gateway": "minecraft:end_gateway",
|
||||
"minecraft:end_portal": "minecraft:end_portal",
|
||||
"minecraft:end_portal_frame": "minecraft:end_portal_frame",
|
||||
"minecraft:end_rod": "minecraft:end_rod",
|
||||
"minecraft:end_stone": "minecraft:end_stone",
|
||||
"minecraft:ender_chest": "minecraft:ender_chest",
|
||||
"minecraft:farmland": "minecraft:farmland",
|
||||
"minecraft:fence": "minecraft:fence",
|
||||
"minecraft:fence_gate": "minecraft:fence_gate",
|
||||
"minecraft:fire": "minecraft:fire",
|
||||
"minecraft:fletching_table": "minecraft:fletching_table",
|
||||
"minecraft:flowing_lava": "minecraft:flowing_lava",
|
||||
"minecraft:flowing_water": "minecraft:flowing_water",
|
||||
"minecraft:frosted_ice": "minecraft:frosted_ice",
|
||||
"minecraft:furnace": "minecraft:furnace",
|
||||
"minecraft:glass": "minecraft:glass",
|
||||
"minecraft:glass_pane": "minecraft:glass_pane",
|
||||
"minecraft:glazedterracotta.black": "minecraft:black_glazed_terracotta",
|
||||
"minecraft:glazedterracotta.blue": "minecraft:blue_glazed_terracotta",
|
||||
"minecraft:glazedterracotta.brown": "minecraft:brown_glazed_terracotta",
|
||||
"minecraft:glazedterracotta.cyan": "minecraft:cyan_glazed_terracotta",
|
||||
"minecraft:glazedterracotta.gray": "minecraft:gray_glazed_terracotta",
|
||||
"minecraft:glazedterracotta.green": "minecraft:green_glazed_terracotta",
|
||||
"minecraft:glazedterracotta.light_blue": "minecraft:light_blue_glazed_terracotta",
|
||||
"minecraft:glazedterracotta.lime": "minecraft:lime_glazed_terracotta",
|
||||
"minecraft:glazedterracotta.magenta": "minecraft:magenta_glazed_terracotta",
|
||||
"minecraft:glazedterracotta.orange": "minecraft:orange_glazed_terracotta",
|
||||
"minecraft:glazedterracotta.pink": "minecraft:pink_glazed_terracotta",
|
||||
"minecraft:glazedterracotta.purple": "minecraft:purple_glazed_terracotta",
|
||||
"minecraft:glazedterracotta.red": "minecraft:red_glazed_terracotta",
|
||||
"minecraft:glazedterracotta.silver": "minecraft:silver_glazed_terracotta",
|
||||
"minecraft:glazedterracotta.white": "minecraft:white_glazed_terracotta",
|
||||
"minecraft:glazedterracotta.yellow": "minecraft:yellow_glazed_terracotta",
|
||||
"minecraft:glowingobsidian": "minecraft:glowingobsidian",
|
||||
"minecraft:glowstone": "minecraft:glowstone",
|
||||
"minecraft:gold_block": "minecraft:gold_block",
|
||||
"minecraft:gold_ore": "minecraft:gold_ore",
|
||||
"minecraft:golden_rail": "minecraft:golden_rail",
|
||||
"minecraft:granite_stairs": "minecraft:granite_stairs",
|
||||
"minecraft:grass": "minecraft:grass",
|
||||
"minecraft:grass_path": "minecraft:grass_path",
|
||||
"minecraft:gravel": "minecraft:gravel",
|
||||
"minecraft:gray_glazed_terracotta": "minecraft:gray_glazed_terracotta",
|
||||
"minecraft:green_glazed_terracotta": "minecraft:green_glazed_terracotta",
|
||||
"minecraft:grindstone": "minecraft:grindstone",
|
||||
"minecraft:hard_glass": "minecraft:hard_glass",
|
||||
"minecraft:hard_glass_pane": "minecraft:hard_glass_pane",
|
||||
"minecraft:hard_stained_glass": "minecraft:hard_stained_glass",
|
||||
"minecraft:hard_stained_glass_pane": "minecraft:hard_stained_glass_pane",
|
||||
"minecraft:hardened_clay": "minecraft:hardened_clay",
|
||||
"minecraft:hay_block": "minecraft:hay_block",
|
||||
"minecraft:heavy_weighted_pressure_plate": "minecraft:heavy_weighted_pressure_plate",
|
||||
"minecraft:ice": "minecraft:ice",
|
||||
"minecraft:info_update": "minecraft:info_update",
|
||||
"minecraft:info_update2": "minecraft:info_update2",
|
||||
"minecraft:invisiblebedrock": "minecraft:invisibleBedrock",
|
||||
"minecraft:iron_bars": "minecraft:iron_bars",
|
||||
"minecraft:iron_block": "minecraft:iron_block",
|
||||
"minecraft:iron_ore": "minecraft:iron_ore",
|
||||
"minecraft:iron_trapdoor": "minecraft:iron_trapdoor",
|
||||
"minecraft:item.acacia_door": "minecraft:acacia_door",
|
||||
"minecraft:item.bed": "minecraft:bed",
|
||||
"minecraft:item.beetroot": "minecraft:beetroot",
|
||||
"minecraft:item.birch_door": "minecraft:birch_door",
|
||||
"minecraft:item.cake": "minecraft:cake",
|
||||
"minecraft:item.campfire": "minecraft:campfire",
|
||||
"minecraft:item.cauldron": "minecraft:cauldron",
|
||||
"minecraft:item.dark_oak_door": "minecraft:dark_oak_door",
|
||||
"minecraft:item.flower_pot": "minecraft:flower_pot",
|
||||
"minecraft:item.frame": "minecraft:frame",
|
||||
"minecraft:item.hopper": "minecraft:hopper",
|
||||
"minecraft:item.iron_door": "minecraft:iron_door",
|
||||
"minecraft:item.jungle_door": "minecraft:jungle_door",
|
||||
"minecraft:item.kelp": "minecraft:kelp",
|
||||
"minecraft:item.nether_wart": "minecraft:nether_wart",
|
||||
"minecraft:item.reeds": "minecraft:reeds",
|
||||
"minecraft:item.skull": "minecraft:skull",
|
||||
"minecraft:item.spruce_door": "minecraft:spruce_door",
|
||||
"minecraft:item.wheat": "minecraft:wheat",
|
||||
"minecraft:item.wooden_door": "minecraft:wooden_door",
|
||||
"minecraft:jigsaw": "minecraft:jigsaw",
|
||||
"minecraft:jukebox": "minecraft:jukebox",
|
||||
"minecraft:jungle_button": "minecraft:jungle_button",
|
||||
"minecraft:jungle_fence_gate": "minecraft:jungle_fence_gate",
|
||||
"minecraft:jungle_pressure_plate": "minecraft:jungle_pressure_plate",
|
||||
"minecraft:jungle_stairs": "minecraft:jungle_stairs",
|
||||
"minecraft:jungle_standing_sign": "minecraft:jungle_standing_sign",
|
||||
"minecraft:jungle_trapdoor": "minecraft:jungle_trapdoor",
|
||||
"minecraft:jungle_wall_sign": "minecraft:jungle_wall_sign",
|
||||
"minecraft:ladder": "minecraft:ladder",
|
||||
"minecraft:lantern": "minecraft:lantern",
|
||||
"minecraft:lapis_block": "minecraft:lapis_block",
|
||||
"minecraft:lapis_ore": "minecraft:lapis_ore",
|
||||
"minecraft:lava": "minecraft:lava",
|
||||
"minecraft:lava_cauldron": "minecraft:lava_cauldron",
|
||||
"minecraft:leaves": "minecraft:leaves",
|
||||
"minecraft:leaves2": "minecraft:leaves2",
|
||||
"minecraft:lectern": "minecraft:lectern",
|
||||
"minecraft:lever": "minecraft:lever",
|
||||
"minecraft:light_blue_glazed_terracotta": "minecraft:light_blue_glazed_terracotta",
|
||||
"minecraft:light_weighted_pressure_plate": "minecraft:light_weighted_pressure_plate",
|
||||
"minecraft:lime_glazed_terracotta": "minecraft:lime_glazed_terracotta",
|
||||
"minecraft:lit_blast_furnace": "minecraft:lit_blast_furnace",
|
||||
"minecraft:lit_furnace": "minecraft:lit_furnace",
|
||||
"minecraft:lit_pumpkin": "minecraft:lit_pumpkin",
|
||||
"minecraft:lit_redstone_lamp": "minecraft:lit_redstone_lamp",
|
||||
"minecraft:lit_redstone_ore": "minecraft:lit_redstone_ore",
|
||||
"minecraft:lit_smoker": "minecraft:lit_smoker",
|
||||
"minecraft:log": "minecraft:log",
|
||||
"minecraft:log2": "minecraft:log2",
|
||||
"minecraft:loom": "minecraft:loom",
|
||||
"minecraft:magenta_glazed_terracotta": "minecraft:magenta_glazed_terracotta",
|
||||
"minecraft:magma": "minecraft:magma",
|
||||
"minecraft:melon_block": "minecraft:melon_block",
|
||||
"minecraft:melon_stem": "minecraft:melon_stem",
|
||||
"minecraft:mob_spawner": "minecraft:mob_spawner",
|
||||
"minecraft:monster_egg": "minecraft:monster_egg",
|
||||
"minecraft:mossy_cobblestone": "minecraft:mossy_cobblestone",
|
||||
"minecraft:mossy_cobblestone_stairs": "minecraft:mossy_cobblestone_stairs",
|
||||
"minecraft:mossy_stone_brick_stairs": "minecraft:mossy_stone_brick_stairs",
|
||||
"minecraft:movingblock": "minecraft:movingBlock",
|
||||
"minecraft:mycelium": "minecraft:mycelium",
|
||||
"minecraft:nether_brick": "minecraft:nether_brick",
|
||||
"minecraft:nether_brick_fence": "minecraft:nether_brick_fence",
|
||||
"minecraft:nether_brick_stairs": "minecraft:nether_brick_stairs",
|
||||
"minecraft:nether_wart_block": "minecraft:nether_wart_block",
|
||||
"minecraft:netherrack": "minecraft:netherrack",
|
||||
"minecraft:netherreactor": "minecraft:netherreactor",
|
||||
"minecraft:normal_stone_stairs": "minecraft:normal_stone_stairs",
|
||||
"minecraft:noteblock": "minecraft:noteblock",
|
||||
"minecraft:oak_stairs": "minecraft:oak_stairs",
|
||||
"minecraft:observer": "minecraft:observer",
|
||||
"minecraft:obsidian": "minecraft:obsidian",
|
||||
"minecraft:orange_glazed_terracotta": "minecraft:orange_glazed_terracotta",
|
||||
"minecraft:packed_ice": "minecraft:packed_ice",
|
||||
"minecraft:pink_glazed_terracotta": "minecraft:pink_glazed_terracotta",
|
||||
"minecraft:piston": "minecraft:piston",
|
||||
"minecraft:pistonarmcollision": "minecraft:pistonArmCollision",
|
||||
"minecraft:planks": "minecraft:planks",
|
||||
"minecraft:podzol": "minecraft:podzol",
|
||||
"minecraft:polished_andesite_stairs": "minecraft:polished_andesite_stairs",
|
||||
"minecraft:polished_diorite_stairs": "minecraft:polished_diorite_stairs",
|
||||
"minecraft:polished_granite_stairs": "minecraft:polished_granite_stairs",
|
||||
"minecraft:portal": "minecraft:portal",
|
||||
"minecraft:potatoes": "minecraft:potatoes",
|
||||
"minecraft:powered_comparator": "minecraft:powered_comparator",
|
||||
"minecraft:powered_repeater": "minecraft:powered_repeater",
|
||||
"minecraft:prismarine": "minecraft:prismarine",
|
||||
"minecraft:prismarine_bricks_stairs": "minecraft:prismarine_bricks_stairs",
|
||||
"minecraft:prismarine_stairs": "minecraft:prismarine_stairs",
|
||||
"minecraft:pumpkin": "minecraft:pumpkin",
|
||||
"minecraft:pumpkin_stem": "minecraft:pumpkin_stem",
|
||||
"minecraft:purple_glazed_terracotta": "minecraft:purple_glazed_terracotta",
|
||||
"minecraft:purpur_block": "minecraft:purpur_block",
|
||||
"minecraft:purpur_stairs": "minecraft:purpur_stairs",
|
||||
"minecraft:quartz_block": "minecraft:quartz_block",
|
||||
"minecraft:quartz_ore": "minecraft:quartz_ore",
|
||||
"minecraft:quartz_stairs": "minecraft:quartz_stairs",
|
||||
"minecraft:rail": "minecraft:rail",
|
||||
"minecraft:real_double_stone_slab": "minecraft:double_stone_slab",
|
||||
"minecraft:real_double_stone_slab2": "minecraft:double_stone_slab2",
|
||||
"minecraft:real_double_stone_slab3": "minecraft:double_stone_slab3",
|
||||
"minecraft:real_double_stone_slab4": "minecraft:double_stone_slab4",
|
||||
"minecraft:red_flower": "minecraft:red_flower",
|
||||
"minecraft:red_glazed_terracotta": "minecraft:red_glazed_terracotta",
|
||||
"minecraft:red_mushroom": "minecraft:red_mushroom",
|
||||
"minecraft:red_mushroom_block": "minecraft:red_mushroom_block",
|
||||
"minecraft:red_nether_brick": "minecraft:red_nether_brick",
|
||||
"minecraft:red_nether_brick_stairs": "minecraft:red_nether_brick_stairs",
|
||||
"minecraft:red_sandstone": "minecraft:red_sandstone",
|
||||
"minecraft:red_sandstone_stairs": "minecraft:red_sandstone_stairs",
|
||||
"minecraft:redstone_block": "minecraft:redstone_block",
|
||||
"minecraft:redstone_lamp": "minecraft:redstone_lamp",
|
||||
"minecraft:redstone_ore": "minecraft:redstone_ore",
|
||||
"minecraft:redstone_torch": "minecraft:redstone_torch",
|
||||
"minecraft:redstone_wire": "minecraft:redstone_wire",
|
||||
"minecraft:repeating_command_block": "minecraft:repeating_command_block",
|
||||
"minecraft:reserved6": "minecraft:reserved6",
|
||||
"minecraft:sand": "minecraft:sand",
|
||||
"minecraft:sandstone": "minecraft:sandstone",
|
||||
"minecraft:sandstone_stairs": "minecraft:sandstone_stairs",
|
||||
"minecraft:sapling": "minecraft:sapling",
|
||||
"minecraft:scaffolding": "minecraft:scaffolding",
|
||||
"minecraft:sea_pickle": "minecraft:sea_pickle",
|
||||
"minecraft:seagrass": "minecraft:seagrass",
|
||||
"minecraft:sealantern": "minecraft:seaLantern",
|
||||
"minecraft:shulker_box": "minecraft:shulker_box",
|
||||
"minecraft:silver_glazed_terracotta": "minecraft:silver_glazed_terracotta",
|
||||
"minecraft:slime": "minecraft:slime",
|
||||
"minecraft:smithing_table": "minecraft:smithing_table",
|
||||
"minecraft:smoker": "minecraft:smoker",
|
||||
"minecraft:smooth_quartz_stairs": "minecraft:smooth_quartz_stairs",
|
||||
"minecraft:smooth_red_sandstone_stairs": "minecraft:smooth_red_sandstone_stairs",
|
||||
"minecraft:smooth_sandstone_stairs": "minecraft:smooth_sandstone_stairs",
|
||||
"minecraft:smooth_stone": "minecraft:smooth_stone",
|
||||
"minecraft:snow": "minecraft:snow",
|
||||
"minecraft:snow_layer": "minecraft:snow_layer",
|
||||
"minecraft:soul_sand": "minecraft:soul_sand",
|
||||
"minecraft:sponge": "minecraft:sponge",
|
||||
"minecraft:spruce_button": "minecraft:spruce_button",
|
||||
"minecraft:spruce_fence_gate": "minecraft:spruce_fence_gate",
|
||||
"minecraft:spruce_pressure_plate": "minecraft:spruce_pressure_plate",
|
||||
"minecraft:spruce_stairs": "minecraft:spruce_stairs",
|
||||
"minecraft:spruce_standing_sign": "minecraft:spruce_standing_sign",
|
||||
"minecraft:spruce_trapdoor": "minecraft:spruce_trapdoor",
|
||||
"minecraft:spruce_wall_sign": "minecraft:spruce_wall_sign",
|
||||
"minecraft:stained_glass": "minecraft:stained_glass",
|
||||
"minecraft:stained_glass_pane": "minecraft:stained_glass_pane",
|
||||
"minecraft:stained_hardened_clay": "minecraft:stained_hardened_clay",
|
||||
"minecraft:standing_banner": "minecraft:standing_banner",
|
||||
"minecraft:standing_sign": "minecraft:standing_sign",
|
||||
"minecraft:sticky_piston": "minecraft:sticky_piston",
|
||||
"minecraft:stone": "minecraft:stone",
|
||||
"minecraft:stone_brick_stairs": "minecraft:stone_brick_stairs",
|
||||
"minecraft:stone_button": "minecraft:stone_button",
|
||||
"minecraft:stone_pressure_plate": "minecraft:stone_pressure_plate",
|
||||
"minecraft:stone_slab": "minecraft:stone_slab",
|
||||
"minecraft:stone_slab2": "minecraft:stone_slab2",
|
||||
"minecraft:stone_slab3": "minecraft:stone_slab3",
|
||||
"minecraft:stone_slab4": "minecraft:stone_slab4",
|
||||
"minecraft:stone_stairs": "minecraft:stone_stairs",
|
||||
"minecraft:stonebrick": "minecraft:stonebrick",
|
||||
"minecraft:stonecutter": "minecraft:stonecutter",
|
||||
"minecraft:stonecutter_block": "minecraft:stonecutter_block",
|
||||
"minecraft:stripped_acacia_log": "minecraft:stripped_acacia_log",
|
||||
"minecraft:stripped_birch_log": "minecraft:stripped_birch_log",
|
||||
"minecraft:stripped_dark_oak_log": "minecraft:stripped_dark_oak_log",
|
||||
"minecraft:stripped_jungle_log": "minecraft:stripped_jungle_log",
|
||||
"minecraft:stripped_oak_log": "minecraft:stripped_oak_log",
|
||||
"minecraft:stripped_spruce_log": "minecraft:stripped_spruce_log",
|
||||
"minecraft:structure_block": "minecraft:structure_block",
|
||||
"minecraft:sweet_berry_bush": "minecraft:sweet_berry_bush",
|
||||
"minecraft:tallgrass": "minecraft:tallgrass",
|
||||
"minecraft:tnt": "minecraft:tnt",
|
||||
"minecraft:torch": "minecraft:torch",
|
||||
"minecraft:trapdoor": "minecraft:trapdoor",
|
||||
"minecraft:trapped_chest": "minecraft:trapped_chest",
|
||||
"minecraft:tripwire": "minecraft:tripWire",
|
||||
"minecraft:tripwire_hook": "minecraft:tripwire_hook",
|
||||
"minecraft:turtle_egg": "minecraft:turtle_egg",
|
||||
"minecraft:underwater_torch": "minecraft:underwater_torch",
|
||||
"minecraft:undyed_shulker_box": "minecraft:undyed_shulker_box",
|
||||
"minecraft:unlit_redstone_torch": "minecraft:unlit_redstone_torch",
|
||||
"minecraft:unpowered_comparator": "minecraft:unpowered_comparator",
|
||||
"minecraft:unpowered_repeater": "minecraft:unpowered_repeater",
|
||||
"minecraft:vine": "minecraft:vine",
|
||||
"minecraft:wall_banner": "minecraft:wall_banner",
|
||||
"minecraft:wall_sign": "minecraft:wall_sign",
|
||||
"minecraft:water": "minecraft:water",
|
||||
"minecraft:waterlily": "minecraft:waterlily",
|
||||
"minecraft:web": "minecraft:web",
|
||||
"minecraft:white_glazed_terracotta": "minecraft:white_glazed_terracotta",
|
||||
"minecraft:wood": "minecraft:wood",
|
||||
"minecraft:wooden_button": "minecraft:wooden_button",
|
||||
"minecraft:wooden_pressure_plate": "minecraft:wooden_pressure_plate",
|
||||
"minecraft:wooden_slab": "minecraft:wooden_slab",
|
||||
"minecraft:wool": "minecraft:wool",
|
||||
"minecraft:yellow_flower": "minecraft:yellow_flower",
|
||||
"minecraft:yellow_glazed_terracotta": "minecraft:yellow_glazed_terracotta"
|
||||
}
|
||||
BIN
internal/item/1.12.0_to_1.18.10_blockstate_map.bin
Normal file
BIN
internal/item/1.12.0_to_1.18.10_blockstate_map.bin
Normal file
Binary file not shown.
110
internal/item/registry.go
Normal file
110
internal/item/registry.go
Normal file
@@ -0,0 +1,110 @@
|
||||
package item
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"embed"
|
||||
"encoding/json"
|
||||
"github.com/df-mc/worldupgrader/blockupgrader"
|
||||
"github.com/sandertv/gophertunnel/minecraft/nbt"
|
||||
"github.com/sandertv/gophertunnel/minecraft/protocol"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
var (
|
||||
//go:embed schemas/*.json
|
||||
schemasFS embed.FS
|
||||
//go:embed 1.12.0_item_id_to_block_id_map.json
|
||||
rawItemToBlockIdMap []byte
|
||||
//go:embed 1.12.0_to_1.18.10_blockstate_map.bin
|
||||
rawblockStateMap []byte
|
||||
// schemaIDs is a list of ids from all registered schemas.
|
||||
schemaIDs []int
|
||||
// schemas is a map of all registered item upgrade schemas.
|
||||
schemas map[uint16]schema
|
||||
// itemToBlockIdMap is a list of all registered item upgrade schemas.
|
||||
itemToBlockIdMap map[string]string
|
||||
// blockStateMap is a list of all legacy block states mapped to an upgraded version of it.
|
||||
blockStateMap map[stateHash]blockupgrader.BlockState
|
||||
|
||||
filenameRegex = regexp.MustCompile(`(\d{4})_[\w.]+\.json`)
|
||||
)
|
||||
|
||||
// stateHash is a struct that may be used as a map key for block states.
|
||||
type stateHash struct {
|
||||
// Name is the name of the block. It looks like 'minecraft:stone'.
|
||||
Name string
|
||||
// Metadata is the metadata value of the block. A lot of blocks only have 0 as data value, but some blocks
|
||||
// carry specific variants or properties encoded in the metadata.
|
||||
Metadata uint32
|
||||
}
|
||||
|
||||
// init ...
|
||||
func init() {
|
||||
schemas = make(map[uint16]schema)
|
||||
files, err := schemasFS.ReadDir("schemas")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
for _, f := range files {
|
||||
if f.IsDir() {
|
||||
continue
|
||||
}
|
||||
subMatches := filenameRegex.FindStringSubmatch(f.Name())
|
||||
if subMatches == nil {
|
||||
continue
|
||||
}
|
||||
id, err := strconv.Atoi(subMatches[1])
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
buf, err := schemasFS.ReadFile("schemas/" + f.Name())
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
var s schema
|
||||
if err = json.Unmarshal(buf, &s); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
schemas[uint16(id)] = s
|
||||
}
|
||||
schemaIDs = make([]int, 0, len(schemas))
|
||||
for k := range schemas {
|
||||
schemaIDs = append(schemaIDs, int(k))
|
||||
}
|
||||
sort.Sort(sort.Reverse(sort.IntSlice(schemaIDs)))
|
||||
|
||||
if err = json.Unmarshal(rawItemToBlockIdMap, &itemToBlockIdMap); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
blockStateMap = make(map[stateHash]blockupgrader.BlockState)
|
||||
buf := protocol.NewReader(bytes.NewBuffer(rawblockStateMap), 0, false)
|
||||
var length uint32
|
||||
buf.Varuint32(&length)
|
||||
for i := uint32(0); i < length; i++ {
|
||||
var legacyStringId string
|
||||
buf.String(&legacyStringId)
|
||||
|
||||
var pairs uint32
|
||||
buf.Varuint32(&pairs)
|
||||
for y := uint32(0); y < pairs; y++ {
|
||||
var meta uint32
|
||||
buf.Varuint32(&meta)
|
||||
|
||||
var blockStateRaw map[string]any
|
||||
buf.NBT(&blockStateRaw, nbt.LittleEndian)
|
||||
latestBlockState := blockupgrader.Upgrade(blockupgrader.BlockState{
|
||||
Name: blockStateRaw["name"].(string),
|
||||
Properties: blockStateRaw["states"].(map[string]any),
|
||||
Version: blockStateRaw["version"].(int32),
|
||||
})
|
||||
blockStateMap[stateHash{
|
||||
Name: legacyStringId,
|
||||
Metadata: meta,
|
||||
}] = latestBlockState
|
||||
}
|
||||
}
|
||||
}
|
||||
7
internal/item/schema.go
Normal file
7
internal/item/schema.go
Normal file
@@ -0,0 +1,7 @@
|
||||
package item
|
||||
|
||||
// schema represents the schema for loading item upgrade data from a JSON file.
|
||||
type schema struct {
|
||||
RenamedIDs map[string]string `json:"renamedIds,omitempty"`
|
||||
RemappedMetas map[string]map[uint32]string `json:"remappedMetas,omitempty"`
|
||||
}
|
||||
10
internal/item/schemas/0001_1.6_beta_to_1.6.0.json
Normal file
10
internal/item/schemas/0001_1.6_beta_to_1.6.0.json
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"renamedIds": {
|
||||
"minecraft:nametag": "minecraft:name_tag",
|
||||
"minecraft:prismarineshard": "minecraft:prismarine_shard",
|
||||
"minecraft:stone_slab": "minecraft:double_stone_slab",
|
||||
"minecraft:stone_slab2": "minecraft:double_stone_slab2",
|
||||
"minecraft:stone_slab3": "minecraft:double_stone_slab3",
|
||||
"minecraft:stone_slab4": "minecraft:double_stone_slab4"
|
||||
}
|
||||
}
|
||||
20
internal/item/schemas/0011_1.11.4_to_1.12.0.json
Normal file
20
internal/item/schemas/0011_1.11.4_to_1.12.0.json
Normal file
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"renamedIds": {
|
||||
"minecraft:glazedterracotta.black": "minecraft:black_glazed_terracotta",
|
||||
"minecraft:glazedterracotta.blue": "minecraft:blue_glazed_terracotta",
|
||||
"minecraft:glazedterracotta.brown": "minecraft:brown_glazed_terracotta",
|
||||
"minecraft:glazedterracotta.cyan": "minecraft:cyan_glazed_terracotta",
|
||||
"minecraft:glazedterracotta.gray": "minecraft:gray_glazed_terracotta",
|
||||
"minecraft:glazedterracotta.green": "minecraft:green_glazed_terracotta",
|
||||
"minecraft:glazedterracotta.light_blue": "minecraft:light_blue_glazed_terracotta",
|
||||
"minecraft:glazedterracotta.lime": "minecraft:lime_glazed_terracotta",
|
||||
"minecraft:glazedterracotta.magenta": "minecraft:magenta_glazed_terracotta",
|
||||
"minecraft:glazedterracotta.orange": "minecraft:orange_glazed_terracotta",
|
||||
"minecraft:glazedterracotta.pink": "minecraft:pink_glazed_terracotta",
|
||||
"minecraft:glazedterracotta.purple": "minecraft:purple_glazed_terracotta",
|
||||
"minecraft:glazedterracotta.red": "minecraft:red_glazed_terracotta",
|
||||
"minecraft:glazedterracotta.silver": "minecraft:silver_glazed_terracotta",
|
||||
"minecraft:glazedterracotta.white": "minecraft:white_glazed_terracotta",
|
||||
"minecraft:glazedterracotta.yellow": "minecraft:yellow_glazed_terracotta"
|
||||
}
|
||||
}
|
||||
165
internal/item/schemas/0021_1.16.0_to_1.16.100.json
Normal file
165
internal/item/schemas/0021_1.16.0_to_1.16.100.json
Normal file
@@ -0,0 +1,165 @@
|
||||
{
|
||||
"remappedMetas": {
|
||||
"minecraft:banner_pattern": {
|
||||
"0": "minecraft:creeper_banner_pattern",
|
||||
"1": "minecraft:skull_banner_pattern",
|
||||
"2": "minecraft:flower_banner_pattern",
|
||||
"3": "minecraft:mojang_banner_pattern",
|
||||
"4": "minecraft:field_masoned_banner_pattern",
|
||||
"5": "minecraft:bordure_indented_banner_pattern",
|
||||
"6": "minecraft:piglin_banner_pattern"
|
||||
},
|
||||
"minecraft:boat": {
|
||||
"0": "minecraft:oak_boat",
|
||||
"1": "minecraft:spruce_boat",
|
||||
"2": "minecraft:birch_boat",
|
||||
"3": "minecraft:jungle_boat",
|
||||
"4": "minecraft:acacia_boat",
|
||||
"5": "minecraft:dark_oak_boat"
|
||||
},
|
||||
"minecraft:bucket": {
|
||||
"1": "minecraft:milk_bucket",
|
||||
"10": "minecraft:lava_bucket",
|
||||
"2": "minecraft:cod_bucket",
|
||||
"3": "minecraft:salmon_bucket",
|
||||
"4": "minecraft:tropical_fish_bucket",
|
||||
"5": "minecraft:pufferfish_bucket",
|
||||
"8": "minecraft:water_bucket"
|
||||
},
|
||||
"minecraft:coal": {
|
||||
"1": "minecraft:charcoal"
|
||||
},
|
||||
"minecraft:dye": {
|
||||
"0": "minecraft:ink_sac",
|
||||
"1": "minecraft:red_dye",
|
||||
"10": "minecraft:lime_dye",
|
||||
"11": "minecraft:yellow_dye",
|
||||
"12": "minecraft:light_blue_dye",
|
||||
"13": "minecraft:magenta_dye",
|
||||
"14": "minecraft:orange_dye",
|
||||
"15": "minecraft:bone_meal",
|
||||
"16": "minecraft:black_dye",
|
||||
"17": "minecraft:brown_dye",
|
||||
"18": "minecraft:blue_dye",
|
||||
"19": "minecraft:white_dye",
|
||||
"2": "minecraft:green_dye",
|
||||
"3": "minecraft:cocoa_beans",
|
||||
"4": "minecraft:lapis_lazuli",
|
||||
"5": "minecraft:purple_dye",
|
||||
"6": "minecraft:cyan_dye",
|
||||
"7": "minecraft:light_gray_dye",
|
||||
"8": "minecraft:gray_dye",
|
||||
"9": "minecraft:pink_dye"
|
||||
},
|
||||
"minecraft:spawn_egg": {
|
||||
"10": "minecraft:chicken_spawn_egg",
|
||||
"104": "minecraft:evoker_spawn_egg",
|
||||
"105": "minecraft:vex_spawn_egg",
|
||||
"108": "minecraft:pufferfish_spawn_egg",
|
||||
"109": "minecraft:salmon_spawn_egg",
|
||||
"11": "minecraft:cow_spawn_egg",
|
||||
"110": "minecraft:drowned_spawn_egg",
|
||||
"111": "minecraft:tropical_fish_spawn_egg",
|
||||
"112": "minecraft:cod_spawn_egg",
|
||||
"113": "minecraft:panda_spawn_egg",
|
||||
"114": "minecraft:pillager_spawn_egg",
|
||||
"115": "minecraft:villager_spawn_egg",
|
||||
"116": "minecraft:zombie_villager_spawn_egg",
|
||||
"118": "minecraft:wandering_trader_spawn_egg",
|
||||
"12": "minecraft:pig_spawn_egg",
|
||||
"121": "minecraft:fox_spawn_egg",
|
||||
"122": "minecraft:bee_spawn_egg",
|
||||
"123": "minecraft:piglin_spawn_egg",
|
||||
"124": "minecraft:hoglin_spawn_egg",
|
||||
"125": "minecraft:strider_spawn_egg",
|
||||
"126": "minecraft:zoglin_spawn_egg",
|
||||
"127": "minecraft:piglin_brute_spawn_egg",
|
||||
"13": "minecraft:sheep_spawn_egg",
|
||||
"14": "minecraft:wolf_spawn_egg",
|
||||
"15": "minecraft:villager_spawn_egg",
|
||||
"16": "minecraft:mooshroom_spawn_egg",
|
||||
"17": "minecraft:squid_spawn_egg",
|
||||
"18": "minecraft:rabbit_spawn_egg",
|
||||
"19": "minecraft:bat_spawn_egg",
|
||||
"22": "minecraft:ocelot_spawn_egg",
|
||||
"23": "minecraft:horse_spawn_egg",
|
||||
"24": "minecraft:donkey_spawn_egg",
|
||||
"25": "minecraft:mule_spawn_egg",
|
||||
"26": "minecraft:skeleton_horse_spawn_egg",
|
||||
"27": "minecraft:zombie_horse_spawn_egg",
|
||||
"28": "minecraft:polar_bear_spawn_egg",
|
||||
"29": "minecraft:llama_spawn_egg",
|
||||
"30": "minecraft:parrot_spawn_egg",
|
||||
"31": "minecraft:dolphin_spawn_egg",
|
||||
"32": "minecraft:zombie_spawn_egg",
|
||||
"33": "minecraft:creeper_spawn_egg",
|
||||
"34": "minecraft:skeleton_spawn_egg",
|
||||
"35": "minecraft:spider_spawn_egg",
|
||||
"36": "minecraft:zombie_pigman_spawn_egg",
|
||||
"37": "minecraft:slime_spawn_egg",
|
||||
"38": "minecraft:enderman_spawn_egg",
|
||||
"39": "minecraft:silverfish_spawn_egg",
|
||||
"40": "minecraft:cave_spider_spawn_egg",
|
||||
"41": "minecraft:ghast_spawn_egg",
|
||||
"42": "minecraft:magma_cube_spawn_egg",
|
||||
"43": "minecraft:blaze_spawn_egg",
|
||||
"44": "minecraft:zombie_villager_spawn_egg",
|
||||
"45": "minecraft:witch_spawn_egg",
|
||||
"46": "minecraft:stray_spawn_egg",
|
||||
"47": "minecraft:husk_spawn_egg",
|
||||
"48": "minecraft:wither_skeleton_spawn_egg",
|
||||
"49": "minecraft:guardian_spawn_egg",
|
||||
"50": "minecraft:elder_guardian_spawn_egg",
|
||||
"51": "minecraft:npc_spawn_egg",
|
||||
"54": "minecraft:shulker_spawn_egg",
|
||||
"55": "minecraft:endermite_spawn_egg",
|
||||
"56": "minecraft:agent_spawn_egg",
|
||||
"57": "minecraft:vindicator_spawn_egg",
|
||||
"58": "minecraft:phantom_spawn_egg",
|
||||
"59": "minecraft:ravager_spawn_egg",
|
||||
"74": "minecraft:turtle_spawn_egg",
|
||||
"75": "minecraft:cat_spawn_egg"
|
||||
}
|
||||
},
|
||||
"renamedIds": {
|
||||
"minecraft:appleenchanted": "minecraft:enchanted_golden_apple",
|
||||
"minecraft:carrotonastick": "minecraft:carrot_on_a_stick",
|
||||
"minecraft:chorus_fruit_popped": "minecraft:popped_chorus_fruit",
|
||||
"minecraft:clownfish": "minecraft:tropical_fish",
|
||||
"minecraft:cooked_fish": "minecraft:cooked_cod",
|
||||
"minecraft:darkoak_sign": "minecraft:dark_oak_sign",
|
||||
"minecraft:emptymap": "minecraft:empty_map",
|
||||
"minecraft:fireball": "minecraft:fire_charge",
|
||||
"minecraft:fireworks": "minecraft:firework_rocket",
|
||||
"minecraft:fireworkscharge": "minecraft:firework_star",
|
||||
"minecraft:fish": "minecraft:cod",
|
||||
"minecraft:horsearmordiamond": "minecraft:diamond_horse_armor",
|
||||
"minecraft:horsearmorgold": "minecraft:golden_horse_armor",
|
||||
"minecraft:horsearmoriron": "minecraft:iron_horse_armor",
|
||||
"minecraft:horsearmorleather": "minecraft:leather_horse_armor",
|
||||
"minecraft:lodestonecompass": "minecraft:lodestone_compass",
|
||||
"minecraft:map": "minecraft:filled_map",
|
||||
"minecraft:melon": "minecraft:melon_slice",
|
||||
"minecraft:muttoncooked": "minecraft:cooked_mutton",
|
||||
"minecraft:muttonraw": "minecraft:mutton",
|
||||
"minecraft:netherstar": "minecraft:nether_star",
|
||||
"minecraft:record_11": "minecraft:music_disc_11",
|
||||
"minecraft:record_13": "minecraft:music_disc_13",
|
||||
"minecraft:record_blocks": "minecraft:music_disc_blocks",
|
||||
"minecraft:record_cat": "minecraft:music_disc_cat",
|
||||
"minecraft:record_chirp": "minecraft:music_disc_chirp",
|
||||
"minecraft:record_far": "minecraft:music_disc_far",
|
||||
"minecraft:record_mall": "minecraft:music_disc_mall",
|
||||
"minecraft:record_mellohi": "minecraft:music_disc_mellohi",
|
||||
"minecraft:record_pigstep": "minecraft:music_disc_pigstep",
|
||||
"minecraft:record_stal": "minecraft:music_disc_stal",
|
||||
"minecraft:record_strad": "minecraft:music_disc_strad",
|
||||
"minecraft:record_wait": "minecraft:music_disc_wait",
|
||||
"minecraft:record_ward": "minecraft:music_disc_ward",
|
||||
"minecraft:reeds": "minecraft:sugar_cane",
|
||||
"minecraft:sign": "minecraft:oak_sign",
|
||||
"minecraft:speckled_melon": "minecraft:glistering_melon_slice",
|
||||
"minecraft:totem": "minecraft:totem_of_undying",
|
||||
"minecraft:turtle_shell_piece": "minecraft:scute"
|
||||
}
|
||||
}
|
||||
7
internal/item/schemas/0031_1.16.100_to_1.16.200.json
Normal file
7
internal/item/schemas/0031_1.16.100_to_1.16.200.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"remappedMetas": {
|
||||
"minecraft:spawn_egg": {
|
||||
"128": "minecraft:goat_spawn_egg"
|
||||
}
|
||||
}
|
||||
}
|
||||
12
internal/item/schemas/0041_1.16.200_to_1.17.30.json
Normal file
12
internal/item/schemas/0041_1.16.200_to_1.17.30.json
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"remappedMetas": {
|
||||
"minecraft:bucket": {
|
||||
"11": "minecraft:powder_snow_bucket",
|
||||
"12": "minecraft:axolotl_bucket"
|
||||
},
|
||||
"minecraft:spawn_egg": {
|
||||
"129": "minecraft:glow_squid_spawn_egg",
|
||||
"130": "minecraft:axolotl_spawn_egg"
|
||||
}
|
||||
}
|
||||
}
|
||||
5
internal/item/schemas/0051_1.17.40_to_1.18.0.json
Normal file
5
internal/item/schemas/0051_1.17.40_to_1.18.0.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"renamedIds": {
|
||||
"minecraft:record_otherside": "minecraft:music_disc_otherside"
|
||||
}
|
||||
}
|
||||
16
internal/item/schemas/0061_1.18.0_to_1.18.10.json
Normal file
16
internal/item/schemas/0061_1.18.0_to_1.18.10.json
Normal file
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"remappedMetas": {
|
||||
"minecraft:banner_pattern": {
|
||||
"7": "minecraft:globe_banner_pattern"
|
||||
},
|
||||
"minecraft:bucket": {
|
||||
"13": "minecraft:tadpole_bucket"
|
||||
},
|
||||
"minecraft:spawn_egg": {
|
||||
"132": "minecraft:frog_spawn_egg",
|
||||
"133": "minecraft:tadpole_spawn_egg",
|
||||
"134": "minecraft:allay_spawn_egg",
|
||||
"135": "minecraft:firefly_spawn_egg"
|
||||
}
|
||||
}
|
||||
}
|
||||
23
internal/item/schemas/0071_1.18.10_to_1.18.30.json
Normal file
23
internal/item/schemas/0071_1.18.10_to_1.18.30.json
Normal file
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"remappedMetas": {
|
||||
"minecraft:chest_boat": {
|
||||
"0": "minecraft:oak_chest_boat",
|
||||
"1": "minecraft:spruce_chest_boat",
|
||||
"2": "minecraft:birch_chest_boat",
|
||||
"3": "minecraft:jungle_chest_boat",
|
||||
"4": "minecraft:acacia_chest_boat",
|
||||
"5": "minecraft:dark_oak_chest_boat"
|
||||
},
|
||||
"minecraft:spawn_egg": {
|
||||
"131": "minecraft:warden_spawn_egg"
|
||||
}
|
||||
},
|
||||
"renamedIds": {
|
||||
"minecraft:concretepowder": "minecraft:concrete_powder",
|
||||
"minecraft:invisiblebedrock": "minecraft:invisible_bedrock",
|
||||
"minecraft:movingblock": "minecraft:moving_block",
|
||||
"minecraft:pistonarmcollision": "minecraft:piston_arm_collision",
|
||||
"minecraft:sealantern": "minecraft:sea_lantern",
|
||||
"minecraft:stickypistonarmcollision": "minecraft:sticky_piston_arm_collision"
|
||||
}
|
||||
}
|
||||
25
internal/item/schemas/0081_1.18.30_to_1.19.30.34_beta.json
Normal file
25
internal/item/schemas/0081_1.18.30_to_1.19.30.34_beta.json
Normal file
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"remappedMetas": {
|
||||
"minecraft:boat": {
|
||||
"6": "minecraft:mangrove_boat"
|
||||
},
|
||||
"minecraft:chest_boat": {
|
||||
"6": "minecraft:mangrove_chest_boat"
|
||||
}
|
||||
},
|
||||
"renamedIds": {
|
||||
"minecraft:double_stone_slab": "minecraft:stone_block_slab",
|
||||
"minecraft:double_stone_slab2": "minecraft:stone_block_slab2",
|
||||
"minecraft:double_stone_slab3": "minecraft:stone_block_slab3",
|
||||
"minecraft:double_stone_slab4": "minecraft:stone_block_slab4",
|
||||
"minecraft:real_double_stone_slab": "minecraft:double_stone_block_slab",
|
||||
"minecraft:real_double_stone_slab2": "minecraft:double_stone_block_slab2",
|
||||
"minecraft:real_double_stone_slab3": "minecraft:double_stone_block_slab3",
|
||||
"minecraft:real_double_stone_slab4": "minecraft:double_stone_block_slab4",
|
||||
"minecraft:record_5": "minecraft:music_disc_5",
|
||||
"minecraft:stone_slab": "minecraft:stone_block_slab",
|
||||
"minecraft:stone_slab2": "minecraft:stone_block_slab2",
|
||||
"minecraft:stone_slab3": "minecraft:stone_block_slab3",
|
||||
"minecraft:stone_slab4": "minecraft:stone_block_slab4"
|
||||
}
|
||||
}
|
||||
37
internal/item/schemas/0091_1.19.60_to_1.19.70.26_beta.json
Normal file
37
internal/item/schemas/0091_1.19.60_to_1.19.70.26_beta.json
Normal file
@@ -0,0 +1,37 @@
|
||||
{
|
||||
"remappedMetas": {
|
||||
"minecraft:boat": {
|
||||
"7": "minecraft:bamboo_raft"
|
||||
},
|
||||
"minecraft:chest_boat": {
|
||||
"7": "minecraft:bamboo_chest_raft"
|
||||
},
|
||||
"minecraft:spawn_egg": {
|
||||
"138": "minecraft:camel_spawn_egg",
|
||||
"139": "minecraft:sniffer_spawn_egg",
|
||||
"157": "minecraft:trader_llama_spawn_egg",
|
||||
"20": "minecraft:iron_golem_spawn_egg",
|
||||
"21": "minecraft:snow_golem_spawn_egg",
|
||||
"52": "minecraft:wither_spawn_egg",
|
||||
"53": "minecraft:ender_dragon_spawn_egg"
|
||||
},
|
||||
"minecraft:wool": {
|
||||
"0": "minecraft:white_wool",
|
||||
"1": "minecraft:orange_wool",
|
||||
"10": "minecraft:purple_wool",
|
||||
"11": "minecraft:blue_wool",
|
||||
"12": "minecraft:brown_wool",
|
||||
"13": "minecraft:green_wool",
|
||||
"14": "minecraft:red_wool",
|
||||
"15": "minecraft:black_wool",
|
||||
"2": "minecraft:magenta_wool",
|
||||
"3": "minecraft:light_blue_wool",
|
||||
"4": "minecraft:yellow_wool",
|
||||
"5": "minecraft:lime_wool",
|
||||
"6": "minecraft:pink_wool",
|
||||
"7": "minecraft:gray_wool",
|
||||
"8": "minecraft:light_gray_wool",
|
||||
"9": "minecraft:cyan_wool"
|
||||
}
|
||||
}
|
||||
}
|
||||
36
internal/item/schemas/0101_1.19.70_to_1.19.80.24_beta.json
Normal file
36
internal/item/schemas/0101_1.19.70_to_1.19.80.24_beta.json
Normal file
@@ -0,0 +1,36 @@
|
||||
{
|
||||
"remappedMetas": {
|
||||
"minecraft:boat": {
|
||||
"8": "minecraft:cherry_boat"
|
||||
},
|
||||
"minecraft:chest_boat": {
|
||||
"8": "minecraft:cherry_chest_boat"
|
||||
},
|
||||
"minecraft:fence": {
|
||||
"0": "minecraft:oak_fence",
|
||||
"1": "minecraft:spruce_fence",
|
||||
"2": "minecraft:birch_fence",
|
||||
"3": "minecraft:jungle_fence",
|
||||
"4": "minecraft:acacia_fence",
|
||||
"5": "minecraft:dark_oak_fence"
|
||||
},
|
||||
"minecraft:log": {
|
||||
"0": "minecraft:oak_log",
|
||||
"1": "minecraft:spruce_log",
|
||||
"10": "minecraft:birch_log",
|
||||
"11": "minecraft:jungle_log",
|
||||
"2": "minecraft:birch_log",
|
||||
"3": "minecraft:jungle_log",
|
||||
"5": "minecraft:spruce_log",
|
||||
"6": "minecraft:birch_log",
|
||||
"7": "minecraft:jungle_log",
|
||||
"9": "minecraft:spruce_log"
|
||||
},
|
||||
"minecraft:log2": {
|
||||
"0": "minecraft:acacia_log",
|
||||
"1": "minecraft:dark_oak_log",
|
||||
"5": "minecraft:dark_oak_log",
|
||||
"9": "minecraft:dark_oak_log"
|
||||
}
|
||||
}
|
||||
}
|
||||
37
internal/item/schemas/0111_1.19.80_to_1.20.0.23_beta.json
Normal file
37
internal/item/schemas/0111_1.19.80_to_1.20.0.23_beta.json
Normal file
@@ -0,0 +1,37 @@
|
||||
{
|
||||
"remappedMetas": {
|
||||
"minecraft:carpet": {
|
||||
"0": "minecraft:white_carpet",
|
||||
"1": "minecraft:orange_carpet",
|
||||
"10": "minecraft:purple_carpet",
|
||||
"11": "minecraft:blue_carpet",
|
||||
"12": "minecraft:brown_carpet",
|
||||
"13": "minecraft:green_carpet",
|
||||
"14": "minecraft:red_carpet",
|
||||
"15": "minecraft:black_carpet",
|
||||
"2": "minecraft:magenta_carpet",
|
||||
"3": "minecraft:light_blue_carpet",
|
||||
"4": "minecraft:yellow_carpet",
|
||||
"5": "minecraft:lime_carpet",
|
||||
"6": "minecraft:pink_carpet",
|
||||
"7": "minecraft:gray_carpet",
|
||||
"8": "minecraft:light_gray_carpet",
|
||||
"9": "minecraft:cyan_carpet"
|
||||
},
|
||||
"minecraft:coral": {
|
||||
"0": "minecraft:tube_coral",
|
||||
"1": "minecraft:brain_coral",
|
||||
"10": "minecraft:dead_bubble_coral",
|
||||
"11": "minecraft:dead_fire_coral",
|
||||
"12": "minecraft:dead_horn_coral",
|
||||
"2": "minecraft:bubble_coral",
|
||||
"3": "minecraft:fire_coral",
|
||||
"4": "minecraft:horn_coral",
|
||||
"8": "minecraft:dead_tube_coral",
|
||||
"9": "minecraft:dead_brain_coral"
|
||||
}
|
||||
},
|
||||
"renamedIds": {
|
||||
"minecraft:record_relic": "minecraft:music_disc_relic"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
{
|
||||
"remappedMetas": {
|
||||
"minecraft:concrete": {
|
||||
"0": "minecraft:white_concrete",
|
||||
"1": "minecraft:orange_concrete",
|
||||
"10": "minecraft:purple_concrete",
|
||||
"11": "minecraft:blue_concrete",
|
||||
"12": "minecraft:brown_concrete",
|
||||
"13": "minecraft:green_concrete",
|
||||
"14": "minecraft:red_concrete",
|
||||
"15": "minecraft:black_concrete",
|
||||
"2": "minecraft:magenta_concrete",
|
||||
"3": "minecraft:light_blue_concrete",
|
||||
"4": "minecraft:yellow_concrete",
|
||||
"5": "minecraft:lime_concrete",
|
||||
"6": "minecraft:pink_concrete",
|
||||
"7": "minecraft:gray_concrete",
|
||||
"8": "minecraft:light_gray_concrete",
|
||||
"9": "minecraft:cyan_concrete"
|
||||
},
|
||||
"minecraft:shulker_box": {
|
||||
"0": "minecraft:white_shulker_box",
|
||||
"1": "minecraft:orange_shulker_box",
|
||||
"10": "minecraft:purple_shulker_box",
|
||||
"11": "minecraft:blue_shulker_box",
|
||||
"12": "minecraft:brown_shulker_box",
|
||||
"13": "minecraft:green_shulker_box",
|
||||
"14": "minecraft:red_shulker_box",
|
||||
"15": "minecraft:black_shulker_box",
|
||||
"2": "minecraft:magenta_shulker_box",
|
||||
"3": "minecraft:light_blue_shulker_box",
|
||||
"4": "minecraft:yellow_shulker_box",
|
||||
"5": "minecraft:lime_shulker_box",
|
||||
"6": "minecraft:pink_shulker_box",
|
||||
"7": "minecraft:gray_shulker_box",
|
||||
"8": "minecraft:light_gray_shulker_box",
|
||||
"9": "minecraft:cyan_shulker_box"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
{
|
||||
"remappedMetas": {
|
||||
"minecraft:stained_glass": {
|
||||
"0": "minecraft:white_stained_glass",
|
||||
"1": "minecraft:orange_stained_glass",
|
||||
"10": "minecraft:purple_stained_glass",
|
||||
"11": "minecraft:blue_stained_glass",
|
||||
"12": "minecraft:brown_stained_glass",
|
||||
"13": "minecraft:green_stained_glass",
|
||||
"14": "minecraft:red_stained_glass",
|
||||
"15": "minecraft:black_stained_glass",
|
||||
"2": "minecraft:magenta_stained_glass",
|
||||
"3": "minecraft:light_blue_stained_glass",
|
||||
"4": "minecraft:yellow_stained_glass",
|
||||
"5": "minecraft:lime_stained_glass",
|
||||
"6": "minecraft:pink_stained_glass",
|
||||
"7": "minecraft:gray_stained_glass",
|
||||
"8": "minecraft:light_gray_stained_glass",
|
||||
"9": "minecraft:cyan_stained_glass"
|
||||
},
|
||||
"minecraft:stained_glass_pane": {
|
||||
"0": "minecraft:white_stained_glass_pane",
|
||||
"1": "minecraft:orange_stained_glass_pane",
|
||||
"10": "minecraft:purple_stained_glass_pane",
|
||||
"11": "minecraft:blue_stained_glass_pane",
|
||||
"12": "minecraft:brown_stained_glass_pane",
|
||||
"13": "minecraft:green_stained_glass_pane",
|
||||
"14": "minecraft:red_stained_glass_pane",
|
||||
"15": "minecraft:black_stained_glass_pane",
|
||||
"2": "minecraft:magenta_stained_glass_pane",
|
||||
"3": "minecraft:light_blue_stained_glass_pane",
|
||||
"4": "minecraft:yellow_stained_glass_pane",
|
||||
"5": "minecraft:lime_stained_glass_pane",
|
||||
"6": "minecraft:pink_stained_glass_pane",
|
||||
"7": "minecraft:gray_stained_glass_pane",
|
||||
"8": "minecraft:light_gray_stained_glass_pane",
|
||||
"9": "minecraft:cyan_stained_glass_pane"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
{
|
||||
"remappedMetas": {
|
||||
"minecraft:concrete_powder": {
|
||||
"0": "minecraft:white_concrete_powder",
|
||||
"1": "minecraft:orange_concrete_powder",
|
||||
"10": "minecraft:purple_concrete_powder",
|
||||
"11": "minecraft:blue_concrete_powder",
|
||||
"12": "minecraft:brown_concrete_powder",
|
||||
"13": "minecraft:green_concrete_powder",
|
||||
"14": "minecraft:red_concrete_powder",
|
||||
"15": "minecraft:black_concrete_powder",
|
||||
"2": "minecraft:magenta_concrete_powder",
|
||||
"3": "minecraft:light_blue_concrete_powder",
|
||||
"4": "minecraft:yellow_concrete_powder",
|
||||
"5": "minecraft:lime_concrete_powder",
|
||||
"6": "minecraft:pink_concrete_powder",
|
||||
"7": "minecraft:gray_concrete_powder",
|
||||
"8": "minecraft:light_gray_concrete_powder",
|
||||
"9": "minecraft:cyan_concrete_powder"
|
||||
},
|
||||
"minecraft:stained_hardened_clay": {
|
||||
"0": "minecraft:white_terracotta",
|
||||
"1": "minecraft:orange_terracotta",
|
||||
"10": "minecraft:purple_terracotta",
|
||||
"11": "minecraft:blue_terracotta",
|
||||
"12": "minecraft:brown_terracotta",
|
||||
"13": "minecraft:green_terracotta",
|
||||
"14": "minecraft:red_terracotta",
|
||||
"15": "minecraft:black_terracotta",
|
||||
"2": "minecraft:magenta_terracotta",
|
||||
"3": "minecraft:light_blue_terracotta",
|
||||
"4": "minecraft:yellow_terracotta",
|
||||
"5": "minecraft:lime_terracotta",
|
||||
"6": "minecraft:pink_terracotta",
|
||||
"7": "minecraft:gray_terracotta",
|
||||
"8": "minecraft:light_gray_terracotta",
|
||||
"9": "minecraft:cyan_terracotta"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"remappedMetas": {
|
||||
"minecraft:planks": {
|
||||
"0": "minecraft:oak_planks",
|
||||
"1": "minecraft:spruce_planks",
|
||||
"2": "minecraft:birch_planks",
|
||||
"3": "minecraft:jungle_planks",
|
||||
"4": "minecraft:acacia_planks",
|
||||
"5": "minecraft:dark_oak_planks"
|
||||
},
|
||||
"minecraft:stone": {
|
||||
"1": "minecraft:granite",
|
||||
"2": "minecraft:polished_granite",
|
||||
"3": "minecraft:diorite",
|
||||
"4": "minecraft:polished_diorite",
|
||||
"5": "minecraft:andesite",
|
||||
"6": "minecraft:polished_andesite"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
{
|
||||
"remappedMetas": {
|
||||
"minecraft:hard_stained_glass": {
|
||||
"0": "minecraft:hard_white_stained_glass",
|
||||
"1": "minecraft:hard_orange_stained_glass",
|
||||
"10": "minecraft:hard_purple_stained_glass",
|
||||
"11": "minecraft:hard_blue_stained_glass",
|
||||
"12": "minecraft:hard_brown_stained_glass",
|
||||
"13": "minecraft:hard_green_stained_glass",
|
||||
"14": "minecraft:hard_red_stained_glass",
|
||||
"15": "minecraft:hard_black_stained_glass",
|
||||
"2": "minecraft:hard_magenta_stained_glass",
|
||||
"3": "minecraft:hard_light_blue_stained_glass",
|
||||
"4": "minecraft:hard_yellow_stained_glass",
|
||||
"5": "minecraft:hard_lime_stained_glass",
|
||||
"6": "minecraft:hard_pink_stained_glass",
|
||||
"7": "minecraft:hard_gray_stained_glass",
|
||||
"8": "minecraft:hard_light_gray_stained_glass",
|
||||
"9": "minecraft:hard_cyan_stained_glass"
|
||||
},
|
||||
"minecraft:hard_stained_glass_pane": {
|
||||
"0": "minecraft:hard_white_stained_glass_pane",
|
||||
"1": "minecraft:hard_orange_stained_glass_pane",
|
||||
"10": "minecraft:hard_purple_stained_glass_pane",
|
||||
"11": "minecraft:hard_blue_stained_glass_pane",
|
||||
"12": "minecraft:hard_brown_stained_glass_pane",
|
||||
"13": "minecraft:hard_green_stained_glass_pane",
|
||||
"14": "minecraft:hard_red_stained_glass_pane",
|
||||
"15": "minecraft:hard_black_stained_glass_pane",
|
||||
"2": "minecraft:hard_magenta_stained_glass_pane",
|
||||
"3": "minecraft:hard_light_blue_stained_glass_pane",
|
||||
"4": "minecraft:hard_yellow_stained_glass_pane",
|
||||
"5": "minecraft:hard_lime_stained_glass_pane",
|
||||
"6": "minecraft:hard_pink_stained_glass_pane",
|
||||
"7": "minecraft:hard_gray_stained_glass_pane",
|
||||
"8": "minecraft:hard_light_gray_stained_glass_pane",
|
||||
"9": "minecraft:hard_cyan_stained_glass_pane"
|
||||
},
|
||||
"minecraft:spawn_egg": {
|
||||
"140": "minecraft:breeze_spawn_egg",
|
||||
"142": "minecraft:armadillo_spawn_egg"
|
||||
}
|
||||
},
|
||||
"renamedIds": {
|
||||
"minecraft:scute": "minecraft:turtle_scute"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
{
|
||||
"remappedMetas": {
|
||||
"minecraft:leaves": {
|
||||
"0": "minecraft:oak_leaves",
|
||||
"1": "minecraft:spruce_leaves",
|
||||
"2": "minecraft:birch_leaves",
|
||||
"3": "minecraft:jungle_leaves"
|
||||
},
|
||||
"minecraft:leaves2": {
|
||||
"0": "minecraft:acacia_leaves",
|
||||
"1": "minecraft:dark_oak_leaves"
|
||||
},
|
||||
"minecraft:spawn_egg": {
|
||||
"144": "minecraft:bogged_spawn_egg"
|
||||
},
|
||||
"minecraft:wood": {
|
||||
"0": "minecraft:oak_wood",
|
||||
"1": "minecraft:spruce_wood",
|
||||
"10": "minecraft:stripped_birch_wood",
|
||||
"11": "minecraft:stripped_jungle_wood",
|
||||
"12": "minecraft:stripped_acacia_wood",
|
||||
"13": "minecraft:stripped_dark_oak_wood",
|
||||
"2": "minecraft:birch_wood",
|
||||
"3": "minecraft:jungle_wood",
|
||||
"4": "minecraft:acacia_wood",
|
||||
"5": "minecraft:dark_oak_wood",
|
||||
"8": "minecraft:stripped_oak_wood",
|
||||
"9": "minecraft:stripped_spruce_wood"
|
||||
},
|
||||
"minecraft:wooden_slab": {
|
||||
"0": "minecraft:oak_slab",
|
||||
"1": "minecraft:spruce_slab",
|
||||
"2": "minecraft:birch_slab",
|
||||
"3": "minecraft:jungle_slab",
|
||||
"4": "minecraft:acacia_slab",
|
||||
"5": "minecraft:dark_oak_slab"
|
||||
}
|
||||
},
|
||||
"renamedIds": {
|
||||
"minecraft:grass": "minecraft:grass_block"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
{
|
||||
"remappedMetas": {
|
||||
"minecraft:coral_fan": {
|
||||
"0": "minecraft:tube_coral_fan",
|
||||
"1": "minecraft:brain_coral_fan",
|
||||
"2": "minecraft:bubble_coral_fan",
|
||||
"3": "minecraft:fire_coral_fan",
|
||||
"4": "minecraft:horn_coral_fan"
|
||||
},
|
||||
"minecraft:coral_fan_dead": {
|
||||
"0": "minecraft:dead_tube_coral_fan",
|
||||
"1": "minecraft:dead_brain_coral_fan",
|
||||
"2": "minecraft:dead_bubble_coral_fan",
|
||||
"3": "minecraft:dead_fire_coral_fan",
|
||||
"4": "minecraft:dead_horn_coral_fan"
|
||||
},
|
||||
"minecraft:red_flower": {
|
||||
"0": "minecraft:poppy",
|
||||
"1": "minecraft:blue_orchid",
|
||||
"10": "minecraft:lily_of_the_valley",
|
||||
"2": "minecraft:allium",
|
||||
"3": "minecraft:azure_bluet",
|
||||
"4": "minecraft:red_tulip",
|
||||
"5": "minecraft:orange_tulip",
|
||||
"6": "minecraft:white_tulip",
|
||||
"7": "minecraft:pink_tulip",
|
||||
"8": "minecraft:oxeye_daisy",
|
||||
"9": "minecraft:cornflower"
|
||||
},
|
||||
"minecraft:sapling": {
|
||||
"0": "minecraft:oak_sapling",
|
||||
"1": "minecraft:spruce_sapling",
|
||||
"2": "minecraft:birch_sapling",
|
||||
"3": "minecraft:jungle_sapling",
|
||||
"4": "minecraft:acacia_sapling",
|
||||
"5": "minecraft:dark_oak_sapling"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
{
|
||||
"remappedMetas": {
|
||||
"minecraft:coral_block": {
|
||||
"0": "minecraft:tube_coral_block",
|
||||
"1": "minecraft:brain_coral_block",
|
||||
"10": "minecraft:dead_bubble_coral_block",
|
||||
"11": "minecraft:dead_fire_coral_block",
|
||||
"12": "minecraft:dead_horn_coral_block",
|
||||
"2": "minecraft:bubble_coral_block",
|
||||
"3": "minecraft:fire_coral_block",
|
||||
"4": "minecraft:horn_coral_block",
|
||||
"8": "minecraft:dead_tube_coral_block",
|
||||
"9": "minecraft:dead_brain_coral_block"
|
||||
},
|
||||
"minecraft:double_plant": {
|
||||
"0": "minecraft:sunflower",
|
||||
"1": "minecraft:lilac",
|
||||
"2": "minecraft:tall_grass",
|
||||
"3": "minecraft:large_fern",
|
||||
"4": "minecraft:rose_bush",
|
||||
"5": "minecraft:peony"
|
||||
},
|
||||
"minecraft:stone_block_slab": {
|
||||
"0": "minecraft:smooth_stone_slab",
|
||||
"1": "minecraft:sandstone_slab",
|
||||
"2": "minecraft:petrified_oak_slab",
|
||||
"3": "minecraft:cobblestone_slab",
|
||||
"4": "minecraft:brick_slab",
|
||||
"5": "minecraft:stone_brick_slab",
|
||||
"6": "minecraft:quartz_slab",
|
||||
"7": "minecraft:nether_brick_slab"
|
||||
},
|
||||
"minecraft:tallgrass": {
|
||||
"0": "minecraft:short_grass",
|
||||
"2": "minecraft:fern",
|
||||
"3": "minecraft:fern"
|
||||
}
|
||||
},
|
||||
"renamedIds": {
|
||||
"minecraft:record_creator": "minecraft:music_disc_creator",
|
||||
"minecraft:record_creator_music_box": "minecraft:music_disc_creator_music_box",
|
||||
"minecraft:record_precipice": "minecraft:music_disc_precipice"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,138 @@
|
||||
{
|
||||
"remappedMetas": {
|
||||
"minecraft:anvil": {
|
||||
"10": "minecraft:damaged_anvil",
|
||||
"11": "minecraft:damaged_anvil",
|
||||
"4": "minecraft:chipped_anvil",
|
||||
"5": "minecraft:chipped_anvil",
|
||||
"6": "minecraft:chipped_anvil",
|
||||
"7": "minecraft:chipped_anvil",
|
||||
"8": "minecraft:damaged_anvil",
|
||||
"9": "minecraft:damaged_anvil"
|
||||
},
|
||||
"minecraft:dirt": {
|
||||
"1": "minecraft:coarse_dirt"
|
||||
},
|
||||
"minecraft:double_stone_block_slab": {
|
||||
"0": "minecraft:smooth_stone_double_slab",
|
||||
"1": "minecraft:sandstone_double_slab",
|
||||
"2": "minecraft:petrified_oak_double_slab",
|
||||
"3": "minecraft:cobblestone_double_slab",
|
||||
"4": "minecraft:brick_double_slab",
|
||||
"5": "minecraft:stone_brick_double_slab",
|
||||
"6": "minecraft:quartz_double_slab",
|
||||
"7": "minecraft:nether_brick_double_slab"
|
||||
},
|
||||
"minecraft:double_stone_block_slab2": {
|
||||
"0": "minecraft:red_sandstone_double_slab",
|
||||
"1": "minecraft:purpur_double_slab",
|
||||
"2": "minecraft:prismarine_double_slab",
|
||||
"3": "minecraft:dark_prismarine_double_slab",
|
||||
"4": "minecraft:prismarine_brick_double_slab",
|
||||
"5": "minecraft:mossy_cobblestone_double_slab",
|
||||
"6": "minecraft:smooth_sandstone_double_slab",
|
||||
"7": "minecraft:red_nether_brick_double_slab"
|
||||
},
|
||||
"minecraft:double_stone_block_slab3": {
|
||||
"0": "minecraft:end_stone_brick_double_slab",
|
||||
"1": "minecraft:smooth_red_sandstone_double_slab",
|
||||
"2": "minecraft:polished_andesite_double_slab",
|
||||
"3": "minecraft:andesite_double_slab",
|
||||
"4": "minecraft:diorite_double_slab",
|
||||
"5": "minecraft:polished_diorite_double_slab",
|
||||
"6": "minecraft:granite_double_slab",
|
||||
"7": "minecraft:polished_granite_double_slab"
|
||||
},
|
||||
"minecraft:double_stone_block_slab4": {
|
||||
"0": "minecraft:mossy_stone_brick_double_slab",
|
||||
"1": "minecraft:smooth_quartz_double_slab",
|
||||
"2": "minecraft:normal_stone_double_slab",
|
||||
"3": "minecraft:cut_sandstone_double_slab",
|
||||
"4": "minecraft:cut_red_sandstone_double_slab"
|
||||
},
|
||||
"minecraft:light_block": {
|
||||
"0": "minecraft:light_block_0",
|
||||
"1": "minecraft:light_block_1",
|
||||
"10": "minecraft:light_block_10",
|
||||
"11": "minecraft:light_block_11",
|
||||
"12": "minecraft:light_block_12",
|
||||
"13": "minecraft:light_block_13",
|
||||
"14": "minecraft:light_block_14",
|
||||
"15": "minecraft:light_block_15",
|
||||
"2": "minecraft:light_block_2",
|
||||
"3": "minecraft:light_block_3",
|
||||
"4": "minecraft:light_block_4",
|
||||
"5": "minecraft:light_block_5",
|
||||
"6": "minecraft:light_block_6",
|
||||
"7": "minecraft:light_block_7",
|
||||
"8": "minecraft:light_block_8",
|
||||
"9": "minecraft:light_block_9"
|
||||
},
|
||||
"minecraft:monster_egg": {
|
||||
"0": "minecraft:infested_stone",
|
||||
"1": "minecraft:infested_cobblestone",
|
||||
"2": "minecraft:infested_stone_bricks",
|
||||
"3": "minecraft:infested_mossy_stone_bricks",
|
||||
"4": "minecraft:infested_cracked_stone_bricks",
|
||||
"5": "minecraft:infested_chiseled_stone_bricks"
|
||||
},
|
||||
"minecraft:prismarine": {
|
||||
"1": "minecraft:dark_prismarine",
|
||||
"2": "minecraft:prismarine_bricks"
|
||||
},
|
||||
"minecraft:quartz_block": {
|
||||
"1": "minecraft:chiseled_quartz_block",
|
||||
"2": "minecraft:quartz_pillar",
|
||||
"3": "minecraft:smooth_quartz"
|
||||
},
|
||||
"minecraft:red_sandstone": {
|
||||
"1": "minecraft:chiseled_red_sandstone",
|
||||
"2": "minecraft:cut_red_sandstone",
|
||||
"3": "minecraft:smooth_red_sandstone"
|
||||
},
|
||||
"minecraft:sand": {
|
||||
"1": "minecraft:red_sand"
|
||||
},
|
||||
"minecraft:sandstone": {
|
||||
"1": "minecraft:chiseled_sandstone",
|
||||
"2": "minecraft:cut_sandstone",
|
||||
"3": "minecraft:smooth_sandstone"
|
||||
},
|
||||
"minecraft:stone_block_slab2": {
|
||||
"0": "minecraft:red_sandstone_slab",
|
||||
"1": "minecraft:purpur_slab",
|
||||
"2": "minecraft:prismarine_slab",
|
||||
"3": "minecraft:dark_prismarine_slab",
|
||||
"4": "minecraft:prismarine_brick_slab",
|
||||
"5": "minecraft:mossy_cobblestone_slab",
|
||||
"6": "minecraft:smooth_sandstone_slab",
|
||||
"7": "minecraft:red_nether_brick_slab"
|
||||
},
|
||||
"minecraft:stone_block_slab3": {
|
||||
"0": "minecraft:end_stone_brick_slab",
|
||||
"1": "minecraft:smooth_red_sandstone_slab",
|
||||
"2": "minecraft:polished_andesite_slab",
|
||||
"3": "minecraft:andesite_slab",
|
||||
"4": "minecraft:diorite_slab",
|
||||
"5": "minecraft:polished_diorite_slab",
|
||||
"6": "minecraft:granite_slab",
|
||||
"7": "minecraft:polished_granite_slab"
|
||||
},
|
||||
"minecraft:stone_block_slab4": {
|
||||
"0": "minecraft:mossy_stone_brick_slab",
|
||||
"1": "minecraft:smooth_quartz_slab",
|
||||
"2": "minecraft:normal_stone_slab",
|
||||
"3": "minecraft:cut_sandstone_slab",
|
||||
"4": "minecraft:cut_red_sandstone_slab"
|
||||
},
|
||||
"minecraft:stonebrick": {
|
||||
"0": "minecraft:stone_bricks",
|
||||
"1": "minecraft:mossy_stone_bricks",
|
||||
"2": "minecraft:cracked_stone_bricks",
|
||||
"3": "minecraft:chiseled_stone_bricks"
|
||||
}
|
||||
},
|
||||
"renamedIds": {
|
||||
"minecraft:yellow_flower": "minecraft:dandelion"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
{
|
||||
"remappedMetas": {
|
||||
"minecraft:chemistry_table": {
|
||||
"0": "minecraft:compound_creator"
|
||||
},
|
||||
"minecraft:cobblestone_wall": {
|
||||
"1": "minecraft:mossy_cobblestone_wall",
|
||||
"10": "minecraft:end_stone_brick_wall",
|
||||
"11": "minecraft:prismarine_wall",
|
||||
"12": "minecraft:red_sandstone_wall",
|
||||
"13": "minecraft:red_nether_brick_wall",
|
||||
"2": "minecraft:granite_wall",
|
||||
"3": "minecraft:diorite_wall",
|
||||
"4": "minecraft:andesite_wall",
|
||||
"5": "minecraft:sandstone_wall",
|
||||
"6": "minecraft:brick_wall",
|
||||
"7": "minecraft:stone_brick_wall",
|
||||
"8": "minecraft:mossy_stone_brick_wall",
|
||||
"9": "minecraft:nether_brick_wall"
|
||||
},
|
||||
"minecraft:colored_torch_bp": {
|
||||
"0": "minecraft:colored_torch_blue",
|
||||
"10": "minecraft:colored_torch_purple",
|
||||
"11": "minecraft:colored_torch_purple",
|
||||
"12": "minecraft:colored_torch_purple",
|
||||
"13": "minecraft:colored_torch_purple",
|
||||
"14": "minecraft:colored_torch_purple",
|
||||
"15": "minecraft:colored_torch_purple",
|
||||
"8": "minecraft:colored_torch_purple",
|
||||
"9": "minecraft:colored_torch_purple"
|
||||
},
|
||||
"minecraft:colored_torch_rg": {
|
||||
"0": "minecraft:colored_torch_red",
|
||||
"10": "minecraft:colored_torch_green",
|
||||
"11": "minecraft:colored_torch_green",
|
||||
"12": "minecraft:colored_torch_green",
|
||||
"13": "minecraft:colored_torch_green",
|
||||
"14": "minecraft:colored_torch_green",
|
||||
"15": "minecraft:colored_torch_green",
|
||||
"8": "minecraft:colored_torch_green",
|
||||
"9": "minecraft:colored_torch_green"
|
||||
},
|
||||
"minecraft:purpur_block": {
|
||||
"1": "minecraft:deprecated_purpur_block_1",
|
||||
"2": "minecraft:purpur_pillar",
|
||||
"3": "minecraft:deprecated_purpur_block_2"
|
||||
},
|
||||
"minecraft:sponge": {
|
||||
"1": "minecraft:wet_sponge"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"remappedMetas": {
|
||||
"minecraft:skull": {
|
||||
"0": "minecraft:skeleton_skull",
|
||||
"1": "minecraft:wither_skeleton_skull",
|
||||
"2": "minecraft:zombie_head",
|
||||
"3": "minecraft:player_head",
|
||||
"4": "minecraft:creeper_head",
|
||||
"5": "minecraft:dragon_head",
|
||||
"6": "minecraft:piglin_head"
|
||||
}
|
||||
}
|
||||
}
|
||||
109
internal/item/upgrader.go
Normal file
109
internal/item/upgrader.go
Normal file
@@ -0,0 +1,109 @@
|
||||
package item
|
||||
|
||||
import (
|
||||
"github.com/df-mc/worldupgrader/blockupgrader"
|
||||
)
|
||||
|
||||
// Item ...
|
||||
type Item struct {
|
||||
Name string
|
||||
Metadata uint32
|
||||
Version uint16
|
||||
}
|
||||
|
||||
// Upgrade upgrades the given item using the registered item upgrade schemas.
|
||||
func Upgrade(item Item, ver uint16) Item {
|
||||
version := item.Version
|
||||
for id, s := range schemas {
|
||||
if version > id || id > ver {
|
||||
continue
|
||||
}
|
||||
|
||||
name := item.Name
|
||||
metadata := item.Metadata
|
||||
nameRenamed := false
|
||||
metadataRemapped := false
|
||||
|
||||
if metadataCombinations, ok := s.RemappedMetas[name]; ok {
|
||||
name, metadataRemapped = metadataCombinations[item.Metadata]
|
||||
metadata = 0
|
||||
} else if name, nameRenamed = s.RenamedIDs[item.Name]; !nameRenamed {
|
||||
name = item.Name
|
||||
}
|
||||
|
||||
if nameRenamed || metadataRemapped {
|
||||
item = Item{
|
||||
Name: name,
|
||||
Metadata: metadata,
|
||||
Version: id,
|
||||
}
|
||||
}
|
||||
}
|
||||
return item
|
||||
}
|
||||
|
||||
// Downgrade downgrades the given item using the registered item upgrade schemas.
|
||||
func Downgrade(item Item, ver uint16) Item {
|
||||
for i, id := range schemaIDs {
|
||||
s := schemas[uint16(id)]
|
||||
if uint16(id) > item.Version {
|
||||
continue
|
||||
}
|
||||
|
||||
name := item.Name
|
||||
metadata := item.Metadata
|
||||
nameRenamed := false
|
||||
metadataRemapped := false
|
||||
|
||||
for oldName, newName := range s.RenamedIDs {
|
||||
if newName == name {
|
||||
name = oldName
|
||||
nameRenamed = true
|
||||
}
|
||||
}
|
||||
|
||||
if !nameRenamed {
|
||||
for oldName, m := range s.RemappedMetas {
|
||||
for meta, newName := range m {
|
||||
if newName == name {
|
||||
name = oldName
|
||||
metadata = meta
|
||||
nameRenamed = true
|
||||
metadataRemapped = true
|
||||
}
|
||||
}
|
||||
if metadataRemapped {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ver > item.Version || i == len(schemaIDs)-1 {
|
||||
break
|
||||
}
|
||||
|
||||
return Downgrade(Item{
|
||||
Name: name,
|
||||
Metadata: metadata,
|
||||
Version: uint16(schemaIDs[i+1]),
|
||||
}, ver)
|
||||
}
|
||||
return item
|
||||
}
|
||||
|
||||
func BlockStateFromItemName(itemName string, metadata uint32) (blockupgrader.BlockState, bool) {
|
||||
blockId, ok := itemToBlockIdMap[itemName]
|
||||
if !ok {
|
||||
return blockupgrader.BlockState{}, false
|
||||
}
|
||||
|
||||
blockState, ok := blockStateMap[stateHash{
|
||||
Name: blockId,
|
||||
Metadata: metadata,
|
||||
}]
|
||||
return blockState, ok
|
||||
}
|
||||
|
||||
func BlockStateFromItem(item Item) (blockupgrader.BlockState, bool) {
|
||||
return BlockStateFromItemName(item.Name, item.Metadata)
|
||||
}
|
||||
41
internal/iterator.go
Normal file
41
internal/iterator.go
Normal file
@@ -0,0 +1,41 @@
|
||||
package internal
|
||||
|
||||
type Iterator[T any] struct {
|
||||
index int
|
||||
values []T
|
||||
}
|
||||
|
||||
func NewIterator[T any](values []T) *Iterator[T] {
|
||||
return &Iterator[T]{values: values}
|
||||
}
|
||||
|
||||
func (i *Iterator[T]) HasNext() bool {
|
||||
if i.index < len(i.values) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (i *Iterator[T]) HasPrevious() bool {
|
||||
if i.index > 0 {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (i *Iterator[T]) Next() T {
|
||||
if i.HasNext() {
|
||||
value := i.values[i.index]
|
||||
i.index++
|
||||
return value
|
||||
}
|
||||
panic("no more elements")
|
||||
}
|
||||
|
||||
func (i *Iterator[T]) Previous() T {
|
||||
if i.HasPrevious() {
|
||||
i.index--
|
||||
return i.values[i.index]
|
||||
}
|
||||
panic("no more elements")
|
||||
}
|
||||
Reference in New Issue
Block a user