mirror of
https://github.com/minetest/minetest.git
synced 2024-11-27 18:13:46 +01:00
Bypass media transfer in single player
This commit is contained in:
parent
50edb30a18
commit
4d024d737c
@ -29,6 +29,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
#include "util/serialize.h"
|
#include "util/serialize.h"
|
||||||
#include "util/sha1.h"
|
#include "util/sha1.h"
|
||||||
#include "util/string.h"
|
#include "util/string.h"
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
static std::string getMediaCacheDir()
|
static std::string getMediaCacheDir()
|
||||||
{
|
{
|
||||||
@ -41,7 +42,16 @@ bool clientMediaUpdateCache(const std::string &raw_hash, const std::string &file
|
|||||||
std::string sha1_hex = hex_encode(raw_hash);
|
std::string sha1_hex = hex_encode(raw_hash);
|
||||||
if (!media_cache.exists(sha1_hex))
|
if (!media_cache.exists(sha1_hex))
|
||||||
return media_cache.update(sha1_hex, filedata);
|
return media_cache.update(sha1_hex, filedata);
|
||||||
return true;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool clientMediaUpdateCacheCopy(const std::string &raw_hash, const std::string &path)
|
||||||
|
{
|
||||||
|
FileCache media_cache(getMediaCacheDir());
|
||||||
|
std::string sha1_hex = hex_encode(raw_hash);
|
||||||
|
if (!media_cache.exists(sha1_hex))
|
||||||
|
return media_cache.updateCopyFile(sha1_hex, path);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -189,10 +199,6 @@ void ClientMediaDownloader::initialStep(Client *client)
|
|||||||
|
|
||||||
assert(m_uncached_received_count == 0);
|
assert(m_uncached_received_count == 0);
|
||||||
|
|
||||||
// Create the media cache dir if we are likely to write to it
|
|
||||||
if (m_uncached_count != 0)
|
|
||||||
createCacheDirs();
|
|
||||||
|
|
||||||
// If we found all files in the cache, report this fact to the server.
|
// If we found all files in the cache, report this fact to the server.
|
||||||
// If the server reported no remote servers, immediately start
|
// If the server reported no remote servers, immediately start
|
||||||
// conventional transfers. Note: if cURL support is not compiled in,
|
// conventional transfers. Note: if cURL support is not compiled in,
|
||||||
@ -511,18 +517,6 @@ IClientMediaDownloader::IClientMediaDownloader():
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void IClientMediaDownloader::createCacheDirs()
|
|
||||||
{
|
|
||||||
if (!m_write_to_cache)
|
|
||||||
return;
|
|
||||||
|
|
||||||
std::string path = getMediaCacheDir();
|
|
||||||
if (!fs::CreateAllDirs(path)) {
|
|
||||||
errorstream << "Client: Could not create media cache directory: "
|
|
||||||
<< path << std::endl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IClientMediaDownloader::tryLoadFromCache(const std::string &name,
|
bool IClientMediaDownloader::tryLoadFromCache(const std::string &name,
|
||||||
const std::string &sha1, Client *client)
|
const std::string &sha1, Client *client)
|
||||||
{
|
{
|
||||||
@ -726,8 +720,6 @@ void SingleMediaDownloader::initialStep(Client *client)
|
|||||||
if (isDone())
|
if (isDone())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
createCacheDirs();
|
|
||||||
|
|
||||||
// If the server reported no remote servers, immediately fall back to
|
// If the server reported no remote servers, immediately fall back to
|
||||||
// conventional transfer.
|
// conventional transfer.
|
||||||
if (!USE_CURL || m_remotes.empty()) {
|
if (!USE_CURL || m_remotes.empty()) {
|
||||||
|
@ -22,7 +22,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
#include "irrlichttypes.h"
|
#include "irrlichttypes.h"
|
||||||
#include "filecache.h"
|
#include "filecache.h"
|
||||||
#include "util/basic_macros.h"
|
#include "util/basic_macros.h"
|
||||||
#include <ostream>
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@ -35,10 +34,15 @@ struct HTTPFetchResult;
|
|||||||
#define MTHASHSET_FILE_NAME "index.mth"
|
#define MTHASHSET_FILE_NAME "index.mth"
|
||||||
|
|
||||||
// Store file into media cache (unless it exists already)
|
// Store file into media cache (unless it exists already)
|
||||||
// Validating the hash is responsibility of the caller
|
// Caller should check the hash.
|
||||||
|
// return true if something was updated
|
||||||
bool clientMediaUpdateCache(const std::string &raw_hash,
|
bool clientMediaUpdateCache(const std::string &raw_hash,
|
||||||
const std::string &filedata);
|
const std::string &filedata);
|
||||||
|
|
||||||
|
// Copy file on disk(!) into media cache (unless it exists already)
|
||||||
|
bool clientMediaUpdateCacheCopy(const std::string &raw_hash,
|
||||||
|
const std::string &path);
|
||||||
|
|
||||||
// more of a base class than an interface but this name was most convenient...
|
// more of a base class than an interface but this name was most convenient...
|
||||||
class IClientMediaDownloader
|
class IClientMediaDownloader
|
||||||
{
|
{
|
||||||
@ -81,8 +85,6 @@ protected:
|
|||||||
virtual bool loadMedia(Client *client, const std::string &data,
|
virtual bool loadMedia(Client *client, const std::string &data,
|
||||||
const std::string &name) = 0;
|
const std::string &name) = 0;
|
||||||
|
|
||||||
void createCacheDirs();
|
|
||||||
|
|
||||||
bool tryLoadFromCache(const std::string &name, const std::string &sha1,
|
bool tryLoadFromCache(const std::string &name, const std::string &sha1,
|
||||||
Client *client);
|
Client *client);
|
||||||
|
|
||||||
|
@ -28,6 +28,14 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
|
|
||||||
|
void FileCache::createDir()
|
||||||
|
{
|
||||||
|
if (!fs::CreateAllDirs(m_dir)) {
|
||||||
|
errorstream << "Could not create cache directory: "
|
||||||
|
<< m_dir << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool FileCache::loadByPath(const std::string &path, std::ostream &os)
|
bool FileCache::loadByPath(const std::string &path, std::ostream &os)
|
||||||
{
|
{
|
||||||
std::ifstream fis(path.c_str(), std::ios_base::binary);
|
std::ifstream fis(path.c_str(), std::ios_base::binary);
|
||||||
@ -40,8 +48,8 @@ bool FileCache::loadByPath(const std::string &path, std::ostream &os)
|
|||||||
|
|
||||||
bool bad = false;
|
bool bad = false;
|
||||||
for(;;){
|
for(;;){
|
||||||
char buf[1024];
|
char buf[4096];
|
||||||
fis.read(buf, 1024);
|
fis.read(buf, sizeof(buf));
|
||||||
std::streamsize len = fis.gcount();
|
std::streamsize len = fis.gcount();
|
||||||
os.write(buf, len);
|
os.write(buf, len);
|
||||||
if(fis.eof())
|
if(fis.eof())
|
||||||
@ -61,6 +69,7 @@ bool FileCache::loadByPath(const std::string &path, std::ostream &os)
|
|||||||
|
|
||||||
bool FileCache::updateByPath(const std::string &path, const std::string &data)
|
bool FileCache::updateByPath(const std::string &path, const std::string &data)
|
||||||
{
|
{
|
||||||
|
createDir();
|
||||||
std::ofstream file(path.c_str(), std::ios_base::binary |
|
std::ofstream file(path.c_str(), std::ios_base::binary |
|
||||||
std::ios_base::trunc);
|
std::ios_base::trunc);
|
||||||
|
|
||||||
@ -95,3 +104,11 @@ bool FileCache::exists(const std::string &name)
|
|||||||
std::ifstream fis(path.c_str(), std::ios_base::binary);
|
std::ifstream fis(path.c_str(), std::ios_base::binary);
|
||||||
return fis.good();
|
return fis.good();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool FileCache::updateCopyFile(const std::string &name, const std::string &src_path)
|
||||||
|
{
|
||||||
|
std::string path = m_dir + DIR_DELIM + name;
|
||||||
|
|
||||||
|
createDir();
|
||||||
|
return fs::CopyFileContents(src_path, path);
|
||||||
|
}
|
||||||
|
@ -35,9 +35,13 @@ public:
|
|||||||
bool load(const std::string &name, std::ostream &os);
|
bool load(const std::string &name, std::ostream &os);
|
||||||
bool exists(const std::string &name);
|
bool exists(const std::string &name);
|
||||||
|
|
||||||
|
// Copy another file on disk into the cache
|
||||||
|
bool updateCopyFile(const std::string &name, const std::string &src_path);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string m_dir;
|
std::string m_dir;
|
||||||
|
|
||||||
|
void createDir();
|
||||||
bool loadByPath(const std::string &path, std::ostream &os);
|
bool loadByPath(const std::string &path, std::ostream &os);
|
||||||
bool updateByPath(const std::string &path, const std::string &data);
|
bool updateByPath(const std::string &path, const std::string &data);
|
||||||
};
|
};
|
||||||
|
@ -33,6 +33,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
#include "client/mapblock_mesh.h"
|
#include "client/mapblock_mesh.h"
|
||||||
#include "client/sound.h"
|
#include "client/sound.h"
|
||||||
#include "clientmap.h"
|
#include "clientmap.h"
|
||||||
|
#include "clientmedia.h" // For clientMediaUpdateCacheCopy
|
||||||
#include "clouds.h"
|
#include "clouds.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "content_cao.h"
|
#include "content_cao.h"
|
||||||
@ -737,6 +738,7 @@ protected:
|
|||||||
bool initSound();
|
bool initSound();
|
||||||
bool createSingleplayerServer(const std::string &map_dir,
|
bool createSingleplayerServer(const std::string &map_dir,
|
||||||
const SubgameSpec &gamespec, u16 port);
|
const SubgameSpec &gamespec, u16 port);
|
||||||
|
void copyServerClientCache();
|
||||||
|
|
||||||
// Client creation
|
// Client creation
|
||||||
bool createClient(const GameStartData &start_data);
|
bool createClient(const GameStartData &start_data);
|
||||||
@ -1419,9 +1421,31 @@ bool Game::createSingleplayerServer(const std::string &map_dir,
|
|||||||
false, nullptr, error_message);
|
false, nullptr, error_message);
|
||||||
server->start();
|
server->start();
|
||||||
|
|
||||||
|
copyServerClientCache();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Game::copyServerClientCache()
|
||||||
|
{
|
||||||
|
// It would be possible to let the client directly read the media files
|
||||||
|
// from where the server knows they are. But aside from being more complicated
|
||||||
|
// it would also *not* fill the media cache and cause slower joining of
|
||||||
|
// remote servers.
|
||||||
|
// (Imagine that you launch a game once locally and then connect to a server.)
|
||||||
|
|
||||||
|
assert(server);
|
||||||
|
auto map = server->getMediaList();
|
||||||
|
u32 n = 0;
|
||||||
|
for (auto &it : map) {
|
||||||
|
assert(it.first.size() == 20); // SHA1
|
||||||
|
if (clientMediaUpdateCacheCopy(it.first, it.second))
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
infostream << "Copied " << n << " files directly from server to client cache"
|
||||||
|
<< std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
bool Game::createClient(const GameStartData &start_data)
|
bool Game::createClient(const GameStartData &start_data)
|
||||||
{
|
{
|
||||||
showOverlayMessage(N_("Creating client..."), 0, 10);
|
showOverlayMessage(N_("Creating client..."), 0, 10);
|
||||||
|
@ -4081,6 +4081,19 @@ Translations *Server::getTranslationLanguage(const std::string &lang_code)
|
|||||||
return translations;
|
return translations;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::unordered_map<std::string, std::string> Server::getMediaList()
|
||||||
|
{
|
||||||
|
MutexAutoLock env_lock(m_env_mutex);
|
||||||
|
|
||||||
|
std::unordered_map<std::string, std::string> ret;
|
||||||
|
for (auto &it : m_media) {
|
||||||
|
if (it.second.no_announce)
|
||||||
|
continue;
|
||||||
|
ret.emplace(base64_decode(it.second.sha1_digest), it.second.path);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
ModStorageDatabase *Server::openModStorageDatabase(const std::string &world_path)
|
ModStorageDatabase *Server::openModStorageDatabase(const std::string &world_path)
|
||||||
{
|
{
|
||||||
std::string world_mt_path = world_path + DIR_DELIM + "world.mt";
|
std::string world_mt_path = world_path + DIR_DELIM + "world.mt";
|
||||||
|
@ -375,6 +375,10 @@ public:
|
|||||||
// Get or load translations for a language
|
// Get or load translations for a language
|
||||||
Translations *getTranslationLanguage(const std::string &lang_code);
|
Translations *getTranslationLanguage(const std::string &lang_code);
|
||||||
|
|
||||||
|
// Returns all media files the server knows about
|
||||||
|
// map key = binary sha1, map value = file path
|
||||||
|
std::unordered_map<std::string, std::string> getMediaList();
|
||||||
|
|
||||||
static ModStorageDatabase *openModStorageDatabase(const std::string &world_path);
|
static ModStorageDatabase *openModStorageDatabase(const std::string &world_path);
|
||||||
|
|
||||||
static ModStorageDatabase *openModStorageDatabase(const std::string &backend,
|
static ModStorageDatabase *openModStorageDatabase(const std::string &backend,
|
||||||
|
Loading…
Reference in New Issue
Block a user