Esempio n. 1
0
        void R_SetBlock(NetConnection client, NetBuffer buffer, ushort numArgs)
        {
            int cx = buffer.ReadInt16();
            int cy = buffer.ReadInt16();
            int cz = buffer.ReadInt16();

            int bx = buffer.ReadUInt16();
            int by = buffer.ReadUInt16();
            int bz = buffer.ReadUInt16();

            byte r = buffer.ReadByte();
            byte g = buffer.ReadByte();
            byte b = buffer.ReadByte();
            byte d = buffer.ReadByte();

            bool placement = buffer.ReadBool();

            ServerMPPlayer player;

            if (players.TryGetValue(client, out player))
            {
                IndexPosition chunkPos = new IndexPosition(cx, cy, cz);
                IndexPosition blockPos = new IndexPosition(bx, by, bz);

                Block block = new Block(new Nybble2(d), r, g, b);
                // Validate modification
                float distToBlock = (player.GetCamera().Position - Chunk.ChunkBlockToWorldCoords(chunkPos, blockPos)).Length;
                if (!placement /* && distToBlock <= Spade.MODIFY_RANGE*/)
                {
                    SetBlock(chunkPos, blockPos, block, placement);

                    if (block == Block.AIR)
                    {
                        player.NumBlocks++;
                    }
                }
                else if (placement && /*distToBlock <= BlockItem.PLACE_RANGE
                                       * &&*/player.NumBlocks > 0)
                {
                    SetBlock(chunkPos, blockPos, block, placement);

                    if (!DashCMD.GetCVar <bool>("ch_infammo"))
                    {
                        player.NumBlocks--;
                    }
                }
            }
        }
Esempio n. 2
0
        static object ReadPrimitive(NetBuffer buffer, SnapshotPrimitiveType type)
        {
            switch (type)
            {
            case SnapshotPrimitiveType.Byte:
                return(buffer.ReadByte());

            case SnapshotPrimitiveType.Char:
                return(buffer.ReadChar());

            case SnapshotPrimitiveType.Boolean:
                return(buffer.ReadBool());

            case SnapshotPrimitiveType.Int16:
            case SnapshotPrimitiveType.SByte:     // SByte is written as a short
                return(buffer.ReadInt16());

            case SnapshotPrimitiveType.UInt16:
                return(buffer.ReadUInt16());

            case SnapshotPrimitiveType.Int32:
                return(buffer.ReadInt32());

            case SnapshotPrimitiveType.UInt32:
                return(buffer.ReadUInt32());

            case SnapshotPrimitiveType.Int64:
                return(buffer.ReadInt64());

            case SnapshotPrimitiveType.UInt64:
                return(buffer.ReadUInt64());

            case SnapshotPrimitiveType.Single:
                return(buffer.ReadFloat());

            case SnapshotPrimitiveType.Double:
                return(buffer.ReadDouble());

            case SnapshotPrimitiveType.ByteFlag:
                return(buffer.ReadByteFlag());

            default:
                throw new Exception("Snapshot primitive type '" + type + "' is not supported!");
            }
        }
Esempio n. 3
0
        public bool ServerAdminRead(NetBuffer incMsg, Client c)
        {
            if (!c.HasPermission(ClientPermissions.Ban))
            {
                UInt16 removeCount = incMsg.ReadUInt16();
                incMsg.Position += removeCount * 4 * 8;
                UInt16 rangeBanCount = incMsg.ReadUInt16();
                incMsg.Position += rangeBanCount * 4 * 8;
                return(false);
            }
            else
            {
                UInt16 removeCount = incMsg.ReadUInt16();
                for (int i = 0; i < removeCount; i++)
                {
                    UInt16       id           = incMsg.ReadUInt16();
                    BannedPlayer bannedPlayer = bannedPlayers.Find(p => p.UniqueIdentifier == id);
                    if (bannedPlayer != null)
                    {
                        GameServer.Log(c.Name + " unbanned " + bannedPlayer.Name + " (" + bannedPlayer.IP + ")", ServerLog.MessageType.ConsoleUsage);
                        RemoveBan(bannedPlayer);
                    }
                }
                Int16 rangeBanCount = incMsg.ReadInt16();
                for (int i = 0; i < rangeBanCount; i++)
                {
                    UInt16       id           = incMsg.ReadUInt16();
                    BannedPlayer bannedPlayer = bannedPlayers.Find(p => p.UniqueIdentifier == id);
                    if (bannedPlayer != null)
                    {
                        GameServer.Log(c.Name + " rangebanned " + bannedPlayer.Name + " (" + bannedPlayer.IP + ")", ServerLog.MessageType.ConsoleUsage);
                        RangeBan(bannedPlayer);
                    }
                }

                return(removeCount > 0 || rangeBanCount > 0);
            }
        }
        protected override void OnDeserialize(NetBuffer buffer)
        {
            ushort numTerrainChanges = buffer.ReadUInt16();

            for (int i = 0; i < numTerrainChanges; i++)
            {
                short cix = buffer.ReadInt16();
                short ciy = buffer.ReadInt16();
                short ciz = buffer.ReadInt16();

                short cx = buffer.ReadInt16();
                short cy = buffer.ReadInt16();
                short cz = buffer.ReadInt16();

                byte r = buffer.ReadByte();
                byte g = buffer.ReadByte();
                byte b = buffer.ReadByte();
                byte d = buffer.ReadByte();

                ReceivedChanges.Add(new TerrainDeltaChange(new IndexPosition(cix, ciy, ciz),
                                                           new IndexPosition(cx, cy, cz), new Block(new Nybble2(d), r, g, b)));
            }
        }
Esempio n. 5
0
        internal void Deserialize(NetBuffer buffer)
        {
            try
            {
                _fields = new Dictionary <string, Pair <DataType, object> >();

                while (true)
                {
                    string key = buffer.ReadString();
                    if (string.IsNullOrEmpty(key))
                    {
                        break;
                    }

                    DataType type = (DataType)buffer.ReadByte();
                    if (type == DataType.Unknown)
                    {
                        throw new Exception();
                    }

                    switch (type)
                    {
                    case DataType.Byte:
                        _fields.Add(key, new Pair <DataType, object>(type, buffer.ReadByte()));
                        break;

                    case DataType.Ushort:
                        _fields.Add(key, new Pair <DataType, object>(type, buffer.ReadUInt16()));
                        break;

                    case DataType.Uint:
                        _fields.Add(key, new Pair <DataType, object>(type, buffer.ReadUInt32()));
                        break;

                    case DataType.Ulong:
                        _fields.Add(key, new Pair <DataType, object>(type, buffer.ReadUInt64()));
                        break;

                    case DataType.Sbyte:
                        _fields.Add(key, new Pair <DataType, object>(type, buffer.ReadSByte()));
                        break;

                    case DataType.Short:
                        _fields.Add(key, new Pair <DataType, object>(type, buffer.ReadInt16()));
                        break;

                    case DataType.Int:
                        _fields.Add(key, new Pair <DataType, object>(type, buffer.ReadInt32()));
                        break;

                    case DataType.Long:
                        _fields.Add(key, new Pair <DataType, object>(type, buffer.ReadInt64()));
                        break;

                    case DataType.String:
                        _fields.Add(key, new Pair <DataType, object>(type, buffer.ReadString()));
                        break;

                    case DataType.Double:
                        _fields.Add(key, new Pair <DataType, object>(type, buffer.ReadDouble()));
                        break;

                    case DataType.Float:
                        _fields.Add(key, new Pair <DataType, object>(type, buffer.ReadFloat()));
                        break;

                    case DataType.Bool:
                        _fields.Add(key, new Pair <DataType, object>(type, buffer.ReadBoolean()));
                        break;

                    case DataType.IPEndPoint:
                        _fields.Add(key, new Pair <DataType, object>(type, buffer.ReadIPEndPoint()));
                        break;
                    }
                }

                Count = _fields.Count;
                Keys  = new string[_fields.Count];
                _fields.Keys.CopyTo(Keys, 0);
            }
            catch
            {
                _Empty();
            }
        }
 public short ReadInt16()
 {
     return(_buffer.ReadInt16());
 }
 void R_UpdateScores(NetConnection server, NetBuffer buffer, ushort numArgs)
 {
     TeamAScore = buffer.ReadInt16();
     TeamBScore = buffer.ReadInt16();
 }
    /// <summary>
    /// 패킷에서 데이터 읽기 (RPC)
    /// </summary>
    /// <param name="type">파라미터 타입</param>
    public static object ReadObjectPacked(this NetBuffer buff, Type type)
    {
        if (type.IsNullable())
        {
            bool isNull = buff.ReadBoolean();

            if (isNull)
            {
                return(null);
            }
        }

        if (type == typeof(byte))
        {
            return(buff.ReadByte());
        }
        if (type == typeof(sbyte))
        {
            return(buff.ReadSByte());
        }
        if (type == typeof(ushort))
        {
            return(buff.ReadUInt16());
        }
        if (type == typeof(short))
        {
            return(buff.ReadInt16());
        }
        if (type == typeof(int))
        {
            return(buff.ReadInt32());
        }
        if (type == typeof(uint))
        {
            return(buff.ReadUInt32());
        }
        if (type == typeof(long))
        {
            return(buff.ReadInt64());
        }
        if (type == typeof(ulong))
        {
            return(buff.ReadUInt64());
        }
        if (type == typeof(float))
        {
            return(buff.ReadFloat());
        }
        if (type == typeof(double))
        {
            return(buff.ReadDouble());
        }
        if (type == typeof(string))
        {
            return(buff.ReadString());
        }
        if (type == typeof(bool))
        {
            return(buff.ReadBoolean());
        }
        if (type == typeof(Vector3))
        {
            Vector3 v = default(Vector3);
            buff.Read(ref v);
            return(v);
        }
        if (type == typeof(char))
        {
            return(buff.ReadByte());
        }
        if (type.IsEnum)
        {
            return(buff.ReadInt32());
        }
        if (type == typeof(List <int>))
        {
            List <int> v        = new List <int>();
            byte       listSize = buff.ReadByte();
            for (byte i = 0; i < listSize; ++i)
            {
                v.Add(buff.ReadInt32());
            }
            return(v);
        }
        if (type == typeof(List <short>))
        {
            List <short> v        = new List <short>();
            byte         listSize = buff.ReadByte();
            for (byte i = 0; i < listSize; ++i)
            {
                v.Add(buff.ReadInt16());
            }
            return(v);
        }
        if (type == typeof(List <float>))
        {
            List <float> v        = new List <float>();
            byte         listSize = buff.ReadByte();
            for (byte i = 0; i < listSize; ++i)
            {
                v.Add(buff.ReadFloat());
            }
            return(v);
        }


        throw new ArgumentException("BitReader cannot read type " + type.Name);
    }
