From: kwolekr Date: Mon, 26 Nov 2012 02:16:48 +0000 (-0500) Subject: The new mapgen, noise functions, et al. X-Git-Url: http://81.2.79.47:8989/gitweb/?a=commitdiff_plain;h=11afcbff69c95915e5142bc4b55636ff6358ece9;p=zefram%2Fminetest%2Fminetest_engine.git The new mapgen, noise functions, et al. --- diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index ac39e43e..995d031e 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -218,6 +218,7 @@ set(common_SRCS sha1.cpp base64.cpp ban.cpp + biome.cpp clientserver.cpp staticobject.cpp util/serialize.cpp diff --git a/src/biome.cpp b/src/biome.cpp new file mode 100644 index 00000000..4b240d5a --- /dev/null +++ b/src/biome.cpp @@ -0,0 +1,229 @@ +/* +Minetest-c55 +Copyright (C) 2010-2011 kwolekr, Ryan Kwolek + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#include "biome.h" +#include "nodedef.h" +#include "map.h" //for ManualMapVoxelManipulator +#include "main.h" + +#define BT_NONE 0 +#define BT_OCEAN 1 +#define BT_LAKE 2 +#define BT_SBEACH 3 +#define BT_GBEACH 4 +#define BT_PLAINS 5 +#define BT_HILLS 6 +#define BT_EXTREMEHILLS 7 +#define BT_MOUNTAINS 8 +#define BT_DESERT 9 +#define BT_DESERTHILLS 10 +#define BT_HELL 11 +#define BT_AETHER 12 + +#define BT_BTMASK 0x3F + +#define BTF_SNOW 0x40 +#define BTF_FOREST 0x80 + +#define BGFREQ_1 ( 0.40) +#define BGFREQ_2 (BGFREQ_1 + 0.05) +#define BGFREQ_3 (BGFREQ_2 + 0.08) +#define BGFREQ_4 (BGFREQ_3 + 0.35) +#define BGFREQ_5 (BGFREQ_4 + 0.18) +//BGFREQ_5 is not checked as an upper bound; it ought to sum up to 1.00, but it's okay if it doesn't. + + +/*float bg1_temps[] = {0.0}; +int bg1_biomes[] = {BT_OCEAN}; + +float bg2_temps[] = {10.0}; +int bg2_biomes[] = {BT_GBEACH, BT_SBEACH}; + +float bg3_temps[] = {30.0, 40.0}; +int bg3_biomes[] = {BT_HILLS, BT_EXTREMEHILLS, BT_MOUNTAINS}; + +float bg4_temps[] = {25.0, 30.0, 35.0, 40.0}; +int bg4_biomes[] = {BT_HILLS, BT_EXTREMEHILLS, BT_MOUNTAINS, BT_DESERT, BT_DESERTHILLS}; + +float bg5_temps[] = {5.0, 40.0}; +int bg5_biomes[] = {BT_LAKE, BT_PLAINS, BT_DESERT};*/ + + +BiomeDefManager::BiomeDefManager(IGameDef *gamedef) { + this->m_gamedef = gamedef; + this->ndef = gamedef->ndef(); + + //addDefaultBiomes(); //can't do this in the ctor, too early +} + + +BiomeDefManager::~BiomeDefManager() { + for (int i = 0; i != bgroups.size(); i++) + delete bgroups[i]; +} + + +void BiomeDefManager::addBiome() { + +} + + +NoiseParams npmtdef = {0.0, 20.0, v3f(250., 250., 250.), 82341, 5, 0.6}; + +void BiomeDefManager::addDefaultBiomes() { + std::vector *bgroup; + Biome *b; + + //bgroup = new std::vector; + + b = new Biome; + b->name = "Default"; + b->n_top = MapNode(ndef->getId("mapgen_stone")); + b->n_filler = b->n_top; + b->ntopnodes = 0; + b->height_min = -MAP_GENERATION_LIMIT; + b->height_max = MAP_GENERATION_LIMIT; + b->heat_min = FLT_MIN; + b->heat_max = FLT_MAX; + b->humidity_min = FLT_MIN; + b->humidity_max = FLT_MAX; + b->np = &npmtdef; + biome_default = b; + + //bgroup->push_back(b); + //bgroups.push_back(bgroup); +} + + +Biome *BiomeDefManager::getBiome(float bgfreq, float heat, float humidity) { + std::vector bgroup; + Biome *b; + int i; + + int ngroups = bgroup_freqs.size(); + if (!ngroups) + return biome_default; + for (i = 0; (i != ngroups - 1) && (bgfreq > bgroup_freqs[i]); i++); + bgroup = *(bgroups[i]); + + int nbiomes = bgroup.size(); + if (!nbiomes) + return biome_default; + for (i = 0; i != nbiomes - 1; i++) { + b = bgroup[i]; + if (heat >= b->heat_min && heat <= b->heat_max && + humidity >= b->humidity_min && humidity <= b->humidity_max) + return b; + } + + return biome_default; +} + + +//////////////////////////// [ Generic biome ] //////////////////////////////// + + +int Biome::getSurfaceHeight(float noise_terrain) { + return np->offset + np->scale * noise_terrain; +} + + +void Biome::genColumn(Mapgen *mg, int x, int z, int y1, int y2) { + //printf("(%d, %d): %f\n", x, z, mg->map_terrain[z * mg->ystride + x]); + + //int surfaceh = 4; + int surfaceh = np->offset + np->scale * mg->map_terrain[(z - mg->node_min.Z) * 80 /*THIS IS TEMPORARY mg->ystride*/ + (x - mg->node_min.X)]; + //printf("gen column %f\n", ); + int y = y1; + int i = mg->vmanip->m_area.index(x, y, z); //z * mg->zstride + x + (y - mg->vmanip->m_area.MinEdge.Y) * mg->ystride; + for (; y <= surfaceh - ntopnodes && y <= y2; y++, i += mg->ystride) + mg->vmanip->m_data[i] = n_filler; + for (; y <= surfaceh && y <= y2; y++, i += mg->ystride) + mg->vmanip->m_data[i] = n_top; + for (; y <= y2; y++, i += mg->ystride) + mg->vmanip->m_data[i] = mg->n_air; +} + + + +///////////////////////////// [ Ocean biome ] ///////////////////////////////// + + + +void BiomeOcean::genColumn(Mapgen *mg, int x, int z, int y1, int y2) { + int y, i = 0; + + int surfaceh = np->offset + np->scale * mg->map_terrain[z * mg->ystride + x]; + + i = z * mg->zstride + x; + for (y = y1; y <= surfaceh - ntopnodes && y <= y2; y++, i += mg->ystride) + mg->vmanip->m_data[i] = n_filler; + for (; y <= surfaceh && y <= y2; y++, i += mg->ystride) + mg->vmanip->m_data[i] = n_top; + for (; y <= y2; y++, i += mg->ystride) + mg->vmanip->m_data[i] = mg->n_air; +} + + +///////////////////////////// [ Nether biome ] ///////////////////////////////// + + +int BiomeHell::getSurfaceHeight(float noise_terrain) { + return np->offset + np->scale * noise_terrain; +} + + +void BiomeHell::genColumn(Mapgen *mg, int x, int z, int y1, int y2) { + int y, i = 0; + + int surfaceh = np->offset + np->scale * mg->map_terrain[z * mg->ystride + x]; + + i = z * mg->zstride + x; + for (y = y1; y <= surfaceh - ntopnodes && y <= y2; y++, i += mg->ystride) + mg->vmanip->m_data[i] = n_filler; + for (; y <= surfaceh && y <= y2; y++, i += mg->ystride) + mg->vmanip->m_data[i] = n_top; + for (; y <= y2; y++, i += mg->ystride) + mg->vmanip->m_data[i] = mg->n_air; +} + + +///////////////////////////// [ Aether biome ] //////////////////////////////// + +/////////////////////////// [ Superflat biome ] /////////////////////////////// + + +int BiomeSuperflat::getSurfaceHeight(float noise_terrain) { + return ntopnodes; +} + + +void BiomeSuperflat::genColumn(Mapgen *mg, int x, int z, int y1, int y2) { + int y, i = 0; + + int surfaceh = ntopnodes; + + i = z * mg->zstride + x; + for (y = y1; y <= surfaceh - ntopnodes && y <= y2; y++, i += mg->ystride) + mg->vmanip->m_data[i] = n_filler; + for (; y <= surfaceh && y <= y2; y++, i += mg->ystride) + mg->vmanip->m_data[i] = n_top; + for (; y <= y2; y++, i += mg->ystride) + mg->vmanip->m_data[i] = mg->n_air; +} diff --git a/src/biome.h b/src/biome.h new file mode 100644 index 00000000..5e43ab6d --- /dev/null +++ b/src/biome.h @@ -0,0 +1,79 @@ +/* +Minetest-c55 +Copyright (C) 2010-2011 kwolekr, Ryan Kwolek + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#ifndef BIOME_HEADER +#define BIOME_HEADER + +#include "nodedef.h" +#include "gamedef.h" +#include "mapnode.h" +#include "noise.h" +#include "mapgen.h" + +class Biome { +public: + MapNode n_top; + MapNode n_filler; + s16 ntopnodes; + s16 flags; + s16 height_min; + s16 height_max; + float heat_min; + float heat_max; + float humidity_min; + float humidity_max; + const char *name; + NoiseParams *np; + + virtual void genColumn(Mapgen *mg, int x, int z, int y1, int y2); + virtual int getSurfaceHeight(float noise_terrain); +}; + +class BiomeOcean : public Biome { + virtual void genColumn(Mapgen *mg, int x, int z, int y1, int y2); +}; + +class BiomeHell : public Biome { + virtual void genColumn(Mapgen *mg, int x, int z, int y1, int y2); + virtual int getSurfaceHeight(float noise_terrain); +}; + +class BiomeSuperflat : public Biome { + virtual void genColumn(Mapgen *mg, int x, int z, int y1, int y2); + virtual int getSurfaceHeight(float noise_terrain); +}; + +class BiomeDefManager { +public: + std::vector bgroup_freqs; + std::vector *> bgroups; + Biome *biome_default; + IGameDef *m_gamedef; + INodeDefManager *ndef; + + BiomeDefManager(IGameDef *gamedef); + ~BiomeDefManager(); + + Biome *getBiome(float bgfreq, float heat, float humidity); + + void addBiome(); + void addDefaultBiomes(); +}; + +#endif diff --git a/src/defaultsettings.cpp b/src/defaultsettings.cpp index 5a1b76b4..38b9accd 100644 --- a/src/defaultsettings.cpp +++ b/src/defaultsettings.cpp @@ -163,7 +163,7 @@ void set_default_settings(Settings *settings) settings->setDefault("max_block_generate_distance", "7"); settings->setDefault("time_send_interval", "5"); settings->setDefault("time_speed", "72"); - settings->setDefault("water_level", "1"); + settings->setDefault("default_water_level", "1"); settings->setDefault("server_unload_unused_data_timeout", "29"); settings->setDefault("server_map_save_interval", "5.3"); settings->setDefault("full_block_send_enable_min_time_from_building", "2.0"); diff --git a/src/environment.cpp b/src/environment.cpp index 3f94484f..51255b91 100644 --- a/src/environment.cpp +++ b/src/environment.cpp @@ -1301,6 +1301,7 @@ u16 ServerEnvironment::addActiveObject(ServerActiveObject *object) return id; } +#if 0 bool ServerEnvironment::addActiveObjectAsStatic(ServerActiveObject *obj) { assert(obj); @@ -1343,6 +1344,7 @@ bool ServerEnvironment::addActiveObjectAsStatic(ServerActiveObject *obj) return succeeded; } +#endif /* Finds out what new objects have been added to @@ -1563,13 +1565,15 @@ void ServerEnvironment::removeRemovedObjects() */ if(obj->m_static_exists && obj->m_removed) { - MapBlock *block = m_map->emergeBlock(obj->m_static_block); - if(block) - { + MapBlock *block = m_map->emergeBlock(obj->m_static_block, false); + if (block) { block->m_static_objects.remove(id); block->raiseModified(MOD_STATE_WRITE_NEEDED, "removeRemovedObjects"); obj->m_static_exists = false; + } else { + infostream << "failed to emerge block from which " + "an object to be removed was loaded from. id="<getValue(); HeightPoint hp; - s16 level = mapgen::find_ground_level_from_noise(seed, p2d, 3); + s16 level = Mapgen::find_ground_level_from_noise(seed, p2d, 3); hp.gh = (level-4)*BS; hp.ma = (4)*BS; /*hp.gh = BS*base_rock_level_2d(seed, p2d); hp.ma = BS*get_mud_add_amount(seed, p2d);*/ - hp.have_sand = mapgen::get_have_beach(seed, p2d); + hp.have_sand = Mapgen::get_have_beach(seed, p2d); if(hp.gh > BS*WATER_LEVEL) - hp.tree_amount = mapgen::tree_amount_2d(seed, p2d); + hp.tree_amount = Mapgen::tree_amount_2d(seed, p2d); else hp.tree_amount = 0; // No mud has been added if mud amount is less than 1 diff --git a/src/guiPauseMenu.cpp b/src/guiPauseMenu.cpp index c800cf95..f6cbf248 100644 --- a/src/guiPauseMenu.cpp +++ b/src/guiPauseMenu.cpp @@ -1,253 +1,253 @@ -/* -Minetest-c55 -Copyright (C) 2010 celeron55, Perttu Ahola - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU Lesser General Public License as published by -the Free Software Foundation; either version 2.1 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public License along -with this program; if not, write to the Free Software Foundation, Inc., -51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -*/ - -#include "guiPauseMenu.h" -#include "debug.h" -#include "serialization.h" -#include "porting.h" -#include "config.h" -#include "main.h" -#include -#include -#include -#include -#include -#include "gettext.h" -#include "util/string.h" - -GUIPauseMenu::GUIPauseMenu(gui::IGUIEnvironment* env, - gui::IGUIElement* parent, s32 id, - IGameCallback *gamecallback, - IMenuManager *menumgr, - bool simple_singleplayer_mode): - GUIModalMenu(env, parent, id, menumgr), - m_gamecallback(gamecallback), - m_simple_singleplayer_mode(simple_singleplayer_mode) -{ -} - -GUIPauseMenu::~GUIPauseMenu() -{ - removeChildren(); -} - -void GUIPauseMenu::removeChildren() -{ - { - gui::IGUIElement *e = getElementFromId(256); - if(e != NULL) - e->remove(); - } - { - gui::IGUIElement *e = getElementFromId(257); - if(e != NULL) - e->remove(); - } - { - gui::IGUIElement *e = getElementFromId(258); - if(e != NULL) - e->remove(); - } - { - gui::IGUIElement *e = getElementFromId(259); - if(e != NULL) - e->remove(); - } - { - gui::IGUIElement *e = getElementFromId(260); - if(e != NULL) - e->remove(); - } - { - gui::IGUIElement *e = getElementFromId(261); - if(e != NULL) - e->remove(); - } -} - -void GUIPauseMenu::regenerateGui(v2u32 screensize) -{ - /* - Remove stuff - */ - removeChildren(); - - /* - Calculate new sizes and positions - */ - core::rect rect( - screensize.X/2 - 580/2, - screensize.Y/2 - 300/2, - screensize.X/2 + 580/2, - screensize.Y/2 + 300/2 - ); - - DesiredRect = rect; - recalculateAbsolutePosition(false); - - v2s32 size = rect.getSize(); - - /* - Add stuff - */ - const s32 btn_height = 30; - const s32 btn_gap = 20; - const s32 btn_num = m_simple_singleplayer_mode ? 3 : 4; - s32 btn_y = size.Y/2-((btn_num*btn_height+(btn_num-1)*btn_gap))/2; - changeCtype(""); - { - core::rect rect(0, 0, 140, btn_height); - rect = rect + v2s32(size.X/2-140/2, btn_y); - Environment->addButton(rect, this, 256, - wgettext("Continue")); - } - btn_y += btn_height + btn_gap; - if(!m_simple_singleplayer_mode) - { - { - core::rect rect(0, 0, 140, btn_height); - rect = rect + v2s32(size.X/2-140/2, btn_y); - Environment->addButton(rect, this, 261, - wgettext("Change Password")); - } - btn_y += btn_height + btn_gap; - } - { - core::rect rect(0, 0, 140, btn_height); - rect = rect + v2s32(size.X/2-140/2, btn_y); - Environment->addButton(rect, this, 260, - wgettext("Exit to Menu")); - } - btn_y += btn_height + btn_gap; - { - core::rect rect(0, 0, 140, btn_height); - rect = rect + v2s32(size.X/2-140/2, btn_y); - Environment->addButton(rect, this, 257, - wgettext("Exit to OS")); - } - - { - core::rect rect(0, 0, 180, 240); - rect = rect + v2s32(size.X/2 + 90, size.Y/2-rect.getHeight()/2); - Environment->addStaticText(chartowchar_t(gettext( - "Default Controls:\n" - "- WASD: Walk\n" - "- Mouse left: dig/hit\n" - "- Mouse right: place/use\n" - "- Mouse wheel: select item\n" - "- 0...9: select item\n" - "- Shift: sneak\n" - "- R: Toggle viewing all loaded chunks\n" - "- I: Inventory menu\n" - "- ESC: This menu\n" - "- T: Chat\n" - )), rect, false, true, this, 258); - } - { - core::rect rect(0, 0, 180, 220); - rect = rect + v2s32(size.X/2 - 90 - rect.getWidth(), size.Y/2-rect.getHeight()/2); - - v2u32 max_texture_size; - { - video::IVideoDriver* driver = Environment->getVideoDriver(); - max_texture_size = driver->getMaxTextureSize(); - } - - std::ostringstream os; - os<<"Minetest\n"; - os<addStaticText(narrow_to_wide(os.str()).c_str(), rect, false, true, this, 259); - } - changeCtype("C"); -} - -void GUIPauseMenu::drawMenu() -{ - gui::IGUISkin* skin = Environment->getSkin(); - if (!skin) - return; - video::IVideoDriver* driver = Environment->getVideoDriver(); - - video::SColor bgcolor(140,0,0,0); - driver->draw2DRectangle(bgcolor, AbsoluteRect, &AbsoluteClippingRect); - - gui::IGUIElement::draw(); -} - -bool GUIPauseMenu::OnEvent(const SEvent& event) -{ - - if(event.EventType==EET_KEY_INPUT_EVENT) - { - if(event.KeyInput.PressedDown) - { - if(event.KeyInput.Key==KEY_ESCAPE) - { - quitMenu(); - return true; - } - else if(event.KeyInput.Key==KEY_RETURN) - { - quitMenu(); - return true; - } - } - } - if(event.EventType==EET_GUI_EVENT) - { - if(event.GUIEvent.EventType==gui::EGET_ELEMENT_FOCUS_LOST - && isVisible()) - { - if(!canTakeFocus(event.GUIEvent.Element)) - { - dstream<<"GUIPauseMenu: Not allowing focus change." - <getID()) - { - case 256: // continue - quitMenu(); - // ALWAYS return immediately after quitMenu() - return true; - case 261: - quitMenu(); - m_gamecallback->changePassword(); - return true; - case 260: // disconnect - m_gamecallback->disconnect(); - quitMenu(); - return true; - case 257: // exit - m_gamecallback->exitToOS(); - quitMenu(); - return true; - } - } - } - - return Parent ? Parent->OnEvent(event) : false; -} - +/* +Minetest-c55 +Copyright (C) 2010 celeron55, Perttu Ahola + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#include "guiPauseMenu.h" +#include "debug.h" +#include "serialization.h" +#include "porting.h" +#include "config.h" +#include "main.h" +#include +#include +#include +#include +#include +#include "gettext.h" +#include "util/string.h" + +GUIPauseMenu::GUIPauseMenu(gui::IGUIEnvironment* env, + gui::IGUIElement* parent, s32 id, + IGameCallback *gamecallback, + IMenuManager *menumgr, + bool simple_singleplayer_mode): + GUIModalMenu(env, parent, id, menumgr), + m_gamecallback(gamecallback), + m_simple_singleplayer_mode(simple_singleplayer_mode) +{ +} + +GUIPauseMenu::~GUIPauseMenu() +{ + removeChildren(); +} + +void GUIPauseMenu::removeChildren() +{ + { + gui::IGUIElement *e = getElementFromId(256); + if(e != NULL) + e->remove(); + } + { + gui::IGUIElement *e = getElementFromId(257); + if(e != NULL) + e->remove(); + } + { + gui::IGUIElement *e = getElementFromId(258); + if(e != NULL) + e->remove(); + } + { + gui::IGUIElement *e = getElementFromId(259); + if(e != NULL) + e->remove(); + } + { + gui::IGUIElement *e = getElementFromId(260); + if(e != NULL) + e->remove(); + } + { + gui::IGUIElement *e = getElementFromId(261); + if(e != NULL) + e->remove(); + } +} + +void GUIPauseMenu::regenerateGui(v2u32 screensize) +{ + /* + Remove stuff + */ + removeChildren(); + + /* + Calculate new sizes and positions + */ + core::rect rect( + screensize.X/2 - 580/2, + screensize.Y/2 - 300/2, + screensize.X/2 + 580/2, + screensize.Y/2 + 300/2 + ); + + DesiredRect = rect; + recalculateAbsolutePosition(false); + + v2s32 size = rect.getSize(); + + /* + Add stuff + */ + const s32 btn_height = 30; + const s32 btn_gap = 20; + const s32 btn_num = m_simple_singleplayer_mode ? 3 : 4; + s32 btn_y = size.Y/2-((btn_num*btn_height+(btn_num-1)*btn_gap))/2; + changeCtype(""); + { + core::rect rect(0, 0, 140, btn_height); + rect = rect + v2s32(size.X/2-140/2, btn_y); + Environment->addButton(rect, this, 256, + wgettext("Continue")); + } + btn_y += btn_height + btn_gap; + if(!m_simple_singleplayer_mode) + { + { + core::rect rect(0, 0, 140, btn_height); + rect = rect + v2s32(size.X/2-140/2, btn_y); + Environment->addButton(rect, this, 261, + wgettext("Change Password")); + } + btn_y += btn_height + btn_gap; + } + { + core::rect rect(0, 0, 140, btn_height); + rect = rect + v2s32(size.X/2-140/2, btn_y); + Environment->addButton(rect, this, 260, + wgettext("Exit to Menu")); + } + btn_y += btn_height + btn_gap; + { + core::rect rect(0, 0, 140, btn_height); + rect = rect + v2s32(size.X/2-140/2, btn_y); + Environment->addButton(rect, this, 257, + wgettext("Exit to OS")); + } + + { + core::rect rect(0, 0, 180, 240); + rect = rect + v2s32(size.X/2 + 90, size.Y/2-rect.getHeight()/2); + Environment->addStaticText(chartowchar_t(gettext( + "Default Controls:\n" + "- WASD: Walk\n" + "- Mouse left: dig/hit\n" + "- Mouse right: place/use\n" + "- Mouse wheel: select item\n" + "- 0...9: select item\n" + "- Shift: sneak\n" + "- R: Toggle viewing all loaded chunks\n" + "- I: Inventory menu\n" + "- ESC: This menu\n" + "- T: Chat\n" + )), rect, false, true, this, 258); + } + { + core::rect rect(0, 0, 180, 220); + rect = rect + v2s32(size.X/2 - 90 - rect.getWidth(), size.Y/2-rect.getHeight()/2); + + v2u32 max_texture_size; + { + video::IVideoDriver* driver = Environment->getVideoDriver(); + max_texture_size = driver->getMaxTextureSize(); + } + + std::ostringstream os; + os<<"Minetest\n"; + os<addStaticText(narrow_to_wide(os.str()).c_str(), rect, false, true, this, 259); + } + changeCtype("C"); +} + +void GUIPauseMenu::drawMenu() +{ + gui::IGUISkin* skin = Environment->getSkin(); + if (!skin) + return; + video::IVideoDriver* driver = Environment->getVideoDriver(); + + video::SColor bgcolor(140,0,0,0); + driver->draw2DRectangle(bgcolor, AbsoluteRect, &AbsoluteClippingRect); + + gui::IGUIElement::draw(); +} + +bool GUIPauseMenu::OnEvent(const SEvent& event) +{ + + if(event.EventType==EET_KEY_INPUT_EVENT) + { + if(event.KeyInput.PressedDown) + { + if(event.KeyInput.Key==KEY_ESCAPE) + { + quitMenu(); + return true; + } + else if(event.KeyInput.Key==KEY_RETURN) + { + quitMenu(); + return true; + } + } + } + if(event.EventType==EET_GUI_EVENT) + { + if(event.GUIEvent.EventType==gui::EGET_ELEMENT_FOCUS_LOST + && isVisible()) + { + if(!canTakeFocus(event.GUIEvent.Element)) + { + dstream<<"GUIPauseMenu: Not allowing focus change." + <getID()) + { + case 256: // continue + quitMenu(); + // ALWAYS return immediately after quitMenu() + return true; + case 261: + quitMenu(); + m_gamecallback->changePassword(); + return true; + case 260: // disconnect + m_gamecallback->disconnect(); + quitMenu(); + return true; + case 257: // exit + m_gamecallback->exitToOS(); + quitMenu(); + return true; + } + } + } + + return Parent ? Parent->OnEvent(event) : false; +} + diff --git a/src/guiPauseMenu.h b/src/guiPauseMenu.h index e28159a9..4b15fc74 100644 --- a/src/guiPauseMenu.h +++ b/src/guiPauseMenu.h @@ -1,60 +1,60 @@ -/* -Minetest-c55 -Copyright (C) 2010 celeron55, Perttu Ahola - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU Lesser General Public License as published by -the Free Software Foundation; either version 2.1 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public License along -with this program; if not, write to the Free Software Foundation, Inc., -51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -*/ - -#ifndef GUIPAUSEMENU_HEADER -#define GUIPAUSEMENU_HEADER - -#include "irrlichttypes_extrabloated.h" -#include "modalMenu.h" - -class IGameCallback -{ -public: - virtual void exitToOS() = 0; - virtual void disconnect() = 0; - virtual void changePassword() = 0; -}; - -class GUIPauseMenu : public GUIModalMenu -{ -public: - GUIPauseMenu(gui::IGUIEnvironment* env, - gui::IGUIElement* parent, s32 id, - IGameCallback *gamecallback, - IMenuManager *menumgr, - bool simple_singleplayer_mode); - ~GUIPauseMenu(); - - void removeChildren(); - /* - Remove and re-add (or reposition) stuff - */ - void regenerateGui(v2u32 screensize); - - void drawMenu(); - - bool OnEvent(const SEvent& event); - -private: - IGameCallback *m_gamecallback; - bool m_simple_singleplayer_mode; -}; - -#endif - +/* +Minetest-c55 +Copyright (C) 2010 celeron55, Perttu Ahola + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#ifndef GUIPAUSEMENU_HEADER +#define GUIPAUSEMENU_HEADER + +#include "irrlichttypes_extrabloated.h" +#include "modalMenu.h" + +class IGameCallback +{ +public: + virtual void exitToOS() = 0; + virtual void disconnect() = 0; + virtual void changePassword() = 0; +}; + +class GUIPauseMenu : public GUIModalMenu +{ +public: + GUIPauseMenu(gui::IGUIEnvironment* env, + gui::IGUIElement* parent, s32 id, + IGameCallback *gamecallback, + IMenuManager *menumgr, + bool simple_singleplayer_mode); + ~GUIPauseMenu(); + + void removeChildren(); + /* + Remove and re-add (or reposition) stuff + */ + void regenerateGui(v2u32 screensize); + + void drawMenu(); + + bool OnEvent(const SEvent& event); + +private: + IGameCallback *m_gamecallback; + bool m_simple_singleplayer_mode; +}; + +#endif + diff --git a/src/map.cpp b/src/map.cpp index 6147bb63..0896c9b4 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -1994,7 +1994,7 @@ void Map::removeNodeTimer(v3s16 p) ServerMap */ -ServerMap::ServerMap(std::string savedir, IGameDef *gamedef): +ServerMap::ServerMap(std::string savedir, IGameDef *gamedef, EmergeManager *emerge): Map(dout_server, gamedef), m_seed(0), m_map_metadata_changed(true), @@ -2004,6 +2004,8 @@ ServerMap::ServerMap(std::string savedir, IGameDef *gamedef): { verbosestream<<__FUNCTION_NAME<get("fixed_map_seed").empty()) @@ -2011,12 +2013,15 @@ ServerMap::ServerMap(std::string savedir, IGameDef *gamedef): m_seed = (((u64)(myrand()%0xffff)<<0) + ((u64)(myrand()%0xffff)<<16) + ((u64)(myrand()%0xffff)<<32) - + ((u64)(myrand()%0xffff)<<48)); + + ((u64)(myrand()&0xffff)<<48)); } else { m_seed = g_settings->getU64("fixed_map_seed"); } + emerge->seed = m_seed; + emerge->water_level = g_settings->getS16("default_water_level"); + // /* Experimental and debug stuff @@ -2136,7 +2141,7 @@ ServerMap::~ServerMap() #endif } -void ServerMap::initBlockMake(mapgen::BlockMakeData *data, v3s16 blockpos) +void ServerMap::initBlockMake(BlockMakeData *data, v3s16 blockpos) { bool enable_mapgen_debug_info = g_settings->getBool("enable_mapgen_debug_info"); if(enable_mapgen_debug_info) @@ -2208,7 +2213,7 @@ void ServerMap::initBlockMake(mapgen::BlockMakeData *data, v3s16 blockpos) Refer to the map generator heuristics. */ - bool ug = mapgen::block_is_underground(data->seed, p); + bool ug = m_emerge->isBlockUnderground(p); block->setIsUnderground(ug); } @@ -2243,7 +2248,7 @@ void ServerMap::initBlockMake(mapgen::BlockMakeData *data, v3s16 blockpos) // Data is ready now. } -MapBlock* ServerMap::finishBlockMake(mapgen::BlockMakeData *data, +MapBlock* ServerMap::finishBlockMake(BlockMakeData *data, core::map &changed_blocks) { v3s16 blockpos_min = data->blockpos_min; @@ -2483,6 +2488,7 @@ ServerMapSector * ServerMap::createSector(v2s16 p2d) return sector; } +#if 0 /* This is a quick-hand function for calling makeBlock(). */ @@ -2518,7 +2524,7 @@ MapBlock * ServerMap::generateBlock( /* Create block make data */ - mapgen::BlockMakeData data; + BlockMakeData data; initBlockMake(&data, p); /* @@ -2526,7 +2532,8 @@ MapBlock * ServerMap::generateBlock( */ { TimeTaker t("mapgen::make_block()"); - mapgen::make_block(&data); + mapgen->makeChunk(&data); + //mapgen::make_block(&data); if(enable_mapgen_debug_info == false) t.stop(true); // Hide output @@ -2595,6 +2602,7 @@ MapBlock * ServerMap::generateBlock( return block; } +#endif MapBlock * ServerMap::createBlock(v3s16 p) { @@ -2656,14 +2664,15 @@ MapBlock * ServerMap::createBlock(v3s16 p) } // Create blank block = sector->createBlankBlock(block_y); + return block; } -MapBlock * ServerMap::emergeBlock(v3s16 p, bool allow_generate) +MapBlock * ServerMap::emergeBlock(v3s16 p, bool create_blank) { - DSTACKF("%s: p=(%d,%d,%d), allow_generate=%d", + DSTACKF("%s: p=(%d,%d,%d), create_blank=%d", __FUNCTION_NAME, - p.X, p.Y, p.Z, allow_generate); + p.X, p.Y, p.Z, create_blank); { MapBlock *block = getBlockNoCreateNoEx(p); @@ -2677,7 +2686,13 @@ MapBlock * ServerMap::emergeBlock(v3s16 p, bool allow_generate) return block; } - if(allow_generate) + if (create_blank) { + ServerMapSector *sector = createSector(v2s16(p.X, p.Z)); + MapBlock *block = sector->createBlankBlock(p.Y); + + return block; + } + /*if(allow_generate) { core::map modified_blocks; MapBlock *block = generateBlock(p, modified_blocks); @@ -2700,7 +2715,7 @@ MapBlock * ServerMap::emergeBlock(v3s16 p, bool allow_generate) return block; } - } + }*/ return NULL; } @@ -2742,7 +2757,7 @@ plan_b: Determine from map generator noise functions */ - s16 level = mapgen::find_ground_level_from_noise(m_seed, p2d, 1); + s16 level = m_emerge->getGroundLevelAtPoint(p2d); return level; //double level = base_rock_level_2d(m_seed, p2d) + AVERAGE_MUD_AMOUNT; @@ -3062,6 +3077,7 @@ void ServerMap::saveMapMeta() Settings params; params.setU64("seed", m_seed); + params.setS16("water_level", m_emerge->water_level); params.writeLines(os); @@ -3100,8 +3116,11 @@ void ServerMap::loadMapMeta() break; params.parseConfigLine(line); } - + m_seed = params.getU64("seed"); + m_emerge->seed = m_seed; + m_emerge->water_level = params.getS16("water_level"); + //m_emerge->np = ; verbosestream<<"ServerMap::loadMapMeta(): "<<"seed="< &changed_blocks); - // A non-threaded wrapper to the above - MapBlock * generateBlock( + // A non-threaded wrapper to the above - DEFUNCT +/* MapBlock * generateBlock( v3s16 p, core::map &modified_blocks - ); + );*/ /* Get a block from somewhere. @@ -400,9 +398,10 @@ public: Forcefully get a block from somewhere. - Memory - Load from disk - - Generate + - Create blank filled with CONTENT_IGNORE + */ - MapBlock * emergeBlock(v3s16 p, bool allow_generate=true); + MapBlock * emergeBlock(v3s16 p, bool create_blank=true); // Helper for placing objects on ground level s16 findGroundLevel(v2s16 p2d); @@ -479,6 +478,7 @@ public: u64 getSeed(){ return m_seed; } + EmergeManager *m_emerge; private: // Seed used for all kinds of randomness in generation u64 m_seed; diff --git a/src/mapgen.cpp b/src/mapgen.cpp index ae0c551c..7271b765 100644 --- a/src/mapgen.cpp +++ b/src/mapgen.cpp @@ -20,7 +20,9 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "mapgen.h" #include "voxel.h" #include "noise.h" +#include "biome.h" #include "mapblock.h" +#include "mapnode.h" #include "map.h" //#include "serverobject.h" #include "content_sao.h" @@ -28,9 +30,296 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "content_mapnode.h" // For content_mapnode_get_new_name #include "voxelalgorithms.h" #include "profiler.h" +#include "settings.h" // For g_settings #include "main.h" // For g_profiler #include "treegen.h" +NoiseParams nparams_mtdefault = + {0.0, 20.0, v3f(250., 250., 250.), 82341, 5, 0.6}; //terrain +NoiseParams nparams_def_bgroup = + {0.5, 1/(2*1.6), v3f(250., 250., 250.), 5923, 2, 0.60}; //0 to 1 +NoiseParams nparams_def_heat = + {25.0, 50.0, v3f(500., 500., 500.), 35293, 1, 0.00}; //-25 to 75 +NoiseParams nparams_def_humidity = + {50, 100/(2*1.6), v3f(750., 750., 750.), 12094, 2, 0.60}; //0 to 100 + + +/////////////////////////////////////////////////////////////////////////////// + +/* +Mapgen::Mapgen(BiomeDefManager *biomedef) { + Mapgen(0, 0, biomedef); +}*/ + + +Mapgen::Mapgen(BiomeDefManager *biomedef, int mapgenid, u64 seed) { + initMapgen(biomedef, mapgenid, seed, + &nparams_mtdefault, &nparams_def_bgroup, + &nparams_def_heat, &nparams_def_humidity); +} + + +Mapgen::Mapgen(BiomeDefManager *biomedef, int mapgenid, u64 seed, + NoiseParams *np_terrain, NoiseParams *np_bgroup, + NoiseParams *np_heat, NoiseParams *np_humidity) { + initMapgen(biomedef, mapgenid, seed, + np_terrain, np_bgroup, np_heat, np_humidity); +} + +void Mapgen::initMapgen(BiomeDefManager *biomedef, int mapgenid, u64 seed, + NoiseParams *np_terrain, NoiseParams *np_bgroup, + NoiseParams *np_heat, NoiseParams *np_humidity) { + this->generating = false; + this->id = mapgenid; + this->seed = (int)seed; + this->biomedef = biomedef; + this->csize = v3s16(5, 5, 5) * MAP_BLOCKSIZE; /////////////////get this from config! + this->water_level = g_settings->getS16("default_water_level"); ////fix this! + + this->np_terrain = np_terrain; + this->np_bgroup = np_bgroup; + this->np_heat = np_heat; + this->np_humidity = np_humidity; + noise_terrain = new Noise(np_terrain, seed, csize.X, csize.Y); + noise_bgroup = new Noise(np_bgroup, seed, csize.X, csize.Y); + noise_heat = new Noise(np_heat, seed, csize.X, csize.Y); + noise_humidity = new Noise(np_humidity, seed, csize.X, csize.Y); + + this->ndef = biomedef->ndef; + n_air = MapNode(ndef->getId("mapgen_air")); + n_water = MapNode(ndef->getId("mapgen_water_source")); + n_lava = MapNode(ndef->getId("mapgen_lava_source")); +} + + +Mapgen::~Mapgen() { + delete noise_terrain; + delete noise_bgroup; + delete noise_heat; + delete noise_humidity; +} + + +void Mapgen::makeChunk(BlockMakeData *data) { + if (data->no_op) + return; + + //printf("generating...\n");////////////// + + assert(data->vmanip); + assert(data->nodedef); + assert(data->blockpos_requested.X >= data->blockpos_min.X && + data->blockpos_requested.Y >= data->blockpos_min.Y && + data->blockpos_requested.Z >= data->blockpos_min.Z); + assert(data->blockpos_requested.X <= data->blockpos_max.X && + data->blockpos_requested.Y <= data->blockpos_max.Y && + data->blockpos_requested.Z <= data->blockpos_max.Z); + + this->generating = true; + + this->data = data; + this->vmanip = data->vmanip; + v3s16 em = vmanip->m_area.getExtent(); + this->ystride = em.X; + this->zstride = em.Y * em.X; + + node_min = (data->blockpos_min) * MAP_BLOCKSIZE; + node_max = (data->blockpos_max + v3s16(1, 1, 1)) * MAP_BLOCKSIZE - v3s16(1, 1, 1); + v3s16 full_node_min = (data->blockpos_min - 1) * MAP_BLOCKSIZE; + v3s16 full_node_max = (data->blockpos_max + 2) * MAP_BLOCKSIZE - v3s16(1,1,1); + + int y1 = node_min.Y; + int y2 = node_max.Y; + int x = node_min.X; + int z = node_min.Z; + //printf("full_node_min.X: %d | full_node_min.Z: %d | MinEdge: %d | MaxEdge: %d\n", node_min.X, node_min.Z, vmanip->m_area.MinEdge.X, vmanip->m_area.MinEdge.Z); + TimeTaker timer("Generating terrain"); + map_terrain = noise_terrain->perlinMap2D(x, z); + map_bgroup = noise_bgroup->perlinMap2D(x, z); + map_heat = noise_heat->perlinMap2D(x, z); + map_humidity = noise_humidity->perlinMap2D(x, z); + + int i = 0; + for (x = node_min.X; x <= node_max.X; x++) { + for (z = node_min.Z; z <= node_max.Z; z++) { + Biome *biome = biomedef->getBiome(map_bgroup[i], map_heat[i], map_humidity[i]); + biome->genColumn(this, x, z, y1, y2); + i++; + } + } + timer.stop(); + + //genCave(); + //genDungeon(); + //add blobs of dirt and gravel underground + //decorateChunk(); + //updateLiquid(full_node_min, full_node_max); + updateLighting(node_min, node_max); + + this->generating = false; + //printf("generated block (%d, %d) to (%d, %d)\n", node_min.X, node_min.Y, node_max.X, node_max.Y);////////// +} + + +void Mapgen::updateLiquid(v3s16 node_min, v3s16 node_max) { + bool isliquid, wasliquid; + u32 i; + content_t c; + + for (s16 z = node_min.Z; z <= node_max.Z; z++) { + for (s16 x = node_min.X; x <= node_max.X; x++) { + v2s16 p2d(x, z); + wasliquid = true; + v3s16 em = vmanip->m_area.getExtent(); + i = vmanip->m_area.index(v3s16(p2d.X, node_max.Y, p2d.Y)); + + for (s16 y = node_max.Y; y >= node_min.Y; y--) { + isliquid = ndef->get(vmanip->m_data[i]).isLiquid(); + //there was a change between liquid and nonliquid, add to queue + if (isliquid != wasliquid) + data->transforming_liquid.push_back(v3s16(p2d.X, y, p2d.Y)); + + wasliquid = isliquid; + vmanip->m_area.add_y(em, i, -1); + } + } + } +} + + +void Mapgen::updateLighting(v3s16 node_min, v3s16 node_max) { + enum LightBank banks[2] = {LIGHTBANK_DAY, LIGHTBANK_NIGHT}; + + VoxelArea a(node_min - v3s16(1,0,1) * MAP_BLOCKSIZE, + node_max + v3s16(1,0,1) * MAP_BLOCKSIZE); + bool block_is_underground = (water_level > node_max.Y); + 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]; + core::map light_sources; + core::map unlight_from; + + voxalgo::clearLightAndCollectSources(*vmanip, a, bank, ndef, + light_sources, unlight_from); + voxalgo::propagateSunlight(*vmanip, a, sunlight, light_sources, ndef); + printf("light_sources: %d\t\tunlight_from: %d\n", light_sources.size(), unlight_from.size()); + vmanip->unspreadLight(bank, unlight_from, light_sources, ndef); + vmanip->spreadLight(bank, light_sources, ndef); + } +} + + +/*class EmergeManager { +public: + int seed; + int water_level; + BiomeDefManager *biomedef; + + //mapgen objects here + + void addBlockToQueue(); + + + //mapgen helper methods + int getGroundLevelAtPoint(u64 mseed, v2s16 p); + bool isBlockUnderground(u64 mseed, v3s16 blockpos); + u32 getBlockSeed(u64 mseed, v3s16 p); +};*/ + +EmergeManager::EmergeManager(IGameDef *gamedef) { + this->seed = 0; + this->water_level = 0; + this->np_terrain = &nparams_mtdefault; + this->np_bgroup = &nparams_def_bgroup; + this->np_heat = &nparams_def_heat; + this->np_humidity = &nparams_def_humidity; + + this->biomedef = new BiomeDefManager(gamedef); +} + + +EmergeManager::~EmergeManager() { + delete biomedef; +} + + +void EmergeManager::addBlockToQueue() { + +} + + +Biome *EmergeManager::getBiomeAtPoint(v3s16 p) { + float bgroup = NoisePerlin2D(np_bgroup, p.X, p.Y, seed); + float heat = NoisePerlin2D(np_heat, p.X, p.Y, seed); + float humidity = NoisePerlin2D(np_humidity, p.X, p.Y, seed); + return biomedef->getBiome(bgroup, heat, humidity); +} + + +//FIXME: This assumes y == 0, that is, always in a non-hell/non-sky biome +int EmergeManager::getGroundLevelAtPoint(v2s16 p) { + float terrain = NoisePerlin2D(np_terrain, p.X, p.Y, seed); + Biome *biome = getBiomeAtPoint(v3s16(p.X, p.Y, 0)); + return biome->getSurfaceHeight(terrain); +} + + +bool EmergeManager::isBlockUnderground(v3s16 blockpos) { + /* + v2s16 p = v2s16((blockpos.X * MAP_BLOCKSIZE) + MAP_BLOCKSIZE / 2, + (blockpos.Y * MAP_BLOCKSIZE) + MAP_BLOCKSIZE / 2); + int ground_level = getGroundLevelAtPoint(p); + return blockpos.Y * (MAP_BLOCKSIZE + 1) <= min(water_level, ground_level); + */ + + //yuck, but then again, should i bother being accurate? + //the height of the nodes in a single block is quite variable + return false; //blockpos.Y * (MAP_BLOCKSIZE + 1) <= water_level; +} + + +u32 EmergeManager::getBlockSeed(v3s16 p) { + return (u32)(seed & 0xFFFFFFFF) + + p.Z * 38134234 + + p.Y * 42123 + + p.Y * 23; +} + + +/////////////////////////////////// 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; + return level; +} + + +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); + + return (sandnoise > 0.15); +} + + +double Mapgen::tree_amount_2d(u64 seed, v2s16 p) { + double noise = noise2d_perlin( + 0.5+(float)p.X/125, 0.5+(float)p.Y/125, + seed+2, 4, 0.66); + double zeroval = -0.39; + if(noise < zeroval) + return 0; + else + return 0.04 * (noise-zeroval) / (1.0-zeroval); +} + + +#if 0 /// BIG COMMENT namespace mapgen { @@ -121,6 +410,7 @@ static s16 find_stone_level(VoxelManipulator &vmanip, v2s16 p2d, } #endif + #if 0 static void make_papyrus(VoxelManipulator &vmanip, v3s16 p0, @@ -190,7 +480,7 @@ static void make_room1(VoxelManipulator &vmanip, v3s16 roomsize, v3s16 roomplace vmanip.m_data[vi] = MapNode(ndef->getId("mapgen_cobble")); } } - + // Make +-Z walls for(s16 x=0; xgetId("mapgen_cobble")); } } - + // Make +-Y walls (floor and ceiling) for(s16 z=0; zgetId("mapgen_cobble")); } } - + // Fill with air for(s16 z=1; z= partlength) { partcount = 0; - + dir = random_turn(random, dir); - + partlength = random.range(1,length); make_stairs = 0; @@ -443,7 +733,7 @@ public: { m_dir = dir; } - + bool findPlaceForDoor(v3s16 &result_place, v3s16 &result_dir) { for(u32 i=0; i<100; i++) @@ -540,7 +830,7 @@ public: if(doordir == v3s16(0,0,-1)) // Z- roomplace = doorplace + v3s16(-roomsize.X/2,-1,-roomsize.Z+1); #endif - + // Check fit bool fits = true; for(s16 z=1; z 0.45) + if(d > 0.45) return BT_DESERT; - if(d > 0.35 && (noise2d( p2d.X, p2d.Y, int(seed) ) + 1.0) > ( 0.45 - d ) * 20.0 ) + if(d > 0.35 && (noise2d( p2d.X, p2d.Y, int(seed) ) + 1.0) > ( 0.45 - d ) * 20.0 ) return BT_DESERT; return BT_NORMAL; }; @@ -1169,7 +1459,7 @@ void make_block(BlockMakeData *data) // Hack: use minimum block coordinates for old code that assumes // a single block v3s16 blockpos = data->blockpos_requested; - + /*dstream<<"makeBlock(): ("<blockpos_max; v3s16 blockpos_full_min = blockpos_min - v3s16(1,1,1); v3s16 blockpos_full_max = blockpos_max + v3s16(1,1,1); - + ManualMapVoxelManipulator &vmanip = *(data->vmanip); // Area of central chunk v3s16 node_min = blockpos_min*MAP_BLOCKSIZE; @@ -1193,10 +1483,10 @@ void make_block(BlockMakeData *data) int volume_blocks = (blockpos_max.X - blockpos_min.X + 1) * (blockpos_max.Y - blockpos_min.Y + 1) * (blockpos_max.Z - blockpos_max.Z + 1); - + int volume_nodes = volume_blocks * MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE; - + // Generated surface area //double gen_area_nodes = MAP_BLOCKSIZE*MAP_BLOCKSIZE * rel_volume; @@ -1207,7 +1497,7 @@ void make_block(BlockMakeData *data) Create a block-specific seed */ u32 blockseed = get_blockseed(data->seed, full_node_min); - + /* Cache some ground type values for speed */ @@ -1253,13 +1543,13 @@ void make_block(BlockMakeData *data) { #if 1 TimeTaker timer1("Generating ground level"); - + for(s16 x=node_min.X; x<=node_max.X; x++) for(s16 z=node_min.Z; z<=node_max.Z; z++) { // Node position v2s16 p2d = v2s16(x,z); - + /* Skip of already generated */ @@ -1274,7 +1564,7 @@ void make_block(BlockMakeData *data) // Use perlin noise for ground height surface_y_f = base_rock_level_2d(data->seed, p2d); - + /*// Experimental stuff { float a = highlands_level_2d(data->seed, p2d); @@ -1284,7 +1574,7 @@ void make_block(BlockMakeData *data) // Convert to integer s16 surface_y = (s16)surface_y_f; - + // Log it if(surface_y > stone_surface_max_y) stone_surface_max_y = surface_y; @@ -1316,9 +1606,9 @@ void make_block(BlockMakeData *data) } } #endif - + }//timer1 - + // Limit dirt flow area by 1 because mud is flown into neighbors. assert(central_area_size.X == central_area_size.Z); s16 mudflow_minpos = 0-max_spread_amount+1; @@ -1375,7 +1665,7 @@ void make_block(BlockMakeData *data) tunnel_routepoints = ps.range(10, ps.range(15,30)); } bool large_cave_is_flat = (ps.range(0,1) == 0); - + v3f main_direction(0,0,0); // Allowed route area size in nodes @@ -1391,7 +1681,7 @@ void make_block(BlockMakeData *data) s16 more = max_spread_amount - max_tunnel_diameter/2 - insure; ar += v3s16(1,0,1) * more * 2; of -= v3s16(1,0,1) * more; - + s16 route_y_min = 0; // Allow half a diameter + 7 over stone surface s16 route_y_max = -of.Y + stone_surface_max_y + max_tunnel_diameter/2 + 7; @@ -1434,7 +1724,7 @@ void make_block(BlockMakeData *data) if(coming_from_surface) route_start_y_min = -of.Y + stone_surface_max_y + 10; }*/ - + route_start_y_min = rangelim(route_start_y_min, 0, ar.Y-1); route_start_y_max = rangelim(route_start_y_max, route_start_y_min, ar.Y-1); @@ -1451,11 +1741,11 @@ void make_block(BlockMakeData *data) MapNode airnode(CONTENT_AIR); MapNode waternode(c_water_source); MapNode lavanode(c_lava_source); - + /* Generate some tunnel starting from orp */ - + for(u16 j=0; jseed, p2d) / 2.0 + 0.5; @@ -1660,7 +1950,7 @@ void make_block(BlockMakeData *data) surface_y + mud_add_amount <= WATER_LEVEL+2){ addnode = MapNode(c_sand); } - + if(bt == BT_DESERT){ if(surface_y > 20){ mud_add_amount = MYMAX(0, mud_add_amount - (surface_y - 20)/5); @@ -1691,7 +1981,7 @@ void make_block(BlockMakeData *data) { if(mudcount >= mud_add_amount) break; - + MapNode &n = vmanip.m_data[i]; n = addnode; mudcount++; @@ -1756,7 +2046,7 @@ void make_block(BlockMakeData *data) /* Flow mud away from steep edges */ - + // Iterate a few times for(s16 k=0; k<3; k++) { @@ -1773,7 +2063,7 @@ void make_block(BlockMakeData *data) // Node position in 2d v2s16 p2d = v2s16(node_min.X, node_min.Z) + v2s16(x,z); - + v3s16 em = vmanip.m_area.getExtent(); u32 i = vmanip.m_area.index(v3s16(p2d.X, node_max.Y, p2d.Y)); s16 y=node_max.Y; @@ -1794,7 +2084,7 @@ void make_block(BlockMakeData *data) n->getContent() == c_dirt_with_grass || n->getContent() == c_gravel) break; - + vmanip.m_area.add_y(em, i, -1); } @@ -1813,7 +2103,7 @@ void make_block(BlockMakeData *data) { // Make it exactly mud n->setContent(c_dirt); - + /* Don't flow it if the stuff under it is not mud */ @@ -1851,7 +2141,7 @@ void make_block(BlockMakeData *data) } // Drop mud on side - + for(u32 di=0; di<4; di++) { v3s16 dirp = dirs4[di]; @@ -1894,7 +2184,7 @@ void make_block(BlockMakeData *data) // Loop one up so that we're in air vmanip.m_area.add_y(em, i2, 1); n2 = &vmanip.m_data[i2]; - + bool old_is_water = (n->getContent() == c_water_source); // Move mud to new place if(!dropped_to_unknown) { @@ -1912,7 +2202,7 @@ void make_block(BlockMakeData *data) } } } - + } }//timer1 @@ -1940,7 +2230,7 @@ void make_block(BlockMakeData *data) for(s16 y=full_node_max.Y; y>=full_node_min.Y; y--) { if(y == full_node_max.Y){ - water_found = + water_found = (vmanip.m_data[i].getContent() == c_water_source || vmanip.m_data[i].getContent() == c_lava_source); } @@ -1982,7 +2272,7 @@ void make_block(BlockMakeData *data) { // Node position in 2d v2s16 p2d = v2s16(x,z); - + /* Find the lowest surface to which enough light ends up to make grass grow. @@ -2008,7 +2298,7 @@ void make_block(BlockMakeData *data) else surface_y = full_node_min.Y; } - + u32 i = vmanip.m_area.index(p2d.X, surface_y, p2d.Y); MapNode *n = &vmanip.m_data[i]; if(n->getContent() == c_dirt){ @@ -2113,7 +2403,7 @@ void make_block(BlockMakeData *data) else vmanip.m_data[i] = n_stone; } - + vmanip->m_area.add_y(em, i, 1); } } @@ -2168,7 +2458,7 @@ void make_block(BlockMakeData *data) /* Add dungeons */ - + //if(node_min.Y < approx_groundlevel) //if(myrand() % 3 == 0) //if(myrand() % 3 == 0 && node_min.Y < approx_groundlevel) @@ -2182,7 +2472,7 @@ void make_block(BlockMakeData *data) // Dungeon generator doesn't modify places which have this set vmanip->clearFlag(VMANIP_FLAG_DUNGEON_INSIDE | VMANIP_FLAG_DUNGEON_PRESERVE); - + // Set all air and water to be untouchable to make dungeons open // to caves and open air for(s16 x=full_node_min.X; x<=full_node_max.X; x++) @@ -2204,12 +2494,12 @@ void make_block(BlockMakeData *data) } } } - + PseudoRandom random(blockseed+2); // Add it make_dungeon1(vmanip, random, ndef); - + // Convert some cobble to mossy cobble for(s16 x=full_node_min.X; x<=full_node_max.X; x++) for(s16 z=full_node_min.Z; z<=full_node_max.Z; z++) @@ -2257,7 +2547,7 @@ void make_block(BlockMakeData *data) make_nc(vmanip, ncrandom, ndef); } } - + /* Add top and bottom side of water to transforming_liquid queue */ @@ -2346,7 +2636,7 @@ void make_block(BlockMakeData *data) if(current_depth == 0 && y <= WATER_LEVEL+2 && possibly_have_sand) have_sand = true; - + if(current_depth < 4) { if(have_sand) @@ -2384,7 +2674,7 @@ void make_block(BlockMakeData *data) /* Calculate some stuff */ - + float surface_humidity = surface_humidity_2d(data->seed, p2d_center); bool is_jungle = surface_humidity > 0.75; // Amount of trees @@ -2521,7 +2811,7 @@ void make_block(BlockMakeData *data) /* Add some kind of random stones */ - + u32 random_stone_count = gen_area_nodes * randomstone_amount_2d(data->seed, p2d_center); // Put in random places on part of division @@ -2555,7 +2845,7 @@ void make_block(BlockMakeData *data) /* Add larger stones */ - + u32 large_stone_count = gen_area_nodes * largestone_amount_2d(data->seed, p2d_center); //u32 large_stone_count = 1; @@ -2612,7 +2902,7 @@ void make_block(BlockMakeData *data) if(mineralrandom.next()%8 == 0) vmanip.m_data[vi] = MapNode(c_mese); } - + } } /* @@ -2742,7 +3032,7 @@ void make_block(BlockMakeData *data) voxalgo::clearLightAndCollectSources(vmanip, a, bank, ndef, light_sources, unlight_from); - + bool inexistent_top_provides_sunlight = !block_is_underground; voxalgo::SunlightPropagateResult res = voxalgo::propagateSunlight( vmanip, a, inexistent_top_provides_sunlight, @@ -2756,6 +3046,8 @@ void make_block(BlockMakeData *data) } } +#endif ///BIG COMMENT + BlockMakeData::BlockMakeData(): no_op(false), vmanip(NULL), @@ -2768,6 +3060,6 @@ BlockMakeData::~BlockMakeData() delete vmanip; } -}; // namespace mapgen +//}; // namespace mapgen diff --git a/src/mapgen.h b/src/mapgen.h index 8986ddab..d6e932ca 100644 --- a/src/mapgen.h +++ b/src/mapgen.h @@ -22,12 +22,121 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "irrlichttypes_extrabloated.h" #include "util/container.h" // UniqueQueue +#include "gamedef.h" +#include "mapnode.h" +#include "noise.h" -struct BlockMakeData; +class BiomeDefManager; +class Biome; + +//struct BlockMakeData; class MapBlock; class ManualMapVoxelManipulator; class INodeDefManager; +struct BlockMakeData { + bool no_op; + ManualMapVoxelManipulator *vmanip; + u64 seed; + v3s16 blockpos_min; + v3s16 blockpos_max; + v3s16 blockpos_requested; + UniqueQueue transforming_liquid; + INodeDefManager *nodedef; + + BlockMakeData(); + ~BlockMakeData(); +}; + +class Mapgen { +public: + BlockMakeData *data; + ManualMapVoxelManipulator *vmanip; + INodeDefManager *ndef; + BiomeDefManager *biomedef; + + int ystride; + int zstride; + + v3s16 csize; + int seed; + int water_level; + + Noise *noise_terrain; + Noise *noise_bgroup; + Noise *noise_heat; + Noise *noise_humidity; + + v3s16 node_min; + v3s16 node_max; + + float *map_terrain; + float *map_bgroup; + float *map_heat; + float *map_humidity; + + bool generating; + int id; + + NoiseParams *np_terrain; + NoiseParams *np_bgroup; + NoiseParams *np_heat; + NoiseParams *np_humidity; + + //should these be broken off into a "commonly used nodes" class? + MapNode n_air; + MapNode n_water; + MapNode n_lava; + + Mapgen(BiomeDefManager *biomedef, int mapgenid=0, u64 seed=0); + Mapgen(BiomeDefManager *biomedef, int mapgenid, u64 seed, + NoiseParams *np_terrain, NoiseParams *np_bgroup, + NoiseParams *np_heat, NoiseParams *np_humidity); + void initMapgen(BiomeDefManager *biomedef, int mapgenid, u64 seed, + NoiseParams *np_terrain, NoiseParams *np_bgroup, + NoiseParams *np_heat, NoiseParams *np_humidity); + ~Mapgen(); + + void makeChunk(BlockMakeData *data); + void updateLiquid(v3s16 node_min, v3s16 node_max); + void updateLighting(v3s16 node_min, v3s16 node_max); + + //Legacy functions for Farmesh (pending removal) + static bool get_have_beach(u64 seed, v2s16 p2d); + static double tree_amount_2d(u64 seed, v2s16 p); + static s16 find_ground_level_from_noise(u64 seed, v2s16 p2d, s16 precision); +}; + +class EmergeManager { +public: + //settings + u64 seed; + int water_level; + NoiseParams *np_terrain; + NoiseParams *np_bgroup; + NoiseParams *np_heat; + NoiseParams *np_humidity; + + //biome manager + BiomeDefManager *biomedef; + + //mapgen objects here + + EmergeManager(IGameDef *gamedef); + ~EmergeManager(); + void addBlockToQueue(); + + + + //mapgen helper methods + Biome *getBiomeAtPoint(v3s16 p); + int getGroundLevelAtPoint(v2s16 p); + bool isBlockUnderground(v3s16 blockpos); + u32 getBlockSeed(v3s16 p); +}; + + +/* namespace mapgen { // Finds precise ground level at any position @@ -41,10 +150,9 @@ namespace mapgen // Main map generation routine void make_block(BlockMakeData *data); - - /* - These are used by FarMesh - */ + + + //These are used by FarMesh bool get_have_beach(u64 seed, v2s16 p2d); double tree_amount_2d(u64 seed, v2s16 p); @@ -64,6 +172,6 @@ namespace mapgen }; }; // namespace mapgen - +*/ #endif diff --git a/src/nodedef.cpp b/src/nodedef.cpp index 36fa798f..560c6090 100644 --- a/src/nodedef.cpp +++ b/src/nodedef.cpp @@ -106,7 +106,7 @@ void NodeBox::deSerialize(std::istream &is) /* TileDef */ - + void TileDef::serialize(std::ostream &os) const { writeU8(os, 0); // version @@ -173,7 +173,7 @@ void ContentFeatures::reset() has_after_destruct = false; /* Actual data - + NOTE: Most of this is always overridden by the default values given in builtin.lua */ @@ -354,7 +354,7 @@ public: ContentFeatures &f = m_content_features[i]; f.reset(); // Reset to defaults } - + // Set CONTENT_AIR { ContentFeatures f; @@ -541,11 +541,11 @@ public: bool new_style_water = g_settings->getBool("new_style_water"); bool new_style_leaves = g_settings->getBool("new_style_leaves"); bool opaque_water = g_settings->getBool("opaque_water"); - + for(u16 i=0; i<=MAX_CONTENT; i++) { ContentFeatures *f = &m_content_features[i]; - + // Figure out the actual tiles to use TileDef tiledef[6]; for(u32 j=0; j<6; j++) diff --git a/src/noise.cpp b/src/noise.cpp index e75fbf4b..5cb4be29 100644 --- a/src/noise.cpp +++ b/src/noise.cpp @@ -21,89 +21,116 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "noise.h" #include #include "debug.h" +#include "util/numeric.h" -#define NOISE_MAGIC_X 1619 -#define NOISE_MAGIC_Y 31337 -#define NOISE_MAGIC_Z 52591 +#define NOISE_MAGIC_X 1619 +#define NOISE_MAGIC_Y 31337 +#define NOISE_MAGIC_Z 52591 #define NOISE_MAGIC_SEED 1013 -double cos_lookup[16] = { - 1.0,0.9238,0.7071,0.3826,0,-0.3826,-0.7071,-0.9238, - 1.0,-0.9238,-0.7071,-0.3826,0,0.3826,0.7071,0.9238 +float cos_lookup[16] = { + 1.0, 0.9238, 0.7071, 0.3826, 0, -0.3826, -0.7071, -0.9238, + 1.0, -0.9238, -0.7071, -0.3826, 0, 0.3826, 0.7071, 0.9238 }; -double dotProduct(double vx, double vy, double wx, double wy){ - return vx*wx+vy*wy; + +/////////////////////////////////////////////////////////////////////////////// + + +//noise poly: p(n) = 60493n^3 + 19990303n + 137612589 +float noise2d(int x, int y, int seed) { + int n = (NOISE_MAGIC_X * x + NOISE_MAGIC_Y * y + + NOISE_MAGIC_SEED * seed) & 0x7fffffff; + n = (n >> 13) ^ n; + n = (n * (n * n * 60493 + 19990303) + 1376312589) & 0x7fffffff; + return 1.f - (float)n / 0x40000000; } - -double easeCurve(double t){ - return t * t * t * (6. * t * t - 15. * t + 10.); + + +float noise3d(int x, int y, int z, int seed) { + int n = (NOISE_MAGIC_X * x + NOISE_MAGIC_Y * y + NOISE_MAGIC_Z * z + + NOISE_MAGIC_SEED * seed) & 0x7fffffff; + n = (n >> 13) ^ n; + n = (n * (n * n * 60493 + 19990303) + 1376312589) & 0x7fffffff; + return 1.f - (float)n / 0x40000000; } - -double linearInterpolation(double x0, double x1, double t){ - return x0+(x1-x0)*t; + + +float dotProduct(float vx, float vy, float wx, float wy) { + return vx * wx + vy * wy; } - -double biLinearInterpolation(double x0y0, double x1y0, double x0y1, double x1y1, double x, double y){ - double tx = easeCurve(x); - double ty = easeCurve(y); - /*double tx = x; - double ty = y;*/ - double u = linearInterpolation(x0y0,x1y0,tx); - double v = linearInterpolation(x0y1,x1y1,tx); - return linearInterpolation(u,v,ty); + + +inline float linearInterpolation(float v0, float v1, float t) { + return v0 + (v1 - v0) * t; } -double triLinearInterpolation( - double v000, double v100, double v010, double v110, - double v001, double v101, double v011, double v111, - double x, double y, double z) -{ - /*double tx = easeCurve(x); - double ty = easeCurve(y); - double tz = easeCurve(z);*/ - double tx = x; - double ty = y; - double tz = z; - return( - v000*(1-tx)*(1-ty)*(1-tz) + - v100*tx*(1-ty)*(1-tz) + - v010*(1-tx)*ty*(1-tz) + - v110*tx*ty*(1-tz) + - v001*(1-tx)*(1-ty)*tz + - v101*tx*(1-ty)*tz + - v011*(1-tx)*ty*tz + - v111*tx*ty*tz - ); + +float biLinearInterpolation(float v00, float v10, + float v01, float v11, + float x, float y) { + float tx = easeCurve(x); + float ty = easeCurve(y); + float u = linearInterpolation(v00, v10, tx); + float v = linearInterpolation(v01, v11, tx); + return linearInterpolation(u, v, ty); } -double noise2d(int x, int y, int seed) -{ - int n = (NOISE_MAGIC_X * x + NOISE_MAGIC_Y * y - + NOISE_MAGIC_SEED * seed) & 0x7fffffff; - n = (n>>13)^n; - n = (n * (n*n*60493+19990303) + 1376312589) & 0x7fffffff; - return 1.0 - (double)n/1073741824; + +float biLinearInterpolationNoEase(float x0y0, float x1y0, + float x0y1, float x1y1, + float x, float y) { + float u = linearInterpolation(x0y0, x1y0, x); + float v = linearInterpolation(x0y1, x1y1, x); + return linearInterpolation(u, v, y); } -double noise3d(int x, int y, int z, int seed) + +float triLinearInterpolation( + float v000, float v100, float v010, float v110, + float v001, float v101, float v011, float v111, + float x, float y, float z) { + float u = biLinearInterpolationNoEase(v000, v100, v010, v110, x, y); + float v = biLinearInterpolationNoEase(v001, v101, v011, v111, x, y); + return linearInterpolation(u, v, z); +} + + +#if 0 +float triLinearInterpolation( + float v000, float v100, float v010, float v110, + float v001, float v101, float v011, float v111, + float x, float y, float z) { - int n = (NOISE_MAGIC_X * x + NOISE_MAGIC_Y * y + NOISE_MAGIC_Z * z - + NOISE_MAGIC_SEED * seed) & 0x7fffffff; - n = (n>>13)^n; - n = (n * (n*n*60493+19990303) + 1376312589) & 0x7fffffff; - return 1.0 - (double)n/1073741824; + /*float tx = easeCurve(x); + float ty = easeCurve(y); + float tz = easeCurve(z);*/ + float tx = x; + float ty = y; + float tz = z; + return( + v000 * (1 - tx) * (1 - ty) * (1 - tz) + + v100 * tx * (1 - ty) * (1 - tz) + + v010 * (1 - tx) * ty * (1 - tz) + + v110 * tx * ty * (1 - tz) + + v001 * (1 - tx) * (1 - ty) * tz + + v101 * tx * (1 - ty) * tz + + v011 * (1 - tx) * ty * tz + + v111 * tx * ty * tz + ); } +#endif + #if 0 -double noise2d_gradient(double x, double y, int seed) +float noise2d_gradient(float x, float y, int seed) { // Calculate the integer coordinates int x0 = (x > 0.0 ? (int)x : (int)x - 1); int y0 = (y > 0.0 ? (int)y : (int)y - 1); // Calculate the remaining part of the coordinates - double xl = x - (double)x0; - double yl = y - (double)y0; + float xl = x - (float)x0; + float yl = y - (float)y0; // Calculate random cosine lookup table indices for the integer corners. // They are looked up as unit vector gradients from the lookup table. int n00 = (int)((noise2d(x0, y0, seed)+1)*8); @@ -111,119 +138,126 @@ double noise2d_gradient(double x, double y, int seed) int n01 = (int)((noise2d(x0, y0+1, seed)+1)*8); int n11 = (int)((noise2d(x0+1, y0+1, seed)+1)*8); // Make a dot product for the gradients and the positions, to get the values - double s = dotProduct(cos_lookup[n00], cos_lookup[(n00+12)%16], xl, yl); - double u = dotProduct(-cos_lookup[n10], cos_lookup[(n10+12)%16], 1.-xl, yl); - double v = dotProduct(cos_lookup[n01], -cos_lookup[(n01+12)%16], xl, 1.-yl); - double w = dotProduct(-cos_lookup[n11], -cos_lookup[(n11+12)%16], 1.-xl, 1.-yl); + float s = dotProduct(cos_lookup[n00], cos_lookup[(n00+12)%16], xl, yl); + float u = dotProduct(-cos_lookup[n10], cos_lookup[(n10+12)%16], 1.-xl, yl); + float v = dotProduct(cos_lookup[n01], -cos_lookup[(n01+12)%16], xl, 1.-yl); + float w = dotProduct(-cos_lookup[n11], -cos_lookup[(n11+12)%16], 1.-xl, 1.-yl); // Interpolate between the values return biLinearInterpolation(s,u,v,w,xl,yl); } #endif -#if 1 -double noise2d_gradient(double x, double y, int seed) + +float noise2d_gradient(float x, float y, int seed) { // Calculate the integer coordinates - int x0 = (x > 0.0 ? (int)x : (int)x - 1); - int y0 = (y > 0.0 ? (int)y : (int)y - 1); + int x0 = myfloor(x); + int y0 = myfloor(y); // Calculate the remaining part of the coordinates - double xl = x - (double)x0; - double yl = y - (double)y0; - // Get values for corners of cube - double v00 = noise2d(x0, y0, seed); - double v10 = noise2d(x0+1, y0, seed); - double v01 = noise2d(x0, y0+1, seed); - double v11 = noise2d(x0+1, y0+1, seed); + float xl = x - (float)x0; + float yl = y - (float)y0; + // Get values for corners of square + float v00 = noise2d(x0, y0, seed); + float v10 = noise2d(x0+1, y0, seed); + float v01 = noise2d(x0, y0+1, seed); + float v11 = noise2d(x0+1, y0+1, seed); // Interpolate return biLinearInterpolation(v00,v10,v01,v11,xl,yl); } -#endif -double noise3d_gradient(double x, double y, double z, int seed) + +float noise3d_gradient(float x, float y, float z, int seed) { // Calculate the integer coordinates - int x0 = (x > 0.0 ? (int)x : (int)x - 1); - int y0 = (y > 0.0 ? (int)y : (int)y - 1); - int z0 = (z > 0.0 ? (int)z : (int)z - 1); + int x0 = myfloor(x); + int y0 = myfloor(y); + int z0 = myfloor(z); // Calculate the remaining part of the coordinates - double xl = x - (double)x0; - double yl = y - (double)y0; - double zl = z - (double)z0; + float xl = x - (float)x0; + float yl = y - (float)y0; + float zl = z - (float)z0; // Get values for corners of cube - double v000 = noise3d(x0, y0, z0, seed); - double v100 = noise3d(x0+1, y0, z0, seed); - double v010 = noise3d(x0, y0+1, z0, seed); - double v110 = noise3d(x0+1, y0+1, z0, seed); - double v001 = noise3d(x0, y0, z0+1, seed); - double v101 = noise3d(x0+1, y0, z0+1, seed); - double v011 = noise3d(x0, y0+1, z0+1, seed); - double v111 = noise3d(x0+1, y0+1, z0+1, seed); + float v000 = noise3d(x0, y0, z0, seed); + float v100 = noise3d(x0 + 1, y0, z0, seed); + float v010 = noise3d(x0, y0 + 1, z0, seed); + float v110 = noise3d(x0 + 1, y0 + 1, z0, seed); + float v001 = noise3d(x0, y0, z0 + 1, seed); + float v101 = noise3d(x0 + 1, y0, z0 + 1, seed); + float v011 = noise3d(x0, y0 + 1, z0 + 1, seed); + float v111 = noise3d(x0 + 1, y0 + 1, z0 + 1, seed); // Interpolate - return triLinearInterpolation(v000,v100,v010,v110,v001,v101,v011,v111,xl,yl,zl); + return triLinearInterpolation(v000, v100, v010, v110, + v001, v101, v011, v111, + xl, yl, zl); } -double noise2d_perlin(double x, double y, int seed, - int octaves, double persistence) + +float noise2d_perlin(float x, float y, int seed, + int octaves, float persistence) { - double a = 0; - double f = 1.0; - double g = 1.0; - for(int i=0; i0, 0->1, 1->0 -double contour(double v) +float contour(float v) { v = fabs(v); if(v >= 1.0) @@ -231,195 +265,276 @@ double contour(double v) return (1.0-v); } -double noise3d_param(const NoiseParams ¶m, double x, double y, double z) -{ - double s = param.pos_scale; - x /= s; - y /= s; - z /= s; - if(param.type == NOISE_CONSTANT_ONE) - { - return 1.0; - } - else if(param.type == NOISE_PERLIN) - { - return param.noise_scale*noise3d_perlin(x,y,z, param.seed, - param.octaves, - param.persistence); - } - else if(param.type == NOISE_PERLIN_ABS) - { - return param.noise_scale*noise3d_perlin_abs(x,y,z, param.seed, - param.octaves, - param.persistence); - } - else if(param.type == NOISE_PERLIN_CONTOUR) - { - return contour(param.noise_scale*noise3d_perlin(x,y,z, - param.seed, param.octaves, - param.persistence)); - } - else if(param.type == NOISE_PERLIN_CONTOUR_FLIP_YZ) - { - return contour(param.noise_scale*noise3d_perlin(x,z,y, - param.seed, param.octaves, - param.persistence)); - } - else assert(0); -} +///////////////////////// [ New perlin stuff ] //////////////////////////// -/* - NoiseBuffer -*/ -NoiseBuffer::NoiseBuffer(): - m_data(NULL) -{ +Noise::Noise(NoiseParams *np, int seed, int sx, int sy) { + int nlx, nly; + float ofactor; + + //maximum possible spread value factor + ofactor = (float)(1 << (np->octaves - 1)); + + //noise lattice point count + //(int)(sz * spread * ofactor) is # of lattice points crossed due to length + // + 2 for the two initial endpoints + // + 1 for potentially crossing a boundary due to offset + nlx = (int)(sx * ofactor / np->spread.X) + 3; + nly = (int)(sy * ofactor / np->spread.Y) + 3; + + this->np = np; + this->seed = seed; + this->sx = sx; + this->sy = sy; + this->sz = 0; + this->noisebuf = new float[nlx * nly]; + this->buf = new float[sx * sy]; + this->result = new float[sx * sy]; } -NoiseBuffer::~NoiseBuffer() -{ - clear(); + +Noise::Noise(NoiseParams *np, int seed, int sx, int sy, int sz) { + int nlx, nly, nlz; + float ofactor; + + ofactor = (float)(1 << (np->octaves - 1)); + nlx = (int)(sx * ofactor / np->spread.X) + 3; + nly = (int)(sy * ofactor / np->spread.Y) + 3; + nlz = (int)(sz * ofactor / np->spread.Z) + 3; + + this->np = np; + this->seed = seed; + this->sx = sx; + this->sy = sy; + this->sz = sz; + this->noisebuf = new float[nlx * nly * nlz]; + this->buf = new float[sx * sy * sz]; + this->result = new float[sx * sy * sz]; } -void NoiseBuffer::clear() -{ - if(m_data) - delete[] m_data; - m_data = NULL; - m_size_x = 0; - m_size_y = 0; - m_size_z = 0; + +Noise::~Noise() { + delete[] buf; + delete[] result; + delete[] noisebuf; } -void NoiseBuffer::create(const NoiseParams ¶m, - double first_x, double first_y, double first_z, - double last_x, double last_y, double last_z, - double samplelength_x, double samplelength_y, double samplelength_z) -{ - clear(); - - m_start_x = first_x - samplelength_x; - m_start_y = first_y - samplelength_y; - m_start_z = first_z - samplelength_z; - m_samplelength_x = samplelength_x; - m_samplelength_y = samplelength_y; - m_samplelength_z = samplelength_z; - - m_size_x = (last_x - m_start_x)/samplelength_x + 2; - m_size_y = (last_y - m_start_y)/samplelength_y + 2; - m_size_z = (last_z - m_start_z)/samplelength_z + 2; - - m_data = new double[m_size_x*m_size_y*m_size_z]; - - for(int x=0; x= 1.0) { + u -= 1.0; + noisex++; + v00 = v10; + v01 = v11; + v10 = noisebuf[noisey * nlx + noisex + 1]; + v11 = noisebuf[(noisey + 1) * nlx + noisex + 1]; + } + } + + v += step_y; + if (v >= 1.0) { + v -= 1.0; + noisey++; + } } } -void NoiseBuffer::multiply(const NoiseParams ¶m) -{ - assert(m_data != NULL); - for(int x=0; x= 1.0) { + u -= 1.0; + noisex++; + v000 = v100; + v010 = v110; + v100 = noisebuf[index(noisex + 1, noisey, noisez)]; + v110 = noisebuf[index(noisex + 1, noisey + 1, noisez)]; + v001 = v101; + v011 = v111; + v101 = noisebuf[index(noisex + 1, noisey, noisez + 1)]; + v111 = noisebuf[index(noisex + 1, noisey + 1, noisez + 1)]; + } + } + + v += step_y; + if (v >= 1.0) { + v -= 1.0; + noisey++; + } + } + + w += step_z; + if (w >= 1.0) { + w -= 1.0; + noisez++; + } } } -// Deprecated -void NoiseBuffer::create(int seed, int octaves, double persistence, - bool abs, - double first_x, double first_y, double first_z, - double last_x, double last_y, double last_z, - double samplelength_x, double samplelength_y, double samplelength_z) -{ - NoiseParams param; - param.type = abs ? NOISE_PERLIN_ABS : NOISE_PERLIN; - param.seed = seed; - param.octaves = octaves; - param.persistence = persistence; - - create(param, first_x, first_y, first_z, - last_x, last_y, last_z, - samplelength_x, samplelength_y, samplelength_z); -} -void NoiseBuffer::intSet(int x, int y, int z, double d) -{ - int i = m_size_x*m_size_y*z + m_size_x*y + x; - assert(i >= 0); - assert(i < m_size_x*m_size_y*m_size_z); - m_data[i] = d; -} +float *Noise::perlinMap2D(float x, float y) { + float a = 0.0, f = 1.0, g = 1.0; + int i, j, index, oct; -void NoiseBuffer::intMultiply(int x, int y, int z, double d) -{ - int i = m_size_x*m_size_y*z + m_size_x*y + x; - assert(i >= 0); - assert(i < m_size_x*m_size_y*m_size_z); - m_data[i] = m_data[i] * d; -} + x /= np->spread.X; + y /= np->spread.Y; -double NoiseBuffer::intGet(int x, int y, int z) -{ - int i = m_size_x*m_size_y*z + m_size_x*y + x; - assert(i >= 0); - assert(i < m_size_x*m_size_y*m_size_z); - return m_data[i]; -} + memset(result, 0, sizeof(float) * sx * sy); -double NoiseBuffer::get(double x, double y, double z) -{ - x -= m_start_x; - y -= m_start_y; - z -= m_start_z; - x /= m_samplelength_x; - y /= m_samplelength_y; - z /= m_samplelength_z; - // Calculate the integer coordinates - int x0 = (x > 0.0 ? (int)x : (int)x - 1); - int y0 = (y > 0.0 ? (int)y : (int)y - 1); - int z0 = (z > 0.0 ? (int)z : (int)z - 1); - // Calculate the remaining part of the coordinates - double xl = x - (double)x0; - double yl = y - (double)y0; - double zl = z - (double)z0; - // Get values for corners of cube - double v000 = intGet(x0, y0, z0); - double v100 = intGet(x0+1, y0, z0); - double v010 = intGet(x0, y0+1, z0); - double v110 = intGet(x0+1, y0+1, z0); - double v001 = intGet(x0, y0, z0+1); - double v101 = intGet(x0+1, y0, z0+1); - double v011 = intGet(x0, y0+1, z0+1); - double v111 = intGet(x0+1, y0+1, z0+1); - // Interpolate - return triLinearInterpolation(v000,v100,v010,v110,v001,v101,v011,v111,xl,yl,zl); + for (oct = 0; oct < np->octaves; oct++) { + gradientMap2D(x * f, y * f, + f / np->spread.X, f / np->spread.Y, + seed + np->seed + oct); + + index = 0; + for (j = 0; j != sy; j++) { + for (i = 0; i != sx; i++) { + result[index] += g * buf[index]; + index++; + } + } + + f *= 2.0; + g *= np->persist; + } + + return result; } -/*bool NoiseBuffer::contains(double x, double y, double z) -{ - x -= m_start_x; - y -= m_start_y; - z -= m_start_z; - x /= m_samplelength_x; - y /= m_samplelength_y; - z /= m_samplelength_z; - if(x <= 0.0 || x >= m_size_x) -}*/ +float *Noise::perlinMap3D(float x, float y, float z) { + float a = 0.0, f = 1.0, g = 1.0; + int i, j, k, index, oct; + + x /= np->spread.X; + y /= np->spread.Y; + z /= np->spread.Z; + + memset(result, 0, sizeof(float) * sx * sy * sz); + + for (oct = 0; oct < np->octaves; oct++) { + gradientMap3D(x * f, y * f, z * f, + f / np->spread.X, f / np->spread.Y, f / np->spread.Z, + seed + np->seed + oct); + + index = 0; + for (k = 0; k != sz; k++) { + for (j = 0; j != sy; j++) { + for (i = 0; i != sx; i++) { + result[index] += g * buf[index]; + index++; + } + } + } + + f *= 2.0; + g *= np->persist; + } + + return result; +} diff --git a/src/noise.h b/src/noise.h index 670c2edd..6e512000 100644 --- a/src/noise.h +++ b/src/noise.h @@ -21,6 +21,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #define NOISE_HEADER #include "debug.h" +#include "irr_v3d.h" class PseudoRandom { @@ -59,91 +60,69 @@ private: int m_next; }; -double easeCurve(double t); - -// Return value: -1 ... 1 -double noise2d(int x, int y, int seed); -double noise3d(int x, int y, int z, int seed); +struct NoiseParams { + float offset; + float scale; + v3f spread; + int seed; + int octaves; + float persist; +}; -double noise2d_gradient(double x, double y, int seed); -double noise3d_gradient(double x, double y, double z, int seed); -double noise2d_perlin(double x, double y, int seed, - int octaves, double persistence); +class Noise { +public: + NoiseParams *np; + int seed; + int sx; + int sy; + int sz; + float *noisebuf; + float *buf; + float *result; + + Noise(NoiseParams *np, int seed, int sx, int sy); + Noise(NoiseParams *np, int seed, int sx, int sy, int sz); + ~Noise(); + + void gradientMap2D( + float x, float y, + float step_x, float step_y, + int seed); + void gradientMap3D( + float x, float y, float z, + float step_x, float step_y, float step_z, + int seed); + float *perlinMap2D(float x, float y); + float *perlinMap3D(float x, float y, float z); +}; -double noise2d_perlin_abs(double x, double y, int seed, - int octaves, double persistence); +// Return value: -1 ... 1 +float noise2d(int x, int y, int seed); +float noise3d(int x, int y, int z, int seed); -double noise3d_perlin(double x, double y, double z, int seed, - int octaves, double persistence); +float noise2d_gradient(float x, float y, int seed); +float noise3d_gradient(float x, float y, float z, int seed); -double noise3d_perlin_abs(double x, double y, double z, int seed, - int octaves, double persistence); +float noise2d_perlin(float x, float y, int seed, + int octaves, float persistence); -enum NoiseType -{ - NOISE_CONSTANT_ONE, - NOISE_PERLIN, - NOISE_PERLIN_ABS, - NOISE_PERLIN_CONTOUR, - NOISE_PERLIN_CONTOUR_FLIP_YZ, -}; +float noise2d_perlin_abs(float x, float y, int seed, + int octaves, float persistence); -struct NoiseParams -{ - NoiseType type; - int seed; - int octaves; - double persistence; - double pos_scale; - double noise_scale; // Useful for contour noises - - NoiseParams(NoiseType type_=NOISE_PERLIN, int seed_=0, - int octaves_=3, double persistence_=0.5, - double pos_scale_=100.0, double noise_scale_=1.0): - type(type_), - seed(seed_), - octaves(octaves_), - persistence(persistence_), - pos_scale(pos_scale_), - noise_scale(noise_scale_) - { - } -}; +float noise3d_perlin(float x, float y, float z, int seed, + int octaves, float persistence); -double noise3d_param(const NoiseParams ¶m, double x, double y, double z); +float noise3d_perlin_abs(float x, float y, float z, int seed, + int octaves, float persistence); -class NoiseBuffer -{ -public: - NoiseBuffer(); - ~NoiseBuffer(); - - void clear(); - void create(const NoiseParams ¶m, - double first_x, double first_y, double first_z, - double last_x, double last_y, double last_z, - double samplelength_x, double samplelength_y, double samplelength_z); - void multiply(const NoiseParams ¶m); - // Deprecated - void create(int seed, int octaves, double persistence, - bool abs, - double first_x, double first_y, double first_z, - double last_x, double last_y, double last_z, - double samplelength_x, double samplelength_y, double samplelength_z); - - void intSet(int x, int y, int z, double d); - void intMultiply(int x, int y, int z, double d); - double intGet(int x, int y, int z); - double get(double x, double y, double z); - //bool contains(double x, double y, double z); +inline float easeCurve(float t) { + return t * t * t * (t * (6.f * t - 15.f) + 10.f); +} -private: - double *m_data; - double m_start_x, m_start_y, m_start_z; - double m_samplelength_x, m_samplelength_y, m_samplelength_z; - int m_size_x, m_size_y, m_size_z; -}; +#define NoisePerlin2D(np, x, y, s) ((np)->offset + (np)->scale * \ + noise2d_perlin((float)(x) * (np)->spread.X, (float)(y) * (np)->spread.Y, \ + (s) + (np)->seed, (np)->octaves, (np)->persist)) #endif diff --git a/src/scriptapi.cpp b/src/scriptapi.cpp index 959885d3..69ee48a7 100644 --- a/src/scriptapi.cpp +++ b/src/scriptapi.cpp @@ -3240,8 +3240,8 @@ class LuaPerlinNoise private: int seed; int octaves; - double persistence; - double scale; + float persistence; + float scale; static const char className[]; static const luaL_reg methods[]; @@ -3273,8 +3273,8 @@ private: } public: - LuaPerlinNoise(int a_seed, int a_octaves, double a_persistence, - double a_scale): + LuaPerlinNoise(int a_seed, int a_octaves, float a_persistence, + float a_scale): seed(a_seed), octaves(a_octaves), persistence(a_persistence), @@ -3292,8 +3292,8 @@ public: { int seed = luaL_checkint(L, 1); int octaves = luaL_checkint(L, 2); - double persistence = luaL_checknumber(L, 3); - double scale = luaL_checknumber(L, 4); + float persistence = luaL_checknumber(L, 3); + float scale = luaL_checknumber(L, 4); LuaPerlinNoise *o = new LuaPerlinNoise(seed, octaves, persistence, scale); *(void **)(lua_newuserdata(L, sizeof(void *))) = o; luaL_getmetatable(L, className); @@ -3999,8 +3999,8 @@ private: int seeddiff = luaL_checkint(L, 2); int octaves = luaL_checkint(L, 3); - double persistence = luaL_checknumber(L, 4); - double scale = luaL_checknumber(L, 5); + float persistence = luaL_checknumber(L, 4); + float scale = luaL_checknumber(L, 5); LuaPerlinNoise *n = new LuaPerlinNoise(seeddiff + int(env->getServerMap().getSeed()), octaves, persistence, scale); *(void **)(lua_newuserdata(L, sizeof(void *))) = n; diff --git a/src/server.cpp b/src/server.cpp index a7767842..a3c0b66e 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -39,6 +39,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "itemdef.h" #include "craftdef.h" #include "mapgen.h" +#include "biome.h" #include "content_mapnode.h" #include "content_nodemeta.h" #include "content_abm.h" @@ -80,7 +81,7 @@ public: *m_flag = false; } } - + private: bool *m_flag; }; @@ -105,7 +106,7 @@ public: *m_ignorevariable = VoxelArea(); } } - + private: VoxelArea *m_ignorevariable; }; @@ -129,7 +130,7 @@ void * ServerThread::Thread() //TimeTaker timer("AsyncRunStep()"); m_server->AsyncRunStep(); } - + //infostream<<"Running m_server->Receive()"<Receive(); } @@ -149,7 +150,7 @@ void * ServerThread::Thread() m_server->setAsyncFatalError(e.what()); } } - + END_DEBUG_EXCEPTION_HANDLER(errorstream) return NULL; @@ -168,7 +169,11 @@ void * EmergeThread::Thread() bool enable_mapgen_debug_info = g_settings->getBool("enable_mapgen_debug_info"); v3s16 last_tried_pos(-32768,-32768,-32768); // For error output - + + ServerMap &map = ((ServerMap&)m_server->m_env->getMap()); + EmergeManager *emerge = m_server->m_emerge; + Mapgen *mapgen = new Mapgen( m_server->m_emerge->biomedef,/*mapgenid*/ 0, map.getSeed()); ////////fix this...! + /* Get block info from queue, emerge them and send them to clients. @@ -180,12 +185,12 @@ void * EmergeThread::Thread() QueuedBlockEmerge *qptr = m_server->m_emerge_queue.pop(); if(qptr == NULL) break; - + SharedPtr q(qptr); v3s16 &p = q->pos; v2s16 p2d(p.X,p.Z); - + last_tried_pos = p; /* @@ -193,18 +198,18 @@ void * EmergeThread::Thread() */ if(blockpos_over_limit(p)) continue; - + //infostream<<"EmergeThread::Thread(): running"<getValue(); if((flags & BLOCK_EMERGE_FLAG_FROMDISK) == false) only_from_disk = false; - + } } - + if(enable_mapgen_debug_info) infostream<<"EmergeThread: p=" <<"("<makeChunk(&data); + //mapgen::make_block(&data); if(enable_mapgen_debug_info == false) t.stop(true); // Hide output } - + do{ // enable break // Lock environment again to access the map JMutexAutoLock envlock(m_server->m_env_mutex); - + ScopeProfiler sp(g_profiler, "EmergeThread: after " "mapgen::make_block (envlock)", SPT_AVG); @@ -306,7 +312,7 @@ void * EmergeThread::Thread() // Get central block block = map.getBlockNoCreateNoEx(p); - + // If block doesn't exist, don't try doing anything with it // This happens if the block is not in generation boundaries if(!block) @@ -319,7 +325,7 @@ void * EmergeThread::Thread() v3s16 minp = data.blockpos_min*MAP_BLOCKSIZE; v3s16 maxp = data.blockpos_max*MAP_BLOCKSIZE + v3s16(1,1,1)*(MAP_BLOCKSIZE-1); - + /* Ignore map edit events, they will not need to be sent to anybody because the block hasn't been sent @@ -332,11 +338,11 @@ void * EmergeThread::Thread() { TimeTaker timer("on_generated"); scriptapi_environment_on_generated(m_server->m_lua, - minp, maxp, mapgen::get_blockseed(data.seed, minp)); + minp, maxp, emerge->getBlockSeed(minp)); /*int t = timer.stop(true); dstream<<"on_generated took "<m_con_mutex); @@ -363,17 +369,17 @@ void * EmergeThread::Thread() { modified_blocks.insert(p, block); } - + /* Set the modified blocks unsent for all the clients */ - + for(core::map::Iterator i = m_server->m_clients.getIterator(); i.atEnd() == false; i++) { RemoteClient *client = i.getNode()->getValue(); - + if(modified_blocks.size() > 0) { // Remove block from sent history @@ -434,14 +440,14 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime, core::array &dest) { DSTACK(__FUNCTION_NAME); - + /*u32 timer_result; TimeTaker timer("RemoteClient::GetNextBlocks", &timer_result);*/ - + // Increment timers m_nothing_to_send_pause_timer -= dtime; m_nearest_unsent_reset_timer += dtime; - + if(m_nothing_to_send_pause_timer >= 0) return; @@ -459,7 +465,7 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime, } //TimeTaker timer("RemoteClient::GetNextBlocks"); - + v3f playerpos = player->getPosition(); v3f playerspeed = player->getSpeed(); v3f playerspeeddir(0,0,0); @@ -471,7 +477,7 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime, v3s16 center_nodepos = floatToInt(playerpos_predicted, BS); v3s16 center = getNodeBlockPos(center_nodepos); - + // Camera position and direction v3f camera_pos = player->getEyePosition(); v3f camera_dir = v3f(0,0,1); @@ -484,7 +490,7 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime, /* Get the starting value of the block finder radius. */ - + if(m_last_center != center) { m_nearest_unsent_d = 0; @@ -493,7 +499,7 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime, /*infostream<<"m_nearest_unsent_reset_timer=" < 20.0) { @@ -514,7 +520,7 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime, /* Check the time from last addNode/removeNode. - + Decrease send rate if player is building stuff. */ m_time_from_building += dtime; @@ -524,12 +530,12 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime, max_simul_sends_usually = LIMITED_MAX_SIMULTANEOUS_BLOCK_SENDS; } - + /* Number of blocks sending + number of blocks selected for sending */ u32 num_blocks_selected = m_blocks_sending.size(); - + /* next time d will be continued from the d from which the nearest unsent block was found this time. @@ -541,28 +547,28 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime, s16 d_max = g_settings->getS16("max_block_send_distance"); s16 d_max_gen = g_settings->getS16("max_block_generate_distance"); - + // Don't loop very much at a time s16 max_d_increment_at_time = 2; if(d_max > d_start + max_d_increment_at_time) d_max = d_start + max_d_increment_at_time; /*if(d_max_gen > d_start+2) d_max_gen = d_start+2;*/ - + //infostream<<"Starting from "<getPlayerName(peer_id)<m_emerge_queue.addBlock(peer_id, p, flags); server->m_emergethread.trigger(); @@ -791,7 +797,7 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime, if(nearest_emergefull_d == -1) nearest_emergefull_d = d; } - + // get next one. continue; } @@ -816,7 +822,7 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime, queue_full_break: //infostream<<"Stopped at "< &blocks) { m_nearest_unsent_d = 0; - + for(core::map::Iterator i = blocks.getIterator(); i.atEnd()==false; i++) @@ -937,6 +943,7 @@ Server::Server( m_rollback(NULL), m_rollback_sink_enabled(true), m_enable_rollback_recording(false), + m_emerge(NULL), m_lua(NULL), m_itemdef(createItemDefManager()), m_nodedef(createNodeDefManager()), @@ -955,7 +962,7 @@ Server::Server( m_objectdata_timer = 0.0; m_emergethread_trigger_timer = 0.0; m_savemap_timer = 0.0; - + m_env_mutex.Init(); m_con_mutex.Init(); m_step_dtime_mutex.Init(); @@ -963,10 +970,10 @@ Server::Server( if(path_world == "") throw ServerError("Supplied empty world path"); - + if(!gamespec.isValid()) throw ServerError("Supplied invalid gamespec"); - + infostream<<"Server created for gameid \""<updateAliases(m_itemdef); + // Add default biomes after nodedef had its aliases added + m_emerge->biomedef->addDefaultBiomes(); + // Initialize Environment - - m_env = new ServerEnvironment(new ServerMap(path_world, this), m_lua, + + m_env = new ServerEnvironment(new ServerMap(path_world, this, m_emerge), m_lua, this, this); - + // Give environment reference to scripting api scriptapi_add_environment(m_lua, m_env); - + // Register us to receive map edit events m_env->getMap().addEventReceiver(this); @@ -1119,7 +1132,7 @@ Server::~Server() */ { JMutexAutoLock conlock(m_con_mutex); - + std::wstring line = L"*** Server shutting down"; /* @@ -1168,12 +1181,12 @@ Server::~Server() infostream<<"Server: Saving environment metadata"<saveMeta(m_path_world); } - + /* Stop threads */ stop(); - + /* Delete clients */ @@ -1184,19 +1197,21 @@ Server::~Server() i = m_clients.getIterator(); i.atEnd() == false; i++) { + // Delete client delete i.getNode()->getValue(); } } - + // Delete things in the reverse order of creation delete m_env; delete m_rollback; + delete m_emerge; delete m_event; delete m_itemdef; delete m_nodedef; delete m_craftdef; - + // Deinitialize scripting infostream<<"Server: Deinitializing scripting"<add("Server::AsyncRunStep (num)", 1); - + float dtime; { JMutexAutoLock lock1(m_step_dtime_mutex); dtime = m_step_dtime; } - + { // Send blocks to clients SendBlocks(dtime); } - + if(dtime < 0.001) return; - + g_profiler->add("Server::AsyncRunStep with dtime (num)", 1); //infostream<<"Server steps "<step(dtime); } - + const float map_timer_and_unload_dtime = 2.92; if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime)) { @@ -1372,7 +1387,7 @@ void Server::AsyncRunStep() m_env->getMap().timerUpdate(map_timer_and_unload_dtime, g_settings->getFloat("server_unload_unused_data_timeout")); } - + /* Do background stuff */ @@ -1419,27 +1434,27 @@ void Server::AsyncRunStep() } } } - + /* Transform liquids */ m_liquid_transform_timer += dtime; if(m_liquid_transform_timer >= 1.00) { m_liquid_transform_timer -= 1.00; - + JMutexAutoLock lock(m_env_mutex); ScopeProfiler sp(g_profiler, "Server: liquid transform"); core::map modified_blocks; m_env->getMap().transformLiquids(modified_blocks); -#if 0 +#if 0 /* Update lighting */ core::map lighting_modified_blocks; ServerMap &map = ((ServerMap&)m_env->getMap()); map.updateLighting(modified_blocks, lighting_modified_blocks); - + // Add blocks modified by lighting to modified_blocks for(core::map::Iterator i = lighting_modified_blocks.getIterator(); @@ -1452,7 +1467,7 @@ void Server::AsyncRunStep() /* Set the modified blocks unsent for all the clients */ - + JMutexAutoLock lock2(m_con_mutex); for(core::map::Iterator @@ -1460,7 +1475,7 @@ void Server::AsyncRunStep() i.atEnd() == false; i++) { RemoteClient *client = i.getNode()->getValue(); - + if(modified_blocks.size() > 0) { // Remove block from sent history @@ -1478,7 +1493,7 @@ void Server::AsyncRunStep() counter = 0.0; JMutexAutoLock lock2(m_con_mutex); - + if(m_clients.size() != 0) infostream<<"Players:"<::Iterator @@ -1541,18 +1556,18 @@ void Server::AsyncRunStep() client->m_known_objects, removed_objects); m_env->getAddedActiveObjects(pos, radius, client->m_known_objects, added_objects); - + // Ignore if nothing happened if(removed_objects.size() == 0 && added_objects.size() == 0) { //infostream<<"active objects: none changed"<getKey()); data_buffer.append(buf, 2); - + // Remove from known objects client->m_known_objects.remove(i.getNode()->getKey()); @@ -1585,7 +1600,7 @@ void Server::AsyncRunStep() // Get object u16 id = i.getNode()->getKey(); ServerActiveObject* obj = m_env->getActiveObject(id); - + // Get object type u8 type = ACTIVEOBJECT_TYPE_INVALID; if(obj == NULL) @@ -1599,7 +1614,7 @@ void Server::AsyncRunStep() data_buffer.append(buf, 2); writeU8((u8*)buf, type); data_buffer.append(buf, 1); - + if(obj) data_buffer.append(serializeLongString( obj->getClientInitializationData(client->net_proto_version))); @@ -1649,7 +1664,7 @@ void Server::AsyncRunStep() all_known_objects[id] = true; } } - + m_env->setKnownActiveObjects(whatever); #endif @@ -1674,7 +1689,7 @@ void Server::AsyncRunStep() ActiveObjectMessage aom = m_env->getActiveObjectMessage(); if(aom.id == 0) break; - + core::list* message_list = NULL; core::map* >::Node *n; n = buffered_messages.find(aom.id); @@ -1689,7 +1704,7 @@ void Server::AsyncRunStep() } message_list->push_back(aom); } - + // Route data to every client for(core::map::Iterator i = m_clients.getIterator(); @@ -1796,7 +1811,7 @@ void Server::AsyncRunStep() while(m_unsent_map_edit_queue.size() != 0) { MapEditEvent* event = m_unsent_map_edit_queue.pop_front(); - + // Players far away from the change are stored here. // Instead of sending the changes, MapBlocks are set not sent // for them. @@ -1848,7 +1863,7 @@ void Server::AsyncRunStep() infostream<<"WARNING: Server: Unknown MapEditEvent " <<((u32)event->type)<= 2.0) { counter = 0.0; - + m_emergethread.trigger(); // Update m_enable_rollback_recording here too @@ -1928,13 +1943,13 @@ void Server::AsyncRunStep() //Ban stuff if(m_banmanager.isModified()) m_banmanager.save(); - + // Save changed parts of map m_env->getMap().save(MOD_STATE_WRITE_NEEDED); // Save players m_env->serializePlayers(m_path_world); - + // Save environment metadata m_env->saveMeta(m_path_world); } @@ -1968,7 +1983,7 @@ void Server::Receive() catch(con::PeerNotFoundException &e) { //NOTE: This is not needed anymore - + // The peer has been disconnected. // Find the associated player and remove it. @@ -1988,9 +2003,9 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) // Environment is locked first. JMutexAutoLock envlock(m_env_mutex); JMutexAutoLock conlock(m_con_mutex); - + ScopeProfiler sp(g_profiler, "Server::ProcessData"); - + try{ Address address = m_con.GetPeerAddress(peer_id); std::string addr_s = address.serializeString(); @@ -2014,7 +2029,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) <serialization_version; @@ -2026,7 +2041,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) return; ToServerCommand command = (ToServerCommand)readU16(&data[0]); - + if(command == TOSERVER_INIT) { // [0] u16 TOSERVER_INIT @@ -2052,7 +2067,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) //peer->serialization_version = deployed; getClient(peer_id)->pending_serialization_version = deployed; - + if(deployed == SER_FMT_VER_INVALID) { actionstream<<"Server: A mismatched client tried to connect from " @@ -2067,7 +2082,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) ); return; } - + /* Read and check network protocol version */ @@ -2123,7 +2138,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) ); return; } - + if(g_settings->getBool("strict_protocol_version_checking")) { if(net_proto_version != LATEST_PROTOCOL_VERSION) @@ -2148,7 +2163,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) /* Set up player */ - + // Get player name char playername[PLAYERNAME_SIZE]; for(u32 i=0; i= g_settings->getU16("max_users") && @@ -2287,7 +2302,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) writeV3S16(&reply[2+1], floatToInt(playersao->getPlayer()->getPosition()+v3f(0,BS/2,0), BS)); writeU64(&reply[2+1+6], m_env->getServerMap().getSeed()); writeF1000(&reply[2+1+6+8], g_settings->getFloat("dedicated_server_step")); - + // Send as reliable m_con.Send(peer_id, 0, reply, true); } @@ -2325,16 +2340,16 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) // Send item definitions SendItemDef(m_con, peer_id, m_itemdef); - + // Send node definitions SendNodeDef(m_con, peer_id, m_nodedef, client->net_proto_version); - + // Send media announcement sendMediaAnnouncement(peer_id); - + // Send privileges SendPlayerPrivileges(peer_id); - + // Send inventory formspec SendPlayerInventoryFormspec(peer_id); @@ -2345,10 +2360,10 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) // Send HP if(g_settings->getBool("enable_damage")) SendPlayerHP(peer_id); - + // Send detached inventories sendDetachedInventories(peer_id); - + // Show death screen if necessary if(player->hp == 0) SendDeathscreen(m_con, peer_id, false, v3f(0,0,0)); @@ -2359,20 +2374,20 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) m_env->getTimeOfDay(), g_settings->getFloat("time_speed")); m_con.Send(peer_id, 0, data, true); } - + // Note things in chat if not in simple singleplayer mode if(!m_simple_singleplayer_mode) { // Send information about server to player in chat SendChatMessage(peer_id, getStatusString()); - + // Send information about joining in chat { std::wstring name = L"unknown"; Player *player = m_env->getPlayer(peer_id); if(player != NULL) name = narrow_to_wide(player->getName()); - + std::wstring message; message += L"*** "; message += name; @@ -2380,7 +2395,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) BroadcastChatMessage(message); } } - + // Warnings about protocol version can be issued here if(getClient(peer_id)->net_proto_version < LATEST_PROTOCOL_VERSION) { @@ -2423,7 +2438,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) " Skipping incoming command="<getPlayer(peer_id); if(player == NULL){ infostream<<"Server::ProcessData(): Cancelling: " @@ -2444,7 +2459,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) { if(datasize < 2+12+12+4+4) return; - + u32 start = 0; v3s32 ps = readV3S32(&data[start+2]); v3s32 ss = readV3S32(&data[start+2+12]); @@ -2472,7 +2487,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) player->control.sneak = (bool)(keyPressed&64); player->control.LMB = (bool)(keyPressed&128); player->control.RMB = (bool)(keyPressed&256); - + /*infostream<<"Server::ProcessData(): Moved player "<hp != 0 || !g_settings->getBool("enable_damage")) return; - + RespawnPlayer(peer_id); - + actionstream<getName()<<" respawns at " <getPosition()/BS)< tosend; u16 numfiles = readU16(is); @@ -3194,7 +3209,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) } } } // action == 2 - + /* 3: place block or right-click object */ @@ -3230,7 +3245,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) // Apply returned ItemStack playersao->setWieldedItem(item); } - + // If item has node placement prediction, always send the above // node to make sure the client knows what exactly happened if(item.getDefinition(m_itemdef).node_placement_prediction != ""){ @@ -3291,7 +3306,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) { std::string datastring((char*)&data[2], datasize-2); std::istringstream is(datastring, std::ios_base::binary); - + v3s16 p = readV3S16(is); std::string formname = deSerializeString(is); int num = readU16(is); @@ -3324,7 +3339,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) { std::string datastring((char*)&data[2], datasize-2); std::istringstream is(datastring, std::ios_base::binary); - + std::string formname = deSerializeString(is); int num = readU16(is); std::map fields; @@ -3341,7 +3356,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) infostream<<"Server::ProcessData(): Ignoring " "unknown command "<getMap().getBlockNoCreateNoEx(blockpos); if(block) block->raiseModified(MOD_STATE_WRITE_NEEDED); - + setBlockNotSent(blockpos); } break; @@ -3446,11 +3461,11 @@ core::list Server::getPlayerInfo() DSTACK(__FUNCTION_NAME); JMutexAutoLock envlock(m_env_mutex); JMutexAutoLock conlock(m_con_mutex); - + core::list list; core::list players = m_env->getPlayers(); - + core::list::Iterator i; for(i = players.begin(); i != players.end(); i++) @@ -3488,7 +3503,7 @@ void Server::peerAdded(con::Peer *peer) DSTACK(__FUNCTION_NAME); verbosestream<<"Server::peerAdded(): peer->id=" <id<id; @@ -3501,7 +3516,7 @@ void Server::deletingPeer(con::Peer *peer, bool timeout) DSTACK(__FUNCTION_NAME); verbosestream<<"Server::deletingPeer(): peer->id=" <id<<", timeout="<id; @@ -3622,7 +3637,7 @@ void Server::SendNodeDef(con::Connection &con, u16 peer_id, void Server::SendInventory(u16 peer_id) { DSTACK(__FUNCTION_NAME); - + PlayerSAO *playersao = getPlayerSAO(peer_id); assert(playersao); @@ -3636,11 +3651,11 @@ void Server::SendInventory(u16 peer_id) playersao->getInventory()->serialize(os); std::string s = os.str(); - + SharedBuffer data(s.size()+2); writeU16(&data[0], TOCLIENT_INVENTORY); memcpy(&data[2], s.c_str(), s.size()); - + // Send as reliable m_con.Send(peer_id, 0, data, true); } @@ -3648,18 +3663,18 @@ void Server::SendInventory(u16 peer_id) void Server::SendChatMessage(u16 peer_id, const std::wstring &message) { DSTACK(__FUNCTION_NAME); - + std::ostringstream os(std::ios_base::binary); u8 buf[12]; - + // Write command writeU16(buf, TOCLIENT_CHAT_MESSAGE); os.write((char*)buf, 2); - + // Write length writeU16(buf, message.size()); os.write((char*)buf, 2); - + // Write string for(u32 i=0; i data((u8*)s.c_str(), s.size()); @@ -3730,7 +3745,7 @@ void Server::SendMovePlayer(u16 peer_id) writeV3F1000(os, player->getPosition()); writeF1000(os, player->getPitch()); writeF1000(os, player->getYaw()); - + { v3f pos = player->getPosition(); f32 pitch = player->getPitch(); @@ -3758,7 +3773,7 @@ void Server::SendPlayerPrivileges(u16 peer_id) std::set privs; scriptapi_get_auth(m_lua, player->getName(), NULL, &privs); - + std::ostringstream os(std::ios_base::binary); writeU16(os, TOCLIENT_PRIVILEGES); writeU16(os, privs.size()); @@ -3920,7 +3935,7 @@ void Server::sendRemoveNode(v3s16 p, u16 ignore_id, // Don't send if it's the same one if(client->peer_id == ignore_id) continue; - + if(far_players) { // Get player @@ -4008,7 +4023,7 @@ void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver) DSTACK(__FUNCTION_NAME); v3s16 p = block->getPos(); - + #if 0 // Analyze it a bit bool completely_air = true; @@ -4033,7 +4048,7 @@ void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver) /* Create a packet with the block in the right format */ - + std::ostringstream os(std::ios_base::binary); block->serialize(os, ver, false); std::string s = os.str(); @@ -4049,7 +4064,7 @@ void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver) /*infostream<<"Server: Sending block ("< queue; s32 total_sending = 0; - + { ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending"); @@ -4085,10 +4100,10 @@ void Server::SendBlocks(float dtime) continue; total_sending += client->SendingCount(); - + if(client->serialization_version == SER_FMT_VER_INVALID) continue; - + client->GetNextBlocks(this, dtime, queue); } } @@ -4104,7 +4119,7 @@ void Server::SendBlocks(float dtime) if(total_sending >= g_settings->getS32 ("max_simultaneous_block_sends_server_total")) break; - + PrioritySortedBlockTransfer q = queue[i]; MapBlock *block = NULL; @@ -4132,7 +4147,7 @@ void Server::fillMediaCache() DSTACK(__FUNCTION_NAME); infostream<<"Server: Calculating media file checksums"< paths; for(std::vector::iterator i = m_mods.begin(); @@ -4145,7 +4160,7 @@ void Server::fillMediaCache() } std::string path_all = "textures"; paths.push_back(path_all + DIR_DELIM + "all"); - + // Collect media file information from paths into cache for(std::list::iterator i = paths.begin(); i != paths.end(); i++) @@ -4265,7 +4280,7 @@ void Server::sendMediaAnnouncement(u16 peer_id) string sha1_digest } */ - + writeU16(os, TOCLIENT_ANNOUNCE_MEDIA); writeU16(os, file_announcements.size()); @@ -4466,7 +4481,7 @@ void Server::sendDetachedInventories(u16 peer_id) void Server::DiePlayer(u16 peer_id) { DSTACK(__FUNCTION_NAME); - + PlayerSAO *playersao = getPlayerSAO(peer_id); assert(playersao); @@ -4506,7 +4521,7 @@ void Server::RespawnPlayer(u16 peer_id) void Server::UpdateCrafting(u16 peer_id) { DSTACK(__FUNCTION_NAME); - + Player* player = m_env->getPlayer(peer_id); assert(player); @@ -4702,7 +4717,7 @@ bool Server::rollbackRevertActions(const std::list &actions, ServerMap *map = (ServerMap*)(&m_env->getMap()); // Disable rollback report sink while reverting BoolScopeSet rollback_scope_disable(&m_rollback_sink_enabled, false); - + // Fail if no actions to handle if(actions.empty()){ log->push_back("Nothing to do."); @@ -4711,7 +4726,7 @@ bool Server::rollbackRevertActions(const std::list &actions, int num_tried = 0; int num_failed = 0; - + for(std::list::const_iterator i = actions.begin(); i != actions.end(); i++) @@ -4734,7 +4749,7 @@ bool Server::rollbackRevertActions(const std::list &actions, log->push_back(os.str()); } } - + infostream<<"Map::rollbackRevertActions(): "<getS16("water_level"); + s16 water_level = map.m_emerge->water_level; //g_settings->getS16("default_water_level"); // Try to find a good place a few times for(s32 i=0; i<1000; i++) @@ -4856,7 +4871,7 @@ v3f findSpawnPos(ServerMap &map) //infostream<<"-> Underwater"<getKey(); ServerActiveObject* obj = m_env->getActiveObject(id); - + if(obj && obj->m_known_by_count > 0) obj->m_known_by_count--; } @@ -5032,7 +5047,7 @@ void Server::handlePeerChange(PeerChange &c) message += L" (timed out)"; } } - + /* Run scripts and remove from environment */ { if(player != NULL) @@ -5075,18 +5090,18 @@ void Server::handlePeerChange(PeerChange &c) <(max)?(max):(d))) +#define myfloor(x) ((x) > 0.0 ? (int)(x) : (int)(x) - 1) inline v3s16 arealim(v3s16 p, s16 d) { diff --git a/src/voxel.h b/src/voxel.h index e7155dfa..c2a5efb4 100644 --- a/src/voxel.h +++ b/src/voxel.h @@ -72,7 +72,7 @@ public: MaxEdge(p) { } - + /* Modifying methods */ @@ -106,14 +106,14 @@ public: if(p.Y > MaxEdge.Y) MaxEdge.Y = p.Y; if(p.Z > MaxEdge.Z) MaxEdge.Z = p.Z; } - + // Pad with d nodes void pad(v3s16 d) { MinEdge -= d; MaxEdge += d; } - + /*void operator+=(v3s16 off) { MinEdge += off; @@ -202,7 +202,7 @@ public: } assert(contains(a)); - + // Take back area, XY inclusive { v3s16 min(MinEdge.X, MinEdge.Y, a.MaxEdge.Z+1); @@ -258,7 +258,7 @@ public: } } - + /* Translates position from virtual coordinates to array index */ @@ -274,7 +274,7 @@ public: { return index(p.X, p.Y, p.Z); } - + // Translate index in the X coordinate void add_x(const v3s16 &extent, u32 &i, s16 a) { @@ -343,7 +343,7 @@ class VoxelManipulator /*: public NodeContainer*/ public: VoxelManipulator(); virtual ~VoxelManipulator(); - + /* Virtuals from NodeContainer */ @@ -430,7 +430,7 @@ public: void setNode(v3s16 p, const MapNode &n) { emerge(p); - + m_data[m_area.index(p)] = n; m_flags[m_area.index(p)] &= ~VOXELFLAG_INEXISTENT; m_flags[m_area.index(p)] &= ~VOXELFLAG_NOT_LOADED; @@ -457,10 +457,10 @@ public: //dstream<<"operator[] p=("< & from_nodes, core::map & light_sources, INodeDefManager *nodemgr); - + void spreadLight(enum LightBank bank, v3s16 p, INodeDefManager *nodemgr); void spreadLight(enum LightBank bank, core::map & from_nodes, INodeDefManager *nodemgr); - + /* Virtual functions */ - + /* Get the contents of the requested area from somewhere. Shall touch only nodes that have VOXELFLAG_NOT_LOADED @@ -565,7 +565,7 @@ public: MaxEdge is 1 higher than maximum allowed position */ VoxelArea m_area; - + /* NULL if data size is 0 (extent (0,0,0)) Data is stored as [z*h*w + y*h + x] @@ -576,7 +576,7 @@ public: Flags of all nodes */ u8 *m_flags; - + //TODO: Use these or remove them //TODO: Would these make any speed improvement? //bool m_pressure_route_valid; diff --git a/src/voxelalgorithms.cpp b/src/voxelalgorithms.cpp index 1af934f8..795530d4 100644 --- a/src/voxelalgorithms.cpp +++ b/src/voxelalgorithms.cpp @@ -86,10 +86,10 @@ SunlightPropagateResult propagateSunlight(VoxelManipulator &v, VoxelArea a, required_a.pad(v3s16(0,1,0)); // Make sure we have access to it v.emerge(a); - + s16 max_y = a.MaxEdge.Y; s16 min_y = a.MinEdge.Y; - + for(s32 x=a.MinEdge.X; x<=a.MaxEdge.X; x++) for(s32 z=a.MinEdge.Z; z<=a.MaxEdge.Z; z++) { @@ -125,11 +125,11 @@ SunlightPropagateResult propagateSunlight(VoxelManipulator &v, VoxelArea a, if(incoming_light > old_light) n.setLight(LIGHTBANK_DAY, incoming_light, ndef); - + if(diminish_light(incoming_light) != 0) light_sources.insert(p, true); } - + // Check validity of sunlight at top of block below if it // hasn't already been proven invalid if(bottom_sunlight_valid)