-
Notifications
You must be signed in to change notification settings - Fork 7
/
RSTutilities.cs
1561 lines (1407 loc) · 52.8 KB
/
RSTutilities.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
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/*
* (C) Copyright 2016, Jamie Leighton (JPLRepo)
* REPOSoft Technologies
* Kerbal Space Program is Copyright (C) 2013 Squad. See http://kerbalspaceprogram.com/. This
* project is in no way associated with nor endorsed by Squad.
*
* This file is part of RST Utils. My attempt at creating my own KSP Mod base Architecture.
*
* RST Utils is free software: you can redistribute it and/or modify
* it under the terms of the MIT License
*
* RST Utils is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
* You should have received a copy of the MIT License
* along with RST Utils. If not, see <http://opensource.org/licenses/MIT>.
*
*/
using System;
using System.Collections;
using System.Collections.Generic;
using UniLinq;
using System.Reflection;
using System.Text;
using Highlighting;
using KSP.UI.Screens.Flight;
using UnityEngine;
using Object = UnityEngine.Object;
using Random = System.Random;
namespace RSTUtils
{
public enum GameState
{
FLIGHT = 0,
EDITOR = 1,
EVA = 2,
SPACECENTER = 3,
OTHER = 4
}
internal static class Utilities
{
public static int randomSeed = new Random().Next();
private static int _nextrandomInt = randomSeed;
public static int getnextrandomInt()
{
_nextrandomInt ++;
return _nextrandomInt;
}
private static GameState state;
//Set the Game State mode indicator, 0 = inflight, 1 = editor, 2 on EVA or F2
public static bool GameModeisFlight
{
get
{
state = SetModeFlag();
if (state == GameState.FLIGHT) return true;
return false;
}
}
public static bool GameModeisEditor
{
get
{
state = SetModeFlag();
if (state == GameState.EDITOR) return true;
return false;
}
}
public static bool GameModeisEVA
{
get
{
state = SetModeFlag();
if (state == GameState.EVA) return true;
return false;
}
}
public static bool GameModeisSpaceCenter
{
get
{
state = SetModeFlag();
if (state == GameState.SPACECENTER) return true;
return false;
}
}
public static GameState GameMode
{
get
{
return SetModeFlag();
}
}
public static GameState SetModeFlag()
{
//Set the mode flag, 0 = inflight, 1 = editor, 2 on EVA or F2
if (HighLogic.LoadedScene == GameScenes.SPACECENTER)
{
return GameState.SPACECENTER;
}
//if (FlightGlobals.fetch != null && FlightGlobals.ActiveVessel != null) // Check if in flight
if (HighLogic.LoadedSceneIsFlight)
{
if (FlightGlobals.fetch != null)
{
if (FlightGlobals.ActiveVessel != null)
{
if (FlightGlobals.ActiveVessel.isEVA) // EVA kerbal
{
return GameState.EVA;
}
}
}
return GameState.FLIGHT;
}
if (EditorLogic.fetch != null) // Check if in editor
{
return GameState.EDITOR;
}
return GameState.OTHER;
}
#region GeometryandSpace
//Geometry and space
public static double DistanceFromHomeWorld(Vessel vessel)
{
Vector3d vslPos = vessel.GetWorldPos3D();
CelestialBody HmePlanet = Planetarium.fetch.Home;
Log_Debug("Home = " + HmePlanet.name + " Pos = " + HmePlanet.position);
Log_Debug("Vessel Pos = " + vslPos);
Vector3d hmeplntPos = HmePlanet.position;
double DstFrmHome = Math.Sqrt(Math.Pow(vslPos.x - hmeplntPos.x, 2) + Math.Pow(vslPos.y - hmeplntPos.y, 2) + Math.Pow(vslPos.z - hmeplntPos.z, 2));
Log_Debug("Distance from Home Planet = " + DstFrmHome);
return DstFrmHome;
}
public static double DistanceFromHomeWorld(string bodyname)
{
CelestialBody body = FlightGlobals.Bodies.FirstOrDefault(a => a.name == bodyname);
if (body == null) body = Planetarium.fetch.Home;
Vector3d bodyPos = body.getPositionAtUT(0);
CelestialBody HmePlanet = Planetarium.fetch.Home;
Log_Debug("Home = " + HmePlanet.name + " Pos = " + HmePlanet.getPositionAtUT(0));
Log_Debug("Body Pos = " + bodyPos);
Vector3d hmeplntPos = HmePlanet.getPositionAtUT(0);
double DstFrmHome = Math.Sqrt(Math.Pow(bodyPos.x - hmeplntPos.x, 2) + Math.Pow(bodyPos.y - hmeplntPos.y, 2) + Math.Pow(bodyPos.z - hmeplntPos.z, 2));
Log_Debug("Distance from Home Planet = " + DstFrmHome);
return DstFrmHome;
}
public static bool CelestialBodyDistancetoSun(CelestialBody cb, out Vector3d sun_dir, out double sun_dist)
{
// bodies traced against
CelestialBody sun = FlightGlobals.Bodies[0];
if (cb == sun) //If we have passed in the sun as the cb we default to a distance of 700000Km
{
sun_dir = Vector3d.forward;
sun_dist = sun.Radius + 700000000;
sun_dir /= sun_dist;
return true;
}
sun_dir = sun.position - cb.position;
sun_dist = sun_dir.magnitude;
sun_dir /= sun_dist;
sun_dist -= sun.Radius;
return true;
}
// return sun luminosity
public static double SolarLuminosity
{
get
{
// note: it is 0 before loading first vessel in a game session, we compute it in that case
if (PhysicsGlobals.SolarLuminosity <= double.Epsilon)
{
double A = FlightGlobals.GetHomeBody().orbit.semiMajorAxis;
return A * A * 12.566370614359172 * PhysicsGlobals.SolarLuminosityAtHome;
}
return PhysicsGlobals.SolarLuminosity;
}
}
#endregion GeometryandSpace
#region ObjectsandTransforms
public static void PrintTransform(Transform t, string title = "")
{
Log_Debug("------" + title + "------");
Log_Debug("Position: " + t.localPosition);
Log_Debug("Rotation: " + t.localRotation);
Log_Debug("Scale: " + t.localScale);
Log_Debug("------------------");
}
public static void DumpObjectProperties(object o, string title = "---------")
{
// Iterate through all of the properties
Log_Debug("--------- " + title + " ------------");
foreach (PropertyInfo property in o.GetType().GetProperties(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Public))
{
if (property.CanRead)
Log_Debug(property.Name + " = " + property.GetValue(o, null));
}
Log_Debug("--------------------------------------");
}
// Dump an object by reflection
internal static void DumpObjectFields(object o, string title = "---------")
{
// Dump (by reflection)
Debug.Log("---------" + title + "------------");
foreach (FieldInfo field in o.GetType().GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Public))
{
if (!field.IsStatic)
{
Debug.Log(field.Name + " = " + field.GetValue(o));
}
}
Debug.Log("--------------------------------------");
}
// Use Reflection to get a field value from an object
internal static object GetObjectField(object o, string fieldName)
{
object outputObj = new object();
bool foundObj = false;
foreach (FieldInfo field in o.GetType().GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Public))
{
if (!field.IsStatic)
{
if (field.Name == fieldName)
{
foundObj = true;
outputObj = field.GetValue(o);
break;
}
}
}
if (foundObj)
{
return outputObj;
}
return null;
}
// Use Reflection to get a field from an object
internal static FieldInfo GetFieldObject(object o, string fieldName)
{
foreach (FieldInfo field in o.GetType().GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Public))
{
if (!field.IsStatic)
{
if (field.Name == fieldName)
{
return field;
}
}
}
return null;
}
// Use Reflection to get a field from an object
internal static object GetObjectMethod(object o, string methodName)
{
object outputObj = new object();
bool foundObj = false;
foreach (MethodInfo method in o.GetType().GetMethods(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Public))
{
if (!method.IsStatic)
{
if (method.Name == methodName)
{
foundObj = true;
outputObj = method;
break;
}
}
}
if (foundObj)
{
return outputObj;
}
return null;
}
/**
* Recursively searches for a named transform in the Transform heirarchy. The requirement of
* such a function is sad. This should really be in the Unity3D API. Transform.Find() only
* searches in the immediate children.
*
* @param transform Transform in which is search for named child
* @param name Name of child to find
*
* @return Desired transform or null if it could not be found
*/
internal static Transform FindInChildren(Transform transform, string name)
{
// Is this null?
if (transform == null)
{
return null;
}
// Are the names equivalent
if (transform.name == name)
{
return transform;
}
// If we did not find a transform, search through the children
return (from Transform child in transform select FindInChildren(child, name)).FirstOrDefault(t => t != null);
// Return the transform (will be null if it was not found)
}
public static Transform FindChildRecursive(Transform parent, string name)
{
return parent.gameObject.GetComponentsInChildren<Transform>().FirstOrDefault(t => t.name == name);
}
public static Animation FindAnimChildRecursive(Transform parent, string name)
{
return parent.gameObject.GetComponentsInChildren<Animation>().FirstOrDefault(t => t.name == name);
}
internal static void dmpKerbalRefs(Kerbal kerbal, Kerbal seatkerbalref, Kerbal protocrewkerbalref)
{
if (kerbal != null)
{
Log_Debug("kerbal " + kerbal.name + " " + kerbal.GetInstanceID());
Log_Debug(kerbal.GetComponent("TRIvaModule") != null
? "kerbal has TRIvaModule attached"
: "kerbal DOES NOT have TRIvaModule attached");
}
if (seatkerbalref != null)
{
Log_Debug("seatkerbalref " + seatkerbalref.name + " " + seatkerbalref.GetInstanceID());
Log_Debug(seatkerbalref.GetComponent("TRIvaModule") != null
? "seatkerbalref has TRIvaModule attached"
: "seatkerbalref DOES NOT have TRIvaModule attached");
}
if (protocrewkerbalref != null)
{
Log_Debug("protocrewkerbalref " + protocrewkerbalref.name + " " + protocrewkerbalref.GetInstanceID());
Log_Debug(protocrewkerbalref.GetComponent("TRIvaModule") != null
? "protocrewkerbalref has TRIvaModule attached"
: "protocrewkerbalref DOES NOT have TRIvaModule attached");
}
}
internal static void dmpAllKerbals()
{
foreach (Kerbal kerbal in Resources.FindObjectsOfTypeAll<Kerbal>())
{
Log_Debug("Kerbal " + kerbal.name + " " + kerbal.crewMemberName + " instance " + kerbal.GetInstanceID() + " rosterstatus " + kerbal.rosterStatus);
Log_Debug(kerbal.protoCrewMember == null ? "ProtoCrewmember is null " : "ProtoCrewmember exists " + kerbal.protoCrewMember.name);
}
}
internal static void dmpAnimationNames(Animation anim)
{
List<AnimationState> states = new List<AnimationState>(anim.Cast<AnimationState>());
Log_Debug("Animation " + anim.name);
foreach (AnimationState state in states)
{
Log_Debug("Animation clip " + state.name);
}
}
// The following method is modified from RasterPropMonitor as-is. Which is covered by GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007
internal static void setTransparentTransforms(this Part thisPart, string transparentTransforms)
{
string transparentShaderName = "Transparent/Specular";
Shader transparentShader = Shader.Find(transparentShaderName);
foreach (string transformName in transparentTransforms.Split('|'))
{
Log_Debug("setTransparentTransforms " + transformName);
try
{
Transform tr = thisPart.FindModelTransform(transformName.Trim());
if (tr != null)
{
// We both change the shader and backup the original shader so we can undo it later.
Shader backupShader = tr.GetComponent<Renderer>().material.shader;
tr.GetComponent<Renderer>().material.shader = transparentShader;
}
}
catch (Exception e)
{
Debug.Log("Unable to set transparent shader transform " + transformName);
Debug.LogException(e);
}
}
}
#endregion ObjectsandTransforms
#region Cameras
internal static Camera FindCamera(string name)
{
return Camera.allCameras.FirstOrDefault(c => c.name == name);
}
// Dump all Unity Cameras
internal static void DumpCameras()
{
// Dump (by reflection)
Debug.Log("--------- Dump Unity Cameras ------------");
foreach (Camera c in Camera.allCameras)
{
Debug.Log("Camera " + c.name + " cullingmask " + c.cullingMask + " depth " + c.depth + " farClipPlane " + c.farClipPlane + " nearClipPlane " + c.nearClipPlane);
}
Debug.Log("--------------------------------------");
}
public static Camera findCameraByName(string camera)
{
return Camera.allCameras.FirstOrDefault(cam => cam.name == camera);
}
/// <summary>
/// Returns True if the Stock Overlay Camera Mode is on, otherwise will return false.
/// </summary>
public static bool StockOverlayCamIsOn
{
get
{
return KerbalPortraitGallery.isIVAOverlayVisible;
}
}
private static Shader DepthMaskShader;
private static string DepthMaskShaderName = "DepthMask";
/// <summary>
/// Will search for and change the Mesh (and all it's children) supplied in MeshName Field on the part supplied to Enabled or NotEnabled based on the SetVisible parm.
/// </summary>
/// <param name="part">The part to look for the mesh on</param>
/// <param name="SetVisible">True will Enable the mesh, False will disable the mesh</param>
/// <param name="MeshName">String containing the Mesh name to look for on the part</param>
/// <param name="cachedTransform">Can pass in a cached transform; which will be used instead of searching for it.</param>
/// <returns>The parent/cached transform that was changed... Or Null if not found.</returns>
internal static Transform SetInternalDepthMask(Part part, bool SetVisible, string MeshName = "", Transform cachedTransform = null)
{
Transform parentTransform = null;
if (DepthMaskShader == null) DepthMaskShader = Shader.Find(DepthMaskShaderName);
if (part.internalModel != null)
{
if (cachedTransform != null)
{
cachedTransform.gameObject.SetActive(SetVisible);
return cachedTransform;
}
if (MeshName != "")
{
parentTransform = FindInChildren(part.internalModel.transform, MeshName);
if (parentTransform != null)
{
parentTransform.gameObject.SetActive(SetVisible);
}
}
}
return parentTransform;
}
#endregion Cameras
#region Animations
public static IEnumerator WaitForAnimation(Animation animation, string name)
{
do
{
yield return null;
} while (animation.IsPlaying(name));
}
public static IEnumerator WaitForAnimationNoClip(Animation animation)
{
do
{
yield return null;
} while (animation.isPlaying);
}
#endregion Animations
#region Kerbals
// The following method is derived from TextureReplacer mod. Which is licensed as:
//Copyright © 2013-2015 Davorin Učakar, Ryan Bray
//Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
//The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
private static double atmSuitPressure = 50.0;
internal static bool isAtmBreathable()
{
bool value = !HighLogic.LoadedSceneIsFlight
|| (FlightGlobals.getStaticPressure() >= atmSuitPressure);
Log_Debug("isATMBreathable Inflight? " + value + " InFlight " + HighLogic.LoadedSceneIsFlight + " StaticPressure " + FlightGlobals.getStaticPressure());
return value;
}
internal static void setHelmetshaders(Kerbal thatKerbal, bool helmetOn)
{
//This will check if Atmospher is breathable then we always remove our hetmets regardless.
if (helmetOn && isAtmBreathable())
{
helmetOn = false;
Log_Debug("setHelmetShaders to put on helmet but in breathable atmosphere");
}
try
{
thatKerbal.ShowHelmet(helmetOn);
}
catch (Exception ex)
{
Log("Error attempting to setHelmetshaders for " + thatKerbal.name + " to " + helmetOn);
Log(ex.Message);
}
}
internal static void setHelmets(this Part thisPart, bool helmetOn)
{
if (thisPart.internalModel == null)
{
Log_Debug("setHelmets but no internalModel");
return;
}
Log_Debug("setHelmets helmetOn=" + helmetOn);
//if helmetOn is true - we want to put them on. Let's not if there is breathable atmosphere.
if (thisPart.vessel != null && helmetOn)
{
CelestialBody vesselBody = thisPart.vessel.mainBody;
bool atmosExistence = vesselBody.atmosphere && thisPart.vessel.altitude < vesselBody.atmosphereDepth;
if (atmosExistence && vesselBody.atmosphereContainsOxygen)
{
//Has breathable Atmosphere. Now Check Pressure and water.
if (thisPart.staticPressureAtm < 5f && !thisPart.Splashed)
{
//We have breathable atmosphere and not too much pressure or water.
helmetOn = false;
}
}
}
foreach (InternalSeat thatSeat in thisPart.internalModel.seats)
{
if (thatSeat.crew != null)
{
Kerbal thatKerbal = thatSeat.kerbalRef;
if (thatKerbal != null)
{
thatSeat.allowCrewHelmet = helmetOn;
Log_Debug("Setting helmet=" + helmetOn + " for kerbal " + thatSeat.crew.name);
thatKerbal.ShowHelmet(helmetOn);
}
else
Log_Debug("kerbalref = null?");
}
}
}
// Sets the kerbal layers to make them visible (Thawed) or not (Frozen), setVisible = true sets layers to visible, false turns them off.
internal static void setFrznKerbalLayer(Part part, ProtoCrewMember kerbal, bool setVisible)
{
if (!setVisible)
{
kerbal.KerbalRef.SetVisibleInPortrait(setVisible);
kerbal.KerbalRef.InPart = null;
}
kerbal.KerbalRef.gameObject.SetActive(setVisible);
if (setVisible)
{
kerbal.KerbalRef.SetVisibleInPortrait(setVisible);
kerbal.KerbalRef.InPart = part;
}
}
private static RuntimeAnimatorController kerbalIVAController, myController;
private static AnimatorOverrideController myOverrideController;
internal static void subdueIVAKerbalAnimations(Kerbal kerbal)
{
try
{
if (kerbal.Animators == null)
return;
foreach (Animator anim in kerbal.Animators)
{
if (anim.name == kerbal.name)
{
kerbalIVAController = anim.runtimeAnimatorController;
myController = anim.runtimeAnimatorController;
if (myController.GetType() != typeof(AnimatorOverrideController))
{
anim.logWarnings = false;
myOverrideController = new AnimatorOverrideController();
AnimatorStateInfo[] layerInfo = new AnimatorStateInfo[anim.layerCount];
for (int i = 0; i < anim.layerCount; i++)
{
layerInfo[i] = anim.GetCurrentAnimatorStateInfo(i);
}
if (kerbal.protoCrewMember.gender == ProtoCrewMember.Gender.Male)
{
myOverrideController.runtimeAnimatorController = myController;
myOverrideController["idle_animA_upWord"] = myOverrideController["idle_animH_notDoingAnything"];
myOverrideController["idle_animB"] = myOverrideController["idle_animH_notDoingAnything"];
myOverrideController["idle_animC"] = myOverrideController["idle_animH_notDoingAnything"];
myOverrideController["idle_animD_dance"] = myOverrideController["idle_animH_notDoingAnything"];
myOverrideController["idle_animE_drummingHelmet"] = myOverrideController["idle_animH_notDoingAnything"];
myOverrideController["idle_animF_helmetAdjustB"] = myOverrideController["idle_animH_notDoingAnything"];
myOverrideController["idle_animG_helmetScratching"] = myOverrideController["idle_animH_notDoingAnything"];
myOverrideController["idle_animI_drummingControls"] = myOverrideController["idle_animH_notDoingAnything"];
myOverrideController["idle_animJ_yo"] = myOverrideController["idle_animH_notDoingAnything"];
myOverrideController["idle_animK_footStretch"] = myOverrideController["idle_animH_notDoingAnything"];
myOverrideController["head_rotation_staringUp"] = myOverrideController["idle_animH_notDoingAnything"];
myOverrideController["head_rotation_longLookUp"] = myOverrideController["idle_animH_notDoingAnything"];
myOverrideController["head_faceExp_fun_ohAh"] = myOverrideController["idle_animH_notDoingAnything"];
}
else //Female
{
myOverrideController.runtimeAnimatorController = myController;
myOverrideController["idle_animA"] = myOverrideController["idle_animH_notDoingAnything"];
myOverrideController["idle_animB"] = myOverrideController["idle_animH_notDoingAnything"];
myOverrideController["idle_animC"] = myOverrideController["idle_animH_notDoingAnything"];
myOverrideController["idle_animD"] = myOverrideController["idle_animH_notDoingAnything"];
myOverrideController["idle_animD_dance"] = myOverrideController["idle_animH_notDoingAnything"];
myOverrideController["idle_animE"] = myOverrideController["idle_animH_notDoingAnything"];
myOverrideController["idle_animF"] = myOverrideController["idle_animH_notDoingAnything"];
myOverrideController["idle_animG"] = myOverrideController["idle_animH_notDoingAnything"];
myOverrideController["idle_animH"] = myOverrideController["idle_animH_notDoingAnything"];
myOverrideController["idle_animI"] = myOverrideController["idle_animH_notDoingAnything"];
myOverrideController["idle_animI_drummingControls"] = myOverrideController["idle_animH_notDoingAnything"];
myOverrideController["idle_animJ"] = myOverrideController["idle_animH_notDoingAnything"];
myOverrideController["idle_animJ_yo"] = myOverrideController["idle_animH_notDoingAnything"];
myOverrideController["idle_animK"] = myOverrideController["idle_animH_notDoingAnything"];
myOverrideController["idle_animK_footStretch"] = myOverrideController["idle_animH_notDoingAnything"];
myOverrideController["head_rotation_staringUp"] = myOverrideController["idle_animH_notDoingAnything"];
myOverrideController["head_rotation_longLookUp"] = myOverrideController["idle_animH_notDoingAnything"];
myOverrideController["head_faceExp_fun_ohAh"] = myOverrideController["idle_animH_notDoingAnything"];
}
// Put this line at the end because when you assign a controller on an Animator, unity rebinds all the animated properties
anim.runtimeAnimatorController = myOverrideController;
// Force an update
anim.Update(0.0f);
// Push back state
for (int i = 0; i < anim.layerCount; i++)
{
anim.Play(layerInfo[i].fullPathHash, i, layerInfo[i].normalizedTime);
}
anim.logWarnings = true;
}
Log_Debug("Animator " + anim.name + " for " + kerbal.name + " subdued");
}
}
}
catch (Exception ex)
{
Log(" failed to subdue IVA animations for " + kerbal.name);
Debug.LogException(ex);
}
}
internal static void reinvigerateIVAKerbalAnimations(Kerbal kerbal)
{
foreach (Animator anim in kerbal.Animators)
{
if (anim.name == kerbal.name)
{
myController = kerbalIVAController;
myOverrideController = new AnimatorOverrideController();
myOverrideController.runtimeAnimatorController = myController;
// Put this line at the end because when you assign a controller on an Animator, unity rebinds all the animated properties
anim.runtimeAnimatorController = myOverrideController;
Log_Debug("Animator " + anim.name + " for " + kerbal.name + " reinvigerated");
}
}
}
internal static ProtoCrewMember findKerbalInPart(Part partRef, string kerbalName)
{
if (partRef.protoModuleCrew == null)
{
return null;
}
for (int i = 0; i < partRef.protoModuleCrew.Count; i++)
{
if (partRef.protoModuleCrew[i].name == kerbalName)
{
return partRef.protoModuleCrew[i];
}
}
return null;
}
#endregion Kerbals
#region Vessels
// The following method is taken from RasterPropMonitor as-is. Which is covered by GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007
/// <summary>
/// Returns True if thatVessel is the activevessel and the camera is in IVA mode, otherwise returns false.
/// </summary>
/// <param name="thatVessel"></param>
/// <returns></returns>
internal static bool VesselIsInIVA(Vessel thatVessel)
{
// Inactive IVAs are renderer.enabled = false, this can and should be used...
// ... but now it can't because we're doing transparent pods, so we need a more complicated way to find which pod the player is in.
return HighLogic.LoadedSceneIsFlight && IsActiveVessel(thatVessel) && IsInIVA;
}
// The following method is taken from RasterPropMonitor as-is. Which is covered by GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007
/// <summary>
/// Returns True if thatVessel is the ActiveVessel, otherwise returns false.
/// </summary>
/// <param name="thatVessel"></param>
/// <returns></returns>
internal static bool IsActiveVessel(Vessel thatVessel)
{
return HighLogic.LoadedSceneIsFlight && thatVessel != null && thatVessel.isActiveVessel;
}
// The following method is taken from RasterPropMonitor as-is. Which is covered by GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007
public static bool UserIsInPod(Part thisPart)
{
// Just in case, check for whether we're not in flight.
if (!HighLogic.LoadedSceneIsFlight)
return false;
// If we're not in IVA, or the part does not have an instantiated IVA, the user can't be in it.
if (!VesselIsInIVA(thisPart.vessel) || thisPart.internalModel == null)
return false;
// Now that we got that out of the way, we know that the user is in SOME pod on our ship. We just don't know which.
// Let's see if he's controlling a kerbal in our pod.
if (ActiveKerbalIsLocal(thisPart))
return true;
// There still remains an option of InternalCamera which we will now sort out.
if (CameraManager.Instance.currentCameraMode == CameraManager.CameraMode.Internal)
{
// So we're watching through an InternalCamera. Which doesn't record which pod we're in anywhere, like with kerbals.
// But we know that if the camera's transform parent is somewhere in our pod, it's us.
// InternalCamera.Instance.transform.parent is the transform the camera is attached to that is on either a prop or the internal itself.
// The problem is figuring out if it's in our pod, or in an identical other pod.
// Unfortunately I don't have anything smarter right now than get a list of all transforms in the internal and cycle through it.
// This is a more annoying computation than looking through every kerbal in a pod (there's only a few of those,
// but potentially hundreds of transforms) and might not even be working as I expect. It needs testing.
return thisPart.internalModel.GetComponentsInChildren<Transform>().Any(thisTransform => thisTransform == InternalCamera.Instance.transform.parent);
}
return false;
}
// The following method is taken from RasterPropMonitor as-is. Which is covered by GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007
public static bool ActiveKerbalIsLocal(this Part thisPart)
{
return FindCurrentKerbal(thisPart) != null;
}
// The following method is taken from RasterPropMonitor as-is. Which is covered by GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007
public static Kerbal FindCurrentKerbal(this Part thisPart)
{
if (thisPart.internalModel == null || !VesselIsInIVA(thisPart.vessel))
return null;
// InternalCamera instance does not contain a reference to the kerbal it's looking from.
// So we have to search through all of them...
return (from thatSeat in thisPart.internalModel.seats
where thatSeat.kerbalRef != null
where thatSeat.kerbalRef.eyeTransform == InternalCamera.Instance.transform.parent
select thatSeat.kerbalRef).FirstOrDefault();
}
// The following method is taken from RasterPropMonitor as-is. Which is covered by GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007
/// <summary>
/// True if Camera is in IVA mode, otherwise false.
/// </summary>
internal static bool IsInIVA
{
get { return CameraManager.Instance.currentCameraMode == CameraManager.CameraMode.IVA; }
}
/// <summary>
/// True if Camera is in Internal mode, otherwise false.
/// </summary>
internal static bool IsInInternal
{
get { return CameraManager.Instance.currentCameraMode == CameraManager.CameraMode.Internal; }
}
internal static bool ValidVslType(Vessel v)
{
switch (v.vesselType)
{
case VesselType.Base:
case VesselType.Lander:
case VesselType.Probe:
case VesselType.Rover:
case VesselType.Ship:
case VesselType.Station:
case VesselType.Plane:
case VesselType.Relay:
return true;
default:
return false;
}
}
// The following method is taken from Kerbal Alarm Clock as-is. Which is covered by MIT license.
internal static int getVesselIdx(Vessel vtarget)
{
for (int i = 0; i < FlightGlobals.Vessels.Count; i++)
{
if (FlightGlobals.Vessels[i].id == vtarget.id)
{
Log_Debug("Found Target idx=" + i + " (" + vtarget.id + ")");
return i;
}
}
return -1;
}
/// <summary>
/// Will Spawn the Internal Model for a part, we do this for DeepFreeze Mod because it doesn't work if the crew capacity is zero, which may be
/// the case sometimes for DeepFreeze parts.
/// </summary>
/// <param name="part">The Part to spawn the internal model for</param>
/// <returns>True if successful or False if not</returns>
internal static bool spawnInternal(Part part)
{
try
{
if (part.internalModel != null) return true;
part.CreateInternalModel();
if (part.internalModel != null)
{
part.internalModel.Initialize(part);
part.internalModel.SpawnCrew();
}
else
{
return false;
}
return true;
}
catch (Exception)
{
return false;
}
}
public static void PartHighlight(Part part, bool on)
{
if (on)
{
if (part.HighlightActive)
{
Color color = XKCDColors.Yellow;
part.SetHighlightColor(color);
part.SetHighlight(true, false);
}
}
else
{
if (part.HighlightActive)
{
part.SetHighlightDefault();
part.SetHighlight(false, false);
}
}
}
#endregion Vessels
#region CelestialBodies
public static List<string> GetCelestialBodyNames()
{
List<string> bodynames = new List<string>();
for (int i = 0; i < FlightGlobals.Bodies.Count; i++)
{
bodynames.Add(FlightGlobals.Bodies[i].bodyName);
}
return bodynames;
}
#endregion
#region Temperature
//Temperature
internal static float KelvintoCelsius(float kelvin)
{
return kelvin - 273.15f;
}
internal static float CelsiustoKelvin(float celsius)
{
return celsius + 273.15f;
}
#endregion Temperature
#region Resources
/// <summary>
/// Can be used to get amount of a resource there is, amount of space for a resource there is, or push/pull resource.
/// </summary>
/// <param name="craft">this is the vessel</param>
/// <param name="res">this is the string resource name</param>
/// <param name="resAmount">amount of the resource</param>
/// <param name="ConsumeResource">true to push/pull</param>
/// <param name="pulling">true if pulling false if pushing</param>
/// <param name="usePri">true if use flow priority false if not</param>
/// <param name="resavail">amount of the resource available or push/pulled</param>
/// <param name="maxavail">max amount of resource vessel can store</param>
/// <returns>bool if successful or not</returns>
internal static bool requireResource(Vessel craft, string res, double resAmount, bool ConsumeResource, bool pulling, bool usePri, out double resavail, out double maxavail)
{
int resID = PartResourceLibrary.Instance.GetDefinition(res).id;
bool result = requireResourceID(craft, resID, resAmount, ConsumeResource, pulling, usePri, out resavail, out maxavail);
return result;
}
/// <summary>
/// Can be used to get amount of a resource there is, amount of space for a resource there is, or push/pull resource.
/// </summary>
/// <param name="craft">this is the vessel</param>
/// <param name="res">this is the hash of the resource name</param>
/// <param name="resAmount">amount of the resource</param>
/// <param name="ConsumeResource">true to push/pull</param>
/// <param name="pulling">true if pulling false if pushing</param>
/// <param name="resavail">amount of the resource available or push/pulled</param>
/// <param name="maxavail">max amount of resource vessel can store</param>
/// <returns>bool if successful or not</returns>
internal static bool requireResourceID(Vessel craft, int res, double resAmount, bool ConsumeResource, bool pulling, bool usePri, out double resavail, out double maxavail)
{
if (!craft.loaded)
{
resavail = 0;
maxavail = 0;
return false; // Unloaded resource checking is unreliable.
}
double amount, maxamount;
//Get how much of the resource is available and capacity
craft.resourcePartSet.GetConnectedResourceTotals(res, out amount, out maxamount, pulling);
//If we are pulling and the amount avail is less than the amount we want. return what's available but don't take the resource
//If we are not pulling is the amount avail (space available) greater than the amount we want. if not return what's available but don't store it.
//So in both cases amount must be >= the anout we want.
resavail = amount;
maxavail = maxamount;
//If we are not consuming the resource (or storing) just return how much there is. We return false if there is less than the amount
//passed in. Otherwise we return true.
if (!ConsumeResource)
{
if (amount < resAmount)
{
return false;
}
return true;
}
//Now we push or pull - Cater for push negative values (abs).
double amountdrawn = craft.RequestResource(craft.rootPart, res, resAmount, pulling);
if (Math.Abs(amountdrawn) < (Math.Abs(resAmount) * 0.99))
{
resavail = amountdrawn;
return false;
}
resavail = amountdrawn;
return true;
}
/// <summary>
/// Converts Stock EC units to SI units (W,kW,mW)