From d6890360d150154236f157a718dbfffa774683a2 Mon Sep 17 00:00:00 2001 From: Tnze Date: Sat, 1 Jan 2022 20:45:16 +0800 Subject: [PATCH] Command parsers plan 1 --- server/command/command.go | 95 +++++++++++++++++++++++++++++++++++++++ server/command/parsers.go | 72 +++++++++++++++++++++++++++++ 2 files changed, 167 insertions(+) create mode 100644 server/command/command.go create mode 100644 server/command/parsers.go diff --git a/server/command/command.go b/server/command/command.go new file mode 100644 index 0000000..ff2c607 --- /dev/null +++ b/server/command/command.go @@ -0,0 +1,95 @@ +package command + +import ( + "io" + "unsafe" + + pk "github.com/Tnze/go-mc/net/packet" +) + +type CmdSet struct { + root int32 + nodes []Node +} + +func NewCmdSet() *CmdSet { + return &CmdSet{ + root: 0, + nodes: []Node{ + { + flags: TypeRoot, + parser: nil, + }, + }, + } +} + +func (c *CmdSet) AddNode(n Node) int32 { + c.nodes = append(c.nodes, n) + return int32(len(c.nodes) - 1) +} + +func (c *CmdSet) WriteTo(w io.Writer) (int64, error) { + return pk.Tuple{ + pk.Array(c.nodes), + pk.VarInt(c.root), + }.WriteTo(w) +} + +func (c *CmdSet) Execute(cmd string) error { + for _, child := range c.nodes[c.root].children { + if node := c.nodes[child]; node.flags&0x03 == TypeLiteral { + + } + } +} + +type Node struct { + flags byte + children []int32 + redirect int32 + name string + parser Parser + suggestions string +} + +func (n *Node) WriteTo(w io.Writer) (int64, error) { + return pk.Tuple{ + pk.Byte(n.flags), + pk.Array(*(*[]pk.VarInt)(unsafe.Pointer(&n.children))), + pk.Opt{ // Redirect + Has: n.flags&HasRedirect != 0, + Field: pk.VarInt(n.redirect), + }, + pk.Opt{ // Name + Has: n.flags&0x03 == TypeLiteral || n.flags&0x03 == TypeArgument, + Field: pk.String(n.name), + }, + pk.Opt{ // Parser & Properties + Has: n.flags&0x03 == TypeArgument, + Field: n.parser, + }, + pk.Opt{ + Has: n.flags&HasSuggestionsType != 0, + Field: pk.Identifier(n.suggestions), + }, + }.WriteTo(w) +} + +type Parser interface { + pk.FieldEncoder + Parse(cmd string) (token string, value interface{}, err error) +} + +const ( + TypeRoot byte = iota + TypeLiteral + TypeArgument + TypeUnknown +) + +const ( + IsExecutable = 1 << (iota + 2) + HasRedirect + HasSuggestionsType +) diff --git a/server/command/parsers.go b/server/command/parsers.go new file mode 100644 index 0000000..aee60b9 --- /dev/null +++ b/server/command/parsers.go @@ -0,0 +1,72 @@ +package command + +import ( + "io" + "strconv" + "strings" + + pk "github.com/Tnze/go-mc/net/packet" +) + +type StringParser struct { + Format int32 + V string +} + +func (s StringParser) WriteTo(w io.Writer) (int64, error) { + return pk.Tuple{ + pk.Identifier("brigadier:string"), + pk.VarInt(s.Format), + }.WriteTo(w) +} + +func (s StringParser) Parse(cmd string) (token string, value interface{}, err error) { + switch s.Format { + case 2: // Greedy Phrase + return cmd, cmd, nil + case 1: // Quotable Phrase + if len(cmd) > 0 && cmd[0] == '"' { + var sb strings.Builder + var isEscaping bool + for i, v := range cmd[1:] { + if isEscaping { + isEscaping = false + switch v { + case '\\': + sb.WriteRune('\\') + case '"': + sb.WriteRune('"') + } + } else if v == '\\' { + isEscaping = true + } else if v == '"' { + return cmd[:i], sb.String(), nil + } else { + sb.WriteRune(v) + } + } + return "", nil, ParseErr{ + Pos: len(cmd) - 1, + Err: "expected '\"'", + } + } + fallthrough + case 0: // Single Word + i := strings.IndexAny(cmd, "\t\n\v\f\r ") + if i == -1 { + return cmd, cmd, nil + } + return cmd[:i], cmd[:i], nil + default: + panic("StringParser: unknown format 0x" + strconv.FormatInt(int64(s.Format), 16)) + } +} + +type ParseErr struct { + Pos int + Err string +} + +func (p ParseErr) Error() string { + return p.Err +}