Skip to content

Commit

Permalink
RELEASE 1.0.0:
Browse files Browse the repository at this point in the history
Item names can now correctly be used as identifiers in content pack RecipeIngredients entries.
Minor changes and cleaning-up for initial release.
  • Loading branch information
b-b-blueberry committed Aug 16, 2021
1 parent 346f528 commit 02f098d
Show file tree
Hide file tree
Showing 6 changed files with 96 additions and 118 deletions.
18 changes: 10 additions & 8 deletions RaisedGardenBeds/AssetManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,19 @@ public class AssetManager : IAssetLoader, IAssetEditor
{
private readonly IModHelper _helper;

internal static readonly string AssetPrefix = Path.Combine("Mods", "blueberry.rgb.Assets");
internal static readonly string GameContentAssetPath = Path.Combine("Mods", "blueberry.rgb.Assets");

internal static readonly string GameContentEndOfNightSpritesPath = Path.Combine(AssetPrefix, "EndOfNightSprites");
internal static readonly string GameContentEventDataPath = Path.Combine(AssetPrefix, "EventData");
internal static readonly string GameContentCommonTranslationDataPath = Path.Combine(AssetPrefix, "CommonTranslations");
internal static readonly string GameContentItemTranslationDataPath = Path.Combine(AssetPrefix, "ItemTranslations");
internal static readonly string GameContentEndOfNightSpritesPath = Path.Combine(GameContentAssetPath, "EndOfNightSprites");
internal static readonly string GameContentEventDataPath = Path.Combine(GameContentAssetPath, "EventData");
internal static readonly string GameContentCommonTranslationDataPath = Path.Combine(GameContentAssetPath, "CommonTranslations");
internal static readonly string GameContentItemTranslationDataPath = Path.Combine(GameContentAssetPath, "ItemTranslations");

internal static readonly string LocalEndOfNightSpritesPath = Path.Combine("assets", "endOfNightSprites.png");
internal static readonly string LocalEventDataPath = Path.Combine("assets", "eventData.json");
internal static readonly string LocalAssetPath = "assets";

internal static readonly string ContentPackPath = Path.Combine("assets", "ContentPack");
internal static readonly string LocalEndOfNightSpritesPath = Path.Combine(LocalAssetPath, "endOfNightSprites.png");
internal static readonly string LocalEventDataPath = Path.Combine(LocalAssetPath, "eventData.json");

internal static readonly string ContentPackPath = Path.Combine(LocalAssetPath, "ContentPack");


public AssetManager(IModHelper helper)
Expand Down
92 changes: 12 additions & 80 deletions RaisedGardenBeds/HarmonyPatches.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
using StardewValley;
using StardewValley.Menus;
using System;
using System.Collections.Generic;
using System.Linq;

namespace RaisedGardenBeds
Expand Down Expand Up @@ -42,57 +41,16 @@ internal static void Patch(string id)
harmony.Patch(
original: AccessTools.Method(typeof(CraftingPage), "clickCraftingRecipe"),
prefix: new HarmonyMethod(typeof(HarmonyPatches), nameof(CraftingPage_ClickCraftingRecipe_Prefix)));
/*
harmony.Patch(
original: AccessTools.Method(typeof(CraftingRecipe), "drawMenuView"),
postfix: new HarmonyMethod(typeof(HarmonyPatches), nameof(CraftingRecipe_DrawMenuView_Postfix)));
*/

// DISPLAY NAME TRANSPILER
/*
var sub = AccessTools.Constructor(type: typeof(CraftingRecipe), parameters: new Type[] { typeof(string), typeof(bool) });
var dom = new HarmonyMethod(typeof(HarmonyPatches), nameof(Transpile_CraftingRecipeConstructor));
harmony.Patch(
original: sub,
transpiler: dom
);
*/
}

