From 7068bc90af1f452359a1fcfe20fa01fc88f3d70a Mon Sep 17 00:00:00 2001 From: Perttu Ahola Date: Sun, 16 Jan 2011 19:32:14 +0200 Subject: [PATCH] Initial commit of mapgen v.2. Lacks configuration and saving to disk. --- src/constants.h | 2 + src/defaultsettings.cpp | 8 +- src/environment.cpp | 2 +- src/heightmap.cpp | 319 +++++++++++++++++++++++++--------- src/heightmap.h | 30 ++-- src/map.cpp | 375 ++++++++++++++++++++++++++++++++++------ src/map.h | 14 ++ src/player.cpp | 43 ++++- src/serialization.h | 3 +- src/server.cpp | 93 +++++++--- src/test.cpp | 26 ++- src/utility.cpp | 226 ++++++++++++++++++++++++ src/utility.h | 243 +++++++++++++++++++++++++- 13 files changed, 1197 insertions(+), 187 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 */ @@ -258,59 +261,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; sgetGroundHeight(npos, false); - //dstream<<"h="<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="<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="< 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::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 hmdata(heightmap_size); + + core::map::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 hmdata(heightmap_size); + + core::map::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 @@ -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="< 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; igetValue(); } - 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 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<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=("<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 *objects = new core::map; - 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="<getNearAttr(nodepos2d).getFloat();*/ + float local_plants_amount = + palist->getInterpolatedFloat(nodepos2d); + + /* + Generate sector heightmap + */ + + // Loop through sub-heightmaps + for(s16 y=0; ygetGroundHeight(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=("<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 *objects = new core::map; + 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 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; @@ -1838,6 +2061,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; xgetPosRelative(); + 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; xgetPosRelative(); + 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) diff --git a/src/map.h b/src/map.h index ff3daf047..3385d7c68 100644 --- a/src/map.h +++ b/src/map.h @@ -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 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; - - block = map.emergeBlock( - p, - only_from_disk, - changed_blocks, - lighting_invalidated_blocks); + // First check if the block already exists + if(only_from_disk) + { + block = map.getBlockNoCreate(p); + } + + 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 \"" + <getName()<<"\""<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 near; + + for(core::list::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::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::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::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::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="<d="<d<<" nearest_d_sum="<