summaryrefslogtreecommitdiff
path: root/src/SMAPI/Framework/ModHelpers
diff options
context:
space:
mode:
authorJesse Plamondon-Willard <github@jplamondonw.com>2018-08-01 11:07:29 -0400
committerJesse Plamondon-Willard <github@jplamondonw.com>2018-08-01 11:07:29 -0400
commit60b41195778af33fd609eab66d9ae3f1d1165e8f (patch)
tree7128b906d40e94c56c34ed6058f27bc31c31a08b /src/SMAPI/Framework/ModHelpers
parentb9bc1a6d17cafa0a97b46ffecda432cfc2f23b51 (diff)
parent52cf953f685c65b2b6814e375ec9a5ffa03c440a (diff)
downloadSMAPI-60b41195778af33fd609eab66d9ae3f1d1165e8f.tar.gz
SMAPI-60b41195778af33fd609eab66d9ae3f1d1165e8f.tar.bz2
SMAPI-60b41195778af33fd609eab66d9ae3f1d1165e8f.zip
Merge branch 'develop' into stable
Diffstat (limited to 'src/SMAPI/Framework/ModHelpers')
-rw-r--r--src/SMAPI/Framework/ModHelpers/ContentHelper.cs78
-rw-r--r--src/SMAPI/Framework/ModHelpers/InputHelper.cs54
-rw-r--r--src/SMAPI/Framework/ModHelpers/ModHelper.cs51
-rw-r--r--src/SMAPI/Framework/ModHelpers/ModRegistryHelper.cs4
-rw-r--r--src/SMAPI/Framework/ModHelpers/MultiplayerHelper.cs40
-rw-r--r--src/SMAPI/Framework/ModHelpers/ReflectionHelper.cs116
6 files changed, 173 insertions, 170 deletions
diff --git a/src/SMAPI/Framework/ModHelpers/ContentHelper.cs b/src/SMAPI/Framework/ModHelpers/ContentHelper.cs
index c7d4c39e..671dc21e 100644
--- a/src/SMAPI/Framework/ModHelpers/ContentHelper.cs
+++ b/src/SMAPI/Framework/ModHelpers/ContentHelper.cs
@@ -7,8 +7,9 @@ using System.IO;
using System.Linq;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
+using StardewModdingAPI.Framework.ContentManagers;
using StardewModdingAPI.Framework.Exceptions;
-using StardewModdingAPI.Framework.Utilities;
+using StardewModdingAPI.Toolkit.Utilities;
using StardewValley;
using xTile;
using xTile.Format;
@@ -23,10 +24,13 @@ namespace StardewModdingAPI.Framework.ModHelpers
** Properties
*********/
/// <summary>SMAPI's core content logic.</summary>
- private readonly ContentCore ContentCore;
+ private readonly ContentCoordinator ContentCore;
- /// <summary>The content manager for this mod.</summary>
- private readonly ContentManagerShim ContentManager;
+ /// <summary>A content manager for this mod which manages files from the game's Content folder.</summary>
+ private readonly IContentManager GameContentManager;
+
+ /// <summary>A content manager for this mod which manages files from the mod's folder.</summary>
+ private readonly IContentManager ModContentManager;
/// <summary>The absolute path to the mod folder.</summary>
private readonly string ModFolderPath;
@@ -42,10 +46,10 @@ namespace StardewModdingAPI.Framework.ModHelpers
** Accessors
*********/
/// <summary>The game's current locale code (like <c>pt-BR</c>).</summary>
- public string CurrentLocale => this.ContentCore.GetLocale();
+ public string CurrentLocale => this.GameContentManager.GetLocale();
/// <summary>The game's current locale as an enum value.</summary>
- public LocalizedContentManager.LanguageCode CurrentLocaleConstant => this.ContentCore.Language;
+ public LocalizedContentManager.LanguageCode CurrentLocaleConstant => this.GameContentManager.Language;
/// <summary>The observable implementation of <see cref="AssetEditors"/>.</summary>
internal ObservableCollection<IAssetEditor> ObservableAssetEditors { get; } = new ObservableCollection<IAssetEditor>();
@@ -65,16 +69,16 @@ namespace StardewModdingAPI.Framework.ModHelpers
*********/
/// <summary>Construct an instance.</summary>
/// <param name="contentCore">SMAPI's core content logic.</param>
- /// <param name="contentManager">The content manager for this mod.</param>
/// <param name="modFolderPath">The absolute path to the mod folder.</param>
/// <param name="modID">The unique ID of the relevant mod.</param>
/// <param name="modName">The friendly mod name for use in errors.</param>
/// <param name="monitor">Encapsulates monitoring and logging.</param>
- public ContentHelper(ContentCore contentCore, ContentManagerShim contentManager, string modFolderPath, string modID, string modName, IMonitor monitor)
+ public ContentHelper(ContentCoordinator contentCore, string modFolderPath, string modID, string modName, IMonitor monitor)
: base(modID)
{
this.ContentCore = contentCore;
- this.ContentManager = contentManager;
+ this.GameContentManager = contentCore.CreateGameContentManager(this.ContentCore.GetManagedAssetPrefix(modID) + ".content");
+ this.ModContentManager = contentCore.CreateModContentManager(this.ContentCore.GetManagedAssetPrefix(modID), rootDirectory: modFolderPath);
this.ModFolderPath = modFolderPath;
this.ModName = modName;
this.Monitor = monitor;
@@ -92,24 +96,22 @@ namespace StardewModdingAPI.Framework.ModHelpers
try
{
- this.AssertValidAssetKeyFormat(key);
+ this.AssertAndNormaliseAssetName(key);
switch (source)
{
case ContentSource.GameContent:
- return this.ContentManager.Load<T>(key);
+ return this.GameContentManager.Load<T>(key);
case ContentSource.ModFolder:
// get file
FileInfo file = this.GetModFile(key);
if (!file.Exists)
throw GetContentError($"there's no matching file at path '{file.FullName}'.");
-
- // get asset path
- string assetName = this.ContentCore.GetAssetNameFromFilePath(file.FullName);
+ string internalKey = this.GetInternalModAssetKey(file);
// try cache
- if (this.ContentCore.IsLoaded(assetName))
- return this.ContentManager.Load<T>(assetName);
+ if (this.ModContentManager.IsLoaded(internalKey))
+ return this.ModContentManager.Load<T>(internalKey);
// fix map tilesheets
if (file.Extension.ToLower() == ".tbin")
@@ -121,15 +123,15 @@ namespace StardewModdingAPI.Framework.ModHelpers
// fetch & cache
FormatManager formatManager = FormatManager.Instance;
Map map = formatManager.LoadMap(file.FullName);
- this.FixCustomTilesheetPaths(map, key);
+ this.FixCustomTilesheetPaths(map, relativeMapPath: key);
// inject map
- this.ContentManager.Inject(assetName, map);
+ this.ModContentManager.Inject(internalKey, map);
return (T)(object)map;
}
// load through content manager
- return this.ContentManager.Load<T>(assetName);
+ return this.ModContentManager.Load<T>(internalKey);
default:
throw GetContentError($"unknown content source '{source}'.");
@@ -146,7 +148,7 @@ namespace StardewModdingAPI.Framework.ModHelpers
[Pure]
public string NormaliseAssetName(string assetName)
{
- return this.ContentCore.NormaliseAssetName(assetName);
+ return this.ModContentManager.AssertAndNormaliseAssetName(assetName);
}
/// <summary>Get the underlying key in the game's content cache for an asset. This can be used to load custom map tilesheets, but should be avoided when you can use the content API instead. This does not validate whether the asset exists.</summary>
@@ -158,11 +160,11 @@ namespace StardewModdingAPI.Framework.ModHelpers
switch (source)
{
case ContentSource.GameContent:
- return this.ContentCore.NormaliseAssetName(key);
+ return this.GameContentManager.AssertAndNormaliseAssetName(key);
case ContentSource.ModFolder:
FileInfo file = this.GetModFile(key);
- return this.ContentCore.NormaliseAssetName(this.ContentCore.GetAssetNameFromFilePath(file.FullName));
+ return this.GetInternalModAssetKey(file);
default:
throw new NotSupportedException($"Unknown content source '{source}'.");
@@ -177,7 +179,7 @@ namespace StardewModdingAPI.Framework.ModHelpers
{
string actualKey = this.GetActualAssetKey(key, ContentSource.GameContent);
this.Monitor.Log($"Requested cache invalidation for '{actualKey}'.", LogLevel.Trace);
- return this.ContentCore.InvalidateCache(asset => asset.AssetNameEquals(actualKey));
+ return this.ContentCore.InvalidateCache(asset => asset.AssetNameEquals(actualKey)).Any();
}
/// <summary>Remove all assets of the given type from the cache so they're reloaded on the next request. <b>This can be a very expensive operation and should only be used in very specific cases.</b> This will reload core game assets if needed, but references to the former assets will still show the previous content.</summary>
@@ -186,7 +188,7 @@ namespace StardewModdingAPI.Framework.ModHelpers
public bool InvalidateCache<T>()
{
this.Monitor.Log($"Requested cache invalidation for all assets of type {typeof(T)}. This is an expensive operation and should be avoided if possible.", LogLevel.Trace);
- return this.ContentCore.InvalidateCache((key, type) => typeof(T).IsAssignableFrom(type));
+ return this.ContentCore.InvalidateCache((key, type) => typeof(T).IsAssignableFrom(type)).Any();
}
/// <summary>Remove matching assets from the content cache so they're reloaded on the next request. This will reload core game assets if needed, but references to the former asset will still show the previous content.</summary>
@@ -195,7 +197,7 @@ namespace StardewModdingAPI.Framework.ModHelpers
public bool InvalidateCache(Func<IAssetInfo, bool> predicate)
{
this.Monitor.Log("Requested cache invalidation for all assets matching a predicate.", LogLevel.Trace);
- return this.ContentCore.InvalidateCache(predicate);
+ return this.ContentCore.InvalidateCache(predicate).Any();
}
/*********
@@ -205,16 +207,24 @@ namespace StardewModdingAPI.Framework.ModHelpers
/// <param name="key">The asset key to check.</param>
/// <exception cref="ArgumentException">The asset key is empty or contains invalid characters.</exception>
[SuppressMessage("ReSharper", "ParameterOnlyUsedForPreconditionCheck.Local", Justification = "Parameter is only used for assertion checks by design.")]
- private void AssertValidAssetKeyFormat(string key)
+ private void AssertAndNormaliseAssetName(string key)
{
- this.ContentCore.AssertValidAssetKeyFormat(key);
+ this.ModContentManager.AssertAndNormaliseAssetName(key);
if (Path.IsPathRooted(key))
throw new ArgumentException("The asset key must not be an absolute path.");
}
+ /// <summary>Get the internal key in the content cache for a mod asset.</summary>
+ /// <param name="modFile">The asset file.</param>
+ private string GetInternalModAssetKey(FileInfo modFile)
+ {
+ string relativePath = PathUtilities.GetRelativePath(this.ModFolderPath, modFile.FullName);
+ return Path.Combine(this.ModContentManager.Name, relativePath);
+ }
+
/// <summary>Fix custom map tilesheet paths so they can be found by the content manager.</summary>
/// <param name="map">The map whose tilesheets to fix.</param>
- /// <param name="mapKey">The map asset key within the mod folder.</param>
+ /// <param name="relativeMapPath">The relative map path within the mod folder.</param>
/// <exception cref="ContentLoadException">A map tilesheet couldn't be resolved.</exception>
/// <remarks>
/// The game's logic for tilesheets in <see cref="Game1.setGraphicsForSeason"/> is a bit specialised. It boils
@@ -230,13 +240,13 @@ namespace StardewModdingAPI.Framework.ModHelpers
///
/// While that doesn't exactly match the game logic, it's close enough that it's unlikely to make a difference.
/// </remarks>
- private void FixCustomTilesheetPaths(Map map, string mapKey)
+ private void FixCustomTilesheetPaths(Map map, string relativeMapPath)
{
// get map info
if (!map.TileSheets.Any())
return;
- mapKey = this.ContentCore.NormaliseAssetName(mapKey); // Mono's Path.GetDirectoryName doesn't handle Windows dir separators
- string relativeMapFolder = Path.GetDirectoryName(mapKey) ?? ""; // folder path containing the map, relative to the mod folder
+ relativeMapPath = this.ModContentManager.AssertAndNormaliseAssetName(relativeMapPath); // Mono's Path.GetDirectoryName doesn't handle Windows dir separators
+ string relativeMapFolder = Path.GetDirectoryName(relativeMapPath) ?? ""; // folder path containing the map, relative to the mod folder
// fix tilesheets
foreach (TileSheet tilesheet in map.TileSheets)
@@ -251,7 +261,7 @@ namespace StardewModdingAPI.Framework.ModHelpers
string seasonalImageSource = null;
if (Game1.currentSeason != null)
{
- string filename = Path.GetFileName(imageSource);
+ string filename = Path.GetFileName(imageSource) ?? throw new InvalidOperationException($"The '{imageSource}' tilesheet couldn't be loaded: filename is unexpectedly null.");
bool hasSeasonalPrefix =
filename.StartsWith("spring_", StringComparison.CurrentCultureIgnoreCase)
|| filename.StartsWith("summer_", StringComparison.CurrentCultureIgnoreCase)
@@ -341,7 +351,7 @@ namespace StardewModdingAPI.Framework.ModHelpers
private FileInfo GetModFile(string path)
{
// try exact match
- path = Path.Combine(this.ModFolderPath, this.ContentCore.NormalisePathSeparators(path));
+ path = Path.Combine(this.ModFolderPath, this.ModContentManager.NormalisePathSeparators(path));
FileInfo file = new FileInfo(path);
// try with default extension
@@ -360,7 +370,7 @@ namespace StardewModdingAPI.Framework.ModHelpers
private FileInfo GetContentFolderFile(string key)
{
// get file path
- string path = Path.Combine(this.ContentCore.FullRootDirectory, key);
+ string path = Path.Combine(this.GameContentManager.FullRootDirectory, key);
if (!path.EndsWith(".xnb"))
path += ".xnb";
diff --git a/src/SMAPI/Framework/ModHelpers/InputHelper.cs b/src/SMAPI/Framework/ModHelpers/InputHelper.cs
new file mode 100644
index 00000000..f4cd12b6
--- /dev/null
+++ b/src/SMAPI/Framework/ModHelpers/InputHelper.cs
@@ -0,0 +1,54 @@
+using StardewModdingAPI.Framework.Input;
+
+namespace StardewModdingAPI.Framework.ModHelpers
+{
+ /// <summary>Provides an API for checking and changing input state.</summary>
+ internal class InputHelper : BaseHelper, IInputHelper
+ {
+ /*********
+ ** Accessors
+ *********/
+ /// <summary>Manages the game's input state.</summary>
+ private readonly SInputState InputState;
+
+
+ /*********
+ ** Public methods
+ *********/
+ /// <summary>Construct an instance.</summary>
+ /// <param name="modID">The unique ID of the relevant mod.</param>
+ /// <param name="inputState">Manages the game's input state.</param>
+ public InputHelper(string modID, SInputState inputState)
+ : base(modID)
+ {
+ this.InputState = inputState;
+ }
+
+ /// <summary>Get the current cursor position.</summary>
+ public ICursorPosition GetCursorPosition()
+ {
+ return this.InputState.CursorPosition;
+ }
+
+ /// <summary>Get whether a button is currently pressed.</summary>
+ /// <param name="button">The button.</param>
+ public bool IsDown(SButton button)
+ {
+ return this.InputState.IsDown(button);
+ }
+
+ /// <summary>Get whether a button is currently suppressed, so the game won't see it.</summary>
+ /// <param name="button">The button.</param>
+ public bool IsSuppressed(SButton button)
+ {
+ return this.InputState.SuppressButtons.Contains(button);
+ }
+
+ /// <summary>Prevent the game from handling a button press. This doesn't prevent other mods from receiving the event.</summary>
+ /// <param name="button">The button to suppress.</param>
+ public void Suppress(SButton button)
+ {
+ this.InputState.SuppressButtons.Add(button);
+ }
+ }
+}
diff --git a/src/SMAPI/Framework/ModHelpers/ModHelper.cs b/src/SMAPI/Framework/ModHelpers/ModHelper.cs
index b5758d21..d9498e83 100644
--- a/src/SMAPI/Framework/ModHelpers/ModHelper.cs
+++ b/src/SMAPI/Framework/ModHelpers/ModHelper.cs
@@ -2,9 +2,11 @@ using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
-using StardewModdingAPI.Framework.Models;
-using StardewModdingAPI.Framework.Serialisation;
-using StardewModdingAPI.Framework.Utilities;
+using StardewModdingAPI.Events;
+using StardewModdingAPI.Framework.Input;
+using StardewModdingAPI.Toolkit.Serialisation;
+using StardewModdingAPI.Toolkit.Serialisation.Models;
+using StardewModdingAPI.Toolkit.Utilities;
namespace StardewModdingAPI.Framework.ModHelpers
{
@@ -33,9 +35,15 @@ namespace StardewModdingAPI.Framework.ModHelpers
/// <summary>The full path to the mod's folder.</summary>
public string DirectoryPath { get; }
+ /// <summary>Manages access to events raised by SMAPI, which let your mod react when something happens in the game.</summary>
+ public IModEvents Events { get; }
+
/// <summary>An API for loading content assets.</summary>
public IContentHelper Content { get; }
+ /// <summary>An API for checking and changing input state.</summary>
+ public IInputHelper Input { get; }
+
/// <summary>An API for accessing private game code.</summary>
public IReflectionHelper Reflection { get; }
@@ -45,6 +53,9 @@ namespace StardewModdingAPI.Framework.ModHelpers
/// <summary>An API for managing console commands.</summary>
public ICommandHelper ConsoleCommands { get; }
+ /// <summary>Provides multiplayer utilities.</summary>
+ public IMultiplayerHelper Multiplayer { get; }
+
/// <summary>An API for reading translations stored in the mod's <c>i18n</c> folder, with one file per locale (like <c>en.json</c>) containing a flat key => value structure. Translations are fetched with locale fallback, so missing translations are filled in from broader locales (like <c>pt-BR.json</c> &lt; <c>pt.json</c> &lt; <c>default.json</c>).</summary>
public ITranslationHelper Translation { get; }
@@ -56,17 +67,20 @@ namespace StardewModdingAPI.Framework.ModHelpers
/// <param name="modID">The mod's unique ID.</param>
/// <param name="modDirectory">The full path to the mod's folder.</param>
/// <param name="jsonHelper">Encapsulate SMAPI's JSON parsing.</param>
+ /// <param name="inputState">Manages the game's input state.</param>
+ /// <param name="events">Manages access to events raised by SMAPI.</param>
/// <param name="contentHelper">An API for loading content assets.</param>
/// <param name="commandHelper">An API for managing console commands.</param>
/// <param name="modRegistry">an API for fetching metadata about loaded mods.</param>
/// <param name="reflectionHelper">An API for accessing private game code.</param>
+ /// <param name="multiplayer">Provides multiplayer utilities.</param>
/// <param name="translationHelper">An API for reading translations stored in the mod's <c>i18n</c> folder.</param>
/// <param name="contentPacks">The content packs loaded for this mod.</param>
/// <param name="createContentPack">Create a transitional content pack.</param>
/// <param name="deprecationManager">Manages deprecation warnings.</param>
/// <exception cref="ArgumentNullException">An argument is null or empty.</exception>
/// <exception cref="InvalidOperationException">The <paramref name="modDirectory"/> path does not exist on disk.</exception>
- public ModHelper(string modID, string modDirectory, JsonHelper jsonHelper, IContentHelper contentHelper, ICommandHelper commandHelper, IModRegistry modRegistry, IReflectionHelper reflectionHelper, ITranslationHelper translationHelper, IEnumerable<IContentPack> contentPacks, Func<string, IManifest, IContentPack> createContentPack, DeprecationManager deprecationManager)
+ public ModHelper(string modID, string modDirectory, JsonHelper jsonHelper, SInputState inputState, IModEvents events, IContentHelper contentHelper, ICommandHelper commandHelper, IModRegistry modRegistry, IReflectionHelper reflectionHelper, IMultiplayerHelper multiplayer, ITranslationHelper translationHelper, IEnumerable<IContentPack> contentPacks, Func<string, IManifest, IContentPack> createContentPack, DeprecationManager deprecationManager)
: base(modID)
{
// validate directory
@@ -79,13 +93,16 @@ namespace StardewModdingAPI.Framework.ModHelpers
this.DirectoryPath = modDirectory;
this.JsonHelper = jsonHelper ?? throw new ArgumentNullException(nameof(jsonHelper));
this.Content = contentHelper ?? throw new ArgumentNullException(nameof(contentHelper));
+ this.Input = new InputHelper(modID, inputState);
this.ModRegistry = modRegistry ?? throw new ArgumentNullException(nameof(modRegistry));
this.ConsoleCommands = commandHelper ?? throw new ArgumentNullException(nameof(commandHelper));
this.Reflection = reflectionHelper ?? throw new ArgumentNullException(nameof(reflectionHelper));
+ this.Multiplayer = multiplayer ?? throw new ArgumentNullException(nameof(multiplayer));
this.Translation = translationHelper ?? throw new ArgumentNullException(nameof(translationHelper));
this.ContentPacks = contentPacks.ToArray();
this.CreateContentPack = createContentPack;
this.DeprecationManager = deprecationManager;
+ this.Events = events;
}
/****
@@ -152,26 +169,24 @@ namespace StardewModdingAPI.Framework.ModHelpers
this.DeprecationManager.Warn($"{nameof(IModHelper)}.{nameof(IModHelper.CreateTransitionalContentPack)}", "2.5", DeprecationLevel.Notice);
// validate
- if(string.IsNullOrWhiteSpace(directoryPath))
+ if (string.IsNullOrWhiteSpace(directoryPath))
throw new ArgumentNullException(nameof(directoryPath));
- if(string.IsNullOrWhiteSpace(id))
+ if (string.IsNullOrWhiteSpace(id))
throw new ArgumentNullException(nameof(id));
- if(string.IsNullOrWhiteSpace(name))
+ if (string.IsNullOrWhiteSpace(name))
throw new ArgumentNullException(nameof(name));
- if(!Directory.Exists(directoryPath))
+ if (!Directory.Exists(directoryPath))
throw new ArgumentException($"Can't create content pack for directory path '{directoryPath}' because no such directory exists.");
// create manifest
- IManifest manifest = new Manifest
- {
- Name = name,
- Author = author,
- Description = description,
- Version = version,
- UniqueID = id,
- UpdateKeys = new string[0],
- ContentPackFor = new ManifestContentPackFor { UniqueID = this.ModID }
- };
+ IManifest manifest = new Manifest(
+ uniqueID: id,
+ name: name,
+ author: author,
+ description: description,
+ version: version,
+ contentPackFor: this.ModID
+ );
// create content pack
return this.CreateContentPack(directoryPath, manifest);
diff --git a/src/SMAPI/Framework/ModHelpers/ModRegistryHelper.cs b/src/SMAPI/Framework/ModHelpers/ModRegistryHelper.cs
index e579a830..008a80f5 100644
--- a/src/SMAPI/Framework/ModHelpers/ModRegistryHelper.cs
+++ b/src/SMAPI/Framework/ModHelpers/ModRegistryHelper.cs
@@ -82,12 +82,12 @@ namespace StardewModdingAPI.Framework.ModHelpers
}
if (!typeof(TInterface).IsInterface)
{
- this.Monitor.Log("Tried to map a mod-provided API to a class; must be a public interface.", LogLevel.Error);
+ this.Monitor.Log($"Tried to map a mod-provided API to class '{typeof(TInterface).FullName}'; must be a public interface.", LogLevel.Error);
return null;
}
if (!typeof(TInterface).IsPublic)
{
- this.Monitor.Log("Tried to map a mod-provided API to a non-public interface; must be a public interface.", LogLevel.Error);
+ this.Monitor.Log($"Tried to map a mod-provided API to non-public interface '{typeof(TInterface).FullName}'; must be a public interface.", LogLevel.Error);
return null;
}
diff --git a/src/SMAPI/Framework/ModHelpers/MultiplayerHelper.cs b/src/SMAPI/Framework/ModHelpers/MultiplayerHelper.cs
new file mode 100644
index 00000000..c449a51b
--- /dev/null
+++ b/src/SMAPI/Framework/ModHelpers/MultiplayerHelper.cs
@@ -0,0 +1,40 @@
+using System.Collections.Generic;
+using StardewValley;
+
+namespace StardewModdingAPI.Framework.ModHelpers
+{
+ /// <summary>Provides multiplayer utilities.</summary>
+ internal class MultiplayerHelper : BaseHelper, IMultiplayerHelper
+ {
+ /*********
+ ** Properties
+ *********/
+ /// <summary>SMAPI's core multiplayer utility.</summary>
+ private readonly SMultiplayer Multiplayer;
+
+
+ /*********
+ ** Public methods
+ *********/
+ /// <summary>Construct an instance.</summary>
+ /// <param name="modID">The unique ID of the relevant mod.</param>
+ /// <param name="multiplayer">SMAPI's core multiplayer utility.</param>
+ public MultiplayerHelper(string modID, SMultiplayer multiplayer)
+ : base(modID)
+ {
+ this.Multiplayer = multiplayer;
+ }
+
+ /// <summary>Get the locations which are being actively synced from the host.</summary>
+ public IEnumerable<GameLocation> GetActiveLocations()
+ {
+ return this.Multiplayer.activeLocations();
+ }
+
+ /// <summary>Get a new multiplayer ID.</summary>
+ public long GetNewID()
+ {
+ return this.Multiplayer.getNewID();
+ }
+ }
+}
diff --git a/src/SMAPI/Framework/ModHelpers/ReflectionHelper.cs b/src/SMAPI/Framework/ModHelpers/ReflectionHelper.cs
index e5bf47f6..648d6742 100644
--- a/src/SMAPI/Framework/ModHelpers/ReflectionHelper.cs
+++ b/src/SMAPI/Framework/ModHelpers/ReflectionHelper.cs
@@ -107,122 +107,6 @@ namespace StardewModdingAPI.Framework.ModHelpers
);
}
-#if !STARDEW_VALLEY_1_3
- /****
- ** Obsolete
- ****/
- /// <summary>Get a private instance field.</summary>
- /// <typeparam name="TValue">The field type.</typeparam>
- /// <param name="obj">The object which has the field.</param>
- /// <param name="name">The field name.</param>
- /// <param name="required">Whether to throw an exception if the private field is not found.</param>
- /// <returns>Returns the field wrapper, or <c>null</c> if the field doesn't exist and <paramref name="required"/> is <c>false</c>.</returns>
- [Obsolete]
- public IPrivateField<TValue> GetPrivateField<TValue>(object obj, string name, bool required = true)
- {
- this.DeprecationManager.Warn($"{nameof(IReflectionHelper)}.GetPrivate*", "2.3", DeprecationLevel.Notice);
- return (IPrivateField<TValue>)this.GetField<TValue>(obj, name, required);
- }
-
- /// <summary>Get a private static field.</summary>
- /// <typeparam name="TValue">The field type.</typeparam>
- /// <param name="type">The type which has the field.</param>
- /// <param name="name">The field name.</param>
- /// <param name="required">Whether to throw an exception if the private field is not found.</param>
- [Obsolete]
- public IPrivateField<TValue> GetPrivateField<TValue>(Type type, string name, bool required = true)
- {
- this.DeprecationManager.Warn($"{nameof(IReflectionHelper)}.GetPrivate*", "2.3", DeprecationLevel.Notice);
- return (IPrivateField<TValue>)this.GetField<TValue>(type, name, required);
- }
-
- /// <summary>Get a private instance property.</summary>
- /// <typeparam name="TValue">The property type.</typeparam>
- /// <param name="obj">The object which has the property.</param>
- /// <param name="name">The property name.</param>
- /// <param name="required">Whether to throw an exception if the private property is not found.</param>
- [Obsolete]
- public IPrivateProperty<TValue> GetPrivateProperty<TValue>(object obj, string name, bool required = true)
- {
- this.DeprecationManager.Warn($"{nameof(IReflectionHelper)}.GetPrivate*", "2.3", DeprecationLevel.Notice);
- return (IPrivateProperty<TValue>)this.GetProperty<TValue>(obj, name, required);
- }
-
- /// <summary>Get a private static property.</summary>
- /// <typeparam name="TValue">The property type.</typeparam>
- /// <param name="type">The type which has the property.</param>
- /// <param name="name">The property name.</param>
- /// <param name="required">Whether to throw an exception if the private property is not found.</param>
- [Obsolete]
- public IPrivateProperty<TValue> GetPrivateProperty<TValue>(Type type, string name, bool required = true)
- {
- this.DeprecationManager.Warn($"{nameof(IReflectionHelper)}.GetPrivate*", "2.3", DeprecationLevel.Notice);
- return (IPrivateProperty<TValue>)this.GetProperty<TValue>(type, name, required);
- }
-
- /// <summary>Get the value of a private instance field.</summary>
- /// <typeparam name="TValue">The field type.</typeparam>
- /// <param name="obj">The object which has the field.</param>
- /// <param name="name">The field name.</param>
- /// <param name="required">Whether to throw an exception if the private field is not found.</param>
- /// <returns>Returns the field value, or the default value for <typeparamref name="TValue"/> if the field wasn't found and <paramref name="required"/> is false.</returns>
- /// <remarks>
- /// This is a shortcut for <see cref="GetPrivateField{TValue}(object,string,bool)"/> followed by <see cref="IPrivateField{TValue}.GetValue"/>.
- /// When <paramref name="required" /> is false, this will return the default value if reflection fails. If you need to check whether the field exists, use <see cref="GetPrivateField{TValue}(object,string,bool)" /> instead.
- /// </remarks>
- [Obsolete]
- public TValue GetPrivateValue<TValue>(object obj, string name, bool required = true)
- {
- this.DeprecationManager.Warn($"{nameof(IReflectionHelper)}.GetPrivate*", "2.3", DeprecationLevel.Notice);
- IPrivateField<TValue> field = (IPrivateField<TValue>)this.GetField<TValue>(obj, name, required);
- return field != null
- ? field.GetValue()
- : default(TValue);
- }
-
- /// <summary>Get the value of a private static field.</summary>
- /// <typeparam name="TValue">The field type.</typeparam>
- /// <param name="type">The type which has the field.</param>
- /// <param name="name">The field name.</param>
- /// <param name="required">Whether to throw an exception if the private field is not found.</param>
- /// <returns>Returns the field value, or the default value for <typeparamref name="TValue"/> if the field wasn't found and <paramref name="required"/> is false.</returns>
- /// <remarks>
- /// This is a shortcut for <see cref="GetPrivateField{TValue}(Type,string,bool)"/> followed by <see cref="IPrivateField{TValue}.GetValue"/>.
- /// When <paramref name="required" /> is false, this will return the default value if reflection fails. If you need to check whether the field exists, use <see cref="GetPrivateField{TValue}(Type,string,bool)" /> instead.
- /// </remarks>
- [Obsolete]
- public TValue GetPrivateValue<TValue>(Type type, string name, bool required = true)
- {
- this.DeprecationManager.Warn($"{nameof(IReflectionHelper)}.GetPrivate*", "2.3", DeprecationLevel.Notice);
- IPrivateField<TValue> field = (IPrivateField<TValue>)this.GetField<TValue>(type, name, required);
- return field != null
- ? field.GetValue()
- : default(TValue);
- }
-
- /// <summary>Get a private instance method.</summary>
- /// <param name="obj">The object which has the method.</param>
- /// <param name="name">The field name.</param>
- /// <param name="required">Whether to throw an exception if the private field is not found.</param>
- [Obsolete]
- public IPrivateMethod GetPrivateMethod(object obj, string name, bool required = true)
- {
- this.DeprecationManager.Warn($"{nameof(IReflectionHelper)}.GetPrivate*", "2.3", DeprecationLevel.Notice);
- return (IPrivateMethod)this.GetMethod(obj, name, required);
- }
-
- /// <summary>Get a private static method.</summary>
- /// <param name="type">The type which has the method.</param>
- /// <param name="name">The field name.</param>
- /// <param name="required">Whether to throw an exception if the private field is not found.</param>
- [Obsolete]
- public IPrivateMethod GetPrivateMethod(Type type, string name, bool required = true)
- {
- this.DeprecationManager.Warn($"{nameof(IReflectionHelper)}.GetPrivate*", "2.3", DeprecationLevel.Notice);
- return (IPrivateMethod)this.GetMethod(type, name, required);
- }
-#endif
-
/*********
** Private methods