Jump to content

Couple of c# / API questions.


Recommended Posts

Hi all,

Been poking around here for a while, and have started on a mod (which for the moment is a secret....sssshhhh :-P)

I'm making really good progress so far but I'm very very new to c#, I have some knowledge of vb.net, so the translation isn't too hard so far.

Chances are I'll have a few more questions on how to do a couple of things I need to do, but for now I'll start with.......

What I have at the moment is a bunch of objects spread around Kerbin and what I would like to do is get the straight line distance value between a Kerbal and the closest of these objects (all of the objects will be identical, so I'll also need a way to identify them, but I assume there will be a method to add a 'tag' or something to said objects, so not worried about that for the moment :)).  The idea being that when said Kerbal is within a certain distance of this object a GUI window pops open.

Would anyone be able to point me in the right direction as to what to use to get this number?

Thanks

TheMightySpud

Edited by TheMightySpud
Link to comment
Share on other sites

 

double distance = Vector3d.Distance(FlightGlobals.ActiveVessel.GetWorldPos3D(), YOURTHINGY.GetWorldPos3D());

The answer to a lot of low level questions like this is frequently easier to find if you just google for Unity info instead of KSP specifically.  Like "Unity Distance Between Two Points".  Good luck and shout at us if you have more questions!

Link to comment
Share on other sites

Excellent, thank you :)

Really appreciate you taking the time to reply :)

Next problem I'm having is how to assign my object to 'YOURTHINGY' in the 'YOURTHINGY.GetWorldPos3D()' part.  :-/  Seems like it should be a very simple thing, but having a devil of a time figuring it out.

Reading lots, but not really making a lot of sense to me. lol.

Thanks

TheMightySpud

Link to comment
Share on other sites

Hi again all,

I have another annoying question. :-P

As part of my mod I'd like to spawn a bunch of Parts as vessels over the surface of a planet/moon at the games startup, I think I've got the positioning etc. all sorted in my head at least, the problem I'm having it getting things to actually spawn. :-/  I've been playing around with the ProtoVessel bits and pieces but I'll be honest, the usage and syntax is kicking my backside.

I've had a poke around at the source of a few mods that kinda do something similar, but again I'm having a real hard time making heads or tails of how it all works.

Could someone point me in the right direction? (Just want to be clear and say I'm not looking for someone to spoonfeed the code to me, just a general idea of where to look for answers :))

 

Thanks,

TheMightySpud

Link to comment
Share on other sites

Sooooo,

I've got some code that should (and I stress should) spawn an object at run time.......logically in my head it should work, but I'm probably doing something really stupid.

At the moment, if I'm reading the log correctly, I don't think this code is even running, I've been staring at it and trying various things for several hours so I would be most appreciative if someone could take a look and point out where I've been an idiot :)

public class TMS_Module_Test_001
    {
        public void Onstart()
        {
            // Create a new blank vessel
            Vessel newVessel = new Vessel();

            // Add a part to the vessel
            Debug.Log("getPartInfoByName");
            AvailablePart avPart = PartLoader.getPartInfoByName("TMS_Module_001");
            
            Debug.Log("Instantiate");
            UnityEngine.Object obj = UnityEngine.Object.Instantiate(avPart.partPrefab);
            
            Debug.Log("newPart");
            Part newPart = (Part)obj;
            
            Debug.Log("rootPart ; parts.Add()");
            newPart.gameObject.name = "TMS_Module_001";
            newPart.partInfo = avPart;
            newVessel.rootPart = newPart;
            newVessel.parts = new List<Part>();
            newVessel.parts.Add(newPart);

            // Set vessel parameters
            Debug.Log("Set vessel params");
            newVessel.name = "Test_Module_001";
            newVessel.Landed = true;
             newVessel.Splashed = false;
             newVessel.landedAt = string.Empty;
            newVessel.situation = Vessel.Situations.LANDED;
            newVessel.vesselType = VesselType.Debris;
            newVessel.transform.position = new Vector3(5f,0f,5f);

            newVessel.GoOffRails();
            newVessel.Load();
        }
    }

 

As I said I'm very new to C# so not really sure what I'm doing wrong, but logically I'm creating a new vessel, adding a part, defining all the attributes of the new vessel and then spawning it.

 

TheMightySpud

Link to comment
Share on other sites

New to modding myself so grain of salt and all. If this is a partless plugin - that is it's not attached to a part - I think you'll need to derive your class from MonoBehaviour (you'll want to double check that) to get it to run in game. As for creating vessels I would dig into the Extra Planetary Launchpads code -unfortunately there's a lot of it.

Good luck!

Link to comment
Share on other sites

FlightGlobals.Vessels is a list of all vessels in the game.  You could iterate or search through it and look for the object with the right name, launch number, location...  whatever you can locate it by.

 

And @wasml is right - you've got to inherit from MonoBehavior for a partless plugin to get it's code to actually get called.  https://github.com/taraniselsu/TacExamples/blob/master/01-SimplePartlessPlugin/Source/SimplePartlessPlugin.cs will show you a simple example of how it's done.

 

I haven't dealt with spawning before, so I can't really comment on that part of what you're doing!

Edited by artwhaley
Link to comment
Share on other sites

Thanks for the responses guys, really appreciate it. :)

I've updated my code a little, and finally figured out I was using the wrong debug window *dumbass* lol.  I was using the one in the Alt+F12 menu, but discovered the Alt+f2 window this morning, which is far more helpful.

