11using BepInEx ;
2+ using BepInEx . Configuration ;
23using BepInEx . Logging ;
34using HarmonyLib ;
45using System ;
1718[ assembly: SecurityPermission ( SecurityAction . RequestMinimum , SkipVerification = true ) ]
1819namespace 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
0 commit comments