public void Load(string xmlPath) { this.Path = xmlPath; LoadResult = SkinLoadResult.Fail; try { XmlDocument xdoc = new XmlDocument(); xdoc.Load(xmlPath); WorkingDir = System.IO.Path.GetDirectoryName(xmlPath); var xroot = xdoc["skin"]; this.Name = xroot.Attributes["name"].Value; string cTypeStr = xroot.Attributes["type"].Value; // see if a mapping is defined for this controller type if (!NintendoSpyMapping.TypeMap.ContainsKey(cTypeStr)) { return; } // retrieve the mapping to munia indices var cType = NintendoSpyMapping.TypeMap[cTypeStr]; Controllers.Add(cType); var mapping = NintendoSpyMapping.ControllerMaps[cType]; foreach (XmlNode xnode in xroot) { // read the background if (xnode.Name == "background") { var bg = new NSpyBackground(); bg.Name = xnode.Attributes["name"].Value; bg.ImagePath = System.IO.Path.Combine(WorkingDir, xnode.Attributes["image"].Value); Backgrounds[bg.Name] = bg; } // read the buttons else if (xnode.Name == "button") { var btn = new Button(); btn.Id = mapping.ButtonMap[xnode.Attributes["name"].Value]; btn.ReadConfig(this, xnode); Buttons.Add(btn); } else if (xnode.Name == "rangebutton") { var btn = new RangeButton(); btn.Id = mapping.ButtonMap[xnode.Attributes["name"].Value]; btn.ReadConfig(this, xnode); btn.VisibleFrom = double.Parse(xnode.Attributes["from"].Value); btn.VisibleTo = double.Parse(xnode.Attributes["to"].Value); RangeButtons.Add(btn); } // read the triggers else if (xnode.Name == "analog") { var trigg = new Trigger(); trigg.Id = mapping.AxisMap[xnode.Attributes["name"].Value]; trigg.ReadConfig(this, xnode); string direction = xnode.Attributes["direction"].Value.ToLower(); // nspy reverse/inverse is slightly different, mapping below makes rendering identical to SvgSkin trigg.Orientation = direction == "left" || direction == "right" ? TriggerOrientation.Horizontal : TriggerOrientation.Vertical; // our reverse means filling from left-to-right or bottom-to-top trigg.Reverse = direction == "left" || direction == "up"; if (xnode.Attributes["reverse"] != null) { bool rev = bool.Parse(xnode.Attributes["reverse"].Value); // nspy 'reverse' is our inverse, but should be considered as another flip for right-to-left or bottom-to-top trigg.Reverse ^= rev; trigg.Inverse = rev; } Triggers.Add(trigg); } // read the sticks else if (xnode.Name == "stick") { var stick = new Stick(); if (mapping.AxisMap.ContainsKey(xnode.Attributes["xname"].Value)) { stick.HorizontalAxis = mapping.AxisMap[xnode.Attributes["xname"].Value]; } if (mapping.AxisMap.ContainsKey(xnode.Attributes["yname"].Value)) { stick.VerticalAxis = mapping.AxisMap[xnode.Attributes["yname"].Value]; } stick.ReadConfig(this, xnode); stick.XReverse = bool.Parse(xnode.Attributes["xreverse"]?.Value ?? "false"); stick.YReverse = bool.Parse(xnode.Attributes["yreverse"]?.Value ?? "false"); stick.XRange = int.Parse(xnode.Attributes["xrange"].Value); stick.YRange = int.Parse(xnode.Attributes["yrange"].Value); Sticks.Add(stick); } // read the detail items else if (xnode.Name == "detail") { var detail = new Detail(); detail.ReadConfig(this, xnode); detail.Targets = xnode.Attributes["target"].Value.Split(';').ToList(); Details.Add(detail); } } SelectedBackground = Backgrounds.First().Value; LoadResult = SkinLoadResult.Ok; } catch { } }