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
// Merges functionality from EQProtocolPacket and EQ2Packet
type ProtoPacket struct {
*Packet
@ -16,7 +15,7 @@ type ProtoPacket struct {
flags uint8 // bit 0: compressed, bit 1: prepared, bit 2: encrypted, bit 3: acked
// EQ2-specific
LoginOp opcodes.EmuOpcode // From EQ2Packet
LoginOp opcodes.EmuOpcode
// Reliability and sequencing
Sequence int32
@ -39,7 +38,7 @@ const (
FlagAcked
)
// Default compression threshold (compress packets larger than this)
// Default compression threshold
const DefaultCompressThreshold = 100
// NewProtoPacket creates a protocol packet with opcode and buffer
@ -190,7 +189,7 @@ func (p *ProtoPacket) EncodeChat() {
return
}
if IsChatPacket(p.Opcode) {
if p.IsChatPacket() {
ChatEncode(p.Buffer, p.EncodeKey)
p.SetEncrypted(true)
}
@ -206,6 +205,29 @@ func (p *ProtoPacket) DecodeChat() {
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
func (p *ProtoPacket) Copy() *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)
}
// PreparePacket prepares an EQ2 packet for transmission (from EQ2Packet)
// PreparePacket prepares an EQ2 packet for transmission
func (p *ProtoPacket) PreparePacket(maxLen int16) int8 {
if p.IsPrepared() {
return 0
@ -367,53 +389,122 @@ func (p *ProtoPacket) MakeApplicationPacket(opcodeSize uint8) *AppPacket {
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 {
const opAppCombined = 0x19 // OP_AppCombined value
const opAppCombined = 0x19 // OP_AppCombined
// Apply compression to both packets before combining
p.CompressPacket()
rhs.CompressPacket()
// Calculate sizes
lhsSize := p.Size()
rhsSize := rhs.Size()
// Case 1: This packet is already a combined packet
if p.Opcode == opAppCombined && (len(p.Buffer)+len(rhs.Buffer)+3) < 255 {
tmpSize := len(rhs.Buffer) - 2
overSized := tmpSize >= 255
// Check max combined size
if lhsSize+rhsSize > MaxCombinedSize {
return false
}
// If this packet is already combined, add to it
if p.Opcode == opAppCombined {
// Calculate new size
var newSize int
if overSized {
newSize = len(p.Buffer) + tmpSize + 3
if rhsSize >= 255 {
newSize = len(p.Buffer) + int(rhsSize) + 3 // oversized header
} 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
// Copy existing combined packet data
copy(tmpBuffer, p.Buffer)
pos += len(p.Buffer)
// Copy existing combined data
copy(newBuffer, p.Buffer)
pos = len(p.Buffer)
// Add size information for the new packet
if overSized {
tmpBuffer[pos] = 255
// Add new packet with size header
if rhsSize >= 255 {
newBuffer[pos] = 255 // Oversized marker
pos++
binary.BigEndian.PutUint16(tmpBuffer[pos:], uint16(tmpSize))
binary.BigEndian.PutUint16(newBuffer[pos:], uint16(rhsSize))
pos += 2
} else {
tmpBuffer[pos] = byte(tmpSize)
newBuffer[pos] = byte(rhsSize)
pos++
}
// Copy the new packet data (skip first 2 bytes which are opcode)
if len(rhs.Buffer) > 2 {
copy(tmpBuffer[pos:], rhs.Buffer[2:])
}
// Serialize rhs packet
tmpBuf := make([]byte, rhsSize)
rhs.Serialize(tmpBuf, 0)
copy(newBuffer[pos:], tmpBuf)
p.Buffer = tmpBuffer
p.Buffer = newBuffer
return true
}
// Case 2: Create new combined packet (simplified)
return false
// Create new combined packet from two non-combined packets
// 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) {
// Create stream configuration
streamCfg := &Config{
SessionID: uint32(time.Now().UnixNano()), // Generate session ID
SessionID: uint32(time.Now().UnixNano()),
CRCKey: f.crcKey,
MaxPacketSize: f.maxPacketSize,
EncodeKey: f.encodeKey,
@ -181,13 +181,17 @@ func (f *StreamFactory) OnTraffic(c gnet.Conn) gnet.Action {
return gnet.None
}
// OnTick called periodically
// OnTick called periodically to process stream queues
func (f *StreamFactory) OnTick() (time.Duration, gnet.Action) {
f.mu.RLock()
defer f.mu.RUnlock()
// Process retransmissions for all streams
streams := make([]*Stream, 0, len(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()
}

File diff suppressed because it is too large Load Diff