Quests предоставя прост API за създаване на персонализирани изисквания, награди и цели. Като начало се уверете, че компилирате спрямо версия 4.0.0 или по-нова. След като приключите с това ръководство, използвайте папката /Quests/modules като дестинация за вашия завършен и компилиран jar. Ако разпространявате вашия модул, не забравяйте да информирате крайния потребител за правилното местоположение на папката.
Requirements API
Изграждането на изискване на задача е много просто. За да започнете, създайте Java клас, който разширява класа като CustomRequirement. След това вижте този пример за персонализирано изискване, при което играчът трябва да има конкретно име, за да вземе задачата:
packagexyz.janedoe;importjava.util.Map;importorg.bukkit.entity.Player;importme.pikamug.quests.module.BukkitCustomRequirement;publicclassNameRequirementextendsBukkitCustomRequirement {// Construct the requirementpublicNameRequirement() {setName("Name Requirement");setAuthor("Jane Doe");setItem("NAME_TAG", (short)0);addStringPrompt("Name","Enter value that player's name must contain in order to take the Quest",null);addStringPrompt("Case-Sensitive","Should the check be case-sensitive or not? (Enter \'true\' or \'false\')",null);setDisplay("Sorry, you are not on the list."); }// Test whether a player has met the requirement @OverridepublicbooleantestRequirement(Player player,Map<String,Object> data) {String caseSensitive = (String) data.get("Case-Sensitive");// Check whether the name must be case-sensitiveif (caseSensitive.equalsIgnoreCase("true")) {// Mark the requirement as satisfied if name matchesreturnplayer.getName().contains((String)data.get("Name")); } else {// Mark the requirement as satisfied if name matches, ignoring casereturnplayer.getName().toLowerCase().contains(((String)data.get("Name")).toLowerCase()); } }}
В конструктора на вашия клас можете да използвате някой от следните методи:
Методи
Описание
setName
Задава името на персонализираната цел.
setAuthor
Задава автора на персонализираната цел (ти!).
setItem
Задайте елемент, който може да се появи в плъгин за наслагване като QuestsGUI.
setDisplay
Задава как изискването да се показва при неуспех.
addStringPrompt
Добавя нова подкана за радактор с указано заглавие, описание и стойност по подразбиране за вашата персонализирана цел. Редактора на задачи може да въведе низ, който зависи от вас да анализирате
Вътре в #testRequirement е мястото където изпълнявате вашата логика, за да определите дали играчът преминава изискването, връщайки 'true', ако го направи, и 'false' ако не го направи.
Картата с данни съдържа данните, които лицето, създало задачата, й е дало. В този пример картата на данните съдържа двете стойности за „Име“ и „Отчитане на малки и големи букви“. Също така имайте предвид, че въпреки че стойностите са от тип Object, те са преобразувани вътрешно към тип String. Трябва да извършите ръчно преобразуване на типа, ако искате да получите integers, booleans стойности и др.
Rewards API
Изграждането на награда за задачи е много просто. За да започнете, създайте Java клас, който разширява класа CustomReward. След това вижте този пример за персонализирана награда, при която играчът получава GUI инвентар, който се появява, съдържащ желязо, злато и диаманти:
packagexyz.janedoe;importjava.util.Map;importorg.bukkit.Bukkit;importorg.bukkit.Material;importorg.bukkit.entity.Player;importorg.bukkit.inventory.Inventory;importorg.bukkit.inventory.ItemStack;importme.pikamug.quests.module.BukkitCustomReward;importjava.util.UUID;publicclassLootRewardextendsBukkitCustomReward {// Construct the rewardpublicLootReward() {setName("Loot Reward");setAuthor("Jane Doe");setItem("CHEST", (short)0);setDisplay("Loot Chest: %Title%");addStringPrompt("Title","Title of the loot inventory interface.",null);addStringPrompt("NumIron","Enter the number of iron ingots to give in the loot chest.",null);addStringPrompt("NumGold","Enter the number of gold ingots to give in the loot chest.",null);addStringPrompt("NumDiamond","Enter the number of diamonds to give in the loot chest.",null); }// Give loot reward to a player @OverridepublicvoidgiveReward(UUID uuid,Map<String,Object> data) {finalPlayer player =Bukkit.getPlayer(uuid);if (player ==null) {Bukkit.getLogger().severe("Player was null for UUID "+ uuid);return; }String title = (String) data.get("Title");int numIron =0;int numGold =0;int numDiamond =0;// Attempt to load user input as integerstry { numIron =Integer.parseInt((String) data.get("NumIron")); } catch (NumberFormatException nfe) {Bukkit.getLogger().severe("Loot Reward has invalid Iron number: "+ numIron); }try { numGold =Integer.parseInt((String) data.get("NumGold")); } catch (NumberFormatException nfe) {Bukkit.getLogger().severe("Loot Reward has invalid Gold number: "+ numGold); }try { numDiamond =Integer.parseInt((String) data.get("NumDiamond")); } catch (NumberFormatException nfe) {Bukkit.getLogger().severe("Loot Reward has invalid Diamond number: "+ numDiamond); }// Create a temporary inventory to add items toInventory inv =Bukkit.getServer().createInventory(player,3, title);int slot =0;// Check if amount is greater than default valueif (numIron >0) {// Add item to current slot in temporary inventory, then get next slot readyinv.setItem(slot,newItemStack(Material.IRON_INGOT, numIron >64?64: numIron)); slot++; }if (numGold >0) {inv.setItem(slot,newItemStack(Material.GOLD_INGOT, numGold >64?64: numGold)); slot++; }if (numDiamond >0) {inv.setItem(slot,newItemStack(Material.DIAMOND, numDiamond >64?64: numDiamond)); }// Open temporary inventory for player to accept itemsplayer.openInventory(inv); }}
В конструктора на вашия клас можете да използвате някой от следните методи
Методи
Описание
setName
Задава името на персонализираната цел.
setAuthor
Задава автора на персонализираната цел (ти!).
setItem
Задайте елемент, който може да се появи в плъгин за наслагване като QuestsGUI.
setDisplay
Задава как изискването да се показва при неуспех.
addStringPrompt
Добавя нова подкана за радактор с указано заглавие, описание и стойност по подразбиране за вашата персонализирана цел. Редактора на задачи може да въведе низ, който зависи от вас да анализирате
Вътре в #giveReward е мястото където изпълнявате вашата логика, за да определите дали играчът преминава изискването, връщайки 'true', ако го направи, и 'false' ако не го направи.
Objectives API
Изграждането на цел за задача е малко по-сложно от изискванията или наградите. За да започнете, създайте Java клас, който разширява класа CustomObjective. Ако искате да хванете някой Event от Bukkit, ще трябва да внедрите класа Listener (Quests ще се погрижи за регистрацията на събитието вместо вас). След това вижте тези примери за персонализираната цел:
// Player must gain a certain amount of experience to advancepackagexyz.janedoe;importme.pikamug.quests.module.BukkitCustomObjective;importme.pikamug.quests.Quest;importme.pikamug.quests.Quests;importorg.bukkit.Bukkit;importorg.bukkit.event.EventHandler;importorg.bukkit.event.player.PlayerExpChangeEvent;publicclassExperienceObjectiveextendsBukkitCustomObjective {// Get the Quests pluginQuests qp = (Quests) Bukkit.getServer().getPluginManager().getPlugin("Quests");// Construct the objectivepublicExperienceObjective() {setName("Experience Objective");setAuthor("Jane Doe");setItem("BOOK", (short)0);setShowCount(true);setCountPrompt("Enter the experience points that the player must acquire:");setDisplay("Acquire experience points: %count%"); }// Catch the Bukkit event for a player gaining/losing exp @EventHandlerpublicvoidonPlayerExpChange(PlayerExpChangeEvent evt) {Quester quester =qp.getQuester(evt.getPlayer().getUniqueId());// Make sure to evaluate for all of the player's current questsfor (Quest quest :qp.getQuester(evt.getPlayer().getUniqueId()).getCurrentQuests().keySet()) {// Check if the player gained exp, rather than lostif (evt.getAmount() >0) {// Add to the objective's progress, completing it if requirements were metincrementObjective(evt.getPlayer(),this,evt.getAmount(), quest);// Optional: Share progress with party members (if applicable)quester.dispatchMultiplayerEverything(quest,ObjectiveType.CUSTOM, (finalQuester q,finalQuest cq) -> {incrementObjective(q.getUUID(),this, quest,evt.getAmount());returnnull; }); } } }}
// Require the player to drop a certain number of a certain type of item.packagexyz.janedoe;importme.pikamug.quests.module.BukkitCustomObjective;importme.pikamug.quests.Quest;importme.pikamug.quests.Quests;importorg.bukkit.Bukkit;importorg.bukkit.entity.EntityType;importorg.bukkit.event.EventHandler;importorg.bukkit.event.player.PlayerDropItemEvent;importorg.bukkit.inventory.ItemStack;publicclassDropItemObjectiveextendsBukkitCustomObjective {// Get the Quests pluginQuests qp = (Quests) Bukkit.getServer().getPluginManager().getPlugin("Quests");// Construct the objectivepublicDropItemObjective() {this.setName("Drop Item Objective");this.setAuthor("Jane Doe");this.setItem("ANVIL", (short)0);this.setShowCount(true);this.setCountPrompt("Enter the amount that the player must drop:");this.setDisplay("Drop %Item Name%: %count%");this.addStringPrompt("Item Name","Enter the name of the item that the player must drop","DIRT"); }// Catch the Bukkit event for a player dropping an item @EventHandlerpublicvoidonPlayerDropItem(PlayerDropItemEvent evt){// Make sure to evaluate for all of the player's current questsfor (Quest quest :qp.getQuester(evt.getPlayer().getUniqueId()).getCurrentQuests().keySet()) {Map<String,Object> map =getDataForPlayer(evt.getPlayer(),this, quest);if (map ==null) {continue; }ItemStack stack =evt.getItemDrop().getItemStack();String userInput = (String) map.get("Item Name");EntityType type =EntityType.fromName(userInput);// Display error if user-specified item name is invalidif (type ==null) {Bukkit.getLogger().severe("Drop Item Objective has invalid item name: "+ userInput);continue; }// Check if the item the player dropped is the one user specifiedif (evt.getItemDrop().getItemStack().getType().equals(type)) {// Add to the objective's progress, completing it if requirements were metincrementObjective(evt.getPlayer().getUniqueId(),this, quest,stack.getAmount()); } } }}
// Allow player to break ANY block rather than a specific onepackagexyz.janedoe;importme.pikamug.quests.module.BukkitCustomObjective;importme.pikamug.quests.Quest;importme.pikamug.quests.Quests;importorg.bukkit.Bukkit;importorg.bukkit.entity.Player;importorg.bukkit.event.EventHandler;importorg.bukkit.event.EventPriority;importorg.bukkit.event.block.BlockBreakEvent;publicclassAnyBreakBlockObjectiveextendsBukkitCustomObjective {// Get the Quests pluginprivatestaticQuests quests = (Quests) Bukkit.getServer().getPluginManager().getPlugin("Quests");publicAnyBreakBlockObjective() {setName("Break Blocks Objective");setAuthor("Jane Doe");setItem("DIRT", (short)0);setShowCount(true);addStringPrompt("Obj Name","Set a name for the objective","Break ANY block");setCountPrompt("Set the amount of blocks to break");setDisplay("%Obj Name%: %count%"); } @EventHandler(priority =EventPriority.LOW)publicvoidonBlockBreak(BlockBreakEvent event) {Player player =event.getPlayer();for (Quest q :quests.getQuester(player.getUniqueId()).getCurrentQuests().keySet()) {incrementObjective(player.getUniqueId(),this, q,1);return; } }}
В конструктора на вашия клас можете да използвате някой от следните методи:
Методи
Описание
setName
Задава името на персонализираната цел.
setAuthor
Задава автора на персонализираната цел (ти!).
setItem
Задайте елемент, който може да се появи в плъгин за наслагване като QuestsGUI.
setShowCount
Определя дали редакторът на задачи може да задавя броя (брой пъти, когато играчът трябва да повтори целта). По подразбиране е "true". Това ще се прилага за всички подкани, дабавени с #addStringPrompt, освен ако не е забранено.
setCountPrompt
Задава подканящото описание за потребителя да въведе броя за целта. По подразбиране е "Въведете номер".
setDisplay
Задава начина, по който целта се показва в "/quests list" и дневника на задачите. За контейнерите използвайте %count%, за да получите стойността на #setShowCount, и #addStringPrompt заглавия за въвеждане от потребителя (като "Item Name" във втория пример). По подразбиране е "Progress: %count%".
addStringPrompt
Добавя нова подкана за радактор с указано заглавие, описание и стойност по подразбиране за вашата персонализирана цел. Редактора на задачи може да въведе низ, който зависи от вас да анализирате
Във вашият EventHandlers (ако е приложимо), определете дали играчът е изпълнил част или цялата цел и след това използвайте #incrementObjective, за да напреднете играча. Първият и вторият аргумент на #incrementObjective винаги трябва да бъдат съответно играчът и 'this'. Третият аргумент е с колко да се увеличи целта, докато последният е търсенете, към което да се приложи увеличението. Дори ако вашата цел няма брой, пак трябва да използвате #incrementObjective - използвайте увеличение от 1, за да сигнализирате, че целта е изпълнена.
Map<String, Object> съдържа данните, предоставени от редактора на задачи. В този пример ключовете за данни са имената на елементите, докато стойностите са въведените от потребителя за вашата подкана (която може да бъде null). Също така имайте предвид, че въпреки, че стойностите са от тип Object, те са преобразувани вътрешно към тип String. Трябва да извършите ръчно преобразуване на типа, ако искате да получите цели integers, booleans стойности и др.