CWolfs / MissionControl

A HBS BattleTech mod that provides a framework for runtime modifications of the contracts and encounters.
GNU General Public License v3.0
20 stars 13 forks source link

Contract Builder: Custom Buildings, Structures, Destructibles #578

Closed CWolfs closed 1 year ago

CWolfs commented 1 year ago

Upgrade the contract builder to allow for adding custom buildings, structures and destructibles.

Buildings

Structures

Destructibles

CWolfs commented 1 year ago

A new 'props' folder exists in Mission Control. Inside there are the definitions and asset bundles (if required for a definition) for this feature to work. The props folder contains:

Models Folder

Contains:

Buildings Folder

Structures Folder

Destructibles Folder

CWolfs commented 1 year ago

Prop Model Definition

For example:

{
  "Key": "BridgeOpenLongA",
  "Mesh": "bridgeOpenLongA", // references the mesh name in the bundle or available game meshes
  "Materials": [ // materials for the mesh and its submeshes. BT makes use of submeshes for its buildings/structures/destructibles
    {
      "Name": "envMatStct_darkMetal_generic"
      // for more options see the below Material Properties comment
    },
    {
      "Name": "envMatStct_concrete_generic"
       // for more options see the below Material Properties comment
    },
    {
      "Name": "envMatStct_asphalt_generic"
       // for more options see the below Material Properties comment
    }
  ],
  "IsMeshInBundle": true, // is the mesh in the provided asset bundle? defaults to false
  "HasCustomShell": true, // is the model using a custom shell or not in the bundle provided? defaults to false
  "CustomShellMaterials": [{ // [optional] materials for a custom shell if provided
    {
      "Name": "envMatStct_darkMetal_generic"
       // for more options see the below Material Properties comment
    },
    {
      "Name": "envMatStct_concrete_generic"
      // for more options see the below Material Properties comment
    },
  }]
  "DestructibleSize": "large",
  "DestructibleMaterial": "metal",
  "FlimsyDestructibleType": "largeMetal",
  "ChangePivotToCenterIfFlimsyMeshFormat": true, // runtime changes the model's pivot to the center of the model bounds - defaults to false
}
CWolfs commented 1 year ago

Prop Building Definition

For example:

{
  "Key": "LargeMilitaryBuildingVariantA1",
  "BuildingDefID": "buildingdef_Military_Large",  // reference to a buildingDefID file
  "MainModel": "LargeMilitaryBuildingA", // reference to a PropModelDef key
  "Glass": { // optional - positions the glass in relation to the main model. If not provided will just spawn at model center
     "Position": { "x": 1, "y": 6, "z": 1}, // optional 
     "Rotation": { "x": 0, "y": 5, "z": 0} // optional
  },
  "Destructibles": [ // optional - destructibles defined in props/destructibles
    {
      "Key": "MachineAirConditioningUnitVariantA", // key of destructible in props/destructibles
      "Position": { "x": 3.3, "y": 18.3, "z": 18 }, // optional override to destructible posistion in the destructible def
       "Position": { "x": 0, "y": 5, "z": 0}  // optional override to destructible posistion in the destructible def 
    },
    {
      "Key": "MachineAirConditioningUnitVariantA",
      "Position": { "x": -2, "y": 18.3, "z": 18 }
    },
    {
      "Key": "PipeTwoShortCurvedVariantA",
      "Position": { "x": -8, "y": 2.5, "z": 22 }
    },
    {
      "Key": "PipeTwoShortCurvedVariantA",
      "Position": { "x": -8, "y": 3.5, "z": 22 }
    }
  ]
}
CWolfs commented 1 year ago

Prop Structure Definition

For example:

{
  "Key": "OpenLongBridgeVariantA1",
  "MainModel": "BridgeOpenLongA", // reference to a PropModelDef key
  "Destructibles": [ // optional - destructibles defined in props/destructibles
    // same as the above buildings set up
  ]
}
CWolfs commented 1 year ago

Prop Destructible Flimsy Definition (Destructibles)

For example:

