forked from Mirrorlandia_minetest/minetest
Sneak: Replicate sneak ladder in new code, is optional
Enabled using the existing 'sneak_glitch' physics override.
This commit is contained in:
parent
e70e15134c
commit
1139a18c3a
@ -66,9 +66,10 @@ LocalPlayer::LocalPlayer(Client *client, const char *name):
|
|||||||
hurt_tilt_strength(0.0f),
|
hurt_tilt_strength(0.0f),
|
||||||
m_position(0,0,0),
|
m_position(0,0,0),
|
||||||
m_sneak_node(32767,32767,32767),
|
m_sneak_node(32767,32767,32767),
|
||||||
|
m_sneak_node_bb_top(0,0,0,0,0,0),
|
||||||
m_sneak_node_exists(false),
|
m_sneak_node_exists(false),
|
||||||
m_need_to_get_new_sneak_node(true),
|
m_need_to_get_new_sneak_node(true),
|
||||||
m_sneak_node_bb_top(0,0,0,0,0,0),
|
m_sneak_ladder_detected(false),
|
||||||
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_can_jump(false),
|
m_can_jump(false),
|
||||||
@ -91,7 +92,7 @@ LocalPlayer::~LocalPlayer()
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
static aabb3f getTopBoundingBox(const std::vector<aabb3f> &nodeboxes, float max_d=1/16*BS)
|
static aabb3f getTopBoundingBox(const std::vector<aabb3f> &nodeboxes)
|
||||||
{
|
{
|
||||||
aabb3f b_max;
|
aabb3f b_max;
|
||||||
b_max.reset(-BS, -BS, -BS);
|
b_max.reset(-BS, -BS, -BS);
|
||||||
@ -106,6 +107,50 @@ static aabb3f getTopBoundingBox(const std::vector<aabb3f> &nodeboxes, float max_
|
|||||||
return aabb3f(v3f(b_max.MinEdge.X, b_max.MaxEdge.Y, b_max.MinEdge.Z), b_max.MaxEdge);
|
return aabb3f(v3f(b_max.MinEdge.X, b_max.MaxEdge.Y, b_max.MinEdge.Z), b_max.MaxEdge);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define GETNODE(map, p3, v2, y, valid) \
|
||||||
|
(map)->getNodeNoEx((p3) + v3s16((v2).X, y, (v2).Y), valid)
|
||||||
|
|
||||||
|
// pos is the node the player is standing inside(!)
|
||||||
|
static bool detectSneakLadder(Map *map, INodeDefManager *nodemgr, v3s16 pos)
|
||||||
|
{
|
||||||
|
// Detects a structure known as "sneak ladder" or "sneak elevator"
|
||||||
|
// that relies on bugs to provide a fast means of vertical transportation,
|
||||||
|
// the bugs have since been fixed but this function remains to keep it working.
|
||||||
|
// NOTE: This is just entirely a huge hack and causes way too many problems.
|
||||||
|
bool is_valid_position;
|
||||||
|
MapNode node;
|
||||||
|
// X/Z vectors for 4 neighboring nodes
|
||||||
|
static const v2s16 vecs[] = { v2s16(-1, 0), v2s16(1, 0), v2s16(0, -1), v2s16(0, 1) };
|
||||||
|
|
||||||
|
for (u16 i = 0; i < ARRLEN(vecs); i++) {
|
||||||
|
const v2s16 vec = vecs[i];
|
||||||
|
|
||||||
|
// walkability of bottom & top node should differ
|
||||||
|
node = GETNODE(map, pos, vec, 0, &is_valid_position);
|
||||||
|
if (!is_valid_position)
|
||||||
|
continue;
|
||||||
|
bool w = nodemgr->get(node).walkable;
|
||||||
|
node = GETNODE(map, pos, vec, 1, &is_valid_position);
|
||||||
|
if (!is_valid_position || w == nodemgr->get(node).walkable)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// check one more node above OR below with corresponding walkability
|
||||||
|
node = GETNODE(map, pos, vec, -1, &is_valid_position);
|
||||||
|
bool ok = is_valid_position && w != nodemgr->get(node).walkable;
|
||||||
|
if (!ok) {
|
||||||
|
node = GETNODE(map, pos, vec, 2, &is_valid_position);
|
||||||
|
ok = is_valid_position && w == nodemgr->get(node).walkable;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ok)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef GETNODE
|
||||||
|
|
||||||
void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d,
|
void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d,
|
||||||
std::vector<CollisionInfo> *collision_info)
|
std::vector<CollisionInfo> *collision_info)
|
||||||
{
|
{
|
||||||
@ -216,6 +261,8 @@ void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d,
|
|||||||
// Max. distance (X, Z) over border for sneaking determined by collision box
|
// Max. distance (X, Z) over border for sneaking determined by collision box
|
||||||
// * 0.49 to keep the center just barely on the node
|
// * 0.49 to keep the center just barely on the node
|
||||||
v3f sneak_max = m_collisionbox.getExtent() * 0.49;
|
v3f sneak_max = m_collisionbox.getExtent() * 0.49;
|
||||||
|
if (m_sneak_ladder_detected)
|
||||||
|
sneak_max = v3f(0.4 * BS, 0, 0.4 * BS); // restore legacy behaviour
|
||||||
|
|
||||||
/*
|
/*
|
||||||
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
|
||||||
@ -234,6 +281,11 @@ void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d,
|
|||||||
sn_f.Z+bmin.Z - sneak_max.Z, sn_f.Z+bmax.Z + sneak_max.Z);
|
sn_f.Z+bmin.Z - sneak_max.Z, sn_f.Z+bmax.Z + sneak_max.Z);
|
||||||
// Because we keep the player collision box on the node,
|
// Because we keep the player collision box on the node,
|
||||||
// limiting position.Y is not necessary
|
// limiting position.Y is not necessary
|
||||||
|
|
||||||
|
if (m_sneak_ladder_detected) {
|
||||||
|
// this sometimes causes some weird slow sinking but *shrug*
|
||||||
|
m_speed.Y = MYMAX(m_speed.Y, 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (got_teleported)
|
if (got_teleported)
|
||||||
@ -261,8 +313,6 @@ void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d,
|
|||||||
bool touching_ground_was = touching_ground;
|
bool touching_ground_was = touching_ground;
|
||||||
touching_ground = result.touching_ground;
|
touching_ground = result.touching_ground;
|
||||||
|
|
||||||
//bool standing_on_unloaded = result.standing_on_unloaded;
|
|
||||||
|
|
||||||
// We want the top of the sneak node to be below the players feet
|
// We want the top of the sneak node to be below the players feet
|
||||||
f32 position_y_mod;
|
f32 position_y_mod;
|
||||||
if (m_sneak_node_exists)
|
if (m_sneak_node_exists)
|
||||||
@ -289,14 +339,13 @@ void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d,
|
|||||||
}
|
}
|
||||||
|
|
||||||
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, 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;
|
||||||
v3s16 new_sneak_node = m_sneak_node;
|
v3s16 new_sneak_node = m_sneak_node;
|
||||||
for(s16 x=-1; x<=1; x++)
|
for(s16 x=-1; x<=1; x++)
|
||||||
for(s16 z=-1; z<=1; z++)
|
for(s16 z=-1; z<=1; z++)
|
||||||
{
|
{
|
||||||
v3s16 p = pos_i_bottom + v3s16(x,0,z);
|
v3s16 p = current_node + v3s16(x,0,z);
|
||||||
v3f pf = intToFloat(p, BS);
|
v3f pf = intToFloat(p, BS);
|
||||||
v2f node_p2df(pf.X, pf.Z);
|
v2f node_p2df(pf.X, pf.Z);
|
||||||
f32 distance_f = player_p2df.getDistanceFrom(node_p2df);
|
f32 distance_f = player_p2df.getDistanceFrom(node_p2df);
|
||||||
@ -309,17 +358,28 @@ void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d,
|
|||||||
|
|
||||||
// The node to be sneaked on has to be walkable
|
// The node to be sneaked on has to be walkable
|
||||||
node = map->getNodeNoEx(p, &is_valid_position);
|
node = map->getNodeNoEx(p, &is_valid_position);
|
||||||
if (!is_valid_position || nodemgr->get(node).walkable == false)
|
if (!is_valid_position || !nodemgr->get(node).walkable)
|
||||||
continue;
|
|
||||||
// And the node above it has to be nonwalkable
|
|
||||||
node = map->getNodeNoEx(p + v3s16(0,1,0), &is_valid_position);
|
|
||||||
if (!is_valid_position || nodemgr->get(node).walkable)
|
|
||||||
continue;
|
continue;
|
||||||
|
// And the node(s) above have to be nonwalkable
|
||||||
|
bool ok = true;
|
||||||
if (!physics_override_sneak_glitch) {
|
if (!physics_override_sneak_glitch) {
|
||||||
node = map->getNodeNoEx(p + v3s16(0,2,0), &is_valid_position);
|
u16 height = ceilf(
|
||||||
if (!is_valid_position || nodemgr->get(node).walkable)
|
(m_collisionbox.MaxEdge.Y - m_collisionbox.MinEdge.Y) / BS
|
||||||
continue;
|
);
|
||||||
|
for (u16 y = 1; y <= height; y++) {
|
||||||
|
node = map->getNodeNoEx(p + v3s16(0,y,0), &is_valid_position);
|
||||||
|
if (!is_valid_position || nodemgr->get(node).walkable) {
|
||||||
|
ok = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// legacy behaviour: check just one node
|
||||||
|
node = map->getNodeNoEx(p + v3s16(0,1,0), &is_valid_position);
|
||||||
|
ok = is_valid_position && !nodemgr->get(node).walkable;
|
||||||
}
|
}
|
||||||
|
if (!ok)
|
||||||
|
continue;
|
||||||
|
|
||||||
min_distance_f = distance_f;
|
min_distance_f = distance_f;
|
||||||
new_sneak_node = p;
|
new_sneak_node = p;
|
||||||
@ -329,12 +389,17 @@ void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d,
|
|||||||
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;
|
||||||
|
|
||||||
// Update saved top bounding box of sneak node
|
|
||||||
if (sneak_node_found) {
|
if (sneak_node_found) {
|
||||||
|
// Update saved top bounding box of sneak node
|
||||||
MapNode n = map->getNodeNoEx(m_sneak_node);
|
MapNode n = map->getNodeNoEx(m_sneak_node);
|
||||||
std::vector<aabb3f> nodeboxes;
|
std::vector<aabb3f> nodeboxes;
|
||||||
n.getCollisionBoxes(nodemgr, &nodeboxes);
|
n.getCollisionBoxes(nodemgr, &nodeboxes);
|
||||||
m_sneak_node_bb_top = getTopBoundingBox(nodeboxes);
|
m_sneak_node_bb_top = getTopBoundingBox(nodeboxes);
|
||||||
|
|
||||||
|
m_sneak_ladder_detected = physics_override_sneak_glitch &&
|
||||||
|
detectSneakLadder(map, nodemgr, floatToInt(position, BS));
|
||||||
|
} else {
|
||||||
|
m_sneak_ladder_detected = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -566,7 +631,7 @@ void LocalPlayer::applyControl(float dtime)
|
|||||||
speedV.Y = movement_speed_walk;
|
speedV.Y = movement_speed_walk;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if(m_can_jump)
|
else if(m_can_jump || (control.sneak && m_sneak_ladder_detected))
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
NOTE: The d value in move() affects jump height by
|
NOTE: The d value in move() affects jump height by
|
||||||
|
@ -135,15 +135,18 @@ private:
|
|||||||
void accelerateVertical(const v3f &target_speed, const f32 max_increase);
|
void accelerateVertical(const v3f &target_speed, const f32 max_increase);
|
||||||
|
|
||||||
v3f m_position;
|
v3f m_position;
|
||||||
// This is used for determining the sneaking range
|
|
||||||
v3s16 m_sneak_node;
|
v3s16 m_sneak_node;
|
||||||
|
// Stores the top bounding box of m_sneak_node
|
||||||
|
aabb3f m_sneak_node_bb_top;
|
||||||
// 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
|
// Whether recalculation of m_sneak_node and its top bbox is needed
|
||||||
bool m_need_to_get_new_sneak_node;
|
bool m_need_to_get_new_sneak_node;
|
||||||
// Stores the top bounding box of m_sneak_node and is updated
|
// Whether a "sneak ladder" structure is detected at the players pos
|
||||||
// when m_need_to_get_new_sneak_node == true
|
// see detectSneakLadder() in the .cpp for more info (always false if disabled)
|
||||||
aabb3f m_sneak_node_bb_top;
|
bool m_sneak_ladder_detected;
|
||||||
|
|
||||||
// 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;
|
||||||
|
Loading…
Reference in New Issue
Block a user