Fix sneaking (fixes #665 and #3045)

This commit is contained in:
BlockMen 2015-08-12 23:25:26 +02:00
parent c4b5561b3f
commit 7238df4c59
2 changed files with 49 additions and 30 deletions

@ -48,9 +48,10 @@ LocalPlayer::LocalPlayer(IGameDef *gamedef, const char *name):
light_color(255,255,255,255), light_color(255,255,255,255),
m_sneak_node(32767,32767,32767), m_sneak_node(32767,32767,32767),
m_sneak_node_exists(false), m_sneak_node_exists(false),
m_need_to_get_new_sneak_node(true),
m_sneak_node_bb_ymax(0),
m_old_node_below(32767,32767,32767), m_old_node_below(32767,32767,32767),
m_old_node_below_type("air"), m_old_node_below_type("air"),
m_need_to_get_new_sneak_node(true),
m_can_jump(false), m_can_jump(false),
m_cao(NULL) m_cao(NULL)
{ {
@ -179,25 +180,26 @@ void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d,
If sneaking, keep in range from the last walked node and don't If sneaking, keep in range from the last walked node and don't
fall off from it fall off from it
*/ */
if(control.sneak && m_sneak_node_exists && if (control.sneak && m_sneak_node_exists &&
!(fly_allowed && g_settings->getBool("free_move")) && !in_liquid && !(fly_allowed && g_settings->getBool("free_move")) && !in_liquid &&
physics_override_sneak) physics_override_sneak) {
{ f32 maxd = 0.5 * BS + sneak_max;
f32 maxd = 0.5*BS + sneak_max;
v3f lwn_f = intToFloat(m_sneak_node, BS); v3f lwn_f = intToFloat(m_sneak_node, BS);
position.X = rangelim(position.X, lwn_f.X-maxd, lwn_f.X+maxd); position.X = rangelim(position.X, lwn_f.X-maxd, lwn_f.X+maxd);
position.Z = rangelim(position.Z, lwn_f.Z-maxd, lwn_f.Z+maxd); position.Z = rangelim(position.Z, lwn_f.Z-maxd, lwn_f.Z+maxd);
if(!is_climbing) if (!is_climbing) {
{ // Move up if necessary
f32 min_y = lwn_f.Y + 0.5*BS; f32 new_y = (lwn_f.Y - 0.5 * BS) + m_sneak_node_bb_ymax;
if(position.Y < min_y) if (position.Y < new_y)
{ position.Y = new_y;
position.Y = min_y; /*
Collision seems broken, since player is sinking when
if(m_speed.Y < 0) sneaking over the edges of current sneaking_node.
m_speed.Y = 0; TODO (when fixed): Set Y-speed only to 0 when position.Y < new_y.
} */
if (m_speed.Y < 0)
m_speed.Y = 0;
} }
} }
@ -230,27 +232,28 @@ void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d,
player is sneaking from, if any. If the node from under player is sneaking from, if any. If the node from under
the player has been removed, the player falls. the player has been removed, the player falls.
*/ */
v3s16 current_node = floatToInt(position - v3f(0, 0.05 * BS, 0), BS); f32 position_y_mod = 0.05 * BS;
if(m_sneak_node_exists && if (m_sneak_node_bb_ymax > 0)
nodemgr->get(map->getNodeNoEx(m_old_node_below)).name == "air" && position_y_mod = m_sneak_node_bb_ymax - position_y_mod;
m_old_node_below_type != "air") v3s16 current_node = floatToInt(position - v3f(0, position_y_mod, 0), BS);
{ if (m_sneak_node_exists &&
nodemgr->get(map->getNodeNoEx(m_old_node_below)).name == "air" &&
m_old_node_below_type != "air") {
// Old node appears to have been removed; that is, // Old node appears to have been removed; that is,
// it wasn't air before but now it is // it wasn't air before but now it is
m_need_to_get_new_sneak_node = false; m_need_to_get_new_sneak_node = false;
m_sneak_node_exists = false; m_sneak_node_exists = false;
} } else if (nodemgr->get(map->getNodeNoEx(current_node)).name != "air") {
else if(nodemgr->get(map->getNodeNoEx(current_node)).name != "air")
{
// We are on something, so make sure to recalculate the sneak // We are on something, so make sure to recalculate the sneak
// node. // node.
m_need_to_get_new_sneak_node = true; m_need_to_get_new_sneak_node = true;
} }
if(m_need_to_get_new_sneak_node && physics_override_sneak)
{ if (m_need_to_get_new_sneak_node && physics_override_sneak) {
v3s16 pos_i_bottom = floatToInt(position - v3f(0, 0.05 * BS ,0), BS); m_sneak_node_bb_ymax = 0;
v3s16 pos_i_bottom = floatToInt(position - v3f(0, position_y_mod, 0), BS);
v2f player_p2df(position.X, position.Z); v2f player_p2df(position.X, position.Z);
f32 min_distance_f = 100000.0*BS; f32 min_distance_f = 100000.0 * BS;
// If already seeking from some node, compare to it. // If already seeking from some node, compare to it.
/*if(m_sneak_node_exists) /*if(m_sneak_node_exists)
{ {
@ -298,11 +301,24 @@ void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d,
new_sneak_node = p; new_sneak_node = p;
} }
bool sneak_node_found = (min_distance_f < 100000.0*BS*0.9); bool sneak_node_found = (min_distance_f < 100000.0 * BS * 0.9);
m_sneak_node = new_sneak_node; m_sneak_node = new_sneak_node;
m_sneak_node_exists = sneak_node_found; m_sneak_node_exists = sneak_node_found;
if (sneak_node_found) {
f32 cb_max = 0;
MapNode n = map->getNodeNoEx(m_sneak_node);
std::vector<aabb3f> nodeboxes = n.getCollisionBoxes(nodemgr);
for (std::vector<aabb3f>::iterator it = nodeboxes.begin();
it != nodeboxes.end(); ++it) {
aabb3f box = *it;
if (box.MaxEdge.Y > cb_max)
cb_max = box.MaxEdge.Y;
}
m_sneak_node_bb_ymax = cb_max;
}
/* /*
If sneaking, the player's collision box can be in air, so If sneaking, the player's collision box can be in air, so
this has to be set explicitly this has to be set explicitly

@ -85,12 +85,15 @@ private:
v3s16 m_sneak_node; v3s16 m_sneak_node;
// Whether the player is allowed to sneak // Whether the player is allowed to sneak
bool m_sneak_node_exists; bool m_sneak_node_exists;
// Whether recalculation of the sneak node is needed
bool m_need_to_get_new_sneak_node;
// Stores the max player uplift by m_sneak_node and is updated
// when m_need_to_get_new_sneak_node == true
f32 m_sneak_node_bb_ymax;
// Node below player, used to determine whether it has been removed, // Node below player, used to determine whether it has been removed,
// and its old type // and its old type
v3s16 m_old_node_below; v3s16 m_old_node_below;
std::string m_old_node_below_type; std::string m_old_node_below_type;
// Whether recalculation of the sneak node is needed
bool m_need_to_get_new_sneak_node;
bool m_can_jump; bool m_can_jump;
GenericCAO* m_cao; GenericCAO* m_cao;