public static OTBNode ParseOTBTree(byte[] serializedTreeData)
        {
            var treeBuilder = new OTBTreeBuilder(serializedTreeData);

            for (int i = 0; i < serializedTreeData.Length; i++)
            {
                var markupByte = (OTBMarkupByte)serializedTreeData[i];
                switch (markupByte)
                {
                case OTBMarkupByte.Escape:
                    i++;
                    break;

                case OTBMarkupByte.Start:
                    treeBuilder.AddNodeBegin(i + 1, OTBNodeType.NotSetYet);
                    break;

                case OTBMarkupByte.End:
                    treeBuilder.AddNodeEnd(i);
                    break;
                }
            }

            return(treeBuilder.BuildTree());
        }
Example #2
0
        public static World ParseWorld(byte[] serializedWorldData)
        {
            if (serializedWorldData.Length < MinimumWorldSize)
            {
                throw new TFSWorldLoadingException();
            }

            //var otbTree = ExtractOTBTree(serializedWorldData);
            var otbTree = new OTBTreeBuilder(serializedWorldData).BuildTree();
            var world   = new World();

            ParseOTBTreeRootNode(otbTree, world);
            Parse(otbTree.Children[0], world);

            throw new NotImplementedException();
        }
Example #3
0
        private static OTBNode ExtractOTBTree(byte[] serializedWorldData)
        {
            var stream = new ReadOnlyMemoryStream(serializedWorldData);

            // Skipping the first 4 bytes coz they are used to store a... identifier?
            stream.Skip(IdentifierLength);

            var treeBuilder = new OTBTreeBuilder(serializedWorldData);

            while (!stream.IsOver)
            {
                var currentMark = (OTBMarkupByte)stream.ReadByte();
                if (currentMark < OTBMarkupByte.Escape)
                {
                    /// Since <see cref="OTBMarkupByte"/> can only have values Escape (0xFD), Start (0xFE) and
                    /// End (0xFF), if currentMark < Escape, then it's just prop data
                    /// and we can safely skip it.
                    continue;
                }

                var nodeType = (OTBNodeType)stream.ReadByte();

                switch (currentMark)
                {
                case OTBMarkupByte.Start:
                    treeBuilder.AddNodeBegin(
                        start: stream.Position,
                        type: nodeType);
                    break;

                case OTBMarkupByte.End:
                    treeBuilder.AddNodeEnd(stream.Position);
                    break;

                case OTBMarkupByte.Escape:
                    stream.Skip();
                    break;

                default:
                    throw new InvalidOperationException();
                }
            }

            return(treeBuilder.BuildTree());
        }
        private static void LoadItemsFromOTB(string path)
        {
            var data = FileManager.ReadFileToByteArray(path);
            var tree = new OTBTreeBuilder(data).BuildTree();


            // SKIP to nodes

            _items = new List <IBaseItemPrototype>(30000);

            foreach (var itemNode in tree.Children)
            {
                var itemStream = new ReadOnlyMemoryStream(itemNode.Data.Span);

                var flags = itemStream.ReadUInt32();

                ushort serverId   = 0;
                ushort clientId   = 0;
                ushort wareId     = 0;
                ushort speed      = 0;
                byte   lightLevel = 0;
                byte   lightColor = 0;
                byte   topOrder   = 0;

                var  toSkip  = 0;
                bool escaped = false;
                while (!itemStream.IsOver)
                {
                    var attr     = itemStream.ReadByte();
                    var isEscape = (OTBMarkupByte)attr == OTBMarkupByte.Escape;
                    if (toSkip > 0)
                    {
                        if (isEscape)
                        {
                            if (escaped)
                            {
                                toSkip++;
                                escaped = false;
                            }
                            else
                            {
                                toSkip--;
                                escaped = true;
                            }
                        }
                        else
                        {
                            toSkip--;
                        }

                        if (toSkip == 0)
                        {
                            break;
                        }

                        continue;
                    }

                    var dataSize = itemStream.ReadUInt16();

                    switch (attr)
                    {
                    case 0x10:     // ServerID 0x10 = 16
                        serverId = itemStream.ReadUInt16();
                        break;

                    case 0x11:     // ClientID 0x11 = 17
                        clientId = itemStream.ReadUInt16();
                        break;

                    case 0x14:     // Speed 0x14 = 20
                        speed = itemStream.ReadUInt16();
                        break;

                    case 0x2A:     // LightBlock 0x2A = 42
                        lightLevel = (byte)itemStream.ReadUInt16();
                        lightColor = (byte)itemStream.ReadUInt16();
                        break;

                    case 0x2B:     // TopOrder 0x2B = 43
                        topOrder = itemStream.ReadByte();
                        break;

                    case 0x2D:     // WareID 0x2D = 45
                        wareId = (byte)itemStream.ReadUInt16();
                        break;

                    default:
                        toSkip = dataSize;
                        break;
                    }
                }
                var blockSolid      = HasFlag(flags, 1 << 0);
                var blockProjectile = HasFlag(flags, 1 << 1);
                var blockPathFind   = HasFlag(flags, 1 << 2);
                //var hasElevation = HasFlag(flags, 1 << 3); // Irrelevant
                var isUsable     = HasFlag(flags, 1 << 4);
                var isPickupable = HasFlag(flags, 1 << 5);
                var isMoveable   = HasFlag(flags, 1 << 6);
                //var isStackable = HasFlag(flags, 1 << 7);
                var alwaysOnTop   = HasFlag(flags, 1 << 13); // Maybe irrelevant
                var isReadable    = HasFlag(flags, 1 << 14);
                var isRotatable   = HasFlag(flags, 1 << 15);
                var isHangable    = HasFlag(flags, 1 << 16);
                var isVertical    = HasFlag(flags, 1 << 17);
                var isHorizontal  = HasFlag(flags, 1 << 18);
                var allowDistRead = HasFlag(flags, 1 << 20);
                var lookTrough    = HasFlag(flags, 1 << 21);
                var isAnimation   = HasFlag(flags, 1 << 22); // Maybe irrelevant too?

                IBaseItemPrototype item = null;
                if (!isPickupable)  // A world item
                {
                    item = new WorldItemPrototype(serverId, clientId, isUsable,
                                                  isMoveable, blockSolid, lookTrough, blockPathFind, blockProjectile);
                }
                else    // An item
                {
                    item = new ItemPrototype(serverId, clientId, isUsable);
                }

                if (item != null)
                {
                    _items.Add(item);
                }
            }

            _items.TrimExcess();
        }