Jump to content

FlowerChild

Members
  • Posts

    754
  • Joined

  • Last visited

Everything posted by FlowerChild

  1. Just put out the first public release of BTSM that includes support for Background Processing: BTSM thread link At present the support is partial in that energy and life support are handled through BP, while the late-game resources processors are not. Those are rather more involved and I wanted to get this out into the wild so people could start testing it beyond my capacity to do so alone. If anyone is looking for a reference on how to implement support for Background Processing feel free to consult the source for the mod. Much thanks for all your help with this james. Handling resources for inactive vessels has been a problem with the mod for a very long time now, and I really appreciate what you've done here
  2. Ah, gotcha. Thanks for the explanation there. The explanation in the OP and on KerbalStuff doesn't really give an impression of when it should be used and what it actually does Cool stuff. Yeah, I think having access to the part prefab or the specific module within would be a minimum to make it useful in that context, and should still keep things relatively simple given the user wouldn't have to deal with parsing proto snapshots or worrying about the limited and sometimes dodgy initialization state of stuff within a background vessel. The context I was going to use it in for example was that I have replacement custom ModuleGenerators within my mod, once again to get around stock rounding errors in energy management. So, this essentially means that I have to handle my own background processing for them, but given they're just producing energy at a constant rate (defined in their .cfg file mind you), using GetBackgroundResource() seemed to be a better fit. Granted, it was super simple for me to just use FixedBackgroundUpdate() instead, especially given I had already written a bunch of helper functions for parsing background vessel data while working on the probe core stuff. Speaking of which, thought you might like to see this: Progress That one is mildly interesting in that I'm actually modifying the damage state of the probe core within the part snapshot during a FixedBackgroundUpdate() and after running multiple tests, it appears that state is automatically successfully saved and loaded once the vessel becomes active again. Relevant code in case it's a useful reference to anyone: public static void FixedBackgroundUpdate( Vessel vessel, uint uiPartFlightID, Func<Vessel, float, string, float> ResourceRequestFunc, ref System.Object customData ) { // Background Processing callback if ( customData != null ) { BTSMModuleProbePowerBackgroundUpdateData probePowerCustomData = (BTSMModuleProbePowerBackgroundUpdateData)customData; if ( probePowerCustomData.m_bIsActive ) { float fResourceDesired = probePowerCustomData.m_fEnergyConsumedRate * TimeWarp.fixedDeltaTime; float fResourceConsumed = ResourceRequestFunc( vessel, fResourceDesired, "ElectricCharge" ); // Check energy consumed and damage probe core on lack of power if it's out for too long if ( fResourceConsumed + 0.01F * fResourceDesired < fResourceDesired ) { probePowerCustomData.m_iOutOfResourceUpdateCount++; if ( probePowerCustomData.m_iOutOfResourceUpdateCount >= m_iNumOutOfEnergyUpdatesForDamage ) { FixedBackgroundUpdateOnProbeCoreOutOfPower( vessel, uiPartFlightID, probePowerCustomData ); } } else { probePowerCustomData.m_iOutOfResourceUpdateCount = 0; } } } } private static void FixedBackgroundUpdateOnProbeCoreOutOfPower( Vessel vessel, uint uiPartFlightID, BTSMModuleProbePowerBackgroundUpdateData probePowerCustomData ) { // the core has been out of power for awhile. Disable further background updates for it and damage it within its config node as well probePowerCustomData.m_bIsActive = false; ProtoPartSnapshot partSnapshot = BTSMUtils.GetProtoPartFromVessel( vessel, uiPartFlightID ); if ( partSnapshot != null ) { ProtoPartModuleSnapshot moduleSnapshot = BTSMUtils.GetProtoModuleSnapshotFromPart( partSnapshot, "BTSMModuleProbePower" ); if ( moduleSnapshot != null ) { Part partPrefab = PartLoader.getPartInfoByName( partSnapshot.partName ).partPrefab; if ( partPrefab != null && partPrefab.Modules != null && partPrefab.Modules.Contains( "BTSMModuleProbePower" ) ) { BTSMModuleProbePower modulePrefab = (BTSMModuleProbePower)partPrefab.Modules["BTSMModuleProbePower"]; if ( modulePrefab != null ) { if ( modulePrefab.canBeDisabled ) { // the probe core can be disabled, so just shut it down moduleSnapshot.moduleValues.SetValue( "coreDisabled", "True" ); ScreenMessages.PostScreenMessage( vessel.vesselName + ": " + partPrefab.partInfo.title + " shut itself down due to lack of power", 10F, ScreenMessageStyle.UPPER_LEFT ); } else { // damage the probe core moduleSnapshot.moduleValues.SetValue( "m_bProbeDamaged", "True" ); ScreenMessages.PostScreenMessage( vessel.vesselName + ": " + partPrefab.partInfo.title + " was damaged due to lack of power", 10F, ScreenMessageStyle.UPPER_LEFT ); } } } } } } Next up I'll be tackling converting my life support system to Background Processing.
  3. Have a question about the following function: public static List<string> GetInterestingResources() Under which circumstances should this be implemented? Does it have any impact if we are implementing our own FixedBackgroundUpdate() handler, or should it only be used with the GetBackgroundResourceCount() and GetBackgroundResource() way of doing things? What is it actually intended to do? Looking over the BP code it seems to only impact the stock module implementation (solar panels, generators, etc.), so I'm wondering under what circumstances it should be applied to a custom one. And a small comment on these functions: public static int GetBackgroundResourceCount() public static void GetBackgroundResource(int index, out string resourceName, out float resourceRate) I just tried using these for a simpler custom module implementation and quickly realized the utility of them is extremely limited due to not having access to any config node information at all. With the current parameters the only thing I could see these being used for is if you have a module that produces or consumes resources at a fixed rate regardless of circumstance (which is what I do have) that also has its production rate hard coded to a specific value within the module itself (which I don't), with no option to have a constant rate parameter even specified in the config file for the part. Not sure what the solution would be there as I think it would rapidly turn into the equivalent of doing things through FixedBackgroundUpdate() if stored data access was added or what have you, but I thought it worth point out that the actual use cases for these functions may currently be limited beyond the point of them being helpful to all but a very narrow set of circumstances. Maybe if the partModule from the part prefab were passed in as a parameter it would become more useful so that the function could access stuff like the default consumption or production rates set for the module? Assuming of course that GetBackgroundResource() is called form a portion of the BP code that has access to it.
  4. Woot! Not a problem man. Glad we managed to track it down Seriously, thanks for all your ongoing support with this. Will download and try it out right away. EDIT: And works like a charm. Double "Woot!"
  5. No, no exceptions at all. I just ran a test where I straight out copy pasted your function prototype listed on Kerbal Stuff for the complex form of FixedBackgroundUpdate() and renamed all my local variables to match your names to make sure I hadn't just made some weird typo somewhere that was preventing it being called, and am still getting nothing on it. So, simple form good, complex form bad apparently And yeah, I'm comfortable compiling from source, and previously set myself up to do so with BP when I was running some initial tests. Before we start inserting debug statements though, can you pass me a code snippet where you're testing with *just* the complex form of the FixedBackgroundUpdate() callback so I can make 100% certain my function definition is kosher? If it's working for you, and not for me, the only thing I can think of is that the definition isn't 100% identical and thus BP isn't recognizing my callback.
  6. Fair enough, but doesn't explain the additional weirdness described in my edit though. Following up on it I just launched another probe to full orbit in my simple test case, and still getting no callbacks. Hmmm...ok, that may be problematic given my mod essentially requires DR to be installed along side it (not doing that for my test cases here though). Can talk about that separately though as callbacks weren't resulting regardless. At the moment I'm just trying to reproduce when the callbacks *do* get called, rather than when they don't, as other than that one specific instance I mentioned above right after launch, they aren't happening right now EDIT: Ah...this is very interesting: Exited game. Restarted. Went back into game and loaded simple test case with probe in orbit. No callbacks. Exited game again. Uncommented the simple form of FixedBackgroundUpdate(). Restarted. Callbacks happening. So it looks like the simple form is working, and if it's present, callbacks are working fine. If you just have the complex form I have listed above, no callbacks are triggered. So either there's a problem with my syntax (you can check it above), or there's something wonky about the complex form in particular. All test cases where I haven't had callbacks have been *only* with the complex form. I'll go back now and check it with DR installed and a more populated save game with the simple form. EDIT 2: Yup, DR installed, populated save game, simple form of FixedBackgroundUpdate() present, popped into save and got debug messages for a whole bunch of different vessels indicating FixedBackgroundUpdate() was being called. Looks like this is really a problem with the complex form.
  7. The specific test case I am using right now is, yes, as I cleaned out the mods folder of everything other than BTSM and BP to make sure it wasn't a secondary interaction, and created a new save with just a single probe core on the launch pad. Same thing seems to be happening with existing saves and many vessels in flight however, which is why I trimmed it down to a test case. I was also getting a bunch of debug log output about modules being in the wrong index with Deadly Reentry installed, I assume because it dynamically adds modules to handle reentry. Launching my simple test case the BackgroundLoad() function is called after I return to the space center, and the simple form of FixedBackroundUpdate() begins to be called each tick. EDIT: Further info: Upon exiting the game, and commenting out the simple form to see if the complex would be called, I booted the game back up. Vessel status is now "landed at launch pad" neither BackgroundLoad() or FixedBackgroundUpdate() appear to be called. Making vessel active then returning to space center doesn't start it up either. Making it active, flying it up a bit, then relanding it and returning to space center also fails to net results. I seemed to get a brief moment there when I first launched it and then returned to space center where BP started calling the callbacks, and that was it. Surprisingly, recovering that vessel, placing a new one, launching it, landing it back, and returning to space center doesn't seem to start it up again either.
  8. BackgroundProcessing: Running assembly at path\Kerbal Space Program\GameData\BackgroundProcessing-0.4.0.0.dll (0.4.0.0) Later on getting messages about clearing and saving game state, so BP itself seems to be functioning fine. The callbacks themselves just never seem to be called.
  9. Hmmm...something appears to have gone amiss with version 4.0. None of the following functions seem to be being called within my part module: public static void BackgroundLoad( Vessel vessel, uint uiPartFlightID, ref System.Object customData ) { Debug.Log( "BTSMModuleProbePower: background load for " + vessel.vesselName ); } public static void FixedBackgroundUpdate(Vessel v, uint partFlightID, ref System.Object data) { Debug.Log( "BTSMModuleProbePower: simple persistant update for " + v.vesselName ); } public static void FixedBackgroundUpdate( Vessel vessel, uint uiPartFlightID, Func<Vessel, float, string, float> ResourceRequestFunc, ref System.Object customData ) { Debug.Log( "BTSMModuleProbePower: Persistant update for " + vessel.vesselName ); } No debug output is generated, and while I've trimmed down the above to only list the log output at the start, the code that follows to drain power in the background isn't triggering either. I only included the simple form of FixedBackgroundUpdate() in there as I wanted to test if it was just a problem with the complex form, but neither seem to be called. Full code for the module below: using System; using System.Collections.Generic; using System.Linq; using System.Text; using UnityEngine; namespace BTSM { [KSPModule( "Probe Core" )] class BTSMModuleProbePower : BTSMPartModule { private static int m_iNumOutOfEnergyUpdatesForDamage = 20; [KSPField( isPersistant = false )] public float energyConsumedRate = 0.16666668F; // default is same as Stayputnik (6X a stock probe core) [KSPField( isPersistant = false )] public bool canBeDisabled = false; [KSPField( isPersistant = true )] public bool m_bProbeDamaged = false; // persistant variable to track if the probe has been damaged by lack of power private float m_fEnergyRequiredLeftovers = 0F; // variable to store any energy remnants required which haven't been consumed on a previous update private int m_iOutOfEnergyUpdateCount = 0; // acts as buffer to prevent momentary power supply problems due to vanilla bugs causing probe cores to fail [KSPField( isPersistant = true, guiActive = true, guiActiveEditor = true, guiName = "Probe Core"), UI_Toggle( disabledText="Enabled", enabledText="Disabled" )] public bool coreDisabled = false; public bool m_bPreviousCoreDisabled = false; [KSPAction( "Toggle Probe Core" )] public void ToggleProbeCoreAction( KSPActionParam param ) { if ( vessel != null && vessel.IsControllable && canBeDisabled ) { coreDisabled = !coreDisabled; RefreshAssociatedWindows(); } } public override void OnStart( StartState state ) { base.OnStart(state); // FCTEST: Debug.Log( "BTSMModuleProbePower: Start()" ); if ( !m_bInEditor ) { if ( m_bProbeDamaged ) { DamageAssociatedProbeCore(); } else { SetProbeCoreDeactivated( coreDisabled ); } } else { BaseField coreEnabledField = Fields["coreDisabled"]; if ( coreEnabledField != null ) { coreEnabledField.guiActive = canBeDisabled; coreEnabledField.guiActiveEditor = canBeDisabled; } } m_bPreviousCoreDisabled = coreDisabled; m_fEnergyRequiredLeftovers = 0F; m_iOutOfEnergyUpdateCount = 0; } public override void FixedUpdate() { base.FixedUpdate(); // FCTEST: Debug.Log( "BTSMModuleProbePower: Fixed Update" ); if ( !m_bInEditor ) { bool bShouldGUIBeActive = canBeDisabled; if ( m_bProbeDamaged ) { bShouldGUIBeActive = false; } else { if ( m_bPreviousCoreDisabled != coreDisabled ) { SetProbeCoreDeactivated( coreDisabled ); m_fEnergyRequiredLeftovers = 0F; m_iOutOfEnergyUpdateCount = 0; } if ( !coreDisabled ) { if ( !AttemptToDeductEnergyForUse() ) { if ( !canBeDisabled ) { DamageAssociatedProbeCore(); bShouldGUIBeActive = false; } else { coreDisabled = true; SetProbeCoreDeactivated( true ); ScreenMessages.PostScreenMessage( part.partInfo.title + " shut itself down due to lack of power.", 10F, ScreenMessageStyle.UPPER_CENTER ); m_fEnergyRequiredLeftovers = 0F; m_iOutOfEnergyUpdateCount = 0; } } } else if ( !vessel.IsControllable ) { bShouldGUIBeActive = false; } } BaseField coreEnabledField = Fields["coreDisabled"]; if ( coreEnabledField != null ) { if ( coreEnabledField.guiActive != bShouldGUIBeActive ) { coreEnabledField.guiActive = bShouldGUIBeActive; RefreshAssociatedWindows(); } } UpdateStateString(); } m_bPreviousCoreDisabled = coreDisabled; } private bool AttemptToDeductEnergyForUse() { return ConsumeResourceReliable( "ElectricCharge", energyConsumedRate, m_iNumOutOfEnergyUpdatesForDamage, ref m_iOutOfEnergyUpdateCount, ref m_fEnergyRequiredLeftovers ); } private void DamageAssociatedProbeCore() { ModuleCommand associatedCommandModule = FindAssociatedCommandModule(); if ( associatedCommandModule != null ) { associatedCommandModule.minimumCrew = 1; if ( !m_bProbeDamaged ) { m_bProbeDamaged = true; ScreenMessages.PostScreenMessage( part.partInfo.title + " was damaged due to lack of power.", 10F, ScreenMessageStyle.UPPER_CENTER ); } } } private void SetProbeCoreDeactivated( bool bDeactivated ) { ModuleCommand associatedCommandModule = FindAssociatedCommandModule(); if ( associatedCommandModule != null ) { if ( bDeactivated ) { associatedCommandModule.minimumCrew = 1; } else { associatedCommandModule.minimumCrew = 0; } } } private void UpdateStateString() { ModuleCommand associatedCommandModule = FindAssociatedCommandModule(); if ( associatedCommandModule != null ) { string sDesiredStateString = "Operational"; if ( m_bProbeDamaged ) { sDesiredStateString = "Damaged"; } else if ( coreDisabled ) { sDesiredStateString = "Disabled"; } associatedCommandModule.controlSrcStatusText = sDesiredStateString; } } private ModuleCommand FindAssociatedCommandModule() { return (ModuleCommand)FindAssociatedModuleOfType( "ModuleCommand" ); } public override string GetInfo() { string sDescString = "<b><color=#99ff00ff>Requires:</color></b>\n" + "- <b>Electric Charge: </b>" + FormatRateString( energyConsumedRate ) + "\n"; if ( canBeDisabled ) { sDescString += "\n<b>Can Be Safely Powered Down</b>\n"; } else { sDescString += "\n<b>WARNING: Requires constant power to avoid damage</b>\n"; } return sDescString; } /*-----------------[ Background Processing Handling ]----------------------------------------------*/ public static void BackgroundLoad( Vessel vessel, uint uiPartFlightID, ref System.Object customData ) { // FCTEST Debug.Log( "BTSMModuleProbePower: background load for " + vessel.vesselName ); bool bIsActive = false; float fEnergyConsumedRate = 0F; ProtoPartSnapshot partSnapshot = BTSMUtils.GetProtoPartFromVessel( vessel, uiPartFlightID ); if ( partSnapshot != null ) { ProtoPartModuleSnapshot moduleSnapshot = BTSMUtils.GetProtoModuleSnapshotFromPart( partSnapshot, "BTSMModuleProbePower" ); if ( moduleSnapshot != null ) { Part partPrefab = PartLoader.getPartInfoByName( partSnapshot.partName ).partPrefab; if ( partPrefab != null ) { if ( partPrefab.Modules != null ) { if ( partPrefab.Modules.Contains( "BTSMModuleProbePower" ) ) { BTSMModuleProbePower modulePrefab = (BTSMModuleProbePower)partPrefab.Modules["BTSMModuleProbePower"]; if ( modulePrefab != null ) { bool bCoreDisabled = false; bool bCoreDamaged = false; if ( bool.TryParse( moduleSnapshot.moduleValues.GetValue( "coreDisabled" ), out bCoreDisabled ) && bool.TryParse( moduleSnapshot.moduleValues.GetValue( "m_bProbeDamaged" ), out bCoreDamaged ) ) { bIsActive = !(bCoreDisabled || bCoreDamaged ); fEnergyConsumedRate = modulePrefab.energyConsumedRate; // FCTEST Debug.Log( "BTSMModuleProbePower: Backround Processing successfully initialized for: " + vessel.vesselName ); } } } } } } } customData = new BTSMModuleProbePowerBackgroundUpdateData( bIsActive, fEnergyConsumedRate ); } public static void FixedBackgroundUpdate(Vessel v, uint partFlightID, ref System.Object data) { // FCTEST Debug.Log( "BTSMModuleProbePower: simple persistant update for " + v.vesselName ); } public static void FixedBackgroundUpdate( Vessel vessel, uint uiPartFlightID, Func<Vessel, float, string, float> ResourceRequestFunc, ref System.Object customData ) { // FCTEST Debug.Log( "BTSMModuleProbePower: Persistant update for " + vessel.vesselName ); // Background Processing callback if ( customData != null ) { BTSMModuleProbePowerBackgroundUpdateData probePowerCustomData = (BTSMModuleProbePowerBackgroundUpdateData)customData; if ( probePowerCustomData.m_bIsActive ) { float fResourceConsumed = ResourceRequestFunc( vessel, probePowerCustomData.m_fEnergyConsumedRate * TimeWarp.fixedDeltaTime, "ElectricCharge" ); // FCTEST Debug.Log( "BTSMModuleProbePower: Persistant update for consumed: " + fResourceConsumed ); // FCTODO: Check energy consumed and damage probe core on lack of power } } } } class BTSMModuleProbePowerBackgroundUpdateData { public bool m_bIsActive; public float m_fEnergyConsumedRate; public BTSMModuleProbePowerBackgroundUpdateData( bool bIsActive, float fEnergyConsumedRate ) { m_bIsActive = bIsActive; m_fEnergyConsumedRate = fEnergyConsumedRate; } } } I included debug output in the OnStart() and FixedUpdate() functions as well to verify that the module is indeed being added to the parts, which it is. Any ideas?
  10. Hey man, if you're cool with it than so am I, and I certainly didn't any intend any of that to be a criticism of how you're handling things. I tend to feel rather embarrassed when I feel that my problems are being turned into someone else's however, as I don't think that you signed up for running both DR and BTSM support when you took over DR
  11. Hehe...I suspected you might be a C++ programmer actually, as I don't think I've ever seen C# code that makes such extensive use of what basically amounts to pointers to functions and such. I actually learned a fair amount of C# syntax I wasn't aware of through perusing your code, so I really appreciate all this on the level of being a learning experience as well
  12. Not sure if that's really going to happen at this point man, even with the the option you mentioned over PM. From what I'm hearing from players the last non-beta release is distinctly easier than what DR used to be with the settings in BTSM. At present I'm suspecting that an extensive rebalance to BTSM will be required to accommodate stock reentry effects once 1.0 comes out, and until that time I don't see there being much point in either of us going out of our way to try and accommodate maintaining the different way of balancing things that you and I are going for. I really do appreciate the effort on your part to minimize the impact through config file settings and such, but at this point I think I've come to view it as a lost cause to try and keep up with the changes that have been occurring to DR. I'd also appreciate it if BTSM players not bother Starwaster with what are ultimately BTSM specific issues. It's really not fair to be saturating his thread with support requests that really have nothing to do with him like this. BTSM has always made extensive modifications to DR, and any support issues that creates are on my shoulders, not his. It really doesn't make any more sense to be telling Starwaster about problems using BTSM in combination with his mod creates, than it would be to be telling Squad about it, as I'm essentially modding his mod, not the other way around.
  13. From what I've seen of its internals it's both extremely flexible (especially with the additions in the latest release), and the approach taken within the code is extremely well thought out, so while I do have my performance concerns, particularly where large numbers of solar panels are involved, I think if any method is likely to resolve this issue in a performance friendly way, this is likely it. It's obvious from the code that it was architected with performance in mind. It's a bit of a shame IMO that this thread has received so little attention the past couple of months. I was planning on checking this out for awhile now but had other things to get off my plate before doing so. BTW James, on the above, I really think it would help the visibility of the mod greatly if the OP here in this thread were more robust. I can definitely appreciate you not wanting to essentially duplicate code by having the instructions for use in two places and thus having to maintain both, but in this case I think it would really be worth the hassle if you're hoping for this system to gain wider acceptance amongst modders. I know myself, I was originally linked to the thread here, took one look at the OP and its brevity and thought "ok...this isn't serious". I almost walked away from it entirely as a result but then thought better of it and decided to check the Kerbal Stuff page almost on a whim. I'm very glad that I took the time to do so as it became immediately apparent that my first impressions were not at all accurate when I saw your callback system.
  14. For exactly what it's being used for here with the ref to an object in C# Any confusion here is stemming from layers of abstraction that have been introduced with each new generation of language. A pointer is just a variable containing an address in memory abstracted slightly so that it has an associated type (which was the only way to do it in C). A reference is just an abstracted pointer that makes things a little more convenient and less prone to error (which was introduced in C++). An object passed in C# as a parameter is just an abstracted reference, and that was likely done so people wouldn't pass objects by value all the time when they didn't know any better, but it also tends to confuse geezers like me who are used to having to explicitly specify when something is a reference or pointer. Thus, in passing a reference to an object in C# you're essentially passing a pointer to a pointer. You're allowing the called function to modify your original reference to that object (not just the contents of the object), and make it refer to something else entirely. With just a pointer to the object, you'd be modifying the contents of the object in the function, but couldn't change which object the calling code was referring to. In this case we want to be able to create a data object and tell BackgroundProcessing to hang onto it for us for later, so we want to specify an actual object, not just modify the contents of an existing one. What it all comes down to (and the way I think of it because I used to code in Assembly) is that you're passing an address in memory as a parameter, which points to another address in the calling code, that points to the object, so that the called function can change it to point to another object entirely. EDIT: Actually, here, I just wrote this up for my mod which is probably a better explanation of what's going on here than anything I've said above: public static void BackgroundLoad( Vessel vessel, uint uiPartFlightID, ref System.Object customData ) { bool bIsActive = false; float fEnergyConsumedRate = 0F; ProtoPartSnapshot partSnapshot = GetProtoPartFromVessel( vessel, uiPartFlightID ); if ( partSnapshot != null ) { ProtoPartModuleSnapshot moduleSnapshot = GetProtoModuleSnapshotFromPart( partSnapshot, "BTSMModuleProbePower" ); if ( moduleSnapshot != null ) { Part partPrefab = PartLoader.getPartInfoByName( partSnapshot.partName ).partPrefab; if ( partPrefab != null ) { if ( partPrefab.Modules != null ) { if ( partPrefab.Modules.Contains( "BTSMModuleProbePower" ) ) { BTSMModuleProbePower modulePrefab = (BTSMModuleProbePower)partPrefab.Modules["BTSMModuleProbePower"]; if ( modulePrefab != null ) { bool bCoreDisabled = false; bool bCoreDamaged = false; if ( bool.TryParse( moduleSnapshot.moduleValues.GetValue( "coreDisabled" ), out bCoreDisabled ) && bool.TryParse( moduleSnapshot.moduleValues.GetValue( "m_bProbeDamaged" ), out bCoreDamaged ) ) { bIsActive = !(bCoreDisabled || bCoreDamaged ); fEnergyConsumedRate = modulePrefab.energyConsumedRate; } } } } } } } customData = new BTSMModuleProbePowerBackgroundUpdateData( bIsActive, fEnergyConsumedRate ); } The really important bit is that last line: customData = new BTSMModuleProbePowerBackgroundUpdateData( bIsActive, fEnergyConsumedRate ); Notice how I'm creating a whole new object and setting customData to it, not just manipulating its internal values. That's essentially setting what object is being referred to in the calling code, not just locally within the function.
  15. Yes, I realize. But in C# any object as a parameter is essentially already a ref (they're all passed by reference, not value, unless you're passing a base type like an int) and thus I suspect by adding another "ref" keyword on top of that, you're essentially creating a ref to a ref, allowing the function to essentially set the reference the calling code is using. I'm pretty sure that jamespicone has it right here, as that's exactly what is needed in this situation so that you can create and set your own data object. As I said, my only confusion with it is likely the difference between how C++ and C# operate in that regard, as in C++ objects default to passing by value. In C++ the equivalent code would look something like: public static void BackgroundLoad(Vessel v, uint partFlightId, System.Object &&data) With the '&' being the equivalent of the 'ref' keyword in C#. But references to references don't even exist in C++ so you'd likely be using a pointer to a pointer instead, but pointers don't exist in C# so you wouldn't be able to use that here. Hopefully you can now see why I was a tad confused by this
  16. Actually, looking at this a little more closely, maybe the syntax is eluding me here (I'm primarily a C++ programmer rather than C#), but I can see no way of actually setting the data with the above. Could you possible provide a small use example here? As I'm reading it, if you set System.Object to another object, you'd only be doing so local to the function, and not actually setting it for storage in background. To my mind, for this to work, you'd either have to return an object from this function and have the calling code then store the return value, or the data parameter would need to be some kind of reference to a reference that could then be set from within the function. Or is data actually already a reference to a reference given that parameters default to passing by reference in C#, rather than passing by value as happens in C++? Actually, in writing this, I suspect that's exactly what's happening here, but I'd appreciate confirmation that I'm interpreting the intended usage correctly. It's one of my pet peeves about C# the way the whole pass by reference or pass by value thing isn't required to be explicitly stated and differs between base types and objects
  17. Totally awesome man. Thank you One question on the save: are any modifications performed to the config nodes contained within the vessel automatically saved, or do we have to handle that part on our end? Like for example if I have a persistent field within a ProtoPartModuleSnapshot, can I simply modify the field directly and then trust that it will be saved appropriately, or is there more to it than that?
  18. Well see, I haven't checked this thread in a long while either now If you're still having trouble with this, I can do a write up on how it to be sure, as I'm already doing it in several BTSM contracts. Let me know if that's the case (probably best via PM so we don't miss it again), but I suspect a couple of months later you may have already sorted it. It's a bit of a shame this thread has fallen into disuse and been unstickied as there's a lot of useful information contained within, and definitely room for ongoing conversation and knowledge sharing with the integration of Fine Print into stock. I actually just popped it open again to reference the table of relative values of contracts based on location and prestige value that DMagic posted earlier in the thread as I had forgotten something about it
  19. Yup, I noticed the cheating on the tracking which is certainly fine by me. If it were just for my own purposes I'd probably even go more abstract and not consider orientation to cut down on overhead as BTSM vessels tend to be rather heavy on the number of solar panels Gotcha. Yeah, the data I'm working with is straight out of the config node, so I'm not really concerned with being able to save/load any changes I make during persistent updates (other than the actual resource amounts which you're taking care of in your code). I was considering doing something like that for my fuel processors though, so that I could just buffer the amount of all fuel produced, and then get it to flow into the appropriate tanks via crossfeed once the vessel becomes active again (since the fuel can't be used in the background anyways, there's no point trying to manage flow via crossfeed while it's inactive), so that's a good thing for me to know so I can make other plans there. That would be quite awesome man. Thanks a bunch
  20. Ah, fair enough. That wasn't apparent from my cursory examination of your code. I was under the impression you were storing the orientation of specific instances of panels and such, and thus assumed that an association to the actual module was maintained. How about parts then? Do you have a clear association between the parts and the data that would then allow creation of such data stores on a per part per module *type* basis? I suspect that for my purposes anyways, that would be just as good. Not sure I get that one though. Wouldn't all your stored vessel data be reinitialized if that were to happen? Not sure if others would consider that a problem, but I can't really think of a circumstance where I would want to have multiple modules of the same type within a single part. Worst case, you could always loop through the individual instances within your FixedBackgroundUpdate function if you *really* needed to do something like that. To me then, the above is definitely an acceptable compromise, and I definitely realize that compromises are an integral part of making something like this happen
  21. A bit more feedback based on my further experimentation: It's occurring to me that it would be super useful in implementing custom background processing for a module if some basic data storage on a per module basis were provided. Looking over the source, it appears you are already doing this kind of thing for stock parts (for example, solar panels) so that when initializing each of the background vessels you can parse the config nodes associated with them once and then refer to that data later on without having to parse it every update. For custom handlers though, unless I'm missing something, modders aren't really left with much of a choice other than to parse those config nodes every update (which would likely be a nasty drain on performance) or maintain their own independent vessel/module lists to store custom data, which effectively duplicates a lot of the functionality already in BackgroundProcessing. So what I'm wondering is if it might not be really helpful to have static callback functions for initializing such custom data within a part module, called when BackgroundProcessing initializes the rest of the vessel data, and returning a reference to it. The list of BackgroundProcessing vessel/module data could then contain a reference to it (null by default), and pass it along to the FixedBackgroundUpdate() functions so that custom handlers could type cast it into whatever specific data type we setup and do with it what they will. To provide a more concrete example, in the case of my probe core energy management code that I posted previously, it would be super handy if I could store whether a particular probe was damaged or disabled during initialization of a background vessel, along with its energy consumption rate, then refer to those stored variables in my custom FixedBackgroundUpdate() function to determine whether it should be draining power or not and how much. I can also see that kind of thing being useful for other things I'm going to be implementing, such as needing to know how many Kerbals are within a part to determine its life support requirements. So maybe something along these lines: public static object InitializeCustomModuleData( Vessel vessel, uint uiFlightID ) { // parse vessel data here return new BTSMModuleProbePowerBackgroundStorage( bIsActiveCore, fEnergyConsumptionRate ); } public static void FixedBackgroundUpdate( Vessel vessel, uint uiFlightID, Func<Vessel, float, string, float> ResourceRequestFunc, object customModuleData ) { BTSMModuleProbePowerBackgroundStorage probeModuleData = (BTSMModuleProbePowerBackgroundStorage)customModuleData; if ( probeModuleData.m_bIsActiveCore ) { // do stuff } } Any thoughts on this? The above may not represent the best implementation for such a scheme, but is what struck me as immediately useful while I was working on creating a custom background update handler.
  22. Fair enough, will stay away from 4.5 in the future if I can avoid it
  23. Can't remember precisely when I changed it, but I've certainly released several version of BTSM compiled with 4.5, so if it was a problem at some point, it definitely isn't with current versions of KSP or I would have heard back from players about it by now Cool stuff man. That should help a lot.
  24. All right, as per our discussion last night just tried compiling with .NET Framework 3.5 instead of the 4.5 I was using and everything seems to be working fine so far. I suspect I had changed to 4.5 awhile back to compile relative to another mod I was working with, but really can't remember the details there other than knowing I did it intentionally at some point. Thanks for the help on tracking it down. On one point of immediate feedback: the debug log spam is currently rather out of control and I suspect I will likely compile my own version of BackgroundProcessing to get rid of that for now. While it might not be a priority for end-users (although I think excessive log spam tends to negatively impact performance), for mod developers it's a rather big deal in being able to track down our own debugging messages amongst a wall of text
×
×
  • Create New...