master
Maksim Gamarnik 2016-02-23 00:40:02 +02:00
parent 40b3667bd2
commit be288f1c52
25 changed files with 643 additions and 496 deletions

View File

@ -214,12 +214,12 @@
# type: key
# keymap_camera_mode = KEY_F7
# Key for increasing the viewing range. Modifies the minimum viewing range.
# Key for increasing the viewing range.
# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
# type: key
# keymap_increase_viewing_range_min = +
# Key for decreasing the viewing range. Modifies the minimum viewing range.
# Key for decreasing the viewing range.
# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
# type: key
# keymap_decrease_viewing_range_min = -
@ -335,12 +335,6 @@
# type: int
# texture_min_size = 64
# Pre-generate all item visuals used in the inventory.
# This increases startup time, but runs smoother in-game.
# The generated textures can easily exceed your VRAM, causing artifacts in the inventory.
# type: bool
# preload_item_visuals = false
# Experimental option, might cause visible spaces between blocks
# when set to higher number than 0.
# type: enum values: 0, 1, 2, 4, 8, 16
@ -437,11 +431,6 @@
#### Advanced
# Minimum wanted FPS.
# The amount of rendered stuff is dynamically set according to this. and viewing range min and max.
# type: int
# wanted_fps = 30
# If FPS would go higher than this, limit it by sleeping
# to not waste CPU power for no benefit.
# type: int
@ -451,15 +440,10 @@
# type: int
# pause_fps_max = 20
# The allowed adjustment range for the automatic rendering range adjustment.
# Set this to be equal to viewing range minimum to disable the auto-adjustment algorithm.
# View range in nodes.
# Min = 20.
# type: int
# viewing_range_nodes_max = 160
# The allowed adjustment range for the automatic rendering range adjustment.
# Set this to be equal to viewing range maximum to disable the auto-adjustment algorithm.
# type: int
# viewing_range_nodes_min = 35
# viewing_range = 100
# Width component of the initial window size.
# type: int

View File

