public override bool Serialize(BitStream stream, EndpointId forClient, uint timestamp, byte packetId, int maxBitPosition)
        {
            bool lowPrecisionOrientation = true;
            bool applyWhenReading = true;
            SetSupport(FindSupportDelegate());
            if (stream.Writing)
            {
                bool moving = IsMoving(Entity);
                stream.WriteBool(moving);
                SerializeVelocities(stream, Entity, MyEntityPhysicsStateGroup.EffectiveSimulationRatio, applyWhenReading, moving);
                SerializeTransform(stream, Entity, null, lowPrecisionOrientation, applyWhenReading, moving, timestamp);
            }
            else
            {
                bool moving = stream.ReadBool();
                // reading
                SerializeServerVelocities(stream, Entity, MyEntityPhysicsStateGroup.EffectiveSimulationRatio, moving, ref Entity.m_serverLinearVelocity, ref Entity.m_serverAngularVelocity);

                applyWhenReading = SerializeServerTransform(stream, Entity, null, moving, timestamp, lowPrecisionOrientation,
                    ref Entity.m_serverPosition, ref Entity.m_serverOrientation, ref Entity.m_serverWorldMatrix, m_positionValidation);

                if (applyWhenReading && moving)
                {
                    Entity.PositionComp.SetWorldMatrix(Entity.m_serverWorldMatrix, null, true);
                    Entity.SetSpeedsAccordingToServerValues();
                }
            }

            SerializeFriction(stream, Entity);
            SerializeActive(stream, Entity);

            return true;
        }
 protected void SerializeActive(BitStream stream, MyEntity entity)
 {
     if (stream.Writing)
     {
         if (entity.Physics.RigidBody != null && entity.Physics.RigidBody.IsActive)
             stream.WriteBool(true);
         else
             stream.WriteBool(false);
     }
     else
     {
         // reading
         bool isActive = stream.ReadBool();
         if (entity != null && entity.Physics != null)
         {
             HkRigidBody rb = entity.Physics.RigidBody;
             if (rb != null)
             {
                 if (isActive)
                     rb.Activate();
                 else
                     rb.Deactivate();
             }
         }
     }
 }
        public override bool Serialize(BitStream stream, EndpointId forClient, uint timestamp, byte packetId, int maxBitPosition)
        {
            bool lowPrecisionOrientation = true;
            bool applyWhenReading = true;
            if (stream.Writing)
            {
                bool moving = IsMoving(Entity);
                stream.WriteBool(moving);
                SerializeVelocities(stream, Entity, MyEntityPhysicsStateGroup.EffectiveSimulationRatio, applyWhenReading, moving);
                SerializeTransform(stream, Entity, null, lowPrecisionOrientation, applyWhenReading, moving, timestamp);
            }
            else
            {
                bool moving = stream.ReadBool();
                // reading
                SerializeServerVelocities(stream, Entity, MyEntityPhysicsStateGroup.EffectiveSimulationRatio, moving, ref Entity.m_serverLinearVelocity, ref Entity.m_serverAngularVelocity);
                float positionTolerancy = Math.Max(Entity.PositionComp.MaximalSize * 0.1f, 0.1f);
                float smallSpeed = 0.1f;
                if (Entity.m_serverLinearVelocity == Vector3.Zero || Entity.m_serverLinearVelocity.Length() < smallSpeed)
                {
                    positionTolerancy = Math.Max(Entity.PositionComp.MaximalSize * 0.5f, 1.0f);
                }

                applyWhenReading = SerializeServerTransform(stream, Entity, null, moving, timestamp, lowPrecisionOrientation, positionTolerancy,
                    ref Entity.m_serverPosition, ref Entity.m_serverOrientation, ref Entity.m_serverWorldMatrix, m_positionValidation);

                if (applyWhenReading && moving)
                {
                    Entity.PositionComp.SetWorldMatrix(Entity.m_serverWorldMatrix, null, true);
                    Entity.SetSpeedsAccordingToServerValues();
                }
            }

            SerializeFriction(stream, Entity);
            SerializeActive(stream, Entity);

            return true;
        }
        public override void SerializePhysics(BitStream stream, MyNetworkClient sender, bool highOrientationCompression = false)
        {
            // Usually 59 B

            // Base stuff (position, orientation, velocities)
            base.SerializePhysics(stream, sender, true); // 50.5 B

            if (MyFakes.CHARACTER_SERVER_SYNC)
            {
                // TODO: Serialize move and rotate when necesary
            }

            if (stream.Writing)
            {
                // Head and spine stuff, 36 - 152b (4.5B - 19 B)
                stream.WriteHalf(Entity.HeadLocalXAngle); // 2B
                stream.WriteHalf(Entity.HeadLocalYAngle); // 2B

                // TODO: Spine has only one angle (bending forward backward)
                stream.WriteQuaternionNormCompressedIdentity(Entity.GetAdditionalRotation(Entity.Definition.SpineBone)); // 1b / 30b
                stream.WriteQuaternionNormCompressedIdentity(Entity.GetAdditionalRotation(Entity.Definition.HeadBone)); // 1b / 30b
                stream.WriteQuaternionNormCompressedIdentity(Entity.GetAdditionalRotation(Entity.Definition.LeftForearmBone)); // 1b / 30b
                stream.WriteQuaternionNormCompressedIdentity(Entity.GetAdditionalRotation(Entity.Definition.LeftUpperarmBone)); // 1b / 30b

                // Movement state, 2B
                stream.WriteUInt16((ushort)Entity.GetCurrentMovementState());

                // Flags, 6 bits
                stream.WriteBool(Entity.JetpackComp != null);
                if (Entity.JetpackComp != null)
                {
                    stream.WriteBool(Entity.JetpackComp.TurnedOn);
                    stream.WriteBool(Entity.JetpackComp.DampenersTurnedOn);
                }

                stream.WriteBool(Entity.LightEnabled); // TODO: Remove
                stream.WriteBool(Entity.ZoomMode == MyZoomModeEnum.IronSight);
                stream.WriteBool(Entity.RadioBroadcaster.WantsToBeEnabled); // TODO: Remove
                stream.WriteBool(Entity.TargetFromCamera);

                if (MyFakes.CHARACTER_SERVER_SYNC)
                {
                    Vector3 temp = Entity.MoveIndicator;
                    stream.WriteHalf(temp.X);
                    stream.WriteHalf(temp.Y);
                    stream.WriteHalf(temp.Z);

                    Vector2 rotation = Entity.RotationIndicator;
                    stream.WriteHalf(rotation.X);
                    stream.WriteHalf(rotation.Y);

                    stream.WriteHalf(Entity.Roll);

                }
            }
            else
            {
                // Head and spine stuff
                float headX = stream.ReadHalf();
                float headY = stream.ReadHalf();
                Quaternion spine = stream.ReadQuaternionNormCompressedIdentity();
                Quaternion head = stream.ReadQuaternionNormCompressedIdentity();
                Quaternion hand = stream.ReadQuaternionNormCompressedIdentity();
                Quaternion upperArm = stream.ReadQuaternionNormCompressedIdentity();
                var handler0 = HeadOrSpineChanged;
                if (handler0 != null) handler0(headX, headY, spine, head, hand, upperArm);

                // Movement state
                MyCharacterMovementEnum movementState = (MyCharacterMovementEnum)stream.ReadUInt16();
                var handler = MovementStateChanged;
                if (handler != null && Entity.GetCurrentMovementState() != movementState) handler(movementState);

                // Flags
                bool hasJetpack = stream.ReadBool();
                bool jetpack = false;
                bool dampeners = false;

                if (hasJetpack)
                {
                    jetpack = stream.ReadBool();
                    dampeners = stream.ReadBool();
                }
                bool lights = stream.ReadBool(); // TODO: Remove
                bool ironsight = stream.ReadBool();
                bool broadcast = stream.ReadBool(); // TODO: Remove
                bool targetFromCamera = stream.ReadBool();

                if (MyFakes.CHARACTER_SERVER_SYNC)
                {
                    Vector3 temp = Vector3.Zero;
                    temp.X = stream.ReadHalf();
                    temp.Y = stream.ReadHalf();
                    temp.Z = stream.ReadHalf();

                    Entity.MoveIndicator = temp;

                    Vector2 rotation = Vector2.Zero;
                    rotation.X = stream.ReadHalf();
                    rotation.Y = stream.ReadHalf();

                    Entity.RotationIndicator = rotation;

                    Entity.Roll = stream.ReadHalf();
                }

                var handler2 = FlagsChanged;
                if (handler2 != null) handler2(jetpack, dampeners, lights, ironsight, broadcast, targetFromCamera);
            }
        }
 private void ReadPhysics(BitStream stream, MyNetworkClient sender, MyEntity controlledEntity)
 {
     var stateGroup = MyExternalReplicable.FindByObject(controlledEntity).FindStateGroup<MyEntityPhysicsStateGroup>();
     bool hasPhysics = stream.ReadBool();
     if (hasPhysics && stateGroup.ResponsibleForUpdate(new EndpointId(sender.SteamUserId)))
     {
         stateGroup.Serialize(stream, null, 0, 65535);
     }
 }
        private void ReadShared(BitStream stream, MyNetworkClient sender, out MyEntity controlledEntity)
        {
            controlledEntity = null;

            var hasControlledEntity = stream.ReadBool();
            if (!hasControlledEntity)
            {
                Vector3D pos = Vector3D.Zero;
                stream.Serialize(ref pos); // 24B
                Position = pos;
            }
            else
            {
                var entityId = stream.ReadInt64();
                MyEntity entity;
                if (!MyEntities.TryGetEntityById(entityId, out entity))
                    return;

                Position = entity.WorldMatrix.Translation;

                // TODO: Obsolete check?
                MySyncEntity syncEntity = entity.SyncObject as MySyncEntity;
                if (syncEntity == null)
                    return;
                controlledEntity = entity;
            }
        }
        private void ReadPhysics(BitStream stream, MyNetworkClient sender, MyEntity controlledEntity,uint serverTimeStamp)
        {
            
            bool hasPhysics = stream.ReadBool();

            //if (m_currentServerTimeStamp == serverTimeStamp)
            //{
            //    return;
            //}

            m_currentServerTimeStamp = serverTimeStamp;

            if (hasPhysics && MyEntityPhysicsStateGroup.ResponsibleForUpdate(controlledEntity, new EndpointId(sender.SteamUserId)))
            {
                IMyStateGroup stateGroup = null;

                bool enableControlOnServer = stream.ReadBool();
                bool stateGroupFound = stream.ReadBool();
                if (stateGroupFound == false)
                {
                    return;
                }

                if (enableControlOnServer)
                {
                    stateGroup = MyExternalReplicable.FindByObject(controlledEntity).FindStateGroup<MyEntityPositionVerificationStateGroup>();
                }
                else
                {
                    stateGroup = MyExternalReplicable.FindByObject(controlledEntity).FindStateGroup<MyEntityPhysicsStateGroup>();
                }

                if (stream.ReadBool())
                {
                    stateGroup.Serialize(stream, new EndpointId(sender.SteamUserId), ClientTimeStamp, 0, 65535);
                }
            }
        }
        private void ReadInventory(BitStream stream)
        {
            if(stream.ReadBool() == false)       
            {
                return;
            }

            if(m_recievedPacketIds == null)
            {
                m_recievedPacketIds = new MyQueue<uint>(RECIEVED_PACKET_HISTORY);
            }

            uint packetId = stream.ReadUInt32();

            bool apply = true;
            if (m_recievedPacketIds.Count == RECIEVED_PACKET_HISTORY)
            {
                m_recievedPacketIds.Dequeue();
            }

            if (m_recievedPacketIds.InternalArray.Contains(packetId) == false)
            {
                m_recievedPacketIds.Enqueue(packetId);
            }
            else
            {
                apply = false;
            }

            bool hasItems = stream.ReadBool();
            if(hasItems)
            {
                int numItems = stream.ReadInt32();

                for (int i = 0; i < numItems; ++i)
                {
                    uint itemId = stream.ReadUInt32();
                    MyFixedPoint amout = new MyFixedPoint();
                    amout.RawValue = stream.ReadInt64();

                    if (apply)
                    {
                        Inventory.UpdateItemAmoutClient(itemId, amout);
                    }
                }
            }

            hasItems = stream.ReadBool();
            if (hasItems)
            {
                int numItems = stream.ReadInt32();
                for (int i = 0; i < numItems; ++i)
                {
                    uint itemId = stream.ReadUInt32();
                    if (apply)
                    {
                        Inventory.RemoveItemClient(itemId);
                    }
                }
            }

            hasItems = stream.ReadBool();
            if (hasItems)
            {
                int numItems = stream.ReadInt32();

                for (int i = 0; i < numItems; ++i)
                {
                    int position = stream.ReadInt32();
                    MyPhysicalInventoryItem item;
                    VRage.Serialization.MySerializer.CreateAndRead(stream, out item, MyObjectBuilderSerializer.Dynamic);
                    if (apply)
                    {
                        Inventory.AddItemClient(position, item);
                    }
                }
            }

            hasItems = stream.ReadBool();
            if (hasItems)
            {
                int numItems = stream.ReadInt32();

                for (int i = 0; i < numItems; ++i)
                {
                    int position = stream.ReadInt32();
                    int newPosition = stream.ReadInt32();
                    if (apply)
                    {
                        Inventory.SwapItemClient(position, newPosition);
                    }
                }
            }

            Inventory.Refresh();
        }
        public void DeserializeDefault(BitStream bs)
        {
            bool isDefault = bs.ReadBool();

            if (!isDefault)
            {
                foreach (var mySyncedObject in m_syncedClass)
                {
                    mySyncedObject.DeserializeDefault(bs);
                }

                foreach (var mySynced in m_syncedVariables)
                {
                    mySynced.DeserializeDefault(bs);
                }
            }
        }
        public static void ReadSubGrids(BitStream stream, uint timestamp, bool apply,bool lowPrecisionOrientation, ref Vector3D basePos)
        {
            while (stream.ReadBool())
            {
                NetworkId networkId = stream.ReadNetworkId(); // ~2 bytes
                MyCubeGridReplicable replicable = MyMultiplayer.Static.ReplicationLayer.GetObjectByNetworkId(networkId) as MyCubeGridReplicable;
                MyCubeGrid grid = replicable != null ? replicable.Grid : null;

                bool moving = stream.ReadBool();
                SerializeTransform(stream, grid, basePos, lowPrecisionOrientation, apply && grid != null, moving, timestamp, null, null); // 12.5 bytes
                SerializeVelocities(stream, grid, EffectiveSimulationRatio, apply && grid != null, moving); // 12 bytes

                UpdateGridMaxSpeed(grid, !Sync.IsServer);
            }
        }
