Add third person view
authorBlockMen <nmuelll@web.de>
Wed, 8 Jan 2014 12:47:53 +0000 (13:47 +0100)
committerBlockMen <nmuelll@web.de>
Sat, 12 Apr 2014 15:44:15 +0000 (17:44 +0200)
19 files changed:
doc/lua_api.txt
minetest.conf.example
src/camera.cpp
src/camera.h
src/client.cpp
src/clientmap.cpp
src/clientserver.h
src/content_cao.cpp
src/defaultsettings.cpp
src/game.cpp
src/game.h
src/hud.cpp
src/localplayer.cpp
src/localplayer.h
src/player.h
src/script/lua_api/l_object.cpp
src/script/lua_api/l_object.h
src/server.cpp
src/server.h

index bd060f9f030e77ceaed0874d52ec8d688b43fdc3..bfc12941b38128bbb01c935ca52c3ede1be4e5ad 100644 (file)
@@ -1874,6 +1874,12 @@ Player-only: (no-op for other objects)
 - 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:
index 4e4495338b6ee866a68be03a5764bac99be1e686..6b2867c37e06eb21504c8a9eab79870fac22be90 100644 (file)
 # try reducing it, but don't reduce it to a number below double of targeted
 # client number
 #max_packets_per_iteration = 1024
+
 #
 # Physics stuff
 #
index 783ae84c475eb1b973a5c830787b7507103291ac..6d17ff74321e3c735c1a67edba85aa5b67b9f47d 100644 (file)
@@ -40,6 +40,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 
 #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),
@@ -248,7 +251,8 @@ void Camera::step(f32 dtime)
 }
 
 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
