commit
afaf559f45
|
@ -11,19 +11,194 @@ using Newtonsoft.Json.Linq;
|
|||
|
||||
namespace StardewModdingAPI
|
||||
{
|
||||
public class Config
|
||||
public partial class Config
|
||||
{
|
||||
[JsonIgnore]
|
||||
public virtual JObject JObject { get; protected set; }
|
||||
public virtual string ConfigLocation { get; protected internal set; }
|
||||
|
||||
[JsonIgnore]
|
||||
public virtual string ConfigLocation { get; protected set; }
|
||||
public virtual string ConfigDir => Path.GetDirectoryName(ConfigLocation);
|
||||
|
||||
public static Config Instance
|
||||
public virtual Config Instance<T>() where T : Config => Activator.CreateInstance<T>();
|
||||
|
||||
/// <summary>
|
||||
/// Should never be used for anything.
|
||||
/// </summary>
|
||||
public Config()
|
||||
{
|
||||
get { return new Config(); }
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Loads the config from the json blob on disk, updating and re-writing to the disk if needed.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <returns></returns>
|
||||
internal virtual T LoadConfig<T>() where T : Config
|
||||
{
|
||||
if (string.IsNullOrEmpty(ConfigLocation))
|
||||
{
|
||||
Log.Error("A config tried to load without specifying a location on the disk.");
|
||||
return null;
|
||||
}
|
||||
|
||||
T ret = null;
|
||||
|
||||
if (!File.Exists(ConfigLocation))
|
||||
{
|
||||
//no config exists, generate default values
|
||||
var c = this.GenerateBaseConfig<T>();
|
||||
c.ConfigLocation = ConfigLocation;
|
||||
ret = c;
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
//try to load the config from a json blob on disk
|
||||
T c = JsonConvert.DeserializeObject<T>(File.ReadAllText(ConfigLocation));
|
||||
|
||||
c.ConfigLocation = ConfigLocation;
|
||||
|
||||
//update the config with default values if needed
|
||||
ret = c.UpdateConfig<T>();
|
||||
|
||||
c = null;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error("Invalid JSON Config: {0} \n{1}", ConfigLocation, ex);
|
||||
return GenerateBaseConfig<T>();
|
||||
}
|
||||
}
|
||||
|
||||
ret.WriteConfig();
|
||||
return ret;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// MUST be implemented in inheriting class!
|
||||
/// </summary>
|
||||
protected virtual T GenerateBaseConfig<T>() where T : Config
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Merges a default-value config with the user-config on disk.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <returns></returns>
|
||||
internal virtual T UpdateConfig<T>() where T : Config
|
||||
{
|
||||
try
|
||||
{
|
||||
//default config
|
||||
var b = JObject.FromObject(Instance<T>().GenerateBaseConfig<T>());
|
||||
|
||||
//user config
|
||||
var u = JObject.FromObject(this);
|
||||
|
||||
//overwrite default values with user values
|
||||
b.Merge(u, new JsonMergeSettings {MergeArrayHandling = MergeArrayHandling.Replace});
|
||||
|
||||
//cast json object to config
|
||||
T c = b.ToObject<T>();
|
||||
|
||||
//re-write the location on disk to the object
|
||||
c.ConfigLocation = ConfigLocation;
|
||||
|
||||
return c;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error("An error occured when updating a config: " + ex);
|
||||
return this as T;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class ConfigExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes an instance of any class that inherits from Config.
|
||||
/// This method performs the loading, saving, and merging of the config on the disk and in memory at a default state.
|
||||
/// This method should not be used to re-load or to re-save a config.
|
||||
/// </summary>
|
||||
public static T InitializeConfig<T>(this T baseConfig, string configLocation) where T : Config
|
||||
{
|
||||
if (baseConfig == null)
|
||||
{
|
||||
baseConfig = Activator.CreateInstance<T>();
|
||||
/*
|
||||
Log.Error("A config tried to initialize whilst being null.");
|
||||
return null;
|
||||
*/
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(configLocation))
|
||||
{
|
||||
Log.Error("A config tried to initialize without specifying a location on the disk.");
|
||||
return null;
|
||||
}
|
||||
|
||||
baseConfig.ConfigLocation = configLocation;
|
||||
T c = baseConfig.LoadConfig<T>();
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a config to a json blob on the disk specified in the config's properties.
|
||||
/// </summary>
|
||||
public static void WriteConfig<T>(this T baseConfig) where T : Config
|
||||
{
|
||||
if (string.IsNullOrEmpty(baseConfig?.ConfigLocation) || string.IsNullOrEmpty(baseConfig.ConfigDir))
|
||||
{
|
||||
Log.Error("A config attempted to save when it itself or it's location were null.");
|
||||
return;
|
||||
}
|
||||
|
||||
string s = JsonConvert.SerializeObject(baseConfig, typeof (T), Formatting.Indented, new JsonSerializerSettings());
|
||||
|
||||
if (!Directory.Exists(baseConfig.ConfigDir))
|
||||
Directory.CreateDirectory(baseConfig.ConfigDir);
|
||||
|
||||
if (!File.Exists(baseConfig.ConfigLocation) || !File.ReadAllText(baseConfig.ConfigLocation).SequenceEqual(s))
|
||||
File.WriteAllText(baseConfig.ConfigLocation, s);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Re-reads the json blob on the disk and merges its values with a default config
|
||||
/// </summary>
|
||||
public static T ReloadConfig<T>(this T baseConfig) where T : Config
|
||||
{
|
||||
return baseConfig.UpdateConfig<T>();
|
||||
}
|
||||
|
||||
[Obsolete]
|
||||
public static void WriteConfig(this Config baseConfig)
|
||||
{
|
||||
Log.Error("A config has been written through an obsolete way.\n\tThis method of writing configs will not be supported in future versions.");
|
||||
WriteConfig<Config>(baseConfig);
|
||||
}
|
||||
|
||||
[Obsolete]
|
||||
public static Config ReloadConfig(this Config baseConfig)
|
||||
{
|
||||
Log.Error("A config has been reloaded through an obsolete way.\n\tThis method of loading configs will not be supported in future versions.");
|
||||
return baseConfig.ReloadConfig<Config>();
|
||||
}
|
||||
}
|
||||
|
||||
[Obsolete]
|
||||
public partial class Config
|
||||
{
|
||||
[JsonIgnore]
|
||||
[Obsolete]
|
||||
public virtual JObject JObject { get; protected set; }
|
||||
|
||||
[Obsolete]
|
||||
public static Config InitializeConfig(string configLocation, Config baseConfig)
|
||||
{
|
||||
if (string.IsNullOrEmpty(configLocation))
|
||||
|
@ -42,17 +217,19 @@ namespace StardewModdingAPI
|
|||
return baseConfig.LoadConfig(baseConfig);
|
||||
}
|
||||
|
||||
[Obsolete]
|
||||
public virtual Config GenerateBaseConfig(Config baseConfig)
|
||||
{
|
||||
//Must be implemented in sub-class
|
||||
return null;
|
||||
}
|
||||
|
||||
[Obsolete]
|
||||
public virtual Config LoadConfig(Config baseConfig)
|
||||
{
|
||||
if (!File.Exists(baseConfig.ConfigLocation))
|
||||
{
|
||||
var v = (Config)baseConfig.GetType().GetMethod("GenerateBaseConfig", BindingFlags.Public | BindingFlags.Instance).Invoke(baseConfig, new object[] { baseConfig });
|
||||
var v = (Config) baseConfig.GetType().GetMethod("GenerateBaseConfig", BindingFlags.Public | BindingFlags.Instance).Invoke(baseConfig, new object[] {baseConfig});
|
||||
v.WriteConfig();
|
||||
}
|
||||
else
|
||||
|
@ -62,7 +239,7 @@ namespace StardewModdingAPI
|
|||
try
|
||||
{
|
||||
var j = JObject.Parse(File.ReadAllText(baseConfig.ConfigLocation));
|
||||
baseConfig = (Config)j.ToObject(baseConfig.GetType());
|
||||
baseConfig = (Config) j.ToObject(baseConfig.GetType());
|
||||
baseConfig.ConfigLocation = p;
|
||||
baseConfig.JObject = j;
|
||||
|
||||
|
@ -74,29 +251,26 @@ namespace StardewModdingAPI
|
|||
}
|
||||
catch
|
||||
{
|
||||
Log.Verbose("Invalid JSON Renamed: " + p);
|
||||
if (File.Exists(p))
|
||||
File.Move(p, Path.Combine(Path.GetDirectoryName(p), Path.GetFileNameWithoutExtension(p) + "." + Guid.NewGuid() + ".json")); //Get it out of the way for a new one
|
||||
var v = (Config)baseConfig.GetType().GetMethod("GenerateBaseConfig", BindingFlags.Public | BindingFlags.Instance).Invoke(baseConfig, new object[] { baseConfig });
|
||||
v.WriteConfig();
|
||||
Log.Verbose("Invalid JSON: " + p);
|
||||
}
|
||||
}
|
||||
|
||||
return baseConfig;
|
||||
}
|
||||
|
||||
[Obsolete]
|
||||
public virtual Config UpdateConfig(Config baseConfig)
|
||||
{
|
||||
try
|
||||
{
|
||||
//default config with all standard values
|
||||
var b = JObject.FromObject(baseConfig.GetType().GetMethod("GenerateBaseConfig", BindingFlags.Public | BindingFlags.Instance).Invoke(baseConfig, new object[] { baseConfig }));
|
||||
var b = JObject.FromObject(baseConfig.GetType().GetMethod("GenerateBaseConfig", BindingFlags.Public | BindingFlags.Instance).Invoke(baseConfig, new object[] {baseConfig}));
|
||||
//user config with their values
|
||||
var u = baseConfig.JObject;
|
||||
|
||||
b.Merge(u, new JsonMergeSettings { MergeArrayHandling = MergeArrayHandling.Replace });
|
||||
b.Merge(u, new JsonMergeSettings {MergeArrayHandling = MergeArrayHandling.Replace});
|
||||
|
||||
return (Config)b.ToObject(baseConfig.GetType());
|
||||
return (Config) b.ToObject(baseConfig.GetType());
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
@ -116,28 +290,4 @@ namespace StardewModdingAPI
|
|||
return theMod.BaseConfigPath;
|
||||
}
|
||||
}
|
||||
|
||||
public static class ConfigExtensions
|
||||
{
|
||||
public static void WriteConfig(this Config baseConfig)
|
||||
{
|
||||
if (baseConfig == null || string.IsNullOrEmpty(baseConfig.ConfigLocation) || string.IsNullOrEmpty(Path.GetDirectoryName(baseConfig.ConfigLocation)))
|
||||
{
|
||||
Log.Error("A config attempted to save when it itself or it's location were null.");
|
||||
return;
|
||||
}
|
||||
|
||||
var toWrite = JsonConvert.SerializeObject(baseConfig, baseConfig.GetType(), Formatting.Indented, new JsonSerializerSettings());
|
||||
if (!Directory.Exists(Path.GetDirectoryName(baseConfig.ConfigLocation)))
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(baseConfig.ConfigLocation));
|
||||
if (!File.Exists(baseConfig.ConfigLocation) || !File.ReadAllText(baseConfig.ConfigLocation).SequenceEqual(toWrite))
|
||||
File.WriteAllText(baseConfig.ConfigLocation, toWrite);
|
||||
toWrite = null;
|
||||
}
|
||||
|
||||
public static Config ReloadConfig(this Config baseConfig)
|
||||
{
|
||||
return baseConfig.UpdateConfig(baseConfig);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -48,7 +48,7 @@ namespace StardewModdingAPI
|
|||
|
||||
public const int MinorVersion = 38;
|
||||
|
||||
public const int PatchVersion = 7;
|
||||
public const int PatchVersion = 8;
|
||||
|
||||
public const string Build = "Alpha";
|
||||
|
||||
|
|
|
@ -21,10 +21,14 @@ namespace StardewModdingAPI
|
|||
return new Color(Random.Next(0, 255), Random.Next(0, 255), Random.Next(0, 255));
|
||||
}
|
||||
|
||||
public static string ToSingular(this IEnumerable<Object> enumerable, string split = ", ")
|
||||
public static string ToSingular(this IEnumerable ienum, string split = ", ")
|
||||
{
|
||||
string result = string.Join(split, enumerable);
|
||||
return result;
|
||||
//Apparently Keys[] won't split normally :l
|
||||
if (ienum is Keys[])
|
||||
{
|
||||
return string.Join(split, (Keys[])ienum);
|
||||
}
|
||||
return string.Join(split, ienum);
|
||||
}
|
||||
|
||||
public static bool IsInt32(this object o)
|
||||
|
|
|
@ -29,16 +29,16 @@ namespace StardewModdingAPI.Inheritance
|
|||
public MouseState MStateNow { get; private set; }
|
||||
public MouseState MStatePrior { get; private set; }
|
||||
|
||||
public Keys[] CurrentlyPressedKeys { get; private set; }
|
||||
public Keys[] PreviouslyPressedKeys { get; private set; }
|
||||
public Keys[] CurrentlyPressedKeys => KStateNow.GetPressedKeys();
|
||||
public Keys[] PreviouslyPressedKeys => KStatePrior.GetPressedKeys();
|
||||
|
||||
public Keys[] FramePressedKeys
|
||||
{
|
||||
get { return CurrentlyPressedKeys.Where(x => !PreviouslyPressedKeys.Contains(x)).ToArray(); }
|
||||
get { return CurrentlyPressedKeys.Except(PreviouslyPressedKeys).ToArray(); }
|
||||
}
|
||||
public Keys[] FrameReleasedKeys
|
||||
{
|
||||
get { return PreviouslyPressedKeys.Where(x => !CurrentlyPressedKeys.Contains(x)).ToArray(); }
|
||||
get { return PreviouslyPressedKeys.Except(CurrentlyPressedKeys).ToArray(); }
|
||||
}
|
||||
|
||||
public Buttons[][] PreviouslyPressedButtons;
|
||||
|
@ -180,6 +180,9 @@ namespace StardewModdingAPI.Inheritance
|
|||
private static SGame instance;
|
||||
public static SGame Instance => instance;
|
||||
|
||||
public static float FramesPerSecond { get; private set; }
|
||||
public static bool Debug { get; private set; }
|
||||
|
||||
public Farmer CurrentFarmer => player;
|
||||
|
||||
public SGame()
|
||||
|
@ -192,7 +195,6 @@ namespace StardewModdingAPI.Inheritance
|
|||
{
|
||||
Log.Verbose("XNA Initialize");
|
||||
ModItems = new Dictionary<Int32, SObject>();
|
||||
PreviouslyPressedKeys = new Keys[0];
|
||||
PreviouslyPressedButtons = new Buttons[4][];
|
||||
for (int i = 0; i < 4; ++i) PreviouslyPressedButtons[i] = new Buttons[0];
|
||||
|
||||
|
@ -211,6 +213,11 @@ namespace StardewModdingAPI.Inheritance
|
|||
{
|
||||
UpdateEventCalls();
|
||||
|
||||
if (FramePressedKeys.Contains(Keys.F3))
|
||||
{
|
||||
Debug = !Debug;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
base.Update(gameTime);
|
||||
|
@ -250,17 +257,37 @@ namespace StardewModdingAPI.Inheritance
|
|||
if (CurrentUpdateTick >= 60)
|
||||
CurrentUpdateTick = 0;
|
||||
|
||||
PreviouslyPressedKeys = CurrentlyPressedKeys;
|
||||
for(PlayerIndex i = PlayerIndex.One; i <= PlayerIndex.Four; i++)
|
||||
if (KStatePrior != KStateNow)
|
||||
KStatePrior = KStateNow;
|
||||
|
||||
for (PlayerIndex i = PlayerIndex.One; i <= PlayerIndex.Four; i++)
|
||||
{
|
||||
PreviouslyPressedButtons[(int)i] = GetButtonsDown(i);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Draw(GameTime gameTime)
|
||||
{
|
||||
FramesPerSecond = 1 / (float)gameTime.ElapsedGameTime.TotalSeconds;
|
||||
|
||||
try
|
||||
{
|
||||
base.Draw(gameTime);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error("An error occured in the base draw loop: " + ex);
|
||||
Console.ReadKey();
|
||||
}
|
||||
|
||||
GraphicsEvents.InvokeDrawTick();
|
||||
|
||||
if (Debug)
|
||||
{
|
||||
spriteBatch.Begin();
|
||||
spriteBatch.DrawString(dialogueFont, "FPS: " + FramesPerSecond, Vector2.Zero, Color.CornflowerBlue);
|
||||
spriteBatch.End();
|
||||
}
|
||||
}
|
||||
|
||||
public static Int32 RegisterModItem(SObject modItem)
|
||||
|
@ -301,7 +328,6 @@ namespace StardewModdingAPI.Inheritance
|
|||
public void UpdateEventCalls()
|
||||
{
|
||||
KStateNow = Keyboard.GetState();
|
||||
CurrentlyPressedKeys = KStateNow.GetPressedKeys();
|
||||
|
||||
MStateNow = Mouse.GetState();
|
||||
|
||||
|
@ -346,7 +372,6 @@ namespace StardewModdingAPI.Inheritance
|
|||
if (KStateNow != KStatePrior)
|
||||
{
|
||||
ControlEvents.InvokeKeyboardChanged(KStatePrior, KStateNow);
|
||||
KStatePrior = KStateNow;
|
||||
}
|
||||
|
||||
if (MStateNow != MStatePrior)
|
||||
|
|
|
@ -39,7 +39,7 @@ namespace StardewModdingAPI
|
|||
/// </summary>
|
||||
public virtual string EntryDll { get; set; }
|
||||
|
||||
public override Config GenerateBaseConfig(Config baseConfig)
|
||||
protected override T GenerateBaseConfig<T>()
|
||||
{
|
||||
Name = "";
|
||||
Authour = "";
|
||||
|
@ -48,7 +48,7 @@ namespace StardewModdingAPI
|
|||
UniqueID = Guid.NewGuid().ToString();
|
||||
PerSaveConfigs = false;
|
||||
EntryDll = "";
|
||||
return this;
|
||||
return this as T;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -290,7 +290,9 @@ namespace StardewModdingAPI
|
|||
continue;
|
||||
}
|
||||
|
||||
manifest = (Manifest)Config.InitializeConfig(s, manifest);
|
||||
//manifest = (Manifest)Config.InitializeConfig(s, manifest);
|
||||
manifest = manifest.InitializeConfig(s);
|
||||
|
||||
if (string.IsNullOrEmpty(manifest.EntryDll))
|
||||
{
|
||||
StardewModdingAPI.Log.Error("Failed to read mod manifest '{0}'. EntryDll is empty!", s);
|
||||
|
|
Loading…
Reference in New Issue