22using System ;
33using System . Collections . Generic ;
44using System . Linq ;
5+ using System . IO ;
6+ using System . Text ;
7+ using System . Diagnostics ;
58using UnityEngine ;
69
710namespace PartInfoInPAW
811{
912 public class ModulePartInfoInPAW : PartModule
1013 {
14+ #region GUI: Fields
15+
1116 [ KSPField ( isPersistant = true ) ]
1217 public bool showTWR = true ;
1318
@@ -21,7 +26,7 @@ public class ModulePartInfoInPAW : PartModule
2126 public string partName = "" ;
2227
2328 [ KSPField ( isPersistant = false , guiActiveEditor = true , guiActive = false , guiName = "#LOC_PartInfoInPAW_PartMod_Title" , groupName = "partInfo" , groupDisplayName = "#LOC_PartInfoInPAW_PartInfo_GroupTitle" ) ]
24- public string partMod = "" ;
29+ public string partModName = "" ;
2530
2631 [ KSPField ( isPersistant = false , guiActiveEditor = false , guiActive = false , guiName = "#LOC_PartInfoInPAW_PartCFGPath_Title" , groupName = "partInfo" , groupDisplayName = "#LOC_PartInfoInPAW_PartInfo_GroupTitle" ) ]
2732 public string partCFGPath = "" ;
@@ -50,33 +55,143 @@ public class ModulePartInfoInPAW : PartModule
5055 [ KSPField ( isPersistant = false , guiActiveEditor = true , guiActive = false , guiName = "#LOC_PartInfoInPAW_Info_Title" , groupName = "engine2Info" , groupDisplayName = "#LOC_PartInfoInPAW_Engine2Info_GroupTitle" ) ]
5156 public string engine2Info = "" ;
5257
58+ #endregion GUI: Fields
59+
60+ #region GUI: Buttons
61+
5362 [ KSPEvent ( guiActive = false , guiActiveEditor = true , guiName = "#LOC_PartInfoInPAW_CopyPartName_Action" , active = true , groupName = "partInfo" , groupDisplayName = "#LOC_PartInfoInPAW_PartInfo_GroupTitle" ) ]
5463 public void CopyPartName ( )
5564 {
56- if ( partName == "" )
65+ try
5766 {
58- partName = GetPartName ( ) ;
67+ if ( partName == "" )
68+ {
69+ partName = GetPartName ( ) ;
70+ }
71+ GUIUtility . systemCopyBuffer = partName ;
72+ Utils . Log ( $ "Part { part . partInfo . name } : ID copied to clipboard") ;
73+ Utils . OnScreenMsg ( Localizer . Format ( "#LOC_PartInfoInPAW_CopyToClipboard_PartID_SuccessMsg" , partName ) , 2.0f ) ;
74+ }
75+ catch ( Exception e )
76+ {
77+ Utils . LogError ( $ "Part { part . partInfo . name } : failed to copy part ID to clipboard: " + e . Message ) ;
78+ Utils . OnScreenMsg ( Localizer . Format ( "#LOC_PartInfoInPAW_CopyToClipboard_PartID_FailureMsg" , partName ) ) ;
5979 }
60- GUIUtility . systemCopyBuffer = partName ;
61- Debug . Log ( String . Format ( $ "[PartInfoInPAW] Part { part . partInfo . name } : ID copied to clipboard") ) ;
62- ScreenMessages . PostScreenMessage ( new ScreenMessage (
63- Localizer . Format ( "#LOC_PartInfoInPAW_CopyToClipboardMsg_PartID_Success" , partName ) ,
64- 2.0f , ScreenMessageStyle . UPPER_CENTER ) ) ;
6580 }
6681
6782 [ KSPEvent ( guiActive = false , guiActiveEditor = true , guiName = "#LOC_PartInfoInPAW_CopyPartNode_Action" , active = true , groupName = "partInfo" , groupDisplayName = "#LOC_PartInfoInPAW_PartInfo_GroupTitle" ) ]
6883 public void CopyPartConfigNode ( )
6984 {
70- GUIUtility . systemCopyBuffer = GetConfigNodeText ( ) ;
85+ string partCFG ;
86+ try
87+ {
88+ partCFG = GetConfigNodeText ( ) ;
89+ }
90+ catch ( Exception e )
91+ {
92+ Utils . LogError ( e . Message ) ;
93+ Utils . OnScreenMsg ( Localizer . Format ( "#LOC_PartInfoInPAW_GetNode_PartCFG_FailureMsg" , partName ) ) ;
94+ return ;
95+ }
96+ try
97+ {
98+ GUIUtility . systemCopyBuffer = partCFG ;
99+ Utils . Log ( $ "Part { part . partInfo . name } : CFG node copied to clipboard") ;
100+ Utils . OnScreenMsg ( Localizer . Format ( "#LOC_PartInfoInPAW_CopyToClipboard_PartCFG_SuccessMsg" , partName ) , 2.0f ) ;
101+ }
102+ catch ( Exception e )
103+ {
104+ Utils . LogError ( $ "Part { part . partInfo . name } : failed to copy CFG node to clipboard: " + e . Message ) ;
105+ Utils . OnScreenMsg ( Localizer . Format ( "#LOC_PartInfoInPAW_CopyToClipboard_PartCFG_FailureMsg" , partName ) ) ;
106+ }
71107 }
72108
109+ [ KSPEvent ( guiActive = false , guiActiveEditor = true , guiName = "#LOC_PartInfoInPAW_OpenPartCFGInEditor_Action" , active = true , groupName = "partInfo" , groupDisplayName = "#LOC_PartInfoInPAW_PartInfo_GroupTitle" ) ]
110+ public void OpenPartCFGInEditor ( )
111+ {
112+ string partCFG ;
113+ try
114+ {
115+ partCFG = GetConfigNodeText ( ) ;
116+ }
117+ catch ( Exception e )
118+ {
119+ Utils . LogError ( e . Message ) ;
120+ Utils . OnScreenMsg ( Localizer . Format ( "#LOC_PartInfoInPAW_GetNode_PartCFG_FailureMsg" , partName ) ) ;
121+ return ;
122+ }
123+ string fileName = partName ;
124+ if ( fileName == "" )
125+ {
126+ fileName = GetPartName ( ) ;
127+ }
128+ foreach ( var c in Path . GetInvalidFileNameChars ( ) )
129+ {
130+ fileName = fileName . Replace ( c , '-' ) ;
131+ }
132+ string filePath = Path . Combine ( Path . GetTempPath ( ) , Process . GetCurrentProcess ( ) . Id . ToString ( ) + "_" + fileName + ".cfg" ) ;
133+ if ( ! File . Exists ( filePath ) )
134+ {
135+ try
136+ {
137+ File . WriteAllText ( filePath , partCFG , Encoding . UTF8 ) ;
138+ }
139+ catch ( Exception e )
140+ {
141+ Utils . LogError ( $ "Could not write part CFG to file { filePath } : " + e . Message ) ;
142+ Utils . OnScreenMsg ( Localizer . Format ( "#LOC_PartInfoInPAW_CantWriteToTempFile_PartCFG_FailureMsg" , filePath ) ) ;
143+ return ;
144+ }
145+ }
146+ Utils . ShellOpenFile ( filePath ) ;
147+ }
148+
149+ [ KSPEvent ( guiActive = false , guiActiveEditor = true , guiName = "#LOC_PartInfoInPAW_CopyOrigPartNode_Action" , active = true , groupName = "partInfo" , groupDisplayName = "#LOC_PartInfoInPAW_PartInfo_GroupTitle" ) ]
150+ public void CopyOrigPartConfigNode ( )
151+ {
152+ string origFilePath = Utils . GetPartFilePath ( part ) ;
153+ string origFileContent ;
154+ try
155+ {
156+ origFileContent = File . ReadAllText ( origFilePath ) ;
157+ }
158+ catch ( Exception e )
159+ {
160+ Utils . LogError ( $ "Could not read part CFG file { origFilePath } : " + e . Message ) ;
161+ Utils . OnScreenMsg ( Localizer . Format ( "#LOC_PartInfoInPAW_OpenFile_PartOrigFile_FailureMsg" , origFilePath ) ) ;
162+ return ;
163+ }
164+ try
165+ {
166+ GUIUtility . systemCopyBuffer = origFileContent ;
167+ Utils . Log ( $ "Part { part . partInfo . name } : CFG file { origFilePath . Replace ( '\\ ' , '/' ) } copied to clipboard") ;
168+ Utils . OnScreenMsg ( Localizer . Format ( "#LOC_PartInfoInPAW_CopyToClipboard_PartOrigFile_SuccessMsg" , partName ) , 2.0f ) ;
169+ }
170+ catch ( Exception e )
171+ {
172+ Utils . LogError ( $ "Part { part . partInfo . name } : failed to copy original CFG file to clipboard: " + e . Message ) ;
173+ Utils . OnScreenMsg ( Localizer . Format ( "#LOC_PartInfoInPAW_CopyToClipboard_PartOrigFile_FailureMsg" , partName ) ) ;
174+ }
175+ }
176+
177+ [ KSPEvent ( guiActive = false , guiActiveEditor = true , guiName = "#LOC_PartInfoInPAW_OpenOrigPartCFGInEditor_Action" , active = true , groupName = "partInfo" , groupDisplayName = "#LOC_PartInfoInPAW_PartInfo_GroupTitle" ) ]
178+ public void OpenOrigPartCFGInEditor ( )
179+ {
180+ Utils . ShellOpenFile ( Utils . GetPartFilePath ( part ) ) ;
181+ }
182+
183+ #endregion GUI: Buttons
184+
185+
73186 protected ModuleEngines engine1 ;
74187 protected ModuleEngines engine2 ;
75188
76- public struct ModWithComplexFoldersStruct
189+ protected bool InfoUpdated = false ;
190+
191+ public readonly struct ModWithComplexFoldersStruct
77192 {
78- private string ModFolder ;
79- private int NestingLevel ;
193+ private readonly string ModFolder ;
194+ private readonly int NestingLevel ;
80195
81196 public ModWithComplexFoldersStruct ( string folder , int nestLevel = 2 )
82197 {
@@ -113,16 +228,14 @@ public string BuildModName(string url)
113228 }
114229 }
115230
116- protected List < ModWithComplexFoldersStruct > ModsWithComplexFoldersStruct = new List < ModWithComplexFoldersStruct > ( )
231+ protected static List < ModWithComplexFoldersStruct > ModsWithComplexFoldersStruct = new List < ModWithComplexFoldersStruct > ( )
117232 {
118233 new ModWithComplexFoldersStruct ( "SquadExpansion" ) ,
119234 new ModWithComplexFoldersStruct ( "UmbraSpaceIndustries" ) ,
120235 new ModWithComplexFoldersStruct ( "WildBlueIndustries" ) ,
121236 new ModWithComplexFoldersStruct ( "Bluedog_DB" , 3 ) ,
122237 } ;
123238
124- protected bool InfoUpdated = false ;
125-
126239 private void Start ( )
127240 {
128241 GameEvents . onEditorShipModified . Add ( EditorShipModified ) ;
@@ -161,9 +274,9 @@ private void UpdateInfo()
161274 {
162275 partName = GetPartName ( ) ;
163276 }
164- if ( partMod == "" )
277+ if ( partModName == "" )
165278 {
166- partMod = GetPartMod ( ) ;
279+ partModName = GetPartModName ( ) ;
167280 }
168281 ModuleEngines [ ] engines ;
169282 MultiModeEngine [ ] isMultimode ;
@@ -177,13 +290,13 @@ private void UpdateInfo()
177290 {
178291 // Dry mass only
179292 Fields [ "partMass" ] . guiName = Localizer . Format ( "#LOC_PartInfoInPAW_PartDryMass_Title" ) ;
180- partMass = FormatMass ( dryMass ) ;
293+ partMass = Utils . FormatMass ( dryMass ) ;
181294 }
182295 else
183296 {
184297 // Dry mass / wet mass
185298 Fields [ "partMass" ] . guiName = Localizer . Format ( "#LOC_PartInfoInPAW_PartDryWetMass_Title" ) ;
186- partMass = FormatMass ( dryMass ) + " / " + FormatMass ( wetMass ) ;
299+ partMass = Utils . FormatMass ( dryMass ) + " / " + Utils . FormatMass ( wetMass ) ;
187300 }
188301
189302 partCost = part . partInfo . cost + part . GetModuleCosts ( part . partInfo . cost ) ;
@@ -234,20 +347,6 @@ private void UpdateInfo()
234347 InfoUpdated = true ;
235348 }
236349
237- private string FormatMass ( float mass )
238- {
239- string result ;
240- if ( mass < 1.0f )
241- {
242- result = ( mass * 1000.0f ) . ToString ( "F0" ) + " " + Localizer . Format ( "#LOC_PartInfoInPAW_Kg_Unit" ) ;
243- }
244- else
245- {
246- result = mass . ToString ( "F3" ) + " " + Localizer . Format ( "#LOC_PartInfoInPAW_T_Unit" ) ;
247- }
248- return result ;
249- }
250-
251350 private string GetPartName ( )
252351 {
253352 string pName = "" ;
@@ -256,14 +355,14 @@ private string GetPartName()
256355 pName = GameDatabase . Instance . GetConfigs ( "PART" ) .
257356 Single ( c => part . partInfo . name . Replace ( '_' , '.' ) == c . name . Replace ( '_' , '.' ) ) . name ;
258357 }
259- catch ( Exception )
358+ catch ( Exception e )
260359 {
261- Debug . LogError ( String . Format ( $ "[PartInfoInPAW] Couldn't get config value name for part { part . partInfo . name } " ) ) ;
360+ Utils . LogError ( $ " Couldn't get config value name for part { part . partInfo . name } : " + e . Message ) ;
262361 }
263362 return pName ;
264363 }
265364
266- private string GetPartMod ( )
365+ private string GetPartModName ( )
267366 {
268367 string url = part . partInfo . partUrl ;
269368 foreach ( var mod in ModsWithComplexFoldersStruct )
@@ -278,49 +377,29 @@ private string GetPartMod()
278377
279378 private string GetConfigNodeText ( )
280379 {
281- string node = "" ;
380+ ConfigNode cfg ;
282381 try
283382 {
284- ConfigNode cfg = GameDatabase . Instance . GetConfigNode ( part . partInfo . partUrl ) ;
285- if ( cfg == null )
286- {
287- cfg = part . partInfo . partConfig ;
288- }
289- if ( cfg != null )
290- {
291- node = cfg . ToString ( ) ;
292- if ( cfg != null && ! cfg . HasValue ( "name" ) && ( partName != "" ) )
293- {
294- node = ReplaceFirstOccurrence ( node , "{" , "{" + $ "{ Environment . NewLine } \t name = { partName } ") ;
295- Debug . Log ( String . Format ( $ "[PartInfoInPAW] Part { part . partInfo . name } : CFG node copied to clipboard") ) ;
296- ScreenMessages . PostScreenMessage ( new ScreenMessage (
297- Localizer . Format ( "#LOC_PartInfoInPAW_CopyToClipboardMsg_PartCFG_Success" , partName ) ,
298- 2.0f , ScreenMessageStyle . UPPER_CENTER ) ) ;
299- }
300- }
301- else
383+ cfg = GameDatabase . Instance . GetConfigNode ( part . partInfo . partUrl ) ?? part . partInfo . partConfig ;
384+ }
385+ catch ( Exception e )
386+ {
387+ throw new Exception ( $ "Couldn't get config node for part { part . partInfo . name } : " + e . Message ) ;
388+ }
389+ string nodeText ;
390+ if ( cfg != null )
391+ {
392+ nodeText = cfg . ToString ( ) ;
393+ if ( cfg != null && ! cfg . HasValue ( "name" ) && ( partName != "" ) )
302394 {
303- Debug . LogError ( String . Format ( $ "[PartInfoInPAW] Couldn't get config node for part { part . partInfo . name } ") ) ;
304- ScreenMessages . PostScreenMessage ( new ScreenMessage (
305- Localizer . Format ( "#LOC_PartInfoInPAW_CopyToClipboardMsg_PartCFG_Failure" , partName ) ,
306- 3.0f , ScreenMessageStyle . UPPER_CENTER ) ) ;
395+ nodeText = Utils . ReplaceFirstOccurrence ( nodeText , "{" , "{" + $ "{ Environment . NewLine } \t name = { partName } ") ;
307396 }
308397 }
309- catch ( Exception )
398+ else
310399 {
311- Debug . LogError ( String . Format ( $ "[PartInfoInPAW] Couldn't get config node for part { part . partInfo . name } ") ) ;
312- ScreenMessages . PostScreenMessage ( new ScreenMessage (
313- Localizer . Format ( "#LOC_PartInfoInPAW_CopyToClipboardMsg_PartCFG_Failure" , partName ) ,
314- 3.0f , ScreenMessageStyle . UPPER_CENTER ) ) ;
400+ throw new Exception ( $ "Couldn't get config node for part { part . partInfo . name } : CFG node is null for some reason") ;
315401 }
316- return node ;
317- }
318-
319- public static string ReplaceFirstOccurrence ( string Source , string Find , string Replace )
320- {
321- int Place = Source . IndexOf ( Find ) ;
322- string result = Source . Remove ( Place , Find . Length ) . Insert ( Place , Replace ) ;
323- return result ;
402+ return nodeText ;
324403 }
325404
326405 public override string GetInfo ( )
@@ -342,10 +421,14 @@ public override string GetInfo()
342421 return Localizer . Format ( "#LOC_PartInfoInPAW_PartModuleInfo" , partName , partURL ) ;
343422 }
344423
424+ #region B9PartSwitch API
425+
345426 [ KSPEvent ]
346427 public void ModuleDataChanged ( BaseEventDetails details )
347428 {
348429 InfoUpdated = false ;
349430 }
431+
432+ #endregion B9PartSwitch API
350433 }
351434}
0 commit comments