sha1.cpp
base64.cpp
ban.cpp
+ biome.cpp
clientserver.cpp
staticobject.cpp
util/serialize.cpp
--- /dev/null
+/*
+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;
+}
--- /dev/null
+/*
+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
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");
return id;
}
+#if 0
bool ServerEnvironment::addActiveObjectAsStatic(ServerActiveObject *obj)
{
assert(obj);
return succeeded;
}
+#endif
/*
Finds out what new objects have been added to
*/
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;
}
}
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)
{
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
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
-/*\r
-Minetest-c55\r
-Copyright (C) 2010 celeron55, Perttu Ahola <celeron55@gmail.com>\r
-\r
-This program is free software; you can redistribute it and/or modify\r
-it under the terms of the GNU Lesser General Public License as published by\r
-the Free Software Foundation; either version 2.1 of the License, or\r
-(at your option) any later version.\r
-\r
-This program is distributed in the hope that it will be useful,\r
-but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
-GNU Lesser General Public License for more details.\r
-\r
-You should have received a copy of the GNU Lesser General Public License along\r
-with this program; if not, write to the Free Software Foundation, Inc.,\r
-51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\r
-*/\r
-\r
-#include "guiPauseMenu.h"\r
-#include "debug.h"\r
-#include "serialization.h"\r
-#include "porting.h"\r
-#include "config.h"\r
-#include "main.h"\r
-#include <IGUICheckBox.h>\r
-#include <IGUIEditBox.h>\r
-#include <IGUIButton.h>\r
-#include <IGUIStaticText.h>\r
-#include <IGUIFont.h>\r
-#include "gettext.h"\r
-#include "util/string.h"\r
-\r
-GUIPauseMenu::GUIPauseMenu(gui::IGUIEnvironment* env,\r
- gui::IGUIElement* parent, s32 id,\r
- IGameCallback *gamecallback,\r
- IMenuManager *menumgr,\r
- bool simple_singleplayer_mode):\r
- GUIModalMenu(env, parent, id, menumgr),\r
- m_gamecallback(gamecallback),\r
- m_simple_singleplayer_mode(simple_singleplayer_mode)\r
-{\r
-}\r
-\r
-GUIPauseMenu::~GUIPauseMenu()\r
-{\r
- removeChildren();\r
-}\r
-\r
-void GUIPauseMenu::removeChildren()\r
-{\r
- {\r
- gui::IGUIElement *e = getElementFromId(256);\r
- if(e != NULL)\r
- e->remove();\r
- }\r
- {\r
- gui::IGUIElement *e = getElementFromId(257);\r
- if(e != NULL)\r
- e->remove();\r
- }\r
- {\r
- gui::IGUIElement *e = getElementFromId(258);\r
- if(e != NULL)\r
- e->remove();\r
- }\r
- {\r
- gui::IGUIElement *e = getElementFromId(259);\r
- if(e != NULL)\r
- e->remove();\r
- }\r
- {\r
- gui::IGUIElement *e = getElementFromId(260);\r
- if(e != NULL)\r
- e->remove();\r
- }\r
- {\r
- gui::IGUIElement *e = getElementFromId(261);\r
- if(e != NULL)\r
- e->remove();\r
- }\r
-}\r
-\r
-void GUIPauseMenu::regenerateGui(v2u32 screensize)\r
-{\r
- /*\r
- Remove stuff\r
- */\r
- removeChildren();\r
- \r
- /*\r
- Calculate new sizes and positions\r
- */\r
- core::rect<s32> rect(\r
- screensize.X/2 - 580/2,\r
- screensize.Y/2 - 300/2,\r
- screensize.X/2 + 580/2,\r
- screensize.Y/2 + 300/2\r
- );\r
- \r
- DesiredRect = rect;\r
- recalculateAbsolutePosition(false);\r
-\r
- v2s32 size = rect.getSize();\r
-\r
- /*\r
- Add stuff\r
- */\r
- const s32 btn_height = 30;\r
- const s32 btn_gap = 20;\r
- const s32 btn_num = m_simple_singleplayer_mode ? 3 : 4;\r
- s32 btn_y = size.Y/2-((btn_num*btn_height+(btn_num-1)*btn_gap))/2;\r
- changeCtype("");\r
- {\r
- core::rect<s32> rect(0, 0, 140, btn_height);\r
- rect = rect + v2s32(size.X/2-140/2, btn_y);\r
- Environment->addButton(rect, this, 256,\r
- wgettext("Continue"));\r
- }\r
- btn_y += btn_height + btn_gap;\r
- if(!m_simple_singleplayer_mode)\r
- {\r
- {\r
- core::rect<s32> rect(0, 0, 140, btn_height);\r
- rect = rect + v2s32(size.X/2-140/2, btn_y);\r
- Environment->addButton(rect, this, 261,\r
- wgettext("Change Password"));\r
- }\r
- btn_y += btn_height + btn_gap;\r
- }\r
- {\r
- core::rect<s32> rect(0, 0, 140, btn_height);\r
- rect = rect + v2s32(size.X/2-140/2, btn_y);\r
- Environment->addButton(rect, this, 260,\r
- wgettext("Exit to Menu"));\r
- }\r
- btn_y += btn_height + btn_gap;\r
- {\r
- core::rect<s32> rect(0, 0, 140, btn_height);\r
- rect = rect + v2s32(size.X/2-140/2, btn_y);\r
- Environment->addButton(rect, this, 257,\r
- wgettext("Exit to OS"));\r
- }\r
-\r
- {\r
- core::rect<s32> rect(0, 0, 180, 240);\r
- rect = rect + v2s32(size.X/2 + 90, size.Y/2-rect.getHeight()/2);\r
- Environment->addStaticText(chartowchar_t(gettext(\r
- "Default Controls:\n"\r
- "- WASD: Walk\n"\r
- "- Mouse left: dig/hit\n"\r
- "- Mouse right: place/use\n"\r
- "- Mouse wheel: select item\n"\r
- "- 0...9: select item\n"\r
- "- Shift: sneak\n"\r
- "- R: Toggle viewing all loaded chunks\n"\r
- "- I: Inventory menu\n"\r
- "- ESC: This menu\n"\r
- "- T: Chat\n"\r
- )), rect, false, true, this, 258);\r
- }\r
- {\r
- core::rect<s32> rect(0, 0, 180, 220);\r
- rect = rect + v2s32(size.X/2 - 90 - rect.getWidth(), size.Y/2-rect.getHeight()/2);\r
- \r
- v2u32 max_texture_size;\r
- {\r
- video::IVideoDriver* driver = Environment->getVideoDriver();\r
- max_texture_size = driver->getMaxTextureSize();\r
- }\r
-\r
- std::ostringstream os;\r
- os<<"Minetest\n";\r
- os<<BUILD_INFO<<"\n";\r
- os<<"path_user = "<<wrap_rows(porting::path_user, 20)<<"\n";\r
- \r
- Environment->addStaticText(narrow_to_wide(os.str()).c_str(), rect, false, true, this, 259);\r
- }\r
- changeCtype("C");\r
-}\r
-\r
-void GUIPauseMenu::drawMenu()\r
-{\r
- gui::IGUISkin* skin = Environment->getSkin();\r
- if (!skin)\r
- return;\r
- video::IVideoDriver* driver = Environment->getVideoDriver();\r
- \r
- video::SColor bgcolor(140,0,0,0);\r
- driver->draw2DRectangle(bgcolor, AbsoluteRect, &AbsoluteClippingRect);\r
-\r
- gui::IGUIElement::draw();\r
-}\r
-\r
-bool GUIPauseMenu::OnEvent(const SEvent& event)\r
-{\r
-\r
- if(event.EventType==EET_KEY_INPUT_EVENT)\r
- {\r
- if(event.KeyInput.PressedDown)\r
- {\r
- if(event.KeyInput.Key==KEY_ESCAPE)\r
- {\r
- quitMenu();\r
- return true;\r
- }\r
- else if(event.KeyInput.Key==KEY_RETURN)\r
- {\r
- quitMenu();\r
- return true;\r
- }\r
- }\r
- }\r
- if(event.EventType==EET_GUI_EVENT)\r
- {\r
- if(event.GUIEvent.EventType==gui::EGET_ELEMENT_FOCUS_LOST\r
- && isVisible())\r
- {\r
- if(!canTakeFocus(event.GUIEvent.Element))\r
- {\r
- dstream<<"GUIPauseMenu: Not allowing focus change."\r
- <<std::endl;\r
- // Returning true disables focus change\r
- return true;\r
- }\r
- }\r
- if(event.GUIEvent.EventType==gui::EGET_BUTTON_CLICKED)\r
- {\r
- switch(event.GUIEvent.Caller->getID())\r
- {\r
- case 256: // continue\r
- quitMenu();\r
- // ALWAYS return immediately after quitMenu()\r
- return true;\r
- case 261:\r
- quitMenu();\r
- m_gamecallback->changePassword();\r
- return true;\r
- case 260: // disconnect\r
- m_gamecallback->disconnect();\r
- quitMenu();\r
- return true;\r
- case 257: // exit\r
- m_gamecallback->exitToOS();\r
- quitMenu();\r
- return true;\r
- }\r
- }\r
- }\r
- \r
- return Parent ? Parent->OnEvent(event) : false;\r
-}\r
-\r
+/*
+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;
+}
+
-/*\r
-Minetest-c55\r
-Copyright (C) 2010 celeron55, Perttu Ahola <celeron55@gmail.com>\r
-\r
-This program is free software; you can redistribute it and/or modify\r
-it under the terms of the GNU Lesser General Public License as published by\r
-the Free Software Foundation; either version 2.1 of the License, or\r
-(at your option) any later version.\r
-\r
-This program is distributed in the hope that it will be useful,\r
-but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
-GNU Lesser General Public License for more details.\r
-\r
-You should have received a copy of the GNU Lesser General Public License along\r
-with this program; if not, write to the Free Software Foundation, Inc.,\r
-51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\r
-*/\r
-\r
-#ifndef GUIPAUSEMENU_HEADER\r
-#define GUIPAUSEMENU_HEADER\r
-\r
-#include "irrlichttypes_extrabloated.h"\r
-#include "modalMenu.h"\r
-\r
-class IGameCallback\r
-{\r
-public:\r
- virtual void exitToOS() = 0;\r
- virtual void disconnect() = 0;\r
- virtual void changePassword() = 0;\r
-};\r
-\r
-class GUIPauseMenu : public GUIModalMenu\r
-{\r
-public:\r
- GUIPauseMenu(gui::IGUIEnvironment* env,\r
- gui::IGUIElement* parent, s32 id,\r
- IGameCallback *gamecallback,\r
- IMenuManager *menumgr,\r
- bool simple_singleplayer_mode);\r
- ~GUIPauseMenu();\r
- \r
- void removeChildren();\r
- /*\r
- Remove and re-add (or reposition) stuff\r
- */\r
- void regenerateGui(v2u32 screensize);\r
-\r
- void drawMenu();\r
-\r
- bool OnEvent(const SEvent& event);\r
- \r
-private:\r
- IGameCallback *m_gamecallback;\r
- bool m_simple_singleplayer_mode;\r
-};\r
-\r
-#endif\r
-\r
+/*
+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
+
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),
{
verbosestream<<__FUNCTION_NAME<<std::endl;
+ m_emerge = emerge;
+
//m_chunksize = 8; // Takes a few seconds
if (g_settings->get("fixed_map_seed").empty())
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
#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)
Refer to the map generator heuristics.
*/
- bool ug = mapgen::block_is_underground(data->seed, p);
+ bool ug = m_emerge->isBlockUnderground(p);
block->setIsUnderground(ug);
}
// 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;
return sector;
}
+#if 0
/*
This is a quick-hand function for calling makeBlock().
*/
/*
Create block make data
*/
- mapgen::BlockMakeData data;
+ BlockMakeData data;
initBlockMake(&data, p);
/*
*/
{
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
return block;
}
+#endif
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);
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);
return block;
}
- }
+ }*/
return NULL;
}
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;
Settings params;
params.setU64("seed", m_seed);
+ params.setS16("water_level", m_emerge->water_level);
params.writeLines(os);
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;
}
#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"
class IGameDef;
class IRollbackReportSink;
-namespace mapgen{
- struct BlockMakeData;
-};
/*
MapEditEvent
/*
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
/*
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.
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);
u64 getSeed(){ return m_seed; }
+ EmergeManager *m_emerge;
private:
// Seed used for all kinds of randomness in generation
u64 m_seed;
#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"
#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
{
}
#endif
+
#if 0
static void make_papyrus(VoxelManipulator &vmanip, v3s16 p0,
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++)
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++)
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++)
if(partcount >= partlength)
{
partcount = 0;
-
+
dir = random_turn(random, dir);
-
+
partlength = random.range(1,length);
make_stairs = 0;
{
m_dir = dir;
}
-
+
bool findPlaceForDoor(v3s16 &result_place, v3s16 &result_dir)
{
for(u32 i=0; i<100; i++)
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++)
v3s16 areasize = vmanip.m_area.getExtent();
v3s16 roomsize;
v3s16 roomplace;
-
+
/*
Find place for first room
*/
// 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)
// Quit if last room
if(i == room_count-1)
break;
-
+
// Determine walker start position
bool start_in_last_room = (random.range(0,2)!=0);
// 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;
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);
else
// Don't actually make a door
roomplace -= doordir;
-
+
}
}
#endif
}
}
}
-
+
// This is more like the actual ground level
level += dec[i-1]/2;
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
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;
};
// 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;*/
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;
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;
Create a block-specific seed
*/
u32 blockseed = get_blockseed(data->seed, full_node_min);
-
+
/*
Cache some ground type values for speed
*/
{
#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
*/
// 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);
// 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;
}
}
#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;
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
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;
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);
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)
);
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);
}
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)
{
(float)(ps.next()%(maxlen.Z*1))-(float)maxlen.Z/2
);
}
-
+
/*if(large_cave){
v3f p = orp + vec;
s16 h = find_ground_level_clever(vmanip,
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 &&
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
orp = rp;
}
-
+
}
}//timer1
#endif
-
+
#if 1
{
// 15ms @cs=8
/*
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;
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);
{
if(mudcount >= mud_add_amount)
break;
-
+
MapNode &n = vmanip.m_data[i];
n = addnode;
mudcount++;
/*
Flow mud away from steep edges
*/
-
+
// Iterate a few times
for(s16 k=0; k<3; k++)
{
// 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;
n->getContent() == c_dirt_with_grass ||
n->getContent() == c_gravel)
break;
-
+
vmanip.m_area.add_y(em, i, -1);
}
{
// Make it exactly mud
n->setContent(c_dirt);
-
+
/*
Don't flow it if the stuff under it is not mud
*/
}
// Drop mud on side
-
+
for(u32 di=0; di<4; di++)
{
v3s16 dirp = dirs4[di];
// 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) {
}
}
}
-
+
}
}//timer1
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);
}
{
// Node position in 2d
v2s16 p2d = v2s16(x,z);
-
+
/*
Find the lowest surface to which enough light ends up
to make grass grow.
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){
else
vmanip.m_data[i] = n_stone;
}
-
+
vmanip->m_area.add_y(em, i, 1);
}
}
/*
Add dungeons
*/
-
+
//if(node_min.Y < approx_groundlevel)
//if(myrand() % 3 == 0)
//if(myrand() % 3 == 0 && node_min.Y < approx_groundlevel)
// 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++)
}
}
}
-
+
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++)
make_nc(vmanip, ncrandom, ndef);
}
}
-
+
/*
Add top and bottom side of water to transforming_liquid queue
*/
if(current_depth == 0 && y <= WATER_LEVEL+2
&& possibly_have_sand)
have_sand = true;
-
+
if(current_depth < 4)
{
if(have_sand)
/*
Calculate some stuff
*/
-
+
float surface_humidity = surface_humidity_2d(data->seed, p2d_center);
bool is_jungle = surface_humidity > 0.75;
// Amount of trees
/*
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
/*
Add larger stones
*/
-
+
u32 large_stone_count = gen_area_nodes *
largestone_amount_2d(data->seed, p2d_center);
//u32 large_stone_count = 1;
if(mineralrandom.next()%8 == 0)
vmanip.m_data[vi] = MapNode(c_mese);
}
-
+
}
}
/*
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,
}
}
+#endif ///BIG COMMENT
+
BlockMakeData::BlockMakeData():
no_op(false),
vmanip(NULL),
delete vmanip;
}
-}; // namespace mapgen
+//}; // namespace mapgen
#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
// 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);
};
}; // namespace mapgen
-
+*/
#endif
/*
TileDef
*/
-
+
void TileDef::serialize(std::ostream &os) const
{
writeU8(os, 0); // version
has_after_destruct = false;
/*
Actual data
-
+
NOTE: Most of this is always overridden by the default values given
in builtin.lua
*/
ContentFeatures &f = m_content_features[i];
f.reset(); // Reset to defaults
}
-
+
// Set CONTENT_AIR
{
ContentFeatures f;
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++)
#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);
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)
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;
+}
#define NOISE_HEADER
#include "debug.h"
+#include "irr_v3d.h"
class PseudoRandom
{
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
private:
int seed;
int octaves;
- double persistence;
- double scale;
+ float persistence;
+ float scale;
static const char className[];
static const luaL_reg methods[];
}
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),
{
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);
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;
#include "itemdef.h"
#include "craftdef.h"
#include "mapgen.h"
+#include "biome.h"
#include "content_mapnode.h"
#include "content_nodemeta.h"
#include "content_abm.h"
*m_flag = false;
}
}
-
+
private:
bool *m_flag;
};
*m_ignorevariable = VoxelArea();
}
}
-
+
private:
VoxelArea *m_ignorevariable;
};
//TimeTaker timer("AsyncRunStep()");
m_server->AsyncRunStep();
}
-
+
//infostream<<"Running m_server->Receive()"<<std::endl;
m_server->Receive();
}
m_server->setAsyncFatalError(e.what());
}
}
-
+
END_DEBUG_EXCEPTION_HANDLER(errorstream)
return NULL;
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.
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;
/*
*/
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.
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;
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())
block = map.loadBlock(p);
}
-
+
// If could not load and allowed to generate, start generation
// inside this same envlock
if(only_from_disk == false &&
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);
// 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)
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
{
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;
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);
{
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
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;
}
//TimeTaker timer("RemoteClient::GetNextBlocks");
-
+
v3f playerpos = player->getPosition();
v3f playerspeed = player->getSpeed();
v3f playerspeeddir(0,0,0);
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);
/*
Get the starting value of the block finder radius.
*/
-
+
if(m_last_center != center)
{
m_nearest_unsent_d = 0;
/*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)
{
/*
Check the time from last addNode/removeNode.
-
+
Decrease send rate if player is building stuff.
*/
m_time_from_building += 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.
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),
*/
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
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;
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
*/
|| 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)
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);
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)
{
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;
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();
if(nearest_emergefull_d == -1)
nearest_emergefull_d = d;
}
-
+
// get next one.
continue;
}
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){
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)
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++)
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()),
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();
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;
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);
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);
*/
{
JMutexAutoLock conlock(m_con_mutex);
-
+
std::wstring line = L"*** Server shutting down";
/*
infostream<<"Server: Saving environment metadata"<<std::endl;
m_env->saveMeta(m_path_world);
}
-
+
/*
Stop threads
*/
stop();
-
+
/*
Delete clients
*/
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);
// Stop thread if already running
m_thread.stop();
-
+
// Initialize connection
m_con.SetTimeoutMs(30);
m_con.Serve(port);
// Start thread
m_thread.setRun(true);
m_thread.Start();
-
+
// ASCII art for the win!
actionstream
<<" .__ __ __ "<<std::endl
void Server::stop()
{
DSTACK(__FUNCTION_NAME);
-
+
infostream<<"Server: Stopping and waiting threads"<<std::endl;
// Stop threads (set run=false first so both start stopping)
m_emergethread.setRun(false);
m_thread.stop();
m_emergethread.stop();
-
+
infostream<<"Server: Threads stopped"<<std::endl;
}
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;
{
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
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))
{
m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
g_settings->getFloat("server_unload_unused_data_timeout"));
}
-
+
/*
Do background stuff
*/
}
}
}
-
+
/* 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();
/*
Set the modified blocks unsent for all the clients
*/
-
+
JMutexAutoLock lock2(m_con_mutex);
for(core::map<u16, RemoteClient*>::Iterator
i.atEnd() == false; i++)
{
RemoteClient *client = i.getNode()->getValue();
-
+
if(modified_blocks.size() > 0)
{
// Remove block from sent history
counter = 0.0;
JMutexAutoLock lock2(m_con_mutex);
-
+
if(m_clients.size() != 0)
infostream<<"Players:"<<std::endl;
for(core::map<u16, RemoteClient*>::Iterator
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);
// 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());
// Get object
u16 id = i.getNode()->getKey();
ServerActiveObject* obj = m_env->getActiveObject(id);
-
+
// Get object type
u8 type = ACTIVEOBJECT_TYPE_INVALID;
if(obj == NULL)
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)));
all_known_objects[id] = true;
}
}
-
+
m_env->setKnownActiveObjects(whatever);
#endif
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);
}
message_list->push_back(aom);
}
-
+
// Route data to every client
for(core::map<u16, RemoteClient*>::Iterator
i = m_clients.getIterator();
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.
infostream<<"WARNING: Server: Unknown MapEditEvent "
<<((u32)event->type)<<std::endl;
}
-
+
/*
Set blocks not sent to far players
*/
verbosestream<<"Server: MapEditEvents:"<<std::endl;
prof.print(verbosestream);
}
-
+
}
/*
if(counter >= 2.0)
{
counter = 0.0;
-
+
m_emergethread.trigger();
// Update m_enable_rollback_recording here too
//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);
}
catch(con::PeerNotFoundException &e)
{
//NOTE: This is not needed anymore
-
+
// The peer has been disconnected.
// Find the associated player and remove it.
// 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();
<<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;
return;
ToServerCommand command = (ToServerCommand)readU16(&data[0]);
-
+
if(command == TOSERVER_INIT)
{
// [0] u16 TOSERVER_INIT
//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 "
);
return;
}
-
+
/*
Read and check network protocol version
*/
);
return;
}
-
+
if(g_settings->getBool("strict_protocol_version_checking"))
{
if(net_proto_version != LATEST_PROTOCOL_VERSION)
/*
Set up player
*/
-
+
// Get player name
char playername[PLAYERNAME_SIZE];
for(u32 i=0; i<PLAYERNAME_SIZE-1; i++)
playername[i] = data[3+i];
}
playername[PLAYERNAME_SIZE-1] = 0;
-
+
if(playername[0]=='\0')
{
actionstream<<"Server: Player with an empty name "
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() &&
scriptapi_create_auth(m_lua, playername, initial_password);
}
-
+
has_auth = scriptapi_get_auth(m_lua, playername, &checkpwd, NULL);
if(!has_auth){
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") &&
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);
}
// 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);
// 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));
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;
BroadcastChatMessage(message);
}
}
-
+
// Warnings about protocol version can be issued here
if(getClient(peer_id)->net_proto_version < LATEST_PROTOCOL_VERSION)
{
" Skipping incoming command="<<command<<std::endl;
return;
}
-
+
Player *player = m_env->getPlayer(peer_id);
if(player == NULL){
infostream<<"Server::ProcessData(): Cancelling: "
{
if(datasize < 2+12+12+4+4)
return;
-
+
u32 start = 0;
v3s32 ps = readV3S32(&data[start+2]);
v3s32 ss = readV3S32(&data[start+2+12]);
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;*/
{
if(datasize < 2+1)
return;
-
+
/*
[0] u16 command
[2] u8 count
{
if(datasize < 2+1)
return;
-
+
/*
[0] u16 command
[2] u8 count
return;
}
}
-
+
// Do the action
a->apply(this, playersao, this);
// Eat the action
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++)
{
// 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'/')
send_to_sender = true;
}
}
-
+
if(line != L"")
{
if(send_to_others)
{
if(player->hp != 0 || !g_settings->getBool("enable_damage"))
return;
-
+
RespawnPlayer(peer_id);
-
+
actionstream<<player->getName()<<" respawns at "
<<PP(player->getPosition()/BS)<<std::endl;
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);
}
}
} // action == 2
-
+
/*
3: place block or right-click object
*/
// 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 != ""){
{
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);
{
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;
infostream<<"Server::ProcessData(): Ignoring "
"unknown command "<<command<<std::endl;
}
-
+
} //try
catch(SendFailedException &e)
{
MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
if(block)
block->raiseModified(MOD_STATE_WRITE_NEEDED);
-
+
setBlockNotSent(blockpos);
}
break;
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++)
DSTACK(__FUNCTION_NAME);
verbosestream<<"Server::peerAdded(): peer->id="
<<peer->id<<std::endl;
-
+
PeerChange c;
c.type = PEER_ADDED;
c.peer_id = peer->id;
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;
void Server::SendInventory(u16 peer_id)
{
DSTACK(__FUNCTION_NAME);
-
+
PlayerSAO *playersao = getPlayerSAO(peer_id);
assert(playersao);
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);
}
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++)
{
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());
writeV3F1000(os, player->getPosition());
writeF1000(os, player->getPitch());
writeF1000(os, player->getYaw());
-
+
{
v3f pos = player->getPosition();
f32 pitch = player->getPitch();
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());
// Don't send if it's the same one
if(client->peer_id == ignore_id)
continue;
-
+
if(far_players)
{
// Get player
DSTACK(__FUNCTION_NAME);
v3s16 p = block->getPos();
-
+
#if 0
// Analyze it a bit
bool completely_air = true;
/*
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();
/*infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
<<": \tpacket size: "<<replysize<<std::endl;*/
-
+
/*
Send packet
*/
core::array<PrioritySortedBlockTransfer> queue;
s32 total_sending = 0;
-
+
{
ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
continue;
total_sending += client->SendingCount();
-
+
if(client->serialization_version == SER_FMT_VER_INVALID)
continue;
-
+
client->GetNextBlocks(this, dtime, queue);
}
}
if(total_sending >= g_settings->getS32
("max_simultaneous_block_sends_server_total"))
break;
-
+
PrioritySortedBlockTransfer q = queue[i];
MapBlock *block = NULL;
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();
}
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++)
string sha1_digest
}
*/
-
+
writeU16(os, TOCLIENT_ANNOUNCE_MEDIA);
writeU16(os, file_announcements.size());
void Server::DiePlayer(u16 peer_id)
{
DSTACK(__FUNCTION_NAME);
-
+
PlayerSAO *playersao = getPlayerSAO(peer_id);
assert(playersao);
void Server::UpdateCrafting(u16 peer_id)
{
DSTACK(__FUNCTION_NAME);
-
+
Player* player = m_env->getPlayer(peer_id);
assert(player);
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.");
int num_tried = 0;
int num_failed = 0;
-
+
for(std::list<RollbackAction>::const_iterator
i = actions.begin();
i != actions.end(); i++)
log->push_back(os.str());
}
}
-
+
infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
<<" failed"<<std::endl;
//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++)
//infostream<<"-> Underwater"<<std::endl;
continue;
}
-
+
nodepos = v3s16(nodepos2d.X, groundheight-2, nodepos2d.Y);
bool is_good = false;
s32 air_count = 0;
}
}
#endif
-
+
return intToFloat(nodepos, BS);
}
{
JMutexAutoLock envlock(m_env_mutex);
JMutexAutoLock conlock(m_con_mutex);
-
+
if(c.type == PEER_ADDED)
{
/*
n = m_clients.find(c.peer_id);
// The client should exist
assert(n != NULL);
-
+
/*
Mark objects to be not known by the client
*/
// 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--;
}
message += L" (timed out)";
}
}
-
+
/* Run scripts and remove from environment */
{
if(player != NULL)
<<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
{
void dedicated_server_loop(Server &server, bool &kill)
{
DSTACK(__FUNCTION_NAME);
-
+
verbosestream<<"dedicated_server_loop()"<<std::endl;
IntervalLimiter m_profiler_interval;
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;
set(name, "false");
}
- void setS32(std::string name, s32 value)
- {
- set(name, itos(value));
- }
+
void setFloat(std::string name, float value)
{
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;
}
#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)
{
MaxEdge(p)
{
}
-
+
/*
Modifying methods
*/
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;
}
assert(contains(a));
-
+
// Take back area, XY inclusive
{
v3s16 min(MinEdge.X, MinEdge.Y, a.MaxEdge.Z+1);
}
}
-
+
/*
Translates position from virtual coordinates to array index
*/
{
return index(p.X, p.Y, p.Z);
}
-
+
// Translate index in the X coordinate
void add_x(const v3s16 &extent, u32 &i, s16 a)
{
public:
VoxelManipulator();
virtual ~VoxelManipulator();
-
+
/*
Virtuals from NodeContainer
*/
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;
//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.
void print(std::ostream &o, INodeDefManager *nodemgr,
VoxelPrintMode mode=VOXELPRINT_MATERIAL);
-
+
void addArea(VoxelArea area);
/*
*/
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);
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
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]
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;
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++)
{
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)