Importing System Contents

Hey all! I'm new to Astrosynthesis, and don't have much knowledge or background with scripts or coding.

I've read the documentation on importing system data (which I read as the star(s) and attached variables), but I wonder if there's a way to import system contents from a csv file in a similar manner? I want to be able to create planets, moons, and other bodies quickly as data, then import them in bulk rather than copy and pasting orbital data one box at a time.

If I had any grounding in coding I'd imagine this could be accomplished with a script - where you select a star system then run the script to import child entities from a csv.

Any pointers on how I might approach this would be appreciated. I'm happy to work on learning about writing scripts... but with no foundation I don't even know where to begin.

Comments

  • CSV isn't very good for hierarchical data, so that's why only stars (or top level bodies) are supported in that format. There's an XML exporter in the plugsin menu, and also an older XML importer here ( https://www.nbos.com/nox/item/7 ) that may still work (been a long time since I tried it). But otherwise, yes, its going to take writing some scripts to import data. That's just the nature of the task.

  • edited May 18

    Makes sense, thank you. I'll give that a shot. Sorry I know I'm ignorantly playing with something I don't even pretend to understand.

    My plan at this point to get around writing a script is to export the star system I want to target as an xml, then edit the xml to add in the bodies I want, then import the xml back into the sector - which would place the star system back in the same place but ideally now with contents.

    I think at this point my only barrier (assuming the importer functions) is BodyID. Can this be a random set of characters - provided they aren't the same as another BodyID in the secotr, or do the specific characters matter?

  • edited May 18

    All right, so I've gone and learned a bunch about xml files and the structure AstroSynthesis uses.

    I exported an xml of a random system that had no contents, then edited it to include details of the child bodies I wanted.

    <?xml version="1.0"?>
        <Sector Name="Ilodium Sector" ID="{8B637477-898C-4BB0-A065-C7425259F4C1}" AstroVersion="f" ExportFilter="Selected Systems" ExportDate="2025-05-18 8:16:34 AM">
            <FileName>D:\RPG Data\Ilodium Grand-Strategy\Maps\Ilodium Sector.AstroDB</FileName>
            <UnitStarMeasureName>Light Years</UnitStarMeasureName>
            <UnitStarMeasureAbbrev>ly</UnitStarMeasureAbbrev>
            <UnitStarMeasureRatio>1</UnitStarMeasureRatio>
            <SizeX>240</SizeX>
            <SizeY>240</SizeY>
            <SizeZ>240</SizeZ>
            <Frequency>5</Frequency>
            <Spherical>-1</Spherical>
            <VisibleCount>2417</VisibleCount>
            <GridStyle>2</GridStyle>
            <GridX>20</GridX>
            <GridY>20</GridY>
            <GridZ>20</GridZ>
            <GridTick>15</GridTick>
            <GridTickLabels>-1</GridTickLabels>
            <GridColor>8421504</GridColor>
            <BaseFont>Verdana</BaseFont>
            <CustomFields>
                <CustomField FieldName="viewer_id" FieldValue="XK56CH"/>
                <CustomField FieldName="viewer_url" FieldValue="https://astro.nbos.com/v/XK56CH/Ilodium-C-2051"/>
                <CustomField FieldName="viewer_title" FieldValue="Ilodium C. 2051"/>
            </CustomFields>
            <Bodies Count="2416">
                <Body ID="{061C8716-2075-4D85-B479-8257CB25C797}" Name="Wolf 359" TypeID="Star">
                    <X>-1.804</X>
                    <Y>6.502</Y>
                    <Z>3.906</Z>
                    <Color>8388736</Color>
                    <LabelColor>8388736</LabelColor>
                    <RenderDistance>30</RenderDistance>
                    <LabelDistance>2</LabelDistance>
                    <RouteDistance>40</RouteDistance>
                    <Spectral>M7V</Spectral>
                    <Radius>0.275945932292243</Radius>
                    <Mass>0.2</Mass>
                    <Luminosity>3.57770876399966E-03</Luminosity>
                    <SphereInfluenceColor>12632256</SphereInfluenceColor>
                    <SphereInfluenceSize>0.5</SphereInfluenceSize>
                    <Notes>Wolf 359                            CN Leo                                  RA:  10 56 42.08      DEC:  +07 03 10.99                                                     Gliese:  Gl 406                HIP:                    HD:                    HR:                BD:                                                                            Spectral:  M7V        V:  13.45      M:  16.56      B-V:  2.00      Mass:  0.200      Dist:  7.7972 ly                                                     Luminosity:  0.002211      HZ:  0.0470 A.U.s      Period @ HZ:  0.0228 years    8.3212 days      Tidal Force:  1924.0166                                                                                                                                                                                                                            Category:  NHC               Tier N-4b      UVC</Notes>
                    <RandomSeed>198594633</RandomSeed>
                </Body>
                <Children>
                    <Body ID="Yashara" Name="Yashara" TypeID="Terrestrial">
                        <Distance>163000000</Distance>
                        <Radius>5872</Radius>
                        <Density>0.92</Density>
                        <Mass>0.79</Mass>
                        <Rotation>22.1</Rotation>
                        <Albedo>0.30</Albedo>
                        <Temp>302</Temp>
                        <AtmosphereComponents>
                            <Component AtmElement="N₂" AtmPercent="33" />
                            <Component AtmElement="O₂" AtmPercent="28" />
                            <Component AtmElement="H₂O" AtmPercent="33" />
                            <Component AtmElement="CO₂" AtmPercent="3" />
                            <Component AtmElement="Ar" AtmPercent="1" />
                        </AtmosphereComponents>
                        <Water>84</Water>
                        <Habitability>2</Habitability>
                        <SphereInfluenceColor>12632256</SphereInfluenceColor>
                        <SphereInfluenceSize>0.5</SphereInfluenceSize>
                        <Notes>Yashara is a verdant world bathed in deep green hues, its continents blanketed in dense rainforests interspersed with expansive river basins and misty highlands. Towering storm clouds regularly roll across the humid tropics, unleashing heavy rainfall and electrical storms. The slightly younger planet maintains a potent magnetic field, supporting a diverse biosphere. Gigantic ferns, climbing bioluminescent vines, and ecosystems akin to prehistoric Earth flourish. The oceans teem with massive filter-feeding leviathans, while land predators and symbiotic insectoid swarms shape the food web. Strange ruins dot the deeper jungles—possibly remnants of lost civilizations.</Notes>
                        <GMNotes>Uncover ancient alien temples hidden under layers of moss, battle over ecosystem-controlling biotech, or resolve factional disputes among settlers and indigenous sapients competing for jungle dominance. Yashara holds secrets under every leaf.</GMNotes>
                        <Eccentricity>0.04</Eccentricity>
                        <AngleAscendingNode>114.7</AngleAscendingNode>
                        <AnglePeriapsis>281.9</AnglePeriapsis>
                        <children>
                            <Body ID="Herith" Name="Herith" TypeID="Small Body">
                                <Distance>244000</Distance>
                                <Radius>888</Radius>
                                <AngleAscendingNode>343.3</AngleAscendingNode>
                                <AnglePeriapsis>275.5</AnglePeriapsis>
                            </Body>
                            <Body ID="Sera" Name="Sera" TypeID="Small Body">
                                <Distance>365000</Distance>
                                <Radius>1020</Radius>
                                <AngleAscendingNode>318.3</AngleAscendingNode>
                                <AnglePeriapsis>275.5</AnglePeriapsis>
                            </Body>
                        </children>
                    </Body>
                </Children>
            </Bodies>
        </Sector>

    I tried using the importer plugin to bring the file in. It created a new sector that was blank aside from the single star system, and had no contents aside from said star.

    Before I continue down this rabbit hole, I'd appreciate any guidance you can offer on

    1) Have I done something wrong with the xml itself to format the data for the bodies I want
    2) Have I run into a need for a script to add the system into my existing sector, or is there something I need to do with the top portion of the file to denote this? Is the importer script designed to merge a system into an existing sector?

  • I just used the XML importer and it seemed to work ok. What I'd do is create a small sector, export it using the xml exporter. Then re-start Astro and use the XML importer to re-import that file. Once you get to that, you can see what the data should be looking like.

    In your case you may just want a file with a tag to define a planet. You'd have to modify the script so that it looks at the selected body and imports the body under that.

    An alternate way of doing this is writing directly to the .AstroDB file. Its an SQLite database file and can be accessed by nearly any programming language. The table structure is very simple.

  • Another possible way might be to make a window with a text field and paste the body info into there. Then when you press 'ok', parse it and create the new body.

  • I did it! Thanks for your help, this was a really fun challenge.

    I realized once I figured out how to run SQL in a DB Browser that it was going to be a pain to have to insert a planet before being able to insert the child bodies and atmospheric components each time.

    So I used AI to write a python script that did it all in one go, and after some tinkering I got it working!

    I've now got a workflow where a GPT will write a custom python script for any planets, moons, or other bodies I want inserted into a star system. I'll link them here for anyone with the same need in future later when I've done some more tinkering and they feel reliable.

    If someone wanted to turn this into a plugin.... that would be cool too.

  • edited May 19
    import sqlite3
    
    DB_PATH = r"D:\RPG Data\Ilodium Grand-Strategy\Maps\smalltestimportedagain.AstroDB"
    
    def sanitize_name(name):
        return name.upper().replace(" ", "").replace("’", "").replace("-", "").replace("'", "").replace("₁", "1").replace("₂", "2").replace("₃", "3").replace("₄", "4")
    
    def get_star_id_by_guid(cursor, id_string):
        cursor.execute("SELECT id FROM bodies WHERE id_string = ?", (id_string,))
        result = cursor.fetchone()
        if result:
            return result[0]
        else:
            raise ValueError(f"Star with id_string {id_string} not found in the database.")
    
    def insert_body(cursor, body, parent_id, system_id):
        id_string = f"{{{body['type_prefix']}-{sanitize_name(body['name'])}}}"
        cursor.execute(f"""
            INSERT INTO bodies (
                id_string, system_id, parent_id, name, type_id, body_type,
                distance, radius, density, mass, rotation,
                albedo, temp, atmosphere, atm_notes, water,
                population, habitability, visible, eccentricity,
                inclination, angle_ascending_node, angle_periapsis,
                axial_tilt, notes, gm_notes
            ) VALUES (
                ?, ?, ?, ?, ?, ?,
                ?, ?, ?, ?, ?,
                ?, ?, ?, ?, ?,
                ?, ?, ?, ?, ?,
                ?, ?, ?, ?, ?
            )
        """, (
            id_string, system_id, parent_id, body['name'], body['type_id'], body['body_type'],
            body['distance'], body['radius'], body['density'], body['mass'], body['rotation'],
            body['albedo'], body['temp'], body['atmosphere'], body['atm_notes'], body['water'],
            body['population'], body['habitability'], 1, body['eccentricity'],
            body['inclination'], body['ascending_node'], body['periapsis'],
            body['axial_tilt'], body['notes'], body['gm_notes']
        ))
        return cursor.lastrowid
    
    def insert_atmosphere(cursor, body_id, atmosphere):
        for gas, percent in atmosphere.items():
            cursor.execute("""
                INSERT INTO atm_components (body_id, gas, percent)
                VALUES (?, ?, ?)
            """, (body_id, gas, percent))
    
    def main():
        conn = sqlite3.connect(DB_PATH)
        cursor = conn.cursor()
    
        # === STEP 1: Look up star ID from GUID ===
        star_id_string = '{AA668191-F188-43A6-B2BC-53FD50E5235D}'
        star_id = get_star_id_by_guid(cursor, star_id_string)
    
        # === STEP 2: Define Nyxaris ===
        nyxaris = {
            'name': 'Nyxaris',
            'type_prefix': 'PL',
            'type_id': 100,
            'body_type': 'Planet',
            'distance': 418000000,
            'radius': 5940,
            'density': 1.05,
            'mass': 1.05,
            'rotation': 31.7,
            'albedo': 0.52,
            'temp': 205,
            'atmosphere': 0.64,
            'atm_notes': '72% N₂, 18% CO₂, 6% Ar, 3% CH₄, 1% O₂',
            'water': 0.17,
            'population': 0,
            'habitability': 1,
            'eccentricity': 0.07,
            'inclination': 3.2,
            'ascending_node': 130,
            'periapsis': 201,
            'axial_tilt': 11.8,
            'notes': 'Nyxaris is a glacial and bleak world, with frost-glazed plains, pale deserts of frozen methane dust, and frozen brine lakes nestled between black rock plateaus. Its skies are painted by soft auroras, and the sunlight is diffuse, casting silvery tones across the icy terrain.',
            'gm_notes': 'Crust may conceal relics of pre-glacial civilizations or xeno-terraforming remnants—puzzlingly aligned with magnetic anomalies and fault lines. Sky-lacing events at apogee alignments. Subsurface seismic "chimes" resonate seasonally.',
            'atmosphere_components': {
                'N₂': 72.0,
                'CO₂': 18.0,
                'Ar': 6.0,
                'CH₄': 3.0,
                'O₂': 1.0
            },
            'moons': [
                {
                    'name': 'Iore',
                    'type_prefix': 'MN',
                    'type_id': 106,
                    'body_type': 'Moon',
                    'distance': 452000,
                    'radius': 980,
                    'density': 0.92,
                    'mass': 0.92,
                    'rotation': 148.8,
                    'albedo': 0.61,
                    'temp': 183,
                    'atmosphere': 0.02,
                    'atm_notes': '48% N₂, 28% Ar, 15% CH₄, 6% CO, 3% O₂',
                    'water': 0.05,
                    'population': 0,
                    'habitability': 0,
                    'eccentricity': 0.084,
                    'inclination': 1.5,
                    'ascending_node': 48,
                    'periapsis': 176,
                    'axial_tilt': 1.1,
                    'notes': 'Iore appears as a glimmering white-gray orb streaked with bluish fractures and icy ridges. Geysers backlit by starlight erupt from fissures.',
                    'gm_notes': 'Emits modulated radio signals from suspected buried cryo-structure. May contain an ancient AI archive or warning system.',
                    'atmosphere_components': {
                        'N₂': 48.0,
                        'Ar': 28.0,
                        'CH₄': 15.0,
                        'CO': 6.0,
                        'O₂': 3.0
                    }
                }
            ]
        }
    
        # === STEP 3: Insert Nyxaris ===
        planet_id = insert_body(cursor, nyxaris, star_id, star_id)
        insert_atmosphere(cursor, planet_id, nyxaris['atmosphere_components'])
    
        # === STEP 4: Insert Iore ===
        for moon in nyxaris['moons']:
            moon_id = insert_body(cursor, moon, planet_id, star_id)
            insert_atmosphere(cursor, moon_id, moon['atmosphere_components'])
    
        conn.commit()
        conn.close()
        print("Nyxaris and Iore inserted successfully.")
    
    if __name__ == "__main__":
        main()
    

Leave a Comment