Skip to content
On this page

目标选择器与实体访问

数据包通常用 @a@e[type=zombie,distance=..16]@s 这样的选择器识别实体。Katton 支持这种风格,但一旦选中实体,你就可以直接操作真实实体对象,并且在之后持久保存对这个对象的引用。

构建选择器

kotlin
import net.minecraft.core.registries.BuiltInRegistries
import net.minecraft.resources.Identifier
import net.minecraft.world.effect.MobEffects
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.phys.Vec3
import top.katton.api.ServerPhase
import top.katton.api.ServerReadyContext
import top.katton.api.ServerScriptEntrypoint
import top.katton.api.dpcaller.addEffect
import top.katton.util.EntitySelectorBuilder

@ServerScriptEntrypoint(ServerPhase.READY)
fun targetSelectorExample(context: ServerReadyContext) {
    val creeperType = BuiltInRegistries.ENTITY_TYPE
        .getOptional(Identifier.parse("minecraft:creeper"))
        .orElseThrow()

    // Build a target selector
    val selector = EntitySelectorBuilder.allEntities()  //@e
        .type(creeperType)   //type = creeper
        .tag("qwq", false)  //tag = qwq
        .distanceBelow(16.0)    //distance = ..16
        .create()
    // So we get a target selector like this: @e[type=creeper,tag=qwq,distance=..16]

    // And then we need to build a command execution source, which is required by the selector to get the world and the position for distance calculation
    val source = context.server.createCommandSourceStack()
        .withLevel(context.server.overworld()) // Set the dimension for the command source
        .withPosition(Vec3(50.0, 70.0, 50.0)) // Set the position for distance calculation

    // Get entities selected by the selector
    val entities = selector.findEntities(source)

    // Once you get the references of the entities, you access those entities at anywhere in your code, and do whatever you want with them
    for (entity in entities) {
        if (entity is LivingEntity) {
            // add some effect to the entity
            addEffect(entity,
                MobEffects.GLOWING, // effect
                200,    // effect duration in **ticks**
                0,      // effect amplifier level
                false,  // show particles
                false   // ambient effect
            )
        }
    }
}

选择器仍然需要命令执行源,因为原版选择器依赖世界、位置、权限和维度上下文。

对比

数据包Katton
选中实体,然后对每个实体执行命令选中实体,然后循环处理对象
把中间值存进计分板把局部值存进 Kotlin 变量
execute as ... at ... 切换上下文把实体或世界直接传给函数
在多个函数里重复选择器过滤写一个返回实体列表的辅助函数

常用模式

如果选择器会复用,把它包成有名字的函数:

kotlin
fun nearbyTaggedCreepers(): List<Entity> {
    val selector = EntitySelectorBuilder.allEntities()
        .type(EntityType.CREEPER)
        .tag("charged_target")
        .distanceBelow(16.0)
        .create()

    val source = requireServer().createCommandSourceStack()
    return selector.findEntities(source)
}

这样后续逻辑就能表达意图,而不是重复选择器语法:

kotlin
for (creeper in nearbyTaggedCreepers()) {
    println("Found ${creeper.name.string}")
}

提示

如果事件参数已经给了你玩家、方块、实体或世界,就直接使用它。重复选择通常比直接使用事件对象更慢,也更不精确。

事件驱动写法见 事件