private bool ProcessForwardMiniguns(ref int p, byte[] d, long bseq, float sendertime)
        {
            int count = d[p];

            p++;

            for (int i = 0; i < count; i++)
            {
                var id     = NetworkDataTools.GetByte(d[p + 0]);
                var ifrac  = NetworkDataTools.GetHighBits(d[p + 1], 3);
                var boost  = NetworkDataTools.GetLowBits(d[p + 1], 5);
                var rotA   = NetworkDataTools.ConvertToRadians(NetworkDataTools.GetByte(d[p + 2]), 8);
                var rotT   = NetworkDataTools.ConvertToRadians(NetworkDataTools.GetByte(d[p + 3]), 8);
                var hp     = NetworkDataTools.GetByte(d[p + 4]) / 255f;
                var chrg   = NetworkDataTools.GetByte(d[p + 5]) / 255f;
                var shield = NetworkDataTools.GetByteFloorRange(d[p + 6], 0, Cannon.MAX_SHIELD_TIME);

                var frac = Screen.GetFractionByID(ifrac, out bool gfbiError);
                if (gfbiError)
                {
                    SAMLog.Error("SNS-COMMON::PFMG_GFBI", "GetFractionByID returned error: Unknown Fraction " + ifrac + "\nData:\n" + ByteUtils.CompressBytesForStorage(d));
                    return(false);
                }

                Cannon c;
                if (Screen.CannonMap.TryGetValue(id, out c))
                {
                    MinigunCannon bc = c as MinigunCannon;
                    if (bc != null && ShouldRecieveData(frac, bc))
                    {
                        if (ShouldRecieveRotationData(frac, bc))
                        {
                            bc.RemoteRotationUpdate(rotA, rotT, sendertime);
                        }

                        if (ShouldRecieveStateData(frac, bc))
                        {
                            bc.RemoteUpdate(frac, hp, boost, chrg, shield, sendertime);
                        }
                    }
                }

                p += PLEN_MINIGUN;
            }

            return(true);
        }
        private bool ProcessForwardLaserCannons(ref int p, byte[] d, long bseq, float sendertime)
        {
            int count = d[p];

            p++;

            for (int i = 0; i < count; i++)
            {
                var id     = NetworkDataTools.GetByte(d[p + 0]);
                var ifrac  = NetworkDataTools.GetHighBits(d[p + 1], 3);
                var boost  = NetworkDataTools.GetLowBits(d[p + 1], 5);
                var rotA   = NetworkDataTools.GetSingle(d[p + 2], d[p + 3], d[p + 4], d[p + 5]);
                var rotT   = NetworkDataTools.GetSingle(d[p + 6], d[p + 7], d[p + 8], d[p + 9]);
                var hp     = NetworkDataTools.GetByte(d[p + 10]) / 255f;
                var ct     = NetworkDataTools.GetByteFloorRange(d[p + 11], 0, Cannon.LASER_CHARGE_COOLDOWN_MAX);
                var shield = NetworkDataTools.GetByteFloorRange(d[p + 12], 0, Cannon.MAX_SHIELD_TIME);

                var frac = Screen.GetFractionByID(ifrac, out bool gfbiError);
                if (gfbiError)
                {
                    SAMLog.Error("SNS-COMMON::PFLC_GFBI", "GetFractionByID returned error: Unknown Fraction " + ifrac + "\nData:\n" + ByteUtils.CompressBytesForStorage(d));
                    return(false);
                }

                Cannon c;
                if (Screen.CannonMap.TryGetValue(id, out c))
                {
                    LaserCannon bc = c as LaserCannon;
                    if (bc != null && ShouldRecieveData(frac, bc))
                    {
                        if (ShouldRecieveRotationData(frac, bc))
                        {
                            bc.RemoteRotationUpdate(rotA, rotT, sendertime);
                        }

                        if (ShouldRecieveStateData(frac, bc))
                        {
                            bc.RemoteUpdate(frac, hp, boost, ct, shield, sendertime);
                        }
                    }
                }

                p += PLEN_LASERCANNON;
            }

            return(true);
        }
        private void ProcessForwardMiniguns(ref int p, byte[] d, long bseq, float sendertime)
        {
            int count = d[p];

            p++;

            for (int i = 0; i < count; i++)
            {
                var id     = NetworkDataTools.GetByte(d[p + 0]);
                var frac   = Screen.GetFractionByID(NetworkDataTools.GetHighBits(d[p + 1], 3));
                var boost  = NetworkDataTools.GetLowBits(d[p + 1], 5);
                var rotA   = NetworkDataTools.ConvertToRadians(NetworkDataTools.GetByte(d[p + 2]), 8);
                var rotT   = NetworkDataTools.ConvertToRadians(NetworkDataTools.GetByte(d[p + 3]), 8);
                var hp     = NetworkDataTools.GetByte(d[p + 4]) / 255f;
                var chrg   = NetworkDataTools.GetByte(d[p + 5]) / 255f;
                var shield = NetworkDataTools.GetByteFloorRange(d[p + 6], 0, Cannon.MAX_SHIELD_TIME);

                Cannon c;
                if (Screen.CannonMap.TryGetValue(id, out c))
                {
                    MinigunCannon bc = c as MinigunCannon;
                    if (bc != null && ShouldRecieveData(frac, bc))
                    {
                        if (ShouldRecieveRotationData(frac, bc))
                        {
                            bc.RemoteRotationUpdate(rotA, rotT, sendertime);
                        }

                        if (ShouldRecieveStateData(frac, bc))
                        {
                            bc.RemoteUpdate(frac, hp, boost, chrg, shield, sendertime);
                        }
                    }
                }

                p += PLEN_MINIGUN;
            }
        }
        private void ProcessForwardLaserCannons(ref int p, byte[] d, long bseq, float sendertime)
        {
            int count = d[p];

            p++;

            for (int i = 0; i < count; i++)
            {
                var id     = NetworkDataTools.GetByte(d[p + 0]);
                var frac   = Screen.GetFractionByID(NetworkDataTools.GetHighBits(d[p + 1], 3));
                var boost  = NetworkDataTools.GetLowBits(d[p + 1], 5);
                var rotA   = NetworkDataTools.GetSingle(d[p + 2], d[p + 3], d[p + 4], d[p + 5]);
                var rotT   = NetworkDataTools.GetSingle(d[p + 6], d[p + 7], d[p + 8], d[p + 9]);
                var hp     = NetworkDataTools.GetByte(d[p + 10]) / 255f;
                var ct     = NetworkDataTools.GetByteFloorRange(d[p + 11], 0, Cannon.LASER_CHARGE_COOLDOWN_MAX);
                var shield = NetworkDataTools.GetByteFloorRange(d[p + 12], 0, Cannon.MAX_SHIELD_TIME);

                Cannon c;
                if (Screen.CannonMap.TryGetValue(id, out c))
                {
                    LaserCannon bc = c as LaserCannon;
                    if (bc != null && ShouldRecieveData(frac, bc))
                    {
                        if (ShouldRecieveRotationData(frac, bc))
                        {
                            bc.RemoteRotationUpdate(rotA, rotT, sendertime);
                        }

                        if (ShouldRecieveStateData(frac, bc))
                        {
                            bc.RemoteUpdate(frac, hp, boost, ct, shield, sendertime);
                        }
                    }
                }

                p += PLEN_LASERCANNON;
            }
        }
        private void ProcessForwardShieldProjectors(ref int p, byte[] d, long bseq, float sendertime)
        {
            int count = d[p];

            p++;

            for (int i = 0; i < count; i++)
            {
                var id    = NetworkDataTools.GetByte(d[p + 0]);
                var frac  = Screen.GetFractionByID(NetworkDataTools.GetHighBits(d[p + 1], 3));
                var boost = NetworkDataTools.GetLowBits(d[p + 1], 5);
                var rotA  = NetworkDataTools.GetSingle(d[p + 2], d[p + 3], d[p + 4], d[p + 5]);
                var rotT  = NetworkDataTools.GetSingle(d[p + 6], d[p + 7], d[p + 8], d[p + 9]);
                var hp    = NetworkDataTools.GetByte(d[p + 10]) / 255f;
                var ct    = (NetworkDataTools.GetByte(d[p + 11]) / 255f) * Cannon.SHIELDLASER_CHARGE_COOLDOWN_MAX;

                Cannon c;
                if (Screen.CannonMap.TryGetValue(id, out c))
                {
                    ShieldProjectorCannon sc = c as ShieldProjectorCannon;
                    if (sc != null && ShouldRecieveData(frac, sc))
                    {
                        if (ShouldRecieveRotationData(frac, sc))
                        {
                            sc.RemoteRotationUpdate(rotA, rotT, sendertime);
                        }

                        if (ShouldRecieveStateData(frac, sc))
                        {
                            sc.RemoteUpdate(frac, hp, boost, ct, sendertime);
                        }
                    }
                }

                p += PLEN_SHIELDPROJECTOR;
            }
        }
        private void ProcessForwardRelayCannons(ref int p, byte[] d, long bseq, float sendertime)
        {
            int count = d[p];

            p++;

            for (int i = 0; i < count; i++)
            {
                var id     = NetworkDataTools.GetByte(d[p + 0]);
                var frac   = Screen.GetFractionByID(NetworkDataTools.GetHighBits(d[p + 1], 3));
                var boost  = NetworkDataTools.GetLowBits(d[p + 1], 5);
                var rotA   = NetworkDataTools.ConvertToRadians(NetworkDataTools.GetByte(d[p + 2]), 8);
                var rotT   = NetworkDataTools.ConvertToRadians(NetworkDataTools.GetByte(d[p + 3]), 8);
                var shield = NetworkDataTools.GetByteFloorRange(d[p + 4], 0, Cannon.MAX_SHIELD_TIME);

                Cannon c;
                if (Screen.CannonMap.TryGetValue(id, out c))
                {
                    RelayCannon rc = c as RelayCannon;
                    if (rc != null && ShouldRecieveData(frac, rc))
                    {
                        if (ShouldRecieveRotationData(frac, rc))
                        {
                            rc.RemoteRotationUpdate(rotA, rotT, sendertime);
                        }

                        if (ShouldRecieveStateData(frac, rc))
                        {
                            rc.RemoteUpdate(frac, sendertime, shield);
                        }
                    }
                }

                p += PLEN_RELAYCANNON;
            }
        }
        private void ProcessForwardBullets(ref int p, byte[] d, long bseq, float sendertime)
        {
            int count = d[p];

            p++;

            for (int i = 0; i < count; i++)
            {
                var id    = NetworkDataTools.GetSplitBits(d[p + 0], d[p + 1], 8, 4);
                var state = (RemoteBullet.RemoteBulletState)NetworkDataTools.GetLowBits(d[p + 1], 4);

                var ipx = NetworkDataTools.GetUInt16(d[p + 2], d[p + 3]);
                var ipy = NetworkDataTools.GetUInt16(d[p + 4], d[p + 5]);
                Screen.DoubleByteToPosition(ipx, ipy, out float px, out float py);

                var rot   = NetworkDataTools.ConvertToRadians(NetworkDataTools.GetSplitBits(d[p + 6], d[p + 7], 8, 2), 10);
                var len   = NetworkDataTools.GetSplitBits(d[p + 7], d[p + 8], 6, 5) / 8f;
                var veloc = new Vector2(len, 0).Rotate(rot);

                var fraction = Screen.GetFractionByID(NetworkDataTools.GetLowBits(d[p + 8], 3));
                var scale    = 16 * (d[p + 9] / 255f);

                var bullet = Screen.RemoteBulletMapping[id];

                switch (state)
                {
                case RemoteBullet.RemoteBulletState.Normal:
                    if (bullet != null)
                    {
                        bullet.RemoteUpdate(state, px, py, veloc, fraction, scale, bseq, sendertime);
                    }
                    else
                    {
                        Screen.RemoteBulletMapping[id]             = new RemoteBullet(Screen, new FPoint(px, py), veloc, id, scale, fraction, bseq);
                        Screen.RemoteBulletMapping[id].RemoteState = state;
                        Screen.Entities.AddEntity(Screen.RemoteBulletMapping[id]);

                        Screen.RemoteBulletMapping[id].RemoteUpdate(state, px, py, veloc, fraction, scale, bseq, sendertime);
                        Screen.RemoteBulletMapping[id].ClientPredictionMiss = false;
                    }
                    break;

                case RemoteBullet.RemoteBulletState.Dying_Explosion:
                case RemoteBullet.RemoteBulletState.Dying_ShrinkSlow:
                case RemoteBullet.RemoteBulletState.Dying_ShrinkFast:
                case RemoteBullet.RemoteBulletState.Dying_Fade:
                case RemoteBullet.RemoteBulletState.Dying_Instant:
                case RemoteBullet.RemoteBulletState.Dying_FadeSlow:
                    if (bullet != null && bullet.RemoteState != state)
                    {
                        bullet.RemoteUpdate(state, px, py, veloc, fraction, scale, bseq, sendertime);
                    }
                    break;

                default:
                    SAMLog.Error("GDMC::EnumSwitch_PFB", "Unknown enum value: " + state);
                    break;
                }

                p += PLEN_BULLETS;
            }

            for (int i = 0; i < GDGameScreen.MAX_BULLET_ID; i++)
            {
                if (Screen.RemoteBulletMapping[i] != null && bseq - Screen.RemoteBulletMapping[i].LastUpdateBigSeq > REMOTE_BULLET_UPDATELESS_LIFETIME)
                {
                    if (Screen.RemoteBulletMapping[i].RemoteState == RemoteBullet.RemoteBulletState.Normal)
                    {
                        SAMLog.Debug("Mercykill Bullet: " + i);
                        Screen.RemoteBulletMapping[i].Alive = false;
                    }
                    else
                    {
                        // all ok - its dying
                    }
                }
            }
        }