mirror of
https://github.com/minetest/minetest.git
synced 2025-03-06 20:48:40 +01:00
Basic camera control API (#15796)
This commit is contained in:
parent
50819ace8f
commit
ba62808fe8
18 changed files with 162 additions and 42 deletions
|
@ -8827,6 +8827,14 @@ child will follow movement and rotation of that bone.
|
|||
Same limits as for `thirdperson_back` apply.
|
||||
Defaults to `thirdperson_back` if unspecified.
|
||||
* `get_eye_offset()`: Returns camera offset vectors as set via `set_eye_offset`.
|
||||
* `set_camera(params)`: Sets camera parameters.
|
||||
* `mode`: Defines the camera mode used
|
||||
- `any`: free choice between all modes (default)
|
||||
- `first`: first-person camera
|
||||
- `third`: third-person camera
|
||||
- `third_front`: third-person camera, looking opposite of movement direction
|
||||
* Supported by client since 5.12.0.
|
||||
* `get_camera()`: Returns the camera parameters as a table as above.
|
||||
* `send_mapblock(blockpos)`:
|
||||
* Sends an already loaded mapblock to the player.
|
||||
* Returns `false` if nothing was sent (note that this can also mean that
|
||||
|
|
|
@ -375,6 +375,9 @@ void Camera::update(LocalPlayer* player, f32 frametime, f32 tool_reload_ratio)
|
|||
{
|
||||
v3f eye_offset = player->getEyeOffset();
|
||||
switch(m_camera_mode) {
|
||||
case CAMERA_MODE_ANY:
|
||||
assert(false);
|
||||
break;
|
||||
case CAMERA_MODE_FIRST:
|
||||
eye_offset += player->eye_offset_first;
|
||||
break;
|
||||
|
|
|
@ -57,8 +57,6 @@ struct Nametag
|
|||
}
|
||||
};
|
||||
|
||||
enum CameraMode {CAMERA_MODE_FIRST, CAMERA_MODE_THIRD, CAMERA_MODE_THIRD_FRONT};
|
||||
|
||||
/*
|
||||
Client camera class, manages the player and camera scene nodes, the viewing distance
|
||||
and performs view bobbing etc. It also displays the wielded tool in front of the
|
||||
|
@ -169,7 +167,8 @@ public:
|
|||
void drawWieldedTool(irr::core::matrix4* translation=NULL);
|
||||
|
||||
// Toggle the current camera mode
|
||||
void toggleCameraMode() {
|
||||
void toggleCameraMode()
|
||||
{
|
||||
if (m_camera_mode == CAMERA_MODE_FIRST)
|
||||
m_camera_mode = CAMERA_MODE_THIRD;
|
||||
else if (m_camera_mode == CAMERA_MODE_THIRD)
|
||||
|
@ -185,7 +184,7 @@ public:
|
|||
}
|
||||
|
||||
//read the current camera mode
|
||||
inline CameraMode getCameraMode()
|
||||
inline CameraMode getCameraMode() const
|
||||
{
|
||||
return m_camera_mode;
|
||||
}
|
||||
|
|
|
@ -217,6 +217,7 @@ public:
|
|||
void handleCommand_MediaPush(NetworkPacket *pkt);
|
||||
void handleCommand_MinimapModes(NetworkPacket *pkt);
|
||||
void handleCommand_SetLighting(NetworkPacket *pkt);
|
||||
void handleCommand_Camera(NetworkPacket* pkt);
|
||||
|
||||
void ProcessData(NetworkPacket *pkt);
|
||||
|
||||
|
|
|
@ -36,6 +36,7 @@ enum ClientEventType : u8
|
|||
CE_SET_STARS,
|
||||
CE_OVERRIDE_DAY_NIGHT_RATIO,
|
||||
CE_CLOUD_PARAMS,
|
||||
CE_UPDATE_CAMERA,
|
||||
CLIENTEVENT_MAX,
|
||||
};
|
||||
|
||||
|
@ -66,11 +67,14 @@ struct ClientEventHudChange
|
|||
|
||||
struct ClientEvent
|
||||
{
|
||||
// TODO: should get rid of this ctor
|
||||
ClientEvent() : type(CE_NONE) {}
|
||||
|
||||
ClientEvent(ClientEventType type) : type(type) {}
|
||||
|
||||
ClientEventType type;
|
||||
union
|
||||
{
|
||||
// struct{
|
||||
//} none;
|
||||
struct
|
||||
{
|
||||
u16 amount;
|
||||
|
@ -86,8 +90,6 @@ struct ClientEvent
|
|||
std::string *formspec;
|
||||
std::string *formname;
|
||||
} show_formspec;
|
||||
// struct{
|
||||
//} textures_updated;
|
||||
ParticleParameters *spawn_particle;
|
||||
struct
|
||||
{
|
||||
|
|
|
@ -564,6 +564,7 @@ protected:
|
|||
void updatePauseState();
|
||||
void step(f32 dtime);
|
||||
void processClientEvents(CameraOrientation *cam);
|
||||
void updateCameraMode(); // call after changing it
|
||||
void updateCameraOffset();
|
||||
void updateCamera(f32 dtime);
|
||||
void updateSound(f32 dtime);
|
||||
|
@ -665,6 +666,7 @@ private:
|
|||
void handleClientEvent_OverrideDayNigthRatio(ClientEvent *event,
|
||||
CameraOrientation *cam);
|
||||
void handleClientEvent_CloudParams(ClientEvent *event, CameraOrientation *cam);
|
||||
void handleClientEvent_UpdateCamera(ClientEvent *event, CameraOrientation *cam);
|
||||
|
||||
void updateChat(f32 dtime);
|
||||
|
||||
|
@ -1921,6 +1923,9 @@ void Game::processKeyInput()
|
|||
toggleFog();
|
||||
} else if (wasKeyDown(KeyType::TOGGLE_UPDATE_CAMERA)) {
|
||||
toggleUpdateCamera();
|
||||
} else if (wasKeyPressed(KeyType::CAMERA_MODE)) {
|
||||
camera->toggleCameraMode();
|
||||
updateCameraMode();
|
||||
} else if (wasKeyPressed(KeyType::TOGGLE_DEBUG)) {
|
||||
toggleDebug();
|
||||
} else if (wasKeyPressed(KeyType::TOGGLE_PROFILER)) {
|
||||
|
@ -2575,6 +2580,7 @@ const ClientEventHandler Game::clientEventHandler[CLIENTEVENT_MAX] = {
|
|||
{&Game::handleClientEvent_SetStars},
|
||||
{&Game::handleClientEvent_OverrideDayNigthRatio},
|
||||
{&Game::handleClientEvent_CloudParams},
|
||||
{&Game::handleClientEvent_UpdateCamera},
|
||||
};
|
||||
|
||||
void Game::handleClientEvent_None(ClientEvent *event, CameraOrientation *cam)
|
||||
|
@ -2879,6 +2885,13 @@ void Game::handleClientEvent_CloudParams(ClientEvent *event, CameraOrientation *
|
|||
clouds->setSpeed(v2f(event->cloud_params.speed_x, event->cloud_params.speed_y));
|
||||
}
|
||||
|
||||
void Game::handleClientEvent_UpdateCamera(ClientEvent *event, CameraOrientation *cam)
|
||||
{
|
||||
// no parameters to update here, this just makes sure the camera is in the
|
||||
// state it should be after something was changed.
|
||||
updateCameraMode();
|
||||
}
|
||||
|
||||
void Game::processClientEvents(CameraOrientation *cam)
|
||||
{
|
||||
while (client->hasClientEvents()) {
|
||||
|
@ -2935,12 +2948,7 @@ void Game::updateCamera(f32 dtime)
|
|||
ClientEnvironment &env = client->getEnv();
|
||||
LocalPlayer *player = env.getLocalPlayer();
|
||||
|
||||
/*
|
||||
For interaction purposes, get info about the held item
|
||||
- What item is it?
|
||||
- Is it a usable item?
|
||||
- Can it point to liquids?
|
||||
*/
|
||||
// For interaction purposes, get info about the held item
|
||||
ItemStack playeritem;
|
||||
{
|
||||
ItemStack selected, hand;
|
||||
|
@ -2950,23 +2958,6 @@ void Game::updateCamera(f32 dtime)
|
|||
ToolCapabilities playeritem_toolcap =
|
||||
playeritem.getToolCapabilities(itemdef_manager);
|
||||
|
||||
if (wasKeyPressed(KeyType::CAMERA_MODE)) {
|
||||
GenericCAO *playercao = player->getCAO();
|
||||
|
||||
// If playercao not loaded, don't change camera
|
||||
if (!playercao)
|
||||
return;
|
||||
|
||||
camera->toggleCameraMode();
|
||||
|
||||
if (g_touchcontrols)
|
||||
g_touchcontrols->setUseCrosshair(!isTouchCrosshairDisabled());
|
||||
|
||||
// Make the player visible depending on camera mode.
|
||||
playercao->updateMeshCulling();
|
||||
playercao->setChildrenVisible(camera->getCameraMode() > CAMERA_MODE_FIRST);
|
||||
}
|
||||
|
||||
float full_punch_interval = playeritem_toolcap.full_punch_interval;
|
||||
float tool_reload_ratio = runData.time_from_last_punch / full_punch_interval;
|
||||
|
||||
|
@ -2981,6 +2972,25 @@ void Game::updateCamera(f32 dtime)
|
|||
}
|
||||
}
|
||||
|
||||
void Game::updateCameraMode()
|
||||
{
|
||||
LocalPlayer *player = client->getEnv().getLocalPlayer();
|
||||
|
||||
// Obey server choice
|
||||
if (player->allowed_camera_mode != CAMERA_MODE_ANY)
|
||||
camera->setCameraMode(player->allowed_camera_mode);
|
||||
|
||||
if (g_touchcontrols)
|
||||
g_touchcontrols->setUseCrosshair(!isTouchCrosshairDisabled());
|
||||
|
||||
GenericCAO *playercao = player->getCAO();
|
||||
if (playercao) {
|
||||
// Make the player visible depending on camera mode.
|
||||
playercao->updateMeshCulling();
|
||||
playercao->setChildrenVisible(camera->getCameraMode() > CAMERA_MODE_FIRST);
|
||||
}
|
||||
}
|
||||
|
||||
void Game::updateCameraOffset()
|
||||
{
|
||||
ClientEnvironment &env = client->getEnv();
|
||||
|
@ -3057,6 +3067,9 @@ void Game::processPlayerInteraction(f32 dtime, bool show_hud)
|
|||
core::line3d<f32> shootline;
|
||||
|
||||
switch (camera->getCameraMode()) {
|
||||
case CAMERA_MODE_ANY:
|
||||
assert(false);
|
||||
break;
|
||||
case CAMERA_MODE_FIRST:
|
||||
// Shoot from camera position, with bobbing
|
||||
shootline.start = camera->getPosition();
|
||||
|
|
|
@ -83,7 +83,7 @@ const ToClientCommandHandler toClientCommandTable[TOCLIENT_NUM_MSG_TYPES] =
|
|||
{ "TOCLIENT_MOVEMENT", TOCLIENT_STATE_CONNECTED, &Client::handleCommand_Movement }, // 0x45
|
||||
{ "TOCLIENT_SPAWN_PARTICLE", TOCLIENT_STATE_CONNECTED, &Client::handleCommand_SpawnParticle }, // 0x46
|
||||
{ "TOCLIENT_ADD_PARTICLESPAWNER", TOCLIENT_STATE_CONNECTED, &Client::handleCommand_AddParticleSpawner }, // 0x47
|
||||
null_command_handler,
|
||||
{ "TOCLIENT_CAMERA", TOCLIENT_STATE_CONNECTED, &Client::handleCommand_Camera }, // 0x48
|
||||
{ "TOCLIENT_HUDADD", TOCLIENT_STATE_CONNECTED, &Client::handleCommand_HudAdd }, // 0x49
|
||||
{ "TOCLIENT_HUDRM", TOCLIENT_STATE_CONNECTED, &Client::handleCommand_HudRemove }, // 0x4a
|
||||
{ "TOCLIENT_HUDCHANGE", TOCLIENT_STATE_CONNECTED, &Client::handleCommand_HudChange }, // 0x4b
|
||||
|
|
|
@ -1530,7 +1530,19 @@ void Client::handleCommand_EyeOffset(NetworkPacket* pkt)
|
|||
*pkt >> player->eye_offset_third_front;
|
||||
} catch (PacketError &e) {
|
||||
player->eye_offset_third_front = player->eye_offset_third;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
void Client::handleCommand_Camera(NetworkPacket* pkt)
|
||||
{
|
||||
LocalPlayer *player = m_env.getLocalPlayer();
|
||||
assert(player);
|
||||
|
||||
u8 tmp;
|
||||
*pkt >> tmp;
|
||||
player->allowed_camera_mode = static_cast<CameraMode>(tmp);
|
||||
|
||||
m_client_event_queue.push(new ClientEvent(CE_UPDATE_CAMERA));
|
||||
}
|
||||
|
||||
void Client::handleCommand_UpdatePlayerList(NetworkPacket* pkt)
|
||||
|
|
|
@ -442,6 +442,11 @@ enum ToClientCommand : u16
|
|||
|
||||
*/
|
||||
|
||||
TOCLIENT_CAMERA = 0x48,
|
||||
/*
|
||||
u8 allowed_camera_mode
|
||||
*/
|
||||
|
||||
TOCLIENT_HUDADD = 0x49,
|
||||
/*
|
||||
u32 id
|
||||
|
|
|
@ -183,7 +183,7 @@ const ClientCommandFactory clientCommandFactoryTable[TOCLIENT_NUM_MSG_TYPES] =
|
|||
{ "TOCLIENT_MOVEMENT", 0, true }, // 0x45
|
||||
{ "TOCLIENT_SPAWN_PARTICLE", 0, true }, // 0x46
|
||||
{ "TOCLIENT_ADD_PARTICLESPAWNER", 0, true }, // 0x47
|
||||
null_command_factory, // 0x48
|
||||
{ "TOCLIENT_CAMERA", 0, true }, // 0x48
|
||||
{ "TOCLIENT_HUDADD", 1, true }, // 0x49
|
||||
{ "TOCLIENT_HUDRM", 1, true }, // 0x4a
|
||||
{ "TOCLIENT_HUDCHANGE", 1, true }, // 0x4b
|
||||
|
|
|
@ -20,12 +20,6 @@
|
|||
|
||||
namespace ParticleParamTypes
|
||||
{
|
||||
template <bool cond, typename T>
|
||||
using enableIf = typename std::enable_if<cond, T>::type;
|
||||
// std::enable_if_t does not appear to be present in GCC????
|
||||
// std::is_enum_v also missing. wtf. these are supposed to be
|
||||
// present as of c++14
|
||||
|
||||
template<typename T> using BlendFunction = T(float,T,T);
|
||||
#define DECL_PARAM_SRZRS(type) \
|
||||
void serializeParameterValue (std::ostream& os, type v); \
|
||||
|
@ -57,12 +51,12 @@ namespace ParticleParamTypes
|
|||
* that's hideous and unintuitive. instead, we supply the following functions to
|
||||
* transparently map enumeration types to their underlying values. */
|
||||
|
||||
template <typename E, enableIf<std::is_enum<E>::value, bool> = true>
|
||||
template <typename E, std::enable_if_t<std::is_enum_v<E>, bool> = true>
|
||||
void serializeParameterValue(std::ostream& os, E k) {
|
||||
serializeParameterValue(os, (std::underlying_type_t<E>)k);
|
||||
}
|
||||
|
||||
template <typename E, enableIf<std::is_enum<E>::value, bool> = true>
|
||||
template <typename E, std::enable_if_t<std::is_enum_v<E>, bool> = true>
|
||||
void deSerializeParameterValue(std::istream& is, E& k) {
|
||||
std::underlying_type_t<E> v;
|
||||
deSerializeParameterValue(is, v);
|
||||
|
|
|
@ -15,6 +15,13 @@
|
|||
#include "porting.h" // strlcpy
|
||||
#include <tuple>
|
||||
|
||||
const struct EnumString es_CameraMode[] = {
|
||||
{CAMERA_MODE_ANY, "any"},
|
||||
{CAMERA_MODE_FIRST, "first"},
|
||||
{CAMERA_MODE_THIRD, "third"},
|
||||
{CAMERA_MODE_THIRD_FRONT, "third_front"},
|
||||
{0, nullptr}
|
||||
};
|
||||
|
||||
bool is_valid_player_name(std::string_view name)
|
||||
{
|
||||
|
|
13
src/player.h
13
src/player.h
|
@ -126,6 +126,17 @@ struct PlayerPhysicsOverride
|
|||
}
|
||||
};
|
||||
|
||||
/// @note numeric values are part of network protocol
|
||||
enum CameraMode {
|
||||
// not a mode. indicates that any may be used.
|
||||
CAMERA_MODE_ANY = 0,
|
||||
CAMERA_MODE_FIRST,
|
||||
CAMERA_MODE_THIRD,
|
||||
CAMERA_MODE_THIRD_FRONT
|
||||
};
|
||||
|
||||
extern const struct EnumString es_CameraMode[];
|
||||
|
||||
class Map;
|
||||
struct HudElement;
|
||||
class Environment;
|
||||
|
@ -160,6 +171,8 @@ public:
|
|||
return size;
|
||||
}
|
||||
|
||||
CameraMode allowed_camera_mode = CAMERA_MODE_ANY;
|
||||
|
||||
v3f eye_offset_first;
|
||||
v3f eye_offset_third;
|
||||
v3f eye_offset_third_front;
|
||||
|
|
|
@ -492,6 +492,39 @@ int ObjectRef::l_get_eye_offset(lua_State *L)
|
|||
return 3;
|
||||
}
|
||||
|
||||
int ObjectRef::l_set_camera(lua_State *L)
|
||||
{
|
||||
NO_MAP_LOCK_REQUIRED;
|
||||
ObjectRef *ref = checkObject<ObjectRef>(L, 1);
|
||||
RemotePlayer *player = getplayer(ref);
|
||||
if (player == nullptr)
|
||||
return 0;
|
||||
|
||||
luaL_checktype(L, 2, LUA_TTABLE);
|
||||
|
||||
lua_getfield(L, -1, "mode");
|
||||
if (lua_isstring(L, -1))
|
||||
string_to_enum(es_CameraMode, player->allowed_camera_mode, lua_tostring(L, -1));
|
||||
lua_pop(L, 1);
|
||||
|
||||
getServer(L)->SendCamera(player->getPeerId(), player);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ObjectRef::l_get_camera(lua_State *L)
|
||||
{
|
||||
NO_MAP_LOCK_REQUIRED;
|
||||
ObjectRef *ref = checkObject<ObjectRef>(L, 1);
|
||||
RemotePlayer *player = getplayer(ref);
|
||||
if (player == nullptr)
|
||||
return 0;
|
||||
|
||||
lua_newtable(L);
|
||||
setstringfield(L, -1, "mode", enum_to_string(es_CameraMode, player->allowed_camera_mode));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
// send_mapblock(self, pos)
|
||||
int ObjectRef::l_send_mapblock(lua_State *L)
|
||||
{
|
||||
|
@ -2900,6 +2933,8 @@ luaL_Reg ObjectRef::methods[] = {
|
|||
luamethod(ObjectRef, respawn),
|
||||
luamethod(ObjectRef, set_flags),
|
||||
luamethod(ObjectRef, get_flags),
|
||||
luamethod(ObjectRef, set_camera),
|
||||
luamethod(ObjectRef, get_camera),
|
||||
|
||||
{0,0}
|
||||
};
|
||||
|
|
|
@ -378,6 +378,12 @@ private:
|
|||
// get_eye_offset(self)
|
||||
static int l_get_eye_offset(lua_State *L);
|
||||
|
||||
// set_camera(self, {params})
|
||||
static int l_set_camera(lua_State *L);
|
||||
|
||||
// get_camera(self)
|
||||
static int l_get_camera(lua_State *L);
|
||||
|
||||
// set_nametag_attributes(self, attributes)
|
||||
static int l_set_nametag_attributes(lua_State *L);
|
||||
|
||||
|
|
|
@ -1944,6 +1944,15 @@ void Server::SendSetLighting(session_t peer_id, const Lighting &lighting)
|
|||
Send(&pkt);
|
||||
}
|
||||
|
||||
void Server::SendCamera(session_t peer_id, Player *player)
|
||||
{
|
||||
NetworkPacket pkt(TOCLIENT_CAMERA, 1, peer_id);
|
||||
|
||||
pkt << static_cast<u8>(player->allowed_camera_mode);
|
||||
|
||||
Send(&pkt);
|
||||
}
|
||||
|
||||
void Server::SendTimeOfDay(session_t peer_id, u16 time, f32 time_speed)
|
||||
{
|
||||
NetworkPacket pkt(TOCLIENT_TIME_OF_DAY, 0, peer_id);
|
||||
|
|
|
@ -45,6 +45,7 @@ class BanManager;
|
|||
class Inventory;
|
||||
class ModChannelMgr;
|
||||
class RemotePlayer;
|
||||
class Player;
|
||||
class PlayerSAO;
|
||||
struct PlayerHPChangeReason;
|
||||
class IRollbackManager;
|
||||
|
@ -409,6 +410,7 @@ public:
|
|||
void SendMovePlayerRel(session_t peer_id, const v3f &added_pos);
|
||||
void SendPlayerSpeed(session_t peer_id, const v3f &added_vel);
|
||||
void SendPlayerFov(session_t peer_id);
|
||||
void SendCamera(session_t peer_id, Player *player);
|
||||
|
||||
void SendMinimapModes(session_t peer_id,
|
||||
std::vector<MinimapMode> &modes,
|
||||
|
@ -546,6 +548,7 @@ private:
|
|||
void SendCloudParams(session_t peer_id, const CloudParams ¶ms);
|
||||
void SendOverrideDayNightRatio(session_t peer_id, bool do_override, float ratio);
|
||||
void SendSetLighting(session_t peer_id, const Lighting &lighting);
|
||||
|
||||
void broadcastModChannelMessage(const std::string &channel,
|
||||
const std::string &message, session_t from_peer);
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <string_view>
|
||||
#include <type_traits>
|
||||
|
||||
struct EnumString
|
||||
{
|
||||
|
@ -14,4 +15,13 @@ struct EnumString
|
|||
|
||||
bool string_to_enum(const EnumString *spec, int &result, std::string_view str);
|
||||
|
||||
template <typename T, std::enable_if_t<std::is_enum_v<T>, bool> = true>
|
||||
bool string_to_enum(const EnumString *spec, T &result, std::string_view str)
|
||||
{
|
||||
int result_int = result;
|
||||
bool ret = string_to_enum(spec, result_int, str);
|
||||
result = static_cast<T>(result_int);
|
||||
return ret;
|
||||
}
|
||||
|
||||
const char *enum_to_string(const EnumString *spec, int num);
|
||||
|
|
Loading…
Add table
Reference in a new issue