220 lines
5.7 KiB
Go
220 lines
5.7 KiB
Go
package packets
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"math"
|
|
)
|
|
|
|
// Message type constants
|
|
const (
|
|
// Login server messages
|
|
MSG_LOGIN_REQUEST = 0x20
|
|
MSG_REGISTER_REQUEST = 0x21
|
|
MSG_LOGIN_RESPONSE = 0x22
|
|
|
|
// World server messages
|
|
MSG_AUTH = 0x30
|
|
MSG_AUTH_RESPONSE = 0x31
|
|
MSG_SPAWN = 0x03
|
|
MSG_MOVE = 0x04
|
|
MSG_UPDATE = 0x05
|
|
MSG_PLAYER_JOINED = 0x06
|
|
MSG_PLAYER_LEFT = 0x07
|
|
MSG_PLAYER_LIST = 0x08
|
|
MSG_HEARTBEAT = 0x0D
|
|
MSG_TIME_SYNC = 0x0E
|
|
MSG_LOGOUT = 0x0C
|
|
)
|
|
|
|
// EncodeLoginResponse creates a login response packet
|
|
func EncodeLoginResponse(success bool, token []byte, worldHost string, worldPort uint16, playerID uint32, message string) []byte {
|
|
msgBytes := []byte(message)
|
|
hostBytes := []byte(worldHost)
|
|
|
|
// Calculate total size
|
|
size := 1 + 1 + 1 + len(msgBytes) // type + success + msgLen + message
|
|
if success {
|
|
size += 32 + 1 + len(hostBytes) + 2 + 4 // token + hostLen + host + port + playerID
|
|
}
|
|
|
|
msg := make([]byte, size)
|
|
offset := 0
|
|
|
|
msg[offset] = MSG_LOGIN_RESPONSE
|
|
offset++
|
|
|
|
if success {
|
|
msg[offset] = 1
|
|
} else {
|
|
msg[offset] = 0
|
|
}
|
|
offset++
|
|
|
|
msg[offset] = uint8(len(msgBytes))
|
|
offset++
|
|
copy(msg[offset:], msgBytes)
|
|
offset += len(msgBytes)
|
|
|
|
if success {
|
|
copy(msg[offset:offset+32], token)
|
|
offset += 32
|
|
|
|
msg[offset] = uint8(len(hostBytes))
|
|
offset++
|
|
copy(msg[offset:], hostBytes)
|
|
offset += len(hostBytes)
|
|
|
|
binary.LittleEndian.PutUint16(msg[offset:], worldPort)
|
|
offset += 2
|
|
|
|
binary.LittleEndian.PutUint32(msg[offset:], playerID)
|
|
}
|
|
|
|
return msg
|
|
}
|
|
|
|
// DecodeLoginRequest decodes a login request packet
|
|
func DecodeLoginRequest(data []byte) (username, password string, ok bool) {
|
|
if len(data) < 3 {
|
|
return "", "", false
|
|
}
|
|
|
|
offset := 1 // Skip message type
|
|
|
|
usernameLen := data[offset]
|
|
offset++
|
|
if len(data) < offset+int(usernameLen)+1 {
|
|
return "", "", false
|
|
}
|
|
username = string(data[offset : offset+int(usernameLen)])
|
|
offset += int(usernameLen)
|
|
|
|
passwordLen := data[offset]
|
|
offset++
|
|
if len(data) < offset+int(passwordLen) {
|
|
return "", "", false
|
|
}
|
|
password = string(data[offset : offset+int(passwordLen)])
|
|
|
|
return username, password, true
|
|
}
|
|
|
|
// DecodeRegisterRequest decodes a register request packet
|
|
func DecodeRegisterRequest(data []byte) (username, password string, ok bool) {
|
|
// Same format as login request
|
|
return DecodeLoginRequest(data)
|
|
}
|
|
|
|
// EncodeAuthResponse creates an auth response packet
|
|
func EncodeAuthResponse(success bool, message string) []byte {
|
|
msgBytes := []byte(message)
|
|
msg := make([]byte, 3+len(msgBytes))
|
|
|
|
msg[0] = MSG_AUTH_RESPONSE
|
|
if success {
|
|
msg[1] = 1
|
|
} else {
|
|
msg[1] = 0
|
|
}
|
|
msg[2] = uint8(len(msgBytes))
|
|
copy(msg[3:], msgBytes)
|
|
|
|
return msg
|
|
}
|
|
|
|
// DecodeAuth decodes an auth packet with token
|
|
func DecodeAuth(data []byte) (token []byte, ok bool) {
|
|
if len(data) < 33 { // 1 byte type + 32 byte token
|
|
return nil, false
|
|
}
|
|
|
|
token = make([]byte, 32)
|
|
copy(token, data[1:33])
|
|
return token, true
|
|
}
|
|
|
|
// EncodeSpawnPacket creates a spawn packet
|
|
func EncodeSpawnPacket(playerID uint32, position Vec3) []byte {
|
|
msg := make([]byte, 17)
|
|
msg[0] = MSG_SPAWN
|
|
binary.LittleEndian.PutUint32(msg[1:5], playerID)
|
|
binary.LittleEndian.PutUint32(msg[5:9], math.Float32bits(position.X))
|
|
binary.LittleEndian.PutUint32(msg[9:13], math.Float32bits(position.Y))
|
|
binary.LittleEndian.PutUint32(msg[13:17], math.Float32bits(position.Z))
|
|
return msg
|
|
}
|
|
|
|
// EncodeUpdatePacket creates an update packet
|
|
func EncodeUpdatePacket(playerID uint32, position Vec3) []byte {
|
|
msg := make([]byte, 17)
|
|
msg[0] = MSG_UPDATE
|
|
binary.LittleEndian.PutUint32(msg[1:5], playerID)
|
|
binary.LittleEndian.PutUint32(msg[5:9], math.Float32bits(position.X))
|
|
binary.LittleEndian.PutUint32(msg[9:13], math.Float32bits(position.Y))
|
|
binary.LittleEndian.PutUint32(msg[13:17], math.Float32bits(position.Z))
|
|
return msg
|
|
}
|
|
|
|
// EncodePlayerJoinedPacket creates a player joined packet
|
|
func EncodePlayerJoinedPacket(playerID uint32, position Vec3, username string) []byte {
|
|
usernameBytes := []byte(username)
|
|
msg := make([]byte, 18+len(usernameBytes))
|
|
msg[0] = MSG_PLAYER_JOINED
|
|
binary.LittleEndian.PutUint32(msg[1:5], playerID)
|
|
binary.LittleEndian.PutUint32(msg[5:9], math.Float32bits(position.X))
|
|
binary.LittleEndian.PutUint32(msg[9:13], math.Float32bits(position.Y))
|
|
binary.LittleEndian.PutUint32(msg[13:17], math.Float32bits(position.Z))
|
|
msg[17] = uint8(len(usernameBytes))
|
|
copy(msg[18:], usernameBytes)
|
|
return msg
|
|
}
|
|
|
|
// EncodePlayerLeftPacket creates a player left packet
|
|
func EncodePlayerLeftPacket(playerID uint32) []byte {
|
|
msg := make([]byte, 5)
|
|
msg[0] = MSG_PLAYER_LEFT
|
|
binary.LittleEndian.PutUint32(msg[1:5], playerID)
|
|
return msg
|
|
}
|
|
|
|
// EncodeTimeSyncPacket creates a time sync packet
|
|
func EncodeTimeSyncPacket(timeOfDay float32) []byte {
|
|
msg := make([]byte, 5)
|
|
msg[0] = MSG_TIME_SYNC
|
|
binary.LittleEndian.PutUint32(msg[1:5], math.Float32bits(timeOfDay))
|
|
return msg
|
|
}
|
|
|
|
// DecodeMovePacket decodes a move packet
|
|
func DecodeMovePacket(data []byte) (playerID uint32, delta Vec3, ok bool) {
|
|
if len(data) < 17 {
|
|
return 0, Vec3{}, false
|
|
}
|
|
|
|
playerID = binary.LittleEndian.Uint32(data[1:5])
|
|
delta.X = math.Float32frombits(binary.LittleEndian.Uint32(data[5:9]))
|
|
delta.Y = math.Float32frombits(binary.LittleEndian.Uint32(data[9:13]))
|
|
delta.Z = math.Float32frombits(binary.LittleEndian.Uint32(data[13:17]))
|
|
|
|
return playerID, delta, true
|
|
}
|
|
|
|
// DecodeHeartbeatPacket decodes a heartbeat packet
|
|
func DecodeHeartbeatPacket(data []byte) (playerID uint32, ok bool) {
|
|
if len(data) < 5 {
|
|
return 0, false
|
|
}
|
|
|
|
playerID = binary.LittleEndian.Uint32(data[1:5])
|
|
return playerID, true
|
|
}
|
|
|
|
// DecodeLogoutPacket decodes a logout packet
|
|
func DecodeLogoutPacket(data []byte) (playerID uint32, ok bool) {
|
|
if len(data) < 5 {
|
|
return 0, false
|
|
}
|
|
|
|
playerID = binary.LittleEndian.Uint32(data[1:5])
|
|
return playerID, true
|
|
} |