欢迎光临散文网 会员登陆 & 注册

Forge模组开发-物品类详解

2023-02-21 16:47 作者:轻描淡写的呵呵  | 我要投稿


引言:


首先要区分[注册物品Items.RED_BED],[物品生成类BlockItem extends Item],[物品堆ItemStack]三种类型,其中:

注册物品除了将该类物品堆注册引入游戏功能中外,剩下的作用就是用于==对比,因为注册物品是以引用形式储存在物品堆中的,所以可以直接使用==对比来判别物品堆是不是指定类型的物品构成的。

物品生成类同时作用于注册物品和物品堆的生成与功能,本文主要讲的就是该内容,故在此不过多赘述。

玩家手持的是物品堆,大部分物品堆的功能来自于你写的注册物品生成类,物品堆就相当于方块中的实例方块,是在监听器或者各种功能类代码段中具体操作的对象。

 

要解析物品生成类,就应当从父类Item开始解析,Item同时实现了IForgeItem接口,所以可以一并进行分析,本文主要分析Item类中,在游戏功能中得到泛用执行的方法,也就是在你CustomItem extends Item类中覆写后能自动产生功能、参与游戏的方法。

 

如果提及物品,一般指的是物品堆或堆叠为1的物品堆。

 

Item类

 

构造器:public Item(Item.Properties properties)

其中,传入的Properties 决定了物品的基本属性,使用new Properties()可以创建一个新的物品基本属性对象,通过形参传入后可以在构造器中初始化物品的属性:

ItemGroup group 创造物品栏,指定了该物品应当展示在哪页创造物品栏,写入了Item类的group成员变量;

Rarity rarity 稀有度,一般显明的影响是在物品名字的颜色上,用作玩家对物品贵重程度的简单区分,写入了Item类的rarity成员变量;

Item containerItem 容纳该物品的容器,例如水桶的容器就是铁桶,此值不为空时,在合成以及使用方面会与其他物品有所不同,写入了Item类的containerItem成员变量;

maxDamage 物品损伤值,一旦设定该值,物品堆最大堆叠数量将不可再被设置且被锁定为1,也就是如同工具物品一样,写入了Item类的maxDamage成员变量;

int maxStackSize 物品堆最大堆叠数目,范围建议1~64,负数或0可能会导致异常,而超过64则会失去较多模组容器的兼容性,到容器章节我会进行详细说明,写入了Item类的maxStackSize成员变量中;

Food food 食物属性对象,一旦设置,决定了物品是食物类型,并根据其内部变量执行对应功能,例如饱食度、饱和度、食用效果、食用速度等,后续再进行介绍,写入了Item类的food成员变量;

boolean immuneToFire 对火免疫,此项属性在更新下界合金锭后加入,如果为true代表无法被烧毁,写入了Item类的isImmuneToFire成员变量;

boolean canRepair 物品是否可修复,无额外代码情况下,一般指铁砧、经验修补等常规手段,其在方法public boolean isRepairable(ItemStack stack)中得到应用,当物品堆有损伤值且canRepair为true时返回为true,表示可以执行修复操作,写入了Item类的canRepair成员变量;

Map<ToolType, Integer> toolClasses 物品工具属性和对应等级,这是一个map,表示一个物品可以同时是斧、铲,对应的Integer对象则是工具挖掘等级,写入了Item类的toolClasses成员变量中;

Supplier<Callable<ItemStackTileEntityRenderer>> ister此处包裹过多原因是因为一般在注册时才能得到对应形参正常引入,所以一般用在物品注册类(注意不是注册物品,是存放注册物品的类例如Items类),这个属性一般用不到,但是他的作用之一就是用于内置渲染,例如箱子,箱子的外貌并非普通的方块烘焙模型,箱子方块实例其实渲染了一个透明模型,真正让玩家看见的箱子是箱子的方块实体渲染出的,这也就导致了一个问题,箱子物品就不能像其他方块物品(BlockItem extends Item)一样继承对应方块的模型渲染,而mojang的解决方法是生成了一个未加入世界的对应方块的方块实体,“附着”在物品上,进行“方块实体渲染”,这样玩家就看得到该物品了,此属性正是用以写入对应供应器,用以给每个物品堆生成渲染实例以供物品显示,至于为什么如此繁琐,等讲至模型渲染在解释烘焙模型的局限。


方法:


###在讲述使用类方法前,先讲明使用是指鼠标右键操作,包括点击使用和长按使用两种,其中点击使用,如果使用耗费时间为0,那么点击指使用一次,使用耗费时间大于某个阈值,将不触发点击使用,长按使用则将长按时间对使用耗费时间取模,每满一份算作一次使用,如果使用耗费时间为0,那么将按tick进行使用。###


