1
0

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
}