Beispiel #11
0
        public virtual bool Serialize(BitStream stream, EndpointId forClient,uint timestamp, byte packetId, int maxBitPosition)
        {
            bool moving = false;
            if (stream.Writing)
            {
                moving = IsMoving(Entity);
                stream.WriteBool(moving);
            }
            else
            {
                moving = stream.ReadBool();
            }

            // When controlled by local player, don't apply what came from server
            SerializeTransform(stream, Entity, null, m_lowPrecisionOrientation, !IsControlledLocally, moving, timestamp, null, MoveHandler);
            SerializeVelocities(stream, Entity, EffectiveSimulationRatio, !IsControlledLocally, moving,VelocityHandler);

            return true;
        }
        /// <summary>
        /// Serializes physics and takes into account support (what's entity standing on)
        /// </summary>
        private void SerializePhysicsWithSupport(BitStream stream, EndpointId forClient,uint timestamp, byte packetId, int maxBitPosition)
        {
            if (stream.Writing)
            {
                // TODO: only prototype implementation
                SetSupport(FindSupportDelegate());

                stream.WriteBool(m_supportPhysics != null);
                if (m_supportPhysics != null)
                {
                    stream.WriteInt64(m_supportPhysics.Entity.EntityId);
                    var localToParent = Entity.WorldMatrix * MatrixD.Invert(m_supportPhysics.Entity.PositionComp.WorldMatrix);
                    stream.Write(localToParent.Translation);
                    stream.Write(Quaternion.CreateFromForwardUp(localToParent.Forward, localToParent.Up).ToVector4());
                    bool moving = IsMoving(Entity);
                    stream.WriteBool(moving);

                    SerializeVelocities(stream, Entity, EffectiveSimulationRatio, !IsControlledLocally, moving);
                }
                else
                {
                    base.Serialize(stream, forClient,timestamp, packetId, maxBitPosition);
                }
            }
            else
            {
                if (stream.ReadBool())
                {
                    MyEntity support;
                    bool apply = MyEntities.TryGetEntityById(stream.ReadInt64(), out support) && !IsControlledLocally;

                    var pos = stream.ReadVector3D();
                    var orient = Quaternion.FromVector4(stream.ReadVector4());

                    if (apply)
                    {
                        var old = Entity.PositionComp.WorldMatrix;

                        MatrixD localToParent = MatrixD.CreateFromQuaternion(orient);
                        localToParent.Translation = pos;
                        MatrixD matrix = localToParent * support.WorldMatrix;
                        Entity.PositionComp.SetWorldMatrix(matrix, null, true);

                        SetSupport(MySupportHelper.FindPhysics(support));

                        var handler = MoveHandler;
                        if (handler != null)
                        {
                            handler(ref old, ref matrix);
                        }
                    }
                    else
                    {
                        SetSupport(null);
                    }
                    bool moving = stream.ReadBool();
                    SerializeVelocities(stream, Entity, EffectiveSimulationRatio, apply, moving);

                }
                else
                {
                    SetSupport(null);
                    base.Serialize(stream, forClient, timestamp, packetId, maxBitPosition);
                }
            }
        }
        static MyCharacterNetState ReadCharacterState(BitStream stream, out Vector3 move)
        {
            MyCharacterNetState charNetState = new MyCharacterNetState();

            charNetState.WorldRealSpeed = stream.ReadHalf();
            // Head and spine stuff
            charNetState.HeadX = stream.ReadHalf();
            if (charNetState.HeadX.IsValid() == false)
            {
                charNetState.HeadX = 0.0f;
            }
            charNetState.HeadY = stream.ReadHalf();
            charNetState.Spine = stream.ReadQuaternionNormCompressedIdentity();
            charNetState.Head = stream.ReadQuaternionNormCompressedIdentity();
            // Movement state
            charNetState.MovementState = (MyCharacterMovementEnum)stream.ReadUInt16();
            // Movement flag
            charNetState.MovementFlag = (MyCharacterMovementFlags)stream.ReadUInt16();
            //Flags
            charNetState.Jetpack = stream.ReadBool();
            charNetState.Dampeners = stream.ReadBool();
            charNetState.Lights = stream.ReadBool(); // TODO: Remove
            charNetState.Ironsight = stream.ReadBool();
            charNetState.Broadcast = stream.ReadBool(); // TODO: Remove
            charNetState.TargetFromCamera = stream.ReadBool();

            move = stream.ReadNormalizedSignedVector3(8);

            return charNetState;
        }
