Add advanced skin customization

This commit is contained in:
Johannes Fritz 2022-08-29 13:09:00 -05:00
parent d81d7febbf
commit 8e6b6393c2
109 changed files with 1550 additions and 567 deletions

@ -362,39 +362,49 @@ function mcl_inventory.set_creative_formspec(player, start_i, pagenum, inv_size,
local stack_size = get_stack_size(player)
-- Survival inventory slots
main_list = "list[current_player;main;0,3.75;9,3;9]"..
mcl_formspec.get_itemslot_bg(0,3.75,9,3)..
-- armor
"list[current_player;armor;2.5,1.3;1,1;1]"..
"list[current_player;armor;2.5,2.75;1,1;2]"..
"list[current_player;armor;5.5,1.3;1,1;3]"..
"list[current_player;armor;5.5,2.75;1,1;4]"..
mcl_formspec.get_itemslot_bg(2.5,1.3,1,1)..
mcl_formspec.get_itemslot_bg(2.5,2.75,1,1)..
mcl_formspec.get_itemslot_bg(5.5,1.3,1,1)..
mcl_formspec.get_itemslot_bg(5.5,2.75,1,1)..
"list[current_player;offhand;1.5,2.025;1,1]"..
mcl_formspec.get_itemslot_bg(1.5,2.025,1,1)..
armor_slot_imgs..
-- player preview
mcl_player.get_player_formspec_model(player, 3.9, 1.4, 1.2333, 2.4666, "")..
-- crafting guide button
"image_button[9,1;1,1;craftguide_book.png;__mcl_craftguide;]"..
"tooltip[__mcl_craftguide;"..F(S("Recipe book")).."]"..
-- help button
"image_button[9,2;1,1;doc_button_icon_lores.png;__mcl_doc;]"..
"tooltip[__mcl_doc;"..F(S("Help")).."]"..
-- skins button
"image_button[9,3;1,1;mcl_skins_button.png;__mcl_skins;]"..
"tooltip[__mcl_skins;"..F(S("Select player skin")).."]"..
-- achievements button
"image_button[9,4;1,1;mcl_achievements_button.png;__mcl_achievements;]"..
--"style_type[image_button;border=;bgimg=;bgimg_pressed=]"..
"tooltip[__mcl_achievements;"..F(S("Achievements")).."]"..
-- switch stack size button
"image_button[9,5;1,1;default_apple.png;__switch_stack;]"..
"label[9.4,5.4;".. F(C("#FFFFFF", stack_size ~= 1 and stack_size or "")) .."]"..
"tooltip[__switch_stack;"..F(S("Switch stack size")).."]"
main_list = "list[current_player;main;0,3.75;9,3;9]" ..
mcl_formspec.get_itemslot_bg(0, 3.75, 9, 3) ..
-- Armor
"list[current_player;armor;2.5,1.3;1,1;1]" ..
"list[current_player;armor;2.5,2.75;1,1;2]" ..
"list[current_player;armor;5.5,1.3;1,1;3]" ..
"list[current_player;armor;5.5,2.75;1,1;4]" ..
mcl_formspec.get_itemslot_bg(2.5, 1.3, 1, 1) ..
mcl_formspec.get_itemslot_bg(2.5, 2.75, 1, 1) ..
mcl_formspec.get_itemslot_bg(5.5, 1.3, 1, 1) ..
mcl_formspec.get_itemslot_bg(5.5, 2.75, 1, 1) ..
"list[current_player;offhand;1.5,2.025;1,1]" ..
mcl_formspec.get_itemslot_bg(1.5, 2.025, 1, 1) ..
armor_slot_imgs ..
-- Player preview
mcl_player.get_player_formspec_model(player, 3.9, 1.4, 1.2333, 2.4666, "") ..
-- Crafting guide button
"image_button[9,1;1,1;craftguide_book.png;__mcl_craftguide;]" ..
"tooltip[__mcl_craftguide;"..F(S("Recipe book")) .. "]" ..
-- Help button
"image_button[9,2;1,1;doc_button_icon_lores.png;__mcl_doc;]" ..
"tooltip[__mcl_doc;" .. F(S("Help")) .. "]" ..
-- Achievements button
"image_button[9,3;1,1;mcl_achievements_button.png;__mcl_achievements;]" ..
--"style_type[image_button;border=;bgimg=;bgimg_pressed=]" ..
"tooltip[__mcl_achievements;"..F(S("Achievements")) .. "]" ..
-- Switch stack size button
"image_button[9,4;1,1;default_apple.png;__switch_stack;]" ..
"label[9.4,4.4;" .. F(C("#FFFFFF", stack_size ~= 1 and stack_size or "")) .. "]" ..
"tooltip[__switch_stack;" .. F(S("Switch stack size")) .. "]"
-- Skins button
if minetest.global_exists("mcl_skins") then
main_list = main_list ..
"image_button[9,5;1,1;mcl_skins_button.png;__mcl_skins;]" ..
"tooltip[__mcl_skins;"..F(S("Select player skin")) .. "]"
end
-- For shortcuts
listrings = listrings ..

@ -72,50 +72,62 @@ local function set_inventory(player, armor_change_only)
armor_slot_imgs = armor_slot_imgs .. "image[3,2;1,1;mcl_inventory_empty_armor_slot_shield.png]"
end
local form = "size[9,8.75]"..
"background[-0.19,-0.25;9.41,9.49;crafting_formspec_bg.png]"..
mcl_player.get_player_formspec_model(player, 1.0, 0.0, 2.25, 4.5, "")..
--armor
"list[current_player;armor;0,0;1,1;1]"..
"list[current_player;armor;0,1;1,1;2]"..
"list[current_player;armor;0,2;1,1;3]"..
"list[current_player;armor;0,3;1,1;4]"..
mcl_formspec.get_itemslot_bg(0,0,1,1)..
mcl_formspec.get_itemslot_bg(0,1,1,1)..
mcl_formspec.get_itemslot_bg(0,2,1,1)..
mcl_formspec.get_itemslot_bg(0,3,1,1)..
"list[current_player;offhand;3,2;1,1]"..
mcl_formspec.get_itemslot_bg(3,2,1,1)..
armor_slot_imgs..
-- craft and inventory
"label[0,4;"..F(minetest.colorize("#313131", S("Inventory"))).."]"..
"list[current_player;main;0,4.5;9,3;9]"..
"list[current_player;main;0,7.74;9,1;]"..
"label[4,0.5;"..F(minetest.colorize("#313131", S("Crafting"))).."]"..
"list[current_player;craft;4,1;2,2]"..
"list[current_player;craftpreview;7,1.5;1,1;]"..
mcl_formspec.get_itemslot_bg(0,4.5,9,3)..
mcl_formspec.get_itemslot_bg(0,7.74,9,1)..
mcl_formspec.get_itemslot_bg(4,1,2,2)..
mcl_formspec.get_itemslot_bg(7,1.5,1,1)..
-- crafting guide button
"image_button[4.5,3;1,1;craftguide_book.png;__mcl_craftguide;]"..
"tooltip[__mcl_craftguide;"..F(S("Recipe book")).."]"..
-- help button
"image_button[8,3;1,1;doc_button_icon_lores.png;__mcl_doc;]"..
"tooltip[__mcl_doc;"..F(S("Help")).."]"..
-- skins button
"image_button[3,3;1,1;mcl_skins_button.png;__mcl_skins;]"..
"tooltip[__mcl_skins;"..F(S("Select player skin")).."]"..
-- achievements button
"image_button[7,3;1,1;mcl_achievements_button.png;__mcl_achievements;]"..
"tooltip[__mcl_achievements;"..F(S("Achievements")).."]"..
-- for shortcuts
"listring[current_player;main]"..
"listring[current_player;armor]"..
"listring[current_player;main]" ..
"listring[current_player;craft]" ..
"listring[current_player;main]"
local form = "size[9,8.75]" ..
"background[-0.19,-0.25;9.41,9.49;crafting_formspec_bg.png]" ..
mcl_player.get_player_formspec_model(player, 1.0, 0.0, 2.25, 4.5, "") ..
-- Armor
"list[current_player;armor;0,0;1,1;1]" ..
"list[current_player;armor;0,1;1,1;2]" ..
"list[current_player;armor;0,2;1,1;3]" ..
"list[current_player;armor;0,3;1,1;4]" ..
mcl_formspec.get_itemslot_bg(0,0,1,1) ..
mcl_formspec.get_itemslot_bg(0,1,1,1) ..
mcl_formspec.get_itemslot_bg(0,2,1,1) ..
mcl_formspec.get_itemslot_bg(0,3,1,1) ..
"list[current_player;offhand;3,2;1,1]" ..
mcl_formspec.get_itemslot_bg(3,2,1,1) ..
armor_slot_imgs ..
-- Craft and inventory
"label[0,4;"..F(minetest.colorize("#313131", S("Inventory"))) .. "]" ..
"list[current_player;main;0,4.5;9,3;9]" ..
"list[current_player;main;0,7.74;9,1;]" ..
"label[4,0.5;"..F(minetest.colorize("#313131", S("Crafting"))) .. "]" ..
"list[current_player;craft;4,1;2,2]" ..
"list[current_player;craftpreview;7,1.5;1,1;]" ..
mcl_formspec.get_itemslot_bg(0, 4.5, 9, 3) ..
mcl_formspec.get_itemslot_bg(0, 7.74, 9, 1) ..
mcl_formspec.get_itemslot_bg(4, 1,2, 2) ..
mcl_formspec.get_itemslot_bg(7, 1.5, 1, 1) ..
-- Crafting guide button
"image_button[4.5,3;1,1;craftguide_book.png;__mcl_craftguide;]" ..
"tooltip[__mcl_craftguide;"..F(S("Recipe book")) .. "]" ..
-- Help button
"image_button[8,3;1,1;doc_button_icon_lores.png;__mcl_doc;]" ..
"tooltip[__mcl_doc;" .. F(S("Help")) .. "]"
-- Skins button
if minetest.global_exists("mcl_skins") then
form = form ..
"image_button[3,3;1,1;mcl_skins_button.png;__mcl_skins;]" ..
"tooltip[__mcl_skins;" .. F(S("Select player skin")) .. "]"
end
form = form ..
-- Achievements button
"image_button[7,3;1,1;mcl_achievements_button.png;__mcl_achievements;]" ..
"tooltip[__mcl_achievements;" .. F(S("Achievements")) .. "]" ..
-- For shortcuts
"listring[current_player;main]" ..
"listring[current_player;armor]" ..
"listring[current_player;main]" ..
"listring[current_player;craft]" ..
"listring[current_player;main]"
player:set_inventory_formspec(form)
end

@ -229,17 +229,40 @@ filled_wield_def.range = minetest.registered_items[""].range
filled_wield_def.on_place = mcl_util.call_on_rightclick
filled_wield_def._mcl_wieldview_item = "mcl_maps:filled_map"
for _, texture in pairs(mcl_skins.list) do
local def = table.copy(filled_wield_def)
def.tiles = {texture .. ".png"}
def.mesh = "mcl_meshhand.b3d"
def._mcl_hand_id = texture
minetest.register_node("mcl_maps:filled_map_" .. texture, def)
local mcl_skins_enabled = minetest.global_exists("mcl_skins")
local female_def = table.copy(def)
female_def.mesh = "mcl_meshhand_female.b3d"
female_def._mcl_hand_id = texture .. "_female"
minetest.register_node("mcl_maps:filled_map_" .. texture .. "_female", female_def)
local function player_base_to_node_id(base, colorspec, sex)
return base:gsub("%.", "") .. minetest.colorspec_to_colorstring(colorspec):gsub("#", "") .. sex
end
if mcl_skins_enabled then
local bases = mcl_skins.base
local base_colors = mcl_skins.base_color
-- Generate a node for every skin
for _, base in pairs(bases) do
for _, base_color in pairs(base_colors) do
local node_id = player_base_to_node_id(base, base_color, "male")
local texture = mcl_skins.make_hand_texture(base, base_color)
local male = table.copy(filled_wield_def)
male._mcl_hand_id = node_id
male.mesh = "mcl_meshhand.b3d"
male.tiles = {texture}
minetest.register_node("mcl_maps:filled_map_" .. node_id, male)
node_id = player_base_to_node_id(base, base_color, "female")
local female = table.copy(filled_wield_def)
female._mcl_hand_id = node_id
female.mesh = "mcl_meshhand_female.b3d"
female.tiles = {texture}
minetest.register_node("mcl_maps:filled_map_" .. node_id, female)
end
end
else
filled_wield_def._mcl_hand_id = "hand"
filled_wield_def.mesh = "mcl_meshhand.b3d"
filled_wield_def.tiles = {"character.png"}
minetest.register_node("mcl_maps:filled_map_hand", filled_wield_def)
end
local old_add_item = minetest.add_item

@ -1,76 +1,66 @@
local has_mcl_skins = minetest.get_modpath("mcl_skins") ~= nil
local mcl_skins_enabled = minetest.global_exists("mcl_skins")
local def = minetest.registered_items[""]
-- This is a fake node that should never be placed in the world
local node_def = {
description = "",
use_texture_alpha = minetest.features.use_texture_alpha_string_modes and "opaque" or false,
visual_scale = 1,
wield_scale = {x=1,y=1,z=1},
paramtype = "light",
drawtype = "mesh",
node_placement_prediction = "",
on_construct = function(pos)
local name = get_node(pos).name
local message = "[mcl_meshhand] Trying to construct " .. name .. " at " .. minetest.pos_to_string(pos)
minetest.log("error", message)
minetest.remove_node(pos)
end,
drop = "",
on_drop = function() return "" end,
groups = { dig_immediate = 3, not_in_creative_inventory = 1 },
range = minetest.registered_items[""].range
}
local list
-- mcl_skins is enabled
if has_mcl_skins == true then
list = mcl_skins.list
else
list = { "hand" }
local function player_base_to_node_id(base, colorspec, sex)
return base:gsub("%.", "") .. minetest.colorspec_to_colorstring(colorspec):gsub("#", "") .. sex
end
--generate a node for every skin
for _,texture in pairs(list) do
-- This is a fake node that should never be placed in the world
minetest.register_node("mcl_meshhand:"..texture, {
description = "",
tiles = {texture..".png"},
use_texture_alpha = minetest.features.use_texture_alpha_string_modes and "opaque" or false,
visual_scale = 1,
wield_scale = {x=1,y=1,z=1},
paramtype = "light",
drawtype = "mesh",
mesh = "mcl_meshhand.b3d",
-- Prevent construction
node_placement_prediction = "",
on_construct = function(pos)
minetest.log("error", "[mcl_meshhand] Trying to construct mcl_meshhand:"..texture.." at "..minetest.pos_to_string(pos))
minetest.remove_node(pos)
end,
drop = "",
on_drop = function()
return ""
end,
groups = { dig_immediate = 3, not_in_creative_inventory = 1 },
range = def.range,
_mcl_hand_id = texture,
})
if mcl_skins_enabled then
local bases = mcl_skins.base
local base_colors = mcl_skins.base_color
minetest.register_node("mcl_meshhand:"..texture.. "_female", {
description = "",
tiles = {texture..".png"},
use_texture_alpha = minetest.features.use_texture_alpha_string_modes and "opaque" or false,
visual_scale = 1,
wield_scale = {x=1,y=1,z=1},
paramtype = "light",
drawtype = "mesh",
mesh = "mcl_meshhand_female.b3d",
-- Prevent construction
node_placement_prediction = "",
on_construct = function(pos)
minetest.log("error", "[mcl_meshhand] Trying to construct mcl_meshhand:"..texture.." at "..minetest.pos_to_string(pos))
minetest.remove_node(pos)
end,
drop = "",
on_drop = function()
return ""
end,
groups = { dig_immediate = 3, not_in_creative_inventory = 1 },
range = def.range,
_mcl_hand_id = texture .. "_female",
})
end
-- Generate a node for every skin
for _, base in pairs(bases) do
for _, base_color in pairs(base_colors) do
local node_id = player_base_to_node_id(base, base_color, "male")
local texture = mcl_skins.make_hand_texture(base, base_color)
local male = table.copy(node_def)
male._mcl_hand_id = node_id
male.mesh = "mcl_meshhand.b3d"
male.tiles = {texture}
minetest.register_node("mcl_meshhand:" .. node_id, male)
if has_mcl_skins == true then
--change the player's hand to their skin
mcl_skins.register_on_set_skin(function(player, skin)
local meta = mcl_skins.meta[skin]
if meta.gender == "female" then
player:get_inventory():set_stack("hand", 1, "mcl_meshhand:"..skin.."_female")
else
player:get_inventory():set_stack("hand", 1, "mcl_meshhand:"..skin)
node_id = player_base_to_node_id(base, base_color, "female")
local female = table.copy(node_def)
female._mcl_hand_id = node_id
female.mesh = "mcl_meshhand_female.b3d"
female.tiles = {texture}
minetest.register_node("mcl_meshhand:" .. node_id, female)
end
end
else
node_def._mcl_hand_id = "hand"
node_def.mesh = "mcl_meshhand.b3d"
node_def.tiles = {"character.png"}
minetest.register_node("mcl_meshhand:hand", node_def)
end
if mcl_skins_enabled then
-- Change the player's hand to their skin
mcl_skins.register_on_set_skin(function(player)
local data = mcl_skins.players[player:get_player_name()]
local node_id = player_base_to_node_id(data.base, data.base_color, data.slim_arms and "female" or "male")
player:get_inventory():set_stack("hand", 1, "mcl_meshhand:" .. node_id)
end)
else
minetest.register_on_joinplayer(function(player)

@ -129,7 +129,7 @@ minetest.register_on_joinplayer(function(player)
local name = player:get_player_name()
mcl_player.player_attached[name] = false
mcl_player.player_set_model(player, "character.b3d")
player_textures[name] = {"blank.png", "blank.png", "blank.png"}
player_textures[name] = {"character.png", "blank.png", "blank.png"}
--player:set_local_animation({x=0, y=79}, {x=168, y=187}, {x=189, y=198}, {x=200, y=219}, 30)
player:set_fov(86.1) -- see <https://minecraft.gamepedia.com/Options#Video_settings>>>>
end)

@ -1,4 +0,0 @@
!textures/mcl_skins_character_1.png
textures/mcl_skins_character_*
!meta/mcl_skins_character_1.txt
meta/mcl_skins_character_*

@ -1,6 +1,6 @@
The MIT License (MIT)
Copyright (c) 2016 TenPlus1
Copyright (c) 2022 MrRar
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

@ -1,13 +1,75 @@
= Skins for MineClone 2 =
# mcl_skins
Simple mod to allow players to select a skin.
Use the chat command /setskin to change skin.
This mod allows advanced skin customization.
Use the /skin command to open the skin configuration screen.
Forked from Simple Skins by TenPlus1.
https://forum.minetest.net/viewtopic.php?id=9100
== License ==
## License
Code under MIT license
Origial authors:
- TenPlus1
- Zeg9
Author: MrRar
See image_credits.txt for image licensing.
## API
### `mcl_skins.register_item(item)`
Register a skin item. `item` is a table with item properties listed below.
### Item properties
`type`
Set the item type. Valid values are: "base", "footwear", "eye", "mouth", "bottom", "top", "hair", "headwear"
`texture`
Set to the image file that will be used. If this property is omitted "blank.png" is used.
`mask`
Set the color mask texture. Coloring is only applied to non transparent areas of the texture.
Coloring only works for "base", "bottom, "top", and "hair".
`preview_rotation`
A table containing properties x and y. x and y represent the x and y rotation of the item preview.
`alex`
If set to true the item will be default for female character.
`steve`
If set to true the item will be default for male character.
### `mcl_skins.show_formspec(player, active_tab, page_num)`
Show the skin configuration screen.
`player` is a player ObjectRef.
`active_tab` is the tab that will be displayed. This parameter is optional.
Can be one of: "arm", "base", "footwear", "eye", "mouth", "bottom", "top", "hair", "headwear"
`page_num` The page number to display of there are multiple pages of items.
This parameter is optional. Must be a number. If it is not a valid page number the closest page number will be shown.
### `mcl_skins.register_on_set_skin(func)`
Register a function to be called whenever a player skin changes.
The function will be given a player ObjectRef as a parameter.
### `mcl_skins.make_hand_texture(base, colorspec)`
Generate a texture string from a base texture and color.
This function is used by mods that want to have a first person hand textured like the player skin.
### `mcl_skins.save(player)`
Save player skin. `player` is a player ObjectRef.
### `mcl_skins.update_player_skin(player)`
Update a player based on skin data in mcl_skins.players.
`player` is a player ObjectRef.
### `mcl_skins.base_color`
A table of ColorSpec integers that the player can select to color the base item.
These colors are separate from `mcl_skins.color` because some mods register two nodes per base color so the amount of base colors needs to be limited.
### `mcl_skins.color`
A table of ColorSpec integers that the player can select to color colorable skin items.
### `mcl_skins.players`
A table mapped by player name containing tables holding the player's selected skin items and colors.
Only stores skin information for logged in users.
### mcl_skins.compile_skin(skin)
`skin` is a table with skin item properties.
Returns an image string.

@ -0,0 +1,523 @@
local S = minetest.get_translator("mcl_skins")
local color_to_string = minetest.colorspec_to_colorstring
mcl_skins = {
item_names = {"base", "footwear", "eye", "mouth", "bottom", "top", "hair", "headwear"},
tab_names = {"template", "base", "headwear", "hair", "eye", "mouth", "top", "arm", "bottom", "footwear"},
tab_descriptions = {
template = S("Templates"),
arm = S("Arm size"),
base = S("Bases"),
footwear = S("Footwears"),
eye = S("Eyes"),
mouth = S("Mouths"),
bottom = S("Bottoms"),
top = S("Tops"),
hair = S("Hairs"),
headwear = S("Headwears")
},
steve = {}, -- Stores skin values for Steve skin
alex = {}, -- Stores skin values for Alex skin
base = {}, -- List of base textures
-- Base color is separate to keep the number of junk nodes registered in check
base_color = {0xffeeb592, 0xffb47a57, 0xff8d471d},
color = {
0xff613915, -- 1 Dark brown Steve hair, Alex bottom
0xff97491b, -- 2 Medium brown
0xffb17050, -- 3 Light brown
0xffe2bc7b, -- 4 Beige
0xff706662, -- 5 Gray
0xff151515, -- 6 Black
0xffc21c1c, -- 7 Red
0xff178c32, -- 8 Green Alex top
0xffae2ad3, -- 9 Plum
0xffebe8e4, -- 10 White
0xffe3dd26, -- 11 Yellow
0xff449acc, -- 12 Light blue Steve top
0xff124d87, -- 13 Dark blue Steve bottom
0xfffc0eb3, -- 14 Pink
0xffd0672a, -- 15 Orange Alex hair
},
footwear = {},
mouth = {},
eye = {},
bottom = {},
top = {},
hair = {},
headwear = {},
masks = {},
preview_rotations = {},
players = {}
}
function mcl_skins.register_item(item)
assert(mcl_skins[item.type], "Skin item type " .. item.type .. " does not exist.")
local texture = item.texture or "blank.png"
if item.steve then
mcl_skins.steve[item.type] = texture
end
if item.alex then
mcl_skins.alex[item.type] = texture
end
table.insert(mcl_skins[item.type], texture)
mcl_skins.masks[texture] = item.mask
if item.preview_rotation then
mcl_skins.preview_rotations[texture] = item.preview_rotation
end
end
function mcl_skins.save(player)
local name = player:get_player_name()
local skin = mcl_skins.players[name]
if not skin then return end
player:get_meta():set_string("mcl_skins:skin", minetest.serialize(skin))
end
minetest.register_chatcommand("skin", {
description = S("Open skin configuration screen."),
privs = {},
func = function(name, param) mcl_skins.show_formspec(minetest.get_player_by_name(name)) end
})
function mcl_skins.make_hand_texture(base, colorspec)
local output = ""
if mcl_skins.masks[base] then
output = mcl_skins.masks[base] ..
"^[colorize:" .. color_to_string(colorspec) .. ":alpha"
end
if #output > 0 then output = output .. "^" end
output = output .. base
return output
end
function mcl_skins.compile_skin(skin)
local output = ""
for i, tab in pairs(mcl_skins.item_names) do
local texture = skin[tab]
if texture and texture ~= "blank.png" then
if skin[tab .. "_color"] and mcl_skins.masks[texture] then
if #output > 0 then output = output .. "^" end
local color = color_to_string(skin[tab .. "_color"])
output = output ..
"(" .. mcl_skins.masks[texture] .. "^[colorize:" .. color .. ":alpha)"
end
if #output > 0 then output = output .. "^" end
output = output .. texture
end
end
return output
end
function mcl_skins.update_player_skin(player)
if not player then
return
end
local skin = mcl_skins.players[player:get_player_name()]
mcl_player.player_set_skin(player, mcl_skins.compile_skin(skin))
local model = skin.slim_arms and "mcl_armor_character_female.b3d" or "mcl_armor_character.b3d"
mcl_player.player_set_model(player, model)
mcl_inventory.update_inventory_formspec(player)
for i=1, #mcl_skins.registered_on_set_skins do
mcl_skins.registered_on_set_skins[i](player)
end
end
-- Load player skin on join
minetest.register_on_joinplayer(function(player)
local function table_get_random(t)
return t[math.random(#t)]
end
local name = player:get_player_name()
local skin = player:get_meta():get_string("mcl_skins:skin")
if skin then
skin = minetest.deserialize(skin)
end
if skin then
mcl_skins.players[name] = skin
else
if math.random() > 0.5 then
skin = table.copy(mcl_skins.steve)
else
skin = table.copy(mcl_skins.alex)
end
mcl_skins.players[name] = skin
end
mcl_skins.save(player)
mcl_skins.update_player_skin(player)
end)
minetest.register_on_leaveplayer(function(player)
local name = player:get_player_name()
if name then
mcl_skins.players[name] = nil
end
end)
mcl_skins.registered_on_set_skins = {}
function mcl_skins.register_on_set_skin(func)
table.insert(mcl_skins.registered_on_set_skins, func)
end
function mcl_skins.show_formspec(player, active_tab, page_num)
active_tab = active_tab or "template"
page_num = page_num or 1
local page_count
if page_num < 1 then page_num = 1 end
if mcl_skins[active_tab] then
page_count = math.ceil(#mcl_skins[active_tab] / 16)
if page_num > page_count then
page_num = page_count
end
else
page_num = 1
page_count = 1
end
local player_name = player:get_player_name()
local skin = mcl_skins.players[player_name]
local formspec = "formspec_version[3]size[13.2,11]"
for i, tab in pairs(mcl_skins.tab_names) do
if tab == active_tab then
formspec = formspec ..
"style[" .. tab .. ";bgcolor=green]"
end
local y = 0.3 + (i - 1) * 0.8
formspec = formspec ..
"button[0.3," .. y .. ";3,0.8;" .. tab .. ";" .. mcl_skins.tab_descriptions[tab] .. "]"
end
local mesh = skin.slim_arms and "mcl_armor_character_female.b3d" or "mcl_armor_character.b3d"
formspec = formspec ..
"model[10,0.3;3,7;player_mesh;" .. mesh .. ";" ..
mcl_skins.compile_skin(skin) ..
",blank.png,blank.png;0,180;false;true;0,0;0]"
if active_tab == "template" then
formspec = formspec ..
"model[4,2;2,3;player_mesh;mcl_armor_character.b3d;" ..
mcl_skins.compile_skin(mcl_skins.steve) ..
",blank.png,blank.png;0,180;false;true;0,0;0]" ..
"button[4,5.2;2,0.8;steve;" .. S("Select") .. "]" ..
"model[6.5,2;2,3;player_mesh;mcl_armor_character_female.b3d;" ..
mcl_skins.compile_skin(mcl_skins.alex) ..
",blank.png,blank.png;0,180;false;true;0,0;0]" ..
"button[6.5,5.2;2,0.8;alex;" .. S("Select") .. "]"
elseif mcl_skins[active_tab] then
formspec = formspec ..
"style_type[button;border=false;bgcolor=#00000000]"
local textures = mcl_skins[active_tab]
local page_start = (page_num - 1) * 16 + 1
local page_end = math.min(page_start + 16 - 1, #textures)
for j = page_start, page_end do
local i = j - page_start + 1
local texture = textures[j]
local preview = mcl_skins.masks[skin.base] .. "^[colorize:gray^" .. skin.base
local color = color_to_string(skin[active_tab .. "_color"])
local mask = mcl_skins.masks[texture]
if color and mask then
preview = preview .. "^(" .. mask .. "^[colorize:" .. color .. ":alpha)"
end
preview = preview .. "^" .. texture
local mesh = "mcl_skins_head.obj"
if active_tab == "top" then
mesh = "mcl_skins_top.obj"
elseif active_tab == "bottom" or active_tab == "footwear" then
mesh = "mcl_skins_bottom.obj"
end
local rot_x = -10
local rot_y = 20
if mcl_skins.preview_rotations[texture] then
rot_x = mcl_skins.preview_rotations[texture].x
rot_y = mcl_skins.preview_rotations[texture].y
end
i = i - 1
local x = 3.5 + i % 4 * 1.6
local y = 0.3 + math.floor(i / 4) * 1.6
formspec = formspec ..
"model[" .. x .. "," .. y ..
";1.5,1.5;" .. mesh .. ";" .. mesh .. ";" ..
preview ..
";" .. rot_x .. "," .. rot_y .. ";false;false;0,0;0]"
if skin[active_tab] == texture then
formspec = formspec ..
"style[" .. texture .. ";border=false;bgcolor=#00000000]" ..
"image_button[" .. x .. "," .. y ..
";1.5,1.5;mcl_skins_select_overlay.png;" .. texture .. ";]"
else
formspec = formspec .. "button[" .. x .. "," .. y .. ";1.5,1.5;" .. texture .. ";]"
end
end
elseif active_tab == "arm" then
local thick_overlay = not skin.slim_arms and "^mcl_skins_select_overlay.png" or ""
local slim_overlay = skin.slim_arms and "^mcl_skins_select_overlay.png" or ""
formspec = formspec ..
"image_button[3.6,0.3;1,1;mcl_skins_thick_arms.png" .. thick_overlay ..";thick_arms;]" ..
"image_button[4.7,0.3;1,1;mcl_skins_slim_arms.png" .. slim_overlay ..";slim_arms;]"
end
if skin[active_tab .. "_color"] then
local colors = mcl_skins.color
if active_tab == "base" then colors = mcl_skins.base_color end
local tab_color = active_tab .. "_color"
local selected_color = skin[tab_color]
for i, colorspec in pairs(colors) do
local overlay = ""
if selected_color == colorspec then
overlay = "^mcl_skins_select_overlay.png"
end
local color = color_to_string(colorspec)
i = i - 1
local x = 3.6 + i % 6 * 0.9
local y = 8 + math.floor(i / 6) * 0.9
formspec = formspec ..
"image_button[" .. x .. "," .. y ..
";0.8,0.8;blank.png^[noalpha^[colorize:" ..
color .. ":alpha" .. overlay .. ";" .. colorspec .. ";]"
end
if not (active_tab == "base") then
-- Bitwise Operations !?!?!
local red = math.floor(selected_color / 0x10000) - 0xff00
local green = math.floor(selected_color / 0x100) - 0xff0000 - red * 0x100
local blue = selected_color - 0xff000000 - red * 0x10000 - green * 0x100
formspec = formspec ..
"container[9.2,8]" ..
"scrollbaroptions[min=0;max=255;smallstep=20]" ..
"box[0.4,0;2.49,0.38;red]" ..
"label[0.2,0.2;-]" ..
"scrollbar[0.4,0;2.5,0.4;horizontal;red;" .. red .."]" ..
"label[2.9,0.2;+]" ..
"box[0.4,0.6;2.49,0.38;green]" ..
"label[0.2,0.8;-]" ..
"scrollbar[0.4,0.6;2.5,0.4;horizontal;green;" .. green .."]" ..
"label[2.9,0.8;+]" ..
"box[0.4,1.2;2.49,0.38;blue]" ..
"label[0.2,1.4;-]" ..
"scrollbar[0.4,1.2;2.5,0.4;horizontal;blue;" .. blue .. "]" ..
"label[2.9,1.4;+]" ..
"container_end[]"
end
end
if page_num > 1 then
formspec = formspec ..
"image_button[3.5,6.7;1,1;mcl_skins_arrow.png^[transformFX;previous_page;]"
end
if page_num < page_count then
formspec = formspec ..
"image_button[8.8,6.7;1,1;mcl_skins_arrow.png;next_page;]"
end
if page_count > 1 then
formspec = formspec ..
"label[6.3,7.2;" .. page_num .. " / " .. page_count .. "]"
end
minetest.show_formspec(player_name, "mcl_skins:" .. active_tab .. "_" .. page_num, formspec)
end
minetest.register_on_player_receive_fields(function(player, formname, fields)
if fields.__mcl_skins then
mcl_skins.show_formspec(player)
return false
end
if not formname:find("^mcl_skins:") then return false end
local _, _, active_tab, page_num = formname:find("^mcl_skins:(%a+)_(%d+)")
local active_tab_found = false
for _, tab in pairs(mcl_skins.tab_names) do
if tab == active_tab then active_tab_found = true end
end
active_tab = active_tab_found and active_tab or "template"
if not page_num or not active_tab then return true end
page_num = math.floor(tonumber(page_num) or 1)
local player_name = player:get_player_name()
-- Cancel formspec resend after scrollbar move
if mcl_skins.players[player_name].form_send_job then
mcl_skins.players[player_name].form_send_job:cancel()
end
if fields.quit then
mcl_skins.save(player)
return true
end
if fields.alex then
mcl_skins.players[player_name] = table.copy(mcl_skins.alex)
mcl_skins.update_player_skin(player)
mcl_skins.show_formspec(player, active_tab, page_num)
return true
elseif fields.steve then
mcl_skins.players[player_name] = table.copy(mcl_skins.steve)
mcl_skins.update_player_skin(player)
mcl_skins.show_formspec(player, active_tab, page_num)
return true
end
for i, tab in pairs(mcl_skins.tab_names) do
if fields[tab] then
mcl_skins.show_formspec(player, tab, page_num)
return true
end
end
local skin = mcl_skins.players[player_name]
if not skin then return true end
if fields.next_page then
page_num = page_num + 1
mcl_skins.show_formspec(player, active_tab, page_num)
return true
elseif fields.previous_page then
page_num = page_num - 1
mcl_skins.show_formspec(player, active_tab, page_num)
return true
end
if active_tab == "arm" then
if fields.thick_arms then
skin.slim_arms = false
elseif fields.slim_arms then
skin.slim_arms = true
end
mcl_skins.update_player_skin(player)
mcl_skins.show_formspec(player, active_tab, page_num)
return true
end
if
skin[active_tab .. "_color"] and (
fields.red and fields.red:find("^CHG") or
fields.green and fields.green:find("^CHG") or
fields.blue and fields.blue:find("^CHG")
)
then
local red = fields.red:gsub("%a%a%a:", "")
local green = fields.green:gsub("%a%a%a:", "")
local blue = fields.blue:gsub("%a%a%a:", "")
red = tonumber(red) or 0
green = tonumber(green) or 0
blue = tonumber(blue) or 0
local color = 0xff000000 + red * 0x10000 + green * 0x100 + blue
if color >= 0 and color <= 0xffffffff then
-- We delay resedning the form because otherwise it will break dragging scrollbars
mcl_skins.players[player_name].form_send_job = minetest.after(0.2, function()
if player and player:is_player() then
skin[active_tab .. "_color"] = color
mcl_skins.update_player_skin(player)
mcl_skins.show_formspec(player, active_tab, page_num)
mcl_skins.players[player_name].form_send_job = nil
end
end)
return true
end
end
local field
for f, value in pairs(fields) do
if value == "" then
field = f
break
end
end
-- See if field is a texture
if field and mcl_skins[active_tab] then
for i, texture in pairs(mcl_skins[active_tab]) do
if texture == field then
skin[active_tab] = texture
mcl_skins.update_player_skin(player)
mcl_skins.show_formspec(player, active_tab, page_num)
return true
end
end
end
-- See if field is a color
local number = tonumber(field)
if number and skin[active_tab .. "_color"] then
local color = math.floor(number)
if color and color >= 0 and color <= 0xffffffff then
skin[active_tab .. "_color"] = color
mcl_skins.update_player_skin(player)
mcl_skins.show_formspec(player, active_tab, page_num)
return true
end
end
return true
end)
local function init()
local function file_exists(name)
local f = io.open(name)
if not f then
return false
end
f:close()
return true
end
local f = io.open(minetest.get_modpath("mcl_skins") .. "/list.json")
assert(f, "Can't open the file list.json")
local data = f:read("*all")
assert(data, "Can't read data from list.json")
local json, error = minetest.parse_json(data)
assert(json, error)
f:close()
for _, item in pairs(json) do
mcl_skins.register_item(item)
end
mcl_skins.steve.base_color = mcl_skins.base_color[1]
mcl_skins.steve.hair_color = mcl_skins.color[1]
mcl_skins.steve.top_color = mcl_skins.color[12]
mcl_skins.steve.bottom_color = mcl_skins.color[13]
mcl_skins.steve.slim_arms = false
mcl_skins.alex.base_color = mcl_skins.base_color[1]
mcl_skins.alex.hair_color = mcl_skins.color[15]
mcl_skins.alex.top_color = mcl_skins.color[8]
mcl_skins.alex.bottom_color = mcl_skins.color[1]
mcl_skins.alex.slim_arms = true
end
init()

@ -1,280 +1,4 @@
-- Skins for MineClone 2
local mod_path = minetest.get_modpath(minetest.get_current_modname())
local modname = minetest.get_current_modname()
mcl_skins = {
skins = {}, list = {}, meta = {},
modpath = minetest.get_modpath(modname),
skin_count = 0, -- counter of _custom_ skins (all skins except character.png)
}
local S = minetest.get_translator(modname)
local has_mcl_inventory = minetest.get_modpath("mcl_inventory")
-- load skin list and metadata
local id, f, data, skin = 0
while true do
if id == 0 then
skin = "character"
else
skin = "mcl_skins_character_" .. id
-- Does skin file exist?
f = io.open(mcl_skins.modpath .. "/textures/" .. skin .. ".png")
-- escape loop if not found
if not f then
break
end
f:close()
end
mcl_skins.list[id] = skin
local metafile
-- does metadata exist for that skin file ?
if id == 0 then
metafile = "mcl_skins_character.txt"
else
metafile = "mcl_skins_character_"..id..".txt"
end
f = io.open(mcl_skins.modpath .. "/meta/" .. metafile)
data = nil
if f then
data = minetest.deserialize("return {" .. f:read("*all") .. "}")
f:close()
end
-- add metadata to list
mcl_skins.meta[skin] = {
name = data and data.name or "",
author = data and data.author or "",
gender = data and data.gender or "",
}
if id > 0 then
mcl_skins.skin_count = mcl_skins.skin_count + 1
end
id = id + 1
end
function mcl_skins.cycle_skin(player)
local skin_id = tonumber(player:get_meta():get_string("mcl_skins:skin_id"))
if not skin_id then
skin_id = 0
end
skin_id = skin_id + 1
if skin_id > mcl_skins.skin_count then
skin_id = 0
end
mcl_skins.set_player_skin(player, skin_id)
end
function mcl_skins.set_player_skin(player, skin_id)
if not player then
return false
end
local playername = player:get_player_name()
local skin
if skin_id == nil or type(skin_id) ~= "number" or skin_id < 0 or skin_id > mcl_skins.skin_count then
return false
elseif skin_id == 0 then
skin = "character"
mcl_player.player_set_model(player, "mcl_armor_character.b3d")
else
skin = "mcl_skins_character_" .. tostring(skin_id)
local meta = mcl_skins.meta[skin]
if meta.gender == "female" then
mcl_player.player_set_model(player, "mcl_armor_character_female.b3d")
else
mcl_player.player_set_model(player, "mcl_armor_character.b3d")
end
end
--local skin_file = skin .. ".png"
mcl_skins.skins[playername] = skin
player:get_meta():set_string("mcl_skins:skin_id", tostring(skin_id))
mcl_skins.update_player_skin(player)
if has_mcl_inventory then
mcl_inventory.update_inventory_formspec(player)
end
for i=1, #mcl_skins.registered_on_set_skins do
mcl_skins.registered_on_set_skins[i](player, skin)
end
minetest.log("action", "[mcl_skins] Player skin for "..playername.." set to skin #"..skin_id)
return true
end
function mcl_skins.update_player_skin(player)
if not player then
return
end
local playername = player:get_player_name()
mcl_player.player_set_skin(player, mcl_skins.skins[playername] .. ".png")
end
-- load player skin on join
minetest.register_on_joinplayer(function(player)
local name = player:get_player_name()
local skin_id = player:get_meta():get_string("mcl_skins:skin_id")
local set_skin
-- do we already have a skin in player attributes?
if skin_id and skin_id ~= "" then
set_skin = tonumber(skin_id)
-- otherwise use random skin if not set
end
if not set_skin then
set_skin = math.random(0, mcl_skins.skin_count)
end
local ok = mcl_skins.set_player_skin(player, set_skin)
if not ok then
set_skin = math.random(0, mcl_skins.skin_count)
minetest.log("warning", "[mcl_skins] Player skin for "..name.." not found, falling back to skin #"..set_skin)
mcl_skins.set_player_skin(player, set_skin)
end
end)
mcl_skins.registered_on_set_skins = {}
function mcl_skins.register_on_set_skin(func)
table.insert(mcl_skins.registered_on_set_skins, func)
end
-- command to set player skin (usually for custom skins)
minetest.register_chatcommand("setskin", {
params = S("[<player>] [<skin number>]"),
description = S("Select player skin of yourself or another player"),
privs = {},
func = function(name, param)
if param == "" and name ~= "" then
mcl_skins.show_formspec(name)
return true
end
local playername, skin_id = string.match(param, "([^ ]+) (%d+)")
if not playername or not skin_id then
skin_id = string.match(param, "(%d+)")
if not skin_id then
return false, S("Insufficient or wrong parameters")
end
playername = name
end
skin_id = tonumber(skin_id)
local player = minetest.get_player_by_name(playername)
if not player then
return false, S("Player @1 not online!", playername)
end
if name ~= playername then
local privs = minetest.get_player_privs(name)
if not privs.server then
return false, S("You need the “server” privilege to change the skin of other players!")
end
end
local ok = mcl_skins.set_player_skin(player, skin_id)
if not ok then
return false, S("Invalid skin number! Valid numbers: 0 to @1", mcl_skins.skin_count)
end
local skinfile = "#"..skin_id
local meta = mcl_skins.meta[mcl_skins.skins[playername]]
local your_msg
if not meta.name or meta.name == "" then
your_msg = S("Your skin has been set to: @1", skinfile)
else
your_msg = S("Your skin has been set to: @1 (@2)", meta.name, skinfile)
end
if name == playername then
return true, your_msg
else
minetest.chat_send_player(playername, your_msg)
return true, S("Skin of @1 set to: @2 (@3)", playername, meta.name, skinfile)
end
end,
})
minetest.register_on_player_receive_fields(function(player, formname, fields)
if fields.__mcl_skins then
if mcl_skins.skin_count <= 6 then
-- Change skin immediately if there are not many skins
mcl_skins.cycle_skin(player)
if player:get_attach() then
mcl_player.player_set_animation(player, "sit")
end
else
-- Show skin selection formspec otherwise
mcl_skins.show_formspec(player:get_player_name())
end
end
end)
function mcl_skins.show_formspec(playername)
local formspec = "size[7,8.5]"
formspec = formspec .. "label[2,2;" .. minetest.formspec_escape(minetest.colorize("#383838", S("Select player skin:"))) .. "]"
.. "textlist[0,2.5;6.8,6;skins_set;"
local meta
local selected = 1
for i = 0, mcl_skins.skin_count do
local label = S("@1 (@2)", mcl_skins.meta[mcl_skins.list[i]].name, "#"..i)
formspec = formspec .. minetest.formspec_escape(label)
if mcl_skins.skins[playername] == mcl_skins.list[i] then
selected = i + 1
meta = mcl_skins.meta[mcl_skins.list[i]]
end
if i < #mcl_skins.list then
formspec = formspec ..","
end
end
formspec = formspec .. ";" .. selected .. ";false]"
local player = minetest.get_player_by_name(playername)
if player then
--maybe the function could accept both player object and player name?
formspec = formspec .. mcl_player.get_player_formspec_model(player, 0, 0, 1.35, 2.7, "mcl_skins:skin_select")
end
if meta then
if meta.name and meta.name ~= "" then
formspec = formspec .. "label[2,0.5;" .. minetest.formspec_escape(minetest.colorize("#383838", S("Name: @1", meta.name))) .. "]"
end
end
minetest.show_formspec(playername, "mcl_skins:skin_select", formspec)
end
minetest.register_on_player_receive_fields(function(player, formname, fields)
if formname == "mcl_skins:skin_select" then
local name = player:get_player_name()
local event = minetest.explode_textlist_event(fields["skins_set"])
if event.type == "CHG" or event.type == "DCL" then
local skin_id = math.min(event.index - 1, mcl_skins.skin_count)
if not mcl_skins.list[skin_id] then
return -- Do not update wrong skin number
end
mcl_skins.set_player_skin(player, skin_id)
mcl_skins.show_formspec(name)
end
end
end)
minetest.log("action", "[mcl_skins] Mod initialized with "..mcl_skins.skin_count.." custom skin(s)")
local mcl_skins_enabled = minetest.settings:get_bool("mcl_enable_skin_customization", true)
if mcl_skins_enabled then dofile(mod_path .. "/edit_skin.lua") end

@ -0,0 +1,259 @@
[
{
"type": "footwear",
"texture": "mcl_skins_footwear_1.png",
"steve": true,
"alex": true
},
{
"type": "footwear",
"texture": "mcl_skins_footwear_2.png"
},
{
"type": "footwear",
"texture": "mcl_skins_footwear_3.png"
},
{
"type": "footwear"
},
{
"type": "eye",
"texture": "mcl_skins_eye_1.png"
},
{
"type": "eye",
"texture": "mcl_skins_eye_2.png"
},
{
"type": "eye",
"texture": "mcl_skins_eye_3.png"
},
{
"type": "eye",
"texture": "mcl_skins_eye_4.png"
},
{
"type": "eye",
"texture": "mcl_skins_eye_5.png",
"steve": true,
"alex": true
},
{
"type": "eye",
"texture": "mcl_skins_eye_6.png"
},
{
"type": "eye",
"texture": "mcl_skins_eye_7.png"
},
{
"type": "mouth",
"texture": "mcl_skins_mouth_1.png",
"steve": true
},
{
"type": "mouth",
"texture": "mcl_skins_mouth_2.png"
},
{
"type": "mouth",
"texture": "mcl_skins_mouth_3.png"
},
{
"type": "mouth",
"texture": "mcl_skins_mouth_4.png"
},
{
"type": "mouth",
"texture": "mcl_skins_mouth_5.png"
},
{
"type": "mouth",
"texture": "mcl_skins_mouth_6.png"
},
{
"type": "mouth",
"texture": "mcl_skins_mouth_7.png",
"alex": true
},
{
"type": "mouth"
},
{
"type": "hair",
"texture": "mcl_skins_hair_1.png",
"mask": "mcl_skins_hair_1_mask.png"
},
{
"type": "hair",
"texture": "mcl_skins_hair_2.png",
"mask": "mcl_skins_hair_2_mask.png"
},
{
"type": "hair",
"texture": "mcl_skins_hair_3.png",
"mask": "mcl_skins_hair_3_mask.png"
},
{
"type": "hair",
"texture": "mcl_skins_hair_4.png",
"mask": "mcl_skins_hair_4_mask.png"
},
{
"type": "hair",
"texture": "mcl_skins_hair_5.png",
"mask": "mcl_skins_hair_5_mask.png"
},
{
"type": "hair",
"texture": "mcl_skins_hair_6.png",
"mask": "mcl_skins_hair_6_mask.png"
},
{
"type": "hair",
"texture": "mcl_skins_hair_7.png",
"mask": "mcl_skins_hair_7_mask.png"
},
{
"type": "hair",
"texture": "mcl_skins_hair_8.png",
"mask": "mcl_skins_hair_8_mask.png"
},
{
"type": "hair",
"texture": "mcl_skins_hair_9.png",
"mask": "mcl_skins_hair_9_mask.png"
},
{
"type": "hair",
"texture": "mcl_skins_hair_10.png",
"mask": "mcl_skins_hair_10_mask.png",
"steve": true
},
{
"type": "hair",
"texture": "mcl_skins_hair_11.png",
"mask": "mcl_skins_hair_11_mask.png",
"alex": true
},
{
"type": "hair"
},
{
"type": "headwear",
"texture": "mcl_skins_headwear_1.png"
},
{
"type": "headwear",
"texture": "mcl_skins_headwear_2.png"
},
{
"type": "headwear",
"texture": "mcl_skins_headwear_3.png"
},
{
"type": "headwear",
"texture": "mcl_skins_headwear_4.png"
},
{
"type": "headwear",
"texture": "mcl_skins_headwear_5.png"
},
{
"type": "headwear",
"texture": "mcl_skins_headwear_6.png",
"preview_rotation": {
"x": -10,
"y": 200
}
},
{
"type": "headwear",
"texture": "mcl_skins_headwear_7.png"
},
{
"type": "headwear",
"steve": true
},
{
"type": "bottom",
"texture": "mcl_skins_bottom_1.png",
"mask": "mcl_skins_bottom_1_mask.png"
},
{
"type": "bottom",
"texture": "mcl_skins_bottom_2.png",
"mask": "mcl_skins_bottom_2_mask.png"
},
{
"type": "bottom",
"texture": "mcl_skins_bottom_3.png",
"mask": "mcl_skins_bottom_3_mask.png"
},
{
"type": "bottom",
"texture": "mcl_skins_bottom_4.png",
"mask": "mcl_skins_bottom_4_mask.png",
"steve": true,
"alex": true
},
{
"type": "top",
"texture": "mcl_skins_top_1.png",
"mask": "mcl_skins_top_1_mask.png"
},
{
"type": "top",
"texture": "mcl_skins_top_2.png",
"mask": "mcl_skins_top_2_mask.png"
},
{
"type": "top",
"texture": "mcl_skins_top_3.png",
"mask": "mcl_skins_top_3_mask.png"
},
{
"type": "top",
"texture": "mcl_skins_top_4.png",
"mask": "mcl_skins_top_4_mask.png"
},
{
"type": "top",
"texture": "mcl_skins_top_5.png",
"mask": "mcl_skins_top_5_mask.png"
},
{
"type": "top",
"texture": "mcl_skins_top_6.png",
"mask": "mcl_skins_top_6_mask.png"
},
{
"type": "top",
"texture": "mcl_skins_top_7.png",
"mask": "mcl_skins_top_7_mask.png"
},
{
"type": "top",
"texture": "mcl_skins_top_8.png",
"mask": "mcl_skins_top_8_mask.png"
},
{
"type": "top",
"texture": "mcl_skins_top_9.png",
"mask": "mcl_skins_top_9_mask.png",
"alex": true
},
{
"type": "top",
"texture": "mcl_skins_top_10.png",
"mask": "mcl_skins_top_10_mask.png",
"steve": true
},
{
"type": "base",
"texture": "mcl_skins_base_1.png",
"mask": "mcl_skins_base_1_mask.png",
"steve": true,
"alex": true
}
]

@ -1,13 +0,0 @@
# textdomain: mcl_skins
[<player>] [<skin number>]=[<Spieler>] [<Aussehens-Nummer>]
Select player skin of yourself or another player=Spieleraussehen von Ihnen oder einem anderen Spieler auswählen
Insufficient or wrong parameters=Unzureichende oder falsche Parameter
Player @1 not online!=Spieler @1 ist nicht online!
You need the “server” privilege to change the skin of other players!=Sie brauchen das „server“-Privileg, um das Aussehen anderer Spieler zu ändern!
Invalid skin number! Valid numbers: 0 to @1=Ungültige Aussehens-Nummer! Gültige Nummern: 0 bis @1
Your skin has been set to: @1=Ihr Aussehen wurde geändert auf: @1
Your skin has been set to: @1 (@2)=Ihr Aussehen wurde geändert auf: @1 (@2)
Skin of @1 set to: @2 (@3)=Aussehen von @1 gesetzt auf: @2 (@3)
Select player skin:=Spieleraussehen wählen:
@1 (@2)=@1 (@2)
Name: @1=Name: @1

@ -1,13 +0,0 @@
# textdomain: mcl_skins
[<player>] [<skin number>]=[<Jugador>] [<Número de skin>]
Select player skin of yourself or another player=Selecciona el skin tuyo o de otro jugador
Insufficient or wrong parameters=Parámetros insuficientes o incorrectos
Player @1 not online!=¡El jugador @1 no está en línea!
You need the “server” privilege to change the skin of other players!=¡Necesitas el privilegio de "servidor" para cambiar el aspecto de otros jugadores!
Invalid skin number! Valid numbers: 0 to @1=¡Número de piel no válido! Números válidos: 0 a @1
Your skin has been set to: @1=Su skin se ha configurado a: @1
Your skin has been set to: @1 (@2)=Su skin se ha configurado a: @1 (@2)
Skin of @1 set to: @2 (@3)=El skin de @1 se ha configurado a: @2 (@3)
Select player skin:=Selecciona el skin del jugador:
@1 (@2)=@1 (@2)
Name: @1=Nombre: @1

@ -1,14 +1,13 @@
# textdomain: mcl_skins
[<player>] [<skin number>]=[<joueur>] [<numéro d'apparence>]
Select player skin of yourself or another player=Sélectionner une apparence pour vous même ou un autre joueur
Insufficient or wrong parameters=Paramètres insuffisants ou incorrects
Player @1 not online!=Le joueur @1 n'est pas en ligne!
You need the “server” privilege to change the skin of other players!=Vous avez besoin du privilège “server” pour changer l'apparence des autres joueurs!
Invalid skin number! Valid numbers: 0 to @1=Numéro d'apparence incorrect! Numéros valides : 0 à @1
Your skin has been set to: @1=Votre apparence a été définie à: @1
Your skin has been set to: @1 (@2)=Votre apparence a été définie à: @1 (@2)
Skin of @1 set to: @2 (@3)=Apparence of @1 set to: @2 (@3)=
Select player skin:=Sélectionner l'apparence du joueur :
@1 (@2)=@1 (@2)
Name: @1=Nom : @
Templates=Modèles
Arm size=Taille des bras
Bases=Teint
Footwears=Chaussures
Eyes=Yeux
Mouths=Bouches
Bottoms=Bas
Tops=Haut
Hairs=Cheveux
Headwears=Coiffe
Open skin configuration screen.=Ouvrir l'écran de configuration du costume.
Select=Sélectionner

@ -1,16 +0,0 @@
# textdomain: mcl_skins
# UNFINISHED translation!
# TODO: Remove the # sign from the translations below and add the missing translations.
[<player>] [<skin number>]=
Select player skin of yourself or another player=
Insufficient or wrong parameters=
Player @1 not online!=
You need the “server” privilege to change the skin of other players!=
Invalid skin number! Valid numbers: 0 to @1=
Your skin has been set to: @1=
Your skin has been set to: @1 (@2)=
Skin of @1 set to: @2 (@3)=
Select player skin:=Pilih Kulit Pemain:
@1 (@2)=
Name: @1=Nama: @1

@ -1,13 +0,0 @@
# textdomain: mcl_skins
[<player>] [<skin number>]=[<gracz>] [<numer skina>]
Select player skin of yourself or another player=Wybierz skin gracza dla siebie lub innego gracza
Insufficient or wrong parameters=Niewystarczające lub złe parametry
Player @1 not online!=Gracz @1 nie jest online!
You need the “server” privilege to change the skin of other players!=Potrzebujesz uprawnienia "serwer", aby zmieniać skiny innych graczy!
Invalid skin number! Valid numbers: 0 to @1=Niepoprawny numer skina! Poprawne numery: od 0 do @1
Your skin has been set to: @1=Twój skin został ustawiony na: @1
Your skin has been set to: @1 (@2)=Twój skin został ustawiony na: @1 (@2)
Skin of @1 set to: @2 (@3)=Skin gracza @1 ustawiony na @2 (@3)
Select player skin:=Wybierz skin gracza:
@1 (@2)=@1 (@2)
Name: @1=Nazwa: @1

@ -1,13 +0,0 @@
# textdomain: mcl_skins
[<player>] [<skin number>]=[<игрок>] [<номер скина>]
Select player skin of yourself or another player=Выберите скин для себя или для другого игрока
Insufficient or wrong parameters=Недопустимые или неправильные параметры
Player @1 not online!=Игрок @1 не в сети!
You need the “server” privilege to change the skin of other players!=Для смены скинов другим игрокам у вас должна быть привилегия “server”!
Invalid skin number! Valid numbers: 0 to @1=Недопустимый номер скина! Правильные номера: от 0 до @1
Your skin has been set to: @1=Ваш скин выбран: @1
Your skin has been set to: @1 (@2)=Ваш скин установлен: @1 (@2)
Skin of @1 set to: @2 (@3)=Скин игрока @1 установлен: @2 (@3)
Select player skin:=Выбор скина игрока:
@1 (@2)=@1 (@2)
Name: @1=Имя: @1

@ -1,13 +0,0 @@
# textdomain: mcl_skins
[<player>] [<skin number>]=[<玩家名字>] [<皮膚篇號>]
Select player skin of yourself or another player=替自己或其他玩家選擇皮膚
Insufficient or wrong parameters=無效或錯誤參數
Player @1 not online!=玩家 @1 不在線!
You need the “server” privilege to change the skin of other players!=你需要「server」權限來替換其他玩家的皮膚
Invalid skin number! Valid numbers: 0 to @1=無效皮膚篇號有效篇號0至@1
Your skin has been set to: @1=你的皮膚已換成:@1
Your skin has been set to: @1 (@2)=你的皮膚已換成:@1@2
Skin of @1 set to: @2 (@3)=@1的皮膚已換成@1
Select player skin:=選擇玩家皮膚:
@1 (@2)=@1@2
Name: @1=名稱:@1

@ -1,13 +1,13 @@
# textdomain: mcl_skins
[<player>] [<skin number>]=
Select player skin of yourself or another player=
Insufficient or wrong parameters=
Player @1 not online!=
You need the “server” privilege to change the skin of other players!=
Invalid skin number! Valid numbers: 0 to @1=
Your skin has been set to: @1=
Your skin has been set to: @1 (@2)=
Skin of @1 set to: @2 (@3)=
Select player skin:=
@1 (@2)=
Name: @1=
Templates=
Arm size=
Bases=
Footwears=
Eyes=
Mouths=
Bottoms=
Tops=
Hairs=
Headwears=
Open skin configuration screen.=
Select=

@ -0,0 +1,115 @@
mcl_skins_base_1.png
mcl_skins_button.png
mcl_skins_footwear_3.png
mcl_skins_headgear_1.png
mcl_skins_headgear_3.png
mcl_skins_headgear_4.png
mcl_skins_headgear_5.png
mcl_skins_mouth_2.png
mcl_skins_mouth_3.png
mcl_skins_mouth_4.png
mcl_skins_mouth_5.png
mcl_skins_select_overlay.png
mcl_skins_slim_arms.png
mcl_skins_thick_arms.png
mcl_skins_top_2.png
mcl_skins_top_5.png
mcl_skins_eye_5.png
mcl_skins_hair_8.png
mcl_skins_top_6.png
mcl_skins_bottom_3.png
mcl_skins_eye_7.png
mcl_skins_mouth_7.png
Original work by MrRar
License: CC BY-SA 4.0
mcl_skins_top_1.png
mcl_skins_mouth_1.png
mcl_skins_hair_1.png
mcl_skins_hair_2.png
mcl_skins_eye_1.png
mcl_skins_eye_2.png
mcl_skins_footwear_1.png
mcl_skins_headgear_2.png
mcl_skins_mouth_1.png
mcl_skins_top_1.png
mcl_skins_mouth_2.png
Name: Pixel Perfection resource pack for Minecraft 1.11
Author: XSSheep. Adapted for mcl_skins by MrRar.
License: CC BY-SA 4.0
Source: https://www.planetminecraft.com/texture_pack/131pixel-perfection/
mcl_skins_hair_3.png
mcl_skins_eye_3.png
mcl_skins_footwear_2.png
Name: the 10the doctor
Author: lovehart. Adapted for mcl_skins by MrRar.
License: CC BY-SA 3.0
Source: http://minetest.fensta.bplaced.net/#!page:1,filtertype:Id,filter:367
mcl_skins_hair_4.png
Blonde Girl
Author: Rin. Adapted for mcl_skins by MrRar.
License: CC BY-SA 3.0
Source: http://minetest.fensta.bplaced.net/#id=918
mcl_skins_hair_5.png
Name: hobbit from lottmob
Author: lovehart. Adapted for mcl_skins by MrRar.
License: CC BY-SA 3.0
Source: http://minetest.fensta.bplaced.net/#id=336
mcl_skins_top_4.png
Name: Oliver_MV
Author: hansuke123. Adapted for mcl_skins by MrRar.
License: CC BY-SA 3.0
Source: http://minetest.fensta.bplaced.net/#!page:1,filtertype:Id,filter:291
mcl_skins_hair_6.png
mcl_skins_eye_6.png
Name: Mumbo Jumbo
Author: ZestyZachary
License: CC 0 (1.0)
Source: http://minetest.fensta.bplaced.net/#!page:1,filtertype:Id,filter:2100
mcl_skins_eye_4.png
Name: lisa
Author: hansuke123
License: CC BY-SA 3.0
Source: http://minetest.fensta.bplaced.net/#!page:1,filtertype:Id,filter:88
mcl_skins_headwear_7.png
Name: Ryu
Author: Ginsu23. Adapted for mcl_skins by MrRar.
License: CC BY-SA 3.0
Source: http://minetest.fensta.bplaced.net/#id=464
mcl_skins_top_8.png
Name: Hoodie Enderman
Author: Kpenguin. Adapted for mcl_skins by MrRar.
License: CC BY-SA 3.0
Source: http://minetest.fensta.bplaced.net/#id=962
mcl_skins_hair_9.png
Name: Trader 1
Author: TenPlus1. Adapted for mcl_skins by MrRar.
License: CC BY-SA 3.0
Source: http://minetest.fensta.bplaced.net/#id=1258
mcl_skins_bottom_4.png
mcl_skins_top_9.png
mcl_skins_top_10.png
mcl_skins_hair_10.png
mcl_skins_hair_11.png
Name: Pixel Perfection Legacy 1.19
Author: Nova_Wostra. Adapted for mcl_skins by MrRar.
License: CC BY-SA 4.0
Source: https://www.planetminecraft.com/texture-pack/pixel-perfection-chorus-edit/
mcl_skins_bottom.obj
mcl_skins_head.obj
mcl_skins_top.obj
Name: character.blend in player_api mod from Minetest Game
Author: celeron55, MirceaKitsune, Jordach, kilbith, sofar, xunto, Rogier-5, TeTpaAka, Desour, stujones11, An0n3m0us. Adapted for mcl_skins by MrRar.
License: CC BY-SA 3.0
Source: https://github.com/minetest/minetest_game

@ -1,3 +0,0 @@
name = "Steve",
author = "%TEXTURE_PACK_AUTHOR%",
gender = "male",

@ -1,3 +0,0 @@
name = "Alex",
author = "%TEXTURE_PACK_AUTHOR%",
gender = "female",

@ -1,5 +1,4 @@
name = mcl_skins
author = TenPlus1
description = Mod that allows players to set their individual skins.
depends = mcl_player
optional_depends = mcl_inventory, intllib
author = MrRar
description = Advanced player skin customization.
depends = mcl_player,mcl_inventory

@ -0,0 +1,108 @@
# Blender v2.93.5 OBJ File: ''
# www.blender.org
mtllib bottom.mtl
o bottom
v -2.100000 4.358421 1.050001
v -2.100000 1.648314 1.049999
v 2.100000 1.648314 1.049999
v 2.100000 4.358421 1.050001
v -2.100000 1.648314 -1.050001
v -2.100000 4.358421 -1.049998
v 2.100000 1.648314 -1.050001
v 2.100000 4.358421 -1.049998
v 0.000000 1.648314 -1.050001
v 0.000000 -4.651686 -1.050003
v 0.000000 -4.651686 1.049997
v 0.000000 1.648314 1.049999
v 0.000000 -4.651686 -1.050003
v 0.000000 -4.651686 1.049997
v -2.100000 -4.651685 1.049997
v -2.100000 -4.651685 -1.050003
v -2.100000 1.648315 1.049999
v -2.100000 1.648315 -1.050001
v 0.000000 1.648314 1.049999
v 2.100000 1.648315 -1.050001
v 2.100000 -4.651685 -1.050003
v 0.000000 1.648314 -1.050001
v 2.100000 -4.651685 1.049997
v 2.100000 1.648315 1.049999
vt 0.500000 0.161316
vt 0.500000 0.000000
vt 0.625000 0.000000
vt 0.625000 0.161316
vt 0.437500 0.000000
vt 0.437500 0.161316
vt 0.312500 0.000000
vt 0.312500 0.161316
vt 0.562500 0.375000
vt 0.562500 0.500000
vt 0.437500 0.500000
vt 0.437500 0.375000
vt 0.125000 0.375000
vt 0.125000 0.000000
vt 0.187500 0.000000
vt 0.187500 0.375000
vt 0.187500 0.375000
vt 0.187500 0.500000
vt 0.125000 0.500000
vt 0.125000 0.375000
vt 0.000000 0.375000
vt 0.062500 0.375000
vt 0.062500 0.000000
vt 0.000000 0.000000
vt 0.187500 0.375000
vt 0.250000 0.375000
vt 0.250000 0.000000
vt 0.187500 0.000000
vt 0.062500 0.375000
vt 0.062500 0.000000
vt 0.125000 0.375000
vt 0.125000 0.000000
vt 0.250000 0.000000
vt 0.250000 0.375000
vt 0.000000 0.375000
vt 0.000000 0.000000
vt 0.250000 0.161316
vt 0.250000 0.000000
vt 0.125000 0.375000
vt 0.125000 0.500000
vt 0.062500 0.500000
vt 0.062500 0.375000
vt 0.187500 0.375000
vt 0.125000 0.375000
vt 0.125000 0.500000
vt 0.187500 0.500000
vt 0.125000 0.375000
vt 0.062500 0.375000
vt 0.062500 0.500000
vt 0.125000 0.500000
vt 0.000000 1.000000
vt 0.000000 1.000000
vt 0.000000 1.000000
vt 0.000000 1.000000
vn 0.0000 -0.0000 1.0000
vn -1.0000 -0.0000 0.0000
vn 0.0000 0.0000 -1.0000
vn 0.0000 -1.0000 -0.0000
vn 1.0000 0.0000 0.0000
vn 0.0000 1.0000 0.0000
usemtl Character
s 1
f 1/1/1 2/2/1 3/3/1 4/4/1
f 5/5/2 2/2/2 1/1/2 6/6/2
f 7/7/3 5/5/3 6/6/3 8/8/3
f 7/9/4 3/10/4 2/11/4 5/12/4
f 9/13/2 10/14/2 11/15/2 12/16/2
f 13/17/4 14/18/4 15/19/4 16/20/4
f 17/21/2 18/22/2 16/23/2 15/24/2
f 19/25/1 17/26/1 15/27/1 14/28/1
f 20/29/3 21/30/3 10/14/3 9/13/3
f 18/22/3 22/31/3 13/32/3 16/23/3
f 12/16/1 11/15/1 23/33/1 24/34/1
f 22/31/5 19/25/5 14/28/5 13/32/5
f 24/35/5 23/36/5 21/30/5 20/29/5
f 4/37/5 3/38/5 7/7/5 8/8/5
f 18/39/6 17/40/6 19/41/6 22/42/6
f 10/43/4 21/44/4 23/45/4 11/46/4
f 20/47/6 9/48/6 12/49/6 24/50/6
f 4/51/6 8/52/6 6/53/6 1/54/6

@ -0,0 +1,72 @@
# Blender v2.93.5 OBJ File: ''
# www.blender.org
mtllib head.mtl
o head
v -2.100000 -2.100004 2.099999
v 2.100000 2.099997 -2.100001
v 2.100000 2.099997 2.099999
v 2.300000 -2.300003 -2.300001
v 2.300000 2.299997 2.299999
v 2.100000 -2.100004 2.099999
v 2.100000 -2.100004 -2.100001
v -2.100000 2.099997 2.099999
v -2.100000 2.099997 -2.100001
v -2.100000 -2.100004 -2.100001
v 2.300000 2.299997 -2.300001
v 2.300000 -2.300003 2.299999
v -2.300000 2.299997 2.299999
v -2.300000 -2.300003 2.299999
v -2.300000 2.299997 -2.300001
v -2.300000 -2.300003 -2.300001
vt 0.500000 0.750000
vt 0.375000 0.750000
vt 0.375000 0.500000
vt 0.500000 0.500000
vt 0.250000 0.750000
vt 0.250000 0.500000
vt 0.125000 0.750000
vt 0.125000 0.500000
vt 0.375000 0.750000
vt 0.375000 1.000000
vt 0.250000 1.000000
vt 0.250000 0.750000
vt 0.250000 1.000000
vt 0.125000 1.000000
vt 0.000000 0.750000
vt 0.000000 0.500000
vt 1.000000 0.750000
vt 0.875000 0.750000
vt 0.875000 0.500000
vt 1.000000 0.500000
vt 0.750000 0.750000
vt 0.750000 0.500000
vt 0.625000 0.750000
vt 0.625000 0.500000
vt 0.875000 0.750000
vt 0.875000 1.000000
vt 0.750000 1.000000
vt 0.750000 0.750000
vt 0.750000 1.000000
vt 0.625000 1.000000
vt 0.500000 0.750000
vt 0.500000 0.500000
vn 0.0000 0.0000 1.0000
vn -1.0000 0.0000 0.0000
vn 0.0000 0.0000 -1.0000
vn 0.0000 -1.0000 0.0000
vn 0.0000 1.0000 0.0000
vn 1.0000 0.0000 0.0000
usemtl Character
s off
f 3/1/1 8/2/1 1/3/1 6/4/1
f 8/2/2 9/5/2 10/6/2 1/3/2
f 9/5/3 2/7/3 7/8/3 10/6/3
f 7/9/4 6/10/4 1/11/4 10/12/4
f 9/5/5 8/13/5 3/14/5 2/7/5
f 3/15/6 6/16/6 7/8/6 2/7/6
f 5/17/1 13/18/1 14/19/1 12/20/1
f 13/18/2 15/21/2 16/22/2 14/19/2
f 15/21/3 11/23/3 4/24/3 16/22/3
f 4/25/4 12/26/4 14/27/4 16/28/4
f 15/21/5 13/29/5 5/30/5 11/23/5
f 5/31/6 12/32/6 4/24/6 11/23/6

@ -0,0 +1,174 @@
# Blender v2.93.5 OBJ File: ''
# www.blender.org
mtllib top.mtl
o top
v -2.100000 -3.149994 1.049999
v -2.100000 -3.149994 -1.050001
v -2.100000 3.150004 1.049999
v -2.100000 3.150004 -1.050001
v -4.200000 3.150003 -1.050001
v -4.200000 3.150003 1.049999
v -2.100000 3.150003 1.049999
v -2.100000 3.150003 -1.050001
v -4.200000 -3.149994 -1.050001
v -4.200000 -3.149994 1.049999
v -2.100000 -3.149994 1.049999
v -2.100000 -3.149994 -1.050001
v 2.100000 -3.149994 -1.050001
v 2.100000 -3.149994 1.049999
v 2.100000 3.150004 -1.050001
v 2.100000 3.150004 1.049999
v 2.100000 -3.149994 -1.050001
v 2.100000 -3.149994 1.049999
v 4.200000 -3.149994 1.049999
v 4.200000 -3.149994 -1.050001
v 2.100000 3.150003 -1.050001
v 2.100000 3.150003 1.049999
v 4.200000 3.150003 1.049999
v 4.200000 3.150003 -1.050001
v 2.100000 3.150004 -1.050001
v 2.100000 3.150004 -1.050001
v 2.100000 3.150004 1.049999
v 2.100000 3.150004 1.049999
v 2.100000 -3.149994 1.049999
v 2.100000 -3.149994 1.049999
v 2.100000 -3.149994 -1.050001
v 2.100000 -3.149994 -1.050001
v -2.100000 3.150004 1.049999
v -2.100000 3.150004 1.049999
v -2.100000 -3.149994 1.049999
v -2.100000 -3.149994 1.049999
v -2.100000 3.150004 -1.050001
v -2.100000 3.150004 -1.050001
v -2.100000 -3.149994 -1.050001
v -2.100000 -3.149994 -1.050001
v -4.200000 3.150003 -1.050001
v -4.200000 3.150003 -1.050001
v -4.200000 -3.149994 -1.050001
v -4.200000 -3.149994 -1.050001
v -2.100000 3.150003 1.049999
v -2.100000 3.150003 1.049999
v -2.100000 -3.149994 1.049999
v -2.100000 -3.149994 1.049999
v -4.200000 3.150003 1.049999
v -4.200000 3.150003 1.049999
v -4.200000 -3.149994 1.049999
v -4.200000 -3.149994 1.049999
v -2.100000 3.150003 -1.050001
v -2.100000 3.150003 -1.050001
v -2.100000 -3.149994 -1.050001
v -2.100000 -3.149994 -1.050001
v 2.100000 3.150003 -1.050001
v 2.100000 3.150003 -1.050001
v 2.100000 3.150003 1.049999
v 2.100000 3.150003 1.049999
v 2.100000 -3.149994 1.049999
v 2.100000 -3.149994 1.049999
v 2.100000 -3.149994 -1.050001
v 2.100000 -3.149994 -1.050001
v 4.200000 3.150003 1.049999
v 4.200000 3.150003 1.049999
v 4.200000 -3.149994 1.049999
v 4.200000 -3.149994 1.049999
v 4.200000 3.150003 -1.050001
v 4.200000 3.150003 -1.050001
v 4.200000 -3.149994 -1.050001
v 4.200000 -3.149994 -1.050001
vt 0.625000 0.375000
vt 0.500000 0.375000
vt 0.500000 0.000000
vt 0.625000 0.000000
vt 0.500000 0.375000
vt 0.437500 0.375000
vt 0.437500 0.000000
vt 0.500000 0.000000
vt 0.437500 0.375000
vt 0.312500 0.375000
vt 0.312500 0.000000
vt 0.437500 0.000000
vt 0.562500 0.375000
vt 0.562500 0.500000
vt 0.437500 0.500000
vt 0.437500 0.375000
vt 0.437500 0.375000
vt 0.437500 0.500000
vt 0.312500 0.500000
vt 0.312500 0.375000
vt 0.812500 0.375000
vt 0.875000 0.375000
vt 0.875000 0.000000
vt 0.812500 0.000000
vt 0.750000 0.375000
vt 0.812500 0.375000
vt 0.812500 0.000000
vt 0.750000 0.000000
vt 0.750000 0.375000
vt 0.812500 0.375000
vt 0.812500 0.500000
vt 0.750000 0.500000
vt 0.687500 0.375000
vt 0.750000 0.375000
vt 0.750000 0.500000
vt 0.687500 0.500000
vt 0.250000 0.375000
vt 0.250000 0.000000
vt 0.312500 0.000000
vt 0.312500 0.375000
vt 0.687500 0.375000
vt 0.750000 0.375000
vt 0.750000 0.000000
vt 0.687500 0.000000
vt 0.625000 0.375000
vt 0.687500 0.375000
vt 0.687500 0.000000
vt 0.625000 0.000000
vt 0.625000 0.375000
vt 0.625000 0.000000
vt 0.687500 0.000000
vt 0.687500 0.375000
vt 0.687500 0.375000
vt 0.687500 0.500000
vt 0.750000 0.500000
vt 0.750000 0.375000
vt 0.687500 0.375000
vt 0.687500 0.000000
vt 0.750000 0.000000
vt 0.750000 0.375000
vt 0.750000 0.375000
vt 0.750000 0.000000
vt 0.812500 0.000000
vt 0.812500 0.375000
vt 0.750000 0.375000
vt 0.750000 0.500000
vt 0.812500 0.500000
vt 0.812500 0.375000
vt 0.812500 0.375000
vt 0.812500 0.000000
vt 0.875000 0.000000
vt 0.875000 0.375000
vn -0.0000 0.0000 1.0000
vn -1.0000 0.0000 0.0000
vn 0.0000 0.0000 -1.0000
vn 0.0000 -1.0000 0.0000
vn 0.0000 1.0000 0.0000
vn 1.0000 0.0000 0.0000
usemtl Character
s off
f 27/1/1 3/2/1 1/3/1 14/4/1
f 33/5/2 4/6/2 2/7/2 35/8/2
f 37/9/3 25/10/3 31/11/3 39/12/3
f 13/13/4 29/14/4 36/15/4 40/16/4
f 38/17/5 34/18/5 16/19/5 15/20/5
f 7/21/1 6/22/1 10/23/1 11/24/1
f 8/25/6 45/26/6 47/27/6 12/28/6
f 17/29/4 20/30/4 19/31/4 18/32/4
f 24/33/5 21/34/5 22/35/5 23/36/5
f 28/37/6 30/38/6 32/39/6 26/40/6
f 5/41/3 53/42/3 55/43/3 9/44/3
f 49/45/2 41/46/2 43/47/2 51/48/2
f 65/49/6 67/50/6 71/51/6 69/52/6
f 42/53/5 50/54/5 46/55/5 54/56/5
f 70/57/3 72/58/3 63/59/3 57/60/3
f 58/61/2 64/62/2 61/63/2 59/64/2
f 56/65/4 48/66/4 52/67/4 44/68/4
f 60/69/1 62/70/1 68/71/1 66/72/1

Binary file not shown.

After

Width:  |  Height:  |  Size: 137 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 153 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 377 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 144 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 694 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 151 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 604 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 137 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 680 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 141 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 203 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 171 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 131 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 121 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 136 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 107 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 151 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 99 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 927 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 229 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 331 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 484 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 328 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 170 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 454 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 202 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 196 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 490 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 169 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 445 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 175 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 196 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 886 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 282 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 680 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 161 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 576 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 195 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 582 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 172 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 730 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 243 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 648 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 886 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 120 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 125 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 120 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 140 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 291 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 99 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 122 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 139 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 129 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 95 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 99 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 98 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 167 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 93 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 93 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 606 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 392 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 154 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 131 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 568 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 146 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 941 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 138 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 150 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 151 B

Some files were not shown because too many files have changed in this diff Show More