Skip to content

Instantly share code, notes, and snippets.

@MathijsdeBoer
Last active January 30, 2020 23:07
Show Gist options
  • Save MathijsdeBoer/984289711c1ca6f78cbd61bf7828154f to your computer and use it in GitHub Desktop.
Save MathijsdeBoer/984289711c1ca6f78cbd61bf7828154f to your computer and use it in GitHub Desktop.
Extract all of Space Engineer's blocks' needed components and generate a C# dictionary definition
"""
Extract Block Data for Space Engineers
Author: Czorio
Updated: 2020-01-30 (5)
Tested on: Python 3.7.4-x64
Usage:
Modify the se_path variable to point at your SE install location. Run the script to generate a Dict.txt file in your current directory.
This Dict.txt file should have slightly formatted C# code that declares and initializes a Dictionary for use in SE scripts.
License:
MIT
"""
import glob
import xml.etree.ElementTree as et
from os import walk
from os.path import join, abspath
se_path = r"C:\Program Files (x86)\Steam\steamapps\common\SpaceEngineers"
# Generate absolute path to CubeBlocks' .sbc files
cubeblocks_subpath = r"Content\Data\CubeBlocks"
sbc_files = [abspath(f) for f in glob.glob(join(se_path, cubeblocks_subpath, "*.sbc"))]
# Basic building blocks for the C# dictionary code
dict_string =\
"""componentsForBlock = new Dictionary<string, Dictionary<string, float>>()
\t{{
{blocks}
\t}};"""
block_dict_string =\
"""\t\t{{
\t\t\t\"{blockId}\",
\t\t\tnew Dictionary<string, float>()
\t\t\t{{
{components}
\t\t\t}}
\t\t}},"""
component_string = "\t\t\t\t{{ \"{comp}\", {value}.0f }},"
def format_components(block_name: str, components: dict) -> str:
"""
Formats a Python dictionary of components into a C# dictionary for each block
str block_name: The MyDefinitionId name of the block
dict components: All components that are associated with this block
"""
combined_component_string = ""
for comp, val in list(components.items())[:-1]:
combined_component_string += (
component_string.format(comp=comp, value=val) + "\n"
)
combined_component_string += component_string.format(
comp=list(components.items())[-1][0], value=list(components.items())[-1][1]
)
return block_dict_string.format(
blockId=block_name, components=combined_component_string
)
if __name__ == "__main__":
# We'll put each block in here
formatted_block_list = []
for sbc in sbc_files:
# CubeBlocks.sbc and CubeBlocks_Extras.sbc contain no real usable blocks, so we skip them
if "CubeBlocks.sbc" in sbc or "Extras.sbc" in sbc:
continue
# Read the sbc file as xml
print(sbc)
root = et.parse(sbc).getroot()
blocks = root.find("CubeBlocks")
# Gather needed data for each block
for block in blocks:
type_id = block.find("Id").find("TypeId").text
subtype_id = block.find("Id").find("SubtypeId").text
subtype_id = subtype_id if subtype_id is not None else "(null)"
resources = block.find("Components").findall("Component")
res_dict = {}
for res in resources:
# Some blocks may declare the same component multiple times, make sure we don't overwrite the other value
if res.attrib["Subtype"] not in res_dict:
res_dict[res.attrib["Subtype"]] = int(res.attrib["Count"])
else:
res_dict[res.attrib["Subtype"]] += int(res.attrib["Count"])
formatted_block_list.append(
format_components(
f"MyObjectBuilder_{type_id}/{subtype_id}",
res_dict,
)
)
# Now that we have collected all blocks, we can write out the C# code
with open("dict.txt", "w") as f:
block_string = ""
for b in formatted_block_list:
block_string += b + "\n"
f.write(dict_string.format(blocks=block_string))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment