forked from Mirrorlandia_minetest/minetest
set_fov: Add support for time-based transitions (#9705)
This commit is contained in:
parent
ac368af4fe
commit
e0ea87f1f3
@ -5998,15 +5998,18 @@ object you are working with still exists.
|
|||||||
* max: bubbles bar is not shown
|
* max: bubbles bar is not shown
|
||||||
* See [Object properties] for more information
|
* See [Object properties] for more information
|
||||||
* Is limited to range 0 ... 65535 (2^16 - 1)
|
* Is limited to range 0 ... 65535 (2^16 - 1)
|
||||||
* `set_fov(fov, is_multiplier)`: Sets player's FOV
|
* `set_fov(fov, is_multiplier, transition_time)`: Sets player's FOV
|
||||||
* `fov`: FOV value.
|
* `fov`: FOV value.
|
||||||
* `is_multiplier`: Set to `true` if the FOV value is a multiplier.
|
* `is_multiplier`: Set to `true` if the FOV value is a multiplier.
|
||||||
Defaults to `false`.
|
Defaults to `false`.
|
||||||
* Set to 0 to clear FOV override.
|
* `transition_time`: If defined, enables smooth FOV transition.
|
||||||
* `get_fov()`:
|
Interpreted as the time (in seconds) to reach target FOV.
|
||||||
* Returns player's FOV override in degrees, and a boolean depending on whether
|
If set to 0, FOV change is instantaneous. Defaults to 0.
|
||||||
the value is a multiplier.
|
* Set `fov` to 0 to clear FOV override.
|
||||||
* Returns 0 as first value if player's FOV hasn't been overridden.
|
* `get_fov()`: Returns the following:
|
||||||
|
* Server-sent FOV value. Returns 0 if an FOV override doesn't exist.
|
||||||
|
* Boolean indicating whether the FOV value is a multiplier.
|
||||||
|
* Time (in seconds) taken for the FOV transition. Set by `set_fov`.
|
||||||
* `set_attribute(attribute, value)`: DEPRECATED, use get_meta() instead
|
* `set_attribute(attribute, value)`: DEPRECATED, use get_meta() instead
|
||||||
* Sets an extra attribute with value on player.
|
* Sets an extra attribute with value on player.
|
||||||
* `value` must be a string, or a number which will be converted to a
|
* `value` must be a string, or a number which will be converted to a
|
||||||
|
@ -86,6 +86,51 @@ Camera::~Camera()
|
|||||||
m_wieldmgr->drop();
|
m_wieldmgr->drop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Camera::notifyFovChange()
|
||||||
|
{
|
||||||
|
LocalPlayer *player = m_client->getEnv().getLocalPlayer();
|
||||||
|
assert(player);
|
||||||
|
|
||||||
|
PlayerFovSpec spec = player->getFov();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Update m_old_fov_degrees first - it serves as the starting point of the
|
||||||
|
* upcoming transition.
|
||||||
|
*
|
||||||
|
* If an FOV transition is already active, mark current FOV as the start of
|
||||||
|
* the new transition. If not, set it to the previous transition's target FOV.
|
||||||
|
*/
|
||||||
|
if (m_fov_transition_active)
|
||||||
|
m_old_fov_degrees = m_curr_fov_degrees;
|
||||||
|
else
|
||||||
|
m_old_fov_degrees = m_server_sent_fov ? m_target_fov_degrees : m_cache_fov;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Update m_server_sent_fov next - it corresponds to the target FOV of the
|
||||||
|
* upcoming transition.
|
||||||
|
*
|
||||||
|
* Set it to m_cache_fov, if server-sent FOV is 0. Otherwise check if
|
||||||
|
* server-sent FOV is a multiplier, and multiply it with m_cache_fov instead
|
||||||
|
* of overriding.
|
||||||
|
*/
|
||||||
|
if (spec.fov == 0.0f) {
|
||||||
|
m_server_sent_fov = false;
|
||||||
|
m_target_fov_degrees = m_cache_fov;
|
||||||
|
} else {
|
||||||
|
m_server_sent_fov = true;
|
||||||
|
m_target_fov_degrees = spec.is_multiplier ? m_cache_fov * spec.fov : spec.fov;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (spec.transition_time > 0.0f)
|
||||||
|
m_fov_transition_active = true;
|
||||||
|
|
||||||
|
// If FOV smooth transition is active, initialize required variables
|
||||||
|
if (m_fov_transition_active) {
|
||||||
|
m_transition_time = spec.transition_time;
|
||||||
|
m_fov_diff = m_target_fov_degrees - m_old_fov_degrees;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool Camera::successfullyCreated(std::string &error_message)
|
bool Camera::successfullyCreated(std::string &error_message)
|
||||||
{
|
{
|
||||||
if (!m_playernode) {
|
if (!m_playernode) {
|
||||||
@ -462,33 +507,38 @@ void Camera::update(LocalPlayer* player, f32 frametime, f32 busytime, f32 tool_r
|
|||||||
m_camera_position = my_cp;
|
m_camera_position = my_cp;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Apply server-sent FOV. If server doesn't enforce FOV,
|
* Apply server-sent FOV, instantaneous or smooth transition.
|
||||||
* check for zoom and set to zoom FOV.
|
* If not, check for zoom and set to zoom FOV.
|
||||||
* Otherwise, default to m_cache_fov
|
* Otherwise, default to m_cache_fov.
|
||||||
*/
|
*/
|
||||||
|
if (m_fov_transition_active) {
|
||||||
|
// Smooth FOV transition
|
||||||
|
// Dynamically calculate FOV delta based on frametimes
|
||||||
|
f32 delta = (frametime / m_transition_time) * m_fov_diff;
|
||||||
|
m_curr_fov_degrees += delta;
|
||||||
|
|
||||||
f32 fov_degrees;
|
// Mark transition as complete if target FOV has been reached
|
||||||
PlayerFovSpec fov_spec = player->getFov();
|
if ((m_fov_diff > 0.0f && m_curr_fov_degrees >= m_target_fov_degrees) ||
|
||||||
if (fov_spec.fov > 0.0f) {
|
(m_fov_diff < 0.0f && m_curr_fov_degrees <= m_target_fov_degrees)) {
|
||||||
// If server-sent FOV is a multiplier, multiply
|
m_fov_transition_active = false;
|
||||||
// it with m_cache_fov instead of overriding
|
m_curr_fov_degrees = m_target_fov_degrees;
|
||||||
if (fov_spec.is_multiplier)
|
}
|
||||||
fov_degrees = m_cache_fov * fov_spec.fov;
|
} else if (m_server_sent_fov) {
|
||||||
else
|
// Instantaneous FOV change
|
||||||
fov_degrees = fov_spec.fov;
|
m_curr_fov_degrees = m_target_fov_degrees;
|
||||||
} else if (player->getPlayerControl().zoom && player->getZoomFOV() > 0.001f) {
|
} else if (player->getPlayerControl().zoom && player->getZoomFOV() > 0.001f) {
|
||||||
// Player requests zoom, apply zoom FOV
|
// Player requests zoom, apply zoom FOV
|
||||||
fov_degrees = player->getZoomFOV();
|
m_curr_fov_degrees = player->getZoomFOV();
|
||||||
} else {
|
} else {
|
||||||
// Set to client's selected FOV
|
// Set to client's selected FOV
|
||||||
fov_degrees = m_cache_fov;
|
m_curr_fov_degrees = m_cache_fov;
|
||||||
}
|
}
|
||||||
fov_degrees = rangelim(fov_degrees, 1.0f, 160.0f);
|
m_curr_fov_degrees = rangelim(m_curr_fov_degrees, 1.0f, 160.0f);
|
||||||
|
|
||||||
// FOV and aspect ratio
|
// FOV and aspect ratio
|
||||||
const v2u32 &window_size = RenderingEngine::get_instance()->getWindowSize();
|
const v2u32 &window_size = RenderingEngine::get_instance()->getWindowSize();
|
||||||
m_aspect = (f32) window_size.X / (f32) window_size.Y;
|
m_aspect = (f32) window_size.X / (f32) window_size.Y;
|
||||||
m_fov_y = fov_degrees * M_PI / 180.0;
|
m_fov_y = m_curr_fov_degrees * M_PI / 180.0;
|
||||||
// Increase vertical FOV on lower aspect ratios (<16:10)
|
// Increase vertical FOV on lower aspect ratios (<16:10)
|
||||||
m_fov_y *= MYMAX(1.0, MYMIN(1.4, sqrt(16./10. / m_aspect)));
|
m_fov_y *= MYMAX(1.0, MYMIN(1.4, sqrt(16./10. / m_aspect)));
|
||||||
m_fov_x = 2 * atan(m_aspect * tan(0.5 * m_fov_y));
|
m_fov_x = 2 * atan(m_aspect * tan(0.5 * m_fov_y));
|
||||||
|
@ -112,6 +112,9 @@ public:
|
|||||||
return MYMAX(m_fov_x, m_fov_y);
|
return MYMAX(m_fov_x, m_fov_y);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Notify about new server-sent FOV and initialize smooth FOV transition
|
||||||
|
void notifyFovChange();
|
||||||
|
|
||||||
// Checks if the constructor was able to create the scene nodes
|
// Checks if the constructor was able to create the scene nodes
|
||||||
bool successfullyCreated(std::string &error_message);
|
bool successfullyCreated(std::string &error_message);
|
||||||
|
|
||||||
@ -186,6 +189,9 @@ private:
|
|||||||
|
|
||||||
Client *m_client;
|
Client *m_client;
|
||||||
|
|
||||||
|
// Default Client FOV (as defined by the "fov" setting)
|
||||||
|
f32 m_cache_fov;
|
||||||
|
|
||||||
// Absolute camera position
|
// Absolute camera position
|
||||||
v3f m_camera_position;
|
v3f m_camera_position;
|
||||||
// Absolute camera direction
|
// Absolute camera direction
|
||||||
@ -193,6 +199,14 @@ private:
|
|||||||
// Camera offset
|
// Camera offset
|
||||||
v3s16 m_camera_offset;
|
v3s16 m_camera_offset;
|
||||||
|
|
||||||
|
// Server-sent FOV variables
|
||||||
|
bool m_server_sent_fov = false;
|
||||||
|
f32 m_curr_fov_degrees, m_old_fov_degrees, m_target_fov_degrees;
|
||||||
|
|
||||||
|
// FOV transition variables
|
||||||
|
bool m_fov_transition_active = false;
|
||||||
|
f32 m_fov_diff, m_transition_time;
|
||||||
|
|
||||||
v2f m_wieldmesh_offset = v2f(55.0f, -35.0f);
|
v2f m_wieldmesh_offset = v2f(55.0f, -35.0f);
|
||||||
v2f m_arm_dir;
|
v2f m_arm_dir;
|
||||||
v2f m_cam_vel;
|
v2f m_cam_vel;
|
||||||
@ -230,7 +244,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_fov;
|
|
||||||
bool m_arm_inertia;
|
bool m_arm_inertia;
|
||||||
|
|
||||||
std::list<Nametag *> m_nametags;
|
std::list<Nametag *> m_nametags;
|
||||||
|
@ -20,6 +20,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
#include "client/client.h"
|
#include "client/client.h"
|
||||||
|
|
||||||
#include "util/base64.h"
|
#include "util/base64.h"
|
||||||
|
#include "client/camera.h"
|
||||||
#include "chatmessage.h"
|
#include "chatmessage.h"
|
||||||
#include "client/clientmedia.h"
|
#include "client/clientmedia.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
@ -530,11 +531,21 @@ void Client::handleCommand_Movement(NetworkPacket* pkt)
|
|||||||
void Client::handleCommand_Fov(NetworkPacket *pkt)
|
void Client::handleCommand_Fov(NetworkPacket *pkt)
|
||||||
{
|
{
|
||||||
f32 fov;
|
f32 fov;
|
||||||
bool is_multiplier;
|
bool is_multiplier = false;
|
||||||
|
f32 transition_time = 0.0f;
|
||||||
|
|
||||||
*pkt >> fov >> is_multiplier;
|
*pkt >> fov >> is_multiplier;
|
||||||
|
|
||||||
|
// Wrap transition_time extraction within a
|
||||||
|
// try-catch to preserve backwards compat
|
||||||
|
try {
|
||||||
|
*pkt >> transition_time;
|
||||||
|
} catch (PacketError &e) {};
|
||||||
|
|
||||||
LocalPlayer *player = m_env.getLocalPlayer();
|
LocalPlayer *player = m_env.getLocalPlayer();
|
||||||
player->setFov({ fov, is_multiplier });
|
assert(player);
|
||||||
|
player->setFov({ fov, is_multiplier, transition_time });
|
||||||
|
m_camera->notifyFovChange();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Client::handleCommand_HP(NetworkPacket *pkt)
|
void Client::handleCommand_HP(NetworkPacket *pkt)
|
||||||
|
@ -384,8 +384,9 @@ enum ToClientCommand
|
|||||||
/*
|
/*
|
||||||
Sends an FOV override/multiplier to client.
|
Sends an FOV override/multiplier to client.
|
||||||
|
|
||||||
float fov
|
f32 fov
|
||||||
bool is_multiplier
|
bool is_multiplier
|
||||||
|
f32 transition_time
|
||||||
*/
|
*/
|
||||||
|
|
||||||
TOCLIENT_DEATHSCREEN = 0x37,
|
TOCLIENT_DEATHSCREEN = 0x37,
|
||||||
|
12
src/player.h
12
src/player.h
@ -35,7 +35,13 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
struct PlayerFovSpec
|
struct PlayerFovSpec
|
||||||
{
|
{
|
||||||
f32 fov;
|
f32 fov;
|
||||||
|
|
||||||
|
// Whether to multiply the client's FOV or to override it
|
||||||
bool is_multiplier;
|
bool is_multiplier;
|
||||||
|
|
||||||
|
// The time to be take to trasition to the new FOV value.
|
||||||
|
// Transition is instantaneous if omitted. Omitted by default.
|
||||||
|
f32 transition_time;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct PlayerControl
|
struct PlayerControl
|
||||||
@ -186,12 +192,12 @@ public:
|
|||||||
|
|
||||||
void setFov(const PlayerFovSpec &spec)
|
void setFov(const PlayerFovSpec &spec)
|
||||||
{
|
{
|
||||||
m_fov_spec = spec;
|
m_fov_override_spec = spec;
|
||||||
}
|
}
|
||||||
|
|
||||||
const PlayerFovSpec &getFov() const
|
const PlayerFovSpec &getFov() const
|
||||||
{
|
{
|
||||||
return m_fov_spec;
|
return m_fov_override_spec;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 keyPressed = 0;
|
u32 keyPressed = 0;
|
||||||
@ -208,7 +214,7 @@ protected:
|
|||||||
char m_name[PLAYERNAME_SIZE];
|
char m_name[PLAYERNAME_SIZE];
|
||||||
v3f m_speed;
|
v3f m_speed;
|
||||||
u16 m_wield_index = 0;
|
u16 m_wield_index = 0;
|
||||||
PlayerFovSpec m_fov_spec = { 0.0f, false };
|
PlayerFovSpec m_fov_override_spec = { 0.0f, false, 0.0f };
|
||||||
|
|
||||||
std::vector<HudElement *> hud;
|
std::vector<HudElement *> hud;
|
||||||
private:
|
private:
|
||||||
|
@ -1249,7 +1249,7 @@ int ObjectRef::l_set_look_yaw(lua_State *L)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// set_fov(self, degrees[, is_multiplier])
|
// set_fov(self, degrees[, is_multiplier, transition_time])
|
||||||
int ObjectRef::l_set_fov(lua_State *L)
|
int ObjectRef::l_set_fov(lua_State *L)
|
||||||
{
|
{
|
||||||
NO_MAP_LOCK_REQUIRED;
|
NO_MAP_LOCK_REQUIRED;
|
||||||
@ -1258,7 +1258,11 @@ int ObjectRef::l_set_fov(lua_State *L)
|
|||||||
if (!player)
|
if (!player)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
player->setFov({ static_cast<f32>(luaL_checknumber(L, 2)), readParam<bool>(L, 3) });
|
player->setFov({
|
||||||
|
static_cast<f32>(luaL_checknumber(L, 2)),
|
||||||
|
readParam<bool>(L, 3, false),
|
||||||
|
lua_isnumber(L, 4) ? static_cast<f32>(luaL_checknumber(L, 4)) : 0.0f
|
||||||
|
});
|
||||||
getServer(L)->SendPlayerFov(player->getPeerId());
|
getServer(L)->SendPlayerFov(player->getPeerId());
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -1276,8 +1280,9 @@ int ObjectRef::l_get_fov(lua_State *L)
|
|||||||
PlayerFovSpec fov_spec = player->getFov();
|
PlayerFovSpec fov_spec = player->getFov();
|
||||||
lua_pushnumber(L, fov_spec.fov);
|
lua_pushnumber(L, fov_spec.fov);
|
||||||
lua_pushboolean(L, fov_spec.is_multiplier);
|
lua_pushboolean(L, fov_spec.is_multiplier);
|
||||||
|
lua_pushnumber(L, fov_spec.transition_time);
|
||||||
|
|
||||||
return 2;
|
return 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
// set_breath(self, breath)
|
// set_breath(self, breath)
|
||||||
|
@ -1892,10 +1892,10 @@ void Server::SendMovePlayer(session_t peer_id)
|
|||||||
|
|
||||||
void Server::SendPlayerFov(session_t peer_id)
|
void Server::SendPlayerFov(session_t peer_id)
|
||||||
{
|
{
|
||||||
NetworkPacket pkt(TOCLIENT_FOV, 4 + 1, peer_id);
|
NetworkPacket pkt(TOCLIENT_FOV, 4 + 1 + 4, peer_id);
|
||||||
|
|
||||||
PlayerFovSpec fov_spec = m_env->getPlayer(peer_id)->getFov();
|
PlayerFovSpec fov_spec = m_env->getPlayer(peer_id)->getFov();
|
||||||
pkt << fov_spec.fov << fov_spec.is_multiplier;
|
pkt << fov_spec.fov << fov_spec.is_multiplier << fov_spec.transition_time;
|
||||||
|
|
||||||
Send(&pkt);
|
Send(&pkt);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user