- override_day_night_ratio(ratio or nil)
^ 0...1: Overrides day-night ratio, controlling sunlight to a specific amount
^ nil: Disables override, defaulting to sunlight based on day-night cycle
+- set_local_animation({x=0, y=79}, {x=168, y=187}, {x=189, y=198}, {x=200, y=219}, frame_speed=30): set animation for player model in third person view
+ ^ stand/idle animation key frames
+ ^ walk animation key frames
+ ^ dig animation key frames
+ ^ walk+dig animation key frames
+ ^ animation frame speed
InvRef: Reference to an inventory
methods:
# try reducing it, but don't reduce it to a number below double of targeted
# client number
#max_packets_per_iteration = 1024
+
#
# Physics stuff
#
#define CAMERA_OFFSET_STEP 200
+#include "nodedef.h"
+#include "game.h" // CameraModes
+
Camera::Camera(scene::ISceneManager* smgr, MapDrawControl& draw_control,
IGameDef *gamedef):
m_smgr(smgr),
}
void Camera::update(LocalPlayer* player, f32 frametime, f32 busytime,
- v2u32 screensize, f32 tool_reload_ratio)
+ v2u32 screensize, f32 tool_reload_ratio,
+ int current_camera_mode, ClientEnvironment &c_env)
{
// Get player position
// Smooth the movement when walking up stairs
// Fall bobbing animation
float fall_bobbing = 0;
- if(player->camera_impact >= 1)
+ if(player->camera_impact >= 1 && current_camera_mode < CAMERA_MODE_THIRD)
{
if(m_view_bobbing_fall == -1) // Effect took place and has finished
player->camera_impact = m_view_bobbing_fall = 0;
v3f rel_cam_target = v3f(0,0,1);
v3f rel_cam_up = v3f(0,1,0);
- if (m_view_bobbing_anim != 0)
+ if (m_view_bobbing_anim != 0 && current_camera_mode < CAMERA_MODE_THIRD)
{
f32 bobfrac = my_modf(m_view_bobbing_anim * 2);
f32 bobdir = (m_view_bobbing_anim < 0.5) ? 1.0 : -1.0;
v3f abs_cam_up;
m_headnode->getAbsoluteTransformation().rotateVect(abs_cam_up, rel_cam_up);
+ // Seperate camera position for calculation
+ v3f my_cp = m_camera_position;
+
+ // Reposition the camera for third person view
+ if (current_camera_mode > CAMERA_MODE_FIRST) {
+
+ if (current_camera_mode == CAMERA_MODE_THIRD_FRONT)
+ m_camera_direction *= -1;
+
+ my_cp.Y += 2;
+
+ // Calculate new position
+ bool abort = false;
+ for (int i = BS; i <= BS*2; i++) {
+ my_cp.X = m_camera_position.X + m_camera_direction.X*-i;
+ my_cp.Z = m_camera_position.Z + m_camera_direction.Z*-i;
+ if (i > 12)
+ my_cp.Y = m_camera_position.Y + (m_camera_direction.Y*-i);
+
+ // Prevent camera positioned inside nodes
+ INodeDefManager *nodemgr = m_gamedef->ndef();
+ MapNode n = c_env.getClientMap().getNodeNoEx(floatToInt(my_cp, BS));
+ const ContentFeatures& features = nodemgr->get(n);
+ if(features.walkable) {
+ my_cp.X += m_camera_direction.X*-1*-BS/2;
+ my_cp.Z += m_camera_direction.Z*-1*-BS/2;
+ my_cp.Y += m_camera_direction.Y*-1*-BS/2;
+ abort = true;
+ break;
+ }
+ }
+
+ // If node blocks camera position don't move y to heigh
+ if (abort && my_cp.Y > player_position.Y+BS*2)
+ my_cp.Y = player_position.Y+BS*2;
+ }
+
// Update offset if too far away from the center of the map
m_camera_offset.X += CAMERA_OFFSET_STEP*
- (((s16)(m_camera_position.X/BS) - m_camera_offset.X)/CAMERA_OFFSET_STEP);
+ (((s16)(my_cp.X/BS) - m_camera_offset.X)/CAMERA_OFFSET_STEP);
m_camera_offset.Y += CAMERA_OFFSET_STEP*
- (((s16)(m_camera_position.Y/BS) - m_camera_offset.Y)/CAMERA_OFFSET_STEP);
+ (((s16)(my_cp.Y/BS) - m_camera_offset.Y)/CAMERA_OFFSET_STEP);
m_camera_offset.Z += CAMERA_OFFSET_STEP*
- (((s16)(m_camera_position.Z/BS) - m_camera_offset.Z)/CAMERA_OFFSET_STEP);
+ (((s16)(my_cp.Z/BS) - m_camera_offset.Z)/CAMERA_OFFSET_STEP);
// Set camera node transformation
- m_cameranode->setPosition(m_camera_position-intToFloat(m_camera_offset, BS));
+ m_cameranode->setPosition(my_cp-intToFloat(m_camera_offset, BS));
m_cameranode->setUpVector(abs_cam_up);
// *100.0 helps in large map coordinates
- m_cameranode->setTarget(m_camera_position-intToFloat(m_camera_offset, BS) + 100 * m_camera_direction);
+ m_cameranode->setTarget(my_cp-intToFloat(m_camera_offset, BS) + 100 * m_camera_direction);
+
+ // update the camera position in front-view mode to render blocks behind player
+ if (current_camera_mode == CAMERA_MODE_THIRD_FRONT)
+ m_camera_position = my_cp;
// Get FOV setting
f32 fov_degrees = g_settings->getFloat("fov");
#include "util/numeric.h"
#include <ICameraSceneNode.h>
+#include "client.h"
+
class LocalPlayer;
struct MapDrawControl;
class IGameDef;
// Update the camera from the local player's position.
// busytime is used to adjust the viewing range.
void update(LocalPlayer* player, f32 frametime, f32 busytime,
- v2u32 screensize, f32 tool_reload_ratio);
+ v2u32 screensize, f32 tool_reload_ratio,
+ int current_camera_mode, ClientEnvironment &c_env);
// Render distance feedback loop
void updateViewingRange(f32 frametime_in, f32 busytime_in);
event.override_day_night_ratio.ratio_f = day_night_ratio_f;
m_client_event_queue.push_back(event);
}
+ else if(command == TOCLIENT_LOCAL_PLAYER_ANIMATIONS)
+ {
+ std::string datastring((char *)&data[2], datasize - 2);
+ std::istringstream is(datastring, std::ios_base::binary);
+
+ LocalPlayer *player = m_env.getLocalPlayer();
+ assert(player != NULL);
+
+ player->local_animations[0] = readV2F1000(is);
+ player->local_animations[1] = readV2F1000(is);
+ player->local_animations[2] = readV2F1000(is);
+ player->local_animations[3] = readV2F1000(is);
+ player->local_animation_speed = readF1000(is);
+ }
else
{
infostream<<"Client: Ignoring unknown command "
#include "mapblock.h"
#include "profiler.h"
#include "settings.h"
+#include "game.h" // CameraModes
#include "util/mathconstants.h"
#include <algorithm>
v3f camera_position = m_camera_position;
m_camera_mutex.Unlock();
+ LocalPlayer *player = m_client->getEnv().getLocalPlayer();
+
MapNode n = getNodeNoEx(floatToInt(camera_position, BS));
// - If the player is in a solid node, make everything black.
// - If the player is in liquid, draw a semi-transparent overlay.
+ // - Do not if player is in third person mode
const ContentFeatures& features = nodemgr->get(n);
video::SColor post_effect_color = features.post_effect_color;
- if(features.solidness == 2 && !(g_settings->getBool("noclip") && m_gamedef->checkLocalPrivilege("noclip")))
+ if(features.solidness == 2 && !(g_settings->getBool("noclip") && m_gamedef->checkLocalPrivilege("noclip")) && player->camera_mode == CAMERA_MODE_FIRST)
{
post_effect_color = video::SColor(255, 0, 0, 0);
}
u8 do_override (boolean)
u16 day-night ratio 0...65535
*/
+
+ TOCLIENT_LOCAL_PLAYER_ANIMATIONS = 0x51,
+ /*
+ u16 command
+ v2f1000 stand/idle
+ v2f1000 walk
+ v2f1000 dig
+ v2f1000 walk+dig
+ f1000 frame_speed
+ */
};
enum ToServerCommand
#include "util/mathconstants.h"
#include "map.h"
#include "main.h" // g_settings
+#include "game.h" // CameraModes
#include <IMeshManipulator.h>
#include <IAnimatedMeshSceneNode.h>
#include <IBoneSceneNode.h>
m_visuals_expired = false;
- if(!m_prop.is_visible || m_is_local_player)
+ if(!m_prop.is_visible)
return;
//video::IVideoDriver* driver = smgr->getVideoDriver();
void step(float dtime, ClientEnvironment *env)
{
+ // Handel model of local player instantly to prevent lags
+ if(m_is_local_player) {
+ LocalPlayer *player = m_env->getLocalPlayer();
+
+ if (player->camera_mode > CAMERA_MODE_FIRST) {
+ int old_anim = player->last_animation;
+ float old_anim_speed = player->last_animation_speed;
+ m_is_visible = true;
+ m_position = player->getPosition() + v3f(0,BS,0);
+ m_velocity = v3f(0,0,0);
+ m_acceleration = v3f(0,0,0);
+ pos_translator.vect_show = m_position;
+ m_yaw = player->getYaw();
+ PlayerControl controls = player->getPlayerControl();
+
+ bool walking = false;
+ if(controls.up || controls.down || controls.left || controls.right)
+ walking = true;
+
+ m_animation_speed = player->local_animation_speed;
+ if(controls.sneak && walking)
+ m_animation_speed = player->local_animation_speed/2;
+
+ player->last_animation_speed = m_animation_speed;
+
+ if(walking && (controls.LMB || controls.RMB)) {
+ m_animation_range = player->local_animations[3];
+ player->last_animation = WD_ANIM;
+ } else if(walking) {
+ m_animation_range = player->local_animations[1];
+ player->last_animation = WALK_ANIM;
+ } else if(controls.LMB || controls.RMB) {
+ m_animation_range = player->local_animations[2];
+ player->last_animation = DIG_ANIM;
+ }
+
+ // reset animation when no input detected
+ if (!walking && !controls.LMB && !controls.RMB) {
+ player->last_animation = NO_ANIM;
+ if (old_anim != NO_ANIM) {
+ m_animation_range = player->local_animations[0];
+ updateAnimation();
+ }
+ }
+
+ // Update local player animations
+ if ((player->last_animation != old_anim && player->last_animation != NO_ANIM) || m_animation_speed != old_anim_speed)
+ updateAnimation();
+
+ } else {
+ m_is_visible = false;
+ }
+ }
+
if(m_visuals_expired && m_smgr && m_irr){
m_visuals_expired = false;
bool sneak = !readU8(is);
bool sneak_glitch = !readU8(is);
+
if(m_is_local_player)
{
LocalPlayer *player = m_env->getLocalPlayer();
}
else if(cmd == GENERIC_CMD_SET_ANIMATION)
{
- m_animation_range = readV2F1000(is);
- m_animation_speed = readF1000(is);
- m_animation_blend = readF1000(is);
-
- updateAnimation();
+ if (!m_is_local_player) {
+ m_animation_range = readV2F1000(is);
+ m_animation_speed = readF1000(is);
+ m_animation_blend = readF1000(is);
+ updateAnimation();
+ } else {
+ LocalPlayer *player = m_env->getLocalPlayer();
+ if(player->last_animation == NO_ANIM) {
+ m_animation_range = readV2F1000(is);
+ m_animation_speed = readF1000(is);
+ m_animation_blend = readF1000(is);
+ }
+ // update animation only if object is not player
+ // or the received animation is not registered
+ if(m_animation_range.X != player->local_animations[1].X &&
+ m_animation_range.X != player->local_animations[2].X &&
+ m_animation_range.X != player->local_animations[3].X)
+ updateAnimation();
+ }
}
else if(cmd == GENERIC_CMD_SET_BONE_POSITION)
{
settings->setDefault("keymap_toggle_update_camera", "KEY_F4");
settings->setDefault("keymap_toggle_debug", "KEY_F5");
settings->setDefault("keymap_toggle_profiler", "KEY_F6");
+ settings->setDefault("keymap_camera_mode", "KEY_F7");
settings->setDefault("keymap_increase_viewing_range_min", "+");
settings->setDefault("keymap_decrease_viewing_range_min", "-");
settings->setDefault("anaglyph", "false");
return false;
}
+bool is_third_person = false;
+
static void show_chat_menu(FormspecFormSource* current_formspec,
TextDest* current_textdest, IWritableTextureSource* tsrc,
IrrlichtDevice * device, Client* client, std::string text)
f32 camera_yaw = 0; // "right/left"
f32 camera_pitch = 0; // "up/down"
+ int current_camera_mode = CAMERA_MODE_FIRST; // start in first-person view
+
/*
Clouds
*/
else{
s32 dx = input->getMousePos().X - displaycenter.X;
s32 dy = input->getMousePos().Y - displaycenter.Y;
- if(invert_mouse)
+ if(invert_mouse || player->camera_mode == CAMERA_MODE_THIRD_FRONT)
dy = -dy;
//infostream<<"window active, pos difference "<<dx<<","<<dy<<std::endl;
LocalPlayer* player = client.getEnv().getLocalPlayer();
float full_punch_interval = playeritem_toolcap.full_punch_interval;
float tool_reload_ratio = time_from_last_punch / full_punch_interval;
+
+ if(input->wasKeyDown(getKeySetting("keymap_camera_mode"))) {
+
+ if (current_camera_mode == CAMERA_MODE_FIRST)
+ current_camera_mode = CAMERA_MODE_THIRD;
+ else if (current_camera_mode == CAMERA_MODE_THIRD)
+ current_camera_mode = CAMERA_MODE_THIRD_FRONT;
+ else
+ current_camera_mode = CAMERA_MODE_FIRST;
+
+ }
+ player->camera_mode = current_camera_mode;
tool_reload_ratio = MYMIN(tool_reload_ratio, 1.0);
- camera.update(player, dtime, busytime, screensize,
- tool_reload_ratio);
+ camera.update(player, dtime, busytime, screensize, tool_reload_ratio,
+ current_camera_mode, client.getEnv());
camera.step(dtime);
v3f player_position = player->getPosition();
core::line3d<f32> shootline(camera_position,
camera_position + camera_direction * BS * (d+1));
+ // prevent player pointing anything in front-view
+ if (current_camera_mode == CAMERA_MODE_THIRD_FRONT)
+ shootline = core::line3d<f32>(0,0,0,0,0,0);
+
ClientActiveObject *selected_object = NULL;
PointedThing pointed = getPointedThing(
/*
Wielded tool
*/
- if(show_hud && (player->hud_flags & HUD_FLAG_WIELDITEM_VISIBLE))
+ if(show_hud &&
+ (player->hud_flags & HUD_FLAG_WIELDITEM_VISIBLE) &&
+ current_camera_mode < CAMERA_MODE_THIRD)
{
// Warning: This clears the Z buffer.
camera.drawWieldedTool();
class ChatBackend; /* to avoid having to include chat.h */
struct SubgameSpec;
+enum CameraModes {CAMERA_MODE_FIRST, CAMERA_MODE_THIRD, CAMERA_MODE_THIRD_FRONT};
void the_game(
bool &kill,
#include "tile.h"
#include "localplayer.h"
#include "camera.h"
+#include "game.h" // CameraModes
#include <IGUIStaticText.h>
void Hud::drawCrosshair() {
- if (!(player->hud_flags & HUD_FLAG_CROSSHAIR_VISIBLE))
+ if (!(player->hud_flags & HUD_FLAG_CROSSHAIR_VISIBLE) ||
+ player->camera_mode == CAMERA_MODE_THIRD_FRONT)
return;
if (use_crosshair_image) {
m_old_node_below(32767,32767,32767),
m_old_node_below_type("air"),
m_need_to_get_new_sneak_node(true),
- m_can_jump(false)
+ m_can_jump(false),
+ camera_mode(0),
+ last_animation(NO_ANIM)
{
// Initialize hp to 0, so that no hearts will be shown if server
// doesn't support health points
class ClientActiveObject;
+enum localPlayerAnimations {NO_ANIM, WALK_ANIM, DIG_ANIM, WD_ANIM}; // no local animation, walking, digging, both
+
class LocalPlayer : public Player
{
public:
unsigned int last_keyPressed;
float camera_impact;
+ int camera_mode;
+ int last_animation;
+ float last_animation_speed;
std::string hotbar_image;
std::string hotbar_selected_image;
bool physics_override_sneak;
bool physics_override_sneak_glitch;
+ v2f local_animations[4];
+ float local_animation_speed;
+
u16 hp;
float hurt_tilt_timer;
return 0;
}
+// set_local_animation(self, {stand/ilde}, {walk}, {dig}, {walk+dig}, frame_speed)
+int ObjectRef::l_set_local_animation(lua_State *L)
+{
+ //NO_MAP_LOCK_REQUIRED;
+ ObjectRef *ref = checkobject(L, 1);
+ Player *player = getplayer(ref);
+ if (player == NULL)
+ return 0;
+ // Do it
+ v2f frames[4];
+ for (int i=0;i<4;i++) {
+ if(!lua_isnil(L, 2+1))
+ frames[i] = read_v2f(L, 2+i);
+ }
+ float frame_speed = 30;
+ if(!lua_isnil(L, 6))
+ frame_speed = lua_tonumber(L, 6);
+
+ if (!getServer(L)->setLocalPlayerAnimations(player, frames, frame_speed))
+ return 0;
+
+ lua_pushboolean(L, true);
+ return 0;
+}
+
// set_bone_position(self, std::string bone, v3f position, v3f rotation)
int ObjectRef::l_set_bone_position(lua_State *L)
{
luamethod(ObjectRef, hud_set_hotbar_selected_image),
luamethod(ObjectRef, set_sky),
luamethod(ObjectRef, override_day_night_ratio),
+ luamethod(ObjectRef, set_local_animation),
{0,0}
};
// override_day_night_ratio(self, type, list)
static int l_override_day_night_ratio(lua_State *L);
+ // set_local_animation(self, {stand/ilde}, {walk}, {dig}, {walk+dig}, frame_speed)
+ static int l_set_local_animation(lua_State *L);
+
public:
ObjectRef(ServerActiveObject *object);
m_clients.send(peer_id, 0, data, true);
}
+void Server::SendLocalPlayerAnimations(u16 peer_id, v2f animation_frames[4], f32 animation_speed)
+{
+ std::ostringstream os(std::ios_base::binary);
+
+ writeU16(os, TOCLIENT_LOCAL_PLAYER_ANIMATIONS);
+ writeV2F1000(os, animation_frames[0]);
+ writeV2F1000(os, animation_frames[1]);
+ writeV2F1000(os, animation_frames[2]);
+ writeV2F1000(os, animation_frames[3]);
+ writeF1000(os, animation_speed);
+
+ // Make data buffer
+ std::string s = os.str();
+ SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
+ // Send as reliable
+ m_clients.send(peer_id, 0, data, true);
+}
+
void Server::SendPlayerPrivileges(u16 peer_id)
{
Player *player = m_env->getPlayer(peer_id);
SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
}
+bool Server::setLocalPlayerAnimations(Player *player, v2f animation_frames[4], f32 frame_speed)
+{
+ if (!player)
+ return false;
+
+ SendLocalPlayerAnimations(player->peer_id, animation_frames, frame_speed);
+ return true;
+}
+
bool Server::setSky(Player *player, const video::SColor &bgcolor,
const std::string &type, const std::vector<std::string> ¶ms)
{
inline Address getPeerAddress(u16 peer_id)
{ return m_con.GetPeerAddress(peer_id); }
+ bool setLocalPlayerAnimations(Player *player, v2f animation_frames[4], f32 frame_speed);
+
bool setSky(Player *player, const video::SColor &bgcolor,
const std::string &type, const std::vector<std::string> ¶ms);
void SendPlayerHP(u16 peer_id);
void SendPlayerBreath(u16 peer_id);
void SendMovePlayer(u16 peer_id);
+ void SendLocalPlayerAnimations(u16 peer_id, v2f animation_frames[4], f32 animation_speed);
void SendPlayerPrivileges(u16 peer_id);
void SendPlayerInventoryFormspec(u16 peer_id);
void SendShowFormspecMessage(u16 peer_id, const std::string &formspec, const std::string &formname);