diff --git a/r5dev/engine/net_chan.cpp b/r5dev/engine/net_chan.cpp
index b80919fc..13c34756 100644
--- a/r5dev/engine/net_chan.cpp
+++ b/r5dev/engine/net_chan.cpp
@@ -64,6 +64,237 @@ double CNetChan::GetTimeConnected(void) const
 	return (t > 0.0) ? t : 0.0;
 }
 
+//-----------------------------------------------------------------------------
+// Purpose: flows a new packet
+// Input  : *pChan   - 
+//          outSeqNr - 
+//          acknr    - 
+//          inSeqNr  - 
+//          nChoked  - 
+//          nDropped - 
+//          nSize    - 
+//-----------------------------------------------------------------------------
+void CNetChan::_FlowNewPacket(CNetChan* pChan, int flow, int outSeqNr, int inSeqNr, int nChoked, int nDropped, int nSize)
+{
+    float v7; // xmm4_8 (was double)
+    int v8; // r13d
+    int v9; // r14d
+    int v12; // r12d
+    int currentindex; // eax
+    int v16; // r15d
+    int v17; // r8d
+    int v18; // ebp
+    unsigned int v19; // eax
+    int v20; // r9 (was char)
+    int v21; // r8d
+    __int64 v22; // r14
+    float time; // xmm0_4
+    __int64 v24; // rdx
+    __int64 v25; // rcx
+    __int64 v26; // rdx
+    __int64 v27; // rcx
+    __int64 v28; // rdx
+    __int64 v29; // rcx
+    int v30; // edx
+    int v31; // r8 (was char)
+    float v32; // xmm0_4
+    __int64 v33; // r9
+    __int64 v34; // rax
+    __int64 v35; // rdx
+    int v36; // r8d
+    float v37; // xmm3_4
+    __int64 result; // rax
+    float v39; // xmm1_4
+    float v40; // xmm0_4
+    float v41; // xmm1_4
+    netframe_header_t* v42; // rdx
+    float v43; // xmm0_4
+    float v44; // xmm2_4
+    float v45; // xmm0_4
+
+    v7 = (float)*g_pNetTime;
+    v8 = flow;
+    v9 = inSeqNr;
+    netflow_t* pFlow = &pChan->m_DataFlow[flow];
+    v12 = outSeqNr;
+
+    netframe_header_t* pFrameHeader = nullptr;
+    netframe_t* pFrame = nullptr;
+
+    currentindex = pFlow->currentindex;
+    if (outSeqNr > currentindex)
+    {
+        v16 = currentindex + 1;
+        if (currentindex + 1 <= outSeqNr)
+        {
+            v17 = outSeqNr - v16;
+            if (v17 + 1 >= 4)
+            {
+                v18 = nChoked + nDropped;
+                v19 = ((unsigned int)(v12 - v16 - 3) >> 2) + 1;
+                v20 = v16 + 2;
+                v21 = v17 - 2;
+                v22 = v19;
+                time = (float)*g_pNetTime;
+                v16 += 4 * v19;
+                do
+                {
+                    v24 = (v20 - 2) & NET_FRAMES_MASK;
+                    v25 = v24;
+                    pFlow->frame_headers[v25].time = time;
+                    pFlow->frame_headers[v25].valid = 0;
+                    pFlow->frame_headers[v25].size = 0;
+                    pFlow->frame_headers[v25].latency = -1.0;
+                    pFlow->frames[v24].avg_latency = pChan->m_DataFlow[FLOW_OUTGOING].avglatency;
+                    pFlow->frame_headers[v25].choked = 0;
+                    pFlow->frames[v24].dropped = 0;
+                    if (v21 + 2 < v18)
+                    {
+                        if (v21 + 2 >= nChoked)
+                            pFlow->frames[v24].dropped = 1;
+                        else
+                            pFlow->frame_headers[(v20 - 2) & NET_FRAMES_MASK].choked = 1;
+                    }
+                    v26 = (v20 - 1) & NET_FRAMES_MASK;
+                    v27 = v26;
+                    pFlow->frame_headers[v27].time = time;
+                    pFlow->frame_headers[v27].valid = 0;
+                    pFlow->frame_headers[v27].size = 0;
+                    pFlow->frame_headers[v27].latency = -1.0;
+                    pFlow->frames[v26].avg_latency = pChan->m_DataFlow[FLOW_OUTGOING].avglatency;
+                    pFlow->frame_headers[v27].choked = 0;
+                    pFlow->frames[v26].dropped = 0;
+                    if (v21 + 1 < v18)
+                    {
+                        if (v21 + 1 >= nChoked)
+                            pFlow->frames[v26].dropped = 1;
+                        else
+                            pFlow->frame_headers[(v20 - 1) & NET_FRAMES_MASK].choked = 1;
+                    }
+                    v28 = v20 & NET_FRAMES_MASK;
+                    v29 = v28;
+                    pFlow->frame_headers[v29].time = time;
+                    pFlow->frame_headers[v29].valid = 0;
+                    pFlow->frame_headers[v29].size = 0;
+                    pFlow->frame_headers[v29].latency = -1.0;
+                    pFlow->frames[v28].avg_latency = pChan->m_DataFlow[FLOW_OUTGOING].avglatency;
+                    pFlow->frame_headers[v29].choked = 0;
+                    pFlow->frames[v28].dropped = 0;
+                    if (v21 < v18)
+                    {
+                        if (v21 >= nChoked)
+                            pFlow->frames[v28].dropped = 1;
+                        else
+                            pFlow->frame_headers[v20 & NET_FRAMES_MASK].choked = 1;
+                    }
+                    pFrame = &pFlow->frames[(v20 + 1) & NET_FRAMES_MASK];
+                    pFrameHeader = &pFlow->frame_headers[(v20 + 1) & NET_FRAMES_MASK];
+                    pFrameHeader->time = time;
+                    pFrameHeader->valid = 0;
+                    pFrameHeader->size = 0;
+                    pFrameHeader->latency = -1.0;
+                    pFrame->avg_latency = pChan->m_DataFlow[FLOW_OUTGOING].avglatency;
+                    pFrameHeader->choked = 0;
+                    pFrame->dropped = 0;
+                    if (v21 - 1 < v18)
+                    {
+                        if (v21 - 1 >= nChoked)
+                            pFrame->dropped = 1;
+                        else
+                            pFrameHeader->choked = 1;
+                    }
+                    v21 -= 4;
+                    v20 += 4;
+                    --v22;
+                } while (v22);
+                v12 = outSeqNr;
+                v8 = flow;
+                v9 = inSeqNr;
+            }
+            if (v16 <= v12)
+            {
+                v30 = v12 - v16;
+                v31 = v16;
+                v33 = v12 - v16 + 1;
+                do
+                {
+                    pFrame = &pFlow->frames[v31 & NET_FRAMES_MASK];
+                    pFrameHeader = &pFlow->frame_headers[v31 & NET_FRAMES_MASK];
+                    v32 = v7;
+                    pFrameHeader->time = v32;
+                    pFrameHeader->valid = 0;
+                    pFrameHeader->size = 0;
+                    pFrameHeader->latency = -1.0;
+                    pFrame->avg_latency = pChan->m_DataFlow[FLOW_OUTGOING].avglatency;
+                    pFrameHeader->choked = 0;
+                    pFrame->dropped = 0;
+                    if (v30 < nChoked + nDropped)
+                    {
+                        if (v30 >= nChoked)
+                            pFrame->dropped = 1;
+                        else
+                            pFrameHeader->choked = 1;
+                    }
+                    --v30;
+                    ++v31;
+                    --v33;
+                } while (v33);
+                v9 = inSeqNr;
+            }
+        }
+        pFrame->dropped = nDropped;
+        pFrameHeader->choked = (short)nChoked;
+        pFrameHeader->size = nSize;
+        pFrameHeader->valid = 1;
+        pFrame->avg_latency = pChan->m_DataFlow[FLOW_OUTGOING].avglatency;
+    }
+    ++pFlow->totalpackets;
+    pFlow->currentindex = v12;
+    v34 = 544i64;
+
+    if (!v8)
+        v34 = 3688i64;
+
+    pFlow->current_frame = pFrame;
+    v35 = 548i64;
+    v36 = *(_DWORD*)(&pChan->m_bProcessingMessages + v34);
+    if (v9 > v36 - NET_FRAMES_BACKUP)
+    {
+        if (!v8)
+            v35 = 3692i64;
+        result = (__int64)pChan + 16 * (v9 & NET_FRAMES_MASK);
+        v42 = (netframe_header_t*)(result + v35);
+        if (v42->valid && v42->latency == -1.0)
+        {
+            v43 = 0.0;
+            v44 = fmax(0.0f, v7 - v42->time);
+            v42->latency = v44;
+            if (v44 >= 0.0)
+                v43 = v44;
+            else
+                v42->latency = 0.0;
+            v45 = v43 + pFlow->latency;
+            ++pFlow->totalupdates;
+            pFlow->latency = v45;
+            pFlow->maxlatency = fmaxf(pFlow->maxlatency, v42->latency);
+        }
+    }
+    else
+    {
+        if (!v8)
+            v35 = 3692i64;
+
+        v37 = *(float*)(&pChan->m_bProcessingMessages + 16 * (v36 & NET_FRAMES_MASK) + v35);
+        result = v35 + 16i64 * (((_BYTE)v36 + 1) & NET_FRAMES_MASK);
+        v39 = v37 - *(float*)(&pChan->m_bProcessingMessages + result);
+        ++pFlow->totalupdates;
+        v40 = (float)((float)(v39 / 127.0) * (float)(v36 - v9)) + v7 - v37;
+        v41 = fmaxf(pFlow->maxlatency, v40);
+        pFlow->latency = v40 + pFlow->latency;
+        pFlow->maxlatency = v41;
+    }
+}
+
 //-----------------------------------------------------------------------------
 // Purpose: shutdown netchannel
 // Input  : *this - 
