Skip to content

Commit 3743f95

Browse files
committed
Update to v1.1.0
Added the speed of input consumption. Added Configuration to disable input speed and output speed separately.
1 parent 1b5d1d0 commit 3743f95

File tree

3 files changed

+213
-37
lines changed

3 files changed

+213
-37
lines changed

DSP_AssemblerUI/AssemblerSpeedUI/AssemblerSpeedUIMod.cs

Lines changed: 205 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using BepInEx;
2+
using BepInEx.Configuration;
23
using BepInEx.Logging;
34
using HarmonyLib;
45
using System;
@@ -17,27 +18,69 @@
1718
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
1819
namespace DSP_AssemblerUI.AssemblerSpeedUI
1920
{
20-
[BepInPlugin("dsp.assemblerUI.speedMod", "Assembler UI Speed Info Mod", "1.0.0.0")]
21+
public static class ModInfo
22+
{
23+
public const string ModID = "dsp.assemblerUI.speedMod";
24+
public const string ModName = "Assembler UI Speed Info Mod";
25+
public const string majorVersion = "1";
26+
public const string minorVersion = "1";
27+
public const string hotfixVersion = "0";
28+
public const string buildVersion = "0";
29+
public const string VersionString = majorVersion + "." + minorVersion + "." + hotfixVersion + "." + buildVersion;
30+
}
31+
32+
[BepInPlugin(ModInfo.ModID, ModInfo.ModName, ModInfo.VersionString)]
2133
public class AssemblerSpeedUIMod : BaseUnityPlugin
2234
{
2335
#region Main Plugin
36+
internal Harmony harmony;
37+
2438
public new static ManualLogSource Logger;
2539

40+
public static ConfigEntry<bool> configEnableOutputSpeeds;
41+
public static ConfigEntry<bool> configEnableInputSpeeds;
42+
2643
internal void Awake()
2744
{
28-
2945
//Adding the Logger
3046
Logger = new ManualLogSource("AssemblerSpeedUIMod");
3147
BepInEx.Logging.Logger.Sources.Add(Logger);
3248

33-
Harmony.CreateAndPatchAll(typeof(AssemblerSpeedUIMod));
49+
configEnableOutputSpeeds = Config.Bind("General", "EnableOutputSpeedInfo", true, "Enables the speed information below the output area in the Assembler Window.");
50+
configEnableInputSpeeds = Config.Bind("General", "EnableInputSpeedInfo", true, "Enables the speed information above the input area in the Assembler Window.");
51+
52+
harmony = new Harmony(ModInfo.ModID);
53+
try
54+
{
55+
harmony.PatchAll(typeof(AssemblerSpeedUIMod));
56+
}
57+
catch(Exception ex)
58+
{
59+
ErrorLog(ex.Message);
60+
ErrorLog(ex.StackTrace);
61+
}
62+
}
63+
64+
internal void OnDestroy()
65+
{
66+
harmony?.UnpatchSelf();
67+
68+
foreach(KeyValuePair<string, ItemSpeedInfoLabel> pair in speedInfos)
69+
{
70+
Destroy(pair.Value.gameObject);
71+
}
3472
}
3573

3674
[Conditional("DEBUG")]
3775
static void DebugLog(string logMessage)
3876
{
3977
Logger.LogDebug(logMessage);
4078
}
79+
80+
static void ErrorLog(string logMessage)
81+
{
82+
Logger.LogError(logMessage);
83+
}
4184
#endregion
4285

4386
#region Patcher
@@ -48,13 +91,18 @@ internal class ItemSpeedInfoLabel
4891
}
4992

5093
internal static Dictionary<string, ItemSpeedInfoLabel> speedInfos = new Dictionary<string, ItemSpeedInfoLabel>();
94+
internal static int speedInfosOutCount = 0;
95+
internal static int speedInfosInCount = 0;
5196

5297
static readonly string TEXT_PATH = "UI Root/Overlay Canvas/In Game/Windows/Assembler Window/produce/speed/speed-text";
5398

54-
public static readonly string[] itemKeys = { "assembler-speed-item0", "assembler-speed-item1", "assembler-speed-item2" };
99+
public const string outputKeyBase = "assembler-speed-out-item";
100+
public const string inputKeyBase = "assembler-speed-in-item";
55101

56-
public static float[][] xLookup = new float[][]{ new float[]{ -60f }, new float[]{ -125f, -60f }, new float[] { -190f, -125f, -60f } };
57-
public static Vector3? ogPos = null;
102+
public static readonly string[] itemOutputKeys = { outputKeyBase + "0", outputKeyBase + "1", outputKeyBase + "2" };
103+
public static readonly string[] itemInputKeys = { inputKeyBase + "0", inputKeyBase + "1", inputKeyBase + "2" };
104+
105+
public static Vector3? vanillaSpeedPos = null;
58106

59107
[HarmonyPostfix, HarmonyPatch(typeof(UIAssemblerWindow), "OnAssemblerIdChange")]
60108
public static void OnAssemblerIdChangePostfix(UIAssemblerWindow __instance)
@@ -68,41 +116,88 @@ public static void OnRecipePickerReturnPostfix(UIAssemblerWindow __instance)
68116
SetupLabels(__instance);
69117
}
70118

