Command parsers plan 1

This commit is contained in:
Tnze
2022-01-01 20:45:16 +08:00
parent 9b1349a274
commit d6890360d1
2 changed files with 167 additions and 0 deletions

95
server/command/command.go Normal file
View File

@ -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
)

72
server/command/parsers.go Normal file
View File

@ -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
}