SBC
Things to know
This is all the things one should know about SBC before proceeding to mod them.
Click the boxes for more details on that subject.
If you've never used XML (or HTML or any other markup language that uses <node>stuff</node>
format) then you should look up tutorials on the internet on how the syntax works.
If you find some other sb* file (.sbx, .sbs, etc) then those are also likely to be XML format.
In the <Game>\Content\Data
folder and copy them to your local mod where you can edit them.
If you don't know what a local mod is, you've skipped an important step: Setting up a modding environment
Once you copied a .sbc file from the game, should only keep the definitions you want to override!
For example if you copy Content\Data\CubeBlocks\CubeBlocks_Production.sbc
and you only want to change reactors, then delete the other blocks from the file.
What we refer as "definition" is a chunk of XML that defines one thing, for example a block or a component or a character or anything that has the <Id>
node.
The individual nodes for CubeBlocks are even called Definition.
The <Id>
node that is present on all definitions is what defines how it's stored (one exception is BlockCategories which ignores SubtypeId in Id node and instead uses the Name node to determine what to merge to).
If you use the same TypeId+SubtypeId that already exists then you're overriding that definition.
However if you use a unique combination of those (SubtypeId can be invented) then it's added as a new definition.
NOTE: TypeId cannot be invented and also usually requires to be paired with an xsi:type="..." for it to be properly loaded.
Highly recommended to not change TypeId on something and instead copy the definition from a vanilla file for that type instead, and then modify the subtype and other nodes on that.
NOTE: Definitions are generally fully overwritten, meaning if you don't declare a node (for example <Model>
) then it will use the default value hardcoded in the game code.
For more details see below at #Definitions that get overwritten vs additive vs merged
SubtypeIds as you may have noticed are not globally unique, only when paired with a TypeId it becomes a full ID and that is what makes it unique.
All assets require something to reference them, usually .sbc and sometimes models or even scripts.
Most of the time they will only ask for a SubtypeId, but some will ask for a full Id, and some will even require the MyObjectBuilder_ prefix of the TypeId, which will often lead to confusion with the xsi:type.
NOTE Never input the value from xsi:type anywhere else that requires an ID. The xsi:type is only used by the game to know what object to deserialize it as.
For example:
<Definition xsi:type="MyObjectBuilder_LargeTurretBaseDefinition">
<Id>
<TypeId>LargeGatlingTurret</TypeId>
<SubtypeId>SmallGatlingTurret</SubtypeId>
</Id>
<!-- other nodes not relevant to the example -->
</Definition>
And when you see BlockVariantsGroups being like this:
<?xml version="1.0" encoding="utf-8"?>
<Definitions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<BlockVariantGroups>
<BlockVariantGroup>
<Id Type="MyObjectBuilder_BlockVariantGroup" Subtype="TurretGroup" />
<Icon>Textures\GUI\Icons\Cubes\gatling_turret.dds</Icon>
<DisplayName>DisplayName_BlockGroup_TurretGroup</DisplayName>
<Description>Description_BlockGroup_TurretGroup</Description>
<Blocks>
<Block Type="MyObjectBuilder_LargeGatlingTurret" Subtype="" />
<Block Type="MyObjectBuilder_LargeGatlingTurret" Subtype="SmallGatlingTurret" />
<Block Type="MyObjectBuilder_LargeMissileTurret" Subtype="" />
<Block Type="MyObjectBuilder_LargeMissileTurret" Subtype="SmallMissileTurret" />
<Block Type="MyObjectBuilder_LargeMissileTurret" Subtype="LargeCalibreTurret" />
<Block Type="MyObjectBuilder_LargeMissileTurret" Subtype="LargeBlockMediumCalibreTurret" />
<Block Type="MyObjectBuilder_LargeMissileTurret" Subtype="SmallBlockMediumCalibreTurret" />
<Block Type="MyObjectBuilder_InteriorTurret" Subtype="LargeInteriorTurret" />
<Block Type="MyObjectBuilder_LargeGatlingTurret" Subtype="AutoCannonTurret" />
</Blocks>
</BlockVariantGroup>
</BlockVariantGroups>
</Definitions>
Your immediate reaction is to use the big name that starts with MyObjectBuilder_ from xsi:type, which as mentioned in the note before is not the right one.
These are the ones you need to focus on:
<TypeId>LargeGatlingTurret</TypeId>
<SubtypeId>SmallGatlingTurret</SubtypeId>
Here's an example .sbc contents that defines a block and an item in the same file:
<Definitions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<CubeBlocks>
<Definition> <!-- this is a definition from here to its end-node (</Definition>) -->
<Id>
<TypeId>CubeBlock</TypeId>
<SubtypeId>LargeBlockArmorCornerSquare</SubtypeId>
</Id>
<!-- some other nodes that are not relevant to the example -->
</Definition>
</CubeBlocks>
<PhysicalItems>
<PhysicalItem> <!-- this is also a definition from here to its end-node (</PhysicalItem>) -->
<Id> <!-- this is what defines what it's indexed as -->
<TypeId>Ore</TypeId>
<SubtypeId>ExampleItemA</SubtypeId>
</Id>
<!-- some other nodes that are not relevant to the example -->
</PhysicalItem>
<PhysicalItem>
<Id>
<TypeId>Ore</TypeId>
<SubtypeId>ExampleItemB</SubtypeId>
</Id>
<!-- some other nodes that are not relevant to the example -->
</PhysicalItem>
</PhysicalItems>
<!-- WARNING: do not close and re-open the same list-node (<CubeBlocks>, <PhysicalItems>, etc) in the same file because you will override the previous one! -->
</Definitions>
Definitions that get overwritten vs additive vs merged
Vast majority of definitions get fully overwritten when the same TypeId+SubtypeId already exists.
Only a few act differently and those are listed below:
<Definition xsi:type="EnvironmentDefinition">
(Environment.sbc)This means you can include only the nodes you wish to change + <Id> node!
An example of an environment definition that only changes ship max speeds:
<?xml version="1.0"?>
<Definitions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Definition xsi:type="EnvironmentDefinition">
<Id>
<TypeId>EnvironmentDefinition</TypeId>
<SubtypeId>Default</SubtypeId>
</Id>
<SmallShipMaxSpeed>100</SmallShipMaxSpeed>
<LargeShipMaxSpeed>100</LargeShipMaxSpeed>
</Definition>
</Definitions>
<Category xsi:type="MyObjectBuilder_GuiBlockCategoryDefinition">
(BlockCategories.sbc)This one is a bit special in that the SubtypeId is ignored but instead it looks if the Name node already exists, and if it does it will ignore all other nodes and only append the contents of ItemIds to the existing one.
For example, to add to the vanilla Large Blocks category:
<?xml version="1.0" encoding="utf-8"?>
<Definitions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<CategoryClasses>
<Category xsi:type="MyObjectBuilder_GuiBlockCategoryDefinition">
<Id>
<TypeId>GuiBlockCategoryDefinition</TypeId>
<SubtypeId/>
</Id>
<Name>LargeBlocks</Name>
<ItemIds>
<string>MotorAdvancedStator/YourVeryGiganticRotor</string>
</ItemIds>
</Category>
</CategoryClasses>
</Definitions>
<BlueprintClassEntries>
(BlueprintClasses.sbc at the end)The <Class> nodes in that file define the category, those will be overwritten if you declare them. However to pair a blueprint to a blueprint-class you have to use the <BlueprintClassEntries> node which is an additive list.
For example to add your blueprint (which is not shown here) to a vanilla class:
<?xml version="1.0" encoding="utf-8"?>
<Definitions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<BlueprintClassEntries>
<Entry Class="Components" BlueprintSubtypeId="SomeFancyComponentBlueprint" />
</BlueprintClassEntries>
</Definitions>
<Decals>
(Decals.sbc)Decal definitions cannot be overwritten because the game sends them to a different system without checking if they already exist there, and because of the way they're stored this doesn't cause errors.
[1]
Quick reference
How are some SBC are linked
- Blocks: CubeBlock is essential, Components is what can be used to build them, BlueprintClassEntries to add them to assemblers, BlockCategories for Build Menu categories on the left and BlockVariantGroups to combine more blocks into one icon that can be scrolled through.
- Weapons: CubeBlock -> WeaponDefinition -> AmmoMagazine -> Ammo.
- Production: CubeBlock -> BlueprintClass -> BlueprintClassEntries -> Blueprints.
- Inventory and more: EntityContainers links entity(block) to EntityComponent, then EntityComponents defines the component data.
- In various definitions there's
<PhysicalMaterial>SubtypeHere</PhyiscalMaterial>
which point to PhysicalMaterials.sbc and then MaterialProperties.sbc defines how they react when they interact. - Hand weapons/tools: HandItems, PhysicalItems, AnimationControllers, Blueprints.
- Random loot in containers: ContainerTypes.sbc and then
<ContainerType>SomeSubtypeId</ContainerType>
in the prefab at the container block (search vanilla prefabs for ContainerType to see an example). - NPC ships: CargoShips/Encounters/SpawnGroups, PirateAntennas, PirateDrones, DroneBehaviors, GlobalEvents
For more details see Tutorials and Reference
Definitions that are not designed to be modded:
- AssetModifiers\AssetModifiers.sbc & ArmorModifiers.sbc
- Adding new ones won't show up in the picker GUIs because those that show up there are tied to Steam items or DLCs.
- Does not look in mod folder for textures.
- Is not additive so you have to copy the entire definition meaning you'd be undoing any additions Keen makes to skins after the release (which they have done).
- GuiTextures.sbc - broken modding support, cannot use textures from mods (BugReport).
- ControllerSchemes.sbc - no reason to do this.
- MainMenuInventoryScenes.sbc, Scenarios.sbx, Tutorials.sbx - mods only get loaded when a world starts, this would have no effect.
- WheelModels.sbc - the game code using this is turned off.
Needs to be researched:
- Game\Game.sbc - specifically explosive stuff at the bottom, if we remove <SessionComponents> does it break stuff? and if we have to include them it will eventually break stuff...
- Screens\*.gsc - they're XML but are they moddable?
- ↑ from
MyDefinitionManager.PostprocessDecals()
ends up in aDictionary<string, List<MyDecalMaterial>>
inMyDecalMaterials