So the code is here, the problems are listed below (there is only one that I can see, well two, but we'll come to the second one in due time :))

using UnityEngine;
using KSP.IO;
using System.Collections.Generic;

namespace TMS_Module_001
{
    [KSPAddon(KSPAddon.Startup.SpaceCentre, true)]

    public class TMS_Module_001 : MonoBehaviour
    {
        public void Awake()
        {
            // Create a new blank vessel
            Vessel newVessel = new Vessel();

            // Add a part to the vessel
            
            Debug.Log("getPartInfoByName");
            AvailablePart avParts = PartLoader.getPartInfoByName("GearFixed");

            Debug.Log("Instantiate");
            //UnityEngine.Object obj = UnityEngine.Object.Instantiate(avParts.partPrefab);
            if (avParts != null)
            {
                UnityEngine.Object obj = Instantiate(avParts.partPrefab, new Vector3(0f, 0f, 0f), Quaternion.identity);
                Debug.Log("newPart");
                Part newPart = (Part)obj;
                Debug.Log("rootPart ; parts.Add()");
                newPart.gameObject.name = "TMS_Module_001";
                newPart.partInfo = avParts;
                newVessel.rootPart = newPart;
                newVessel.parts = new List<Part>();
                newVessel.parts.Add(newPart);

                // Set vessel parameters
                Debug.Log("Set vessel params");
                Debug.Log("-----------------");


                Debug.Log("Set vessel name");
                if (newVessel != null)
                {
                    newVessel.name = "TMS_Module_001";
                }
                else
                {
                    Debug.Log("Vessel is Empty");
                }



                Debug.Log("Set Landed status");
                if (newVessel != null)
                {
                newVessel.Landed = true;
                }
                else
                {
                    Debug.Log("Vessel is Empty");
                }



                Debug.Log("Set Splashed status");
                if (newVessel != null)
                {
                newVessel.Splashed = false;
                }
                else
                {
                    Debug.Log("Vessel is Empty");
                }



                Debug.Log("Set LandedAt status");
                 if (newVessel != null)
                {
                newVessel.landedAt = string.Empty;
                }
                else
                {
                    Debug.Log("Vessel is Empty");
                }



                Debug.Log("Set Landed status");
                if (newVessel != null)
                {
                newVessel.situation = Vessel.Situations.LANDED;
                }
                else
                {
                    Debug.Log("Vessel is Empty");
                }


                Debug.Log("Set vessel type");
                if (newVessel != null)
                {
                newVessel.vesselType = VesselType.Debris;
                }
                else
                {
                    Debug.Log("Vessel is Empty");
                }


                Debug.Log("Set vessel Position");
                if (newVessel != null)
                {
                newVessel.transform.position = new Vector3(5f, 0f, 5f);
                }
                else
                {
                    Debug.Log("Vessel is Empty");
                }

                newVessel.GoOffRails();
                newVessel.Load();
            }
            else
            {
                print("Part Not Found");
            }

            

        }
    }
}

 

After a little more poking around I decided to go with the KSPAddon bit, and the code executes exactly when I want it to, which is great. :)  (yes I realise that my module will spawn every time I go to the space center at the moment, but I'll be adding a check to see if the object already exists when I finally get it to spawn. :)

 

So onto the main problem.  According to the Log, the 'newVessel' Vessel, never gets populated.  As you can see I've added a bunch of debug commands to see what's going on and each line prints out the debug info (Vessel is Empty) So right off the bat there's nothing there which is stopping pretty much everything else, and I can't seem to figure out the problem.

Any insight would be greatly appreciated.

Thanks

TheMightySpud

Link to comment
Share on other sites

Apologies, forgot to address @wasml's comments.

I've looked at a bunch of 'spawning' mods, but to be completely honest, I can't make head nor tail of any of them.  I'm still very new to the whole class thing and find it really confusing as to what's referencing what etc. (especially in other people's code).  I'm primarily a Modeller but do have a little background in coding (PHP/HTML, a little vb.net, a little python etc) but nothing as complicated as some of the things I've seen on here. lol.

TheMightySpud

Link to comment
Share on other sites

Right then, completely changed my approach.

I found a plugin that was a lot easier to 'read' than the others I've seen.  Typically I now can't find the thread (The mod is called KSPSmelter) to give proper credit, as soon as I do though I will.

The Smelter mod makes use of code modified from Planetary Launch systems (I believe) and the Kerbal Attachment system.

I'm making progress on whittling down what I need and modifying it to be a partless mod.

But I've hit something of a roadblock with an exception error. (I think I've commented something important out. lol.)

This is the vehicle 'Spawner code'

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;

namespace TMS_Module_001
{

    /// <summary>
    /// This class is pretty much built on what KAS uses to pull parts out of containers
    /// All credit to https://github.com/KospY/KAS
    /// https://github.com/KospY/KAS/blob/master/LICENSE.md
    /// </summary>
    public class VesselSpawner
    {
        const string PluginPath = "\\GameData\\TMSOrbitalMechanics\\PluginData\\";

        private HideConfigNode _OldVabShip;
        private string _craftFile = "";
        private string vesselName = "";
        private Vector3 vesselPosition = new Vector3(0, 0, 0);
        //private Part _srcPart = null;


        /// <summary>
        /// 
        /// </summary>
        /// <param name="_craftFile">Craft file name as it appears in the PluginPath folder</param>
        /// <param name="_srcPart">Source part to spawn relative to</param>
        /// <param name="_spawnOffset">Offset spawn from Source part position</param>
        //public VesselSpawner(string _craftFile, Vector3 _spawnOffset)
        public VesselSpawner(string _craftFile, string vesselName, Vector3 vesselPosition)
        {
            //Store paths
            this._craftFile = _craftFile;
            //this._srcPart = _srcPart;
            this.vesselPosition = vesselPosition;
            this.vesselName = vesselName;

            //if (this._srcPart == null)
            //    Debug.Log("Relative source part can't be null");
            //if ((_craftFile != String.Empty))
            //    Debug.Log("Source part path can't be null");

        }

        /// <summary>
        /// Spawns the vessel
        /// </summary>
        public void SpawnVessel()
        {
            Debug.Log("SpawnVessel");
            //Load craft file
            ShipConstruct _ship = LoadVessel(this._craftFile);
            if (_ship != null)
                SpawnVessel(this.vesselName, _ship, this.vesselPosition);
            else
                Debug.Log("Failed to load the vessel");
        }


        /// <summary>
        /// Attempt vessel load
        /// </summary>
        /// <param name="_craftFile"></param>
        /// <returns></returns>
        private ShipConstruct LoadVessel(string _craftFile)
        {
            Debug.Log("ConstructVessel");
            //Get path to vessel
            Debug.Log("Loading the craft file");
            string BasePath = Environment.CurrentDirectory + PluginPath;
            string path = BasePath + _craftFile;
            Debug.Log(path);
            //Save old ship for later, else player will see it in the VAB
            _OldVabShip = new HideConfigNode(ShipConstruction.ShipConfig);

            //Load craft file
            ShipConstruct _shipConstruct = ShipConstruction.LoadShip(path);

            //Check load
            Debug.Log("Checking if its loaded");
            if (_shipConstruct == null)
            {
                // Restore ShipConstruction ship, otherwise player sees loaded craft in VAB
                ShipConstruction.ShipConfig = _OldVabShip.GetConfigNode();
                return null; //Fail
            }
            Debug.Log("Sending it back");
            return _shipConstruct;
        }


        /// <summary>
        /// Spawn ship construct
        /// https://github.com/KospY/KAS/blob/master/Plugin/KAS_Shared.cs
        /// </summary>
        /// <param name="_shipConstruct">Shipconstruct to spawn</param>
        /// <param name="_srcPart">Source part to spawn relative to</param>
        /// <param name="_spawnOffset">Offset spawn from Source part position</param>
        private void SpawnVessel(string vesselName, ShipConstruct _shipConstruct, Vector3 _spawnOffset)
        {
            Debug.Log("PrivateSpawnVessel");
            //Store construct root
            Part _newConstructRootPart = _shipConstruct.parts[0];

            Debug.Log("Doing something with the Root");
            //Center rootpart
            Vector3 offset = _newConstructRootPart.transform.localPosition;
            _newConstructRootPart.transform.Translate(-offset);

            //Get launch spawn point, relative to part
            //Transform t = _srcPart.transform;
            //GameObject launchPos = new GameObject();
            //launchPos.transform.parent = _srcPart.transform;
            //launchPos.transform.position = t.position;
            //launchPos.transform.position += t.TransformDirection(_spawnOffset);
            //launchPos.transform.rotation = t.rotation;


            //Store our launch / spawn position
            //Transform launchTransform = launchPos.transform;


            //Kill original object
            //launchPos.DestroyGameObject();


            //Set rootpart origin
            //_shipConstruct.Parts[0].localRoot.transform.Translate(launchPos.transform.position, Space.World);


            //Position
            //float angle;
            //Vector3 axis;


            //Extract ToAngleAxis data from selected spawning location
            //launchTransform.rotation.ToAngleAxis(out angle, out axis);


            //TRANSFORM Rotate localRootPart in relation to root
            //_shipConstruct.Parts[0].localRoot.transform.RotateAround(launchTransform.position, axis, angle);

            //Create vessel object
            Debug.Log("CreateVesselObject");
            Vessel _newVessel = _newConstructRootPart.localRoot.gameObject.AddComponent<Vessel>();

            //Init from VAB
            _newVessel.Initialize(true);

            Debug.Log("Adding all the info to the ship");
            //Attach vessel information
            _newVessel.id = Guid.NewGuid();
            _newVessel.name = vesselName;
            _newVessel.Landed = true;
            _newVessel.Splashed = false;
            _newVessel.landedAt = string.Empty;
            _newVessel.situation = Vessel.Situations.LANDED;
            _newVessel.vesselType = VesselType.Debris;
            Vector3 vesselPosition = new Vector3(5f, 0f, 5f);

            //_newVessel.vesselName = _srcPart.vessel.vesselName + " - " + _shipConstruct.shipName;
            //_newVessel.landedAt = _srcPart.vessel.vesselName;

            //Store backup
            ShipConstruction.CreateBackup(_shipConstruct);


            Debug.Log("MissionIDStuff");
            //Set Orbit
            //InitiateOrbit(vesselPosition, _newVessel);

            //Set Mission info
            Debug.Log("Set Mission ID");
            uint missionId = (uint)Guid.NewGuid().GetHashCode();
            //string flagUrl = _srcPart.flagURL;
            Debug.Log("Set Launch ID");
            uint launchId = HighLogic.CurrentGame.launchID++;

            //Set part mission info
            for (int i = 0; i < _newVessel.parts.Count; i++)
            {
                Debug.Log("Loop through parts");
                Part part = _newVessel.parts[i];
                Debug.Log("Assign FlightID using ShipConstruction");
                part.flightID = ShipConstruction.GetUniqueFlightID(FlightDriver.FlightStateCache.flightState);
                Debug.Log("Done it Once");
                part.launchID = launchId;
                part.missionID = missionId;
            }
            Debug.Log("Finished Mission Stuff");
            //Generate staging
            //Staging.beginFlight();
            //_newConstructRootPart.vessel.ResumeStaging();
            //Staging.GenerateStagingSequence(_newConstructRootPart.localRoot);
            //Staging.RecalculateVesselStaging(_newConstructRootPart.vessel);

            //Set position, again
            //_newVessel.SetPosition(launchTransform.position);
            //_newVessel.SetRotation(launchTransform.rotation);

            ////Get allll the parts, does it even matter since we launch from VAB?
            //for (int i = 0; i < _newVessel.parts.Count; i++)
            //{
            //    // Solar panels from containers (we dont have no bloody containers here tho) don't work otherwise
            //    for (int j = 0; j < _newVessel.parts[i].Modules.Count; j++)
            //    {
            //        ConfigNode node = new ConfigNode();
            //        node.AddValue("name", _newVessel.parts[i].Modules[j].moduleName);
            //        _newVessel.parts[i].LoadModule(node, ref j);
            //    }
            //}

            Debug.Log("ProtoVesselStuff");
            //Save Protovessel
            ProtoVessel _newProto = new ProtoVessel(_newVessel);

            Debug.Log("Defined ProtoVessel");

            if (_newProto == null)
            {
                Debug.Log("Nope");
            }

            else
            {
                Debug.Log("If Statement if not failed");

                //Kill and remove spawned vessel, had some serious problems with spawn position warping/glitching
                _newVessel.Die();

                //Set the protovessels position to the relative one we found, maybe redundant
                //_newProto.position = launchPos.transform.position;

                //If you check this value, you will see the height change from launch scene to resume scene, extra dafuq
                float height = _newProto.height;

                if (FlightDriver.StartupBehaviour == FlightDriver.StartupBehaviours.RESUME_SAVED_FILE ||
                    FlightDriver.StartupBehaviour == FlightDriver.StartupBehaviours.RESUME_SAVED_CACHE)
                {
                    //Odd behaviour with positioning during different flight scenes, workaround awaaaay
                    //_newProto.height = TrueAlt(launchTransform.position, _srcPart.vessel);
                }

                //Load Protovessel
                _newProto.Load(HighLogic.CurrentGame.flightState);

                // Restore ShipConstruction ship, otherwise player sees loaded craft in VAB
                ShipConstruction.ShipConfig = _OldVabShip.GetConfigNode();

                //Fix Control Lock
                //FlightInputHandler.ResumeVesselCtrlState(FlightGlobals.ActiveVessel);

                //Fix active vessel staging
                //FlightGlobals.ActiveVessel.ResumeStaging();
            }

        }

        /// <summary>
        /// http://forum.kerbalspaceprogram.com/threads/111116-KSP-Altitude-Calculation-Inquiry
        /// </summary>
        /// <returns></returns>
        //private float TrueAlt(Vector3 _LauncPos, Vessel _srcVessel)
        //{
        //    Debug.Log("Altitude Stuff?");
        //    //Vector3 pos = _srcPart.transform.position; //or this.vessel.GetWorldPos3D()
        //    float ASL = FlightGlobals.getAltitudeAtPos(_LauncPos);
        //    if (_srcVessel.mainBody.pqsController == null) { return ASL; }
        //    float terrainAlt = Convert.ToSingle(_srcVessel.pqsAltitude);
        //    if (_srcVessel.mainBody.ocean && _srcVessel.heightFromTerrain <= 0) { return ASL; } //Checks for oceans
        //    return ASL - terrainAlt;
        //}

        /// <summary>
        /// https://github.com/taniwha-qf/Extraplanetary-Launchpads/blob/master/Source/BuildControl.cs
        /// https://github.com/taniwha-qf/Extraplanetary-Launchpads/blob/master/License.txt
        /// </summary>
        /// <param name="_newVessel"></param>
        /// <param name="_srcVessel"></param>
        //private void InitiateOrbit(Vector3 vesselPosition, Vessel _newVessel)
        //{
        //   Debug.Log("More OrbitStuff");
        //    var mode = OrbitDriver.UpdateMode.UPDATE;
        //    _newVessel.orbitDriver.SetOrbitMode(mode);
        //
        //   var craftCoM = GetVesselWorldCoM(_newVessel);
        //    var vesselCoM = vesselPosition;
        //    var offset = (Vector3d.zero + craftCoM - vesselCoM).xzy;
        //
        //    var corb = _newVessel.orbit;
        //    //var orb = _srcVessel.orbit;
        //    var UT = Planetarium.GetUniversalTime();
        //    //var body = orb.referenceBody;
        //    //corb.UpdateFromStateVectors(orb.pos + offset, orb.vel, body, UT);

        //Debug.Log(String.Format("[EL] {0} {1}", "orb", orb.pos));
        //    Debug.Log(String.Format("[EL] {0} {1}", "corb", corb.pos));

        //}


        //public Vector3 GetVesselWorldCoM(Vessel v)
        //{
        //    var com = v.findLocalCenterOfMass();
        //    return v.rootPart.partTransform.TransformPoint(com);
        //}
    }
}

 

And here is the code I'm using to call the class etc.

There are a few things that I will need to change later on down the line one I get the actual spawning part working.

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;

namespace TMS_Module_001
{
    [KSPAddon(KSPAddon.Startup.SpaceCentre, true)]

    public class TMS_Stargate : MonoBehaviour
    {
        public void Awake()
        {
            string vesselName = "namespace TMS_Module_001";
            Vector3 vesselPosition = new Vector3(5f, 0f, 5f);
            VesselSpawner TMS_Module_001 = new VesselSpawner("namespace TMS_Module_001.craft", vesselName, vesselPosition);
            Debug.Log("Spawn the Ship");
            TMS_Module_001.SpawnVessel();
        }
    }
}

 

According to the Log, everything is getting called and running fine.  However, there is a problem in the code which I can't seem to figure out how to fix (or at least undo what I've done to it)