private static void ErrorHandler(Exception e)
{
Log.E($"{ModEntry.Instance.ModManifest.UniqueID} failed in harmony prefix.{Environment.NewLine}{e}");
}
/*
public static IEnumerable<CodeInstruction> Transpile_CraftingRecipeConstructor(ILGenerator gen, MethodBase original, IEnumerable<CodeInstruction> instructions)
{
foreach (CodeInstruction i in instructions)
{
if (i.opcode != OpCodes.Call || !(i.operand is MethodInfo method && method.Name == "get_CurrentLanguageCode"))
{
yield return i;
}
else
{
// Original: Call LocalizedContentManager.get_CurrentLanguageCode()
// Goal: Call HarmonyPatches.CheckDisplayName(int, bool)
yield return new CodeInstruction(OpCodes.Ldloc_1, null) { labels = i.labels }; // infoSplit
yield return new CodeInstruction(OpCodes.Ldlen, null); // Length
yield return new CodeInstruction(OpCodes.Conv_I4, null); // (int)
yield return new CodeInstruction(OpCodes.Ldarg_2, null); // isCookingRecipe
yield return new CodeInstruction(OpCodes.Call, AccessTools.Method(typeof(HarmonyPatches), nameof(CheckDisplayName)));
}
}
}
public static int CheckDisplayName(int infoSplitLength, bool isCookingRecipe)
{
return infoSplitLength < (isCookingRecipe ? 5 : 6) ? 0 : 1;
Log.E($"{ModEntry.Instance.ModManifest.UniqueID} failed in harmony patch method.{Environment.NewLine}{e}");
}
*/

/// <summary>
/// Replace logic determining item drop-in actions on garden bed objects.
/// </summary>
public static bool Utility_IsThereAnObjectHereWhichAcceptsThisItem_Prefix(
ref bool __result,
GameLocation location,
Expand Down Expand Up @@ -123,6 +81,9 @@ public static bool Utility_IsThereAnObjectHereWhichAcceptsThisItem_Prefix(
return true;
}

/// <summary>
/// Add logic to consider new conditions for planting seeds in garden bed objects.
/// </summary>
public static bool Utility_IsViableSeedSpot_Prefix(
GameLocation location,
Vector2 tileLocation,
Expand All @@ -132,11 +93,7 @@ public static bool Utility_IsViableSeedSpot_Prefix(
{
if (location.Objects.TryGetValue(tileLocation, out StardewValley.Object o) && o != null && o is OutdoorPot op)
{
if (OutdoorPot.CanAcceptItemOrSeed(item) && OutdoorPot.CanAcceptSeed(item: item, op: op) && OutdoorPot.CanAcceptAnything(op: op))
{
return true;
}
return false;
return OutdoorPot.CanAcceptItemOrSeed(item) && OutdoorPot.CanAcceptSeed(item: item, op: op) && OutdoorPot.CanAcceptAnything(op: op);
}
}
catch (Exception e)
Expand All @@ -146,6 +103,9 @@ public static bool Utility_IsViableSeedSpot_Prefix(
return true;
}

/// <summary>
/// Replace logic for garden bed objects being watered by sprinklers.
/// </summary>
public static bool Object_ApplySprinkler_Prefix(
GameLocation location,
Vector2 tile)
Expand Down Expand Up @@ -266,33 +226,5 @@ public static bool CraftingPage_ClickCraftingRecipe_Prefix(
}
return true;
}
/*
/// <summary>
///
/// </summary>
public static void CraftingRecipe_DrawMenuView_Postfix(
CraftingRecipe __instance,
Microsoft.Xna.Framework.Graphics.SpriteBatch b,
int x,
int y,
float layerDepth)
{
if (__instance.name.StartsWith(OutdoorPot.GenericName))
{
string variantKey = OutdoorPot.GetVariantKeyFromName(name: __instance.name);
Utility.drawWithShadow(
b,
texture: ModEntry.Sprites[ModEntry.ItemDefinitions[variantKey].SpriteKey],
position: new Vector2(x, y),
sourceRect: OutdoorPot.GetSourceRectangle(spriteIndex: ModEntry.ItemDefinitions[variantKey].SpriteIndex),
color: Color.White,
rotation: 0f,
origin: Vector2.Zero,
scale: Game1.pixelZoom,
flipped: false,
layerDepth: layerDepth);
}
}
*/
}
}
12 changes: 6 additions & 6 deletions RaisedGardenBeds/ItemDefinition.cs
Original file line number Diff line number Diff line change
Expand Up @@ -98,12 +98,12 @@ internal static string ParseRecipeIngredients(ItemDefinition data)
List<string> ingredients = new List<string>();
foreach (Dictionary<string, string> entry in data.RecipeIngredients)
{
int id = int.TryParse(entry["Object"], out int rawId)
// Base game objects must be referenced by ID
? rawId
// Json Assets objects may be referenced by name
: Game1.objectInformation.Keys.FirstOrDefault
(key => key >= 2000 && Game1.objectInformation[key].Split('/')[0] == entry["Object"]);
string strId = entry["Object"];
int id = int.TryParse(strId, out int intId)
// Base game objects may be referenced by ID
? intId
// Base and Json Assets objects may be referenced by name
: Utility.fuzzyItemSearch(query: strId)?.ParentSheetIndex ?? -1;
int quantity = int.Parse(entry["Count"]);
ingredients.Add($"{id} {quantity}");
}
Expand Down
56 changes: 50 additions & 6 deletions RaisedGardenBeds/OutdoorPot.cs
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,9 @@ private void Event_VariantKeyChanged(NetString field, string oldValue, string ne
}
}

