Ejemplo n.º 1
0
 public void AddRow(int itemID, PyPackedRow entityRow, PyDictionary effects, PyDictionary attributes, long time)
 {
     this.AddRow(itemID, (PyList) new PyDataType[]
     {
         itemID, entityRow, effects, attributes, time
     });
 }
Ejemplo n.º 2
0
        public static PyPackedRow CreatePackedRow(DBRowDescriptor header, ref MySqlDataReader result)
        {
            PyPackedRow row = new PyPackedRow(header);

            for (int i = 0; i < header.ColumnCount; i++)
            {
                row.SetValue(header.GetColumnName(i).StringValue, DBColumnToPyObject(i, ref result));
            }
            return(row);
        }
Ejemplo n.º 3
0
 public void AddRow(int itemID, PyPackedRow entityRow, PyDictionary effects, PyDictionary attributes, long time)
 {
     this.AddRow(itemID, new PyList(5)
     {
         [0] = itemID,
         [1] = entityRow,
         [2] = effects,
         [3] = attributes,
         [4] = time
     });
 }
Ejemplo n.º 4
0
        private void ProcessPackedRow(PyPackedRow packedRow)
        {
            this.mStringBuilder.AppendFormat("[PyPackedRow {0} columns]", packedRow.Header.Columns.Count);
            if (packedRow.Header.Columns.Count > 0)
            {
                this.mStringBuilder.AppendLine();
            }
            this.mIndentation++;

            foreach (DBRowDescriptor.Column column in packedRow.Header.Columns)
            {
                this.mStringBuilder.AppendFormat("[PyPackedRowColumn '{0}']", column.Name);
                this.mStringBuilder.AppendLine();
                this.Process(packedRow[column.Name]);
            }

            this.mIndentation--;
        }
Ejemplo n.º 5
0
 public void Insert(PyPackedRow row)
 {
     row.Header = descriptor.Encode();
     items.Items.Add(row);
 }
Ejemplo n.º 6
0
        static void Main(string[] args)
        {
            Log.Init("evesharp");
            Log.Info("Main", "Starting node...");
            Log.Trace("Database", "Connecting to database...");

            if (Database.Database.Init() == false)
            {
                Log.Error("Main", "Cannot connect to database");
                while (true)
                {
                    ;
                }
            }

            /*
             * DBRowDescriptor descriptor = new DBRowDescriptor();
             *
             * descriptor.AddColumn("itemID", FieldType.I4);
             * descriptor.AddColumn("custominfo", FieldType.Str);
             *
             * PyPackedRow packed = new PyPackedRow(descriptor);
             *
             * packed.SetValue("itemID", new PyInt(500));
             * packed.SetValue("custominfo", new PyString("hello world"));
             *
             * byte[] marshaled = Marshal.Marshal.Process(packed);
             *
             * PyPackedRow unmarshaled = Unmarshal.Process<PyPackedRow>(marshaled);
             *
             * Console.WriteLine(PrettyPrinter.Print(unmarshaled));
             */

            byte[] raw = new byte[] { 1, 0, 55, 1, 22, 33, 0, 33, 25, 33, 14, 0, 0, 25, 45 };

            MemoryStream output = new MemoryStream(raw);
            BinaryReader reader = new BinaryReader(output);

            MemoryStream stream       = new MemoryStream();
            BinaryWriter streamWriter = new BinaryWriter(stream);
            BinaryReader streamReader = new BinaryReader(stream);

            PyPackedRow.ZeroCompress(reader, output, streamWriter);

            byte[] compressed = stream.ToArray();
            stream.Seek(0, SeekOrigin.Begin);

            byte[] uncompress = PyPackedRow.LoadZeroCompressed(streamReader);

            while (true)
            {
                Thread.Sleep(1);
            }

            /*
             * SHA1 sha1 = SHA1.Create();
             * byte[] hash = sha1.ComputeHash(Encoding.ASCII.GetBytes("password"));
             * char[] strHash = new char[20];
             *
             * for (int i = 0; i < 20; i++)
             * {
             *  strHash[i] = (char)hash[i];
             * }
             *
             * string str = new string(strHash);
             *
             * Database.Database.Query("INSERT INTO account(accountID, accountName, password, role, online, banned)VALUES(NULL, 'Username', '" + str + "', 2, 0, 0);");
             */

            Log.Info("Main", "Connection to the DB sucessfull");

            Log.Trace("Main", "Registering services...");

            SvcMgr.AddService(new Services.Network.machoNet());
            SvcMgr.AddService(new Services.Network.alert());
            SvcMgr.AddService(new Services.CacheSvc.objectCaching());

            Log.Info("Main", "Done");
            Log.Info("Main", "Connecting to proxy...");

            proxyConnection = new TCPSocket(ushort.Parse(proxy[0, 1]), false);
            if (proxyConnection.Connect(proxy[0, 0]) == false)
            {
                Log.Error("Main", "Cannot connect to proxy. Halting");
                Database.Database.Stop();
                while (true)
                {
                    ;
                }
            }

            Log.Trace("Main", "Server started");

            while (true)
            {
                Thread.Sleep(1);
                try
                {
                    byte[] data  = new byte[proxyConnection.Available];
                    int    bytes = proxyConnection.Recv(data);

                    if (bytes == -1)
                    {
                        // Proxy is closing, shutdown the node
                        break;
                    }
                    else if (bytes > 0)
                    {
                        packetizer.QueuePackets(data, bytes);
                        int p = packetizer.ProcessPackets();

                        for (int i = 0; i < p; i++)
                        {
                            byte[]   packet = packetizer.PopItem();
                            PyObject obj    = Unmarshal.Process <PyObject>(packet);

                            if (obj is PyObjectData)
                            {
                                PyObjectData info = obj as PyObjectData;

                                if (info.Name == "machoNet.nodeInfo")
                                {
                                    // Update our local info
                                    NodeInfo nodeinfo = new NodeInfo();

                                    if (nodeinfo.Decode(info) == true)
                                    {
                                        nodeID = nodeinfo.nodeID;

                                        SystemManager.LoadSolarSystems(nodeinfo.solarSystems);
                                    }
                                }
                                else
                                {
                                    // Client packet
                                    PyPacket clientpacket = new PyPacket();

                                    if (clientpacket.Decode(info) == false)
                                    {
                                        Log.Error("Main", "Unknown packet");
                                    }
                                    else
                                    {
                                        // Something similar to Async calls
                                        new Thread(new ParameterizedThreadStart(HandlePacket)).Start(clientpacket);
                                    }
                                }
                            }
                            else if (obj is PyChecksumedStream) // Checksumed packets
                            {
                                PyPacket clientpacket = new PyPacket();

                                if (clientpacket.Decode(obj) == false)
                                {
                                    Log.Error("Main", "Cannot decode packet");
                                }
                                else
                                {
                                    new Thread(new ParameterizedThreadStart(HandlePacket)).Start(clientpacket);
                                }
                            }
                            else if (obj is PyTuple)
                            {
                                // The only tuple packet is the LowLevelVersionExchange
                                LowLevelVersionExchange ex = new LowLevelVersionExchange();

                                if (ex.Decode(obj) == false)
                                {
                                    Log.Error("Main", "LowLevelVersionExchange error");
                                }

                                // Reply with the node LowLevelVersionExchange
                                LowLevelVersionExchange reply = new LowLevelVersionExchange();

                                reply.codename     = Common.Constants.Game.codename;
                                reply.birthday     = Common.Constants.Game.birthday;
                                reply.build        = Common.Constants.Game.build;
                                reply.machoVersion = Common.Constants.Game.machoVersion;
                                reply.version      = Common.Constants.Game.version;
                                reply.region       = Common.Constants.Game.region;

                                Send(reply.Encode(true));
                            }
                            else if (obj is PyObjectEx)
                            {
                                Log.Error("PyObjectEx", PrettyPrinter.Print(obj));
                            }
                            else
                            {
                                Log.Error("Main", PrettyPrinter.Print(obj));
                                Log.Error("Main", "Unhandled packet type");
                            }
                        }
                    }
                }
                catch (Exception)
                {
                }
            }

            /* Code to ADD an account:
             * SHA1 sha1 = SHA1.Create();
             * byte[] hash = sha1.ComputeHash(Encoding.ASCII.GetBytes("password"));
             * char[] strHash = new char[20];
             *
             * for (int i = 0; i < 20; i++)
             * {
             *  strHash[i] = (char)hash[i];
             * }
             *
             * string str = new string(strHash);
             *
             * Database.Database.Query("INSERT INTO account(accountID, accountName, password, role, online, banned)VALUES(NULL, 'Username', '" + str + "', 2, 0, 0);");
             */
        }
Ejemplo n.º 7
0
        /// <summary>
        /// Converts the given <paramref name="data"/> to it's byte array representation.
        /// Packed rows are the big elephant in the room. These are a direct representation of a row in any of the tables
        /// the server has and are composed of 3 parts.
        ///
        /// The first is the header that contains information about the columns that the PackedRow has data for.
        /// This header is known as <see cref="DBRowDescriptor" /> which is composed of a tuple with a string (column name)
        /// and an integer (column type). The column order doesn't matter on the header.
        ///
        /// The second part is the compressible bit data. Contains part of the actual data in the row. The columns are sorted
        /// by bit size in descending order, this way the amount of zeros one after the another is kept to a minimum, allowing
        /// the zero compression algorithm (<see cref="ZeroCompressionUtils" />) to greatly reduce the size of this data.
        /// Strings are not encoded here and are part of the third section of the PackedRow.
        /// The 1-bit sized columns (booleans) are encoded a bit differently from the rest of the data. Once the multi-bit
        /// sized data is written (long, int, short, byte) the bool values are grouped into 1 byte chunks, storing up to 8 booleans
        /// in each byte. The booleans are added to the byte from right to left and the byte blocks are written one after the other.
        /// These resources might be useful to better understand this operation
        /// https://stackoverflow.com/questions/36829860/using-binary-to-compress-boolean-array
        /// https://en.wikipedia.org/wiki/Bit_array
        /// https://sakai.rutgers.edu/wiki/site/e07619c5-a492-4ebe-8771-179dfe450ae4/bit-to-boolean%20conversion.html
        ///
        /// The third and last section contains the byte arrays and strings. These are encoded as normal python types
        /// after the second part.
        ///
        /// The following opcodes are supported
        /// <seealso cref="Opcode.PackedRow" />
        /// </summary>
        /// <param name="writer">Where to write the encoded data to</param>
        /// <param name="packedRow">The value to write</param>
        private static void ProcessPackedRow(BinaryWriter writer, PyPackedRow packedRow)
        {
            writer.WriteOpcode(Opcode.PackedRow);
            Process(writer, packedRow.Header);

            // prepare the zero-compression stream
            MemoryStream wholeByteStream = new MemoryStream();
            MemoryStream bitPacketStream = new MemoryStream();
            MemoryStream objectStream    = new MemoryStream();

            BinaryWriter wholeByteWriter = new BinaryWriter(wholeByteStream);
            BinaryWriter bitPacketWriter = new BinaryWriter(bitPacketStream);
            BinaryWriter objectWriter    = new BinaryWriter(objectStream);

            // sort the columns by size
            IOrderedEnumerable <DBRowDescriptor.Column> enumerator = packedRow.Header.Columns.OrderByDescending(c => Utils.GetTypeBits(c.Type));
            byte bitOffset = 0;
            byte toWrite   = 0;

            foreach (DBRowDescriptor.Column column in enumerator)
            {
                PyDataType value = packedRow[column.Name];

                switch (column.Type)
                {
                case FieldType.I8:
                case FieldType.UI8:
                case FieldType.CY:
                case FieldType.FileTime:
                    wholeByteWriter.Write((long)(value as PyInteger ?? 0));
                    break;

                case FieldType.I4:
                case FieldType.UI4:
                    wholeByteWriter.Write((int)(value as PyInteger ?? 0));
                    break;

                case FieldType.I2:
                case FieldType.UI2:
                    wholeByteWriter.Write((short)(value as PyInteger ?? 0));
                    break;

                case FieldType.I1:
                case FieldType.UI1:
                    wholeByteWriter.Write((byte)(value as PyInteger ?? 0));
                    break;

                case FieldType.R8:
                    wholeByteWriter.Write((double)(value as PyDecimal ?? 0));
                    break;

                case FieldType.R4:
                    wholeByteWriter.Write((float)(value as PyDecimal ?? 0));
                    break;

                // bools, bytes and str are handled differently
                case FieldType.Bool:
                    if (value as PyBool)
                    {
                        // bytes are written from right to left in the buffer
                        toWrite |= (byte)(1 << bitOffset);
                    }

                    bitOffset++;

                    if (bitOffset > 7)
                    {
                        // byte is full, write the byte to the stream
                        bitPacketWriter.Write(toWrite);
                        // reset the byte to keep using it as buffer
                        toWrite = 0;
                        // do the same for the next bit offset
                        bitOffset = 0;
                    }

                    break;

                case FieldType.Bytes:
                case FieldType.Str:
                case FieldType.WStr:
                    // write the object to the proper memory stream
                    Process(objectWriter, packedRow[column.Name]);
                    break;

                default:
                    throw new Exception($"Unknown field type {column.Type}");
                }
            }

            // after the column loop is done there might be some leftover compressed bits
            // that have to be written to the bit stream too
            if (bitOffset > 0)
            {
                bitPacketWriter.Write(toWrite);
            }

            // append the bitStream to the to the wholeByteWriter
            bitPacketStream.WriteTo(wholeByteStream);
            // create a reader for the stream
            wholeByteStream.Seek(0, SeekOrigin.Begin);
            // create the reader used to compress the buffer
            BinaryReader reader = new BinaryReader(wholeByteStream);

            // finally compress the data into the output
            ZeroCompressionUtils.ZeroCompress(reader, writer);
            // as last step write the encoded objects after the packed data
            objectStream.WriteTo(writer.BaseStream);
        }
