add world_clear console command
This commit is contained in:
parent
270d436a17
commit
7294cb3cc5
|
@ -1,6 +1,7 @@
|
|||
# Release notes
|
||||
## Upcoming release
|
||||
* For players:
|
||||
* Added `world_clear` console command to remove spawned or placed entities.
|
||||
* Tweaked installer to reduce antivirus false positives.
|
||||
|
||||
## 2.9.3
|
||||
|
|
|
@ -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
|
||||
{
|
||||
/*********
|
||||
** Properties
|
||||
*********/
|
||||
/// <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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -62,6 +62,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" />
|
||||
|
|
Loading…
Reference in New Issue