跑跑車首頁(yè)

當(dāng)前位置:首頁(yè)攻略秘籍單機(jī)攻略 → 我的世界神秘時(shí)代4.2.3.5從源代碼詳解注魔的風(fēng)險(xiǎn)控制

我的世界神秘時(shí)代4.2.3.5從源代碼詳解注魔的風(fēng)險(xiǎn)控制

作者:佚名來(lái)源:本站整理 發(fā)表時(shí)間:2015/12/31 8:41:23 評(píng)論(0)

玩過(guò)神秘(Thaumcraft)4的人都知道,奧術(shù)注魔如果沒有采取保護(hù)措施,往往會(huì)出現(xiàn)咒波污染、爆炸等事故。《魔導(dǎo)手冊(cè)》告訴我們,頭骨、魔晶、蠟燭等物品能降低注魔的風(fēng)險(xiǎn)。于是很多人看了網(wǎng)上的攻略或者教程,直接在符文矩陣下方幾個(gè)格子的地方擺了13*13的蠟燭方陣,的確解決了這些問(wèn)題。然而,為什么是13*13呢?為什么要擺在那個(gè)位置呢?一般玩家都沒有這么深入地想下去。今天,我就通過(guò)解析反編譯之后的Java源代碼的方式,介紹一下關(guān)于奧術(shù)注魔的風(fēng)險(xiǎn)的詳細(xì)計(jì)算方法。不過(guò)不會(huì)Java也沒關(guān)系,直接看帖子結(jié)尾的結(jié)論就好了。

代碼的位置

和注魔有關(guān)的代碼(不包括配方)在thaumcraft.common.tiles包里的TileInfusionMatrix這個(gè)類中。其中TileInfusionMatrix.class文件用各種工具反編譯之后可以得到代碼TileInfusionMatrix.txt。  TileInfusionMatrix.txt  

不穩(wěn)定性(instability)

這是craftingCycle方法中,第436~513行的代碼:


  1. if ((!valid) || ((this.instability > 0) &&

  2.                 (this.worldObj.rand.nextInt(500) <= this.instability))) {

  3.     switch (this.worldObj.rand.nextInt(21)) {

  4.         case 0: case 2: case 10: case 13: inEvEjectItem(0); break;

  5.         case 6: case 17: inEvEjectItem(1); break;

  6.         case 1: case 11: inEvEjectItem(2); break;

  7.         case 3: case 8: case 14: inEvZap(false); break;

  8.         case 5: case 16: inEvHarm(false); break;

  9.         case 12: inEvZap(true); break;

  10.         case 19: inEvEjectItem(3); break;

  11.         case 7: inEvEjectItem(4); break;

  12.         case 4: case 15: inEvEjectItem(5); break;

  13.         case 18: inEvHarm(true); break;

  14.         case 9:

  15.             this.worldObj.createExplosion(null, this.xCoord + 0.5F,

  16.                 this.yCoord + 0.5F, this.zCoord + 0.5F,

  17.                 1.5F + this.worldObj.rand.nextFloat(), false);

  18.             break;

  19.         case 20: inEvWarp();

  20.     }

  21.     if (valid) return;

  22. }


復(fù)制代碼

craftingCycle方法會(huì)在奧術(shù)注魔的過(guò)程中被不斷調(diào)用,每10個(gè)tick調(diào)用一次,直到注魔結(jié)束。

這個(gè)if語(yǔ)句內(nèi)部是奧術(shù)注魔的各種副作用,從調(diào)用的函數(shù)的名稱就可以看出來(lái),什么彈出物品啊、爆炸啊、扭曲啊之類的。這些事故是我們玩家不希望發(fā)生的,因此這段代碼的關(guān)鍵就是if語(yǔ)句的條件。首先是"!valid",觀察前面的代碼會(huì)發(fā)現(xiàn),當(dāng)注魔中途有檢測(cè)到注魔材料不完整的時(shí)候valid才會(huì)等于false,此時(shí),不論后面的條件滿不滿足,都會(huì)強(qiáng)制觸發(fā)一次注魔事故。因此一旦注魔開始,就要盡量保護(hù)好基座上的物品,否則必定發(fā)生事故。

