[CSM] sound_play & sound_stop support + client_lua_api doc (#5096)
authorLoïc Blot <nerzhul@users.noreply.github.com>
Sun, 22 Jan 2017 10:17:41 +0000 (11:17 +0100)
committerLoïc Blot <nerzhul@users.noreply.github.com>
Mon, 13 Mar 2017 22:56:05 +0000 (23:56 +0100)
* 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

23 files changed:
builtin/client/init.lua
builtin/client/preview.lua
builtin/client/register.lua
builtin/common/after.lua [new file with mode: 0644]
builtin/game/init.lua
builtin/game/misc.lua
doc/client_lua_api.txt [new file with mode: 0644]
src/client.cpp
src/client.h
src/clientenvironment.cpp
src/clientenvironment.h
src/guiEngine.h
src/script/clientscripting.cpp
src/script/cpp_api/s_client.cpp
src/script/cpp_api/s_client.h
src/script/lua_api/CMakeLists.txt
src/script/lua_api/l_client.h
src/script/lua_api/l_mainmenu.cpp
src/script/lua_api/l_mainmenu.h
src/script/lua_api/l_sound.cpp [new file with mode: 0644]
src/script/lua_api/l_sound.h [new file with mode: 0644]
src/script/lua_api/l_util.cpp
src/script/scripting_mainmenu.cpp

index 4797ac4b6fbac1666dfd997ebd3dfb5dd89fd2af..dd218aab66b9f40991edba96d212e43a71de6443 100644 (file)
@@ -4,9 +4,10 @@ local clientpath = scriptpath.."client"..DIR_DELIM
 local commonpath = scriptpath.."common"..DIR_DELIM
 
 dofile(clientpath .. "register.lua")
+dofile(commonpath .. "after.lua")
+dofile(commonpath .. "chatcommands.lua")
 dofile(clientpath .. "preview.lua")
 
 core.register_on_death(function()
        core.display_chat_message("You died.")
 end)
-
index c421791f5f99eadf9d63452b69e0f60dd8e52566..22e8bb97f647e9385b9b94d8eea4f20972d95654 100644 (file)
@@ -1,6 +1,6 @@
 -- This is an example function to ensure it's working properly, should be removed before merge
 core.register_on_shutdown(function()
-       print("shutdown client")
+       print("[PREVIEW] shutdown client")
 end)
 
 -- 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
 end)
 
+-- This is an example function to ensure it's working properly, should be removed before merge
 core.register_on_hp_modification(function(hp)
        print("[PREVIEW] HP modified " .. hp)
 end)
 
+-- This is an example function to ensure it's working properly, should be removed before merge
 core.register_on_damage_taken(function(hp)
        print("[PREVIEW] Damage taken " .. hp)
 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
 core.register_chatcommand("dump", {
        func = function(name, param)
                return true, dump(_G)
        end,
-})
\ No newline at end of file
+})
+
+core.after(2, function()
+       print("After 2")
+end)
index ddaf4f424acc5e06a09a8d70238d41d8477bf478..8b60c1222312c09b6f409535218da6abaf91a1d8 100644 (file)
@@ -55,6 +55,7 @@ local function make_registration()
        return t, registerfunc
 end
 
+core.registered_globalsteps, core.register_globalstep = 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_sending_chat_messages, core.register_on_sending_chat_messages = make_registration()
diff --git a/builtin/common/after.lua b/builtin/common/after.lua
new file mode 100644 (file)
index 0000000..30a9c7b
--- /dev/null
@@ -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
index 793d9fe2bcc61957a4fa30b4c9f4594e5bd3bef6..3e192a30ab6d30b3f1f2d0236b549d02070bf160 100644 (file)
@@ -17,6 +17,7 @@ if core.setting_getbool("profiler.load") then
        profiler = dofile(scriptpath.."profiler"..DIR_DELIM.."init.lua")
 end
 
+dofile(commonpath .. "after.lua")
 dofile(gamepath.."item_entity.lua")
 dofile(gamepath.."deprecated.lua")
 dofile(gamepath.."misc.lua")
index 3419c19802608d404102ce04a82d3b7107a77f70..25376c18046756b68d286f0fe4d587054a8c0d17 100644 (file)
@@ -4,50 +4,6 @@
 -- 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, ...)
        local arg_type = type(name)
        if (arg_type == "userdata" or arg_type == "table") and
