I don't use UCGO unpackable cargo all that often, but I became interested in trying to determine what exactly is causing the reported problem of unpacked cargo returning to packed state after a scenario save/reload. The discussion always seemed to be centered around AFCMODE numbers so I started there, did a lot of tests, recorded a lot of results, and came up with a Lua script that I think could be the start of finding a 'fix' for the problem.
The difficulty that most run into when trying to find information about what AFCMODE in a scenario file is for is that within the Orbiter internals, it's not called AFCMODE. It's called something more akin to ADCMODE. Specifically, the Orbiter SDK information one wants to look for is information pertaining to:
DWORD VESSEL::GetADCtrlMode() const
and
void VESSEL::SetADCtrlMode(DWORD mode) const
ADCtrlMode is AeroDynamic Control Surfaces Mode, while AFCMODE as appears in scenario files could simply be a typo in the internals which would be a nightmare to correct since every scenario file out there uses that spelling; or, AFCMODE might be read as Aerodynamic Flight Control Surfaces Mode. Whatever the reason, scenario files use AFC and internals use ADC.
Now that that's out of the way, what do the numbers for AFCMODE mean? The number used for AFCMODE is a sequence of bit flags defining which types of control surfaces can be manually controlled by the user. Only 3 bits are used. bit 0 indicates whether elevators are enabled (1) or disabled (0); bit 1 is for rudder; and bit 2 is for ailerons. So, you can see that as far as Orbiter is concerned, values for AFCMODE should be between 0 (all disabled) and 7 (all enabled) inclusive. However, the mode used to set these flags is a DWORD long, so there are plenty of other bits to fiddle with. It's just that the outcome of doing so is not defined by Orbiter.
So here's where the UCGO 'odd-looking' AFCMODE numbers come in. UCGO appears to be using additional bits of the AFCMODE to store information. Through trial and error I've come up with the following observations:
1) Unpacked cargo always has bit 3 set.
(2^3 = 8 ; note that the oft-recommended AFCMODE value of 120 is equal to 8, MOD 16. More on this later.)
2) Packed cargo always has bit 4 set, and may set higher bits as well.
(However, the use of "CargoUnpacked 0" in the scenario file seems capable of overriding these higher bits. Perhaps there is some legacy code in UCGO 2.0.)
3) Packed cargo which is unpacked during a simulation will set bit 3 but does not unset the correct bits 4 or higher. I think the UCGO internals which handle these bit manipulations might be off by a bit which creates new bits set that are unneeded (ex: AFCMODE 48 while packed) or fails to unset the proper bits when the cargo is unpacked (ex: AFCMODE 24 when unpacked).
(This results in unpacked cargo which seems to function, but does not display the appropriate 'unpacked' meshes. Bit 3 is indicating unpacked, "CargoUnpacked" is indicating unpacked, but the higher bits are indicating packed. My guess is that UCGO internals are doing bit checks such that having multiple bits set allows the cargo to appear to be in both packed and unpacked states at the same time.)
4) Upon scenario load, some unpackable cargo (whether packed or unpacked) will receive an additional bit being set, above that specified in the scenario file AFCMODE for that cargo. This seems to be related to #3 above.
(This is why you might get the cargo working by manually editing the scenario file, but it all goes haywire once you create a new save. Internally the mode is not what it was when the scenario started.)
So to try and correct this in the sim we need the following:
A) Bits 0, 1, and 2 must be preserved since those are defined within the Orbiter SDK and are used to indicate the usable state of control surfaces.
B) If the cargo is unpacked, bit 3 needs to be set and bits 4 and higher need to be cleared.
C) If the cargo is packed, the UCGO internal "CargoUnpacked 0" information seems to work to correctly identify that it is packed. But, bits 4 and higher are going to be set for some reason that I cannot discern. So we need to disable those bits after the scenario loads, or before a save to prevent 'incorrect' AFCMODE settings being written into the scenario save file.
The easiest way to accomplish these that I can think of is to cycle through each vessel, mod its adcmode with 16, and if the mode changed then write the new mode back to the vessel. This will ensure that all AFCMODE numbers written to a save file will be between 0 and 15 inclusive (0-7 for control surfaces with packed cargo, 8-15 for control surfaces with unpacked cargo).
To test whether or not a small correction like this will help overcome the problem people have had with unpacked UCGO cargo, I wrote a short Lua script to modify the adcmode of vessels on the fly. I've never used Lua before so this is really just a way to start discussion for a possible fix to the unpacked cargo problem. I think a small plugin module to handle this automatically during scenario load and save would be appreciated by users who don't want to mess with Lua scripts; but, that can wait until we hear some test results back.
Below is the script I've been using to test out 'correcting' packed and unpacked cargo. It seems to work for me, but I don't use unpackable cargo all that often. Better testing by cargo geeks is needed. Note also that there is no way I know of from Lua script to tell whether a vessel is a UCGO cargo or not, so this just cycles through every vessel in the scenario. If there are other add-on vessels out there that use higher bits of AFCMODE for their own purpose, then this is going to break those vessels most likely. But I don't think I've ever come across anything else that modifies AFCMODE beyond bit 2.
It would be wonderful if folks could test this out. It would be even better if some real programmers and some folks who understand Orbiter internals better could improve upon this proof of concept to make a module that would automatically handle this for users.
When the function fixcargo() is run within the sim, cargo should take on the state that it was supposed to have been left in -- packed or unpacked. It should not unpack things that are supposed to be packed, nor should it pack things up that should be unpacked. Getting cargo to take on the correct state can be accomplished by running this script function after the scenario loads. To ensure that the AFCMODEs are correct for the next time the scenario is loaded, run this script function again prior to saving.
Thanks to those who test and provide feedback or add to the discussion of how we might all come up with a fix for the unpacking problem.
-- Mike
The difficulty that most run into when trying to find information about what AFCMODE in a scenario file is for is that within the Orbiter internals, it's not called AFCMODE. It's called something more akin to ADCMODE. Specifically, the Orbiter SDK information one wants to look for is information pertaining to:
DWORD VESSEL::GetADCtrlMode() const
and
void VESSEL::SetADCtrlMode(DWORD mode) const
ADCtrlMode is AeroDynamic Control Surfaces Mode, while AFCMODE as appears in scenario files could simply be a typo in the internals which would be a nightmare to correct since every scenario file out there uses that spelling; or, AFCMODE might be read as Aerodynamic Flight Control Surfaces Mode. Whatever the reason, scenario files use AFC and internals use ADC.
Now that that's out of the way, what do the numbers for AFCMODE mean? The number used for AFCMODE is a sequence of bit flags defining which types of control surfaces can be manually controlled by the user. Only 3 bits are used. bit 0 indicates whether elevators are enabled (1) or disabled (0); bit 1 is for rudder; and bit 2 is for ailerons. So, you can see that as far as Orbiter is concerned, values for AFCMODE should be between 0 (all disabled) and 7 (all enabled) inclusive. However, the mode used to set these flags is a DWORD long, so there are plenty of other bits to fiddle with. It's just that the outcome of doing so is not defined by Orbiter.
So here's where the UCGO 'odd-looking' AFCMODE numbers come in. UCGO appears to be using additional bits of the AFCMODE to store information. Through trial and error I've come up with the following observations:
1) Unpacked cargo always has bit 3 set.
(2^3 = 8 ; note that the oft-recommended AFCMODE value of 120 is equal to 8, MOD 16. More on this later.)
2) Packed cargo always has bit 4 set, and may set higher bits as well.
(However, the use of "CargoUnpacked 0" in the scenario file seems capable of overriding these higher bits. Perhaps there is some legacy code in UCGO 2.0.)
3) Packed cargo which is unpacked during a simulation will set bit 3 but does not unset the correct bits 4 or higher. I think the UCGO internals which handle these bit manipulations might be off by a bit which creates new bits set that are unneeded (ex: AFCMODE 48 while packed) or fails to unset the proper bits when the cargo is unpacked (ex: AFCMODE 24 when unpacked).
(This results in unpacked cargo which seems to function, but does not display the appropriate 'unpacked' meshes. Bit 3 is indicating unpacked, "CargoUnpacked" is indicating unpacked, but the higher bits are indicating packed. My guess is that UCGO internals are doing bit checks such that having multiple bits set allows the cargo to appear to be in both packed and unpacked states at the same time.)
4) Upon scenario load, some unpackable cargo (whether packed or unpacked) will receive an additional bit being set, above that specified in the scenario file AFCMODE for that cargo. This seems to be related to #3 above.
(This is why you might get the cargo working by manually editing the scenario file, but it all goes haywire once you create a new save. Internally the mode is not what it was when the scenario started.)
So to try and correct this in the sim we need the following:
A) Bits 0, 1, and 2 must be preserved since those are defined within the Orbiter SDK and are used to indicate the usable state of control surfaces.
B) If the cargo is unpacked, bit 3 needs to be set and bits 4 and higher need to be cleared.
C) If the cargo is packed, the UCGO internal "CargoUnpacked 0" information seems to work to correctly identify that it is packed. But, bits 4 and higher are going to be set for some reason that I cannot discern. So we need to disable those bits after the scenario loads, or before a save to prevent 'incorrect' AFCMODE settings being written into the scenario save file.
The easiest way to accomplish these that I can think of is to cycle through each vessel, mod its adcmode with 16, and if the mode changed then write the new mode back to the vessel. This will ensure that all AFCMODE numbers written to a save file will be between 0 and 15 inclusive (0-7 for control surfaces with packed cargo, 8-15 for control surfaces with unpacked cargo).
To test whether or not a small correction like this will help overcome the problem people have had with unpacked UCGO cargo, I wrote a short Lua script to modify the adcmode of vessels on the fly. I've never used Lua before so this is really just a way to start discussion for a possible fix to the unpacked cargo problem. I think a small plugin module to handle this automatically during scenario load and save would be appreciated by users who don't want to mess with Lua scripts; but, that can wait until we hear some test results back.
Below is the script I've been using to test out 'correcting' packed and unpacked cargo. It seems to work for me, but I don't use unpackable cargo all that often. Better testing by cargo geeks is needed. Note also that there is no way I know of from Lua script to tell whether a vessel is a UCGO cargo or not, so this just cycles through every vessel in the scenario. If there are other add-on vessels out there that use higher bits of AFCMODE for their own purpose, then this is going to break those vessels most likely. But I don't think I've ever come across anything else that modifies AFCMODE beyond bit 2.
It would be wonderful if folks could test this out. It would be even better if some real programmers and some folks who understand Orbiter internals better could improve upon this proof of concept to make a module that would automatically handle this for users.
When the function fixcargo() is run within the sim, cargo should take on the state that it was supposed to have been left in -- packed or unpacked. It should not unpack things that are supposed to be packed, nor should it pack things up that should be unpacked. Getting cargo to take on the correct state can be accomplished by running this script function after the scenario loads. To ensure that the AFCMODEs are correct for the next time the scenario is loaded, run this script function again prior to saving.
Thanks to those who test and provide feedback or add to the discussion of how we might all come up with a fix for the unpacking problem.
-- Mike
Code:
-- UCGO unpack fix script
-- Proof of Concept to provide information and encourage discussion
-- toward finding a good fix.
term.out('')
term.out('UCGO unpack fix script')
term.out('ALPHA testing stage')
term.out('Run function \'fixcargo()\' to start')
term.out('')
-- cycle through vessels in the scenario looking for strange adcmode numbers
-- there is ABSOLUTELY no guarantee that only UCGO cargos use such adcmode
-- numbers, so other things might break
function fixcargo()
local n = vessel.get_count()
if n > 0 then
term.out('Total Vessels: '..n)
for i=0, n-1 do
vif = vessel.get_interface(i)
if vif == nil then
term.out('Bad Vessel Interface. Stopping.')
break
end
name = vif:get_name()
oldmode = vif:get_adcmode()
newmode = (oldmode % 16)
if oldmode ~= newmode then
vif:set_adcmode(newmode)
end
term.out('Vessel: '..i..' Name: '..name..' Old Mode: '..oldmode..' New Mode: '..newmode)
end
else
term.out('No vessels to process.')
end
end