diff options
author | Weblate <42@minetest.ru> | 2013-06-21 10:24:16 +0200 |
---|---|---|
committer | Weblate <42@minetest.ru> | 2013-06-21 10:24:16 +0200 |
commit | 3af90db5b51da0c37f77fe6410e488c8c27acd67 (patch) | |
tree | 12edd6f0661b464e36863517241b5ec0b87b5ec1 /src | |
parent | 58f3cd3eb598a7cf79983fe9e48c738591c6e004 (diff) | |
parent | b1ebd9f79c63cf78b0e0fb2ea6f52d82cdfb95b6 (diff) | |
download | minetest-3af90db5b51da0c37f77fe6410e488c8c27acd67.tar.gz minetest-3af90db5b51da0c37f77fe6410e488c8c27acd67.tar.bz2 minetest-3af90db5b51da0c37f77fe6410e488c8c27acd67.zip |
Merge remote-tracking branch 'origin/master'
Diffstat (limited to 'src')
45 files changed, 997 insertions, 200 deletions
diff --git a/src/biome.cpp b/src/biome.cpp index b50c562a0..bc84d4bc1 100644 --- a/src/biome.cpp +++ b/src/biome.cpp @@ -168,3 +168,13 @@ Biome *BiomeDefManager::getBiome(float heat, float humidity, s16 y) { return biome_closest ? biome_closest : biomes[0]; } + + +u8 BiomeDefManager::getBiomeIdByName(const char *name) { + for (size_t i = 0; i != biomes.size(); i++) { + if (!strcasecmp(name, biomes[i]->name.c_str())) + return i; + } + + return 0; +} diff --git a/src/biome.h b/src/biome.h index 17703db5a..535dc4989 100644 --- a/src/biome.h +++ b/src/biome.h @@ -84,6 +84,7 @@ public: void addBiome(Biome *b); void resolveNodeNames(INodeDefManager *ndef); + u8 getBiomeIdByName(const char *name); }; #endif diff --git a/src/client.cpp b/src/client.cpp index 6b1789fe0..5f53e14f7 100644 --- a/src/client.cpp +++ b/src/client.cpp @@ -2680,6 +2680,13 @@ u16 Client::getHP() return player->hp; } +u16 Client::getBreath() +{ + Player *player = m_env.getLocalPlayer(); + assert(player != NULL); + return player->breath; +} + bool Client::getChatMessage(std::wstring &message) { if(m_chat_queue.size() == 0) diff --git a/src/client.h b/src/client.h index f0cc55868..1d231a5a3 100644 --- a/src/client.h +++ b/src/client.h @@ -349,6 +349,7 @@ public: void setCrack(int level, v3s16 pos); u16 getHP(); + u16 getBreath(); bool checkPrivilege(const std::string &priv) { return (m_privileges.count(priv) != 0); } diff --git a/src/defaultsettings.cpp b/src/defaultsettings.cpp index f270a47aa..ffaa7a3c7 100644 --- a/src/defaultsettings.cpp +++ b/src/defaultsettings.cpp @@ -175,6 +175,7 @@ void set_default_settings(Settings *settings) settings->setDefault("max_simultaneous_block_sends_server_total", "20"); settings->setDefault("max_block_send_distance", "9"); settings->setDefault("max_block_generate_distance", "7"); + settings->setDefault("max_clearobjects_extra_loaded_blocks", "4096"); settings->setDefault("time_send_interval", "5"); settings->setDefault("time_speed", "72"); settings->setDefault("server_unload_unused_data_timeout", "29"); @@ -208,6 +209,7 @@ void set_default_settings(Settings *settings) //liquid stuff settings->setDefault("liquid_finite", "false"); + settings->setDefault("liquid_loop_max", "1000"); settings->setDefault("liquid_update", "1.0"); settings->setDefault("liquid_relax", "2"); settings->setDefault("liquid_fast_flood", "1"); @@ -238,7 +240,7 @@ void set_default_settings(Settings *settings) settings->setDefault("mgv7_np_terrain_mod", "0, 1, (350, 350, 350), 85039, 5, 0.6"); settings->setDefault("mgv7_np_terrain_persist", "0, 1, (500, 500, 500), 539, 3, 0.6"); settings->setDefault("mgv7_np_height_select", "0.5, 0.5, (250, 250, 250), 4213, 5, 0.69"); - settings->setDefault("mgv7_np_ridge", "0.5, 1, (100, 100, 100), 6467, 4, 0.75"); + settings->setDefault("mgv7_np_ridge", "0, 1, (100, 100, 100), 6467, 4, 0.75"); settings->setDefault("mgindev_np_terrain_base", "-4, 20, (250, 250, 250), 82341, 5, 0.6, 10, 10"); settings->setDefault("mgindev_np_terrain_higher", "20, 16, (500, 500, 500), 85039, 5, 0.6, 10, 10"); diff --git a/src/emerge.cpp b/src/emerge.cpp index fd6c0e91f..9edc42b7b 100644 --- a/src/emerge.cpp +++ b/src/emerge.cpp @@ -101,6 +101,10 @@ EmergeManager::~EmergeManager() { for (unsigned int i = 0; i < ores.size(); i++) delete ores[i]; ores.clear(); + + for (unsigned int i = 0; i < decorations.size(); i++) + delete decorations[i]; + decorations.clear(); for (std::map<std::string, MapgenFactory *>::iterator iter = mglist.begin(); iter != mglist.end(); iter ++) { @@ -119,9 +123,13 @@ void EmergeManager::initMapgens(MapgenParams *mgparams) { return; biomedef->resolveNodeNames(ndef); + for (size_t i = 0; i != ores.size(); i++) + ores[i]->resolveNodeNames(ndef); + for (size_t i = 0; i != decorations.size(); i++) + decorations[i]->resolveNodeNames(ndef); this->params = mgparams; - for (unsigned int i = 0; i != emergethread.size(); i++) { + for (size_t i = 0; i != emergethread.size(); i++) { mg = createMapgen(params->mg_name, 0, params); if (!mg) { infostream << "EmergeManager: falling back to mapgen v6" << std::endl; diff --git a/src/emerge.h b/src/emerge.h index b42e82d38..084956932 100644 --- a/src/emerge.h +++ b/src/emerge.h @@ -87,6 +87,7 @@ public: //Mapgen-related structures BiomeDefManager *biomedef; std::vector<Ore *> ores; + std::vector<Decoration *> decorations; EmergeManager(IGameDef *gamedef); ~EmergeManager(); diff --git a/src/environment.cpp b/src/environment.cpp index 83ae59014..99da5190c 100644 --- a/src/environment.cpp +++ b/src/environment.cpp @@ -40,6 +40,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #ifndef SERVER #include "clientmap.h" #include "localplayer.h" +#include "event.h" #endif #include "daynightratio.h" #include "map.h" @@ -945,6 +946,16 @@ void ServerEnvironment::clearAllObjects() m_active_objects.erase(*i); } + // Get list of loaded blocks + std::list<v3s16> loaded_blocks; + infostream<<"ServerEnvironment::clearAllObjects(): " + <<"Listing all loaded blocks"<<std::endl; + m_map->listAllLoadedBlocks(loaded_blocks); + infostream<<"ServerEnvironment::clearAllObjects(): " + <<"Done listing all loaded blocks: " + <<loaded_blocks.size()<<std::endl; + + // Get list of loadable blocks std::list<v3s16> loadable_blocks; infostream<<"ServerEnvironment::clearAllObjects(): " <<"Listing all loadable blocks"<<std::endl; @@ -953,6 +964,20 @@ void ServerEnvironment::clearAllObjects() <<"Done listing all loadable blocks: " <<loadable_blocks.size() <<", now clearing"<<std::endl; + + // Grab a reference on each loaded block to avoid unloading it + for(std::list<v3s16>::iterator i = loaded_blocks.begin(); + i != loaded_blocks.end(); ++i) + { + v3s16 p = *i; + MapBlock *block = m_map->getBlockNoCreateNoEx(p); + assert(block); + block->refGrab(); + } + + // Remove objects in all loadable blocks + u32 unload_interval = g_settings->getS32("max_clearobjects_extra_loaded_blocks"); + unload_interval = MYMAX(unload_interval, 1); u32 report_interval = loadable_blocks.size() / 10; u32 num_blocks_checked = 0; u32 num_blocks_cleared = 0; @@ -987,7 +1012,22 @@ void ServerEnvironment::clearAllObjects() <<" in "<<num_blocks_cleared<<" blocks (" <<percent<<"%)"<<std::endl; } + if(num_blocks_checked % unload_interval == 0){ + m_map->unloadUnreferencedBlocks(); + } } + m_map->unloadUnreferencedBlocks(); + + // Drop references that were added above + for(std::list<v3s16>::iterator i = loaded_blocks.begin(); + i != loaded_blocks.end(); ++i) + { + v3s16 p = *i; + MapBlock *block = m_map->getBlockNoCreateNoEx(p); + assert(block); + block->refDrop(); + } + infostream<<"ServerEnvironment::clearAllObjects(): " <<"Finished: Cleared "<<num_objs_cleared<<" objects" <<" in "<<num_blocks_cleared<<" blocks"<<std::endl; @@ -2151,8 +2191,11 @@ void ClientEnvironment::step(float dtime) { f32 damage_f = (speed - tolerance)/BS * post_factor; u16 damage = (u16)(damage_f+0.5); - if(damage != 0) + if(damage != 0){ damageLocalPlayer(damage, true); + MtEvent *e = new SimpleTriggerEvent("PlayerFallingDamage"); + m_gamedef->event()->put(e); + } } } @@ -2184,7 +2227,45 @@ void ClientEnvironment::step(float dtime) damageLocalPlayer(damage_per_second, true); } } - + + /* + Drowning + */ + if(m_drowning_interval.step(dtime, 2.0)) + { + v3f pf = lplayer->getPosition(); + + // head + v3s16 p = floatToInt(pf + v3f(0, BS*1.6, 0), BS); + MapNode n = m_map->getNodeNoEx(p); + ContentFeatures c = m_gamedef->ndef()->get(n); + + if(c.isLiquid() && c.drowning){ + if(lplayer->breath > 10) + lplayer->breath = 11; + if(lplayer->breath > 0) + lplayer->breath -= 1; + } + + if(lplayer->breath == 0){ + damageLocalPlayer(1, true); + } + } + if(m_breathing_interval.step(dtime, 0.5)) + { + v3f pf = lplayer->getPosition(); + + // head + v3s16 p = floatToInt(pf + v3f(0, BS*1.6, 0), BS); + MapNode n = m_map->getNodeNoEx(p); + ContentFeatures c = m_gamedef->ndef()->get(n); + + if(!c.isLiquid() || !c.drowning){ + if(lplayer->breath <= 10) + lplayer->breath += 1; + } + } + /* Stuff that can be done in an arbitarily large dtime */ @@ -2221,6 +2302,7 @@ void ClientEnvironment::step(float dtime) Step active objects and update lighting of them */ + g_profiler->avg("CEnv: num of objects", m_active_objects.size()); bool update_lighting = m_active_object_light_update_interval.step(dtime, 0.21); for(std::map<u16, ClientActiveObject*>::iterator i = m_active_objects.begin(); @@ -2250,6 +2332,7 @@ void ClientEnvironment::step(float dtime) /* Step and handle simple objects */ + g_profiler->avg("CEnv: num of simple objects", m_simple_objects.size()); for(std::list<ClientSimpleObject*>::iterator i = m_simple_objects.begin(); i != m_simple_objects.end();) { diff --git a/src/environment.h b/src/environment.h index a62173a11..ac479999c 100644 --- a/src/environment.h +++ b/src/environment.h @@ -494,6 +494,8 @@ private: Queue<ClientEnvEvent> m_client_event_queue; IntervalLimiter m_active_object_light_update_interval; IntervalLimiter m_lava_hurt_interval; + IntervalLimiter m_drowning_interval; + IntervalLimiter m_breathing_interval; std::list<std::string> m_player_names; }; diff --git a/src/game.cpp b/src/game.cpp index 22bd8c429..833117959 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -729,6 +729,18 @@ public: sm->m_sound->playSound(sm->m_ndef->get(nde->n).sound_dug, false); } + static void playerDamage(MtEvent *e, void *data) + { + SoundMaker *sm = (SoundMaker*)data; + sm->m_sound->playSound(SimpleSoundSpec("player_damage", 0.5), false); + } + + static void playerFallingDamage(MtEvent *e, void *data) + { + SoundMaker *sm = (SoundMaker*)data; + sm->m_sound->playSound(SimpleSoundSpec("player_falling_damage", 0.5), false); + } + void registerReceiver(MtEventManager *mgr) { mgr->reg("ViewBobbingStep", SoundMaker::viewBobbingStep, this); @@ -737,6 +749,8 @@ public: mgr->reg("CameraPunchLeft", SoundMaker::cameraPunchLeft, this); mgr->reg("CameraPunchRight", SoundMaker::cameraPunchRight, this); mgr->reg("NodeDug", SoundMaker::nodeDug, this); + mgr->reg("PlayerDamage", SoundMaker::playerDamage, this); + mgr->reg("PlayerFallingDamage", SoundMaker::playerFallingDamage, this); } void step(float dtime) @@ -820,7 +834,7 @@ public: } }; -void nodePlacementPrediction(Client &client, +bool nodePlacementPrediction(Client &client, const ItemDefinition &playeritem_def, v3s16 nodepos, v3s16 neighbourpos) { @@ -840,7 +854,7 @@ void nodePlacementPrediction(Client &client, if(nodedef->get(n_under).buildable_to) p = nodepos; else if (!nodedef->get(map.getNode(p)).buildable_to) - return; + return false; }catch(InvalidPositionException &e){} // Find id of predicted node content_t id; @@ -850,7 +864,7 @@ void nodePlacementPrediction(Client &client, <<playeritem_def.name<<" (places " <<prediction <<") - Name not known"<<std::endl; - return; + return false; } // Predict param2 for facedir and wallmounted nodes u8 param2 = 0; @@ -889,13 +903,14 @@ void nodePlacementPrediction(Client &client, else pp = p + v3s16(0,-1,0); if(!nodedef->get(map.getNode(pp)).walkable) - return; + return false; } // Add node to client map MapNode n(id, 0, param2); try{ // This triggers the required mesh update too client.addNode(p, n); + return true; }catch(InvalidPositionException &e){ errorstream<<"Node placement prediction failed for " <<playeritem_def.name<<" (places " @@ -903,6 +918,7 @@ void nodePlacementPrediction(Client &client, <<") - Position not loaded"<<std::endl; } } + return false; } @@ -1366,6 +1382,7 @@ void the_game( false, false); guitext_profiler->setBackgroundColor(video::SColor(120,0,0,0)); guitext_profiler->setVisible(false); + guitext_profiler->setWordWrap(true); /* Some statistics are collected in these @@ -1684,6 +1701,10 @@ void the_game( { input->clear(); } + if (!guienv->hasFocus(gui_chat_console) && gui_chat_console->isOpen()) + { + gui_chat_console->closeConsoleAtOnce(); + } // Input handler step() (used by the random input generator) input->step(dtime); @@ -2198,6 +2219,9 @@ void the_game( player->hurt_tilt_timer = 1.5; player->hurt_tilt_strength = event.player_damage.amount/2; player->hurt_tilt_strength = rangelim(player->hurt_tilt_strength, 2.0, 10.0); + + MtEvent *e = new SimpleTriggerEvent("PlayerDamage"); + gamedef->event()->put(e); } else if(event.type == CE_PLAYER_FORCE_MOVE) { @@ -2567,7 +2591,8 @@ void the_game( Handle digging */ - if(nodig_delay_timer <= 0.0 && input->getLeftState()) + if(nodig_delay_timer <= 0.0 && input->getLeftState() + && client.checkPrivilege("interact")) { if(!digging) { @@ -2684,13 +2709,20 @@ void the_game( gamedef->event()->put(e); } - dig_time += dtime; + if(dig_time_complete < 100000.0) + dig_time += dtime; + else { + dig_time = 0; + client.setCrack(-1, nodepos); + } camera.setDigging(0); // left click animation } - if(input->getRightClicked() || - repeat_rightclick_timer >= g_settings->getFloat("repeat_rightclick_time")) + if((input->getRightClicked() || + repeat_rightclick_timer >= + g_settings->getFloat("repeat_rightclick_time")) && + client.checkPrivilege("interact")) { repeat_rightclick_timer = 0; infostream<<"Ground right-clicked"<<std::endl; @@ -2744,13 +2776,17 @@ void the_game( // If the wielded item has node placement prediction, // make that happen - nodePlacementPrediction(client, + bool placed = nodePlacementPrediction(client, playeritem_def, nodepos, neighbourpos); // Read the sound - soundmaker.m_player_rightpunch_sound = - playeritem_def.sound_place; + if(placed) + soundmaker.m_player_rightpunch_sound = + playeritem_def.sound_place; + else + soundmaker.m_player_rightpunch_sound = + SimpleSoundSpec(); } } } @@ -3283,7 +3319,7 @@ void the_game( if (show_hud) { hud.drawHotbar(v2s32(displaycenter.X, screensize.Y), - client.getHP(), client.getPlayerItem()); + client.getHP(), client.getPlayerItem(), client.getBreath()); } /* diff --git a/src/guiChatConsole.cpp b/src/guiChatConsole.cpp index 3dfd0090a..daec18efc 100644 --- a/src/guiChatConsole.cpp +++ b/src/guiChatConsole.cpp @@ -134,6 +134,11 @@ void GUIChatConsole::openConsole(f32 height) reformatConsole(); } +bool GUIChatConsole::isOpen() const +{ + return m_open; +} + bool GUIChatConsole::isOpenInhibited() const { return m_open_inhibited > 0; @@ -545,7 +550,13 @@ bool GUIChatConsole::OnEvent(const SEvent& event) } else if(event.KeyInput.Char != 0 && !event.KeyInput.Control) { - m_chat_backend->getPrompt().input(event.KeyInput.Char); + #if (defined(linux) || defined(__linux)) + wchar_t wc = L'_'; + mbtowc( &wc, (char *) &event.KeyInput.Char, sizeof(event.KeyInput.Char) ); + m_chat_backend->getPrompt().input(wc); + #else + m_chat_backend->getPrompt().input(event.KeyInput.Char); + #endif return true; } } diff --git a/src/guiChatConsole.h b/src/guiChatConsole.h index c896aae28..5991157b2 100644 --- a/src/guiChatConsole.h +++ b/src/guiChatConsole.h @@ -39,6 +39,9 @@ public: // This doesn't open immediately but initiates an animation. // You should call isOpenInhibited() before this. void openConsole(f32 height); + + bool isOpen() const; + // Check if the console should not be opened at the moment // This is to avoid reopening the console immediately after closing bool isOpenInhibited() const; diff --git a/src/guiFormSpecMenu.cpp b/src/guiFormSpecMenu.cpp index 3e0d7fd46..c1b256f08 100644 --- a/src/guiFormSpecMenu.cpp +++ b/src/guiFormSpecMenu.cpp @@ -698,7 +698,7 @@ void GUIFormSpecMenu::drawList(const ListDrawSpec &s, int phase) bool selected = m_selected_item && m_invmgr->getInventory(m_selected_item->inventoryloc) == inv && m_selected_item->listname == s.listname - && m_selected_item->i == i; + && m_selected_item->i == item_i; bool hovering = rect.isPointInside(m_pointer); if(phase == 0) @@ -912,11 +912,20 @@ void GUIFormSpecMenu::drawMenu() void GUIFormSpecMenu::updateSelectedItem() { + // If the selected stack has become empty for some reason, deselect it. + // If the selected stack has become inaccessible, deselect it. + // If the selected stack has become smaller, adjust m_selected_amount. + ItemStack selected = verifySelectedItem(); + // WARNING: BLACK MAGIC // See if there is a stack suited for our current guess. // If such stack does not exist, clear the guess. - if(m_selected_content_guess.name != "") - { + if(m_selected_content_guess.name != "" && + selected.name == m_selected_content_guess.name && + selected.count == m_selected_content_guess.count){ + // Selected item fits the guess. Skip the black magic. + } + else if(m_selected_content_guess.name != ""){ bool found = false; for(u32 i=0; i<m_inventorylists.size() && !found; i++){ const ListDrawSpec &s = m_inventorylists[i]; @@ -934,23 +943,12 @@ void GUIFormSpecMenu::updateSelectedItem() if(stack.name == m_selected_content_guess.name && stack.count == m_selected_content_guess.count){ found = true; - if(m_selected_item){ - // If guessed stack is already selected, all is fine - if(m_selected_item->inventoryloc == s.inventoryloc && - m_selected_item->listname == s.listname && - m_selected_item->i == (s32)item_i && - m_selected_amount == stack.count){ - break; - } - delete m_selected_item; - m_selected_item = NULL; - } infostream<<"Client: Changing selected content guess to " <<s.inventoryloc.dump()<<" "<<s.listname <<" "<<item_i<<std::endl; + delete m_selected_item; m_selected_item = new ItemSpec(s.inventoryloc, s.listname, item_i); m_selected_amount = stack.count; - break; } } } @@ -960,35 +958,6 @@ void GUIFormSpecMenu::updateSelectedItem() m_selected_content_guess.name = ""; } } - // If the selected stack has become empty for some reason, deselect it. - // If the selected stack has become smaller, adjust m_selected_amount. - if(m_selected_item) - { - bool selection_valid = false; - if(m_selected_item->isValid()) - { - Inventory *inv = m_invmgr->getInventory(m_selected_item->inventoryloc); - if(inv) - { - InventoryList *list = inv->getList(m_selected_item->listname); - if(list && (u32) m_selected_item->i < list->getSize()) - { - ItemStack stack = list->getItem(m_selected_item->i); - if(m_selected_amount > stack.count) - m_selected_amount = stack.count; - if(!stack.empty()) - selection_valid = true; - } - } - } - if(!selection_valid) - { - delete m_selected_item; - m_selected_item = NULL; - m_selected_amount = 0; - m_selected_dragging = false; - } - } // If craftresult is nonempty and nothing else is selected, select it now. if(!m_selected_item) @@ -1017,12 +986,43 @@ void GUIFormSpecMenu::updateSelectedItem() // If craftresult is selected, keep the whole stack selected if(m_selected_item && m_selected_item->listname == "craftresult") { - Inventory *inv = m_invmgr->getInventory(m_selected_item->inventoryloc); - assert(inv); - InventoryList *list = inv->getList(m_selected_item->listname); - assert(list); - m_selected_amount = list->getItem(m_selected_item->i).count; + m_selected_amount = verifySelectedItem().count; + } +} + +ItemStack GUIFormSpecMenu::verifySelectedItem() +{ + // If the selected stack has become empty for some reason, deselect it. + // If the selected stack has become inaccessible, deselect it. + // If the selected stack has become smaller, adjust m_selected_amount. + // Return the selected stack. + + if(m_selected_item) + { + if(m_selected_item->isValid()) + { + Inventory *inv = m_invmgr->getInventory(m_selected_item->inventoryloc); + if(inv) + { + InventoryList *list = inv->getList(m_selected_item->listname); + if(list && (u32) m_selected_item->i < list->getSize()) + { + ItemStack stack = list->getItem(m_selected_item->i); + if(m_selected_amount > stack.count) + m_selected_amount = stack.count; + if(!stack.empty()) + return stack; + } + } + } + + // selection was not valid + delete m_selected_item; + m_selected_item = NULL; + m_selected_amount = 0; + m_selected_dragging = false; } + return ItemStack(); } void GUIFormSpecMenu::acceptInput() diff --git a/src/guiFormSpecMenu.h b/src/guiFormSpecMenu.h index 17b202b18..ae985adde 100644 --- a/src/guiFormSpecMenu.h +++ b/src/guiFormSpecMenu.h @@ -186,6 +186,7 @@ public: void drawSelectedItem(); void drawMenu(); void updateSelectedItem(); + ItemStack verifySelectedItem(); void acceptInput(); bool OnEvent(const SEvent& event); diff --git a/src/hud.cpp b/src/hud.cpp index a3ae38bcb..9404ed997 100644 --- a/src/hud.cpp +++ b/src/hud.cpp @@ -278,7 +278,7 @@ void Hud::drawStatbar(v2s32 pos, u16 corner, u16 drawdir, std::string texture, s } -void Hud::drawHotbar(v2s32 centerlowerpos, s32 halfheartcount, u16 playeritem) { +void Hud::drawHotbar(v2s32 centerlowerpos, s32 halfheartcount, u16 playeritem, s32 breath) { InventoryList *mainlist = inventory->getList("main"); if (mainlist == NULL) { errorstream << "draw_hotbar(): mainlist == NULL" << std::endl; @@ -295,6 +295,9 @@ void Hud::drawHotbar(v2s32 centerlowerpos, s32 halfheartcount, u16 playeritem) { if (player->hud_flags & HUD_FLAG_HEALTHBAR_VISIBLE) drawStatbar(pos - v2s32(0, 4), HUD_CORNER_LOWER, HUD_DIR_LEFT_RIGHT, "heart.png", halfheartcount, v2s32(0, 0)); + if (player->hud_flags & HUD_FLAG_BREATHBAR_VISIBLE && breath <= 10) + drawStatbar(pos - v2s32(-180, 4), HUD_CORNER_LOWER, HUD_DIR_LEFT_RIGHT, + "bubble.png", breath*2, v2s32(0, 0)); } @@ -35,6 +35,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #define HUD_FLAG_HEALTHBAR_VISIBLE (1 << 1) #define HUD_FLAG_CROSSHAIR_VISIBLE (1 << 2) #define HUD_FLAG_WIELDITEM_VISIBLE (1 << 3) +#define HUD_FLAG_BREATHBAR_VISIBLE (1 << 4) #define HUD_PARAM_HOTBAR_ITEMCOUNT 1 @@ -122,7 +123,7 @@ public: void drawStatbar(v2s32 pos, u16 corner, u16 drawdir, std::string texture, s32 count, v2s32 offset); - void drawHotbar(v2s32 centerlowerpos, s32 halfheartcount, u16 playeritem); + void drawHotbar(v2s32 centerlowerpos, s32 halfheartcount, u16 playeritem, s32 breath); void resizeHotbar(); void drawCrosshair(); diff --git a/src/map.cpp b/src/map.cpp index 43502253b..001ae1609 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -1510,6 +1510,11 @@ void Map::timerUpdate(float dtime, float unload_timeout, } } +void Map::unloadUnreferencedBlocks(std::list<v3s16> *unloaded_blocks) +{ + timerUpdate(0.0, -1.0, unloaded_blocks); +} + void Map::deleteSectors(std::list<v2s16> &list) { for(std::list<v2s16>::iterator j = list.begin(); @@ -1646,10 +1651,12 @@ void Map::transformLiquidsFinite(std::map<v3s16, MapBlock*> & modified_blocks) // List of MapBlocks that will require a lighting update (due to lava) std::map<v3s16, MapBlock*> lighting_modified_blocks; + u16 loop_max = g_settings->getU16("liquid_loop_max"); + while (m_transforming_liquid.size() > 0) { // This should be done here so that it is done when continue is used - if (loopcount >= initial_size || loopcount >= 1000) + if (loopcount >= initial_size || loopcount >= loop_max) break; loopcount++; /* @@ -1988,10 +1995,12 @@ void Map::transformLiquids(std::map<v3s16, MapBlock*> & modified_blocks) // List of MapBlocks that will require a lighting update (due to lava) std::map<v3s16, MapBlock*> lighting_modified_blocks; + u16 loop_max = g_settings->getU16("liquid_loop_max"); + while(m_transforming_liquid.size() != 0) { // This should be done here so that it is done when continue is used - if(loopcount >= initial_size || loopcount >= 10000) + if(loopcount >= initial_size || loopcount >= loop_max) break; loopcount++; @@ -3409,6 +3418,26 @@ void ServerMap::listAllLoadableBlocks(std::list<v3s16> &dst) } } +void ServerMap::listAllLoadedBlocks(std::list<v3s16> &dst) +{ + for(std::map<v2s16, MapSector*>::iterator si = m_sectors.begin(); + si != m_sectors.end(); ++si) + { + MapSector *sector = si->second; + + std::list<MapBlock*> blocks; + sector->getBlocks(blocks); + + for(std::list<MapBlock*>::iterator i = blocks.begin(); + i != blocks.end(); ++i) + { + MapBlock *block = (*i); + v3s16 p = block->getPos(); + dst.push_back(p); + } + } +} + void ServerMap::saveMapMeta() { DSTACK(__FUNCTION_NAME); @@ -279,6 +279,12 @@ public: void timerUpdate(float dtime, float unload_timeout, std::list<v3s16> *unloaded_blocks=NULL); + /* + Unloads all blocks with a zero refCount(). + Saves modified blocks before unloading on MAPTYPE_SERVER. + */ + void unloadUnreferencedBlocks(std::list<v3s16> *unloaded_blocks=NULL); + // Deletes sectors and their blocks from memory // Takes cache into account // If deleted sector is in sector cache, clears cache @@ -433,8 +439,8 @@ public: void endSave(); void save(ModifiedState save_level); - //void loadAll(); void listAllLoadableBlocks(std::list<v3s16> &dst); + void listAllLoadedBlocks(std::list<v3s16> &dst); // Saves map seed and possibly other stuff void saveMapMeta(); void loadMapMeta(); diff --git a/src/mapblock_mesh.cpp b/src/mapblock_mesh.cpp index 0f83e863c..be88b1973 100644 --- a/src/mapblock_mesh.cpp +++ b/src/mapblock_mesh.cpp @@ -717,8 +717,7 @@ TileSpec getNodeTile(MapNode mn, v3s16 p, v3s16 dir, MeshMakeData *data) u16 tile_index=facedir*16 + dir_i; TileSpec spec = getNodeTileN(mn, p, dir_to_tile[tile_index], data); spec.rotation=dir_to_tile[tile_index + 1]; - std::string name = data->m_gamedef->tsrc()->getTextureName(spec.texture.id); - spec.texture = data->m_gamedef->tsrc()->getTexture(name); + spec.texture = data->m_gamedef->tsrc()->getTexture(spec.texture.id); return spec; } @@ -1200,7 +1199,6 @@ MapBlockMesh::MapBlockMesh(MeshMakeData *data): */ translateMesh(m_mesh, intToFloat(data->m_blockpos * MAP_BLOCKSIZE, BS)); - m_mesh->recalculateBoundingBox(); // translateMesh already does this if(m_mesh) { diff --git a/src/mapgen.cpp b/src/mapgen.cpp index 835c14be1..72757f4fa 100644 --- a/src/mapgen.cpp +++ b/src/mapgen.cpp @@ -87,7 +87,7 @@ void Ore::resolveNodeNames(INodeDefManager *ndef) { wherein = CONTENT_AIR; } } - + if (wherein == CONTENT_IGNORE) { wherein = ndef->getId(wherein_name); if (wherein == CONTENT_IGNORE) { @@ -109,10 +109,7 @@ void Ore::placeOre(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax) { if (!in_range) return; - resolveNodeNames(mg->ndef); - int ymin, ymax; - if (in_range & ORE_RANGE_MIRROR) { ymin = MYMAX(nmin.Y, -height_max); ymax = MYMIN(nmax.Y, -height_min); @@ -122,7 +119,7 @@ void Ore::placeOre(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax) { } if (clust_size >= ymax - ymin + 1) return; - + nmin.Y = ymin; nmax.Y = ymax; generate(mg->vm, mg->seed, blockseed, nmin, nmax); @@ -130,7 +127,7 @@ void Ore::placeOre(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax) { void OreScatter::generate(ManualMapVoxelManipulator *vm, int seed, - u32 blockseed, v3s16 nmin, v3s16 nmax) { + u32 blockseed, v3s16 nmin, v3s16 nmax) { PseudoRandom pr(blockseed); MapNode n_ore(ore, 0, ore_param2); @@ -145,16 +142,16 @@ void OreScatter::generate(ManualMapVoxelManipulator *vm, int seed, int x0 = pr.range(nmin.X, nmax.X - csize + 1); int y0 = pr.range(nmin.Y, nmax.Y - csize + 1); int z0 = pr.range(nmin.Z, nmax.Z - csize + 1); - + if (np && (NoisePerlin3D(np, x0, y0, z0, seed) < nthresh)) continue; - + for (int z1 = 0; z1 != csize; z1++) for (int y1 = 0; y1 != csize; y1++) for (int x1 = 0; x1 != csize; x1++) { if (pr.range(1, orechance) != 1) continue; - + u32 i = vm->m_area.index(x0 + x1, y0 + y1, z0 + z1); if (vm->m_data[i].getContent() == wherein) vm->m_data[i] = n_ore; @@ -167,10 +164,10 @@ void OreSheet::generate(ManualMapVoxelManipulator *vm, int seed, u32 blockseed, v3s16 nmin, v3s16 nmax) { PseudoRandom pr(blockseed + 4234); MapNode n_ore(ore, 0, ore_param2); - + int max_height = clust_size; int y_start = pr.range(nmin.Y, nmax.Y - max_height); - + if (!noise) { int sx = nmax.X - nmin.X + 1; int sz = nmax.Z - nmin.Z + 1; @@ -178,14 +175,14 @@ void OreSheet::generate(ManualMapVoxelManipulator *vm, int seed, } noise->seed = seed + y_start; noise->perlinMap2D(nmin.X, nmin.Z); - + int index = 0; for (int z = nmin.Z; z <= nmax.Z; z++) for (int x = nmin.X; x <= nmax.X; x++) { float noiseval = noise->result[index++]; if (noiseval < nthresh) continue; - + int height = max_height * (1. / pr.range(1, 3)); int y0 = y_start + np->scale * noiseval; //pr.range(1, 3) - 1; int y1 = y0 + height; @@ -193,7 +190,7 @@ void OreSheet::generate(ManualMapVoxelManipulator *vm, int seed, u32 i = vm->m_area.index(x, y, z); if (!vm->m_area.contains(i)) continue; - + if (vm->m_data[i].getContent() == wherein) vm->m_data[i] = n_ore; } @@ -201,6 +198,325 @@ void OreSheet::generate(ManualMapVoxelManipulator *vm, int seed, } +Decoration *createDecoration(DecorationType type) { + switch (type) { + case DECO_SIMPLE: + return new DecoSimple; + //case DECO_SCHEMATIC: + // return new DecoSchematic; + //case DECO_LSYSTEM: + // return new DecoLSystem; + default: + return NULL; + } +} + + +Decoration::~Decoration() { + delete np; +} + + +void Decoration::resolveNodeNames(INodeDefManager *ndef) { + if (c_place_on == CONTENT_IGNORE) + c_place_on = ndef->getId(place_on_name); +} + + +void Decoration::placeDeco(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax) { + PseudoRandom ps(blockseed + 53); + int carea_size = nmax.X - nmin.X + 1; + + // Divide area into parts + if (carea_size % sidelen) { + errorstream << "Decoration::placeDeco: chunk size is not divisible by " + "sidelen; setting sidelen to " << carea_size << std::endl; + sidelen = carea_size; + } + + s16 divlen = carea_size / sidelen; + int area = sidelen * sidelen; + + for (s16 z0 = 0; z0 < divlen; z0++) + for (s16 x0 = 0; x0 < divlen; x0++) { + v2s16 p2d_center( // Center position of part of division + nmin.X + sidelen / 2 + sidelen * x0, + nmin.Z + sidelen / 2 + sidelen * z0 + ); + v2s16 p2d_min( // Minimum edge of part of division + nmin.X + sidelen * x0, + nmin.Z + sidelen * z0 + ); + v2s16 p2d_max( // Maximum edge of part of division + nmin.X + sidelen + sidelen * x0 - 1, + nmin.Z + sidelen + sidelen * z0 - 1 + ); + + // Amount of decorations + float nval = np ? + NoisePerlin2D(np, p2d_center.X, p2d_center.Y, mapseed) : + fill_ratio; + u32 deco_count = area * MYMAX(nval, 0.f); + + for (u32 i = 0; i < deco_count; i++) { + s16 x = ps.range(p2d_min.X, p2d_max.X); + s16 z = ps.range(p2d_min.Y, p2d_max.Y); + + int mapindex = carea_size * (z - nmin.Z) + (x - nmin.X); + + s16 y = mg->heightmap ? + mg->heightmap[mapindex] : + mg->findGroundLevel(v2s16(x, z), nmin.Y, nmax.Y); + + if (y < nmin.Y || y > nmax.Y) + continue; + + int height = getHeight(); + int max_y = nmax.Y + MAP_BLOCKSIZE; + if (y + 1 + height > max_y) { + continue; +#if 0 + printf("Decoration at (%d %d %d) cut off\n", x, y, z); + //add to queue + JMutexAutoLock cutofflock(cutoff_mutex); + cutoffs.push_back(CutoffData(x, y, z, height)); +#endif + } + + if (mg->biomemap) { + std::set<u8>::iterator iter; + + if (biomes.size()) { + iter = biomes.find(mg->biomemap[mapindex]); + if (iter == biomes.end()) + continue; + } + } + + generate(mg, &ps, max_y, 0, v3s16(x, y, z)); + } + } +} + + +#if 0 +void Decoration::placeCutoffs(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax) { + PseudoRandom pr(blockseed + 53); + std::vector<CutoffData> handled_cutoffs; + + // Copy over the cutoffs we're interested in so we don't needlessly hold a lock + { + JMutexAutoLock cutofflock(cutoff_mutex); + for (std::list<CutoffData>::iterator i = cutoffs.begin(); + i != cutoffs.end(); ++i) { + CutoffData cutoff = *i; + v3s16 p = cutoff.p; + s16 height = cutoff.height; + if (p.X < nmin.X || p.X > nmax.X || + p.Z < nmin.Z || p.Z > nmax.Z) + continue; + if (p.Y + height < nmin.Y || p.Y > nmax.Y) + continue; + + handled_cutoffs.push_back(cutoff); + } + } + + // Generate the cutoffs + for (size_t i = 0; i != handled_cutoffs.size(); i++) { + v3s16 p = handled_cutoffs[i].p; + s16 height = handled_cutoffs[i].height; + + if (p.Y + height > nmax.Y) { + //printf("Decoration at (%d %d %d) cut off again!\n", p.X, p.Y, p.Z); + cuttoffs.push_back(v3s16(p.X, p.Y, p.Z)); + } + + generate(mg, &pr, nmax.Y, nmin.Y - p.Y, v3s16(p.X, nmin.Y, p.Z)); + } + + // Remove cutoffs that were handled from the cutoff list + { + JMutexAutoLock cutofflock(cutoff_mutex); + for (std::list<CutoffData>::iterator i = cutoffs.begin(); + i != cutoffs.end(); ++i) { + + for (size_t j = 0; j != handled_cutoffs.size(); j++) { + CutoffData coff = *i; + if (coff.p == handled_cutoffs[j].p) + i = cutoffs.erase(i); + } + } + } +} +#endif + + +void DecoSimple::resolveNodeNames(INodeDefManager *ndef) { + Decoration::resolveNodeNames(ndef); + + if (c_deco == CONTENT_IGNORE) { + c_deco = ndef->getId(deco_name); + if (c_deco == CONTENT_IGNORE) { + errorstream << "DecoSimple::resolveNodeNames: decoration node '" + << deco_name << "' not defined"; + c_deco = CONTENT_AIR; + } + } + if (c_spawnby == CONTENT_IGNORE) { + c_spawnby = ndef->getId(spawnby_name); + if (c_spawnby == CONTENT_IGNORE) { + errorstream << "DecoSimple::resolveNodeNames: spawnby node '" + << deco_name << "' not defined"; + nspawnby = -1; + c_spawnby = CONTENT_AIR; + } + } + + if (c_decolist.size()) + return; + + for (size_t i = 0; i != decolist_names.size(); i++) { + content_t c = ndef->getId(decolist_names[i]); + if (c == CONTENT_IGNORE) { + errorstream << "DecoSimple::resolveNodeNames: decolist node '" + << decolist_names[i] << "' not defined"; + c = CONTENT_AIR; + } + c_decolist.push_back(c); + } +} + + +void DecoSimple::generate(Mapgen *mg, PseudoRandom *pr, s16 max_y, s16 start_y, v3s16 p) { + ManualMapVoxelManipulator *vm = mg->vm; + + u32 vi = vm->m_area.index(p); + if (vm->m_data[vi].getContent() != c_place_on && + c_place_on != CONTENT_IGNORE) + return; + + if (nspawnby != -1) { + int nneighs = 0; + v3s16 dirs[8] = { // a Moore neighborhood + v3s16( 0, 0, 1), + v3s16( 0, 0, -1), + v3s16( 1, 0, 0), + v3s16(-1, 0, 0), + v3s16( 1, 0, 1), + v3s16(-1, 0, 1), + v3s16(-1, 0, -1), + v3s16( 1, 0, -1) + }; + + for (int i = 0; i != 8; i++) { + u32 index = vm->m_area.index(p + dirs[i]); + if (vm->m_area.contains(index) && + vm->m_data[index].getContent() == c_spawnby) + nneighs++; + } + + if (nneighs < nspawnby) + return; + } + + size_t ndecos = c_decolist.size(); + content_t c_place = ndecos ? c_decolist[pr->range(0, ndecos - 1)] : c_deco; + + s16 height = (deco_height_max > 0) ? + pr->range(deco_height, deco_height_max) : deco_height; + + height = MYMIN(height, max_y - p.Y); + + v3s16 em = vm->m_area.getExtent(); + for (int i = start_y; i < height; i++) { + vm->m_area.add_y(em, vi, 1); + + content_t c = vm->m_data[vi].getContent(); + if (c != CONTENT_AIR && c != CONTENT_IGNORE) + break; + + vm->m_data[vi] = MapNode(c_place); + } +} + + +int DecoSimple::getHeight() { + return (deco_height_max > 0) ? deco_height_max : deco_height; +} + + +std::string DecoSimple::getName() { + return deco_name; +} + + +/////////////////////////////////////////////////////////////////////////////// + + +Mapgen::Mapgen() { + seed = 0; + water_level = 0; + generating = false; + id = -1; + vm = NULL; + ndef = NULL; + heightmap = NULL; + biomemap = NULL; +} + + +// Returns Y one under area minimum if not found +s16 Mapgen::findGroundLevelFull(v2s16 p2d) { + v3s16 em = vm->m_area.getExtent(); + s16 y_nodes_max = vm->m_area.MaxEdge.Y; + s16 y_nodes_min = vm->m_area.MinEdge.Y; + u32 i = vm->m_area.index(p2d.X, y_nodes_max, p2d.Y); + s16 y; + + for (y = y_nodes_max; y >= y_nodes_min; y--) { + MapNode &n = vm->m_data[i]; + if (ndef->get(n).walkable) + break; + + vm->m_area.add_y(em, i, -1); + } + return (y >= y_nodes_min) ? y : y_nodes_min - 1; +} + + +s16 Mapgen::findGroundLevel(v2s16 p2d, s16 ymin, s16 ymax) { + v3s16 em = vm->m_area.getExtent(); + u32 i = vm->m_area.index(p2d.X, ymax, p2d.Y); + s16 y; + + for (y = ymax; y >= ymin; y--) { + MapNode &n = vm->m_data[i]; + if (ndef->get(n).walkable) + break; + + vm->m_area.add_y(em, i, -1); + } + return y; +} + + +void Mapgen::updateHeightmap(v3s16 nmin, v3s16 nmax) { + if (!heightmap) + return; + + //TimeTaker t("Mapgen::updateHeightmap", NULL, PRECISION_MICRO); + int index = 0; + for (s16 z = nmin.Z; z <= nmax.Z; z++) { + for (s16 x = nmin.X; x <= nmax.X; x++) { + s16 y = findGroundLevel(v2s16(x, z), nmin.Y, nmax.Y); + heightmap[index++] = y; + } + } + //printf("updateHeightmap: %dus\n", t.stop()); +} + + void Mapgen::updateLiquid(UniqueQueue<v3s16> *trans_liquid, v3s16 nmin, v3s16 nmax) { bool isliquid, wasliquid; v3s16 em = vm->m_area.getExtent(); @@ -208,11 +524,11 @@ void Mapgen::updateLiquid(UniqueQueue<v3s16> *trans_liquid, v3s16 nmin, v3s16 nm for (s16 z = nmin.Z; z <= nmax.Z; z++) { for (s16 x = nmin.X; x <= nmax.X; x++) { wasliquid = true; - + u32 i = vm->m_area.index(x, nmax.Y, z); for (s16 y = nmax.Y; y >= nmin.Y; y--) { isliquid = ndef->get(vm->m_data[i]).isLiquid(); - + // there was a change between liquid and nonliquid, add to queue if (isliquid != wasliquid) trans_liquid->push_back(v3s16(x, y, z)); @@ -242,7 +558,7 @@ void Mapgen::setLighting(v3s16 nmin, v3s16 nmax, u8 light) { void Mapgen::lightSpread(VoxelArea &a, v3s16 p, u8 light) { if (light <= 1 || !a.contains(p)) return; - + u32 vi = vm->m_area.index(p); MapNode &nn = vm->m_data[vi]; @@ -250,9 +566,9 @@ void Mapgen::lightSpread(VoxelArea &a, v3s16 p, u8 light) { // should probably compare masked, but doesn't seem to make a difference if (light <= nn.param1 || !ndef->get(nn).light_propagates) return; - + nn.param1 = light; - + lightSpread(a, p + v3s16(0, 0, 1), light); lightSpread(a, p + v3s16(0, 1, 0), light); lightSpread(a, p + v3s16(1, 0, 0), light); @@ -282,7 +598,7 @@ void Mapgen::calcLighting(v3s16 nmin, v3s16 nmax) { continue; } vm->m_area.add_y(em, i, -1); - + for (int y = a.MaxEdge.Y; y >= a.MinEdge.Y; y--) { MapNode &n = vm->m_data[i]; if (!ndef->get(n).sunlight_propagates) @@ -292,7 +608,7 @@ void Mapgen::calcLighting(v3s16 nmin, v3s16 nmax) { } } } - + // now spread the sunlight and light up any sources for (int z = a.MinEdge.Z; z <= a.MaxEdge.Z; z++) { for (int y = a.MinEdge.Y; y <= a.MaxEdge.Y; y++) { @@ -302,11 +618,11 @@ void Mapgen::calcLighting(v3s16 nmin, v3s16 nmax) { if (n.getContent() == CONTENT_IGNORE || !ndef->get(n).light_propagates) continue; - + u8 light_produced = ndef->get(n).light_source & 0x0F; if (light_produced) n.param1 = light_produced; - + u8 light = n.param1 & 0x0F; if (light) { lightSpread(a, v3s16(x, y, z + 1), light); @@ -319,7 +635,7 @@ void Mapgen::calcLighting(v3s16 nmin, v3s16 nmax) { } } } - + //printf("updateLighting: %dms\n", t.stop()); } @@ -331,24 +647,24 @@ void Mapgen::calcLightingOld(v3s16 nmin, v3s16 nmax) { bool sunlight = !block_is_underground; ScopeProfiler sp(g_profiler, "EmergeThread: mapgen lighting update", SPT_AVG); - + for (int i = 0; i < 2; i++) { enum LightBank bank = banks[i]; std::set<v3s16> light_sources; std::map<v3s16, u8> unlight_from; voxalgo::clearLightAndCollectSources(*vm, a, bank, ndef, - light_sources, unlight_from); + light_sources, unlight_from); voxalgo::propagateSunlight(*vm, a, sunlight, light_sources, ndef); vm->unspreadLight(bank, unlight_from, light_sources, ndef); vm->spreadLight(bank, light_sources, ndef); } } - - + + //////////////////////// Mapgen V6 parameter read/write - + bool MapgenV6Params::readParams(Settings *settings) { freq_desert = settings->getFloat("mgv6_freq_desert"); freq_beach = settings->getFloat("mgv6_freq_beach"); @@ -367,12 +683,12 @@ bool MapgenV6Params::readParams(Settings *settings) { settings->getNoiseParams("mgv6_np_apple_trees", np_apple_trees); return success; } - - + + void MapgenV6Params::writeParams(Settings *settings) { settings->setFloat("mgv6_freq_desert", freq_desert); settings->setFloat("mgv6_freq_beach", freq_beach); - + settings->setNoiseParams("mgv6_np_terrain_base", np_terrain_base); settings->setNoiseParams("mgv6_np_terrain_higher", np_terrain_higher); settings->setNoiseParams("mgv6_np_steepness", np_steepness); @@ -411,7 +727,6 @@ void MapgenV7Params::writeParams(Settings *settings) { /////////////////////////////////// legacy static functions for farmesh - s16 Mapgen::find_ground_level_from_noise(u64 seed, v2s16 p2d, s16 precision) { //just need to return something s16 level = 5; @@ -421,9 +736,9 @@ s16 Mapgen::find_ground_level_from_noise(u64 seed, v2s16 p2d, s16 precision) { bool Mapgen::get_have_beach(u64 seed, v2s16 p2d) { double sandnoise = noise2d_perlin( - 0.2+(float)p2d.X/250, 0.7+(float)p2d.Y/250, - seed+59420, 3, 0.50); - + 0.2+(float)p2d.X/250, 0.7+(float)p2d.Y/250, + seed+59420, 3, 0.50); + return (sandnoise > 0.15); } diff --git a/src/mapgen.h b/src/mapgen.h index 5d1e3bdf0..f3d90a14e 100644 --- a/src/mapgen.h +++ b/src/mapgen.h @@ -86,9 +86,15 @@ public: int id; ManualMapVoxelManipulator *vm; INodeDefManager *ndef; + s16 *heightmap; + u8 *biomemap; + Mapgen(); virtual ~Mapgen() {} + s16 findGroundLevelFull(v2s16 p2d); + s16 findGroundLevel(v2s16 p2d, s16 ymin, s16 ymax); + void updateHeightmap(v3s16 nmin, v3s16 nmax); void updateLiquid(UniqueQueue<v3s16> *trans_liquid, v3s16 nmin, v3s16 nmax); void setLighting(v3s16 nmin, v3s16 nmax, u8 light); void lightSpread(VoxelArea &a, v3s16 p, u8 light); @@ -166,5 +172,90 @@ class OreSheet : public Ore { Ore *createOre(OreType type); + +enum DecorationType { + DECO_SIMPLE, + DECO_SCHEMATIC, + DECO_LSYSTEM +}; + +#if 0 +struct CutoffData { + VoxelArea a; + Decoration *deco; + //v3s16 p; + //v3s16 size; + //s16 height; + + CutoffData(s16 x, s16 y, s16 z, s16 h) { + p = v3s16(x, y, z); + height = h; + } +}; +#endif + +class Decoration { +public: + int mapseed; + std::string place_on_name; + content_t c_place_on; + s16 sidelen; + float fill_ratio; + NoiseParams *np; + + std::set<u8> biomes; + //std::list<CutoffData> cutoffs; + //JMutex cutoff_mutex; + + virtual ~Decoration(); + + virtual void resolveNodeNames(INodeDefManager *ndef); + void placeDeco(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax); + void placeCutoffs(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax); + + virtual void generate(Mapgen *mg, PseudoRandom *pr, s16 max_y, + s16 start_y, v3s16 p) = 0; + virtual int getHeight() = 0; + virtual std::string getName() = 0; +}; + +class DecoSimple : public Decoration { +public: + std::string deco_name; + std::string spawnby_name; + content_t c_deco; + content_t c_spawnby; + s16 deco_height; + s16 deco_height_max; + s16 nspawnby; + + std::vector<std::string> decolist_names; + std::vector<content_t> c_decolist; + + ~DecoSimple() {} + + void resolveNodeNames(INodeDefManager *ndef); + virtual void generate(Mapgen *mg, PseudoRandom *pr, s16 max_y, + s16 start_y, v3s16 p); + virtual int getHeight(); + virtual std::string getName(); +}; + +/* +class DecoSchematic : public Decoration { +public: + virtual void generate(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax); +}; +*/ + +/* +class DecoLSystem : public Decoration { +public: + virtual void generate(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax); +}; +*/ + +Decoration *createDecoration(DecorationType type); + #endif diff --git a/src/mapgen_v6.cpp b/src/mapgen_v6.cpp index eaca33988..d3db00dc2 100644 --- a/src/mapgen_v6.cpp +++ b/src/mapgen_v6.cpp @@ -79,7 +79,7 @@ MapgenV6::MapgenV6(int mapgenid, MapgenV6Params *params, EmergeManager *emerge) this->freq_beach = params->freq_beach; this->ystride = csize.X; //////fix this - + np_cave = ¶ms->np_cave; np_humidity = ¶ms->np_humidity; np_trees = ¶ms->np_trees; @@ -108,23 +108,6 @@ MapgenV6::~MapgenV6() { //////////////////////// Some helper functions for the map generator -// Returns Y one under area minimum if not found -s16 MapgenV6::find_ground_level(v2s16 p2d) { - v3s16 em = vm->m_area.getExtent(); - s16 y_nodes_max = vm->m_area.MaxEdge.Y; - s16 y_nodes_min = vm->m_area.MinEdge.Y; - u32 i = vm->m_area.index(p2d.X, y_nodes_max, p2d.Y); - s16 y; - - for (y = y_nodes_max; y >= y_nodes_min; y--) { - MapNode &n = vm->m_data[i]; - if(ndef->get(n).walkable) - break; - - vm->m_area.add_y(em, i, -1); - } - return (y >= y_nodes_min) ? y : y_nodes_min - 1; -} // Returns Y one under area minimum if not found s16 MapgenV6::find_stone_level(v2s16 p2d) { @@ -462,6 +445,12 @@ void MapgenV6::makeChunk(BlockMakeData *data) { // Generate some trees, and add grass, if a jungle if (flags & MG_TREES) placeTreesAndJungleGrass(); + + // Generate the registered decorations + for (unsigned int i = 0; i != emerge->decorations.size(); i++) { + Decoration *deco = emerge->decorations[i]; + deco->placeDeco(this, blockseed + i, node_min, node_max); + } // Generate the registered ores for (unsigned int i = 0; i != emerge->ores.size(); i++) { @@ -849,7 +838,7 @@ void MapgenV6::placeTreesAndJungleGrass() { s16 x = grassrandom.range(p2d_min.X, p2d_max.X); s16 z = grassrandom.range(p2d_min.Y, p2d_max.Y); - s16 y = find_ground_level(v2s16(x, z)); ////////////////optimize this! + s16 y = findGroundLevelFull(v2s16(x, z)); ////////////////optimize this! if (y < water_level || y < node_min.Y || y > node_max.Y) continue; @@ -866,7 +855,7 @@ void MapgenV6::placeTreesAndJungleGrass() { for (u32 i = 0; i < tree_count; i++) { s16 x = myrand_range(p2d_min.X, p2d_max.X); s16 z = myrand_range(p2d_min.Y, p2d_max.Y); - s16 y = find_ground_level(v2s16(x, z)); ////////////////////optimize this! + s16 y = findGroundLevelFull(v2s16(x, z)); ////////////////////optimize this! // Don't make a tree under water level // Don't make a tree so high that it doesn't fit if(y < water_level || y > node_max.Y - 6) diff --git a/src/mapgen_v6.h b/src/mapgen_v6.h index 8f456fd3f..f4ffd25f3 100644 --- a/src/mapgen_v6.h +++ b/src/mapgen_v6.h @@ -132,7 +132,6 @@ public: virtual float baseTerrainLevelFromMap(v2s16 p); virtual float baseTerrainLevelFromMap(int index); - s16 find_ground_level(v2s16 p2d); s16 find_stone_level(v2s16 p2d); bool block_is_underground(u64 seed, v3s16 blockpos); s16 find_ground_level_from_noise(u64 seed, v2s16 p2d, s16 precision); diff --git a/src/mapgen_v7.cpp b/src/mapgen_v7.cpp index 6daa5fc6a..2439c95b3 100644 --- a/src/mapgen_v7.cpp +++ b/src/mapgen_v7.cpp @@ -52,7 +52,7 @@ NoiseParams nparams_v7_def_terrain_persist = NoiseParams nparams_v7_def_height_select = {0.5, 0.5, v3f(250.0, 250.0, 250.0), 4213, 5, 0.69}; NoiseParams nparams_v7_def_ridge = - {0.5, 1.0, v3f(100.0, 100.0, 100.0), 6467, 4, 0.75}; + {0, 1.0, v3f(100.0, 100.0, 100.0), 6467, 4, 0.75}; /* NoiseParams nparams_v6_def_beach = {0.0, 1.0, v3f(250.0, 250.0, 250.0), 59420, 3, 0.50}; @@ -121,15 +121,19 @@ int MapgenV7::getGroundLevelAtPoint(v2s16 p) { Biome *b = bmgr->getBiome(heat, humidity, groundlevel); s16 y = groundlevel; - if (y > water_level) { - int iters = 1024; // don't even bother iterating more than 1024 times.. - while (iters--) { - float ridgenoise = NoisePerlin3D(noise_ridge->np, p.X, y, p.Y, seed); - if (ridgenoise * (float)(y * y) < 15.0) - break; - y--; - } + int iters = 1024; // don't even bother iterating more than 64 times.. + while (iters--) { + if (y <= water_level) + break; + + float ridgenoise = NoisePerlin3D(noise_ridge->np, p.X, y, p.Y, seed); + if (ridgenoise * (float)(y * y) < 15.0) + break; + + y--; } + if (iters == 0) + printf("iters exhausted at %d %d\n", p.X, p.Y); return y + b->top_depth; } @@ -182,15 +186,24 @@ void MapgenV7::makeChunk(BlockMakeData *data) { generateTerrain(); carveRidges(); + + if (flags & MG_CAVES) + generateCaves(stone_surface_max_y); - generateCaves(stone_surface_max_y); addTopNodes(); + + updateHeightmap(node_min, node_max); if (flags & MG_DUNGEONS) { DungeonGen dgen(ndef, data->seed, water_level); dgen.generate(vm, blockseed, full_node_min, full_node_max); } + for (size_t i = 0; i != emerge->decorations.size(); i++) { + Decoration *deco = emerge->decorations[i]; + deco->placeDeco(this, blockseed + i, node_min, node_max); + } + for (size_t i = 0; i != emerge->ores.size(); i++) { Ore *ore = emerge->ores[i]; ore->placeOre(this, blockseed + i, node_min, node_max); diff --git a/src/mapgen_v7.h b/src/mapgen_v7.h index b6b03689d..d7177862d 100644 --- a/src/mapgen_v7.h +++ b/src/mapgen_v7.h @@ -67,9 +67,7 @@ public: v3s16 full_node_min; v3s16 full_node_max; - s16 *heightmap; s16 *ridge_heightmap; - u8 *biomemap; Noise *noise_terrain_base; Noise *noise_terrain_alt; diff --git a/src/modalMenu.h b/src/modalMenu.h index d19b4e27c..62bfabc06 100644 --- a/src/modalMenu.h +++ b/src/modalMenu.h @@ -99,6 +99,7 @@ public: allowFocusRemoval(true); // This removes Environment's grab on us Environment->removeFocus(this); + m_menumgr->deletingMenu(this); this->remove(); } diff --git a/src/nodedef.cpp b/src/nodedef.cpp index ba3e42e98..7d8ce70d3 100644 --- a/src/nodedef.cpp +++ b/src/nodedef.cpp @@ -211,6 +211,7 @@ void ContentFeatures::reset() liquid_alternative_source = ""; liquid_viscosity = 0; liquid_renewable = true; + drowning = true; light_source = 0; damage_per_second = 0; node_box = NodeBox(); @@ -279,6 +280,7 @@ void ContentFeatures::serialize(std::ostream &os, u16 protocol_version) writeU8(os, rightclickable); // Stuff below should be moved to correct place in a version that otherwise changes // the protocol version + writeU8(os, drowning); } void ContentFeatures::deSerialize(std::istream &is) @@ -343,6 +345,7 @@ void ContentFeatures::deSerialize(std::istream &is) try{ // Stuff below should be moved to correct place in a version that // otherwise changes the protocol version + drowning = readU8(is); }catch(SerializationError &e) {}; } diff --git a/src/nodedef.h b/src/nodedef.h index 2691aca33..e397d20e0 100644 --- a/src/nodedef.h +++ b/src/nodedef.h @@ -219,6 +219,7 @@ struct ContentFeatures u8 liquid_viscosity; // Is liquid renewable (new liquid source will be created between 2 existing) bool liquid_renewable; + bool drowning; // Amount of light the node emits u8 light_source; u32 damage_per_second; diff --git a/src/player.cpp b/src/player.cpp index 4eb5955c0..a199c9a6c 100644 --- a/src/player.cpp +++ b/src/player.cpp @@ -36,6 +36,7 @@ Player::Player(IGameDef *gamedef): camera_barely_in_ceiling(false), inventory(gamedef->idef()), hp(PLAYER_MAX_HP), + breath(-1), peer_id(PEER_ID_INEXISTENT), // protected m_gamedef(gamedef), @@ -80,7 +81,8 @@ Player::Player(IGameDef *gamedef): physics_override_gravity = 1; hud_flags = HUD_FLAG_HOTBAR_VISIBLE | HUD_FLAG_HEALTHBAR_VISIBLE | - HUD_FLAG_CROSSHAIR_VISIBLE | HUD_FLAG_WIELDITEM_VISIBLE; + HUD_FLAG_CROSSHAIR_VISIBLE | HUD_FLAG_WIELDITEM_VISIBLE | + HUD_FLAG_BREATHBAR_VISIBLE; hud_hotbar_itemcount = HUD_HOTBAR_ITEMCOUNT_DEFAULT; } diff --git a/src/player.h b/src/player.h index d3738fd52..517bd354d 100644 --- a/src/player.h +++ b/src/player.h @@ -232,6 +232,7 @@ public: float physics_override_gravity; u16 hp; + u16 breath; float hurt_tilt_timer; float hurt_tilt_strength; diff --git a/src/script/common/c_content.cpp b/src/script/common/c_content.cpp index c7966a0be..64c76ef7c 100644 --- a/src/script/common/c_content.cpp +++ b/src/script/common/c_content.cpp @@ -389,6 +389,7 @@ ContentFeatures read_content_features(lua_State *L, int index) f.liquid_viscosity = getintfield_default(L, index, "liquid_viscosity", f.liquid_viscosity); getboolfield(L, index, "liquid_renewable", f.liquid_renewable); + getboolfield(L, index, "drowning", f.drowning); // Amount of light the node emits f.light_source = getintfield_default(L, index, "light_source", f.light_source); diff --git a/src/script/common/c_content.h b/src/script/common/c_content.h index 251a72e27..58be7118c 100644 --- a/src/script/common/c_content.h +++ b/src/script/common/c_content.h @@ -39,19 +39,19 @@ extern "C" { #include "irrlichttypes_bloated.h" #include "util/string.h" -class MapNode; +struct MapNode; class INodeDefManager; -class PointedThing; -class ItemStack; -class ItemDefinition; -class ToolCapabilities; -class ObjectProperties; -class SimpleSoundSpec; -class ServerSoundParams; +struct PointedThing; +struct ItemStack; +struct ItemDefinition; +struct ToolCapabilities; +struct ObjectProperties; +struct SimpleSoundSpec; +struct ServerSoundParams; class Inventory; -class NodeBox; -class ContentFeatures; -class TileDef; +struct NodeBox; +struct ContentFeatures; +struct TileDef; class Server; struct DigParams; struct HitParams; diff --git a/src/script/cpp_api/s_entity.h b/src/script/cpp_api/s_entity.h index b95b6b4b4..8df9d7f00 100644 --- a/src/script/cpp_api/s_entity.h +++ b/src/script/cpp_api/s_entity.h @@ -23,8 +23,8 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "cpp_api/s_base.h" #include "irr_v3d.h" -class ObjectProperties; -class ToolCapabilities; +struct ObjectProperties; +struct ToolCapabilities; class ScriptApiEntity : virtual public ScriptApiBase diff --git a/src/script/cpp_api/s_inventory.h b/src/script/cpp_api/s_inventory.h index bf3b5de85..d1a81de80 100644 --- a/src/script/cpp_api/s_inventory.h +++ b/src/script/cpp_api/s_inventory.h @@ -22,7 +22,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "cpp_api/s_base.h" -class ItemStack; +struct ItemStack; class ScriptApiDetached : virtual public ScriptApiBase diff --git a/src/script/cpp_api/s_item.h b/src/script/cpp_api/s_item.h index 28ac444f6..0f2b16042 100644 --- a/src/script/cpp_api/s_item.h +++ b/src/script/cpp_api/s_item.h @@ -23,10 +23,10 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "cpp_api/s_base.h" #include "irr_v3d.h" -class PointedThing; -class ItemStack; +struct PointedThing; +struct ItemStack; class ServerActiveObject; -class ItemDefinition; +struct ItemDefinition; class LuaItemStack; class ModApiItemMod; diff --git a/src/script/cpp_api/s_node.h b/src/script/cpp_api/s_node.h index bff6072b9..a8c9b3a79 100644 --- a/src/script/cpp_api/s_node.h +++ b/src/script/cpp_api/s_node.h @@ -26,7 +26,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "cpp_api/s_base.h" #include "cpp_api/s_nodemeta.h" -class MapNode; +struct MapNode; class ServerActiveObject; class ScriptApiNode diff --git a/src/script/cpp_api/s_nodemeta.h b/src/script/cpp_api/s_nodemeta.h index 9be126c62..c2ebeba6d 100644 --- a/src/script/cpp_api/s_nodemeta.h +++ b/src/script/cpp_api/s_nodemeta.h @@ -24,7 +24,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "cpp_api/s_item.h" #include "irr_v3d.h" -class ItemStack; +struct ItemStack; class ScriptApiNodemeta : virtual public ScriptApiBase, diff --git a/src/script/lua_api/l_env.cpp b/src/script/lua_api/l_env.cpp index 58cf337ed..a287281a9 100644 --- a/src/script/lua_api/l_env.cpp +++ b/src/script/lua_api/l_env.cpp @@ -550,7 +550,7 @@ int ModApiEnvMod::l_line_of_sight(lua_State *L) { GET_ENV_PTR; // read position 1 from lua - v3f pos1 = checkFloatPos(L, 2); + v3f pos1 = checkFloatPos(L, 1); // read position 2 from lua v3f pos2 = checkFloatPos(L, 2); //read step size from lua @@ -566,14 +566,14 @@ int ModApiEnvMod::l_find_path(lua_State *L) { GET_ENV_PTR; - v3s16 pos1 = read_v3s16(L, 2); - v3s16 pos2 = read_v3s16(L, 3); - unsigned int searchdistance = luaL_checkint(L, 4); - unsigned int max_jump = luaL_checkint(L, 5); - unsigned int max_drop = luaL_checkint(L, 6); + v3s16 pos1 = read_v3s16(L, 1); + v3s16 pos2 = read_v3s16(L, 2); + unsigned int searchdistance = luaL_checkint(L, 3); + unsigned int max_jump = luaL_checkint(L, 4); + unsigned int max_drop = luaL_checkint(L, 5); algorithm algo = A_PLAIN_NP; - if(! lua_isnil(L, 7)) { - std::string algorithm = luaL_checkstring(L,7); + if(! lua_isnil(L, 6)) { + std::string algorithm = luaL_checkstring(L,6); if (algorithm == "A*") algo = A_PLAIN; @@ -680,6 +680,8 @@ bool ModApiEnvMod::Initialize(lua_State *L,int top) retval &= API_FCT(get_perlin_map); retval &= API_FCT(clear_objects); retval &= API_FCT(spawn_tree); + retval &= API_FCT(find_path); + retval &= API_FCT(line_of_sight); return retval; } diff --git a/src/script/lua_api/l_inventory.cpp b/src/script/lua_api/l_inventory.cpp index 1404c3c8a..f57a4e8cd 100644 --- a/src/script/lua_api/l_inventory.cpp +++ b/src/script/lua_api/l_inventory.cpp @@ -121,6 +121,9 @@ int InvRef::l_set_size(lua_State *L) const char *listname = luaL_checkstring(L, 2); int newsize = luaL_checknumber(L, 3); Inventory *inv = getinv(L, ref); + if(inv == NULL){ + return 0; + } if(newsize == 0){ inv->deleteList(listname); reportInventoryChange(L, ref); @@ -144,6 +147,9 @@ int InvRef::l_set_width(lua_State *L) const char *listname = luaL_checkstring(L, 2); int newwidth = luaL_checknumber(L, 3); Inventory *inv = getinv(L, ref); + if(inv == NULL){ + return 0; + } InventoryList *list = inv->getList(listname); if(list){ list->setWidth(newwidth); @@ -195,7 +201,11 @@ int InvRef::l_get_list(lua_State *L) InvRef *ref = checkobject(L, 1); const char *listname = luaL_checkstring(L, 2); Inventory *inv = getinv(L, ref); - push_inventory_list(inv, listname, L); + if(inv){ + push_inventory_list(inv, listname, L); + } else { + lua_pushnil(L); + } return 1; } @@ -206,6 +216,9 @@ int InvRef::l_set_list(lua_State *L) InvRef *ref = checkobject(L, 1); const char *listname = luaL_checkstring(L, 2); Inventory *inv = getinv(L, ref); + if(inv == NULL){ + return 0; + } InventoryList *list = inv->getList(listname); if(list) read_inventory_list(inv, listname, L, 3, diff --git a/src/script/lua_api/l_object.cpp b/src/script/lua_api/l_object.cpp index 1e45610a6..f90b59285 100644 --- a/src/script/lua_api/l_object.cpp +++ b/src/script/lua_api/l_object.cpp @@ -62,6 +62,7 @@ struct EnumString es_HudBuiltinElement[] = {HUD_FLAG_HEALTHBAR_VISIBLE, "healthbar"}, {HUD_FLAG_CROSSHAIR_VISIBLE, "crosshair"}, {HUD_FLAG_WIELDITEM_VISIBLE, "wielditem"}, + {HUD_FLAG_BREATHBAR_VISIBLE, "breathbar"}, {0, NULL}, }; diff --git a/src/script/lua_api/luaapi.cpp b/src/script/lua_api/luaapi.cpp index b75304b3a..e19c90952 100644 --- a/src/script/lua_api/luaapi.cpp +++ b/src/script/lua_api/luaapi.cpp @@ -43,6 +43,14 @@ struct EnumString ModApiBasic::es_OreType[] = {0, NULL}, }; +struct EnumString ModApiBasic::es_DecorationType[] = +{ + {DECO_SIMPLE, "simple"}, + {DECO_SCHEMATIC, "schematic"}, + {DECO_LSYSTEM, "lsystem"}, + {0, NULL}, +}; + ModApiBasic::ModApiBasic() : ModApiBase() { } @@ -72,7 +80,7 @@ bool ModApiBasic::Initialize(lua_State* L,int top) { retval &= API_FCT(get_ban_list); retval &= API_FCT(get_ban_description); retval &= API_FCT(ban_player); - retval &= API_FCT(unban_player_of_ip); + retval &= API_FCT(unban_player_or_ip); retval &= API_FCT(get_password_hash); retval &= API_FCT(notify_authentication_modified); @@ -92,17 +100,36 @@ bool ModApiBasic::Initialize(lua_State* L,int top) { retval &= API_FCT(rollback_revert_actions_by); retval &= API_FCT(register_ore); + retval &= API_FCT(register_decoration); return retval; } -// debug(text) +// debug(...) // Writes a line to dstream int ModApiBasic::l_debug(lua_State *L) { NO_MAP_LOCK_REQUIRED; - std::string text = lua_tostring(L, 1); - dstream << text << std::endl; + // Handle multiple parameters to behave like standard lua print() + int n = lua_gettop(L); + lua_getglobal(L, "tostring"); + for(int i = 1; i <= n; i++){ + /* + Call tostring(i-th argument). + This is what print() does, and it behaves a bit + differently from directly calling lua_tostring. + */ + lua_pushvalue(L, -1); /* function to be called */ + lua_pushvalue(L, i); /* value to print */ + lua_call(L, 1, 1); + const char *s = lua_tostring(L, -1); + if(i>1) + dstream << "\t"; + if(s) + dstream << s; + lua_pop(L, 1); + } + dstream << std::endl; return 0; } @@ -162,30 +189,28 @@ int ModApiBasic::l_register_biome(lua_State *L) } enum BiomeTerrainType terrain = (BiomeTerrainType)getenumfield(L, index, - "terrain_type", es_BiomeTerrainType, BIOME_TERRAIN_NORMAL); + "terrain_type", es_BiomeTerrainType, BIOME_TERRAIN_NORMAL); Biome *b = bmgr->createBiome(terrain); - b->name = getstringfield_default(L, index, "name", ""); - b->top_nodename = getstringfield_default(L, index, "top_node", ""); - b->top_depth = getintfield_default(L, index, "top_depth", 0); + b->name = getstringfield_default(L, index, "name", ""); + b->top_nodename = getstringfield_default(L, index, "top_node", ""); + b->top_depth = getintfield_default(L, index, "top_depth", 0); b->filler_nodename = getstringfield_default(L, index, "filler_node", ""); - b->filler_height = getintfield_default(L, index, "filler_height", 0); - b->height_min = getintfield_default(L, index, "height_min", 0); - b->height_max = getintfield_default(L, index, "height_max", 0); - b->heat_point = getfloatfield_default(L, index, "heat_point", 0.); - b->humidity_point = getfloatfield_default(L, index, "humidity_point", 0.); - - b->flags = 0; //reserved - b->c_top = CONTENT_IGNORE; + b->filler_height = getintfield_default(L, index, "filler_height", 0); + b->height_min = getintfield_default(L, index, "height_min", 0); + b->height_max = getintfield_default(L, index, "height_max", 0); + b->heat_point = getfloatfield_default(L, index, "heat_point", 0.); + b->humidity_point = getfloatfield_default(L, index, "humidity_point", 0.); + + b->flags = 0; //reserved + b->c_top = CONTENT_IGNORE; b->c_filler = CONTENT_IGNORE; + verbosestream << "register_biome: " << b->name << std::endl; bmgr->addBiome(b); - verbosestream << "register_biome: " << b->name << std::endl; return 0; } - - // setting_set(name, value) int ModApiBasic::l_setting_set(lua_State *L) { @@ -353,7 +378,7 @@ int ModApiBasic::l_ban_player(lua_State *L) } // unban_player_or_ip() -int ModApiBasic::l_unban_player_of_ip(lua_State *L) +int ModApiBasic::l_unban_player_or_ip(lua_State *L) { NO_MAP_LOCK_REQUIRED; const char * ip_or_name = luaL_checkstring(L, 1); @@ -650,4 +675,111 @@ int ModApiBasic::l_register_ore(lua_State *L) return 0; } +// register_decoration({lots of stuff}) +int ModApiBasic::l_register_decoration(lua_State *L) +{ + int index = 1; + luaL_checktype(L, index, LUA_TTABLE); + + EmergeManager *emerge = getServer(L)->getEmergeManager(); + BiomeDefManager *bdef = emerge->biomedef; + + enum DecorationType decotype = (DecorationType)getenumfield(L, index, + "deco_type", es_DecorationType, -1); + if (decotype == -1) { + errorstream << "register_decoration: unrecognized " + "decoration placement type"; + return 0; + } + + Decoration *deco = createDecoration(decotype); + if (!deco) { + errorstream << "register_decoration: decoration placement type " + << decotype << " not implemented"; + return 0; + } + + deco->c_place_on = CONTENT_IGNORE; + deco->place_on_name = getstringfield_default(L, index, "place_on", "ignore"); + deco->sidelen = getintfield_default(L, index, "sidelen", 8); + deco->fill_ratio = getfloatfield_default(L, index, "fill_ratio", 0.02); + + lua_getfield(L, index, "noise_params"); + deco->np = read_noiseparams(L, -1); + lua_pop(L, 1); + + lua_getfield(L, index, "biomes"); + if (lua_istable(L, -1)) { + lua_pushnil(L); + while (lua_next(L, -2)) { + const char *s = lua_tostring(L, -1); + u8 biomeid = bdef->getBiomeIdByName(s); + if (biomeid) + deco->biomes.insert(biomeid); + + lua_pop(L, 1); + } + lua_pop(L, 1); + } + + switch (decotype) { + case DECO_SIMPLE: { + DecoSimple *dsimple = (DecoSimple *)deco; + dsimple->c_deco = CONTENT_IGNORE; + dsimple->c_spawnby = CONTENT_IGNORE; + dsimple->spawnby_name = getstringfield_default(L, index, "spawn_by", "air"); + dsimple->deco_height = getintfield_default(L, index, "height", 1); + dsimple->deco_height_max = getintfield_default(L, index, "height_max", 0); + dsimple->nspawnby = getintfield_default(L, index, "num_spawn_by", -1); + + lua_getfield(L, index, "decoration"); + if (lua_istable(L, -1)) { + lua_pushnil(L); + while (lua_next(L, -2)) { + const char *s = lua_tostring(L, -1); + std::string str(s); + dsimple->decolist_names.push_back(str); + + lua_pop(L, 1); + } + } else if (lua_isstring(L, -1)) { + dsimple->deco_name = std::string(lua_tostring(L, -1)); + } else { + dsimple->deco_name = std::string("air"); + } + lua_pop(L, 1); + + if (dsimple->deco_height <= 0) { + errorstream << "register_decoration: simple decoration height" + " must be greater than 0" << std::endl; + delete dsimple; + return 0; + } + + break; } + case DECO_SCHEMATIC: { + //DecoSchematic *decoschematic = (DecoSchematic *)deco; + + break; } + case DECO_LSYSTEM: { + //DecoLSystem *decolsystem = (DecoLSystem *)deco; + + break; } + } + + if (deco->sidelen <= 0) { + errorstream << "register_decoration: sidelen must be " + "greater than 0" << std::endl; + delete deco; + return 0; + } + + emerge->decorations.push_back(deco); + + verbosestream << "register_decoration: decoration '" << deco->getName() + << "' registered" << std::endl; + return 0; +} + + ModApiBasic modapibasic_prototype; diff --git a/src/script/lua_api/luaapi.h b/src/script/lua_api/luaapi.h index 592046965..d03c14117 100644 --- a/src/script/lua_api/luaapi.h +++ b/src/script/lua_api/luaapi.h @@ -45,9 +45,6 @@ private: // get_server_status() static int l_get_server_status(lua_State *L); - // register_biome_groups({frequencies}) - static int l_register_biome_groups(lua_State *L); - // register_biome({lots of stuff}) static int l_register_biome(lua_State *L); @@ -85,7 +82,7 @@ private: static int l_ban_player(lua_State *L); // unban_player_or_ip() - static int l_unban_player_of_ip(lua_State *L); + static int l_unban_player_or_ip(lua_State *L); // show_formspec(playername,formname,formspec) static int l_show_formspec(lua_State *L); @@ -130,9 +127,15 @@ private: // rollback_revert_actions_by(actor, seconds) -> bool, log messages static int l_rollback_revert_actions_by(lua_State *L); + // register_ore(oredesc) static int l_register_ore(lua_State *L); + + // register_decoration(deco) + static int l_register_decoration(lua_State *L); static struct EnumString es_OreType[]; + static struct EnumString es_DecorationType[]; + }; diff --git a/src/server.cpp b/src/server.cpp index 4268bb809..7963aeaae 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -2401,6 +2401,18 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) setInventoryModified(da->from_inv); + /* + Disable dropping items out of craftpreview + */ + if(da->from_list == "craftpreview") + { + infostream<<"Ignoring IDropAction from " + <<(da->from_inv.dump())<<":"<<da->from_list + <<" because src is "<<da->from_list<<std::endl; + delete a; + return; + } + // Disallow dropping items if not allowed to interact if(!checkPriv(player->getName(), "interact")) { diff --git a/src/test.cpp b/src/test.cpp index 3a0316e17..5267b2768 100644 --- a/src/test.cpp +++ b/src/test.cpp @@ -1452,7 +1452,7 @@ struct TestConnection: public TestBase // Server should not have added client yet UASSERT(hand_server.count == 0); - sleep_ms(50); + sleep_ms(100); try { diff --git a/src/tile.cpp b/src/tile.cpp index 5f25e123b..f176d1549 100644 --- a/src/tile.cpp +++ b/src/tile.cpp @@ -364,14 +364,14 @@ public: // Gets a separate texture video::ITexture* getTextureRaw(const std::string &name) { - AtlasPointer ap = getTexture(name + "^[forcesingle"); + AtlasPointer ap = getTexture(name + m_forcesingle_suffix); return ap.atlas; } // Gets a separate texture atlas pointer AtlasPointer getTextureRawAP(const AtlasPointer &ap) { - return getTexture(getTextureName(ap.id) + "^[forcesingle"); + return getTexture(getTextureName(ap.id) + m_forcesingle_suffix); } // Returns a pointer to the irrlicht device @@ -437,9 +437,14 @@ private: // Main texture atlas. This is filled at startup and is then not touched. video::IImage *m_main_atlas_image; video::ITexture *m_main_atlas_texture; + std::string m_forcesingle_suffix; // Queued texture fetches (to be processed by the main thread) RequestQueue<std::string, u32, u8, u8> m_get_texture_queue; + + // Textures that have been overwritten with other ones + // but can't be deleted because the ITexture* might still be used + std::list<video::ITexture*> m_texture_trash; }; IWritableTextureSource* createTextureSource(IrrlichtDevice *device) @@ -485,6 +490,16 @@ TextureSource::~TextureSource() } m_atlaspointer_cache.clear(); + for (std::list<video::ITexture*>::iterator iter = + m_texture_trash.begin(); iter != m_texture_trash.end(); + iter++) + { + video::ITexture *t = *iter; + + //cleanup trashed texture + driver->removeTexture(t); + } + infostream << "~TextureSource() "<< textures_before << "/" << driver->getTextureCount() << std::endl; } @@ -870,7 +885,7 @@ void TextureSource::rebuildImagesAndTextures() sap->intsize = img->getDimension(); if (t_old != 0) - driver->removeTexture(t_old); + m_texture_trash.push_back(t_old); } } @@ -1123,6 +1138,8 @@ void TextureSource::buildMainAtlas(class IGameDef *gamedef) <<atlaspath<<std::endl; fs::RecursiveDelete(atlaspath); driver->writeImageToFile(atlas_img, atlaspath.c_str());*/ + + m_forcesingle_suffix = "^[forcesingle"; } video::IImage* generate_image_from_scratch(std::string name, |