From 712c7211c1b96f006cc354b292de24a98c7409f1 Mon Sep 17 00:00:00 2001 From: Le Duc Anh Date: Wed, 15 Oct 2025 09:43:58 +0700 Subject: [PATCH 1/5] add comments --- .../Scripts/Network/CSNetwork/NetworkManager.cs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/Assets/PerfectWorld/Scripts/Network/CSNetwork/NetworkManager.cs b/Assets/PerfectWorld/Scripts/Network/CSNetwork/NetworkManager.cs index 2982f4c1e1..1d96b1a667 100644 --- a/Assets/PerfectWorld/Scripts/Network/CSNetwork/NetworkManager.cs +++ b/Assets/PerfectWorld/Scripts/Network/CSNetwork/NetworkManager.cs @@ -298,15 +298,16 @@ namespace CSNetwork try { if (token.IsCancellationRequested) break; + // Read data from client-server stream into the receive buffer bytesRead = await stream.ReadAsync( _receiveOctets.RawBuffer, currentBufferLength, _receiveOctets.Capacity - currentBufferLength, token ); - - - // _logger.Log(LogType.Info, $"ProcessReceivedData:: Buffer remaining data size: {currentBufferLength} -- Raw first byte: {_receiveOctets.RawBuffer[0]}"); + + _logger.Log(LogType.Info, $"ProcessReceivedData:: Buffer remaining data size from {_previousLength} to {currentBufferLength} --- Last byte: {_receiveOctets.RawBuffer[currentBufferLength - 1]}"); + _previousLength = currentBufferLength; // cache to check if the buffer is growing } catch (IOException ex) when (ex.InnerException is SocketException se @@ -338,10 +339,8 @@ namespace CSNetwork currentBufferLength += bytesRead; _receiveOctets.SetSize(currentBufferLength); - _logger.Log(LogType.Info, $"BF Process Buffer:: Read {bytesRead} bytes -- Total size: {currentBufferLength}"); // Process the data currently in the buffer ProcessBuffer(); - _logger.Log(LogType.Info, $"AF Process Buffer:: Read {bytesRead} bytes -- Total size: {currentBufferLength}"); // After processing, the buffer might have been compacted, update length currentBufferLength = _receiveOctets.Length; } From 793c8a370fe8ccf8c17b081f96eaa8e4d17b15ba Mon Sep 17 00:00:00 2001 From: Le Duc Anh Date: Wed, 15 Oct 2025 10:06:10 +0700 Subject: [PATCH 2/5] add comments --- .../PerfectWorld/Scripts/Network/CSNetwork/NetworkManager.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Assets/PerfectWorld/Scripts/Network/CSNetwork/NetworkManager.cs b/Assets/PerfectWorld/Scripts/Network/CSNetwork/NetworkManager.cs index 1d96b1a667..d0962bbadb 100644 --- a/Assets/PerfectWorld/Scripts/Network/CSNetwork/NetworkManager.cs +++ b/Assets/PerfectWorld/Scripts/Network/CSNetwork/NetworkManager.cs @@ -305,8 +305,9 @@ namespace CSNetwork _receiveOctets.Capacity - currentBufferLength, token ); - - _logger.Log(LogType.Info, $"ProcessReceivedData:: Buffer remaining data size from {_previousLength} to {currentBufferLength} --- Last byte: {_receiveOctets.RawBuffer[currentBufferLength - 1]}"); + + if (currentBufferLength < _receiveOctets.Length) + _logger.Log(LogType.Info, $"ProcessReceivedData:: Buffer remaining data size from {_previousLength} to {currentBufferLength} --- Last byte: {_receiveOctets.RawBuffer[currentBufferLength - 1]}"); _previousLength = currentBufferLength; // cache to check if the buffer is growing } catch (IOException ex) From c67d0e5c4c9e21901dff9b9f48883c8fa648e47a Mon Sep 17 00:00:00 2001 From: NguyenVanDat Date: Wed, 15 Oct 2025 16:01:48 +0700 Subject: [PATCH 3/5] modify decompress algo --- .../Network/CSNetwork/NetworkManager.cs | 15 +- .../CSNetwork/Security/StreamCompress.cs | 400 ++++++------------ 2 files changed, 151 insertions(+), 264 deletions(-) diff --git a/Assets/PerfectWorld/Scripts/Network/CSNetwork/NetworkManager.cs b/Assets/PerfectWorld/Scripts/Network/CSNetwork/NetworkManager.cs index d0962bbadb..7368e1c009 100644 --- a/Assets/PerfectWorld/Scripts/Network/CSNetwork/NetworkManager.cs +++ b/Assets/PerfectWorld/Scripts/Network/CSNetwork/NetworkManager.cs @@ -305,10 +305,15 @@ namespace CSNetwork _receiveOctets.Capacity - currentBufferLength, token ); - - if (currentBufferLength < _receiveOctets.Length) - _logger.Log(LogType.Info, $"ProcessReceivedData:: Buffer remaining data size from {_previousLength} to {currentBufferLength} --- Last byte: {_receiveOctets.RawBuffer[currentBufferLength - 1]}"); - _previousLength = currentBufferLength; // cache to check if the buffer is growing + + // if (bytesRead > 0) + // { + // _logger.Log(LogType.Info, $"ProcessReceivedData:: Last Byte: {_receiveOctets.RawBuffer[currentBufferLength + bytesRead - 1]}"); + // if (_previousLength > 0) + // _logger.Log(LogType.Info, $"ProcessReceivedData:: Buffer remaining data size from {_previousLength} to {currentBufferLength + bytesRead} --- Last byte: {_receiveOctets.RawBuffer[_previousLength - 1]}"); + // } + // + // _previousLength = currentBufferLength + bytesRead; // cache to check if the buffer is growing } catch (IOException ex) when (ex.InnerException is SocketException se @@ -399,7 +404,7 @@ namespace CSNetwork catch (Exception ex) { _logger.Log(LogType.Info, - $"Input security update error: {ex.Message} - Clearing receive buffer." + $"Input security update error: {ex.Message} - {ex.StackTrace} - Clearing receive buffer." ); OnErrorOccurred($"Input security error: {ex.Message}"); _receiveOctets.SetSize(0); diff --git a/Assets/PerfectWorld/Scripts/Network/CSNetwork/Security/StreamCompress.cs b/Assets/PerfectWorld/Scripts/Network/CSNetwork/Security/StreamCompress.cs index b2b7f20450..4aceb693d2 100644 --- a/Assets/PerfectWorld/Scripts/Network/CSNetwork/Security/StreamCompress.cs +++ b/Assets/PerfectWorld/Scripts/Network/CSNetwork/Security/StreamCompress.cs @@ -10,43 +10,43 @@ namespace CSNetwork.Security private const int MPPC_HIST_LEN = 8192; private byte[] history = new byte[MPPC_HIST_LEN]; - private int historyPos; - private uint bitPos; - private uint adjust_bitPos; - private uint bitsProcessed; - private uint totalBits; + private int histptr; + private uint l; + private uint adjust_l; + private uint blen; + private uint blen_total; private List legacyInput = new List(); - private int readPos; - private int adjust_readPos; + private int rptr; + private int adjust_rptr; public Decompress() { - historyPos = 0; - bitPos = 0; + histptr = 0; + l = 0; } public Decompress(Decompress source) { Array.Copy(source.history, history, MPPC_HIST_LEN); - historyPos = source.historyPos; - bitPos = source.bitPos; - adjust_bitPos = source.adjust_bitPos; - bitsProcessed = source.bitsProcessed; - totalBits = source.totalBits; + histptr = source.histptr; + l = source.l; + adjust_l = source.adjust_l; + blen = source.blen; + blen_total = source.blen_total; legacyInput = new List(source.legacyInput); - readPos = source.readPos; - adjust_readPos = source.adjust_readPos; + rptr = source.rptr; + adjust_rptr = source.adjust_rptr; } - private bool PassBits(uint n) + private bool passbits(uint n) { - bitPos += n; - bitsProcessed += n; - if (bitsProcessed < totalBits) + l += n; + blen += n; + if (blen < blen_total) return true; - bitPos = adjust_bitPos; - readPos = adjust_readPos; + l = adjust_l; + rptr = adjust_rptr; return false; } @@ -58,19 +58,19 @@ namespace CSNetwork.Security | ((value & 0xFF000000) >> 24); } - private uint Fetch() + private uint fetch() { - readPos += (int)(bitPos >> 3); - bitPos &= 7; + rptr += (int)(l >> 3); + l &= 7; byte[] fourBytes = new byte[4]; - for (int i = 0; i < 4 && readPos + i < legacyInput.Count; i++) + for (int i = 0; i < 4; i++) { - fourBytes[i] = legacyInput[readPos + i]; + fourBytes[i] = legacyInput[rptr + i]; } uint value = BitConverter.ToUInt32(fourBytes, 0); - return ByteOrder32(value) << (int)bitPos; + return ByteOrder32(value) << (int)l; } private void LameCopy(int dstPos, int srcPos, int len) @@ -93,34 +93,6 @@ namespace CSNetwork.Security } } - // Copy bytes from history using MPPC's 8 KB circular window semantics. - // Source starts at (historyPos - offset) modulo window size and may overlap - // destination; freshly written bytes must be visible to subsequent reads. - private void CopyFromHistoryCircular(int offset, int length) - { - int srcPos = historyPos - offset; - if (srcPos < 0) - srcPos += MPPC_HIST_LEN; // wrap source into window - - int dstPos = historyPos; - - while (length-- > 0) - { - history[dstPos] = history[srcPos]; - - dstPos++; - if (dstPos == MPPC_HIST_LEN) - dstPos = 0; // wrap destination - - srcPos++; - if (srcPos == MPPC_HIST_LEN) - srcPos = 0; // wrap source - } - - // Advance history head to the end of the copied sequence - historyPos = dstPos; - } - public Octets Update(Octets input) { // Add input to legacy buffer @@ -129,253 +101,163 @@ namespace CSNetwork.Security legacyInput.Add(b); } - totalBits = (uint)(legacyInput.Count * 8 - bitPos); - readPos = 0; - bitsProcessed = 7; + blen_total = (uint)(legacyInput.Count * 8 - l); + rptr = 0; + blen = 7; Octets output = new Octets(); - int histHead = historyPos; + int histhead = histptr; - while (totalBits > bitsProcessed) + while (blen_total > blen) { - adjust_bitPos = bitPos; - adjust_readPos = readPos; - uint val = Fetch(); - + adjust_l = l; + adjust_rptr = rptr; + + uint val = fetch(); if (val < 0x80000000) { - if (!PassBits(8)) + if (!passbits(8)) break; - // Defer if writing this literal would cross the end of the linear window. - // We only wrap at EOB to match the original C++ semantics. - if (historyPos + 1 > MPPC_HIST_LEN) - { - bitPos = adjust_bitPos; - readPos = adjust_readPos; - break; - } - history[historyPos++] = (byte)(val >> 24); - // Do not wrap here; wrapping is handled only at EOB. + + history[histptr++] = (byte)(val >> 24); continue; } - if (val < 0xC0000000) { - if (!PassBits(9)) + if (!passbits(9)) break; - // Defer if writing this literal would cross the end of the linear window. - if (historyPos + 1 > MPPC_HIST_LEN) - { - bitPos = adjust_bitPos; - readPos = adjust_readPos; - break; - } - history[historyPos++] = (byte)(((val >> 23) | 0x80) & 0xFF); - // Do not wrap here; wrapping is handled only at EOB. + history[histptr++] = (byte)(((val >> 23) | 0x80) & 0xFF); continue; } - uint offset = 0, - length = 0; + uint off = 0, len = 0; if (val >= 0xF0000000) { - if (!PassBits(10)) + if (!passbits(10)) break; - offset = (val >> 22) & 0x3F; - if (offset == CTRL_OFF_EOB) + off = (val >> 22) & 0x3F; + if (off == CTRL_OFF_EOB) { - uint advance = 8 - (bitPos & 7); + uint advance = (uint)(8 - (l & 7)); if (advance < 8) - if (!PassBits(advance)) + if (!passbits(advance)) break; // Copy current history segment to output - if (historyPos >= histHead) - { - byte[] segment = new byte[historyPos - histHead]; - Array.Copy(history, histHead, segment, 0, segment.Length); + byte[] segment = new byte[histptr - histhead]; + Array.Copy(history, histhead, segment, 0, segment.Length); + output.Insert(output.Size, segment); - // If output is empty, replace it, otherwise insert at the end - if (output.Size == 0) - output.Replace(segment); - else - output.Insert(output.Size, segment); - } - else - { - // Wrap around case - two segments - byte[] segment1 = new byte[MPPC_HIST_LEN - histHead]; - Array.Copy(history, histHead, segment1, 0, segment1.Length); + if (histptr - histhead == MPPC_HIST_LEN) + histptr = 0; - // Add first segment (from histHead to end of buffer) - if (output.Size == 0) - output.Replace(segment1); - else - output.Insert(output.Size, segment1); - - // Add second segment (from beginning to historyPos) - if (historyPos > 0) - { - byte[] segment2 = new byte[historyPos]; - Array.Copy(history, 0, segment2, 0, historyPos); - output.Insert(output.Size, segment2); - } - } - - if (historyPos == MPPC_HIST_LEN) - historyPos = 0; - - histHead = historyPos; + histhead = histptr; continue; } } else if (val >= 0xE0000000) { - if (!PassBits(12)) + if (!passbits(12)) break; - offset = ((val >> 20) & 0xFF) + 64; + off = ((val >> 20) & 0xFF) + 64; } else if (val >= 0xC0000000) { - if (!PassBits(16)) + if (!passbits(16)) break; - offset = ((val >> 16) & 0x1FFF) + 320; + off = ((val >> 16) & 0x1FFF) + 320; + } + + val = fetch(); + if ( val < 0x80000000 ) + { + if ( !passbits(1) ) + break; + len = 3; + } + else if ( val < 0xc0000000 ) + { + if ( !passbits(4) ) + break; + len = 4|((val>>28)&3); + } + else if ( val < 0xe0000000 ) + { + if ( !passbits(6) ) + break; + len = 8|((val>>26)&7); + } + else if ( val < 0xf0000000 ) + { + if ( !passbits(8) ) + break; + len = 16|((val>>24)&15); + } + else if ( val < 0xf8000000 ) + { + if ( !passbits(10) ) + break; + len = 32|((val>>22)&0x1f); + } + else if ( val < 0xfc000000 ) + { + if ( !passbits(12) ) + break; + len = 64|((val>>20)&0x3f); + } + else if ( val < 0xfe000000 ) + { + if ( !passbits(14) ) + break; + len = 128|((val>>18)&0x7f); + } + else if ( val < 0xff000000 ) + { + if ( !passbits(16) ) + break; + len = 256|((val>>16)&0xff); + } + else if ( val < 0xff800000 ) + { + if ( !passbits(18) ) + break; + len = 0x200|((val>>14)&0x1ff); + } + else if ( val < 0xffc00000 ) + { + if ( !passbits(20) ) + break; + len = 0x400|((val>>12)&0x3ff); + } + else if ( val < 0xffe00000 ) + { + if ( !passbits(22) ) + break; + len = 0x800|((val>>10)&0x7ff); + } + else if ( val < 0xfff00000 ) + { + if ( !passbits(24) ) + break; + len = 0x1000|((val>>8)&0xfff); } else { - // Invalid data - bitPos = adjust_bitPos; - readPos = adjust_readPos; + l = adjust_l; + rptr = adjust_rptr; break; } - - val = Fetch(); - if (val < 0x80000000) - { - if (!PassBits(1)) - break; - length = 3; - } - else if (val < 0xC0000000) - { - if (!PassBits(4)) - break; - length = 4 | ((val >> 28) & 3); - } - else if (val < 0xE0000000) - { - if (!PassBits(6)) - break; - length = 8 | ((val >> 26) & 7); - } - else if (val < 0xF0000000) - { - if (!PassBits(8)) - break; - length = 16 | ((val >> 24) & 15); - } - else if (val < 0xF8000000) - { - if (!PassBits(10)) - break; - length = 32 | ((val >> 22) & 0x1F); - } - else if (val < 0xFC000000) - { - if (!PassBits(12)) - break; - length = 64 | ((val >> 20) & 0x3F); - } - else if (val < 0xFE000000) - { - if (!PassBits(14)) - break; - length = 128 | ((val >> 18) & 0x7F); - } - else if (val < 0xFF000000) - { - if (!PassBits(16)) - break; - length = 256 | ((val >> 16) & 0xFF); - } - else if (val < 0xFF800000) - { - if (!PassBits(18)) - break; - length = 0x200 | ((val >> 14) & 0x1FF); - } - else if (val < 0xFFC00000) - { - if (!PassBits(20)) - break; - length = 0x400 | ((val >> 12) & 0x3FF); - } - else if (val < 0xFFE00000) - { - if (!PassBits(22)) - break; - length = 0x800 | ((val >> 10) & 0x7FF); - } - else if (val < 0xFFF00000) - { - if (!PassBits(24)) - break; - length = 0x1000 | ((val >> 8) & 0xFFF); - } - else - { - bitPos = adjust_bitPos; - readPos = adjust_readPos; + if (histptr < off || histptr + len > MPPC_HIST_LEN) break; - } - - // Validate match boundaries against the current linear window. Defer if it would cross. - // This mirrors the C++ check: if (histptr - off < history || histptr + len > history + MPPC_HIST_LEN) break; - if (offset == 0 || offset > MPPC_HIST_LEN || historyPos - (int)offset < 0 || historyPos + (int)length > MPPC_HIST_LEN) - { - // Not enough room in the current linear window; rollback and wait for more data. - bitPos = adjust_bitPos; - readPos = adjust_readPos; - break; - } - - // Linear, overlap-safe copy within current window. No mid-block wrap. - LameCopy(historyPos, historyPos - (int)offset, (int)length); - historyPos += (int)length; - } - - // Copy remaining history segment to output - if (historyPos >= histHead) - { - byte[] result = new byte[historyPos - histHead]; - Array.Copy(history, histHead, result, 0, result.Length); - if (output.Size == 0) - output.Replace(result); - else - output.Insert(output.Size, result); - } - else - { - if (histHead < MPPC_HIST_LEN) - { - byte[] segment1 = new byte[MPPC_HIST_LEN - histHead]; - Array.Copy(history, histHead, segment1, 0, segment1.Length); - if (output.Size == 0) - output.Replace(segment1); - else - output.Insert(output.Size, segment1); - } - - if (historyPos > 0) - { - byte[] segment2 = new byte[historyPos]; - Array.Copy(history, 0, segment2, 0, historyPos); - output.Insert(output.Size, segment2); - } + LameCopy(histptr, histptr - (int)off, (int)len); + histptr += (int)len; } + byte[] result = new byte[histptr - histhead]; + Array.Copy(history, histhead, result, 0, result.Length); + output.Insert(output.Size, result); // Remove processed bytes from legacy input - legacyInput.RemoveRange(0, readPos); + legacyInput.RemoveRange(0, rptr); return output; } From d757c3137befa8417c24dfb234696d06089b19b4 Mon Sep 17 00:00:00 2001 From: NguyenVanDat Date: Wed, 15 Oct 2025 18:27:16 +0700 Subject: [PATCH 4/5] add decrypted buffer --- .../Network/CSNetwork/NetworkManager.cs | 27 ++++++++++--------- .../CSNetwork/Security/ARCFourSecurity.cs | 6 ++--- .../Security/DecompressArcFourSecurity.cs | 6 ++--- .../CSNetwork/Security/StreamCompress.cs | 3 ++- 4 files changed, 21 insertions(+), 21 deletions(-) diff --git a/Assets/PerfectWorld/Scripts/Network/CSNetwork/NetworkManager.cs b/Assets/PerfectWorld/Scripts/Network/CSNetwork/NetworkManager.cs index 7368e1c009..2ab051fcd8 100644 --- a/Assets/PerfectWorld/Scripts/Network/CSNetwork/NetworkManager.cs +++ b/Assets/PerfectWorld/Scripts/Network/CSNetwork/NetworkManager.cs @@ -14,6 +14,7 @@ namespace CSNetwork private TcpClient? _client; private NetworkStream? _stream; private readonly Octets _receiveOctets; // Underlying buffer for receiving + private readonly Octets _decryptedOctets; private readonly OctetsStream _receiveBufferStream; // Stream wrapper (less used now) private BaseSecurity? _inputSecurity = null; // Use abstract Security class private BaseSecurity? _outputSecurity = null; // Use abstract Security class @@ -42,6 +43,7 @@ namespace CSNetwork { // Removed TcpClient initialization here, do it in ConnectAsync _receiveOctets = new Octets(8192); // Initial buffer size + _decryptedOctets = new Octets(8192); // initial the decrypted buffer _receiveBufferStream = new OctetsStream(_receiveOctets); // Keep for reference maybe? // Initialize security using the factory _inputSecurity = BaseSecurity.Create(SecurityType.NULLSECURITY); @@ -301,8 +303,8 @@ namespace CSNetwork // Read data from client-server stream into the receive buffer bytesRead = await stream.ReadAsync( _receiveOctets.RawBuffer, - currentBufferLength, - _receiveOctets.Capacity - currentBufferLength, + 0, + _receiveOctets.Capacity, token ); @@ -343,12 +345,12 @@ namespace CSNetwork } currentBufferLength += bytesRead; - _receiveOctets.SetSize(currentBufferLength); + _receiveOctets.SetSize(bytesRead); // Process the data currently in the buffer ProcessBuffer(); // After processing, the buffer might have been compacted, update length - currentBufferLength = _receiveOctets.Length; + // currentBufferLength = _receiveOctets.Length; } } catch (OperationCanceledException) @@ -381,7 +383,7 @@ namespace CSNetwork bool securityApplied = currentIsec != null && currentIsec.GetType() != typeof(NullSecurity); Octets dataToProcess; // This will hold the data block we decode from - int originalBlockLength = _receiveOctets.Length; // Length before security + int originalBlockLength = _decryptedOctets.Length; // Length before security int bytesConsumedFromOriginal = 0; // How many bytes of _receiveOctets are processed // 1. Apply Input Security (if active) @@ -389,16 +391,16 @@ namespace CSNetwork { try { - // Create a temporary Octets with the current buffer content + // Create a temporary Octets with the current raw buffer content Octets currentData = new Octets( _receiveOctets.RawBuffer, 0, originalBlockLength ); - _logger.Log(LogType.Info, $"ProcessBuffer:: raw first byte {currentData.RawBuffer[0]} - Length: {currentData.Length}"); // Update returns a NEW Octets object with processed data dataToProcess = currentIsec!.Update(currentData); - _logger.Log(LogType.Info, $"ProcessBuffer:: decompressed first byte {dataToProcess.RawBuffer[0]} - Length: {dataToProcess.Length}"); + _decryptedOctets.Insert(_decryptedOctets.Size, dataToProcess.ByteArray); + dataToProcess = _decryptedOctets; // _logger.Log(LogType.Info, $"Input security applied. Original size: {originalBlockLength}, Processed size: {dataToProcess.Length}"); } catch (Exception ex) @@ -481,12 +483,13 @@ namespace CSNetwork } EndProcessing: + _receiveOctets.SetSize(0); // 4. Compact the *original* _receiveOctets buffer - CompactOriginalBuffer(bytesConsumedFromOriginal, originalBlockLength); + CompactDecryptedBuffer(bytesConsumedFromOriginal, originalBlockLength); } // *** Helper to compact the original receive buffer *** - private void CompactOriginalBuffer(int bytesToConsume, int originalLength) + private void CompactDecryptedBuffer(int bytesToConsume, int originalLength) { if (bytesToConsume <= 0 || _receiveOctets == null) // Add null check { @@ -501,9 +504,9 @@ namespace CSNetwork int remaining = originalLength - bytesToConsume; // _logger.Log(LogType.Info, $"Compacting original buffer: Consumed {bytesToConsume}, Moving {remaining} bytes from pos {bytesToConsume}"); Buffer.BlockCopy( - _receiveOctets.RawBuffer, + _decryptedOctets.RawBuffer, bytesToConsume, - _receiveOctets.RawBuffer, + _decryptedOctets.RawBuffer, 0, remaining ); diff --git a/Assets/PerfectWorld/Scripts/Network/CSNetwork/Security/ARCFourSecurity.cs b/Assets/PerfectWorld/Scripts/Network/CSNetwork/Security/ARCFourSecurity.cs index b8e31e30b7..3b8bcf75b8 100644 --- a/Assets/PerfectWorld/Scripts/Network/CSNetwork/Security/ARCFourSecurity.cs +++ b/Assets/PerfectWorld/Scripts/Network/CSNetwork/Security/ARCFourSecurity.cs @@ -80,8 +80,7 @@ namespace CSNetwork.Security for (int i = 0; i < length; i++) { - _index1++; // Note: byte overflows wrap around from 255 to 0 automatically - _index2 = (byte)(_index2 + _perm[_index1]); + _index2 += _perm[++_index1]; // Swap perm[index1] and perm[index2] byte temp = _perm[_index1]; @@ -89,9 +88,8 @@ namespace CSNetwork.Security _perm[_index2] = temp; byte j = (byte)(_perm[_index1] + _perm[_index2]); - byte keystreamByte = _perm[j]; - buffer[offset + i] ^= keystreamByte; + buffer[offset + i] ^= _perm[j]; } return data; // Return the modified Octets diff --git a/Assets/PerfectWorld/Scripts/Network/CSNetwork/Security/DecompressArcFourSecurity.cs b/Assets/PerfectWorld/Scripts/Network/CSNetwork/Security/DecompressArcFourSecurity.cs index 769a67a446..5a2ee9a521 100644 --- a/Assets/PerfectWorld/Scripts/Network/CSNetwork/Security/DecompressArcFourSecurity.cs +++ b/Assets/PerfectWorld/Scripts/Network/CSNetwork/Security/DecompressArcFourSecurity.cs @@ -45,8 +45,6 @@ namespace CSNetwork.Security { if (data == null || data.Length == 0) { - _logger.Log(LogType.Debug,$"HoangDev: AF _arcFour data{data.RawBuffer[0]} - Length: {data.Length}"); - return new Octets(); // Return empty if input is empty } // 1. Decrypt using ARCFour @@ -57,8 +55,8 @@ namespace CSNetwork.Security // or just to be safe. Ensure _arcFour.Update returns a *new* Octets. // *** If ARCFourSecurity.Update modified the input Octets in-place, this would be wrong. *** // *** Assuming ARCFourSecurity.Update follows the abstract Security pattern and returns new Octets *** + UnityEngine.Debug.Log($"ENCRYPTED: {data.RawBuffer[0]}"); decryptedData = _arcFour.Update(data); - _logger.Log(LogType.Debug,$"HoangDev: AF _arcFour data{decryptedData.RawBuffer[0]} - Length: {decryptedData.Length}"); } catch (Exception ex) @@ -78,8 +76,8 @@ namespace CSNetwork.Security Octets decompressedData; try { + UnityEngine.Debug.Log($"DECRYPTED: {decryptedData.RawBuffer[0]}"); decompressedData = decompressor.Update(decryptedData); - _logger.Log(LogType.Debug, $"Decompressed {decryptedData.Length} bytes to {decompressedData.Length} bytes. Decompressed Data: {decompressedData.ToString()}"); } catch (Exception ex) { diff --git a/Assets/PerfectWorld/Scripts/Network/CSNetwork/Security/StreamCompress.cs b/Assets/PerfectWorld/Scripts/Network/CSNetwork/Security/StreamCompress.cs index 4aceb693d2..b64048cd1d 100644 --- a/Assets/PerfectWorld/Scripts/Network/CSNetwork/Security/StreamCompress.cs +++ b/Assets/PerfectWorld/Scripts/Network/CSNetwork/Security/StreamCompress.cs @@ -66,7 +66,8 @@ namespace CSNetwork.Security byte[] fourBytes = new byte[4]; for (int i = 0; i < 4; i++) { - fourBytes[i] = legacyInput[rptr + i]; + if (rptr + i < legacyInput.Count) fourBytes[i] = legacyInput[rptr + i]; + else fourBytes[i] = 0; } uint value = BitConverter.ToUInt32(fourBytes, 0); From 668f808883661d1b077b40e703cfc99da6facb0d Mon Sep 17 00:00:00 2001 From: NguyenVanDat Date: Wed, 15 Oct 2025 18:45:26 +0700 Subject: [PATCH 5/5] fix the buffer issue --- .../Scripts/Network/CSNetwork/NetworkManager.cs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/Assets/PerfectWorld/Scripts/Network/CSNetwork/NetworkManager.cs b/Assets/PerfectWorld/Scripts/Network/CSNetwork/NetworkManager.cs index 2ab051fcd8..f44941284c 100644 --- a/Assets/PerfectWorld/Scripts/Network/CSNetwork/NetworkManager.cs +++ b/Assets/PerfectWorld/Scripts/Network/CSNetwork/NetworkManager.cs @@ -395,7 +395,7 @@ namespace CSNetwork Octets currentData = new Octets( _receiveOctets.RawBuffer, 0, - originalBlockLength + _receiveOctets.Size ); // Update returns a NEW Octets object with processed data dataToProcess = currentIsec!.Update(currentData); @@ -473,7 +473,7 @@ namespace CSNetwork { // If security was applied and we processed/consumed *any* bytes from the processed stream, // assume the whole original block was consumed. - bytesConsumedFromOriginal = processedAnyProtocols ? originalBlockLength : 0; + bytesConsumedFromOriginal = totalConsumedFromProcessedStream; } else { @@ -491,7 +491,7 @@ namespace CSNetwork // *** Helper to compact the original receive buffer *** private void CompactDecryptedBuffer(int bytesToConsume, int originalLength) { - if (bytesToConsume <= 0 || _receiveOctets == null) // Add null check + if (bytesToConsume <= 0 || _decryptedOctets == null) // Add null check { return; // Nothing to consume/compact } @@ -510,15 +510,14 @@ namespace CSNetwork 0, remaining ); - _receiveOctets.SetSize(remaining); + _decryptedOctets.SetSize(remaining); } else // Consumed all { // All data processed or skipped, clear buffer // _logger.Log(LogType.Info, $"Clearing original buffer: Consumed {bytesToConsume} >= Original {originalLength}"); - _receiveOctets.SetSize(0); + _decryptedOctets.SetSize(0); } - _receiveBufferStream.Position = _receiveOctets.Length; // Reset stream pos just in case } // Helper to raise ErrorOccurred event