Jump to content

PartReplacement Prototype v1


Greys

Recommended Posts

To anyone who has been following #KSPModders or myself over the last 3 days this is not much of a surprise, but I have been developing a proof of concept for a centralized project that will allow other mods to modify the behavior of certain classes in KSP's Part class, with minimal conflict between us.

The concept is simple, certain methods in Part are virtual, these can be overridden already, but the way that it currently works is that you must make a class which inherits from Part and then edit all the cfg files (or use an MM patch) to make every part you care about use your class. The problem here is that every part has only a single class such as this, so if there exist two projects which need to do this, they are inherently incompatible with each other. PartReplacement steps in to fix this, and replaces the class itself, but then offers an Event style system for other assemblies to tap in and access things happening, or change how those things happen. So the two projects instead of making their own Part replacement, interface with this one, and can now be compatible with each other. There do remain, and will always remain situations where there can be only one, but many of the reasons you would override Part are completely unrelated to each other.

As it stands this is only a prototype and proof of concept. In my testing it does function, and presents a standard for expansion; but it does not yet offer access to every virtual class in Part, as that is simply time consuming. I am only aware of a single bug in the current implementation, if during a flight the player reverts to launch, and presumably reverts to quicksave, some object reference is broken and an NRE spam results. I don't entirely understand where so I'm not going to let that stand in the way.

Please understand that this is not ready for distribution to users

Please also understand that this is very much a Request For Comments

PartReplacement is available here https://github.com/Greys0/Virgin-Kalactic/blob/master/Source/Virgin_Kalactic/BetterPart/PartReplacement.cs

There are two classes contained,

-PartTapIn, which via an MM patch is set to be the PART.module for all parts during the loading process

-PartEventTypes, this contains the types that are instantiated in PartTapIn to form the event system, there are only two types currently but this will be expanded as necessary;

Though I am trying to keep all the event types as generic as possible so they can be reused

PartTapIn contains the instantiated events, OnRequestResource and OnResourceRequested, and a type casting funnel to cover the six different overloads of Part.requestResource(), bringing them all down to a single point.

At that point the request is passed to OnResourceRequested to be fulfilled, and the results are then broadcast to OnRequestResource. I personally find the nomenclature at this point a bit easily confused, if anybody has a better naming scheme for these two events I'd be glad to hear it.

Without any other action, PartTapIn defaults to sending the OnResourceRequested event to the original handler from KSP, so until another assembly sets it otherwise, the original behavior is maintained.

Like I said, I have not populated the rest of the virtual classes, but it should at this point only be a matter of deciding on an event type that will work for it, making that if needed, and then assembling the event instance and override.

I have also updated my TrackResource system, entirely rewritten actually; to use this new interface and test that it works, you can see that here:

https://github.com/Greys0/Virgin-Kalactic/blob/master/Source/Virgin_Kalactic/TrackResource/TrackResource.cs

You can see on lines 43-46 how I add the ResourceStats instance to every part's OnRequestResource throughout the vessel; but if you were running from a PartModule you'd only need the regular part reference

So, big questions, is this a good way to do this? How can I improve the nomenclature? What's the next most important method to expand this to? Anybody know where that object reference went? (error log to follow)

Really anything.

Regarding Licensing. I do not care whatsoever about having my name attached to this project, I'm pretty proud of what I've achieved and that's good enough. But, the reason this project exists is as a sort of solution to the There Can Only Be One problem that comes along with overriding Part, as such I really want to dissuade any competing PartReplacement projects. I have to begin with licensed this as all rights reserved to the Virgin Kalactic Group, I am willing to discuss changes to this.

Link to comment
Share on other sites

Here is the complete log exemplifying the NRE that results from reverting-to-launch

https://gist.github.com/Greys0/70fec163ca1677f17803


NullReferenceException: Object reference not set to an instance of an object
at Part.requestResource (.Part origin, Int32 resourceID, ResourceFlowMode flowMode, Double demand, Int32 requestID) [0x00000] in <filename unknown>:0

at Part.RequestResource (System.String resourceName, Double demand, ResourceFlowMode flowMode) [0x00000] in <filename unknown>:0

