MCFPP——实体设计

在Minecraft命令中,实体操作是非常核心的部分。可以说,百分之九十的数据包,都和实体密切相关。在MCFPP中,当然也需要对实体操作部分进行精巧的设计。

实体的选择

在数据包中,大致有两种方法对实体进行选择操作。

第一种方法就是最常见的目标选择器。直接使用@e,@s之类的目标选择器,对实体进行选择,之后再对其进行各种操作。

第二种方法是物品Thrower法,适用于从大量实体中选择某一个实体,在总实体特别多的情况下,相较于@e的优势尤为明显。具体来说,这个方法就是将一个实体的UUID-NBT储存到一个物品实体的Thrower nbt中,之后通过execute on origin,就可以选中这个实体了。一般来说,用于选择用的物品实体都会拥有一个特定的UUID值,因此可以直接使用execute as uuid on origin,从而避免@e昂贵的性能开销。

在MCFPP中,提供了两种方法,用于选择实体,分别对应了上述的两种方案。

<Java>class Selector <MCFPP>type selector

Selector类,在mcfpp中,对应selector类型,表示一个目标选择器。一般来说,可以直接使用和Minecraft中一样的形式构建一个目标选择器:

//一个基本的目标选择器
selector a = @a;
//当然也可以使用var关键字
var b = @a;
//带有参数的目标选择器
var c = @e[type=creeper,distance=7..10];

在创建好一个目标选择器后,可以对目标选择器进行进一步的修饰,实质上是为目标选择器添加参数

//基本的目标选择器
var a = @e;
//添加参数修饰
a = a.type("creeper");
a = a.distance(1,2);
//相当于@e[type=creeper,distance=1..2]
//允许使用参数
a = a.limit(count);
//你可以使用链式调用
var p = @e.type("fox").limit(1).sorted(Sort.Nearest);

值得注意的是,目标选择器实际上有两种类型。一种是单数目标选择器,即只会选择一个实体的目标选择器(@p,@s,@e[limit=1]),一种是复数目标选择器,可能选择多个实体。在Minecraft中,某些命令仅可接受一个实体作为命令的参数, 因此我们也需要在MCFPP中对这两种目标选择器进行区分。同样都会使用selector作为类型名,但是使用泛型参数进行区分。

对于selector<int limit>,表示最多只会选择limit个实体,比如selector<1>就可以表示一个单数目标选择器。而对于没有泛型参数的selector,就表示会选择的实体个数不确定。

除了数量限制以外,还有实体种类限制。有selector<string type>,用于限制目标选择器会选择哪种实体。比如selector<"pig">只会选中猪。

<Java>class Entity <MCFPP>type entity

Entity对应mcfpp中的类型entityEntity类继承于NBTBasedData,意味着这是一个基于NBT的数据。事实上,entity类型的数据中,就是存储的一个实体的uuid-nbt数组。它是基于第二种方案,也就是Thrower来选中实体的。

你可以使用目标选择器来获取entity类型,也可以通过NBT数据获取。

//通过目标选择器
var s = @s;     //单数目标选择器选择单个实体
entity e = s.select();
var a = @a;     //复数目标选择器选择多个实体
list<entity> es = a.select();

//通过nbt
nbt uuid = @s.nbt["UUID"];
entity e = (entity)uuid;     //强制类型转换

entity不适用于访问多个实体,一般适用于访问单个实体。

实体的操作

无论是selector还是entity,它们的类都继承了EntityBase接口类型。EntityBase接口要求其继承者实现所有对实体的操作。因此,selectorentity都能用同一套API实现对实体的操作。

对实体的操作主要分为两种。第一种是以实体为执行者执行命令。比如

//目标选择器
var a = @e;
a.say("hi");    //相当于execute as @e run say hi

//entity
var b = (entity)[I;0,0,0,1];
b.say("hi");

第二种操作是获取实体上的数据,主要是记分板和nbt。以目标选择器举例

//目标选择器
var a = @p;
int i = a.score["test"];

var b = @e;
list<int> scores = b.score["test"];

可以看到,单数目标选择器和复数目标选择器获取数据的时候,获取到的数据也是不一样的。单数目标选择器获取到的说单个的数据,而复数目标选择器获取到的是这个数据类型的列表,里面存放的是选中的所有实体的数据,存放顺序和实体选择的顺序一致。

类似文章

发表回复