Compare commits

...

5 Commits

Author SHA1 Message Date
Lars Mueller 30755b164f Fix: Take eye offset into account for raycasts 2022-08-20 16:41:50 +02:00
Lars Mueller 99cb17d6bb Add eraser instructions in Readme 2022-08-20 15:52:17 +02:00
Lars Mueller d83c40b6e9 Delete paintable data on object removal 2022-08-11 15:09:49 +02:00
Lars Mueller 52ae3ae5c5 Add missing title to mod.conf 2022-08-11 15:09:15 +02:00
Lars Mueller b2af386587 Make SkinDB support optional 2022-08-02 20:43:42 +02:00
6 changed files with 130 additions and 73 deletions

View File

@ -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`

View File

@ -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"

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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)