diff --git a/.idea/ant.xml b/.idea/ant.xml new file mode 100644 index 0000000..a2a4769 --- /dev/null +++ b/.idea/ant.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml index b589d56..b86273d 100644 --- a/.idea/compiler.xml +++ b/.idea/compiler.xml @@ -1,6 +1,6 @@ - + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml index 5b99cf8..5cd9a10 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -1,7 +1,7 @@ - + \ No newline at end of file diff --git a/.idea/saveactions_settings.xml b/.idea/saveactions_settings.xml new file mode 100644 index 0000000..7a3a79c --- /dev/null +++ b/.idea/saveactions_settings.xml @@ -0,0 +1,16 @@ + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/build.gradle b/build.gradle index 07160dc..f1c12b7 100644 --- a/build.gradle +++ b/build.gradle @@ -1,7 +1,6 @@ plugins { id 'java' id("xyz.jpenilla.run-paper") version "2.3.1" - id 'com.rikonardo.papermake' version '1.0.6' } group = 'hdvtdev' @@ -10,6 +9,7 @@ version = '0.0.1-a' repositories { mavenCentral() maven { url 'https://repo.md-5.net/content/groups/public/' } + maven { url 'https://jitpack.io' } maven { name = "papermc-repo" url = "https://repo.papermc.io/repository/maven-public/" @@ -22,17 +22,10 @@ repositories { dependencies { compileOnly("io.papermc.paper:paper-api:1.20.4-R0.1-SNAPSHOT") + implementation("com.github.lewysDavies:Java-Probability-Collection:v0.8") implementation group: 'me.libraryaddict.disguises', name: 'libsdisguises', version: '11.0.6' } -tasks { - runServer { - // Configure the Minecraft version for our task. - // This is the only required configuration besides applying the plugin. - // Your plugin's jar (or shadowJar if present) will be used automatically. - minecraftVersion("1.20") - } -} def targetJavaVersion = 21 java { @@ -62,6 +55,10 @@ processResources { } jar { + destinationDirectory.set(file("/home/hadvart/Documents/Minecraft/Pufferfish 1.20.4/plugins")) + from sourceSets.main.output + from { configurations.runtimeClasspath.findAll { it.name.startsWith('Java-Probability-Collection') }.collect { zipTree(it) } } + duplicatesStrategy = DuplicatesStrategy.EXCLUDE } diff --git a/build.xml b/build.xml new file mode 100644 index 0000000..44efce6 --- /dev/null +++ b/build.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/java/hdvtdev/blockAndSeek/BlockAndSeek.java b/src/main/java/hdvtdev/blockAndSeek/BlockAndSeek.java index de5db00..de409f0 100644 --- a/src/main/java/hdvtdev/blockAndSeek/BlockAndSeek.java +++ b/src/main/java/hdvtdev/blockAndSeek/BlockAndSeek.java @@ -3,34 +3,63 @@ package hdvtdev.blockAndSeek; import me.libraryaddict.disguise.LibsDisguises; import org.bukkit.Bukkit; import org.bukkit.command.CommandExecutor; +import org.bukkit.plugin.Plugin; import org.bukkit.plugin.java.JavaPlugin; import java.io.File; +import java.io.IOException; +import java.io.InputStream; import java.util.Objects; +import java.util.logging.Logger; public class BlockAndSeek extends JavaPlugin implements CommandExecutor { - private static File dataFolder; + private static Plugin javaPlugin; + + public static Plugin getInstance() { + return javaPlugin; + } public static File getPluginDataFolder() { - return dataFolder; + return javaPlugin.getDataFolder(); + } + + public static InputStream getPluginResource(String resource) { + return javaPlugin.getResource(resource); + } + + public static void saveResource(File file) { + saveResource(file.getAbsolutePath()); + } + + public static void saveResource(String file) { + javaPlugin.saveResource(file, false); + } + + public static Logger getPluginLogger() { + return javaPlugin.getLogger(); } @Override public void onEnable() { - dataFolder = getDataFolder(); + javaPlugin = this; + LibsDisguises libsDisguises = (LibsDisguises) Bukkit.getPluginManager().getPlugin("LibsDisguises"); if (libsDisguises == null) { - getLogger().severe("LibsDisguises не найден!"); + getLogger().severe("LibsDisguises not found! It's required for the plugin to work!"); super.onDisable(); } - Localization.load(this); - ConfigManager.load(); + try { + ConfigManager.loadAll(); + } catch (IOException e) { + getLogger().severe("Failed to save some .yml configs!"); + } Objects.requireNonNull(getCommand("blockandseek")).setExecutor(new CommandListener()); + getServer().getPluginManager().registerEvents(new EventListener(), this); } diff --git a/src/main/java/hdvtdev/blockAndSeek/BlockAndSeekContainer.java b/src/main/java/hdvtdev/blockAndSeek/BlockAndSeekContainer.java new file mode 100644 index 0000000..0cd54f5 --- /dev/null +++ b/src/main/java/hdvtdev/blockAndSeek/BlockAndSeekContainer.java @@ -0,0 +1,24 @@ +package hdvtdev.blockAndSeek; + +import org.bukkit.Bukkit; +import org.bukkit.NamespacedKey; +import org.bukkit.scoreboard.Scoreboard; +import org.bukkit.scoreboard.Team; + +public class BlockAndSeekContainer { + + public static final NamespacedKey SOUND_ITEM = new NamespacedKey(BlockAndSeek.getInstance(), "BlockAndSeekSoundItem"); + public static final NamespacedKey FREEZE_ITEM = new NamespacedKey(BlockAndSeek.getInstance(), "BlockAndSeekFreezeItem"); + public static final NamespacedKey FROZEN_PLAYER = new NamespacedKey(BlockAndSeek.getInstance(), "BlockAndSeekFrozenPlayer"); + public static final NamespacedKey PLAYER = new NamespacedKey(BlockAndSeek.getInstance(), "BlockAndSeekPlayer"); + + public static final Team NO_COLLIDE_TEAM; + + static { + Scoreboard scoreboard = Bukkit.getScoreboardManager().getMainScoreboard(); + Team team = scoreboard.getTeam("BlockAndSeekNoCollide"); + if (team == null) team = scoreboard.registerNewTeam("BlockAndSeekNoCollide"); + team.setOption(Team.Option.COLLISION_RULE, Team.OptionStatus.NEVER); + NO_COLLIDE_TEAM = team; + } +} diff --git a/src/main/java/hdvtdev/blockAndSeek/BlockAndSeekGame.java b/src/main/java/hdvtdev/blockAndSeek/BlockAndSeekGame.java index 2bf70e5..a9beda5 100644 --- a/src/main/java/hdvtdev/blockAndSeek/BlockAndSeekGame.java +++ b/src/main/java/hdvtdev/blockAndSeek/BlockAndSeekGame.java @@ -1,29 +1,94 @@ package hdvtdev.blockAndSeek; -import org.bukkit.Bukkit; -import org.bukkit.Location; -import org.bukkit.World; +import me.libraryaddict.disguise.DisguiseAPI; +import org.bukkit.Material; import org.bukkit.entity.Player; -import org.jetbrains.annotations.NotNull; +import org.bukkit.persistence.PersistentDataType; -import java.util.*; +import java.security.SecureRandom; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicBoolean; public class BlockAndSeekGame { - private final Set players = Collections.synchronizedSet(new HashSet<>()); + private final ConcurrentHashMap players = new ConcurrentHashMap<>(); - public BlockAndSeekGame(String name, List players) { - for (String player : players) { - this.addPlayer(player); + private AtomicBoolean started = new AtomicBoolean(false); + private final String name; + + public BlockAndSeekGame(String name) { + this.name = name; + } + + public void end() { + for (Player player : players.keySet()) { + EventListener.unfreezePlayer(player); + player.getPersistentDataContainer().remove(BlockAndSeekContainer.PLAYER); + player.sendBlockChange(player.getLocation(), Material.AIR.createBlockData()); + DisguiseAPI.undisguiseToAll(player); } } - public void addPlayer(String name) { - Player p = Bukkit.getPlayerExact(name); - if (p != null) players.add(p); + public boolean addPlayer(Player player) { + if (started.get()) { + return false; + } + player.getPersistentDataContainer().set(BlockAndSeekContainer.PLAYER, PersistentDataType.STRING, name); + players.put(player, PlayerType.HIDER); + return true; + } + + public void removePlayer(Player player) { + players.remove(player); + } + + public Set getPlayers() { + return players.keySet(); + } + + public Player getLastHider() { + for (Map.Entry entry : players.entrySet()) { + if (entry.getValue() == PlayerType.HIDER) return entry.getKey(); + } + return null; + } + + public int seekersCount() { + return (int) players.values().stream().filter(f -> f.equals(PlayerType.SEEKER)).count(); + } + + public int hidersCound() { + return (int) players.values().stream().filter(f -> f.equals(PlayerType.HIDER)).count(); + } + + public int playerCount() { + return players.size(); + } + + public void start() { + started.set(true); + } + + public boolean isStarted() { + return started.get(); + } + + public Player selectRandomSeeker() { + SecureRandom random = new SecureRandom(); + int i = 0; + int randomNum = random.nextInt(0, players.size()); + for (Player player : players.keySet()) { + if (i == randomNum) return player; + } + return null; + } + + private enum PlayerType { + SEEKER, + HIDER } - - } diff --git a/src/main/java/hdvtdev/blockAndSeek/BlockAndSeekMap.java b/src/main/java/hdvtdev/blockAndSeek/BlockAndSeekMap.java new file mode 100644 index 0000000..c78844b --- /dev/null +++ b/src/main/java/hdvtdev/blockAndSeek/BlockAndSeekMap.java @@ -0,0 +1,13 @@ +package hdvtdev.blockAndSeek; + +import org.bukkit.inventory.ItemStack; + +import java.util.List; + +public record BlockAndSeekMap(List spawn, List lobby, int duration, List blocks) { + + + public record Block(ItemStack block, int chance) { + } + +} diff --git a/src/main/java/hdvtdev/blockAndSeek/CommandListener.java b/src/main/java/hdvtdev/blockAndSeek/CommandListener.java index 1d45ab3..cf72e20 100644 --- a/src/main/java/hdvtdev/blockAndSeek/CommandListener.java +++ b/src/main/java/hdvtdev/blockAndSeek/CommandListener.java @@ -1,38 +1,32 @@ package hdvtdev.blockAndSeek; -import me.libraryaddict.disguise.DisguiseAPI; -import me.libraryaddict.disguise.disguisetypes.Disguise; -import me.libraryaddict.disguise.disguisetypes.DisguiseType; -import me.libraryaddict.disguise.disguisetypes.MiscDisguise; +import hdvtdev.blockAndSeek.roulette.RouletteCreator; import net.kyori.adventure.text.minimessage.MiniMessage; -import org.bukkit.Bukkit; -import org.bukkit.Location; import org.bukkit.Material; -import org.bukkit.World; -import org.bukkit.command.*; +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.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; +import org.bukkit.persistence.PersistentDataType; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.io.IOException; import java.util.ArrayList; import java.util.List; -import java.util.Map; +import java.util.Set; public class CommandListener implements CommandExecutor, TabCompleter { - public static List getAllCommands() { - return List.of("tpp", "morph"); - } - - + private static final MiniMessage miniMessage = MiniMessage.miniMessage(); @Override public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) { - int argsLen = args.length; if (argsLen == 0) { @@ -41,54 +35,77 @@ public class CommandListener implements CommandExecutor, TabCompleter { } switch (args[0]) { + case "test" -> { + if (sender instanceof Player player) { + RouletteCreator.createRoulette(player, null, true); + } + } + case "freeze" -> { + if (sender instanceof Player player) { + ItemStack foo = new ItemStack(Material.HEART_OF_THE_SEA); + ItemMeta fooMeta = foo.getItemMeta(); + fooMeta.displayName(MiniMessage.miniMessage().deserialize("Freeze")); + fooMeta.getPersistentDataContainer().set(BlockAndSeekContainer.FREEZE_ITEM, PersistentDataType.BOOLEAN, true); + foo.setItemMeta(fooMeta); + player.getInventory().addItem(foo); + } + } + case "foo" -> { + if (sender instanceof Player player) { + ItemStack foo = new ItemStack(Material.BROWN_DYE); + ItemMeta fooMeta = foo.getItemMeta(); + fooMeta.displayName(MiniMessage.miniMessage().deserialize("SoundMaker3000")); + fooMeta.getPersistentDataContainer().set(BlockAndSeekContainer.SOUND_ITEM, PersistentDataType.BOOLEAN, true); + foo.setItemMeta(fooMeta); + player.getInventory().addItem(foo); + } + } case "map" -> { - if (argsLen > 1) { - switch (args[1]) { - case "list" -> sender.sendMessage(Localization.get("maps-list", "{maps}", ConfigManager.createdMaps().toString())); - case "create" -> { - if (argsLen > 2) { - String mapName = args[2]; - World world = Bukkit.getWorld(mapName); - if (world == null) { - sender.sendMessage(Localization.get("map-missing-world", "{world}", mapName)); - } else { - try { - if (ConfigManager.addMap(mapName)) sender.sendMessage(Localization.get("map-created", "{map}", mapName)); - else sender.sendMessage(Localization.get("map-already-exist", "{map}", mapName)); - } catch (IOException e) { - sender.sendMessage(Localization.get("map-creation-failed", "{error}", e.getMessage())); - } + if (sender.hasPermission("blockandseek.manage")) { + if (argsLen > 1) { + switch (args[1]) { + case "list" -> { + StringBuilder buffer = new StringBuilder(Localization.get("maps-available")); + String listElement = Localization.get("maps-available-element"); + Set readyMaps = ConfigManager.getReadyMaps(); + for (String map : ConfigManager.getAllMaps()) { + buffer.append("\n").append(listElement.replace("{map}", map).replace("{color-status}", + readyMaps.contains(map) ? "" : "")); } - } else sender.sendMessage(Localization.get("not-enough-arguments", "{usage}", "/blockandseek create [MAP NAME]")); + sender.sendMessage(miniMessage.deserialize(buffer.toString())); + } } - default -> { - if (ConfigManager.createdMaps().contains(args[1])) { - if (argsLen > 2) { - switch (args[2]) { - case "setspawn" -> {} - case "setlobby" -> {} - case "setduration" -> {} - default -> sender.sendMessage(Localization.get("unknown-subcommand", "{subcommand}", args[2])); - } - } else sender.sendMessage(Localization.get("not-enough-arguments", "{usage}", String.format("/blockandseek create %s [SUBCOMMAND]", args[1]))); - } else sender.sendMessage(Localization.get("map-not-exist", "{map}", args[1])); - } - } - } else sender.sendMessage(Localization.get("not-enough-arguments", "{usage}", "/blockandseek map [MAP NAME | SUBCOMMAND]")); + } else + sender.sendMessage(Localization.getComponent("not-enough-arguments", "{command}", "/blockandseek map", "{help}", "[MAP NAME | COMMANDS]")); + + } else sender.sendMessage(Localization.getComponent("not-enough-permissions")); } case "reload" -> { - if (argsLen > 1) { - switch (args[1]) { - case "messages" -> { - Localization.reload(); - sender.sendMessage(Localization.get("messages-reload")); + if (sender.hasPermission("blockandseek.manage")) { + if (argsLen > 1) { + switch (args[1]) { + case "localization" -> { + try { + ConfigManager.load("localization.yml"); + sender.sendMessage(Localization.getPrefix().append(Localization.getComponent("successful-reload", "{config}", "localization.yml"))); + } catch (IOException e) { + sender.sendMessage(Localization.getComponent("failed-reload", "{config}", "localization.yml", "{e}", e.getMessage())); + } + + } + case "maps" -> { + try { + ConfigManager.load(null); + } catch (IOException e) { + throw new RuntimeException(e); + } + sender.sendMessage(Localization.get("maps-reload")); + } } - case "maps" -> { - ConfigManager.load(); - sender.sendMessage(Localization.get("maps-reload")); - } - } - } + } else + sender.sendMessage(Localization.get("not-enough-arguments", "{usage}", "/blockandseek reload [messages | maps]")); + + } else sender.sendMessage(Localization.get("not-enough-permissions")); } } @@ -98,7 +115,6 @@ public class CommandListener implements CommandExecutor, TabCompleter { */ - return true; } @@ -106,23 +122,41 @@ public class CommandListener implements CommandExecutor, TabCompleter { public @Nullable List onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) { sender.sendActionBar(MiniMessage.miniMessage().deserialize("" + args.length)); return switch (args.length) { - case 1 -> List.of("reload", "help", "map", "join"); + case 1 -> { + if (sender.hasPermission("blockandseek.manage")) { + yield List.of("reload", "help", "map", "join"); + } else yield List.of("help", "join"); + } case 2 -> switch (args[0]) { case "map" -> { - List scmds = new ArrayList<>(List.of("create", "list")); - scmds.addAll(ConfigManager.createdMaps()); + List scmds = new ArrayList<>(); + /* + if (sender.hasPermission("blockandseek.manage")) { + scmds.addAll(List.of("create", "list")); + scmds.addAll(ConfigManager.createdMaps()); + } + + */ yield scmds; } - case "join" -> List.of("test"); - case "reload" -> List.of("messages", "maps"); + case "join" -> List.of("test"); //TODO + case "reload" -> { + if (sender.hasPermission("blockandseek.manage")) { + yield List.of("messages", "maps"); + } else yield List.of(); + } default -> List.of(); }; case 3 -> switch (args[1]) { case "create", "list" -> List.of(); default -> { - if (ConfigManager.createdMaps().contains(args[1])) { + /* + if (ConfigManager.createdMaps().contains(args[1]) && sender.hasPermission("blockandseek.manage")) { yield List.of("setspawn", "setlobby", "setduration"); } else yield List.of(); + + */ + yield List.of(); } }; default -> List.of(); diff --git a/src/main/java/hdvtdev/blockAndSeek/ConfigManager.java b/src/main/java/hdvtdev/blockAndSeek/ConfigManager.java index f7c3539..dbd4884 100644 --- a/src/main/java/hdvtdev/blockAndSeek/ConfigManager.java +++ b/src/main/java/hdvtdev/blockAndSeek/ConfigManager.java @@ -1,57 +1,252 @@ package hdvtdev.blockAndSeek; +import org.bukkit.Material; +import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.file.YamlConfiguration; -import org.jetbrains.annotations.NotNull; +import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.Nullable; import java.io.File; import java.io.IOException; +import java.io.InputStreamReader; +import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; public class ConfigManager { - private static final File mapsConfigFile = new File(BlockAndSeek.getPluginDataFolder(), "maps.yml"); - private static final ConcurrentHashMap mapsConfigs = new ConcurrentHashMap<>(); + private static volatile ConcurrentHashMap localization = new ConcurrentHashMap<>(); + private static volatile ConcurrentHashMap config = new ConcurrentHashMap<>(); + private static volatile ConcurrentHashMap maps = new ConcurrentHashMap<>(); - public static Set createdMaps() { - return mapsConfigs.keySet(); + private static final File mapsFile = new File(BlockAndSeek.getPluginDataFolder(), "maps.yml"); + + public static Set getAllMaps() { + return YamlConfiguration.loadConfiguration(mapsFile).getKeys(false); } - public static MapConfig getMapConfig(@NotNull String name) { - return mapsConfigs.get(name); + public enum MapStatus { + SPAWN_REQUIRED, + LOBBY_REQUIRED, + DURATION_REQUIRED, + BLOCKS_REQUIRED } - public static boolean addMap(String name) throws IOException { - if (mapsConfigs.containsKey(name)) return false; - mapsConfigs.put(name, MapConfig.defaults()); - YamlConfiguration config = YamlConfiguration.loadConfiguration(mapsConfigFile); - config.set(name + ".spawn", "null"); - config.set(name + ".duration", "null"); - config.set(name + ".lobby", "null"); + public static Set getReadyMaps() { + return maps.keySet(); + } - config.save(mapsConfigFile); + public static @Nullable Set checkMap(String name) { + + Set status = new HashSet<>(); + + YamlConfiguration configuration = YamlConfiguration.loadConfiguration(mapsFile); + ConfigurationSection section = configuration.getConfigurationSection(name); + + if (section != null) { + List spawn = section.getIntegerList("spawn"); + if (spawn.size() != 3) status.add(MapStatus.SPAWN_REQUIRED); + List lobby = section.getIntegerList("lobby"); + if (lobby.size() != 3) status.add(MapStatus.LOBBY_REQUIRED); + int duration = section.getInt("duration"); + if (duration <= 0) status.add(MapStatus.DURATION_REQUIRED); + List blocks = section.getMapList("blocks").stream().map( + block -> { + try { + return new BlockAndSeekMap.Block( + new ItemStack(Material.valueOf(((String) block.get("block")).toUpperCase())), + (int) block.get("chance") + ); + } catch (IllegalArgumentException | ClassCastException ignored) { + return null; + } + + } + ).toList(); + if (blocks.isEmpty() || new HashSet<>(blocks).size() == 1) status.add(MapStatus.BLOCKS_REQUIRED); + + if (status.isEmpty()) maps.put(name, new BlockAndSeekMap(spawn, lobby, duration, blocks)); + + } else return null; + + return status; + } + + public static boolean addDefaultMap(String name) { + + YamlConfiguration configuration = YamlConfiguration.loadConfiguration(mapsFile); + + if (configuration.get(name) != null) return false; + + ConfigurationSection section = configuration.createSection(name); + section.set("spawn", List.of()); + section.set("lobby", List.of()); + section.set("duration", 0); + section.set("blocks", List.of(Map.of())); + + try { + configuration.save(mapsFile); + } catch (IOException ignored) { + return false; + } return true; } + public static boolean setMapProperty(String map, String property, Object value) { + YamlConfiguration configuration = YamlConfiguration.loadConfiguration(mapsFile); + ConfigurationSection section = configuration.getConfigurationSection(map); - public static void load() { - mapsConfigs.clear(); - YamlConfiguration config = YamlConfiguration.loadConfiguration(mapsConfigFile); - for (String mapKey : config.getKeys(false)) { - List spawn = config.getLongList(mapKey + ".spawn"); - List lobby = config.getLongList(mapKey + ".lobby"); - int duration = config.getInt(mapKey + ".duration"); - MapConfig mapConfig = new MapConfig(spawn, lobby, duration); - mapsConfigs.put(mapKey, mapConfig); + if (section != null) { + section.set(property, value); + try { + configuration.save(mapsFile); + } catch (IOException e) { + return false; + } } + + return true; } - public record MapConfig(List spawn, List lobby, int duration) { - public static MapConfig defaults() { - return new MapConfig(null, null, -1); + public static void loadAll() throws IOException { + load("config.yml"); + load("localization.yml"); + load("maps.yml"); + } + + public static void load(String file) throws IOException { + + File conf = new File(BlockAndSeek.getPluginDataFolder(), file); + + YamlConfiguration defaultConfiguration = YamlConfiguration.loadConfiguration( + new InputStreamReader(BlockAndSeek.getPluginResource(file))); + + if (!conf.exists()) { + BlockAndSeek.saveResource(file); + + ConcurrentHashMap confMap = new ConcurrentHashMap<>(); + + switch (file) { + case "config.yml" -> { + for (String key : defaultConfiguration.getKeys(false)) { + confMap.put(key, defaultConfiguration.getString(key, "NULL")); + } + config = confMap; + } + case "localization.yml" -> { + for (String key : defaultConfiguration.getConfigurationSection("en_US").getKeys(false)) { + confMap.put(key, defaultConfiguration.getString(key, "NULL")); + } + localization = confMap; + Localization.update(); + } + } + + + } else { + switch (file) { + case "config.yml" -> loadConfig(conf, defaultConfiguration); + case "localization.yml" -> loadLocalization(conf, defaultConfiguration); + case "maps.yml" -> loadMaps(conf); + } } + + + } + + private static void loadMaps(File configurationFile) throws IOException { + ConcurrentHashMap confMap = new ConcurrentHashMap<>(); + YamlConfiguration configuration = YamlConfiguration.loadConfiguration(configurationFile); + + for (String map : configuration.getKeys(false)) { + ConfigurationSection section = configuration.getConfigurationSection(map); + if (section != null) { + List spawn = section.getIntegerList("spawn"); + List lobby = section.getIntegerList("lobby"); + int duration = section.getInt("duration"); + List blocks = section.getMapList("blocks").stream().map( + block -> { + try { + return new BlockAndSeekMap.Block( + new ItemStack(Material.valueOf(((String) block.get("name")).toUpperCase())), + (int) block.get("chance") + ); + } catch (IllegalArgumentException | ClassCastException | NullPointerException ignored) { + return null; + } + + } + ).toList(); + + if (!spawn.isEmpty() && !lobby.isEmpty() && duration != 0 && !blocks.isEmpty()) { + confMap.put(map, new BlockAndSeekMap(spawn, lobby, duration, blocks)); + } + } + maps = confMap; + } + + + } + + private static void loadConfig(File configurationFile, YamlConfiguration defaultConfiguration) throws IOException { + ConcurrentHashMap confMap = new ConcurrentHashMap<>(); + YamlConfiguration configuration = YamlConfiguration.loadConfiguration(configurationFile); + + for (String key : defaultConfiguration.getKeys(false)) { + if (configuration.isSet(key)) { + confMap.put(key, configuration.getString(key, defaultConfiguration.getString(key, "NULL"))); + } else { + String value = defaultConfiguration.getString(key, "NULL"); + configuration.set(key, value); + confMap.put(key, value); + } + } + + configuration.save(configurationFile); + + config = confMap; + } + + private static void loadLocalization(File configurationFile, YamlConfiguration defaultConfiguration) throws IOException { + + ConcurrentHashMap confMap = new ConcurrentHashMap<>(); + YamlConfiguration configuration = YamlConfiguration.loadConfiguration(configurationFile); + String language = config.get("language"); + + ConfigurationSection defaultSection = defaultConfiguration.getConfigurationSection("en_US"); + ConfigurationSection configSection = configuration.getConfigurationSection(language); + + if (configSection != null) { + for (String key : defaultSection.getKeys(false)) { + if (configSection.contains(key)) { + confMap.put(key, configSection.getString(key, defaultSection.getString(key, "NULL"))); + } else { + String value = defaultSection.getString(key, "NULL"); + configSection.set(key, value); + confMap.put(key, value); + } + + } + } else { + BlockAndSeek.getPluginLogger().warning(String.format("Language \"%s\" does not exist in localization.yml! Using default language en_US.", language)); + for (String key : defaultSection.getKeys(false)) { + confMap.put(key, defaultSection.getString(key, "NULL")); + } + } + + configuration.save(configurationFile); + + localization = confMap; + + + } + + + public static ConcurrentHashMap getLocalization() { + return localization; } diff --git a/src/main/java/hdvtdev/blockAndSeek/EventListener.java b/src/main/java/hdvtdev/blockAndSeek/EventListener.java new file mode 100644 index 0000000..7d7e77b --- /dev/null +++ b/src/main/java/hdvtdev/blockAndSeek/EventListener.java @@ -0,0 +1,213 @@ +package hdvtdev.blockAndSeek; + + +import me.libraryaddict.disguise.DisguiseAPI; +import me.libraryaddict.disguise.disguisetypes.DisguiseType; +import me.libraryaddict.disguise.disguisetypes.MiscDisguise; +import net.kyori.adventure.text.minimessage.MiniMessage; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.Sound; +import org.bukkit.block.Block; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.entity.EntityDamageByEntityEvent; +import org.bukkit.event.inventory.InventoryClickEvent; +import org.bukkit.event.inventory.InventoryCloseEvent; +import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.event.player.PlayerQuitEvent; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; +import org.bukkit.persistence.PersistentDataContainer; +import org.bukkit.persistence.PersistentDataType; +import org.bukkit.potion.PotionEffect; +import org.bukkit.potion.PotionEffectType; +import org.bukkit.scheduler.BukkitTask; +import org.bukkit.util.Vector; + +import java.util.concurrent.ConcurrentHashMap; + + +public class EventListener implements Listener { + + private static final ConcurrentHashMap tasks = new ConcurrentHashMap<>(); + private static final ConcurrentHashMap soundCoolDown = new ConcurrentHashMap<>(); + private static final ConcurrentHashMap frozenPlayers = new ConcurrentHashMap<>(); + + private static final Vector ZERO_VELOCITY = new Vector(0, 0, 0); + private static final PotionEffect INVISIBILITY = new PotionEffect(PotionEffectType.INVISIBILITY, PotionEffect.INFINITE_DURATION, 2, false, false); + + public static void createTask(Player player, BukkitTask bukkitTask) { + tasks.put(player, bukkitTask); + } + + public static void stopTask(Player player) { + BukkitTask task = tasks.remove(player); + task.cancel(); + } + + @EventHandler + public void onPlayerQuit(PlayerQuitEvent event) { + Player player = event.getPlayer(); + PersistentDataContainer container = player.getPersistentDataContainer(); + if (frozenPlayers.remove(player) != null) { + unfreezePlayer(player); + } + String arena = container.get(BlockAndSeekContainer.PLAYER, PersistentDataType.STRING); + if (arena != null) { + container.remove(BlockAndSeekContainer.PLAYER); + GamesManager.get(arena).removePlayer(player); + } + } + + @EventHandler + public void onDamage(EntityDamageByEntityEvent event) { + + if (event.getEntity() instanceof Player victim) { + PersistentDataContainer container = victim.getPersistentDataContainer(); + if (event.getDamager() instanceof Player && container.has(BlockAndSeekContainer.FROZEN_PLAYER)) { + BlockAndSeekGame game = GamesManager.get(container.get(BlockAndSeekContainer.PLAYER, PersistentDataType.STRING)); + for (Player player : game.getPlayers()) { + player.sendBlockChange(frozenPlayers.get(victim), Material.AIR.createBlockData()); + } + unfreezePlayer(victim); + } + } + } + + + @EventHandler + public void onRightClick(PlayerInteractEvent event) { + Player player = event.getPlayer(); + ItemStack item = player.getInventory().getItemInMainHand(); + ItemMeta itemMeta = item.getItemMeta(); + if (itemMeta != null) { + + PersistentDataContainer data = itemMeta.getPersistentDataContainer(); + PersistentDataContainer playerData = player.getPersistentDataContainer(); + + if (data.has(BlockAndSeekContainer.SOUND_ITEM)) { + Long time = soundCoolDown.get(player); + if (time != null) { + long diff = System.currentTimeMillis() - time; + if (diff > 3000) { + soundCoolDown.remove(player); + } else { + player.sendActionBar(MiniMessage.miniMessage().deserialize("Подождите немного перед следующим использованием")); + return; + } + } + Location location = player.getLocation(); + for (Player p : Bukkit.getOnlinePlayers()) { + p.playSound(location, Sound.ENTITY_CHICKEN_AMBIENT, 2f, 1.5f); + } + soundCoolDown.put(player, System.currentTimeMillis()); + } + + if (data.has(BlockAndSeekContainer.FREEZE_ITEM)) { + + String arena = playerData.get(BlockAndSeekContainer.PLAYER, PersistentDataType.STRING); + if (arena != null) { + BlockAndSeekGame game = GamesManager.get(arena); + if (frozenPlayers.remove(player) != null) { + for (Player p : game.getPlayers()) { + p.sendBlockChange(player.getLocation(), Material.AIR.createBlockData()); + } + unfreezePlayer(player); + } else { + if (game.isStarted()) { + Location playerLocation = player.getLocation(); + Block block = playerLocation.getBlock(); + Block upperBlock = player.getLocation().getBlock(); + if (!upperBlock.isSolid()) { + + Location blockLocation = block.getLocation(); + blockLocation.setX(blockLocation.getX() + 0.5); + double y = Math.round(blockLocation.getY()); + blockLocation.setY(block.isSolid() ? y + 1 : y); + blockLocation.setZ(blockLocation.getZ() + 0.5); + blockLocation.setPitch(playerLocation.getPitch()); + blockLocation.setYaw(playerLocation.getYaw()); + + player.getPersistentDataContainer().set(BlockAndSeekContainer.FROZEN_PLAYER, PersistentDataType.BOOLEAN, true); + + player.setWalkSpeed(0); + player.setFreezeTicks(40); + player.setVelocity(ZERO_VELOCITY); + player.setFlySpeed(0); + player.setAllowFlight(true); + player.setFlying(true); + player.setGravity(false); + player.addPotionEffect(INVISIBILITY); + BlockAndSeekContainer.NO_COLLIDE_TEAM.addEntry(player.getName()); + + for (Player p : Bukkit.getOnlinePlayers()) { + p.sendBlockChange(blockLocation, Material.CHORUS_PLANT.createBlockData()); + } + + player.teleport(blockLocation); + frozenPlayers.put(player, blockLocation); + } else + player.sendActionBar(MiniMessage.miniMessage().deserialize(" Could not freeze here!")); + + } else + player.sendActionBar(MiniMessage.miniMessage().deserialize(" Could not freeze now!")); + + } + } else player.sendActionBar(MiniMessage.miniMessage().deserialize(" Could not freeze now!")); + } + + + } + } + + public static void unfreezePlayer(Player player) { + player.getPersistentDataContainer().remove(BlockAndSeekContainer.FROZEN_PLAYER); + player.setFlySpeed(0.2f); + player.setWalkSpeed(0.2f); + player.setAllowFlight(false); + player.setFlying(false); + BlockAndSeekContainer.NO_COLLIDE_TEAM.removeEntry(player.getName()); + player.setGravity(true); + player.setFreezeTicks(0); + player.removePotionEffect(PotionEffectType.INVISIBILITY); + } + + @EventHandler + public void onClick(InventoryClickEvent event) { + Player player = (Player) event.getWhoClicked(); + + if (player.hasMetadata("RollingMenu")) { + event.setCancelled(true); + int slot = event.getSlot(); + if (slot == 21 || slot == 23 || slot == 25) { + if (!tasks.containsKey(player)) { + MiscDisguise miscDisguise = new MiscDisguise(DisguiseType.FALLING_BLOCK, event.getInventory().getItem(slot)); + DisguiseAPI.disguiseToAll(player, miscDisguise); + player.closeInventory(InventoryCloseEvent.Reason.UNKNOWN); + } + } + } + } + + @EventHandler + public void onClose(InventoryCloseEvent event) { + + Player player = (Player) event.getPlayer(); + if (player.hasMetadata("RollingMenu")) { + if (!tasks.containsKey(player)) { + player.removeMetadata("RollingMenu", BlockAndSeek.getInstance()); + if (!event.getReason().equals(InventoryCloseEvent.Reason.UNKNOWN)) { + MiscDisguise miscDisguise = new MiscDisguise(DisguiseType.FALLING_BLOCK, event.getInventory().getItem(21)); + DisguiseAPI.disguiseToAll(player, miscDisguise); + } + } else { + Bukkit.getScheduler().runTaskLater(BlockAndSeek.getInstance(), () -> player.openInventory(event.getInventory()), 0L); + } + + } + } + +} diff --git a/src/main/java/hdvtdev/blockAndSeek/GamesManager.java b/src/main/java/hdvtdev/blockAndSeek/GamesManager.java index 50a7e58..3e0b13d 100644 --- a/src/main/java/hdvtdev/blockAndSeek/GamesManager.java +++ b/src/main/java/hdvtdev/blockAndSeek/GamesManager.java @@ -1,25 +1,106 @@ package hdvtdev.blockAndSeek; -import java.util.ArrayList; -import java.util.List; +import hdvtdev.blockAndSeek.roulette.RouletteCreator; +import net.kyori.adventure.text.Component; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.bukkit.scheduler.BukkitRunnable; + +import java.util.Set; import java.util.concurrent.ConcurrentHashMap; public class GamesManager { private static final ConcurrentHashMap games = new ConcurrentHashMap<>(); - public static void createGame(String name, ArrayList players) { - games.put(name, new BlockAndSeekGame(name, players)); + public static boolean isExist(String name) { + return games.containsKey(name); } - public static boolean joinGame(String name) { - return false; + public static Set getAvailableGames() { + return games.keySet(); } - public static void endGame(String name) { - games.remove(name); + public static int createGame(String name) { + if (games.containsKey(name)) return 1; + if (Bukkit.getWorld(name) == null) return 2; + BlockAndSeekGame game = new BlockAndSeekGame(name); + games.put(name, game); + + new BukkitRunnable() { + + int duration = 30; + int waitTime = 10; + + + @Override + public void run() { + + if (!game.isStarted()) { + int playerCount = game.playerCount(); + + for (Player player : game.getPlayers()) { + player.sendActionBar(Component.text("Игроков " + playerCount + "/12")); + } + + if (playerCount > 1) { + + if (waitTime == 0) { + game.start(); + for (Player player : game.getPlayers()) { + RouletteCreator.createRoulette(player, null, true); + } + } else { + for (Player player : game.getPlayers()) { + player.sendMessage(Component.text("Осталось: " + waitTime)); + } + waitTime--; + } + + } else waitTime = 10; + + } else { + + if (game.hidersCound() == 0) { + + for (Player player : game.getPlayers()) { + player.sendActionBar(Component.text("Сикеры победили!")); + //TODO + } + + game.end(); + games.remove(name); + this.cancel(); + } + + for (Player player : game.getPlayers()) { + player.sendActionBar(Component.text("Осталось: " + duration)); + } + + if (duration == 0) { + for (Player player : game.getPlayers()) { + player.sendActionBar(Component.text("Хайдеры победили!")); + } + game.end(); + games.remove(name); + this.cancel(); + } else duration--; + + + } + + + } + + + }.runTaskTimer(BlockAndSeek.getInstance(), 0L, 20L); + + + return 0; } - + public static BlockAndSeekGame get(String name) { + return games.get(name); + } } diff --git a/src/main/java/hdvtdev/blockAndSeek/Localization.java b/src/main/java/hdvtdev/blockAndSeek/Localization.java index fb496b2..5ea65f6 100644 --- a/src/main/java/hdvtdev/blockAndSeek/Localization.java +++ b/src/main/java/hdvtdev/blockAndSeek/Localization.java @@ -2,66 +2,35 @@ package hdvtdev.blockAndSeek; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.minimessage.MiniMessage; -import org.bukkit.ChatColor; -import org.bukkit.configuration.file.YamlConfiguration; -import org.bukkit.plugin.java.JavaPlugin; -import org.jetbrains.annotations.Nullable; - -import java.io.*; import java.util.Map; -import java.util.Objects; -import java.util.concurrent.ConcurrentHashMap; public class Localization { - private static final Map localization = new ConcurrentHashMap<>(); - private static JavaPlugin javaPlugin; + private static volatile Map localization = ConfigManager.getLocalization(); + private static final MiniMessage miniMessage = MiniMessage.miniMessage(); + private static final Component prefix = miniMessage.deserialize("[BlockAndSeek] "); - public static void reload() { - File localizationFile = new File(javaPlugin.getDataFolder(), "messages.yml"); - if (!localizationFile.exists()) javaPlugin.saveResource("messages.yml", false); - - YamlConfiguration locale = YamlConfiguration.loadConfiguration(localizationFile); - YamlConfiguration defaultLocale = YamlConfiguration.loadConfiguration( - new InputStreamReader(Objects.requireNonNull(javaPlugin.getResource("messages.yml")))); - - String prefix = locale.getString("prefix"); - prefix = prefix == null ? defaultLocale.getString("prefix") : prefix; - - for (String defaultElement : defaultLocale.getKeys(false)) { - String element = locale.getString(defaultElement); - localization.put(defaultElement, String.format("%s%s", prefix, element == null ? defaultLocale.getString(defaultElement) : element)); - } + public static Component getPrefix() { + return prefix; } - public static void load(JavaPlugin plugin) { - javaPlugin = plugin; - File localizationFile = new File(plugin.getDataFolder(), "messages.yml"); - if (!localizationFile.exists()) plugin.saveResource("messages.yml", false); - - YamlConfiguration locale = YamlConfiguration.loadConfiguration(localizationFile); - YamlConfiguration defaultLocale = YamlConfiguration.loadConfiguration( - new InputStreamReader(Objects.requireNonNull(plugin.getResource("messages.yml")))); - - String prefix = locale.getString("prefix"); - prefix = prefix == null ? defaultLocale.getString("prefix") : prefix; - - for (String defaultElement : defaultLocale.getKeys(false)) { - String element = locale.getString(defaultElement); - localization.put(defaultElement, String.format("%s%s", prefix, element == null ? defaultLocale.getString(defaultElement) : element)); - } - + public static void update() { + localization = ConfigManager.getLocalization(); } - - public static Component get(String key, String... replacements) { + public static String get(String key, String... replacements) { String s = localization.get(key); - for (int i = 0; i < replacements.length; i+=2) { - s = s.replace(replacements[i], replacements[i + 1]); - } + if (s != null) { + for (int i = 0; i < replacements.length; i += 2) { + s = s.replace(replacements[i], replacements[i + 1]); + } + } else return "Unknown localization: " + key; + return s; + } - return MiniMessage.miniMessage().deserialize(s); + public static Component getComponent(String key, String... replacements) { + return miniMessage.deserialize(get(key, replacements)); } diff --git a/src/main/java/hdvtdev/blockAndSeek/roulette/RouletteCreator.java b/src/main/java/hdvtdev/blockAndSeek/roulette/RouletteCreator.java new file mode 100644 index 0000000..347f836 --- /dev/null +++ b/src/main/java/hdvtdev/blockAndSeek/roulette/RouletteCreator.java @@ -0,0 +1,154 @@ +package hdvtdev.blockAndSeek.roulette; + +import hdvtdev.blockAndSeek.BlockAndSeek; +import hdvtdev.blockAndSeek.EventListener; +import me.libraryaddict.disguise.DisguiseAPI; +import me.libraryaddict.disguise.disguisetypes.DisguiseType; +import me.libraryaddict.disguise.disguisetypes.MiscDisguise; +import net.kyori.adventure.text.Component; +import org.bukkit.Bukkit; +import org.bukkit.Material; +import org.bukkit.Sound; +import org.bukkit.entity.Player; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.InventoryHolder; +import org.bukkit.inventory.ItemFlag; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; +import org.bukkit.metadata.FixedMetadataValue; +import org.bukkit.scheduler.BukkitRunnable; +import org.jetbrains.annotations.NotNull; + +import java.util.List; + +public class RouletteCreator implements InventoryHolder { + + private static final int[] filledSlots = { + + }; + + public static void createRoulette(Player player, Inventory inventory, boolean openInventory) { + + Inventory gui = inventory == null ? new RouletteCreator().getInventory() : inventory; + + + EventListener.createTask(player, new BukkitRunnable() { + + int i = 0; + final RouletteGenerator rouletteGenerator = new RouletteGenerator(List.of( + new RouletteGenerator.Block(new ItemStack(Material.FLOWER_POT), 55), + new RouletteGenerator.Block(new ItemStack(Material.GOLD_BLOCK), 25), + new RouletteGenerator.Block(new ItemStack(Material.EMERALD_BLOCK), 10), + new RouletteGenerator.Block(new ItemStack(Material.DIAMOND_BLOCK), 6), + new RouletteGenerator.Block(new ItemStack(Material.NETHERITE_BLOCK), 4) + )); + + final List> rows = List.of( + new RouletteList<>(rouletteGenerator.getRandomRow(15)), + new RouletteList<>(rouletteGenerator.getRandomRow(15)), + new RouletteList<>(rouletteGenerator.getRandomRow(15)) + ); + + final List items = List.of( + new ItemStack[]{ + rows.getFirst().next(), + rows.getFirst().next(), + rows.getFirst().next(), + rows.getFirst().next(), + rows.getFirst().next() + }, + new ItemStack[]{ + rows.get(1).next(), + rows.get(1).next(), + rows.get(1).next(), + rows.get(1).next(), + rows.get(1).next() + + }, + new ItemStack[]{ + rows.get(2).next(), + rows.get(2).next(), + rows.get(2).next(), + rows.get(2).next(), + rows.get(2).next() + } + ); + + @Override + public void run() { + + for (int j = 0; j < 5; j++) { + gui.setItem(3 + j * 9, items.getFirst()[j]); + gui.setItem(5 + j * 9, items.get(1)[j]); + gui.setItem(7 + j * 9, items.get(2)[j]); + } + + player.playSound(player.getLocation(), Sound.UI_BUTTON_CLICK, 0.5f, 2f); + + + if (i == 30) { + player.playSound(player.getLocation(), Sound.ENTITY_PLAYER_LEVELUP, 0.5f, 0.5f); + EventListener.stopTask(player); + } + + for (int j = 4; j >= 1; j--) { + items.getFirst()[j] = items.getFirst()[j - 1]; + items.get(1)[j] = items.get(1)[j - 1]; + items.get(2)[j] = items.get(2)[j - 1]; + } + + + items.getFirst()[0] = rows.getFirst().next(); + items.get(1)[0] = rows.get(1).next(); + items.get(2)[0] = rows.get(2).next(); + + i++; + } + + + }.runTaskTimer(BlockAndSeek.getInstance(), 0, 3L)); + + new BukkitRunnable() { + + @Override + public void run() { + + Inventory inventory = player.getOpenInventory().getTopInventory(); + + if (inventory.getHolder() instanceof RouletteCreator) { + inventory.close(); + MiscDisguise miscDisguise = new MiscDisguise(DisguiseType.FALLING_BLOCK, inventory.getItem(21)); + DisguiseAPI.disguiseToAll(player, miscDisguise); + } + + } + + + }.runTaskLater(BlockAndSeek.getInstance(), 300L); + + if (openInventory) { + player.openInventory(gui); + player.setMetadata("RollingMenu", new FixedMetadataValue(BlockAndSeek.getInstance(), "RollingMenu")); + } + + + } + + + @Override + public @NotNull Inventory getInventory() { + + Inventory gui = Bukkit.createInventory(this, 45, Component.text("РулетОЧКА")); + + ItemStack filler = new ItemStack(Material.BLUE_STAINED_GLASS_PANE); + ItemMeta fillerMeta = filler.getItemMeta(); + fillerMeta.displayName(Component.text("")); + fillerMeta.lore(null); + fillerMeta.addItemFlags(ItemFlag.HIDE_ATTRIBUTES); + filler.setItemMeta(fillerMeta); + for (int i = 0; i < 45; i++) { + gui.setItem(i, filler); + } + return gui; + } +} diff --git a/src/main/java/hdvtdev/blockAndSeek/roulette/RouletteGenerator.java b/src/main/java/hdvtdev/blockAndSeek/roulette/RouletteGenerator.java new file mode 100644 index 0000000..d73c724 --- /dev/null +++ b/src/main/java/hdvtdev/blockAndSeek/roulette/RouletteGenerator.java @@ -0,0 +1,30 @@ +package hdvtdev.blockAndSeek.roulette; + +import com.lewdev.probabilitylib.ProbabilityCollection; +import org.bukkit.inventory.ItemStack; + +import java.util.ArrayList; +import java.util.List; + +public class RouletteGenerator { + + + private final ProbabilityCollection probabilityCollection = new ProbabilityCollection<>(); + + public RouletteGenerator(List blocks) { + for (Block block : blocks) { + probabilityCollection.add(block.itemStack, block.chance); + } + } + + public List getRandomRow(int count) { + List items = new ArrayList<>(count); + for (; count > 0; --count) items.add(probabilityCollection.get()); + return items; + } + + public record Block(ItemStack itemStack, int chance) { + } + + +} diff --git a/src/main/java/hdvtdev/blockAndSeek/roulette/RouletteList.java b/src/main/java/hdvtdev/blockAndSeek/roulette/RouletteList.java new file mode 100644 index 0000000..d1e3524 --- /dev/null +++ b/src/main/java/hdvtdev/blockAndSeek/roulette/RouletteList.java @@ -0,0 +1,23 @@ +package hdvtdev.blockAndSeek.roulette; + +import java.util.List; +import java.util.Objects; + +public class RouletteList { + private final List items; + private int currentIndex; + + public RouletteList(List items) { + this.items = Objects.requireNonNull(items); + this.currentIndex = 0; + if (items.isEmpty()) { + throw new IllegalArgumentException("List must not be empty"); + } + } + + public T next() { + T item = items.get(currentIndex); + currentIndex = (currentIndex + 1) % items.size(); + return item; + } +} diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 4287ca8..8e3b571 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -1 +1,3 @@ -# \ No newline at end of file +# Selected language in localization.yml (en_US is used by default) +language: en_US + diff --git a/src/main/resources/localization.yml b/src/main/resources/localization.yml new file mode 100644 index 0000000..73dba61 --- /dev/null +++ b/src/main/resources/localization.yml @@ -0,0 +1,10 @@ +en_US: + #Maps + maps-available: "Available maps: " + maps-available-element: "- {color-status}{map}" + + not-enough-permissions: "You do not have permission to run this command." + not-enough-arguments: "Too few arguments to run command {command}. Arguments example: {help}" + + successful-reload: "Successfully reloaded {config}." + failed-reload: "Failed to reload {config}. Error: {e}" \ No newline at end of file diff --git a/src/main/resources/maps.yml b/src/main/resources/maps.yml index e69de29..10855ad 100644 --- a/src/main/resources/maps.yml +++ b/src/main/resources/maps.yml @@ -0,0 +1 @@ +# DO NOT edit this file manually! Use plugin commands to edit maps instead. \ No newline at end of file diff --git a/src/main/resources/messages.yml b/src/main/resources/messages.yml deleted file mode 100644 index 8bab099..0000000 --- a/src/main/resources/messages.yml +++ /dev/null @@ -1,15 +0,0 @@ -prefix: "[BlockAndSeek] " -bs-usage: "Usage: /blockandseek [SUBCOMMAND]" - -messages-reload: "Successfully reload messages.yml" -not-enough-arguments: "Too few args. Usage: {usage}." -unknown-subcommand: "Unknown subcommand {subcommand}." - -#Map -maps-list: "Available maps: {maps}" -maps-reload: "Successfully reload maps.yml" -map-created: "Successfully created map {map}." -map-missing-world: "Could not find world {world} in server folder. An existing world is required to create a map" -map-creation-failed: "Failed to create map {map}. Error: {error}." -map-already-exist: "Map {map} already exist!" -map-not-exist: "Map {map} does not exist!" \ No newline at end of file diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index c6029b2..6e9a625 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -2,6 +2,12 @@ name: BlockAndSeek version: '0.0.1-a' main: hdvtdev.blockAndSeek.BlockAndSeek api-version: '1.20' + +permissions: + blockandseek.manage: + description: "Permission to use this subcommands: reload, map" + default: op + commands: blockandseek: aliases: