Skip to content

Commit 2424dfe

Browse files
authoredJun 13, 2020
Server pushing media at runtime (#9961)
1 parent 982a030 commit 2424dfe

16 files changed

+263
-85
lines changed
 

Diff for: ‎doc/lua_api.txt

+14
Original file line numberDiff line numberDiff line change
@@ -5217,6 +5217,20 @@ Server
52175217
* Returns a code (0: successful, 1: no such player, 2: player is connected)
52185218
* `minetest.remove_player_auth(name)`: remove player authentication data
52195219
* Returns boolean indicating success (false if player nonexistant)
5220+
* `minetest.dynamic_add_media(filepath)`
5221+
* Adds the file at the given path to the media sent to clients by the server
5222+
on startup and also pushes this file to already connected clients.
5223+
The file must be a supported image, sound or model format. It must not be
5224+
modified, deleted, moved or renamed after calling this function.
5225+
The list of dynamically added media is not persisted.
5226+
* Returns boolean indicating success (duplicate files count as error)
5227+
* The media will be ready to use (in e.g. entity textures, sound_play)
5228+
immediately after calling this function.
5229+
Old clients that lack support for this feature will not see the media
5230+
unless they reconnect to the server.
5231+
* Since media transferred this way does not use client caching or HTTP
5232+
transfers, dynamic media should not be used with big files or performance
5233+
will suffer.
52205234

52215235
Bans
52225236
----

Diff for: ‎src/client/client.cpp

+7-5
Original file line numberDiff line numberDiff line change
@@ -670,11 +670,9 @@ void Client::step(float dtime)
670670
}
671671
}
672672

