用户:MashKJo/1.12.2模组开发教程/11.高级物品和方块 - 前置概念

MashKJo留言 | 贡献2024年12月25日 (三) 00:42的版本 →‎ActionResult<T>:​ // Edit via Wikiplus

首先,笔者想对能看到这里的读者,道一声恭喜!因为能学到这里,读者应该已经掌握了创建一个新物品或新方块的基本的标准化流程,且已经熟悉了相关的重要概念(如ItemStack和NBT格式的运用),这已经超越了许多新手modder了。不过应该也有读者存有疑问:之前学习的东西,充其量只能搞出一些没有任何额外行为和高级功能的,仅能被当作合成材料或建材使用的物品/方块,那么那些知名模组中的看起来很高级的物品/方块,都是怎么做出来的呢?

很简单,如果我们排除掉使用TileEntity的方块,那么剩下的那些高级的物品/方块,几乎都是通过覆写Item类或Block类下的若干方法实现的,这些方法有的是Minecraft原生支持的,还有一些是Forge塞进去的。你可能会看到Minecraft有些原生支持的方法被@Deprecated了,那可能是因为Forge觉得这个方法提供的形参不够多,对于对应功能的控制还不够精细,因此patch了一个更为强大的同功能重载方法。另外,如果你实在找不到可以覆写的方法,那么可以考虑监听一些事件。

然而,覆写这些方法通常涉及到一些很重要也比较复杂的类,这些类比较琐碎,应用也非常广泛,如果真的按照“讲到了对应的专题再详细讲”这个原则安排内容,会导致一系列问题——例如,World类是一个非常重要的类,用到的地方超级多,但是读者想必也不希望掌握如何创建一个新维度后,再回来写高级的物品/方块吧?因此这一节就专门讲这些琐碎的类以及它们涉及到的一些重要概念。

一些枚举类

在给我们的高级的物品/方块实现一些功能时,我们会和很多枚举类打交道,如:

  • EnumAction:这个枚举类专用于物品,具体地说,是表示物品被使用时,产生的动画效果的“类型”(说是动画效果,实际上就是一层薄薄的贴图转了个角度后的一堆平移、伸缩或旋转变换而已),由Item#getItemUseAction决定。原版有5种EnumAction,分别是:NONE、EAT、DRINK、BLOCK、BOW。很显然,后四者分别用于食物、水瓶和药水、方块的物品形式、弓。那么可能会有读者问了:如果我想自定义物品使用时的动画效果,怎么办,如何去做到?答案是通常情况下做不到,除非你用黑魔法。一般而言,新的EnumAction可以通过Forge提供的EnumHelper来通过反射生成,但是Minecraft具体处理这个EnumAction并实际产生动画的代码中,Forge实际上没有发布任何事件,所以理论上我们无法新增自定义的物品使用动画,除非你用Mixin大法,但除非你Modding水平够高,否则执意在Forge框架下开发时用Mixin实现自己的需求,还不如自己换个需求。
  • EnumActionResult:这个枚举类有3个实例:SUCCESS、PASS和FAIL,它用于描述某个交互逻辑进行后,返回的结果(或者说执行结果)。其实它的意义不是那么大,因为它也就只是一个返回值而已,你可以在写一堆你自己的自定义逻辑后返回FAIL,本质上就是一个标记而已。不过对于物品的使用而言,SUCCESS和FAIL都不会在执行完主手上的物品的相关逻辑后,继续执行副手上对应物品的相关逻辑,而PASS则会,这个特性需要小小地注意一下。
  • EnumBlockRenderType:顾名思义,这个枚举类用于描述方块的渲染类型——INVISIBLE、LIQUID、ENTITYBLOCK_ANIMATED、MODEL。
    • MODEL:默认值,就是最普通的渲染类型——从指定的模型文件中读取出一个模型(实际上是通过一个ICustomModelLoader得到了一个IModel),并经历一系列加工过程,最后渲染出来。
    • INVISIBLE:顾名思义,就是代表该方块什么都不渲染,如空气方块,如果你的模组中有一些方块纯粹是用于技术性用途,那可以设定成INVISIBLE这个渲染类型,再附加一个setHardness(-1.0F)即可。
    • LIQUID:用于流体方块的渲染,代表例子是原版的水方块。
    • ENTITYBLOCK_ANIMATED:这个渲染类型很特殊,它单独起到的效果和INVISIBLE其实是大差不差的,只是它用于标记——该方块有TileEntity[1],且该方块的渲染全部由该TileEntity对应的一些相对接近于底层(实际上是lwjgl的OpenGL)的渲染代码来完成,包装成的东西名为TileEntitySpecialRenderer,一般简称TESR,TESR能帮我们实现很多单纯的模型文件做不到的效果,如:在方块表面渲染文字、动态贴图甚至实现动画效果。但是注意:用了TESR的方块实体,对应的方块的渲染类型,一般也还是MODEL。为何?因为这代表先让Minecraft默认的渲染机制为我们渲染好方块的大致轮廓和基础材质,再用TESR作补充;然而如果用了ENTITYBLOCK_ANIMATED,代表:方块的基础轮廓也是要我们手动去渲染的,典型的例子是原版的箱子。当它开启时,它的顶部的全部材质和四个侧面的一部分材质都会抬升并旋转一个角度——由于四个侧面都仅仅有一部分材质会参与这个过程,因此Minecraft的默认渲染机制确实不能胜任,所以才有必要用这个渲染类型。所以记住——除非你有特殊的需求,否则就算你用TESR渲染TileEntity,你也该用MODEL作为渲染类型而非ENTITYBLOCK_ANIMATED。有关TileEntity和TESR的内容,将会在后面讲到,这里先做了解即可。
  • BlockRenderLayer:这个枚举类同样应用于方块,只是它用于指定方块的材质的特性。它有4个实例:SOLID、TRANSLUCENT、CUTOUT、CUTOUT_MIPPED。SOLID代表方块的材质完全不透明,TRANSLUCENT则代表半透明,CUTOUT则是材质中有一部分全透明而另外一部分完全不透明,至于CUTOUT_MIPPED,它是CUTOUT的抗锯齿版本,和CUTOUT实际上差别不是很大。
  • EnumFacing:这是一个表示方向的枚举类,可以表示东、南、西、北、上、下六个方向,前面已经提过,此处不再赘述。
  • EnumHand和EnumHandSide:二者都用于表示主手和副手,不知道Mojang出于怎样的考量写出了这两个定位几乎一样的枚举类,反正用的时候也没区别,注意一下到底是哪个类型就行。
  • EntityEquipmentSlot:用于描述一个有物品栏的生物的物品栏槽位种类,总共有6种:主手、副手、头部、胸部、腿部、脚部。

