add parsing tests to ls_structs

This commit is contained in:
Sky Johnson 2025-07-26 11:33:05 -05:00
parent 2912f871a5
commit 231f16e9de

View File

@ -0,0 +1,641 @@
package ls_structs
import (
"eq2emu/internal/packets/parser"
"testing"
)
func TestDeleteCharacterRequest(t *testing.T) {
// CharID=12345, ServerID=1, Unknown=0, Name="TestChar"
data := []byte{
0x39, 0x30, 0x00, 0x00, // CharID = 12345
0x01, 0x00, 0x00, 0x00, // ServerID = 1
0x00, 0x00, 0x00, 0x00, // Unknown = 0
0x08, 0x00, 'T', 'e', 's', 't', 'C', 'h', 'a', 'r', // Name = "TestChar"
}
parser := parser.NewParser(data)
var packet DeleteCharacterRequest
err := parser.ParseStruct(&packet)
if err != nil {
t.Fatalf("Parse error: %v", err)
}
if packet.CharID != 12345 {
t.Errorf("Expected CharID=12345, got %d", packet.CharID)
}
if packet.ServerID != 1 {
t.Errorf("Expected ServerID=1, got %d", packet.ServerID)
}
if packet.Name.Data != "TestChar" {
t.Errorf("Expected Name='TestChar', got '%s'", packet.Name.Data)
}
}
func TestDeleteCharacterResponse(t *testing.T) {
// Response=1, ServerID=1, CharID=12345, AccountID=54321, Name="TestChar", MaxCharacters=8
data := []byte{
0x01, // Response = 1
0x01, 0x00, 0x00, 0x00, // ServerID = 1
0x39, 0x30, 0x00, 0x00, // CharID = 12345
0x31, 0xD4, 0x00, 0x00, // AccountID = 54321
0x08, 0x00, 'T', 'e', 's', 't', 'C', 'h', 'a', 'r', // Name = "TestChar"
0x08, 0x00, 0x00, 0x00, // MaxCharacters = 8
}
parser := parser.NewParser(data)
var packet DeleteCharacterResponse
err := parser.ParseStruct(&packet)
if err != nil {
t.Fatalf("Parse error: %v", err)
}
if packet.Response != 1 {
t.Errorf("Expected Response=1, got %d", packet.Response)
}
if packet.CharID != 12345 {
t.Errorf("Expected CharID=12345, got %d", packet.CharID)
}
if packet.AccountID != 54321 {
t.Errorf("Expected AccountID=54321, got %d", packet.AccountID)
}
if packet.MaxCharacters != 8 {
t.Errorf("Expected MaxCharacters=8, got %d", packet.MaxCharacters)
}
}
func TestCreateCharacterReplyV1(t *testing.T) {
// AccountID=54321, Response=0, Name="NewChar"
data := []byte{
0x31, 0xD4, 0x00, 0x00, // AccountID = 54321
0x00, // Response = 0
0x07, 0x00, 'N', 'e', 'w', 'C', 'h', 'a', 'r', // Name = "NewChar"
}
parser := parser.NewParser(data)
var packet CreateCharacterReplyV1
err := parser.ParseStruct(&packet)
if err != nil {
t.Fatalf("Parse error: %v", err)
}
if packet.AccountID != 54321 {
t.Errorf("Expected AccountID=54321, got %d", packet.AccountID)
}
if packet.Response != 0 {
t.Errorf("Expected Response=0, got %d", packet.Response)
}
if packet.Name.Data != "NewChar" {
t.Errorf("Expected Name='NewChar', got '%s'", packet.Name.Data)
}
}
func TestCreateCharacterReplyV1189(t *testing.T) {
// AccountID=54321, Unknown=100, Response=0, Name="NewChar"
data := []byte{
0x31, 0xD4, 0x00, 0x00, // AccountID = 54321
0x64, 0x00, 0x00, 0x00, // Unknown = 100
0x00, // Response = 0
0x07, 0x00, 'N', 'e', 'w', 'C', 'h', 'a', 'r', // Name = "NewChar"
}
parser := parser.NewParser(data)
var packet CreateCharacterReplyV1189
err := parser.ParseStruct(&packet)
if err != nil {
t.Fatalf("Parse error: %v", err)
}
if packet.AccountID != 54321 {
t.Errorf("Expected AccountID=54321, got %d", packet.AccountID)
}
if packet.Unknown != 100 {
t.Errorf("Expected Unknown=100, got %d", packet.Unknown)
}
if packet.Response != 0 {
t.Errorf("Expected Response=0, got %d", packet.Response)
}
}
func TestLoginRequestV1(t *testing.T) {
data := []byte{
// SessionID = "session123"
0x0A, 0x00, 's', 'e', 's', 's', 'i', 'o', 'n', '1', '2', '3',
// SessionRecycleToken = "token456"
0x08, 0x00, 't', 'o', 'k', 'e', 'n', '4', '5', '6',
// Username = "testuser"
0x08, 0x00, 't', 'e', 's', 't', 'u', 's', 'e', 'r',
// Password = "testpass"
0x08, 0x00, 't', 'e', 's', 't', 'p', 'a', 's', 's',
0x31, 0xD4, 0x00, 0x00, // AcctNum = 54321
0x39, 0x30, 0x00, 0x00, // PassCode = 12345
0xDC, 0x05, // Version = 1500
}
parser := parser.NewParser(data)
var packet LoginRequestV1
err := parser.ParseStruct(&packet)
if err != nil {
t.Fatalf("Parse error: %v", err)
}
if packet.SessionID.Data != "session123" {
t.Errorf("Expected SessionID='session123', got '%s'", packet.SessionID.Data)
}
if packet.Username.Data != "testuser" {
t.Errorf("Expected Username='testuser', got '%s'", packet.Username.Data)
}
if packet.AcctNum != 54321 {
t.Errorf("Expected AcctNum=54321, got %d", packet.AcctNum)
}
if packet.Version != 1500 {
t.Errorf("Expected Version=1500, got %d", packet.Version)
}
}
func TestLoginByNumRequestV1(t *testing.T) {
data := []byte{
0x31, 0xD4, 0x00, 0x00, // AccountID = 54321
0x39, 0x30, 0x00, 0x00, // AccessCode = 12345
0xDC, 0x05, // Version = 1500
// Unknown2 = [1, 2, 3, 4, 5]
0x01, 0x00, 0x00, 0x00,
0x02, 0x00, 0x00, 0x00,
0x03, 0x00, 0x00, 0x00,
0x04, 0x00, 0x00, 0x00,
0x05, 0x00, 0x00, 0x00,
}
parser := parser.NewParser(data)
var packet LoginByNumRequestV1
err := parser.ParseStruct(&packet)
if err != nil {
t.Fatalf("Parse error: %v", err)
}
if packet.AccountID != 54321 {
t.Errorf("Expected AccountID=54321, got %d", packet.AccountID)
}
if packet.AccessCode != 12345 {
t.Errorf("Expected AccessCode=12345, got %d", packet.AccessCode)
}
if packet.Version != 1500 {
t.Errorf("Expected Version=1500, got %d", packet.Version)
}
if len(packet.Unknown2) != 5 {
t.Errorf("Expected Unknown2 length=5, got %d", len(packet.Unknown2))
}
if packet.Unknown2[0] != 1 || packet.Unknown2[4] != 5 {
t.Errorf("Expected Unknown2=[1,2,3,4,5], got %v", packet.Unknown2)
}
}
func TestPlayRequestV1(t *testing.T) {
data := []byte{
0x39, 0x30, 0x00, 0x00, // CharID = 12345
0x08, 0x00, 'T', 'e', 's', 't', 'C', 'h', 'a', 'r', // Name = "TestChar"
}
parser := parser.NewParser(data)
var packet PlayRequestV1
err := parser.ParseStruct(&packet)
if err != nil {
t.Fatalf("Parse error: %v", err)
}
if packet.CharID != 12345 {
t.Errorf("Expected CharID=12345, got %d", packet.CharID)
}
if packet.Name.Data != "TestChar" {
t.Errorf("Expected Name='TestChar', got '%s'", packet.Name.Data)
}
}
func TestPlayResponseV1(t *testing.T) {
data := []byte{
0x01, // Response = 1
0x09, '1', '2', '7', '.', '0', '.', '0', '.', '1', // Server = "127.0.0.1"
0xC4, 0x09, // Port = 2500
0x31, 0xD4, 0x00, 0x00, // AccountID = 54321
0x39, 0x30, 0x00, 0x00, // AccessCode = 12345
}
parser := parser.NewParser(data)
var packet PlayResponseV1
err := parser.ParseStruct(&packet)
if err != nil {
t.Fatalf("Parse error: %v", err)
}
if packet.Response != 1 {
t.Errorf("Expected Response=1, got %d", packet.Response)
}
if packet.Server.Data != "127.0.0.1" {
t.Errorf("Expected Server='127.0.0.1', got '%s'", packet.Server.Data)
}
if packet.Port != 2500 {
t.Errorf("Expected Port=2500, got %d", packet.Port)
}
if packet.AccountID != 54321 {
t.Errorf("Expected AccountID=54321, got %d", packet.AccountID)
}
}
func TestWorldListV1(t *testing.T) {
data := []byte{
0x02, // NumWorlds = 2
// World 1
0x01, 0x00, 0x00, 0x00, // ID = 1
0x07, 0x00, 'A', 'n', 't', 'o', 'n', 'i', 'a', // Name = "Antonia"
0x01, // Online = 1
0x00, // Locked = 0
0x00, // Unknown2 = 0
0x00, // Unknown3 = 0
0x32, // Load = 50
// World 2
0x02, 0x00, 0x00, 0x00, // ID = 2
0x08, 0x00, 'N', 'a', 'g', 'a', 'f', 'e', 'n', ' ', // Name = "Nagafen "
0x01, // Online = 1
0x01, // Locked = 1
0x00, // Unknown2 = 0
0x00, // Unknown3 = 0
0x64, // Load = 100
}
parser := parser.NewParser(data)
var packet WorldListV1
err := parser.ParseStruct(&packet)
if err != nil {
t.Fatalf("Parse error: %v", err)
}
if packet.NumWorlds != 2 {
t.Errorf("Expected NumWorlds=2, got %d", packet.NumWorlds)
}
if len(packet.WorldList) != 2 {
t.Errorf("Expected 2 worlds, got %d", len(packet.WorldList))
}
if packet.WorldList[0].Name.Data != "Antonia" {
t.Errorf("Expected first world 'Antonia', got '%s'", packet.WorldList[0].Name.Data)
}
if packet.WorldList[0].Online != 1 {
t.Errorf("Expected first world online=1, got %d", packet.WorldList[0].Online)
}
if packet.WorldList[1].Locked != 1 {
t.Errorf("Expected second world locked=1, got %d", packet.WorldList[1].Locked)
}
}
func TestWorldListV373(t *testing.T) {
data := []byte{
0x01, // NumWorlds = 1
// World 1
0x01, 0x00, 0x00, 0x00, // ID = 1
0x07, 0x00, 'A', 'n', 't', 'o', 'n', 'i', 'a', // Name = "Antonia"
0x01, // Tag = 1
0x00, // Locked = 0
0x00, // Hidden = 0
0x00, // Unknown = 0
0x64, 0x00, // NumPlayers = 100
0x32, // Load = 50
0x01, // NumberOnlineFlag = 1
0xFF, 0xFF, 0xFF, 0xFF, // AllowedRaces = 0xFFFFFFFF
}
parser := parser.NewParser(data)
var packet WorldListV373
err := parser.ParseStruct(&packet)
if err != nil {
t.Fatalf("Parse error: %v", err)
}
if packet.NumWorlds != 1 {
t.Errorf("Expected NumWorlds=1, got %d", packet.NumWorlds)
}
if packet.WorldList[0].NumPlayers != 100 {
t.Errorf("Expected NumPlayers=100, got %d", packet.WorldList[0].NumPlayers)
}
if packet.WorldList[0].AllowedRaces != 0xFFFFFFFF {
t.Errorf("Expected AllowedRaces=0xFFFFFFFF, got %d", packet.WorldList[0].AllowedRaces)
}
}
func TestLoginReplyMsgV1(t *testing.T) {
data := []byte{
0x00, // LoginResponse = 0 (success)
0x07, 0x00, 'A', 'n', 't', 'o', 'n', 'i', 'a', // WorldName = "Antonia"
0x00, // ParentalControlFlag = 0
0x00, 0x00, 0x00, 0x00, // ParentalControlTimer[0] = 0
0x00, 0x00, 0x00, 0x00, // ParentalControlTimer[1] = 0
0x00, 0x00, 0x00, 0x00, // ParentalControlNext = 0
0x31, 0xD4, 0x00, 0x00, // AccountID = 54321
}
parser := parser.NewParser(data)
var packet LoginReplyMsgV1
err := parser.ParseStruct(&packet)
if err != nil {
t.Fatalf("Parse error: %v", err)
}
if packet.LoginResponse != 0 {
t.Errorf("Expected LoginResponse=0, got %d", packet.LoginResponse)
}
if packet.WorldName.Data != "Antonia" {
t.Errorf("Expected WorldName='Antonia', got '%s'", packet.WorldName.Data)
}
if packet.AccountID != 54321 {
t.Errorf("Expected AccountID=54321, got %d", packet.AccountID)
}
}
func TestLoginReplyMsgV284WithClassItems(t *testing.T) {
data := []byte{
0x00, // LoginResponse = 0
0x07, 0x00, 'A', 'n', 't', 'o', 'n', 'i', 'a', // Unknown = "Antonia"
0x00, // ParentalControlFlag = 0
0x00, 0x00, 0x00, 0x00, // ParentalControlTimer = 0
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Unknown2 (8 bytes)
0x31, 0xD4, 0x00, 0x00, // CacheSettingAccountID = 54321
0x04, 0x00, 't', 'e', 's', 't', // Unknown3 = "test"
0x00, // ResetAppearance = 0
0x00, // DoNotForceSoga = 0
0x00, 0x00, // Unknown5 = 0
0x00, // Unknown6 = 0
0x00, 0x00, 0x00, 0x00, // Unknown7 = 0
0x00, 0x00, // Unknown8 (2 bytes)
0x01, // Unknown10 = 1 (truthy, so class items will be parsed)
0x01, // NumClassItems = 1
// ClassItem 1
0x05, // ClassID = 5
0x01, // NumItems = 1
// StartingItem 1
0x64, 0x00, // ModelID = 100
0x01, // SlotID = 1
0x01, // UseColor = 1
0x01, // UseHighlightColor = 1
0xFF, 0x00, 0x00, // ModelColor = Red
0x00, 0xFF, 0x00, // ModelHighlightColor = Green
0x00, // UnknownArray2Size = 0
}
parser := parser.NewParser(data)
var packet LoginReplyMsgV284
err := parser.ParseStruct(&packet)
if err != nil {
t.Fatalf("Parse error: %v", err)
}
if packet.LoginResponse != 0 {
t.Errorf("Expected LoginResponse=0, got %d", packet.LoginResponse)
}
if packet.CacheSettingAccountID != 54321 {
t.Errorf("Expected CacheSettingAccountID=54321, got %d", packet.CacheSettingAccountID)
}
if packet.Unknown10 != 1 {
t.Errorf("Expected Unknown10=1, got %d", packet.Unknown10)
}
if packet.NumClassItems != 1 {
t.Errorf("Expected NumClassItems=1, got %d", packet.NumClassItems)
}
if len(packet.ClassItems) != 1 {
t.Errorf("Expected 1 class item, got %d", len(packet.ClassItems))
}
if packet.ClassItems[0].ClassID != 5 {
t.Errorf("Expected ClassID=5, got %d", packet.ClassItems[0].ClassID)
}
if len(packet.ClassItems[0].StartingItems) != 1 {
t.Errorf("Expected 1 starting item, got %d", len(packet.ClassItems[0].StartingItems))
}
if packet.ClassItems[0].StartingItems[0].ModelID != 100 {
t.Errorf("Expected ModelID=100, got %d", packet.ClassItems[0].StartingItems[0].ModelID)
}
}
func TestLoginReplyMsgV284WithoutClassItems(t *testing.T) {
data := []byte{
0x00, // LoginResponse = 0
0x07, 0x00, 'A', 'n', 't', 'o', 'n', 'i', 'a', // Unknown = "Antonia"
0x00, // ParentalControlFlag = 0
0x00, 0x00, 0x00, 0x00, // ParentalControlTimer = 0
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Unknown2 (8 bytes)
0x31, 0xD4, 0x00, 0x00, // CacheSettingAccountID = 54321
0x04, 0x00, 't', 'e', 's', 't', // Unknown3 = "test"
0x00, // ResetAppearance = 0
0x00, // DoNotForceSoga = 0
0x00, 0x00, // Unknown5 = 0
0x00, // Unknown6 = 0
0x00, 0x00, 0x00, 0x00, // Unknown7 = 0
0x00, 0x00, // Unknown8 (2 bytes)
0x00, // Unknown10 = 0 (falsy, so class items will be skipped)
0x00, // UnknownArray2Size = 0
}
parser := parser.NewParser(data)
var packet LoginReplyMsgV284
err := parser.ParseStruct(&packet)
if err != nil {
t.Fatalf("Parse error: %v", err)
}
if packet.Unknown10 != 0 {
t.Errorf("Expected Unknown10=0, got %d", packet.Unknown10)
}
if packet.NumClassItems != 0 {
t.Errorf("Expected NumClassItems=0 (should be skipped), got %d", packet.NumClassItems)
}
if len(packet.ClassItems) != 0 {
t.Errorf("Expected 0 class items (should be skipped), got %d", len(packet.ClassItems))
}
}
func TestVersionRegistryWithLoginReplyMsg(t *testing.T) {
registry := parser.NewVersionRegistry()
RegisterLoginServerStructs(registry)
// Test data for LoginReplyMsgV1
data := []byte{
0x00, // LoginResponse = 0
0x07, 0x00, 'A', 'n', 't', 'o', 'n', 'i', 'a', // WorldName = "Antonia"
0x00, // ParentalControlFlag = 0
0x00, 0x00, 0x00, 0x00, // ParentalControlTimer[0] = 0
0x00, 0x00, 0x00, 0x00, // ParentalControlTimer[1] = 0
0x00, 0x00, 0x00, 0x00, // ParentalControlNext = 0
0x31, 0xD4, 0x00, 0x00, // AccountID = 54321
}
parser := parser.NewParser(data)
result, err := parser.ParseWithVersion(registry, "LoginReplyMsg", "1")
if err != nil {
t.Fatalf("Parse with version error: %v", err)
}
packet, ok := result.(LoginReplyMsgV1)
if !ok {
t.Fatal("Expected LoginReplyMsgV1 type")
}
if packet.LoginResponse != 0 {
t.Errorf("Expected LoginResponse=0, got %d", packet.LoginResponse)
}
if packet.WorldName.Data != "Antonia" {
t.Errorf("Expected WorldName='Antonia', got '%s'", packet.WorldName.Data)
}
}
func TestVersionRegistryFallback(t *testing.T) {
registry := parser.NewVersionRegistry()
RegisterLoginServerStructs(registry)
data := []byte{
0x39, 0x30, 0x00, 0x00, // CharID = 12345
0x08, 0x00, 'T', 'e', 's', 't', 'C', 'h', 'a', 'r', // Name = "TestChar"
}
parser := parser.NewParser(data)
// Request version 150 (doesn't exist), should fall back to version 1
result, err := parser.ParseWithVersion(registry, "PlayRequest", "150")
if err != nil {
t.Fatalf("Parse with fallback error: %v", err)
}
// Should get PlayRequestV1 (nearest lower version)
packet, ok := result.(PlayRequestV1)
if !ok {
t.Error("Expected fallback to PlayRequestV1")
}
if packet.CharID != 12345 {
t.Errorf("Expected CharID=12345, got %d", packet.CharID)
}
}
func TestWorldUpdate(t *testing.T) {
data := []byte{
0x01, 0x00, 0x00, 0x00, // ServerID = 1
0x01, // Up = 1
0x00, // Locked = 0
0x00, // Unknown1 = 0
0x32, // Unknown2 = 50
}
parser := parser.NewParser(data)
var packet WorldUpdate
err := parser.ParseStruct(&packet)
if err != nil {
t.Fatalf("Parse error: %v", err)
}
if packet.ServerID != 1 {
t.Errorf("Expected ServerID=1, got %d", packet.ServerID)
}
if packet.Up != 1 {
t.Errorf("Expected Up=1, got %d", packet.Up)
}
if packet.Locked != 0 {
t.Errorf("Expected Locked=0, got %d", packet.Locked)
}
}
func TestLoginResponseV60100WithComplexArrays(t *testing.T) {
data := []byte{
0x00, // LoginResponse = 0
0x07, 0x00, 'A', 'n', 't', 'o', 'n', 'i', 'a', // Unknown = "Antonia"
0x00, // ParentalControlFlag = 0
0x00, 0x00, 0x00, 0x00, // ParentalControlTimer = 0
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Unknown2 (8 bytes)
0x21, 0xD4, 0x00, 0x00, // AccountID = 54321
0x04, 0x00, 't', 'e', 's', 't', // Unknown3 = "test"
0x00, // ResetAppearance = 0
0x00, // DoNotForceSoga = 0
0x00, // Unknown4 = 0
0x00, 0x00, // Unknown5 = 0
0x00, 0x00, 0x00, 0x00, 0x00, // Unknown6 (5 bytes)
0x00, 0x00, 0x00, 0x00, // Unknown7 = 0
0x00, 0x00, // Unknown7a = 0
0x00, // RaceUnknown = 0
0x00, 0x00, 0x00, // Unknown8 (3 bytes)
0x00, 0x00, 0x00, // Unknown9 (3 bytes)
0x01, // Unknown10 = 1 (enables class items)
0x01, // NumClassItems = 1
// ClassItem 1
0x05, // ClassID = 5
0x01, // NumItems = 1
// StartingItem 1
0x64, 0x00, 0x00, 0x00, // ModelID = 100 (int32 in newer versions)
0x01, // SlotID = 1
0x01, // UseColor = 1
0x01, // UseHighlightColor = 1
0xFF, 0x00, 0x00, // ModelColor = Red
0x00, 0xFF, 0x00, // ModelHighlightColor = Green
0x00, // UnknownArray2Size = 0
0x00, 0x00, 0x00, 0x00, // Unknown11 = 0
0x00, 0x00, 0x00, 0x00, // SubLevel = 0
0xFF, 0xFF, 0xFF, 0xFF, // RaceFlag = 0xFFFFFFFF
0xFF, 0xFF, 0xFF, 0xFF, // ClassFlag = 0xFFFFFFFF
0x08, 0x00, 't', 'e', 's', 't', 'p', 'a', 's', 's', // Password = "testpass"
0x08, 0x00, 't', 'e', 's', 't', 'u', 's', 'e', 'r', // Username = "testuser"
0x07, 0x00, 's', 'e', 'r', 'v', 'i', 'c', 'e', // Service = "service"
0x01, // Unknown12 = 1 (enables Lvl90 class items)
0x01, // Lvl90NumClassItems = 1
// Lvl90 ClassItem 1
0x06, // ClassID = 6
0x01, // NumItems = 1
// StartingItem 1
0x65, 0x00, 0x00, 0x00, // ModelID = 101
0x02, // SlotID = 2
0x01, // UseColor = 1
0x01, // UseHighlightColor = 1
0x00, 0xFF, 0x00, // ModelColor = Green
0xFF, 0x00, 0x00, // ModelHighlightColor = Red
0x01, // Unknown13 = 1 (enables TimeLocked class items)
0x01, // TimeLockedNumClassItems = 1
// TimeLocked ClassItem 1
0x07, // ClassID = 7
0x01, // NumItems = 1
// StartingItem 1
0x66, 0x00, 0x00, 0x00, // ModelID = 102
0x03, // SlotID = 3
0x00, // UseColor = 0
0x00, // UseHighlightColor = 0
0x80, 0x80, 0x80, // ModelColor = Gray
0x40, 0x40, 0x40, // ModelHighlightColor = Dark gray
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Unknown14 (13 bytes)
}
parser := parser.NewParser(data)
var packet LoginResponseV60100
err := parser.ParseStruct(&packet)
if err != nil {
t.Fatalf("Parse error: %v", err)
}
// Test main class items
if len(packet.ClassItems) != 1 {
t.Errorf("Expected 1 class item, got %d", len(packet.ClassItems))
}
if packet.ClassItems[0].ClassID != 5 {
t.Errorf("Expected ClassID=5, got %d", packet.ClassItems[0].ClassID)
}
// Test Lvl90 class items
if len(packet.Lvl90ClassItems) != 1 {
t.Errorf("Expected 1 Lvl90 class item, got %d", len(packet.Lvl90ClassItems))
}
if packet.Lvl90ClassItems[0].ClassID != 6 {
t.Errorf("Expected Lvl90 ClassID=6, got %d", packet.Lvl90ClassItems[0].ClassID)
}
// Test TimeLocked class items
if len(packet.TimeLockedClassItems) != 1 {
t.Errorf("Expected 1 TimeLocked class item, got %d", len(packet.TimeLockedClassItems))
}
if packet.TimeLockedClassItems[0].ClassID != 7 {
t.Errorf("Expected TimeLocked ClassID=7, got %d", packet.TimeLockedClassItems[0].ClassID)
}
if packet.RaceFlag != 0xFFFFFFFF {
t.Errorf("Expected RaceFlag=0xFFFFFFFF, got %d", packet.RaceFlag)
}
}