Lagback/zh: Difference between revisions

From Minecraft Parkour Wiki
Content added Content deleted
(Created page with "当玩家潜行降落在边缘时会发生潜行故障(或下蹲故障),这会导致他们掉落(在 1.16.2 中被修复)。")
(Created page with "<youtube>https://youtu.be/IOrpHNqn5t0</youtube>")
Line 69: Line 69:
</div>
</div>


<div lang="en" dir="ltr" class="mw-content-ltr">
<youtube>https://youtu.be/IOrpHNqn5t0</youtube>
<youtube>https://youtu.be/IOrpHNqn5t0</youtube>
</div>


<div lang="en" dir="ltr" class="mw-content-ltr">
<div lang="en" dir="ltr" class="mw-content-ltr">

Revision as of 16:48, 6 September 2022

Other languages:

回彈是指玩家被傳送回之前的位置。它可以被利用於卡進牆壁或以類似卡角的方式跳得更高,儘管這些做法在多人伺服器上可能是禁止的。在本文中,我們主要關注1.8的單人模式,但大多數信息都與多人模式和1.9+相關。

以下是已知的回彈觸發因素:

  • 卡在一個方塊中。
  • 與船相撞。
  • 蜘蛛網中移動過快。
  • 以足夠的速度在潛行時降落
  • 以極快的速度(例如速度100)通過步行輔助移動。
  • 靠着牆快速移動。


常規解釋

觸發回彈有兩種方法:

  • 與碰撞箱相交(卡在方塊中,或與船相撞)。
  • "錯誤地"移動。

第一種方法是無需解釋的。

關於第二種方法,我們必須首先了解玩家的移動是如何在服務端處理的(即使是在單人遊戲中,遊戲也運行在一個集成的伺服器上)。每過一刻,客戶端就會計算玩家的下一個位置,並向伺服器發送一個數據包。伺服器通過從玩家的最後一個位置重新計算來驗證玩家的移動,理論上兩者計算結果應相同。然而,伺服器不會消除玩家移動的副作用,這可能會導致玩家預期和實際位置之間的差異。如果兩者之間的水平距離超過 0.25 m ,那麼這種差異就會被認為是顯著的,在這種情況下,玩家會被回彈至他們之前的位置。

在驗證之前未消除的副作用包括:

  • onGround 着陸時被設置為 true (這會改變潛行的行為)。
  • inWeb 在與蜘蛛網碰撞時被設置為 false
  • 當與牆壁或天花板發生碰撞時,各種 collided 被設置為 true

總之,玩家的移動每刻計算兩次,但第一次計算的副作用可能會影響第二次計算的結果。如果玩家移動足夠快,伺服器就會認為玩家移動錯誤,從而觸發回彈。


特殊觸發的解釋

與碰撞箱相交

玩家不應該移動到一個碰撞箱中。但是,伺服器在每個方向都有 0.0625b 的寬容度,這意味着玩家的邊界箱可以與方塊的"表面"相交並正常移動。如果玩家進一步向內移動,就會觸發回彈。

如果玩家已經完全進入方塊的碰撞箱,則玩家在移動時不會回彈。


與蜘蛛網碰撞

當與蜘蛛網碰撞時(在滴答結束時檢測,但在玩家的上一個位置),玩家的 inWeb 被設置為 true。當玩家移動並且 inWebtrue 時,它會立即被設置為 false,並且蜘蛛網的效果會應用在玩家的速度上。這會導致原始計算和重新計算之間存在差異,如果滿足足夠的速度,則會觸發回彈。


在潛行時從高處落下

此變種是通過掉落和潛行實現的,具有以下要求:

  • 水平移動速度超過 0.25m/t。
  • 落地前至少在地面上方一格(在 1.11+ 中為 0.6 格)。

達到至少 -1m/t 垂直速度所需的最小跳躍高度為 -7.3125b。嘗試這種方法的一個簡單高度是 -9.5b。你不需要準確地計算潛行時間,但過早潛行會顯著降低玩家的水平速度。


潛行故障

當玩家潛行降落在邊緣時會發生潛行故障(或下蹲故障),這會導致他們掉落(在 1.16.2 中被修復)。

執行潛行故障時,伺服器對玩家的預期移動與玩家的實際移動不同。原因如下:

  • 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 singleplayer, lagbacks are caused by this section of code (heavily simplified, we ignore exceptional cases such as flying, sleeping, teleporting, respawning, mounting an entity...):
//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());
}
Note that the handling of fall damage is not processed if the player gets lagbacked. This may cause the player to suffer unexpectedly high fall damage when they eventually land. Since 1.15 (when the boat fall damage bug was fixed), jumping resets the player's fall distance, which can be abused to survive high falls when combined with lagback.