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
View File

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

View File

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

View File

@ -5304,6 +5304,8 @@ Utilities
item_specific_pointabilities = true,
-- Nodes `pointable` property can be `"blocking"` (5.9.0)
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
use of `to_player` to send the same, already existent file to multiple
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,
this can make transfer of bigger files painless (if set up). Nevertheless
it is advised not to use dynamic media for big media files.

View File

@ -149,15 +149,25 @@ fractal = nil
frac_emb = nil
checker = nil
local textures_path = minetest.get_modpath( minetest.get_current_modname() ) .. "/textures/"
minetest.safe_file_write(
do
-- 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",
encode_and_check(512, 512, "rgb", data_mb)
)
minetest.safe_file_write(
core.safe_file_write(
textures_path .. "testnodes_generated_ck.png",
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", {
description = S("Generated Mandelbrot PNG Test Node"),

View File

@ -545,9 +545,8 @@ int ModApiServer::l_dynamic_add_media(lua_State *L)
{
NO_MAP_LOCK_REQUIRED;
if (!getEnv(L))
throw LuaError("Dynamic media cannot be added before server has started up");
Server *server = getServer(L);
const bool at_startup = !getEnv(L);
std::string filepath;
std::string to_player;
@ -562,7 +561,16 @@ int ModApiServer::l_dynamic_add_media(lua_State *L)
}
if (filepath.empty())
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);

View File

@ -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
std::string 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;
}
// 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;
{
// 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);
for (auto &pair : m_clients.getClientList()) {
if (pair.second->getState() == CS_DefinitionsSent && !ephemeral) {