Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Automate] Add option to transfer seeds and fertilizers into Junimo huts #763

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 15 additions & 3 deletions Automate/Framework/AutomationFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -255,9 +255,21 @@ public AutomationFactory(Func<ModConfig> config, IMonitor monitor, IReflectionHe

case JunimoHut hut:
{
var config = this.Config();
bool betterJunimosCompat = config.ModCompatibility.BetterJunimos && this.IsBetterJunimosLoaded;
return new JunimoHutMachine(hut, location, ignoreSeedOutput: betterJunimosCompat, ignoreFertilizerOutput: betterJunimosCompat, pullGemstonesFromJunimoHuts: config.PullGemstonesFromJunimoHuts);
ModConfig config = this.Config();

JunimoHutBehavior gemBehavior = config.JunimoHutBehaviorForGemStones;
if (gemBehavior is JunimoHutBehavior.AutoDetect)
gemBehavior = JunimoHutBehavior.Ignore;

JunimoHutBehavior fertilizerBehavior = config.JunimoHutBehaviorForFertilizer;
if (fertilizerBehavior is JunimoHutBehavior.AutoDetect)
fertilizerBehavior = this.IsBetterJunimosLoaded ? JunimoHutBehavior.Ignore : JunimoHutBehavior.MoveIntoChests;

JunimoHutBehavior seedBehavior = config.JunimoHutBehaviorForFertilizer;
if (seedBehavior is JunimoHutBehavior.AutoDetect)
seedBehavior = this.IsBetterJunimosLoaded ? JunimoHutBehavior.Ignore : JunimoHutBehavior.MoveIntoChests;

return new JunimoHutMachine(hut, location, gemBehavior, fertilizerBehavior, seedBehavior);
}

case Mill mill:
Expand Down
72 changes: 54 additions & 18 deletions Automate/Framework/GenericModConfigMenuIntegrationForAutomate.cs
Original file line number Diff line number Diff line change
Expand Up @@ -57,12 +57,6 @@ public void Register()
get: config => config.Enabled,
set: (config, value) => config.Enabled = value
)
.AddCheckbox(
name: I18n.Config_JunimoHutsOutputGems_Name,
tooltip: I18n.Config_JunimoHutsOutputGems_Desc,
get: config => config.PullGemstonesFromJunimoHuts,
set: (config, value) => config.PullGemstonesFromJunimoHuts = value
)
.AddNumberField(
name: I18n.Config_AutomationInterval_Name,
tooltip: I18n.Config_AutomationInterval_Desc,
Expand All @@ -76,22 +70,12 @@ public void Register()
tooltip: I18n.Config_ToggleOverlayKey_Desc,
get: config => config.Controls.ToggleOverlay,
set: (config, value) => config.Controls.ToggleOverlay = value
);

// mod compatibility
menu
.AddSectionTitle(I18n.Config_Title_ModCompatibility)
.AddCheckbox(
name: I18n.Config_BetterJunimos_Name,
tooltip: I18n.Config_BetterJunimos_Desc,
get: config => config.ModCompatibility.BetterJunimos,
set: (config, value) => config.ModCompatibility.BetterJunimos = value
)
.AddCheckbox(
name: I18n.Config_WarnForMissingBridgeMod_Name,
tooltip: I18n.Config_WarnForMissingBridgeMod_Desc,
get: config => config.ModCompatibility.WarnForMissingBridgeMod,
set: (config, value) => config.ModCompatibility.WarnForMissingBridgeMod = value
get: config => config.WarnForMissingBridgeMod,
set: (config, value) => config.WarnForMissingBridgeMod = value
);

// connectors
Expand All @@ -114,6 +98,30 @@ public void Register()
set: (config, value) => this.SetCustomConnectors(config, value.Split(',').Select(p => p.Trim()))
);

// Junimo huts
menu.AddSectionTitle(I18n.Config_Title_JunimoHuts);
this.AddJunimoHutBehaviorDropdown(
menu,
name: I18n.Config_JunimoHutGems_Name,
tooltip: I18n.Config_JunimoHutGems_Desc,
get: config => config.JunimoHutBehaviorForGemStones,
set: (config, value) => config.JunimoHutBehaviorForGemStones = value
);
this.AddJunimoHutBehaviorDropdown(
menu,
name: I18n.Config_JunimoHutFertilizer_Name,
tooltip: I18n.Config_JunimoHutFertilizer_Desc,
get: config => config.JunimoHutBehaviorForFertilizer,
set: (config, value) => config.JunimoHutBehaviorForFertilizer = value
);
this.AddJunimoHutBehaviorDropdown(
menu,
name: I18n.Config_JunimoHutSeeds_Name,
tooltip: I18n.Config_JunimoHutSeeds_Desc,
get: config => config.JunimoHutBehaviorForSeeds,
set: (config, value) => config.JunimoHutBehaviorForSeeds = value
);

