Skip to content

Commit 5cbedb8

Browse files
committed
Quest tracker formatting via minimessage
1 parent 09c4420 commit 5cbedb8

8 files changed

Lines changed: 189 additions & 67 deletions

File tree

modules/src/main/java/parallelmc/parallelutils/modules/parallelquests/ParallelQuests.java

Lines changed: 46 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
package parallelmc.parallelutils.modules.parallelquests;
22

3+
import net.kyori.adventure.key.Key;
4+
import net.kyori.adventure.sound.Sound;
5+
import net.kyori.adventure.text.Component;
6+
import net.kyori.adventure.text.format.NamedTextColor;
37
import org.bukkit.Bukkit;
8+
import org.bukkit.entity.Player;
49
import org.bukkit.plugin.Plugin;
510
import org.bukkit.plugin.PluginManager;
611
import org.jetbrains.annotations.NotNull;
@@ -92,7 +97,13 @@ PRIMARY KEY (Id)
9297
}
9398

9499
Bukkit.getScheduler().runTaskTimer(puPlugin, () -> {
95-
PlayerQuestStatuses.keySet().forEach(u -> savePlayerQuestStatus(u, false));
100+
PlayerQuestStatuses.keySet().forEach(u -> {
101+
Player p = Bukkit.getPlayer(u);
102+
// the quest cache should only contain online players since players are removed when they log off
103+
// regardless, make sure the players we're saving actually exist
104+
if (p == null) return;
105+
savePlayerQuestStatus(p, false);
106+
});
96107
}, 6000L, 6000L); // 5 minutes
97108

98109
Instance = this;
@@ -120,23 +131,36 @@ public Quest getQuest(String questId) {
120131
return RegisteredQuests.get(questId);
121132
}
122133

