Jump to content

Load only the newest plugin version


Recommended Posts

I know this is possible but before I jump through a gob of hoops trying to figure this out, does anyone have a simple method of loading only the newest version of a specific plugin when multiple versions exist in the GameData directory?

Thanks in advance.

Link to comment
Share on other sites

  • 2 weeks later...

Ok, so I've dug a bit more into this problem.  What I'm trying to achieve is the plugin only running the newest version.

so, here's the code I have:

    [KSPAddon(KSPAddon.Startup.Instantly, true)]
    public class MPStartup : MonoBehaviour
    {
        private const int intVersion = 6;
        private static int _version = intVersion;
        public static bool MPUtilsrunning = false;

        public void Awake()
        {
            MPConfig.Getconfig();
            //MPLog.NewLog();
            MPLog.Writelog("[Maritime Pack] MPUtils v" + MPFunctions.GetVersion() + " Anchors Aweigh!");
        }

        public void Start()
        {
            var version = Assembly.GetExecutingAssembly().GetName().Version;

            Debug.Assert(version.Major >= 0 && version.Major < 100);
            Debug.Assert(version.Minor >= 0 && version.Minor < 100);
            Debug.Assert(version.Build >= 0 && version.Build < 10000);
            Debug.Assert(version.Revision >= 0 && version.Revision < 100);

            long longVersion = version.Major * 100000000L +
                   version.Minor * 1000000L +
                   version.Build * 100L +
                   version.Revision;

            //intVersion = (int)longVersion;

            Debug.Assert((long)intVersion == longVersion);
            int highest =
                getAllTypes()
                .Where(t => t.Name == typeof(MPStartup).Name)
                .Select(t => t.GetField("_version", BindingFlags.Static | BindingFlags.NonPublic))
                .Where(f => f != null)
                .Where(f => f.FieldType == typeof(int))
                .Max(f => (int)f.GetValue(null));

            MPLog.Writelog("[Maritime Pack] This Version:" + intVersion + " Highest Version:"+highest);
            if (intVersion != highest)
            {
                MPLog.Writelog("[Maritime Pack] Setting to false: "+ MPFunctions.GetVersion());
                return;
            }

            MPLog.Writelog("[Maritime Pack] Setting to true: " + MPFunctions.GetVersion());
            MPUtilsrunning = true;
        }

        private static IEnumerable<Type> getAllTypes()
        {
            foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
            {
                Type[] types;
                try
                {
                    types = assembly.GetTypes();
                }
                catch (Exception)
                {
                    types = Type.EmptyTypes;
                }

                foreach (var type in types)
                {
                    yield return type;
                }
            }
        }
        public void FixedUpdate()
        {
            if (!MPUtilsrunning) { return; }
        }
    }

I was hoping to use the actual version number from the build but I can't seem to get that to work. So, I switched to the constant intVersion.

So, what I've done is built 2 copies of my .dll.  The only difference is, one has intVersion set to 6 and the other has it set to 7.  I placed both in the same directory (different names) and fired up KSP.

Now, from my log file, what I expected to see was two distinct versions of the .dll running.  I expected one .dll to say it was version 6 and the highest it found was 7 and that it was disabling 6.  I expected version 7 to run and say it was version 7 and 7 is the highest version and that it was going to run.

Instead, I got this

8/5/2016 5:57:52 PM: [Maritime Pack] MPUtils v0.1.6061.32309 Anchors Aweigh!
8/5/2016 5:57:52 PM: [Maritime Pack] MPUtils v0.1.6061.32309 Anchors Aweigh!
8/5/2016 5:57:54 PM: [Maritime Pack] This Version:6 Highest Version:7
8/5/2016 5:57:54 PM: [Maritime Pack] Setting to false: 0.1.6061.32309
8/5/2016 5:57:54 PM: [Maritime Pack] This Version:6 Highest Version:7
8/5/2016 5:57:54 PM: [Maritime Pack] Setting to false: 0.1.6061.32309

It appears that only one of the two dll files even loaded, ran itself twice, found the highest version was the other dll and then set itself to not run.  The other dll apparently didn't even start up.

 

Any ideas what I'm doing wrong?

Link to comment
Share on other sites

Might want to try a non-const value (readonly). Const is normally used to imply that it wont change ever => compiler can do special things with it, which could be having an impact (or compare against _version which appears to be working as expected)

Edited by Crzyrndm
Link to comment
Share on other sites

