init.lua 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286
  1. -- Simple Skins mod for minetest
  2. -- Adds a simple skin selector to the inventory by using
  3. -- the default sfinv or inventory_plus when running.
  4. -- Released by TenPlus1 and based on Zeg9's code under MIT license
  5. skins = {
  6. skins = {}, list = {}, meta = {},
  7. modpath = minetest.get_modpath("simple_skins"),
  8. invplus = minetest.get_modpath("inventory_plus"),
  9. sfinv = minetest.get_modpath("sfinv"),
  10. file = minetest.get_worldpath() .. "/simple_skins.mt",
  11. formspec = {},
  12. }
  13. -- Load support for intllib.
  14. local S, NS = dofile(skins.modpath .. "/intllib.lua")
  15. -- load skin list and metadata
  16. local id, f, data, skin = 1
  17. while true do
  18. skin = "character_" .. id
  19. -- does skin file exist ?
  20. f = io.open(skins.modpath .. "/textures/" .. skin .. ".png")
  21. -- escape loop if not found and remove last entry
  22. if not f then
  23. skins.list[id] = nil
  24. id = id - 1
  25. break
  26. end
  27. f:close()
  28. table.insert(skins.list, skin)
  29. -- does metadata exist for that skin file ?
  30. f = io.open(skins.modpath .. "/meta/" .. skin .. ".txt")
  31. if f then
  32. data = minetest.deserialize("return {" .. f:read('*all') .. "}")
  33. f:close()
  34. end
  35. -- add metadata to list
  36. skins.meta[skin] = {
  37. name = data and data.name or "",
  38. author = data and data.author or "",
  39. }
  40. id = id + 1
  41. end
  42. -- load player skins file for backwards compatibility
  43. local input = io.open(skins.file, "r")
  44. local data = nil
  45. if input then
  46. data = input:read('*all')
  47. io.close(input)
  48. end
  49. if data and data ~= "" then
  50. local lines = string.split(data, "\n")
  51. for _, line in pairs(lines) do
  52. data = string.split(line, " ", 2)
  53. skins.skins[data[1]] = data[2]
  54. end
  55. end
  56. -- create formspec for skin selection page
  57. skins.formspec.main = function(name)
  58. local formspec = ""
  59. if skins.invplus then
  60. formspec = "size[8,8.6]"
  61. .. "bgcolor[#08080822;true]"
  62. end
  63. formspec = formspec .. "label[.5,2;" .. S("Select Player Skin:") .. "]"
  64. .. "textlist[.5,2.5;6.8,6;skins_set;"
  65. local meta
  66. local selected = 1
  67. for i = 1, #skins.list do
  68. formspec = formspec .. skins.meta[ skins.list[i] ].name
  69. if skins.skins[name] == skins.list[i] then
  70. selected = i
  71. meta = skins.meta[ skins.skins[name] ]
  72. end
  73. if i < #skins.list then
  74. formspec = formspec ..","
  75. end
  76. end
  77. if skins.invplus then
  78. formspec = formspec .. ";" .. selected .. ";true]"
  79. else
  80. formspec = formspec .. ";" .. selected .. ";false]"
  81. end
  82. if meta then
  83. if meta.name then
  84. formspec = formspec .. "label[2,.5;" .. S("Name: ") .. meta.name .. "]"
  85. end
  86. if meta.author then
  87. formspec = formspec .. "label[2,1;" .. S("Author: ") .. meta.author .. "]"
  88. end
  89. end
  90. return formspec
  91. end
  92. -- update player skin
  93. skins.update_player_skin = function(player)
  94. if not player then
  95. return
  96. end
  97. local name = player:get_player_name()
  98. default.player_set_textures(player, skins.skins[name] .. ".png")
  99. end
  100. -- register sfinv tab when inv+ not active
  101. if skins.sfinv and not skins.invplus then
  102. sfinv.register_page("skins:skins", {title = "Skins",
  103. get = function(self, player, context)
  104. local name = player:get_player_name()
  105. return sfinv.make_formspec(player, context,skins.formspec.main(name))
  106. end,
  107. on_player_receive_fields = function(self, player, context, fields)
  108. local event = minetest.explode_textlist_event(fields["skins_set"])
  109. if event.type == "CHG" then
  110. local index = event.index
  111. if index > id then index = id end
  112. local name = player:get_player_name()
  113. skins.skins[name] = skins.list[index]
  114. skins.update_player_skin(player)
  115. player:set_attribute("simple_skins:skin", skins.skins[name])
  116. sfinv.override_page("skins:skins", {
  117. get = function(self, player, context)
  118. local name = player:get_player_name()
  119. return sfinv.make_formspec(player, context,
  120. skins.formspec.main(name))
  121. end,
  122. })
  123. sfinv.set_player_inventory_formspec(player)
  124. end
  125. end,
  126. })
  127. end
  128. -- load player skin on join
  129. minetest.register_on_joinplayer(function(player)
  130. local name = player:get_player_name()
  131. local skin = player:get_attribute("simple_skins:skin")
  132. -- do we already have a skin in player attributes?
  133. if skin then
  134. skins.skins[name] = skin
  135. -- otherwise use skin from simple_skins.mt file or default if not set
  136. elseif not skins.skins[name] then
  137. skins.skins[name] = "character_1"
  138. end
  139. skins.update_player_skin(player)
  140. if skins.invplus then
  141. inventory_plus.register_button(player,"skins", "Skin")
  142. end
  143. end)
  144. -- formspec control for inventory_plus
  145. minetest.register_on_player_receive_fields(function(player, formname, fields)
  146. if skins.sfinv and not skins.invplus then
  147. return
  148. end
  149. local name = player:get_player_name()
  150. if fields.skins then
  151. inventory_plus.set_inventory_formspec(player,
  152. skins.formspec.main(name) .. "button[0,.75;2,.5;main;Back]")
  153. end
  154. local event = minetest.explode_textlist_event(fields["skins_set"])
  155. if event.type == "CHG" then
  156. local index = math.min(event.index, id)
  157. if not skins.list[index] then
  158. return -- Do not update wrong skin number
  159. end
  160. skins.skins[name] = skins.list[index]
  161. if skins.invplus then
  162. inventory_plus.set_inventory_formspec(player,
  163. skins.formspec.main(name) .. "button[0,.75;2,.5;main;Back]")
  164. end
  165. skins.update_player_skin(player)
  166. player:set_attribute("simple_skins:skin", skins.skins[name])
  167. end
  168. end)
  169. -- admin command to set player skin (usually for custom skins)
  170. minetest.register_chatcommand("setskin", {
  171. params = "<player> <skin number>",
  172. description = S("Admin command to set player skin"),
  173. privs = {server = true},
  174. func = function(name, param)
  175. local playername, skin = string.match(param, "([^ ]+) (-?%d+)")
  176. if not playername or not skin then
  177. return false, S("** Insufficient or wrong parameters")
  178. end
  179. local player = minetest.get_player_by_name(playername)
  180. if not player then
  181. return false, S("** Player @1 not online!", playername)
  182. end
  183. -- this check is only used when custom skins aren't in use
  184. -- if not skins.list[tonumber(skin)] then
  185. -- return false, S("** Invalid skin number (max value is @1)", id)
  186. -- end
  187. skins.skins[playername] = "character_" .. tonumber(skin)
  188. skins.update_player_skin(player)
  189. player:set_attribute("simple_skins:skin", skins.skins[playername])
  190. minetest.chat_send_player(playername,
  191. S("Your skin has been set to") .. " character_" .. skin)
  192. return true, "** " .. playername .. S("'s skin set to")
  193. .. " character_" .. skin .. ".png"
  194. end,
  195. })
  196. print (S("[MOD] Simple Skins loaded"))