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:
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.Code:string[] c_craftingMultiplierBlacklist; c_craftingMultiplierBlacklist = ((IEnumerable)GetConfigValue("Blacklists", "craftingMultiplierBlacklist", new string[] { })).Cast<object>().Select(x => x.ToString()).ToArray();
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:
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.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()); }
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.
Solved Configs & classes or dictionaries, etc.
Discussion in 'Rust Development' started by Deicide666ra, Jul 30, 2015.
-
Bump! Would really be nice to be able to save/load a full class structure in a config variable...
-
Vote for this too! Might need to move it oxide feature requests.
-
How are you trying to save it? -
The new WriteObject and ReadObject functions in Config solved this issue. Works great, the new version of Cornucopia I'll release soon uses it.
-
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"); } }
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. -
Wulf Community Admin
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();
-
Thanks Wulf, never even saw they were optional params my bad! Got it working I'll post an new version!