-
Notifications
You must be signed in to change notification settings - Fork 45
/
WorkbenchPatch.cs
133 lines (118 loc) · 5.33 KB
/
WorkbenchPatch.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using Harmony;
using Microsoft.Xna.Framework;
using StardewValley;
using StardewValley.Locations;
using StardewValley.Menus;
using StardewValley.Network;
using StardewValley.Objects;
namespace BetterWorkbenches
{
/// <summary>Patches the workbench to find chests recursively.</summary>
[HarmonyPatch]
internal class WorkbenchPatch
{
/// <summary>Gets the method to patch.</summary>
/// <returns>The method to patch.</returns>
[SuppressMessage("ReSharper", "UnusedMember.Local", Justification = "Method names are defined by Harmony.")]
private static MethodBase TargetMethod()
{
return typeof(Workbench).GetMethod(nameof(Workbench.checkForAction));
}
/// <summary>The method to run before the original method.</summary>
/// <returns>Whether to run the original method or not.</returns>
[SuppressMessage("ReSharper", "UnusedMember.Local", Justification = "Method names are defined by Harmony.")]
private static bool Prefix(Farmer who, bool justCheckingForActivity, Workbench __instance, ref bool __result)
{
// This shouldn't ever throw an exception, but just in case, run the original method so workbenches can still be used if this mod fails.
try
{
__result = CheckForAction(__instance, who, justCheckingForActivity);
return false;
}
catch
{
return true;
}
}
private static Type multipleMutexRequestType;
private static MethodInfo releaseLocksMethod;
public static void GetTypes()
{
multipleMutexRequestType = Type.GetType("StardewValley.MultipleMutexRequest, StardewValley") ?? Type.GetType("StardewValley.MultipleMutexRequest, Stardew Valley");
releaseLocksMethod = multipleMutexRequestType.GetMethod("ReleaseLocks");
}
private static bool CheckForAction(Workbench workbench, Farmer who, bool justCheckingForActivity)
{
if (justCheckingForActivity)
{
return true;
}
if (workbench.mutex.IsLocked())
{
return true;
}
List<Chest> nearbyChests = new List<Chest>();
GetChests(workbench.TileLocation, who, nearbyChests);
NetMutex[] mutexes = nearbyChests.Select(chest => chest.mutex).ToArray();
object multipleMutexRequest = null;
void ReleaseLocks() => releaseLocksMethod.Invoke(multipleMutexRequest, new object[] { });
multipleMutexRequest = Activator.CreateInstance(multipleMutexRequestType, mutexes, (Action) (() => workbench.mutex.RequestLock((Action) (() =>
{
Vector2 centeringOnScreen = Utility.getTopLeftPositionForCenteringOnScreen(800 + IClickableMenu.borderWidth * 2, 600 + IClickableMenu.borderWidth * 2, 0, 0);
Game1.activeClickableMenu = (IClickableMenu) new CraftingPage((int) centeringOnScreen.X, (int) centeringOnScreen.Y, 800 + IClickableMenu.borderWidth * 2, 600 + IClickableMenu.borderWidth * 2, false, true, nearbyChests);
Game1.activeClickableMenu.exitFunction = (IClickableMenu.onExit) (() =>
{
workbench.mutex.ReleaseLock();
ReleaseLocks();
});
}), ReleaseLocks)), (Action) (() => Game1.showRedMessage(Game1.content.LoadString("Strings\\UI:Workbench_Chest_Warning"))));
return true;
}
private static void GetChests(Vector2 position, Farmer who, IList<Chest> nearbyChests)
{
// Only check cardinal directions for recursive chests, but all adjacent positions for the workbench (b/c vanilla does this).
List<Vector2> offsets = new List<Vector2>()
{
new Vector2(0.0f, 1f),
new Vector2(-1f, 0.0f),
new Vector2(1f, 0.0f),
new Vector2(0.0f, -1f)
};
if (nearbyChests.Count == 0)
{
offsets.AddRange(new []{
new Vector2(-1f, 1f),
new Vector2(1f, 1f),
new Vector2(-1f, -1f),
new Vector2(1f, -1f)
});
}
foreach (Vector2 offset in offsets)
{
Chest chest = null;
Vector2 key = new Vector2((int)(position.X + offset.X), (int)(position.Y + offset.Y));
if (who.currentLocation is FarmHouse farmHouse && who.currentLocation.getTileIndexAt((int)key.X, (int)key.Y, "Buildings") == 173)
{
chest = farmHouse.fridge.Value;
}
else
{
if (who.currentLocation.objects.TryGetValue(key, out StardewValley.Object obj) && obj is Chest foundChest)
chest = foundChest;
}
if (chest != null && !nearbyChests.Contains(chest))
{
nearbyChests.Add(chest);
GetChests(key, who, nearbyChests);
}
}
}
}
}