Forge模組開發(fā)-物品類詳解

引言:
首先要區(qū)分[注冊(cè)物品Items.RED_BED],[物品生成類BlockItem extends Item],[物品堆ItemStack]三種類型,其中:
注冊(cè)物品除了將該類物品堆注冊(cè)引入游戲功能中外,剩下的作用就是用于==對(duì)比,因?yàn)樽?cè)物品是以引用形式儲(chǔ)存在物品堆中的,所以可以直接使用==對(duì)比來判別物品堆是不是指定類型的物品構(gòu)成的。
物品生成類同時(shí)作用于注冊(cè)物品和物品堆的生成與功能,本文主要講的就是該內(nèi)容,故在此不過多贅述。
玩家手持的是物品堆,大部分物品堆的功能來自于你寫的注冊(cè)物品生成類,物品堆就相當(dāng)于方塊中的實(shí)例方塊,是在監(jiān)聽器或者各種功能類代碼段中具體操作的對(duì)象。
?
要解析物品生成類,就應(yīng)當(dāng)從父類Item開始解析,Item同時(shí)實(shí)現(xiàn)了IForgeItem接口,所以可以一并進(jìn)行分析,本文主要分析Item類中,在游戲功能中得到泛用執(zhí)行的方法,也就是在你CustomItem extends Item類中覆寫后能自動(dòng)產(chǎn)生功能、參與游戲的方法。
?
如果提及物品,一般指的是物品堆或堆疊為1的物品堆。
?
Item類
?
構(gòu)造器:public Item(Item.Properties properties)
其中,傳入的Properties 決定了物品的基本屬性,使用new Properties()可以創(chuàng)建一個(gè)新的物品基本屬性對(duì)象,通過形參傳入后可以在構(gòu)造器中初始化物品的屬性:
ItemGroup group?創(chuàng)造物品欄,指定了該物品應(yīng)當(dāng)展示在哪頁(yè)創(chuàng)造物品欄,寫入了Item類的group成員變量;
Rarity rarity?稀有度,一般顯明的影響是在物品名字的顏色上,用作玩家對(duì)物品貴重程度的簡(jiǎn)單區(qū)分,寫入了Item類的rarity成員變量;
Item containerItem?容納該物品的容器,例如水桶的容器就是鐵桶,此值不為空時(shí),在合成以及使用方面會(huì)與其他物品有所不同,寫入了Item類的containerItem成員變量;
maxDamage?物品損傷值,一旦設(shè)定該值,物品堆最大堆疊數(shù)量將不可再被設(shè)置且被鎖定為1,也就是如同工具物品一樣,寫入了Item類的maxDamage成員變量;
int maxStackSize?物品堆最大堆疊數(shù)目,范圍建議1~64,負(fù)數(shù)或0可能會(huì)導(dǎo)致異常,而超過64則會(huì)失去較多模組容器的兼容性,到容器章節(jié)我會(huì)進(jìn)行詳細(xì)說明,寫入了Item類的maxStackSize成員變量中;
Food food?食物屬性對(duì)象,一旦設(shè)置,決定了物品是食物類型,并根據(jù)其內(nèi)部變量執(zhí)行對(duì)應(yīng)功能,例如飽食度、飽和度、食用效果、食用速度等,后續(xù)再進(jìn)行介紹,寫入了Item類的food成員變量;
boolean immuneToFire?對(duì)火免疫,此項(xiàng)屬性在更新下界合金錠后加入,如果為true代表無(wú)法被燒毀,寫入了Item類的isImmuneToFire成員變量;
boolean canRepair?物品是否可修復(fù),無(wú)額外代碼情況下,一般指鐵砧、經(jīng)驗(yàn)修補(bǔ)等常規(guī)手段,其在方法public boolean isRepairable(ItemStack stack)中得到應(yīng)用,當(dāng)物品堆有損傷值且canRepair為true時(shí)返回為true,表示可以執(zhí)行修復(fù)操作,寫入了Item類的canRepair成員變量;
Map<ToolType, Integer> toolClasses?物品工具屬性和對(duì)應(yīng)等級(jí),這是一個(gè)map,表示一個(gè)物品可以同時(shí)是斧、鏟,對(duì)應(yīng)的Integer對(duì)象則是工具挖掘等級(jí),寫入了Item類的toolClasses成員變量中;
Supplier<Callable<ItemStackTileEntityRenderer>> ister此處包裹過多原因是因?yàn)橐话阍谧?cè)時(shí)才能得到對(duì)應(yīng)形參正常引入,所以一般用在物品注冊(cè)類(注意不是注冊(cè)物品,是存放注冊(cè)物品的類例如Items類),這個(gè)屬性一般用不到,但是他的作用之一就是用于內(nèi)置渲染,例如箱子,箱子的外貌并非普通的方塊烘焙模型,箱子方塊實(shí)例其實(shí)渲染了一個(gè)透明模型,真正讓玩家看見的箱子是箱子的方塊實(shí)體渲染出的,這也就導(dǎo)致了一個(gè)問題,箱子物品就不能像其他方塊物品(BlockItem extends Item)一樣繼承對(duì)應(yīng)方塊的模型渲染,而mojang的解決方法是生成了一個(gè)未加入世界的對(duì)應(yīng)方塊的方塊實(shí)體,“附著”在物品上,進(jìn)行“方塊實(shí)體渲染”,這樣玩家就看得到該物品了,此屬性正是用以寫入對(duì)應(yīng)供應(yīng)器,用以給每個(gè)物品堆生成渲染實(shí)例以供物品顯示,至于為什么如此繁瑣,等講至模型渲染在解釋烘焙模型的局限。
方法:
###在講述使用類方法前,先講明使用是指鼠標(biāo)右鍵操作,包括點(diǎn)擊使用和長(zhǎng)按使用兩種,其中點(diǎn)擊使用,如果使用耗費(fèi)時(shí)間為0,那么點(diǎn)擊指使用一次,使用耗費(fèi)時(shí)間大于某個(gè)閾值,將不觸發(fā)點(diǎn)擊使用,長(zhǎng)按使用則將長(zhǎng)按時(shí)間對(duì)使用耗費(fèi)時(shí)間取模,每滿一份算作一次使用,如果使用耗費(fèi)時(shí)間為0,那么將按tick進(jìn)行使用。###
onUse(World worldIn, LivingEntity livingEntityIn, ItemStack stack, int count)
該方法在物品使用完成前每tick都調(diào)用,執(zhí)行一些你想要的功能,worldin是物品堆所在世界(使用實(shí)體),livingentityin是使用者,stack是該物品堆,count是從開始使用多少tick了,此處不建議寫繁重代碼,我的一些可用的建議是,用以渲染使用特效或者粒子效果。
boolean updateItemStackNBT(CompoundNBT nbt)
是否更新物品堆nbt,nbt就是儲(chǔ)存了每個(gè)實(shí)例必要數(shù)據(jù)的對(duì)象,是一種數(shù)據(jù)類,方便物品在 文件-對(duì)象 直接的轉(zhuǎn)換,也方便在網(wǎng)絡(luò)間傳輸,此方法僅頭顱物品使用,用以更新外形,一般傳入nbt的方法,若不傳出,那么傳入的該nbt一般不為空對(duì)象,而是確實(shí)是包含該物品的必要數(shù)據(jù)以供使用、操作。
boolean canPlayerBreakBlockWhileHolding(BlockState state, World worldIn, BlockPos pos, PlayerEntity player)
返回為true時(shí),允許玩家手持該物品時(shí)破壞方塊,返回為false則不允許,例如劍,其中state為目標(biāo)方塊實(shí)例,worldin為對(duì)應(yīng)世界,pos為方塊所在位置,player為手持有該物品的玩家,可用作制作解密物品。
ActionResultType onItemUse(ItemUseContext context)
該方法在物品對(duì)方塊使用完成后調(diào)用,應(yīng)當(dāng)是模組對(duì)工具類物品編寫使用后功能的地方,context包含詳細(xì)信息可獲取使用。
float getDestroySpeed(ItemStack stack, BlockState state)
物品stack破壞方塊state的速度,默認(rèn)為1.0f,工具類覆寫常見,工具類中是依靠Material選擇對(duì)應(yīng)破壞速度,Material影響方塊標(biāo)簽的應(yīng)用,方塊標(biāo)簽決定了方塊是否有工具加速效果。
ActionResult<ItemStack> onItemRightClick(World worldIn, PlayerEntity playerIn, Hand handIn)
與onuse依靠進(jìn)行,也是tick執(zhí)行,決定了物品使用動(dòng)作狀態(tài),一些長(zhǎng)按動(dòng)作需要該方法持續(xù)返回resultConsume才有對(duì)應(yīng)動(dòng)畫效果,resultSuccess則播放執(zhí)行完成動(dòng)畫,其余皆是對(duì)應(yīng)動(dòng)畫,worldin為對(duì)應(yīng)世界,playerin為使用者,handin為持有該物品的玩家的手,一般是先從玩家手中獲取物品堆,執(zhí)行完功能并消耗等操作操作完物品堆后,返回該物品堆構(gòu)造的ActionResult。
ItemStack onItemUseFinish(ItemStack stack, World worldIn, LivingEntity entityLiving)
正常情況下,非工具類物品覆寫該方法實(shí)現(xiàn)使用功能,在stack為完全使用完成前物品堆,你則需要返回使用后物品堆,worldin為當(dāng)前世界,entityliving是使用物品的生物。
boolean isDamageable()
該方法原版兼容覆寫有效,但是你要實(shí)現(xiàn)的功能不應(yīng)該在這實(shí)現(xiàn)。
boolean hitEntity(ItemStack stack, LivingEntity target, LivingEntity attacker)
該物品stack對(duì)實(shí)體target擊打方法,攻擊者為attaker,該方法應(yīng)當(dāng)寫的功能是計(jì)算物品損傷值并應(yīng)用,在保證不出錯(cuò)情況下,可以寫一些武器的額外效果。
boolean onBlockDestroyed(ItemStack stack, World worldIn, BlockState state, BlockPos pos, LivingEntity entityLiving)
該物品stack被entityliving在世界worldin破壞位于pos的方塊state的方法,同樣,forge推薦功能是計(jì)算工具損傷值,我的建議也同上。
boolean canHarvestBlock(BlockState blockIn)
該方法決定了該種物品是否能采集對(duì)應(yīng)方塊blockin,返回true表示可以,false表示不可以,注意,是采集而不是破壞。
ActionResultType itemInteractionForEntity(ItemStack stack, PlayerEntity playerIn, LivingEntity target, Hand hand)
該方法為物品stack右鍵實(shí)體target時(shí)的動(dòng)作,默認(rèn)pass完全不會(huì)有任何反應(yīng),例如剪刀重寫了該方法返回SSUCCES實(shí)現(xiàn)了動(dòng)作反饋,并在其中執(zhí)行了剪下羊毛的功能代碼,playerin是使用者玩家,hand為持有物品的手用以獲取物品,物品應(yīng)用損傷值也應(yīng)當(dāng)在此計(jì)算。
@OnlyIn(Dist.CLIENT)
ITextComponent getName()
該方法返回了物品國(guó)際化名稱,本地顯示用。
String getTranslationKey()
該方法返回了物品國(guó)際化名稱代碼,被上一方法調(diào)用,可以對(duì)應(yīng)更改。
String getTranslationKey(ItemStack stack)
該方法是上一方法進(jìn)階,可以根據(jù)同一物品種類物品堆細(xì)節(jié)差異不同顯示不同名稱,例如藥水。
boolean shouldSyncTag()
是否同步物品數(shù)據(jù)至客戶端,默認(rèn)為true,設(shè)置為false應(yīng)當(dāng)極其小心同步問題。
boolean hasContainerItem()
判斷物品是否有容器物品,在合成時(shí)會(huì)檢測(cè),例如水桶在合成式消耗時(shí)會(huì)保留鐵桶,要注意的是,容器物品getter方法被設(shè)置為了final,最好在初始化時(shí)就設(shè)置物品容器物品,不然反射后果可能會(huì)導(dǎo)致注冊(cè)失常。
inventoryTick(ItemStack stack, World worldIn, Entity entityIn, int itemSlot, boolean isSelected)
物品堆通常是不像方塊一樣每tick檢測(cè)更新數(shù)據(jù)的,有些物品例外例如指南針,需要在背包時(shí)不斷修正指針指向,故該方法覆寫后每tick執(zhí)行可以進(jìn)行一些檢測(cè),例如持有buff。
onCreated(ItemStack stack, World worldIn, PlayerEntity playerIn)
目前僅地圖使用該方法,如果你想在該物品被合成出時(shí)操作一番,可以進(jìn)行覆寫。
boolean isComplex()
目前僅地圖使用,true表明該物品由多部分組成,該方法僅在物品數(shù)據(jù)同步時(shí)調(diào)用,實(shí)際應(yīng)用效果不大。
UseAction getUseAction(ItemStack stack)
該方法返回物品的使用動(dòng)作,前面講的使用動(dòng)作類型對(duì)應(yīng)該動(dòng)作的開始、進(jìn)行、結(jié)束,例如吃東西分拿到嘴邊、上下抖動(dòng)掉渣、物品與手復(fù)位。
int getUseDuration(ItemStack stack)
該方法返回值決定了物品使用耗費(fèi)時(shí)間,單位為tick,例如返回100,那么如果該物品堆是食物,長(zhǎng)按右鍵五秒才能完成一次進(jìn)食。
onPlayerStoppedUsing(ItemStack stack, World worldIn, LivingEntity entityLiving, int timeLeft)
當(dāng)玩家使用物品半路取消,即長(zhǎng)按時(shí)間不足上一個(gè)方法返回的時(shí)間時(shí)調(diào)用,timeleft是還有多少tick就執(zhí)行完使用了(總時(shí)間減已經(jīng)進(jìn)行使用的時(shí)間),例如弓就使用了該方法射出了鍵,在該功能里,剩余時(shí)間被用于計(jì)算蓄力程度。
@OnlyIn(Dist.CLIENT)
addInformation(ItemStack stack, @Nullable World worldIn, List<ITextComponent> tooltip, ITooltipFlag flagIn)
該方法可以在客戶端側(cè)對(duì)物品顯示lore,使用方法為對(duì)tooltip集合操作即可例如:tooltip.add(new TranslationTextComponent("§7這是一條lore。"));
ITextComponent getDisplayName(ItemStack stack)
該方法用以顯示物品堆名,默認(rèn)調(diào)用String getTranslationKey(ItemStack stack)來進(jìn)行構(gòu)造。
boolean hasEffect(ItemStack stack)
如果該方法返回true,那么物品會(huì)被打上附魔光效,不影響附魔臺(tái)附魔,單純光效而已。boolean isEnchantable(ItemStack stack)
該方法返回true,表示物品stack可被附魔,默認(rèn)檢測(cè)物品最大堆疊為1且具有損傷值時(shí)可以附魔,在附魔書和書上有重寫,讓單本書變得可以附魔而不需要具有損傷值。
int getItemEnchantability()
該方法決定了附魔的一些基本屬性,數(shù)值越高,附魔消耗、附魔臺(tái)出高等級(jí)附魔概率等一系列參數(shù)都會(huì)增益化。
fillItemGroup(ItemGroup group, NonNullList<ItemStack> items)
形參的group為創(chuàng)造物品背包頁(yè),items是該頁(yè)對(duì)應(yīng)的物品欄,應(yīng)當(dāng)判斷物品在不在而加不加入,也可以借此將物品的不同損傷值的形態(tài)加入,諸如此類。
boolean getIsRepairable(ItemStack toRepair, ItemStack repair)
是否可以在鐵砧中修復(fù)默認(rèn)為false,應(yīng)當(dāng)根據(jù)具體情況返回true,否則物品不具有損傷值會(huì)讓鐵砧出錯(cuò)。
Multimap<Attribute, AttributeModifier> getAttributeModifiers(EquipmentSlotType equipmentSlot)
此方法決定了物品所處位置提供的屬性,形參為裝備位置,一般包括裝備欄、手,用以進(jìn)行加成,例如一些武器主副手傷害不同。
SoundEvent getDrinkSound()
SoundEvent getEatSound()
飲用、食用動(dòng)作聲音
?
有關(guān)物品注冊(cè)
第一種方法 新建一個(gè)物品注冊(cè)類,其內(nèi)寫一靜態(tài)成員:
public static final DeferredRegister<Item> ITEMS = DeferredRegister.create(ForgeRegistries.ITEMS, "modid");
然后可以使用:
public static final RegistryObject<Item> 物品類型名稱?= ITEMS .register("類型鍵名", 物品生成類::new);
或者
public static final RegistryObject<Item> 物品類型名稱 = ITEMS .register("類型鍵名", () -> new Item(new Item.Properties().group(ModGroup.itemGroup)));
這樣,將屬性等內(nèi)容在這寫,一般用在注冊(cè)方塊物品(BlockItem)。
注冊(cè)幾個(gè)方塊都可以,最后是注冊(cè)這個(gè)注冊(cè)類,在你的模組主類構(gòu)造器中寫
方塊注冊(cè)類.BLOCKS.register(FMLJavaModLoadingContext.get().getModEventBus());即可
第二種方法?也可以監(jiān)聽RegistryEvent.Register<Item>,在這里通過事件獲取物品注冊(cè)器,將你的物品注冊(cè)進(jìn)去。
另外,也可以將方塊注冊(cè)類和物品注冊(cè)類合并使用,這樣可以調(diào)用方塊注冊(cè)器的功能聯(lián)合注冊(cè),將方塊實(shí)體渲染類捆綁至物品的iter,實(shí)現(xiàn)在構(gòu)造器講的內(nèi)容,不過還是建議中規(guī)中矩使用setISTER(() -> BlockItemStackRender::new)將渲染類寫入物品屬性對(duì)象中。
============
到此,有關(guān)物品的覆寫有效方法已經(jīng)解析完畢,有時(shí)間后我會(huì)把可調(diào)用方法解析也補(bǔ)充上去。
下一更新內(nèi)容是對(duì)方塊、物品構(gòu)造器使用的基本屬性對(duì)象以及各種context信息對(duì)象進(jìn)行解析。