Command parse compound
This commit is contained in:
@ -5,6 +5,7 @@ import (
|
|||||||
_ "embed"
|
_ "embed"
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/Tnze/go-mc/server/command"
|
||||||
"image"
|
"image"
|
||||||
_ "image/png"
|
_ "image/png"
|
||||||
"log"
|
"log"
|
||||||
@ -37,11 +38,31 @@ func main() {
|
|||||||
log.Fatalf("Load chunks fail: %v", err)
|
log.Fatalf("Load chunks fail: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
commands := server.NewCommandGraph()
|
||||||
|
handleFunc := func(args []command.ParsedData) error {
|
||||||
|
log.Printf("Command: args: %v", args)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
commands.AppendLiteral(commands.Literal("me").
|
||||||
|
AppendArgument(commands.Argument("action", command.StringParser(2)).
|
||||||
|
HandleFunc(handleFunc)).
|
||||||
|
Unhandle(),
|
||||||
|
).AppendLiteral(commands.Literal("help").
|
||||||
|
AppendArgument(commands.Argument("command", command.StringParser(0)).
|
||||||
|
HandleFunc(handleFunc)).
|
||||||
|
HandleFunc(handleFunc),
|
||||||
|
).AppendLiteral(commands.Literal("list").
|
||||||
|
AppendLiteral(commands.Literal("uuids").
|
||||||
|
HandleFunc(handleFunc)).
|
||||||
|
HandleFunc(handleFunc),
|
||||||
|
)
|
||||||
|
|
||||||
game := server.NewGame(
|
game := server.NewGame(
|
||||||
defaultDimension,
|
defaultDimension,
|
||||||
playerList,
|
playerList,
|
||||||
server.NewKeepAlive(),
|
server.NewKeepAlive(),
|
||||||
server.NewGlobalChat(),
|
server.NewGlobalChat(),
|
||||||
|
commands,
|
||||||
)
|
)
|
||||||
go game.Run(context.Background())
|
go game.Run(context.Background())
|
||||||
|
|
||||||
|
@ -82,7 +82,16 @@ func (a Ary) ReadFrom(r io.Reader) (n int64, err error) {
|
|||||||
//
|
//
|
||||||
// Warning: unstable API, may change in later version
|
// Warning: unstable API, may change in later version
|
||||||
func Array(array interface{}) Field {
|
func Array(array interface{}) Field {
|
||||||
length := VarInt(reflect.ValueOf(array).Len())
|
var length VarInt
|
||||||
|
|
||||||
|
value := reflect.ValueOf(array)
|
||||||
|
for value.Kind() == reflect.Ptr {
|
||||||
|
value = value.Elem()
|
||||||
|
}
|
||||||
|
|
||||||
|
if array != nil {
|
||||||
|
length = VarInt(value.Len())
|
||||||
|
}
|
||||||
return Tuple{
|
return Tuple{
|
||||||
&length,
|
&length,
|
||||||
Ary{
|
Ary{
|
||||||
|
@ -87,10 +87,7 @@ func (g *GlobalChat) Run(ctx context.Context) {
|
|||||||
|
|
||||||
func (g *GlobalChat) broadcast(packet Packet757) {
|
func (g *GlobalChat) broadcast(packet Packet757) {
|
||||||
for _, p := range g.players {
|
for _, p := range g.players {
|
||||||
err := p.WritePacket(packet)
|
p.WritePacket(packet)
|
||||||
if err != nil {
|
|
||||||
p.PutErr(err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
49
server/command.go
Normal file
49
server/command.go
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
package server
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"github.com/Tnze/go-mc/data/packetid"
|
||||||
|
pk "github.com/Tnze/go-mc/net/packet"
|
||||||
|
"github.com/Tnze/go-mc/server/command"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type CommandGraph struct {
|
||||||
|
*command.Graph
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewCommandGraph() *CommandGraph {
|
||||||
|
return &CommandGraph{
|
||||||
|
Graph: command.NewGraph(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *CommandGraph) Init(g *Game) {
|
||||||
|
g.AddHandler(&PacketHandler{
|
||||||
|
ID: packetid.ServerboundChat,
|
||||||
|
F: func(player *Player, packet Packet757) error {
|
||||||
|
var msg pk.String
|
||||||
|
if err := pk.Packet(packet).Scan(&msg); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if cmd := string(msg); strings.HasPrefix(cmd, "/") {
|
||||||
|
cmderr := c.Graph.Run(strings.TrimPrefix(cmd, "/"))
|
||||||
|
if cmderr != nil {
|
||||||
|
// TODO: tell player that their command has error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *CommandGraph) Run(ctx context.Context) {}
|
||||||
|
|
||||||
|
func (c *CommandGraph) AddPlayer(p *Player) {
|
||||||
|
p.WritePacket(Packet757(pk.Marshal(
|
||||||
|
packetid.ClientboundCommands,
|
||||||
|
c.Graph,
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *CommandGraph) RemovePlayer(p *Player) {}
|
@ -6,22 +6,22 @@ func (g *Graph) AppendLiteral(child *Literal) *Graph {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (g *Graph) Literal(str string) LiteralBuilder {
|
func (g *Graph) Literal(str string) LiteralBuilder {
|
||||||
index := len(g.nodes)
|
index := int32(len(g.nodes))
|
||||||
g.nodes = append(g.nodes, Node{
|
g.nodes = append(g.nodes, Node{
|
||||||
g: g,
|
g: g,
|
||||||
index: index,
|
index: index,
|
||||||
flags: LiteralNode,
|
kind: LiteralNode,
|
||||||
Name: str,
|
Name: str,
|
||||||
})
|
})
|
||||||
return LiteralBuilder{g: g, current: index}
|
return LiteralBuilder{g: g, current: index}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *Graph) Argument(name string, parser Parser) ArgumentBuilder {
|
func (g *Graph) Argument(name string, parser Parser) ArgumentBuilder {
|
||||||
index := len(g.nodes)
|
index := int32(len(g.nodes))
|
||||||
g.nodes = append(g.nodes, Node{
|
g.nodes = append(g.nodes, Node{
|
||||||
g: g,
|
g: g,
|
||||||
index: index,
|
index: index,
|
||||||
flags: ArgumentNode,
|
kind: ArgumentNode,
|
||||||
Name: name,
|
Name: name,
|
||||||
Parser: parser,
|
Parser: parser,
|
||||||
})
|
})
|
||||||
@ -30,7 +30,7 @@ func (g *Graph) Argument(name string, parser Parser) ArgumentBuilder {
|
|||||||
|
|
||||||
type LiteralBuilder struct {
|
type LiteralBuilder struct {
|
||||||
g *Graph
|
g *Graph
|
||||||
current int
|
current int32
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n LiteralBuilder) AppendLiteral(node *Literal) LiteralBuilderWithLiteral {
|
func (n LiteralBuilder) AppendLiteral(node *Literal) LiteralBuilderWithLiteral {
|
||||||
@ -57,7 +57,7 @@ func (n LiteralBuilder) Unhandle() *Literal {
|
|||||||
|
|
||||||
type ArgumentBuilder struct {
|
type ArgumentBuilder struct {
|
||||||
g *Graph
|
g *Graph
|
||||||
current int
|
current int32
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n ArgumentBuilder) AppendLiteral(node *Literal) ArgumentBuilderWithLiteral {
|
func (n ArgumentBuilder) AppendLiteral(node *Literal) ArgumentBuilderWithLiteral {
|
||||||
|
@ -18,8 +18,8 @@ type Graph struct {
|
|||||||
func NewGraph() *Graph {
|
func NewGraph() *Graph {
|
||||||
g := new(Graph)
|
g := new(Graph)
|
||||||
root := Node{
|
root := Node{
|
||||||
g: g,
|
g: g,
|
||||||
flags: RootNode,
|
kind: RootNode,
|
||||||
}
|
}
|
||||||
g.nodes = append(g.nodes, root)
|
g.nodes = append(g.nodes, root)
|
||||||
return g
|
return g
|
||||||
@ -43,7 +43,7 @@ func (g *Graph) Run(cmd string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if next == 0 {
|
if next == 0 {
|
||||||
panic("root node can't be child")
|
return errors.New("command contains extra text: " + left)
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd = left
|
cmd = left
|
||||||
@ -56,19 +56,20 @@ type ParsedData interface{}
|
|||||||
type HandlerFunc func(args []ParsedData) error
|
type HandlerFunc func(args []ParsedData) error
|
||||||
|
|
||||||
type Node struct {
|
type Node struct {
|
||||||
g *Graph
|
g *Graph
|
||||||
index int
|
index int32
|
||||||
flags byte
|
kind byte
|
||||||
Name string
|
Name string
|
||||||
Children []int
|
Children []int32
|
||||||
Parser Parser
|
SuggestionsType string
|
||||||
Run HandlerFunc
|
Parser Parser
|
||||||
|
Run HandlerFunc
|
||||||
}
|
}
|
||||||
type Literal Node
|
type Literal Node
|
||||||
type Argument Node
|
type Argument Node
|
||||||
|
|
||||||
func (n *Node) parse(cmd string) (left string, value ParsedData, next int, err error) {
|
func (n *Node) parse(cmd string) (left string, value ParsedData, next int32, err error) {
|
||||||
switch n.flags & 0x03 {
|
switch n.kind & 0x03 {
|
||||||
case RootNode:
|
case RootNode:
|
||||||
left = cmd
|
left = cmd
|
||||||
value = nil
|
value = nil
|
||||||
@ -90,7 +91,7 @@ func (n *Node) parse(cmd string) (left string, value ParsedData, next int, err e
|
|||||||
// find next
|
// find next
|
||||||
if len(n.Children) > 0 {
|
if len(n.Children) > 0 {
|
||||||
// look up the first child's type
|
// look up the first child's type
|
||||||
switch n.g.nodes[n.Children[0]].flags & 0x03 {
|
switch n.g.nodes[n.Children[0]].kind & 0x03 {
|
||||||
case RootNode:
|
case RootNode:
|
||||||
panic("root node can't be child")
|
panic("root node can't be child")
|
||||||
default:
|
default:
|
||||||
|
@ -1,63 +1,32 @@
|
|||||||
package command
|
package command
|
||||||
|
|
||||||
import "testing"
|
import (
|
||||||
|
"log"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
func TestRoot_Run(t *testing.T) {
|
func TestRoot_Run(t *testing.T) {
|
||||||
|
handleFunc := func(args []ParsedData) error {
|
||||||
|
log.Printf("Command: args: %v", args)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
g := NewGraph()
|
g := NewGraph()
|
||||||
g.AppendLiteral(g.Literal("whitelist").
|
g.AppendLiteral(g.Literal("me").
|
||||||
AppendLiteral(g.Literal("add").
|
AppendArgument(g.Argument("action", StringParser(2)).
|
||||||
AppendArgument(g.Argument("targets", StringParser(0)).
|
HandleFunc(handleFunc)).
|
||||||
HandleFunc(func(args []ParsedData) error {
|
|
||||||
t.Logf("whitelist add: %v", args)
|
|
||||||
return nil
|
|
||||||
})).Unhandle()).
|
|
||||||
AppendLiteral(g.Literal("remove").
|
|
||||||
AppendArgument(g.Argument("targets", StringParser(0)).
|
|
||||||
HandleFunc(func(args []ParsedData) error {
|
|
||||||
t.Logf("whitelist remove: %v", args)
|
|
||||||
return nil
|
|
||||||
})).Unhandle()).
|
|
||||||
AppendLiteral(g.Literal("on").
|
|
||||||
HandleFunc(func(args []ParsedData) error {
|
|
||||||
t.Logf("whitelist on: %v", args)
|
|
||||||
return nil
|
|
||||||
})).
|
|
||||||
AppendLiteral(g.Literal("off").
|
|
||||||
HandleFunc(func(args []ParsedData) error {
|
|
||||||
t.Logf("whitelist off: %v", args)
|
|
||||||
return nil
|
|
||||||
})).
|
|
||||||
Unhandle(),
|
Unhandle(),
|
||||||
|
).AppendLiteral(g.Literal("help").
|
||||||
|
AppendArgument(g.Argument("command", StringParser(0)).
|
||||||
|
HandleFunc(handleFunc)).
|
||||||
|
HandleFunc(handleFunc),
|
||||||
|
).AppendLiteral(g.Literal("list").
|
||||||
|
AppendLiteral(g.Literal("uuids").
|
||||||
|
HandleFunc(handleFunc)).
|
||||||
|
HandleFunc(handleFunc),
|
||||||
)
|
)
|
||||||
|
|
||||||
targetB := g.Argument("targetB", StringParser(0)).
|
err := g.Run("me Tnze Xi_Xi_Mi")
|
||||||
HandleFunc(func(args []ParsedData) error {
|
|
||||||
t.Logf("tp A <from/to> B parsed: %v", args)
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
g.AppendLiteral(g.Literal("tp").AppendArgument(
|
|
||||||
g.Argument("targetA", StringParser(0)).
|
|
||||||
AppendLiteral(g.Literal("from").
|
|
||||||
AppendArgument(targetB).
|
|
||||||
Unhandle()).
|
|
||||||
AppendLiteral(g.Literal("to").
|
|
||||||
AppendArgument(targetB).
|
|
||||||
Unhandle()).
|
|
||||||
Unhandle(),
|
|
||||||
).Unhandle())
|
|
||||||
|
|
||||||
err := g.Run("tp Tnze to Xi_Xi_Mi")
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
//g2 := NewGraph()
|
|
||||||
//g2.Then(
|
|
||||||
// g.Lite("whitelist").Then(
|
|
||||||
// // using reflect to generate all arguments nodes
|
|
||||||
// g.Lite("add").Then(g.Func(func(player GameProfile) {
|
|
||||||
//
|
|
||||||
// })),
|
|
||||||
// ),
|
|
||||||
//)
|
|
||||||
}
|
}
|
||||||
|
49
server/command/serialize.go
Normal file
49
server/command/serialize.go
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
package command
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
pk "github.com/Tnze/go-mc/net/packet"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
isExecutable = 1 << (iota + 2)
|
||||||
|
hasRedirect
|
||||||
|
hasSuggestionsType
|
||||||
|
)
|
||||||
|
|
||||||
|
func (g *Graph) WriteTo(w io.Writer) (int64, error) {
|
||||||
|
return pk.Tuple{
|
||||||
|
pk.Array(g.nodes),
|
||||||
|
pk.VarInt(0),
|
||||||
|
}.WriteTo(w)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n Node) WriteTo(w io.Writer) (int64, error) {
|
||||||
|
var flag byte
|
||||||
|
flag |= n.kind & 0x03
|
||||||
|
if n.Run != nil {
|
||||||
|
flag |= isExecutable
|
||||||
|
}
|
||||||
|
return pk.Tuple{
|
||||||
|
pk.Byte(flag),
|
||||||
|
pk.Array((*[]pk.VarInt)(unsafe.Pointer(&n.Children))),
|
||||||
|
pk.Opt{
|
||||||
|
Has: func() bool { return n.kind&hasRedirect != 0 },
|
||||||
|
Field: nil, // TODO: send redirect node
|
||||||
|
},
|
||||||
|
pk.Opt{
|
||||||
|
Has: func() bool { return n.kind == ArgumentNode || n.kind == LiteralNode },
|
||||||
|
Field: pk.String(n.Name),
|
||||||
|
},
|
||||||
|
pk.Opt{
|
||||||
|
Has: func() bool { return n.kind == ArgumentNode },
|
||||||
|
Field: n.Parser, // Parser identifier and Properties
|
||||||
|
},
|
||||||
|
pk.Opt{
|
||||||
|
Has: func() bool { return flag&hasSuggestionsType != 0 },
|
||||||
|
Field: nil, // TODO: send Suggestions type
|
||||||
|
},
|
||||||
|
}.WriteTo(w)
|
||||||
|
}
|
@ -50,13 +50,10 @@ func (s *SimpleDim) PlayerJoin(p *Player) {
|
|||||||
)
|
)
|
||||||
column.Unlock()
|
column.Unlock()
|
||||||
|
|
||||||
err := p.WritePacket(Packet757(packet))
|
p.WritePacket(Packet757(packet))
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
err := p.WritePacket(Packet757(pk.Marshal(
|
p.WritePacket(Packet757(pk.Marshal(
|
||||||
packetid.ClientboundPlayerPosition,
|
packetid.ClientboundPlayerPosition,
|
||||||
pk.Double(0), pk.Double(143), pk.Double(0),
|
pk.Double(0), pk.Double(143), pk.Double(0),
|
||||||
pk.Float(0), pk.Float(0),
|
pk.Float(0), pk.Float(0),
|
||||||
@ -64,9 +61,6 @@ func (s *SimpleDim) PlayerJoin(p *Player) {
|
|||||||
pk.VarInt(0),
|
pk.VarInt(0),
|
||||||
pk.Boolean(true),
|
pk.Boolean(true),
|
||||||
)))
|
)))
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *SimpleDim) PlayerQuit(p *Player) {
|
func (s *SimpleDim) PlayerQuit(p *Player) {
|
||||||
|
@ -80,15 +80,16 @@ func (g *Game) Run(ctx context.Context) {
|
|||||||
|
|
||||||
func (g *Game) AcceptPlayer(name string, id uuid.UUID, protocol int32, conn *net.Conn) {
|
func (g *Game) AcceptPlayer(name string, id uuid.UUID, protocol int32, conn *net.Conn) {
|
||||||
p := &Player{
|
p := &Player{
|
||||||
Conn: conn,
|
Conn: conn,
|
||||||
Name: name,
|
Name: name,
|
||||||
UUID: id,
|
UUID: id,
|
||||||
EntityID: g.newEID(),
|
EntityID: g.newEID(),
|
||||||
Gamemode: 1,
|
Gamemode: 1,
|
||||||
errChan: make(chan error, 1),
|
packetQueue: NewPacketQueue(),
|
||||||
|
errChan: make(chan error, 1),
|
||||||
}
|
}
|
||||||
dimInfo := g.Dim.Info()
|
dimInfo := g.Dim.Info()
|
||||||
err := p.WritePacket(Packet757(pk.Marshal(
|
err := p.Conn.WritePacket(pk.Marshal(
|
||||||
packetid.ClientboundLogin,
|
packetid.ClientboundLogin,
|
||||||
pk.Int(p.EntityID), // Entity ID
|
pk.Int(p.EntityID), // Entity ID
|
||||||
pk.Boolean(false), // Is hardcore
|
pk.Boolean(false), // Is hardcore
|
||||||
@ -106,10 +107,26 @@ func (g *Game) AcceptPlayer(name string, id uuid.UUID, protocol int32, conn *net
|
|||||||
pk.Boolean(true), // Enable respawn screen
|
pk.Boolean(true), // Enable respawn screen
|
||||||
pk.Boolean(false), // Is Debug
|
pk.Boolean(false), // Is Debug
|
||||||
pk.Boolean(true), // Is Flat
|
pk.Boolean(true), // Is Flat
|
||||||
)))
|
))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
for {
|
||||||
|
packet, ok := p.packetQueue.Pull()
|
||||||
|
if !ok {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
err := p.Conn.WritePacket(packet)
|
||||||
|
if err != nil {
|
||||||
|
p.PutErr(err)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
defer p.packetQueue.Close()
|
||||||
|
|
||||||
g.Dim.PlayerJoin(p)
|
g.Dim.PlayerJoin(p)
|
||||||
defer g.Dim.PlayerQuit(p)
|
defer g.Dim.PlayerQuit(p)
|
||||||
|
|
||||||
|
@ -121,14 +121,10 @@ func (k *KeepAlive) pingPlayer(now time.Time) {
|
|||||||
if elem := k.pingList.Front(); elem != nil {
|
if elem := k.pingList.Front(); elem != nil {
|
||||||
p := k.pingList.Remove(elem).(keepAliveItem).player
|
p := k.pingList.Remove(elem).(keepAliveItem).player
|
||||||
// Send Clientbound KeepAlive packet.
|
// Send Clientbound KeepAlive packet.
|
||||||
err := p.WritePacket(Packet757(pk.Marshal(
|
p.WritePacket(Packet757(pk.Marshal(
|
||||||
packetid.ClientboundKeepAlive,
|
packetid.ClientboundKeepAlive,
|
||||||
pk.Long(k.keepAliveID),
|
pk.Long(k.keepAliveID),
|
||||||
)))
|
)))
|
||||||
if err != nil {
|
|
||||||
p.PutErr(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
k.keepAliveID++
|
k.keepAliveID++
|
||||||
// Clientbound KeepAlive packet is sent, move the player to waiting list.
|
// Clientbound KeepAlive packet is sent, move the player to waiting list.
|
||||||
k.listIndex[p.UUID] = k.waitList.PushBack(
|
k.listIndex[p.UUID] = k.waitList.PushBack(
|
||||||
|
@ -1,25 +1,25 @@
|
|||||||
package server
|
package server
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"container/list"
|
||||||
|
"github.com/google/uuid"
|
||||||
"strconv"
|
"strconv"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/google/uuid"
|
|
||||||
|
|
||||||
"github.com/Tnze/go-mc/net"
|
"github.com/Tnze/go-mc/net"
|
||||||
pk "github.com/Tnze/go-mc/net/packet"
|
pk "github.com/Tnze/go-mc/net/packet"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Player struct {
|
type Player struct {
|
||||||
*net.Conn
|
*net.Conn
|
||||||
writeLock sync.Mutex
|
|
||||||
|
|
||||||
Name string
|
Name string
|
||||||
uuid.UUID
|
uuid.UUID
|
||||||
EntityID int32
|
EntityID int32
|
||||||
Gamemode byte
|
Gamemode byte
|
||||||
|
|
||||||
errChan chan error
|
packetQueue *PacketQueue
|
||||||
|
errChan chan error
|
||||||
}
|
}
|
||||||
|
|
||||||
// Packet757 is a packet in protocol 757.
|
// Packet757 is a packet in protocol 757.
|
||||||
@ -27,14 +27,8 @@ type Player struct {
|
|||||||
type Packet757 pk.Packet
|
type Packet757 pk.Packet
|
||||||
|
|
||||||
// WritePacket to player client. The type of parameter will update per version.
|
// WritePacket to player client. The type of parameter will update per version.
|
||||||
func (p *Player) WritePacket(packet Packet757) error {
|
func (p *Player) WritePacket(packet Packet757) {
|
||||||
p.writeLock.Lock()
|
p.packetQueue.Push(pk.Packet(packet))
|
||||||
defer p.writeLock.Unlock()
|
|
||||||
err := p.Conn.WritePacket(pk.Packet(packet))
|
|
||||||
if err != nil {
|
|
||||||
return WritePacketError{Err: err, ID: packet.ID}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type WritePacketError struct {
|
type WritePacketError struct {
|
||||||
@ -66,3 +60,47 @@ func (p *Player) GetErr() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type PacketQueue struct {
|
||||||
|
queue *list.List
|
||||||
|
closed bool
|
||||||
|
cond sync.Cond
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewPacketQueue() (p *PacketQueue) {
|
||||||
|
p = &PacketQueue{
|
||||||
|
queue: list.New(),
|
||||||
|
cond: sync.Cond{L: new(sync.Mutex)},
|
||||||
|
}
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *PacketQueue) Push(packet pk.Packet) {
|
||||||
|
p.cond.L.Lock()
|
||||||
|
if !p.closed {
|
||||||
|
p.queue.PushBack(packet)
|
||||||
|
}
|
||||||
|
p.cond.Signal()
|
||||||
|
p.cond.L.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *PacketQueue) Pull() (packet pk.Packet, ok bool) {
|
||||||
|
p.cond.L.Lock()
|
||||||
|
defer p.cond.L.Unlock()
|
||||||
|
for p.queue.Front() == nil && !p.closed {
|
||||||
|
p.cond.Wait()
|
||||||
|
}
|
||||||
|
if p.closed {
|
||||||
|
return pk.Packet{}, false
|
||||||
|
}
|
||||||
|
packet = p.queue.Remove(p.queue.Front()).(pk.Packet)
|
||||||
|
ok = true
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *PacketQueue) Close() {
|
||||||
|
p.cond.L.Lock()
|
||||||
|
p.closed = true
|
||||||
|
p.cond.Broadcast()
|
||||||
|
p.cond.L.Unlock()
|
||||||
|
}
|
||||||
|
@ -42,15 +42,11 @@ func (p *PlayerList) AddPlayer(player *Player) {
|
|||||||
defer p.playersLock.Unlock()
|
defer p.playersLock.Unlock()
|
||||||
|
|
||||||
if len(p.players) >= p.maxPlayer {
|
if len(p.players) >= p.maxPlayer {
|
||||||
err := player.WritePacket(Packet757(pk.Marshal(
|
player.WritePacket(Packet757(pk.Marshal(
|
||||||
packetid.ClientboundDisconnect,
|
packetid.ClientboundDisconnect,
|
||||||
chat.TranslateMsg("multiplayer.disconnect.server_full"),
|
chat.TranslateMsg("multiplayer.disconnect.server_full"),
|
||||||
)))
|
)))
|
||||||
if err != nil {
|
player.PutErr(errors.New("playerlist: server full"))
|
||||||
player.PutErr(err)
|
|
||||||
} else {
|
|
||||||
player.PutErr(errors.New("playerlist: server full"))
|
|
||||||
}
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user