673-
bool Client::loadMedia(const std::string &data, const std::string &filename)
673+
bool Client::loadMedia(const std::string &data, const std::string &filename,
674+
bool from_media_push)
674675
{
675-
// Silly irrlicht's const-incorrectness
676-
Buffer<char> data_rw(data.c_str(), data.size());
677-
678676
std::string name;
679677

680678
const char *image_ext[] = {
@@ -690,6 +688,9 @@ bool Client::loadMedia(const std::string &data, const std::string &filename)
690688
io::IFileSystem *irrfs = RenderingEngine::get_filesystem();
691689
video::IVideoDriver *vdrv = RenderingEngine::get_video_driver();
692690

691+
// Silly irrlicht's const-incorrectness
692+
Buffer<char> data_rw(data.c_str(), data.size());
693+
693694
// Create an irrlicht memory file
694695
io::IReadFile *rfile = irrfs->createMemoryReadFile(
695696
*data_rw, data_rw.getSize(), "_tempreadfile");
@@ -727,7 +728,6 @@ bool Client::loadMedia(const std::string &data, const std::string &filename)
727728
".x", ".b3d", ".md2", ".obj",
728729
NULL
729730
};
730-
731731
name = removeStringEnd(filename, model_ext);
732732
if (!name.empty()) {
733733
verbosestream<<"Client: Storing model into memory: "
@@ -744,6 +744,8 @@ bool Client::loadMedia(const std::string &data, const std::string &filename)
744744
};
745745
name = removeStringEnd(filename, translate_ext);
746746
if (!name.empty()) {
747+
if (from_media_push)
748+
return false;
747749
TRACESTREAM(<< "Client: Loading translation: "
748750
<< "\"" << filename << "\"" << std::endl);
749751
g_client_translations->loadTranslation(data);

Diff for: ‎src/client/client.h

+7-2
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,7 @@ class Client : public con::PeerHandler, public InventoryManager, public IGameDef
222222
void handleCommand_FormspecPrepend(NetworkPacket *pkt);
223223
void handleCommand_CSMRestrictionFlags(NetworkPacket *pkt);
224224
void handleCommand_PlayerSpeed(NetworkPacket *pkt);
225+
void handleCommand_MediaPush(NetworkPacket *pkt);
225226

226227
void ProcessData(NetworkPacket *pkt);
227228

@@ -376,7 +377,8 @@ class Client : public con::PeerHandler, public InventoryManager, public IGameDef
376377

377378
// The following set of functions is used by ClientMediaDownloader
378379
// Insert a media file appropriately into the appropriate manager
379-
bool loadMedia(const std::string &data, const std::string &filename);
380+
bool loadMedia(const std::string &data, const std::string &filename,
381+
bool from_media_push = false);
380382
// Send a request for conventional media transfer
381383
void request_media(const std::vector<std::string> &file_requests);
382384

@@ -488,6 +490,7 @@ class Client : public con::PeerHandler, public InventoryManager, public IGameDef
488490
Camera *m_camera = nullptr;
489491
Minimap *m_minimap = nullptr;
490492
bool m_minimap_disabled_by_server = false;
493+
491494
// Server serialization version
492495
u8 m_server_ser_ver;
493496

@@ -529,7 +532,6 @@ class Client : public con::PeerHandler, public InventoryManager, public IGameDef
529532
AuthMechanism m_chosen_auth_mech;
530533
void *m_auth_data = nullptr;
531534

532-
533535
bool m_access_denied = false;
534536
bool m_access_denied_reconnect = false;
535537
std::string m_access_denied_reason = "";
@@ -538,7 +540,10 @@ class Client : public con::PeerHandler, public InventoryManager, public IGameDef
538540
bool m_nodedef_received = false;
539541
bool m_activeobjects_received = false;
540542
bool m_mods_loaded = false;
543+
541544
ClientMediaDownloader *m_media_downloader;
545+
// Set of media filenames pushed by server at runtime
546+
std::unordered_set<std::string> m_media_pushed_files;
542547

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

Diff for: ‎src/client/clientmedia.cpp

+9-1
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,15 @@ static std::string getMediaCacheDir()
3535
return porting::path_cache + DIR_DELIM + "media";
3636
}
3737

38+
bool clientMediaUpdateCache(const std::string &raw_hash, const std::string &filedata)
39+
{
40+
FileCache media_cache(getMediaCacheDir());
41+
std::string sha1_hex = hex_encode(raw_hash);
42+
if (!media_cache.exists(sha1_hex))
43+
return media_cache.update(sha1_hex, filedata);
44+
return true;
45+
}
46+
3847
/*
3948
ClientMediaDownloader
4049
*/
@@ -559,7 +568,6 @@ bool ClientMediaDownloader::checkAndLoad(
559568
return true;
560569
}
561570

562-
563571
/*
564572
Minetest Hashset File Format
565573

Diff for: ‎src/client/clientmedia.h

+5
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,11 @@ struct HTTPFetchResult;
3333
#define MTHASHSET_FILE_SIGNATURE 0x4d544853 // 'MTHS'
3434
#define MTHASHSET_FILE_NAME "index.mth"
3535

36+
// Store file into media cache (unless it exists already)
37+
// Validating the hash is responsibility of the caller
38+
bool clientMediaUpdateCache(const std::string &raw_hash,
39+
const std::string &filedata);
40+
3641
class ClientMediaDownloader
3742
{
3843
public:

Diff for: ‎src/client/filecache.cpp

+8
Original file line numberDiff line numberDiff line change
@@ -82,8 +82,16 @@ bool FileCache::update(const std::string &name, const std::string &data)
8282
std::string path = m_dir + DIR_DELIM + name;
8383
return updateByPath(path, data);
8484
}
85+
8586
bool FileCache::load(const std::string &name, std::ostream &os)
8687
{
8788
std::string path = m_dir + DIR_DELIM + name;
8889
return loadByPath(path, os);
8990
}
91+
92+
bool FileCache::exists(const std::string &name)
93+
{
94+
std::string path = m_dir + DIR_DELIM + name;
95+
std::ifstream fis(path.c_str(), std::ios_base::binary);
96+
return fis.good();
97+
}

Diff for: ‎src/client/filecache.h

+1
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ class FileCache
3333

3434
bool update(const std::string &name, const std::string &data);
3535
bool load(const std::string &name, std::ostream &os);
36+
bool exists(const std::string &name);
3637

3738
private:
3839
std::string m_dir;

Diff for: ‎src/filesys.cpp

+6
Original file line numberDiff line numberDiff line change
@@ -691,6 +691,12 @@ std::string AbsolutePath(const std::string &path)
691691
const char *GetFilenameFromPath(const char *path)
692692
{
693693
const char *filename = strrchr(path, DIR_DELIM_CHAR);
694+
// Consistent with IsDirDelimiter this function handles '/' too
695+
if (DIR_DELIM_CHAR != '/') {
696+
const char *tmp = strrchr(path, '/');
697+
if (tmp && tmp > filename)
698+
filename = tmp;
699+
}
694700
return filename ? filename + 1 : path;
695701
}
696702

Diff for: ‎src/network/clientopcodes.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ const ToClientCommandHandler toClientCommandTable[TOCLIENT_NUM_MSG_TYPES] =
6868
{ "TOCLIENT_TIME_OF_DAY", TOCLIENT_STATE_CONNECTED, &Client::handleCommand_TimeOfDay }, // 0x29
6969
{ "TOCLIENT_CSM_RESTRICTION_FLAGS", TOCLIENT_STATE_CONNECTED, &Client::handleCommand_CSMRestrictionFlags }, // 0x2A
7070
{ "TOCLIENT_PLAYER_SPEED", TOCLIENT_STATE_CONNECTED, &Client::handleCommand_PlayerSpeed }, // 0x2B
71-
null_command_handler,
71+
{ "TOCLIENT_MEDIA_PUSH", TOCLIENT_STATE_CONNECTED, &Client::handleCommand_MediaPush }, // 0x2C
7272
null_command_handler,
7373
null_command_handler,
7474
{ "TOCLIENT_CHAT_MESSAGE", TOCLIENT_STATE_CONNECTED, &Client::handleCommand_ChatMessage }, // 0x2F

Diff for: ‎src/network/clientpackethandler.cpp

+46
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
3939
#include "script/scripting_client.h"
4040
#include "util/serialize.h"
4141
#include "util/srp.h"
42+
#include "util/sha1.h"
4243
#include "tileanimation.h"
4344
#include "gettext.h"
4445
#include "skyparams.h"
@@ -1471,6 +1472,51 @@ void Client::handleCommand_PlayerSpeed(NetworkPacket *pkt)
14711472
player->addVelocity(added_vel);
14721473
}
14731474

1475+
void Client::handleCommand_MediaPush(NetworkPacket *pkt)
1476+
{
1477+
std::string raw_hash, filename, filedata;
1478+
bool cached;
1479+
1480+
*pkt >> raw_hash >> filename >> cached;
1481+
filedata = pkt->readLongString();
1482+
1483+
if (raw_hash.size() != 20 || filedata.empty() || filename.empty() ||
1484+
!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)) {
1485+
throw PacketError("Illegal filename, data or hash");
1486+
}
1487+
1488+
verbosestream << "Server pushes media file \"" << filename << "\" with "
1489+
<< filedata.size() << " bytes of data (cached=" << cached
1490+
<< ")" << std::endl;
1491+
1492+
if (m_media_pushed_files.count(filename) != 0) {
1493+
// Silently ignore for synchronization purposes
1494+
return;
1495+
}
1496+
1497+
// Compute and check checksum of data
1498+
std::string computed_hash;
1499+
{
1500+
SHA1 ctx;
1501+
ctx.addBytes(filedata.c_str(), filedata.size());
1502+
unsigned char *buf = ctx.getDigest();
1503+
computed_hash.assign((char*) buf, 20);
1504+
free(buf);
1505+
}
1506+
if (raw_hash != computed_hash) {
1507+
verbosestream << "Hash of file data mismatches, ignoring." << std::endl;
1508+
return;
1509+
}
1510+
1511+
// Actually load media
1512+
loadMedia(filedata, filename, true);
1513+
m_media_pushed_files.insert(filename);
1514+
1515+
// Cache file for the next time when this client joins the same server
1516+
if (cached)
1517+
clientMediaUpdateCache(raw_hash, filedata);
1518+
}
1519+
14741520
/*
14751521
* Mod channels
14761522
*/

Diff for: ‎src/network/networkprotocol.h

+9
Original file line numberDiff line numberDiff line change
@@ -323,6 +323,15 @@ enum ToClientCommand
323323
v3f added_vel
324324
*/
325325

326+
TOCLIENT_MEDIA_PUSH = 0x2C,
327+
/*
328+
std::string raw_hash
329+
std::string filename
330+
bool should_be_cached
331+
u32 len
332+
char filedata[len]
333+
*/
334+
326335
// (oops, there is some gap here)
327336

328337
TOCLIENT_CHAT_MESSAGE = 0x2F,

Diff for: ‎src/network/serveropcodes.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ const ClientCommandFactory clientCommandFactoryTable[TOCLIENT_NUM_MSG_TYPES] =
167167
{ "TOCLIENT_TIME_OF_DAY", 0, true }, // 0x29
168168
{ "TOCLIENT_CSM_RESTRICTION_FLAGS", 0, true }, // 0x2A
169169
{ "TOCLIENT_PLAYER_SPEED", 0, true }, // 0x2B
170-
null_command_factory, // 0x2C
170+
{ "TOCLIENT_MEDIA_PUSH", 0, true }, // 0x2C (sent over channel 1 too)
171171
null_command_factory, // 0x2D
172172
null_command_factory, // 0x2E
173173
{ "TOCLIENT_CHAT_MESSAGE", 0, true }, // 0x2F

Diff for: ‎src/script/lua_api/l_server.cpp

+19-3
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
2222
#include "common/c_converter.h"
2323
#include "common/c_content.h"
2424
#include "cpp_api/s_base.h"
25+
#include "cpp_api/s_security.h"
2526
#include "server.h"
2627
#include "environment.h"
2728
#include "remoteplayer.h"
@@ -412,9 +413,6 @@ int ModApiServer::l_get_modnames(lua_State *L)
412413
std::vector<std::string> modlist;
413414
getServer(L)->getModNames(modlist);
414415

415-
// Take unsorted items from mods_unsorted and sort them into
416-
// mods_sorted; not great performance but the number of mods on a
417-
// server will likely be small.
418416
std::sort(modlist.begin(), modlist.end());
419417

420418
// Package them up for Lua
@@ -474,6 +472,23 @@ int ModApiServer::l_sound_fade(lua_State *L)
474472
return 0;
475473
}
476474