In the Log I see.......

Quote

[LOG 12:55:49.006] Assign FlightID using ShipConstruction
[EXC 12:55:49.009] NullReferenceException: Object reference not set to an instance of an object
    TMS_Module_001.VesselSpawner.SpawnVessel (System.String vesselName, .ShipConstruct _shipConstruct, Vector3 _spawnOffset)
    TMS_Module_001.VesselSpawner.SpawnVessel ()
    TMS_Module_001.TMS_Module_001.Awake ()
    UnityEngine.GameObject:AddComponent(Type)
    AddonLoader:StartAddon(LoadedAssembly, Type, KSPAddon, Startup)
    AddonLoader:StartAddons(Startup)
    AddonLoader:OnLevelWasLoaded(Int32)

This exception is referring to this part of the code......(I've added a buttload of debug statements around this part to help identify the problem.

for (int i = 0; i < _newVessel.parts.Count; i++)
            {
                Debug.Log("Loop through parts");
                Part part = _newVessel.parts[i];
                Debug.Log("Assign FlightID using ShipConstruction");
                part.flightID = ShipConstruction.GetUniqueFlightID(FlightDriver.FlightStateCache.flightState);
                Debug.Log("Done it Once");
                part.launchID = launchId;
                part.missionID = missionId;
            }
            Debug.Log("Finished Mission Stuff");

Specifically, line 6 in that block (part.flightID = ShipConstruction..........yadda yadda yadda)

A weird side-effect of this is that it completely breaks the game.  It creates an infinite for loop and messes everything else up (can't get off the Space Center screen :-O)

Would anyone have any clue what's going on with that?

 

Thanks

TheMightySpud

Link to comment
Share on other sites

Thanks @artwhaley,

I did see that (I think I've seen pretty much every thread involving spawning vessels. lol.)  The problem I'm having with a lot of the threads is how to use the methods etc. that are mentioned.

I'm still dissecting the KSPSmelter plugin as it looks like that's the most promising (I am definitely making progress:)).  It's just a matter of figuring out what it's doing and how to change it from spawning based on the location of a vessel part and spawning it in world space instead.

TheMightySpud

Link to comment
Share on other sites

Sorry but I've never been in that area of KSP code before. My only suggestion would be that if the "part.flightID = ShipConstruction.GetUniqueFlightID(FlightDriver.FlightStateCache.flightState);" line is throwing an exception you put a few debug statements right before it like so:

if (ShipConstruction== null) Debug.Log("ShipConstruction== null");

if (FlightDriver == null) Debug.Log("FlightDriver == null");

if (FlightStateCache== null) Debug.Log("FlightStateCache== null");

When I find some new objects that has info I want but they throw exceptions it usually turns out they're null at that point in the game.

Link to comment
Share on other sites

14 hours ago, TheMightySpud said:

Thanks @artwhaley,

I did see that (I think I've seen pretty much every thread involving spawning vessels. lol.)  The problem I'm having with a lot of the threads is how to use the methods etc. that are mentioned.

I'm still dissecting the KSPSmelter plugin as it looks like that's the most promising (I am definitely making progress:)).  It's just a matter of figuring out what it's doing and how to change it from spawning based on the location of a vessel part and spawning it in world space instead.

TheMightySpud

Here's some more code for you to peruse, if it will help. This was functional to the point that I could spawn space stations using config data. (it would look for a specific named node in all game config nodes until it found the space station template)

https://github.com/Starwaster/Ioncross-Crew-Support/blob/master/Source/IoncrossCrewSupport/Contracts/Templates/IonContractResupply.cs

It was designed to work with the format used by *.craft files. The config data was here:

https://github.com/Starwaster/Ioncross-Crew-Support/blob/master/KerbalInstallFolder/GameData/IoncrossCrewSupport/Contracts/Stations/station.type2.cfg

Feel free to use any of this that is useful to you.

Link to comment
Share on other sites

Ooooooh......

After a quick glance over I think this is going to be very helpful.

From what I can tell it pretty much does exactly what I want to do, all I need to do I think is remove the contracts parts (with a little fiddling obviously :)) and tie it to a specific craft file instead of searching through the database.

Thank you so much for that :)

