跳到主要内容

语句的简单使用

我们先来从几个比较基础的语句开始说起

print {action}
「展开 / 收起详情」💠 Print 语句

这个语句可以将消息输出到控制台,语句后面写了什么它就会在控制台上输出什么信息

其中 {action} 为语句的参数,在这个位置的内容会被当做参数传入 Print 语句,然后在控制台中输出

例如我们在控制台中使用 Vulpecula 插件试着玩一下这个语句,能得到这样的效果

/vul eval print "今天翻的是书"

[Vulpecula] 今天翻的是书

‹ › Result: kotlin1510.Unit

这里我们可以看到,今天翻的是书 位于 Print 语句的 {action} 参数位置,因此它被作为参数传入了 Print 语句,并被 Print 语句输出到了控制台上。

Tell 语句

tell {action}
「展开 / 收起详情」💠 Tell 语句

这个语句跟刚才的 Print 语句是差不多的功能,都是输出一段消息

只不过区别在于,Print 语句是把消息输出到控制台,而 Tell 语句会把消息输出给 脚本的执行者

/vul eval tell "明天数的是钱!"

对于 /vul eval <kether> 这个命令来说,谁执行的命令,谁就是脚本执行者。

例如上面玩家执行了该指令,此时玩家是脚本执行者,所以 Tell 语句会把这段消息发送给玩家。

提示

如果我们需要向玩家发送消息,基本上都是使用 Tell 语句

当然,如果你在控制台里执行同样的命令,那么这段信息显然会输出到控制台,此时 tell 语句跟 print 语句并无差别,作用无外乎都是输出信息到控制台了。

Color Text 语句

如果你尝试这样发送有颜色代码的文本 tell "&d丈母娘喜欢有学历的女婿" 你会发现颜色代码并不起作用

这是因为,Tell 和 Print 语句都没有转换颜色的功能,它们的作用是输出信息,而并不具有转换颜色代码的功能

要实现颜色的转换,还需要通过 Color Text 这个语句才行。

color {action}
「展开 / 收起详情」💠 Color Text 语句

那么如何使用该语句呢?

现在我们知道,要转换颜色代码可以这样写:

color "&d丈母娘喜欢有学历的女婿"

但是有一个问题,Color Text 语句的作用是转换颜色,而不具有输出消息的功能,那我们怎么输出这段信息呢?

很简单,在这段语句前面套上一个 Tell 语句或者 Print 语句就可以了。

tell color "&d丈母娘喜欢有学历的女婿"

最后我们来验证一下

/vul eval tell color "&d丈母娘喜欢有学历的女婿"

注意看,这个时候,Tell 语句参数的位置就不再是 "&d丈母娘喜欢有学历的女婿" 文本了

而是 Color Text 语句 color "&d丈母娘喜欢有学历的女婿" 整体作为 Tell 语句的参数

注意这里千万不要犯迷糊了

语句的返回值

不知道你有没有思考过,为什么 Color Text 可以作为 Tell 的参数呢?

因为 Color Text 语句有返回值呀!什么返回值?颜色转换后的返回值啊!

Color Text 语句将颜色转换后,它的返回值会被前面的语句当做参数来使用

所以前面说的"Color Text 语句整体作为 Tell 语句的参数"实质上就是 Color Text 的返回值被前面的 Tell 语句拿来发送给玩家了。

那如果把前面的 Tell 语句去掉呢?那它的返回值又会何去何从?

/vul eval color "&d丈母娘喜欢有学历的女婿"

提示

/vul eval <kether> 命令执行后,Result 信息表示为整个脚本的运行结果

显而易见,前面没有了 Tell 语句,那么此时 Color Text 的返回值不就相当于整个 Kether 的运行结果了吗

那是不是所有语句都有返回值呢?并不完全算是。

你可以回头看一下 Print 语句和 Tell 语句执行之后,Result 信息是什么?

是一段奇怪的东西"kotlin1510.Unit",这表明该语句没有可用的返回值。

很好理解嘛,Print 和 Tell 的作用是输出信息,你说它要返回值干啥?对吧!

接下来我们学习两个常用的具有返回值的语句

Name 语句

player name
「展开 / 收起详情」💠 Name 语句

这个语句的作用是返回玩家的名字,也就是返回玩家的 ID 名字

可以看到,这个语句里没有 {action} 的字样,说明它不需要任何参数,直接返回玩家的名字

/vul eval tell player name

看到这里你是不是有点疑惑:它不需要参数,那它是从哪获取的玩家名字呢?服务器有那么多玩家,获取的又是谁的名字?当然是从脚本执行者那里拿的咯!

你想想 Tell 语句,它只接收一个参数,用来输出信息。并没有额外的参数去指明向谁输出信息。那么向谁输出信息?当然是向脚本执行者输出信息啦!

哪个玩家是脚本执行者,返回的就是哪个玩家的名字。

什么?!这么荒唐?那我要是想给多个玩家发消息岂不是实现不了???

