Fixed quests not saving to YML. New quest-level option to disable bossbar. New option to disable on the bossbar the % of completion of current objective. Updated default files

This commit is contained in:
Jules 2025-10-14 01:19:23 +02:00
parent e5ecd46611
commit 08aaa82a7a
12 changed files with 183 additions and 87 deletions

View File

@ -32,6 +32,11 @@ public abstract class ObjectiveProgress implements Closeable {
return questProgress;
}
public double getProgress() {
// default to 0, maybe ppl implemented quest objectives
return 0;
}
@Override
public void close() {
if (this instanceof Listener)

View File

@ -6,6 +6,7 @@ import io.lumine.mythic.lib.gson.JsonObject;
import io.lumine.mythic.lib.util.Closeable;
import net.Indyuce.mmocore.MMOCore;
import net.Indyuce.mmocore.api.player.PlayerData;
import org.apache.commons.lang3.Validate;
import org.bukkit.Bukkit;
import org.bukkit.NamespacedKey;
import org.bukkit.boss.BarColor;
@ -24,27 +25,25 @@ import java.util.logging.Level;
public class PlayerQuests implements Closeable {
private final PlayerData playerData;
private final Map<String, Long> finished = new HashMap<>();
@Nullable
private final BossBar bossbar;
private final NamespacedKey bossbarNamespacedKey;
@Nullable
private BossBar bossbar;
private QuestProgress current;
public PlayerQuests(PlayerData playerData) {
this.playerData = playerData;
if (!MMOCore.plugin.configManager.disableQuestBossBar && playerData.isOnline()) {
bossbarNamespacedKey = new NamespacedKey(MMOCore.plugin, "mmocore_quest_progress_" + playerData.getUniqueId().toString());
bossbar = Bukkit.createBossBar(bossbarNamespacedKey, "", BarColor.PURPLE, BarStyle.SEGMENTED_20);
bossbar.addPlayer(playerData.getPlayer());
bossbar.setVisible(false); // Safety
bossbarNamespacedKey = new NamespacedKey(MMOCore.plugin, "quest_progress_" + playerData.getUniqueId());
/*
Bukkit.getScheduler().runTaskTimer(MMOCore.plugin, () -> {
// Bossbar is disabled
} else {
bossbarNamespacedKey = null;
bossbar = null;
}
Bukkit.broadcastMessage("bossbar=" + bossbar);
Bukkit.broadcastMessage("current=" + current);
}, 20, 20);
*/
}
public PlayerQuests load(ConfigurationSection config) {
@ -69,6 +68,8 @@ public class PlayerQuests implements Closeable {
return this;
}
//region DB
public void save(ConfigurationSection config) {
if (current != null) {
config.set("current.id", current.getQuest().getId());
@ -93,7 +94,7 @@ public class PlayerQuests implements Closeable {
for (String key : finished.keySet())
fin.addProperty(key, finished.get(key));
if (finished.size() != 0)
if (!finished.isEmpty())
json.add("finished", fin);
return json.toString();
}
@ -114,6 +115,8 @@ public class PlayerQuests implements Closeable {
finished.put(entry.getKey(), entry.getValue().getAsLong());
}
//endregion DB
public QuestProgress getCurrent() {
return current;
}
@ -135,6 +138,7 @@ public class PlayerQuests implements Closeable {
}
public void finishCurrent() {
Validate.notNull(current, "No ongoing quest");
finished.put(current.getQuest().getId(), System.currentTimeMillis());
start(null);
}
@ -147,35 +151,36 @@ public class PlayerQuests implements Closeable {
return new Date(finished.get(quest.getId()));
}
public void start(Quest quest) {
public void start(@Nullable Quest quest) {
// Close current objective progress if quest is active
closeCurrentQuest();
cancelCurrentQuest();
// Apply newest quest
current = quest == null ? null : quest.generateNewProgress(playerData);
updateBossBar();
}
public void closeCurrentQuest() {
if (current == null)
return;
public void cancelCurrentQuest() {
if (current == null) return;
current.getProgress().close();
current = null;
}
@Deprecated
public void closeCurrentQuest() {
cancelCurrentQuest();
}
@Override
public void close() {
// Remove boss bar
if (bossbar != null) {
bossbar.removeAll();
Bukkit.removeBossBar(bossbarNamespacedKey);
}
if (bossbar != null) deleteBossbar();
// Close current objective progress
closeCurrentQuest();
// Close only progress
if (current != null) current.getProgress().close();
}
public boolean checkCooldownAvailability(Quest quest) {
@ -193,20 +198,50 @@ public class PlayerQuests implements Closeable {
return true;
}
public void updateBossBar() {
//region Bossbar
// Bossbar is disabled
if (bossbar == null)
return;
if (!hasCurrent() || !current.getProgress().getObjective().hasLore()) {
bossbar.setVisible(false);
return;
}
private boolean isBossbarRelevant() {
return !MMOCore.plugin.configManager.disableQuestBossBar
&& current != null
&& current.getQuest().usesBossbar();
}
private void initializeBossbar() {
Validate.isTrue(this.bossbar == null, "Tried to create a new bossbar while one already exists");
this.bossbar = Bukkit.createBossBar(bossbarNamespacedKey, "", BarColor.PURPLE, BarStyle.SEGMENTED_20);
bossbar.addPlayer(playerData.getPlayer());
bossbar.setVisible(true);
}
private void deleteBossbar() {
Validate.notNull(this.bossbar, "Bossbar is null");
bossbar.removeAll();
Bukkit.removeBossBar(bossbarNamespacedKey);
this.bossbar = null;
}
public void updateBossBar() {
final var flag = isBossbarRelevant();
final var enabled = bossbar != null;
// Initialize/remove if needed
if (enabled && !flag) deleteBossbar();
else if (!enabled && flag) initializeBossbar();
// Bossbar
if (bossbar == null) return;
final var bossbarProgress = current.getQuest().isObjectiveBossbar()
// Fine tuned progress
? current.getProgress().getProgress()
// Based on objective number
: (double) current.getObjectiveNumber() / current.getQuest().getObjectives().size();
bossbar.setColor(current.getProgress().getObjective().getBarColor());
bossbar.setTitle(current.getFormattedLore());
bossbar.setProgress((double) current.getObjectiveNumber() / current.getQuest().getObjectives().size());
bossbar.setProgress(bossbarProgress);
}
//endregion
}

View File

@ -20,6 +20,7 @@ public class Quest implements PreloadedObject {
private final List<Objective> objectives = new ArrayList<>();
private final List<String> lore;
private final int mainLevelRestriction;
private final boolean useBossbar, objectiveBossbar;
private final Map<Profession, Integer> levelRestrictions = new HashMap<>();
// Cooldown in millis
@ -40,6 +41,8 @@ public class Quest implements PreloadedObject {
cooldown = (long) (config.contains("delay") ? config.getDouble("delay") * 60 * 60 * 1000 : -1);
name = config.getString("name");
lore = config.getStringList("lore");
objectiveBossbar = config.getBoolean("bossbar.objective", true);
useBossbar = config.getBoolean("bossbar.enabled", true);
mainLevelRestriction = config.getInt("level-req.main");
@ -80,6 +83,14 @@ public class Quest implements PreloadedObject {
return id;
}
public boolean usesBossbar() {
return useBossbar;
}
public boolean isObjectiveBossbar() {
return objectiveBossbar;
}
public String getName() {
return name;
}

View File

@ -8,7 +8,7 @@ public class QuestProgress {
private final Quest quest;
private final PlayerData player;
private int objective;
private int objectiveIndex;
private ObjectiveProgress objectiveProgress;
public QuestProgress(Quest quest, PlayerData player) {
@ -19,7 +19,7 @@ public class QuestProgress {
this.quest = quest;
this.player = player;
this.objective = objective;
this.objectiveIndex = objective;
objectiveProgress = nextObjective().newProgress(this);
}
@ -32,7 +32,7 @@ public class QuestProgress {
}
public int getObjectiveNumber() {
return objective;
return objectiveIndex;
}
public ObjectiveProgress getProgress() {
@ -40,18 +40,19 @@ public class QuestProgress {
}
private Objective nextObjective() {
return quest.getObjectives().get(objective);
return quest.getObjectives().get(objectiveIndex);
}
public void completeObjective() {
objective++;
objectiveIndex++;
objectiveProgress.close();
final ObjectiveProgress finishedObjectiveProgress = objectiveProgress;
final var finishedObjectiveProgress = objectiveProgress;
// Start next objective, or end quest.
if (objective >= quest.getObjectives().size()) player.getQuestData().finishCurrent();
if (objectiveIndex >= quest.getObjectives().size()) player.getQuestData().finishCurrent();
else objectiveProgress = nextObjective().newProgress(this);
// Update bossbar
player.getQuestData().updateBossBar();
/*

View File

@ -31,13 +31,13 @@ public class ClickonObjective extends Objective {
}
@Override
public ObjectiveProgress newProgress(QuestProgress questProgress) {
return new GotoProgress(questProgress, this);
public GotoProgress newProgress(QuestProgress questProgress) {
return new GotoProgress(questProgress);
}
public class GotoProgress extends ObjectiveProgress implements Listener {
public GotoProgress(QuestProgress questProgress, Objective objective) {
super(questProgress, objective);
public GotoProgress(QuestProgress questProgress) {
super(questProgress, ClickonObjective.this);
}
@EventHandler
@ -51,6 +51,11 @@ public class ClickonObjective extends Objective {
getQuestProgress().completeObjective();
}
@Override
public double getProgress() {
return 1d;
}
@Override
public String formatLore(String lore) {
return lore;

View File

@ -29,18 +29,20 @@ public class GoToObjective extends Objective {
}
@Override
public ObjectiveProgress newProgress(QuestProgress questProgress) {
return new GotoProgress(questProgress, this);
public GotoProgress newProgress(QuestProgress questProgress) {
return new GotoProgress(questProgress);
}
public class GotoProgress extends ObjectiveProgress implements Listener {
public GotoProgress(QuestProgress questProgress, Objective objective) {
super(questProgress, objective);
public GotoProgress(QuestProgress questProgress) {
super(questProgress, GoToObjective.this);
}
@EventHandler
public void a(PlayerMoveEvent event) {
if (event.getFrom().getBlockX() == event.getTo().getBlockX() && event.getFrom().getBlockY() == event.getTo().getBlockY() && event.getFrom().getBlockZ() == event.getTo().getBlockZ())
if (event.getFrom().getBlockX() == event.getTo().getBlockX()
&& event.getFrom().getBlockY() == event.getTo().getBlockY()
&& event.getFrom().getBlockZ() == event.getTo().getBlockZ())
return;
Player player = event.getPlayer();
@ -50,6 +52,11 @@ public class GoToObjective extends Objective {
}
}
@Override
public double getProgress() {
return 1d;
}
@Override
public String formatLore(String lore) {
return lore;

View File

@ -23,26 +23,32 @@ public class KillMobObjective extends Objective {
}
@Override
public ObjectiveProgress newProgress(QuestProgress questProgress) {
return new KillMobProgress(questProgress, this);
public KillMobProgress newProgress(QuestProgress questProgress) {
return new KillMobProgress(questProgress);
}
public class KillMobProgress extends ObjectiveProgress implements Listener {
private int count;
public KillMobProgress(QuestProgress questProgress, Objective objective) {
super(questProgress, objective);
public KillMobProgress(QuestProgress questProgress) {
super(questProgress, KillMobObjective.this);
}
@EventHandler
public void a(PlayerKillEntityEvent event) {
if(!getPlayer().isOnline()) return;
if (event.getTarget().getType() == type && event.getPlayer().equals(getPlayer().getPlayer())) {
count++;
getQuestProgress().getPlayer().getQuestData().updateBossBar();
if (count >= required)
getQuestProgress().completeObjective();
}
@EventHandler
public void a(PlayerKillEntityEvent event) {
if (!getPlayer().isOnline()) return;
if (event.getTarget().getType() == type && event.getPlayer().equals(getPlayer().getPlayer())) {
count++;
getQuestProgress().getPlayer().getQuestData().updateBossBar();
if (count >= required)
getQuestProgress().completeObjective();
}
}
@Override
public double getProgress() {
return (double) count / required;
}
@Override

View File

@ -54,6 +54,11 @@ public class MineBlockObjective extends Objective {
}
}
@Override
public double getProgress() {
return (double) count / required;
}
@EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
public void b(CustomBlockMineEvent event) {
if(!getQuestProgress().getPlayer().isOnline()) return;

View File

@ -2,9 +2,7 @@ package net.Indyuce.mmocore.api.quest.trigger;
import io.lumine.mythic.lib.api.MMOLineConfig;
import io.lumine.mythic.lib.message.SoundReader;
import io.lumine.mythic.lib.version.Sounds;
import net.Indyuce.mmocore.api.player.PlayerData;
import org.bukkit.Sound;
public class SoundTrigger extends Trigger {
private final SoundReader sound;

View File

@ -1,30 +1,37 @@
# Display options
name: 'The Beginning of an Adventure'
lore:
- 'Yet another quest example.'
- ''
- '&eRewards:'
- '&7► Stone Tools'
- '&7► 30 EXP'
- 'Yet another quest example.'
- ''
- '&eRewards:'
- '&7► Stone Tools'
- '&7► 30 EXP'
# Parent quests
parent:
- 'tutorial'
- 'tutorial'
bossbar:
# Enable bossbar during the quest
enabled: true
# If true, it will display the percent of progress of the
# current objective. If false, it will display the percent of
# total quest progress (for instance, 33% = 1/3 objectives completed).
objective: true
# Quest objectives
objectives:
1:
type: 'goto{world="world";x=120;y=46;z=652;range=10}'
lore: 'Head to the camp.'
triggers:
- 'message{format="Good job!"}'
2:
type: 'talkto{npc=0}'
lore: 'Go talk to the Blacksmith.'
triggers:
- 'message{format="The blacksmith told you to come see me... ?"}'
- 'item{type=STONE_SWORD}'
- 'item{type=STONE_AXE}'
- 'item{type=STONE_PICKAXE}'
- 'experience{amount=30}'
1:
type: 'goto{world="world";x=120;y=46;z=652;range=10}'
lore: 'Head to the camp.'
triggers:
- 'message{format="Good job!"}'
2:
type: 'talkto{npc=0}'
lore: 'Go talk to the Blacksmith.'
triggers:
- 'message{format="The blacksmith told you to come see me... ?"}'
- 'item{type=STONE_SWORD}'
- 'item{type=STONE_AXE}'
- 'item{type=STONE_PICKAXE}'
- 'experience{amount=30}'

View File

@ -19,6 +19,14 @@ parent: []
# Put it to 0 to make it instantly redoable.
delay: 0
bossbar:
# Enable bossbar during the quest
enabled: true
# If true, it will display the percent of progress of the
# current objective. If false, it will display the percent of
# total quest progress (for instance, 33% = 1/3 objectives completed).
objective: true
# Objectives the player needs to
# complete. Once they're all complete,
# the quest will end.

View File

@ -27,6 +27,14 @@ parent: []
# Put it to 0 to make it instantly redoable.
delay: 12
bossbar:
# Enable bossbar during the quest
enabled: true
# If true, it will display the percent of progress of the
# current objective. If false, it will display the percent of
# total quest progress (for instance, 33% = 1/3 objectives completed).
objective: true
# Objectives the player needs to
# complete. Once they're all complete,
# the quest will end.