"或"符號(hào)后面的條件是(this.instability > 0) && (this.worldObj.rand.nextInt(500) <= this.instability)。

翻譯成自然語(yǔ)言,大概就是:

不穩(wěn)定性>0  且  不穩(wěn)定性>=(一個(gè)0~499的隨機(jī)數(shù))

也就是說(shuō)注魔的風(fēng)險(xiǎn)和不穩(wěn)定性有關(guān),只要不穩(wěn)定性大于零,就有幾率發(fā)生風(fēng)險(xiǎn)。不穩(wěn)定性越大,產(chǎn)生風(fēng)險(xiǎn)的可能性也就越大。

那么不穩(wěn)定性又是如何計(jì)算出來(lái)的呢?這是craftingStart方法的307~310行:


  1. this.recipeInstability = recipe.getInstability(this.recipeInput);

  2. this.recipeEssentia = recipe.getAspects(this.recipeInput).copy();

  3. this.recipePlayer = player.getCommandSenderName();

  4. this.instability = (this.symmetry + this.recipeInstability);


復(fù)制代碼

翻譯成自然語(yǔ)言就是:

不穩(wěn)定性 = 對(duì)稱性 + 配方不穩(wěn)定性

不過(guò)不要高興地太早,代碼中還有這么幾行(craftingCycle中,有好幾處):


  1. if (this.worldObj.rand.nextInt(50 -(this.recipeInstability * 2)) == 0) {

  2.     this.instability += 1;

  3. }

  4. if (this.instability > 25) {

  5.     this.instability = 25;

  6. }


復(fù)制代碼

這里似乎會(huì)不斷增加注魔的不穩(wěn)定性,最多增加到25,也就是每0.5s有5%的概率發(fā)生事故。然而仔細(xì)觀察上下文會(huì)發(fā)現(xiàn),這兩行代碼在正常情況下是不會(huì)被執(zhí)行的,它們只會(huì)在注魔過(guò)程中源質(zhì)缺失、物品缺失或者注魔附魔時(shí)經(jīng)驗(yàn)不足時(shí)執(zhí)行。

配方不穩(wěn)定性是一個(gè)整數(shù),對(duì)應(yīng)著魔導(dǎo)手冊(cè)中不同的風(fēng)險(xiǎn)等級(jí)。具體數(shù)值可以直接在配方文件中查閱,addInfusionCraftingRecipe方法的第三個(gè)參數(shù)就是配方不穩(wěn)定性:

 ConfigRecipes.txt 

在原版TC中,絕大多數(shù)的注魔的配方不穩(wěn)定性都在1~8之間,只有高級(jí)節(jié)點(diǎn)穩(wěn)定器的配方不穩(wěn)定性是10。

對(duì)稱性(symmetry)

對(duì)稱性涉及到的東西就是注魔祭壇的擺放問(wèn)題了。關(guān)于對(duì)稱性的全部代碼幾乎都能在getSurroundings方法(852~953行)找到。