TheMightySpud

Link to comment
Share on other sites

Hmmm........

So I've been playing around for a while with the code that @Starwaster provided, and I'm pretty sure I'm on the right track........however (yes there's always a however), it would appear as though the config file doesn't get added to the database (I double checked in the Alt+f12 options and it's nowhere to be seen).  So I'm a bit stumped.

I tried loading the file directly, but I couldn't get my head around how to do that at all. :-/

Anyone have any ideas?

Thanks

TheMightySpud

Link to comment
Share on other sites

@TheMightySpud

Ok, this section is how you search for a specific config. This is pretty much how every mod out there does it.

https://github.com/Starwaster/Ioncross-Crew-Support/blob/master/Source/IoncrossCrewSupport/Contracts/Templates/IonContractResupply.cs#L47-L64

Spoiler

		public List<ConfigNode> GetProtoStation()
		{

			List<ConfigNode> Stations = new List<ConfigNode>();
			//Loops through all ION_CONTRACT_FLEET configNodes in the GameDatabase
			foreach (ConfigNode fleet in GameDatabase.Instance.GetConfigNodes("ION_CONTRACT_STATIONS"))
			{
#if DEBUG
				Debug.Log("IonContractResupply.GetStationFleet(): found ION_CONTRACT_STATIONS node");
#endif
				foreach(ConfigNode station_candidate in fleet.GetNodes ("VESSEL"))
				{
					Debug.Log("IonContractResupply.GetStationFleet(): found VESSEL node");
					Stations.Add (station_candidate);
				}
			}
			return Stations;
		}

 

 

