Jump to content

PAW Event being disabled


Recommended Posts

Fusebox uses the following MM patch to replace the  "module = PART" with it's own part module:

@PART[*]:HAS[#module[Part]]:Final
{
	@module = PartTapIn
}

It does this so it can override all the resource requests and, while not changing anything, it's able to monitor the resource usage.

PartTapIn is derived from Part:

public class PartTapIn : Part
{
 ...
}

It was reported to me that the new "Configure Vessel Naming" is not visible when Fusebox is installed.  After extensive testing, it seems that there is a KSPEvent in the Part module which is hidden and not being made visible in the editor as a result of the KSP Part module not being the main module of the part..

I'm only guessing, since it's not visible, and by looking at a binary dump of the files, I do see something called "SetVesselNaming", but since it's not visible, I can only assume it's a private member which I have no access to.

I thought that maybe the part.Start wasn't being called, but since it also appears to be private, I can't touch that either.

So right now I'm stumped.  Any ideas?

 

Edited by linuxgurugamer
Link to comment
Share on other sites

From easiest to most convoluted:

  1. Cheat by implementing a similarly-named KSPEvent (with different method name) and abusing GameObject.SendMessage
  2. Reimplement the method yourself (VesselRenameDialog looks interesting)
  3. Fix the cached reflected delegate data yourself. This will make things "just work", but it's a little hacky
[KSPAddon(KSPAddon.Startup.MainMenu, true)]
class FixSetVesselNamingIssue : MonoBehaviour
{
    class SneakyWayIntoCachedReflectedData : BaseEventList
    {
        public SneakyWayIntoCachedReflectedData(Type nobodyCares) : base(nobodyCares)
        {
            EnsureDataExists<Part>();       // if ALL modules changed, might not be any cached data for Part
            EnsureDataExists<PartTapIn>();  // it's possible some MM failure didn't edit the parts as expected, so confirm here too

            // "reflectedAttributeCache" is part of BaseEventList and is why we derive from it -> to get access so
            // we can tweak it
            var partData = reflectedAttributeCache[typeof(Part)];           // <-- this has an event we want to copy
            var tapinData = reflectedAttributeCache[typeof(PartTapIn)];     // <-- this is where we'll copy it to

            // unfortunately the only way to tell the various attributes apart
            // is to examine their guiName, which is localized #autoLOC_8003140
            var targetLocalizedName = Localizer.Format("#autoLOC_8003140");

            var configureNamingAttr =
                partData.eventAttributes.Single(kspe => kspe.guiName.Equals(targetLocalizedName, StringComparison.Ordinal));

            if (tapinData.eventAttributes.Any(
                kspe => kspe.guiName.Equals(targetLocalizedName, StringComparison.Ordinal)))
            {
                return; // clearly changes already made
            }

            // insert attribute into PartTapIn data
            tapinData.eventAttributes.Add(configureNamingAttr);


            // copy "SetVesselNaming" delegate from Part to PartTapIn
            // this'll work because it's technically part of PartTapIn as well
            // note: method name directly, no localization needed here
            var setVesselNamingFunc = partData.eventDelegates.Single(mi => "SetVesselNaming".Equals(mi.Name));

            tapinData.eventDelegates.Add(setVesselNamingFunc);
        }

        private static void EnsureDataExists<T>() where T : MonoBehaviour
        {
            if (reflectedAttributeCache.ContainsKey(typeof(T))) return; // already cached

            // if we create an inactive GameObject, we can prevent stuff from triggering
            // (awake, start)
            var dummyGo = new GameObject("dummy");
            dummyGo.SetActive(false); // suppress awake, start

            var target = dummyGo.AddComponent<T>();

            var dummy = new BaseEventList(target); // force data to be cached

            UnityEngine.Object.Destroy(dummyGo.gameObject);
        }
    }

    private void Start()
    {
        try
        {
            new SneakyWayIntoCachedReflectedData(
                typeof(Part)); // we literally don't care about anything but getting this constructor to run
        }
        catch (Exception e)
        {
            Debug.LogError("Exception while trying to meddle with cached data: " + e);
        }
        finally
        {

            Destroy(gameObject); // done
        }
    }
}

 

Link to comment
Share on other sites

16 hours ago, xEvilReeperx said:

From easiest to most convoluted:

  1.  Cheat by implementing a similarly-named KSPEvent (with different method name) and abusing GameObject.SendMessage
  2. Reimplement the method yourself (VesselRenameDialog looks interesting)
  3. Fix the cached reflected delegate data yourself. This will make things "just work", but it's a little hacky

Already did #2, but I'll look at your code, looks interesting 

Edited by linuxgurugamer
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...