onUse(World worldIn, LivingEntity livingEntityIn, ItemStack stack, int count)

该方法在物品使用完成前每tick都调用,执行一些你想要的功能,worldin是物品堆所在世界(使用实体),livingentityin是使用者,stack是该物品堆,count是从开始使用多少tick了,此处不建议写繁重代码,我的一些可用的建议是,用以渲染使用特效或者粒子效果。

boolean updateItemStackNBT(CompoundNBT nbt)

是否更新物品堆nbt,nbt就是储存了每个实例必要数据的对象,是一种数据类,方便物品在 文件-对象 直接的转换,也方便在网络间传输,此方法仅头颅物品使用,用以更新外形,一般传入nbt的方法,若不传出,那么传入的该nbt一般不为空对象,而是确实是包含该物品的必要数据以供使用、操作。

boolean canPlayerBreakBlockWhileHolding(BlockState state, World worldIn, BlockPos pos, PlayerEntity player)

返回为true时,允许玩家手持该物品时破坏方块,返回为false则不允许,例如剑,其中state为目标方块实例,worldin为对应世界,pos为方块所在位置,player为手持有该物品的玩家,可用作制作解密物品。

ActionResultType onItemUse(ItemUseContext context)

该方法在物品对方块使用完成后调用,应当是模组对工具类物品编写使用后功能的地方,context包含详细信息可获取使用。

float getDestroySpeed(ItemStack stack, BlockState state)

物品stack破坏方块state的速度,默认为1.0f,工具类覆写常见,工具类中是依靠Material选择对应破坏速度,Material影响方块标签的应用,方块标签决定了方块是否有工具加速效果。

ActionResult<ItemStack> onItemRightClick(World worldIn, PlayerEntity playerIn, Hand handIn)

与onuse依靠进行,也是tick执行,决定了物品使用动作状态,一些长按动作需要该方法持续返回resultConsume才有对应动画效果,resultSuccess则播放执行完成动画,其余皆是对应动画,worldin为对应世界,playerin为使用者,handin为持有该物品的玩家的手,一般是先从玩家手中获取物品堆,执行完功能并消耗等操作操作完物品堆后,返回该物品堆构造的ActionResult。

ItemStack onItemUseFinish(ItemStack stack, World worldIn, LivingEntity entityLiving)

正常情况下,非工具类物品覆写该方法实现使用功能,在stack为完全使用完成前物品堆,你则需要返回使用后物品堆,worldin为当前世界,entityliving是使用物品的生物。

boolean isDamageable()

该方法原版兼容覆写有效,但是你要实现的功能不应该在这实现。

boolean hitEntity(ItemStack stack, LivingEntity target, LivingEntity attacker)

该物品stack对实体target击打方法,攻击者为attaker,该方法应当写的功能是计算物品损伤值并应用,在保证不出错情况下,可以写一些武器的额外效果。

boolean onBlockDestroyed(ItemStack stack, World worldIn, BlockState state, BlockPos pos, LivingEntity entityLiving)

该物品stack被entityliving在世界worldin破坏位于pos的方块state的方法,同样,forge推荐功能是计算工具损伤值,我的建议也同上。

boolean canHarvestBlock(BlockState blockIn)

该方法决定了该种物品是否能采集对应方块blockin,返回true表示可以,false表示不可以,注意,是采集而不是破坏。

ActionResultType itemInteractionForEntity(ItemStack stack, PlayerEntity playerIn, LivingEntity target, Hand hand)

该方法为物品stack右键实体target时的动作,默认pass完全不会有任何反应,例如剪刀重写了该方法返回SSUCCES实现了动作反馈,并在其中执行了剪下羊毛的功能代码,playerin是使用者玩家,hand为持有物品的手用以获取物品,物品应用损伤值也应当在此计算。

@OnlyIn(Dist.CLIENT)

ITextComponent getName()

该方法返回了物品国际化名称,本地显示用。

String getTranslationKey()

该方法返回了物品国际化名称代码,被上一方法调用,可以对应更改。

String getTranslationKey(ItemStack stack)

该方法是上一方法进阶,可以根据同一物品种类物品堆细节差异不同显示不同名称,例如药水。

boolean shouldSyncTag()

是否同步物品数据至客户端,默认为true,设置为false应当极其小心同步问题。

boolean hasContainerItem()

判断物品是否有容器物品,在合成时会检测,例如水桶在合成式消耗时会保留铁桶,要注意的是,容器物品getter方法被设置为了final,最好在初始化时就设置物品容器物品,不然反射后果可能会导致注册失常。

