diff options
Diffstat (limited to 'playeranim')
-rw-r--r-- | playeranim/LICENSE.md | 23 | ||||
-rw-r--r-- | playeranim/README.md | 47 | ||||
-rw-r--r-- | playeranim/depends.txt | 2 | ||||
-rw-r--r-- | playeranim/description.txt | 1 | ||||
-rw-r--r-- | playeranim/init.lua | 301 | ||||
-rw-r--r-- | playeranim/mod.conf | 3 | ||||
-rw-r--r-- | playeranim/model.lua | 99 | ||||
-rw-r--r-- | playeranim/screenshot.png | bin | 0 -> 88380 bytes | |||
-rw-r--r-- | playeranim/settingtypes.txt | 18 |
9 files changed, 494 insertions, 0 deletions
diff --git a/playeranim/LICENSE.md b/playeranim/LICENSE.md new file mode 100644 index 0000000..5957b8c --- /dev/null +++ b/playeranim/LICENSE.md @@ -0,0 +1,23 @@ +Copyright (c) 2013-2014, Diego MartÃnez +Copyright (c) 2016-2018, Rui +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/playeranim/README.md b/playeranim/README.md new file mode 100644 index 0000000..9938d60 --- /dev/null +++ b/playeranim/README.md @@ -0,0 +1,47 @@ +# playeranim + +Makes the head, and the right arm when you're mining, face the way you're facing, similar to Minecraft. Compatible with [3d_armor](https://github.com/stujones11/minetest-3d_armor). This is an ugly hack. Forked from [Kaeza's animplus mod](https://github.com/kaeza/minetest-animplus). + +The head only turns up and down relative to the body, except it turns slightly to the right/left when you strafe right/left. When you turn the body turns with the head. +Works in both singleplayer and multiplayer. + +Created by [Rui](https://github.com/Rui-Minetest), this document was written by [sloantothebone](https://github.com/sloantothebone). + +## Configuration + +### Version of player model + +Player models supported by this mod: +- `MTG_4_Jun_2017` (minetest_game after 4 Jun 2017, 0.4.16) +- `MTG_4_Nov_2017` (minetest_game after 4 Nov 2017, 0.5.0) + +As there is no automatic way to determine which version is used, this must be configured with advanced settings menu, or by manually editing `playeranim.model_version` entry in minetest.conf. +The default value is `MTG_4_Jun_2017`. + +Symptoms of having configured the incorrect player model: +- In rest, arms are raised up, and are either detached from the body, or are too close to the body +- Cape (if visible) points upward + +### The delay of sideways body rotation + +Configure `playeranim.body_rotation_delay`. +It's the number of frame delay of sideways body rotation. +The default value is `7`. + +### Lengthways body rotation in sneaking + +Configure `playeranim.body_x_rotation_sneak`. +It's the degrees of the body's X-axis rotation in sneaking. +The default value is `6.0`. + +### The speed of an animation + +Configure `playeranim.animation_speed`. +It's the number of stepping per seconds. +The default value is `2.4`. + +### The speed of an animation in sneaking + +Configure `playeranim.animation_speed_sneak`. +It's the number of stepping per seconds in sneaking. +The default value is `0.8`. diff --git a/playeranim/depends.txt b/playeranim/depends.txt new file mode 100644 index 0000000..9bcff68 --- /dev/null +++ b/playeranim/depends.txt @@ -0,0 +1,2 @@ +default? +player_api? diff --git a/playeranim/description.txt b/playeranim/description.txt new file mode 100644 index 0000000..0c1198d --- /dev/null +++ b/playeranim/description.txt @@ -0,0 +1 @@ +Adds animations to the players' head and right arm.
\ No newline at end of file diff --git a/playeranim/init.lua b/playeranim/init.lua new file mode 100644 index 0000000..e6730e2 --- /dev/null +++ b/playeranim/init.lua @@ -0,0 +1,301 @@ +local ANIMATION_SPEED = tonumber(minetest.settings:get("playeranim.animation_speed")) or 2.4 +local ANIMATION_SPEED_SNEAK = tonumber(minetest.settings:get("playeranim.animation_speed_sneak")) or 0.8 +local BODY_ROTATION_DELAY = math.max(math.floor(tonumber(minetest.settings:get("playeranim.body_rotation_delay")) or 7), 1) +local BODY_X_ROTATION_SNEAK = tonumber(minetest.settings:get("playeranim.body_x_rotation_sneak")) or 6.0 + +local BONE_POSITION, BONE_ROTATION = (function() + local modname = minetest.get_current_modname() + local modpath = minetest.get_modpath(modname) + return dofile(modpath .. "/model.lua") +end)() + +local get_animation = player_api and player_api.get_animation or default.player_get_animation +if not get_animation then + error("player_api.get_animation or default.player_get_animation is not found") +end + +local function get_animation_speed(player) + if player:get_player_control().sneak then + return ANIMATION_SPEED_SNEAK + end + return ANIMATION_SPEED +end + +local math_deg = math.deg +local function get_pitch_deg(player) + return math_deg(player:get_look_vertical()) +end + +local players_animation_data = setmetatable({}, { + __index = { + init_player = function(self, player) + self[player] = { + time = 0, + yaw_history = {}, + bone_rotations = {}, + bone_positions = {}, + previous_animation = 0, + } + end, + + -- time + get_time = function(self, player) + return self[player].time + end, + + increment_time = function(self, player, dtime) + self[player].time = self:get_time(player) + dtime + end, + + reset_time = function(self, player) + self[player].time = 0 + end, + + -- yaw_history + get_yaw_history = function(self, player) + return self[player].yaw_history -- Return mutable reference + end, + + add_yaw_to_history = function(self, player) + local yaw = player:get_look_horizontal() + local history = self:get_yaw_history(player) + history[#history + 1] = yaw + end, + + clear_yaw_history = function(self, player) + if #self[player].yaw_history > 0 then + self[player].yaw_history = {} + end + end, + + -- bone_rotations + get_bone_rotation = function(self, player, bone) + return self[player].bone_rotations[bone] + end, + + set_bone_rotation = function(self, player, bone, rotation) + self[player].bone_rotations[bone] = rotation + end, + + -- bone_positions + get_bone_position = function(self, player, bone) + return self[player].bone_positions[bone] + end, + + set_bone_position = function(self, player, bone, position) + self[player].bone_positions[bone] = position + end, + + -- previous_animation + get_previous_animation = function(self, player) + return self[player].previous_animation + end, + + set_previous_animation = function(self, player, animation) + self[player].previous_animation = animation + end, + } +}) + +minetest.register_on_joinplayer(function(player) + players_animation_data:init_player(player) +end) + +local vector_add, vector_equals = vector.add, vector.equals +local function rotate_bone(player, bone, rotation, position_optional) + local previous_rotation = players_animation_data:get_bone_rotation(player, bone) + local rotation = vector_add(rotation, BONE_ROTATION[bone]) + + local previous_position = players_animation_data:get_bone_position(player, bone) + local position = BONE_POSITION[bone] + if position_optional then + position = vector_add(position, position_optional) + end + + if not previous_rotation + or not previous_position + or not vector_equals(rotation, previous_rotation) + or not vector_equals(position, previous_position) then + player:set_bone_position(bone, position, rotation) + players_animation_data:set_bone_rotation(player, bone, rotation) + players_animation_data:set_bone_position(player, bone, position) + end +end + +-- Animation alias +local STAND = 1 +local WALK = 2 +local MINE = 3 +local WALK_MINE = 4 +local SIT = 5 +local LAY = 6 + +-- Bone alias +local BODY = "Body" +local HEAD = "Head" +local CAPE = "Cape" +local LARM = "Arm_Left" +local RARM = "Arm_Right" +local LLEG = "Leg_Left" +local RLEG = "Leg_Right" + +local math_sin, math_cos, math_pi = math.sin, math.cos, math.pi +local ANIMATIONS = { + [STAND] = function(player, _time) + rotate_bone(player, BODY, {x = 0, y = 0, z = 0}) + rotate_bone(player, CAPE, {x = 0, y = 0, z = 0}) + rotate_bone(player, LARM, {x = 0, y = 0, z = 0}) + rotate_bone(player, RARM, {x = 0, y = 0, z = 0}) + rotate_bone(player, LLEG, {x = 0, y = 0, z = 0}) + rotate_bone(player, RLEG, {x = 0, y = 0, z = 0}) + end, + + [LAY] = function(player, _time) + rotate_bone(player, HEAD, {x = 0, y = 0, z = 0}) + rotate_bone(player, CAPE, {x = 0, y = 0, z = 0}) + rotate_bone(player, LARM, {x = 0, y = 0, z = 0}) + rotate_bone(player, RARM, {x = 0, y = 0, z = 0}) + rotate_bone(player, LLEG, {x = 0, y = 0, z = 0}) + rotate_bone(player, RLEG, {x = 0, y = 0, z = 0}) + rotate_bone(player, BODY, BONE_ROTATION.body_lay, BONE_POSITION.body_lay) + end, + + [SIT] = function(player, _time) + rotate_bone(player, LARM, {x = 0, y = 0, z = 0}) + rotate_bone(player, RARM, {x = 0, y = 0, z = 0}) + rotate_bone(player, LLEG, {x = 90, y = 0, z = 0}) + rotate_bone(player, RLEG, {x = 90, y = 0, z = 0}) + rotate_bone(player, BODY, BONE_ROTATION.body_sit, BONE_POSITION.body_sit) + end, + + [WALK] = function(player, time) + local speed = get_animation_speed(player) + local sin = math_sin(time * speed * math_pi) + + rotate_bone(player, CAPE, {x = -35 * sin - 35, y = 0, z = 0}) + rotate_bone(player, LARM, {x = -55 * sin, y = 0, z = 0}) + rotate_bone(player, RARM, {x = 55 * sin, y = 0, z = 0}) + rotate_bone(player, LLEG, {x = 55 * sin, y = 0, z = 0}) + rotate_bone(player, RLEG, {x = -55 * sin, y = 0, z = 0}) + end, + + [MINE] = function(player, time) + local speed = get_animation_speed(player) + + local cape_sin = math_sin(time * speed * math_pi) + local rarm_sin = math_sin(2 * time * speed * math_pi) + local rarm_cos = -math_cos(2 * time * speed * math_pi) + local pitch = 90 - get_pitch_deg(player) + + rotate_bone(player, CAPE, {x = -5 * cape_sin - 5, y = 0, z = 0}) + rotate_bone(player, LARM, {x = 0, y = 0, z = 0}) + rotate_bone(player, RARM, {x = 10 * rarm_sin + pitch, y = 10 * rarm_cos, z = 0}) + rotate_bone(player, LLEG, {x = 0, y = 0, z = 0}) + rotate_bone(player, RLEG, {x = 0, y = 0, z = 0}) + end, + + [WALK_MINE] = function(player, time) + local speed = get_animation_speed(player) + + local sin = math_sin(time * speed * math_pi) + local rarm_sin = math_sin(2 * time * speed * math_pi) + local rarm_cos = -math_cos(2 * time * speed * math_pi) + local pitch = 90 - get_pitch_deg(player) + + rotate_bone(player, CAPE, {x = -35 * sin - 35, y = 0, z = 0}) + rotate_bone(player, LARM, {x = -55 * sin, y = 0, z = 0}) + rotate_bone(player, RARM, {x = 10 * rarm_sin + pitch, y = 10 * rarm_cos, z = 0}) + rotate_bone(player, LLEG, {x = 55 * sin, y = 0, z = 0}) + rotate_bone(player, RLEG, {x = -55 * sin, y = 0, z = 0}) + end, +} + +local function set_animation(player, animation, force_animate) + local animation_changed + = (players_animation_data:get_previous_animation(player) ~= animation) + + if force_animate or animation_changed then + players_animation_data:set_previous_animation(player, animation) + ANIMATIONS[animation](player, players_animation_data:get_time(player)) + end +end + +local function rotate_head(player) + local head_x_rotation = -get_pitch_deg(player) + rotate_bone(player, HEAD, {x = head_x_rotation, y = 0, z = 0}) +end + +local table_remove, math_deg = table.remove, math.deg +local function rotate_body_and_head(player) + local body_x_rotation = (function() + local sneak = player:get_player_control().sneak + return sneak and BODY_X_ROTATION_SNEAK or 0 + end)() + + local body_y_rotation = (function() + local yaw_history = players_animation_data:get_yaw_history(player) + if #yaw_history > BODY_ROTATION_DELAY then + local body_yaw = table_remove(yaw_history, 1) + local player_yaw = player:get_look_horizontal() + return math_deg(player_yaw - body_yaw) + end + return 0 + end)() + + rotate_bone(player, BODY, {x = body_x_rotation, y = body_y_rotation, z = 0}) + + local head_x_rotation = -get_pitch_deg(player) + rotate_bone(player, HEAD, {x = head_x_rotation, y = -body_y_rotation, z = 0}) +end + + +local function animate_player(player, dtime) + local animation = get_animation(player).animation + + -- Yaw history + if animation == "lay" or animation == "sit" then + players_animation_data:clear_yaw_history(player) + else + players_animation_data:add_yaw_to_history(player) + end + + -- Increment animation time + if animation == "walk" + or animation == "mine" + or animation == "walk_mine" then + players_animation_data:increment_time(player, dtime) + else + players_animation_data:reset_time(player) + end + + -- Set animation + if animation == "stand" then + set_animation(player, STAND) + elseif animation == "lay" then + set_animation(player, LAY) + elseif animation == "sit" then + set_animation(player, SIT) + elseif animation == "walk" then + set_animation(player, WALK, true) + elseif animation == "mine" then + set_animation(player, MINE, true) + elseif animation == "walk_mine" then + set_animation(player, WALK_MINE, true) + end + + -- Rotate body and head + if animation == "lay" then + -- Do nothing + elseif animation == "sit" then + rotate_head(player) + else + rotate_body_and_head(player) + end +end + +local minetest_get_connected_players = minetest.get_connected_players +minetest.register_globalstep(function(dtime) + for _, player in ipairs(minetest_get_connected_players()) do + animate_player(player, dtime) + end +end) diff --git a/playeranim/mod.conf b/playeranim/mod.conf new file mode 100644 index 0000000..3e162f0 --- /dev/null +++ b/playeranim/mod.conf @@ -0,0 +1,3 @@ +name = playeranim +description = Adds animations to the players' head and right arm. +optional_depends = player_api, default diff --git a/playeranim/model.lua b/playeranim/model.lua new file mode 100644 index 0000000..717382c --- /dev/null +++ b/playeranim/model.lua @@ -0,0 +1,99 @@ +-- Bone alias +local BODY = "Body" +local HEAD = "Head" +local CAPE = "Cape" +local LARM = "Arm_Left" +local RARM = "Arm_Right" +local LLEG = "Leg_Left" +local RLEG = "Leg_Right" + +-- Version of player model +local DEFAULT_PLAYER_MODEL_VERSION = "MTG_4_Jun_2017" + +local VALID_PLAYER_MODEL_VERSIONS = { + MTG_4_Jun_2017 = true, + MTG_4_Nov_2017 = true, +} + +local LEGACY_PLAYER_MODEL_VERSIONS = { + default_character_v1 = true, + default_character_v2 = true, + default_character_v3 = true, +} + +local BONE_POSITIONS = { + MTG_4_Jun_2017 = { + [BODY] = {x = 0, y = -3.5, z = 0}, + [HEAD] = {x = 0, y = 6.5, z = 0}, + [CAPE] = {x = 0, y = 6.5, z = 1.2}, + [LARM] = {x = 3, y = 5.5, z = 0}, + [RARM] = {x = -3, y = 5.5, z = 0}, + [LLEG] = {x = 1, y = 0, z = 0}, + [RLEG] = {x = -1, y = 0, z = 0}, + + body_sit = {x = 0, y = -5.5, z = 0}, + body_lay = {x = 0, y = -5.5, z = 0}, + }, + MTG_4_Nov_2017 = { + [BODY] = {x = 0, y = 6.25, z = 0}, + [HEAD] = {x = 0, y = 6.5, z = 0}, + [CAPE] = {x = 0, y = 6.5, z = 1.2}, + [LARM] = {x = 3, y = 5.5, z = 0}, + [RARM] = {x = -3, y = 5.5, z = 0}, + [LLEG] = {x = 1, y = 0, z = 0}, + [RLEG] = {x = -1, y = 0, z = 0}, + + body_sit = {x = 0, y = -5, z = 0}, + body_lay = {x = 0, y = -5, z = 0}, + }, +} + +local BONE_ROTATIONS = { + MTG_4_Jun_2017 = { + [BODY] = {x = 0, y = 0, z = 0}, + [HEAD] = {x = 0, y = 0, z = 0}, + [CAPE] = {x = 0, y = 0, z = 0}, + [LARM] = {x = 0, y = 0, z = 0}, + [RARM] = {x = 0, y = 0, z = 0}, + [LLEG] = {x = 0, y = 0, z = 0}, + [RLEG] = {x = 0, y = 0, z = 0}, + + body_sit = {x = 0, y = 0, z = 0}, + body_lay = {x = 270, y = 0, z = 0}, + }, + MTG_4_Nov_2017 = { + [BODY] = {x = 0, y = 0, z = 0}, + [HEAD] = {x = 0, y = 0, z = 0}, + [CAPE] = {x = 0, y = 0, z = 0}, + [LARM] = {x = 0, y = 0, z = 0}, + [RARM] = {x = 0, y = 0, z = 0}, + [LLEG] = {x = 0, y = 0, z = 0}, + [RLEG] = {x = 0, y = 0, z = 0}, + + body_sit = {x = 0, y = 0, z = 0}, + body_lay = {x = 270, y = 0, z = 0}, + }, +} + +local PLAYER_MODEL_VERSION = (function() + local version = minetest.settings:get("playeranim.model_version") + if version == nil or version == "" then + version = DEFAULT_PLAYER_MODEL_VERSION + end + + if LEGACY_PLAYER_MODEL_VERSIONS[version] then + error("The model version '" .. version .. "' is no longer suppported") + elseif not VALID_PLAYER_MODEL_VERSIONS[version] then + error("Invalid value for playeranim.model_version in minetest.conf: " .. version) + end + + return version +end)() + +local BONE_POSITION = BONE_POSITIONS[PLAYER_MODEL_VERSION] +local BONE_ROTATION = BONE_ROTATIONS[PLAYER_MODEL_VERSION] +if not BONE_POSITION or not BONE_ROTATION then + error("Internal error: invalid player_model_version: " .. PLAYER_MODEL_VERSION) +end + +return BONE_POSITION, BONE_ROTATION diff --git a/playeranim/screenshot.png b/playeranim/screenshot.png Binary files differnew file mode 100644 index 0000000..57aeefe --- /dev/null +++ b/playeranim/screenshot.png diff --git a/playeranim/settingtypes.txt b/playeranim/settingtypes.txt new file mode 100644 index 0000000..a36322f --- /dev/null +++ b/playeranim/settingtypes.txt @@ -0,0 +1,18 @@ +# Version of player model. +# +# Player models supported by this mod: +# . -- `MTG_4_Jun_2017` (minetest_game after 4 Jun 2017, 0.4.16) +# . -- `MTG_4_Nov_2017` (minetest_game after 4 Nov 2017, 0.5.0) +playeranim.model_version (Version of player model) enum MTG_4_Jun_2017 MTG_4_Jun_2017,MTG_4_Nov_2017 + +# The number of frame delay of sideways body rotation. (between 1 and 20). +playeranim.body_rotation_delay (The delay of sideways body rotation) int 7 1 20 + +# The degrees of the body's X-axis rotation in sneaking. +playeranim.body_x_rotation_sneak (Lengthways body rotation in sneaking) float 6.0 + +# The number of stepping per seconds. +playeranim.animation_speed (The speed of an animation) float 2.4 + +# The number of stepping per seconds in sneaking. +playeranim.animation_speed_sneak (The speed of an animation in sneaking) float 0.8 |