Fix player head with wrong pitch while swiming

This commit is contained in:
epCode 2021-02-06 18:18:19 -08:00
parent c5169e48a1
commit 29d43b9709

@ -1,287 +1,294 @@
local S = minetest.get_translator("mcl_playerplus") local S = minetest.get_translator("mcl_playerplus")
-- Internal player state -- Internal player state
local mcl_playerplus_internal = {} local mcl_playerplus_internal = {}
local def = {} local def = {}
local time = 0 local time = 0
-- converts yaw to degrees -- converts yaw to degrees
local function degrees(rad) local function degrees(rad)
return rad * 180.0 / math.pi return rad * 180.0 / math.pi
end end
local pitch, name, node_stand, node_stand_below, node_head, node_feet, pos local pitch, name, node_stand, node_stand_below, node_head, node_feet, pos
minetest.register_globalstep(function(dtime) minetest.register_globalstep(function(dtime)
time = time + dtime time = time + dtime
-- Update jump status immediately since we need this info in real time. -- Update jump status immediately since we need this info in real time.
-- WARNING: This section is HACKY as hell since it is all just based on heuristics. -- WARNING: This section is HACKY as hell since it is all just based on heuristics.
for _,player in pairs(minetest.get_connected_players()) do for _,player in pairs(minetest.get_connected_players()) do
local controls = player:get_player_control() local controls = player:get_player_control()
name = player:get_player_name() name = player:get_player_name()
-- controls head bone -- controls head bone
pitch = degrees(player:get_look_vertical()) * -1 pitch = degrees(player:get_look_vertical()) * -1
if controls.LMB then if controls.LMB then
player:set_bone_position("Arm_Right_Pitch_Control", vector.new(-3,5.785,0), vector.new(pitch,0,0)) player:set_bone_position("Arm_Right_Pitch_Control", vector.new(-3,5.785,0), vector.new(pitch,0,0))
else else
player:set_bone_position("Arm_Right_Pitch_Control", vector.new(-3,5.785,0), vector.new(0,0,0)) player:set_bone_position("Arm_Right_Pitch_Control", vector.new(-3,5.785,0), vector.new(0,0,0))
end end
if controls.sneak and player:get_attach() == nil then if controls.sneak and player:get_attach() == nil then
-- controls head pitch when sneaking -- controls head pitch when sneaking
player:set_bone_position("Head", vector.new(0,6.3,0), vector.new(pitch+36,0,0)) player:set_bone_position("Head", vector.new(0,6.3,0), vector.new(pitch+36,0,0))
-- sets collisionbox, eye height, and nametag color accordingly -- sets collisionbox, eye height, and nametag color accordingly
if player:get_properties().collisionbox ~= {-0.35,0,-0.35,0.35,1.35,0.35} then if player:get_properties().collisionbox ~= {-0.35,0,-0.35,0.35,1.35,0.35} then
player:set_properties({collisionbox = {-0.35,0,-0.35,0.35,1.35,0.35}, eye_height = 1.35, nametag_color = { r = 255, b = 225, a = 0, g = 225 }}) player:set_properties({collisionbox = {-0.35,0,-0.35,0.35,1.35,0.35}, eye_height = 1.35, nametag_color = { r = 255, b = 225, a = 0, g = 225 }})
end end
else elseif minetest.get_item_group(mcl_playerinfo[name].node_stand, "water") ~= 0 then
-- controls head pitch when not sneaking -- controls head pitch when swiming
player:set_bone_position("Head", vector.new(0,6.3,0), vector.new(pitch,0,0)) player:set_bone_position("Head", vector.new(0,6.3,0), vector.new(pitch+90,0,0))
-- sets collisionbox, eye height, and nametag color accordingly -- sets collisionbox, eye height, and nametag color accordingly
if player:get_properties().collisionbox ~= {-0.35,0,-0.35,0.35,1.8,0.35} then if player:get_properties().collisionbox ~= {-0.35,0.2,-0.35,0.35,1.8,0.35} then
player:set_properties({collisionbox = {-0.35,0,-0.35,0.35,1.8,0.35}, eye_height = 1.65, nametag_color = { r = 255, b = 225, a = 225, g = 225 }}) player:set_properties({collisionbox = {-0.35,0.2,-0.35,0.35,1.8,0.35}, eye_height = 1.65, nametag_color = { r = 255, b = 225, a = 225, g = 225 }})
end end
end else
-- controls head pitch when not sneaking
if mcl_playerplus_internal[name].jump_cooldown > 0 then player:set_bone_position("Head", vector.new(0,6.3,0), vector.new(pitch,0,0))
mcl_playerplus_internal[name].jump_cooldown = mcl_playerplus_internal[name].jump_cooldown - dtime -- sets collisionbox, eye height, and nametag color accordingly
end if player:get_properties().collisionbox ~= {-0.35,0,-0.35,0.35,1.8,0.35} then
if player:get_player_control().jump and mcl_playerplus_internal[name].jump_cooldown <= 0 then player:set_properties({collisionbox = {-0.35,0,-0.35,0.35,1.8,0.35}, eye_height = 1.65, nametag_color = { r = 255, b = 225, a = 225, g = 225 }})
end
pos = player:get_pos() end
node_stand = mcl_playerinfo[name].node_stand if mcl_playerplus_internal[name].jump_cooldown > 0 then
node_stand_below = mcl_playerinfo[name].node_stand_below mcl_playerplus_internal[name].jump_cooldown = mcl_playerplus_internal[name].jump_cooldown - dtime
node_head = mcl_playerinfo[name].node_head end
node_feet = mcl_playerinfo[name].node_feet if player:get_player_control().jump and mcl_playerplus_internal[name].jump_cooldown <= 0 then
if not node_stand or not node_stand_below or not node_head or not node_feet then
return pos = player:get_pos()
end
if not minetest.registered_nodes[node_stand] or not minetest.registered_nodes[node_stand_below] or not minetest.registered_nodes[node_head] or not minetest.registered_nodes[node_feet] then node_stand = mcl_playerinfo[name].node_stand
return node_stand_below = mcl_playerinfo[name].node_stand_below
end node_head = mcl_playerinfo[name].node_head
node_feet = mcl_playerinfo[name].node_feet
-- Cause buggy exhaustion for jumping if not node_stand or not node_stand_below or not node_head or not node_feet then
return
--[[ Checklist we check to know the player *actually* jumped: end
* Not on or in liquid if not minetest.registered_nodes[node_stand] or not minetest.registered_nodes[node_stand_below] or not minetest.registered_nodes[node_head] or not minetest.registered_nodes[node_feet] then
* Not on or at climbable return
* On walkable end
* Not on disable_jump
FIXME: This code is pretty hacky and it is possible to miss some jumps or detect false -- Cause buggy exhaustion for jumping
jumps because of delays, rounding errors, etc.
What this code *really* needs is some kind of jumping callback which this engine lacks --[[ Checklist we check to know the player *actually* jumped:
as of 0.4.15. * Not on or in liquid
]] * Not on or at climbable
* On walkable
if minetest.get_item_group(node_feet, "liquid") == 0 and * Not on disable_jump
minetest.get_item_group(node_stand, "liquid") == 0 and FIXME: This code is pretty hacky and it is possible to miss some jumps or detect false
not minetest.registered_nodes[node_feet].climbable and jumps because of delays, rounding errors, etc.
not minetest.registered_nodes[node_stand].climbable and What this code *really* needs is some kind of jumping callback which this engine lacks
(minetest.registered_nodes[node_stand].walkable or minetest.registered_nodes[node_stand_below].walkable) as of 0.4.15.
and minetest.get_item_group(node_stand, "disable_jump") == 0 ]]
and minetest.get_item_group(node_stand_below, "disable_jump") == 0 then
-- Cause exhaustion for jumping if minetest.get_item_group(node_feet, "liquid") == 0 and
if mcl_sprint.is_sprinting(name) then minetest.get_item_group(node_stand, "liquid") == 0 and
mcl_hunger.exhaust(name, mcl_hunger.EXHAUST_SPRINT_JUMP) not minetest.registered_nodes[node_feet].climbable and
else not minetest.registered_nodes[node_stand].climbable and
mcl_hunger.exhaust(name, mcl_hunger.EXHAUST_JUMP) (minetest.registered_nodes[node_stand].walkable or minetest.registered_nodes[node_stand_below].walkable)
end and minetest.get_item_group(node_stand, "disable_jump") == 0
and minetest.get_item_group(node_stand_below, "disable_jump") == 0 then
-- Reset cooldown timer -- Cause exhaustion for jumping
mcl_playerplus_internal[name].jump_cooldown = 0.45 if mcl_sprint.is_sprinting(name) then
end mcl_hunger.exhaust(name, mcl_hunger.EXHAUST_SPRINT_JUMP)
end else
end mcl_hunger.exhaust(name, mcl_hunger.EXHAUST_JUMP)
end
-- Run the rest of the code every 0.5 seconds
if time < 0.5 then -- Reset cooldown timer
return mcl_playerplus_internal[name].jump_cooldown = 0.45
end end
end
-- reset time for next check end
-- FIXME: Make sure a regular check interval applies
time = 0 -- Run the rest of the code every 0.5 seconds
if time < 0.5 then
-- check players return
for _,player in pairs(minetest.get_connected_players()) do end
-- who am I?
local name = player:get_player_name() -- reset time for next check
-- FIXME: Make sure a regular check interval applies
-- where am I? time = 0
local pos = player:get_pos()
-- check players
-- what is around me? for _,player in pairs(minetest.get_connected_players()) do
local node_stand = mcl_playerinfo[name].node_stand -- who am I?
local node_stand_below = mcl_playerinfo[name].node_stand_below local name = player:get_player_name()
local node_head = mcl_playerinfo[name].node_head
local node_feet = mcl_playerinfo[name].node_feet -- where am I?
if not node_stand or not node_stand_below or not node_head or not node_feet then local pos = player:get_pos()
return
end -- what is around me?
local node_stand = mcl_playerinfo[name].node_stand
-- set defaults local node_stand_below = mcl_playerinfo[name].node_stand_below
def.speed = 1 local node_head = mcl_playerinfo[name].node_head
local node_feet = mcl_playerinfo[name].node_feet
-- Standing on soul sand? If so, walk slower (unless player wears Soul Speed boots) if not node_stand or not node_stand_below or not node_head or not node_feet then
if node_stand == "mcl_nether:soul_sand" then return
-- TODO: Tweak walk speed end
-- TODO: Also slow down mobs
-- Slow down even more when soul sand is above certain block -- set defaults
local boots = player:get_inventory():get_stack("armor", 5) def.speed = 1
local soul_speed = mcl_enchanting.get_enchantment(boots, "soul_speed")
if soul_speed > 0 then -- Standing on soul sand? If so, walk slower (unless player wears Soul Speed boots)
playerphysics.add_physics_factor(player, "speed", "mcl_playerplus:surface", soul_speed * 0.105 + 1.3) if node_stand == "mcl_nether:soul_sand" then
else -- TODO: Tweak walk speed
if node_stand_below == "mcl_core:ice" or node_stand_below == "mcl_core:packed_ice" or node_stand_below == "mcl_core:slimeblock" or node_stand_below == "mcl_core:water_source" then -- TODO: Also slow down mobs
playerphysics.add_physics_factor(player, "speed", "mcl_playerplus:surface", 0.1) -- Slow down even more when soul sand is above certain block
else local boots = player:get_inventory():get_stack("armor", 5)
playerphysics.add_physics_factor(player, "speed", "mcl_playerplus:surface", 0.4) local soul_speed = mcl_enchanting.get_enchantment(boots, "soul_speed")
end if soul_speed > 0 then
end playerphysics.add_physics_factor(player, "speed", "mcl_playerplus:surface", soul_speed * 0.105 + 1.3)
else else
-- Reset speed decrease if node_stand_below == "mcl_core:ice" or node_stand_below == "mcl_core:packed_ice" or node_stand_below == "mcl_core:slimeblock" or node_stand_below == "mcl_core:water_source" then
playerphysics.remove_physics_factor(player, "speed", "mcl_playerplus:surface") playerphysics.add_physics_factor(player, "speed", "mcl_playerplus:surface", 0.1)
end else
playerphysics.add_physics_factor(player, "speed", "mcl_playerplus:surface", 0.4)
-- Is player suffocating inside node? (Only for solid full opaque cube type nodes end
-- without group disable_suffocation=1) end
local ndef = minetest.registered_nodes[node_head] else
-- Reset speed decrease
if (ndef.walkable == nil or ndef.walkable == true) playerphysics.remove_physics_factor(player, "speed", "mcl_playerplus:surface")
and (ndef.collision_box == nil or ndef.collision_box.type == "regular") end
and (ndef.node_box == nil or ndef.node_box.type == "regular")
and (ndef.groups.disable_suffocation ~= 1) -- Is player suffocating inside node? (Only for solid full opaque cube type nodes
and (ndef.groups.opaque == 1) -- without group disable_suffocation=1)
and (node_head ~= "ignore") local ndef = minetest.registered_nodes[node_head]
-- Check privilege, too
and (not minetest.check_player_privs(name, {noclip = true})) then if (ndef.walkable == nil or ndef.walkable == true)
if player:get_hp() > 0 then and (ndef.collision_box == nil or ndef.collision_box.type == "regular")
mcl_death_messages.player_damage(player, S("@1 suffocated to death.", name)) and (ndef.node_box == nil or ndef.node_box.type == "regular")
player:set_hp(player:get_hp() - 1) and (ndef.groups.disable_suffocation ~= 1)
end and (ndef.groups.opaque == 1)
end and (node_head ~= "ignore")
-- Check privilege, too
-- Am I near a cactus? and (not minetest.check_player_privs(name, {noclip = true})) then
local near = minetest.find_node_near(pos, 1, "mcl_core:cactus") if player:get_hp() > 0 then
if not near then mcl_death_messages.player_damage(player, S("@1 suffocated to death.", name))
near = minetest.find_node_near({x=pos.x, y=pos.y-1, z=pos.z}, 1, "mcl_core:cactus") player:set_hp(player:get_hp() - 1)
end end
if near then end
-- Am I touching the cactus? If so, it hurts
local dist = vector.distance(pos, near) -- Am I near a cactus?
local dist_feet = vector.distance({x=pos.x, y=pos.y-1, z=pos.z}, near) local near = minetest.find_node_near(pos, 1, "mcl_core:cactus")
if dist < 1.1 or dist_feet < 1.1 then if not near then
if player:get_hp() > 0 then near = minetest.find_node_near({x=pos.x, y=pos.y-1, z=pos.z}, 1, "mcl_core:cactus")
mcl_death_messages.player_damage(player, S("@1 was prickled to death by a cactus.", name)) end
player:set_hp(player:get_hp() - 1, { type = "punch", from = "mod" }) if near then
end -- Am I touching the cactus? If so, it hurts
end local dist = vector.distance(pos, near)
end local dist_feet = vector.distance({x=pos.x, y=pos.y-1, z=pos.z}, near)
if dist < 1.1 or dist_feet < 1.1 then
--[[ Swimming: Cause exhaustion. if player:get_hp() > 0 then
NOTE: As of 0.4.15, it only counts as swimming when you are with the feet inside the liquid! mcl_death_messages.player_damage(player, S("@1 was prickled to death by a cactus.", name))
Head alone does not count. We respect that for now. ]] player:set_hp(player:get_hp() - 1, { type = "punch", from = "mod" })
if minetest.get_item_group(node_feet, "liquid") ~= 0 or end
minetest.get_item_group(node_stand, "liquid") ~= 0 then end
local lastPos = mcl_playerplus_internal[name].lastPos end
if lastPos then
local dist = vector.distance(lastPos, pos) --[[ Swimming: Cause exhaustion.
mcl_playerplus_internal[name].swimDistance = mcl_playerplus_internal[name].swimDistance + dist NOTE: As of 0.4.15, it only counts as swimming when you are with the feet inside the liquid!
if mcl_playerplus_internal[name].swimDistance >= 1 then Head alone does not count. We respect that for now. ]]
local superficial = math.floor(mcl_playerplus_internal[name].swimDistance) if minetest.get_item_group(node_feet, "liquid") ~= 0 or
mcl_hunger.exhaust(name, mcl_hunger.EXHAUST_SWIM * superficial) minetest.get_item_group(node_stand, "liquid") ~= 0 then
mcl_playerplus_internal[name].swimDistance = mcl_playerplus_internal[name].swimDistance - superficial local lastPos = mcl_playerplus_internal[name].lastPos
end if lastPos then
end local dist = vector.distance(lastPos, pos)
mcl_playerplus_internal[name].swimDistance = mcl_playerplus_internal[name].swimDistance + dist
end if mcl_playerplus_internal[name].swimDistance >= 1 then
local superficial = math.floor(mcl_playerplus_internal[name].swimDistance)
-- Underwater: Spawn bubble particles mcl_hunger.exhaust(name, mcl_hunger.EXHAUST_SWIM * superficial)
if minetest.get_item_group(node_head, "water") ~= 0 then mcl_playerplus_internal[name].swimDistance = mcl_playerplus_internal[name].swimDistance - superficial
end
minetest.add_particlespawner({ end
amount = 10,
time = 0.15, end
minpos = { x = -0.25, y = 0.3, z = -0.25 },
maxpos = { x = 0.25, y = 0.7, z = 0.75 }, -- Underwater: Spawn bubble particles
attached = player, if minetest.get_item_group(node_head, "water") ~= 0 then
minvel = {x = -0.2, y = 0, z = -0.2},
maxvel = {x = 0.5, y = 0, z = 0.5}, minetest.add_particlespawner({
minacc = {x = -0.4, y = 4, z = -0.4}, amount = 10,
maxacc = {x = 0.5, y = 1, z = 0.5}, time = 0.15,
minexptime = 0.3, minpos = { x = -0.25, y = 0.3, z = -0.25 },
maxexptime = 0.8, maxpos = { x = 0.25, y = 0.7, z = 0.75 },
minsize = 0.7, attached = player,
maxsize = 2.4, minvel = {x = -0.2, y = 0, z = -0.2},
texture = "mcl_particles_bubble.png" maxvel = {x = 0.5, y = 0, z = 0.5},
}) minacc = {x = -0.4, y = 4, z = -0.4},
end maxacc = {x = 0.5, y = 1, z = 0.5},
minexptime = 0.3,
-- Show positions of barriers when player is wielding a barrier maxexptime = 0.8,
local wi = player:get_wielded_item():get_name() minsize = 0.7,
if wi == "mcl_core:barrier" or wi == "mcl_core:realm_barrier" then maxsize = 2.4,
local pos = vector.round(player:get_pos()) texture = "mcl_particles_bubble.png"
local r = 8 })
local vm = minetest.get_voxel_manip() end
local emin, emax = vm:read_from_map({x=pos.x-r, y=pos.y-r, z=pos.z-r}, {x=pos.x+r, y=pos.y+r, z=pos.z+r})
local area = VoxelArea:new{ -- Show positions of barriers when player is wielding a barrier
MinEdge = emin, local wi = player:get_wielded_item():get_name()
MaxEdge = emax, if wi == "mcl_core:barrier" or wi == "mcl_core:realm_barrier" then
} local pos = vector.round(player:get_pos())
local data = vm:get_data() local r = 8
for x=pos.x-r, pos.x+r do local vm = minetest.get_voxel_manip()
for y=pos.y-r, pos.y+r do local emin, emax = vm:read_from_map({x=pos.x-r, y=pos.y-r, z=pos.z-r}, {x=pos.x+r, y=pos.y+r, z=pos.z+r})
for z=pos.z-r, pos.z+r do local area = VoxelArea:new{
local vi = area:indexp({x=x, y=y, z=z}) MinEdge = emin,
local nodename = minetest.get_name_from_content_id(data[vi]) MaxEdge = emax,
local tex }
if nodename == "mcl_core:barrier" then local data = vm:get_data()
tex = "mcl_core_barrier.png" for x=pos.x-r, pos.x+r do
elseif nodename == "mcl_core:realm_barrier" then for y=pos.y-r, pos.y+r do
tex = "mcl_core_barrier.png^[colorize:#FF00FF:127^[transformFX" for z=pos.z-r, pos.z+r do
end local vi = area:indexp({x=x, y=y, z=z})
if tex then local nodename = minetest.get_name_from_content_id(data[vi])
minetest.add_particle({ local tex
pos = {x=x, y=y, z=z}, if nodename == "mcl_core:barrier" then
expirationtime = 1, tex = "mcl_core_barrier.png"
size = 8, elseif nodename == "mcl_core:realm_barrier" then
texture = tex, tex = "mcl_core_barrier.png^[colorize:#FF00FF:127^[transformFX"
glow = 14, end
playername = name if tex then
}) minetest.add_particle({
end pos = {x=x, y=y, z=z},
end expirationtime = 1,
end size = 8,
end texture = tex,
end glow = 14,
playername = name
-- Update internal values })
mcl_playerplus_internal[name].lastPos = pos end
end
end end
end
end) end
-- set to blank on join (for 3rd party mods) -- Update internal values
minetest.register_on_joinplayer(function(player) mcl_playerplus_internal[name].lastPos = pos
local name = player:get_player_name()
end
mcl_playerplus_internal[name] = {
lastPos = nil, end)
swimDistance = 0,
jump_cooldown = -1, -- Cooldown timer for jumping, we need this to prevent the jump exhaustion to increase rapidly -- set to blank on join (for 3rd party mods)
} minetest.register_on_joinplayer(function(player)
end) local name = player:get_player_name()
-- clear when player leaves mcl_playerplus_internal[name] = {
minetest.register_on_leaveplayer(function(player) lastPos = nil,
local name = player:get_player_name() swimDistance = 0,
jump_cooldown = -1, -- Cooldown timer for jumping, we need this to prevent the jump exhaustion to increase rapidly
mcl_playerplus_internal[name] = nil }
end) end)
-- clear when player leaves
minetest.register_on_leaveplayer(function(player)
local name = player:get_player_name()
mcl_playerplus_internal[name] = nil
end)