internal void Load(XmlNode xmlSkillNode, bool blnLegacy = false) { if (xmlSkillNode == null) { return; } Timekeeper.Start("load_char_skills"); if (!blnLegacy) { Timekeeper.Start("load_char_skills_groups"); List <SkillGroup> lstLoadingSkillGroups = new List <SkillGroup>(); using (XmlNodeList xmlGroupsList = xmlSkillNode.SelectNodes("groups/group")) if (xmlGroupsList != null) { foreach (XmlNode xmlNode in xmlGroupsList) { SkillGroup objGroup = new SkillGroup(_objCharacter); objGroup.Load(xmlNode); lstLoadingSkillGroups.Add(objGroup); } } lstLoadingSkillGroups.Sort((i1, i2) => string.Compare(i2.DisplayName, i1.DisplayName, StringComparison.Ordinal)); foreach (SkillGroup skillgroup in lstLoadingSkillGroups) { SkillGroups.Add(skillgroup); } Timekeeper.Finish("load_char_skills_groups"); Timekeeper.Start("load_char_skills_normal"); //Load skills. Because sorting a BindingList is complicated we use a temporery normal list List <Skill> lstLoadingSkills = new List <Skill>(); using (XmlNodeList xmlSkillsList = xmlSkillNode.SelectNodes("skills/skill")) if (xmlSkillsList != null) { foreach (XmlNode xmlNode in xmlSkillsList) { Skill objSkill = Skill.Load(_objCharacter, xmlNode); if (objSkill != null) { lstLoadingSkills.Add(objSkill); } } } lstLoadingSkills.Sort(CompareSkills); foreach (Skill objSkill in lstLoadingSkills) { string strName = objSkill.IsExoticSkill ? $"{objSkill.Name} ({objSkill.DisplaySpecializationMethod(GlobalOptions.DefaultLanguage)})" : objSkill.Name; bool blnDoAddToDictionary = true; _lstSkills.MergeInto(objSkill, CompareSkills, (objExistSkill, objNewSkill) => { blnDoAddToDictionary = false; if (objNewSkill.Base > objExistSkill.Base) { objExistSkill.Base = objNewSkill.Base; } if (objNewSkill.Karma > objExistSkill.Karma) { objExistSkill.Karma = objNewSkill.Karma; } objExistSkill.Specializations.MergeInto(objNewSkill.Specializations, (x, y) => x.Free == y.Free ? string.Compare(x.DisplayName(GlobalOptions.Language), y.DisplayName(GlobalOptions.Language), StringComparison.Ordinal) : (x.Free ? 1 : -1)); }); if (blnDoAddToDictionary) { _dicSkills.Add(strName, objSkill); } } // TODO: Skill groups don't refresh their CanIncrease property correctly when the last of their skills is being added, as the total basse rating will be zero. Call this here to force a refresh. foreach (SkillGroup g in SkillGroups) { g.OnPropertyChanged(nameof(SkillGroup.SkillList)); } Timekeeper.Finish("load_char_skills_normal"); Timekeeper.Start("load_char_skills_kno"); using (XmlNodeList xmlSkillsList = xmlSkillNode.SelectNodes("knoskills/skill")) if (xmlSkillsList != null) { foreach (XmlNode xmlNode in xmlSkillsList) { if (Skill.Load(_objCharacter, xmlNode) is KnowledgeSkill objSkill) { KnowledgeSkills.Add(objSkill); } } } Timekeeper.Finish("load_char_skills_kno"); Timekeeper.Start("load_char_knowsoft_buffer"); // Knowsoft Buffer. using (XmlNodeList xmlSkillsList = xmlSkillNode.SelectNodes("skilljackknowledgeskills/skill")) if (xmlSkillsList != null) { foreach (XmlNode xmlNode in xmlSkillsList) { string strName = string.Empty; if (xmlNode.TryGetStringFieldQuickly("name", ref strName)) { KnowsoftSkills.Add(new KnowledgeSkill(_objCharacter, strName)); } } } Timekeeper.Finish("load_char_knowsoft_buffer"); } else { List <Skill> lstTempSkillList = new List <Skill>(); using (XmlNodeList xmlSkillsList = xmlSkillNode.SelectNodes("skills/skill")) if (xmlSkillsList != null) { foreach (XmlNode xmlNode in xmlSkillsList) { Skill objSkill = Skill.LegacyLoad(_objCharacter, xmlNode); if (objSkill != null) { lstTempSkillList.Add(objSkill); } } } if (lstTempSkillList.Count > 0) { List <Skill> lstUnsortedSkills = new List <Skill>(); //Variable/Anon method as to not clutter anywhere else. Not sure if clever or stupid bool OldSkillFilter(Skill skill) { if (skill.Rating > 0) { return(true); } if (skill.SkillCategory == "Resonance Active" && !_objCharacter.RESEnabled) { return(false); } //This could be more fine grained, but frankly i don't care if (skill.SkillCategory == "Magical Active" && !_objCharacter.MAGEnabled) { return(false); } return(true); } foreach (Skill objSkill in lstTempSkillList) { if (objSkill is KnowledgeSkill objKnoSkill) { KnowledgeSkills.Add(objKnoSkill); } else if (OldSkillFilter(objSkill)) { lstUnsortedSkills.Add(objSkill); } } lstUnsortedSkills.Sort(CompareSkills); foreach (Skill objSkill in lstUnsortedSkills) { _lstSkills.Add(objSkill); _dicSkills.Add(objSkill.IsExoticSkill ? objSkill.Name + " (" + objSkill.DisplaySpecializationMethod(GlobalOptions.DefaultLanguage) + ')' : objSkill.Name, objSkill); } UpdateUndoList(xmlSkillNode); } } //This might give subtle bugs in the future, //but right now it needs to be run once when upgrading or it might crash. //As some didn't they crashed on loading skills. //After this have run, it won't (for the crash i'm aware) //TODO: Move it to the other side of the if someday? if (!_objCharacter.Created) { // zero out any skillgroups whose skills did not make the final cut foreach (SkillGroup objSkillGroup in SkillGroups) { if (!objSkillGroup.SkillList.Any(x => SkillsDictionary.ContainsKey(x.Name))) { objSkillGroup.Base = 0; objSkillGroup.Karma = 0; } } } //Workaround for probably breaking compability between earlier beta builds if (xmlSkillNode["skillptsmax"] == null) { xmlSkillNode = xmlSkillNode.OwnerDocument?["character"]; } int intTmp = 0; if (xmlSkillNode.TryGetInt32FieldQuickly("skillptsmax", ref intTmp)) { SkillPointsMaximum = intTmp; } if (xmlSkillNode.TryGetInt32FieldQuickly("skillgrpsmax", ref intTmp)) { SkillGroupPointsMaximum = intTmp; } Timekeeper.Finish("load_char_skills"); }
internal void Load(XmlNode skillNode, bool legacy = false) { if (skillNode == null) { return; } Timekeeper.Start("load_char_skills"); if (!legacy) { Timekeeper.Start("load_char_skills_groups"); List <SkillGroup> loadingSkillGroups = new List <SkillGroup>(); foreach (XmlNode node in skillNode.SelectNodes("groups/group")) { SkillGroup skillgroup = SkillGroup.Load(_character, node); if (skillgroup != null) { loadingSkillGroups.Add(skillgroup); } } loadingSkillGroups.Sort((i1, i2) => String.Compare(i2.DisplayName, i1.DisplayName, StringComparison.Ordinal)); foreach (SkillGroup skillgroup in loadingSkillGroups) { SkillGroups.Add(skillgroup); } Timekeeper.Finish("load_char_skills_groups"); Timekeeper.Start("load_char_skills_normal"); //Load skills. Because sorting a BindingList is complicated we use a temporery normal list List <Skill> loadingSkills = new List <Skill>(); foreach (XmlNode node in skillNode.SelectNodes("skills/skill")) { Skill skill = Skill.Load(_character, node); if (skill != null) { loadingSkills.Add(skill); } } loadingSkills.Sort(CompareSkills); foreach (Skill skill in loadingSkills) { _skills.Add(skill); _dicSkills.Add(skill.IsExoticSkill ? skill.Name + " (" + skill.DisplaySpecialization + ")" : skill.Name, skill); } Timekeeper.Finish("load_char_skills_normal"); Timekeeper.Start("load_char_skills_kno"); foreach (XmlNode node in skillNode.SelectNodes("knoskills/skill")) { if (Skill.Load(_character, node) is KnowledgeSkill skill) { KnowledgeSkills.Add(skill); } } Timekeeper.Finish("load_char_skills_kno"); Timekeeper.Start("load_char_knowsoft_buffer"); // Knowsoft Buffer. foreach (XmlNode objXmlSkill in skillNode.SelectNodes("skilljackknowledgeskills/skill")) { string strName = string.Empty; if (objXmlSkill.TryGetStringFieldQuickly("name", ref strName)) { KnowsoftSkills.Add(new KnowledgeSkill(_character, strName)); } } Timekeeper.Finish("load_char_knowsoft_buffer"); } else { List <Skill> tempSkillList = new List <Skill>(); foreach (XmlNode node in skillNode.SelectNodes("skills/skill")) { Skill skill = Skill.LegacyLoad(_character, node); if (skill != null) { tempSkillList.Add(skill); } } if (tempSkillList.Count > 0) { List <Skill> unsoredSkills = new List <Skill>(); //Variable/Anon method as to not clutter anywhere else. Not sure if clever or stupid bool oldSkillFilter(Skill skill) { if (skill.Rating > 0) { return(true); } if (skill.SkillCategory == "Resonance Active" && !_character.RESEnabled) { return(false); } //This could be more fine grained, but frankly i don't care if (skill.SkillCategory == "Magical Active" && !_character.MAGEnabled) { return(false); } return(true); } foreach (Skill skill in tempSkillList) { if (skill is KnowledgeSkill knoSkill) { KnowledgeSkills.Add(knoSkill); } else if (oldSkillFilter(skill)) { unsoredSkills.Add(skill); } } unsoredSkills.Sort(CompareSkills); foreach (Skill objSkill in unsoredSkills) { _skills.Add(objSkill); _dicSkills.Add(objSkill.IsExoticSkill ? objSkill.Name + " (" + objSkill.DisplaySpecialization + ")" : objSkill.Name, objSkill); } UpdateUndoList(skillNode); } } //This might give subtle bugs in the future, //but right now it needs to be run once when upgrading or it might crash. //As some didn't they crashed on loading skills. //After this have run, it won't (for the crash i'm aware) //TODO: Move it to the other side of the if someday? if (!_character.Created) { // zero out any skillgroups whose skills did not make the final cut foreach (SkillGroup objSkillGroup in SkillGroups) { if (!objSkillGroup.SkillList.Any(x => SkillsDictionary.ContainsKey(x.Name))) { objSkillGroup.Base = 0; objSkillGroup.Karma = 0; } } } //Workaround for probably breaking compability between earlier beta builds if (skillNode["skillptsmax"] == null) { skillNode = skillNode.OwnerDocument["character"]; } int intTmp = 0; if (skillNode.TryGetInt32FieldQuickly("skillptsmax", ref intTmp)) { SkillPointsMaximum = intTmp; } if (skillNode.TryGetInt32FieldQuickly("skillgrpsmax", ref intTmp)) { SkillGroupPointsMaximum = intTmp; } Timekeeper.Finish("load_char_skills"); }