mirror of
https://github.com/minetest/minetest.git
synced 2024-12-23 22:52:25 +01:00
[CSM] sound_play & sound_stop support + client_lua_api doc (#5096)
* squashed: CSM: Implement register_globalstep * Re-use fatal error mechanism from server to disconnect client on CSM error * Little client functions cleanups * squashed: CSM: add core.after function * core.after is shared code between client & server * ModApiUtil get_us_time feature enabled for client
This commit is contained in:
parent
d7bc346981
commit
2c19d51409
@ -4,9 +4,10 @@ local clientpath = scriptpath.."client"..DIR_DELIM
|
|||||||
local commonpath = scriptpath.."common"..DIR_DELIM
|
local commonpath = scriptpath.."common"..DIR_DELIM
|
||||||
|
|
||||||
dofile(clientpath .. "register.lua")
|
dofile(clientpath .. "register.lua")
|
||||||
|
dofile(commonpath .. "after.lua")
|
||||||
|
dofile(commonpath .. "chatcommands.lua")
|
||||||
dofile(clientpath .. "preview.lua")
|
dofile(clientpath .. "preview.lua")
|
||||||
|
|
||||||
core.register_on_death(function()
|
core.register_on_death(function()
|
||||||
core.display_chat_message("You died.")
|
core.display_chat_message("You died.")
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
-- This is an example function to ensure it's working properly, should be removed before merge
|
-- This is an example function to ensure it's working properly, should be removed before merge
|
||||||
core.register_on_shutdown(function()
|
core.register_on_shutdown(function()
|
||||||
print("shutdown client")
|
print("[PREVIEW] shutdown client")
|
||||||
end)
|
end)
|
||||||
|
|
||||||
-- This is an example function to ensure it's working properly, should be removed before merge
|
-- This is an example function to ensure it's working properly, should be removed before merge
|
||||||
@ -15,17 +15,28 @@ core.register_on_sending_chat_messages(function(message)
|
|||||||
return false
|
return false
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
-- This is an example function to ensure it's working properly, should be removed before merge
|
||||||
core.register_on_hp_modification(function(hp)
|
core.register_on_hp_modification(function(hp)
|
||||||
print("[PREVIEW] HP modified " .. hp)
|
print("[PREVIEW] HP modified " .. hp)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
-- This is an example function to ensure it's working properly, should be removed before merge
|
||||||
core.register_on_damage_taken(function(hp)
|
core.register_on_damage_taken(function(hp)
|
||||||
print("[PREVIEW] Damage taken " .. hp)
|
print("[PREVIEW] Damage taken " .. hp)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
-- This is an example function to ensure it's working properly, should be removed before merge
|
||||||
|
core.register_globalstep(function(dtime)
|
||||||
|
-- print("[PREVIEW] globalstep " .. dtime)
|
||||||
|
end)
|
||||||
|
|
||||||
-- This is an example function to ensure it's working properly, should be removed before merge
|
-- This is an example function to ensure it's working properly, should be removed before merge
|
||||||
core.register_chatcommand("dump", {
|
core.register_chatcommand("dump", {
|
||||||
func = function(name, param)
|
func = function(name, param)
|
||||||
return true, dump(_G)
|
return true, dump(_G)
|
||||||
end,
|
end,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
core.after(2, function()
|
||||||
|
print("After 2")
|
||||||
|
end)
|
||||||
|
@ -55,6 +55,7 @@ local function make_registration()
|
|||||||
return t, registerfunc
|
return t, registerfunc
|
||||||
end
|
end
|
||||||
|
|
||||||
|
core.registered_globalsteps, core.register_globalstep = make_registration()
|
||||||
core.registered_on_shutdown, core.register_on_shutdown = make_registration()
|
core.registered_on_shutdown, core.register_on_shutdown = make_registration()
|
||||||
core.registered_on_receiving_chat_messages, core.register_on_receiving_chat_messages = make_registration()
|
core.registered_on_receiving_chat_messages, core.register_on_receiving_chat_messages = make_registration()
|
||||||
core.registered_on_sending_chat_messages, core.register_on_sending_chat_messages = make_registration()
|
core.registered_on_sending_chat_messages, core.register_on_sending_chat_messages = make_registration()
|
||||||
|
43
builtin/common/after.lua
Normal file
43
builtin/common/after.lua
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
local jobs = {}
|
||||||
|
local time = 0.0
|
||||||
|
local last = core.get_us_time() / 1000000
|
||||||
|
|
||||||
|
core.register_globalstep(function(dtime)
|
||||||
|
local new = core.get_us_time() / 1000000
|
||||||
|
if new > last then
|
||||||
|
time = time + (new - last)
|
||||||
|
else
|
||||||
|
-- Overflow, we may lose a little bit of time here but
|
||||||
|
-- only 1 tick max, potentially running timers slightly
|
||||||
|
-- too early.
|
||||||
|
time = time + new
|
||||||
|
end
|
||||||
|
last = new
|
||||||
|
|
||||||
|
if #jobs < 1 then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Iterate backwards so that we miss any new timers added by
|
||||||
|
-- a timer callback, and so that we don't skip the next timer
|
||||||
|
-- in the list if we remove one.
|
||||||
|
for i = #jobs, 1, -1 do
|
||||||
|
local job = jobs[i]
|
||||||
|
if time >= job.expire then
|
||||||
|
core.set_last_run_mod(job.mod_origin)
|
||||||
|
job.func(unpack(job.arg))
|
||||||
|
table.remove(jobs, i)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
function core.after(after, func, ...)
|
||||||
|
assert(tonumber(after) and type(func) == "function",
|
||||||
|
"Invalid core.after invocation")
|
||||||
|
jobs[#jobs + 1] = {
|
||||||
|
func = func,
|
||||||
|
expire = time + after,
|
||||||
|
arg = {...},
|
||||||
|
mod_origin = core.get_last_run_mod()
|
||||||
|
}
|
||||||
|
end
|
@ -17,6 +17,7 @@ if core.setting_getbool("profiler.load") then
|
|||||||
profiler = dofile(scriptpath.."profiler"..DIR_DELIM.."init.lua")
|
profiler = dofile(scriptpath.."profiler"..DIR_DELIM.."init.lua")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
dofile(commonpath .. "after.lua")
|
||||||
dofile(gamepath.."item_entity.lua")
|
dofile(gamepath.."item_entity.lua")
|
||||||
dofile(gamepath.."deprecated.lua")
|
dofile(gamepath.."deprecated.lua")
|
||||||
dofile(gamepath.."misc.lua")
|
dofile(gamepath.."misc.lua")
|
||||||
|
@ -4,50 +4,6 @@
|
|||||||
-- Misc. API functions
|
-- Misc. API functions
|
||||||
--
|
--
|
||||||
|
|
||||||
local jobs = {}
|
|
||||||
local time = 0.0
|
|
||||||
local last = core.get_us_time() / 1000000
|
|
||||||
|
|
||||||
core.register_globalstep(function(dtime)
|
|
||||||
local new = core.get_us_time() / 1000000
|
|
||||||
if new > last then
|
|
||||||
time = time + (new - last)
|
|
||||||
else
|
|
||||||
-- Overflow, we may lose a little bit of time here but
|
|
||||||
-- only 1 tick max, potentially running timers slightly
|
|
||||||
-- too early.
|
|
||||||
time = time + new
|
|
||||||
end
|
|
||||||
last = new
|
|
||||||
|
|
||||||
if #jobs < 1 then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Iterate backwards so that we miss any new timers added by
|
|
||||||
-- a timer callback, and so that we don't skip the next timer
|
|
||||||
-- in the list if we remove one.
|
|
||||||
for i = #jobs, 1, -1 do
|
|
||||||
local job = jobs[i]
|
|
||||||
if time >= job.expire then
|
|
||||||
core.set_last_run_mod(job.mod_origin)
|
|
||||||
job.func(unpack(job.arg))
|
|
||||||
table.remove(jobs, i)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
|
|
||||||
function core.after(after, func, ...)
|
|
||||||
assert(tonumber(after) and type(func) == "function",
|
|
||||||
"Invalid core.after invocation")
|
|
||||||
jobs[#jobs + 1] = {
|
|
||||||
func = func,
|
|
||||||
expire = time + after,
|
|
||||||
arg = {...},
|
|
||||||
mod_origin = core.get_last_run_mod()
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
function core.check_player_privs(name, ...)
|
function core.check_player_privs(name, ...)
|
||||||
local arg_type = type(name)
|
local arg_type = type(name)
|
||||||
if (arg_type == "userdata" or arg_type == "table") and
|
if (arg_type == "userdata" or arg_type == "table") and
|
||||||
|
787
doc/client_lua_api.txt
Normal file
787
doc/client_lua_api.txt
Normal file
@ -0,0 +1,787 @@
|
|||||||
|
Minetest Lua Modding API Reference 0.4.15
|
||||||
|
=========================================
|
||||||
|
* More information at <http://www.minetest.net/>
|
||||||
|
* Developer Wiki: <http://dev.minetest.net/>
|
||||||
|
|
||||||
|
Introduction
|
||||||
|
------------
|
||||||
|
Content and functionality can be added to Minetest 0.4 by using Lua
|
||||||
|
scripting in run-time loaded mods.
|
||||||
|
|
||||||
|
A mod is a self-contained bunch of scripts, textures and other related
|
||||||
|
things that is loaded by and interfaces with Minetest.
|
||||||
|
|
||||||
|
Mods are contained and ran solely on the server side. Definitions and media
|
||||||
|
files are automatically transferred to the client.
|
||||||
|
|
||||||
|
If you see a deficiency in the API, feel free to attempt to add the
|
||||||
|
functionality in the engine and API. You can send such improvements as
|
||||||
|
source code patches on GitHub (https://github.com/minetest/minetest).
|
||||||
|
|
||||||
|
Programming in Lua
|
||||||
|
------------------
|
||||||
|
If you have any difficulty in understanding this, please read
|
||||||
|
[Programming in Lua](http://www.lua.org/pil/).
|
||||||
|
|
||||||
|
Startup
|
||||||
|
-------
|
||||||
|
Mods are loaded during client startup from the mod load paths by running
|
||||||
|
the `init.lua` scripts in a shared environment.
|
||||||
|
|
||||||
|
Paths
|
||||||
|
-----
|
||||||
|
* `RUN_IN_PLACE=1` (Windows release, local build)
|
||||||
|
* `$path_user`:
|
||||||
|
* Linux: `<build directory>`
|
||||||
|
* Windows: `<build directory>`
|
||||||
|
* `$path_share`
|
||||||
|
* Linux: `<build directory>`
|
||||||
|
* Windows: `<build directory>`
|
||||||
|
* `RUN_IN_PLACE=0`: (Linux release)
|
||||||
|
* `$path_share`
|
||||||
|
* Linux: `/usr/share/minetest`
|
||||||
|
* Windows: `<install directory>/minetest-0.4.x`
|
||||||
|
* `$path_user`:
|
||||||
|
* Linux: `$HOME/.minetest`
|
||||||
|
* Windows: `C:/users/<user>/AppData/minetest` (maybe)
|
||||||
|
|
||||||
|
Mod load path
|
||||||
|
-------------
|
||||||
|
Generic:
|
||||||
|
|
||||||
|
* `$path_share/clientmods/`
|
||||||
|
* `$path_user/clientmods/` (User-installed mods)
|
||||||
|
|
||||||
|
In a run-in-place version (e.g. the distributed windows version):
|
||||||
|
|
||||||
|
* `minetest-0.4.x/clientmods/` (User-installed mods)
|
||||||
|
|
||||||
|
On an installed version on Linux:
|
||||||
|
|
||||||
|
* `/usr/share/minetest/clientmods/`
|
||||||
|
* `$HOME/.minetest/clientmods/` (User-installed mods)
|
||||||
|
|
||||||
|
Modpack support
|
||||||
|
----------------
|
||||||
|
Mods can be put in a subdirectory, if the parent directory, which otherwise
|
||||||
|
should be a mod, contains a file named `modpack.txt`. This file shall be
|
||||||
|
empty, except for lines starting with `#`, which are comments.
|
||||||
|
|
||||||
|
Mod directory structure
|
||||||
|
------------------------
|
||||||
|
|
||||||
|
mods
|
||||||
|
|-- modname
|
||||||
|
| |-- depends.txt
|
||||||
|
| |-- screenshot.png
|
||||||
|
| |-- description.txt
|
||||||
|
| |-- settingtypes.txt
|
||||||
|
| |-- init.lua
|
||||||
|
| |-- models
|
||||||
|
| |-- textures
|
||||||
|
| | |-- modname_stuff.png
|
||||||
|
| | `-- modname_something_else.png
|
||||||
|
| |-- sounds
|
||||||
|
| |-- media
|
||||||
|
| `-- <custom data>
|
||||||
|
`-- another
|
||||||
|
|
||||||
|
|
||||||
|
### modname
|
||||||
|
The location of this directory can be fetched by using
|
||||||
|
`minetest.get_modpath(modname)`.
|
||||||
|
|
||||||
|
### `depends.txt`
|
||||||
|
List of mods that have to be loaded before loading this mod.
|
||||||
|
|
||||||
|
A single line contains a single modname.
|
||||||
|
|
||||||
|
Optional dependencies can be defined by appending a question mark
|
||||||
|
to a single modname. Their meaning is that if the specified mod
|
||||||
|
is missing, that does not prevent this mod from being loaded.
|
||||||
|
|
||||||
|
### `screenshot.png`
|
||||||
|
A screenshot shown in the mod manager within the main menu. It should
|
||||||
|
have an aspect ratio of 3:2 and a minimum size of 300×200 pixels.
|
||||||
|
|
||||||
|
### `description.txt`
|
||||||
|
A File containing description to be shown within mainmenu.
|
||||||
|
|
||||||
|
### `settingtypes.txt`
|
||||||
|
A file in the same format as the one in builtin. It will be parsed by the
|
||||||
|
settings menu and the settings will be displayed in the "Mods" category.
|
||||||
|
|
||||||
|
### `init.lua`
|
||||||
|
The main Lua script. Running this script should register everything it
|
||||||
|
wants to register. Subsequent execution depends on minetest calling the
|
||||||
|
registered callbacks.
|
||||||
|
|
||||||
|
`minetest.setting_get(name)` and `minetest.setting_getbool(name)` can be used
|
||||||
|
to read custom or existing settings at load time, if necessary.
|
||||||
|
|
||||||
|
### `sounds`
|
||||||
|
Media files (sounds) that will be transferred to the
|
||||||
|
client and will be available for use by the mod.
|
||||||
|
|
||||||
|
Naming convention for registered textual names
|
||||||
|
----------------------------------------------
|
||||||
|
Registered names should generally be in this format:
|
||||||
|
|
||||||
|
"modname:<whatever>" (<whatever> can have characters a-zA-Z0-9_)
|
||||||
|
|
||||||
|
This is to prevent conflicting names from corrupting maps and is
|
||||||
|
enforced by the mod loader.
|
||||||
|
|
||||||
|
### Example
|
||||||
|
In the mod `experimental`, there is the ideal item/node/entity name `tnt`.
|
||||||
|
So the name should be `experimental:tnt`.
|
||||||
|
|
||||||
|
Enforcement can be overridden by prefixing the name with `:`. This can
|
||||||
|
be used for overriding the registrations of some other mod.
|
||||||
|
|
||||||
|
Example: Any mod can redefine `experimental:tnt` by using the name
|
||||||
|
|
||||||
|
:experimental:tnt
|
||||||
|
|
||||||
|
when registering it.
|
||||||
|
(also that mod is required to have `experimental` as a dependency)
|
||||||
|
|
||||||
|
The `:` prefix can also be used for maintaining backwards compatibility.
|
||||||
|
|
||||||
|
### Aliases
|
||||||
|
Aliases can be added by using `minetest.register_alias(name, convert_to)` or
|
||||||
|
`minetest.register_alias_force(name, convert_to).
|
||||||
|
|
||||||
|
This will make Minetest to convert things called name to things called
|
||||||
|
`convert_to`.
|
||||||
|
|
||||||
|
The only difference between `minetest.register_alias` and
|
||||||
|
`minetest.register_alias_force` is that if an item called `name` exists,
|
||||||
|
`minetest.register_alias` will do nothing while
|
||||||
|
`minetest.register_alias_force` will unregister it.
|
||||||
|
|
||||||
|
This can be used for maintaining backwards compatibility.
|
||||||
|
|
||||||
|
This can be also used for setting quick access names for things, e.g. if
|
||||||
|
you have an item called `epiclylongmodname:stuff`, you could do
|
||||||
|
|
||||||
|
minetest.register_alias("stuff", "epiclylongmodname:stuff")
|
||||||
|
|
||||||
|
and be able to use `/giveme stuff`.
|
||||||
|
|
||||||
|
Sounds
|
||||||
|
------
|
||||||
|
Only Ogg Vorbis files are supported.
|
||||||
|
|
||||||
|
For positional playing of sounds, only single-channel (mono) files are
|
||||||
|
supported. Otherwise OpenAL will play them non-positionally.
|
||||||
|
|
||||||
|
Mods should generally prefix their sounds with `modname_`, e.g. given
|
||||||
|
the mod name "`foomod`", a sound could be called:
|
||||||
|
|
||||||
|
foomod_foosound.ogg
|
||||||
|
|
||||||
|
Sounds are referred to by their name with a dot, a single digit and the
|
||||||
|
file extension stripped out. When a sound is played, the actual sound file
|
||||||
|
is chosen randomly from the matching sounds.
|
||||||
|
|
||||||
|
When playing the sound `foomod_foosound`, the sound is chosen randomly
|
||||||
|
from the available ones of the following files:
|
||||||
|
|
||||||
|
* `foomod_foosound.ogg`
|
||||||
|
* `foomod_foosound.0.ogg`
|
||||||
|
* `foomod_foosound.1.ogg`
|
||||||
|
* (...)
|
||||||
|
* `foomod_foosound.9.ogg`
|
||||||
|
|
||||||
|
Examples of sound parameter tables:
|
||||||
|
|
||||||
|
-- Play locationless on all clients
|
||||||
|
{
|
||||||
|
gain = 1.0, -- default
|
||||||
|
}
|
||||||
|
-- Play locationless to one player
|
||||||
|
{
|
||||||
|
to_player = name,
|
||||||
|
gain = 1.0, -- default
|
||||||
|
}
|
||||||
|
-- Play locationless to one player, looped
|
||||||
|
{
|
||||||
|
to_player = name,
|
||||||
|
gain = 1.0, -- default
|
||||||
|
loop = true,
|
||||||
|
}
|
||||||
|
-- Play in a location
|
||||||
|
{
|
||||||
|
pos = {x = 1, y = 2, z = 3},
|
||||||
|
gain = 1.0, -- default
|
||||||
|
max_hear_distance = 32, -- default, uses an euclidean metric
|
||||||
|
}
|
||||||
|
-- Play connected to an object, looped
|
||||||
|
{
|
||||||
|
object = <an ObjectRef>,
|
||||||
|
gain = 1.0, -- default
|
||||||
|
max_hear_distance = 32, -- default, uses an euclidean metric
|
||||||
|
loop = true,
|
||||||
|
}
|
||||||
|
|
||||||
|
Looped sounds must either be connected to an object or played locationless to
|
||||||
|
one player using `to_player = name,`
|
||||||
|
|
||||||
|
### `SimpleSoundSpec`
|
||||||
|
* e.g. `""`
|
||||||
|
* e.g. `"default_place_node"`
|
||||||
|
* e.g. `{}`
|
||||||
|
* e.g. `{name = "default_place_node"}`
|
||||||
|
* e.g. `{name = "default_place_node", gain = 1.0}`
|
||||||
|
|
||||||
|
Representations of simple things
|
||||||
|
--------------------------------
|
||||||
|
|
||||||
|
### Position/vector
|
||||||
|
|
||||||
|
{x=num, y=num, z=num}
|
||||||
|
|
||||||
|
For helper functions see "Vector helpers".
|
||||||
|
|
||||||
|
### `pointed_thing`
|
||||||
|
* `{type="nothing"}`
|
||||||
|
* `{type="node", under=pos, above=pos}`
|
||||||
|
* `{type="object", ref=ObjectRef}`
|
||||||
|
|
||||||
|
Flag Specifier Format
|
||||||
|
---------------------
|
||||||
|
Flags using the standardized flag specifier format can be specified in either of
|
||||||
|
two ways, by string or table.
|
||||||
|
|
||||||
|
The string format is a comma-delimited set of flag names; whitespace and
|
||||||
|
unrecognized flag fields are ignored. Specifying a flag in the string sets the
|
||||||
|
flag, and specifying a flag prefixed by the string `"no"` explicitly
|
||||||
|
clears the flag from whatever the default may be.
|
||||||
|
|
||||||
|
In addition to the standard string flag format, the schematic flags field can
|
||||||
|
also be a table of flag names to boolean values representing whether or not the
|
||||||
|
flag is set. Additionally, if a field with the flag name prefixed with `"no"`
|
||||||
|
is present, mapped to a boolean of any value, the specified flag is unset.
|
||||||
|
|
||||||
|
E.g. A flag field of value
|
||||||
|
|
||||||
|
{place_center_x = true, place_center_y=false, place_center_z=true}
|
||||||
|
|
||||||
|
is equivalent to
|
||||||
|
|
||||||
|
{place_center_x = true, noplace_center_y=true, place_center_z=true}
|
||||||
|
|
||||||
|
which is equivalent to
|
||||||
|
|
||||||
|
"place_center_x, noplace_center_y, place_center_z"
|
||||||
|
|
||||||
|
or even
|
||||||
|
|
||||||
|
"place_center_x, place_center_z"
|
||||||
|
|
||||||
|
since, by default, no schematic attributes are set.
|
||||||
|
|
||||||
|
Formspec
|
||||||
|
--------
|
||||||
|
Formspec defines a menu. Currently not much else than inventories are
|
||||||
|
supported. It is a string, with a somewhat strange format.
|
||||||
|
|
||||||
|
Spaces and newlines can be inserted between the blocks, as is used in the
|
||||||
|
examples.
|
||||||
|
|
||||||
|
### Examples
|
||||||
|
|
||||||
|
#### Chest
|
||||||
|
|
||||||
|
size[8,9]
|
||||||
|
list[context;main;0,0;8,4;]
|
||||||
|
list[current_player;main;0,5;8,4;]
|
||||||
|
|
||||||
|
#### Furnace
|
||||||
|
|
||||||
|
size[8,9]
|
||||||
|
list[context;fuel;2,3;1,1;]
|
||||||
|
list[context;src;2,1;1,1;]
|
||||||
|
list[context;dst;5,1;2,2;]
|
||||||
|
list[current_player;main;0,5;8,4;]
|
||||||
|
|
||||||
|
#### Minecraft-like player inventory
|
||||||
|
|
||||||
|
size[8,7.5]
|
||||||
|
image[1,0.6;1,2;player.png]
|
||||||
|
list[current_player;main;0,3.5;8,4;]
|
||||||
|
list[current_player;craft;3,0;3,3;]
|
||||||
|
list[current_player;craftpreview;7,1;1,1;]
|
||||||
|
|
||||||
|
### Elements
|
||||||
|
|
||||||
|
#### `size[<W>,<H>,<fixed_size>]`
|
||||||
|
* Define the size of the menu in inventory slots
|
||||||
|
* `fixed_size`: `true`/`false` (optional)
|
||||||
|
* deprecated: `invsize[<W>,<H>;]`
|
||||||
|
|
||||||
|
#### `container[<X>,<Y>]`
|
||||||
|
* Start of a container block, moves all physical elements in the container by (X, Y)
|
||||||
|
* Must have matching container_end
|
||||||
|
* Containers can be nested, in which case the offsets are added
|
||||||
|
(child containers are relative to parent containers)
|
||||||
|
|
||||||
|
#### `container_end[]`
|
||||||
|
* End of a container, following elements are no longer relative to this container
|
||||||
|
|
||||||
|
#### `list[<inventory location>;<list name>;<X>,<Y>;<W>,<H>;]`
|
||||||
|
* Show an inventory list
|
||||||
|
|
||||||
|
#### `list[<inventory location>;<list name>;<X>,<Y>;<W>,<H>;<starting item index>]`
|
||||||
|
* Show an inventory list
|
||||||
|
|
||||||
|
#### `listring[<inventory location>;<list name>]`
|
||||||
|
* Allows to create a ring of inventory lists
|
||||||
|
* Shift-clicking on items in one element of the ring
|
||||||
|
will send them to the next inventory list inside the ring
|
||||||
|
* The first occurrence of an element inside the ring will
|
||||||
|
determine the inventory where items will be sent to
|
||||||
|
|
||||||
|
#### `listring[]`
|
||||||
|
* Shorthand for doing `listring[<inventory location>;<list name>]`
|
||||||
|
for the last two inventory lists added by list[...]
|
||||||
|
|
||||||
|
#### `listcolors[<slot_bg_normal>;<slot_bg_hover>]`
|
||||||
|
* Sets background color of slots as `ColorString`
|
||||||
|
* Sets background color of slots on mouse hovering
|
||||||
|
|
||||||
|
#### `listcolors[<slot_bg_normal>;<slot_bg_hover>;<slot_border>]`
|
||||||
|
* Sets background color of slots as `ColorString`
|
||||||
|
* Sets background color of slots on mouse hovering
|
||||||
|
* Sets color of slots border
|
||||||
|
|
||||||
|
#### `listcolors[<slot_bg_normal>;<slot_bg_hover>;<slot_border>;<tooltip_bgcolor>;<tooltip_fontcolor>]`
|
||||||
|
* Sets background color of slots as `ColorString`
|
||||||
|
* Sets background color of slots on mouse hovering
|
||||||
|
* Sets color of slots border
|
||||||
|
* Sets default background color of tooltips
|
||||||
|
* Sets default font color of tooltips
|
||||||
|
|
||||||
|
#### `tooltip[<gui_element_name>;<tooltip_text>;<bgcolor>,<fontcolor>]`
|
||||||
|
* Adds tooltip for an element
|
||||||
|
* `<bgcolor>` tooltip background color as `ColorString` (optional)
|
||||||
|
* `<fontcolor>` tooltip font color as `ColorString` (optional)
|
||||||
|
|
||||||
|
#### `image[<X>,<Y>;<W>,<H>;<texture name>]`
|
||||||
|
* Show an image
|
||||||
|
* Position and size units are inventory slots
|
||||||
|
|
||||||
|
#### `item_image[<X>,<Y>;<W>,<H>;<item name>]`
|
||||||
|
* Show an inventory image of registered item/node
|
||||||
|
* Position and size units are inventory slots
|
||||||
|
|
||||||
|
#### `bgcolor[<color>;<fullscreen>]`
|
||||||
|
* Sets background color of formspec as `ColorString`
|
||||||
|
* If `true`, the background color is drawn fullscreen (does not effect the size of the formspec)
|
||||||
|
|
||||||
|
#### `background[<X>,<Y>;<W>,<H>;<texture name>]`
|
||||||
|
* Use a background. Inventory rectangles are not drawn then.
|
||||||
|
* Position and size units are inventory slots
|
||||||
|
* Example for formspec 8x4 in 16x resolution: image shall be sized
|
||||||
|
8 times 16px times 4 times 16px.
|
||||||
|
|
||||||
|
#### `background[<X>,<Y>;<W>,<H>;<texture name>;<auto_clip>]`
|
||||||
|
* Use a background. Inventory rectangles are not drawn then.
|
||||||
|
* Position and size units are inventory slots
|
||||||
|
* Example for formspec 8x4 in 16x resolution:
|
||||||
|
image shall be sized 8 times 16px times 4 times 16px
|
||||||
|
* If `true` the background is clipped to formspec size
|
||||||
|
(`x` and `y` are used as offset values, `w` and `h` are ignored)
|
||||||
|
|
||||||
|
#### `pwdfield[<X>,<Y>;<W>,<H>;<name>;<label>]`
|
||||||
|
* Textual password style field; will be sent to server when a button is clicked
|
||||||
|
* When enter is pressed in field, fields.key_enter_field will be sent with the name
|
||||||
|
of this field.
|
||||||
|
* `x` and `y` position the field relative to the top left of the menu
|
||||||
|
* `w` and `h` are the size of the field
|
||||||
|
* Fields are a set height, but will be vertically centred on `h`
|
||||||
|
* Position and size units are inventory slots
|
||||||
|
* `name` is the name of the field as returned in fields to `on_receive_fields`
|
||||||
|
* `label`, if not blank, will be text printed on the top left above the field
|
||||||
|
* See field_close_on_enter to stop enter closing the formspec
|
||||||
|
|
||||||
|
#### `field[<X>,<Y>;<W>,<H>;<name>;<label>;<default>]`
|
||||||
|
* Textual field; will be sent to server when a button is clicked
|
||||||
|
* When enter is pressed in field, fields.key_enter_field will be sent with the name
|
||||||
|
of this field.
|
||||||
|
* `x` and `y` position the field relative to the top left of the menu
|
||||||
|
* `w` and `h` are the size of the field
|
||||||
|
* Fields are a set height, but will be vertically centred on `h`
|
||||||
|
* Position and size units are inventory slots
|
||||||
|
* `name` is the name of the field as returned in fields to `on_receive_fields`
|
||||||
|
* `label`, if not blank, will be text printed on the top left above the field
|
||||||
|
* `default` is the default value of the field
|
||||||
|
* `default` may contain variable references such as `${text}'` which
|
||||||
|
will fill the value from the metadata value `text`
|
||||||
|
* **Note**: no extra text or more than a single variable is supported ATM.
|
||||||
|
* See field_close_on_enter to stop enter closing the formspec
|
||||||
|
|
||||||
|
#### `field[<name>;<label>;<default>]`
|
||||||
|
* As above, but without position/size units
|
||||||
|
* When enter is pressed in field, fields.key_enter_field will be sent with the name
|
||||||
|
of this field.
|
||||||
|
* Special field for creating simple forms, such as sign text input
|
||||||
|
* Must be used without a `size[]` element
|
||||||
|
* A "Proceed" button will be added automatically
|
||||||
|
* See field_close_on_enter to stop enter closing the formspec
|
||||||
|
|
||||||
|
#### `field_close_on_enter[<name>;<close_on_enter>]`
|
||||||
|
* <name> is the name of the field
|
||||||
|
* if <close_on_enter> is false, pressing enter in the field will submit the form but not close it
|
||||||
|
* defaults to true when not specified (ie: no tag for a field)
|
||||||
|
|
||||||
|
#### `textarea[<X>,<Y>;<W>,<H>;<name>;<label>;<default>]`
|
||||||
|
* Same as fields above, but with multi-line input
|
||||||
|
|
||||||
|
#### `label[<X>,<Y>;<label>]`
|
||||||
|
* `x` and `y` work as per field
|
||||||
|
* `label` is the text on the label
|
||||||
|
* Position and size units are inventory slots
|
||||||
|
|
||||||
|
#### `vertlabel[<X>,<Y>;<label>]`
|
||||||
|
* Textual label drawn vertically
|
||||||
|
* `x` and `y` work as per field
|
||||||
|
* `label` is the text on the label
|
||||||
|
* Position and size units are inventory slots
|
||||||
|
|
||||||
|
#### `button[<X>,<Y>;<W>,<H>;<name>;<label>]`
|
||||||
|
* Clickable button. When clicked, fields will be sent.
|
||||||
|
* `x`, `y` and `name` work as per field
|
||||||
|
* `w` and `h` are the size of the button
|
||||||
|
* `label` is the text on the button
|
||||||
|
* Position and size units are inventory slots
|
||||||
|
|
||||||
|
#### `image_button[<X>,<Y>;<W>,<H>;<texture name>;<name>;<label>]`
|
||||||
|
* `x`, `y`, `w`, `h`, and `name` work as per button
|
||||||
|
* `texture name` is the filename of an image
|
||||||
|
* Position and size units are inventory slots
|
||||||
|
|
||||||
|
#### `image_button[<X>,<Y>;<W>,<H>;<texture name>;<name>;<label>;<noclip>;<drawborder>;<pressed texture name>]`
|
||||||
|
* `x`, `y`, `w`, `h`, and `name` work as per button
|
||||||
|
* `texture name` is the filename of an image
|
||||||
|
* Position and size units are inventory slots
|
||||||
|
* `noclip=true` means the image button doesn't need to be within specified formsize
|
||||||
|
* `drawborder`: draw button border or not
|
||||||
|
* `pressed texture name` is the filename of an image on pressed state
|
||||||
|
|
||||||
|
#### `item_image_button[<X>,<Y>;<W>,<H>;<item name>;<name>;<label>]`
|
||||||
|
* `x`, `y`, `w`, `h`, `name` and `label` work as per button
|
||||||
|
* `item name` is the registered name of an item/node,
|
||||||
|
tooltip will be made out of its description
|
||||||
|
to override it use tooltip element
|
||||||
|
* Position and size units are inventory slots
|
||||||
|
|
||||||
|
#### `button_exit[<X>,<Y>;<W>,<H>;<name>;<label>]`
|
||||||
|
* When clicked, fields will be sent and the form will quit.
|
||||||
|
|
||||||
|
#### `image_button_exit[<X>,<Y>;<W>,<H>;<texture name>;<name>;<label>]`
|
||||||
|
* When clicked, fields will be sent and the form will quit.
|
||||||
|
|
||||||
|
#### `textlist[<X>,<Y>;<W>,<H>;<name>;<listelem 1>,<listelem 2>,...,<listelem n>]`
|
||||||
|
* Scrollable item list showing arbitrary text elements
|
||||||
|
* `x` and `y` position the itemlist relative to the top left of the menu
|
||||||
|
* `w` and `h` are the size of the itemlist
|
||||||
|
* `name` fieldname sent to server on doubleclick value is current selected element
|
||||||
|
* `listelements` can be prepended by #color in hexadecimal format RRGGBB (only),
|
||||||
|
* if you want a listelement to start with "#" write "##".
|
||||||
|
|
||||||
|
#### `textlist[<X>,<Y>;<W>,<H>;<name>;<listelem 1>,<listelem 2>,...,<listelem n>;<selected idx>;<transparent>]`
|
||||||
|
* Scrollable itemlist showing arbitrary text elements
|
||||||
|
* `x` and `y` position the item list relative to the top left of the menu
|
||||||
|
* `w` and `h` are the size of the item list
|
||||||
|
* `name` fieldname sent to server on doubleclick value is current selected element
|
||||||
|
* `listelements` can be prepended by #RRGGBB (only) in hexadecimal format
|
||||||
|
* if you want a listelement to start with "#" write "##"
|
||||||
|
* Index to be selected within textlist
|
||||||
|
* `true`/`false`: draw transparent background
|
||||||
|
* See also `minetest.explode_textlist_event` (main menu: `engine.explode_textlist_event`)
|
||||||
|
|
||||||
|
#### `tabheader[<X>,<Y>;<name>;<caption 1>,<caption 2>,...,<caption n>;<current_tab>;<transparent>;<draw_border>]`
|
||||||
|
* Show a tab**header** at specific position (ignores formsize)
|
||||||
|
* `x` and `y` position the itemlist relative to the top left of the menu
|
||||||
|
* `name` fieldname data is transferred to Lua
|
||||||
|
* `caption 1`...: name shown on top of tab
|
||||||
|
* `current_tab`: index of selected tab 1...
|
||||||
|
* `transparent` (optional): show transparent
|
||||||
|
* `draw_border` (optional): draw border
|
||||||
|
|
||||||
|
#### `box[<X>,<Y>;<W>,<H>;<color>]`
|
||||||
|
* Simple colored semitransparent box
|
||||||
|
* `x` and `y` position the box relative to the top left of the menu
|
||||||
|
* `w` and `h` are the size of box
|
||||||
|
* `color` is color specified as a `ColorString`
|
||||||
|
|
||||||
|
#### `dropdown[<X>,<Y>;<W>;<name>;<item 1>,<item 2>, ...,<item n>;<selected idx>]`
|
||||||
|
* Show a dropdown field
|
||||||
|
* **Important note**: There are two different operation modes:
|
||||||
|
1. handle directly on change (only changed dropdown is submitted)
|
||||||
|
2. read the value on pressing a button (all dropdown values are available)
|
||||||
|
* `x` and `y` position of dropdown
|
||||||
|
* Width of dropdown
|
||||||
|
* Fieldname data is transferred to Lua
|
||||||
|
* Items to be shown in dropdown
|
||||||
|
* Index of currently selected dropdown item
|
||||||
|
|
||||||
|
#### `checkbox[<X>,<Y>;<name>;<label>;<selected>]`
|
||||||
|
* Show a checkbox
|
||||||
|
* `x` and `y`: position of checkbox
|
||||||
|
* `name` fieldname data is transferred to Lua
|
||||||
|
* `label` to be shown left of checkbox
|
||||||
|
* `selected` (optional): `true`/`false`
|
||||||
|
|
||||||
|
#### `scrollbar[<X>,<Y>;<W>,<H>;<orientation>;<name>;<value>]`
|
||||||
|
* Show a scrollbar
|
||||||
|
* There are two ways to use it:
|
||||||
|
1. handle the changed event (only changed scrollbar is available)
|
||||||
|
2. read the value on pressing a button (all scrollbars are available)
|
||||||
|
* `x` and `y`: position of trackbar
|
||||||
|
* `w` and `h`: width and height
|
||||||
|
* `orientation`: `vertical`/`horizontal`
|
||||||
|
* Fieldname data is transferred to Lua
|
||||||
|
* Value this trackbar is set to (`0`-`1000`)
|
||||||
|
* See also `minetest.explode_scrollbar_event` (main menu: `engine.explode_scrollbar_event`)
|
||||||
|
|
||||||
|
#### `table[<X>,<Y>;<W>,<H>;<name>;<cell 1>,<cell 2>,...,<cell n>;<selected idx>]`
|
||||||
|
* Show scrollable table using options defined by the previous `tableoptions[]`
|
||||||
|
* Displays cells as defined by the previous `tablecolumns[]`
|
||||||
|
* `x` and `y`: position the itemlist relative to the top left of the menu
|
||||||
|
* `w` and `h` are the size of the itemlist
|
||||||
|
* `name`: fieldname sent to server on row select or doubleclick
|
||||||
|
* `cell 1`...`cell n`: cell contents given in row-major order
|
||||||
|
* `selected idx`: index of row to be selected within table (first row = `1`)
|
||||||
|
* See also `minetest.explode_table_event` (main menu: `engine.explode_table_event`)
|
||||||
|
|
||||||
|
#### `tableoptions[<opt 1>;<opt 2>;...]`
|
||||||
|
* Sets options for `table[]`
|
||||||
|
* `color=#RRGGBB`
|
||||||
|
* default text color (`ColorString`), defaults to `#FFFFFF`
|
||||||
|
* `background=#RRGGBB`
|
||||||
|
* table background color (`ColorString`), defaults to `#000000`
|
||||||
|
* `border=<true/false>`
|
||||||
|
* should the table be drawn with a border? (default: `true`)
|
||||||
|
* `highlight=#RRGGBB`
|
||||||
|
* highlight background color (`ColorString`), defaults to `#466432`
|
||||||
|
* `highlight_text=#RRGGBB`
|
||||||
|
* highlight text color (`ColorString`), defaults to `#FFFFFF`
|
||||||
|
* `opendepth=<value>`
|
||||||
|
* all subtrees up to `depth < value` are open (default value = `0`)
|
||||||
|
* only useful when there is a column of type "tree"
|
||||||
|
|
||||||
|
#### `tablecolumns[<type 1>,<opt 1a>,<opt 1b>,...;<type 2>,<opt 2a>,<opt 2b>;...]`
|
||||||
|
* Sets columns for `table[]`
|
||||||
|
* Types: `text`, `image`, `color`, `indent`, `tree`
|
||||||
|
* `text`: show cell contents as text
|
||||||
|
* `image`: cell contents are an image index, use column options to define images
|
||||||
|
* `color`: cell contents are a ColorString and define color of following cell
|
||||||
|
* `indent`: cell contents are a number and define indentation of following cell
|
||||||
|
* `tree`: same as indent, but user can open and close subtrees (treeview-like)
|
||||||
|
* Column options:
|
||||||
|
* `align=<value>`
|
||||||
|
* for `text` and `image`: content alignment within cells.
|
||||||
|
Available values: `left` (default), `center`, `right`, `inline`
|
||||||
|
* `width=<value>`
|
||||||
|
* for `text` and `image`: minimum width in em (default: `0`)
|
||||||
|
* for `indent` and `tree`: indent width in em (default: `1.5`)
|
||||||
|
* `padding=<value>`: padding left of the column, in em (default `0.5`).
|
||||||
|
Exception: defaults to 0 for indent columns
|
||||||
|
* `tooltip=<value>`: tooltip text (default: empty)
|
||||||
|
* `image` column options:
|
||||||
|
* `0=<value>` sets image for image index 0
|
||||||
|
* `1=<value>` sets image for image index 1
|
||||||
|
* `2=<value>` sets image for image index 2
|
||||||
|
* and so on; defined indices need not be contiguous empty or
|
||||||
|
non-numeric cells are treated as `0`.
|
||||||
|
* `color` column options:
|
||||||
|
* `span=<value>`: number of following columns to affect (default: infinite)
|
||||||
|
|
||||||
|
**Note**: do _not_ use a element name starting with `key_`; those names are reserved to
|
||||||
|
pass key press events to formspec!
|
||||||
|
|
||||||
|
Spatial Vectors
|
||||||
|
---------------
|
||||||
|
* `vector.new(a[, b, c])`: returns a vector:
|
||||||
|
* A copy of `a` if `a` is a vector.
|
||||||
|
* `{x = a, y = b, z = c}`, if all `a, b, c` are defined
|
||||||
|
* `vector.direction(p1, p2)`: returns a vector
|
||||||
|
* `vector.distance(p1, p2)`: returns a number
|
||||||
|
* `vector.length(v)`: returns a number
|
||||||
|
* `vector.normalize(v)`: returns a vector
|
||||||
|
* `vector.floor(v)`: returns a vector, each dimension rounded down
|
||||||
|
* `vector.round(v)`: returns a vector, each dimension rounded to nearest int
|
||||||
|
* `vector.apply(v, func)`: returns a vector
|
||||||
|
* `vector.equals(v1, v2)`: returns a boolean
|
||||||
|
|
||||||
|
For the following functions `x` can be either a vector or a number:
|
||||||
|
|
||||||
|
* `vector.add(v, x)`: returns a vector
|
||||||
|
* `vector.subtract(v, x)`: returns a vector
|
||||||
|
* `vector.multiply(v, x)`: returns a scaled vector or Schur product
|
||||||
|
* `vector.divide(v, x)`: returns a scaled vector or Schur quotient
|
||||||
|
|
||||||
|
Helper functions
|
||||||
|
----------------
|
||||||
|
* `dump2(obj, name="_", dumped={})`
|
||||||
|
* Return object serialized as a string, handles reference loops
|
||||||
|
* `dump(obj, dumped={})`
|
||||||
|
* Return object serialized as a string
|
||||||
|
* `math.hypot(x, y)`
|
||||||
|
* Get the hypotenuse of a triangle with legs x and y.
|
||||||
|
Useful for distance calculation.
|
||||||
|
* `math.sign(x, tolerance)`
|
||||||
|
* Get the sign of a number.
|
||||||
|
Optional: Also returns `0` when the absolute value is within the tolerance (default: `0`)
|
||||||
|
* `string.split(str, separator=",", include_empty=false, max_splits=-1,
|
||||||
|
* sep_is_pattern=false)`
|
||||||
|
* If `max_splits` is negative, do not limit splits.
|
||||||
|
* `sep_is_pattern` specifies if separator is a plain string or a pattern (regex).
|
||||||
|
* e.g. `string:split("a,b", ",") == {"a","b"}`
|
||||||
|
* `string:trim()`
|
||||||
|
* e.g. `string.trim("\n \t\tfoo bar\t ") == "foo bar"`
|
||||||
|
* `minetest.is_yes(arg)`
|
||||||
|
* returns whether `arg` can be interpreted as yes
|
||||||
|
* `minetest.get_us_time()`
|
||||||
|
* returns time with microsecond precision. May not return wall time.
|
||||||
|
* `table.copy(table)`: returns a table
|
||||||
|
* returns a deep copy of `table`
|
||||||
|
|
||||||
|
`minetest` namespace reference
|
||||||
|
------------------------------
|
||||||
|
|
||||||
|
### Utilities
|
||||||
|
|
||||||
|
* `minetest.get_current_modname()`: returns the currently loading mod's name, when we are loading a mod
|
||||||
|
* `minetest.get_version()`: returns a table containing components of the
|
||||||
|
engine version. Components:
|
||||||
|
* `project`: Name of the project, eg, "Minetest"
|
||||||
|
* `string`: Simple version, eg, "1.2.3-dev"
|
||||||
|
* `hash`: Full git version (only set if available), eg, "1.2.3-dev-01234567-dirty"
|
||||||
|
Use this for informational purposes only. The information in the returned
|
||||||
|
table does not represent the capabilities of the engine, nor is it
|
||||||
|
reliable or verifyable. Compatible forks will have a different name and
|
||||||
|
version entirely. To check for the presence of engine features, test
|
||||||
|
whether the functions exported by the wanted features exist. For example:
|
||||||
|
`if core.nodeupdate then ... end`.
|
||||||
|
|
||||||
|
### Logging
|
||||||
|
* `minetest.debug(...)`
|
||||||
|
* Equivalent to `minetest.log(table.concat({...}, "\t"))`
|
||||||
|
* `minetest.log([level,] text)`
|
||||||
|
* `level` is one of `"none"`, `"error"`, `"warning"`, `"action"`,
|
||||||
|
`"info"`, or `"verbose"`. Default is `"none"`.
|
||||||
|
|
||||||
|
### Global callback registration functions
|
||||||
|
Call these functions only at load time!
|
||||||
|
|
||||||
|
* `minetest.register_globalstep(func(dtime))`
|
||||||
|
* Called every client environment step, usually interval of 0.1s
|
||||||
|
* `minetest.register_on_shutdown(func())`
|
||||||
|
* Called before client shutdown
|
||||||
|
* **Warning**: If the client terminates abnormally (i.e. crashes), the registered
|
||||||
|
callbacks **will likely not be run**. Data should be saved at
|
||||||
|
semi-frequent intervals as well as on server shutdown.
|
||||||
|
* `minetest.register_on_receiving_chat_message(func(name, message))`
|
||||||
|
* Called always when a client receive a message
|
||||||
|
* Return `true` to mark the message as handled, which means that it will not be shown to chat
|
||||||
|
* `minetest.register_on_sending_chat_message(func(name, message))`
|
||||||
|
* Called always when a client send a message from chat
|
||||||
|
* Return `true` to mark the message as handled, which means that it will not be sent to server
|
||||||
|
* `minetest.register_chatcommand(cmd, chatcommand definition)`
|
||||||
|
* Adds definition to minetest.registered_chatcommands
|
||||||
|
* `minetest.register_on_death(func())`
|
||||||
|
* Called when player die
|
||||||
|
* `minetest.register_on_hp_modification(func(hp))`
|
||||||
|
* Called when server modified player's HP
|
||||||
|
* `minetest.register_on_damage_taken(func(hp))`
|
||||||
|
* Called when player take damages
|
||||||
|
|
||||||
|
### Sounds
|
||||||
|
* `minetest.sound_play(spec, parameters)`: returns a handle
|
||||||
|
* `spec` is a `SimpleSoundSpec`
|
||||||
|
* `parameters` is a sound parameter table
|
||||||
|
* `minetest.sound_stop(handle)`
|
||||||
|
|
||||||
|
### Timing
|
||||||
|
* `minetest.after(time, func, ...)`
|
||||||
|
* Call the function `func` after `time` seconds, may be fractional
|
||||||
|
* Optional: Variable number of arguments that are passed to `func`
|
||||||
|
|
||||||
|
### Misc.
|
||||||
|
* `minetest.parse_json(string[, nullvalue])`: returns something
|
||||||
|
* Convert a string containing JSON data into the Lua equivalent
|
||||||
|
* `nullvalue`: returned in place of the JSON null; defaults to `nil`
|
||||||
|
* On success returns a table, a string, a number, a boolean or `nullvalue`
|
||||||
|
* On failure outputs an error message and returns `nil`
|
||||||
|
* Example: `parse_json("[10, {\"a\":false}]")`, returns `{10, {a = false}}`
|
||||||
|
* `minetest.write_json(data[, styled])`: returns a string or `nil` and an error message
|
||||||
|
* Convert a Lua table into a JSON string
|
||||||
|
* styled: Outputs in a human-readable format if this is set, defaults to false
|
||||||
|
* Unserializable things like functions and userdata are saved as null.
|
||||||
|
* **Warning**: JSON is more strict than the Lua table format.
|
||||||
|
1. You can only use strings and positive integers of at least one as keys.
|
||||||
|
2. You can not mix string and integer keys.
|
||||||
|
This is due to the fact that JSON has two distinct array and object values.
|
||||||
|
* Example: `write_json({10, {a = false}})`, returns `"[10, {\"a\": false}]"`
|
||||||
|
* `minetest.serialize(table)`: returns a string
|
||||||
|
* Convert a table containing tables, strings, numbers, booleans and `nil`s
|
||||||
|
into string form readable by `minetest.deserialize`
|
||||||
|
* Example: `serialize({foo='bar'})`, returns `'return { ["foo"] = "bar" }'`
|
||||||
|
* `minetest.deserialize(string)`: returns a table
|
||||||
|
* Convert a string returned by `minetest.deserialize` into a table
|
||||||
|
* `string` is loaded in an empty sandbox environment.
|
||||||
|
* Will load functions, but they cannot access the global environment.
|
||||||
|
* Example: `deserialize('return { ["foo"] = "bar" }')`, returns `{foo='bar'}`
|
||||||
|
* Example: `deserialize('print("foo")')`, returns `nil` (function call fails)
|
||||||
|
* `error:[string "print("foo")"]:1: attempt to call global 'print' (a nil value)`
|
||||||
|
* `minetest.compress(data, method, ...)`: returns `compressed_data`
|
||||||
|
* Compress a string of data.
|
||||||
|
* `method` is a string identifying the compression method to be used.
|
||||||
|
* Supported compression methods:
|
||||||
|
* Deflate (zlib): `"deflate"`
|
||||||
|
* `...` indicates method-specific arguments. Currently defined arguments are:
|
||||||
|
* Deflate: `level` - Compression level, `0`-`9` or `nil`.
|
||||||
|
* `minetest.decompress(compressed_data, method, ...)`: returns data
|
||||||
|
* Decompress a string of data (using ZLib).
|
||||||
|
* See documentation on `minetest.compress()` for supported compression methods.
|
||||||
|
* currently supported.
|
||||||
|
* `...` indicates method-specific arguments. Currently, no methods use this.
|
||||||
|
* `minetest.encode_base64(string)`: returns string encoded in base64
|
||||||
|
* Encodes a string in base64.
|
||||||
|
* `minetest.decode_base64(string)`: returns string
|
||||||
|
* Decodes a string encoded in base64.
|
||||||
|
|
||||||
|
Class reference
|
||||||
|
---------------
|
||||||
|
|
||||||
|
### `Settings`
|
||||||
|
An interface to read config files in the format of `minetest.conf`.
|
||||||
|
|
||||||
|
It can be created via `Settings(filename)`.
|
||||||
|
|
||||||
|
#### Methods
|
||||||
|
* `get(key)`: returns a value
|
||||||
|
* `get_bool(key)`: returns a boolean
|
||||||
|
* `set(key, value)`
|
||||||
|
* `remove(key)`: returns a boolean (`true` for success)
|
||||||
|
* `get_names()`: returns `{key1,...}`
|
||||||
|
* `write()`: returns a boolean (`true` for success)
|
||||||
|
* write changes to file
|
||||||
|
* `to_table()`: returns `{[key1]=value1,...}`
|
||||||
|
|
||||||
|
Definition tables
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
### Chat command definition (`register_chatcommand`)
|
||||||
|
|
||||||
|
{
|
||||||
|
params = "<name> <privilege>", -- Short parameter description
|
||||||
|
description = "Remove privilege from player", -- Full description
|
||||||
|
privs = {privs=true}, -- Require the "privs" privilege to run
|
||||||
|
func = function(name, param), -- Called when command is run.
|
||||||
|
-- Returns boolean success and text output.
|
||||||
|
}
|
@ -263,6 +263,7 @@ Client::Client(
|
|||||||
g_settings->getBool("enable_parallax_occlusion"));
|
g_settings->getBool("enable_parallax_occlusion"));
|
||||||
|
|
||||||
m_script = new ClientScripting(this);
|
m_script = new ClientScripting(this);
|
||||||
|
m_env.setScript(m_script);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Client::initMods()
|
void Client::initMods()
|
||||||
|
16
src/client.h
16
src/client.h
@ -488,13 +488,19 @@ public:
|
|||||||
// Get event from queue. CE_NONE is returned if queue is empty.
|
// Get event from queue. CE_NONE is returned if queue is empty.
|
||||||
ClientEvent getClientEvent();
|
ClientEvent getClientEvent();
|
||||||
|
|
||||||
bool accessDenied()
|
bool accessDenied() const { return m_access_denied; }
|
||||||
{ return m_access_denied; }
|
|
||||||
|
|
||||||
bool reconnectRequested() { return m_access_denied_reconnect; }
|
bool reconnectRequested() const { return m_access_denied_reconnect; }
|
||||||
|
|
||||||
std::string accessDeniedReason()
|
void setFatalError(const std::string &reason)
|
||||||
{ return m_access_denied_reason; }
|
{
|
||||||
|
m_access_denied = true;
|
||||||
|
m_access_denied_reason = reason;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Renaming accessDeniedReason to better name could be good as it's used to
|
||||||
|
// disconnect client when CSM failed.
|
||||||
|
const std::string &accessDeniedReason() const { return m_access_denied_reason; }
|
||||||
|
|
||||||
bool itemdefReceived()
|
bool itemdefReceived()
|
||||||
{ return m_itemdef_received; }
|
{ return m_itemdef_received; }
|
||||||
|
@ -22,6 +22,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
#include "clientenvironment.h"
|
#include "clientenvironment.h"
|
||||||
#include "clientsimpleobject.h"
|
#include "clientsimpleobject.h"
|
||||||
#include "clientmap.h"
|
#include "clientmap.h"
|
||||||
|
#include "clientscripting.h"
|
||||||
#include "mapblock_mesh.h"
|
#include "mapblock_mesh.h"
|
||||||
#include "event.h"
|
#include "event.h"
|
||||||
#include "collision.h"
|
#include "collision.h"
|
||||||
@ -42,6 +43,7 @@ ClientEnvironment::ClientEnvironment(ClientMap *map, scene::ISceneManager *smgr,
|
|||||||
m_smgr(smgr),
|
m_smgr(smgr),
|
||||||
m_texturesource(texturesource),
|
m_texturesource(texturesource),
|
||||||
m_client(client),
|
m_client(client),
|
||||||
|
m_script(NULL),
|
||||||
m_irr(irr)
|
m_irr(irr)
|
||||||
{
|
{
|
||||||
char zero = 0;
|
char zero = 0;
|
||||||
@ -243,6 +245,8 @@ void ClientEnvironment::step(float dtime)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_script->environment_step(dtime);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
A quick draft of lava damage
|
A quick draft of lava damage
|
||||||
*/
|
*/
|
||||||
|
@ -27,6 +27,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
|
|
||||||
class ClientSimpleObject;
|
class ClientSimpleObject;
|
||||||
class ClientMap;
|
class ClientMap;
|
||||||
|
class ClientScripting;
|
||||||
class ClientActiveObject;
|
class ClientActiveObject;
|
||||||
class GenericCAO;
|
class GenericCAO;
|
||||||
class LocalPlayer;
|
class LocalPlayer;
|
||||||
@ -75,6 +76,7 @@ public:
|
|||||||
ClientMap & getClientMap();
|
ClientMap & getClientMap();
|
||||||
|
|
||||||
Client *getGameDef() { return m_client; }
|
Client *getGameDef() { return m_client; }
|
||||||
|
void setScript(ClientScripting *script) { m_script = script; }
|
||||||
|
|
||||||
void step(f32 dtime);
|
void step(f32 dtime);
|
||||||
|
|
||||||
@ -176,6 +178,7 @@ private:
|
|||||||
scene::ISceneManager *m_smgr;
|
scene::ISceneManager *m_smgr;
|
||||||
ITextureSource *m_texturesource;
|
ITextureSource *m_texturesource;
|
||||||
Client *m_client;
|
Client *m_client;
|
||||||
|
ClientScripting *m_script;
|
||||||
IrrlichtDevice *m_irr;
|
IrrlichtDevice *m_irr;
|
||||||
UNORDERED_MAP<u16, ClientActiveObject*> m_active_objects;
|
UNORDERED_MAP<u16, ClientActiveObject*> m_active_objects;
|
||||||
std::vector<ClientSimpleObject*> m_simple_objects;
|
std::vector<ClientSimpleObject*> m_simple_objects;
|
||||||
|
@ -139,6 +139,7 @@ private:
|
|||||||
class GUIEngine {
|
class GUIEngine {
|
||||||
/** grant ModApiMainMenu access to private members */
|
/** grant ModApiMainMenu access to private members */
|
||||||
friend class ModApiMainMenu;
|
friend class ModApiMainMenu;
|
||||||
|
friend class ModApiSound;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
|
@ -22,6 +22,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
#include "client.h"
|
#include "client.h"
|
||||||
#include "cpp_api/s_internal.h"
|
#include "cpp_api/s_internal.h"
|
||||||
#include "lua_api/l_client.h"
|
#include "lua_api/l_client.h"
|
||||||
|
#include "lua_api/l_sound.h"
|
||||||
#include "lua_api/l_util.h"
|
#include "lua_api/l_util.h"
|
||||||
|
|
||||||
ClientScripting::ClientScripting(Client *client):
|
ClientScripting::ClientScripting(Client *client):
|
||||||
@ -51,4 +52,5 @@ void ClientScripting::InitializeModApi(lua_State *L, int top)
|
|||||||
{
|
{
|
||||||
ModApiUtil::InitializeClient(L, top);
|
ModApiUtil::InitializeClient(L, top);
|
||||||
ModApiClient::Initialize(L, top);
|
ModApiClient::Initialize(L, top);
|
||||||
|
ModApiSound::Initialize(L, top);
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
|
|
||||||
#include "s_client.h"
|
#include "s_client.h"
|
||||||
#include "s_internal.h"
|
#include "s_internal.h"
|
||||||
|
#include "client.h"
|
||||||
|
|
||||||
void ScriptApiClient::on_shutdown()
|
void ScriptApiClient::on_shutdown()
|
||||||
{
|
{
|
||||||
@ -94,3 +95,20 @@ void ScriptApiClient::on_death()
|
|||||||
// Call callbacks
|
// Call callbacks
|
||||||
runCallbacks(0, RUN_CALLBACKS_MODE_FIRST);
|
runCallbacks(0, RUN_CALLBACKS_MODE_FIRST);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ScriptApiClient::environment_step(float dtime)
|
||||||
|
{
|
||||||
|
SCRIPTAPI_PRECHECKHEADER
|
||||||
|
|
||||||
|
// Get core.registered_globalsteps
|
||||||
|
lua_getglobal(L, "core");
|
||||||
|
lua_getfield(L, -1, "registered_globalsteps");
|
||||||
|
// Call callbacks
|
||||||
|
lua_pushnumber(L, dtime);
|
||||||
|
try {
|
||||||
|
runCallbacks(1, RUN_CALLBACKS_MODE_FIRST);
|
||||||
|
} catch (LuaError &e) {
|
||||||
|
getClient()->setFatalError(std::string("Client environment_step: ") + e.what() + "\n"
|
||||||
|
+ script_get_backtrace(L));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -36,5 +36,7 @@ public:
|
|||||||
void on_damage_taken(int32_t damage_amount);
|
void on_damage_taken(int32_t damage_amount);
|
||||||
void on_hp_modification(int32_t newhp);
|
void on_hp_modification(int32_t newhp);
|
||||||
void on_death();
|
void on_death();
|
||||||
|
|
||||||
|
void environment_step(float dtime);
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
@ -25,4 +25,5 @@ set(common_SCRIPT_LUA_API_SRCS
|
|||||||
set(client_SCRIPT_LUA_API_SRCS
|
set(client_SCRIPT_LUA_API_SRCS
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/l_client.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/l_client.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/l_mainmenu.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/l_mainmenu.cpp
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/l_sound.cpp
|
||||||
PARENT_SCOPE)
|
PARENT_SCOPE)
|
||||||
|
@ -23,7 +23,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
|
|
||||||
#include "lua_api/l_base.h"
|
#include "lua_api/l_base.h"
|
||||||
|
|
||||||
class ModApiClient : public ModApiBase
|
class ModApiClient:
|
||||||
|
public ModApiBase
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
// get_current_modname()
|
// get_current_modname()
|
||||||
|
@ -32,9 +32,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
#include "convert_json.h"
|
#include "convert_json.h"
|
||||||
#include "serverlist.h"
|
#include "serverlist.h"
|
||||||
#include "mapgen.h"
|
#include "mapgen.h"
|
||||||
#include "sound.h"
|
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
#include "log.h"
|
|
||||||
#include "EDriverTypes.h"
|
#include "EDriverTypes.h"
|
||||||
|
|
||||||
#include <IFileArchive.h>
|
#include <IFileArchive.h>
|
||||||
@ -962,33 +960,6 @@ int ModApiMainMenu::l_show_file_open_dialog(lua_State *L)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/******************************************************************************/
|
|
||||||
int ModApiMainMenu::l_sound_play(lua_State *L)
|
|
||||||
{
|
|
||||||
GUIEngine* engine = getGuiEngine(L);
|
|
||||||
|
|
||||||
SimpleSoundSpec spec;
|
|
||||||
read_soundspec(L, 1, spec);
|
|
||||||
bool looped = lua_toboolean(L, 2);
|
|
||||||
|
|
||||||
u32 handle = engine->playSound(spec, looped);
|
|
||||||
|
|
||||||
lua_pushinteger(L, handle);
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/******************************************************************************/
|
|
||||||
int ModApiMainMenu::l_sound_stop(lua_State *L)
|
|
||||||
{
|
|
||||||
GUIEngine* engine = getGuiEngine(L);
|
|
||||||
|
|
||||||
u32 handle = luaL_checkinteger(L, 1);
|
|
||||||
engine->stopSound(handle);
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
int ModApiMainMenu::l_download_file(lua_State *L)
|
int ModApiMainMenu::l_download_file(lua_State *L)
|
||||||
{
|
{
|
||||||
@ -1160,8 +1131,6 @@ void ModApiMainMenu::Initialize(lua_State *L, int top)
|
|||||||
API_FCT(download_file);
|
API_FCT(download_file);
|
||||||
API_FCT(get_modstore_details);
|
API_FCT(get_modstore_details);
|
||||||
API_FCT(get_modstore_list);
|
API_FCT(get_modstore_list);
|
||||||
API_FCT(sound_play);
|
|
||||||
API_FCT(sound_stop);
|
|
||||||
API_FCT(gettext);
|
API_FCT(gettext);
|
||||||
API_FCT(get_video_drivers);
|
API_FCT(get_video_drivers);
|
||||||
API_FCT(get_video_modes);
|
API_FCT(get_video_modes);
|
||||||
|
@ -25,7 +25,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
class AsyncEngine;
|
class AsyncEngine;
|
||||||
|
|
||||||
/** Implementation of lua api support for mainmenu */
|
/** Implementation of lua api support for mainmenu */
|
||||||
class ModApiMainMenu : public ModApiBase {
|
class ModApiMainMenu: public ModApiBase
|
||||||
|
{
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/**
|
/**
|
||||||
@ -79,10 +80,6 @@ private:
|
|||||||
|
|
||||||
static int l_delete_favorite(lua_State *L);
|
static int l_delete_favorite(lua_State *L);
|
||||||
|
|
||||||
static int l_sound_play(lua_State *L);
|
|
||||||
|
|
||||||
static int l_sound_stop(lua_State *L);
|
|
||||||
|
|
||||||
static int l_gettext(lua_State *L);
|
static int l_gettext(lua_State *L);
|
||||||
|
|
||||||
//gui
|
//gui
|
||||||
|
62
src/script/lua_api/l_sound.cpp
Normal file
62
src/script/lua_api/l_sound.cpp
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
/*
|
||||||
|
Minetest
|
||||||
|
Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
|
||||||
|
Copyright (C) 2017 nerzhul, Loic Blot <loic.blot@unix-experience.fr>
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2.1 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public License along
|
||||||
|
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "l_sound.h"
|
||||||
|
#include "l_internal.h"
|
||||||
|
#include "common/c_content.h"
|
||||||
|
#include "guiEngine.h"
|
||||||
|
|
||||||
|
|
||||||
|
int ModApiSound::l_sound_play(lua_State *L)
|
||||||
|
{
|
||||||
|
SimpleSoundSpec spec;
|
||||||
|
read_soundspec(L, 1, spec);
|
||||||
|
bool looped = lua_toboolean(L, 2);
|
||||||
|
|
||||||
|
s32 handle;
|
||||||
|
if (Client *client = getClient(L))
|
||||||
|
handle = client->getSoundManager()->playSound(spec, looped);
|
||||||
|
// Main menu doesn't have access to client, use guiEngine
|
||||||
|
else
|
||||||
|
handle = getGuiEngine(L)->playSound(spec, looped);
|
||||||
|
|
||||||
|
lua_pushinteger(L, handle);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ModApiSound::l_sound_stop(lua_State *L)
|
||||||
|
{
|
||||||
|
u32 handle = luaL_checkinteger(L, 1);
|
||||||
|
|
||||||
|
if (Client *client = getClient(L))
|
||||||
|
client->getSoundManager()->stopSound(handle);
|
||||||
|
// Main menu doesn't have access to client, use guiEngine
|
||||||
|
else
|
||||||
|
getGuiEngine(L)->stopSound(handle);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ModApiSound::Initialize(lua_State *L, int top)
|
||||||
|
{
|
||||||
|
API_FCT(sound_play);
|
||||||
|
API_FCT(sound_stop);
|
||||||
|
}
|
36
src/script/lua_api/l_sound.h
Normal file
36
src/script/lua_api/l_sound.h
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
/*
|
||||||
|
Minetest
|
||||||
|
Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
|
||||||
|
Copyright (C) 2017 nerzhul, Loic Blot <loic.blot@unix-experience.fr>
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2.1 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public License along
|
||||||
|
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef L_SOUND_H_
|
||||||
|
#define L_SOUND_H_
|
||||||
|
|
||||||
|
#include "lua_api/l_base.h"
|
||||||
|
|
||||||
|
|
||||||
|
class ModApiSound: public ModApiBase
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
static int l_sound_play(lua_State *L);
|
||||||
|
static int l_sound_stop(lua_State *L);
|
||||||
|
public:
|
||||||
|
static void Initialize(lua_State *L, int top);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
@ -530,6 +530,8 @@ void ModApiUtil::InitializeClient(lua_State *L, int top)
|
|||||||
{
|
{
|
||||||
API_FCT(log);
|
API_FCT(log);
|
||||||
|
|
||||||
|
API_FCT(get_us_time);
|
||||||
|
|
||||||
API_FCT(setting_set);
|
API_FCT(setting_set);
|
||||||
API_FCT(setting_get);
|
API_FCT(setting_get);
|
||||||
API_FCT(setting_setbool);
|
API_FCT(setting_setbool);
|
||||||
|
@ -19,11 +19,10 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
|
|
||||||
#include "scripting_mainmenu.h"
|
#include "scripting_mainmenu.h"
|
||||||
#include "mods.h"
|
#include "mods.h"
|
||||||
#include "porting.h"
|
|
||||||
#include "log.h"
|
|
||||||
#include "cpp_api/s_internal.h"
|
#include "cpp_api/s_internal.h"
|
||||||
#include "lua_api/l_base.h"
|
#include "lua_api/l_base.h"
|
||||||
#include "lua_api/l_mainmenu.h"
|
#include "lua_api/l_mainmenu.h"
|
||||||
|
#include "lua_api/l_sound.h"
|
||||||
#include "lua_api/l_util.h"
|
#include "lua_api/l_util.h"
|
||||||
#include "lua_api/l_settings.h"
|
#include "lua_api/l_settings.h"
|
||||||
|
|
||||||
@ -63,6 +62,7 @@ void MainMenuScripting::initializeModApi(lua_State *L, int top)
|
|||||||
// Initialize mod API modules
|
// Initialize mod API modules
|
||||||
ModApiMainMenu::Initialize(L, top);
|
ModApiMainMenu::Initialize(L, top);
|
||||||
ModApiUtil::Initialize(L, top);
|
ModApiUtil::Initialize(L, top);
|
||||||
|
ModApiSound::Initialize(L, top);
|
||||||
|
|
||||||
// Register reference classes (userdata)
|
// Register reference classes (userdata)
|
||||||
LuaSettings::Register(L);
|
LuaSettings::Register(L);
|
||||||
|
Loading…
Reference in New Issue
Block a user