Esempio n. 9
0
        public void LoadServerTerrain(NetBuffer data)
        {
            SetTerrain(new FixedTerrain(Renderer));

            DashCMD.WriteStandard("[MPWorld] Loading server world...");

            ushort numChunks    = data.ReadUInt16();
            Chunk  currentChunk = null;
            int    blockI       = 0;
            int    ci           = 0;

            while (ci <= numChunks && data.Position < data.Data.Length)
            {
                byte type = data.ReadByte();

                if (type == 0) // New Chunk
                {
                    int ix = data.ReadInt16();
                    int iy = data.ReadInt16();
                    int iz = data.ReadInt16();

                    if (currentChunk != null)
                    {
                        currentChunk.BakeColors();
                    }

                    IndexPosition ipos = new IndexPosition(ix, iy, iz);
                    currentChunk = new Chunk(Terrain, ipos, AceOfSpades.Terrain.ChunkToWorldCoords(ipos));
                    currentChunk.InitBlocks(Chunk.HSIZE, Chunk.VSIZE, Chunk.HSIZE);
                    currentChunk.State   = ChunkState.Unlit;
                    currentChunk.IsDirty = true;
                    Terrain.Chunks.TryAdd(ipos, currentChunk);

                    blockI = 0;
                    ci++;
                }
                else if (type == 1) // Block section
                {
                    ushort  numBlocks = data.ReadUInt16();
                    byte    d = data.ReadByte();
                    Nybble2 n = new Nybble2(d);
                    byte    r, g, b;
                    byte    mat = n.Lower;

                    if (mat == Block.CUSTOM.Material)
                    {
                        r = data.ReadByte();
                        g = data.ReadByte();
                        b = data.ReadByte();
                    }
                    else
                    {
                        if (mat == Block.GRASS.Material)
                        {
                            r = Block.GRASS.R;
                            g = Block.GRASS.G;
                            b = Block.GRASS.B;
                        }
                        else
                        {
                            r = Block.STONE.R;
                            g = Block.STONE.G;
                            b = Block.STONE.B;
                        }
                    }

                    Block block = new Block(n, r, g, b);

                    for (int i = 0; i < numBlocks; i++)
                    {
                        int z = blockI % Chunk.HSIZE;
                        int y = (blockI / Chunk.HSIZE) % Chunk.VSIZE;
                        int x = blockI / (Chunk.VSIZE * Chunk.HSIZE);

                        currentChunk.Blocks[z, y, x] = block;
                        blockI++;
                    }
                }
            }

            if (currentChunk != null)
            {
                currentChunk.BakeColors();
            }

            Terrain.CreatedFromFile();
        }
