summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorWeblate <42@minetest.ru>2013-06-21 10:24:16 +0200
committerWeblate <42@minetest.ru>2013-06-21 10:24:16 +0200
commit3af90db5b51da0c37f77fe6410e488c8c27acd67 (patch)
tree12edd6f0661b464e36863517241b5ec0b87b5ec1 /src
parent58f3cd3eb598a7cf79983fe9e48c738591c6e004 (diff)
parentb1ebd9f79c63cf78b0e0fb2ea6f52d82cdfb95b6 (diff)
downloadminetest-3af90db5b51da0c37f77fe6410e488c8c27acd67.tar.gz
minetest-3af90db5b51da0c37f77fe6410e488c8c27acd67.tar.bz2
minetest-3af90db5b51da0c37f77fe6410e488c8c27acd67.zip
Merge remote-tracking branch 'origin/master'
Diffstat (limited to 'src')
-rw-r--r--src/biome.cpp10
-rw-r--r--src/biome.h1
-rw-r--r--src/client.cpp7
-rw-r--r--src/client.h1
-rw-r--r--src/defaultsettings.cpp4
-rw-r--r--src/emerge.cpp10
-rw-r--r--src/emerge.h1
-rw-r--r--src/environment.cpp87
-rw-r--r--src/environment.h2
-rw-r--r--src/game.cpp60
-rw-r--r--src/guiChatConsole.cpp13
-rw-r--r--src/guiChatConsole.h3
-rw-r--r--src/guiFormSpecMenu.cpp98
-rw-r--r--src/guiFormSpecMenu.h1
-rw-r--r--src/hud.cpp5
-rw-r--r--src/hud.h3
-rw-r--r--src/map.cpp33
-rw-r--r--src/map.h8
-rw-r--r--src/mapblock_mesh.cpp4
-rw-r--r--src/mapgen.cpp387
-rw-r--r--src/mapgen.h91
-rw-r--r--src/mapgen_v6.cpp29
-rw-r--r--src/mapgen_v6.h1
-rw-r--r--src/mapgen_v7.cpp33
-rw-r--r--src/mapgen_v7.h2
-rw-r--r--src/modalMenu.h1
-rw-r--r--src/nodedef.cpp3
-rw-r--r--src/nodedef.h1
-rw-r--r--src/player.cpp4
-rw-r--r--src/player.h1
-rw-r--r--src/script/common/c_content.cpp1
-rw-r--r--src/script/common/c_content.h22
-rw-r--r--src/script/cpp_api/s_entity.h4
-rw-r--r--src/script/cpp_api/s_inventory.h2
-rw-r--r--src/script/cpp_api/s_item.h6
-rw-r--r--src/script/cpp_api/s_node.h2
-rw-r--r--src/script/cpp_api/s_nodemeta.h2
-rw-r--r--src/script/lua_api/l_env.cpp18
-rw-r--r--src/script/lua_api/l_inventory.cpp15
-rw-r--r--src/script/lua_api/l_object.cpp1
-rw-r--r--src/script/lua_api/luaapi.cpp172
-rw-r--r--src/script/lua_api/luaapi.h11
-rw-r--r--src/server.cpp12
-rw-r--r--src/test.cpp2
-rw-r--r--src/tile.cpp23
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));
}
diff --git a/src/hud.h b/src/hud.h
index fa9d33f8b..c7289f7c4 100644
--- a/src/hud.h
+++ b/src/hud.h
@@ -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);
diff --git a/src/map.h b/src/map.h
index 31001e4c3..530d81e7a 100644
--- a/src/map.h
+++ b/src/map.h
@@ -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 = &params->np_cave;
np_humidity = &params->np_humidity;
np_trees = &params->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,