@@ -276,7 +280,7 @@ void Camera::update(LocalPlayer* player, f32 frametime, f32 busytime,
 
        // 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;
@@ -303,7 +307,7 @@ void Camera::update(LocalPlayer* player, f32 frametime, f32 busytime,
        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;
@@ -352,19 +356,60 @@ void Camera::update(LocalPlayer* player, f32 frametime, f32 busytime,
        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");
index df40e3b9f02229503ebcf6a987b00b3729c5ad65..645b9355d572758d639a0d51f94c1f49240f5b71 100644 (file)
@@ -27,6 +27,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "util/numeric.h"
 #include <ICameraSceneNode.h>
 
+#include "client.h"
+
 class LocalPlayer;
 struct MapDrawControl;
 class IGameDef;
@@ -113,7 +115,8 @@ public:
        // 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);
index 56f55ef6ce6ec92c78ec7e395fab8a7d5fbe23f6..4f392ad7a9c1afef8d17a4112dd5d9c0b2637b9e 100644 (file)
@@ -1914,6 +1914,20 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
                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 "
index 20a59f266a4d12328eec5403496c0ef2b8dd252d..c8b2d412d05312e21b1e40d1ce28796c96fbe57a 100644 (file)
@@ -29,6 +29,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "mapblock.h"
 #include "profiler.h"
 #include "settings.h"
+#include "game.h" // CameraModes
 #include "util/mathconstants.h"
 #include <algorithm>
 
@@ -866,13 +867,16 @@ void ClientMap::renderPostFx()
        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);
        }
index 5c541863288613afd21854a333d2e82b576126fb..3d1adfc2d6c871c38f0a651c0303093480b83cad 100644 (file)
@@ -530,6 +530,16 @@ enum ToClientCommand
                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
index 84ec3e1430701014e3ee3791f958e558c50c1490..dc3bae00dc8c8fbe1579add0491dcbbfe300fdee 100644 (file)
@@ -41,6 +41,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #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>
@@ -858,7 +859,7 @@ public:
                
                m_visuals_expired = false;
 
-               if(!m_prop.is_visible || m_is_local_player)
+               if(!m_prop.is_visible)
                        return;
        
                //video::IVideoDriver* driver = smgr->getVideoDriver();
@@ -1078,6 +1079,60 @@ public:
        
        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;
 
@@ -1701,6 +1756,7 @@ public:
                        bool sneak = !readU8(is);
                        bool sneak_glitch = !readU8(is);
                        
+
                        if(m_is_local_player)
                        {
                                LocalPlayer *player = m_env->getLocalPlayer();
@@ -1713,11 +1769,25 @@ public:
                }
                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)
                {
index b08d79aee84c8e44d559345d7154889b13049514..c39fa54a9ca2cea50b53a68f4d1820570935f667 100644 (file)
@@ -53,6 +53,7 @@ void set_default_settings(Settings *settings)
        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");
index f435a4d71ad7f2b4091291be408295e3b7533a63..02308b65d3423a2fad78a05e99444291a4d47b16 100644 (file)
@@ -977,6 +977,8 @@ bool nodePlacementPrediction(Client &client,
        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)
@@ -1470,6 +1472,8 @@ void the_game(bool &kill, bool random_input, InputHandler *input,
        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
        */
@@ -2251,7 +2255,7 @@ void the_game(bool &kill, bool random_input, InputHandler *input,
                        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;
                                
@@ -2659,9 +2663,21 @@ void the_game(bool &kill, bool random_input, InputHandler *input,
                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();
@@ -2717,6 +2733,10 @@ void the_game(bool &kill, bool random_input, InputHandler *input,
                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(
@@ -3507,7 +3527,9 @@ void the_game(bool &kill, bool random_input, InputHandler *input,
                /*
                        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();
index 1c831c530067527c3bda16135109ec2728eae465..de0b8483b07500d4adbea2915bfe8f0151dc3ad8 100644 (file)
@@ -124,6 +124,7 @@ public:
 
 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,
index f87fdfc14b2df3d0f077f31a2eb4a919f98f387a..d210111768b0756c72db932d46aec72d5987ecbf 100644 (file)
@@ -30,6 +30,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "tile.h"
 #include "localplayer.h"
 #include "camera.h"
+#include "game.h" // CameraModes
 
 #include <IGUIStaticText.h>
 
@@ -384,7 +385,8 @@ void Hud::drawHotbar(v2s32 centerlowerpos, s32 halfheartcount, u16 playeritem, s
 
 
 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) {
index a6f04849ab42c27778f3904e3be42c6036ef25af..276d8e57c7d85dfe26cb8e9ae88a233eb75591de 100644 (file)
@@ -50,7 +50,9 @@ LocalPlayer::LocalPlayer(IGameDef *gamedef):
        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
index b6a3ed1f6c8b951a5020da2a809c228b435ed8bd..4a35ca929a930b98fdc3fda0bbd8339050b7a420 100644 (file)
@@ -27,6 +27,8 @@ class ClientEnvironment;
 
 class ClientActiveObject;
 
+enum localPlayerAnimations {NO_ANIM, WALK_ANIM, DIG_ANIM, WD_ANIM};  // no local animation, walking, digging, both
+
 class LocalPlayer : public Player
 {
 public:
@@ -60,6 +62,9 @@ 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;
index a1050d4c7dae5fdc979b0f38d72f9af44902b453..b9783997e415d540533f3f54fe22a76fd62f5d58 100644 (file)
@@ -269,6 +269,9 @@ public:
        bool physics_override_sneak;
        bool physics_override_sneak_glitch;
 
+       v2f local_animations[4];
+       float local_animation_speed;
+
        u16 hp;
 
        float hurt_tilt_timer;
index 90af51cc78719098ee619b6b47f02309d29e636b..e801ddd5fd69b6ac0a4eea60fd5c0f7e92cdd4c0 100644 (file)
@@ -406,6 +406,31 @@ int ObjectRef::l_set_animation(lua_State *L)
        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)
 {
@@ -1270,5 +1295,6 @@ const luaL_reg ObjectRef::methods[] = {
        luamethod(ObjectRef, hud_set_hotbar_selected_image),
        luamethod(ObjectRef, set_sky),
        luamethod(ObjectRef, override_day_night_ratio),
+       luamethod(ObjectRef, set_local_animation),
        {0,0}
 };
index 2c53d1a6959b374e8d517a4db041015fa2a4a067..be1068c14f09392ddcede6d507d359d466af6269 100644 (file)
@@ -231,6 +231,9 @@ private:
        // 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);
 
index 5c93988b8f3ac02d1d902628572e3d84852db05e..4f42cfabe3c2244ccbf2c2ba0b203ec127520490 100644 (file)
@@ -3484,6 +3484,24 @@ void Server::SendMovePlayer(u16 peer_id)
        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);
@@ -4578,6 +4596,15 @@ void Server::hudSetHotbarSelectedImage(Player *player, std::string name) {
        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> &params)
 {
index ab89fbc6e165d69fdf9374672c5578b18a92a4eb..c796fc82722afd057c9446eaada6b7d97d82bf56 100644 (file)
@@ -322,6 +322,8 @@ public:
        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> &params);
        
@@ -361,6 +363,7 @@ private:
        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);