首先,程序獲取了周圍方塊的信息:


  1. for (int xx = -12; xx <= 12; xx++) {

  2.     for (int zz = -12; zz <= 12; zz++) {

  3.         boolean skip = false;

  4.         for (int yy = -5; yy <= 10; yy++) {

  5.             if ((xx != 0) || (zz != 0)) {

  6.                 int x = this.xCoord + xx;

  7.                 int y = this.yCoord - yy;

  8.                 int z = this.zCoord + zz;

  9.                 TileEntity te = this.worldObj.getTileEntity(x, y, z);

  10.                 if ((!skip) && (yy > 0) && (Math.abs(xx) <= 8) && (Math.abs(zz) <= 8)

  11.                             && (te != null) && (te instanceof TilePedestal)) {

  12.                     this.pedestals.add(new ChunkCoordinates(x, y, z));

  13.                     skip = true;

  14.                 } else {

  15.                     Block bi = this.worldObj.getBlock(x, y, z);

  16.                     if ((bi == Blocks.skull) || ((bi instanceof IInfusionStabiliser)

  17.                                 && (((IInfusionStabiliser) bi).canStabaliseInfusion(getWorldObj(), x, y, z)))) {

  18.                         stuff.add(new ChunkCoordinates(x, y, z));

  19.                     }

  20.                 }

  21.             }

  22.         }

  23.     }

  24. }


復(fù)制代碼

搜索的范圍是橫縱坐標(biāo)±12、豎直方向-10~+5的范圍。為什么不是-5~+10呢?因?yàn)?quot;int y = this.yCoord - yy;",中間是個(gè)減號(hào)而不是加號(hào),千萬(wàn)不要上當(dāng)了。"if ((xx != 0) || (zz != 0))",有了這句話,說(shuō)明和符文矩陣在同一條鉛垂線的格子不會(huì)被搜索到。這里還有個(gè)"skip",在yy循環(huán)的外層初始化為false,當(dāng)檢查到第一個(gè)物品基座時(shí)變?yōu)閠rue,當(dāng)檢查到第二個(gè)物品基座時(shí)就直接忽略——它的作用是對(duì)于幾個(gè)在同一條鉛垂線上的物品基座,只考慮最頂上的,忽略掉下方其它的基座。雖然搜索范圍很大,但是第一個(gè)if語(yǔ)句"if ((!skip) && (yy > 0) && (Math.abs(xx) <= 8) && (Math.abs(zz) <= 8) && (te != null) && ((te instanceof TilePedestal)))"告訴我們,實(shí)際上只有x坐標(biāo)和z坐標(biāo)相差小于等于8,且嚴(yán)格處于符文矩陣所在格子下方的物品基座才會(huì)被考慮進(jìn)去。

但是對(duì)于"IInfusionStabiliser",也就是魔鏡、頭骨、蠟燭等“法器”,搜索范圍就是原來(lái)的大小,也就是橫縱坐標(biāo)±12、豎直方向-10~+5的范圍。

這整一段代碼把一定范圍內(nèi)的基座和“法器”都記錄下來(lái),用于接下來(lái)的判斷:


  1. this.symmetry = 0;

  2. for (ChunkCoordinates cc : this.pedestals) {

  3.     boolean items = false;

  4.     int x = this.xCoord - cc.posX;

  5.     int z = this.zCoord - cc.posZ;

  6.     TileEntity te = this.worldObj.getTileEntity(cc.posX, cc.posY, cc.posZ);

  7.     if ((te != null) && (te instanceof TilePedestal)) {

  8.         this.symmetry += 2;

  9.         if (((TilePedestal) te).getStackInSlot(0) != null) {

  10.             this.symmetry += 1;

  11.             items = true;

  12.         }

  13.     }

  14.     int xx = this.xCoord + x;

  15.     int zz = this.zCoord + z;

  16.     te = this.worldObj.getTileEntity(xx, cc.posY, zz);

  17.     if ((te != null) && (te instanceof TilePedestal)) {

  18.         this.symmetry -= 2;

  19.         if ((((TilePedestal) te).getStackInSlot(0) != null) && (items)) {

  20.             this.symmetry -= 1;

  21.         }

  22.     }

  23. }


復(fù)制代碼

