3 槽位和需求 - Tollainmear/VirtualChest-wiki-zh_CN GitHub Wiki

栏/槽位配置

这里有一个配置样例,实现了小麦的买卖功能,其中实现了相应游戏币的扣除和获取的功能:

Slot0 {
  Item {
    Count = 1
    ItemType = "minecraft:wheat"
    UnsafeDamage = 0
    DisplayName = "&lWheat seller"
    ItemLore = [
      "&ePrice for %player_name%: $10 => 9 wheats"
      "&eYou can left or right click to buy some wheats"
    ]
  }
  PrimaryAction {
    Command = "cost: 10; console: give %player_name% minecraft:wheat 9"
    KeepInventoryOpen = true
  }
  SecondaryAction {
    Command = "cost: 10; console: give %player_name% minecraft:wheat 9"
    KeepInventoryOpen = true
  }
  Requirements = "%economy_balance% >= 10"
}

槽位的配置内容包括了7个关键项: ItemRequirementsPrimaryActionSecondaryActionPrimaryShiftAction(上例中没有用到)、SecondaryShiftAction(上例中没有用到)和 IgnoredPermissions (上例中没有用到)。

Item

本项对应的值应该用于描述槽位显示的物品信息。

如果您加载了PlaceholderAPI,它将会作用于配置文件,为玩家显示出不同的物品名字、不同的物品、和不同的描述文本等。

例如:如果一个叫做Notch的玩家查看 Hello %player_name% 将会显示为Hello Notch

一个物品有一系列的属性,下面列出了一些常用属性:

Count 属性

物品在槽位中的显示数量,需要在配置中显式声明。在大多数情况下,它是1。

ItemType 属性

插槽中的物品的类型,需要在配置中显式声明。

UnsafeDamage 属性

插槽中的物品的损耗值,需要在配置中显式声明。通常是0。

UnsafeData 属性

物品的NBT属性。例如,下面所示的部分将显示打开菜单玩家的脑袋:

Item {
  Count = 1
  ItemType = "minecraft:skull"
  UnsafeDamage = 3
  UnsafeData = {
    SkullOwner = "%player_name%"
  }
}

DisplayName 属性

物品的自定义显示名字,可以通过"&"关键字进行格式化。

ItemLore 属性

物品的自定义描述,可以通过"&"关键字进行格式化。

ItemEnchantments 属性

物品的附魔属性列表,例如:

ItemEnchantments = [
  "minecraft:protection:4"
  "minecraft:fire_protection:4"
  "minecraft:feather_falling:4"
  "minecraft:blast_protection:4"
  "minecraft:projectile_protection:4"
]

上面物品附魔了所有的保护类属性,并且都到达了4级(满级)。

HideEnchantments 属性

是否要显示物品的附魔信息,对应的值应该为truefalse

HideAttributes 属性

是否要显示物品(通常是工具)的属性,对应的值应该为truefalse

RepresentedPlayer 属性

如果描述的是一个头颅的话,此属性将会指定其显示为指定玩家的头颅。这个属性所对应的值应该是由两个大括号所包围的语句块,其中至少包含一个UUID项,而Name项是选填的,比如:

RepresentedPlayer = {
  UUID = "%player_uuid%"
}

以上的代码将会为玩家显示其自己的头颅,而下面的代码将会指定头颅的材质为“Dinnerbone”:

RepresentedPlayer = {
  UUID = "61699b2e-d327-4a01-9f1e-0ea8c3f06bc6"
  Name = "Dinnerbone"
}

Requirements

本项的值应该描述对玩家的要求。如果玩家与要求不匹配,那么相应的项将不会显示给他们。如果提供多个项目来描述一个槽位,插件将尝试显示下一个符合要求的项目。如果没有匹配,那么这个槽位将是空的。

例如,如果玩家有足够的钱(不少于10),就应该显示一个小麦项目,否则应该显示一个屏障,配置文件大概是这样的:

Slot0 = [{
  Item {
    Count = 1
    ItemType = "minecraft:wheat"
    UnsafeDamage = 0
  }
  Requirements = "%economy_balance% >= 10"
}, {
  Item {
    Count = 1
    ItemType = "minecraft:barrier"
    UnsafeDamage = 0
  }
}]

