]> git.lizzy.rs Git - minetest.git/commitdiff
Revise dynamic_add_media API to better accomodate future changes
authorsfan5 <sfan5@live.de>
Sat, 30 Jan 2021 13:35:34 +0000 (14:35 +0100)
committersfan5 <sfan5@live.de>
Mon, 1 Feb 2021 22:00:13 +0000 (23:00 +0100)
builtin/game/misc.lua
doc/lua_api.txt
src/script/lua_api/l_server.cpp
src/script/lua_api/l_server.h
src/server.cpp
src/server.h

index 96a0a2dda6284213e5cd2e8b0c59cf67f090d5a6..b8c5e16a9ab5730cd611841dd426bca12cd88c95 100644 (file)
@@ -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
index 18499e15a84c16cec36f040e826a817778474be5..9c2a0f1316c6616ffe94bb07537abf63de96f266 100644 (file)
@@ -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
 ----
index 0ae699c9fba529b0244489c0bf8d18c07c9f8688..78cf4b40335813e53c9af9fc33ab8166251d16bb 100644 (file)
@@ -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);
index 938bfa8ef24fc68426285b341a5a494925ba7b33..2df180b17df39a66ca436d0b8d0c46b34d4a0613 100644 (file)
@@ -71,7 +71,7 @@ class ModApiServer : public ModApiBase
        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);
index 8a86dbd82cba761c5dd9f77f65123a8c9ef69f2d..90496129e29b41aa99d627226f5ae9249c67857d 100644 (file)
@@ -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;
 }
index 7071d2d077f9e91e9454292da5a57102f32b230a..5c143a6575dc7b9b6e26bc41986edc719ac0f8b1 100644 (file)
@@ -257,7 +257,7 @@ class Server : public con::PeerHandler, public MapEventReceiver,
 
        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);