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 = {}, formspec = {},
  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. }
  12. -- Load support for intllib.
  13. local S, NS = dofile(skins.modpath .. "/intllib.lua")
  14. -- load skin list and metadata
  15. local id, f, data, skin = 1
  16. while true do
  17. skin = "character_" .. id
  18. -- does skin file exist ?
  19. f = io.open(skins.modpath .. "/textures/" .. skin .. ".png")
  20. -- escape loop if not found and remove last entry
  21. if not f then
  22. skins.list[id] = nil
  23. id = id - 1
  24. break
  25. end
  26. f:close()
  27. table.insert(skins.list, skin)
  28. -- does metadata exist for that skin file ?
  29. f = io.open(skins.modpath .. "/meta/" .. skin .. ".txt")
  30. if f then
  31. data = minetest.deserialize("return {" .. f:read("*all") .. "}")
  32. f:close()
  33. end
  34. -- add metadata to list
  35. skins.meta[skin] = {
  36. name = data and data.name or "",
  37. author = data and data.author or "",
  38. }
  39. id = id + 1
  40. end
  41. -- load player skins file for backwards compatibility
  42. local input = io.open(skins.file, "r")
  43. local data = nil
  44. if input then
  45. data = input:read("*all")
  46. io.close(input)
  47. end
  48. if data and data ~= "" then
  49. local lines = string.split(data, "\n")
  50. for _, line in pairs(lines) do
  51. data = string.split(line, " ", 2)
  52. skins.skins[data[1]] = data[2]
  53. end
  54. end
  55. -- create formspec for skin selection page
  56. skins.formspec.main = function(name)
  57. local formspec = ""
  58. if skins.invplus then
  59. formspec = "size[8,8.6]"
  60. .. "bgcolor[#08080822;true]"
  61. end
  62. formspec = formspec .. "label[.5,2;" .. S("Select Player Skin:") .. "]"
  63. .. "textlist[.5,2.5;6.8,6;skins_set;"
  64. local meta
  65. local selected = 1
  66. for i = 1, #skins.list do
  67. formspec = formspec .. skins.meta[ skins.list[i] ].name
  68. if skins.skins[name] == skins.list[i] then
  69. selected = i
  70. meta = skins.meta[ skins.skins[name] ]
  71. end
  72. if i < #skins.list then
  73. formspec = formspec ..","
  74. end
  75. end
  76. if skins.invplus then
  77. formspec = formspec .. ";" .. selected .. ";true]"
  78. else
  79. formspec = formspec .. ";" .. selected .. ";false]"
  80. end
  81. if meta then
  82. if meta.name then
  83. formspec = formspec .. "label[2,.5;" .. S("Name: ") .. meta.name .. "]"
  84. end
  85. if meta.author then
  86. formspec = formspec .. "label[2,1;" .. S("Author: ") .. meta.author .. "]"
  87. end
  88. end
  89. return formspec
  90. end
  91. -- update player skin
  92. skins.update_player_skin = function(player)
  93. if not player then
  94. return
  95. end
  96. local name = player:get_player_name()
  97. default.player_set_textures(player, skins.skins[name] .. ".png")
  98. end
  99. -- register sfinv tab when inv+ not active
  100. if skins.sfinv and not skins.invplus then
  101. sfinv.register_page("skins:skins", {title = "Skins",
  102. get = function(self, player, context)
  103. local name = player:get_player_name()
  104. return sfinv.make_formspec(player, context,skins.formspec.main(name))
  105. end,
  106. on_player_receive_fields = function(self, player, context, fields)
  107. local event = minetest.explode_textlist_event(fields["skins_set"])
  108. if event.type == "CHG" then
  109. local index = event.index
  110. if index > id then index = id end
  111. local name = player:get_player_name()
  112. skins.skins[name] = skins.list[index]
  113. skins.update_player_skin(player)
  114. player:set_attribute("simple_skins:skin", skins.skins[name])
  115. sfinv.override_page("skins:skins", {
  116. get = function(self, player, context)
  117. local name = player:get_player_name()
  118. return sfinv.make_formspec(player, context,
  119. skins.formspec.main(name))
  120. end,
  121. })
  122. sfinv.set_player_inventory_formspec(player)
  123. end
  124. end,
  125. })
  126. end
  127. -- load player skin on join
  128. minetest.register_on_joinplayer(function(player)
  129. local name = player:get_player_name()
  130. local skin = player:get_attribute("simple_skins:skin")
  131. -- do we already have a skin in player attributes?
  132. if skin then
  133. skins.skins[name] = skin
  134. -- otherwise use skin from simple_skins.mt file or default if not set
  135. elseif not skins.skins[name] then
  136. skins.skins[name] = "character_1"
  137. end
  138. skins.update_player_skin(player)
  139. if skins.invplus then
  140. inventory_plus.register_button(player,"skins", "Skin", 0,
  141. "inventory_plus_skins.png")
  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"))