From 63611932ebae93620386b26cfa82f7c4552b22ff Mon Sep 17 00:00:00 2001 From: Perttu Ahola Date: Sun, 29 May 2011 21:11:16 +0300 Subject: player passwords and privileges in world/auth.txt --HG-- extra : rebase_source : 7260636295d9068fbeeddf4143c89f2b8a91446c --- src/utility.h | 55 +++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 35 insertions(+), 20 deletions(-) (limited to 'src/utility.h') diff --git a/src/utility.h b/src/utility.h index c7513e94d..f18d31278 100644 --- a/src/utility.h +++ b/src/utility.h @@ -1984,17 +1984,23 @@ inline std::string serializeString(const std::string &plain) return s; } -/*// Reads a string with the length as the first two bytes -inline std::string deSerializeString(const std::string encoded) +// Creates a string with the length as the first two bytes from wide string +inline std::string serializeWideString(const std::wstring &plain) { - u16 s_size = readU16((u8*)&encoded.c_str()[0]); - if(s_size > encoded.length() - 2) - return ""; + //assert(plain.size() <= 65535); + if(plain.size() > 65535) + throw SerializationError("String too long for serializeString"); + char buf[2]; + writeU16((u8*)buf, plain.size()); std::string s; - s.reserve(s_size); - s.append(&encoded.c_str()[2], s_size); + s.append(buf, 2); + for(u32 i=0; i encoded.length() - 4) - return ""; - std::string s; - s.reserve(s_size); - s.append(&encoded.c_str()[4], s_size); - return s; -}*/ - // Reads a string with the length as the first four bytes inline std::string deSerializeLongString(std::istream &is) { -- cgit v1.2.3 From 223b3793485a76f87599d39364b1003c2ca7c49c Mon Sep 17 00:00:00 2001 From: Perttu Ahola Date: Tue, 31 May 2011 00:15:43 +0300 Subject: Reduced the CPU usage of the sent block selector algorithm --- minetest.conf.example | 11 +-- src/defaultsettings.cpp | 3 +- src/game.cpp | 19 +++++ src/main.cpp | 33 ++++++++- src/main.h | 4 ++ src/map.cpp | 6 +- src/mapblock.cpp | 4 +- src/profiler.h | 131 ++++++++++++++++++++++++++++++++++ src/server.cpp | 185 +++++++++++++++++++++++++++++++++++++----------- src/server.h | 11 +++ src/utility.h | 3 + 11 files changed, 355 insertions(+), 55 deletions(-) create mode 100644 src/profiler.h (limited to 'src/utility.h') diff --git a/minetest.conf.example b/minetest.conf.example index 1a1dbe0fc..743186853 100644 --- a/minetest.conf.example +++ b/minetest.conf.example @@ -92,10 +92,6 @@ # Server side stuff # -# Set to true to enable experimental features -# (varies from version to version, see wiki) -#enable_experimental = false - # Map directory (everything in the world is stored here) #map-dir = /home/palle/custom_map @@ -112,6 +108,13 @@ # Gives some stuff to players at the beginning #give_initial_stuff = false +# Set to true to enable experimental features +# (varies from version to version, see wiki) +#enable_experimental = false + +# Profiler data print interval. 0 = disable. +#profiler_print_interval = 10 + # Player and object positions are sent at intervals specified by this #objectdata_inverval = 0.2 diff --git a/src/defaultsettings.cpp b/src/defaultsettings.cpp index 6fcdc1dbb..73f22a7f7 100644 --- a/src/defaultsettings.cpp +++ b/src/defaultsettings.cpp @@ -74,12 +74,13 @@ void set_default_settings() g_settings.setDefault("give_initial_stuff", "false"); g_settings.setDefault("default_password", ""); g_settings.setDefault("default_privs", "build, shout"); + g_settings.setDefault("profiler_print_interval", "0"); g_settings.setDefault("objectdata_interval", "0.2"); g_settings.setDefault("active_object_range", "2"); g_settings.setDefault("max_simultaneous_block_sends_per_client", "1"); //g_settings.setDefault("max_simultaneous_block_sends_per_client", "2"); - g_settings.setDefault("max_simultaneous_block_sends_server_total", "4"); + g_settings.setDefault("max_simultaneous_block_sends_server_total", "8"); g_settings.setDefault("max_block_send_distance", "8"); g_settings.setDefault("max_block_generate_distance", "8"); g_settings.setDefault("time_send_interval", "20"); diff --git a/src/game.cpp b/src/game.cpp index 6932b45f1..e8e6cb71f 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -903,6 +903,10 @@ void the_game( bool first_loop_after_window_activation = true; + // TODO: Convert the static interval timers to these + // Interval limiter for profiler + IntervalLimiter m_profiler_interval; + // Time is in milliseconds // NOTE: getRealTime() causes strange problems in wine (imprecision?) // NOTE: So we have to use getTime() and call run()s between them @@ -1089,6 +1093,21 @@ void the_game( } } + /* + Profiler + */ + float profiler_print_interval = + g_settings.getFloat("profiler_print_interval"); + if(profiler_print_interval != 0) + { + if(m_profiler_interval.step(0.030, profiler_print_interval)) + { + dstream<<"Profiler:"< diff --git a/src/map.cpp b/src/map.cpp index a49de3c46..f9809e9fd 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -5692,9 +5692,9 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass) p_nodes_min.Y / MAP_BLOCKSIZE - 1, p_nodes_min.Z / MAP_BLOCKSIZE - 1); v3s16 p_blocks_max( - p_nodes_max.X / MAP_BLOCKSIZE + 1, - p_nodes_max.Y / MAP_BLOCKSIZE + 1, - p_nodes_max.Z / MAP_BLOCKSIZE + 1); + p_nodes_max.X / MAP_BLOCKSIZE, + p_nodes_max.Y / MAP_BLOCKSIZE, + p_nodes_max.Z / MAP_BLOCKSIZE); u32 vertex_count = 0; diff --git a/src/mapblock.cpp b/src/mapblock.cpp index c448ef236..b2f972dde 100644 --- a/src/mapblock.cpp +++ b/src/mapblock.cpp @@ -540,10 +540,10 @@ void updateFastFaceRow( v3s16 p_next; - bool next_makes_face; + bool next_makes_face = false; v3s16 next_p_corrected; v3s16 next_face_dir_corrected; - u8 next_lights[4]; + u8 next_lights[4] = {0,0,0,0}; TileSpec next_tile; // If at last position, there is nothing to compare to and diff --git a/src/profiler.h b/src/profiler.h new file mode 100644 index 000000000..a30e34a7c --- /dev/null +++ b/src/profiler.h @@ -0,0 +1,131 @@ +/* +Minetest-c55 +Copyright (C) 2011 celeron55, Perttu Ahola + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#ifndef PROFILER_HEADER +#define PROFILER_HEADER + +#include "common_irrlicht.h" +#include +#include "utility.h" +#include +#include + +/* + Time profiler +*/ + +class Profiler +{ +public: + Profiler() + { + m_mutex.Init(); + } + + void add(const std::string &name, u32 duration) + { + JMutexAutoLock lock(m_mutex); + core::map::Node *n = m_data.find(name); + if(n == NULL) + { + m_data[name] = duration; + } + else + { + n->setValue(n->getValue()+duration); + } + } + + void clear() + { + JMutexAutoLock lock(m_mutex); + for(core::map::Iterator + i = m_data.getIterator(); + i.atEnd() == false; i++) + { + i.getNode()->setValue(0); + } + } + + void print(std::ostream &o) + { + JMutexAutoLock lock(m_mutex); + for(core::map::Iterator + i = m_data.getIterator(); + i.atEnd() == false; i++) + { + std::string name = i.getNode()->getKey(); + o<getValue(); + o< m_data; +}; + +class ScopeProfiler +{ +public: + ScopeProfiler(Profiler *profiler, const std::string &name): + m_profiler(profiler), + m_name(name), + m_timer(NULL) + { + if(m_profiler) + m_timer = new TimeTaker(m_name.c_str()); + } + // name is copied + ScopeProfiler(Profiler *profiler, const char *name): + m_profiler(profiler), + m_name(name), + m_timer(NULL) + { + if(m_profiler) + m_timer = new TimeTaker(m_name.c_str()); + } + ~ScopeProfiler() + { + if(m_timer) + { + u32 duration = m_timer->stop(true); + if(m_profiler) + m_profiler->add(m_name, duration); + delete m_timer; + } + } +private: + Profiler *m_profiler; + std::string m_name; + TimeTaker *m_timer; +}; + +#endif + diff --git a/src/server.cpp b/src/server.cpp index 56874c46c..6f1f1e6e8 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -312,11 +312,14 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime, TimeTaker timer("RemoteClient::GetNextBlocks", &timer_result);*/ // Increment timers - m_nearest_unsent_reset_timer += dtime; m_nothing_to_send_pause_timer -= dtime; if(m_nothing_to_send_pause_timer >= 0) + { + // Keep this reset + m_nearest_unsent_reset_timer = 0; return; + } // Won't send anything if already sending if(m_blocks_sending.size() >= g_settings.getU16 @@ -326,14 +329,21 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime, return; } + //TimeTaker timer("RemoteClient::GetNextBlocks"); + Player *player = server->m_env.getPlayer(peer_id); assert(player != NULL); v3f playerpos = player->getPosition(); v3f playerspeed = player->getSpeed(); + v3f playerspeeddir(0,0,0); + if(playerspeed.getLength() > 1.0*BS) + playerspeeddir = playerspeed / playerspeed.getLength(); + // Predict to next block + v3f playerpos_predicted = playerpos + playerspeeddir*MAP_BLOCKSIZE*BS; - v3s16 center_nodepos = floatToInt(playerpos, BS); + v3s16 center_nodepos = floatToInt(playerpos_predicted, BS); v3s16 center = getNodeBlockPos(center_nodepos); @@ -344,6 +354,9 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime, camera_dir.rotateYZBy(player->getPitch()); camera_dir.rotateXZBy(player->getYaw()); + /*dstream<<"camera_dir=("<getPlayerName(peer_id)< d_start+1) + d_max = d_start+1; + /*if(d_max_gen > d_start+2) + d_max_gen = d_start+2;*/ + //dstream<<"Starting from "<= 3) + if((s16)m_nothing_to_send_counter >= + g_settings.getS16("max_block_send_distance")) { // Pause time in seconds - m_nothing_to_send_pause_timer = 2.0; + m_nothing_to_send_pause_timer = 1.0; + dstream<<"nothing to send to " + <getPlayerName(peer_id) + <<" (d="< modified_blocks; m_env.getMap().transformLiquids(modified_blocks); #if 0 @@ -1298,10 +1360,11 @@ void Server::AsyncRunStep() */ { //dstream<<"Server: Checking added and deleted active objects"<* > buffered_messages; @@ -1598,6 +1663,9 @@ void Server::AsyncRunStep() { JMutexAutoLock lock1(m_env_mutex); JMutexAutoLock lock2(m_con_mutex); + + ScopeProfiler sp(&g_profiler, "Server: sending mbo positions"); + SendObjectData(counter); counter = 0.0; @@ -1612,7 +1680,9 @@ void Server::AsyncRunStep() JMutexAutoLock envlock(m_env_mutex); JMutexAutoLock conlock(m_con_mutex); - + + ScopeProfiler sp(&g_profiler, "Server: stepping node metadata"); + core::map changed_blocks; m_env.getMap().nodeMetadataStep(dtime, changed_blocks); @@ -1655,6 +1725,8 @@ void Server::AsyncRunStep() { counter = 0.0; + ScopeProfiler sp(&g_profiler, "Server: saving stuff"); + // Auth stuff m_authmanager.save(); @@ -3646,20 +3718,24 @@ void Server::SendBlocks(float dtime) core::array queue; s32 total_sending = 0; - - for(core::map::Iterator - i = m_clients.getIterator(); - i.atEnd() == false; i++) + { - RemoteClient *client = i.getNode()->getValue(); - assert(client->peer_id == i.getNode()->getKey()); + ScopeProfiler sp(&g_profiler, "Server: selecting blocks for sending"); - total_sending += client->SendingCount(); - - if(client->serialization_version == SER_FMT_VER_INVALID) - continue; - - client->GetNextBlocks(this, dtime, queue); + for(core::map::Iterator + i = m_clients.getIterator(); + i.atEnd() == false; i++) + { + RemoteClient *client = i.getNode()->getValue(); + assert(client->peer_id == i.getNode()->getKey()); + + total_sending += client->SendingCount(); + + if(client->serialization_version == SER_FMT_VER_INVALID) + continue; + + client->GetNextBlocks(this, dtime, queue); + } } // Sort. @@ -4531,25 +4607,48 @@ void dedicated_server_loop(Server &server, bool &kill) { DSTACK(__FUNCTION_NAME); - std::cout<PrintLine(&std::cout); + i->PrintLine(&dstream); } } sum_old = sum; diff --git a/src/server.h b/src/server.h index 7b73e476c..6bee10685 100644 --- a/src/server.h +++ b/src/server.h @@ -500,6 +500,15 @@ private: // When called, connection mutex should be locked RemoteClient* getClient(u16 peer_id); + // When called, environment mutex should be locked + std::string getPlayerName(u16 peer_id) + { + Player *player = m_env.getPlayer(peer_id); + if(player == NULL) + return "[id="+itos(peer_id); + return player->getName(); + } + /* Get a player from memory or creates one. If player is already connected, return NULL @@ -627,6 +636,8 @@ private: */ u16 m_ignore_map_edit_events_peer_id; + Profiler *m_profiler; + friend class EmergeThread; friend class RemoteClient; }; diff --git a/src/utility.h b/src/utility.h index f18d31278..534aea483 100644 --- a/src/utility.h +++ b/src/utility.h @@ -244,6 +244,9 @@ inline f32 readF1000(std::istream &is) { char buf[2]; is.read(buf, 2); + // TODO: verify if this gets rid of the valgrind warning + //if(is.gcount() != 2) + // return 0; return readF1000((u8*)buf); } -- cgit v1.2.3 From aed9e809a19bffdf911f75dd9d718efb8decd2c1 Mon Sep 17 00:00:00 2001 From: Perttu Ahola Date: Sat, 25 Jun 2011 16:32:09 +0300 Subject: mapgen stuff --- src/defaultsettings.cpp | 1 + src/environment.cpp | 2 + src/map.cpp | 535 ++++++++++++++++++++++++++++++------------------ src/mapblock_mesh.cpp | 4 +- src/noise.h | 39 ++++ src/server.cpp | 2 +- src/utility.h | 5 + 7 files changed, 392 insertions(+), 196 deletions(-) (limited to 'src/utility.h') diff --git a/src/defaultsettings.cpp b/src/defaultsettings.cpp index 289be0a06..74d323237 100644 --- a/src/defaultsettings.cpp +++ b/src/defaultsettings.cpp @@ -92,5 +92,6 @@ void set_default_settings() g_settings.setDefault("server_unload_unused_sectors_timeout", "60"); g_settings.setDefault("server_map_save_interval", "60"); g_settings.setDefault("full_block_send_enable_min_time_from_building", "2.0"); + //g_settings.setDefault("dungeon_rarity", "0.025"); } diff --git a/src/environment.cpp b/src/environment.cpp index 9bbba08b0..cd255341f 100644 --- a/src/environment.cpp +++ b/src/environment.cpp @@ -619,6 +619,7 @@ void ServerEnvironment::activateBlock(MapBlock *block, u32 additional_dtime) { v3s16 p = p0 + block->getPosRelative(); MapNode n = block->getNodeNoEx(p0); +#if 1 // Test something: // Convert all mud under proper day lighting to grass if(n.d == CONTENT_MUD) @@ -634,6 +635,7 @@ void ServerEnvironment::activateBlock(MapBlock *block, u32 additional_dtime) } } } +#endif } } diff --git a/src/map.cpp b/src/map.cpp index fe6b7a701..cb0967c35 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -2169,6 +2169,7 @@ void make_randomstone(VoxelManipulator &vmanip, v3s16 p0) } #endif +#if 0 void make_largestone(VoxelManipulator &vmanip, v3s16 p0) { MapNode stonenode(CONTENT_STONE); @@ -2250,6 +2251,7 @@ void make_largestone(VoxelManipulator &vmanip, v3s16 p0) vmanip.m_data[vi] = stonenode; } } +#endif /* Dungeon making routines @@ -2375,39 +2377,79 @@ void make_hole1(VoxelManipulator &vmanip, v3s16 place) void make_door1(VoxelManipulator &vmanip, v3s16 doorplace, v3s16 doordir) { make_hole1(vmanip, doorplace); + // Place torch (for testing) + //vmanip.m_data[vmanip.m_area.index(doorplace)] = MapNode(CONTENT_TORCH); +} + +v3s16 rand_ortho_dir(PseudoRandom &random) +{ + if(random.next()%2==0) + return random.next()%2 ? v3s16(-1,0,0) : v3s16(1,0,0); + else + return random.next()%2 ? v3s16(0,0,-1) : v3s16(0,0,1); } -v3s16 rand_ortho_dir() +v3s16 turn_xz(v3s16 olddir, int t) { - if(myrand()%2==0) - return myrand()%2 ? v3s16(-1,0,0) : v3s16(1,0,0); + v3s16 dir; + if(t == 0) + { + // Turn right + dir.X = olddir.Z; + dir.Z = -olddir.X; + dir.Y = olddir.Y; + } else - return myrand()%2 ? v3s16(0,0,-1) : v3s16(0,0,1); + { + // Turn left + dir.X = -olddir.Z; + dir.Z = olddir.X; + dir.Y = olddir.Y; + } + return dir; +} + +v3s16 random_turn(PseudoRandom &random, v3s16 olddir) +{ + int turn = random.range(0,2); + v3s16 dir; + if(turn == 0) + { + // Go straight + dir = olddir; + } + else if(turn == 1) + // Turn right + dir = turn_xz(olddir, 0); + else + // Turn left + dir = turn_xz(olddir, 1); + return dir; } void make_corridor(VoxelManipulator &vmanip, v3s16 doorplace, v3s16 doordir, - v3s16 &result_place, v3s16 &result_dir) + v3s16 &result_place, v3s16 &result_dir, PseudoRandom &random) { make_hole1(vmanip, doorplace); v3s16 p0 = doorplace; v3s16 dir = doordir; u32 length; - if(myrand()%2) - length = myrand_range(1,13); + if(random.next()%2) + length = random.range(1,13); else - length = myrand_range(1,6); - u32 partlength = myrand_range(1,length); + length = random.range(1,6); + length = random.range(1,13); + u32 partlength = random.range(1,length); u32 partcount = 0; s16 make_stairs = 0; - if(myrand()%2 == 0 && partlength >= 3) - make_stairs = myrand()%2 ? 1 : -1; + if(random.next()%2 == 0 && partlength >= 3) + make_stairs = random.next()%2 ? 1 : -1; for(u32 i=0; i= partlength) { partcount = 0; - v3s16 newdir = rand_ortho_dir(); - partlength = myrand_range(1,7); - make_stairs = 0; - if(myrand()%2 == 0 && partlength >= 3) - make_stairs = myrand()%2 ? 1 : -1; + dir = random_turn(random, dir); + + partlength = random.range(1,length); - if(make_stairs != 0) - { - if(newdir.X == 0 && dir.X != 0) - dir = newdir; - if(newdir.Z == 0 && dir.Z != 0) - dir = newdir; - } - else - { - dir = newdir; - } - dir.Y = make_stairs; + make_stairs = 0; + if(random.next()%2 == 0 && partlength >= 3) + make_stairs = random.next()%2 ? 1 : -1; } } - //p0.Y -= make_stairs; - dir.Y = 0; result_place = p0; result_dir = dir; } @@ -2466,16 +2513,17 @@ class RoomWalker { public: - RoomWalker(VoxelManipulator &vmanip_, v3s16 pos): + RoomWalker(VoxelManipulator &vmanip_, v3s16 pos, PseudoRandom &random): vmanip(vmanip_), - m_pos(pos) + m_pos(pos), + m_random(random) { randomizeDir(); } void randomizeDir() { - m_dir = rand_ortho_dir(); + m_dir = rand_ortho_dir(m_random); } void setPos(v3s16 pos) @@ -2561,13 +2609,13 @@ public: v3s16 roomplace; // X east, Z north, Y up if(doordir == v3s16(1,0,0)) // X+ - roomplace = doorplace + v3s16(0,-1,-roomsize.Z/2+myrand_range(-roomsize.Z/2,roomsize.Z/2)); + roomplace = doorplace + v3s16(0,-1,-roomsize.Z/2+m_random.range(-roomsize.Z/2+1,roomsize.Z/2-1)); if(doordir == v3s16(-1,0,0)) // X- - roomplace = doorplace + v3s16(-roomsize.X+1,-1,-roomsize.Z/2+myrand_range(-roomsize.Z/2,roomsize.Z/2)); + roomplace = doorplace + v3s16(-roomsize.X+1,-1,-roomsize.Z/2+m_random.range(-roomsize.Z/2+1,roomsize.Z/2-1)); if(doordir == v3s16(0,0,1)) // Z+ - roomplace = doorplace + v3s16(-roomsize.X/2+myrand_range(-roomsize.X/2,roomsize.X/2),-1,0); + roomplace = doorplace + v3s16(-roomsize.X/2+m_random.range(-roomsize.X/2+1,roomsize.X/2-1),-1,0); if(doordir == v3s16(0,0,-1)) // Z- - roomplace = doorplace + v3s16(-roomsize.X/2+myrand_range(-roomsize.X/2,roomsize.X/2),-1,-roomsize.Z+1); + roomplace = doorplace + v3s16(-roomsize.X/2+m_random.range(-roomsize.X/2+1,roomsize.X/2-1),-1,-roomsize.Z+1); // Check fit bool fits = true; @@ -2604,58 +2652,133 @@ public: private: VoxelManipulator &vmanip; v3s16 m_pos; - v3s16 m_dir; + v3s16 m_dir; + PseudoRandom &m_random; }; -void make_dungeon1(VoxelManipulator &vmanip) +void make_dungeon1(VoxelManipulator &vmanip, PseudoRandom &random) { v3s16 areasize = vmanip.m_area.getExtent(); v3s16 roomsize; v3s16 roomplace; - roomsize = v3s16(myrand_range(4,8),myrand_range(4,6),myrand_range(4,8)); - roomplace = vmanip.m_area.MinEdge + v3s16( - myrand_range(0,areasize.X-roomsize.X-1), - myrand_range(0,areasize.Y-roomsize.Y-1), - myrand_range(0,areasize.Z-roomsize.Z-1)); + /* + Find place for first room + */ + bool fits = false; + for(u32 i=0; i<100; i++) + { + roomsize = v3s16(random.range(4,8),random.range(4,6),random.range(4,8)); + roomplace = vmanip.m_area.MinEdge + v3s16( + random.range(0,areasize.X-roomsize.X-1), + random.range(0,areasize.Y-roomsize.Y-1), + random.range(0,areasize.Z-roomsize.Z-1)); + /* + Check that we're not putting the room to an unknown place, + otherwise it might end up floating in the air + */ + fits = true; + for(s16 z=1; zm_static_objects.insert(0, s_obj); delete obj; } - if(myrand() % 300 == 0) + if(myrand() % 1000 == 0) { v3f pos_f = intToFloat(p+block->getPosRelative(), BS); pos_f.Y -= BS*0.4; @@ -3078,18 +3202,18 @@ void makeBlock(BlockMakeData *data) s16 approx_ground_depth = approx_groundlevel - (node_min.Y+MAP_BLOCKSIZE/2); - /*s16 minimum_groundlevel = (s16)get_sector_minimum_ground_level( + s16 minimum_groundlevel = (s16)get_sector_minimum_ground_level( data->seed, v2s16(blockpos.X, blockpos.Z)); - // Minimum amount of ground above the central block - s16 minimum_ground_depth = minimum_groundlevel - node_max.Y;*/ - + // Minimum amount of ground above the top of the central block + s16 minimum_ground_depth = minimum_groundlevel - node_max.Y; + s16 maximum_groundlevel = (s16)get_sector_maximum_ground_level( data->seed, v2s16(blockpos.X, blockpos.Z), 1); - // Minimum amount of ground above the central block + // Maximum amount of ground above the bottom of the central block s16 maximum_ground_depth = maximum_groundlevel - node_min.Y; /* - Special case for high air or water + Special case for high air or water: Just fill with air and water. */ if(maximum_ground_depth < -20) { @@ -3121,6 +3245,18 @@ void makeBlock(BlockMakeData *data) // We're done return; } + + /* + If block is deep underground, this is set to true and ground + density noise is not generated, for speed optimization. + */ + bool all_is_ground_except_caves = (minimum_ground_depth > 16); + + /* + Create a block-specific seed + */ + u32 blockseed = (data->seed%0x100000000) + full_node_min.Z*38134234 + + full_node_min.Y*42123 + full_node_min.X*23; /* Make some 3D noise @@ -3145,8 +3281,7 @@ void makeBlock(BlockMakeData *data) noisebuf_cave.create(get_cave_noise1_params(data->seed), minpos_f.X, minpos_f.Y, minpos_f.Z, maxpos_f.X, maxpos_f.Y, maxpos_f.Z, - 4, 4, 4); - //3.5, 3.5, 3.5); + 4, 3, 4); noisebuf_cave.multiply(get_cave_noise2_params(data->seed)); @@ -3158,16 +3293,17 @@ void makeBlock(BlockMakeData *data) v3f sl = v3f(4.0, 4.0, 4.0); /* - Density + Density noise */ - //noisebuf_ground.create(data->seed+983240, 6, 0.60, false, - noisebuf_ground.create(get_ground_noise1_params(data->seed), - minpos_f.X, minpos_f.Y, minpos_f.Z, - maxpos_f.X, maxpos_f.Y, maxpos_f.Z, - sl.X, sl.Y, sl.Z); + if(all_is_ground_except_caves == false) + //noisebuf_ground.create(data->seed+983240, 6, 0.60, false, + noisebuf_ground.create(get_ground_noise1_params(data->seed), + minpos_f.X, minpos_f.Y, minpos_f.Z, + maxpos_f.X, maxpos_f.Y, maxpos_f.Z, + sl.X, sl.Y, sl.Z); /* - Content + Ground property noise */ sl = v3f(2.5, 2.5, 2.5); noisebuf_ground_crumbleness.create( @@ -3200,42 +3336,22 @@ void makeBlock(BlockMakeData *data) // Only modify places that have no content if(vmanip.m_data[i].d == CONTENT_IGNORE) { - if(noisebuf_cave.get(x,y,z) > CAVE_NOISE_THRESHOLD) + // First priority: make air and water. + // This avoids caves inside water. + if(all_is_ground_except_caves == false + && val_is_ground(noisebuf_ground.get(x,y,z), + v3s16(x,y,z), data->seed) == false) + { + if(y <= WATER_LEVEL) + vmanip.m_data[i] = MapNode(CONTENT_WATERSOURCE); + else + vmanip.m_data[i] = MapNode(CONTENT_AIR); + } + else if(noisebuf_cave.get(x,y,z) > CAVE_NOISE_THRESHOLD) vmanip.m_data[i] = MapNode(CONTENT_AIR); - else if(val_is_ground(noisebuf_ground.get(x,y,z), - v3s16(x,y,z), data->seed)) - vmanip.m_data[i] = MapNode(CONTENT_STONE); - else if(y <= WATER_LEVEL) - vmanip.m_data[i] = MapNode(CONTENT_WATERSOURCE); else - vmanip.m_data[i] = MapNode(CONTENT_AIR); - } - - /*if(noisebuf_cave.get(x,y,z) > CAVE_NOISE_THRESHOLD) - { - // Only modify places that have no content - if(vmanip.m_data[i].d == CONTENT_IGNORE) - vmanip.m_data[i] = MapNode(CONTENT_AIR); - } - else if(is_ground(noisebuf_ground.get(x,y,z), y)) - { - // Only modify places that have no content - if(vmanip.m_data[i].d == CONTENT_IGNORE) vmanip.m_data[i] = MapNode(CONTENT_STONE); } - else if(y <= WATER_LEVEL) - { - // Only modify places that have air or no content - if(vmanip.m_data[i].d == CONTENT_IGNORE - || vmanip.m_data[i].d == CONTENT_AIR) - vmanip.m_data[i] = MapNode(CONTENT_WATERSOURCE); - } - else - { - // Only modify places that have no content - if(vmanip.m_data[i].d == CONTENT_IGNORE) - vmanip.m_data[i] = MapNode(CONTENT_AIR); - }*/ data->vmanip.m_area.add_y(em, i, 1); } @@ -3247,22 +3363,24 @@ void makeBlock(BlockMakeData *data) */ { + PseudoRandom mineralrandom(blockseed); + /* Add meseblocks */ for(s16 i=0; iseed)+1.0)/2.0) + < dungeon_rarity + && node_min.Y < approx_groundlevel) { // Dungeon generator doesn't modify places which have this set data->vmanip.clearFlag(VMANIP_FLAG_DUNGEON_INSIDE @@ -3433,7 +3556,7 @@ void makeBlock(BlockMakeData *data) // Use fast index incrementing v3s16 em = vmanip.m_area.getExtent(); u32 i = vmanip.m_area.index(v3s16(p2d.X, full_node_max.Y, p2d.Y)); - for(s16 y=node_max.Y; y>=full_node_min.Y; y--) + for(s16 y=full_node_max.Y; y>=full_node_min.Y; y--) { if(vmanip.m_data[i].d == CONTENT_AIR) vmanip.m_flags[i] |= VMANIP_FLAG_DUNGEON_PRESERVE; @@ -3444,18 +3567,11 @@ void makeBlock(BlockMakeData *data) } } - /*s16 x = myrand_range(node_min.X, node_max.X); - s16 z = myrand_range(node_min.Z, node_max.Z); - s16 y = myrand_range(node_min.Y, node_max.Y);*/ + PseudoRandom random(blockseed+2); + // Add it - make_dungeon1(data->vmanip); + make_dungeon1(data->vmanip, random); - // Take different seed for every dungeon for not blending their - // mossyness together - //u32 mossyseed = z*38134234+y*42123+x*23; - u32 mossyseed = full_node_min.Z*38134234 - +full_node_min.Y*42123+full_node_min.X*23; - // Convert some cobble to mossy cobble for(s16 x=full_node_min.X; x<=full_node_max.X; x++) for(s16 z=full_node_min.Z; z<=full_node_max.Z; z++) @@ -3466,20 +3582,27 @@ void makeBlock(BlockMakeData *data) // Use fast index incrementing v3s16 em = vmanip.m_area.getExtent(); u32 i = vmanip.m_area.index(v3s16(p2d.X, full_node_max.Y, p2d.Y)); - for(s16 y=node_max.Y; y>=full_node_min.Y; y--) + for(s16 y=full_node_max.Y; y>=full_node_min.Y; y--) { - // No mossy in dry places - // (noisebuf not used because it's smaller in size) - if(noise3d_param(get_ground_wetness_params(data->seed), x,y,z) - < -0.6) - continue; - double d = noise3d_perlin((float)x/4., - (float)y/4.,(float)z/4., - mossyseed, 2, 0.9); - if(d < 0.0) - continue; + // (noisebuf not used because it doesn't contain the + // full area) + double wetness = noise3d_param( + get_ground_wetness_params(data->seed), x,y,z); + double d = noise3d_perlin((float)x/2.5, + (float)y/2.5,(float)z/2.5, + blockseed, 2, 1.4); if(vmanip.m_data[i].d == CONTENT_COBBLE) - vmanip.m_data[i].d = CONTENT_MOSSYCOBBLE; + { + if(d < wetness/3.0) + { + vmanip.m_data[i].d = CONTENT_MOSSYCOBBLE; + } + } + /*else if(vmanip.m_flags[i] & VMANIP_FLAG_DUNGEON_INSIDE) + { + if(wetness > 1.2) + vmanip.m_data[i].d = CONTENT_MUD; + }*/ data->vmanip.m_area.add_y(em, i, -1); } } @@ -3533,7 +3656,8 @@ void makeBlock(BlockMakeData *data) If close to ground level */ - if(abs(approx_ground_depth) < 20) + //if(abs(approx_ground_depth) < 30) + if(minimum_ground_depth < 5 && maximum_ground_depth > -5) { /* Add grass and mud @@ -3547,14 +3671,14 @@ void makeBlock(BlockMakeData *data) { bool possibly_have_sand = get_have_sand(data->seed, p2d); bool have_sand = false; - u32 mud_count = 0; + u32 current_depth = 0; bool air_detected = false; bool water_detected = false; // Use fast index incrementing s16 start_y = node_max.Y+2; v3s16 em = vmanip.m_area.getExtent(); u32 i = vmanip.m_area.index(v3s16(p2d.X, start_y, p2d.Y)); - for(s16 y=start_y; y>=node_min.Y-2; y--) + for(s16 y=start_y; y>=node_min.Y-3; y--) { if(vmanip.m_data[i].d == CONTENT_WATERSOURCE) water_detected = true; @@ -3568,24 +3692,37 @@ void makeBlock(BlockMakeData *data) || vmanip.m_data[i].d == CONTENT_GRAVEL ) && (air_detected || water_detected)) { - if(mud_count == 0 && y <= WATER_LEVEL+2 + if(current_depth == 0 && y <= WATER_LEVEL+2 && possibly_have_sand) have_sand = true; - - if(have_sand) + + if(current_depth < 4) { - vmanip.m_data[i] = MapNode(CONTENT_SAND); + if(have_sand) + { + vmanip.m_data[i] = MapNode(CONTENT_SAND); + } + #if 1 + else if(current_depth==0 && !water_detected + && y >= WATER_LEVEL && air_detected) + vmanip.m_data[i] = MapNode(CONTENT_GRASS); + #endif + else + vmanip.m_data[i] = MapNode(CONTENT_MUD); } - else if(mud_count==0 && !water_detected && y >= WATER_LEVEL) - vmanip.m_data[i] = MapNode(CONTENT_GRASS); else - vmanip.m_data[i] = MapNode(CONTENT_MUD); + { + if(vmanip.m_data[i].d == CONTENT_MUD + || vmanip.m_data[i].d == CONTENT_GRASS) + vmanip.m_data[i] = MapNode(CONTENT_STONE); + } - mud_count++; - if(mud_count >= 4) + current_depth++; + + if(current_depth >= 8) break; } - else if(mud_count != 0) + else if(current_depth != 0) break; data->vmanip.m_area.add_y(em, i, -1); @@ -3599,11 +3736,12 @@ void makeBlock(BlockMakeData *data) // Amount of trees u32 tree_count = block_area_nodes * tree_amount_2d(data->seed, p2d_center); + PseudoRandom treerandom(blockseed); // Put trees in random places on part of division for(u32 i=0; ivmanip, v2s16(x,z)); s16 y = find_ground_level_from_noise(data->seed, v2s16(x,z), 4); // Don't make a tree under water level @@ -3800,15 +3938,17 @@ MapBlock* ServerMap::finishBlockMake(BlockMakeData *data, /* Blit generated stuff to map + NOTE: blitBackAll adds nearly everything to changed_blocks */ { // 70ms @cs=8 //TimeTaker timer("finishBlockMake() blitBackAll"); data->vmanip.blitBackAll(&changed_blocks); } - - //dstream<<"changed_blocks.size()="< 32768/10) + { + //dstream<<"WARNING: PseudoRandom::range: max > 32767"< max) + { + assert(0); + return max; + } + return (next()%(max-min+1))+min; + } +private: + int m_next; +}; + double easeCurve(double t); // Return value: -1 ... 1 diff --git a/src/server.cpp b/src/server.cpp index 3036aef26..49eb15731 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -1720,7 +1720,7 @@ void Server::AsyncRunStep() // Don't send too many at a time count++; - if(count >= 2 && m_unsent_map_edit_queue.size() < 50) + if(count >= 1 && m_unsent_map_edit_queue.size() < 100) break; } } diff --git a/src/utility.h b/src/utility.h index 534aea483..497f79fa0 100644 --- a/src/utility.h +++ b/src/utility.h @@ -1741,6 +1741,11 @@ void mysrand(unsigned seed); inline int myrand_range(int min, int max) { + if(max-min > MYRAND_MAX) + { + dstream<<"WARNING: myrand_range: max-min > MYRAND_MAX"< max) { assert(0); -- cgit v1.2.3