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)),
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),
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();
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;
+ }
+}
}
// 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;
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
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;
}