diff options
-rw-r--r-- | src/CMakeLists.txt | 1 | ||||
-rw-r--r-- | src/biome.cpp | 229 | ||||
-rw-r--r-- | src/biome.h | 79 | ||||
-rw-r--r-- | src/defaultsettings.cpp | 2 | ||||
-rw-r--r-- | src/environment.cpp | 12 | ||||
-rw-r--r-- | src/environment.h | 3 | ||||
-rw-r--r-- | src/farmesh.cpp | 6 | ||||
-rw-r--r-- | src/guiPauseMenu.cpp | 506 | ||||
-rw-r--r-- | src/guiPauseMenu.h | 120 | ||||
-rw-r--r-- | src/map.cpp | 47 | ||||
-rw-r--r-- | src/map.h | 22 | ||||
-rw-r--r-- | src/mapgen.cpp | 442 | ||||
-rw-r--r-- | src/mapgen.h | 120 | ||||
-rw-r--r-- | src/nodedef.cpp | 10 | ||||
-rw-r--r-- | src/noise.cpp | 695 | ||||
-rw-r--r-- | src/noise.h | 129 | ||||
-rw-r--r-- | src/scriptapi.cpp | 16 | ||||
-rw-r--r-- | src/server.cpp | 419 | ||||
-rw-r--r-- | src/server.h | 3 | ||||
-rw-r--r-- | src/settings.h | 15 | ||||
-rw-r--r-- | src/util/numeric.h | 1 | ||||
-rw-r--r-- | src/voxel.h | 34 | ||||
-rw-r--r-- | src/voxelalgorithms.cpp | 8 |
23 files changed, 1887 insertions, 1032 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index ac39e43e3..995d031e3 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 000000000..4b240d5a5 --- /dev/null +++ b/src/biome.cpp @@ -0,0 +1,229 @@ +/* +Minetest-c55 +Copyright (C) 2010-2011 kwolekr, Ryan Kwolek <kwolekr2@cs.scranton.edu> + +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<Biome *> *bgroup; + Biome *b; + + //bgroup = new std::vector<Biome *>; + + 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<Biome *> 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 000000000..5e43ab6d7 --- /dev/null +++ b/src/biome.h @@ -0,0 +1,79 @@ +/* +Minetest-c55 +Copyright (C) 2010-2011 kwolekr, Ryan Kwolek <kwolekr2@cs.scranton.edu> + +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<float> bgroup_freqs; + std::vector<std::vector<Biome *> *> 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 5a1b76b4a..38b9accd1 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 3f94484fe..51255b918 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="<<id<<std::endl; } } @@ -1717,6 +1721,8 @@ void ServerEnvironment::activateObjects(MapBlock *block, u32 dtime_s) If force_delete is set, active object is deleted nevertheless. It shall only be set so in the destructor of the environment. + + If block wasn't generated (not in memory or on disk), */ void ServerEnvironment::deactivateFarObjects(bool force_delete) { diff --git a/src/environment.h b/src/environment.h index d17edeacd..d1e61967f 100644 --- a/src/environment.h +++ b/src/environment.h @@ -241,8 +241,9 @@ public: MapBlock. Caller allocates memory, ServerEnvironment frees memory. Return value: true if succeeded, false if failed. + (note: not used, pending removal from engine) */ - bool addActiveObjectAsStatic(ServerActiveObject *object); + //bool addActiveObjectAsStatic(ServerActiveObject *object); /* Find out what new objects have been added to diff --git a/src/farmesh.cpp b/src/farmesh.cpp index bd08acadc..23f3db5f6 100644 --- a/src/farmesh.cpp +++ b/src/farmesh.cpp @@ -120,14 +120,14 @@ HeightPoint ground_height(u64 seed, v2s16 p2d) if(n) return n->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 c800cf952..f6cbf248f 100644 --- a/src/guiPauseMenu.cpp +++ b/src/guiPauseMenu.cpp @@ -1,253 +1,253 @@ -/*
-Minetest-c55
-Copyright (C) 2010 celeron55, Perttu Ahola <celeron55@gmail.com>
-
-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 <IGUICheckBox.h>
-#include <IGUIEditBox.h>
-#include <IGUIButton.h>
-#include <IGUIStaticText.h>
-#include <IGUIFont.h>
-#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<s32> 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<s32> 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<s32> 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<s32> 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<s32> 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<s32> 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<s32> 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<<BUILD_INFO<<"\n";
- os<<"path_user = "<<wrap_rows(porting::path_user, 20)<<"\n";
-
- Environment->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."
- <<std::endl;
- // Returning true disables focus change
- return true;
- }
- }
- if(event.GUIEvent.EventType==gui::EGET_BUTTON_CLICKED)
- {
- switch(event.GUIEvent.Caller->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 <celeron55@gmail.com> + +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 <IGUICheckBox.h> +#include <IGUIEditBox.h> +#include <IGUIButton.h> +#include <IGUIStaticText.h> +#include <IGUIFont.h> +#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<s32> 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<s32> 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<s32> 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<s32> 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<s32> 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<s32> 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<s32> 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<<BUILD_INFO<<"\n"; + os<<"path_user = "<<wrap_rows(porting::path_user, 20)<<"\n"; + + Environment->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." + <<std::endl; + // Returning true disables focus change + return true; + } + } + if(event.GUIEvent.EventType==gui::EGET_BUTTON_CLICKED) + { + switch(event.GUIEvent.Caller->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 e28159a93..4b15fc74f 100644 --- a/src/guiPauseMenu.h +++ b/src/guiPauseMenu.h @@ -1,60 +1,60 @@ -/*
-Minetest-c55
-Copyright (C) 2010 celeron55, Perttu Ahola <celeron55@gmail.com>
-
-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 <celeron55@gmail.com> + +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 6147bb635..0896c9b4f 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<<std::endl; + m_emerge = emerge; + //m_chunksize = 8; // Takes a few seconds if (g_settings->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"); + //<set noiseparams here> /* 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<v3s16, MapBlock*> &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<v3s16, MapBlock*> 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="<<m_seed<<std::endl; } @@ -30,6 +30,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "mapnode.h" #include "constants.h" #include "voxel.h" +#include "mapgen.h" //for BlockMakeData and EmergeManager #include "modifiedstate.h" #include "util/container.h" #include "nodetimer.h" @@ -46,9 +47,6 @@ class NodeMetadata; class IGameDef; class IRollbackReportSink; -namespace mapgen{ - struct BlockMakeData; -}; /* MapEditEvent @@ -360,7 +358,7 @@ public: /* savedir: directory to which map data should be saved */ - ServerMap(std::string savedir, IGameDef *gamedef); + ServerMap(std::string savedir, IGameDef *gamedef, EmergeManager *emerge); ~ServerMap(); s32 mapType() const @@ -379,15 +377,15 @@ public: /* Blocks are generated by using these and makeBlock(). */ - void initBlockMake(mapgen::BlockMakeData *data, v3s16 blockpos); - MapBlock* finishBlockMake(mapgen::BlockMakeData *data, + void initBlockMake(BlockMakeData *data, v3s16 blockpos); + MapBlock* finishBlockMake(BlockMakeData *data, core::map<v3s16, MapBlock*> &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<v3s16, MapBlock*> &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 ae0c551cb..7271b7652 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<v3s16, bool> light_sources; + core::map<v3s16, u8> 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; x<roomsize.X; x++) for(s16 y=0; y<roomsize.Y; y++) @@ -214,7 +504,7 @@ static void make_room1(VoxelManipulator &vmanip, v3s16 roomsize, v3s16 roomplace vmanip.m_data[vi] = MapNode(ndef->getId("mapgen_cobble")); } } - + // Make +-Y walls (floor and ceiling) for(s16 z=0; z<roomsize.Z; z++) for(s16 x=0; x<roomsize.X; x++) @@ -238,7 +528,7 @@ static void make_room1(VoxelManipulator &vmanip, v3s16 roomsize, v3s16 roomplace vmanip.m_data[vi] = MapNode(ndef->getId("mapgen_cobble")); } } - + // Fill with air for(s16 z=1; z<roomsize.Z-1; z++) for(s16 y=1; y<roomsize.Y-1; y++) @@ -401,9 +691,9 @@ static void make_corridor(VoxelManipulator &vmanip, v3s16 doorplace, if(partcount >= 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<roomsize.Z-1; z++) @@ -587,7 +877,7 @@ static void make_dungeon1(VoxelManipulator &vmanip, PseudoRandom &random, v3s16 areasize = vmanip.m_area.getExtent(); v3s16 roomsize; v3s16 roomplace; - + /* Find place for first room */ @@ -627,20 +917,20 @@ static void make_dungeon1(VoxelManipulator &vmanip, PseudoRandom &random, // No place found if(fits == false) return; - + /* Stores the center position of the last room made, so that a new corridor can be started from the last room instead of the new room, if chosen so. */ v3s16 last_room_center = roomplace+v3s16(roomsize.X/2,1,roomsize.Z/2); - + u32 room_count = random.range(2,7); for(u32 i=0; i<room_count; i++) { // Make a room to the determined place make_room1(vmanip, roomsize, roomplace, ndef); - + v3s16 room_center = roomplace + v3s16(roomsize.X/2,1,roomsize.Z/2); // Place torch at room center (for testing) @@ -649,7 +939,7 @@ static void make_dungeon1(VoxelManipulator &vmanip, PseudoRandom &random, // Quit if last room if(i == room_count-1) break; - + // Determine walker start position bool start_in_last_room = (random.range(0,2)!=0); @@ -667,7 +957,7 @@ static void make_dungeon1(VoxelManipulator &vmanip, PseudoRandom &random, // Store center of current room as the last one last_room_center = room_center; } - + // Create walker and find a place for a door RoomWalker walker(vmanip, walker_start_place, random, ndef); v3s16 doorplace; @@ -675,20 +965,20 @@ static void make_dungeon1(VoxelManipulator &vmanip, PseudoRandom &random, bool r = walker.findPlaceForDoor(doorplace, doordir); if(r == false) return; - + if(random.range(0,1)==0) // Make the door make_door1(vmanip, doorplace, doordir, ndef); else // Don't actually make a door doorplace -= doordir; - + // Make a random corridor starting from the door v3s16 corridor_end; v3s16 corridor_end_dir; make_corridor(vmanip, doorplace, doordir, corridor_end, corridor_end_dir, random, ndef); - + // Find a place for a random sized room roomsize = v3s16(random.range(4,8),random.range(4,6),random.range(4,8)); walker.setPos(corridor_end); @@ -703,7 +993,7 @@ static void make_dungeon1(VoxelManipulator &vmanip, PseudoRandom &random, else // Don't actually make a door roomplace -= doordir; - + } } #endif @@ -926,7 +1216,7 @@ s16 find_ground_level_from_noise(u64 seed, v2s16 p2d, s16 precision) } } } - + // This is more like the actual ground level level += dec[i-1]/2; @@ -1024,7 +1314,7 @@ bool block_is_underground(u64 seed, v3s16 blockpos) seed, v2s16(blockpos.X, blockpos.Z));*/ // Nah, this is just a heuristic, just return something s16 minimum_groundlevel = WATER_LEVEL; - + if(blockpos.Y*MAP_BLOCKSIZE + MAP_BLOCKSIZE <= minimum_groundlevel) return true; else @@ -1132,9 +1422,9 @@ BiomeType get_biome(u64 seed, v2s16 p2d) double d = noise2d_perlin( 0.6+(float)p2d.X/250, 0.2+(float)p2d.Y/250, seed+9130, 3, 0.50); - if(d > 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.X<<","<<blockpos.Y<<"," <<blockpos.Z<<")"<<std::endl;*/ @@ -1177,7 +1467,7 @@ void make_block(BlockMakeData *data) v3s16 blockpos_max = data->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; j<tunnel_routepoints; j++) { if(j%dswitchint==0 && large_cave == false) @@ -1467,12 +1757,12 @@ void make_block(BlockMakeData *data) ); main_direction *= (float)ps.range(0, 10)/10; } - + // Randomize size s16 min_d = min_tunnel_diameter; s16 max_d = max_tunnel_diameter; s16 rs = ps.range(min_d, max_d); - + // Every second section is rough bool randomize_xz = (ps2.range(1,2) == 1); @@ -1495,13 +1785,13 @@ void make_block(BlockMakeData *data) } v3f vec; - + vec = v3f( (float)(ps.next()%(maxlen.X*1))-(float)maxlen.X/2, (float)(ps.next()%(maxlen.Y*1))-(float)maxlen.Y/2, (float)(ps.next()%(maxlen.Z*1))-(float)maxlen.Z/2 ); - + // Jump downward sometimes if(!large_cave && ps.range(0,12) == 0) { @@ -1511,7 +1801,7 @@ void make_block(BlockMakeData *data) (float)(ps.next()%(maxlen.Z*1))-(float)maxlen.Z/2 ); } - + /*if(large_cave){ v3f p = orp + vec; s16 h = find_ground_level_clever(vmanip, @@ -1573,12 +1863,12 @@ void make_block(BlockMakeData *data) s16 x = cp.X + x0; v3s16 p(x,y,z); p += of; - + if(vmanip.m_area.contains(p) == false) continue; - + u32 i = vmanip.m_area.index(p); - + if(large_cave) { if(full_node_min.Y < WATER_LEVEL && @@ -1602,7 +1892,7 @@ void make_block(BlockMakeData *data) vmanip.m_data[i].getContent() == c_water_source || vmanip.m_data[i].getContent() == c_lava_source) continue; - + vmanip.m_data[i] = airnode; // Set tunnel flag @@ -1615,12 +1905,12 @@ void make_block(BlockMakeData *data) orp = rp; } - + } }//timer1 #endif - + #if 1 { // 15ms @cs=8 @@ -1629,13 +1919,13 @@ void make_block(BlockMakeData *data) /* Add mud to the central chunk */ - + for(s16 x=node_min.X; x<=node_max.X; x++) for(s16 z=node_min.Z; z<=node_max.Z; z++) { // Node position in 2d v2s16 p2d = v2s16(x,z); - + // Randomize mud amount s16 mud_add_amount = get_mud_add_amount(data->seed, 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 8986ddab0..d6e932ca0 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<v3s16> 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 36fa798fd..560c6090d 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 e75fbf4bd..5cb4be29a 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 <iostream> #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; i<octaves; i++) + float a = 0; + float f = 1.0; + float g = 1.0; + for (int i = 0; i < octaves; i++) { - a += g * noise2d_gradient(x*f, y*f, seed+i); + a += g * noise2d_gradient(x * f, y * f, seed + i); f *= 2.0; g *= persistence; } return a; } -double noise2d_perlin_abs(double x, double y, int seed, - int octaves, double persistence) + +float noise2d_perlin_abs(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; i<octaves; i++) + float a = 0; + float f = 1.0; + float g = 1.0; + for (int i = 0; i < octaves; i++) { - a += g * fabs(noise2d_gradient(x*f, y*f, seed+i)); + a += g * fabs(noise2d_gradient(x * f, y * f, seed + i)); f *= 2.0; g *= persistence; } return a; } -double noise3d_perlin(double x, double y, double z, int seed, - int octaves, double persistence) + +float noise3d_perlin(float x, float y, float z, int seed, + int octaves, float persistence) { - double a = 0; - double f = 1.0; - double g = 1.0; - for(int i=0; i<octaves; i++) + float a = 0; + float f = 1.0; + float g = 1.0; + for (int i = 0; i < octaves; i++) { - a += g * noise3d_gradient(x*f, y*f, z*f, seed+i); + a += g * noise3d_gradient(x * f, y * f, z * f, seed + i); f *= 2.0; g *= persistence; } return a; } -double noise3d_perlin_abs(double x, double y, double z, int seed, - int octaves, double persistence) + +float noise3d_perlin_abs(float x, float y, float z, int seed, + int octaves, float persistence) { - double a = 0; - double f = 1.0; - double g = 1.0; - for(int i=0; i<octaves; i++) + float a = 0; + float f = 1.0; + float g = 1.0; + for (int i = 0; i < octaves; i++) { - a += g * fabs(noise3d_gradient(x*f, y*f, z*f, seed+i)); + a += g * fabs(noise3d_gradient(x * f, y * f, z * f, seed + i)); f *= 2.0; g *= persistence; } return a; } + // -1->0, 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<m_size_x; x++) - for(int y=0; y<m_size_y; y++) - for(int z=0; z<m_size_z; z++) - { - double xd = (m_start_x + (double)x*m_samplelength_x); - double yd = (m_start_y + (double)y*m_samplelength_y); - double zd = (m_start_z + (double)z*m_samplelength_z); - double a = noise3d_param(param, xd,yd,zd); - intSet(x,y,z, a); + +/* + * NB: This algorithm is not optimal in terms of space complexity. The entire + * integer lattice of noise points could be done as 2 lines instead, and for 3D, + * 2 lines + 2 planes. + * However, this would require the noise calls to be interposed with the + * interpolation loops, which may trash the icache, leading to lower overall + * performance. + * Another optimization that could save half as many noise calls is to carry over + * values from the previous noise lattice as midpoints in the new lattice for the + * next octave. + */ +void Noise::gradientMap2D(float x, float y, float step_x, float step_y, int seed) { + float v00, v01, v10, v11, u, v, orig_u; + int index, i, j, x0, y0, noisex, noisey; + int nlx, nly; + + x0 = floor(x); + y0 = floor(y); + u = x - (float)x0; + v = y - (float)y0; + orig_u = u; + + //calculate noise point lattice + + nlx = (int)(u + sx * step_x) + 2; + nly = (int)(v + sy * step_y) + 2; + index = 0; + for (j = 0; j != nly; j++) + for (i = 0; i != nlx; i++) + noisebuf[index++] = noise2d(x0 + i, y0 + j, seed); + + //calculate interpolations + noisey = 0; + for (j = 0; j != sy; j++) { + v00 = noisebuf[noisey * nlx]; + v10 = noisebuf[noisey * nlx + 1]; + v01 = noisebuf[(noisey + 1) * nlx]; + v11 = noisebuf[(noisey + 1) * nlx + 1]; + + u = orig_u; + noisex = 0; + for (i = 0; i != sx; i++) { + buf[j * sx + i] = biLinearInterpolation(v00, v10, v01, v11, u, v); + u += step_x; + if (u >= 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<m_size_x; x++) - for(int y=0; y<m_size_y; y++) - for(int z=0; z<m_size_z; z++) - { - double xd = (m_start_x + (double)x*m_samplelength_x); - double yd = (m_start_y + (double)y*m_samplelength_y); - double zd = (m_start_z + (double)z*m_samplelength_z); - double a = noise3d_param(param, xd,yd,zd); - intMultiply(x,y,z, a); +void Noise::gradientMap3D(float x, float y, float z, + float step_x, float step_y, float step_z, + int seed) { + float v000, v010, v100, v110; + float v001, v011, v101, v111; + float u, v, w, orig_u, orig_w; + int index, i, j, k, x0, y0, z0, noisex, noisey, noisez; + int nlx, nly, nlz; + + x0 = floor(x); + y0 = floor(y); + z0 = floor(z); + u = x - (float)x0; + v = y - (float)y0; + w = z - (float)z0; + orig_u = u; + orig_w = w; + + //calculate noise point lattice + nlx = (int)(u + sx * step_x) + 2; + nly = (int)(v + sy * step_y) + 2; + nlz = (int)(v + sy * step_z) + 2; + index = 0; + for (k = 0; k != nlz; k++) + for (j = 0; j != nly; j++) + for (i = 0; i != nlx; i++) + noisebuf[index++] = noise3d(x0 + i, y0 + j, z0 + k, seed); + +#define index(x, y, z) ((z) * nly * nlx + (y) * nlx + (x)) + + //calculate interpolations + noisey = 0; + noisez = 0; + for (k = 0; k != sz; k++) { + v000 = noisebuf[index(0, noisey, noisez)]; + v100 = noisebuf[index(1, noisey, noisez)]; + v010 = noisebuf[index(0, noisey + 1, noisez)]; + v110 = noisebuf[index(1, noisey + 1, noisez)]; + v001 = noisebuf[index(0, noisey, noisez + 1)]; + v101 = noisebuf[index(1, noisey, noisez + 1)]; + v011 = noisebuf[index(0, noisey + 1, noisez + 1)]; + v111 = noisebuf[index(1, noisey + 1, noisez + 1)]; + + w = orig_w; + noisey = 0; + for (j = 0; j != sy; j++) { + v000 = noisebuf[index(0, noisey, noisez)]; + v100 = noisebuf[index(1, noisey, noisez)]; + v010 = noisebuf[index(0, noisey + 1, noisez)]; + v110 = noisebuf[index(1, noisey + 1, noisez)]; + v001 = noisebuf[index(0, noisey, noisez + 1)]; + v101 = noisebuf[index(1, noisey, noisez + 1)]; + v011 = noisebuf[index(0, noisey + 1, noisez + 1)]; + v111 = noisebuf[index(1, noisey + 1, noisez + 1)]; + + u = orig_u; + noisex = 0; + for (i = 0; i != sx; i++) { + buf[j * sx + i] = triLinearInterpolation( + v000, v100, v010, v110, + v001, v101, v011, v111, + u, v, w); + u += step_x; + if (u >= 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 670c2eddc..6e5120003 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 959885d32..69ee48a76 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 a7767842d..a3c0b66ed 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()"<<std::endl; m_server->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<QueuedBlockEmerge> 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"<<std::endl; //TimeTaker timer("block emerge"); - + /* Try to emerge it from somewhere. If it is only wanted as optional, only loading from disk will be allowed. */ - + /* Check if any peer wants it as non-optional. In that case it will be generated. @@ -224,17 +229,17 @@ void * EmergeThread::Thread() u8 flags = i.getNode()->getValue(); if((flags & BLOCK_EMERGE_FLAG_FROMDISK) == false) only_from_disk = false; - + } } - + if(enable_mapgen_debug_info) infostream<<"EmergeThread: p=" <<"("<<p.X<<","<<p.Y<<","<<p.Z<<") " <<"only_from_disk="<<only_from_disk<<std::endl; - - ServerMap &map = ((ServerMap&)m_server->m_env->getMap()); - + + + MapBlock *block = NULL; bool got_block = true; core::map<v3s16, MapBlock*> modified_blocks; @@ -243,17 +248,17 @@ void * EmergeThread::Thread() Try to fetch block from memory or disk. If not found and asked to generate, initialize generator. */ - + bool started_generate = false; - mapgen::BlockMakeData data; + BlockMakeData data; { JMutexAutoLock envlock(m_server->m_env_mutex); - + // Load sector if it isn't loaded if(map.getSectorNoGenerateNoEx(p2d) == NULL) map.loadSectorMeta(p2d); - + // Attempt to load block block = map.getBlockNoCreateNoEx(p); if(!block || block->isDummy() || !block->isGenerated()) @@ -264,7 +269,7 @@ void * EmergeThread::Thread() block = map.loadBlock(p); } - + // If could not load and allowed to generate, start generation // inside this same envlock if(only_from_disk == false && @@ -287,16 +292,17 @@ void * EmergeThread::Thread() SPT_AVG); 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 } - + 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 "<<t<<"ms"<<std::endl;*/ } - + if(enable_mapgen_debug_info) infostream<<"EmergeThread: ended up with: " <<analyze_block(block)<<std::endl; @@ -348,11 +354,11 @@ void * EmergeThread::Thread() if(block == NULL) got_block = false; - + /* Set sent status of modified blocks on clients */ - + // NOTE: Server's clients are also behind the connection mutex JMutexAutoLock lock(m_server->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<u16, RemoteClient*>::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<PrioritySortedBlockTransfer> &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=" <<m_nearest_unsent_reset_timer<<std::endl;*/ - + // Reset periodically to workaround for some bugs or stuff if(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 "<<d_start<<std::endl; s32 nearest_emerged_d = -1; s32 nearest_emergefull_d = -1; s32 nearest_sent_d = -1; bool queue_is_full = false; - + s16 d; for(d = d_start; d <= d_max; d++) { /*errorstream<<"checking d="<<d<<" for " <<server->getPlayerName(peer_id)<<std::endl;*/ //infostream<<"RemoteClient::SendBlocks(): d="<<d<<std::endl; - + /* If m_nearest_unsent_d was changed by the EmergeThread (it can change it to 0 through SetBlockNotSent), @@ -581,12 +587,12 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime, */ core::list<v3s16> list; getFacePositions(list, d); - + core::list<v3s16>::Iterator li; for(li=list.begin(); li!=list.end(); li++) { v3s16 p = *li + center; - + /* Send throttling - Don't allow too many simultaneous transfers @@ -594,10 +600,10 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime, Also, don't send blocks that are already flying. */ - + // Start with the usual maximum u16 max_simul_dynamic = max_simul_sends_usually; - + // If block is very close, allow full maximum if(d <= BLOCK_SEND_DISABLE_LIMITS_MAX_D) max_simul_dynamic = max_simul_sends_setting; @@ -608,11 +614,11 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime, queue_is_full = true; goto queue_full_break; } - + // Don't send blocks that are currently being transferred if(m_blocks_sending.find(p) != NULL) continue; - + /* Do not go over-limit */ @@ -623,10 +629,10 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime, || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE || p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE) continue; - + // If this is true, inexistent block will be made from scratch bool generate = d <= d_max_gen; - + { /*// Limit the generating area vertically to 2/3 if(abs(p.Y - center.Y) > d_max_gen - d_max_gen / 3) @@ -655,7 +661,7 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime, v2s16 p2d_nodes_center( MAP_BLOCKSIZE*p.X, MAP_BLOCKSIZE*p.Z); - + // Get ground height in nodes s16 gh = server->m_env->getServerMap().findGroundLevel( p2d_nodes_center); @@ -697,7 +703,7 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime, Check if map has this block */ MapBlock *block = server->m_env->getMap().getBlockNoCreateNoEx(p); - + bool surely_not_found_on_disk = false; bool block_is_invalid = false; if(block != NULL) @@ -711,13 +717,13 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime, { surely_not_found_on_disk = true; } - + // Block is valid if lighting is up-to-date and data exists if(block->isValid() == false) { block_is_invalid = true; } - + /*if(block->isFullyGenerated() == false) { block_is_invalid = true; @@ -775,13 +781,13 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime, if(server->m_emerge_queue.peerItemCount(peer_id) < max_emerge) { //infostream<<"Adding block to emerge queue"<<std::endl; - + // Add it to the emerge queue and trigger the thread - + u8 flags = 0; if(generate == false) flags |= BLOCK_EMERGE_FLAG_FROMDISK; - + server->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 "<<d<<std::endl; - + // If nothing was found for sending and nothing was queued for // emerging, continue next time browsing from here if(nearest_emerged_d != -1){ @@ -871,7 +877,7 @@ void RemoteClient::SentBlock(v3s16 p) void RemoteClient::SetBlockNotSent(v3s16 p) { m_nearest_unsent_d = 0; - + if(m_blocks_sending.find(p) != NULL) m_blocks_sending.remove(p); if(m_blocks_sent.find(p) != NULL) @@ -881,7 +887,7 @@ void RemoteClient::SetBlockNotSent(v3s16 p) void RemoteClient::SetBlocksNotSent(core::map<v3s16, MapBlock*> &blocks) { m_nearest_unsent_d = 0; - + for(core::map<v3s16, MapBlock*>::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 \""<<m_gamespec.id<<"\""; if(m_simple_singleplayer_mode) infostream<<" in simple singleplayer mode"<<std::endl; @@ -976,6 +983,9 @@ Server::Server( infostream<<"- config: "<<m_path_config<<std::endl; infostream<<"- game: "<<m_gamespec.path<<std::endl; + // Create emerge manager + m_emerge = new EmergeManager(this); + // Create rollback manager std::string rollback_path = m_path_world+DIR_DELIM+"rollback.txt"; m_rollback = createRollbackManager(rollback_path, this); @@ -1075,21 +1085,24 @@ Server::Server( throw ModError("Failed to load and run "+scriptpath); } } - + // Read Textures and calculate sha1 sums fillMediaCache(); // Apply item aliases in the node definition manager m_nodedef->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"<<std::endl; m_env->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"<<std::endl; script_deinit(m_lua); @@ -1218,7 +1233,7 @@ void Server::start(unsigned short port) // Stop thread if already running m_thread.stop(); - + // Initialize connection m_con.SetTimeoutMs(30); m_con.Serve(port); @@ -1226,7 +1241,7 @@ void Server::start(unsigned short port) // Start thread m_thread.setRun(true); m_thread.Start(); - + // ASCII art for the win! actionstream <<" .__ __ __ "<<std::endl @@ -1243,7 +1258,7 @@ void Server::start(unsigned short port) void Server::stop() { DSTACK(__FUNCTION_NAME); - + infostream<<"Server: Stopping and waiting threads"<<std::endl; // Stop threads (set run=false first so both start stopping) @@ -1251,7 +1266,7 @@ void Server::stop() m_emergethread.setRun(false); m_thread.stop(); m_emergethread.stop(); - + infostream<<"Server: Threads stopped"<<std::endl; } @@ -1275,28 +1290,28 @@ void Server::step(float dtime) void Server::AsyncRunStep() { DSTACK(__FUNCTION_NAME); - + g_profiler->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 "<<dtime<<std::endl; //infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl; - + { JMutexAutoLock lock1(m_step_dtime_mutex); m_step_dtime -= dtime; @@ -1308,14 +1323,14 @@ void Server::AsyncRunStep() { m_uptime.set(m_uptime.get() + dtime); } - + { // Process connection's timeouts JMutexAutoLock lock2(m_con_mutex); ScopeProfiler sp(g_profiler, "Server: connection timeout processing"); m_con.RunTimeouts(dtime); } - + { // This has to be called so that the client list gets synced // with the peer list of the connection @@ -1362,7 +1377,7 @@ void Server::AsyncRunStep() ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG); m_env->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<v3s16, MapBlock*> modified_blocks; m_env->getMap().transformLiquids(modified_blocks); -#if 0 +#if 0 /* Update lighting */ core::map<v3s16, MapBlock*> 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<v3s16, MapBlock*>::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<u16, RemoteClient*>::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:"<<std::endl; for(core::map<u16, RemoteClient*>::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"<<std::endl; continue; } - + std::string data_buffer; char buf[4]; - + // Handle removed objects writeU16((u8*)buf, removed_objects.size()); data_buffer.append(buf, 2); @@ -1567,7 +1582,7 @@ void Server::AsyncRunStep() // Add to data buffer for sending writeU16((u8*)buf, i.getNode()->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<ActiveObjectMessage>* message_list = NULL; core::map<u16, core::list<ActiveObjectMessage>* >::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<u16, RemoteClient*>::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)<<std::endl; } - + /* Set blocks not sent to far players */ @@ -1892,7 +1907,7 @@ void Server::AsyncRunStep() verbosestream<<"Server: MapEditEvents:"<<std::endl; prof.print(verbosestream); } - + } /* @@ -1905,7 +1920,7 @@ void Server::AsyncRunStep() if(counter >= 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) <<peer_id<<" not found"<<std::endl; return; } - + std::string addr_s = m_con.GetPeerAddress(peer_id).serializeString(); u8 peer_ser_ver = getClient(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<PLAYERNAME_SIZE-1; i++) @@ -2156,7 +2171,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) playername[i] = data[3+i]; } playername[PLAYERNAME_SIZE-1] = 0; - + if(playername[0]=='\0') { actionstream<<"Server: Player with an empty name " @@ -2200,10 +2215,10 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) SendAccessDenied(m_con, peer_id, L"Invalid password hash"); return; } - + std::string checkpwd; // Password hash to check against bool has_auth = scriptapi_get_auth(m_lua, playername, &checkpwd, NULL); - + // If no authentication info exists for user, create it if(!has_auth){ if(!isSingleplayer() && @@ -2224,7 +2239,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) scriptapi_create_auth(m_lua, playername, initial_password); } - + has_auth = scriptapi_get_auth(m_lua, playername, &checkpwd, NULL); if(!has_auth){ @@ -2249,7 +2264,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) L"Running in simple singleplayer mode."); return; } - + // Enforce user limit. // Don't enforce for users that have some admin right if(m_clients.size() >= 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="<<command<<std::endl; return; } - + Player *player = m_env->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 "<<peer_id<<" to " <<"("<<position.X<<","<<position.Y<<","<<position.Z<<")" <<" pitch="<<pitch<<" yaw="<<yaw<<std::endl;*/ @@ -2481,7 +2496,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) { if(datasize < 2+1) return; - + /* [0] u16 command [2] u8 count @@ -2507,7 +2522,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) { if(datasize < 2+1) return; - + /* [0] u16 command [2] u8 count @@ -2688,7 +2703,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) return; } } - + // Do the action a->apply(this, playersao, this); // Eat the action @@ -2704,11 +2719,11 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) u8 buf[6]; std::string datastring((char*)&data[2], datasize-2); std::istringstream is(datastring, std::ios_base::binary); - + // Read stuff is.read((char*)buf, 2); u16 len = readU16(buf); - + std::wstring message; for(u16 i=0; i<len; i++) { @@ -2722,21 +2737,21 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) // Get player name of this client std::wstring name = narrow_to_wide(player->getName()); - + // Run script hook bool ate = scriptapi_on_chat_message(m_lua, player->getName(), wide_to_narrow(message)); // If script ate the message, don't proceed if(ate) return; - + // Line to send to players std::wstring line; // Whether to send to the player that sent the line bool send_to_sender = false; // Whether to send to other players bool send_to_others = false; - + // Commands are implemented in Lua, so only catch invalid // commands that were not "eaten" and send an error back if(message[0] == L'/') @@ -2761,7 +2776,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) send_to_sender = true; } } - + if(line != L"") { if(send_to_others) @@ -2888,9 +2903,9 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) { if(player->hp != 0 || !g_settings->getBool("enable_damage")) return; - + RespawnPlayer(peer_id); - + actionstream<<player->getName()<<" respawns at " <<PP(player->getPosition()/BS)<<std::endl; @@ -2900,7 +2915,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) else if(command == TOSERVER_REQUEST_MEDIA) { std::string datastring((char*)&data[2], datasize-2); std::istringstream is(datastring, std::ios_base::binary); - + core::list<MediaRequest> 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<std::string, std::string> fields; @@ -3341,7 +3356,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) infostream<<"Server::ProcessData(): Ignoring " "unknown command "<<command<<std::endl; } - + } //try catch(SendFailedException &e) { @@ -3427,7 +3442,7 @@ void Server::setInventoryModified(const InventoryLocation &loc) MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos); if(block) block->raiseModified(MOD_STATE_WRITE_NEEDED); - + setBlockNotSent(blockpos); } break; @@ -3446,11 +3461,11 @@ core::list<PlayerInfo> Server::getPlayerInfo() DSTACK(__FUNCTION_NAME); JMutexAutoLock envlock(m_env_mutex); JMutexAutoLock conlock(m_con_mutex); - + core::list<PlayerInfo> list; core::list<Player*> players = m_env->getPlayers(); - + core::list<Player*>::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=" <<peer->id<<std::endl; - + PeerChange c; c.type = PEER_ADDED; c.peer_id = peer->id; @@ -3501,7 +3516,7 @@ void Server::deletingPeer(con::Peer *peer, bool timeout) DSTACK(__FUNCTION_NAME); verbosestream<<"Server::deletingPeer(): peer->id=" <<peer->id<<", timeout="<<timeout<<std::endl; - + PeerChange c; c.type = PEER_REMOVED; c.peer_id = peer->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<u8> 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<message.size(); i++) { @@ -3667,7 +3682,7 @@ void Server::SendChatMessage(u16 peer_id, const std::wstring &message) writeU16(buf, w); os.write((char*)buf, 2); } - + // Make data buffer std::string s = os.str(); SharedBuffer<u8> 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<std::string> 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 ("<<p.X<<","<<p.Y<<","<<p.Z<<")" <<": \tpacket size: "<<replysize<<std::endl;*/ - + /* Send packet */ @@ -4068,7 +4083,7 @@ void Server::SendBlocks(float dtime) core::array<PrioritySortedBlockTransfer> 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"<<std::endl; - + // Collect all media file paths std::list<std::string> paths; for(std::vector<ModSpec>::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<std::string>::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<RollbackAction> &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<RollbackAction> &actions, int num_tried = 0; int num_failed = 0; - + for(std::list<RollbackAction>::const_iterator i = actions.begin(); i != actions.end(); i++) @@ -4734,7 +4749,7 @@ bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions, log->push_back(os.str()); } } - + infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried <<" failed"<<std::endl; @@ -4825,14 +4840,14 @@ v3f findSpawnPos(ServerMap &map) //return v3f(50,50,50)*BS; v3s16 nodepos; - + #if 0 nodepos = v2s16(0,0); groundheight = 20; #endif #if 1 - s16 water_level = g_settings->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"<<std::endl; continue; } - + nodepos = v3s16(nodepos2d.X, groundheight-2, nodepos2d.Y); bool is_good = false; s32 air_count = 0; @@ -4881,7 +4896,7 @@ v3f findSpawnPos(ServerMap &map) } } #endif - + return intToFloat(nodepos, BS); } @@ -4954,7 +4969,7 @@ void Server::handlePeerChange(PeerChange &c) { JMutexAutoLock envlock(m_env_mutex); JMutexAutoLock conlock(m_con_mutex); - + if(c.type == PEER_ADDED) { /* @@ -4984,7 +4999,7 @@ void Server::handlePeerChange(PeerChange &c) n = m_clients.find(c.peer_id); // The client should exist assert(n != NULL); - + /* Mark objects to be not known by the client */ @@ -4997,7 +5012,7 @@ void Server::handlePeerChange(PeerChange &c) // Get object u16 id = i.getNode()->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) <<os.str()<<std::endl; } } - + // Delete client delete m_clients[c.peer_id]; m_clients.remove(c.peer_id); // Send player info to all remaining clients //SendPlayerInfos(); - + // Send leave chat message to all remaining clients if(message.length() != 0) BroadcastChatMessage(message); - + } // PEER_REMOVED else { @@ -5111,7 +5126,7 @@ void Server::handlePeerChanges() void dedicated_server_loop(Server &server, bool &kill) { DSTACK(__FUNCTION_NAME); - + verbosestream<<"dedicated_server_loop()"<<std::endl; IntervalLimiter m_profiler_interval; diff --git a/src/server.h b/src/server.h index 26e47d36c..a60be2c0b 100644 --- a/src/server.h +++ b/src/server.h @@ -739,6 +739,9 @@ private: bool m_rollback_sink_enabled; bool m_enable_rollback_recording; // Updated once in a while + // Emerge manager + EmergeManager *m_emerge; + // Scripting // Envlock and conlock should be locked when using Lua lua_State *m_lua; diff --git a/src/settings.h b/src/settings.h index 1a29ef00a..eec546b1a 100644 --- a/src/settings.h +++ b/src/settings.h @@ -574,10 +574,7 @@ public: set(name, "false"); } - void setS32(std::string name, s32 value) - { - set(name, itos(value)); - } + void setFloat(std::string name, float value) { @@ -598,6 +595,16 @@ public: set(name, os.str()); } + void setS16(std::string name, s16 value) + { + set(name, itos(value)); + } + + void setS32(std::string name, s32 value) + { + set(name, itos(value)); + } + void setU64(std::string name, u64 value) { std::ostringstream os; diff --git a/src/util/numeric.h b/src/util/numeric.h index 5ed4d0e99..a028f1ff2 100644 --- a/src/util/numeric.h +++ b/src/util/numeric.h @@ -120,6 +120,7 @@ inline s16 rangelim(s16 i, s16 max) } #define rangelim(d, min, max) ((d) < (min) ? (min) : ((d)>(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 e7155dfac..c2a5efb4b 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=("<<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl; if(isValidPosition(p) == false) emerge(VoxelArea(p)); - + return m_data[m_area.index(p)]; }*/ - + /* Set stuff if available without an emerge. Return false if failed. @@ -496,7 +496,7 @@ public: void print(std::ostream &o, INodeDefManager *nodemgr, VoxelPrintMode mode=VOXELPRINT_MATERIAL); - + void addArea(VoxelArea area); /* @@ -505,7 +505,7 @@ public: */ void copyFrom(MapNode *src, VoxelArea src_area, v3s16 from_pos, v3s16 to_pos, v3s16 size); - + // Copy data void copyTo(MapNode *dst, VoxelArea dst_area, v3s16 dst_pos, v3s16 from_pos, v3s16 size); @@ -523,15 +523,15 @@ public: void unspreadLight(enum LightBank bank, core::map<v3s16, u8> & from_nodes, core::map<v3s16, bool> & light_sources, INodeDefManager *nodemgr); - + void spreadLight(enum LightBank bank, v3s16 p, INodeDefManager *nodemgr); void spreadLight(enum LightBank bank, core::map<v3s16, bool> & 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 1af934f80..795530d40 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) |