idk some "cool" stuff
This commit is contained in:
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
/.gradle/
|
||||||
|
/gradle/
|
||||||
|
/bin/
|
||||||
Binary file not shown.
1
.idea/modules.xml
generated
1
.idea/modules.xml
generated
@@ -2,6 +2,7 @@
|
|||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="ProjectModuleManager">
|
<component name="ProjectModuleManager">
|
||||||
<modules>
|
<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" />
|
<module fileurl="file://$PROJECT_DIR$/.idea/modules/BlockAndSeek.main.iml" filepath="$PROJECT_DIR$/.idea/modules/BlockAndSeek.main.iml" />
|
||||||
</modules>
|
</modules>
|
||||||
</component>
|
</component>
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package hdvtdev.blockAndSeek;
|
package hdvtdev.blockAndSeek;
|
||||||
|
|
||||||
|
import hdvtdev.blockAndSeek.managers.ConfigManager;
|
||||||
import me.libraryaddict.disguise.LibsDisguises;
|
import me.libraryaddict.disguise.LibsDisguises;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.command.CommandExecutor;
|
import org.bukkit.command.CommandExecutor;
|
||||||
@@ -24,6 +25,10 @@ public class BlockAndSeek extends JavaPlugin implements CommandExecutor {
|
|||||||
return javaPlugin.getDataFolder();
|
return javaPlugin.getDataFolder();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static File getServerDataFolder() {
|
||||||
|
return javaPlugin.getServer().getPluginsFolder().getParentFile();
|
||||||
|
}
|
||||||
|
|
||||||
public static InputStream getPluginResource(String resource) {
|
public static InputStream getPluginResource(String resource) {
|
||||||
return javaPlugin.getResource(resource);
|
return javaPlugin.getResource(resource);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,15 @@
|
|||||||
package hdvtdev.blockAndSeek;
|
package hdvtdev.blockAndSeek;
|
||||||
|
|
||||||
import me.libraryaddict.disguise.DisguiseAPI;
|
import me.libraryaddict.disguise.DisguiseAPI;
|
||||||
|
import org.bukkit.GameMode;
|
||||||
import org.bukkit.Material;
|
import org.bukkit.Material;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.persistence.PersistentDataType;
|
import org.bukkit.persistence.PersistentDataType;
|
||||||
|
|
||||||
import java.security.SecureRandom;
|
import java.security.SecureRandom;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
@@ -15,24 +18,32 @@ public class BlockAndSeekGame {
|
|||||||
|
|
||||||
private final ConcurrentHashMap<Player, PlayerType> players = new ConcurrentHashMap<>();
|
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 String name;
|
||||||
|
private final int maxPlayers;
|
||||||
|
|
||||||
public BlockAndSeekGame(String name) {
|
|
||||||
|
public BlockAndSeekGame(String name, int maxPlayers) {
|
||||||
this.name = name;
|
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() {
|
public void end() {
|
||||||
for (Player player : players.keySet()) {
|
for (Player player : players.keySet()) {
|
||||||
EventListener.unfreezePlayer(player);
|
//EventListener.unfreezePlayer(player); TODO
|
||||||
player.getPersistentDataContainer().remove(BlockAndSeekContainer.PLAYER);
|
player.getPersistentDataContainer().remove(BlockAndSeekContainer.PLAYER);
|
||||||
player.sendBlockChange(player.getLocation(), Material.AIR.createBlockData());
|
player.sendBlockChange(player.getLocation(), Material.AIR.createBlockData());
|
||||||
|
player.setGameMode(GameMode.SURVIVAL);
|
||||||
DisguiseAPI.undisguiseToAll(player);
|
DisguiseAPI.undisguiseToAll(player);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean addPlayer(Player player) {
|
public boolean addPlayer(Player player) {
|
||||||
if (started.get()) {
|
if (started.get() || playerCount() + 1 > maxPlayers) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
player.getPersistentDataContainer().set(BlockAndSeekContainer.PLAYER, PersistentDataType.STRING, name);
|
player.getPersistentDataContainer().set(BlockAndSeekContainer.PLAYER, PersistentDataType.STRING, name);
|
||||||
@@ -44,6 +55,11 @@ public class BlockAndSeekGame {
|
|||||||
players.remove(player);
|
players.remove(player);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setSpectator(Player player) {
|
||||||
|
players.put(player, PlayerType.SPECTATOR);
|
||||||
|
player.setGameMode(GameMode.SPECTATOR);
|
||||||
|
}
|
||||||
|
|
||||||
public Set<Player> getPlayers() {
|
public Set<Player> getPlayers() {
|
||||||
return players.keySet();
|
return players.keySet();
|
||||||
}
|
}
|
||||||
@@ -59,7 +75,7 @@ public class BlockAndSeekGame {
|
|||||||
return (int) players.values().stream().filter(f -> f.equals(PlayerType.SEEKER)).count();
|
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();
|
return (int) players.values().stream().filter(f -> f.equals(PlayerType.HIDER)).count();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -80,14 +96,19 @@ public class BlockAndSeekGame {
|
|||||||
int i = 0;
|
int i = 0;
|
||||||
int randomNum = random.nextInt(0, players.size());
|
int randomNum = random.nextInt(0, players.size());
|
||||||
for (Player player : players.keySet()) {
|
for (Player player : players.keySet()) {
|
||||||
if (i == randomNum) return player;
|
if (i == randomNum) {
|
||||||
|
players.put(player, PlayerType.SEEKER);
|
||||||
|
return player;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private enum PlayerType {
|
private enum PlayerType {
|
||||||
SEEKER,
|
SEEKER,
|
||||||
HIDER
|
HIDER,
|
||||||
|
SPECTATOR
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,13 +1,17 @@
|
|||||||
package hdvtdev.blockAndSeek;
|
package hdvtdev.blockAndSeek;
|
||||||
|
|
||||||
|
|
||||||
import org.bukkit.inventory.ItemStack;
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
import java.util.List;
|
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) {
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
package hdvtdev.blockAndSeek;
|
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 net.kyori.adventure.text.minimessage.MiniMessage;
|
||||||
|
import org.bukkit.Location;
|
||||||
import org.bukkit.Material;
|
import org.bukkit.Material;
|
||||||
import org.bukkit.command.Command;
|
import org.bukkit.command.Command;
|
||||||
import org.bukkit.command.CommandExecutor;
|
import org.bukkit.command.CommandExecutor;
|
||||||
@@ -36,8 +39,20 @@ public class CommandListener implements CommandExecutor, TabCompleter {
|
|||||||
|
|
||||||
switch (args[0]) {
|
switch (args[0]) {
|
||||||
case "test" -> {
|
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) {
|
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" -> {
|
case "freeze" -> {
|
||||||
@@ -50,6 +65,12 @@ public class CommandListener implements CommandExecutor, TabCompleter {
|
|||||||
player.getInventory().addItem(foo);
|
player.getInventory().addItem(foo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
case "f" -> {
|
||||||
|
if (sender instanceof Player player) {
|
||||||
|
FreezeManager.freeze(player, Material.TARGET);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
case "foo" -> {
|
case "foo" -> {
|
||||||
if (sender instanceof Player player) {
|
if (sender instanceof Player player) {
|
||||||
ItemStack foo = new ItemStack(Material.BROWN_DYE);
|
ItemStack foo = new ItemStack(Material.BROWN_DYE);
|
||||||
@@ -86,10 +107,11 @@ public class CommandListener implements CommandExecutor, TabCompleter {
|
|||||||
switch (args[1]) {
|
switch (args[1]) {
|
||||||
case "localization" -> {
|
case "localization" -> {
|
||||||
try {
|
try {
|
||||||
|
|
||||||
ConfigManager.load("localization.yml");
|
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) {
|
} 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
|
@Override
|
||||||
public @Nullable List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
|
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) {
|
return switch (args.length) {
|
||||||
case 1 -> {
|
case 1 -> {
|
||||||
if (sender.hasPermission("blockandseek.manage")) {
|
if (hasPermission) {
|
||||||
yield List.of("reload", "help", "map", "join");
|
yield List.of("reload", "help", "map");
|
||||||
} else yield List.of("help", "join");
|
} else yield List.of("help");
|
||||||
}
|
}
|
||||||
case 2 -> switch (args[0]) {
|
case 2 -> switch (args[0]) {
|
||||||
case "map" -> {
|
case "map" -> {
|
||||||
List<String> scmds = new ArrayList<>();
|
List<String> scmds = new ArrayList<>();
|
||||||
/*
|
|
||||||
if (sender.hasPermission("blockandseek.manage")) {
|
if (hasPermission) {
|
||||||
scmds.addAll(List.of("create", "list"));
|
scmds.addAll(List.of("create", "list"));
|
||||||
scmds.addAll(ConfigManager.createdMaps());
|
scmds.addAll(ConfigManager.getAllMaps());
|
||||||
}
|
}
|
||||||
|
|
||||||
*/
|
|
||||||
yield scmds;
|
yield scmds;
|
||||||
}
|
}
|
||||||
case "join" -> List.of("test"); //TODO
|
|
||||||
case "reload" -> {
|
case "reload" -> {
|
||||||
if (sender.hasPermission("blockandseek.manage")) {
|
if (hasPermission) {
|
||||||
yield List.of("messages", "maps");
|
yield List.of("localization", "config");
|
||||||
} else yield List.of();
|
} else yield List.of();
|
||||||
}
|
}
|
||||||
default -> List.of();
|
default -> List.of();
|
||||||
@@ -150,15 +171,24 @@ public class CommandListener implements CommandExecutor, TabCompleter {
|
|||||||
case 3 -> switch (args[1]) {
|
case 3 -> switch (args[1]) {
|
||||||
case "create", "list" -> List.of();
|
case "create", "list" -> List.of();
|
||||||
default -> {
|
default -> {
|
||||||
/*
|
|
||||||
if (ConfigManager.createdMaps().contains(args[1]) && sender.hasPermission("blockandseek.manage")) {
|
if (ConfigManager.getAllMaps().contains(args[1]) && hasPermission) {
|
||||||
yield List.of("setspawn", "setlobby", "setduration");
|
yield List.of("setspawn", "setlobby", "setduration", "setmaxplayers", "setminplayers", "status", "remove");
|
||||||
} else yield List.of();
|
} 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();
|
default -> List.of();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,25 +1,26 @@
|
|||||||
package hdvtdev.blockAndSeek;
|
package hdvtdev.blockAndSeek;
|
||||||
|
|
||||||
|
|
||||||
|
import hdvtdev.blockAndSeek.managers.FreezeManager;
|
||||||
|
import hdvtdev.blockAndSeek.managers.GamesManager;
|
||||||
import me.libraryaddict.disguise.DisguiseAPI;
|
import me.libraryaddict.disguise.DisguiseAPI;
|
||||||
import me.libraryaddict.disguise.disguisetypes.DisguiseType;
|
import me.libraryaddict.disguise.disguisetypes.DisguiseType;
|
||||||
import me.libraryaddict.disguise.disguisetypes.MiscDisguise;
|
import me.libraryaddict.disguise.disguisetypes.MiscDisguise;
|
||||||
import net.kyori.adventure.text.minimessage.MiniMessage;
|
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.Location;
|
|
||||||
import org.bukkit.Material;
|
import org.bukkit.Material;
|
||||||
import org.bukkit.Sound;
|
import org.bukkit.entity.ArmorStand;
|
||||||
import org.bukkit.block.Block;
|
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.event.EventHandler;
|
import org.bukkit.event.EventHandler;
|
||||||
import org.bukkit.event.Listener;
|
import org.bukkit.event.Listener;
|
||||||
|
import org.bukkit.event.block.Action;
|
||||||
import org.bukkit.event.entity.EntityDamageByEntityEvent;
|
import org.bukkit.event.entity.EntityDamageByEntityEvent;
|
||||||
|
import org.bukkit.event.entity.PlayerDeathEvent;
|
||||||
import org.bukkit.event.inventory.InventoryClickEvent;
|
import org.bukkit.event.inventory.InventoryClickEvent;
|
||||||
import org.bukkit.event.inventory.InventoryCloseEvent;
|
import org.bukkit.event.inventory.InventoryCloseEvent;
|
||||||
import org.bukkit.event.player.PlayerInteractEvent;
|
import org.bukkit.event.player.PlayerInteractEvent;
|
||||||
import org.bukkit.event.player.PlayerQuitEvent;
|
import org.bukkit.event.player.PlayerQuitEvent;
|
||||||
|
import org.bukkit.inventory.EquipmentSlot;
|
||||||
import org.bukkit.inventory.ItemStack;
|
import org.bukkit.inventory.ItemStack;
|
||||||
import org.bukkit.inventory.meta.ItemMeta;
|
|
||||||
import org.bukkit.persistence.PersistentDataContainer;
|
import org.bukkit.persistence.PersistentDataContainer;
|
||||||
import org.bukkit.persistence.PersistentDataType;
|
import org.bukkit.persistence.PersistentDataType;
|
||||||
import org.bukkit.potion.PotionEffect;
|
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, BukkitTask> tasks = new ConcurrentHashMap<>();
|
||||||
private static final ConcurrentHashMap<Player, Long> soundCoolDown = 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 Vector ZERO_VELOCITY = new Vector(0, 0, 0);
|
||||||
private static final PotionEffect INVISIBILITY = new PotionEffect(PotionEffectType.INVISIBILITY, PotionEffect.INFINITE_DURATION, 2, false, false);
|
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) {
|
public void onPlayerQuit(PlayerQuitEvent event) {
|
||||||
Player player = event.getPlayer();
|
Player player = event.getPlayer();
|
||||||
PersistentDataContainer container = player.getPersistentDataContainer();
|
PersistentDataContainer container = player.getPersistentDataContainer();
|
||||||
if (frozenPlayers.remove(player) != null) {
|
|
||||||
unfreezePlayer(player);
|
|
||||||
}
|
|
||||||
String arena = container.get(BlockAndSeekContainer.PLAYER, PersistentDataType.STRING);
|
String arena = container.get(BlockAndSeekContainer.PLAYER, PersistentDataType.STRING);
|
||||||
if (arena != null) {
|
if (arena != null) {
|
||||||
container.remove(BlockAndSeekContainer.PLAYER);
|
container.remove(BlockAndSeekContainer.PLAYER);
|
||||||
@@ -62,118 +61,31 @@ public class EventListener implements Listener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void onPlayerDeath(PlayerDeathEvent event) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
public void onDamage(EntityDamageByEntityEvent event) {
|
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
|
@EventHandler
|
||||||
public void onRightClick(PlayerInteractEvent event) {
|
public void onRightClick(PlayerInteractEvent event) {
|
||||||
Player player = event.getPlayer();
|
if (event.getHand() != EquipmentSlot.HAND) return;
|
||||||
ItemStack item = player.getInventory().getItemInMainHand();
|
Action action = event.getAction();
|
||||||
ItemMeta itemMeta = item.getItemMeta();
|
if (action == Action.RIGHT_CLICK_BLOCK || action == Action.RIGHT_CLICK_AIR) {
|
||||||
if (itemMeta != null) {
|
Player player = event.getPlayer();
|
||||||
|
if (player.getInventory().getItemInMainHand().equals(new ItemStack(Material.HEART_OF_THE_SEA))) {
|
||||||
PersistentDataContainer data = itemMeta.getPersistentDataContainer();
|
FreezeManager.freeze(player, Material.TARGET);
|
||||||
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());
|
|
||||||
}
|
}
|
||||||
|
} else event.getPlayer().sendMessage(action.toString());
|
||||||
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!"));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
@EventHandler
|
||||||
public void onClick(InventoryClickEvent event) {
|
public void onClick(InventoryClickEvent event) {
|
||||||
|
|||||||
@@ -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);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,26 +1,33 @@
|
|||||||
package hdvtdev.blockAndSeek;
|
package hdvtdev.blockAndSeek;
|
||||||
|
|
||||||
|
import hdvtdev.blockAndSeek.managers.ConfigManager;
|
||||||
import net.kyori.adventure.text.Component;
|
import net.kyori.adventure.text.Component;
|
||||||
import net.kyori.adventure.text.minimessage.MiniMessage;
|
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;
|
import java.util.Map;
|
||||||
|
|
||||||
public class Localization {
|
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 MiniMessage miniMessage = MiniMessage.miniMessage();
|
||||||
private static final Component prefix = miniMessage.deserialize("<gold>[<bold><blue>BlockAndSeek<reset><gold>] ");
|
private static final Component prefix = miniMessage.deserialize("<gold>[<bold><blue>BlockAndSeek<reset><gold>] ");
|
||||||
|
|
||||||
public static Component getPrefix() {
|
|
||||||
return prefix;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void update() {
|
public static void update() {
|
||||||
localization = ConfigManager.getLocalization();
|
localization = Collections.unmodifiableMap(ConfigManager.getLocalization());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String get(String key, String... replacements) {
|
public static String get(@NotNull String key, String... replacements) {
|
||||||
String s = localization.get(key);
|
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) {
|
if (s != null) {
|
||||||
for (int i = 0; i < replacements.length; i += 2) {
|
for (int i = 0; i < replacements.length; i += 2) {
|
||||||
s = s.replace(replacements[i], replacements[i + 1]);
|
s = s.replace(replacements[i], replacements[i + 1]);
|
||||||
@@ -30,8 +37,19 @@ public class Localization {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static Component getComponent(String key, String... replacements) {
|
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));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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.Material;
|
||||||
import org.bukkit.configuration.ConfigurationSection;
|
import org.bukkit.configuration.ConfigurationSection;
|
||||||
import org.bukkit.configuration.file.YamlConfiguration;
|
import org.bukkit.configuration.file.YamlConfiguration;
|
||||||
@@ -9,20 +12,21 @@ import org.jetbrains.annotations.Nullable;
|
|||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
import java.util.HashSet;
|
import java.util.*;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
public class ConfigManager {
|
public class ConfigManager {
|
||||||
|
|
||||||
private static volatile ConcurrentHashMap<String, String> localization = new ConcurrentHashMap<>();
|
private static volatile Map<String, Map<String, String>> localization;
|
||||||
private static volatile ConcurrentHashMap<String, String> config = new ConcurrentHashMap<>();
|
private static volatile Map<String, String> config;
|
||||||
private static volatile ConcurrentHashMap<String, BlockAndSeekMap> maps = new ConcurrentHashMap<>();
|
private static Map<String, BlockAndSeekMap> maps = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
private static final File mapsFile = new File(BlockAndSeek.getPluginDataFolder(), "maps.yml");
|
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() {
|
public static Set<String> getAllMaps() {
|
||||||
return YamlConfiguration.loadConfiguration(mapsFile).getKeys(false);
|
return YamlConfiguration.loadConfiguration(mapsFile).getKeys(false);
|
||||||
}
|
}
|
||||||
@@ -31,7 +35,9 @@ public class ConfigManager {
|
|||||||
SPAWN_REQUIRED,
|
SPAWN_REQUIRED,
|
||||||
LOBBY_REQUIRED,
|
LOBBY_REQUIRED,
|
||||||
DURATION_REQUIRED,
|
DURATION_REQUIRED,
|
||||||
BLOCKS_REQUIRED
|
BLOCKS_REQUIRED,
|
||||||
|
MIN_PLAYERS_REQUIRED,
|
||||||
|
MAX_PLAYERS_REQUIRED
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Set<String> getReadyMaps() {
|
public static Set<String> getReadyMaps() {
|
||||||
@@ -52,6 +58,10 @@ public class ConfigManager {
|
|||||||
if (lobby.size() != 3) status.add(MapStatus.LOBBY_REQUIRED);
|
if (lobby.size() != 3) status.add(MapStatus.LOBBY_REQUIRED);
|
||||||
int duration = section.getInt("duration");
|
int duration = section.getInt("duration");
|
||||||
if (duration <= 0) status.add(MapStatus.DURATION_REQUIRED);
|
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(
|
List<BlockAndSeekMap.Block> blocks = section.getMapList("blocks").stream().map(
|
||||||
block -> {
|
block -> {
|
||||||
try {
|
try {
|
||||||
@@ -67,7 +77,8 @@ public class ConfigManager {
|
|||||||
).toList();
|
).toList();
|
||||||
if (blocks.isEmpty() || new HashSet<>(blocks).size() == 1) status.add(MapStatus.BLOCKS_REQUIRED);
|
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;
|
} else return null;
|
||||||
|
|
||||||
@@ -84,6 +95,8 @@ public class ConfigManager {
|
|||||||
section.set("spawn", List.of());
|
section.set("spawn", List.of());
|
||||||
section.set("lobby", List.of());
|
section.set("lobby", List.of());
|
||||||
section.set("duration", 0);
|
section.set("duration", 0);
|
||||||
|
section.set("min-players", 0);
|
||||||
|
section.set("max-players", 0);
|
||||||
section.set("blocks", List.of(Map.of()));
|
section.set("blocks", List.of(Map.of()));
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -127,19 +140,22 @@ public class ConfigManager {
|
|||||||
if (!conf.exists()) {
|
if (!conf.exists()) {
|
||||||
BlockAndSeek.saveResource(file);
|
BlockAndSeek.saveResource(file);
|
||||||
|
|
||||||
ConcurrentHashMap<String, String> confMap = new ConcurrentHashMap<>();
|
|
||||||
|
|
||||||
switch (file) {
|
switch (file) {
|
||||||
case "config.yml" -> {
|
case "config.yml" -> {
|
||||||
|
Map<String, String> confMap = new HashMap<>();
|
||||||
for (String key : defaultConfiguration.getKeys(false)) {
|
for (String key : defaultConfiguration.getKeys(false)) {
|
||||||
confMap.put(key, defaultConfiguration.getString(key, "NULL"));
|
confMap.put(key, defaultConfiguration.getString(key, "NULL"));
|
||||||
}
|
}
|
||||||
config = confMap;
|
config = confMap;
|
||||||
}
|
}
|
||||||
case "localization.yml" -> {
|
case "localization.yml" -> {
|
||||||
for (String key : defaultConfiguration.getConfigurationSection("en_US").getKeys(false)) {
|
Map<String, Map<String, String>> confMap = new HashMap<>();
|
||||||
confMap.put(key, defaultConfiguration.getString(key, "NULL"));
|
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 = confMap;
|
||||||
Localization.update();
|
Localization.update();
|
||||||
}
|
}
|
||||||
@@ -158,7 +174,7 @@ public class ConfigManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static void loadMaps(File configurationFile) throws IOException {
|
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);
|
YamlConfiguration configuration = YamlConfiguration.loadConfiguration(configurationFile);
|
||||||
|
|
||||||
for (String map : configuration.getKeys(false)) {
|
for (String map : configuration.getKeys(false)) {
|
||||||
@@ -167,24 +183,28 @@ public class ConfigManager {
|
|||||||
List<Integer> spawn = section.getIntegerList("spawn");
|
List<Integer> spawn = section.getIntegerList("spawn");
|
||||||
List<Integer> lobby = section.getIntegerList("lobby");
|
List<Integer> lobby = section.getIntegerList("lobby");
|
||||||
int duration = section.getInt("duration");
|
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(
|
List<BlockAndSeekMap.Block> blocks = section.getMapList("blocks").stream().map(
|
||||||
block -> {
|
block -> {
|
||||||
try {
|
try {
|
||||||
return new BlockAndSeekMap.Block(
|
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")
|
(int) block.get("chance")
|
||||||
);
|
);
|
||||||
} catch (IllegalArgumentException | ClassCastException | NullPointerException ignored) {
|
} catch (IllegalArgumentException | ClassCastException | NullPointerException ignored) {
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
).toList();
|
).filter(Objects::nonNull).toList();
|
||||||
|
|
||||||
if (!spawn.isEmpty() && !lobby.isEmpty() && duration != 0 && !blocks.isEmpty()) {
|
if (!spawn.isEmpty() && !lobby.isEmpty() && duration > 0 && !blocks.isEmpty() && minPlayers > 0 && maxPlayers > 0) {
|
||||||
confMap.put(map, new BlockAndSeekMap(spawn, lobby, duration, blocks));
|
confMap.put(map, new BlockAndSeekMap(spawn, lobby, duration, minPlayers, maxPlayers, blocks));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
maps = confMap;
|
maps = confMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -212,40 +232,44 @@ public class ConfigManager {
|
|||||||
|
|
||||||
private static void loadLocalization(File configurationFile, YamlConfiguration defaultConfiguration) throws IOException {
|
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);
|
YamlConfiguration configuration = YamlConfiguration.loadConfiguration(configurationFile);
|
||||||
String language = config.get("language");
|
|
||||||
|
|
||||||
ConfigurationSection defaultSection = defaultConfiguration.getConfigurationSection("en_US");
|
ConfigurationSection defaultSection = defaultConfiguration.getConfigurationSection("en-US");
|
||||||
ConfigurationSection configSection = configuration.getConfigurationSection(language);
|
|
||||||
|
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"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
confMap.put(langKey, langMap);
|
||||||
} 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);
|
configuration.save(configurationFile);
|
||||||
|
|
||||||
localization = confMap;
|
localization = confMap;
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static ConcurrentHashMap<String, String> getLocalization() {
|
public static Map<String, Map<String, String>> getLocalization() {
|
||||||
return localization;
|
return localization;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -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) {
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
171
src/main/java/hdvtdev/blockAndSeek/managers/GamesManager.java
Normal file
171
src/main/java/hdvtdev/blockAndSeek/managers/GamesManager.java
Normal 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
11
src/main/java/hdvtdev/blockAndSeek/managers/MapsManager.java
Normal file
11
src/main/java/hdvtdev/blockAndSeek/managers/MapsManager.java
Normal 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;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
package hdvtdev.blockAndSeek.roulette;
|
package hdvtdev.blockAndSeek.roulette;
|
||||||
|
|
||||||
import hdvtdev.blockAndSeek.BlockAndSeek;
|
import hdvtdev.blockAndSeek.BlockAndSeek;
|
||||||
|
import hdvtdev.blockAndSeek.BlockAndSeekMap;
|
||||||
import hdvtdev.blockAndSeek.EventListener;
|
import hdvtdev.blockAndSeek.EventListener;
|
||||||
import me.libraryaddict.disguise.DisguiseAPI;
|
import me.libraryaddict.disguise.DisguiseAPI;
|
||||||
import me.libraryaddict.disguise.disguisetypes.DisguiseType;
|
import me.libraryaddict.disguise.disguisetypes.DisguiseType;
|
||||||
@@ -23,11 +24,8 @@ import java.util.List;
|
|||||||
|
|
||||||
public class RouletteCreator implements InventoryHolder {
|
public class RouletteCreator implements InventoryHolder {
|
||||||
|
|
||||||
private static final int[] filledSlots = {
|
|
||||||
|
|
||||||
};
|
public static void createRoulette(Player player, Inventory inventory, boolean openInventory, List<BlockAndSeekMap.Block> blocks) {
|
||||||
|
|
||||||
public static void createRoulette(Player player, Inventory inventory, boolean openInventory) {
|
|
||||||
|
|
||||||
Inventory gui = inventory == null ? new RouletteCreator().getInventory() : inventory;
|
Inventory gui = inventory == null ? new RouletteCreator().getInventory() : inventory;
|
||||||
|
|
||||||
@@ -35,13 +33,7 @@ public class RouletteCreator implements InventoryHolder {
|
|||||||
EventListener.createTask(player, new BukkitRunnable() {
|
EventListener.createTask(player, new BukkitRunnable() {
|
||||||
|
|
||||||
int i = 0;
|
int i = 0;
|
||||||
final RouletteGenerator rouletteGenerator = new RouletteGenerator(List.of(
|
final RouletteGenerator rouletteGenerator = new RouletteGenerator(blocks);
|
||||||
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<RouletteList<ItemStack>> rows = List.of(
|
final List<RouletteList<ItemStack>> rows = List.of(
|
||||||
new RouletteList<>(rouletteGenerator.getRandomRow(15)),
|
new RouletteList<>(rouletteGenerator.getRandomRow(15)),
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package hdvtdev.blockAndSeek.roulette;
|
package hdvtdev.blockAndSeek.roulette;
|
||||||
|
|
||||||
import com.lewdev.probabilitylib.ProbabilityCollection;
|
import com.lewdev.probabilitylib.ProbabilityCollection;
|
||||||
|
import hdvtdev.blockAndSeek.BlockAndSeekMap;
|
||||||
import org.bukkit.inventory.ItemStack;
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@@ -11,9 +12,9 @@ public class RouletteGenerator {
|
|||||||
|
|
||||||
private final ProbabilityCollection<ItemStack> probabilityCollection = new ProbabilityCollection<>();
|
private final ProbabilityCollection<ItemStack> probabilityCollection = new ProbabilityCollection<>();
|
||||||
|
|
||||||
public RouletteGenerator(List<Block> blocks) {
|
public RouletteGenerator(List<BlockAndSeekMap.Block> blocks) {
|
||||||
for (Block block : blocks) {
|
for (BlockAndSeekMap.Block block : blocks) {
|
||||||
probabilityCollection.add(block.itemStack, block.chance);
|
probabilityCollection.add(block.block(), block.chance());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -23,8 +24,5 @@ public class RouletteGenerator {
|
|||||||
return items;
|
return items;
|
||||||
}
|
}
|
||||||
|
|
||||||
public record Block(ItemStack itemStack, int chance) {
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,21 @@
|
|||||||
en_US:
|
en-US:
|
||||||
#Maps
|
#Maps
|
||||||
maps-available: "<gold>Available maps: <white>"
|
maps-available: "<gold>Available maps: <white>"
|
||||||
maps-available-element: "- {color-status}{map}<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-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}"
|
not-enough-arguments: "<red><bold>Too few arguments to run command {command}. Arguments example: {help}"
|
||||||
|
|
||||||
successful-reload: "<green>Successfully reloaded <yellow><u>{config}<green>."
|
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"
|
||||||
Reference in New Issue
Block a user