Compare commits
5 Commits
f705f446b5
...
30755b164f
Author | SHA1 | Date |
---|---|---|
|
30755b164f | |
|
99cb17d6bb | |
|
d83c40b6e9 | |
|
52ae3ae5c5 | |
|
b2af386587 |
|
@ -163,8 +163,15 @@ Floodfills adjacent pixels of exactly the same color, swapping out their color f
|
|||
|
||||
Left-click to undo, right-click to redo. Undo-redo log size is limited due to [Memory Usage] constraints.
|
||||
|
||||
##### Eraser
|
||||
|
||||
Left-click to mark a pixel as transparent, right-click to restore opacity of the first transparent pixel above the pointed pixel.
|
||||
|
||||
## Configuration
|
||||
|
||||
`epidermis` must be added to `secure.http_mods` for SkinDB uploading & downloading (including syncing) to be enabled;
|
||||
otherwise epidermis will be limited to the local (offline, cached) SkinDB copy
|
||||
|
||||
<!--modlib:conf:2-->
|
||||
### `skindb`
|
||||
|
||||
|
|
3
init.lua
3
init.lua
|
@ -9,8 +9,7 @@ include"theme.lua"
|
|||
include"send_notification.lua"
|
||||
include"colorpicker_rgb_formspec.lua"
|
||||
include"colorpicker_hsv_ingame.lua"
|
||||
local http = assert(minetest.request_http_api(), "add epidermis to secure.http_mods")
|
||||
assert(loadfile(modlib.mod.get_resource("skindb.lua")))(http)
|
||||
assert(loadfile(modlib.mod.get_resource("skindb.lua")))(minetest.request_http_api())
|
||||
include"skin.lua"
|
||||
include"paintable.lua"
|
||||
include"tools.lua"
|
||||
|
|
1
mod.conf
1
mod.conf
|
@ -1,4 +1,5 @@
|
|||
name = epidermis
|
||||
title = Epidermis
|
||||
description = Feature-fledged skin (painting) mod
|
||||
depends = modlib, moblib, fslib
|
||||
optional_depends = visible_wielditem, player_api, nc_player_model, nc_skins
|
||||
|
|
|
@ -292,13 +292,18 @@ function def:on_activate()
|
|||
end, true)
|
||||
end
|
||||
|
||||
-- TODO (engine change needed) call this on object removal
|
||||
-- See https://github.com/minetest/minetest/pull/11931
|
||||
function def:_delete()
|
||||
epidermis.mark_for_deletion(self._.id)
|
||||
self.object:remove()
|
||||
end
|
||||
|
||||
-- TODO override clearobjects to catch that as well
|
||||
function def:on_deactivate(removal)
|
||||
if removal then
|
||||
epidermis.mark_for_deletion(self._.id)
|
||||
end
|
||||
end
|
||||
|
||||
function def:_get_intersection_infos(mt_pos, mt_direction)
|
||||
local intersection_infos = {}
|
||||
|
||||
|
@ -436,33 +441,41 @@ function def:_show_control_panel(player)
|
|||
tooltip = "Open texture preview"
|
||||
},
|
||||
},
|
||||
{
|
||||
{
|
||||
exit = false,
|
||||
name = "upload",
|
||||
icon = "upload",
|
||||
tooltip = "Upload to SkinDB"
|
||||
},
|
||||
{
|
||||
exit = false,
|
||||
name = "download",
|
||||
icon = "download",
|
||||
tooltip = "Pick from SkinDB"
|
||||
}
|
||||
},
|
||||
{{
|
||||
exit = false,
|
||||
name = "delete",
|
||||
icon = "bin",
|
||||
tooltip = "Delete"
|
||||
}},
|
||||
{{
|
||||
exit = true,
|
||||
name = "close",
|
||||
icon = "cross",
|
||||
tooltip = "Close"
|
||||
}}
|
||||
}
|
||||
|
||||
local skindb_group = {}
|
||||
if def._show_upload_formspec then
|
||||
table.insert(skindb_group, {
|
||||
exit = false,
|
||||
name = "upload",
|
||||
icon = "upload",
|
||||
tooltip = "Upload to SkinDB"
|
||||
})
|
||||
end
|
||||
if def._show_picker_formspec then
|
||||
table.insert(skindb_group, {
|
||||
exit = false,
|
||||
name = "download",
|
||||
icon = "download",
|
||||
tooltip = "Pick from SkinDB"
|
||||
})
|
||||
end
|
||||
if #skindb_group > 0 then
|
||||
table.insert(action_groups, skindb_group)
|
||||
end
|
||||
|
||||
table.insert(action_groups, {{
|
||||
exit = false,
|
||||
name = "delete",
|
||||
icon = "bin",
|
||||
tooltip = "Delete"
|
||||
}})
|
||||
table.insert(action_groups, {{
|
||||
exit = true,
|
||||
name = "close",
|
||||
icon = "cross",
|
||||
tooltip = "Close"
|
||||
}})
|
||||
local fs = {
|
||||
false, -- placeholder
|
||||
{"real_coordinates", true},
|
||||
|
@ -504,9 +517,13 @@ function def:_show_control_panel(player)
|
|||
elseif fields.delete then
|
||||
self:_show_delete_formspec(player)
|
||||
elseif fields.upload then
|
||||
self:_show_upload_formspec(player)
|
||||
if self._show_upload_formspec then
|
||||
self:_show_upload_formspec(player)
|
||||
end
|
||||
elseif fields.download then
|
||||
self:_show_picker_formspec(player)
|
||||
if self._show_picker_formspec then
|
||||
self:_show_picker_formspec(player)
|
||||
end
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
@ -634,6 +651,9 @@ function def:_show_upload_formspec(player, message)
|
|||
}
|
||||
end)
|
||||
end
|
||||
if not epidermis.upload then -- no SkinDB support
|
||||
def._show_upload_formspec = nil
|
||||
end
|
||||
|
||||
function def:_show_picker_formspec(player)
|
||||
if #epidermis.skins == 0 then
|
||||
|
@ -749,5 +769,8 @@ function def:_show_picker_formspec(player)
|
|||
end
|
||||
show_formspec()
|
||||
end
|
||||
if not epidermis.skins then -- no SkinDB support
|
||||
def._show_picker_formspec = nil
|
||||
end
|
||||
|
||||
moblib.register_entity("epidermis:paintable", def)
|
||||
|
|
83
skindb.lua
83
skindb.lua
|
@ -7,7 +7,53 @@ Assumptions:
|
|||
- `GROUP BY` works like `ORDER BY` (otherwise no ordering is guaranteed)
|
||||
]]
|
||||
|
||||
local http = assert(...)
|
||||
-- Load offline copy
|
||||
|
||||
local texture_path = epidermis.paths.dynamic_textures.skindb
|
||||
epidermis.skins = {}
|
||||
|
||||
local function on_local_copy_loaded() end
|
||||
|
||||
local function load_local_copy()
|
||||
local ids = {}
|
||||
for _, filename in ipairs(minetest.get_dir_list(texture_path, false)) do
|
||||
local id = filename:match"^epidermis_skindb_(%d+)%.png$"
|
||||
if id then
|
||||
table.insert(ids, tonumber(id))
|
||||
end
|
||||
end
|
||||
table.sort(ids)
|
||||
for index, id in ipairs(ids) do
|
||||
local filename = ("epidermis_skindb_%d.png"):format(id)
|
||||
local path = modlib.file.concat_path{texture_path, filename}
|
||||
local metafile = assert(io.open(modlib.file.concat_path{texture_path, filename .. ".json"}))
|
||||
local meta = modlib.json:read_file(metafile)
|
||||
metafile:close()
|
||||
meta.texture = "blank.png" -- dynamic media isn't available yet
|
||||
epidermis.skins[index] = meta
|
||||
epidermis.dynamic_add_media(path, function()
|
||||
meta.texture = filename
|
||||
end, false) -- Enable caching for SkinDB skins
|
||||
end
|
||||
on_local_copy_loaded()
|
||||
end
|
||||
-- HACK wait a globalstep before loading the local copy to prevent the dynamic media join race condition in singleplayer
|
||||
minetest.after(0, function()
|
||||
minetest.after(0, load_local_copy)
|
||||
end)
|
||||
|
||||
-- HTTP-requiring code
|
||||
|
||||
local http = ...
|
||||
|
||||
if not http then
|
||||
function on_local_copy_loaded()
|
||||
if #epidermis.skins == 0 then -- empty local copy...
|
||||
epidermis.skins = nil -- ... disable skin picking entirely
|
||||
end
|
||||
end
|
||||
return -- disable entirely
|
||||
end
|
||||
|
||||
local base_url = "http://minetest.fensta.bplaced.net"
|
||||
|
||||
|
@ -68,40 +114,7 @@ minetest.register_privilege("epidermis_upload", {
|
|||
give_to_admin = false,
|
||||
})
|
||||
|
||||
-- "Downloading"
|
||||
|
||||
local texture_path = epidermis.paths.dynamic_textures.skindb
|
||||
epidermis.skins = {}
|
||||
|
||||
local function on_local_copy_loaded() end
|
||||
|
||||
local function load_local_copy()
|
||||
local ids = {}
|
||||
for _, filename in ipairs(minetest.get_dir_list(texture_path, false)) do
|
||||
local id = filename:match"^epidermis_skindb_(%d+)%.png$"
|
||||
if id then
|
||||
table.insert(ids, tonumber(id))
|
||||
end
|
||||
end
|
||||
table.sort(ids)
|
||||
for index, id in ipairs(ids) do
|
||||
local filename = ("epidermis_skindb_%d.png"):format(id)
|
||||
local path = modlib.file.concat_path{texture_path, filename}
|
||||
local metafile = assert(io.open(modlib.file.concat_path{texture_path, filename .. ".json"}))
|
||||
local meta = modlib.json:read_file(metafile)
|
||||
metafile:close()
|
||||
meta.texture = "blank.png" -- dynamic media isn't available yet
|
||||
epidermis.skins[index] = meta
|
||||
epidermis.dynamic_add_media(path, function()
|
||||
meta.texture = filename
|
||||
end, false) -- Enable caching for SkinDB skins
|
||||
end
|
||||
on_local_copy_loaded()
|
||||
end
|
||||
-- HACK wait a globalstep before loading the local copy to prevent the dynamic media join race condition in singleplayer
|
||||
minetest.after(0, function()
|
||||
minetest.after(0, load_local_copy)
|
||||
end)
|
||||
-- "Downloading" / Updating
|
||||
|
||||
local timeout = 10
|
||||
local html_unescape = modlib.web.html.unescape
|
||||
|
|
26
tools.lua
26
tools.lua
|
@ -101,8 +101,22 @@ local function get_entity(user, pointed_thing, allow_any)
|
|||
end
|
||||
end
|
||||
|
||||
local function get_paintable_intersection(user, entity)
|
||||
local intersection_infos = entity:_get_intersection_infos(moblib.get_eye_pos(user), user:get_look_dir())
|
||||
local function get_eye_pos(player)
|
||||
local eye_pos = player:get_pos()
|
||||
eye_pos.y = eye_pos.y + player:get_properties().eye_height
|
||||
local first, third = player:get_eye_offset()
|
||||
if not vector.equals(first, third) then
|
||||
minetest.log("warning", "First & third person eye offsets don't match, assuming first person")
|
||||
end
|
||||
return vector.add(eye_pos, vector.divide(first, 10))
|
||||
end
|
||||
|
||||
local function get_intersection_infos(user, paintable)
|
||||
return paintable:_get_intersection_infos(get_eye_pos(user), user:get_look_dir())
|
||||
end
|
||||
|
||||
local function get_paintable_intersection(user, paintable)
|
||||
local intersection_infos = get_intersection_infos(user, paintable)
|
||||
for _, intersection_info in ipairs(intersection_infos) do
|
||||
if intersection_info.color.a > 0 then
|
||||
return intersection_info
|
||||
|
@ -191,7 +205,7 @@ epidermis.register_tool("epidermis:eraser", {
|
|||
return
|
||||
end
|
||||
local last_transparent_frontface
|
||||
local intersection_infos = paintable:_get_intersection_infos(moblib.get_eye_pos(user), user:get_look_dir())
|
||||
local intersection_infos = get_intersection_infos(user, paintable)
|
||||
for _, intersection_info in ipairs(intersection_infos) do
|
||||
if intersection_info.color.a < 255 then
|
||||
last_transparent_frontface = intersection_info
|
||||
|
@ -210,7 +224,7 @@ epidermis.register_tool("epidermis:eraser", {
|
|||
if not paintable then
|
||||
return
|
||||
end
|
||||
local intersection_infos = paintable:_get_intersection_infos(moblib.get_eye_pos(user), user:get_look_dir())
|
||||
local intersection_infos = get_intersection_infos(user, paintable)
|
||||
for _, intersection_info in ipairs(intersection_infos) do
|
||||
if intersection_info.color.a > 0 then
|
||||
local idx = paintable:_get_pixel_index(unpack(intersection_info.pixelcoord))
|
||||
|
@ -313,7 +327,7 @@ minetest.register_globalstep(function()
|
|||
local wielded_item = player:get_wielded_item()
|
||||
local def = wielded_item:get_definition()
|
||||
local range = def.range or 4
|
||||
local eye_pos = moblib.get_eye_pos(player)
|
||||
local eye_pos = get_eye_pos(player)
|
||||
local raycast = minetest.raycast(eye_pos,
|
||||
vector.add(eye_pos, vector.multiply(player:get_look_dir(), range)),
|
||||
true, def.liquids_pointable)
|
||||
|
@ -435,4 +449,4 @@ register_color_tool("epidermis:line", {
|
|||
return actions, color_argb
|
||||
end
|
||||
}
|
||||
end)
|
||||
end)
|
||||
|
|
Loading…
Reference in New Issue