DMagic Posted November 15, 2015 Share Posted November 15, 2015 This one has probably been asked before, but...Does anyone know the best way to get a list of all loaded Part Modules? Not for the current vessel or scene, but all part modules loaded by KSP. Quote Link to comment Share on other sites More sharing options...
blowfish Posted November 15, 2015 Share Posted November 15, 2015 This one has probably been asked before, but...Does anyone know the best way to get a list of all loaded Part Modules? Not for the current vessel or scene, but all part modules loaded by KSP.You probably have to iterate through AssemblyLoader.loadedTypes Quote Link to comment Share on other sites More sharing options...
Diazo Posted November 15, 2015 Share Posted November 15, 2015 Erm, not sure actually.I think partModules exist as Unity GameObjects right? Can you do a FindAllObjects of type PartModule maybe?Failing that, I'd look at something like cycling each assembly through the assembly loader and finding all classes of type PartModule.D. Quote Link to comment Share on other sites More sharing options...
DMagic Posted November 15, 2015 Share Posted November 15, 2015 (edited) You probably have to iterate through AssemblyLoader.loadedTypesI think partModules exist as Unity GameObjects right? Can you do a FindAllObjects of type PartModule maybe?Failing that, I'd look at something like cycling each assembly through the assembly loader and finding all classes of type PartModule.D.I'm not sure if FindAllObjects will work (I was hoping to avoid something like that anyway, since it's so slow ), I think it only works on currently loaded objects of a type. So it would just find whatever Unity currently has instantiated.AssemblyLoader looks like it might work though. I guess I can try going through them all once at startup so I don't have to continually cycle through the whole list.Update:-------------------The answer to my specific need, in one line , is: var loadedPartModules = AssemblyLoader.loadedAssemblies.Where(a => a.types.ContainsKey(typeof(PartModule))).SelectMany(b => b.types[typeof(PartModule)]);For those of you who hate that sort of thing...First off, AssemblyLoader.loadedTypes isn't what it sounds like. It actually seems to be KSP's method of tracking which base Types to look for when loading assemblies. It has only four elements; Part, PartModule, ScenarioModule, and InternalModule.So what we have instead is AssemblyLoader.loadedAssemblies, which returns an instance of the subclass AssemblyLoader.LoadedAssembyList. This class is an IEnumerable that keeps a list of AssemblyLoader.LoadedAssemby. It also has a method GetTypeByName(Type baseType, string name), for finding a specific Type, if you are just looking for one, for instance: Type myModule = AssemblyLoader.loadedAssemblies.GetTypeByName(typeof(PartModule), "myStupidModule");That sort of thing might be an alternative to reflection in some cases.The AssemblyLoader.LoadedAssemby class has a bunch of info about each assembly and a dictionary of types. The dictionary uses the base type as a key. So the example aboveAssemblyLoader.loadedAssemblies.Where(a => a.types.ContainsKey(typeof(PartModule)))makes a list of all loaded assemblies that have types that inherit from PartModule.Then the next partSelectMany(b => b.types[typeof(PartModule)])just collects all of those types in a list (the value of each dictionary entry is a List<Type>). With a few mods installed I get around 130 PartModules, which sounds about right. Edited November 15, 2015 by DMagic Quote Link to comment Share on other sites More sharing options...
Kalzuron Posted November 19, 2015 Share Posted November 19, 2015 (edited) I'm wanting to use a layer for my mod, but I don't want to step on the toes of another modder. My questions are : 1. Do any other mods use layers and which ones? 2. Which layer would be the best to use so that it wouldn't cause issues later on? Edited November 19, 2015 by Kalzuron Quote Link to comment Share on other sites More sharing options...
RocketSquid Posted November 29, 2015 Share Posted November 29, 2015 I'm designing a mod that will add several new engines. Would it be better to base an electric fan on a stock jet engine or a stock rocket engine? This is just for the .cfg file, I can do the .mu myself. It will probably end up looking like a fan air intake, in fact I'm currently using the circular intake as a placeholder texture. Quote Link to comment Share on other sites More sharing options...
i_like_kerbals Posted December 29, 2015 Share Posted December 29, 2015 (edited) If this has already been answered (I'm sure it has), please link me to the post or page... Hi I am experienced with C#, can someone tell me what libraries I need to download for reference in my projects and a sample project that shows how to setup the entry point. Thanks! Basically I am new to KSP modding but not modding in general (I have written countless script mods in c# and c++ for GTA IV and GTA V), can someone please guide me on how to get started. Thanks! Edited December 29, 2015 by i_like_kerbals Quote Link to comment Share on other sites More sharing options...
NathanKell Posted December 29, 2015 Share Posted December 29, 2015 http://wiki.kerbalspaceprogram.com/wiki/Setting_up_Visual_Studio There are also tutorials on the wiki for other dev environments. In terms of entry points, there's quite a few now: partmodules, KSPAddons, scenario modules, contracts... Quote Link to comment Share on other sites More sharing options...
i_like_kerbals Posted December 29, 2015 Share Posted December 29, 2015 5 minutes ago, NathanKell said: http://wiki.kerbalspaceprogram.com/wiki/Setting_up_Visual_Studio There are also tutorials on the wiki for other dev environments. In terms of entry points, there's quite a few now: partmodules, KSPAddons, scenario modules, contracts... Thanks! Quote Link to comment Share on other sites More sharing options...
sarbian Posted December 30, 2015 Share Posted December 30, 2015 And hang on #kspmodders on esper. We may talk about modding from time to time. Maybe. When the planets aligns. Quote Link to comment Share on other sites More sharing options...
NathanKell Posted December 31, 2015 Share Posted December 31, 2015 And if you do, ping the regulars. We don't often follow it live, but do (sometimes) come when called. Quote Link to comment Share on other sites More sharing options...
JPLRepo Posted December 31, 2015 Share Posted December 31, 2015 I have a unique problem perhaps? Tarsier Space Tech mod that I maintain which has space telescopes. When playing in career mode, when taking pictures of far away bodies it actually completes the progresstracking events (reached and unmanned) for those bodies. Which means that KSP does not then generate the discover/visit contracts for those bodies. Looking at ProgressTracking class and ProgressTree class I couldn't not see any public classes that allow you to remove/reset/delete the tracking nodes. Does anyone know if there is a way to remove/reset these tracking events so that say I can remove/reset them when pictures are taken of far away bodies, or a way to not complete them when taking pictures of the bodies? Quote Link to comment Share on other sites More sharing options...
sarbian Posted December 31, 2015 Share Posted December 31, 2015 (edited) Is not done with a flag on the Body ? Check the body.DiscoveryInfo.Level before/after you look at it and reset it back with body.DiscoveryInfo.SetLevel(xx) I guess. (not sure / tested) Edit : or ProgressTracking.Instance.GetBodyTree(body) and look into the field in here. I think it more likely to be there. (not sure you can "unreach" a node however...) Edited December 31, 2015 by sarbian Quote Link to comment Share on other sites More sharing options...
JPLRepo Posted December 31, 2015 Share Posted December 31, 2015 1 hour ago, sarbian said: Is not done with a flag on the Body ? Check the body.DiscoveryInfo.Level before/after you look at it and reset it back with body.DiscoveryInfo.SetLevel(xx) I guess. (not sure / tested) Edit : or ProgressTracking.Instance.GetBodyTree(body) and look into the field in here. I think it more likely to be there. (not sure you can "unreach" a node however...) Ya thanks. I found already a ProgressTracking node is being saved saying body 'x' (eg: Duna) has been reached and Science has been completedUnmanned is being added into the ProgressTracking SCENARIO node (CelestialBodySubtree.science). There appears to be no way to 'remove' this as the set methods are private. Not sure I really want to be doing this anyway. The real problem here is KSP stops generating the "Explore x" contracts for any bodies that you take pictures of. Which I believe/think that the adding of the progresstracking node is what the contract system is checking and then stops generating the normal "Discover x" contracts. Not sure there is anything that can be done given what is exposed in the ProgressTracking and Contracts system. Quote Link to comment Share on other sites More sharing options...
sarbian Posted December 31, 2015 Share Posted December 31, 2015 Yep, I don't think you have any clean option beside asking a dev to add a way to reset a Progress for 1.1. @Arsonide ? @JPLRepo Load(ConfigNode node) is public for CelestialBodySubtree. You would have to rebuild the node. Awkward but I don't see any other way Or maybe the problem is that your mod trigger the flyby event. But I don't know how your telescope work.... Quote Link to comment Share on other sites More sharing options...
xEvilReeperx Posted December 31, 2015 Share Posted December 31, 2015 (edited) @JPLRepoI noticed that ProgressTree has a Deploy and Stow method which traverses the tree and runs some callbacks that hook/unhook each ProgressNode listener from their respective events. You could skip the ProgressNode (CelestialBodyScience) you're accidentally tripping by playing a little GameEvent shell game inside your contract using those callbacks... of course, it's a bit ugly // TSTTelescopeContract private void FakeCallback(float f, ScienceSubject s, ProtoVessel p, bool b) { GameEvents.OnScienceRecieved.Remove(FakeCallback); } protected override void AwardCompletion() { base.AwardCompletion(); var bodyName = GetParameter<TSTTelescopeContractParam>().target.name; var targetBody = FlightGlobals.Bodies.FirstOrDefault(cb => bodyName == cb.name); if (targetBody == null) { Debug.LogWarning("Couldn't find CelestialBody with name " + bodyName + " that " + typeof(TSTTelescopeContractParam).Name + " specifies"); return; } var subtree = ProgressTracking.Instance.GetBodyTree(targetBody); if (subtree.science.Subtree.Count > 0) { Debug.LogWarning("Multiple science subtree nodes for " + bodyName + " -- investigate"); return; } subtree.science.OnStow(); // removes it from onScienceReceived GameEvents.OnScienceRecieved.Add(FakeCallback); // we need a fake callback because the one that triggered this method call was removed by // TSTScienceParam.OnUnregister. GameEvent callbacks are stored in a list and called in reverse order // so the subtree.science callback we're about to add would otherwise be the next called subtree.science.OnDeploy(); // adds to end of onScienceReceived } Edited December 31, 2015 by xEvilReeperx Quote Link to comment Share on other sites More sharing options...
JPLRepo Posted December 31, 2015 Share Posted December 31, 2015 (edited) On 31/12/2015 at 2:57 AM, xEvilReeperx said: @JPLRepoI noticed that ProgressTree has a Deploy and Stow method which traverses the tree and runs some callbacks that hook/unhook each ProgressNode listener from their respective events. You could skip the ProgressNode (CelestialBodyScience) you're accidentally tripping by playing a little GameEvent shell game inside your contract using those callbacks... of course, it's a bit ugly <snip> @xEvilReeperx Thanks for that. Was so busy looking at ProgressTree and Contracts I didn't look at ProgressNode. Your code seems the best solution given ProgressNode does not have the set methods exposed. Your work-around stops the ProgressTree from adding the science node. I am yet to prove this fixes the Contracts for exploring the bodies, working through a test now to see if I can get one to generate. Seems to have resolved the problem. No longer adds progress for science when taking pictures and generating the usual flyby/visit etc contracts. @sarbian Thanks for your help as well! Edited January 1, 2016 by JPLRepo Quote Link to comment Share on other sites More sharing options...
hab136 Posted January 9, 2016 Share Posted January 9, 2016 (edited) 1. Is there any way to mark the VAB editor as dirty, so that it will prompt you to save if you try to load another ship? The use case is that I've modified the ship in the editor, saved the ship to a temporary file and then re-loaded it. The editor thinks it hasn't been modified (since it was just loaded), but really it is different from the ship the user gave me, and should be treated as such. 2. Is there any simple way to get an icon of a part, like the icons where you pick parts from the editor? I know KIS renders icons for parts, but a cursory glance over their source made me realize I know nothing about the camera and lighting system, and don't really mess with GameObjects much. I'd be perfectly fine with copying the icons that the editor has already rendered, but I haven't figured out how. I really just want a method "Texture2D icon = AvailablePart.RenderIcon(sizeX,sizeY)" which doesn't exist These are the type of icons I want: Edited January 9, 2016 by hab136 add image Quote Link to comment Share on other sites More sharing options...
sarbian Posted January 10, 2016 Share Posted January 10, 2016 @hab136 1. try calling EditorLogic.fetch.SetBackup() 2. IDK Quote Link to comment Share on other sites More sharing options...
hab136 Posted January 10, 2016 Share Posted January 10, 2016 2 hours ago, sarbian said: @hab136 1. try calling EditorLogic.fetch.SetBackup() 2. IDK Thanks, SetBackup() was exactly it. Quote Link to comment Share on other sites More sharing options...
xEvilReeperx Posted January 10, 2016 Share Posted January 10, 2016 16 hours ago, hab136 said: 2. Is there any simple way to get an icon of a part, like the icons where you pick parts from the editor? I know KIS renders icons for parts, but a cursory glance over their source made me realize I know nothing about the camera and lighting system, and don't really mess with GameObjects much. I'd be perfectly fine with copying the icons that the editor has already rendered, but I haven't figured out how. I really just want a method "Texture2D icon = AvailablePart.RenderIcon(sizeX,sizeY)" which doesn't exist The editor isn't using pre-rendered icons; there's actually a separate layer where instances of the icon are being rendered (think of the way you're looking at actual pieces of candy in a vending machine). If you wanted to do things with them like rotate or play animations, you'd need to set up a camera and do something similar. If you just need a static image, I've adapted some code from another of my projects that should get you there: [KSPAddon(KSPAddon.Startup.SpaceCentre, false)] public class PartIconSnapshot : MonoBehaviour { private const int IconWidth = 256; private const int IconHeight = 256; private Rect _rect = new Rect(0f, 0f, 120f, 120f); private Texture2D _selectedIcon = new Texture2D(1, 1); private int _partIndex = 0; private void Start() { _rect.center = new Vector2(Screen.width * 0.5f, Screen.height * 0.5f); CreatePartIconForCurrentPart(); } private void OnGUI() { _rect = KSPUtil.ClampRectToScreen(GUILayout.Window(GetInstanceID(), _rect, DrawWindow, "PartIconSnapshot")); } private void DrawWindow(int winid) { GUILayout.BeginHorizontal(); { if (GUILayout.Button("<<")) PreviousIcon(); if (GUILayout.Button(">>")) NextIcon(); GUILayout.FlexibleSpace(); GUILayout.Label(PartLoader.LoadedPartsList[_partIndex].name, GUILayout.ExpandWidth(true)); } GUILayout.EndHorizontal(); var textureRect = GUILayoutUtility.GetRect(IconWidth, IconHeight, GUILayout.ExpandWidth(false), GUILayout.ExpandHeight(false)); if (Event.current.type == EventType.Repaint) Graphics.DrawTexture(textureRect, _selectedIcon); GUI.DragWindow(); } private void PreviousIcon() { if (--_partIndex < 0) _partIndex = PartLoader.LoadedPartsList.Count - 1; CreatePartIconForCurrentPart(); } private void NextIcon() { if (++_partIndex >= PartLoader.LoadedPartsList.Count) _partIndex = 0; CreatePartIconForCurrentPart(); } private void CreatePartIconForCurrentPart() { CreatePartIconSnapshot(PartLoader.LoadedPartsList[_partIndex]); } private void CreatePartIconSnapshot(AvailablePart part) { if (part == null) throw new ArgumentNullException("part"); Destroy(_selectedIcon); _selectedIcon = PartIconGenerator.Create2D(part, IconWidth, IconHeight, Quaternion.AngleAxis(-15f, Vector3.right) * Quaternion.AngleAxis(-30f, Vector3.up), Color.clear); } } public static class PartIconGenerator { private const string IconHiddenTag = "Icon_Hidden"; private const string KerbalEvaSubstring = "kerbal"; private static readonly int GameObjectLayer = LayerMask.NameToLayer("PartsList_Icons"); // note to future: if creating icons inside editor, you might want to choose a different layer or translate the camera and object out of frame private static Camera CreateCamera(int pixelWidth, int pixelHeight, Color backgroundColor) { var camGo = new GameObject("PartIconGenerator.Camera", typeof (Camera)); var cam = camGo.camera; cam.enabled = false; cam.cullingMask = (1 << GameObjectLayer); cam.clearFlags = ~CameraClearFlags.Nothing; cam.nearClipPlane = 0.1f; cam.farClipPlane = 10f; cam.orthographic = true; cam.backgroundColor = backgroundColor; cam.aspect = pixelWidth / (float) pixelHeight; // Camera Size = x / ((( x / y ) * 2 ) * s ) cam.orthographicSize = pixelWidth / (((pixelWidth / (float) pixelHeight) * 2f) * pixelHeight); cam.pixelRect = new Rect(0f, 0f, pixelWidth, pixelHeight); return cam; } private static Light CreateLight() { var light = new GameObject("PartIconGenerator.Light").AddComponent<Light>(); light.type = LightType.Directional; light.color = XKCDColors.OffWhite; light.cullingMask = 1 << GameObjectLayer; light.intensity = 0.5f; return light; } private static GameObject CreateIcon(AvailablePart part) { // kerbalEVA doesn't seem to init at origin if we aren't explicit var go = Object.Instantiate(part.iconPrefab, Vector3.zero, Quaternion.identity) as GameObject; // The kerbals are initially facing along positive Z so we'll be looking at their backs if we don't // rotate them around if (part.name.StartsWith(KerbalEvaSubstring)) go.transform.rotation = Quaternion.AngleAxis(180f, Vector3.up); go.SetLayerRecursive(GameObjectLayer); go.SetActive(true); return go; } private static void AdjustScaleAndCameraPosition(GameObject icon, Camera camera) { // get size of prefab var bounds = CalculateBounds(icon); float sphereDiameter = Mathf.Max(bounds.size.x, bounds.size.y, bounds.size.z); // rescale to size 1 unit so that object will take up as much viewspace as possible in ortho cam (with ortho size = 0.5) var currentScale = icon.transform.localScale; float scaleFactor = 1f / sphereDiameter; icon.transform.localScale = currentScale * scaleFactor; icon.transform.position = -bounds.center * scaleFactor; camera.transform.position = Vector3.zero; // back out, else we'll be inside the model (which is scaled at 1 unit so this should be plenty) camera.transform.Translate(new Vector3(0f, 0f, -5f), Space.Self); camera.transform.LookAt(Vector3.zero, Vector3.up); } public static Texture2D Create2D(AvailablePart part, int width, int height, Quaternion orientation, Color backgroundColor) { var cam = CreateCamera(width, height, backgroundColor); var icon = CreateIcon(part); var light = CreateLight(); var texture = new Texture2D(width, height, TextureFormat.ARGB32, false); var rt = RenderTexture.GetTemporary(width, height, 24); var prevRt = RenderTexture.active; RenderTexture.active = rt; icon.transform.rotation = orientation * icon.transform.rotation; AdjustScaleAndCameraPosition(icon, cam); cam.targetTexture = rt; cam.pixelRect = new Rect(0f, 0f, width, height); // doc says this should be ignored but doesn't seem to be (?) -- rendered area very small once targetTexture is set cam.Render(); texture.ReadPixels(new Rect(0f, 0f, width, height), 0, 0, false); texture.Apply(); RenderTexture.active = prevRt; RenderTexture.ReleaseTemporary(rt); Object.DestroyImmediate(light); Object.DestroyImmediate(cam); Object.DestroyImmediate(icon); return texture; } private static Bounds CalculateBounds(GameObject go) { var renderers = go.GetComponentsInChildren<Renderer>(true).ToList(); if (renderers.Count == 0) return default(Bounds); var boundsList = new List<Bounds>(); renderers.ForEach(r => { if (r.tag == IconHiddenTag) return; if (r is SkinnedMeshRenderer) { var smr = r as SkinnedMeshRenderer; // the localBounds of the SkinnedMeshRenderer are initially large enough // to accomodate all animation frames; they're likely to be far off for // parts that do a lot of animation-related movement (like solar panels expanding) // // We can get correct mesh bounds by baking the current animation into a mesh // note: vertex positions in baked mesh are relative to smr.transform; any scaling // is already baked in var mesh = new Mesh(); smr.BakeMesh(mesh); // while the mesh bounds will now be correct, they don't consider orientation at all. // If a long part is oriented along the wrong axis in world space, the bounds we'd get // here could be very wrong. We need to come up with essentially the renderer bounds: // a bounding box in world space that encompasses the mesh var m = Matrix4x4.TRS(smr.transform.position, smr.transform.rotation, Vector3.one /* remember scale already factored in!*/); var vertices = mesh.vertices; var smrBounds = new Bounds(m.MultiplyPoint3x4(vertices[0]), Vector3.zero); for (int i = 1; i < vertices.Length; ++i) smrBounds.Encapsulate(m.MultiplyPoint3x4(vertices[i])); Object.Destroy(mesh); boundsList.Add(smrBounds); } else if (r is MeshRenderer) // note: there are ParticleRenderers, LineRenderers, and TrailRenderers { r.gameObject.GetComponent<MeshFilter>().sharedMesh.RecalculateBounds(); boundsList.Add(r.bounds); } }); Bounds bounds = boundsList[0]; boundsList.Skip(1).ToList().ForEach(b => bounds.Encapsulate(b)); return bounds; } } Note that doing it this way (ReadPixels into a texture) is quite slow, not to mention the mesh baking it does if the part has an animation so call it as rarely as possible Quote Link to comment Share on other sites More sharing options...
grimlock14 Posted January 18, 2016 Share Posted January 18, 2016 What section code controls which actions of a part can be set as Action Groups? For example, what would I have to change if I wanted make an MPL transmit its science using an Action Group. I've already tried AGX, but that doesn't allow me to make something from the right-click menu "actionable." Quote Link to comment Share on other sites More sharing options...
sarbian Posted January 18, 2016 Share Posted January 18, 2016 50 minutes ago, grimlock14 said: What section code controls which actions of a part can be set as Action Groups? For example, what would I have to change if I wanted make an MPL transmit its science using an Action Group. I've already tried AGX, but that doesn't allow me to make something from the right-click menu "actionable." [KSPAction("Do something")] public void MyAmazingActionMethod(KSPActionParam param) { // Stuff } Quote Link to comment Share on other sites More sharing options...
Diazo Posted January 19, 2016 Share Posted January 19, 2016 Unfortunately, actions as assignable to action groups and the objects in the right-click menu have no relation at all to each other. As Sarbian showed, code in the partModule that is tagged 'KSPAction' will show as an action while code tagged 'KSPEvent' or 'KSPField' will show in the right-click menu. There is no way to tag the same piece of code with more then one flag so generally, the 'KSPEvent' is where things actually happen and the mod maker makes a small code snippet tagged with 'KSPAction' that does nothing but trigger the 'KSPEvent' code. To make something in the right-click menu actionable requires that 'KSPAction' code to be added. Either talk to the creator of MPL science and ask for it to be added or look at something like my ModActions mod that can do this. As you mentioned AGX does not do this, it only adds more action groups, but it is still a very common request and I'm working on trying to make this work for players with the ModActions mod. D. Quote Link to comment Share on other sites More sharing options...
hab136 Posted January 23, 2016 Share Posted January 23, 2016 On 1/10/2016 at 5:58 PM, xEvilReeperx said: I've adapted some code from another of my projects that should get you there: Oh man, that was 105% of what I needed. Behold my new part selector in all its glory: Thanks so much! Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.