Modding Help Is it possible to define templated/generic recipes/objects?

Discussion in 'Starbound Modding' started by Exilyth, Mar 17, 2017.

  1. Exilyth

    Exilyth Astral Cartographer

    Hello.

    Just got into starbound modding. I made a simple little mod which adds some craftable objects.
    The amount of objects and recipes is small (read: currently four objects w/recipes) and I already have a lot of code duplication (four doors = four object files).

    So, I was wondering, is there a way to create templated/generic objects/recipes?

    What I'd like to do is e.g. define a door only once and then just use different textures (and maybe sounds) to skin/theme the object without having to write a new full definition for each variant.

    Similarly with recipes: I'd like to turn <ore> and <ingot> and darkwoodmaterial into the specific <ore>_<ingot>_door, e.g. iron ore + iron ingot + darkwoodmaterial => ironore_ironingot_door.
     
  2. bk3k

    bk3k Black Hole Surfer

    From the Starbound end of things... no. You copy/paste/edit..

    You can write scripts for your computer that do what you're talking about. Powersheel, Python, etc. That's got nothing to do with Starbound specifically.

    Since you're making tiles, please utilized this to avoid conflicts. Also appending your handle or mod name(perhaps abbreviated) to nameSpaces is also useful on that front. exylth_redDoor etc.

    Now depending on your ability to use LUA, it is possible to create objects with different parameters dynamically. They wouldn't have "recipes" per say(not regular ones) but consuming materials can be handled with code. Creating dynamic GUI buttons is possible too. Those buttons could be to make an object. You could make an external "rules list" etc type JSON file for the script to load from for easier handling.

    Maybe I'm being too vague, but I don't know what you currently know and for much of this you'd need to look at lots of vanilla assets.
     
    Last edited: Mar 18, 2017
    Exilyth likes this.
  3. Exilyth

    Exilyth Astral Cartographer

    I see, so the only way would be writing a lua script which parses a custom definition file and adds the objects and recipes dynamically during runtime.

    I'm already using a namespace prefix in my mod and I don't intend to get into creating custom materials/tiles at the moment. I've already seen that some mods have legacy versions and new versions with fixed tileIDs, so that link is very usefull indeed.

    I think I've seen custom crafting implemented somewhere before ... *takes a quick detour to the frackin' universe github and takes a look at stuff like the powder sifter*

    I know json, I know lua, I just need to find out how starbound does things and how to get the 'glorified json parser' to do my bidding. :nuruwink:
    Well, the wiki and the modding forum are good sources for information on starbound modding (although some info is a bit outdated or incomplete, e.g. http://starbounder.org/Modding:Lua).

    I've scoured through the unpacked assets and now got a list of all doors currently in the game.
    I'll come up with something and post my findings/solution here as soon(tm) as I can spare the time.


    Edit: I've just seen that there is no info yet on how strongly the lua in starbound is sandboxed. Most games limit the available functions in lua so that scripts are less able to perform 'evil' actions (like deleting all files or something).
     
    Last edited: Mar 19, 2017
  4. bk3k

    bk3k Black Hole Surfer

    Well there are a few ways of creating more than one thing. Like you say, a customer definition file. Take a look at the upgradable workbenches too. They more or less have "objects within objects" and I'm not talking JSON objects {} of course.

    You can create a valid "itemDescriptor" by starting with table that we're going to call "itemDes"
    Code:
      local itemDes = {
        name = "soluskatana",
        count = 1,
        parameters = {
          shortdescription = "Sword of Light",
          description = "Powerful sword forged by Darkstar himself",
          level = 10,
          altAbilityType = "flipslash"
        }
      }
    
    You need to start with some valid entity as a basis. You then plug into itemDes.parameters any parameters that you would change(or add) versus the base. You could have generic prototypes added into your mods(that wouldn't have a real recipe or anything), then plug in any variable detail.

    As for

    LUA 5.3
    no debugger
    no io library
    I think you're find only os.time() and os.difftime()
    Their require has no "path" to work with - literal paths only(with root as a basis, no os paths) - and it returns nothing.

    You'll have to be a bit more creative to save any info that must be saved. Created items can be embedded with information obviously. If You had to, you can write information into the world properties itself. And regarding that, even though you may see something like "ship.fuel", don't assume there is a "ship" table involved there. Just something addressed by the "ship.fuel" nameSpace. This is probably more appropriate for things beyond the scope of a single object's data and of course use unique nameSpaces.

    root.assetJson can help you access different JSON files but that's nothing you can't find in the docs folder (documentation errors not withstanding). A critical thing they're missing is the ability to get a readout of the different files within any given path. Say you wanted to look at different monsters(potentially including mod added content), and build a pool of monsters with certain attributes... good luck with that!

    Oh also, during all the evaluation that may occur before the first run of init - say gathering requirements, hooking functions, etc. All engine added tables/functions will be nil. A notable absence being sb.logInfo()

    init() itself may run multiple times - especially when teleporting to/from ship but I've seen it run multiple times upon simply loading the character. So save some value that tells you init() has run, and check it within init().

    The engine functions you'll have access to do vary based upon what sort of entity you're talking. Objects can't access the player table functions etc. When starting on a new type of entity, you may want to dump the _ENV table(and skip UTF8 !). I thought about building a complete list and making a thread, but I haven't done so yet.

    Your entity's storage table will persist through the session, but will not persist between them. It WILL save storage.state though... in a boolean reduced form. If you tried to save a table, you'd have true upon reload. But that can at the very least tell you that a door is open, a light is off, and a machine is running. For that I'd recommend this line in init()
    Code:
    storage.state = storage.state or false


    Regarding JSON though, besides all the special nameSpaces observed by the engine's C++ base, there are notable exceptions to the standard.
    1. Comments are valid - as they once where in the official standard before it was foolishly nerfed in a fit of nerd rage over pre-compile directives.
    2. JSON patches can be sequentially batched by nesting the patches in another array. This makes them 10^17% more useful. For example -

    /player.config.patch
    Code:
    [
      [
        {
          "op" : "add",
          "path" : "/statusControllerSettings/primaryScriptSources/-",
          "value" : "/scripts/bk3k/bk3k_shipDamage.lua"
        }
      ],
    
      [
        {
          "op" : "test",
          "path" : "/modEnvironment",
          "inverse" : true
        },
        {
          "op" : "add",
          "path" : "/modEnvironment",
          "value" : {}
        }
      ],
    
      [
        {
          "op" : "test",
          "path" : "/modEnvironment/on_shipDamage",
          "inverse" : true
        },
        {
          "op" : "add",
          "path" : "/modEnvironment/on_shipDamage",
          "value" : true
        }
      ]
    ]
    and another unrelated example

    /interface/scripted/techupgrade/techupgradegui.config.patch
    Code:
    [
      [
        {
          "op" : "add",
          "path" : "/scripts/-",
          "value" : "/interface/scripted/techupgrade/bk3k_addTechs.lua"
        }
      ],
    
      [
        {
          "op" : "test",
          "path" : "/modTech",
          "inverse" : true
        },
        {
          "op" : "add",
          "path" : "/modTech",
          "value" : []
        }
      ],
    
      [
        {
          "op" : "add",
          "path" : "/modTech/-",
          "value" : "bk3k_dash"
        },
        {
          "op" : "add",
          "path" : "/modTech/-",
          "value" : "bk3k_doubleDash"
        },
        {
          "op" : "add",
          "path" : "/modTech/-",
          "value" : "bk3k_insaneDash"
        },
        {
          "op" : "add",
          "path" : "/modTech/-",
          "value" : "bk3k_ftlboost"
        },
        {
          "op" : "add",
          "path" : "/modTech/-",
          "value" : "bk3k_multijump"
        },
        {
          "op" : "add",
          "path" : "/modTech/-",
          "value" : "bk3k_multijump_plusBoost"
        }
      ]
    ]
    So you see, a failure in one batch(generally the test condition is false) won't prevent the application of other batches. In an environment where you don't know what other mods may be installed, this provides a great way to keep mods playing nicely with each other.

    In the first example, I don't know if /modEnvironment exists, but if not I create the path. Then I add to it knowing that - one way or another - the path now exists. If a person wanted to spawn a ship invasion - but wanted to know that the player could indeed be harmed during the event - they could check easily using root.assetJson within their scripts. For that matter, their own patches could check for this. It might be useful when patching to check at least for major mods like FU by looking for things they've changed(in which case you may also want to affect load order).

    In that last example I'm patching the tech console's gui config file to add a list of techs I want added. The script I'm adding there hooks the gui's functions and does the actual tech adding by reading that list. Another tech mod could copy this method without breaking my mod.

    Even if you're simply wanting to remove something, it is better to test that it exists first and thus prevent the log errors that come from attempting to remove something that doesn't exist.
     
    Exilyth likes this.
  5. DraikNova

    DraikNova Phantasmal Quasar

    You can spawn in weapons with their colors changed, but I'm not entirely sure if that also works properly for placed items. I think you might be able to get some Lua code to find the particular color or colors that you want from the source item and replace different colors in the door's sprite with those colors. I'm pretty sure it would require a completely new, unique workbench. I mean, if the ingredients you are crafting from have the colors at the same positions for each ingredient, then you could just have the Lua code take the colors at those positions, and simply spawn in a door with color 1 from its sprites replaced by color 1 from the ingredient, and the same for color 2, etc.

    And besides that, I think you might be able to do some fooling around with container-like stuff, the way capture pods do. If you use that approach, each door would be crafted in a standard way, using certain basic ingredients, and then you'd add a material to it (probably by right-clicking the material onto the door like an epp onto an augment). That way, each door would permanently contain a reference to the material used to customize its appearance, which might work better with placeable items than an at crafting time manipulation.
     
  6. Exilyth

    Exilyth Astral Cartographer

    Thank you for providing such a wealth of information.

    I implemented a crafting station today, but I'm still mulling over whether and how to go about reducing the amount of json needed for the craftable objects.

    An easy hack would be (ab-)using the way colored items work: Just make an image with more rows and use different materials instead of different colors. But I'd rather let people color their doors in addition to using different materials.

    Edit:
    Regarding storage of parameters, unpacked_assets\objects\outpost\customsign\customsign.lua seems to be of interest.

    It looks like starbound/docs/lua/ contains more information than the wiki.

    Lua way of teaching recipes: player.giveBlueprint(`ItemDecriptor` item)
    Might come in handy later.

    unpacked_assets\items\buildscripts contains the lua scripts used to generate weapons and a .config file with weapon abilities. This is interesting, but somewhat hard to read. How is this related to unpacked_assets\items\active\weapons\weapon.lua ?

    unpacked_assets\items\active\unsorted\filledcapturepod\filledcapturepod.lua is the capturepod script



    I've been thinking about this a bit more: If I'd go this route, I would have to add the object definitions when starbound is beig initialised, otherwise objects placed in the world would lack object definitions.
     
    Last edited: Mar 25, 2017

Share This Page