1. This is driving me nuts I'm wasting so much time on this!

    Is there an easy way to save and retrieve a class or say a Dictionary to the config? There's an example out there that uses Interface.GetMod().DataFileSystem.WriteObject and Interface.GetMod().DataFileSystem.ReadObject which does that but it saves the config in the Data folder instead of the Config folder and I don't really like that, I'd rather just use a "standard" config.

    The config system seems to be saving these objects fine but when it comes back to load them, it doesn't work. I suppose I have to do a 1231312 character cryptic cast line to get it to work, but I just can't get it.

    I did manage to save/load an array of strings like this:
    Code:
    string[] c_craftingMultiplierBlacklist;
    c_craftingMultiplierBlacklist = ((IEnumerable)GetConfigValue("Blacklists", "craftingMultiplierBlacklist", new string[] { })).Cast<object>().Select(x => x.ToString()).ToArray();
    But I'd really like to be able to save a Dictionary<string, string> or better yet, a Dictionary<string, CustomClass> and be able to reload that effortlessly in the same way the GetMod().DataFileSystem does, but to the main config file.

    I seen some mods use Newtonsoft to perform some pretty complex manipulations in order to achieve something like this, but it feels way overkill for something that should be relatively simple.

    For the record, the solution I use now which works but is ugly as dog that's been hit by a truck is this:

    Code:
    var mess= GetConfigValue("Salvager", "Salvagers", c_salvagers);c_salvagers.Clear();
    foreach (var entry in (IEnumerable)mess)
    {
        var parts = entry.ToString().Trim(new[] { '[', ']' }).Split(',');
        c_salvagers.Add(parts.First(), parts.Last());
    }
    
    This is to reload a Dictionary<string, string> and it works well, so long as there are no commas in any of the two values.

    Any help would be appreciated!
    [DOUBLEPOST=1438228148][/DOUBLEPOST]Edit: I said "it works" for that last bit of code but actually it doesn't work so well. The first time the config is created, "mess" does not have the same format as the second time it's ran and loaded from disk. I have debug code that enumerates the contents of the dictionary after the load and if I put stuff as default in the dict, it won't show on the first run so I'm running on an empty dictionary despite the fact it saved entries on disk.
     
  2. Bump! Would really be nice to be able to save/load a full class structure in a config variable...
     
  3. Vote for this too! Might need to move it oxide feature requests.
     
  4. Doesnt that work? I did not try yet.
    How are you trying to save it?
     
  5. The new WriteObject and ReadObject functions in Config solved this issue. Works great, the new version of Cornucopia I'll release soon uses it.
     
  6. Alright I need some lights here! One of the last Oxide update added a WriteObject and ReadObject function to Config which is very good news. That said, I haven't seen any examples of how to use this so I went how I could and did it like this:

    Code:
            void LoadConfigValues()
            {
                try
                {
                    g_config = Config.ReadObject<CornuConfig>(Interface.GetMod().InstanceDirectory + "/config/Cornu.json");
                }
                catch
                {
                    Puts("New configuration file created.");
                    g_config = new CornuConfig();
                    Config.WriteObject(g_config, false, Interface.GetMod().InstanceDirectory + "/config/Cornu.json");
                }
            }
    
    Problem is I'm getting reports of servers that are not using that folder to store configs and this is preventing these servers/hosts from using the plugin properly, as they cannot load or even create the config.

    I could just add a try/catch and try the other folder that's been reported, but I have a feeling this "other" folder can be arbitrary. Is there a way to determine programmatically where the config folder is exactly?

    The only sure way I see of doing this would be to use a standard config in which the config folder would be the only setting, but that seems very sketchy.

    I wish we could save an object as a named setting like any other variable in the config.. that would remove this issue.
     
  7. Wulf

    Wulf Community Admin

    You're overcomplicating simplicity and hard-coding it to the /config/ folder, that's what the report is. ;)

    Take a look at the example below from the Gather Rewards plugin I am overhauling.
    Code:
            #region Configuration Defaults        PluginConfig DefaultConfig()
            {
                var defaultConfig = new PluginConfig
                {
                    Settings = new PluginSettings
                    {
                        ShowMessages = true,
                        Rewards = new Dictionary<string, int>
                        {
                            { PluginRewards.Corpse, 25 },
                            { PluginRewards.Ore, 25 },
                            { PluginRewards.Wood, 25 }
                        }
                    },
                    Messages = new Dictionary<string, string>
                    {
                        { PluginMessage.ReceivedForGather, "You have received ${0} for gathering {1}." },
                        { PluginMessage.ReceivedForKill, "You have received ${0} for killing a {1}." },
                        { PluginMessage.ReceivedForLoot, "You have received ${0} for looting {1}." }
                    }
                };
                foreach (GameManifest.PooledString str in GameManifest.Get().pooledStrings)
                {
                    if (str.str.StartsWith("assets/bundled/prefabs/autospawn/animals/"))
                    {
                        var animal = str.str.Substring(str.str.LastIndexOf("/") + 1).Replace(".prefab", "");
                        defaultConfig.Settings.Rewards[UppercaseFirst(animal)] = 25;
                    }
                }
                return defaultConfig;
            }        #endregion        #region Configuration Setup        private bool configChanged;
            private PluginConfig config;        static class PluginRewards
            {
                public const string Corpse = "Corpse";
                public const string Ore = "Ore";
                public const string Wood = "Wood";
            }        static class PluginMessage
            {
                public const string ReceivedForGather = "ReceivedForGather";
                public const string ReceivedForKill = "ReceivedForKill";
                public const string ReceivedForLoot = "ReceivedForLoot";
            }        class PluginSettings
            {
                public bool ShowMessages { get; set; }
                public Dictionary<string, int> Rewards { get; set; }
            }        class PluginConfig
            {
                public PluginSettings Settings { get; set; }
                public Dictionary<string, string> Messages { get; set; }
            }        protected override void LoadDefaultConfig()
            {
                Config.WriteObject(DefaultConfig(), true);
                PrintWarning("New configuration file created.");
            }        void LoadConfigValues()
            {
                config = Config.ReadObject<PluginConfig>();
                var defaultConfig = DefaultConfig();
                Merge(config.Messages, defaultConfig.Messages);
                Merge(config.Settings.Rewards, defaultConfig.Settings.Rewards);            if (!configChanged) return;
                PrintWarning("Configuration file updated.");
                Config.WriteObject(config);
            }        void Merge<T1, T2>(IDictionary<T1, T2> current, IDictionary<T1, T2> defaultDict)
            {
                foreach (var pair in defaultDict)
                {
                    if (current.ContainsKey(pair.Key)) continue;
                    current[pair.Key] = pair.Value;
                    configChanged = true;
                }
                var oldPairs = current.Keys.Except(defaultDict.Keys).ToList();
                foreach (var oldPair in oldPairs)
                {
                    current.Remove(oldPair);
                    configChanged = true;
                }
            }        #endregion        void Loaded() => LoadConfigValues();
     
  8. Thanks Wulf, never even saw they were optional params my bad! Got it working I'll post an new version!