Проблема петли посетителя
Я использую следующий код шаблона посетителя для анализа файла XML:
using RimWorld;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Xml;
using UnityEngine;
using Verse;
namespace ColonistCreationMod
{
class LoadColonists
{
public static void LoadFromFile(Map map, string groupName)
{
try
{
string path = Directory.GetParent(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)).FullName;
if (Environment.OSVersion.Version.Major >= 6)
{
path = Directory.GetParent(path).FullName;
}
path += "\\AppData\\LocalLow\\Ludeon Studios\\RimWorld\\CharSaves\\" + groupName + ".col";
ColonistRegen(path);
Parse(path);
}
catch (Exception e)
{
Log.Message(e.Message);
}
GC.Collect();
}
private static void ColonistRegen(string file)
{
using (XmlTextReader reader = new XmlTextReader(File.OpenRead(file)))
{
while (reader.Read())
{
switch (reader.Name)
{
case "ColonistAmount":
ColonistNum.Amount = VisitAmount(reader);
ColonistManager.RandomColonists();
ModdedMapInitParams.GenerateColonists();
break;
}
}
}
}
private static int VisitAmount(XmlTextReader reader)
{
int amount = 0;
while (reader.MoveToNextAttribute())
{
switch (reader.Name)
{
case "amount":
amount = int.Parse(reader.Value);
break;
}
}
return amount;
}
private static void Parse(string file)
{
using (XmlTextReader reader = new XmlTextReader(File.OpenRead(file)))
{
int i = 0;
while (reader.Read())
{
switch (reader.Name)
{
case "Colonist":
Log.Message("Colonist: " + i.ToString());
VisitColonist(reader, i);
i++;
break;
}
}
}
}
private static void VisitColonist(XmlTextReader reader, int i)
{
while (reader.Read())
{
if (reader.Name == "Colonist" && reader.NodeType == XmlNodeType.EndElement)
break;
switch (reader.Name)
{
case "BasicInfo":
VisitBasicInfo(reader, i);
break;
case "Graphics":
VisitGraphics(reader, i);
break;
case "HairDef":
VisitHairDef(reader, i);
break;
case "OnSkin":
VisitOnSkin(reader, i);
break;
case "Shell":
VisitShell(reader, i);
break;
case "Childhood":
VisitChildhood(reader, i);
break;
case "Adulthood":
VisitAdulthood(reader, i);
break;
case "SkillPool":
VisitSkillPool(reader, i);
break;
case "Skills":
VisitSkills(reader, i);
break;
}
}
}
private static void VisitBasicInfo(XmlTextReader reader, int i)
{
while (reader.MoveToNextAttribute())
{
switch (reader.Name)
{
case "Name":
var parts = reader.Value.Split(' ');
ColonistManager.Population[i].FirstName = parts[0];
ColonistManager.Population[i].NickName = parts[1];
ColonistManager.Population[i].LastName = parts[2];
Log.Message("Colonist Name: " + ColonistManager.Population[i].FirstName + ColonistManager.Population[i].NickName + ColonistManager.Population[i].LastName);
break;
case "Age":
ColonistManager.Population[i].Age = int.Parse(reader.Value);
Log.Message("Colonist Age: " + ColonistManager.Population[i].Age.ToString());
break;
}
}
}
private static void VisitGraphics(XmlTextReader reader, int i)
{
while (reader.MoveToNextAttribute())
{
switch (reader.Name)
{
case "BodyType":
string body = reader.Value;
int bodyType = 0;
if (body == "Male")
{
bodyType = 1;
}
else if (body == "Female")
{
bodyType = 2;
}
else if (body == "Thin")
{
bodyType = 3;
}
else if (body == "Hulk")
{
bodyType = 4;
}
else if (body == "Fat")
{
bodyType = 5;
}
ColonistManager.Population[i].BodyType = (BodyType)bodyType;
Log.Message("Colonist BodyType: " + ColonistManager.Population[i].BodyType.ToString());
break;
case "SkinColor":
ColonistManager.Population[i].SkinColor = GetColor(reader.Value);
Log.Message("Colonist SkinColor: " + ColonistManager.Population[i].SkinColor.r.ToString() + ", " + ColonistManager.Population[i].SkinColor.g.ToString() + ", " + ColonistManager.Population[i].SkinColor.b.ToString() + ", " + ColonistManager.Population[i].SkinColor.a.ToString());
break;
case "CrownType":
string crown = reader.Value;
int crownType = 0;
if (crown == "Average")
{
crownType = 1;
}
else if (crown == "Narrow")
{
crownType = 2;
}
ColonistManager.Population[i].CrownType = (CrownType)crownType;
break;
case "HeadGraphicPath":
ColonistManager.Population[i].HeadGraphicPath = reader.Value;
break;
case "HairColor":
ColonistManager.Population[i].HairColor = GetColor(reader.Value);
break;
}
}
}
private static void VisitHairDef(XmlTextReader reader, int i)
{
ColHairDef hairDef = new ColHairDef();
while (reader.MoveToNextAttribute())
{
switch (reader.Name)
{
case "DefName":
hairDef.DefName = reader.Value;
break;
case "GraphicPath":
hairDef.GraphicPath = reader.Value;
break;
case "HairGender":
string hair = reader.Value;
int hairGender = 0;
if (hair == "Any")
{
hairGender = 2;
}
else if (hair == "Female")
{
hairGender = 4;
}
else if (hair == "FemaleUsually")
{
hairGender = 3;
}
else if (hair == "MaleUsually")
{
hairGender = 1;
}
hairDef.HairGender = (HairGender)hairGender;
break;
case "Label":
hairDef.Label = reader.Value;
break;
case "Tags":
hairDef.HairTags = GetTags(reader.Value);
ColonistManager.Population[i].HairDef = hairDef;
break;
}
}
}
private static List<string> GetTags(string tagList)
{
List<string> tags = tagList.Split(',').ToList<string>();
return tags;
}
private static void VisitOnSkin(XmlTextReader reader, int i)
{
Clothing clothing = new Clothing();
while (reader.MoveToNextAttribute())
{
switch (reader.Name)
{
case "Layer":
clothing.Layer = reader.Value;
break;
case "Label":
clothing.Label = reader.Value;
break;
case "GraphicPath":
clothing.GraphicPath = reader.Value;
break;
case "Color":
clothing.Color = GetColor(reader.Value);
break;
}
}
ColonistManager.Population[i].Clothing[0] = clothing;
}
private static void VisitShell(XmlTextReader reader, int i)
{
Clothing clothing = new Clothing();
while (reader.MoveToNextAttribute())
{
switch (reader.Name)
{
case "Layer":
clothing.Layer = reader.Value;
break;
case "Label":
clothing.Label = reader.Value;
break;
case "GraphicPath":
clothing.GraphicPath = reader.Value;
break;
case "Color":
clothing.Color = GetColor(reader.Value);
break;
}
}
ColonistManager.Population[i].Clothing[1] = clothing;
}
private static Color GetColor(string colorValue)
{
var parts = colorValue.Split(',');
Color color = new Color();
color.r = Single.Parse(parts[0]);
color.g = Single.Parse(parts[1]);
color.b = Single.Parse(parts[2]);
color.a = Single.Parse(parts[3]);
return color;
}
private static void VisitChildhood(XmlTextReader reader, int i)
{
while (reader.MoveToNextAttribute())
{
switch (reader.Name)
{
case "Index":
ColonistManager.Population[i].Backstory[0] = ColonistManager.Backstories[int.Parse(reader.Value)];
break;
}
}
}
private static void VisitAdulthood(XmlTextReader reader, int i)
{
while (reader.MoveToNextAttribute())
{
switch (reader.Name)
{
case "Index":
ColonistManager.Population[i].Backstory[1] = ColonistManager.Backstories[int.Parse(reader.Value)];
break;
}
}
}
private static void VisitSkillPool(XmlTextReader reader, int i)
{
while (reader.MoveToNextAttribute())
{
switch (reader.Name)
{
case "Amount":
ColonistManager.Population[i].SkillPool = int.Parse(reader.Value);
break;
}
}
}
private static void VisitSkills(XmlTextReader reader, int i)
{
while (reader.MoveToNextAttribute())
{
string name = "";
int value = 0;
switch (reader.Name)
{
case "Name":
name = reader.Value;
break;
case "Value":
value = int.Parse(reader.Value);
break;
case "Passion":
value = int.Parse(reader.Value);
if (name == "Construction")
{
ColonistManager.Population[i].Skills[0].SkillName = name;
ColonistManager.Population[i].Skills[0].SkillValue = value;
ColonistManager.Population[i].Skills[0].SkillPassion = int.Parse(reader.Value);
}
else if (name == "Growing")
{
ColonistManager.Population[i].Skills[1].SkillName = name;
ColonistManager.Population[i].Skills[1].SkillValue = value;
ColonistManager.Population[i].Skills[1].SkillPassion = int.Parse(reader.Value);
}
else if (name == "Research")
{
ColonistManager.Population[i].Skills[2].SkillName = name;
ColonistManager.Population[i].Skills[2].SkillValue = value;
ColonistManager.Population[i].Skills[2].SkillPassion = int.Parse(reader.Value);
}
else if (name == "Mining")
{
ColonistManager.Population[i].Skills[3].SkillName = name;
ColonistManager.Population[i].Skills[3].SkillValue = value;
ColonistManager.Population[i].Skills[3].SkillPassion = int.Parse(reader.Value);
}
else if (name == "Shooting")
{
ColonistManager.Population[i].Skills[4].SkillName = name;
ColonistManager.Population[i].Skills[4].SkillValue = value;
ColonistManager.Population[i].Skills[4].SkillPassion = int.Parse(reader.Value);
}
else if (name == "Melee")
{
ColonistManager.Population[i].Skills[5].SkillName = name;
ColonistManager.Population[i].Skills[5].SkillValue = value;
ColonistManager.Population[i].Skills[5].SkillPassion = int.Parse(reader.Value);
}
else if (name == "Social")
{
ColonistManager.Population[i].Skills[6].SkillName = name;
ColonistManager.Population[i].Skills[6].SkillValue = value;
ColonistManager.Population[i].Skills[6].SkillPassion = int.Parse(reader.Value);
}
else if (name == "Cooking")
{
ColonistManager.Population[i].Skills[7].SkillName = name;
ColonistManager.Population[i].Skills[7].SkillValue = value;
ColonistManager.Population[i].Skills[7].SkillPassion = int.Parse(reader.Value);
}
else if (name == "Medicine")
{
ColonistManager.Population[i].Skills[8].SkillName = name;
ColonistManager.Population[i].Skills[8].SkillValue = value;
ColonistManager.Population[i].Skills[8].SkillPassion = int.Parse(reader.Value);
}
else if (name == "Artistic")
{
ColonistManager.Population[i].Skills[9].SkillName = name;
ColonistManager.Population[i].Skills[9].SkillValue = value;
ColonistManager.Population[i].Skills[9].SkillPassion = int.Parse(reader.Value);
}
else if (name == "Crafting")
{
ColonistManager.Population[i].Skills[10].SkillName = name;
ColonistManager.Population[i].Skills[10].SkillValue = value;
ColonistManager.Population[i].Skills[10].SkillPassion = int.Parse(reader.Value);
}
break;
}
}
}
}
}
Вот XML-файл:
<?xml version="1.0" encoding="utf-8"?>
<Colonists>
<ColonistAmount amount="1" />
<Colonist num="1">
<BasicInfo Name="Argain Don Bentham" />
<BasicInfo Age="29" />
<BasicInfo Gender="1" />
<BasicInfo Trait1="Gadgeteer" />
<BasicInfo Trait2="Knitter" />
<Graphics BodyType="Thin" />
<Graphics SkinColor="0.9490196,0.9294118,0.8784314,1" />
<Graphics CrownType="Narrow" />
<Graphics HeadGraphicPath="Things/Pawn/Humanoid/Heads/Female/Female_Narrow_Wide" />
<Graphics HairColor="0.5,0.5,0.5,1" />
<HairDef DefName="Mop" />
<HairDef GraphicPath="Things/Pawn/Humanoid/Hairs/Mop" />
<HairDef HairGender="MaleUsually" />
<HairDef Label="Mop" />
<HairDef Tags="Urban,Rural" />
<Apparel>
<OnSkin Layer="OnSkin" Label="Button-down shirt" GraphicPath="Things/Pawn/Humanoid/Apparel/ShirtButton/ShirtButton" Color="1,1,1,1" />
<Shell Layer="Shell" Label="Duster" GraphicPath="Things/Pawn/Humanoid/Apparel/Duster/Duster" Color="0,0,0,1" />
</Apparel>
<Backstories>
<Childhood Index="177" />
<Adulthood Index="26" />
</Backstories>
<SkillPool Amount="0" />
<Skills Name="Construction" Value="0" Passion="0" />
<Skills Name="Growing" Value="0" Passion="0" />
<Skills Name="Research" Value="6" Passion="0" />
<Skills Name="Mining" Value="0" Passion="0" />
<Skills Name="Shooting" Value="16" Passion="2" />
<Skills Name="Melee" Value="0" Passion="1" />
<Skills Name="Social" Value="18" Passion="3" />
<Skills Name="Cooking" Value="0" Passion="0" />
<Skills Name="Medicine" Value="0" Passion="0" />
<Skills Name="Artistic" Value="0" Passion="0" />
<Skills Name="Crafting" Value="0" Passion="0" />
<End />
</Colonist>
</Colonists>
Я новичок в использовании этого стиля "шаблон посетителя" и столкнулся с проблемой повторения кода 5 раз VisitHairDef
метод. Каждый раз, когда этот метод зацикливается, HairDef
объект воссоздается и впоследствии сохраняет только один фрагмент информации за цикл, прежде чем записать его в ColonistManager.Population[i].HairDef
объект. Таким образом, конечный результат - только одна переменная сохраняется в ColonistManager.Population[i].HairDef
, Я не знаю, почему этот конкретный раздел зацикливается, и я надеюсь, что кто-то с большим опытом в этом может пролить свет на это для меня. Если требуется дополнительная информация, я загрузил весь свой исходный код в dropbox: https://www.dropbox.com/s/eeq8hwwaoa2ld0b/ColonistCreationMod%20Source.zip
2 ответа
Сделай так, чтобы Colonist.HairDef
инициализируется в конструкторе для Colonist
, Затем в VisitHairDef
, установите свойства прямо на ColonistManager.Population[i].HairDef
,
public class Colonist
{
public HairDef HairDef { get; set; }
public Colonist()
{
HairDef = new HairDef();
}
}
private static void VisitHairDef(XmlTextReader reader, int i)
{
//ColHairDef hairDef = new ColHairDef();
while (reader.MoveToNextAttribute())
{
switch (reader.Name)
{
case "DefName":
ColonistManager.Population[i].HairDef.DefName = reader.Value;
break;
case "GraphicPath":
ColonistManager.Population[i].HairDef.GraphicPath = reader.Value;
break;
case "HairGender":
string hair = reader.Value;
int hairGender = 0;
if (hair == "Any")
{
hairGender = 2;
}
else if (hair == "Female")
{
hairGender = 4;
}
else if (hair == "FemaleUsually")
{
hairGender = 3;
}
else if (hair == "MaleUsually")
{
hairGender = 1;
}
ColonistManager.Population[i].HairDef.HairGender = (HairGender)hairGender;
break;
case "Label":
ColonistManager.Population[i].HairDef.Label = reader.Value;
break;
case "Tags":
ColonistManager.Population[i].HairDef.HairTags = GetTags(reader.Value);
//ColonistManager.Population[i].HairDef = hairDef;
break;
}
}
}
Я обнаружил, что это проблема с самим файлом XML... VisitOnSkin
Метод работал безупречно с Clothing clothing = new Clothing();
в методе, потому что XML был так:
<OnSkin Layer="OnSkin" Label="Button-down shirt" GraphicPath="Things/Pawn/Humanoid/Apparel/ShirtButton/ShirtButton" Color="1,1,1,1" />
XML для HairDef
однако, было не так много атрибутов, вложенных в один узел... как только я установил все атрибуты для одного узла "HairDef", вот так:
<HairDef DefName="Mop" GraphicPath="Things/Pawn/Humanoid/Hairs/Mop" HairGender="MaleUsually" Label="Mop" Tags="Urban,Rural" />
Тогда все работало гладко:D