Revise dynamic_add_media API to better accomodate future changes

This commit is contained in:
sfan5 2021-01-30 14:35:34 +01:00
parent a01a02f7a1
commit 40ad976753
6 changed files with 68 additions and 22 deletions

@ -266,3 +266,26 @@ end
function core.cancel_shutdown_requests()
core.request_shutdown("", false, -1)
end
-- Callback handling for dynamic_add_media
local dynamic_add_media_raw = core.dynamic_add_media_raw
core.dynamic_add_media_raw = nil
function core.dynamic_add_media(filepath, callback)
local ret = dynamic_add_media_raw(filepath)
if ret == false then
return ret
end
if callback == nil then
core.log("deprecated", "Calling minetest.dynamic_add_media without "..
"a callback is deprecated and will stop working in future versions.")
else
-- At the moment async loading is not actually implemented, so we
-- immediately call the callback ourselves
for _, name in ipairs(ret) do
callback(name)
end
end
return true
end

@ -5446,20 +5446,22 @@ Server
* Returns a code (0: successful, 1: no such player, 2: player is connected)
* `minetest.remove_player_auth(name)`: remove player authentication data
* Returns boolean indicating success (false if player nonexistant)
* `minetest.dynamic_add_media(filepath)`
* Adds the file at the given path to the media sent to clients by the server
on startup and also pushes this file to already connected clients.
* `minetest.dynamic_add_media(filepath, callback)`
* `filepath`: path to a media file on the filesystem
* `callback`: function with arguments `name`, where name is a player name
(previously there was no callback argument; omitting it is deprecated)
* Adds the file to the media sent to clients by the server on startup
and also pushes this file to already connected clients.
The file must be a supported image, sound or model format. It must not be
modified, deleted, moved or renamed after calling this function.
The list of dynamically added media is not persisted.
* Returns boolean indicating success (duplicate files count as error)
* The media will be ready to use (in e.g. entity textures, sound_play)
immediately after calling this function.
* Returns false on error, true if the request was accepted
* The given callback will be called for every player as soon as the
media is available on the client.
Old clients that lack support for this feature will not see the media
unless they reconnect to the server.
* Since media transferred this way does not use client caching or HTTP
transfers, dynamic media should not be used with big files or performance
will suffer.
unless they reconnect to the server. (callback won't be called)
* Since media transferred this way currently does not use client caching
or HTTP transfers, dynamic media should not be used with big files.
Bans
----

@ -452,19 +452,30 @@ int ModApiServer::l_sound_fade(lua_State *L)
}
// dynamic_add_media(filepath)
int ModApiServer::l_dynamic_add_media(lua_State *L)
int ModApiServer::l_dynamic_add_media_raw(lua_State *L)
{
NO_MAP_LOCK_REQUIRED;
// Reject adding media before the server has started up
if (!getEnv(L))
throw LuaError("Dynamic media cannot be added before server has started up");
std::string filepath = readParam<std::string>(L, 1);
CHECK_SECURE_PATH(L, filepath.c_str(), false);
bool ok = getServer(L)->dynamicAddMedia(filepath);
lua_pushboolean(L, ok);
std::vector<RemotePlayer*> sent_to;
bool ok = getServer(L)->dynamicAddMedia(filepath, sent_to);
if (ok) {
// (see wrapper code in builtin)
lua_createtable(L, sent_to.size(), 0);
int i = 0;
for (RemotePlayer *player : sent_to) {
lua_pushstring(L, player->getName());
lua_rawseti(L, -2, ++i);
}
} else {
lua_pushboolean(L, false);
}
return 1;
}
@ -532,7 +543,7 @@ void ModApiServer::Initialize(lua_State *L, int top)
API_FCT(sound_play);
API_FCT(sound_stop);
API_FCT(sound_fade);
API_FCT(dynamic_add_media);
API_FCT(dynamic_add_media_raw);
API_FCT(get_player_information);
API_FCT(get_player_privs);

@ -71,7 +71,7 @@ private:
static int l_sound_fade(lua_State *L);
// dynamic_add_media(filepath)
static int l_dynamic_add_media(lua_State *L);
static int l_dynamic_add_media_raw(lua_State *L);
// get_player_privs(name, text)
static int l_get_player_privs(lua_State *L);

@ -3465,7 +3465,8 @@ void Server::deleteParticleSpawner(const std::string &playername, u32 id)
SendDeleteParticleSpawner(peer_id, id);
}
bool Server::dynamicAddMedia(const std::string &filepath)
bool Server::dynamicAddMedia(const std::string &filepath,
std::vector<RemotePlayer*> &sent_to)
{
std::string filename = fs::GetFilenameFromPath(filepath.c_str());
if (m_media.find(filename) != m_media.end()) {
@ -3485,9 +3486,17 @@ bool Server::dynamicAddMedia(const std::string &filepath)
pkt << raw_hash << filename << (bool) true;
pkt.putLongString(filedata);
auto client_ids = m_clients.getClientIDs(CS_DefinitionsSent);
for (session_t client_id : client_ids) {
m_clients.lock();
for (auto &pair : m_clients.getClientList()) {
if (pair.second->getState() < CS_DefinitionsSent)
continue;
if (pair.second->net_proto_version < 39)
continue;
if (auto player = m_env->getPlayer(pair.second->peer_id))
sent_to.emplace_back(player);
/*
FIXME: this is a very awful hack
The network layer only guarantees ordered delivery inside a channel.
Since the very next packet could be one that uses the media, we have
to push the media over ALL channels to ensure it is processed before
@ -3496,9 +3505,10 @@ bool Server::dynamicAddMedia(const std::string &filepath)
- channel 1 (HUD)
- channel 0 (everything else: e.g. play_sound, object messages)
*/
m_clients.send(client_id, 1, &pkt, true);
m_clients.send(client_id, 0, &pkt, true);
m_clients.send(pair.second->peer_id, 1, &pkt, true);
m_clients.send(pair.second->peer_id, 0, &pkt, true);
}
m_clients.unlock();
return true;
}

@ -257,7 +257,7 @@ public:
void deleteParticleSpawner(const std::string &playername, u32 id);
bool dynamicAddMedia(const std::string &filepath);
bool dynamicAddMedia(const std::string &filepath, std::vector<RemotePlayer*> &sent_to);
ServerInventoryManager *getInventoryMgr() const { return m_inventory_mgr.get(); }
void sendDetachedInventory(Inventory *inventory, const std::string &name, session_t peer_id);