@@ -14,11 +14,18 @@ namespace ShipSaveSplicer
1414 public class ShipSaveSplicer : MonoBehaviour
1515 {
1616 public static ApplicationLauncherButton theButton ;
17- public static bool includeCrew = false ; //currently not working when true
17+ public static bool includeCrew = false ;
18+ private static bool EventAdded = false ;
1819 public void Start ( )
1920 {
2021 //add button to the Stock toolbar
21- AddButton ( ) ;
22+ if ( ! EventAdded )
23+ {
24+ GameEvents . onGUIApplicationLauncherReady . Add ( AddButton ) ;
25+ EventAdded = true ;
26+ }
27+
28+ //AddButton();
2229 }
2330
2431 public void OnDestroy ( )
@@ -50,6 +57,13 @@ public void OnClick()
5057 else
5158 includeCrew = false ;
5259
60+ if ( Input . GetKey ( KeyCode . LeftShift ) )
61+ {
62+ OpenConvertWindow ( ) ; //convert ships to craft files
63+ theButton . SetFalse ( ) ;
64+ return ;
65+ }
66+
5367 //get the selected craft
5468 Vessel selectedVessel = null ;
5569
@@ -101,6 +115,135 @@ public void ExportSelectedCraft(Vessel vessel)
101115 ScreenMessages . PostScreenMessage ( message ) ;
102116 }
103117
118+ public void OpenConvertWindow ( )
119+ {
120+ //convert the selected vessel to a craft file and save it in the ships folder for the save
121+ string dir = KSPUtil . ApplicationRootPath + "/Ships/export/" ;
122+ //provide a list of all the craft we can import
123+ string [ ] files = System . IO . Directory . GetFiles ( dir ) ;
124+ int count = files . Length ;
125+
126+ DialogGUIBase [ ] options = new DialogGUIBase [ count + 1 ] ;
127+ for ( int i = 0 ; i < count ; i ++ )
128+ {
129+ int select = i ;
130+ options [ i ] = new DialogGUIButton ( files [ i ] . Split ( '/' ) . Last ( ) , ( ) => { ConvertVessel ( files [ select ] ) ; } ) ;
131+ }
132+ options [ count ] = new DialogGUIButton ( "Close" , Dummy ) ;
133+ string msg = "Select a vessel to convert to a .craft file." ;
134+
135+ MultiOptionDialog a = new MultiOptionDialog ( msg , "Convert Vessel to .craft" , null , options ) ;
136+ PopupDialog . SpawnPopupDialog ( new Vector2 ( 0.5f , 0.5f ) , new Vector2 ( 0.5f , 0.5f ) , a , false , HighLogic . UISkin ) ;
137+ }
138+
139+ public void ConvertVessel ( string name )
140+ {
141+ if ( System . IO . File . Exists ( name ) )
142+ {
143+ ConfigNode storedNode = ConfigNode . Load ( name ) ;
144+
145+ ConfigNode vesselNode = storedNode . GetNode ( "VESSEL" ) ;
146+
147+ List < string > invalidParts = InvalidParts ( vesselNode ) ;
148+ if ( invalidParts . Count > 0 ) //contains invalid parts and can't be loaded
149+ {
150+ string msg = "The selected vessel cannot be converted because it contains the following invalid parts (perhaps you removed a mod?):\n " ;
151+ foreach ( string invalid in invalidParts )
152+ msg += " " + invalid + "\n " ;
153+ PopupDialog . SpawnPopupDialog ( new Vector2 ( 0.5f , 0.5f ) , new Vector2 ( 0.5f , 0.5f ) , "Missing Parts" , msg , "Ok" , false , HighLogic . UISkin ) ;
154+ return ;
155+ }
156+ //clear out all crew on vessel
157+ foreach ( ConfigNode partNode in vesselNode . GetNodes ( "PART" ) )
158+ {
159+ if ( partNode . HasValue ( "crew" ) )
160+ {
161+ partNode . RemoveValues ( "crew" ) ;
162+ }
163+ }
164+
165+ VesselToCraftFile ( vesselNode ) ;
166+
167+ }
168+ }
169+
170+ public void VesselToCraftFile ( ConfigNode VesselNode )
171+ {
172+ //This code is taken from InflightShipSave by Claw, using the CC-BY-NC-SA license.
173+ //This code thus is licensed under the same license, despite the GPLv3 license covering original KCT code
174+ //See https://github.com/ClawKSP/InflightShipSave
175+
176+ ProtoVessel VesselToSave = HighLogic . CurrentGame . AddVessel ( VesselNode ) ;
177+ if ( VesselToSave . vesselRef == null )
178+ {
179+ Debug . LogError ( "Vessel reference is null!" ) ;
180+ return ;
181+ }
182+
183+ try
184+ {
185+ string ShipName = VesselToSave . vesselName ;
186+ // Debug.LogWarning("Saving: " + ShipName);
187+
188+ //Vessel FromFlight = FlightGlobals.Vessels.Find(v => v.id == VesselToSave.vesselID);
189+ try
190+ {
191+ VesselToSave . vesselRef . Load ( ) ;
192+ }
193+ catch ( Exception ex )
194+ {
195+ Debug . LogException ( ex ) ;
196+ Debug . Log ( "Attempting to continue." ) ;
197+ }
198+
199+ ShipConstruct ConstructToSave = new ShipConstruct ( ShipName , "" , VesselToSave . vesselRef . Parts [ 0 ] ) ;
200+ Quaternion OriginalRotation = VesselToSave . vesselRef . vesselTransform . rotation ;
201+ Vector3 OriginalPosition = VesselToSave . vesselRef . vesselTransform . position ;
202+
203+ VesselToSave . vesselRef . SetRotation ( new Quaternion ( 0 , 0 , 0 , 1 ) ) ;
204+ Vector3 ShipSize = ShipConstruction . CalculateCraftSize ( ConstructToSave ) ;
205+ VesselToSave . vesselRef . SetPosition ( new Vector3 ( 0 , ShipSize . y + 2 , 0 ) ) ;
206+
207+
208+ ConfigNode CN = new ConfigNode ( "ShipConstruct" ) ;
209+ CN = ConstructToSave . SaveShip ( ) ;
210+ //SanitizeShipNode(CN);
211+ CleanEditorNodes ( CN ) ;
212+
213+ //VesselToSave.rotation = OriginalRotation;
214+ //VesselToSave.position = OriginalPosition;
215+
216+ if ( ConstructToSave . shipFacility == EditorFacility . SPH )
217+ {
218+ CN . Save ( UrlDir . ApplicationRootPath + "saves/" + HighLogic . SaveFolder
219+ + "/Ships/SPH/" + ShipName + "_Rescued.craft" ) ;
220+
221+ ScreenMessage message = new ScreenMessage ( ShipName + " converted to " + UrlDir . ApplicationRootPath + "saves/" + HighLogic . SaveFolder
222+ + "/Ships/SPH/" + ShipName + "_Rescued.craft" , 6 , ScreenMessageStyle . UPPER_CENTER ) ;
223+ ScreenMessages . PostScreenMessage ( message ) ;
224+ }
225+ else
226+ {
227+ CN . Save ( UrlDir . ApplicationRootPath + "saves/" + HighLogic . SaveFolder
228+ + "/Ships/VAB/" + ShipName + "_Rescued.craft" ) ;
229+
230+ ScreenMessage message = new ScreenMessage ( ShipName + " converted to " + UrlDir . ApplicationRootPath + "saves/" + HighLogic . SaveFolder
231+ + "/Ships/VAB/" + ShipName + "_Rescued.craft" , 6 , ScreenMessageStyle . UPPER_CENTER ) ;
232+ ScreenMessages . PostScreenMessage ( message ) ;
233+ }
234+ }
235+ catch ( Exception e )
236+ {
237+ Debug . LogException ( e ) ;
238+ }
239+ finally
240+ {
241+ HighLogic . CurrentGame . DestroyVessel ( VesselToSave . vesselRef ) ;
242+ VesselToSave . vesselRef . Die ( ) ;
243+ }
244+ //End of Claw's code. Thanks Claw!
245+ }
246+
104247 public void OpenImportWindow ( )
105248 {
106249 string dir = KSPUtil . ApplicationRootPath + "/Ships/export/" ;
@@ -271,6 +414,91 @@ public string PartNameFromNode(ConfigNode part)
271414 name = part . GetValue ( "name" ) ;
272415 return name ;
273416 }
417+
418+ /* The following is directly from Claw's InflightShipSave and credit goes to the original author */
419+ private void CleanEditorNodes ( ConfigNode CN )
420+ {
421+
422+ CN . SetValue ( "EngineIgnited" , "False" ) ;
423+ CN . SetValue ( "currentThrottle" , "0" ) ;
424+ CN . SetValue ( "Staged" , "False" ) ;
425+ CN . SetValue ( "sensorActive" , "False" ) ;
426+ CN . SetValue ( "throttle" , "0" ) ;
427+ CN . SetValue ( "generatorIsActive" , "False" ) ;
428+ CN . SetValue ( "persistentState" , "STOWED" ) ;
429+
430+ string ModuleName = CN . GetValue ( "name" ) ;
431+
432+ // Turn off or remove specific things
433+ if ( "ModuleScienceExperiment" == ModuleName )
434+ {
435+ CN . RemoveNodes ( "ScienceData" ) ;
436+ }
437+ else if ( "ModuleScienceExperiment" == ModuleName )
438+ {
439+ CN . SetValue ( "Inoperable" , "False" ) ;
440+ CN . RemoveNodes ( "ScienceData" ) ;
441+ }
442+ else if ( "Log" == ModuleName )
443+ {
444+ CN . ClearValues ( ) ;
445+ }
446+
447+
448+ for ( int IndexNodes = 0 ; IndexNodes < CN . nodes . Count ; IndexNodes ++ )
449+ {
450+ CleanEditorNodes ( CN . nodes [ IndexNodes ] ) ;
451+ }
452+ }
453+
454+ private void PristineNodes ( ConfigNode CN )
455+ {
456+ if ( null == CN ) { return ; }
457+
458+ if ( "PART" == CN . name )
459+ {
460+ string PartName = ( ( CN . GetValue ( "part" ) ) . Split ( '_' ) ) [ 0 ] ;
461+
462+ Debug . LogWarning ( "PART: " + PartName ) ;
463+
464+ Part NewPart = PartLoader . getPartInfoByName ( PartName ) . partPrefab ;
465+ ConfigNode NewPartCN = new ConfigNode ( ) ;
466+ Debug . LogWarning ( "New Part: " + NewPart . name ) ;
467+
468+ NewPart . InitializeModules ( ) ;
469+
470+ CN . ClearNodes ( ) ;
471+
472+ // EVENTS, ACTIONS, PARTDATA, MODULE, RESOURCE
473+
474+
475+ NewPart . Events . OnSave ( CN . AddNode ( "EVENTS" ) ) ;
476+
477+ NewPart . Actions . OnSave ( CN . AddNode ( "ACTIONS" ) ) ;
478+
479+ NewPart . OnSave ( CN . AddNode ( "PARTDATA" ) ) ;
480+
481+ for ( int IndexModules = 0 ; IndexModules < NewPart . Modules . Count ; IndexModules ++ )
482+ {
483+ NewPart . Modules [ IndexModules ] . Save ( CN . AddNode ( "MODULE" ) ) ;
484+ }
485+
486+ for ( int IndexResources = 0 ; IndexResources < NewPart . Resources . Count ; IndexResources ++ )
487+ {
488+ NewPart . Resources [ IndexResources ] . Save ( CN . AddNode ( "RESOURCE" ) ) ;
489+ }
490+
491+ //CN.AddNode(CompiledNodes);
492+
493+ return ;
494+ }
495+ for ( int IndexNodes = 0 ; IndexNodes < CN . nodes . Count ; IndexNodes ++ )
496+ {
497+ PristineNodes ( CN . nodes [ IndexNodes ] ) ;
498+ }
499+ }
500+
501+
274502 }
275503}
276504/*
0 commit comments