mc root source folder cleanup
This commit is contained in:
@@ -0,0 +1,55 @@
|
||||
package nbt
|
||||
|
||||
import (
|
||||
"compress/gzip"
|
||||
"io"
|
||||
"os"
|
||||
|
||||
"github.com/admin-else/strom/mc/mapstructure"
|
||||
)
|
||||
|
||||
var Format = mapstructure.NewFormat("nbt", mapstructure.WithRequireAll(), mapstructure.WithTrySnakeCase(), mapstructure.WithTryLowCase())
|
||||
|
||||
func ReadFile(file io.Reader, data any) (err error) {
|
||||
n, err := ReadUnstructuredFile(file)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return Format.Decode(n.Value, data)
|
||||
}
|
||||
|
||||
func WriteUnstructuredFilePath(path string, n *Tag) (err error) {
|
||||
f, err := os.Create(path)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer f.Close()
|
||||
return WriteUnstructuredFile(f, n)
|
||||
}
|
||||
|
||||
func WriteUnstructuredFile(file io.Writer, n *Tag) (err error) {
|
||||
gzw := gzip.NewWriter(file)
|
||||
defer gzw.Close()
|
||||
err = n.Encode(gzw)
|
||||
return
|
||||
}
|
||||
|
||||
func ReadUnstructuredFile(file io.Reader) (n *Tag, err error) {
|
||||
r, err := gzip.NewReader(file)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer r.Close()
|
||||
n = &Tag{}
|
||||
err = n.Decode(r)
|
||||
return
|
||||
}
|
||||
|
||||
func ReadUnstructuredFilePath(path string) (n *Tag, err error) {
|
||||
f, err := os.Open(path)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer f.Close()
|
||||
return ReadUnstructuredFile(f)
|
||||
}
|
||||
+369
@@ -0,0 +1,369 @@
|
||||
package nbt
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
)
|
||||
|
||||
const (
|
||||
End int8 = iota
|
||||
Byte
|
||||
Short
|
||||
Int
|
||||
Long
|
||||
Float
|
||||
Double
|
||||
ByteArray
|
||||
String
|
||||
List
|
||||
Compound
|
||||
IntArray
|
||||
LongArray
|
||||
)
|
||||
|
||||
var Order binary.ByteOrder = binary.BigEndian
|
||||
|
||||
var BadStringLengthError = errors.New("bad string length")
|
||||
|
||||
type Tag struct {
|
||||
Name string
|
||||
Value any
|
||||
}
|
||||
|
||||
type Anon struct {
|
||||
Value any
|
||||
}
|
||||
|
||||
func (s *Anon) Decode(r io.Reader) (err error) {
|
||||
id := int8(0)
|
||||
err = binary.Read(r, Order, &id)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
s.Value, err = readPayload(id, r)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (s *Anon) Encode(w io.Writer) (err error) {
|
||||
id, err := getId(s.Value)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = writePayload(id, w)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = writePayload(s.Value, w)
|
||||
return
|
||||
}
|
||||
|
||||
func (s *Tag) Decode(r io.Reader) (err error) {
|
||||
id := int8(0)
|
||||
err = binary.Read(r, Order, &id)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
var name any
|
||||
name, err = readPayload(String, r)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
s.Value, err = readPayload(id, r)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
s.Name = name.(string)
|
||||
return
|
||||
}
|
||||
|
||||
func (s *Tag) Encode(w io.Writer) (err error) {
|
||||
id, err := getId(s.Value)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = writePayload(id, w)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = writePayload(s.Name, w)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = writePayload(s.Value, w)
|
||||
return
|
||||
}
|
||||
|
||||
func getId(v any) (id int8, err error) {
|
||||
switch v.(type) {
|
||||
case struct{}:
|
||||
id = End
|
||||
case int8:
|
||||
id = Byte
|
||||
case int16:
|
||||
id = Short
|
||||
case int32:
|
||||
id = Int
|
||||
case int64:
|
||||
id = Long
|
||||
case float32:
|
||||
id = Float
|
||||
case float64:
|
||||
id = Double
|
||||
case []int8:
|
||||
id = ByteArray
|
||||
case string:
|
||||
id = String
|
||||
case []any:
|
||||
id = List
|
||||
case map[string]any:
|
||||
id = Compound
|
||||
case []int32:
|
||||
id = IntArray
|
||||
case []int64:
|
||||
id = LongArray
|
||||
default:
|
||||
err = fmt.Errorf("unsupported type %T", v)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func readPayload(id int8, r io.Reader) (ret any, err error) {
|
||||
switch id {
|
||||
case End:
|
||||
ret = struct{}{}
|
||||
case Byte:
|
||||
rett := int8(0)
|
||||
err = binary.Read(r, Order, &rett)
|
||||
ret = rett
|
||||
case Short:
|
||||
rett := int16(0)
|
||||
err = binary.Read(r, Order, &rett)
|
||||
ret = rett
|
||||
case Int:
|
||||
rett := int32(0)
|
||||
err = binary.Read(r, Order, &rett)
|
||||
ret = rett
|
||||
case Long:
|
||||
rett := int64(0)
|
||||
err = binary.Read(r, Order, &rett)
|
||||
ret = rett
|
||||
case Float:
|
||||
rett := float32(0)
|
||||
err = binary.Read(r, Order, &rett)
|
||||
ret = rett
|
||||
case Double:
|
||||
rett := float64(0)
|
||||
err = binary.Read(r, Order, &rett)
|
||||
ret = rett
|
||||
case ByteArray:
|
||||
var l int32
|
||||
err = binary.Read(r, Order, &l)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if l < 0 {
|
||||
err = errors.New("bad array length")
|
||||
return
|
||||
}
|
||||
var rett []int8
|
||||
for range l {
|
||||
var element int8
|
||||
err = binary.Read(r, Order, &element)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
rett = append(rett, element)
|
||||
}
|
||||
ret = rett
|
||||
case String:
|
||||
var l uint16
|
||||
err = binary.Read(r, Order, &l)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
var s []byte
|
||||
s, err = io.ReadAll(io.LimitReader(r, int64(l)))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if len(s) != int(l) {
|
||||
err = BadStringLengthError
|
||||
return
|
||||
}
|
||||
ret = string(s)
|
||||
case List:
|
||||
var id int8
|
||||
err = binary.Read(r, Order, &id)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
var l int32
|
||||
err = binary.Read(r, Order, &l)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if l <= 0 || id == End {
|
||||
ret = []any{}
|
||||
return
|
||||
}
|
||||
var rett []any
|
||||
for range l {
|
||||
var result any
|
||||
result, err = readPayload(id, r)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
rett = append(rett, result)
|
||||
}
|
||||
ret = rett
|
||||
case Compound:
|
||||
rett := map[string]any{}
|
||||
for {
|
||||
id := int8(0)
|
||||
err = binary.Read(r, Order, &id)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if id == End {
|
||||
break
|
||||
}
|
||||
var namea any
|
||||
namea, err = readPayload(String, r)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
name := namea.(string)
|
||||
rett[name], err = readPayload(id, r)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
ret = rett
|
||||
case IntArray:
|
||||
var l int32
|
||||
err = binary.Read(r, Order, &l)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if l < 0 {
|
||||
err = errors.New("bad array length")
|
||||
return
|
||||
}
|
||||
var rett []int32
|
||||
for range l {
|
||||
var element int32
|
||||
err = binary.Read(r, Order, &element)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
rett = append(rett, element)
|
||||
}
|
||||
ret = rett
|
||||
case LongArray:
|
||||
var l int32
|
||||
err = binary.Read(r, Order, &l)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if l < 0 {
|
||||
err = errors.New("bad array length")
|
||||
return
|
||||
}
|
||||
var rett []int64
|
||||
for range l {
|
||||
var element int64
|
||||
err = binary.Read(r, Order, &element)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
rett = append(rett, element)
|
||||
}
|
||||
ret = rett
|
||||
default:
|
||||
err = errors.New("unkown nbt type id")
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
var UnknownTagTypeErr = errors.New("unknown nbt type")
|
||||
|
||||
func writePayload(v any, w io.Writer) (err error) {
|
||||
switch v := v.(type) {
|
||||
case struct{}:
|
||||
case int8, int16, int32, int64, float32, float64:
|
||||
err = binary.Write(w, Order, v)
|
||||
case []int8:
|
||||
err = binary.Write(w, Order, int32(len(v)))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = binary.Write(w, Order, v)
|
||||
case []int32:
|
||||
err = binary.Write(w, Order, int32(len(v)))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = binary.Write(w, Order, v)
|
||||
case []int64:
|
||||
err = binary.Write(w, Order, int32(len(v)))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = binary.Write(w, Order, v)
|
||||
case string:
|
||||
err = binary.Write(w, Order, uint16(len(v)))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = binary.Write(w, Order, []byte(v))
|
||||
case []any:
|
||||
id := End
|
||||
if len(v) != 0 {
|
||||
id, err = getId(v[0])
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
err = binary.Write(w, Order, id)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = binary.Write(w, Order, int32(len(v)))
|
||||
for _, v := range v {
|
||||
err = writePayload(v, w)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
case map[string]any:
|
||||
for k, v := range v {
|
||||
var id int8
|
||||
id, err = getId(v)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = binary.Write(w, Order, id)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = writePayload(k, w)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = writePayload(v, w)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
err = binary.Write(w, Order, End)
|
||||
default:
|
||||
err = UnknownTagTypeErr
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
package nbt
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
)
|
||||
|
||||
// PrintSNBTAny documented at https://minecraft.wiki/w/NBT_format#SNBT_format
|
||||
func PrintSNBTAny(t any, w io.Writer) (err error) {
|
||||
switch t := t.(type) {
|
||||
case int8:
|
||||
_, err = fmt.Fprintf(w, "%vB", t)
|
||||
case bool:
|
||||
_, err = fmt.Fprintf(w, "%v", t)
|
||||
case int16:
|
||||
_, err = fmt.Fprintf(w, "%vS", t)
|
||||
case int32:
|
||||
_, err = fmt.Fprintf(w, "%vI", t)
|
||||
case int64:
|
||||
_, err = fmt.Fprintf(w, "%vL", t)
|
||||
case float32:
|
||||
_, err = fmt.Fprintf(w, "%vF", t)
|
||||
case float64:
|
||||
_, err = fmt.Fprintf(w, "%vD", t)
|
||||
case string:
|
||||
_, err = fmt.Fprintf(w, "%q", t)
|
||||
case []any:
|
||||
_, err = fmt.Fprintf(w, "[")
|
||||
for _, v := range t {
|
||||
err = PrintSNBTAny(v, w)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
_, err = fmt.Fprintf(w, ",")
|
||||
}
|
||||
_, err = fmt.Fprintf(w, "]")
|
||||
case map[string]any:
|
||||
_, err = fmt.Fprintf(w, "{")
|
||||
for k, v := range t {
|
||||
_, err = fmt.Fprintf(w, "%q:", k)
|
||||
err = PrintSNBTAny(v, w)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
_, err = fmt.Fprintf(w, ",")
|
||||
}
|
||||
_, err = fmt.Fprintf(w, "}")
|
||||
case []int8:
|
||||
_, err = fmt.Fprintf(w, "[B;")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
for _, v := range t {
|
||||
err = PrintSNBTAny(v, w)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
_, err = fmt.Fprintf(w, ",")
|
||||
}
|
||||
_, err = fmt.Fprintf(w, "]")
|
||||
case []int32:
|
||||
_, err = fmt.Fprintf(w, "[I;")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
for _, v := range t {
|
||||
err = PrintSNBTAny(v, w)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
_, err = fmt.Fprintf(w, ",")
|
||||
}
|
||||
_, err = fmt.Fprintf(w, "]")
|
||||
case []int64:
|
||||
_, err = fmt.Fprintf(w, "[L;")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
for _, v := range t {
|
||||
err = PrintSNBTAny(v, w)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
_, err = fmt.Fprintf(w, ",")
|
||||
}
|
||||
_, err = fmt.Fprintf(w, "]")
|
||||
default:
|
||||
err = UnknownTagTypeErr
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package nbt
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
_ "embed"
|
||||
"testing"
|
||||
)
|
||||
|
||||
//go:embed testdata/top_0_20.nbt
|
||||
var topSNBT []byte
|
||||
|
||||
func TestPrintSNBTAny(t *testing.T) {
|
||||
n, err := ReadUnstructuredFile(bytes.NewReader(topSNBT))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
bb := bytes.NewBuffer(nil)
|
||||
err = PrintSNBTAny(n.Value, bb)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
t.Log(bb.String())
|
||||
}
|
||||
Vendored
BIN
Binary file not shown.
Reference in New Issue
Block a user