1
0
Fork 0
- SnowballProjectile
 - ZombieCreature
 - About (us/game) command
 - Credits command
 - Stop command
 - Terminal
All Color phases are now working
This commit is contained in:
Andus 2024-08-13 17:51:38 +02:00
parent b82cdb3a4b
commit 90ddb82640
29 changed files with 1024 additions and 300 deletions

View file

@ -0,0 +1,10 @@
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<option name="myName" value="Project Default" />
<inspection_tool class="DuplicatedCode" enabled="true" level="WEAK WARNING" enabled_by_default="true">
<Languages>
<language minSize="50" name="Java" />
</Languages>
</inspection_tool>
</profile>
</component>

View file

@ -3,7 +3,13 @@ plugins {
alias(libs.plugins.shadowJar) alias(libs.plugins.shadowJar)
} }
group = "dev.celestialfox" tasks.withType<Jar> {
manifest {
attributes["Main-Class"] = "dev.celestialfox.spectrumsurvival.Server"
}
}
group = "dev.celestialfox.spectrumsurvival"
version = "1.0" version = "1.0"
repositories { repositories {
@ -15,6 +21,8 @@ dependencies {
implementation("dev.hollowcube:polar:1.11.1") implementation("dev.hollowcube:polar:1.11.1")
implementation("net.kyori:adventure-text-minimessage:4.17.0") implementation("net.kyori:adventure-text-minimessage:4.17.0")
implementation("org.slf4j:slf4j-api:2.0.13") implementation("org.slf4j:slf4j-api:2.0.13")
implementation("org.jline:jline-terminal:3.26.3")
implementation("org.jline:jline-reader:3.26.3")
implementation("ch.qos.logback:logback-classic:1.5.6") implementation("ch.qos.logback:logback-classic:1.5.6")
testImplementation(platform("org.junit:junit-bom:5.9.1")) testImplementation(platform("org.junit:junit-bom:5.9.1"))
testImplementation("org.junit.jupiter:junit-jupiter") testImplementation("org.junit.jupiter:junit-jupiter")

View file

@ -1,10 +1,10 @@
package dev.cfox.gamejam; package dev.celestialfox.spectrumsurvival;
import dev.cfox.gamejam.game.commands.QueueCommand; import dev.celestialfox.spectrumsurvival.game.commands.*;
import dev.cfox.gamejam.utils.config.Checks; import dev.celestialfox.spectrumsurvival.utils.config.Checks;
import dev.cfox.gamejam.utils.config.Settings; import dev.celestialfox.spectrumsurvival.utils.config.Settings;
import dev.cfox.gamejam.utils.events.MiscEvents; import dev.celestialfox.spectrumsurvival.utils.events.MiscEvents;
import dev.cfox.gamejam.utils.events.StartEvents; import dev.celestialfox.spectrumsurvival.utils.events.StartEvents;
import net.minestom.server.MinecraftServer; import net.minestom.server.MinecraftServer;
import net.minestom.server.command.CommandManager; import net.minestom.server.command.CommandManager;
import org.slf4j.Logger; import org.slf4j.Logger;
@ -32,6 +32,8 @@ public class Server {
MiscEvents.register(); MiscEvents.register();
registerCommands(); registerCommands();
Terminal.start();
// Server Start // Server Start
server.start(Settings.getIP(), Settings.getPort()); server.start(Settings.getIP(), Settings.getPort());
logger.info("Server Started at " + Settings.getIP() + ":" + Settings.getPort() + " (MC: " + MinecraftServer.VERSION_NAME + ")"); logger.info("Server Started at " + Settings.getIP() + ":" + Settings.getPort() + " (MC: " + MinecraftServer.VERSION_NAME + ")");
@ -40,5 +42,8 @@ public class Server {
public static void registerCommands() { public static void registerCommands() {
CommandManager commandManager = MinecraftServer.getCommandManager(); CommandManager commandManager = MinecraftServer.getCommandManager();
commandManager.register(new QueueCommand()); commandManager.register(new QueueCommand());
commandManager.register(new AboutCommand());
commandManager.register(new CreditsCommand());
commandManager.register(new StopCommand());
} }
} }

View file

@ -1,10 +1,9 @@
package dev.cfox.gamejam.game.classes; package dev.celestialfox.spectrumsurvival.game.classes;
import dev.cfox.gamejam.game.managers.GameManager; import dev.celestialfox.spectrumsurvival.game.managers.GameManager;
import dev.cfox.gamejam.game.managers.QueueManager; import dev.celestialfox.spectrumsurvival.game.phases.Phase;
import dev.cfox.gamejam.game.phases.Phase; import dev.celestialfox.spectrumsurvival.utils.Misc;
import dev.cfox.gamejam.utils.Misc; import dev.celestialfox.spectrumsurvival.utils.classes.Randomized;
import dev.cfox.gamejam.utils.classes.Randomized;
import net.kyori.adventure.sound.Sound; import net.kyori.adventure.sound.Sound;
import net.kyori.adventure.text.Component; import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor; import net.kyori.adventure.text.format.NamedTextColor;
@ -87,10 +86,16 @@ public class GameLobby {
} }
} }
public void setInstance(Instance instance) {
this.instance = instance;
players.forEach(uuid ->
Misc.getPlayer(uuid).setInstance(instance));
}
public void setInstance(Instance instance, Pos pos) { public void setInstance(Instance instance, Pos pos) {
this.instance = instance; this.instance = instance;
players.forEach(uuid -> players.forEach(uuid ->
Misc.getPlayer(uuid).setInstance(instance).thenRun(() -> Misc.getPlayer(uuid).teleport(pos))); Misc.getPlayer(uuid).setInstance(instance, pos));
} }
public Instance getInstance() { public Instance getInstance() {
return instance; return instance;

View file

@ -1,14 +1,12 @@
package dev.cfox.gamejam.game.classes; package dev.celestialfox.spectrumsurvival.game.classes;
import dev.cfox.gamejam.game.managers.QueueManager; import dev.celestialfox.spectrumsurvival.game.managers.QueueManager;
import dev.cfox.gamejam.utils.Misc; import dev.celestialfox.spectrumsurvival.utils.Misc;
import net.kyori.adventure.text.Component; import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor; import net.kyori.adventure.text.format.NamedTextColor;
import net.minestom.server.MinecraftServer;
import net.minestom.server.entity.GameMode; import net.minestom.server.entity.GameMode;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Objects;
import java.util.UUID; import java.util.UUID;
public class GameQueue { public class GameQueue {
@ -27,7 +25,7 @@ public class GameQueue {
public void removePlayer(UUID uuid) { public void removePlayer(UUID uuid) {
if (players.contains(uuid)) { if (players.contains(uuid)) {
players.remove(uuid); players.remove(uuid);
Misc.getPlayer(uuid).setGameMode(GameMode.SURVIVAL); Misc.getPlayer(uuid).setGameMode(GameMode.ADVENTURE);
Misc.getPlayer(uuid).sendMessage(Component.text("You have left the queue", NamedTextColor.RED)); Misc.getPlayer(uuid).sendMessage(Component.text("You have left the queue", NamedTextColor.RED));
} }
} }

View file

@ -0,0 +1,11 @@
package dev.celestialfox.spectrumsurvival.game.classes;
import net.minestom.server.entity.Entity;
import net.minestom.server.entity.EntityType;
import net.minestom.server.entity.PlayerProjectile;
public class SnowballProjectile extends PlayerProjectile {
public SnowballProjectile(Entity shooter) {
super(shooter, EntityType.SNOWBALL);
}
}

View file

@ -0,0 +1,31 @@
package dev.celestialfox.spectrumsurvival.game.classes;
import net.minestom.server.entity.EntityCreature;
import net.minestom.server.entity.EntityType;
import net.minestom.server.entity.GameMode;
import net.minestom.server.entity.Player;
import net.minestom.server.entity.ai.goal.MeleeAttackGoal;
import net.minestom.server.entity.ai.target.ClosestEntityTarget;
import net.minestom.server.entity.attribute.Attribute;
import net.minestom.server.utils.time.TimeUnit;
import java.util.List;
public class ZombieCreature extends EntityCreature {
public ZombieCreature() {
super(EntityType.ZOMBIE);
getAttribute(Attribute.GENERIC_MOVEMENT_SPEED).setBaseValue(0.15);
addAIGroup(
List.of(
new MeleeAttackGoal(this, 1.6, 20, TimeUnit.SERVER_TICK) // Attack the target
),
List.of(
new ClosestEntityTarget(this, 50,
entity -> entity instanceof Player && ((Player) entity).getGameMode() != GameMode.SPECTATOR) // Target the nearest player
)
);
}
}

View file

@ -0,0 +1,43 @@
package dev.celestialfox.spectrumsurvival.game.commands;
import dev.celestialfox.spectrumsurvival.game.managers.GameManager;
import dev.celestialfox.spectrumsurvival.game.managers.QueueManager;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.event.ClickEvent;
import net.kyori.adventure.text.format.NamedTextColor;
import net.kyori.adventure.text.format.TextDecoration;
import net.minestom.server.command.builder.Command;
import net.minestom.server.command.builder.arguments.ArgumentType;
import net.minestom.server.entity.Player;
public class AboutCommand extends Command {
public AboutCommand() {
super("about");
addSyntax(((sender, context) -> {
final String arg1 = context.get("arg1");
if (sender instanceof Player player) {
if (arg1.equals("us")) {
player.sendMessage(
Component.text("\n§lAbout CelestialFox Studio\n", NamedTextColor.GOLD)
.append(Component.text("We are a passionate indie game studio creating unique experiences.\n", NamedTextColor.YELLOW))
.append(Component.text("Want to know more? Check our website: ", NamedTextColor.YELLOW))
.append(Component.text("https://celestial-fox.com/", NamedTextColor.LIGHT_PURPLE, TextDecoration.UNDERLINED)
.clickEvent(ClickEvent.openUrl("https://celestial-fox.com/")))
);
} else if (arg1.equals("game")) {
player.sendMessage(
Component.text("\n§lAbout Spectrum Survival\n", NamedTextColor.DARK_AQUA)
.append(Component.text("Dive into Spectrum Survival, where each color phase brings a new challenge! Every 30 seconds, the color changes, creating a chaotic 3-minute survival test.\n\n", NamedTextColor.AQUA))
.append(Component.text("§lColor Phases:\n", NamedTextColor.LIGHT_PURPLE))
.append(Component.text("- §lRed: §cFlames spread across the map. Avoid getting burned!\n", NamedTextColor.RED))
.append(Component.text("- §lBlue: §9Snowball fight frenzy! Knock back your foes.\n", NamedTextColor.BLUE))
.append(Component.text("- §lGreen: §aWatch out for wither roses and zombies. Roses hurt, zombies eliminate instantly.\n", NamedTextColor.GREEN))
.append(Component.text("- §lYellow: §eDodge lightning or be struck! §8§o(You can punch players into the lightning)\n", NamedTextColor.YELLOW))
.append(Component.text("- §lGray: §7Darkness falls, pvp enabled. Fight to survive!\n", NamedTextColor.GRAY))
.append(Component.text("\nSurvive all phases and adapt to win! Good luck!", NamedTextColor.AQUA))
);
}
}
}), ArgumentType.String("arg1"));
}
}

View file

@ -0,0 +1,39 @@
package dev.celestialfox.spectrumsurvival.game.commands;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.ComponentBuilder;
import net.kyori.adventure.text.TextComponent;
import net.kyori.adventure.text.format.NamedTextColor;
import net.minestom.server.command.builder.Command;
import net.minestom.server.entity.Player;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class CreditsCommand extends Command {
public CreditsCommand() {
super("credits");
addSyntax(((sender, context) -> {
if (sender instanceof Player player) {
player.sendMessage(generateCredits());
}
}));
}
private static Component generateCredits() {
ComponentBuilder<TextComponent, TextComponent.Builder> messageBuilder = Component.text().content("\n§lCredits\n").color(NamedTextColor.GOLD);
messageBuilder.append(Component.text("- §lDeveloper: §eAndus\n", NamedTextColor.YELLOW));
messageBuilder.append(Component.text("- §lIdeas: §7" + randomizeNames(List.of("Andus", "LucePric", "xnlx0000")) + "\n", NamedTextColor.GRAY));
messageBuilder.append(Component.text("- §lMaps: §e" + randomizeNames(List.of("LucePric", "Bali__0", "GummyW0rm", "xnlx0000")) + "\n", NamedTextColor.YELLOW));
return messageBuilder.build();
}
private static String randomizeNames(List<String> names) {
List<String> shuffledNames = new ArrayList<>(names);
Collections.shuffle(shuffledNames);
return String.join(", ", shuffledNames);
}
}

View file

@ -0,0 +1,38 @@
package dev.celestialfox.spectrumsurvival.game.commands;
import dev.celestialfox.spectrumsurvival.game.managers.GameManager;
import dev.celestialfox.spectrumsurvival.game.managers.QueueManager;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import net.minestom.server.command.builder.Command;
import net.minestom.server.command.builder.arguments.ArgumentType;
import net.minestom.server.entity.GameMode;
import net.minestom.server.entity.Player;
import net.minestom.server.item.ItemStack;
import net.minestom.server.item.Material;
import net.minestom.server.potion.Potion;
import net.minestom.server.potion.PotionEffect;
public class QueueCommand extends Command {
public QueueCommand() {
super("queue", "q");
addSyntax(((sender, context) -> {
final String arg1 = context.get("arg1");
if (sender instanceof Player player) {
if (arg1.equals("join")) {
QueueManager.joinPlayer(player);
} else if (arg1.equals("leave")) {
QueueManager.removePlayer(player);
} else if (arg1.equals("force")) {
if (QueueManager.getPlayerQueue(player) != null) {
GameManager.startGame(QueueManager.getPlayerQueue(player));
} else {
player.sendMessage(Component.text("You're not in a queue!", NamedTextColor.RED));
}
} else if (arg1.equals("a")) {
player.getInventory().addItemStack(ItemStack.of(Material.SNOWBALL, 16));
}
}
}), ArgumentType.String("arg1"));
}
}

View file

@ -0,0 +1,18 @@
package dev.celestialfox.spectrumsurvival.game.commands;
import net.minestom.server.MinecraftServer;
import net.minestom.server.command.builder.Command;
import net.minestom.server.entity.Player;
public class StopCommand extends Command {
public StopCommand() {
super("stop");
addSyntax(((sender, context) -> {
if (sender instanceof Player player) {
player.sendMessage("No.");
} else {
MinecraftServer.stopCleanly();
}
}));
}
}

View file

@ -0,0 +1,84 @@
package dev.celestialfox.spectrumsurvival.game.commands;
import dev.celestialfox.spectrumsurvival.Server;
import net.minestom.server.MinecraftServer;
import net.minestom.server.command.builder.Command;
import net.minestom.server.command.builder.suggestion.Suggestion;
import net.minestom.server.command.builder.suggestion.SuggestionEntry;
import net.minestom.server.listener.TabCompleteListener;
import org.jetbrains.annotations.ApiStatus;
import org.jline.reader.*;
import org.jline.terminal.TerminalBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.util.List;
public class Terminal {
private static final String PROMPT = "> ";
private static volatile org.jline.terminal.Terminal terminal;
static volatile LineReader reader;
private static volatile boolean running = false;
private static final Logger logger = LoggerFactory.getLogger(Terminal.class);
@ApiStatus.Internal
public static void start() {
final Thread thread = new Thread(null, () -> {
try {
terminal = TerminalBuilder.terminal();
} catch (IOException e) {
logger.error(e.getMessage());
}
reader = LineReaderBuilder.builder()
.completer(new MinestomCompleter())
.terminal(terminal)
.build();
running = true;
while (running) {
String command;
try {
command = reader.readLine(PROMPT);
var commandManager = MinecraftServer.getCommandManager();
commandManager.execute(commandManager.getConsoleSender(), command);
} catch (UserInterruptException e) {
// Handle Ctrl + C
System.exit(0);
return;
} catch (EndOfFileException e) {
return;
}
}
}, "Jline");
thread.setDaemon(true);
thread.start();
}
private static final class MinestomCompleter implements Completer {
@Override
public void complete(LineReader reader, ParsedLine line, List<Candidate> candidates) {
final var commandManager = MinecraftServer.getCommandManager();
final var consoleSender = commandManager.getConsoleSender();
if (line.wordIndex() == 0) {
final String commandString = line.word().toLowerCase();
candidates.addAll(
commandManager.getDispatcher().getCommands().stream()
.map(Command::getName)
.filter(name -> commandString.isBlank() || name.toLowerCase().startsWith(commandString))
.map(Candidate::new)
.toList()
);
} else {
final String text = line.line();
final Suggestion suggestion = TabCompleteListener.getSuggestion(consoleSender, text);
if (suggestion != null) {
suggestion.getEntries().stream()
.map(SuggestionEntry::getEntry)
.map(Candidate::new)
.forEach(candidates::add);
}
}
}
}
}

View file

@ -1,10 +1,12 @@
package dev.cfox.gamejam.game.managers; package dev.celestialfox.spectrumsurvival.game.managers;
import dev.cfox.gamejam.game.classes.GameLobby; import dev.celestialfox.spectrumsurvival.game.classes.GameLobby;
import dev.cfox.gamejam.game.classes.GameQueue; import dev.celestialfox.spectrumsurvival.game.classes.GameQueue;
import dev.celestialfox.spectrumsurvival.utils.Misc;
import net.kyori.adventure.text.Component; import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor; import net.kyori.adventure.text.format.NamedTextColor;
import net.minestom.server.coordinate.Pos; import net.minestom.server.coordinate.Pos;
import net.minestom.server.entity.GameMode;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -27,7 +29,12 @@ public class ConversionManager {
logger.debug("GameLobby removed: " + game.getName()); logger.debug("GameLobby removed: " + game.getName());
game.sendMessage(Component.text("Game ended!", NamedTextColor.RED)); game.sendMessage(Component.text("Game ended!", NamedTextColor.RED));
game.setInstance(QueueManager.lobbyInstance, new Pos(0, 60, 0, 180, 0)); game.setInstance(QueueManager.lobbyInstance, new Pos(0, 66, 0, 180, 0));
game.getPlayers().forEach(uuid -> {
Misc.getPlayer(uuid).setGameMode(GameMode.ADVENTURE);
Misc.getPlayer(uuid).setHealth(20);
});
GameManager.sendEndTitles(game);
GameManager.gameLobbies.remove(game.getName()); GameManager.gameLobbies.remove(game.getName());
} }
} }

View file

@ -1,10 +1,9 @@
package dev.cfox.gamejam.game.managers; package dev.celestialfox.spectrumsurvival.game.managers;
import dev.cfox.gamejam.game.classes.GameLobby; import dev.celestialfox.spectrumsurvival.game.phases.PhaseLogic;
import dev.cfox.gamejam.game.classes.GameQueue; import dev.celestialfox.spectrumsurvival.utils.Misc;
import dev.cfox.gamejam.game.phases.PhaseLogic; import dev.celestialfox.spectrumsurvival.game.classes.GameLobby;
import dev.cfox.gamejam.utils.Misc; import dev.celestialfox.spectrumsurvival.game.classes.GameQueue;
import dev.cfox.gamejam.utils.events.StartEvents;
import net.hollowcube.polar.PolarLoader; import net.hollowcube.polar.PolarLoader;
import net.kyori.adventure.text.Component; import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor; import net.kyori.adventure.text.format.NamedTextColor;
@ -60,7 +59,7 @@ public class GameManager {
} }
public static void startGame(GameLobby game) { public static void startGame(GameLobby game) {
logger.debug("Creating Lobby Instance"); logger.debug("Creating Game Instance");
InstanceManager instanceManager = MinecraftServer.getInstanceManager(); InstanceManager instanceManager = MinecraftServer.getInstanceManager();
InstanceContainer instanceContainer = instanceManager.createInstanceContainer(); InstanceContainer instanceContainer = instanceManager.createInstanceContainer();
try { try {
@ -83,10 +82,10 @@ public class GameManager {
for (Player player : instance.getPlayers()) { for (Player player : instance.getPlayers()) {
if (eliminated.contains(player.getUuid())) { if (eliminated.contains(player.getUuid())) {
player.showTitle(Title.title(Component.text("Eliminated!", NamedTextColor.RED, TextDecoration.BOLD), Component.text(""))); player.showTitle(Title.title(Component.text("You Lost.", NamedTextColor.RED, TextDecoration.BOLD), Component.text("")));
} else { } else {
// Player is a winner if they were not eliminated // Player is a winner if they were not eliminated
player.showTitle(Title.title(Component.text("Qualified!", NamedTextColor.GREEN, TextDecoration.BOLD), Component.text(""))); player.showTitle(Title.title(Component.text("You Win!", NamedTextColor.GREEN, TextDecoration.BOLD), Component.text("")));
winners.add(player.getUsername()); winners.add(player.getUsername());
} }
} }

View file

@ -1,7 +1,7 @@
package dev.cfox.gamejam.game.managers; package dev.celestialfox.spectrumsurvival.game.managers;
import dev.cfox.gamejam.game.classes.GameQueue; import dev.celestialfox.spectrumsurvival.utils.Misc;
import dev.cfox.gamejam.utils.Misc; import dev.celestialfox.spectrumsurvival.game.classes.GameQueue;
import net.kyori.adventure.text.Component; import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor; import net.kyori.adventure.text.format.NamedTextColor;
import net.kyori.adventure.title.Title; import net.kyori.adventure.title.Title;
@ -23,28 +23,30 @@ public class QueueManager {
public static Instance lobbyInstance; public static Instance lobbyInstance;
public static void joinPlayer(Player player) { public static void joinPlayer(Player player) {
boolean queueFound = false; if (!GameManager.isPlayerInGame(player)) {
boolean queueFound = false;
if (!queues.isEmpty()) { if (!queues.isEmpty()) {
for (GameQueue queue : queues) { for (GameQueue queue : queues) {
if (queue.getPlayers().size() < maxPlayers) { if (queue.getPlayers().size() < maxPlayers) {
queue.addPlayer(player.getUuid()); queue.addPlayer(player.getUuid());
queueFound = true; queueFound = true;
if (queue.getPlayers().size() >= minPlayers) { if (queue.getPlayers().size() >= minPlayers) {
startCountdown(queue); startCountdown(queue);
}
break;
} }
break;
} }
} }
}
if (!queueFound) { if (!queueFound) {
createQueue(player); createQueue(player);
} }
player.sendMessage(Component.text("The queue starts the countdown from §e6 players.", NamedTextColor.GRAY)); player.sendMessage(Component.text("The queue starts the countdown from §e6 players.", NamedTextColor.GRAY));
player.sendMessage(Component.text("One queue can hold up to §e10 players.", NamedTextColor.GRAY)); player.sendMessage(Component.text("One queue can hold up to §e10 players.", NamedTextColor.GRAY));
player.sendMessage(Component.text("§e§lWaiting for too long? §rUse §a/queue force §rto start now.", NamedTextColor.GRAY)); player.sendMessage(Component.text("§e§lWaiting for too long? §rUse §a/queue force §rto start now.", NamedTextColor.GRAY));
}
} }
public static void removePlayer(Player player) { public static void removePlayer(Player player) {

View file

@ -1,9 +1,9 @@
package dev.cfox.gamejam.game.phases; package dev.celestialfox.spectrumsurvival.game.phases;
public enum Phase { public enum Phase {
RED, RED,
BLUE, BLUE,
GREEN, GREEN,
YELLOW, YELLOW,
PURPLE; GRAY;
} }

View file

@ -0,0 +1,400 @@
package dev.celestialfox.spectrumsurvival.game.phases;
import dev.celestialfox.spectrumsurvival.game.classes.ZombieCreature;
import dev.celestialfox.spectrumsurvival.utils.Misc;
import dev.celestialfox.spectrumsurvival.game.classes.GameLobby;
import dev.celestialfox.spectrumsurvival.game.managers.ConversionManager;
import net.hollowcube.polar.PolarLoader;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import net.minestom.server.MinecraftServer;
import net.minestom.server.coordinate.Pos;
import net.minestom.server.entity.Entity;
import net.minestom.server.entity.EntityType;
import net.minestom.server.entity.GameMode;
import net.minestom.server.entity.Player;
import net.minestom.server.instance.InstanceContainer;
import net.minestom.server.instance.InstanceManager;
import net.minestom.server.instance.Weather;
import net.minestom.server.instance.block.Block;
import net.minestom.server.item.ItemStack;
import net.minestom.server.item.Material;
import net.minestom.server.potion.Potion;
import net.minestom.server.potion.PotionEffect;
import net.minestom.server.timer.SchedulerManager;
import net.minestom.server.timer.Task;
import net.minestom.server.timer.TaskSchedule;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.nio.file.Path;
import java.time.Duration;
import java.util.*;
public class PhaseLogic {
private static final Logger logger = LoggerFactory.getLogger(PhaseLogic.class);
private static final SchedulerManager scheduler = MinecraftServer.getSchedulerManager();
private static final int phaseDuration = 20; // in seconds
private static final int gameTime = 180; // 3 minutes in seconds
private static Task repeatTask;
private static Task endTask;
private static final int zombiesSpawn = 5;
public static void random(GameLobby game) {
if (repeatTask != null) {
repeatTask.cancel();
}
repeatTask = scheduler.buildTask(() -> {
// Check if all players are eliminated
if (game.getEliminated().size() == game.getPlayers().size()) {
ConversionManager.fromGame(game);
repeatTask.cancel();
endTask.cancel();
} else {
logger.debug("Starting random phase selection for GameLobby: {}", game.getName());
try {
Phase[] phases = Phase.values();
Phase selectedPhase;
do {
int randomIndex = new Random().nextInt(phases.length);
selectedPhase = phases[randomIndex];
} while (
(selectedPhase == game.getPhase())
|| ((selectedPhase == Phase.GRAY) && (game.getPlayers().size() == game.getEliminated().size()+1)));
game.setPhase(selectedPhase);
logger.debug("Selected phase: {} for GameLobby: {}", selectedPhase.name(), game.getName());
if (game.getTask() != null) {
game.getTask().cancel();
}
switch (selectedPhase) {
case RED -> red(game);
case BLUE -> blue(game);
case GREEN -> green(game);
case YELLOW -> yellow(game);
case GRAY -> gray(game);
}
} catch (Exception e) {
logger.error("Exception occurred during phase execution: {}", e.getMessage());
}
}
}).repeat(TaskSchedule.seconds(phaseDuration)).schedule();
endTask = scheduler.buildTask(() -> {
try {
logger.debug("Ending game for GameLobby: {}", game.getName());
ConversionManager.fromGame(game);
repeatTask.cancel();
} catch (Exception e) {
logger.error("Exception occurred during game ending: {}", e.getMessage());
}
}).delay(TaskSchedule.seconds(gameTime)).schedule();
}
public static void red(GameLobby game) {
setupPhase(game, Phase.RED, "New color picked! §cRED",
"Dodge the fire! It does damage to you.",
"Red", NamedTextColor.RED, 13000, Weather.CLEAR);
// Logic
List<Pos> positions = new ArrayList<>();
int minX = -10;
int maxX = 10;
int minZ = -10;
int maxZ = 10;
for (int x = minX; x <= maxX; x++) {
for (int z = minZ; z <= maxZ; z++) {
for (int y = 55; y < 75; y++) {
Pos pos = new Pos(x, y, z);
if (new Random().nextInt(10) < 2) {
if (isFlamableBlock(game.getInstance().getBlock(pos))) {
positions.add(pos);
}
}
}
}
}
Iterator<Pos> iterator = positions.iterator();
Task task;
task = scheduler.buildTask(() -> {
if (iterator.hasNext()) {
Pos pos = iterator.next();
game.getInstance().setBlock(pos, Block.FIRE);
}
}).repeat(Duration.ofMillis(250)).schedule();
scheduler.buildTask(() -> {
task.cancel();
resetInstance(game);
}).delay(TaskSchedule.seconds(phaseDuration-1)).schedule();
}
public static void blue(GameLobby game) {
setupPhase(game, Phase.BLUE, "New color picked! §9BLUE",
"Battle it out with snowballs! Knock back and disorient your opponents.",
"Blue", NamedTextColor.BLUE, 1000, Weather.CLEAR);
// Logic
int minX = -20;
int maxX = 20;
int minZ = -20;
int maxZ = 20;
for (int x = minX; x <= maxX; x++) {
for (int z = minZ; z <= maxZ; z++) {
for (int y = 55; y < 75; y++) {
Pos pos = new Pos(x, y, z);
Block block = game.getInstance().getBlock(pos);
if (block.compare(Block.GRASS_BLOCK) || block.compare(Block.SAND) || block.compare(Block.MOSS_BLOCK)) {
game.getInstance().setBlock(pos, Block.SNOW_BLOCK);
}
if (block.compare(Block.MOSS_CARPET) || block.compare(Block.SHORT_GRASS) || block.compare(Block.TALL_GRASS)) {
game.getInstance().setBlock(pos, Block.AIR);
}
}
}
}
// Snowball Supply
game.getPlayers().forEach(uuid -> {
Player player = Misc.getPlayer(uuid);
player.getInventory().addItemStack(ItemStack.of(Material.SNOWBALL, 64));
});
// Phase end
scheduler.buildTask(() -> {
game.getPlayers().forEach(uuid -> {
Player player = Misc.getPlayer(uuid);
player.getInventory().clear();
});
resetInstance(game);
}).delay(TaskSchedule.seconds(phaseDuration-1)).schedule();
}
public static void green(GameLobby game) {
setupPhase(game, Phase.GREEN, "New color picked! §aGREEN",
"Avoid wither roses and zombies! Wither roses deal damage, while zombies eliminate players instantly.",
"Green", NamedTextColor.GREEN, 18000, Weather.CLEAR);
// Logic
scheduler.buildTask(() -> spawnZombies(game)).delay(TaskSchedule.seconds(zombiesSpawn)).schedule();
int minX = -20;
int maxX = 20;
int minZ = -20;
int maxZ = 20;
for (int x = minX; x <= maxX; x++) {
for (int z = minZ; z <= maxZ; z++) {
for (int y = 55; y < 75; y++) {
Pos pos = new Pos(x, y, z);
Block block = game.getInstance().getBlock(pos);
if (block.compare(Block.SHORT_GRASS)) {
game.getInstance().setBlock(pos, Block.WITHER_ROSE);
}
}
}
}
}
public static void yellow(GameLobby game) {
setupPhase(game, Phase.YELLOW, "New color picked! §eYELLOW",
"Thunder is coming! Find a place to hide!",
"Yellow", NamedTextColor.YELLOW, 18000, Weather.RAIN);
// Logic
scheduler.buildTask(() -> {
Task task = scheduler.buildTask(() -> {
List<UUID> uuids = game.getPlayers();
List<Player> eligiblePlayers = new ArrayList<>();
for (UUID uuid : uuids) {
Player player = Misc.getPlayer(uuid);
if (player.getGameMode() == GameMode.ADVENTURE && !isUnderBlock(player)) {
eligiblePlayers.add(player);
}
}
if (!eligiblePlayers.isEmpty()) {
Random random = new Random();
Player randomPlayer = eligiblePlayers.get(random.nextInt(eligiblePlayers.size()));
Entity lightning = new Entity(EntityType.LIGHTNING_BOLT);
lightning.setInstance(randomPlayer.getInstance(), randomPlayer.getPosition());
lightning.spawn();
game.eliminate(randomPlayer);
} else {
Random random = new Random();
Player randomPlayer = Misc.getPlayer(uuids.get(random.nextInt(uuids.size())));
Pos playerPos = randomPlayer.getPosition();
Pos lightningPos = playerPos.add(random.nextInt(11) - 5, 0, random.nextInt(11) - 5
);
Entity lightning = new Entity(EntityType.LIGHTNING_BOLT);
lightning.setInstance(randomPlayer.getInstance(), lightningPos);
lightning.spawn();
}
}).repeat(Duration.ofSeconds(5)).schedule();
game.setTask(task);
}).delay(Duration.ofSeconds(5)).schedule();
}
public static void gray(GameLobby game) {
setupPhase(game, Phase.GRAY, "New color picked! §8GRAY",
"Darkness everywhere, PvP active. Fight everyone to survive.",
"Gray", NamedTextColor.DARK_GRAY, 18000, Weather.CLEAR);
// Logic
game.getPlayers().forEach(uuid -> {
if (Misc.getPlayer(uuid).getGameMode() == GameMode.ADVENTURE) {
Misc.getPlayer(uuid).addEffect(new Potion(PotionEffect.DARKNESS, (byte) 1, phaseDuration*20));
Misc.getPlayer(uuid).addEffect(new Potion(PotionEffect.BLINDNESS, (byte) 1, phaseDuration*20));
}
});
scheduler.buildTask(() -> {
startHealthRegeneration(game);
}).delay(TaskSchedule.seconds(phaseDuration)).schedule();
}
public static void setupPhase(GameLobby game, Phase phase, String colorPicked, String desc,
String colorText, NamedTextColor color, int time, Weather weather) {
game.setPhase(phase);
game.sendMessage(Component.text(colorPicked, NamedTextColor.GRAY));
game.sendMessage(Component.text(desc, color));
Misc.showTitle(game.getInstance(), Component.text("", color), Component.text(colorText, color));
long currentGameTime = game.getInstance().getTime();
if (time != currentGameTime) {
Misc.transitionToTime(game, Duration.ofSeconds(2), currentGameTime, time);
}
game.getInstance().setWeather(weather);
}
private static boolean isUnderBlock(Player player) {
Pos playerPosition = player.getPosition();
for (int i = 1; i <= 5; i++) {
Pos posAbove = playerPosition.add(0, i, 0);
Block blockAbove = player.getInstance().getBlock(posAbove);
if (blockAbove.isSolid()) {
return true;
}
}
return false;
}
private static void spawnZombies(GameLobby game) {
List<Pos> spawnLocations = Arrays.asList(
new Pos(8, 65, 15),
new Pos(-15, 67, 7),
new Pos(11, 66, -12),
new Pos(18, 64, 3)
);
Collections.shuffle(spawnLocations);
int numZombiesToSpawn = Math.min(3, spawnLocations.size());
for (int i = 0; i < numZombiesToSpawn; i++) {
Pos pos = spawnLocations.get(i);
Entity zombie = new ZombieCreature();
zombie.setInstance(game.getInstance(), pos);
zombie.spawn();
}
scheduler.buildTask(() -> endGreen(game))
.delay(TaskSchedule.seconds(phaseDuration - zombiesSpawn))
.schedule();
}
private static void endGreen(GameLobby game) {
for (Entity entity : game.getInstance().getEntities()) {
if (entity.getEntityType() == EntityType.ZOMBIE) {
entity.remove();
}
}
int minX = -100;
int maxX = 100;
int minZ = -100;
int maxZ = 100;
for (int x = minX; x <= maxX; x++) {
for (int z = minZ; z <= maxZ; z++) {
for (int y = 55; y < 75; y++) {
Pos pos = new Pos(x, y, z);
Block block = game.getInstance().getBlock(pos);
if (block.compare(Block.WITHER_ROSE)) {
game.getInstance().setBlock(pos, Block.SHORT_GRASS);
}
}
}
}
startHealthRegeneration(game);
}
private static boolean isFlamableBlock(Block block) {
return !block.compare(Block.AIR)
&& !block.compare(Block.GRASS_BLOCK)
&& !block.compare(Block.FARMLAND)
&& !block.compare(Block.STONE)
&& !block.compare(Block.ANDESITE)
&& !block.compare(Block.ANDESITE_STAIRS)
&& !block.compare(Block.ANDESITE_SLAB)
&& !block.compare(Block.GRAVEL)
&& !block.compare(Block.DIRT_PATH)
&& !block.compare(Block.OAK_FENCE)
&& !block.compare(Block.OAK_FENCE_GATE)
&& !block.compare(Block.STONE_BRICKS)
&& !block.compare(Block.MOSSY_STONE_BRICK_WALL)
&& !block.compare(Block.MOSSY_STONE_BRICKS)
&& !block.compare(Block.MOSSY_STONE_BRICK_STAIRS)
&& !block.compare(Block.STONE_BRICK_STAIRS)
&& !block.compare(Block.MOSSY_STONE_BRICK_SLAB)
&& !block.compare(Block.STONE_BRICK_WALL)
&& !block.compare(Block.BRICK_SLAB)
&& !block.compare(Block.BRICK_STAIRS)
&& !block.compare(Block.CHAIN)
&& !block.compare(Block.WATER_CAULDRON)
&& !block.compare(Block.OAK_TRAPDOOR)
&& !block.compare(Block.SPRUCE_FENCE)
&& !block.compare(Block.SPRUCE_FENCE_GATE)
&& !block.compare(Block.SPRUCE_TRAPDOOR)
&& !block.compare(Block.SPRUCE_WALL_SIGN)
&& !block.compare(Block.SPRUCE_STAIRS)
&& !block.compare(Block.BARRIER)
&& !block.compare(Block.SAND)
&& !block.compare(Block.MOSS_BLOCK)
&& !block.compare(Block.WATER)
&& !block.compare(Block.SEA_LANTERN)
&& !block.compare(Block.RED_CARPET)
&& !block.compare(Block.WHITE_CARPET)
&& !block.compare(Block.TRIPWIRE);
}
public static void resetInstance(GameLobby game) {
InstanceManager instanceManager = MinecraftServer.getInstanceManager();
InstanceContainer instanceContainer = instanceManager.createInstanceContainer();
try {
instanceContainer.setChunkLoader(new PolarLoader(Path.of("worlds/game.polar")));
} catch (IOException e) {
logger.error(e.getMessage());
}
game.setInstance(instanceContainer);
}
public static void startHealthRegeneration(GameLobby game) {
int regenerationInterval = 20; // in seconds
Task healthRegenTask = scheduler.buildTask(() -> {
for (UUID playerId : game.getPlayers()) {
Player player = Misc.getPlayer(playerId);
if (player != null && player.getGameMode() == GameMode.ADVENTURE) {
player.addEffect(new Potion(PotionEffect.REGENERATION, (byte) 1, 100));
}
}
}).repeat(TaskSchedule.seconds(regenerationInterval)).schedule();
scheduler.buildTask(healthRegenTask::cancel).delay(TaskSchedule.seconds(phaseDuration)).schedule();
}
}

View file

@ -0,0 +1,81 @@
package dev.celestialfox.spectrumsurvival.utils;
import dev.celestialfox.spectrumsurvival.game.classes.GameLobby;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.title.Title;
import net.minestom.server.MinecraftServer;
import net.minestom.server.coordinate.Pos;
import net.minestom.server.entity.Player;
import net.minestom.server.instance.Instance;
import net.minestom.server.instance.block.Block;
import net.minestom.server.timer.Task;
import java.time.Duration;
import java.util.UUID;
public class Misc {
static Task timeTask;
public static Player getPlayer(UUID uuid) {
return MinecraftServer.getConnectionManager().getOnlinePlayerByUuid(uuid);
}
public static void showTitle(Instance instance, Component title, Component subtitle) {
for (Player player : instance.getPlayers()) { // Get all players in the instance
player.showTitle(Title.title(title, subtitle)); // Send the title to each player
}
}
public static void replaceInRegion(Instance instance, Pos start, Pos end, Block newBlockType) {
int startX = (int) Math.min(start.x(), end.x());
int startY = (int) Math.min(start.y(), end.y());
int startZ = (int) Math.min(start.z(), end.z());
int endX = (int) Math.max(start.x(), end.x());
int endY = (int) Math.max(start.y(), end.y());
int endZ = (int) Math.max(start.z(), end.z());
for (int x = startX; x <= endX; x++) {
for (int y = startY; y <= endY; y++) {
for (int z = startZ; z <= endZ; z++) {
Pos pos = new Pos(x, y, z);
if (instance.getBlock(pos).compare(Block.AIR)
|| instance.getBlock(pos).compare(Block.MOSS_CARPET)
|| instance.getBlock(pos).compare(Block.SHORT_GRASS)
|| instance.getBlock(pos).compare(Block.TALL_GRASS)
|| instance.getBlock(pos).compare(Block.WHEAT)
|| instance.getBlock(pos).compare(Block.CREEPER_HEAD)
|| instance.getBlock(pos).compare(Block.RED_CARPET)
|| instance.getBlock(pos).compare(Block.WHITE_CARPET)) {
instance.setBlock(pos, newBlockType);
}
}
}
}
}
public static void transitionToTime(GameLobby game, Duration duration, long startTime, long endTime) {
long transitionDuration = duration.toMillis();
long startMillis = System.currentTimeMillis();
timeTask = MinecraftServer.getSchedulerManager().buildTask(() -> {
long currentMillis = System.currentTimeMillis();
long elapsedMillis = currentMillis - startMillis;
double progress = Math.min(1.0, (double) elapsedMillis / transitionDuration);
long newTime = startTime + (long) (progress * (endTime - startTime));
game.getInstance().setTime(newTime);
if (progress >= 1.0) {
game.getInstance().setTime(endTime);
timeTask.cancel();
}
}).repeat(Duration.ofMillis(50)).schedule();
}
public static Block getBlockAtPlayerPosition(Player player) {
Pos playerPosition = player.getPosition();
Instance instance = player.getInstance();
return instance.getBlock(playerPosition);
}
}

View file

@ -1,4 +1,4 @@
package dev.cfox.gamejam.utils.classes; package dev.celestialfox.spectrumsurvival.utils.classes;
import net.kyori.adventure.text.Component; import net.kyori.adventure.text.Component;
import net.minestom.server.entity.*; import net.minestom.server.entity.*;

View file

@ -1,4 +1,4 @@
package dev.cfox.gamejam.utils.classes; package dev.celestialfox.spectrumsurvival.utils.classes;
import net.kyori.adventure.text.Component; import net.kyori.adventure.text.Component;
import net.minestom.server.entity.Player; import net.minestom.server.entity.Player;

View file

@ -1,4 +1,4 @@
package dev.cfox.gamejam.utils.config; package dev.celestialfox.spectrumsurvival.utils.config;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;

View file

@ -1,4 +1,4 @@
package dev.cfox.gamejam.utils.config; package dev.celestialfox.spectrumsurvival.utils.config;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;

View file

@ -1,4 +1,4 @@
package dev.cfox.gamejam.utils.config; package dev.celestialfox.spectrumsurvival.utils.config;
public class Settings { public class Settings {
public static String getIP() { public static String getIP() {

View file

@ -0,0 +1,177 @@
package dev.celestialfox.spectrumsurvival.utils.events;
import dev.celestialfox.spectrumsurvival.game.classes.GameLobby;
import dev.celestialfox.spectrumsurvival.game.classes.SnowballProjectile;
import dev.celestialfox.spectrumsurvival.game.classes.ZombieCreature;
import dev.celestialfox.spectrumsurvival.game.managers.GameManager;
import dev.celestialfox.spectrumsurvival.game.managers.QueueManager;
import dev.celestialfox.spectrumsurvival.game.phases.Phase;
import dev.celestialfox.spectrumsurvival.utils.Misc;
import dev.celestialfox.spectrumsurvival.utils.classes.NPC;
import net.kyori.adventure.text.Component;
import net.minestom.server.MinecraftServer;
import net.minestom.server.coordinate.Pos;
import net.minestom.server.coordinate.Vec;
import net.minestom.server.entity.Entity;
import net.minestom.server.entity.EntityType;
import net.minestom.server.entity.GameMode;
import net.minestom.server.entity.Player;
import net.minestom.server.entity.damage.Damage;
import net.minestom.server.entity.damage.DamageType;
import net.minestom.server.event.GlobalEventHandler;
import net.minestom.server.event.entity.EntityAttackEvent;
import net.minestom.server.event.entity.EntityDamageEvent;
import net.minestom.server.event.entity.projectile.ProjectileCollideWithBlockEvent;
import net.minestom.server.event.entity.projectile.ProjectileCollideWithEntityEvent;
import net.minestom.server.event.player.PlayerDeathEvent;
import net.minestom.server.event.player.PlayerDisconnectEvent;
import net.minestom.server.event.player.PlayerMoveEvent;
import net.minestom.server.event.player.PlayerUseItemEvent;
import net.minestom.server.instance.block.Block;
import net.minestom.server.item.ItemStack;
import net.minestom.server.item.Material;
import net.minestom.server.timer.TaskSchedule;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.swing.text.Position;
import java.util.UUID;
public class MiscEvents {
private static final double KNOCKBACK_STRENGTH = 15.0;
static GlobalEventHandler globalEventHandler = MinecraftServer.getGlobalEventHandler();
private static final Logger logger = LoggerFactory.getLogger(MiscEvents.class);
public static void register() {
logger.debug("Registering Misc Listeners");
globalEventHandler.addListener(PlayerMoveEvent.class, event -> {
Player player = event.getPlayer();
if (GameManager.isPlayerInGame(player)) {
if (GameManager.getPlayerGame(player).getPhase() == Phase.GREEN) {
if (Misc.getBlockAtPlayerPosition(player) == Block.WITHER_ROSE && player.getGameMode() == GameMode.ADVENTURE) {
player.damage(Damage.fromPlayer(player, 1));
}
} else if (GameManager.getPlayerGame(player).getPhase() == Phase.RED) {
if (Misc.getBlockAtPlayerPosition(player) == Block.FIRE && player.getGameMode() == GameMode.ADVENTURE) {
player.damage(Damage.fromPosition(DamageType.IN_FIRE, player.getPosition(), 1));
}
}
}
});
globalEventHandler.addListener(EntityAttackEvent.class, event -> {
Entity targeter = event.getEntity();
Entity targeted = event.getTarget();
if (targeter instanceof Player player) {
if (targeted instanceof NPC npc && npc.getCustomName().equals(Component.text("Join the Queue"))) {
QueueManager.joinPlayer(player);
}
if (targeted instanceof Player player2) {
if (player.getGameMode() == GameMode.ADVENTURE) {
applyKnockback(player, player2);
if (GameManager.isPlayerInGame(player)) {
if (GameManager.getPlayerGame(player).getPhase() == Phase.GRAY) {
player2.damage(Damage.fromPlayer(player, 1));
}
}
}
}
}
if (targeted instanceof Player player) {
if (GameManager.isPlayerInGame(player)) {
if (GameManager.getPlayerGame(player).getPhase() == Phase.GREEN) {
if (targeter instanceof ZombieCreature) {
ZombieCreature zombie = new ZombieCreature();
zombie.setInstance(player.getInstance(), player.getPosition());
GameManager.getPlayerGame(player).eliminate(player);
}
}
}
}
});
globalEventHandler.addListener(EntityDamageEvent.class, event -> {
Entity damaged = event.getEntity();
if (damaged instanceof Player player) {
if (player.getHealth() == 1 && GameManager.isPlayerInGame(player)) {
GameManager.getPlayerGame(player).eliminate(player);
}
}
});
globalEventHandler.addListener(PlayerDisconnectEvent.class, event -> {
Player player = event.getPlayer();
GameLobby playerGame = GameManager.getPlayerGame(player);
UUID uuid = player.getUuid();
if (GameManager.isPlayerInGame(player)) {
playerGame.getPlayers().remove(uuid);
playerGame.getEliminated().remove(uuid);
}
});
globalEventHandler.addListener(PlayerUseItemEvent.class, event -> {
Player player = event.getPlayer();
ItemStack item = event.getItemStack();
if (item.material() == Material.SNOWBALL) {
Pos playerPosition = player.getPosition().add(0, 1.5, 0);
Vec direction = player.getPosition().direction().normalize().mul(20);
SnowballProjectile snowball = new SnowballProjectile(player);
snowball.setInstance(player.getInstance(), playerPosition);
snowball.setVelocity(direction);
snowball.setNoGravity(false);
snowball.spawn();
MinecraftServer.getSchedulerManager().buildTask(() -> {
if (snowball.isActive()) {
snowball.remove();
}
}).delay(TaskSchedule.seconds(10)).schedule();
event.setCancelled(true);
}
});
globalEventHandler.addListener(ProjectileCollideWithBlockEvent.class, event -> {
if (event.getEntity() instanceof SnowballProjectile snowball) {
if (snowball.isActive()) {
snowball.remove();
}
}
});
globalEventHandler.addListener(ProjectileCollideWithEntityEvent.class, event -> {
if (event.getEntity() instanceof SnowballProjectile snowball) {
if (event.getTarget() instanceof Player target) {
if (snowball.isActive()) {
snowball.remove();
}
target.damage(Damage.fromProjectile(snowball, snowball, 0.75F));
}
}
});
globalEventHandler.addListener(PlayerDeathEvent.class, event -> {
// Cancel the default death message
event.setDeathText(Component.text("You were eliminated!"));
event.setChatMessage(null);
});
}
private static void applyKnockback(Player attacker, Player target) {
Pos targetPos = target.getPosition();
Pos attackerPos = attacker.getPosition();
double dx = targetPos.x() - attackerPos.x();
double dz = targetPos.z() - attackerPos.z();
double length = Math.sqrt(dx * dx + dz * dz);
if (length > 0) {
dx /= length;
dz /= length;
target.setVelocity(target.getVelocity().add(dx * KNOCKBACK_STRENGTH, 0, dz * KNOCKBACK_STRENGTH));
}
}
}

View file

@ -1,12 +1,10 @@
package dev.cfox.gamejam.utils.events; package dev.celestialfox.spectrumsurvival.utils.events;
import dev.cfox.gamejam.utils.Misc; import dev.celestialfox.spectrumsurvival.game.managers.QueueManager;
import dev.cfox.gamejam.utils.classes.NPC; import dev.celestialfox.spectrumsurvival.utils.classes.NPC;
import dev.cfox.gamejam.utils.classes.Randomized;
import net.hollowcube.polar.PolarLoader; import net.hollowcube.polar.PolarLoader;
import net.kyori.adventure.text.Component; import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor; import net.kyori.adventure.text.format.NamedTextColor;
import net.kyori.adventure.text.minimessage.MiniMessage;
import net.minestom.server.MinecraftServer; import net.minestom.server.MinecraftServer;
import net.minestom.server.coordinate.Pos; import net.minestom.server.coordinate.Pos;
import net.minestom.server.entity.GameMode; import net.minestom.server.entity.GameMode;
@ -16,13 +14,11 @@ import net.minestom.server.event.player.AsyncPlayerConfigurationEvent;
import net.minestom.server.event.player.PlayerChatEvent; import net.minestom.server.event.player.PlayerChatEvent;
import net.minestom.server.event.player.PlayerSpawnEvent; import net.minestom.server.event.player.PlayerSpawnEvent;
import net.minestom.server.instance.*; import net.minestom.server.instance.*;
import net.minestom.server.instance.block.Block;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import java.io.IOException; import java.io.IOException;
import java.nio.file.Path; import java.nio.file.Path;
import java.time.Duration;
public class StartEvents { public class StartEvents {
static GlobalEventHandler globalEventHandler = MinecraftServer.getGlobalEventHandler(); static GlobalEventHandler globalEventHandler = MinecraftServer.getGlobalEventHandler();
@ -50,14 +46,15 @@ public class StartEvents {
final Player player = event.getPlayer(); final Player player = event.getPlayer();
player.setGameMode(GameMode.ADVENTURE); player.setGameMode(GameMode.ADVENTURE);
event.setSpawningInstance(instanceContainer); event.setSpawningInstance(instanceContainer);
player.setRespawnPoint(new Pos(0.5, 66, 0.5, 180, 0)); player.setRespawnPoint(new Pos(0, 66, 0, 180, 0));
}); });
globalEventHandler.addListener(PlayerSpawnEvent.class, event -> { globalEventHandler.addListener(PlayerSpawnEvent.class, event -> {
Player player = event.getPlayer(); Player player = event.getPlayer();
if (event.isFirstSpawn()) { if (event.isFirstSpawn()) {
player.sendMessage(Component.text( player.sendMessage(
"§ePunch §rthe Minestom NPC to §ajoin the queue!", NamedTextColor.GRAY)); Component.text("Use §e/about game §rto read the rules.", NamedTextColor.GRAY)
.append(Component.text("§ePunch §rthe Minestom NPC to §ajoin the queue!", NamedTextColor.GRAY)));
} }
}); });
} }
@ -77,6 +74,8 @@ public class StartEvents {
"yWIH6gVDRhgd/HwVYpRT87NBHf+q9EgYs/CYqIwnz5xXR22k29c7MTnaYFvWukbwF1FhWNilAyYzagSn/7ScvOpYn0RtyTWk656cwjzFSbTsSFzRwUl5f4mu1EeunYh8v5cZH27KTfAI7a9Q7ylXz7NoAbvaw056thXa7jHhLhFdPECnziRTnv9jDRwpoN/4jblmdOz5NCLtynubf8hwIwm9od18tXy4+gsV3aXS5+1MirpWDizqdozb9mtwzML9NYwVNpO2bRB9KYJ91VUWqxjfTy/q0xFQ1paolq4pp3tgvLXw0y+rdwCsCgh39JA4MKvIIJShww5xbqo4oFBRDj+/BI3+Y154Ess1004vE+iTRdt+az0v4y+evnOQLgryEr/36QzZOndpSFqYfKPl1MeUeZe1u4VDQJcgyJImg2TZJbG2WOmmTySWSEPrHcYC6c3Y9rVnQ6Zi4NxTe4e6/ZuDQVm14fuSUPd4Ll7/aIDyumHupBMMbBEa9qCmuZJPT5iWVlIGfzA2Dg/kea4Jw9WudUmiCYngB56HZEivDPniIxeGSTRFHMR2FfTKnLkxb2LDOvD+CgDWyr8cGy4xnB2hwdY2n28cCAYI5axj0qzCpHMl8Y90e2rKfX7NsUvyivbAVRwAsd/bWkkJoZ4/QStFEjV//81iNbuUz/4lFQA="); "yWIH6gVDRhgd/HwVYpRT87NBHf+q9EgYs/CYqIwnz5xXR22k29c7MTnaYFvWukbwF1FhWNilAyYzagSn/7ScvOpYn0RtyTWk656cwjzFSbTsSFzRwUl5f4mu1EeunYh8v5cZH27KTfAI7a9Q7ylXz7NoAbvaw056thXa7jHhLhFdPECnziRTnv9jDRwpoN/4jblmdOz5NCLtynubf8hwIwm9od18tXy4+gsV3aXS5+1MirpWDizqdozb9mtwzML9NYwVNpO2bRB9KYJ91VUWqxjfTy/q0xFQ1paolq4pp3tgvLXw0y+rdwCsCgh39JA4MKvIIJShww5xbqo4oFBRDj+/BI3+Y154Ess1004vE+iTRdt+az0v4y+evnOQLgryEr/36QzZOndpSFqYfKPl1MeUeZe1u4VDQJcgyJImg2TZJbG2WOmmTySWSEPrHcYC6c3Y9rVnQ6Zi4NxTe4e6/ZuDQVm14fuSUPd4Ll7/aIDyumHupBMMbBEa9qCmuZJPT5iWVlIGfzA2Dg/kea4Jw9WudUmiCYngB56HZEivDPniIxeGSTRFHMR2FfTKnLkxb2LDOvD+CgDWyr8cGy4xnB2hwdY2n28cCAYI5axj0qzCpHMl8Y90e2rKfX7NsUvyivbAVRwAsd/bWkkJoZ4/QStFEjV//81iNbuUz/4lFQA=");
joinNPC.setInstance(instanceContainer, new Pos(0.5, 66.5, -16.5)); joinNPC.setInstance(instanceContainer, new Pos(0.5, 66.5, -16.5));
QueueManager.lobbyInstance = instanceContainer;
return instanceContainer; return instanceContainer;
} }
} }

View file

@ -1,34 +0,0 @@
package dev.cfox.gamejam.game.commands;
import dev.cfox.gamejam.game.managers.GameManager;
import dev.cfox.gamejam.game.managers.QueueManager;
import net.kyori.adventure.sound.Sound;
import net.minestom.server.MinecraftServer;
import net.minestom.server.command.builder.Command;
import net.minestom.server.command.builder.arguments.ArgumentType;
import net.minestom.server.entity.Entity;
import net.minestom.server.entity.EntityType;
import net.minestom.server.entity.Player;
import net.minestom.server.sound.SoundEvent;
import net.minestom.server.timer.TaskSchedule;
import net.minestom.server.utils.NamespaceID;
import java.util.concurrent.TimeUnit;
public class QueueCommand extends Command {
public QueueCommand() {
super("queue", "q");
addSyntax(((sender, context) -> {
final String arg1 = context.get("arg1");
if (sender instanceof Player player) {
if (arg1.equals("join")) {
QueueManager.joinPlayer(player);
} else if (arg1.equals("leave")) {
QueueManager.removePlayer(player);
} else if (arg1.equals("force")) {
GameManager.startGame(QueueManager.getPlayerQueue(player));
}
}
}), ArgumentType.String("arg1"));
}
}

View file

@ -1,108 +0,0 @@
package dev.cfox.gamejam.game.phases;
import dev.cfox.gamejam.game.classes.GameLobby;
import dev.cfox.gamejam.game.managers.ConversionManager;
import dev.cfox.gamejam.utils.Misc;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import net.minestom.server.MinecraftServer;
import net.minestom.server.entity.Entity;
import net.minestom.server.entity.EntityType;
import net.minestom.server.entity.GameMode;
import net.minestom.server.entity.Player;
import net.minestom.server.timer.SchedulerManager;
import net.minestom.server.timer.Task;
import net.minestom.server.timer.TaskSchedule;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.time.Duration;
import java.util.List;
import java.util.Random;
import java.util.UUID;
public class PhaseLogic {
private static final Logger logger = LoggerFactory.getLogger(PhaseLogic.class);
private static final SchedulerManager scheduler = MinecraftServer.getSchedulerManager();
private static int phaseDuration = 30; // in seconds
private static int gameTime = 300; // 5 minutes in seconds
public static void random(GameLobby game) {
Task task = scheduler.buildTask(() -> {
Phase[] phases = Phase.values();
int randomIndex = new Random().nextInt(phases.length);
Phase selectedPhase = phases[randomIndex];
if (game.getTask() != null) {
game.getTask().cancel();
}
switch (selectedPhase) {
case RED -> red(game);
case BLUE -> blue(game);
case GREEN -> green(game);
case YELLOW -> yellow(game);
case PURPLE -> purple(game);
}
}).repeat(TaskSchedule.seconds(phaseDuration)).schedule();
scheduler.buildTask(() -> {
ConversionManager.fromGame(game);
task.cancel();
}).delay(TaskSchedule.seconds(gameTime)).schedule();
}
public static void red(GameLobby game) {
logger.debug("Picked red phase for GameLobby: " + game.getName());
game.setPhase(Phase.RED);
game.sendMessage(Component.text("New color picked! §cRED", NamedTextColor.GRAY));
game.sendMessage(Component.text("BLAH BLAH BLAH BLAH", NamedTextColor.RED));
Misc.showTitle(game.getInstance(), Component.text("", NamedTextColor.RED), Component.text("Red", NamedTextColor.RED));
// Handle red phase logic
}
public static void blue(GameLobby game) {
logger.debug("Picked blue phase for GameLobby: " + game.getName());
game.setPhase(Phase.BLUE);
game.sendMessage(Component.text("New color picked! §9BLUE", NamedTextColor.GRAY));
game.sendMessage(Component.text("BLAH BLAH BLAH BLAH", NamedTextColor.BLUE));
Misc.showTitle(game.getInstance(), Component.text("", NamedTextColor.BLUE), Component.text("Blue", NamedTextColor.BLUE));
// Handle blue phase logic
}
public static void green(GameLobby game) {
logger.debug("Picked green phase for GameLobby: " + game.getName());
game.setPhase(Phase.GREEN);
game.sendMessage(Component.text("New color picked! §aGREEN", NamedTextColor.GRAY));
game.sendMessage(Component.text("BLAH BLAH BLAH BLAH", NamedTextColor.GREEN));
Misc.showTitle(game.getInstance(), Component.text("", NamedTextColor.GREEN), Component.text("Green", NamedTextColor.GREEN));
// Handle green phase logic
}
public static void yellow(GameLobby game) {
logger.debug("Picked yellow phase for GameLobby: " + game.getName());
game.setPhase(Phase.YELLOW);
game.sendMessage(Component.text("New color picked! §eYELLOW", NamedTextColor.GRAY));
game.sendMessage(Component.text("Thunder is coming! Find a place to hide!", NamedTextColor.YELLOW));
Misc.showTitle(game.getInstance(), Component.text("", NamedTextColor.YELLOW), Component.text("Yellow", NamedTextColor.YELLOW));
scheduler.buildTask(() -> {
Task task = scheduler.buildTask(() -> {
List<UUID> uuids = game.getPlayers();
Random random = new Random();
Player randomPlayer = null;
while (randomPlayer == null || randomPlayer.getGameMode() != GameMode.ADVENTURE) {
randomPlayer = Misc.getPlayer(uuids.get(random.nextInt(uuids.size())));
}
Entity lightning = new Entity(EntityType.LIGHTNING_BOLT);
lightning.setInstance(randomPlayer.getInstance(), randomPlayer.getPosition());
lightning.spawn();
game.eliminate(randomPlayer);
}).repeat(Duration.ofSeconds(5)).schedule();
game.setTask(task);
}).delay(Duration.ofSeconds(5)).schedule();
}
public static void purple(GameLobby game) {
logger.debug("Picked purple phase for GameLobby: " + game.getName());
game.setPhase(Phase.PURPLE);
game.sendMessage(Component.text("New color picked! §dPURPLE", NamedTextColor.GRAY));
game.sendMessage(Component.text("BLAH BLAH BLAH BLAH", NamedTextColor.LIGHT_PURPLE));
Misc.showTitle(game.getInstance(), Component.text("", NamedTextColor.LIGHT_PURPLE), Component.text("Purple", NamedTextColor.LIGHT_PURPLE));
// Handle purple phase logic
}
}

View file

@ -1,44 +0,0 @@
package dev.cfox.gamejam.utils;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.title.Title;
import net.minestom.server.MinecraftServer;
import net.minestom.server.coordinate.Pos;
import net.minestom.server.entity.Player;
import net.minestom.server.instance.Instance;
import net.minestom.server.instance.block.Block;
import java.util.UUID;
public class Misc {
public static Player getPlayer(UUID uuid) {
return MinecraftServer.getConnectionManager().getOnlinePlayerByUuid(uuid);
}
public static void showTitle(Instance instance, Component title, Component subtitle) {
for (Player player : instance.getPlayers()) { // Get all players in the instance
player.showTitle(Title.title(title, subtitle)); // Send the title to each player
}
}
public void replaceAirInRegion(Instance instance, Pos start, Pos end, Block newBlockType) {
int startX = (int) Math.min(start.x(), end.x());
int startY = (int) Math.min(start.y(), end.y());
int startZ = (int) Math.min(start.z(), end.z());
int endX = (int) Math.max(start.x(), end.x());
int endY = (int) Math.max(start.y(), end.y());
int endZ = (int) Math.max(start.z(), end.z());
for (int x = startX; x <= endX; x++) {
for (int y = startY; y <= endY; y++) {
for (int z = startZ; z <= endZ; z++) {
Pos pos = new Pos(x, y, z);
if (instance.getBlock(pos).compare(Block.AIR)) {
instance.setBlock(pos, newBlockType);
}
}
}
}
}
}

View file

@ -1,45 +0,0 @@
package dev.cfox.gamejam.utils.events;
import dev.cfox.gamejam.game.managers.GameManager;
import dev.cfox.gamejam.game.managers.QueueManager;
import dev.cfox.gamejam.game.phases.Phase;
import dev.cfox.gamejam.utils.classes.NPC;
import net.kyori.adventure.text.Component;
import net.minestom.server.MinecraftServer;
import net.minestom.server.entity.Entity;
import net.minestom.server.entity.Player;
import net.minestom.server.event.GlobalEventHandler;
import net.minestom.server.event.entity.EntityAttackEvent;
import net.minestom.server.event.player.PlayerMoveEvent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class MiscEvents {
static GlobalEventHandler globalEventHandler = MinecraftServer.getGlobalEventHandler();
private static final Logger logger = LoggerFactory.getLogger(MiscEvents.class);
public static void register() {
logger.debug("Registering Misc Listeners");
globalEventHandler.addListener(PlayerMoveEvent.class, event -> {
Player player = event.getPlayer();
if (GameManager.isPlayerInGame(player)) {
Phase phase = GameManager.getPlayerGame(player).getPhase();
if (phase == Phase.YELLOW) {
}
}
});
globalEventHandler.addListener(EntityAttackEvent.class, event -> {
Entity targeter = event.getEntity();
Entity targeted = event.getTarget();
if (targeter instanceof Player player) {
if (targeted instanceof NPC npc && npc.getCustomName().equals(Component.text("Join the Queue"))) {
QueueManager.joinPlayer(player);
}
}
});
}
}