diff --git a/doc/client_lua_api.txt b/doc/client_lua_api.txt
new file mode 100644 (file)
index 0000000..8ce487b
--- /dev/null
@@ -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.
+    }
index 3a3e0673ee54678b2005392b1e237d6286efa270..3b807425224caf859232b422bd58092c55df83f9 100644 (file)
@@ -263,6 +263,7 @@ Client::Client(
                g_settings->getBool("enable_parallax_occlusion"));
 
        m_script = new ClientScripting(this);
+       m_env.setScript(m_script);
 }
 
 void Client::initMods()
index 21aeb05758fb62ff324b085db700f05fcd768233..ff8aea5913c5decd6a2b59ff241910317b5c0b72 100644 (file)
@@ -488,13 +488,19 @@ public:
        // Get event from queue. CE_NONE is returned if queue is empty.
        ClientEvent getClientEvent();
 
-       bool accessDenied()
-       { return m_access_denied; }
+       bool accessDenied() const { return m_access_denied; }
 
-       bool reconnectRequested() { return m_access_denied_reconnect; }
+       bool reconnectRequested() const { return m_access_denied_reconnect; }
 
-       std::string accessDeniedReason()
-       { return m_access_denied_reason; }
+       void setFatalError(const std::string &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()
        { return m_itemdef_received; }
index 77f53d214fb2bf2e78d1cc4889db99a61d7e43b4..1175d00c0bc837c7c4d381c88ae0dcad78315bad 100644 (file)
@@ -22,6 +22,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "clientenvironment.h"
 #include "clientsimpleobject.h"
 #include "clientmap.h"
+#include "clientscripting.h"
 #include "mapblock_mesh.h"
 #include "event.h"
 #include "collision.h"
@@ -42,6 +43,7 @@ ClientEnvironment::ClientEnvironment(ClientMap *map, scene::ISceneManager *smgr,
        m_smgr(smgr),
        m_texturesource(texturesource),
        m_client(client),
+       m_script(NULL),
        m_irr(irr)
 {
        char zero = 0;
@@ -243,6 +245,8 @@ void ClientEnvironment::step(float dtime)
                }
        }
 
+       m_script->environment_step(dtime);
+
        /*
                A quick draft of lava damage
        */
index b30a7a6d7b71504a379c45d417fbd3cb3abe702d..c273ede54a278dff088f335d27f544b9ef85e016 100644 (file)
@@ -27,6 +27,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 
 class ClientSimpleObject;
 class ClientMap;
+class ClientScripting;
 class ClientActiveObject;
 class GenericCAO;
 class LocalPlayer;
@@ -75,6 +76,7 @@ public:
        ClientMap & getClientMap();
 
        Client *getGameDef() { return m_client; }
+       void setScript(ClientScripting *script) { m_script = script; }
 
        void step(f32 dtime);
 
@@ -176,6 +178,7 @@ private:
        scene::ISceneManager *m_smgr;
        ITextureSource *m_texturesource;
        Client *m_client;
+       ClientScripting *m_script;
        IrrlichtDevice *m_irr;
        UNORDERED_MAP<u16, ClientActiveObject*> m_active_objects;
        std::vector<ClientSimpleObject*> m_simple_objects;
index 897244808fdae6baeaf5d2a810c54c34e9a6499f..a81813d18e3ae984852da85245b9a6bd728695fa 100644 (file)
@@ -139,6 +139,7 @@ private:
 class GUIEngine {
        /** grant ModApiMainMenu access to private members */
        friend class ModApiMainMenu;
+       friend class ModApiSound;
 
 public:
        /**
index 9bf93eb83a2579f54647b342c79730e74a9c8042..37032443358867f2920b58481eba14e89e7d2542 100644 (file)
@@ -22,6 +22,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "client.h"
 #include "cpp_api/s_internal.h"
 #include "lua_api/l_client.h"
+#include "lua_api/l_sound.h"
 #include "lua_api/l_util.h"
 
 ClientScripting::ClientScripting(Client *client):
@@ -51,4 +52,5 @@ void ClientScripting::InitializeModApi(lua_State *L, int top)
 {
        ModApiUtil::InitializeClient(L, top);
        ModApiClient::Initialize(L, top);
+       ModApiSound::Initialize(L, top);
 }
index f0676f4c21f1c2d7bd0b27132e16db414024c640..ce88d67e38d874f0641b1473d272bfdd857cf8a0 100644 (file)
@@ -20,6 +20,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 
 #include "s_client.h"
 #include "s_internal.h"
+#include "client.h"
 
 void ScriptApiClient::on_shutdown()
 {
@@ -94,3 +95,20 @@ void ScriptApiClient::on_death()
        // Call callbacks
        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));
+       }
+}
index 3155c7e674b446ed0dc0554125e88741b075e78d..3d373f97c6851e0f905a120ed4b15dede0e131fd 100644 (file)
@@ -36,5 +36,7 @@ public:
        void on_damage_taken(int32_t damage_amount);
        void on_hp_modification(int32_t newhp);
        void on_death();
+
+       void environment_step(float dtime);
 };
 #endif
index ea3d75ffa6438acbec17f5fa481d9a35b473861f..17bcdde4c42b8f148238f509f9632af811d58e58 100644 (file)
@@ -25,4 +25,5 @@ set(common_SCRIPT_LUA_API_SRCS
 set(client_SCRIPT_LUA_API_SRCS
        ${CMAKE_CURRENT_SOURCE_DIR}/l_client.cpp
        ${CMAKE_CURRENT_SOURCE_DIR}/l_mainmenu.cpp
+       ${CMAKE_CURRENT_SOURCE_DIR}/l_sound.cpp
        PARENT_SCOPE)
index e3106e74214870b07cf4de8151cd406fb11456d6..150880e3c4b09643330afbc976bdc390ace73d82 100644 (file)
@@ -23,7 +23,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 
 #include "lua_api/l_base.h"
 
-class ModApiClient : public ModApiBase
+class ModApiClient:
+       public ModApiBase
 {
 private:
        // get_current_modname()
index de8890b11878671f7987e527ac5176474dce3d4a..3d204db98618ea5e703fc89fb2c722b87b2004fa 100644 (file)
@@ -32,9 +32,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "convert_json.h"
 #include "serverlist.h"
 #include "mapgen.h"
-#include "sound.h"
 #include "settings.h"
-#include "log.h"
 #include "EDriverTypes.h"
 
 #include <IFileArchive.h>
@@ -962,33 +960,6 @@ int ModApiMainMenu::l_show_file_open_dialog(lua_State *L)
        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)
 {
@@ -1160,8 +1131,6 @@ void ModApiMainMenu::Initialize(lua_State *L, int top)
        API_FCT(download_file);
        API_FCT(get_modstore_details);
        API_FCT(get_modstore_list);
-       API_FCT(sound_play);
-       API_FCT(sound_stop);
        API_FCT(gettext);
        API_FCT(get_video_drivers);
        API_FCT(get_video_modes);
index ad5155ac6a77026c45d8820e8f17cc73c9e45eb5..e31ac0112c71c2cfed9398b9135baf11056491d2 100644 (file)
@@ -25,7 +25,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 class AsyncEngine;
 
 /** Implementation of lua api support for mainmenu */
-class ModApiMainMenu : public ModApiBase {
+class ModApiMainMenu: public ModApiBase
+{
 
 private:
        /**
@@ -79,10 +80,6 @@ private:
 
        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);
 
        //gui
diff --git a/src/script/lua_api/l_sound.cpp b/src/script/lua_api/l_sound.cpp
new file mode 100644 (file)
index 0000000..774b5be
--- /dev/null
@@ -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);
+}
diff --git a/src/script/lua_api/l_sound.h b/src/script/lua_api/l_sound.h
new file mode 100644 (file)
index 0000000..86ba908
--- /dev/null
@@ -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
index 277a874bf5c7444bbc3ab78495ad86bdf2695c62..b9c334121d9ab58a1db4424659f79b1b868bac30 100644 (file)
@@ -530,6 +530,8 @@ void ModApiUtil::InitializeClient(lua_State *L, int top)
 {
        API_FCT(log);
 
+       API_FCT(get_us_time);
+
        API_FCT(setting_set);
        API_FCT(setting_get);
        API_FCT(setting_setbool);
index b1e50c94b446c2a5210a4db0ba0234b8167479ca..61318735d18eb82380a0280c90e633ea8bb01fdd 100644 (file)
@@ -19,11 +19,10 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 
 #include "scripting_mainmenu.h"
 #include "mods.h"
-#include "porting.h"
-#include "log.h"
 #include "cpp_api/s_internal.h"
 #include "lua_api/l_base.h"
 #include "lua_api/l_mainmenu.h"
+#include "lua_api/l_sound.h"
 #include "lua_api/l_util.h"
 #include "lua_api/l_settings.h"
 
@@ -63,6 +62,7 @@ void MainMenuScripting::initializeModApi(lua_State *L, int top)
        // Initialize mod API modules
        ModApiMainMenu::Initialize(L, top);
        ModApiUtil::Initialize(L, top);
+       ModApiSound::Initialize(L, top);
 
        // Register reference classes (userdata)
        LuaSettings::Register(L);