First working version
parent
87a2f78671
commit
29dd09e8dc
|
@ -0,0 +1,177 @@
|
|||
LuaConfig Minetet Mod
|
||||
=====================
|
||||
|
||||
This mod makes it really, really easy for other mods to load Lua-based
|
||||
configuration settings. It's as simple as adding "luaconfig" to your mod's
|
||||
depends.txt and putting this at the top of your init.lua:
|
||||
|
||||
local config = luaconfig.loadConfig();
|
||||
|
||||
and then optionally (to make settings globally visible):
|
||||
|
||||
mymod = { config = config };
|
||||
|
||||
This automatically detects the name and path of your mod and loads settings
|
||||
from "config.lua" in your mod directory and/or "<myMod>_config.lua" in the
|
||||
world directory, allowing the latter to add to or overwrite the former. No
|
||||
errors will be generated if either or both files are missing.
|
||||
|
||||
This mod allows simple Lua variable-based configuration settings that almost
|
||||
guarantee that you don't accidentally set global variables (you can if you
|
||||
REALLY try, but it's difficult). You'll have access to all variables defined
|
||||
from the config files using logic like:
|
||||
|
||||
print(config.message);
|
||||
|
||||
Simple Example
|
||||
--------------
|
||||
|
||||
Here's a mod that announces to all when a player joins and leaves, and greets
|
||||
the player directly when he/she joins. Keep in mind that the name "mymod" is
|
||||
just an example, and would actually be replaced by the name of your own mod.
|
||||
|
||||
-- mymod/init.lua
|
||||
|
||||
local config = luaconfig.loadConfig();
|
||||
|
||||
local function prepare(message, player)
|
||||
return string.gsub(message, "<player>", player:get_player_name());
|
||||
end;
|
||||
|
||||
minetest.register_on_joinplayer(function(player)
|
||||
minetest.chat_send_all(
|
||||
prepare(config.joinAnnouncement, player));
|
||||
|
||||
minetest.after(
|
||||
3.0,
|
||||
function()
|
||||
minetest.chat_send_player(player:get_player_name(),
|
||||
prepare(config.greeting, player));
|
||||
end);
|
||||
end);
|
||||
|
||||
minetest.register_on_leaveplayer(function(player)
|
||||
minetest.chat_send_all(
|
||||
prepare(config.leaveAnnouncement, player));
|
||||
end);
|
||||
|
||||
Here is the mod's (default) config file:
|
||||
|
||||
-- mymod/config.lua
|
||||
|
||||
joinAnnouncement = "<player> says hello!"
|
||||
leaveAnnouncement = "<player> says goodbye!"
|
||||
greeting = "Hello <player>, and welcome"
|
||||
|
||||
And here's a world-specific config file for world "myworld":
|
||||
|
||||
-- myworld/mymod_config.lua
|
||||
|
||||
joinAnnouncement = "<player> saunters in and says 'Howdy!'"
|
||||
leaveAnnouncement = "<player> tips his hat and says 'Adiós, amigos!'"
|
||||
greeting = string.gsub(greeting, "Hello", "Howdy") .. " to myworld!"
|
||||
|
||||
Advanced Use/Examples
|
||||
---------------------
|
||||
|
||||
The luaconfig.loadConfig() function takes two optional parameters, for
|
||||
convenience. The first is the name of your module. It's auto-detected if
|
||||
missing or nil, but passing it in is helpful if you don't call the function
|
||||
right away (e.g. if you reload some settings periodically without restarting
|
||||
the server), as there is no way to auto-detect what mod you are in once you get
|
||||
to callbacks. So you can do:
|
||||
|
||||
local MOD_NAME = minetest.get_current_modname();
|
||||
-- and later, from a callback...
|
||||
local config = luaconfig.loadConfig(MOD_NAME);
|
||||
|
||||
The second optional parameter is an existing table to use instead of creating a
|
||||
new one. This same table is returned by the function, but can be safely
|
||||
ignored. This is useful if you want to set some defaults right from your mod
|
||||
code before loading settings from the config files:
|
||||
|
||||
local config = { greeting = "What, you're back?!" };
|
||||
luaconfig.loadConfig(nil, config);
|
||||
-- Use config.greeting as usual
|
||||
|
||||
If this second parameter is missing or nil, the luaconfig.loadConfig() function
|
||||
looks for a globally visible table named after your module, and a 'config'
|
||||
table inside that. If it finds this, it uses it. Otherwise it creates a new
|
||||
table and returns it. So doing this works just fine:
|
||||
|
||||
mymod = {};
|
||||
mymod.config = {};
|
||||
mymod.config.greeting = "What, you're back?!";
|
||||
|
||||
luaconfig.loadConfig();
|
||||
-- Use mymod.config.greeting as usual
|
||||
|
||||
Of course, if your mod uses a table called 'mymod.config' already, you can just
|
||||
pass in an empty table and/or retrieve it back from the function to avoid
|
||||
conflicts:
|
||||
|
||||
local settings = luaconfig.loadConfig(nil, {});
|
||||
-- or
|
||||
mymod = { settings = {} };
|
||||
luaconfig.loadConfig(nil, mymod.settings);
|
||||
|
||||
Note that the "config.lua" file in the mod directory is loaded first, and then
|
||||
the "<modName>_config.lua" file from the world directory. The world-specific
|
||||
file can thus access and modify settings made from the mod file, and both can
|
||||
access and modify settings that your mod code makes before calling
|
||||
luaconfig.loadConfig(). For more complicated (table-based) settings, you might
|
||||
want to practice writing the configuration like:
|
||||
|
||||
complexSettings = complexSettings or {};
|
||||
complexSettings.name = "Freeway";
|
||||
complexSettings.length = 16;
|
||||
complexSettings.units = "km";
|
||||
|
||||
so that it is easy to copy/paste, comment, and override individual settings
|
||||
later from other files (or the mod code), whether or not the tables or
|
||||
individual settings already exist:
|
||||
|
||||
complexSettings = complexSettings or {};
|
||||
-- default complexSettings.name
|
||||
complexSettings.length = 20;
|
||||
-- default complexSettings.units
|
||||
|
||||
At this time there is NO built-in support for (re-)writing the config files
|
||||
from within the game. This is by design. These config files contain
|
||||
executable Lua code, and it's not usually advisable to auto-generate that. If
|
||||
you really want to you can implement something using, for example, io.open(),
|
||||
file:write(), and some custom serialization (e.g. making use of
|
||||
minetest.serialize() for each table entry). This is left as an exercise for
|
||||
brave and desperate readers.
|
||||
|
||||
Mod Information
|
||||
---------------
|
||||
|
||||
Require Minetest Version: (probably any; tested in 0.4.12)
|
||||
|
||||
Dependencies: (none)
|
||||
|
||||
Soft Dependencies: (none)
|
||||
|
||||
Craft Recipes: (none)
|
||||
|
||||
API: luaconfig.loadConfig([modName, [configTable]])
|
||||
|
||||
Git Repo: https://github.com/prestidigitator/minetest-mod-luaconfig
|
||||
|
||||
Change History
|
||||
--------------
|
||||
|
||||
Version 1.0
|
||||
|
||||
* Released 2015-05-03
|
||||
* First working version.
|
||||
|
||||
Copyright and Licensing
|
||||
-----------------------
|
||||
|
||||
All content, including documentation and source code, are original content
|
||||
created by the mod author and are licensed under WTFPL.
|
||||
|
||||
Author: prestidigitator (as registered on forum.minetest.net)
|
||||
License: WTFPL
|
|
@ -0,0 +1,74 @@
|
|||
local MOD_NAME = minetest.get_current_modname() or "luaconfig";
|
||||
local MOD_PATH = minetest.get_modpath(MOD_NAME);
|
||||
|
||||
local luaconfig = { MOD_NAME = MOD_NAME, MOD_PATH = MOD_PATH };
|
||||
_G[MOD_NAME] = luaconfig;
|
||||
|
||||
local function loadConfigFile(filePath)
|
||||
-- test for existence/readability
|
||||
local file = io.open(filePath, 'r');
|
||||
if not file then return nil; end;
|
||||
file:close();
|
||||
|
||||
local chunk, err = loadfile(filePath);
|
||||
return chunk or error(err);
|
||||
end;
|
||||
|
||||
function luaconfig.loadConfig(modName, config)
|
||||
modName = modName or minetest.get_current_modname();
|
||||
if not modName or modName == "" then
|
||||
error(MOD_NAME .. ": Couldn't determine mod name for loading config");
|
||||
end;
|
||||
local modPath =
|
||||
minetest.get_modpath(modName) or
|
||||
error(MOD_NAME .. ": Couldn't determine mod path for loading config");
|
||||
|
||||
local modConfigFile =
|
||||
modPath .. "/config.lua";
|
||||
local worldConfigFile =
|
||||
minetest.get_worldpath() .. "/" .. modName .. "_config.lua";
|
||||
|
||||
-- Avoids errors due to testing for nil global variables
|
||||
local gCopy = {};
|
||||
for k, v in pairs(_G) do gCopy[k] = v; end;
|
||||
|
||||
if not config then
|
||||
local modApi = gCopy[modName];
|
||||
local modConfig = (type(modApi) == 'table') and modApi.config;
|
||||
config = (type(modConfig) == 'table' and modConfig) or {};
|
||||
end;
|
||||
|
||||
local modConfigFunc = loadConfigFile(modConfigFile);
|
||||
local worldConfigFunc = loadConfigFile(worldConfigFile);
|
||||
if not modConfigFunc and not worldConfigFunc then return config; end;
|
||||
|
||||
-- Setting any "global" variable in the config files actually modifies the
|
||||
-- local config table (unless the variable is accessed through another
|
||||
-- existing table like _G or minetest).
|
||||
local configEnv =
|
||||
setmetatable(
|
||||
{},
|
||||
{
|
||||
__index = function(self, key)
|
||||
local v = config[key];
|
||||
if v ~= nil then return v; else return gCopy[key]; end;
|
||||
end,
|
||||
|
||||
__newindex = function(self, key, value)
|
||||
config[key] = value;
|
||||
return true;
|
||||
end
|
||||
});
|
||||
|
||||
if modConfigFunc then
|
||||
setfenv(modConfigFunc, configEnv);
|
||||
modConfigFunc();
|
||||
end;
|
||||
|
||||
if worldConfigFunc then
|
||||
setfenv(worldConfigFunc, configEnv);
|
||||
worldConfigFunc();
|
||||
end;
|
||||
|
||||
return config;
|
||||
end;
|
Loading…
Reference in New Issue