Jump to content

Recommended Posts

Ok I'm trying to create a custom category module with no success. Could someone please tell me what I'm doing wrong here, as it seems to me it should be working but nothing is happening can't even get the Debug.Log("") to show anything in the log.

using KSP.IO;
using RUI.Icons.Selectable;
using UnityEngine;
using static KSP.UI.Screens.PartCategorizer;

namespace NextStarIndustries
{
    [KSPAddon(KSPAddon.Startup.EditorAny, false)]

    public class NSICategoryModule : MonoBehaviour
    {
        public void Start()
        {
            GameEvents.onGUIEditorToolbarReady.Add(NSICategory);
            Debug.Log("Category Started");
        }

        private void NSICategory()
        {
            //Loading Textures
            Texture2D unselected = new Texture2D(32, 32);
            Texture2D selected = new Texture2D(32, 32);
            Texture2D nuclear = new Texture2D(32, 32);
            Texture2D conventional = new Texture2D(32, 32);
            Texture2D rd = new Texture2D(32, 32);
            Texture2D probe = new Texture2D(32, 32);
            Texture2D engine = new Texture2D(32, 32);
            unselected.LoadImage(File.ReadAllBytes<NSICategoryModule>("GameData/BDArmory Weapons Extension/textures/NSIIcon"));
            selected.LoadImage(File.ReadAllBytes<NSICategoryModule>("GameData/BDArmory Weapons Extension/textures/NSIIconActive"));
            nuclear.LoadImage(File.ReadAllBytes<NSICategoryModule>("GameData/BDArmory Weapons Extension/textures/NSIIconNW"));
            conventional.LoadImage(File.ReadAllBytes<NSICategoryModule>("GameData/BDArmory Weapons Extension/textures/NSIIconCW"));
            rd.LoadImage(File.ReadAllBytes<NSICategoryModule>("GameData/BDArmory Weapons Extension/textures/NSIIconRD"));
            probe.LoadImage(File.ReadAllBytes<NSICategoryModule>("GameData/Squad/PartList/SimpleIcons/R&D_node_icon_advunmanned"));
            engine.LoadImage(File.ReadAllBytes<NSICategoryModule>("GameData/Squad/PartList/SimpleIcons/R&D_node_icon_advancedmotors"));
            Debug.Log("Textures Loaded");

            Icon NSIIcon = new Icon("NSI", selected, unselected); //Defining NSIIcon
            Icon NSIIconNW = new Icon("Nuclear Weapons", nuclear, nuclear); //Defining NSIIconNW
            Icon NSIIconCW = new Icon("Conventional Weapons", conventional, conventional); //Defining NSIIconCW
            Icon NSIIconRD = new Icon("R&D Parts", rd, rd); //Defining NSIIconRD
            Icon NSIIconProbe = new Icon("Probes", probe, probe); //Defining NSIIconProbes
            Icon NSIIconEngine = new Icon("Engines", engine, engine); //Defining NSIIconEngines

            Category NSI = AddCustomFilter("Next Star Industries", "NSI", NSIIcon, Color.white);

            //filters for All NSI Parts, Nuclear Weapons, Conventional Weapons, R&D, Probes, and Engines
            AddCustomSubcategoryFilter(NSI, "All NSI Parts", "All NSI Parts", NSIIcon, All => All.manufacturer == "Next Star Industries");
            AddCustomSubcategoryFilter(NSI, "Nuclear", "Nuclear Weapons", NSIIconNW, NW => NW.description.Contains("Nuclear") && NW.manufacturer == "Next Star Industries");
            AddCustomSubcategoryFilter(NSI, "Conventional", "Conventional Weapons", NSIIconCW, CW => CW.description.Contains("Conventional") && CW.manufacturer == "Next Star Industries");
            AddCustomSubcategoryFilter(NSI, "R&D", "R&D Parts", NSIIconRD, RD => RD.description.Contains("R&D") && RD.manufacturer == "Next Star Industries");
            AddCustomSubcategoryFilter(NSI, "Probes", "NSI Probes", NSIIconProbe, Probe => Probe.description.Contains("Probe") && Probe.manufacturer == "Next Star Industries");
            AddCustomSubcategoryFilter(NSI, "Engines", "NSI Engines", NSIIconEngine, Engine => Engine.description.Contains("Engine") && Engine.manufacturer == "Next Start Industries");
        }
    }
}

