idk some "cool" stuff

This commit is contained in:
hdvt
2025-06-28 00:36:06 +03:00
parent 54eb07cc86
commit e63ac83c17
17 changed files with 499 additions and 312 deletions

3
.gitignore vendored Normal file
View File

@@ -0,0 +1,3 @@
/.gradle/
/gradle/
/bin/

1
.idea/modules.xml generated
View File

@@ -2,6 +2,7 @@
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/modules/BlockAndSeek.iml" filepath="$PROJECT_DIR$/.idea/modules/BlockAndSeek.iml" />
<module fileurl="file://$PROJECT_DIR$/.idea/modules/BlockAndSeek.main.iml" filepath="$PROJECT_DIR$/.idea/modules/BlockAndSeek.main.iml" />
</modules>
</component>

View File

@@ -1,5 +1,6 @@
package hdvtdev.blockAndSeek;
import hdvtdev.blockAndSeek.managers.ConfigManager;
import me.libraryaddict.disguise.LibsDisguises;
import org.bukkit.Bukkit;
import org.bukkit.command.CommandExecutor;
@@ -24,6 +25,10 @@ public class BlockAndSeek extends JavaPlugin implements CommandExecutor {
return javaPlugin.getDataFolder();
}
public static File getServerDataFolder() {
return javaPlugin.getServer().getPluginsFolder().getParentFile();
}
public static InputStream getPluginResource(String resource) {
return javaPlugin.getResource(resource);
}

View File

