diff options
author | Perttu Ahola <celeron55@gmail.com> | 2011-01-16 19:32:14 +0200 |
---|---|---|
committer | Perttu Ahola <celeron55@gmail.com> | 2011-01-16 19:32:14 +0200 |
commit | 7068bc90af1f452359a1fcfe20fa01fc88f3d70a (patch) | |
tree | 43ecf753c1e178cfc29ce4f736d77897a340ed44 /src | |
parent | 69e7cd9b5b36783ec83a663789a95a3c512809c4 (diff) | |
download | minetest-7068bc90af1f452359a1fcfe20fa01fc88f3d70a.tar.gz minetest-7068bc90af1f452359a1fcfe20fa01fc88f3d70a.tar.bz2 minetest-7068bc90af1f452359a1fcfe20fa01fc88f3d70a.zip |
Initial commit of mapgen v.2. Lacks configuration and saving to disk.
Diffstat (limited to 'src')
-rw-r--r-- | src/constants.h | 2 | ||||
-rw-r--r-- | src/defaultsettings.cpp | 8 | ||||
-rw-r--r-- | src/environment.cpp | 2 | ||||
-rw-r--r-- | src/heightmap.cpp | 313 | ||||
-rw-r--r-- | src/heightmap.h | 30 | ||||
-rw-r--r-- | src/map.cpp | 375 | ||||
-rw-r--r-- | src/map.h | 14 | ||||
-rw-r--r-- | src/player.cpp | 43 | ||||
-rw-r--r-- | src/serialization.h | 3 | ||||
-rw-r--r-- | src/server.cpp | 91 | ||||
-rw-r--r-- | src/test.cpp | 26 | ||||
-rw-r--r-- | src/utility.cpp | 226 | ||||
-rw-r--r-- | src/utility.h | 243 |
13 files changed, 1193 insertions, 183 deletions
diff --git a/src/constants.h b/src/constants.h index cfb340bf9..e31f75d32 100644 --- a/src/constants.h +++ b/src/constants.h @@ -26,6 +26,8 @@ with this program; if not, write to the Free Software Foundation, Inc., Cross-platform compatibility crap should go in porting.h. */ +#define HAXMODE 0 + #define APPNAME "minetest" #define DEBUGFILE "debug.txt" diff --git a/src/defaultsettings.cpp b/src/defaultsettings.cpp index 581948071..dd4a7b2ef 100644 --- a/src/defaultsettings.cpp +++ b/src/defaultsettings.cpp @@ -48,10 +48,12 @@ void set_default_settings() g_settings.setDefault("ravines_amount", "1.0"); g_settings.setDefault("coal_amount", "1.0");*/ g_settings.setDefault("heightmap_blocksize", "16"); - g_settings.setDefault("height_randmax", "linear 0 0 30"); - g_settings.setDefault("height_randfactor", "linear 0.50 -0.10 0"); + //g_settings.setDefault("height_randmax", "linear 0 0 30"); + g_settings.setDefault("height_randmax", "linear 0.5 0 0"); + //g_settings.setDefault("height_randfactor", "linear 0.50 -0.10 0"); + g_settings.setDefault("height_randfactor", "linear 0.60 0 0"); g_settings.setDefault("height_base", "linear 5 0 0"); - g_settings.setDefault("plants_amount", "0.2"); + g_settings.setDefault("plants_amount", "1.0"); g_settings.setDefault("ravines_amount", "0"); g_settings.setDefault("coal_amount", "1.0"); diff --git a/src/environment.cpp b/src/environment.cpp index 906bab611..420681355 100644 --- a/src/environment.cpp +++ b/src/environment.cpp @@ -107,7 +107,7 @@ void Environment::step(float dtime) v3f playerpos = player->getPosition(); // Apply physics to local player - if(player->isLocal()) + if(player->isLocal() && HAXMODE == false) { // Apply gravity to local player v3f speed = player->getSpeed(); diff --git a/src/heightmap.cpp b/src/heightmap.cpp index 2f7ecc4dc..bb7f2a1d1 100644 --- a/src/heightmap.cpp +++ b/src/heightmap.cpp @@ -23,6 +23,9 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "heightmap.h" +// For MAP_BLOCKSIZE +#include "mapblock.h" + /* ValueGenerator */ @@ -259,59 +262,6 @@ void FixedHeightmap::generateContinued(f32 randmax, f32 randfactor, } /* - Seed borders from master heightmap - NOTE: Does this actually have any effect on the output? - */ - /*struct SeedSpec - { - v2s16 neighbour_start; - v2s16 heightmap_start; - v2s16 dir; - }; - - SeedSpec seeds[4] = - { - { // Z- edge on X-axis - v2s16(0, -1), // neighbour_start - v2s16(0, 0), // heightmap_start - v2s16(1, 0) // dir - }, - { // Z+ edge on X-axis - v2s16(0, m_blocksize), - v2s16(0, m_blocksize), - v2s16(1, 0) - }, - { // X- edge on Z-axis - v2s16(-1, 0), - v2s16(0, 0), - v2s16(0, 1) - }, - { // X+ edge on Z-axis - v2s16(m_blocksize, 0), - v2s16(m_blocksize, 0), - v2s16(0, 1) - }, - }; - - for(s16 i=0; i<4; i++){ - v2s16 npos = seeds[i].neighbour_start + m_pos_on_master * m_blocksize; - v2s16 hpos = seeds[i].heightmap_start; - for(s16 s=0; s<m_blocksize+1; s++){ - f32 h = m_master->getGroundHeight(npos, false); - //dstream<<"h="<<h<<std::endl; - if(h < GROUNDHEIGHT_VALID_MINVALUE) - continue; - //break; - setGroundHeight(hpos, h); - hpos += seeds[i].dir; - npos += seeds[i].dir; - } - }*/ - - /*dstream<<"borders seeded:"<<std::endl; - print();*/ - - /* Fill with corners[] (if not already set) */ v2s16 dirs[4] = { @@ -549,29 +499,51 @@ FixedHeightmap * UnlimitedHeightmap::getHeightmap(v2s16 p_from, bool generate) m_heightmaps.insert(p, heightmap); f32 corners[4]; - - if(m_palist) + + s32 div = SECTOR_HEIGHTMAP_SPLIT * MAP_BLOCKSIZE; + { - //TODO: palist must be taken into account in generateContinued. - // It is almost useless in here. - s32 div = 2 * 16; - Settings *attr = m_palist->getNearAttr(p / div); - assert(attr); - corners[0] = attr->getFloat("baseheight"); - corners[1] = attr->getFloat("baseheight"); - corners[2] = attr->getFloat("baseheight"); - corners[3] = attr->getFloat("baseheight"); + 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 + /*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_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); } @@ -702,6 +674,148 @@ void UnlimitedHeightmap::serialize(std::ostream &os, u8 version) /*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") @@ -797,9 +911,11 @@ void UnlimitedHeightmap::serialize(std::ostream &os, u8 version) i++; } } +#endif } -UnlimitedHeightmap * UnlimitedHeightmap::deSerialize(std::istream &is) +UnlimitedHeightmap * UnlimitedHeightmap::deSerialize(std::istream &is, + PointAttributeDatabase *padb) { u8 version; is.read((char*)&version, 1); @@ -823,9 +939,10 @@ UnlimitedHeightmap * UnlimitedHeightmap::deSerialize(std::istream &is) throw SerializationError ("UnlimitedHeightmap::deSerialize: no enough input data"); s16 blocksize = readU16(&data[0]); - f32 randmax = (f32)readU32(&data[2]) / 1000.0; - f32 randfactor = (f32)readU32(&data[6]) / 1000.0; - f32 basevalue = (f32)readU32(&data[10]) / 1000.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():" @@ -838,12 +955,12 @@ UnlimitedHeightmap * UnlimitedHeightmap::deSerialize(std::istream &is) //dstream<<"heightmap_size="<<heightmap_size<<std::endl; - ValueGenerator *maxgen = new ConstantGenerator(randmax); + /*ValueGenerator *maxgen = new ConstantGenerator(randmax); ValueGenerator *factorgen = new ConstantGenerator(randfactor); - ValueGenerator *basegen = new ConstantGenerator(basevalue); - + ValueGenerator *basegen = new ConstantGenerator(basevalue);*/ + UnlimitedHeightmap *hm = new UnlimitedHeightmap - (blocksize, maxgen, factorgen, basegen, NULL); + (blocksize, padb); for(u32 i=0; i<heightmap_count; i++) { @@ -862,6 +979,44 @@ UnlimitedHeightmap * UnlimitedHeightmap::deSerialize(std::istream &is) } 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]; @@ -869,9 +1024,9 @@ UnlimitedHeightmap * UnlimitedHeightmap::deSerialize(std::istream &is) is.read((char*)buf, 2); s16 blocksize = readU16(buf); - ValueGenerator *maxgen = ValueGenerator::deSerialize(is); + /*ValueGenerator *maxgen = ValueGenerator::deSerialize(is); ValueGenerator *factorgen = ValueGenerator::deSerialize(is); - ValueGenerator *basegen = ValueGenerator::deSerialize(is); + ValueGenerator *basegen = ValueGenerator::deSerialize(is);*/ is.read((char*)buf, 4); u32 heightmap_count = readU32(buf); @@ -880,7 +1035,7 @@ UnlimitedHeightmap * UnlimitedHeightmap::deSerialize(std::istream &is) FixedHeightmap::serializedLength(version, blocksize); UnlimitedHeightmap *hm = new UnlimitedHeightmap - (blocksize, maxgen, factorgen, basegen, NULL); + (blocksize, padb); for(u32 i=0; i<heightmap_count; i++) { diff --git a/src/heightmap.h b/src/heightmap.h index fe0a7f405..aba3b050d 100644 --- a/src/heightmap.h +++ b/src/heightmap.h @@ -503,30 +503,31 @@ private: s16 m_blocksize; // TODO: Remove ValueGenerators - ValueGenerator *m_randmax_generator; + /*ValueGenerator *m_randmax_generator; ValueGenerator *m_randfactor_generator; - ValueGenerator *m_base_generator; + ValueGenerator *m_base_generator;*/ - PointAttributeList *m_palist; + PointAttributeDatabase *m_padb; public: UnlimitedHeightmap( s16 blocksize, - ValueGenerator *randmax_generator, + /*ValueGenerator *randmax_generator, ValueGenerator *randfactor_generator, - ValueGenerator *base_generator, - PointAttributeList *palist=NULL + ValueGenerator *base_generator,*/ + PointAttributeDatabase *padb ): m_blocksize(blocksize), - m_randmax_generator(randmax_generator), + /*m_randmax_generator(randmax_generator), m_randfactor_generator(randfactor_generator), - m_base_generator(base_generator), - m_palist(palist) + m_base_generator(base_generator),*/ + m_padb(padb) { - assert(m_randmax_generator != NULL); + /*assert(m_randmax_generator != NULL); assert(m_randfactor_generator != NULL); - assert(m_base_generator != NULL); + assert(m_base_generator != NULL);*/ + assert(m_padb); } ~UnlimitedHeightmap() @@ -538,9 +539,9 @@ public: delete i.getNode()->getValue(); } - delete m_randmax_generator; + /*delete m_randmax_generator; delete m_randfactor_generator; - delete m_base_generator; + delete m_base_generator;*/ } void print(); @@ -563,7 +564,8 @@ public: //SharedBuffer<u8> serialize(u8 version); void serialize(std::ostream &os, u8 version); - static UnlimitedHeightmap * deSerialize(std::istream &istr); + static UnlimitedHeightmap * deSerialize(std::istream &istr, + PointAttributeDatabase *padb); }; #endif diff --git a/src/map.cpp b/src/map.cpp index c8175c4cf..c290f69e9 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -1312,6 +1312,197 @@ ServerMap::ServerMap(std::string savedir, HMParams hmp, MapParams mp): Map(dout_server), m_heightmap(NULL) { + /* + Experimental and debug stuff + */ + + { + 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"); + + for(u32 i=0; i<3000; i++) + { + u32 lim = MAP_GENERATION_LIMIT; + if(i < 200) + lim = 1000; + + 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()%5 == 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; + } + + 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_plants_amount->addPoint(p, Attribute(plants_amount)); + list_caves_amount->addPoint(p, Attribute(caves_amount)); + } +#if 1 + for(u32 i=0; i<3000; i++) + { + u32 lim = MAP_GENERATION_LIMIT; + if(i < 100) + lim = 1000; + + 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()%4 == 0) + { + baseheight = 100; + randmax = 100; + randfactor = 0.63; + } + else if(myrand()%5 == 0) + { + baseheight = 200; + randmax = 200; + 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.60; + } + else + { + baseheight = -3; + randmax = 20; + randfactor = 0.5; + } + + list_baseheight->addPoint(p, Attribute(baseheight)); + list_randmax->addPoint(p, Attribute(randmax)); + list_randfactor->addPoint(p, Attribute(randfactor)); + } +#endif + + /*list_baseheight->addPoint(v3s16(0,0,0), Attribute(5)); + list_randmax->addPoint(v3s16(0,0,0), Attribute(20)); + list_randfactor->addPoint(v3s16(0,0,0), Attribute(0.6));*/ + } + +#if 0 + { + PointAttributeList *palist = m_padb.getList("hm_baseheight"); + + { + v3s16 p(0,0,0); + Attribute attr; + attr.set("5"); + palist->addPoint(p, attr); + } + + /*{ + v3s16 p(-50,-50,0); + Attribute attr; + attr.set("-10"); + palist->addPoint(p, attr); + } + + { + v3s16 p(50,0,50); + Attribute attr; + attr.set("200"); + palist->addPoint(p, attr); + }*/ + } +#endif +#if 0 + { + PointAttributeList *palist = m_padb.getList("plants_amount"); + + // Back + { + v3s16 p(0,0,-100); + Attribute attr; + attr.set("0"); + palist->addPoint(p, attr); + } + + // Front right + { + v3s16 p(100,0,100); + Attribute attr; + attr.set("2.0"); + palist->addPoint(p, attr); + } + + // Front left + { + v3s16 p(-100,0,100); + Attribute attr; + attr.set("0.2"); + palist->addPoint(p, attr); + } + } +#endif + + /* + Try to load map; if not found, create a new one. + */ + m_savedir = savedir; m_map_saving_enabled = false; @@ -1362,14 +1553,20 @@ ServerMap::ServerMap(std::string savedir, HMParams hmp, MapParams mp): dstream<<DTIME<<"Initializing new map."<<std::endl; // Create master heightmap - ValueGenerator *maxgen = + /*ValueGenerator *maxgen = ValueGenerator::deSerialize(hmp.randmax); ValueGenerator *factorgen = ValueGenerator::deSerialize(hmp.randfactor); ValueGenerator *basegen = ValueGenerator::deSerialize(hmp.base); m_heightmap = new UnlimitedHeightmap - (hmp.blocksize, maxgen, factorgen, basegen); + (hmp.blocksize, maxgen, factorgen, basegen, &m_padb);*/ + + /*m_heightmap = new UnlimitedHeightmap + (hmp.blocksize, &m_padb);*/ + + m_heightmap = new UnlimitedHeightmap + (32, &m_padb); // Set map parameters m_params = mp; @@ -1456,50 +1653,17 @@ MapSector * ServerMap::emergeSector(v2s16 p2d) s16 hm_d = MAP_BLOCKSIZE / hm_split; ServerMapSector *sector = new ServerMapSector(this, p2d, hm_split); + + // Sector position on map in nodes + v2s16 nodepos2d = p2d * MAP_BLOCKSIZE; /*dstream<<"Generating sector ("<<p2d.X<<","<<p2d.Y<<")" " heightmaps and objects"<<std::endl;*/ - // 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); - - //TODO: Make these values configurable - - //hm->generateContinued(0.0, 0.0, corners); - hm->generateContinued(0.25, 0.2, corners); - //hm->generateContinued(0.5, 0.2, corners); - //hm->generateContinued(1.0, 0.2, corners); - //hm->generateContinued(2.0, 0.2, corners); - - //hm->print(); - - } - /* - Generate objects + Calculate some information about local properties */ - core::map<v3s16, u8> *objects = new core::map<v3s16, u8>; - sector->setObjects(objects); - v2s16 mhm_p = p2d * hm_split; f32 corners[4] = { m_heightmap->getGroundHeight(mhm_p+v2s16(0,0)*hm_split), @@ -1535,19 +1699,78 @@ MapSector * ServerMap::emergeSector(v2s16 p2d) pitness /= 4.0; pitness /= MAP_BLOCKSIZE; //dstream<<"pitness="<<pitness<<std::endl; + + /* + Get local attributes + */ + // Get plant amount from attributes + PointAttributeList *palist = m_padb.getList("plants_amount"); + assert(palist); + /*float local_plants_amount = + palist->getNearAttr(nodepos2d).getFloat();*/ + float local_plants_amount = + palist->getInterpolatedFloat(nodepos2d); + + /* + Generate sector heightmap + */ + + // 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); + + //TODO: Make these values configurable + //hm->generateContinued(0.0, 0.0, corners); + //hm->generateContinued(0.25, 0.2, corners); + //hm->generateContinued(0.5, 0.2, corners); + //hm->generateContinued(1.0, 0.2, corners); + //hm->generateContinued(2.0, 0.2, corners); + hm->generateContinued(2.0 * avgslope, 0.5, corners); + + //hm->print(); + } + + /* + Generate objects + */ + + core::map<v3s16, u8> *objects = new core::map<v3s16, u8>; + sector->setObjects(objects); + /* Plant some trees if there is not much slope */ { // Avgslope is the derivative of a hill - float t = avgslope * avgslope; - float a = MAP_BLOCKSIZE * m_params.plants_amount; + //float t = avgslope * avgslope; + float t = avgslope; + float a = MAP_BLOCKSIZE * m_params.plants_amount * local_plants_amount; u32 tree_max; - if(t > 0.03) - tree_max = a / (t/0.03); + //float something = 0.17*0.17; + float something = 0.3; + if(t > something) + tree_max = a / (t/something); else tree_max = a; + u32 count = (myrand()%(tree_max+1)); //u32 count = tree_max; for(u32 i=0; i<count; i++) @@ -1567,7 +1790,7 @@ MapSector * ServerMap::emergeSector(v2s16 p2d) { // Pitness usually goes at around -0.5...0.5 u32 bush_max = 0; - u32 a = MAP_BLOCKSIZE * 3.0 * m_params.plants_amount; + u32 a = MAP_BLOCKSIZE * 3.0 * m_params.plants_amount * local_plants_amount; if(pitness > 0) bush_max = (pitness*a*4); if(bush_max > a) @@ -1589,7 +1812,7 @@ MapSector * ServerMap::emergeSector(v2s16 p2d) */ if(m_params.ravines_amount != 0) { - if(myrand()%(s32)(20.0 / m_params.ravines_amount) == 0) + if(myrand()%(s32)(200.0 / m_params.ravines_amount) == 0) { s16 s = 6; s16 x = myrand()%(MAP_BLOCKSIZE-s*2-1)+s; @@ -1839,6 +2062,14 @@ MapBlock * ServerMap::emergeBlock( bool some_part_underground = block_y * MAP_BLOCKSIZE <= highest_ground_y; /* + Get local attributes + */ + + v2s16 nodepos2d = p2d * MAP_BLOCKSIZE; + PointAttributeList *list_caves_amount = m_padb.getList("caves_amount"); + float caves_amount = list_caves_amount->getInterpolatedFloat(nodepos2d); + + /* Generate dungeons */ @@ -1937,20 +2168,60 @@ MapBlock * ServerMap::emergeBlock( } catch(InvalidPositionException &e){} + // Check y- + try + { + s16 y = -1; + for(s16 x=0; x<ued; x++) + for(s16 z=0; z<ued; z++) + { + v3s16 ap = v3s16(x,y,z) + block->getPosRelative(); + if(getNode(ap).d == CONTENT_AIR) + { + orp = v3f(x+1,0,z+1); + found_existing = true; + goto continue_generating; + } + } + } + catch(InvalidPositionException &e){} + + // Check y+ + try + { + s16 y = ued; + for(s16 x=0; x<ued; x++) + for(s16 z=0; z<ued; z++) + { + v3s16 ap = v3s16(x,y,z) + block->getPosRelative(); + if(getNode(ap).d == CONTENT_AIR) + { + orp = v3f(x+1,ued-1,z+1); + found_existing = true; + goto continue_generating; + } + } + } + catch(InvalidPositionException &e){} + continue_generating: /* Don't always generate dungeon */ bool do_generate_dungeons = true; + // Don't generate if no part is underground if(!some_part_underground) do_generate_dungeons = false; + // If block is partly underground, caves are generated. else if(!completely_underground) - do_generate_dungeons = rand() % 5; - else if(found_existing) + do_generate_dungeons = (rand() % 100 <= (u32)(caves_amount*100)); + // Always continue if found existing dungeons underground + else if(found_existing && completely_underground) do_generate_dungeons = true; + // If underground and no dungeons found else - do_generate_dungeons = rand() % 2; + do_generate_dungeons = (rand() % 2 == 0); if(do_generate_dungeons) { @@ -2426,6 +2697,12 @@ continue_generating: changed_blocks.insert(block->getPos(), block); } + + if(HAXMODE) + { + // Don't calculate lighting at all + lighting_invalidated_blocks.clear(); + } return block; } @@ -2659,7 +2936,7 @@ void ServerMap::loadMasterHeightmap() if(m_heightmap != NULL) delete m_heightmap; - m_heightmap = UnlimitedHeightmap::deSerialize(is); + m_heightmap = UnlimitedHeightmap::deSerialize(is, &m_padb); } void ServerMap::saveSectorMeta(ServerMapSector *sector) @@ -381,6 +381,12 @@ struct MapParams //u16 max_objects_in_block; }; +/* + ServerMap + + This is the only map class that is able to generate map. +*/ + class ServerMap : public Map { public: @@ -467,8 +473,10 @@ public: virtual void PrintInfo(std::ostream &out); private: + // Generator parameters UnlimitedHeightmap *m_heightmap; MapParams m_params; + PointAttributeDatabase m_padb; std::string m_savedir; bool m_map_saving_enabled; @@ -503,6 +511,12 @@ struct MapDrawControl class Client; +/* + ClientMap + + This is the only map class that is able to render itself on screen. +*/ + class ClientMap : public Map, public scene::ISceneNode { public: diff --git a/src/player.cpp b/src/player.cpp index 37fcda991..3c06283a0 100644 --- a/src/player.cpp +++ b/src/player.cpp @@ -286,6 +286,10 @@ void LocalPlayer::move(f32 dtime, Map &map) { // Doing nothing here will block the player from // walking over map borders + + // Go over borders in debug mode + if(HAXMODE) + continue; } core::aabbox3d<f32> nodebox = Map::getNodeBox( @@ -374,14 +378,33 @@ void LocalPlayer::applyControl(float dtime) v3f speed = v3f(0,0,0); + if(HAXMODE) + { + v3f speed = getSpeed(); + speed.Y = 0; + setSpeed(speed); + } + // Superspeed mode bool superspeed = false; if(control.superspeed) { - speed += move_direction; - superspeed = true; + if(HAXMODE) + { + v3f speed = getSpeed(); + speed.Y = -20*BS; + setSpeed(speed); + } + else + { + speed += move_direction; + superspeed = true; + } } + if(HAXMODE) + superspeed = true; + if(control.up) { speed += move_direction; @@ -400,7 +423,16 @@ void LocalPlayer::applyControl(float dtime) } if(control.jump) { - if(touching_ground) + if(HAXMODE) + { + v3f speed = getSpeed(); + /*speed.Y += 20.*BS * dtime * 2; + if(speed.Y < 0) + speed.Y = 0;*/ + speed.Y = 20*BS; + setSpeed(speed); + } + else if(touching_ground) { v3f speed = getSpeed(); speed.Y = 6.5*BS; @@ -421,7 +453,10 @@ void LocalPlayer::applyControl(float dtime) speed = speed.normalize() * walkspeed_max; f32 inc = walk_acceleration * BS * dtime; - + + if(HAXMODE) + inc = walk_acceleration * BS * dtime * 10; + // Accelerate to target speed with maximum increment accelerate(speed, inc); } diff --git a/src/serialization.h b/src/serialization.h index 3206b580a..a2eca2357 100644 --- a/src/serialization.h +++ b/src/serialization.h @@ -44,11 +44,12 @@ with this program; if not, write to the Free Software Foundation, Inc., 9: (dev) block objects 10: (dev) water pressure 11: (dev) zlib'd blocks, block flags + 12: (dev) UnlimitedHeightmap now uses interpolated areas */ // This represents an uninitialized or invalid format #define SER_FMT_VER_INVALID 255 // Highest supported serialization version -#define SER_FMT_VER_HIGHEST 11 +#define SER_FMT_VER_HIGHEST 12 // Lowest supported serialization version #define SER_FMT_VER_LOWEST 2 diff --git a/src/server.cpp b/src/server.cpp index 9d2e9697d..da643339b 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -149,13 +149,39 @@ void * EmergeThread::Thread() if(optional) only_from_disk = true; + + // First check if the block already exists + if(only_from_disk) + { + block = map.getBlockNoCreate(p); + } - block = map.emergeBlock( - p, - only_from_disk, - changed_blocks, - lighting_invalidated_blocks); + if(block == NULL) + { + block = map.emergeBlock( + p, + only_from_disk, + changed_blocks, + lighting_invalidated_blocks); + /* + EXPERIMENTAL: Create a few other blocks too + */ + + map.emergeBlock( + p + v3s16(0,1,0), + only_from_disk, + changed_blocks, + lighting_invalidated_blocks); + + map.emergeBlock( + p + v3s16(0,-1,0), + only_from_disk, + changed_blocks, + lighting_invalidated_blocks); + + } + // If it is a dummy, block was not found on disk if(block->isDummy()) { @@ -457,10 +483,19 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime, continue; bool generate = d <= d_max_gen; - - // Limit the generating area vertically to 2/3 - if(abs(p.Y - center.Y) > d_max_gen - d_max_gen / 3) - generate = false; + + if(HAXMODE) + { + // Don't generate above player + if(p.Y > center.Y) + generate = false; + } + else + { + // Limit the generating area vertically to 2/3 + if(abs(p.Y - center.Y) > d_max_gen - d_max_gen / 3) + generate = false; + } /* Don't send already sent blocks @@ -472,6 +507,23 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime, continue; } + if(HAXMODE) + { + /* + Ignore block if it is not at ground surface + */ + v2s16 p2d(p.X*MAP_BLOCKSIZE + MAP_BLOCKSIZE/2, + p.Z*MAP_BLOCKSIZE + MAP_BLOCKSIZE/2); + f32 y = server->m_env.getMap().getGroundHeight(p2d); + // The sector might not exist yet, thus no heightmap + if(y > GROUNDHEIGHT_VALID_MINVALUE) + { + f32 by = p.Y*MAP_BLOCKSIZE + MAP_BLOCKSIZE/2; + if(fabs(by - y) > MAP_BLOCKSIZE + MAP_BLOCKSIZE/3) + continue; + } + } + /* Check if map has this block */ @@ -2980,22 +3032,9 @@ Player *Server::emergePlayer(const char *name, const char *password) /* Set player position */ -#if 0 - // We're going to throw the player to this position - //v2s16 nodepos(29990,29990); - //v2s16 nodepos(9990,9990); - v2s16 nodepos(0,0); - v2s16 sectorpos = getNodeSectorPos(nodepos); - // Get sector - m_env.getMap().emergeSector(sectorpos); - // Get ground height at point - f32 groundheight = m_env.getMap().getGroundHeight(nodepos, true); - // The sector should have been generated -> groundheight exists - assert(groundheight > GROUNDHEIGHT_VALID_MINVALUE); - // Don't go underwater - if(groundheight < WATER_LEVEL) - groundheight = WATER_LEVEL; -#endif + + dstream<<"Server: Finding spawn place for player \"" + <<player->getName()<<"\""<<std::endl; #if 1 v2s16 nodepos; @@ -3003,7 +3042,7 @@ Player *Server::emergePlayer(const char *name, const char *password) // Try to find a good place a few times for(s32 i=0; i<100; i++) { - s32 range = 1 + i*2; + s32 range = 1 + i*4; // We're going to try to throw the player to this position nodepos = v2s16(-range/2 + (myrand()%range), -range/2 + (myrand()%range)); diff --git a/src/test.cpp b/src/test.cpp index f8f954742..d78c62120 100644 --- a/src/test.cpp +++ b/src/test.cpp @@ -695,10 +695,12 @@ struct TestHeightmap { //g_heightmap_debugprint = true; const s16 BS1 = 4; - UnlimitedHeightmap hm1(BS1, + /*UnlimitedHeightmap hm1(BS1, new ConstantGenerator(0.0), new ConstantGenerator(0.0), - new ConstantGenerator(5.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++){ @@ -729,10 +731,26 @@ struct TestHeightmap dstream<<std::endl; const s16 BS1 = 8; - UnlimitedHeightmap hm1(BS1, + /*UnlimitedHeightmap hm1(BS1, new ConstantGenerator(10.0), new ConstantGenerator(0.3), - new ConstantGenerator(0.0)); + 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.9)); + + UnlimitedHeightmap hm1(BS1, &padb); // Force hm1 to generate a some heightmap hm1.getGroundHeight(v2s16(0,0)); diff --git a/src/utility.cpp b/src/utility.cpp index 924324b90..d6ca48153 100644 --- a/src/utility.cpp +++ b/src/utility.cpp @@ -102,4 +102,230 @@ void mysrand(unsigned seed) next = seed; } +// Float with distance +struct DFloat +{ + float v; + u32 d; +}; + +float PointAttributeList::getInterpolatedFloat(v3s16 p) +{ + const u32 near_wanted_count = 5; + // Last is nearest, first is farthest + 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.size() == 0) + { + near.push_back(df); + continue; + } + + // Get distance of farthest in near list + u32 near_d = 100000; + if(near.size() > 0) + { + core::list<DFloat>::Iterator i = near.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.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.begin(); + for(; i != near.end(); i++) + { + // Stop when i is at the first nearer node + if(i->d < d) + break; + } + // Add df to before i + if(i == near.end()) + near.push_back(df); + else + near.insert_before(i, df); + + // Keep near list at right size + if(near.size() > near_wanted_count) + { + core::list<DFloat>::Iterator j = near.begin(); + near.erase(j); + } + } + } + + // Return if no values found + if(near.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.begin(); + i != near.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.size() == 0) + { + near.push_back(df); + continue; + } + + // Get distance of farthest in near list + u32 near_d = 100000; + if(near.size() > 0) + { + core::list<DFloat>::Iterator i = near.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.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.begin(); + for(; i != near.end(); i++) + { + // Stop when i is at the first nearer node + if(i->d < d) + break; + } + // Add df to before i + if(i == near.end()) + near.push_back(df); + else + near.insert_before(i, df); + + // Keep near list at right size + if(near.size() > near_wanted_count) + { + core::list<DFloat>::Iterator j = near.begin(); + near.erase(j); + } + } + } + + // Return if no values found + if(near.size() == 0) + return 0.0; + + /* + Get nearest ones + */ + + u32 nearest_count = nearest_wanted_count; + if(nearest_count > near.size()) + nearest_count = near.size(); + core::list<DFloat> nearest; + { + core::list<DFloat>::Iterator i = near.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 + diff --git a/src/utility.h b/src/utility.h index e2a6afdea..28cc95ddd 100644 --- a/src/utility.h +++ b/src/utility.h @@ -666,6 +666,20 @@ inline s32 stoi(std::string s) return atoi(s.c_str()); } +inline std::string itos(s32 i) +{ + std::ostringstream o; + o<<i; + return o.str(); +} + +inline std::string ftos(float f) +{ + std::ostringstream o; + o<<f; + return o.str(); +} + /* A base class for simple background thread implementation */ @@ -1101,6 +1115,46 @@ public: return stoi(get(name)); } + void clear() + { + m_settings.clear(); + m_defaults.clear(); + } + + Settings & operator+=(Settings &other) + { + if(&other == this) + return *this; + + for(core::map<std::string, std::string>::Iterator + i = other.m_settings.getIterator(); + i.atEnd() == false; i++) + { + m_settings.insert(i.getNode()->getKey(), + i.getNode()->getValue()); + } + + for(core::map<std::string, std::string>::Iterator + i = other.m_defaults.getIterator(); + i.atEnd() == false; i++) + { + m_defaults.insert(i.getNode()->getKey(), + i.getNode()->getValue()); + } + + } + + Settings & operator=(Settings &other) + { + if(&other == this) + return *this; + + clear(); + (*this) += other; + + return *this; + } + private: core::map<std::string, std::string> m_settings; core::map<std::string, std::string> m_defaults; @@ -1331,9 +1385,194 @@ void mysrand(unsigned seed); #define MYRAND_MAX 32767 /* - TODO: Some kind of a thing that stores arbitary data related to - 2D coordinate points + 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 + { + v3s16 p; + Attribute attr; + }; + +public: + ~PointAttributeList() + { + /*for(core::list<PointWithAttr>::Iterator + i = m_points.begin(); + i != m_points.end(); i++) + { + PointWithAttr &pwa = *i; + //delete pwa.attr; + }*/ + } + + Attribute getNearAttr(v3s16 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(v2s16 p) + { + return getNearAttr(v3s16(p.X, 0, p.Y)); + } + + 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(v3s16 p); + + float getInterpolatedFloat(v2s16 p) + { + return getInterpolatedFloat(v3s16(p.X, 0, p.Y)); + } + + //float getInterpolatedFloat(v3s16 p, s32 range); + /*float getInterpolatedFloat(v2s16 p, s32 range) + { + return getInterpolatedFloat(v3s16(p.X, 0, p.Y), range); + }*/ + + void addPoint(v3s16 p, const Attribute &attr) + { + PointWithAttr pattr; + pattr.p = p; + pattr.attr = attr; + m_points.push_back(pattr); + } + + void addPoint(v2s16 p, const Attribute &attr) + { + addPoint(v3s16(p.X, 0, p.Y), 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; +}; + #endif |