This commit is contained in:
Maksim Gamarnik 2016-02-23 00:40:02 +02:00
parent ae3d7c3ebc
commit fe70a72fe6
25 changed files with 643 additions and 496 deletions

View File

@ -214,12 +214,12 @@
# type: key # type: key
# keymap_camera_mode = KEY_F7 # 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 # See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
# type: key # type: key
# keymap_increase_viewing_range_min = + # 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 # See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
# type: key # type: key
# keymap_decrease_viewing_range_min = - # keymap_decrease_viewing_range_min = -
@ -335,12 +335,6 @@
# type: int # type: int
# texture_min_size = 64 # 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 # Experimental option, might cause visible spaces between blocks
# when set to higher number than 0. # when set to higher number than 0.
# type: enum values: 0, 1, 2, 4, 8, 16 # type: enum values: 0, 1, 2, 4, 8, 16
@ -437,11 +431,6 @@
#### Advanced #### 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 # If FPS would go higher than this, limit it by sleeping
# to not waste CPU power for no benefit. # to not waste CPU power for no benefit.
# type: int # type: int
@ -451,15 +440,10 @@
# type: int # type: int
# pause_fps_max = 20 # pause_fps_max = 20
# The allowed adjustment range for the automatic rendering range adjustment. # View range in nodes.
# Set this to be equal to viewing range minimum to disable the auto-adjustment algorithm. # Min = 20.
# type: int # type: int
# viewing_range_nodes_max = 160 # viewing_range = 100
# 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
# Width component of the initial window size. # Width component of the initial window size.
# type: int # type: int

View File

