minetest_collective/init.lua
Bill Niblock f1553e6c8e First Upload of Collective
This first upload includes a relatively full and untested version of
Collective. Much should be done still.

- README.md: Basic repository and code information
- init.lua: The first implementation of collective. Entirely tested on a
  single-player server, meaning much of the multi-person aspects are
  currently untested. This is first priority.
- mod.conf: Standard Minetest mod stuff

TO-DO:

- Test Collective on a multi-player server with multiple people.
2022-05-25 18:00:39 -04:00

357 lines
11 KiB
Lua

local mod_storage = minetest.get_mod_storage()
local collective = {}
-- ###################
-- #### FUNCTIONS ####
-- ###################
function collective.disband(name)
--[[
Disbands name's collective.
Params:
name[string]: current player's name
]]--
if not collective.in_collective(name) then
minetest.chat_send_player(name, "You're not in a collective.")
return
end
local player = minetest.get_player_by_name(name)
local pmeta = player:get_meta()
pmeta:set_string("collective", "")
minetest.chat_send_player(name, "Disbanding collective.")
local members = {}
members = minetest.deserialize(mod_storage:get_string(name))
for i, p in pairs(members) do
if name ~= p then
local exists = minetest.get_player_by_name(p)
if exists then
local cmeta = p:get_meta()
local membership = cmeta:get_string("collective")
if membership == name then
cmeta:set_string("collective", "")
minetest.chat_send_player(p, name.."'s collective has been disbanded")
end
end
end
end
mod_storage:set_string(name, "")
end
function collective.invite(name, param)
--[[
Invite users to join name's collective.
Params:
name[string]: current player's name
param[list]: list of player name strings
]]--
if not collective.in_collective(name) then
minetest.chat_send_player(name, "You're not in a collective. Use /collective start to make one.")
return
end
local players = {}
if #param > 0 then
players = param
else
minetest.chat_send_player(name, "Usage: /collective invite <player name> [player name]...")
return
end
for i, p in pairs(players) do
local exists = minetest.get_player_by_name(p)
local membership = collective.in_collective(p)
if exists then
if membership then
minetest.chat_send_player(name, "Player "..p.." already in a collective.")
minetest.chat_send_player(p, "You've been invited to "..name.."'s collective, but you can only be in one collective at a time.")
else
table.append(mod_storage[name], p)
minetest.chat_send_player(p, "You've been invited to "..name.."'s collective. Type /collective join "..name.." to join.")
minetest.chat_send_player(name, "Player "..p.." invited to your collective.")
end
else
minetest.chat_send_player(name, "Player "..p.." doesn't exist!")
end
end
end
function collective.join(name, param)
--[[
Join a collective. Requires being invited by the collective owner
Params:
name[string]: current player's name
param[list]: list of player name strings; expecting a single value
]]--
if collective.in_collective(name) then
minetest.chat_send_player(name, "You're already in a collective!")
return
end
if #param ~= 1 then
minetest.chat_send_player(name, "Usage: /collective join <player name>")
return
end
local player = minetest.get_player_by_name(name)
local pmeta = player:get_meta()
local members = mod_storage:get_string(param)
if members then
if collective.membership(name, members) then
pmeta:set_string("collective", param)
table.append(mod_storage[name], p)
minetest.chat_send_player(name, "You've joined "..name.."'s collective.")
else
minetest.chat_send_player(name, param.." has not established a collective.")
end
end
function collective.kick(name, param)
--[[
Kick a player from name's collective.
Params:
name[string]: current player's name
param[list]: list of player name strings; expecting a single value
]]--
if not collective.in_collective(name) then
minetest.chat_send_player(name, "You're not in a collective.")
return
end
if #param ~= 1 then
minetest.chat_send_player(name, "Usage: /collective kick <player name>")
return
end
if name == param[1] then
minetest.chat_send_player(name, "Cannot kick self! Use /collective disband")
return
end
local exists = minetest.get_player_by_name(param[1])
local member = collective.membership(name, param[1])
if exists then
if member then
minetest.chat_send_player(name, "Kicking "..param[1].." from your collective.")
collective.reform(name, param)
minetest.chat_send_player(param[1], "You have been kicked from "..name.."'s collective.")
else
minetest.chat_send_player(name, param[1].." is not a member of your collective.")
end
else
minetest.chat_send_player(name, param[1].." is not an active player.")
end
end
function collective.leave(name)
--[[
Leave a collective, if currently in one. If name is the owner of the
collective, also disband the collective.
Params:
name[string]: current player's name
]]--
if not collective.in_collective(name) then
minetest.chat_send_player(name, "You're not in a collective.")
return
end
local player = minetest.get_player_by_name(name)
local pmeta = player:get_meta()
local membership = pmeta:get_string("collective")
if name == membership then
collective.disband(name)
else
collective.reform(membership, name)
pmeta:set_string("collective", "")
minetest.chat_send_player(name, "You have left "..membership.."'s collective.")
minetest.chat_send_player(membership, name.." has left your collective.")
end
end
function collective.start(name, param)
--[[
Start a collective, and invite players if provided.
Params:
name[string]: current player's name
param[list]: list of player name strings
]]--
if collective.in_collective(name) then
minetest.chat_send_player(name, "You're already in a collective!")
return
end
local players = {}
if #param > 0 then
players = param
end
local player = minetest.get_player_by_name(name)
local pmeta = player:get_meta()
pmeta:set_string("collective", name)
mod_storage:set_string(name, minetest.serialize({name}))
minetest.chat_send_player(name, "Collective established!")
collective.invite(name, players)
end
function collective.status(name)
--[[
Shows current collective information
Params:
name[string]: current player's name
]]--
local player = minetest.get_player_by_name(name)
local pmeta = player:get_meta()
local player_collective = pmeta:get_string("collective")
minetest.chat_send_player(name, "Current collective: "..player_collective)
local members = mod_storage:get_string(name)
minetest.chat_send_player(name, "Collective members: "..members)
end
-- ##########################
-- #### HELPER FUNCTIONS ####
-- ##########################
function collective.in_collective(name)
--[[
Check if a player is in any collectives
Params:
name[string]: player name
Returns:
boolean; false if the player's "collective" metadata is "" or nil
true otherwise
]]--
local player = minetest.get_player_by_name(name)
local pmeta = player:get_meta()
local membership = pmeta:get_string("collective")
if membership == "" or membership == nil then
return false
else
return true
end
end
function collective.membership(name, param)
--[[
Check if current player is a member of a specific collective
Params:
name[string]: current player's name
param[list]: list of player name strings; expecting a single value
Returns:
boolean; true if name is a member of param's collective
false otherwise
]]--
local members = mod_storage:get_string(param)
if string.match(cmeta, name) then
return true
else
return false
end
end
function collective.print_usage()
--[[
Print the /collective usage message
Returns:
string; the usage message
]]--
return "Usage: /collective [join,leave,start,disband] [player {,player...}]"
end
function collective.reform(name, param)
--[[
Reform name's collective without param
Params:
name[string]: player's name; used for collective
param[list]: list of player name strings
]]--
local members = {}
members = minetest.deserialize(mod_storage:get_string(name))
local new_members = {}
-- For each member of the collective, and each player provided in param, if
-- the member does not match the param, add the member to the new_members
-- list.
--
-- This is expensive. Is there a better way to handle this?
for i,m in pairs(members) do
for j,p in pairs(param) do
if not m == p then table.append(new_members, m) end
end
end
mod_storage:set_string(name, minetest.serialize(new_members))
end
-- #######################
-- #### CHAT COMMANDS ####
-- #######################
minetest.register_chatcommand("collective", {
func = function(name, param)
if #param <= 0 then
return false, collective.print_usage()
end
local player = minetest.get_player_by_name(name)
if not player then
return false, "You must be online to interact with the collective."
end
local parsed = {}
for w in string.gmatch(param, "%g+") do
table.insert(parsed, w)
end
local command = table.remove(parsed, 1)
if command == "start" then
collective.start(name, parsed)
return true
elseif command == "invite" then
collective.invite(name, parsed)
return true
elseif command == "join" then
collective.join(name, parsed)
return true
elseif command == "leave" then
collective.leave(name)
return true
elseif command == "kick" then
collective.leave(name, parsed)
return true
elseif command == "disband" then
collective.disband(name)
return true
elseif command == "status" then
collective.status(name)
return true
else
return false, collective.print_usage()
end
end,
})