Modding Help What handles dungeon generation?

Discussion in 'Starbound Modding' started by midramble, Jan 11, 2017.

  1. midramble

    midramble Space Hobo

    What script, lua, or compiled code, handles the processing/generation of dungeons? I know how to make dungeons and their parts, but I wanted to see and modify how they actually generate for a mod I'm trying to build.

    I've done some searching in the forum, on google, and in the assets, but I haven't been able to find the file that handles the processing of dungeons and parts. Anyone know, am I blind, or is this just a function that is only compiled in binaries and not available to the public.

    Big fan of the game btw. Still getting friends and family hooked. Want to build some mods to bring even more people in.
     
  2. Inf_Wolf14

    Inf_Wolf14 Parsec Taste Tester

    The farthest back we have access to, to my knowledge, concerning dungeon generation would be between the "terrestrial_worlds.config", "instance_worlds.config", "dungeon_worlds.config", and "asteroid_worlds.config".
    We only can alter those configs which contain the information and properties concerning specific dungeon generation, sadly, NOT the properties and function of generation itself. The rest is backdoor, outside us modders' scope.
     
    midramble likes this.
  3. midramble

    midramble Space Hobo

    I see. Thank you. Just looked at those now. The customization of worldsize, width, and heights is very useful. I definitely think I will play around more with these instanced dungeons. As for limited generation access, looks like I'll have to game its function then and will have to rely on the experience of the wonderful modders here and my own testing.

    That being said, I have a few questions if anyone has experimented enough to know the answers:
    1) I know that dungeon parts will overwrite the tiles of separate dungeons, but do parts not generate on a connector if they would collide with their own dungeon?
    2) If 1 is the case, does the generator cycle through every possible part that is allowed to gen on that connector to find one that does fit?
    3) If 2, does this self "collision detection" for generation allow generation if the overlapping tiles of only the generating part are mod layer "allowOverdrawing"?
    4) What about 3 if the overlapping tiles are "allowOverdrawing" only for the already generated colliding part?
    5) What about 3 if both are allowOverdrawing? Whatever is generated first gets drawn over but both parts are generated?
    6) What order does the connector part generation happen?
    6a) Do the connectors generate parts when they come within a certain distance of the player? (if so, skip 6c through the rest of 6)
    6b) If so, is it radius based or a box of height and width?
    6c) If generation happens at world gen, does every connector of the anchor part get a part generated before it moves on to a sub part?
    6d) Do the connectors decide generation order at all?
    6e) If they do, is it based on orientation order? (top to bottom left to right?)
    6f) If not based on orientation, is it based on the connector color?
    7) Do wired objects prevent part generation if they would overlap with another part? (Does it depend on what it overlaps with? As in object over background is fine but not over solid?)
    8) Does allowOverdrawing work with wired objects?
    9) If not 8 and not 7, is it possible to set wires to these objects? Is it possible to set allowOverdrawing for wires?
    10) If two parts overlap to the point that they have a connector in the same location, which connector/part "wins" the generation?
    11) Is there a list of other useful custom properties like allowOverdrawing?
    12) Does stagehand object collision prevent generation?

    All I can think of at the moment. Sorry for the question dump.
     
  4. lazarus78

    lazarus78 The Waste of Time

    1. The "random" dungeons start with an "anchor" section and branch off from there based on connector points you set so you can make sure sections line up. They also use tester spots to see if there is a block, air, background block, background air, or both, when deciding if a dungeon section can be places somewhere (Player defined in the dungeon sections). So if a dungeon is overlapping itself, then you didn't properly add these testers, or you didn't place them very well.

    2. Sort of. You can set priorities and limitations. IE Section A can connect to section B and C, but section B can never connect to section C. You can also set a limit on how many of a section can generate, so if that pool is exausted, then it will have to pick something else if able.

    3. Uhh... not sure.

    4. Ditto ^

    5. Ditto ^

    6a. The dungeons are generated at worldgen. You can see it in the game log when you travel to another planet.
    6c. As said above in #1, every dungeon starts with an anchor section and branches from there based on connector points you have set and the other priorities and limitations you have set. You can define specific connector points so that, say, only sections A, B, and C will branch off from the left side of the anchor, and sections , D, E, and F will only branch off the right side.
    6d. Im sure there is a technical order the game processes things in for this, but I don't know what it is. Never needed to know that information.
    6e. Ditto ^
    6f. The connector points are part of it.

    7. Dungeons will generate if they believe it is a valid spot based on the above mentioned "tester" spots. It will overwrite anything under it.

    8. Don't know.

    9. I don't think wires can traverse sections, but I could be wrong.

    10. Since there is an order to how they generate (one section at a time), it would literally come down to a stack, and the one on top will always win since it overwrites whatever was under it.

    11. No idea.

    12. Doubtful, since the overlapping will wipe out whatever is below it.
     
    Inf_Wolf14 and midramble like this.
  5. midramble

    midramble Space Hobo

    I see! That's awesome. I assume thats what the Air and So blocks are in Tiled, for testing for solid or air fore or background. Does this only test for dungeon part generated tiles or does it also include worldgen terrain generated tiles?

    I saw this feature and love it. I do wonder though if there is a canonlycombine vs don't combine as if you have say 100s of parts, the don'tcombine list will be tediously large for every part.


    I think I may do some experimenting with this and report back. Though I doubt anyone will care haha.

    I may do some experimenting with this as well.

    Thanks so much. I'll keep checking in on this to see if anyone else has info, otherwise I'll update if I find anything in my experiments.
     
  6. lazarus78

    lazarus78 The Waste of Time

    It checks the surrounding area, so it will include both depending on how much of the dungeon is already generated.

    From the looks of it, then it is explicet deny only. It assumes all sections are valid in any position (Assuming their connectors match) and you have to tell it which ones you don't want it to connect with. They use this for having variants of the same room but with different interiors and whatnot.

    The connectors are basically what you are looking for with "CanOnlyCombineWith", since if the connectors are not of the same type, then they are not considered as valid sections.
     
    midramble likes this.
  7. midramble

    midramble Space Hobo

    That being the case, is it possible to add extra connectors? I notice in the connector custom properties that the actual connector property is 4 octets so I wonder if I put in custom values for this if it will create a new ID connector. If no one knows then I may experiment myself as this would make things a good amount easier.
     
  8. lazarus78

    lazarus78 The Waste of Time

    Yeah you can make as many connectors as you wish.
     
    midramble likes this.
  9. bk3k

    bk3k Oxygen Tank

    You might also note that dungeons are spawnable via LUA too. From the documentation
    At a point I'm going to make objects that spawn dungeons. No reason you couldn't make such objects that happen to be part of a dungeon. That might give you some control you crave. I can't say I know anything about Tiled as I haven't dived in yet.
     
    midramble likes this.
  10. midramble

    midramble Space Hobo

    Awesome. Where is this documentation? Im quitr familiar with lua if there is something i can do with generating there. My original idea was to create sub dungeon objects and make added parameters for size and shape limitataion. Though in an editable area a custom object like that could cause problems. Still worth a look.

    Right, I mean make extra types as there are only 4 types and thus only 4 possible link identifiers. With larger dungeons I'd like to have more so I didn't have to extensively use the don't combine with field. It looks like I may be able to add connector types (IDs really) bit they will probably have to be added as custom tiles.
     
  11. bk3k

    bk3k Oxygen Tank

    \starbound\doc\lua\
     
    midramble likes this.
  12. midramble

    midramble Space Hobo

    Well this is embarrassing, spent all that time talking a big game but in my early tests parts aren't even spawning on dungeon generation. Only the anchor part generates. Either my dungeon file has to be wrong or my connectors are messed up. I've double checked that I have corresponding connectors and that they exist on the anchors layer instead of the front or back. I have applied no tester objects as I want them to spawn no matter what at the moment (again for testing). Chance is set to 1 and maxspawn for each part is set to 1. Dungeon parts set to 12. Radius is sufficiently large. Ya know what, I'll just post the test dungeon code.

    Code:
    {
      "metadata" : {
        "name" : "sprawl",
        "species" : "human",
        "rules" : [
        ],
        "anchor" : [ "spaceport" ],
        "gravity" : 80,
        "maxRadius" : 1000000,
        "maxParts" : 12,
        "protected" : true
      },
    
      "parts" : [
        {
          "name" : "spaceport",
          "rules" : [
            [ "maxSpawnCount", [1] ]
            // [ "doNotCombineWith", [ "examplepiece" ] ]
            // [ "ignorePartMaximumRule" ]
          ],
          "def" : [ "tmx", "spaceport.json" ],
          "chance" : 1
        },
        {
          "name" : "anchorcorador",
          "rules" : [
            [ "maxSpawnCount", [1] ]
            // [ "doNotCombineWith", [ "examplepiece" ] ]
            // [ "ignorePartMaximumRule" ]
          ],
          "def" : [ "tmx", "anchorcorador.json" ],
          "chance" : 1
        },
        {
          "name" : "room1",
          "rules" : [
            [ "maxSpawnCount", [1] ]
            // [ "doNotCombineWith", [ "examplepiece" ] ]
            // [ "ignorePartMaximumRule" ]
          ],
          "def" : [ "tmx", "room1.json" ],
          "chance" : 1
        },
        {
          "name" : "room2",
          "rules" : [
            [ "maxSpawnCount", [1] ]
            // [ "doNotCombineWith", [ "examplepiece" ] ]
            // [ "ignorePartMaximumRule" ]
          ],
          "def" : [ "tmx", "room2.json" ],
          "chance" : 1
        },
        {
          "name" : "room3",
          "rules" : [
            [ "maxSpawnCount", [1] ]
            // [ "doNotCombineWith", [ "examplepiece" ] ]
            // [ "ignorePartMaximumRule" ]
          ],
          "def" : [ "tmx", "room3.json" ],
          "chance" : 1
        },
        {
          "name" : "room4",
          "rules" : [
            [ "maxSpawnCount", [1] ]
            // [ "doNotCombineWith", [ "examplepiece" ] ]
            // [ "ignorePartMaximumRule" ]
          ],
          "def" : [ "tmx", "room4.json" ],
          "chance" : 1
        },
        {
          "name" : "room5",
          "rules" : [
            [ "maxSpawnCount", [1] ]
            // [ "doNotCombineWith", [ "examplepiece" ] ]
            // [ "ignorePartMaximumRule" ]
          ],
          "def" : [ "tmx", "room5.json" ],
          "chance" : 1
        },
        {
          "name" : "room6",
          "rules" : [
            [ "maxSpawnCount", [1] ]
            // [ "doNotCombineWith", [ "examplepiece" ] ]
            // [ "ignorePartMaximumRule" ]
          ],
          "def" : [ "tmx", "room6.json" ],
          "chance" : 1
        },
        {
          "name" : "room7",
          "rules" : [
            [ "maxSpawnCount", [1] ]
            // [ "doNotCombineWith", [ "examplepiece" ] ]
            // [ "ignorePartMaximumRule" ]
          ],
          "def" : [ "tmx", "room7.json" ],
          "chance" : 1
        },
        {
          "name" : "room8",
          "rules" : [
            [ "maxSpawnCount", [1] ]
            // [ "doNotCombineWith", [ "examplepiece" ] ]
            // [ "ignorePartMaximumRule" ]
          ],
          "def" : [ "tmx", "room8.json" ],
          "chance" : 1
        },
        {
          "name" : "room9",
          "rules" : [
            [ "maxSpawnCount", [1] ]
            // [ "doNotCombineWith", [ "examplepiece" ] ]
            // [ "ignorePartMaximumRule" ]
          ],
          "def" : [ "tmx", "room9.json" ],
          "chance" : 1
        },
        {
          "name" : "room10",
          "rules" : [
            [ "maxSpawnCount", [1] ]
            // [ "doNotCombineWith", [ "examplepiece" ] ]
            // [ "ignorePartMaximumRule" ]
          ],
          "def" : [ "tmx", "room10.json" ],
          "chance" : 1
        }
      ]
    }
    
     
  13. lazarus78

    lazarus78 The Waste of Time

    What does your log say?
     
  14. midramble

    midramble Space Hobo

    Code:
    [00:28:37.281] [Info] Chat: <server> Lets do the space warp again
    [00:28:37.397] [Info] UniverseServer: Creating temporary world file for world InstanceWorld:sprawl:-:-
    [00:28:37.398] [Info] UniverseServer: Creating temporary instance world 'InstanceWorld:sprawl:-:-'
    [00:28:37.400] [Info] Placing dungeon sprawl
    [00:28:38.070] [Info] Forcing generation of dungeon sprawl
    [00:28:38.075] [Info] Placing dungeon at (0, 1000)
    [00:28:39.376] [Info] Protected dungeonIds for world set to (0)
    [00:28:40.313] [Info] UniverseServer: Warping player 1 to InstanceWorld:sprawl:-:-
    No errors. I warp there but only the anchor part has generated.
     
  15. lazarus78

    lazarus78 The Waste of Time

    Hmm. Hard to tell wihout seeing what the sections look like. Could you post some images, or the actual files?
     
  16. midramble

    midramble Space Hobo

    They are very simple parts. And if all else fails I can upload the whole dungeon itself. The one with the playerspawn is spaceport (the anchor) and the one with all the extra connectors is anchorcorador in the dungeon file and by json name. Only the anchor generates with my character spawned on top. Is it somehow the open space around the anchor overdrawing the corridor? Have a lot of pinkbrush background and no data foreground.

     
  17. lazarus78

    lazarus78 The Waste of Time

    Ill have to concede here. Im not sure exactly how Tiled works. Ive really only ever done the old png style dungeons.

    Good luck.
     
  18. midramble

    midramble Space Hobo

    Is there any documentation on the connectors in tiled then? I've found the tut for png dungeon creation and the standard tiled one but I can't find anything about the specifics of the connectors. Been just trying a lot of trial and error. Maybe if I can get this figured out, I'll make some kind of tut here hahaha.
     
  19. midramble

    midramble Space Hobo

    Ok update:

    Got it working and generating parts. These are my findings.

    1) Looks like connectors have to be snapped to grid in Tiled (using ctrl key). I also put them in the anchor layer. Haven't really tried with them in the front or back layer.
    2) The connector doesn't work by supplying a tile where the corresponding connector tile will overlap, instead it actually acts as sort of an edge detector and the corresponding connector spawns "inside" of the corresponding connector. Though this doesn't require the connector to be adjacent to a front or back tile. I plan to show this graphically later and will do some more testing to see how this applies diagonally and with jigsaw style overlapping pieces.
    3) If a part, that is configured to generate, would have tiles overlapping with an already spawned part of the dungeon (while generating) it will not spawn.
    4) spawn order appears to happen like a tree. All connectors on the anchor will generate a part, then one of the anchor child parts will gen all of it's connector parts, then a second anchor child will do the same, and continue on through all of the child parts before moving on to the "grandchildren". The order of this generation makes some generation gaming possible.
    5) It also appears that the order of progression through the child parts is based on which one has the object ID number. (will need to confirm this)

    Additional questions: (some I will test and research on my own)

    1) how does the chance parameter in the dungeon file work? I've seen vanilla files have it set to 0, 500, 1000, and 1, but am not entirely sure how these values apply to spawn ratios.
    2) Confirm #5 above

    I'll add more here as I come up with it haha.
     
    bk3k likes this.
  20. midramble

    midramble Space Hobo

    Another update: (shamelessly bumping my own thread :/)

    1) You CAN create objects with a parameter of allowoverdrawing and a block identity (as appears in the hylotl ocean city bedrooms part) in order to set sections of the part that will "paint" tiles; however, they conveniently do not block a part from being generated if it would overlap with these tiles. It does actually draw over these tiles, including if the overlapping tiles are set to nothing. It will overdraw the tiles with any data with the exception of magicpinkbrush tiles.
    2) I put these objects using the draw rectangle tool on the mod layer using ctrl to snap to the grid and then manually write the overdraw parameter as true and write in the front block and back block I want to be painted. (another example is in the endcap parts of ancient dungeons)
    3) #1 is exceptionally convenient in cases where you want to adjust part gen ratios with filler tiles that use up the connector spot; however, allow future generated parts to draw over them should your design go that direction.
    4) The chance parameter is based on weighting. The number in the parameter gives that particular part a occurrence weight, if you will. What the generator appears to do is collect the list of all possible parts based on connector compatibility and donotcombinewith and donotconnectwith parameters (not sure if before or after sizing/overlap restrictions, may test) and adds up the total weight of all parts and generates procedurally based on the ratio of that part weighting compared to the weight of all available parts.

    For example:
    Room1 chance: 1000
    Room2 chance: 1000
    Room3 chance: 1000
    Hallway chance: 100

    Total weight pool is 3100 if all of these parts are allowed to spawn to this particular connector based on rules.

    In this scenario the hallway will gen only 100 out of 3100 (equally 1 out of 31) times. 30 out of 31 times will be a room, and each particular room will gen 10 out of 31 times. As a tip for those wanting to adjust their ratios you'll want to keep track of "groups" of parts and adjust ratios based on that.

    For instance if I wanted rooms (in general) to be only 3 times as common as hallways I'd want the total rooms weight to be 3 times the weight of hallways. (I suggest running with bigger numbers as it will allow you to use smaller numbers later if you have a large pool of parts but want some parts to be particularly rare). In this circumstance I would change Hallway to 1000. Say I also wanted room2 to show up half the time and room1 or 3 to show up the other half of the time when it's a room being generated. I would do the same but only look at the group of rooms. In order to keep the generation balanced with the hallways still, I have to keep the collection of room weight at a total or 3000 while room2 is twice the weight of the other two rooms. That being the case I'd have the table as below.

    Room1 chance: 750
    Room2 chance: 1500
    Room3 chance: 750
    Hallway chance: 1000

    This accomplishes our goal. However, notice that the total of this entire group has increased by 900 as a result of increasing Hallway. If this is the only group that competes of generation then this isn't a problem, but if this group is in a pool with a larger group (like room1-3 are a sub group of this one) then we would similarly have to keep the total pool the same. This a reason why bigger numbers are easier to deal with. If I wanted to keep the total weight the same, with some quick algebra I'd put the weighting at...

    Room1 chance: 581
    Room2 chance: 1163
    Room3 chance: 581
    Hallway chance: 775

    I'm showing this in order to explain that it's best to plan out your ratios on big projects because the numbers can get very tedious quickly if you start arbitrarily. If I'd started this group pool at 4000 like in the first example this would be easier to work with. You have to keep in mind that the weight of this part sticks with it throughout the entire dungeon. As far as I've been able to tell there is no way to set chance based on a particular part connection/combination. (this would be amazing if so...)

    Will continue to update with findings.

    If anyone is reading this and knows any information about the dungeon generation mechanics please feel free to post them. I have no problem testing their limits and functions. I would particularly love any new parameters that I"ve missed in other dungeon parts or that existed in old builds.

    As a matter of fact, does anyone know how to reliably contact devs?
     

Share This Page