/// <summary>
/// Get a KeyValuePair containing the sprite key and index to be used with the common <see cref="ModEntry.Sprites"/> spritesheet.
/// </summary>
public static KeyValuePair<string, int> GetSpriteFromVariantKey(string variantKey)
{
return new KeyValuePair<string, int>(ModEntry.ItemDefinitions[variantKey].SpriteKey, ModEntry.ItemDefinitions[variantKey].SpriteIndex);
Expand Down Expand Up @@ -266,16 +269,25 @@ public static string GetDisplayNameFromRecipeName(string recipeName)
return OutdoorPot.GetDisplayNameFromName(recipeName.Split('.').Last());
}

/// <summary>
/// Get shared localised description for garden bed objects.
/// </summary>
public static string GetRawDescription()
{
return Translations.GetTranslation($"item.description{(ModEntry.Config.CanBePlacedInBuildings ? ".indoors" : "")}");
}

/// <summary>
/// Get localised display name for this object variant.
/// </summary>
protected override string loadDisplayName()
{
return OutdoorPot.GetDisplayNameFromVariantKey(this.VariantKey.Value);
}

/// <summary>
/// Get localised description string to fit object hovered-in-inventory popout box.
/// </summary>
public override string getDescription()
{
string description = OutdoorPot.GetRawDescription();
Expand Down Expand Up @@ -460,7 +472,7 @@ public override void ApplySprinklerAnimation(GameLocation location)

Vector2 position = (this.TileLocation * Game1.tileSize) - new Vector2(0, this.SoilHeightAboveGround * Game1.pixelZoom);
int delay = Game1.random.Next(1000);
float id = (this.tileLocation.X * 4000) + this.tileLocation.Y;
float id = (this.TileLocation.X * 4000) + this.TileLocation.Y;
Color colour = Color.White * 0.4f;
const int frames = 4;
const int interval = 60;
Expand Down Expand Up @@ -821,13 +833,20 @@ public static bool CanAcceptSeed(Item item, OutdoorPot op)
{
return op.hoeDirt.Value.canPlantThisSeedHere(item.ParentSheetIndex, (int)op.TileLocation.X, (int)op.TileLocation.Y);
}


/// <summary>
/// Set this object's held object to a given item.
/// </summary>
public void HoldItem(Item item)
{
this.heldObject.Value = item.getOne() as StardewValley.Object;
this.heldObject.Value.TileLocation = this.TileLocation;
}

/// <summary>
///
/// </summary>
/// <param name="force">If true, ejects the held object as debris regardless of any other conditions.</param>
public bool PopHeldItem(bool force = false)
{
bool popped = false;
Expand Down Expand Up @@ -859,22 +878,36 @@ public bool PopHeldItem(bool force = false)
return popped || (this.hoeDirt.Value.crop == null && this.heldObject.Value == null);
}

/// <summary>
/// Check whether this object's held object is a sprinkler.
/// </summary>
public bool IsHoldingSprinkler()
{
return this.heldObject.Value != null && this.heldObject.Value.IsSprinkler();
}

/// <summary>
/// Get the current radius for this object's held sprinkler, if any. Returns -1 if none is held.
/// </summary>
public int GetSprinklerRadius()
{
return this.IsHoldingSprinkler() ? this.heldObject.Value.GetModifiedRadiusForSprinkler() : -1;
}

/// <summary>
/// Water the garden bed's hoe dirt and any held crops.
/// </summary>
public void Water()
{
this.hoeDirt.Value.state.Value = 1;
this.showNextIndex.Value = this.hoeDirt.Value.state.Value == 1;
}

/// <summary>
///
/// </summary>
/// <param name="location"></param>
/// <param name="adjust"></param>
public void Unbreak(GameLocation location = null, bool adjust = false)
{
this.BreakageTimer.Value = this.BreakageStart;
Expand Down Expand Up @@ -937,9 +970,13 @@ public static void ArrangeAll(GameLocation specificLocation = null)
location.Objects.Values.OfType<OutdoorPot>().ToList().ForEach(o => o.Arrange(location: location));
}

/// <summary>
/// Considers neighbouring objects and sets this object's corner sprites to tile/tesselate/pattern with its neighbours to form arrangements.
/// </summary>
/// <param name="location">Specific location whose <see cref="StardewValley.GameLocation.Objects"/> dictionary contains this object.</param>
public void Arrange(GameLocation location)
{
if (!this.CanBeArranged)
if (!this.CanBeArranged || location == null)
return;

for (int i = 0; i < 4; ++i)
Expand All @@ -964,13 +1001,17 @@ public void Arrange(GameLocation location)
}
}

