206 lines
5.6 KiB
Go
206 lines
5.6 KiB
Go
package net
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"math"
|
|
)
|
|
|
|
// Message type constants
|
|
const (
|
|
MSG_LOGIN = 0x01
|
|
MSG_POSITION = 0x02
|
|
MSG_SPAWN = 0x03
|
|
MSG_MOVE = 0x04
|
|
MSG_UPDATE = 0x05
|
|
MSG_PLAYER_JOINED = 0x06
|
|
MSG_PLAYER_LEFT = 0x07
|
|
MSG_PLAYER_LIST = 0x08
|
|
MSG_CHANGE_COLOR = 0x09
|
|
MSG_COLOR_CHANGED = 0x0A
|
|
MSG_LOGIN_RESPONSE = 0x0B
|
|
MSG_LOGOUT = 0x0C
|
|
MSG_HEARTBEAT = 0x0D
|
|
MSG_TIME_SYNC = 0x0E
|
|
)
|
|
|
|
// Vec3 represents a 3D vector
|
|
type Vec3 struct {
|
|
X, Y, Z float32
|
|
}
|
|
|
|
// EncodeSpawnPacket creates a spawn packet
|
|
func EncodeSpawnPacket(playerID uint32, position Vec3, color string) []byte {
|
|
colorBytes := []byte(color)
|
|
msg := make([]byte, 18+len(colorBytes))
|
|
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))
|
|
msg[17] = uint8(len(colorBytes))
|
|
copy(msg[18:], colorBytes)
|
|
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, color string) []byte {
|
|
colorBytes := []byte(color)
|
|
msg := make([]byte, 18+len(colorBytes))
|
|
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(colorBytes))
|
|
copy(msg[18:], colorBytes)
|
|
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
|
|
}
|
|
|
|
// EncodeColorChangedPacket creates a color changed packet
|
|
func EncodeColorChangedPacket(playerID uint32, color string) []byte {
|
|
colorBytes := []byte(color)
|
|
msg := make([]byte, 6+len(colorBytes))
|
|
msg[0] = MSG_COLOR_CHANGED
|
|
binary.LittleEndian.PutUint32(msg[1:5], playerID)
|
|
msg[5] = uint8(len(colorBytes))
|
|
copy(msg[6:], colorBytes)
|
|
return msg
|
|
}
|
|
|
|
// EncodePlayerListPacket creates a player list packet
|
|
func EncodePlayerListPacket(players []*Player) []byte {
|
|
if len(players) == 0 {
|
|
return []byte{MSG_PLAYER_LIST, 0}
|
|
}
|
|
|
|
msg := make([]byte, 1024)
|
|
msg[0] = MSG_PLAYER_LIST
|
|
msg[1] = uint8(len(players))
|
|
|
|
offset := 2
|
|
for _, p := range players {
|
|
binary.LittleEndian.PutUint32(msg[offset:], p.ID)
|
|
binary.LittleEndian.PutUint32(msg[offset+4:], math.Float32bits(p.Position.X))
|
|
binary.LittleEndian.PutUint32(msg[offset+8:], math.Float32bits(p.Position.Y))
|
|
binary.LittleEndian.PutUint32(msg[offset+12:], math.Float32bits(p.Position.Z))
|
|
|
|
colorBytes := []byte(p.Color)
|
|
msg[offset+16] = uint8(len(colorBytes))
|
|
copy(msg[offset+17:], colorBytes)
|
|
|
|
offset += 17 + len(colorBytes)
|
|
if offset > 1000 {
|
|
break // Prevent overflow
|
|
}
|
|
}
|
|
|
|
return msg[:offset]
|
|
}
|
|
|
|
// 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
|
|
}
|
|
|
|
// DecodeColorChangePacket decodes a color change packet
|
|
func DecodeColorChangePacket(data []byte) (playerID uint32, color string, ok bool) {
|
|
if len(data) < 6 {
|
|
return 0, "", false
|
|
}
|
|
|
|
playerID = binary.LittleEndian.Uint32(data[1:5])
|
|
colorLen := data[5]
|
|
|
|
if len(data) < 6+int(colorLen) {
|
|
return 0, "", false
|
|
}
|
|
|
|
color = string(data[6 : 6+colorLen])
|
|
return playerID, color, true
|
|
}
|
|
|
|
// EncodeLoginResponsePacket creates a login response packet
|
|
func EncodeLoginResponsePacket(success bool, message string) []byte {
|
|
msgBytes := []byte(message)
|
|
msg := make([]byte, 3+len(msgBytes))
|
|
msg[0] = MSG_LOGIN_RESPONSE
|
|
if success {
|
|
msg[1] = 1
|
|
} else {
|
|
msg[1] = 0
|
|
}
|
|
msg[2] = uint8(len(msgBytes))
|
|
copy(msg[3:], msgBytes)
|
|
return msg
|
|
}
|
|
|
|
// DecodeLoginPacket decodes a login packet with username
|
|
func DecodeLoginPacket(data []byte) (username string, ok bool) {
|
|
if len(data) < 2 {
|
|
return "", false
|
|
}
|
|
|
|
usernameLen := data[1]
|
|
if len(data) < 2+int(usernameLen) {
|
|
return "", false
|
|
}
|
|
|
|
username = string(data[2 : 2+usernameLen])
|
|
return username, 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
|
|
}
|
|
|
|
// 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
|
|
}
|
|
|
|
// 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
|
|
} |