Skip to content

Commit 6de668d

Browse files
committed
various updates (May 2023)
1 parent 889dc37 commit 6de668d

45 files changed

Lines changed: 202 additions & 359 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

connection.go

Lines changed: 62 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -5,45 +5,62 @@ import (
55
"errors"
66
"fmt"
77
enc "github.com/Raqbit/mcproto/encoding"
8-
"github.com/Raqbit/mcproto/game"
9-
"github.com/Raqbit/mcproto/packet"
108
"io"
119
"net"
1210
"time"
1311
)
1412

13+
const MaxPacketLength = 1048576
14+
const (
15+
clientBound PacketDirection = iota
16+
serverBound PacketDirection = iota
17+
)
18+
1519
var (
16-
ErrConnectionState = errors.New("connection has invalid state for packet type")
17-
ErrDirection = errors.New("packet being sent in wrong direction")
18-
ErrLegacyServerPing = errors.New("not implemented: legacy server ping")
20+
ErrInvalidPacketLength = errors.New("packet has a malformed length")
21+
ErrLegacyServerPing = errors.New("legacy server ping not supported")
1922
)
2023

21-
// Connection represents a connection
22-
// to a Minecraft server or client.
23-
type Connection interface {
24-
ReadPacket() (packet.Packet, error)
25-
WritePacket(packet.Packet) error
26-
SetReadDeadline(time.Time) error
27-
SetWriteDeadline(time.Time) error
28-
Close() error
29-
SetState(state game.ConnectionState)
30-
}
24+
type (
25+
// Packet is a packet with side-bound ID
26+
Packet interface {
27+
fmt.Stringer
28+
enc.MinecraftEncodable
29+
enc.MinecraftDecodable
3130

32-
type connection struct {
33-
conn net.Conn
34-
state game.ConnectionState
35-
side Side
36-
packets map[packet.Info]packet.Packet
37-
writeBuf *bytes.Buffer
38-
readBuf *bytes.Buffer
39-
logger Logger
40-
}
31+
ID() int32
32+
}
33+
34+
// Connection represents a connection
35+
// to a Minecraft server or client.
36+
Connection interface {
37+
Read() (Packet, error)
38+
Write(Packet) error
39+
SetReadDeadline(time.Time) error
40+
SetWriteDeadline(time.Time) error
41+
Close() error
42+
SetState(state ConnectionState)
43+
}
44+
45+
// packetKey uniquely identifies a packet
46+
packetKey struct {
47+
id int32
48+
direction PacketDirection
49+
state ConnectionState
50+
}
51+
52+
connection struct {
53+
conn net.Conn
54+
state ConnectionState
55+
side Side
56+
packets map[packetKey]Packet
57+
writeBuf *bytes.Buffer
58+
readBuf *bytes.Buffer
59+
logger Logger
60+
}
61+
)
4162