public static void ArrangeWithNeighbours(GameLocation location, Vector2 tileLocation, int radius = 1)
/// <summary>
/// Identifies any garden bed objects on the given tile and tries to reform arrangements with neighbouring objects.
/// </summary>
/// <param name="location">Specific location to check within. Defaults to player's current location.</param>
/// <param name="tileLocation">Tile location to check for objects.</param>
public static void ArrangeWithNeighbours(GameLocation location, Vector2 tileLocation)
{
if (location == null)
location = Game1.currentLocation;
if (radius < 1)
return;

const int radius = 1;
Point origin = Utility.Vector2ToPoint(tileLocation);
Point start = new Point(
Math.Max(0, origin.X - radius),
Expand All @@ -992,6 +1033,9 @@ public static void ArrangeWithNeighbours(GameLocation location, Vector2 tileLoca
}
}

/// <summary>
/// Whether any two objects are garden beds that can be grouped into arrangements.
/// </summary>
private static bool CanBeArrangedWithNeighbour(OutdoorPot p, StardewValley.Object o)
{
bool facts = o is OutdoorPot op && op != null && op.canStackWith(p) && !op.IsBroken && op.CanBeArranged && p.CanBeArranged;
Expand Down
2 changes: 1 addition & 1 deletion RaisedGardenBeds/manifest.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"Name": "Raised Garden Beds",
"Author": "blueberry",
"Version": "1.0.0-prerelease.5",
"Version": "1.0.0",
"Description": "Garden beds for your farm, usable outdoors with seasonal crops.",
"UniqueID": "blueberry.RaisedGardenBeds",
"EntryDll": "RaisedGardenBeds.dll",
Expand Down
Loading

0 comments on commit 02f098d

Please sign in to comment.