staff/init.lua

207 lines
6.2 KiB
Lua

-- staff mod for Blocky Survival
-- copyright (c) 2019 BillyS
local ienv = minetest.request_insecure_environment()
local wp = minetest.get_worldpath()
-- Open database
if not ienv then
error("The staff mod requires an insecure environment; please add this mod as trusted")
end
local sqlite = ienv.require("lsqlite3")
local db = sqlite.open(wp .. "/staff.sqlite")
-- Close on shutdown
minetest.register_on_shutdown(function()
db:close_vm(false)
db:close()
end)
-- Functions
local function log_error()
minetest.log("error", "[staff]: SQLite error: " .. db:errmsg())
end
local function first_row(ps)
for r in ps:nrows() do return r end -- luacheck: ignore
return nil
end
local function get_rank_by_uid(ruid)
local ps = db:prepare("SELECT name FROM ranks WHERE rowid=:rowid")
ps:bind_values(ruid)
return first_row(ps).name
end
local function execute_sql(sql, func)
local code = db:exec(sql, func)
if code ~= sqlite.OK then
minetest.log("error", "[staff]: SQLite error: " .. db:errmsg())
return false
end
return true
end
-- Create tables if needed
execute_sql("CREATE TABLE IF NOT EXISTS ranks(name VARCHAR(50), UNIQUE(name));" ..
"CREATE TABLE IF NOT EXISTS staff(" ..
"name VARCHAR(50) NOT NULL," ..
"rank_uid INTEGER NOT NULL," ..
"UNIQUE(name)" ..
"FOREIGN KEY(rank_uid) REFERENCES ranks(rowid));")
local function format_tag(pname, rank)
return minetest.colorize("#00FF00", "[" .. rank .. "] ") .. pname
end
-- Register chat commands
ChatCmdBuilder.new("staff", function(cmd)
cmd:sub("add rank :rank", function(name, rank)
local ps = db:prepare("INSERT INTO ranks(name) VALUES (:rank)")
ps:bind_values(rank)
local code = ps:step()
if code == sqlite.DONE then
return true, "Rank '" .. rank .. "' created"
elseif code == sqlite.CONSTRAINT then
return false, "Rank '" .. rank .. "' already exists"
else
log_error()
return false, "SQLite error code " .. tostring(code) .. ": See server logs"
end
end)
cmd:sub("rename rank :old :new", function(name, old, new)
local ps = db:prepare("UPDATE ranks SET name=:new WHERE name=:old")
ps:bind_values(new, old)
local code = ps:step()
if code == sqlite.DONE then
if db:changes() == 0 then
return false, "No such rank '" .. old .. "'"
else
return true, "Rank '" .. old .. "' renamed to '" .. new .. "'"
end
elseif code == sqlite.CONSTRAINT then
return false, "There is already a rank named '" .. new .. "'"
else
log_error()
return false, "SQLite error code " .. tostring(code) .. ": See server logs"
end
end)
cmd:sub("remove rank :rank", function(name, rank)
local ps = db:prepare("DELETE FROM ranks WHERE name=:rank")
ps:bind_values(rank)
local code = ps:step()
if code == sqlite.DONE then
if db:changes() == 0 then
return false, "No such rank '" .. rank .. "'"
else
return true, "Removed rank '" .. rank .. "'"
end
else
log_error()
return false, "SQLite error code " .. tostring(code) .. ": See server logs"
end
end)
cmd:sub("list ranks", function(name)
local rtext = ""
for rank in db:urows("SELECT name FROM ranks") do
rtext = rtext .. rank .. "\n"
end
return true, rtext
end)
cmd:sub("add staff :name :rank", function(name, staff, rank)
local ps = db:prepare("SELECT rowid FROM ranks WHERE name=:rank")
ps:bind_values(rank)
local ruid = first_row(ps)
if ruid == nil then
return false, "No such rank '" .. rank .. "'"
end
ruid = ruid.rowid
ps = db:prepare("INSERT INTO staff(name, rank_uid) VALUES(:name, :ruid)")
ps:bind_values(staff, ruid)
local code = ps:step()
if code == sqlite.DONE then
local player = minetest.get_player_by_name(staff)
if player then
local tag = format_tag(staff, rank)
more_monoids.player_tag:add_change(player, tag, "staff")
end
return true, "Added staff member '" .. staff .. "' with rank '" .. rank .. "'"
elseif code == sqlite.CONSTRAINT then
return false, "'" .. staff .. "' is already a staff member"
else
log_error()
return false, "SQLite error code " .. tostring(code) .. ": See server logs"
end
end)
cmd:sub("remove staff :name", function(name, staff)
local ps = db:prepare("DELETE FROM staff WHERE name=:name")
ps:bind_values(staff)
local code = ps:step()
if code == sqlite.DONE then
if db:changes() == 0 then
return false, "No such staff member '" .. staff .. "'"
else
return true, "Staff member '" .. staff .. "' removed"
end
else
log_error()
return false, "SQLite error code " .. tostring(code) .. ": See server logs"
end
end)
cmd:sub("list staff", function(name)
local stext = ""
for sname, ruid in db:urows("SELECT name,rank_uid FROM staff") do
local rank = get_rank_by_uid(ruid)
stext = stext .. sname .. ": " .. rank .. "\n"
end
return true, stext
end)
cmd:sub("help", function (name)
return true, "Commands:\n" ..
"add rank <rank>\n" ..
"rename rank <rank> <new name>\n" ..
"remove rank <rank>\n" ..
"list ranks\n" ..
"add staff <name> <rank>\n" ..
"remove staff <name>\n" ..
"list staff"
end)
end, {
description = "Modify staff ranks",
privs = {
server = true,
}
})
-- Modify nametag
local name_ps = db:prepare("SELECT name, rank_uid FROM staff WHERE name=:name")
minetest.register_on_joinplayer(function(player)
local pname = player:get_player_name()
name_ps:bind_values(pname)
local fr = first_row(name_ps)
if fr ~= nil then
local rank = get_rank_by_uid(fr.rank_uid)
local tag = format_tag(pname, rank)
more_monoids.player_tag:add_change(player, tag, "staff")
else
more_monoids.player_tag:add_change(player, pname, "staff")
end
name_ps:reset()
end)
minetest.register_on_leaveplayer(function(player)
more_monoids.player_tag:del_change(player, "staff")
end)