如果玩家有足够的钱,第一个项目将被显示,否则第二个项目。

JavaScript

Requirement属性对应的值应该是一句JavaScript,这意味着它将被编译或解释,以决定这个玩家是否匹配需求。脚本的以下返回值将被视为玩家符合需求:

  • 布尔值 true
  • 大小写不敏感的 trueTrueTRUE等。

在其他情况下,它将被视为“false”,这意味着这个玩家不符合要求。

如果PlaceholderAPI的文字段 (%xxxx_xxxx_xxxx%) 出现在了脚本的文字段中,它将被转换为函数调用(papi('xxxx_xxxx_xxxx'),再计算得到结果值。

如果你曾经使用过其他一些使用JavaScript的菜单插件(例如deluxemenus),你需要特别需要注意一下本插件同他们之间的区别。例如,在配置DeluxeMenus插件时,如果你想检查玩家是否是Notch,你可以写 '%player_name%' == 'Notch' ,它将被翻译成 'Notch' == 'Notch''Dinnerbone' == 'Notch',或者别的什么。然而,如果你使用的是virtualchest,它将被翻译成'papi('player_name')' == 'Notch',这将产生一个语法错误。

这虚拟箱子菜单插件中,你应该写成 %player_name% == 'Notch',这样这段文字将会被翻译成papi('player_name') == 'Notch',然后判断'Notch' == 'Notch''Dinnerbone' == 'Notch'或者其他的什么玩意,这样就符合了JavaScript的语法要求。

让我们回头谈谈开始时的Requirement%economy_balance% >= 10。如果玩家有20游戏币,那么原式等同于'20' > 10,此时JavaScript提供一个一个隐式转换,将数字转换为字符串,所以 '20' > 10 等同于 20 > 10 ,这样获得的布尔值就为 true 了。

为了方便起见,我们提供了一些预置变量:

  • server,海绵端服务器对象
  • player,玩家对象
  • papi,一个能将占位符翻译为其实际值的函数
  • tick,从打开菜单界面以来的tick值,我们可以用它来制作一些简单的动画

常用的需求字符串模式

  • %player_name% == 'Notch'

    检查玩家是不是叫Notch

  • %economy_balance% >= 10

    检查玩家的余额是否不小于 10 (默认的货币单位)

  • player.hasPermission('virtualchest.open.self')%player_perm_virtualchest.open.self%

    检查玩家是否拥有 virtualchest.open.self 权限,我们建议您使用第一种格式

  • %server_online% > 20server.getOnlinePlayers().size() > 20

    检查在线的玩家数量是否大于20个,我们建议您使用第一种格式

当然,您也可以使用&&(与) 或者||(或) 来连接两个语句。例如: %player_name% == 'Notch' && %economy_balance% >= 10 ,检查这个玩家是不是同时满足叫Notch和不少于10游戏币。(默认的货币单位)

PrimaryActionSecondaryAction

这两项的值将会决定玩家在做出对应动作之后所执行的行为。PrimaryAction代表左键单击,SecondaryAction代表右键单击,例如:

PrimaryAction {
  Command = "cost: 10; console: give %player_name% minecraft:wheat 9"
  KeepInventoryOpen = true
}

KeepInventoryOpen这一项决定了在玩家点击完项目后是否立刻关闭菜单,此项的默认值为false

Command项定义了一系列有序执行的命令,。其中每一个命令都需要被分号(;)隔断开来,在下面的示例中,我们使用了两个指令cost: 10console: give %player_name% minecraft:wheat 9。同样的,在Command项内也支持使用占位符来对关键字进行替换,%player_name%将会被替换为点击菜单的玩家的名字。

Command项中的指令是允许包含前缀的,不同的前缀会执行不同类型的指令,其中,前缀和主体指令之间使用冒号进行分割(:)。请参考 指令前缀

这里我们还有另外一个在上面没有用到的项 HandheldItemHandheldItem用于检测鼠标上拾取物品的类型和数量,例如

PrimaryAction {
  Command = "cost-item: 9; cost: -8"
  HandheldItem {
    ItemType = "minecraft:wheat"
    UnsafeDamage = 0
    Count = 9
  }
  KeepInventoryOpen = true
}

这段代码的意思是,玩家的鼠标上至少要持有九个小麦的情况下点击指定的物品,才能执行相关的行为。其中UnsafeDamage这一项不是必填的,如果这一项没有指定的话,那么任意损耗值的物品都能够成功激活后续的动作。这一特性可以用来创建箱子商店,玩家随时随地都可以通过它购买或者出售道具,

PrimaryAction的值也可以对应多个对象。如果它对应了多个值,那么其中的元素将会用来同其手中所持(由HandheldItem项所定义)的道具进行识别和匹配,例如:

PrimaryAction = [{
  Command = "cost-item: 9; cost: -8"
  HandheldItem {
    ItemType = "minecraft:wheat"
    UnsafeDamage = 0
    Count = 9
  }
  KeepInventoryOpen = true
}, {
  Command = "cost-item: 1; cost: -8"
  HandheldItem {
    ItemType = "minecraft:hay_block"
    UnsafeDamage = 0
    Count = 1
  }
  KeepInventoryOpen = true
}]

不仅是对于小麦,干草块也是可以被正确识别,只要玩家鼠标拾取了两者之一并点击这一按钮。

如果您想了解更多的关于HandheldItem的信息,请参考Identifing Items

PrimaryShiftActionSecondaryShiftAction

PrimaryShiftActionSecondaryShiftActionPrimaryActionSecondaryAction 非常相似,但是他们仅会在玩家按住Shift的状态下点击按钮才会被激活。如果没有设置此项 PrimaryShiftAction 将会具备同 PrimaryAction 一样的表现,相应的, SecondaryShiftAction 将会具备同 SecondaryAction 一样的表现。

IgnoredPermissions

虚拟箱子菜单不提供op(管理员)权限的行为,虽然这些行为都在ChestCommands和BossShop插件中出现了。由于安全和一些其他原因,Sponge端故意忽略了OP的概念。 (请参考这个 pull request)。因此,虚拟箱子菜单提供了一个叫做 IgnoredPermissions 的特性来解决这个问题,这种方式将会变得更加灵活并且安全。

您可以定义多个允许忽略权限,像这样:

Slot0 {
  Item {
    // blablabla
  }
  PrimaryAction {
    // blablabla
  }
  SecondaryAction {
    // blablabla
  }
  IgnoredPermissions = [
    "plugin1.permission1"
    "plugin2.permission2"
  ]
}

所有列进IgnoredPermissions列表内的权限将会在执行指令前设置为true,而在执行完对应的指令之后,这些权限将会回归于之前的状态。感谢Sponge的权限系统的设计,让我们能够临时的处理权限变更,这对于服务器来说已经足够安全了。

识别物品

HandheldItem 是一个字段的关键,他应当被定义在 PrimaryActionSecondaryActionPrimaryShiftAction或者SecondaryShiftAction部分。 HandheldItem被用来识别不同的物品,并对不同的物品做出不同的反馈。换句话说,HandheldItem 在虚拟箱子插件中扮演着道具过滤器的角色。

虚拟箱子可以在HandheldItem部分内识别六种不同的字段,如以下所示。

ItemType字段

如字面意思,ItemType被用来识别道具的类型。

这里有一个示例,用来识别钻石:

HandheldItem {
  ItemType = "minecraft:diamond"
}

Count字段

Count用于识别对应的道具至少达到了给出的限额。而如果您没有定义这一字段的话,默认的值将会是1。

这里是一个示例,用于识别至少60个钻石:

HandheldItem {
  Count = 60
  ItemType = "minecraft:diamond"
}

一个槽位包含61, 62, 63, 或者 64 个钻石也会被正确的识别。

UnsafeDamage字段

UnsafeDamage字段用于识别物品的损耗值。如果此字段没有设置的话,那么相关被HandheldItem检测的道具将无视损耗值(作为通配符比较器)。

这里的示例用于识别一个木炭:

HandheldItem {
  UnsafeDamage = 1
  ItemType = "minecraft:coal"
}

这里的示例用于演示识别一个自然生成的煤炭:

HandheldItem {
  UnsafeDamage = 1
  ItemType = "minecraft:coal"
}

如果 UnsafeDamage 字段没有被定义,那么煤炭和木炭都会成为识别对象:

HandheldItem {
  ItemType = "minecraft:coal"
}

UnsafeData字段

UnsafeData用于匹配物品的nbt标签。其nbt标签的检测逻辑是同 /testfor 指令一样的。

SearchInventory字段

默认情况下 SearchInventory 字段所对应的值为 false。如果将此字段对应的值设置为真 true,那么不仅会检测玩家鼠标指针所拾取的道具,还会检测玩家的背包里所有和 HandheldItem 字段相匹配的道具。由于玩家的背包可以放置多组物品,因此此字段对应的Count字段可以设置的大于一组的值(通常情况下,一组为64个)。

如果您使用了多个行为绑定了多个HandheldItem字段,当玩家的鼠标指针未拾取任何物品的时候,那么里表中的先后顺序决定了执行的优先级。下面以小麦和干草块为例:

PrimaryAction = [{
  Command = "cost-item: 9; cost: -8"
  HandheldItem {
    SearchInventory = true
    ItemType = "minecraft:wheat"
    UnsafeDamage = 0
    Count = 9
  }
  KeepInventoryOpen = true
}, {
  Command = "cost-item: 1; cost: -8"
  HandheldItem {
    SearchInventory = true
    ItemType = "minecraft:hay_block"
    UnsafeDamage = 0
    Count = 1
  }
  KeepInventoryOpen = true
}]

如果玩家在未拾取任何物品的情况下点击了这个按钮,那么优先在玩家背包中搜索的物品将会是小麦(译者注:小麦排在前面),而如果小麦数量不足的话(小于9个),那么第二次在背包中搜索的道具才会是干草块。

然而,被鼠标指针拾取的物品永远具有最高的检索优先级。如果在拾取一个干草块的情况下点击这个按钮的话,那么写在第二检测次序的道具(干草块)会被直接检测,即使玩家的背包里有足够的小麦。

RepetitionUpperLimit字段

我们能不能一次性出售背包中所有匹配的道具呢?当然啦,RepetitionUpperLimit字段允许你重复的检索玩家的背包和鼠标指针所拾取的道具,并且尽可能多次数的(自动)执行相关的行为,直到到达了你设定好的循环次数。默认情况下RepetitionUpperLimit的值为0,这意味着它不会重复执行。如果您将此字段的值设置为一个正整数,情况就会大不相同了。此处仍然以小麦为例:

PrimaryAction {
  Command = "cost-item: 9; cost: -8"
  HandheldItem {
    RepetitionUpperLimit = 2
    ItemType = "minecraft:wheat"
    UnsafeDamage = 0
    Count = 9
  }
  KeepInventoryOpen = true
}
  • 如果您所拥有的小麦少于9个,那么将无事发生。
  • 如果您所拥有的小麦大于9个但小于18个,那么此行为将会被执行一次。意味着你使用了9个小麦兑换了8单位的默认货币。
  • 如果您所拥有的小麦大于18个但小于27个,那么此行为将会被执行两次(相当于重复一次)。意味着你使用了18个小麦兑换了16单位的默认货币。
  • 如果您所拥有的小麦大于27个但小于36个,那么此行为将会被执行三次(相当于重复两次)。意味着你使用了27个小麦兑换了24单位的默认货币。
  • 如果您所拥有的小麦大于36个,那么此行为本应该被执行四次,但是由于RepetitionUpperLimit限制了最大重复次数为两次,因此此处的动作只会被执行三次(相当于重复两次),意味着你将会被扣除27个小麦,并得到24单位的默认货币。

RepetitionUpperLimit 设置为较大的数值确实会让操作更加便捷,但是较大的数值将会导致服务器在同一Tick内执行更多的操作,因此我们并不推荐您将此数值设置过大,请看下面的示例:

HandheldItem {
  RepetitionUpperLimit = 9
  ItemType = "minecraft:wheat"
  UnsafeDamage = 0
  Count = 64
}

上面的示例同下面这个相比,有更好的性能表现:

HandheldItem {
  RepetitionUpperLimit = 64
  ItemType = "minecraft:wheat"
  UnsafeDamage = 0
  Count = 9
}

所有需要您调整的数值只和要被执行的行为有关(比如获得的金钱和扣除的物品)。

指令前缀

空的前缀

空的前缀代表着这段代码是一个将被玩家立即执行的指令。

console 前缀

console 代表着这段代码的主体指令将会被服务器控制台执行。

tell 前缀

tell 代表着这段代码将会以信息的形式发送给相关玩家,您可以使用&字符来格式化这段文字。

tellraw 前缀

tellraw代表着这段代码的主体部分将会被作为一个raw json message进行处理再发送给目标玩家。

broadcast 前缀

broadcast代表着这段代码的主体部分将会被公告给所有的在线玩家,您可以使用&字符来格式化这段文字。

title 前缀

title 代表着这段代码的主体部分将会被发送到目标玩家的动作条(action bar)。它不代表游戏界面中心显示的大标题。 title这个名称的使用,只是一个历史遗留问题。如果您想使用显示在游戏界面中心的大标题,请使用bigtitlesubtitle

bigtitie 前缀

bigtitle代表着这段代码的主体部分讲会以大标题的形式展示在目标玩家游戏界面的正中央,此外,其子标题可以被Besides, the subtitle can be set by the subtitle,您可以使用&字符来格式化这段文字。

subtitle 前缀

subtitle代表着这段代码的主体部分讲吧以子标题的形式缓慢的现实在目标玩家的屏幕上,您可以使用&字符来格式化这段文字。

delay 前缀

delay代表着在此前缀之后紧随着的行为将会延迟指定tick再执行,这里的tick通常情况下是0.05秒。例如:delay: 20代表着后面紧随的指令将会延迟1秒后再执行,请避免指定一个过大的数值,如果玩家在倒计时的中途传送至其他世界,或者倒计时中途服务器关闭将导致后续指令无法成功加载。

connect 前缀

connect代表着目标玩家将会传送到一个指定的服务器,如果您的服务器没有加载BungeeCord的话,这个前缀将失效。

cost 前缀

cost代表着目标玩家将会扣除指定的游戏币。扣除数额由紧随此前缀之后的数字决定,如果玩家没有足够的游戏币,后续的指令仍将继续执行,因此,请使用Requirements项来检查玩家是否有足够的余额。

cost-item 前缀

cost-item代表着虚拟箱子菜单将会尝试从指向此项目的持有指定物品的鼠标指针上移除指定数量的物品。移除的数量由此前缀紧随的数字决定,如果鼠标指针是没有足够的物品,后续的指令仍将继续执行,因此,请使用HandheldItem项来检查玩家是否有足够的物品。

sound 前缀

sound代表着一个声音时间将会被激活。声音的名字(例如 minecraft:block.chest.open minecraft:block.chest.close等)和音量(通常介于0.0到2.0之间)可以通过紧随于此前缀的主体部分决定,请使用冒号(:)进行分割。例如:sound: minecraft:block.chest.open:0.5sound: minecraft:block.chest.close:2.0等。音量是选填的一项,默认值为1(sound: minecraft:block.chest.open 等同于 sound: minecraft:block.chest.open:1.0)。

###sound-with-pitch 前缀

sound-with-pitch代表着特定音调的声音时间将被触发。他甚至可以通过音符箱的声音和delay前缀的配合,播放出一首歌,音品、音量和音调可以通过紧随此前缀之后的主体部分决定,同样适用冒号(:)来分割各个元素,例如: sound-with-pitch: minecraft:block.note.harp:0.5:1.5sound-with-pitch: minecraft:block.note.harp:2.0:3.0等。音量是选填的一项,默认值为1 (sound-with-pitch: minecraft:block.note.harp:1.5等同于sound-with-pitch: minecraft:block.note.harp:1.0:1.5)。