Esempio n. 10
0
        static unsafe void Main(string[] args)
        {
            // JIT stuff
            NetBuffer msg = new NetBuffer(20);

            msg.Write((short)short.MaxValue);

            // Go
            double timeStart = NetTime.Now;

            msg = new NetBuffer(20);
            for (int n = 0; n < 10000; n++)
            {
                msg.Reset();

                msg.Write((short)short.MaxValue);
                msg.Write((short)short.MinValue);
                msg.Write((short)-42);

                msg.Write(421);
                msg.Write((byte)7);
                msg.Write(-42.8f);

                if (msg.LengthBytes != 15)
                {
                    throw new Exception("Bad message length");
                }

                msg.Write("duke of earl");

                int bytesWritten;
                bytesWritten = msg.WriteVariableInt32(-1);
                bytesWritten = msg.WriteVariableInt32(5);
                bytesWritten = msg.WriteVariableInt32(-18);
                bytesWritten = msg.WriteVariableInt32(42);
                bytesWritten = msg.WriteVariableInt32(-420);

                msg.Write((uint)9991);

                // byte boundary kept until here

                msg.Write(true);
                msg.Write((uint)3, 5);
                msg.Write(8.111f);
                msg.Write("again");
                byte[] arr = new byte[] { 1, 6, 12, 24 };
                msg.Write(arr);
                msg.Write((byte)7, 7);
                msg.Write(Int32.MinValue);
                msg.Write(UInt32.MaxValue);
                msg.WriteRangedSingle(21.0f, -10, 50, 12);

                // test reduced bit signed writing
                msg.Write(15, 5);
                msg.Write(2, 5);
                msg.Write(0, 5);
                msg.Write(-1, 5);
                msg.Write(-2, 5);
                msg.Write(-15, 5);

                msg.Write(UInt64.MaxValue);
                msg.Write(Int64.MaxValue);
                msg.Write(Int64.MinValue);

                msg.Write(42);
                msg.WritePadBits();

                int numBits = msg.WriteRangedInteger(0, 10, 5);
                if (numBits != 4)
                {
                    throw new Exception("Ack WriteRangedInteger failed");
                }

                // verify
                msg.Position = 0;

                short a = msg.ReadInt16();
                short b = msg.ReadInt16();
                short c = msg.ReadInt16();

                if (a != short.MaxValue || b != short.MinValue || c != -42)
                {
                    throw new Exception("Ack thpth short failed");
                }

                if (msg.ReadInt32() != 421)
                {
                    throw new Exception("Ack thphth 1");
                }
                if (msg.ReadByte() != (byte)7)
                {
                    throw new Exception("Ack thphth 2");
                }
                if (msg.ReadSingle() != -42.8f)
                {
                    throw new Exception("Ack thphth 3");
                }
                if (msg.ReadString() != "duke of earl")
                {
                    throw new Exception("Ack thphth 4");
                }

                if (msg.ReadVariableInt32() != -1)
                {
                    throw new Exception("ReadVariableInt32 failed 1");
                }
                if (msg.ReadVariableInt32() != 5)
                {
                    throw new Exception("ReadVariableInt32 failed 2");
                }
                if (msg.ReadVariableInt32() != -18)
                {
                    throw new Exception("ReadVariableInt32 failed 3");
                }
                if (msg.ReadVariableInt32() != 42)
                {
                    throw new Exception("ReadVariableInt32 failed 4");
                }
                if (msg.ReadVariableInt32() != -420)
                {
                    throw new Exception("ReadVariableInt32 failed 5");
                }

                if (msg.ReadUInt32() != 9991)
                {
                    throw new Exception("Ack thphth 4.5");
                }

                if (msg.ReadBoolean() != true)
                {
                    throw new Exception("Ack thphth 5");
                }
                if (msg.ReadUInt32(5) != (uint)3)
                {
                    throw new Exception("Ack thphth 6");
                }
                if (msg.ReadSingle() != 8.111f)
                {
                    throw new Exception("Ack thphth 7");
                }
                if (msg.ReadString() != "again")
                {
                    throw new Exception("Ack thphth 8");
                }
                byte[] rrr = msg.ReadBytes(4);
                if (rrr[0] != arr[0] || rrr[1] != arr[1] || rrr[2] != arr[2] || rrr[3] != arr[3])
                {
                    throw new Exception("Ack thphth 9");
                }
                if (msg.ReadByte(7) != 7)
                {
                    throw new Exception("Ack thphth 10");
                }
                if (msg.ReadInt32() != Int32.MinValue)
                {
                    throw new Exception("Ack thphth 11");
                }
                if (msg.ReadUInt32() != UInt32.MaxValue)
                {
                    throw new Exception("Ack thphth 12");
                }

                float v = msg.ReadRangedSingle(-10, 50, 12);
                // v should be close to, but not necessarily exactly, 21.0f
                if ((float)Math.Abs(21.0f - v) > 0.1f)
                {
                    throw new Exception("Ack thphth *RangedSingle() failed");
                }

                if (msg.ReadInt32(5) != 15)
                {
                    throw new Exception("Ack thphth ReadInt32 1");
                }
                if (msg.ReadInt32(5) != 2)
                {
                    throw new Exception("Ack thphth ReadInt32 2");
                }
                if (msg.ReadInt32(5) != 0)
                {
                    throw new Exception("Ack thphth ReadInt32 3");
                }
                if (msg.ReadInt32(5) != -1)
                {
                    throw new Exception("Ack thphth ReadInt32 4");
                }
                if (msg.ReadInt32(5) != -2)
                {
                    throw new Exception("Ack thphth ReadInt32 5");
                }
                if (msg.ReadInt32(5) != -15)
                {
                    throw new Exception("Ack thphth ReadInt32 6");
                }

                UInt64 longVal = msg.ReadUInt64();
                if (longVal != UInt64.MaxValue)
                {
                    throw new Exception("Ack thphth UInt64");
                }
                if (msg.ReadInt64() != Int64.MaxValue)
                {
                    throw new Exception("Ack thphth Int64");
                }
                if (msg.ReadInt64() != Int64.MinValue)
                {
                    throw new Exception("Ack thphth Int64");
                }

                if (msg.ReadInt32() != 42)
                {
                    throw new Exception("Ack thphth end");
                }

                msg.SkipPadBits();

                if (msg.ReadRangedInteger(0, 10) != 5)
                {
                    throw new Exception("Ack thphth ranged integer");
                }
            }

            // test writevariableuint64
            NetBuffer largeBuffer = new NetBuffer(100 * 8);

            UInt64[] largeNumbers = new ulong[100];
            for (int i = 0; i < 100; i++)
            {
                largeNumbers[i] = ((ulong)NetRandom.Instance.NextUInt() << 32) | (ulong)NetRandom.Instance.NextUInt();
                largeBuffer.WriteVariableUInt64(largeNumbers[i]);
            }

            largeBuffer.Position = 0;
            for (int i = 0; i < 100; i++)
            {
                UInt64 ln = largeBuffer.ReadVariableUInt64();
                if (ln != largeNumbers[i])
                {
                    throw new Exception("large fail");
                }
            }

            //
            // Extended tests on padbits
            //
            for (int i = 1; i < 31; i++)
            {
                NetBuffer buf = new NetBuffer();
                buf.Write((int)1, i);

                if (buf.LengthBits != i)
                {
                    throw new Exception("Bad length!");
                }

                buf.WritePadBits();
                int wholeBytes = buf.LengthBits / 8;
                if (wholeBytes * 8 != buf.LengthBits)
                {
                    throw new Exception("WritePadBits failed! Length is " + buf.LengthBits);
                }
            }

            NetBuffer small = new NetBuffer(100);

            byte[] rnd  = new byte[24];
            int[]  bits = new int[24];
            for (int i = 0; i < 24; i++)
            {
                rnd[i]  = (byte)NetRandom.Instance.Next(0, 65);
                bits[i] = NetUtility.BitsToHoldUInt((uint)rnd[i]);

                small.Write(rnd[i], bits[i]);
            }

            small.Position = 0;
            for (int i = 0; i < 24; i++)
            {
                byte got = small.ReadByte(bits[i]);
                if (got != rnd[i])
                {
                    throw new Exception("Failed small allocation test");
                }
            }

            double timeEnd  = NetTime.Now;
            double timeSpan = timeEnd - timeStart;

            Console.WriteLine("Trivial tests passed in " + (timeSpan * 1000.0) + " milliseconds");

            Console.WriteLine("Creating client and server for live testing...");

            NetConfiguration config = new NetConfiguration("unittest");

            config.Port = 14242;
            NetServer server       = new NetServer(config);
            NetBuffer serverBuffer = new NetBuffer();

            server.Start();

            config = new NetConfiguration("unittest");
            NetClient client = new NetClient(config);

            client.SetMessageTypeEnabled(NetMessageType.Receipt, true);
            NetBuffer clientBuffer = client.CreateBuffer();

            client.Start();

            client.Connect("127.0.0.1", 14242);

            List <string> events = new List <string>();

            double end        = double.MaxValue;
            double disconnect = double.MaxValue;

            while (NetTime.Now < end)
            {
                double now = NetTime.Now;

                NetMessageType nmt;
                NetConnection  sender;

                //
                // client
                //
                if (client.ReadMessage(clientBuffer, out nmt))
                {
                    switch (nmt)
                    {
                    case NetMessageType.StatusChanged:
                        Console.WriteLine("Client: " + client.Status + " (" + clientBuffer.ReadString() + ")");
                        events.Add("CStatus " + client.Status);
                        if (client.Status == NetConnectionStatus.Connected)
                        {
                            // send reliable message
                            NetBuffer buf = client.CreateBuffer();
                            buf.Write(true);
                            buf.Write((int)52, 7);
                            buf.Write("Hallon");

                            client.SendMessage(buf, NetChannel.ReliableInOrder1, new NetBuffer("kokos"));
                        }

                        if (client.Status == NetConnectionStatus.Disconnected)
                        {
                            end = NetTime.Now + 1.0;                                     // end in one second
                        }
                        break;

                    case NetMessageType.Receipt:
                        events.Add("CReceipt " + clientBuffer.ReadString());
                        break;

                    case NetMessageType.ConnectionRejected:
                    case NetMessageType.BadMessageReceived:
                        throw new Exception("Failed: " + nmt);

                    case NetMessageType.DebugMessage:
                        // silently ignore
                        break;

                    default:
                        // ignore
                        Console.WriteLine("Ignored: " + nmt);
                        break;
                    }
                }

                //
                // server
                //
                if (server.ReadMessage(serverBuffer, out nmt, out sender))
                {
                    switch (nmt)
                    {
                    case NetMessageType.StatusChanged:
                        events.Add("SStatus " + sender.Status);
                        Console.WriteLine("Server: " + sender.Status + " (" + serverBuffer.ReadString() + ")");
                        break;

                    case NetMessageType.ConnectionRejected:
                    case NetMessageType.BadMessageReceived:
                        throw new Exception("Failed: " + nmt);

                    case NetMessageType.Data:
                        events.Add("DataRec " + serverBuffer.LengthBits);
                        bool   shouldBeTrue     = serverBuffer.ReadBoolean();
                        int    shouldBeFifthTwo = serverBuffer.ReadInt32(7);
                        string shouldBeHallon   = serverBuffer.ReadString();

                        if (shouldBeTrue != true ||
                            shouldBeFifthTwo != 52 ||
                            shouldBeHallon != "Hallon")
                        {
                            throw new Exception("Bad data transmission");
                        }

                        disconnect = now + 1.0;
                        break;

                    case NetMessageType.DebugMessage:
                        // silently ignore
                        break;

                    default:
                        // ignore
                        Console.WriteLine("Ignored: " + nmt);
                        break;
                    }
                }

                if (now > disconnect)
                {
                    server.Connections[0].Disconnect("Bye", 0.1f);
                    disconnect = double.MaxValue;
                }
            }

            // verify events
            string[] expected = new string[] {
                "CStatus Connecting",
                "SStatus Connecting",
                "CStatus Connected",
                "SStatus Connected",
                "DataRec 64",
                "CReceipt kokos",
                "SStatus Disconnecting",
                "CStatus Disconnecting",
                "SStatus Disconnected",
                "CStatus Disconnected"
            };

            if (events.Count != expected.Length)
            {
                throw new Exception("Mismatch in events count! Expected " + expected.Length + ", got " + events.Count);
            }

            for (int i = 0; i < expected.Length; i++)
            {
                if (events[i] != expected[i])
                {
                    throw new Exception("Event " + i + " (" + expected[i] + ") mismatched!");
                }
            }

            Console.WriteLine("All tests successful");

            Console.ReadKey();

            server.Shutdown("App exiting");
            client.Shutdown("App exiting");
        }