aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/lua_api.txt6
-rw-r--r--src/content_cao.cpp2
-rw-r--r--src/content_sao.cpp6
-rw-r--r--src/content_sao.h1
-rw-r--r--src/genericobject.cpp3
-rw-r--r--src/genericobject.h3
-rw-r--r--src/localplayer.cpp309
-rw-r--r--src/localplayer.h8
-rw-r--r--src/script/lua_api/l_object.cpp21
-rw-r--r--src/script/lua_api/l_object.h2
10 files changed, 349 insertions, 12 deletions
diff --git a/doc/lua_api.txt b/doc/lua_api.txt
index 7b967726d..4427e26d8 100644
--- a/doc/lua_api.txt
+++ b/doc/lua_api.txt
@@ -3021,7 +3021,11 @@ This is basically a reference to a C++ `ServerActiveObject`
* `jump`: multiplier to default jump value (default: `1`)
* `gravity`: multiplier to default gravity value (default: `1`)
* `sneak`: whether player can sneak (default: `true`)
- * `sneak_glitch`: whether player can use the sneak glitch (default: `true`)
+ * `sneak_glitch`: whether player can use the new move code replications
+ of the old sneak side-effects: sneak ladders and 2 node sneak jump
+ when next to a ledge 2 nodes up (default: `true`)
+ * `new_move`: use new move/sneak code. When `false` the exact old code
+ is used for the specific old sneak behaviour (default: `true`)
* `get_physics_override()`: returns the table given to set_physics_override
* `hud_add(hud definition)`: add a HUD element described by HUD def, returns ID
number on success
diff --git a/src/content_cao.cpp b/src/content_cao.cpp
index 84f198b75..ac283da88 100644
--- a/src/content_cao.cpp
+++ b/src/content_cao.cpp
@@ -1652,6 +1652,7 @@ void GenericCAO::processMessage(const std::string &data)
// these are sent inverted so we get true when the server sends nothing
bool sneak = !readU8(is);
bool sneak_glitch = !readU8(is);
+ bool new_move = !readU8(is);
if(m_is_local_player)
@@ -1662,6 +1663,7 @@ void GenericCAO::processMessage(const std::string &data)
player->physics_override_gravity = override_gravity;
player->physics_override_sneak = sneak;
player->physics_override_sneak_glitch = sneak_glitch;
+ player->physics_override_new_move = new_move;
}
} else if (cmd == GENERIC_CMD_SET_ANIMATION) {
// TODO: change frames send as v2s32 value
diff --git a/src/content_sao.cpp b/src/content_sao.cpp
index bb2387d1a..908365397 100644
--- a/src/content_sao.cpp
+++ b/src/content_sao.cpp
@@ -789,6 +789,7 @@ PlayerSAO::PlayerSAO(ServerEnvironment *env_, u16 peer_id_, bool is_singleplayer
m_physics_override_gravity(1),
m_physics_override_sneak(true),
m_physics_override_sneak_glitch(true),
+ m_physics_override_new_move(true),
m_physics_override_sent(false)
{
assert(m_peer_id != 0); // pre-condition
@@ -886,7 +887,7 @@ std::string PlayerSAO::getClientInitializationData(u16 protocol_version)
m_attachment_bone, m_attachment_position, m_attachment_rotation)); // 4
msg_os << serializeLongString(gob_cmd_update_physics_override(m_physics_override_speed,
m_physics_override_jump, m_physics_override_gravity, m_physics_override_sneak,
- m_physics_override_sneak_glitch)); // 5
+ m_physics_override_sneak_glitch, m_physics_override_new_move)); // 5
// (GENERIC_CMD_UPDATE_NAMETAG_ATTRIBUTES) : Deprecated, for backwards compatibility only.
msg_os << serializeLongString(gob_cmd_update_nametag_attributes(m_prop.nametag_color)); // 6
int message_count = 6 + m_bone_position.size();
@@ -1049,7 +1050,8 @@ void PlayerSAO::step(float dtime, bool send_recommended)
m_physics_override_sent = true;
std::string str = gob_cmd_update_physics_override(m_physics_override_speed,
m_physics_override_jump, m_physics_override_gravity,
- m_physics_override_sneak, m_physics_override_sneak_glitch);
+ m_physics_override_sneak, m_physics_override_sneak_glitch,
+ m_physics_override_new_move);
// create message and add to list
ActiveObjectMessage aom(getId(), true, str);
m_messages_out.push(aom);
diff --git a/src/content_sao.h b/src/content_sao.h
index c1b01b6dd..e53e8ecce 100644
--- a/src/content_sao.h
+++ b/src/content_sao.h
@@ -397,6 +397,7 @@ public:
float m_physics_override_gravity;
bool m_physics_override_sneak;
bool m_physics_override_sneak_glitch;
+ bool m_physics_override_new_move;
bool m_physics_override_sent;
};
diff --git a/src/genericobject.cpp b/src/genericobject.cpp
index c4660cf44..07d2445b4 100644
--- a/src/genericobject.cpp
+++ b/src/genericobject.cpp
@@ -118,7 +118,7 @@ std::string gob_cmd_update_armor_groups(const ItemGroupList &armor_groups)
}
std::string gob_cmd_update_physics_override(float physics_override_speed, float physics_override_jump,
- float physics_override_gravity, bool sneak, bool sneak_glitch)
+ float physics_override_gravity, bool sneak, bool sneak_glitch, bool new_move)
{
std::ostringstream os(std::ios::binary);
// command
@@ -130,6 +130,7 @@ std::string gob_cmd_update_physics_override(float physics_override_speed, float
// these are sent inverted so we get true when the server sends nothing
writeU8(os, !sneak);
writeU8(os, !sneak_glitch);
+ writeU8(os, !new_move);
return os.str();
}
diff --git a/src/genericobject.h b/src/genericobject.h
index 48e71db75..7d2ec4b14 100644
--- a/src/genericobject.h
+++ b/src/genericobject.h
@@ -68,7 +68,8 @@ std::string gob_cmd_punched(s16 damage, s16 result_hp);
std::string gob_cmd_update_armor_groups(const ItemGroupList &armor_groups);
std::string gob_cmd_update_physics_override(float physics_override_speed,
- float physics_override_jump, float physics_override_gravity, bool sneak, bool sneak_glitch);
+ float physics_override_jump, float physics_override_gravity,
+ bool sneak, bool sneak_glitch, bool new_move);
std::string gob_cmd_update_animation(v2f frames, float frame_speed, float frame_blend, bool frame_loop);
diff --git a/src/localplayer.cpp b/src/localplayer.cpp
index 9dc3bf5aa..ea4347207 100644
--- a/src/localplayer.cpp
+++ b/src/localplayer.cpp
@@ -49,6 +49,7 @@ LocalPlayer::LocalPlayer(Client *client, const char *name):
physics_override_gravity(1.0f),
physics_override_sneak(true),
physics_override_sneak_glitch(true),
+ physics_override_new_move(true), // Temporary option for old move code
overridePosition(v3f(0,0,0)),
last_position(v3f(0,0,0)),
last_speed(v3f(0,0,0)),
@@ -66,6 +67,7 @@ LocalPlayer::LocalPlayer(Client *client, const char *name):
hurt_tilt_strength(0.0f),
m_position(0,0,0),
m_sneak_node(32767,32767,32767),
+ m_sneak_node_bb_ymax(0), // To support temporary option for old move code
m_sneak_node_bb_top(0,0,0,0,0,0),
m_sneak_node_exists(false),
m_need_to_get_new_sneak_node(true),
@@ -178,6 +180,12 @@ static bool detectLedge(Map *map, INodeDefManager *nodemgr, v3s16 pos)
void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d,
std::vector<CollisionInfo> *collision_info)
{
+ // Temporary option for old move code
+ if (!physics_override_new_move) {
+ old_move(dtime, env, pos_max_d, collision_info);
+ return;
+ }
+
Map *map = &env->getMap();
INodeDefManager *nodemgr = m_client->ndef();
@@ -806,3 +814,304 @@ void LocalPlayer::accelerateVertical(const v3f &target_speed, const f32 max_incr
m_speed.Y += d_wanted;
}
+// Temporary option for old move code
+void LocalPlayer::old_move(f32 dtime, Environment *env, f32 pos_max_d,
+ std::vector<CollisionInfo> *collision_info)
+{
+ Map *map = &env->getMap();
+ INodeDefManager *nodemgr = m_client->ndef();
+
+ v3f position = getPosition();
+
+ // Copy parent position if local player is attached
+ if (isAttached) {
+ setPosition(overridePosition);
+ m_sneak_node_exists = false;
+ return;
+ }
+
+ // Skip collision detection if noclip mode is used
+ bool fly_allowed = m_client->checkLocalPrivilege("fly");
+ bool noclip = m_client->checkLocalPrivilege("noclip") &&
+ g_settings->getBool("noclip");
+ bool free_move = noclip && fly_allowed && g_settings->getBool("free_move");
+ if (free_move) {
+ position += m_speed * dtime;
+ setPosition(position);
+ m_sneak_node_exists = false;
+ return;
+ }
+
+ /*
+ Collision detection
+ */
+ bool is_valid_position;
+ MapNode node;
+ v3s16 pp;
+
+ /*
+ Check if player is in liquid (the oscillating value)
+ */
+ if (in_liquid) {
+ // If in liquid, the threshold of coming out is at higher y
+ pp = floatToInt(position + v3f(0, BS * 0.1, 0), BS);
+ node = map->getNodeNoEx(pp, &is_valid_position);
+ if (is_valid_position) {
+ in_liquid = nodemgr->get(node.getContent()).isLiquid();
+ liquid_viscosity = nodemgr->get(node.getContent()).liquid_viscosity;
+ } else {
+ in_liquid = false;
+ }
+ } else {
+ // If not in liquid, the threshold of going in is at lower y
+ pp = floatToInt(position + v3f(0, BS * 0.5, 0), BS);
+ node = map->getNodeNoEx(pp, &is_valid_position);
+ if (is_valid_position) {
+ in_liquid = nodemgr->get(node.getContent()).isLiquid();
+ liquid_viscosity = nodemgr->get(node.getContent()).liquid_viscosity;
+ } else {
+ in_liquid = false;
+ }
+ }
+
+ /*
+ Check if player is in liquid (the stable value)
+ */
+ pp = floatToInt(position + v3f(0, 0, 0), BS);
+ node = map->getNodeNoEx(pp, &is_valid_position);
+ if (is_valid_position)
+ in_liquid_stable = nodemgr->get(node.getContent()).isLiquid();
+ else
+ in_liquid_stable = false;
+
+ /*
+ Check if player is climbing
+ */
+ pp = floatToInt(position + v3f(0, 0.5 * BS, 0), BS);
+ v3s16 pp2 = floatToInt(position + v3f(0, -0.2 * BS, 0), BS);
+ node = map->getNodeNoEx(pp, &is_valid_position);
+ bool is_valid_position2;
+ MapNode node2 = map->getNodeNoEx(pp2, &is_valid_position2);
+
+ if (!(is_valid_position && is_valid_position2))
+ is_climbing = false;
+ else
+ is_climbing = (nodemgr->get(node.getContent()).climbable ||
+ nodemgr->get(node2.getContent()).climbable) && !free_move;
+
+ /*
+ Collision uncertainty radius
+ Make it a bit larger than the maximum distance of movement
+ */
+ //f32 d = pos_max_d * 1.1;
+ // A fairly large value in here makes moving smoother
+ f32 d = 0.15 * BS;
+ // This should always apply, otherwise there are glitches
+ sanity_check(d > pos_max_d);
+ // Maximum distance over border for sneaking
+ f32 sneak_max = BS * 0.4;
+
+ /*
+ If sneaking, keep in range from the last walked node and don't
+ fall off from it
+ */
+ if (control.sneak && m_sneak_node_exists &&
+ !(fly_allowed && g_settings->getBool("free_move")) && !in_liquid &&
+ physics_override_sneak && !got_teleported) {
+ f32 maxd = 0.5 * BS + sneak_max;
+ v3f lwn_f = intToFloat(m_sneak_node, BS);
+ 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);
+
+ if (!is_climbing) {
+ // Move up if necessary
+ f32 new_y = (lwn_f.Y - 0.5 * BS) + m_sneak_node_bb_ymax;
+ if (position.Y < new_y)
+ position.Y = new_y;
+ /*
+ Collision seems broken, since player is sinking when
+ sneaking over the edges of current sneaking_node.
+ TODO (when fixed): Set Y-speed only to 0 when position.Y < new_y.
+ */
+ if (m_speed.Y < 0)
+ m_speed.Y = 0;
+ }
+ }
+
+ if (got_teleported)
+ got_teleported = false;
+
+ // this shouldn't be hardcoded but transmitted from server
+ float player_stepheight = touching_ground ? (BS * 0.6) : (BS * 0.2);
+
+#ifdef __ANDROID__
+ player_stepheight += (0.6 * BS);
+#endif
+
+ v3f accel_f = v3f(0, 0, 0);
+
+ collisionMoveResult result = collisionMoveSimple(env, m_client,
+ pos_max_d, m_collisionbox, player_stepheight, dtime,
+ &position, &m_speed, accel_f);
+
+ /*
+ If the player's feet touch the topside of any node, this is
+ set to true.
+
+ Player is allowed to jump when this is true.
+ */
+ bool touching_ground_was = touching_ground;
+ touching_ground = result.touching_ground;
+
+ //bool standing_on_unloaded = result.standing_on_unloaded;
+
+ /*
+ Check the nodes under the player to see from which node the
+ player is sneaking from, if any. If the node from under
+ the player has been removed, the player falls.
+ */
+ f32 position_y_mod = 0.05 * BS;
+ if (m_sneak_node_bb_ymax > 0)
+ position_y_mod = m_sneak_node_bb_ymax - position_y_mod;
+ 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,
+ // it wasn't air before but now it is
+ m_need_to_get_new_sneak_node = false;
+ m_sneak_node_exists = false;
+ } else if (nodemgr->get(map->getNodeNoEx(current_node)).name != "air") {
+ // We are on something, so make sure to recalculate the sneak
+ // node.
+ m_need_to_get_new_sneak_node = true;
+ }
+
+ if (m_need_to_get_new_sneak_node && physics_override_sneak) {
+ 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);
+ f32 min_distance_f = 100000.0 * BS;
+ // If already seeking from some node, compare to it.
+ v3s16 new_sneak_node = m_sneak_node;
+ for (s16 x= -1; x <= 1; x++)
+ for (s16 z= -1; z <= 1; z++) {
+ v3s16 p = pos_i_bottom + v3s16(x, 0, z);
+ v3f pf = intToFloat(p, BS);
+ v2f node_p2df(pf.X, pf.Z);
+ f32 distance_f = player_p2df.getDistanceFrom(node_p2df);
+ f32 max_axis_distance_f = MYMAX(
+ fabs(player_p2df.X - node_p2df.X),
+ fabs(player_p2df.Y - node_p2df.Y));
+
+ if (distance_f > min_distance_f ||
+ max_axis_distance_f > 0.5 * BS + sneak_max + 0.1 * BS)
+ continue;
+
+ // The node to be sneaked on has to be walkable
+ node = map->getNodeNoEx(p, &is_valid_position);
+ if (!is_valid_position || nodemgr->get(node).walkable == false)
+ 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;
+ // If not 'sneak_glitch' the node 2 nodes above it has to be nonwalkable
+ if (!physics_override_sneak_glitch) {
+ node =map->getNodeNoEx(p + v3s16(0, 2, 0), &is_valid_position);
+ if (!is_valid_position || nodemgr->get(node).walkable)
+ continue;
+ }
+
+ min_distance_f = distance_f;
+ new_sneak_node = p;
+ }
+
+ bool sneak_node_found = (min_distance_f < 100000.0 * BS * 0.9);
+
+ m_sneak_node = new_sneak_node;
+ 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, &nodeboxes);
+ 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
+ this has to be set explicitly
+ */
+ if (sneak_node_found && control.sneak)
+ touching_ground = true;
+ }
+
+ /*
+ Set new position
+ */
+ setPosition(position);
+
+ /*
+ Report collisions
+ */
+ // Dont report if flying
+ if (collision_info && !(g_settings->getBool("free_move") && fly_allowed)) {
+ for (size_t i = 0; i < result.collisions.size(); i++) {
+ const CollisionInfo &info = result.collisions[i];
+ collision_info->push_back(info);
+ }
+ }
+
+ if (!result.standing_on_object && !touching_ground_was && touching_ground) {
+ MtEvent *e = new SimpleTriggerEvent("PlayerRegainGround");
+ m_client->event()->put(e);
+ // Set camera impact value to be used for view bobbing
+ camera_impact = getSpeed().Y * -1;
+ }
+
+ {
+ camera_barely_in_ceiling = false;
+ v3s16 camera_np = floatToInt(getEyePosition(), BS);
+ MapNode n = map->getNodeNoEx(camera_np);
+ if (n.getContent() != CONTENT_IGNORE) {
+ if (nodemgr->get(n).walkable && nodemgr->get(n).solidness == 2)
+ camera_barely_in_ceiling = true;
+ }
+ }
+
+ /*
+ Update the node last under the player
+ */
+ m_old_node_below = floatToInt(position - v3f(0, BS / 2, 0), BS);
+ m_old_node_below_type = nodemgr->get(map->getNodeNoEx(m_old_node_below)).name;
+
+ /*
+ Check properties of the node on which the player is standing
+ */
+ const ContentFeatures &f = nodemgr->get(map->getNodeNoEx(getStandingNodePos()));
+ // Determine if jumping is possible
+ m_can_jump = touching_ground && !in_liquid;
+ if (itemgroup_get(f.groups, "disable_jump"))
+ m_can_jump = false;
+ // Jump key pressed while jumping off from a bouncy block
+ if (m_can_jump && control.jump && itemgroup_get(f.groups, "bouncy") &&
+ m_speed.Y >= -0.5 * BS) {
+ float jumpspeed = movement_speed_jump * physics_override_jump;
+ if (m_speed.Y > 1) {
+ // Reduce boost when speed already is high
+ m_speed.Y += jumpspeed / (1 + (m_speed.Y / 16 ));
+ } else {
+ m_speed.Y += jumpspeed;
+ }
+ setSpeed(m_speed);
+ m_can_jump = false;
+ }
+}
diff --git a/src/localplayer.h b/src/localplayer.h
index ae987b893..01e859bf0 100644
--- a/src/localplayer.h
+++ b/src/localplayer.h
@@ -58,12 +58,17 @@ public:
float physics_override_gravity;
bool physics_override_sneak;
bool physics_override_sneak_glitch;
+ // Temporary option for old move code
+ bool physics_override_new_move;
v3f overridePosition;
void move(f32 dtime, Environment *env, f32 pos_max_d);
void move(f32 dtime, Environment *env, f32 pos_max_d,
std::vector<CollisionInfo> *collision_info);
+ // Temporary option for old move code
+ void old_move(f32 dtime, Environment *env, f32 pos_max_d,
+ std::vector<CollisionInfo> *collision_info);
void applyControl(float dtime);
@@ -137,6 +142,9 @@ private:
v3f m_position;
v3s16 m_sneak_node;
+ // Stores the max player uplift by m_sneak_node
+ // To support temporary option for old move code
+ f32 m_sneak_node_bb_ymax;
// Stores the top bounding box of m_sneak_node
aabb3f m_sneak_node_bb_top;
// Whether the player is allowed to sneak
diff --git a/src/script/lua_api/l_object.cpp b/src/script/lua_api/l_object.cpp
index 0699705cb..95e977f9e 100644
--- a/src/script/lua_api/l_object.cpp
+++ b/src/script/lua_api/l_object.cpp
@@ -401,7 +401,7 @@ int ObjectRef::l_get_armor_groups(lua_State *L)
}
// set_physics_override(self, physics_override_speed, physics_override_jump,
-// physics_override_gravity, sneak, sneak_glitch)
+// physics_override_gravity, sneak, sneak_glitch, new_move)
int ObjectRef::l_set_physics_override(lua_State *L)
{
NO_MAP_LOCK_REQUIRED;
@@ -410,11 +410,18 @@ int ObjectRef::l_set_physics_override(lua_State *L)
if (co == NULL) return 0;
// Do it
if (lua_istable(L, 2)) {
- co->m_physics_override_speed = getfloatfield_default(L, 2, "speed", co->m_physics_override_speed);
- co->m_physics_override_jump = getfloatfield_default(L, 2, "jump", co->m_physics_override_jump);
- co->m_physics_override_gravity = getfloatfield_default(L, 2, "gravity", co->m_physics_override_gravity);
- co->m_physics_override_sneak = getboolfield_default(L, 2, "sneak", co->m_physics_override_sneak);
- co->m_physics_override_sneak_glitch = getboolfield_default(L, 2, "sneak_glitch", co->m_physics_override_sneak_glitch);
+ co->m_physics_override_speed = getfloatfield_default(
+ L, 2, "speed", co->m_physics_override_speed);
+ co->m_physics_override_jump = getfloatfield_default(
+ L, 2, "jump", co->m_physics_override_jump);
+ co->m_physics_override_gravity = getfloatfield_default(
+ L, 2, "gravity", co->m_physics_override_gravity);
+ co->m_physics_override_sneak = getboolfield_default(
+ L, 2, "sneak", co->m_physics_override_sneak);
+ co->m_physics_override_sneak_glitch = getboolfield_default(
+ L, 2, "sneak_glitch", co->m_physics_override_sneak_glitch);
+ co->m_physics_override_new_move = getboolfield_default(
+ L, 2, "new_move", co->m_physics_override_new_move);
co->m_physics_override_sent = false;
} else {
// old, non-table format
@@ -454,6 +461,8 @@ int ObjectRef::l_get_physics_override(lua_State *L)
lua_setfield(L, -2, "sneak");
lua_pushboolean(L, co->m_physics_override_sneak_glitch);
lua_setfield(L, -2, "sneak_glitch");
+ lua_pushboolean(L, co->m_physics_override_new_move);
+ lua_setfield(L, -2, "new_move");
return 1;
}
diff --git a/src/script/lua_api/l_object.h b/src/script/lua_api/l_object.h
index b6fc35bc2..98f5c2b11 100644
--- a/src/script/lua_api/l_object.h
+++ b/src/script/lua_api/l_object.h
@@ -105,7 +105,7 @@ private:
static int l_get_armor_groups(lua_State *L);
// set_physics_override(self, physics_override_speed, physics_override_jump,
- // physics_override_gravity, sneak, sneak_glitch)
+ // physics_override_gravity, sneak, sneak_glitch, new_move)
static int l_set_physics_override(lua_State *L);
// get_physics_override(self)