475+
// dynamic_add_media(filepath)
476+
int ModApiServer::l_dynamic_add_media(lua_State *L)
477+
{
478+
NO_MAP_LOCK_REQUIRED;
479+
480+
// Reject adding media before the server has started up
481+
if (!getEnv(L))
482+
throw LuaError("Dynamic media cannot be added before server has started up");
483+
484+
std::string filepath = readParam<std::string>(L, 1);
485+
CHECK_SECURE_PATH(L, filepath.c_str(), false);
486+
487+
bool ok = getServer(L)->dynamicAddMedia(filepath);
488+
lua_pushboolean(L, ok);
489+
return 1;
490+
}
491+
477492
// is_singleplayer()
478493
int ModApiServer::l_is_singleplayer(lua_State *L)
479494
{
@@ -538,6 +553,7 @@ void ModApiServer::Initialize(lua_State *L, int top)
538553
API_FCT(sound_play);
539554
API_FCT(sound_stop);
540555
API_FCT(sound_fade);
556+
API_FCT(dynamic_add_media);
541557

542558
API_FCT(get_player_information);
543559
API_FCT(get_player_privs);

Diff for: ‎src/script/lua_api/l_server.h

+3
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,9 @@ class ModApiServer : public ModApiBase
7070
// sound_fade(handle, step, gain)
7171
static int l_sound_fade(lua_State *L);
7272

73+
// dynamic_add_media(filepath)
74+
static int l_dynamic_add_media(lua_State *L);
75+
7376
// get_player_privs(name, text)
7477
static int l_get_player_privs(lua_State *L);
7578

Diff for: ‎src/server.cpp

+123-72
Original file line numberDiff line numberDiff line change
@@ -2405,9 +2405,87 @@ bool Server::SendBlock(session_t peer_id, const v3s16 &blockpos)
24052405
return true;
24062406
}
24072407

