- 欢迎来到Minecraft插件百科!
- 对百科编辑一脸懵逼?帮助:快速入门带您快速熟悉百科编辑!
- 因近日遭受攻击,百科现已限制编辑,有意编辑请加入插件百科企鹅群:223812289
GuillaumeVDN的插件文档/QuestCreator/高级内容
GuillaumeVDN的插件文档 | |
---|---|
页面 | |
所有插件都有的常见内容 | |
QuestCreator |
变量
插件有一个可影响任务的内置变量系统。例如,你可以用它来记住一名玩家在任务A中做出的抉择,并因此在任务B中显示不同的抉择选项,而这将存储在用户变量中。
每个变量都是一行文本。变量可以包含数字,并用在解析逻辑或在数学公式中。
变量名对大小写敏感:MyValue
不等于myvalue
。
如果变量没有值,则该变量值会显示为0
。
用户变量
每名玩家的用户变量都是特有的。如果有一个名为my_variable
的变量,那么它对GuillaumeVDN而言的值是1
,而对Notch而言的值是2
。
你可以在这里配置变量默认值:/plugins/QuestCreator/default_variables.yml
variable_1: 0
variable_2: 'default'
模型变量
模型变量用于活跃的任务中,任务结束后这些变量就会被废弃。这些变量可能只在进行任务时有用,而对未来的任务并不重要。
你可以在每个任务模型中配置变量默认值。
服务器变量
这些变量用于服务器。服务器变量值对所有的玩家都一样。
你可以在这里配置服务器变量默认值:/plugins/QuestCreator/server_variables.yml
server_variable_1: 0
server_variable_2: 'default'
全局变量
全局变量拥有固定值且无法修改。它主要用于避免你在任务中重复编写相同内容。它就相当于宏,你可以在配置内的某个地方使用{gvariable:<variable>}
来获取全局变量。
全局变量包含其它变量或占位符。
你可以在这批配置全局变量默认值:/plugins/QuestCreator/global_variables.yml
message_prefix: '&6[QuestCreator] &7'
sample_variable_placeholderapi: '嘿,%player_name%'
sample_variable_qc: '{variable:my_variable} is the value'
sample_spawn_location: 'world,0,64,0'
sample_player_location_through_papi: '%player_world%,%player_x%,%player_y%,%player_z%'
全局元素
为避免重复,你可以用全局元素来配置几乎全部的元素类型,其位于/global_<element type>/
。
比如在这个分支里,玩家重连服务器时会获得药水效果:
branches:
MAIN_BRANCH:
# 任务内容
ANOTHER_BRANCH:
# 其它任务分支
RECONNECT_EFFECTS:
starts_directly: true
starts_at: TRIGGER
objects:
TRIGGER:
type: PLAYER_CONNECT
goto: OBJECT EFFECT
EFFECT:
type: SERVER_PLAYER_EFFECTS_GIVE
start_notify:
message: >
&a欢迎回来,{player}&a!这是你的速度 II效果。
effects:
a:
type: SPEED
amplifier: 1
duration: 1 MINUTE
goto: OBJECT TRIGGER # 循环触发
你不需要复制粘帖该分支到你的全部任务内,你可以在/global_branches/RECONNECT_EFFECTS.yml
内创建一个全局分支:
starts_directly: true
starts_at: TRIGGER
objects:
TRIGGER:
type: PLAYER_CONNECT
goto: OBJECT EFFECT
EFFECT:
type: SERVER_PLAYER_EFFECTS_GIVE
start_notify:
message: >
&a欢迎回来,{player}&a!这是你的速度 II效果。
effects:
a:
type: SPEED
amplifier: 1
duration: 1 MINUTE
goto: OBJECT TRIGGER # 循环触发
只需要一行文本,你就可以在你的实际任务模型里面引用这个分支。
你可以通过将元素键设置为global@<全局元素id>
和一个任意值来引用全局元素,如下示例:
branches:
MAIN_BRANCH:
# 任务内容
ANOTHER_BRANCH:
# 其它任务分支
global@RECONNECT_EFFECTS: /
global@ANOTHER_EASY_GENERIC_BRANCH: /
全局任务目标
全局任务目标只有一点不同:你仍可以配置goto:
objects:
SOME_OBJECT:
# 普通本地目标
global@COOL_GLOBAL_OBJECT:
goto: OBJECT NEXT_COOL_GLOBAL_OBJECT
global@NEXT_COOL_GLOBAL_OBJECT:
goto: OBJECT ANOTHER_OBJECT
ANOTHER_OBJECT:
# 其它普通本地目标
任务进度检测流程
以下是插件检查一个任务进度时的流程。这适用于常规任务模型。
任务进度会在玩家触发事件(比如破坏方块)或每X刻时进行检测。第二张方式称为“定时器调用”:这种方式是更新服务器目标进度最常使用的。
对每个任务进行检测(所有玩家进行中的任务或所有调用定时器的活跃任务):
确保世界允许
如果调用定时器,则使符合条件的任务回到检查点。
尝试检测每个分支/独立分支的进度:
检查是否还必须等待一定的时间才能开始该分支的当前目标。
如须等待,则不检测该分支
如无须等待,则发送开始该目标的提醒
检测当前目标是否超时
如果超时,则应用失败goto
如果未超时,则发送剩余时间提醒
检测该分支的当前目标,如果尚未完成,
(a) 如果是事件调用:
1. 独立检测分支是否与事件玩家匹配。 2. 检查身份限制是否与事件中的玩家匹配 3. 检测目标的特定设置是否匹配事件(比如方块类型是否正确,是否是玩家放置的方块等 4. 确认匹配位置设置(大多数情况下是玩家位置,少数情况下是方块位置) 5. 确认事件玩家是否有所需物品 6. 确认匹配进度条件是否匹配 > 如果不匹配,则应用失败goto 7. 计算进度成功率 > 如果失败,则应用失败goto 8. (如果设置则)取消事件 9. 计算并应用进度 10. 从事件玩家处获取进度条件 11. 从事件玩家处拿取所需物品
(b) 如果是定时器调用:
1. 检测定时器调用刻是否匹配目标刻 2. (如果设置了‘wait_after_match_fail’则)在检测该目标前等待 3. 检测目标是否取得进展 4. 确认匹配身份的玩家拥有所需物品 5. 确认匹配进度条件(检测匹配身份的玩家) > 如果不匹配,则应用失败goto 6. 计算进度成功率 > 如果失败,则应用失败goto 7. 计算并应用进度 8. 从匹配身份的玩家处获取进度条件 9. 从匹配身份的玩家处拿取所需物品
之后:
(a) 如果调用完成目标且该目标是委托目标,则发送完成提醒。
(b) 如果调用影响目标(取得进展),则发送进度提醒
另外,如果必须按顺序完成委托目标的话,或许可以停止检查目标。(GROUP目标)
(c) 如果调用完全不影响目标:
1. 启用“position_stay”时,确认玩家是否在指定位置 > 如果不在,则发送警告提醒 > 如果玩家长时间未留在指定位置,则执行失败goto 1. 如果玩家离上次任务更新太久未取得进展则发送更新提醒 2. 如果玩家太久未取得进展则重新发送分支目标抉择选项
如果任务受到影响:更新显示 (actionbar/显示/计分板/……)
功能性任务
功能性任务是基本没有用户显示和限制的任务。它对于创建一些特性很有用,你可以用QuestCreator的任务分支/目标轻松地创建功能性任务。你可以用功能性任务做任何事情:当玩家进入一片区域,与一个方块交互,杀死一个实体等时,执行一些效果。你可以使用所有的玩家和服务器目标类型(不包括特殊类型)。
功能性任务实际上并不会被保存,它们在玩家连接时自动启动(根据条件自动启动),并在玩家断开连接时被丢弃。它们无法拥有激活器或结束目标。
它拥有大部分常规任务模型的设置,但没有大部分的用户显示:它没有提醒、显示名、描述、信息、GUI物品等。它也没有一些时间设置,如模型时间限制或冷却。它们不能在多人任务中运行,因为它们是针对每个玩家的,且没有玩家相关的设置。
它位于/quest_models_functional/
。
开发者API
插件包含了一些事件,但由于一切都可以轻易地完成,插件并没有特定的API。我的插件并没有混淆代码。
如果你想要关联QuestCreator而不想购买这款插件,你可以联系我。
确保在你的项目路径中同时包含QuestCreator和GCore,这样你就可以看到所有的自动补全选项。
如有疑问,请勿犹豫,请联系我。
事件
事件无法取消,它只会告诉你有事情发生。它主要用于统计数据或增加额外效果
QuestStartEvent
:在任务开始时调用QuestStopEvent
:在任务完成时调用BranchStartEvent
:在分支开始时调用BranchStopEvent
:在分支停止时调用ObjectCompleteEvent
:在任务目标完成时调用QuestAppliedGotoEvent
:在应用got时调用QueueChangePositionEvent
:在排队中玩家更改队列位置时调用
在这些事件中,当你调用 getQuest()
方法时,你会得到 AbstractQuest
。 如果是进行中的任务Quest
,你将可以获得更多关于它的信息(启动/停止任务的原因等)。
即使功能性任务会触发事件,它也不值得检查(FunctionalQuest)。
数据管理
你可以用UserQC
访问用户数据。
// 检索缓存用户
UserQC user = UserQC.cachedOrNull(player);
// 如果用户不在缓存中,则获取用户,然后做一些事。
// 如果用户不在缓存中且数据被修改,则保存数据,并在回调后丢弃。
UserQC.process(uuid, user -> {
// user was loaded
});
// 如果用户不在缓存中,则获取用户,然后做一些事。
// 如果用户不在缓存中且数据被修改,则保存数据,并在回调后丢弃。
UserQC.processWithQuests(uuid, user -> {
// user was loaded
});
// 你也可以用“UserQC”访问任务数据
user.getCachedActiveQuests().forEach(quest -> {
// process quest
});
您也可以直接从任务板中获取缓存任务。不建议通过任务板获取某个玩家的任务,请使用UserQC来获取。
// get all cached active quests on the server
BoardQuests.inst().getCacheValues().forEach(quest -> {
// process quest
});
自定义目标类型
为了创建自定义元素类型,我们以一个新的任务目标类型作为示例。我建议您查看进度流程,以了解任务调用的大致情况。
首先你需要扩展类型类。以事件目标为例 :
public class TypePlayerBlockFarmCustom extends QuestObjectTypeEventGoalCustom<BlockPlaceEvent> {
public static final QuestObjectEvent EVENT = QuestObjectEvent.register(BlockPlaceEvent.class, "getPlayer");
public TypePlayerBlockFarm(String id) {
super(id, CommonMats.DIRT, PositionNeed.OPTIONAL, AllowItemsNeeded.YES, AllowProgressConditions.YES, EVENT);
}
// call
@Override
protected boolean match(AbstractElementQuestObject object, QuestCallBranchProgress call, ObjectProgression progression, BlockPlaceEvent event, Player eventPlayer) {
if (!event.getBlock().getType().equals(Material.FARMLAND)) {
return false;
}
Mat mat = Mat.fromItem(eventPlayer.getItemInHand()).orNull();
if (mat == null || !mat.getData().getDataName().toUpperCase().contains("_HOE")) {
WorkerQC.inst().logSpam(call.getQuest(), event, eventPlayer, ">>>> found item " + mat + " isn't a hoe");
return false;
}
return true;
}
@Override
protected Location findLocationToMatch(AbstractElementQuestObject object, QuestCallBranchProgress call, BlockPlaceEvent event, Player eventPlayer) {
return event.getBlock().getLocation();
}
}
QuestObjectTypeEventGoalCustom
自动添加在目标设置内,但你也许想要为该目标添加自定义设置。你可以在fill方法内这么做。比如:
// 添加额外几率设置
@Override
protected void doFillSettingsElements(AbstractElementQuestObject object) {
super.doFillSettingsElements(object); // fill other type settings
object.addChancePercentage("extra_chance", Need.OPTIONAL, 0d, new TextElement(CollectionUtils.asList("&7这是我们为该目标添加的额外几率 (editor description)")));
}
// 在匹配方法中,让我们在能够正常继续之前先确保匹配额外的设置。
@Override
protected boolean match(AbstractElementQuestObject object, QuestCallBranchProgress call, ObjectProgression progression, BlockPlaceEvent event, Player eventPlayer) {
// ... other stuff described above
Double configuredExtraChance = object.parseElementAsOrNull("extra_chance", call.getParser()); // retrieve the current value of the setting
if (configuredExtraChance != null && NumberUtils.random(0d, 100d) > configuredExtraChance) {
WorkerQC.inst().logSpam(call.getQuest(), event, eventPlayer, ">>>> we are very unlucky and can't progress the object for this event");
return false;
}
return true;
}
可用于目标的类型类:
QuestObjectTypeEvent
:默认事件类型(你必须手动建立目标)QuestObjectTypeEventGoalDefault
:目标数为1的事件类型QuestObjectTypeEventGoalCustom
:用户可配置的带目标事件类型QuestObjectTypeTimer
:默认定时器类型(你必须手动建立目标)QuestObjectTypeTimerGoalDefault
:目标数为1的定时器类型;在调用后会立即进行QuestObjectTypeTimerAction
:目标数为1的定时器类型;在调用后会立即进行并调用performInstantEffects()方法
之后,你需要在任务目标类型中注册你的目标。
QuestCreator.inst().getQuestObjectTypes().register(new TypePlayerBlockFarmCustom("PLAYER_BLOCK_FARM_CUSTOM"));
TypePlayerBlockFarmCustom.EVENT.registerListener(); // 在示例中,我们必须也要注册事件的监听器
别忘了在插件卸载时取消注册。
QuestCreator.inst().getQuestObjectTypes().unregister("PLAYER_BLOCK_FARM_CUSTOM");
TypePlayerBlockFarmCustom.EVENT.unregisterListener(); // 在示例中,我们必须也要注册事件的监听器
其它自定义类型
你可以注册几乎全部新内容:
- 激活器类型必须扩展
ActivatorType
(或ActivatorTypePhysical
)并用QuestCreator.inst().getActivatorTypes()
注册/取消注册 - 条件类型必须拓展
ConditionType
并用QuestCreator.inst().getConditionTypes()
注册/取消注册 - 分支类型必须拓展
BranchType
并用QuestCreator.inst().getBranchTypes()
注册/取消注册
……