This thread seems to have digressed a bit towards the concrete example of storing mod data, so I'm going to address that first. For reference, the "first mod" in my example,
Thirsty, does loading and saving of per-player values like this:
Your phone or window isn't wide enough to display the code box. If it's a phone, try rotating it to landscape mode.
- Code: Select all
function thirsty.read_stash()
local filename = minetest.get_worldpath() .. "/" .. thirsty.config.stash_filename
local file, err = io.open(filename, "r")
if not file then
-- no problem, its just not there
-- TODO: or parse err?
return
end
thirsty.players = {}
for line in file:lines() do
if string.match(line, '^%-%-') then
-- comment, ignore
elseif string.match(line, '^P [%d.]+ [%d.]+ .+') then
-- player line
-- is matching again really the best solution?
local hydro, dmg, name = string.match(line, '^P ([%d.]+) ([%d.]+) (.+)')
thirsty.players[name] = {
hydro = tonumber(hydro),
last_pos = '0:0', -- not true, but no matter
time_in_pos = 0.0,
pending_dmg = tonumber(dmg),
thirst_factor = 1.0,
}
end
end
file:close()
end
function thirsty.write_stash()
local filename = minetest.get_worldpath() .. "/" .. thirsty.config.stash_filename
local file, err = io.open(filename, "w")
if not file then
minetest.log("error", "Thirsty: could not write " .. thirsty.config.stash_filename .. ": " ..err)
return
end
file:write('-- Stash file for Minetest mod [thirsty] --\n')
-- write players:
-- P <hydro> <pending_dmg> <name>
file:write('-- Player format: "P <hydro> <pending damage> <name>"\n')
for name, data in pairs(thirsty.players) do
file:write("P " .. data.hydro .. " " .. data.pending_dmg .. " " .. name .. "\n")
end
file:close()
end
Some explanation: I code Perl for a living, and as such am a bit wary of serializing data as code and eval'ing it to deserialize it (which is what I remember seeing the MT functions do), but I love me some regular expressions, so that's the hammer I use :-P
Still, I need to take care of IO myself, including error handling. In contrast, storing values in hidden inventory fields is
very hackish, but I wouldn't call it bad: it uses internal, very well tested code (imagine if inventories "sometimes didn't work"), it does not create any additional files, and is guaranteed to work across all versions, updates or other changes that themselves guarantee to preserve inventories.
Code snippet from the second mod,
Beware the Dark, for completeness (needs refactoring, this is all hardcoded to get it out the door):
Your phone or window isn't wide enough to display the code box. If it's a phone, try rotating it to landscape mode.
- Code: Select all
-- setup on_joinplayer:
inv:set_size("bewarethedark_sanity", 1)
if inv:is_empty("bewarethedark_sanity") then
inv:set_stack("bewarethedark_sanity", 1, ItemStack({ name = ":", count = 65535 }))
end
-- get value
local sanity = inv:get_stack("bewarethedark_sanity", 1):get_count() / 65535.0 * 20.0;
-- set value
local inv_count = sanity / 20.0 * 65535.0
if inv_count > 65535 then inv_count = 65535 end
if inv_count < 0 then inv_count = 0 end
inv:set_stack("bewarethedark_sanity", 1, ItemStack({ name = ":", count = inv_count}))
Back to the actual question: Consensus seems to be "make it a library mod to depend on". My problem with this approach is the burden it places on the user of the mod: if [bewarethedark] depends on, say, [playerdata], then every user of [bewarethedark] needs to track down and install [playerdata], and keep it up to date. If the moddb does these installations of dependencies, that helps, but still shows [playerdata] in the mod list, and requires the user (not just server owners, but regular players) to remember to enable it / not to uninstall it, even if they "don't see the point".
(Apologies if I'm getting things wrong, I'm new to Minetest, if that's not apparent by now ;-) )
The appeal of "mixins" for me is that they are invisible to mod users, and are distributed
with the mods that use them. Sort of like "header libraries" in C++ (e.g.
Boost).
For now, I'm the only one using my code anyway, so I'll go ahead and try out the mixin idea ;-)