g_settings.setDefault("active_object_range", "2");
g_settings.setDefault("max_simultaneous_block_sends_per_client", "1");
g_settings.setDefault("max_simultaneous_block_sends_server_total", "4");
+ g_settings.setDefault("water_moves", "true");
g_settings.setDefault("disable_water_climb", "true");
g_settings.setDefault("endless_water", "true");
- g_settings.setDefault("max_block_send_distance", "5");
- g_settings.setDefault("max_block_generate_distance", "5");
+ g_settings.setDefault("max_block_send_distance", "6");
+ g_settings.setDefault("max_block_generate_distance", "6");
g_settings.setDefault("time_send_interval", "20");
g_settings.setDefault("time_speed", "96");
g_settings.setDefault("server_unload_unused_sectors_timeout", "60");
TODO: When server sees that client is removing an inexistent block or\r
adding a block to an existent position, resend the MapBlock.\r
\r
+TODO: Generate map from the area the client is looking at\r
+\r
Objects:\r
\r
TODO: Better handling of objects and mobs\r
video::E_DRIVER_TYPE driverType;\r
\r
#ifdef _WIN32\r
- //driverType = video::EDT_DIRECT3D9; // Doesn't seem to work\r
+ //driverType = video::EDT_DIRECT3D9;\r
driverType = video::EDT_OPENGL;\r
#else\r
driverType = video::EDT_OPENGL;\r
+ //driverType = video::EDT_BURNINGSVIDEO;\r
#endif\r
\r
// create device and exit if creation failed\r
*/
{
+ dstream<<"Generating map point attribute lists"<<std::endl;
+
PointAttributeList *list_baseheight = m_padb.getList("hm_baseheight");
PointAttributeList *list_randmax = m_padb.getList("hm_randmax");
PointAttributeList *list_randfactor = m_padb.getList("hm_randfactor");
PointAttributeList *list_plants_amount = m_padb.getList("plants_amount");
PointAttributeList *list_caves_amount = m_padb.getList("caves_amount");
+
+ /*
+ NOTE: BEWARE: Too big amount of these will make map generation
+ slow. Especially those that are read by every block emerge.
+ */
- for(u32 i=0; i<3000; i++)
+ for(u32 i=0; i<15000; i++)
{
- u32 lim = MAP_GENERATION_LIMIT;
- if(i < 200)
- lim = 1000;
+ /*u32 lim = MAP_GENERATION_LIMIT;
+ if(i < 400)
+ lim = 2000;*/
+
+ u32 lim = 1000 + MAP_GENERATION_LIMIT * i / 15000;
v3s16 p(
-lim + myrand()%(lim*2),
plants_amount = 0.0;
}
+
+ list_plants_amount->addPoint(p, Attribute(plants_amount));
+ }
+
+ for(u32 i=0; i<1000; i++)
+ {
+ /*u32 lim = MAP_GENERATION_LIMIT;
+ if(i < 400)
+ lim = 2000;*/
+
+ u32 lim = 500 + MAP_GENERATION_LIMIT * i / 1000;
+
+ v3s16 p(
+ -lim + myrand()%(lim*2),
+ 0,
+ -lim + myrand()%(lim*2)
+ );
+
float caves_amount = 0;
if(myrand()%5 == 0)
{
caves_amount = 0.05;
}
- list_plants_amount->addPoint(p, Attribute(plants_amount));
list_caves_amount->addPoint(p, Attribute(caves_amount));
}
-#if 1
- for(u32 i=0; i<3000; i++)
+
+ for(u32 i=0; i<5000; i++)
{
- u32 lim = MAP_GENERATION_LIMIT;
- if(i < 100)
- lim = 1000;
+ /*u32 lim = MAP_GENERATION_LIMIT;
+ if(i < 400)
+ lim = 2000;*/
+
+ u32 lim = 1000 + MAP_GENERATION_LIMIT * i / 5000;
v3s16 p(
- -lim + myrand()%(lim*2),
+ -lim + (myrand()%(lim*2)),
0,
- -lim + myrand()%(lim*2)
+ -lim + (myrand()%(lim*2))
);
/*s32 bh_i = (myrand()%200) - 50;
if(myrand()%4 == 0)
{
baseheight = 100;
- randmax = 100;
+ randmax = 50;
randfactor = 0.63;
}
- else if(myrand()%5 == 0)
+ else if(myrand()%6 == 0)
{
baseheight = 200;
- randmax = 200;
+ randmax = 100;
randfactor = 0.66;
}
else if(myrand()%4 == 0)
{
baseheight = 0;
randmax = 30;
- randfactor = 0.60;
+ randfactor = 0.63;
}
else
{
list_randmax->addPoint(p, Attribute(randmax));
list_randfactor->addPoint(p, Attribute(randfactor));
}
-#endif
/*list_baseheight->addPoint(v3s16(0,0,0), Attribute(5));
list_randmax->addPoint(v3s16(0,0,0), Attribute(20));
list_randfactor->addPoint(v3s16(0,0,0), Attribute(0.6));*/
- }
-
-#if 0
- {
- PointAttributeList *palist = m_padb.getList("hm_baseheight");
-
- {
- v3s16 p(0,0,0);
- Attribute attr;
- attr.set("5");
- palist->addPoint(p, attr);
- }
- /*{
- v3s16 p(-50,-50,0);
- Attribute attr;
- attr.set("-10");
- palist->addPoint(p, attr);
- }
-
- {
- v3s16 p(50,0,50);
- Attribute attr;
- attr.set("200");
- palist->addPoint(p, attr);
- }*/
+ // Easy spawn point
+ /*list_baseheight->addPoint(v3s16(0,0,0), Attribute(0));
+ list_randmax->addPoint(v3s16(0,0,0), Attribute(10));
+ list_randfactor->addPoint(v3s16(0,0,0), Attribute(0.65));*/
}
-#endif
-#if 0
- {
- PointAttributeList *palist = m_padb.getList("plants_amount");
-
- // Back
- {
- v3s16 p(0,0,-100);
- Attribute attr;
- attr.set("0");
- palist->addPoint(p, attr);
- }
-
- // Front right
- {
- v3s16 p(100,0,100);
- Attribute attr;
- attr.set("2.0");
- palist->addPoint(p, attr);
- }
-
- // Front left
- {
- v3s16 p(-100,0,100);
- Attribute attr;
- attr.set("0.2");
- palist->addPoint(p, attr);
- }
- }
-#endif
/*
Try to load map; if not found, create a new one.
Get local attributes
*/
+ //dstream<<"emergeSector(): Reading point attribute lists"<<std::endl;
+
// Get plant amount from attributes
PointAttributeList *palist = m_padb.getList("plants_amount");
assert(palist);
float local_plants_amount =
palist->getInterpolatedFloat(nodepos2d);
+ //dstream<<"emergeSector(): done."<<std::endl;
+
/*
Generate sector heightmap
*/
/*
Add ravine (randomly)
*/
- if(m_params.ravines_amount != 0)
+ if(m_params.ravines_amount > 0.001)
{
if(myrand()%(s32)(200.0 / m_params.ravines_amount) == 0)
{
bool some_part_underground = block_y * MAP_BLOCKSIZE <= highest_ground_y;
+ bool mostly_underwater_surface = false;
+ if(highest_ground_y < WATER_LEVEL
+ && some_part_underground && !completely_underground)
+ mostly_underwater_surface = true;
+
/*
Get local attributes
*/
+
+ //dstream<<"emergeBlock(): Getting local attributes"<<std::endl;
+
+ float caves_amount = 0;
- v2s16 nodepos2d = p2d * MAP_BLOCKSIZE;
- PointAttributeList *list_caves_amount = m_padb.getList("caves_amount");
- float caves_amount = list_caves_amount->getInterpolatedFloat(nodepos2d);
+ {
+ /*
+ NOTE: BEWARE: Too big amount of attribute points slows verything
+ down by a lot.
+ 1 interpolation from 5000 points takes 2-3ms.
+ */
+ //TimeTaker timer("emergeBlock() local attribute retrieval");
+ v2s16 nodepos2d = p2d * MAP_BLOCKSIZE;
+ PointAttributeList *list_caves_amount = m_padb.getList("caves_amount");
+ caves_amount = list_caves_amount->getInterpolatedFloat(nodepos2d);
+ }
+
+ //dstream<<"emergeBlock(): Done"<<std::endl;
/*
Generate dungeons
}
// Fill table
+#if 1
{
/*
Initialize orp and ors. Try to find if some neighboring
continue_generating:
/*
- Don't always generate dungeon
+ Choose whether to actually generate dungeon
*/
bool do_generate_dungeons = true;
// Don't generate if no part is underground
if(!some_part_underground)
+ {
do_generate_dungeons = false;
- // If block is partly underground, caves are generated.
+ }
+ // Don't generate if mostly underwater surface
+ else if(mostly_underwater_surface)
+ {
+ do_generate_dungeons = false;
+ }
+ // Partly underground = cave
else if(!completely_underground)
- do_generate_dungeons = (rand() % 100 <= (u32)(caves_amount*100));
- // Always continue if found existing dungeons underground
+ {
+ do_generate_dungeons = (rand() % 100 <= (s32)(caves_amount*100));
+ }
+ // Found existing dungeon underground
else if(found_existing && completely_underground)
- do_generate_dungeons = true;
- // If underground and no dungeons found
+ {
+ do_generate_dungeons = (rand() % 100 <= (s32)(caves_amount*100));
+ }
+ // Underground and no dungeons found
else
- do_generate_dungeons = (rand() % 2 == 0);
+ {
+ do_generate_dungeons = (rand() % 300 <= (s32)(caves_amount*100));
+ }
if(do_generate_dungeons)
{
}
}
}
+#endif
// Set to true if has caves.
// Set when some non-air is changed to air when making caves.
- bool has_caves = false;
+ bool has_dungeons = false;
/*
Apply temporary cave data to block
if(is_ground_content(n.d))
{
// Has now caves
- has_caves = true;
+ has_dungeons = true;
// Set air to node
n.d = CONTENT_AIR;
}
Force lighting update if some part of block is partly
underground and has caves.
*/
- /*if(some_part_underground && !completely_underground && has_caves)
+ /*if(some_part_underground && !completely_underground && has_dungeons)
{
//dstream<<"Half-ground caves"<<std::endl;
lighting_invalidated_blocks[block->getPos()] = block;
/*
Add meseblocks
*/
- for(s16 i=0; i< underground_level/4 + 1; i++)
+ for(s16 i=0; i<underground_level/4 + 1; i++)
{
- if(myrand()%10 == 0)
+ if(myrand()%50 == 0)
{
v3s16 cp(
(myrand()%(MAP_BLOCKSIZE-2))+1,
changed_blocks.insert(block->getPos(), block);
}
-
+
+ /*
+ Debug information
+ */
+ if(0)
+ {
+ dstream
+ <<"lighting_invalidated_blocks.size()"
+ <<", has_dungeons"
+ <<", completely_ug"
+ <<", some_part_ug"
+ <<" "<<lighting_invalidated_blocks.size()
+ <<", "<<has_dungeons
+ <<", "<<completely_underground
+ <<", "<<some_part_underground
+ <<std::endl;
+ }
+
+ /*
+ Debug mode operation
+ */
if(HAXMODE)
{
// Don't calculate lighting at all
if not seen on display
*/
+ float range = 100000 * BS;
+ if(m_control.range_all == false)
+ range = m_control.wanted_range * BS;
+
+ if(isBlockInSight(block->getPos(), camera_position,
+ camera_direction, range) == false)
+ {
+ continue;
+ }
+
+#if 0
v3s16 blockpos_nodes = block->getPosRelative();
// Block center position
{
// If block is far away, don't draw it
if(d > m_control.wanted_range * BS)
- // This is nicer when fog is used
- //if((dforward+d)/2 > m_control.wanted_range * BS)
continue;
}
if(cosangle < cos(FOV_ANGLE/2. * 4./3.))
continue;
}
+#endif
+
+ v3s16 blockpos_nodes = block->getPosRelative();
+ // Block center position
+ v3f blockpos(
+ ((float)blockpos_nodes.X + MAP_BLOCKSIZE/2) * BS,
+ ((float)blockpos_nodes.Y + MAP_BLOCKSIZE/2) * BS,
+ ((float)blockpos_nodes.Z + MAP_BLOCKSIZE/2) * BS
+ );
+
+ // Block position relative to camera
+ v3f blockpos_relative = blockpos - camera_position;
+
+ // Total distance
+ f32 d = blockpos_relative.getLength();
+
/*
Draw the faces of the block
*/
their differing fetch methods.
*/
virtual MapSector * emergeSector(v2s16 p) = 0;
-
+
// Returns InvalidPositionException if not found
MapBlock * getBlockNoCreate(v3s16 p);
// Returns NULL if not found
DiggingProperties(true, 15.0*toughness, 0));
g_material_properties[material].setDiggingProperties("WPick",
- DiggingProperties(true, 1.5*toughness, 65535./20.*toughness));
+ DiggingProperties(true, 1.5*toughness, 65535./30.*toughness));
g_material_properties[material].setDiggingProperties("STPick",
- DiggingProperties(true, 0.7*toughness, 65535./60.*toughness));
+ DiggingProperties(true, 0.7*toughness, 65535./100.*toughness));
/*g_material_properties[material].setDiggingProperties("MesePick",
DiggingProperties(true, 0.0*toughness, 65535./20.*toughness));*/
// Y direction is ignored
void Player::accelerate(v3f target_speed, f32 max_increase)
{
+ v3f d_wanted = target_speed - m_speed;
+ d_wanted.Y = 0;
+ f32 dl_wanted = d_wanted.getLength();
+ f32 dl = dl_wanted;
+ if(dl > max_increase)
+ dl = max_increase;
+
+ v3f d = d_wanted.normalize() * dl;
+
+ m_speed.X += d.X;
+ m_speed.Z += d.Z;
+ //m_speed += d;
+
+#if 0 // old code
if(m_speed.X < target_speed.X - max_increase)
m_speed.X += max_increase;
else if(m_speed.X > target_speed.X + max_increase)
m_speed.Z = target_speed.Z;
else if(m_speed.Z > target_speed.Z)
m_speed.Z = target_speed.Z;
+#endif
}
/*
position += m_speed * dtime;
// Skip collision detection if player is non-local
- if(isLocal() == false)
+ if(isLocal() == false || HAXMODE)
{
setPosition(position);
return;
{
// Doing nothing here will block the player from
// walking over map borders
-
- // Go over borders in debug mode
- if(HAXMODE)
- continue;
}
core::aabbox3d<f32> nodebox = Map::getNodeBox(
v3s16 center_nodepos = floatToInt(playerpos);
v3s16 center = getNodeBlockPos(center_nodepos);
+
+ // Camera position and direction
+ v3f camera_pos =
+ playerpos + v3f(0, BS+BS/2, 0);
+ v3f camera_dir = v3f(0,0,1);
+ camera_dir.rotateYZBy(player->getPitch());
+ camera_dir.rotateXZBy(player->getYaw());
/*
Get the starting value of the block finder radius.
if(abs(p.Y - center.Y) > d_max_gen - d_max_gen / 3)
generate = false;
}
+
+ /*
+ Don't draw if not in sight
+ */
+
+ if(isBlockInSight(p, camera_pos, camera_dir, 10000*BS) == false)
+ {
+ continue;
+ }
/*
Don't send already sent blocks
{
/*
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);
if(y > GROUNDHEIGHT_VALID_MINVALUE)
{
f32 by = p.Y*MAP_BLOCKSIZE + MAP_BLOCKSIZE/2;
- if(fabs(by - y) > MAP_BLOCKSIZE + MAP_BLOCKSIZE/3)
+ if(fabs(by - y) > MAP_BLOCKSIZE + MAP_BLOCKSIZE/3
+ && fabs(by - WATER_LEVEL) >= MAP_BLOCKSIZE)
continue;
}
}
if(m_blocks_sending.find(p) != NULL)
m_blocks_sending.remove(p);
else
- dstream<<"RemoteClient::GotBlock(): Didn't find in"
- " m_blocks_sending"<<std::endl;
+ {
+ /*dstream<<"RemoteClient::GotBlock(): Didn't find in"
+ " m_blocks_sending"<<std::endl;*/
+ m_excess_gotblocks++;
+ }
m_blocks_sent.insert(p, true);
}
/*
Flow water
*/
+ if(g_settings.getBool("water_moves") == true)
{
float interval;
v2s16 nodepos;
f32 groundheight = 0;
// Try to find a good place a few times
- for(s32 i=0; i<100; i++)
+ for(s32 i=0; i<500; i++)
{
- s32 range = 1 + i*4;
+ s32 range = 1 + i;
// We're going to try to throw the player to this position
- nodepos = v2s16(-range/2 + (myrand()%range),
- -range/2 + (myrand()%range));
+ nodepos = v2s16(-range + (myrand()%(range*2)),
+ -range + (myrand()%(range*2)));
v2s16 sectorpos = getNodeSectorPos(nodepos);
// Get sector
m_env.getMap().emergeSector(sectorpos);
assert(groundheight > GROUNDHEIGHT_VALID_MINVALUE);
// Don't go underwater
if(groundheight < WATER_LEVEL)
+ {
+ //dstream<<"-> Underwater"<<std::endl;
continue;
+ }
+#if 0 // Doesn't work, generating blocks is a bit too complicated for doing here
+ // Get block at point
+ v3s16 nodepos3d;
+ nodepos3d = v3s16(nodepos.X, groundheight+1, nodepos.Y);
+ v3s16 blockpos = getNodeBlockPos(nodepos3d);
+ ((ServerMap*)(&m_env.getMap()))->emergeBlock(blockpos);
// Don't go inside ground
try{
- v3s16 footpos(nodepos.X, groundheight+1, nodepos.Y);
- v3s16 headpos(nodepos.X, groundheight+2, nodepos.Y);
+ /*v3s16 footpos(nodepos.X, groundheight+1, nodepos.Y);
+ v3s16 headpos(nodepos.X, groundheight+2, nodepos.Y);*/
+ v3s16 footpos = nodepos3d + v3s16(0,0,0);
+ v3s16 headpos = nodepos3d + v3s16(0,1,0);
if(m_env.getMap().getNode(footpos).d != CONTENT_AIR
|| m_env.getMap().getNode(headpos).d != CONTENT_AIR)
{
+ dstream<<"-> Inside ground"<<std::endl;
// In ground
continue;
}
}catch(InvalidPositionException &e)
{
+ dstream<<"-> Invalid position"<<std::endl;
// Ignore invalid position
continue;
}
+#endif
// Found a good place
+ dstream<<"Searched through "<<i<<" places."<<std::endl;
break;
}
#endif
u8 pending_serialization_version;
RemoteClient():
- m_time_from_building(9999)
+ m_time_from_building(9999),
+ m_excess_gotblocks(0)
{
peer_id = 0;
serialization_version = SER_FMT_VER_INVALID;
<<", m_blocks_sent.size()="<<m_blocks_sent.size()
<<", m_blocks_sending.size()="<<m_blocks_sending.size()
<<", m_nearest_unsent_d="<<m_nearest_unsent_d
+ <<", m_excess_gotblocks="<<m_excess_gotblocks
<<std::endl;
+ m_excess_gotblocks = 0;
}
// Time from last placing or removing blocks
*/
core::map<v3s16, float> m_blocks_sending;
JMutex m_blocks_sending_mutex;
+
+ /*
+ Count of excess GotBlocks().
+ There is an excess amount because the client sometimes
+ gets a block so late that the server sends it again,
+ and the client then sends two GOTBLOCKs.
+ This is resetted by PrintInfo()
+ */
+ u32 m_excess_gotblocks;
};
/*struct ServerSettings
padb.getList("hm_baseheight")->addPoint(v2s16(BS1*2,BS1), Attribute(0));
padb.getList("hm_randmax")->addPoint(v2s16(BS1*2,BS1), Attribute(30));
- padb.getList("hm_randfactor")->addPoint(v2s16(BS1*2,BS1), Attribute(0.9));
+ padb.getList("hm_randfactor")->addPoint(v2s16(BS1*2,BS1), Attribute(0.63));
UnlimitedHeightmap hm1(BS1, &padb);
#include "utility.h"
#include "irrlichtwrapper.h"
#include "gettime.h"
+#include "mapblock.h"
TimeTaker::TimeTaker(const char *name, u32 *result)
{
}
#endif
+/*
+ blockpos: position of block in block coordinates
+ camera_pos: position of camera in nodes
+ camera_dir: an unit vector pointing to camera direction
+ range: viewing range
+*/
+bool isBlockInSight(v3s16 blockpos_b, v3f camera_pos, v3f camera_dir, f32 range)
+{
+ v3s16 blockpos_nodes = blockpos_b * MAP_BLOCKSIZE;
+
+ // Block center position
+ v3f blockpos(
+ ((float)blockpos_nodes.X + MAP_BLOCKSIZE/2) * BS,
+ ((float)blockpos_nodes.Y + MAP_BLOCKSIZE/2) * BS,
+ ((float)blockpos_nodes.Z + MAP_BLOCKSIZE/2) * BS
+ );
+
+ // Block position relative to camera
+ v3f blockpos_relative = blockpos - camera_pos;
+
+ // Distance in camera direction (+=front, -=back)
+ f32 dforward = blockpos_relative.dotProduct(camera_dir);
+
+ // Total distance
+ f32 d = blockpos_relative.getLength();
+
+ // If block is far away, it's not in sight
+ if(d > range * BS)
+ return false;
+
+ // Maximum radius of a block
+ f32 block_max_radius = 0.5*1.44*1.44*MAP_BLOCKSIZE*BS;
+
+ // If block is (nearly) touching the camera, don't
+ // bother validating further (that is, render it anyway)
+ if(d > block_max_radius * 1.5)
+ {
+ // Cosine of the angle between the camera direction
+ // and the block direction (camera_dir is an unit vector)
+ f32 cosangle = dforward / d;
+
+ // Compensate for the size of the block
+ // (as the block has to be shown even if it's a bit off FOV)
+ // This is an estimate.
+ cosangle += block_max_radius / dforward;
+
+ // If block is not in the field of view, skip it
+ //if(cosangle < cos(FOV_ANGLE/2))
+ if(cosangle < cos(FOV_ANGLE/2. * 4./3.))
+ return false;
+ }
+
+ return true;
+}
core::map<std::string, PointAttributeList*> m_lists;
};
+/*
+ Miscellaneous functions
+*/
+
+bool isBlockInSight(v3s16 blockpos_b, v3f camera_pos, v3f camera_dir, f32 range);
+
+
#endif