Merge
This commit is contained in:
parent
ae3d7c3ebc
commit
fe70a72fe6
@ -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
|
||||
|
154
src/camera.cpp
154
src/camera.cpp
@ -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) {
|
||||
|
16
src/camera.h
16
src/camera.h
@ -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;
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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();
|
||||
|
@ -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;*/
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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()));
|
||||
|
159
src/game.cpp
159
src/game.cpp
@ -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;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -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()
|
||||
|
@ -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.
|
||||
|
@ -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{
|
||||
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
////
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
176
src/script/lua_api/l_http.cpp
Normal file
176
src/script/lua_api/l_http.cpp
Normal 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
|
||||
}
|
50
src/script/lua_api/l_http.h
Normal file
50
src/script/lua_api/l_http.h
Normal 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_ */
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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");
|
||||
|
BIN
textures/base/pack/object_marker_red.png
Normal file
BIN
textures/base/pack/object_marker_red.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 663 B |
Loading…
x
Reference in New Issue
Block a user