119+
/// <summary>
120+
/// Sets up all currently required and configured labels
121+
/// </summary>
122+
/// <param name="window">The UIAssemblerWindow for which the data shall be set up.</param>
71123
public static void SetupLabels(UIAssemblerWindow window)
72124
{
73-
int? productCount = window.factorySystem?.assemblerPool[window.assemblerId].products?.Length;
74-
if (!productCount.HasValue)
125+
//Output
126+
if (configEnableOutputSpeeds.Value)
75127
{
76-
return;
128+
int? productCount = window.factorySystem?.assemblerPool[window.assemblerId].products?.Length;
129+
if (productCount.HasValue)
130+
{
131+
SetupSidedLabels(productCount.Value, false);
132+
}
77133
}
78-
int loopCap = Math.Min(productCount.Value, itemKeys.Length);
134+
135+
//Input
136+
if (configEnableInputSpeeds.Value)
137+
{
138+
int? inputCount = window.factorySystem?.assemblerPool[window.assemblerId].requires?.Length;
139+
if (inputCount.HasValue)
140+
{
141+
SetupSidedLabels(inputCount.Value, true);
142+
}
143+
}
144+
}
145+
146+
/// <summary>
147+
/// Sets up the currently required labels for either input or output side
148+
/// </summary>
149+
/// <param name="itemCount">The number of items which currently need a label</param>
150+
/// <param name="isInput">Whether the labels are on the input or output side of the UI</param>
151+
public static void SetupSidedLabels(int itemCount, bool isInput)
152+
{
153+
string[] matchingKeys = isInput ? itemInputKeys : itemOutputKeys;
154+
int loopCap = Math.Min(itemCount, matchingKeys.Length);
79155

80156
for (int cnt = 0; cnt < loopCap; cnt++)
81157
{
82-
if (!speedInfos.ContainsKey(itemKeys[cnt]))
158+
if (!speedInfos.ContainsKey(matchingKeys[cnt]))
83159
{
84-
AddSpeedLabel(itemKeys[cnt], cnt, loopCap);
160+
AddSpeedLabel(matchingKeys[cnt], cnt, loopCap, isInput);
161+
if (isInput)
162+
{
163+
speedInfosInCount++;
164+
}
165+
else
166+
{
167+
speedInfosOutCount++;
168+
}
85169
}
86170
}
87171

88172
string perMinuteString = "每分钟".Translate();
173+
int matchingInfoCount = isInput ? speedInfosInCount : speedInfosOutCount;
89174

90-
for (int cnt2 = 0; cnt2 < speedInfos.Count; cnt2++)
175+
//Iterate only over the already created text labels for the side
176+
for (int cnt2 = 0; cnt2 < matchingInfoCount; cnt2++)
91177
{
92-
if (cnt2 < productCount)
178+
if (cnt2 < itemCount)
93179
{
94-
speedInfos[itemKeys[cnt2]].gameObject.SetActive(true);
95-
speedInfos[itemKeys[cnt2]].value.text = "0.0" + perMinuteString;
96-
PositionSpeedLabel(speedInfos[itemKeys[cnt2]].gameObject, cnt2, loopCap);
180+
//If it is a label that should be visible, set it up
181+
speedInfos[matchingKeys[cnt2]].gameObject.SetActive(true);
182+
speedInfos[matchingKeys[cnt2]].value.text = " 0.0" + perMinuteString;
183+
PositionSpeedLabel(speedInfos[matchingKeys[cnt2]].gameObject, cnt2, loopCap, isInput);
97184
}
98185
else
99186
{
100-
speedInfos[itemKeys[cnt2]].gameObject.SetActive(false);
187+
//If the label exists, but the current assembler doesn't use it, set it to inactive
188+
speedInfos[matchingKeys[cnt2]].gameObject.SetActive(false);
101189
}
102190
}
103191
}
104192

