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 ) // 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 }