Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
9a2cb34
setup new features
wsaada19 Nov 24, 2024
5717259
cleanup
wsaada19 Nov 24, 2024
a086a14
imports
wsaada19 Nov 24, 2024
e8e04ee
Merge branch 'main' into modelIds-quest-history-and-auto-rewards
wsaada19 Nov 25, 2024
dc0f605
Merge branch 'main' into modelIds-quest-history-and-auto-rewards
wsaada19 Nov 27, 2024
c79ffcd
ad history menu, new quests and stuff
wsaada19 Nov 28, 2024
3b3352a
Merge branch 'main' into modelIds-quest-history-and-auto-rewards
wsaada19 Nov 28, 2024
84e2ed7
add tab completions, improve filtering logic for event constraints
wsaada19 Nov 29, 2024
4148a32
Update README.md
wsaada19 Nov 29, 2024
8e7da20
potion quest updates / levelup event
wsaada19 Nov 29, 2024
c8cf835
save quest complete message with rewards, give reward, fix reload bre…
wsaada19 Nov 30, 2024
4d1a2ae
Update ServerQuests.java
wsaada19 Nov 30, 2024
1d1fed1
cut enchantments string
wsaada19 Nov 30, 2024
ad061c3
Merge branch 'main' into modelIds-quest-history-and-auto-rewards
wsaada19 Nov 30, 2024
5e371fd
fix double schedule, code cleanup and finalize quest filter testing
wsaada19 Dec 1, 2024
04d0337
Merge branch 'main' into modelIds-quest-history-and-auto-rewards
wsaada19 Dec 1, 2024
70c054c
add more tab completes
wsaada19 Dec 1, 2024
8268380
add bStats
wsaada19 Dec 2, 2024
b02f338
begin adding logic for collective quest type
wsaada19 Dec 3, 2024
52fc1e9
new quest type / rename for clarity
wsaada19 Dec 7, 2024
c900b43
cleanup code, test modelIds and new quest type
wsaada19 Dec 8, 2024
dd7f8fc
cleanup
wsaada19 Dec 8, 2024
2b4d7cb
fix issue with placeholder/holograms, better # formatting
wsaada19 Feb 1, 2025
db22676
bug fixes
wsaada19 Feb 8, 2025
91ca15c
cleanup
wsaada19 May 31, 2025
f76184a
Merge branch 'main' into modelIds-quest-history-and-auto-rewards
wsaada19 Jun 11, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 35 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,10 @@ Claims rewards for a specific player. Rewards are directly given to the user

Clear all rewards for a specific player. Do not specify a player name if you want to clear rewards for all players.

### /cq history

Opens a UI with historical quest information and data

## Configuration

The config.yml is used to configure quests in the plugin. Once the quests have been created you can start them using the /cq start command.
Expand Down Expand Up @@ -147,6 +151,17 @@ objectives:
description: Oak Saplings
```

### Objective filters

The quest above uses the `materials` filter so the first objective looks for `ACACIA_SAPLINGS` on a blockplace event and then second objective looks for `OAK_SAPLING`. Both objectives run concurrently. For block related events, materials is the only valid filter but there are six more filters you can use. If no constraints are provided (or you provide an invalid material name!), the quest will count all events of that type!

- **materials** - use to specify the material type of blocks or items
- **entities** - use to specify the entity type of mobs for quests like mobKill, projectileKill and tameevent. It's also used in the catchfish event and the mythicmob event.
- **customNames** - use to specify the custom name of both mobs and items. This can be used for custom mobs or renamed items.
- **modelIds** - use to specify the model id of items. This can be used for custom items with a specific model id in custom model plugins like oraxen.
- **potions** - use to specify the potion type for the brewpotion event. For example, `AWKWARD` or `FIRE_RESISTANCE`.
- **enchants** - use to specify the enchantment type for the enchantitem event. For example, `DAMAGE_ALL` or `PROTECTION_ENVIRONMENTAL`.

The quest below requires you to kill 15 zombified piglins and 10 zombie pigmen. For mob related quests you can use the customNames field to specify the name of the mob you want to kill. If you want to kill a specific mob type you can use the entities field and specify the mob type from the [entity list](https://hub.spigotmc.org/javadocs/bukkit/org/bukkit/entity/EntityType.html).

```yaml
Expand Down Expand Up @@ -227,6 +242,10 @@ Rewards example
```yaml
rewards:
rewardsLimit: 5 # only top 5 contributors get the rewards, if not set or 0 then everyone gets rewards
rewardDisplay: # If this is set it will show the rewards in the quest view
- "REWARDS!"
- "1 Iron Sword"
- "50 Experience"
rankedRewards:
"1": # The key is the rank of the player
experience: 100
Expand Down Expand Up @@ -275,26 +294,26 @@ rewards:
displayName: "&capples"
```

