目标选择器与实体访问
数据包通常用 @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}")
}提示
如果事件参数已经给了你玩家、方块、实体或世界,就直接使用它。重复选择通常比直接使用事件对象更慢,也更不精确。
事件驱动写法见 事件。
