![](https://forum.kerbalspaceprogram.com/uploads/set_resources_17/84c1e40ea0e759e3f1505eb1788ddf3c_pattern.png)
![](https://forum.kerbalspaceprogram.com/uploads/set_resources_17/84c1e40ea0e759e3f1505eb1788ddf3c_default_photo.png)
xEvilReeperx
Members-
Posts
894 -
Joined
-
Last visited
Content Type
Profiles
Forums
Developer Articles
KSP2 Release Notes
Everything posted by xEvilReeperx
-
Is it possible to open a texture???
xEvilReeperx replied to mjy's topic in KSP1 Modelling and Texturing Discussion
This is the correct texture. KSP uses the KSP/Specular shader on this material. If you look at the shader code in Unity, it uses the texture's alpha channel as a multiplier for specular highlighting. -
Ew Just don't modify the collection while you're iterating through it. Here are two more ways: var deathList = new List<Part>(); foreach (Part p in this.part.children) if (p.Resources.Contains("SolidFuel")) deathList.Add(p); foreach (var p in deathList) p.Die(); for (int i = 0; i < this.part.children.Count; ) if (this.part.Resources.Contains("SolidFuel")) { this.part.children[i].Die(); } else ++i;
-
Call animation from a plugin?
xEvilReeperx replied to lo-fi's topic in KSP1 C# Plugin Development Help and Support
I use my own debug routines. That's equivalent to Debug.LogError(string.format("Repulsor etc etc {0}", ...). Sorry, I got used to working with some of my own convenience classes A simple myAnimation.Toggle() would work in almost all cases. The problem the above solves is if somebody had a mod that replaced all "ModuleAnimateGeneric" PartModules with a derived version using something like ModuleManager. I'm sure you've noticed there are a lot of potential replacements out there. Essentially, what the line does is to use reflection to search through the real underlying type for a method with the name specified and then calls it. It will almost always resolve to ModuleAnimateGeneric.Toggle, but should anyone replace the ModuleAnimateGeneric in your part with an "improved" version, that method will be run as the derived version author expects and your code won't break because you accidentally called the wrong method and skipped any extra logic the derived version implemented in its version of Toggle. It's just a bit of a safety net. Just a bug; your way is fine (and better) Well, I was going by what the state of the wheel was and targeting other wheels that didn't match that state. The player would have clicked on "Retract all" if the wheel was already deployed (based on my understanding of your initial snippet), so I figured it'd make the most sense to retract any deployed wheels rather than deploy the undeployed ones. You could give every wheel a "deploy all" and "retract all" event that's active all the time or you could make sure every wheel's "deploy all" stays active until all wheels are deployed. -
Call animation from a plugin?
xEvilReeperx replied to lo-fi's topic in KSP1 C# Plugin Development Help and Support
Looks cool! Not at all -
Call animation from a plugin?
xEvilReeperx replied to lo-fi's topic in KSP1 C# Plugin Development Help and Support
I wrote some pseudo-code for you. It's untested so it might need some adjustments or have a couple bugs, but it should lead you in the right direction public class Repulsor : PartModule { /* --- your other code ----- */ public void PlayAnimation() { // note: assumes one ModuleAnimateGeneric (or derived version) for this part // if this isn't the case, needs fixing ModuleAnimateGeneric myAnimation = part.FindModulesImplementing<ModuleAnimateGeneric>().SingleOrDefault(); if (!myAnimation) { // this shouldn't happen under normal circumstances Log.Error("Repulsor animation error: Did not find ModuleAnimateGeneric on {0}", part.ConstructID); return; } else { // if another mod were to replace all ModuleAnimateGenerics with // their own (derived) version and we tried to call the derived // Toggle method with myAnimation.Toggle(), we'll end up calling // the base version instead of the most derived version we want. // If they do any critical logic in there, you've opened yourself // up to all sorts of bugs or strange behaviour try { // Get the most-derived type and use its Toggle method so we don't // skip any plugin-derived versions myAnimation.GetType().InvokeMember("Toggle", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.IgnoreReturn | System.Reflection.BindingFlags.InvokeMethod, null, myAnimation, null); } catch (Exception e) { Log.Error("Failed to invoke \"Toggle\" using GetType(), falling back to base type after encountering exception {0}", e); myAnimation.Toggle(); } } } [KSPEvent(guiActive = true, guiName = "Deploy All", active = true)] public void deploy() { // note: this loop will find "us" too. Intended foreach (Repulsor rp in this.vessel.FindPartModulesImplementing<Repulsor>()) { // it's risky to assume all Repulsors are in the same animation state. // If the player manages to attach a new one with KAS or docks two // vessels together with repulsors in different states, you can see // how there could be a problem with just toggling animations on all // repulsors if (rp.Events["deploy"].active == this.Events["deploy"].active) { print(string.Format("{1} Repulsor attached to {0}", rp.part.ConstructID, rp.Events["deploy"].active ? "Deploying" : "Retracting")); rp.PlayAnimation(); // was this intended? Once deployed and // retracted, Repulsor will never be deployable again //rp.Events["deploy"].active = false; //rp.Events["retract"].active = true; //rp.deployed = true; rp.deployed = !rp.deployed; rp.Events["deploy"].active = !rp.deployed; rp.Events["retract"].active = rp.deployed; // I assume whether the wheel is deployed matters here foreach (WheelCollider wc in rp.GetComponentsInChildren<WheelCollider>()) wc.suspensionDistance = rp.deployed ? rp.Rideheight : StowedDistance; //wc.suspensionDistance = rp.Rideheight; } } }//end Deploy All } -
Looks like the EzGUI stuff is all in Assembly-CSharp-firstpass DLL. Here's something I put together that should help with both your goals: [KSPAddon(KSPAddon.Startup.EditorAny, false)] public class ActionGroupEditorTest : MonoBehaviour { void Start() { var panel = EditorPanels.Instance.actions; // fired when the user selects a different part and selection list changes // This list appears to be the rightmost list, containing possible actions // note: the "reset" button is included in this list once an item has been moved // out of this list EditorActionGroups.Instance.partActionList.AddValueChangedDelegate(OnPartActionListChange); // This is the left-most list, listing possible action groups EditorActionGroups.Instance.actionGroupList.AddValueChangedDelegate(OnActionGroupListChange); // This is the middle list. Note that the name of the part // is included as an item. EditorActionGroups.Instance.groupActionsList.AddValueChangedDelegate(OnGroupActionsListChange); // Seems to be fired when the panel state changes (opens, closes) // also triggered by calls in ShowPanel panel.AddValueChangedDelegate(OnChanged); } public void ShowPanel(bool visible = true) { if (EditorLogic.fetch.editorScreen == EditorLogic.EditorScreen.Actions) if (!visible) { // Dismiss causes transition; this hides panel immediately EditorPanels.Instance.panelManager.DismissImmediate(); // note: stays in action group edit mode } else { //EditorPanels.Instance.ShowActionGroups(); doesn't work EditorPanels.Instance.panelManager.BringInImmediate(EditorPanels.Instance.actions); // works } } // Invoked when actions panel changes (made visible or invisible); // called AFTER transition is complete public void OnChanged(IUIObject obj) { Log.Error("OnChanged delegate! {0}", obj.name); Log.Write("Action editor {0}", EditorLogic.fetch.editorScreen == EditorLogic.EditorScreen.Actions ? "activated" : "deactivated"); } /// <summary> /// Invoked when an action is added to the middle list. /// </summary> /// <param name="obj"></param> public void OnGroupActionsListChange(IUIObject obj) { Log.Error("OnGroupActionsListChange: {0}", obj.name); for (int i = 0; i < EditorActionGroups.Instance.groupActionsList.Count; ++i) { var item = EditorActionGroups.Instance.groupActionsList.GetItem(i); Log.Write("groupActionsList item {0} = {1}", i, item); //EditorActionGroups.Instance.groupActionsList.GetItem(i).gameObject.PrintComponents(); /* * [LOG 06:27:30.993] DebugTools, ActionGroupItem(Clone) has components: [LOG 06:27:30.994] DebugTools, ...c: UnityEngine.Transform [LOG 06:27:30.994] DebugTools, ...c: UIListItemContainer [LOG 06:27:30.995] DebugTools, ...c: EditorActionPartItem [LOG 06:27:30.995] DebugTools, --->ActionGroupTitle has components: [LOG 06:27:30.996] DebugTools, ......c: UnityEngine.Transform [LOG 06:27:30.997] DebugTools, ......c: UnityEngine.MeshRenderer [LOG 06:27:30.997] DebugTools, ......c: UnityEngine.MeshFilter [LOG 06:27:30.998] DebugTools, ......c: SpriteText [LOG 06:27:30.999] DebugTools, --->Background has components: [LOG 06:27:30.999] DebugTools, ......c: UnityEngine.Transform [LOG 06:27:31.000] DebugTools, ......c: UnityEngine.MeshFilter [LOG 06:27:31.000] DebugTools, ......c: UnityEngine.MeshRenderer [LOG 06:27:31.001] DebugTools, ......c: UIButton [LOG 06:27:31.001] DebugTools, ......c: UnityEngine.BoxCollider * */ var pa = item.gameObject.GetComponent<EditorActionPartItem>(); if (pa != null && pa.evt != null) Log.Write("guiName: {0}", pa.evt.guiName); } } /// <summary> /// right-most list /// </summary> /// <param name="obj"></param> public void OnPartActionListChange(IUIObject obj) { Log.Error("OnPartActionListChange: {0}", obj.name); for (int i = 0; i < EditorActionGroups.Instance.partActionList.Count; ++i) Log.Write("partActionList item {0} = {1}", i, EditorActionGroups.Instance.partActionList.GetItem(i)); } /// <summary> /// left-most list /// </summary> /// <param name="obj"></param> public void OnActionGroupListChange(IUIObject obj) { Log.Error("OnActionGroupListChange: {0}", obj.name); for (int i = 0; i < EditorActionGroups.Instance.actionGroupList.Count; ++i) Log.Write("ActionGroupList item {0} = {1}", i, EditorActionGroups.Instance.actionGroupList.GetItem(i)); } void OnGUI() { if (EditorLogic.fetch.editorScreen == EditorLogic.EditorScreen.Actions) { if (GUI.Button(new Rect(400f, 400f, 128f, 20f), "Show")) ShowPanel(true); if (GUI.Button(new Rect(400f, 424f, 128f, 20f), "Hide")) ShowPanel(false); } } } I wonder if we can get our own UIButtons running. It might solve the clickthrough problem with Unity's GUI. No time to look into it today though
-
KSPAddon instantiated twice
xEvilReeperx replied to Ippo's topic in KSP1 C# Plugin Development Help and Support
You've got a bit of a mistake in there. ScenarioModules are handled differently. The game's persistence file contains a list of them and which scenes to load them in and the game uses that information to load them, rather than the KSPAddon attribute. What you need is a special KSPAddon that checks to see if your ScenarioModule was added to the game or not. I seem to recall a cleaner method of going about this but I couldn't find it, so in the meantime I'll give you my version: //note the lack of any attributes on this one public class YourScenarioModule : ScenarioModule { } [KSPAddon(KSPAddon.Startup.SpaceCentre, false)] public class ScenarioCreator : MonoBehaviour { public void Start() { bool scenarioExists = !HighLogic.CurrentGame.scenarios.All(scenario => scenario.moduleName != typeof(YourScenarioModule).Name ); if (!scenarioExists) { try { Debug.Log("Adding YourScenarioModule to game '" + HighLogic.CurrentGame.Title + "'"); HighLogic.CurrentGame.AddProtoScenarioModule(typeof(YourScenarioModule), new GameScenes[1] { GameScenes.FLIGHT }); // the game will add this scenario to the appropriate persistent file on save from now on } catch (ArgumentException ae) { Debug.LogException(ae); } catch { Debug.Log("Unknown failure while adding scenario."); } } Destroy(this); } } Modify the GameScenes array passed into AddProtoScenarioModule to include any scenes in which your ScenarioModule should be loaded. Once you've run this code once, look into the persistence file (or a quicksave) and confirm that a section that looks like this is in there: SCENARIO { name = YourScenarioModule scene = 7 } -
The gameObject based 'breakable' system
xEvilReeperx replied to NoMrBond's topic in KSP1 Modelling and Texturing Discussion
I don't know if this will help you any, but it might provide some clues. Here's a dump of how the hierarchy is setup ingame: [LOG 21:10:10.542] DebugTools, Transform: solarPanels2 [LOG 21:10:10.542] DebugTools, ---> Transform: model [LOG 21:10:10.543] DebugTools, ------> Transform: solarPanel2 [LOG 21:10:10.543] DebugTools, ---------> Transform: base [LOG 21:10:10.544] DebugTools, ---------> Transform: door [LOG 21:10:10.545] DebugTools, ---------> Transform: sunPivot [LOG 21:10:10.545] DebugTools, ------------> Transform: knob [LOG 21:10:10.546] DebugTools, ---------------> Transform: panel3 [LOG 21:10:10.546] DebugTools, ------------------> Transform: panel04 [LOG 21:10:10.547] DebugTools, ---------------------> Transform: panel05 [LOG 21:10:10.547] DebugTools, ------------------------> Transform: panel06 [LOG 21:10:10.548] DebugTools, ---------------------------> Transform: panel07 [LOG 21:10:10.549] DebugTools, ------------------------------> Transform: panel08 Note that the Unity hierarchy starts at under "model", i.e. the first child in the Unity hierarchy here would be "base" with a parent that apparently has no collider nor mesh LOG 21:10:10.506] DebugTools, solarPanels2 has components: [LOG 21:10:10.506] DebugTools, ...c: UnityEngine.Transform [LOG 21:10:10.507] DebugTools, ...c: Part [LOG 21:10:10.508] DebugTools, ...c: ModuleDeployableSolarPanel [LOG 21:10:10.508] DebugTools, --->model has components: [LOG 21:10:10.509] DebugTools, ......c: UnityEngine.Transform [LOG 21:10:10.509] DebugTools, ------>solarPanel2 has components: [LOG 21:10:10.510] DebugTools, .........c: UnityEngine.Transform [LOG 21:10:10.511] DebugTools, .........c: UnityEngine.Animation [LOG 21:10:10.511] DebugTools, --------->base has components: [LOG 21:10:10.512] DebugTools, ............c: UnityEngine.Transform [LOG 21:10:10.512] DebugTools, ............c: UnityEngine.BoxCollider [LOG 21:10:10.513] DebugTools, ............c: UnityEngine.MeshFilter [LOG 21:10:10.514] DebugTools, ............c: UnityEngine.MeshRenderer [LOG 21:10:10.514] DebugTools, --------->door has components: [LOG 21:10:10.515] DebugTools, ............c: UnityEngine.Transform [LOG 21:10:10.516] DebugTools, ............c: UnityEngine.BoxCollider [LOG 21:10:10.516] DebugTools, ............c: UnityEngine.MeshFilter [LOG 21:10:10.517] DebugTools, ............c: UnityEngine.MeshRenderer [LOG 21:10:10.517] DebugTools, --------->sunPivot has components: [LOG 21:10:10.518] DebugTools, ............c: UnityEngine.Transform [LOG 21:10:10.519] DebugTools, ------------>knob has components: [LOG 21:10:10.519] DebugTools, ...............c: UnityEngine.Transform [LOG 21:10:10.520] DebugTools, ...............c: UnityEngine.MeshFilter [LOG 21:10:10.521] DebugTools, ...............c: UnityEngine.MeshRenderer [LOG 21:10:10.521] DebugTools, --------------->panel3 has components: [LOG 21:10:10.522] DebugTools, ..................c: UnityEngine.Transform [LOG 21:10:10.522] DebugTools, ..................c: UnityEngine.BoxCollider [LOG 21:10:10.523] DebugTools, ..................c: UnityEngine.MeshFilter [LOG 21:10:10.524] DebugTools, ..................c: UnityEngine.MeshRenderer [LOG 21:10:10.524] DebugTools, ------------------>panel04 has components: [LOG 21:10:10.525] DebugTools, .....................c: UnityEngine.Transform [LOG 21:10:10.526] DebugTools, .....................c: UnityEngine.BoxCollider [LOG 21:10:10.526] DebugTools, .....................c: UnityEngine.MeshFilter [LOG 21:10:10.527] DebugTools, .....................c: UnityEngine.MeshRenderer [LOG 21:10:10.528] DebugTools, --------------------->panel05 has components: [LOG 21:10:10.528] DebugTools, ........................c: UnityEngine.Transform [LOG 21:10:10.529] DebugTools, ........................c: UnityEngine.BoxCollider [LOG 21:10:10.529] DebugTools, ........................c: UnityEngine.MeshFilter [LOG 21:10:10.531] DebugTools, ........................c: UnityEngine.MeshRenderer [LOG 21:10:10.531] DebugTools, ------------------------>panel06 has components: [LOG 21:10:10.532] DebugTools, ...........................c: UnityEngine.Transform [LOG 21:10:10.533] DebugTools, ...........................c: UnityEngine.BoxCollider [LOG 21:10:10.533] DebugTools, ...........................c: UnityEngine.MeshFilter [LOG 21:10:10.534] DebugTools, ...........................c: UnityEngine.MeshRenderer [LOG 21:10:10.535] DebugTools, --------------------------->panel07 has components: [LOG 21:10:10.535] DebugTools, ..............................c: UnityEngine.Transform [LOG 21:10:10.536] DebugTools, ..............................c: UnityEngine.BoxCollider [LOG 21:10:10.537] DebugTools, ..............................c: UnityEngine.MeshFilter [LOG 21:10:10.537] DebugTools, ..............................c: UnityEngine.MeshRenderer [LOG 21:10:10.538] DebugTools, ------------------------------>panel08 has components: [LOG 21:10:10.539] DebugTools, .................................c: UnityEngine.Transform [LOG 21:10:10.539] DebugTools, .................................c: UnityEngine.BoxCollider [LOG 21:10:10.540] DebugTools, .................................c: UnityEngine.MeshFilter [LOG 21:10:10.541] DebugTools, .................................c: UnityEngine.MeshRenderer Good luck -
How to add fairings to engines?
xEvilReeperx replied to GrumpyOldMan's topic in KSP1 Mod Development
The engine fairings are part of the engine's model and should be tagged Icon_Hidden in Unity. I can't tell you much more than that, having never modeled an engine myself. My assumption is that they'll be disabled by default unless explicitly enabled by a PartModule like ModuleDecouple. Should get you moving in the right direction at least -
I hesitate to suggest this since it's quite hacky and will prevent your mod from working with any other mod that happens to also use it, but one thing you could do is stuff your data into Part.customPartData and redo your editor associations on ship launch. I can't think of any other way to uniquely identify any given part from the editor to flight than either that or doing what you're doing and adding a new PartModule with a single field to all existing parts Edit: Also I didn't try this out, but another possibility (that I haven't explored and so may not work as imagined): When the player enters the editor, add your identifying PartModule to ALL part prefabs If the player leaves the editor and it's not to launch the ship, remove the PartModule from all part prefabs again If the player leaves the editor and it's to launch the ship, leave the PartModules attached until the ship is loaded, then strip all PartModules from all part prefabs, do your logic with whatever uses them to identify parts, and then strip all unused identifier PartModules from the ship The idea is to get around the issue of the .craft loading a PartModule that it doesn't recognize. If it's attached temporarily, you could use it to smuggle your GUID data out of the editor and into the flight vessel. The main attraction of this method is that you wouldn't clobber any other mod functionality doing it, although it could be argued that it's even uglier than the first method
-
It's persistent, but not how you think. If you added the part inflight, changing scenes is no problem. The problem you're encountering is that KSP treats "persistent" and "regular" data differently. Your module is added to the .craft file but is ignored if that file isn't loaded as a persistent save, which it isn't when moving from editor to flight. So it's deleted, KSP writes a warning about not being able to load a module for any affected parts and things proceed. Is there a reason you're adding the PartModules in the editor as opposed to when flight begins? A description of what you're trying to do would be helpful.
-
One question: does your "ModuleActiveStrutFreeAttachTarget" have an Awake method? P.S. Your code works fine in my test
-
Command Module transfer/assign part.
xEvilReeperx replied to Gristle's topic in KSP1 C# Plugin Development Help and Support
Yes, it would require a plugin. Yes it can be done. I do something that's sort of along these lines in ScienceAlert: adding and removing a PartModule at runtime from particular parts -
PluginConfigNode probably has some issue with objects. If you convert it to a string before passing it in, it'll work config.SetValue("CUSTOM_1_VALUE", v.ToString());I'll also point out the KSPUtil class, which has a number of convenient static methods to help parse various KSP types to and from strings. It sometimes gets overlooked
-
I wasn't thinking automatic reports, more just a way for a user to quickly and easily upload their depersonalized log and a short message describing the problem. Re: I thought this List of plugins detected and their versions indicated that version info was included already. That's why not having any way for the user to upload a log is so frustrating to me; I thought about 95% of the work was already done. You could copy-paste the entire project, add about 30 lines and for the cost of storing some logs on the server for a day have a very useful, widely desirable debugging utility for modders to distribute with all of their mods. Anyway, won't cloud the thread any more
-
What's the problem, exactly? KerbalEVA.lampOn seems to work exactly as you'd expect. Here's a snippet: [KSPAddon(KSPAddon.Startup.Flight, false)] public class LightChecker : MonoBehaviour { private bool lastStatus = false; void Update() { if (FlightGlobals.ActiveVessel != null && FlightGlobals.ActiveVessel.isEVA) { KerbalEVA evaPm = FlightGlobals.ActiveVessel.FindPartModulesImplementing<KerbalEVA>().Single(); if (evaPm.lampOn != lastStatus) { lastStatus = evaPm.lampOn; ScreenMessages.PostScreenMessage(string.Format("You turned {0} the lights!", evaPm.lampOn ? "on" : "off"), 3f, ScreenMessageStyle.LOWER_CENTER); } } } }
-
You have some code that looks like this: thiswheelCollider = GameObject.Find("wheelCollider"); This will find ANY GameObject named "wheelCollider" in the scene. If there is more than one with the same name, you can see how there might be trouble. Every instance of your PartModule is (I assume, I don't know how Unity searches internally) finding the exact same wheelCollider and printing its values. This thread from yesterday will probably be helpful to you.
-
There are a couple ways. It looks like PartTools rearranges the transforms a little, so here's something of a roadmap of the ingame hierarchy: [LOG 18:24:33.499] Transform: roverWheel1 [LOG 18:24:33.499] ---> Transform: model [LOG 18:24:33.500] ------> Transform: roverWheelBig [LOG 18:24:33.501] ---------> Transform: base [LOG 18:24:33.501] ------------> Transform: susp1-2 [LOG 18:24:33.502] ------------> Transform: susp2-2 [LOG 18:24:33.502] ------------> Transform: susp3-2 [LOG 18:24:33.503] ---------> Transform: suspensionNeutralPoint [LOG 18:24:33.504] ------------> Transform: steering [LOG 18:24:33.504] ---------------> Transform: wheelCollider [LOG 18:24:33.505] ---------> Transform: suspensionTraverse [LOG 18:24:33.506] ------------> Transform: bracket [LOG 18:24:33.506] ------------> Transform: susp1-1 [LOG 18:24:33.507] ---------------> Transform: susp3-1 [LOG 18:24:33.508] ------------> Transform: susp2-1 [LOG 18:24:33.508] ------------> Transform: trackSteering [LOG 18:24:33.509] ---------------> Transform: bustedwheel [LOG 18:24:33.510] ------------------> Transform: bustedwheel [LOG 18:24:33.510] ------------------> Transform: collisionEnhancer [LOG 18:24:33.511] ------------------> Transform: Object01 [LOG 18:24:33.512] ---------------> Transform: wheelMount [LOG 18:24:33.513] ------------------> Transform: wheel [LOG 18:24:33.513] ---------------------> Transform: collisionEnhancer [LOG 18:24:33.441] roverWheel1 has components: [LOG 18:24:33.441] ...c: UnityEngine.Transform [LOG 18:24:33.442] ...c: Part [LOG 18:24:33.443] ...c: ModuleWheel [LOG 18:24:33.443] ...c: FXModuleLookAtConstraint [LOG 18:24:33.444] ...c: FXModuleConstrainPosition [LOG 18:24:33.445] ...c: UnityEngine.AudioSource [LOG 18:24:33.445] ...c: UnityEngine.Rigidbody [LOG 18:24:33.446] ...c: CollisionEnhancer [LOG 18:24:33.446] ...c: PartBuoyancy [LOG 18:24:33.447] --->model has components: [LOG 18:24:33.448] ......c: UnityEngine.Transform [LOG 18:24:33.448] ------>roverWheelBig has components: [LOG 18:24:33.449] .........c: UnityEngine.Transform [LOG 18:24:33.450] --------->base has components: [LOG 18:24:33.450] ............c: UnityEngine.Transform [LOG 18:24:33.451] ............c: UnityEngine.BoxCollider [LOG 18:24:33.452] ............c: UnityEngine.MeshFilter [LOG 18:24:33.452] ............c: UnityEngine.MeshRenderer [LOG 18:24:33.453] ------------>susp1-2 has components: [LOG 18:24:33.454] ...............c: UnityEngine.Transform [LOG 18:24:33.454] ...............c: UnityEngine.MeshFilter [LOG 18:24:33.455] ...............c: UnityEngine.MeshRenderer [LOG 18:24:33.456] ------------>susp2-2 has components: [LOG 18:24:33.456] ...............c: UnityEngine.Transform [LOG 18:24:33.457] ...............c: UnityEngine.MeshFilter [LOG 18:24:33.458] ...............c: UnityEngine.MeshRenderer [LOG 18:24:33.458] ------------>susp3-2 has components: [LOG 18:24:33.459] ...............c: UnityEngine.Transform [LOG 18:24:33.460] ...............c: UnityEngine.MeshFilter [LOG 18:24:33.460] ...............c: UnityEngine.MeshRenderer [LOG 18:24:33.461] --------->suspensionNeutralPoint has components: [LOG 18:24:33.462] ............c: UnityEngine.Transform [LOG 18:24:33.462] ------------>steering has components: [LOG 18:24:33.463] ...............c: UnityEngine.Transform [LOG 18:24:33.464] --------------->wheelCollider has components: [LOG 18:24:33.464] ..................c: UnityEngine.Transform [LOG 18:24:33.465] ..................c: UnityEngine.WheelCollider [LOG 18:24:33.466] --------->suspensionTraverse has components: [LOG 18:24:33.467] ............c: UnityEngine.Transform [LOG 18:24:33.467] ------------>bracket has components: [LOG 18:24:33.468] ...............c: UnityEngine.Transform [LOG 18:24:33.469] ...............c: UnityEngine.BoxCollider [LOG 18:24:33.469] ...............c: UnityEngine.MeshFilter [LOG 18:24:33.470] ...............c: UnityEngine.MeshRenderer [LOG 18:24:33.471] ------------>susp1-1 has components: [LOG 18:24:33.471] ...............c: UnityEngine.Transform [LOG 18:24:33.472] ...............c: UnityEngine.MeshFilter [LOG 18:24:33.473] ...............c: UnityEngine.MeshRenderer [LOG 18:24:33.473] --------------->susp3-1 has components: [LOG 18:24:33.474] ..................c: UnityEngine.Transform [LOG 18:24:33.475] ..................c: UnityEngine.MeshFilter [LOG 18:24:33.475] ..................c: UnityEngine.MeshRenderer [LOG 18:24:33.476] ------------>susp2-1 has components: [LOG 18:24:33.477] ...............c: UnityEngine.Transform [LOG 18:24:33.478] ...............c: UnityEngine.MeshFilter [LOG 18:24:33.478] ...............c: UnityEngine.MeshRenderer [LOG 18:24:33.479] ------------>trackSteering has components: [LOG 18:24:33.480] ...............c: UnityEngine.Transform [LOG 18:24:33.481] --------------->bustedwheel has components: [LOG 18:24:33.481] ..................c: UnityEngine.Transform [LOG 18:24:33.482] ------------------>bustedwheel has components: [LOG 18:24:33.483] .....................c: UnityEngine.Transform [LOG 18:24:33.483] .....................c: UnityEngine.MeshFilter [LOG 18:24:33.484] .....................c: UnityEngine.MeshRenderer [LOG 18:24:33.485] ------------------>collisionEnhancer has components: [LOG 18:24:33.485] .....................c: UnityEngine.Transform [LOG 18:24:33.486] .....................c: UnityEngine.SphereCollider [LOG 18:24:33.487] ------------------>Object01 has components: [LOG 18:24:33.488] .....................c: UnityEngine.Transform [LOG 18:24:33.488] .....................c: UnityEngine.MeshFilter [LOG 18:24:33.489] .....................c: UnityEngine.MeshRenderer [LOG 18:24:33.490] --------------->wheelMount has components: [LOG 18:24:33.490] ..................c: UnityEngine.Transform [LOG 18:24:33.491] ..................c: UnityEngine.MeshFilter [LOG 18:24:33.492] ..................c: UnityEngine.MeshRenderer [LOG 18:24:33.492] ------------------>wheel has components: [LOG 18:24:33.493] .....................c: UnityEngine.Transform [LOG 18:24:33.494] .....................c: UnityEngine.MeshFilter [LOG 18:24:33.495] .....................c: UnityEngine.MeshRenderer [LOG 18:24:33.495] --------------------->collisionEnhancer has components: [LOG 18:24:33.496] ........................c: UnityEngine.Transform [LOG 18:24:33.497] ........................c: UnityEngine.SphereCollider You can see a transform named "model" in there where the Unity hierarchy got moved. KSP accesses this portion of the GameObject in a different way; you might've come across Part.FindModel* functions. Use those to find stuff you're looking for that's underneath the model section of the tree. So if you want to find a transform named "wheelCollider" you'll be wanting myPart.FindModelTransform("wheelCollider") You can use the base transform to do it, but for that you apparently need the whole path: transform.Find("model/roverWheelBig/suspensionNeutralPoint/steering/wheelCollider"); You can also look for the component(s) directly, being careful around cases where more than one might exist of course: var wc = part.FindModelComponent<WheelCollider>(); var wc2 = part.gameObject.GetComponentInChildren<WheelCollider>();