Minetest Mod: Adds animations to the players' head.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

321 lines
9.9KB

  1. if not minetest.settings then
  2. error("Mod playeranim requires Minetest 0.4.16 or newer")
  3. end
  4. local ANIMATION_SPEED = tonumber(minetest.settings:get("playeranim.animation_speed")) or 2.4
  5. local ANIMATION_SPEED_SNEAK = tonumber(minetest.settings:get("playeranim.animation_speed_sneak")) or 0.8
  6. local BODY_ROTATION_DELAY = math.max(math.floor(tonumber(minetest.settings:get("playeranim.body_rotation_delay")) or 7), 1)
  7. local BODY_X_ROTATION_SNEAK = tonumber(minetest.settings:get("playeranim.body_x_rotation_sneak")) or 6.0
  8. local BONE_POSITION, BONE_ROTATION = (function()
  9. local modname = minetest.get_current_modname()
  10. local modpath = minetest.get_modpath(modname)
  11. return dofile(modpath .. "/model.lua")
  12. end)()
  13. local get_animation = minetest.global_exists("player_api")
  14. and player_api.get_animation or default.player_get_animation
  15. if not get_animation then
  16. error("player_api.get_animation or default.player_get_animation is not found")
  17. end
  18. -- stop player_api from messing stuff up (since 5.3)
  19. if minetest.global_exists("player_api") then
  20. for _, v in pairs(player_api.registered_models["character.b3d"].animations) do
  21. v.x = 0
  22. v.y = 0
  23. end
  24. minetest.register_on_joinplayer(function(player)
  25. player:set_local_animation(nil, nil, nil, nil, 0)
  26. end)
  27. end
  28. local function get_animation_speed(player)
  29. if player:get_player_control().sneak then
  30. return ANIMATION_SPEED_SNEAK
  31. end
  32. return ANIMATION_SPEED
  33. end
  34. local math_deg = math.deg
  35. local function get_pitch_deg(player)
  36. return math_deg(player:get_look_vertical())
  37. end
  38. local players_animation_data = setmetatable({}, {
  39. __index = {
  40. init_player = function(self, player)
  41. self[player] = {
  42. time = 0,
  43. yaw_history = {},
  44. bone_rotations = {},
  45. bone_positions = {},
  46. previous_animation = 0,
  47. }
  48. end,
  49. -- time
  50. get_time = function(self, player)
  51. return self[player].time
  52. end,
  53. increment_time = function(self, player, dtime)
  54. self[player].time = self:get_time(player) + dtime
  55. end,
  56. reset_time = function(self, player)
  57. self[player].time = 0
  58. end,
  59. -- yaw_history
  60. get_yaw_history = function(self, player)
  61. return self[player].yaw_history -- Return mutable reference
  62. end,
  63. add_yaw_to_history = function(self, player)
  64. local yaw = player:get_look_horizontal()
  65. local history = self:get_yaw_history(player)
  66. history[#history + 1] = yaw
  67. end,
  68. clear_yaw_history = function(self, player)
  69. if #self[player].yaw_history > 0 then
  70. self[player].yaw_history = {}
  71. end
  72. end,
  73. -- bone_rotations
  74. get_bone_rotation = function(self, player, bone)
  75. return self[player].bone_rotations[bone]
  76. end,
  77. set_bone_rotation = function(self, player, bone, rotation)
  78. self[player].bone_rotations[bone] = rotation
  79. end,
  80. -- bone_positions
  81. get_bone_position = function(self, player, bone)
  82. return self[player].bone_positions[bone]
  83. end,
  84. set_bone_position = function(self, player, bone, position)
  85. self[player].bone_positions[bone] = position
  86. end,
  87. -- previous_animation
  88. get_previous_animation = function(self, player)
  89. return self[player].previous_animation
  90. end,
  91. set_previous_animation = function(self, player, animation)
  92. self[player].previous_animation = animation
  93. end,
  94. }
  95. })
  96. minetest.register_on_joinplayer(function(player)
  97. players_animation_data:init_player(player)
  98. end)
  99. local vector_add, vector_equals = vector.add, vector.equals
  100. local function rotate_bone(player, bone, rotation, position_optional)
  101. local previous_rotation = players_animation_data:get_bone_rotation(player, bone)
  102. local rotation = vector_add(rotation, BONE_ROTATION[bone])
  103. local previous_position = players_animation_data:get_bone_position(player, bone)
  104. local position = BONE_POSITION[bone]
  105. if position_optional then
  106. position = vector_add(position, position_optional)
  107. end
  108. if not previous_rotation
  109. or not previous_position
  110. or not vector_equals(rotation, previous_rotation)
  111. or not vector_equals(position, previous_position) then
  112. player:set_bone_position(bone, position, rotation)
  113. players_animation_data:set_bone_rotation(player, bone, rotation)
  114. players_animation_data:set_bone_position(player, bone, position)
  115. end
  116. end
  117. -- Animation alias
  118. local STAND = 1
  119. local WALK = 2
  120. local MINE = 3
  121. local WALK_MINE = 4
  122. local SIT = 5
  123. local LAY = 6
  124. -- Bone alias
  125. local BODY = "Body"
  126. local HEAD = "Head"
  127. local CAPE = "Cape"
  128. local LARM = "Arm_Left"
  129. local RARM = "Arm_Right"
  130. local LLEG = "Leg_Left"
  131. local RLEG = "Leg_Right"
  132. local math_sin, math_cos, math_pi = math.sin, math.cos, math.pi
  133. local ANIMATIONS = {
  134. [STAND] = function(player, _time)
  135. rotate_bone(player, BODY, {x = 0, y = 0, z = 0})
  136. rotate_bone(player, CAPE, {x = 0, y = 0, z = 0})
  137. rotate_bone(player, LARM, {x = 0, y = 0, z = 0})
  138. rotate_bone(player, RARM, {x = 0, y = 0, z = 0})
  139. rotate_bone(player, LLEG, {x = 0, y = 0, z = 0})
  140. rotate_bone(player, RLEG, {x = 0, y = 0, z = 0})
  141. end,
  142. [LAY] = function(player, _time)
  143. rotate_bone(player, HEAD, {x = 0, y = 0, z = 0})
  144. rotate_bone(player, CAPE, {x = 0, y = 0, z = 0})
  145. rotate_bone(player, LARM, {x = 0, y = 0, z = 0})
  146. rotate_bone(player, RARM, {x = 0, y = 0, z = 0})
  147. rotate_bone(player, LLEG, {x = 0, y = 0, z = 0})
  148. rotate_bone(player, RLEG, {x = 0, y = 0, z = 0})
  149. rotate_bone(player, BODY, BONE_ROTATION.body_lay, BONE_POSITION.body_lay)
  150. end,
  151. [SIT] = function(player, _time)
  152. rotate_bone(player, LARM, {x = 0, y = 0, z = 0})
  153. rotate_bone(player, RARM, {x = 0, y = 0, z = 0})
  154. rotate_bone(player, LLEG, {x = 90, y = 0, z = 0})
  155. rotate_bone(player, RLEG, {x = 90, y = 0, z = 0})
  156. rotate_bone(player, BODY, BONE_ROTATION.body_sit, BONE_POSITION.body_sit)
  157. end,
  158. [WALK] = function(player, time)
  159. local speed = get_animation_speed(player)
  160. local sin = math_sin(time * speed * math_pi)
  161. rotate_bone(player, CAPE, {x = -35 * sin - 35, y = 0, z = 0})
  162. rotate_bone(player, LARM, {x = -55 * sin, y = 0, z = 0})
  163. rotate_bone(player, RARM, {x = 55 * sin, y = 0, z = 0})
  164. rotate_bone(player, LLEG, {x = 55 * sin, y = 0, z = 0})
  165. rotate_bone(player, RLEG, {x = -55 * sin, y = 0, z = 0})
  166. end,
  167. [MINE] = function(player, time)
  168. local speed = get_animation_speed(player)
  169. local cape_sin = math_sin(time * speed * math_pi)
  170. local rarm_sin = math_sin(2 * time * speed * math_pi)
  171. local rarm_cos = -math_cos(2 * time * speed * math_pi)
  172. local pitch = 90 - get_pitch_deg(player)
  173. rotate_bone(player, CAPE, {x = -5 * cape_sin - 5, y = 0, z = 0})
  174. rotate_bone(player, LARM, {x = 0, y = 0, z = 0})
  175. rotate_bone(player, RARM, {x = 10 * rarm_sin + pitch, y = 10 * rarm_cos, z = 0})
  176. rotate_bone(player, LLEG, {x = 0, y = 0, z = 0})
  177. rotate_bone(player, RLEG, {x = 0, y = 0, z = 0})
  178. end,
  179. [WALK_MINE] = function(player, time)
  180. local speed = get_animation_speed(player)
  181. local sin = math_sin(time * speed * math_pi)
  182. local rarm_sin = math_sin(2 * time * speed * math_pi)
  183. local rarm_cos = -math_cos(2 * time * speed * math_pi)
  184. local pitch = 90 - get_pitch_deg(player)
  185. rotate_bone(player, CAPE, {x = -35 * sin - 35, y = 0, z = 0})
  186. rotate_bone(player, LARM, {x = -55 * sin, y = 0, z = 0})
  187. rotate_bone(player, RARM, {x = 10 * rarm_sin + pitch, y = 10 * rarm_cos, z = 0})
  188. rotate_bone(player, LLEG, {x = 55 * sin, y = 0, z = 0})
  189. rotate_bone(player, RLEG, {x = -55 * sin, y = 0, z = 0})
  190. end,
  191. }
  192. local function set_animation(player, animation, force_animate)
  193. local animation_changed
  194. = (players_animation_data:get_previous_animation(player) ~= animation)
  195. if force_animate or animation_changed then
  196. players_animation_data:set_previous_animation(player, animation)
  197. ANIMATIONS[animation](player, players_animation_data:get_time(player))
  198. end
  199. end
  200. local function rotate_head(player)
  201. local head_x_rotation = -get_pitch_deg(player)
  202. rotate_bone(player, HEAD, {x = head_x_rotation, y = 0, z = 0})
  203. end
  204. local table_remove, math_deg = table.remove, math.deg
  205. local function rotate_body_and_head(player)
  206. local body_x_rotation = (function()
  207. local sneak = player:get_player_control().sneak
  208. return sneak and BODY_X_ROTATION_SNEAK or 0
  209. end)()
  210. local body_y_rotation = (function()
  211. local yaw_history = players_animation_data:get_yaw_history(player)
  212. if #yaw_history > BODY_ROTATION_DELAY then
  213. local body_yaw = table_remove(yaw_history, 1)
  214. local player_yaw = player:get_look_horizontal()
  215. return math_deg(player_yaw - body_yaw)
  216. end
  217. return 0
  218. end)()
  219. rotate_bone(player, BODY, {x = body_x_rotation, y = body_y_rotation, z = 0})
  220. local head_x_rotation = -get_pitch_deg(player)
  221. rotate_bone(player, HEAD, {x = head_x_rotation, y = -body_y_rotation, z = 0})
  222. end
  223. local function animate_player(player, dtime)
  224. local animation = get_animation(player).animation
  225. -- Yaw history
  226. if animation == "lay" or animation == "sit" then
  227. players_animation_data:clear_yaw_history(player)
  228. else
  229. players_animation_data:add_yaw_to_history(player)
  230. end
  231. -- Increment animation time
  232. if animation == "walk"
  233. or animation == "mine"
  234. or animation == "walk_mine" then
  235. players_animation_data:increment_time(player, dtime)
  236. else
  237. players_animation_data:reset_time(player)
  238. end
  239. -- Set animation
  240. if animation == "stand" then
  241. set_animation(player, STAND)
  242. elseif animation == "lay" then
  243. set_animation(player, LAY)
  244. elseif animation == "sit" then
  245. set_animation(player, SIT)
  246. elseif animation == "walk" then
  247. set_animation(player, WALK, true)
  248. elseif animation == "mine" then
  249. set_animation(player, MINE, true)
  250. elseif animation == "walk_mine" then
  251. set_animation(player, WALK_MINE, true)
  252. end
  253. -- Rotate body and head
  254. if animation == "lay" then
  255. -- Do nothing
  256. elseif animation == "sit" then
  257. rotate_head(player)
  258. else
  259. rotate_body_and_head(player)
  260. end
  261. end
  262. local minetest_get_connected_players = minetest.get_connected_players
  263. minetest.register_globalstep(function(dtime)
  264. for _, player in ipairs(minetest_get_connected_players()) do
  265. animate_player(player, dtime)
  266. end
  267. end)
  268. minetest.log("action", "[playeranim] loaded.")