// machine overrides
menu.AddSectionTitle(I18n.Config_Title_MachineOverrides);
foreach (var entry in this.Data.DefaultMachineOverrides)
Expand All @@ -132,6 +140,34 @@ public void Register()
/*********
** Private methods
*********/
/****
** Junimo huts
****/
/// <summary>Add a dropdown to configure Junimo hut behavior for an item type.</summary>
/// <param name="menu">The config menu to extend.</param>
/// <param name="name">The label text to show in the form.</param>
/// <param name="tooltip">The tooltip text shown when the cursor hovers on the field.</param>
/// <param name="get">Get the current value from the mod config.</param>
/// <param name="set">Set a new value in the mod config.</param>
private void AddJunimoHutBehaviorDropdown(GenericModConfigMenuIntegration<ModConfig> menu, Func<string> name, Func<string> tooltip, Func<ModConfig, JunimoHutBehavior> get, Action<ModConfig, JunimoHutBehavior> set)
{
menu.AddDropdown(
name: name,
tooltip: tooltip,
get: config => get(config).ToString(),
set: (config, value) => set(config, Enum.Parse<JunimoHutBehavior>(value)),
allowedValues: Enum.GetNames<JunimoHutBehavior>(),
formatAllowedValue: value => value switch
{
nameof(JunimoHutBehavior.AutoDetect) => I18n.Config_JunimoHuts_AutoDetect(),
nameof(JunimoHutBehavior.Ignore) => I18n.Config_JunimoHuts_Ignore(),
nameof(JunimoHutBehavior.MoveIntoChests) => I18n.Config_JunimoHuts_MoveIntoChests(),
nameof(JunimoHutBehavior.MoveIntoHut) => I18n.Config_JunimoHuts_MoveIntoHuts(),
_ => "???" // should never happen
}
);
}

/****
** Connectors
****/
Expand Down
110 changes: 85 additions & 25 deletions Automate/Framework/Machines/Buildings/JunimoHutMachine.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Linq;
using Pathoschild.Stardew.Automate.Framework.Models;
using StardewValley;
using StardewValley.Buildings;
using StardewValley.Objects;
Expand All @@ -12,14 +13,20 @@ internal class JunimoHutMachine : BaseMachineForBuilding<JunimoHut>
/*********
** Fields
*********/
/// <summary>Whether seeds should be ignored when selecting output.</summary>
private readonly bool IgnoreSeedOutput;
/// <summary>How to handle gem stones in the hut or connected chests.</summary>
private readonly JunimoHutBehavior GemBehavior;

/// <summary>Whether fertilizer should be ignored when selecting output.</summary>
private readonly bool IgnoreFertilizerOutput;
/// <summary>How to handle fertilizer in the hut or connected chests.</summary>
private readonly JunimoHutBehavior FertilizerBehavior;

/// <summary>Whether to pull gemstones out of Junimo huts.</summary>
public bool PullGemstonesFromJunimoHuts { get; set; }
/// <summary>How to handle seeds in the hut or connected chests.</summary>
private readonly JunimoHutBehavior SeedBehavior;

/// <summary>Whether the Junimo hut can automate input.</summary>
private readonly bool HasInput;

/// <summary>Whether any items are configured to be skipped when outputting.</summary>
private readonly bool HasIgnoredOutput;