Beispiel #14
0
        void Read(BitStream stream)
        {
            // TODO: Read additional client data, context

            MyNetworkClient sender;
            if (!Sync.Clients.TryGetClient(EndpointId.Value, out sender))
            {
                Debug.Fail("Unknown sender");
                return;
            }

            var hasControlledEntity = stream.ReadBool();
            if (hasControlledEntity == false)
            {
                Vector3D pos = Vector3D.Zero;
                stream.Serialize(ref pos); // 24B
                Position = pos;
            }
            else
            {
                int numEntity = 0;
                if (stream.BytePosition < stream.ByteLength)
                {
                    var entityId = stream.ReadInt64();
                    MyEntity entity;
                    if (!MyEntities.TryGetEntityById(entityId, out entity))
                        return;

                    MySyncEntity syncEntity = entity.SyncObject as MySyncEntity;
                    if (syncEntity == null)
                        return;

                    Context = (MyContextKind)stream.ReadInt32(2);

                    switch (Context)
                    {
                        case MyContextKind.Inventory:
                            entityId = stream.ReadInt64();
                            break;
                        case MyContextKind.Terminal:
                            entityId = stream.ReadInt64();
                            break;
                        case MyContextKind.Production:
                            entityId = stream.ReadInt64();
                            break;
                        default:
                            entityId = stream.ReadInt64();
                            break;
                    }

                    MyEntities.TryGetEntityById(entityId, out entity);
                    ContextEntity = entity;

                    if (!syncEntity.ResponsibleForUpdate(sender))
                    {
                        // Also happens when entering cockpit due to order of operations and responsibility update change
                        //Debug.Fail("Server sending entity update for entity controlled by client, should happen only very rarely (packets out-of-order)");
                        return;
                    }
                    syncEntity.SerializePhysics(stream, sender);

                    if (numEntity == 0)
                    {
                        Position = syncEntity.Entity.WorldMatrix.Translation;
                    }
                    numEntity++;
                }
            }
        }
