public static GuildMetadata Parse(MemoryMappedFile m2dFile, IEnumerable <PackFileEntry> entries) { GuildMetadata guildMetadata = new GuildMetadata(); foreach (PackFileEntry entry in entries) { if (!entry.Name.StartsWith("table/guildcontribution")) { continue; } // Parse XML XmlDocument document = m2dFile.GetDocument(entry.FileHeader); XmlNodeList contributions = document.SelectNodes("/ms2/contribution"); foreach (XmlNode contribution in contributions) { string type = contribution.Attributes["type"].Value; int value = int.Parse(contribution.Attributes["value"].Value); guildMetadata.Contribution.Add(new GuildContribution(type, value)); } } foreach (PackFileEntry entry in entries) { if (!entry.Name.StartsWith("table/guildbuff")) { continue; } // Parse XML XmlDocument document = m2dFile.GetDocument(entry.FileHeader); XmlNodeList buffs = document.SelectNodes("/ms2/guildBuff"); foreach (XmlNode buff in buffs) { int id = int.Parse(buff.Attributes["id"].Value); byte level = byte.Parse(buff.Attributes["level"].Value); int effectId = int.Parse(buff.Attributes["additionalEffectId"].Value); byte effectLevel = byte.Parse(buff.Attributes["additionalEffectLevel"].Value); byte levelRequirement = byte.Parse(buff.Attributes["requireLevel"].Value); int upgradeCost = int.Parse(buff.Attributes["upgradeCost"].Value); int cost = int.Parse(buff.Attributes["cost"].Value); short duration = short.Parse(buff.Attributes["duration"].Value); guildMetadata.Buff.Add(new GuildBuff(id, level, effectId, effectLevel, levelRequirement, upgradeCost, cost, duration)); } } return(guildMetadata); }
public static PrestigeMetadata Parse(MemoryMappedFile m2dFile, IEnumerable <PackFileEntry> entries) { PrestigeMetadata prestigeMetadata = new PrestigeMetadata(); foreach (PackFileEntry entry in entries) { // Only check for reward for now, abilities will need to be added later if (!entry.Name.StartsWith("table/adventurelevelreward")) { continue; } // Parse XML XmlDocument document = m2dFile.GetDocument(entry.FileHeader); XmlNodeList rewards = document.SelectNodes("/ms2/reward"); foreach (XmlNode reward in rewards) { int level = int.Parse(reward.Attributes["level"].Value); string type = reward.Attributes["type"].Value; int id = int.Parse(reward.Attributes["id"].Value.Length == 0 ? "0" : reward.Attributes["id"].Value); int value = int.Parse(reward.Attributes["value"].Value); prestigeMetadata.Rewards.Add(new PrestigeReward(level, type, id, value)); } } return(prestigeMetadata); }
public static List <MapEntityMetadata> Parse(MemoryMappedFile m2dFile, IEnumerable <PackFileEntry> entries) { List <MapEntityMetadata> entities = new List <MapEntityMetadata>(); Dictionary <string, string> maps = new Dictionary <string, string>(); foreach (PackFileEntry entry in entries) { if (!entry.Name.StartsWith("xblock/")) { continue; } string mapIdStr = Regex.Match(entry.Name, @"\d{8}").Value; if (string.IsNullOrEmpty(mapIdStr)) { continue; } int mapId = int.Parse(mapIdStr); if (maps.ContainsKey(mapIdStr)) { Console.WriteLine($"Duplicate {entry.Name} was already added as {maps[mapIdStr]}"); continue; } maps.Add(mapIdStr, entry.Name); MapEntityMetadata metadata = new MapEntityMetadata(mapId); XmlDocument document = m2dFile.GetDocument(entry.FileHeader); XmlNodeList mapEntities = document.SelectNodes("/game/entitySet/entity"); foreach (XmlNode node in mapEntities) { if (node.Attributes["name"].Value.Contains("SpawnPointPC")) { XmlNode playerCoord = node.SelectSingleNode("property[@name='Position']"); XmlNode playerRotation = node.SelectSingleNode("property[@name='Rotation']"); string playerPositionValue = playerCoord?.FirstChild.Attributes["value"].Value ?? "0, 0, 0"; string playerRotationValue = playerRotation?.FirstChild.Attributes["value"].Value ?? "0, 0, 0"; metadata.PlayerSpawns.Add(new MapPlayerSpawn(ParseCoord(playerPositionValue), ParseCoord(playerRotationValue))); } } //XmlNodeList nodes = document.SelectNodes("/game/entitySet/entity/property[@name='NpcList']"); XmlNodeList nodes = document.SelectNodes("/game/entitySet/entity/property"); foreach (XmlNode node in nodes) { if (node.Attributes["name"].Value == "NpcList") { if (node.FirstChild != null) { XmlNode parent = node.ParentNode; try { XmlNode coordNode = parent.SelectSingleNode("property[@name='Position']"); XmlNode rotationNode = parent.SelectSingleNode("property[@name='Rotation']"); int npcId = int.Parse(node.FirstChild.Attributes["index"].Value); string positionValue = coordNode?.FirstChild.Attributes["value"].Value ?? "0, 0, 0"; string rotationValue = rotationNode?.FirstChild.Attributes["value"].Value ?? "0, 0, 0"; CoordS position = ParseCoord(positionValue); CoordS rotation = ParseCoord(rotationValue); metadata.Npcs.Add(new MapNpc(npcId, position, rotation)); } catch (Exception ex) { Console.WriteLine(ex); Console.WriteLine(mapId); Console.WriteLine("Failed NPC " + parent.InnerXml); } } } else if (node.Attributes["name"].Value == "PortalID") { XmlNode parent = node.ParentNode; try { XmlNode visibleNode = parent.SelectSingleNode("property[@name='IsVisible']"); XmlNode enabledNode = parent.SelectSingleNode("property[@name='PortalEnable']"); XmlNode minimapVisibleNode = parent.SelectSingleNode("property[@name='MinimapIconVisible']"); XmlNode targetNode = parent.SelectSingleNode("property[@name='TargetFieldSN']"); XmlNode coordNode = parent.SelectSingleNode("property[@name='Position']"); XmlNode rotationNode = parent.SelectSingleNode("property[@name='Rotation']"); if (targetNode == null) { continue; } if (!bool.TryParse(visibleNode?.FirstChild.Attributes["value"].Value, out bool visibleValue)) { visibleValue = true; } if (!bool.TryParse(enabledNode?.FirstChild.Attributes["value"].Value, out bool enabledValue)) { enabledValue = true; } if (!bool.TryParse(minimapVisibleNode?.FirstChild.Attributes["value"].Value, out bool minimapVisibleValue)) { minimapVisibleValue = true; } int target = int.Parse(targetNode.FirstChild.Attributes["value"].Value); int portalId = int.Parse(node.FirstChild.Attributes["value"].Value); string positionValue = coordNode?.FirstChild.Attributes["value"].Value ?? "0, 0, 0"; string rotationValue = rotationNode?.FirstChild.Attributes["value"].Value ?? "0, 0, 0"; MapPortalFlag flags = visibleValue ? MapPortalFlag.Visible : MapPortalFlag.None; flags |= enabledValue ? MapPortalFlag.Enabled : MapPortalFlag.None; flags |= minimapVisibleValue ? MapPortalFlag.MinimapVisible : MapPortalFlag.None; CoordS position = ParseCoord(positionValue); CoordS rotation = ParseCoord(rotationValue); metadata.Portals.Add(new MapPortal(portalId, flags, target, position, rotation)); } catch (Exception ex) { Console.WriteLine(ex); Console.WriteLine(mapId); Console.WriteLine("Failed NPC " + parent.InnerXml); } } } // No data on this map if (metadata.Npcs.Count == 0 && metadata.Portals.Count == 0 && metadata.PlayerSpawns.Count == 0) { continue; } entities.Add(metadata); } return(entities); }
public static List <ItemMetadata> Parse(MemoryMappedFile m2dFile, IEnumerable <PackFileEntry> entries) { List <ItemMetadata> items = new List <ItemMetadata>(); foreach (PackFileEntry entry in entries) { if (!entry.Name.StartsWith("item/")) { continue; } ItemMetadata metadata = new ItemMetadata(); string itemId = Path.GetFileNameWithoutExtension(entry.Name); if (items.Exists(item => item.Id.ToString() == itemId)) { //Console.WriteLine($"Duplicate {entry.Name} was already added."); continue; } metadata.Id = int.Parse(itemId); Debug.Assert(metadata.Id > 0, $"Invalid Id {metadata.Id} from {itemId}"); using XmlReader reader = m2dFile.GetReader(entry.FileHeader); while (reader.Read()) { if (reader.NodeType != XmlNodeType.Element) { continue; } if (reader.Name == "slot") { bool result = Enum.TryParse <ItemSlot>(reader["name"], out metadata.Slot); if (!result && !string.IsNullOrEmpty(reader["name"])) { throw new ArgumentException("Failed to parse item slot:" + reader["name"]); } } else if (reader.Name == "gem") { bool result = Enum.TryParse <GemSlot>(reader["system"], out metadata.Gem); if (!result && !string.IsNullOrEmpty(reader["system"])) { throw new ArgumentException("Failed to parse item slot:" + reader["system"]); } } else if (reader.Name == "property") { try { byte type = byte.Parse(reader["type"]); byte subType = byte.Parse(reader["subtype"]); bool skin = byte.Parse(reader["skin"]) != 0; metadata.Tab = GetTab(type, subType, skin); metadata.IsTemplate = byte.Parse(reader["skinType"] ?? "0") == 99; } catch (Exception e) { Console.WriteLine($"Failed {itemId}: {e.Message}"); } metadata.SlotMax = int.Parse(reader["slotMax"]); } else if (reader.Name == "option") { int rarity = 1; if (reader["constant"].Length == 1) { rarity = int.Parse(reader["constant"]); } metadata.Rarity = rarity; } else if (reader.Name == "function") { string contentType = reader["name"]; if (contentType != "OpenItemBox" && contentType != "SelectItemBox") { continue; } // selection boxes are SelectItemBox and 1,boxid // normal boxes are OpenItemBox and 0,1,0,boxid // fragments are OpenItemBox and 0,1,0,boxid,required_amount List <string> parameters = new List <string>(reader["parameter"].Split(",")); // Remove empty params parameters.RemoveAll(param => param.Length == 0); if (parameters.Count < 2) { continue; } string boxId = contentType == "OpenItemBox" ? parameters[3] : parameters[1]; foreach (PackFileEntry innerEntry in entries) { if (!innerEntry.Name.StartsWith("table/individualitemdrop") && !innerEntry.Name.StartsWith("table/na/individualitemdrop")) { continue; } if (metadata.Content.Count > 0) { continue; } // Parse XML XmlDocument document = m2dFile.GetDocument(innerEntry.FileHeader); XmlNodeList individualBoxItems = document.SelectNodes($"/ms2/individualDropBox[@individualDropBoxID={boxId}]"); foreach (XmlNode individualBoxItem in individualBoxItems) { int id = int.Parse(individualBoxItem.Attributes["item"].Value); int minAmount = int.Parse(individualBoxItem.Attributes["minCount"].Value); int maxAmount = int.Parse(individualBoxItem.Attributes["maxCount"].Value); int dropGroup = int.Parse(individualBoxItem.Attributes["dropGroup"].Value); int smartDropRate = string.IsNullOrEmpty(individualBoxItem.Attributes["smartDropRate"]?.Value) ? 0 : int.Parse(individualBoxItem.Attributes["smartDropRate"].Value); int rarity = string.IsNullOrEmpty(individualBoxItem.Attributes["PackageUIShowGrade"]?.Value) ? 0 : int.Parse(individualBoxItem.Attributes["PackageUIShowGrade"].Value); int enchant = string.IsNullOrEmpty(individualBoxItem.Attributes["enchantLevel"]?.Value) ? 0 : int.Parse(individualBoxItem.Attributes["enchantLevel"].Value); int id2 = string.IsNullOrEmpty(individualBoxItem.Attributes["item2"]?.Value) ? 0 : int.Parse(individualBoxItem.Attributes["item2"].Value); // Skip already existing item, this may need to check for locales but not certain if (metadata.Content.Exists(content => content.Id == id)) { continue; } metadata.Content.Add(new ItemContent(id, minAmount, maxAmount, dropGroup, smartDropRate, rarity, enchant, id2)); } } } else if (reader.Name == "MusicScore") { int playCount = int.Parse(reader["playCount"]); metadata.PlayCount = playCount; } else if (reader.Name == "limit") { if (!string.IsNullOrEmpty(reader["recommendJobs"])) { List <string> temp = new List <string>(reader["recommendJobs"].Split(",")); foreach (string item in temp) { metadata.RecommendJobs.Add(int.Parse(item)); } } } } items.Add(metadata); } return(items); }
public static List <SkillMetadata> Parse(MemoryMappedFile m2dFile, IEnumerable <PackFileEntry> entries) { List <SkillMetadata> skillList = new List <SkillMetadata>(); foreach (PackFileEntry entry in entries) { // Parsing Skills if (entry.Name.StartsWith("skill")) { string skillId = Path.GetFileNameWithoutExtension(entry.Name); SkillMetadata metadata = new SkillMetadata(); List <SkillLevel> skillLevels = new List <SkillLevel>(); metadata.SkillId = int.Parse(skillId); XmlDocument document = m2dFile.GetDocument(entry.FileHeader); XmlNodeList levels = document.SelectNodes("/ms2/level"); foreach (XmlNode level in levels) { // Getting all skills level string feature = level.Attributes["feature"] != null ? level.Attributes["feature"].Value : ""; int levelValue = level.Attributes["value"].Value != null?int.Parse(level.Attributes["value"].Value) : 0; int spirit = level.SelectSingleNode("consume/stat").Attributes["sp"] != null?int.Parse(level.SelectSingleNode("consume/stat").Attributes["sp"].Value) : 0; float damageRate = level.SelectSingleNode("motion/attack/damageProperty") != null?float.Parse(level.SelectSingleNode("motion/attack/damageProperty").Attributes["rate"].Value) : 0; skillLevels.Add(new SkillLevel(levelValue, spirit, damageRate, feature)); } metadata.SkillLevels = skillLevels; skillList.Add(metadata); } // Parsing SubSkills else if (entry.Name.StartsWith("table/job")) { XmlDocument document = m2dFile.GetDocument(entry.FileHeader); XmlNodeList jobs = document.SelectNodes("/ms2/job"); foreach (XmlNode job in jobs) { if (job.Attributes["feature"] != null) // Getting attribute that just have "feature" { string feature = job.Attributes["feature"].Value; if (feature == "JobChange_02") // Getting JobChange_02 skillList for now until better handle Awakening system. { XmlNode skills = job.SelectSingleNode("skills"); int jobCode = int.Parse(job.Attributes["code"].Value); for (int i = 0; i < skills.ChildNodes.Count; i++) { int id = int.Parse(skills.ChildNodes[i].Attributes["main"].Value); int[] sub = new int[0]; SkillMetadata skill = skillList.Find(x => x.SkillId == id); // This find the skill in the SkillList skill.Job = jobCode; if (skills.ChildNodes[i].Attributes["sub"] != null) { if (skillList.Select(x => x.SkillId).Contains(id)) { sub = Array.ConvertAll(skills.ChildNodes[i].Attributes["sub"].Value.Split(","), int.Parse); skill.SubSkills = sub; for (int n = 0; n < sub.Length; n++) { if (skillList.Select(x => x.SkillId).Contains(sub[n])) { skillList.Find(x => x.SkillId == sub[n]).Job = jobCode; } } } } } XmlNode learn = job.SelectSingleNode("learn"); for (int i = 0; i < learn.ChildNodes.Count; i++) { int id = int.Parse(learn.ChildNodes[i].Attributes["id"].Value); skillList.Find(x => x.SkillId == id).Learned = 1; } } } else if (job.Attributes["code"].Value == "001") { XmlNode skills = job.SelectSingleNode("skills"); for (int i = 0; i < skills.ChildNodes.Count; i++) { int id = int.Parse(skills.ChildNodes[i].Attributes["main"].Value); int[] sub = new int[0]; if (skills.ChildNodes[i].Attributes["sub"] != null) { sub = Array.ConvertAll(skills.ChildNodes[i].Attributes["sub"].Value.Split(","), int.Parse); } } } } } } return(skillList); }
public static List <ScriptMetadata> ParseNpc(MemoryMappedFile m2dFile, IEnumerable <PackFileEntry> entries) { List <ScriptMetadata> scripts = new List <ScriptMetadata>(); foreach (PackFileEntry entry in entries) { if (!entry.Name.StartsWith("script/npc")) { continue; } ScriptMetadata metadata = new ScriptMetadata(); string npcID = Path.GetFileNameWithoutExtension(entry.Name); XmlDocument document = m2dFile.GetDocument(entry.FileHeader); foreach (XmlNode node in document.DocumentElement.ChildNodes) { int id = int.Parse(node.Attributes["id"].Value); string feature = node.Attributes["feature"].Value; int randomPick = string.IsNullOrEmpty(node.Attributes["randomPick"]?.Value) ? 0 : int.Parse(node.Attributes["randomPick"].Value); int popupState = string.IsNullOrEmpty(node.Attributes["popupState"]?.Value) ? 0 : int.Parse(node.Attributes["popupState"].Value); int popupProp = string.IsNullOrEmpty(node.Attributes["popupProp"]?.Value) ? 0 : int.Parse(node.Attributes["popupProp"].Value); List <int> gotoConditionTalkID = new List <int>(); if (!string.IsNullOrEmpty(node.Attributes["popupProp"]?.Value)) { foreach (string item in node.Attributes["popupProp"].Value.Split(",")) { gotoConditionTalkID.Add(int.Parse(item)); } } List <Content> contents = new List <Content>(); foreach (XmlNode content in node.ChildNodes) { long contentScriptID = string.IsNullOrEmpty(content.Attributes["text"]?.Value) ? 0 : long.Parse(content.Attributes["text"].Value.Substring(8, 16)); string voiceID = string.IsNullOrEmpty(content.Attributes["voiceID"]?.Value) ? "" : content.Attributes["voiceID"].Value; int otherNpcTalk = string.IsNullOrEmpty(content.Attributes["otherNpcTalk"]?.Value) ? 0 : int.Parse(content.Attributes["otherNpcTalk"].Value); string leftIllust = string.IsNullOrEmpty(content.Attributes["leftIllust"]?.Value) ? "" : content.Attributes["leftIllust"].Value; string illust = string.IsNullOrEmpty(content.Attributes["illust"]?.Value) ? "" : content.Attributes["illust"].Value; string speakerIllust = string.IsNullOrEmpty(content.Attributes["speakerIllust"]?.Value) ? "" : content.Attributes["speakerIllust"].Value; bool myTalk = !string.IsNullOrEmpty(content.Attributes["myTalk"]?.Value); byte functionID = string.IsNullOrEmpty(content.Attributes["functionID"]?.Value) ? 0 : byte.Parse(content.Attributes["functionID"].Value); List <Distractor> distractors = new List <Distractor>(); List <Event> events = new List <Event>(); foreach (XmlNode distractor in content.ChildNodes) { if (distractor.Name == "event") { int eventid = string.IsNullOrEmpty(content.Attributes["id"]?.Value) ? 0 : int.Parse(content.Attributes["id"].Value); List <Content> contents2 = new List <Content>(); foreach (XmlNode item in distractor.ChildNodes) { long contentScriptID2 = long.Parse(item.Attributes["text"].Value.Substring(8, 16)); string voiceID2 = string.IsNullOrEmpty(item.Attributes["voiceID"]?.Value) ? "" : item.Attributes["voiceID"].Value; int otherNpcTalk2 = string.IsNullOrEmpty(item.Attributes["otherNpcTalk"]?.Value) ? 0 : int.Parse(item.Attributes["otherNpcTalk"].Value); string leftIllust2 = string.IsNullOrEmpty(item.Attributes["leftIllust"]?.Value) ? "" : item.Attributes["leftIllust"].Value; string illust2 = string.IsNullOrEmpty(item.Attributes["illust"]?.Value) ? "" : item.Attributes["illust"].Value; string speakerIllust2 = string.IsNullOrEmpty(item.Attributes["speakerIllust"]?.Value) ? "" : item.Attributes["speakerIllust"].Value; bool myTalk2 = !string.IsNullOrEmpty(item.Attributes["myTalk"]?.Value); byte functionID2 = string.IsNullOrEmpty(item.Attributes["functionID"]?.Value) ? 0 : byte.Parse(item.Attributes["functionID"].Value); contents2.Add(new Content(contentScriptID2, voiceID2, functionID2, leftIllust2, speakerIllust2, otherNpcTalk2, myTalk2, illust2, null)); } events.Add(new Event(eventid, contents2)); } else { long distractorScriptID = long.Parse(distractor.Attributes["text"].Value.Substring(8, 16)); List <int> goTo = new List <int>(); if (!string.IsNullOrEmpty(distractor.Attributes["goto"]?.Value)) { foreach (string item in distractor.Attributes["goto"].Value.Split(",")) { goTo.Add(int.Parse(item)); } } List <int> goToFail = new List <int>(); if (!string.IsNullOrEmpty(distractor.Attributes["gotoFail"]?.Value)) { foreach (string item in distractor.Attributes["gotoFail"].Value.Split(",")) { goToFail.Add(int.Parse(item)); } } distractors.Add(new Distractor(distractorScriptID, goTo, goToFail)); } } contents.Add(new Content(contentScriptID, voiceID, functionID, leftIllust, speakerIllust, otherNpcTalk, myTalk, illust, distractors)); } metadata.Id = int.Parse(npcID); metadata.IsQuestScript = false; if (node.Name == "select") { metadata.Selects[id] = new Select(id, contents); } else if (node.Name == "script") { metadata.Scripts[id] = new Script(id, feature, randomPick, gotoConditionTalkID, contents); } else if (node.Name == "monologue") { metadata.Monologues[id] = new Monologue(id, popupState, popupProp, contents); } } scripts.Add(metadata); } return(scripts); }
public static List <SkillMetadata> Parse(MemoryMappedFile m2dFile, IEnumerable <PackFileEntry> entries) { List <SkillMetadata> skillList = new List <SkillMetadata>(); foreach (PackFileEntry skill in entries) { if (!skill.Name.StartsWith("skill/10")) { continue; } string skillId = Path.GetFileNameWithoutExtension(skill.Name); SkillMetadata metadata = new SkillMetadata(); List <SkillMotion> motions = new List <SkillMotion>(); List <SkillLevel> skillLevel = new List <SkillLevel>(); metadata.SkillId = int.Parse(skillId); Debug.Assert(metadata.SkillId > 0, $"Invalid Id {metadata.SkillId} from {skillId}"); //using XmlReader reader = m2dFile.GetReader(skill.FileHeader); XmlDocument document = m2dFile.GetDocument(skill.FileHeader); XmlNodeList basic = document.SelectNodes("/ms2/basic"); foreach (XmlNode node in basic) { if (node.Attributes.GetNamedItem("feature") != null) { // Get Rank metadata.Feature = node.Attributes["feature"].Value; } XmlNode kinds = node.SelectSingleNode("kinds"); metadata.Type = kinds.Attributes["type"].Value != null?int.Parse(kinds.Attributes["type"].Value) : 0; metadata.SubType = kinds.Attributes["subType"].Value != null?int.Parse(kinds.Attributes["subType"].Value) : 0; metadata.RangeType = kinds.Attributes["rangeType"].Value != null?int.Parse(kinds.Attributes["rangeType"].Value) : 0; metadata.Element = kinds.Attributes["element"].Value != null?int.Parse(kinds.Attributes["element"].Value) : 0; } XmlNodeList levels = document.SelectNodes("/ms2/level"); foreach (XmlNode node in levels) { int level = node.Attributes["value"].Value != null?int.Parse(node.Attributes["value"].Value) : 1; XmlNode consume = node.SelectSingleNode("consume/stat"); int spirit = 0; int upgradeLevel = 0; int[] upgradeSkillId = new int[0]; int[] upgradeSkillLevel = new int[0]; if (consume.Attributes.GetNamedItem("sp") != null) { spirit = int.Parse(consume.Attributes["sp"].Value); } XmlNode upgrade = node.SelectSingleNode("upgrade"); if (upgrade.Attributes != null) { if (upgrade.Attributes.GetNamedItem("level") != null) { upgradeLevel = int.Parse(upgrade.Attributes["level"].Value); } if (upgrade.Attributes.GetNamedItem("skillIDs") != null) { upgradeSkillId = Array.ConvertAll(upgrade.Attributes.GetNamedItem("skillIDs").Value.Split(","), int.Parse); } if (upgrade.Attributes.GetNamedItem("skillLevels") != null) { upgradeSkillLevel = Array.ConvertAll(upgrade.Attributes.GetNamedItem("skillLevels").Value.Split(","), int.Parse); } } XmlNode motion = node.SelectSingleNode("motion/motionProperty"); string sequenceName = ""; string motionEffect = ""; string strTagEffects = ""; if (motion.Attributes != null) { if (motion.Attributes.GetNamedItem("sequenceName") != null) { sequenceName = motion.Attributes["sequenceName"].Value; } if (motion.Attributes.GetNamedItem("motionEffect") != null) { motionEffect = motion.Attributes["motionEffect"].Value; } if (motion.Attributes.GetNamedItem("strTagEffects") != null) { strTagEffects = motion.Attributes["strTagEffects"].Value; } } motions.Add(new SkillMotion(sequenceName, motionEffect, strTagEffects)); metadata.SkillLevel.Add(new SkillLevel(level, spirit, upgradeLevel, upgradeSkillId, upgradeSkillLevel, motions)); } skillList.Add(metadata); } return(skillList); }
public static List <SkillMetadata> Parse(MemoryMappedFile m2dFile, IEnumerable <PackFileEntry> entries) { List <SkillMetadata> skillList = new List <SkillMetadata>(); foreach (PackFileEntry skill in entries) { if (!skill.Name.StartsWith("skill")) { continue; } string skillId = Path.GetFileNameWithoutExtension(skill.Name); SkillMetadata metadata = new SkillMetadata(); List <SkillLevel> skillLevel = new List <SkillLevel>(); metadata.SkillId = int.Parse(skillId); Debug.Assert(metadata.SkillId > 0, $"Invalid Id {metadata.SkillId} from {skillId}"); //using XmlReader reader = m2dFile.GetReader(skill.FileHeader); XmlDocument document = m2dFile.GetDocument(skill.FileHeader); XmlNodeList basic = document.SelectNodes("/ms2/basic"); foreach (XmlNode node in basic) { if (node.Attributes.GetNamedItem("feature") != null) { // Get Rank metadata.Feature = node.Attributes["feature"].Value; } XmlNode kinds = node.SelectSingleNode("kinds"); metadata.Type = kinds.Attributes["type"].Value != null?int.Parse(kinds.Attributes["type"].Value) : 0; if (kinds.Attributes.GetNamedItem("subType") != null) { // Get Rank metadata.SubType = kinds.Attributes["subType"].Value != null?int.Parse(kinds.Attributes["subType"].Value) : 0; } XmlNode stateAttr = node.SelectSingleNode("stateAttr"); if (stateAttr.Attributes.GetNamedItem("useDefaultSkill") != null) { // Get Rank metadata.DefaultSkill = stateAttr.Attributes["useDefaultSkill"].Value != null?byte.Parse(stateAttr.Attributes["useDefaultSkill"].Value) : 0; } } XmlNodeList levels = document.SelectNodes("/ms2/level"); foreach (XmlNode node in levels) { if (node.Attributes.GetNamedItem("feature") == null || node.Attributes.GetNamedItem("feature").Value == metadata.Feature) { int level = node.Attributes["value"].Value != null?int.Parse(node.Attributes["value"].Value) : 1; XmlNode consume = node.SelectSingleNode("consume/stat"); int spirit = 0; int upgradeLevel = 0; int[] upgradeSkillId = new int[0]; int[] upgradeSkillLevel = new int[0]; if (consume.Attributes.GetNamedItem("sp") != null) { spirit = int.Parse(consume.Attributes["sp"].Value); } XmlNode upgrade = node.SelectSingleNode("upgrade"); if (upgrade.Attributes != null) { if (upgrade.Attributes.GetNamedItem("level") != null) { upgradeLevel = int.Parse(upgrade.Attributes["level"].Value); } if (upgrade.Attributes.GetNamedItem("skillIDs") != null) { upgradeSkillId = Array.ConvertAll(upgrade.Attributes.GetNamedItem("skillIDs").Value.Split(","), int.Parse); } if (upgrade.Attributes.GetNamedItem("skillLevels") != null) { upgradeSkillLevel = Array.ConvertAll(upgrade.Attributes.GetNamedItem("skillLevels").Value.Split(","), int.Parse); } } skillLevel.Add(new SkillLevel(level, spirit, upgradeLevel, upgradeSkillId, upgradeSkillLevel)); metadata.SkillLevel = skillLevel[0]; } } skillList.Add(metadata); } return(skillList); }
public static List <ItemMetadata> Parse(MemoryMappedFile m2dFile, IEnumerable <PackFileEntry> entries) { List <ItemMetadata> items = new List <ItemMetadata>(); foreach (PackFileEntry entry in entries) { if (!entry.Name.StartsWith("item/")) { continue; } ItemMetadata metadata = new ItemMetadata(); string itemId = Path.GetFileNameWithoutExtension(entry.Name); if (items.Exists(item => item.Id.ToString() == itemId)) { //Console.WriteLine($"Duplicate {entry.Name} was already added."); continue; } metadata.Id = int.Parse(itemId); Debug.Assert(metadata.Id > 0, $"Invalid Id {metadata.Id} from {itemId}"); // Parse XML XmlDocument document = m2dFile.GetDocument(entry.FileHeader); XmlNode item = document.SelectSingleNode("ms2/environment"); // Gear/Cosmetic slot XmlNode slots = item.SelectSingleNode("slots"); XmlNode slot = slots.FirstChild; bool slotResult = Enum.TryParse <ItemSlot>(slot.Attributes["name"].Value, out metadata.Slot); if (!slotResult && !string.IsNullOrEmpty(slot.Attributes["name"].Value)) { Console.WriteLine($"Failed to parse item slot for {itemId}: {slot.Attributes["name"].Value}"); } int totalSlots = slots.SelectNodes("slot").Count; metadata.IsTwoHand = totalSlots > 1; // Badge slot XmlNode gem = item.SelectSingleNode("gem"); bool gemResult = Enum.TryParse <GemSlot>(gem.Attributes["system"].Value, out metadata.Gem); if (!gemResult && !string.IsNullOrEmpty(gem.Attributes["system"].Value)) { Console.WriteLine($"Failed to parse badge slot for {itemId}: {gem.Attributes["system"].Value}"); } // Inventory tab and max stack size XmlNode property = item.SelectSingleNode("property"); try { byte type = byte.Parse(property.Attributes["type"].Value); byte subType = byte.Parse(property.Attributes["subtype"].Value); bool skin = byte.Parse(property.Attributes["skin"].Value) != 0; metadata.Tab = GetTab(type, subType, skin); metadata.IsTemplate = byte.Parse(property.Attributes["skinType"]?.Value ?? "0") == 99; } catch (Exception e) { Console.WriteLine($"Failed to parse tab slot for {itemId}: {e.Message}"); } metadata.StackLimit = int.Parse(property.Attributes["slotMax"].Value); // Rarity XmlNode option = item.SelectSingleNode("option"); int rarity = 1; if (option.Attributes["constant"].Value.Length == 1) { rarity = int.Parse(option.Attributes["constant"].Value); } metadata.Rarity = rarity; // Item boxes XmlNode function = item.SelectSingleNode("function"); string contentType = function.Attributes["name"].Value; if (contentType == "OpenItemBox" || contentType == "SelectItemBox") { // selection boxes are SelectItemBox and 1,boxid // normal boxes are OpenItemBox and 0,1,0,boxid // fragments are OpenItemBox and 0,1,0,boxid,required_amount List <string> parameters = new List <string>(function.Attributes["parameter"].Value.Split(",")); // Remove empty params parameters.RemoveAll(param => param.Length == 0); if (parameters.Count >= 2) { string boxId = contentType == "OpenItemBox" ? parameters[3] : parameters[1]; foreach (PackFileEntry innerEntry in entries) { if (!innerEntry.Name.StartsWith("table/individualitemdrop") && !innerEntry.Name.StartsWith("table/na/individualitemdrop")) { continue; } if (metadata.Content.Count > 0) { continue; } // Parse XML XmlDocument innerDocument = m2dFile.GetDocument(innerEntry.FileHeader); XmlNodeList individualBoxItems = innerDocument.SelectNodes($"/ms2/individualDropBox[@individualDropBoxID={boxId}]"); foreach (XmlNode individualBoxItem in individualBoxItems) { int id = int.Parse(individualBoxItem.Attributes["item"].Value); int minAmount = int.Parse(individualBoxItem.Attributes["minCount"].Value); int maxAmount = int.Parse(individualBoxItem.Attributes["maxCount"].Value); int dropGroup = int.Parse(individualBoxItem.Attributes["dropGroup"].Value); int smartDropRate = string.IsNullOrEmpty(individualBoxItem.Attributes["smartDropRate"]?.Value) ? 0 : int.Parse(individualBoxItem.Attributes["smartDropRate"].Value); int contentRarity = string.IsNullOrEmpty(individualBoxItem.Attributes["PackageUIShowGrade"]?.Value) ? 0 : int.Parse(individualBoxItem.Attributes["PackageUIShowGrade"].Value); int enchant = string.IsNullOrEmpty(individualBoxItem.Attributes["enchantLevel"]?.Value) ? 0 : int.Parse(individualBoxItem.Attributes["enchantLevel"].Value); int id2 = string.IsNullOrEmpty(individualBoxItem.Attributes["item2"]?.Value) ? 0 : int.Parse(individualBoxItem.Attributes["item2"].Value); // Skip already existing item if (metadata.Content.Exists(content => content.Id == id)) { continue; } // Skip locales other than NA in table/na if (innerEntry.Name.StartsWith("table/na/individualitemdrop") && individualBoxItem.Attributes["locale"] != null) { if (!individualBoxItem.Attributes["locale"].Value.Equals("NA")) { continue; } } metadata.Content.Add(new ItemContent(id, minAmount, maxAmount, dropGroup, smartDropRate, contentRarity, enchant, id2)); } } } } // Music score charges XmlNode musicScore = item.SelectSingleNode("MusicScore"); int playCount = int.Parse(musicScore.Attributes["playCount"].Value); metadata.PlayCount = playCount; // Recommended jobs XmlNode limit = item.SelectSingleNode("limit"); if (!string.IsNullOrEmpty(limit.Attributes["recommendJobs"].Value)) { List <string> recommendJobs = new List <string>(limit.Attributes["recommendJobs"].Value.Split(",")); foreach (string recommendJob in recommendJobs) { metadata.RecommendJobs.Add(int.Parse(recommendJob)); } } items.Add(metadata); } return(items); }
public static List <MapEntityMetadata> Parse(MemoryMappedFile m2dFile, IEnumerable <PackFileEntry> entries) { // Iterate over preset objects to later reference while iterating over exported maps Dictionary <string, string> mapObjects = new Dictionary <string, string>(); foreach (PackFileEntry entry in entries) { if (!entry.Name.StartsWith("flat/presets/presets object/")) { continue; } // Check if file is valid string objStr = entry.Name.ToLower(); if (string.IsNullOrEmpty(objStr)) { continue; } if (mapObjects.ContainsKey(objStr)) { Console.WriteLine($"Duplicate {entry.Name} was already added as {mapObjects[objStr]}"); continue; } // Parse XML XmlDocument document = m2dFile.GetDocument(entry.FileHeader); XmlElement root = document.DocumentElement; XmlNodeList objProperties = document.SelectNodes("/model/property"); string objectName = root.Attributes["name"].Value.ToLower(); foreach (XmlNode node in objProperties) { // Storing only weapon item code for now, but there are other uses if (node.Attributes["name"].Value.Contains("ObjectWeaponItemCode")) { string weaponId = node?.FirstChild.Attributes["value"].Value ?? "0"; if (!weaponId.Equals("0")) { mapObjects.Add(objectName, weaponId); } } } } // Iterate over map xblocks List <MapEntityMetadata> entities = new List <MapEntityMetadata>(); Dictionary <string, string> maps = new Dictionary <string, string>(); foreach (PackFileEntry entry in entries) { if (!entry.Name.StartsWith("xblock/")) { continue; } string mapIdStr = Regex.Match(entry.Name, @"\d{8}").Value; if (string.IsNullOrEmpty(mapIdStr)) { continue; } int mapId = int.Parse(mapIdStr); if (maps.ContainsKey(mapIdStr)) { Console.WriteLine($"Duplicate {entry.Name} was already added as {maps[mapIdStr]}"); continue; } maps.Add(mapIdStr, entry.Name); MapEntityMetadata metadata = new MapEntityMetadata(mapId); XmlDocument document = m2dFile.GetDocument(entry.FileHeader); XmlNodeList mapEntities = document.SelectNodes("/game/entitySet/entity"); foreach (XmlNode node in mapEntities) { string modelName = node.Attributes["modelName"].Value.ToLower(); if (node.Attributes["name"].Value.Contains("SpawnPointPC")) { XmlNode playerCoord = node.SelectSingleNode("property[@name='Position']"); XmlNode playerRotation = node.SelectSingleNode("property[@name='Rotation']"); string playerPositionValue = playerCoord?.FirstChild.Attributes["value"].Value ?? "0, 0, 0"; string playerRotationValue = playerRotation?.FirstChild.Attributes["value"].Value ?? "0, 0, 0"; metadata.PlayerSpawns.Add(new MapPlayerSpawn(ParseCoord(playerPositionValue), ParseCoord(playerRotationValue))); } else if (mapObjects.ContainsKey(modelName)) { string nameCoord = node.Attributes["name"].Value.ToLower(); Match coordMatch = Regex.Match(nameCoord, @"[\-]?\d+[,]\s[\-]?\d+[,]\s[\-]?\d+"); if (!coordMatch.Success) { continue; } CoordB coord = CoordB.Parse(coordMatch.Value, ", "); metadata.Objects.Add(new MapObject(coord, int.Parse(mapObjects[modelName]))); } } //XmlNodeList nodes = document.SelectNodes("/game/entitySet/entity/property[@name='NpcList']"); XmlNodeList nodes = document.SelectNodes("/game/entitySet/entity/property"); foreach (XmlNode node in nodes) { if (node.Attributes["name"].Value == "NpcList") { if (node.FirstChild != null) { XmlNode parent = node.ParentNode; try { XmlNode coordNode = parent.SelectSingleNode("property[@name='Position']"); XmlNode rotationNode = parent.SelectSingleNode("property[@name='Rotation']"); int npcId = int.Parse(node.FirstChild.Attributes["index"].Value); string positionValue = coordNode?.FirstChild.Attributes["value"].Value ?? "0, 0, 0"; string rotationValue = rotationNode?.FirstChild.Attributes["value"].Value ?? "0, 0, 0"; CoordS position = ParseCoord(positionValue); CoordS rotation = ParseCoord(rotationValue); metadata.Npcs.Add(new MapNpc(npcId, position, rotation)); } catch (Exception ex) { Console.WriteLine(ex); Console.WriteLine(mapId); Console.WriteLine("Failed NPC " + parent.InnerXml); } } } else if (node.Attributes["name"].Value == "PortalID") { XmlNode parent = node.ParentNode; try { XmlNode visibleNode = parent.SelectSingleNode("property[@name='IsVisible']"); XmlNode enabledNode = parent.SelectSingleNode("property[@name='PortalEnable']"); XmlNode minimapVisibleNode = parent.SelectSingleNode("property[@name='MinimapIconVisible']"); XmlNode targetNode = parent.SelectSingleNode("property[@name='TargetFieldSN']"); XmlNode coordNode = parent.SelectSingleNode("property[@name='Position']"); XmlNode rotationNode = parent.SelectSingleNode("property[@name='Rotation']"); if (targetNode == null) { continue; } if (!bool.TryParse(visibleNode?.FirstChild.Attributes["value"].Value, out bool visibleValue)) { visibleValue = true; } if (!bool.TryParse(enabledNode?.FirstChild.Attributes["value"].Value, out bool enabledValue)) { enabledValue = true; } if (!bool.TryParse(minimapVisibleNode?.FirstChild.Attributes["value"].Value, out bool minimapVisibleValue)) { minimapVisibleValue = true; } int target = int.Parse(targetNode.FirstChild.Attributes["value"].Value); int portalId = int.Parse(node.FirstChild.Attributes["value"].Value); string positionValue = coordNode?.FirstChild.Attributes["value"].Value ?? "0, 0, 0"; string rotationValue = rotationNode?.FirstChild.Attributes["value"].Value ?? "0, 0, 0"; MapPortalFlag flags = visibleValue ? MapPortalFlag.Visible : MapPortalFlag.None; flags |= enabledValue ? MapPortalFlag.Enabled : MapPortalFlag.None; flags |= minimapVisibleValue ? MapPortalFlag.MinimapVisible : MapPortalFlag.None; CoordS position = ParseCoord(positionValue); CoordS rotation = ParseCoord(rotationValue); metadata.Portals.Add(new MapPortal(portalId, flags, target, position, rotation)); } catch (Exception ex) { Console.WriteLine(ex); Console.WriteLine(mapId); Console.WriteLine("Failed NPC " + parent.InnerXml); } } } // No data on this map if (metadata.Npcs.Count == 0 && metadata.Portals.Count == 0 && metadata.PlayerSpawns.Count == 0) { continue; } entities.Add(metadata); } return(entities); }