当然是有办法滴!下一节我们会学习如何修改脚本执行者,现阶段你只要知道,脚本执行者是能改的就好了

那么问题来了。如果我在控制台里执行这个命令呢?它会返回控制台的名字吗?话说控制台也有名字的吗?

/vul eval tell player name

[Vulpecula] Unexpected exception while running the kether script.
[Vulpecula] No player selected.

‹ › Result: null

如果你真的这样做了,那么恭喜你!你成功收到了你的第一份 Kether 报错!

Tips: 英语不好,看不懂报错也别愣着啊哥们!打开你的翻译软件!注意这不是在考试!

第一句报错"Unexpected exception while running the kether script."告诉我们,Kether 运行的时候出现了报错,出现报错第一句信息基本上都是它,所以这不是重点!

第二句报错"No player selected."告诉我们,没有选择任何玩家,言外之意就是,脚本执行者是控制台而不是玩家,player name 语句拿不到玩家名字所以报错了。

这也从侧面告诉我们,部分语句必须依赖玩家才能执行,所以如果今后你遇到类似的报错"No player selected."基本上都是在告诉你,脚本执行者并非玩家。而你却使用了需要依赖玩家的语句。这个时候你需要检查你的脚本,是不是哪里用到了需要依赖玩家的语句,而没有指定玩家为脚本执行者。

大部分用到 Kether 的环境下,脚本执行者多数是玩家,所以不用担心哦!

就算没有也可以通过 Switch 语句手动指定,这个后面会讲噢!

例如 Invero 和 TrMenu:玩家点击菜单时执行 Kether,其脚本执行者当然是这名玩家咯

还有 Chemdah:玩家在对话过程中执行的 Kether,其脚本执行者当然也是这名玩家啦

Permission 语句

perm {action}

这个语句的作用是判断玩家是否拥有某条权限

例如我想判断玩家是否拥有 Essentials 指令 /hat 的权限 essentials.hat

那么我就可以这样去写:

perm essentials.hat

/vul eval perm "essentials.hat"

判断玩家有权限就返回 true,反之就是 false。

跟刚才的 Name 语句类似,它也必须依赖玩家才能执行,否则你会收到"No player selected."的报错。

脚本执行者

相信看完前面的内容,你已经对脚本执行者这个概念并不陌生了吧!

大部分语句都是需要以脚本执行者来作为操作对象的。例如 Tell 语句,会将信息发送给脚本执行者;Name 语句会获取玩家的名字(当玩家作为脚本执行者时);还有 Perm 语句等等...

接下来我们学习两个与脚本执行者相关的语句

Sender 语句

sender

该语句虽然没有在官方文档中给出,但并不影响使用。

它的作用是获取脚本执行者的名字。跟 player name 作用类似,它也能用来获取玩家的名字,并且都没有参数。

除此之外,当控制台作为脚本执行者时,它还能获取控制台的名字:console,只不过这并没有什么用而已。

但它的优点在于不依赖玩家执行,相对来说会比 player name 更安全保守一些。

Switch 语句

switch {action}

能修改脚本执行者的语句来咯!

该语句的作用是修改脚本执行者为指定玩家。参数的位置需要填在线玩家的名字 ID

例如我们在控制台里执行:

/vul eval switch Lanscarlos tell "找到你了!"

这样就能在控制台中,将脚本执行者切换到指定的玩家,然后对他说悄悄话了!嘻嘻!

语句的参数

现在让我们把目光放在语句的参数上面

语句的参数分为许多种不同的类型,参数的类型决定了这个位置的内容它应该以怎样的方式读取,这一点很重要!

前面我们见到的 {action} 就是其中一种参数类型:Action

Action 类型参数

前面我们学习过的 Print 语句、Tell 语句还有 Color Text 语句的参数都属于 Action 类型。

什么意思呢?我们慢慢来讲

"Action"一词是"动作"的意思,在 Kether 里同样也有"语句"的意思。

那就不难理解了,Action 参数类型,会把该位置的参数当成语句去读取,以前面的内容为例:

tell color "&d丈母娘喜欢有学历的女婿"

Tell 语句的参数类型为 Action,这就意味着它会把参数当做语句去读取。正巧参数位置又是 Color Text 语句。

一通操作下来,Color Text 语句就变成了 Tell 语句的参数咯,那自然而然,在运行阶段 Color Text 语句的返回值就会作为 Tell 语句的参数并被 Tell 语句发送到玩家那里。

Token 类型参数

这个类型的参数比较少见,但要理解起来并不难。

Token 参数类型,会把该位置的参数当成文本去读取

也就是说,我在参数这个位置写了什么,那它实际上读取到的参数就是什么,它不会把参数当成语句去读取

所以如果你在参数位置填入一个语句(比如 Color Text),那么解析过程会出现不可预料的问题!

由于使用 Token 类型参数的语句较少,这里我们做个假想实验来对比一下 Token 与 Action 类型参数的区别

