nbt

package
v0.0.0-...-fdeead0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 5, 2024 License: MIT Imports: 12 Imported by: 0

README

NBT Go Reference

This package implements the Named Binary Tag format of Minecraft.

The API is very similar to the standard library encoding/json. (But fix some its problem) If you (high probability) have used that, it is easy to use this.

Supported Struct Tags and Options

  • nbt - The primary tag name. See below.
  • nbtkey - The key name of the field (Used to support commas , in tag names)
The nbt tag

In most cases, you only need this one to specify the name of the tag.

The format of nbt struct tag: <nbt tag>[,opt].

It's a comma-separated list of options. The first item is the name of the tag, and the rest are options.

Like this:

type MyStruct struct {
    Name string `nbt:"name"`
}

To tell the encoder not to encode a field, use -:

type MyStruct struct {
    Internal string `nbt:"-"`
}

To tell the encoder to skip the field if it is zero value, use omitempty:

type MyStruct struct {
    Name string `nbt:"name,omitempty"`
}

Fields typed []byte, []int32 and []int64 will be encoded as TagByteArray, TagIntArray and TagLongArray respectively by default. You can override this behavior by specifying encode them asTagList by using list:

type MyStruct struct {
    Data []byte `nbt:"data,list"`
}
The nbtkey tag

Common issue with JSON standard libraries: inability to specify keys containing commas for structures. (e.g {"a,b" : "c"})

So this is a workaround for that:

type MyStruct struct {
    AB string `nbt:",omitempty" nbtkey:"a,b"`
}

Documentation

Overview

Package nbt implement the Named Binary Tag format of Minecraft. It provides api like encoding/json package.

Index

Examples

Constants

View Source
const (
	TagEnd byte = iota
	TagByte
	TagShort
	TagInt
	TagLong
	TagFloat
	TagDouble
	TagByteArray
	TagString
	TagList
	TagCompound
	TagIntArray
	TagLongArray
)

Tag type IDs

Variables

View Source
var ErrEND = errors.New("unexpected TAG_End")

ErrEND error will be returned when reading a NBT with only Tag_End

Functions

func Marshal

func Marshal(v any) ([]byte, error)

Marshal is the shortcut of NewEncoder().Encode() with empty tag name. Notices that repeatedly init buffers is low efficiency. Using Encoder and Reset the buffer in each time is recommended in that cases.

Example (AnonymousStructField)
package main

import (
	"fmt"

	"github.com/OOPSgary/go-mc-modified/nbt"
)

func main() {
	type A struct{ F string }
	type B struct{ E string }
	type S struct {
		A           // anonymous fields are usually marshaled as if their inner exported fields were fields in the outer struct
		B `nbt:"B"` // anonymous field, but with an explicit tag name specified
	}

	var val S
	val.F = "Tnze"
	val.E = "GoMC"

	data, err := nbt.Marshal(val)
	if err != nil {
		panic(err)
	}

	var snbt nbt.StringifiedMessage
	if err := nbt.Unmarshal(data, &snbt); err != nil {
		panic(err)
	}
	fmt.Println(snbt)

}
Output:

{F:Tnze,B:{E:GoMC}}

func Unmarshal

func Unmarshal(data []byte, v any) error

Unmarshal decode binary NBT data and fill into v This is a shortcut to `NewDecoder(bytes.NewReader(data)).Decode(v)`.

Example (AnonymousStructField)
package main

import (
	"fmt"

	"github.com/OOPSgary/go-mc-modified/nbt"
)

func main() {
	type A struct{ F string }
	type B struct{ E string }
	type S struct {
		A           // anonymous fields are usually marshaled as if their inner exported fields were fields in the outer struct
		B `nbt:"B"` // anonymous field, but with an explicit tag name specified
	}

	data, err := nbt.Marshal(nbt.StringifiedMessage(`{F:Tnze,B:{E:GoMC}}`))
	if err != nil {
		panic(err)
	}

	var val S
	if err := nbt.Unmarshal(data, &val); err != nil {
		panic(err)
	}
	fmt.Println(val.F)
	fmt.Println(val.E)

}
Output:

Tnze
GoMC

Types

type Decoder

type Decoder struct {
	// contains filtered or unexported fields
}

func NewDecoder

func NewDecoder(r io.Reader) *Decoder

func (*Decoder) Decode

func (d *Decoder) Decode(v any) (string, error)

Decode method decodes an NBT value from the reader underline the Decoder into v. Internally try to handle all possible v by reflection, but the type of v must matches the NBT value logically. For example, you can decode an NBT value which root tag is TagCompound(0x0a) into a struct or map, but not a string.

If v implement Unmarshaler, the method will be called and override the default behavior. Else if v implement encoding.TextUnmarshaler, the value will be encoded as TagString.

This method also return tag name of the root tag. In real world, it is often empty, but the API should allow you to get it when ever you want.

Example
reader := bytes.NewReader([]byte{
	0x0a, // Start TagCompound("")
	0x00, 0x00,

	0x08, // TagString("Author"): "Tnze"
	0x00, 0x06, 'A', 'u', 't', 'h', 'o', 'r',
	0x00, 0x04, 'T', 'n', 'z', 'e',

	0x00, // End TagCompound
})

var value struct {
	Author string
}

decoder := NewDecoder(reader)
_, err := decoder.Decode(&value)
if err != nil {
	panic(err)
}

