最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會員登陸 & 注冊

Minecraft:退出重進(jìn)大法的原理,到底是無敵時間還是重置高度

2020-08-17 19:16 作者:Nickid2018  | 我要投稿

在玩MC的時候,總是會出現(xiàn)這樣尷尬的局面:腳滑了,掉入萬丈深淵。除了聽天由命外,另一種選擇就是快到地面時退出重進(jìn)。對此現(xiàn)象的解釋,玩家分成了兩派:無敵時間派和重置高度派。

下面,我們將從代碼層和用戶層進(jìn)行分析。

1.代碼層原理

警告:此處會涉及到大量的代碼邏輯,沒有學(xué)習(xí)過編程的人可以直接查看用戶層驗證。

Minecraft源碼來自由官方混淆表對1.14.4.jar進(jìn)行反混淆反編譯形成的源碼,官方混淆表地址能在1.14.4+的版本JSON文件中找到,名為client_mappings。使用官方混淆表以保證代碼純凈。

首先,我們了解一下玩家受到傷害的代碼,這也是我們研究這個問題的切入點:

玩家收到傷害是由hurt方法進(jìn)行處理,定義在net.minecraft.world.entity.Entity內(nèi),返回true為傷害成立,返回false則傷害取消。接著它被LivingEntity覆蓋(沒有調(diào)用super.hurt),之后被Player類覆蓋。

net.minecraft.world.entity.LivingEntity#hurt

net.minecraft.world.entity.player.Player#hurt

Player的子類有兩個:ServerPlayer和AbstractCilentPlayer。我們需要的hurt代碼在ServerPlayer中,因為另一個類是進(jìn)行客戶端渲染占位的。

net.minecraft.server.level.ServerPlayer#hurt,注意紅框內(nèi)的代碼

在這里我們看到了spawnInvulnerableTime,翻譯為"出生無敵時間"。注意其他的條件,總結(jié)出來一共有五個條件:

  1. 服務(wù)器不能為專用服務(wù)器

  2. PVP不被允許

  3. 傷害不能為掉落傷害

  4. 在出生無敵時間內(nèi)

  5. 傷害不能為虛空傷害

其中,1,2,3點滿足一點即可,4,5點必須滿足

所以我們可以證明無敵時間確實能阻止摔落傷害發(fā)生:單機條件下,服務(wù)器為IntegratedServer,它不是"專用服務(wù)器",滿足第一點。退出重進(jìn)后的傷害一瞬間,如果在無敵時間內(nèi),并且不是掉到虛空外或kill帶來的傷害(kill本質(zhì)是數(shù)值極大,也就是Float.MAX_VALUE的虛空傷害),那么這個傷害效果將被取消。

那么這么萬能的無敵時間是多少呢,代碼層得出的結(jié)果:60tick,也就是TPS為20時的3s。(判斷為60tick而不是60ms是因為下方的tick方法寫到了它的自減,所以推斷單位是tick)

注意:無敵時間不僅是在進(jìn)入世界時起效,死亡重生之后也會有3s的無敵時間,因為死亡時系統(tǒng)刪除了原先的Player,重生時會創(chuàng)建新的Player,因此存在無敵時間。

spawnInvulnerableTime的定義,默認(rèn)值為60


net.minecraft.server.level.ServerPlayer#restoreFrom,應(yīng)該是從一個過去的Player拷貝數(shù)據(jù),也就是死亡后進(jìn)行數(shù)據(jù)傳輸?shù)姆椒?/figcaption>

那么紅框上那個isInvulnerableTo又是什么呢,翻找之后發(fā)現(xiàn)它和無敵時間無關(guān),但是能解釋創(chuàng)造模式下為什么還會受到虛空傷害。

net.minecraft.world.entity.Entity#isInvulnerableTo

同時通過ServerPlayer的覆蓋,我們了解到變更維度過程中,也無法受到傷害。

net.minecraft.server.level.ServerPlayer#isInvulnerableTo

說完了無敵時間,我們再從另一個角度——重置高度進(jìn)行分析。

為了這個分析,我們就要了解摔落傷害是怎么產(chǎn)生的:

net.minecraft.world.entity.LivingEntity#causeFallDamage,這是摔落傷害的執(zhí)行部分

然而到這里,我們就找不到線索了:是誰調(diào)用了它。但是突然想起來干草塊能降低摔落傷害,所以去找干草塊的類(HayBlock),找到了發(fā)生傷害的地方。

net.minecraft.world.level.block.HayBlock,fallOn就是產(chǎn)生傷害的方法

通過此處,我們看到causeFallDamage的第二個參數(shù)的真面目:摔落傷害比例。Block內(nèi),這里寫的是1f,而這里寫為了0.2f,也就是干草塊能阻止80%的摔落傷害。

同時,我們得出了摔落傷害的公式(不具有緩降效果):

當(dāng)沒有跳躍提升效果時:fallDamage = (fallDistance - 3.0f) * damageRatio

當(dāng)存在跳躍提升效果時:fallDamage = (fallDistance - 4.0f - amplifier) * damageRatio

fallDamage-摔落傷害 fallDistance-摔落高度

damageRatio-摔落傷害比例 amplifier-跳躍提升等級

但是到了這里,線索又消失了。

由于沒法通過eclipse的調(diào)用層次結(jié)構(gòu)尋找,我只好用了代碼探針,在Block類的fallOn那里動態(tài)插入了一個Thread.dumpStack()。

通過命令在Block#fallOn(代碼行806)插入一個dumpStack

之后進(jìn)行摔落,產(chǎn)生了兩組堆棧:

Client端(不負(fù)責(zé)實體傷害)

