Allow dynamic_add_media at mod load time

This commit is contained in:
sfan5 2024-01-22 20:37:26 +01:00
parent 6c8ae2b72a
commit af69d4f7a9
6 changed files with 50 additions and 21 deletions

3
.gitignore vendored

@ -92,11 +92,8 @@ cmake_install.cmake
CMakeCache.txt CMakeCache.txt
CPackConfig.cmake CPackConfig.cmake
CPackSourceConfig.cmake CPackSourceConfig.cmake
src/test_config.h
src/cmake_config.h src/cmake_config.h
src/cmake_config_githash.h src/cmake_config_githash.h
src/unittest/test_world/world.mt
games/devtest/mods/testnodes/textures/testnodes_generated_*.png
/locale/ /locale/
.directory .directory
*.cbp *.cbp

@ -35,6 +35,7 @@ core.features = {
wallmounted_rotate = true, wallmounted_rotate = true,
item_specific_pointabilities = true, item_specific_pointabilities = true,
blocking_pointability_type = true, blocking_pointability_type = true,
dynamic_add_media_startup = true,
} }
function core.has_feature(arg) function core.has_feature(arg)

@ -5304,6 +5304,8 @@ Utilities
item_specific_pointabilities = true, item_specific_pointabilities = true,
-- Nodes `pointable` property can be `"blocking"` (5.9.0) -- Nodes `pointable` property can be `"blocking"` (5.9.0)
blocking_pointability_type = true, blocking_pointability_type = true,
-- dynamic_add_media can be called at startup when leaving callback as `nil` (5.9.0)
dynamic_add_media_startup = true,
} }
``` ```
@ -6621,6 +6623,9 @@ Server
name twice is not possible/guaranteed to work. An exception to this is the name twice is not possible/guaranteed to work. An exception to this is the
use of `to_player` to send the same, already existent file to multiple use of `to_player` to send the same, already existent file to multiple
chosen players. chosen players.
* You can also call this at startup time. In that case `callback` MUST
be `nil` and you cannot use `ephemeral` or `to_player`, as these logically
do not make sense.
* Clients will attempt to fetch files added this way via remote media, * Clients will attempt to fetch files added this way via remote media,
this can make transfer of bigger files painless (if set up). Nevertheless this can make transfer of bigger files painless (if set up). Nevertheless
it is advised not to use dynamic media for big media files. it is advised not to use dynamic media for big media files.

@ -149,15 +149,25 @@ fractal = nil
frac_emb = nil frac_emb = nil
checker = nil checker = nil
local textures_path = minetest.get_modpath( minetest.get_current_modname() ) .. "/textures/" do
minetest.safe_file_write( -- we used to write the textures to our mod folder. in order to avoid
-- duplicate errors delete them if they still exist.
local path = core.get_modpath(core.get_current_modname()) .. "/textures/"
os.remove(path .. "testnodes_generated_mb.png")
os.remove(path .. "testnodes_generated_ck.png")
end
local textures_path = core.get_worldpath() .. "/"
core.safe_file_write(
textures_path .. "testnodes_generated_mb.png", textures_path .. "testnodes_generated_mb.png",
encode_and_check(512, 512, "rgb", data_mb) encode_and_check(512, 512, "rgb", data_mb)
) )
minetest.safe_file_write( core.safe_file_write(
textures_path .. "testnodes_generated_ck.png", textures_path .. "testnodes_generated_ck.png",
encode_and_check(512, 512, "gray", data_ck) encode_and_check(512, 512, "gray", data_ck)
) )
core.dynamic_add_media(textures_path .. "testnodes_generated_mb.png")
core.dynamic_add_media(textures_path .. "testnodes_generated_ck.png")
minetest.register_node("testnodes:generated_png_mb", { minetest.register_node("testnodes:generated_png_mb", {
description = S("Generated Mandelbrot PNG Test Node"), description = S("Generated Mandelbrot PNG Test Node"),

@ -545,9 +545,8 @@ int ModApiServer::l_dynamic_add_media(lua_State *L)
{ {
NO_MAP_LOCK_REQUIRED; NO_MAP_LOCK_REQUIRED;
if (!getEnv(L))
throw LuaError("Dynamic media cannot be added before server has started up");
Server *server = getServer(L); Server *server = getServer(L);
const bool at_startup = !getEnv(L);
std::string filepath; std::string filepath;
std::string to_player; std::string to_player;
@ -562,7 +561,16 @@ int ModApiServer::l_dynamic_add_media(lua_State *L)
} }
if (filepath.empty()) if (filepath.empty())
luaL_typerror(L, 1, "non-empty string"); luaL_typerror(L, 1, "non-empty string");
luaL_checktype(L, 2, LUA_TFUNCTION); if (at_startup) {
if (!lua_isnoneornil(L, 2))
throw LuaError("must be called without callback at load-time");
// In order to keep edge cases to a minimum actually use an empty function.
int err = luaL_loadstring(L, "");
SANITY_CHECK(err == 0);
lua_replace(L, 2);
} else {
luaL_checktype(L, 2, LUA_TFUNCTION);
}
CHECK_SECURE_PATH(L, filepath.c_str(), false); CHECK_SECURE_PATH(L, filepath.c_str(), false);

@ -3582,6 +3582,13 @@ bool Server::dynamicAddMedia(std::string filepath,
} }
} }
if (!m_env && (!to_player.empty() || ephemeral)) {
errorstream << "Server::dynamicAddMedia(): "
"adding ephemeral or player-specific media at startup is nonsense"
<< std::endl;
return false;
}
// Load the file and add it to our media cache // Load the file and add it to our media cache
std::string filedata, raw_hash; std::string filedata, raw_hash;
bool ok = addMediaFile(filename, filepath, &filedata, &raw_hash); bool ok = addMediaFile(filename, filepath, &filedata, &raw_hash);
@ -3618,19 +3625,20 @@ bool Server::dynamicAddMedia(std::string filepath,
m_media[filename].no_announce = true; m_media[filename].no_announce = true;
} }
// Push file to existing clients
NetworkPacket pkt(TOCLIENT_MEDIA_PUSH, 0);
pkt << raw_hash << filename << (bool)ephemeral;
NetworkPacket legacy_pkt = pkt;
// Newer clients get asked to fetch the file (asynchronous)
pkt << token;
// Older clients have an awful hack that just throws the data at them
legacy_pkt.putLongString(filedata);
std::unordered_set<session_t> delivered, waiting; std::unordered_set<session_t> delivered, waiting;
{
// Push file to existing clients
if (m_env) {
NetworkPacket pkt(TOCLIENT_MEDIA_PUSH, 0);
pkt << raw_hash << filename << static_cast<bool>(ephemeral);
NetworkPacket legacy_pkt = pkt;
// Newer clients get asked to fetch the file (asynchronous)
pkt << token;
// Older clients have an awful hack that just throws the data at them
legacy_pkt.putLongString(filedata);
ClientInterface::AutoLock clientlock(m_clients); ClientInterface::AutoLock clientlock(m_clients);
for (auto &pair : m_clients.getClientList()) { for (auto &pair : m_clients.getClientList()) {
if (pair.second->getState() == CS_DefinitionsSent && !ephemeral) { if (pair.second->getState() == CS_DefinitionsSent && !ephemeral) {