aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/CMakeLists.txt2
-rw-r--r--src/biome.cpp267
-rw-r--r--src/biome.h75
-rw-r--r--src/camera.cpp2
-rw-r--r--src/chat.cpp8
-rw-r--r--src/chat.h2
-rw-r--r--src/client.cpp13
-rw-r--r--src/client.h2
-rw-r--r--src/clientserver.h4
-rw-r--r--src/collision.cpp7
-rw-r--r--src/content_cao.cpp24
-rw-r--r--src/content_sao.cpp17
-rw-r--r--src/content_sao.h9
-rw-r--r--src/defaultsettings.cpp11
-rw-r--r--src/emerge.cpp16
-rw-r--r--src/emerge.h23
-rw-r--r--src/environment.cpp25
-rw-r--r--src/environment.h11
-rw-r--r--src/game.cpp2
-rw-r--r--src/genericobject.cpp12
-rw-r--r--src/genericobject.h3
-rw-r--r--src/guiChatConsole.cpp2
-rw-r--r--src/guiMainMenu.cpp9
-rw-r--r--src/localplayer.cpp35
-rw-r--r--src/localplayer.h4
-rw-r--r--src/map.cpp24
-rw-r--r--src/mapgen.cpp36
-rw-r--r--src/mapgen_indev.cpp4
-rw-r--r--src/mapgen_singlenode.cpp3
-rw-r--r--src/mapgen_v6.cpp3
-rw-r--r--src/mapgen_v7.cpp490
-rw-r--r--src/mapgen_v7.h125
-rw-r--r--src/nodedef.cpp2
-rw-r--r--src/noise.cpp36
-rw-r--r--src/noise.h2
-rw-r--r--src/pathfinder.cpp1081
-rw-r--r--src/pathfinder.h345
-rw-r--r--src/player.cpp5
-rw-r--r--src/player.h4
-rw-r--r--src/scriptapi.cpp76
-rw-r--r--src/scriptapi_env.cpp66
-rw-r--r--src/scriptapi_env.h6
-rw-r--r--src/scriptapi_object.cpp23
-rw-r--r--src/scriptapi_object.h3
-rw-r--r--src/server.cpp9
-rw-r--r--src/server.h8
-rw-r--r--src/serverobject.h2
-rw-r--r--src/tile.cpp5
48 files changed, 2582 insertions, 361 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index d6182861f..9bef3289e 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -227,6 +227,7 @@ set(common_SRCS
emerge.cpp
mapgen.cpp
mapgen_v6.cpp
+ mapgen_v7.cpp
mapgen_indev.cpp
mapgen_singlenode.cpp
treegen.cpp
@@ -264,6 +265,7 @@ set(common_SRCS
clientserver.cpp
staticobject.cpp
serverlist.cpp
+ pathfinder.cpp
util/serialize.cpp
util/directiontables.cpp
util/numeric.cpp
diff --git a/src/biome.cpp b/src/biome.cpp
index 86af75310..b50c562a0 100644
--- a/src/biome.cpp
+++ b/src/biome.cpp
@@ -1,6 +1,6 @@
/*
Minetest
-Copyright (C) 2010-2013 kwolekr, Ryan Kwolek <kwolekr2@cs.scranton.edu>
+Copyright (C) 2010-2013 kwolekr, Ryan Kwolek <kwolekr@minetest.net>
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
@@ -23,68 +23,50 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "log.h"
#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
+NoiseParams nparams_biome_def_heat =
+ {50, 50, v3f(500.0, 500.0, 500.0), 5349, 3, 0.70};
+NoiseParams nparams_biome_def_humidity =
+ {50, 50, v3f(500.0, 500.0, 500.0), 842, 3, 0.55};
-#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.
+BiomeDefManager::BiomeDefManager() {
+ biome_registration_finished = false;
+ np_heat = &nparams_biome_def_heat;
+ np_humidity = &nparams_biome_def_humidity;
+ // Create default biome to be used in case none exist
+ Biome *b = new Biome;
+
+ b->id = 0;
+ b->name = "Default";
+ b->flags = 0;
-/*float bg1_temps[] = {0.0};
-int bg1_biomes[] = {BT_OCEAN};
+ b->c_top = CONTENT_AIR;
+ b->top_depth = 0;
+ b->c_filler = b->c_top;
+ b->filler_height = MAP_GENERATION_LIMIT;
-float bg2_temps[] = {10.0};
-int bg2_biomes[] = {BT_GBEACH, BT_SBEACH};
+ b->height_min = -MAP_GENERATION_LIMIT;
+ b->height_max = MAP_GENERATION_LIMIT;
+ b->heat_point = 0.0;
+ b->humidity_point = 0.0;
-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};*/
-
-NoiseParams np_default = {20.0, 15.0, v3f(250., 250., 250.), 82341, 5, 0.6};
-
-
-BiomeDefManager::BiomeDefManager(IGameDef *gamedef) {
- this->m_gamedef = gamedef;
- this->ndef = gamedef->ndef();
-
- //the initial biome group
- bgroups.push_back(new std::vector<Biome *>);
+ biomes.push_back(b);
}
BiomeDefManager::~BiomeDefManager() {
- for (unsigned int i = 0; i != bgroups.size(); i++)
- delete bgroups[i];
+ //if (biomecache)
+ // delete[] biomecache;
+
+ for (size_t i = 0; i != biomes.size(); i++)
+ delete biomes[i];
}
Biome *BiomeDefManager::createBiome(BiomeTerrainType btt) {
- switch (btt) {
+ /*switch (btt) {
case BIOME_TERRAIN_NORMAL:
return new Biome;
case BIOME_TERRAIN_LIQUID:
@@ -92,142 +74,97 @@ Biome *BiomeDefManager::createBiome(BiomeTerrainType btt) {
case BIOME_TERRAIN_NETHER:
return new BiomeHell;
case BIOME_TERRAIN_AETHER:
- return new BiomeAether;
+ return new BiomeSky;
case BIOME_TERRAIN_FLAT:
return new BiomeSuperflat;
}
- return NULL;
-}
-
-
-void BiomeDefManager::addBiomeGroup(float freq) {
- int size = bgroup_freqs.size();
- float newfreq = freq;
-
- if (size)
- newfreq += bgroup_freqs[size - 1];
- bgroup_freqs.push_back(newfreq);
- bgroups.push_back(new std::vector<Biome *>);
-
- verbosestream << "BiomeDefManager: added biome group with frequency " <<
- newfreq << std::endl;
+ return NULL;*/
+ return new Biome;
}
-void BiomeDefManager::addBiome(Biome *b) {
- std::vector<Biome *> *bgroup;
-
- if ((unsigned int)b->groupid >= bgroups.size()) {
- errorstream << "BiomeDefManager: attempted to add biome '" << b->name
- << "' to nonexistent biome group " << b->groupid << std::endl;
- return;
+// just a PoC, obviously needs optimization later on (precalculate this)
+void BiomeDefManager::calcBiomes(BiomeNoiseInput *input, u8 *biomeid_map) {
+ int i = 0;
+ for (int y = 0; y != input->mapsize.Y; y++) {
+ for (int x = 0; x != input->mapsize.X; x++, i++) {
+ float heat = (input->heat_map[i] + 1) * 50;
+ float humidity = (input->humidity_map[i] + 1) * 50;
+ biomeid_map[i] = getBiome(heat, humidity, input->height_map[i])->id;
+ }
}
-
- bgroup = bgroups[b->groupid];
- bgroup->push_back(b);
-
- verbosestream << "BiomeDefManager: added biome '" << b->name <<
- "' to biome group " << (int)b->groupid << std::endl;
}
-void BiomeDefManager::addDefaultBiomes() {
+void BiomeDefManager::resolveNodeNames(INodeDefManager *ndef) {
Biome *b;
-
- 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 = &np_default;
- biome_default = b;
-}
-
-
-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) && (bgfreq > bgroup_freqs[i]); i++);
- bgroup = bgroups[i];
-
- int nbiomes = bgroup->size();
- for (i = 0; i != nbiomes; i++) {
- b = bgroup->operator[](i);
- if (heat >= b->heat_min && heat <= b->heat_max &&
- humidity >= b->humidity_min && humidity <= b->humidity_max)
- return b;
+
+ biome_registration_finished = true;
+
+ for (size_t i = 0; i != biomes.size(); i++) {
+ b = biomes[i];
+
+ if (b->c_top == CONTENT_IGNORE) {
+ b->c_top = ndef->getId(b->top_nodename);
+ if (b->c_top == CONTENT_IGNORE) {
+ errorstream << "BiomeDefManager::resolveNodeNames: node '"
+ << b->top_nodename << "' not defined" << std::endl;
+ b->c_top = CONTENT_AIR;
+ b->top_depth = 0;
+ }
+ }
+
+ if (b->c_filler == CONTENT_IGNORE) {
+ b->c_filler = ndef->getId(b->filler_nodename);
+ if (b->c_filler == CONTENT_IGNORE) {
+ errorstream << "BiomeDefManager::resolveNodeNames: node '"
+ << b->filler_nodename << "' not defined" << std::endl;
+ b->c_filler = CONTENT_AIR;
+ b->filler_height = MAP_GENERATION_LIMIT;
+ }
+ }
}
-
- return biome_default;
-}
-
-
-//////////////////////////// [ Generic biome ] ////////////////////////////////
-
-
-int Biome::getSurfaceHeight(float noise_terrain) {
- return np->offset + np->scale * noise_terrain;
-}
-
-
-void Biome::genColumn(Mapgen *mapgen, int x, int z, int y1, int y2) {
-
}
-///////////////////////////// [ Ocean biome ] /////////////////////////////////
-
-
-void BiomeLiquid::genColumn(Mapgen *mapgen, int x, int z, int y1, int y2) {
-
-}
-
-
-///////////////////////////// [ Nether biome ] /////////////////////////////////
-
-
-int BiomeHell::getSurfaceHeight(float noise_terrain) {
- return np->offset + np->scale * noise_terrain;
-}
-
-
-void BiomeHell::genColumn(Mapgen *mapgen, int x, int z, int y1, int y2) {
-
-}
-
-
-///////////////////////////// [ Aether biome ] ////////////////////////////////
-
-
-int BiomeAether::getSurfaceHeight(float noise_terrain) {
- return np->offset + np->scale * noise_terrain;
-}
-
-
-void BiomeAether::genColumn(Mapgen *mapgen, int x, int z, int y1, int y2) {
+void BiomeDefManager::addBiome(Biome *b) {
+ if (biome_registration_finished) {
+ errorstream << "BIomeDefManager: biome registration already finished, dropping " << b->name <<std::endl;
+ delete b;
+ return;
+ }
+
+ size_t nbiomes = biomes.size();
+ if (nbiomes >= 0xFF) {
+ errorstream << "BiomeDefManager: too many biomes, dropping " << b->name << std::endl;
+ delete b;
+ return;
+ }
+ b->id = (u8)nbiomes;
+ biomes.push_back(b);
+ verbosestream << "BiomeDefManager: added biome " << b->name << std::endl;
}
-/////////////////////////// [ Superflat biome ] ///////////////////////////////
+Biome *BiomeDefManager::getBiome(float heat, float humidity, s16 y) {
+ Biome *b, *biome_closest = NULL;
+ float dist_min = FLT_MAX;
+ for (size_t i = 1; i < biomes.size(); i++) {
+ b = biomes[i];
+ if (y > b->height_max || y < b->height_min)
+ continue;
-int BiomeSuperflat::getSurfaceHeight(float noise_terrain) {
- return ntopnodes;
-}
-
-
-void BiomeSuperflat::genColumn(Mapgen *mapgen, int x, int z, int y1, int y2) {
-
+ float d_heat = heat - b->heat_point;
+ float d_humidity = humidity - b->humidity_point;
+ float dist = (d_heat * d_heat) +
+ (d_humidity * d_humidity);
+ if (dist < dist_min) {
+ dist_min = dist;
+ biome_closest = b;
+ }
+ }
+
+ return biome_closest ? biome_closest : biomes[0];
}
diff --git a/src/biome.h b/src/biome.h
index c30af46ad..17703db5a 100644
--- a/src/biome.h
+++ b/src/biome.h
@@ -1,6 +1,6 @@
/*
Minetest
-Copyright (C) 2010-2013 kwolekr, Ryan Kwolek <kwolekr2@cs.scranton.edu>
+Copyright (C) 2010-2013 kwolekr, Ryan Kwolek <kwolekr@minetest.net>
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
@@ -27,7 +27,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "noise.h"
#include "mapgen.h"
-
enum BiomeTerrainType
{
BIOME_TERRAIN_NORMAL,
@@ -37,62 +36,54 @@ enum BiomeTerrainType
BIOME_TERRAIN_FLAT
};
+extern NoiseParams nparams_biome_def_heat;
+extern NoiseParams nparams_biome_def_humidity;
+
class Biome {
public:
- MapNode n_top;
- MapNode n_filler;
- s16 ntopnodes;
- s8 groupid;
- s8 flags;
- s16 height_min;
- s16 height_max;
- float heat_min;
- float heat_max;
- float humidity_min;
- float humidity_max;
+ u8 id;
std::string name;
- NoiseParams *np;
+ u32 flags;
+
+ std::string top_nodename;
+ std::string filler_nodename;
- virtual void genColumn(Mapgen *mg, int x, int z, int y1, int y2);
- virtual int getSurfaceHeight(float noise_terrain);
-};
-
-class BiomeLiquid : public Biome {
- virtual void genColumn(Mapgen *mg, int x, int z, int y1, int y2);
-};
+ content_t c_top;
+ s16 top_depth;
-class BiomeHell : public Biome {
- virtual void genColumn(Mapgen *mg, int x, int z, int y1, int y2);
- virtual int getSurfaceHeight(float noise_terrain);
-};
-
-class BiomeAether : public Biome {
- virtual void genColumn(Mapgen *mg, int x, int z, int y1, int y2);
- virtual int getSurfaceHeight(float noise_terrain);
+ content_t c_filler;
+ s16 filler_height;
+
+ s16 height_min;
+ s16 height_max;
+ float heat_point;
+ float humidity_point;
};
-class BiomeSuperflat : public Biome {
- virtual void genColumn(Mapgen *mg, int x, int z, int y1, int y2);
- virtual int getSurfaceHeight(float noise_terrain);
+struct BiomeNoiseInput {
+ v2s16 mapsize;
+ float *heat_map;
+ float *humidity_map;
+ s16 *height_map;
};
class BiomeDefManager {
public:
- std::vector<float> bgroup_freqs;
- std::vector<std::vector<Biome *> *> bgroups;
- Biome *biome_default;
- IGameDef *m_gamedef;
- INodeDefManager *ndef;
+ std::vector<Biome *> biomes;
- BiomeDefManager(IGameDef *gamedef);
- ~BiomeDefManager();
+ bool biome_registration_finished;
+ NoiseParams *np_heat;
+ NoiseParams *np_humidity;
+ BiomeDefManager();
+ ~BiomeDefManager();
+
Biome *createBiome(BiomeTerrainType btt);
- Biome *getBiome(float bgfreq, float heat, float humidity);
+ void calcBiomes(BiomeNoiseInput *input, u8 *biomeid_map);
+ Biome *getBiome(float heat, float humidity, s16 y);
- void addBiomeGroup(float freq);
void addBiome(Biome *b);
- void addDefaultBiomes();
+ void resolveNodeNames(INodeDefManager *ndef);
};
#endif
diff --git a/src/camera.cpp b/src/camera.cpp
index b1e588415..138b022c0 100644
--- a/src/camera.cpp
+++ b/src/camera.cpp
@@ -218,6 +218,8 @@ void Camera::update(LocalPlayer* player, f32 frametime, v2u32 screensize,
// Smooth the movement when walking up stairs
v3f old_player_position = m_playernode->getPosition();
v3f player_position = player->getPosition();
+ if (player->isAttached && player->parent)
+ player_position = player->parent->getPosition();
//if(player->touching_ground && player_position.Y > old_player_position.Y)
if(player->touching_ground &&
player_position.Y > old_player_position.Y)
diff --git a/src/chat.cpp b/src/chat.cpp
index 1135ccdf7..3102e194a 100644
--- a/src/chat.cpp
+++ b/src/chat.cpp
@@ -464,7 +464,7 @@ void ChatPrompt::historyNext()
}
}
-void ChatPrompt::nickCompletion(const std::list<std::wstring>& names, bool backwards)
+void ChatPrompt::nickCompletion(const std::list<std::string>& names, bool backwards)
{
// Two cases:
// (a) m_nick_completion_start == m_nick_completion_end == 0
@@ -493,13 +493,13 @@ void ChatPrompt::nickCompletion(const std::list<std::wstring>& names, bool backw
// find all names that start with the selected prefix
std::vector<std::wstring> completions;
- for (std::list<std::wstring>::const_iterator
+ for (std::list<std::string>::const_iterator
i = names.begin();
i != names.end(); ++i)
{
- if (str_starts_with(*i, prefix, true))
+ if (str_starts_with(narrow_to_wide(*i), prefix, true))
{
- std::wstring completion = *i;
+ std::wstring completion = narrow_to_wide(*i);
if (prefix_start == 0)
completion += L":";
completions.push_back(completion);
diff --git a/src/chat.h b/src/chat.h
index 8a40c7ccf..19b48456e 100644
--- a/src/chat.h
+++ b/src/chat.h
@@ -160,7 +160,7 @@ public:
void historyNext();
// Nick completion
- void nickCompletion(const std::list<std::wstring>& names, bool backwards);
+ void nickCompletion(const std::list<std::string>& names, bool backwards);
// Update console size and reformat the visible portion of the prompt
void reformat(u32 cols);
diff --git a/src/client.cpp b/src/client.cpp
index f27f95d98..1d5f8f472 100644
--- a/src/client.cpp
+++ b/src/client.cpp
@@ -2501,18 +2501,9 @@ void Client::printDebugInfo(std::ostream &os)
<<std::endl;*/
}
-std::list<std::wstring> Client::getConnectedPlayerNames()
+std::list<std::string> Client::getConnectedPlayerNames()
{
- std::list<Player*> players = m_env.getPlayers(true);
- std::list<std::wstring> playerNames;
- for(std::list<Player*>::iterator
- i = players.begin();
- i != players.end(); ++i)
- {
- Player *player = *i;
- playerNames.push_back(narrow_to_wide(player->getName()));
- }
- return playerNames;
+ return m_env.getPlayerNames();
}
float Client::getAnimationTime()
diff --git a/src/client.h b/src/client.h
index d476a1d51..16cdc237f 100644
--- a/src/client.h
+++ b/src/client.h
@@ -315,7 +315,7 @@ public:
// Prints a line or two of info
void printDebugInfo(std::ostream &os);
- std::list<std::wstring> getConnectedPlayerNames();
+ std::list<std::string> getConnectedPlayerNames();
float getAnimationTime();
diff --git a/src/clientserver.h b/src/clientserver.h
index 28b579971..8b1e0a7e4 100644
--- a/src/clientserver.h
+++ b/src/clientserver.h
@@ -88,9 +88,11 @@ SharedBuffer<u8> makePacket_TOCLIENT_TIME_OF_DAY(u16 time, float time_speed);
PROTOCOL_VERSION 18:
damageGroups added to ToolCapabilities
sound_place added to ItemDefinition
+ PROTOCOL_VERSION 19:
+ GENERIC_CMD_SET_PHYSICS_OVERRIDE
*/
-#define LATEST_PROTOCOL_VERSION 18
+#define LATEST_PROTOCOL_VERSION 19
// Server's supported network protocol range
#define SERVER_PROTOCOL_VERSION_MIN 13
diff --git a/src/collision.cpp b/src/collision.cpp
index 806a3b720..cd170196f 100644
--- a/src/collision.cpp
+++ b/src/collision.cpp
@@ -209,10 +209,15 @@ collisionMoveResult collisionMoveSimple(Environment *env, IGameDef *gamedef,
}
speed_f += accel_f * dtime;
- // If there is no speed, there are no collisions
+ // If there is no speed, there are no collisions
if(speed_f.getLength() == 0)
return result;
+ // Limit speed for avoiding hangs
+ speed_f.Y=rangelim(speed_f.Y,-5000,5000);
+ speed_f.X=rangelim(speed_f.X,-5000,5000);
+ speed_f.Z=rangelim(speed_f.Z,-5000,5000);
+
/*
Collect node boxes in movement range
*/
diff --git a/src/content_cao.cpp b/src/content_cao.cpp
index ee1009b6c..9738dc34c 100644
--- a/src/content_cao.cpp
+++ b/src/content_cao.cpp
@@ -708,11 +708,15 @@ public:
if(player && player->isLocal()){
m_is_local_player = true;
}
+ m_env->addPlayerName(m_name.c_str());
}
}
~GenericCAO()
{
+ if(m_is_player){
+ m_env->removePlayerName(m_name.c_str());
+ }
}
static ClientActiveObject* create(IGameDef *gamedef, ClientEnvironment *env)
@@ -860,7 +864,7 @@ public:
m_spritenode = smgr->addBillboardSceneNode(
NULL, v2f(1, 1), v3f(0,0,0), -1);
m_spritenode->setMaterialTexture(0,
- tsrc->getTextureRaw("unknown_block.png"));
+ tsrc->getTextureRaw("unknown_node.png"));
m_spritenode->setMaterialFlag(video::EMF_LIGHTING, false);
m_spritenode->setMaterialFlag(video::EMF_BILINEAR_FILTER, false);
m_spritenode->setMaterialType(video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF);
@@ -1129,6 +1133,7 @@ public:
{
LocalPlayer *player = m_env->getLocalPlayer();
player->overridePosition = getParent()->getPosition();
+ m_env->getLocalPlayer()->parent = getParent();
}
}
else
@@ -1263,7 +1268,7 @@ public:
{
if(m_prop.visual == "sprite")
{
- std::string texturestring = "unknown_block.png";
+ std::string texturestring = "unknown_node.png";
if(m_prop.textures.size() >= 1)
texturestring = m_prop.textures[0];
texturestring += mod;
@@ -1329,7 +1334,7 @@ public:
{
for (u32 i = 0; i < 6; ++i)
{
- std::string texturestring = "unknown_block.png";
+ std::string texturestring = "unknown_node.png";
if(m_prop.textures.size() > i)
texturestring = m_prop.textures[i];
texturestring += mod;
@@ -1678,6 +1683,19 @@ public:
updateTexturePos();
}
+ else if(cmd == GENERIC_CMD_SET_PHYSICS_OVERRIDE)
+ {
+ float override_speed = readF1000(is);
+ float override_jump = readF1000(is);
+ float override_gravity = readF1000(is);
+ if(m_is_local_player)
+ {
+ LocalPlayer *player = m_env->getLocalPlayer();
+ player->physics_override_speed = override_speed;
+ player->physics_override_jump = override_jump;
+ player->physics_override_gravity = override_gravity;
+ }
+ }
else if(cmd == GENERIC_CMD_SET_ANIMATION)
{
m_animation_range = readV2F1000(is);
diff --git a/src/content_sao.cpp b/src/content_sao.cpp
index ae08b4260..e6c8c725c 100644
--- a/src/content_sao.cpp
+++ b/src/content_sao.cpp
@@ -935,7 +935,11 @@ PlayerSAO::PlayerSAO(ServerEnvironment *env_, Player *player_, u16 peer_id_,
m_moved(false),
m_inventory_not_sent(false),
m_hp_not_sent(false),
- m_wielded_item_not_sent(false)
+ m_wielded_item_not_sent(false),
+ m_physics_override_speed(1),
+ m_physics_override_jump(1),
+ m_physics_override_gravity(1),
+ m_physics_override_sent(false)
{
assert(m_player);
assert(m_peer_id != 0);
@@ -1019,7 +1023,7 @@ std::string PlayerSAO::getClientInitializationData(u16 protocol_version)
writeF1000(os, m_player->getYaw());
writeS16(os, getHP());
- writeU8(os, 4 + m_bone_position.size()); // number of messages stuffed in here
+ writeU8(os, 5 + m_bone_position.size()); // number of messages stuffed in here
os<<serializeLongString(getPropertyPacket()); // message 1
os<<serializeLongString(gob_cmd_update_armor_groups(m_armor_groups)); // 2
os<<serializeLongString(gob_cmd_update_animation(m_animation_range, m_animation_speed, m_animation_blend)); // 3
@@ -1027,6 +1031,7 @@ std::string PlayerSAO::getClientInitializationData(u16 protocol_version)
os<<serializeLongString(gob_cmd_update_bone_position((*ii).first, (*ii).second.X, (*ii).second.Y)); // m_bone_position.size
}
os<<serializeLongString(gob_cmd_update_attachment(m_attachment_parent_id, m_attachment_bone, m_attachment_position, m_attachment_rotation)); // 4
+ os<<serializeLongString(gob_cmd_update_physics_override(m_physics_override_speed, m_physics_override_jump, m_physics_override_gravity)); // 5
}
else
{
@@ -1196,6 +1201,14 @@ void PlayerSAO::step(float dtime, bool send_recommended)
m_messages_out.push_back(aom);
}
+ if(m_physics_override_sent == false){
+ m_physics_override_sent = true;
+ std::string str = gob_cmd_update_physics_override(m_physics_override_speed, m_physics_override_jump, m_physics_override_gravity);
+ // create message and add to list
+ ActiveObjectMessage aom(getId(), true, str);
+ m_messages_out.push_back(aom);
+ }
+
if(m_animation_sent == false){
m_animation_sent = true;
std::string str = gob_cmd_update_animation(m_animation_range, m_animation_speed, m_animation_blend);
diff --git a/src/content_sao.h b/src/content_sao.h
index 60ca8f319..dca02bb00 100644
--- a/src/content_sao.h
+++ b/src/content_sao.h
@@ -101,7 +101,7 @@ private:
float m_last_sent_position_timer;
float m_last_sent_move_precision;
bool m_armor_groups_sent;
-
+
v2f m_animation_range;
float m_animation_speed;
float m_animation_blend;
@@ -257,8 +257,6 @@ private:
ItemGroupList m_armor_groups;
bool m_armor_groups_sent;
-
-
bool m_properties_sent;
struct ObjectProperties m_prop;
// Cached privileges for enforcement
@@ -285,6 +283,11 @@ public:
bool m_inventory_not_sent;
bool m_hp_not_sent;
bool m_wielded_item_not_sent;
+
+ float m_physics_override_speed;
+ float m_physics_override_jump;
+ float m_physics_override_gravity;
+ bool m_physics_override_sent;
};
#endif
diff --git a/src/defaultsettings.cpp b/src/defaultsettings.cpp
index 592c6bcca..9875c6ecb 100644
--- a/src/defaultsettings.cpp
+++ b/src/defaultsettings.cpp
@@ -231,10 +231,12 @@ void set_default_settings(Settings *settings)
settings->setDefault("mgv6_np_trees", "0, 1, (125, 125, 125), 2, 4, 0.66");
settings->setDefault("mgv6_np_apple_trees", "0, 1, (100, 100, 100), 342902, 3, 0.45");
- settings->setDefault("mgv7_np_terrain", "10, 12, (350, 350, 350), 82341, 5, 0.6");
- settings->setDefault("mgv7_np_bgroup", "0.5, 0.3125, (350, 350, 350), 5923, 2, 0.6");
- settings->setDefault("mgv7_np_heat", "25, 50, (500, 500, 500), 35293, 1, 0");
- settings->setDefault("mgv7_np_humidity", "50, 31.25, (750, 750, 750), 12094, 2, 0.6");
+ settings->setDefault("mgv7_np_terrain_base", "0, 80, (250, 250, 250), 82341, 5, 0.6");
+ settings->setDefault("mgv7_np_terrain_alt", "0, 20, (250, 250, 250), 5934, 5, 0.6");
+ settings->setDefault("mgv7_np_terrain_mod", "0, 1, (350, 350, 350), 85039, 5, 0.6");
+ settings->setDefault("mgv7_np_terrain_persist", "0, 1, (500, 500, 500), 539, 3, 0.6");
+ settings->setDefault("mgv7_np_height_select", "0.5, 0.5, (250, 250, 250), 4213, 5, 0.69");
+ settings->setDefault("mgv7_np_ridge", "0.5, 1, (100, 100, 100), 6467, 4, 0.75");
settings->setDefault("mgindev_np_terrain_base", "-4, 20, (250, 250, 250), 82341, 5, 0.6, 10, 10");
settings->setDefault("mgindev_np_terrain_higher", "20, 16, (500, 500, 500), 85039, 5, 0.6, 10, 10");
@@ -245,7 +247,6 @@ void set_default_settings(Settings *settings)
settings->setDefault("mgindev_np_float_islands3", "0, 1, (256, 256, 256), 6412, 2, 0.5, 1, 0.5");
settings->setDefault("mgindev_np_biome", "0, 1, (250, 250, 250), 9130, 3, 0.50, 1, 10");
settings->setDefault("mgindev_float_islands", "500");
-
}
void override_default_settings(Settings *settings, Settings *from)
diff --git a/src/emerge.cpp b/src/emerge.cpp
index e4bd997cb..499aaf291 100644
--- a/src/emerge.cpp
+++ b/src/emerge.cpp
@@ -1,6 +1,7 @@
/*
-Minetest-c55
-Copyright (C) 2010-2011 celeron55, Perttu Ahola <celeron55@gmail.com>
+Minetest
+Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
+Copyright (C) 2010-2013 kwolekr, Ryan Kwolek <kwolekr@minetest.net>
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
@@ -39,19 +40,22 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "biome.h"
#include "emerge.h"
#include "mapgen_v6.h"
+#include "mapgen_v7.h"
#include "mapgen_indev.h"
#include "mapgen_singlenode.h"
/////////////////////////////// Emerge Manager ////////////////////////////////
-EmergeManager::EmergeManager(IGameDef *gamedef, BiomeDefManager *bdef) {
+EmergeManager::EmergeManager(IGameDef *gamedef) {
//register built-in mapgens
registerMapgen("v6", new MapgenFactoryV6());
+ //registerMapgen("v7", new MapgenFactoryV7());
registerMapgen("indev", new MapgenFactoryIndev());
registerMapgen("singlenode", new MapgenFactorySinglenode());
- this->biomedef = bdef ? bdef : new BiomeDefManager(gamedef);
+ this->ndef = gamedef->getNodeDefManager();
+ this->biomedef = new BiomeDefManager();
this->params = NULL;
mapgen_debug_info = g_settings->getBool("enable_mapgen_debug_info");
@@ -104,6 +108,8 @@ void EmergeManager::initMapgens(MapgenParams *mgparams) {
if (mapgen.size())
return;
+ biomedef->resolveNodeNames(ndef);
+
this->params = mgparams;
for (unsigned int i = 0; i != emergethread.size(); i++) {
mg = createMapgen(params->mg_name, 0, params);
@@ -237,6 +243,8 @@ MapgenParams *EmergeManager::createMapgenParams(std::string mgname) {
MapgenParams *EmergeManager::getParamsFromSettings(Settings *settings) {
std::string mg_name = settings->get("mg_name");
MapgenParams *mgparams = createMapgenParams(mg_name);
+ if (!mgparams)
+ return NULL;
mgparams->mg_name = mg_name;
mgparams->seed = settings->getU64(settings == g_settings ? "fixed_map_seed" : "seed");
diff --git a/src/emerge.h b/src/emerge.h
index 3d717bce3..fdca93c06 100644
--- a/src/emerge.h
+++ b/src/emerge.h
@@ -1,3 +1,22 @@
+/*
+Minetest
+Copyright (C) 2010-2013 kwolekr, Ryan Kwolek <kwolekr@minetest.net>
+
+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 EMERGE_HEADER
#define EMERGE_HEADER
@@ -46,6 +65,8 @@ struct BlockEmergeData {
class EmergeManager {
public:
+ INodeDefManager *ndef;
+
std::map<std::string, MapgenFactory *> mglist;
std::vector<Mapgen *> mapgen;
@@ -67,7 +88,7 @@ public:
BiomeDefManager *biomedef;
std::vector<Ore *> ores;
- EmergeManager(IGameDef *gamedef, BiomeDefManager *bdef);
+ EmergeManager(IGameDef *gamedef);
~EmergeManager();
void initMapgens(MapgenParams *mgparams);
diff --git a/src/environment.cpp b/src/environment.cpp
index 07cdb24d1..fc7972b2c 100644
--- a/src/environment.cpp
+++ b/src/environment.cpp
@@ -364,6 +364,29 @@ ServerMap & ServerEnvironment::getServerMap()
return *m_map;
}
+bool ServerEnvironment::line_of_sight(v3f pos1, v3f pos2, float stepsize)
+{
+ float distance = pos1.getDistanceFrom(pos2);
+
+ //calculate normalized direction vector
+ v3f normalized_vector = v3f((pos2.X - pos1.X)/distance,
+ (pos2.Y - pos1.Y)/distance,
+ (pos2.Z - pos1.Z)/distance);
+
+ //find out if there's a node on path between pos1 and pos2
+ for (float i = 1; i < distance; i += stepsize) {
+ v3s16 pos = floatToInt(v3f(normalized_vector.X * i,
+ normalized_vector.Y * i,
+ normalized_vector.Z * i) +pos1,BS);
+
+ MapNode n = getMap().getNodeNoEx(pos);
+
+ if(n.param0 != CONTENT_AIR) {
+ return false;
+ }
+ }
+ return true;
+}
void ServerEnvironment::serializePlayers(const std::string &savedir)
{
@@ -2057,7 +2080,7 @@ void ClientEnvironment::step(float dtime)
// Gravity
v3f speed = lplayer->getSpeed();
if(lplayer->in_liquid == false)
- speed.Y -= lplayer->movement_gravity * dtime_part * 2;
+ speed.Y -= lplayer->movement_gravity * lplayer->physics_override_gravity * dtime_part * 2;
// Liquid floating / sinking
if(lplayer->in_liquid && !lplayer->swimming_vertical)
diff --git a/src/environment.h b/src/environment.h
index 02301e5d3..a3e43dbb4 100644
--- a/src/environment.h
+++ b/src/environment.h
@@ -298,6 +298,9 @@ public:
// This makes stuff happen
void step(f32 dtime);
+ //check if there's a line of sight between two positions
+ bool line_of_sight(v3f pos1, v3f pos2, float stepsize=1.0);
+
private:
/*
@@ -470,6 +473,13 @@ public:
ClientEnvEvent getClientEvent();
std::vector<core::vector2d<int> > attachment_list; // X is child ID, Y is parent ID
+
+ std::list<std::string> getPlayerNames()
+ { return m_player_names; }
+ void addPlayerName(std::string name)
+ { m_player_names.push_back(name); }
+ void removePlayerName(std::string name)
+ { m_player_names.remove(name); }
private:
ClientMap *m_map;
@@ -482,6 +492,7 @@ private:
Queue<ClientEnvEvent> m_client_event_queue;
IntervalLimiter m_active_object_light_update_interval;
IntervalLimiter m_lava_hurt_interval;
+ std::list<std::string> m_player_names;
};
#endif
diff --git a/src/game.cpp b/src/game.cpp
index 5e4e06148..65feb50bf 100644
--- a/src/game.cpp
+++ b/src/game.cpp
@@ -2388,7 +2388,7 @@ void the_game(
infotext = narrow_to_wide(meta->getString("infotext"));
} else {
MapNode n = map.getNode(nodepos);
- if(nodedef->get(n).tiledef[0].name == "unknown_block.png"){
+ if(nodedef->get(n).tiledef[0].name == "unknown_node.png"){
infotext = L"Unknown node: ";
infotext += narrow_to_wide(nodedef->get(n).name);
}
diff --git a/src/genericobject.cpp b/src/genericobject.cpp
index f7b272b00..e2fbde838 100644
--- a/src/genericobject.cpp
+++ b/src/genericobject.cpp
@@ -117,6 +117,18 @@ std::string gob_cmd_update_armor_groups(const ItemGroupList &armor_groups)
return os.str();
}
+std::string gob_cmd_update_physics_override(float physics_override_speed, float physics_override_jump, float physics_override_gravity)
+{
+ std::ostringstream os(std::ios::binary);
+ // command
+ writeU8(os, GENERIC_CMD_SET_PHYSICS_OVERRIDE);
+ // parameters
+ writeF1000(os, physics_override_speed);
+ writeF1000(os, physics_override_jump);
+ writeF1000(os, physics_override_gravity);
+ return os.str();
+}
+
std::string gob_cmd_update_animation(v2f frames, float frame_speed, float frame_blend)
{
std::ostringstream os(std::ios::binary);
diff --git a/src/genericobject.h b/src/genericobject.h
index 9a21baa67..276865ab9 100644
--- a/src/genericobject.h
+++ b/src/genericobject.h
@@ -33,6 +33,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#define GENERIC_CMD_SET_ANIMATION 6
#define GENERIC_CMD_SET_BONE_POSITION 7
#define GENERIC_CMD_SET_ATTACHMENT 8
+#define GENERIC_CMD_SET_PHYSICS_OVERRIDE 9
#include "object_properties.h"
std::string gob_cmd_set_properties(const ObjectProperties &prop);
@@ -62,6 +63,8 @@ std::string gob_cmd_punched(s16 damage, s16 result_hp);
#include "itemgroup.h"
std::string gob_cmd_update_armor_groups(const ItemGroupList &armor_groups);
+std::string gob_cmd_update_physics_override(float physics_override_speed, float physics_override_jump, float physics_override_gravity);
+
std::string gob_cmd_update_animation(v2f frames, float frame_speed, float frame_blend);
std::string gob_cmd_update_bone_position(std::string bone, v3f position, v3f rotation);
diff --git a/src/guiChatConsole.cpp b/src/guiChatConsole.cpp
index 5fc576cf8..ec23648f8 100644
--- a/src/guiChatConsole.cpp
+++ b/src/guiChatConsole.cpp
@@ -535,7 +535,7 @@ bool GUIChatConsole::OnEvent(const SEvent& event)
{
// Tab or Shift-Tab pressed
// Nick completion
- std::list<std::wstring> names = m_client->getConnectedPlayerNames();
+ std::list<std::string> names = m_client->getConnectedPlayerNames();
bool backwards = event.KeyInput.Shift;
m_chat_backend->getPrompt().nickCompletion(names, backwards);
return true;
diff --git a/src/guiMainMenu.cpp b/src/guiMainMenu.cpp
index 4c2030039..1e3083577 100644
--- a/src/guiMainMenu.cpp
+++ b/src/guiMainMenu.cpp
@@ -1207,6 +1207,15 @@ bool GUIMainMenu::OnEvent(const SEvent& event)
switch(event.GUIEvent.Caller->getID())
{
case GUI_ID_ADDRESS_INPUT: case GUI_ID_PORT_INPUT: case GUI_ID_NAME_INPUT: case 264:
+ MainMenuData cur;
+ readInput(&cur);
+ if (getTab() == TAB_MULTIPLAYER && cur.address == L"")
+ {
+ (new GUIMessageMenu(env, parent, -1, menumgr,
+ wgettext("Address required."))
+ )->drop();
+ return true;
+ }
acceptInput();
quitMenu();
return true;
diff --git a/src/localplayer.cpp b/src/localplayer.cpp
index ee9b41c58..9c70c8b2f 100644
--- a/src/localplayer.cpp
+++ b/src/localplayer.cpp
@@ -35,6 +35,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
LocalPlayer::LocalPlayer(IGameDef *gamedef):
Player(gamedef),
+ parent(0),
isAttached(false),
overridePosition(v3f(0,0,0)),
last_position(v3f(0,0,0)),
@@ -388,7 +389,8 @@ void LocalPlayer::applyControl(float dtime)
bool free_move = fly_allowed && g_settings->getBool("free_move");
bool fast_move = fast_allowed && g_settings->getBool("fast_move");
- bool fast_or_aux1_descends = (fast_move && control.aux1) || (fast_move && g_settings->getBool("aux1_descends"));
+ // When aux1_descends is enabled the fast key is used to go down, so fast isn't possible
+ bool fast_climb = fast_move && control.aux1 && !g_settings->getBool("aux1_descends");
bool continuous_forward = g_settings->getBool("continuous_forward");
// Whether superspeed mode is used or not
@@ -417,14 +419,12 @@ void LocalPlayer::applyControl(float dtime)
}
else if(in_liquid || in_liquid_stable)
{
- // Always use fast when aux1_descends & fast_move are enabled in liquid, since the aux1 button would mean both turbo and "swim down" causing a conflict
- speedV.Y = -movement_speed_fast;
+ speedV.Y = -movement_speed_walk;
swimming_vertical = true;
}
else if(is_climbing)
{
- // Always use fast when aux1_descends & fast_move are enabled when climbing, since the aux1 button would mean both turbo and "descend" causing a conflict
- speedV.Y = -movement_speed_fast;
+ speedV.Y = -movement_speed_climb;
}
else
{
@@ -461,8 +461,7 @@ void LocalPlayer::applyControl(float dtime)
}
else if(in_liquid || in_liquid_stable)
{
- if(fast_or_aux1_descends)
- // Always use fast when aux1_descends & fast_move are enabled in liquid, since the aux1 button would mean both turbo and "swim down" causing a conflict
+ if(fast_climb)
speedV.Y = -movement_speed_fast;
else
speedV.Y = -movement_speed_walk;
@@ -470,8 +469,7 @@ void LocalPlayer::applyControl(float dtime)
}
else if(is_climbing)
{
- if(fast_or_aux1_descends)
- // Always use fast when aux1_descends & fast_move are enabled when climbing, since the aux1 button would mean both turbo and "descend" causing a conflict
+ if(fast_climb)
speedV.Y = -movement_speed_fast;
else
speedV.Y = -movement_speed_climb;
@@ -528,7 +526,7 @@ void LocalPlayer::applyControl(float dtime)
v3f speedJ = getSpeed();
if(speedJ.Y >= -0.5 * BS)
{
- speedJ.Y = movement_speed_jump;
+ speedJ.Y = movement_speed_jump * physics_override_jump;
setSpeed(speedJ);
MtEvent *e = new SimpleTriggerEvent("PlayerJump");
@@ -537,8 +535,7 @@ void LocalPlayer::applyControl(float dtime)
}
else if(in_liquid)
{
- if(fast_or_aux1_descends)
- // Always use fast when aux1_descends & fast_move are enabled in liquid, since the aux1 button would mean both turbo and "swim down" causing a conflict
+ if(fast_climb)
speedV.Y = movement_speed_fast;
else
speedV.Y = movement_speed_walk;
@@ -546,8 +543,7 @@ void LocalPlayer::applyControl(float dtime)
}
else if(is_climbing)
{
- if(fast_or_aux1_descends)
- // Always use fast when aux1_descends & fast_move are enabled when climbing, since the aux1 button would mean both turbo and "descend" causing a conflict
+ if(fast_climb)
speedV.Y = movement_speed_fast;
else
speedV.Y = movement_speed_climb;
@@ -555,7 +551,7 @@ void LocalPlayer::applyControl(float dtime)
}
// The speed of the player (Y is ignored)
- if(superspeed || (is_climbing && fast_or_aux1_descends) || ((in_liquid || in_liquid_stable) && fast_or_aux1_descends))
+ if(superspeed || (is_climbing && fast_climb) || ((in_liquid || in_liquid_stable) && fast_climb))
speedH = speedH.normalize() * movement_speed_fast;
else if(control.sneak && !free_move && !in_liquid && !in_liquid_stable)
speedH = speedH.normalize() * movement_speed_crouch;
@@ -574,17 +570,14 @@ void LocalPlayer::applyControl(float dtime)
incH = movement_acceleration_air * BS * dtime;
incV = 0; // No vertical acceleration in air
}
- else if(superspeed || (fast_move && control.aux1))
- incH = incV = movement_acceleration_fast * BS * dtime;
- else if ((in_liquid || in_liquid_stable) && fast_or_aux1_descends)
- // Always use fast when aux1_descends & fast_move are enabled in liquid, since the aux1 button would mean both turbo and "swim down" causing a conflict
+ else if (superspeed || (is_climbing && fast_climb) || ((in_liquid || in_liquid_stable) && fast_climb))
incH = incV = movement_acceleration_fast * BS * dtime;
else
incH = incV = movement_acceleration_default * BS * dtime;
// Accelerate to target speed with maximum increment
- accelerateHorizontal(speedH, incH);
- accelerateVertical(speedV, incV);
+ accelerateHorizontal(speedH * physics_override_speed, incH * physics_override_speed);
+ accelerateVertical(speedV * physics_override_speed, incV * physics_override_speed);
}
v3s16 LocalPlayer::getStandingNodePos()
diff --git a/src/localplayer.h b/src/localplayer.h
index 17434d379..9ac2bc682 100644
--- a/src/localplayer.h
+++ b/src/localplayer.h
@@ -25,6 +25,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
class ClientEnvironment;
+class ClientActiveObject;
+
class LocalPlayer : public Player
{
public:
@@ -35,6 +37,8 @@ public:
{
return true;
}
+
+ ClientActiveObject *parent;
bool isAttached;
diff --git a/src/map.cpp b/src/map.cpp
index 5d6b79fb0..a8201f3ee 100644
--- a/src/map.cpp
+++ b/src/map.cpp
@@ -1763,6 +1763,11 @@ void Map::transformLiquidsFinite(std::map<v3s16, MapBlock*> & modified_blocks)
total_level = LIQUID_LEVEL_SOURCE * can_liquid_same_level;
}
+ // prevent lakes in air above unloaded blocks
+ if (p0.Y > water_level && neighbors[D_BOTTOM].n.getContent() == CONTENT_IGNORE) {
+ --total_level;
+ }
+
// calculate self level 5 blocks
u8 want_level =
total_level >= LIQUID_LEVEL_SOURCE * can_liquid_same_level
@@ -1807,8 +1812,8 @@ void Map::transformLiquidsFinite(std::map<v3s16, MapBlock*> & modified_blocks)
}
for (u16 ii = 0; ii < 7; ii++) // infinity and cave flood optimization
- if (liquid_levels_want[ii] >= 0 &&
- (neighbors[ii].i ||
+ if ( neighbors[ii].i ||
+ (liquid_levels_want[ii] >= 0 &&
(fast_flood && p0.Y < water_level &&
(initial_size >= 1000
&& ii != D_TOP
@@ -1916,8 +1921,7 @@ void Map::transformLiquidsFinite(std::map<v3s16, MapBlock*> & modified_blocks)
if(!suspect.empty()){
// Blame suspect
- RollbackScopeActor rollback_scope(m_gamedef->rollback(),
- suspect, true);
+ RollbackScopeActor rollback_scope(m_gamedef->rollback(), suspect, true);
// Get old node for rollback
RollbackNode rollback_oldnode(this, p0, m_gamedef);
// Set node
@@ -3462,8 +3466,16 @@ void ServerMap::loadMapMeta()
break;
params.parseConfigLine(line);
}
-
- MapgenParams *mgparams = m_emerge->getParamsFromSettings(&params);
+
+ MapgenParams *mgparams;
+ try {
+ mgparams = m_emerge->getParamsFromSettings(&params);
+ } catch (SettingNotFoundException &e) {
+ infostream << "Couldn't get a setting from map_meta.txt: "
+ << e.what() << std::endl;
+ mgparams = NULL;
+ }
+
if (mgparams) {
if (m_mgparams)
delete m_mgparams;
diff --git a/src/mapgen.cpp b/src/mapgen.cpp
index 64c1886b3..22488bc4c 100644
--- a/src/mapgen.cpp
+++ b/src/mapgen.cpp
@@ -34,6 +34,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "main.h" // For g_profiler
#include "treegen.h"
#include "mapgen_v6.h"
+#include "mapgen_v7.h"
FlagDesc flagdesc_mapgen[] = {
{"trees", MG_TREES},
@@ -240,8 +241,7 @@ void Mapgen::updateLiquid(UniqueQueue<v3s16> *trans_liquid, v3s16 nmin, v3s16 nm
void Mapgen::setLighting(v3s16 nmin, v3s16 nmax, u8 light) {
ScopeProfiler sp(g_profiler, "EmergeThread: mapgen lighting update", SPT_AVG);
- VoxelArea a(nmin - v3s16(1,0,1) * MAP_BLOCKSIZE,
- nmax + v3s16(1,0,1) * MAP_BLOCKSIZE);
+ VoxelArea a(nmin, nmax);
for (int z = a.MinEdge.Z; z <= a.MaxEdge.Z; z++) {
for (int y = a.MinEdge.Y; y <= a.MaxEdge.Y; y++) {
@@ -277,8 +277,7 @@ void Mapgen::lightSpread(VoxelArea &a, v3s16 p, u8 light) {
void Mapgen::calcLighting(v3s16 nmin, v3s16 nmax) {
- VoxelArea a(nmin - v3s16(1,0,1) * MAP_BLOCKSIZE,
- nmax + v3s16(1,0,1) * MAP_BLOCKSIZE);
+ VoxelArea a(nmin, nmax);
bool block_is_underground = (water_level >= nmax.Y);
ScopeProfiler sp(g_profiler, "EmergeThread: mapgen lighting update", SPT_AVG);
@@ -341,9 +340,7 @@ void Mapgen::calcLighting(v3s16 nmin, v3s16 nmax) {
void Mapgen::calcLightingOld(v3s16 nmin, v3s16 nmax) {
enum LightBank banks[2] = {LIGHTBANK_DAY, LIGHTBANK_NIGHT};
-
- VoxelArea a(nmin - v3s16(1,0,1) * MAP_BLOCKSIZE,
- nmax + v3s16(1,0,1) * MAP_BLOCKSIZE);
+ VoxelArea a(nmin, nmax);
bool block_is_underground = (water_level > nmax.Y);
bool sunlight = !block_is_underground;
@@ -409,6 +406,31 @@ void MapgenV6Params::writeParams(Settings *settings) {
}
+bool MapgenV7Params::readParams(Settings *settings) {
+ np_terrain_base = settings->getNoiseParams("mgv7_np_terrain_base");
+ np_terrain_alt = settings->getNoiseParams("mgv7_np_terrain_alt");
+ np_terrain_mod = settings->getNoiseParams("mgv7_np_terrain_mod");
+ np_terrain_persist = settings->getNoiseParams("mgv7_np_terrain_persist");
+ np_height_select = settings->getNoiseParams("mgv7_np_height_select");
+ np_ridge = settings->getNoiseParams("mgv7_np_ridge");
+
+ bool success =
+ np_terrain_base && np_terrain_alt && np_terrain_mod &&
+ np_terrain_persist && np_height_select && np_ridge;
+ return success;
+}
+
+
+void MapgenV7Params::writeParams(Settings *settings) {
+ settings->setNoiseParams("mgv7_np_terrain_base", np_terrain_base);
+ settings->setNoiseParams("mgv7_np_terrain_alt", np_terrain_alt);
+ settings->setNoiseParams("mgv7_np_terrain_mod", np_terrain_mod);
+ settings->setNoiseParams("mgv7_np_terrain_persist", np_terrain_persist);
+ settings->setNoiseParams("mgv7_np_height_select", np_height_select);
+ settings->setNoiseParams("mgv7_np_ridge", np_ridge);
+}
+
+
/////////////////////////////////// legacy static functions for farmesh
diff --git a/src/mapgen_indev.cpp b/src/mapgen_indev.cpp
index 5d455827a..5c842b6a5 100644
--- a/src/mapgen_indev.cpp
+++ b/src/mapgen_indev.cpp
@@ -265,9 +265,9 @@ void MapgenIndev::defineCave(Cave & cave, PseudoRandom ps, v3s16 node_min, bool
cave.part_max_length_rs = ps.range(2,4);
if (node_min.Y < -100 && !ps.range(0, farscale(0.2, node_min.X,node_min.Y,node_min.Z)*30)) { //huge
cave.flooded = !ps.range(0, 3);
- cave.tunnel_routepoints = ps.range(5, 20);
+ cave.tunnel_routepoints = ps.range(5, 30);
cave.min_tunnel_diameter = 30;
- cave.max_tunnel_diameter = ps.range(40, ps.range(80,120));
+ cave.max_tunnel_diameter = ps.range(40, ps.range(80,200));
} else {
cave.tunnel_routepoints = ps.range(5, ps.range(15,30));
cave.min_tunnel_diameter = 5;
diff --git a/src/mapgen_singlenode.cpp b/src/mapgen_singlenode.cpp
index 22b756abb..f05ddd2f4 100644
--- a/src/mapgen_singlenode.cpp
+++ b/src/mapgen_singlenode.cpp
@@ -91,7 +91,8 @@ void MapgenSinglenode::makeChunk(BlockMakeData *data) {
updateLiquid(&data->transforming_liquid, node_min, node_max);
// Calculate lighting
- calcLighting(node_min, node_max);
+ calcLighting(node_min - v3s16(1, 0, 1) * MAP_BLOCKSIZE,
+ node_max + v3s16(1, 0, 1) * MAP_BLOCKSIZE);
this->generating = false;
}
diff --git a/src/mapgen_v6.cpp b/src/mapgen_v6.cpp
index 275d4b78f..4a037bb85 100644
--- a/src/mapgen_v6.cpp
+++ b/src/mapgen_v6.cpp
@@ -471,7 +471,8 @@ void MapgenV6::makeChunk(BlockMakeData *data) {
}
// Calculate lighting
- calcLighting(node_min, node_max);
+ calcLighting(node_min - v3s16(1, 1, 1) * MAP_BLOCKSIZE,
+ node_max + v3s16(1, 0, 1) * MAP_BLOCKSIZE);
this->generating = false;
}
diff --git a/src/mapgen_v7.cpp b/src/mapgen_v7.cpp
new file mode 100644
index 000000000..6aecfe310
--- /dev/null
+++ b/src/mapgen_v7.cpp
@@ -0,0 +1,490 @@
+/*
+Minetest
+Copyright (C) 2010-2013 kwolekr, Ryan Kwolek <kwolekr@minetest.net>
+
+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 "mapgen.h"
+#include "voxel.h"
+#include "noise.h"
+#include "mapblock.h"
+#include "mapnode.h"
+#include "map.h"
+//#include "serverobject.h"
+#include "content_sao.h"
+#include "nodedef.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 "emerge.h"
+#include "dungeongen.h"
+#include "treegen.h"
+#include "biome.h"
+#include "mapgen_v7.h"
+
+
+/////////////////// Mapgen V7 perlin noise default values
+NoiseParams nparams_v7_def_terrain_base =
+ {0, 80.0, v3f(250.0, 250.0, 250.0), 82341, 5, 0.6};
+NoiseParams nparams_v7_def_terrain_alt =
+ {0, 20.0, v3f(250.0, 250.0, 250.0), 5934, 5, 0.6};
+NoiseParams nparams_v7_def_terrain_mod =
+ {0, 1.0, v3f(350.0, 350.0, 350.0), 85039, 5, 0.6};
+NoiseParams nparams_v7_def_terrain_persist =
+ {0, 1.0, v3f(500.0, 500.0, 500.0), 539, 3, 0.6};
+NoiseParams nparams_v7_def_height_select =
+ {0.5, 0.5, v3f(250.0, 250.0, 250.0), 4213, 5, 0.69};
+NoiseParams nparams_v7_def_ridge =
+ {0.5, 1.0, v3f(100.0, 100.0, 100.0), 6467, 4, 0.75};
+/*
+NoiseParams nparams_v6_def_beach =
+ {0.0, 1.0, v3f(250.0, 250.0, 250.0), 59420, 3, 0.50};
+NoiseParams nparams_v6_def_cave =
+ {6.0, 6.0, v3f(250.0, 250.0, 250.0), 34329, 3, 0.50};
+NoiseParams nparams_v6_def_humidity =
+ {0.5, 0.5, v3f(500.0, 500.0, 500.0), 72384, 4, 0.66};
+NoiseParams nparams_v6_def_trees =
+ {0.0, 1.0, v3f(125.0, 125.0, 125.0), 2, 4, 0.66};
+NoiseParams nparams_v6_def_apple_trees =
+ {0.0, 1.0, v3f(100.0, 100.0, 100.0), 342902, 3, 0.45};
+*/
+///////////////////////////////////////////////////////////////////////////////
+
+
+MapgenV7::MapgenV7(int mapgenid, MapgenV7Params *params, EmergeManager *emerge) {
+ this->generating = false;
+ this->id = mapgenid;
+ this->emerge = emerge;
+ this->bmgr = emerge->biomedef;
+
+ this->seed = (int)params->seed;
+ this->water_level = params->water_level;
+ this->flags = params->flags;
+ this->csize = v3s16(1, 1, 1) * params->chunksize * MAP_BLOCKSIZE;
+// this->ystride = csize.X; //////fix this
+
+ this->biomemap = new u8[csize.X * csize.Z];
+ this->heightmap = new s16[csize.X * csize.Z];
+ this->ridge_heightmap = new s16[csize.X * csize.Z];
+
+ // Terrain noise
+ noise_terrain_base = new Noise(params->np_terrain_base, seed, csize.X, csize.Z);
+ noise_terrain_alt = new Noise(params->np_terrain_alt, seed, csize.X, csize.Z);
+ noise_terrain_mod = new Noise(params->np_terrain_mod, seed, csize.X, csize.Z);
+ noise_terrain_persist = new Noise(params->np_terrain_persist, seed, csize.X, csize.Z);
+ noise_height_select = new Noise(params->np_height_select, seed, csize.X, csize.Z);
+ noise_ridge = new Noise(params->np_ridge, seed, csize.X, csize.Y, csize.Z);
+
+ // Biome noise
+ noise_heat = new Noise(bmgr->np_heat, seed, csize.X, csize.Z);
+ noise_humidity = new Noise(bmgr->np_humidity, seed, csize.X, csize.Z);
+}
+
+
+MapgenV7::~MapgenV7() {
+ delete noise_terrain_base;
+ delete noise_terrain_mod;
+ delete noise_terrain_persist;
+ delete noise_height_select;
+ delete noise_terrain_alt;
+ delete noise_ridge;
+ delete noise_heat;
+ delete noise_humidity;
+
+ delete[] ridge_heightmap;
+ delete[] heightmap;
+ delete[] biomemap;
+}
+
+
+int MapgenV7::getGroundLevelAtPoint(v2s16 p) {
+ return 20;
+}
+
+
+void MapgenV7::makeChunk(BlockMakeData *data) {
+ 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->vm = data->vmanip;
+ this->ndef = data->nodedef;
+ //TimeTaker t("makeChunk");
+
+ v3s16 blockpos_min = data->blockpos_min;
+ 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);
+ node_min = blockpos_min * MAP_BLOCKSIZE;
+ node_max = (blockpos_max + v3s16(1, 1, 1)) * MAP_BLOCKSIZE - v3s16(1, 1, 1);
+ full_node_min = (blockpos_min - 1) * MAP_BLOCKSIZE;
+ full_node_max = (blockpos_max + 2) * MAP_BLOCKSIZE - v3s16(1, 1, 1);
+
+ //blockseed = emerge->getBlockSeed(full_node_min);
+
+ // Make some noise
+ calculateNoise();
+
+ // Calculate height map
+ s16 stone_surface_max_y = calcHeightMap();
+
+ // Calculate biomes
+ BiomeNoiseInput binput;
+ binput.mapsize = v2s16(csize.X, csize.Z);
+ binput.heat_map = noise_heat->result;
+ binput.humidity_map = noise_humidity->result;
+ binput.height_map = heightmap;
+ bmgr->calcBiomes(&binput, biomemap);
+
+ c_stone = ndef->getId("mapgen_stone");
+ c_dirt = ndef->getId("mapgen_dirt");
+ c_dirt_with_grass = ndef->getId("mapgen_dirt_with_grass");
+ c_sand = ndef->getId("mapgen_sand");
+ c_water_source = ndef->getId("mapgen_water_source");
+
+ generateTerrain();
+ carveRidges();
+
+ //carveRivers();
+ addTopNodes();
+ growGrass();
+
+ //v3s16 central_area_size = node_max - node_min + v3s16(1,1,1);
+
+ if (flags & MG_DUNGEONS) {
+ DungeonGen dgen(ndef, data->seed, water_level);
+ dgen.generate(vm, blockseed, full_node_min, full_node_max);
+ }
+
+ for (size_t i = 0; i != emerge->ores.size(); i++) {
+ Ore *ore = emerge->ores[i];
+ ore->generate(this, blockseed + i, node_min, node_max);
+ }
+
+ //printf("makeChunk: %dms\n", t.stop());
+
+ updateLiquid(&data->transforming_liquid, full_node_min, full_node_max);
+
+ calcLighting(node_min - v3s16(1, 0, 1) * MAP_BLOCKSIZE,
+ node_max + v3s16(1, 0, 1) * MAP_BLOCKSIZE);
+ //setLighting(node_min, node_max, 0xFF);
+
+ this->generating = false;
+}
+
+
+void MapgenV7::calculateNoise() {
+ //TimeTaker t("calculateNoise", NULL, PRECISION_MICRO);
+ int x = node_min.X;
+ int y = node_min.Y;
+ int z = node_min.Z;
+
+ noise_terrain_mod->perlinMap2D(x, z);
+
+ noise_height_select->perlinMap2D(x, z);
+ noise_height_select->transformNoiseMap();
+
+ noise_terrain_persist->perlinMap2D(x, z);
+ float *persistmap = noise_terrain_persist->result;
+ for (int i = 0; i != csize.X * csize.Z; i++)
+ persistmap[i] = abs(persistmap[i]);
+
+ noise_terrain_base->perlinMap2DModulated(x, z, persistmap);
+ noise_terrain_base->transformNoiseMap();
+
+ noise_terrain_alt->perlinMap2DModulated(x, z, persistmap);
+ noise_terrain_alt->transformNoiseMap();
+
+ noise_ridge->perlinMap3D(x, y, z);
+
+ noise_heat->perlinMap2D(x, z);
+
+ noise_humidity->perlinMap2D(x, z);
+
+ //printf("calculateNoise: %dus\n", t.stop());
+}
+
+
+Biome *MapgenV7::getBiomeAtPoint(v3s16 p) {
+ float heat = NoisePerlin2D(bmgr->np_heat, p.X, p.Z, seed);
+ float humidity = NoisePerlin2D(bmgr->np_humidity, p.X, p.Z, seed);
+ s16 groundlevel = baseTerrainLevelAtPoint(p.X, p.Z);
+
+ return bmgr->getBiome(heat, humidity, groundlevel);
+}
+
+
+float MapgenV7::baseTerrainLevelAtPoint(int x, int z) {
+ float terrain_mod = NoisePerlin2DNoTxfm(noise_terrain_mod->np, x, z, seed);
+ float hselect = NoisePerlin2D(noise_height_select->np, x, z, seed);
+ float persist = abs(NoisePerlin2DNoTxfm(noise_terrain_persist->np, x, z, seed));
+
+ noise_terrain_base->np->persist = persist;
+ float terrain_base = NoisePerlin2D(noise_terrain_base->np, x, z, seed);
+ float height_base = terrain_base * terrain_mod;
+
+ noise_terrain_alt->np->persist = persist;
+ float height_alt = NoisePerlin2D(noise_terrain_alt->np, x, z, seed);
+
+ return (height_base * hselect) + (height_alt * (1.0 - hselect));
+}
+
+
+float MapgenV7::baseTerrainLevelFromMap(int index) {
+ float terrain_mod = noise_terrain_mod->result[index];
+ float hselect = noise_height_select->result[index];
+ float terrain_base = noise_terrain_base->result[index];
+ float height_base = terrain_base * terrain_mod;
+ float height_alt = noise_terrain_alt->result[index];
+
+ return (height_base * hselect) + (height_alt * (1.0 - hselect));
+}
+
+
+#if 0
+// Crap code to test log rivers as a proof-of-concept. Didn't work out too well.
+void MapgenV7::carveRivers() {
+ MapNode n_air(CONTENT_AIR), n_water_source(c_water_source);
+ MapNode n_stone(c_stone);
+ u32 index = 0;
+
+ int river_depth = 4;
+
+ for (s16 z = node_min.Z; z <= node_max.Z; z++)
+ for (s16 x = node_min.X; x <= node_max.X; x++, index++) {
+ float terrain_mod = noise_terrain_mod->result[index];
+ NoiseParams *np = noise_terrain_river->np;
+ np->persist = noise_terrain_persist->result[index];
+ float terrain_river = NoisePerlin2DNoTxfm(np, x, z, seed);
+ float height = terrain_river * (1 - abs(terrain_mod)) *
+ noise_terrain_river->np->scale;
+ height = log(height * height); //log(h^3) is pretty interesting for terrain
+
+ s16 y = heightmap[index];
+ if (height < 1.0 && y > river_depth &&
+ y - river_depth >= node_min.Y && y <= node_max.Y) {
+
+ for (s16 ry = y; ry != y - river_depth; ry--) {
+ u32 vi = vm->m_area.index(x, ry, z);
+ vm->m_data[vi] = n_air;
+ }
+
+ u32 vi = vm->m_area.index(x, y - river_depth, z);
+ vm->m_data[vi] = n_water_source;
+ }
+ }
+}
+#endif
+
+
+int MapgenV7::calcHeightMap() {
+ int stone_surface_max_y = -MAP_GENERATION_LIMIT;
+ u32 index = 0;
+
+ for (s16 z = node_min.Z; z <= node_max.Z; z++)
+ for (s16 x = node_min.X; x <= node_max.X; x++, index++) {
+ float surface_height = baseTerrainLevelFromMap(index);
+ s16 surface_y = (s16)surface_height;
+
+ heightmap[index] = surface_y;
+ ridge_heightmap[index] = surface_y;
+
+ if (surface_y > stone_surface_max_y)
+ stone_surface_max_y = surface_y;
+ }
+
+ return stone_surface_max_y;
+}
+
+
+void MapgenV7::generateTerrain() {
+ MapNode n_air(CONTENT_AIR), n_water_source(c_water_source);
+ MapNode n_stone(c_stone);
+
+ v3s16 em = vm->m_area.getExtent();
+ u32 index = 0;
+
+ for (s16 z = node_min.Z; z <= node_max.Z; z++)
+ for (s16 x = node_min.X; x <= node_max.X; x++, index++) {
+ s16 surface_y = heightmap[index];
+ Biome *biome = bmgr->biomes[biomemap[index]];
+
+ u32 i = vm->m_area.index(x, node_min.Y, z);
+ for (s16 y = node_min.Y; y <= node_max.Y; y++) {
+ if (vm->m_data[i].getContent() == CONTENT_IGNORE) {
+ if (y <= surface_y) {
+ vm->m_data[i] = (y > water_level + biome->filler_height) ?
+ MapNode(biome->c_filler) : n_stone;
+ } else if (y <= water_level) {
+ vm->m_data[i] = n_water_source;
+ } else {
+ vm->m_data[i] = n_air;
+ }
+ }
+ vm->m_area.add_y(em, i, 1);
+ }
+ }
+}
+
+
+void MapgenV7::carveRidges() {
+ if (node_max.Y <= water_level)
+ return;
+
+ MapNode n_air(CONTENT_AIR);
+ u32 index = 0;
+
+ for (s16 z = node_min.Z; z <= node_max.Z; z++)
+ for (s16 y = node_min.Y; y <= node_max.Y; y++) {
+ u32 vi = vm->m_area.index(node_min.X, y, z);
+ for (s16 x = node_min.X; x <= node_max.X; x++, index++, vi++) {
+ // Removing this check will create huge underwater caverns,
+ // which are interesting but not desirable for gameplay
+ if (y <= water_level)
+ continue;
+
+ if (noise_ridge->result[index] * (float)(y * y) < 15.0)
+ continue;
+
+ int j = (z - node_min.Z) * csize.Z + (x - node_min.X); //////obviously just temporary
+ if (y < ridge_heightmap[j])
+ ridge_heightmap[j] = y - 1;
+
+ vm->m_data[vi] = n_air;
+ }
+ }
+}
+
+/*
+void MapgenV7::testBiomes() {
+ u32 index = 0;
+
+ for (s16 z = node_min.Z; z <= node_min.Z; z++)
+ for (s16 x = node_min.X; x <= node_min.X; x++) {;
+ Biome *b = bmgr->getBiome(heat, humidity, 0);
+ }
+ // make an 80x80 grid with axes heat/humidity as a voroni diagram for biomes
+ // clear out y space for it first with air
+ // use absolute positioning, each chunk will be a +1 height
+}*/
+
+
+void MapgenV7::addTopNodes() {
+ v3s16 em = vm->m_area.getExtent();
+ s16 ntopnodes;
+ u32 index = 0;
+
+ for (s16 z = node_min.Z; z <= node_max.Z; z++)
+ for (s16 x = node_min.X; x <= node_max.X; x++, index++) {
+ // First, add top nodes below the ridge
+ s16 y = ridge_heightmap[index];
+
+ // This cutoff is good enough, but not perfect.
+ // It will cut off potentially placed top nodes at chunk boundaries
+ if (y < node_min.Y)
+ continue;
+ if (y > node_max.Y) {
+ y = node_max.Y; // Let's see if we can still go downward anyway
+ u32 vi = vm->m_area.index(x, y, z);
+ if (vm->m_data[vi].getContent() != CONTENT_AIR)
+ continue;
+ }
+
+ // N.B. It is necessary to search downward since range_heightmap[i]
+ // might not be the actual height, just the lowest part in the chunk
+ // where a ridge had been carved
+ u32 i = vm->m_area.index(x, y, z);
+ for (; y >= node_min.Y; y--) {
+ if (vm->m_data[i].getContent() != CONTENT_AIR)
+ break;
+ vm->m_area.add_y(em, i, -1);
+ }
+
+ Biome *biome = bmgr->biomes[biomemap[index]];
+
+ if (y != node_min.Y - 1) {
+ ridge_heightmap[index] = y; //update ridgeheight
+ ntopnodes = biome->top_depth;
+ for (; y <= node_max.Y && ntopnodes; y++) {
+ ntopnodes--;
+ vm->m_data[i] = MapNode(biome->c_top);
+ vm->m_area.add_y(em, i, 1);
+ }
+ //heightmap[index] = y;
+ }
+
+ // Now, add top nodes on top of the ridge
+ y = heightmap[index];
+
+ i = vm->m_area.index(x, y, z);
+ for (; y >= node_min.Y; y--) {
+ if (vm->m_data[i].getContent() != CONTENT_AIR)
+ break;
+ vm->m_area.add_y(em, i, -1);
+ }
+
+ if (y != node_min.Y - 1) {
+ ntopnodes = biome->top_depth;
+ // Let's see if we've already added it...
+ if (y == ridge_heightmap[index] + ntopnodes - 1)
+ continue;
+
+ for (; y <= node_max.Y && ntopnodes; y++) {
+ ntopnodes--;
+ vm->m_data[i] = MapNode(biome->c_top);
+ vm->m_area.add_y(em, i, 1);
+ }
+ }
+ }
+}
+
+
+void MapgenV7::growGrass() {
+ for (s16 z = node_min.Z; z <= node_max.Z; z++)
+ for (s16 x = node_min.X; x <= node_max.X; x++) {
+ // Find the lowest surface to which enough light ends up to make
+ // grass grow. Basically just wait until not air and not leaves.
+ s16 surface_y = 0;
+ {
+ v3s16 em = vm->m_area.getExtent();
+ u32 i = vm->m_area.index(x, node_max.Y, z);
+ s16 y;
+ // Go to ground level
+ for (y = node_max.Y; y >= node_min.Y; y--) {
+ MapNode &n = vm->m_data[i];
+ if (ndef->get(n).param_type != CPT_LIGHT ||
+ ndef->get(n).liquid_type != LIQUID_NONE)
+ break;
+ vm->m_area.add_y(em, i, -1);
+ }
+ surface_y = (y >= node_min.Y) ? y : node_min.Y;
+ }
+
+ u32 i = vm->m_area.index(x, surface_y, z);
+ MapNode *n = &vm->m_data[i];
+ if (n->getContent() == c_dirt && surface_y >= water_level - 20)
+ n->setContent(c_dirt_with_grass);
+ }
+}
diff --git a/src/mapgen_v7.h b/src/mapgen_v7.h
new file mode 100644
index 000000000..73fa9be03
--- /dev/null
+++ b/src/mapgen_v7.h
@@ -0,0 +1,125 @@
+/*
+Minetest
+Copyright (C) 2010-2013 kwolekr, Ryan Kwolek <kwolekr@minetest.net>
+
+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 MAPGEN_V7_HEADER
+#define MAPGEN_V7_HEADER
+
+#include "mapgen.h"
+
+extern NoiseParams nparams_v7_def_terrain_base;
+extern NoiseParams nparams_v7_def_terrain_alt;
+extern NoiseParams nparams_v7_def_terrain_mod;
+extern NoiseParams nparams_v7_def_terrain_persist;
+extern NoiseParams nparams_v7_def_height_select;
+extern NoiseParams nparams_v7_def_ridge;
+
+struct MapgenV7Params : public MapgenParams {
+ NoiseParams *np_terrain_base;
+ NoiseParams *np_terrain_alt;
+ NoiseParams *np_terrain_mod;
+ NoiseParams *np_terrain_persist;
+ NoiseParams *np_height_select;
+ NoiseParams *np_ridge;
+
+ MapgenV7Params() {
+ np_terrain_base = &nparams_v7_def_terrain_base;
+ np_terrain_alt = &nparams_v7_def_terrain_alt;
+ np_terrain_mod = &nparams_v7_def_terrain_mod;
+ np_terrain_persist = &nparams_v7_def_terrain_persist;
+ np_height_select = &nparams_v7_def_height_select;
+ np_ridge = &nparams_v7_def_ridge;
+ }
+
+ bool readParams(Settings *settings);
+ void writeParams(Settings *settings);
+};
+
+class MapgenV7 : public Mapgen {
+public:
+ EmergeManager *emerge;
+ BiomeDefManager *bmgr;
+
+ int ystride;
+ v3s16 csize;
+ u32 flags;
+
+ u32 blockseed;
+ v3s16 node_min;
+ v3s16 node_max;
+ v3s16 full_node_min;
+ v3s16 full_node_max;
+
+ s16 *heightmap;
+ s16 *ridge_heightmap;
+ u8 *biomemap;
+
+ Noise *noise_terrain_base;
+ Noise *noise_terrain_alt;
+ Noise *noise_terrain_mod;
+ Noise *noise_terrain_persist;
+ Noise *noise_height_select;
+
+ Noise *noise_ridge;
+
+ Noise *noise_heat;
+ Noise *noise_humidity;
+
+ content_t c_stone;
+ content_t c_dirt;
+ content_t c_dirt_with_grass;
+ content_t c_sand;
+ content_t c_water_source;
+ content_t c_lava_source;
+ content_t c_gravel;
+ content_t c_cobble;
+ content_t c_desert_sand;
+ content_t c_desert_stone;
+
+ MapgenV7(int mapgenid, MapgenV7Params *params, EmergeManager *emerge);
+ ~MapgenV7();
+
+ void makeChunk(BlockMakeData *data);
+ int getGroundLevelAtPoint(v2s16 p);
+ Biome *getBiomeAtPoint(v3s16 p);
+
+ float baseTerrainLevelAtPoint(int x, int z);
+ float baseTerrainLevelFromMap(int index);
+ void calculateNoise();
+ int calcHeightMap();
+
+ void generateTerrain();
+ void carveRidges();
+ //void carveRivers(); //experimental
+
+ void testBiomes();
+ void addTopNodes();
+ void growGrass();
+};
+
+struct MapgenFactoryV7 : public MapgenFactory {
+ Mapgen *createMapgen(int mgid, MapgenParams *params, EmergeManager *emerge) {
+ return new MapgenV7(mgid, (MapgenV7Params *)params, emerge);
+ };
+
+ MapgenParams *createMapgenParams() {
+ return new MapgenV7Params();
+ };
+};
+
+#endif
diff --git a/src/nodedef.cpp b/src/nodedef.cpp
index ca8898907..e2b72333f 100644
--- a/src/nodedef.cpp
+++ b/src/nodedef.cpp
@@ -593,7 +593,7 @@ public:
{
tiledef[j] = f->tiledef[j];
if(tiledef[j].name == "")
- tiledef[j].name = "unknown_block.png";
+ tiledef[j].name = "unknown_node.png";
}
bool is_liquid = false;
diff --git a/src/noise.cpp b/src/noise.cpp
index 49b5f7e58..5788a8320 100644
--- a/src/noise.cpp
+++ b/src/noise.cpp
@@ -1,6 +1,7 @@
/*
Minetest
Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
+Copyright (C) 2010-2013 kwolekr, Ryan Kwolek <kwolekr@minetest.net>
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
@@ -536,6 +537,41 @@ float *Noise::perlinMap2D(float x, float y) {
}
+float *Noise::perlinMap2DModulated(float x, float y, float *persist_map) {
+ float f = 1.0;
+ int i, j, index, oct;
+
+ x /= np->spread.X;
+ y /= np->spread.Y;
+
+ memset(result, 0, sizeof(float) * sx * sy);
+
+ float *g = new float[sx * sy];
+ for (index = 0; index != sx * sy; index++)
+ g[index] = 1.0;
+
+ 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[index] * buf[index];
+ g[index] *= persist_map[index];
+ index++;
+ }
+ }
+
+ f *= 2.0;
+ }
+
+ delete[] g;
+ return result;
+}
+
+
float *Noise::perlinMap3D(float x, float y, float z) {
float f = 1.0, g = 1.0;
int i, j, k, index, oct;
diff --git a/src/noise.h b/src/noise.h
index 34b4d0b41..ace6d7eb4 100644
--- a/src/noise.h
+++ b/src/noise.h
@@ -1,6 +1,7 @@
/*
Minetest
Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
+Copyright (C) 2010-2013 kwolekr, Ryan Kwolek <kwolekr@minetest.net>
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
@@ -105,6 +106,7 @@ public:
float step_x, float step_y, float step_z,
int seed);
float *perlinMap2D(float x, float y);
+ float *perlinMap2DModulated(float x, float y, float *persist_map);
float *perlinMap3D(float x, float y, float z);
void transformNoiseMap();
};
diff --git a/src/pathfinder.cpp b/src/pathfinder.cpp
new file mode 100644
index 000000000..c7621177e
--- /dev/null
+++ b/src/pathfinder.cpp
@@ -0,0 +1,1081 @@
+/*
+Minetest
+Copyright (C) 2013 sapier, sapier at gmx dot net
+
+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.
+*/
+
+/******************************************************************************/
+/* Includes */
+/******************************************************************************/
+
+#include "pathfinder.h"
+
+#ifdef PATHFINDER_DEBUG
+#include <iomanip>
+#endif
+#ifdef PATHFINDER_CALC_TIME
+ #include <sys/time.h>
+#endif
+
+/******************************************************************************/
+/* Typedefs and macros */
+/******************************************************************************/
+
+//#define PATHFINDER_CALC_TIME
+
+/** shortcut to print a 3d pos */
+#define PPOS(pos) "(" << pos.X << "," << pos.Y << "," << pos.Z << ")"
+
+#define LVL "(" << level << ")" <<
+
+#ifdef PATHFINDER_DEBUG
+#define DEBUG_OUT(a) std::cout << a
+#define INFO_TARGET std::cout
+#define VERBOSE_TARGET std::cout
+#define ERROR_TARGET std::cout
+#else
+#define DEBUG_OUT(a) while(0)
+#define INFO_TARGET infostream
+#define VERBOSE_TARGET verbosestream
+#define ERROR_TARGET errorstream
+#endif
+
+/******************************************************************************/
+/* implementation */
+/******************************************************************************/
+
+std::vector<v3s16> get_Path(ServerEnvironment* env,
+ v3s16 source,
+ v3s16 destination,
+ unsigned int searchdistance,
+ unsigned int max_jump,
+ unsigned int max_drop,
+ algorithm algo) {
+
+ pathfinder searchclass;
+
+ return searchclass.get_Path(env,
+ source,destination,
+ searchdistance,max_jump,max_drop,algo);
+}
+
+/******************************************************************************/
+path_cost::path_cost()
+: valid(false),
+ value(0),
+ direction(0),
+ updated(false)
+{
+ //intentionaly empty
+}
+
+/******************************************************************************/
+path_cost::path_cost(const path_cost& b) {
+ valid = b.valid;
+ direction = b.direction;
+ value = b.value;
+ updated = b.updated;
+}
+
+/******************************************************************************/
+path_cost& path_cost::operator= (const path_cost& b) {
+ valid = b.valid;
+ direction = b.direction;
+ value = b.value;
+ updated = b.updated;
+
+ return *this;
+}
+
+/******************************************************************************/
+path_gridnode::path_gridnode()
+: valid(false),
+ target(false),
+ source(false),
+ totalcost(-1),
+ sourcedir(v3s16(0,0,0)),
+ surfaces(0),
+ pos(v3s16(0,0,0)),
+ is_element(false),
+ type('u')
+{
+ //intentionaly empty
+}
+
+/******************************************************************************/
+path_gridnode::path_gridnode(const path_gridnode& b)
+: valid(b.valid),
+ target(b.target),
+ source(b.source),
+ totalcost(b.totalcost),
+ sourcedir(b.sourcedir),
+ surfaces(b.surfaces),
+ pos(b.pos),
+ is_element(b.is_element),
+ type(b.type)
+ {
+
+ directions[DIR_XP] = b.directions[DIR_XP];
+ directions[DIR_XM] = b.directions[DIR_XM];
+ directions[DIR_ZP] = b.directions[DIR_ZP];
+ directions[DIR_ZM] = b.directions[DIR_ZM];
+}
+
+/******************************************************************************/
+path_gridnode& path_gridnode::operator= (const path_gridnode& b) {
+ valid = b.valid;
+ target = b.target;
+ source = b.source;
+ is_element = b.is_element;
+ totalcost = b.totalcost;
+ sourcedir = b.sourcedir;
+ surfaces = b.surfaces;
+ pos = b.pos;
+ type = b.type;
+
+ directions[DIR_XP] = b.directions[DIR_XP];
+ directions[DIR_XM] = b.directions[DIR_XM];
+ directions[DIR_ZP] = b.directions[DIR_ZP];
+ directions[DIR_ZM] = b.directions[DIR_ZM];
+
+ return *this;
+}
+
+/******************************************************************************/
+path_cost path_gridnode::get_cost(v3s16 dir) {
+ if (dir.X > 0) {
+ return directions[DIR_XP];
+ }
+ if (dir.X < 0) {
+ return directions[DIR_XM];
+ }
+ if (dir.Z > 0) {
+ return directions[DIR_ZP];
+ }
+ if (dir.Z < 0) {
+ return directions[DIR_ZM];
+ }
+ path_cost retval;
+ return retval;
+}
+
+/******************************************************************************/
+void path_gridnode::set_cost(v3s16 dir,path_cost cost) {
+ if (dir.X > 0) {
+ directions[DIR_XP] = cost;
+ }
+ if (dir.X < 0) {
+ directions[DIR_XM] = cost;
+ }
+ if (dir.Z > 0) {
+ directions[DIR_ZP] = cost;
+ }
+ if (dir.Z < 0) {
+ directions[DIR_ZM] = cost;
+ }
+}
+
+/******************************************************************************/
+std::vector<v3s16> pathfinder::get_Path(ServerEnvironment* env,
+ v3s16 source,
+ v3s16 destination,
+ unsigned int searchdistance,
+ unsigned int max_jump,
+ unsigned int max_drop,
+ algorithm algo) {
+#ifdef PATHFINDER_CALC_TIME
+ timespec ts;
+ clock_gettime(CLOCK_REALTIME, &ts);
+#endif
+ std::vector<v3s16> retval;
+
+ //check parameters
+ if (env == 0) {
+ std::cout << "missing environment pointer" << std::endl;
+ return retval;
+ }
+
+ m_searchdistance = searchdistance;
+ m_env = env;
+ m_maxjump = max_jump;
+ m_maxdrop = max_drop;
+ m_start = source;
+ m_destination = destination;
+ m_min_target_distance = -1;
+ m_prefetch = true;
+
+ if (algo == A_PLAIN_NP) {
+ m_prefetch = false;
+ }
+
+ int min_x = MYMIN(source.X,destination.X);
+ int max_x = MYMAX(source.X,destination.X);
+
+ int min_y = MYMIN(source.Y,destination.Y);
+ int max_y = MYMAX(source.Y,destination.Y);
+
+ int min_z = MYMIN(source.Z,destination.Z);
+ int max_z = MYMAX(source.Z,destination.Z);
+
+ m_limits.X.min = min_x - searchdistance;
+ m_limits.X.max = max_x + searchdistance;
+ m_limits.Y.min = min_y - searchdistance;
+ m_limits.Y.max = max_y + searchdistance;
+ m_limits.Z.min = min_z - searchdistance;
+ m_limits.Z.max = max_z + searchdistance;
+
+ m_max_index_x = m_limits.X.max - m_limits.X.min;
+ m_max_index_y = m_limits.Y.max - m_limits.Y.min;
+ m_max_index_z = m_limits.Z.max - m_limits.Z.min;
+
+ //build data map
+ if (!build_costmap()) {
+ std::cout << "failed to build costmap" << std::endl;
+ return retval;
+ }
+#ifdef PATHFINDER_DEBUG
+ print_type();
+ print_cost();
+ print_ydir();
+#endif
+
+ //validate and mark start and end pos
+ v3s16 StartIndex = getIndexPos(source);
+ v3s16 EndIndex = getIndexPos(destination);
+
+ path_gridnode& startpos = getIndexElement(StartIndex);
+ path_gridnode& endpos = getIndexElement(EndIndex);
+
+ if (!startpos.valid) {
+ std::cout << "invalid startpos" <<
+ "Index: " << PPOS(StartIndex) <<
+ "Realpos: " << PPOS(getRealPos(StartIndex)) << std::endl;
+ return retval;
+ }
+ if (!endpos.valid) {
+ std::cout << "invalid stoppos" <<
+ "Index: " << PPOS(EndIndex) <<
+ "Realpos: " << PPOS(getRealPos(EndIndex)) << std::endl;
+ return retval;
+ }
+
+ endpos.target = true;
+ startpos.source = true;
+ startpos.totalcost = 0;
+
+ bool update_cost_retval = false;
+
+ switch (algo) {
+ case DIJKSTRA:
+ update_cost_retval = update_all_costs(StartIndex,v3s16(0,0,0),0,0);
+ break;
+ case A_PLAIN_NP:
+ case A_PLAIN:
+ update_cost_retval = update_cost_heuristic(StartIndex,v3s16(0,0,0),0,0);
+ break;
+ default:
+ std::cout << "missing algorithm"<< std::endl;
+ break;
+ }
+
+ if (update_cost_retval) {
+
+#ifdef PATHFINDER_DEBUG
+ std::cout << "Path to target found!" << std::endl;
+ print_pathlen();
+#endif
+
+ //find path
+ std::vector<v3s16> path;
+ build_path(path,EndIndex,0);
+
+#ifdef PATHFINDER_DEBUG
+ std::cout << "Full index path:" << std::endl;
+ print_path(path);
+#endif
+
+ //optimize path
+ std::vector<v3s16> optimized_path;
+
+ std::vector<v3s16>::iterator startpos = path.begin();
+ optimized_path.push_back(source);
+
+ for (std::vector<v3s16>::iterator i = path.begin();
+ i != path.end(); i++) {
+ if (!m_env->line_of_sight(
+ tov3f(getIndexElement(*startpos).pos),
+ tov3f(getIndexElement(*i).pos))) {
+ optimized_path.push_back(getIndexElement(*(i-1)).pos);
+ startpos = (i-1);
+ }
+ }
+
+ optimized_path.push_back(destination);
+
+#ifdef PATHFINDER_DEBUG
+ std::cout << "Optimized path:" << std::endl;
+ print_path(optimized_path);
+#endif
+#ifdef PATHFINDER_CALC_TIME
+ timespec ts2;
+ clock_gettime(CLOCK_REALTIME, &ts2);
+
+ int ms = (ts2.tv_nsec - ts.tv_nsec)/(1000*1000);
+ int us = ((ts2.tv_nsec - ts.tv_nsec) - (ms*1000*1000))/1000;
+ int ns = ((ts2.tv_nsec - ts.tv_nsec) - ( (ms*1000*1000) + (us*1000)));
+
+
+ std::cout << "Calculating path took: " << (ts2.tv_sec - ts.tv_sec) <<
+ "s " << ms << "ms " << us << "us " << ns << "ns " << std::endl;
+#endif
+ return optimized_path;
+ }
+ else {
+#ifdef PATHFINDER_DEBUG
+ print_pathlen();
+#endif
+ std::cout << "failed to update cost map"<< std::endl;
+ }
+
+
+ //return
+ return retval;
+}
+
+/******************************************************************************/
+pathfinder::pathfinder() :
+ m_max_index_x(0),
+ m_max_index_y(0),
+ m_max_index_z(0),
+ m_searchdistance(0),
+ m_maxdrop(0),
+ m_maxjump(0),
+ m_min_target_distance(0),
+ m_prefetch(true),
+ m_start(0,0,0),
+ m_destination(0,0,0),
+ m_limits(),
+ m_data(),
+ m_env(0)
+{
+ //intentionaly empty
+}
+
+/******************************************************************************/
+v3s16 pathfinder::getRealPos(v3s16 ipos) {
+
+ v3s16 retval = ipos;
+
+ retval.X += m_limits.X.min;
+ retval.Y += m_limits.Y.min;
+ retval.Z += m_limits.Z.min;
+
+ return retval;
+}
+
+/******************************************************************************/
+bool pathfinder::build_costmap()
+{
+ INFO_TARGET << "Pathfinder build costmap: (" << m_limits.X.min << ","
+ << m_limits.Z.min << ") ("
+ << m_limits.X.max << ","
+ << m_limits.Z.max << ")"
+ << std::endl;
+ m_data.resize(m_max_index_x);
+ for (int x = 0; x < m_max_index_x; x++) {
+ m_data[x].resize(m_max_index_z);
+ for (int z = 0; z < m_max_index_z; z++) {
+ m_data[x][z].resize(m_max_index_y);
+
+ int surfaces = 0;
+ for (int y = 0; y < m_max_index_y; y++) {
+ v3s16 ipos(x,y,z);
+
+ v3s16 realpos = getRealPos(ipos);
+
+ MapNode current = m_env->getMap().getNodeNoEx(realpos);
+ MapNode below = m_env->getMap().getNodeNoEx(realpos + v3s16(0,-1,0));
+
+
+ if ((current.param0 == CONTENT_IGNORE) ||
+ (below.param0 == CONTENT_IGNORE)) {
+ DEBUG_OUT("Pathfinder: " << PPOS(realpos) <<
+ " current or below is invalid element" << std::endl);
+ if (current.param0 == CONTENT_IGNORE) {
+ m_data[x][z][y].type = 'i';
+ DEBUG_OUT(x << "," << y << "," << z << ": " << 'i' << std::endl);
+ }
+ continue;
+ }
+
+ //don't add anything if it isn't an air node
+ if ((current.param0 != CONTENT_AIR) ||
+ (below.param0 == CONTENT_AIR )) {
+ DEBUG_OUT("Pathfinder: " << PPOS(realpos)
+ << " not on surface" << std::endl);
+ if (current.param0 != CONTENT_AIR) {
+ m_data[x][z][y].type = 's';
+ DEBUG_OUT(x << "," << y << "," << z << ": " << 's' << std::endl);
+ }
+ else {
+ m_data[x][z][y].type = '-';
+ DEBUG_OUT(x << "," << y << "," << z << ": " << '-' << std::endl);
+ }
+ continue;
+ }
+
+ surfaces++;
+
+ m_data[x][z][y].valid = true;
+ m_data[x][z][y].pos = realpos;
+ m_data[x][z][y].type = 'g';
+ DEBUG_OUT(x << "," << y << "," << z << ": " << 'a' << std::endl);
+
+ if (m_prefetch) {
+ m_data[x][z][y].directions[DIR_XP] =
+ calc_cost(realpos,v3s16( 1,0, 0));
+ m_data[x][z][y].directions[DIR_XM] =
+ calc_cost(realpos,v3s16(-1,0, 0));
+ m_data[x][z][y].directions[DIR_ZP] =
+ calc_cost(realpos,v3s16( 0,0, 1));
+ m_data[x][z][y].directions[DIR_ZM] =
+ calc_cost(realpos,v3s16( 0,0,-1));
+ }
+
+ }
+
+ if (surfaces >= 1 ) {
+ for (int y = 0; y < m_max_index_y; y++) {
+ if (m_data[x][z][y].valid) {
+ m_data[x][z][y].surfaces = surfaces;
+ }
+ }
+ }
+ }
+ }
+ return true;
+}
+
+/******************************************************************************/
+path_cost pathfinder::calc_cost(v3s16 pos,v3s16 dir) {
+ path_cost retval;
+
+ retval.updated = true;
+
+ v3s16 pos2 = pos + dir;
+
+ //check limits
+ if ( (pos2.X < m_limits.X.min) ||
+ (pos2.X >= m_limits.X.max) ||
+ (pos2.Z < m_limits.Z.min) ||
+ (pos2.Z >= m_limits.Z.max)) {
+ DEBUG_OUT("Pathfinder: " << PPOS(pos2) <<
+ " no cost -> out of limits" << std::endl);
+ return retval;
+ }
+
+ MapNode node_at_pos2 = m_env->getMap().getNodeNoEx(pos2);
+
+ //did we get information about node?
+ if (node_at_pos2.param0 == CONTENT_IGNORE ) {
+ VERBOSE_TARGET << "Pathfinder: (1) area at pos: "
+ << PPOS(pos2) << " not loaded";
+ return retval;
+ }
+
+ if (node_at_pos2.param0 == CONTENT_AIR) {
+ MapNode node_below_pos2 =
+ m_env->getMap().getNodeNoEx(pos2 + v3s16(0,-1,0));
+
+ //did we get information about node?
+ if (node_below_pos2.param0 == CONTENT_IGNORE ) {
+ VERBOSE_TARGET << "Pathfinder: (2) area at pos: "
+ << PPOS((pos2 + v3s16(0,-1,0))) << " not loaded";
+ return retval;
+ }
+
+ if (node_below_pos2.param0 != CONTENT_AIR) {
+ retval.valid = true;
+ retval.value = 1;
+ retval.direction = 0;
+ DEBUG_OUT("Pathfinder: "<< PPOS(pos)
+ << " cost same height found" << std::endl);
+ }
+ else {
+ v3s16 testpos = pos2 - v3s16(0,-1,0);
+ MapNode node_at_pos = m_env->getMap().getNodeNoEx(testpos);
+
+ while ((node_at_pos.param0 != CONTENT_IGNORE) &&
+ (node_at_pos.param0 == CONTENT_AIR) &&
+ (testpos.Y > m_limits.Y.min)) {
+ testpos += v3s16(0,-1,0);
+ node_at_pos = m_env->getMap().getNodeNoEx(testpos);
+ }
+
+ //did we find surface?
+ if ((testpos.Y >= m_limits.Y.min) &&
+ (node_at_pos.param0 != CONTENT_IGNORE) &&
+ (node_at_pos.param0 != CONTENT_AIR)) {
+ if (((pos2.Y - testpos.Y)*-1) <= m_maxdrop) {
+ retval.valid = true;
+ retval.value = 2;
+ //difference of y-pos +1 (target node is ABOVE solid node)
+ retval.direction = ((testpos.Y - pos2.Y) +1);
+ DEBUG_OUT("Pathfinder cost below height found" << std::endl);
+ }
+ else {
+ INFO_TARGET << "Pathfinder:"
+ " distance to surface below to big: "
+ << (testpos.Y - pos2.Y) << " max: " << m_maxdrop
+ << std::endl;
+ }
+ }
+ else {
+ DEBUG_OUT("Pathfinder: no surface below found" << std::endl);
+ }
+ }
+ }
+ else {
+ v3s16 testpos = pos2;
+ MapNode node_at_pos = m_env->getMap().getNodeNoEx(testpos);
+
+ while ((node_at_pos.param0 != CONTENT_IGNORE) &&
+ (node_at_pos.param0 != CONTENT_AIR) &&
+ (testpos.Y < m_limits.Y.max)) {
+ testpos += v3s16(0,1,0);
+ node_at_pos = m_env->getMap().getNodeNoEx(testpos);
+ }
+
+ //did we find surface?
+ if ((testpos.Y <= m_limits.Y.max) &&
+ (node_at_pos.param0 == CONTENT_AIR)) {
+
+ if (testpos.Y - pos2.Y <= m_maxjump) {
+ retval.valid = true;
+ retval.value = 2;
+ retval.direction = (testpos.Y - pos2.Y);
+ DEBUG_OUT("Pathfinder cost above found" << std::endl);
+ }
+ else {
+ DEBUG_OUT("Pathfinder: distance to surface above to big: "
+ << (testpos.Y - pos2.Y) << " max: " << m_maxjump
+ << std::endl);
+ }
+ }
+ else {
+ DEBUG_OUT("Pathfinder: no surface above found" << std::endl);
+ }
+ }
+ return retval;
+}
+
+/******************************************************************************/
+v3s16 pathfinder::getIndexPos(v3s16 pos) {
+
+ v3s16 retval = pos;
+ retval.X -= m_limits.X.min;
+ retval.Y -= m_limits.Y.min;
+ retval.Z -= m_limits.Z.min;
+
+ return retval;
+}
+
+/******************************************************************************/
+path_gridnode& pathfinder::getIndexElement(v3s16 ipos) {
+ return m_data[ipos.X][ipos.Z][ipos.Y];
+}
+
+/******************************************************************************/
+bool pathfinder::valid_index(v3s16 index) {
+ if ( (index.X < m_max_index_x) &&
+ (index.Y < m_max_index_y) &&
+ (index.Z < m_max_index_z) &&
+ (index.X >= 0) &&
+ (index.Y >= 0) &&
+ (index.Z >= 0))
+ return true;
+
+ return false;
+}
+
+/******************************************************************************/
+v3s16 pathfinder::invert(v3s16 pos) {
+ v3s16 retval = pos;
+
+ retval.X *=-1;
+ retval.Y *=-1;
+ retval.Z *=-1;
+
+ return retval;
+}
+
+/******************************************************************************/
+bool pathfinder::update_all_costs( v3s16 ipos,
+ v3s16 srcdir,
+ int current_cost,
+ int level) {
+
+ path_gridnode& g_pos = getIndexElement(ipos);
+ g_pos.totalcost = current_cost;
+ g_pos.sourcedir = srcdir;
+
+ level ++;
+
+ //check if target has been found
+ if (g_pos.target) {
+ m_min_target_distance = current_cost;
+ DEBUG_OUT(LVL " Pathfinder: target found!" << std::endl);
+ return true;
+ }
+
+ bool retval = false;
+
+ std::vector<v3s16> directions;
+
+ directions.push_back(v3s16( 1,0, 0));
+ directions.push_back(v3s16(-1,0, 0));
+ directions.push_back(v3s16( 0,0, 1));
+ directions.push_back(v3s16( 0,0,-1));
+
+ for (unsigned int i=0; i < directions.size(); i++) {
+ if (directions[i] != srcdir) {
+ path_cost cost = g_pos.get_cost(directions[i]);
+
+ if (cost.valid) {
+ directions[i].Y = cost.direction;
+
+ v3s16 ipos2 = ipos + directions[i];
+
+ if (!valid_index(ipos2)) {
+ DEBUG_OUT(LVL " Pathfinder: " << PPOS(ipos2) <<
+ " out of range (" << m_limits.X.max << "," <<
+ m_limits.Y.max << "," << m_limits.Z.max
+ <<")" << std::endl);
+ continue;
+ }
+
+ path_gridnode& g_pos2 = getIndexElement(ipos2);
+
+ if (!g_pos2.valid) {
+ VERBOSE_TARGET << LVL "Pathfinder: no data for new position: "
+ << PPOS(ipos2) << std::endl;
+ continue;
+ }
+
+ assert(cost.value > 0);
+
+ int new_cost = current_cost + cost.value;
+
+ // check if there already is a smaller path
+ if ((m_min_target_distance > 0) &&
+ (m_min_target_distance < new_cost)) {
+ return false;
+ }
+
+ if ((g_pos2.totalcost < 0) ||
+ (g_pos2.totalcost > new_cost)) {
+ int old_cost = g_pos2.totalcost;
+ DEBUG_OUT(LVL "Pathfinder: updating path at: "<<
+ PPOS(ipos2) << " from: " << old_cost << " to "<<
+ new_cost << std::endl);
+ if (update_all_costs(ipos2,invert(directions[i]),
+ new_cost,level)) {
+ retval = true;
+ }
+ }
+ else {
+ DEBUG_OUT(LVL "Pathfinder:"
+ " already found shorter path to: "
+ << PPOS(ipos2) << std::endl);
+ }
+ }
+ else {
+ DEBUG_OUT(LVL "Pathfinder:"
+ " not moving to invalid direction: "
+ << PPOS(directions[i]) << std::endl);
+ }
+ }
+ }
+ return retval;
+}
+
+/******************************************************************************/
+int pathfinder::get_manhattandistance(v3s16 pos) {
+
+ int min_x = MYMIN(pos.X,m_destination.X);
+ int max_x = MYMAX(pos.X,m_destination.X);
+ int min_z = MYMIN(pos.Z,m_destination.Z);
+ int max_z = MYMAX(pos.Z,m_destination.Z);
+
+ return (max_x - min_x) + (max_z - min_z);
+}
+
+/******************************************************************************/
+v3s16 pathfinder::get_dir_heuristic(std::vector<v3s16>& directions,path_gridnode& g_pos) {
+ int minscore = -1;
+ v3s16 retdir = v3s16(0,0,0);
+ v3s16 srcpos = g_pos.pos;
+ DEBUG_OUT("Pathfinder: remaining dirs at beginning:"
+ << directions.size() << std::endl);
+
+ for (std::vector<v3s16>::iterator iter = directions.begin();
+ iter != directions.end();
+ iter ++) {
+
+ v3s16 pos1 = v3s16(srcpos.X + iter->X,0,srcpos.Z+iter->Z);
+
+ int cur_manhattan = get_manhattandistance(pos1);
+ path_cost cost = g_pos.get_cost(*iter);
+
+ if (!cost.updated) {
+ cost = calc_cost(g_pos.pos,*iter);
+ g_pos.set_cost(*iter,cost);
+ }
+
+ if (cost.valid) {
+ int score = cost.value + cur_manhattan;
+
+ if ((minscore < 0)|| (score < minscore)) {
+ minscore = score;
+ retdir = *iter;
+ }
+ }
+ }
+
+ if (retdir != v3s16(0,0,0)) {
+ for (std::vector<v3s16>::iterator iter = directions.begin();
+ iter != directions.end();
+ iter ++) {
+ if(*iter == retdir) {
+ DEBUG_OUT("Pathfinder: removing return direction" << std::endl);
+ directions.erase(iter);
+ break;
+ }
+ }
+ }
+ else {
+ DEBUG_OUT("Pathfinder: didn't find any valid direction clearing"
+ << std::endl);
+ directions.clear();
+ }
+ DEBUG_OUT("Pathfinder: remaining dirs at end:" << directions.size()
+ << std::endl);
+ return retdir;
+}
+
+/******************************************************************************/
+bool pathfinder::update_cost_heuristic( v3s16 ipos,
+ v3s16 srcdir,
+ int current_cost,
+ int level) {
+
+ path_gridnode& g_pos = getIndexElement(ipos);
+ g_pos.totalcost = current_cost;
+ g_pos.sourcedir = srcdir;
+
+ level ++;
+
+ //check if target has been found
+ if (g_pos.target) {
+ m_min_target_distance = current_cost;
+ DEBUG_OUT(LVL " Pathfinder: target found!" << std::endl);
+ return true;
+ }
+
+ bool retval = false;
+
+ std::vector<v3s16> directions;
+
+ directions.push_back(v3s16( 1,0, 0));
+ directions.push_back(v3s16(-1,0, 0));
+ directions.push_back(v3s16( 0,0, 1));
+ directions.push_back(v3s16( 0,0,-1));
+
+ v3s16 direction = get_dir_heuristic(directions,g_pos);
+
+ while (direction != v3s16(0,0,0) && (!retval)) {
+
+ if (direction != srcdir) {
+ path_cost cost = g_pos.get_cost(direction);
+
+ if (cost.valid) {
+ direction.Y = cost.direction;
+
+ v3s16 ipos2 = ipos + direction;
+
+ if (!valid_index(ipos2)) {
+ DEBUG_OUT(LVL " Pathfinder: " << PPOS(ipos2) <<
+ " out of range (" << m_limits.X.max << "," <<
+ m_limits.Y.max << "," << m_limits.Z.max
+ <<")" << std::endl);
+ continue;
+ }
+
+ path_gridnode& g_pos2 = getIndexElement(ipos2);
+
+ if (!g_pos2.valid) {
+ VERBOSE_TARGET << LVL "Pathfinder: no data for new position: "
+ << PPOS(ipos2) << std::endl;
+ continue;
+ }
+
+ assert(cost.value > 0);
+
+ int new_cost = current_cost + cost.value;
+
+ // check if there already is a smaller path
+ if ((m_min_target_distance > 0) &&
+ (m_min_target_distance < new_cost)) {
+ DEBUG_OUT(LVL "Pathfinder:"
+ " already longer than best already found path "
+ << PPOS(ipos2) << std::endl);
+ return false;
+ }
+
+ if ((g_pos2.totalcost < 0) ||
+ (g_pos2.totalcost > new_cost)) {
+ int old_cost = g_pos2.totalcost;
+ DEBUG_OUT(LVL "Pathfinder: updating path at: "<<
+ PPOS(ipos2) << " from: " << old_cost << " to "<<
+ new_cost << " srcdir=" <<
+ PPOS(invert(direction))<< std::endl);
+ if (update_cost_heuristic(ipos2,invert(direction),
+ new_cost,level)) {
+ retval = true;
+ }
+ }
+ else {
+ DEBUG_OUT(LVL "Pathfinder:"
+ " already found shorter path to: "
+ << PPOS(ipos2) << std::endl);
+ }
+ }
+ else {
+ DEBUG_OUT(LVL "Pathfinder:"
+ " not moving to invalid direction: "
+ << PPOS(direction) << std::endl);
+ }
+ }
+ else {
+ DEBUG_OUT(LVL "Pathfinder:"
+ " skipping srcdir: "
+ << PPOS(direction) << std::endl);
+ }
+ direction = get_dir_heuristic(directions,g_pos);
+ }
+ return retval;
+}
+
+/******************************************************************************/
+void pathfinder::build_path(std::vector<v3s16>& path,v3s16 pos, int level) {
+ level ++;
+ if (level > 1000) {
+ ERROR_TARGET
+ << LVL "Pathfinder: path is too long aborting" << std::endl;
+ return;
+ }
+
+ path_gridnode& g_pos = getIndexElement(pos);
+ if (!g_pos.valid) {
+ ERROR_TARGET
+ << LVL "Pathfinder: invalid next pos detected aborting" << std::endl;
+ return;
+ }
+
+ g_pos.is_element = true;
+
+ //check if source reached
+ if (g_pos.source) {
+ path.push_back(pos);
+ return;
+ }
+
+ build_path(path,pos + g_pos.sourcedir,level);
+ path.push_back(pos);
+}
+
+/******************************************************************************/
+v3f pathfinder::tov3f(v3s16 pos) {
+ return v3f(BS*pos.X,BS*pos.Y,BS*pos.Z);
+}
+
+#ifdef PATHFINDER_DEBUG
+
+/******************************************************************************/
+void pathfinder::print_cost() {
+ print_cost(DIR_XP);
+ print_cost(DIR_XM);
+ print_cost(DIR_ZP);
+ print_cost(DIR_ZM);
+}
+
+/******************************************************************************/
+void pathfinder::print_ydir() {
+ print_ydir(DIR_XP);
+ print_ydir(DIR_XM);
+ print_ydir(DIR_ZP);
+ print_ydir(DIR_ZM);
+}
+
+/******************************************************************************/
+void pathfinder::print_cost(path_directions dir) {
+
+ std::cout << "Cost in direction: " << dir_to_name(dir) << std::endl;
+ std::cout << std::setfill('-') << std::setw(80) << "-" << std::endl;
+ std::cout << std::setfill(' ');
+ for (int y = 0; y < m_max_index_y; y++) {
+
+ std::cout << "Level: " << y << std::endl;
+
+ std::cout << std::setw(4) << " " << " ";
+ for (int x = 0; x < m_max_index_x; x++) {
+ std::cout << std::setw(4) << x;
+ }
+ std::cout << std::endl;
+
+ for (int z = 0; z < m_max_index_z; z++) {
+ std::cout << std::setw(4) << z <<": ";
+ for (int x = 0; x < m_max_index_x; x++) {
+ if (m_data[x][z][y].directions[dir].valid)
+ std::cout << std::setw(4)
+ << m_data[x][z][y].directions[dir].value;
+ else
+ std::cout << std::setw(4) << "-";
+ }
+ std::cout << std::endl;
+ }
+ std::cout << std::endl;
+ }
+}
+
+/******************************************************************************/
+void pathfinder::print_ydir(path_directions dir) {
+
+ std::cout << "Height difference in direction: " << dir_to_name(dir) << std::endl;
+ std::cout << std::setfill('-') << std::setw(80) << "-" << std::endl;
+ std::cout << std::setfill(' ');
+ for (int y = 0; y < m_max_index_y; y++) {
+
+ std::cout << "Level: " << y << std::endl;
+
+ std::cout << std::setw(4) << " " << " ";
+ for (int x = 0; x < m_max_index_x; x++) {
+ std::cout << std::setw(4) << x;
+ }
+ std::cout << std::endl;
+
+ for (int z = 0; z < m_max_index_z; z++) {
+ std::cout << std::setw(4) << z <<": ";
+ for (int x = 0; x < m_max_index_x; x++) {
+ if (m_data[x][z][y].directions[dir].valid)
+ std::cout << std::setw(4)
+ << m_data[x][z][y].directions[dir].direction;
+ else
+ std::cout << std::setw(4) << "-";
+ }
+ std::cout << std::endl;
+ }
+ std::cout << std::endl;
+ }
+}
+
+/******************************************************************************/
+void pathfinder::print_type() {
+ std::cout << "Type of node:" << std::endl;
+ std::cout << std::setfill('-') << std::setw(80) << "-" << std::endl;
+ std::cout << std::setfill(' ');
+ for (int y = 0; y < m_max_index_y; y++) {
+
+ std::cout << "Level: " << y << std::endl;
+
+ std::cout << std::setw(3) << " " << " ";
+ for (int x = 0; x < m_max_index_x; x++) {
+ std::cout << std::setw(3) << x;
+ }
+ std::cout << std::endl;
+
+ for (int z = 0; z < m_max_index_z; z++) {
+ std::cout << std::setw(3) << z <<": ";
+ for (int x = 0; x < m_max_index_x; x++) {
+ char toshow = m_data[x][z][y].type;
+ std::cout << std::setw(3) << toshow;
+ }
+ std::cout << std::endl;
+ }
+ std::cout << std::endl;
+ }
+ std::cout << std::endl;
+}
+
+/******************************************************************************/
+void pathfinder::print_pathlen() {
+ std::cout << "Pathlen:" << std::endl;
+ std::cout << std::setfill('-') << std::setw(80) << "-" << std::endl;
+ std::cout << std::setfill(' ');
+ for (int y = 0; y < m_max_index_y; y++) {
+
+ std::cout << "Level: " << y << std::endl;
+
+ std::cout << std::setw(3) << " " << " ";
+ for (int x = 0; x < m_max_index_x; x++) {
+ std::cout << std::setw(3) << x;
+ }
+ std::cout << std::endl;
+
+ for (int z = 0; z < m_max_index_z; z++) {
+ std::cout << std::setw(3) << z <<": ";
+ for (int x = 0; x < m_max_index_x; x++) {
+ std::cout << std::setw(3) << m_data[x][z][y].totalcost;
+ }
+ std::cout << std::endl;
+ }
+ std::cout << std::endl;
+ }
+ std::cout << std::endl;
+}
+
+/******************************************************************************/
+std::string pathfinder::dir_to_name(path_directions dir) {
+ switch (dir) {
+ case DIR_XP:
+ return "XP";
+ break;
+ case DIR_XM:
+ return "XM";
+ break;
+ case DIR_ZP:
+ return "ZP";
+ break;
+ case DIR_ZM:
+ return "ZM";
+ break;
+ default:
+ return "UKN";
+ }
+}
+
+/******************************************************************************/
+void pathfinder::print_path(std::vector<v3s16> path) {
+
+ unsigned int current = 0;
+ for (std::vector<v3s16>::iterator i = path.begin();
+ i != path.end(); i++) {
+ std::cout << std::setw(3) << current << ":" << PPOS((*i)) << std::endl;
+ current++;
+ }
+}
+
+#endif
diff --git a/src/pathfinder.h b/src/pathfinder.h
new file mode 100644
index 000000000..7caf5844e
--- /dev/null
+++ b/src/pathfinder.h
@@ -0,0 +1,345 @@
+/*
+Minetest
+Copyright (C) 2013 sapier, sapier at gmx dot net
+
+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 PATHFINDER_H_
+#define PATHFINDER_H_
+
+/******************************************************************************/
+/* Includes */
+/******************************************************************************/
+#include <vector>
+
+#include "server.h"
+#include "irr_v3d.h"
+
+
+/******************************************************************************/
+/* Typedefs and macros */
+/******************************************************************************/
+
+//#define PATHFINDER_DEBUG
+
+typedef enum {
+ DIR_XP,
+ DIR_XM,
+ DIR_ZP,
+ DIR_ZM
+} path_directions;
+
+/** List of supported algorithms */
+typedef enum {
+ DIJKSTRA, /**< Dijkstra shortest path algorithm */
+ A_PLAIN, /**< A* algorithm using heuristics to find a path */
+ A_PLAIN_NP /**< A* algorithm without prefetching of map data */
+} algorithm;
+
+/******************************************************************************/
+/* declarations */
+/******************************************************************************/
+
+/** c wrapper function to use from scriptapi */
+std::vector<v3s16> get_Path(ServerEnvironment* env,
+ v3s16 source,
+ v3s16 destination,
+ unsigned int searchdistance,
+ unsigned int max_jump,
+ unsigned int max_drop,
+ algorithm algo);
+
+/** representation of cost in specific direction */
+class path_cost {
+public:
+
+ /** default constructor */
+ path_cost();
+
+ /** copy constructor */
+ path_cost(const path_cost& b);
+
+ /** assignment operator */
+ path_cost& operator= (const path_cost& b);
+
+ bool valid; /**< movement is possible */
+ int value; /**< cost of movement */
+ int direction; /**< y-direction of movement */
+ bool updated; /**< this cost has ben calculated */
+
+};
+
+
+/** representation of a mapnode to be used for pathfinding */
+class path_gridnode {
+
+public:
+ /** default constructor */
+ path_gridnode();
+
+ /** copy constructor */
+ path_gridnode(const path_gridnode& b);
+
+ /**
+ * assignment operator
+ * @param b node to copy
+ */
+ path_gridnode& operator= (const path_gridnode& b);
+
+ /**
+ * read cost in a specific direction
+ * @param dir direction of cost to fetch
+ */
+ path_cost get_cost(v3s16 dir);
+
+ /**
+ * set cost value for movement
+ * @param dir direction to set cost for
+ * @cost cost to set
+ */
+ void set_cost(v3s16 dir,path_cost cost);
+
+ bool valid; /**< node is on surface */
+ bool target; /**< node is target position */
+ bool source; /**< node is stating position */
+ int totalcost; /**< cost to move here from starting point */
+ v3s16 sourcedir; /**< origin of movement for current cost */
+ int surfaces; /**< number of surfaces with same x,z value*/
+ v3s16 pos; /**< real position of node */
+ path_cost directions[4]; /**< cost in different directions */
+
+ /* debug values */
+ bool is_element; /**< node is element of path detected */
+ char type; /**< type of node */
+};
+
+/** class doing pathfinding */
+class pathfinder {
+
+public:
+ /**
+ * default constructor
+ */
+ pathfinder();
+
+ /**
+ * path evaluation function
+ * @param env environment to look for path
+ * @param source origin of path
+ * @param destination end position of path
+ * @param searchdistance maximum number of nodes to look in each direction
+ * @param max_jump maximum number of blocks a path may jump up
+ * @param max_drop maximum number of blocks a path may drop
+ * @param algo algorithm to use for finding a path
+ */
+ std::vector<v3s16> get_Path(ServerEnvironment* env,
+ v3s16 source,
+ v3s16 destination,
+ unsigned int searchdistance,
+ unsigned int max_jump,
+ unsigned int max_drop,
+ algorithm algo);
+
+private:
+ /** data struct for storing internal information */
+ struct limits {
+ struct limit {
+ int min;
+ int max;
+ };
+
+ limit X;
+ limit Y;
+ limit Z;
+ };
+
+ /* helper functions */
+
+ /**
+ * transform index pos to mappos
+ * @param ipos a index position
+ * @return map position
+ */
+ v3s16 getRealPos(v3s16 ipos);
+
+ /**
+ * transform mappos to index pos
+ * @param pos a real pos
+ * @return index position
+ */
+ v3s16 getIndexPos(v3s16 pos);
+
+ /**
+ * get gridnode at a specific index position
+ * @param ipos index position
+ * @return gridnode for index
+ */
+ path_gridnode& getIndexElement(v3s16 ipos);
+
+ /**
+ * invert a 3d position
+ * @param pos 3d position
+ * @return pos *-1
+ */
+ v3s16 invert(v3s16 pos);
+
+ /**
+ * check if a index is within current search area
+ * @param index position to validate
+ * @return true/false
+ */
+ bool valid_index(v3s16 index);
+
+ /**
+ * translate position to float position
+ * @param pos integer position
+ * @return float position
+ */
+ v3f tov3f(v3s16 pos);
+
+
+ /* algorithm functions */
+
+ /**
+ * calculate 2d manahttan distance to target
+ * @param pos position to calc distance
+ * @return integer distance
+ */
+ int get_manhattandistance(v3s16 pos);
+
+ /**
+ * get best direction based uppon heuristics
+ * @param directions list of unchecked directions
+ * @param g_pos mapnode to start from
+ * @return direction to check
+ */
+ v3s16 get_dir_heuristic(std::vector<v3s16>& directions,path_gridnode& g_pos);
+
+ /**
+ * build internal data representation of search area
+ * @return true/false if costmap creation was successfull
+ */
+ bool build_costmap();
+
+ /**
+ * calculate cost of movement
+ * @param pos real world position to start movement
+ * @param dir direction to move to
+ * @return cost information
+ */
+ path_cost calc_cost(v3s16 pos,v3s16 dir);
+
+ /**
+ * recursive update whole search areas total cost information
+ * @param ipos position to check next
+ * @param srcdir positionc checked last time
+ * @param total_cost cost of moving to ipos
+ * @param level current recursion depth
+ * @return true/false path to destination has been found
+ */
+ bool update_all_costs(v3s16 ipos,v3s16 srcdir,int total_cost,int level);
+
+ /**
+ * recursive try to find a patrh to destionation
+ * @param ipos position to check next
+ * @param srcdir positionc checked last time
+ * @param total_cost cost of moving to ipos
+ * @param level current recursion depth
+ * @return true/false path to destination has been found
+ */
+ bool update_cost_heuristic(v3s16 ipos,v3s16 srcdir,int current_cost,int level);
+
+ /**
+ * recursive build a vector containing all nodes from source to destination
+ * @param path vector to add nodes to
+ * @param pos pos to check next
+ * @param level recursion depth
+ */
+ void build_path(std::vector<v3s16>& path,v3s16 pos, int level);
+
+ /* variables */
+ int m_max_index_x; /**< max index of search area in x direction */
+ int m_max_index_y; /**< max index of search area in y direction */
+ int m_max_index_z; /**< max index of search area in z direction */
+
+
+ int m_searchdistance; /**< max distance to search in each direction */
+ int m_maxdrop; /**< maximum number of blocks a path may drop */
+ int m_maxjump; /**< maximum number of blocks a path may jump */
+ int m_min_target_distance; /**< current smalest path to target */
+
+ bool m_prefetch; /**< prefetch cost data */
+
+ v3s16 m_start; /**< source position */
+ v3s16 m_destination; /**< destination position */
+
+ limits m_limits; /**< position limits in real map coordinates */
+
+ /** 3d grid containing all map data already collected and analyzed */
+ std::vector<std::vector<std::vector<path_gridnode> > > m_data;
+
+ ServerEnvironment* m_env; /**< minetest environment pointer */
+
+#ifdef PATHFINDER_DEBUG
+
+ /**
+ * print collected cost information
+ */
+ void print_cost();
+
+ /**
+ * print collected cost information in a specific direction
+ * @param dir direction to print
+ */
+ void print_cost(path_directions dir);
+
+ /**
+ * print type of node as evaluated
+ */
+ void print_type();
+
+ /**
+ * print pathlenght for all nodes in search area
+ */
+ void print_pathlen();
+
+ /**
+ * print a path
+ * @param path path to show
+ */
+ void print_path(std::vector<v3s16> path);
+
+ /**
+ * print y direction for all movements
+ */
+ void print_ydir();
+
+ /**
+ * print y direction for moving in a specific direction
+ * @param dir direction to show data
+ */
+ void print_ydir(path_directions dir);
+
+ /**
+ * helper function to translate a direction to speaking text
+ * @param dir direction to translate
+ * @return textual name of direction
+ */
+ std::string dir_to_name(path_directions dir);
+#endif
+};
+
+#endif /* PATHFINDER_H_ */
diff --git a/src/player.cpp b/src/player.cpp
index 4c81887be..1ca9423b0 100644
--- a/src/player.cpp
+++ b/src/player.cpp
@@ -71,6 +71,11 @@ Player::Player(IGameDef *gamedef):
movement_liquid_fluidity_smooth = 0.5 * BS;
movement_liquid_sink = 10 * BS;
movement_gravity = 9.81 * BS;
+
+ // Movement overrides are multipliers and must be 1 by default
+ physics_override_speed = 1;
+ physics_override_jump = 1;
+ physics_override_gravity = 1;
}
Player::~Player()
diff --git a/src/player.h b/src/player.h
index 496c99532..d95e535ff 100644
--- a/src/player.h
+++ b/src/player.h
@@ -222,6 +222,10 @@ public:
f32 movement_liquid_sink;
f32 movement_gravity;
+ float physics_override_speed;
+ float physics_override_jump;
+ float physics_override_gravity;
+
u16 hp;
float hurt_tilt_timer;
diff --git a/src/scriptapi.cpp b/src/scriptapi.cpp
index c372456d4..0227c6a19 100644
--- a/src/scriptapi.cpp
+++ b/src/scriptapi.cpp
@@ -616,76 +616,36 @@ static int l_get_server_status(lua_State *L)
return 1;
}
-// register_biome_groups({frequencies})
-static int l_register_biome_groups(lua_State *L)
-{
- luaL_checktype(L, 1, LUA_TTABLE);
- int index = 1;
-
- BiomeDefManager *bmgr = get_server(L)->getBiomeDef();
- if (!bmgr) {
- verbosestream << "register_biome_groups: BiomeDefManager not active" << std::endl;
- return 0;
- }
-
- lua_pushnil(L);
- for (int i = 1; lua_next(L, index) != 0; i++) {
- bmgr->addBiomeGroup(lua_tonumber(L, -1));
- lua_pop(L, 1);
- }
- lua_pop(L, 1);
-
- return 0;
-}
// register_biome({lots of stuff})
static int l_register_biome(lua_State *L)
{
- luaL_checktype(L, 1, LUA_TTABLE);
- int index = 1, groupid;
- std::string nodename;
+ int index = 1;
+ luaL_checktype(L, index, LUA_TTABLE);
- IWritableNodeDefManager *ndef = get_server(L)->getWritableNodeDefManager();
- BiomeDefManager *bmgr = get_server(L)->getBiomeDef();
+ BiomeDefManager *bmgr = get_server(L)->getEmergeManager()->biomedef;
if (!bmgr) {
verbosestream << "register_biome: BiomeDefManager not active" << std::endl;
return 0;
}
-
- groupid = getintfield_default(L, index, "group_id", 0);
-
+
enum BiomeTerrainType terrain = (BiomeTerrainType)getenumfield(L, index,
"terrain_type", es_BiomeTerrainType, BIOME_TERRAIN_NORMAL);
Biome *b = bmgr->createBiome(terrain);
- b->name = getstringfield_default(L, index, "name", "");
-
- if (getstringfield(L, index, "node_top", nodename))
- b->n_top = MapNode(ndef->getId(nodename));
- else
- b->n_top = MapNode(CONTENT_IGNORE);
-
- if (getstringfield(L, index, "node_filler", nodename))
- b->n_filler = MapNode(ndef->getId(nodename));
- else
- b->n_filler = b->n_top;
-
- b->ntopnodes = getintfield_default(L, index, "num_top_nodes", 0);
-
- b->height_min = getintfield_default(L, index, "height_min", 0);
- b->height_max = getintfield_default(L, index, "height_max", 0);
- b->heat_min = getfloatfield_default(L, index, "heat_min", 0.);
- b->heat_max = getfloatfield_default(L, index, "heat_max", 0.);
- b->humidity_min = getfloatfield_default(L, index, "humidity_min", 0.);
- b->humidity_max = getfloatfield_default(L, index, "humidity_max", 0.);
-
- b->np = new NoiseParams; // should read an entire NoiseParams later on...
- getfloatfield(L, index, "scale", b->np->scale);
- getfloatfield(L, index, "offset", b->np->offset);
-
- b->groupid = (s8)groupid;
- b->flags = 0; //reserved
-
+ b->name = getstringfield_default(L, index, "name", "");
+ b->top_nodename = getstringfield_default(L, index, "top_node", "");
+ b->top_depth = getintfield_default(L, index, "top_depth", 0);
+ b->filler_nodename = getstringfield_default(L, index, "filler_node", "");
+ b->filler_height = getintfield_default(L, index, "filler_height", 0);
+ b->height_min = getintfield_default(L, index, "height_min", 0);
+ b->height_max = getintfield_default(L, index, "height_max", 0);
+ b->heat_point = getfloatfield_default(L, index, "heat_point", 0.);
+ b->humidity_point = getfloatfield_default(L, index, "humidity_point", 0.);
+
+ b->flags = 0; //reserved
+ b->c_top = CONTENT_IGNORE;
+ b->c_filler = CONTENT_IGNORE;
bmgr->addBiome(b);
verbosestream << "register_biome: " << b->name << std::endl;
@@ -698,7 +658,6 @@ static int l_register_ore(lua_State *L)
int index = 1;
luaL_checktype(L, index, LUA_TTABLE);
- IWritableNodeDefManager *ndef = get_server(L)->getWritableNodeDefManager();
EmergeManager *emerge = get_server(L)->getEmergeManager();
enum OreType oretype = (OreType)getenumfield(L, index,
@@ -1113,7 +1072,6 @@ static const struct luaL_Reg minetest_f [] = {
{"register_alias_raw", l_register_alias_raw},
{"register_craft", l_register_craft},
{"register_biome", l_register_biome},
- {"register_biome_groups", l_register_biome_groups},
{"register_ore", l_register_ore},
{"setting_set", l_setting_set},
{"setting_get", l_setting_get},
diff --git a/src/scriptapi_env.cpp b/src/scriptapi_env.cpp
index 4e068e377..9bf7f0b55 100644
--- a/src/scriptapi_env.cpp
+++ b/src/scriptapi_env.cpp
@@ -26,6 +26,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "content_sao.h"
#include "script.h"
#include "treegen.h"
+#include "pathfinder.h"
#include "util/pointedthing.h"
#include "scriptapi_types.h"
#include "scriptapi_noise.h"
@@ -647,6 +648,69 @@ int EnvRef::l_clear_objects(lua_State *L)
return 0;
}
+int EnvRef::l_line_of_sight(lua_State *L) {
+ float stepsize = 1.0;
+
+ //infostream<<"EnvRef::l_get_node()"<<std::endl;
+ EnvRef *o = checkobject(L, 1);
+ ServerEnvironment *env = o->m_env;
+ if(env == NULL) return 0;
+
+ // read position 1 from lua
+ v3f pos1 = checkFloatPos(L, 2);
+ // read position 2 from lua
+ v3f pos2 = checkFloatPos(L, 2);
+ //read step size from lua
+ if(lua_isnumber(L, 3))
+ stepsize = lua_tonumber(L, 3);
+
+ return (env->line_of_sight(pos1,pos2,stepsize));
+}
+
+int EnvRef::l_find_path(lua_State *L)
+{
+ EnvRef *o = checkobject(L, 1);
+ ServerEnvironment *env = o->m_env;
+
+ if(env == NULL) return 0;
+
+ v3s16 pos1 = read_v3s16(L, 2);
+ v3s16 pos2 = read_v3s16(L, 3);
+ unsigned int searchdistance = luaL_checkint(L, 4);
+ unsigned int max_jump = luaL_checkint(L, 5);
+ unsigned int max_drop = luaL_checkint(L, 6);
+ algorithm algo = A_PLAIN_NP;
+ if(! lua_isnil(L, 7)) {
+ std::string algorithm = luaL_checkstring(L,7);
+
+ if (algorithm == "A*")
+ algo = A_PLAIN;
+
+ if (algorithm == "Dijkstra")
+ algo = DIJKSTRA;
+ }
+
+ std::vector<v3s16> path =
+ get_Path(env,pos1,pos2,searchdistance,max_jump,max_drop,algo);
+
+ if (path.size() > 0)
+ {
+ lua_newtable(L);
+ int top = lua_gettop(L);
+ unsigned int index = 1;
+ for (std::vector<v3s16>::iterator i = path.begin(); i != path.end();i++)
+ {
+ lua_pushnumber(L,index);
+ push_v3s16(L, *i);
+ lua_settable(L, top);
+ index++;
+ }
+ return 1;
+ }
+
+ return 0;
+}
+
int EnvRef::l_spawn_tree(lua_State *L)
{
EnvRef *o = checkobject(L, 1);
@@ -780,6 +844,8 @@ const luaL_reg EnvRef::methods[] = {
luamethod(EnvRef, get_perlin_map),
luamethod(EnvRef, clear_objects),
luamethod(EnvRef, spawn_tree),
+ luamethod(EnvRef, line_of_sight),
+ luamethod(EnvRef, find_path),
{0,0}
};
diff --git a/src/scriptapi_env.h b/src/scriptapi_env.h
index 1599969a4..2b7ea9573 100644
--- a/src/scriptapi_env.h
+++ b/src/scriptapi_env.h
@@ -137,6 +137,12 @@ private:
static int l_spawn_tree(lua_State *L);
+
+ static int l_line_of_sight(lua_State *L);
+
+ //find a path between two positions
+ static int l_find_path(lua_State *L);
+
public:
EnvRef(ServerEnvironment *env);
diff --git a/src/scriptapi_object.cpp b/src/scriptapi_object.cpp
index a0f93cbba..05433a598 100644
--- a/src/scriptapi_object.cpp
+++ b/src/scriptapi_object.cpp
@@ -297,6 +297,28 @@ int ObjectRef::l_set_armor_groups(lua_State *L)
return 0;
}
+// set_physics_override(self, physics_override_speed, physics_override_jump, physics_override_gravity)
+int ObjectRef::l_set_physics_override(lua_State *L)
+{
+ ObjectRef *ref = checkobject(L, 1);
+ PlayerSAO *co = (PlayerSAO *) getobject(ref);
+ if(co == NULL) return 0;
+ // Do it
+ if(!lua_isnil(L, 2)){
+ co->m_physics_override_speed = lua_tonumber(L, 2);
+ co->m_physics_override_sent = false;
+ }
+ if(!lua_isnil(L, 3)){
+ co->m_physics_override_jump = lua_tonumber(L, 3);
+ co->m_physics_override_sent = false;
+ }
+ if(!lua_isnil(L, 4)){
+ co->m_physics_override_gravity = lua_tonumber(L, 4);
+ co->m_physics_override_sent = false;
+ }
+ return 0;
+}
+
// set_animation(self, frame_range, frame_speed, frame_blend)
int ObjectRef::l_set_animation(lua_State *L)
{
@@ -756,6 +778,7 @@ const luaL_reg ObjectRef::methods[] = {
luamethod(ObjectRef, get_wielded_item),
luamethod(ObjectRef, set_wielded_item),
luamethod(ObjectRef, set_armor_groups),
+ luamethod(ObjectRef, set_physics_override),
luamethod(ObjectRef, set_animation),
luamethod(ObjectRef, set_bone_position),
luamethod(ObjectRef, set_attach),
diff --git a/src/scriptapi_object.h b/src/scriptapi_object.h
index a37abbb78..a44016933 100644
--- a/src/scriptapi_object.h
+++ b/src/scriptapi_object.h
@@ -103,6 +103,9 @@ private:
// set_armor_groups(self, groups)
static int l_set_armor_groups(lua_State *L);
+ // set_physics_override(self, physics_override_speed, physics_override_jump, physics_override_gravity)
+ static int l_set_physics_override(lua_State *L);
+
// set_animation(self, frame_range, frame_speed, frame_blend)
static int l_set_animation(lua_State *L);
diff --git a/src/server.cpp b/src/server.cpp
index c4dd0ab0f..05075a72c 100644
--- a/src/server.cpp
+++ b/src/server.cpp
@@ -646,7 +646,6 @@ Server::Server(
m_rollback_sink_enabled(true),
m_enable_rollback_recording(false),
m_emerge(NULL),
- m_biomedef(NULL),
m_lua(NULL),
m_itemdef(createItemDefManager()),
m_nodedef(createNodeDefManager()),
@@ -694,12 +693,9 @@ Server::Server(
Settings gamedefaults;
getGameMinetestConfig(gamespec.path, gamedefaults);
override_default_settings(g_settings, &gamedefaults);
-
- // Create biome definition manager
- m_biomedef = new BiomeDefManager(this);
// Create emerge manager
- m_emerge = new EmergeManager(this, m_biomedef);
+ m_emerge = new EmergeManager(this);
// Create rollback manager
std::string rollback_path = m_path_world+DIR_DELIM+"rollback.txt";
@@ -813,9 +809,6 @@ Server::Server(
// Apply item aliases in the node definition manager
m_nodedef->updateAliases(m_itemdef);
- // Add default biomes after nodedef had its aliases added
- m_biomedef->addDefaultBiomes();
-
// Initialize Environment
ServerMap *servermap = new ServerMap(path_world, this, m_emerge);
m_env = new ServerEnvironment(servermap, m_lua, this, this);
diff --git a/src/server.h b/src/server.h
index 04e693fc8..ea1cb79af 100644
--- a/src/server.h
+++ b/src/server.h
@@ -485,7 +485,6 @@ public:
void deleteParticleSpawner(const char *playername, u32 id);
void deleteParticleSpawnerAll(u32 id);
-
void queueBlockEmerge(v3s16 blockpos, bool allow_generate);
// Creates or resets inventory
@@ -497,11 +496,9 @@ public:
// Envlock should be locked when using the rollback manager
IRollbackManager *getRollbackManager(){ return m_rollback; }
- //TODO: determine what should be locked when accessing the emerge manager
+ //TODO: determine what (if anything) should be locked to access EmergeManager
EmergeManager *getEmergeManager(){ return m_emerge; }
- BiomeDefManager *getBiomeDef(){ return m_biomedef; }
-
// actions: time-reversed list
// Return value: success/failure
bool rollbackRevertActions(const std::list<RollbackAction> &actions,
@@ -734,9 +731,6 @@ private:
// Emerge manager
EmergeManager *m_emerge;
- // Biome Definition Manager
- BiomeDefManager *m_biomedef;
-
// Scripting
// Envlock and conlock should be locked when using Lua
lua_State *m_lua;
diff --git a/src/serverobject.h b/src/serverobject.h
index 7a5b47bd1..13a075a25 100644
--- a/src/serverobject.h
+++ b/src/serverobject.h
@@ -152,6 +152,8 @@ public:
virtual void setArmorGroups(const ItemGroupList &armor_groups)
{}
+ virtual void setPhysicsOverride(float physics_override_speed, float physics_override_jump, float physics_override_gravity)
+ {}
virtual void setAnimation(v2f frames, float frame_speed, float frame_blend)
{}
virtual void setBonePosition(std::string bone, v3f position, v3f rotation)
diff --git a/src/tile.cpp b/src/tile.cpp
index aea9665f5..c5e8a2a9d 100644
--- a/src/tile.cpp
+++ b/src/tile.cpp
@@ -826,7 +826,7 @@ void TextureSource::rebuildImagesAndTextures()
video::ITexture *t = NULL;
if(img)
t = driver->addTexture(sap->name.c_str(), img);
-
+ video::ITexture *t_old = sap->a.atlas;
// Replace texture
sap->a.atlas = t;
sap->a.pos = v2f(0,0);
@@ -835,6 +835,9 @@ void TextureSource::rebuildImagesAndTextures()
sap->atlas_img = img;
sap->intpos = v2s32(0,0);
sap->intsize = img->getDimension();
+
+ if (t_old != 0)
+ driver->removeTexture(t_old);
}
}