using System;
using System.Threading.Tasks;
using Microsoft.Xna.Framework.Input;
using StardewModdingAPI.Events;
using StardewModdingAPI.Framework;
using StardewValley;
using StardewValley.Events;
namespace StardewModdingAPI.Utilities
{
/// An implementation of which automatically calls the parent instance for any method that's not overridden.
/// The mod hooks are primarily meant for SMAPI to use. Using this directly in mods is a last resort, since it's very easy to break SMAPI this way. This class requires that SMAPI is present in the parent chain.
public class DelegatingModHooks : ModHooks
{
/*********
** Accessors
*********/
/// The underlying instance to delegate to by default.
public ModHooks Parent { get; }
/*********
** Public methods
*********/
/// Construct an instance.
/// The underlying instance to delegate to by default.
public DelegatingModHooks(ModHooks modHooks)
{
this.AssertSmapiInChain(modHooks);
this.Parent = modHooks;
}
/// Raised before the in-game clock changes.
/// Run the vanilla update logic.
/// In mods, consider using instead.
public override void OnGame1_PerformTenMinuteClockUpdate(Action action)
{
this.Parent.OnGame1_PerformTenMinuteClockUpdate(action);
}
/// Raised before initializing the new day and saving.
/// Run the vanilla update logic.
/// In mods, consider using or instead.
public override void OnGame1_NewDayAfterFade(Action action)
{
this.Parent.OnGame1_NewDayAfterFade(action);
}
/// Raised before showing the end-of-day menus (e.g. shipping menus, level-up screen, etc).
/// Run the vanilla update logic.
public override void OnGame1_ShowEndOfNightStuff(Action action)
{
this.Parent.OnGame1_ShowEndOfNightStuff(action);
}
/// Raised before updating the gamepad, mouse, and keyboard input state.
/// The keyboard state.
/// The mouse state.
/// The gamepad state.
/// Run the vanilla update logic.
/// In mods, consider using instead.
public override void OnGame1_UpdateControlInput(ref KeyboardState keyboardState, ref MouseState mouseState, ref GamePadState gamePadState, Action action)
{
this.Parent.OnGame1_UpdateControlInput(ref keyboardState, ref mouseState, ref gamePadState, action);
}
/// Raised before a location is updated for the local player entering it.
/// The location that will be updated.
/// Run the vanilla update logic.
/// In mods, consider using instead.
public override void OnGameLocation_ResetForPlayerEntry(GameLocation location, Action action)
{
this.Parent.OnGameLocation_ResetForPlayerEntry(location, action);
}
/// Raised before the game checks for an action to trigger for a player interaction with a tile.
/// The location being checked.
/// The tile position being checked.
/// The game's current position and size within the map, measured in pixels.
/// The player interacting with the tile.
/// Run the vanilla update logic.
/// Returns whether the interaction was handled.
public override bool OnGameLocation_CheckAction(GameLocation location, xTile.Dimensions.Location tileLocation, xTile.Dimensions.Rectangle viewport, Farmer who, Func action)
{
return this.Parent.OnGameLocation_CheckAction(location, tileLocation, viewport, who, action);
}
/// Raised before the game picks a night event to show on the farm after the player sleeps.
/// Run the vanilla update logic.
/// Returns the selected farm event.
public override FarmEvent OnUtility_PickFarmEvent(Func action)
{
return this.Parent.OnUtility_PickFarmEvent(action);
}
/// Start an asynchronous task for the game.
/// The task to start.
/// A unique key which identifies the task.
public override Task StartTask(Task task, string id)
{
return this.Parent.StartTask(task, id);
}
/// Start an asynchronous task for the game.
/// The type returned by the task when it completes.
/// The task to start.
/// A unique key which identifies the task.
public override Task StartTask(Task task, string id)
{
return this.Parent.StartTask(task, id);
}
/*********
** Private methods
*********/
/// Assert that SMAPI's mod hook implementation is in the inheritance chain.
/// The mod hooks to check.
private void AssertSmapiInChain(ModHooks hooks)
{
// this is SMAPI
if (this is SModHooks)
return;
// SMAPI in delegated chain
for (ModHooks? cur = hooks; cur != null; cur = (cur as DelegatingModHooks)?.Parent)
{
if (cur is SModHooks)
return;
}
// SMAPI not found
throw new InvalidOperationException($"Can't create a {nameof(DelegatingModHooks)} instance without SMAPI's mod hooks in the parent chain.");
}
}
}