/// <summary>The Junimo hut's output chest.</summary>
private Chest Output => this.Machine.output.Value;
Expand All @@ -31,15 +38,24 @@ internal class JunimoHutMachine : BaseMachineForBuilding<JunimoHut>
/// <summary>Construct an instance.</summary>
/// <param name="hut">The underlying Junimo hut.</param>
/// <param name="location">The location which contains the machine.</param>
/// <param name="ignoreSeedOutput">Whether seeds should be ignored when selecting output.</param>
/// <param name="ignoreFertilizerOutput">Whether fertilizer should be ignored when selecting output.</param>
/// <param name="pullGemstonesFromJunimoHuts">Whether to pull gemstones out of Junimo huts.</param>
public JunimoHutMachine(JunimoHut hut, GameLocation location, bool ignoreSeedOutput, bool ignoreFertilizerOutput, bool pullGemstonesFromJunimoHuts)
/// <param name="gemBehavior">How to handle gem stones in the hut or connected chests.</param>
/// <param name="fertilizerBehavior">How to handle fertilizer in the hut or connected chests.</param>
/// <param name="seedBehavior">How to handle seeds in the hut or connected chests.</param>
public JunimoHutMachine(JunimoHut hut, GameLocation location, JunimoHutBehavior gemBehavior, JunimoHutBehavior fertilizerBehavior, JunimoHutBehavior seedBehavior)
: base(hut, location, BaseMachine.GetTileAreaFor(hut))
{
this.IgnoreSeedOutput = ignoreSeedOutput;
this.IgnoreFertilizerOutput = ignoreFertilizerOutput;
this.PullGemstonesFromJunimoHuts = pullGemstonesFromJunimoHuts;
this.GemBehavior = gemBehavior;
this.FertilizerBehavior = fertilizerBehavior;
this.SeedBehavior = seedBehavior;

this.HasInput =
gemBehavior is JunimoHutBehavior.MoveIntoHut
|| fertilizerBehavior is JunimoHutBehavior.MoveIntoHut
|| seedBehavior is JunimoHutBehavior.MoveIntoHut;
this.HasIgnoredOutput =
gemBehavior is not JunimoHutBehavior.MoveIntoChests
|| fertilizerBehavior is not JunimoHutBehavior.MoveIntoChests
|| seedBehavior is not JunimoHutBehavior.MoveIntoChests;
}

/// <summary>Get the machine's processing state.</summary>
Expand All @@ -48,8 +64,11 @@ public override MachineState GetState()
if (this.Machine.isUnderConstruction())
return MachineState.Disabled;

return this.GetNextOutput() != null
? MachineState.Done
if (this.GetNextOutput() != null)
return MachineState.Done;

return this.HasInput
? MachineState.Empty
: MachineState.Processing;
}

Expand All @@ -64,7 +83,41 @@ public override MachineState GetState()
/// <returns>Returns whether the machine started processing an item.</returns>
public override bool SetInput(IStorage input)
{
return false; // no input
if (!this.HasInput)
return false;

// get next item
ITrackedStack? tracker = null;
foreach (ITrackedStack stack in input.GetItems())
{
if (stack.Sample is not SObject obj)
continue;

switch (obj.Category)
{
case SObject.SeedsCategory when this.SeedBehavior == JunimoHutBehavior.MoveIntoHut:
tracker = stack;
break;

case SObject.fertilizerCategory when this.FertilizerBehavior == JunimoHutBehavior.MoveIntoHut:
tracker = stack;
break;

case (SObject.GemCategory or SObject.mineralsCategory) when this.GemBehavior == JunimoHutBehavior.MoveIntoHut:
tracker = stack;
break;
}

if (tracker is not null)
break;
}
if (tracker == null)
return false;

// place item in output chest
SObject item = (SObject)tracker.Take(1)!;
this.Output.addItem(item);
return true;
}


