FOV: Raise lower limit to avoid zoom-loading of distant world (#7234)
authorParamat <paramat@users.noreply.github.com>
Sun, 15 Apr 2018 20:56:05 +0000 (21:56 +0100)
committerGitHub <noreply@github.com>
Sun, 15 Apr 2018 20:56:05 +0000 (21:56 +0100)
In the client, raise lower limit from 30 to 45 degrees, to avoid server
seeing this as a zoom and loading world beyond the server-set limit.
Add minimum in settingtypes.txt and enforce lower limit when set using
minetest.conf.

In the server, distrust the client-sent FOV if below the heuristic zoom
threshold and use the player object property 'zoom_fov' to check it, to
protect against hacked clients.

builtin/settingtypes.txt
src/camera.cpp
src/clientiface.cpp
src/content_sao.cpp
src/content_sao.h

index 080a57888fbaa7cd975c859805ac3beaa6cb4151..b8b864c8b2bbf3f71447a5b75c77dbca2dd75eb7 100644 (file)
@@ -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.
index ebb1541375720f310bfbbaa13ee94c82ae346a0e..1bbdb56eac7bd45836b57025989c712e438b35f5 100644 (file)
@@ -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();
 }
index 3a6caf8004ece7754b8ea09364fbc9c232e80e4e..8c429976be025cc650f35c0765d7ff3893f60b79 100644 (file)
@@ -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.
index 3ea219846706a2b4c9dd416bb91f8ec6cfe4e9b0..c554b775d80daf3935d54a2ea1ef372cf5ecfe8e 100644 (file)
@@ -1473,3 +1473,8 @@ bool PlayerSAO::getSelectionBox(aabb3f *toset) const
 
        return true;
 }
+
+float PlayerSAO::getZoomFOV() const
+{
+       return m_prop.zoom_fov;
+}
index 6583f31d659c82a3b4ef04ddf465a1bb4818307f..59e3b3d4ba0edb3d17624e0c5a073261298fcb71 100644 (file)
@@ -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; }