## Competitive vs. Cooperative
## Quest Types

There are two quest types to chose from: competitive and cooperative. If you're using the GUI which is opened from the /sp start command, after choosing the quest you'd like to run you're presented with a
GUI to pick the type. You can also do /cq start [QuestId] [coop/comp].
There are three quest types to chose from: competitive, cooperative and collective. If you're using the GUI which is opened from the /sp start command, after choosing the quest you'd like to run you're presented with a
GUI to pick the type. You can also do /cq start [QuestId] [coop/comp/coll].

### Cooperative

Cooperative quests involve everyone on the server working together to complete the goal. For example in the quest created in the configuration section, the quest will be complete once 100 zombies, pigs, and zombie pigmen have been killed. Note: This means 100 total of
any combination of zombies/pigs/zombie pigman kills that add to 100. If questDuration is set then the player's must complete the quest in the given time limit.
If the quest is not completed no rewards will be given out.
In cooperative quests player's work together to reach a goal. For example, if the quest has 3 objectives: kill 100 zombies, kill 100 pigmen and kill 200 skeletons. Players will need to reach all 3 of those objectives together to win the rewards. If questDuration is set, the player's must complete the quest before the time limit is reached to get the rewards.

Player's are rewarded based on how much they contribute to the quest. If the reward is 1000
money and PlayerX kills 50 of the 100 zombies, PlayerX will receive 500. Item and command rewards are given to every player who contributes to the quest. You can use the **_rewardsLimit_** field in the rewards section of the config if you only want the top x number of players to get a reward.
Player's are rewarded based on how much they contribute to the quest. If the reward is 1000 money and PlayerX kills 50 of the 100 zombies, PlayerX will receive 500. Item and command rewards are given to every player who contributes to the quest. You can use the **_rewardsLimit_** field in the rewards section of the config if you only want the top x number of players to get a reward. You can also set rewards for specific ranks using the **_rankedRewards_** field.

### Competitive

Competitive quests put the players against each other to see who can complete a goal first. Using our zombie/pig example
from above, the quest will end once a single player gets 100 kills for the correct mob types. If a time limit is set and the quest ends before the goal is reached the top players will still get rewards based on their contributions.
In competitive quests, players compete to see who can reach the objective first. If goals are set on the objectives then the quest ends when the first player completes them. If a time limit is set then a goal is no required, and once the timer runs out players will be rewarded based on their ranking.

Money/experience awards work the same way as cooperative quests. If the money reward is 1000 the winner of the competition will get 1000. If Player1 came in second with 70 kills, he or she will get 700. The winner is the only person who will get items and commands in a competitive quest. Think of it as more of a challenge than a quest.
Money/experience rewards work the same way as cooperative quests. If the money reward is 1000 the winner of the competition will get 1000. If Player1 came in second with 70 kills, he or she will get 700. The winner is the only person who will get items and commands in a competitive quest, unless rewards are specified for specific rankings.

### Collective

