#include "filesys.h"
#include "mapblock_mesh.h"
#include "mapblock.h"
+#include "mapsector.h"
#include "minimap.h"
#include "modchannels.h"
#include "content/mods.h"
#include "clientmap.h"
#include "clientmedia.h"
#include "version.h"
+#include "database/database-files.h"
#include "database/database-sqlite3.h"
#include "serialization.h"
#include "guiscalingfilter.h"
#include "game.h"
#include "chatmessage.h"
#include "translation.h"
+#include "content/mod_configuration.h"
extern gui::IGUIEnvironment* guienv;
MtEventManager *event,
RenderingEngine *rendering_engine,
bool ipv6,
- GameUI *game_ui
+ GameUI *game_ui,
+ ELoginRegister allow_login_or_register
):
m_tsrc(tsrc),
m_shsrc(shsrc),
m_sound(sound),
m_event(event),
m_rendering_engine(rendering_engine),
- m_mesh_update_thread(this),
+ m_mesh_update_manager(this),
m_env(
new ClientMap(this, rendering_engine, control, 666),
tsrc, this
m_particle_manager(&m_env),
m_con(new con::Connection(PROTOCOL_ID, 512, CONNECTION_TIMEOUT, ipv6, this)),
m_address_name(address_name),
+ m_allow_login_or_register(allow_login_or_register),
m_server_ser_ver(SER_FMT_VER_INVALID),
m_last_chat_message_sent(time(NULL)),
m_password(password),
// Add local player
m_env.setLocalPlayer(new LocalPlayer(this, playername));
+ // Make the mod storage database and begin the save for later
+ m_mod_storage_database =
+ new ModStorageDatabaseSQLite3(porting::path_user + DIR_DELIM + "client");
+ m_mod_storage_database->beginSave();
+
if (g_settings->getBool("enable_minimap")) {
m_minimap = new Minimap(this);
}
m_cache_save_interval = g_settings->getU16("server_map_save_interval");
+ m_mesh_grid = { g_settings->getU16("client_mesh_chunk") };
+}
+
+void Client::migrateModStorage()
+{
+ std::string mod_storage_dir = porting::path_user + DIR_DELIM + "client";
+ std::string old_mod_storage = mod_storage_dir + DIR_DELIM + "mod_storage";
+ if (fs::IsDir(old_mod_storage)) {
+ infostream << "Migrating client mod storage to SQLite3 database" << std::endl;
+ {
+ ModStorageDatabaseFiles files_db(mod_storage_dir);
+ std::vector<std::string> mod_list;
+ files_db.listMods(&mod_list);
+ for (const std::string &modname : mod_list) {
+ infostream << "Migrating client mod storage for mod " << modname << std::endl;
+ StringMap meta;
+ files_db.getModEntries(modname, &meta);
+ for (const auto &pair : meta) {
+ m_mod_storage_database->setModEntry(modname, pair.first, pair.second);
+ }
+ }
+ }
+ if (!fs::Rename(old_mod_storage, old_mod_storage + ".bak")) {
+ // Execution cannot move forward if the migration does not complete.
+ throw BaseException("Could not finish migrating client mod storage");
+ }
+ infostream << "Finished migration of client mod storage" << std::endl;
+ }
}
void Client::loadMods()
// Load builtin
scanModIntoMemory(BUILTIN_MOD_NAME, getBuiltinLuaPath());
m_script->loadModFromMemory(BUILTIN_MOD_NAME);
+ m_script->checkSetByBuiltin();
+
+ ModConfiguration modconf;
+ {
+ std::unordered_map<std::string, std::string> paths;
+ std::string path_user = porting::path_user + DIR_DELIM + "clientmods";
+ const auto modsPath = getClientModsLuaPath();
+ if (modsPath != path_user) {
+ paths["share"] = modsPath;
+ }
+ paths["mods"] = path_user;
+
+ std::string settings_path = path_user + DIR_DELIM + "mods.conf";
+ modconf.addModsFromConfig(settings_path, paths);
+ modconf.checkConflictsAndDeps();
+ }
- ClientModConfiguration modconf(getClientModsLuaPath());
m_mods = modconf.getMods();
+
// complain about mods with unsatisfied dependencies
if (!modconf.isConsistent()) {
- modconf.printUnsatisfiedModsError();
+ errorstream << modconf.getUnsatisfiedModsError() << std::endl;
return;
}
// Load "mod" scripts
for (const ModSpec &mod : m_mods) {
- if (!string_allowed(mod.name, MODNAME_ALLOWED_CHARS)) {
- throw ModError("Error loading mod \"" + mod.name +
- "\": Mod name does not follow naming conventions: "
- "Only characters [a-z0-9_] are allowed.");
- }
+ mod.checkAndLog();
scanModIntoMemory(mod.name, mod.path);
}
std::string full_path = mod_path + DIR_DELIM + mod_subpath;
std::vector<fs::DirListNode> mod = fs::GetDirListing(full_path);
for (const fs::DirListNode &j : mod) {
+ if (j.name[0] == '.')
+ continue;
+
if (j.dir) {
scanModSubfolder(mod_name, mod_path, mod_subpath + j.name + DIR_DELIM);
continue;
if (m_mods_loaded)
m_script->on_shutdown();
//request all client managed threads to stop
- m_mesh_update_thread.stop();
+ m_mesh_update_manager.stop();
// Save local server map
if (m_localdb) {
infostream << "Local map saving ended." << std::endl;
bool Client::isShutdown()
{
- return m_shutdown || !m_mesh_update_thread.isRunning();
+ return m_shutdown || !m_mesh_update_manager.isRunning();
}
Client::~Client()
deleteAuthData();
- m_mesh_update_thread.stop();
- m_mesh_update_thread.wait();
- while (!m_mesh_update_thread.m_queue_out.empty()) {
- MeshUpdateResult r = m_mesh_update_thread.m_queue_out.pop_frontNoEx();
+ m_mesh_update_manager.stop();
+ m_mesh_update_manager.wait();
+
+ MeshUpdateResult r;
+ while (m_mesh_update_manager.getNextResult(r)) {
+ for (auto block : r.map_blocks)
+ if (block)
+ block->refDrop();
delete r.mesh;
}
-
delete m_inventory_from_server;
// Delete detached inventories
// cleanup 3d model meshes on client shutdown
m_rendering_engine->cleanupMeshCache();
+ guiScalingCacheClear();
+
delete m_minimap;
m_minimap = nullptr;
delete m_media_downloader;
+
+ // Write the changes and delete
+ if (m_mod_storage_database)
+ m_mod_storage_database->endSave();
+ delete m_mod_storage_database;
}
void Client::connect(Address address, bool is_local_server)
initial_step = false;
}
else if(m_state == LC_Created) {
- if (m_is_registration_confirmation_state) {
- // Waiting confirmation
- return;
- }
float &counter = m_connection_reinit_timer;
counter -= dtime;
if(counter <= 0.0) {
if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime)) {
std::vector<v3s16> deleted_blocks;
m_env.getMap().timerUpdate(map_timer_and_unload_dtime,
- g_settings->getFloat("client_unload_unused_data_timeout"),
+ std::max(g_settings->getFloat("client_unload_unused_data_timeout"), 0.0f),
g_settings->getS32("client_mapblock_limit"),
&deleted_blocks);
ClientEvent *event = new ClientEvent();
event->type = CE_PLAYER_DAMAGE;
event->player_damage.amount = damage;
+ event->player_damage.effect = true;
m_client_event_queue.push(event);
}
}
{
int num_processed_meshes = 0;
std::vector<v3s16> blocks_to_ack;
- while (!m_mesh_update_thread.m_queue_out.empty())
+ bool force_update_shadows = false;
+ MeshUpdateResult r;
+ while (m_mesh_update_manager.getNextResult(r))
{
num_processed_meshes++;
- MinimapMapblock *minimap_mapblock = NULL;
+ std::vector<MinimapMapblock*> minimap_mapblocks;
bool do_mapper_update = true;
- MeshUpdateResult r = m_mesh_update_thread.m_queue_out.pop_frontNoEx();
- MapBlock *block = m_env.getMap().getBlockNoCreateNoEx(r.p);
+ MapSector *sector = m_env.getMap().emergeSector(v2s16(r.p.X, r.p.Z));
+
+ MapBlock *block = sector->getBlockNoCreateNoEx(r.p.Y);
+
+ // The block in question is not visible (perhaps it is culled at the server),
+ // create a blank block just to hold the chunk's mesh.
+ // If the block becomes visible later it will replace the blank block.
+ if (!block && r.mesh)
+ block = sector->createBlankBlock(r.p.Y);
+
if (block) {
// Delete the old mesh
delete block->mesh;
block->mesh = nullptr;
if (r.mesh) {
- minimap_mapblock = r.mesh->moveMinimapMapblock();
- if (minimap_mapblock == NULL)
+ minimap_mapblocks = r.mesh->moveMinimapMapblocks();
+ if (minimap_mapblocks.empty())
do_mapper_update = false;
bool is_empty = true;
if (is_empty)
delete r.mesh;
- else
+ else {
// Replace with the new mesh
block->mesh = r.mesh;
+ if (r.urgent)
+ force_update_shadows = true;
+ }
}
} else {
delete r.mesh;
}
- if (m_minimap && do_mapper_update)
- m_minimap->addBlock(r.p, minimap_mapblock);
+ for (auto p : r.solid_sides) {
+ auto block = m_env.getMap().getBlockNoCreateNoEx(p.first);
+ if (block)
+ block->solid_sides = p.second;
+ }
+
+ if (m_minimap && do_mapper_update) {
+ v3s16 ofs;
+
+ // See also mapblock_mesh.cpp for the code that creates the array of minimap blocks.
+ for (ofs.Z = 0; ofs.Z < m_mesh_grid.cell_size; ofs.Z++)
+ for (ofs.Y = 0; ofs.Y < m_mesh_grid.cell_size; ofs.Y++)
+ for (ofs.X = 0; ofs.X < m_mesh_grid.cell_size; ofs.X++) {
+ size_t i = m_mesh_grid.getOffsetIndex(ofs);
+ if (i < minimap_mapblocks.size() && minimap_mapblocks[i])
+ m_minimap->addBlock(r.p + ofs, minimap_mapblocks[i]);
+ }
+ }
- if (r.ack_block_to_server) {
+ for (auto p : r.ack_list) {
if (blocks_to_ack.size() == 255) {
sendGotBlocks(blocks_to_ack);
blocks_to_ack.clear();
}
- blocks_to_ack.emplace_back(r.p);
+ blocks_to_ack.emplace_back(p);
}
+
+ for (auto block : r.map_blocks)
+ if (block)
+ block->refDrop();
}
if (blocks_to_ack.size() > 0) {
// Acknowledge block(s)
if (num_processed_meshes > 0)
g_profiler->graphAdd("num_processed_meshes", num_processed_meshes);
+
+ auto shadow_renderer = RenderingEngine::get_shadow_renderer();
+ if (shadow_renderer && force_update_shadows)
+ shadow_renderer->setForceUpdateShadowMap();
}
/*
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();) {
+ assert(it->second->isStarted());
+ it->second->step(this);
+ if (it->second->isDone()) {
+ done.emplace_back(it->first);
+
+ it = m_pending_media_downloads.erase(it);
+ } else {
+ it++;
+ }
+
+ if (done.size() == 255) { // maximum in one packet
+ sendHaveMedia(done);
+ done.clear();
+ }
+ }
+ if (!done.empty())
+ sendHaveMedia(done);
+ }
/*
If the server didn't update the inventory in a while, revert
}
}
+ // Write changes to the mod storage
m_mod_storage_save_timer -= dtime;
if (m_mod_storage_save_timer <= 0.0f) {
m_mod_storage_save_timer = g_settings->getFloat("server_map_save_interval");
- int n = 0;
- for (std::unordered_map<std::string, ModMetadata *>::const_iterator
- it = m_mod_storages.begin(); it != m_mod_storages.end(); ++it) {
- if (it->second->isModified()) {
- it->second->save(getModStoragePath());
- n++;
- }
- }
- if (n > 0)
- infostream << "Saved " << n << " modified mod storages." << std::endl;
+ m_mod_storage_database->endSave();
+ m_mod_storage_database->beginSave();
}
// Write server map
return false;
}
-bool Client::extractZipFile(const char *filename, const std::string &destination)
-{
- auto fs = m_rendering_engine->get_filesystem();
-
- if (!fs->addFileArchive(filename, false, false, io::EFAT_ZIP)) {
- return false;
- }
-
- sanity_check(fs->getFileArchiveCount() > 0);
-
- /**********************************************************************/
- /* WARNING this is not threadsafe!! */
- /**********************************************************************/
- io::IFileArchive* opened_zip = fs->getFileArchive(fs->getFileArchiveCount() - 1);
-
- const io::IFileList* files_in_zip = opened_zip->getFileList();
-
- unsigned int number_of_files = files_in_zip->getFileCount();
-
- for (unsigned int i=0; i < number_of_files; i++) {
- std::string fullpath = destination;
- fullpath += DIR_DELIM;
- fullpath += files_in_zip->getFullFileName(i).c_str();
- std::string fullpath_dir = fs::RemoveLastPathComponent(fullpath);
-
- if (!files_in_zip->isDirectory(i)) {
- if (!fs::PathExists(fullpath_dir) && !fs::CreateAllDirs(fullpath_dir)) {
- fs->removeFileArchive(fs->getFileArchiveCount()-1);
- return false;
- }
-
- io::IReadFile* toread = opened_zip->createAndOpenFile(i);
-
- FILE *targetfile = fopen(fullpath.c_str(),"wb");
-
- if (targetfile == NULL) {
- fs->removeFileArchive(fs->getFileArchiveCount()-1);
- return false;
- }
-
- char read_buffer[1024];
- long total_read = 0;
-
- while (total_read < toread->getSize()) {
-
- unsigned int bytes_read =
- toread->read(read_buffer,sizeof(read_buffer));
- if ((bytes_read == 0 ) ||
- (fwrite(read_buffer, 1, bytes_read, targetfile) != bytes_read))
- {
- fclose(targetfile);
- fs->removeFileArchive(fs->getFileArchiveCount() - 1);
- return false;
- }
- total_read += bytes_read;
- }
-
- fclose(targetfile);
- }
-
- }
-
- fs->removeFileArchive(fs->getFileArchiveCount() - 1);
- return true;
-}
-
// Virtual methods from con::PeerHandler
void Client::peerAdded(con::Peer *peer)
{
infostream << "Client::peerAdded(): peer->id="
<< peer->id << std::endl;
}
+
void Client::deletingPeer(con::Peer *peer, bool timeout)
{
infostream << "Client::deletingPeer(): "
"Server Peer is getting deleted "
<< "(timeout=" << timeout << ")" << std::endl;
- if (timeout) {
- m_access_denied = true;
+ m_access_denied = true;
+ if (timeout)
m_access_denied_reason = gettext("Connection timed out.");
- }
+ else if (m_access_denied_reason.empty())
+ m_access_denied_reason = gettext("Connection aborted (protocol error?).");
}
/*
Send(&pkt);
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,
{
NetworkPacket pkt;
u64 start_ms = porting::getTimeMs();
- const u64 budget = 100;
+ const u64 budget = 10;
for(;;) {
// Limit time even if there would be huge amounts of data to
// process
*/
if(sender_peer_id != PEER_ID_SERVER) {
infostream << "Client::ProcessData(): Discarding data not "
- "coming from server: peer_id=" << sender_peer_id
+ "coming from server: peer_id=" << sender_peer_id << " command=" << pkt->getCommand()
<< std::endl;
return;
}
v3f sf = myplayer->getSpeed() * 100;
s32 pitch = myplayer->getPitch() * 100;
s32 yaw = myplayer->getYaw() * 100;
- u32 keyPressed = myplayer->keyPressed;
+ u32 keyPressed = myplayer->control.getKeysPressed();
// scaled by 80, so that pi can fit into a u8
u8 fov = clientMap->getCameraFov() * 80;
u8 wanted_range = MYMIN(255,
Send(&pkt);
}
-void Client::promptConfirmRegistration(AuthMechanism chosen_auth_mechanism)
-{
- m_chosen_auth_mech = chosen_auth_mechanism;
- m_is_registration_confirmation_state = true;
-}
-
-void Client::confirmRegistration()
-{
- m_is_registration_confirmation_state = false;
- startAuth(m_chosen_auth_mech);
-}
-
void Client::startAuth(AuthMechanism chosen_auth_mechanism)
{
m_chosen_auth_mech = chosen_auth_mechanism;
pkt << message;
Send(&pkt);
- } else if (m_out_chat_queue.size() < (u16) max_queue_size || max_queue_size == -1) {
+ } else if (m_out_chat_queue.size() < (u16) max_queue_size || max_queue_size < 0) {
m_out_chat_queue.push(message);
} else {
infostream << "Could not queue chat message because maximum out chat queue size ("
if (!player)
return;
- ClientMap &map = m_env.getClientMap();
- u8 camera_fov = map.getCameraFov();
- u8 wanted_range = map.getControl().wanted_range;
-
// Save bandwidth by only updating position when
// player is not dead and something changed
if (m_activeobjects_received && player->isDead())
return;
+ ClientMap &map = m_env.getClientMap();
+ u8 camera_fov = map.getCameraFov();
+ u8 wanted_range = map.getControl().wanted_range;
+
+ u32 keyPressed = player->control.getKeysPressed();
+
if (
player->last_position == player->getPosition() &&
player->last_speed == player->getSpeed() &&
player->last_pitch == player->getPitch() &&
player->last_yaw == player->getYaw() &&
- player->last_keyPressed == player->keyPressed &&
+ player->last_keyPressed == keyPressed &&
player->last_camera_fov == camera_fov &&
player->last_wanted_range == wanted_range)
return;
player->last_speed = player->getSpeed();
player->last_pitch = player->getPitch();
player->last_yaw = player->getYaw();
- player->last_keyPressed = player->keyPressed;
+ player->last_keyPressed = keyPressed;
player->last_camera_fov = camera_fov;
player->last_wanted_range = wanted_range;
Send(&pkt);
}
+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;
+
+ Send(&pkt);
+}
+
+void Client::sendUpdateClientInfo(const ClientDynamicInfo& info)
+{
+ NetworkPacket pkt(TOSERVER_UPDATE_CLIENT_INFO, 4*2 + 4 + 4 + 4*2);
+ pkt << (u32)info.render_target_size.X << (u32)info.render_target_size.Y;
+ pkt << info.real_gui_scaling;
+ pkt << info.real_hud_scaling;
+ pkt << (f32)info.max_fs_size.X << (f32)info.max_fs_size.Y;
+
+ Send(&pkt);
+}
+
void Client::removeNode(v3s16 p)
{
std::map<v3s16, MapBlock*> modified_blocks;
list->setModified(false);
if (auto *list = player->inventory.getList("hand"))
list->setModified(false);
+ if (auto *list = player->inventory.getList("offhand"))
+ list->setModified(false);
return true;
}
-irr::scene::ISceneManager* Client::getSceneManager()
+scene::ISceneManager* Client::getSceneManager()
{
return m_rendering_engine->get_scene_manager();
}
if (b == NULL)
return;
- m_mesh_update_thread.updateBlock(&m_env.getMap(), p, ack_to_server, urgent);
+ m_mesh_update_manager.updateBlock(&m_env.getMap(), p, ack_to_server, urgent);
}
void Client::addUpdateMeshTaskWithEdge(v3s16 blockpos, bool ack_to_server, bool urgent)
{
- try{
- addUpdateMeshTask(blockpos, ack_to_server, urgent);
- }
- catch(InvalidPositionException &e){}
-
- // Leading edge
- for (int i=0;i<6;i++)
- {
- try{
- v3s16 p = blockpos + g_6dirs[i];
- addUpdateMeshTask(p, false, urgent);
- }
- catch(InvalidPositionException &e){}
- }
+ m_mesh_update_manager.updateBlock(&m_env.getMap(), blockpos, ack_to_server, urgent, true);
}
void Client::addUpdateMeshTaskForNode(v3s16 nodepos, bool ack_to_server, bool urgent)
<<std::endl;
}
- v3s16 blockpos = getNodeBlockPos(nodepos);
+ v3s16 blockpos = getNodeBlockPos(nodepos);
v3s16 blockpos_relative = blockpos * MAP_BLOCKSIZE;
-
- try{
- addUpdateMeshTask(blockpos, ack_to_server, urgent);
- }
- catch(InvalidPositionException &e) {}
-
+ m_mesh_update_manager.updateBlock(&m_env.getMap(), blockpos, ack_to_server, urgent, false);
// Leading edge
- if(nodepos.X == blockpos_relative.X){
- try{
- v3s16 p = blockpos + v3s16(-1,0,0);
- addUpdateMeshTask(p, false, urgent);
- }
- catch(InvalidPositionException &e){}
- }
-
- if(nodepos.Y == blockpos_relative.Y){
- try{
- v3s16 p = blockpos + v3s16(0,-1,0);
- addUpdateMeshTask(p, false, urgent);
- }
- catch(InvalidPositionException &e){}
- }
-
- if(nodepos.Z == blockpos_relative.Z){
- try{
- v3s16 p = blockpos + v3s16(0,0,-1);
- addUpdateMeshTask(p, false, urgent);
- }
- catch(InvalidPositionException &e){}
- }
+ if (nodepos.X == blockpos_relative.X)
+ addUpdateMeshTask(blockpos + v3s16(-1, 0, 0), false, urgent);
+ if (nodepos.Y == blockpos_relative.Y)
+ addUpdateMeshTask(blockpos + v3s16(0, -1, 0), false, urgent);
+ if (nodepos.Z == blockpos_relative.Z)
+ addUpdateMeshTask(blockpos + v3s16(0, 0, -1), false, urgent);
}
ClientEvent *Client::getClientEvent()
return 1.0; // downloader only exists when not yet done
}
-typedef struct TextureUpdateArgs {
+struct TextureUpdateArgs {
gui::IGUIEnvironment *guienv;
u64 last_time_ms;
u16 last_percent;
const wchar_t* text_base;
ITextureSource *tsrc;
-} TextureUpdateArgs;
+};
-void texture_update_progress(void *args, u32 progress, u32 max_progress)
+void Client::showUpdateProgressTexture(void *args, u32 progress, u32 max_progress)
{
TextureUpdateArgs* targs = (TextureUpdateArgs*) args;
u16 cur_percent = ceil(progress / (double) max_progress * 100.);
- // update the loading menu -- if neccessary
+ // update the loading menu -- if necessary
bool do_draw = false;
u64 time_ms = targs->last_time_ms;
if (cur_percent != targs->last_percent) {
if (do_draw) {
targs->last_time_ms = time_ms;
- std::basic_stringstream<wchar_t> strm;
- strm << targs->text_base << " " << targs->last_percent << "%...";
- RenderingEngine::draw_load_screen(strm.str(), targs->guienv, targs->tsrc, 0,
+ std::wostringstream strm;
+ strm << targs->text_base << L" " << targs->last_percent << L"%...";
+ m_rendering_engine->draw_load_screen(strm.str(), targs->guienv, targs->tsrc, 0,
72 + (u16) ((18. / 100.) * (double) targs->last_percent), true);
}
}
// Rebuild inherited images and recreate textures
infostream<<"- Rebuilding images and textures"<<std::endl;
- RenderingEngine::draw_load_screen(text, guienv, m_tsrc, 0, 70);
+ m_rendering_engine->draw_load_screen(text, guienv, m_tsrc, 0, 70);
m_tsrc->rebuildImagesAndTextures();
delete[] text;
// Rebuild shaders
infostream<<"- Rebuilding shaders"<<std::endl;
text = wgettext("Rebuilding shaders...");
- RenderingEngine::draw_load_screen(text, guienv, m_tsrc, 0, 71);
+ m_rendering_engine->draw_load_screen(text, guienv, m_tsrc, 0, 71);
m_shsrc->rebuildShaders();
delete[] text;
// Update node aliases
infostream<<"- Updating node aliases"<<std::endl;
text = wgettext("Initializing nodes...");
- RenderingEngine::draw_load_screen(text, guienv, m_tsrc, 0, 72);
+ m_rendering_engine->draw_load_screen(text, guienv, m_tsrc, 0, 72);
m_nodedef->updateAliases(m_itemdef);
for (const auto &path : getTextureDirs()) {
TextureOverrideSource override_source(path + DIR_DELIM + "override.txt");
tu_args.guienv = guienv;
tu_args.last_time_ms = porting::getTimeMs();
tu_args.last_percent = 0;
- tu_args.text_base = wgettext("Initializing nodes");
+ tu_args.text_base = wgettext("Initializing nodes");
tu_args.tsrc = m_tsrc;
- m_nodedef->updateTextures(this, texture_update_progress, &tu_args);
+ m_nodedef->updateTextures(this, &tu_args);
delete[] tu_args.text_base;
// Start mesh update thread after setting up content definitions
infostream<<"- Starting mesh update thread"<<std::endl;
- m_mesh_update_thread.start();
+ m_mesh_update_manager.start();
m_state = LC_Ready;
sendReady();
m_script->on_client_ready(m_env.getLocalPlayer());
text = wgettext("Done!");
- RenderingEngine::draw_load_screen(text, guienv, m_tsrc, 0, 100);
+ m_rendering_engine->draw_load_screen(text, guienv, m_tsrc, 0, 100);
infostream<<"Client::afterContentReceived() done"<<std::endl;
delete[] text;
}
void Client::makeScreenshot()
{
- irr::video::IVideoDriver *driver = RenderingEngine::get_video_driver();
+ irr::video::IVideoDriver *driver = m_rendering_engine->get_video_driver();
irr::video::IImage* const raw_image = driver->createScreenShot();
if (!raw_image)
return;
- time_t t = time(NULL);
- struct tm *tm = localtime(&t);
+ const struct tm tm = mt_localtime();
char timetstamp_c[64];
- strftime(timetstamp_c, sizeof(timetstamp_c), "%Y%m%d_%H%M%S", tm);
+ strftime(timetstamp_c, sizeof(timetstamp_c), "%Y%m%d_%H%M%S", &tm);
std::string screenshot_dir;
return &it->second;
}
-bool Client::registerModStorage(ModMetadata *storage)
-{
- if (m_mod_storages.find(storage->getModName()) != m_mod_storages.end()) {
- errorstream << "Unable to register same mod storage twice. Storage name: "
- << storage->getModName() << std::endl;
- return false;
- }
-
- m_mod_storages[storage->getModName()] = storage;
- return true;
-}
-
-void Client::unregisterModStorage(const std::string &name)
-{
- std::unordered_map<std::string, ModMetadata *>::const_iterator it =
- m_mod_storages.find(name);
- if (it != m_mod_storages.end()) {
- // Save unconditionaly on unregistration
- it->second->save(getModStoragePath());
- m_mod_storages.erase(name);
- }
-}
-
-std::string Client::getModStoragePath() const
-{
- return porting::path_user + DIR_DELIM + "client" + DIR_DELIM + "mod_storage";
-}
-
/*
* Mod channels
*/