From: BlockMen Date: Wed, 8 Jan 2014 12:47:53 +0000 (+0100) Subject: Add third person view X-Git-Tag: 0.4.10~190 X-Git-Url: https://git.librecmc.org/?a=commitdiff_plain;h=a1db9242ec491efdee70a7184aa61e861b17595a;p=oweals%2Fminetest.git Add third person view --- diff --git a/doc/lua_api.txt b/doc/lua_api.txt index bd060f9f0..bfc12941b 100644 --- a/doc/lua_api.txt +++ b/doc/lua_api.txt @@ -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: diff --git a/minetest.conf.example b/minetest.conf.example index 4e4495338..6b2867c37 100644 --- a/minetest.conf.example +++ b/minetest.conf.example @@ -361,6 +361,7 @@ # try reducing it, but don't reduce it to a number below double of targeted # client number #max_packets_per_iteration = 1024 + # # Physics stuff # diff --git a/src/camera.cpp b/src/camera.cpp index 783ae84c4..6d17ff743 100644 --- a/src/camera.cpp +++ b/src/camera.cpp @@ -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"); diff --git a/src/camera.h b/src/camera.h index df40e3b9f..645b9355d 100644 --- a/src/camera.h +++ b/src/camera.h @@ -27,6 +27,8 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "util/numeric.h" #include +#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); diff --git a/src/client.cpp b/src/client.cpp index 56f55ef6c..4f392ad7a 100644 --- a/src/client.cpp +++ b/src/client.cpp @@ -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 " diff --git a/src/clientmap.cpp b/src/clientmap.cpp index 20a59f266..c8b2d412d 100644 --- a/src/clientmap.cpp +++ b/src/clientmap.cpp @@ -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 @@ -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); } diff --git a/src/clientserver.h b/src/clientserver.h index 5c5418632..3d1adfc2d 100644 --- a/src/clientserver.h +++ b/src/clientserver.h @@ -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 diff --git a/src/content_cao.cpp b/src/content_cao.cpp index 84ec3e143..dc3bae00d 100644 --- a/src/content_cao.cpp +++ b/src/content_cao.cpp @@ -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 #include #include @@ -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) { diff --git a/src/defaultsettings.cpp b/src/defaultsettings.cpp index b08d79aee..c39fa54a9 100644 --- a/src/defaultsettings.cpp +++ b/src/defaultsettings.cpp @@ -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"); diff --git a/src/game.cpp b/src/game.cpp index f435a4d71..02308b65d 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -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 "<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 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(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(); diff --git a/src/game.h b/src/game.h index 1c831c530..de0b8483b 100644 --- a/src/game.h +++ b/src/game.h @@ -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, diff --git a/src/hud.cpp b/src/hud.cpp index f87fdfc14..d21011176 100644 --- a/src/hud.cpp +++ b/src/hud.cpp @@ -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 @@ -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) { diff --git a/src/localplayer.cpp b/src/localplayer.cpp index a6f04849a..276d8e57c 100644 --- a/src/localplayer.cpp +++ b/src/localplayer.cpp @@ -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 diff --git a/src/localplayer.h b/src/localplayer.h index b6a3ed1f6..4a35ca929 100644 --- a/src/localplayer.h +++ b/src/localplayer.h @@ -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; diff --git a/src/player.h b/src/player.h index a1050d4c7..b9783997e 100644 --- a/src/player.h +++ b/src/player.h @@ -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; diff --git a/src/script/lua_api/l_object.cpp b/src/script/lua_api/l_object.cpp index 90af51cc7..e801ddd5f 100644 --- a/src/script/lua_api/l_object.cpp +++ b/src/script/lua_api/l_object.cpp @@ -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} }; diff --git a/src/script/lua_api/l_object.h b/src/script/lua_api/l_object.h index 2c53d1a69..be1068c14 100644 --- a/src/script/lua_api/l_object.h +++ b/src/script/lua_api/l_object.h @@ -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); diff --git a/src/server.cpp b/src/server.cpp index 5c93988b8..4f42cfabe 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -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 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 ¶ms) { diff --git a/src/server.h b/src/server.h index ab89fbc6e..c796fc827 100644 --- a/src/server.h +++ b/src/server.h @@ -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 ¶ms); @@ -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);