inventoryTick(ItemStack stack, World worldIn, Entity entityIn, int itemSlot, boolean isSelected)

物品堆通常是不像方块一样每tick检测更新数据的,有些物品例外例如指南针,需要在背包时不断修正指针指向,故该方法覆写后每tick执行可以进行一些检测,例如持有buff。

onCreated(ItemStack stack, World worldIn, PlayerEntity playerIn)

目前仅地图使用该方法,如果你想在该物品被合成出时操作一番,可以进行覆写。

boolean isComplex()

目前仅地图使用,true表明该物品由多部分组成,该方法仅在物品数据同步时调用,实际应用效果不大。

UseAction getUseAction(ItemStack stack)

该方法返回物品的使用动作,前面讲的使用动作类型对应该动作的开始、进行、结束,例如吃东西分拿到嘴边、上下抖动掉渣、物品与手复位。

int getUseDuration(ItemStack stack)

该方法返回值决定了物品使用耗费时间,单位为tick,例如返回100,那么如果该物品堆是食物,长按右键五秒才能完成一次进食。

onPlayerStoppedUsing(ItemStack stack, World worldIn, LivingEntity entityLiving, int timeLeft)

当玩家使用物品半路取消,即长按时间不足上一个方法返回的时间时调用,timeleft是还有多少tick就执行完使用了(总时间减已经进行使用的时间),例如弓就使用了该方法射出了键,在该功能里,剩余时间被用于计算蓄力程度。

@OnlyIn(Dist.CLIENT)

addInformation(ItemStack stack, @Nullable World worldIn, List<ITextComponent> tooltip, ITooltipFlag flagIn)

该方法可以在客户端侧对物品显示lore,使用方法为对tooltip集合操作即可例如:tooltip.add(new TranslationTextComponent("§7这是一条lore。"));

ITextComponent getDisplayName(ItemStack stack)

该方法用以显示物品堆名,默认调用String getTranslationKey(ItemStack stack)来进行构造。

boolean hasEffect(ItemStack stack)

如果该方法返回true,那么物品会被打上附魔光效,不影响附魔台附魔,单纯光效而已。boolean isEnchantable(ItemStack stack)

该方法返回true,表示物品stack可被附魔,默认检测物品最大堆叠为1且具有损伤值时可以附魔,在附魔书和书上有重写,让单本书变得可以附魔而不需要具有损伤值。

int getItemEnchantability()

该方法决定了附魔的一些基本属性,数值越高,附魔消耗、附魔台出高等级附魔概率等一系列参数都会增益化。

fillItemGroup(ItemGroup group, NonNullList<ItemStack> items)

形参的group为创造物品背包页,items是该页对应的物品栏,应当判断物品在不在而加不加入,也可以借此将物品的不同损伤值的形态加入,诸如此类。

boolean getIsRepairable(ItemStack toRepair, ItemStack repair)

是否可以在铁砧中修复默认为false,应当根据具体情况返回true,否则物品不具有损伤值会让铁砧出错。

Multimap<Attribute, AttributeModifier> getAttributeModifiers(EquipmentSlotType equipmentSlot)

此方法决定了物品所处位置提供的属性,形参为装备位置,一般包括装备栏、手,用以进行加成,例如一些武器主副手伤害不同。

SoundEvent getDrinkSound()

SoundEvent getEatSound()

饮用、食用动作声音

 

有关物品注册


第一种方法 新建一个物品注册类,其内写一静态成员:

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)));

这样,将属性等内容在这写,一般用在注册方块物品(BlockItem)。

注册几个方块都可以,最后是注册这个注册类,在你的模组主类构造器中写

方块注册类.BLOCKS.register(FMLJavaModLoadingContext.get().getModEventBus());即可

第二种方法 也可以监听RegistryEvent.Register<Item>,在这里通过事件获取物品注册器,将你的物品注册进去。

另外,也可以将方块注册类和物品注册类合并使用,这样可以调用方块注册器的功能联合注册,将方块实体渲染类捆绑至物品的iter,实现在构造器讲的内容,不过还是建议中规中矩使用setISTER(() -> BlockItemStackRender::new)将渲染类写入物品属性对象中。

============

到此,有关物品的覆写有效方法已经解析完毕,有时间后我会把可调用方法解析也补充上去。

下一更新内容是对方块、物品构造器使用的基本属性对象以及各种context信息对象进行解析。


Forge模组开发-物品类详解的评论 (共 条)

分享到微博请遵守国家法律