@@ -170,10 +401,12 @@ bool CNetChan::HasPendingReliableData(void)
 void VNetChan::Attach() const
 {
 	DetourAttach((PVOID*)&v_NetChan_Shutdown, &CNetChan::_Shutdown);
+	DetourAttach((PVOID*)&v_NetChan_FlowNewPacket, &CNetChan::_FlowNewPacket);
 	DetourAttach((PVOID*)&v_NetChan_ProcessMessages, &CNetChan::_ProcessMessages);
 }
 void VNetChan::Detach() const
 {
 	DetourDetach((PVOID*)&v_NetChan_Shutdown, &CNetChan::_Shutdown);
+    DetourDetach((PVOID*)&v_NetChan_FlowNewPacket, &CNetChan::_FlowNewPacket);
 	DetourDetach((PVOID*)&v_NetChan_ProcessMessages, &CNetChan::_ProcessMessages);
 }
diff --git a/r5dev/engine/net_chan.h b/r5dev/engine/net_chan.h
index 501cde4e..ad719610 100644
--- a/r5dev/engine/net_chan.h
+++ b/r5dev/engine/net_chan.h
@@ -96,6 +96,9 @@ inline void(*v_NetChan_Shutdown)(CNetChan* pChan, const char* szReason, uint8_t
 inline CMemory p_NetChan_CanPacket;
 inline bool(*v_NetChan_CanPacket)(const CNetChan* pChan);
 
+inline CMemory p_NetChan_FlowNewPacket;
+inline void(*v_NetChan_FlowNewPacket)(CNetChan* pChan, int flow, int outSeqNr, int inSeqNr, int nChoked, int nDropped, int nSize);
+
 inline CMemory p_NetChan_SendDatagram;
 inline int(*v_NetChan_SendDatagram)(CNetChan* pChan, bf_write* pMsg);
 
@@ -145,6 +148,8 @@ public:
 	static void _Shutdown(CNetChan* pChan, const char* szReason, uint8_t bBadRep, bool bRemoveNow);
 	static bool _ProcessMessages(CNetChan* pChan, bf_read* pMsg);
 
+	static void _FlowNewPacket(CNetChan* pChan, int flow, int outSeqNr, int inSeqNr, int nChoked, int nDropped, int nSize);
+
 	void SetChoked();
 	void SetRemoteFramerate(float flFrameTime, float flFrameTimeStdDeviation);
 	inline void SetRemoteCPUStatistics(uint8_t nStats) { m_nServerCPU = nStats; }
@@ -251,6 +256,7 @@ class VNetChan : public IDetour
 		LogFunAdr("CNetChan::Clear", p_NetChan_Clear.GetPtr());
 		LogFunAdr("CNetChan::Shutdown", p_NetChan_Shutdown.GetPtr());
 		LogFunAdr("CNetChan::CanPacket", p_NetChan_CanPacket.GetPtr());
+		LogFunAdr("CNetChan::FlowNewPacket", p_NetChan_FlowNewPacket.GetPtr());
 		LogFunAdr("CNetChan::SendDatagram", p_NetChan_SendDatagram.GetPtr());
 		LogFunAdr("CNetChan::ProcessMessages", p_NetChan_ProcessMessages.GetPtr());
 	}
@@ -265,6 +271,9 @@ class VNetChan : public IDetour
 		p_NetChan_CanPacket = g_GameDll.FindPatternSIMD("40 53 48 83 EC 20 83 B9 ?? ?? ?? ?? ?? 48 8B D9 75 15 48 8B 05 ?? ?? ?? ??");
 		v_NetChan_CanPacket = p_NetChan_CanPacket.RCast<bool (*)(const CNetChan*)>();
 
+		p_NetChan_FlowNewPacket = g_GameDll.FindPatternSIMD("44 89 4C 24 ?? 44 89 44 24 ?? 89 54 24 10 56");
+		v_NetChan_FlowNewPacket = p_NetChan_FlowNewPacket.RCast<void (*)(CNetChan*, int, int, int, int, int, int)>();
+
 		p_NetChan_SendDatagram = g_GameDll.FindPatternSIMD("48 89 5C 24 ?? 55 56 57 41 56 41 57 48 83 EC 70");
 		v_NetChan_SendDatagram = p_NetChan_SendDatagram.RCast<int (*)(CNetChan*, bf_write*)>();