Skip to content
This repository has been archived by the owner on Mar 8, 2022. It is now read-only.

Commit

Permalink
[skip-ci]quest claim/verification/cancellation #31
Browse files Browse the repository at this point in the history
  • Loading branch information
RecursiveG committed Sep 23, 2017
1 parent 2308427 commit ed56c0d
Show file tree
Hide file tree
Showing 7 changed files with 154 additions and 84 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,12 @@ public void postQuest(CommandSender sender, Arguments args) {
msg(sender, "user.quest.not_station");
return;
}

if (!plugin.eco.enoughMoney(asPlayer(sender), station.postingFee)) {
msg(sender, "user.quest.wizard.not_enough_money_posting");
return;
}

new QuestWizard(station.id, asPlayer(sender), 30);
}

Expand Down
163 changes: 88 additions & 75 deletions src/main/java/cat/nyaa/HamsterEcoHelper/quest/QuestCommon.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,14 @@
import cat.nyaa.HamsterEcoHelper.utils.database.tables.quest.QuestEntry;
import cat.nyaa.HamsterEcoHelper.utils.database.tables.quest.QuestInstance;
import cat.nyaa.HamsterEcoHelper.utils.database.tables.quest.QuestStation;
import cat.nyaa.nyaacore.database.BaseDatabase;
import cat.nyaa.nyaacore.utils.InventoryUtils;
import net.milkbowl.vault.item.Items;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.OfflinePlayer;
import org.bukkit.entity.Player;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;

import java.time.ZonedDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

Expand Down Expand Up @@ -76,7 +73,7 @@ public static void claimQuest(Player player, String questId) {
throw new RuntimeException("user.quest.menu.reject_unfinished");
}

if (!quest.claimable) throw new RuntimeException("user.quest.menu.reject_unavailable");
if (!quest.claimable || quest.masked) throw new RuntimeException("user.quest.menu.reject_unavailable");
if (quest.isExpired()) throw new RuntimeException("user.quest.menu.reject_expired");
// TODO prereq etc.

Expand All @@ -88,13 +85,15 @@ public static void claimQuest(Player player, String questId) {
q.status = IN_PROGRESS;
q.startTime = ZonedDateTime.now();

quest.claimable = false;

db.query(QuestEntry.class).whereEq("id", questId).update(quest, "claimable");
if (!quest.isRecurrentQuest) {
quest.claimable = false;
db.query(QuestEntry.class).whereEq("id", questId).update(quest, "claimable");
}
db.query(QuestInstance.class).insert(q);
}
}