fmt.Println(value)
Output:

{Tnze}
Example (SingleTagString)
reader := bytes.NewReader([]byte{
	// TagString
	0x08,
	// TagName
	0x00, 0x04,
	0x6e, 0x61, 0x6d, 0x65,
	// Content
	0x00, 0x09,
	0x42, 0x61, 0x6e, 0x61, 0x6e, 0x72, 0x61, 0x6d, 0x61,
})

var Name string

decoder := NewDecoder(reader)
tagName, err := decoder.Decode(&Name)
if err != nil {
	panic(err)
}

fmt.Println(tagName)
fmt.Println(Name)
Output:

name
Bananrama

func (*Decoder) DisallowUnknownFields

func (d *Decoder) DisallowUnknownFields()

DisallowUnknownFields makes the decoder return an error when unmarshalling a compound tag item that has a tag name not present in the destination struct.

func (*Decoder) NetworkFormat

func (d *Decoder) NetworkFormat(enable bool)

NetworkFormat controls wether the decoder parsing nbt in "network format". Means it haven't a tag name for root tag.

It is disabled by default.

type DecoderReader

type DecoderReader = interface {
	io.ByteReader
	io.Reader
}

type Encoder

type Encoder struct {
	// contains filtered or unexported fields
}
Example (WriteSNBT)
var buf bytes.Buffer
if err := NewEncoder(&buf).Encode(StringifiedMessage(`{ name: [Tnze, "Xi_Xi_Mi"]}`), ""); err != nil {
	panic(err)
}
fmt.Printf("% 02x ", buf.Bytes())
Output:

0a 00 00 09 00 04 6e 61 6d 65 08 00 00 00 02 00 04 54 6e 7a 65 00 08 58 69 5f 58 69 5f 4d 69 00

func NewEncoder

func NewEncoder(w io.Writer) *Encoder

func (*Encoder) Encode

func (e *Encoder) Encode(v any, tagName string) (err error)

Encode encodes v into the writer inside Encoder with the root tag named tagName. In most cases, the root tag typed TagCompound and the tag name is empty string, but any other type is allowed just because there is valid technically. Once if you should pass a string into this, you should get a TagString.

Normally, any slice or array typed Go value will be encoded as TagList, expect `[]int8`, `[]int32`, `[]int64`, `[]uint8`, `[]uint32` and `[]uint64`, which TagByteArray, TagIntArray and TagLongArray. To force encode them as TagList, add a struct field tag.

Example (TagCompound)
value := struct {
	Name string `nbt:"name"`
}{"Tnze"}

var buff bytes.Buffer
encoder := NewEncoder(&buff)
err := encoder.Encode(value, "")
if err != nil {
	panic(err)
}

fmt.Printf("% 02x ", buff.Bytes())
Output:

	0a 00 00 08 00 04 6e 61 6d 65 00 04 54 6e 7a 65 00

func (*Encoder) NetworkFormat

func (e *Encoder) NetworkFormat(enable bool)

NetworkFormat controls wether encoder encoding nbt in "network format". Means it haven't a tag name for root tag.

It is disabled by default.

type Marshaler

type Marshaler interface {
	TagType() byte
	MarshalNBT(w io.Writer) error
}

type RawMessage

type RawMessage struct {
	Type byte
	Data []byte
}

RawMessage stores the raw binary data of NBT. This is usable if you want to store an unknown NBT data and use it later.

Notice that this struct doesn't store the root tag name.

To convert RawMessage to valid NBT binary value: Encoder.Encode(RawMessage, Name) = []byte{ Type (1 byte) | n (2 byte) | Name (n byte) | Data}.

func (RawMessage) MarshalNBT

func (m RawMessage) MarshalNBT(w io.Writer) error

func (RawMessage) String

func (m RawMessage) String() string

String converts the data into the SNBT(Stringified NBT) format. The output is valid for using in in-game command. Expect two exceptions: - Empty string "" if there is only a TagEnd in the NBT (aka: []byte{0}). - "<Invalid: $Err>" if the content is not valid NBT data.

func (RawMessage) TagType

func (m RawMessage) TagType() byte

func (RawMessage) Unmarshal

func (m RawMessage) Unmarshal(v any) error

Unmarshal decode the data into v.

func (RawMessage) UnmarshalDisallowUnknownField

func (m RawMessage) UnmarshalDisallowUnknownField(v any) error

func (*RawMessage) UnmarshalNBT

func (m *RawMessage) UnmarshalNBT(tagType byte, r DecoderReader) error

type StringifiedMessage

type StringifiedMessage string

func (StringifiedMessage) MarshalNBT

func (m StringifiedMessage) MarshalNBT(w io.Writer) error

func (StringifiedMessage) TagType

func (m StringifiedMessage) TagType() byte

func (*StringifiedMessage) UnmarshalNBT

func (m *StringifiedMessage) UnmarshalNBT(tagType byte, r DecoderReader) error

type SyntaxError

type SyntaxError struct {
	Message string
	Offset  int
}

func (*SyntaxError) Error

func (e *SyntaxError) Error() string

type Unmarshaler

type Unmarshaler interface {
	UnmarshalNBT(tagType byte, r DecoderReader) error
}

Directories

Path Synopsis
Package dynbt is a library that provides dynamic NBT operation APIs.
Package dynbt is a library that provides dynamic NBT operation APIs.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL