Пример #1
0
        /// <summary>
        /// Logs the information embedded in the root node of the OTB tree.
        /// </summary>
        private static void ParseOTBTreeRootNode(OTBNode rootNode)
        {
            if (rootNode == null)
            {
                throw new ArgumentNullException(nameof(rootNode));
            }
            if (rootNode.Children.Count != 1)
            {
                throw new InvalidOperationException();
            }

            var parsingStream = new OTBParsingStream(rootNode.Data);

            var headerVersion = parsingStream.ReadUInt32();
            //if (headerVersion == 0 || headerVersion > 2)
            //	throw new InvalidOperationException();

            var worldWidth  = parsingStream.ReadUInt16();
            var worldHeight = parsingStream.ReadUInt16();

            var itemEncodingMajorVersion = parsingStream.ReadUInt32();
            //if (itemEncodingMajorVersion != SupportedItemEncodingMajorVersion)
            //	throw new InvalidOperationException();

            var itemEncodingMinorVersion = parsingStream.ReadUInt32();

            //if (itemEncodingMinorVersion < SupportedItemEncodingMinorVersion)
            //	throw new InvalidOperationException();

            _logger.Info($"OTBM header version: {headerVersion}.");
            _logger.Info($"World width: {worldWidth}.");
            _logger.Info($"World height: {worldHeight}.");
            _logger.Info($"Item encoding major version: {itemEncodingMajorVersion}.");
            _logger.Info($"Item encoding minor version: {itemEncodingMinorVersion}.");
        }
Пример #2
0
        /// <summary>
        /// Updates the <paramref name="world"/> with the data contained
        /// in <paramref name="tileAreaNode"/>.
        /// </summary>
        private static void ParseTileAreaNode(OTBNode tileAreaNode, World world)
        {
            if (tileAreaNode == null)
            {
                throw new ArgumentNullException(nameof(tileAreaNode));
            }
            if (tileAreaNode.Type != OTBNodeType.TileArea)
            {
                throw new InvalidOperationException();
            }

            var stream = new OTBParsingStream(tileAreaNode.Data);

            var areaStartX = stream.ReadUInt16();
            var areaStartY = stream.ReadUInt16();
            var areaZ      = (sbyte)stream.ReadByte();

            var areaStartPosition = new Coordinate(
                x: areaStartX,
                y: areaStartY,
                z: areaZ);

            foreach (var tileNode in tileAreaNode.Children)
            {
                ParseTileNode(
                    tilesAreaStartPosition: areaStartPosition,
                    tileNode: tileNode,
                    world: world);
            }
        }
Пример #3
0
        private static UInt16 GetItemIdAndConvertPvpFieldsToPermanentFields(OTBParsingStream stream)
        {
            var originalItemId = stream.ReadUInt16();
            var newItemId      = originalItemId;

            switch (originalItemId)
            {
            case (UInt16)OTBMWorldItemId.FireFieldPvpLarge:
                newItemId = (UInt16)OTBMWorldItemId.FireFieldPersistentLarge;
                break;

            case (UInt16)OTBMWorldItemId.FireFieldPvpMedium:
                newItemId = (UInt16)OTBMWorldItemId.FireFieldPersistentMedium;
                break;

            case (UInt16)OTBMWorldItemId.FireFieldPvpSmall:
                newItemId = (UInt16)OTBMWorldItemId.FireFieldPersistentSmall;
                break;

            case (UInt16)OTBMWorldItemId.EnergyFieldPvp:
                newItemId = (UInt16)OTBMWorldItemId.EnergyFieldPersistent;
                break;

            case (UInt16)OTBMWorldItemId.PoisonFieldPvp:
                newItemId = (UInt16)OTBMWorldItemId.PoisonFieldPersistent;
                break;

            case (UInt16)OTBMWorldItemId.MagicWall:
                newItemId = (UInt16)OTBMWorldItemId.MagicWallPersistent;
                break;

            case (UInt16)OTBMWorldItemId.WildGrowth:
                newItemId = (UInt16)OTBMWorldItemId.WildGrowthPersistent;
                break;

            default:
                break;
            }

            if (newItemId != originalItemId)
            {
                _logger.Warn($"Converted {(OTBMWorldItemId)originalItemId} to {(OTBMWorldItemId)newItemId}.");
            }

            return(newItemId);
        }
Пример #4
0
        public void ReadByte_WithoutEscapeBytes(byte[] buffer, byte[] expectedBytes)
        {
            var stream = new OTBParsingStream(buffer);

            var bytesRead = new List <byte>();

            while (!stream.IsOver)
            {
                bytesRead.Add(stream.ReadByte());
            }

            var actualBytes = bytesRead.ToArray();

            Assert.AreEqual(
                expected: expectedBytes,
                actual: actualBytes);
        }
Пример #5
0
        private static Item ParseItemData(OTBParsingStream stream)
        {
            var newItemId = GetItemIdAndConvertPvpFieldsToPermanentFields(stream);

            var item = ItemFactory.Create(newItemId);

            if (item == null)
            {
                _logger.Warn($"{nameof(ItemFactory)} was unable to create a item with id: {newItemId}.");
                return(null);
            }

            //if(!stream.IsOver && item.Count > 0) {
            //	var itemAttribute = (OTBMWorldItemAttribute)stream.ReadByte();
            //	itemAttribute = (OTBMWorldItemAttribute)stream.ReadByte();
            //	itemAttribute = (OTBMWorldItemAttribute)stream.ReadByte();
            //	itemAttribute = (OTBMWorldItemAttribute)stream.ReadByte();
            //	while (!stream.IsOver && itemAttribute != OTBMWorldItemAttribute.None && itemAttribute != OTBMWorldItemAttribute.None2) {
            //		switch (itemAttribute) {
            //			case OTBMWorldItemAttribute.Count:
            //			case OTBMWorldItemAttribute.RuneCharges:
            //			var count = stream.ReadByte();
            //			item.SetAmount(count);
            //			break;

            //			case OTBMWorldItemAttribute.ActionId:
            //			var actionId = stream.ReadUInt16();
            //			_logger.Warn($"OTBM {nameof(OTBMWorldItemAttribute.ActionId)} not implemented.");
            //			break;

            //			case OTBMWorldItemAttribute.UniqueId:
            //			var uniqueId = stream.ReadUInt16();
            //			_logger.Warn($"OTBM {nameof(OTBMWorldItemAttribute.UniqueId)} not implemented.");
            //			break;

            //			case OTBMWorldItemAttribute.Text:
            //			var text = stream.ReadString();
            //			_logger.Warn($"OTBM {nameof(OTBMWorldItemAttribute.Text)} not implemented.");
            //			break;

            //			case OTBMWorldItemAttribute.WrittenDate:
            //			var writtenDate = stream.ReadUInt32();
            //			_logger.Warn($"OTBM {nameof(OTBMWorldItemAttribute.WrittenDate)} not implemented.");
            //			break;

            //			case OTBMWorldItemAttribute.WrittenBy:
            //			var writtenBy = stream.ReadString();
            //			_logger.Warn($"OTBM {nameof(OTBMWorldItemAttribute.WrittenBy)} not implemented.");
            //			break;

            //			case OTBMWorldItemAttribute.Description:
            //			var anotherDescription = stream.ReadString();
            //			_logger.Warn($"OTBM {nameof(OTBMWorldItemAttribute.Description)} not implemented.");
            //			break;

            //			case OTBMWorldItemAttribute.Charges:
            //			var charges = stream.ReadUInt16();
            //			_logger.Warn($"OTBM {nameof(OTBMWorldItemAttribute.Charges)} not implemented.");
            //			break;

            //			case OTBMWorldItemAttribute.Duration:
            //			var duration = stream.ReadUInt32();
            //			_logger.Warn($"OTBM {nameof(OTBMWorldItemAttribute.Duration)} not implemented.");
            //			break;

            //			case OTBMWorldItemAttribute.DecayingState:
            //			var decayingState = stream.ReadByte();
            //			_logger.Warn($"OTBM {nameof(OTBMWorldItemAttribute.DecayingState)} not implemented.");
            //			break;

            //			case OTBMWorldItemAttribute.Name:
            //			var name = stream.ReadString();
            //			_logger.Warn($"OTBM {nameof(OTBMWorldItemAttribute.Name)} not implemented.");
            //			break;

            //			case OTBMWorldItemAttribute.Article:
            //			var article = stream.ReadString();
            //			_logger.Warn($"OTBM {nameof(OTBMWorldItemAttribute.Article)} not implemented.");
            //			break;

            //			case OTBMWorldItemAttribute.PluralName:
            //			var pluralName = stream.ReadString();
            //			_logger.Warn($"OTBM {nameof(OTBMWorldItemAttribute.Article)} not implemented.");
            //			break;

            //			case OTBMWorldItemAttribute.Weight:
            //			var weight = stream.ReadUInt32();
            //			_logger.Warn($"OTBM {nameof(OTBMWorldItemAttribute.Weight)} not implemented.");
            //			break;

            //			case OTBMWorldItemAttribute.Attack:
            //			var attack = stream.ReadUInt32();
            //			_logger.Warn($"OTBM {nameof(OTBMWorldItemAttribute.Attack)} not implemented.");
            //			break;

            //			case OTBMWorldItemAttribute.Defense:
            //			var defense = stream.ReadUInt32();
            //			_logger.Warn($"OTBM {nameof(OTBMWorldItemAttribute.Defense)} not implemented.");
            //			break;

            //			case OTBMWorldItemAttribute.ExtraDefense:
            //			var extraDefense = stream.ReadUInt32();
            //			_logger.Warn($"OTBM {nameof(OTBMWorldItemAttribute.ExtraDefense)} not implemented.");
            //			break;

            //			case OTBMWorldItemAttribute.Armor:
            //			var armor = stream.ReadUInt32();
            //			_logger.Warn($"OTBM {nameof(OTBMWorldItemAttribute.Armor)} not implemented.");
            //			break;

            //			case OTBMWorldItemAttribute.HitChance:
            //			var hitChance = stream.ReadUInt32();
            //			_logger.Warn($"OTBM {nameof(OTBMWorldItemAttribute.HitChance)} not implemented.");
            //			break;

            //			case OTBMWorldItemAttribute.ShootRange:
            //			var shootRange = stream.ReadUInt32();
            //			_logger.Warn($"OTBM {nameof(OTBMWorldItemAttribute.ShootRange)} not implemented.");
            //			break;

            //			case OTBMWorldItemAttribute.DepotId:
            //			var depotId = stream.ReadUInt32();
            //			_logger.Warn($"OTBM {nameof(OTBMWorldItemAttribute.DepotId)} not implemented.");
            //			break;

            //			case OTBMWorldItemAttribute.HouseDorId:
            //			var hourDoorId = stream.ReadUInt32();
            //			_logger.Warn($"OTBM {nameof(OTBMWorldItemAttribute.HouseDorId)} not implemented.");
            //			break;

            //			case OTBMWorldItemAttribute.SleeperGUID:
            //			var sleeperGUID = stream.ReadUInt32();
            //			_logger.Warn($"OTBM {nameof(OTBMWorldItemAttribute.SleeperGUID)} not implemented.");
            //			break;

            //			case OTBMWorldItemAttribute.SleepStart:
            //			var sleepStart = stream.ReadUInt32();
            //			_logger.Warn($"OTBM {nameof(OTBMWorldItemAttribute.SleepStart)} not implemented.");
            //			break;

            //			case OTBMWorldItemAttribute.TeleportDestination:
            //			var teleportDestination = stream.ReadUInt32();
            //			_logger.Warn($"OTBM {nameof(OTBMWorldItemAttribute.TeleportDestination)} not implemented.");
            //			break;

            //			case OTBMWorldItemAttribute.ContainerItems:
            //			throw new InvalidOperationException("TFS threw an exception here, so we're throwing too.");

            //			case OTBMWorldItemAttribute.CustomAttributes:
            //			var size = stream.ReadUInt64();
            //			_logger.Warn($"OTBM {nameof(OTBMWorldItemAttribute.CustomAttributes)} not implemented.");
            //			for (UInt64 i = 0; i < size; i++) {
            //				var key = stream.ReadString();
            //				var pos = (OTBMCustomAttributeValueType)stream.ReadByte();
            //				object value;

            //				switch (pos) {
            //					case OTBMCustomAttributeValueType.String:
            //					value = stream.ReadString();
            //					break;

            //					case OTBMCustomAttributeValueType.Int64:
            //					value = stream.ReadUInt64();
            //					break;

            //					case OTBMCustomAttributeValueType.Double:
            //					value = stream.ReadDouble();
            //					break;

            //					case OTBMCustomAttributeValueType.Bool:
            //					value = stream.ReadBool();
            //					break;

            //					default:
            //					value = new object();
            //					break;
            //				}
            //			}
            //			break;

            //			case OTBMWorldItemAttribute.AnotherDescription:
            //			throw new InvalidOperationException("TFS didn't implement this.");

            //			case OTBMWorldItemAttribute.ExtensionFile:
            //			throw new InvalidOperationException("TFS didn't implement this.");

            //			case OTBMWorldItemAttribute.TileFlags:
            //			throw new InvalidOperationException("TFS didn't implement this.");

            //			case OTBMWorldItemAttribute.Item:
            //			throw new InvalidOperationException("TFS didn't implement this.");

            //			case OTBMWorldItemAttribute.ExtensionFileForSpawns:
            //			throw new InvalidOperationException("TFS didn't implement this.");

            //			case OTBMWorldItemAttribute.ExtensionFileForHouses:
            //			throw new InvalidOperationException("TFS didn't implement this.");

            //			default:
            //			throw new InvalidOperationException($"Unknown {nameof(OTBMWorldItemAttribute)}.");
            //		}
            //	}
            //}

            return(item);
        }
