Skip to content

任务和 runEntityTask

单词:task n. 任务。所以任务就是Task,Task就是任务。

我们可以在 “方法大全”→AttributeAPI 中可以看到这两个方法。

Java
//返回值:void
//描述:此处留空
//kotlin版本号.jvm.functions.Function0
AttributeAPI.runEntityTask(long millis, String id, LivingEntity entity, Boolean skipStateCheck, Function0<Unit> block)

//返回值:void
//描述:此处留空
//org.serverct.ersha.attribute.data.task.TaskFunction
AttributeAPI.runJvmEntityTask(long millis, String id, LivingEntity entity, Boolean skipStateCheck, TaskFunction func)

这就是标题中所说的 runEntityTask,他允许向服务器发送一个延迟任务。

这些参数是什么? 我们看到 runEntityTask runJvmEntityTask 的参数几乎是相同的,它们只有最后一个参数有略微区别,我们逐个分析。

相同的部分:
long millis 是要求一个 long,他的作用是延迟任务要延迟的时间(毫秒)
String id 是要求一个 String,它是这个任务的 id
LivingEntity entity 是要求一个 LivingEntity 对象,它是这个任务绑定的生物。
Boolean skipStateCheck 是要求一个 Boolean,它决定了是否跳过状态检查。

有区别的部分:
Function0<Unit> block 是要求一个 Function0<Unit> 对象。
TaskFunction func 是要求一个 TaskFunction 对象。

简单来说,runEntityTask runJvmEntityTask 的意思就是,多长时间运行一个名为什么任务

runJvmEntityTask 是什么

我们看到 runEntityTask runJvmEntityTask 仅有一个单词的区别,但AttribtePlus文档并没有告诉我们它们的区别。但是我们反编译可以看到,runJvmEntityTaskrunEntityTask 方法的一个适配器桥接方法,其核心作用是实现 Kotlin 函数类型与 Java 兼容函数接口之间的类型适配与互操作

Java
@JvmStatic
public final void runJvmEntityTask(long millis, @NotNull String id, @NotNull LivingEntity entity, @Nullable Boolean skipStateCheck, @NotNull final TaskFunction func) {
    Intrinsics.checkNotNullParameter(id, "id");
    Intrinsics.checkNotNullParameter(entity, "entity");
    Intrinsics.checkNotNullParameter(func, "func");
    this.runEntityTask(millis, id, entity, skipStateCheck, (Function0)(new Function0() {
    public final void invoke() {
        func.invoke();
    }

    public Object invoke() {
        this.invoke();
        return Unit.INSTANCE;
    }
    }));
}

你不需要关心代码内部是如何实现的,写脚本也不会用到它,了解即可。

如何使用

我们只使用 runEntityTask 即可
就像:

JavaScript
function runAttack(attr, attacker, entity, handle){
    AttributeAPI.runEntityTask(10000, "测试", attacker, function() {
        print("任务开始执行了!")
    })
    return true
}

他的意思就是,向 attacker 这个实体发送一个名为 测试 的任务,这个任务在 10000 毫秒后被触发,任务内容是 print("任务开始执行了!")

我们看到,print("任务开始执行了!") 是被一个 function() { } 包裹起来的。function() { ... } 是一个整体,它是一个函数对象。

函数对象

在 JavaScript 中,函数是一等公民。这意味着函数可以像其他任何数据类型(如数字、字符串、数组)一样被对待。比如:

可以被赋值给变量

JavaScript
var aFunc = function() { print("任务开始执行了!") }
// 现在 aFunc 这个变量就“指向”或“引用”这个函数对象

可以作为另一个函数的返回值

JavaScript
function createGreeter() {
    return function() { print("任务开始执行了!") } // 返回一个函数对象
}

所以我们可以直接将它作为参数

JavaScript
AttributeAPI.runEntityTask(..., function() { ... });
// 把这个匿名函数作为参数传递给了 runEntityTask 方法

我们也可以

JavaScript
function runAttack(attr, attacker, entity, handle){
    AttributeAPI.runEntityTask(10000, "测试", attacker, run())
    return true
}
function run() {
    print("任务开始执行了!")
}

任务 id

我们可以看到,runEntityTask 中有一个 id 参数,它除了定义这个任务的名字,还有什么作用?

想象一下
你对小机器人下令:id="浇花",10分钟后浇水!
机器人:“滴!任务浇花已设定!”(心里记下id)
5分钟后,你又喊:“等等!id="浇花",改成10分钟后浇!”
机器人:“叮!取消旧浇花!新浇花任务已更新!”
结果:共计 15分钟后 你看到花被浇了一次。而不是浇了两次花。
id 就是机器人的“任务名”,同名就换新指令,不叠罗汉!

顺嘴一提:Function0<Unit>

Function0<Unit> 是 Kotlin 语言在 JVM(Java 虚拟机)上实现函数式编程的一个核心接口。了解即可,不了解也没事。

拆解

kotlin.jvm.functions
这是 Kotlin 为在 JVM 上运行而提供的标准库包。
里面定义了一系列接口:Function0, Function1, Function2, ..., Function22,分别代表有 0, 1, 2, ... 22 个参数的函数。

Function0
0 表示这个函数接受 0 个参数。

<Unit>
这是函数的返回类型。
Unit,我们在JavaScript中什么都不需要返回。

实例 Function0<Double> 就代表我们需要返回一个 Double,他的具体表现是

JavaScript
function test() {
    return 10.0
}

Function1<String, Double> 就代表要求一个 String 参数,并需要返回一个 Double,他的具体表现是

JavaScript
function test(string) {
    print(string)
    return 10.0;
}

Function3<String, Boolean, Double, Double> 同理

JavaScript
function test(string, boolean, double) {
    if (boolean) {
        return double * 2;
        print(string)
    }
    return double;
}