From 25a7fabed83caccb2c321bb4d080c5907f37b60a Mon Sep 17 00:00:00 2001 From: Perttu Ahola Date: Sun, 6 Feb 2011 16:35:27 +0200 Subject: [PATCH] mapgen tweaking --- src/defaultsettings.cpp | 9 +- src/environment.cpp | 4 +- src/main.cpp | 59 ++------- src/map.cpp | 265 ++++++++++++++++++++++++++++++++-------- src/noise.h | 2 + src/player.cpp | 65 ++++++---- src/player.h | 8 +- src/server.cpp | 46 +------ src/utility.h | 11 +- 9 files changed, 285 insertions(+), 184 deletions(-) diff --git a/src/defaultsettings.cpp b/src/defaultsettings.cpp index 70f5e0ae..714703b0 100644 --- a/src/defaultsettings.cpp +++ b/src/defaultsettings.cpp @@ -37,13 +37,14 @@ void set_default_settings() g_settings.setDefault("client_delete_unused_sectors_timeout", "1200"); g_settings.setDefault("enable_fog", "true"); g_settings.setDefault("new_style_water", "true"); + g_settings.setDefault("terrain_viewer", "false"); + + g_settings.setDefault("free_move", "false"); + g_settings.setDefault("continuous_forward", "false"); + g_settings.setDefault("fast_move", "false"); // Server stuff g_settings.setDefault("creative_mode", "false"); - g_settings.setDefault("haxmode", "false"); - g_settings.setDefault("plants_amount", "1.0"); - g_settings.setDefault("ravines_amount", "0"); - g_settings.setDefault("coal_amount", "1.0"); g_settings.setDefault("objectdata_interval", "0.2"); g_settings.setDefault("active_object_range", "2"); diff --git a/src/environment.cpp b/src/environment.cpp index dc44b3a3..b1722ee3 100644 --- a/src/environment.cpp +++ b/src/environment.cpp @@ -107,8 +107,8 @@ void Environment::step(float dtime) v3f playerpos = player->getPosition(); // Apply physics to local player - bool haxmode = g_settings.getBool("haxmode"); - if(player->isLocal() && haxmode == false) + bool free_move = g_settings.getBool("free_move"); + if(player->isLocal() && free_move == false) { // Apply gravity to local player v3f speed = player->getSpeed(); diff --git a/src/main.cpp b/src/main.cpp index 75ee2f26..24f3664f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -79,13 +79,9 @@ SUGG: Split MapBlockObject serialization to to-client and to-disk SUGG: MovingObject::move and Player::move are basically the same. combine them. -SUGG: Implement a "Fast check queue" (a queue with a map for checking - if something is already in it) - - Use it in active block queue in water flowing - SUGG: Precalculate lighting translation table at runtime (at startup) - This is not doable because it is currently hand-made and not - based on some mathematical function. + based on some mathematical function. Now it is not. SUGG: A version number to blocks, which increments when the block is modified (node add/remove, water update, lighting update) @@ -128,6 +124,7 @@ FIXME: Graphical mode seems to segfault with Irrlicht 1.7.1 on 64-bit FIXME: Some network errors on Windows that cause local game to not work - See siggjen's emails. + - Is this the famous "windows 7 problem"? Networking and serialization: ----------------------------- @@ -168,21 +165,7 @@ TODO: Make fetching sector's blocks more efficient when rendering TODO: Flowing water animation -FIXME(FIXED): The new texture stuff is slow on wine - - A basic grassy ground block takes 20-40ms - - A bit more complicated block can take 270ms - - On linux, a similar one doesn't take long at all (14ms) - - It is NOT a bad std::string implementation of MSVC. - - Can take up to 200ms? Is it when loading textures or always? - - Updating excess amount of meshes when making footprints is too - slow. It has to be fixed. - -> implement Map::updateNodeMeshes() - The fix: - * Optimize TileSpec to only contain a reference number that - is fast to compare, which refers to a cached string, or - * Make TextureSpec for using instead of strings - -FIXME(FIXED): A lock condition is possible: +NOTE(FIXED): A lock condition is possible: 1) MapBlock::updateMesh() is called from client asynchronously: - AsyncProcessData() -> Map::updateMeshes() 2) Asynchronous locks m_temp_mods_mutex @@ -201,9 +184,8 @@ Client: TODO: Untie client network operations from framerate - Needs some input queues or something - - Not really necessary? -TODO: Make morning and evening shorter +TODO: Make morning and evening transition more smooth and maybe shorter TODO: Don't update all meshes always on single node changes, but check which ones should be updated @@ -226,8 +208,10 @@ TODO: Copy the text of the last picked sign to inventory in creative TODO: Check what goes wrong with caching map to disk (Kray) - Nothing? -TODO: When server sees that client is removing an inexistent block or - adding a block to an existent position, resend the MapBlock. +TODO: When server sees that client is removing an inexistent block to + an existent position, resend the MapBlock. + +FIXME: Server went into some infinite PeerNotFoundException loop Objects: -------- @@ -261,31 +245,16 @@ Block object server side: Map: ---- -NOTE: There are some lighting-related todos and fixmes in - ServerMap::emergeBlock. And there always will be. 8) - TODO: Mineral and ground material properties - This way mineral ground toughness can be calculated with just some formula, as well as tool strengths -TODO: Change AttributeList to split the area into smaller sections so - that searching won't be as heavy. - -TODO: Remove HMParams - TODO: Flowing water to actually contain flow direction information TODO: Remove duplicate lighting implementation from Map (leave VoxelManipulator, which is faster) FEATURE: Map generator version 2 - - Create surface areas based on central points; a given point's - area type is given by the nearest central point - - Separate points for heightmap, caves, plants and minerals? - - Flat land, mountains, forest, jungle - - Cliffs, arcs - - There could be a certain height (to which mountains only reach) - where some minerals are found - Create a system that allows a huge amount of different "map generator modules/filters" @@ -321,15 +290,11 @@ Doing now (most important at the top): * not done === Stuff to do before release -* Save map seed to a metafile (with version information) +* Save the new mapgen stuff - map/meta.txt, which should contain only plain text, something like this: - seed = O7+BZT9Vk/iVYiBlZ2dsb6zemp4xdGVysJqYmNt2X+MQ+Kg1 + seed = 7ff1bafcd7118800 chunksize = 8 - - map/chunks/ - - - - Compressed bunch of data... um, actually no. - - Make a directory for every chunk instead, which contains - sectors and blocks + - map/chunks.dat * Save chunk metadata on disk * Make server find the spawning place from the real map data, not from the heightmap @@ -338,8 +303,10 @@ Doing now (most important at the top): * Make the generator to run in background and not blocking block placement and transfer * only_from_disk might not work anymore - check and fix it. +* Check the fixmes in the list above === Stuff to do after release +* Set backface culling on, especially for water * Add some kind of erosion and other stuff that now is possible * Make client to fetch stuff asynchronously - Needs method SyncProcessData diff --git a/src/map.cpp b/src/map.cpp index e748b143..ef6263c7 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -1736,7 +1736,7 @@ ServerMap::ServerMap(std::string savedir): //m_chunksize = 64; //m_chunksize = 16; // Too slow - m_chunksize = 8; // Fine. Takes a few seconds. + m_chunksize = 8; // Takes a few seconds //m_chunksize = 4; //m_chunksize = 2; @@ -1973,22 +1973,22 @@ double tree_amount_2d(u64 seed, v2s16 p) { double noise = noise2d_perlin( 0.5+(float)p.X/250, 0.5+(float)p.Y/250, - seed+2, 4, 0.6); - double zeroval = -0.3; + seed+2, 5, 0.6); + double zeroval = -0.4; if(noise < zeroval) return 0; else return 0.04 * (noise-zeroval) / (1.0-zeroval); } -double base_rock_level_2d(u64 seed, v2s16 p) +/*double base_rock_level_2d(u64 seed, v2s16 p) { return WATER_LEVEL - 6.0 + 25. * noise2d_perlin( 0.5+(float)p.X/500., 0.5+(float)p.Y/500., seed, 6, 0.6); -} +}*/ -double highlands_level_2d(u64 seed, v2s16 p) +/*double highlands_level_2d(u64 seed, v2s16 p) { double a = noise2d_perlin( 0.5+(float)p.X/1000., 0.5+(float)p.Y/1000., @@ -1996,12 +1996,53 @@ double highlands_level_2d(u64 seed, v2s16 p) if(a > 0.0) //if(1) { + return WATER_LEVEL + 25; return WATER_LEVEL + 55. * noise2d_perlin( 0.5+(float)p.X/500., 0.5+(float)p.Y/500., seed+85039, 6, 0.69); } else return -100000; +}*/ + +double base_rock_level_2d(u64 seed, v2s16 p) +{ + // The base ground level + double base = WATER_LEVEL - 4.0 + 25. * noise2d_perlin( + 0.5+(float)p.X/500., 0.5+(float)p.Y/500., + seed, 6, 0.6); + + // Higher ground level + double higher = WATER_LEVEL + 23. + 30. * noise2d_perlin( + 0.5+(float)p.X/500., 0.5+(float)p.Y/500., + seed+85039, 6, 0.69); + //higher = 30; // For debugging + + // Limit higher to at least base + if(higher < base) + higher = base; + + // Steepness factor of cliffs + double b = 1.0 + 1.0 * noise2d_perlin( + 0.5+(float)p.X/250., 0.5+(float)p.Y/250., + seed-932, 7, 0.7); + b = rangelim(b, 0.0, 1000.0); + // Make steep stuff very steep and non-steep stuff very non-steep + b = pow(b, 4); + b *= 10; + //double b = 20; + + // High/low selector + double a = 0.5 + b * noise2d_perlin( + 0.5+(float)p.X/500., 0.5+(float)p.Y/500., + seed-359, 6, 0.7); + a = rangelim(a, 0.0, 1.0); + + //dstream<<"a="< surface_y_f) surface_y_f = a; - } + }*/ // Convert to integer s16 surface_y = (s16)surface_y_f; @@ -2208,20 +2249,20 @@ MapChunk* ServerMap::generateChunkRaw(v2s16 chunkpos, Randomize some parameters */ - //TODO s32 stone_obstacle_count = 0; - /*s32 stone_obstacle_count = (1.0+noise2d(m_seed+90443, sectorpos_base.X, - sectorpos_base.Y))/2.0 * stone_obstacle_amount/3;*/ + /*s32 stone_obstacle_count = + rangelim((1.0+noise2d(m_seed+897, + sectorpos_base.X, sectorpos_base.Y))/2.0 * 30, 0, 100000);*/ s16 stone_obstacle_max_height = 0; - - //u32 stone_obstacle_amount = - // myrand_range(0, myrand_range(20, myrand_range(80,150))); + /*s16 stone_obstacle_max_height = + rangelim((1.0+noise2d(m_seed+5902, + sectorpos_base.X, sectorpos_base.Y))/2.0 * 30, 0, 100000);*/ /* Loop this part, it will make stuff look older and newer nicely */ - + //for(u32 i_age=0; i_age<1; i_age++) for(u32 i_age=0; i_age<2; i_age++) { // Aging loop @@ -2238,7 +2279,8 @@ MapChunk* ServerMap::generateChunkRaw(v2s16 chunkpos, // Randomize max height so usually stuff will be quite low s16 maxheight_randomized = myrand_range(0, stone_obstacle_max_height); - s16 stone_obstacle_max_size = sectorpos_base_size * MAP_BLOCKSIZE - 10; + //s16 stone_obstacle_max_size = sectorpos_base_size * MAP_BLOCKSIZE - 10; + s16 stone_obstacle_max_size = MAP_BLOCKSIZE*4-4; v3s16 ob_size( myrand_range(5, stone_obstacle_max_size), @@ -2371,11 +2413,15 @@ MapChunk* ServerMap::generateChunkRaw(v2s16 chunkpos, if(bruise_surface) { - //min_tunnel_diameter = 5; - //max_tunnel_diameter = myrand_range(10, 20); - min_tunnel_diameter = MYMAX(0, stone_surface_max_y/6); - max_tunnel_diameter = myrand_range(MYMAX(0, stone_surface_max_y/6), MYMAX(0, stone_surface_max_y/4)); - tunnel_routepoints = 3; + min_tunnel_diameter = 5; + max_tunnel_diameter = myrand_range(10, 20); + /*min_tunnel_diameter = MYMAX(0, stone_surface_max_y/6); + max_tunnel_diameter = myrand_range(MYMAX(0, stone_surface_max_y/6), MYMAX(0, stone_surface_max_y/2));*/ + + /*s16 tunnel_rou = rangelim(25*(0.5+1.0*noise2d(m_seed+42, + sectorpos_base.X, sectorpos_base.Y)), 0, 15);*/ + + tunnel_routepoints = 5; } // Allowed route area size in nodes @@ -2441,11 +2487,16 @@ MapChunk* ServerMap::generateChunkRaw(v2s16 chunkpos, for(u16 j=0; j light_sources; { // 750ms @cs=8, can't optimize more - //TimeTaker timer1("initial lighting"); + TimeTaker timer1("initial lighting"); #if 0 /* @@ -3209,6 +3255,81 @@ MapChunk* ServerMap::generateChunkRaw(v2s16 chunkpos, { light_sources.insert(v3s16(p2d.X, y, p2d.Y), true); } + //NOTE: This is broken, at least the index has to + // be incremented + } + } + } +#endif + +#if 1 + /* + Go through the edges and apply sunlight to them, not caring + about neighbors + */ + + // Four edges + for(s16 i=0; i<4; i++) + // Edge length + for(s16 j=lighting_min_d; + j<=lighting_max_d; + j++) + { + s16 x; + s16 z; + // +-X + if(i == 0 || i == 1) + { + x = (i==0) ? lighting_min_d : lighting_max_d; + if(i == 0) + z = lighting_min_d; + else + z = lighting_max_d; + } + // +-Z + else + { + z = (i==0) ? lighting_min_d : lighting_max_d; + if(i == 0) + x = lighting_min_d; + else + x = lighting_max_d; + } + + // Node position in 2d + v2s16 p2d = sectorpos_base*MAP_BLOCKSIZE + v2s16(x,z); + + // Loop from top to down + { + u8 light = LIGHT_SUN; + v3s16 em = vmanip.m_area.getExtent(); + s16 y_start = y_nodes_max; + u32 i = vmanip.m_area.index(v3s16(p2d.X, y_start, p2d.Y)); + for(s16 y=y_start; y>=y_nodes_min; y--) + { + MapNode *n = &vmanip.m_data[i]; + if(light_propagates_content(n->d) == false) + { + light = 0; + } + else if(light != LIGHT_SUN + || sunlight_propagates_content(n->d) == false) + { + if(light > 0) + light--; + } + + n->setLight(LIGHTBANK_DAY, light); + n->setLight(LIGHTBANK_NIGHT, 0); + + if(light != 0) + { + // Insert light source + light_sources.insert(v3s16(p2d.X, y, p2d.Y), true); + } + + // Increment index by y + vmanip.m_area.add_y(em, i, -1); } } } @@ -3222,7 +3343,7 @@ MapChunk* ServerMap::generateChunkRaw(v2s16 chunkpos, for(s16 z=0-max_spread_amount+1; z=y_nodes_min; y--) + { + MapNode *n = &vmanip.m_data[i]; + + if(light_propagates_content(n->d) == false) + { + light = 0; + } + else if(light != LIGHT_SUN + || sunlight_propagates_content(n->d) == false) + { + if(light > 0) + light--; + } + + n->setLight(LIGHTBANK_DAY, light); + n->setLight(LIGHTBANK_NIGHT, 0); + + // This doesn't take much time + if(light != 0) + { + // Insert light source + light_sources.insert(v3s16(p2d.X, y, p2d.Y), true); + } + + // Increment index by y + vmanip.m_area.add_y(em, i, -1); + } + } + } +#endif }//timer1 @@ -4006,7 +4179,7 @@ continue_generating: /* Add coal */ - u16 coal_amount = 30.0 * g_settings.getFloat("coal_amount"); + u16 coal_amount = 30; u16 coal_rareness = 60 / coal_amount; if(coal_rareness == 0) coal_rareness = 1; @@ -4039,7 +4212,7 @@ continue_generating: Add iron */ //TODO: change to iron_amount or whatever - u16 iron_amount = 30.0 * g_settings.getFloat("coal_amount"); + u16 iron_amount = 15; u16 iron_rareness = 60 / iron_amount; if(iron_rareness == 0) iron_rareness = 1; @@ -4286,16 +4459,6 @@ MapBlock * ServerMap::emergeBlock( } } - /* - Debug mode operation - */ - bool haxmode = g_settings.getBool("haxmode"); - if(haxmode) - { - // Don't calculate lighting at all - //lighting_invalidated_blocks.clear(); - } - return block; } diff --git a/src/noise.h b/src/noise.h index ee73aa3e..c069046c 100644 --- a/src/noise.h +++ b/src/noise.h @@ -20,6 +20,8 @@ with this program; if not, write to the Free Software Foundation, Inc., #ifndef NOISE_HEADER #define NOISE_HEADER +double easeCurve(double t); + // Return value: -1 ... 1 double noise2d(int x, int y, int seed); diff --git a/src/player.cpp b/src/player.cpp index 1a553157..9817d590 100644 --- a/src/player.cpp +++ b/src/player.cpp @@ -274,10 +274,12 @@ void LocalPlayer::move(f32 dtime, Map &map) position += m_speed * dtime; - bool haxmode = g_settings.getBool("haxmode"); + bool free_move = g_settings.getBool("free_move"); + bool terrain_viewer = g_settings.getBool("terrain_viewer"); - // Skip collision detection if player is non-local - if(isLocal() == false || haxmode) + // Skip collision detection if player is non-local or + // a special movement mode is used + if(isLocal() == false || free_move || terrain_viewer) { setPosition(position); return; @@ -445,39 +447,55 @@ void LocalPlayer::applyControl(float dtime) v3f speed = v3f(0,0,0); - bool haxmode = g_settings.getBool("haxmode"); - - if(haxmode) + bool free_move = g_settings.getBool("free_move"); + bool fast_move = g_settings.getBool("fast_move"); + bool continuous_forward = g_settings.getBool("continuous_forward"); + + if(free_move) { v3f speed = getSpeed(); speed.Y = 0; setSpeed(speed); } - // Superspeed mode + // Whether superspeed mode is used or not bool superspeed = false; - if(control.superspeed) + + // If free movement and fast movement, always move fast + if(free_move && fast_move) + superspeed = true; + + // Auxiliary button 1 (E) + if(control.aux1) { - if(haxmode) + if(free_move) { + // In free movement mode, aux1 descends v3f speed = getSpeed(); - speed.Y = -20*BS; + if(fast_move) + speed.Y = -20*BS; + else + speed.Y = -walkspeed_max; setSpeed(speed); } else { + // If not free movement but fast is allowed, aux1 is // "Turbo button" - /*speed += move_direction; - superspeed = true;*/ + if(fast_move) + superspeed = true; } } - if(haxmode) - superspeed = true; + if(continuous_forward) + speed += move_direction; if(control.up) { - speed += move_direction; + if(continuous_forward) + superspeed = true; + else + speed += move_direction; } if(control.down) { @@ -493,13 +511,13 @@ void LocalPlayer::applyControl(float dtime) } if(control.jump) { - if(haxmode) + if(free_move) { v3f speed = getSpeed(); - /*speed.Y += 20.*BS * dtime * 2; - if(speed.Y < 0) - speed.Y = 0;*/ - speed.Y = 20*BS; + if(fast_move) + speed.Y = 20*BS; + else + speed.Y = walkspeed_max; setSpeed(speed); } else if(touching_ground) @@ -524,10 +542,11 @@ void LocalPlayer::applyControl(float dtime) speed = speed.normalize() * walkspeed_max; f32 inc = walk_acceleration * BS * dtime; - - if(haxmode) + + // Faster acceleration if fast and free movement + if(free_move && fast_move) inc = walk_acceleration * BS * dtime * 10; - + // Accelerate to target speed with maximum increment accelerate(speed, inc); } diff --git a/src/player.h b/src/player.h index 30df1db8..3bbb4034 100644 --- a/src/player.h +++ b/src/player.h @@ -263,7 +263,7 @@ struct PlayerControl left = false; right = false; jump = false; - superspeed = false; + aux1 = false; pitch = 0; yaw = 0; } @@ -273,7 +273,7 @@ struct PlayerControl bool a_left, bool a_right, bool a_jump, - bool a_superspeed, + bool a_aux1, float a_pitch, float a_yaw ) @@ -283,7 +283,7 @@ struct PlayerControl left = a_left; right = a_right; jump = a_jump; - superspeed = a_superspeed; + aux1 = a_aux1; pitch = a_pitch; yaw = a_yaw; } @@ -292,7 +292,7 @@ struct PlayerControl bool left; bool right; bool jump; - bool superspeed; + bool aux1; float pitch; float yaw; }; diff --git a/src/server.cpp b/src/server.cpp index a3baaf1a..71a094e1 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -326,8 +326,6 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime, } } - bool haxmode = g_settings.getBool("haxmode"); - Player *player = server->m_env.getPlayer(peer_id); assert(player != NULL); @@ -502,13 +500,6 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime, // If this is true, inexistent block will be made from scratch bool generate = d <= d_max_gen; - 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) @@ -572,31 +563,6 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime, continue; } -#if 0 - /* - NOTE: We can't know the ground level this way with the - new generator. - */ - if(haxmode) - { - /* - Ignore block if it is not at ground surface - but don't ignore water surface blocks - */ - 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 - && fabs(by - WATER_LEVEL) >= MAP_BLOCKSIZE) - continue; - } - } -#endif - /* Check if map has this block */ @@ -3204,16 +3170,6 @@ Player *Server::emergePlayer(const char *name, const char *password, setCreativeInventory(player); } - /* - With new map generator the map is regenerated anyway, - so start at somewhere where you probably don't get underground - */ - player->setPosition(intToFloat(v3s16( - 0, - 64, - 0 - ))); - return player; } @@ -3248,7 +3204,7 @@ Player *Server::emergePlayer(const char *name, const char *password, #if 1 player->setPosition(intToFloat(v3s16( 0, - 64, + 40, //64, 0 ))); #endif diff --git a/src/utility.h b/src/utility.h index ab5ecfca..10b7af63 100644 --- a/src/utility.h +++ b/src/utility.h @@ -585,15 +585,6 @@ inline bool isInArea(v3s16 p, v3s16 d) ); } -inline s16 rangelim(s16 i, s16 min, s16 max) -{ - if(i < min) - return min; - if(i > max) - return max; - return i; -} - inline s16 rangelim(s16 i, s16 max) { if(i < 0) @@ -603,6 +594,8 @@ inline s16 rangelim(s16 i, s16 max) return i; } +#define rangelim(d, min, max) ((d) < (min) ? (min) : ((d)>(max)?(max):(d))) + inline v3s16 arealim(v3s16 p, s16 d) { if(p.X < 0)