2408+
bool Server::addMediaFile(const std::string &filename,
2409+
const std::string &filepath, std::string *filedata_to,
2410+
std::string *digest_to)
2411+
{
2412+
// If name contains illegal characters, ignore the file
2413+
if (!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)) {
2414+
infostream << "Server: ignoring illegal file name: \""
2415+
<< filename << "\"" << std::endl;
2416+
return false;
2417+
}
2418+
// If name is not in a supported format, ignore it
2419+
const char *supported_ext[] = {
2420+
".png", ".jpg", ".bmp", ".tga",
2421+
".pcx", ".ppm", ".psd", ".wal", ".rgb",
2422+
".ogg",
2423+
".x", ".b3d", ".md2", ".obj",
2424+
// Custom translation file format
2425+
".tr",
2426+
NULL
2427+
};
2428+
if (removeStringEnd(filename, supported_ext).empty()) {
2429+
infostream << "Server: ignoring unsupported file extension: \""
2430+
<< filename << "\"" << std::endl;
2431+
return false;
2432+
}
2433+
// Ok, attempt to load the file and add to cache
2434+
2435+
// Read data
2436+
std::ifstream fis(filepath.c_str(), std::ios_base::binary);
2437+
if (!fis.good()) {
2438+
errorstream << "Server::addMediaFile(): Could not open \""
2439+
<< filename << "\" for reading" << std::endl;
2440+
return false;
2441+
}
2442+
std::string filedata;
2443+
bool bad = false;
2444+
for (;;) {
2445+
char buf[1024];
2446+
fis.read(buf, sizeof(buf));
2447+
std::streamsize len = fis.gcount();
2448+
filedata.append(buf, len);
2449+
if (fis.eof())
2450+
break;
2451+
if (!fis.good()) {
2452+
bad = true;
2453+
break;
2454+
}
2455+
}
2456+
if (bad) {
2457+
errorstream << "Server::addMediaFile(): Failed to read \""
2458+
<< filename << "\"" << std::endl;
2459+
return false;
2460+
} else if (filedata.empty()) {
2461+
errorstream << "Server::addMediaFile(): Empty file \""
2462+
<< filepath << "\"" << std::endl;
2463+
return false;
2464+
}
2465+
2466+
SHA1 sha1;
2467+
sha1.addBytes(filedata.c_str(), filedata.length());
2468+
2469+
unsigned char *digest = sha1.getDigest();
2470+
std::string sha1_base64 = base64_encode(digest, 20);
2471+
std::string sha1_hex = hex_encode((char*) digest, 20);
2472+
if (digest_to)
2473+
*digest_to = std::string((char*) digest, 20);
2474+
free(digest);
2475+
2476+
// Put in list
2477+
m_media[filename] = MediaInfo(filepath, sha1_base64);
2478+
verbosestream << "Server: " << sha1_hex << " is " << filename
2479+
<< std::endl;
2480+
2481+
if (filedata_to)
2482+
*filedata_to = std::move(filedata);
2483+
return true;
2484+
}
2485+
24082486
void Server::fillMediaCache()
24092487
{
2410-
infostream<<"Server: Calculating media file checksums"<<std::endl;
2488+
infostream << "Server: Calculating media file checksums" << std::endl;
24112489

24122490
// Collect all media file paths
24132491
std::vector<std::string> paths;
@@ -2419,80 +2497,15 @@ void Server::fillMediaCache()
24192497
for (const std::string &mediapath : paths) {
24202498
std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
24212499
for (const fs::DirListNode &dln : dirlist) {
2422-
if (dln.dir) // Ignode dirs
2423-
continue;
2424-
std::string filename = dln.name;
2425-
// If name contains illegal characters, ignore the file
2426-
if (!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)) {
2427-
infostream<<"Server: ignoring illegal file name: \""
2428-
<< filename << "\"" << std::endl;
2429-
continue;
2430-
}
2431-
// If name is not in a supported format, ignore it
2432-
const char *supported_ext[] = {
2433-
".png", ".jpg", ".bmp", ".tga",
2434-
".pcx", ".ppm", ".psd", ".wal", ".rgb",
2435-
".ogg",
2436-
".x", ".b3d", ".md2", ".obj",
2437-
// Custom translation file format
2438-
".tr",
2439-
NULL
2440-
};
2441-
if (removeStringEnd(filename, supported_ext).empty()){
2442-
infostream << "Server: ignoring unsupported file extension: \""
2443-
<< filename << "\"" << std::endl;
2500+
if (dln.dir) // Ignore dirs
24442501
continue;
2445-
}
2446-
// Ok, attempt to load the file and add to cache
2447-
std::string filepath;
2448-
filepath.append(mediapath).append(DIR_DELIM).append(filename);
2449-
2450-
// Read data
2451-
std::ifstream fis(filepath.c_str(), std::ios_base::binary);
2452-
if (!fis.good()) {
2453-
errorstream << "Server::fillMediaCache(): Could not open \""
2454-
<< filename << "\" for reading" << std::endl;
2455-
continue;
2456-
}
2457-
std::ostringstream tmp_os(std::ios_base::binary);
2458-
bool bad = false;
2459-
for(;;) {
2460-
char buf[1024];
2461-
fis.read(buf, 1024);
2462-
std::streamsize len = fis.gcount();
2463-
tmp_os.write(buf, len);
2464-
if (fis.eof())
2465-
break;
2466-
if (!fis.good()) {
2467-
bad = true;
2468-
break;
2469-
}
2470-
}
2471-
if(bad) {
2472-
errorstream<<"Server::fillMediaCache(): Failed to read \""
2473-
<< filename << "\"" << std::endl;
2474-
continue;
2475-
}
2476-
if(tmp_os.str().length() == 0) {
2477-
errorstream << "Server::fillMediaCache(): Empty file \""
2478-
<< filepath << "\"" << std::endl;
2479-
continue;
2480-
}
2481-
2482-
SHA1 sha1;
2483-
sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
2484-
2485-
unsigned char *digest = sha1.getDigest();
2486-
std::string sha1_base64 = base64_encode(digest, 20);
2487-
std::string sha1_hex = hex_encode((char*)digest, 20);
2488-
free(digest);
2489-
2490-
// Put in list
2491-
m_media[filename] = MediaInfo(filepath, sha1_base64);
2492-
verbosestream << "Server: " << sha1_hex << " is " << filename
2493-
<< std::endl;
2502+
std::string filepath = mediapath;
2503+
filepath.append(DIR_DELIM).append(dln.name);
2504+
addMediaFile(dln.name, filepath);
24942505
}
24952506
}
2507+
2508+
infostream << "Server: " << m_media.size() << " media files collected" << std::endl;
24962509
}
24972510

