diff --git a/docs/release-notes.md b/docs/release-notes.md
index fa2ec91b..42519b1f 100644
--- a/docs/release-notes.md
+++ b/docs/release-notes.md
@@ -1,6 +1,10 @@
← [README](README.md)
# Release notes
+## Upcoming release
+* For players:
+ * Added `set_farm_type` [console command](https://stardewvalleywiki.com/Modding:Console_commands#Console_commands) to change the current farm type.
+
## 3.12.8
Released 18 October 2021 for Stardew Valley 1.5.4.
diff --git a/src/SMAPI.Mods.ConsoleCommands/Framework/Commands/Player/SetFarmTypeCommand.cs b/src/SMAPI.Mods.ConsoleCommands/Framework/Commands/Player/SetFarmTypeCommand.cs
new file mode 100644
index 00000000..0bebd2b7
--- /dev/null
+++ b/src/SMAPI.Mods.ConsoleCommands/Framework/Commands/Player/SetFarmTypeCommand.cs
@@ -0,0 +1,91 @@
+using System.Collections.Generic;
+using System.Linq;
+using StardewValley;
+
+namespace StardewModdingAPI.Mods.ConsoleCommands.Framework.Commands.Player
+{
+ /// A command which changes the player's farm type.
+ internal class SetFarmTypeCommand : ConsoleCommand
+ {
+ /*********
+ ** Fields
+ *********/
+ /// The vanilla farm type IDs.
+ private static readonly ISet VanillaFarmTypes = new HashSet(
+ Enumerable.Range(0, Farm.layout_max + 1)
+ );
+
+
+ /*********
+ ** Public methods
+ *********/
+ /// Construct an instance.
+ public SetFarmTypeCommand()
+ : base("set_farm_type", $"Sets the current player's farm type.\n\nUsage: set_farm_type \n- farm type: one of {string.Join(", ", SetFarmTypeCommand.VanillaFarmTypes.Select(id => $"{id} ({SetFarmTypeCommand.GetFarmLabel(id)})"))}.") { }
+
+ /// Handle the command.
+ /// Writes messages to the console and log file.
+ /// The command name.
+ /// The command arguments.
+ public override void Handle(IMonitor monitor, string command, ArgumentParser args)
+ {
+ // validation checks
+ if (!Context.IsWorldReady)
+ {
+ monitor.Log("You must load a save to use this command.", LogLevel.Error);
+ return;
+ }
+
+ // parse argument
+ if (!args.TryGetInt(0, "farm type", out int farmType, min: 0, max: Farm.layout_max))
+ return;
+
+ // handle
+ if (Game1.whichFarm == farmType)
+ {
+ monitor.Log($"Your current farm is already set to {farmType} ({SetFarmTypeCommand.GetFarmLabel(farmType)}).", LogLevel.Info);
+ return;
+ }
+
+ this.SetFarmType(farmType);
+ monitor.Log($"Your current farm has been converted to {farmType} ({SetFarmTypeCommand.GetFarmLabel(farmType)}).", LogLevel.Warn);
+ monitor.Log("Saving and reloading is recommended to make sure everything is updated for the change.", LogLevel.Warn);
+ }
+
+
+ /*********
+ ** Private methods
+ *********/
+ /// Change the farm type to the given value.
+ /// The farm type ID.
+ private void SetFarmType(int type)
+ {
+ Game1.whichFarm = type;
+
+ Farm farm = Game1.getFarm();
+ farm.mapPath.Value = $@"Maps\{Farm.getMapNameFromTypeInt(Game1.whichFarm)}";
+ farm.reloadMap();
+ }
+
+ /// Get the display name for a vanilla farm type.
+ /// The farm type.
+ private static string GetFarmLabel(int type)
+ {
+ string translationKey = type switch
+ {
+ Farm.default_layout => "Character_FarmStandard",
+ Farm.riverlands_layout => "Character_FarmFishing",
+ Farm.forest_layout => "Character_FarmForaging",
+ Farm.mountains_layout => "Character_FarmMining",
+ Farm.combat_layout => "Character_FarmCombat",
+ Farm.fourCorners_layout => "Character_FarmFourCorners",
+ Farm.beach_layout => "Character_FarmBeach",
+ _ => null
+ };
+
+ return translationKey != null
+ ? Game1.content.LoadString(@$"Strings\UI:{translationKey}").Split('_')[0]
+ : type.ToString();
+ }
+ }
+}