Skip to content
Browse files
Dynamic_Add_Media v2 (#11550)
  • Loading branch information
sfan5 committed Sep 9, 2021
1 parent bcb6565 commit bbfae0cc673d3abdc21224c53e09b209ee4688a2
@@ -269,27 +269,8 @@ function core.cancel_shutdown_requests()

-- 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
if callback == nil then
core.log("deprecated", "Calling minetest.dynamic_add_media without "..
"a callback is deprecated and will stop working in future versions.")
-- At the moment async loading is not actually implemented, so we
-- immediately call the callback ourselves
for _, name in ipairs(ret) do
return true
-- Used for callback handling with dynamic_add_media
core.dynamic_media_callbacks = {}

-- PNG encoder safety wrapper
@@ -5649,22 +5649,33 @@ 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, 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.
* `minetest.dynamic_add_media(options, callback)`
* `options`: table containing the following parameters
* `filepath`: path to a media file on the filesystem
* `to_player`: name of the player the media should be sent to instead of
all players (optional)
* `ephemeral`: boolean that marks the media as ephemeral,
it will not be cached on the client (optional, default false)
* `callback`: function with arguments `name`, which is a player name
* Pushes the specified media file to client(s). (details below)
The file must be a supported image, sound or model format.
Dynamically added media is not persisted between server restarts.
* 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. (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.
* Details/Notes:
* If `ephemeral`=false and `to_player` is unset the file is added to the media
sent to clients on startup, this means the media will appear even on
old clients if they rejoin the server.
* If `ephemeral`=false the file must not be modified, deleted, moved or
renamed after calling this function.
* Regardless of any use of `ephemeral`, adding media files with the same
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.
* 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.

@@ -555,6 +555,29 @@ void Client::step(float dtime)
m_media_downloader = NULL;
// Acknowledge dynamic media downloads to server
std::vector<u32> done;
for (auto it = m_pending_media_downloads.begin();
it != m_pending_media_downloads.end();) {
if (it->second->isDone()) {

it = m_pending_media_downloads.erase(it);
} else {

if (done.size() == 255) { // maximum in one packet
if (!done.empty())

If the server didn't update the inventory in a while, revert
@@ -770,7 +793,8 @@ void Client::request_media(const std::vector<std::string> &file_requests)

infostream << "Client: Sending media request list to server ("
<< file_requests.size() << " files. packet size)" << std::endl;
<< file_requests.size() << " files, packet size "
<< pkt.getSize() << ")" << std::endl;

void Client::initLocalMapSaving(const Address &address,
@@ -1295,6 +1319,19 @@ void Client::sendPlayerPos()

void Client::sendHaveMedia(const std::vector<u32> &tokens)
NetworkPacket pkt(TOSERVER_HAVE_MEDIA, 1 + tokens.size() * 4);

sanity_check(tokens.size() < 256);

pkt << static_cast<u8>(tokens.size());
for (u32 token : tokens)
pkt << token;


void Client::removeNode(v3s16 p)
std::map<v3s16, MapBlock*> modified_blocks;
@@ -53,6 +53,7 @@ class ISoundManager;
class NodeDefManager;
//class IWritableCraftDefManager;
class ClientMediaDownloader;
class SingleMediaDownloader;
struct MapDrawControl;
class ModChannelMgr;
class MtEventManager;
@@ -245,6 +246,7 @@ class Client : public con::PeerHandler, public InventoryManager, public IGameDef
void sendDamage(u16 damage);
void sendRespawn();
void sendReady();
void sendHaveMedia(const std::vector<u32> &tokens);

ClientEnvironment& getEnv() { return m_env; }
ITextureSource *tsrc() { return getTextureSource(); }
@@ -536,9 +538,13 @@ class Client : public con::PeerHandler, public InventoryManager, public IGameDef
bool m_activeobjects_received = false;
bool m_mods_loaded = false;

std::vector<std::string> m_remote_media_servers;
// Media downloader, only exists during init
ClientMediaDownloader *m_media_downloader;
// Set of media filenames pushed by server at runtime
std::unordered_set<std::string> m_media_pushed_files;
// Pending downloads of dynamic media (key: token)
std::vector<std::pair<u32, std::unique_ptr<SingleMediaDownloader>>> m_pending_media_downloads;

// time_of_day speed approximation for old protocol
bool m_time_of_day_set = false;

0 comments on commit bbfae0c

Please sign in to comment.