24982511
void Server::sendMediaAnnouncement(session_t peer_id, const std::string &lang_code)
@@ -3428,6 +3441,44 @@ void Server::deleteParticleSpawner(const std::string &playername, u32 id)
34283441
SendDeleteParticleSpawner(peer_id, id);
34293442
}
34303443

3444+
bool Server::dynamicAddMedia(const std::string &filepath)
3445+
{
3446+
std::string filename = fs::GetFilenameFromPath(filepath.c_str());
3447+
if (m_media.find(filename) != m_media.end()) {
3448+
errorstream << "Server::dynamicAddMedia(): file \"" << filename
3449+
<< "\" already exists in media cache" << std::endl;
3450+
return false;
3451+
}
3452+
3453+
// Load the file and add it to our media cache
3454+
std::string filedata, raw_hash;
3455+
bool ok = addMediaFile(filename, filepath, &filedata, &raw_hash);
3456+
if (!ok)
3457+
return false;
3458+
3459+
// Push file to existing clients
3460+
NetworkPacket pkt(TOCLIENT_MEDIA_PUSH, 0);
3461+
pkt << raw_hash << filename << (bool) true;
3462+
pkt.putLongString(filedata);
3463+
3464+
auto client_ids = m_clients.getClientIDs(CS_DefinitionsSent);
3465+
for (session_t client_id : client_ids) {
3466+
/*
3467+
The network layer only guarantees ordered delivery inside a channel.
3468+
Since the very next packet could be one that uses the media, we have
3469+
to push the media over ALL channels to ensure it is processed before
3470+
it is used.
3471+
In practice this means we have to send it twice:
3472+
- channel 1 (HUD)
3473+
- channel 0 (everything else: e.g. play_sound, object messages)
3474+
*/
3475+
m_clients.send(client_id, 1, &pkt, true);
3476+
m_clients.send(client_id, 0, &pkt, true);
3477+
}
3478+
3479+
return true;
3480+
}
3481+
34313482
// actions: time-reversed list
34323483
// Return value: success/failure
34333484
bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,

Diff for: ‎src/server.h

+4
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,8 @@ class Server : public con::PeerHandler, public MapEventReceiver,
236236

237237
void deleteParticleSpawner(const std::string &playername, u32 id);
238238

239+
bool dynamicAddMedia(const std::string &filepath);
240+
239241
ServerInventoryManager *getInventoryMgr() const { return m_inventory_mgr.get(); }
240242
void sendDetachedInventory(Inventory *inventory, const std::string &name, session_t peer_id);
241243

@@ -435,6 +437,8 @@ class Server : public con::PeerHandler, public MapEventReceiver,
435437
// Sends blocks to clients (locks env and con on its own)
436438
void SendBlocks(float dtime);
437439

440+
bool addMediaFile(const std::string &filename, const std::string &filepath,
441+
std::string *filedata = nullptr, std::string *digest = nullptr);
438442
void fillMediaCache();
439443
void sendMediaAnnouncement(session_t peer_id, const std::string &lang_code);
440444
void sendRequestedMedia(session_t peer_id,

0 commit comments

Comments
 (0)
Please sign in to comment.