42-
// ReadPacket reads a Minecraft protocol packet from the connection.
43-
// ReadPacket will also try to parse the contents of this packet and return
44-
// an error if the given packet ID is unknown or if the known packet format
45-
// did not decode correctly.
46-
func (c *connection) ReadPacket() (packet.Packet, error) {
63+
func (c *connection) Read() (Packet, error) {
4764
var err error
4865

4966
// Read packet length
@@ -58,8 +75,8 @@ func (c *connection) ReadPacket() (packet.Packet, error) {
5875
}
5976

6077
// Catch invalid packet lengths
61-
if length < 1 || length > packet.MaxPacketLength {
62-
return nil, packet.ErrInvalidPacketLength
78+
if length < 1 || length > MaxPacketLength {
79+
return nil, ErrInvalidPacketLength
6380
}
6481

6582
// Read complete packet into read buffer
@@ -74,7 +91,7 @@ func (c *connection) ReadPacket() (packet.Packet, error) {
7491
}
7592

7693
// Lookup packet type
77-
pkt, err := c.getPacketTypeByID(int32(pID))
94+
pkt, err := c.packetTypeFromID(int32(pID))
7895

7996
if err != nil {
8097
return nil, err
@@ -98,15 +115,7 @@ func (c *connection) ReadPacket() (packet.Packet, error) {
98115
// If the provided deadline expires before a packet could be written,
99116
// an error is returned. Providing a zero value for the deadline will
100117
// make the read not time out.
101-
func (c *connection) WritePacket(packetToWrite packet.Packet) error {
102-
if packetToWrite.State() != c.state {
103-
return ErrConnectionState
104-
}
105-
106-
if packetToWrite.Direction() != c.side.WriteDirection() {
107-
return ErrDirection
108-
}
109-
118+
func (c *connection) Write(packetToWrite Packet) error {
110119
c.logger.Debugf("[Send] %s, %d: %s\n", c.state, packetToWrite.ID(), packetToWrite.String())
111120

112121
packetId := enc.VarInt(packetToWrite.ID())
@@ -156,7 +165,7 @@ func (c *connection) SetWriteDeadline(t time.Time) error {
156165

157166
// SetState switches the protocol to a different state,
158167
// which changes the meaning of packet IDs.
159-
func (c *connection) SetState(state game.ConnectionState) {
168+
func (c *connection) SetState(state ConnectionState) {
160169
c.state = state
161170
}
162171

@@ -166,35 +175,31 @@ func (c *connection) Close() error {
166175
return c.conn.Close()
167176
}
168177

169-
func (c *connection) registerPacket(pkt packet.Packet) {
170-
c.packets[packet.Info{
171-
ID: pkt.ID(),
172-
ConnectionState: pkt.State(),
173-
Direction: pkt.Direction(),
174-
}] = pkt
178+
func (c *connection) registerPacket(pkt Packet, dir PacketDirection, state ConnectionState) {
179+
c.packets[packetKey{id: pkt.ID(), direction: dir, state: state}] = pkt
175180
}
176181

177182
type UnknownPacketError struct {
178183
id int32
179-
direction packet.Direction
180-
state game.ConnectionState
184+
direction PacketDirection
185+
state ConnectionState
181186
}
182187

183188
func (u UnknownPacketError) Error() string {
184-
return fmt.Sprintf("unknown packet ID, direction: %s, state: %s, ID: %#x", u.direction, u.state, u.id)
189+
return fmt.Sprintf("unknown packet id, direction: %s, state: %s, id: %#x", u.direction, u.state, u.id)
185190
}
186191

187-
func (c *connection) getPacketTypeByID(id int32) (packet.Packet, error) {
188-
p, ok := c.packets[packet.Info{
189-
ID: id,
190-
Direction: c.side.ReadDirection(),
191-
ConnectionState: c.state,
192+
func (c *connection) packetTypeFromID(id int32) (Packet, error) {
193+
p, ok := c.packets[packetKey{
194+
id: id,
195+
direction: c.side.readDirection(),
196+
state: c.state,
192197
}]
193198

194199
if !ok {
195200
return nil, UnknownPacketError{
196201
id: id,
197-
direction: c.side.WriteDirection(),
202+
direction: c.side.writeDirection(),
198203
state: c.state,
199204
}
200205
}

dial.go

Lines changed: 18 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ package mcproto
33
import (
44
"bytes"
55
"context"
6-
"github.com/Raqbit/mcproto/game"
76
"github.com/Raqbit/mcproto/packet"
87
"net"
98
)
@@ -43,7 +42,7 @@ func DialContext(ctx context.Context, address string, opts ...Option) (Connectio
4342

4443
// TODO: separate add timeout to SRV lookup
4544
// Resolve server address from host & port, by checking SRV record & joining host & port
46-
resolvedAddress := ResolveServerAddress(ctx, address)
45+
resolvedAddress := resolveServerAddress(ctx, address)
4746

4847
// Make TCP connection
4948
tcpConn, err := dialer.DialContext(ctx, "tcp", resolvedAddress)
@@ -52,10 +51,10 @@ func DialContext(ctx context.Context, address string, opts ...Option) (Connectio
5251
return nil, resolvedAddress, err
5352
}
5453

55-
// Set options
54+
// Combine default options with given options
5655
opts = append([]Option{
5756
WithSide(ClientSide),
58-
WithState(game.HandshakeState),
57+
WithState(HandshakeState),
5958
}, opts...)
6059

6160
// Wrap TCP connection in a wrapper for sending/receiving Minecraft packets
@@ -78,29 +77,29 @@ func Wrap(conn net.Conn, opts ...Option) Connection {
7877
mcConn := &connection{
7978
conn: conn,
8079
side: ServerSide,
81-
state: game.HandshakeState,
82-
packets: make(map[packet.Info]packet.Packet),
80+
state: HandshakeState,
81+
packets: make(map[packetKey]Packet),
8382
readBuf: new(bytes.Buffer),
8483
writeBuf: new(bytes.Buffer),
8584
logger: noopLogger{},
8685
}
8786

8887
// Server bound packets
89-
mcConn.registerPacket(&packet.HandshakePacket{})
90-
mcConn.registerPacket(&packet.ServerQueryPacket{})
91-
mcConn.registerPacket(&packet.PingPacket{})
92-
mcConn.registerPacket(&packet.LoginStartPacket{})
93-
mcConn.registerPacket(&packet.ClientSettingsPacket{})
88+
mcConn.registerPacket(new(packet.HandshakePacket), serverBound, HandshakeState)
89+
mcConn.registerPacket(new(packet.ServerQueryPacket), serverBound, StatusState)
90+
mcConn.registerPacket(new(packet.PingPacket), serverBound, StatusState)
91+
mcConn.registerPacket(new(packet.LoginStartPacket), serverBound, LoginState)
92+
mcConn.registerPacket(new(packet.ClientSettingsPacket), serverBound, PlayState)
9493

9594
// Client bound packets
96-
mcConn.registerPacket(&packet.PongPacket{})
97-
mcConn.registerPacket(&packet.LoginSuccessPacket{})
98-
mcConn.registerPacket(&packet.ChatMessagePacket{})
99-
mcConn.registerPacket(&packet.ServerInfoPacket{})
100-
mcConn.registerPacket(&packet.LoginDisconnectPacket{})
101-
mcConn.registerPacket(&packet.JoinGamePacket{})
102-
mcConn.registerPacket(&packet.PlayerPositionLookPacket{})
103-
mcConn.registerPacket(&packet.PluginMessagePacket{})
95+
mcConn.registerPacket(new(packet.PongPacket), clientBound, StatusState)
96+
mcConn.registerPacket(new(packet.LoginSuccessPacket), clientBound, LoginState)
97+
mcConn.registerPacket(new(packet.ChatMessagePacket), clientBound, PlayState)
98+
mcConn.registerPacket(new(packet.ServerInfoPacket), clientBound, StatusState)
99+
mcConn.registerPacket(new(packet.LoginDisconnectPacket), clientBound, LoginState)
100+
mcConn.registerPacket(new(packet.JoinGamePacket), clientBound, PlayState)
101+
mcConn.registerPacket(new(packet.PlayerPositionLookPacket), clientBound, PlayState)
102+
mcConn.registerPacket(new(packet.PluginMessagePacket), clientBound, PlayState)
104103

105104
// Apply options
106105
for _, opt := range opts {

direction.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package mcproto
2+
3+
//go:generate stringer -type=PacketDirection -output direction_string.go -linecomment
4+
5+
// PacketDirection is the direction of a packet
6+
type PacketDirection byte
7+
8+
const (
9+
ClientBound PacketDirection = iota // client-bound
10+
ServerBound // server-bound
11+
)

direction_string.go

Lines changed: 26 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

encoding/codec.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package encoding
2+
3+
import "io"
4+
5+
// MinecraftEncodable types can be encoded for the Minecraft protocol
6+
type MinecraftEncodable interface {
7+
Write(w io.Writer) error
8+
}
9+
10+
// MinecraftDecodable types can be decoded for the Minecraft protocol
11+
type MinecraftDecodable interface {
12+
Read(r io.Reader) error
13+
}

examples/client/status/status.go

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import (
66
"fmt"
77
"github.com/Raqbit/mcproto"
88
enc "github.com/Raqbit/mcproto/encoding"
9-
"github.com/Raqbit/mcproto/game"
109
"github.com/Raqbit/mcproto/packet"
1110
"log"
1211
"net"
@@ -43,27 +42,27 @@ func main() {
4342
log.Fatal(err)
4443
}
4544

46-
err = conn.WritePacket(&packet.HandshakePacket{
45+
err = conn.Write(&packet.HandshakePacket{
4746
ProtoVer: ProtocolVersion,
4847
ServerAddr: enc.String(host),
4948
ServerPort: enc.UnsignedShort(port),
50-
NextState: game.StatusState,
49+
NextState: mcproto.StatusState.ID(),
5150
})
5251

5352
// Actually update our connection as well
54-
conn.SetState(game.StatusState)
53+
conn.SetState(mcproto.StatusState)
5554

5655
if err != nil {
5756
log.Fatalf("could not write handshake packet: %s", err)
5857
}
5958

60-
err = conn.WritePacket(&packet.ServerQueryPacket{})
59+
err = conn.Write(&packet.ServerQueryPacket{})
6160

6261
if err != nil {
6362
log.Fatalf("could not write request packet: %s", err)
6463
}
6564

66-
resp, err := conn.ReadPacket()
65+
resp, err := conn.Read()
6766

6867
if err != nil {
6968
log.Fatalf("could not read response packet: %s", err)

0 commit comments

Comments
 (0)