Link to comment
Share on other sites

Thanks for the pointers @Starwaster, it's really been helpful.

I've edited down the code quite substantially to the best of my knowledge, and logically it all seems fine.

However there is a problem which I can't seem to figure out.

I've narrowed down where the problem is, and it's definitely something to do with finding and parsing the config.

 

In this part of the code.......

public List<ConfigNode> GetProtoModule()
        {
            Debug.Log("TMS ORBITAL MECHANICS - Defining our Module List");
            List<ConfigNode> Modules = new List<ConfigNode>();
            Debug.Log("TMS ORBITAL MECHANICS - Defined our Module List");

            //Loops through all TMSMODULE001 configNodes in the GameDatabase
            Debug.Log("TMS ORBITAL MECHANICS - About to Start our first foreach Loop");
            foreach (ConfigNode modules in GameDatabase.Instance.GetConfigNodes("TMSMODULE001"))
            {
                Debug.Log("TMS ORBITAL MECHANICS - Modules in list = " + Modules.Count);
                Debug.Log("TMS ORBITAL MECHANICS - found TMSMODULE001 node");
                Debug.Log("TMS ORBITAL MECHANICS - About to Start our Second ForEach loop");
                foreach (ConfigNode module_candidate in gates.GetNodes("VESSEL"))
                {
                    Debug.Log("TMS ORBITAL MECHANICS - found VESSEL node");
                    Debug.Log("TMS ORBITAL MECHANICS - Adding to candidate List");
                    Modules.Add(module_candidate);
                    Debug.Log("TMS ORBITAL MECHANICS - Modules in list = " + Modules.Count);
                }
            }
            Debug.Log("TMS ORBITAL MECHANICS - Returning Info");
            return Modules;
        }

Everything works fine, except that it never finds the node 'TMSMODULE001' So everything else carries on, but as soon as it starts to go through the PART node, it craps out.

 

This is the log of that section so you can see what's happening.

Quote

