diff --git a/src/main/java/fr/openmc/core/CommandsManager.java b/src/main/java/fr/openmc/core/CommandsManager.java index 3ee07f4d2..eb7626164 100644 --- a/src/main/java/fr/openmc/core/CommandsManager.java +++ b/src/main/java/fr/openmc/core/CommandsManager.java @@ -10,6 +10,7 @@ import fr.openmc.core.features.adminshop.AdminShopCommand; import fr.openmc.core.features.cube.CubeCommands; import fr.openmc.core.features.cube.multiblocks.MultiBlockManager; +import fr.openmc.core.features.dimsopener.command.DimensionCommands; import fr.openmc.core.features.friend.FriendCommand; import fr.openmc.core.features.friend.FriendManager; import fr.openmc.core.features.mailboxes.MailboxCommand; @@ -57,12 +58,12 @@ private static void registerCommands() { new SocialSpyCommand(), new SettingsCommand(), new Cooldowns(), - new CubeCommands() + new CubeCommands(), + new DimensionCommands() ); } private static void registerSuggestions() { FriendManager.initCommandSuggestion(); - MultiBlockManager.initCommandSuggestion(); } } diff --git a/src/main/java/fr/openmc/core/OMCPlugin.java b/src/main/java/fr/openmc/core/OMCPlugin.java index d0b7d297a..31a435383 100644 --- a/src/main/java/fr/openmc/core/OMCPlugin.java +++ b/src/main/java/fr/openmc/core/OMCPlugin.java @@ -17,6 +17,7 @@ import fr.openmc.core.features.city.sub.war.WarManager; import fr.openmc.core.features.contest.managers.ContestManager; import fr.openmc.core.features.cube.multiblocks.MultiBlockManager; +import fr.openmc.core.features.dimsopener.DimsOpenerManager; import fr.openmc.core.features.displays.TabList; import fr.openmc.core.features.displays.bossbar.BossbarManager; import fr.openmc.core.features.displays.holograms.HologramLoader; @@ -147,6 +148,7 @@ public void loadWithItemsAdder() { ParticleUtils.spawnContestParticlesInRegion("spawn", Bukkit.getWorld("world"), 10, 70, 135); } HomeIconCacheManager.initialize(); + DimsOpenerManager.initConfig(); } @Override diff --git a/src/main/java/fr/openmc/core/features/dimsopener/DimensionConfig.java b/src/main/java/fr/openmc/core/features/dimsopener/DimensionConfig.java new file mode 100644 index 000000000..681288455 --- /dev/null +++ b/src/main/java/fr/openmc/core/features/dimsopener/DimensionConfig.java @@ -0,0 +1,18 @@ +package fr.openmc.core.features.dimsopener; + +import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.NotNull; + +import java.util.List; + +public record DimensionConfig(String dimensionKey, String name, ItemStack icon, List steps) { + @Override + public @NotNull String toString() { + return "DimensionConfig{" + + "dimensionKey='" + dimensionKey + '\'' + + ", name='" + name + '\'' + + ", icon=" + icon + + ", steps=" + steps + + '}'; + } +} diff --git a/src/main/java/fr/openmc/core/features/dimsopener/DimensionStep.java b/src/main/java/fr/openmc/core/features/dimsopener/DimensionStep.java new file mode 100644 index 000000000..c2ae3c6f5 --- /dev/null +++ b/src/main/java/fr/openmc/core/features/dimsopener/DimensionStep.java @@ -0,0 +1,4 @@ +package fr.openmc.core.features.dimsopener; + +public record DimensionStep(String itemType, int count, int nextStepDelay) { +} \ No newline at end of file diff --git a/src/main/java/fr/openmc/core/features/dimsopener/DimsOpenerManager.java b/src/main/java/fr/openmc/core/features/dimsopener/DimsOpenerManager.java new file mode 100644 index 000000000..6afec8931 --- /dev/null +++ b/src/main/java/fr/openmc/core/features/dimsopener/DimsOpenerManager.java @@ -0,0 +1,179 @@ +package fr.openmc.core.features.dimsopener; + +import com.j256.ormlite.dao.Dao; +import com.j256.ormlite.dao.DaoManager; +import com.j256.ormlite.support.ConnectionSource; +import com.j256.ormlite.table.TableUtils; +import fr.openmc.core.OMCPlugin; +import fr.openmc.core.features.dimsopener.event.DimensionUnlockedEvent; +import fr.openmc.core.features.dimsopener.model.DimensionProgress; +import fr.openmc.core.items.CustomItemRegistry; +import org.bukkit.Bukkit; +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.sql.SQLException; +import java.util.*; +import java.util.concurrent.TimeUnit; + +public class DimsOpenerManager { + + private static final Map dimensionConfigs = new HashMap<>(); + private static final Map progressCache = new HashMap<>(); + private static Dao dao; + + public static void initDB(ConnectionSource connectionSource) throws SQLException { + TableUtils.createTableIfNotExists(connectionSource, DimensionProgress.class); + dao = DaoManager.createDao(connectionSource, DimensionProgress.class); + + List allProgress = dao.queryForAll(); + allProgress.forEach(progress -> progressCache.put(progress.getDimensionKey(), progress)); + } + + public static void initConfig() { + File configFile = new File(OMCPlugin.getInstance().getDataFolder(), "data/dimsopener.yml"); + + if (!configFile.exists()) { + OMCPlugin.getInstance().saveResource("data/dimsopener.yml", false); + } + + YamlConfiguration config = YamlConfiguration.loadConfiguration(configFile); + ConfigurationSection dimsSection = config.getConfigurationSection("dims"); + + if (dimsSection == null) return; + + for (String dimKey : dimsSection.getKeys(false)) { + ConfigurationSection dimSection = dimsSection.getConfigurationSection(dimKey); + if (dimSection == null) continue; + + List stepsList = dimSection.getList("steps"); + if (stepsList == null) continue; + + List steps = new ArrayList<>(); + + for (Object stepObj : stepsList) { + if (!(stepObj instanceof Map stepMap)) continue; + + System.out.println("Processing step map: " + stepMap); + + for (Map.Entry entry : stepMap.entrySet()) { + String itemType = entry.getKey().toString(); + if (!(entry.getValue() instanceof Map itemData)) continue; + + int requiredAmount = itemData.containsKey("count") ? ((Number) itemData.get("count")).intValue() : 0; + int nextStepDelay = itemData.containsKey("next_step_delay") ? ((Number) itemData.get("next_step_delay")).intValue() : 0; + + if (requiredAmount == 0 && nextStepDelay == 0) continue; + + steps.add(new DimensionStep(itemType, requiredAmount, nextStepDelay)); + } + } + + String dimensionName = dimSection.getString("name", dimKey); + String dimensionIconStr = dimSection.getString("icon", "minecraft:grass_block"); + ItemStack dimensionIcon; + + System.out.println(dimensionIconStr.split(":")[0]); + + if (dimensionIconStr.split(":")[0].equals("minecraft")) { + dimensionIcon = new ItemStack(Material.matchMaterial(dimensionIconStr.split(":")[1]) != null ? Material.matchMaterial(dimensionIconStr.split(":")[1]) : Material.GRASS_BLOCK); + } else { + System.out.println("Loading custom item for dimension icon: " + dimensionIconStr); + dimensionIcon = CustomItemRegistry.getByName(dimensionIconStr).getBest(); + } + + System.out.println("Loaded dimension: " + dimKey + " with name: " + dimensionName + " and icon: " + dimensionIcon); + + dimensionConfigs.put(dimKey, new DimensionConfig(dimKey, dimensionName, dimensionIcon, steps)); + + if (!progressCache.containsKey(dimKey)) { + DimensionProgress progress = new DimensionProgress(dimKey); + progressCache.put(dimKey, progress); + } + } + } + + public static DimensionProgress getProgress(String dimensionKey) { + return progressCache.get(dimensionKey); + } + + public static DimensionConfig getConfig(String dimensionKey) { + return dimensionConfigs.get(dimensionKey); + } + + public static boolean contributeItems(String dimensionKey, ItemStack item) { + DimensionProgress progress = progressCache.get(dimensionKey); + DimensionConfig config = dimensionConfigs.get(dimensionKey); + + + if (progress == null || config == null || progress.isUnlocked() || !progress.canProgressToNextStep()) return false; + + List steps = config.steps(); + int currentStepIndex = progress.getCurrentStep(); + + if (currentStepIndex >= steps.size()) { + return false; + } + + DimensionStep currentStep = steps.get(currentStepIndex); + if (!item.getType().toString().equals(currentStep.itemType())) return false; + + int toAdd = Math.min(item.getAmount(), currentStep.count() - progress.getItemsCollected()); + item.setAmount(item.getAmount() - toAdd); + + if (progress.getItemsCollected() >= currentStep.count()) + completeCurrentStep(progress, currentStep); + + return true; + } + + private static void completeCurrentStep(DimensionProgress progress, DimensionStep currentStep) { + progress.setItemsCollected(0); + progress.setCurrentStep(progress.getCurrentStep() + 1); + + DimensionConfig config = dimensionConfigs.get(currentStep.itemType()); + if (config == null) return; + + if (progress.getCurrentStep() >= config.steps().size()) { + progress.setUnlocked(true); + progress.setNextStepUnlockTime(0); + + Bukkit.getPluginManager().callEvent( + new DimensionUnlockedEvent(progress.getDimensionKey()) + ); + } else { + long unlockTime = System.currentTimeMillis() + TimeUnit.MINUTES.toMillis(currentStep.nextStepDelay()); + progress.setNextStepUnlockTime(unlockTime); + } + } + + private static void save() { + try { + for (DimensionProgress progress : progressCache.values()) { + dao.createOrUpdate(progress); + } + } catch (SQLException e) { + throw new RuntimeException(e); + } + } + + public static String getFormattedTimeRemaining(String dimensionKey) { + DimensionProgress progress = progressCache.get(dimensionKey); + if (progress == null || progress.isUnlocked() || progress.canProgressToNextStep()) { + return "Disponible maintenant"; + } + + long remain = progress.getCurrentStep() - System.currentTimeMillis(); + long hours = TimeUnit.MILLISECONDS.toHours(remain); + long minutes = TimeUnit.MILLISECONDS.toMinutes(remain) % 60; + + return String.format("Disponible dans %dh %dm", hours, minutes); + } + + public static Map getAllConfigs() { + return Collections.unmodifiableMap(dimensionConfigs); + } +} diff --git a/src/main/java/fr/openmc/core/features/dimsopener/command/DimensionCommands.java b/src/main/java/fr/openmc/core/features/dimsopener/command/DimensionCommands.java new file mode 100644 index 000000000..db546e8f5 --- /dev/null +++ b/src/main/java/fr/openmc/core/features/dimsopener/command/DimensionCommands.java @@ -0,0 +1,16 @@ +package fr.openmc.core.features.dimsopener.command; + +import fr.openmc.core.features.dimsopener.menus.DimensionListMenu; +import org.bukkit.entity.Player; +import revxrsal.commands.annotation.Command; +import revxrsal.commands.annotation.DefaultFor; + +@Command("dimension") +public class DimensionCommands { + + @DefaultFor("~") + public void dimension(Player player) { + new DimensionListMenu(player).open(); + } + +} diff --git a/src/main/java/fr/openmc/core/features/dimsopener/event/DimensionUnlockedEvent.java b/src/main/java/fr/openmc/core/features/dimsopener/event/DimensionUnlockedEvent.java new file mode 100644 index 000000000..23213bf03 --- /dev/null +++ b/src/main/java/fr/openmc/core/features/dimsopener/event/DimensionUnlockedEvent.java @@ -0,0 +1,28 @@ +package fr.openmc.core.features.dimsopener.event; + +import lombok.Getter; +import org.bukkit.event.Event; +import org.bukkit.event.HandlerList; +import org.jetbrains.annotations.NotNull; + +@Getter +public class DimensionUnlockedEvent extends Event { + + private static final HandlerList HANDLERS = new HandlerList(); + + private final String dimensionKey; + + public DimensionUnlockedEvent(String dimensionKey) { + this.dimensionKey = dimensionKey; + } + + @NotNull + @Override + public HandlerList getHandlers() { + return HANDLERS; + } + + public static HandlerList getHandlerList() { + return HANDLERS; + } +} \ No newline at end of file diff --git a/src/main/java/fr/openmc/core/features/dimsopener/menus/DimensionListMenu.java b/src/main/java/fr/openmc/core/features/dimsopener/menus/DimensionListMenu.java new file mode 100644 index 000000000..9dd0b25f0 --- /dev/null +++ b/src/main/java/fr/openmc/core/features/dimsopener/menus/DimensionListMenu.java @@ -0,0 +1,146 @@ +package fr.openmc.core.features.dimsopener.menus; + +import fr.openmc.api.menulib.Menu; +import fr.openmc.api.menulib.PaginatedMenu; +import fr.openmc.api.menulib.utils.InventorySize; +import fr.openmc.api.menulib.utils.ItemBuilder; +import fr.openmc.api.menulib.utils.MenuUtils; +import fr.openmc.api.menulib.utils.StaticSlots; +import fr.openmc.core.features.dimsopener.DimensionStep; +import fr.openmc.core.features.dimsopener.DimsOpenerManager; +import fr.openmc.core.features.dimsopener.DimensionConfig; +import fr.openmc.core.features.dimsopener.model.DimensionProgress; +import net.kyori.adventure.text.Component; +import org.bukkit.Material; +import org.bukkit.entity.Player; +import org.bukkit.event.inventory.InventoryClickEvent; +import org.bukkit.event.inventory.InventoryCloseEvent; +import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class DimensionListMenu extends PaginatedMenu { + + public DimensionListMenu(Player owner) { + super(owner); + } + + @Override + public @Nullable Material getBorderMaterial() { + return Material.BLUE_STAINED_GLASS_PANE; + } + + @Override + public @NotNull List getStaticSlots() { + return StaticSlots.getStandardSlots(getInventorySize()); + } + + @Override + public @NotNull String getName() { + return "§6§lDimensions" + (getNumberOfPages() > 1 ? " §7- Page " + (getPage() + 1) : ""); + } + + @Override + public String getTexture() { + return null; + } + + @Override + public @NotNull InventorySize getInventorySize() { + return InventorySize.NORMAL; + } + + @Override + public int getSizeOfItems() { + return 6; + } + + @Override + public void onInventoryClick(InventoryClickEvent e) { + e.setCancelled(true); + } + + @Override + public void onClose(InventoryCloseEvent event) {} + + @Override + public List getItems() { + List items = new ArrayList<>(); + for (Map.Entry entry : DimsOpenerManager.getAllConfigs().entrySet()) { + String dimKey = entry.getKey(); + DimensionConfig config = entry.getValue(); + DimensionProgress progress = DimsOpenerManager.getProgress(dimKey); + + if (progress == null) continue; + + List lore = new ArrayList<>(); + + if (progress.isUnlocked()) { + lore.add(Component.text("§a§lDÉVERROUILLÉE")); + lore.add(Component.text("")); + lore.add(Component.text("§7Cette dimension est accessible !")); + } else { + int currentStepIndex = progress.getCurrentStep(); + if (config.steps().isEmpty()) continue; + DimensionStep currentStep = config.steps().get(currentStepIndex); + + lore.add(Component.text("§eÉtape §6" + (currentStepIndex + 1) + "§e/§6" + config.steps().size())); + lore.add(Component.text("")); + lore.add(Component.text("§7Item requis: §f" + getItemName(currentStep.itemType()))); + lore.add(Component.text("§7Progrès: §6" + progress.getItemsCollected() + "§7/§6" + currentStep.count())); + lore.add(Component.text("")); + + if (!progress.canProgressToNextStep()) { + String timeRemaining = DimsOpenerManager.getFormattedTimeRemaining(dimKey); + lore.add(Component.text("§cProchaine contribution: §e" + timeRemaining)); + } else { + lore.add(Component.text("§a✔ Vous pouvez contribuer !")); + } + + lore.add(Component.text("")); + lore.add(Component.text("§e§lCLIQUEZ POUR CONTRIBUER")); + } + + ItemBuilder item = new ItemBuilder(this, config.icon(), meta -> { + meta.displayName(Component.text(config.name())); + meta.lore(lore); + }).setItemId("dimension_" + dimKey); + + items.add(item); + } + + return items; + } + + @Override + public Map getButtons() { + Map buttons = new HashMap<>(); + System.out.println("Page: " + this.getPage() + " / " + this.getNumberOfPages()); + if (!isLastPage()) buttons.put(18, MenuUtils.getNavigationButtons(this).get(0).setPreviousPageButton()); + buttons.put(22, MenuUtils.getNavigationButtons(this).get(1).setCloseButton()); + if (this.getPage() < 1) buttons.put(26, MenuUtils.getNavigationButtons(this).get(2).setNextPageButton()); + return buttons; + } + + @Override + public List getTakableSlot() { + return List.of(); + } + + @Override + public int getNumberOfPages() { + int itemCount = DimsOpenerManager.getAllConfigs().size(); + int itemsPerPage = getInventorySize().getSize() - 9; + return (int) Math.ceil((double) itemCount / itemsPerPage); + } + + private String getItemName(String itemType) { + String name = itemType.replace("minecraft:", "").replace("_", " "); + return name.substring(0, 1).toUpperCase() + name.substring(1); + } +} \ No newline at end of file diff --git a/src/main/java/fr/openmc/core/features/dimsopener/model/DimensionProgress.java b/src/main/java/fr/openmc/core/features/dimsopener/model/DimensionProgress.java new file mode 100644 index 000000000..0442ac73a --- /dev/null +++ b/src/main/java/fr/openmc/core/features/dimsopener/model/DimensionProgress.java @@ -0,0 +1,47 @@ +package fr.openmc.core.features.dimsopener.model; + +import com.j256.ormlite.field.DatabaseField; +import com.j256.ormlite.table.DatabaseTable; +import fr.openmc.core.features.dimsopener.DimensionStep; +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +@DatabaseTable(tableName = "dimension_progress") +public class DimensionProgress { + + @DatabaseField(generatedId = true) + private int id; + + @DatabaseField(canBeNull = false, index = true, columnName = "dimension_key") + private String dimensionKey; + + @DatabaseField(canBeNull = false, columnName = "current_step") + private int currentStep; + + @DatabaseField(canBeNull = false, columnName = "items_collected") + private int itemsCollected; + + @DatabaseField(canBeNull = false, columnName = "next_step_unlock_time") + private long nextStepUnlockTime; + + @DatabaseField(canBeNull = false, columnName = "unlocked") + private boolean isUnlocked; + + public DimensionProgress() { + // Default constructor for ORMLite + } + + public DimensionProgress(String dimensionKey) { + this.dimensionKey = dimensionKey; + this.currentStep = 0; + this.itemsCollected = 0; + this.nextStepUnlockTime = 0; + this.isUnlocked = false; + } + + public boolean canProgressToNextStep() { + return System.currentTimeMillis() >= nextStepUnlockTime; + } +} diff --git a/src/main/java/fr/openmc/core/utils/database/DatabaseManager.java b/src/main/java/fr/openmc/core/utils/database/DatabaseManager.java index 699c2e1d9..9b97dcef8 100644 --- a/src/main/java/fr/openmc/core/utils/database/DatabaseManager.java +++ b/src/main/java/fr/openmc/core/utils/database/DatabaseManager.java @@ -13,6 +13,7 @@ import fr.openmc.core.features.city.sub.statistics.CityStatisticsManager; import fr.openmc.core.features.city.sub.war.WarManager; import fr.openmc.core.features.contest.managers.ContestManager; +import fr.openmc.core.features.dimsopener.DimsOpenerManager; import fr.openmc.core.features.economy.BankManager; import fr.openmc.core.features.economy.EconomyManager; import fr.openmc.core.features.economy.TransactionsManager; @@ -69,6 +70,7 @@ public DatabaseManager() { MascotsManager.initDB(connectionSource); PlayerSettingsManager.initDB(connectionSource); CityStatisticsManager.initDB(connectionSource); + DimsOpenerManager.initDB(connectionSource); } catch (SQLException e) { OMCPlugin.getInstance().getSLF4JLogger().error("Failed to initialize the database connection.", e); throw new RuntimeException(e); diff --git a/src/main/resources/data/dimsopener.yml b/src/main/resources/data/dimsopener.yml new file mode 100644 index 000000000..653fba349 --- /dev/null +++ b/src/main/resources/data/dimsopener.yml @@ -0,0 +1,15 @@ +dims: + "minecraft:nether": + name: "§4§lNETHER" + icon: "minecraft:crimson_nylium" + steps: + - minecraft:cobblestone: + count: 64 + next_step_delay: 1 + "custom:test": + name: "§4§lTEST" + icon: "omc_items:aywenite" + steps: + - minecraft:cobblestone: + count: 64 + next_step_delay: 1 \ No newline at end of file