2020-10-25 19:05:08 +01:00
|
|
|
skins.meta = {}
|
|
|
|
|
2024-12-19 12:55:40 +01:00
|
|
|
local has_hand_monoid = minetest.get_modpath("hand_monoid")
|
|
|
|
|
2020-10-25 19:05:08 +01:00
|
|
|
local skin_class = {}
|
|
|
|
skin_class.__index = skin_class
|
|
|
|
skins.skin_class = skin_class
|
|
|
|
-----------------------
|
|
|
|
-- Class methods
|
|
|
|
-----------------------
|
|
|
|
-- constructor
|
|
|
|
function skins.new(key, object)
|
|
|
|
assert(key, 'Unique skins key required, like "character_1"')
|
|
|
|
local self = object or {}
|
|
|
|
setmetatable(self, skin_class)
|
|
|
|
self.__index = skin_class
|
|
|
|
|
|
|
|
self._key = key
|
|
|
|
self._sort_id = 0
|
|
|
|
skins.meta[key] = self
|
|
|
|
return self
|
|
|
|
end
|
|
|
|
|
|
|
|
-- getter
|
|
|
|
function skins.get(key)
|
|
|
|
return skins.meta[key]
|
|
|
|
end
|
|
|
|
|
|
|
|
-- Skin methods
|
|
|
|
-- In this implementation it is just access to attrubutes wrapped
|
|
|
|
-- but this way allow to redefine the functionality for more complex skins provider
|
|
|
|
function skin_class:get_key()
|
|
|
|
return self._key
|
|
|
|
end
|
|
|
|
|
|
|
|
function skin_class:set_meta(key, value)
|
|
|
|
self[key] = value
|
|
|
|
end
|
|
|
|
|
|
|
|
function skin_class:get_meta(key)
|
|
|
|
return self[key]
|
|
|
|
end
|
|
|
|
|
|
|
|
function skin_class:get_meta_string(key)
|
|
|
|
return tostring(self:get_meta(key) or "")
|
|
|
|
end
|
|
|
|
|
|
|
|
function skin_class:set_texture(value)
|
|
|
|
self._texture = value
|
|
|
|
end
|
|
|
|
|
|
|
|
function skin_class:get_texture()
|
|
|
|
return self._texture
|
|
|
|
end
|
|
|
|
|
2024-12-19 12:55:40 +01:00
|
|
|
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
|
|
|
|
|
2020-10-25 19:05:08 +01:00
|
|
|
function skin_class:set_preview(value)
|
|
|
|
self._preview = value
|
|
|
|
end
|
|
|
|
|
|
|
|
function skin_class:get_preview()
|
|
|
|
if self._preview then
|
|
|
|
return self._preview
|
|
|
|
end
|
|
|
|
|
|
|
|
local player_skin = "("..self:get_texture()..")"
|
|
|
|
local skin = ""
|
|
|
|
|
|
|
|
-- Consistent on both sizes:
|
|
|
|
--Chest
|
|
|
|
skin = skin .. "([combine:16x32:-16,-12=" .. player_skin .. "^[mask:skindb_mask_chest.png)^"
|
|
|
|
--Head
|
|
|
|
skin = skin .. "([combine:16x32:-4,-8=" .. player_skin .. "^[mask:skindb_mask_head.png)^"
|
|
|
|
--Hat
|
|
|
|
skin = skin .. "([combine:16x32:-36,-8=" .. player_skin .. "^[mask:skindb_mask_head.png)^"
|
|
|
|
--Right Arm
|
|
|
|
skin = skin .. "([combine:16x32:-44,-12=" .. player_skin .. "^[mask:skindb_mask_rarm.png)^"
|
|
|
|
--Right Leg
|
|
|
|
skin = skin .. "([combine:16x32:0,0=" .. player_skin .. "^[mask:skindb_mask_rleg.png)^"
|
|
|
|
|
|
|
|
-- 64x skins have non-mirrored arms and legs
|
|
|
|
local left_arm
|
|
|
|
local left_leg
|
|
|
|
|
|
|
|
if self:get_meta("format") == "1.8" then
|
|
|
|
left_arm = "([combine:16x32:-24,-44=" .. player_skin .. "^[mask:(skindb_mask_rarm.png^[transformFX))^"
|
|
|
|
left_leg = "([combine:16x32:-12,-32=" .. player_skin .. "^[mask:(skindb_mask_rleg.png^[transformFX))^"
|
|
|
|
else
|
|
|
|
left_arm = "([combine:16x32:-44,-12=" .. player_skin .. "^[mask:skindb_mask_rarm.png^[transformFX)^"
|
|
|
|
left_leg = "([combine:16x32:0,0=" .. player_skin .. "^[mask:skindb_mask_rleg.png^[transformFX)^"
|
|
|
|
end
|
|
|
|
|
|
|
|
-- Left Arm
|
|
|
|
skin = skin .. left_arm
|
|
|
|
--Left Leg
|
|
|
|
skin = skin .. left_leg
|
|
|
|
|
|
|
|
-- Add overlays for 64x skins. these wont appear if skin is 32x because it will be cropped out
|
|
|
|
--Chest Overlay
|
|
|
|
skin = skin .. "([combine:16x32:-16,-28=" .. player_skin .. "^[mask:skindb_mask_chest.png)^"
|
|
|
|
--Right Arm Overlay
|
|
|
|
skin = skin .. "([combine:16x32:-44,-28=" .. player_skin .. "^[mask:skindb_mask_rarm.png)^"
|
|
|
|
--Right Leg Overlay
|
|
|
|
skin = skin .. "([combine:16x32:0,-16=" .. player_skin .. "^[mask:skindb_mask_rleg.png)^"
|
|
|
|
--Left Arm Overlay
|
|
|
|
skin = skin .. "([combine:16x32:-40,-44=" .. player_skin .. "^[mask:(skindb_mask_rarm.png^[transformFX))^"
|
|
|
|
--Left Leg Overlay
|
|
|
|
skin = skin .. "([combine:16x32:4,-32=" .. player_skin .. "^[mask:(skindb_mask_rleg.png^[transformFX))"
|
|
|
|
|
|
|
|
-- Full Preview
|
|
|
|
skin = "(((" .. skin .. ")^[resize:64x128)^[mask:skindb_transform.png)"
|
|
|
|
|
|
|
|
return skin
|
|
|
|
end
|
|
|
|
|
|
|
|
function skin_class:apply_skin_to_player(player)
|
|
|
|
|
|
|
|
local function concat_texture(base, ext)
|
|
|
|
if base == "blank.png" then
|
|
|
|
return ext
|
|
|
|
elseif ext == "blank.png" then
|
|
|
|
return base
|
|
|
|
else
|
|
|
|
return base .. "^" .. ext
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
local playername = player:get_player_name()
|
|
|
|
local ver = self:get_meta("format") or "1.0"
|
|
|
|
|
|
|
|
player_api.set_model(player, "skinsdb_3d_armor_character_5.b3d")
|
|
|
|
|
|
|
|
local v10_texture = "blank.png"
|
|
|
|
local v18_texture = "blank.png"
|
|
|
|
local armor_texture = "blank.png"
|
|
|
|
local wielditem_texture = "blank.png"
|
|
|
|
|
|
|
|
if ver == "1.8" then
|
|
|
|
v18_texture = self:get_texture()
|
|
|
|
else
|
|
|
|
v10_texture = self:get_texture()
|
|
|
|
end
|
|
|
|
|
|
|
|
-- Support for clothing
|
|
|
|
if skins.clothing_loaded and clothing.player_textures[playername] then
|
|
|
|
local cape = clothing.player_textures[playername].cape
|
|
|
|
local layers = {}
|
|
|
|
for k, v in pairs(clothing.player_textures[playername]) do
|
|
|
|
if k ~= "skin" and k ~= "cape" then
|
|
|
|
table.insert(layers, v)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
local overlay = table.concat(layers, "^")
|
|
|
|
v10_texture = concat_texture(v10_texture, cape)
|
|
|
|
v18_texture = concat_texture(v18_texture, overlay)
|
|
|
|
end
|
|
|
|
|
|
|
|
-- Support for armor
|
|
|
|
if skins.armor_loaded then
|
|
|
|
local armor_textures = armor.textures[playername]
|
|
|
|
if armor_textures then
|
|
|
|
armor_texture = concat_texture(armor_texture, armor_textures.armor)
|
|
|
|
wielditem_texture = concat_texture(wielditem_texture, armor_textures.wielditem)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
player_api.set_textures(player, {
|
|
|
|
v10_texture,
|
|
|
|
v18_texture,
|
|
|
|
armor_texture,
|
|
|
|
wielditem_texture,
|
|
|
|
})
|
|
|
|
|
|
|
|
player:set_properties({
|
|
|
|
visual_size = {
|
|
|
|
x = self:get_meta("visual_size_x") or 1,
|
|
|
|
y = self:get_meta("visual_size_y") or 1
|
|
|
|
}
|
|
|
|
})
|
2024-12-19 12:55:40 +01:00
|
|
|
|
|
|
|
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
|
2020-10-25 19:05:08 +01:00
|
|
|
end
|
|
|
|
|
|
|
|
function skin_class:set_skin(player)
|
|
|
|
-- The set_skin is used on skins selection
|
|
|
|
-- This means the method could be redefined to start an furmslec
|
|
|
|
-- See character_creator for example
|
|
|
|
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
|
2024-12-19 12:55:40 +01:00
|
|
|
playername and (minetest.check_player_privs(playername, {server=true}) or
|
|
|
|
assigned_player:lower() == playername:lower())
|
2020-10-25 19:05:08 +01:00
|
|
|
end
|