123-
public Optional<QuestStatus> getQuestStatus(UUID uuid, String questId) {
124-
return getAllQuestStatuses(uuid).stream()
134+
public Optional<QuestStatus> getQuestStatus(Player player, String questId) {
135+
return getAllQuestStatuses(player).stream()
125136
.filter(x -> x.getQuestId().equals(questId))
126137
.findFirst();
127138
}
128139

129140
/**
130141
* Returns a list of quests a player currently has active, as well as if they are completed.
131142
* If a quest ID is not in this list, the player has not accepted it yet.
132-
* @param uuid The player UUID to search
143+
* @param player The Player to search
133144
*/
134-
public List<QuestStatus> getAllQuestStatuses(UUID uuid) {
135-
return PlayerQuestStatuses.getOrDefault(uuid, new ArrayList<>());
145+
public List<QuestStatus> getAllQuestStatuses(Player player) {
146+
return PlayerQuestStatuses.getOrDefault(player.getUniqueId(), new ArrayList<>());
136147
}
137148

138-
public void startQuest(UUID uuid, String questId, String initialStage) {
139-
List<QuestStatus> statuses = getAllQuestStatuses(uuid);
149+
public boolean hasCompletedQuest(Player player, String questId) {
150+
Optional<QuestStatus> status = getQuestStatus(player, questId);
151+
return status.isPresent() && status.get().isCompleted();
152+
}
153+
154+
public void startQuest(Player player, String questId, String initialStage) {
155+
Quest quest = getQuest(questId);
156+
if (quest == null) {
157+
ParallelUtils.log(Level.SEVERE, "Tried to start-nonexistent quest: " + questId);
158+
return;
159+
}
160+
player.sendMessage(Component.text("Quest Accepted: " + quest.getQuestName(), NamedTextColor.GOLD));
161+
player.playSound(Sound.sound(Key.key(Key.MINECRAFT_NAMESPACE, "block.note_block.chime"), Sound.Source.MASTER, 1f, 1f));
162+
UUID uuid = player.getUniqueId();
163+
List<QuestStatus> statuses = getAllQuestStatuses(player);
140164
if (statuses.isEmpty()) {
141165
statuses.add(new QuestStatus(questId, initialStage));
142166
PlayerQuestStatuses.put(uuid, statuses);
@@ -149,10 +173,10 @@ public void startQuest(UUID uuid, String questId, String initialStage) {
149173
statuses.add(new QuestStatus(questId, initialStage));
150174
}
151175

152-
public void setQuestStage(UUID uuid, String questId, String newStage) {
153-
var status = getQuestStatus(uuid, questId);
176+
public void setQuestStage(Player player, String questId, String newStage) {
177+
var status = getQuestStatus(player, questId);
154178
if (status.isEmpty()) {
155-
ParallelUtils.log(Level.WARNING, "Tried to update status of quest " + questId + " for UUID " + uuid + " that has not accepted said quest!");
179+
ParallelUtils.log(Level.WARNING, "Tried to update status of quest " + questId + " for " + player.getName() + " that has not accepted said quest!");
156180
return;
157181
}
158182
status.get().setQuestStage(newStage);
@@ -161,16 +185,16 @@ public void setQuestStage(UUID uuid, String questId, String newStage) {
161185
/**
162186
* Asynchronously loads a player's quest data into the cache.
163187
* If a player's data already exists in the cache, the load will be ignored.
164-
* @param uuid The Player UUID to load
188+
* @param player The Player to load
165189
*/
166-
public void loadPlayerQuestStatus(UUID uuid) {
190+
public void loadPlayerQuestStatus(Player player) {
167191
Bukkit.getScheduler().runTaskAsynchronously(puPlugin, () -> {
168192
List<QuestStatus> result = new ArrayList<>();
169193
try (Connection conn = puPlugin.getDbConn()) {
170194
if (conn == null) throw new SQLException("Unable to establish connection!");
171195
Statement statement = conn.createStatement();
172196
statement.setQueryTimeout(10);
173-
ResultSet results = statement.executeQuery("select * from Quests where UUID = '" + uuid + "'");
197+
ResultSet results = statement.executeQuery("select * from Quests where UUID = '" + player.getUniqueId() + "'");
174198
while (results.next()) {
175199
String questId = results.getString("QuestId");
176200
String questStage = results.getString("QuestStage");
@@ -182,30 +206,30 @@ public void loadPlayerQuestStatus(UUID uuid) {
182206
e.printStackTrace();
183207
}
184208

185-
if (PlayerQuestStatuses.putIfAbsent(uuid, result) != null) {
186-
ParallelUtils.log(Level.WARNING, "UUID " + uuid + " already has an entry in PlayerQuestStatuses, ignoring!");
209+
if (PlayerQuestStatuses.putIfAbsent(player.getUniqueId(), result) != null) {
210+
ParallelUtils.log(Level.WARNING, "UUID " + player.getUniqueId() + " already has an entry in PlayerQuestStatuses, ignoring!");
187211
}
188212
});
189213
}
190214

191215
/**
192216
* Asynchronously saves a player's quest data to the database.
193-
* @param uuid The Player UUID to save
217+
* @param player The Player to save
194218
* @param removeFromCache If true, the data will also be removed from the local cache
195219
*/
196-
public void savePlayerQuestStatus(UUID uuid, boolean removeFromCache) {
220+
public void savePlayerQuestStatus(Player player, boolean removeFromCache) {
197221
Bukkit.getScheduler().runTaskAsynchronously(puPlugin, () -> {
198-
List<QuestStatus> status = getAllQuestStatuses(uuid);
222+
List<QuestStatus> status = getAllQuestStatuses(player);
199223
try (Connection conn = puPlugin.getDbConn()) {
200224
if (conn == null) throw new SQLException("Unable to establish connection!");
201225
Statement statement = conn.createStatement();
202226
statement.setQueryTimeout(10);
203-
statement.execute("delete from Quests where UUID = '" + uuid + "'");
227+
statement.execute("delete from Quests where UUID = '" + player.getUniqueId() + "'");
204228
PreparedStatement prepared = conn.prepareStatement("insert into Quests (UUID, QuestId, QuestStage) values (?, ?, ?)");
205229
prepared.setQueryTimeout(30);
206230
status.forEach(s -> {
207231
try {
208-
prepared.setString(1, uuid.toString());
232+
prepared.setString(1, player.getUniqueId().toString());
209233
prepared.setString(2, s.getQuestId());
210234
prepared.setString(3, s.getQuestStage());
211235
prepared.addBatch();
@@ -222,7 +246,7 @@ public void savePlayerQuestStatus(UUID uuid, boolean removeFromCache) {
222246
e.printStackTrace();
223247
} finally {
224248
if (removeFromCache)
225-
PlayerQuestStatuses.remove(uuid);
249+
PlayerQuestStatuses.remove(player.getUniqueId());
226250
}
227251
});
228252
}

modules/src/main/java/parallelmc/parallelutils/modules/parallelquests/dialogue/Conversation.java

Lines changed: 9 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,6 @@
11
package parallelmc.parallelutils.modules.parallelquests.dialogue;
22

3-
import net.kyori.adventure.text.Component;
4-
import net.kyori.adventure.text.event.ClickEvent;
5-
import net.kyori.adventure.text.event.HoverEvent;
6-
import net.kyori.adventure.text.format.NamedTextColor;
3+
import net.kyori.adventure.text.minimessage.MiniMessage;
74
import org.bukkit.entity.Player;
85
import org.bukkit.map.MinecraftFont;
96

@@ -29,19 +26,17 @@ public void choose(Player player, int index) {
2926
}
3027

3128
private void display(Player player) {
32-
Component message = Component
33-
.text(centerText(dialogue.getSpeaker()), NamedTextColor.YELLOW)
34-
.appendNewline()
35-
.append(Component.text(current.getText(), NamedTextColor.WHITE))
36-
.appendNewline();
29+
StringBuilder sb = new StringBuilder();
30+
sb.append("<yellow>").append(centerText(dialogue.getSpeaker())).append("</yellow><br>")
31+
.append(current.getText()).append("<br>");
32+
3733
for (int i = 0; i < current.getOptions().size(); i++) {
3834
DialogueOption option = current.getOptions().get(i);
39-
message = message.append(Component.text(" ".repeat(5) + option.getText(), NamedTextColor.AQUA)
40-
.clickEvent(ClickEvent.runCommand("/dialogueoption " + i))
41-
.hoverEvent(HoverEvent.showText(Component.text("Click to Select Option " + (i + 1), NamedTextColor.YELLOW)))
42-
).appendNewline();
35+
sb.append("<hover:show_text:'<yellow>Click to select option ").append(i + 1)
36+
.append("</yellow>'><click:run_command:dialogueoption ").append(i).append("><aqua>")
37+
.append(" ".repeat(5)).append(option.getText()).append("</aqua><br>");
4338
}
44-
player.sendMessage(message);
39+
player.sendMessage(MiniMessage.miniMessage().deserialize(sb.toString()));
4540
}
4641

4742
public boolean isFinished() { return !current.hasNext(); }

modules/src/main/java/parallelmc/parallelutils/modules/parallelquests/dialogue/DialogueBuilder.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@ public DialogueBuilder option(String optionText, DialogueBuilder next) {
2828
this.options.add(new DialogueOption(optionText, next.build()));
2929
return this;
3030
}
31-
3231
public DialogueNode build() {
3332
return new DialogueNode(text, options, actions);
3433
}

modules/src/main/java/parallelmc/parallelutils/modules/parallelquests/events/OnCommand.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,13 +36,14 @@ public void onCommand(PlayerCommandPreprocessEvent event) {
3636
else if (message.startsWith("/startdialogue")) {
3737
event.setCancelled(true);
3838
String[] split = event.getMessage().split(" ");
39-
if (split.length != 2) return;
39+
if (split.length != 3) return;
4040
Quest quest = ParallelQuests.get().getQuest(split[1]);
4141
if (quest == null) {
4242
ParallelUtils.log(Level.WARNING, "Got null quest when attempting to start dialogue with quest ID " + split[1]);
4343
return;
4444
}
45-
quest.enter(player);
45+
String npcName = split[2];
46+
quest.enter(player, npcName);
4647
}
4748
}
4849
}

modules/src/main/java/parallelmc/parallelutils/modules/parallelquests/events/OnJoinLeave.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,13 @@
1313
public class OnJoinLeave implements Listener {
1414
@EventHandler(priority = EventPriority.HIGH)
1515
public void onPlayerJoin(PlayerJoinEvent event) {
16-
ParallelQuests.get().loadPlayerQuestStatus(event.getPlayer().getUniqueId());
16+
ParallelQuests.get().loadPlayerQuestStatus(event.getPlayer());
1717
}
1818

1919
@EventHandler(priority = EventPriority.HIGH)
2020
public void onPlayerLeave(PlayerQuitEvent event) {
2121
Player player = event.getPlayer();
22-
ParallelQuests.get().savePlayerQuestStatus(player.getUniqueId(), true);
22+
ParallelQuests.get().savePlayerQuestStatus(player, true);
2323
ParallelQuests.getConversationManager().endConversation(player);
2424
}
2525
}

modules/src/main/java/parallelmc/parallelutils/modules/parallelquests/gui/QuestTrackerInventory.java

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import net.kyori.adventure.text.Component;
44
import net.kyori.adventure.text.format.NamedTextColor;
55
import net.kyori.adventure.text.format.TextDecoration;
6+
import net.kyori.adventure.text.minimessage.MiniMessage;
67
import org.bukkit.Material;
78
import org.bukkit.entity.Player;
89
import org.bukkit.inventory.ItemStack;
@@ -46,7 +47,7 @@ public QuestTrackerInventory() {
4647

4748
@Override
4849
public void onOpen(Player player) {
49-
List<QuestStatus> statuses = ParallelQuests.get().getAllQuestStatuses(player.getUniqueId());
50+
List<QuestStatus> statuses = ParallelQuests.get().getAllQuestStatuses(player);
5051
int slot = 9;
5152
for (QuestStatus status : statuses) {
5253
Quest quest = ParallelQuests.get().getQuest(status.getQuestId());
@@ -58,7 +59,20 @@ public void onOpen(Player player) {
5859
ItemStack entry = new ItemStack(status.isCompleted() ? Material.LIME_CONCRETE : Material.YELLOW_CONCRETE);
5960
ItemMeta meta = entry.getItemMeta();
6061
meta.displayName(Component.text(quest.getQuestName(), NamedTextColor.AQUA).decoration(TextDecoration.ITALIC, false));
61-
meta.lore(List.of(Component.text(quest.getQuestDescription(), NamedTextColor.YELLOW).decoration(TextDecoration.ITALIC, false)));
62+
ArrayList<Component> lore = new ArrayList<>();
63+
for (String line : quest.getQuestDescription()) {
64+
lore.add(MiniMessage.miniMessage().deserialize(line).decoration(TextDecoration.ITALIC, false));
65+
}
66+
lore.add(Component.empty());
67+
lore.add(Component.text("Current Stage:", NamedTextColor.AQUA).decoration(TextDecoration.ITALIC, false));
68+
if (status.isCompleted())
69+
lore.add(Component.text("Completed!", NamedTextColor.GREEN).decoration(TextDecoration.ITALIC, false));
70+
else {
71+
for (String line : quest.getStageDescription(status.getQuestStage())) {
72+
lore.add(MiniMessage.miniMessage().deserialize(line).decoration(TextDecoration.ITALIC, false));
73+
}
74+
}
75+
meta.lore(lore);
6276
entry.setItemMeta(meta);
6377

6478
inventory.setItem(slot, entry);

modules/src/main/java/parallelmc/parallelutils/modules/parallelquests/quests/Quest.java

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,23 +5,38 @@
55
import net.kyori.adventure.text.Component;
66
import net.kyori.adventure.text.format.NamedTextColor;
77
import org.bukkit.entity.Player;
8+
import org.jetbrains.annotations.Nullable;
9+
import parallelmc.parallelutils.ParallelUtils;
810
import parallelmc.parallelutils.modules.parallelquests.ParallelQuests;
911
import parallelmc.parallelutils.modules.parallelquests.dialogue.Dialogue;
1012

13+
import java.util.HashMap;
14+
import java.util.List;
15+
import java.util.logging.Level;
16+
1117
public abstract class Quest {
1218
protected final String questId;
1319
protected final String questName;
14-
protected final String questDescription;
20+
protected final List<String> questDescription;
21+
protected final HashMap<String, List<String>> questStages;
1522

16-
public Quest(String questId, String questName, String questDescription) {
23+
public Quest(String questId, String questName, List<String> questDescription) {
1724
this.questId = questId;
1825
this.questName = questName;
1926
this.questDescription = questDescription;
27+
this.questStages = new HashMap<>();
2028
}
2129

2230
public String getQuestId() { return questId; }
2331
public String getQuestName() { return questName; }
24-
public String getQuestDescription() { return questDescription; }
32+
public List<String> getQuestDescription() { return questDescription; }
33+
public List<String> getStageDescription(String stageId) { return questStages.getOrDefault(stageId, List.of()); }
34+
35+
protected void registerStageDescription(String stageId, List<String> description) {
36+
if (questStages.putIfAbsent(stageId, description) != null) {
37+
ParallelUtils.log(Level.WARNING, "Duplicate stage description for stage ID " + stageId + " in quest " + questId + ", ignoring!");
38+
}
39+
}
2540

2641
protected void registerDialogue(String dialogueId, Dialogue dialogue) {
2742
ParallelQuests.getConversationManager().registerDialogue(dialogueId, dialogue);
@@ -32,7 +47,7 @@ protected void showDialogue(Player player, String dialogueId) {
3247
}
3348

3449
protected void setQuestStage(Player player, String stage) {
35-
ParallelQuests.get().setQuestStage(player.getUniqueId(), questId, stage);
50+
ParallelQuests.get().setQuestStage(player, questId, stage);
3651
}
3752

3853
protected void completeQuest(Player player) {
@@ -43,5 +58,7 @@ protected void completeQuest(Player player) {
4358

4459
public abstract void init();
4560

46-
public abstract void enter(Player player);
61+
public abstract void enter(Player player, String npcName);
62+
63+
public abstract List<String> prerequisites();
4764
}

0 commit comments

Comments
 (0)