@ -60,13 +60,6 @@ Camera::Camera(scene::ISceneManager* smgr, MapDrawControl& draw_control,
m_fov_x(1.0), m_fov_x(1.0),
m_fov_y(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_anim(0),
m_view_bobbing_state(0), m_view_bobbing_state(0),
m_view_bobbing_speed(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_fall_bobbing_amount = g_settings->getFloat("fall_bobbing_amount");
m_cache_view_bobbing_amount = g_settings->getFloat("view_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_fov = g_settings->getFloat("fov");
m_cache_view_bobbing = g_settings->getBool("view_bobbing"); m_cache_view_bobbing = g_settings->getBool("view_bobbing");
m_nametags.clear(); m_nametags.clear();
@ -455,8 +447,8 @@ void Camera::update(LocalPlayer* player, f32 frametime, f32 busytime,
m_wieldnode->setColor(player->light_color); m_wieldnode->setColor(player->light_color);
// Render distance feedback loop // Set render distance
updateViewingRange(frametime, busytime); updateViewingRange();
// If the player is walking, swimming, or climbing, // If the player is walking, swimming, or climbing,
// view bobbing is enabled and free_move is off, // 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) if (m_draw_control.range_all) {
return; m_cameranode->setFarValue(100000.0);
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;
return; return;
} }
f32 range = m_draw_control.wanted_range; f32 viewing_range = g_settings->getFloat("viewing_range");
f32 new_range = range; m_draw_control.wanted_range = viewing_range;
m_cameranode->setFarValue((viewing_range < 2000) ? 2000 * BS : viewing_range * BS);
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;
} }
void Camera::setDigging(s32 button) void Camera::setDigging(s32 button)
@ -675,8 +540,7 @@ void Camera::drawNametags()
i = m_nametags.begin(); i = m_nametags.begin();
i != m_nametags.end(); ++i) { i != m_nametags.end(); ++i) {
Nametag *nametag = *i; Nametag *nametag = *i;
v3f pos = nametag->parent_node->getPosition() - v3f pos = nametag->parent_node->getPosition() + v3f(0.0, 1.1 * BS, 0.0);
intToFloat(m_camera_offset, BS) + v3f(0.0, 1.1 * BS, 0.0);
f32 transformed_pos[4] = { pos.X, pos.Y, pos.Z, 1.0f }; f32 transformed_pos[4] = { pos.X, pos.Y, pos.Z, 1.0f };
trans.multiplyWith1x4Matrix(transformed_pos); trans.multiplyWith1x4Matrix(transformed_pos);
if (transformed_pos[3] > 0) { if (transformed_pos[3] > 0) {

View File

@ -136,8 +136,8 @@ public:
void update(LocalPlayer* player, f32 frametime, f32 busytime, void update(LocalPlayer* player, f32 frametime, f32 busytime,
f32 tool_reload_ratio, ClientEnvironment &c_env); f32 tool_reload_ratio, ClientEnvironment &c_env);
// Render distance feedback loop // Update render distance
void updateViewingRange(f32 frametime_in, f32 busytime_in); void updateViewingRange();
// Start digging animation // Start digging animation
// Pass 0 for left click, 1 for right click // Pass 0 for left click, 1 for right click
@ -172,6 +172,9 @@ public:
void removeNametag(Nametag *nametag); void removeNametag(Nametag *nametag);
std::list<Nametag *> *getNametags()
{ return &m_nametags; }
void drawNametags(); void drawNametags();
private: private:
@ -201,14 +204,6 @@ private:
f32 m_fov_x; f32 m_fov_x;
f32 m_fov_y; 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) // View bobbing animation frame (0 <= m_view_bobbing_anim < 1)
f32 m_view_bobbing_anim; f32 m_view_bobbing_anim;
// If 0, view bobbing is off (e.g. player is standing). // 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_fall_bobbing_amount;
f32 m_cache_view_bobbing_amount; f32 m_cache_view_bobbing_amount;
f32 m_cache_wanted_fps;
f32 m_cache_fov; f32 m_cache_fov;
bool m_cache_view_bobbing; 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); m_nodedef->updateTextures(this, texture_update_progress, &tu_args);
delete[] tu_args.text_base; 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 // Start mesh update thread after setting up content definitions
infostream<<"- Starting mesh update thread"<<std::endl; infostream<<"- Starting mesh update thread"<<std::endl;
m_mesh_update_thread.start(); m_mesh_update_thread.start();

View File

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

View File

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

View File

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

View File

@ -248,8 +248,9 @@ collisionMoveResult collisionMoveSimple(Environment *env, IGameDef *gamedef,
bool any_position_valid = false; 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 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++) for(s16 z = min_z; z <= max_z; z++)
{ {
v3s16 p(x,y,z); v3s16 p(x,y,z);
@ -388,7 +389,6 @@ collisionMoveResult collisionMoveSimple(Environment *env, IGameDef *gamedef,
loopcount++; loopcount++;
if (loopcount >= 100) { if (loopcount >= 100) {
warningstream << "collisionMoveSimple: Loop count exceeded, aborting to avoid infiniite loop" << std::endl; warningstream << "collisionMoveSimple: Loop count exceeded, aborting to avoid infiniite loop" << std::endl;
dtime = 0;
break; break;
} }
@ -398,21 +398,23 @@ collisionMoveResult collisionMoveSimple(Environment *env, IGameDef *gamedef,
int nearest_collided = -1; int nearest_collided = -1;
f32 nearest_dtime = dtime; f32 nearest_dtime = dtime;
u32 nearest_boxindex = -1; int nearest_boxindex = -1;
/* /*
Go through every nodebox, find nearest collision Go through every nodebox, find nearest collision
*/ */
for (u32 boxindex = 0; boxindex < cboxes.size(); boxindex++) { 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) // Find nearest collision of the two boxes (raytracing-like)
f32 dtime_tmp; f32 dtime_tmp;
int collided = axisAlignedCollision( int collided = axisAlignedCollision(
cboxes[boxindex], movingbox, *speed_f, d, &dtime_tmp); 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) if (collided == -1 || dtime_tmp >= nearest_dtime)
continue; continue;
@ -462,10 +464,12 @@ collisionMoveResult collisionMoveSimple(Environment *env, IGameDef *gamedef,
is_collision = false; is_collision = false;
CollisionInfo info; CollisionInfo info;
if (is_object[nearest_boxindex]) if (is_object[nearest_boxindex]) {
info.type = COLLISION_OBJECT; info.type = COLLISION_OBJECT;
else result.standing_on_object = true;
} else {
info.type = COLLISION_NODE; info.type = COLLISION_NODE;
}
info.node_p = node_positions[nearest_boxindex]; info.node_p = node_positions[nearest_boxindex];
info.bouncy = bouncy; info.bouncy = bouncy;
@ -483,12 +487,13 @@ collisionMoveResult collisionMoveSimple(Environment *env, IGameDef *gamedef,
speed_f->X = 0; speed_f->X = 0;
result.collides = true; result.collides = true;
result.collides_xz = true; result.collides_xz = true;
} } else if(nearest_collided == 1) { // Y
else if(nearest_collided == 1) { // Y if (fabs(speed_f->Y) > BS * 3) {
if (fabs(speed_f->Y) > BS * 3)
speed_f->Y *= bounce; speed_f->Y *= bounce;
else } else {
speed_f->Y = 0; speed_f->Y = 0;
result.touching_ground = true;
}
result.collides = true; result.collides = true;
} else if(nearest_collided == 2) { // Z } else if(nearest_collided == 2) { // Z
if (fabs(speed_f->Z) > BS * 3) 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; return result;
} }

View File

@ -88,12 +88,10 @@ void set_default_settings(Settings *settings)
#else #else
settings->setDefault("show_debug", "true"); settings->setDefault("show_debug", "true");
#endif #endif
settings->setDefault("wanted_fps", "20");
settings->setDefault("fps_max", "60"); settings->setDefault("fps_max", "60");
settings->setDefault("pause_fps_max", "15"); 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", "100");
settings->setDefault("viewing_range_nodes_max", "240");
settings->setDefault("viewing_range_nodes_min", "35");
settings->setDefault("map_generation_limit", "31000"); settings->setDefault("map_generation_limit", "31000");
settings->setDefault("screenW", "800"); settings->setDefault("screenW", "800");
settings->setDefault("screenH", "600"); settings->setDefault("screenH", "600");
@ -159,7 +157,6 @@ void set_default_settings(Settings *settings)
settings->setDefault("trilinear_filter", "false"); settings->setDefault("trilinear_filter", "false");
settings->setDefault("texture_clean_transparent", "false"); settings->setDefault("texture_clean_transparent", "false");
settings->setDefault("texture_min_size", "32"); settings->setDefault("texture_min_size", "32");
settings->setDefault("preload_item_visuals", "false");
settings->setDefault("tone_mapping", "false"); settings->setDefault("tone_mapping", "false");
settings->setDefault("enable_bumpmapping", "false"); settings->setDefault("enable_bumpmapping", "false");
settings->setDefault("enable_parallax_occlusion", "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("num_emerge_threads", "1");
settings->setDefault("secure.enable_security", "false"); settings->setDefault("secure.enable_security", "false");
settings->setDefault("secure.trusted_mods", ""); settings->setDefault("secure.trusted_mods", "");
settings->setDefault("secure.http_mods", "");
// physics stuff // physics stuff
settings->setDefault("movement_acceleration_default", "3"); 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_diskonly", "8");
settings->setDefault("emergequeue_limit_generate", "8"); settings->setDefault("emergequeue_limit_generate", "8");
settings->setDefault("max_block_generate_distance", "3"); 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("enable_3d_clouds", "false");
settings->setDefault("wanted_fps", "25");
settings->setDefault("fps_max", "35"); settings->setDefault("fps_max", "35");
settings->setDefault("pause_fps_max", "10"); settings->setDefault("pause_fps_max", "10");
settings->setDefault("max_objects_per_block", "32"); 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("curl_verify_cert","false");
settings->setDefault("mouse_sensitivity", "0.15"); settings->setDefault("mouse_sensitivity", "0.15");
settings->setDefault("hud_scaling", "0.9"); settings->setDefault("hud_scaling", "0.9");
settings->setDefault("viewing_range", "40");
settings->setDefault("inventory_image_hack", "true");
//check for device with small screen //check for device with small screen
float x_inches = ((double) porting::getDisplaySize().X / float x_inches = ((double) porting::getDisplaySize().X /
(160 * porting::getDisplayDensity())); (160 * porting::getDisplayDensity()));

View File

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

View File

@ -18,7 +18,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
*/ */
#include "socket.h" // for select() #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 "httpfetch.h"
#include <iostream> #include <iostream>
#include <sstream> #include <sstream>
@ -34,9 +34,11 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "util/thread.h" #include "util/thread.h"
#include "version.h" #include "version.h"
#include "settings.h" #include "settings.h"
#include "noise.h"
Mutex g_httpfetch_mutex; Mutex g_httpfetch_mutex;
std::map<unsigned long, std::queue<HTTPFetchResult> > g_httpfetch_results; std::map<unsigned long, std::queue<HTTPFetchResult> > g_httpfetch_results;
PcgRandom g_callerid_randomness;
HTTPFetchRequest::HTTPFetchRequest() HTTPFetchRequest::HTTPFetchRequest()
{ {
@ -84,6 +86,34 @@ unsigned long httpfetch_caller_alloc()
return discard; 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) void httpfetch_caller_free(unsigned long caller)
{ {
verbosestream<<"httpfetch_caller_free: freeing " verbosestream<<"httpfetch_caller_free: freeing "
@ -262,7 +292,7 @@ HTTPFetchOngoing::HTTPFetchOngoing(HTTPFetchRequest request_, CurlHandlePool *po
} }
// Set POST (or GET) data // 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); curl_easy_setopt(curl, CURLOPT_HTTPGET, 1);
} else if (request.multipart) { } else if (request.multipart) {
curl_httppost *last = NULL; curl_httppost *last = NULL;
@ -710,6 +740,11 @@ void httpfetch_init(int parallel_limit)
FATAL_ERROR_IF(res != CURLE_OK, "CURL init failed"); FATAL_ERROR_IF(res != CURLE_OK, "CURL init failed");
g_httpfetch_thread = new CurlFetchThread(parallel_limit); 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() 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 // Not required if you want to set caller = HTTPFETCH_DISCARD
unsigned long httpfetch_caller_alloc(); 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 // Frees a caller ID allocated with httpfetch_caller_alloc
// Note: This can be expensive, because the httpfetch thread is told // Note: This can be expensive, because the httpfetch thread is told
// to stop any ongoing fetches for the given caller. // to stop any ongoing fetches for the given caller.

View File

@ -885,8 +885,9 @@ static void updateFastFaceRow(
&& next_lights[3] == lights[3] && next_lights[3] == lights[3]
&& next_tile == tile && next_tile == tile
&& tile.rotation == 0 && 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; next_is_different = false;
} }
else{ 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) Mapper::Mapper(IrrlichtDevice *device, Client *client)
{ {
this->client = client;
this->driver = device->getVideoDriver(); this->driver = device->getVideoDriver();
this->m_tsrc = client->getTextureSource(); this->m_tsrc = client->getTextureSource();
this->m_shdrsrc = client->getShaderSource(); this->m_shdrsrc = client->getShaderSource();
@ -250,6 +251,8 @@ Mapper::Mapper(IrrlichtDevice *device, Client *client)
// Create player marker texture // Create player marker texture
data->player_marker = m_tsrc->getTexture("player_marker.png"); 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 // Create mesh buffer for minimap
m_meshbuffer = getMinimapMeshBuffer(); m_meshbuffer = getMinimapMeshBuffer();
@ -274,6 +277,7 @@ Mapper::~Mapper()
driver->removeTexture(data->heightmap_texture); driver->removeTexture(data->heightmap_texture);
driver->removeTexture(data->minimap_overlay_round); driver->removeTexture(data->minimap_overlay_round);
driver->removeTexture(data->minimap_overlay_square); driver->removeTexture(data->minimap_overlay_square);
driver->removeTexture(data->object_marker_red);
delete data; delete data;
delete m_minimap_update_thread; delete m_minimap_update_thread;
@ -468,6 +472,7 @@ void Mapper::drawMinimap()
if (!minimap_texture) if (!minimap_texture)
return; return;
updateActiveMarkers();
v2u32 screensize = porting::getWindowSize(); v2u32 screensize = porting::getWindowSize();
const u32 size = 0.25 * screensize.Y; const u32 size = 0.25 * screensize.Y;
@ -527,6 +532,70 @@ void Mapper::drawMinimap()
driver->setTransform(video::ETS_VIEW, oldViewMat); driver->setTransform(video::ETS_VIEW, oldViewMat);
driver->setTransform(video::ETS_PROJECTION, oldProjMat); driver->setTransform(video::ETS_PROJECTION, oldProjMat);
driver->setViewPort(oldViewPort); 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 <map>
#include <string> #include <string>
#include <vector> #include <vector>
#include "camera.h"
#define MINIMAP_MAX_SX 512 #define MINIMAP_MAX_SX 512
#define MINIMAP_MAX_SY 512 #define MINIMAP_MAX_SY 512
@ -82,6 +83,7 @@ struct MinimapData {
video::ITexture *minimap_overlay_round; video::ITexture *minimap_overlay_round;
video::ITexture *minimap_overlay_square; video::ITexture *minimap_overlay_square;
video::ITexture *player_marker; video::ITexture *player_marker;
video::ITexture *object_marker_red;
}; };
struct QueuedMinimapUpdate { struct QueuedMinimapUpdate {
@ -138,9 +140,12 @@ public:
video::IImage *heightmap_image); video::IImage *heightmap_image);
scene::SMeshBuffer *getMinimapMeshBuffer(); scene::SMeshBuffer *getMinimapMeshBuffer();
void updateActiveMarkers();
void drawMinimap(); void drawMinimap();
video::IVideoDriver *driver; video::IVideoDriver *driver;
Client* client;
MinimapData *data; MinimapData *data;
private: private:
@ -153,6 +158,7 @@ private:
u16 m_surface_mode_scan_height; u16 m_surface_mode_scan_height;
f32 m_angle; f32 m_angle;
Mutex m_mutex; Mutex m_mutex;
std::list<v2f> m_active_markers;
}; };
#endif #endif

View File

@ -558,8 +558,9 @@ void initializePaths()
infostream << "Detected user path: " << path_user << std::endl; infostream << "Detected user path: " << path_user << std::endl;
infostream << "Detected cache path: " << path_cache << std::endl; infostream << "Detected cache path: " << path_cache << std::endl;
#ifdef USE_GETTEXT
bool found_localedir = false; bool found_localedir = false;
#ifdef STATIC_LOCALEDIR # ifdef STATIC_LOCALEDIR
if (STATIC_LOCALEDIR[0] && fs::PathExists(STATIC_LOCALEDIR)) { if (STATIC_LOCALEDIR[0] && fs::PathExists(STATIC_LOCALEDIR)) {
found_localedir = true; found_localedir = true;
path_locale = STATIC_LOCALEDIR; path_locale = STATIC_LOCALEDIR;
@ -573,15 +574,16 @@ void initializePaths()
<< "(RUN_IN_PLACE or CUSTOM_LOCALEDIR)." << std::endl; << "(RUN_IN_PLACE or CUSTOM_LOCALEDIR)." << std::endl;
} }
} }
#else # else
path_locale = getDataPath("locale"); path_locale = getDataPath("locale");
if (fs::PathExists(path_locale)) { if (fs::PathExists(path_locale)) {
found_localedir = true; found_localedir = true;
} }
#endif # endif
if (!found_localedir) { 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; 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, void setintfield(lua_State *L, int table,
const char *fieldname, int value) 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, std::string checkstringfield(lua_State *L, int table,
const char *fieldname); const char *fieldname);
void setstringfield(lua_State *L, int table,
const char *fieldname, const char *value);
void setintfield(lua_State *L, int table, void setintfield(lua_State *L, int table,
const char *fieldname, int value); const char *fieldname, int value);
void setfloatfield(lua_State *L, int table, 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_util.cpp
${CMAKE_CURRENT_SOURCE_DIR}/l_vmanip.cpp ${CMAKE_CURRENT_SOURCE_DIR}/l_vmanip.cpp
${CMAKE_CURRENT_SOURCE_DIR}/l_settings.cpp ${CMAKE_CURRENT_SOURCE_DIR}/l_settings.cpp
${CMAKE_CURRENT_SOURCE_DIR}/l_http.cpp
PARENT_SCOPE) PARENT_SCOPE)
set(client_SCRIPT_LUA_API_SRCS 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) int ModApiUtil::l_request_insecure_environment(lua_State *L)
{ {
NO_MAP_LOCK_REQUIRED; NO_MAP_LOCK_REQUIRED;
// Just return _G if security is disabled
if (!ScriptApiSecurity::isSecure(L)) { if (!ScriptApiSecurity::isSecure(L)) {
lua_getglobal(L, "_G"); lua_getglobal(L, "_G");
return 1; 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); lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_CURRENT_MOD_NAME);
if (!lua_isstring(L, -1)) { if (!lua_isstring(L, -1)) {
lua_pushnil(L); return 0;
return 1;
} }
// Check secure.trusted_mods
const char *mod_name = lua_tostring(L, -1); const char *mod_name = lua_tostring(L, -1);
std::string trusted_mods = g_settings->get("secure.trusted_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 = str_split(trusted_mods, ','); std::vector<std::string> mod_list = str_split(trusted_mods, ',');
if (std::find(mod_list.begin(), mod_list.end(), mod_name) == mod_list.end()) { if (std::find(mod_list.begin(), mod_list.end(), mod_name) ==
lua_pushnil(L); mod_list.end()) {
return 1; return 0;
} }
// Push insecure environment
lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_GLOBALS_BACKUP); lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_GLOBALS_BACKUP);
return 1; 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_util.h"
#include "lua_api/l_vmanip.h" #include "lua_api/l_vmanip.h"
#include "lua_api/l_settings.h" #include "lua_api/l_settings.h"
#include "lua_api/l_http.h"
extern "C" { extern "C" {
#include "lualib.h" #include "lualib.h"
@ -89,6 +90,7 @@ void GameScripting::InitializeModApi(lua_State *L, int top)
ModApiRollback::Initialize(L, top); ModApiRollback::Initialize(L, top);
ModApiServer::Initialize(L, top); ModApiServer::Initialize(L, top);
ModApiUtil::Initialize(L, top); ModApiUtil::Initialize(L, top);
ModApiHttp::Initialize(L, top);
// Register reference classes (userdata) // Register reference classes (userdata)
InvRef::Register(L); 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("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("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("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("FSAA");
gettext("Experimental option, might cause visible spaces between blocks\nwhen set to higher number than 0."); gettext("Experimental option, might cause visible spaces between blocks\nwhen set to higher number than 0.");
gettext("Shaders"); gettext("Shaders");

Binary file not shown.

After

Width:  |  Height:  |  Size: 663 B