Initial Commit

master
rubenwardy 2016-12-30 22:08:38 +00:00
commit 49241b8a50
6 changed files with 417 additions and 0 deletions

85
.gitignore vendored Normal file
View File

@ -0,0 +1,85 @@
# Created by https://www.gitignore.io/api/lua,linux,windows
### Lua ###
# Compiled Lua sources
luac.out
# luarocks build files
*.src.rock
*.zip
*.tar.gz
# Object files
*.o
*.os
*.ko
*.obj
*.elf
# Precompiled Headers
*.gch
*.pch
# Libraries
*.lib
*.a
*.la
*.lo
*.def
*.exp
# Shared objects (inc. Windows DLLs)
*.dll
*.so
*.so.*
*.dylib
# Executables
*.exe
*.out
*.app
*.i*86
*.x86_64
*.hex
### Linux ###
*~
# temporary files which can be created if a process still has a handle open of a deleted file
.fuse_hidden*
# KDE directory preferences
.directory
# Linux trash folder which might appear on any partition or disk
.Trash-*
# .nfs files are created when an open file is removed but is still being accessed
.nfs*
### Windows ###
# Windows thumbnail cache files
Thumbs.db
ehthumbs.db
ehthumbs_vista.db
# Folder config file
Desktop.ini
# Recycle Bin used on file shares
$RECYCLE.BIN/
# Windows Installer files
*.cab
*.msi
*.msm
*.msp
# Windows shortcuts
*.lnk
# End of https://www.gitignore.io/api/lua,linux,windows

231
ChatCmdBuilder.lua Normal file
View File

@ -0,0 +1,231 @@
perplayer_gamemode.ChatCmdBuilder = {}
local ChatCmdBuilder = perplayer_gamemode.ChatCmdBuilder
function ChatCmdBuilder.new(name, func, def)
def = def or {}
local cmd = ChatCmdBuilder.build(func)
cmd.def = def
def.func = cmd.run
minetest.register_chatcommand(name, def)
return cmd
end
local STATE_READY = 1
local STATE_PARAM = 2
local STATE_PARAM_TYPE = 3
local bad_chars = {}
bad_chars["("] = true
bad_chars[")"] = true
bad_chars["."] = true
bad_chars["%"] = true
bad_chars["+"] = true
bad_chars["-"] = true
bad_chars["*"] = true
bad_chars["?"] = true
bad_chars["["] = true
bad_chars["^"] = true
bad_chars["$"] = true
local function escape(char)
if bad_chars[char] then
return "%" .. char
else
return char
end
end
function ChatCmdBuilder.build(func)
local cmd = {
_subs = {}
}
function cmd:sub(route, func, def)
print("Parsing " .. route)
def = def or {}
if string.trim then
route = string.trim(route)
end
local sub = {
pattern = "^",
params = {},
func = func
}
-- End of param reached: add it to the pattern
local param = ""
local param_type = ""
local should_be_eos = false
local function finishParam()
if param ~= "" and param_type ~= "" then
print(" - Found param " .. param .. " type " .. param_type)
if param_type == "pos" then
sub.pattern = sub.pattern .. "%(? *([%d.]+) *, *([%d.]+) *, *([%d.]+) *%)?"
elseif param_type == "text" then
sub.pattern = sub.pattern .. "(*+)"
should_be_eos = true
elseif param_type == "number" then
sub.pattern = sub.pattern .. "([%d.]+)"
elseif param_type == "int" then
sub.pattern = sub.pattern .. "([%d]+)"
else
if param_type ~= "word" then
print("Unrecognised param_type=" .. param_type .. ", using 'word' type instead")
param_type = "word"
end
sub.pattern = sub.pattern .. "([^ ]+)"
end
table.insert(sub.params, param_type)
param = ""
param_type = ""
end
end
-- Iterate through the route to find params
local state = STATE_READY
for i = 1, #route do
local c = route:sub(i, i)
if should_be_eos then
error("Should be end of string. Nothing is allowed after a param of type text.")
end
if state == STATE_READY then
if c == ":" then
print(" - Found :, entering param")
state = STATE_PARAM
param_type = "word"
else
sub.pattern = sub.pattern .. escape(c)
end
elseif state == STATE_PARAM then
if c == ":" then
print(" - Found :, entering param type")
state = STATE_PARAM_TYPE
param_type = ""
elseif c:match("%W") then
print(" - Found nonalphanum, leaving param")
state = STATE_READY
finishParam()
sub.pattern = sub.pattern .. escape(c)
else
param = param .. c
end
elseif state == STATE_PARAM_TYPE then
if c:match("%W") then
print(" - Found nonalphanum, leaving param type")
state = STATE_READY
finishParam()
sub.pattern = sub.pattern .. escape(c)
else
param_type = param_type .. c
end
end
end
print(" - End of route")
finishParam()
print("Pattern: " .. sub.pattern)
table.insert(self._subs, sub)
end
if func then
func(cmd)
end
cmd.run = function(name, param)
print("Running <" .. name .. "> CMD " .. param)
for i = 1, #cmd._subs do
local sub = cmd._subs[i]
local res = { string.match(param, sub.pattern) }
if res then
local pointer = 1
local params = { name }
for j = 1, #sub.params do
local param = sub.params[j]
if param == "pos" then
local pos = {
x = tonumber(res[pointer]),
y = tonumber(res[pointer + 1]),
z = tonumber(res[pointer + 2])
}
table.insert(params, pos)
pointer = pointer + 3
elseif param == "number" or param == "int" then
table.insert(params, tonumber(res[pointer]))
pointer = pointer + 1
else
table.insert(params, res[pointer])
pointer = pointer + 1
end
end
return sub.func(unpack(params))
end
end
print("No matches")
end
return cmd
end
local function run_tests()
if not (ChatCmdBuilder.build(function(cmd)
cmd:sub("bar :one and :two:word", function(name, one, two)
if name == "singleplayer" and one == "abc" and two == "def" then
return true
end
end)
end))("singleplayer", "bar abc and def") then
error("Test 1 failed")
end
local move = ChatCmdBuilder.build(function(cmd)
cmd:sub("move :target to :pos:pos", function(name, target, pos)
if name == "singleplayer" and target == "player1" and
pos.x == 0 and pos.y == 1 and pos.z == 2 then
return true
end
end)
end)
if not move("singleplayer", "move player1 to 0,1,2") then
error("Test 2 failed")
end
if not move("singleplayer", "move player1 to (0,1,2)") then
error("Test 3 failed")
end
if not move("singleplayer", "move player1 to 0, 1,2") then
error("Test 4 failed")
end
if not move("singleplayer", "move player1 to 0 ,1, 2") then
error("Test 5 failed")
end
if not move("singleplayer", "move player1 to 0, 1, 2") then
error("Test 6 failed")
end
if not move("singleplayer", "move player1 to 0 ,1 ,2") then
error("Test 7 failed")
end
if not move("singleplayer", "move player1 to ( 0 ,1 ,2)") then
error("Test 7 failed")
end
if move("singleplayer", "move player1 to abc,def,sdosd") then
error("Test 8 failed")
end
if move("singleplayer", "move player1 to abc def sdosd") then
error("Test 8 failed")
end
if not (ChatCmdBuilder.build(function(cmd)
cmd:sub("does :one:int plus :two:int equal :three:int", function(name, one, two, three)
if name == "singleplayer" and one + two == three then
return true
end
end)
end))("singleplayer", "does 1 plus 2 equal 3") then
error("Test 9 failed")
end
end
if not minetest then
run_tests()
end