[LOG 20:06:53.735] TMS ORBITAL MECHANICS - Going to GetProtoModule
[LOG 20:06:53.737] TMS ORBITAL MECHANICS - Defining our Module List
[LOG 20:06:53.738] TMS ORBITAL MECHANICS - Defined our Module List
[LOG 20:06:53.742] TMS ORBITAL MECHANICS - About to Start our first foreach Loop
[LOG 20:06:53.745] TMS ORBITAL MECHANICS - Returning Info
[LOG 20:06:53.746] TMS ORBITAL MECHANICS - Coming back from GetProtoModule
[LOG 20:06:53.747] TMS ORBITAL MECHANICS - about to return false (empty Module nodes; unable to spawn)
[LOG 20:06:53.749] TMS ORBITAL MECHANICS - Module Name = Kerbin Module
[LOG 20:06:53.751] TMS ORBITAL MECHANICS - assign Flight ID
[LOG 20:06:53.757] TMS ORBITAL MECHANICS - Get Parts
[EXC 20:06:53.765] ArgumentOutOfRangeException: Argument is out of range.
Parameter name: index
    System.Collections.Generic.List`1[ConfigNode].get_Item (Int32 index)
    TMS_Stargate.CreateModule.BuildModule (System.String planet)
    TMS_Stargate.TMS_Module001.Awake ()
    UnityEngine.GameObject:AddComponent(Type)
    AddonLoader:StartAddon(LoadedAssembly, Type, KSPAddon, Startup)
    AddonLoader:StartAddons(Startup)
    AddonLoader:OnLevelWasLoaded(Int32)

As you can see it craps out when trying to get the Parts because there's nothing to get, and I'm a little bit stumped :-/

 

This is the config file I'm trying to reference.  It's just a mk1 pod at the moment for testing purposes, I've tried to match the sample that was provided but I may have missed something. :-/

 

TMSMODULE001
{
	VESSEL
	{
	ship = Untitled Space Craft
	version = 1.0.5
	description = mk1pod Test Vehicle
	type = VAB
	size = 1.268897,1.132535,1.270908
	PART
	{
		part = mk1pod_4294731242
		partName = Part
		pos = 0,15,0
		attPos = 0,0,0
		attPos0 = 0,15,0
		rot = 0,0,0,1
		attRot = 0,0,0,1
		attRot0 = 0,0,0,1
		mir = 1,1,1
		symMethod = Radial
		istg = 0
		dstg = 0
		sidx = -1
		sqor = -1
		sepI = 0
		attm = 0
		modCost = 0
		modMass = 0
		modSize = (0.0, 0.0, 0.0)
		EVENTS
		{
		}
		ACTIONS
		{
		}
		PARTDATA
		{
		}
		MODULE
		{
			name = ModuleCommand
			isEnabled = True
			controlSrcStatusText = 
			stagingEnabled = True
			EVENTS
			{
				MakeReference
				{
					active = True
					guiActive = True
					guiActiveUncommand = False
					guiIcon = Control From Here
					guiName = Control From Here
					category = Control From Here
					guiActiveUnfocused = False
					unfocusedRange = 2
					externalToEVAOnly = True
				}
				RenameVessel
				{
					active = True
					guiActive = True
					guiActiveUncommand = True
					guiIcon = Rename Vessel
					guiName = Rename Vessel
					category = Rename Vessel
					guiActiveUnfocused = False
					unfocusedRange = 2
					externalToEVAOnly = True
				}
				ToggleStaging
				{
					active = True
					guiActive = False
					guiActiveUncommand = False
					guiIcon = Disable Staging
					guiName = Disable Staging
					category = Disable Staging
					guiActiveUnfocused = False
					unfocusedRange = 2
					externalToEVAOnly = True
				}
			}
			ACTIONS
			{
			}
		}
		MODULE
		{
			name = ModuleReactionWheel
			isEnabled = True
			stateString = Active
			stagingEnabled = True
			WheelState = Active
			EVENTS
			{
				OnToggle
				{
					active = True
					guiActive = True
					guiActiveEditor = True
					guiActiveUncommand = False
					guiIcon = Toggle Torque
					guiName = Toggle Torque
					category = Toggle Torque
					guiActiveUnfocused = False
					unfocusedRange = 2
					externalToEVAOnly = True
				}
				ToggleStaging
				{
					active = True
					guiActive = False
					guiActiveUncommand = False
					guiIcon = Disable Staging
					guiName = Disable Staging
					category = Disable Staging
					guiActiveUnfocused = False
					unfocusedRange = 2
					externalToEVAOnly = True
				}
			}
			ACTIONS
			{
				Activate
				{
					actionGroup = None
				}
				Deactivate
				{
					actionGroup = None
				}
				Toggle
				{
					actionGroup = None
				}
			}
		}
		MODULE
		{
			name = ModuleScienceExperiment
			isEnabled = True
			Deployed = False
			Inoperable = False
			stagingEnabled = True
			EVENTS
			{
				DeployExperiment
				{
					active = True
					guiActive = True
					guiActiveUncommand = False
					guiIcon = Deploy
					guiName = Deploy
					category = Deploy
					guiActiveUnfocused = False
					unfocusedRange = 2
					externalToEVAOnly = True
				}
				CollectDataExternalEvent
				{
					active = True
					guiActive = False
					guiActiveUncommand = False
					guiIcon = 
					guiName = 
					category = 
					guiActiveUnfocused = True
					unfocusedRange = 1.5
					externalToEVAOnly = True
				}
				ReviewDataEvent
				{
					active = True
					guiActive = True
					guiActiveUncommand = False
					guiIcon = Review Data
					guiName = Review Data
					category = Review Data
					guiActiveUnfocused = False
					unfocusedRange = 2
					externalToEVAOnly = True
				}
				ResetExperiment
				{
					active = True
					guiActive = True
					guiActiveUncommand = False
					guiIcon = Reset
					guiName = Reset
					category = Reset
					guiActiveUnfocused = False
					unfocusedRange = 2
					externalToEVAOnly = True
				}
				DeployExperimentExternal
				{
					active = True
					guiActive = False
					guiActiveUncommand = False
					guiIcon = Deploy
					guiName = Deploy
					category = Deploy
					guiActiveUnfocused = True
					unfocusedRange = 2
					externalToEVAOnly = True
				}
				ResetExperimentExternal
				{
					active = True
					guiActive = False
					guiActiveUncommand = False
					guiIcon = Reset
					guiName = Reset
					category = Reset
					guiActiveUnfocused = True
					unfocusedRange = 2
					externalToEVAOnly = True
				}
				CleanUpExperimentExternal
				{
					active = True
					guiActive = False
					guiActiveUncommand = False
					guiIcon = Restore
					guiName = Restore
					category = Restore
					guiActiveUnfocused = True
					unfocusedRange = 2
					externalToEVAOnly = True
				}
				ToggleStaging
				{
					active = True
					guiActive = False
					guiActiveUncommand = False
					guiIcon = Disable Staging
					guiName = Disable Staging
					category = Disable Staging
					guiActiveUnfocused = False
					unfocusedRange = 2
					externalToEVAOnly = True
				}
			}
			ACTIONS
			{
				DeployAction
				{
					actionGroup = None
				}
				ResetAction
				{
					actionGroup = None
				}
			}
		}
		MODULE
		{
			name = ModuleScienceContainer
			isEnabled = True
			stagingEnabled = True
			EVENTS
			{
				StoreDataExternalEvent
				{
					active = False
					guiActive = False
					guiActiveUncommand = False
					guiIcon = 
					guiName = Store Experiments (0)
					category = 
					guiActiveUnfocused = True
					unfocusedRange = 1.3
					externalToEVAOnly = True
				}
				CollectDataExternalEvent
				{
					active = False
					guiActive = False
					guiActiveUncommand = False
					guiIcon = 
					guiName = Take Data (0)
					category = 
					guiActiveUnfocused = True
					unfocusedRange = 1.3
					externalToEVAOnly = True
				}
				ReviewDataEvent
				{
					active = False
					guiActive = True
					guiActiveUncommand = False
					guiIcon = Review Data
					guiName = Review Stored Data (0)
					category = Review Data
					guiActiveUnfocused = False
					unfocusedRange = 2
					externalToEVAOnly = True
				}
				ToggleStaging
				{
					active = True
					guiActive = False
					guiActiveUncommand = False
					guiIcon = Disable Staging
					guiName = Disable Staging
					category = Disable Staging
					guiActiveUnfocused = False
					unfocusedRange = 2
					externalToEVAOnly = True
				}
			}
			ACTIONS
			{
			}
		}
		MODULE
		{
			name = FlagDecal
			isEnabled = True
			flagDisplayed = True
			stagingEnabled = True
			EVENTS
			{
				ToggleFlag
				{
					active = True
					guiActive = False
					guiActiveEditor = True
					guiActiveUncommand = False
					guiIcon = Toggle Flag
					guiName = Toggle Flag
					category = Toggle Flag
					guiActiveUnfocused = False
					unfocusedRange = 2
					externalToEVAOnly = True
				}
				ToggleStaging
				{
					active = True
					guiActive = False
					guiActiveUncommand = False
					guiIcon = Disable Staging
					guiName = Disable Staging
					category = Disable Staging
					guiActiveUnfocused = False
					unfocusedRange = 2
					externalToEVAOnly = True
				}
			}
			ACTIONS
			{
			}
		}
		MODULE
		{
			name = ModuleConductionMultiplier
			isEnabled = True
			stagingEnabled = True
			EVENTS
			{
				ToggleStaging
				{
					active = True
					guiActive = False
					guiActiveUncommand = False
					guiIcon = Disable Staging
					guiName = Disable Staging
					category = Disable Staging
					guiActiveUnfocused = False
					unfocusedRange = 2
					externalToEVAOnly = True
				}
			}
			ACTIONS
			{
			}
		}
		MODULE
		{
			name = ModuleTripLogger
			isEnabled = True
			stagingEnabled = True
			EVENTS
			{
				ToggleStaging
				{
					active = True
					guiActive = False
					guiActiveUncommand = False
					guiIcon = Disable Staging
					guiName = Disable Staging
					category = Disable Staging
					guiActiveUnfocused = False
					unfocusedRange = 2
					externalToEVAOnly = True
				}
			}
			ACTIONS
			{
			}
			Log
			{
				flight = 0
			}
		}
		MODULE
		{
			name = TransferDialogSpawner
			isEnabled = True
			stagingEnabled = True
			EVENTS
			{
				SpawnDialog
				{
					active = True
					guiActive = True
					guiActiveUncommand = True
					guiIcon = Transfer Crew
					guiName = Transfer Crew
					category = Transfer Crew
					guiActiveUnfocused = False
					unfocusedRange = 2
					externalToEVAOnly = True
				}
				ToggleStaging
				{
					active = True
					guiActive = False
					guiActiveUncommand = False
					guiIcon = Disable Staging
					guiName = Disable Staging
					category = Disable Staging
					guiActiveUnfocused = False
					unfocusedRange = 2
					externalToEVAOnly = True
				}
			}
			ACTIONS
			{
			}
		}
		RESOURCE
		{
			name = ElectricCharge
			amount = 50
			maxAmount = 50
			flowState = True
			isTweakable = True
			hideFlow = False
			isVisible = True
			flowMode = Both
		}
		RESOURCE
		{
			name = MonoPropellant
			amount = 10
			maxAmount = 10
			flowState = True
			isTweakable = True
			hideFlow = False
			isVisible = True
			flowMode = Both
		}
	}
	}
}

 

From what I can see it's just a matter of wrapping the existing Craft file contents inside TMSMODULE001 { VESSEL {           } } tags.

But like I say I could have missed something.

 

Thanks

TheMightySpud

Link to comment
Share on other sites

You'll save yourself a lot of time if you can get debug mode working inside KSP via one of the stickies. Where is the cfg file itself located? That would be my current suspicion. GameDatabase only auto-loads ConfigNodes inside GameData and subdirectories so if you've put it elsewhere (maybe alongside the persistent sfs or .craft you copied its contents from?) it won't be found

Link to comment
Share on other sites

AH HAAAAA!!!!

Thank you so so so so so so so much.

Got it to read everything, now I'm getting a new error. lol.

This one is an 'in game' error saying that it can't load the vessel because of a missing part, but it doesn't say which part, it's just blank.....lol.

Well, time to go and mess about with stuff :)

Thanks again

TheMightySpud

Link to comment
Share on other sites

Hooooookay,

Spent a couple of hours trying to figure this out and have gotten nowhere. :-/

// ------------------------------------------------------------------------------
//  <autogenerated>
//      This code was generated by a tool.
//      Mono Runtime Version: 4.0.30319.1
// 
//      Changes to this file may cause incorrect behavior and will be lost if 
//      the code is regenerated.
//  </autogenerated>
// ------------------------------------------------------------------------------

using KSP;
using UnityEngine;
using Contracts;
using Contracts.Parameters;
using System;
using System.Collections.Generic;
using System.Linq;

namespace TMS_Stargate
{

    public class CreateGates : MonoBehaviour
    {

        //Define a load of lists and variables
        private List<ConfigNode> stargateList = new List<ConfigNode>();
        private CelestialBody gateBody = null;
        private string _planet;
        public string stargateName = "Unnamed Stargate";

        public List<ConfigNode> GetProtoGate()
        {
            //Defines our list of Stargates
            Debug.Log("TMS ORBITAL MECHANICS - Defining our Gate List");
            List<ConfigNode> Stargates = new List<ConfigNode>();
            Debug.Log("TMS ORBITAL MECHANICS - Defined our Gate List");

            //Loops through all the configs to find any starting with a Node called STARGATE
            Debug.Log("TMS ORBITAL MECHANICS - About to Start our first foreach Loop");
            foreach (ConfigNode gates in GameDatabase.Instance.GetConfigNodes("STARGATE"))
            {
                Debug.Log("TMS ORBITAL MECHANICS - Gates in list = " + Stargates.Count);
                Debug.Log("TMS ORBITAL MECHANICS - found STARGATE node");
                Debug.Log("TMS ORBITAL MECHANICS - About to Start our Second ForEach loop");
                //Finds all the VESSEL Nodes in our Configs
                foreach (ConfigNode stargate_candidate in gates.GetNodes("VESSEL"))
                {
                    //Adds any relevant items from the Configs to our Stargate List
                    Debug.Log("TMS ORBITAL MECHANICS - found VESSEL node");
                    Debug.Log("TMS ORBITAL MECHANICS - Adding to candidate List");
                    Stargates.Add(stargate_candidate);
                    Debug.Log("TMS ORBITAL MECHANICS - Gates in list = " + Stargates.Count);
                }
            }
            //Sends the completed list back to the main bit
            Debug.Log("TMS ORBITAL MECHANICS - Returning Info");
            return Stargates;
        }

        public void BuildGate(string planet)
        {
            //Defines which planet/moon we are referencing
            this._planet = planet;
            Debug.Log("The Commencement has Beginulated");
            foreach (CelestialBody targetBody in FlightGlobals.Bodies)
            {
                Debug.Log("TMS ORBITAL MECHANICS - Found Body " + targetBody);
                if (targetBody.name == _planet)
                    gateBody = targetBody;
            }
            Debug.Log("Locked on to " + gateBody);

            Debug.Log("TMS ORBITAL MECHANICS - Trying to Spawn a Gate");            
            //Sends a request to 'GetProtoGate' to grab info we can use.
            Debug.Log("TMS ORBITAL MECHANICS - Going to GetProtoGate");
            stargateList = GetProtoGate();
            Debug.Log("TMS ORBITAL MECHANICS - Coming back from GetProtoGate");

            //Checks to make sure we're getting something back
            if (stargateList.Count <= 0)
            {
                Debug.Log("TMS ORBITAL MECHANICS - about to return false (empty fleet nodes; unable to spawn)");
                //return false;
            }

            //Give our Stargate a name
            stargateName = gateBody.bodyName + " Stargate";
            Debug.Log("TMS ORBITAL MECHANICS - Stargate Name = " + stargateName);

            //Defines out unique flightID
            Debug.Log("TMS ORBITAL MECHANICS - assign Flight ID");
            uint uniqueFlightID = ShipConstruction.GetUniqueFlightID(HighLogic.CurrentGame.flightState);
            Debug.Log("TMS ORBITAL MECHANICS - Stargate Name" + stargateList[0].name);

            //Tries to get all the parts from our loaded vessel config file
            Debug.Log("TMS ORBITAL MECHANICS - Get Parts");
            ConfigNode[] stargateParts = stargateList[0].GetNodes("PART");
            Debug.Log("TMS ORBITAL MECHANICS - Part Name" + stargateParts[0].name);

            //Define our orbit details (Needs heavy editing to put our gates exactly where we want them.  Ideally getting info from TMS_Stargate.cs)
            Debug.Log("TMS ORBITAL MECHANICS - Defining Orbit Details");
            double lowOrbit = Math.Max(gateBody.Radius + gateBody.Radius * 0.15, gateBody.Radius + (double)gateBody.atmosphereDepth * 2.0);
            double highOrbit = Math.Max(gateBody.Radius + gateBody.Radius * 0.2, gateBody.Radius + (double)gateBody.atmosphereDepth * 2.3);
            Debug.Log("TMS ORBITAL MECHANICS - Defining Parameters config node");

            //Define our parameters node (not actually sure what this does if honest)
            ConfigNode[] parameters = new ConfigNode[] { ProtoVessel.CreateDiscoveryNode(DiscoveryLevels.Unowned, UntrackedObjectClass.A, 50000 * 2.0, 50000 * 2.0) };

            //Assign our orbit details to our actual orbit
            Debug.Log("TMS ORBITAL MECHANICS - Creating Orbit details");
            Orbit orbit = Orbit.CreateRandomOrbitAround(this.gateBody, lowOrbit, highOrbit);
            
            //Define and add our details to the ProtoVessel
            Debug.Log("TMS ORBITAL MECHANICS - Adding all info to the ProtoVesselNode");
            ConfigNode protoVesselNode = ProtoVessel.CreateVesselNode(stargateName,
                                                                       VesselType.Station,
                                                                       orbit,
                                                                       0,
                                                                       stargateParts,
                                                                       parameters
                                                                       );

            //Add our ProtoVessel to the game
            Debug.Log("TMS ORBITAL MECHANICS - Adding our Gate to the game(I think)");
            ProtoVessel protoVessel = HighLogic.CurrentGame.AddVessel(protoVesselNode);

        }
    }
}

Here's what I've got (Yes, it's a Stargate Mod, don't judge me. lol.)

All credit to @Starwaster for the code, making more headway with this than I have any other. :)

I've got the thing to read the file and attempt loading, but there's a line that's causing a bit of a problem.

This little nugget seems to refuse to read the parts of the loaded file.

ConfigNode[] stargateParts = stargateList[0].GetNodes("PART");

In Starwasters original code this was set to look for a random value based on how many items were in the 'stargateList' however as this will only ever return a single item, I've set it to 0.

But I can't see what it won't get the parts. :-/

Thanks.

TheMightySpud

Link to comment
Share on other sites

My first question would be: what does the node stargateList[0] look like? Print it to the log and you can see exactly what is / isn't there. The other thing would be what behaviour are you actually getting, vs. expecting

EDIT

Also, if you have a github (or similar) repository, it's much easier to read larger blocks of code vs. the small forum code blocks (for example: https://github.com/Crzyrndm/FilterExtension/blob/master/FilterExtension/Core.cs#L58-L69)

Edited by Crzyrndm
Link to comment
Share on other sites

This thread is quite old. Please consider starting a new thread rather than reviving this one.

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.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...