socket.cpp
mapblock.cpp
mapsector.cpp
- heightmap.cpp
map.cpp
player.cpp
utility.cpp
/*
This is good to be a bit different than 0 so that water level
- is not between to MapBlocks
+ is not between two MapBlocks
*/
-#define WATER_LEVEL 3
+#define WATER_LEVEL 1
// Length of cracking animation in count of images
#define CRACK_ANIMATION_LENGTH 5
+// Some stuff needed by old code moved to here from heightmap.h
+#define GROUNDHEIGHT_NOTFOUND_SETVALUE (-10e6)
+#define GROUNDHEIGHT_VALID_MINVALUE ( -9e6)
+
#endif
L"- Mouse left: dig blocks\n"\r
L"- Mouse right: place blocks\n"\r
L"- Mouse wheel: select item\n"\r
+ L"- 0...9: select item\n"\r
L"- R: Toggle viewing all loaded chunks\n"\r
L"- I: Inventory menu\n"\r
L"- ESC: This menu\n"\r
+++ /dev/null
-/*
-Minetest-c55
-Copyright (C) 2010 celeron55, Perttu Ahola <celeron55@gmail.com>
-
-This program is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2 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 General Public License for more details.
-
-You should have received a copy of the GNU 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.
-*/
-
-/*
-(c) 2010 Perttu Ahola <celeron55@gmail.com>
-*/
-
-#include "heightmap.h"
-
-// For MAP_BLOCKSIZE
-#include "mapblock.h"
-
-/*
- ValueGenerator
-*/
-
-ValueGenerator* ValueGenerator::deSerialize(std::string line)
-{
- std::istringstream ss(line);
- //ss.imbue(std::locale("C"));
-
- std::string name;
- std::getline(ss, name, ' ');
-
- if(name == "constant")
- {
- f32 value;
- ss>>value;
-
- return new ConstantGenerator(value);
- }
- else if(name == "linear")
- {
- f32 height;
- v2f slope;
-
- ss>>height;
- ss>>slope.X;
- ss>>slope.Y;
-
- return new LinearGenerator(height, slope);
- }
- else if(name == "power")
- {
- f32 height;
- v2f slope;
- f32 power;
-
- ss>>height;
- ss>>slope.X;
- ss>>slope.Y;
- ss>>power;
-
- return new PowerGenerator(height, slope, power);
- }
- else
- {
- throw SerializationError
- ("Invalid heightmap generator (deSerialize)");
- }
-}
-
-/*
- FixedHeightmap
-*/
-
-f32 FixedHeightmap::avgNeighbours(v2s16 p, s16 d)
-{
- v2s16 dirs[4] = {
- v2s16(1,0),
- v2s16(0,1),
- v2s16(-1,0),
- v2s16(0,-1)
- };
- f32 sum = 0.0;
- f32 count = 0.0;
- for(u16 i=0; i<4; i++){
- v2s16 p2 = p + dirs[i] * d;
- f32 n = getGroundHeightParent(p2);
- if(n < GROUNDHEIGHT_VALID_MINVALUE)
- continue;
- sum += n;
- count += 1.0;
- }
- assert(count > 0.001);
- return sum / count;
-}
-
-f32 FixedHeightmap::avgDiagNeighbours(v2s16 p, s16 d)
-{
- v2s16 dirs[4] = {
- v2s16(1,1),
- v2s16(-1,-1),
- v2s16(-1,1),
- v2s16(1,-1)
- };
- f32 sum = 0.0;
- f32 count = 0.0;
- for(u16 i=0; i<4; i++){
- v2s16 p2 = p + dirs[i] * d;
- f32 n = getGroundHeightParent(p2);
- if(n < GROUNDHEIGHT_VALID_MINVALUE)
- continue;
- sum += n;
- count += 1.0;
- }
- assert(count > 0.001);
- return sum / count;
-}
-
-/*
- Adds a point to transform into a diamond pattern
- center = Center of the diamond phase (center of a square)
- a = Side length of the existing square (2, 4, 8, ...)
-
- Adds the center points of the next squares to next_squares as
- dummy "true" values.
-*/
-void FixedHeightmap::makeDiamond(
- v2s16 center,
- s16 a,
- f32 randmax,
- core::map<v2s16, bool> &next_squares)
-{
- /*dstream<<"makeDiamond(): center="
- <<"("<<center.X<<","<<center.Y<<")"
- <<", a="<<a<<", randmax="<<randmax
- <<", next_squares.size()="<<next_squares.size()
- <<std::endl;*/
-
- f32 n = avgDiagNeighbours(center, a/2);
- // Add (-1.0...1.0) * randmax
- n += ((float)myrand() / (float)(MYRAND_MAX/2) - 1.0)*randmax;
- bool worked = setGroundHeightParent(center, n);
-
- if(a >= 2 && worked)
- {
- next_squares[center + a/2*v2s16(-1,0)] = true;
- next_squares[center + a/2*v2s16(1,0)] = true;
- next_squares[center + a/2*v2s16(0,-1)] = true;
- next_squares[center + a/2*v2s16(0,1)] = true;
- }
-}
-
-/*
- Adds a point to transform into a square pattern
- center = The point that is added. The center of a diamond.
- a = Diameter of the existing diamond. (2, 4, 8, 16, ...)
-
- Adds center points of the next diamonds to next_diamonds.
-*/
-void FixedHeightmap::makeSquare(
- v2s16 center,
- s16 a,
- f32 randmax,
- core::map<v2s16, bool> &next_diamonds)
-{
- /*dstream<<"makeSquare(): center="
- <<"("<<center.X<<","<<center.Y<<")"
- <<", a="<<a<<", randmax="<<randmax
- <<", next_diamonds.size()="<<next_diamonds.size()
- <<std::endl;*/
-
- f32 n = avgNeighbours(center, a/2);
- // Add (-1.0...1.0) * randmax
- n += ((float)myrand() / (float)(MYRAND_MAX/2) - 1.0)*randmax;
- bool worked = setGroundHeightParent(center, n);
-
- if(a >= 4 && worked)
- {
- next_diamonds[center + a/4*v2s16(1,1)] = true;
- next_diamonds[center + a/4*v2s16(-1,1)] = true;
- next_diamonds[center + a/4*v2s16(-1,-1)] = true;
- next_diamonds[center + a/4*v2s16(1,-1)] = true;
- }
-}
-
-void FixedHeightmap::DiamondSquare(f32 randmax, f32 randfactor)
-{
- u16 a;
- if(W < H)
- a = W-1;
- else
- a = H-1;
-
- // Check that a is a power of two
- if((a & (a-1)) != 0)
- throw;
-
- core::map<v2s16, bool> next_diamonds;
- core::map<v2s16, bool> next_squares;
-
- next_diamonds[v2s16(a/2, a/2)] = true;
-
- while(a >= 2)
- {
- next_squares.clear();
-
- for(core::map<v2s16, bool>::Iterator
- i = next_diamonds.getIterator();
- i.atEnd() == false; i++)
- {
- v2s16 p = i.getNode()->getKey();
- makeDiamond(p, a, randmax, next_squares);
- }
-
- //print();
-
- next_diamonds.clear();
-
- for(core::map<v2s16, bool>::Iterator
- i = next_squares.getIterator();
- i.atEnd() == false; i++)
- {
- v2s16 p = i.getNode()->getKey();
- makeSquare(p, a, randmax, next_diamonds);
- }
-
- //print();
-
- a /= 2;
- randmax *= randfactor;
- }
-}
-
-void FixedHeightmap::generateContinued(f32 randmax, f32 randfactor,
- f32 *corners)
-{
- DSTACK(__FUNCTION_NAME);
- /*dstream<<"FixedHeightmap("<<m_pos_on_master.X
- <<","<<m_pos_on_master.Y
- <<")::generateContinued()"<<std::endl;*/
-
- // Works only with blocksize=2,4,8,16,32,64,...
- s16 a = m_blocksize;
-
- // Check that a is a power of two
- assert((a & (a-1)) == 0);
-
- // Overwrite with GROUNDHEIGHT_NOTFOUND_SETVALUE
- for(s16 y=0; y<=a; y++){
- for(s16 x=0; x<=a; x++){
- v2s16 p(x,y);
- setGroundHeight(p, GROUNDHEIGHT_NOTFOUND_SETVALUE);
- }
- }
-
- /*
- Fill with corners[] (if not already set)
- */
- v2s16 dirs[4] = {
- v2s16(0,0),
- v2s16(1,0),
- v2s16(1,1),
- v2s16(0,1),
- };
- for(u16 i=0; i<4; i++){
- v2s16 npos = dirs[i] * a;
- // Don't replace already seeded corners
- f32 h = getGroundHeight(npos);
- if(h > GROUNDHEIGHT_VALID_MINVALUE)
- continue;
- setGroundHeight(dirs[i] * a, corners[i]);
- }
-
- /*dstream<<"corners filled:"<<std::endl;
- print();*/
-
- DiamondSquare(randmax, randfactor);
-}
-
-u32 FixedHeightmap::serializedLength(u8 version, u16 blocksize)
-{
- if(!ser_ver_supported(version))
- throw VersionMismatchException("ERROR: FixedHeightmap format not supported");
-
- // Any version
- {
- /*// [0] s32 blocksize
- // [4] v2s16 pos_on_master
- // [8] s32 data[W*H] (W=H=blocksize+1)
- return 4 + 4 + (blocksize+1)*(blocksize+1)*4;*/
-
- // [8] s32 data[W*H] (W=H=blocksize+1)
- return (blocksize+1)*(blocksize+1)*4;
- }
-}
-
-u32 FixedHeightmap::serializedLength(u8 version)
-{
- return serializedLength(version, m_blocksize);
-}
-
-void FixedHeightmap::serialize(u8 *dest, u8 version)
-{
- //dstream<<"FixedHeightmap::serialize"<<std::endl;
-
- if(!ser_ver_supported(version))
- throw VersionMismatchException("ERROR: FixedHeightmap format not supported");
-
- // Any version
- {
- /*writeU32(&dest[0], m_blocksize);
- writeV2S16(&dest[4], m_pos_on_master);
- u32 nodecount = W*H;
- for(u32 i=0; i<nodecount; i++)
- {
- writeS32(&dest[8+i*4], (s32)(m_data[i]*1000.0));
- }*/
-
- u32 nodecount = W*H;
- for(u32 i=0; i<nodecount; i++)
- {
- writeS32(&dest[i*4], (s32)(m_data[i]*1000.0));
- }
- }
-}
-
-void FixedHeightmap::deSerialize(u8 *source, u8 version)
-{
- /*dstream<<"FixedHeightmap::deSerialize m_blocksize="
- <<m_blocksize<<std::endl;*/
-
- if(!ser_ver_supported(version))
- throw VersionMismatchException("ERROR: FixedHeightmap format not supported");
-
- // Any version
- {
- u32 nodecount = (m_blocksize+1)*(m_blocksize+1);
- for(u32 i=0; i<nodecount; i++)
- {
- m_data[i] = ((f32)readS32(&source[i*4]))/1000.0;
- }
-
- /*printf("source[0,1,2,3]=%x,%x,%x,%x\n",
- (int)source[0]&0xff,
- (int)source[1]&0xff,
- (int)source[2]&0xff,
- (int)source[3]&0xff);
-
- dstream<<"m_data[0]="<<m_data[0]<<", "
- <<"readS32(&source[0])="<<readS32(&source[0])
- <<std::endl;
- dstream<<"m_data[4*4]="<<m_data[4*4]<<", "
- <<"readS32(&source[4*4])="<<readS32(&source[4*4])
- <<std::endl;*/
- }
-}
-
-
-void setcolor(f32 h, f32 rangemin, f32 rangemax)
-{
-#ifndef _WIN32
- const char *colors[] =
- {
- "\x1b[40m",
- "\x1b[44m",
- "\x1b[46m",
- "\x1b[42m",
- "\x1b[43m",
- "\x1b[41m",
- };
- u16 colorcount = sizeof(colors)/sizeof(colors[0]);
- f32 scaled = (h - rangemin) / (rangemax - rangemin);
- u8 color = scaled * colorcount;
- if(color > colorcount-1)
- color = colorcount-1;
- /*printf("rangemin=%f, rangemax=%f, h=%f -> color=%i\n",
- rangemin,
- rangemax,
- h,
- color);*/
- printf("%s", colors[color]);
- //printf("\x1b[31;40m");
- //printf("\x1b[44;1m");
-#endif
-}
-void resetcolor()
-{
-#ifndef _WIN32
- printf("\x1b[0m");
-#endif
-}
-
-/*
- UnlimitedHeightmap
-*/
-
-void UnlimitedHeightmap::print()
-{
- s16 minx = 10000;
- s16 miny = 10000;
- s16 maxx = -10000;
- s16 maxy = -10000;
- core::map<v2s16, FixedHeightmap*>::Iterator i;
- i = m_heightmaps.getIterator();
- if(i.atEnd()){
- printf("UnlimitedHeightmap::print(): empty.\n");
- return;
- }
- for(; i.atEnd() == false; i++)
- {
- v2s16 p = i.getNode()->getValue()->getPosOnMaster();
- if(p.X < minx) minx = p.X;
- if(p.Y < miny) miny = p.Y;
- if(p.X > maxx) maxx = p.X;
- if(p.Y > maxy) maxy = p.Y;
- }
- minx = minx * m_blocksize;
- miny = miny * m_blocksize;
- maxx = (maxx+1) * m_blocksize;
- maxy = (maxy+1) * m_blocksize;
- printf("UnlimitedHeightmap::print(): from (%i,%i) to (%i,%i)\n",
- minx, miny, maxx, maxy);
-
- // Calculate range
- f32 rangemin = 1e10;
- f32 rangemax = -1e10;
- for(s32 y=miny; y<=maxy; y++){
- for(s32 x=minx; x<=maxx; x++){
- f32 h = getGroundHeight(v2s16(x,y), false);
- if(h < GROUNDHEIGHT_VALID_MINVALUE)
- continue;
- if(h < rangemin)
- rangemin = h;
- if(h > rangemax)
- rangemax = h;
- }
- }
-
- printf(" ");
- for(s32 x=minx; x<=maxx; x++){
- printf("% .3d ", x);
- }
- printf("\n");
-
- for(s32 y=miny; y<=maxy; y++){
- printf("% .3d ", y);
- for(s32 x=minx; x<=maxx; x++){
- f32 n = getGroundHeight(v2s16(x,y), false);
- if(n < GROUNDHEIGHT_VALID_MINVALUE)
- printf(" - ");
- else
- {
- setcolor(n, rangemin, rangemax);
- printf("% -5.1f", getGroundHeight(v2s16(x,y), false));
- resetcolor();
- }
- }
- printf("\n");
- }
-}
-
-FixedHeightmap * UnlimitedHeightmap::getHeightmap(v2s16 p_from, bool generate)
-{
- DSTACK("UnlimitedHeightmap::getHeightmap()");
- /*
- We want to check that all neighbours of the wanted heightmap
- exist.
- This is because generating the neighboring heightmaps will
- modify the current one.
- */
-
- if(generate)
- {
- // Go through all neighbors (corners also) and the current one
- // and generate every one of them.
- for(s16 x=p_from.X-1; x<=p_from.X+1; x++)
- for(s16 y=p_from.Y-1; y<=p_from.Y+1; y++)
- {
- v2s16 p(x,y);
-
- // Check if exists
- core::map<v2s16, FixedHeightmap*>::Node *n = m_heightmaps.find(p);
- if(n != NULL)
- continue;
-
- // Doesn't exist
- // Generate it
-
- FixedHeightmap *heightmap = new FixedHeightmap(this, p, m_blocksize);
-
- m_heightmaps.insert(p, heightmap);
-
- f32 corners[4];
-
- s32 div = SECTOR_HEIGHTMAP_SPLIT * MAP_BLOCKSIZE;
-
- {
- PointAttributeList *palist = m_padb->getList("hm_baseheight");
-
- if(palist->empty())
- {
- corners[0] = 0;
- corners[1] = 0;
- corners[2] = 0;
- corners[3] = 0;
- }
- else
- {
-#if 0
- corners[0] = palist->getNearAttr((p+v2s16(0,0)) * div).getFloat();
- corners[1] = palist->getNearAttr((p+v2s16(1,0)) * div).getFloat();
- corners[2] = palist->getNearAttr((p+v2s16(1,1)) * div).getFloat();
- corners[3] = palist->getNearAttr((p+v2s16(0,1)) * div).getFloat();
-#endif
-#if 1
- corners[0] = palist->getInterpolatedFloat((p+v2s16(0,0))*div);
- corners[1] = palist->getInterpolatedFloat((p+v2s16(1,0))*div);
- corners[2] = palist->getInterpolatedFloat((p+v2s16(1,1))*div);
- corners[3] = palist->getInterpolatedFloat((p+v2s16(0,1))*div);
-#endif
- }
- }
- /*else
- {
- corners[0] = m_base_generator->getValue(p+v2s16(0,0));
- corners[1] = m_base_generator->getValue(p+v2s16(1,0));
- corners[2] = m_base_generator->getValue(p+v2s16(1,1));
- corners[3] = m_base_generator->getValue(p+v2s16(0,1));
- }*/
-
- /*f32 randmax = m_randmax_generator->getValue(p);
- f32 randfactor = m_randfactor_generator->getValue(p);*/
-
- f32 randmax = m_padb->getList("hm_randmax")
- ->getInterpolatedFloat(p*div);
- f32 randfactor = m_padb->getList("hm_randfactor")
- ->getInterpolatedFloat(p*div);
- //dstream<<"randmax="<<randmax<<" randfactor="<<randfactor<<std::endl;
-
- heightmap->generateContinued(randmax, randfactor, corners);
- }
- }
-
- core::map<v2s16, FixedHeightmap*>::Node *n = m_heightmaps.find(p_from);
-
- if(n != NULL)
- {
- return n->getValue();
- }
- else
- {
- throw InvalidPositionException
- ("Something went really wrong in UnlimitedHeightmap::getHeightmap");
- }
-}
-
-f32 UnlimitedHeightmap::getGroundHeight(v2s16 p, bool generate)
-{
- v2s16 heightmappos = getNodeHeightmapPos(p);
- v2s16 relpos = p - heightmappos*m_blocksize;
- try{
- FixedHeightmap * href = getHeightmap(heightmappos, generate);
- f32 h = href->getGroundHeight(relpos);
- if(h > GROUNDHEIGHT_VALID_MINVALUE)
- return h;
- }
- catch(InvalidPositionException){}
- /*
- If on border or in the (0,0) corner, try to get from
- overlapping heightmaps
- */
- if(relpos.X == 0){
- try{
- FixedHeightmap * href = getHeightmap(
- heightmappos-v2s16(1,0), false);
- f32 h = href->getGroundHeight(v2s16(m_blocksize, relpos.Y));
- if(h > GROUNDHEIGHT_VALID_MINVALUE)
- return h;
- }
- catch(InvalidPositionException){}
- }
- if(relpos.Y == 0){
- try{
- FixedHeightmap * href = getHeightmap(
- heightmappos-v2s16(0,1), false);
- f32 h = href->getGroundHeight(v2s16(relpos.X, m_blocksize));
- if(h > GROUNDHEIGHT_VALID_MINVALUE)
- return h;
- }
- catch(InvalidPositionException){}
- }
- if(relpos.X == 0 && relpos.Y == 0){
- try{
- FixedHeightmap * href = getHeightmap(
- heightmappos-v2s16(1,1), false);
- f32 h = href->getGroundHeight(v2s16(m_blocksize, m_blocksize));
- if(h > GROUNDHEIGHT_VALID_MINVALUE)
- return h;
- }
- catch(InvalidPositionException){}
- }
- return GROUNDHEIGHT_NOTFOUND_SETVALUE;
-}
-
-void UnlimitedHeightmap::setGroundHeight(v2s16 p, f32 y, bool generate)
-{
- bool was_set = false;
-
- v2s16 heightmappos = getNodeHeightmapPos(p);
- v2s16 relpos = p - heightmappos*m_blocksize;
- /*dstream<<"UnlimitedHeightmap::setGroundHeight(("
- <<p.X<<","<<p.Y<<"), "<<y<<"): "
- <<"heightmappos=("<<heightmappos.X<<","
- <<heightmappos.Y<<") relpos=("
- <<relpos.X<<","<<relpos.Y<<")"
- <<std::endl;*/
- try{
- FixedHeightmap * href = getHeightmap(heightmappos, generate);
- href->setGroundHeight(relpos, y);
- was_set = true;
- }catch(InvalidPositionException){}
- // Update in neighbour heightmap if it's at border
- if(relpos.X == 0){
- try{
- FixedHeightmap * href = getHeightmap(
- heightmappos-v2s16(1,0), generate);
- href->setGroundHeight(v2s16(m_blocksize, relpos.Y), y);
- was_set = true;
- }catch(InvalidPositionException){}
- }
- if(relpos.Y == 0){
- try{
- FixedHeightmap * href = getHeightmap(
- heightmappos-v2s16(0,1), generate);
- href->setGroundHeight(v2s16(relpos.X, m_blocksize), y);
- was_set = true;
- }catch(InvalidPositionException){}
- }
- if(relpos.X == 0 && relpos.Y == 0){
- try{
- FixedHeightmap * href = getHeightmap(
- heightmappos-v2s16(1,1), generate);
- href->setGroundHeight(v2s16(m_blocksize, m_blocksize), y);
- was_set = true;
- }catch(InvalidPositionException){}
- }
-
- if(was_set == false)
- {
- throw InvalidPositionException
- ("UnlimitedHeightmap failed to set height");
- }
-}
-
-
-void UnlimitedHeightmap::serialize(std::ostream &os, u8 version)
-{
- //dstream<<"UnlimitedHeightmap::serialize()"<<std::endl;
-
- if(!ser_ver_supported(version))
- throw VersionMismatchException
- ("ERROR: UnlimitedHeightmap format not supported");
-
- if(version <= 7)
- {
- /*if(m_base_generator->getId() != VALUE_GENERATOR_ID_CONSTANT
- || m_randmax_generator->getId() != VALUE_GENERATOR_ID_CONSTANT
- || m_randfactor_generator->getId() != VALUE_GENERATOR_ID_CONSTANT)*/
- /*if(std::string(m_base_generator->getName()) != "constant"
- || std::string(m_randmax_generator->getName()) != "constant"
- || std::string(m_randfactor_generator->getName()) != "constant")
- {
- throw SerializationError
- ("Cannot write UnlimitedHeightmap in old version: "
- "Generators are not ConstantGenerators.");
- }*/
-
- // Dummy values
- f32 basevalue = 0.0;
- f32 randmax = 0.0;
- f32 randfactor = 0.0;
-
- // Write version
- os.write((char*)&version, 1);
-
- /*
- [0] u16 blocksize
- [2] s32 randmax*1000
- [6] s32 randfactor*1000
- [10] s32 basevalue*1000
- [14] u32 heightmap_count
- [18] X * (v2s16 pos + heightmap)
- */
- u32 heightmap_size =
- FixedHeightmap::serializedLength(version, m_blocksize);
- u32 heightmap_count = m_heightmaps.size();
-
- //dstream<<"heightmap_size="<<heightmap_size<<std::endl;
-
- u32 datasize = 2+4+4+4+4+heightmap_count*(4+heightmap_size);
- SharedBuffer<u8> data(datasize);
-
- writeU16(&data[0], m_blocksize);
- writeU32(&data[2], (s32)(randmax*1000.0));
- writeU32(&data[6], (s32)(randfactor*1000.0));
- writeU32(&data[10], (s32)(basevalue*1000.0));
- writeU32(&data[14], heightmap_count);
-
- core::map<v2s16, FixedHeightmap*>::Iterator j;
- j = m_heightmaps.getIterator();
- u32 i=0;
- for(; j.atEnd() == false; j++)
- {
- FixedHeightmap *hm = j.getNode()->getValue();
- v2s16 pos = j.getNode()->getKey();
- writeV2S16(&data[18+i*(4+heightmap_size)], pos);
- hm->serialize(&data[18+i*(4+heightmap_size)+4], version);
- i++;
- }
-
- os.write((char*)*data, data.getSize());
- }
- else if(version <= 11)
- {
- // Write version
- os.write((char*)&version, 1);
-
- u8 buf[4];
-
- writeU16(buf, m_blocksize);
- os.write((char*)buf, 2);
-
- /*m_randmax_generator->serialize(os);
- m_randfactor_generator->serialize(os);
- m_base_generator->serialize(os);*/
- os<<"constant 0.0\n";
- os<<"constant 0.0\n";
- os<<"constant 0.0\n";
-
- u32 heightmap_count = m_heightmaps.size();
- writeU32(buf, heightmap_count);
- os.write((char*)buf, 4);
-
- u32 heightmap_size =
- FixedHeightmap::serializedLength(version, m_blocksize);
-
- SharedBuffer<u8> hmdata(heightmap_size);
-
- core::map<v2s16, FixedHeightmap*>::Iterator j;
- j = m_heightmaps.getIterator();
- u32 i=0;
- for(; j.atEnd() == false; j++)
- {
- v2s16 pos = j.getNode()->getKey();
- writeV2S16(buf, pos);
- os.write((char*)buf, 4);
-
- FixedHeightmap *hm = j.getNode()->getValue();
- hm->serialize(*hmdata, version);
- os.write((char*)*hmdata, hmdata.getSize());
-
- i++;
- }
- }
- else
- {
- // Write version
- os.write((char*)&version, 1);
-
- u8 buf[4];
-
- writeU16(buf, m_blocksize);
- os.write((char*)buf, 2);
-
- /*m_randmax_generator->serialize(os);
- m_randfactor_generator->serialize(os);
- m_base_generator->serialize(os);*/
-
- u32 heightmap_count = m_heightmaps.size();
- writeU32(buf, heightmap_count);
- os.write((char*)buf, 4);
-
- u32 heightmap_size =
- FixedHeightmap::serializedLength(version, m_blocksize);
-
- SharedBuffer<u8> hmdata(heightmap_size);
-
- core::map<v2s16, FixedHeightmap*>::Iterator j;
- j = m_heightmaps.getIterator();
- u32 i=0;
- for(; j.atEnd() == false; j++)
- {
- v2s16 pos = j.getNode()->getKey();
- writeV2S16(buf, pos);
- os.write((char*)buf, 4);
-
- FixedHeightmap *hm = j.getNode()->getValue();
- hm->serialize(*hmdata, version);
- os.write((char*)*hmdata, hmdata.getSize());
-
- i++;
- }
- }
-
-#if 0
- if(version <= 7)
- {
- /*if(m_base_generator->getId() != VALUE_GENERATOR_ID_CONSTANT
- || m_randmax_generator->getId() != VALUE_GENERATOR_ID_CONSTANT
- || m_randfactor_generator->getId() != VALUE_GENERATOR_ID_CONSTANT)*/
- if(std::string(m_base_generator->getName()) != "constant"
- || std::string(m_randmax_generator->getName()) != "constant"
- || std::string(m_randfactor_generator->getName()) != "constant")
- {
- throw SerializationError
- ("Cannot write UnlimitedHeightmap in old version: "
- "Generators are not ConstantGenerators.");
- }
-
- f32 basevalue = ((ConstantGenerator*)m_base_generator)->m_value;
- f32 randmax = ((ConstantGenerator*)m_randmax_generator)->m_value;
- f32 randfactor = ((ConstantGenerator*)m_randfactor_generator)->m_value;
-
- // Write version
- os.write((char*)&version, 1);
-
- /*
- [0] u16 blocksize
- [2] s32 randmax*1000
- [6] s32 randfactor*1000
- [10] s32 basevalue*1000
- [14] u32 heightmap_count
- [18] X * (v2s16 pos + heightmap)
- */
- u32 heightmap_size =
- FixedHeightmap::serializedLength(version, m_blocksize);
- u32 heightmap_count = m_heightmaps.size();
-
- //dstream<<"heightmap_size="<<heightmap_size<<std::endl;
-
- u32 datasize = 2+4+4+4+4+heightmap_count*(4+heightmap_size);
- SharedBuffer<u8> data(datasize);
-
- writeU16(&data[0], m_blocksize);
- writeU32(&data[2], (s32)(randmax*1000.0));
- writeU32(&data[6], (s32)(randfactor*1000.0));
- writeU32(&data[10], (s32)(basevalue*1000.0));
- writeU32(&data[14], heightmap_count);
-
- core::map<v2s16, FixedHeightmap*>::Iterator j;
- j = m_heightmaps.getIterator();
- u32 i=0;
- for(; j.atEnd() == false; j++)
- {
- FixedHeightmap *hm = j.getNode()->getValue();
- v2s16 pos = j.getNode()->getKey();
- writeV2S16(&data[18+i*(4+heightmap_size)], pos);
- hm->serialize(&data[18+i*(4+heightmap_size)+4], version);
- i++;
- }
-
- os.write((char*)*data, data.getSize());
- }
- else
- {
- // Write version
- os.write((char*)&version, 1);
-
- u8 buf[4];
-
- writeU16(buf, m_blocksize);
- os.write((char*)buf, 2);
-
- /*m_randmax_generator->serialize(os, version);
- m_randfactor_generator->serialize(os, version);
- m_base_generator->serialize(os, version);*/
- m_randmax_generator->serialize(os);
- m_randfactor_generator->serialize(os);
- m_base_generator->serialize(os);
-
- u32 heightmap_count = m_heightmaps.size();
- writeU32(buf, heightmap_count);
- os.write((char*)buf, 4);
-
- u32 heightmap_size =
- FixedHeightmap::serializedLength(version, m_blocksize);
-
- SharedBuffer<u8> hmdata(heightmap_size);
-
- core::map<v2s16, FixedHeightmap*>::Iterator j;
- j = m_heightmaps.getIterator();
- u32 i=0;
- for(; j.atEnd() == false; j++)
- {
- v2s16 pos = j.getNode()->getKey();
- writeV2S16(buf, pos);
- os.write((char*)buf, 4);
-
- FixedHeightmap *hm = j.getNode()->getValue();
- hm->serialize(*hmdata, version);
- os.write((char*)*hmdata, hmdata.getSize());
-
- i++;
- }
- }
-#endif
-}
-
-UnlimitedHeightmap * UnlimitedHeightmap::deSerialize(std::istream &is,
- PointAttributeDatabase *padb)
-{
- u8 version;
- is.read((char*)&version, 1);
-
- if(!ser_ver_supported(version))
- throw VersionMismatchException("ERROR: UnlimitedHeightmap format not supported");
-
- if(version <= 7)
- {
- /*
- [0] u16 blocksize
- [2] s32 randmax*1000
- [6] s32 randfactor*1000
- [10] s32 basevalue*1000
- [14] u32 heightmap_count
- [18] X * (v2s16 pos + heightmap)
- */
- SharedBuffer<u8> data(18);
- is.read((char*)*data, 18);
- if(is.gcount() != 18)
- throw SerializationError
- ("UnlimitedHeightmap::deSerialize: no enough input data");
- s16 blocksize = readU16(&data[0]);
- // Dummy read randmax, randfactor, basevalue
- /*f32 randmax = (f32)*/readU32(&data[2]) /*/ 1000.0*/;
- /*f32 randfactor = (f32)*/readU32(&data[6]) /*/ 1000.0*/;
- /*f32 basevalue = (f32)*/readU32(&data[10]) /*/ 1000.0*/;
- u32 heightmap_count = readU32(&data[14]);
-
- /*dstream<<"UnlimitedHeightmap::deSerialize():"
- <<" blocksize="<<blocksize
- <<" heightmap_count="<<heightmap_count
- <<std::endl;*/
-
- u32 heightmap_size =
- FixedHeightmap::serializedLength(version, blocksize);
-
- //dstream<<"heightmap_size="<<heightmap_size<<std::endl;
-
- /*ValueGenerator *maxgen = new ConstantGenerator(randmax);
- ValueGenerator *factorgen = new ConstantGenerator(randfactor);
- ValueGenerator *basegen = new ConstantGenerator(basevalue);*/
-
- UnlimitedHeightmap *hm = new UnlimitedHeightmap
- (blocksize, padb);
-
- for(u32 i=0; i<heightmap_count; i++)
- {
- //dstream<<"i="<<i<<std::endl;
- SharedBuffer<u8> data(4+heightmap_size);
- is.read((char*)*data, 4+heightmap_size);
- if(is.gcount() != (s32)(4+heightmap_size)){
- delete hm;
- throw SerializationError
- ("UnlimitedHeightmap::deSerialize: no enough input data");
- }
- v2s16 pos = readV2S16(&data[0]);
- FixedHeightmap *f = new FixedHeightmap(hm, pos, blocksize);
- f->deSerialize(&data[4], version);
- hm->m_heightmaps.insert(pos, f);
- }
- return hm;
- }
- else if(version <= 11)
- {
- u8 buf[4];
-
- is.read((char*)buf, 2);
- s16 blocksize = readU16(buf);
-
- // Dummy-read three lines (generators)
- std::string templine;
- std::getline(is, templine, '\n');
-
- is.read((char*)buf, 4);
- u32 heightmap_count = readU32(buf);
-
- u32 heightmap_size =
- FixedHeightmap::serializedLength(version, blocksize);
-
- UnlimitedHeightmap *hm = new UnlimitedHeightmap
- (blocksize, padb);
-
- for(u32 i=0; i<heightmap_count; i++)
- {
- is.read((char*)buf, 4);
- v2s16 pos = readV2S16(buf);
-
- SharedBuffer<u8> data(heightmap_size);
- is.read((char*)*data, heightmap_size);
- if(is.gcount() != (s32)(heightmap_size)){
- delete hm;
- throw SerializationError
- ("UnlimitedHeightmap::deSerialize: no enough input data");
- }
- FixedHeightmap *f = new FixedHeightmap(hm, pos, blocksize);
- f->deSerialize(*data, version);
- hm->m_heightmaps.insert(pos, f);
- }
- return hm;
- }
- else
- {
- u8 buf[4];
-
- is.read((char*)buf, 2);
- s16 blocksize = readU16(buf);
-
- /*ValueGenerator *maxgen = ValueGenerator::deSerialize(is);
- ValueGenerator *factorgen = ValueGenerator::deSerialize(is);
- ValueGenerator *basegen = ValueGenerator::deSerialize(is);*/
-
- is.read((char*)buf, 4);
- u32 heightmap_count = readU32(buf);
-
- u32 heightmap_size =
- FixedHeightmap::serializedLength(version, blocksize);
-
- UnlimitedHeightmap *hm = new UnlimitedHeightmap
- (blocksize, padb);
-
- for(u32 i=0; i<heightmap_count; i++)
- {
- is.read((char*)buf, 4);
- v2s16 pos = readV2S16(buf);
-
- SharedBuffer<u8> data(heightmap_size);
- is.read((char*)*data, heightmap_size);
- if(is.gcount() != (s32)(heightmap_size)){
- delete hm;
- throw SerializationError
- ("UnlimitedHeightmap::deSerialize: no enough input data");
- }
- FixedHeightmap *f = new FixedHeightmap(hm, pos, blocksize);
- f->deSerialize(*data, version);
- hm->m_heightmaps.insert(pos, f);
- }
- return hm;
- }
-}
-
-
+++ /dev/null
-/*
-Minetest-c55
-Copyright (C) 2010 celeron55, Perttu Ahola <celeron55@gmail.com>
-
-This program is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2 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 General Public License for more details.
-
-You should have received a copy of the GNU 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 HEIGHTMAP_HEADER
-#define HEIGHTMAP_HEADER
-
-#include <iostream>
-#include <time.h>
-#include <sstream>
-
-#include "debug.h"
-#include "common_irrlicht.h"
-#include "exceptions.h"
-#include "utility.h"
-#include "serialization.h"
-
-#define GROUNDHEIGHT_NOTFOUND_SETVALUE (-10e6)
-#define GROUNDHEIGHT_VALID_MINVALUE ( -9e6)
-
-class Heightmappish
-{
-public:
- virtual f32 getGroundHeight(v2s16 p, bool generate=true) = 0;
- virtual void setGroundHeight(v2s16 p, f32 y, bool generate=true) = 0;
-
- v2f32 getSlope(v2s16 p)
- {
- f32 y0 = getGroundHeight(p, false);
-
- v2s16 dirs[] = {
- v2s16(1,0),
- v2s16(0,1),
- };
-
- v2f32 fdirs[] = {
- v2f32(1,0),
- v2f32(0,1),
- };
-
- v2f32 slopevector(0.0, 0.0);
-
- for(u16 i=0; i<2; i++){
- f32 y1 = 0.0;
- f32 y2 = 0.0;
- f32 count = 0.0;
-
- v2s16 p1 = p - dirs[i];
- y1 = getGroundHeight(p1, false);
- if(y1 > GROUNDHEIGHT_VALID_MINVALUE){
- y1 -= y0;
- count += 1.0;
- }
- else
- y1 = 0;
-
- v2s16 p2 = p + dirs[i];
- y2 = getGroundHeight(p2, false);
- if(y2 > GROUNDHEIGHT_VALID_MINVALUE){
- y2 -= y0;
- count += 1.0;
- }
- else
- y2 = 0;
-
- if(count < 0.001)
- return v2f32(0.0, 0.0);
-
- /*
- If y2 is higher than y1, slope is positive
- */
- f32 slope = (y2 - y1)/count;
-
- slopevector += fdirs[i] * slope;
- }
-
- return slopevector;
- }
-
-};
-
-// TODO: Get rid of this dummy wrapper
-class Heightmap : public Heightmappish /*, public ReferenceCounted*/
-{
-};
-
-class WrapperHeightmap : public Heightmap
-{
- Heightmappish *m_target;
-public:
-
- WrapperHeightmap(Heightmappish *target):
- m_target(target)
- {
- if(target == NULL)
- throw NullPointerException();
- }
-
- f32 getGroundHeight(v2s16 p, bool generate=true)
- {
- return m_target->getGroundHeight(p, generate);
- }
- void setGroundHeight(v2s16 p, f32 y, bool generate=true)
- {
- m_target->setGroundHeight(p, y, generate);
- }
-};
-
-/*
- Base class that defines a generator that gives out values at
- positions in 2-dimensional space.
- Can be given to UnlimitedHeightmap to feed stuff.
-
- These are always serialized as readable text ending in "\n"
-*/
-class ValueGenerator
-{
-public:
- ValueGenerator(){}
- virtual ~ValueGenerator(){}
-
- static ValueGenerator* deSerialize(std::string line);
-
- static ValueGenerator* deSerialize(std::istream &is)
- {
- std::string line;
- std::getline(is, line, '\n');
- return deSerialize(line);
- }
-
- void serializeBase(std::ostream &os)
- {
- os<<getName()<<" ";
- }
-
- // Virtual methods
- virtual const char * getName() const = 0;
- virtual f32 getValue(v2s16 p) = 0;
- virtual void serialize(std::ostream &os) = 0;
-};
-
-class ConstantGenerator : public ValueGenerator
-{
-public:
- f32 m_value;
-
- ConstantGenerator(f32 value)
- {
- m_value = value;
- }
-
- const char * getName() const
- {
- return "constant";
- }
-
- f32 getValue(v2s16 p)
- {
- return m_value;
- }
-
- void serialize(std::ostream &os)
- {
- serializeBase(os);
-
- std::ostringstream ss;
- //ss.imbue(std::locale("C"));
-
- ss<<m_value<<"\n";
-
- os<<ss.str();
- }
-};
-
-class LinearGenerator : public ValueGenerator
-{
-public:
- f32 m_height;
- v2f m_slope;
-
- LinearGenerator(f32 height, v2f slope)
- {
- m_height = height;
- m_slope = slope;
- }
-
- const char * getName() const
- {
- return "linear";
- }
-
- f32 getValue(v2s16 p)
- {
- return m_height + m_slope.X * p.X + m_slope.Y * p.Y;
- }
-
- void serialize(std::ostream &os)
- {
- serializeBase(os);
-
- std::ostringstream ss;
- //ss.imbue(std::locale("C"));
-
- ss<<m_height<<" "<<m_slope.X<<" "<<m_slope.Y<<"\n";
-
- os<<ss.str();
- }
-};
-
-class PowerGenerator : public ValueGenerator
-{
-public:
- f32 m_height;
- v2f m_slope;
- f32 m_power;
-
- PowerGenerator(f32 height, v2f slope, f32 power)
- {
- m_height = height;
- m_slope = slope;
- m_power = power;
- }
-
- const char * getName() const
- {
- return "power";
- }
-
- f32 getValue(v2s16 p)
- {
- return m_height
- + m_slope.X * pow((f32)p.X, m_power)
- + m_slope.Y * pow((f32)p.Y, m_power);
- }
-
- void serialize(std::ostream &os)
- {
- serializeBase(os);
-
- std::ostringstream ss;
- //ss.imbue(std::locale("C"));
-
- ss<<m_height<<" "
- <<m_slope.X<<" "
- <<m_slope.Y<<" "
- <<m_power<<"\n";
-
- os<<ss.str();
- }
-};
-
-class FixedHeightmap : public Heightmap
-{
- // A meta-heightmap on which this heightmap is located
- // (at m_pos_on_master * m_blocksize)
- Heightmap * m_master;
- // Position on master heightmap (in blocks)
- v2s16 m_pos_on_master;
- s32 m_blocksize; // This is (W-1) = (H-1)
- // These are the actual size of the data
- s32 W;
- s32 H;
- f32 *m_data;
-
-public:
-
- FixedHeightmap(Heightmap * master,
- v2s16 pos_on_master, s32 blocksize):
- m_master(master),
- m_pos_on_master(pos_on_master),
- m_blocksize(blocksize)
- {
- W = m_blocksize+1;
- H = m_blocksize+1;
- m_data = NULL;
- m_data = new f32[(blocksize+1)*(blocksize+1)];
-
- for(s32 i=0; i<(blocksize+1)*(blocksize+1); i++){
- m_data[i] = GROUNDHEIGHT_NOTFOUND_SETVALUE;
- }
- }
-
- ~FixedHeightmap()
- {
- if(m_data)
- delete[] m_data;
- }
-
- v2s16 getPosOnMaster()
- {
- return m_pos_on_master;
- }
-
- /*
- TODO: BorderWrapper class or something to allow defining
- borders that wrap to an another heightmap. The algorithm
- should be allowed to edit stuff over the border and on
- the border in that case, too.
- This will allow non-square heightmaps, too. (probably)
- */
-
- void print()
- {
- printf("FixedHeightmap::print(): size is %ix%i\n", W, H);
- for(s32 y=0; y<H; y++){
- for(s32 x=0; x<W; x++){
- /*if(getSeeded(v2s16(x,y)))
- printf("S");*/
- f32 n = getGroundHeight(v2s16(x,y));
- if(n < GROUNDHEIGHT_VALID_MINVALUE)
- printf(" - ");
- else
- printf("% -5.1f ", getGroundHeight(v2s16(x,y)));
- }
- printf("\n");
- }
- }
-
- bool overborder(v2s16 p)
- {
- return (p.X < 0 || p.X >= W || p.Y < 0 || p.Y >= H);
- }
-
- bool atborder(v2s16 p)
- {
- if(overborder(p))
- return false;
- return (p.X == 0 || p.X == W-1 || p.Y == 0 || p.Y == H-1);
- }
-
- void setGroundHeight(v2s16 p, f32 y, bool generate=false)
- {
- /*dstream<<"FixedHeightmap::setGroundHeight(("
- <<p.X<<","<<p.Y
- <<"), "<<y<<")"<<std::endl;*/
- if(overborder(p))
- throw InvalidPositionException();
- m_data[p.Y*W + p.X] = y;
- }
-
- // Returns true on success, false on railure.
- bool setGroundHeightParent(v2s16 p, f32 y, bool generate=false)
- {
- /*// Position on master
- v2s16 blockpos_nodes = m_pos_on_master * m_blocksize;
- v2s16 nodepos_master = blockpos_nodes + p;
- dstream<<"FixedHeightmap::setGroundHeightParent(("
- <<p.X<<","<<p.Y
- <<"), "<<y<<"): nodepos_master=("
- <<nodepos_master.X<<","
- <<nodepos_master.Y<<")"<<std::endl;
- m_master->setGroundHeight(nodepos_master, y, false);*/
-
- // Try to set on master
- bool master_got_it = false;
- if(overborder(p) || atborder(p))
- {
- try{
- // Position on master
- v2s16 blockpos_nodes = m_pos_on_master * m_blocksize;
- v2s16 nodepos_master = blockpos_nodes + p;
- m_master->setGroundHeight(nodepos_master, y, false);
-
- master_got_it = true;
- }
- catch(InvalidPositionException &e)
- {
- }
- }
-
- if(overborder(p))
- return master_got_it;
-
- setGroundHeight(p, y);
-
- return true;
- }
-
- f32 getGroundHeight(v2s16 p, bool generate=false)
- {
- if(overborder(p))
- return GROUNDHEIGHT_NOTFOUND_SETVALUE;
- return m_data[p.Y*W + p.X];
- }
-
- f32 getGroundHeightParent(v2s16 p)
- {
- /*v2s16 blockpos_nodes = m_pos_on_master * m_blocksize;
- return m_master->getGroundHeight(blockpos_nodes + p, false);*/
-
- if(overborder(p) == false){
- f32 h = getGroundHeight(p);
- if(h > GROUNDHEIGHT_VALID_MINVALUE)
- return h;
- }
-
- // Position on master
- v2s16 blockpos_nodes = m_pos_on_master * m_blocksize;
- f32 h = m_master->getGroundHeight(blockpos_nodes + p, false);
- return h;
- }
-
- f32 avgNeighbours(v2s16 p, s16 d);
-
- f32 avgDiagNeighbours(v2s16 p, s16 d);
-
- void makeDiamond(
- v2s16 center,
- s16 a,
- f32 randmax,
- core::map<v2s16, bool> &next_squares);
-
- void makeSquare(
- v2s16 center,
- s16 a,
- f32 randmax,
- core::map<v2s16, bool> &next_diamonds);
-
- void DiamondSquare(f32 randmax, f32 randfactor);
-
- /*
- corners: [i]=XY: [0]=00, [1]=10, [2]=11, [3]=10
- */
- void generateContinued(f32 randmax, f32 randfactor, f32 *corners);
-
-
- static u32 serializedLength(u8 version, u16 blocksize);
- u32 serializedLength(u8 version);
- void serialize(u8 *dest, u8 version);
- void deSerialize(u8 *source, u8 version);
- /*static FixedHeightmap * deSerialize(u8 *source, u32 size,
- u32 &usedsize, Heightmap *master, u8 version);*/
-};
-
-class OneChildHeightmap : public Heightmap
-{
- s16 m_blocksize;
-
-public:
-
- FixedHeightmap m_child;
-
- OneChildHeightmap(s16 blocksize):
- m_blocksize(blocksize),
- m_child(this, v2s16(0,0), blocksize)
- {
- }
-
- f32 getGroundHeight(v2s16 p, bool generate=true)
- {
- if(p.X < 0 || p.X > m_blocksize
- || p.Y < 0 || p.Y > m_blocksize)
- return GROUNDHEIGHT_NOTFOUND_SETVALUE;
- return m_child.getGroundHeight(p);
- }
- void setGroundHeight(v2s16 p, f32 y, bool generate=true)
- {
- //dstream<<"OneChildHeightmap::setGroundHeight()"<<std::endl;
- if(p.X < 0 || p.X > m_blocksize
- || p.Y < 0 || p.Y > m_blocksize)
- throw InvalidPositionException();
- m_child.setGroundHeight(p, y);
- }
-};
-
-
-/*
- This is a dynamic container of an arbitrary number of heightmaps
- at arbitrary positions.
-
- It is able to redirect queries to the corresponding heightmaps and
- it generates new heightmaps on-the-fly according to the relevant
- parameters.
-
- It doesn't have a master heightmap because it is meant to be used
- as such itself.
-
- Child heightmaps are spaced at m_blocksize distances, and are of
- size (m_blocksize+1)*(m_blocksize+1)
-
- This is used as the master heightmap of a Map object.
-*/
-class UnlimitedHeightmap: public Heightmap
-{
-private:
-
- core::map<v2s16, FixedHeightmap*> m_heightmaps;
- s16 m_blocksize;
-
- // TODO: Remove ValueGenerators
- /*ValueGenerator *m_randmax_generator;
- ValueGenerator *m_randfactor_generator;
- ValueGenerator *m_base_generator;*/
-
- PointAttributeDatabase *m_padb;
-
-public:
-
- UnlimitedHeightmap(
- s16 blocksize,
- /*ValueGenerator *randmax_generator,
- ValueGenerator *randfactor_generator,
- ValueGenerator *base_generator,*/
- PointAttributeDatabase *padb
- ):
- m_blocksize(blocksize),
- /*m_randmax_generator(randmax_generator),
- m_randfactor_generator(randfactor_generator),
- m_base_generator(base_generator),*/
- m_padb(padb)
- {
- /*assert(m_randmax_generator != NULL);
- assert(m_randfactor_generator != NULL);
- assert(m_base_generator != NULL);*/
- assert(m_padb);
- }
-
- ~UnlimitedHeightmap()
- {
- core::map<v2s16, FixedHeightmap*>::Iterator i;
- i = m_heightmaps.getIterator();
- for(; i.atEnd() == false; i++)
- {
- delete i.getNode()->getValue();
- }
-
- /*delete m_randmax_generator;
- delete m_randfactor_generator;
- delete m_base_generator;*/
- }
-
- void print();
-
- v2s16 getNodeHeightmapPos(v2s16 p)
- {
- return v2s16(
- (p.X>=0 ? p.X : p.X-m_blocksize+1) / m_blocksize,
- (p.Y>=0 ? p.Y : p.Y-m_blocksize+1) / m_blocksize);
- }
-
- // Can throw an InvalidPositionException
- FixedHeightmap * getHeightmap(v2s16 p, bool generate=true);
-
- f32 getGroundHeight(v2s16 p, bool generate=true);
- void setGroundHeight(v2s16 p, f32 y, bool generate=true);
-
- /*static UnlimitedHeightmap * deSerialize(u8 *source, u32 maxsize,
- u32 &usedsize, u8 version);*/
-
- //SharedBuffer<u8> serialize(u8 version);
- void serialize(std::ostream &os, u8 version);
- static UnlimitedHeightmap * deSerialize(std::istream &istr,
- PointAttributeDatabase *padb);
-};
-
-#endif
-
# maybe done\r
* not done\r
\r
-* Perlin noise stuff sucks in heightmap generation, fix it\r
-* Create perlin noise functions and use them to get natural randomness\r
- in everything. No need for attributes or fractal terrain.\r
-* Do something about AttributeDatabase/List being too slow\r
- - Remove it\r
+=== Stuff to do before release\r
+* Save map seed to a metafile (with version information)\r
+ - map/meta.txt, which should contain only plain text, something like this:\r
+ seed = O7+BZT9Vk/iVYiBlZ2dsb6zemp4xdGVysJqYmNt2X+MQ+Kg1\r
+ chunksize = 8\r
+ - map/chunks/\r
+ - \r
+ - Compressed bunch of data... um, actually no.\r
+ - Make a directory for every chunk instead, which contains\r
+ sectors and blocks\r
* Save chunk metadata on disk\r
-* Remove all kinds of systems that are made redundant by the new map\r
- generator\r
- - Sector heightmaps? At least they should be made redundant.\r
- - Sector objects\r
-* Fix the strange mineral occurences\r
- - Do they appear anymore?\r
* Make server find the spawning place from the real map data, not from\r
the heightmap\r
- But the changing borders of chunk have to be avoided, because\r
there is time to generate only one chunk.\r
-* only_from_disk might not work anymore - check and fix it.\r
* Make the generator to run in background and not blocking block\r
placement and transfer\r
+* only_from_disk might not work anymore - check and fix it.\r
+\r
+=== Stuff to do after release\r
* Add some kind of erosion and other stuff that now is possible\r
* Make client to fetch stuff asynchronously\r
- Needs method SyncProcessData\r
-* What is the problem with the server constantly saving one or a few\r
+* Fix the problem with the server constantly saving one or a few\r
blocks? List the first saved block, maybe it explains.\r
- - Does it still do this?\r
+ - It is probably caused by oscillating water\r
* Water doesn't start flowing after map generation like it should\r
- Are there still problems?\r
-* Better water generation (spread it to underwater caverns)\r
+* Better water generation (spread it to underwater caverns but don't\r
+ fill dungeons that don't touch outside air)\r
* When generating a chunk and the neighboring chunk doesn't have mud\r
and stuff yet and the ground is fairly flat, the mud will flow to\r
the other chunk making nasty straight walls when the other chunk\r
is generated. Fix it.\r
-* Save map seed to a metafile (with version information)\r
- - Remove master heightmap\r
+* Make a small history check to transformLiquids to detect and log\r
+ continuous oscillations, in such detail that they can be fixed.\r
\r
======================================================================\r
\r
}\r
\r
// Material selection\r
- if(event.KeyInput.Key == irr::KEY_KEY_F)\r
+ /*if(event.KeyInput.Key == irr::KEY_KEY_F)\r
{\r
if(g_selected_item < PLAYER_INVENTORY_SIZE-1)\r
g_selected_item++;\r
g_selected_item = 0;\r
dstream<<DTIME<<"Selected item: "\r
<<g_selected_item<<std::endl;\r
+ }*/\r
+\r
+ if(event.KeyInput.Key >= irr::KEY_KEY_0\r
+ && event.KeyInput.Key <= irr::KEY_KEY_9)\r
+ {\r
+ u16 s1 = event.KeyInput.Key - irr::KEY_KEY_0;\r
+ if(event.KeyInput.Key == irr::KEY_KEY_0)\r
+ s1 = 10;\r
+ if(s1 < PLAYER_INVENTORY_SIZE)\r
+ g_selected_item = s1-1;\r
+ dstream<<DTIME<<"Selected item: "\r
+ <<g_selected_item<<std::endl;\r
}\r
\r
// Viewing range selection\r
if(counter1 < 0.0)\r
{\r
counter1 = 0.1*Rand(1, 40);\r
- keydown[irr::KEY_KEY_2] = !keydown[irr::KEY_KEY_2];\r
+ keydown[irr::KEY_KEY_E] = !keydown[irr::KEY_KEY_E];\r
}\r
}\r
{\r
run_tests();\r
}\r
\r
- // Read map parameters from settings\r
-\r
- HMParams hm_params;\r
- /*hm_params.blocksize = g_settings.getU16("heightmap_blocksize");\r
- hm_params.randmax = g_settings.get("height_randmax");\r
- hm_params.randfactor = g_settings.get("height_randfactor");\r
- hm_params.base = g_settings.get("height_base");*/\r
-\r
- MapParams map_params;\r
- map_params.plants_amount = g_settings.getFloat("plants_amount");\r
- map_params.ravines_amount = g_settings.getFloat("ravines_amount");\r
-\r
/*\r
Some parameters\r
*/\r
DSTACK("Dedicated server branch");\r
\r
// Create server\r
- Server server(map_dir.c_str(), hm_params, map_params);\r
+ Server server(map_dir.c_str());\r
server.start(port);\r
\r
// Run server\r
*/\r
SharedPtr<Server> server;\r
if(address == ""){\r
- server = new Server(map_dir, hm_params, map_params);\r
+ server = new Server(map_dir);\r
server->start(port);\r
}\r
\r
g_input->isKeyDown(irr::KEY_KEY_A),\r
g_input->isKeyDown(irr::KEY_KEY_D),\r
g_input->isKeyDown(irr::KEY_SPACE),\r
- g_input->isKeyDown(irr::KEY_KEY_2),\r
+ g_input->isKeyDown(irr::KEY_KEY_E),\r
camera_pitch,\r
camera_yaw\r
);\r
m_dout(dout),
m_camera_position(0,0,0),
m_camera_direction(0,0,1),
- m_sector_cache(NULL),
- m_hwrapper(this)
+ m_sector_cache(NULL)
{
m_sector_mutex.Init();
m_camera_mutex.Init();
ServerMap
*/
-ServerMap::ServerMap(std::string savedir, HMParams hmp, MapParams mp):
+ServerMap::ServerMap(std::string savedir):
Map(dout_server),
- m_heightmap(NULL),
m_seed(0)
{
//m_chunksize = 64;
- //m_chunksize = 16;
- m_chunksize = 8;
+ //m_chunksize = 16; // Too slow
+ m_chunksize = 8; // Fine. Takes a few seconds.
//m_chunksize = 4;
//m_chunksize = 2;
*/
{
- dstream<<"Generating map point attribute lists"<<std::endl;
-
- PointAttributeList *list_baseheight = m_padb.getList("hm_baseheight");
- PointAttributeList *list_randmax = m_padb.getList("hm_randmax");
- PointAttributeList *list_randfactor = m_padb.getList("hm_randfactor");
- //PointAttributeList *list_plants_amount = m_padb.getList("plants_amount");
- //PointAttributeList *list_caves_amount = m_padb.getList("caves_amount");
-
-#if 0
- /*
- NOTE: BEWARE: Too big amount of these will make map generation
- slow. Especially those that are read by every block emerge.
-
- Fetch times:
- 1000 points: 2-3ms
- 5000 points: 15ms
- 15000 points: 40ms
- */
-
- for(u32 i=0; i<500; i++)
- {
- /*u32 lim = MAP_GENERATION_LIMIT;
- if(i < 400)
- lim = 2000;*/
-
- u32 lim = 500 + MAP_GENERATION_LIMIT * i / 500;
-
- v3s16 p(
- -lim + myrand()%(lim*2),
- 0,
- -lim + myrand()%(lim*2)
- );
- /*float plants_amount = (float)(myrand()%1050) / 1000.0;
- plants_amount = pow(plants_amount, 5);
- list_plants_amount->addPoint(p, Attribute(plants_amount));*/
-
- float plants_amount = 0;
- if(myrand()%4 == 0)
- {
- plants_amount = 1.5;
- }
- else if(myrand()%4 == 0)
- {
- plants_amount = 0.5;
- }
- else if(myrand()%2 == 0)
- {
- plants_amount = 0.03;
- }
- else
- {
- plants_amount = 0.0;
- }
-
-
- list_plants_amount->addPoint(p, Attribute(plants_amount));
- }
-
- for(u32 i=0; i<500; i++)
- {
- /*u32 lim = MAP_GENERATION_LIMIT;
- if(i < 400)
- lim = 2000;*/
-
- u32 lim = 500 + MAP_GENERATION_LIMIT * i / 500;
-
- v3s16 p(
- -lim + myrand()%(lim*2),
- 0,
- -lim + myrand()%(lim*2)
- );
-
- float caves_amount = 0;
- if(myrand()%5 == 0)
- {
- caves_amount = 1.0;
- }
- else if(myrand()%3 == 0)
- {
- caves_amount = 0.3;
- }
- else
- {
- caves_amount = 0.05;
- }
-
- list_caves_amount->addPoint(p, Attribute(caves_amount));
- }
-
- for(u32 i=0; i<500; i++)
- {
- /*u32 lim = MAP_GENERATION_LIMIT;
- if(i < 400)
- lim = 2000;*/
-
- u32 lim = 500 + MAP_GENERATION_LIMIT * i / 500;
-
- v3s16 p(
- -lim + (myrand()%(lim*2)),
- 0,
- -lim + (myrand()%(lim*2))
- );
-
- /*s32 bh_i = (myrand()%200) - 50;
- float baseheight = (float)bh_i;
-
- float m = 100.;
- float e = 3.;
- float randmax = (float)(myrand()%(int)(10.*pow(m, 1./e)))/10.;
- randmax = pow(randmax, e);
-
- //float randmax = (float)(myrand()%60);
- float randfactor = (float)(myrand()%450) / 1000.0 + 0.4;*/
-
- float baseheight = 0;
- float randmax = 0;
- float randfactor = 0;
-
- /*if(myrand()%5 == 0)
- {
- baseheight = 100;
- randmax = 50;
- randfactor = 0.63;
- }
- else if(myrand()%6 == 0)
- {
- baseheight = 200;
- randmax = 100;
- randfactor = 0.66;
- }
- else if(myrand()%4 == 0)
- {
- baseheight = -3;
- randmax = 30;
- randfactor = 0.7;
- }
- else if(myrand()%3 == 0)
- {
- baseheight = 0;
- randmax = 30;
- randfactor = 0.63;
- }
- else
- {
- baseheight = -3;
- randmax = 20;
- randfactor = 0.5;
- }*/
-
- if(myrand()%3 < 2)
- {
- baseheight = 10;
- randmax = 30;
- randfactor = 0.7;
- }
- else
- {
- baseheight = 0;
- randmax = 15;
- randfactor = 0.63;
- }
-
- list_baseheight->addPoint(p, Attribute(baseheight));
- list_randmax->addPoint(p, Attribute(randmax));
- list_randfactor->addPoint(p, Attribute(randfactor));
- }
-#endif
-
- // Add only one entry
- list_baseheight->addPoint(v3s16(0,0,0), Attribute(-4));
- list_randmax->addPoint(v3s16(0,0,0), Attribute(22));
- //list_randmax->addPoint(v3s16(0,0,0), Attribute(0));
- list_randfactor->addPoint(v3s16(0,0,0), Attribute(0.45));
-
- // Easy spawn point
- /*list_baseheight->addPoint(v3s16(0,0,0), Attribute(0));
- list_randmax->addPoint(v3s16(0,0,0), Attribute(10));
- list_randfactor->addPoint(v3s16(0,0,0), Attribute(0.65));*/
}
/*
dstream<<DTIME<<"Initializing new map."<<std::endl;
- // Create master heightmap
- // NOTE: Yes, that is a magic number down there. It specifies
- // the size of the internal FixedHeightmaps.
- m_heightmap = new UnlimitedHeightmap
- (32, &m_padb);
-
- // Set map parameters
- m_params = mp;
-
// Create zero sector
emergeSector(v2s16(0,0));
<<", exception: "<<e.what()<<std::endl;
}
- if(m_heightmap != NULL)
- delete m_heightmap;
-
/*
Free all MapChunks
*/
double tree_amount_2d(u64 seed, v2s16 p)
{
double noise = noise2d_perlin(
- 0.5+(float)p.X/500, 0.5+(float)p.Y/500,
- seed+2, 4, 0.55);
+ 0.5+(float)p.X/250, 0.5+(float)p.Y/250,
+ seed+2, 4, 0.6);
double zeroval = -0.3;
if(noise < zeroval)
return 0;
else
- return 0.05 * (noise-zeroval) / (0.5-zeroval);
+ return 0.04 * (noise-zeroval) / (1.0-zeroval);
}
double base_rock_level_2d(u64 seed, v2s16 p)
{
- return -4. + 25. * noise2d_perlin(
+ return WATER_LEVEL - 6.0 + 25. * noise2d_perlin(
0.5+(float)p.X/500., 0.5+(float)p.Y/500.,
seed, 6, 0.6);
}
{
double a = noise2d_perlin(
0.5+(float)p.X/1000., 0.5+(float)p.Y/1000.,
- seed-359, 6, 0.55);
- if(a > 0.2)
+ seed-359, 6, 0.65);
+ if(a > 0.0)
+ //if(1)
{
- return 35. + 10. * noise2d_perlin(
+ return WATER_LEVEL + 55. * noise2d_perlin(
0.5+(float)p.X/500., 0.5+(float)p.Y/500.,
- seed+85039, 6, 0.55);
+ seed+85039, 6, 0.69);
}
else
return -100000;
MapChunk* ServerMap::generateChunkRaw(v2s16 chunkpos,
core::map<v3s16, MapBlock*> &changed_blocks)
{
+ DSTACK(__FUNCTION_NAME);
+
/*
Don't generate if already fully generated
*/
s16 max_spread_amount_sectors = 2;
assert(max_spread_amount_sectors <= m_chunksize);
s16 max_spread_amount = max_spread_amount_sectors * MAP_BLOCKSIZE;
+
// Minimum amount of space left on sides for mud to fall in
- s16 min_mud_fall_space = 2;
+ //s16 min_mud_fall_space = 2;
+
// Maximum diameter of stone obstacles in X and Z
- s16 stone_obstacle_max_size = (max_spread_amount-min_mud_fall_space)*2;
- assert(stone_obstacle_max_size/2 <= max_spread_amount-min_mud_fall_space);
+ /*s16 stone_obstacle_max_size = (max_spread_amount-min_mud_fall_space)*2;
+ assert(stone_obstacle_max_size/2 <= max_spread_amount-min_mud_fall_space);*/
s16 y_blocks_min = -4;
s16 y_blocks_max = 3;
TimeTaker timer_generate("generateChunkRaw() generate");
+ // Maximum height of the stone surface and obstacles.
+ // This is used to disable dungeon generation from going too high.
+ s16 stone_surface_max_y = 0;
+
/*
Generate general ground level to full area
*/
// Convert to integer
s16 surface_y = (s16)surface_y_f;
+
+ // Log it
+ if(surface_y > stone_surface_max_y)
+ stone_surface_max_y = surface_y;
/*
Fill ground with stone
/*
Randomize some parameters
*/
-
- u32 stone_obstacle_amount = 0;
- if(myrand() % 2 == 0)
- stone_obstacle_amount = myrand_range(0, myrand_range(20, 150));
- else
- stone_obstacle_amount = myrand_range(0, myrand_range(20, 50));
+
+ //TODO
+ s32 stone_obstacle_count = 0;
+ /*s32 stone_obstacle_count = (1.0+noise2d(m_seed+90443, sectorpos_base.X,
+ sectorpos_base.Y))/2.0 * stone_obstacle_amount/3;*/
+
+ s16 stone_obstacle_max_height = 0;
//u32 stone_obstacle_amount =
// myrand_range(0, myrand_range(20, myrand_range(80,150)));
for(u32 i_age=0; i_age<2; i_age++)
{ // Aging loop
- // This is set during the next operation.
- // Maximum height of the stone surface and obstacles.
- // This is used to disable dungeon generation from going too high.
- s16 stone_surface_max_y = 0;
-
{
// 8ms @cs=8
//TimeTaker timer1("stone obstacles");
Add some random stone obstacles
*/
- for(u32 ri=0; ri<stone_obstacle_amount/3; ri++)
- //for(u32 ri=0; ri<7; ri++)
- //if(0)
+ for(s32 ri=0; ri<stone_obstacle_count; ri++)
{
// Randomize max height so usually stuff will be quite low
- //s16 maxheight_randomized = myrand_range(0, 25);
- s16 maxheight_randomized = myrand_range(0, stone_obstacle_amount/3);
+ s16 maxheight_randomized = myrand_range(0, stone_obstacle_max_height);
+
+ s16 stone_obstacle_max_size = sectorpos_base_size * MAP_BLOCKSIZE - 10;
- // The size of these could actually be m_chunksize*MAP_BLOCKSIZE*2
v3s16 ob_size(
myrand_range(5, stone_obstacle_max_size),
myrand_range(0, maxheight_randomized),
myrand_range(5, stone_obstacle_max_size)
);
- // Don't make stupid small rectable bumps
+ // Don't make stupid small rectangle bumps
if(ob_size.Y < 5)
continue;
-
- /*v2s16 ob_place(
- myrand_range(0, sectorpos_base_size*MAP_BLOCKSIZE-1),
- myrand_range(0, sectorpos_base_size*MAP_BLOCKSIZE-1)
- );*/
- /*
- Limit by 1 to not obstruct sunlight at borders, because
- it would fuck up lighting in some places because we're
- leaving out removing light from the borders for optimization
- and simplicity.
- */
+
v2s16 ob_place(
- myrand_range(1, sectorpos_base_size*MAP_BLOCKSIZE-1-1),
- myrand_range(1, sectorpos_base_size*MAP_BLOCKSIZE-1-1)
+ myrand_range(1+ob_size.X/2+2,
+ sectorpos_base_size*MAP_BLOCKSIZE-1-1-ob_size.X/2-2),
+ myrand_range(1+ob_size.Z/2+2,
+ sectorpos_base_size*MAP_BLOCKSIZE-1-1-ob_size.Z/2-2)
);
// Minimum space left on top of the obstacle
/*
Make dungeons
*/
- u32 dungeons_count = relative_volume / 400000;
- u32 bruises_count = relative_volume * stone_surface_max_y / 200000 / 50;
- /*u32 dungeons_count = 0;
- u32 bruises_count = 0;*/
+ u32 dungeons_count = relative_volume / 600000;
+ u32 bruises_count = relative_volume * stone_surface_max_y / 40000000;
+ if(stone_surface_max_y < WATER_LEVEL)
+ bruises_count = 0;
+ //dungeons_count = 0;
+ //bruises_count = 0;
for(u32 jj=0; jj<dungeons_count+bruises_count; jj++)
{
s16 min_tunnel_diameter = 2;
if(bruise_surface)
{
- min_tunnel_diameter = 5;
- max_tunnel_diameter = myrand_range(10, 20);
+ //min_tunnel_diameter = 5;
+ //max_tunnel_diameter = myrand_range(10, 20);
+ min_tunnel_diameter = MYMAX(0, stone_surface_max_y/6);
+ max_tunnel_diameter = myrand_range(MYMAX(0, stone_surface_max_y/6), MYMAX(0, stone_surface_max_y/4));
tunnel_routepoints = 3;
}
s16 route_y_min = 0;
//s16 route_y_max = ar.Y-1;
s16 route_y_max = -of.Y + stone_surface_max_y + max_tunnel_diameter/2;
+ // If dungeons
if(bruise_surface == false)
{
// Don't go through surface too often
- route_y_max -= myrand_range(0, max_tunnel_diameter);
+ route_y_max -= myrand_range(0, max_tunnel_diameter*2);
}
route_y_max = rangelim(route_y_max, 0, ar.Y-1);
for(u16 j=0; j<tunnel_routepoints; j++)
{
- v3s16 maxlen(20, 10, 20);
+ v3s16 maxlen(15, 5, 15);
if(bruise_surface)
{
- maxlen = v3s16(60,60,60);
+ maxlen = v3s16(30,25,30);
}
v3f vec(
Flow mud away from steep edges
*/
+ // Limit area by 1 because mud is flown into neighbors.
+ s16 mudflow_minpos = 0-max_spread_amount+1;
+ s16 mudflow_maxpos = sectorpos_base_size*MAP_BLOCKSIZE+max_spread_amount-2;
+
// Iterate a few times
for(s16 k=0; k<3; k++)
{
- /*for(s16 x=0-max_spread_amount+1;
- x<sectorpos_base_size*MAP_BLOCKSIZE+max_spread_amount-1;
+ for(s16 x=mudflow_minpos;
+ x<=mudflow_maxpos;
x++)
- for(s16 z=0-max_spread_amount+1;
- z<sectorpos_base_size*MAP_BLOCKSIZE+max_spread_amount-1;
- z++)*/
-
- /*
- Firstly, limit area by 1 because mud is flown into neighbors.
- Secondly, limit by 1 more to not obstruct sunlight at borders,
- because it would fuck up lighting in some places because we're
- leaving out removing light from the borders for optimization
- and simplicity.
- */
- /*for(s16 x=0-max_spread_amount+2;
- x<sectorpos_base_size*MAP_BLOCKSIZE+max_spread_amount-2;
- x++)
- for(s16 z=0-max_spread_amount+2;
- z<sectorpos_base_size*MAP_BLOCKSIZE+max_spread_amount-2;
- z++)*/
- for(s16 x=0-max_spread_amount+1;
- x<sectorpos_base_size*MAP_BLOCKSIZE+max_spread_amount-1;
- x++)
- for(s16 z=0-max_spread_amount+1;
- z<sectorpos_base_size*MAP_BLOCKSIZE+max_spread_amount-1;
+ for(s16 z=mudflow_minpos;
+ z<=mudflow_maxpos;
z++)
{
+ // Invert coordinates every 2nd iteration
+ if(k%2 == 0)
+ {
+ x = mudflow_maxpos - (x-mudflow_minpos);
+ z = mudflow_maxpos - (z-mudflow_minpos);
+ }
+
// Node position in 2d
v2s16 p2d = sectorpos_base*MAP_BLOCKSIZE + v2s16(x,z);
continue;
// Check that under side is air
vmanip.m_area.add_y(em, i2, -1);
- // Fail if out of area
if(vmanip.m_area.contains(i2) == false)
continue;
n2 = &vmanip.m_data[i2];
if(content_walkable(n2->d))
continue;
+ /*// Check that under that is air (need a drop of 2)
+ vmanip.m_area.add_y(em, i2, -1);
+ if(vmanip.m_area.contains(i2) == false)
+ continue;
+ n2 = &vmanip.m_data[i2];
+ if(content_walkable(n2->d))
+ continue;*/
// Loop further down until not air
do{
vmanip.m_area.add_y(em, i2, -1);
{
MapNode *n = &vmanip.m_data[i];
if(n->d == CONTENT_MUD || n->d == CONTENT_GRASS)
+ {
n->d = CONTENT_SAND;
+ }
else
{
not_sand_counter++;
}//timer1
{
// 1ms @cs=8
- //TimeTaker timer1("plant trees");
+ //TimeTaker timer1("generate trees");
/*
- Plant some trees
+ Generate some trees
*/
{
// Divide area into parts
return sector;
}
- /*
- If there is no master heightmap, throw.
- */
- if(m_heightmap == NULL)
- {
- throw InvalidPositionException("createSector(): no heightmap");
- }
-
/*
Do not create over-limit
*/
Generate blank sector
*/
- // Number of heightmaps in sector in each direction
- u16 hm_split = SECTOR_HEIGHTMAP_SPLIT;
-
- // Heightmap side width
- s16 hm_d = MAP_BLOCKSIZE / hm_split;
-
- sector = new ServerMapSector(this, p2d, hm_split);
+ sector = new ServerMapSector(this, p2d);
// Sector position on map in nodes
v2s16 nodepos2d = p2d * MAP_BLOCKSIZE;
- /*dstream<<"Generating sector ("<<p2d.X<<","<<p2d.Y<<")"
- " heightmaps and objects"<<std::endl;*/
-
- /*
- Generate sector heightmap
- */
-
- v2s16 mhm_p = p2d * hm_split;
- /*f32 corners[4] = {
- m_heightmap->getGroundHeight(mhm_p+v2s16(0,0)*hm_split),
- m_heightmap->getGroundHeight(mhm_p+v2s16(1,0)*hm_split),
- m_heightmap->getGroundHeight(mhm_p+v2s16(1,1)*hm_split),
- m_heightmap->getGroundHeight(mhm_p+v2s16(0,1)*hm_split),
- };*/
-
- // Loop through sub-heightmaps
- for(s16 y=0; y<hm_split; y++)
- for(s16 x=0; x<hm_split; x++)
- {
- v2s16 p_in_sector = v2s16(x,y);
- v2s16 mhm_p = p2d * hm_split + p_in_sector;
- f32 corners[4] = {
- m_heightmap->getGroundHeight(mhm_p+v2s16(0,0)),
- m_heightmap->getGroundHeight(mhm_p+v2s16(1,0)),
- m_heightmap->getGroundHeight(mhm_p+v2s16(1,1)),
- m_heightmap->getGroundHeight(mhm_p+v2s16(0,1)),
- };
-
- /*dstream<<"p_in_sector=("<<p_in_sector.X<<","<<p_in_sector.Y<<")"
- <<" mhm_p=("<<mhm_p.X<<","<<mhm_p.Y<<")"
- <<std::endl;*/
-
- FixedHeightmap *hm = new FixedHeightmap(&m_hwrapper,
- mhm_p, hm_d);
- sector->setHeightmap(p_in_sector, hm);
-
- //hm->generateContinued(1.0, 0.5, corners);
- hm->generateContinued(0.5, 0.5, corners);
-
- //hm->print();
- }
-
- // Add dummy objects
- core::map<v3s16, u8> *objects = new core::map<v3s16, u8>;
- sector->setObjects(objects);
-
/*
Insert to container
*/
block->unDummify();
}
- /*u8 water_material = CONTENT_WATER;
- if(g_settings.getBool("endless_water"))
- water_material = CONTENT_WATERSOURCE;*/
u8 water_material = CONTENT_WATERSOURCE;
s32 lowest_ground_y = 32767;
s32 highest_ground_y = -32768;
- // DEBUG
- //sector->printHeightmaps();
-
for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
{
//dstream<<"generateBlock: x0="<<x0<<", z0="<<z0<<std::endl;
- float surface_y_f = sector->getGroundHeight(v2s16(x0,z0));
- //assert(surface_y_f > GROUNDHEIGHT_VALID_MINVALUE);
- if(surface_y_f < GROUNDHEIGHT_VALID_MINVALUE)
- {
- dstream<<"WARNING: Surface height not found in sector "
- "for block that is being emerged"<<std::endl;
- surface_y_f = 0.0;
- }
+ s16 surface_y = 0;
- s16 surface_y = surface_y_f;
- //avg_ground_y += surface_y;
if(surface_y < lowest_ground_y)
lowest_ground_y = surface_y;
if(surface_y > highest_ground_y)
highest_ground_y = surface_y;
- s32 surface_depth = 0;
-
- float slope = sector->getSlope(v2s16(x0,z0)).getLength();
+ s32 surface_depth = 2;
- //float min_slope = 0.45;
- //float max_slope = 0.85;
- float min_slope = 0.60;
- float max_slope = 1.20;
- float min_slope_depth = 5.0;
- float max_slope_depth = 0;
-
- if(slope < min_slope)
- surface_depth = min_slope_depth;
- else if(slope > max_slope)
- surface_depth = max_slope_depth;
- else
- surface_depth = (1.-(slope-min_slope)/max_slope) * min_slope_depth;
-
for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
{
s16 real_y = block_y * MAP_BLOCKSIZE + y0;
*/
sector->insertBlock(block);
- /*
- Sector object stuff
- */
-
- // An y-wise container of changed blocks
- core::map<s16, MapBlock*> changed_blocks_sector;
-
- /*
- Check if any sector's objects can be placed now.
- If so, place them.
- */
- core::map<v3s16, u8> *objects = sector->getObjects();
- core::list<v3s16> objects_to_remove;
- for(core::map<v3s16, u8>::Iterator i = objects->getIterator();
- i.atEnd() == false; i++)
- {
- v3s16 p = i.getNode()->getKey();
- v2s16 p2d(p.X,p.Z);
- u8 d = i.getNode()->getValue();
-
- // Ground level point (user for stuff that is on ground)
- v3s16 gp = p;
- bool ground_found = true;
-
- // Search real ground level
- try{
- for(;;)
- {
- MapNode n = sector->getNode(gp);
-
- // If not air, go one up and continue to placing the tree
- if(n.d != CONTENT_AIR)
- {
- gp += v3s16(0,1,0);
- break;
- }
-
- // If air, go one down
- gp += v3s16(0,-1,0);
- }
- }catch(InvalidPositionException &e)
- {
- // Ground not found.
- ground_found = false;
- // This is most close to ground
- gp += v3s16(0,1,0);
- }
-
- try
- {
-
- if(d == SECTOR_OBJECT_TEST)
- {
- if(sector->isValidArea(p + v3s16(0,0,0),
- p + v3s16(0,0,0), &changed_blocks_sector))
- {
- MapNode n;
- n.d = CONTENT_TORCH;
- sector->setNode(p, n);
- objects_to_remove.push_back(p);
- }
- }
- else if(d == SECTOR_OBJECT_TREE_1)
- {
- if(ground_found == false)
- continue;
-
- v3s16 p_min = gp + v3s16(-1,0,-1);
- v3s16 p_max = gp + v3s16(1,5,1);
- if(sector->isValidArea(p_min, p_max,
- &changed_blocks_sector))
- {
- MapNode n;
- n.d = CONTENT_TREE;
- sector->setNode(gp+v3s16(0,0,0), n);
- sector->setNode(gp+v3s16(0,1,0), n);
- sector->setNode(gp+v3s16(0,2,0), n);
- sector->setNode(gp+v3s16(0,3,0), n);
-
- n.d = CONTENT_LEAVES;
-
- if(myrand()%4!=0) sector->setNode(gp+v3s16(0,5,0), n);
-
- if(myrand()%3!=0) sector->setNode(gp+v3s16(-1,5,0), n);
- if(myrand()%3!=0) sector->setNode(gp+v3s16(1,5,0), n);
- if(myrand()%3!=0) sector->setNode(gp+v3s16(0,5,-1), n);
- if(myrand()%3!=0) sector->setNode(gp+v3s16(0,5,1), n);
- /*if(myrand()%3!=0) sector->setNode(gp+v3s16(1,5,1), n);
- if(myrand()%3!=0) sector->setNode(gp+v3s16(-1,5,1), n);
- if(myrand()%3!=0) sector->setNode(gp+v3s16(-1,5,-1), n);
- if(myrand()%3!=0) sector->setNode(gp+v3s16(1,5,-1), n);*/
-
- sector->setNode(gp+v3s16(0,4,0), n);
-
- sector->setNode(gp+v3s16(-1,4,0), n);
- sector->setNode(gp+v3s16(1,4,0), n);
- sector->setNode(gp+v3s16(0,4,-1), n);
- sector->setNode(gp+v3s16(0,4,1), n);
- sector->setNode(gp+v3s16(1,4,1), n);
- sector->setNode(gp+v3s16(-1,4,1), n);
- sector->setNode(gp+v3s16(-1,4,-1), n);
- sector->setNode(gp+v3s16(1,4,-1), n);
-
- sector->setNode(gp+v3s16(-1,3,0), n);
- sector->setNode(gp+v3s16(1,3,0), n);
- sector->setNode(gp+v3s16(0,3,-1), n);
- sector->setNode(gp+v3s16(0,3,1), n);
- sector->setNode(gp+v3s16(1,3,1), n);
- sector->setNode(gp+v3s16(-1,3,1), n);
- sector->setNode(gp+v3s16(-1,3,-1), n);
- sector->setNode(gp+v3s16(1,3,-1), n);
-
- if(myrand()%3!=0) sector->setNode(gp+v3s16(-1,2,0), n);
- if(myrand()%3!=0) sector->setNode(gp+v3s16(1,2,0), n);
- if(myrand()%3!=0) sector->setNode(gp+v3s16(0,2,-1), n);
- if(myrand()%3!=0) sector->setNode(gp+v3s16(0,2,1), n);
- /*if(myrand()%3!=0) sector->setNode(gp+v3s16(1,2,1), n);
- if(myrand()%3!=0) sector->setNode(gp+v3s16(-1,2,1), n);
- if(myrand()%3!=0) sector->setNode(gp+v3s16(-1,2,-1), n);
- if(myrand()%3!=0) sector->setNode(gp+v3s16(1,2,-1), n);*/
-
- // Objects are identified by wanted position
- objects_to_remove.push_back(p);
-
- // Lighting has to be recalculated for this one.
- sector->getBlocksInArea(p_min, p_max,
- lighting_invalidated_blocks);
- }
- }
- else if(d == SECTOR_OBJECT_BUSH_1)
- {
- if(ground_found == false)
- continue;
-
- if(sector->isValidArea(gp + v3s16(0,0,0),
- gp + v3s16(0,0,0), &changed_blocks_sector))
- {
- MapNode n;
- n.d = CONTENT_LEAVES;
- sector->setNode(gp+v3s16(0,0,0), n);
-
- // Objects are identified by wanted position
- objects_to_remove.push_back(p);
- }
- }
- else if(d == SECTOR_OBJECT_RAVINE)
- {
- s16 maxdepth = -20;
- v3s16 p_min = p + v3s16(-6,maxdepth,-6);
- v3s16 p_max = p + v3s16(6,6,6);
- if(sector->isValidArea(p_min, p_max,
- &changed_blocks_sector))
- {
- MapNode n;
- n.d = CONTENT_STONE;
- MapNode n2;
- n2.d = CONTENT_AIR;
- s16 depth = maxdepth + (myrand()%10);
- s16 z = 0;
- s16 minz = -6 - (-2);
- s16 maxz = 6 -1;
- for(s16 x=-6; x<=6; x++)
- {
- z += -1 + (myrand()%3);
- if(z < minz)
- z = minz;
- if(z > maxz)
- z = maxz;
- for(s16 y=depth+(myrand()%2); y<=6; y++)
- {
- /*std::cout<<"("<<p2.X<<","<<p2.Y<<","<<p2.Z<<")"
- <<std::endl;*/
- {
- v3s16 p2 = p + v3s16(x,y,z-2);
- //if(is_ground_content(sector->getNode(p2).d))
- if(content_features(sector->getNode(p2).d).walkable)
- sector->setNode(p2, n);
- }
- {
- v3s16 p2 = p + v3s16(x,y,z-1);
- if(content_features(sector->getNode(p2).d).walkable)
- sector->setNode(p2, n2);
- }
- {
- v3s16 p2 = p + v3s16(x,y,z+0);
- if(content_features(sector->getNode(p2).d).walkable)
- sector->setNode(p2, n2);
- }
- {
- v3s16 p2 = p + v3s16(x,y,z+1);
- if(content_features(sector->getNode(p2).d).walkable)
- sector->setNode(p2, n);
- }
-
- //if(sector->getNode(p+v3s16(x,y,z+1)).solidness()==2)
- //if(p.Y+y <= sector->getGroundHeight(p2d+v2s16(x,z-2))+0.5)
- }
- }
-
- objects_to_remove.push_back(p);
-
- // Lighting has to be recalculated for this one.
- sector->getBlocksInArea(p_min, p_max,
- lighting_invalidated_blocks);
- }
- }
- else
- {
- dstream<<"ServerMap::generateBlock(): "
- "Invalid heightmap object"
- <<std::endl;
- }
-
- }//try
- catch(InvalidPositionException &e)
- {
- dstream<<"WARNING: "<<__FUNCTION_NAME
- <<": while inserting object "<<(int)d
- <<" to ("<<p.X<<","<<p.Y<<","<<p.Z<<"):"
- <<" InvalidPositionException.what()="
- <<e.what()<<std::endl;
- // This is not too fatal and seems to happen sometimes.
- assert(0);
- }
- }
-
- for(core::list<v3s16>::Iterator i = objects_to_remove.begin();
- i != objects_to_remove.end(); i++)
- {
- objects->remove(*i);
- }
-
- /*
- Translate sector's changed blocks to global changed blocks
- */
-
- for(core::map<s16, MapBlock*>::Iterator
- i = changed_blocks_sector.getIterator();
- i.atEnd() == false; i++)
- {
- MapBlock *block = i.getNode()->getValue();
-
- changed_blocks.insert(block->getPos(), block);
- }
-
+ // Lighting is invalid after generation.
block->setLightingExpired(true);
#if 0
return v3s16(p2d.X, y, p2d.Y);
}
-// Debug helpers
-#define ENABLE_SECTOR_SAVING 1
-#define ENABLE_SECTOR_LOADING 1
-#define ENABLE_BLOCK_SAVING 1
-#define ENABLE_BLOCK_LOADING 1
-
void ServerMap::save(bool only_changed)
{
DSTACK(__FUNCTION_NAME);
{
ServerMapSector *sector = (ServerMapSector*)i.getNode()->getValue();
assert(sector->getId() == MAPSECTOR_SERVER);
-
- if(ENABLE_SECTOR_SAVING)
+
+ if(sector->differs_from_disk || only_changed == false)
{
- if(sector->differs_from_disk || only_changed == false)
- {
- saveSectorMeta(sector);
- sector_meta_count++;
- }
+ saveSectorMeta(sector);
+ sector_meta_count++;
}
- if(ENABLE_BLOCK_SAVING)
+ core::list<MapBlock*> blocks;
+ sector->getBlocks(blocks);
+ core::list<MapBlock*>::Iterator j;
+ for(j=blocks.begin(); j!=blocks.end(); j++)
{
- core::list<MapBlock*> blocks;
- sector->getBlocks(blocks);
- core::list<MapBlock*>::Iterator j;
- for(j=blocks.begin(); j!=blocks.end(); j++)
+ MapBlock *block = *j;
+ if(block->getChangedFlag() || only_changed == false)
{
- MapBlock *block = *j;
- if(block->getChangedFlag() || only_changed == false)
- {
- saveBlock(block);
- block_count++;
-
- /*dstream<<"ServerMap: Written block ("
- <<block->getPos().X<<","
- <<block->getPos().Y<<","
- <<block->getPos().Z<<")"
- <<std::endl;*/
- }
+ saveBlock(block);
+ block_count++;
+
+ /*dstream<<"ServerMap: Written block ("
+ <<block->getPos().X<<","
+ <<block->getPos().Y<<","
+ <<block->getPos().Z<<")"
+ <<std::endl;*/
}
}
}
// This catches unknown crap in directory
}
- if(ENABLE_BLOCK_LOADING)
+ std::vector<fs::DirListNode> list2 = fs::GetDirListing
+ (m_savedir+"/sectors/"+i->name);
+ std::vector<fs::DirListNode>::iterator i2;
+ for(i2=list2.begin(); i2!=list2.end(); i2++)
{
- std::vector<fs::DirListNode> list2 = fs::GetDirListing
- (m_savedir+"/sectors/"+i->name);
- std::vector<fs::DirListNode>::iterator i2;
- for(i2=list2.begin(); i2!=list2.end(); i2++)
+ // We want files
+ if(i2->dir)
+ continue;
+ try{
+ loadBlock(i->name, i2->name, sector);
+ }
+ catch(InvalidFilenameException &e)
{
- // We want files
- if(i2->dir)
- continue;
- try{
- loadBlock(i->name, i2->name, sector);
- }
- catch(InvalidFilenameException &e)
- {
- // This catches unknown crap in directory
- }
+ // This catches unknown crap in directory
}
}
}
void ServerMap::saveMasterHeightmap()
{
DSTACK(__FUNCTION_NAME);
+
+ dstream<<"DEPRECATED: "<<__FUNCTION_NAME<<std::endl;
+
createDir(m_savedir);
- std::string fullpath = m_savedir + "/master_heightmap";
+ /*std::string fullpath = m_savedir + "/master_heightmap";
std::ofstream o(fullpath.c_str(), std::ios_base::binary);
if(o.good() == false)
- throw FileNotGoodException("Cannot open master heightmap");
+ throw FileNotGoodException("Cannot open master heightmap");*/
// Format used for writing
- u8 version = SER_FMT_VER_HIGHEST;
-
-#if 0
- SharedBuffer<u8> hmdata = m_heightmap->serialize(version);
- /*
- [0] u8 serialization version
- [1] X master heightmap
- */
- u32 fullsize = 1 + hmdata.getSize();
- SharedBuffer<u8> data(fullsize);
-
- data[0] = version;
- memcpy(&data[1], *hmdata, hmdata.getSize());
-
- o.write((const char*)*data, fullsize);
-#endif
-
- m_heightmap->serialize(o, version);
+ //u8 version = SER_FMT_VER_HIGHEST;
}
void ServerMap::loadMasterHeightmap()
{
DSTACK(__FUNCTION_NAME);
- std::string fullpath = m_savedir + "/master_heightmap";
+
+ dstream<<"DEPRECATED: "<<__FUNCTION_NAME<<std::endl;
+
+ /*std::string fullpath = m_savedir + "/master_heightmap";
std::ifstream is(fullpath.c_str(), std::ios_base::binary);
if(is.good() == false)
- throw FileNotGoodException("Cannot open master heightmap");
-
- if(m_heightmap != NULL)
- delete m_heightmap;
-
- m_heightmap = UnlimitedHeightmap::deSerialize(is, &m_padb);
+ throw FileNotGoodException("Cannot open master heightmap");*/
}
void ServerMap::saveSectorMeta(ServerMapSector *sector)
throw FileNotGoodException("Cannot open sector heightmap");
ServerMapSector *sector = ServerMapSector::deSerialize
- (is, this, p2d, &m_hwrapper, m_sectors);
+ (is, this, p2d, m_sectors);
sector->differs_from_disk = false;
return false;
}
- if(ENABLE_BLOCK_LOADING)
+ std::vector<fs::DirListNode> list2 = fs::GetDirListing
+ (m_savedir+"/sectors/"+sectorsubdir);
+ std::vector<fs::DirListNode>::iterator i2;
+ for(i2=list2.begin(); i2!=list2.end(); i2++)
{
- std::vector<fs::DirListNode> list2 = fs::GetDirListing
- (m_savedir+"/sectors/"+sectorsubdir);
- std::vector<fs::DirListNode>::iterator i2;
- for(i2=list2.begin(); i2!=list2.end(); i2++)
+ // We want files
+ if(i2->dir)
+ continue;
+ try{
+ loadBlock(sectorsubdir, i2->name, sector);
+ }
+ catch(InvalidFilenameException &e)
{
- // We want files
- if(i2->dir)
- continue;
- try{
- loadBlock(sectorsubdir, i2->name, sector);
- }
- catch(InvalidFilenameException &e)
- {
- // This catches unknown crap in directory
- }
+ // This catches unknown crap in directory
}
}
return true;
// Gets from master heightmap
void ServerMap::getSectorCorners(v2s16 p2d, s16 *corners)
{
- assert(m_heightmap != NULL);
+ dstream<<"DEPRECATED: "<<__FUNCTION_NAME<<std::endl;
+ //assert(m_heightmap != NULL);
/*
Corner definition:
v2s16(0,0),
v2s16(1,1),
v2s16(0,1),
*/
- corners[0] = m_heightmap->getGroundHeight
+ /*corners[0] = m_heightmap->getGroundHeight
((p2d+v2s16(0,0))*SECTOR_HEIGHTMAP_SPLIT);
corners[1] = m_heightmap->getGroundHeight
((p2d+v2s16(1,0))*SECTOR_HEIGHTMAP_SPLIT);
corners[2] = m_heightmap->getGroundHeight
((p2d+v2s16(1,1))*SECTOR_HEIGHTMAP_SPLIT);
corners[3] = m_heightmap->getGroundHeight
- ((p2d+v2s16(0,1))*SECTOR_HEIGHTMAP_SPLIT);
+ ((p2d+v2s16(0,1))*SECTOR_HEIGHTMAP_SPLIT);*/
}
void ServerMap::PrintInfo(std::ostream &out)
Map(dout_client),
scene::ISceneNode(parent, mgr, id),
m_client(client),
- mesh(NULL),
m_control(control)
{
- mesh_mutex.Init();
+ //mesh_mutex.Init();
/*m_box = core::aabbox3d<f32>(0,0,0,
map->getW()*BS, map->getH()*BS, map->getD()*BS);*/
ClientMap::~ClientMap()
{
- JMutexAutoLock lock(mesh_mutex);
+ /*JMutexAutoLock lock(mesh_mutex);
if(mesh != NULL)
{
mesh->drop();
mesh = NULL;
- }
+ }*/
}
MapSector * ClientMap::emergeSector(v2s16 p2d)
#endif
#include "common_irrlicht.h"
-#include "heightmap.h"
+//#include "heightmap.h"
#include "mapnode.h"
#include "mapblock.h"
#include "mapsector.h"
#define MAPTYPE_SERVER 1
#define MAPTYPE_CLIENT 2
-class Map : public NodeContainer, public Heightmappish
+class Map : public NodeContainer
{
public:
MapSector *m_sector_cache;
v2s16 m_sector_cache_p;
- WrapperHeightmap m_hwrapper;
+ //WrapperHeightmap m_hwrapper;
// Queued transforming water nodes
UniqueQueue<v3s16> m_transforming_liquid;
};
-// Master heightmap parameters
-struct HMParams
-{
- HMParams()
- {
- blocksize = 64;
- randmax = "constant 70.0";
- randfactor = "constant 0.6";
- base = "linear 0 80 0";
- }
- s16 blocksize;
- std::string randmax;
- std::string randfactor;
- std::string base;
-};
-
-// Map parameters
-struct MapParams
-{
- MapParams()
- {
- plants_amount = 1.0;
- ravines_amount = 1.0;
- //max_objects_in_block = 30;
- }
- float plants_amount;
- float ravines_amount;
- //u16 max_objects_in_block;
-};
-
/*
ServerMap
/*
savedir: directory to which map data should be saved
*/
- ServerMap(std::string savedir, HMParams hmp, MapParams mp);
+ ServerMap(std::string savedir);
~ServerMap();
s32 mapType() const
void save(bool only_changed);
void loadAll();
-
+
+ // TODO
+ void saveMapMeta();
+ void loadMapMeta();
+
+ // TODO
+ void saveChunkMeta();
+ void loadChunkMeta();
+
+ // DEPRECATED
void saveMasterHeightmap();
void loadMasterHeightmap();
// This only saves sector-specific data such as the heightmap
// (no MapBlocks)
+ // DEPRECATED? Sectors have no metadata anymore.
void saveSectorMeta(ServerMapSector *sector);
MapSector* loadSectorMeta(std::string dirname);
void loadBlock(std::string sectordir, std::string blockfile, MapSector *sector);
// Gets from master heightmap
+ // DEPRECATED?
void getSectorCorners(v2s16 p2d, s16 *corners);
// For debug printing
virtual void PrintInfo(std::ostream &out);
private:
- // Generator parameters
- UnlimitedHeightmap *m_heightmap;
- MapParams m_params;
- PointAttributeDatabase m_padb;
-
// Seed used for all kinds of randomness
u64 m_seed;
core::aabbox3d<f32> m_box;
// This is the master heightmap mesh
- scene::SMesh *mesh;
- JMutex mesh_mutex;
+ //scene::SMesh *mesh;
+ //JMutex mesh_mutex;
MapDrawControl &m_control;
};
bool new_style_water = g_settings.getBool("new_style_water");
float node_water_level = 1.0;
if(new_style_water)
- node_water_level = 0.8;
+ node_water_level = 0.9;
/*
We are including the faces of the trailing edges of the block.
ServerMapSector
*/
-ServerMapSector::ServerMapSector(NodeContainer *parent, v2s16 pos, u16 hm_split):
- MapSector(parent, pos),
- m_hm_split(hm_split),
- m_objects(NULL)
+ServerMapSector::ServerMapSector(NodeContainer *parent, v2s16 pos):
+ MapSector(parent, pos)
{
- // hm_split has to be 1 or 2^x
- assert(hm_split == 0 || hm_split == 1 || (hm_split & (hm_split-1)) == 0);
- assert(hm_split * hm_split <= MAPSECTOR_FIXEDHEIGHTMAPS_MAXCOUNT);
-
- for(u16 i=0; i<hm_split*hm_split; i++)
- m_heightmaps[i] = NULL;
}
ServerMapSector::~ServerMapSector()
{
- u16 hm_count = m_hm_split * m_hm_split;
-
- // Write heightmaps
- for(u16 i=0; i<hm_count; i++)
- {
- if(m_heightmaps[i])
- delete m_heightmaps[i];
- }
-
- if(m_objects)
- delete m_objects;
-}
-
-void ServerMapSector::setHeightmap(v2s16 hm_p, FixedHeightmap *hm)
-{
- assert(isInArea(hm_p, m_hm_split));
-
- s16 i = hm_p.Y * m_hm_split + hm_p.X;
-
- // Don't allow setting already set heightmaps as of now
- assert(m_heightmaps[i] == NULL);
-
- /*std::cout<<"MapSector::setHeightmap for sector "
- <<"("<<m_pos.X<<","<<m_pos.Y<<"): "
- <<"Setting heightmap "
- <<"("<<hm_p.X<<","<<hm_p.Y<<")"
- <<" which is i="<<i
- <<" to pointer "<<(long long)hm
- <<std::endl;*/
-
- m_heightmaps[i] = hm;
-
- differs_from_disk = true;
-}
-
-FixedHeightmap * ServerMapSector::getHeightmap(v2s16 hm_p)
-{
- assert(isInArea(hm_p, m_hm_split));
-
- s16 i = hm_p.Y * m_hm_split + hm_p.X;
-
- return m_heightmaps[i];
}
f32 ServerMapSector::getGroundHeight(v2s16 p, bool generate)
{
- // If no heightmaps
- if(m_hm_split == 0)
- {
- /*std::cout<<"Sector has no heightmap"
- <<" while trying to get height at ("<<p.X<<","<<p.Y<<")"
- <<" for sector ("<<m_pos.X<<","<<m_pos.Y<<")"
- <<std::endl;*/
- return GROUNDHEIGHT_NOTFOUND_SETVALUE;
- }
-
- // Side length of heightmap
- s16 hm_d = MAP_BLOCKSIZE / m_hm_split;
-
- // Position of selected heightmap
- v2s16 hm_p = getContainerPos(p, hm_d);
- if(isInArea(hm_p, m_hm_split) == false)
- {
- /*std::cout<<"Sector has no heightmap ("<<hm_p.X<<","<<hm_p.Y<<")"
- <<" while trying to get height at ("<<p.X<<","<<p.Y<<")"
- <<" for sector ("<<m_pos.X<<","<<m_pos.Y<<")"
- <<std::endl;*/
- return GROUNDHEIGHT_NOTFOUND_SETVALUE;
- }
-
- // Selected heightmap
- FixedHeightmap *hm = m_heightmaps[hm_p.Y * m_hm_split + hm_p.X];
-
- if(hm == NULL)
- {
- /*std::cout<<"Sector heightmap ("<<hm_p.X<<","<<hm_p.Y<<")"
- " is NULL"
- <<" while trying to get height at ("<<p.X<<","<<p.Y<<")"
- <<" for sector ("<<m_pos.X<<","<<m_pos.Y<<")"
- <<std::endl;*/
- return GROUNDHEIGHT_NOTFOUND_SETVALUE;
- }
-
- // Position in selected heighmap
- v2s16 p_in_hm = p - hm_p * hm_d;
- if(isInArea(p_in_hm, hm_d+1) == false)
- {
- /*std::cout<<"Position ("<<p_in_hm.X<<","<<p_in_hm.Y<<")"
- " not in sector heightmap area"
- <<" while trying to get height at ("<<p.X<<","<<p.Y<<")"
- <<" for sector ("<<m_pos.X<<","<<m_pos.Y<<")"
- <<std::endl;*/
- return GROUNDHEIGHT_NOTFOUND_SETVALUE;
- }
-
- f32 h = hm->getGroundHeight(p_in_hm);
-
- /*if(h < GROUNDHEIGHT_VALID_MINVALUE)
- {
- std::cout<<"Sector heightmap ("<<hm_p.X<<","<<hm_p.Y<<")"
- " returned invalid value"
- <<" while trying to get height at ("<<p.X<<","<<p.Y<<")"
- <<" which is ("<<p_in_hm.X<<","<<p_in_hm.Y<<") in heightmap"
- <<" for sector ("<<m_pos.X<<","<<m_pos.Y<<")"
- <<std::endl;
- }*/
-
- return h;
+ return GROUNDHEIGHT_NOTFOUND_SETVALUE;
}
void ServerMapSector::setGroundHeight(v2s16 p, f32 y, bool generate)
{
- /*
- NOTE:
- This causes glitches because the sector cannot be actually
- modified according to heightmap changes.
-
- This is useful when generating continued sub-heightmaps
- inside the sector.
- */
-
- // If no heightmaps
- if(m_hm_split == 0)
- return;
-
- // Side length of heightmap
- s16 hm_d = MAP_BLOCKSIZE / m_hm_split;
-
- // Position of selected heightmap
- v2s16 hm_p = getContainerPos(p, hm_d);
- if(isInArea(hm_p, m_hm_split) == false)
- return;
-
- // Selected heightmap
- FixedHeightmap *hm = m_heightmaps[hm_p.Y * m_hm_split + hm_p.X];
-
- if(hm == NULL)
- return;
-
- // Position in selected heighmap
- v2s16 p_in_hm = p - hm_p * hm_d;
- if(isInArea(p_in_hm, hm_d) == false)
- return;
-
- hm->setGroundHeight(p_in_hm, y);
-
- differs_from_disk = true;
}
void ServerMapSector::serialize(std::ostream &os, u8 version)
*/
// Server has both of these, no need to support not having them.
- assert(m_objects != NULL);
+ //assert(m_objects != NULL);
// Write version
os.write((char*)&version, 1);
/*
- Serialize heightmap(s)
+ Add stuff here, if needed
*/
- // Version with single heightmap
- if(version <= 7)
- {
- u32 heightmap_size =
- FixedHeightmap::serializedLength(version, MAP_BLOCKSIZE);
-
- SharedBuffer<u8> data(heightmap_size);
- m_heightmaps[0]->serialize(*data, version);
-
- os.write((const char*)*data, heightmap_size);
-
- if(version >= 5)
- {
- /*
- Write objects
- */
-
- u16 object_count;
- if(m_objects->size() > 65535)
- object_count = 65535;
- else
- object_count = m_objects->size();
-
- u8 b[2];
- writeU16(b, object_count);
- os.write((char*)b, 2);
-
- core::map<v3s16, u8>::Iterator i;
- i = m_objects->getIterator();
- for(; i.atEnd() == false; i++)
- {
- v3s16 p = i.getNode()->getKey();
- u8 d = i.getNode()->getValue();
- u8 b[7];
- writeV3S16(&b[0], p);
- b[6] = d;
- os.write((char*)b, 7);
- }
- }
- }
- // Version with multiple heightmaps
- else
- {
- u8 buf[2];
-
- if(m_hm_split > 255)
- throw SerializationError("Sector has too many heightmaps");
-
- // Write heightmap split ratio
- writeU8(buf, m_hm_split);
- os.write((char*)buf, 1);
-
- // If there are heightmaps, write them
- if(m_hm_split != 0)
- {
- u16 hm_d = MAP_BLOCKSIZE / m_hm_split;
-
- u32 hm_size = FixedHeightmap::serializedLength(version, hm_d);
- SharedBuffer<u8> data(hm_size);
-
- u16 hm_count = m_hm_split * m_hm_split;
-
- // Write heightmaps
- for(u16 i=0; i<hm_count; i++)
- {
- m_heightmaps[i]->serialize(*data, version);
- os.write((const char*)*data, hm_size);
- }
- }
-
- /*
- Write objects
- */
-
- u16 object_count;
- if(m_objects->size() > 65535)
- object_count = 65535;
- else
- object_count = m_objects->size();
-
- u8 b[2];
- writeU16(b, object_count);
- os.write((char*)b, 2);
-
- core::map<v3s16, u8>::Iterator i;
- i = m_objects->getIterator();
- for(; i.atEnd() == false; i++)
- {
- v3s16 p = i.getNode()->getKey();
- u8 d = i.getNode()->getValue();
- u8 b[7];
- writeV3S16(&b[0], p);
- b[6] = d;
- os.write((char*)b, 7);
- }
- }
}
ServerMapSector* ServerMapSector::deSerialize(
std::istream &is,
NodeContainer *parent,
v2s16 p2d,
- Heightmap *master_hm,
core::map<v2s16, MapSector*> & sectors
)
{
throw VersionMismatchException("ERROR: MapSector format not supported");
/*
- Read heightmap(s)
- */
-
- FixedHeightmap *hms[MAPSECTOR_FIXEDHEIGHTMAPS_MAXCOUNT];
- u16 hm_split = 0;
-
- // Version with a single heightmap
- if(version <= 7)
- {
- hm_split = 1;
-
- u32 hm_size =
- FixedHeightmap::serializedLength(version, MAP_BLOCKSIZE);
-
- SharedBuffer<u8> data(hm_size);
- is.read((char*)*data, hm_size);
-
- hms[0] = new FixedHeightmap(master_hm, p2d, MAP_BLOCKSIZE);
- hms[0]->deSerialize(*data, version);
- }
- // Version with multiple heightmaps
- else
- {
- u8 buf[2];
-
- // Read split ratio
- is.read((char*)buf, 1);
- hm_split = readU8(buf);
-
- // If there are heightmaps, read them
- if(hm_split != 0)
- {
- u16 hm_count = hm_split * hm_split;
-
- if(hm_count > MAPSECTOR_FIXEDHEIGHTMAPS_MAXCOUNT)
- throw SerializationError("Sector has too many heightmaps");
-
- u16 hm_d = MAP_BLOCKSIZE / hm_split;
-
- u32 hm_size = FixedHeightmap::serializedLength(version, hm_d);
-
- u16 i=0;
- for(s16 y=0; y<hm_split; y++)
- for(s16 x=0; x<hm_split; x++)
- {
- SharedBuffer<u8> data(hm_size);
- is.read((char*)*data, hm_size);
-
- hms[i] = new FixedHeightmap(master_hm, p2d+v2s16(x,y), hm_d);
- hms[i]->deSerialize(*data, version);
- i++;
- }
- }
- }
-
- /*
- Read objects
+ Add necessary reading stuff here
*/
-
- core::map<v3s16, u8> *objects = new core::map<v3s16, u8>;
-
- if(version >= 5)
- {
- u8 b[2];
- is.read((char*)b, 2);
- u16 object_count = readU16(b);
-
- for(u16 i=0; i<object_count; i++)
- {
- u8 b[7];
- is.read((char*)b, 7);
- v3s16 p = readV3S16(&b[0]);
- u8 d = b[6];
- objects->insert(p, d);
- }
- }
/*
Get or create sector
"at the moment, because code hasn't been tested."
<<std::endl;
- //assert(0);
MapSector *sector = n->getValue();
assert(sector->getId() == MAPSECTOR_SERVER);
return (ServerMapSector*)sector;
-
- // NOTE: At least hm_split mismatch would have to be checked
-
- //sector = n->getValue();
}
else
{
- sector = new ServerMapSector(parent, p2d, hm_split);
+ sector = new ServerMapSector(parent, p2d);
sectors.insert(p2d, sector);
}
Set stuff in sector
*/
- // Set heightmaps
-
- sector->m_hm_split = hm_split;
-
- u16 hm_count = hm_split * hm_split;
-
- for(u16 i=0; i<hm_count; i++)
- {
- // Set (or change) heightmap
- FixedHeightmap *oldhm = sector->m_heightmaps[i];
- sector->m_heightmaps[i] = hms[i];
- if(oldhm != NULL)
- delete oldhm;
- }
-
- // Set (or change) objects
- core::map<v3s16, u8> *oldfo = sector->m_objects;
- sector->m_objects = objects;
- if(oldfo)
- delete oldfo;
+ // Nothing here
return sector;
}
if(!ser_ver_supported(version))
throw VersionMismatchException("ERROR: MapSector format not supported");
- if(version <= 7)
- throw VersionMismatchException("ERROR: MapSector format not supported");
u8 buf[2];
- // Read corners
+ // Dummy read corners
is.read((char*)buf, 2);
- s16 c0 = readU16(buf);
is.read((char*)buf, 2);
- s16 c1 = readU16(buf);
is.read((char*)buf, 2);
- s16 c2 = readU16(buf);
is.read((char*)buf, 2);
- s16 c3 = readU16(buf);
/*
Set stuff in sector
*/
- m_corners[0] = c0;
- m_corners[1] = c1;
- m_corners[2] = c2;
- m_corners[3] = c3;
+ // Nothing here
+
}
#endif // !SERVER
#include <jmutex.h>
#include "common_irrlicht.h"
#include "mapblock.h"
-#include "heightmap.h"
+//#include "heightmap.h"
#include "exceptions.h"
/*
This is an Y-wise stack of MapBlocks.
*/
-#define SECTOR_OBJECT_TEST 0
-#define SECTOR_OBJECT_TREE_1 1
-#define SECTOR_OBJECT_BUSH_1 2
-#define SECTOR_OBJECT_RAVINE 3
-
-//#define MAPSECTOR_FIXEDHEIGHTMAPS_MAXCOUNT 4
-#define MAPSECTOR_FIXEDHEIGHTMAPS_MAXCOUNT \
- (SECTOR_HEIGHTMAP_SPLIT * SECTOR_HEIGHTMAP_SPLIT)
-
#define MAPSECTOR_SERVER 0
#define MAPSECTOR_CLIENT 1
-class MapSector: public NodeContainer, public Heightmappish
+class MapSector: public NodeContainer
{
public:
blockref->setNode(relpos, n);
}
+ // DEPRECATED?
virtual f32 getGroundHeight(v2s16 p, bool generate=false)
{
return GROUNDHEIGHT_NOTFOUND_SETVALUE;
class ServerMapSector : public MapSector
{
public:
- ServerMapSector(NodeContainer *parent, v2s16 pos, u16 hm_split);
+ ServerMapSector(NodeContainer *parent, v2s16 pos);
~ServerMapSector();
u32 getId() const
{
return MAPSECTOR_SERVER;
}
-
- void setHeightmap(v2s16 hm_p, FixedHeightmap *hm);
- FixedHeightmap * getHeightmap(v2s16 hm_p);
-
- void printHeightmaps()
- {
- for(s16 y=0; y<m_hm_split; y++)
- for(s16 x=0; x<m_hm_split; x++)
- {
- std::cout<<"Sector "
- <<"("<<m_pos.X<<","<<m_pos.Y<<")"
- " heightmap "
- "("<<x<<","<<y<<"):"
- <<std::endl;
- FixedHeightmap *hm = getHeightmap(v2s16(x,y));
- hm->print();
- }
- }
- void setObjects(core::map<v3s16, u8> *objects)
- {
- m_objects = objects;
- differs_from_disk = true;
- }
-
- core::map<v3s16, u8> * getObjects()
- {
- differs_from_disk = true;
- return m_objects;
- }
-
+ // DEPRECATED?
f32 getGroundHeight(v2s16 p, bool generate=false);
void setGroundHeight(v2s16 p, f32 y, bool generate=false);
std::istream &is,
NodeContainer *parent,
v2s16 p2d,
- Heightmap *master_hm,
core::map<v2s16, MapSector*> & sectors
);
private:
- // Heightmap(s) for the sector
- FixedHeightmap *m_heightmaps[MAPSECTOR_FIXEDHEIGHTMAPS_MAXCOUNT];
- // Sector is split in m_hm_split^2 heightmaps.
- // Value of 0 means there is no heightmap.
- u16 m_hm_split;
- // These are removed when they are drawn to blocks.
- // - Each is drawn when generating blocks; When the last one of
- // the needed blocks is being generated.
- core::map<v3s16, u8> *m_objects;
};
#ifndef SERVER
void deSerialize(std::istream &is);
- s16 getCorner(u16 i)
+ /*s16 getCorner(u16 i)
{
return m_corners[i];
- }
+ }*/
private:
// The ground height of the corners is stored in here
- s16 m_corners[4];
+ //s16 m_corners[4];
};
#endif
*/
Server::Server(
- std::string mapsavedir,
- HMParams hm_params,
- MapParams map_params
+ std::string mapsavedir
):
- m_env(new ServerMap(mapsavedir, hm_params, map_params), dout_server),
+ m_env(new ServerMap(mapsavedir), dout_server),
m_con(PROTOCOL_ID, 512, CONNECTION_TIMEOUT, this),
m_thread(this),
m_emergethread(this),
}
}
- // Trigger emergethread (it gets somehow gets to a
- // non-triggered but bysy state sometimes)
+ /*
+ Trigger emergethread (it somehow gets to a non-triggered but
+ bysy state sometimes)
+ */
{
float &counter = m_emergethread_trigger_timer;
counter += dtime;
NOTE: Every public method should be thread-safe
*/
Server(
- std::string mapsavedir,
- HMParams hm_params,
- MapParams map_params
+ std::string mapsavedir
);
~Server();
void start(unsigned short port);
init_mapnode(&irrlicht);
init_mineral(&irrlicht);
- // Read map parameters from settings
-
- HMParams hm_params;
- /*hm_params.blocksize = g_settings.getU16("heightmap_blocksize");
- hm_params.randmax = g_settings.get("height_randmax");
- hm_params.randfactor = g_settings.get("height_randfactor");
- hm_params.base = g_settings.get("height_base");*/
-
- MapParams map_params;
- map_params.plants_amount = g_settings.getFloat("plants_amount");
- map_params.ravines_amount = g_settings.getFloat("ravines_amount");
-
/*
Check parameters
*/
map_dir = g_settings.get("map-dir");
// Create server
- Server server(map_dir.c_str(), hm_params, map_params);
+ Server server(map_dir.c_str());
server.start(port);
// Run server
#include "map.h"
#include "player.h"
#include "main.h"
-#include "heightmap.h"
#include "socket.h"
#include "connection.h"
#include "utility.h"
parent.position_valid = false;
// Create one with no heightmaps
- ServerMapSector sector(&parent, v2s16(1,1), 0);
- //ConstantGenerator *dummyheightmap = new ConstantGenerator();
- //sector->setHeightmap(dummyheightmap);
+ ServerMapSector sector(&parent, v2s16(1,1));
EXCEPTION_CHECK(InvalidPositionException, sector.getBlockNoCreate(0));
EXCEPTION_CHECK(InvalidPositionException, sector.getBlockNoCreate(1));
}
};
-struct TestHeightmap
-{
- void TestSingleFixed()
- {
- const s16 BS1 = 4;
- OneChildHeightmap hm1(BS1);
-
- // Test that it is filled with < GROUNDHEIGHT_VALID_MINVALUE
- for(s16 y=0; y<=BS1; y++){
- for(s16 x=0; x<=BS1; x++){
- v2s16 p(x,y);
- assert(hm1.m_child.getGroundHeight(p)
- < GROUNDHEIGHT_VALID_MINVALUE);
- }
- }
-
- hm1.m_child.setGroundHeight(v2s16(1,0), 2.0);
- //hm1.m_child.print();
- assert(fabs(hm1.getGroundHeight(v2s16(1,0))-2.0)<0.001);
- hm1.setGroundHeight(v2s16(0,1), 3.0);
- assert(fabs(hm1.m_child.getGroundHeight(v2s16(0,1))-3.0)<0.001);
-
- // Fill with -1.0
- for(s16 y=0; y<=BS1; y++){
- for(s16 x=0; x<=BS1; x++){
- v2s16 p(x,y);
- hm1.m_child.setGroundHeight(p, -1.0);
- }
- }
-
- f32 corners[] = {0.0, 0.0, 1.0, 1.0};
- hm1.m_child.generateContinued(0.0, 0.0, corners);
-
- hm1.m_child.print();
- assert(fabs(hm1.m_child.getGroundHeight(v2s16(1,0))-0.2)<0.05);
- assert(fabs(hm1.m_child.getGroundHeight(v2s16(4,3))-0.7)<0.05);
- assert(fabs(hm1.m_child.getGroundHeight(v2s16(4,4))-1.0)<0.05);
- }
-
- void TestUnlimited()
- {
- //g_heightmap_debugprint = true;
- const s16 BS1 = 4;
- /*UnlimitedHeightmap hm1(BS1,
- new ConstantGenerator(0.0),
- new ConstantGenerator(0.0),
- new ConstantGenerator(5.0));*/
- PointAttributeDatabase padb;
- UnlimitedHeightmap hm1(BS1, &padb);
- // Go through it so it generates itself
- for(s16 y=0; y<=BS1; y++){
- for(s16 x=0; x<=BS1; x++){
- v2s16 p(x,y);
- hm1.getGroundHeight(p);
- }
- }
- // Print it
- dstream<<"UnlimitedHeightmap hm1:"<<std::endl;
- hm1.print();
-
- dstream<<"testing UnlimitedHeightmap set/get"<<std::endl;
- v2s16 p1(0,3);
- f32 v1(234.01);
- // Get first heightmap and try setGroundHeight
- FixedHeightmap * href = hm1.getHeightmap(v2s16(0,0));
- href->setGroundHeight(p1, v1);
- // Read from UnlimitedHeightmap
- assert(fabs(hm1.getGroundHeight(p1)-v1)<0.001);
- }
-
- void Random()
- {
- dstream<<"Running random code (get a human to check this)"<<std::endl;
- dstream<<"myrand() values: ";
- for(u16 i=0; i<5; i++)
- dstream<<(u16)myrand()<<" ";
- dstream<<std::endl;
-
- const s16 BS1 = 8;
- /*UnlimitedHeightmap hm1(BS1,
- new ConstantGenerator(10.0),
- new ConstantGenerator(0.3),
- new ConstantGenerator(0.0));*/
-
- PointAttributeDatabase padb;
-
- padb.getList("hm_baseheight")->addPoint(v2s16(-BS1,0), Attribute(0));
- padb.getList("hm_randmax")->addPoint(v2s16(-BS1,0), Attribute(0));
- padb.getList("hm_randfactor")->addPoint(v2s16(-BS1,0), Attribute(0.0));
-
- padb.getList("hm_baseheight")->addPoint(v2s16(0,0), Attribute(-20));
- padb.getList("hm_randmax")->addPoint(v2s16(0,0), Attribute(0));
- padb.getList("hm_randfactor")->addPoint(v2s16(0,0), Attribute(0.5));
-
- padb.getList("hm_baseheight")->addPoint(v2s16(BS1*2,BS1), Attribute(0));
- padb.getList("hm_randmax")->addPoint(v2s16(BS1*2,BS1), Attribute(30));
- padb.getList("hm_randfactor")->addPoint(v2s16(BS1*2,BS1), Attribute(0.63));
-
- UnlimitedHeightmap hm1(BS1, &padb);
-
- // Force hm1 to generate a some heightmap
- hm1.getGroundHeight(v2s16(0,0));
- hm1.getGroundHeight(v2s16(0,BS1));
- /*hm1.getGroundHeight(v2s16(BS1,-1));
- hm1.getGroundHeight(v2s16(BS1-1,-1));*/
- hm1.print();
-
- // Get the (0,0) and (1,0) heightmaps
- /*FixedHeightmap * hr00 = hm1.getHeightmap(v2s16(0,0));
- FixedHeightmap * hr01 = hm1.getHeightmap(v2s16(1,0));
- f32 corners[] = {1.0, 1.0, 1.0, 1.0};
- hr00->generateContinued(0.0, 0.0, corners);
- hm1.print();*/
-
- //assert(0);
- }
-
- void Run()
- {
- //srand(7); // Get constant random
- srand(time(0)); // Get better random
-
- TestSingleFixed();
- TestUnlimited();
- Random();
- }
-};
-
struct TestSocket
{
void Run()
TEST(TestVoxelManipulator);
TEST(TestMapBlock);
TEST(TestMapSector);
- TEST(TestHeightmap);
if(INTERNET_SIMULATOR == false){
TEST(TestSocket);
dout_con<<"=== BEGIN RUNNING UNIT TESTS FOR CONNECTION ==="<<std::endl;
next = seed;
}
-/*
- PointAttributeList
-*/
-
-// Float with distance
-struct DFloat
-{
- float v;
- u32 d;
-};
-
-float PointAttributeList::getInterpolatedFloat(v2s16 p)
-{
- const u32 near_wanted_count = 5;
- // Last is nearest, first is farthest
- core::list<DFloat> near_list;
-
- for(core::list<PointWithAttr>::Iterator
- i = m_points.begin();
- i != m_points.end(); i++)
- {
- PointWithAttr &pwa = *i;
- u32 d = pwa.p.getDistanceFrom(p);
-
- DFloat df;
- df.v = pwa.attr.getFloat();
- df.d = d;
-
- // If near list is empty, add directly and continue
- if(near_list.size() == 0)
- {
- near_list.push_back(df);
- continue;
- }
-
- // Get distance of farthest in near list
- u32 near_d = 100000;
- if(near_list.size() > 0)
- {
- core::list<DFloat>::Iterator i = near_list.begin();
- near_d = i->d;
- }
-
- /*
- If point is closer than the farthest in the near list or
- there are not yet enough points on the list
- */
- if(d < near_d || near_list.size() < near_wanted_count)
- {
- // Find the right place in the near list and put it there
-
- // Go from farthest to near in the near list
- core::list<DFloat>::Iterator i = near_list.begin();
- for(; i != near_list.end(); i++)
- {
- // Stop when i is at the first nearer node
- if(i->d < d)
- break;
- }
- // Add df to before i
- if(i == near_list.end())
- near_list.push_back(df);
- else
- near_list.insert_before(i, df);
-
- // Keep near list at right size
- if(near_list.size() > near_wanted_count)
- {
- core::list<DFloat>::Iterator j = near_list.begin();
- near_list.erase(j);
- }
- }
- }
-
- // Return if no values found
- if(near_list.size() == 0)
- return 0.0;
-
- /*
-20:58:29 < tejeez> joka pisteelle a += arvo / etäisyys^6; b += 1 / etäisyys^6; ja
-lopuks sit otetaan a/b
- */
-
- float a = 0;
- float b = 0;
- for(core::list<DFloat>::Iterator i = near_list.begin();
- i != near_list.end(); i++)
- {
- if(i->d == 0)
- return i->v;
-
- //float dd = pow((float)i->d, 6);
- float dd = pow((float)i->d, 5);
- float v = i->v;
- //dstream<<"dd="<<dd<<", v="<<v<<std::endl;
- a += v / dd;
- b += 1 / dd;
- }
-
- return a / b;
-}
-
-#if 0
-float PointAttributeList::getInterpolatedFloat(v3s16 p)
-{
- const u32 near_wanted_count = 2;
- const u32 nearest_wanted_count = 2;
- // Last is near
- core::list<DFloat> near;
-
- for(core::list<PointWithAttr>::Iterator
- i = m_points.begin();
- i != m_points.end(); i++)
- {
- PointWithAttr &pwa = *i;
- u32 d = pwa.p.getDistanceFrom(p);
-
- DFloat df;
- df.v = pwa.attr.getFloat();
- df.d = d;
-
- // If near list is empty, add directly and continue
- if(near_list.size() == 0)
- {
- near_list.push_back(df);
- continue;
- }
-
- // Get distance of farthest in near list
- u32 near_d = 100000;
- if(near_list.size() > 0)
- {
- core::list<DFloat>::Iterator i = near_list.begin();
- near_d = i->d;
- }
-
- /*
- If point is closer than the farthest in the near list or
- there are not yet enough points on the list
- */
- if(d < near_d || near_list.size() < near_wanted_count)
- {
- // Find the right place in the near list and put it there
-
- // Go from farthest to near in the near list
- core::list<DFloat>::Iterator i = near_list.begin();
- for(; i != near_list.end(); i++)
- {
- // Stop when i is at the first nearer node
- if(i->d < d)
- break;
- }
- // Add df to before i
- if(i == near_list.end())
- near_list.push_back(df);
- else
- near_list.insert_before(i, df);
-
- // Keep near list at right size
- if(near_list.size() > near_wanted_count)
- {
- core::list<DFloat>::Iterator j = near_list.begin();
- near_list.erase(j);
- }
- }
- }
-
- // Return if no values found
- if(near_list.size() == 0)
- return 0.0;
-
- /*
- Get nearest ones
- */
-
- u32 nearest_count = nearest_wanted_count;
- if(nearest_count > near_list.size())
- nearest_count = near_list.size();
- core::list<DFloat> nearest;
- {
- core::list<DFloat>::Iterator i = near_list.getLast();
- for(u32 j=0; j<nearest_count; j++)
- {
- nearest.push_front(*i);
- i--;
- }
- }
-
- /*
- TODO: Try this:
-20:58:29 < tejeez> joka pisteelle a += arvo / etäisyys^6; b += 1 / etäisyys^6; ja
-lopuks sit otetaan a/b
- */
-
- /*
- Get total distance to nearest points
- */
-
- float nearest_d_sum = 0;
- for(core::list<DFloat>::Iterator i = nearest.begin();
- i != nearest.end(); i++)
- {
- nearest_d_sum += (float)i->d;
- }
-
- /*
- Interpolate a value between the first ones
- */
-
- dstream<<"nearest.size()="<<nearest.size()<<std::endl;
-
- float interpolated = 0;
-
- for(core::list<DFloat>::Iterator i = nearest.begin();
- i != nearest.end(); i++)
- {
- float weight;
- if(nearest_d_sum > 0.001)
- weight = (float)i->d / nearest_d_sum;
- else
- weight = 1. / nearest.size();
- /*dstream<<"i->d="<<i->d<<" nearest_d_sum="<<nearest_d_sum
- <<" weight="<<weight<<std::endl;*/
- interpolated += weight * i->v;
- }
-
- return interpolated;
-}
-#endif
-
/*
blockpos: position of block in block coordinates
camera_pos: position of camera in nodes
return (myrand()%(max-min+1))+min;
}
-/*
- Some kind of a thing that stores attributes related to
- coordinate points
-*/
-
-struct Attribute
-{
- Attribute()
- {
- }
-
- Attribute(const std::string &value):
- m_value(value)
- {
- }
-
- Attribute(float value)
- {
- m_value = ftos(value);
- }
-
- void set(const std::string &value)
- {
- m_value = value;
- }
-
- std::string get()
- {
- return m_value;
- }
-
- bool getBool()
- {
- return is_yes(get());
- }
-
- float getFloat()
- {
- float f;
- std::istringstream vis(get());
- vis>>f;
- return f;
- }
-
- u16 getU16()
- {
- return stoi(get(), 0, 65535);
- }
-
- s16 getS16()
- {
- return stoi(get(), -32768, 32767);
- }
-
- s32 getS32()
- {
- return stoi(get());
- }
-
- std::string m_value;
-};
-
-class PointAttributeList
-{
- struct PointWithAttr
- {
- v2s16 p;
- Attribute attr;
- };
-
-public:
- ~PointAttributeList()
- {
- }
-
- Attribute getNearAttr(v2s16 p)
- {
- core::list<PointWithAttr>::Iterator
- nearest_i = m_points.end();
- s16 nearest_d = 32767;
- for(core::list<PointWithAttr>::Iterator
- i = m_points.begin();
- i != m_points.end(); i++)
- {
- PointWithAttr &pwa = *i;
- s16 d = pwa.p.getDistanceFrom(p);
- if(d < nearest_d)
- {
- nearest_i = i;
- nearest_d = d;
- }
- }
-
- if(nearest_i == m_points.end())
- Attribute();
-
- return nearest_i->attr;
- }
-
- Attribute getNearAttr(v3s16 p)
- {
- return getNearAttr(v2s16(p.X, p.Z));
- }
-
- bool empty()
- {
- return (m_points.size() == 0);
- }
-
- /*
- Take all points in range, or at least the nearest point,
- and interpolate the values as floats
- */
- float getInterpolatedFloat(v2s16 p);
-
- float getInterpolatedFloat(v3s16 p)
- {
- return getInterpolatedFloat(v2s16(p.X, p.Z));
- }
-
- void addPoint(v2s16 p, const Attribute &attr)
- {
- PointWithAttr pattr;
- pattr.p = p;
- pattr.attr = attr;
- m_points.push_back(pattr);
- }
-
- void addPoint(v3s16 p, const Attribute &attr)
- {
- addPoint(v2s16(p.X, p.Z), attr);
- }
-
-private:
- core::list<PointWithAttr> m_points;
-};
-
-/*
- Basically just a wrapper to core::map<PointAttributeList*>
-*/
-
-class PointAttributeDatabase
-{
-public:
- ~PointAttributeDatabase()
- {
- for(core::map<std::string, PointAttributeList*>::Iterator
- i = m_lists.getIterator();
- i.atEnd() == false; i++)
- {
- delete i.getNode()->getValue();
- }
- }
-
- PointAttributeList *getList(const std::string &name)
- {
- PointAttributeList *list = NULL;
-
- core::map<std::string, PointAttributeList*>::Node *n;
- n = m_lists.find(name);
-
- if(n == NULL)
- {
- list = new PointAttributeList();
- m_lists.insert(name, list);
- }
- else
- {
- list = n->getValue();
- }
-
- return list;
- }
-private:
- core::map<std::string, PointAttributeList*> m_lists;
-};
-
/*
Miscellaneous functions
*/