天才一秒記住【UU看書】地址:www.uukanshu.co
(注:非常不推薦在手機上閱讀此章節,請使用平板或電腦閱讀此章)
(本章用到了大量的字元畫,有可能會出現嚴重的錯位情況,可手動調整字型和大小至最佳狀態)
(此章節已於2022年7月17日重寫)
在第六十九章,我為了提醒你注意各個子命令的順序,專門舉了個例子:
executeaseateruntps1
但是你是否有注意到遊戲執行這條指令的過程:
①將玩家傳送至玩家上方1米的位置(玩家此時抬高了1米)
②將玩家傳送至村民上方1米的位置(玩家此時位於村民上方1米)
③將玩家傳送至羊上方1米的位置(玩家此時位於羊上方1米)
④將村民傳送至玩家上方1米的位置(村民此時位於玩家原本位置上方1米,玩家此時位於羊上方1米)
⑤將村民傳送至村民上方1米的位置(村民此時位於村民原本位置上方1米,玩家此時位於羊上方1米)
⑥將村民傳送至羊上方1米的位置(村民和玩家此時位於羊上方1米)
⑦將羊傳送至玩家上方1米的位置(村民和玩家此時位於羊原本位置上方1米,羊位於玩家原本位置上方1米)
⑧將羊傳送至村民上方1米的位置(村民和玩家此時位於羊原本位置上方1米,羊位於村民原本位置上方1米)
⑨將羊傳送至羊上方1米的位置(村民、玩家和羊此時都位於羊原本位置上方1米)
這個過程有何特殊的呢?
你仔細看看第④、⑤、⑦、⑧和⑨條過程,你有沒有什麼發現?
當遊戲將村民傳送至玩家上方1米的位置時,雖然玩家已經被傳送至了羊上方1米的位置,但遊戲仍然將村民傳送至玩家原本位置上方1米,而不是羊上方2米的位置。
這是怎麼回事?
我們設玩家2,2,2為A、村民3,2,3為B、羊4,2,4為C,遊戲在執行execute時,其實它的流程是這樣的:
executeABC
遊戲先解析ase,得到了上面的三個目標。
executeABC
↓↓↓
2·2·22·2·22·2·2
↓↓↓
3·2·33·2·33·2·3
↓↓↓
4·2·44·2·44·2·4
然後遊戲會解析ate,預先將實體的位置記錄下來。上面為了方便展示,用x·y·z來表示座標。
executeABC
↓↓↓
2·2·2—3·2·3—4·2·42·2·2—3·2·3—4·2·42·2·2—3·2·3—4·2·4
↓↓↓↓↓↓↓↓↓
①②③④⑤⑥⑦⑧⑨
①:tp玩家名232
②:tp玩家名333
③:tp玩家名434
④:tp村民UUID232
⑤:tp村民UUID333
⑥:tp村民UUID434
⑦:tp羊UUID232
⑧:tp羊UUID333
⑨:tp羊UUID434
接下來遊戲會解析runtps1,根據三要素,將其中的目標選擇器和相對座標等引數具體化(但計分板分數之類的不會具體化,因為沒必要),得到具體的指令(如上)。
最後,遊戲執行具體的指令,也就是本章最開頭的那九個過程。
其中,最重要的,也是最關鍵的一點,就在於execute指令解析ate的過程。
execute並不是說執行一次解析一次,而是先全部解析了再執行,所以並不會使得『村民傳到玩家傳送過後上方1米的位置』之類的事情發生。
能理解吧?
那問題來了,如果execute再套一個execute會發生什麼?比如我們將上述指令寫成:
executeaserunexecuteateruntps1
其實效果還是一樣的,具體原因就等你自己去推導吧,按照我上面的流程去推導。
這就是Javaexecute113版本的執行流程。如果你還不懂,我們再看一個簡單並且效果比較明顯的例子。
設有盔甲架A和B,分別位於主世界的40,60,29和42,60,29。盔甲架A的生成時間比盔甲架B更早,已載入區塊中沒有其他盔甲架。在盔甲架A、B旁執行如下指令:
executeasetypeminecraftarmorstandatsruntpetypeminecraftarmorstand,distance1310
讓我們分析一下,執行上述指令會發生什麼。
首先,如果我們按照正常的思維去分析這條指令,就會得到以下結果:
A會先將B傳送到自己上方10米的位置,B由於處於那個位置無法選取到A來傳送,最終僅僅B會被傳送到A的上方10米處。
但其實,如果你真的去執行這條指令,就會發現A和B都會被傳送到對方原位置的上方10米處。
為什麼?我們按照遊戲的思維分析一下就可以了:
executeAB
遊戲先解析asetypeminecraftarmorstand,得到了上面的兩個目標:盔甲架A和盔甲架B。
executeAB
↓↓
40·60·2942·60·29
然後遊戲會解析ats,預先將實體的位置記錄下來。
executeAB
↓↓
40·60·2942·60·29
↓↓
①②
①:tp盔甲架B的UUID405029
②:tp盔甲架A的UUID425029
接下來遊戲會解析runtpetypeminecraftarmorstand,distance1310,根據三要素,具體化指令,得到具體的指令。由於此時還未傳送,所以目標選擇器會分別選擇到『盔甲架A』和『盔甲架B』。
最後,遊戲按照順序執行指令,分別將盔甲架A和盔甲架B傳送到對方上面10米高的位置。
這個例子比較簡單,你應該能夠理解吧?
所以你明白了嗎?
上面講的是Java113更新後的execute指令其執行的具體流程,那麼Java113更新前的呢?以及基岩版的呢?
2016年6月22日,MCBBS大佬pca006132在『礦工茶館』釋出了一個猜猜樂(ID594475),大致的問題如下:
executeesummonArmorStand,這個指令在初始實體不同數目的時候出來的結果是什麼
沒想到竟然沒人能夠解答這個問題,於是這位大佬在次日講解了這個問題(帖子ID:594698)。他舉了一個簡單的例子:
當初始實體數為2時,執行executeeexecuteesummonArmorstand
這個例子的結果竟然是8。
那如果在相同的初始情況下,執行executeeexecuteeexecuteesummonArmorstand,即套了三個execute的指令會發生什麼?
答案是:2048。
很令人震驚啊!那為什麼會這樣呢?
如果我們在Java113及以上版本,執行類似的指令,將達不到一樣的效果,因為在Java113之前,execute的執行邏輯是完全不一樣的。
那麼到底是個怎麼個邏輯法呢?其實在Java113前,execute並不會在執行前先存好各種資料,而是執行一遍解析一遍。以上面那個巢狀了3層execute的指令為例子,我們來解析一下。
條件:初始兩個實體A1,2,1和B2,2,2,A比B離執行地點更近。
executeAB
↓
1·2·1
遊戲先解析第一個『executee』,得到了上面的結果。後面我們將會忽略執行地點,因為這邊不需要考慮執行地點的影響。
executeAB
↓
A——B
遊戲按照順序,先以A為執行者執行指令,並解析了第二個『executee』,得到了上面的結果。
executeAB
↓
A——B
↓
A——B
遊戲按照順序,再次以A為執行者執行指令,並解析了第三個『executee』,得到了上面的結果。
executeAB
↓
A——B
↓
A——B
↓↓
CD
第三個execute執行指令,產生了新的盔甲架C和D。
executeAB
↓
A————B
↓↓
2B—A—C—D
遊戲回到第二層execute,以目標選擇器順序選取B為執行者,由於之前已經生成了C和D,所以B執行第三層execute指令時,會選取到4個實體來執行指令,最終實體數量4(現在為8224)。
executeAB
↓↓
6B—A—C—D—E—F—G—H
遊戲回到第一層execute,以目標選擇器順序選取B為執行者。由於已經有了八個實體,因此這一次第二層execute會選取到八個實體來執行第三層execute。
executeAB
↓↓
6B——A——C——D———E———F———G———H
↓↓↓↓↓↓↓↓
增加實體數81632641282565121024
增加後數量16326412825651210242048
隨後,遊戲按照順序依次以這八個實體執行指令,實體數量在此過程中快速增長,最終變為2048。
不難發現,每一次第三層的execute指令被執行,都會將當前實體數量×2,而上面一共執行了10次第三層的execute,相當於2被乘以了10次2,也就是2×2×2×2×2×2×2×2×2×2×2,即2的11次方,結果為2048,即2048個實體。
實在是太令人驚訝了是不是?在Java113以下的execute指令中,execute僅僅會在被選取的執行者開始執行指令時才會進行下一步的解析動作,而且不會一下子就將所有執行者執行指令的情況全部解析出來再執行指令。
所以,Java113對execute的改動不僅僅是格式上的,還有執行流程上的改動。
如果你並不能很好理解上面為什麼會由2個實體產生出2048個實體,別擔心,我們繼續以剛才兩個盔甲架互相傳送為例子,看看類似的指令在Java113以下的版本有何不同的效果。
還是設有盔甲架A和B,分別位於主世界的40,60,29和42,60,29。盔甲架A的比盔甲架B更靠近執行地點,已載入區塊中沒有其他盔甲架。在盔甲架A、B旁執行如下指令:
executeetypearmorstandteleportetypearmorstand,r3,rm110
遊戲先解析『executeetypearmorstand』得到如下結果:
executeAB
↓
40·60·29
然後以A為執行者,解析『teleportetypearmorstand,r3,rm110』,得到了如下指令:
teleport盔甲架B的UUID407029
執行上述指令,盔甲架B被傳送至40,70,29處。隨後遊戲以B為執行者,先解析執行地點引數『』,得到如下結果:
executeAB
↓↓
40·60·2940·70·29
將B傳送至40·70·29
接下來,遊戲以B為執行者,再次解析指令,得到如下內容:
選擇器etypearmorstand,r3,rm1什麼都沒找到
沒錯,由於B被傳送到了40,70,29,因此目標選擇器就選不到A,自然就無法執行指令。最終,正如我們在最開始以正常思維分析的那樣,得到了如下結果:
A會先將B傳送到自己上方10米的位置,B由於處於那個位置無法選取到A來傳送,最終僅僅B會被傳送到A的上方10米處。
雖然在Java113更新後,我們的『正常思維』沒用了,但在Java113以下版本還是很準的。
那在基岩版呢?
作者在基岩版也測試過了(用的上面的兩個盔甲架tp法),確認基岩版不管是舊版還是新版(11910更新的)的execute,都是會得到和Java版113以下版本一模一樣的資料。
其中,對於目前還在測試的新版execute,用的是如下指令:
executeasetypearmorstandatsruntpetypearmorstand,r3,rm110
也就是說,如果你在基岩版執行上面套了3層execute的生成指令,在初始實體數為2的情況下,也會得到有2048個實體的糹
你的電腦遇到問題,需要重新啟動。
我們只收集某些錯誤資訊,然後為你重新啟動。
——附錄:跟本章有關係的MCBBS帖子原連結
wwwmcbbsnetthread59469811html
wwwmcbbsnetthread59447511html
(上述帖子均已被MCBBS論壇系統自動關閉)