{
  "Key": "WallTinyThinRectangleVariantA",
  "MainModel": "WallTinyThinRectangle", // reference to a PropModelDef key
  "Mass": 600, // mass of the destructible - used for calculating how far it should be thrown on explosive force / destruction
  "Position": { "x": 0, "y": 0, "z": 0}, // optional - can set a predefined position/rotation but almost always this isn't needed
  "Rotation": { "x": 0, "y": 0, "z": 0} // optional  - can set a predefined position/rotation but almost always this isn't needed
}
CWolfs commented 1 year ago

Custom Asset Bundles

When forming a custom bundle names of the meshes are important. For example, in the above PropModelDef the mesh 'bridgeOpenLongA' is referenced.

In the asset bundle the set up for supporting all the features would be:

Most of the above is optional but the absolute minimum required are:

Everything else can either be dynamically created (dynamic shell debris is placed by Mission Control based on size of the model if no custom shell is provided) or not required (e.g. glass). If only LOD0 is provided then LOD1 and LOD2 are not used and LOD0 is always used.

Fallback / Flimsy Mode

There is a fallback that exists if _COL and _LOD0 cannot be found. It will look for a mesh with the exact name as the model key. For example a mesh named:

In this case that mesh is then used for both bridgeOpenLongA_COL and bridgeOpenLongA_LOD0

Best Practice

It's recommended you set a sensible pivot point for your mesh as this system uses direct Meshes and not Unity GameObjects. This means the pivot is within the Mesh data.

If for whatever reason you're unable to set a sensible mesh pivot, you can ask Mission Control to set the pivot to the center of the Mesh. Set the model's json property ChangePivotToCenterIfFlimsyMeshFormat to true.

CWolfs commented 1 year ago

In develop.

CWolfs commented 1 year ago

Material & Texture Resolution

If providing an asset bundle the system will attempt to find referenced materials in the bundle first, if it cannot find it in the bundle it will check any special Mission Control created/loaded assets - and if it can't find those it will look in a cached lookup of whatever is available in BattleTech at the time.

Often Materials and Textures aren't always available in each map. The Materials and Textures available in each map change so it's much safer to rely on providing a bundle with a texture and material properties.

Bundling Materials, Textures & Shaders in Bundles

All you need to do is just ensure the bundle label of the model's bundle is set on the materials, textures and shaders. Then reference these files by their names in the PropModelDef json file. Mission Control will do the rest.

CWolfs commented 1 year ago

Material Properties

In the PropModelDef json you have fine level contrl over the Material, Shader and Texture used. In the Materials block you can have something like:

"Materials": [ // materials for the mesh and its submeshes. BT makes use of submeshes for its buildings/structures/destructibles
    {
      "Name": "envMatStct_myCustomMaterial",
      "Shader": "myCustomShader", // if not provided it uses 'BattleTech Standard' shader
      "MaterialProperties": { // for this example I'm using the 'BattleTexch Standard' property names to illustrate how you use it
         "_MainTex.texture": "my-texture-name", // sets the main texture of the shader 
         "_BumpMap.texture": "my-normal-texture-name", // sets the normal texture of the shader 
         "_EmissionMap.texture": "my-emissive-texture-name", // sets the emission map of the shader
         "_Color.vector": { "r": 100, "g": 100, "b": 100, "a": 150 } // sets the tint colour of the shader
      },
    }
  ],

When specifying a property you must specify what type the property is so Mission Control knows how to correctly set it. This is why the [name].[type] format exists. For example, in the above snippet you see '_MainTex.texture' or '_Color.vector'. The 'texture' and 'vector' are the types.

The usable types in this system that Mission Control provides are:

The properties above would be of the custom shader you're using. If you do not provide a 'Shader' name then it fallsback to the usual 'BattleTech Standard' shader that buildings use in the game. The properties for these are:

    Properties {
        _Color ("Color", Vector) = (1,1,1,1)
        _MainTex ("Albedo", 2D) = "white" {}
        _Cutoff ("Alpha Cutoff", Range(0, 1)) = 0.5
        _Glossiness ("Smoothness", Range(0, 1)) = 0.5
        [Gamma] _Metallic ("Metallic", Range(0, 1)) = 0
        _MetallicGlossMap ("Metallic", 2D) = "white" {}
        _Gradient ("Gradient", 2D) = "white" {}
        _BumpScale ("Scale", Float) = 1
        _BumpMap ("Normal Map", 2D) = "bump" {}
        _Parallax ("Height Scale", Range(0.005, 0.08)) = 0.02
        _ParallaxMap ("Height Map", 2D) = "black" {}
        _OcclusionStrength ("Strength", Range(0, 1)) = 1
        _OcclusionMap ("Occlusion", 2D) = "white" {}
        _EmissionColor ("Color", Vector) = (0,0,0,1)
        _EmissionMap ("Emission", 2D) = "white" {}
        _DetailMask ("Detail Mask", 2D) = "white" {}
        _DetailAlbedoMap ("Detail Albedo x2", 2D) = "grey" {}
        _DetailNormalMapScale ("Scale", Float) = 1
        _DetailNormalMap ("Normal Map", 2D) = "bump" {}
        _BlendMainTex ("Blend Albedo", 2D) = "white" {}
        _BlendMetallicGlossMap ("Blend Metallic", 2D) = "bump" {}
        _BlendNormalMap ("Blend Normal Map", 2D) = "bump" {}
        _BlendOcclusionMap ("Blend Occlusion", 2D) = "white" {}
        [MaterialToggle(_VERTEX_BLEND)] _UseBlend ("__blend", Float) = 0
        [Enum(UV0,0,UV1,1)] _UVSec ("UV Set for secondary textures", Float) = 0
        [Enum(UV0,0,UV1,1)] _UVSecMask ("UV Set for detail mask texture", Float) = 0
        [HideInInspector] _Mode ("__mode", Float) = 0
        [HideInInspector] _SrcBlend ("__src", Float) = 1
        [HideInInspector] _DstBlend ("__dst", Float) = 0
        [HideInInspector] _ZWrite ("__zw", Float) = 1
        [MaterialToggle(_OVERLAY_DOWNMOSS)] _Downmoss ("___moss", Float) = 0
        [MaterialToggle(_OVERLAY_UPMOSS)] _Upmoss ("___moss", Float) = 0
        _MatID ("Material Type", Float) = 1
        _PaintScheme ("Paint Scheme", 2D) = "black" {}
        _PaintColor1 ("Color 1", Vector) = (1,1,1,1)
        _PaintColor2 ("Color 2", Vector) = (1,1,1,1)
        _PaintColor3 ("Color 3", Vector) = (1,1,1,1)
        _PaintSmoothness1 ("P1S", Range(0, 1)) = 0.5
        _PaintSmoothness2 ("P2S", Range(0, 1)) = 0.5
        _PaintSmoothness3 ("P3S", Range(0, 1)) = 0.5
        _PaintMetal1 ("P1M", Range(0, 1)) = 0
        _PaintMetal2 ("P2M", Range(0, 1)) = 0
        _PaintMetal3 ("P3M", Range(0, 1)) = 0
        _PaintWear ("Paint Wear", Range(0, 1)) = 0.5
        [HideInInspector] _SelectedID ("selected", Float) = 1
        [HideInInspector] _SelectedIntensity ("highlight intensity", Float) = 0
        [HideInInspector] _StippleAlpha ("Stipple Alpha", Float) = 1
        [MaterialToggle(_RUBBLE)] _Rubble ("___rubble", Float) = 0
        [MaterialToggle(_BLINKING)] _Blinking ("___blinking", Float) = 0
        [MaterialToggle(_TERRAIN_BLEND)] _TerrainBlend ("_____", Float) = 0
        _BlinkingProps ("BlinkingProperties", Vector) = (0,0,0,0)
        _BlinkingTex ("Blinking Texture", 2D) = "black" {}
        [Enum(Normal,0,Counter,1,Night,2)] _EmissiveMode ("Emissive Mode", Float) = 0
    }