Functions and messages for using system resources, controlling the engine, error handling and debugging.
The table can later be loaded by sys.load
.
Use sys.get_save_file
to obtain a valid location for the file.
Internally, this function uses a workspace buffer sized output file sized 512kb.
This size reflects the output file size which must not exceed this limit.
Additionally, the total number of rows that any one table may contain is limited to 65536
(i.e. a 16 bit range). When tables are used to represent arrays, the values of
keys are permitted to fall within a 32 bit range, supporting sparse arrays, however
the limit on the total number of rows remains in effect.
filename - file to write to
table - lua table to save
success - a boolean indicating if the table could be saved or not
Save data:
local my_table = {}
table.insert(my_table, "my_value")
local my_file_path = sys.get_save_file("my_game", "my_file")
if not sys.save(my_file_path, my_table) then
-- Alert user that the data could not be saved
end
If the file exists, it must have been created by sys.save
to be loaded.
filename - file to read from
loaded - lua table, which is empty if the file could not be found
Load data that was previously saved, e.g. an earlier game session:
local my_file_path = sys.get_save_file("my_game", "my_file")
local my_table = sys.load(my_file_path)
if not next(my_table) then
-- empty table
end
Check if a path exists Good for checking if a file exists before loading a large file
path - path to check
result - true
if the path exists, false
otherwise
Load data but return nil if path didn't exist
if not sys.exists(path) then
return nil
end
return sys.load(path) -- returns {} if it failed
Create a path to the host device for unit testing Useful for saving logs etc during development
filename - file to read from
host_path - the path prefixed with the proper host mount
Save data on the host
local host_path = sys.get_host_path("logs/test.txt")
sys.save(host_path, mytable)
local host_path = sys.get_host_path("logs/test.txt")
local table = sys.load(host_path)
The save-file path is operating system specific and is typically located under the user's home directory.
application_id - user defined id of the application, which helps define the location of the save-file
file_name - file-name to get path for
path - path to save-file
Find a path where we can store data (the example path is on the macOS platform):
local my_file_path = sys.get_save_file("my_game", "my_file")
print(my_file_path) --> /Users/my_users/Library/Application Support/my_game/my_file
The path from which the application is run.
path - path to application executable
Find a path where we can store data (the example path is on the macOS platform):
-- macOS: /Applications/my_game.app
local application_path = sys.get_application_path()
print(application_path) --> /Applications/my_game.app
-- Windows: C:\Program Files\my_game\my_game.exe
print(application_path) --> C:\Program Files\my_game
-- Linux: /home/foobar/my_game/my_game
print(application_path) --> /home/foobar/my_game
-- Android package name: com.foobar.my_game
print(application_path) --> /data/user/0/com.foobar.my_game
-- iOS: my_game.app
print(application_path) --> /var/containers/Bundle/Applications/123456AB-78CD-90DE-12345678ABCD/my_game.app
-- HTML5: http://www.foobar.com/my_game/
print(application_path) --> http://www.foobar.com/my_game
Get string config value from the game.project configuration file with optional default value
key - key to get value for. The syntax is SECTION.KEY
[default_value] - (optional) default value to return if the value does not exist
value - config value as a string. default_value if the config key does not exist. nil if no default value was supplied.
Get user config value
local text = sys.get_config_string("my_game.text", "default text"))
$ dmengine --config=bootstrap.main_collection=/mytest.collectionc --config=mygame.testmode=1
local testmode = sys.get_config_int("mygame.testmode")
Get integer config value from the game.project configuration file with optional default value
key - key to get value for. The syntax is SECTION.KEY
[default_value] - (optional) default value to return if the value does not exist
value - config value as an integer. default_value if the config key does not exist. 0 if no default value was supplied.
Get user config value
local speed = sys.get_config_int("my_game.speed", 20) -- with default value
local testmode = sys.get_config_int("my_game.testmode") -- without default value
if testmode ~= nil then
-- do stuff
end
Get number config value from the game.project configuration file with optional default value
key - key to get value for. The syntax is SECTION.KEY
[default_value] - (optional) default value to return if the value does not exist
value - config value as an number. default_value if the config key does not exist. 0 if no default value was supplied.
Get user config value
local speed = sys.get_config_number("my_game.speed", 20.0)
Open URL in default application, typically a browser
url - url to open
[attributes] - table with attributes
target
- string : Optional. Specifies the target attribute or the name of the window. The following values are supported:
- _self
- (default value) URL replaces the current page.
- _blank
- URL is loaded into a new window, or tab.
- _parent
- URL is loaded into the parent frame.
- _top
- URL replaces any framesets that may be loaded.
- name
- The name of the window (Note: the name does not specify the title of the new window).
success - a boolean indicating if the url could be opened or not
Open an URL:
local success = sys.open_url("http://www.defold.com", {target = "_blank"})
if not success then
-- could not open the url...
end
Loads a custom resource. Specify the full filename of the resource that you want
to load. When loaded, the file data is returned as a string.
If loading fails, the function returns nil
plus the error message.
In order for the engine to include custom resources in the build process, you need
to specify them in the "custom_resources" key in your "game.project" settings file.
You can specify single resource files or directories. If a directory is included
in the resource list, all files and directories in that directory is recursively
included:
For example "main/data/,assets/level_data.json".
filename - resource to load, full path
data - loaded data, or nil
if the resource could not be loaded
error - the error message, or nil
if no error occurred
-- Load level data into a string
local data, error = sys.load_resource("/assets/level_data.json")
-- Decode json string to a Lua table
if data then
local data_table = json.decode(data)
pprint(data_table)
else
print(error)
end
Returns a table with system information.
[options] - optional options table
- ignore_secure boolean this flag ignores values might be secured by OS e.g. device_ident
sys_info - table with system information in the following fields:
device_model
manufacturer
system_name
system_version
api_version
language
device_language
territory
gmt_offset
device_ident
READ_PHONE_STATE
permission to be able to get this data. We don't use this permission in Defold.user_agent
How to get system information:
local info = sys.get_sys_info()
if info.system_name == "HTML5" then
-- We are running in a browser.
end
Returns a table with engine information.
engine_info - table with engine information in the following fields:
version
version_sha1
is_debug
How to retrieve engine information:
-- Update version text label so our testers know what version we're running
local engine_info = sys.get_engine_info()
local version_str = "Defold " .. engine_info.version .. "\n" .. engine_info.version_sha1
gui.set_text(gui.get_node("version"), version_str)
Returns a table with application information for the requested app.
On iOS, the app_string
is an url scheme for the app that is queried. Your
game needs to list the schemes that are queried in an LSApplicationQueriesSchemes
array
in a custom "Info.plist".
On Android, the app_string
is the package identifier for the app.
app_string - platform specific string with application package or query, see above for details.
app_info - table with application information in the following fields:
installed
true
if the application is installed, false
otherwise.Check if twitter is installed:
sysinfo = sys.get_sys_info()
twitter = {}
if sysinfo.system_name == "Android" then
twitter = sys.get_application_info("com.twitter.android")
elseif sysinfo.system_name == "iPhone OS" then
twitter = sys.get_application_info("twitter:")
end
if twitter.installed then
-- twitter is installed!
end
...
<key>LSApplicationQueriesSchemes</key>
<array>
<string>twitter</string>
</array>
...
Returns an array of tables with information on network interfaces.
ifaddrs - an array of tables. Each table entry contain the following fields:
name
address
nil
if not available.mac
up
true
if the interface is up (available to transmit and receive data), false
otherwise.running
true
if the interface is running, false
otherwise.How to get the IP address of interface "en0":
ifaddrs = sys.get_ifaddrs()
for _,interface in ipairs(ifaddrs) do
if interface.name == "en0" then
local ip = interface.address
end
end
Set the Lua error handler function. The error handler is a function which is called whenever a lua runtime error occurs.
error_handler - the function to be called on error
source
"lua"
.message
traceback
Install error handler that just prints the errors
local function my_error_handler(source, message, traceback)
print(source) --> lua
print(message) --> main/my.script:10: attempt to perform arithmetic on a string value
print(traceback) --> stack traceback:
--> main/test.script:10: in function 'boom'
--> main/test.script:15: in function <main/my.script:13>
end
local function boom()
return 10 + "string"
end
function init(self)
sys.set_error_handler(my_error_handler)
boom()
end
Sets the host that is used to check for network connectivity against.
host - hostname to check against
sys.set_connectivity_host("www.google.com")
Returns the current network connectivity status
on mobile platforms.
On desktop, this function always return sys.NETWORK_CONNECTED
.
status - network connectivity status:
sys.NETWORK_DISCONNECTED
(no network connection is found)sys.NETWORK_CONNECTED_CELLULAR
(connected through mobile cellular)sys.NETWORK_CONNECTED
(otherwise, Wifi)Check if we are connected through a cellular connection
if (sys.NETWORK_CONNECTED_CELLULAR == sys.get_connectivity()) then
print("Connected via cellular, avoid downloading big files!")
end
Terminates the game application and reports the specified code
to the OS.
code - exit code to report to the OS, 0 means clean exit
This examples demonstrates how to exit the application when some kind of quit messages is received (maybe from gui or similar):
function on_message(self, message_id, message, sender)
if message_id == hash("quit") then
sys.exit(0)
end
end
Reboots the game engine with a specified set of arguments. Arguments will be translated into command line arguments. Calling reboot function is equivalent to starting the engine with the same arguments. On startup the engine reads configuration from "game.project" in the project root.
arg1 - argument 1
arg2 - argument 2
arg3 - argument 3
arg4 - argument 4
arg5 - argument 5
arg6 - argument 6
How to reboot engine with a specific bootstrap collection.
local arg1 = '--config=bootstrap.main_collection=/my.collectionc'
local arg2 = 'build/game.projectc'
sys.reboot(arg1, arg2)
Set the vsync swap interval. The interval with which to swap the front and back buffers
in sync with vertical blanks (v-blank), the hardware event where the screen image is updated
with data from the front buffer. A value of 1 swaps the buffers at every v-blank, a value of
2 swaps the buffers every other v-blank and so on. A value of 0 disables waiting for v-blank
before swapping the buffers. Default value is 1.
When setting the swap interval to 0 and having vsync
disabled in
"game.project", the engine will try to respect the set frame cap value from
"game.project" in software instead.
This setting may be overridden by driver settings.
swap_interval - target swap interval.
Setting the swap intervall to swap every v-blank
sys.set_vsync_swap_interval(1)
Set game update-frequency (frame cap). This option is equivalent to display.update_frequency
in
the "game.project" settings but set in run-time. If Vsync
checked in "game.project", the rate will
be clamped to a swap interval that matches any detected main monitor refresh rate. If Vsync
is
unchecked the engine will try to respect the rate in software using timers. There is no
guarantee that the frame cap will be achieved depending on platform specifics and hardware settings.
frequency - target frequency. 60 for 60 fps
Setting the update frequency to 60 frames per second
sys.set_update_frequency(60)
The buffer can later deserialized by sys.deserialize
.
This method has all the same limitations as sys.save
.
table - lua table to serialize
buffer - serialized data buffer
Serialize table:
local my_table = {}
table.insert(my_table, "my_value")
local buffer = sys.serialize(my_table)
deserializes buffer into a lua table
buffer - buffer to deserialize from
table - lua table with deserialized data
Deserialize a lua table that was previously serialized:
local buffer = sys.serialize(my_table)
local table = sys.deserialize(buffer)
no network connection found
network connected through mobile cellular
network connected through other, non cellular, connection
Terminates the game application and reports the specified code
to the OS.
This message can only be sent to the designated @system
socket.
code - exit code to report to the OS, 0 means clean exit
This examples demonstrates how to exit the application when some kind of quit messages is received (maybe from gui or similar):
function on_message(self, message_id, message, sender)
if message_id == hash("quit") then
msg.post("@system:", "exit", {code = 0})
end
end
Toggles the on-screen profiler.
The profiler is a real-time tool that shows the numbers of milliseconds spent
in each scope per frame as well as counters. The profiler is very useful for
tracking down performance and resource problems.
In addition to the on-screen profiler, Defold includes a web-based profiler that
allows you to sample a series of data points and then analyze them in detail.
The web profiler is available at http://<device IP>:8002
where @system
socket.
msg.post("@system:", "toggle_profile")
Toggles the on-screen physics visual debugging mode which is very useful for
tracking down issues related to physics. This mode visualizes
all collision object shapes and normals at detected contact points. Toggling
this mode on is equal to setting physics.debug
in the "game.project" settings,
but set in run-time.
This message can only be sent to the designated @system
socket.
msg.post("@system:", "toggle_physics_debug")
Starts video recording of the game frame-buffer to file. Current video format is the
open vp8 codec in the ivf container. It's possible to upload this format directly
to YouTube. The VLC video player has native support but with the known issue that
not the entire file is played back. It's probably an issue with VLC.
The Miro Video Converter has support for vp8/ivf.
Video recording is only supported on desktop platforms.
Audio is currently not supported
Window width and height must be a multiple of 8 to be able to record video.
This message can only be sent to the designated @system
socket.
file_name - file name to write the video to
frame_period - frame period to record, ie write every nth frame. Default value is 2
fps - frames per second. Playback speed for the video. Default value is 30
. The fps value doens't affect the recording. It's only meta-data in the written video file.
Record a video in 30 fps given that the native game fps is 60:
msg.post("@system:", "start_record", { file_name = "test_rec.ivf" } )
msg.post("@system:", "start_record", { file_name = "test_rec.ivf", frame_period = 1, fps = 60 } )
Stops the currently active video recording.
Video recording is only supported on desktop platforms.
This message can only be sent to the designated @system
socket.
msg.post("@system:", "stop_record")
Reboots the game engine with a specified set of arguments.
Arguments will be translated into command line arguments. Sending the reboot
command is equivalent to starting the engine with the same arguments.
On startup the engine reads configuration from "game.project" in the
project root.
This message can only be sent to the designated @system
socket.
arg1 - argument 1
arg2 - argument 2
arg3 - argument 3
arg4 - argument 4
arg5 - argument 5
arg6 - argument 6
How to reboot engine with a specific bootstrap collection.
local arg1 = '--config=bootstrap.main_collection=/my.collectionc'
local arg2 = 'build/game.projectc'
msg.post("@system:", "reboot", {arg1 = arg1, arg2 = arg2})
Set the vsync swap interval. The interval with which to swap the front and back buffers
in sync with vertical blanks (v-blank), the hardware event where the screen image is updated
with data from the front buffer. A value of 1 swaps the buffers at every v-blank, a value of
2 swaps the buffers every other v-blank and so on. A value of 0 disables waiting for v-blank
before swapping the buffers. Default value is 1.
When setting the swap interval to 0 and having vsync
disabled in
"game.project", the engine will try to respect the set frame cap value from
"game.project" in software instead.
This setting may be overridden by driver settings.
This message can only be sent to the designated @system
socket.
swap_interval - target swap interval.
msg.post("@system:", "set_vsync", { swap_interval = 1 } )
Set game update-frequency (frame cap). This option is equivalent to display.update_frequency
in
the "game.project" settings but set in run-time. If Vsync
checked in "game.project", the rate will
be clamped to a swap interval that matches any detected main monitor refresh rate. If Vsync
is
unchecked the engine will try to respect the rate in software using timers. There is no
guarantee that the frame cap will be achieved depending on platform specifics and hardware settings.
This message can only be sent to the designated @system
socket.
frequency - target frequency. 60 for 60 fps
msg.post("@system:", "set_update_frequency", { frequency = 60 } )
The sys.load_buffer function will first try to load the resource from any of the mounted resource locations and return the data if any matching entries found. If not, the path will be tried as is from the primary disk on the device. In order for the engine to include custom resources in the build process, you need to specify them in the "custom_resources" key in your "game.project" settings file. You can specify single resource files or directories. If a directory is included in the resource list, all files and directories in that directory is recursively included: For example "main/data/,assets/level_data.json".
path - the path to load the buffer from
buffer - the buffer with data
Load binary data from a custom project resource:
local my_buffer = sys.load_buffer("/assets/my_level_data.bin")
local data_str = buffer.get_bytes(my_buffer, "data")
local has_my_header = string.sub(data_str,1,6) == "D3F0LD"
local asset_1 = sys.load_buffer("folder_next_to_binary/my_level_asset.txt")
local asset_2 = sys.load_buffer("/my/absolute/path")
The sys.load_buffer function will first try to load the resource from any of the mounted resource locations and return the data if any matching entries found. If not, the path will be tried as is from the primary disk on the device. In order for the engine to include custom resources in the build process, you need to specify them in the "custom_resources" key in your "game.project" settings file. You can specify single resource files or directories. If a directory is included in the resource list, all files and directories in that directory is recursively included: For example "main/data/,assets/level_data.json". Note that issuing multiple requests of the same resource will yield individual buffers per request. There is no implic caching of the buffers based on request path.
path - the path to load the buffer from
status_callback - A status callback that will be invoked when a request has been handled, or an error occured. The result is a table containing:
status
resource.REQUEST_STATUS_FINISHED
resource.REQUEST_STATUS_ERROR_IO_ERROR
resource.REQUEST_STATUS_ERROR_NOT_FOUND
buffer
handle - a handle to the request
Load binary data from a custom project resource and update a texture resource:
function my_callback(self, request_id, result)
if result.status == resource.REQUEST_STATUS_FINISHED then
resource.set_texture("/my_texture", { ... }, result.buf)
end
end
local my_request = sys.load_buffer_async("/assets/my_level_data.bin", my_callback)
function my_callback(self, request_id, result)
if result.status ~= sys.REQUEST_STATUS_FINISHED then
-- uh oh! File could not be found, do something graceful
elseif request_id == self.first_asset then
-- result.buffer contains data from my_level_asset.bin
elif request_id == self.second_asset then
-- result.buffer contains data from 'my_level.bin'
end
end
function init(self)
self.first_asset = hash("folder_next_to_binary/my_level_asset.bin")
self.second_asset = hash("/some_absolute_path/my_level.bin")
self.first_request = sys.load_buffer_async(self.first_asset, my_callback)
self.second_request = sys.load_buffer_async(self.second_asset, my_callback)
end
an asyncronous request has finished successfully
an asyncronous request is unable to read the resource
an asyncronous request is unable to locate the resource