Beispiel #1
0
        public void Tick()
        {
            if (!IsReadyForNextFrame)
            {
                throw new InvalidOperationException();
            }

            Connection.Send(NetFrameNumber + FramesAhead, localOrders.Select(o => o.Serialize()).ToList());
            localOrders.Clear();

            var sync = new List <int>();

            sync.Add(world.SyncHash());

            foreach (var order in frameData.OrdersForFrame(world, NetFrameNumber))
            {
                UnitOrders.ProcessOrder(this, world, order.Client, order.Order);
                sync.Add(world.SyncHash());
            }

            var ss = sync.SerializeSync();

            Connection.SendSync(NetFrameNumber, ss);

            syncReport.UpdateSyncReport();

            ++NetFrameNumber;
        }
Beispiel #2
0
        public void TickImmediate()
        {
            if (localImmediateOrders.Count != 0 && GameSaveLastFrame < NetFrameNumber + FramesAhead)
            {
                Connection.SendImmediate(localImmediateOrders.Select(o => o.Serialize()));
            }
            localImmediateOrders.Clear();

            Connection.Receive(
                (clientId, packet) =>
            {
                // HACK: The shellmap relies on ticking a disposed OM
                if (disposed && World.Type != WorldType.Shellmap)
                {
                    return;
                }

                var frame = BitConverter.ToInt32(packet, 0);
                if (packet.Length == 5 && packet[4] == (byte)OrderType.Disconnect)
                {
                    pendingPackets.Remove(clientId);
                }
                else if (packet.Length > 4 && packet[4] == (byte)OrderType.SyncHash)
                {
                    if (packet.Length != 4 + Order.SyncHashOrderLength)
                    {
                        Log.Write("debug", $"Dropped sync order with length {packet.Length}. Expected length {4 + Order.SyncHashOrderLength}.");
                        return;
                    }

                    CheckSync(packet);
                }
                else if (frame == 0)
                {
                    foreach (var o in packet.ToOrderList(World))
                    {
                        UnitOrders.ProcessOrder(this, World, clientId, o);

                        // A mod switch or other event has pulled the ground from beneath us
                        if (disposed)
                        {
                            return;
                        }
                    }
                }
                else
                {
                    if (pendingPackets.TryGetValue(clientId, out var queue))
                    {
                        queue.Enqueue(packet);
                    }
                    else
                    {
                        Log.Write("debug", $"Received packet from disconnected client '{clientId}'");
                    }
                }
            });
        }
Beispiel #3
0
        void ProcessOrders()
        {
            var clientOrders = new List <ClientOrder>();

            foreach (var(clientId, clientPackets) in pendingPackets)
            {
                // The IsReadyForNextFrame check above guarantees that all clients have sent a packet
                var frameData = clientPackets.Dequeue();

                // Orders are synchronised by sending an initial FramesAhead set of empty packets
                // and then making sure that we enqueue and process exactly one packet for each player each tick.
                // This may change in the future, so sanity check that the orders are for the frame we expect
                // and crash early instead of risking desyncs.
                var frameNumber = BitConverter.ToInt32(frameData, 0);
                if (frameNumber != NetFrameNumber)
                {
                    throw new InvalidDataException($"Attempted to process orders from client {clientId} for frame {frameNumber} on frame {NetFrameNumber}");
                }

                foreach (var order in frameData.ToOrderList(World))
                {
                    UnitOrders.ProcessOrder(this, World, clientId, order);
                    clientOrders.Add(new ClientOrder {
                        Client = clientId, Order = order
                    });
                }
            }

            if (NetFrameNumber + FramesAhead >= GameSaveLastSyncFrame)
            {
                var defeatState = 0UL;
                for (var i = 0; i < World.Players.Length; i++)
                {
                    if (World.Players[i].WinState == WinState.Lost)
                    {
                        defeatState |= 1UL << i;
                    }
                }

                Connection.SendSync(NetFrameNumber, OrderIO.SerializeSync(World.SyncHash(), defeatState));
            }
            else
            {
                Connection.SendSync(NetFrameNumber, OrderIO.SerializeSync(0, 0));
            }

            if (generateSyncReport)
            {
                using (new PerfSample("sync_report"))
                    syncReport.UpdateSyncReport(clientOrders);
            }

            ++NetFrameNumber;
        }
Beispiel #4
0
        public void TickImmediate()
        {
            if (localImmediateOrders.Count != 0 && GameSaveLastFrame < NetFrameNumber + FramesAhead)
            {
                Connection.SendImmediate(localImmediateOrders.Select(o => o.Serialize()));
            }
            localImmediateOrders.Clear();

            var immediatePackets = new List <(int ClientId, byte[] Packet)>();

            Connection.Receive(
                (clientId, packet) =>
            {
                var frame = BitConverter.ToInt32(packet, 0);
                if (packet.Length == 5 && packet[4] == (byte)OrderType.Disconnect)
                {
                    frameData.ClientQuit(clientId, frame);
                }
                else if (packet.Length > 4 && packet[4] == (byte)OrderType.SyncHash)
                {
                    if (packet.Length != 4 + Order.SyncHashOrderLength)
                    {
                        Log.Write("debug", "Dropped sync order with length {0}. Expected length {1}.".F(packet.Length, 4 + Order.SyncHashOrderLength));
                        return;
                    }

                    CheckSync(packet);
                }
                else if (frame == 0)
                {
                    immediatePackets.Add((clientId, packet));
                }
                else
                {
                    frameData.AddFrameOrders(clientId, frame, packet);
                }
            });

            foreach (var p in immediatePackets)
            {
                foreach (var o in p.Packet.ToOrderList(World))
                {
                    UnitOrders.ProcessOrder(this, World, p.ClientId, o);

                    // A mod switch or other event has pulled the ground from beneath us
                    if (disposed)
                    {
                        return;
                    }
                }
            }
        }
Beispiel #5
0
        void ReceiveAllOrdersAndCheckSync()
        {
            Connection.Receive(
                (clientId, packet) =>
            {
                // HACK: The shellmap relies on ticking a disposed OM
                if (disposed && World.Type != WorldType.Shellmap)
                {
                    return;
                }

                var frame = BitConverter.ToInt32(packet, 0);
                if (packet.Length == Order.DisconnectOrderLength + 4 && packet[4] == (byte)OrderType.Disconnect)
                {
                    pendingPackets.Remove(BitConverter.ToInt32(packet, 5));
                }
                else if (packet.Length > 4 && packet[4] == (byte)OrderType.SyncHash)
                {
                    if (packet.Length != 4 + Order.SyncHashOrderLength)
                    {
                        Log.Write("debug", $"Dropped sync order with length {packet.Length}. Expected length {4 + Order.SyncHashOrderLength}.");
                        return;
                    }

                    CheckSync(packet);
                }
                else if (frame == 0)
                {
                    foreach (var o in packet.ToOrderList(World))
                    {
                        UnitOrders.ProcessOrder(this, World, clientId, o);

                        // A mod switch or other event has pulled the ground from beneath us
                        if (disposed)
                        {
                            return;
                        }
                    }
                }
                else
                {
                    if (pendingPackets.TryGetValue(clientId, out var queue))
                    {
                        queue.Enqueue(packet);
                    }
                    else
                    {
                        Log.Write("debug", $"Received packet from disconnected client '{clientId}'");
                    }
                }
            });
        }
Beispiel #6
0
        public void TickImmediate()
        {
            var immediateOrders = localOrders.Where(o => o.IsImmediate).ToList();

            if (immediateOrders.Count != 0)
            {
                Connection.SendImmediate(immediateOrders.Select(o => o.Serialize()).ToList());
            }
            localOrders.RemoveAll(o => o.IsImmediate);

            var immediatePackets = new List <Pair <int, byte[]> >();

            Connection.Receive(
                (clientId, packet) =>
            {
                var frame = BitConverter.ToInt32(packet, 0);
                if (packet.Length == 5 && packet[4] == 0xBF)
                {
                    frameData.ClientQuit(clientId, frame);
                }
                else if (packet.Length >= 5 && packet[4] == 0x65)
                {
                    CheckSync(packet);
                }
                else if (frame == 0)
                {
                    immediatePackets.Add(Pair.New(clientId, packet));
                }
                else
                {
                    frameData.AddFrameOrders(clientId, frame, packet);
                }
            });

            foreach (var p in immediatePackets)
            {
                foreach (var o in p.Second.ToOrderList(World))
                {
                    UnitOrders.ProcessOrder(this, World, p.First, o);

                    // A mod switch or other event has pulled the ground from beneath us
                    if (disposed)
                    {
                        return;
                    }
                }
            }
        }
