X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=src%2Fclient%2Fclient.cpp;h=8760b416da43c922ecbdd6f9d170db6813ebba9b;hb=925309eba69a95bcd2a49233125ce32e530fa663;hp=c9cd24cb3f000b4cefe10c113fa67161cfadf111;hpb=de73f989eb1397b1103236031fd91309b294583c;p=minetest.git diff --git a/src/client/client.cpp b/src/client/client.cpp index c9cd24cb3..8760b416d 100644 --- a/src/client/client.cpp +++ b/src/client/client.cpp @@ -41,6 +41,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "filesys.h" #include "mapblock_mesh.h" #include "mapblock.h" +#include "mapsector.h" #include "minimap.h" #include "modchannels.h" #include "content/mods.h" @@ -50,6 +51,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #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" @@ -57,6 +59,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "game.h" #include "chatmessage.h" #include "translation.h" +#include "content/mod_configuration.h" extern gui::IGUIEnvironment* guienv; @@ -64,6 +67,14 @@ extern gui::IGUIEnvironment* guienv; Utility classes */ +u32 PacketCounter::sum() const +{ + u32 n = 0; + for (const auto &it : m_packets) + n += it.second; + return n; +} + void PacketCounter::print(std::ostream &o) const { for (const auto &it : m_packets) { @@ -89,8 +100,10 @@ Client::Client( NodeDefManager *nodedef, ISoundManager *sound, MtEventManager *event, + RenderingEngine *rendering_engine, bool ipv6, - GameUI *game_ui + GameUI *game_ui, + ELoginRegister allow_login_or_register ): m_tsrc(tsrc), m_shsrc(shsrc), @@ -98,14 +111,16 @@ Client::Client( m_nodedef(nodedef), m_sound(sound), m_event(event), - m_mesh_update_thread(this), + m_rendering_engine(rendering_engine), + m_mesh_update_manager(this), m_env( - new ClientMap(this, control, 666), + 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), @@ -118,10 +133,44 @@ Client::Client( // 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 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() @@ -149,26 +198,28 @@ void Client::loadMods() // Load builtin scanModIntoMemory(BUILTIN_MOD_NAME, getBuiltinLuaPath()); m_script->loadModFromMemory(BUILTIN_MOD_NAME); + m_script->checkSetByBuiltin(); - // TODO Uncomment when server-sent CSM and verifying of builtin are complete - /* - // Don't load client-provided mods if disabled by server - if (checkCSMRestrictionFlag(CSMRestrictionFlags::CSM_RF_LOAD_CLIENT_MODS)) { - warningstream << "Client-provided mod loading is disabled by server." << - std::endl; - // If builtin integrity is wrong, disconnect user - if (!checkBuiltinIntegrity()) { - // TODO disconnect user + ModConfiguration modconf; + { + std::unordered_map paths; + std::string path_user = porting::path_user + DIR_DELIM + "clientmods"; + const auto modsPath = getClientModsLuaPath(); + if (modsPath != path_user) { + paths["share"] = modsPath; } - return; + 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; } @@ -178,17 +229,13 @@ void Client::loadMods() infostream << mod.name << " "; infostream << std::endl; - // Load and run "mod" scripts + // 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); } - // Load and run "mod" scripts + // Run them for (const ModSpec &mod : m_mods) m_script->loadModFromMemory(mod.name); @@ -197,16 +244,14 @@ void Client::loadMods() // Run a callback when mods are loaded m_script->on_mods_loaded(); + + // Create objects if they're ready if (m_state == LC_Ready) m_script->on_client_ready(m_env.getLocalPlayer()); if (m_camera) m_script->on_camera_ready(m_camera); -} - -bool Client::checkBuiltinIntegrity() -{ - // TODO - return true; + if (m_minimap) + m_script->on_minimap_ready(m_minimap); } void Client::scanModSubfolder(const std::string &mod_name, const std::string &mod_path, @@ -215,6 +260,9 @@ void Client::scanModSubfolder(const std::string &mod_name, const std::string &mo std::string full_path = mod_path + DIR_DELIM + mod_subpath; std::vector 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; @@ -226,18 +274,13 @@ void Client::scanModSubfolder(const std::string &mod_name, const std::string &mo infostream << "Client::scanModSubfolder(): Loading \"" << real_path << "\" as \"" << vfs_path << "\"." << std::endl; - std::ifstream is(real_path, std::ios::binary | std::ios::ate); - if(!is.good()) { + std::string contents; + if (!fs::ReadFile(real_path, contents)) { errorstream << "Client::scanModSubfolder(): Can't read file \"" << real_path << "\"." << std::endl; continue; } - auto size = is.tellg(); - std::string contents(size, '\0'); - is.seekg(0); - is.read(&contents[0], size); - infostream << " size: " << size << " bytes" << std::endl; m_mod_vfs.emplace(vfs_path, contents); } } @@ -271,7 +314,7 @@ void Client::Stop() 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; @@ -284,7 +327,7 @@ void Client::Stop() bool Client::isShutdown() { - return m_shutdown || !m_mesh_update_thread.isRunning(); + return m_shutdown || !m_mesh_update_manager.isRunning(); } Client::~Client() @@ -294,14 +337,17 @@ 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 @@ -310,15 +356,19 @@ Client::~Client() } // cleanup 3d model meshes on client shutdown - while (RenderingEngine::get_mesh_cache()->getMeshCount() != 0) { - scene::IAnimatedMesh *mesh = RenderingEngine::get_mesh_cache()->getMeshByIndex(0); + m_rendering_engine->cleanupMeshCache(); - if (mesh) - RenderingEngine::get_mesh_cache()->removeMesh(mesh); - } + 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) @@ -353,9 +403,11 @@ void Client::step(float dtime) if(counter <= 0.0f) { counter = 30.0f; + u32 sum = m_packetcounter.sum(); + float avg = sum / counter; - infostream << "Client packetcounter (" << m_packetcounter_timer - << "s):"< 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); @@ -445,12 +493,9 @@ void Client::step(float dtime) /* Handle environment */ - // Control local player (0ms) LocalPlayer *player = m_env.getLocalPlayer(); - assert(player); - player->applyControl(dtime, &m_env); - // Step environment + // Step environment (also handles player controls) m_env.step(dtime); m_sound->step(dtime); @@ -470,6 +515,7 @@ void Client::step(float dtime) 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); } } @@ -505,23 +551,33 @@ void Client::step(float dtime) { int num_processed_meshes = 0; std::vector 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 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; @@ -531,25 +587,48 @@ void Client::step(float dtime) 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) @@ -558,6 +637,10 @@ void Client::step(float dtime) 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(); } /* @@ -570,6 +653,29 @@ void Client::step(float dtime) m_media_downloader = NULL; } } + { + // Acknowledge dynamic media downloads to server + std::vector 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 @@ -633,19 +739,12 @@ void Client::step(float dtime) } } + // 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::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 @@ -656,11 +755,9 @@ void Client::step(float dtime) } } -bool Client::loadMedia(const std::string &data, const std::string &filename) +bool Client::loadMedia(const std::string &data, const std::string &filename, + bool from_media_push) { - // Silly irrlicht's const-incorrectness - Buffer data_rw(data.c_str(), data.size()); - std::string name; const char *image_ext[] = { @@ -673,12 +770,11 @@ bool Client::loadMedia(const std::string &data, const std::string &filename) TRACESTREAM(<< "Client: Attempting to load image " << "file \"" << filename << "\"" << std::endl); - io::IFileSystem *irrfs = RenderingEngine::get_filesystem(); - video::IVideoDriver *vdrv = RenderingEngine::get_video_driver(); + io::IFileSystem *irrfs = m_rendering_engine->get_filesystem(); + video::IVideoDriver *vdrv = m_rendering_engine->get_video_driver(); - // Create an irrlicht memory file io::IReadFile *rfile = irrfs->createMemoryReadFile( - *data_rw, data_rw.getSize(), "_tempreadfile"); + data.c_str(), data.size(), "_tempreadfile"); FATAL_ERROR_IF(!rfile, "Could not create irrlicht memory file."); @@ -713,7 +809,6 @@ bool Client::loadMedia(const std::string &data, const std::string &filename) ".x", ".b3d", ".md2", ".obj", NULL }; - name = removeStringEnd(filename, model_ext); if (!name.empty()) { verbosestream<<"Client: Storing model into memory: " @@ -730,9 +825,11 @@ bool Client::loadMedia(const std::string &data, const std::string &filename) }; name = removeStringEnd(filename, translate_ext); if (!name.empty()) { + if (from_media_push) + return false; TRACESTREAM(<< "Client: Loading translation: " << "\"" << filename << "\"" << std::endl); - g_translations->loadTranslation(data); + g_client_translations->loadTranslation(data); return true; } @@ -747,16 +844,18 @@ 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?)."); } /* @@ -787,7 +886,8 @@ void Client::request_media(const std::vector &file_requests) 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, @@ -823,7 +923,7 @@ void Client::ReceiveAll() { 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 @@ -870,7 +970,7 @@ void Client::ProcessData(NetworkPacket *pkt) */ 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; } @@ -921,7 +1021,7 @@ void writePlayerPos(LocalPlayer *myplayer, ClientMap *clientMap, NetworkPacket * 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, @@ -1029,18 +1129,6 @@ void Client::sendInit(const std::string &playerName) 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; @@ -1205,7 +1293,7 @@ void Client::sendChatMessage(const std::wstring &message) if (canSendChatMessage()) { u32 now = time(NULL); float time_passed = now - m_last_chat_message_sent; - m_last_chat_message_sent = time(NULL); + m_last_chat_message_sent = now; m_chat_message_allowance += time_passed * (CLIENT_CHAT_MESSAGE_LIMIT_PER_10S / 8.0f); if (m_chat_message_allowance > CLIENT_CHAT_MESSAGE_LIMIT_PER_10S) @@ -1218,7 +1306,7 @@ void Client::sendChatMessage(const std::wstring &message) 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 (" @@ -1277,24 +1365,25 @@ void Client::sendPlayerPos() if (!player) return; + // 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; - // Save bandwidth by only updating position when - // player is not dead and something changed - - // FIXME: This part causes breakages in mods like 3d_armor, and has been commented for now - // if (m_activeobjects_received && player->isDead()) - // return; + 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_camera_fov == camera_fov && + player->last_keyPressed == keyPressed && + player->last_camera_fov == camera_fov && player->last_wanted_range == wanted_range) return; @@ -1302,7 +1391,7 @@ void Client::sendPlayerPos() 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; @@ -1313,6 +1402,30 @@ void Client::sendPlayerPos() Send(&pkt); } +void Client::sendHaveMedia(const std::vector &tokens) +{ + NetworkPacket pkt(TOSERVER_HAVE_MEDIA, 1 + tokens.size() * 4); + + sanity_check(tokens.size() < 256); + + pkt << static_cast(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 modified_blocks; @@ -1422,10 +1535,17 @@ bool Client::updateWieldedItem() 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; } +scene::ISceneManager* Client::getSceneManager() +{ + return m_rendering_engine->get_scene_manager(); +} + Inventory* Client::getInventory(const InventoryLocation &loc) { switch(loc.type){ @@ -1582,25 +1702,12 @@ void Client::addUpdateMeshTask(v3s16 p, bool ack_to_server, bool urgent) 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) @@ -1612,38 +1719,16 @@ void Client::addUpdateMeshTaskForNode(v3s16 nodepos, bool ack_to_server, bool ur <Connected(); -} - const Address Client::getServerAddress() { return m_con->GetPeerAddress(PEER_ID_SERVER); @@ -1674,20 +1754,20 @@ float Client::mediaReceiveProgress() 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) { @@ -1699,9 +1779,9 @@ void texture_update_progress(void *args, u32 progress, u32 max_progress) if (do_draw) { targs->last_time_ms = time_ms; - std::basic_stringstream 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); } } @@ -1722,24 +1802,27 @@ void Client::afterContentReceived() // Rebuild inherited images and recreate textures infostream<<"- Rebuilding images and textures"<draw_load_screen(text, guienv, m_tsrc, 0, 70); m_tsrc->rebuildImagesAndTextures(); delete[] text; // Rebuild shaders infostream<<"- Rebuilding shaders"<draw_load_screen(text, guienv, m_tsrc, 0, 71); m_shsrc->rebuildShaders(); delete[] text; // Update node aliases infostream<<"- Updating node aliases"<draw_load_screen(text, guienv, m_tsrc, 0, 72); m_nodedef->updateAliases(m_itemdef); - for (const auto &path : getTextureDirs()) - m_nodedef->applyTextureOverrides(path + DIR_DELIM + "override.txt"); + for (const auto &path : getTextureDirs()) { + TextureOverrideSource override_source(path + DIR_DELIM + "override.txt"); + m_nodedef->applyTextureOverrides(override_source.getNodeTileOverrides()); + m_itemdef->applyTextureOverrides(override_source.getItemTextureOverrides()); + } m_nodedef->setNodeRegistrationStatus(true); m_nodedef->runNodeResolveCallbacks(); delete[] text; @@ -1750,14 +1833,14 @@ void Client::afterContentReceived() 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"<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"<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; @@ -1844,7 +1926,7 @@ void Client::makeScreenshot() sstr << "Failed to save screenshot '" << filename << "'"; } pushToChatQueue(new ChatMessage(CHATMESSAGE_TYPE_SYSTEM, - narrow_to_wide(sstr.str()))); + utf8_to_wide(sstr.str()))); infostream << sstr.str() << std::endl; image->drop(); } @@ -1926,16 +2008,17 @@ scene::IAnimatedMesh* Client::getMesh(const std::string &filename, bool cache) // Create the mesh, remove it from cache and return it // This allows unique vertex colors and other properties for each instance - Buffer data_rw(data.c_str(), data.size()); // Const-incorrect Irrlicht - io::IReadFile *rfile = RenderingEngine::get_filesystem()->createMemoryReadFile( - *data_rw, data_rw.getSize(), filename.c_str()); + io::IReadFile *rfile = m_rendering_engine->get_filesystem()->createMemoryReadFile( + data.c_str(), data.size(), filename.c_str()); FATAL_ERROR_IF(!rfile, "Could not create/open RAM file"); - scene::IAnimatedMesh *mesh = RenderingEngine::get_scene_manager()->getMesh(rfile); + scene::IAnimatedMesh *mesh = m_rendering_engine->get_scene_manager()->getMesh(rfile); rfile->drop(); + if (!mesh) + return nullptr; mesh->grab(); if (!cache) - RenderingEngine::get_mesh_cache()->removeMesh(mesh); + m_rendering_engine->removeMesh(mesh); return mesh; } @@ -1956,34 +2039,6 @@ const std::string* Client::getModFile(std::string filename) 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::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 */