-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathPobCodeImporter.cs
More file actions
84 lines (78 loc) · 4.44 KB
/
PobCodeImporter.cs
File metadata and controls
84 lines (78 loc) · 4.44 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Xml;
namespace GemGuide;
public class PobCodeImporter
{
public static (List<SkillSet> parsedSets, List<string> errors, string className) GetGemSets(string code)
{
try
{
var xml = PobHelpers.CodeToXml(code);
var xmlDocument = new XmlDocument();
//because loading xml securely is surprisingly hard
xmlDocument.Load(XmlReader.Create(new StringReader(xml)));
var root = xmlDocument.GetElementsByTagName("PathOfBuilding").Cast<XmlNode>().First();
var buildNode = root.ChildNodes.Cast<XmlNode>().FirstOrDefault(x => x.Name == "Build");
var className = buildNode?.Attributes?.GetNamedItem("className")?.Value;
var skillsNode = root.ChildNodes.Cast<XmlNode>().First(x => x.Name == "Skills");
var setNodes = skillsNode.ChildNodes.Cast<XmlNode>().Where(x => x.Name == "SkillSet");
var setAndSkillNodes = setNodes.Select(sn => (sn, skills: sn.ChildNodes.Cast<XmlNode>().Where(x => x.Name == "Skill")));
var setAndGemNodes = setAndSkillNodes.Select(d =>
(skillSetNode: d.sn, skills: d.skills.Select(skillNode => (skillNode, gems: skillNode.ChildNodes.Cast<XmlNode>().Where(x => x.Name == "Gem")))));
var errors = new List<string>();
T Push<T>(string error, T value)
{
errors.Add(error);
return value;
}
var unnamedSetId = 0;
var parsedSets = setAndGemNodes.Select(x =>
{
var setName = x.skillSetNode.Attributes?.GetNamedItem("title")?.Value switch
{
{ } s when string.IsNullOrWhiteSpace(s) => $"Unnamed set {unnamedSetId++}",
var s => s
} ?? Push($"{x.skillSetNode.FindXPath()} does not have a set name", $"Unnamed set {unnamedSetId++}");
var skills = x.skills.Select(skill =>
{
var skillLabel = skill.skillNode.Attributes?.GetNamedItem("label")?.Value ?? "";
var gems = skill.gems.Select(g =>
{
var gemName = g.Attributes?.GetNamedItem("variantId")?.Value ?? Push($"{g.FindXPath()} does not have a gem name", "");
var level = g.Attributes?.GetNamedItem("level")?.Value is { } levelString
? int.TryParse(levelString, out var l)
? l
: Push($"{g.FindXPath()}({gemName}).level ('{levelString}') cannot be parsed, using 20 as default", 20)
: Push($"{g.FindXPath()}({gemName}) does not have the level attribute, using 20 as default", 20);
var quality = g.Attributes?.GetNamedItem("quality")?.Value is { } qualityString
? int.TryParse(qualityString, out var q)
? q
: Push($"{g.FindXPath()}({gemName}).quality ('{qualityString}') cannot be parsed, using 0 as default", 0)
: Push($"{g.FindXPath()}({gemName}) does not have the quality attribute, using 0 as default", 0);
var enabled = g.Attributes?.GetNamedItem("enabled")?.Value is { } enabledString
? bool.TryParse(enabledString, out var b)
? b
: Push($"{g.FindXPath()}({gemName}).quality ('{enabledString}') cannot be parsed, using true as default", true)
: Push($"{g.FindXPath()}({gemName}) does not have the enabled attribute, using true as default", true);
var nameSpec = g.Attributes?.GetNamedItem("nameSpec")?.Value;
return new Gem(level, gemName, quality, enabled, nameSpec);
}).ToList();
return new GemSet(skillLabel, gems);
}).ToList();
return new SkillSet(setName, skills);
}).ToList();
return (parsedSets, errors, className);
}
catch (Exception ex)
{
return ([], [ex.ToString()], null);
}
}
public static bool IsValidUrl(string url)
{
return url.Length > 100 && Convert.TryFromBase64String(url.Replace('-', '+').Replace('_', '/'), new byte[url.Length], out _);
}
}