Skip to content

BetterCargoPartVolume

gotmachine edited this page Aug 26, 2021 · 6 revisions

Automatic ModuleCargoPart volume generation

This patch will generate a value for the ModuleCargoPart.packedVolume field if it set to 0 or isn't defined in the module configuration. This works by getting the bounds of the part prefab active colliders, after part compilation. Generated volumes are logged to ksp.log.

ModulePartVariants volume switching

For parts that don't have a ModuleCargoPart.packedVolume defined and have a ModulePartVariants, a separate volume will be generated for every VARIANT that use a GAMEOBJECTS definition. Those separate volumes will be used when the part instance is put in an inventory.

The volume for a variant can be explicitly defined (preventing it from being auto-generated) by adding an EXTRA_INFO sub-node to the VARIANT node, and adding a packedVolume = x value (x in liters) to that subnode. Example :

MODULE
{
  name = ModuleCargoPart
  // make sure packedVolume isn't defined or is 0
}

MODULE
{
  name = ModulePartVariants
  baseVariant = Short
  VARIANT
  {
    name = Short
    GAMEOBJECTS
    {
      Shroud1x0 = true
      Shroud1x1 = false
    }
    EXTRA_INFO
    {
      packedVolume = 200
    }
  }
  VARIANT
  {
    name = Long
    GAMEOBJECTS
    {
      Shroud1x0 = false
      Shroud1x1 = true
    }
    EXTRA_INFO
    {
      packedVolume = 400
    }
  }
}

packedVolume API for PartModule

The public or private instance method with the signature float GetCargoVolume() implemented on a PartModule derivative will be called prior to the Part being stored in an inventory. This allow plugins that alter the shape of a part (ex : Tweakscale, B9PartSwitch...) to properly handle the volume of cargo parts. Example :

public class MyPartShapeChangingModule : PartModule
{
    private ShapeDefinition currentShape;

    private float GetCargoVolume()
    {
        return currentShape.packedVolume;
    }
}

Note that when that method is called, you can't rely anymore on the part geometry (the part scale will be altered, and overall things are out of your control), so you must either :

  • Have config values for the current shape volume
  • Generate volumes during prefab compilation, and save the values
  • Rely on scaling formulas

Implementing volumes auto-generation can look like this :

public override void OnLoad(ConfigNode node)
{
    // Execute only during prefab (re)compilation
    if (HighLogic.LoadedScene == GameScenes.LOADING || PartLoader.Instance.Recompile)
    {
        foreach (ShapeDefinition shape in shapes)
        {
            // setup the part transforms/meshes/scale acording to your logic 
            shape.Activate();

            Collider[] colliders = part.transform.GetComponentsInChildren<Collider>(false);

            if (colliders.Length > 0)
            {
                Bounds bounds = colliders[0].bounds;

                for (int i = 1; i < colliders.Length; i++)
                {
                    bounds.Encapsulate(colliders[i].bounds);
                }

                shape.packedVolume = Mathf.Ceil(bounds.size.x * bounds.size.y * bounds.size.z * 1000f);
            }
        }
    }
}

Misc notes

  • The patch override the stock implementation of ModuleInventoryPart.UpdateCapacityValues to rely on the stored part ProtoPartSnapshot for mass and volume, instead of using the part prefab mass/volume :
    • This is necessary to handle packedVolume switching on instances. For that to work, the patch force the ModuleCargoPart.packedVolume KSPField to be persisted.
    • This fixes tons of issues where the part instance mass doesn't match the part prefab mass (modified resources, modules implementing IPartMassModifier...)
  • The patch override the stock implementation of ModuleCargoPart.GetInfo(), showing packed volume: variable instead of a value when the part use a module implementing volume switching.
  • The patch remove the ability to switch variants from the cargo part icon when the part is stored in an inventory and make use of volume switching
Clone this wiki locally