Link to post
Share on other sites
8 hours ago, Crzyrndm said:

I use awake for Filter Extensions instead of Start, and I do recall having to change sometime in the recent past

Thanks I have switched to Awake()  and have now changed all this code. I have it making the main filter now but when I try to add the subcategories it keeps crashing it out not sure what I have wrong. This what I have now and when I add the addcustomsubcategory() it crashes it. Game still loads but no custom category listed:

using static KSP.UI.Screens.PartCategorizer;
using UnityEngine;
using RUI.Icons.Selectable;
using System.Collections.Generic;

namespace NextStarIndustries
{
    [KSPAddon(KSPAddon.Startup.MainMenu, true)]
    public class NISCategoryModule : MonoBehaviour
    {
        private static readonly List<AvailablePart> availableParts = new List<AvailablePart>();
        void Awake()
        {
            GameEvents.onGUIEditorToolbarReady.Add(NSICategory);
            Debug.Log("NSI Category is Awake");
        }

        void NSICategory()
        {
            Debug.Log("NSI Category Added");
            //Icon Textures
            Texture2D NSIIconN = GameDatabase.Instance.GetTexture("BDArmory Weapons Extension/textures/NSIIcon", false);
            Texture2D NSIIconS = GameDatabase.Instance.GetTexture("BDArmory Weapons Extension/textures/NSIIconActive", false);
            Texture2D NSIIconNW = GameDatabase.Instance.GetTexture("BDArmory Weapons Extension/textures/NSIIconNW", false);
            Texture2D NSIIconCW = GameDatabase.Instance.GetTexture("BDArmory Weapons Extension/textures/NSIIconCW", false);
            Texture2D NSIIconRD = GameDatabase.Instance.GetTexture("BDArmory Weapons Extension/textures/NSIIconRD", false);
            Texture2D NSIIconProbes = GameDatabase.Instance.GetTexture("BDArmory Weapons Extension/textures/NSIIconActive", false);
            Texture2D NSIIconEngines = GameDatabase.Instance.GetTexture("BDArmory Weapons Extension/textures/NSIIconActive", false);
            //Icon Main Category
            Icon NSI = new Icon("NSI", NSIIconN, NSIIconS, false);
            //Icons SubCategories
            Icon NSINuclear = new Icon("Nuclear Weapons", NSIIconNW, NSIIconNW, false);
            Icon NSIConventional = new Icon("Conventional Weapons", NSIIconCW, NSIIconCW, false);
            Icon NSIRD = new Icon("R&D Parts", NSIIconRD, NSIIconRD, false);
            Icon NSIProbe = new Icon("Probes", NSIIconProbes, NSIIconProbes, false);
            Icon NSIEngine = new Icon("Engines", NSIIconEngines, NSIIconEngines, false);
            //Main Category
            Category filter = AddCustomFilter("NSI", "Next Star Industries", NSI, Color.red);
            //Sub Categories
            AddCustomSubcategoryFilter(filter, "NSI", "Next Star Industries", NSI, p => p.author.Contains("Next Star Industries"));
        }
    }
}

I believe it has to be the lambda expression but not sure.

Edited by Next_Star_Industries
Link to post
Share on other sites
1 minute ago, Benjamin Kerman said:

I think for getTexture, you need the complete file path from the hard drive, and not from the local GameData folder. 

I have tried both ways and they both work. The textures are being found, and they load, and I can get it to add the main filter, I just can't get the subcategories working.

Link to post
Share on other sites
4 hours ago, Next_Star_Industries said:

I believe it has to be the lambda expression but not sure.

Lambda is just a function (albeit an unnamed/anonymous one). FE uses the same method to express its callback (I do wonder why you're using string.Contains instead of Equals? But that's a nitpick...)