/* Check the database for all in-progress quest of this player and submit them */
public static void submitQuest(Player player) {
String playerId = player.getUniqueId().toString();
Database db = HamsterEcoHelper.instance.database;
Expand All @@ -104,112 +103,126 @@ public static void submitQuest(Player player) {
.select();
for (QuestInstance q : quests) {
String questId = q.questId;
QuestEntry e = selectUniqueUnchecked(db.query(QuestEntry.class).whereEq("id", questId));
// TODO reset quest claimable
QuestEntry e = db.query(QuestEntry.class).whereEq("id", questId).selectUniqueUnchecked();
if (e == null) {
player.sendMessage(I18n.format("user.quest.submit.no_entry", questId));
q.status = CANCELLED;
db.query(QuestInstance.class).update(q, "status");
q.status = INVALID;
q.endTime = ZonedDateTime.now();
db.query(QuestInstance.class).whereEq("id", q.id).update(q, "status", "end_time");
continue;
}

player.sendMessage(I18n.format("user.quest.submit.submitting", e.questName));

if (!e.completedInTime(q.startTime)) {
player.sendMessage(I18n.format("user.quest.submit.timeout"));
q.status = TIMEOUT;
db.query(QuestInstance.class).update(q, "status");
q.endTime = ZonedDateTime.now();
if (!e.isRecurrentQuest && !e.isExpired()) {
e.claimable = true;
db.query(QuestEntry.class).whereEq("id", e.id).update(e, "claimable");
}
db.query(QuestInstance.class).whereEq("id", q.id).update(q, "status", "end_time");
continue;
}

if (e.targetType == QuestEntry.QuestType.OTHER) {
player.sendMessage(I18n.format("user.quest.submit.need_verification"));
UUID publisherId = UUID.fromString(e.publisher);
if (Bukkit.getPlayer(publisherId) != null) Bukkit.getPlayer(publisherId).sendMessage(
I18n.format("user.quest.quest_need_verify", player.getName(), e.questName));
q.status = UNVERIFIED;
db.query(QuestInstance.class).update(q, "status");
q.endTime = ZonedDateTime.now();
db.query(QuestInstance.class).whereEq("id", q.id).update(q, "status", "end_time");
} else if (e.targetType == QuestEntry.QuestType.ITEM) {
List<ItemStack> ret = withdrawInventoryAtomic(player.getInventory(), e.targetItems);
List<ItemStack> ret = InventoryUtils.withdrawInventoryAtomic(player.getInventory(), e.targetItems);
if (ret == null) {
// TODO return target item to publisher notification.
//for (ItemStack item : e.targetItems) Utils.giveItem(Bukkit.getOfflinePlayer(UUID.fromString(e.publisher)), item);
UUID publisherId = UUID.fromString(e.publisher);
for (ItemStack item : e.targetItems) Utils.giveItem(Bukkit.getOfflinePlayer(publisherId), item);
msgIfOnline(e.publisher, "user.quest.quest_complete_by");
switch (e.rewardType) {
case ITEM: for (ItemStack i : e.rewardItem) Utils.giveItem(player, i); break;
case MONEY: HamsterEcoHelper.instance.eco.deposit(player, e.rewardMoney); break;
default: break;
}
q.status = COMPLETED;
// TODO update endTime
db.query(QuestInstance.class).update(q, "status");
q.endTime = ZonedDateTime.now();
db.query(QuestInstance.class).whereEq("id", q.id).update(q, "status", "end_time");
player.sendMessage(I18n.format("user.quest.submit.quest_complete", e.id));
} else {
player.sendMessage(I18n.format("user.quest.submit.target_not_satisfy", e.id));
}
} else {
player.sendMessage(I18n.format("user.quest.submit.bad_target_type", e.id));
q.status = CANCELLED;
db.query(QuestInstance.class).update(q, "status");
q.status = INVALID;
q.endTime = ZonedDateTime.now();
db.query(QuestInstance.class).whereEq("id", q.id).update(q, "status", "end_time");
}



}
}

// TODO move to NC
private static <T> T selectUniqueUnchecked(BaseDatabase.Query<T> q) {
try {
return q.selectUnique();
} catch (RuntimeException ex) {
return null;
public static void confirmQuest(String questInstanceId, boolean confirmed) {
Database db = HamsterEcoHelper.instance.database;
QuestInstance questInstance = db.query(QuestInstance.class).whereEq("id", questInstanceId).selectUnique();
if (questInstance.status != UNVERIFIED) throw new IllegalArgumentException("quest status incorrect, expecting UNVERIFIED: " + questInstanceId);
QuestEntry questEntry = db.query(QuestEntry.class).whereEq("id", questInstance.questId).selectUnique();
UUID claimerId = UUID.fromString(questInstance.claimer);
if (!confirmed) {
msgIfOnline(claimerId, "user.quest.rejected", questEntry.questName);
questInstance.status = QuestInstance.QuestStatus.REJECTED;
db.query(QuestInstance.class).whereEq("id", questInstanceId).update(questInstance, "status");
if (!questEntry.isRecurrentQuest && !questEntry.isExpired()) {
questEntry.claimable = true;
db.query(QuestEntry.class).whereEq("id", questEntry.id).update(questEntry, "claimable");
}
} else {
OfflinePlayer claimer = Bukkit.getOfflinePlayer(claimerId);
switch (questEntry.rewardType) {
case ITEM: for (ItemStack i : questEntry.rewardItem) Utils.giveItem(claimer, i); break;
case MONEY: HamsterEcoHelper.instance.eco.deposit(claimer, questEntry.rewardMoney); break;
default: break;
}
questInstance.status = COMPLETED;
db.query(QuestInstance.class).whereEq("id", questInstanceId).update(questInstance, "status");
msgIfOnline(claimerId, "user.quest.verified", questEntry.questName);
}
}

/**
* Remove items from inventory.
* Either all removed or none removed.
* @param inv the inventory
* @param itemToBeTaken items to be removed
* @return If null, then all designated items are removed. If not null, it contains the items missing
* TODO move to NC
*/
private static List<ItemStack> withdrawInventoryAtomic(Inventory inv, List<ItemStack> itemToBeTaken) {
ItemStack[] itemStacks = inv.getContents();
ItemStack[] cloneStacks = new ItemStack[itemStacks.length];
for (int i = 0; i < itemStacks.length; i++) {
cloneStacks[i] = itemStacks[i] == null ? null : itemStacks[i].clone();
public static void cancelQuest(String questInstanceId) {
Database db = HamsterEcoHelper.instance.database;
QuestInstance questInstance = db.query(QuestInstance.class).whereEq("id", questInstanceId).selectUnique();
if (questInstance.status != IN_PROGRESS && questInstance.status != UNVERIFIED)
throw new IllegalArgumentException("quest status incorrect, expecting IN_PROGRESS or UNVERIFIED: " + questInstanceId);
QuestEntry questEntry = db.query(QuestEntry.class).whereEq("id", questInstance.questId).selectUnique();
msgIfOnline(questInstance.claimer, "user.quest.cancelled", questEntry.questName);
questInstance.status = QuestInstance.QuestStatus.CANCELLED;
questInstance.endTime = ZonedDateTime.now();
db.query(QuestInstance.class).whereEq("id", questInstance.id).update(questInstance, "status", "end_time");
if (!questEntry.isRecurrentQuest && !questEntry.isExpired()) {
questEntry.claimable = true;
db.query(QuestEntry.class).whereEq("id", questEntry.id).update(questEntry, "claimable");
}
}

List<ItemStack> ret = new ArrayList<>();

for (ItemStack item : itemToBeTaken) {
int sizeReq = item.getAmount();

for (int i = 0; i < cloneStacks.length;i++) {
if (cloneStacks[i] == null) continue;
if (cloneStacks[i].isSimilar(item)) {
int sizeSupp = cloneStacks[i].getAmount();
if (sizeSupp > sizeReq) {
cloneStacks[i].setAmount(sizeSupp - sizeReq);
sizeReq = 0;
break;
} else {
cloneStacks[i] = null;
sizeReq -= sizeSupp;
if (sizeReq == 0) break;
}
}
}
public static void withdrawQuest(String questEntryId) {
Database db = HamsterEcoHelper.instance.database;
QuestEntry questEntry = db.query(QuestEntry.class).whereEq("id", questEntryId).selectUnique();
for (QuestInstance qi : db.query(QuestInstance.class).whereEq("questId", questEntryId).select())
if (qi.status == IN_PROGRESS || qi.status == UNVERIFIED)
cancelQuest(qi.id);
questEntry.masked = true;
db.query(QuestEntry.class).whereEq("id", questEntryId).update(questEntry, "masked");
msgIfOnline(questEntry.publisher, "user.quest.withdrawn", questEntry.questName);
}

if (sizeReq > 0) {
ItemStack n = item.clone();
item.setAmount(sizeReq);
ret.add(n);
}
}
private static void msgIfOnline(String id, String template, Object... objs) {;
UUID uid = UUID.fromString(id);
msgIfOnline(uid, template, objs);
}

if (ret.size() == 0) {
inv.setContents(cloneStacks);
return null;
} else {
return ret;
private static void msgIfOnline(UUID uid, String template, Object... objs) {
if (Bukkit.getPlayer(uid) != null) {
Bukkit.getPlayer(uid).sendMessage(I18n.format(template, objs));
}
}

}
42 changes: 39 additions & 3 deletions src/main/java/cat/nyaa/HamsterEcoHelper/quest/QuestWizard.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import cat.nyaa.HamsterEcoHelper.I18n;
import cat.nyaa.HamsterEcoHelper.utils.Utils;
import cat.nyaa.HamsterEcoHelper.utils.database.tables.quest.QuestEntry;
import cat.nyaa.HamsterEcoHelper.utils.database.tables.quest.QuestStation;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.Material;
Expand Down Expand Up @@ -78,6 +79,8 @@ enum State {
WAITING_TIME_LIMIT,
WAITING_EXPIRE_IN,

WAITING_ICON_MATERIAL, // TODO

WAITING_IS_RECURRENT,
WAITING_CLAIM_LIMIT,
WAITING_ENABLED,
Expand All @@ -95,10 +98,15 @@ public QuestWizard(String stationUUID, Player p, int timeoutSeconds) {
entry.publisher = p.getUniqueId().toString();
entry.stationId = stationUUID;
state = State.WAITING_NAME;
p.sendMessage(I18n.format("user.quest.wizard." + state.name().toLowerCase()));
Bukkit.getServer().getPluginManager().registerEvents(this, HamsterEcoHelper.instance);
timer = new Timer(timeout);
this.reallyTakeItem = !p.hasPermission("heh.quest.admin");
Bukkit.getScheduler().runTaskLater(HamsterEcoHelper.instance, new Runnable() {
@Override
public void run() {
p.sendMessage(I18n.format("user.quest.wizard." + state.name().toLowerCase()));
}
}, 1L);
}

private void cancelWizard() {
Expand Down Expand Up @@ -205,9 +213,15 @@ public void onPlayerChat(PlayerChatEvent ev) {
try {
player.sendMessage(input);
double money = Double.parseDouble(input);
if (reallyTakeItem) {
if (!HamsterEcoHelper.instance.eco.enoughMoney(player, money)) {
player.sendMessage(I18n.format("user.quest.wizard.not_enough_money"));
break;
}
HamsterEcoHelper.instance.eco.withdraw(player, money);
}
entry.rewardMoney = money;
state = WAITING_TIME_LIMIT;
HamsterEcoHelper.instance.eco.withdraw(player, money);
} catch (NumberFormatException ex) {
player.sendMessage(I18n.format("user.quest.wizard.invalid_number"));
}
Expand Down Expand Up @@ -236,10 +250,32 @@ public void onPlayerChat(PlayerChatEvent ev) {
}
entry.questExpire = ZonedDateTime.now().plus(dur);
}
state = reallyTakeItem ? FINISH : WAITING_IS_RECURRENT;
break;
case WAITING_IS_RECURRENT:
entry.isRecurrentQuest = "yes".equalsIgnoreCase(input);
state = reallyTakeItem ? FINISH : WAITING_ENABLED;
break;
case WAITING_ENABLED:
entry.claimable = "yes".equalsIgnoreCase(input);
entry.masked = !entry.claimable;
state = FINISH;
break;
case FINISH:
entry.claimable = true;
if (reallyTakeItem) {
entry.claimable = true;
QuestStation station = HamsterEcoHelper.instance.database.query(QuestStation.class).whereEq("id", this.station.toString()).selectUniqueUnchecked();
if (station == null) {
player.sendMessage(I18n.format("user.quest.wizard.station_invalid", this.station.toString()));
cancelWizard();
return;
}
if (!HamsterEcoHelper.instance.eco.enoughMoney(player, station.postingFee)) {
player.sendMessage(I18n.format("user.quest.wizard.not_enough_money_posting"));
break;
}
HamsterEcoHelper.instance.eco.withdraw(player, station.postingFee); // TODO system balance
}
entry.iconMaterial = Material.BOOK_AND_QUILL.name();
HamsterEcoHelper.instance.database.query(QuestEntry.class).insert(entry);
HandlerList.unregisterAll(this);
Expand Down
5 changes: 3 additions & 2 deletions src/main/java/cat/nyaa/HamsterEcoHelper/utils/Utils.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import cat.nyaa.HamsterEcoHelper.HamsterEcoHelper;
import cat.nyaa.nyaacore.utils.InventoryUtils;
import cat.nyaa.nyaacore.utils.ItemStackUtils;
import cat.nyaa.nyaacore.utils.ReflectionUtils;
import com.google.common.io.BaseEncoding;
import org.bukkit.Bukkit;
Expand Down Expand Up @@ -98,7 +99,7 @@ public static String getItemName(ItemStack item) {
}

public static String encodeItemStack(ItemStack item) {
byte[] nbt = ReflectionUtils.dumpRawNbt(item);
byte[] nbt = ItemStackUtils.toBinaryNbt(item);
byte[] compressedNbt = null;
try {
Deflater compresser = new Deflater();
Expand Down Expand Up @@ -135,7 +136,7 @@ public static ItemStack decodeItemStack(String item) {
decompresser.end();
bos.close();
nbt = bos.toByteArray();
return ReflectionUtils.loadItemStackFromNbt(nbt);
return ItemStackUtils.fromBinaryNbt(nbt);
} catch (DataFormatException | IOException ex) {
throw new RuntimeException(ex);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ public enum QuestType {
public Long singlePlayerClaimLimit = -1L; // how many time a single player can claim this quest, valid only if is recurrent quest
@DataColumn
public String iconMaterial = "";
@DataColumn
public Boolean masked = false;

public QuestType prerequisiteType = QuestType.NONE; // NONE, ITEM or MONEY
public List<ItemStack> prerequisiteItems = new ArrayList<>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ public enum QuestStatus {

COMPLETED,
CANCELLED,
REJECTED,
TIMEOUT,
INVALID;
}
Expand Down
Loading

0 comments on commit ed56c0d

Please sign in to comment.