Client Thread的堆棧跟蹤,看出這里負(fù)責(zé)了實體的運動

Server端(真正需要的地方)

Server端的堆棧跟蹤

通過這些,我們?nèi)フ襍erverPlayer#doCheckFallDamage:

net.minecraft.server.level.ServerPlayer#doCheckFallDamage

通過這里,我們了解到了這個方法是用于檢查下方的方塊的,但是還是沒有出現(xiàn)下落距離等的出現(xiàn),所以繼續(xù)向下查。

net.minecraft.world.entity.LivingEntity#checkFallDamage

這里出現(xiàn)了一個激動人心的字段:fallDistance,下落距離。也就是說,下落距離是根據(jù)此字段保存的,那么只要證明它被保存了,就能說明重置高度的說法是錯誤的。

可是LivingEntity沒有定義該字段,那么這個字段就一定定義在它的上一級:Entity。

net.minecraft.world.entity.Entity#saveWithoutId,也就是保存實體數(shù)據(jù)的地方

通過這一張圖,我們的代碼驗證走到了盡頭:我們可以清晰地看到這句

compoundTag.putFloat("FallDistance", this.fallDistance);

這句話意味著保存了下落高度,也就是說,在下次進(jìn)入世界時,下落高度會從文件中重新讀取回來,也就是你上一次退出游戲時已經(jīng)下落的高度,所以說,重置高度說是錯誤的。

為了進(jìn)行嚴(yán)謹(jǐn)?shù)恼撟C,下面用客戶端進(jìn)行驗證。

2.客戶端驗證

首先,驗證無敵時間,這個很容易驗證,你在出生60tick內(nèi)泡個巖漿澡就能驗證:

來泡澡嗎?

而重置高度,就不好驗證了。我想到了一種方案:生命提升后看摔落傷害——只要在超過3s的摔落高度下進(jìn)行摔落測試,就能受到傷害并且能看出與不退出的關(guān)系:如果摔落之后血量有差異(誤差保持在±5內(nèi)),那么就證明了確實有重置高度;相反的,如果基本沒有差異,那么就沒有重置。

首先給予生命提升255級,把血條變成了1024滴,然后用瞬間治療10級10秒,把心補滿。之后第一次試驗,從Y=1000直接摔到1,看血量。

從1000直接摔到1,經(jīng)歷了非人的折磨

第二次測試也是在Y=1000落下,不同的是,這次讓它在Y=700左右的時候退出重進(jìn),然后再落到Y(jié)=1。

在Y=718退出了一次,為了保證不出偶然性,把MC主程序也關(guān)掉重啟
經(jīng)歷了一次退出,仍然摔的很慘

這兩次摔落結(jié)果很明顯,幾乎沒有任何血量差異。如果進(jìn)行了重置,那么血量會差250滴左右。因此,我們知道了重置高度是錯誤的。

結(jié)論

退出重進(jìn)的原理是無敵時間而非重置高度,所以下回使用這個方法的時候,還是要注意一下你距地面的高度(雖然我知道3s能下落200格高度,早死了)

一些其他的話

fallDistance其實并不是只有在掉落時才會改變,這里我們說一些和運動的內(nèi)容(具體的一些東西可以去CV7593366去看),不同狀態(tài)下,這些值也會改變(這里的detlaMovement是Y軸上的,簡寫為dY):

1.地面上的普通移動(不包括跳):dY=-0.0784000015258789(趨勢位移,在實際運動中不體現(xiàn))

2.水中:fallDistance逐漸變?yōu)?.025000002,dY逐漸變?yōu)?0.02500000149011622

3.飛行:dY逐漸變?yōu)椤?.22500000894069672

4.水中飛行:dY逐漸變?yōu)椤?.28500000759959215

5.在水中站立:dY=-0.005(水中的趨勢位移)

6.水中向上移動:dY逐漸變?yōu)?.13500000685453442

7.梯子下行:fallDistance=0.15,dY=-0.22540001022815717

由于浮點數(shù)誤差,小數(shù)點后四位基本上是準(zhǔn)確極限。不過還是能從這里看出了比如說水中飛行比普通飛行快的結(jié)論。

文章中用到的Minecraft反混淆和動態(tài)修改程序包含反混淆程序(直接運行)和動態(tài)修改替換MC類的功能(原版Java Agent而非模組):https://github.com/Nickid2018/MCDynamicExchanger,該程序正在被完善中。

反編譯器:Eclipse的插件,選擇了CFK反編譯器。

啟動器:HMCL版本3.3.172

MC客戶端:反混淆的1.14.4客戶端,反混淆過程中不會改變代碼邏輯,只有當(dāng)進(jìn)行Agent代理時才修改了一部分net.minecraft.commands.Commands的代碼。

驗證視頻:


如果你有任何問題或是文章有數(shù)據(jù)和代碼錯誤,可以在評論區(qū)留言。

Minecraft:退出重進(jìn)大法的原理,到底是無敵時間還是重置高度的評論 (共 條)

分享到微博請遵守國家法律
册亨县| 金川县| 江都市| 金山区| 万盛区| 汪清县| 巴中市| 高阳县| 饶河县| 高淳县| 宝鸡市| 宁乡县| 都江堰市| 霍山县| 伊川县| 民乐县| 恩平市| 苍溪县| 张北县| 达日县| 乌拉特前旗| 乐陵市| 梁河县| 宣汉县| 合作市| 阿克| 丹东市| 渝北区| 新昌县| 汤原县| 通化县| 吴忠市| 阿克陶县| 龙岩市| 吴桥县| 建湖县| 卫辉市| 安顺市| 新源县| 汨罗市| 尉氏县|