【Forge】Minecraft 1.7.10 Mod开发研究 - 黑猫背包MOD 【06-给你唱一首岁月的歌】
老實說我已經忘了這個mod是怎么寫出來的了。
所以下面的代碼不能運行是非常正常的。
?
上回書說到,我們處理了玩家拿著背包右鍵時觸發的事件,發送了一條打開背包窗口的命令,但是背包窗口還沒有寫,這回就來解決這個問題。
這次因為嵌套關系太多,所以我按執行順序反過來說。
那么先不管上次沒有打開的那個GUI。
?
MC中的每一個能放進物品的容器,不管是箱子、熔爐還是釀造臺,各自都持有一個自己的內容空間(Inventory)實例,在這個內容空間中各自保存自己的內容物。
內容空間的基類是InventoryBasic,實現了IInventory接口,為了方便,咱直接繼承InventoryBasic類。
InventoryBasic類已經實現了大部分內容空間需要的功能,可以粗讀一下代碼,挺好懂的。
于是我們黑貓背包的內容空間類只需要處理內容物的保存和讀取。
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 } 先扔代碼自己寫兩個方法,名字可以隨便起,我這里一個叫writeToNBT,用于保存內容物,一個叫readFromNBT,用于讀取內容物。
保存和讀取用到的是NBT機制,NBT全稱是什么我已經忘了。
先說保存。
首先創建一個NBT的列表NBTTagList,用于保存各個物品和它們的位置。這個類可以簡單理解為一個列表。
然后遍歷所有內容空間中的格子,只要發現格子中有物品,就把當前的格子位置保存在一個NBTTagCompound中,這個類理解為一個存儲單元。
光保存位置不夠,調用現成的API把這個物品的信息也加到存儲單元中。
最后把這個存儲單元添加到列表里。
這樣遍歷下來,所有物品的信息都保存起來了,最后把這個列表放到參數中傳來的存儲單元中。
怎么處理參數中的那個存儲單元就不是你的事了。
?
最后是writeToNBT這個方法的調用,按照經驗,應該會有一個回調方法,由系統在需要保存內容空間的內容的時候自動調用。
確實有。
找得我好苦啊。
重寫父類的markDirty方法,先調用一遍父類的實現,然后加上
writeToNBT(this.itemStack.stackTagCompound);這里的itemStack指的是使用了這個內容空間的物品,也就是黑貓背包。
在構造方法里接收并保存一下就好了。
?
這樣系統就會自動把背包中的所有物品保存到這個背包實例中了。
?
但是光保存不行,還得讀取。
于是來處理readFromNBT。
首先回到構造方法里。
第一次打開背包的時候肯定是不會有已經保存了的內容物的,this.itemStack.stackTagCompound這個東西也是不存在的,所以判斷一下,初始化一個。
if (!itemStack.hasTagCompound()) {itemStack.setTagCompound(new NBTTagCompound());id = UUID.randomUUID().toString(); }再給當前內容空間一個id用來識別不同的背包。
不作id的區分的話就變成末影背包了。
?
現在已經不會有空指針的問題了,于是不管三七二十一,讀取一下吧。
我這上面用訪問器下面直接訪問變量效果是一樣的,請不要在意。
首先從物品中保存的存儲單元中拿到當前內容空間的id。
然后取出在剛才保存了所有物品的列表NBTTagList,這個方法的第二個參數我忘了是干嘛用的了,照抄吧。
接下來就是遍歷了,拿出一個存儲單元,找出格子的位置,然后用ItemStack類中的方法和存儲單元中保存的信息創建一個物品棧并設置到指定的位置上。
就完美地恢復了之前保存的東西。
?
最后說一下三個常量。
TITLE是內容空間的名稱,貌似會顯示在界面上。
因為為了方便之后會直接拿箱子的界面來用,所以SLOTS_PER_LINE請不要亂動。
LINES就是行數了,我為了平衡給了個2,箱子貌似是4?給65535應該也是可行的。如果你顯示器縱向分辨率有那么高的話……
?
寫到這里背包的基本功能就已經完成了,后面就要開始蛋疼了。
如剛才所說,我打算直接復用箱子的界面,但是箱子相關的兩個類都用了硬編碼,所以沒辦法用繼承的方式來創建背包的界面。
用英文說就是用了一個非常蛋疼的workaround。
?
下一篇再說。
轉載于:https://www.cnblogs.com/chihane/p/4230333.html
總結
以上是生活随笔為你收集整理的【Forge】Minecraft 1.7.10 Mod开发研究 - 黑猫背包MOD 【06-给你唱一首岁月的歌】的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 开源PCRF、PCRF体验与PCRF实现
- 下一篇: HTML基本操作