summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorcheapie <no-email-for-you@example.com>2021-03-05 00:00:01 -0600
committercheapie <no-email-for-you@example.com>2021-03-05 00:00:01 -0600
commit17dc9a8247c35b9710741d0f23d502e7d66d37ba (patch)
treecef1ef11cf26f4411741840a1ae99cbf1619122e
downloadplayersettings-main.tar
playersettings-main.tar.gz
playersettings-main.tar.bz2
playersettings-main.tar.xz
playersettings-main.zip
Add initial contentHEADmain
-rw-r--r--COPYING24
-rw-r--r--README76
-rw-r--r--init.lua176
-rw-r--r--mod.conf5
-rw-r--r--textures/playersettings_settings_button.pngbin0 -> 5577 bytes
5 files changed, 281 insertions, 0 deletions
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..68a49da
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,24 @@
+This is free and unencumbered software released into the public domain.
+
+Anyone is free to copy, modify, publish, use, compile, sell, or
+distribute this software, either in source code form or as a compiled
+binary, for any purpose, commercial or non-commercial, and by any
+means.
+
+In jurisdictions that recognize copyright laws, the author or authors
+of this software dedicate any and all copyright interest in the
+software to the public domain. We make this dedication for the benefit
+of the public at large and to the detriment of our heirs and
+successors. We intend this dedication to be an overt act of
+relinquishment in perpetuity of all present and future rights to this
+software under copyright law.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+
+For more information, please refer to <http://unlicense.org/>
diff --git a/README b/README
new file mode 100644
index 0000000..71a4ca9
--- /dev/null
+++ b/README
@@ -0,0 +1,76 @@
+playersettings
+==============
+
+This mod provides a GUI (via unified_inventory) that allows players to change various per-player settings.
+No settings are actually included, but other mods can provide their own.
+
+To register a setting:
+
+playersettings.register("yourmodname:yoursettingname",{
+
+ type = "number",
+ -- Specifies the type of the setting to register.
+ -- Valid types are:
+ ---- "number": An integer or floating-point value.
+ ---- "string": A text string.
+ ---- "boolean": A simple yes/no checkbox.
+ ---- "enum": A list of possible choices.
+
+ shortdesc = "Short Description",
+ -- A short (human-readable) description of the setting, to be shown as the setting name in the menu.
+
+ longdesc = "Long Description Goes Here",
+ -- A longer desciption that is shown when the user selects your setting in the menu.
+
+ default = 5,
+ -- The default value of the setting.
+
+ min = 0,
+ -- For "number" settings: The smallest selectable value.
+
+ max = 10,
+ -- For "number" settings: The largest selectable value.
+
+ integer = true,
+ -- For "integer" settings: If true, entered numbers will be rounded down to the nearest integer.
+
+ values = "some text here",
+ -- For "string" settings: Text to be displayed under the entry field to assist the user in selecting valid values.
+
+ values = {"Apple", "Orange", "Banana"},
+ -- For "enum" settings: A list of the possible choices.
+
+ onjoin = function(player_name,setting_value),
+ -- A function to be called whenever a player joins the game.
+ -- 'player_name' is the name of the player that just joined.
+ -- 'setting_value' is the current value of the setting.
+
+ onchange = function(player_name,old_value,new_value)
+ -- A function to be called when a player tries to change the setting, before the setting is actually changed.
+ -- Custom validation logic should go here.
+ -- 'player_name' is the name of the player trying to change the setting.
+ -- 'old_value' is the current value of the setting.
+ -- 'new_value' is the value the player wants to change the setting to.
+ -- Return true to allow the change to take place, or false (or nothing at all) to prevent the change.
+
+ afterchange = function(player_name,old_value,new_value)
+ -- A function to be called after the setting is changed.
+ -- Code to apply the new value of the setting should go here.
+ -- 'player_name' is the name of the player that changed the setting.
+ -- 'old_value' is the old value of the setting, before it was changed.
+ -- 'new_value' is the value that the setting was changed to.
+})
+
+To set a setting (from another mod):
+
+playersettings.set(player_name,setting_name,new_value)
+-- 'player_name' is the player to change the setting for.
+-- 'setting_name' is the name of the setting to change.
+-- 'new_value' is the new value of the setting.
+-- Changing settings via this interface bypasses the built-in validation (such as range checking on numbers) but NOT any specified onchange or afterchange actions.
+
+To get the value of a setting (from another mod):
+
+playersettings.get(player_name,setting_name)
+-- 'player_name' is the player to get the setting value from.
+-- 'setting_name' is the name of the setting to get.
diff --git a/init.lua b/init.lua
new file mode 100644
index 0000000..814431e
--- /dev/null
+++ b/init.lua
@@ -0,0 +1,176 @@
+local storage = minetest.get_mod_storage()
+
+playersettings = {}
+
+playersettings.registered = {}
+
+playersettings.settingslist = {}
+
+playersettings.highlighted = {}
+
+playersettings.form = "formspec_version[4]"..
+ "size[15,15]" ..
+ "button[12.5,13.5;2,1;quit;Save and Exit]"..
+ "textlist[0.5,0.5;7,14;settinglist;%s;%d;false]"..
+ "label[8,2;%s]"..
+ "label[8,3;%s]"..
+ "%s"
+
+function playersettings.openform(player)
+ if type(player) == "string" then player = minetest.get_player_by_name(player) end
+ local name = player:get_player_name()
+ if #playersettings.settingslist < 1 then
+ local form = "formspec_version[4]size[12,3]label[0.5,1;No settings currently exist.]label[0.5,1.5;To use the settings menu, one or more mods that provide some settings must be installed.]button_exit[5,2;2,1;quit;Close]"
+ minetest.show_formspec(name,"playersettings:nosettings",form)
+ return
+ end
+ if not playersettings.highlighted[name] then playersettings.highlighted[name] = 1 end
+ local settingslist = ""
+ for _,setting in ipairs(playersettings.settingslist) do
+ settingslist = settingslist..minetest.formspec_escape(playersettings.registered[setting].shortdesc)..","
+ end
+ settingslist = settingslist:sub(1,-2)
+ local settingname = playersettings.settingslist[playersettings.highlighted[name]]
+ local def = playersettings.registered[settingname]
+ local extras = ""
+ if def.type == "boolean" then
+ extras = "checkbox[8,8;checkbox;Enabled;%s]"
+ extras = extras:format(playersettings.get(name,settingname) and "true" or "false")
+ elseif def.type == "string" then
+ extras = "field[8,8;6,1;field;Enter value:;%s]label[8,9.5;Allowed values: %s]field_close_on_enter[field;false]"
+ extras = extras:format(minetest.formspec_escape(playersettings.get(name,settingname)),minetest.formspec_escape(def.values or "any string"))
+ elseif def.type == "number" then
+ extras = "field[8,8;6,1;field;Enter value:;%s]label[8,9.5;Allowed values: %s]field_close_on_enter[field;false]"
+ local allowed = "any number"
+ if def.min and def.max then
+ allowed = "numbers "..def.min.." to "..def.max
+ elseif def.max then
+ allowed = "numbers up to "..def.max
+ elseif def.min then
+ allowed = "numbers "..def.min.." and up"
+ end
+ if def.integer then
+ allowed = allowed.." (whole numbers only)"
+ end
+ extras = extras:format(minetest.formspec_escape(playersettings.get(name,settingname)),allowed)
+ elseif def.type == "enum" then
+ extras = "dropdown[8,8;6,1;dropdown;%s;%d;false]"
+ local choices = ""
+ local current = playersettings.get(name,settingname)
+ local selected = 1
+ for k,v in ipairs(def.values) do
+ choices = choices..minetest.formspec_escape(v)..","
+ if v == current then selected = k end
+ end
+ choices = choices:sub(1,-2)
+ extras = extras:format(choices,selected)
+ end
+ local form = playersettings.form:format(settingslist,playersettings.highlighted[name],minetest.formspec_escape(def.shortdesc),minetest.formspec_escape(def.longdesc),extras)
+ minetest.show_formspec(name,"playersettings:settings",form)
+end
+
+function playersettings.handleform(player,form,fields)
+ if form ~= "playersettings:settings" then return end
+ local name = player:get_player_name()
+ local settingname = playersettings.settingslist[playersettings.highlighted[name]]
+ local def = playersettings.registered[settingname]
+ if def.type == "boolean" and fields.checkbox then
+ playersettings.set(name,settingname,fields.checkbox == "true")
+ elseif def.type == "enum" and fields.dropdown then
+ playersettings.set(name,settingname,fields.dropdown)
+ elseif def.type == "number" and fields.field then
+ local value = tonumber(fields.field)
+ if value
+ and ((not def.max) or (value <= def.max))
+ and ((not def.min) or (value >= def.min)) then
+ if def.integer then value = math.floor(value) end
+ playersettings.set(name,settingname,value)
+ end
+ elseif def.type == "string" and fields.field then
+ playersettings.set(name,settingname,fields.field)
+ end
+ if fields.settinglist then
+ local exp = minetest.explode_textlist_event(fields.settinglist)
+ if exp.type == "CHG" then
+ playersettings.highlighted[name] = exp.index
+ playersettings.openform(player)
+ end
+ end
+ if fields.quit then
+ minetest.close_formspec(name,"playersettings:settings")
+ end
+end
+
+function playersettings.getdefault(setting)
+ local def = playersettings.registered[setting]
+ if def.default ~= nil then return def.default end
+ if def.type == "boolean" then
+ return false
+ elseif def.type == "number" then
+ return def.min or 0
+ elseif def.type == "string" then
+ return ""
+ end
+end
+
+function playersettings.get(name,setting)
+ assert(type(name) == "string",string.format("Invalid player name (expected string, got %s)",type(name)))
+ assert(type(setting) == "string",string.format("Invalid setting name (expected string, got %s)",type(setting)))
+ assert(playersettings.registered[setting],"No such setting: "..setting)
+ local value = minetest.deserialize(storage:get_string(string.format("%s|%s",name,setting)))
+ if value then
+ return value
+ else
+ return playersettings.getdefault(setting)
+ end
+end
+
+function playersettings.set(name,setting,value)
+ assert(type(name) == "string",string.format("Invalid player name (expected string, got %s)",type(name)))
+ assert(type(setting) == "string",string.format("Invalid setting name (expected string, got %s)",type(setting)))
+ assert(playersettings.registered[setting],"No such setting: "..setting)
+ local old = playersettings.get(name,setting)
+ local def = playersettings.registered[setting]
+ if def.onchange then
+ if not def.onchange(name,old,value) then return end
+ end
+ storage:set_string(string.format("%s|%s",name,setting),minetest.serialize(value))
+ if def.afterchange then def.afterchange(name,old,value) end
+end
+
+function playersettings.register(setting,def)
+ assert(type(setting) == "string",string.format("Invalid setting name (expected string, got %s)",type(setting)))
+ assert(not playersettings.registered[setting],string.format("Setting %s already defined",setting))
+ assert(type(def) == "table",string.format("Invalid setting definition (expected table, got %s)",type(def)))
+ table.insert(playersettings.settingslist,setting)
+ table.sort(playersettings.settingslist)
+ playersettings.registered[setting] = def
+end
+
+function playersettings.onjoin(player)
+ local name = player:get_player_name()
+ for setting,def in pairs(playersettings.registered) do
+ if type(def.onjoin) == "function" then
+ def.onjoin(name,playersettings.get(name,setting))
+ end
+ end
+end
+
+if minetest.get_modpath("unified_inventory") then
+ unified_inventory.register_button("playersettings",
+ {
+ action = playersettings.openform,
+ tooltip = "Settings",
+ type = "image",
+ image = "playersettings_settings_button.png"
+ }
+ )
+end
+
+minetest.register_chatcommand("settings",{
+ description = "Open player settings menu",
+ func = playersettings.openform,
+})
+
+minetest.register_on_joinplayer(playersettings.onjoin)
+minetest.register_on_player_receive_fields(playersettings.handleform)
diff --git a/mod.conf b/mod.conf
new file mode 100644
index 0000000..66ae225
--- /dev/null
+++ b/mod.conf
@@ -0,0 +1,5 @@
+name = playersettings
+description = Per-Player Settings System
+optional_depends = unified_inventory
+author = cheapie
+title = Per-Player Settings System
diff --git a/textures/playersettings_settings_button.png b/textures/playersettings_settings_button.png
new file mode 100644
index 0000000..124b098
--- /dev/null
+++ b/textures/playersettings_settings_button.png
Binary files differ