Add a base layer for challenges.
Implement a challenge system. This allows players to work towards them and add some goals to reach. Demo challenges are included in file challenges.yml. This should provide details on how to create your own challenges. --------- Co-authored-by: Teriuihi <teriuihi@alttd.com>
This commit is contained in:
parent
53d4549573
commit
efc6b62b2f
|
|
@ -0,0 +1,9 @@
|
|||
package com.alttd.cometskyblock.api.challenges;
|
||||
|
||||
public enum ChallengeDifficulty {
|
||||
EASY,
|
||||
MEDIUM,
|
||||
HARD,
|
||||
LEGENDARY,
|
||||
EXOTIC
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
package com.alttd.cometskyblock.api.challenges;
|
||||
|
||||
public enum ChallengeType {
|
||||
/**
|
||||
* Player must have the items to turn in
|
||||
*/
|
||||
ON_PLAYER,
|
||||
/**
|
||||
* Requirements must be on the island
|
||||
*/
|
||||
ON_ISLAND,
|
||||
/**
|
||||
* Island level requirement
|
||||
*/
|
||||
ISLAND_LEVEL;
|
||||
|
||||
public static ChallengeType of(String challengeType) {
|
||||
if (challengeType == null || challengeType.isEmpty())
|
||||
return null;
|
||||
return switch (challengeType.toUpperCase()) {
|
||||
case "ON_PLAYER" -> ChallengeType.ON_PLAYER;
|
||||
case "ON_ISLAND" -> ChallengeType.ON_ISLAND;
|
||||
case "ISLAND_LEVEL" -> ChallengeType.ISLAND_LEVEL;
|
||||
default -> null;
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -9,12 +9,19 @@ dependencies {
|
|||
|
||||
compileOnly("org.projectlombok:lombok:1.18.24")
|
||||
annotationProcessor("org.projectlombok:lombok:1.18.24")
|
||||
|
||||
testImplementation("org.junit.jupiter:junit-jupiter-api:5.8.1")
|
||||
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.8.1")
|
||||
}
|
||||
|
||||
tasks {
|
||||
jar {
|
||||
archiveFileName.set("${rootProject.name}-${project.name}.jar")
|
||||
}
|
||||
|
||||
test {
|
||||
useJUnitPlatform()
|
||||
}
|
||||
}
|
||||
|
||||
bukkit {
|
||||
|
|
@ -32,12 +39,12 @@ bukkit {
|
|||
permission = "${rootProject.name}.command.island"
|
||||
}
|
||||
|
||||
register("Challenges") {
|
||||
register("challenges") {
|
||||
description = "Opens the challenges menu."
|
||||
permission = "${rootProject.name}.command.island"
|
||||
}
|
||||
|
||||
register("cometskyblock") {
|
||||
register("skyblock") {
|
||||
description = "${rootProject.name} admin command."
|
||||
permission = "${rootProject.name}.command.admin"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,8 @@
|
|||
package com.alttd.cometskyblock;
|
||||
|
||||
import com.alttd.cometskyblock.challenges.ChallengeHandler;
|
||||
import com.alttd.cometskyblock.challenges.ChallengeLoader;
|
||||
import com.alttd.cometskyblock.commands.admin.SkyBlockCommand;
|
||||
import com.alttd.cometskyblock.commands.challenges.ChallengeCommand;
|
||||
import com.alttd.cometskyblock.commands.island.IslandCommand;
|
||||
import com.alttd.cometskyblock.configuration.*;
|
||||
|
|
@ -25,12 +28,13 @@ public class CometSkyBlockPlugin extends JavaPlugin implements CometSkyBlockAPI
|
|||
@Getter private ConfigurationContainer<PluginConfiguration> pluginConfiguration;
|
||||
@Getter private ConfigurationContainer<DatabaseConfiguration> databaseConfiguration;
|
||||
@Getter private ConfigurationContainer<MessageConfiguration> messagesConfiguration;
|
||||
@Getter private ConfigurationContainer<ChallengesConfiguration> challengesConfiguration;
|
||||
@Getter private ConfigurationContainer<CobblestoneGeneratorConfiguration> cobblestoneGeneratorConfiguration;
|
||||
@Getter private ConfigurationContainer<WorldBorderConfiguration> worldBorderConfiguration;
|
||||
|
||||
@Getter private IslandManager islandManager;
|
||||
@Getter private MasterWorldGenerator worldGenerator;
|
||||
@Getter private ChallengeHandler challengeHandler;
|
||||
@Getter private ChallengeLoader challengeLoader;
|
||||
|
||||
@Override
|
||||
public void onLoad() {
|
||||
|
|
@ -60,6 +64,8 @@ public class CometSkyBlockPlugin extends JavaPlugin implements CometSkyBlockAPI
|
|||
// load worlds & manager
|
||||
islandManager = new IslandManager(this);
|
||||
worldGenerator = new MasterWorldGenerator(this);
|
||||
challengeHandler = new ChallengeHandler(this);
|
||||
loadChallenges();
|
||||
|
||||
worldGenerator.checkMasterIslandWorld();
|
||||
}
|
||||
|
|
@ -72,13 +78,18 @@ public class CometSkyBlockPlugin extends JavaPlugin implements CometSkyBlockAPI
|
|||
// close data connection
|
||||
}
|
||||
|
||||
public void loadChallenges() {
|
||||
challengeHandler.clearChallenges();
|
||||
challengeLoader = new ChallengeLoader(this);
|
||||
challengeLoader.loadAllChallenges();
|
||||
}
|
||||
|
||||
public void loadConfiguration() {
|
||||
Path path = this.getDataFolder().toPath();
|
||||
Logger logger = this.getSLF4JLogger();
|
||||
pluginConfiguration = ConfigurationContainer.load(logger, path, PluginConfiguration.class, "config");
|
||||
databaseConfiguration = ConfigurationContainer.load(logger, path, DatabaseConfiguration.class, "database");
|
||||
messagesConfiguration = ConfigurationContainer.load(logger, path, MessageConfiguration.class, "messages");
|
||||
challengesConfiguration = ConfigurationContainer.load(logger, path, ChallengesConfiguration.class, "challenges");
|
||||
cobblestoneGeneratorConfiguration = ConfigurationContainer.load(logger, path, CobblestoneGeneratorConfiguration.class, "coblestonegenerator");
|
||||
worldBorderConfiguration = ConfigurationContainer.load(logger, path, WorldBorderConfiguration.class, "worldborder");
|
||||
}
|
||||
|
|
@ -86,7 +97,7 @@ public class CometSkyBlockPlugin extends JavaPlugin implements CometSkyBlockAPI
|
|||
public void loadCommands() {
|
||||
getCommand("island").setExecutor(new IslandCommand(this));
|
||||
getCommand("challenges").setExecutor(new ChallengeCommand(this));
|
||||
// getCommand("cometskyblock").setExecutor( new AdminCommands(this));
|
||||
getCommand("skyblock").setExecutor( new SkyBlockCommand(this));
|
||||
}
|
||||
|
||||
public void loadEventListeners() {
|
||||
|
|
|
|||
|
|
@ -1,29 +1,30 @@
|
|||
package com.alttd.cometskyblock.challenges;
|
||||
|
||||
import com.alttd.cometskyblock.api.challenges.ChallengeDifficulty;
|
||||
import com.alttd.cometskyblock.api.challenges.ChallengeType;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.spongepowered.configurate.objectmapping.ConfigSerializable;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Getter
|
||||
@ConfigSerializable
|
||||
@Getter @Setter
|
||||
public class Challenge {
|
||||
|
||||
private String challengeName;
|
||||
private String mySQLKey;
|
||||
private String key;
|
||||
private Material shownItem;
|
||||
private ChallengeDifficulty difficulty;
|
||||
private ChallengeType challengeType;
|
||||
private String description;
|
||||
private String neededText;
|
||||
private String requiredText;
|
||||
private String rewardText;
|
||||
private String repeatRewardText;
|
||||
private List<ItemStack> rewards;
|
||||
private List<ItemStack> repeatRewards;
|
||||
private List<ItemStack> neededItems;
|
||||
private Integer neededLevel;
|
||||
private Integer slot;
|
||||
private List<ItemStack> requiredItems;
|
||||
private Integer requiredLevel;
|
||||
private Integer radius;
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +0,0 @@
|
|||
package com.alttd.cometskyblock.challenges;
|
||||
|
||||
public class ChallengeDifficulty {
|
||||
}
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
package com.alttd.cometskyblock.challenges;
|
||||
|
||||
import com.alttd.cometskyblock.CometSkyBlockPlugin;
|
||||
import com.alttd.cometskyblock.api.challenges.ChallengeDifficulty;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class ChallengeHandler {
|
||||
|
||||
private final Map<String, Challenge> easyChallenges = new HashMap<>();
|
||||
private final Map<String, Challenge> mediumChallenges = new HashMap<>();
|
||||
private final Map<String, Challenge> hardChallenges = new HashMap<>();
|
||||
private final Map<String, Challenge> impossibleChallenges = new HashMap<>();
|
||||
private final Map<String, Challenge> exoticChallenges = new HashMap<>();
|
||||
|
||||
private final CometSkyBlockPlugin plugin;
|
||||
|
||||
public ChallengeHandler(CometSkyBlockPlugin plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
public void addChallenge(Challenge challenge) {
|
||||
switch (challenge.difficulty()) {
|
||||
case EASY -> easyChallenges.put(challenge.key(), challenge);
|
||||
case MEDIUM -> mediumChallenges.put(challenge.key(), challenge);
|
||||
case HARD -> hardChallenges.put(challenge.key(), challenge);
|
||||
case LEGENDARY -> impossibleChallenges.put(challenge.key(), challenge);
|
||||
case EXOTIC -> exoticChallenges.put(challenge.key(), challenge);
|
||||
}
|
||||
}
|
||||
|
||||
public void clearChallenges() {
|
||||
for (ChallengeDifficulty difficulty : ChallengeDifficulty.values()) {
|
||||
getChallenges(difficulty).clear();
|
||||
}
|
||||
}
|
||||
|
||||
public Map<String, Challenge> getChallenges(ChallengeDifficulty challengeDifficulty) {
|
||||
switch (challengeDifficulty) {
|
||||
case MEDIUM -> {
|
||||
return mediumChallenges;
|
||||
}
|
||||
case HARD -> {
|
||||
return hardChallenges;
|
||||
}
|
||||
case LEGENDARY -> {
|
||||
return impossibleChallenges;
|
||||
}
|
||||
case EXOTIC -> {
|
||||
return exoticChallenges;
|
||||
}
|
||||
default -> {
|
||||
return easyChallenges;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,212 @@
|
|||
package com.alttd.cometskyblock.challenges;
|
||||
|
||||
import com.alttd.cometskyblock.CometSkyBlockPlugin;
|
||||
import com.alttd.cometskyblock.api.challenges.ChallengeDifficulty;
|
||||
import com.alttd.cometskyblock.api.challenges.ChallengeType;
|
||||
import it.unimi.dsi.fastutil.objects.Object2IntMap;
|
||||
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Data loader for challenges
|
||||
* Parse the data and build the challenges to be used by the plugin.
|
||||
*/
|
||||
public class ChallengeLoader extends YamlConfiguration {
|
||||
|
||||
private final CometSkyBlockPlugin plugin;
|
||||
private final File file;
|
||||
private final Object saveLock = new Object();
|
||||
private final Object2IntMap<ChallengeDifficulty> difficultyLevels = new Object2IntOpenHashMap<>();
|
||||
|
||||
public ChallengeLoader(CometSkyBlockPlugin plugin) {
|
||||
super();
|
||||
this.plugin = plugin;
|
||||
this.file = new File(plugin.getDataFolder(), "challenges.yml");
|
||||
difficultyLevels.defaultReturnValue(0);
|
||||
reload();
|
||||
}
|
||||
|
||||
private void reload() {
|
||||
synchronized (saveLock) {
|
||||
try {
|
||||
load(file);
|
||||
} catch (Exception ignore) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Todo - do we continue loading or end the loading procedure?
|
||||
public void loadAllChallenges() {
|
||||
for (ChallengeDifficulty difficulty : ChallengeDifficulty.values()) {
|
||||
if (!loadChallenges(difficulty)) {
|
||||
plugin.getLogger().warning(String.format("could not load %s challenges", difficulty.toString()));
|
||||
}
|
||||
loadDifficultyLevel(difficulty);
|
||||
}
|
||||
}
|
||||
|
||||
private void loadDifficultyLevel(ChallengeDifficulty challengeDifficulty) {
|
||||
if (challengeDifficulty == null) {
|
||||
plugin.getLogger().warning("Could not load challenges!");
|
||||
return;
|
||||
}
|
||||
String difficulty = challengeDifficulty.toString().toLowerCase();
|
||||
int level = getInt("level." + difficulty, 0);
|
||||
if (level > 0)
|
||||
difficultyLevels.put(challengeDifficulty, level);
|
||||
}
|
||||
|
||||
private boolean loadChallenges(ChallengeDifficulty challengeDifficulty) {
|
||||
if (challengeDifficulty == null) {
|
||||
plugin.getLogger().warning("Could not load challenges!");
|
||||
return false;
|
||||
}
|
||||
String difficulty = challengeDifficulty.toString().toLowerCase();
|
||||
ConfigurationSection section = getConfigurationSection(difficulty);
|
||||
if (section == null) {
|
||||
plugin.getLogger().warning(String.format("could not load challenges for difficulty %s", difficulty));
|
||||
return false;
|
||||
}
|
||||
Set<String> challenges = section.getKeys(false);
|
||||
for (String currentChallenge : challenges) {
|
||||
String challengeName = section.getString(currentChallenge + ".name");
|
||||
String key = section.getString(currentChallenge + ".key");
|
||||
String shownItem = section.getString(currentChallenge + ".shown-item");
|
||||
if (shownItem == null || shownItem.isEmpty() || isNotMaterial(shownItem)) {
|
||||
plugin.getLogger().warning(String.format("could not load challenge %s material data", currentChallenge));
|
||||
continue;
|
||||
}
|
||||
Material shownItemMaterial = Material.getMaterial(shownItem.toUpperCase());
|
||||
ChallengeType challengeType = ChallengeType.of(section.getString(currentChallenge + ".challenge-type"));
|
||||
String description = section.getString(currentChallenge + ".description");
|
||||
String requiredText = section.getString(currentChallenge + ".required-text");
|
||||
String rewardText = section.getString(currentChallenge + ".reward-text");
|
||||
String repeatRewardText = section.getString(currentChallenge + ".repeat-reward-text");
|
||||
List<String> rewards = section.getStringList(currentChallenge + ".reward-items");
|
||||
List<String> repeatRewards = section.getStringList(currentChallenge + ".repeat-reward-items");
|
||||
List<String> requiredItems = section.getStringList(currentChallenge + ".required-items");
|
||||
Integer requiredLevel = section.getInt(currentChallenge + ".required-level", 0);
|
||||
Integer radius = section.getInt(currentChallenge + ".radius", 50);
|
||||
// Build the challenge
|
||||
Challenge challenge = new Challenge()
|
||||
.challengeName(challengeName)
|
||||
.difficulty(challengeDifficulty)
|
||||
.key(key)
|
||||
.shownItem(shownItemMaterial)
|
||||
.description(description)
|
||||
.requiredText(requiredText)
|
||||
.rewardText(rewardText)
|
||||
.repeatRewardText(repeatRewardText)
|
||||
.requiredLevel(requiredLevel)
|
||||
.challengeType(challengeType)
|
||||
.rewards(createItems(rewards))
|
||||
.repeatRewards(createItems(repeatRewards))
|
||||
.requiredItems(createItems(requiredItems))
|
||||
.radius(radius);
|
||||
if (!validateChallenge(challenge)) {
|
||||
plugin.getLogger().warning(String.format("Invalid %s challenge: %s", difficulty, currentChallenge));
|
||||
continue;
|
||||
}
|
||||
plugin.challengeHandler().addChallenge(challenge);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean isNotMaterial(String material) {
|
||||
return Material.matchMaterial(material.toUpperCase()) == null;
|
||||
}
|
||||
|
||||
private List<ItemStack> createItems(List<String> items) {
|
||||
List<ItemStack> itemStacks = new ArrayList<>();
|
||||
for (String currentItem : items) {
|
||||
String material = currentItem;
|
||||
int amount = 1;
|
||||
if (currentItem.contains(";")) {
|
||||
String[] strings = currentItem.split(";");
|
||||
if (strings.length != 2) {
|
||||
plugin.getLogger().warning(String.format("Could not make itemstack for item %s, invalid separator", currentItem));
|
||||
continue;
|
||||
}
|
||||
if (!isNumber(strings[1])) {
|
||||
plugin.getLogger().warning(String.format("Could not make itemstack for item %s, %s is not an int", currentItem, strings[1]));
|
||||
continue;
|
||||
}
|
||||
material = strings[0];
|
||||
amount = Integer.parseInt(strings[1]);
|
||||
}
|
||||
ItemStack itemStack = makeItemStack(material, amount);
|
||||
if (itemStack == null) {
|
||||
plugin.getLogger().warning(String.format("Could not make itemstack for item %s", currentItem));
|
||||
continue;
|
||||
}
|
||||
itemStacks.add(itemStack);
|
||||
}
|
||||
return itemStacks;
|
||||
}
|
||||
|
||||
private ItemStack makeItemStack(String materialString, int amount) {
|
||||
if (materialString == null || materialString.isEmpty() || isNotMaterial(materialString)) {
|
||||
return null;
|
||||
}
|
||||
Material material = Material.getMaterial(materialString.toUpperCase());
|
||||
if (material == null) {
|
||||
return null;
|
||||
}
|
||||
return new ItemStack(material, amount);
|
||||
}
|
||||
|
||||
private boolean validateChallenge(Challenge challenge) {
|
||||
if (challenge.challengeName() != null &&
|
||||
challenge.key() != null &&
|
||||
challenge.challengeType() != null &&
|
||||
challenge.description() != null &&
|
||||
challenge.difficulty() != null &&
|
||||
challenge.shownItem() != null &&
|
||||
challenge.requiredText() != null &&
|
||||
challenge.rewardText() != null &&
|
||||
challenge.rewards() != null &&
|
||||
!challenge.rewards().isEmpty()
|
||||
) {
|
||||
switch (challenge.challengeType()) {
|
||||
case ISLAND_LEVEL -> {
|
||||
if (challenge.requiredLevel() != null)
|
||||
return true;
|
||||
}
|
||||
case ON_ISLAND -> {
|
||||
if (challenge.requiredItems() != null && !challenge.requiredItems().isEmpty() && challenge.radius() != null)
|
||||
return true;
|
||||
|
||||
}
|
||||
case ON_PLAYER -> {
|
||||
if (challenge.requiredItems() != null && !challenge.requiredItems().isEmpty() && challenge.repeatRewards() != null && !challenge.repeatRewards().isEmpty() && challenge.repeatRewardText() != null)
|
||||
return true;
|
||||
}
|
||||
default -> {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public int requiredLevel(ChallengeDifficulty challengeDifficulty) {
|
||||
return difficultyLevels.getInt(challengeDifficulty);
|
||||
}
|
||||
|
||||
private boolean isNumber(String s) {
|
||||
try {
|
||||
Integer.parseInt(s);
|
||||
} catch (NumberFormatException nfe) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
package com.alttd.cometskyblock.challenges;
|
||||
|
||||
import org.spongepowered.configurate.objectmapping.ConfigSerializable;
|
||||
|
||||
@ConfigSerializable
|
||||
public enum ChallengeType {
|
||||
|
||||
onPlayer,
|
||||
onIsland,
|
||||
islandLevel
|
||||
|
||||
}
|
||||
|
|
@ -1,27 +1,186 @@
|
|||
package com.alttd.cometskyblock.challenges;
|
||||
|
||||
import com.alttd.cometskyblock.CometSkyBlockPlugin;
|
||||
import com.alttd.cometskyblock.api.challenges.ChallengeDifficulty;
|
||||
import com.alttd.cometskyblock.api.challenges.ChallengeType;
|
||||
import com.alttd.cometskyblock.gui.GUIButton;
|
||||
import com.alttd.cometskyblock.gui.GUIInventory;
|
||||
import com.alttd.cometskyblock.island.Island;
|
||||
import com.alttd.cometskyblock.util.PlayerUtils;
|
||||
import com.alttd.cometskyblock.util.StringUtil;
|
||||
import it.unimi.dsi.fastutil.objects.Object2IntMap;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.minimessage.MiniMessage;
|
||||
import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder;
|
||||
import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.enchantments.Enchantment;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.inventory.InventoryClickEvent;
|
||||
import org.bukkit.inventory.Inventory;
|
||||
import org.bukkit.inventory.ItemFlag;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class ChallengesGUI extends GUIInventory {
|
||||
|
||||
protected ChallengeDifficulty challengeDifficulty = ChallengeDifficulty.EASY;
|
||||
|
||||
public ChallengesGUI(Island island) {
|
||||
super(island);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Inventory createInventory() { // TODO - config
|
||||
return Bukkit.createInventory(this, 54, MiniMessage.miniMessage().deserialize("<red>GUI"));
|
||||
return Bukkit.createInventory(this, 36, MiniMessage.miniMessage().deserialize("<yellow>Island - challenges menu"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decorate(Player player) {
|
||||
resetButtons();
|
||||
makeMenuBar(player);
|
||||
// Add buttons to change difficulty
|
||||
if (!challengeDifficulty.equals(ChallengeDifficulty.EASY))
|
||||
addButton(getInventory().getSize() - 5, createMenuButton(Material.WHITE_BANNER, "Easy Challenges", new ArrayList<>(), event -> {
|
||||
changeDifficulty(player, ChallengeDifficulty.EASY);
|
||||
}));
|
||||
if (!challengeDifficulty.equals(ChallengeDifficulty.MEDIUM))
|
||||
addButton(getInventory().getSize() - 4, createMenuButton(Material.GREEN_BANNER, "Medium Challenges", new ArrayList<>(), event -> {
|
||||
changeDifficulty(player, ChallengeDifficulty.MEDIUM);
|
||||
}));
|
||||
if (!challengeDifficulty.equals(ChallengeDifficulty.HARD))
|
||||
addButton(getInventory().getSize() - 3, createMenuButton(Material.BLUE_BANNER, "Hard Challenges", new ArrayList<>(), event -> {
|
||||
changeDifficulty(player, ChallengeDifficulty.HARD);
|
||||
}));
|
||||
if (!challengeDifficulty.equals(ChallengeDifficulty.LEGENDARY))
|
||||
addButton(getInventory().getSize() - 2, createMenuButton(Material.PURPLE_BANNER, "Legendary Challenges", new ArrayList<>(), event -> {
|
||||
changeDifficulty(player, ChallengeDifficulty.LEGENDARY);
|
||||
}));
|
||||
if (!challengeDifficulty.equals(ChallengeDifficulty.EXOTIC))
|
||||
addButton(getInventory().getSize() - 1, createMenuButton(Material.YELLOW_BANNER, "Exotic Challenges", new ArrayList<>(), event -> {
|
||||
changeDifficulty(player, ChallengeDifficulty.EXOTIC);
|
||||
}));
|
||||
|
||||
currentSlot = 0;
|
||||
int startIndex = pageIndex * (getInventory().getSize() - 9);
|
||||
List<Challenge> challenges = CometSkyBlockPlugin.instance().challengeHandler().getChallenges(challengeDifficulty).values().stream().toList();
|
||||
for (int i = startIndex; i < challenges.size(); i++) {
|
||||
Challenge challenge = challenges.get(i);
|
||||
int challengeCount = island.challengeCount(challenge.key());
|
||||
GUIButton guiButton = createChallengeButton(challenge, event -> {
|
||||
// TODO -- Clean up
|
||||
boolean repeat = challengeCount != 0;
|
||||
List<ItemStack> rewards = repeat ? challenge.repeatRewards() : challenge.rewards();
|
||||
boolean hasRequirements = false;
|
||||
boolean takeItems = false;
|
||||
switch (challenge.challengeType()) {
|
||||
case ON_PLAYER -> {
|
||||
hasRequirements = PlayerUtils.hasItems(player.getInventory(), challenge.requiredItems());
|
||||
takeItems = true;
|
||||
}
|
||||
case ON_ISLAND -> {
|
||||
if (!player.getWorld().getUID().equals(island.islandUUID())) {
|
||||
player.sendRichMessage(CometSkyBlockPlugin.instance().messagesConfiguration().get().island().notOnIsland());
|
||||
return;
|
||||
}
|
||||
Object2IntMap<Material> blocks = PlayerUtils.getBlocks(player, challenge.radius());
|
||||
for (ItemStack itemStack : challenge.requiredItems()) {
|
||||
if (blocks.getInt(itemStack.getType()) < itemStack.getAmount()) {
|
||||
hasRequirements = false;
|
||||
break;
|
||||
}
|
||||
|
||||
hasRequirements = true;
|
||||
}
|
||||
}
|
||||
case ISLAND_LEVEL -> {
|
||||
hasRequirements = island.level() >= challenge.requiredLevel();
|
||||
if (!hasRequirements) {
|
||||
player.sendRichMessage("<red>You do no have the required island level.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
default -> {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (!hasRequirements) {
|
||||
player.sendRichMessage("<red>You do not have all the required items.");
|
||||
return;
|
||||
}
|
||||
if (!PlayerUtils.hasRoom(player.getInventory(), rewards)) {
|
||||
player.sendRichMessage("<red>You do not have room for the reward items.");
|
||||
return;
|
||||
}
|
||||
island.challengeCount(challenge.key(), challengeCount + 1);
|
||||
TagResolver placeholders = TagResolver.resolver(
|
||||
Placeholder.component("player", player.displayName()),
|
||||
Placeholder.unparsed("challengename", challenge.challengeName())
|
||||
);
|
||||
island.broadCast("<player> has completed challenge <challengename>.", placeholders);
|
||||
PlayerUtils.giveItems(player.getInventory(), rewards);
|
||||
if (takeItems) {
|
||||
PlayerUtils.takeItems(player.getInventory(), challenge.requiredItems());
|
||||
}
|
||||
this.decorate(player);
|
||||
}, challengeCount);
|
||||
if (!addItem(guiButton)) {
|
||||
createNextPageButton(player);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (pageIndex > 0) {
|
||||
createPrevPageButton(player);
|
||||
}
|
||||
super.decorate(player);
|
||||
}
|
||||
|
||||
protected void changeDifficulty(Player player, ChallengeDifficulty challengeDifficulty) {
|
||||
int requiredLevel = CometSkyBlockPlugin.instance().challengeLoader().requiredLevel(challengeDifficulty);
|
||||
if (!(island.level() >= requiredLevel)) {
|
||||
TagResolver placeholders = TagResolver.resolver(
|
||||
Placeholder.unparsed("requiredlevel", requiredLevel + ""),
|
||||
Placeholder.unparsed("difficulty", challengeDifficulty.toString().toLowerCase())
|
||||
);
|
||||
player.sendRichMessage("<red>You need island level <requiredlevel> to access <difficulty> challenges", placeholders);
|
||||
return;
|
||||
}
|
||||
this.challengeDifficulty = challengeDifficulty;
|
||||
this.decorate(player);
|
||||
}
|
||||
|
||||
private GUIButton createChallengeButton(Challenge challenge, Consumer<InventoryClickEvent> eventConsumer, int challengeCount) {
|
||||
return new GUIButton()
|
||||
.creator(player -> {
|
||||
ItemStack itemStack = new ItemStack(challenge.shownItem(), Math.min(Math.max(1, challengeCount), 64));
|
||||
itemStack.editMeta(meta -> {
|
||||
MiniMessage miniMessage = MiniMessage.miniMessage();
|
||||
meta.displayName(miniMessage.deserialize(challenge.challengeName()));
|
||||
List<Component> lore = new ArrayList<>(StringUtil.splitMiniMessageString(challenge.description()).stream().map(miniMessage::deserialize).toList());
|
||||
String prefix = switch (challenge.challengeType()) {
|
||||
case ON_PLAYER -> "<yellow>Required items:</yellow>";
|
||||
case ON_ISLAND -> "<yellow>Build:</yellow>";
|
||||
case ISLAND_LEVEL -> "<yellow>Requires</yellow>";
|
||||
};
|
||||
lore.addAll(StringUtil.splitMiniMessageString(prefix + " " + challenge.requiredText()).stream().map(miniMessage::deserialize).toList());
|
||||
lore.add(miniMessage.deserialize("<yellow>Reward: " + StringUtil.splitMiniMessageString(
|
||||
(challenge.challengeType().equals(ChallengeType.ON_PLAYER) && challengeCount != 0) ?
|
||||
challenge.repeatRewardText() : challenge.rewardText())));
|
||||
// TODO -- Add glow for challenges that are completed
|
||||
// if (challengeCount > 0 || challenge.repeatRewards() != null && !challenge.repeatRewards().isEmpty()) {
|
||||
// meta.addEnchant(Enchantment.MENDING, 1, true);
|
||||
// }
|
||||
meta.addItemFlags(ItemFlag.values());
|
||||
|
||||
meta.lore(lore);
|
||||
});
|
||||
return itemStack;
|
||||
})
|
||||
.consumer(eventConsumer);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,30 @@
|
|||
package com.alttd.cometskyblock.commands.admin;
|
||||
|
||||
import com.alttd.cometskyblock.CometSkyBlockPlugin;
|
||||
import com.alttd.cometskyblock.commands.SubCommand;
|
||||
import org.bukkit.command.CommandSender;
|
||||
|
||||
public class ReloadCommand extends SubCommand {
|
||||
|
||||
public ReloadCommand(CometSkyBlockPlugin plugin) {
|
||||
super(plugin, "reload");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean execute(CommandSender sender, String... args) {
|
||||
if (args.length < 1) {
|
||||
sender.sendRichMessage("<red>Wrong usage try /skyblock reload config|challenges|all");
|
||||
return true;
|
||||
}
|
||||
switch (args[0].toLowerCase()) {
|
||||
case "all" -> {
|
||||
plugin.loadConfiguration();
|
||||
plugin.loadChallenges();
|
||||
}
|
||||
case "config" -> plugin.loadConfiguration();
|
||||
case "challenges" -> plugin.loadChallenges();
|
||||
default -> sender.sendRichMessage("<red>Wrong usage try /skyblock reload config|challenges|all");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
package com.alttd.cometskyblock.commands.admin;
|
||||
|
||||
import com.alttd.cometskyblock.CometSkyBlockPlugin;
|
||||
import com.alttd.cometskyblock.commands.SubCommand;
|
||||
import org.bukkit.command.CommandSender;
|
||||
|
||||
public class SkyBlockCommand extends SubCommand {
|
||||
|
||||
private final CometSkyBlockPlugin plugin;
|
||||
|
||||
public SkyBlockCommand(CometSkyBlockPlugin plugin) {
|
||||
super(plugin, "skyblock");
|
||||
this.plugin = plugin;
|
||||
|
||||
registerSubCommand(new ReloadCommand(plugin));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean execute(CommandSender sender, String... args) {
|
||||
sender.sendRichMessage("<red>Wrong usage try /skyblock reload config|challenges");
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,7 +1,9 @@
|
|||
package com.alttd.cometskyblock.commands.challenges;
|
||||
|
||||
import com.alttd.cometskyblock.CometSkyBlockPlugin;
|
||||
import com.alttd.cometskyblock.challenges.ChallengesGUI;
|
||||
import com.alttd.cometskyblock.commands.PlayerSubCommand;
|
||||
import com.alttd.cometskyblock.island.Island;
|
||||
import com.alttd.cometskyblock.island.IslandPlayer;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
|
|
@ -13,11 +15,19 @@ public class ChallengeCommand extends PlayerSubCommand {
|
|||
super(plugin, "challenge");
|
||||
this.plugin = plugin;
|
||||
}
|
||||
// TODO - Challenges, ChallengesGUI and ChallengesCommand
|
||||
|
||||
@Override
|
||||
public boolean execute(Player player, IslandPlayer islandPlayer, String[] args) {
|
||||
// open challenge inventory - not implemented yet -- TODO
|
||||
player.sendRichMessage("<red>Not implemented yet, please wait for a future update.");
|
||||
if (islandPlayer.islandId() == 0) {
|
||||
player.sendRichMessage("<red>You should create an island before doing this. Do /island go");
|
||||
return true;
|
||||
}
|
||||
Island island = Island.getIsland(islandPlayer.islandUUID());
|
||||
if (island == null) {
|
||||
player.sendRichMessage("<red>Could not load your island. Contact an administrator");
|
||||
return true;
|
||||
}
|
||||
new ChallengesGUI(island).open(player);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,16 +0,0 @@
|
|||
package com.alttd.cometskyblock.configuration;
|
||||
|
||||
import com.alttd.cometskyblock.challenges.Challenge;
|
||||
import lombok.Getter;
|
||||
import org.spongepowered.configurate.objectmapping.ConfigSerializable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@ConfigSerializable
|
||||
@Getter
|
||||
@SuppressWarnings({"CanBeFinal", "FieldMayBeFinal"})
|
||||
public class ChallengesConfiguration implements Configuration {
|
||||
|
||||
private List<Challenge> challenges = new ArrayList<>();
|
||||
}
|
||||
|
|
@ -65,11 +65,16 @@ public abstract class GUIInventory implements GUI, InventoryHolder {
|
|||
|
||||
}
|
||||
|
||||
public void resetButtons() {
|
||||
this.buttons.clear();
|
||||
}
|
||||
|
||||
public void addButton(int slot, GUIButton button) {
|
||||
this.buttons.put(slot, button);
|
||||
}
|
||||
|
||||
protected void decorate(Player player) {
|
||||
this.inventory.clear();
|
||||
this.buttons.forEach((slot, button) -> {
|
||||
ItemStack icon = button.iconCreator().apply(player);
|
||||
this.inventory.setItem(slot, icon);
|
||||
|
|
@ -99,11 +104,16 @@ public abstract class GUIInventory implements GUI, InventoryHolder {
|
|||
}
|
||||
|
||||
protected void makeMenuBar(Player player) {
|
||||
makeMenuBar(player, false);
|
||||
}
|
||||
|
||||
protected void makeMenuBar(Player player, boolean makeTopBar) {
|
||||
for (int i = inventory.getSize() - 9; i < inventory.getSize(); ++i) {
|
||||
addButton(i, createMenuButton(Material.BLACK_STAINED_GLASS_PANE, "", new ArrayList<>(), event -> {}));
|
||||
}
|
||||
createMainMenuButton(player, inventory.getSize() - 9);
|
||||
makeTopBar();
|
||||
if (makeTopBar)
|
||||
makeTopBar();
|
||||
}
|
||||
|
||||
protected void makeTopBar() {
|
||||
|
|
@ -129,14 +139,14 @@ public abstract class GUIInventory implements GUI, InventoryHolder {
|
|||
}
|
||||
|
||||
protected void createPrevPageButton(Player player) {
|
||||
addButton(48, createMenuButton(Material.PAPER, "<yellow><< Previous Page", new ArrayList<>(), event -> {
|
||||
addButton(inventory.getSize() - 8, createMenuButton(Material.PAPER, "<yellow><< Previous Page", new ArrayList<>(), event -> {
|
||||
--pageIndex;
|
||||
decorate(player);
|
||||
}));
|
||||
}
|
||||
|
||||
protected void createNextPageButton(Player player) {
|
||||
addButton(50, createMenuButton(Material.PAPER, "<yellow>Next Page >>", new ArrayList<>(), event -> {
|
||||
addButton(inventory.getSize() - 7, createMenuButton(Material.PAPER, "<yellow>Next Page >>", new ArrayList<>(), event -> {
|
||||
++pageIndex;
|
||||
decorate(player);
|
||||
}));
|
||||
|
|
|
|||
|
|
@ -251,4 +251,14 @@ public class Island extends YamlConfiguration {
|
|||
public IslandRecord toRecord() {
|
||||
return new IslandRecord(islandId(), islandName(), level());
|
||||
}
|
||||
|
||||
|
||||
public int challengeCount(String key) {
|
||||
return getInt("challenges." + key, 0);
|
||||
}
|
||||
|
||||
public void challengeCount(String key, int amount) {
|
||||
set("challenges." + key, amount);
|
||||
save();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ public class IslandGUI extends GUIInventory {
|
|||
|
||||
@Override
|
||||
public void decorate(Player player) {
|
||||
makeMenuBar(player);
|
||||
makeMenuBar(player, true);
|
||||
|
||||
// Island GO
|
||||
addButton(10, createMenuButton(Material.GRASS_BLOCK, "Visit your island!", new ArrayList<>(), event -> {
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ public class MembersGUI extends GUIInventory {
|
|||
@Override
|
||||
public void decorate(Player player) {
|
||||
currentSlot = 9;
|
||||
makeMenuBar(player);
|
||||
makeMenuBar(player, true);
|
||||
|
||||
int startIndex = pageIndex * 45;
|
||||
for (int i = startIndex; i < island.members().size(); i++) {
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ public class SettingsGUI extends GUIInventory {
|
|||
|
||||
@Override
|
||||
public void decorate(Player player) {
|
||||
makeMenuBar(player);
|
||||
makeMenuBar(player, true);
|
||||
// setHome
|
||||
addButton(10, createMenuButton(Material.GRASS_BLOCK, "Set your IslandSpawn location!", List.of(
|
||||
"<white>This sets your island spawn location to your current location."
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ public class UpgradesGUI extends GUIInventory {
|
|||
|
||||
@Override
|
||||
public void decorate(Player player) {
|
||||
makeMenuBar(player);
|
||||
makeMenuBar(player, true);
|
||||
MessageConfiguration.Island islandMessages = CometSkyBlockPlugin.instance().messagesConfiguration().get().island();
|
||||
// Todo - move to handlers, add costs, validation ...
|
||||
// WorldBorder
|
||||
|
|
|
|||
|
|
@ -0,0 +1,115 @@
|
|||
package com.alttd.cometskyblock.util;
|
||||
|
||||
import it.unimi.dsi.fastutil.objects.Object2IntMap;
|
||||
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.Inventory;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class PlayerUtils {
|
||||
|
||||
public static boolean hasItems(Inventory inventory, List<ItemStack> items) {
|
||||
if (inventory == null || items == null)
|
||||
return false;
|
||||
|
||||
for (ItemStack itemStack : items) {
|
||||
int requiredAmount = itemStack.getAmount();
|
||||
for (int slot = 0; slot < inventory.getSize(); slot++) {
|
||||
if (inventory.getItem(slot) != null) {
|
||||
if (inventory.getItem(slot).getType().equals(itemStack.getType())) {
|
||||
requiredAmount = requiredAmount - inventory.getItem(slot).getAmount();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (requiredAmount > 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static boolean hasRoom(Inventory inventory, List<ItemStack> items) {
|
||||
for (ItemStack itemStack : items) {
|
||||
if (!hasRoom(inventory, itemStack))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static boolean hasRoom(Inventory inventory, ItemStack itemStack) {
|
||||
if (inventory == null)
|
||||
return false;
|
||||
|
||||
if (itemStack.getAmount() <= 0)
|
||||
return true;
|
||||
|
||||
Inventory test = Bukkit.createInventory(null, 36);
|
||||
test.setContents(inventory.getContents());
|
||||
Map<Integer, ItemStack> remainingItems = test.addItem(itemStack);
|
||||
|
||||
return remainingItems.isEmpty();
|
||||
}
|
||||
|
||||
public static void giveItems(Inventory inventory, List<ItemStack> items) {
|
||||
for (ItemStack current : items) {
|
||||
inventory.addItem(current.clone());
|
||||
}
|
||||
}
|
||||
|
||||
public static Object2IntMap<Material> getBlocks(Player player, Integer radius) {
|
||||
Object2IntMap<Material> blocks = new Object2IntOpenHashMap<>();
|
||||
blocks.defaultReturnValue(0);
|
||||
|
||||
Location loc = player.getLocation();
|
||||
int blockX = loc.getBlockX();
|
||||
int blockY = loc.getBlockY();
|
||||
int blockZ = loc.getBlockZ();
|
||||
|
||||
for (int x = blockX - radius; x < blockX + radius; x++ ) {
|
||||
for (int z = blockZ - radius; z < blockZ + radius; z++) {
|
||||
if (player.getWorld().isChunkLoaded(x >> 4, z >> 4)) {
|
||||
for (int y = blockY - radius; y < blockY + radius; y++) {
|
||||
Material blockType = player.getWorld().getBlockAt(x, y, z).getType();
|
||||
if (!blockType.isAir()) {
|
||||
blocks.put(blockType, blocks.getInt(blockType) + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return blocks;
|
||||
}
|
||||
|
||||
public static void takeItems(Inventory inventory, List<ItemStack> items) {
|
||||
if (inventory == null || items == null)
|
||||
return;
|
||||
|
||||
for (ItemStack itemStack : items) {
|
||||
int amount = itemStack.getAmount();
|
||||
for (int slot = 0; slot < inventory.getSize(); slot++) {
|
||||
ItemStack inventoryItem = inventory.getItem(slot);
|
||||
if (inventoryItem != null) {
|
||||
if (inventoryItem.getType().equals(itemStack.getType())) {
|
||||
int newAmount = inventoryItem.getAmount() - amount;
|
||||
if (newAmount > 0) {
|
||||
inventoryItem.setAmount(newAmount);
|
||||
break;
|
||||
} else {
|
||||
inventory.clear(slot);
|
||||
amount = amount - inventoryItem.getAmount();
|
||||
if (amount == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,109 @@
|
|||
package com.alttd.cometskyblock.util;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class StringUtil {
|
||||
|
||||
/**
|
||||
* Splits a mini message string into smaller chunks. It re-opens any unclosed tags it encounters for
|
||||
* each part of the string added to the list
|
||||
*
|
||||
* @param string the mini message string to split
|
||||
* @return a list of the split strings
|
||||
*/
|
||||
public static List<String> splitMiniMessageString(String string) {
|
||||
Set<String> tags = findTags(string);
|
||||
List<String> splitString = new ArrayList<>();
|
||||
Stack<String> openTags = new Stack<>();
|
||||
Stack<String> previousOpenTags = new Stack<>();
|
||||
int startCurString = 0;
|
||||
int len = 0;
|
||||
int i = 0;
|
||||
for (; i < string.length(); i++) {
|
||||
while (string.charAt(i) == '<') {
|
||||
i = skipTags(i, string, openTags, tags);
|
||||
}
|
||||
len++;
|
||||
if (len != 30) {
|
||||
continue;
|
||||
}
|
||||
while (i < string.length() && !Character.isWhitespace(string.charAt(i))) {
|
||||
while (string.charAt(i) == '<') {
|
||||
i = skipTags(i, string, openTags, tags);
|
||||
}
|
||||
if (Character.isWhitespace(string.charAt(i))) {
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
String prependTags = previousOpenTags.stream().map(str -> "<" + str + ">").collect(Collectors.joining(""));
|
||||
splitString.add(prependTags + string.substring(startCurString, i));
|
||||
previousOpenTags.clear();
|
||||
previousOpenTags.addAll(openTags);
|
||||
startCurString = ++i;
|
||||
len = 0;
|
||||
}
|
||||
if (startCurString < string.length()) {
|
||||
String prependTags = previousOpenTags.stream().map(str -> "<" + str + ">").collect(Collectors.joining(""));
|
||||
splitString.add(prependTags + string.substring(startCurString));
|
||||
}
|
||||
return splitString;
|
||||
}
|
||||
|
||||
private static int skipTags(int i, String string, Stack<String> openTags, Set<String> tags) {
|
||||
StringBuilder tagBuilder = new StringBuilder();
|
||||
i++;
|
||||
for (; i < string.length() && string.charAt(i) != '>'; i++) {
|
||||
tagBuilder.append(string.charAt(i));
|
||||
}
|
||||
String tagString = tagBuilder.toString();
|
||||
if (!tagString.isEmpty() && tagString.charAt(0) == '/') {
|
||||
if (!openTags.isEmpty() && openTags.peek().contentEquals(tagString.substring(1))) {
|
||||
openTags.pop();
|
||||
}
|
||||
} else if (tags.contains(tagString)) {
|
||||
openTags.add(tagString);
|
||||
}
|
||||
tagBuilder.setLength(0);
|
||||
return Math.min(++i, string.length() - 1);
|
||||
}
|
||||
|
||||
public static Set<String> findTags(String string) {
|
||||
List<String> tags = new ArrayList<>();
|
||||
HashSet<String> closedTags = new HashSet<>();
|
||||
StringBuilder tag = new StringBuilder();
|
||||
boolean tagFound = false;
|
||||
|
||||
for (int i = 0; i < string.length(); i++) {
|
||||
if (string.charAt(i) == '<') {
|
||||
tagFound = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (string.charAt(i) == '>') {
|
||||
tagFound = false;
|
||||
|
||||
if (tag.charAt(0) != '/') {
|
||||
tags.add(tag.toString());
|
||||
} else {
|
||||
String closingTag = tag.substring(1);
|
||||
if (tags.contains(closingTag)) {
|
||||
tags.remove(closingTag);
|
||||
closedTags.add(closingTag);
|
||||
}
|
||||
}
|
||||
|
||||
tag.setLength(0);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (tagFound) {
|
||||
tag.append(string.charAt(i));
|
||||
}
|
||||
}
|
||||
|
||||
return closedTags;
|
||||
}
|
||||
|
||||
}
|
||||
219
plugin/src/main/resources/challenges.yml
Normal file
219
plugin/src/main/resources/challenges.yml
Normal file
|
|
@ -0,0 +1,219 @@
|
|||
level:
|
||||
easy: 0
|
||||
medium: 20
|
||||
hard: 50
|
||||
legendary: 75
|
||||
exotic: 100
|
||||
easy:
|
||||
CobblestoneGenerator:
|
||||
name: Cobblestone Generator
|
||||
key: easy_cobblestone_generator
|
||||
shown-item: Cobblestone
|
||||
challenge-type: ON_PLAYER
|
||||
description: "Build a cobblestone generator and farm 64 cobblestone."
|
||||
required-text: "64 cobblestone"
|
||||
required-items:
|
||||
- Cobblestone;64
|
||||
reward-text: "3 Leather"
|
||||
reward-items:
|
||||
- Leather;3
|
||||
repeat-reward-text: "1 Leather"
|
||||
repeat-reward-items:
|
||||
- Leather;1
|
||||
CropFarmer:
|
||||
name: Wheat Farmer
|
||||
key: easy_crop_farmer
|
||||
shown-item: Wheat
|
||||
challenge-type: ON_PLAYER
|
||||
description: "Collect 64 wheat."
|
||||
required-text: "64 wheat"
|
||||
required-items:
|
||||
- Wheat;64
|
||||
reward-text: "variety seed pack."
|
||||
reward-items:
|
||||
- Melon_seeds;1
|
||||
- pumpkin_seeds;1
|
||||
repeat-reward-text: "variety seed pack."
|
||||
repeat-reward-items:
|
||||
- Melon_seeds;1
|
||||
- pumpkin_seeds;1
|
||||
CactusFarmer:
|
||||
name: Cactus Farmer
|
||||
key: easy_cactus_farmer
|
||||
shown-item: Cactus
|
||||
challenge-type: ON_PLAYER
|
||||
description: "Collect 64 cactus."
|
||||
required-text: "64 cactus"
|
||||
required-items:
|
||||
- Cactus;64
|
||||
reward-text: "5 sand"
|
||||
reward-items:
|
||||
- Sand;5
|
||||
repeat-reward-text: "1 sand"
|
||||
repeat-reward-items:
|
||||
- Sand;1
|
||||
AppleFarmer:
|
||||
name: Apple Farmer
|
||||
key: medium_apple_farmer
|
||||
shown-item: Apple
|
||||
challenge-type: ON_PLAYER
|
||||
description: "Collect 8 apples."
|
||||
required-text: "8 apples"
|
||||
required-items:
|
||||
- Apple;8
|
||||
reward-text: "One sapling from each type."
|
||||
reward-items:
|
||||
- Oak_Sapling;1
|
||||
- Spruce_Sapling;1
|
||||
- Birch_Sapling;1
|
||||
- Jungle_Sapling;1
|
||||
- Acacia_Sapling;1
|
||||
- Dark_Oak_Sapling;1
|
||||
repeat-reward-text: "One sapling from each type."
|
||||
repeat-reward-items:
|
||||
- Oak_Sapling;1
|
||||
- Spruce_Sapling;1
|
||||
- Birch_Sapling;1
|
||||
- Jungle_Sapling;1
|
||||
- Acacia_Sapling;1
|
||||
- Dark_Oak_Sapling;1
|
||||
medium:
|
||||
Lumberjack:
|
||||
name: Lumberjack
|
||||
key: medium_lumberjack
|
||||
shown-item: Diamond_axe
|
||||
challenge-type: ON_PLAYER
|
||||
description: "Obtain 32 oak-, spruce-, birch-, jungle-, acacia-, and dark oak logs."
|
||||
required-text: "32 oak logs, 32 spruce logs, 32 birch logs, 32 jungle logs, 32 acacia logs, 32 dark oak logs"
|
||||
required-items:
|
||||
- Oak_Log;32
|
||||
- Spruce_Log;32
|
||||
- Birch_Log;32
|
||||
- Jungle_Log;32
|
||||
- Acacia_Log;32
|
||||
- Dark_Oak_Log;32
|
||||
reward-text: "16 gilded blackstone"
|
||||
reward-items:
|
||||
- Gilded_Blackstone;16
|
||||
repeat-reward-text: "8 gilded blackstone"
|
||||
repeat-reward-items:
|
||||
- Gilded_Blackstone;8
|
||||
AppleFarmer:
|
||||
name: Apple Farmer
|
||||
key: medium_apple_farmer
|
||||
shown-item: Apple
|
||||
challenge-type: ON_PLAYER
|
||||
description: "Collect 8 apples."
|
||||
required-text: "8 apples"
|
||||
required-items:
|
||||
- Apple;8
|
||||
reward-text: "One sapling from each type."
|
||||
reward-items:
|
||||
- Oak_Sapling;1
|
||||
- Spruce_Sapling;1
|
||||
- Birch_Sapling;1
|
||||
- Jungle_Sapling;1
|
||||
- Acacia_Sapling;1
|
||||
- Dark_Oak_Sapling;1
|
||||
repeat-reward-text: "One sapling from each type."
|
||||
repeat-reward-items:
|
||||
- Oak_Sapling;1
|
||||
- Spruce_Sapling;1
|
||||
- Birch_Sapling;1
|
||||
- Jungle_Sapling;1
|
||||
- Acacia_Sapling;1
|
||||
- Dark_Oak_Sapling;1
|
||||
MonsterHunter:
|
||||
name: Monster Hunter
|
||||
key: medium_monster_hunter
|
||||
shown-item: Bone
|
||||
challenge-type: ON_PLAYER
|
||||
description: "Kill monsters and collect 64 rotten flesh, bones and arrows."
|
||||
required-text: "64 rotten flesh, bones and arrows."
|
||||
required-items:
|
||||
- Rotten_Flesh;64
|
||||
- Bone;64
|
||||
- Arrow;64
|
||||
reward-text: "2 experience bottles!"
|
||||
reward-items:
|
||||
- experience_bottle;2
|
||||
repeat-reward-text: "One experience bottles!"
|
||||
repeat-reward-items:
|
||||
- experience_bottle
|
||||
Exterminator:
|
||||
name: Exterminator
|
||||
key: medium_exterminator
|
||||
shown-item: Cobweb
|
||||
challenge-type: ON_PLAYER
|
||||
description: "Kill spiders and collect their drops."
|
||||
required-text: "64 strings, 32 spider eyes"
|
||||
required-items:
|
||||
- String;64
|
||||
- Spider_Eye;32
|
||||
reward-text: "2 Cobwebs"
|
||||
reward-items:
|
||||
- Cobweb;8
|
||||
repeat-reward-text: "One cobweb"
|
||||
repeat-reward-items:
|
||||
- Cobweb
|
||||
FisherMan:
|
||||
name: Fisherman
|
||||
key: medium_fisherman
|
||||
shown-item: Fishing_rod
|
||||
challenge-type: ON_PLAYER
|
||||
description: "This could have been sushi"
|
||||
required-text: "10 cooked cod and 10 cooked salmon"
|
||||
required-items:
|
||||
- Cooked_Cod;10
|
||||
- Cooked_Salmon;10
|
||||
reward-text: "2 experience bottles!"
|
||||
reward-items:
|
||||
- experience_bottle;2
|
||||
repeat-reward-text: "One experience bottles!"
|
||||
repeat-reward-items:
|
||||
- experience_bottle
|
||||
hard:
|
||||
NetherLumberjack:
|
||||
name: Nether Lumberjack
|
||||
key: hard_nether_lumberjack
|
||||
shown-item: Netherite_axe
|
||||
challenge-type: ON_PLAYER
|
||||
description: "Obtain 64 crimson stems and 64 warped stems"
|
||||
required-text: "64 crimson stems, 64 warped stems"
|
||||
required-items:
|
||||
- Crimson_Stem;64
|
||||
- Warped_Stem;64
|
||||
reward-text: "16 gilded blackstone"
|
||||
reward-items:
|
||||
- Gilded_Blackstone;16
|
||||
repeat-reward-text: "8 gilded blackstone"
|
||||
repeat-reward-items:
|
||||
- Gilded_Blackstone;8
|
||||
legendary:
|
||||
BeastSlayer:
|
||||
name: Beast Slayer
|
||||
key: legendary_beast_slayer
|
||||
shown-item: Beacon
|
||||
challenge-type: ON_ISLAND
|
||||
description: "Place a beacon on your island."
|
||||
required-text: "One beacon"
|
||||
required-items:
|
||||
- Beacon;1
|
||||
reward-text: "One Nether Star"
|
||||
reward-items:
|
||||
- Nether_star
|
||||
repeat-reward-text: "1 Diamond_Block"
|
||||
repeat-reward-items:
|
||||
- Diamond_Block;1
|
||||
exotic:
|
||||
Babylon:
|
||||
name: Babylon
|
||||
key: exotic_babylon
|
||||
shown-item: bedrock
|
||||
challenge-type: ISLAND_LEVEL
|
||||
description: "Open the gates of <rainbow>Babylon<rainbow>!"
|
||||
required-text: "Island level 1000"
|
||||
reward-text: "1 bedrock"
|
||||
reward-items:
|
||||
- Bedrock;1
|
||||
required-level: 1000
|
||||
91
plugin/src/test/java/StringUtilTest.java
Normal file
91
plugin/src/test/java/StringUtilTest.java
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
import com.alttd.cometskyblock.util.StringUtil;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
public class StringUtilTest {
|
||||
|
||||
/**
|
||||
* StringUtilTest tests the splitString method in the StringUtil class.
|
||||
* The splitString method is designed to split a string, making them shorter and more suitable
|
||||
* for use in minecraft lore.
|
||||
*/
|
||||
|
||||
@Test
|
||||
public void testSplitString() {
|
||||
String testString = "This is a long string that needs to be split into multiple smaller chunks.";
|
||||
List<String> expectedOutput = List.of(
|
||||
"This is a long string that needs",
|
||||
"to be split into multiple smaller",
|
||||
"chunks.");
|
||||
assertEquals(expectedOutput, StringUtil.splitMiniMessageString(testString));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSplitStringWithMarkups() {
|
||||
String testString = "<blue>This is a <red>long tag string</red> <green>that</green> <orange>needs</orange> <rainbow>to be</rainbow> split into smaller chunks.</blue>";
|
||||
List<String> expectedOutput = List.of(
|
||||
"<blue>This is a <red>long tag string</red> <green>that</green>",
|
||||
"<blue><orange>needs</orange> <rainbow>to be</rainbow> split into",
|
||||
"<blue>smaller chunks.</blue>");
|
||||
assertEquals(expectedOutput, StringUtil.splitMiniMessageString(testString));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUsedString() {
|
||||
String testString = "<yellow>Required items:</yellow> 64 Cobblestone";
|
||||
List<String> expectedOutput = List.of("<yellow>Required items:</yellow> 64 Cobblestone");
|
||||
assertEquals(expectedOutput, StringUtil.splitMiniMessageString(testString));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSplitStringWithShortString() {
|
||||
String testString = "Short string.";
|
||||
List<String> expectedOutput = List.of("Short string.");
|
||||
assertEquals(expectedOutput, StringUtil.splitMiniMessageString(testString));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSplitStringWithManyTagsString() {
|
||||
String testString = "<red><blue><green><not_a_color><orange>This is a long string with a <placeholder> and a lot of text</orange></green></blue></red>";
|
||||
List<String> expectedOutput = List.of("<red><blue><green><not_a_color><orange>This is a long string with a <placeholder>",
|
||||
"<red><blue><green><orange>and a lot of text</orange></green></blue></red>");
|
||||
assertEquals(expectedOutput, StringUtil.splitMiniMessageString(testString));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFindTagsWithCorrectTags() {
|
||||
String input = "<red>This is a <blue>test</blue> string.</red>";
|
||||
Set<String> result = StringUtil.findTags(input);
|
||||
assertTrue(result.containsAll(List.of("red", "blue")));
|
||||
assertEquals(2, result.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFindTagsWithUnclosedTag() {
|
||||
String input = "<red>This is a <placeholder> test string.</red>";
|
||||
Set<String> result = StringUtil.findTags(input);
|
||||
assertTrue(result.contains("red"));
|
||||
assertFalse(result.contains("placeholder"));
|
||||
assertEquals(1, result.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFindTagsWithNoTags() {
|
||||
String input = "This is a test string.";
|
||||
Set<String> result = StringUtil.findTags(input);
|
||||
assertTrue(result.isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFindTagsWithManyTags() {
|
||||
String input = "<red><blue><green><not_a_color><orange>This is a test string.</orange></green></blue></red>";
|
||||
Set<String> result = StringUtil.findTags(input);
|
||||
assertTrue(result.containsAll(List.of("red", "blue", "green", "orange")));
|
||||
assertFalse(result.contains("not_a_color"));
|
||||
assertEquals(4, result.size());
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user