I would suggest printing each of the parameters to the log (check they're not null, etc.).
What error is being reported in the log file? What does the stack trace point at?
Does it work if you change the function to a coroutine and delay 10 frames before initialising?

FE call path for completeness:
EditorInit() called by callback registered in awake calls initialise on categories
Category setup adds the CustomFilter and then passes the returned instance to Init Subcategories on
Subcategory initialise just registers the filter against the category

The only major difference I can see is that I call all this through a coroutine so it might be delayed from the original callback

Edited by Crzyrndm
Link to post
Share on other sites
30 minutes ago, Crzyrndm said:

Lambda is just a function (albeit an unnamed/anonymous one). FE uses the same method to express its callback (I do wonder why you're using string.Contains instead of Equals? But that's a nitpick...)

I would suggest printing each of the parameters to the log (check they're not null, etc.).
What error is being reported in the log file? What does the stack trace point at?
Does it work if you change the function to a coroutine and delay 10 frames before initialising?

FE call path for completeness:
EditorInit() called by callback registered in awake calls initialise on categories
Category setup adds the CustomFilter and then passes the returned instance to Init Subcategories on
Subcategory initialise just registers the filter against the category

The only major difference I can see is that I call all this through a coroutine so it might be delayed from the original callback

Thanks for the help. The only reason for Contains is I was trying different things out but I do agree it should be Equals. Trying the coroutine I'll see what happens there.

Link to post
Share on other sites

@Crzyrndm So after discovering what FE is and what it does :) and after I woke up from bashing my head :confused: against the desk for not finding it earlier. Everything is doing what I'm wanting it to do. Thanks for the help with the coding though, but it's out :wink:. I'll send the stuff to see about getting my mod added.

Edited by Next_Star_Industries
Link to post
Share on other sites

Well FE doesn't do what I was expecting after all, but I was able to fix the code here is what I came up with. It uses the author field as a tagging system. Feel free to copy and paste the code to create your own categories while it's licence is for CC BY-SA 4.0 I give everyone permission to do what ever you want with it.

using RUI.Icons.Selectable;
using System.Collections.Generic;
using static KSP.UI.Screens.PartCategorizer;
using UnityEngine;

namespace NextStarIndustries
{
    [KSPAddon(KSPAddon.Startup.MainMenu, true)]
    public class NISCategoryModule : MonoBehaviour
    {
        readonly List<AvailablePart> availableParts = new List<AvailablePart>();
        readonly List<AvailablePart> nwParts = new List<AvailablePart>();
        readonly List<AvailablePart> cwParts = new List<AvailablePart>();
        readonly List<AvailablePart> rdParts = new List<AvailablePart>();
        readonly List<AvailablePart> probeParts = new List<AvailablePart>();
        readonly List<AvailablePart> engineParts = new List<AvailablePart>();
        void Awake()
        {
            availableParts.Clear();
            var countap = PartLoader.LoadedPartsList.Count;
            for (int a = 0; a < countap; ++a)
            {
                var avPart = PartLoader.LoadedPartsList[a];
                if (!avPart.partPrefab) continue;
                if (avPart.author.Contains("NSI"))
                {
                    availableParts.Add(avPart);
                }
            }
            nwParts.Clear();
            var countnp = PartLoader.LoadedPartsList.Count;
            for (int n = 0; n < countnp; ++n)
            {
                var nPart = PartLoader.LoadedPartsList[n];
                if (!nPart.partPrefab) continue;
                if (nPart.author.Contains("NSINuclear"))
                {
                    nwParts.Add(nPart);
                }

            }
            cwParts.Clear();
            var countcp = PartLoader.LoadedPartsList.Count;
            for (int c = 0; c < countcp; ++c)
            {
                var cPart = PartLoader.LoadedPartsList[c];
                if (!cPart.partPrefab) continue;
                if (cPart.author.Contains("NSIConventional"))
                {
                    cwParts.Add(cPart);
                }
            }
            rdParts.Clear();
            var countrdp = PartLoader.LoadedPartsList.Count;
            for (int r = 0; r < countcp; ++r)
            {
                var rdPart = PartLoader.LoadedPartsList[r];
                if (!rdPart.partPrefab) continue;
                if (rdPart.author.Contains("NSIRD"))
                {
                    rdParts.Add(rdPart);
                }
            }
            probeParts.Clear();
            var countpp = PartLoader.LoadedPartsList.Count;
            for (int p = 0; p < countcp; ++p)
            {
                var prPart = PartLoader.LoadedPartsList[p];
                if (!prPart.partPrefab) continue;
                if (prPart.author.Contains("NSIProbes"))
                {
                    probeParts.Add(prPart);
                }
            }
            engineParts.Clear();
            var countep = PartLoader.LoadedPartsList.Count;
            for (int e = 0; e < countcp; ++e)
            {
                var ePart = PartLoader.LoadedPartsList[e];
                if (!ePart.partPrefab) continue;
                if (ePart.author.Contains("NSIEngines"))
                {
                    engineParts.Add(ePart);
                }
            }

            GameEvents.onGUIEditorToolbarReady.Add(NSICategory);
            Debug.Log("NSI Category is Awake");
            Debug.Log("NSI aPart Count: " + availableParts.Count);
            Debug.Log("NSI nPart Count: " + nwParts.Count);
            Debug.Log("NSI cPart Count: " + cwParts.Count);
            Debug.Log("NSI rdPart Count: " + rdParts.Count);
            Debug.Log("NSI pPart Count: " + probeParts.Count);
            Debug.Log("NSI ePart Count: " + engineParts.Count);
        }

        bool ap(AvailablePart avPart)
        {
            return availableParts.Contains(avPart);
        }
        bool np(AvailablePart nPart)
        {
            return nwParts.Contains(nPart);
        }
        bool cp(AvailablePart cPart)
        {
            return cwParts.Contains(cPart);
        }
        bool rdp(AvailablePart rdPart)
        {
            return rdParts.Contains(rdPart);
        }
        bool pp(AvailablePart prPart)
        {
            return probeParts.Contains(prPart);
        }
        bool ep(AvailablePart ePart)
        {
            return engineParts.Contains(ePart);
        }

        void NSICategory()
        {
            Debug.Log("NSI Category Added");
            //Icon Textures
            Texture2D NSIIconN = GameDatabase.Instance.GetTexture("BDArmory Weapons Extension/textures/NSIIcon", false);
            Texture2D NSIIconS = GameDatabase.Instance.GetTexture("BDArmory Weapons Extension/textures/NSIIconActive", false);
            Texture2D NSIIconNW = GameDatabase.Instance.GetTexture("BDArmory Weapons Extension/textures/NSIIconNW", false);
            Texture2D NSIIconCW = GameDatabase.Instance.GetTexture("BDArmory Weapons Extension/textures/NSIIconCW", false);
            Texture2D NSIIconRD = GameDatabase.Instance.GetTexture("BDArmory Weapons Extension/textures/NSIIconRD", false);
            Texture2D NSIIconProbes = GameDatabase.Instance.GetTexture("Squad/PartList/SimpleIcons/R&D_node_icon_largeprobes", false);
            Texture2D NSIIconEngines = GameDatabase.Instance.GetTexture("Squad/PartList/SimpleIcons/R&D_node_icon_advancedmotors", false);
            //Icon Main Category
            Icon NSI = new Icon("NSI", NSIIconN, NSIIconS, false);
            //Icons SubCategories
            Icon NSINuclear = new Icon("Nuclear Weapons", NSIIconNW, NSIIconNW, false);
            Icon NSIConventional = new Icon("Conventional Weapons", NSIIconCW, NSIIconCW, false);
            Icon NSIRD = new Icon("R&D Parts", NSIIconRD, NSIIconRD, false);
            Icon NSIProbe = new Icon("Probes", NSIIconProbes, NSIIconProbes, false);
            Icon NSIEngine = new Icon("Engines", NSIIconEngines, NSIIconEngines, false);
            //Main Category
            Category filter = AddCustomFilter("NSI", "Next Star Industries", NSI, Color.red);
            //Sub Categories
            AddCustomSubcategoryFilter(filter, "NSI", "Next Star Industries", NSI, p => ap(p));
            AddCustomSubcategoryFilter(filter, "Nuclear", "Nuclear Weapons", NSINuclear, nwp => np(nwp));
            AddCustomSubcategoryFilter(filter, "Conventional", "Conventional Weapons", NSIConventional, cwp => cp(cwp));
            AddCustomSubcategoryFilter(filter, "R&D", "Research and Development", NSIRD, radp => rdp(radp));
            AddCustomSubcategoryFilter(filter, "NSIProbes", "NSI Probe Cores", NSIProbe, prp => pp(prp));
            AddCustomSubcategoryFilter(filter, "NSIEngines", "NSI Engines", NSIEngine, enp => ep(enp));
        }
    }
}

Link to post
Share on other sites
  • 1 month later...

@Next_Star_Industries - Here you go, in the spoiler ... This code comes out of USITools and is Licensed under GPLv3 (edited to work for your mod)

You will need to create icons that are 32x32 and save them in the same directory as the plugin ... One called NextStarIndustries_normal.png and the other NextStarIndustries_selected.png

As long as the part config has 'manufacturer = Next Star Industries' this code will work ... or you can change it, pretty straight forward how the code works

Anyways, enjoy :)

