Minetest Lua Client Modding API Reference 5.4.0 ================================================ * More information at * Developer Wiki: Introduction ------------ ** WARNING: The client API is currently unstable, and may break/change without warning. ** Content and functionality can be added to Minetest 0.4.15-dev+ 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. Transferring client-sided mods from the server to the client is planned, but not implemented yet. 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. In order to load client-side mods, the following conditions need to be satisfied: 1) `$path_user/minetest.conf` contains the setting `enable_client_modding = true` 2) The client-side mod located in `$path_user/clientmods/` is added to `$path_user/clientmods/mods.conf` as `load_mod_ = true`. Note: Depending on the remote server's settings, client-side mods might not be loaded or have limited functionality. See setting `csm_restriction_flags` for reference. Paths ----- * `RUN_IN_PLACE=1` (Windows release, local build) * `$path_user`: `` * `$path_share`: `` * `RUN_IN_PLACE=0`: (Linux release) * `$path_share`: * Linux: `/usr/share/minetest` * Windows: `/minetest-0.4.x` * `$path_user`: * Linux: `$HOME/.minetest` * Windows: `C:/users//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.conf`. The file is a key-value store of modpack details. * `name`: The modpack name. * `description`: Description of mod to be shown in the Mods tab of the main menu. Mod directory structure ------------------------ clientmods ├── modname │   ├── mod.conf │   ├── init.lua └── another ### modname The location of this directory. ### mod.conf An (optional) settings file that provides meta information about the mod. * `name`: The mod name. Allows Minetest to determine the mod name even if the folder is wrongly named. * `description`: Description of mod to be shown in the Mods tab of the main menu. * `depends`: A comma separated list of dependencies. These are mods that must be loaded before this mod. * `optional_depends`: A comma separated list of optional dependencies. Like a dependency, but no error if the mod doesn't exist. ### `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. **NOTE**: Client mods currently can't provide textures, sounds, or models by themselves. Any media referenced in function calls must already be loaded (provided by mods that exist on the server). Naming convention for registered textual names ---------------------------------------------- Registered names should generally be in this format: "modname:" ( 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. Sounds ------ **NOTE: Connecting sounds to objects is not implemented.** 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` 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 "test.h" #include <sstream> #include "gamedef.h" #include "nodedef.h" #include "network/networkprotocol.h" class TestNodeDef : public TestBase { public: TestNodeDef() { TestManager::registerTestModule(this); } const char *getName() { return "TestNodeDef"; } void runTests(IGameDef *gamedef); void testContentFeaturesSerialization(); }; static TestNodeDef g_test_instance; void TestNodeDef::runTests(IGameDef *gamedef) { TEST(testContentFeaturesSerialization); } //////////////////////////////////////////////////////////////////////////////// void TestNodeDef::testContentFeaturesSerialization() { ContentFeatures f; f.name = "default:stone"; for (int i = 0; i < 6; i++) f.tiledef[i].name = "default_stone.png"; f.is_ground_content = true; std::ostringstream os(std::ios::binary); f.serialize(os, LATEST_PROTOCOL_VERSION); //verbosestream<<"Test ContentFeatures size: "<<os.str().size()<<std::endl; std::istringstream is(os.str(), std::ios::binary); ContentFeatures f2; f2.deSerialize(is); UASSERT(f.walkable == f2.walkable); UASSERT(f.node_box.type == f2.node_box.type); } e 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[,;,;;