Пример #6
0
        public Dictionary <ushort, ItemType> LoadOTItems()
        {
            var itemDictionary = new Dictionary <UInt16, ItemType>();

            var attrsNotSuported = 0;
            var attrsNotValid    = 0;

            var fileTree = OTBDeserializer.DeserializeOTBData(new ReadOnlyMemory <byte>(ServerResourcesManager.GetItemsBytes("items.otb")));

            foreach (var itemChildren in fileTree.Children)
            {
                var current    = new ItemType();
                var itemStream = new OTBParsingStream(itemChildren.Data);

                var flags = itemStream.ReadUInt32();
                current.ParseOTFlags(flags);

                while (!itemStream.IsOver)
                {
                    var attr     = itemStream.ReadByte();
                    var dataSize = itemStream.ReadUInt16();

                    switch ((ItemAttributes)attr)
                    {
                    case ItemAttributes.ServerId:
                        var serverId = itemStream.ReadUInt16();

                        if (serverId == 4535)
                        {
                            serverId = 4535;
                        }

                        if (serverId > 30000 && serverId < 30100)
                        {
                            serverId -= 30000;
                        }

                        current.SetId(serverId);
                        break;

                    case ItemAttributes.ClientId:
                        current.SetClientId(itemStream.ReadUInt16());
                        break;

                    default:
                        itemStream.Skip(dataSize);
                        break;
                    }
                }
                itemDictionary.Add(current.TypeId, current);
            }

            var rootElement = XElement.Load(ServerResourcesManager.GetItems("items.xml"), LoadOptions.SetLineInfo);

            foreach (var element in rootElement.Elements("item"))
            {
                var id     = element.Attribute("id");
                var fromId = element.Attribute("fromid");
                var toId   = element.Attribute("toid");

                // Malformed element, missing id information, ignore it
                if (id == null && (fromId == null || toId == null))
                {
                    continue;
                }

                ushort serverId = 0;
                ushort aplyTo   = 1;
                if (id == null)
                {
                    // Ignore if can't parse the values or if fromId >= toId
                    if (!ushort.TryParse(fromId.Value, out serverId) || !ushort.TryParse(toId.Value, out aplyTo) || serverId >= aplyTo)
                    {
                        continue;
                    }

                    aplyTo -= serverId;
                }
                else
                {
                    if (!ushort.TryParse(id.Value, out serverId))
                    {
                        continue;
                    }
                }

                for (ushort key = serverId; key < serverId + aplyTo; key++)
                {
                    if (!itemDictionary.TryGetValue(key, out ItemType current))
                    {
                        continue;
                    }

                    var name = element.Attribute("name");
                    if (name != null)
                    {
                        current.SetName(name.Value);
                    }

                    foreach (var attribute in element.Elements("attribute"))
                    {
                        var attrName  = attribute.Attribute("key");
                        var attrValue = attribute.Attribute("value");

                        if (attrName == null || attrValue == null)
                        {
                            continue;
                        }

                        if (attrName.Value == "description")
                        {
                            current.SetDescription(attrValue.Value);
                            continue;
                        }

                        var lineInfo = (IXmlLineInfo)attribute;
                        var attr     = OpenTibiaTranslationMap.TranslateAttributeName(attrName.Value, out bool success);

                        if (success)
                        {
                            int  value   = -1;
                            bool setAttr = true;
                            switch (attrName.Value)
                            {
                            case "weaponType":
                                success = current.ParseOTWeaponType(attrValue.Value);
                                setAttr = false;
                                break;

                            case "fluidSource":
                                value = OpenTibiaTranslationMap.TranslateLiquidType(attrValue.Value, out success);
                                break;

                            case "corpseType":
                                value = OpenTibiaTranslationMap.TranslateCorpseType(attrValue.Value, out success);
                                break;

                            case "slotType":
                                value = OpenTibiaTranslationMap.TranslateSlotType(attrValue.Value, out success);
                                break;

                            default:
                                success = int.TryParse(attrValue.Value, out value);
                                break;
                            }

                            if (!success)
                            {
                                attrsNotValid++;
                                //Console.WriteLine($"[{Path.GetFileName(itemExtensionFilePath)}:{lineInfo.LineNumber}] \"{attrValue.Value}\" is not a valid value for attribute \"{attrName.Value}\"");
                            }
                            else if (setAttr)
                            {
                                current.SetAttribute(attr, value);
                            }
                        }
                        else
                        {
                            attrsNotSuported++;
                            //Console.WriteLine($"[{Path.GetFileName(itemExtensionFilePath)}:{lineInfo.LineNumber}] Attribute \"{attrName.Value}\" is not supported!");
                        }
                    }
                }
            }

            foreach (var type in itemDictionary)
            {
                type.Value.LockChanges();
            }

            Console.WriteLine($"Items with attributes not supported: {attrsNotSuported}");
            Console.WriteLine($"Not valid attributes: {attrsNotSuported}");

            return(itemDictionary);
        }