In a collective quest, all player's are working toward the same goal. Like competitive quests, the goal is tracked individually for each player, but when a player reaches the goal the quest doesn't end. The quest must have a duration and will end when the timer runs out. All player's who reach the goal will be eligible for rewards, you can use ranked rewards to reward player's based on who finishes the quest first.

## Objectives

Expand All @@ -320,7 +339,6 @@ Fishing:
experience: 100
```

- **playerkill**: kill other players
- **blockbreak**: break a block specified in the materials list in the configuration
- **blockplace**: place a block specified in the materials list in the configuration
- **projectilekill**: kill entities with a projectile specify entities in the configuration
Expand All @@ -332,6 +350,10 @@ Fishing:
- **enchantitem**: enchant something
- **money**: players can contribute money with /cq deposit <amount>
- **experience**: players must gather Minecraft experience
- **level**: players must levelup
- **furnace**: use furnace to smelt or cook an item
- **brewpotion**: brew potions
- **playerkill**: kill other players
- **carvepumpkin**: use shears on a pumpkin
- **mythicmob**: Kill mobs from the mythicmob plugin (requires MythicMobs to be installed)
- **movement**: travel a certain distance in blocks
Expand Down Expand Up @@ -486,7 +508,7 @@ You can directly configure schedules in `schedules.yml`:
```yaml
12345678-example:
questId: "mining" # Quest identifier
mode: "coop" # Mode: "coop" or "comp"
mode: "coop" # Mode: "coop", "comp" or "coll"
time: "14:30" # 24-hour format (HH:mm)
scheduleType: "DAILY" # DAILY, WEEKLY, or CUSTOM_DAYS
interval: 1 # Days between runs (for CUSTOM_DAYS only)
Expand Down
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

<groupId>me.wonka01</groupId>
<artifactId>CommunityQuests</artifactId>
<version>2.11.5</version>
<version>2.12.0</version>

<contributors>
<contributor>
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/me/knighthat/apis/files/Getters.java
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package me.knighthat.apis.files;

import lombok.NonNull;
import me.knighthat.apis.utils.Colorization;
import me.wonka01.ServerQuests.ServerQuests;
import me.wonka01.ServerQuests.utils.Colorization;

