3,417
个编辑
MCBBS Wiki欢迎您共同参与编辑!在参与编辑之前请先阅读Wiki方针。
如果在编辑的过程中遇到了什么问题,可以去讨论板提问。
为了您能够无阻碍地参与编辑 未验证/绑定过邮箱的用户,请尽快绑定/验证。
MCBBS Wiki GitHub群组已上线!
您可以在回声洞中发表吐槽!
服务器状态监控。点击进入
本站由MCBBS用户自行搭建,与MCBBS及东银河系漫游指南(北京)科技有限公司没有从属关系。点此了解 MCBBS Wiki 不是什么>>
(// Edit via Wikiplus) |
(// Edit via Wikiplus) |
||
| (未显示同一用户的11个中间版本) | |||
| 第3行: | 第3行: | ||
很简单,如果我们排除掉使用TileEntity的方块,那么剩下的那些高级的物品/方块,几乎都是通过覆写Item类或Block类下的若干方法实现的,这些方法有的是Minecraft原生支持的,还有一些是Forge塞进去的。你可能会看到Minecraft有些原生支持的方法被@Deprecated了,那可能是因为Forge觉得这个方法提供的形参不够多,对于对应功能的控制还不够精细,因此patch了一个更为强大的同功能重载方法。另外,如果你实在找不到可以覆写的方法,那么可以考虑监听一些事件。 | 很简单,如果我们排除掉使用TileEntity的方块,那么剩下的那些高级的物品/方块,几乎都是通过覆写Item类或Block类下的若干方法实现的,这些方法有的是Minecraft原生支持的,还有一些是Forge塞进去的。你可能会看到Minecraft有些原生支持的方法被@Deprecated了,那可能是因为Forge觉得这个方法提供的形参不够多,对于对应功能的控制还不够精细,因此patch了一个更为强大的同功能重载方法。另外,如果你实在找不到可以覆写的方法,那么可以考虑监听一些事件。 | ||
想必读者也看到了,覆写这些方法通常涉及到一些很重要也比较复杂的类,这些类比较琐碎,应用也非常广泛,如果真的按照“讲到了对应的专题再详细讲”这个原则安排内容,会导致一系列问题——例如,World类是一个非常重要的类,用到的地方超级多,但是读者想必也不希望掌握如何创建一个新维度后,再回来写高级的物品/方块吧?因此这一节就专门讲这些琐碎的类以及它们涉及到的一些重要概念。 | |||
== 一些枚举类 == | == 一些枚举类 == | ||
在给我们的高级的物品/方块实现一些功能时,我们会和很多枚举类打交道,如: | 在给我们的高级的物品/方块实现一些功能时,我们会和很多枚举类打交道,如: | ||
* EnumAction:这个枚举类专用于物品,具体地说,是表示物品被使用时,产生的动画效果的“类型”(说是动画效果,实际上就是一层薄薄的贴图转了个角度后的一堆平移、伸缩或旋转变换而已),由<code>Item#getItemUseAction</code>决定。原版有5种EnumAction,分别是:NONE、EAT、DRINK、BLOCK、BOW。很显然,后四者分别用于食物、水瓶和药水、方块的物品形式、弓。那么可能会有读者问了:如果我想自定义物品使用时的动画效果,怎么办,如何去做到?答案是通常情况下做不到,除非你用黑魔法。一般而言,新的EnumAction可以通过Forge提供的EnumHelper来通过反射生成,但是Minecraft具体处理这个EnumAction并实际产生动画的代码中,Forge实际上没有发布任何事件,所以理论上我们无法新增自定义的物品使用动画,除非你用Mixin大法,但除非你Modding水平够高,否则执意在Forge框架下开发时用Mixin实现自己的需求,还不如自己换个需求。 | * EnumAction:这个枚举类专用于物品,具体地说,是表示物品被使用时,产生的动画效果的“类型”(说是动画效果,实际上就是一层薄薄的贴图转了个角度后的一堆平移、伸缩或旋转变换而已),由<code>Item#getItemUseAction</code>决定。原版有5种EnumAction,分别是:NONE、EAT、DRINK、BLOCK、BOW。很显然,后四者分别用于食物、水瓶和药水、方块的物品形式、弓。那么可能会有读者问了:如果我想自定义物品使用时的动画效果,怎么办,如何去做到?答案是通常情况下做不到,除非你用黑魔法。一般而言,新的EnumAction可以通过Forge提供的EnumHelper来通过反射生成,但是Minecraft具体处理这个EnumAction并实际产生动画的代码中,Forge实际上没有发布任何事件,所以理论上我们无法新增自定义的物品使用动画,除非你用Mixin大法,但除非你Modding水平够高,否则执意在Forge框架下开发时用Mixin实现自己的需求,还不如自己换个需求。 | ||
* | * EnumActionResult:这个枚举类有3个实例:SUCCESS、PASS和FAIL,它用于描述某个交互逻辑进行后,返回的结果(或者说执行结果)。其实它的意义不是那么大,因为它也就只是一个返回值而已,你可以在写一堆你自己的自定义逻辑后返回FAIL,本质上就是一个标记而已。3个返回值没有固定的含义,读者在使用前请先查看相关的代码。 | ||
* EnumBlockRenderType:顾名思义,这个枚举类用于描述方块的渲染类型——INVISIBLE、LIQUID、ENTITYBLOCK_ANIMATED、MODEL。 | * EnumBlockRenderType:顾名思义,这个枚举类用于描述方块的渲染类型——INVISIBLE、LIQUID、ENTITYBLOCK_ANIMATED、MODEL。 | ||
** MODEL:默认值,就是最普通的渲染类型——从指定的模型文件中读取出一个模型(实际上是通过一个ICustomModelLoader得到了一个IModel),并经历一系列加工过程,最后渲染出来。 | ** MODEL:默认值,就是最普通的渲染类型——从指定的模型文件中读取出一个模型(实际上是通过一个ICustomModelLoader得到了一个IModel),并经历一系列加工过程,最后渲染出来。 | ||
| 第21行: | 第21行: | ||
== 一些向量类 == | == 一些向量类 == | ||
Minecraft在<code>net.minecraft.util.math</code> | Minecraft在<code>net.minecraft.util.math</code>包下提供了三个向量类:Vec2f、Vec3i和Vec3d。实际上读者应该能很清楚地看出来,数字代表空间维度数,第一个是平面向量,后两个是空间向量;而字母代表坐标精度,i代表int,f代表float,d代表double。一般而言,我们用的都是Vec3d。 | ||
合理运用向量类能给不少问题中的数学运算带来极大的便利,如Vec3d下就有很多简化计算过程的好用方法,读者可以去自行察看。 | 合理运用向量类能给不少问题中的数学运算带来极大的便利,如Vec3d下就有很多简化计算过程的好用方法,读者可以去自行察看。 | ||
| 第28行: | 第28行: | ||
== ActionResult<T> == | == ActionResult<T> == | ||
这是对EnumActionResult的一个扩展——有时候,Minecraft处理游戏逻辑时,在获取对某个对象的处理的结果时,不仅想知道处理是否成功(SUCCESS、PASS、FAIL这些结果),还想知道该对象的最终值,这个时候就需要用到这个类了,该类的构造很简单,就是<code>( | 这是对EnumActionResult的一个扩展——有时候,Minecraft处理游戏逻辑时,在获取对某个对象的处理的结果时,不仅想知道处理是否成功(SUCCESS、PASS、FAIL这些结果),还想知道该对象的最终值,这个时候就需要用到这个类了,该类的构造很简单,就是<code>(EnumActionResult typeIn, T value)</code>。实际上我们一般能见到的是ActionResult<ItemStack>。 | ||
== AxisAlignedBB == | == AxisAlignedBB == | ||
| 第46行: | 第46行: | ||
== I18n和ITextComponent == | == I18n和ITextComponent == | ||
在模组开发中,我们时常会遇到这样一种需求:给某个玩家发送聊天栏信息,很简单,用<code>EntityPlayer#sendMessage</code>即可(注意不是sendStatusMessage),我们注意到这个方法接受一个ITextComponent,实际上出于本地化的需求与考虑,我们用的最多的该接口的实现是TextComponentTranslation。这个类的构造方法接受一个String——实际上就是用于充当该消息内容的本地化键名。我们在发送消息时,应该先判断逻辑端,否则消息会发送两次——由于我们处理逻辑一般是在逻辑服务端,因此发送消息一般也在这一端执行。 | |||
如果我们在发送消息之外的场景中,还有本地化的需求怎么办?答案是使用<code>net.minecraft.client.resources.I18n#format</code>,该方法返回一个本地化之后的String量,用法和TextComponentTranslation基本一样,但从该类的包名即可看出——该类只在物理客户端有意义,使用它时要尤其注意这一点。 | |||
另外,你或许也注意到了,无论是TextComponentTranslation的构造方法还是<code>I18n#format</code>,它都还可以接受一个Object变长参数,这实际上是为了满足一个需求:需要在本地化文本中插入动态的内容,具体用法类似于C语言中的printf函数,如字符串的占位符是<code>%s</code>。 | |||
== RayTraceResult == | == RayTraceResult == | ||
RayTrace,意思为“光线追踪”,如该词语的含义所言,RayTrace在Minecraft中的含义,即为“计算生物实体的视线,确定其视线选中的到底是一个实体,还是一个非空气方块,亦或者就是空气(即等价于什么都没选中)”。玩家在游戏中在准星指向的位置放置方块时,就会有RayTrace的过程。描述RayTrace结果的类型便是RayTraceResult。从一个RayTraceResult中,你可以拿到很多相关的有用信息。 | |||
World类下有与RayTrace相关的一些方法,我们需要的时候可以直接拿来用。 | |||
另外,实体的碰撞结果也是用RayTraceResult来描述的(最常见的例子就是实体投掷物砸中某个方块或实体)。 | |||
== World == | == World == | ||
其实在笔者看来,World类是个设计得比较奇怪的类,从字面意思上看,它就是代表着某个维度——这么理解的确是对的。然而,World类可不仅承载了维度这一概念,甚至还包括了存档这一概念——World中相关信息的保存路径、世界生成时选择的设置(如是否有奖励箱生成),甚至“是否开启了极限模式”这种全局通用设置,你都能从一个World对象中获取。Mojang显然是把“维度”和“存档”这两个概念揉到了一个类中——即World类。 | |||
World类的设计极为复杂,相关的方法、用途也很多,这里只做简要说明。很多其他的东西,会在将来讲到添加新维度时,一并说明的。 | |||
=== 判断当前逻辑端 === | |||
没错,我们终于说到了,判断当前所处的逻辑端的方法——检查非静态字段isRemote的值——是true,则代表当前为逻辑客户端,否则为逻辑服务端。虽然也有其它一些方法来判断逻辑段,但都没有这种方法好用,因为World对象在Minecraft各处代码中均可见到。 | |||
=== 在世界中放置方块 === | |||
在一个World中获取某坐标处的方块状态很简单,getBlockState这个方法即可胜任。与之类似地,放置方块,可以用setBlockState。 | |||
但我们注意到:后者有2个重载,形参列表的区别在于:有一个重载较另一个重载而言,多了一个:<code>int flags</code>。flags即标记,但它又是一个int类型的数——显然,它是一个幻数,具体含义到底如何,全看Mojang的底层设计如何了。如果去看看那个较为简单的方法,可以发现,它实际上是调用了另一个重载方法,并指定flags为3——为什么是3? | |||
显然,这很让人摸不着头脑。不过Forge在<code>Constants.BlockFlags</code>类下提供了相应的常量,并通过注释和常量名说明了flags的具体含义。简单地说,Minecraft会从传入的幻数中获取很多信息,每一种信息的具体值都由传入的幻数对应的二进制数的每一位决定: | |||
{| class="wikitable" | |||
|- | |||
! 常量名及含义 !! 数值(二进制形式) | |||
|- | |||
| NOTIFY_NEIGHBORS(邻近方块更新) || 0b00001 | |||
|- | |||
| SEND_TO_CLIENTS(将相关数据同步到客户端) || 0b00010 | |||
|- | |||
| NO_RENDERER(该方块的渲染状态不会被更新) || 0b00100 | |||
|- | |||
| RENDERER_MAIN_THREAD(让方块的渲染状态在游戏主线程中立刻被更新) || 0b01000 | |||
|- | |||
| NO_OBSERVERS(该行为不会被观察者方块观测到) || 0b10000 | |||
|- | |||
|} | |||
Minecraft的默认行为是采取前两项行为,因此默认的幻数值是把前两项行为对应的数进行按位或运算,即0b00011——实际上也就是上文提到的3。你可能会注意到,第三条和第四条是相冲突的,当发生冲突时,以第三条为准。 | |||
== 注释与外部链接 == | |||