7
LICENSE Normal file
View File

@ -0,0 +1,7 @@
Copyright 2017 rubenwardy
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
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 OR COPYRIGHT HOLDERS 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.

10
README.md Normal file
View File

@ -0,0 +1,10 @@
# Per Player Gamemode
Created by rubenwardy. Licensed under MIT.
Enable or disable game mode per player
* `/gamemode <mode>` - requires `gamemode` privilege
* `/gamemode playername <mode>` - requires `gamemode_super` privilege
Where `<mode>` is either `creative` or `survival`

2
depends.txt Normal file
View File

@ -0,0 +1,2 @@
sfinv
creative

82
init.lua Normal file
View File

@ -0,0 +1,82 @@
perplayer_gamemode = { users = {} }
dofile(minetest.get_modpath("perplayer_gamemode") .. "/ChatCmdBuilder.lua")
function perplayer_gamemode.is_in_creative(name)
if perplayer_gamemode.users[name] == nil then
return minetest.setting_getbool("creative_mode")
else
return perplayer_gamemode.users[name]
end
end
function perplayer_gamemode.set_creative(name, v)
perplayer_gamemode.users[name] = v
local player = minetest.get_player_by_name(name)
if player then
local context = sfinv.contexts[name]
context.page = sfinv.get_homepage_name(player)
sfinv.set_player_inventory_formspec(player)
end
end
if creative.is_in_creative then
creative.is_in_creative = perplayer_gamemode.is_in_creative
else
for name, def in pairs(sfinv.pages) do
if #name > 9 and name:sub(1, 9) == "creative:" then
def.is_in_nav = function(self, player, context)
return perplayer_gamemode.is_in_creative(player:get_player_name())
end
end
end
local old_homepage_name = sfinv.get_homepage_name
function sfinv.get_homepage_name(player)
if perplayer_gamemode.is_in_creative(player:get_player_name()) then
return "creative:all"
else
return "sfinv:crafting"
end
end
end
minetest.register_privilege("gamemode", "Can set own creative mode")
minetest.register_privilege("gamemode_super", "Can set anyone's creative mode")
local function is_creative(str)
return minetest.is_yes(str) or str == "creative"
end
perplayer_gamemode.ChatCmdBuilder.new("gamemode", function(cmd)
cmd:sub(":value", function(name, value)
if minetest.check_player_privs(name, { gamemode = true }) then
local v = is_creative(value)
perplayer_gamemode.set_creative(name, v)
if v then
return true, "Turned creative mode on"
else
return true, "Turned creative mode off"
end
else
return false, "Missing privs: gamemode"
end
end)
cmd:sub(":username :value", function(name, username, value)
if minetest.check_player_privs(name, { gamemode_super = true }) then
local v = is_creative(value)
perplayer_gamemode.set_creative(username, v)
if v then
return true, "Turned creative mode on for " .. username
else
return true, "Turned creative mode off for " .. username
end
else
return false, "Missing privs: gamemode_super"
end
end)
end, {
description = "Set game mode (creative or survival)"
})