package eq2net import ( "fmt" ) // LoginEmuOpcode represents emulator opcodes for the login server type LoginEmuOpcode uint16 // Login server emulator opcodes const ( LOP_Unknown LoginEmuOpcode = iota LOP_LoginRequestMsg LOP_LoginByNumRequestMsg LOP_WSLoginRequestMsg LOP_ESLoginRequestMsg LOP_LoginReplyMsg LOP_WorldListMsg LOP_WorldStatusChangeMsg LOP_AllWSDescRequestMsg LOP_WSStatusReplyMsg LOP_AllCharactersDescRequestMsg LOP_AllCharactersDescReplyMsg LOP_CreateCharacterRequestMsg LOP_ReskinCharacterRequestMsg LOP_CreateCharacterReplyMsg LOP_WSCreateCharacterRequestMsg LOP_WSCreateCharacterReplyMsg LOP_DeleteCharacterRequestMsg LOP_DeleteCharacterReplyMsg LOP_PlayCharacterRequestMsg LOP_PlayCharacterReplyMsg LOP_ServerPlayCharacterRequestMsg LOP_ServerPlayCharacterReplyMsg LOP_KeymapLoadMsg LOP_KeymapNoneMsg LOP_KeymapDataMsg LOP_KeymapSaveMsg LOP_LSCheckAcctLockMsg LOP_WSAcctLockStatusMsg LOP_LsRequestClientCrashLogMsg LOP_LsClientBaselogReplyMsg LOP_LsClientCrashlogReplyMsg LOP_LsClientAlertlogReplyMsg LOP_LsClientVerifylogReplyMsg LOP_BadLanguageFilter LOP_WSServerLockMsg LOP_WSServerHideMsg LOP_LSServerLockMsg LOP_UpdateCharacterSheetMsg LOP_UpdateInventoryMsg LOP_MaxLoginOpcode ) // LoginPacket represents a login server packet type LoginPacket struct { EQPacket // Embed base packet LoginEmuOpcode LoginEmuOpcode // Login server emulator opcode } // NewLoginPacket creates a new login server packet func NewLoginPacket(opcode LoginEmuOpcode, data []byte) *LoginPacket { base := NewEQPacket(uint16(opcode), data) base.EmuOpcode = uint16(opcode) base.OpcodeSize = 1 // Login server uses 1-byte opcodes p := &LoginPacket{ EQPacket: *base, LoginEmuOpcode: opcode, } return p } // ParseLoginPacket creates a login packet from raw data func ParseLoginPacket(data []byte) (*LoginPacket, error) { if len(data) < 1 { return nil, fmt.Errorf("packet too small for login opcode") } // Extract 1-byte opcode opcode := LoginEmuOpcode(data[0]) // Create packet with remaining data base := NewEQPacket(uint16(opcode), data[1:]) base.EmuOpcode = uint16(opcode) base.OpcodeSize = 1 p := &LoginPacket{ EQPacket: *base, LoginEmuOpcode: opcode, } return p, nil } // GetLoginOpcode returns the login emulator opcode func (p *LoginPacket) GetLoginOpcode() LoginEmuOpcode { return p.LoginEmuOpcode } // SetLoginOpcode sets the login emulator opcode func (p *LoginPacket) SetLoginOpcode(opcode LoginEmuOpcode) { p.LoginEmuOpcode = opcode p.EmuOpcode = uint16(opcode) p.Opcode = uint16(opcode) } // SerializeLogin serializes the login packet with proper encoding func (p *LoginPacket) SerializeLogin() []byte { // Login packets use 1-byte opcodes buf := make([]byte, 1+len(p.Buffer)) buf[0] = byte(p.LoginEmuOpcode) if len(p.Buffer) > 0 { copy(buf[1:], p.Buffer) } return buf } // GetLoginOpcodeName returns the string name of a login emulator opcode func GetLoginOpcodeName(opcode LoginEmuOpcode) string { switch opcode { case LOP_Unknown: return "LOP_Unknown" case LOP_LoginRequestMsg: return "LOP_LoginRequestMsg" case LOP_LoginByNumRequestMsg: return "LOP_LoginByNumRequestMsg" case LOP_WSLoginRequestMsg: return "LOP_WSLoginRequestMsg" case LOP_ESLoginRequestMsg: return "LOP_ESLoginRequestMsg" case LOP_LoginReplyMsg: return "LOP_LoginReplyMsg" case LOP_WorldListMsg: return "LOP_WorldListMsg" case LOP_WorldStatusChangeMsg: return "LOP_WorldStatusChangeMsg" case LOP_AllWSDescRequestMsg: return "LOP_AllWSDescRequestMsg" case LOP_WSStatusReplyMsg: return "LOP_WSStatusReplyMsg" case LOP_AllCharactersDescRequestMsg: return "LOP_AllCharactersDescRequestMsg" case LOP_AllCharactersDescReplyMsg: return "LOP_AllCharactersDescReplyMsg" case LOP_CreateCharacterRequestMsg: return "LOP_CreateCharacterRequestMsg" case LOP_ReskinCharacterRequestMsg: return "LOP_ReskinCharacterRequestMsg" case LOP_CreateCharacterReplyMsg: return "LOP_CreateCharacterReplyMsg" case LOP_WSCreateCharacterRequestMsg: return "LOP_WSCreateCharacterRequestMsg" case LOP_WSCreateCharacterReplyMsg: return "LOP_WSCreateCharacterReplyMsg" case LOP_DeleteCharacterRequestMsg: return "LOP_DeleteCharacterRequestMsg" case LOP_DeleteCharacterReplyMsg: return "LOP_DeleteCharacterReplyMsg" case LOP_PlayCharacterRequestMsg: return "LOP_PlayCharacterRequestMsg" case LOP_PlayCharacterReplyMsg: return "LOP_PlayCharacterReplyMsg" case LOP_ServerPlayCharacterRequestMsg: return "LOP_ServerPlayCharacterRequestMsg" case LOP_ServerPlayCharacterReplyMsg: return "LOP_ServerPlayCharacterReplyMsg" case LOP_KeymapLoadMsg: return "LOP_KeymapLoadMsg" case LOP_KeymapNoneMsg: return "LOP_KeymapNoneMsg" case LOP_KeymapDataMsg: return "LOP_KeymapDataMsg" case LOP_KeymapSaveMsg: return "LOP_KeymapSaveMsg" case LOP_LSCheckAcctLockMsg: return "LOP_LSCheckAcctLockMsg" case LOP_WSAcctLockStatusMsg: return "LOP_WSAcctLockStatusMsg" case LOP_LsRequestClientCrashLogMsg: return "LOP_LsRequestClientCrashLogMsg" case LOP_LsClientBaselogReplyMsg: return "LOP_LsClientBaselogReplyMsg" case LOP_LsClientCrashlogReplyMsg: return "LOP_LsClientCrashlogReplyMsg" case LOP_LsClientAlertlogReplyMsg: return "LOP_LsClientAlertlogReplyMsg" case LOP_LsClientVerifylogReplyMsg: return "LOP_LsClientVerifylogReplyMsg" case LOP_BadLanguageFilter: return "LOP_BadLanguageFilter" case LOP_WSServerLockMsg: return "LOP_WSServerLockMsg" case LOP_WSServerHideMsg: return "LOP_WSServerHideMsg" case LOP_LSServerLockMsg: return "LOP_LSServerLockMsg" case LOP_UpdateCharacterSheetMsg: return "LOP_UpdateCharacterSheetMsg" case LOP_UpdateInventoryMsg: return "LOP_UpdateInventoryMsg" default: return fmt.Sprintf("Unknown(%d)", opcode) } } // ConvertToProtocolPacket wraps this login packet in a protocol packet func (p *LoginPacket) ConvertToProtocolPacket() *ProtocolPacket { // Serialize the login packet loginData := p.SerializeLogin() // Create protocol packet with OP_Packet opcode proto := NewProtocolPacket(OP_Packet, loginData) // Copy network info proto.SrcIP = p.SrcIP proto.SrcPort = p.SrcPort proto.DstIP = p.DstIP proto.DstPort = p.DstPort proto.Timestamp = p.Timestamp proto.Version = p.Version return proto } // Copy creates a deep copy of the login packet func (p *LoginPacket) Copy() *LoginPacket { newPacket := &LoginPacket{ EQPacket: *p.Clone(), LoginEmuOpcode: p.LoginEmuOpcode, } return newPacket }