mirror of
				https://github.com/minetest-mods/skinsdb.git
				synced 2025-10-25 18:05:25 +02:00 
			
		
		
		
	Compare commits
	
		
			29 Commits
		
	
	
		
			da6905fd02
			...
			pr_105_del
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | 0bfcb4ed14 | ||
|  | 8deb08696f | ||
|  | e315876c75 | ||
|  | 00e5696eec | ||
|  | 71f803e2fb | ||
|  | 312780c82e | ||
|  | cd27e24b6f | ||
|  | 58739e9f9f | ||
|  | e1cd937470 | ||
|  | 616262de4b | ||
|  | 271c109073 | ||
|  | d3c7fa71c0 | ||
|  | 1d1053dbc2 | ||
|  | b49907c4b1 | ||
|  | 6db9a55f0c | ||
|  | c0b6f761dc | ||
|  | e275159dd0 | ||
|  | b769824d24 | ||
|  | 03d424fea7 | ||
|  | c9fa5d92df | ||
|  | af5e6fcecc | ||
|  | 2e39651821 | ||
|  | da820d06cb | ||
|  | cf712e5b54 | ||
|  | c51905d44b | ||
|  | b3ea5a9e1f | ||
|  | e479e8e745 | ||
|  | 716a9a3f9a | ||
|  | c53158d159 | 
							
								
								
									
										11
									
								
								.github/workflows/build.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								.github/workflows/build.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,11 @@ | ||||
| on: [push, pull_request] | ||||
| name: build | ||||
| jobs: | ||||
|   lint: | ||||
|     runs-on: ubuntu-latest | ||||
|     steps: | ||||
|       - uses: actions/checkout@master | ||||
|       - name: lint | ||||
|         uses: Roang-zero1/factorio-mod-luacheck@master | ||||
|         with: | ||||
|           luacheckrc_url: "" | ||||
							
								
								
									
										14
									
								
								.luacheckrc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								.luacheckrc
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,14 @@ | ||||
| unused_args = false | ||||
| allow_defined_top = true | ||||
| max_line_length = 999 | ||||
|  | ||||
| globals = { | ||||
|     "minetest", "unified_inventory", "core", | ||||
|     "player_api", "clothing", "armor", "sfinv", | ||||
| } | ||||
|  | ||||
| read_globals = { | ||||
|     string = {fields = {"split", "trim"}}, | ||||
|     table = {fields = {"copy", "getn"}}, | ||||
|     "hand_monoid", | ||||
| } | ||||
							
								
								
									
										15
									
								
								API.md
									
									
									
									
									
								
							
							
						
						
									
										15
									
								
								API.md
									
									
									
									
									
								
							| @@ -55,6 +55,17 @@ Get the skin texture for any reason. Note to apply them the skin:set_skin() shou | ||||
|  | ||||
| Could be redefined for dynamic texture generation | ||||
|  | ||||
| ## skin:set_hand(hand_node) | ||||
| Set the hand node to be used with this skin | ||||
|  | ||||
| ## skin:set_hand_from_texture() | ||||
| Register and set hand node based on skin texture. | ||||
| Uses different model depending on get_meta("format") ("1.0" or "1.8") | ||||
| Only works on mod load | ||||
|  | ||||
| ## skin:get_hand() | ||||
| Get hand node. Returns ItemStack | ||||
|  | ||||
| ## skin:set_preview(texture) | ||||
| Set the skin preview - usually at the init time only | ||||
|  | ||||
| @@ -67,7 +78,7 @@ Could be redefined for dynamic preview texture generation | ||||
| Hook for dynamic skins updates on select. Is called in skins.set_player_skin() | ||||
| In skinsdb the default implementation for this function is empty. | ||||
|  | ||||
| skin:apply_skin_to_player(player) | ||||
| ## skin:apply_skin_to_player(player) | ||||
| Apply the skin to the player. Called in skins.update_player_skin() to update visuals | ||||
|  | ||||
| ## skin:set_meta(key, value) | ||||
| @@ -80,7 +91,7 @@ The next metadata keys are filled or/and used interally in skinsdb framework | ||||
|   - name - A name for the skin | ||||
|   - author - The skin author | ||||
|   - license - THe skin texture license | ||||
|   - assignment - (obsolete) is "player:playername" in case the skin is assigned to be privat for a player | ||||
|   - assignment - (obsolete) is "player:playername" in case the skin is assigned to be private for a player | ||||
|   - playername - Player assignment for private skin. Set false for skins not usable by all players (like NPC-Skins), true or nothing for all player skins | ||||
|   - in_inventory_list - If set to false the skin is not visible in inventory skins selection but can be still applied to the player | ||||
|   - _sort_id - Thi skins lists are sorted by this field for output (internal key) | ||||
|   | ||||
							
								
								
									
										14
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										14
									
								
								README.md
									
									
									
									
									
								
							| @@ -15,19 +15,21 @@ This Minetest mod offers changeable player skins with a graphical interface for | ||||
| - Support for different skins lists: public and a per-player list are currently implemented | ||||
| - Full [3d_armor](https://forum.minetest.net/viewtopic.php?t=4654) support | ||||
| - Compatible to 1.0 and 1.8 Minecraft skins format | ||||
| - Skinned hand in 1st person view (1.0 skins only) | ||||
|  | ||||
|  | ||||
| ## Installing skins | ||||
|  | ||||
| ### Download from the [database](http://minetest.fensta.bplaced.net/) | ||||
| ### Download from the [database](https://skinsdb.terraqueststudios.net/) | ||||
|  | ||||
| #### Ingame Downloader | ||||
|  | ||||
| 1) Get Minetest 5.1.0-dev-cb00632 or newer | ||||
| 2) Start your world | ||||
| 3) Run `/skinsdb_download_skins <skindb start page> <amount of pages>` | ||||
| 4) Wait for the Minetest server to shut down | ||||
| 5) Start the server again | ||||
| 2) In the settings menu show advanced options, find the "Developer Options" tab and add "skinsdb" to "Trusted mods" (secure.trusted_mods in minetest.conf) | ||||
| 3) Start your world | ||||
| 4) Run `/skinsdb_download_skins <skindb start page> <amount of pages>` | ||||
| 5) Wait for the Minetest server to shut down | ||||
| 6) Start the server again | ||||
|  | ||||
| You might want to run `minetest` in a Terminal/Console window to check the log output instantly. | ||||
|  | ||||
| @@ -53,6 +55,7 @@ The Script will download all the skins from the database for you. | ||||
| ## License: | ||||
| - GPLv3 | ||||
| - skin texture licenses: See "meta" folder | ||||
| - hand model: CC0 | ||||
|  | ||||
| ### Credits | ||||
|  | ||||
| @@ -62,3 +65,4 @@ The Script will download all the skins from the database for you. | ||||
| - Krock (source code) | ||||
| - bell07 (source code) | ||||
| - stujones11 (player models) | ||||
| - jordan4ibanez (1st person view hand) | ||||
|   | ||||
							
								
								
									
										23
									
								
								api.lua
									
									
									
									
									
								
							
							
						
						
									
										23
									
								
								api.lua
									
									
									
									
									
								
							| @@ -2,14 +2,26 @@ | ||||
| local storage = minetest.get_mod_storage() | ||||
|  | ||||
| function skins.get_player_skin(player) | ||||
| 	local player_name = player:get_player_name() | ||||
| 	local meta = player:get_meta() | ||||
| 	if meta:get("skinsdb:skin_key") then | ||||
| 		-- Move player data prior July 2018 to mod storage | ||||
| 		storage:set_string(player:get_player_name(), player:get_string("skinsdb:skin_key")) | ||||
| 		storage:set_string(player_name, meta:get_string("skinsdb:skin_key")) | ||||
| 		meta:set_string("skinsdb:skin_key", "") | ||||
| 	end | ||||
| 	local skin = storage:get_string(player:get_player_name()) | ||||
| 	return skins.get(skin) or skins.get(skins.default) | ||||
|  | ||||
| 	local skin_name = storage:get_string(player_name) | ||||
| 	local skin = skins.get(skin_name) | ||||
| 	if #skin_name > 0 and not skin then | ||||
| 		-- Migration step to convert `_`-delimited skins to `.` (if possible) | ||||
| 		skin = skins.__fuzzy_match_skin_name(player_name, skin_name, true) | ||||
| 		if skin then | ||||
| 			storage:set_string(player_name, skin:get_key()) | ||||
| 		else | ||||
| 			storage:set_string(player_name, "") | ||||
| 		end | ||||
| 	end | ||||
| 	return skin or skins.get(skins.default) | ||||
| end | ||||
|  | ||||
| -- Assign skin to player | ||||
| @@ -34,7 +46,7 @@ function skins.assign_player_skin(player, skin) | ||||
| 	else | ||||
| 		return false | ||||
| 	end | ||||
| 	return true | ||||
| 	return true, skin_obj | ||||
| end | ||||
|  | ||||
| -- update visuals | ||||
| @@ -53,10 +65,11 @@ end | ||||
|  | ||||
| -- Assign and update - should be used on selection externally | ||||
| function skins.set_player_skin(player, skin) | ||||
| 	local success = skins.assign_player_skin(player, skin) | ||||
| 	local success, skin_obj = skins.assign_player_skin(player, skin) | ||||
| 	if success then | ||||
| 		skins.get_player_skin(player):set_skin(player) | ||||
| 		skins.update_player_skin(player) | ||||
| 		minetest.log("action", player:get_player_name().." set skin to "..skin_obj:get_key("")) | ||||
| 	end | ||||
| 	return success | ||||
| end | ||||
|   | ||||
| @@ -11,7 +11,7 @@ end | ||||
|  | ||||
|  | ||||
| minetest.register_chatcommand("skinsdb", { | ||||
| 	params = "[set] <skin key> | show [<skin key>] | list | list private | list public | [ui]", | ||||
| 	params = S("[set] <skin key> | show [<skin key>] | list | list private | list public | [ui]"), | ||||
| 	description = S("Show, list or set player's skin"), | ||||
| 	func = function(name, param) | ||||
| 		local player = minetest.get_player_by_name(name) | ||||
|   | ||||
| @@ -1,4 +1,5 @@ | ||||
| local S = minetest.get_translator("skinsdb") | ||||
| local ui = minetest.global_exists("unified_inventory") and unified_inventory | ||||
|  | ||||
| function skins.get_formspec_context(player) | ||||
| 	if player then | ||||
| @@ -11,7 +12,7 @@ function skins.get_formspec_context(player) | ||||
| end | ||||
|  | ||||
| -- Show skin info | ||||
| function skins.get_skin_info_formspec(skin) | ||||
| function skins.get_skin_info_formspec(skin, perplayer_formspec) | ||||
| 	local texture = skin:get_texture() | ||||
| 	local m_name = skin:get_meta_string("name") | ||||
| 	local m_author = skin:get_meta_string("author") | ||||
| @@ -20,30 +21,82 @@ function skins.get_skin_info_formspec(skin) | ||||
| 	-- overview page | ||||
| 	local raw_size = m_format == "1.8" and "2,2" or "2,1" | ||||
|  | ||||
| 	local formspec = "image[0.8,.6;1,2;"..minetest.formspec_escape(skin:get_preview()).."]" | ||||
| 	local lxoffs = 0.8 | ||||
| 	local cxoffs = 2 | ||||
| 	local rxoffs = 5.5 | ||||
|  | ||||
| 	if type(perplayer_formspec) == "table" then -- we're using Unified Inventory | ||||
| 		lxoffs = 1.5 | ||||
| 		cxoffs = 3.75 | ||||
| 		rxoffs = 7.5 | ||||
| 	end | ||||
|  | ||||
| 	local formspec = "image["..lxoffs..",.6;1,2;"..minetest.formspec_escape(skin:get_preview()).."]" | ||||
| 	if texture then | ||||
| 		formspec = formspec.."label[6,.5;"..S("Raw texture")..":]" | ||||
| 		.."image[6,1;"..raw_size..";"..texture.."]" | ||||
| 		formspec = formspec.."label["..rxoffs..",.5;"..S("Raw texture")..":]" | ||||
| 		.."image["..rxoffs..",1;"..raw_size..";"..texture.."]" | ||||
| 	end | ||||
| 	if m_name ~= "" then | ||||
| 		formspec = formspec.."label[2,.5;"..S("Name")..": "..minetest.formspec_escape(m_name).."]" | ||||
| 		formspec = formspec.."label["..cxoffs..",.5;"..S("Name")..": "..minetest.formspec_escape(m_name).."]" | ||||
| 	end | ||||
| 	if m_author ~= "" then | ||||
| 		formspec = formspec.."label[2,1;"..S("Author")..": "..minetest.formspec_escape(m_author).."]" | ||||
| 		formspec = formspec.."label["..cxoffs..",1;"..S("Author")..": "..minetest.formspec_escape(m_author).."]" | ||||
| 	end | ||||
| 	if m_license ~= "" then | ||||
| 		formspec = formspec.."label[2,1.5;"..S("License")..": "..minetest.formspec_escape(m_license).."]" | ||||
| 		formspec = formspec.."label["..cxoffs..",1.5;"..S("License")..": "..minetest.formspec_escape(m_license).."]" | ||||
| 	end | ||||
| 	return formspec | ||||
| end | ||||
|  | ||||
| function skins.get_skin_selection_formspec(player, context, y_delta) | ||||
| function skins.get_skin_selection_formspec(player, context, perplayer_formspec) | ||||
| 	context.skins_list = skins.get_skinlist_for_player(player:get_player_name()) | ||||
| 	context.total_pages = 1 | ||||
| 	local xoffs = 0 | ||||
| 	local yoffs = 4 | ||||
| 	local xspc = 1 | ||||
| 	local yspc = 2 | ||||
| 	local skinwidth = 1 | ||||
| 	local skinheight = 2 | ||||
| 	local xscale = 1 -- luacheck: ignore | ||||
| 	local btn_y = 8.15 | ||||
| 	local drop_y = 8 | ||||
| 	local btn_width = 1 | ||||
| 	local droppos = 1 | ||||
| 	local droplen = 6.25 | ||||
| 	local btn_right = 7 | ||||
| 	local maxdisp = 16 | ||||
|  | ||||
| 	local ctrls_height = 0.5 | ||||
|  | ||||
| 	if type(perplayer_formspec) == "table" then -- it's being used under Unified Inventory | ||||
| 		xoffs =  perplayer_formspec.std_inv_x | ||||
| 		xspc =   ui.imgscale | ||||
| 		yspc =   ui.imgscale*2 | ||||
| 		skinwidth =  ui.imgscale*0.9 | ||||
| 		skinheight = ui.imgscale*1.9 | ||||
| 		xscale = ui.imgscale | ||||
| 		btn_width = ui.imgscale | ||||
| 		droppos = xoffs + btn_width + 0.1 | ||||
| 		droplen = ui.imgscale * 6 - 0.2 | ||||
| 		btn_right = droppos + droplen + 0.1 | ||||
|  | ||||
| 		if perplayer_formspec.pagecols == 4 then -- and we're in lite mode | ||||
| 			yoffs =  1 | ||||
| 			maxdisp = 8 | ||||
| 			drop_y = yoffs + skinheight + 0.1 | ||||
| 		else | ||||
| 			yoffs =  0.2 | ||||
| 			drop_y = yoffs + skinheight*2 + 0.2 | ||||
| 		end | ||||
|  | ||||
| 		btn_y = drop_y | ||||
|  | ||||
| 	end | ||||
|  | ||||
| 	for i, skin in ipairs(context.skins_list ) do | ||||
| 		local page = math.floor((i-1) / 16)+1 | ||||
| 		local page = math.floor((i-1) / maxdisp)+1 | ||||
| 		skin:set_meta("inv_page", page) | ||||
| 		skin:set_meta("inv_page_index", (i-1)%16+1) | ||||
| 		skin:set_meta("inv_page_index", (i-1)%maxdisp+1) | ||||
| 		context.total_pages = page | ||||
| 	end | ||||
| 	context.skins_page = context.skins_page or skins.get_player_skin(player):get_meta("inv_page") or 1 | ||||
| @@ -51,22 +104,25 @@ function skins.get_skin_selection_formspec(player, context, y_delta) | ||||
|  | ||||
| 	local page = context.skins_page | ||||
| 	local formspec = "" | ||||
| 	for i = (page-1)*16+1, page*16 do | ||||
|  | ||||
| 	for i = (page-1)*maxdisp+1, page*maxdisp do | ||||
| 		local skin = context.skins_list[i] | ||||
| 		if not skin then | ||||
| 			break | ||||
| 		end | ||||
|  | ||||
| 		local index_p = skin:get_meta("inv_page_index") | ||||
| 		local x = (index_p-1) % 8 | ||||
| 		local x = ((index_p-1) % 8) * xspc + xoffs | ||||
| 		local y | ||||
| 		if index_p > 8 then | ||||
| 			y = y_delta + 1.9 | ||||
| 			y = yoffs + yspc | ||||
| 		else | ||||
| 			y = y_delta | ||||
| 			y = yoffs | ||||
| 		end | ||||
| 		formspec = formspec.."image_button["..x..","..y..";1,2;".. | ||||
| 			minetest.formspec_escape(skin:get_preview())..";skins_set$"..i..";]".. | ||||
| 		formspec = formspec.. | ||||
| 			string.format("image_button[%f,%f;%f,%f;%s;skins_set$%i;]", | ||||
| 				x, y, skinwidth, skinheight, | ||||
| 				minetest.formspec_escape(skin:get_preview()), i).. | ||||
| 			"tooltip[skins_set$"..i..";"..minetest.formspec_escape(skin:get_meta_string("name")).."]" | ||||
| 	end | ||||
|  | ||||
| @@ -87,10 +143,13 @@ function skins.get_skin_selection_formspec(player, context, y_delta) | ||||
| 			if pg > 1 then page_list = page_list.."," end | ||||
| 			page_list = page_list..pagename | ||||
| 		end | ||||
| 		formspec = formspec | ||||
| 			.."button[0,"..(y_delta+4.0)..";1,.5;skins_page$"..page_prev..";<<]" | ||||
| 			.."dropdown[0.9,"..(y_delta+3.88)..";6.5,.5;skins_selpg;"..page_list..";"..page.."]" | ||||
| 			.."button[7,"..(y_delta+4.0)..";1,.5;skins_page$"..page_next..";>>]" | ||||
| 		formspec = formspec.. | ||||
| 			string.format("button[%f,%f;%f,%f;skins_page$%i;<<]", | ||||
| 				xoffs, btn_y, btn_width, ctrls_height, page_prev).. | ||||
| 			string.format("button[%f,%f;%f,%f;skins_page$%i;>>]", | ||||
| 				btn_right, btn_y, btn_width, ctrls_height, page_next).. | ||||
| 			string.format("dropdown[%f,%f;%f,%f;skins_selpg;%s;%i]", | ||||
| 				droppos, drop_y, droplen, ctrls_height, page_list, page) | ||||
| 	end | ||||
| 	return formspec | ||||
| end | ||||
|   | ||||
							
								
								
									
										22
									
								
								init.lua
									
									
									
									
									
								
							
							
						
						
									
										22
									
								
								init.lua
									
									
									
									
									
								
							| @@ -63,6 +63,13 @@ end) | ||||
|  | ||||
| minetest.register_on_leaveplayer(function(player) | ||||
| 	skins.ui_context[player:get_player_name()] = nil | ||||
| 	player:get_inventory():set_size("hand", 0) | ||||
| end) | ||||
|  | ||||
| minetest.register_on_shutdown(function() | ||||
| 	for _, player in pairs(minetest.get_connected_players()) do | ||||
| 		player:get_inventory():set_size("hand", 0) | ||||
| 	end | ||||
| end) | ||||
|  | ||||
| player_api.register_model("skinsdb_3d_armor_character_5.b3d", { | ||||
| @@ -80,6 +87,10 @@ player_api.register_model("skinsdb_3d_armor_character_5.b3d", { | ||||
| 		mine = {x=189, y=198}, | ||||
| 		walk_mine = {x=200, y=219}, | ||||
| 		sit = {x=81, y=160}, | ||||
| 		-- compatibility w/ the emote mod | ||||
| 		wave = {x = 192, y = 196, override_local = true}, | ||||
| 		point = {x = 196, y = 196, override_local = true}, | ||||
| 		freeze = {x = 205, y = 205, override_local = true}, | ||||
| 	}, | ||||
| }) | ||||
|  | ||||
| @@ -91,4 +102,15 @@ if not default_skin_obj then | ||||
| 	default_skin_obj:set_meta("format", '1.0') | ||||
| 	default_skin_obj:set_meta("_sort_id", 0) | ||||
| 	default_skin_obj:set_meta("name", "Sam") | ||||
| 	default_skin_obj:set_hand_from_texture() | ||||
| end | ||||
|  | ||||
| -- Secure hand inventory slot | ||||
| minetest.register_allow_player_inventory_action(function(player, action, inv, data) | ||||
| 	if data.to_list == "hand" or data.from_list == "hand" or data.listname == "hand" then | ||||
| 		return 0 | ||||
| 	end | ||||
| end) | ||||
|  | ||||
| --dofile(skins.modpath.."/unittest.lua") | ||||
|  | ||||
|   | ||||
| @@ -1,19 +1,19 @@ | ||||
| # textdomain: skinsdb | ||||
| # Translation by Xanthin | ||||
|  | ||||
| Raw texture=Rohtextur | ||||
| Name=Name | ||||
| Author=Autor | ||||
| Change=Wechseln | ||||
| Page=Seite | ||||
| License=Lizenz | ||||
| Description=Beschreibung | ||||
| [set] <skin key> | show [<skin key>] | list | list private | list public | [ui]= | ||||
| Show, list or set player's skin=Anzeigen oder setzen der Spieler-Skins | ||||
| Player not found=Spieler nicht da | ||||
| unknown command=unbekannter Befehl | ||||
| see /help skinsdb for supported parameters=Lese /help für erlaubte Parameter | ||||
| skin set to=Skin ist jetzt | ||||
| invalid skin=unbekannter Skin | ||||
| unknown parameter=unbekannter Parameter | ||||
| Skins=Aussehen | ||||
| Requires skin key=Benötigt Skin-Name | ||||
| unknown parameter=unbekannter Parameter | ||||
| Raw texture=Rohtextur | ||||
| Page=Seite | ||||
| Name=Name | ||||
| Author=Autor | ||||
| License=Lizenz | ||||
| <skindb start page> <amount of pages>= | ||||
| Downloads the specified range of skins and shuts down the server= | ||||
| Change=Wechseln | ||||
| Skins=Aussehen | ||||
|   | ||||
							
								
								
									
										19
									
								
								locale/skinsdb.eo.tr
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								locale/skinsdb.eo.tr
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,19 @@ | ||||
| # textdomain: skinsdb | ||||
| [set] <skin key> | show [<skin key>] | list | list private | list public | [ui]=[set] <haŭtonomo> | show [<haŭtonomo>] | list | list private | list public | [ui] | ||||
| Show, list or set player's skin=Montri haŭtojn («show»), listigi haŭtojn («list»), aŭ agordi onian haŭton («set») | ||||
| Player not found=Ludanto ne trovita | ||||
| unknown command=nekonata ordono | ||||
| see /help skinsdb for supported parameters=rulu «/help skinsdb» por vidi subtenatajn parametrojn | ||||
| skin set to=haŭto agordita al | ||||
| invalid skin=nevalida haŭto | ||||
| Requires skin key=Postulas haŭtonomon | ||||
| unknown parameter=nekonata parametro | ||||
| Raw texture=Kruda bildo | ||||
| Page=Paĝo | ||||
| Name=Nomo | ||||
| Author=Aŭtoro | ||||
| License=Permesilo | ||||
| <skindb start page> <amount of pages>=<komenca paĝo> <paĝokvanto> | ||||
| Downloads the specified range of skins and shuts down the server=Elŝutinte haŭtojn el skindb inter la donitaj paĝoj, restartigas la servilon | ||||
| Change=Ŝanĝi | ||||
| Skins=Haŭtoj | ||||
| @@ -1,18 +1,19 @@ | ||||
| # textdomain: skinsdb | ||||
|  | ||||
| Raw texture=Texture | ||||
| Name=Nom | ||||
| Author=Auteur | ||||
| Change=Changer | ||||
| Page=Page | ||||
| License=Licence | ||||
| Description=Description | ||||
| [set] <skin key> | show [<skin key>] | list | list private | list public | [ui]= | ||||
| Show, list or set player's skin=Afficher, lister ou définir le skin du joueur | ||||
| Player not found=Joueur non trouvé | ||||
| unknown command=commande inconnue | ||||
| see /help skinsdb for supported parameters=voir /help skinsdb pour les paramètres supportés | ||||
| skin set to=skin définie sur | ||||
| invalid skin=skin peau invalide | ||||
| Requires skin key= | ||||
| unknown parameter=paramètre inconnu | ||||
| unknown skin=skin inconnue | ||||
|  | ||||
| Raw texture=Texture | ||||
| Page=Page | ||||
| Name=Nom | ||||
| Author=Auteur | ||||
| License=Licence | ||||
| <skindb start page> <amount of pages>= | ||||
| Downloads the specified range of skins and shuts down the server= | ||||
| Change=Changer | ||||
| Skins= | ||||
|   | ||||
| @@ -1,18 +1,19 @@ | ||||
| # textdomain: skinsdb | ||||
| # Malay translation by muhdnurhidayat | ||||
|  | ||||
| Raw texture=Tekstur mentah | ||||
| Name=Nama | ||||
| Author=Pencipta | ||||
| Change=Ubah | ||||
| Page=Halaman | ||||
| License=Lesen | ||||
| Description=Keterangan | ||||
| [set] <skin key> | show [<skin key>] | list | list private | list public | [ui]= | ||||
| Show, list or set player's skin=Tunjukkan, senaraikan atau tetapkan kulit pemain | ||||
| Player not found=Pemain tidak dijumpai | ||||
| unknown command=perintah tidak diketahui | ||||
| see /help skinsdb for supported parameters=lihat /help skinsdb untuk parameter yang disokong | ||||
| skin set to=kulit ditetapkan kepada | ||||
| invalid skin=kulit tidak sah | ||||
| Requires skin key= | ||||
| unknown parameter=parameter tidak diketahui | ||||
| unknown skin=kulit tidak diketahui | ||||
| Raw texture=Tekstur mentah | ||||
| Page=Halaman | ||||
| Name=Nama | ||||
| Author=Pencipta | ||||
| License=Lesen | ||||
| <skindb start page> <amount of pages>= | ||||
| Downloads the specified range of skins and shuts down the server= | ||||
| Change=Ubah | ||||
| Skins= | ||||
|   | ||||
							
								
								
									
										19
									
								
								locale/skinsdb.pt_BR.tr
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								locale/skinsdb.pt_BR.tr
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,19 @@ | ||||
| # textdomain: skinsdb | ||||
| [set] <skin key> | show [<skin key>] | list | list private | list public | [ui]= | ||||
| Show, list or set player's skin=Mostrar, listar ou definir a skin do jogador | ||||
| Player not found=Jogador não encontrado | ||||
| unknown command=Comando desconhecido | ||||
| see /help skinsdb for supported parameters= consulte /help skinsdb para obter os parâmetros suportados | ||||
| skin set to=Aparência definida para | ||||
| invalid skin=Aparência inválida | ||||
| Requires skin key=Requer chave de aparência | ||||
| unknown parameter=parâmetro desconhecido | ||||
| Raw texture=Textura crua | ||||
| Page=Página | ||||
| Name=Nome | ||||
| Author=Autor | ||||
| License=Licença | ||||
| <skindb start page> <amount of pages>= | ||||
| Downloads the specified range of skins and shuts down the server=Baixa o intervalo especificado de capas e desliga o servidor | ||||
| Change=Mudar | ||||
| Skins=Aparência | ||||
							
								
								
									
										19
									
								
								locale/skinsdb.ru.tr
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								locale/skinsdb.ru.tr
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,19 @@ | ||||
| # textdomain: skinsdb | ||||
| [set] <skin key> | show [<skin key>] | list | list private | list public | [ui]= | ||||
| Show, list or set player's skin=Показать скин, список скинов, установить скин игрока | ||||
| Player not found=Игрок не найден | ||||
| unknown command=неизвестная команда | ||||
| see /help skinsdb for supported parameters=смотрите /help skinsdb для просмотра параметров | ||||
| skin set to=установлено скин | ||||
| invalid skin=некорректный скин | ||||
| Requires skin key=Зависимый идентификатор скина | ||||
| unknown parameter=неопределенный параметр | ||||
| Raw texture=Текстура | ||||
| Page=Страница | ||||
| Name=Имя | ||||
| Author=Автор | ||||
| License=Лицензия | ||||
| <skindb start page> <amount of pages>= | ||||
| Downloads the specified range of skins and shuts down the server=Загрузить массив скинов и остановить сервер | ||||
| Change=Изменить | ||||
| Skins=Скины | ||||
							
								
								
									
										19
									
								
								locale/skinsdb.uk.tr
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								locale/skinsdb.uk.tr
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,19 @@ | ||||
| # textdomain: skinsdb | ||||
| [set] <skin key> | show [<skin key>] | list | list private | list public | [ui]= | ||||
| Show, list or set player's skin=Показати скін, список скінів, встановити скін гравця | ||||
| Player not found=Гравець не знайдений | ||||
| unknown command=невідома команда | ||||
| see /help skinsdb for supported parameters=дивіться /help skinsdb для перегляду параметрів | ||||
| skin set to=встановлено скін | ||||
| invalid skin=некоректний скін | ||||
| Requires skin key=Залежний ідентифікатор скіна | ||||
| unknown parameter=невизначений параметр | ||||
| Raw texture=Текстура | ||||
| Page=Сторінка | ||||
| Name=Ім'я | ||||
| Author=Автор | ||||
| License=Ліцензія | ||||
| <skindb start page> <amount of pages>= | ||||
| Downloads the specified range of skins and shuts down the server=Завантажити масив скінів та зупинити сервер | ||||
| Change=Змінити | ||||
| Skins=Скіни | ||||
| @@ -1,20 +1,19 @@ | ||||
| # textdomain: skinsdb | ||||
| #Translation by IFRFSX(BingFengFSX) | ||||
|  | ||||
| Raw texture=自然状态的纹理 | ||||
| Name=名称 | ||||
| Author=作者 | ||||
| Change=更换 | ||||
| Page=页面 | ||||
| License=许可证 | ||||
| Description=说明 | ||||
| [set] <skin key> | show [<skin key>] | list | list private | list public | [ui]= | ||||
| Show, list or set player's skin=显示,列出或者设置玩家的皮肤 | ||||
| Player not found=玩家未找到 | ||||
| unknown command=未知命令 | ||||
| see /help skinsdb for supported parameters=有关skinsdb支持的参数,参见 /help | ||||
| skin set to=皮肤设置为 | ||||
| invalid skin=无效皮肤 | ||||
| Requires skin key= | ||||
| unknown parameter=未知参数 | ||||
| unknown skin=未知皮肤 | ||||
| Raw texture=自然状态的纹理 | ||||
| Page=页面 | ||||
| Name=名称 | ||||
| Author=作者 | ||||
| License=许可证 | ||||
| <skindb start page> <amount of pages>= | ||||
| Downloads the specified range of skins and shuts down the server=下载指定范围的皮肤并关闭服务器 | ||||
| Change=更换 | ||||
| Skins=皮肤 | ||||
|   | ||||
| @@ -1,19 +1,19 @@ | ||||
| # textdomain: skinsdb | ||||
| #Translation by IFRFSX(BingFengFSX) | ||||
| Raw texture=自然狀態的紋理 | ||||
| Name=名稱 | ||||
| Author=作者 | ||||
| Change=更換 | ||||
| Page=頁面 | ||||
| License=許可證 | ||||
| Description=說明 | ||||
| Show,list or set player's skin=顯示,列出或者設定玩家的皮膚 | ||||
| [set] <skin key> | show [<skin key>] | list | list private | list public | [ui]= | ||||
| Show, list or set player's skin=顯示,列出或者設定玩家的皮膚 | ||||
| Player not found=玩家未找到 | ||||
| unknown command=未知命令 | ||||
| see /help skinsdb for supported parameters=有關skinsdb支持的參數,參見/help | ||||
| skin set to=皮膚設定為 | ||||
| invalid skin=無效皮膚 | ||||
| Requires skin key= | ||||
| unknown parameter=未知參數 | ||||
| unknown skin=未知皮膚 | ||||
| Raw texture=自然狀態的紋理 | ||||
| Page=頁面 | ||||
| Name=名稱 | ||||
| Author=作者 | ||||
| License=許可證 | ||||
| <skindb start page> <amount of pages>= | ||||
| Downloads the specified range of skins and shuts down the server=下載指定範圍的皮膚並關閉服務器 | ||||
| Change=更換 | ||||
| Skins=皮膚 | ||||
|   | ||||
| @@ -1,20 +1,19 @@ | ||||
| # textdomain: skinsdb | ||||
|  | ||||
| Raw texture= | ||||
| Name= | ||||
| Author= | ||||
| Change= | ||||
| Page= | ||||
| License= | ||||
| Description= | ||||
| [set] <skin key> | show [<skin key>] | list | list private | list public | [ui]= | ||||
| Show, list or set player's skin= | ||||
| Player not found= | ||||
| unknown command= | ||||
| see /help skinsdb for supported parameters= | ||||
| skin set to= | ||||
| invalid skin= | ||||
| unknown parameter= | ||||
| unknown skin= | ||||
| Downloads the specified range of skins and shuts down the server= | ||||
| Skins= | ||||
| Requires skin key= | ||||
| unknown parameter= | ||||
| Raw texture= | ||||
| Page= | ||||
| Name= | ||||
| Author= | ||||
| License= | ||||
| <skindb start page> <amount of pages>= | ||||
| Downloads the specified range of skins and shuts down the server= | ||||
| Change= | ||||
| Skins= | ||||
|   | ||||
							
								
								
									
										3
									
								
								mod.conf
									
									
									
									
									
								
							
							
						
						
									
										3
									
								
								mod.conf
									
									
									
									
									
								
							| @@ -1,4 +1,5 @@ | ||||
| name = skinsdb | ||||
| description = Player skin mod, supporting unified_inventory, sfinv and smart_inventory | ||||
| depends = player_api | ||||
| optional_depends = unified_inventory,3d_armor,clothing,sfinv | ||||
| optional_depends = unified_inventory,3d_armor,clothing,sfinv,hand_monoid | ||||
| min_minetest_version = 5.4.0 | ||||
|   | ||||
							
								
								
									
										
											BIN
										
									
								
								models/skinsdb_hand.b3d
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								models/skinsdb_hand.b3d
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								models/skinsdb_hand.blend
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								models/skinsdb_hand.blend
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								models/skinsdb_hand_18.b3d
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								models/skinsdb_hand_18.b3d
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								models/skinsdb_hand_18.blend
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								models/skinsdb_hand_18.blend
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| @@ -1,5 +1,7 @@ | ||||
| skins.meta = {} | ||||
|  | ||||
| local has_hand_monoid = minetest.get_modpath("hand_monoid") | ||||
|  | ||||
| local skin_class = {} | ||||
| skin_class.__index = skin_class | ||||
| skins.skin_class = skin_class | ||||
| @@ -51,6 +53,38 @@ function skin_class:get_texture() | ||||
| 	return self._texture | ||||
| end | ||||
|  | ||||
| function skin_class:set_hand(hand) | ||||
| 	self._hand = hand | ||||
| end | ||||
|  | ||||
| local ALPHA_CLIP = minetest.features.use_texture_alpha_string_modes and "clip" or true | ||||
| function skin_class:set_hand_from_texture() | ||||
| 	local hand = core.get_current_modname()..':'..self._texture:gsub('[%p%c%s]', '') | ||||
| 	local hand_def = {} | ||||
| 	for k,v in pairs(minetest.registered_items[""]) do | ||||
| 		if k ~= "mod_origin" and k ~= "type" and k ~= "wield_image" then | ||||
| 			hand_def[k] = v | ||||
| 		end | ||||
| 	end | ||||
| 	hand_def.tiles = {self:get_texture()} | ||||
| 	hand_def.visual_scale = 1 | ||||
| 	hand_def.wield_scale = {x=1,y=1,z=1} | ||||
| 	hand_def.paramtype = "light" | ||||
| 	hand_def.drawtype = "mesh" | ||||
| 	if(self:get_meta("format") == "1.0") then | ||||
| 		hand_def.mesh = "skinsdb_hand.b3d" | ||||
| 	else | ||||
| 		hand_def.mesh = "skinsdb_hand_18.b3d" | ||||
| 	end | ||||
| 	hand_def.use_texture_alpha = ALPHA_CLIP | ||||
| 	minetest.register_node(hand, hand_def) | ||||
| 	self:set_hand(hand) | ||||
| end | ||||
|  | ||||
| function skin_class:get_hand() | ||||
| 	return self._hand | ||||
| end | ||||
|  | ||||
| function skin_class:set_preview(value) | ||||
| 	self._preview = value | ||||
| end | ||||
| @@ -174,6 +208,22 @@ function skin_class:apply_skin_to_player(player) | ||||
| 			y = self:get_meta("visual_size_y") or 1 | ||||
| 		} | ||||
| 	}) | ||||
|  | ||||
| 	local hand = self:get_hand() | ||||
| 	if has_hand_monoid then | ||||
| 		if hand then | ||||
| 			hand_monoid.monoid:add_change(player, {name = hand}, "skinsdb:hand") | ||||
| 		else | ||||
| 			hand_monoid.monoid:del_change(player, "skinsdb:hand") | ||||
| 		end | ||||
| 	else | ||||
| 		if hand then | ||||
| 			player:get_inventory():set_size("hand", 1) | ||||
| 			player:get_inventory():set_stack("hand", 1, hand) | ||||
| 		else | ||||
| 			player:get_inventory():set_stack("hand", 1, "") | ||||
| 		end | ||||
| 	end | ||||
| end | ||||
|  | ||||
| function skin_class:set_skin(player) | ||||
| @@ -185,6 +235,6 @@ end | ||||
| function skin_class:is_applicable_for_player(playername) | ||||
| 	local assigned_player = self:get_meta("playername") | ||||
| 	return assigned_player == nil or assigned_player == true or | ||||
|  			playername and (minetest.check_player_privs(playername, {server=true}) or | ||||
| 			assigned_player:lower() == playername:lower()) | ||||
| 		playername and (minetest.check_player_privs(playername, {server=true}) or | ||||
| 		assigned_player:lower() == playername:lower()) | ||||
| end | ||||
|   | ||||
							
								
								
									
										194
									
								
								skinlist.lua
									
									
									
									
									
								
							
							
						
						
									
										194
									
								
								skinlist.lua
									
									
									
									
									
								
							| @@ -1,71 +1,149 @@ | ||||