@@ -1,12 +1,15 @@
package hdvtdev.blockAndSeek;
import me.libraryaddict.disguise.DisguiseAPI;
import org.bukkit.GameMode;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.persistence.PersistentDataType;
import java.security.SecureRandom;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -15,24 +18,32 @@ public class BlockAndSeekGame {
private final ConcurrentHashMap<Player, PlayerType> players = new ConcurrentHashMap<>();
private AtomicBoolean started = new AtomicBoolean(false);
private final AtomicBoolean started = new AtomicBoolean(false);
private final String name;
private final int maxPlayers;
public BlockAndSeekGame(String name) {
public BlockAndSeekGame(String name, int maxPlayers) {
this.name = name;
this.maxPlayers = maxPlayers;
}
public List<Player> getHiders() {
return players.entrySet().stream().filter(e -> Objects.equals(e.getValue(), PlayerType.HIDER)).map(Map.Entry::getKey).toList();
}
public void end() {
for (Player player : players.keySet()) {
EventListener.unfreezePlayer(player);
//EventListener.unfreezePlayer(player); TODO
player.getPersistentDataContainer().remove(BlockAndSeekContainer.PLAYER);
player.sendBlockChange(player.getLocation(), Material.AIR.createBlockData());
player.setGameMode(GameMode.SURVIVAL);
DisguiseAPI.undisguiseToAll(player);
}
}
public boolean addPlayer(Player player) {
if (started.get()) {
if (started.get() || playerCount() + 1 > maxPlayers) {
return false;
}
player.getPersistentDataContainer().set(BlockAndSeekContainer.PLAYER, PersistentDataType.STRING, name);
@@ -44,6 +55,11 @@ public class BlockAndSeekGame {
players.remove(player);
}
public void setSpectator(Player player) {
players.put(player, PlayerType.SPECTATOR);
player.setGameMode(GameMode.SPECTATOR);
}
public Set<Player> getPlayers() {
return players.keySet();
}
@@ -59,7 +75,7 @@ public class BlockAndSeekGame {
return (int) players.values().stream().filter(f -> f.equals(PlayerType.SEEKER)).count();
}
public int hidersCound() {
public int hidersCount() {
return (int) players.values().stream().filter(f -> f.equals(PlayerType.HIDER)).count();
}
@@ -80,14 +96,19 @@ public class BlockAndSeekGame {
int i = 0;
int randomNum = random.nextInt(0, players.size());
for (Player player : players.keySet()) {
if (i == randomNum) return player;
if (i == randomNum) {
players.put(player, PlayerType.SEEKER);
return player;
}
i++;
}
return null;
}
private enum PlayerType {
SEEKER,
HIDER
HIDER,
SPECTATOR
}

View File

@@ -1,13 +1,17 @@
package hdvtdev.blockAndSeek;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import java.util.List;
public record BlockAndSeekMap(List<Integer> spawn, List<Integer> lobby, int duration, List<Block> blocks) {
public record BlockAndSeekMap(List<Integer> spawn, List<Integer> lobby, int duration, int minPlayers, int maxPlayers,
List<Block> blocks) {
public record Block(@NotNull ItemStack block, int chance) {
public record Block(ItemStack block, int chance) {
}
}

View File

@@ -1,7 +1,10 @@
package hdvtdev.blockAndSeek;
import hdvtdev.blockAndSeek.roulette.RouletteCreator;
import hdvtdev.blockAndSeek.managers.ConfigManager;
import hdvtdev.blockAndSeek.managers.FreezeManager;
import hdvtdev.blockAndSeek.managers.GamesManager;
import net.kyori.adventure.text.minimessage.MiniMessage;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
@@ -36,8 +39,20 @@ public class CommandListener implements CommandExecutor, TabCompleter {
switch (args[0]) {
case "test" -> {
switch (GamesManager.createGame("dust2")) {
case 1 -> {
sender.sendMessage("Game already exist");
GamesManager.get("dust2").addPlayer((Player) sender);
}
case 2 -> sender.sendMessage("Could not find world");
default -> GamesManager.get("dust2").addPlayer((Player) sender);
}
}
case "locale" -> {
if (sender instanceof Player player) {
RouletteCreator.createRoulette(player, null, true);
player.sendMessage(player.locale().toLanguageTag());
player.sendMessage("eq: " + player.locale().toLanguageTag().equals("en-US"));
}
}
case "freeze" -> {
@@ -50,6 +65,12 @@ public class CommandListener implements CommandExecutor, TabCompleter {
player.getInventory().addItem(foo);
}
}
case "f" -> {
if (sender instanceof Player player) {
FreezeManager.freeze(player, Material.TARGET);
}
}
case "foo" -> {
if (sender instanceof Player player) {
ItemStack foo = new ItemStack(Material.BROWN_DYE);
@@ -86,10 +107,11 @@ public class CommandListener implements CommandExecutor, TabCompleter {
switch (args[1]) {
case "localization" -> {
try {
ConfigManager.load("localization.yml");
sender.sendMessage(Localization.getPrefix().append(Localization.getComponent("successful-reload", "{config}", "localization.yml")));
sender.sendMessage(Localization.getComponentWithPrefix("successful-reload", "{config}", "localization.yml"));
} catch (IOException e) {
sender.sendMessage(Localization.getComponent("failed-reload", "{config}", "localization.yml", "{e}", e.getMessage()));
sender.sendMessage(Localization.getComponentWithPrefix("failed-reload", "{config}", "localization.yml", "{e}", e.getMessage()));
}
}
@@ -120,29 +142,28 @@ public class CommandListener implements CommandExecutor, TabCompleter {
@Override
public @Nullable List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
sender.sendActionBar(MiniMessage.miniMessage().deserialize("<b><blue>" + args.length));
boolean hasPermission = sender.hasPermission("blockandseek.manage");
return switch (args.length) {
case 1 -> {
if (sender.hasPermission("blockandseek.manage")) {
yield List.of("reload", "help", "map", "join");
} else yield List.of("help", "join");
if (hasPermission) {
yield List.of("reload", "help", "map");
} else yield List.of("help");
}
case 2 -> switch (args[0]) {
case "map" -> {
List<String> scmds = new ArrayList<>();
/*
if (sender.hasPermission("blockandseek.manage")) {
if (hasPermission) {
scmds.addAll(List.of("create", "list"));
scmds.addAll(ConfigManager.createdMaps());
scmds.addAll(ConfigManager.getAllMaps());
}
*/
yield scmds;
}
case "join" -> List.of("test"); //TODO
case "reload" -> {
if (sender.hasPermission("blockandseek.manage")) {
yield List.of("messages", "maps");
if (hasPermission) {
yield List.of("localization", "config");
} else yield List.of();
}
default -> List.of();
@@ -150,15 +171,24 @@ public class CommandListener implements CommandExecutor, TabCompleter {
case 3 -> switch (args[1]) {
case "create", "list" -> List.of();
default -> {
/*
if (ConfigManager.createdMaps().contains(args[1]) && sender.hasPermission("blockandseek.manage")) {
yield List.of("setspawn", "setlobby", "setduration");
if (ConfigManager.getAllMaps().contains(args[1]) && hasPermission) {
yield List.of("setspawn", "setlobby", "setduration", "setmaxplayers", "setminplayers", "status", "remove");
} else yield List.of();
*/
yield List.of();
}
};
case 4 -> switch (args[2]) {
case "setspawn", "setlobby" -> {
if (hasPermission && sender instanceof Player player) {
Location location = player.getLocation();
yield List.of(String.format("%.1f %.0f %.1f", location.getX(), location.getY(), location.getZ()));
} else yield List.of();
}
default -> List.of();
};
default -> List.of();
};
}

View File

@@ -1,25 +1,26 @@
package hdvtdev.blockAndSeek;
import hdvtdev.blockAndSeek.managers.FreezeManager;
import hdvtdev.blockAndSeek.managers.GamesManager;
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.ArmorStand;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.block.Action;
import org.bukkit.event.entity.EntityDamageByEntityEvent;
import org.bukkit.event.entity.PlayerDeathEvent;
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.EquipmentSlot;
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;
@@ -34,7 +35,7 @@ public class EventListener implements Listener {
private static final ConcurrentHashMap<Player, BukkitTask> tasks = new ConcurrentHashMap<>();
private static final ConcurrentHashMap<Player, Long> soundCoolDown = new ConcurrentHashMap<>();
private static final ConcurrentHashMap<Player, Location> frozenPlayers = new ConcurrentHashMap<>();
private static final ConcurrentHashMap<Player, ArmorStand> 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);
@@ -52,9 +53,7 @@ public class EventListener implements Listener {
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);
@@ -62,118 +61,31 @@ public class EventListener implements Listener {
}
}
@EventHandler
public void onPlayerDeath(PlayerDeathEvent event) {
}
@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("<gradient:#ff0000:#ff6666><bold>Подождите немного перед следующим использованием"));
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 (event.getHand() != EquipmentSlot.HAND) return;
Action action = event.getAction();
if (action == Action.RIGHT_CLICK_BLOCK || action == Action.RIGHT_CLICK_AIR) {
Player player = event.getPlayer();
if (player.getInventory().getItemInMainHand().equals(new ItemStack(Material.HEART_OF_THE_SEA))) {
FreezeManager.freeze(player, Material.TARGET);
}
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("<red> Could not freeze here!"));
} else
player.sendActionBar(MiniMessage.miniMessage().deserialize("<red> Could not freeze now!"));
}
} else player.sendActionBar(MiniMessage.miniMessage().deserialize("<red> Could not freeze now!"));
}
}
} else event.getPlayer().sendMessage(action.toString());
}
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) {

View File

@@ -1,106 +0,0 @@
package hdvtdev.blockAndSeek;
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<String, BlockAndSeekGame> games = new ConcurrentHashMap<>();
public static boolean isExist(String name) {
return games.containsKey(name);
}
public static Set<String> getAvailableGames() {
return games.keySet();
}
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);
}
}

View File

@@ -1,26 +1,33 @@
package hdvtdev.blockAndSeek;
import hdvtdev.blockAndSeek.managers.ConfigManager;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.minimessage.MiniMessage;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collections;
import java.util.Map;
public class Localization {
private static volatile Map<String, String> localization = ConfigManager.getLocalization();
private static volatile Map<String, Map<String, String>> localization = Collections.unmodifiableMap(ConfigManager.getLocalization());
private static final MiniMessage miniMessage = MiniMessage.miniMessage();
private static final Component prefix = miniMessage.deserialize("<gold>[<bold><blue>BlockAndSeek<reset><gold>] ");
public static Component getPrefix() {
return prefix;
}
public static void update() {
localization = ConfigManager.getLocalization();
localization = Collections.unmodifiableMap(ConfigManager.getLocalization());
}
public static String get(String key, String... replacements) {
String s = localization.get(key);
public static String get(@NotNull String key, String... replacements) {
return getLang(null, key, replacements);
}
public static String getLang(@Nullable String lang, @NotNull String key, String... replacements) {
lang = lang == null || !localization.containsKey(lang) ? "en-US" : lang;
String s = localization.get(lang).get(key);
if (s != null) {
for (int i = 0; i < replacements.length; i += 2) {
s = s.replace(replacements[i], replacements[i + 1]);
@@ -30,8 +37,19 @@ public class Localization {
}
public static Component getComponent(String key, String... replacements) {
return miniMessage.deserialize(get(key, replacements));
return getLangComponent(null, key, replacements);
}
public static Component getLangComponent(String lang, String key, String... replacements) {
return miniMessage.deserialize(getLang(lang, key, replacements));
}
public static Component getLangComponentWithPrefix(String lang, String key, String... replacements) {
return prefix.append(getLangComponent(lang, key, replacements));
}
public static Component getComponentWithPrefix(String key, String... replacements) {
return prefix.append(getLangComponent(null, key, replacements));
}
}

View File

@@ -1,5 +1,8 @@
package hdvtdev.blockAndSeek;
package hdvtdev.blockAndSeek.managers;
import hdvtdev.blockAndSeek.BlockAndSeek;
import hdvtdev.blockAndSeek.BlockAndSeekMap;
import hdvtdev.blockAndSeek.Localization;
import org.bukkit.Material;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.file.YamlConfiguration;
@@ -9,20 +12,21 @@ 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.*;
import java.util.concurrent.ConcurrentHashMap;
public class ConfigManager {
private static volatile ConcurrentHashMap<String, String> localization = new ConcurrentHashMap<>();
private static volatile ConcurrentHashMap<String, String> config = new ConcurrentHashMap<>();
private static volatile ConcurrentHashMap<String, BlockAndSeekMap> maps = new ConcurrentHashMap<>();
private static volatile Map<String, Map<String, String>> localization;
private static volatile Map<String, String> config;
private static Map<String, BlockAndSeekMap> maps = new ConcurrentHashMap<>();
private static final File mapsFile = new File(BlockAndSeek.getPluginDataFolder(), "maps.yml");
public static BlockAndSeekMap getMap(String name) {
return maps.get(name);
}
public static Set<String> getAllMaps() {
return YamlConfiguration.loadConfiguration(mapsFile).getKeys(false);
}
@@ -31,7 +35,9 @@ public class ConfigManager {
SPAWN_REQUIRED,
LOBBY_REQUIRED,
DURATION_REQUIRED,
BLOCKS_REQUIRED
BLOCKS_REQUIRED,
MIN_PLAYERS_REQUIRED,
MAX_PLAYERS_REQUIRED
}
public static Set<String> getReadyMaps() {
@@ -52,6 +58,10 @@ public class ConfigManager {
if (lobby.size() != 3) status.add(MapStatus.LOBBY_REQUIRED);
int duration = section.getInt("duration");
if (duration <= 0) status.add(MapStatus.DURATION_REQUIRED);
int minPlayers = section.getInt("min-players");
if (minPlayers <= 0) status.add(MapStatus.MIN_PLAYERS_REQUIRED);
int maxPlayers = section.getInt("max-players");
if (maxPlayers <= 0) status.add(MapStatus.MAX_PLAYERS_REQUIRED);
List<BlockAndSeekMap.Block> blocks = section.getMapList("blocks").stream().map(
block -> {
try {
@@ -67,7 +77,8 @@ public class ConfigManager {
).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));
if (status.isEmpty())
maps.put(name, new BlockAndSeekMap(spawn, lobby, duration, minPlayers, maxPlayers, blocks));
} else return null;
@@ -84,6 +95,8 @@ public class ConfigManager {
section.set("spawn", List.of());
section.set("lobby", List.of());
section.set("duration", 0);
section.set("min-players", 0);
section.set("max-players", 0);
section.set("blocks", List.of(Map.of()));
try {
@@ -127,19 +140,22 @@ public class ConfigManager {
if (!conf.exists()) {
BlockAndSeek.saveResource(file);
ConcurrentHashMap<String, String> confMap = new ConcurrentHashMap<>();
switch (file) {
case "config.yml" -> {
Map<String, String> confMap = new HashMap<>();
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"));
Map<String, Map<String, String>> confMap = new HashMap<>();
Map<String, String> lang = new HashMap<>();
for (String key : defaultConfiguration.getConfigurationSection("en-US").getKeys(false)) {
lang.put(key, defaultConfiguration.getString(key, "NULL"));
}
confMap.put("en-US", lang);
localization = confMap;
Localization.update();
}
@@ -158,7 +174,7 @@ public class ConfigManager {
}
private static void loadMaps(File configurationFile) throws IOException {
ConcurrentHashMap<String, BlockAndSeekMap> confMap = new ConcurrentHashMap<>();
Map<String, BlockAndSeekMap> confMap = new ConcurrentHashMap<>();
YamlConfiguration configuration = YamlConfiguration.loadConfiguration(configurationFile);
for (String map : configuration.getKeys(false)) {
@@ -167,24 +183,28 @@ public class ConfigManager {
List<Integer> spawn = section.getIntegerList("spawn");
List<Integer> lobby = section.getIntegerList("lobby");
int duration = section.getInt("duration");
int minPlayers = section.getInt("min-players");
int maxPlayers = section.getInt("max-players");
List<BlockAndSeekMap.Block> blocks = section.getMapList("blocks").stream().map(
block -> {
try {
return new BlockAndSeekMap.Block(
new ItemStack(Material.valueOf(((String) block.get("name")).toUpperCase())),
new ItemStack(Material.valueOf(((String) block.get("block")).toUpperCase())),
(int) block.get("chance")
);
} catch (IllegalArgumentException | ClassCastException | NullPointerException ignored) {
return null;
}
}
).toList();
).filter(Objects::nonNull).toList();
if (!spawn.isEmpty() && !lobby.isEmpty() && duration != 0 && !blocks.isEmpty()) {
confMap.put(map, new BlockAndSeekMap(spawn, lobby, duration, blocks));
if (!spawn.isEmpty() && !lobby.isEmpty() && duration > 0 && !blocks.isEmpty() && minPlayers > 0 && maxPlayers > 0) {
confMap.put(map, new BlockAndSeekMap(spawn, lobby, duration, minPlayers, maxPlayers, blocks));
}
}
maps = confMap;
}
@@ -212,40 +232,44 @@ public class ConfigManager {
private static void loadLocalization(File configurationFile, YamlConfiguration defaultConfiguration) throws IOException {
ConcurrentHashMap<String, String> confMap = new ConcurrentHashMap<>();
Map<String, Map<String, String>> confMap = new HashMap<>();
YamlConfiguration configuration = YamlConfiguration.loadConfiguration(configurationFile);
String language = config.get("language");
ConfigurationSection defaultSection = defaultConfiguration.getConfigurationSection("en_US");
ConfigurationSection configSection = configuration.getConfigurationSection(language);
ConfigurationSection defaultSection = defaultConfiguration.getConfigurationSection("en-US");
for (String langKey : configuration.getKeys(false)) {
ConfigurationSection configSection = configuration.getConfigurationSection(langKey);
Map<String, String> langMap = new HashMap<>();
if (configSection != null) {
for (String key : defaultSection.getKeys(false)) {
if (configSection.contains(key)) {
langMap.put(key, configSection.getString(key, defaultSection.getString(key, "NULL")));
} else {
String value = defaultSection.getString(key, "NULL");
configSection.set(key, value);
langMap.put(key, value);
}
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("No any language found in the configuration! Using default en-US.");
for (String key : defaultSection.getKeys(false)) {
langMap.put(key, defaultSection.getString(key, "NULL"));
}
}
}
} 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"));
}
confMap.put(langKey, langMap);
}
configuration.save(configurationFile);
localization = confMap;
}
public static ConcurrentHashMap<String, String> getLocalization() {
public static Map<String, Map<String, String>> getLocalization() {
return localization;
}

View File

@@ -0,0 +1,92 @@
package hdvtdev.blockAndSeek.managers;
import hdvtdev.blockAndSeek.BlockAndSeekContainer;
import me.libraryaddict.disguise.DisguiseAPI;
import me.libraryaddict.disguise.disguisetypes.Disguise;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.block.data.BlockData;
import org.bukkit.entity.ArmorStand;
import org.bukkit.entity.Player;
import org.bukkit.util.Vector;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public class FreezeManager {
private static final Map<Player, FreezeData> frozenPlayers = new ConcurrentHashMap<>();
private static final Vector velocity = new Vector(0, 0, 0);
public static boolean freeze(Player player, Material material) {
Location location = player.getLocation();
if (frozenPlayers.containsKey(player)) {
FreezeData data = frozenPlayers.remove(player);
Location blockLocation = location.getBlock().getLocation();
for (Player p : Bukkit.getOnlinePlayers()) {
p.sendBlockChange(blockLocation, data.blockData);
}
ArmorStand armorStand = data.armorStand;
armorStand.removePassenger(player);
armorStand.remove();
player.setInvulnerable(false);
BlockAndSeekContainer.NO_COLLIDE_TEAM.removeEntry(player.getName());
if (data.disguise() != null) DisguiseAPI.disguiseToAll(player, data.disguise);
} else {
Block block = location.getBlock();
BlockData blockData = block.getBlockData();
Location blockLocation = block.getLocation();
Location centerLocation = blockLocation.toCenterLocation();
Location upperBlockLocation = centerLocation.clone();
upperBlockLocation.setY(upperBlockLocation.getY() + 1);
if (!upperBlockLocation.getBlock().isSolid() && !blockLocation.getBlock().isSolid()) {
for (Player p : Bukkit.getOnlinePlayers()) {
p.sendBlockChange(blockLocation, material.createBlockData());
}
centerLocation.setY(centerLocation.getY() - 0.5);
player.setVelocity(velocity);
player.setInvulnerable(true);
BlockAndSeekContainer.NO_COLLIDE_TEAM.addEntry(player.getName());
ArmorStand armorStand = location.getWorld().spawn(centerLocation, ArmorStand.class);
armorStand.setInvulnerable(true);
armorStand.setSmall(true);
armorStand.setGravity(true);
armorStand.setCanMove(false);
armorStand.setInvisible(true);
armorStand.setCollidable(false);
armorStand.addPassenger(player);
Disguise disguise = DisguiseAPI.getDisguise(player);
DisguiseAPI.undisguiseToAll(player);
frozenPlayers.put(player, new FreezeData(armorStand, blockData, disguise));
} else return false;
}
return true;
}
private record FreezeData(ArmorStand armorStand, BlockData blockData, Disguise disguise) {
}
}

View File

@@ -0,0 +1,171 @@
package hdvtdev.blockAndSeek.managers;
import hdvtdev.blockAndSeek.BlockAndSeek;
import hdvtdev.blockAndSeek.BlockAndSeekGame;
import hdvtdev.blockAndSeek.BlockAndSeekMap;
import hdvtdev.blockAndSeek.Localization;
import hdvtdev.blockAndSeek.roulette.RouletteCreator;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.title.Title;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.WorldCreator;
import org.bukkit.entity.Player;
import org.bukkit.scheduler.BukkitRunnable;
import org.bukkit.scoreboard.Criteria;
import org.bukkit.scoreboard.DisplaySlot;
import org.bukkit.scoreboard.Objective;
import org.bukkit.scoreboard.Scoreboard;
import java.io.File;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
public class GamesManager {
private static final ConcurrentHashMap<String, BlockAndSeekGame> games = new ConcurrentHashMap<>();
public static boolean isExist(String name) {
return games.containsKey(name);
}
public static Set<String> getAvailableGames() {
return games.keySet();
}
public static int createGame(String name) {
if (games.containsKey(name)) return 1;
if (Bukkit.getWorld(name) == null) {
if (new File(BlockAndSeek.getServerDataFolder(), name).exists()) {
Bukkit.createWorld(new WorldCreator(name));
} else return 2;
}
BlockAndSeekMap map = ConfigManager.getMap(name);
BlockAndSeekGame game = new BlockAndSeekGame(name, map.maxPlayers());
List<Integer> spawnCords = map.spawn();
List<Integer> lobbyCords = map.lobby();
games.put(name, game);
new BukkitRunnable() {
int duration = map.duration();
int waitTime = 30;
final Location spawn = new Location(Bukkit.getWorld(name), spawnCords.getFirst(), spawnCords.get(1), spawnCords.get(2));
final Location lobby = new Location(Bukkit.getWorld(name), lobbyCords.getFirst(), lobbyCords.get(1), lobbyCords.get(2));
@Override
public void run() {
if (!game.isStarted()) {
int playerCount = game.playerCount();
for (Player player : game.getPlayers()) {
player.sendActionBar(Component.text("Игроков " + playerCount + "/12")); //TODO!
}
if (playerCount >= map.minPlayers()) {
if (waitTime == 0 || playerCount == map.maxPlayers()) {
game.start();
Player seeker = game.selectRandomSeeker();
seeker.teleport(spawn);
for (Player player : game.getHiders()) {
player.teleport(spawn);
RouletteCreator.createRoulette(player, null, true, map.blocks());
}
} else {
if (waitTime < 5 || waitTime % 5 == 0) {
for (Player player : game.getPlayers()) {
player.sendMessage(Localization.getLangComponentWithPrefix(player.locale().toLanguageTag(), "wait-time-left", "{time}", String.valueOf(waitTime)));
}
}
waitTime--;
}
} else waitTime = 10;
} else {
if (game.hidersCount() == 0) {
for (Player player : game.getPlayers()) {
player.showTitle(Title.title(Localization.getComponent("seekers-won"), Component.text("")));
}
game.end();
games.remove(name);
this.cancel();
}
for (Player player : game.getPlayers()) {
player.sendActionBar(Localization.getComponent("game-time-left", "{time}", String.valueOf(duration)));
}
if (duration == 0) {
if (game.hidersCount() == 1) {
for (Player player : game.getPlayers()) {
player.showTitle(Title.title(Localization.getComponent("hiders-solo-win", "{player}", player.getName()), Component.text("")));
}
} else {
for (Player player : game.getPlayers()) {
player.showTitle(Title.title(Localization.getComponent("hiders-won"), 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);
}
private static Scoreboard updateScoreboard(Scoreboard scoreboard, int players, int maxPlayers) {
Objective objective = scoreboard.getObjective(DisplaySlot.SIDEBAR);
for (String o : scoreboard.getEntries()) {
scoreboard.resetScores(o);
}
objective.getScore(" ").setScore(3);
objective.getScore(Localization.getComponent("game-players-count", "{players}", String.valueOf(players), "{max-players}", String.valueOf(maxPlayers)).toString()).setScore(2);
objective.getScore(" ").setScore(1);
objective.getScore(Localization.getComponent("wait-time-left", "{time}", String.valueOf(30)).toString()).setScore(0);
return scoreboard;
}
private static Scoreboard newLobbyScoreboard(String name, int players, int maxPlayers) {
Scoreboard scoreboard = Bukkit.getScoreboardManager().getNewScoreboard();
Objective objective = scoreboard.registerNewObjective(name, Criteria.DUMMY, Localization.getComponent(" game-title", "{title}", name));
objective.setDisplaySlot(DisplaySlot.SIDEBAR);
objective.getScore(" ").setScore(3);
objective.getScore(Localization.getComponent("game-players-count", "{players}", String.valueOf(players), "{max-players}", String.valueOf(maxPlayers)).toString()).setScore(2);
objective.getScore(" ").setScore(1);
objective.getScore(Localization.getComponent("wait-time-left", "{time}", String.valueOf(30)).toString()).setScore(0);
return scoreboard;
}
}

View File

@@ -0,0 +1,11 @@
package hdvtdev.blockAndSeek.managers;
import hdvtdev.blockAndSeek.BlockAndSeekMap;
import java.util.Map;
public class MapsManager {
private static final Map<String, BlockAndSeekMap> maps = null;
}

View File

@@ -1,6 +1,7 @@
package hdvtdev.blockAndSeek.roulette;
import hdvtdev.blockAndSeek.BlockAndSeek;
import hdvtdev.blockAndSeek.BlockAndSeekMap;
import hdvtdev.blockAndSeek.EventListener;
import me.libraryaddict.disguise.DisguiseAPI;
import me.libraryaddict.disguise.disguisetypes.DisguiseType;
@@ -23,11 +24,8 @@ import java.util.List;
public class RouletteCreator implements InventoryHolder {
private static final int[] filledSlots = {
};
public static void createRoulette(Player player, Inventory inventory, boolean openInventory) {
public static void createRoulette(Player player, Inventory inventory, boolean openInventory, List<BlockAndSeekMap.Block> blocks) {
Inventory gui = inventory == null ? new RouletteCreator().getInventory() : inventory;
@@ -35,13 +33,7 @@ public class RouletteCreator implements InventoryHolder {
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 RouletteGenerator rouletteGenerator = new RouletteGenerator(blocks);
final List<RouletteList<ItemStack>> rows = List.of(
new RouletteList<>(rouletteGenerator.getRandomRow(15)),

View File

@@ -1,6 +1,7 @@
package hdvtdev.blockAndSeek.roulette;
import com.lewdev.probabilitylib.ProbabilityCollection;
import hdvtdev.blockAndSeek.BlockAndSeekMap;
import org.bukkit.inventory.ItemStack;
import java.util.ArrayList;
@@ -11,9 +12,9 @@ public class RouletteGenerator {
private final ProbabilityCollection<ItemStack> probabilityCollection = new ProbabilityCollection<>();
public RouletteGenerator(List<Block> blocks) {
for (Block block : blocks) {
probabilityCollection.add(block.itemStack, block.chance);
public RouletteGenerator(List<BlockAndSeekMap.Block> blocks) {
for (BlockAndSeekMap.Block block : blocks) {
probabilityCollection.add(block.block(), block.chance());
}
}
@@ -23,8 +24,5 @@ public class RouletteGenerator {
return items;
}
public record Block(ItemStack itemStack, int chance) {
}
}

View File

@@ -1,10 +1,21 @@
en_US:
en-US:
#Maps
maps-available: "<gold>Available maps: <white>"
maps-available-element: "- {color-status}{map}<white>"
map-lobby-sidebar: "<bold><gradient:#FFFF00:#FFD700:#FFA500>{map}"
not-enough-permissions: "<red><bold>You do not have permission to run this command."
not-enough-arguments: "<red><bold>Too few arguments to run command {command}. Arguments example: {help}"
successful-reload: "<green>Successfully reloaded <yellow><u>{config}<green>."
failed-reload: "<red>Failed to reload <yellow><u>{config}<red>. Error: {e}"
failed-reload: "<red>Failed to reload <yellow><u>{config}<red>. Error: {e}"
seekers-won: "<bold><yellow>Seekers <red>won!"
hiders-won: "<bold><yellow>Seekers <green>won!"
hiders-solo-win: "<bold><yellow>{player} <green>won this game!"
game-time-left: "<gold>Time left: <yellow>{time}<gold>s"
game-players-count: "<yellow>{players} <gold>of <yellow>{max-players}"
game-title: "<bold><gold>{title}"
wait-time-left: "<gold>Game starts in: <yellow><bold>{time}<reset><gold>s"