Beispiel #7
0
        public void TickImmediate()
        {
            if (localImmediateOrders.Count != 0 && GameSaveLastFrame < NetFrameNumber + FramesAhead)
            {
                Connection.SendImmediate(localImmediateOrders.Select(o => o.Serialize()));
            }
            localImmediateOrders.Clear();

            var immediatePackets = new List <Pair <int, byte[]> >();

            Connection.Receive(
                (clientId, packet) =>
            {
                var frame = BitConverter.ToInt32(packet, 0);
                if (packet.Length == 5 && packet[4] == (byte)OrderType.Disconnect)
                {
                    frameData.ClientQuit(clientId, frame);
                }
                else if (packet.Length >= 5 && packet[4] == (byte)OrderType.SyncHash)
                {
                    CheckSync(packet);
                }
                else if (frame == 0)
                {
                    immediatePackets.Add(Pair.New(clientId, packet));
                }
                else
                {
                    frameData.AddFrameOrders(clientId, frame, packet);
                }
            });

            foreach (var p in immediatePackets)
            {
                foreach (var o in p.Second.ToOrderList(World))
                {
                    UnitOrders.ProcessOrder(this, World, p.First, o);

                    // A mod switch or other event has pulled the ground from beneath us
                    if (disposed)
                    {
                        return;
                    }
                }
            }
        }
Beispiel #8
0
        public void Tick()
        {
            if (!IsReadyForNextFrame)
            {
                throw new InvalidOperationException();
            }

            if (GameSaveLastFrame < NetFrameNumber + FramesAhead)
            {
                Connection.Send(NetFrameNumber + FramesAhead, localOrders.Select(o => o.Serialize()).ToList());
            }

            localOrders.Clear();

            foreach (var order in frameData.OrdersForFrame(World, NetFrameNumber))
            {
                UnitOrders.ProcessOrder(this, World, order.Client, order.Order);
            }

            if (NetFrameNumber + FramesAhead >= GameSaveLastSyncFrame)
            {
                var defeatState = 0UL;
                for (var i = 0; i < World.Players.Length; i++)
                {
                    if (World.Players[i].WinState == WinState.Lost)
                    {
                        defeatState |= 1UL << i;
                    }
                }

                Connection.SendSync(NetFrameNumber, OrderIO.SerializeSync(World.SyncHash(), defeatState));
            }
            else
            {
                Connection.SendSync(NetFrameNumber, OrderIO.SerializeSync(0, 0));
            }

            if (generateSyncReport)
            {
                using (new PerfSample("sync_report"))
                    syncReport.UpdateSyncReport();
            }

            ++NetFrameNumber;
        }
Beispiel #9
0
        void ProcessImmediateOrders()
        {
            foreach (var p in receivedImmediateOrders)
            {
                foreach (var o in p.Second.ToOrderList(World))
                {
                    UnitOrders.ProcessOrder(this, World, p.First, o);

                    // A mod switch or other event has pulled the ground from beneath us
                    if (disposed)
                    {
                        return;
                    }
                }
            }

            receivedImmediateOrders.Clear();
        }
Beispiel #10
0
        /*
         * Only available if TickImmediate() is called first and we are ready to dispatch received orders locally.
         * Process all incoming orders for this frame, handle sync hashes and step our net frame.
         */
        void ProcessOrders()
        {
            foreach (var order in frameData.OrdersForFrame(World, NetFrameNumber))
            {
                UnitOrders.ProcessOrder(this, World, order.Client, order.Order);
            }

            if (NetFrameNumber + FramesAhead >= GameSaveLastSyncFrame)
            {
                Connection.SendSync(NetFrameNumber, OrderIO.SerializeSync(World.SyncHash()));
            }
            else
            {
                Connection.SendSync(NetFrameNumber, OrderIO.SerializeSync(0));
            }

            if (generateSyncReport)
            {
                using (new PerfSample("sync_report"))
                    syncReport.UpdateSyncReport();
            }

            ++NetFrameNumber;
        }
Beispiel #11
0
        public void Tick()
        {
            if (!IsReadyForNextFrame)
            {
                throw new InvalidOperationException();
            }

            Connection.Send(NetFrameNumber + FramesAhead, localOrders.Select(o => o.Serialize()).ToList());
            localOrders.Clear();

            foreach (var order in frameData.OrdersForFrame(World, NetFrameNumber))
            {
                UnitOrders.ProcessOrder(this, World, order.Client, order.Order);
            }

            Connection.SendSync(NetFrameNumber, OrderIO.SerializeSync(World.SyncHash()));

            if (generateSyncReport)
            {
                syncReport.UpdateSyncReport();
            }

            ++NetFrameNumber;
        }