diff options
author | Jesse Plamondon-Willard <Pathoschild@users.noreply.github.com> | 2018-12-29 20:09:33 -0500 |
---|---|---|
committer | Jesse Plamondon-Willard <Pathoschild@users.noreply.github.com> | 2018-12-29 20:09:33 -0500 |
commit | f046091fe637963fd6a8cc8c1324daf81b64899f (patch) | |
tree | adeffec4a5d31503548ef5dead7d67b3bff9e694 /src/SMAPI.Mods.ConsoleCommands | |
parent | 82beefd8531467de318c1881afd15a258d489f37 (diff) | |
parent | ca18a2867b457fd6bfda71d9828884032ecadfb8 (diff) | |
download | SMAPI-f046091fe637963fd6a8cc8c1324daf81b64899f.tar.gz SMAPI-f046091fe637963fd6a8cc8c1324daf81b64899f.tar.bz2 SMAPI-f046091fe637963fd6a8cc8c1324daf81b64899f.zip |
Merge branch 'develop' into stable
Diffstat (limited to 'src/SMAPI.Mods.ConsoleCommands')
14 files changed, 261 insertions, 13 deletions
diff --git a/src/SMAPI.Mods.ConsoleCommands/Framework/Commands/ArgumentParser.cs b/src/SMAPI.Mods.ConsoleCommands/Framework/Commands/ArgumentParser.cs index 3ad1e168..10007b42 100644 --- a/src/SMAPI.Mods.ConsoleCommands/Framework/Commands/ArgumentParser.cs +++ b/src/SMAPI.Mods.ConsoleCommands/Framework/Commands/ArgumentParser.cs @@ -9,7 +9,7 @@ namespace StardewModdingAPI.Mods.ConsoleCommands.Framework.Commands internal class ArgumentParser : IReadOnlyList<string> { /********* - ** Properties + ** Fields *********/ /// <summary>The command name for errors.</summary> private readonly string CommandName; diff --git a/src/SMAPI.Mods.ConsoleCommands/Framework/Commands/Player/AddCommand.cs b/src/SMAPI.Mods.ConsoleCommands/Framework/Commands/Player/AddCommand.cs index 37f4719e..263e126c 100644 --- a/src/SMAPI.Mods.ConsoleCommands/Framework/Commands/Player/AddCommand.cs +++ b/src/SMAPI.Mods.ConsoleCommands/Framework/Commands/Player/AddCommand.cs @@ -10,7 +10,7 @@ namespace StardewModdingAPI.Mods.ConsoleCommands.Framework.Commands.Player internal class AddCommand : TrainerCommand { /********* - ** Properties + ** Fields *********/ /// <summary>Provides methods for searching and constructing items.</summary> private readonly ItemRepository Items = new ItemRepository(); diff --git a/src/SMAPI.Mods.ConsoleCommands/Framework/Commands/Player/ListItemTypesCommand.cs b/src/SMAPI.Mods.ConsoleCommands/Framework/Commands/Player/ListItemTypesCommand.cs index 34f1760c..a835455e 100644 --- a/src/SMAPI.Mods.ConsoleCommands/Framework/Commands/Player/ListItemTypesCommand.cs +++ b/src/SMAPI.Mods.ConsoleCommands/Framework/Commands/Player/ListItemTypesCommand.cs @@ -7,7 +7,7 @@ namespace StardewModdingAPI.Mods.ConsoleCommands.Framework.Commands.Player internal class ListItemTypesCommand : TrainerCommand { /********* - ** Properties + ** Fields *********/ /// <summary>Provides methods for searching and constructing items.</summary> private readonly ItemRepository Items = new ItemRepository(); diff --git a/src/SMAPI.Mods.ConsoleCommands/Framework/Commands/Player/ListItemsCommand.cs b/src/SMAPI.Mods.ConsoleCommands/Framework/Commands/Player/ListItemsCommand.cs index 942a50b8..5b52e9a2 100644 --- a/src/SMAPI.Mods.ConsoleCommands/Framework/Commands/Player/ListItemsCommand.cs +++ b/src/SMAPI.Mods.ConsoleCommands/Framework/Commands/Player/ListItemsCommand.cs @@ -9,7 +9,7 @@ namespace StardewModdingAPI.Mods.ConsoleCommands.Framework.Commands.Player internal class ListItemsCommand : TrainerCommand { /********* - ** Properties + ** Fields *********/ /// <summary>Provides methods for searching and constructing items.</summary> private readonly ItemRepository Items = new ItemRepository(); diff --git a/src/SMAPI.Mods.ConsoleCommands/Framework/Commands/Player/SetHealthCommand.cs b/src/SMAPI.Mods.ConsoleCommands/Framework/Commands/Player/SetHealthCommand.cs index 2e8f6630..1abb82b5 100644 --- a/src/SMAPI.Mods.ConsoleCommands/Framework/Commands/Player/SetHealthCommand.cs +++ b/src/SMAPI.Mods.ConsoleCommands/Framework/Commands/Player/SetHealthCommand.cs @@ -7,7 +7,7 @@ namespace StardewModdingAPI.Mods.ConsoleCommands.Framework.Commands.Player internal class SetHealthCommand : TrainerCommand { /********* - ** Properties + ** Fields *********/ /// <summary>Whether to keep the player's health at its maximum.</summary> private bool InfiniteHealth; diff --git a/src/SMAPI.Mods.ConsoleCommands/Framework/Commands/Player/SetMoneyCommand.cs b/src/SMAPI.Mods.ConsoleCommands/Framework/Commands/Player/SetMoneyCommand.cs index 3fc504b1..ad11cc66 100644 --- a/src/SMAPI.Mods.ConsoleCommands/Framework/Commands/Player/SetMoneyCommand.cs +++ b/src/SMAPI.Mods.ConsoleCommands/Framework/Commands/Player/SetMoneyCommand.cs @@ -7,7 +7,7 @@ namespace StardewModdingAPI.Mods.ConsoleCommands.Framework.Commands.Player internal class SetMoneyCommand : TrainerCommand { /********* - ** Properties + ** Fields *********/ /// <summary>Whether to keep the player's money at a set value.</summary> private bool InfiniteMoney; diff --git a/src/SMAPI.Mods.ConsoleCommands/Framework/Commands/Player/SetStaminaCommand.cs b/src/SMAPI.Mods.ConsoleCommands/Framework/Commands/Player/SetStaminaCommand.cs index 866c3d22..009cb1de 100644 --- a/src/SMAPI.Mods.ConsoleCommands/Framework/Commands/Player/SetStaminaCommand.cs +++ b/src/SMAPI.Mods.ConsoleCommands/Framework/Commands/Player/SetStaminaCommand.cs @@ -7,7 +7,7 @@ namespace StardewModdingAPI.Mods.ConsoleCommands.Framework.Commands.Player internal class SetStaminaCommand : TrainerCommand { /********* - ** Properties + ** Fields *********/ /// <summary>Whether to keep the player's stamina at its maximum.</summary> private bool InfiniteStamina; diff --git a/src/SMAPI.Mods.ConsoleCommands/Framework/Commands/World/ClearCommand.cs b/src/SMAPI.Mods.ConsoleCommands/Framework/Commands/World/ClearCommand.cs new file mode 100644 index 00000000..c769b622 --- /dev/null +++ b/src/SMAPI.Mods.ConsoleCommands/Framework/Commands/World/ClearCommand.cs @@ -0,0 +1,246 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using StardewValley; +using StardewValley.Locations; +using StardewValley.Objects; +using StardewValley.TerrainFeatures; +using SObject = StardewValley.Object; + +namespace StardewModdingAPI.Mods.ConsoleCommands.Framework.Commands.World +{ + /// <summary>A command which clears in-game objects.</summary> + internal class ClearCommand : TrainerCommand + { + /********* + ** Fields + *********/ + /// <summary>The valid types that can be cleared.</summary> + private readonly string[] ValidTypes = { "debris", "fruit-trees", "grass", "trees", "everything" }; + + /// <summary>The resource clump IDs to consider debris.</summary> + private readonly int[] DebrisClumps = { ResourceClump.stumpIndex, ResourceClump.hollowLogIndex, ResourceClump.meteoriteIndex, ResourceClump.boulderIndex }; + + + /********* + ** Public methods + *********/ + /// <summary>Construct an instance.</summary> + public ClearCommand() + : base( + name: "world_clear", + description: "Clears in-game entities in a given location.\n\n" + + "Usage: world_clear <location> <object type>\n" + + "- location: the location name for which to clear objects (like Farm), or 'current' for the current location.\n" + + " - object type: the type of object clear. You can specify 'debris' (stones/twigs/weeds and dead crops), 'grass', and 'trees' / 'fruit-trees'. You can also specify 'everything', which includes things not removed by the other types (like furniture or resource clumps)." + ) + { } + + /// <summary>Handle the command.</summary> + /// <param name="monitor">Writes messages to the console and log file.</param> + /// <param name="command">The command name.</param> + /// <param name="args">The command arguments.</param> + public override void Handle(IMonitor monitor, string command, ArgumentParser args) + { + // check context + if (!Context.IsWorldReady) + { + monitor.Log("You need to load a save to use this command.", LogLevel.Error); + return; + } + + // parse arguments + if (!args.TryGet(0, "location", out string locationName, required: true)) + return; + if (!args.TryGet(1, "object type", out string type, required: true, oneOf: this.ValidTypes)) + return; + + // get target location + GameLocation location = Game1.locations.FirstOrDefault(p => p.Name != null && p.Name.Equals(locationName, StringComparison.InvariantCultureIgnoreCase)); + if (location == null && locationName == "current") + location = Game1.currentLocation; + if (location == null) + { + string[] locationNames = (from loc in Game1.locations where !string.IsNullOrWhiteSpace(loc.Name) orderby loc.Name select loc.Name).ToArray(); + monitor.Log($"Could not find a location with that name. Must be one of [{string.Join(", ", locationNames)}].", LogLevel.Error); + return; + } + + // apply + switch (type) + { + case "debris": + { + int removed = 0; + foreach (var pair in location.terrainFeatures.Pairs.ToArray()) + { + TerrainFeature feature = pair.Value; + if (feature is HoeDirt dirt && dirt.crop?.dead == true) + { + dirt.crop = null; + removed++; + } + } + + removed += + this.RemoveObjects(location, obj => obj.Name.ToLower().Contains("weed") || obj.Name == "Twig" || obj.Name == "Stone") + + this.RemoveResourceClumps(location, clump => this.DebrisClumps.Contains(clump.parentSheetIndex.Value)); + + monitor.Log($"Done! Removed {removed} entities from {location.Name}.", LogLevel.Info); + break; + } + + case "fruit-trees": + { + int removed = this.RemoveTerrainFeatures(location, feature => feature is FruitTree); + monitor.Log($"Done! Removed {removed} entities from {location.Name}.", LogLevel.Info); + break; + } + + case "grass": + { + int removed = this.RemoveTerrainFeatures(location, feature => feature is Grass); + monitor.Log($"Done! Removed {removed} entities from {location.Name}.", LogLevel.Info); + break; + } + + case "trees": + { + int removed = this.RemoveTerrainFeatures(location, feature => feature is Tree); + monitor.Log($"Done! Removed {removed} entities from {location.Name}.", LogLevel.Info); + break; + } + + case "everything": + { + int removed = + this.RemoveFurniture(location, p => true) + + this.RemoveObjects(location, p => true) + + this.RemoveTerrainFeatures(location, p => true) + + this.RemoveLargeTerrainFeatures(location, p => true) + + this.RemoveResourceClumps(location, p => true); + monitor.Log($"Done! Removed {removed} entities from {location.Name}.", LogLevel.Info); + break; + } + + default: + monitor.Log($"Unknown type '{type}'. Must be one [{string.Join(", ", this.ValidTypes)}].", LogLevel.Error); + break; + } + } + + + /********* + ** Private methods + *********/ + /// <summary>Remove objects from a location matching a lambda.</summary> + /// <param name="location">The location to search.</param> + /// <param name="shouldRemove">Whether an entity should be removed.</param> + /// <returns>Returns the number of removed entities.</returns> + private int RemoveObjects(GameLocation location, Func<SObject, bool> shouldRemove) + { + int removed = 0; + + foreach (var pair in location.Objects.Pairs.ToArray()) + { + if (shouldRemove(pair.Value)) + { + location.Objects.Remove(pair.Key); + removed++; + } + } + + return removed; + } + + /// <summary>Remove terrain features from a location matching a lambda.</summary> + /// <param name="location">The location to search.</param> + /// <param name="shouldRemove">Whether an entity should be removed.</param> + /// <returns>Returns the number of removed entities.</returns> + private int RemoveTerrainFeatures(GameLocation location, Func<TerrainFeature, bool> shouldRemove) + { + int removed = 0; + + foreach (var pair in location.terrainFeatures.Pairs.ToArray()) + { + if (shouldRemove(pair.Value)) + { + location.terrainFeatures.Remove(pair.Key); + removed++; + } + } + + return removed; + } + + /// <summary>Remove large terrain features from a location matching a lambda.</summary> + /// <param name="location">The location to search.</param> + /// <param name="shouldRemove">Whether an entity should be removed.</param> + /// <returns>Returns the number of removed entities.</returns> + private int RemoveLargeTerrainFeatures(GameLocation location, Func<LargeTerrainFeature, bool> shouldRemove) + { + int removed = 0; + + foreach (LargeTerrainFeature feature in location.largeTerrainFeatures.ToArray()) + { + if (shouldRemove(feature)) + { + location.largeTerrainFeatures.Remove(feature); + removed++; + } + } + + return removed; + } + + /// <summary>Remove resource clumps from a location matching a lambda.</summary> + /// <param name="location">The location to search.</param> + /// <param name="shouldRemove">Whether an entity should be removed.</param> + /// <returns>Returns the number of removed entities.</returns> + private int RemoveResourceClumps(GameLocation location, Func<ResourceClump, bool> shouldRemove) + { + int removed = 0; + + // get resource clumps + IList<ResourceClump> resourceClumps = + (location as Farm)?.resourceClumps + ?? (IList<ResourceClump>)(location as Woods)?.stumps + ?? new List<ResourceClump>(); + + // remove matching clumps + foreach (var clump in resourceClumps.ToArray()) + { + if (shouldRemove(clump)) + { + resourceClumps.Remove(clump); + removed++; + } + } + + return removed; + } + + /// <summary>Remove furniture from a location matching a lambda.</summary> + /// <param name="location">The location to search.</param> + /// <param name="shouldRemove">Whether an entity should be removed.</param> + /// <returns>Returns the number of removed entities.</returns> + private int RemoveFurniture(GameLocation location, Func<Furniture, bool> shouldRemove) + { + int removed = 0; + + if (location is DecoratableLocation decoratableLocation) + { + foreach (Furniture furniture in decoratableLocation.furniture.ToArray()) + { + if (shouldRemove(furniture)) + { + decoratableLocation.furniture.Remove(furniture); + removed++; + } + } + } + + return removed; + } + } +} diff --git a/src/SMAPI.Mods.ConsoleCommands/Framework/Commands/World/FreezeTimeCommand.cs b/src/SMAPI.Mods.ConsoleCommands/Framework/Commands/World/FreezeTimeCommand.cs index 2627b714..6a7ab162 100644 --- a/src/SMAPI.Mods.ConsoleCommands/Framework/Commands/World/FreezeTimeCommand.cs +++ b/src/SMAPI.Mods.ConsoleCommands/Framework/Commands/World/FreezeTimeCommand.cs @@ -7,7 +7,7 @@ namespace StardewModdingAPI.Mods.ConsoleCommands.Framework.Commands.World internal class FreezeTimeCommand : TrainerCommand { /********* - ** Properties + ** Fields *********/ /// <summary>The time of day at which to freeze time.</summary> internal static int FrozenTime; diff --git a/src/SMAPI.Mods.ConsoleCommands/Framework/Commands/World/SetSeasonCommand.cs b/src/SMAPI.Mods.ConsoleCommands/Framework/Commands/World/SetSeasonCommand.cs index b5db9c0d..0615afe7 100644 --- a/src/SMAPI.Mods.ConsoleCommands/Framework/Commands/World/SetSeasonCommand.cs +++ b/src/SMAPI.Mods.ConsoleCommands/Framework/Commands/World/SetSeasonCommand.cs @@ -7,7 +7,7 @@ namespace StardewModdingAPI.Mods.ConsoleCommands.Framework.Commands.World internal class SetSeasonCommand : TrainerCommand { /********* - ** Properties + ** Fields *********/ /// <summary>The valid season names.</summary> private readonly string[] ValidSeasons = { "winter", "spring", "summer", "fall" }; diff --git a/src/SMAPI.Mods.ConsoleCommands/Framework/ItemRepository.cs b/src/SMAPI.Mods.ConsoleCommands/Framework/ItemRepository.cs index f4a38403..fc631826 100644 --- a/src/SMAPI.Mods.ConsoleCommands/Framework/ItemRepository.cs +++ b/src/SMAPI.Mods.ConsoleCommands/Framework/ItemRepository.cs @@ -12,7 +12,7 @@ namespace StardewModdingAPI.Mods.ConsoleCommands.Framework internal class ItemRepository { /********* - ** Properties + ** Fields *********/ /// <summary>The custom ID offset for items don't have a unique ID in the game.</summary> private readonly int CustomIDOffset = 1000; diff --git a/src/SMAPI.Mods.ConsoleCommands/ModEntry.cs b/src/SMAPI.Mods.ConsoleCommands/ModEntry.cs index 30951064..77dace26 100644 --- a/src/SMAPI.Mods.ConsoleCommands/ModEntry.cs +++ b/src/SMAPI.Mods.ConsoleCommands/ModEntry.cs @@ -10,7 +10,7 @@ namespace StardewModdingAPI.Mods.ConsoleCommands public class ModEntry : Mod { /********* - ** Properties + ** Fields *********/ /// <summary>The commands to handle.</summary> private ITrainerCommand[] Commands; diff --git a/src/SMAPI.Mods.ConsoleCommands/StardewModdingAPI.Mods.ConsoleCommands.csproj b/src/SMAPI.Mods.ConsoleCommands/StardewModdingAPI.Mods.ConsoleCommands.csproj index d1f16e41..2c958dbc 100644 --- a/src/SMAPI.Mods.ConsoleCommands/StardewModdingAPI.Mods.ConsoleCommands.csproj +++ b/src/SMAPI.Mods.ConsoleCommands/StardewModdingAPI.Mods.ConsoleCommands.csproj @@ -11,6 +11,7 @@ <AssemblyName>ConsoleCommands</AssemblyName> <TargetFrameworkVersion>v4.5</TargetFrameworkVersion> <FileAlignment>512</FileAlignment> + <LangVersion>latest</LangVersion> </PropertyGroup> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' "> <DebugSymbols>true</DebugSymbols> @@ -62,6 +63,7 @@ <Compile Include="Framework\Commands\TrainerCommand.cs" /> <Compile Include="Framework\Commands\World\SetMineLevelCommand.cs" /> <Compile Include="Framework\Commands\World\DownMineLevelCommand.cs" /> + <Compile Include="Framework\Commands\World\ClearCommand.cs" /> <Compile Include="Framework\Commands\World\SetYearCommand.cs" /> <Compile Include="Framework\Commands\World\SetSeasonCommand.cs" /> <Compile Include="Framework\Commands\World\SetDayCommand.cs" /> diff --git a/src/SMAPI.Mods.ConsoleCommands/manifest.json b/src/SMAPI.Mods.ConsoleCommands/manifest.json index 541d1045..3e7001d5 100644 --- a/src/SMAPI.Mods.ConsoleCommands/manifest.json +++ b/src/SMAPI.Mods.ConsoleCommands/manifest.json @@ -1,9 +1,9 @@ { "Name": "Console Commands", "Author": "SMAPI", - "Version": "2.9.3", + "Version": "2.10.0", "Description": "Adds SMAPI console commands that let you manipulate the game.", "UniqueID": "SMAPI.ConsoleCommands", "EntryDll": "ConsoleCommands.dll", - "MinimumApiVersion": "2.9.3" + "MinimumApiVersion": "2.10.0" } |