...

Source file src/go.formulabun.club/srb2kart/network/info/info.go

Documentation: go.formulabun.club/srb2kart/network/info

     1  package info
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/binary"
     6  	"fmt"
     7  
     8  	"go.formulabun.club/functional/strings"
     9  )
    10  
    11  var GetServerInfoPacket = [...]byte{
    12  	0x58, 0x46, 0x23, 0x01,
    13  	0x00,
    14  	0x00,
    15  	0x0C,
    16  	0x00,
    17  
    18  	0x01,
    19  	0x1f, 0x02, 0x00, 0x00,
    20  }
    21  
    22  type PacketType uint8
    23  
    24  const (
    25  	PacketTypeServerInfo PacketType = 0x0D
    26  	PacketTypePlayerInfo PacketType = 0x0E
    27  )
    28  
    29  type packetHeader struct {
    30  	Checksum   uint32
    31  	Ack        uint8
    32  	Ackret     uint8
    33  	PacketType PacketType
    34  	_          [1]byte
    35  }
    36  
    37  type serverInfoPacketRaw struct {
    38  	Header         packetHeader
    39  	_              uint8 // 255 field
    40  	PacketVersion  uint8
    41  	Application    [16]byte
    42  	Version        uint8
    43  	SubVersion     uint8
    44  	NumberOfPlayer uint8
    45  	MaxPlayers     uint8
    46  	GameType       uint8
    47  	ModifiedGame   bool
    48  	CheatsEnabled  bool
    49  	KartVars       uint8
    50  	FileNeededNum  uint8
    51  	Time           uint32
    52  	LevelTime      uint32
    53  	ServerName     [32]byte
    54  	MapName        [8]byte
    55  	MapTitle       [33]byte
    56  	MapMD5         [16]uint8
    57  	ActNum         uint8
    58  	IsZone         uint8
    59  	HttpSource     [256]byte
    60  	FileNeeded     [915]uint8
    61  }
    62  
    63  type ServerInfoPacket struct {
    64  	header         packetHeader
    65  	PacketVersion  uint8
    66  	Application    [16]byte
    67  	Version        uint8
    68  	SubVersion     uint8
    69  	NumberOfPlayer uint8
    70  	MaxPlayers     uint8
    71  	GameType       uint8
    72  	ModifiedGame   bool
    73  	CheatsEnabled  bool
    74  	KartVars       uint8
    75  	FileNeededNum  uint8
    76  	Time           uint32
    77  	LevelTime      uint32
    78  	ServerNameRaw  []byte
    79  	ServerName     string
    80  	MapName        string
    81  	MapTitle       string
    82  	MapMD5         [16]uint8
    83  	ActNum         uint8
    84  	IsZone         uint8
    85  	HttpSource     string
    86  	FileNeeded     []FileNeededEntry
    87  }
    88  
    89  func (p ServerInfoPacket) GetPacketType() PacketType {
    90  	return p.header.PacketType
    91  }
    92  
    93  type playerInfoPacketRaw struct {
    94  	Header     packetHeader
    95  	PlayerInfo [32]playerInfoEntryRaw
    96  }
    97  
    98  type playerInfoEntryRaw struct {
    99  	Node         uint8
   100  	Name         [21 + 1]byte
   101  	Address      [4]uint8
   102  	Team         uint8
   103  	Skin         uint8
   104  	Data         uint8
   105  	Score        uint32
   106  	TimeInServer uint16
   107  }
   108  
   109  type PlayerInfoPacket struct {
   110  	header     packetHeader
   111  	PlayerInfo []PlayerInfoEntry
   112  }
   113  
   114  func (p PlayerInfoPacket) GetPacketType() PacketType {
   115  	return p.header.PacketType
   116  }
   117  
   118  type PlayerInfoEntry struct {
   119  	Node         uint8
   120  	Name         string
   121  	Address      [4]uint8
   122  	Team         uint8
   123  	Skin         uint8
   124  	Data         uint8
   125  	Score        uint32
   126  	TimeInServer uint16
   127  }
   128  
   129  type packet interface {
   130  	GetPacketType() PacketType
   131  }
   132  
   133  type FileNeededEntry struct {
   134  	WillSend  bool
   135  	TotalSize uint32
   136  	FileName  string
   137  	MD5       [16]uint8
   138  }
   139  
   140  func ParsePacket(data []byte) (packet, error) {
   141  	header := packetHeader{}
   142  	if err := binary.Read(bytes.NewReader(data), binary.LittleEndian, &header); err != nil {
   143  		return nil, err
   144  	}
   145  
   146  	switch header.PacketType {
   147  	case PacketTypeServerInfo:
   148  		return parseServerInfoPacket(data)
   149  	case PacketTypePlayerInfo:
   150  		return parsePlayerInfoPacket(data)
   151  	default:
   152  		return nil, fmt.Errorf("unknown packet type: %d", header.PacketType)
   153  	}
   154  }
   155  
   156  func parseFileNeeded(data []byte, fileNeededCount int) []FileNeededEntry {
   157  	var entries []FileNeededEntry
   158  	buf := bytes.NewBuffer(data[:])
   159  	for i := 0; i < fileNeededCount; i++ {
   160  		entry := FileNeededEntry{}
   161  		binary.Read(buf, binary.LittleEndian, &entry.WillSend)
   162  		b, _ := buf.ReadByte()
   163  		entry.WillSend = (b >> 4) == 1
   164  		binary.Read(buf, binary.LittleEndian, &entry.TotalSize)
   165  		entry.FileName, _ = buf.ReadString(0)
   166  		// Trim off the null terminator
   167  		entry.FileName = entry.FileName[:len(entry.FileName)-1]
   168  		binary.Read(buf, binary.LittleEndian, &entry.MD5)
   169  		entries = append(entries, entry)
   170  	}
   171  	return entries
   172  }
   173  
   174  func parseServerInfoPacket(data []byte) (ServerInfoPacket, error) {
   175  	var packetRaw serverInfoPacketRaw
   176  	if err := binary.Read(bytes.NewReader(data), binary.LittleEndian, &packetRaw); err != nil {
   177  		return ServerInfoPacket{}, fmt.Errorf("failed to unpack server info packet: %v", err)
   178  	}
   179  	packet := ServerInfoPacket{
   180  		header:         packetRaw.Header,
   181  		PacketVersion:  packetRaw.PacketVersion,
   182  		Application:    packetRaw.Application,
   183  		Version:        packetRaw.Version,
   184  		SubVersion:     packetRaw.SubVersion,
   185  		NumberOfPlayer: packetRaw.NumberOfPlayer,
   186  		MaxPlayers:     packetRaw.MaxPlayers,
   187  		GameType:       packetRaw.GameType,
   188  		ModifiedGame:   packetRaw.ModifiedGame,
   189  		CheatsEnabled:  packetRaw.CheatsEnabled,
   190  		KartVars:       packetRaw.KartVars,
   191  		FileNeededNum:  packetRaw.FileNeededNum,
   192  		Time:           packetRaw.Time,
   193  		LevelTime:      packetRaw.LevelTime,
   194  		ServerNameRaw: strings.NullTerminated(packetRaw.ServerName[:]),
   195  		ServerName:     strings.SafeNullTerminated(packetRaw.ServerName[:]),
   196  		MapName:        strings.SafeNullTerminated(packetRaw.MapName[:]),
   197  		MapTitle:       strings.SafeNullTerminated(packetRaw.MapTitle[:]),
   198  		MapMD5:         packetRaw.MapMD5,
   199  		ActNum:         packetRaw.ActNum,
   200  		IsZone:         packetRaw.IsZone,
   201  		HttpSource:     strings.SafeNullTerminated(packetRaw.HttpSource[:]),
   202  		FileNeeded:     parseFileNeeded(packetRaw.FileNeeded[:], int(packetRaw.FileNeededNum)),
   203  	}
   204  	return packet, nil
   205  }
   206  
   207  func parsePlayerInfoPacket(data []byte) (PlayerInfoPacket, error) {
   208  	var packetRaw playerInfoPacketRaw
   209  	if err := binary.Read(bytes.NewReader(data), binary.LittleEndian, &packetRaw); err != nil {
   210  		return PlayerInfoPacket{}, fmt.Errorf("failed to unpack playerinfo packet: %w", err)
   211  	}
   212  	packet := PlayerInfoPacket{
   213  		header: packetRaw.Header,
   214  	}
   215  	for i := 0; i < len(packetRaw.PlayerInfo); i++ {
   216  		// Skin nodes if they are not used
   217  		if packetRaw.PlayerInfo[i].Node == 255 {
   218  			continue
   219  		}
   220  		entry := packetRaw.PlayerInfo[i]
   221  		packet.PlayerInfo = append(packet.PlayerInfo, PlayerInfoEntry{
   222  			Node: entry.Node,
   223  			Name: strings.SafeNullTerminated(entry.Name[:]),
   224  			Address: [4]uint8{
   225  				entry.Address[0],
   226  				entry.Address[1],
   227  				entry.Address[2],
   228  				entry.Address[3],
   229  			},
   230  			Team:         entry.Team,
   231  			Skin:         entry.Skin,
   232  			Data:         entry.Data,
   233  			Score:        entry.Score,
   234  			TimeInServer: entry.TimeInServer,
   235  		})
   236  	}
   237  	return packet, nil
   238  }
   239  

View as plain text