| local skins_dir_list = minetest.get_dir_list(skins.modpath.."/textures") | ||||
| local dbgprint = false and print or function() end | ||||
|  | ||||
| for _, fn in pairs(skins_dir_list) do | ||||
| 	local name, sort_id, assignment, is_preview, playername | ||||
| 	local nameparts = string.gsub(fn, "[.]", "_"):split("_") | ||||
| --- @param path     Path to the "textures" directory, without tailing slash. | ||||
| --- @param filename Current file name, such as "player.groot.17.png". | ||||
| --- @return On error: false, error message. On success: true, skin key | ||||
| function skins.register_skin(path, filename) | ||||
| 	-- See "textures/readme.txt" for allowed formats | ||||
|  | ||||
| 	-- check allowed prefix and file extension | ||||
| 	if (nameparts[1] == 'player' or nameparts[1] == 'character') and | ||||
| 			nameparts[#nameparts]:lower() == 'png' then | ||||
| 	local prefix, sep, identifier, extension = filename:match("^(%a+)([_.])([%w_.]+)%.(%a+)$") | ||||
| 	--[[ | ||||
| 		prefix:     "character" or "player" | ||||
| 		sep:        "." (new) or "_" (legacy) | ||||
| 		identifier: number, name or (name + sep + number) | ||||
| 			^ previews are explicity skipped | ||||
| 		extension:  "png" only due `skins.get_skin_format` | ||||
| 	]] | ||||
|  | ||||
| 		-- cut filename extension | ||||
| 		table.remove(nameparts, #nameparts) | ||||
| 	-- Filter out files that do not match the allowed patterns | ||||
| 	if not extension or extension:lower() ~= "png" then | ||||
| 		return false, "invalid skin name" | ||||
| 	end | ||||
| 	if prefix ~= "player" and prefix ~= "character" then | ||||
| 		return false, "unknown type" | ||||
| 	end | ||||
|  | ||||
| 		-- check preview suffix | ||||
| 		if nameparts[#nameparts] == 'preview' then | ||||
| 			is_preview = true | ||||
| 			table.remove(nameparts, #nameparts) | ||||
| 	local preview_suffix = sep .. "preview" | ||||
| 	if identifier:sub(-#preview_suffix) == preview_suffix then | ||||
| 		-- The preview texture is added by the main skin texture (if exists) | ||||
| 		return false, "preview texture" | ||||
| 	end | ||||
|  | ||||
| 	assert(path) | ||||
| 	if path == ":UNITTEST:" then | ||||
| 		path = nil | ||||
| 	end | ||||
|  | ||||
| 	dbgprint("Found skin", prefix, identifier, extension) | ||||
|  | ||||
| 	local sort_id    -- number, sorting "rank" in the skin list | ||||
| 	local playername -- string, if player-specific | ||||
| 	if prefix == "player" then | ||||
| 		-- Allow "player.PLAYERNAME.png" and "player.PLAYERNAME.123.png" | ||||
| 		local splits = identifier:split(sep) | ||||
|  | ||||
| 		playername = splits[1] | ||||
| 		-- Put in front | ||||
| 		sort_id = 0 + (tonumber(splits[2]) or 0) | ||||
|  | ||||
| 		if #splits > 1 and sep == "_" then | ||||
| 			minetest.log("warning", "skinsdb: The skin name '" .. filename .. "' is ambigous." .. | ||||
| 				" Please use the separator '.' to lock it down to the correct player name.") | ||||
| 		end | ||||
| 	else -- Public skin "character*" | ||||
| 		-- Less priority | ||||
| 		sort_id = 5000 + (tonumber(identifier) or 0) | ||||
| 	end | ||||
|  | ||||
| 		-- Build technically skin name | ||||
| 		name = table.concat(nameparts, '_') | ||||
| 	local filename_noext = prefix .. sep .. identifier | ||||
|  | ||||
| 		-- Handle metadata from file name | ||||
| 		if not is_preview then | ||||
| 			-- Get player name | ||||
| 			if nameparts[1] == "player" then | ||||
| 				playername = nameparts[2] | ||||
| 				table.remove(nameparts, 1) | ||||
| 				sort_id = 0 | ||||
| 			else | ||||
| 				sort_id = 5000 | ||||
| 			end | ||||
| 	dbgprint("Register skin", filename_noext, playername, sort_id) | ||||
|  | ||||
| 			-- Get sort index | ||||
| 			if tonumber(nameparts[#nameparts]) then | ||||
| 				sort_id = sort_id + nameparts[#nameparts] | ||||
| 			end | ||||
| 	-- Register skin texture | ||||
| 	local skin_obj = skins.get(filename_noext) or skins.new(filename_noext) | ||||
| 	skin_obj:set_texture(filename) | ||||
| 	skin_obj:set_meta("_sort_id", sort_id) | ||||
| 	if sep ~= "_" then | ||||
| 		skin_obj._legacy_name = filename_noext:gsub("[._]+", "_") | ||||
| 	end | ||||
|  | ||||
| 	if playername then | ||||
| 		skin_obj:set_meta("assignment", "player:"..playername) | ||||
| 		skin_obj:set_meta("playername", playername) | ||||
| 	end | ||||
|  | ||||
| 	if path then | ||||
| 		-- Get type of skin based on dimensions | ||||
| 		local file = io.open(path .. "/" .. filename, "r") | ||||
| 		local skin_format = skins.get_skin_format(file) | ||||
| 		skin_obj:set_meta("format", skin_format) | ||||
| 		file:close() | ||||
| 	end | ||||
|  | ||||
| 	skin_obj:set_hand_from_texture() | ||||
| 	skin_obj:set_meta("name", identifier) | ||||
|  | ||||
| 	if path then | ||||
| 		-- Optional skin information | ||||
| 		local file = io.open(path .. "/../meta/" .. filename_noext .. ".txt", "r") | ||||
| 		if file then | ||||
| 			dbgprint("Found meta") | ||||
| 			local data = string.split(file:read("*all"), "\n", 3) | ||||
| 			skin_obj:set_meta("name", data[1]) | ||||
| 			skin_obj:set_meta("author", data[2]) | ||||
| 			skin_obj:set_meta("license", data[3]) | ||||
| 		end | ||||
| 	end | ||||
|  | ||||
| 		local skin_obj = skins.get(name) or skins.new(name) | ||||
| 		if is_preview then | ||||
| 			skin_obj:set_preview(fn) | ||||
| 		else | ||||
| 			skin_obj:set_texture(fn) | ||||
| 			skin_obj:set_meta("_sort_id", sort_id) | ||||
| 			if playername then | ||||
| 				skin_obj:set_meta("assignment", "player:"..playername) | ||||
| 				skin_obj:set_meta("playername", playername) | ||||
| 			end | ||||
| 			local file = io.open(skins.modpath.."/textures/"..fn, "r") | ||||
| 			skin_obj:set_meta("format", skins.get_skin_format(file)) | ||||
| 			file:close() | ||||
| 			file = io.open(skins.modpath.."/meta/"..name..".txt", "r") | ||||
| 			if file then | ||||
| 				local data = string.split(file:read("*all"), "\n", 3) | ||||
| 				file:close() | ||||
| 				skin_obj:set_meta("name", data[1]) | ||||
| 				skin_obj:set_meta("author", data[2]) | ||||
| 				skin_obj:set_meta("license", data[3]) | ||||
| 			else | ||||
| 				-- remove player / character prefix if further naming given | ||||
| 				if nameparts[2] and not tonumber(nameparts[2]) then | ||||
| 					table.remove(nameparts, 1) | ||||
| 				end | ||||
| 				skin_obj:set_meta("name", table.concat(nameparts, ' ')) | ||||
| 			end | ||||
| 	if path then | ||||
| 		-- Optional preview texture | ||||
| 		local preview_name = filename_noext .. sep .. "preview.png" | ||||
| 		local fh = io.open(path .. "/" .. preview_name) | ||||
| 		if fh then | ||||
| 			dbgprint("Found preview", preview_name) | ||||
| 			skin_obj:set_preview(preview_name) | ||||
| 		end | ||||
| 	end | ||||
|  | ||||
| 	return true, skin_obj:get_key() | ||||
| end | ||||
|  | ||||
| --- Internal function. Fallback/migration code for `.`-delimited skin names that | ||||
| --- were equipped between d3c7fa7 and 312780c (master branch). | ||||
| --- During this period, `.`-delimited skin names were internally registered with | ||||
| --- `_` delimiters. This function tries to find a matching skin. | ||||
| --- @param player_name (string) | ||||
| --- @param skin_name   (string) e.g. `player_foo_mc_bar` | ||||
| --- @param be_noisy    (boolean) whether to print a warning in case of mismatches` | ||||
| --- @return On match, the new skin (skins.skin_class) or `nil` if nothing matched. | ||||
| function skins.__fuzzy_match_skin_name(player_name, skin_name, be_noisy) | ||||
| 	if select(2, skin_name:gsub("%.", "")) > 0 then | ||||
| 		-- Not affected by ambiguity | ||||
| 		return | ||||
| 	end | ||||
|  | ||||
| 	for _, skin in pairs(skins.meta) do | ||||
| 		if skin._legacy_name == skin_name then | ||||
| 			dbgprint("Match", skin_name, skin:get_key()) | ||||
| 			return skin | ||||
| 		end | ||||
| 		--dbgprint("Try match", skin_name, skin:get_key(), skin._legacy_name) | ||||
| 	end | ||||
|  | ||||
| 	if be_noisy then | ||||
| 		minetest.log("warning", "skinsdb: cannot find matching skin '" .. | ||||
| 			skin_name .. "' for player '" .. player_name .. "'.") | ||||
| 	end | ||||
| end | ||||
|  | ||||
| do | ||||
| 	-- Load skins from the current mod directory | ||||
| 	local skins_path = skins.modpath.."/textures" | ||||
| 	local skins_dir_list = minetest.get_dir_list(skins_path) | ||||
|  | ||||
| 	for _, fn in pairs(skins_dir_list) do | ||||
| 		skins.register_skin(skins_path, fn) | ||||
| 	end | ||||
| end | ||||
|  | ||||
| local function skins_sort(skinslist) | ||||
| @@ -73,9 +151,9 @@ local function skins_sort(skinslist) | ||||
| 		local a_id = a:get_meta("_sort_id") or 10000 | ||||
| 		local b_id = b:get_meta("_sort_id") or 10000 | ||||
| 		if a_id ~= b_id then | ||||
| 			return a:get_meta("_sort_id") < b:get_meta("_sort_id") | ||||
| 			return a_id < b_id | ||||
| 		else | ||||
| 			return a:get_meta("name") < b:get_meta("name") | ||||
| 			return (a:get_meta("name") or 'ZZ') < (b:get_meta("name") or 'ZZ') | ||||
| 		end | ||||
| 	end) | ||||
| end | ||||
|   | ||||
| @@ -20,7 +20,7 @@ if not ie or not http then | ||||
| end | ||||
|  | ||||
| minetest.register_chatcommand("skinsdb_download_skins", { | ||||
| 	params = "<skindb start page> <amount of pages>", | ||||
| 	params = S("<skindb start page> <amount of pages>"), | ||||
| 	description = S("Downloads the specified range of skins and shuts down the server"), | ||||
| 	privs = {server=true}, | ||||
| 	func = function(name, param) | ||||
| @@ -47,13 +47,12 @@ if #internal.errors > 0 then | ||||
| end | ||||
|  | ||||
| -- http://minetest.fensta.bplaced.net/api/apidoku.md | ||||
| local root_url = "http://minetest.fensta.bplaced.net" | ||||
| local page_url = root_url .. "/api/v2/get.json.php?getlist&page=%i&outformat=base64" -- [1] = Page# | ||||
| local preview_url = root_url .. "/skins/1/%i.png" -- [1] = ID | ||||
| local root_url = "http://skinsdb.terraqueststudios.net" | ||||
| local page_url = root_url .. "/api/v1/content?client=mod&page=%i" -- [1] = Page# | ||||
|  | ||||
| local mod_path = skins.modpath | ||||
| local meta_path = mod_path .. "/meta/" | ||||
| local skins_path = mod_path .. "/textures/" | ||||
| local download_path = skins.modpath | ||||
| local meta_path = download_path .. "/meta/" | ||||
| local skins_path = download_path .. "/textures/" | ||||
|  | ||||
| -- Fancy debug wrapper to download an URL | ||||
| local function fetch_url(url, callback) | ||||
| @@ -81,14 +80,22 @@ local function unsafe_file_write(path, contents) | ||||
| end | ||||
|  | ||||
| -- Takes a valid skin table from the Skins Database and saves it | ||||
| local function safe_single_skin(skin) | ||||
| local function save_single_skin(skin) | ||||
| 	local meta = { | ||||
| 		skin.name, | ||||
| 		skin.author, | ||||
| 		skin.license | ||||
| 	} | ||||
|  | ||||
| 	local name =  "character_" .. skin.id | ||||
| 	local name = "character." .. skin.id | ||||
| 	do | ||||
| 		local legacy_name = "character_" .. skin.id | ||||
| 		local fh = ie.io.open(skins_path .. legacy_name .. ".png", "r") | ||||
| 		-- Use the old name if either the texture ... | ||||
| 		if fh then | ||||
| 			name = legacy_name | ||||
| 		end | ||||
| 	end | ||||
|  | ||||
| 	-- core.safe_file_write does not work here | ||||
| 	unsafe_file_write( | ||||
| @@ -100,9 +107,6 @@ local function safe_single_skin(skin) | ||||
| 		skins_path .. name .. ".png", | ||||
| 		core.decode_base64(skin.img) | ||||
| 	) | ||||
| 	fetch_url(preview_url:format(skin.id), function(preview) | ||||
| 		unsafe_file_write(skins_path .. name .. "_preview.png", preview) | ||||
| 	end) | ||||
| 	core.log("action", ("%s: Completed skin %s"):format(_ID_, name)) | ||||
| end | ||||
|  | ||||
| @@ -115,7 +119,7 @@ internal.get_pages_count = function(callback, ...) | ||||
| 		callback(math.ceil(list.pages / 20), unpack(vars)) | ||||
| 	end) | ||||
| end | ||||
| 	 | ||||
|  | ||||
| -- Function to fetch a range of pages | ||||
| internal.fetch_function = function(pages_total, start_page, len) | ||||
| 	start_page = math.max(start_page, 1) | ||||
| @@ -132,7 +136,7 @@ internal.fetch_function = function(pages_total, start_page, len) | ||||
| 				assert(skin.id ~= "") | ||||
|  | ||||
| 				if skin.id ~= 1 then -- Skin 1 is bundled with skinsdb | ||||
| 					safe_single_skin(skin) | ||||
| 					save_single_skin(skin) | ||||
| 				end | ||||
| 			end | ||||
|  | ||||
|   | ||||
| @@ -1,13 +1,32 @@ | ||||
| In this folder the skin files could be placed according the following file naming convention. | ||||
| This location is where you can put your custom skins. | ||||
|  | ||||
|  | ||||
| List of accepted texture names | ||||
| ------------------------------ | ||||
|  | ||||
| Public skin available for all users: | ||||
| 	character_[number-or-name].png | ||||
| 	character.[number or name].png | ||||
|  | ||||
| One or multiple private skins for player "nick": | ||||
| 	player_[nick].png or | ||||
| 	player_[nick]_[number-or-name].png | ||||
| One or multiple private skins for player "[nick]": | ||||
| 	player.[nick].png | ||||
| 	player.[nick].[number or name].png | ||||
|  | ||||
| Preview files for public and private skins. | ||||
| Optional, overrides the generated preview | ||||
| 	character_*_preview.png or | ||||
| 	player_*_*_preview.png | ||||
| Skin previews for public and private skins: | ||||
| 	character.[number or name].preview.png | ||||
| 	player.[nick].preview.png | ||||
| 	player.[nick].[number or name].preview.png | ||||
|  | ||||
| 	Note: This is optional and overrides automatically generated preciewws. | ||||
|  | ||||
|  | ||||
| Legacy texture names | ||||
| -------------------- | ||||
|  | ||||
| The character `_` is accepted in player names, thus it is not recommended to | ||||
| use such file names. For compatibility reasons, they are still recognized. | ||||
|  | ||||
| 	character_[number or name].png | ||||
| 	player_[nick].png | ||||
| 	player_[nick]_[number or name].png | ||||
|  | ||||
| ... and corresponding previews that end in `_preview.png`. | ||||
|   | ||||
										
											Binary file not shown.
										
									
								
							| Before Width: | Height: | Size: 6.0 KiB | 
| @@ -1,10 +1,13 @@ | ||||
| local S = minetest.get_translator("skinsdb") | ||||
|  | ||||
| unified_inventory.register_page("skins", { | ||||
| 	get_formspec = function(player) | ||||
| 	get_formspec = function(player, perplayer_formspec) | ||||
| 		local skin = skins.get_player_skin(player) | ||||
| 		local formspec = "background[0.06,0.99;7.92,7.52;ui_misc_form.png]"..skins.get_skin_info_formspec(skin).. | ||||
| 				"button[.75,3;6.5,.5;skins_page;"..S("Change").."]" | ||||
| 		local boffs = (type(perplayer_formspec) == "table") and 2 or 0.75 | ||||
|  | ||||
| 		local formspec = perplayer_formspec.standard_inv_bg.. | ||||
| 			skins.get_skin_info_formspec(skin, perplayer_formspec).. | ||||
| 			"button["..boffs..",3;6.5,.5;skins_page;"..S("Change").."]" | ||||
| 		return {formspec=formspec} | ||||
| 	end, | ||||
| }) | ||||
| @@ -15,16 +18,16 @@ unified_inventory.register_button("skins", { | ||||
| 	tooltip = S("Skins"), | ||||
| }) | ||||
|  | ||||
| local function get_formspec(player) | ||||
| local function get_formspec(player, perplayer_formspec) | ||||
| 	local context = skins.get_formspec_context(player) | ||||
| 	local formspec = "background[0.06,0.99;7.92,7.52;ui_misc_form.png]".. | ||||
| 			skins.get_skin_selection_formspec(player, context, -0.2) | ||||
| 	local formspec = perplayer_formspec.standard_inv_bg.. | ||||
| 			skins.get_skin_selection_formspec(player, context, perplayer_formspec) | ||||
| 	return formspec | ||||
| end | ||||
|  | ||||
| unified_inventory.register_page("skins_page", { | ||||
| 	get_formspec = function(player) | ||||
| 		return {formspec=get_formspec(player)} | ||||
| 	get_formspec = function(player, perplayer_formspec) | ||||
| 		return {formspec=get_formspec(player, perplayer_formspec)} | ||||
| 	end | ||||
| }) | ||||
|  | ||||
|   | ||||
							
								
								
									
										50
									
								
								unittest.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								unittest.lua
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,50 @@ | ||||
| local function get_skin(skin_name) | ||||
| 	local skin = skins.get(skin_name) | ||||
| 		or skins.__fuzzy_match_skin_name("(unittest)", skin_name, true) | ||||
| 	return skin and skin:get_key() or nil | ||||
| end | ||||
|  | ||||
| local function run_unittest() | ||||
| 	local PATH = ":UNITTEST:" | ||||
|  | ||||
| 	-- ----- | ||||
| 	-- `.`: Simple register + retrieve operations | ||||
| 	skins.register_skin(PATH, "player.DotSep.png") | ||||
| 	skins.register_skin(PATH, "player._DotSep_666_.1.png") | ||||
|  | ||||
| 	assert(get_skin("player.DotSep")) | ||||
| 	assert(get_skin("player._DotSep_666_.1")) | ||||
| 	assert(get_skin("player.DotSep.1") == nil) | ||||
|  | ||||
| 	-- ----- | ||||
| 	-- Ambiguous skin names (filenames without extension). Register + retrieve | ||||
| 	skins.new("player_AmbSki") | ||||
| 	skins.new("player_AmbSki_1") | ||||
| 	skins.new("player_AmbSki_666_1") | ||||
|  | ||||
| 	assert(get_skin("player_AmbSki")) | ||||
| 	assert(get_skin("player_AmbSki_") == nil) | ||||
| 	assert(get_skin("player_AmbSki_1")) | ||||
| 	assert(get_skin("player_AmbSki_666_1")) | ||||
| 	-- There are no `__` patterns as they were silently removed by string.split | ||||
|  | ||||
|  | ||||
| 	-- ----- | ||||
| 	-- Mod Storage backwards compatibility | ||||
| 	-- Match the old `_` notation to `.`-separated skins | ||||
| 	skins.register_skin(PATH, "player.ComPat42.png") | ||||
| 	skins.register_skin(PATH, "player.ComPat42.5.png") | ||||
| 	skins.register_skin(PATH, "player._Com_Pat_42.png") | ||||
| 	skins.register_skin(PATH, "player._Com_Pat_42.1.png") | ||||
|  | ||||
| 	assert(get_skin("player_ComPat42") == "player.ComPat42") | ||||
| 	assert(get_skin("player_ComPat42_5") == "player.ComPat42.5") | ||||
| 	assert(get_skin("player_Com_Pat_42") == "player._Com_Pat_42") | ||||
| 	assert(get_skin("player_Com_Pat_42_1") == "player._Com_Pat_42.1") | ||||
|  | ||||
|  | ||||
| 	error("Unittest passed! Please disable them now.") | ||||
| end | ||||
|  | ||||
| run_unittest() | ||||
|  | ||||
| @@ -1,11 +1,9 @@ | ||||
| import sys, requests, base64 | ||||
|  | ||||
| download_preview = ( len (sys.argv) > 1 and sys.argv[1] == "with_preview" ) | ||||
| import os.path, sys, requests, base64 | ||||
|  | ||||
|  | ||||
| print("Downloading skins from minetest.fensta.bplaced.net ...") | ||||
| print("Downloading skins from skinsdb.terraqueststudio.net ...") | ||||
| # Requesting all skins and their raw texture using the API | ||||
| r = requests.get('http://minetest.fensta.bplaced.net/api/v2/get.json.php?getlist&page=1&per_page=999999999') | ||||
| r = requests.get('http://skinsdb.terraqueststudios.net/api/v1/content?client=script&page=1&per_page=10000') | ||||
|  | ||||
| if r.status_code != 200: | ||||
|     sys.exit("Request failed!") | ||||
| @@ -13,42 +11,33 @@ if r.status_code != 200: | ||||
| data = r.json() | ||||
| count = 0 | ||||
|  | ||||
| if download_preview: | ||||
|     print("Writing to file and downloading previews ...") | ||||
| else: | ||||
|     print("Writing skins") | ||||
| print("Writing skins") | ||||
|  | ||||
|  | ||||
| for json in data["skins"]: | ||||
|     id = str(json["id"]) | ||||
|  | ||||
|     name = "character." + id | ||||
|     if True: | ||||
|         legacy_name = "character_" + id | ||||
|         if os.path.exists("../textures/" + legacy_name + ".png"): | ||||
|             name = legacy_name | ||||
|  | ||||
|  | ||||
|     # Texture file | ||||
|     raw_data = base64.b64decode(json["img"]) | ||||
|     file = open("../textures/character_" + id + ".png", "wb") | ||||
|     file = open("../textures/" + name + ".png", "wb") | ||||
|     file.write(bytearray(raw_data)) | ||||
|     file.close() | ||||
|  | ||||
|     # Meta file | ||||
|     name = str(json["name"]) | ||||
|     author = str(json["author"]) | ||||
|     license = str(json["license"]) | ||||
|     file = open("../meta/character_" + id + ".txt", "w") | ||||
|     file.write(name + "\n" + author + "\n" + license + "\n") | ||||
|     meta_name = str(json["name"]) | ||||
|     meta_author = str(json["author"]) | ||||
|     meta_license = str(json["license"]) | ||||
|     file = open("../meta/" + name + ".txt", "w") | ||||
|     file.write(meta_name + "\n" + meta_author + "\n" + meta_license + "\n") | ||||
|     file.close() | ||||
|     print("Added #%s Name: %s Author: %s License: %s" % (id, name, author, license)) | ||||
|     print("Added #%s Name: %s Author: %s License: %s" % (id, meta_name, meta_author, meta_license)) | ||||
|     count += 1 | ||||
|  | ||||
|     if download_preview: | ||||
|         # Downloading the preview of the skin | ||||
|         r2 = requests.get('http://minetest.fensta.bplaced.net/skins/1/' + id + ".png") | ||||
|         if r2.status_code == 200: | ||||
|             # Preview file | ||||
|             preview = r2.content | ||||
|             file = open("../textures/character_" + id + "_preview.png", "wb") | ||||
|             file.write(bytearray(preview)) | ||||
|             file.close() | ||||
|         else: | ||||
|             print("Failed to download skin preview #" + id) | ||||
|  | ||||
|  | ||||
| print("Fetched " + str(count) + " skins!") | ||||
|   | ||||
		Reference in New Issue
	
	Block a user