Lagback/zh: Difference between revisions
(Created page with "在验证之前未消除的副作用包括:") |
(Created page with "* <code>onGround</code> 着陆时被设置为 <code>true</code> (这会改变潜行的行为)。 * <code>inWeb</code> 在与蜘蛛网碰撞时被设置为 <code>false</code>。 * 当与墙壁或天花板发生碰撞时,各种 <code>collided</code> 被设置为 <code>true</code>。") |
||
Line 22: | Line 22: | ||
在验证之前未消除的副作用包括: |
在验证之前未消除的副作用包括: |
||
* <code>onGround</code> 着陆时被设置为 <code>true</code> (这会改变潜行的行为)。 |
|||
<div lang="en" dir="ltr" class="mw-content-ltr"> |
|||
* <code>inWeb</code> 在与[[Special:MyLanguage/cobweb|蜘蛛网]]碰撞时被设置为 <code>false</code>。 |
|||
* The <code>onGround</code> flag being set to <code>true</code> when landing (which changes the behaviour of sneaking). |
|||
* 当与墙壁或天花板发生碰撞时,各种 <code>collided</code> 被设置为 <code>true</code>。 |
|||
* The <code>inWeb</code> flag being set to <code>false</code> when colliding with a [[Special:MyLanguage/cobweb|cobweb]]. |
|||
* The various <code>collided</code> flags being set to <code>true</code> when colliding with a wall or ceiling. |
|||
</div> |
|||
<div lang="en" dir="ltr" class="mw-content-ltr"> |
<div lang="en" dir="ltr" class="mw-content-ltr"> |
Revision as of 16:26, 6 September 2022
回弹是指玩家被传送回之前的位置。它可以被利用于卡进墙壁或以类似卡角的方式跳得更高,尽管这些做法在多人服务器上可能是禁止的。在本文中,我们主要关注1.8的单人模式,但大多数信息都与多人模式和1.9+相关。
以下是已知的回弹触发因素:
常规解释
触发回弹有两种方法:
- 与碰撞箱相交(卡在方块中,或与船相撞)。
- "错误地"移动。
第一种方法是无需解释的。
关于第二种方法,我们必须首先了解玩家的移动是如何在服务端处理的(即使是在单人游戏中,游戏也运行在一个集成的服务器上)。每过一刻,客户端就会计算玩家的下一个位置,并向服务器发送一个数据包。服务器通过从玩家的最后一个位置重新计算来验证玩家的移动,理论上两者计算结果应相同。然而,服务器不会消除玩家移动的副作用,这可能会导致玩家预期和实际位置之间的差异。如果两者之间的水平距离超过 0.25 m ,那么这种差异就会被认为是显著的,在这种情况下,玩家会被回弹至他们之前的位置。
在验证之前未消除的副作用包括:
onGround
着陆时被设置为true
(这会改变潜行的行为)。inWeb
在与蜘蛛网碰撞时被设置为false
。- 当与墙壁或天花板发生碰撞时,各种
collided
被设置为true
。
In short, the player's movement is calculated twice each tick, but the side effects of the first calculation may influence the result of the second one. If the player moves fast enough, the server thinks the player moves wrongly, and triggers a lagback.
Explanations for specific triggers
Intersecting with a collision box
The player is not supposed to move into a collision box. However, the server has a leniency of 0.0625b in each direction, meaning the player's bounding box can intersect with the "exterior shell" of a block and move normally. If the player move further inward, it triggers a lagback.
If the player is already fully inside a collision box, they do not get lagged back when moving.
Colliding with a cobweb
When colliding with a cobweb (detected at the end of the tick, but at the player's previous position), the player's inWeb
flag is set to true
. When the player is moved and and inWeb
is true
, it is immediately set to false
, and the cobweb's effect is applied on the player's velocity. This causes a discrepancy between the original calculation and the recalculation, which triggers a lagback if sufficient speed is met.
Landing from a high fall while sneaking
This variant is achieved by landing and sneaking with the following requirements:
- Moving horizontally at strictly more than 0.25m/t.
- Being at least one block above ground on the tick before landing (or 0.6b in 1.11+).
The minimum jump height required to achieve at least -1m/t of vertical speed is -7.3125b. An easy setup to try this method is -9.5b. You are not required to time the sneak exactly, but sneaking too early will significantly reduce the player's horizontal speed.
Sneak Glitch
A sneak glitch (or shift glitch) happens when the player sneaks while landing on an edge, which causes them to fall anyway (this was fixed in 1.16.2).
When performing a sneak glitch, the server's expected movement for the player is different from their actual movement. Here's why:
- During the original calculation, the player is sneaking but not "on ground", hence they move past the edge. However, they still land, which sets
onGround = true
. - During the recalculation, the player is now considered "on ground" before actually landing, which changes the behaviour of sneaking: they can not "fall off the edge", despite not being at ground level.
With at least 0.25m/t of horizontal speed and appropriate placement, performing a sneak glitch can therefore trigger a lagback. After being teleported back to their previous position, the player is now able to jump. The resulting jump looks similar to a blip-up, in the sense that the player can start jumping mid-air. Here is an example:
Some jump heights do not work. This is still being investigated.
Code
//in NetHandlerPlayServer.java
public void processPlayer(PacketPlayer packetIn)
{
double posY_original = this.playerEntity.posY;
this.lastPosX = this.playerEntity.posX;
this.lastPosY = this.playerEntity.posY;
this.lastPosZ = this.playerEntity.posZ;
double next_posX = packetIn.getPositionX();
double next_posY = packetIn.getPositionY();
double next_posZ = packetIn.getPositionZ();
float yaw = this.playerEntity.rotationYaw;
float pitch = this.playerEntity.rotationPitch;
if (packetIn.getRotating()) {yaw = packetIn.getYaw(); pitch = packetIn.getPitch();}
</div>
<div lang="en" dir="ltr" class="mw-content-ltr">
//checks whether the player is starting from inside a collision box: in this case, there is no lagback
boolean noCollisionInside = worldserver.getCollidingBoundingBoxes(this.playerEntity, this.playerEntity.getEntityBoundingBox().contract(0.0625, 0.0625, 0.0625).isEmpty();
</div>
<div lang="en" dir="ltr" class="mw-content-ltr">
//begin movement verification
double deltaX = next_posX - this.playerEntity.posX;
double deltaY = next_posY - this.playerEntity.posY;
double deltaZ = next_posZ - this.playerEntity.posZ;
</div>
<div lang="en" dir="ltr" class="mw-content-ltr">
if (this.playerEntity.onGround && !packetIn.isOnGround() && deltaY > 0.0)
this.playerEntity.jump();
this.playerEntity.moveEntity(deltaX, deltaY, deltaZ);
this.playerEntity.onGround = packetIn.isOnGround();
//calculates error between the expected and actual positions
double errorX = next_posX - this.playerEntity.posX;
double errorZ = next_posZ - this.playerEntity.posZ;
double error_squared = errorX * errorX + errorZ * errorZ;
boolean movedWrongly = (error_squared > 0.0625 && !this.playerEntity.theItemInWorldManager.isCreative());
</div>
<div lang="en" dir="ltr" class="mw-content-ltr">
//sets the player to their actual position, and checks for collisions
this.playerEntity.setPositionAndRotation(next_posX, next_posY, next_posZ, yaw, pitch);
boolean next_noCollisionInside = worldserver.getCollidingBoundingBoxes(this.playerEntity, this.playerEntity.getEntityBoundingBox().contract(0.0625, 0.0625, 0.0625).isEmpty();
</div>
<div lang="en" dir="ltr" class="mw-content-ltr">
//detects an error: player moved wrongly, or moved inside a collision box
if (noCollisionInside && (movedWrongly || !next_noCollisionInside))
{
//lags the player back to their previous position
this.setPlayerLocation(this.lastPosX, this.lastPosY, this.lastPosZ, yaw, pitch);
return;
}
</div>
<div lang="en" dir="ltr" class="mw-content-ltr">
this.playerEntity.handleFalling(this.playerEntity.posY - posY_original, packetIn.isOnGround());
}