Ejemplo n.º 8
0
        /// <summary>
        /// Converts the given <paramref name="packedRow"/> to it's byte array representation.
        /// Packed rows are the big elephant in the room. These are a direct representation of a row in any of the tables
        /// the server has and are composed of 3 parts.
        ///
        /// The first is the header that contains information about the columns that the PackedRow has data for.
        /// This header is known as <see cref="DBRowDescriptor" /> which is composed of a tuple with a string (column name)
        /// and an integer (column type). The column order doesn't matter on the header.
        ///
        /// The second part is the compressible bit data. Contains part of the actual data in the row. The columns are sorted
        /// by bit size in descending order, this way the amount of zeros one after the another is kept to a minimum, allowing
        /// the zero compression algorithm (<see cref="ZeroCompressionUtils" />) to greatly reduce the size of this data.
        /// Strings are not encoded here and are part of the third section of the PackedRow.
        /// The 1-bit sized columns (booleans) are encoded a bit differently from the rest of the data. Once the multi-bit
        /// sized data is written (long, int, short, byte) the bool values are grouped into 1 byte chunks, storing up to 8 booleans
        /// in each byte. The booleans are added to the byte from right to left and the byte blocks are written one after the other.
        /// These resources might be useful to better understand this operation
        /// https://stackoverflow.com/questions/36829860/using-binary-to-compress-boolean-array
        /// https://en.wikipedia.org/wiki/Bit_array
        /// https://sakai.rutgers.edu/wiki/site/e07619c5-a492-4ebe-8771-179dfe450ae4/bit-to-boolean%20conversion.html
        ///
        /// The third and last section contains the byte arrays and strings. These are encoded as normal python types
        /// after the second part.
        ///
        /// The following opcodes are supported
        /// <seealso cref="Opcode.PackedRow" />
        /// </summary>
        /// <param name="writer">Where to write the encoded data to</param>
        /// <param name="packedRow">The value to write</param>
        private static void ProcessPackedRow(BinaryWriter writer, PyPackedRow packedRow)
        {
            writer.WriteOpcode(Opcode.PackedRow);
            Process(writer, packedRow.Header);
            // bit where null flags will be written
            int booleanBits = 0;
            int nullBits    = 0;
            int wholeBytes  = 0;

            List <DBRowDescriptor.Column> booleanColumns = new List <DBRowDescriptor.Column>();

            foreach (DBRowDescriptor.Column column in packedRow.Header.Columns)
            {
                int bitLength = Utils.GetTypeBits(column.Type);

                if (column.Type == FieldType.Bool)
                {
                    booleanColumns.Add(column);
                    booleanBits++;
                }

                nullBits++;

                if (bitLength >= 8)
                {
                    wholeBytes += bitLength >> 3;
                }
            }

            // build byte buffers for the bitfields like booleans and nulls
            byte[] bitField = new byte[((booleanBits + nullBits) >> 3) + 1];

            // prepare the zero-compression stream
            MemoryStream wholeByteStream = new MemoryStream(wholeBytes + bitField.Length);
            MemoryStream objectStream    = new MemoryStream();

            BinaryWriter wholeByteWriter = new BinaryWriter(wholeByteStream);
            BinaryWriter objectWriter    = new BinaryWriter(objectStream);

            // sort the columns by size and obtain some important statistics
            IOrderedEnumerable <DBRowDescriptor.Column> enumerator = packedRow.Header.Columns.OrderByDescending(c => Utils.GetTypeBits(c.Type));

            foreach (DBRowDescriptor.Column column in enumerator)
            {
                PyDataType value = packedRow[column.Name];

                switch (column.Type)
                {
                case FieldType.I8:
                case FieldType.UI8:
                case FieldType.CY:
                case FieldType.FileTime:
                    wholeByteWriter.Write((long)(value as PyInteger ?? 0));
                    break;

                case FieldType.I4:
                case FieldType.UI4:
                    wholeByteWriter.Write((int)(value as PyInteger ?? 0));
                    break;

                case FieldType.I2:
                case FieldType.UI2:
                    wholeByteWriter.Write((short)(value as PyInteger ?? 0));
                    break;

                case FieldType.I1:
                case FieldType.UI1:
                    wholeByteWriter.Write((byte)(value as PyInteger ?? 0));
                    break;

                case FieldType.R8:
                    wholeByteWriter.Write((double)(value as PyDecimal ?? 0));
                    break;

                case FieldType.R4:
                    wholeByteWriter.Write((float)(value as PyDecimal ?? 0));
                    break;

                // bools, bytes and str are handled differently
                case FieldType.Bool:
                    if (value as PyBool)
                    {
                        int bit = booleanColumns.IndexOf(column);

                        bitField[bit >> 3] |= (byte)(1 << (bit & 0x7));
                    }

                    break;

                case FieldType.Bytes:
                case FieldType.Str:
                case FieldType.WStr:
                    // write the object to the proper memory stream
                    Process(objectWriter, packedRow[column.Name]);
                    continue;

                default:
                    throw new Exception($"Unknown field type {column.Type}");
                }

                if (value is null)
                {
                    int bit = packedRow.Header.Columns.IndexOf(column) + booleanBits;

                    bitField[bit >> 3] |= (byte)(1 << (bit & 0x7));
                }
            }

            // write the bit field buffer into the wholeByteWriter
            wholeByteWriter.Write(bitField);
            // create a reader for the stream
            wholeByteStream.Seek(0, SeekOrigin.Begin);
            // create the reader used to compress the buffer
            BinaryReader reader = new BinaryReader(wholeByteStream);

            // finally compress the data into the output
            ZeroCompressionUtils.ZeroCompress(reader, writer);
            // as last step write the encoded objects after the packed data
            objectStream.WriteTo(writer.BaseStream);
        }