任务和 runEntityTask
单词:task n. 任务。所以任务就是Task,Task就是任务。
我们可以在 “方法大全”→AttributeAPI 中可以看到这两个方法。
//返回值: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文档并没有告诉我们它们的区别。但是我们反编译可以看到,runJvmEntityTask
是 runEntityTask
方法的一个适配器 和 桥接方法,其核心作用是实现 Kotlin 函数类型与 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
即可
就像:
function runAttack(attr, attacker, entity, handle){
AttributeAPI.runEntityTask(10000, "测试", attacker, function() {
print("任务开始执行了!")
})
return true
}
他的意思就是,向 attacker
这个实体发送一个名为 测试
的任务,这个任务在 10000
毫秒后被触发,任务内容是 print("任务开始执行了!")
我们看到,print("任务开始执行了!")
是被一个 function() { }
包裹起来的。function() { ... }
是一个整体,它是一个函数对象。
函数对象
在 JavaScript 中,函数是一等公民。这意味着函数可以像其他任何数据类型(如数字、字符串、数组)一样被对待。比如:
可以被赋值给变量
var aFunc = function() { print("任务开始执行了!") }
// 现在 aFunc 这个变量就“指向”或“引用”这个函数对象
可以作为另一个函数的返回值
function createGreeter() {
return function() { print("任务开始执行了!") } // 返回一个函数对象
}
所以我们可以直接将它作为参数
AttributeAPI.runEntityTask(..., function() { ... });
// 把这个匿名函数作为参数传递给了 runEntityTask 方法
我们也可以
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
,他的具体表现是
function test() {
return 10.0
}
Function1<String, Double>
就代表要求一个 String
参数,并需要返回一个 Double
,他的具体表现是
function test(string) {
print(string)
return 10.0;
}
Function3<String, Boolean, Double, Double>
同理
function test(string, boolean, double) {
if (boolean) {
return double * 2;
print(string)
}
return double;
}