1
0

compat pass 2

This commit is contained in:
Sky Johnson 2025-09-03 13:29:04 -05:00
parent 9cc3273a81
commit c692b25ac0
3 changed files with 641 additions and 562 deletions

View File

@ -8,7 +8,6 @@ import (
) )
// ProtoPacket handles low-level protocol features including EQ2-specific operations // ProtoPacket handles low-level protocol features including EQ2-specific operations
// Merges functionality from EQProtocolPacket and EQ2Packet
type ProtoPacket struct { type ProtoPacket struct {
*Packet *Packet
@ -16,7 +15,7 @@ type ProtoPacket struct {
flags uint8 // bit 0: compressed, bit 1: prepared, bit 2: encrypted, bit 3: acked flags uint8 // bit 0: compressed, bit 1: prepared, bit 2: encrypted, bit 3: acked
// EQ2-specific // EQ2-specific
LoginOp opcodes.EmuOpcode // From EQ2Packet LoginOp opcodes.EmuOpcode
// Reliability and sequencing // Reliability and sequencing
Sequence int32 Sequence int32
@ -39,7 +38,7 @@ const (
FlagAcked FlagAcked
) )
// Default compression threshold (compress packets larger than this) // Default compression threshold
const DefaultCompressThreshold = 100 const DefaultCompressThreshold = 100
// NewProtoPacket creates a protocol packet with opcode and buffer // NewProtoPacket creates a protocol packet with opcode and buffer
@ -190,7 +189,7 @@ func (p *ProtoPacket) EncodeChat() {
return return
} }
if IsChatPacket(p.Opcode) { if p.IsChatPacket() {
ChatEncode(p.Buffer, p.EncodeKey) ChatEncode(p.Buffer, p.EncodeKey)
p.SetEncrypted(true) p.SetEncrypted(true)
} }
@ -206,6 +205,29 @@ func (p *ProtoPacket) DecodeChat() {
p.SetEncrypted(false) p.SetEncrypted(false)
} }
// IsChatPacket checks if this is a chat packet using opcode manager
func (p *ProtoPacket) IsChatPacket() bool {
if p.manager == nil {
return false
}
// Get emulator opcode
emuOp := p.manager.EQToEmu(p.Opcode)
// Check against known chat opcodes
switch emuOp {
case opcodes.OP_ChatMsg,
opcodes.OP_TellMsg,
opcodes.OP_ChatLeaveChannelMsg,
opcodes.OP_ChatTellChannelMsg,
opcodes.OP_ChatTellUserMsg,
opcodes.OP_GuildsayMsg:
return true
default:
return false
}
}
// Copy creates a deep copy of this protocol packet // Copy creates a deep copy of this protocol packet
func (p *ProtoPacket) Copy() *ProtoPacket { func (p *ProtoPacket) Copy() *ProtoPacket {
newPacket := &ProtoPacket{ newPacket := &ProtoPacket{
@ -255,7 +277,7 @@ func (p *ProtoPacket) Serialize(dest []byte, offset int8) uint32 {
return uint32(len(p.Buffer)-int(offset)) + uint32(pos) return uint32(len(p.Buffer)-int(offset)) + uint32(pos)
} }
// PreparePacket prepares an EQ2 packet for transmission (from EQ2Packet) // PreparePacket prepares an EQ2 packet for transmission
func (p *ProtoPacket) PreparePacket(maxLen int16) int8 { func (p *ProtoPacket) PreparePacket(maxLen int16) int8 {
if p.IsPrepared() { if p.IsPrepared() {
return 0 return 0
@ -367,53 +389,122 @@ func (p *ProtoPacket) MakeApplicationPacket(opcodeSize uint8) *AppPacket {
return app return app
} }
// AppCombine combines this packet with another for efficient transmission (from EQ2Packet) // AppCombine combines this packet with another for efficient transmission
func (p *ProtoPacket) AppCombine(rhs *ProtoPacket) bool { func (p *ProtoPacket) AppCombine(rhs *ProtoPacket) bool {
const opAppCombined = 0x19 // OP_AppCombined value const opAppCombined = 0x19 // OP_AppCombined
// Apply compression to both packets before combining // Calculate sizes
p.CompressPacket() lhsSize := p.Size()
rhs.CompressPacket() rhsSize := rhs.Size()
// Case 1: This packet is already a combined packet // Check max combined size
if p.Opcode == opAppCombined && (len(p.Buffer)+len(rhs.Buffer)+3) < 255 { if lhsSize+rhsSize > MaxCombinedSize {
tmpSize := len(rhs.Buffer) - 2 return false
overSized := tmpSize >= 255 }
// If this packet is already combined, add to it
if p.Opcode == opAppCombined {
// Calculate new size
var newSize int var newSize int
if overSized { if rhsSize >= 255 {
newSize = len(p.Buffer) + tmpSize + 3 newSize = len(p.Buffer) + int(rhsSize) + 3 // oversized header
} else { } else {
newSize = len(p.Buffer) + tmpSize + 1 newSize = len(p.Buffer) + int(rhsSize) + 1 // normal header
} }
tmpBuffer := make([]byte, newSize) // Check size limit
if newSize > MaxCombinedSize {
return false
}
// Create new buffer
newBuffer := make([]byte, newSize)
pos := 0 pos := 0
// Copy existing combined packet data // Copy existing combined data
copy(tmpBuffer, p.Buffer) copy(newBuffer, p.Buffer)
pos += len(p.Buffer) pos = len(p.Buffer)
// Add size information for the new packet // Add new packet with size header
if overSized { if rhsSize >= 255 {
tmpBuffer[pos] = 255 newBuffer[pos] = 255 // Oversized marker
pos++ pos++
binary.BigEndian.PutUint16(tmpBuffer[pos:], uint16(tmpSize)) binary.BigEndian.PutUint16(newBuffer[pos:], uint16(rhsSize))
pos += 2 pos += 2
} else { } else {
tmpBuffer[pos] = byte(tmpSize) newBuffer[pos] = byte(rhsSize)
pos++ pos++
} }
// Copy the new packet data (skip first 2 bytes which are opcode) // Serialize rhs packet
if len(rhs.Buffer) > 2 { tmpBuf := make([]byte, rhsSize)
copy(tmpBuffer[pos:], rhs.Buffer[2:]) rhs.Serialize(tmpBuf, 0)
} copy(newBuffer[pos:], tmpBuf)
p.Buffer = tmpBuffer p.Buffer = newBuffer
return true return true
} }
// Case 2: Create new combined packet (simplified) // Create new combined packet from two non-combined packets
return false // Calculate total size: size1(1-3) + packet1 + size2(1-3) + packet2
var totalSize int
if lhsSize >= 255 {
totalSize += 3 + int(lhsSize)
} else {
totalSize += 1 + int(lhsSize)
}
if rhsSize >= 255 {
totalSize += 3 + int(rhsSize)
} else {
totalSize += 1 + int(rhsSize)
}
// Check size limit
if totalSize > MaxCombinedSize {
return false
}
// Build combined packet
newBuffer := make([]byte, totalSize)
pos := 0
// Add first packet with size header
if lhsSize >= 255 {
newBuffer[pos] = 255
pos++
binary.BigEndian.PutUint16(newBuffer[pos:], uint16(lhsSize))
pos += 2
} else {
newBuffer[pos] = byte(lhsSize)
pos++
}
// Serialize first packet
tmpBuf := make([]byte, lhsSize)
p.Serialize(tmpBuf, 0)
copy(newBuffer[pos:], tmpBuf)
pos += int(lhsSize)
// Add second packet with size header
if rhsSize >= 255 {
newBuffer[pos] = 255
pos++
binary.BigEndian.PutUint16(newBuffer[pos:], uint16(rhsSize))
pos += 2
} else {
newBuffer[pos] = byte(rhsSize)
pos++
}
// Serialize second packet
tmpBuf = make([]byte, rhsSize)
rhs.Serialize(tmpBuf, 0)
copy(newBuffer[pos:], tmpBuf)
// Update this packet to be combined
p.Opcode = opAppCombined
p.Buffer = newBuffer
p.SetPrepared(false) // Need to re-prepare
return true
} }

View File

@ -95,7 +95,7 @@ func (f *StreamFactory) OnBoot(eng gnet.Engine) gnet.Action {
func (f *StreamFactory) OnOpen(c gnet.Conn) ([]byte, gnet.Action) { func (f *StreamFactory) OnOpen(c gnet.Conn) ([]byte, gnet.Action) {
// Create stream configuration // Create stream configuration
streamCfg := &Config{ streamCfg := &Config{
SessionID: uint32(time.Now().UnixNano()), // Generate session ID SessionID: uint32(time.Now().UnixNano()),
CRCKey: f.crcKey, CRCKey: f.crcKey,
MaxPacketSize: f.maxPacketSize, MaxPacketSize: f.maxPacketSize,
EncodeKey: f.encodeKey, EncodeKey: f.encodeKey,
@ -181,13 +181,17 @@ func (f *StreamFactory) OnTraffic(c gnet.Conn) gnet.Action {
return gnet.None return gnet.None
} }
// OnTick called periodically // OnTick called periodically to process stream queues
func (f *StreamFactory) OnTick() (time.Duration, gnet.Action) { func (f *StreamFactory) OnTick() (time.Duration, gnet.Action) {
f.mu.RLock() f.mu.RLock()
defer f.mu.RUnlock() streams := make([]*Stream, 0, len(f.streams))
// Process retransmissions for all streams
for _, stream := range f.streams { for _, stream := range f.streams {
streams = append(streams, stream)
}
f.mu.RUnlock()
// Process queues for all streams
for _, stream := range streams {
stream.processQueues() stream.processQueues()
} }

File diff suppressed because it is too large Load Diff