105-
public static void AddSpeedLabel(string id, int num, int ofNum)
193+
/// <summary>
194+
/// Adds and initalizes a new speed label when it is needed.
195+
/// </summary>
196+
/// <param name="id">The dictionary ID of the new label</param>
197+
/// <param name="num">Index of the new label (0-based)</param>
198+
/// <param name="ofNum">Count of total labels (max index + 1)</param>
199+
/// <param name="input">Whether the label is on the input or output side.</param>
200+
public static void AddSpeedLabel(string id, int num, int ofNum, bool input)
106201
{
107202
var originalDetailLabel = GameObject.Find(TEXT_PATH);
108203
if (originalDetailLabel == null)
@@ -122,15 +217,21 @@ public static void AddSpeedLabel(string id, int num, int ofNum)
122217
var textComponents = gameObject.GetComponentsInChildren<Text>();
123218
var value = textComponents[0];
124219

125-
if (!ogPos.HasValue)
220+
if (!vanillaSpeedPos.HasValue)
126221
{
127-
ogPos = originalDetailLabel.transform.localPosition;
222+
vanillaSpeedPos = originalDetailLabel.transform.localPosition;
128223
}
129224

130225
gameObject.transform.localScale = new Vector3(1f, 1f, 1f);
131-
PositionSpeedLabel(gameObject, num, ofNum);
226+
PositionSpeedLabel(gameObject, num, ofNum, input);
132227
gameObject.transform.right = originalDetailLabel.transform.right;
133228

229+
//Input area is smaller, decrease font size
230+
if (input)
231+
{
232+
value.fontSize -= 2;
233+
}
234+
134235
ItemSpeedInfoLabel newItemSpeedInfo = new ItemSpeedInfoLabel()
135236
{
136237
gameObject = gameObject,
@@ -139,32 +240,99 @@ public static void AddSpeedLabel(string id, int num, int ofNum)
139240
speedInfos.Add(id, newItemSpeedInfo);
140241
}
141242

142-
public static void PositionSpeedLabel(GameObject gameObject, int num, int ofNum)
243+
/// <summary>
244+
/// Sets the position of a given label.
245+
/// </summary>
246+
/// <param name="gameObject">The GameObject of the label to be moved.</param>
247+
/// <param name="num">Index of the label (0-based)</param>
248+
/// <param name="ofNum">Count of total labels (max index + 1)</param>
249+
/// <param name="input">Whether the label is on the input or output side.</param>
250+
public static void PositionSpeedLabel(GameObject gameObject, int num, int ofNum, bool input)
143251
{
144252

145253
DebugLog($"OgPosition:{gameObject.transform.localPosition}");
146-
Vector3 shiftVector = getPosShift(num, ofNum);
254+
Vector3 shiftVector = getPosShift(num, ofNum, input);
147255
DebugLog($"ShiftedBy:{shiftVector}");
148256

149-
gameObject.transform.localPosition = ogPos.Value + shiftVector;
257+
gameObject.transform.localPosition = vanillaSpeedPos.Value + shiftVector;
150258
}
151259

152-
public static Vector3 getPosShift(int num, int ofNum)
260+
/// <summary>
261+
/// Gets the Vector3 by which the label is shifted compared to the original speed label.
262+
/// </summary>
263+
/// <param name="num">Index of the label (0-based)</param>
264+
/// <param name="ofNum">Count of total labels (max index + 1)</param>
265+
/// <param name="input">Whether the label is on the input or output side.</param>
266+
/// <returns>The Vector3 by which the label shall be shifted</returns>
267+
public static Vector3 getPosShift(int num, int ofNum, bool input)
153268
{
154-
return new Vector3(xLookup[ofNum - 1][num], -50f, 0f);
269+
float yShift = input ? 25f : -50f;
270+
float xShift = getXShift(num, ofNum, input);
271+
272+
return new Vector3(xShift, yShift, 0f);
155273
}
156274

275+
/// <summary>
276+
/// Calculates the x-Shift of a Label, based on the label count and whether it's on the input or output side.
277+
/// </summary>
278+
/// <param name="num">Index of the label (0-based)</param>
279+
/// <param name="ofNum">Count of total labels (max index + 1)</param>
280+
/// <param name="input">Whether the label is on the input or output side.</param>
281+
/// <returns>The x-Shift of the label</returns>
282+
private static float getXShift(int num, int ofNum, bool input)
283+
{
284+
//based on:
285+
//float[][] xOutputLookup = new float[][] { new float[] { -60f }, new float[] { -125f, -60f }, new float[] { -190f, -125f, -60f } };
286+
//float[][] xInputLookup = new float[][] { new float[] { 74 }, new float[] { 74f, 125f }, new float[] { 74f, 125f, 176f } };
287+
if (input)
288+
{
289+
float baseX = 74f;
290+
float itemStep = 49f;
291+
return baseX + num * itemStep;
292+
}
293+
else
294+
{
295+
float baseX = -60f;
296+
float itemStep = -65f;
297+
return baseX + (ofNum - 1 - num) * itemStep;
298+
}
299+
}
300+
301+
/// <summary>
302+
/// Updates a singular label with the current speed data
303+
/// </summary>
304+
/// <param name="id">The Dict-ID of the label to update</param>
305+
/// <param name="value">The value which to write in the label</param>
157306
public static void UpdateSpeedLabel(string id, float value)
158307
{
159308
string perMinuteString = "每分钟".Translate();
160-
speedInfos[id].value.text = value.ToString("0.0") + perMinuteString;
309+
speedInfos[id].value.text = value.ToString("0.0").PadLeft(5) + perMinuteString;
161310
}
162311

163-
public static void UpdateSpeedLabels(float baseSpeed, int[] productCounts)
312+
/// <summary>
313+
/// Update all the labels for the given base speed, as well as inputs and outputs
314+
/// </summary>
315+
/// <param name="baseSpeed">The base speed (number of recipe runs per minute)</param>
316+
/// <param name="productCounts">The array with info how many items of each product are created each run</param>
317+
/// <param name="requireCounts">The array with info how many items of each input are consumed each run</param>
318+
public static void UpdateSpeedLabels(float baseSpeed, int[] productCounts, int[] requireCounts)
164319
{
165-
for(int cnt = 0; cnt < Math.Min(productCounts.Length, itemKeys.Length); cnt++)
320+
//Output
321+
if (configEnableOutputSpeeds.Value)
322+
{
323+
for (int cnt = 0; cnt < Math.Min(productCounts.Length, itemOutputKeys.Length); cnt++)
324+
{
325+
UpdateSpeedLabel(itemOutputKeys[cnt], productCounts[cnt] * baseSpeed);
326+
}
327+
}
328+
329+
//Input
330+
if (configEnableInputSpeeds.Value)
166331
{
167-
UpdateSpeedLabel(itemKeys[cnt], productCounts[cnt]*baseSpeed);
332+
for (int cnt = 0; cnt < Math.Min(requireCounts.Length, itemInputKeys.Length); cnt++)
333+
{
334+
UpdateSpeedLabel(itemInputKeys[cnt], requireCounts[cnt] * baseSpeed);
335+
}
168336
}
169337
}
170338

@@ -195,13 +363,17 @@ public static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstructio
195363
//ldloc.s 18
196364
//ldloca.s 0 //AssemblerComponent local var
197365
//ldfld int32[] AssemblerComponent::productCounts
366+
//ldloca.s 0 //AssemblerComponent local var
367+
//ldfld int32[] AssemblerComponent::requireCounts
198368
//call update
199369
//<-- endInsert
200370
DebugLog($"UiTextTranspiler Matcher Codes Count: {matcher.Instructions().Count}, Matcher Pos: {matcher.Pos}!");
201371
matcher.InsertAndAdvance(
202-
new CodeInstruction(OpCodes.Ldloc_S, (byte)18),
372+
new CodeInstruction(OpCodes.Ldloc_S, (byte)18), //Load base speed on stack
373+
new CodeInstruction(OpCodes.Ldloca_S, (byte)0),
374+
new CodeInstruction(OpCodes.Ldfld, typeof(AssemblerComponent).GetField("productCounts")), //load product counts array on stack
203375
new CodeInstruction(OpCodes.Ldloca_S, (byte)0),
204-
new CodeInstruction(OpCodes.Ldfld, typeof(AssemblerComponent).GetField("productCounts")),
376+
new CodeInstruction(OpCodes.Ldfld, typeof(AssemblerComponent).GetField("requireCounts")), //load require counts array on stack
205377
new CodeInstruction(OpCodes.Call, typeof(AssemblerSpeedUIMod).GetMethod("UpdateSpeedLabels"))
206378
);
207379

DSP_AssemblerUI/Properties/AssemblyInfo.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,5 +32,5 @@
3232
// Sie können alle Werte angeben oder Standardwerte für die Build- und Revisionsnummern verwenden,
3333
// indem Sie "*" wie unten gezeigt eingeben:
3434
// [assembly: AssemblyVersion("1.0.*")]
35-
[assembly: AssemblyVersion("1.0.0.0")]
36-
[assembly: AssemblyFileVersion("1.0.0.0")]
35+
[assembly: AssemblyVersion("1.1.0.0")]
36+
[assembly: AssemblyFileVersion("1.1.0.0")]

README.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
11
# DSPAssemblerUI
22
A Dyson Sphere Program Mod to enhance the Assembler UI Window.
33

4-
It shows the production speeds of the produced items below the corresponding item slots in the window.
5-
This way, you can plan your factory setup more easily without having to calculate your outputs yourself.
4+
It shows the production speeds of the produced items below the corresponding output slots in the window,
5+
as well as the consumption speed of the input items above the input slots.
6+
This way, you can plan your factory setup more easily without having to calculate your in- and outputs yourself.
67

8+
The speed info for both input and output can be disabled, should you prefer not showing one of them.
9+
Or both of them - even though I don't understand why you would install this mod in the first place then...
710

811

912
## Version History
1013
- v1.0.0 First Version. Shows Production Speeds below Items.
14+
- v1.1.0 Updated to also show input consumption speeds. Added configuration to enable/disable input and output speeds separately.

0 commit comments

Comments
 (0)