at PartReplacement.PartEventTypes+SingleCallBack3Arg`4[System.Double,System.String,System.Double,ResourceFlowMode].Invoke (System.String arg1, Double arg2, ResourceFlowMode arg3) [0x00000] in <filename unknown>:0

at PartReplacement.PartTapIn.RequestResource (System.String resourceName, Double demand, ResourceFlowMode flowMode) [0x00000] in <filename unknown>:0

at PartReplacement.PartTapIn.RequestResource (System.String resourceName, Double demand) [0x00000] in <filename unknown>:0

at PartReplacement.PartTapIn.RequestResource (Int32 resourceID, Double demand) [0x00000] in <filename unknown>:0

at ModuleReactionWheel.ActiveUpdate () [0x00000] in <filename unknown>:0

at ModuleReactionWheel.FixedUpdate () [0x00000] in <filename unknown>:0

Link to comment
Share on other sites

@CaptRobeau: is for plug-in developers, it allows to make something I may called a "shared child class" among various plug-in (basic OO programming: you can create a child class from any existing classes, to add more features or specific feature, ie: make a ModuleEngines to use 3 propellants, and another plug-in which play with ModuleEngines class can do its stuff and both can work together, which is not possible basically)

@Greys: I suggest you to find another title, PartReplacement is very confusing.

Link to comment
Share on other sites

Ok so both of you are pretty far off, Justin is closer but critically incorrect, and I believe the best way to explain this is a short class on how plugins in KSP work

Coding for KSP consists primarily of exploiting two mechanisms for making code run, MonoBehaviors, and PartModules, now the tricky part here is that almost everything is a monobehavior.

Monobehavior is a class provided by Unity which has access to a set of event-like systems for making code run when you want it to, mostly by using the KSPAddon attribute to control what scene the code fires on, and specifically named methods that Unity looks for and executes as needed.

PartModule is a class provided by KSP which is itself a monobehavior, with additional built in fields and methods that define a context, the big two are part, an instance of Part, and vessel, an instance of Vessel (you'll see this theme a lot in Squad's code)

PartModules get executed by being added to a Part instance's Modules object (part.Modules), usually via cfg file. The intent of PartModules is to section off functionality so they can be applied to any part, and any part can have many of them, allowing for the mixing of features with minimal custom code.

PartReplacement has Nothing to do with PartModules.

As mentioned there is a class Part which is instantiated for every part that actually exists. Now Part is what remains of an older system intended to allow for the reuse of functionality, Module, or PART{module=Part} in a cfg file. The problem with Modules is that the Part instance can only have one Module, so you can't mix features provided by Modules. Over time Squad has deprecated most of the Modules by converting their functions into PartModules, but there are a few notable remaining Modules, Part is likely to stay forever, but there's also FuelDuct and Strut, which are a weird sort of magical mystery box of disappointment and anger when you look into how they work.

Much of the base features that PartModules make use of to actually achieve stuff is defined within Part, or within Vessel. For example, if a PartModule wishes to charge a resource cost for the use of it's function, such as engines burning fuel to produce thrust, they do so via part.requestResource() (remember, lowercase p is the Part instance). This is all great unless you don't like how Squad decided to make something work, or want to expand upon it.

If you want to change the way something in Part works, you can, maybe. Because Modules are defined per part in the cfg file, you can make a class that inherits from Part (public class BetterPart : Part), and then change the cfg files to use your class instead. The limiting factor is whether you can override the methods that provide the function you want to change, and a good handful of them are Virtual, so you can override them, but most are not. The other limiting factor is that you cannot change signatures, if the class you're overriding took 3 arguments of these types and returned a float; you must also take 3 arguments of those types and return a float. You can of course add wholly new methods without issue, and this can be very useful for adding new functionality; or circumventing access levels.

And here is the problem.

There Can Be Only One Module On A Part.

So if I make a class that inherits from Part, and you make a class that inherits from Part, and our classes do completely unrelated things to Part, only one of us gets to make a given part use our Module.

That is what PartReplacement solves. it Replaces Part and slips in a system that lets other assemblies insert changes to the Part instance through it. Thus, now two plugins that want to make unrelated changes to Part, can do so and be compatible with each other.

PartReplacement is exactly what it is, if you found the name confusing it meant that you didn't understand what this project does.

Link to comment
Share on other sites

  • 5 months later...

As mentioned in the main Virgin Kalactic thread, I am releasing this project under MIT as of now, and will no longer be developing it myself. Repository is in the first post, if anybody cares, have at it.

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