Xander9009 wrote:I finally found the source of the issue I posted, but I have no idea how to correctly fix it. In the DeckBuilder.cs file -> ExportWad function -> kvpPersonalityName variable. It's set to an empty dictionary, and then only added to the exported deck's text permanent if the personality isn't a "BuiltIn" personality. When I replaced that with the same method the 'kvpDeckName' uses (initialized directly to the personality's name regardless of built-in status), the problem disappeared. Unfortunately, I don't see where personalities are being marked as BuiltIn, so I don't know how to figure out why it's marking some as built-in even though they aren't.
For the record, they're definitely not built in. They're completely custom, with custom names, images, and everything except music.
I was actually using BuiltIn to determine if a Personality is already available to the user (i.e. they have the personality installed, either from game default or from mods). This was so that I could minimize how much is put into a deck and try to keep duplication to a minimum. Since if they have something installed it is available to everything without needing to have additional copies.
Though obviously things aren't being kept installed which is why this problem is cropping up.
I have a fix (and have had for a while, but can't really release due to partial state of other code) for loading saved deck XMLs where the personality information is missing (essentially I check to see if the LocalizedName is null before I try to use it and if it is I replace it with a localized version of "AI Personality"). Additionally, to prevent the problem from cropping up again when saving the localized text (XmlTools.SaveLocalizedText()) I check to make sure there is at least one child node and if not I put an empty string into the fallback language (English, en-US) so that it has one.
For quickly finding where something is set you can either go to the accessor set right-click on the name and select "Find All References" (if you are using Visual Studio) or you can set a break point on the set accessor and run in Debug mode and wait for it to be hit then look at the call stack to see what called it. With a lot of important data I have kept it private and provided accessors for them (even when the accessors don't really do much of anything) specifically to make debugging easier (public variables that are directly accessed can be hard to debug).
- DeckInformation Constructor excerpt | Open
- Code: Select all
// Personality
m_apPersonality = m_dkInfo.Personality;
if (m_apPersonality.LocalizedName != null)
lblAiPersonality.Text = m_apPersonality.LocalizedName.Replace("&", "&&");
else
lblAiPersonality.Text = Settings.UIStrings["AI_PERSONALITY"];
- EditAiPersonality.RefreshPersonality excerpt | Open
- Code: Select all
if (m_apPersonality.LocalizedName != null)
lblPersonalityName.Text = m_apPersonality.LocalizedName.Replace("&", "&&");
else
lblPersonalityName.Text = String.Empty;
- SaveLocalizedText | Open
- Code: Select all
public static void SaveLocalizedText(Dictionary<string, string> dicLocalized, XmlDocument xdDoc, XmlNode xnNodeToSaveIn)
{
// By doing things this way we only write out the text we have rather than creating bogus entries.
foreach (KeyValuePair<string, string> kvPair in dicLocalized)
SaveLocalizedString(kvPair.Key, kvPair.Value, xdDoc, xnNodeToSaveIn);
// Check to make sure we have a localized string and if not create an empty one in our fallback
// langauge. This is used to help prevent errors when no-one sets any strings.
if (!xnNodeToSaveIn.HasChildNodes)
SaveLocalizedString(FALLBACK_LANG_CODE, String.Empty, xdDoc, xnNodeToSaveIn);
}
Xander9009 wrote:Nevermind. I figured out where it is. WadDirectory.cs -> LoadPersonalities() -> "ap.BuiltIn = true". Replaced that with (and of course undid the change to kvpPersonalityName )
- Code: Select all
if (
m_strFullDir.IndexOf("\\DATA_DECKS_", StringComparison.OrdinalIgnoreCase) < 0 ||
m_strFullDir.IndexOf("\\DATA_DECKS_D14\\", StringComparison.OrdinalIgnoreCase) >= 0 ||
m_strFullDir.IndexOf("\\DATA_DECKS_E14\\", StringComparison.OrdinalIgnoreCase) >= 0 ||
m_strFullDir.IndexOf("\\DATA_DECKS_F14_PACK1\\", StringComparison.OrdinalIgnoreCase) >= 0 ||
m_strFullDir.IndexOf("\\DATA_DECKS_F14_PACK2\\", StringComparison.OrdinalIgnoreCase) >= 0 ||
m_strFullDir.IndexOf("\\DATA_DECKS_F14_PACK3\\", StringComparison.OrdinalIgnoreCase) >= 0
)
{
// This was loaded from the game directory and not a custom deck so we consider it built-in because the user already has it.
ap.BuiltIn = true;
}
Sadly, I don't know the best method of doing this. I imagine the really best way would be to make a master list of official mods and a function for seeing if a particular path lies inside one of those, but that's too far outside my comfort level to risk my DotP modding lol. It works, so it's good enough for me. It'd probably be a lot better, since not everyone's decks were in the format DATA_DECKS_. Some used DATA_DLC_, such as TFM's decks. But I don't plan to go modding those anyway, so...
I don't know if you'd want to change that in the main version, but in case you do (or just so you're aware of it), I figured I'd post about what I discovered.
Actually, if you want to see if something is official the best way is probably to have a list of official WADs then compare the name of the containing WAD to the list to see if it is official or not. Though this would only work 100% as intended if people don't modify the official WADs which they really aren't supposed to do anyway (due to the side effects from doing so).
I actually have more changes in the pipe such as a more memory efficient "Build an Image", card order precedence with duplicate filtering (so that the Deck Builder will attempt to detect the version of a particular card the game will use and only show that version, based on card filename). Unfortunately, they are in a partial state and so aren't ready to be released yet.