以上就是一些常用的枚举类,多亏了MCP,它们的类名和实例名都很容易让人顾名思义,用起来也比较简单,这里就不多说了。

一些向量类

Minecraft在net.minecraft.util.math包下提供了三个向量类:Vec2f、Vec3f和Vec3d。实际上读者应该能很清楚地看出来,数字代表空间维度数,第一个是平面向量,后两个是空间向量;而字母代表坐标精度,f代表float,d代表double。一般而言,我们用的都是Vec3d。

合理运用向量类能给不少问题中的数学运算带来极大的便利,如Vec3d下就有很多简化计算过程的好用方法,读者可以去自行察看。

实际上,虽然这三个类被MCP取名为向量(Vector),然而它果真只能代表平面中或空间中一个向量或坐标吗?显然不是。它们本质上,其实是对有序数对或三维有序数组的简单封装而已。所以理论上它们也可以用来表示除向量和坐标之外的其他东西。比如,Vec3d也被经常用来表示维度的天空和虚空迷雾的颜色——在这里,Vec3d构造方法中传入的3个数值,其实就是相当于该颜色的R、G、B三个通道的各自的值。

ActionResult<T>

这是对EnumActionResult的一个扩展——有时候,Minecraft处理游戏逻辑时,在获取对某个对象的处理的结果时,不仅想知道处理是否成功(SUCCESS、PASS、FAIL这些结果),还想知道该对象的最终值,这个时候就需要用到这个类了,该类的构造很简单,就是(EnumFacing typeIn, T value)。实际上我们一般能见到的是ActionResult<ItemStack>。

AxisAlignedBB

BlockPos

DamageSource

EntityPlayer

I18n和ITextComponent

MinecraftServer

RayTraceResult

World

  1. 没错,EntityBlock指的其实就是TileEntity,实际上高版本它也叫BlockEntity,意思其实都一样,翻译成中文都是方块实体。