From 9582bc2a7e6fbace051961401cf6c8a330dde28c Mon Sep 17 00:00:00 2001 From: Tnze Date: Tue, 25 Apr 2023 01:10:15 +0800 Subject: [PATCH] rename fastnbt -> dynbt. add some NewXXX api --- nbt/decode_test.go | 16 ++++++ nbt/{fastnbt => dynbt}/bigTest_test.snbt | 0 nbt/{fastnbt => dynbt}/decode.go | 2 +- nbt/{fastnbt => dynbt}/decode_test.go | 2 +- nbt/{fastnbt => dynbt}/encode.go | 2 +- nbt/{fastnbt => dynbt}/encode_test.go | 22 ++++++++- nbt/{fastnbt => dynbt}/types.go | 62 ++++++++++++++++++++++-- nbt/{fastnbt => dynbt}/update.go | 2 +- 8 files changed, 99 insertions(+), 9 deletions(-) rename nbt/{fastnbt => dynbt}/bigTest_test.snbt (100%) rename nbt/{fastnbt => dynbt}/decode.go (99%) rename nbt/{fastnbt => dynbt}/decode_test.go (99%) rename nbt/{fastnbt => dynbt}/encode.go (99%) rename nbt/{fastnbt => dynbt}/encode_test.go (77%) rename nbt/{fastnbt => dynbt}/types.go (59%) rename nbt/{fastnbt => dynbt}/update.go (97%) diff --git a/nbt/decode_test.go b/nbt/decode_test.go index e6a6301..e537a2c 100644 --- a/nbt/decode_test.go +++ b/nbt/decode_test.go @@ -428,6 +428,22 @@ func TestDecoder_Decode_textUnmarshaler(t *testing.T) { if b != true { t.Errorf("b should be true") } + + var s struct { + A TextBool + } + data = []byte{ + TagCompound, 0, 0, + TagString, 0, 1, 'A', 0, 4, 't', 'r', 'u', 'e', + TagEnd, + } + _, err = NewDecoder(bytes.NewReader(data)).Decode(&s) + if err != nil { + t.Fatal(err) + } + if s.A != true { + t.Errorf("s.A should be true") + } } func TestDecoder_Decode_ErrorUnknownField(t *testing.T) { diff --git a/nbt/fastnbt/bigTest_test.snbt b/nbt/dynbt/bigTest_test.snbt similarity index 100% rename from nbt/fastnbt/bigTest_test.snbt rename to nbt/dynbt/bigTest_test.snbt diff --git a/nbt/fastnbt/decode.go b/nbt/dynbt/decode.go similarity index 99% rename from nbt/fastnbt/decode.go rename to nbt/dynbt/decode.go index d77ca58..fab6e64 100644 --- a/nbt/fastnbt/decode.go +++ b/nbt/dynbt/decode.go @@ -1,4 +1,4 @@ -package fastnbt +package dynbt import ( "encoding/binary" diff --git a/nbt/fastnbt/decode_test.go b/nbt/dynbt/decode_test.go similarity index 99% rename from nbt/fastnbt/decode_test.go rename to nbt/dynbt/decode_test.go index bf9e181..49378e2 100644 --- a/nbt/fastnbt/decode_test.go +++ b/nbt/dynbt/decode_test.go @@ -1,4 +1,4 @@ -package fastnbt +package dynbt import ( "bytes" diff --git a/nbt/fastnbt/encode.go b/nbt/dynbt/encode.go similarity index 99% rename from nbt/fastnbt/encode.go rename to nbt/dynbt/encode.go index 1e23b58..9abc1fa 100644 --- a/nbt/fastnbt/encode.go +++ b/nbt/dynbt/encode.go @@ -1,4 +1,4 @@ -package fastnbt +package dynbt import ( "errors" diff --git a/nbt/fastnbt/encode_test.go b/nbt/dynbt/encode_test.go similarity index 77% rename from nbt/fastnbt/encode_test.go rename to nbt/dynbt/encode_test.go index 38b8663..4ee9b70 100644 --- a/nbt/fastnbt/encode_test.go +++ b/nbt/dynbt/encode_test.go @@ -1,7 +1,9 @@ -package fastnbt +package dynbt import ( "bytes" + "math/rand" + "reflect" "testing" "github.com/Tnze/go-mc/nbt" @@ -37,13 +39,29 @@ func TestValue_new(t *testing.T) { } byteArray := make([]byte, 1000) - for n := 0; n < 1000; n++ { + for n := range byteArray { byteArray[n] = byte((n*n*255 + n*7) % 100) } if val := NewByteArray(byteArray); !bytes.Equal(byteArray, val.ByteArray()) { t.Error("encode byteArray error") } + intArray := make([]int32, 250) + for n := range intArray { + intArray[n] = rand.Int31() + } + if val := NewIntArray(intArray); !reflect.DeepEqual(intArray, val.IntArray()) { + t.Error("encode intArray error") + } + + longArray := make([]int64, 125) + for n := range longArray { + longArray[n] = rand.Int63() + } + if val := NewLongArray(longArray); !reflect.DeepEqual(longArray, val.LongArray()) { + t.Error("encode longArray error") + } + val := NewCompound() val.Set("a", NewString("tnze")) if val.Get("a").String() != "tnze" || val.Compound().Len() != 1 { diff --git a/nbt/fastnbt/types.go b/nbt/dynbt/types.go similarity index 59% rename from nbt/fastnbt/types.go rename to nbt/dynbt/types.go index ce8a6b3..2235b56 100644 --- a/nbt/fastnbt/types.go +++ b/nbt/dynbt/types.go @@ -1,4 +1,21 @@ -package fastnbt +// Package dynbt is a library that provides dynamic NBT operation APIs. +// +// Dynamically represented NBT value is useful in many cases, for example, +// - You want to store custom structural values at runtime. +// - You want to query or modify the data later. (Otherwise use the [nbt.RawMessage]) +// - You don't know what type the data is at compile time. (Otherwise use the [nbt.RawMessage] too) +// +// The [*Value] provides a group of APIs on top of the [nbt] package. +// [*Value] implements [nbt.Marshaler] and [nbt.Unmarshaler] interfaces. +// It can be used as a field of struct, or element of slice, map, etc. +// The pointer type should always be used, unless used as fields for structures +// +// Notice that querying Tags in Compound use a linear search, so it's not recommended to use it in a large Compound. +// The better choice is map[string]*Value for dynamic accessing a large Compound. +// +// This package tries its best to not copy data if possible. +// It returns the underlying data in some cases. Don't modify them! +package dynbt import ( "encoding/binary" @@ -62,6 +79,24 @@ func NewByteArray(v []byte) *Value { return &Value{tag: nbt.TagByteArray, data: append(data, v...)} } +func NewIntArray(v []int32) *Value { + data := make([]byte, 4+len(v)*4) + binary.BigEndian.PutUint32(data, uint32(len(v))) + for i, j := 0, 4; i < len(v); i, j = i+1, j+4 { + binary.BigEndian.PutUint32(data[j:], uint32(v[i])) + } + return &Value{tag: nbt.TagIntArray, data: data} +} + +func NewLongArray(v []int64) *Value { + data := make([]byte, 4+len(v)*8) + binary.BigEndian.PutUint32(data, uint32(len(v))) + for i, j := 0, 4; i < len(v); i, j = i+1, j+8 { + binary.BigEndian.PutUint64(data[j:], uint64(v[i])) + } + return &Value{tag: nbt.TagLongArray, data: data} +} + func NewString(str string) *Value { data := make([]byte, 2, 2+len(str)) binary.BigEndian.PutUint16(data, uint16(len(str))) @@ -126,10 +161,16 @@ func (v *Value) Double() float64 { } func (v *Value) List() []*Value { + if v.tag != nbt.TagList { + return nil + } return v.list } func (v *Value) Compound() *Compound { + if v.tag != nbt.TagCompound { + return nil + } return &v.comp } @@ -141,10 +182,25 @@ func (v *Value) ByteArray() []byte { } func (v *Value) IntArray() []int32 { + if v.tag != nbt.TagIntArray { + return nil + } length := binary.BigEndian.Uint32(v.data) ret := make([]int32, length) - for i := uint32(0); i < length; i += 4 { - ret[i] = int32(binary.BigEndian.Uint32(v.data[i:])) + for i, j := uint32(0), 4; i < length; i, j = i+1, j+4 { + ret[i] = int32(binary.BigEndian.Uint32(v.data[j:])) + } + return ret +} + +func (v *Value) LongArray() []int64 { + if v.tag != nbt.TagLongArray { + return nil + } + length := binary.BigEndian.Uint32(v.data) + ret := make([]int64, length) + for i, j := uint32(0), 4; i < length; i, j = i+1, j+8 { + ret[i] = int64(binary.BigEndian.Uint64(v.data[j:])) } return ret } diff --git a/nbt/fastnbt/update.go b/nbt/dynbt/update.go similarity index 97% rename from nbt/fastnbt/update.go rename to nbt/dynbt/update.go index 01dd806..1187abc 100644 --- a/nbt/fastnbt/update.go +++ b/nbt/dynbt/update.go @@ -1,4 +1,4 @@ -package fastnbt +package dynbt import "github.com/Tnze/go-mc/nbt"