Compare commits

...
10 Commits
17 changed files with 260 additions and 48 deletions
@@ -20,6 +20,7 @@ public final class Main extends JavaPlugin {
private LootService lootService;
private StatService statService;
private BossBarService bossBarService;
private TabListService tabListService;
@Override
public void onEnable() {
@@ -37,6 +38,8 @@ public final class Main extends JavaPlugin {
statService = new StatService(this, round);
playerTeleporterService = PlayerTeleporterService.createSingletonInstance();
roundService = RoundService.createSingletonInstance(round, this, lootService, statService, playerTeleporterService);
tabListService = new TabListService(round, roundService);
roundService.setTabListService(tabListService);
playerService = PlayerService.createSingletonInstance(round, roundService, playerTeleporterService);
bossBarService = BossBarService.createSingletonInstance(round, roundService);
@@ -50,13 +53,13 @@ public final class Main extends JavaPlugin {
}
private void registerCommands() {
BaseCommand command = new BaseCommand(this, roundService, playerService, round, statService);
BaseCommand command = new BaseCommand(this, roundService, playerService, round, statService, tabListService);
}
private void registerEvents() {
PluginManager pluginManager = getServer().getPluginManager();
pluginManager.registerEvents(new PlayerDisconnectListener(playerService), this);
pluginManager.registerEvents(new PlayerJoinListener(playerService), this);
pluginManager.registerEvents(new PlayerJoinListener(playerService, tabListService), this);
pluginManager.registerEvents(new PlayerDamageListener(roundService, playerService, statService), this);
pluginManager.registerEvents(new ChestListener(roundService, lootService), this);
pluginManager.registerEvents(new ItemSpawnListener(roundService), this);
@@ -3,10 +3,7 @@ package com.alttd.hunger_games.commands;
import com.alttd.hunger_games.Main;
import com.alttd.hunger_games.commands.subcommands.*;
import com.alttd.hunger_games.config.Messages;
import com.alttd.hunger_games.services.PlayerService;
import com.alttd.hunger_games.services.Round;
import com.alttd.hunger_games.services.RoundService;
import com.alttd.hunger_games.services.StatService;
import com.alttd.hunger_games.services.*;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder;
@@ -23,7 +20,7 @@ import java.util.stream.Collectors;
public class BaseCommand implements CommandExecutor, TabExecutor {
private final List<SubCommand> subCommands;
public BaseCommand(Main main, RoundService roundService, PlayerService playerService, Round round, StatService statService) {
public BaseCommand(Main main, RoundService roundService, PlayerService playerService, Round round, StatService statService, TabListService tablistService) {
PluginCommand command = main.getCommand("hungergames");
if (command == null) {
subCommands = null;
@@ -37,12 +34,13 @@ public class BaseCommand implements CommandExecutor, TabExecutor {
subCommands = new ArrayList<>(List.of(
new Reload(main),
new RoundState(roundService),
new Register(playerService),
new StartRound(round, roundService),
new Register(playerService, tablistService),
new StartRound(round, roundService, playerService),
new NextPhase(round),
new EndRound(round),
new Stuck(main),
new Stats(statService)
new Stats(statService),
new ListPlayers(roundService)
));
}
@@ -0,0 +1,71 @@
package com.alttd.hunger_games.commands.subcommands;
import com.alttd.hunger_games.commands.SubCommand;
import com.alttd.hunger_games.config.Messages;
import com.alttd.hunger_games.data_objects.PLAYER_STATE;
import com.alttd.hunger_games.services.RoundService;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.JoinConfiguration;
import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder;
import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import java.util.*;
public class ListPlayers extends SubCommand {
private final RoundService roundService;
public ListPlayers(RoundService roundService) {
this.roundService = roundService;
}
@Override
public boolean onCommand(CommandSender commandSender, String[] args) {
Set<UUID> registeredUuids = roundService.getPlayers(PLAYER_STATE.REGISTERED);
Set<UUID> spectatingUuids = roundService.getPlayers(PLAYER_STATE.SPECTATING);
List<Component> registeredNames = registeredUuids.stream()
.map(Bukkit::getPlayer)
.filter(Objects::nonNull)
.map(Player::name)
.toList();
List<Component> spectatingNames = spectatingUuids.stream()
.map(Bukkit::getPlayer)
.filter(Objects::nonNull)
.map(Player::name)
.toList();
Component inGamePlayers = Component.join(JoinConfiguration.commas(true), registeredNames);
Component spectators = Component.join(JoinConfiguration.commas(true), spectatingNames);
int inGameCount = registeredNames.size();
int totalCount = inGameCount + spectatingNames.size();
commandSender.sendRichMessage(Messages.COMMANDS.LIST_PLAYERS,
Placeholder.unparsed("in_game", String.valueOf(inGameCount)),
Placeholder.unparsed("total", String.valueOf(totalCount)),
Placeholder.component("in_game_players", inGamePlayers),
Placeholder.component("spectators", spectators)
);
return true;
}
@Override
public String getName() {
return "list";
}
@Override
public List<String> getTabComplete(CommandSender commandSender, String[] args) {
return Collections.emptyList();
}
@Override
public String getHelpMessage() {
return Messages.HELP.LIST;
}
}
@@ -5,6 +5,8 @@ import com.alttd.hunger_games.commands.shared_parsers.OnlinePlayerParser;
import com.alttd.hunger_games.config.Messages;
import com.alttd.hunger_games.data_objects.PLAYER_STATE;
import com.alttd.hunger_games.services.PlayerService;
import com.alttd.hunger_games.services.TabListService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder;
import org.bukkit.Bukkit;
@@ -15,16 +17,14 @@ import javax.annotation.Nullable;
import java.util.List;
import java.util.Optional;
@RequiredArgsConstructor
@Slf4j
public class Register extends SubCommand {
private final static OnlinePlayerParser ONLINE_PLAYER_PARSER = new OnlinePlayerParser();
private final static int PLAYER_ARG = 1;
private final PlayerService playerService;
public Register(PlayerService playerService) {
this.playerService = playerService;
}
private final TabListService tabListService;
@Override
public boolean onCommand(CommandSender commandSender, String[] args) {
@@ -44,6 +44,7 @@ public class Register extends SubCommand {
playerToRegister.sendRichMessage(Messages.REGISTER.FAILED_TO_REGISTER_YOU);
} else {
notifyRegisteredPlayer(playerToRegister, nullablePlayerState);
tabListService.updatePlayerColor(playerToRegister);
}
if (commandSender instanceof Player commandPlayer) {
@@ -3,10 +3,12 @@ package com.alttd.hunger_games.commands.subcommands;
import com.alttd.hunger_games.commands.SubCommand;
import com.alttd.hunger_games.config.Messages;
import com.alttd.hunger_games.data_objects.ROUND_STATE;
import com.alttd.hunger_games.services.PlayerService;
import com.alttd.hunger_games.services.Round;
import com.alttd.hunger_games.services.RoundService;
import lombok.RequiredArgsConstructor;
import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder;
import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender;
import java.util.List;
@@ -16,11 +18,15 @@ public class StartRound extends SubCommand {
private final Round round;
private final RoundService roundService;
private final PlayerService playerService;
@Override
public boolean onCommand(CommandSender commandSender, String[] args) {
ROUND_STATE roundState = roundService.getRoundState();
if (roundState == ROUND_STATE.PLAYER_REGISTRATION) {
if (roundState == ROUND_STATE.PLAYER_REGISTRATION || roundState == ROUND_STATE.ENDED) {
Bukkit.getOnlinePlayers().stream()
.filter(player -> !player.hasPermission("hungergames.auto-join-bypass"))
.forEach(playerService::registerPlayer);
round.startRound();
} else {
commandSender.sendRichMessage(Messages.START_ROUND.CAN_NOT_START_ROUND,
@@ -40,6 +40,7 @@ public class Config extends AbstractConfig {
public static class ROUND {
private static final String prefix = "round.";
public static String HG_WORLD = "world";
public static Duration COUNTDOWN = Duration.ofSeconds(10);
public static Duration SAFE_PHASE = Duration.ofSeconds(30);
public static Duration TIME_TO_FINALE = Duration.ofMinutes(5);
@@ -54,6 +55,7 @@ public class Config extends AbstractConfig {
@SuppressWarnings("unused")
private static void load() {
HG_WORLD = config.getString(prefix, "hg-world", HG_WORLD);
int countdownSeconds = config.getInt(prefix, "countdown-seconds", Math.toIntExact(COUNTDOWN.toSeconds()));
COUNTDOWN = Duration.ofSeconds(countdownSeconds);
int safePhaseSeconds = config.getInt(prefix, "safe-phase-seconds", Math.toIntExact(SAFE_PHASE.toSeconds()));
@@ -33,6 +33,7 @@ public class Messages extends AbstractConfig {
public static String RELOAD = "<green>Reload config and messages: <gold>/hg reload</gold></green>";
public static String STUCK = "<green>Teleport to safety if stuck: <gold>/hg stuck</gold></green>";
public static String STATS = "<green>Show player stats: <gold>/hg stats [player]</gold></green>";
public static String LIST = "<green>List all players in the game and spectators: <gold>/hg list</gold></green>";
public static String END_ROUND = "<green>End the game: <gold>/hg end</gold></green>";
@SuppressWarnings("unused")
@@ -46,6 +47,7 @@ public class Messages extends AbstractConfig {
RELOAD = config.getString(prefix, "reload", RELOAD);
STUCK = config.getString(prefix, "stuck", STUCK);
STATS = config.getString(prefix, "stats", STATS);
LIST = config.getString(prefix, "list", LIST);
END_ROUND = config.getString(prefix, "end-round", END_ROUND);
}
}
@@ -89,6 +91,7 @@ public class Messages extends AbstractConfig {
public static String CHEST_EMPTY = "<red>This chest is empty!</red>";
public static String WINNER = "<gold><player> has won the Hunger Games!</gold>";
public static String PLAYER_DEATH = "<red><player> has died! <gold><remaining></gold> players remaining.</red>";
public static String PLAYER_KILLED = "<red><victim> was killed by <killer>! <gold><remaining></gold> players remaining.</red>";
public static String BOSSBAR_COUNTDOWN = "<gold>Loot phase in <time></gold>";
public static String BOSSBAR_PVP_COUNTDOWN = "<green>PVP starts in <time></green>";
@@ -106,6 +109,7 @@ public class Messages extends AbstractConfig {
CHEST_EMPTY = config.getString(prefix, "chest-empty", CHEST_EMPTY);
WINNER = config.getString(prefix, "winner", WINNER);
PLAYER_DEATH = config.getString(prefix, "player-death", PLAYER_DEATH);
PLAYER_KILLED = config.getString(prefix, "player-killed", PLAYER_KILLED);
BOSSBAR_COUNTDOWN = config.getString(prefix, "bossbar-countdown", BOSSBAR_COUNTDOWN);
BOSSBAR_PVP_COUNTDOWN = config.getString(prefix, "bossbar-pvp-countdown", BOSSBAR_PVP_COUNTDOWN);
@@ -208,10 +212,15 @@ public class Messages extends AbstractConfig {
private static final String prefix = "commands.";
public static String NEXT_PHASE_SUCCESS = "<green>Skipping to the next phase/stage.</green>";
public static String LIST_PLAYERS = """
<gold>HungerGames Players (<in_game>/<total>):</gold>
<green>In Game: <white><in_game_players></white></green>
<yellow>Spectators: <white><spectators></white></yellow>""";
@SuppressWarnings("unused")
private static void load() {
NEXT_PHASE_SUCCESS = config.getString(prefix + "next-phase", "success", NEXT_PHASE_SUCCESS);
LIST_PLAYERS = config.getString(prefix, "list-players", LIST_PLAYERS);
}
}
}
@@ -4,22 +4,47 @@ import com.alttd.hunger_games.data_objects.ROUND_STATE;
import com.alttd.hunger_games.services.RoundService;
import lombok.RequiredArgsConstructor;
import org.bukkit.entity.Item;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.entity.EntityDeathEvent;
import org.bukkit.event.entity.ItemSpawnEvent;
import org.bukkit.event.player.PlayerDropItemEvent;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
@RequiredArgsConstructor
public class ItemSpawnListener implements Listener {
private final RoundService roundService;
private final Set<UUID> deathDrops = new HashSet<>();
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
public void onItemSpawn(ItemSpawnEvent event) {
if (deathDrops.remove(event.getEntity().getUniqueId())) {
event.getEntity().setTicksLived(5400); // 300 seconds total - 5400 ticks = 30 seconds left
return;
}
setDespawnDelay(event.getEntity());
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onPlayerDeath(EntityDeathEvent event) {
if (!(event.getEntity() instanceof Player)) {
return;
}
ROUND_STATE roundState = roundService.getRoundState();
if (roundState == ROUND_STATE.SAFE_PHASE || roundState == ROUND_STATE.KILL_PHASE || roundState == ROUND_STATE.FINALE) {
event.getDrops().forEach(itemStack -> {
Item item = event.getEntity().getWorld().dropItemNaturally(event.getEntity().getLocation(), itemStack);
deathDrops.add(item.getUniqueId());
});
}
}
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
public void onPlayerDropItem(PlayerDropItemEvent event) {
setDespawnDelay(event.getItemDrop());
@@ -45,8 +45,6 @@ public class PlayerDamageListener implements Listener {
Player player = event.getPlayer();
event.setShowDeathMessages(false);
event.deathMessage(null);
event.getDrops().clear();
player.getInventory().clear();
playerService.handlePlayerDeath(player);
statService.addDeath(player.getUniqueId());
@@ -1,18 +1,33 @@
package com.alttd.hunger_games.event_listeners;
import com.alttd.hunger_games.services.PlayerService;
import com.alttd.hunger_games.services.TabListService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.bukkit.Bukkit;
import org.bukkit.command.CommandException;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerJoinEvent;
@Slf4j
@RequiredArgsConstructor
public class PlayerJoinListener implements Listener {
private final PlayerService playerService;
private final TabListService tabListService;
@EventHandler
public void onPlayerJoin(PlayerJoinEvent event) {
playerService.handleJoin(event.getPlayer());
Player player = event.getPlayer();
playerService.handleJoin(player);
tabListService.updatePlayerColor(player);
try {
Bukkit.dispatchCommand(Bukkit.getConsoleSender(),
String.format("lp user %s permission settemp cmi.kit.hunger-games true 7d", player.getName()));
} catch (CommandException e) {
log.error("Failed to set participant permission for {}", player.getName(), e);
}
}
}
@@ -66,6 +66,10 @@ public class BossBarService implements RoundListener {
}
private void updateBossBarColor(ROUND_STATE state) {
if (state == ROUND_STATE.ENDED || state == ROUND_STATE.PLAYER_REGISTRATION) {
hideAll();
return;
}
switch (state) {
case COUNTDOWN -> bossBar.color(BossBar.Color.YELLOW);
case SAFE_PHASE -> bossBar.color(BossBar.Color.GREEN);
@@ -92,27 +96,20 @@ public class BossBarService implements RoundListener {
}
private void updateViewers() {
Set<UUID> registeredPlayers = roundService.getPlayers(PLAYER_STATE.REGISTERED);
if (roundService.getRoundState() == ROUND_STATE.ENDED || roundService.getRoundState() == ROUND_STATE.PLAYER_REGISTRATION) {
hideAll();
return;
}
Bukkit.getOnlinePlayers().forEach(player -> {
if (viewers.add(player.getUniqueId())) {
player.showBossBar(bossBar);
}
});
// Add new viewers
registeredPlayers.stream()
.filter(viewers::add)
.map(Bukkit::getPlayer)
.filter(Objects::nonNull)
.forEach(player -> player.showBossBar(bossBar));
// Remove old viewers
Set<UUID> toRemove = viewers.stream()
.filter(uuid -> !registeredPlayers.contains(uuid))
.collect(Collectors.toSet());
for (UUID uuid : toRemove) {
viewers.remove(uuid);
viewers.removeIf(uuid -> {
Player player = Bukkit.getPlayer(uuid);
if (player != null) {
player.hideBossBar(bossBar);
}
}
return player == null || !player.isOnline();
});
}
private void hideAll() {
@@ -91,6 +91,7 @@ public class PlayerService implements RoundListener {
}
public void handleDisconnect(Player player) {
player.playerListName(null);
UUID uuid = player.getUniqueId();
roundService.setPlayerState(uuid, PLAYER_STATE.DISCONNECTED);
}
@@ -113,10 +114,18 @@ public class PlayerService implements RoundListener {
roundService.setPlayerState(uuid, PLAYER_STATE.SPECTATING);
int remaining = roundService.getPlayers(PLAYER_STATE.REGISTERED).size();
Player killer = player.getKiller();
if (killer != null) {
Bukkit.broadcast(MiniMessage.miniMessage().deserialize(Messages.GAME.PLAYER_KILLED,
Placeholder.component("victim", player.name()),
Placeholder.component("killer", killer.name()),
Placeholder.unparsed("remaining", String.valueOf(remaining))));
} else {
Bukkit.broadcast(MiniMessage.miniMessage().deserialize(Messages.GAME.PLAYER_DEATH,
Placeholder.component("player", player.name()),
Placeholder.unparsed("remaining", String.valueOf(remaining))));
}
}
public void handlePlayerRespawn(PlayerRespawnEvent event) {
Location spectatorArea = playerTeleporterService.getLocationFromDestination(DESTINATION.SPECTATOR_AREA);
@@ -131,13 +140,18 @@ public class PlayerService implements RoundListener {
if (optionalPlayerState.isPresent()) {
PLAYER_STATE playerState = optionalPlayerState.get();
return Optional.of(switch (playerState) {
case DISCONNECTED, SPECTATING -> PLAYER_STATE.SPECTATING;
case DISCONNECTED, SPECTATING -> {
if (roundState.equals(ROUND_STATE.ENDED)) {
yield PLAYER_STATE.REGISTERED;
}
yield PLAYER_STATE.SPECTATING;
}
case REGISTERED -> PLAYER_STATE.REGISTERED;
});
}
return switch (roundState) {
case PLAYER_REGISTRATION, COUNTDOWN -> Optional.of(PLAYER_STATE.REGISTERED);
case KILL_PHASE, FINALE, ENDED, SAFE_PHASE -> Optional.of(PLAYER_STATE.SPECTATING);
case PLAYER_REGISTRATION, COUNTDOWN, ENDED -> Optional.of(PLAYER_STATE.REGISTERED);
case KILL_PHASE, FINALE, SAFE_PHASE -> Optional.of(PLAYER_STATE.SPECTATING);
};
}
}
@@ -77,7 +77,7 @@ public class Round {
}
public void startRound() {
if (!roundState.equals(ROUND_STATE.PLAYER_REGISTRATION)) {
if (!roundState.equals(ROUND_STATE.PLAYER_REGISTRATION) && !roundState.equals(ROUND_STATE.ENDED)) {
throw new IllegalStateException("Round can not be started before player registration.");
}
roundState = ROUND_STATE.COUNTDOWN;
@@ -15,6 +15,8 @@ import net.kyori.adventure.text.minimessage.MiniMessage;
import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder;
import org.bukkit.Bukkit;
import org.bukkit.GameMode;
import org.bukkit.World;
import org.bukkit.entity.Item;
import org.bukkit.entity.Player;
import org.bukkit.event.HandlerList;
@@ -38,6 +40,8 @@ public class RoundService implements RoundListener {
private final Round round;
@Setter
private BossBarService bossBarService;
@Setter
private TabListService tabListService;
public static RoundService createSingletonInstance(Round round, Main main, LootService lootService, StatService statService, PlayerTeleporterService playerTeleporterService) {
if (instance != null) {
@@ -73,6 +77,13 @@ public class RoundService implements RoundListener {
}
}
if (tabListService != null) {
Player player = Bukkit.getPlayer(uuid);
if (player != null) {
tabListService.updatePlayerColor(player);
}
}
if (!roundState.equals(ROUND_STATE.KILL_PHASE) && !roundState.equals(ROUND_STATE.FINALE)) {
return;
}
@@ -117,7 +128,10 @@ public class RoundService implements RoundListener {
public void stateChange(ROUND_STATE roundState) {
this.roundState = roundState;
stopFreeze();
if (roundState.equals(ROUND_STATE.PLAYER_REGISTRATION)) {
if (roundState.equals(ROUND_STATE.PLAYER_REGISTRATION) || roundState.equals(ROUND_STATE.ENDED)) {
if (roundState.equals(ROUND_STATE.ENDED)) {
cleanupItems();
}
clear();
lootService.clear();
}
@@ -137,7 +151,7 @@ public class RoundService implements RoundListener {
WorldBorderUtil.resetBorder();
}
if (roundState.equals(ROUND_STATE.FINALE)) {
WorldBorderUtil.setSize(Config.ROUND.FINALE_BORDER_SIZE);
WorldBorderUtil.setSize(Config.ROUND.FINALE_BORDER_SIZE, 1);
}
if (!roundState.equals(ROUND_STATE.ENDED) && !roundState.equals(ROUND_STATE.PLAYER_REGISTRATION)) {
Bukkit.broadcast(MiniMessage.miniMessage().deserialize(Messages.GAME.NEXT_STATE, Placeholder.parsed("round", roundState.getHumanReadableName())));
@@ -159,4 +173,13 @@ public class RoundService implements RoundListener {
main.getServer().getPluginManager().registerEvents(playerMovementListener, main);
}
private void cleanupItems() {
World world = Bukkit.getWorld(Config.ROUND.HG_WORLD);
if (world == null) {
log.error("Unable to cleanup items, world {} not found", Config.ROUND.HG_WORLD);
return;
}
world.getEntitiesByClass(Item.class).forEach(Item::remove);
}
}
@@ -45,7 +45,7 @@ public class StatService implements RoundListener {
@Override
public void stateChange(ROUND_STATE roundState) {
if (roundState.equals(ROUND_STATE.FINALE)) {
if (roundState.equals(ROUND_STATE.ENDED)) {
saveRoundStats();
}
if (roundState.equals(ROUND_STATE.PLAYER_REGISTRATION)) {
@@ -0,0 +1,46 @@
package com.alttd.hunger_games.services;
import com.alttd.hunger_games.data_objects.PLAYER_STATE;
import com.alttd.hunger_games.data_objects.ROUND_STATE;
import net.kyori.adventure.text.format.NamedTextColor;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import java.util.UUID;
public class TabListService implements RoundListener {
private final RoundService roundService;
private ROUND_STATE roundState;
public TabListService(Round round, RoundService roundService) {
this.roundService = roundService;
this.roundState = round.register(this);
}
public void updatePlayerColor(Player player) {
if (!player.isOnline()) {
return;
}
if (roundState == null || roundState == ROUND_STATE.ENDED || roundState == ROUND_STATE.PLAYER_REGISTRATION) {
player.playerListName(null);
return;
}
PLAYER_STATE state = roundService.getPlayerState(player.getUniqueId()).orElse(PLAYER_STATE.SPECTATING);
switch (state) {
case REGISTERED -> player.playerListName(player.name().color(NamedTextColor.GREEN));
case SPECTATING, DISCONNECTED -> player.playerListName(player.name().color(NamedTextColor.RED));
}
}
public void updateAllPlayers() {
Bukkit.getOnlinePlayers().forEach(this::updatePlayerColor);
}
@Override
public void stateChange(ROUND_STATE roundState) {
this.roundState = roundState;
updateAllPlayers();
}
}
+4
View File
@@ -3,6 +3,10 @@ version: ${version}
main: com.alttd.hunger_games.Main
api-version: "1.21"
# Load after Multiverse-Core to be able to find the teleport locations
softdepend:
- Multiverse-Core
commands:
hungergames:
description: Main HungerGames command