假设我们现在有一个 Output 语句,它的作用与 Tell 语句一样,都是输出一段信息,但是它的参数类型为 Token

output {token}

那么如果我分别执行以下两条语句,输出玩家的名字,会有什么区别呢?

tell player name
output player name

Tell 语句不必多说,将参数看做语句读取到 player name 语句。最后输出的是玩家名称,没有问题。

Output 语句会将参数看做文本来读取。由于"player"与"name"之间含有空格,会被视为两段文本。所以 Output 只能读取到前面的"player"文本。后面的"name"只能无奈作为 Kether 的运行结果。

总结一下:

Token 类型参数 {token} 是将文本作为参数读取,将参数解析为文本

Action 类型参数 {action} 是将语句作为参数读取,将参数解析为语句

关于参数的宽容解析

就在刚才 Token 与 Action 假想实验里不知道你有没有这样的疑惑:

Tell 语句的参数不是 Action 类型吗?按道理来说,会将参数解析为语句。

在刚才的例子里 tell player name, Tell 后面的"player name"能够被正常解析为 Name 语句

那么在 tell "明天数的是钱!" 例子里,Tell 后面的"明天数的是钱!"也能被解析为语句么?

这是为什么呢?

因为我们漏掉了一个容易被大多数人忽略,但又无处不在的语句

隆重介绍:Literal 语句!

「展开 / 收起详情」💠 Literal 语句

Literal 语句的作用是创建并返回字符串,其参数为 Token 类型,也就是读取一段文本,然后将它作为语句的返回值。而且注意看,它支持三种书写格式:

literal {token}
*{token}
{token}

特别是第三种格式,在必要时候,能直接将参数 {token} 文本转化为 Literal 语句

所以前面的 tell "明天数的是钱!" 例子其实是 Literal 语句的第三种缩写形式,将它写完整应该是这样:

tell literal "明天数的是钱!",只不过是中间省略了"literal"关键字而已。

也正是因为有这样的特性,在 Action 类型参数里我们直接写文本是没有问题的,Kether 会自动将文本解析为 Literal 语句,这个过程有个官方名称,叫做"宽容解析"

当文本内容无法被解析为语句时,Kether 会进行宽容解析,将文本内容解析为 Literal 语句。

例如在 tell color "&d丈母娘喜欢有学历的女婿" 例子里,由于"color"能够被解析为 Color Text 语句,所以 Kether 不会傻傻地把"color"直接解析为 Literal 语句。那岂不是乱套了!当然如果 Kether 里没有 Color Text 语句,那才会进行宽容解析,把"color"解析为 Literal 语句。

tell "明天数的是钱!" 例子中,由于"明天数的是钱!"无法解析为任何语句,所以它会被直接解析为 Literal 语句。

注意噢!文本内容无法被解析为任何语句时,才会被解析为 Literal 语句!

言外之意:如果文本内容可以被解析为语句,那么它就不会被解析为 Literal 语句!

为什么我要强调这一点呢?因为我担心有人会下意识认为:只要是引号括起来的内容,就一定会被解析为 Literal 语句。事实真的是这样吗?当然不是!不信那我来考考你:

以玩家身份执行命令:/vul eval "<tell>" "<hello>",你觉得会发生什么呢?

「展开 / 收起详情」💠 答案

所以,千万不要单纯以为用引号括起来的内容就一定会被解析为 Literal 语句,只要能被解析为其他语句,那它最后的运行结果一定得以解析的语句为准!

那如果我非得把"color"字样输出给玩家而不想让它解析为 Color Text 呢?Literal 语句不是还有另外两种写法吗?随便选一个用就行了:tell literal "color" 或者 tell *"color"

Action List 类型参数

"List"一词有"列表"的意思,你也可以理解为"数组"的意思

在编辑 Yaml 配置文件时,我们也能经常看到 List 列表的身影,想不起来了?来看:

# 常见的写法
disabled-worlds:
- 'world'
- 'world_nether'
- 'world_the_end'

# 第二种写法
disabled-worlds: [ 'world', 'world_nether', 'world_the_end' ]

怎么样?是不是很眼熟?这就是 List 列表,将多个内容按一定顺序写到某个节点上。

在 Kether 中,Action List 类型参数也是同样的道理,将多个语句按一定顺序写到参数位置上。

这里以 Array 语句简单举例

array {action list}
「展开 / 收起详情」💠 Array 语句

该语句的作用是,根据给定的参数列表,创建一个集合

注意这里写法跟 Yaml 中第二种写法类似,但有所区别:

列表前后需要使用中括号括住,语句之间不需要使用逗号隔开!

/vul eval array [ 1 1 4 5 1 4 ]
/vul eval array [ Lanscarlos Spark_nano ]

其他类型参数

本章我们介绍了 Action 类型、Token 类型和 Action List 类型的参数。

除此之外还有许多其他类型的参数诸如 {int}{double}{symbol} 等等...

这里暂时不做过多介绍,放在后面的章节里再深入探讨吧!