-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathplayer.go
168 lines (162 loc) · 4.76 KB
/
player.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
package main
import (
"fmt"
"io"
"time"
)
type Player struct {
session *Session
username string
password string
/* TODO: A lot of player data goes here. */
}
/**
* Detect if Player connection has been reset by peer.
*
* Side-effect: If the connection isn't closed, set the
* default read timeout to 1 minute.
*
* @return {true} if connection isn't closed, otherwise {false}
*/
func (self Player) isConnected() bool {
one := []byte{}
self.session.conn.SetReadDeadline(time.Now())
if _, err := self.session.conn.Read(one); err == io.EOF {
fmt.Printf("Connection closed for %s\n", self.session)
self.session.conn.Close()
self.session.conn = nil
return false
} else {
self.session.conn.SetReadDeadline(time.Now().Add(60 * time.Second))
}
return true
}
/**
* This is the main loop that each player has for processing
* incoming packets. It reads from their {Session}'s connection
* buffer, and attempts to decode packet frames from the data it
* reads.
*
* If a packet frame is detected and successfully decoded, then
* it is passed to a {PacketHandler} instance that belongs to this
* {Player}, to perform whatever actions that packet is intended to.
*
* If the connection times out, or is closed by other means,
* the loop will end, and the players {Session}'s connection
* will be set to nil.
*
* TODO: Possibly add more processing to this loop.
* TODO: Handle errors while decoding frames more gracefully?
* That is to say, I don't believe we should end the {Session}
* because of a malformed packet frame. Maybe just log it.
*/
func (self Player) process() {
ph := NewPacketHandler(self)
for {
// End player process routine if the peer closed connection
if !self.isConnected() {
break
}
buffer := make([]byte, 3)
bytesRead, err := self.session.conn.Read(buffer)
// Connection reset by peer
if err == io.EOF {
fmt.Printf("Connection closed for %s\n", self.session)
self.session.conn.Close()
self.session.conn = nil
break
} else if err != nil || bytesRead < 3 {
// The header for every packet is minimum 2 bytes for raw packets, 3 for frames
continue
}
// position we're reading at in the buffer
caret := 0
/**
* Start by reading the packet frames length.
* The length is held in a Jagex-specific data type,
* commonly referred to as a SmartInt.
*
* If the length is less than 160, the length is held
* in a single byte, the first byte of the frame, and
* the second byte of the frame is given value of the last
* byte to be read in the frame.
*
* If the length is 160 or more, the length is held
* in the first 2 bytes of the frame, forming a
* short integer(16 bits).
*
* I imagine Jagex made this SmartInt type to
* save bandwidth, as this is a circa-2001 MMORPG.
* This type is unsigned.
*/
length := int(buffer[caret] & 0xFF)
caret++
var lastByte uint8 = 0
/**
* Here we check if it's encoded as a short integer.
* Any length of 160 or over should be encoded to
* a short integer.
*/
fmt.Println("Length:",length)
if length >= 160 {
length = (length-160)*256 + int(buffer[caret]&0xFF)
caret++
} else if length > 1 {
lastByte = uint8(buffer[caret])
caret++
length--
}
opcode := uint8(buffer[caret] & 0xFF)
caret++
length--
buffer = make([]byte, length)
bytesRead, err = self.session.conn.Read(buffer)
// Connection reset by peer
if err == io.EOF {
fmt.Printf("Connection closed for %s\n", self.session)
self.session.conn.Close()
self.session.conn = nil
break
} else if err != nil || bytesRead < length {
fmt.Printf("packet read error:invalid length; expected %d, got %d\n", length, bytesRead)
continue
}
fmt.Printf("%d\n", length)
caret = 0
/**
* If the packet frame is a byte, the second byte
* written to the buffer is the last byte of the packet
* frame. I can't be sure why they did this, yet.
*/
// var lastByte uint8 = 0
// if length < 160 && length > 1 {
// lastByte = uint8(buffer[caret])
// caret++
// length--
// }
if length < 160 && length > 0 {
// buffer[length] = lastByte
tmpBuffer := make([]byte, length + 1)
for i := 0; i < length; i++ {
tmpBuffer[i] = buffer[i]
}
tmpBuffer[length] = lastByte
p := NewPacket(opcode, length, tmpBuffer)
ph.HandlePacket(&p)
} else if length == 0 {
buffer = []byte{lastByte}
p := NewPacket(opcode, length, buffer)
ph.HandlePacket(&p)
} else {
p := NewPacket(opcode, length, buffer)
ph.HandlePacket(&p)
}
// p := NewPacket(opcode, length, buffer)
/* TODO: Maybe goroutine for handling packets, to read next one instantly? */
// ph.HandlePacket(&p)
}
}
func NewPlayer(session *Session, username string, password string) Player {
p := Player{session, username, password}
return p
}