Thursday 24 August 2017

Atom Tabletop Simulator package, experimental #include system

A note about the experimental additions, specifically the #include:

You can #include other files into your source; when you hit Save And Play the plugin will go and grab those files and inline them in your code at the point you have placed them. The files are looked for inside the folder specified, or you can specify a complete path to their location.

For example, on the game I'm working my Global.-1.ttslua is now simply:

-- workshop id = 945458382

#include Shard/shard
When I hit Save And Play it will look for the shard file in the folder location specified in the settings: by default this is your USER_FOLDER/Documents/Tabletop Simulator. So in my case it will get the file:

C:\Users\onelivesleft\Documents\Tabletop Simulator\Shard\shard.ttslua
- Shard\shard.ttslua being specified by the #include 

My shard.ttslua file looks like this:
Code:
#include constants
#include guids
#include globals
#include levels
#include !/utils

#include admin
#include game
#include draft
#include rewards
#include dice
#include expansions

--NO_SAVE_OR_LOAD = true  -- To remove any state for clean upload to workshop
--DEBUG_DISPLAY   = true

game_started = false
loaded = false

function onload(saved_data)
    current_level = nil
    ...
When the plugin fetches it, it will then look through it inlining the includes it has, and so on. This time it won't look in the folder specified in the settings, it will look in the same folder as the file which included them. My file structure looks like this (and is a git repo!):



Almost all the files included by shard.ttslua are in the same folder as it, so I only need their name.

Note the line: #include !/utils - the !/ is an identifier that specifies the folder specified in the package settings.  In this way I can have a utils library sitting in the root of my TTS folders, accessible by all my games.  You may have a vector library you wish to include in all your objects' code; now, this is easy to do.  You may also use the symbol ~/ to start a path from your user home folder (even on Windows), or specify a full path on the #include line if you want to.

In practice how this works is it takes all the text in the files you are including and dumps them into the source at the point they are included.  This means if you have a bunch of functions you want your objects to have access to then you can, but they are in effect being repeated in every object. 

As it stands this means all your modules are sharing the same namespace; a global in one is accessible in all.  I'm OK with this (it's the Lua spirit), but if you want to make them behave like modules you can, you just have to do it explicitly.  

  1. Start the module by declaring itself as a table.
  2. Prefix all it's "globals" and function with that table.

Let's say you have a module to greet the players, saved as greetings.ttslua :

greetings = {}

greetings.default_greeting = "Hello!"

function greetings.greet(message)
    local message = message or greetings.default_greeting
    for p, player in pairs(getSeatedPlayers()) do
        printToColor(message, player, rgb)
    end
end

Then you can use it in your program by:

#include greetings

greetings.greet()
greetings.greet("Hi!")
greetings.default_greeting = "Yo!"
greetings.greet()

When you get the script from TTS the atom plugin will automatically strip out the inlined code and give you what you expect.  Note that the package commands like Go To Function will take into account all your includes, and when you use them will jump to the correct place.  If you are in your Global.-1.ttslua file and type a line number into the Go To Function dialog it is smart enough to know which line you are referring to and take you to it.  i.e. even though the program I listed at the top of this post only has 3 lines when I see it in the editor, when TTS says there's a bug on line 4345 I can hit ctrl-g and type 4345, and it will take me to the correct line (opening up the relevant included file if necessary).

EDIT: As of plugin version 11.0.2 you may optionally enclose your include in `<` and `>`; if you do so then the inserted text will be enclosed within a `do`...`end` block, keeping local variables contained. Example:

#include <Console/Console++>