diff --git a/Makefile b/Makefile index c8912d1ff..979631fc0 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,7 @@ # It's usually sufficient to change just the target name and source file list # and be sure that CXX is set to a valid compiler TARGET = test -SOURCE_FILES = mapblockobject.cpp inventory.cpp debug.cpp serialization.cpp light.cpp filesys.cpp connection.cpp environment.cpp client.cpp server.cpp socket.cpp mapblock.cpp mapsector.cpp heightmap.cpp map.cpp player.cpp utility.cpp main.cpp test.cpp +SOURCE_FILES = voxel.cpp mapblockobject.cpp inventory.cpp debug.cpp serialization.cpp light.cpp filesys.cpp connection.cpp environment.cpp client.cpp server.cpp socket.cpp mapblock.cpp mapsector.cpp heightmap.cpp map.cpp player.cpp utility.cpp main.cpp test.cpp SOURCES = $(addprefix src/, $(SOURCE_FILES)) OBJECTS = $(SOURCES:.cpp=.o) FASTTARGET = fasttest @@ -13,7 +13,7 @@ JTHREADPATH = ../jthread/jthread-1.2.1 CPPFLAGS = -I$(IRRLICHTPATH)/include -I/usr/X11R6/include -I$(JTHREADPATH)/src #CXXFLAGS = -O2 -ffast-math -Wall -fomit-frame-pointer -pipe -CXXFLAGS = -O2 -ffast-math -Wall -g +CXXFLAGS = -O2 -ffast-math -Wall -g -pipe #CXXFLAGS = -O1 -ffast-math -Wall -g #CXXFLAGS = -Wall -g -O0 @@ -21,8 +21,8 @@ CXXFLAGS = -O2 -ffast-math -Wall -g #CXXFLAGS = -O3 -ffast-math -Wall -g #CXXFLAGS = -O2 -ffast-math -Wall -g -#FASTCXXFLAGS = -O3 -ffast-math -Wall -fomit-frame-pointer -pipe -funroll-loops -mtune=pentium3 -FASTCXXFLAGS = -O3 -ffast-math -Wall -fomit-frame-pointer -pipe -funroll-loops -mtune=i686 +#FASTCXXFLAGS = -O3 -ffast-math -Wall -fomit-frame-pointer -pipe -funroll-loops -mtune=i686 +FASTCXXFLAGS = -O3 -ffast-math -Wall -fomit-frame-pointer -pipe -funroll-loops -mtune=i686 -fwhole-program #Default target @@ -53,7 +53,9 @@ all_linux all_win32: $(DESTPATH) fast_linux: $(FASTDESTPATH) $(FASTDESTPATH): $(SOURCES) - $(CXX) -o $(FASTDESTPATH) $(SOURCES) $(CPPFLAGS) $(FASTCXXFLAGS) $(LDFLAGS) -DUNITTEST_DISABLE + @#$(CXX) -o $(FASTDESTPATH) $(SOURCES) $(CPPFLAGS) $(FASTCXXFLAGS) $(LDFLAGS) -DUNITTEST_DISABLE + @# Errno doesn't work ("error: ‘__errno_location’ was not declared in this scope") + cat $(SOURCES) | $(CXX) -o $(FASTDESTPATH) -x c++ - -Isrc/ $(CPPFLAGS) $(FASTCXXFLAGS) $(LDFLAGS) -DUNITTEST_DISABLE -DDISABLE_ERRNO $(DESTPATH): $(OBJECTS) $(CXX) -o $@ $(OBJECTS) $(LDFLAGS) diff --git a/data/mud.png b/data/mud.png new file mode 100644 index 000000000..0c6925d3b Binary files /dev/null and b/data/mud.png differ diff --git a/makepackage_binary.sh b/makepackage_binary.sh index c11c45b18..38a301294 100755 --- a/makepackage_binary.sh +++ b/makepackage_binary.sh @@ -32,6 +32,7 @@ cp -r data/light.png $PACKAGEPATH/data/ cp -r data/sign.png $PACKAGEPATH/data/ cp -r data/sign_back.png $PACKAGEPATH/data/ cp -r data/rat.png $PACKAGEPATH/data/ +cp -r data/mud.png $PACKAGEPATH/data/ cp -r doc/README.txt $PACKAGEPATH/doc/README.txt diff --git a/minetest.conf.example b/minetest.conf.example index 172032f40..6aa16917e 100644 --- a/minetest.conf.example +++ b/minetest.conf.example @@ -44,4 +44,8 @@ creative_mode = false # Player and object positions are sent at intervals specified by this objectdata_inverval = 0.2 +active_object_range = 2 + +max_simultaneous_block_sends_per_client = 2 +max_simultaneous_block_sends_server_total = 4 diff --git a/src/client.cpp b/src/client.cpp index a4f0ffb07..cf9feed7d 100644 --- a/src/client.cpp +++ b/src/client.cpp @@ -31,7 +31,7 @@ void * ClientUpdateThread::Thread() bool was = m_client->AsyncProcessData(); if(was == false) - sleep_ms(50); + sleep_ms(10); } #if CATCH_UNHANDLED_EXCEPTIONS } @@ -159,13 +159,17 @@ void Client::step(float dtime) { /* Delete unused sectors + + NOTE: This jams the game for a while because deleting sectors + clear caches */ static float counter = -0.001; counter -= dtime; if(counter <= 0.0) { - counter = 10.0; + // 3 minute interval + counter = 180.0; JMutexAutoLock lock(m_env_mutex); @@ -381,6 +385,8 @@ float Client::asyncStep() /*float dtime; { JMutexAutoLock lock1(m_step_dtime_mutex); + if(m_step_dtime < 0.001) + return 0.0; dtime = m_step_dtime; m_step_dtime = 0.0; } @@ -1207,6 +1213,18 @@ bool Client::AsyncProcessPacket(LazyMeshUpdater &mesh_updater) bool Client::AsyncProcessData() { + for(;;) + { + // We want to update the meshes as soon as a single packet has + // been processed + LazyMeshUpdater mesh_updater(&m_env); + bool r = AsyncProcessPacket(mesh_updater); + if(r == false) + break; + } + return false; + + /* LazyMeshUpdater mesh_updater(&m_env); for(;;) { @@ -1214,7 +1232,7 @@ bool Client::AsyncProcessData() if(r == false) break; } - return false; + return false;*/ } void Client::Send(u16 channelnum, SharedBuffer data, bool reliable) diff --git a/src/constants.h b/src/constants.h index f7ff0aef1..8cc4ee473 100644 --- a/src/constants.h +++ b/src/constants.h @@ -28,19 +28,20 @@ // The absolute working limit is (2^15 - viewing_range). #define MAP_GENERATION_LIMIT (31000) -#define MAX_SIMULTANEOUS_BLOCK_SENDS 2 +//#define MAX_SIMULTANEOUS_BLOCK_SENDS 2 #define FULL_BLOCK_SEND_ENABLE_MIN_TIME_FROM_BUILDING 2.0 -#define LIMITED_MAX_SIMULTANEOUS_BLOCK_SENDS 1 +//#define LIMITED_MAX_SIMULTANEOUS_BLOCK_SENDS 1 +#define LIMITED_MAX_SIMULTANEOUS_BLOCK_SENDS 0 -#define MAX_SIMULTANEOUS_BLOCK_SENDS_SERVER_TOTAL 4 +// Override for the previous one when distance is low +#define BLOCK_SEND_DISABLE_LIMITS_MAX_D 1 + +//#define MAX_SIMULTANEOUS_BLOCK_SENDS_SERVER_TOTAL 4 // Viewing range stuff -#define FPS_DEFAULT_WANTED 30 -#define FPS_DEFAULT_MAX 60 - -#define HEIGHTMAP_RANGE_NODES 300 +//#define HEIGHTMAP_RANGE_NODES 300 //#define FREETIME_RATIO 0.2 #define FREETIME_RATIO 0.15 @@ -56,7 +57,7 @@ //#define ACTIVE_OBJECT_D_BLOCKS 2 // Wether to catch all std::exceptions -#define CATCH_UNJANDLED_EXCEPTIONS 1 +#define CATCH_UNHANDLED_EXCEPTIONS 0 /* Collecting active blocks is stopped after object data diff --git a/src/exceptions.h b/src/exceptions.h index cbe13f1f3..3e939a086 100644 --- a/src/exceptions.h +++ b/src/exceptions.h @@ -81,6 +81,22 @@ public: {} }; +class SettingNotFoundException : public BaseException +{ +public: + SettingNotFoundException(const char *s): + BaseException(s) + {} +}; + +class InvalidFilenameException : public BaseException +{ +public: + InvalidFilenameException(const char *s): + BaseException(s) + {} +}; + /* Some "old-style" interrupts: */ diff --git a/src/main.cpp b/src/main.cpp index 258119c4a..991185ca6 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -21,11 +21,15 @@ with this program; if not, write to the Free Software Foundation, Inc., =============================== NOTES ============================== NOTE: VBO cannot be turned on for fast-changing stuff because there - is an apparanet memory leak in irrlicht when using it + is an apparanet memory leak in irrlicht when using it (not sure) + +NOTE: iostream.imbue(std::locale("C")) is very slow +NOTE: Global locale is now set at initialization SUGGESTION: add a second lighting value to the MS nibble of param of air to tell how bright the air node is when there is no sunlight. When day changes to night, these two values can be interpolated. + TODO: Fix address to be ipv6 compatible TODO: ESC Pause mode in which the cursor is not kept at the center of window. @@ -93,9 +97,7 @@ TODO: Expose Connection's seqnums and ACKs to server and client. - This also enables server to check if client has received the most recent block sent, for example. -SUGG: Add a time value to the param of footstepped grass and check it - against a global timer when a block is accessed, to make old - steps fade away. +TODO: Add a sane bandwidth throttling system to Connection FIXME: There still are *some* tiny glitches in lighting as seen from the client side. The server calculates them right but sometimes @@ -105,8 +107,9 @@ FIXME: There still are *some* tiny glitches in lighting as seen from the sender sends the block as it was before emerging? TODO: How about adding a "revision" field to MapBlocks? -TODO: More fine-grained control of client's dumping of blocks from +SUGG: More fine-grained control of client's dumping of blocks from memory + - ...What does this mean in the first place? TODO: Somehow prioritize the sending of blocks and combine the block send queue lengths @@ -130,9 +133,6 @@ SUGG: Make client send GOTBLOCKS before updating meshes TODO: Server to load starting inventory from disk -NOTE: iostream.imbue(std::locale("C")) is very slow -NOTE: Global locale is now set at initialization - TODO: PLayers to only be hidden when the client quits. TODO: - Players to be saved on disk, with inventory TODO: Players to be saved as text in map/players/ @@ -158,12 +158,18 @@ Block object server side: - A "near blocks" buffer, in which some nearby blocks are stored. - For all blocks in the buffer, objects are stepped(). This means they are active. - - TODO All blocks going in and out of the buffer are recorded. - - TODO For outgoing blocks, a timestamp is written. - - TODO For incoming blocks, the time difference is calculated and + - TODO: A global active buffer is needed for the server + - TODO: All blocks going in and out of the buffer are recorded. + - TODO: For outgoing blocks, a timestamp is written. + - TODO: For incoming blocks, the time difference is calculated and objects are stepped according to it. TODO: A timestamp to blocks +SUGG: Add a time value to the param of footstepped grass and check it + against a global timer when a block is accessed, to make old + steps fade away. + + TODO: Add config parameters for server's sending and generating distance TODO: Copy the text of the last picked sign to inventory in creative @@ -185,12 +191,16 @@ SUGG: Split MapBlockObject serialization to to-client and to-disk - This will allow saving ages of rats on disk but not sending them to clients -TODO: Fix the long-lived Server Block Emerge Jam bug - - Is it related to the client deleting blocks? +TODO: Get rid of GotSplitPacketException + +Before release: + +TODO: Check what goes wrong with caching map to disk (Kray) Doing now: ====================================================================== +TODO: Implement lighting using VoxelManipulator ====================================================================== @@ -202,7 +212,7 @@ Doing now: the starting place to a static direction. This allows one to move around with the player and see what - is actually drawn behind solid things etc. + is actually drawn behind solid things and behind the player. */ #define FIELD_OF_VIEW_TEST 0 @@ -265,7 +275,8 @@ const char *g_material_filenames[MATERIALS_COUNT] = "../data/tree.png", "../data/leaves.png", "../data/grass_footsteps.png", - "../data/mese.png" + "../data/mese.png", + "../data/mud.png" }; video::SMaterial g_materials[MATERIALS_COUNT]; @@ -296,28 +307,39 @@ bool g_viewing_range_all = false; These are loaded from the config file. */ -std::string g_dedicated_server; +Settings g_settings; -// Client stuff -float g_wanted_fps = FPS_DEFAULT_WANTED; -float g_fps_max = FPS_DEFAULT_MAX; -s16 g_viewing_range_nodes_max = 300; -s16 g_viewing_range_nodes_min = 20; -std::string g_screenW; -std::string g_screenH; -std::string g_host_game; -std::string g_port; -std::string g_address; -std::string g_name; -bool g_random_input = false; -float g_client_delete_unused_sectors_timeout = 1200; +// Sets default settings +void set_default_settings() +{ + g_settings.set("dedicated_server", ""); -// Server stuff -bool g_creative_mode = false; -HMParams g_hm_params; -MapParams g_map_params; -float g_objectdata_interval = 0.2; -u16 g_active_object_range = 2; + // Client stuff + g_settings.set("wanted_fps", "30"); + g_settings.set("fps_max", "60"); + g_settings.set("viewing_range_nodes_max", "300"); + g_settings.set("viewing_range_nodes_min", "20"); + g_settings.set("screenW", ""); + g_settings.set("screenH", ""); + g_settings.set("host_game", ""); + g_settings.set("port", ""); + g_settings.set("address", ""); + g_settings.set("name", ""); + g_settings.set("random_input", "false"); + g_settings.set("client_delete_unused_sectors_timeout", "1200"); + + // Server stuff + g_settings.set("creative_mode", "false"); + g_settings.set("heightmap_blocksize", "128"); + g_settings.set("height_randmax", "constant 70.0"); + g_settings.set("height_randfactor", "constant 0.6"); + g_settings.set("height_base", "linear 0 35 0"); + g_settings.set("plants_amount", "1.0"); + g_settings.set("objectdata_interval", "0.2"); + g_settings.set("active_object_range", "2"); + g_settings.set("max_simultaneous_block_sends_per_client", "2"); + g_settings.set("max_simultaneous_block_sends_server_total", "4"); +} /* Random stuff @@ -354,144 +376,6 @@ std::ostream *derr_server_ptr = &dstream; std::ostream *dout_client_ptr = &dstream; std::ostream *derr_client_ptr = &dstream; -/* - Config stuff -*/ - -// Returns false on EOF -bool parseConfigObject(std::istream &is) -{ - // float g_wanted_fps - // s16 g_viewing_range_nodes_max - - if(is.eof()) - return false; - - std::string line; - std::getline(is, line); - //dstream<<"got line: \""<>g_client_delete_unused_sectors_timeout; - } - - // Server stuff - else if(name == "creative_mode") - g_creative_mode = is_yes(value); - else if(name == "mapgen_heightmap_blocksize") - { - s32 d = atoi(value.c_str()); - if(d > 0 && (d & (d-1)) == 0) - g_hm_params.heightmap_blocksize = d; - else - dstream<<"Invalid value in config file: \"" - <>g_map_params.plants_amount; - } - else if(name == "objectdata_inverval") - { - std::istringstream vis(value); - vis>>g_objectdata_interval; - } - else if(name == "active_object_range") - g_active_object_range = stoi(value, 0, 65535); - - else - { - dstream<<"Unknown option in config file: \"" - < g_viewing_range_nodes_max) - n = g_viewing_range_nodes_max; + if(n < viewing_range_nodes_min) + n = viewing_range_nodes_min; + if(n > viewing_range_nodes_max) + n = viewing_range_nodes_max; bool can_change = true; @@ -1050,10 +939,11 @@ int main(int argc, char *argv[]) disable_stderr = true; #endif + // Initialize debug streams debugstreams_init(disable_stderr, DEBUGFILE); + // Initialize debug stacks debug_stacks_init(); - DSTACK(__FUNCTION_NAME); try @@ -1063,6 +953,10 @@ int main(int argc, char *argv[]) Basic initialization */ + // Initialize default settings + set_default_settings(); + + // Print startup message dstream< yes"< no"< "< "<setResizable(true); - if(g_random_input) + if(g_settings.getBool("random_input")) g_input = new RandomInputHandler(); else g_input = new RealInputHandler(device, &receiver); @@ -1443,9 +1319,7 @@ int main(int argc, char *argv[]) */ SharedPtr server; if(hosting){ - server = new Server("../map", g_creative_mode, g_hm_params, - g_map_params, g_objectdata_interval, - g_active_object_range); + server = new Server("../map", hm_params, map_params); server->start(port); } @@ -1455,7 +1329,7 @@ int main(int argc, char *argv[]) // TODO: Get rid of the g_materials parameter or it's globalness Client client(device, g_materials, - g_client_delete_unused_sectors_timeout, + g_settings.getFloat("client_delete_unused_sectors_timeout"), playername); Address connect_address(0,0,0,0, port); @@ -1648,7 +1522,7 @@ int main(int argc, char *argv[]) */ { - float fps_max = g_fps_max; + float fps_max = g_settings.getFloat("fps_max"); u32 frametime_min = 1000./fps_max; if(busytime_u32 < frametime_min) @@ -2326,7 +2200,7 @@ int main(int argc, char *argv[]) delete g_input; /* - In the end, delete the Irrlicht device. + In the end, delete the Irrlicht device. */ device->drop(); diff --git a/src/main.h b/src/main.h index 59ef0ff03..950e4039f 100644 --- a/src/main.h +++ b/src/main.h @@ -16,6 +16,9 @@ extern s16 g_viewing_range_nodes; //extern s16 g_actual_viewing_range_nodes; extern bool g_viewing_range_all; +// Settings +extern Settings g_settings; + #include // Debug streams diff --git a/src/map.cpp b/src/map.cpp index 35bf8bb40..33f40f064 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -9,6 +9,7 @@ #include "client.h" #include "filesys.h" #include "utility.h" +#include "voxel.h" #ifdef _WIN32 #include @@ -18,6 +19,47 @@ #define sleep_ms(x) usleep(x*1000) #endif +MapBlockPointerCache::MapBlockPointerCache(Map *map) +{ + m_map = map; + m_map->m_blockcachelock.cacheCreated(); + + m_from_cache_count = 0; + m_from_map_count = 0; +} + +MapBlockPointerCache::~MapBlockPointerCache() +{ + m_map->m_blockcachelock.cacheRemoved(); + + dstream<<"MapBlockPointerCache:" + <<" from_cache_count="<isDummy()) continue; - + // Calculate relative position in block - v3s16 relpos = n2pos - blockpos * MAP_BLOCKSIZE; + v3s16 relpos = pos - blockpos_last * MAP_BLOCKSIZE; + // Get node straight from the block - MapNode n2 = block->getNode(relpos); - - /* - If the neighbor is dimmer than what was specified - as oldlight (the light of the previous node) - */ - if(n2.getLight() < oldlight) - { - /* - And the neighbor is transparent and it has some light - */ - if(n2.light_propagates() && n2.getLight() != 0) + MapNode n = block->getNode(relpos); + + u8 oldlight = n.getLight(); + u8 newlight = diminish_light(oldlight); + + // Loop through 6 neighbors + for(u16 i=0; i<6; i++){ + // Get the position of the neighbor node + v3s16 n2pos = pos + dirs[i]; + + // Get the block where the node is located + v3s16 blockpos = getNodeBlockPos(n2pos); + + try { - /* - Set light to 0 and recurse. - */ - u8 current_light = n2.getLight(); - n2.setLight(0); - block->setNode(relpos, n2); - unLightNeighbors(n2pos, current_light, - light_sources, modified_blocks); + // Only fetch a new block if the block position has changed + try{ + if(block == NULL || blockpos != blockpos_last){ + block = getBlockNoCreate(blockpos); + blockpos_last = blockpos; + + block_checked_in_modified = false; + blockchangecount++; + } + } + catch(InvalidPositionException &e) + { + continue; + } - if(block_checked_in_modified == false) + // Calculate relative position in block + v3s16 relpos = n2pos - blockpos * MAP_BLOCKSIZE; + // Get node straight from the block + MapNode n2 = block->getNode(relpos); + + bool changed = false; + /* + If the neighbor is brighter than the current node, + add to list (it will light up this node on its turn) + */ + if(n2.getLight() > undiminish_light(oldlight)) + { + lighted_nodes.insert(n2pos, true); + //lighted_nodes.push_back(n2pos); + changed = true; + } + /* + If the neighbor is dimmer than how much light this node + would spread on it, add to list + */ + if(n2.getLight() < newlight) + { + if(n2.light_propagates()) + { + n2.setLight(newlight); + block->setNode(relpos, n2); + lighted_nodes.insert(n2pos, true); + //lighted_nodes.push_back(n2pos); + changed = true; + } + } + + // Add to modified_blocks + if(changed == true && block_checked_in_modified == false) { // If the block is not found in modified_blocks, add. if(modified_blocks.find(blockpos) == NULL) @@ -263,12 +333,20 @@ void Map::unLightNeighbors(v3s16 pos, u8 oldlight, block_checked_in_modified = true; } } - } - else{ - //light_sources.push_back(n2pos); - light_sources.insert(n2pos, true); + catch(InvalidPositionException &e) + { + continue; + } } } + + /*dstream<<"spreadLight(): Changed block " + < 0) + spreadLight(lighted_nodes, modified_blocks); } #endif @@ -1090,6 +1168,13 @@ void Map::timerUpdate(float dtime) void Map::deleteSectors(core::list &list, bool only_blocks) { + /* + Wait for caches to be removed before continuing. + + This disables the existence of caches while locked + */ + SharedPtr cachelock(m_blockcachelock.waitCaches()); + core::list::Iterator j; for(j=list.begin(); j!=list.end(); j++) { @@ -1215,13 +1300,13 @@ ServerMap::ServerMap(std::string savedir, HMParams hmp, MapParams mp): // Create master heightmap ValueGenerator *maxgen = - ValueGenerator::deSerialize(hmp.height_randmax); + ValueGenerator::deSerialize(hmp.randmax); ValueGenerator *factorgen = - ValueGenerator::deSerialize(hmp.height_randfactor); + ValueGenerator::deSerialize(hmp.randfactor); ValueGenerator *basegen = - ValueGenerator::deSerialize(hmp.height_base); + ValueGenerator::deSerialize(hmp.base); m_heightmap = new UnlimitedHeightmap - (hmp.heightmap_blocksize, maxgen, factorgen, basegen); + (hmp.blocksize, maxgen, factorgen, basegen); // Set map parameters m_params = mp; @@ -1409,6 +1494,9 @@ MapSector * ServerMap::emergeSector(v2s16 p2d) SECTOR_OBJECT_TREE_1); } } + /* + Plant some bushes if sector is pit-like + */ { // Pitness usually goes at around -0.5...0.5 u32 bush_max = 0; @@ -1429,6 +1517,22 @@ MapSector * ServerMap::emergeSector(v2s16 p2d) SECTOR_OBJECT_BUSH_1); } } + /* + Add ravine (randomly) + */ + { + if(rand()%10 == 0) + { + s16 s = 6; + s16 x = rand()%(MAP_BLOCKSIZE-s*2-1)+s; + s16 z = rand()%(MAP_BLOCKSIZE-s*2-1)+s; + /*s16 x = 8; + s16 z = 8;*/ + s16 y = sector->getGroundHeight(v2s16(x,z))+1; + objects->insert(v3s16(x, y, z), + SECTOR_OBJECT_RAVINE); + } + } /* Insert to container @@ -1533,9 +1637,16 @@ MapBlock * ServerMap::emergeBlock( } // Randomize a bit. This makes dungeons. - bool low_block_is_empty = false; + /*bool low_block_is_empty = false; if(rand() % 4 == 0) - low_block_is_empty = true; + low_block_is_empty = true;*/ + + s32 ued = 4; + bool underground_emptiness[ued*ued*ued]; + for(s32 i=0; isetYaw(45); - block->addObject(obj); - } - - { - v3s16 pos(8, 11, 8); - RatObject *obj = new RatObject(NULL, -1, intToFloat(pos)); - block->addObject(obj); - } - */ - /* Add block to sector. */ sector->insertBlock(block); - // An y-wise container if changed blocks + /* + Do some interpolation for dungeons + */ + +#if 0 + { + TimeTaker timer("interpolation", g_device); + + MapVoxelManipulator vmanip(this); + + v3s16 relpos = block->getPosRelative(); + + vmanip.interpolate(VoxelArea(relpos-v3s16(1,1,1), + relpos+v3s16(1,1,1)*(MAP_BLOCKSIZE+1))); + /*vmanip.interpolate(VoxelArea(relpos, + relpos+v3s16(1,1,1)*(MAP_BLOCKSIZE-1)));*/ + + core::map modified_blocks; + vmanip.blitBack(modified_blocks); + dstream<<"blitBack modified "<::Iterator + i = modified_blocks.getIterator(); + i.atEnd() == false; i++) + { + MapBlock *block = i.getNode()->getValue(); + + changed_blocks.insert(block->getPos(), block); + //lighting_invalidated_blocks.insert(block->getPos(), block); + } + + } +#endif + + /* + Sector object stuff + */ + + // An y-wise container of changed blocks core::map changed_blocks_sector; /* @@ -1722,6 +1866,7 @@ MapBlock * ServerMap::emergeBlock( i.atEnd() == false; i++) { v3s16 p = i.getNode()->getKey(); + v2s16 p2d(p.X,p.Z); u8 d = i.getNode()->getValue(); //v3s16 p = p_sector - v3s16(0, block_y*MAP_BLOCKSIZE, 0); @@ -1795,6 +1940,66 @@ MapBlock * ServerMap::emergeBlock( 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 = MATERIAL_STONE; + MapNode n2; + n2.d = MATERIAL_AIR; + s16 depth = maxdepth + (rand()%10); + s16 z = 0; + s16 minz = -6 - (-2); + s16 maxz = 6 -1; + for(s16 x=-6; x<=6; x++) + { + z += -1 + (rand()%3); + if(z < minz) + z = minz; + if(z > maxz) + z = maxz; + for(s16 y=depth+(rand()%2); y<=6; y++) + { + /*std::cout<<"("<getNode(p2).d)) + sector->setNode(p2, n); + } + { + v3s16 p2 = p + v3s16(x,y,z-1); + if(is_ground_material(sector->getNode(p2).d)) + sector->setNode(p2, n2); + } + { + v3s16 p2 = p + v3s16(x,y,z+0); + if(is_ground_material(sector->getNode(p2).d)) + sector->setNode(p2, n2); + } + { + v3s16 p2 = p + v3s16(x,y,z+1); + if(is_ground_material(sector->getNode(p2).d)) + 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::emergeBlock(): " @@ -1807,7 +2012,7 @@ MapBlock * ServerMap::emergeBlock( { dstream<<"WARNING: "<<__FUNCTION_NAME <<": while inserting object "<<(int)d - <<" to ("<getNodeNoCheck(relpos); + } + + // virtual from NodeContainer + void setNode(v3s16 p, MapNode & n) + { + v3s16 blockpos = getNodeBlockPos(p); + MapBlock * block = getBlockNoCreate(blockpos); + v3s16 relpos = p - blockpos*MAP_BLOCKSIZE; + block->setNodeNoCheck(relpos, n); + m_modified_blocks[blockpos] = block; + } + + core::map m_modified_blocks; + +private: + Map *m_map; + core::map m_blocks; + + u32 m_from_cache_count; + u32 m_from_map_count; +}; + +class CacheLock +{ +public: + CacheLock() + { + m_count = 0; + m_count_mutex.Init(); + m_cache_mutex.Init(); + m_waitcache_mutex.Init(); + } + + void cacheCreated() + { + JMutexAutoLock waitcachelock(m_waitcache_mutex); + JMutexAutoLock countlock(m_count_mutex); + + // If this is the first cache, grab the cache lock + if(m_count == 0) + m_cache_mutex.Lock(); + + m_count++; + } + + void cacheRemoved() + { + JMutexAutoLock countlock(m_count_mutex); + + assert(m_count > 0); + + m_count--; + + // If this is the last one, release the cache lock + if(m_count == 0) + m_cache_mutex.Unlock(); + } + + /* + This lock should be taken when removing stuff that can be + pointed by the cache. + + You'll want to grab this in a SharedPtr. + */ + JMutexAutoLock * waitCaches() + { + JMutexAutoLock waitcachelock(m_waitcache_mutex); + return new JMutexAutoLock(m_cache_mutex); + } + +private: + // Count of existing caches + u32 m_count; + JMutex m_count_mutex; + // This is locked always when there are some caches + JMutex m_cache_mutex; + // Locked so that when waitCaches() is called, no more caches are created + JMutex m_waitcache_mutex; }; #define MAPTYPE_BASE 0 @@ -60,6 +177,13 @@ protected: public: v3s16 drawoffset; // for drawbox() + + /* + Used by MapBlockPointerCache. + + waitCaches() can be called to remove all caches before continuing + */ + CacheLock m_blockcachelock; Map(std::ostream &dout); virtual ~Map(); @@ -154,7 +278,7 @@ public: MapBlock * blockref = getBlockNoCreate(blockpos); v3s16 relpos = p - blockpos*MAP_BLOCKSIZE; - return blockref->getNode(relpos); + return blockref->getNodeNoCheck(relpos); } // virtual from NodeContainer @@ -163,7 +287,7 @@ public: v3s16 blockpos = getNodeBlockPos(p); MapBlock * blockref = getBlockNoCreate(blockpos); v3s16 relpos = p - blockpos*MAP_BLOCKSIZE; - blockref->setNode(relpos, n); + blockref->setNodeNoCheck(relpos, n); } /*MapNode getNodeGenerate(v3s16 p) @@ -247,15 +371,15 @@ struct HMParams { HMParams() { - heightmap_blocksize = 64; - height_randmax = "constant 70.0"; - height_randfactor = "constant 0.6"; - height_base = "linear 0 80 0"; + blocksize = 64; + randmax = "constant 70.0"; + randfactor = "constant 0.6"; + base = "linear 0 80 0"; } - s16 heightmap_blocksize; - std::string height_randmax; - std::string height_randfactor; - std::string height_base; + s16 blocksize; + std::string randmax; + std::string randfactor; + std::string base; }; // Map parameters diff --git a/src/mapblock.h b/src/mapblock.h index 60f78b6ff..48f877551 100644 --- a/src/mapblock.h +++ b/src/mapblock.h @@ -38,7 +38,9 @@ enum { NODECONTAINER_ID_MAPBLOCK, NODECONTAINER_ID_MAPSECTOR, - NODECONTAINER_ID_MAP + NODECONTAINER_ID_MAP, + NODECONTAINER_ID_MAPBLOCKCACHE, + NODECONTAINER_ID_VOXELMANIPULATOR, }; class NodeContainer @@ -245,6 +247,35 @@ public: setNode(p.X, p.Y, p.Z, n); } + /* + Non-checking variants of the above + */ + + MapNode getNodeNoCheck(s16 x, s16 y, s16 z) + { + if(data == NULL) + throw InvalidPositionException(); + return data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x]; + } + + MapNode getNodeNoCheck(v3s16 p) + { + return getNodeNoCheck(p.X, p.Y, p.Z); + } + + void setNodeNoCheck(s16 x, s16 y, s16 z, MapNode & n) + { + if(data == NULL) + throw InvalidPositionException(); + data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x] = n; + setChangedFlag(); + } + + void setNodeNoCheck(v3s16 p, MapNode & n) + { + setNodeNoCheck(p.X, p.Y, p.Z, n); + } + /* These functions consult the parent container if the position is not valid on this MapBlock. diff --git a/src/mapnode.h b/src/mapnode.h index 68e669161..981f36d86 100644 --- a/src/mapnode.h +++ b/src/mapnode.h @@ -17,10 +17,25 @@ #define MATERIALS_COUNT 256 -// This is completely ignored. It doesn't create faces with anything. +/* + Ignored node. + + param is used for custom information in special containers, + like VoxelManipulator. + + Anything that stores MapNodes doesn't have to preserve parameters + associated with this material. + + Doesn't create faces with anything and is considered being + out-of-map in the game map. +*/ #define MATERIAL_IGNORE 255 -// This is the common material through which the player can walk -// and which is transparent to light +#define MATERIAL_IGNORE_DEFAULT_PARAM 0 + +/* + The common material through which the player can walk and which + is transparent to light +*/ #define MATERIAL_AIR 254 /* @@ -63,6 +78,8 @@ enum Material MATERIAL_GRASS_FOOTSTEPS, MATERIAL_MESE, + + MATERIAL_MUD, // This is set to the number of the actual values in this enum USEFUL_MATERIAL_COUNT @@ -126,6 +143,21 @@ inline u8 face_materials(u8 m1, u8 m2) return 2; } +/* + Returns true for materials that form the base ground that + follows the main heightmap +*/ +inline bool is_ground_material(u8 m) +{ + return( + m == MATERIAL_STONE || + m == MATERIAL_GRASS || + m == MATERIAL_GRASS_FOOTSTEPS || + m == MATERIAL_MESE || + m == MATERIAL_MUD + ); +} + struct MapNode { //TODO: block type to differ from material @@ -133,9 +165,6 @@ struct MapNode // block type u8 d; - // Removed because light is now stored in param for air - // f32 light; - /* Misc parameter. Initialized to 0. - For light_propagates() blocks, this is light intensity, @@ -155,6 +184,11 @@ struct MapNode param = a_param; } + bool operator==(const MapNode &other) + { + return (d == other.d && param == other.param); + } + bool light_propagates() { return light_propagates_material(d); diff --git a/src/mapsector.h b/src/mapsector.h index 196a129c3..de8cab536 100644 --- a/src/mapsector.h +++ b/src/mapsector.h @@ -20,6 +20,7 @@ #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 diff --git a/src/server.cpp b/src/server.cpp index 83d43599f..e17e21d32 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -178,7 +178,10 @@ void * EmergeThread::Thread() modified_blocks.insert(block->getPos(), block); } - //TimeTaker timer("** updateLighting", g_device); + /*dstream<<"lighting "<SetBlocksNotSent(modified_blocks); } - if(q->peer_ids.find(client->peer_id) != NULL) + /*if(q->peer_ids.find(client->peer_id) != NULL) { // Decrement emerge queue count of client client->BlockEmerged(); - } + }*/ } } @@ -246,282 +249,6 @@ void * EmergeThread::Thread() return NULL; } -#if 0 -void RemoteClient::SendBlocks(Server *server, float dtime) -{ - DSTACK(__FUNCTION_NAME); - - /* - Find what blocks to send to the client next, and send them. - - Throttling is based on limiting the amount of blocks "flying" - at a given time. - */ - - // Can't send anything without knowing version - if(serialization_version == SER_FMT_VER_INVALID) - { - dstream<<"RemoteClient::SendBlocks(): Not sending, no version." - <= MAX_SIMULTANEOUS_BLOCK_SENDS) - { - //dstream<<"Not sending any blocks, Queue full."<m_env.getPlayer(peer_id); - - v3f playerpos = player->getPosition(); - v3f playerspeed = player->getSpeed(); - - v3s16 center_nodepos = floatToInt(playerpos); - - v3s16 center = getNodeBlockPos(center_nodepos); - - /* - Get the starting value of the block finder radius. - */ - s16 last_nearest_unsent_d; - s16 d_start; - { - JMutexAutoLock lock(m_blocks_sent_mutex); - - if(m_last_center != center) - { - m_nearest_unsent_d = 0; - m_last_center = center; - } - - static float reset_counter = 0; - reset_counter += dtime; - if(reset_counter > 5.0) - { - reset_counter = 0; - m_nearest_unsent_d = 0; - } - - last_nearest_unsent_d = m_nearest_unsent_d; - - d_start = m_nearest_unsent_d; - } - - u16 maximum_simultaneous_block_sends = MAX_SIMULTANEOUS_BLOCK_SENDS; - - { - SharedPtr lock(m_time_from_building.getLock()); - m_time_from_building.m_value += dtime; - /* - Check the time from last addNode/removeNode. - Decrease send rate if player is building stuff. - */ - if(m_time_from_building.m_value - < FULL_BLOCK_SEND_ENABLE_MIN_TIME_FROM_BUILDING) - { - maximum_simultaneous_block_sends - = LIMITED_MAX_SIMULTANEOUS_BLOCK_SENDS; - } - } - - // Serialization version used - //u8 ser_version = serialization_version; - - //bool has_incomplete_blocks = false; - - /* - TODO: Get this from somewhere - */ - //s16 d_max = 7; - s16 d_max = 8; - - //TODO: Get this from somewhere (probably a bigger value) - s16 d_max_gen = 5; - - //dstream<<"Starting from "< list; - getFacePositions(list, d); - - core::list::Iterator li; - for(li=list.begin(); li!=list.end(); li++) - { - v3s16 p = *li + center; - - /* - Send throttling - - Don't allow too many simultaneous transfers - - Also, don't send blocks that are already flying. - */ - { - JMutexAutoLock lock(m_blocks_sending_mutex); - - if(m_blocks_sending.size() - >= maximum_simultaneous_block_sends) - { - /*dstream<<"Not sending more blocks. Queue full. " - < MAP_GENERATION_LIMIT / MAP_BLOCKSIZE - || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE - || p.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE - || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE - || p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE) - continue; - - bool generate = d <= d_max_gen; - - // Limit the generating area vertically to half - if(abs(p.Y - center.Y) > d_max_gen / 2) - generate = false; - - /* - Don't send already sent blocks - */ - { - JMutexAutoLock lock(m_blocks_sent_mutex); - - if(m_blocks_sent.find(p) != NULL) - continue; - } - - /* - Check if map has this block - */ - MapBlock *block = NULL; - try - { - block = server->m_env.getMap().getBlockNoCreate(p); - } - catch(InvalidPositionException &e) - { - } - - bool surely_not_found_on_disk = false; - if(block != NULL) - { - /*if(block->isIncomplete()) - { - has_incomplete_blocks = true; - continue; - }*/ - - if(block->isDummy()) - { - surely_not_found_on_disk = true; - } - } - - /* - If block has been marked to not exist on disk (dummy) - and generating new ones is not wanted, skip block. TODO - */ - if(generate == false && surely_not_found_on_disk == true) - { - // get next one. - continue; - } - - /* - Add inexistent block to emerge queue. - */ - if(block == NULL || surely_not_found_on_disk) - { - // Block not found. - SharedPtr lock - (m_num_blocks_in_emerge_queue.getLock()); - - //TODO: Get value from somewhere - //TODO: Balance between clients - //if(server->m_emerge_queue.size() < 1) - - // Allow only one block in emerge queue - if(m_num_blocks_in_emerge_queue.m_value == 0) - { - // Add it to the emerge queue and trigger the thread - - u8 flags = 0; - if(generate == false) - flags |= TOSERVER_GETBLOCK_FLAG_OPTIONAL; - - { - m_num_blocks_in_emerge_queue.m_value++; - } - - server->m_emerge_queue.addBlock(peer_id, p, flags); - server->m_emergethread.trigger(); - } - - // get next one. - continue; - } - - /* - Send block - */ - - /*dstream<<"RemoteClient::SendBlocks(): d="<SendBlockNoLock(peer_id, block, serialization_version); - - /* - Add to history - */ - SentBlock(p); - } - } - - // Don't add anything here. The loop breaks by returning. -} -#endif // backup of SendBlocks - void RemoteClient::GetNextBlocks(Server *server, float dtime, core::array &dest) { @@ -531,7 +258,8 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime, { JMutexAutoLock lock(m_blocks_sending_mutex); - if(m_blocks_sending.size() >= MAX_SIMULTANEOUS_BLOCK_SENDS) + if(m_blocks_sending.size() >= g_settings.getU16 + ("max_simultaneous_block_sends_per_client")) { //dstream<<"Not sending any blocks, Queue full."< lock(m_time_from_building.getLock()); m_time_from_building.m_value += dtime; - /* - Check the time from last addNode/removeNode. - Decrease send rate if player is building stuff. - */ if(m_time_from_building.m_value < FULL_BLOCK_SEND_ENABLE_MIN_TIME_FROM_BUILDING) { @@ -646,9 +376,11 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime, /* Send throttling - Don't allow too many simultaneous transfers + - EXCEPT when the blocks are very close Also, don't send blocks that are already flying. */ + if(d >= BLOCK_SEND_DISABLE_LIMITS_MAX_D) { JMutexAutoLock lock(m_blocks_sending_mutex); @@ -722,7 +454,7 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime, /* If block has been marked to not exist on disk (dummy) - and generating new ones is not wanted, skip block. TODO + and generating new ones is not wanted, skip block. */ if(generate == false && surely_not_found_on_disk == true) { @@ -735,16 +467,12 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime, */ if(block == NULL || surely_not_found_on_disk) { - // Block not found. - SharedPtr lock - (m_num_blocks_in_emerge_queue.getLock()); + /*SharedPtr lock + (m_num_blocks_in_emerge_queue.getLock());*/ //TODO: Get value from somewhere - //TODO: Balance between clients - //if(server->m_emerge_queue.size() < 1) - // Allow only one block in emerge queue - if(m_num_blocks_in_emerge_queue.m_value == 0) + if(server->m_emerge_queue.peerItemCount(peer_id) < 1) { // Add it to the emerge queue and trigger the thread @@ -752,10 +480,6 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime, if(generate == false) flags |= TOSERVER_GETBLOCK_FLAG_OPTIONAL; - { - m_num_blocks_in_emerge_queue.m_value++; - } - server->m_emerge_queue.addBlock(peer_id, p, flags); server->m_emergethread.trigger(); } @@ -880,7 +604,7 @@ void RemoteClient::SendObjectData( v3s16 center = getNodeBlockPos(center_nodepos); //s16 d_max = ACTIVE_OBJECT_D_BLOCKS; - s16 d_max = server->m_active_object_range; + s16 d_max = g_settings.getS16("active_object_range"); // Number of blocks whose objects were written to bos u16 blockcount = 0; @@ -956,9 +680,9 @@ void RemoteClient::SendObjectData( // Fetch the block only if it is on disk. // Grab and increment counter - SharedPtr lock + /*SharedPtr lock (m_num_blocks_in_emerge_queue.getLock()); - m_num_blocks_in_emerge_queue.m_value++; + m_num_blocks_in_emerge_queue.m_value++;*/ // Add to queue as an anonymous fetch from disk u8 flags = TOSERVER_GETBLOCK_FLAG_OPTIONAL; @@ -1072,12 +796,12 @@ void RemoteClient::SetBlocksNotSent(core::map &blocks) } } -void RemoteClient::BlockEmerged() +/*void RemoteClient::BlockEmerged() { SharedPtr lock(m_num_blocks_in_emerge_queue.getLock()); assert(m_num_blocks_in_emerge_queue.m_value > 0); m_num_blocks_in_emerge_queue.m_value--; -} +}*/ /*void RemoteClient::RunSendingTimeouts(float dtime, float timeout) { @@ -1145,19 +869,13 @@ u32 PIChecksum(core::list &l) Server::Server( std::string mapsavedir, - bool creative_mode, HMParams hm_params, - MapParams map_params, - float objectdata_interval, - u16 active_object_range + MapParams map_params ): m_env(new ServerMap(mapsavedir, hm_params, map_params), dout_server), m_con(PROTOCOL_ID, 512, CONNECTION_TIMEOUT, this), m_thread(this), - m_emergethread(this), - m_creative_mode(creative_mode), - m_objectdata_interval(objectdata_interval), - m_active_object_range(active_object_range) + m_emergethread(this) { m_env_mutex.Init(); m_con_mutex.Init(); @@ -1196,7 +914,7 @@ void Server::start(unsigned short port) m_thread.stop(); // Initialize connection - m_con.setTimeoutMs(50); + m_con.setTimeoutMs(30); m_con.Serve(port); // Start thread @@ -1287,7 +1005,7 @@ void Server::AsyncRunStep() // Run time- and client- related stuff // NOTE: If you intend to add something here, check that it - // doesn't fit in RemoteClient::SendBlocks for example. + // doesn't fit in RemoteClient::GetNextBlocks for example. /*{ // Clients are behind connection lock JMutexAutoLock lock(m_con_mutex); @@ -1309,7 +1027,7 @@ void Server::AsyncRunStep() { static float counter = 0.0; counter += dtime; - if(counter >= m_objectdata_interval) + if(counter >= g_settings.getFloat("objectdata_interval")) { JMutexAutoLock lock1(m_env_mutex); JMutexAutoLock lock2(m_con_mutex); @@ -1318,9 +1036,22 @@ void Server::AsyncRunStep() counter = 0.0; } } - + + // Trigger emergethread (it gets somehow gets to a + // non-triggered but bysy state sometimes) + { + static float counter = 0.0; + counter += dtime; + if(counter >= 2.0) + { + counter = 0.0; + + m_emergethread.trigger(); + } + } + + // Save map { - // Save map static float counter = 0.0; counter += dtime; if(counter >= SERVER_MAP_SAVE_INTERVAL) @@ -1619,7 +1350,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) // Left click if(button == 0) { - if(m_creative_mode == false) + if(g_settings.getBool("creative_mode") == false) { // Skip if inventory has no free space @@ -1684,8 +1415,6 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) { return; } - // Otherwise remove it - m_env.getMap().removeNodeAndUpdate(p_under, modified_blocks); } catch(InvalidPositionException &e) { @@ -1707,7 +1436,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) // Send as reliable m_con.SendToAll(0, reply, true); - if(m_creative_mode == false) + if(g_settings.getBool("creative_mode") == false) { // Add to inventory and send inventory InventoryItem *item = new MaterialItem(material, 1); @@ -1715,6 +1444,12 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) SendInventory(player->peer_id); } + /* + Remove the node + (this takes some time so it is done after the quick stuff) + */ + m_env.getMap().removeNodeAndUpdate(p_under, modified_blocks); + } // button == 0 /* Right button places blocks and stuff @@ -1744,9 +1479,6 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) MapNode n2 = m_env.getMap().getNode(p_over); if(n2.d != MATERIAL_AIR) return; - - core::map modified_blocks; - m_env.getMap().addNodeAndUpdate(p_over, n, modified_blocks); } catch(InvalidPositionException &e) { @@ -1758,7 +1490,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) // Reset build time counter getClient(peer->id)->m_time_from_building.set(0.0); - if(m_creative_mode == false) + if(g_settings.getBool("creative_mode") == false) { // Remove from inventory and send inventory if(mitem->getCount() == 1) @@ -1779,6 +1511,14 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) n.serialize(&reply[8], peer_ser_ver); // Send as reliable m_con.SendToAll(0, reply, true); + + /* + Add node. + + This takes some time so it is done after the quick stuff + */ + core::map modified_blocks; + m_env.getMap().addNodeAndUpdate(p_over, n, modified_blocks); } /* Handle block object items @@ -1828,7 +1568,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) //dout_server<<"Placed object"<inventory.deleteItem(item_i); @@ -2168,7 +1908,7 @@ void Server::peerAdded(con::Peer *peer) Add stuff to inventory */ - if(m_creative_mode) + if(g_settings.getBool("creative_mode")) { // Give all materials assert(USEFUL_MATERIAL_COUNT <= PLAYER_INVENTORY_SIZE); @@ -2327,35 +2067,6 @@ void Server::SendInventory(u16 peer_id) m_con.Send(peer_id, 0, data, true); } -#if 0 -void Server::SendBlocks(float dtime) -{ - DSTACK(__FUNCTION_NAME); - //dstream<<"Server::SendBlocks(): BEGIN"<::Iterator - i = m_clients.getIterator(); - i.atEnd() == false; i++) - { - RemoteClient *client = i.getNode()->getValue(); - assert(client->peer_id == i.getNode()->getKey()); - - if(client->serialization_version == SER_FMT_VER_INVALID) - continue; - - //dstream<<"Server::SendBlocks(): sending blocks for client "<peer_id<peer_id; - client->SendBlocks(this, dtime); - } - - //dstream<<"Server::SendBlocks(): END"<= MAX_SIMULTANEOUS_BLOCK_SENDS_SERVER_TOTAL) + //TODO: Calculate limit dynamically + if(total_sending >= g_settings.getS32 + ("max_simultaneous_block_sends_server_total")) break; PrioritySortedBlockTransfer q = queue[i]; diff --git a/src/server.h b/src/server.h index 8e2e05626..79cdf052d 100644 --- a/src/server.h +++ b/src/server.h @@ -102,6 +102,23 @@ public: JMutexAutoLock lock(m_mutex); return m_queue.size(); } + + u32 peerItemCount(u16 peer_id) + { + JMutexAutoLock lock(m_mutex); + + u32 count = 0; + + core::list::Iterator i; + for(i=m_queue.begin(); i!=m_queue.end(); i++) + { + QueuedBlockEmerge *q = *i; + if(q->peer_ids.find(peer_id) != NULL) + count++; + } + + return count; + } private: core::list m_queue; @@ -237,8 +254,8 @@ public: u8 pending_serialization_version; RemoteClient(): - m_time_from_building(0.0), - m_num_blocks_in_emerge_queue(0) + m_time_from_building(0.0) + //m_num_blocks_in_emerge_queue(0) { peer_id = 0; serialization_version = SER_FMT_VER_INVALID; @@ -276,7 +293,7 @@ public: void SetBlockNotSent(v3s16 p); void SetBlocksNotSent(core::map &blocks); - void BlockEmerged(); + //void BlockEmerged(); /*bool IsSendingBlock(v3s16 p) { @@ -300,8 +317,8 @@ public: JMutexAutoLock l2(m_blocks_sent_mutex); JMutexAutoLock l3(m_blocks_sending_mutex); o<<"RemoteClient "< #ifdef _WIN32 @@ -125,6 +125,45 @@ struct TestMapNode } }; +struct TestVoxelManipulator +{ + void Run() + { + VoxelArea a(v3s16(-1,-1,-1), v3s16(1,1,1)); + assert(a.index(0,0,0) == 1*3*3 + 1*3 + 1); + assert(a.index(-1,-1,-1) == 0); + + VoxelManipulator v; + + v.print(dstream); + + dstream<<"*** Setting (-1,0,-1)=2 ***"< +#include #include +#include extern const v3s16 g_26dirs[26]; @@ -613,5 +616,157 @@ inline s32 stoi(std::string s, s32 min, s32 max) return i; } +inline s32 stoi(std::string s) +{ + return atoi(s.c_str()); +} + +/* + Config stuff +*/ + +class Settings +{ +public: + + // Returns false on EOF + bool parseConfigObject(std::istream &is) + { + if(is.eof()) + return false; + + // NOTE: This function will be expanded to allow multi-line settings + std::string line; + std::getline(is, line); + //dstream<<"got line: \""<::Node *n; + n = m_settings.find(name); + if(n == NULL) + throw SettingNotFoundException("Setting not found"); + + return n->getValue(); + } + + bool getBool(std::string name) + { + return is_yes(get(name)); + } + + // Asks if empty + bool getBoolAsk(std::string name, std::string question, bool def) + { + std::string s = get(name); + if(s != "") + return is_yes(s); + + char templine[10]; + std::cout<>f; + return f; + } + + u16 getU16(std::string name) + { + return stoi(get(name), 0, 65535); + } + + u16 getU16Ask(std::string name, std::string question, u16 def) + { + std::string s = get(name); + if(s != "") + return stoi(s, 0, 65535); + + char templine[10]; + std::cout< m_settings; +}; + #endif