void EmergeManager::initMapgens() { if (m_mapgens.size()) return; MapgenFactory *mgfactory = getMapgenFactory(params.mg_name); if (!mgfactory) { errorstream << "EmergeManager: mapgen " << params.mg_name << " not registered; falling back to " << DEFAULT_MAPGEN << std::endl; params.mg_name = DEFAULT_MAPGEN; mgfactory = getMapgenFactory(params.mg_name); FATAL_ERROR_IF(mgfactory == NULL, "Couldn't use any mapgen!"); } if (!params.sparams) { params.sparams = mgfactory->createMapgenParams(); params.sparams->readParams(g_settings); } for (u32 i = 0; i != m_threads.size(); i++) { Mapgen *mg = mgfactory->createMapgen(i, ¶ms, this); m_mapgens.push_back(mg); } }
void CNodeDefManager::serialize(std::ostream &os, u16 protocol_version) const { writeU8(os, 1); // version u16 count = 0; std::ostringstream os2(std::ios::binary); for (u32 i = 0; i < m_content_features.size(); i++) { if (i == CONTENT_IGNORE || i == CONTENT_AIR || i == CONTENT_UNKNOWN) continue; const ContentFeatures *f = &m_content_features[i]; if (f->name == "") continue; writeU16(os2, i); // Wrap it in a string to allow different lengths without // strict version incompatibilities std::ostringstream wrapper_os(std::ios::binary); f->serialize(wrapper_os, protocol_version); os2<<serializeString(wrapper_os.str()); // must not overflow u16 next = count + 1; FATAL_ERROR_IF(next < count, "Overflow"); count++; } writeU16(os, count); os << serializeLongString(os2.str()); }
bool GUIEngine::setTexture(texture_layer layer, std::string texturepath, bool tile_image, unsigned int minsize) { video::IVideoDriver* driver = m_device->getVideoDriver(); FATAL_ERROR_IF(driver == 0, "Could not get video driver"); if (m_textures[layer].texture != NULL) { driver->removeTexture(m_textures[layer].texture); m_textures[layer].texture = NULL; } if ((texturepath == "") || !fs::PathExists(texturepath)) { return false; } m_textures[layer].texture = driver->getTexture(texturepath.c_str()); m_textures[layer].tile = tile_image; m_textures[layer].minsize = minsize; if (m_textures[layer].texture == NULL) { return false; } return true; }
scene::IAnimatedMesh* Client::getMesh(const std::string &filename) { StringMap::const_iterator it = m_mesh_data.find(filename); if (it == m_mesh_data.end()) { errorstream << "Client::getMesh(): Mesh not found: \"" << filename << "\"" << std::endl; return NULL; } const std::string &data = it->second; scene::ISceneManager *smgr = m_device->getSceneManager(); // Create the mesh, remove it from cache and return it // This allows unique vertex colors and other properties for each instance Buffer<char> data_rw(data.c_str(), data.size()); // Const-incorrect Irrlicht io::IFileSystem *irrfs = m_device->getFileSystem(); io::IReadFile *rfile = irrfs->createMemoryReadFile( *data_rw, data_rw.getSize(), filename.c_str()); FATAL_ERROR_IF(!rfile, "Could not create/open RAM file"); scene::IAnimatedMesh *mesh = smgr->getMesh(rfile); rfile->drop(); // NOTE: By playing with Irrlicht refcounts, maybe we could cache a bunch // of uniquely named instances and re-use them mesh->grab(); smgr->getMeshCache()->removeMesh(mesh); return mesh; }
GUIEngine::~GUIEngine() { video::IVideoDriver* driver = m_device->getVideoDriver(); FATAL_ERROR_IF(driver == 0, "Could not get video driver"); if(m_sound_manager != &dummySoundManager){ delete m_sound_manager; m_sound_manager = NULL; } infostream<<"GUIEngine: Deinitializing scripting"<<std::endl; delete m_script; m_irr_toplefttext->setText(L""); //clean up texture pointers for (unsigned int i = 0; i < TEX_LAYER_MAX; i++) { if (m_textures[i].texture != NULL) driver->removeTexture(m_textures[i].texture); } delete m_texture_source; if (m_cloud.clouds) m_cloud.clouds->drop(); }
// Push the list of callbacks (a lua table). // Then push nargs arguments. // Then call this function, which // - runs the callbacks // - replaces the table and arguments with the return value, // computed depending on mode void ScriptApiBase::runCallbacksRaw(int nargs, RunCallbacksMode mode, const char *fxn) { lua_State *L = getStack(); FATAL_ERROR_IF(lua_gettop(L) < nargs + 1, "Not enough arguments"); // Insert error handler lua_pushcfunction(L, script_error_handler); int errorhandler = lua_gettop(L) - nargs - 1; lua_insert(L, errorhandler); // Insert run_callbacks between error handler and table lua_getglobal(L, "core"); lua_getfield(L, -1, "run_callbacks"); lua_remove(L, -2); lua_insert(L, errorhandler + 1); // Insert mode after table lua_pushnumber(L, (int)mode); lua_insert(L, errorhandler + 3); // Stack now looks like this: // ... <error handler> <run_callbacks> <table> <mode> <arg#1> <arg#2> ... <arg#n> int result = lua_pcall(L, nargs + 2, 1, errorhandler); if (result != 0) scriptError(result, fxn); lua_remove(L, -2); // Remove error handler }
int ModApiUtil::l_request_insecure_environment(lua_State *L) { NO_MAP_LOCK_REQUIRED; // Just return _G if security is disabled if (!ScriptApiSecurity::isSecure(L)) { lua_getglobal(L, "_G"); return 1; } // We have to make sure that this function is being called directly by // a mod, otherwise a malicious mod could override this function and // steal its return value. lua_Debug info; // Make sure there's only one item below this function on the stack... if (lua_getstack(L, 2, &info)) { return 0; } FATAL_ERROR_IF(!lua_getstack(L, 1, &info), "lua_getstack() failed"); FATAL_ERROR_IF(!lua_getinfo(L, "S", &info), "lua_getinfo() failed"); // ...and that that item is the main file scope. if (strcmp(info.what, "main") != 0) { return 0; } // Get mod name lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_CURRENT_MOD_NAME); if (!lua_isstring(L, -1)) { return 0; } // Check secure.trusted_mods const char *mod_name = lua_tostring(L, -1); std::string trusted_mods = g_settings->get("secure.trusted_mods"); trusted_mods.erase(std::remove_if(trusted_mods.begin(), trusted_mods.end(), static_cast<int(*)(int)>(&std::isspace)), trusted_mods.end()); std::vector<std::string> mod_list = str_split(trusted_mods, ','); if (std::find(mod_list.begin(), mod_list.end(), mod_name) == mod_list.end()) { return 0; } // Push insecure environment lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_GLOBALS_BACKUP); return 1; }
const char *getHomeOrFail() { const char *home = getenv("HOME"); // In rare cases the HOME environment variable may be unset FATAL_ERROR_IF(!home, "Required environment variable HOME is not set"); return home; }
ClientEvent *Client::getClientEvent() { FATAL_ERROR_IF(m_client_event_queue.empty(), "Cannot getClientEvent, queue is empty."); ClientEvent *event = m_client_event_queue.front(); m_client_event_queue.pop(); return event; }
bool setSystemPaths() { char buf[BUFSIZ]; // Find path of executable and set path_share relative to it FATAL_ERROR_IF(!getCurrentExecPath(buf, sizeof(buf)), "Failed to get current executable path"); pathRemoveFile(buf, '\\'); // Use ".\bin\.." path_share = std::string(buf) + "\\.."; // Use "C:\Documents and Settings\user\Application Data\<PROJECT_NAME>" DWORD len = GetEnvironmentVariable("APPDATA", buf, sizeof(buf)); FATAL_ERROR_IF(len == 0 || len > sizeof(buf), "Failed to get APPDATA"); path_user = std::string(buf) + DIR_DELIM + PROJECT_NAME; return true; }
// Call lower level SRP code to generate a verifier with the // given pointers. Contains the preparations, call parameters // and error checking common to all srp verifier generation code. // See docs of srp_create_salted_verification_key for more info. static inline void gen_srp_v(const std::string &name, const std::string &password, char **salt, size_t *salt_len, char **bytes_v, size_t *len_v) { std::string n_name = lowercase(name); SRP_Result res = srp_create_salted_verification_key(SRP_SHA256, SRP_NG_2048, n_name.c_str(), (const unsigned char *)password.c_str(), password.size(), (unsigned char **)salt, salt_len, (unsigned char **)bytes_v, len_v, NULL, NULL); FATAL_ERROR_IF(res != SRP_OK, "Couldn't create salted SRP verifier"); }
void ClientEnvironment::setLocalPlayer(LocalPlayer *player) { DSTACK(FUNCTION_NAME); /* It is a failure if already is a local player */ FATAL_ERROR_IF(m_local_player != NULL, "Local player already allocated"); m_local_player = player; }
unsigned int FontEngine::getTextHeight(unsigned int font_size, FontMode mode) { irr::gui::IGUIFont* font = getFont(font_size, mode); // use current skin font as fallback if (font == NULL) { font = m_env->getSkin()->getFont(); } FATAL_ERROR_IF(font == NULL, "Could not get skin font"); return font->getDimension(L"Some unimportant example String").Height; }
void Client::startAuth(AuthMechanism chosen_auth_mechanism) { m_chosen_auth_mech = chosen_auth_mechanism; switch (chosen_auth_mechanism) { case AUTH_MECHANISM_FIRST_SRP: { // send srp verifier to server NetworkPacket resp_pkt(TOSERVER_FIRST_SRP, 0); char *salt, *bytes_v; std::size_t len_salt, len_v; salt = NULL; getSRPVerifier(getPlayerName(), m_password, &salt, &len_salt, &bytes_v, &len_v); resp_pkt << std::string((char*)salt, len_salt) << std::string((char*)bytes_v, len_v) << (u8)((m_password == "") ? 1 : 0); free(salt); free(bytes_v); Send(&resp_pkt); break; } case AUTH_MECHANISM_SRP: case AUTH_MECHANISM_LEGACY_PASSWORD: { u8 based_on = 1; if (chosen_auth_mechanism == AUTH_MECHANISM_LEGACY_PASSWORD) { m_password = translatePassword(getPlayerName(), m_password); based_on = 0; } std::string playername_u = lowercase(getPlayerName()); m_auth_data = srp_user_new(SRP_SHA256, SRP_NG_2048, getPlayerName().c_str(), playername_u.c_str(), (const unsigned char *) m_password.c_str(), m_password.length(), NULL, NULL); char *bytes_A = 0; size_t len_A = 0; SRP_Result res = srp_user_start_authentication( (struct SRPUser *) m_auth_data, NULL, NULL, 0, (unsigned char **) &bytes_A, &len_A); FATAL_ERROR_IF(res != SRP_OK, "Creating local SRP user failed."); NetworkPacket resp_pkt(TOSERVER_SRP_BYTES_A, 0); resp_pkt << std::string(bytes_A, len_A) << based_on; Send(&resp_pkt); break; } case AUTH_MECHANISM_NONE: break; // not handled in this method } }
unsigned int FontEngine::getTextWidth(const std::wstring& text, unsigned int font_size, FontMode mode) { irr::gui::IGUIFont* font = getFont(font_size, mode); // use current skin font as fallback if (font == NULL) { font = m_env->getSkin()->getFont(); } FATAL_ERROR_IF(font == NULL, "Could not get font"); return font->getDimension(text.c_str()).Width; }
KeyPress::KeyPress(const char *name) { if (strlen(name) == 0) { Key = irr::KEY_KEY_CODES_COUNT; Char = L'\0'; m_name = ""; return; } if (strlen(name) <= 4) { // Lookup by resulting character int chars_read = mbtowc(&Char, name, 1); FATAL_ERROR_IF(chars_read != 1, "Unexpected multibyte character"); try { struct table_key k = lookup_keychar(Char); m_name = k.Name; Key = k.Key; return; } catch (UnknownKeycode &e) {}; } else { // Lookup by name m_name = name; try { struct table_key k = lookup_keyname(name); Key = k.Key; Char = k.Char; return; } catch (UnknownKeycode &e) {}; } // It's not a known key, complain and try to do something Key = irr::KEY_KEY_CODES_COUNT; int chars_read = mbtowc(&Char, name, 1); FATAL_ERROR_IF(chars_read != 1, "Unexpected multibyte character"); m_name = ""; warningstream << "KeyPress: Unknown key '" << name << "', falling back to first char."; }
ScriptApiBase::ScriptApiBase() { #ifdef SCRIPTAPI_LOCK_DEBUG m_locked = false; #endif m_luastack = luaL_newstate(); FATAL_ERROR_IF(!m_luastack, "luaL_newstate() failed"); luaL_openlibs(m_luastack); // Add and save an error handler lua_pushcfunction(m_luastack, script_error_handler); m_errorhandler = lua_gettop(m_luastack); // Make the ScriptApiBase* accessible to ModApiBase lua_pushlightuserdata(m_luastack, this); lua_setfield(m_luastack, LUA_REGISTRYINDEX, "scriptapi"); // If we are using LuaJIT add a C++ wrapper function to catch // exceptions thrown in Lua -> C++ calls #if USE_LUAJIT lua_pushlightuserdata(m_luastack, (void*) script_exception_wrapper); luaJIT_setmode(m_luastack, -1, LUAJIT_MODE_WRAPCFUNC | LUAJIT_MODE_ON); lua_pop(m_luastack, 1); #endif // Add basic globals lua_newtable(m_luastack); lua_setglobal(m_luastack, "core"); lua_pushstring(m_luastack, DIR_DELIM); lua_setglobal(m_luastack, "DIR_DELIM"); lua_pushstring(m_luastack, porting::getPlatformName()); lua_setglobal(m_luastack, "PLATFORM"); // m_secure gets set to true inside // ScriptApiSecurity::initializeSecurity(), if neccessary. // Default to false otherwise m_secure = false; m_server = NULL; m_environment = NULL; m_guiengine = NULL; }
virtual void registerItem(const ItemDefinition &def) { verbosestream<<"ItemDefManager: registering \""<<def.name<<"\""<<std::endl; // Ensure that the "" item (the hand) always has ToolCapabilities if (def.name.empty()) FATAL_ERROR_IF(!def.tool_capabilities, "Hand does not have ToolCapabilities"); if(m_item_definitions.count(def.name) == 0) m_item_definitions[def.name] = new ItemDefinition(def); else *(m_item_definitions[def.name]) = def; // Remove conflicting alias if it exists bool alias_removed = (m_aliases.erase(def.name) != 0); if(alias_removed) infostream<<"ItemDefManager: erased alias "<<def.name <<" because item was defined"<<std::endl; }
EmergeThread *EmergeManager::getOptimalThread() { size_t nthreads = m_threads.size(); FATAL_ERROR_IF(nthreads == 0, "No emerge threads!"); size_t index = 0; size_t nitems_lowest = m_threads[0]->m_block_queue.size(); for (size_t i = 1; i < nthreads; i++) { size_t nitems = m_threads[i]->m_block_queue.size(); if (nitems < nitems_lowest) { index = i; nitems_lowest = nitems; } } return m_threads[index]; }
void Client::sendInventoryFields(const std::string &formname, const StringMap &fields) { size_t fields_size = fields.size(); FATAL_ERROR_IF(fields_size > 0xFFFF, "Unsupported number of inventory fields"); NetworkPacket pkt(TOSERVER_INVENTORY_FIELDS, 0); pkt << formname << (u16) (fields_size & 0xFFFF); StringMap::const_iterator it; for (it = fields.begin(); it != fields.end(); ++it) { const std::string &name = it->first; const std::string &value = it->second; pkt << name; pkt.putLongString(value); } Send(&pkt); }
std::string ClientMediaDownloader::serializeRequiredHashSet() { std::ostringstream os(std::ios::binary); writeU32(os, MTHASHSET_FILE_SIGNATURE); // signature writeU16(os, 1); // version // Write list of hashes of files that have not been // received (found in cache) yet for (std::map<std::string, FileStatus*>::iterator it = m_files.begin(); it != m_files.end(); ++it) { if (!it->second->received) { FATAL_ERROR_IF(it->second->sha1.size() != 20, "Invalid SHA1 size"); os << it->second->sha1; } } return os.str(); }
void FontEngine::updateSkin() { gui::IGUIFont *font = getFont(); if (font) m_env->getSkin()->setFont(font); else errorstream << "FontEngine: Default font file: " << "\n\t\"" << m_settings->get("font_path") << "\"" << "\n\trequired for current screen configuration was not found" << " or was invalid file format." << "\n\tUsing irrlicht default font." << std::endl; // If we did fail to create a font our own make irrlicht find a default one font = m_env->getSkin()->getFont(); FATAL_ERROR_IF(font == NULL, "Could not create/get font"); u32 text_height = font->getDimension(L"Hello, world!").Height; infostream << "text_height=" << text_height << std::endl; }
void Client::sendNodemetaFields(v3s16 p, const std::string &formname, const std::map<std::string, std::string> &fields) { size_t fields_size = fields.size(); FATAL_ERROR_IF(fields_size > 0xFFFF, "Unsupported number of nodemeta fields"); NetworkPacket pkt(TOSERVER_NODEMETA_FIELDS, 0); pkt << p << formname << (u16) (fields_size & 0xFFFF); for(std::map<std::string, std::string>::const_iterator i = fields.begin(); i != fields.end(); i++) { const std::string &name = i->first; const std::string &value = i->second; pkt << name; pkt.putLongString(value); } Send(&pkt); }
void LuaLBM::trigger(ServerEnvironment *env, v3s16 p, MapNode n) { ServerScripting *scriptIface = env->getScriptIface(); scriptIface->realityCheck(); lua_State *L = scriptIface->getStack(); sanity_check(lua_checkstack(L, 20)); StackUnroller stack_unroller(L); int error_handler = PUSH_ERROR_HANDLER(L); // Get registered_lbms lua_getglobal(L, "core"); lua_getfield(L, -1, "registered_lbms"); luaL_checktype(L, -1, LUA_TTABLE); lua_remove(L, -2); // Remove core // Get registered_lbms[m_id] lua_pushnumber(L, m_id); lua_gettable(L, -2); FATAL_ERROR_IF(lua_isnil(L, -1), "Entry with given id not found in registered_lbms table"); lua_remove(L, -2); // Remove registered_lbms scriptIface->setOriginFromTable(-1); // Call action luaL_checktype(L, -1, LUA_TTABLE); lua_getfield(L, -1, "action"); luaL_checktype(L, -1, LUA_TFUNCTION); lua_remove(L, -2); // Remove registered_lbms[m_id] push_v3s16(L, p); pushnode(L, n, env->getGameDef()->ndef()); int result = lua_pcall(L, 2, 0, error_handler); if (result) scriptIface->scriptError(result, "LuaLBM::trigger"); lua_pop(L, 1); // Pop error handler }
/* u16 command u16 number of files requested for each file { u16 length of name string name } */ void Client::request_media(const std::vector<std::string> &file_requests) { std::ostringstream os(std::ios_base::binary); writeU16(os, TOSERVER_REQUEST_MEDIA); size_t file_requests_size = file_requests.size(); FATAL_ERROR_IF(file_requests_size > 0xFFFF, "Unsupported number of file requests"); // Packet dynamicly resized NetworkPacket pkt(TOSERVER_REQUEST_MEDIA, 2 + 0); pkt << (u16) (file_requests_size & 0xFFFF); for (const std::string &file_request : file_requests) { pkt << file_request; } Send(&pkt); infostream << "Client: Sending media request list to server (" << file_requests.size() << " files. packet size)" << std::endl; }
bool ClientLauncher::run(GameParams &game_params, const Settings &cmd_args) { init_args(game_params, cmd_args); // List video modes if requested if (list_video_modes) return print_video_modes(); if (!init_engine(game_params.log_level)) { errorstream << "Could not initialize game engine." << std::endl; return false; } // Create time getter g_timegetter = new IrrlichtTimeGetter(device); // Speed tests (done after irrlicht is loaded to get timer) if (cmd_args.getFlag("speedtests")) { dstream << "Running speed tests" << std::endl; speed_tests(); return true; } video::IVideoDriver *video_driver = device->getVideoDriver(); if (video_driver == NULL) { errorstream << "Could not initialize video driver." << std::endl; return false; } porting::setXorgClassHint(video_driver->getExposedVideoData(), PROJECT_NAME_C); /* This changes the minimum allowed number of vertices in a VBO. Default is 500. */ //driver->setMinHardwareBufferVertexCount(50); // Create game callback for menus g_gamecallback = new MainGameCallback(device); device->setResizable(true); if (random_input) input = new RandomInputHandler(); else input = new RealInputHandler(device, receiver); smgr = device->getSceneManager(); smgr->getParameters()->setAttribute(scene::ALLOW_ZWRITE_ON_TRANSPARENT, true); guienv = device->getGUIEnvironment(); skin = guienv->getSkin(); skin->setColor(gui::EGDC_BUTTON_TEXT, video::SColor(255, 255, 255, 255)); skin->setColor(gui::EGDC_3D_LIGHT, video::SColor(0, 0, 0, 0)); skin->setColor(gui::EGDC_3D_HIGH_LIGHT, video::SColor(255, 30, 30, 30)); skin->setColor(gui::EGDC_3D_SHADOW, video::SColor(255, 0, 0, 0)); skin->setColor(gui::EGDC_HIGH_LIGHT, video::SColor(255, 70, 120, 50)); skin->setColor(gui::EGDC_HIGH_LIGHT_TEXT, video::SColor(255, 255, 255, 255)); g_fontengine = new FontEngine(g_settings, guienv); FATAL_ERROR_IF(g_fontengine == NULL, "Font engine creation failed."); #if (IRRLICHT_VERSION_MAJOR >= 1 && IRRLICHT_VERSION_MINOR >= 8) || IRRLICHT_VERSION_MAJOR >= 2 // Irrlicht 1.8 input colours skin->setColor(gui::EGDC_EDITABLE, video::SColor(255, 128, 128, 128)); skin->setColor(gui::EGDC_FOCUSED_EDITABLE, video::SColor(255, 96, 134, 49)); #endif // Create the menu clouds if (!g_menucloudsmgr) g_menucloudsmgr = smgr->createNewSceneManager(); if (!g_menuclouds) g_menuclouds = new Clouds(g_menucloudsmgr->getRootSceneNode(), g_menucloudsmgr, -1, rand(), 100); g_menuclouds->update(v2f(0, 0), video::SColor(255, 200, 200, 255)); scene::ICameraSceneNode* camera; camera = g_menucloudsmgr->addCameraSceneNode(0, v3f(0, 0, 0), v3f(0, 60, 100)); camera->setFarValue(10000); /* GUI stuff */ ChatBackend chat_backend; // If an error occurs, this is set to something by menu(). // It is then displayed before the menu shows on the next call to menu() std::string error_message; bool first_loop = true; /* Menu-game loop */ bool retval = true; bool *kill = porting::signal_handler_killstatus(); while (device->run() && !*kill && !g_gamecallback->shutdown_requested) { // Set the window caption const wchar_t *text = wgettext("Main Menu"); device->setWindowCaption((narrow_to_wide("MultiCraft") + L" [" + text + L"]").c_str()); delete[] text; #ifdef ANDROID porting::handleAndroidActivityEvents(); #endif try { // This is used for catching disconnects guienv->clear(); /* We need some kind of a root node to be able to add custom gui elements directly on the screen. Otherwise they won't be automatically drawn. */ guiroot = guienv->addStaticText(L"", core::rect<s32>(0, 0, 10000, 10000)); bool game_has_run = launch_game(error_message, game_params, cmd_args); // If skip_main_menu, we only want to startup once if (skip_main_menu && !first_loop) break; first_loop = false; if (!game_has_run) { if (skip_main_menu) break; else continue; } // Break out of menu-game loop to shut down cleanly if (!device->run() || *kill) { if (g_settings_path != "") g_settings->updateConfigFile(g_settings_path.c_str()); break; } if (current_playername.length() > PLAYERNAME_SIZE-1) { error_message = gettext("Player name too long."); playername = current_playername.substr(0, PLAYERNAME_SIZE-1); g_settings->set("name", playername); continue; } device->getVideoDriver()->setTextureCreationFlag( video::ETCF_CREATE_MIP_MAPS, g_settings->getBool("mip_map")); #ifdef HAVE_TOUCHSCREENGUI receiver->m_touchscreengui = new TouchScreenGUI(device, receiver); g_touchscreengui = receiver->m_touchscreengui; #endif the_game( kill, random_input, input, device, worldspec.path, current_playername, current_password, current_address, current_port, error_message, chat_backend, gamespec, simple_singleplayer_mode ); smgr->clear(); #ifdef HAVE_TOUCHSCREENGUI delete g_touchscreengui; g_touchscreengui = NULL; receiver->m_touchscreengui = NULL; #endif } //try catch (con::PeerNotFoundException &e) { error_message = gettext("Connection error (timed out?)"); errorstream << error_message << std::endl; } #ifdef NDEBUG catch (std::exception &e) { std::string error_message = "Some exception: \""; error_message += e.what(); error_message += "\""; errorstream << error_message << std::endl; } #endif // If no main menu, show error and exit if (skip_main_menu) { if (!error_message.empty()) { verbosestream << "error_message = " << error_message << std::endl; retval = false; } break; } } // Menu-game loop g_menuclouds->drop(); g_menucloudsmgr->drop(); return retval; }
void getItemMesh(Client *client, const ItemStack &item, ItemMesh *result) { ITextureSource *tsrc = client->getTextureSource(); IItemDefManager *idef = client->getItemDefManager(); const NodeDefManager *ndef = client->getNodeDefManager(); const ItemDefinition &def = item.getDefinition(idef); const ContentFeatures &f = ndef->get(def.name); content_t id = ndef->getId(def.name); FATAL_ERROR_IF(!g_extrusion_mesh_cache, "Extrusion mesh cache is not yet initialized"); scene::SMesh *mesh = nullptr; // Shading is on by default result->needs_shading = true; // If inventory_image is defined, it overrides everything else if (!def.inventory_image.empty()) { mesh = getExtrudedMesh(tsrc, def.inventory_image, def.inventory_overlay); result->buffer_colors.emplace_back(); // overlay is white, if present result->buffer_colors.emplace_back(true, video::SColor(0xFFFFFFFF)); // Items with inventory images do not need shading result->needs_shading = false; } else if (def.type == ITEM_NODE) { if (f.mesh_ptr[0]) { mesh = cloneMesh(f.mesh_ptr[0]); scaleMesh(mesh, v3f(0.12, 0.12, 0.12)); postProcessNodeMesh(mesh, f, false, false, nullptr, &result->buffer_colors); } else { switch (f.drawtype) { case NDT_PLANTLIKE: { mesh = getExtrudedMesh(tsrc, tsrc->getTextureName(f.tiles[0].layers[0].texture_id), tsrc->getTextureName(f.tiles[0].layers[1].texture_id)); // Add color const TileLayer &l0 = f.tiles[0].layers[0]; result->buffer_colors.emplace_back(l0.has_color, l0.color); const TileLayer &l1 = f.tiles[0].layers[1]; result->buffer_colors.emplace_back(l1.has_color, l1.color); break; } case NDT_PLANTLIKE_ROOTED: { mesh = getExtrudedMesh(tsrc, tsrc->getTextureName(f.special_tiles[0].layers[0].texture_id), ""); // Add color const TileLayer &l0 = f.special_tiles[0].layers[0]; result->buffer_colors.emplace_back(l0.has_color, l0.color); break; } case NDT_NORMAL: case NDT_ALLFACES: case NDT_LIQUID: case NDT_FLOWINGLIQUID: { scene::IMesh *cube = g_extrusion_mesh_cache->createCube(); mesh = cloneMesh(cube); cube->drop(); scaleMesh(mesh, v3f(1.2, 1.2, 1.2)); // add overlays postProcessNodeMesh(mesh, f, false, false, nullptr, &result->buffer_colors); break; } default: { mesh = createSpecialNodeMesh(client, id, &result->buffer_colors); scaleMesh(mesh, v3f(0.12, 0.12, 0.12)); } } } u32 mc = mesh->getMeshBufferCount(); for (u32 i = 0; i < mc; ++i) { scene::IMeshBuffer *buf = mesh->getMeshBuffer(i); video::SMaterial &material = buf->getMaterial(); material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL; material.setFlag(video::EMF_BILINEAR_FILTER, false); material.setFlag(video::EMF_TRILINEAR_FILTER, false); material.setFlag(video::EMF_BACK_FACE_CULLING, true); material.setFlag(video::EMF_LIGHTING, false); } rotateMeshXZby(mesh, -45); rotateMeshYZby(mesh, -30); } result->mesh = mesh; }
void Client::step(float dtime) { // Limit a bit if(dtime > 2.0) dtime = 2.0; if(m_ignore_damage_timer > dtime) m_ignore_damage_timer -= dtime; else m_ignore_damage_timer = 0.0; m_animation_time += dtime; if(m_animation_time > 60.0) m_animation_time -= 60.0; m_time_of_day_update_timer += dtime; ReceiveAll(); /* Packet counter */ { float &counter = m_packetcounter_timer; counter -= dtime; if(counter <= 0.0) { counter = 20.0; infostream << "Client packetcounter (" << m_packetcounter_timer << "):"<<std::endl; m_packetcounter.print(infostream); m_packetcounter.clear(); } } // UGLY hack to fix 2 second startup delay caused by non existent // server client startup synchronization in local server or singleplayer mode static bool initial_step = true; if (initial_step) { initial_step = false; } else if(m_state == LC_Created) { float &counter = m_connection_reinit_timer; counter -= dtime; if(counter <= 0.0) { counter = 2.0; LocalPlayer *myplayer = m_env.getLocalPlayer(); FATAL_ERROR_IF(myplayer == NULL, "Local player not found in environment."); sendInit(myplayer->getName()); } // Not connected, return return; } /* Do stuff if connected */ /* Run Map's timers and unload unused data */ const float map_timer_and_unload_dtime = 5.25; if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime)) { ScopeProfiler sp(g_profiler, "Client: map timer and unload"); std::vector<v3s16> deleted_blocks; m_env.getMap().timerUpdate(map_timer_and_unload_dtime, g_settings->getFloat("client_unload_unused_data_timeout"), g_settings->getS32("client_mapblock_limit"), &deleted_blocks); /* Send info to server NOTE: This loop is intentionally iterated the way it is. */ std::vector<v3s16>::iterator i = deleted_blocks.begin(); std::vector<v3s16> sendlist; for(;;) { if(sendlist.size() == 255 || i == deleted_blocks.end()) { if(sendlist.empty()) break; /* [0] u16 command [2] u8 count [3] v3s16 pos_0 [3+6] v3s16 pos_1 ... */ sendDeletedBlocks(sendlist); if(i == deleted_blocks.end()) break; sendlist.clear(); } sendlist.push_back(*i); ++i; } } /* Send pending messages on out chat queue */ if (!m_out_chat_queue.empty() && canSendChatMessage()) { sendChatMessage(m_out_chat_queue.front()); m_out_chat_queue.pop(); } /* Handle environment */ // Control local player (0ms) LocalPlayer *player = m_env.getLocalPlayer(); assert(player); player->applyControl(dtime, &m_env); // Step environment m_env.step(dtime); m_sound->step(dtime); /* Get events */ while (m_env.hasClientEnvEvents()) { ClientEnvEvent envEvent = m_env.getClientEnvEvent(); if (envEvent.type == CEE_PLAYER_DAMAGE) { if (m_ignore_damage_timer <= 0) { u8 damage = envEvent.player_damage.amount; if (envEvent.player_damage.send_to_server) sendDamage(damage); // Add to ClientEvent queue ClientEvent *event = new ClientEvent(); event->type = CE_PLAYER_DAMAGE; event->player_damage.amount = damage; m_client_event_queue.push(event); } } } /* Print some info */ float &counter = m_avg_rtt_timer; counter += dtime; if(counter >= 10) { counter = 0.0; // connectedAndInitialized() is true, peer exists. float avg_rtt = getRTT(); infostream << "Client: avg_rtt=" << avg_rtt << std::endl; } /* Send player position to server */ { float &counter = m_playerpos_send_timer; counter += dtime; if((m_state == LC_Ready) && (counter >= m_recommended_send_interval)) { counter = 0.0; sendPlayerPos(); } } /* Replace updated meshes */ { int num_processed_meshes = 0; while (!m_mesh_update_thread.m_queue_out.empty()) { num_processed_meshes++; MinimapMapblock *minimap_mapblock = NULL; bool do_mapper_update = true; MeshUpdateResult r = m_mesh_update_thread.m_queue_out.pop_frontNoEx(); MapBlock *block = m_env.getMap().getBlockNoCreateNoEx(r.p); if (block) { // Delete the old mesh delete block->mesh; block->mesh = nullptr; if (r.mesh) { minimap_mapblock = r.mesh->moveMinimapMapblock(); if (minimap_mapblock == NULL) do_mapper_update = false; bool is_empty = true; for (int l = 0; l < MAX_TILE_LAYERS; l++) if (r.mesh->getMesh(l)->getMeshBufferCount() != 0) is_empty = false; if (is_empty) delete r.mesh; else // Replace with the new mesh block->mesh = r.mesh; } } else { delete r.mesh; } if (m_minimap && do_mapper_update) m_minimap->addBlock(r.p, minimap_mapblock); if (r.ack_block_to_server) { /* Acknowledge block [0] u8 count [1] v3s16 pos_0 */ sendGotBlocks(r.p); } } if (num_processed_meshes > 0) g_profiler->graphAdd("num_processed_meshes", num_processed_meshes); } /* Load fetched media */ if (m_media_downloader && m_media_downloader->isStarted()) { m_media_downloader->step(this); if (m_media_downloader->isDone()) { delete m_media_downloader; m_media_downloader = NULL; } } /* If the server didn't update the inventory in a while, revert the local inventory (so the player notices the lag problem and knows something is wrong). */ if(m_inventory_from_server) { float interval = 10.0; float count_before = floor(m_inventory_from_server_age / interval); m_inventory_from_server_age += dtime; float count_after = floor(m_inventory_from_server_age / interval); if(count_after != count_before) { // Do this every <interval> seconds after TOCLIENT_INVENTORY // Reset the locally changed inventory to the authoritative inventory LocalPlayer *player = m_env.getLocalPlayer(); player->inventory = *m_inventory_from_server; m_inventory_updated = true; } } /* Update positions of sounds attached to objects */ { for (auto &m_sounds_to_object : m_sounds_to_objects) { int client_id = m_sounds_to_object.first; u16 object_id = m_sounds_to_object.second; ClientActiveObject *cao = m_env.getActiveObject(object_id); if (!cao) continue; m_sound->updateSoundPosition(client_id, cao->getPosition()); } } /* Handle removed remotely initiated sounds */ m_removed_sounds_check_timer += dtime; if(m_removed_sounds_check_timer >= 2.32) { m_removed_sounds_check_timer = 0; // Find removed sounds and clear references to them std::vector<s32> removed_server_ids; for (std::unordered_map<s32, int>::iterator i = m_sounds_server_to_client.begin(); i != m_sounds_server_to_client.end();) { s32 server_id = i->first; int client_id = i->second; ++i; if(!m_sound->soundExists(client_id)) { m_sounds_server_to_client.erase(server_id); m_sounds_client_to_server.erase(client_id); m_sounds_to_objects.erase(client_id); removed_server_ids.push_back(server_id); } } // Sync to server if(!removed_server_ids.empty()) { sendRemovedSounds(removed_server_ids); } } m_mod_storage_save_timer -= dtime; if (m_mod_storage_save_timer <= 0.0f) { verbosestream << "Saving registered mod storages." << std::endl; m_mod_storage_save_timer = g_settings->getFloat("server_map_save_interval"); 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()); } } } // Write server map if (m_localdb && m_localdb_save_interval.step(dtime, m_cache_save_interval)) { m_localdb->endSave(); m_localdb->beginSave(); } }
void Client::step(float dtime) { DSTACK(FUNCTION_NAME); // Limit a bit if(dtime > 2.0) dtime = 2.0; if(m_ignore_damage_timer > dtime) m_ignore_damage_timer -= dtime; else m_ignore_damage_timer = 0.0; m_animation_time += dtime; if(m_animation_time > 60.0) m_animation_time -= 60.0; m_time_of_day_update_timer += dtime; ReceiveAll(); /* Packet counter */ { float &counter = m_packetcounter_timer; counter -= dtime; if(counter <= 0.0) { counter = 20.0; infostream << "Client packetcounter (" << m_packetcounter_timer << "):"<<std::endl; m_packetcounter.print(infostream); m_packetcounter.clear(); } } // UGLY hack to fix 2 second startup delay caused by non existent // server client startup synchronization in local server or singleplayer mode static bool initial_step = true; if (initial_step) { initial_step = false; } else if(m_state == LC_Created) { float &counter = m_connection_reinit_timer; counter -= dtime; if(counter <= 0.0) { counter = 2.0; Player *myplayer = m_env.getLocalPlayer(); FATAL_ERROR_IF(myplayer == NULL, "Local player not found in environment."); // Send TOSERVER_INIT_LEGACY // [0] u16 TOSERVER_INIT_LEGACY // [2] u8 SER_FMT_VER_HIGHEST_READ // [3] u8[20] player_name // [23] u8[28] password (new in some version) // [51] u16 minimum supported network protocol version (added sometime) // [53] u16 maximum supported network protocol version (added later than the previous one) char pName[PLAYERNAME_SIZE]; char pPassword[PASSWORD_SIZE]; memset(pName, 0, PLAYERNAME_SIZE * sizeof(char)); memset(pPassword, 0, PASSWORD_SIZE * sizeof(char)); std::string hashed_password = translatePassword(myplayer->getName(), m_password); snprintf(pName, PLAYERNAME_SIZE, "%s", myplayer->getName()); snprintf(pPassword, PASSWORD_SIZE, "%s", hashed_password.c_str()); sendLegacyInit(pName, pPassword); if (LATEST_PROTOCOL_VERSION >= 25) sendInit(myplayer->getName()); } // Not connected, return return; } /* Do stuff if connected */ /* Run Map's timers and unload unused data */ const float map_timer_and_unload_dtime = 5.25; if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime)) { ScopeProfiler sp(g_profiler, "Client: map timer and unload"); std::vector<v3s16> deleted_blocks; m_env.getMap().timerUpdate(map_timer_and_unload_dtime, g_settings->getFloat("client_unload_unused_data_timeout"), g_settings->getS32("client_mapblock_limit"), &deleted_blocks); /* Send info to server NOTE: This loop is intentionally iterated the way it is. */ std::vector<v3s16>::iterator i = deleted_blocks.begin(); std::vector<v3s16> sendlist; for(;;) { if(sendlist.size() == 255 || i == deleted_blocks.end()) { if(sendlist.empty()) break; /* [0] u16 command [2] u8 count [3] v3s16 pos_0 [3+6] v3s16 pos_1 ... */ sendDeletedBlocks(sendlist); if(i == deleted_blocks.end()) break; sendlist.clear(); } sendlist.push_back(*i); ++i; } } /* Handle environment */ // Control local player (0ms) LocalPlayer *player = m_env.getLocalPlayer(); assert(player != NULL); player->applyControl(dtime); // Step environment m_env.step(dtime); /* Get events */ for(;;) { ClientEnvEvent event = m_env.getClientEvent(); if(event.type == CEE_NONE) { break; } else if(event.type == CEE_PLAYER_DAMAGE) { if(m_ignore_damage_timer <= 0) { u8 damage = event.player_damage.amount; if(event.player_damage.send_to_server) sendDamage(damage); // Add to ClientEvent queue ClientEvent event; event.type = CE_PLAYER_DAMAGE; event.player_damage.amount = damage; m_client_event_queue.push(event); } } else if(event.type == CEE_PLAYER_BREATH) { u16 breath = event.player_breath.amount; sendBreath(breath); } } /* Print some info */ float &counter = m_avg_rtt_timer; counter += dtime; if(counter >= 10) { counter = 0.0; // connectedAndInitialized() is true, peer exists. float avg_rtt = getRTT(); infostream << "Client: avg_rtt=" << avg_rtt << std::endl; } /* Send player position to server */ { float &counter = m_playerpos_send_timer; counter += dtime; if((m_state == LC_Ready) && (counter >= m_recommended_send_interval)) { counter = 0.0; sendPlayerPos(); } } /* Replace updated meshes */ { int num_processed_meshes = 0; while (!m_mesh_update_thread.m_queue_out.empty()) { num_processed_meshes++; MinimapMapblock *minimap_mapblock = NULL; bool do_mapper_update = true; MeshUpdateResult r = m_mesh_update_thread.m_queue_out.pop_frontNoEx(); MapBlock *block = m_env.getMap().getBlockNoCreateNoEx(r.p); if (block) { // Delete the old mesh if (block->mesh != NULL) { delete block->mesh; block->mesh = NULL; } if (r.mesh) { minimap_mapblock = r.mesh->moveMinimapMapblock(); if (minimap_mapblock == NULL) do_mapper_update = false; } if (r.mesh && r.mesh->getMesh()->getMeshBufferCount() == 0) { delete r.mesh; } else { // Replace with the new mesh block->mesh = r.mesh; } } else { delete r.mesh; } if (do_mapper_update) m_mapper->addBlock(r.p, minimap_mapblock); if (r.ack_block_to_server) { /* Acknowledge block [0] u8 count [1] v3s16 pos_0 */ sendGotBlocks(r.p); } } if (num_processed_meshes > 0) g_profiler->graphAdd("num_processed_meshes", num_processed_meshes); } /* Load fetched media */ if (m_media_downloader && m_media_downloader->isStarted()) { m_media_downloader->step(this); if (m_media_downloader->isDone()) { received_media(); delete m_media_downloader; m_media_downloader = NULL; } } /* If the server didn't update the inventory in a while, revert the local inventory (so the player notices the lag problem and knows something is wrong). */ if(m_inventory_from_server) { float interval = 10.0; float count_before = floor(m_inventory_from_server_age / interval); m_inventory_from_server_age += dtime; float count_after = floor(m_inventory_from_server_age / interval); if(count_after != count_before) { // Do this every <interval> seconds after TOCLIENT_INVENTORY // Reset the locally changed inventory to the authoritative inventory Player *player = m_env.getLocalPlayer(); player->inventory = *m_inventory_from_server; m_inventory_updated = true; } } /* Update positions of sounds attached to objects */ { for(std::map<int, u16>::iterator i = m_sounds_to_objects.begin(); i != m_sounds_to_objects.end(); ++i) { int client_id = i->first; u16 object_id = i->second; ClientActiveObject *cao = m_env.getActiveObject(object_id); if(!cao) continue; v3f pos = cao->getPosition(); m_sound->updateSoundPosition(client_id, pos); } } /* Handle removed remotely initiated sounds */ m_removed_sounds_check_timer += dtime; if(m_removed_sounds_check_timer >= 2.32) { m_removed_sounds_check_timer = 0; // Find removed sounds and clear references to them std::vector<s32> removed_server_ids; for(std::map<s32, int>::iterator i = m_sounds_server_to_client.begin(); i != m_sounds_server_to_client.end();) { s32 server_id = i->first; int client_id = i->second; ++i; if(!m_sound->soundExists(client_id)) { m_sounds_server_to_client.erase(server_id); m_sounds_client_to_server.erase(client_id); m_sounds_to_objects.erase(client_id); removed_server_ids.push_back(server_id); } } // Sync to server if(!removed_server_ids.empty()) { sendRemovedSounds(removed_server_ids); } } // Write server map if (m_localdb && m_localdb_save_interval.step(dtime, m_cache_save_interval)) { m_localdb->endSave(); m_localdb->beginSave(); } }
bool Client::loadMedia(const std::string &data, const std::string &filename) { // Silly irrlicht's const-incorrectness Buffer<char> data_rw(data.c_str(), data.size()); std::string name; const char *image_ext[] = { ".png", ".jpg", ".bmp", ".tga", ".pcx", ".ppm", ".psd", ".wal", ".rgb", NULL }; name = removeStringEnd(filename, image_ext); if(name != "") { verbosestream<<"Client: Attempting to load image " <<"file \""<<filename<<"\""<<std::endl; io::IFileSystem *irrfs = m_device->getFileSystem(); video::IVideoDriver *vdrv = m_device->getVideoDriver(); // Create an irrlicht memory file io::IReadFile *rfile = irrfs->createMemoryReadFile( *data_rw, data_rw.getSize(), "_tempreadfile"); FATAL_ERROR_IF(!rfile, "Could not create irrlicht memory file."); // Read image video::IImage *img = vdrv->createImageFromFile(rfile); if(!img){ errorstream<<"Client: Cannot create image from data of " <<"file \""<<filename<<"\""<<std::endl; rfile->drop(); return false; } else { m_tsrc->insertSourceImage(filename, img); img->drop(); rfile->drop(); return true; } } const char *sound_ext[] = { ".0.ogg", ".1.ogg", ".2.ogg", ".3.ogg", ".4.ogg", ".5.ogg", ".6.ogg", ".7.ogg", ".8.ogg", ".9.ogg", ".ogg", NULL }; name = removeStringEnd(filename, sound_ext); if(name != "") { verbosestream<<"Client: Attempting to load sound " <<"file \""<<filename<<"\""<<std::endl; m_sound->loadSoundData(name, data); return true; } const char *model_ext[] = { ".x", ".b3d", ".md2", ".obj", NULL }; name = removeStringEnd(filename, model_ext); if(name != "") { verbosestream<<"Client: Storing model into memory: " <<"\""<<filename<<"\""<<std::endl; if(m_mesh_data.count(filename)) errorstream<<"Multiple models with name \""<<filename.c_str() <<"\" found; replacing previous model"<<std::endl; m_mesh_data[filename] = data; return true; } errorstream<<"Client: Don't know how to load file \"" <<filename<<"\""<<std::endl; return false; }