Beispiel #15
0
        bool ReadTransform(BitStream stream, MyEntity entity, Vector3D? deltaPosBase, bool applyWhenReading, bool movingOnServer, ref Vector3D outPosition, ref Quaternion outOrientation, ref MatrixD outWorldMartix, Func<MyEntity, Vector3D, bool> posValidation = null, MovedDelegate moveHandler = null)
        {
            Vector3D position;
            if (stream.ReadBool())
            {
                position = stream.ReadVector3D(); // 24 B
            }
            else
            {
                Vector3 pos = stream.ReadVector3(); // 6 B
                if (deltaPosBase != null)
                {
                    position = pos + deltaPosBase.Value;
                }
                else
                {
                    position = pos;
                }
            }
            Quaternion orientation;
            bool lowPrecisionOrientation = stream.ReadBool();
            if (lowPrecisionOrientation)
            {
                orientation = stream.ReadQuaternionNormCompressed(); // 29b
            }
            else
            {
                orientation = stream.ReadQuaternionNorm(); // 52b
            }

            if (entity != null)
            {
                movingOnServer |= (entity.PositionComp.GetPosition() - position).LengthSquared() > epsilonSq;

                if (movingOnServer && applyWhenReading && (posValidation == null || posValidation(entity, position)))
                {
                    MatrixD matrix = MatrixD.CreateFromQuaternion(orientation);
                    if (matrix.IsValid())
                    {
                        matrix.Translation = position;

                        outPosition = matrix.Translation;
                        outOrientation = orientation;
                        outWorldMartix = matrix;
                        return true;
                    }
                    return false;
                }
            }
            return false;
        }
        public override bool Serialize(BitStream stream, EndpointId forClient,uint timestamp, byte packetId, int maxBitPosition)
        {
            // Client does not care about slave grids, he always synced group through controlled object
            Debug.Assert(stream.Reading || !Sync.IsServer || Entity == GetMasterGrid(Entity), "Writing data from SlaveGrid!");

            bool apply = !IsControlledLocally;

            bool moving = false;
            if (stream.Writing)
            {
                moving = IsMoving(Entity);
                stream.WriteBool(moving);
            }
            else
            {
                moving = stream.ReadBool();
            }


            // Serialize this grid
            apply = SerializeTransform(stream, Entity, null, m_lowPrecisionOrientation, apply,moving, timestamp, m_positionValidation, MoveHandler);
            SerializeVelocities(stream, Entity, EffectiveSimulationRatio, apply, moving,VelocityHandler);

     
            // Serialize other grids in group
            Vector3D basePos = Entity.WorldMatrix.Translation;
            if (stream.Writing)
            {
 
                UpdateGridMaxSpeed(Entity, Sync.IsServer);

                bool fullyWritten = WriteSubgrids(Entity,stream, ref forClient, timestamp, maxBitPosition,m_lowPrecisionOrientation, ref basePos, ref m_currentSentPosition);

                stream.WriteBool(fullyWritten);

                if (fullyWritten)
                {
                    SerializeRopeData(stream, apply, gridsGroup: m_groups);
                }
                return fullyWritten;

            }
            else
            {
                UpdateGridMaxSpeed(Entity, !Sync.IsServer);

                ReadSubGrids(stream, timestamp, apply,m_lowPrecisionOrientation, ref basePos);

                if (stream.ReadBool())
                {
                    SerializeRopeData(stream, apply);
                }
            }
            return true;
        }
        public override void Serialize(BitStream stream, MyClientStateBase forClient, byte packetId, int maxBitPosition)
        {
            // Client does not care about slave grids, he always synced group through controlled object
            Debug.Assert(stream.Reading || !Sync.IsServer || Entity == GetMasterGrid(Entity), "Writing data from SlaveGrid!");

            bool apply = !IsControlledLocally;

            bool moving = false;
            if (stream.Writing)
            {
                moving = IsMoving(Entity);
                stream.WriteBool(moving);
            }
            else
            {
                moving = stream.ReadBool();
            }

            // Serialize this grid
            apply = SerializeTransform(stream, Entity, null, m_lowPrecisionOrientation, apply,moving, m_positionValidation, MoveHandler);
            SerializeVelocities(stream, Entity, EffectiveSimulationRatio, apply, moving,VelocityHandler);

     
            // Serialize other grids in group
            Vector3D basePos = Entity.WorldMatrix.Translation;
            if (stream.Writing)
            {
                UpdateGridMaxSpeed(Entity, Sync.IsServer);
                var g = MyCubeGridGroups.Static.PhysicalDynamic.GetGroup(Entity);
                if (g == null)
                {
                    stream.WriteByte(0);
                }
                else
                {
                    m_groups.Clear();
                    int i= -1;
                    foreach (var node in g.Nodes)
                    {
                        i++;
                        if(i < m_currentSentPosition)
                        {
                            continue;
                        }
                        if (i == m_currentSentPosition + NUM_NODES_TO_SEND_ALL)
                        {
                            break;
                        }
                        var target = MyMultiplayer.Static.ReplicationLayer.GetProxyTarget((IMyEventProxy)node.NodeData);
                        if (node.NodeData != Entity && !node.NodeData.IsStatic && target != null)
                        {
                            m_groups.Add(node.NodeData);
                        }
                    }

                    m_currentSentPosition = i;
                    if (m_currentSentPosition >= g.Nodes.Count-1)
                    {
                        m_currentSentPosition = 0;
                    }
                    stream.WriteByte((byte)m_groups.Count); // Ignoring self
                    foreach (var node in m_groups)
                    {
                        var target = MyMultiplayer.Static.ReplicationLayer.GetProxyTarget((IMyEventProxy)node);

                        // ~26.5 bytes per grid, not bad
                        NetworkId networkId = MyMultiplayer.Static.ReplicationLayer.GetNetworkIdByObject(target);
                        stream.WriteNetworkId(networkId); // ~2 bytes

                        moving = IsMoving(node);
                        stream.WriteBool(moving);
               
                        SerializeTransform(stream, node, basePos, true, apply, moving,null, null); // 12.5 bytes
                        SerializeVelocities(stream, node, EffectiveSimulationRatio, apply, moving); // 12 byte
                        UpdateGridMaxSpeed(node, Sync.IsServer);
                    }
                }

                SerializeRopeData(stream, apply, gridsGroup: m_groups);
            }
            else
            {
                UpdateGridMaxSpeed(Entity, !Sync.IsServer);

                byte numRecords = stream.ReadByte();
                for (int i = 0; i < numRecords; i++)
                {               
                    NetworkId networkId = stream.ReadNetworkId(); // ~2 bytes
                    MyCubeGridReplicable replicable = MyMultiplayer.Static.ReplicationLayer.GetObjectByNetworkId(networkId) as MyCubeGridReplicable;
                    MyCubeGrid grid = replicable != null ? replicable.Grid : null;

                    moving = stream.ReadBool();
                    SerializeTransform(stream, grid, basePos, true, apply && grid != null,moving, null, null); // 12.5 bytes
                    SerializeVelocities(stream, grid, EffectiveSimulationRatio, apply && grid != null, moving); // 12 bytes
                   
                    UpdateGridMaxSpeed(grid,!Sync.IsServer);
                }

                SerializeRopeData(stream, apply);
            }
        }
        public override bool Serialize(BitStream stream, EndpointId forClient,uint timestamp, byte packetId, int maxBitPosition)
        {
            // Client does not care about slave grids, he always synced group through controlled object
            Debug.Assert(stream.Reading || !Sync.IsServer || Entity == GetMasterGrid(Entity), "Writing data from SlaveGrid!");

            bool apply = !IsControlledLocally;

            bool moving = false;
            if (stream.Writing)
            {
                moving = IsMoving(Entity);
                stream.WriteBool(moving);
            }
            else
            {
                moving = stream.ReadBool();
            }


            // Serialize this grid
            apply = SerializeTransform(stream, Entity, null, m_lowPrecisionOrientation, apply,moving, timestamp, m_positionValidation, MoveHandler);
            SerializeVelocities(stream, Entity, EffectiveSimulationRatio, apply, moving,VelocityHandler);

     
            // Serialize other grids in group
            Vector3D basePos = Entity.WorldMatrix.Translation;
            if (stream.Writing)
            {
                bool fullyWritten = true;
                UpdateGridMaxSpeed(Entity, Sync.IsServer);
                var g = MyCubeGridGroups.Static.PhysicalDynamic.GetGroup(Entity);
                if (g == null)
                {
                    stream.WriteBool(false);
                }
                else
                {
                    m_groups.Clear();
                    int i = 0;
                    foreach (var node in g.Nodes)
                    {                        
                        i++;
                        if (ResponsibleForUpdate(node.NodeData, forClient))
                        {
                            continue;
                        } 

                        if(i < m_currentSentPosition)
                        {
                            continue;
                        }


                        var target = MyMultiplayer.Static.ReplicationLayer.GetProxyTarget((IMyEventProxy)node.NodeData);
                        
                        int pos = stream.BitPosition;

                        if (node.NodeData != Entity && !node.NodeData.IsStatic && target != null)
                        {                 
                            stream.WriteBool(true);
                            // ~26.5 bytes per grid, not bad
                            NetworkId networkId = MyMultiplayer.Static.ReplicationLayer.GetNetworkIdByObject(target);
                            stream.WriteNetworkId(networkId); // ~2 bytes
             
                            moving = IsMoving(node.NodeData);
                            stream.WriteBool(moving);

                            SerializeTransform(stream, node.NodeData, basePos, m_lowPrecisionOrientation, apply, moving, timestamp, null, null); // 12.5 bytes
                            SerializeVelocities(stream, node.NodeData, EffectiveSimulationRatio, apply, moving); // 12 byte
                            UpdateGridMaxSpeed(node.NodeData, Sync.IsServer);
                            m_groups.Add(node.NodeData);

                            m_currentSentPosition++;
                        }

                        if (stream.BitPosition > maxBitPosition)
                        {
                            stream.SetBitPositionWrite(pos);
                            fullyWritten = false;
                            m_currentSentPosition--;
                            break;
                        }

                        if (i == g.Nodes.Count)
                        {
                            m_currentSentPosition = 0;
                        }
                    }

                    stream.WriteBool(false);
                }

                stream.WriteBool(fullyWritten);

                if (fullyWritten)
                {
                    SerializeRopeData(stream, apply, gridsGroup: m_groups);
                }
                return fullyWritten;

            }
            else
            {
                UpdateGridMaxSpeed(Entity, !Sync.IsServer);

                while (stream.ReadBool())
                {               
                    NetworkId networkId = stream.ReadNetworkId(); // ~2 bytes
                    MyCubeGridReplicable replicable = MyMultiplayer.Static.ReplicationLayer.GetObjectByNetworkId(networkId) as MyCubeGridReplicable;
                    MyCubeGrid grid = replicable != null ? replicable.Grid : null;

                    moving = stream.ReadBool();
                    SerializeTransform(stream, grid, basePos, m_lowPrecisionOrientation, apply && grid != null, moving, timestamp, null, null); // 12.5 bytes
                    SerializeVelocities(stream, grid, EffectiveSimulationRatio, apply && grid != null, moving); // 12 bytes
                   
                    UpdateGridMaxSpeed(grid,!Sync.IsServer);
                }

                if (stream.ReadBool())
                {
                    SerializeRopeData(stream, apply);
                }
            }
            return true;
        }
        public void Deserialize(BitStream bs)
        {
            bool fieldExists = bs.ReadBool();

            if (fieldExists)
            {
                foreach (var mySyncedObject in m_syncedClass)
                {
                    mySyncedObject.Deserialize(bs);
                }

                foreach (var mySynced in m_syncedVariables)
                {
                    mySynced.Deserialize(bs);
                }
            }
        }