Spoiler

using KSP.UI.Screens;
using RUI.Icons.Selectable;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using UnityEngine;

namespace NextStarIndustries
{
    
    [KSPAddon(KSPAddon.Startup.MainMenu, true)]
    public class NSIFilter : BaseFilter
    {
        protected override string Manufacturer
        {
            get { return "Next Star Industries"; }
            set { }
        }
        protected override string categoryTitle
        {
            get { return "NSI"; }
            set { }
        }
    }


    public abstract class BaseFilter : MonoBehaviour
    {
        private readonly List<AvailablePart> parts = new List<AvailablePart>();
        internal string category = "Filter by function";
        internal bool filter = true;
        protected abstract string Manufacturer { get; set; }
        protected abstract string categoryTitle { get; set; }

        void Awake()
        {
            parts.Clear();
            var count = PartLoader.LoadedPartsList.Count;
            for(int i = 0; i < count; ++i)
            {
                var avPart = PartLoader.LoadedPartsList;
                if (!avPart.partPrefab) continue;
                if (avPart.manufacturer == Manufacturer)
                {
                    parts.Add(avPart);
                }
            }

            print(categoryTitle + "  Filter Count: " + parts.Count);
            if (parts.Count > 0)
                GameEvents.onGUIEditorToolbarReady.Add(SubCategories);
        }