Expand All @@ -84,15 +137,22 @@ private void OnOutputTaken(Item item)
{
foreach (Item item in this.Output.items.Where(p => p != null))
{
// ignore gems which change Junimo colors (see JunimoHut:getGemColor)
if (!this.PullGemstonesFromJunimoHuts && item.Category is SObject.GemCategory or SObject.mineralsCategory)
continue;

// ignore items used by another mod
if (this.IgnoreSeedOutput && item.Category == SObject.SeedsCategory)
continue;
if (this.IgnoreFertilizerOutput && item.Category == SObject.fertilizerCategory)
continue;
if (this.HasIgnoredOutput)
{
bool ignore = false;

switch (item.Category)
{
case SObject.SeedsCategory when this.SeedBehavior is not JunimoHutBehavior.MoveIntoChests:
case SObject.fertilizerCategory when this.FertilizerBehavior is not JunimoHutBehavior.MoveIntoChests:
case (SObject.GemCategory or SObject.mineralsCategory) when this.GemBehavior is not JunimoHutBehavior.MoveIntoChests:
ignore = true;
break;
}

if (ignore)
continue;
}

return item;
}
Expand Down
18 changes: 18 additions & 0 deletions Automate/Framework/Models/JunimoHutBehavior.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
namespace Pathoschild.Stardew.Automate.Framework.Models
{
/// <summary>Indicates how Junimo huts should be automated for a specific item type.</summary>
internal enum JunimoHutBehavior
{
/// <summary>Apply the default logic based on the player's installed mods (e.g. leave seeds in the hut if Better Junimos is installed).</summary>
AutoDetect,

/// <summary>Ignore items of this type, so they're not transferred either way.</summary>
Ignore,

/// <summary>Move any items of this type from the Junimo Hut into connected chests.</summary>
MoveIntoChests,

/// <summary>Move any items of this type from connected chests into the Junimo Hut.</summary>
MoveIntoHut
}
}
15 changes: 0 additions & 15 deletions Automate/Framework/Models/ModCompatibilityConfig.cs

This file was deleted.

18 changes: 13 additions & 5 deletions Automate/Framework/Models/ModConfig.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,17 @@ internal class ModConfig
/// <summary>Whether Automate is enabled.</summary>
public bool Enabled { get; set; } = true;

/// <summary>Whether to pull gemstones out of Junimo huts. If true, you won't be able to change Junimo colors by placing gemstones in their hut.</summary>
public bool PullGemstonesFromJunimoHuts { get; set; } = false;
/// <summary>How Junimo huts should automate gemstones.</summary>
/// <remarks>The <see cref="JunimoHutBehavior.AutoDetect"/> option is equivalent to <see cref="JunimoHutBehavior.Ignore"/>.</remarks>
public JunimoHutBehavior JunimoHutBehaviorForGemStones { get; set; } = JunimoHutBehavior.AutoDetect;

/// <summary>How Junimo huts should automate fertilizer items.</summary>
/// <remarks>The <see cref="JunimoHutBehavior.AutoDetect"/> option is equivalent to <see cref="JunimoHutBehavior.Ignore"/> (if Better Junimos is installed), else <see cref="JunimoHutBehavior.MoveIntoChests"/>.</remarks>
public JunimoHutBehavior JunimoHutBehaviorForFertilizer { get; set; } = JunimoHutBehavior.AutoDetect;

/// <summary>How Junimo huts should automate seed items.</summary>
/// <remarks>The <see cref="JunimoHutBehavior.AutoDetect"/> option is equivalent to <see cref="JunimoHutBehavior.Ignore"/> (if Better Junimos is installed), else <see cref="JunimoHutBehavior.MoveIntoChests"/>.</remarks>
public JunimoHutBehavior JunimoHutBehaviorForSeeds { get; set; } = JunimoHutBehavior.AutoDetect;

/// <summary>The number of ticks between each automation process (60 = once per second).</summary>
public int AutomationInterval { get; set; } = 60;
Expand All @@ -27,8 +36,8 @@ internal class ModConfig
/// <summary>The in-game object names through which machines can connect.</summary>
public HashSet<string> ConnectorNames { get; set; } = new() { "Workbench" };

/// <summary>Options affecting compatibility with other mods.</summary>
public ModCompatibilityConfig ModCompatibility { get; set; } = new();
/// <summary>Whether to log a warning if the player installs a custom-machine mod that requires a separate compatibility patch which isn't installed.</summary>
public bool WarnForMissingBridgeMod { get; set; } = true;

/// <summary>The configuration for specific machines by ID.</summary>
public Dictionary<string, ModConfigMachine> MachineOverrides { get; set; } = new();
Expand All @@ -47,7 +56,6 @@ public void OnDeserialized(StreamingContext context)
// normalize
this.Controls ??= new();
this.ConnectorNames = this.ConnectorNames.ToNonNullCaseInsensitive();
this.ModCompatibility ??= new();
this.MachineOverrides = this.MachineOverrides.ToNonNullCaseInsensitive();

// remove null values
Expand Down
2 changes: 1 addition & 1 deletion Automate/ModEntry.cs
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ public override void Entry(IModHelper helper)

// log info
this.Monitor.VerboseLog($"Initialized with automation every {this.Config.AutomationInterval} ticks.");
if (this.Config.ModCompatibility.WarnForMissingBridgeMod)
if (this.Config.WarnForMissingBridgeMod)
this.ReportMissingBridgeMods(this.Data.SuggestedIntegrations);
}

Expand Down
Loading