@ -60,13 +60,6 @@ Camera::Camera(scene::ISceneManager* smgr, MapDrawControl& draw_control,
m_fov_x(1.0),
m_fov_y(1.0),
m_added_busytime(0),
m_added_frames(0),
m_range_old(0),
m_busytime_old(0),
m_frametime_counter(0),
m_time_per_range(30. / 50), // a sane default of 30ms per 50 nodes of range
m_view_bobbing_anim(0),
m_view_bobbing_state(0),
m_view_bobbing_speed(0),
@ -109,7 +102,6 @@ Camera::Camera(scene::ISceneManager* smgr, MapDrawControl& draw_control,
*/
m_cache_fall_bobbing_amount = g_settings->getFloat("fall_bobbing_amount");
m_cache_view_bobbing_amount = g_settings->getFloat("view_bobbing_amount");
m_cache_wanted_fps = g_settings->getFloat("wanted_fps");
m_cache_fov = g_settings->getFloat("fov");
m_cache_view_bobbing = g_settings->getBool("view_bobbing");
m_nametags.clear();
@ -455,8 +447,8 @@ void Camera::update(LocalPlayer* player, f32 frametime, f32 busytime,
m_wieldnode->setColor(player->light_color);
// Render distance feedback loop
updateViewingRange(frametime, busytime);
// Set render distance
updateViewingRange();
// If the player is walking, swimming, or climbing,
// view bobbing is enabled and free_move is off,
@ -484,143 +476,16 @@ void Camera::update(LocalPlayer* player, f32 frametime, f32 busytime,
}
}
void Camera::updateViewingRange(f32 frametime_in, f32 busytime_in)
void Camera::updateViewingRange()
{
if (m_draw_control.range_all)
return;
m_added_busytime += busytime_in;
m_added_frames += 1;
m_frametime_counter -= frametime_in;
if (m_frametime_counter > 0)
return;
m_frametime_counter = 0.2; // Same as ClientMap::updateDrawList interval
/*dstream<<FUNCTION_NAME
<<": Collected "<<m_added_frames<<" frames, total of "
<<m_added_busytime<<"s."<<std::endl;
dstream<<"m_draw_control.blocks_drawn="
<<m_draw_control.blocks_drawn
<<", m_draw_control.blocks_would_have_drawn="
<<m_draw_control.blocks_would_have_drawn
<<std::endl;*/
// Get current viewing range and FPS settings
f32 viewing_range_min = g_settings->getFloat("viewing_range_nodes_min");
viewing_range_min = MYMAX(15.0, viewing_range_min);
f32 viewing_range_max = g_settings->getFloat("viewing_range_nodes_max");
viewing_range_max = MYMAX(viewing_range_min, viewing_range_max);
// Immediately apply hard limits
if(m_draw_control.wanted_range < viewing_range_min)
m_draw_control.wanted_range = viewing_range_min;
if(m_draw_control.wanted_range > viewing_range_max)
m_draw_control.wanted_range = viewing_range_max;
// Just so big a value that everything rendered is visible
// Some more allowance than viewing_range_max * BS because of clouds,
// active objects, etc.
if(viewing_range_max < 200*BS)
m_cameranode->setFarValue(200 * BS * 10);
else
m_cameranode->setFarValue(viewing_range_max * BS * 10);
f32 wanted_fps = m_cache_wanted_fps;
wanted_fps = MYMAX(wanted_fps, 1.0);
f32 wanted_frametime = 1.0 / wanted_fps;
m_draw_control.wanted_min_range = viewing_range_min;
m_draw_control.wanted_max_blocks = (2.0*m_draw_control.blocks_would_have_drawn)+1;
if (m_draw_control.wanted_max_blocks < 10)
m_draw_control.wanted_max_blocks = 10;
f32 block_draw_ratio = 1.0;
if (m_draw_control.blocks_would_have_drawn != 0)
{
block_draw_ratio = (f32)m_draw_control.blocks_drawn
/ (f32)m_draw_control.blocks_would_have_drawn;
}
// Calculate the average frametime in the case that all wanted
// blocks had been drawn
f32 frametime = m_added_busytime / m_added_frames / block_draw_ratio;
m_added_busytime = 0.0;
m_added_frames = 0;
f32 wanted_frametime_change = wanted_frametime - frametime;
//dstream<<"wanted_frametime_change="<<wanted_frametime_change<<std::endl;
g_profiler->avg("wanted_frametime_change", wanted_frametime_change);
// If needed frametime change is small, just return
// This value was 0.4 for many months until 2011-10-18 by c55;
if (fabs(wanted_frametime_change) < wanted_frametime*0.33)
{
//dstream<<"ignoring small wanted_frametime_change"<<std::endl;
if (m_draw_control.range_all) {
m_cameranode->setFarValue(100000.0);
return;
}
f32 range = m_draw_control.wanted_range;
f32 new_range = range;
f32 d_range = range - m_range_old;
f32 d_busytime = busytime_in - m_busytime_old;
if (d_range != 0)
{
m_time_per_range = d_busytime / d_range;
}
//dstream<<"time_per_range="<<m_time_per_range<<std::endl;
g_profiler->avg("time_per_range", m_time_per_range);
// The minimum allowed calculated frametime-range derivative:
// Practically this sets the maximum speed of changing the range.
// The lower this value, the higher the maximum changing speed.
// A low value here results in wobbly range (0.001)
// A low value can cause oscillation in very nonlinear time/range curves.
// A high value here results in slow changing range (0.0025)
// SUGG: This could be dynamically adjusted so that when
// the camera is turning, this is lower
//f32 min_time_per_range = 0.0010; // Up to 0.4.7
f32 min_time_per_range = 0.0005;
if(m_time_per_range < min_time_per_range)
{
m_time_per_range = min_time_per_range;
//dstream<<"m_time_per_range="<<m_time_per_range<<" (min)"<<std::endl;
}
else
{
//dstream<<"m_time_per_range="<<m_time_per_range<<std::endl;
}
f32 wanted_range_change = wanted_frametime_change / m_time_per_range;
// Dampen the change a bit to kill oscillations
//wanted_range_change *= 0.9;
//wanted_range_change *= 0.75;
wanted_range_change *= 0.5;
//dstream<<"wanted_range_change="<<wanted_range_change<<std::endl;
// If needed range change is very small, just return
if(fabs(wanted_range_change) < 0.001)
{
//dstream<<"ignoring small wanted_range_change"<<std::endl;
return;
}
new_range += wanted_range_change;
//f32 new_range_unclamped = new_range;
new_range = MYMAX(new_range, viewing_range_min);
new_range = MYMIN(new_range, viewing_range_max);
/*dstream<<"new_range="<<new_range_unclamped
<<", clamped to "<<new_range<<std::endl;*/
m_range_old = m_draw_control.wanted_range;
m_busytime_old = busytime_in;
m_draw_control.wanted_range = new_range;
f32 viewing_range = g_settings->getFloat("viewing_range");
m_draw_control.wanted_range = viewing_range;
m_cameranode->setFarValue((viewing_range < 2000) ? 2000 * BS : viewing_range * BS);
}
void Camera::setDigging(s32 button)
@ -675,8 +540,7 @@ void Camera::drawNametags()
i = m_nametags.begin();
i != m_nametags.end(); ++i) {
Nametag *nametag = *i;
v3f pos = nametag->parent_node->getPosition() -
intToFloat(m_camera_offset, BS) + v3f(0.0, 1.1 * BS, 0.0);
v3f pos = nametag->parent_node->getPosition() + v3f(0.0, 1.1 * BS, 0.0);
f32 transformed_pos[4] = { pos.X, pos.Y, pos.Z, 1.0f };
trans.multiplyWith1x4Matrix(transformed_pos);
if (transformed_pos[3] > 0) {

View File

@ -136,8 +136,8 @@ public:
void update(LocalPlayer* player, f32 frametime, f32 busytime,
f32 tool_reload_ratio, ClientEnvironment &c_env);
// Render distance feedback loop
void updateViewingRange(f32 frametime_in, f32 busytime_in);
// Update render distance
void updateViewingRange();
// Start digging animation
// Pass 0 for left click, 1 for right click
@ -172,6 +172,9 @@ public:
void removeNametag(Nametag *nametag);
std::list<Nametag *> *getNametags()
{ return &m_nametags; }
void drawNametags();
private:
@ -201,14 +204,6 @@ private:
f32 m_fov_x;
f32 m_fov_y;
// Stuff for viewing range calculations
f32 m_added_busytime;
s16 m_added_frames;
f32 m_range_old;
f32 m_busytime_old;
f32 m_frametime_counter;
f32 m_time_per_range;
// View bobbing animation frame (0 <= m_view_bobbing_anim < 1)
f32 m_view_bobbing_anim;
// If 0, view bobbing is off (e.g. player is standing).
@ -235,7 +230,6 @@ private:
f32 m_cache_fall_bobbing_amount;
f32 m_cache_view_bobbing_amount;
f32 m_cache_wanted_fps;
f32 m_cache_fov;
bool m_cache_view_bobbing;

View File

@ -1766,29 +1766,6 @@ void Client::afterContentReceived(IrrlichtDevice *device)
m_nodedef->updateTextures(this, texture_update_progress, &tu_args);
delete[] tu_args.text_base;
// Preload item textures and meshes if configured to
if(g_settings->getBool("preload_item_visuals"))
{
verbosestream<<"Updating item textures and meshes"<<std::endl;
text = wgettext("Item textures...");
draw_load_screen(text, device, guienv, 0, 0);
std::set<std::string> names = m_itemdef->getAll();
size_t size = names.size();
size_t count = 0;
int percent = 0;
for(std::set<std::string>::const_iterator
i = names.begin(); i != names.end(); ++i)
{
// Asking for these caches the result
m_itemdef->getInventoryTexture(*i, this);
m_itemdef->getWieldMesh(*i, this);
count++;
percent = (count * 100 / size * 0.2) + 80;
draw_load_screen(text, device, guienv, 0, percent);
}
delete[] text;
}
// Start mesh update thread after setting up content definitions
infostream<<"- Starting mesh update thread"<<std::endl;
m_mesh_update_thread.start();

View File

@ -391,7 +391,7 @@ void RemoteClient::SentBlock(v3s16 p)
void RemoteClient::SetBlockNotSent(v3s16 p)
{
m_nearest_unsent_d = 0;
m_nothing_to_send_pause_timer = 0.1;
m_nothing_to_send_pause_timer = 0;
if(m_blocks_sending.find(p) != m_blocks_sending.end())
m_blocks_sending.erase(p);
@ -402,7 +402,7 @@ void RemoteClient::SetBlockNotSent(v3s16 p)
void RemoteClient::SetBlocksNotSent(std::map<v3s16, MapBlock*> &blocks)
{
m_nearest_unsent_d = 0;
m_nothing_to_send_pause_timer=0.1;
m_nothing_to_send_pause_timer = 0;
for(std::map<v3s16, MapBlock*>::iterator
i = blocks.begin();

View File

@ -141,6 +141,33 @@ static bool isOccluded(Map *map, v3s16 p0, v3s16 p1, float step, float stepfac,
return false;
}
void ClientMap::getBlocksInViewRange(v3s16 cam_pos_nodes,
v3s16 *p_blocks_min, v3s16 *p_blocks_max)
{
v3s16 box_nodes_d = m_control.wanted_range * v3s16(1, 1, 1);
// Define p_nodes_min/max as v3s32 because 'cam_pos_nodes -/+ box_nodes_d'
// can exceed the range of v3s16 when a large view range is used near the
// world edges.
v3s32 p_nodes_min(
cam_pos_nodes.X - box_nodes_d.X,
cam_pos_nodes.Y - box_nodes_d.Y,
cam_pos_nodes.Z - box_nodes_d.Z);
v3s32 p_nodes_max(
cam_pos_nodes.X + box_nodes_d.X,
cam_pos_nodes.Y + box_nodes_d.Y,
cam_pos_nodes.Z + box_nodes_d.Z);
// Take a fair amount as we will be dropping more out later
// Umm... these additions are a bit strange but they are needed.
*p_blocks_min = v3s16(
p_nodes_min.X / MAP_BLOCKSIZE - 3,
p_nodes_min.Y / MAP_BLOCKSIZE - 3,
p_nodes_min.Z / MAP_BLOCKSIZE - 3);
*p_blocks_max = v3s16(
p_nodes_max.X / MAP_BLOCKSIZE + 1,
p_nodes_max.Y / MAP_BLOCKSIZE + 1,
p_nodes_max.Z / MAP_BLOCKSIZE + 1);
}
void ClientMap::updateDrawList(video::IVideoDriver* driver)
{
ScopeProfiler sp(g_profiler, "CM::updateDrawList()", SPT_AVG);
@ -148,10 +175,8 @@ void ClientMap::updateDrawList(video::IVideoDriver* driver)
INodeDefManager *nodemgr = m_gamedef->ndef();
for(std::map<v3s16, MapBlock*>::iterator
i = m_drawlist.begin();
i != m_drawlist.end(); ++i)
{
for (std::map<v3s16, MapBlock*>::iterator i = m_drawlist.begin();
i != m_drawlist.end(); ++i) {
MapBlock *block = i->second;
block->refDrop();
}
@ -167,19 +192,9 @@ void ClientMap::updateDrawList(video::IVideoDriver* driver)
camera_fov *= 1.2;
v3s16 cam_pos_nodes = floatToInt(camera_position, BS);
v3s16 box_nodes_d = m_control.wanted_range * v3s16(1,1,1);
v3s16 p_nodes_min = cam_pos_nodes - box_nodes_d;
v3s16 p_nodes_max = cam_pos_nodes + box_nodes_d;
// Take a fair amount as we will be dropping more out later
// Umm... these additions are a bit strange but they are needed.
v3s16 p_blocks_min(
p_nodes_min.X / MAP_BLOCKSIZE - 3,
p_nodes_min.Y / MAP_BLOCKSIZE - 3,
p_nodes_min.Z / MAP_BLOCKSIZE - 3);
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);
v3s16 p_blocks_min;
v3s16 p_blocks_max;
getBlocksInViewRange(cam_pos_nodes, &p_blocks_min, &p_blocks_max);
// Number of blocks in rendering range
u32 blocks_in_range = 0;
@ -199,19 +214,14 @@ void ClientMap::updateDrawList(video::IVideoDriver* driver)
// Distance to farthest drawn block
float farthest_drawn = 0;
for(std::map<v2s16, MapSector*>::iterator
si = m_sectors.begin();
si != m_sectors.end(); ++si)
{
for (std::map<v2s16, MapSector*>::iterator si = m_sectors.begin();
si != m_sectors.end(); ++si) {
MapSector *sector = si->second;
v2s16 sp = sector->getPos();
if(m_control.range_all == false)
{
if(sp.X < p_blocks_min.X
|| sp.X > p_blocks_max.X
|| sp.Y < p_blocks_min.Z
|| sp.Y > p_blocks_max.Z)
if (m_control.range_all == false) {
if (sp.X < p_blocks_min.X || sp.X > p_blocks_max.X ||
sp.Y < p_blocks_min.Z || sp.Y > p_blocks_max.Z)
continue;
}
@ -224,9 +234,8 @@ void ClientMap::updateDrawList(video::IVideoDriver* driver)
u32 sector_blocks_drawn = 0;
for(MapBlockVect::iterator i = sectorblocks.begin();
i != sectorblocks.end(); ++i)
{
for (MapBlockVect::iterator i = sectorblocks.begin();
i != sectorblocks.end(); ++i) {
MapBlock *block = *i;
/*
@ -238,16 +247,13 @@ void ClientMap::updateDrawList(video::IVideoDriver* driver)
block->mesh->updateCameraOffset(m_camera_offset);
float range = 100000 * BS;
if(m_control.range_all == false)
if (m_control.range_all == false)
range = m_control.wanted_range * BS;
float d = 0.0;
if(isBlockInSight(block->getPos(), camera_position,
camera_direction, camera_fov,
range, &d) == false)
{
if (!isBlockInSight(block->getPos(), camera_position,
camera_direction, camera_fov, range, &d))
continue;
}
// This is ugly (spherical distance limit?)
/*if(m_control.range_all == false &&
@ -262,7 +268,7 @@ void ClientMap::updateDrawList(video::IVideoDriver* driver)
{
//MutexAutoLock lock(block->mesh_mutex);
if(block->mesh == NULL){
if (block->mesh == NULL) {
blocks_in_range_without_mesh++;
continue;
}
@ -275,44 +281,41 @@ void ClientMap::updateDrawList(video::IVideoDriver* driver)
// No occlusion culling when free_move is on and camera is
// inside ground
bool occlusion_culling_enabled = true;
if(g_settings->getBool("free_move")){
if (g_settings->getBool("free_move")) {
MapNode n = getNodeNoEx(cam_pos_nodes);
if(n.getContent() == CONTENT_IGNORE ||
if (n.getContent() == CONTENT_IGNORE ||
nodemgr->get(n).solidness == 2)
occlusion_culling_enabled = false;
}
v3s16 cpn = block->getPos() * MAP_BLOCKSIZE;
cpn += v3s16(MAP_BLOCKSIZE/2, MAP_BLOCKSIZE/2, MAP_BLOCKSIZE/2);
float step = BS*1;
cpn += v3s16(MAP_BLOCKSIZE / 2, MAP_BLOCKSIZE / 2, MAP_BLOCKSIZE / 2);
float step = BS * 1;
float stepfac = 1.1;
float startoff = BS*1;
float endoff = -BS*MAP_BLOCKSIZE*1.42*1.42;
v3s16 spn = cam_pos_nodes + v3s16(0,0,0);
s16 bs2 = MAP_BLOCKSIZE/2 + 1;
float startoff = BS * 1;
float endoff = -BS*MAP_BLOCKSIZE * 1.42 * 1.42;
v3s16 spn = cam_pos_nodes + v3s16(0, 0, 0);
s16 bs2 = MAP_BLOCKSIZE / 2 + 1;
u32 needed_count = 1;
if(
occlusion_culling_enabled &&
isOccluded(this, spn, cpn + v3s16(0,0,0),
step, stepfac, startoff, endoff, needed_count, nodemgr) &&
isOccluded(this, spn, cpn + v3s16(bs2,bs2,bs2),
step, stepfac, startoff, endoff, needed_count, nodemgr) &&
isOccluded(this, spn, cpn + v3s16(bs2,bs2,-bs2),
step, stepfac, startoff, endoff, needed_count, nodemgr) &&
isOccluded(this, spn, cpn + v3s16(bs2,-bs2,bs2),
step, stepfac, startoff, endoff, needed_count, nodemgr) &&
isOccluded(this, spn, cpn + v3s16(bs2,-bs2,-bs2),
step, stepfac, startoff, endoff, needed_count, nodemgr) &&
isOccluded(this, spn, cpn + v3s16(-bs2,bs2,bs2),
step, stepfac, startoff, endoff, needed_count, nodemgr) &&
isOccluded(this, spn, cpn + v3s16(-bs2,bs2,-bs2),
step, stepfac, startoff, endoff, needed_count, nodemgr) &&
isOccluded(this, spn, cpn + v3s16(-bs2,-bs2,bs2),
step, stepfac, startoff, endoff, needed_count, nodemgr) &&
isOccluded(this, spn, cpn + v3s16(-bs2,-bs2,-bs2),
step, stepfac, startoff, endoff, needed_count, nodemgr)
)
{
if (occlusion_culling_enabled &&
isOccluded(this, spn, cpn + v3s16(0, 0, 0),
step, stepfac, startoff, endoff, needed_count, nodemgr) &&
isOccluded(this, spn, cpn + v3s16(bs2,bs2,bs2),
step, stepfac, startoff, endoff, needed_count, nodemgr) &&
isOccluded(this, spn, cpn + v3s16(bs2,bs2,-bs2),
step, stepfac, startoff, endoff, needed_count, nodemgr) &&
isOccluded(this, spn, cpn + v3s16(bs2,-bs2,bs2),
step, stepfac, startoff, endoff, needed_count, nodemgr) &&
isOccluded(this, spn, cpn + v3s16(bs2,-bs2,-bs2),
step, stepfac, startoff, endoff, needed_count, nodemgr) &&
isOccluded(this, spn, cpn + v3s16(-bs2,bs2,bs2),
step, stepfac, startoff, endoff, needed_count, nodemgr) &&
isOccluded(this, spn, cpn + v3s16(-bs2,bs2,-bs2),
step, stepfac, startoff, endoff, needed_count, nodemgr) &&
isOccluded(this, spn, cpn + v3s16(-bs2,-bs2,bs2),
step, stepfac, startoff, endoff, needed_count, nodemgr) &&
isOccluded(this, spn, cpn + v3s16(-bs2,-bs2,-bs2),
step, stepfac, startoff, endoff, needed_count, nodemgr)) {
blocks_occlusion_culled++;
continue;
}
@ -322,9 +325,9 @@ void ClientMap::updateDrawList(video::IVideoDriver* driver)
// Limit block count in case of a sudden increase
blocks_would_have_drawn++;
if(blocks_drawn >= m_control.wanted_max_blocks
&& m_control.range_all == false
&& d > m_control.wanted_min_range * BS)
if (blocks_drawn >= m_control.wanted_max_blocks &&
!m_control.range_all &&
d > m_control.wanted_range * BS)
continue;
// Add to set
@ -333,12 +336,12 @@ void ClientMap::updateDrawList(video::IVideoDriver* driver)
sector_blocks_drawn++;
blocks_drawn++;
if(d/BS > farthest_drawn)
farthest_drawn = d/BS;
if (d / BS > farthest_drawn)
farthest_drawn = d / BS;
} // foreach sectorblocks
if(sector_blocks_drawn != 0)
if (sector_blocks_drawn != 0)
m_last_drawn_sectors.insert(sp);
}
@ -348,9 +351,9 @@ void ClientMap::updateDrawList(video::IVideoDriver* driver)
g_profiler->avg("CM: blocks in range", blocks_in_range);
g_profiler->avg("CM: blocks occlusion culled", blocks_occlusion_culled);
if(blocks_in_range != 0)
if (blocks_in_range != 0)
g_profiler->avg("CM: blocks in range without mesh (frac)",
(float)blocks_in_range_without_mesh/blocks_in_range);
(float)blocks_in_range_without_mesh / blocks_in_range);
g_profiler->avg("CM: blocks drawn", blocks_drawn);
g_profiler->avg("CM: farthest drawn", farthest_drawn);
g_profiler->avg("CM: wanted max blocks", m_control.wanted_max_blocks);
@ -402,7 +405,7 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
bool is_transparent_pass = pass == scene::ESNRP_TRANSPARENT;
std::string prefix;
if(pass == scene::ESNRP_SOLID)
if (pass == scene::ESNRP_SOLID)
prefix = "CM: solid: ";
else
prefix = "CM: transparent: ";
@ -410,10 +413,8 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
/*
This is called two times per frame, reset on the non-transparent one
*/
if(pass == scene::ESNRP_SOLID)
{
if (pass == scene::ESNRP_SOLID)
m_last_drawn_sectors.clear();
}
/*
Get time for measuring timeout.
@ -439,22 +440,9 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
*/
v3s16 cam_pos_nodes = floatToInt(camera_position, BS);
v3s16 box_nodes_d = m_control.wanted_range * v3s16(1,1,1);
v3s16 p_nodes_min = cam_pos_nodes - box_nodes_d;
v3s16 p_nodes_max = cam_pos_nodes + box_nodes_d;
// Take a fair amount as we will be dropping more out later
// Umm... these additions are a bit strange but they are needed.
v3s16 p_blocks_min(
p_nodes_min.X / MAP_BLOCKSIZE - 3,
p_nodes_min.Y / MAP_BLOCKSIZE - 3,
p_nodes_min.Z / MAP_BLOCKSIZE - 3);
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);
v3s16 p_blocks_min;
v3s16 p_blocks_max;
getBlocksInViewRange(cam_pos_nodes, &p_blocks_min, &p_blocks_max);
u32 vertex_count = 0;
u32 meshbuffer_count = 0;
@ -475,27 +463,22 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
*/
{
ScopeProfiler sp(g_profiler, prefix+"drawing blocks", SPT_AVG);
ScopeProfiler sp(g_profiler, prefix + "drawing blocks", SPT_AVG);
MeshBufListList drawbufs;
for(std::map<v3s16, MapBlock*>::iterator
i = m_drawlist.begin();
i != m_drawlist.end(); ++i)
{
for (std::map<v3s16, MapBlock*>::iterator i = m_drawlist.begin();
i != m_drawlist.end(); ++i) {
MapBlock *block = i->second;
// If the mesh of the block happened to get deleted, ignore it
if(block->mesh == NULL)
if (block->mesh == NULL)
continue;
float d = 0.0;
if(isBlockInSight(block->getPos(), camera_position,
camera_direction, camera_fov,
100000*BS, &d) == false)
{
if (!isBlockInSight(block->getPos(), camera_position,
camera_direction, camera_fov, 100000 * BS, &d))
continue;
}
// Mesh animation
{
@ -503,24 +486,17 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
MapBlockMesh *mapBlockMesh = block->mesh;
assert(mapBlockMesh);
// Pretty random but this should work somewhat nicely
bool faraway = d >= BS*50;
bool faraway = d >= BS * 50;
//bool faraway = d >= m_control.wanted_range * BS;
if(mapBlockMesh->isAnimationForced() ||
!faraway ||
mesh_animate_count_far < (m_control.range_all ? 200 : 50))
{
bool animated = mapBlockMesh->animate(
faraway,
animation_time,
crack,
daynight_ratio);
if(animated)
if (mapBlockMesh->isAnimationForced() || !faraway ||
mesh_animate_count_far < (m_control.range_all ? 200 : 50)) {
bool animated = mapBlockMesh->animate(faraway, animation_time,
crack, daynight_ratio);
if (animated)
mesh_animate_count++;
if(animated && faraway)
if (animated && faraway)
mesh_animate_count_far++;
}
else
{
} else {
mapBlockMesh->decreaseAnimationForceTimer();
}
}
@ -538,7 +514,7 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
assert(mesh);
u32 c = mesh->getMeshBufferCount();
for(u32 i=0; i<c; i++)
for (u32 i = 0; i < c; i++)
{
scene::IMeshBuffer *buf = mesh->getMeshBuffer(i);
@ -550,11 +526,10 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
video::IMaterialRenderer* rnd =
driver->getMaterialRenderer(material.MaterialType);
bool transparent = (rnd && rnd->isTransparent());
if(transparent == is_transparent_pass)
{
if(buf->getVertexCount() == 0)
errorstream<<"Block ["<<analyze_block(block)
<<"] contains an empty meshbuf"<<std::endl;
if (transparent == is_transparent_pass) {
if (buf->getVertexCount() == 0)
errorstream << "Block [" << analyze_block(block)
<< "] contains an empty meshbuf" << std::endl;
drawbufs.add(buf);
}
}
@ -564,13 +539,13 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
std::vector<MeshBufList> &lists = drawbufs.lists;
int timecheck_counter = 0;
for(std::vector<MeshBufList>::iterator i = lists.begin();
for (std::vector<MeshBufList>::iterator i = lists.begin();
i != lists.end(); ++i) {
timecheck_counter++;
if(timecheck_counter > 50) {
if (timecheck_counter > 50) {
timecheck_counter = 0;
int time2 = time(0);
if(time2 > time1 + 4) {
if (time2 > time1 + 4) {
infostream << "ClientMap::renderMap(): "
"Rendering takes ages, returning."
<< std::endl;
@ -582,7 +557,7 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
driver->setMaterial(list.m);
for(std::vector<scene::IMeshBuffer*>::iterator j = list.bufs.begin();
for (std::vector<scene::IMeshBuffer*>::iterator j = list.bufs.begin();
j != list.bufs.end(); ++j) {
scene::IMeshBuffer *buf = *j;
driver->drawMeshBuffer(buf);
@ -594,18 +569,18 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
} // ScopeProfiler
// Log only on solid pass because values are the same
if(pass == scene::ESNRP_SOLID){
if (pass == scene::ESNRP_SOLID) {
g_profiler->avg("CM: animated meshes", mesh_animate_count);
g_profiler->avg("CM: animated meshes (far)", mesh_animate_count_far);
}
g_profiler->avg(prefix+"vertices drawn", vertex_count);
if(blocks_had_pass_meshbuf != 0)
g_profiler->avg(prefix+"meshbuffers per block",
(float)meshbuffer_count / (float)blocks_had_pass_meshbuf);
if(blocks_drawn != 0)
g_profiler->avg(prefix+"empty blocks (frac)",
(float)blocks_without_stuff / blocks_drawn);
g_profiler->avg(prefix + "vertices drawn", vertex_count);
if (blocks_had_pass_meshbuf != 0)
g_profiler->avg(prefix + "meshbuffers per block",
(float)meshbuffer_count / (float)blocks_had_pass_meshbuf);
if (blocks_drawn != 0)
g_profiler->avg(prefix + "empty blocks (frac)",
(float)blocks_without_stuff / blocks_drawn);
/*infostream<<"renderMap(): is_transparent_pass="<<is_transparent_pass
<<", rendered "<<vertex_count<<" vertices."<<std::endl;*/

View File

@ -30,9 +30,8 @@ struct MapDrawControl
{
MapDrawControl():
range_all(false),
wanted_range(50),
wanted_range(0),
wanted_max_blocks(0),
wanted_min_range(0),
blocks_drawn(0),
blocks_would_have_drawn(0),
farthest_drawn(0)
@ -44,8 +43,6 @@ struct MapDrawControl
float wanted_range;
// Maximum number of blocks to draw
u32 wanted_max_blocks;
// Blocks in this range are drawn regardless of number of blocks drawn
float wanted_min_range;
// Number of blocks rendered is written here by the renderer
u32 blocks_drawn;
// Number of blocks that would have been drawn in wanted_range
@ -120,6 +117,8 @@ public:
return m_box;
}
void getBlocksInViewRange(v3s16 cam_pos_nodes,
v3s16 *p_blocks_min, v3s16 *p_blocks_max);
void updateDrawList(video::IVideoDriver* driver);
void renderMap(video::IVideoDriver* driver, s32 pass);

View File

@ -235,7 +235,7 @@ collisionMoveResult collisionMoveSimple(Environment *env, IGameDef *gamedef,
std::vector<v3s16> node_positions;
{
//TimeTaker tt2("collisionMoveSimple collect boxes");
ScopeProfiler sp(g_profiler, "collisionMoveSimple collect boxes avg", SPT_AVG);
ScopeProfiler sp(g_profiler, "collisionMoveSimple collect boxes avg", SPT_AVG);
v3s16 oldpos_i = floatToInt(*pos_f, BS);
v3s16 newpos_i = floatToInt(*pos_f + *speed_f * dtime, BS);
@ -248,8 +248,9 @@ collisionMoveResult collisionMoveSimple(Environment *env, IGameDef *gamedef,
bool any_position_valid = false;
// The order is important here, must be y first
for(s16 y = max_y; y >= min_y; y--)
for(s16 x = min_x; x <= max_x; x++)
for(s16 y = min_y; y <= max_y; y++)
for(s16 z = min_z; z <= max_z; z++)
{
v3s16 p(x,y,z);
@ -382,13 +383,12 @@ collisionMoveResult collisionMoveSimple(Environment *env, IGameDef *gamedef,
while(dtime > BS * 1e-10) {
//TimeTaker tt3("collisionMoveSimple dtime loop");
ScopeProfiler sp(g_profiler, "collisionMoveSimple dtime loop avg", SPT_AVG);
ScopeProfiler sp(g_profiler, "collisionMoveSimple dtime loop avg", SPT_AVG);
// Avoid infinite loop
loopcount++;
if (loopcount >= 100) {
warningstream << "collisionMoveSimple: Loop count exceeded, aborting to avoid infiniite loop" << std::endl;
dtime = 0;
break;
}
@ -398,21 +398,23 @@ collisionMoveResult collisionMoveSimple(Environment *env, IGameDef *gamedef,
int nearest_collided = -1;
f32 nearest_dtime = dtime;
u32 nearest_boxindex = -1;
int nearest_boxindex = -1;
/*
Go through every nodebox, find nearest collision
*/
for (u32 boxindex = 0; boxindex < cboxes.size(); boxindex++) {
// Ignore if already stepped up this nodebox.
if(is_step_up[boxindex])
continue;
// Find nearest collision of the two boxes (raytracing-like)
f32 dtime_tmp;
int collided = axisAlignedCollision(
cboxes[boxindex], movingbox, *speed_f, d, &dtime_tmp);
// Ignore if already stepped up this nodebox.
if (is_step_up[boxindex]) {
pos_f->Y += (cboxes[boxindex].MaxEdge.Y - movingbox.MinEdge.Y);
continue;
}
if (collided == -1 || dtime_tmp >= nearest_dtime)
continue;
@ -462,10 +464,12 @@ collisionMoveResult collisionMoveSimple(Environment *env, IGameDef *gamedef,
is_collision = false;
CollisionInfo info;
if (is_object[nearest_boxindex])
if (is_object[nearest_boxindex]) {
info.type = COLLISION_OBJECT;
else
result.standing_on_object = true;
} else {
info.type = COLLISION_NODE;
}
info.node_p = node_positions[nearest_boxindex];
info.bouncy = bouncy;
@ -483,12 +487,13 @@ collisionMoveResult collisionMoveSimple(Environment *env, IGameDef *gamedef,
speed_f->X = 0;
result.collides = true;
result.collides_xz = true;
}
else if(nearest_collided == 1) { // Y
if (fabs(speed_f->Y) > BS * 3)
} else if(nearest_collided == 1) { // Y
if (fabs(speed_f->Y) > BS * 3) {
speed_f->Y *= bounce;
else
} else {
speed_f->Y = 0;
result.touching_ground = true;
}
result.collides = true;
} else if(nearest_collided == 2) { // Z
if (fabs(speed_f->Z) > BS * 3)
@ -509,43 +514,5 @@ collisionMoveResult collisionMoveSimple(Environment *env, IGameDef *gamedef,
}
}
/*
Final touches: Check if standing on ground, step up stairs.
*/
aabb3f box = box_0;
box.MinEdge += *pos_f;
box.MaxEdge += *pos_f;
for (u32 boxindex = 0; boxindex < cboxes.size(); boxindex++) {
const aabb3f& cbox = cboxes[boxindex];
/*
See if the object is touching ground.
Object touches ground if object's minimum Y is near node's
maximum Y and object's X-Z-area overlaps with the node's
X-Z-area.
Use 0.15*BS so that it is easier to get on a node.
*/
if (cbox.MaxEdge.X - d > box.MinEdge.X && cbox.MinEdge.X + d < box.MaxEdge.X &&
cbox.MaxEdge.Z - d > box.MinEdge.Z &&
cbox.MinEdge.Z + d < box.MaxEdge.Z) {
if (is_step_up[boxindex]) {
pos_f->Y += (cbox.MaxEdge.Y - box.MinEdge.Y);
box = box_0;
box.MinEdge += *pos_f;
box.MaxEdge += *pos_f;
}
if (fabs(cbox.MaxEdge.Y - box.MinEdge.Y) < 0.15 * BS) {
result.touching_ground = true;
if (is_object[boxindex])
result.standing_on_object = true;
if (is_unloaded[boxindex])
result.standing_on_unloaded = true;
}
}
}
return result;
}

View File

@ -88,12 +88,10 @@ void set_default_settings(Settings *settings)
#else
settings->setDefault("show_debug", "true");
#endif
settings->setDefault("wanted_fps", "20");
settings->setDefault("fps_max", "60");
settings->setDefault("pause_fps_max", "15");
// A bit more than the server will send around the player, to make fog blend well
settings->setDefault("viewing_range_nodes_max", "240");
settings->setDefault("viewing_range_nodes_min", "35");
settings->setDefault("viewing_range", "100");
settings->setDefault("map_generation_limit", "31000");
settings->setDefault("screenW", "800");
settings->setDefault("screenH", "600");
@ -159,7 +157,6 @@ void set_default_settings(Settings *settings)
settings->setDefault("trilinear_filter", "false");
settings->setDefault("texture_clean_transparent", "false");
settings->setDefault("texture_min_size", "32");
settings->setDefault("preload_item_visuals", "false");
settings->setDefault("tone_mapping", "false");
settings->setDefault("enable_bumpmapping", "false");
settings->setDefault("enable_parallax_occlusion", "false");
@ -289,6 +286,7 @@ void set_default_settings(Settings *settings)
settings->setDefault("num_emerge_threads", "1");
settings->setDefault("secure.enable_security", "false");
settings->setDefault("secure.trusted_mods", "");
settings->setDefault("secure.http_mods", "");
// physics stuff
settings->setDefault("movement_acceleration_default", "3");
@ -345,12 +343,7 @@ void set_default_settings(Settings *settings)
settings->setDefault("emergequeue_limit_diskonly", "8");
settings->setDefault("emergequeue_limit_generate", "8");
settings->setDefault("max_block_generate_distance", "3");
settings->setDefault("preload_item_visuals", "false");
settings->setDefault("viewing_range_nodes_max", "50");
settings->setDefault("viewing_range_nodes_min", "5");
settings->setDefault("inventory_image_hack", "true");
settings->setDefault("enable_3d_clouds", "false");
settings->setDefault("wanted_fps", "25");
settings->setDefault("fps_max", "35");
settings->setDefault("pause_fps_max", "10");
settings->setDefault("max_objects_per_block", "32");
@ -359,6 +352,9 @@ void set_default_settings(Settings *settings)
settings->setDefault("curl_verify_cert","false");
settings->setDefault("mouse_sensitivity", "0.15");
settings->setDefault("hud_scaling", "0.9");
settings->setDefault("viewing_range", "40");
settings->setDefault("inventory_image_hack", "true");
//check for device with small screen
float x_inches = ((double) porting::getDisplaySize().X /
(160 * porting::getDisplayDensity()));

View File

@ -304,7 +304,7 @@ PointedThing getPointedThing(Client *client, Hud *hud, const v3f &player_positio
INodeDefManager *nodedef = client->getNodeDefManager();
ClientMap &map = client->getEnv().getClientMap();
f32 mindistance = BS * 1001;
f32 min_distance = BS * 1001;
// First try to find a pointed at active object
if (look_for_object) {
@ -324,7 +324,7 @@ PointedThing getPointedThing(Client *client, Hud *hud, const v3f &player_positio
hud->setSelectionPos(pos, camera_offset);
}
mindistance = (selected_object->getPosition() - camera_position).getLength();
min_distance = (selected_object->getPosition() - camera_position).getLength();
result.type = POINTEDTHING_OBJECT;
result.object_id = selected_object->getId();
@ -333,14 +333,13 @@ PointedThing getPointedThing(Client *client, Hud *hud, const v3f &player_positio
// That didn't work, try to find a pointed at node
v3s16 pos_i = floatToInt(player_position, BS);
/*infostream<<"pos_i=("<<pos_i.X<<","<<pos_i.Y<<","<<pos_i.Z<<")"
<<std::endl;*/
s16 a = d;
s16 ystart = pos_i.Y + 0 - (camera_direction.Y < 0 ? a : 1);
s16 ystart = pos_i.Y - (camera_direction.Y < 0 ? a : 1);
s16 zstart = pos_i.Z - (camera_direction.Z < 0 ? a : 1);
s16 xstart = pos_i.X - (camera_direction.X < 0 ? a : 1);
s16 yend = pos_i.Y + 1 + (camera_direction.Y > 0 ? a : 1);
@ -357,24 +356,25 @@ PointedThing getPointedThing(Client *client, Hud *hud, const v3f &player_positio
if (xend == 32767)
xend = 32766;
for (s16 y = ystart; y <= yend; y++)
for (s16 z = zstart; z <= zend; z++)
v3s16 pointed_pos(0, 0, 0);
for (s16 y = ystart; y <= yend; y++) {
for (s16 z = zstart; z <= zend; z++) {
for (s16 x = xstart; x <= xend; x++) {
MapNode n;
bool is_valid_position;
n = map.getNodeNoEx(v3s16(x, y, z), &is_valid_position);
if (!is_valid_position)
if (!is_valid_position) {
continue;
if (!isPointableNode(n, client, liquids_pointable))
}
if (!isPointableNode(n, client, liquids_pointable)) {
continue;
}
std::vector<aabb3f> boxes = n.getSelectionBoxes(nodedef);
v3s16 np(x, y, z);
v3f npf = intToFloat(np, BS);
for (std::vector<aabb3f>::const_iterator
i = boxes.begin();
i != boxes.end(); ++i) {
@ -382,62 +382,80 @@ PointedThing getPointedThing(Client *client, Hud *hud, const v3f &player_positio
box.MinEdge += npf;
box.MaxEdge += npf;
for (u16 j = 0; j < 6; j++) {
v3s16 facedir = g_6dirs[j];
aabb3f facebox = box;
f32 d = 0.001 * BS;
if (facedir.X > 0)
facebox.MinEdge.X = facebox.MaxEdge.X - d;
else if (facedir.X < 0)
facebox.MaxEdge.X = facebox.MinEdge.X + d;
else if (facedir.Y > 0)
facebox.MinEdge.Y = facebox.MaxEdge.Y - d;
else if (facedir.Y < 0)
facebox.MaxEdge.Y = facebox.MinEdge.Y + d;
else if (facedir.Z > 0)
facebox.MinEdge.Z = facebox.MaxEdge.Z - d;
else if (facedir.Z < 0)
facebox.MaxEdge.Z = facebox.MinEdge.Z + d;
v3f centerpoint = facebox.getCenter();
f32 distance = (centerpoint - camera_position).getLength();
if (distance >= mindistance)
continue;
if (!facebox.intersectsWithLine(shootline))
continue;
v3s16 np_above = np + facedir;
result.type = POINTEDTHING_NODE;
result.node_undersurface = np;
result.node_abovesurface = np_above;
mindistance = distance;
selectionboxes->clear();
for (std::vector<aabb3f>::const_iterator
i2 = boxes.begin();
i2 != boxes.end(); ++i2) {
aabb3f box = *i2;
box.MinEdge += v3f(-d, -d, -d);
box.MaxEdge += v3f(d, d, d);
selectionboxes->push_back(box);
}
hud->setSelectionPos(npf, camera_offset);
v3f centerpoint = box.getCenter();
f32 distance = (centerpoint - camera_position).getLength();
if (distance >= min_distance) {
continue;
}
if (!box.intersectsWithLine(shootline)) {
continue;
}
result.type = POINTEDTHING_NODE;
min_distance = distance;
pointed_pos = np;
}
} // for coords
}
}
}
if (result.type == POINTEDTHING_NODE) {
f32 d = 0.001 * BS;
MapNode n = map.getNodeNoEx(pointed_pos);
v3f npf = intToFloat(pointed_pos, BS);
std::vector<aabb3f> boxes = n.getSelectionBoxes(nodedef);
f32 face_min_distance = 1000 * BS;
for (std::vector<aabb3f>::const_iterator
i = boxes.begin();
i != boxes.end(); ++i) {
aabb3f box = *i;
box.MinEdge += npf;
box.MaxEdge += npf;
for (u16 j = 0; j < 6; j++) {
v3s16 facedir = g_6dirs[j];
aabb3f facebox = box;
if (facedir.X > 0) {
facebox.MinEdge.X = facebox.MaxEdge.X - d;
} else if (facedir.X < 0) {
facebox.MaxEdge.X = facebox.MinEdge.X + d;
} else if (facedir.Y > 0) {
facebox.MinEdge.Y = facebox.MaxEdge.Y - d;
} else if (facedir.Y < 0) {
facebox.MaxEdge.Y = facebox.MinEdge.Y + d;
} else if (facedir.Z > 0) {
facebox.MinEdge.Z = facebox.MaxEdge.Z - d;
} else if (facedir.Z < 0) {
facebox.MaxEdge.Z = facebox.MinEdge.Z + d;
}
v3f centerpoint = facebox.getCenter();
f32 distance = (centerpoint - camera_position).getLength();
if (distance >= face_min_distance)
continue;
if (!facebox.intersectsWithLine(shootline))
continue;
result.node_abovesurface = pointed_pos + facedir;
face_min_distance = distance;
}
}
selectionboxes->clear();
for (std::vector<aabb3f>::const_iterator
i = boxes.begin();
i != boxes.end(); ++i) {
aabb3f box = *i;
box.MinEdge += v3f(-d, -d, -d);
box.MaxEdge += v3f(d, d, d);
selectionboxes->push_back(box);
}
hud->setSelectionPos(intToFloat(pointed_pos, BS), camera_offset);
result.node_undersurface = pointed_pos;
}
// Update selection mesh light level and vertex colors
if (selectionboxes->size() > 0) {
v3f pf = hud->getSelectionPos();
v3s16 p = floatToInt(pf, BS);
v3s16 p = floatToInt(pf, BS);
// Get selection mesh light level
MapNode n = map.getNodeNoEx(p);
MapNode n = map.getNodeNoEx(p);
u16 node_light = getInteriorLight(n, -1, nodedef);
u16 light_level = node_light;
@ -3012,10 +3030,10 @@ void Game::toggleProfiler(float *statustext_time, u32 *profiler_current_page,
void Game::increaseViewRange(float *statustext_time)
{
s16 range = g_settings->getS16("viewing_range_nodes_min");
s16 range = g_settings->getS16("viewing_range");
s16 range_new = range + 10;
g_settings->set("viewing_range_nodes_min", itos(range_new));
statustext = utf8_to_wide("Minimum viewing range changed to "
g_settings->set("viewing_range", itos(range_new));
statustext = utf8_to_wide("Viewing range changed to "
+ itos(range_new));
*statustext_time = 0;
}
@ -3023,14 +3041,14 @@ void Game::increaseViewRange(float *statustext_time)
void Game::decreaseViewRange(float *statustext_time)
{
s16 range = g_settings->getS16("viewing_range_nodes_min");
s16 range = g_settings->getS16("viewing_range");
s16 range_new = range - 10;
if (range_new < 0)
range_new = range;
if (range_new < 20)
range_new = 20;
g_settings->set("viewing_range_nodes_min", itos(range_new));
statustext = utf8_to_wide("Minimum viewing range changed to "
g_settings->set("viewing_range", itos(range_new));
statustext = utf8_to_wide("Viewing range changed to "
+ itos(range_new));
*statustext_time = 0;
}
@ -3917,12 +3935,7 @@ void Game::updateFrame(ProfilerGraph *graph, RunStats *stats,
if (draw_control->range_all) {
runData->fog_range = 100000 * BS;
} else {
runData->fog_range = draw_control->wanted_range * BS
+ 0.0 * MAP_BLOCKSIZE * BS;
runData->fog_range = MYMIN(
runData->fog_range,
(draw_control->farthest_drawn + 20) * BS);
runData->fog_range *= 0.9;
runData->fog_range = 0.9 * draw_control->wanted_range * BS;
}
/*

View File

@ -18,7 +18,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
*/
#include "socket.h" // for select()
#include "porting.h" // for sleep_ms(), get_sysinfo()
#include "porting.h" // for sleep_ms(), get_sysinfo(), secure_rand_fill_buf()
#include "httpfetch.h"
#include <iostream>
#include <sstream>
@ -34,9 +34,11 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "util/thread.h"
#include "version.h"
#include "settings.h"
#include "noise.h"
Mutex g_httpfetch_mutex;
std::map<unsigned long, std::queue<HTTPFetchResult> > g_httpfetch_results;
PcgRandom g_callerid_randomness;
HTTPFetchRequest::HTTPFetchRequest()
{
@ -84,6 +86,34 @@ unsigned long httpfetch_caller_alloc()
return discard;
}
unsigned long httpfetch_caller_alloc_secure()
{
MutexAutoLock lock(g_httpfetch_mutex);
// Generate random caller IDs and make sure they're not
// already used or equal to HTTPFETCH_DISCARD
// Give up after 100 tries to prevent infinite loop
u8 tries = 100;
unsigned long caller;
do {
caller = (((u64) g_callerid_randomness.next()) << 32) |
g_callerid_randomness.next();
if (--tries < 1) {
FATAL_ERROR("httpfetch_caller_alloc_secure: ran out of caller IDs");
return HTTPFETCH_DISCARD;
}
} while (g_httpfetch_results.find(caller) != g_httpfetch_results.end());
verbosestream << "httpfetch_caller_alloc_secure: allocating "
<< caller << std::endl;
// Access element to create it
g_httpfetch_results[caller];
return caller;
}
void httpfetch_caller_free(unsigned long caller)
{
verbosestream<<"httpfetch_caller_free: freeing "
@ -262,7 +292,7 @@ HTTPFetchOngoing::HTTPFetchOngoing(HTTPFetchRequest request_, CurlHandlePool *po
}
// Set POST (or GET) data
if (request.post_fields.empty()) {
if (request.post_fields.empty() && request.post_data.empty()) {
curl_easy_setopt(curl, CURLOPT_HTTPGET, 1);
} else if (request.multipart) {
curl_httppost *last = NULL;
@ -710,6 +740,11 @@ void httpfetch_init(int parallel_limit)
FATAL_ERROR_IF(res != CURLE_OK, "CURL init failed");
g_httpfetch_thread = new CurlFetchThread(parallel_limit);
// Initialize g_callerid_randomness for httpfetch_caller_alloc_secure
u64 randbuf[2];
porting::secure_rand_fill_buf(randbuf, sizeof(u64) * 2);
g_callerid_randomness = PcgRandom(randbuf[0], randbuf[1]);
}
void httpfetch_cleanup()

View File

@ -116,6 +116,9 @@ bool httpfetch_async_get(unsigned long caller, HTTPFetchResult &fetch_result);
// Not required if you want to set caller = HTTPFETCH_DISCARD
unsigned long httpfetch_caller_alloc();
// Allocates a non-predictable caller ID for httpfetch_async
unsigned long httpfetch_caller_alloc_secure();
// Frees a caller ID allocated with httpfetch_caller_alloc
// Note: This can be expensive, because the httpfetch thread is told
// to stop any ongoing fetches for the given caller.

View File

@ -885,8 +885,9 @@ static void updateFastFaceRow(
&& next_lights[3] == lights[3]
&& next_tile == tile
&& tile.rotation == 0
&& next_light_source == light_source)
{
&& next_light_source == light_source
&& (tile.material_flags & MATERIAL_FLAG_TILEABLE_HORIZONTAL)
&& (tile.material_flags & MATERIAL_FLAG_TILEABLE_VERTICAL)) {
next_is_different = false;
}
else{

View File

@ -211,6 +211,7 @@ void MinimapUpdateThread::getMap(v3s16 pos, s16 size, s16 height, bool is_radar)
Mapper::Mapper(IrrlichtDevice *device, Client *client)
{
this->client = client;
this->driver = device->getVideoDriver();
this->m_tsrc = client->getTextureSource();
this->m_shdrsrc = client->getShaderSource();
@ -250,6 +251,8 @@ Mapper::Mapper(IrrlichtDevice *device, Client *client)
// Create player marker texture
data->player_marker = m_tsrc->getTexture("player_marker.png");
// Create object marker texture
data->object_marker_red = m_tsrc->getTexture("object_marker_red.png");
// Create mesh buffer for minimap
m_meshbuffer = getMinimapMeshBuffer();
@ -274,6 +277,7 @@ Mapper::~Mapper()
driver->removeTexture(data->heightmap_texture);
driver->removeTexture(data->minimap_overlay_round);
driver->removeTexture(data->minimap_overlay_square);
driver->removeTexture(data->object_marker_red);
delete data;
delete m_minimap_update_thread;
@ -468,6 +472,7 @@ void Mapper::drawMinimap()
if (!minimap_texture)
return;
updateActiveMarkers();
v2u32 screensize = porting::getWindowSize();
const u32 size = 0.25 * screensize.Y;
@ -527,6 +532,70 @@ void Mapper::drawMinimap()
driver->setTransform(video::ETS_VIEW, oldViewMat);
driver->setTransform(video::ETS_PROJECTION, oldProjMat);
driver->setViewPort(oldViewPort);
// Draw player markers
v2s32 s_pos(screensize.X - size - 10, 10);
core::dimension2di imgsize(data->object_marker_red->getOriginalSize());
core::rect<s32> img_rect(0, 0, imgsize.Width, imgsize.Height);
static const video::SColor col(255, 255, 255, 255);
static const video::SColor c[4] = {col, col, col, col};
f32 sin_angle = sin(m_angle * core::DEGTORAD);
f32 cos_angle = cos(m_angle * core::DEGTORAD);
s32 marker_size2 = 0.025 * (float)size;
for (std::list<v2f>::const_iterator
i = m_active_markers.begin();
i != m_active_markers.end(); ++i) {
v2f posf = *i;
if (data->minimap_shape_round) {
f32 t1 = posf.X * cos_angle - posf.Y * sin_angle;
f32 t2 = posf.X * sin_angle + posf.Y * cos_angle;
posf.X = t1;
posf.Y = t2;
}
posf.X = (posf.X + 0.5) * (float)size;
posf.Y = (posf.Y + 0.5) * (float)size;
core::rect<s32> dest_rect(
s_pos.X + posf.X - marker_size2,
s_pos.Y + posf.Y - marker_size2,
s_pos.X + posf.X + marker_size2,
s_pos.Y + posf.Y + marker_size2);
driver->draw2DImage(data->object_marker_red, dest_rect,
img_rect, &dest_rect, &c[0], true);
}
}
void Mapper::updateActiveMarkers ()
{
video::IImage *minimap_mask = data->minimap_shape_round ?
data->minimap_mask_round : data->minimap_mask_square;
std::list<Nametag *> *nametags = client->getCamera()->getNametags();
m_active_markers.clear();
for (std::list<Nametag *>::const_iterator
i = nametags->begin();
i != nametags->end(); ++i) {
Nametag *nametag = *i;
v3s16 pos = floatToInt(nametag->parent_node->getPosition() +
intToFloat(client->getCamera()->getOffset(), BS), BS);
pos -= data->pos - v3s16(data->map_size / 2,
data->scan_height / 2,
data->map_size / 2);
if (pos.X < 0 || pos.X > data->map_size ||
pos.Y < 0 || pos.Y > data->scan_height ||
pos.Z < 0 || pos.Z > data->map_size) {
continue;
}
pos.X = ((float)pos.X / data->map_size) * MINIMAP_MAX_SX;
pos.Z = ((float)pos.Z / data->map_size) * MINIMAP_MAX_SY;
video::SColor mask_col = minimap_mask->getPixel(pos.X, pos.Z);
if (!mask_col.getAlpha()) {
continue;
}
m_active_markers.push_back(v2f(((float)pos.X / (float)MINIMAP_MAX_SX) - 0.5,
(1.0 - (float)pos.Z / (float)MINIMAP_MAX_SY) - 0.5));
}
}
////

View File

@ -28,6 +28,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include <map>
#include <string>
#include <vector>
#include "camera.h"
#define MINIMAP_MAX_SX 512
#define MINIMAP_MAX_SY 512
@ -82,6 +83,7 @@ struct MinimapData {
video::ITexture *minimap_overlay_round;
video::ITexture *minimap_overlay_square;
video::ITexture *player_marker;
video::ITexture *object_marker_red;
};
struct QueuedMinimapUpdate {
@ -138,9 +140,12 @@ public:
video::IImage *heightmap_image);
scene::SMeshBuffer *getMinimapMeshBuffer();
void updateActiveMarkers();
void drawMinimap();
video::IVideoDriver *driver;
Client* client;
MinimapData *data;
private:
@ -153,6 +158,7 @@ private:
u16 m_surface_mode_scan_height;
f32 m_angle;
Mutex m_mutex;
std::list<v2f> m_active_markers;
};
#endif

View File

@ -558,8 +558,9 @@ void initializePaths()
infostream << "Detected user path: " << path_user << std::endl;
infostream << "Detected cache path: " << path_cache << std::endl;
#ifdef USE_GETTEXT
bool found_localedir = false;
#ifdef STATIC_LOCALEDIR
# ifdef STATIC_LOCALEDIR
if (STATIC_LOCALEDIR[0] && fs::PathExists(STATIC_LOCALEDIR)) {
found_localedir = true;
path_locale = STATIC_LOCALEDIR;
@ -573,15 +574,16 @@ void initializePaths()
<< "(RUN_IN_PLACE or CUSTOM_LOCALEDIR)." << std::endl;
}
}
#else
# else
path_locale = getDataPath("locale");
if (fs::PathExists(path_locale)) {
found_localedir = true;
}
#endif
# endif
if (!found_localedir) {
errorstream << "Couldn't find a locale directory!" << std::endl;
warningstream << "Couldn't find a locale directory!" << std::endl;
}
#endif // USE_GETTEXT
}

View File

@ -517,6 +517,15 @@ bool getboolfield_default(lua_State *L, int table,
return result;
}
void setstringfield(lua_State *L, int table,
const char *fieldname, const char *value)
{
lua_pushstring(L, value);
if(table < 0)
table -= 1;
lua_setfield(L, table, fieldname);
}
void setintfield(lua_State *L, int table,
const char *fieldname, int value)
{

View File

@ -69,6 +69,8 @@ bool getfloatfield(lua_State *L, int table,
std::string checkstringfield(lua_State *L, int table,
const char *fieldname);
void setstringfield(lua_State *L, int table,
const char *fieldname, const char *value);
void setintfield(lua_State *L, int table,
const char *fieldname, int value);
void setfloatfield(lua_State *L, int table,

View File

@ -16,6 +16,7 @@ set(common_SCRIPT_LUA_API_SRCS
${CMAKE_CURRENT_SOURCE_DIR}/l_util.cpp
${CMAKE_CURRENT_SOURCE_DIR}/l_vmanip.cpp
${CMAKE_CURRENT_SOURCE_DIR}/l_settings.cpp
${CMAKE_CURRENT_SOURCE_DIR}/l_http.cpp
PARENT_SCOPE)
set(client_SCRIPT_LUA_API_SRCS

View File

@ -0,0 +1,176 @@
/*
Minetest
Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser 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.
*/
#include "lua_api/l_internal.h"
#include "common/c_converter.h"
#include "common/c_content.h"
#include "lua_api/l_http.h"
#include "httpfetch.h"
#include "settings.h"
#include "log.h"
#include <algorithm>
#include <iomanip>
#include <cctype>
#define HTTP_API(name) \
lua_pushstring(L, #name); \
lua_pushcfunction(L, l_http_##name); \
lua_settable(L, -3);
#if USE_CURL
void ModApiHttp::read_http_fetch_request(lua_State *L, HTTPFetchRequest &req)
{
luaL_checktype(L, 1, LUA_TTABLE);
req.caller = httpfetch_caller_alloc_secure();
getstringfield(L, 1, "url", req.url);
lua_getfield(L, 1, "user_agent");
if (lua_isstring(L, -1))
req.useragent = getstringfield_default(L, 1, "user_agent", "");
lua_pop(L, 1);
req.multipart = getboolfield_default(L, 1, "multipart", false);
req.timeout = getintfield_default(L, 1, "timeout", 3) * 1000;
// post_data: if table, post form data, otherwise raw data
lua_getfield(L, 1, "post_data");
if (lua_istable(L, 2)) {
lua_pushnil(L);
while (lua_next(L, 2) != 0)
{
req.post_fields[luaL_checkstring(L, -2)] = luaL_checkstring(L, -1);
lua_pop(L, 1);
}
} else if (lua_isstring(L, 2)) {
req.post_data = lua_tostring(L, 2);
}
lua_pop(L, 1);
lua_getfield(L, 1, "extra_headers");
if (lua_istable(L, 2)) {
lua_pushnil(L);
while (lua_next(L, 2) != 0)
{
const char *header = luaL_checkstring(L, -1);
req.extra_headers.push_back(header);
lua_pop(L, 1);
}
}
lua_pop(L, 1);
}
void ModApiHttp::push_http_fetch_result(lua_State *L, HTTPFetchResult &res, bool completed)
{
lua_newtable(L);
setboolfield(L, -1, "succeeded", res.succeeded);
setboolfield(L, -1, "timeout", res.timeout);
setboolfield(L, -1, "completed", completed);
setintfield(L, -1, "code", res.response_code);
setstringfield(L, -1, "data", res.data.c_str());
}
// http_api.fetch_async(HTTPRequest definition)
int ModApiHttp::l_http_fetch_async(lua_State *L)
{
NO_MAP_LOCK_REQUIRED;
HTTPFetchRequest req;
read_http_fetch_request(L, req);
actionstream << "Mod performs HTTP request with URL " << req.url << std::endl;
httpfetch_async(req);
// Convert handle to hex string since lua can't handle 64-bit integers
std::stringstream handle_conversion_stream;
handle_conversion_stream << std::hex << req.caller;
std::string caller_handle(handle_conversion_stream.str());
lua_pushstring(L, caller_handle.c_str());
return 1;
}
// http_api.fetch_async_get(handle)
int ModApiHttp::l_http_fetch_async_get(lua_State *L)
{
NO_MAP_LOCK_REQUIRED;
std::string handle_str = luaL_checkstring(L, 1);
// Convert hex string back to 64-bit handle
u64 handle;
std::stringstream handle_conversion_stream;
handle_conversion_stream << std::hex << handle_str;
handle_conversion_stream >> handle;
HTTPFetchResult res;
bool completed = httpfetch_async_get(handle, res);
push_http_fetch_result(L, res, completed);
return 1;
}
int ModApiHttp::l_request_http_api(lua_State *L)
{
NO_MAP_LOCK_REQUIRED;
// Mod must be listed in secure.http_mods or secure.trusted_mods
lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_CURRENT_MOD_NAME);
if (!lua_isstring(L, -1)) {
lua_pushnil(L);
return 1;
}
const char *mod_name = lua_tostring(L, -1);
std::string http_mods = g_settings->get("secure.http_mods");
http_mods.erase(std::remove(http_mods.begin(), http_mods.end(), ' '), http_mods.end());
std::vector<std::string> mod_list_http = str_split(http_mods, ',');
std::string trusted_mods = g_settings->get("secure.trusted_mods");
trusted_mods.erase(std::remove(trusted_mods.begin(), trusted_mods.end(), ' '), trusted_mods.end());
std::vector<std::string> mod_list_trusted = str_split(trusted_mods, ',');
mod_list_http.insert(mod_list_http.end(), mod_list_trusted.begin(), mod_list_trusted.end());
if (std::find(mod_list_http.begin(), mod_list_http.end(), mod_name) == mod_list_http.end()) {
lua_pushnil(L);
return 1;
}
lua_getglobal(L, "core");
lua_getfield(L, -1, "http_add_fetch");
lua_newtable(L);
HTTP_API(fetch_async);
HTTP_API(fetch_async_get);
// Stack now looks like this:
// <core.http_add_fetch> <table with fetch_async, fetch_async_get>
// Now call core.http_add_fetch to append .fetch(request, callback) to table
lua_call(L, 1, 1);
return 1;
}
#endif
void ModApiHttp::Initialize(lua_State *L, int top)
{
#if USE_CURL
API_FCT(request_http_api);
#endif
}

View File

@ -0,0 +1,50 @@
/*
Minetest
Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser 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 L_HTTP_H_
#define L_HTTP_H_
#include "lua_api/l_base.h"
#include "config.h"
struct HTTPFetchRequest;
struct HTTPFetchResult;
class ModApiHttp : public ModApiBase {
private:
#if USE_CURL
// Helpers for HTTP fetch functions
static void read_http_fetch_request(lua_State *L, HTTPFetchRequest &req);
static void push_http_fetch_result(lua_State *L, HTTPFetchResult &res, bool completed = true);
// http_fetch_async({url=, timeout=, post_data=})
static int l_http_fetch_async(lua_State *L);
// http_fetch_async_get(handle)
static int l_http_fetch_async_get(lua_State *L);
// request_http_api()
static int l_request_http_api(lua_State *L);
#endif
public:
static void Initialize(lua_State *L, int top);
};
#endif /* L_HTTP_H_ */

View File

@ -357,22 +357,46 @@ int ModApiUtil::l_get_dir_list(lua_State *L)
int ModApiUtil::l_request_insecure_environment(lua_State *L)
{
NO_MAP_LOCK_REQUIRED;
// Just return _G if security is disabled
if (!ScriptApiSecurity::isSecure(L)) {
lua_getglobal(L, "_G");
return 1;
}
// We have to make sure that this function is being called directly by
// a mod, otherwise a malicious mod could override this function and
// steal its return value.
lua_Debug info;
// Make sure there's only one item below this function on the stack...
if (lua_getstack(L, 2, &info)) {
return 0;
}
assert(lua_getstack(L, 1, &info));
assert(lua_getinfo(L, "S", &info));
// ...and that that item is the main file scope.
if (strcmp(info.what, "main") != 0) {
return 0;
}
// Get mod name
lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_CURRENT_MOD_NAME);
if (!lua_isstring(L, -1)) {
lua_pushnil(L);
return 1;
return 0;
}
// Check secure.trusted_mods
const char *mod_name = lua_tostring(L, -1);
std::string trusted_mods = g_settings->get("secure.trusted_mods");
trusted_mods.erase(std::remove(trusted_mods.begin(),
trusted_mods.end(), ' '), trusted_mods.end());
std::vector<std::string> mod_list = str_split(trusted_mods, ',');
if (std::find(mod_list.begin(), mod_list.end(), mod_name) == mod_list.end()) {
lua_pushnil(L);
return 1;
if (std::find(mod_list.begin(), mod_list.end(), mod_name) ==
mod_list.end()) {
return 0;
}
// Push insecure environment
lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_GLOBALS_BACKUP);
return 1;
}

View File

@ -39,6 +39,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "lua_api/l_util.h"
#include "lua_api/l_vmanip.h"
#include "lua_api/l_settings.h"
#include "lua_api/l_http.h"
extern "C" {
#include "lualib.h"
@ -89,6 +90,7 @@ void GameScripting::InitializeModApi(lua_State *L, int top)
ModApiRollback::Initialize(L, top);
ModApiServer::Initialize(L, top);
ModApiUtil::Initialize(L, top);
ModApiHttp::Initialize(L, top);
// Register reference classes (userdata)
InvRef::Register(L);

View File

@ -136,8 +136,6 @@ fake_function() {
gettext("Filtered textures can blend RGB values with fully-transparent neighbors,\nwhich PNG optimizers usually discard, sometimes resulting in a dark or\nlight edge to transparent textures. Apply this filter to clean that up\nat texture load time.");
gettext("Minimum texture size for filters");
gettext("When using bilinear/trilinear/anisotropic filters, low-resolution textures\ncan be blurred, so automatically upscale them with nearest-neighbor\ninterpolation to preserve crisp pixels. This sets the minimum texture size\nfor the upscaled textures; higher values look sharper, but require more\nmemory. Powers of 2 are recommended. Setting this higher than 1 may not\nhave a visible effect unless bilinear/trilinear/anisotropic filtering is\nenabled.");
gettext("Preload inventory textures");
gettext("Pre-generate all item visuals used in the inventory.\nThis increases startup time, but runs smoother in-game.\nThe generated textures can easily exceed your VRAM, causing artifacts in the inventory.");
gettext("FSAA");
gettext("Experimental option, might cause visible spaces between blocks\nwhen set to higher number than 0.");
gettext("Shaders");

Binary file not shown.

After

Width:  |  Height:  |  Size: 663 B