這一部分計(jì)算的是所有的基座。對(duì)于每個(gè)基座,都會(huì)提供2點(diǎn)symmetry,如果上面有物品還會(huì)額外提供一點(diǎn)symmetry;后面的xx,zz計(jì)算的是這個(gè)基座以符文矩陣所在鉛垂線為軸的對(duì)稱位置,如果對(duì)稱位置也有基座,就會(huì)減少兩點(diǎn)symmetry;同理,這個(gè)基座上有物品、對(duì)稱的基座上也有物品,symmetry還會(huì)再減少一點(diǎn)。也就是說(shuō),如果基座擺得不對(duì)稱或者基座上的物品擺得不對(duì)稱就會(huì)增大注魔的風(fēng)險(xiǎn),如果完全對(duì)稱,這一部分的貢獻(xiàn)的風(fēng)險(xiǎn)可以降為0。


  1. float sym = 0.0F;

  2. for (ChunkCoordinates cc : stuff) {

  3.     boolean items = false;

  4.     int x = this.xCoord - cc.posX;

  5.     int z = this.zCoord - cc.posZ;

  6.     Block bi = this.worldObj.getBlock(cc.posX, cc.posY, cc.posZ);

  7.     if ((bi == Blocks.skull) || ((bi instanceof IInfusionStabiliser) &&

  8.             (((IInfusionStabiliser) bi).canStabaliseInfusion(getWorldObj(), cc.posX, cc.posY, cc.posZ)))) {

  9.         sym += 0.1F;

  10.     }

  11.     int xx = this.xCoord + x;

  12.     int zz = this.zCoord + z;

  13.     bi = this.worldObj.getBlock(xx, cc.posY, zz);

  14.     if ((bi == Blocks.skull) || ((bi instanceof IInfusionStabiliser) &&

  15.             (((IInfusionStabiliser) bi).canStabaliseInfusion(getWorldObj(), cc.posX, cc.posY, cc.posZ)))) {

  16.         sym -= 0.2F;

  17.     }

  18. }


復(fù)制代碼

這部分計(jì)算的是所有的"法器"。對(duì)于每個(gè)"法器",都會(huì)提供0.1的symmetry;如果對(duì)稱位置也有"法器"則會(huì)再減少0.2的symmetry(無(wú)論兩者是否相同)。也就是說(shuō)擺放對(duì)稱的"法器"可以減少注魔風(fēng)險(xiǎn),但是如果沒有成對(duì)地?cái)[放反而會(huì)增加注魔風(fēng)險(xiǎn)。注意,"法器"提供的symmetry單獨(dú)存在一個(gè)單精度浮點(diǎn)數(shù)變量"sym"里面。


  1. this.symmetry = ((int) (this.symmetry + sym));


復(fù)制代碼

最后把基座和"法器"提供的symmetry加起來(lái),轉(zhuǎn)換為整數(shù)。注意這個(gè)轉(zhuǎn)換過(guò)程是截?cái)嗳≌簿褪窍?方向取整。

結(jié)論

1.注魔祭壇相關(guān)的所有“對(duì)稱性”都是以符文矩陣所在鉛垂線軸對(duì)稱(從上往下看就像是中心對(duì)稱),而且只需考慮“有”和“沒有”,和物品的種類無(wú)關(guān)。比如A位置和B位置對(duì)稱的,那么如果A擺了物品,B也要擺物品,否則就會(huì)不穩(wěn)定;但是對(duì)于B位置擺的物品的種類,是不影響注魔風(fēng)險(xiǎn)的。對(duì)于蠟燭、頭骨、魔晶等"法器"也是一樣,甚至蠟燭的對(duì)稱位置是頭骨,也能配成一對(duì)來(lái)降低注魔風(fēng)險(xiǎn);而且蠟燭、頭骨、魔晶降低注魔風(fēng)險(xiǎn)的效果完全相同。此外,除了基座和法器外的方塊和實(shí)體對(duì)注魔祭壇的穩(wěn)定性沒有任何影響。

