Compare commits

..

No commits in common. "master" and "v7" have entirely different histories.
master ... v7

5 changed files with 72 additions and 57 deletions

43
.gitignore vendored Normal file
View file

@ -0,0 +1,43 @@
# ---> 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

View file

@ -118,4 +118,4 @@ express Statement of Purpose.
Work. Work.
d. Affirmer understands and acknowledges that Creative Commons is not a d. Affirmer understands and acknowledges that Creative Commons is not a
party to this document and has no duty or obligation with respect to party to this document and has no duty or obligation with respect to
this CC0 or use of the Work. this CC0 or use of the Work.

3
README.md Normal file
View file

@ -0,0 +1,3 @@
# libskinupload
A Minetest mod that allows players to upload custom skins to a server.

View file

@ -41,17 +41,6 @@ if minetest.get_modpath("u_skins") then
end end
end end
-- Shim for Nodecore
if minetest.global_exists("nodecore") then
local _player_skin = nodecore.player_skin
function nodecore.player_skin(player, options, ...)
local pname = options and options.playername or player and player:get_player_name()
local skin = pname and libskinupload.get_skin(pname)
return skin or _player_skin(player, options, ...)
end
end
-- Polyfill for older versions -- Polyfill for older versions
if not minetest.hypertext_escape then if not minetest.hypertext_escape then
local hypertext_escapes = { local hypertext_escapes = {
@ -66,7 +55,12 @@ if not minetest.hypertext_escape then
end end
local function player_model(p, tx, slim_arms) local function player_model(p, tx, slim_arms)
return p:get_properties().mesh..";"..tx..",blank.png,blank.png,blank.png" if mcl then
return (slim_arms and "mcl_armor_character_female.b3d" or "mcl_armor_character.b3d")..";"..tx..",blank.png"
elseif it then
return "player.b3d;"..tx
end
return "character.b3d;"..tx..",blank.png"
end end
local db = minetest.get_mod_storage() local db = minetest.get_mod_storage()
@ -92,13 +86,11 @@ else
for _, x in pairs(dl) do for _, x in pairs(dl) do
minetest.log("action", "Merging file "..x.."...") minetest.log("action", "Merging file "..x.."...")
local id = x:match "libskinupload_uploaded_skin_(%d*).json" local id = x:match "libskinupload_uploaded_skin_(%d*).json"
if id then local file = io.open(storage_dir_meta..x)
local file = io.open(storage_dir_meta..x) local data = file:read("a")
local data = file:read("a") file:close()
file:close() out = out..(i == 0 and ("\""..id.."\":") or (",\""..id.."\":"))..data
out = out..(i == 0 and ("\""..id.."\":") or (",\""..id.."\":"))..data i = i +1
i = i +1
end
end end
local f = io.open(meta_file, "w+") local f = io.open(meta_file, "w+")
f:write(out.."}") f:write(out.."}")
@ -141,9 +133,7 @@ function libskinupload.add_skin_media(id, fname, cb)
else else
meta = libskinupload.get_skin_meta(x) meta = libskinupload.get_skin_meta(x)
end end
if not meta.p then mcl_skins.register_simple_skin{texture = x, slim_arms = meta.msa or false}
mcl_skins.register_simple_skin{texture = x, slim_arms = meta.msa or false}
end
end end
end end
@ -165,6 +155,10 @@ minetest.register_privilege("skin_review", {
give_to_singleplayer = false, give_to_singleplayer = false,
give_to_admin = false give_to_admin = false
}) })
minetest.register_privilege("no_skin_upload", {
give_to_singleplayer = false,
give_to_admin = false
})
libskinupload.notifications = minetest.deserialize(db:get_string("notifications")) or {} libskinupload.notifications = minetest.deserialize(db:get_string("notifications")) or {}
libskinupload.reviewers = minetest.deserialize(db:get_string("reviewers")) or {} libskinupload.reviewers = minetest.deserialize(db:get_string("reviewers")) or {}
@ -225,21 +219,12 @@ minetest.register_on_joinplayer(function(p)
if minetest.check_player_privs(p, {skin_review = true}) then if minetest.check_player_privs(p, {skin_review = true}) then
local newskins = db:get_int("newrequests") local newskins = db:get_int("newrequests")
if newskins > 0 then minetest.chat_send_player(p:get_player_name(), minetest.colorize("#579a1e", "[libskinupload] "..newskins.." new skin request"..(newskins == 1 and " has" or "s have").." been submitted. Run /skinreview to see "..(newskins == 1 and "it" or "them")..".")) end if newskins > 0 then minetest.chat_send_player(p:get_player_name(), minetest.colorize("#579a1e", "[libskinupload] "..newskins.." new skin request"..(newskins == 1 and " has" or "s have").." been submitted. Run /skinreview to see "..(newskins == 1 and "it" or "them")..".")) end
elseif p:get_player_name() == "singleplayer" then
minetest.change_player_privs(p:get_player_name(), {skin_review = true})
end end
end) end)
function libskinupload.can_player_upload_skins(p)
if db:get("upload_permitted:"..p:get_player_name()) == "false" then
return false
end
return true
end
function libskinupload.queue(p, req) function libskinupload.queue(p, req)
local data = req.data local data = req.data
if not libskinupload.can_player_upload_skins(p) then if minetest.check_player_privs(p, {no_skin_upload = true}) then
minetest.chat_send_player(p:get_player_name(), "Insufficient permissions.") minetest.chat_send_player(p:get_player_name(), "Insufficient permissions.")
return "No permission." return "No permission."
end end
@ -368,10 +353,6 @@ local upload_state = {}
function libskinupload.show_upload_dialog(name, args) function libskinupload.show_upload_dialog(name, args)
if not args or type(args) == "string" then args = {err = ""} end if not args or type(args) == "string" then args = {err = ""} end
local p = minetest.get_player_by_name(name) local p = minetest.get_player_by_name(name)
if not libskinupload.can_player_upload_skins(p) then
minetest.chat_send_player(name, "Insufficient privileges.")
return
end
if not upload_state[name] then upload_state[name] = {} end if not upload_state[name] then upload_state[name] = {} end
local m = upload_state[name] local m = upload_state[name]
local size = (minetest.get_player_window_information(name) or {}).max_formspec_size or {x = 20, y = 11.5} local size = (minetest.get_player_window_information(name) or {}).max_formspec_size or {x = 20, y = 11.5}
@ -424,11 +405,12 @@ function libskinupload.show_upload_dialog(name, args)
style[help:hovered;bgcolor=#0000;border=false;bgimg=]\ style[help:hovered;bgcolor=#0000;border=false;bgimg=]\
style[help:pressed;bgcolor=#0000;border=false;bgimg=]\ style[help:pressed;bgcolor=#0000;border=false;bgimg=]\
button[0,0;"..size.x..","..size.y..";help;]\ button[0,0;"..size.x..","..size.y..";help;]\
hypertext["..(size.x /4)..","..(size.y /4)..";"..(size.x /2)..","..(size.y /2)..";;<tag name=clr color=#ffbc5b>"..minetest.formspec_escape("To upload a skin, paste the base64-encoded image into the Data field below. This can be obtained from a terminal by running <clr><b>`base64 -i <filepath>`</b></clr> (e.g. <clr><b>`base64 -i ~/Desktop/skins/my_skin.png`</b></clr>) and copying the output. Alternatively, you can use a web tool (search <clr>'base64-encode an image'</clr> or similar). Once a request is sbmitted, it will need to be reviewed. You will be notified when your request is accepted or denied. Note that you can only have one skin request pending approval at a time; if you send another request before the previous one is approved or rejected, the later request will overwrite the previous one.\nIf the preview for the skin you're uploading looks wrong, the image was probably in a layout that won't work with the player model. Usually, this is because you're trying to upload a Minecraft skin, which is incompatible with most Minetest player models. In that case, you can fix it by simply cropping off the bottom 32 pixels of the original 64x64 image and trying again.").."]" or "")) hypertext["..(size.x /4)..","..(size.y /4)..";"..(size.x /2)..","..(size.y /2)..";;<tag name=clr color=#ffbc5b>"..minetest.formspec_escape("To upload a skin, paste the base64-encoded image into the Data field below. This can be obtained from a terminal by running <clr><b>`base64 -i <filepath>`</b></clr> (e.g. <clr><b>`base64 -i ~/Desktop/skins/my_skin.png`</b></clr>) and copying the output. Alternatively, you can use a web tool (search <clr>'base64-encode an image'</clr> or similar). Once a request is sbmitted, it will need to be reviewed. You will be notified when your request is accepted or denied. Note that you can only have one skin request pending approval at a time; if you send another request before the previous one is approved or rejected, the later request will overwrite the previous one.").."]" or ""))
end end
minetest.register_chatcommand("skinupload", { minetest.register_chatcommand("skinupload", {
description = "Show the skin upload dialog.", description = "Show the skin upload dialog.",
func = libskinupload.show_upload_dialog func = libskinupload.show_upload_dialog,
privs = {no_skin_upload = false}
}) })
local review_state = {} local review_state = {}
@ -781,7 +763,7 @@ minetest.register_chatcommand("skinlimit", {
params = "<name> <limit>", params = "<name> <limit>",
description = "Set the maximum concurrent skin requests allowed for player <name> to <limit>.", description = "Set the maximum concurrent skin requests allowed for player <name> to <limit>.",
func = function(name, args) func = function(name, args)
local pn, num = args:match "([%w_-]+)%s+(%d+)" local pn, num = args:match "(%w+)%s+(%d+)"
num = tonumber(num) num = tonumber(num)
if pn and pn ~= "" and num and num > 0 then if pn and pn ~= "" and num and num > 0 then
db:set_int("reqmax:"..pn, num) db:set_int("reqmax:"..pn, num)
@ -814,7 +796,7 @@ end
minetest.register_chatcommand("skinmanage", { minetest.register_chatcommand("skinmanage", {
privs = {skin_review = true}, privs = {skin_review = true},
params = "cull | list | meta <id> | grant <name> | revoke <name> | privs <name> | alter <id> <newkey>=<newvalue>[,<newkey2>=<newvalue2>]*", params = "cull | list | (meta <id>) | alter <id> <newkey>=<newvalue>[,<newkey2>=<newvalue2>]*",
func = function(name, args) func = function(name, args)
if args == "cull" then if args == "cull" then
local i = 0 local i = 0
@ -883,17 +865,6 @@ minetest.register_chatcommand("skinmanage", {
elseif args:match "^remove_fragmented_meta" then elseif args:match "^remove_fragmented_meta" then
minetest.rmdir(storage_dir_meta, true) minetest.rmdir(storage_dir_meta, true)
minetest.chat_send_player(name, "Removed all fragmented meta.") minetest.chat_send_player(name, "Removed all fragmented meta.")
elseif args:match "^grant" then
local pname = args:match "grant%s+([%w_-]+)"
db:set_string("upload_permitted:"..pname, "")
minetest.chat_send_player(name, "Granted skin upload privileges to player "..pname..".")
elseif args:match "^revoke" then
local pname = args:match "revoke%s+([%w_-]+)"
db:set_string("upload_permitted:"..pname, "false")
minetest.chat_send_player(name, "Revoked skin upload privileges from player "..pname..".")
elseif args:match "^privs" then
local pname = args:match "privs%s+([%w_-]+)"
minetest.chat_send_player(name, "Player "..pname.." is "..(db:get("upload_permitted:"..pname) == "false" and "not " or "").."allowed to upload skins.")
else else
minetest.chat_send_player(name, "Invalid arguments, see /help skinmanage for accepted subcommands.") minetest.chat_send_player(name, "Invalid arguments, see /help skinmanage for accepted subcommands.")
end end
@ -957,8 +928,7 @@ function libskinupload.get_skin_id(name)
end end
function libskinupload.get_skin(name) function libskinupload.get_skin(name)
local id = db:get("skin:"..name) return "libskinupload_uploaded_skin_"..db:get_string("skin:"..name)..".png"
return id and "libskinupload_uploaded_skin_"..id..".png"
end end
function libskinupload.get_skin_meta(skin) function libskinupload.get_skin_meta(skin)
@ -982,7 +952,6 @@ function libskinupload.get_skin_meta(skin)
else else
local res = minetest.parse_json(f:read("a")) local res = minetest.parse_json(f:read("a"))
f:close() f:close()
if not res then return {n = "Unnamed", d = "Nondescript", c = "<Unknown>"} end
return res[string.gsub(string.sub(skin, string.len("libskinupload_uploaded_skin_."), -1), ".png", "")] or {n = "Unnamed", d = "Nondescript", c = "<Unknown>"} return res[string.gsub(string.sub(skin, string.len("libskinupload_uploaded_skin_."), -1), ".png", "")] or {n = "Unnamed", d = "Nondescript", c = "<Unknown>"}
end end
end end
@ -1062,7 +1031,7 @@ end
minetest.register_on_player_receive_fields(function(p, name, data) minetest.register_on_player_receive_fields(function(p, name, data)
if name == "libskinupload:upload" then if name == "libskinupload:upload" then
if not libskinupload.can_player_upload_skins(p) then if minetest.check_player_privs(p, {no_skin_upload = true}) then
minetest.chat_send_player(p:get_player_name(), "Insufficient permissions.") minetest.chat_send_player(p:get_player_name(), "Insufficient permissions.")
minetest.close_formspec(p:get_player_name(), name) minetest.close_formspec(p:get_player_name(), name)
return true return true

View file

@ -1,2 +1,2 @@
name = libskinupload name = libskinupload
optional_depends = unified_inventory, u_skins, mcl_skins, 3d_armor, nc_player_model optional_depends = unified_inventory, u_skins, mcl_skins, 3d_armor