7 hours ago, Crzyrndm said:

Might want to try a non-const value (readonly). Const is normally used to imply that it wont change ever => compiler can do special things with it, which could be having an impact (or compare against _version which appears to be working as expected)

Originally, I had a chunk of code in there that would read the actual version number of the build and convert it into an integer.  But, when I tried to assign it to _version and read it, it always came back 0.

Yea, _version seems to be found by other copies.

The big question is, why does it appear that only one version of the .dll is running but the KSP log shows both versions (each with distinct version numbers) are being loaded.

Link to comment
Share on other sites

Maybe check what ModuleManager does?  Given that so many mods out there depend on it, and bundle it, and as often-as-not don't necessarily have the most recent version... it's fairly common to end up with multiple versions of ModuleManager sitting there.

I'm pretty sure it has code in there to work out who's newest, and the older one bows out.  Works like a charm.

Link to comment
Share on other sites

Thanks @Snark.  I checked MM and using chunks of this code I got something working I think.  It's similar to what I had but not quite.  His code is CC share alike but you have to attribute to him.  So, here's what I came up with.

 

    [KSPAddon(KSPAddon.Startup.Instantly, true)]
    public class MPStartup : MonoBehaviour
    {
        public static bool MPUtilsrunning;
        private bool multipleCopies = false;

        public void Awake()
        {
            MPConfig.Getconfig();
            //MPLog.NewLog();
            Application.runInBackground = true;
            if (MPUtilsrunning || !ElectionAndCheck())
            {
                       MPLog.Writelog("[Maritime Pack] Multiple copies. Using the first copy. Version: " + MPFunctions.GetVersion());
                Destroy(gameObject);
                return;
            }
            DontDestroyOnLoad(gameObject);
            MPUtilsrunning = true;
            MPLog.Writelog("[Maritime Pack] MPUtils v" + MPFunctions.GetVersion() + " Anchors Aweigh!");
        }

        public void Start()
        {
            if (multipleCopies == true)
            {
                PopupDialog.SpawnPopupDialog(new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), "Multiple Copies of MPUtils", "[ERROR] Multiple copies of MPUTils were found! This may lead to unpredicable results.", "Ok", false, HighLogic.UISkin);
            }
        }

        public bool ElectionAndCheck()
        {
            #region Type election

            // TODO : Move the old version check in a process that call Update.

            Assembly currentAssembly = Assembly.GetExecutingAssembly();
            IEnumerable<AssemblyLoader.LoadedAssembly> eligible = from a in AssemblyLoader.loadedAssemblies
                                                                  let ass = a.assembly
                                                                  where ass.GetName().Name == currentAssembly.GetName().Name
                                                                  orderby ass.GetName().Version descending, a.path ascending
                                                                  select a;

            if (eligible.Count()>1)
            {
                multipleCopies = true;
            }
            if (eligible.First().assembly != currentAssembly)
            {
                //loaded = true;
                MPLog.Writelog("version " + currentAssembly.GetName().Version + " at " + currentAssembly.Location +
                    " lost the election");
                Destroy(gameObject);
                return false;
            }
            string candidates = "";
            foreach (AssemblyLoader.LoadedAssembly a in eligible)
            {
                if (currentAssembly.Location != a.path)
                    candidates += "Version " + a.assembly.GetName().Version + " " + a.path + " " + "\n";
            }
            if (candidates.Length > 0)
            {
                MPLog.Writelog("version " + currentAssembly.GetName().Version + " at " + currentAssembly.Location +
                    " won the election against\n" + candidates);
            }

            #endregion Type election

            return true;
        }


        public void FixedUpdate()
        {
            if (!MPUtilsrunning) { return; }
        }
    }

The MPLog and Getconfig are just some custom logging routines so I don't have to dig through the KSP log.  You can safely ignore them and convert the Writelogs to whatever format you use.

I had to put the popup dialog in the Start.  If you try to put it in awake, it will show up without the button and it null refs.  In start, it looks and works properly.

From what I understand of this, and someone feel free to correct me, it doesn't even attempt to keep the .dll with the highest version number, it just keeps the first one it finds.

Either way, and more importantly to me, is that it does find multiple copies and it does notify the user during startup that multiples were found and it may cause issues.

I suppose with some work the previous code I posted and this code could be bashed together to create something that does check version numbers and keeps the highest one.

Either way, thanks guys for the help.

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...