2.假設(shè)符文矩陣的坐標(biāo)是(x,y,z),那么基座的有效擺放范圍是(x-8 ~ x+8, y-10 ~ y-1, z-8 ~ z+8),還要滿足兩個(gè)條件:基座和符文矩陣不能擺在同一條鉛垂線上、任意兩個(gè)基座不能擺在同一條鉛垂線上(否則只有上面的有效)。

3.假設(shè)符文矩陣的坐標(biāo)是(x,y,z),那么蠟燭、頭骨、魔晶等"法器"的有效擺放范圍是(x-12 ~ x+12, y-10 ~ y+5, z-12 ~ z+12),并且不能和符文矩陣在同一條鉛垂線上。理論上可以擺下大量的蠟燭,因?yàn)橄灎T不只可以擺一層、而是可以擺好多層。

4.原版中,最危險(xiǎn)的注魔是高級(jí)節(jié)點(diǎn)穩(wěn)定器。它的配方不穩(wěn)定性是10;因?yàn)槲锲穫(gè)數(shù)是偶數(shù),可以擺成完全對(duì)稱,所以基座和基座上的材料帶來(lái)的symmetry可以達(dá)到0;因此理論上只需要擺100個(gè)兩兩對(duì)稱的蠟燭即可做到0風(fēng)險(xiǎn)。實(shí)測(cè)需要104個(gè),可能是浮點(diǎn)數(shù)誤差的問(wèn)題。如果基座上所需材料個(gè)數(shù)是奇數(shù),不穩(wěn)定性要+1,但是原版神秘中需要奇數(shù)個(gè)材料的注魔配方不穩(wěn)定性最高也只有8,還不如高級(jí)節(jié)點(diǎn)穩(wěn)定器危險(xiǎn)?傊衩4原版想要100%安全地注魔只需要104根兩兩對(duì)稱的蠟燭,而不是大部分教程聲稱的169個(gè)、168個(gè)或是152個(gè)。如果不信,可以用NBT edit實(shí)時(shí)查看符文矩陣的instability值(http://www.royaljewelryandwatches.com/buding/116137.html)(安裝后鼠標(biāo)指著符文矩陣輸入命令/nbtedit查看)

5.前期注魔的時(shí)候?yàn)榱斯?jié)約材料可以不用造那么多蠟燭(那些風(fēng)險(xiǎn)"微乎其微"的只要十來(lái)根蠟燭就夠了),蠟燭的數(shù)目可以隨著所需注魔的風(fēng)險(xiǎn)越來(lái)越高而逐漸增加。有些附屬M(fèi)OD里的注魔或者被整合包作者魔改的注魔,如果不知道需要多少蠟燭,可以裝個(gè)NBT edit,先到創(chuàng)造模式里去試一試,計(jì)算出需要多少蠟燭了再回到生存里面實(shí)踐。

這里用的代碼來(lái)自TC4.2.3.5的dev版,和玩家拿到的版本是在功能上是完全一樣的。這些代碼的分發(fā)并沒有得到Thaumcraft作者Azanor的授權(quán),僅供學(xué)習(xí)研究,請(qǐng)勿用于商業(yè)用途,下載后請(qǐng)?jiān)?4小時(shí)內(nèi)刪除。(感謝 @u.s.knowledge )

最后引用被神秘時(shí)代的作者很喜歡的一句話:

"Thaumaturgy... which giveth certain order to make strange works, of the sense to be perceived and of men greatly to be wondered at."

- Mathematicall Praeface to Euclid's Elements (1570), John Dee

意思是說(shuō),神秘也是有一定規(guī)律的,在MC里體現(xiàn)為——神秘時(shí)代MOD就是一堆代碼。從代碼內(nèi)部剖析神秘時(shí)代,得到的是另一種趣味。


玩家評(píng)論
我要點(diǎn)評(píng)

網(wǎng)名 注:您的評(píng)論需要經(jīng)過(guò)審核才會(huì)顯示出來(lái)。

已有 0 位玩家參與點(diǎn)評(píng)
下載排行