diff --git a/builtin/settingtypes.txt b/builtin/settingtypes.txt index 080a57888..b8b864c8b 100644 --- a/builtin/settingtypes.txt +++ b/builtin/settingtypes.txt @@ -574,7 +574,7 @@ fullscreen_bpp (Full screen BPP) int 24 vsync (V-Sync) bool false # Field of view in degrees. -fov (Field of view) int 72 30 160 +fov (Field of view) int 72 45 160 # Adjust the gamma encoding for the light tables. Higher numbers are brighter. # This setting is for the client only and is ignored by the server. diff --git a/src/camera.cpp b/src/camera.cpp index ebb154137..1bbdb56ea 100644 --- a/src/camera.cpp +++ b/src/camera.cpp @@ -71,7 +71,9 @@ Camera::Camera(MapDrawControl &draw_control, Client *client): */ m_cache_fall_bobbing_amount = g_settings->getFloat("fall_bobbing_amount"); m_cache_view_bobbing_amount = g_settings->getFloat("view_bobbing_amount"); - m_cache_fov = g_settings->getFloat("fov"); + // 45 degrees is the lowest FOV that doesn't cause the server to treat this + // as a zoom FOV and load world beyond the set server limits. + m_cache_fov = std::fmax(g_settings->getFloat("fov"), 45.0f); m_arm_inertia = g_settings->getBool("arm_inertia"); m_nametags.clear(); } diff --git a/src/clientiface.cpp b/src/clientiface.cpp index 3a6caf800..8c429976b 100644 --- a/src/clientiface.cpp +++ b/src/clientiface.cpp @@ -192,17 +192,35 @@ void RemoteClient::GetNextBlocks ( */ s32 new_nearest_unsent_d = -1; - // get view range and camera fov from the client + // Get view range and camera fov (radians) from the client s16 wanted_range = sao->getWantedRange() + 1; float camera_fov = sao->getFov(); - const s16 full_d_max = std::min(adjustDist(m_max_send_distance, camera_fov), wanted_range); - const s16 d_opt = std::min(adjustDist(m_block_optimize_distance, camera_fov), wanted_range); + // If below the heuristic zoom threshold (see adjustDist() in numeric.cpp) + // distrust client-sent FOV and get server-set player object property + // zoom FOV (degrees) as a check to avoid hacked clients using FOV to load + // distant world. + // 0.888 radians is slightly larger than the zoom threshold of 1.775 / 2 + // radians. + if (camera_fov < 0.888f) { + float prop_zoom_fov = sao->getZoomFOV(); + // If zoom is disabled by value 0 + if (prop_zoom_fov < 0.001f) + camera_fov = 0.888f; + else + // Degrees -> radians + camera_fov = prop_zoom_fov * core::DEGTORAD; + } + + const s16 full_d_max = std::min(adjustDist(m_max_send_distance, camera_fov), + wanted_range); + const s16 d_opt = std::min(adjustDist(m_block_optimize_distance, camera_fov), + wanted_range); const s16 d_blocks_in_sight = full_d_max * BS * MAP_BLOCKSIZE; - //infostream << "Fov from client " << camera_fov << " full_d_max " << full_d_max << std::endl; s16 d_max = full_d_max; - s16 d_max_gen = std::min(adjustDist(m_max_gen_distance, camera_fov), wanted_range); + s16 d_max_gen = std::min(adjustDist(m_max_gen_distance, camera_fov), + wanted_range); // Don't loop very much at a time, adjust with distance, // do more work per RTT with greater distances. diff --git a/src/content_sao.cpp b/src/content_sao.cpp index 3ea219846..c554b775d 100644 --- a/src/content_sao.cpp +++ b/src/content_sao.cpp @@ -1473,3 +1473,8 @@ bool PlayerSAO::getSelectionBox(aabb3f *toset) const return true; } + +float PlayerSAO::getZoomFOV() const +{ + return m_prop.zoom_fov; +} diff --git a/src/content_sao.h b/src/content_sao.h index 6583f31d6..59e3b3d4b 100644 --- a/src/content_sao.h +++ b/src/content_sao.h @@ -330,6 +330,7 @@ public: v3f getEyePosition() const { return m_base_position + getEyeOffset(); } v3f getEyeOffset() const; + float getZoomFOV() const; inline Metadata &getMeta() { return m_meta; }