【Forge】Minecraft 1.7.10 Mod开发研究 - 黑猫背包MOD 【06-给你唱一首岁月的歌】
老實(shí)說(shuō)我已經(jīng)忘了這個(gè)mod是怎么寫(xiě)出來(lái)的了。
所以下面的代碼不能運(yùn)行是非常正常的。
?
上回書(shū)說(shuō)到,我們處理了玩家拿著背包右鍵時(shí)觸發(fā)的事件,發(fā)送了一條打開(kāi)背包窗口的命令,但是背包窗口還沒(méi)有寫(xiě),這回就來(lái)解決這個(gè)問(wèn)題。
這次因?yàn)榍短钻P(guān)系太多,所以我按執(zhí)行順序反過(guò)來(lái)說(shuō)。
那么先不管上次沒(méi)有打開(kāi)的那個(gè)GUI。
?
MC中的每一個(gè)能放進(jìn)物品的容器,不管是箱子、熔爐還是釀造臺(tái),各自都持有一個(gè)自己的內(nèi)容空間(Inventory)實(shí)例,在這個(gè)內(nèi)容空間中各自保存自己的內(nèi)容物。
內(nèi)容空間的基類(lèi)是InventoryBasic,實(shí)現(xiàn)了IInventory接口,為了方便,咱直接繼承InventoryBasic類(lèi)。
InventoryBasic類(lèi)已經(jīng)實(shí)現(xiàn)了大部分內(nèi)容空間需要的功能,可以粗讀一下代碼,挺好懂的。
于是我們黑貓背包的內(nèi)容空間類(lèi)只需要處理內(nèi)容物的保存和讀取。
1 public class InventoryKuroNeko extends InventoryBasic { 2 public static final String TITLE = "黑貓"; 3 public static final int SLOTS_PER_LINE = 9; 4 public static final int LINES = 2; 5 6 private ItemStack itemStack; 7 8 private String id; 9 10 public InventoryKuroNeko(ItemStack itemStack) { 11 super(TITLE, true, LINES * SLOTS_PER_LINE); 12 13 this.itemStack = itemStack; 14 15 if (!itemStack.hasTagCompound()) { 16 itemStack.setTagCompound(new NBTTagCompound()); 17 id = UUID.randomUUID().toString(); 18 } 19 20 readFromNBT(itemStack.getTagCompound()); 21 } 22 23 public NBTTagCompound writeToNBT(NBTTagCompound compound) { 24 NBTTagList items = new NBTTagList(); 25 26 for (int i = 0; i < getSizeInventory(); i++) { 27 ItemStack itemStack = getStackInSlot(i); 28 if (itemStack != null) { 29 NBTTagCompound item = new NBTTagCompound(); 30 item.setInteger("slot", i); 31 itemStack.writeToNBT(item); 32 items.appendTag(item); 33 } 34 } 35 36 compound.setTag("items", items); 37 38 compound.setString("id", id); 39 40 return compound; 41 } 42 43 public void readFromNBT(NBTTagCompound compound) { 44 if (id == null) { 45 id = compound.getString("id"); 46 } 47 if (id == null) { 48 id = UUID.randomUUID().toString(); 49 } 50 51 NBTTagList items = compound.getTagList("items", 10); 52 53 for (int i = 0; i < items.tagCount(); i++) { 54 NBTTagCompound item = items.getCompoundTagAt(i); 55 56 int slot = item.getInteger("slot"); 57 if (slot >= 0 && slot < getSizeInventory()) { 58 ItemStack itemStack = ItemStack.loadItemStackFromNBT(item); 59 setInventorySlotContents(slot, itemStack); 60 } 61 } 62 } 63 64 @Override 65 public void markDirty() { 66 super.markDirty(); 67 writeToNBT(this.itemStack.stackTagCompound); 68 } 69 } 先扔代碼自己寫(xiě)兩個(gè)方法,名字可以隨便起,我這里一個(gè)叫writeToNBT,用于保存內(nèi)容物,一個(gè)叫readFromNBT,用于讀取內(nèi)容物。
保存和讀取用到的是NBT機(jī)制,NBT全稱(chēng)是什么我已經(jīng)忘了。
先說(shuō)保存。
首先創(chuàng)建一個(gè)NBT的列表NBTTagList,用于保存各個(gè)物品和它們的位置。這個(gè)類(lèi)可以簡(jiǎn)單理解為一個(gè)列表。
然后遍歷所有內(nèi)容空間中的格子,只要發(fā)現(xiàn)格子中有物品,就把當(dāng)前的格子位置保存在一個(gè)NBTTagCompound中,這個(gè)類(lèi)理解為一個(gè)存儲(chǔ)單元。
光保存位置不夠,調(diào)用現(xiàn)成的API把這個(gè)物品的信息也加到存儲(chǔ)單元中。
最后把這個(gè)存儲(chǔ)單元添加到列表里。
這樣遍歷下來(lái),所有物品的信息都保存起來(lái)了,最后把這個(gè)列表放到參數(shù)中傳來(lái)的存儲(chǔ)單元中。
怎么處理參數(shù)中的那個(gè)存儲(chǔ)單元就不是你的事了。
?
最后是writeToNBT這個(gè)方法的調(diào)用,按照經(jīng)驗(yàn),應(yīng)該會(huì)有一個(gè)回調(diào)方法,由系統(tǒng)在需要保存內(nèi)容空間的內(nèi)容的時(shí)候自動(dòng)調(diào)用。
確實(shí)有。
找得我好苦啊。
重寫(xiě)父類(lèi)的markDirty方法,先調(diào)用一遍父類(lèi)的實(shí)現(xiàn),然后加上
writeToNBT(this.itemStack.stackTagCompound);這里的itemStack指的是使用了這個(gè)內(nèi)容空間的物品,也就是黑貓背包。
在構(gòu)造方法里接收并保存一下就好了。
?
這樣系統(tǒng)就會(huì)自動(dòng)把背包中的所有物品保存到這個(gè)背包實(shí)例中了。
?
但是光保存不行,還得讀取。
于是來(lái)處理readFromNBT。
首先回到構(gòu)造方法里。
第一次打開(kāi)背包的時(shí)候肯定是不會(huì)有已經(jīng)保存了的內(nèi)容物的,this.itemStack.stackTagCompound這個(gè)東西也是不存在的,所以判斷一下,初始化一個(gè)。
if (!itemStack.hasTagCompound()) {itemStack.setTagCompound(new NBTTagCompound());id = UUID.randomUUID().toString(); }再給當(dāng)前內(nèi)容空間一個(gè)id用來(lái)識(shí)別不同的背包。
不作id的區(qū)分的話就變成末影背包了。
?
現(xiàn)在已經(jīng)不會(huì)有空指針的問(wèn)題了,于是不管三七二十一,讀取一下吧。
我這上面用訪問(wèn)器下面直接訪問(wèn)變量效果是一樣的,請(qǐng)不要在意。
首先從物品中保存的存儲(chǔ)單元中拿到當(dāng)前內(nèi)容空間的id。
然后取出在剛才保存了所有物品的列表NBTTagList,這個(gè)方法的第二個(gè)參數(shù)我忘了是干嘛用的了,照抄吧。
接下來(lái)就是遍歷了,拿出一個(gè)存儲(chǔ)單元,找出格子的位置,然后用ItemStack類(lèi)中的方法和存儲(chǔ)單元中保存的信息創(chuàng)建一個(gè)物品棧并設(shè)置到指定的位置上。
就完美地恢復(fù)了之前保存的東西。
?
最后說(shuō)一下三個(gè)常量。
TITLE是內(nèi)容空間的名稱(chēng),貌似會(huì)顯示在界面上。
因?yàn)闉榱朔奖阒髸?huì)直接拿箱子的界面來(lái)用,所以SLOTS_PER_LINE請(qǐng)不要亂動(dòng)。
LINES就是行數(shù)了,我為了平衡給了個(gè)2,箱子貌似是4?給65535應(yīng)該也是可行的。如果你顯示器縱向分辨率有那么高的話……
?
寫(xiě)到這里背包的基本功能就已經(jīng)完成了,后面就要開(kāi)始蛋疼了。
如剛才所說(shuō),我打算直接復(fù)用箱子的界面,但是箱子相關(guān)的兩個(gè)類(lèi)都用了硬編碼,所以沒(méi)辦法用繼承的方式來(lái)創(chuàng)建背包的界面。
用英文說(shuō)就是用了一個(gè)非常蛋疼的workaround。
?
下一篇再說(shuō)。
轉(zhuǎn)載于:https://www.cnblogs.com/chihane/p/4230333.html
總結(jié)
以上是生活随笔為你收集整理的【Forge】Minecraft 1.7.10 Mod开发研究 - 黑猫背包MOD 【06-给你唱一首岁月的歌】的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 开源PCRF、PCRF体验与PCRF实现
- 下一篇: ADB server didn't AC