Initial commit

This commit is contained in:
octacian 2017-05-19 08:37:08 -07:00
commit c568c3a793
7 changed files with 500 additions and 0 deletions

BIN
.gh-screenshot.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 504 KiB

72
API.md Normal file
View File

@ -0,0 +1,72 @@
Ranks API
=========
The ranks API allows you to register, unregister, and manage ranks.
`ranks.register(name, def)`
* Register a new rank
* `name`: Name for rank (name cannot be `clear`)
* `def`: See [#Rank definition]
`ranks.unregister(name)`
* Unregister a rank
* `name`: Name of rank
`ranks.list_plaintext()`
* Returns a plaintext, comma-separated list of ranks
`ranks.get_rank(player)`
* Returns the player's rank or `nil`
* `player`: PlayerRef or string
`ranks.get_def(name)`
* Returns the rank definition or `nil`
* `name`: Name of rank
`ranks.update_privs(player)`
* Checks and updates player privileges based on rank definition
* Returns `true` if successful, `nil` if player has no rank
* Automatically called `on_joinplayer` and on `ranks.set_rank`
* `player`: PlayerRef or string
`ranks.update_nametag(player)`
* Checks and updates player nametag based on rank definition
* Returns `true` if successful, `nil` if player has no rank
* Automatically called `on_joinplayer` and on `ranks.set_rank`
* `player`: PlayerRef or string
`ranks.set_rank(player, rank)`
* Changes a player's rank
* Returns `true` if successful, `nil` if rank doesn't exist
* `player`: PlayerRef or string
* `rank`: Name of rank
`ranks.remove_rank(player)`
* Removes all ranking information from a player
* `player`: PlayerRef or string
#### Rank definition
```lua
{
prefix = "Moderator", -- Prefix to be shown on nametag and chat
colour = {a = 255, r = 255, g = 83, b = 37}, -- A table of RGBA values or a single base colour (e.g. "red")
strict_privs = false, -- Whether the rank should have a strict set of privileges (prevents privileges from being granted/revoked)
grant_missing = true, -- Whether missing privileges should be automatically granted
revoke_extra = false, -- Whether extra privileges should be automatically revoked
privs = { -- Default privileges (usage modified by above items)
interact = true,
shout = true,
fly = true,
fast = true,
...
}
}
```

51
README.md Normal file
View File

@ -0,0 +1,51 @@
![Screenshot](.gh-screenshot.png)
Advanced Ranks [ranks]
=======================
- GitHub: https://github.com/octacian/ranks
- Download: https://github.com/octacian/ranks/archive/master.zip
**Warning:** Ranks uses important features currently only available in development builds of Minetest. In order to use Ranks, you'll need to [build](https://forum.minetest.net/viewtopic.php?id=3837) Minetest yourself with [this commit](https://github.com/minetest/minetest/pull/5716) or newer (May 7th, 2016).
Ranks is an advanced ranks mod geared towards larger servers helps to both distiguish between players and make managing privileges much easier. With several ranks premade and a simplistic API, ranks is a good addition to any server, especially those with many players.
This mod was made in an effort to solve two problems. One of these is new players getting confused when they see moderators or administrators doing things that normal players cannot, resulting in repeated accusations of hacking. Ranks allows there to be no confusion between what a player should or should not be able to do, as their rank is displayed in both their nametag and as a prefix to chat messages sent by them.
Displaying the rank prefix on a player's nametag can be disabled by setting `ranks.prefix_nametag = false` in `minetest.conf`, while prefixes before chat messages can be disabled with `ranks.prefix_chat = false`.
Ranks also attempts to make privilege updates easier by allowing you to assign a set of privileges to each rank allowing a strict set of privileges for that rank, automatically granting missing privileges, and automatically revoking extra privileges (configurable per-rank). This means that when a player is given a rank with privilege definitions, they will automatically inherit the privileges specified. Whenever `/grant`, `/grantme`, or `/revoke` is called on a player, their privileges are updated according to rank and a warning is sent to the player who called the chatcommand if privileges are modified further.
### Packaged Ranks
By default, four ranks are included with the ranks mod, however, they are only for decoration purposes and do not modify any privileges as they should be configured by each server owner.
* Admin (`admin`)
* Moderator (`moderator`)
* Guardian (`guardian`)
* YouTube (`youtube`)
The above demonstrates that while ranks can be useful for managing privileges, it can also be a very nice form of progression/recognition.
### Usage
Ranks introduces two chatcommands, `/getrank` and `/rank`. The first allows you to get a player's rank while the latter allows you to set a player's rank and requires the `rank` chatcommand. **Note**: the player whose username is the same as the administrator (defined by `name` in `minetest.conf`) will automatically be granted the `rank` privilege.
**`/rank` Usage:**
```
Name or operation is either a player name, or "list" to list ranks
If the operation is "list", no new rank is needed
Setting new rank to "clear" causes all rank information to be removed from the player
/rank <name or operation> <new rank>
```
**`/getrank` Usage:**
```
Name is the name of the player whose rank you wish to retrieve
If name is blank, your own rank is returned
/getrank <name>
```
### Creating Ranks
You can create your own ranks and learn about privilege management in the API documentation. It explains how to manage privileges and register ranks with the `ranks.register` function. Registrations can be made either in the `ranks.lua` file of the mod itself (where default ranks or unregistered), or they can be preferrably placed in a `ranks.lua` file inside the world directory.
If you don't want one of the built in ranks, you can either register a new rank with the same name (effectively overriding the rank) or learn about `ranks.unregister` which can also be called from the world file.

355
init.lua Normal file
View File

@ -0,0 +1,355 @@
-- ranks/init.lua
ranks = {}
local registered = {}
local default
---
--- API
---
-- [function] Register rank
function ranks.register(name, def)
assert(name ~= "clear", "Invalid name \"clear\" for rank")
registered[name] = def
if def.default then
default = name
end
end
-- [function] Unregister rank
function ranks.unregister(name)
registered[name] = nil
end
-- [function] List ranks in plain text
function ranks.list_plaintext()
local list = ""
for rank, i in pairs(registered) do
if list == "" then
list = rank
else
list = list..", "..rank
end
end
return list
end
-- [function] Get player rank
function ranks.get_rank(player)
if type(player) == "string" then
player = minetest.get_player_by_name(player)
end
local rank = player:get_attribute("ranks:rank")
if rank and registered[rank] then
return rank
end
end
-- [function] Get rank definition
function ranks.get_def(rank)
if not rank then
return
end
return registered[rank]
end
-- [function] Update player privileges
function ranks.update_privs(player, trigger)
if type(player) == "string" then
player = minetest.get_player_by_name(player)
end
local name = player:get_player_name()
local rank = ranks.get_rank(player)
if rank then
-- [local function] Warn
local function warn(msg)
if msg and trigger and minetest.get_player_by_name(trigger) then
minetest.chat_send_player(trigger, minetest.colorize("red", "Warning: ")..msg)
end
end
local def = registered[rank]
if not def.privs then
return
end
if def.strict_privs == true then
minetest.set_player_privs(name, def.privs)
warn(name.."'s privileges have been reset to that of their rank (strict privileges)")
return true
end
local privs = minetest.get_player_privs(name)
if def.grant_missing == true then
local changed = false
for name, priv in pairs(def.privs) do
if not privs[name] and priv == true then
privs[name] = priv
changed = true
end
end
if changed then
warn("Missing rank privileges have been granted to "..name)
end
end
if def.revoke_extra == true then
local changed = false
for name, priv in pairs(privs) do
if not def.privs[name] then
privs[name] = nil
changed = true
end
end
if changed then
warn("Extra non-rank privileges have been revoked from "..name)
end
end
local admin = player:get_player_name() == minetest.settings:get("name")
-- If owner, grant `rank` privilege
if admin then
local name = player:get_player_name()
local privs = minetest.get_player_privs(name)
privs["rank"] = true
minetest.set_player_privs(name, privs)
end
minetest.set_player_privs(name, privs)
return true
end
end
-- [function] Update player nametag
function ranks.update_nametag(player)
if minetest.settings:get("ranks.prefix_nametag") == "false" then
return
end
if type(player) == "string" then
player = minetest.get_player_by_name(player)
end
local name = player:get_player_name()
local rank = ranks.get_rank(player)
if rank then
local def = ranks.get_def(rank)
local colour = def.colour or "#ffffff"
local prefix = def.prefix
if prefix then
prefix = prefix.." "
else
prefix = ""
end
player:set_nametag_attributes({
text = prefix..name,
color = colour,
})
return true
end
end
-- [function] Set player rank
function ranks.set_rank(player, rank)
if type(player) == "string" then
player = minetest.get_player_by_name(player)
end
if registered[rank] then
-- Set attribute
player:set_attribute("ranks:rank", rank)
-- Update nametag
ranks.update_nametag(player)
-- Update privileges
ranks.update_privs(player)
return true
end
end
-- [function] Remove rank from player
function ranks.remove_rank(player)
if type(player) == "string" then
player = minetest.get_player_by_name(player)
end
local rank = ranks.get_rank(player)
if rank then
local name = player:get_player_name()
-- Clear attribute
player:set_attribute("ranks:rank", nil)
-- Update nametag
player:set_nametag_attributes({
text = name,
color = "#ffffff",
})
-- Update privileges
local basic_privs =
core.string_to_privs(core.settings:get("basic_privs") or "interact,shout")
minetest.set_player_privs(name, basic_privs)
end
end
---
--- Registrations
---
-- [privilege] Rank
minetest.register_privilege("rank", {
description = "Permission to use /rank chatcommand",
give_to_singleplayer = false,
})
-- Assign/update rank on join player
minetest.register_on_joinplayer(function(player)
if ranks.get_rank(player) then
-- Update nametag
ranks.update_nametag(player)
-- Update privileges
ranks.update_privs(player)
else
if ranks.default then
ranks.set_rank(player, ranks.default)
end
end
end)
-- Prefix messages if enabled
minetest.register_on_chat_message(function(name, message)
if minetest.settings:get("ranks.prefix_chat") ~= "false" then
local rank = ranks.get_rank(name)
if rank then
local def = ranks.get_def(rank)
if def.prefix then
local colour = def.colour or "#ffffff"
minetest.chat_send_all(minetest.colorize(colour, def.prefix)..
" <"..name.."> "..message)
return true
end
end
end
end)
--[chatcommand] /rank
minetest.register_chatcommand("rank", {
description = "Set a player's rank",
params = "<player> <new rank> / \"list\" | username, rankname / list ranks",
privs = {rank = true},
func = function(name, param)
local param = param:split(" ")
if #param == 0 then
return false, "Invalid usage (see /help rank)"
end
if #param == 1 and param[1] == "list" then
return true, "Available Ranks: "..ranks.list_plaintext()
elseif #param == 2 then
if minetest.get_player_by_name(param[1]) then
if ranks.get_def(param[2]) then
if ranks.set_rank(param[1], param[2]) then
if name ~= param[1] then
minetest.chat_send_player(param[1], name.." set your rank to "..param[2])
end
return true, "Set "..param[1].."'s rank to "..param[2]
else
return false, "Unknown error while setting "..param[1].."'s rank to "..param[2]
end
elseif param[2] == "clear" then
ranks.remove_rank(param[1])
return true, "Removed rank from "..param[1]
else
return false, "Invalid rank (see /rank list)"
end
else
return false, "Invalid player \""..param[1].."\""
end
else
return false, "Invalid usage (see /help rank)"
end
end,
})
-- [chatcommand] /getrank
minetest.register_chatcommand("getrank", {
description = "Get a player's rank. If no player is specified, your own rank is returned.",
params = "<name> | name of player",
func = function(name, param)
if param and param ~= "" then
if minetest.get_player_by_name(param) then
local rank = ranks.get_rank(param) or "No rank"
return true, "Rank of "..param..": "..rank
else
return false, "Invalid player \""..name.."\""
end
else
local rank = ranks.get_rank(name) or "No rank"
return false, "Your rank: "..rank
end
end,
})
---
--- Overrides
---
local grant = minetest.registered_chatcommands["grant"].func
-- [override] /grant
minetest.registered_chatcommands["grant"].func = function(name, param)
local ok, msg = grant(name, param) -- Call original function
local grantname, grantprivstr = string.match(param, "([^ ]+) (.+)")
if grantname then
ranks.update_privs(grantname, name) -- Update privileges
end
return ok, msg
end
local grantme = minetest.registered_chatcommands["grantme"].func
-- [override] /grantme
minetest.registered_chatcommands["grantme"].func = function(name, param)
local ok, msg = grantme(name, param) -- Call original function
ranks.update_privs(name, name) -- Update privileges
return ok, msg
end
local revoke = minetest.registered_chatcommands["revoke"].func
-- [override] /revoke
minetest.registered_chatcommands["revoke"].func = function(name, param)
local ok, msg = revoke(name, param) -- Call original function
local revokename, revokeprivstr = string.match(param, "([^ ]+) (.+)")
if revokename then
ranks.update_privs(revokename, name) -- Update privileges
end
return ok, msg
end
---
--- Ranks
---
-- Load default ranks
dofile(minetest.get_modpath("ranks").."/ranks.lua")
local path = minetest.get_worldpath().."/ranks.lua"
-- Attempt to load per-world ranks
if io.open(path) then
dofile(path)
end

1
mod.conf Normal file
View File

@ -0,0 +1 @@
name = ranks

21
ranks.lua Normal file
View File

@ -0,0 +1,21 @@
-- ranks/ranks.lua
ranks.register("admin", {
prefix = "Admin",
colour = {a = 255, r = 230, g = 33, b = 23},
})
ranks.register("moderator", {
prefix = "Moderator",
colour = {a = 255, r = 255, g = 83, b = 37},
})
ranks.register("guardian", {
prefix = "Guardian",
colour = {a = 255, r = 255, g = 132, b = 0},
})
ranks.register("youtube", {
prefix = "YouTube",
colour = {a = 255, r = 255, g = 80, b = 71},
})

BIN
screenshot.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 547 KiB