public abstract class Getters extends PluginFiles implements Colorization {

Expand Down
16 changes: 11 additions & 5 deletions src/main/java/me/knighthat/apis/menus/Menu.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@
import me.wonka01.ServerQuests.questcomponents.QuestController;
import me.wonka01.ServerQuests.questcomponents.QuestData;
import me.wonka01.ServerQuests.questcomponents.schedulers.ParseDurationString;
import me.knighthat.apis.utils.Colorization;
import me.wonka01.ServerQuests.utils.Colorization;

import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.entity.Player;
Expand Down Expand Up @@ -65,10 +66,15 @@ protected void onClose(@NonNull final InventoryCloseEvent event) {
}

public void open() {
setBorder();
setButtons();
setContents();
owner.openInventory(inventory);
try {
setBorder();
setButtons();
setContents();
owner.openInventory(inventory);
} catch (Exception exception) {
Bukkit.getLogger().warning("Error opening menu: " + exception.getMessage());
exception.printStackTrace();
}
}

protected @NonNull ItemStack createItemStack(@NonNull Material m, @NonNull String n) {
Expand Down
41 changes: 36 additions & 5 deletions src/main/java/me/wonka01/ServerQuests/ServerQuests.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,27 @@

import lombok.Getter;
import lombok.NonNull;
import me.knighthat.apis.files.Config;
import me.knighthat.apis.files.Messages;
import me.knighthat.apis.menus.MenuEvents;
import me.wonka01.ServerQuests.commands.CommandManager;
import me.wonka01.ServerQuests.configuration.Config;
import me.wonka01.ServerQuests.configuration.JsonQuestSave;
import me.wonka01.ServerQuests.configuration.QuestHistoryManager;
import me.wonka01.ServerQuests.events.*;
import me.wonka01.ServerQuests.questcomponents.ActiveQuests;
import me.wonka01.ServerQuests.questcomponents.bossbar.BarManager;
import me.wonka01.ServerQuests.questcomponents.bossbar.BossbarPlayerInfo;
import me.wonka01.ServerQuests.questcomponents.hologram.DecentHologramsDisplay;
import me.wonka01.ServerQuests.questcomponents.rewards.RewardJoinListener;
import me.wonka01.ServerQuests.questcomponents.rewards.RewardManager;
import me.wonka01.bStats.Metrics;
import me.wonka01.placeholders.CommunityQuestsPlaceholders;
import net.milkbowl.vault.economy.Economy;

import java.util.concurrent.Callable;

import org.bukkit.Bukkit;
import org.bukkit.command.PluginCommand;
import org.bukkit.plugin.RegisteredServiceProvider;
import org.bukkit.plugin.java.JavaPlugin;

Expand All @@ -36,10 +42,15 @@ public class ServerQuests extends JavaPlugin {
private boolean isPlaceholderApiEnabled;
@Getter
private CommandManager commandManager;
@Getter
private QuestHistoryManager questHistoryManager;

@Override
public void onEnable() {
this.commandManager = new CommandManager(this);
PluginCommand pluginCommand = getCommand("communityquests");
pluginCommand.setExecutor(commandManager);
pluginCommand.setTabCompleter(commandManager);

loadSaveData();

Expand All @@ -60,9 +71,10 @@ public void onEnable() {
}

registerPlaceholders();
if (!setupDecentHologram() && getConfig().getBoolean("hologram.enabled")) {
getLogger().info("Warning! DecentHolograms not found, holograms will not work.");
} else {
if (!setupDecentHologram()) {
getLogger()
.info("Warning! DecentHolograms not found or no placeholder api found, holograms will not work.");
} else if (getConfig().getBoolean("hologram.enabled")) {
hologram = new DecentHologramsDisplay(this);
hologram.displayHologram();
}
Expand All @@ -71,6 +83,21 @@ public void onEnable() {
registerQuestEvents();
RewardManager.getInstance().populateFromJsonFile(getDataFolder(), getLogger());
BossbarPlayerInfo.getInstance().loadFromJsonFile(getDataFolder());
questHistoryManager = new QuestHistoryManager(this, getDataFolder());

int pluginId = 24062;

try {
Metrics metrics = new Metrics(this, pluginId);
metrics.addCustomChart(new Metrics.SingleLineChart("active_quests", new Callable<Integer>() {
@Override
public Integer call() throws Exception {
return ActiveQuests.getActiveQuestsInstance().getActiveQuestsList().size();
}
}));
} catch (Exception e) {
getLogger().info("[Community Quests] Failed to submit metrics data for bstats");
}
getLogger().info("Plugin is enabled");
}

Expand Down Expand Up @@ -121,7 +148,9 @@ private boolean setupMythicMobs() {
}

private boolean setupDecentHologram() {
return Bukkit.getPluginManager().getPlugin("DecentHolograms") != null;
boolean isEnabled = Bukkit.getPluginManager().getPlugin("DecentHolograms") != null && isPlaceholderApiEnabled;
getLogger().info("DecentHolograms enabled: " + isEnabled);
return isEnabled;
}

private void registerQuestEvents() {
Expand All @@ -140,6 +169,8 @@ private void registerQuestEvents() {
getServer().getPluginManager().registerEvents(new ConsumeItemQuestEvent(activeQuests), this);
getServer().getPluginManager().registerEvents(new EnchantItemQuestEvent(activeQuests), this);
getServer().getPluginManager().registerEvents(new DistanceTraveled(activeQuests), this);
getServer().getPluginManager().registerEvents(new InventoryClickEvents(activeQuests, this), this);
getServer().getPluginManager().registerEvents(new RewardJoinListener(true), this);
try {
getServer().getPluginManager().registerEvents(new ExperienceEvent(activeQuests), this);
getServer().getPluginManager().registerEvents(new HarvestEvent(activeQuests), this);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@
import me.wonka01.ServerQuests.questcomponents.rewards.RewardEntry;
import me.wonka01.ServerQuests.questcomponents.rewards.RewardManager;

import java.util.List;

import org.bukkit.Bukkit;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
Expand Down Expand Up @@ -75,4 +78,10 @@ public void execute(@NonNull CommandSender sender, @NotNull @NonNull String[] ar
rewards.removeRewards(player.getUniqueId());
}
}

@Override
public List<String> onTabComplete(CommandSender sender, Command command, String alias, String[] args) {
// TODO Auto-generated method stub
return null;
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package me.wonka01.ServerQuests.commands;

import java.util.List;

import org.bukkit.Bukkit;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;

Expand Down Expand Up @@ -57,4 +60,9 @@ public void execute(CommandSender sender, String[] args) {
}
}

@Override
public List<String> onTabComplete(CommandSender sender, Command command, String alias, String[] args) {
// TODO Auto-generated method stub
return null;
}
}
36 changes: 33 additions & 3 deletions src/main/java/me/wonka01/ServerQuests/commands/CommandManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,14 @@
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.command.TabCompleter;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.Nullable;

import java.util.ArrayList;
import java.util.List;

public class CommandManager implements CommandExecutor {
public class CommandManager implements CommandExecutor, TabCompleter {

private final ServerQuests plugin;

Expand All @@ -35,11 +36,11 @@ public CommandManager(ServerQuests plugin) {
commands.add(new DonateCommand(plugin));
commands.add(new MoneyCommand(plugin));
commands.add(new ToggleBarCommand(plugin));
commands.add(new ToggleMessageCommand(plugin));
commands.add(new RewardsCommand(plugin));
commands.add(new EndAllCommand(plugin));
commands.add(new ClaimRewards(plugin));
commands.add(new ClearRewardsCommand(plugin));
commands.add(new HistoryCommand(plugin));
this.questScheduler = new QuestScheduler(plugin);
commands.add(this.questScheduler);
}
Expand All @@ -57,11 +58,40 @@ public boolean onCommand(CommandSender sender, Command command, String label, St
return true;
}

@Override
public List<String> onTabComplete(CommandSender sender, Command command, String alias, String[] args) {
List<String> completions = new ArrayList<>();
if (args.length == 1) {
for (PluginCommand cmd : commands) {
if (cmd.getName().startsWith(args[0].toLowerCase())) {
if (cmd.isPlayerCommand() && !(sender instanceof Player))
break;

if (cmd.getPermission().isEmpty() || sender.hasPermission(cmd.getPermission()))
completions.add(cmd.getName());
}
}
}

if (args.length > 1) {
for (PluginCommand cmd : commands) {
if (cmd.getName().equalsIgnoreCase(args[0])) {
// Check if the command implements a tab complete method
List<String> comps = cmd.onTabComplete(sender, command, alias, args);
if (comps != null)
return comps;
break;
}
}
}
return completions;
}

private @Nullable PluginCommand getCommand(@NonNull CommandSender sender, @NonNull String arg) {
for (PluginCommand cmd : commands)
if (cmd.getName().equalsIgnoreCase(arg)) {

if (cmd.isRequiresPlayer() && !(sender instanceof Player))
if (cmd.isPlayerCommand() && !(sender instanceof Player))
break;

if (cmd.getPermission().isEmpty() || sender.hasPermission(cmd.getPermission()))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import me.wonka01.ServerQuests.questcomponents.QuestController;

import org.bukkit.Bukkit;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
Expand Down Expand Up @@ -71,4 +72,10 @@ public void execute(@NonNull CommandSender sender, @NotNull @NonNull String[] ar

player.sendMessage(noActiveQuest);
}

@Override
public List<String> onTabComplete(CommandSender sender, Command command, String alias, String[] args) {
// TODO Auto-generated method stub
return null;
}
}
Loading