        private bool EditorItemsFilter(AvailablePart avPart)
        {
            return parts.Contains(avPart);
        }

        private void SubCategories()
        {
            var icon = GenIcon(categoryTitle);
            var filter = PartCategorizer.Instance.filters.Find(f => f.button.categoryName == category);
            PartCategorizer.AddCustomSubcategoryFilter(filter, categoryTitle, categoryTitle, icon, EditorItemsFilter);
        }

        private Icon GenIcon(string iconName)
        {
            var normIcon = new Texture2D(64, 64, TextureFormat.RGBA32, false);
            var normIconFile = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), iconName + "_normal.png");
            normIcon.LoadImage(File.ReadAllBytes(normIconFile));

            var selIcon = new Texture2D(64, 64, TextureFormat.RGBA32, false);
            var selIconFile = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), iconName + "_selected.png");
            selIcon.LoadImage(File.ReadAllBytes(selIconFile));

            print("*****Adding icon for " + categoryTitle);
            var icon = new Icon(iconName + "Icon", normIcon, selIcon);
            return icon;
        }
    }

}

 

Edited by DoctorDavinci
Link to post
Share on other sites
1 hour ago, Next_Star_Industries said:

@DoctorDavinci Thank you so much, this will be awesome!!:D I will implement this into the mod for sure, if they would ever let me out of this dang hospital so I can get back to working on things.:/

Not a problem ... Lets hope they set you loose without taking a kidney :wink:

On another note, I should have mentioned the license obligations you will have if you use that code

You are required to mention in the OP of your thread and the download location that your mod contains code from USITools ... put it in a spoiler at the end of your thread op (use DCK's OP as an example if you want) and put it into your README.md on Github

 

Link to post
Share on other sites
19 minutes ago, flywlyx said:

@DoctorDavinci Everyday opening help and support subforum is like opening a treasure box, thanks for the awesome code.

Edit: So, does it compile with CC licences or I need to transfer to GPL too? 

From what I understand you will need to upgrade your license to GPLv3 for that portion of the code

Take a look at the spoilers at the the bottom of the OP in DCK's thread for an example ... feel free to copy the applicable parts

There are others who know better than I and they may know more about the ins and outs

Edited by DoctorDavinci
Link to post
Share on other sites
1 hour ago, flywlyx said:

@DoctorDavinci Everyday opening help and support subforum is like opening a treasure box, thanks for the awesome code.

Edit: So, does it compile with CC licences or I need to transfer to GPL too? 

They are not compatible but you are able to say "The whole mod is CC except for this little section which is GPL"

Link to post
Share on other sites
1 hour ago, TheRagingIrishman said:

They are not compatible but you are able to say "The whole mod is CC except for this little section which is GPL"

Honestly I do not know

I changed DCK from MIT to GPLv3

Edited by DoctorDavinci
Link to post
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...