1
0
Fork 0

Finishing touches and bugfixing

Some finishing touches and bug fixing before the end of the game jam
This commit is contained in:
Andus 2024-08-14 03:09:28 +02:00
parent 90ddb82640
commit a5c9aea14f
13 changed files with 234 additions and 88 deletions

BIN
server/SpectrumSurvival.jar Normal file

Binary file not shown.

View file

@ -1,15 +1,24 @@
package dev.celestialfox.spectrumsurvival;
import dev.celestialfox.spectrumsurvival.game.commands.*;
import dev.celestialfox.spectrumsurvival.game.managers.GameManager;
import dev.celestialfox.spectrumsurvival.game.managers.QueueManager;
import dev.celestialfox.spectrumsurvival.utils.classes.SignHandler;
import dev.celestialfox.spectrumsurvival.utils.config.Checks;
import dev.celestialfox.spectrumsurvival.utils.config.Settings;
import dev.celestialfox.spectrumsurvival.utils.events.MiscEvents;
import dev.celestialfox.spectrumsurvival.utils.events.StartEvents;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import net.minestom.server.MinecraftServer;
import net.minestom.server.adventure.audience.Audiences;
import net.minestom.server.command.CommandManager;
import net.minestom.server.timer.TaskSchedule;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Random;
public class Server {
// Other
private static final Logger logger = LoggerFactory.getLogger(Server.class);
@ -33,6 +42,8 @@ public class Server {
registerCommands();
Terminal.start();
tablist();
MinecraftServer.getBlockManager().registerHandler("minecraft:spruce_wall_sign", SignHandler::new);
// Server Start
server.start(Settings.getIP(), Settings.getPort());
@ -46,4 +57,33 @@ public class Server {
commandManager.register(new CreditsCommand());
commandManager.register(new StopCommand());
}
public static void tablist() {
MinecraftServer.getSchedulerManager().scheduleTask(() -> {
Component header = Component.text("\nᴘʟᴀʏᴇʀѕ ᴏɴʟɪɴᴇ: " + MinecraftServer.getConnectionManager().getOnlinePlayers().size(), NamedTextColor.BLUE)
.append(Component.text("\nᴘʟᴀʏᴇʀѕ ɪɴ ǫᴜᴇᴜᴇ: " + QueueManager.getPlayersInQueue(), NamedTextColor.GRAY)
.append(Component.text("\nᴘʟᴀʏᴇʀѕ ɪɴ-ɢᴀᴍᴇ: " + GameManager.getPlayersInGame() + "\n", NamedTextColor.BLUE)));
Component footer = Component.newline()
.append(Component.text("ᴍᴀᴅᴇ ʙʏ: CelestialFox Studio", randomMadeByColor()));
Audiences.players().sendPlayerListHeaderAndFooter(header, footer);
}, TaskSchedule.tick(10), TaskSchedule.tick(10));
}
public static NamedTextColor randomMadeByColor() {
Random random = new Random();
int num = random.nextInt(4);
if (num == 0) {
return NamedTextColor.BLUE;
} else if (num == 1) {
return NamedTextColor.GRAY;
} else if (num == 2) {
return NamedTextColor.GOLD;
} else if (num == 3) {
return NamedTextColor.GREEN;
} else {
return NamedTextColor.BLUE;
}
}
}

View file

@ -31,6 +31,8 @@ public class GameLobby {
private final ArrayList<UUID> eliminated = new ArrayList<>();
private Phase phase;
private Task latestTask;
private Task repeatTask;
private Task endTask;
private Instance instance;
private String name = "";
@ -114,4 +116,18 @@ public class GameLobby {
public Task getTask() {
return latestTask;
}
public void setRepeatTask(Task task) {
repeatTask = task;
}
public Task getRepeatTask() {
return repeatTask;
}
public void setEndTask(Task task) {
endTask = task;
}
public Task getEndTask() {
return endTask;
}
}

View file

@ -27,10 +27,10 @@ public class AboutCommand extends Command {
} 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("Dive into Spectrum Survival, where each color phase brings a new challenge! Every 20 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("- §lBlue: §9Snowball fight frenzy! Eliminate 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))

View file

@ -29,8 +29,6 @@ public class QueueCommand extends Command {
} 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

@ -5,8 +5,11 @@ import dev.celestialfox.spectrumsurvival.game.classes.GameQueue;
import dev.celestialfox.spectrumsurvival.utils.Misc;
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.GameMode;
import net.minestom.server.instance.Instance;
import net.minestom.server.timer.TaskSchedule;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -23,11 +26,19 @@ public class ConversionManager {
}
public static void fromGame(GameLobby game) {
if (!GameManager.gameLobbies.containsKey(game.getName())) {
Instance instance = game.getInstance();
String lobbyName = game.getName();
MinecraftServer.getSchedulerManager().buildTask(() -> {
logger.debug("Instance for GameLobby {} removed", lobbyName);
MinecraftServer.getInstanceManager().unregisterInstance(instance);
}).delay(TaskSchedule.seconds(5)).schedule();
if (!GameManager.gameLobbies.containsKey(lobbyName)) {
return;
}
logger.debug("GameLobby removed: " + game.getName());
GameManager.gameLobbies.remove(lobbyName);
logger.debug("GameLobby removed: " + lobbyName);
game.sendMessage(Component.text("Game ended!", NamedTextColor.RED));
game.setInstance(QueueManager.lobbyInstance, new Pos(0, 66, 0, 180, 0));
game.getPlayers().forEach(uuid -> {
@ -35,6 +46,5 @@ public class ConversionManager {
Misc.getPlayer(uuid).setHealth(20);
});
GameManager.sendEndTitles(game);
GameManager.gameLobbies.remove(game.getName());
}
}

View file

@ -76,21 +76,28 @@ public class GameManager {
}
public static void sendEndTitles(GameLobby game) {
Instance instance = game.getInstance();
List<UUID> uuids = game.getPlayers();
List<String> winners = new ArrayList<>();
List<UUID> eliminated = game.getEliminated();
for (Player player : instance.getPlayers()) {
if (eliminated.contains(player.getUuid())) {
player.showTitle(Title.title(Component.text("You Lost.", NamedTextColor.RED, TextDecoration.BOLD), Component.text("")));
for (UUID uuid : uuids) {
if (eliminated.contains(uuid)) {
Misc.getPlayer(uuid).showTitle(Title.title(Component.text("You Lost.", NamedTextColor.RED, TextDecoration.BOLD), Component.text("")));
} else {
// Player is a winner if they were not eliminated
player.showTitle(Title.title(Component.text("You Win!", NamedTextColor.GREEN, TextDecoration.BOLD), Component.text("")));
winners.add(player.getUsername());
Misc.getPlayer(uuid).showTitle(Title.title(Component.text("You Win!", NamedTextColor.GREEN, TextDecoration.BOLD), Component.text("")));
winners.add(Misc.getPlayer(uuid).getUsername());
}
}
// Announce winners
instance.sendMessage(Component.text("Winner(s): " + winners, NamedTextColor.YELLOW));
game.sendMessage(Component.text("Winner(s): " + winners, NamedTextColor.YELLOW));
}
public static int getPlayersInGame() {
int totalPlayers = 0;
for (GameLobby gameLobby : gameLobbies.values()) {
totalPlayers += gameLobby.getPlayers().size();
}
return totalPlayers;
}
}

View file

@ -1,7 +1,10 @@
package dev.celestialfox.spectrumsurvival.game.managers;
import dev.celestialfox.spectrumsurvival.game.classes.GameLobby;
import dev.celestialfox.spectrumsurvival.utils.Misc;
import dev.celestialfox.spectrumsurvival.game.classes.GameQueue;
import net.kyori.adventure.key.Key;
import net.kyori.adventure.sound.Sound;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import net.kyori.adventure.title.Title;
@ -89,9 +92,15 @@ public class QueueManager {
queue.getPlayers().forEach(player -> Misc.getPlayer(player).showTitle(Title.title(
Component.text("Starting in " + countdown[0], NamedTextColor.GREEN),
Component.text("Get ready", NamedTextColor.GRAY))));
queue.getPlayers().forEach(player -> {
Misc.getPlayer(player).playSound(Sound.sound(Key.key("minecraft", "entity.experience_orb.pickup"), Sound.Source.MASTER, 1f, 1f));
});
if (countdown[0] == 0) {
// Time's up, cancel the task and start the game
queue.getPlayers().forEach(player -> {
Misc.getPlayer(player).playSound(Sound.sound(Key.key("minecraft", "entity.player.levelup"), Sound.Source.MASTER, 1f, 1f));
});
GameManager.startGame(queue);
countdownTasks.get(queue).cancel();
countdownTasks.remove(queue);
@ -110,4 +119,21 @@ public class QueueManager {
countdownTasks.remove(queue);
}
}
public static boolean isPlayerInQueue(Player player) {
for (GameQueue queue : queues) {
if (queue.getPlayers().contains(player.getUuid())) {
return true;
}
}
return false;
}
public static int getPlayersInQueue() {
int totalPlayers = 0;
for (GameQueue queue : queues) {
totalPlayers += queue.getPlayers().size();
}
return totalPlayers;
}
}

View file

@ -1,6 +1,7 @@
package dev.celestialfox.spectrumsurvival.game.phases;
import dev.celestialfox.spectrumsurvival.game.classes.ZombieCreature;
import dev.celestialfox.spectrumsurvival.game.managers.GameManager;
import dev.celestialfox.spectrumsurvival.utils.Misc;
import dev.celestialfox.spectrumsurvival.game.classes.GameLobby;
import dev.celestialfox.spectrumsurvival.game.managers.ConversionManager;
@ -43,18 +44,27 @@ public class PhaseLogic {
private static final int zombiesSpawn = 5;
public static void random(GameLobby game) {
if (repeatTask != null) {
repeatTask.cancel();
if (game.getRepeatTask() != null) {
game.getRepeatTask().cancel();
}
if (game.getEndTask() != null) {
game.getEndTask().cancel();
}
repeatTask = scheduler.buildTask(() -> {
// Check if all players are eliminated
if (game.getEliminated().size() == game.getPlayers().size()) {
ConversionManager.fromGame(game);
repeatTask.cancel();
endTask.cancel();
game.getRepeatTask().cancel();
game.getEndTask().cancel();
if (game.getTask() != null) {
game.getTask().cancel();
}
} else {
logger.debug("Starting random phase selection for GameLobby: {}", game.getName());
if (game.getTask() != null) {
game.getTask().cancel();
}
try {
Phase[] phases = Phase.values();
Phase selectedPhase;
@ -63,14 +73,10 @@ public class PhaseLogic {
selectedPhase = phases[randomIndex];
} while (
(selectedPhase == game.getPhase())
|| ((selectedPhase == Phase.GRAY) && (game.getPlayers().size() == game.getEliminated().size()+1)));
|| ((selectedPhase == Phase.GRAY || selectedPhase == Phase.BLUE) && (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);
@ -88,11 +94,17 @@ public class PhaseLogic {
try {
logger.debug("Ending game for GameLobby: {}", game.getName());
ConversionManager.fromGame(game);
repeatTask.cancel();
game.getRepeatTask().cancel();
if (game.getTask() != null) {
game.getTask().cancel();
}
} catch (Exception e) {
logger.error("Exception occurred during game ending: {}", e.getMessage());
}
}).delay(TaskSchedule.seconds(gameTime)).schedule();
game.setRepeatTask(repeatTask);
game.setEndTask(endTask);
}
public static void red(GameLobby game) {
@ -135,7 +147,7 @@ public class PhaseLogic {
}
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.",
"Battle it out with snowballs! Eliminate everyone.",
"Blue", NamedTextColor.BLUE, 1000, Weather.CLEAR);
// Logic
@ -154,14 +166,24 @@ public class PhaseLogic {
if (block.compare(Block.MOSS_CARPET) || block.compare(Block.SHORT_GRASS) || block.compare(Block.TALL_GRASS)) {
game.getInstance().setBlock(pos, Block.AIR);
}
if (block.compare(Block.HAY_BLOCK)) {
game.getInstance().setBlock(pos, Block.DRIED_KELP_BLOCK);
}
}
}
}
game.getInstance().setBlock(new Pos(5, 66, 3), Block.SNOW_BLOCK);
game.getInstance().setBlock(new Pos(5, 67, 3), Block.SNOW_BLOCK);
game.getInstance().setBlock(new Pos(5, 68, 3), Block.CARVED_PUMPKIN);
game.getInstance().setBlock(new Pos(-10, 66, -1), Block.SNOW_BLOCK);
game.getInstance().setBlock(new Pos(-10, 67, -1), Block.SNOW_BLOCK);
// Snowball Supply
game.getPlayers().forEach(uuid -> {
Player player = Misc.getPlayer(uuid);
player.getInventory().addItemStack(ItemStack.of(Material.SNOWBALL, 64));
player.getInventory().addItemStack(ItemStack.of(Material.SNOWBALL, 16));
});
// Phase end
@ -203,7 +225,6 @@ public class PhaseLogic {
"Yellow", NamedTextColor.YELLOW, 18000, Weather.RAIN);
// Logic
scheduler.buildTask(() -> {
Task task = scheduler.buildTask(() -> {
List<UUID> uuids = game.getPlayers();
List<Player> eligiblePlayers = new ArrayList<>();
@ -226,16 +247,14 @@ public class PhaseLogic {
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
);
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();
}).delay(Duration.ofSeconds(5)).repeat(Duration.ofSeconds(2)).schedule();
game.setTask(task);
}).delay(Duration.ofSeconds(5)).schedule();
}
public static void gray(GameLobby game) {
setupPhase(game, Phase.GRAY, "New color picked! §8GRAY",
@ -249,9 +268,6 @@ public class PhaseLogic {
Misc.getPlayer(uuid).addEffect(new Potion(PotionEffect.BLINDNESS, (byte) 1, phaseDuration*20));
}
});
scheduler.buildTask(() -> {
startHealthRegeneration(game);
}).delay(TaskSchedule.seconds(phaseDuration)).schedule();
}
@ -328,8 +344,6 @@ public class PhaseLogic {
}
}
}
startHealthRegeneration(game);
}
private static boolean isFlamableBlock(Block block) {
@ -382,19 +396,4 @@ public class PhaseLogic {
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,25 @@
package dev.celestialfox.spectrumsurvival.utils.classes;
import net.minestom.server.instance.block.BlockHandler;
import net.minestom.server.tag.Tag;
import net.minestom.server.utils.NamespaceID;
import org.jetbrains.annotations.NotNull;
import java.util.Collection;
import java.util.List;
public final class SignHandler implements BlockHandler {
@Override
public @NotNull Collection<Tag<?>> getBlockEntityTags() {
return List.of(
Tag.Boolean("is_waxed"),
Tag.NBT("front_text"),
Tag.NBT("back_text")
);
}
@Override
public @NotNull NamespaceID getNamespaceId() {
return NamespaceID.from("minecraft:sign");
}
}

View file

@ -9,7 +9,23 @@ public class Checks {
private static final Logger logger = LoggerFactory.getLogger(Checks.class);
public static void worldFiles() {
logger.info("Checking for world files...");
logger.debug("(Placeholder) World 'lobby.polar' found");
File lobbyWorldFile = new File("worlds/lobby.polar");
File gameWorldFile = new File("worlds/game.polar");
if (lobbyWorldFile.exists()) {
logger.debug("World 'lobby.polar' found");
} else {
logger.error("World 'lobby.polar' not found");
System.exit(0);
}
if (gameWorldFile.exists()) {
logger.debug("World 'game.polar' found");
} else {
logger.error("World 'game.polar' not found");
System.exit(0);
}
}
public static void configFile() {
File configFile = new File(Configuration.CONFIG_FILE);

View file

@ -8,6 +8,7 @@ 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.sound.Sound;
import net.kyori.adventure.text.Component;
import net.minestom.server.MinecraftServer;
import net.minestom.server.coordinate.Pos;
@ -93,15 +94,6 @@ public class MiscEvents {
}
});
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);
@ -110,6 +102,9 @@ public class MiscEvents {
playerGame.getPlayers().remove(uuid);
playerGame.getEliminated().remove(uuid);
}
if (QueueManager.isPlayerInQueue(player)) {
QueueManager.getPlayerQueue(player).removePlayer(uuid);
}
});
globalEventHandler.addListener(PlayerUseItemEvent.class, event -> {
@ -118,7 +113,7 @@ public class MiscEvents {
if (item.material() == Material.SNOWBALL) {
Pos playerPosition = player.getPosition().add(0, 1.5, 0);
Vec direction = player.getPosition().direction().normalize().mul(20);
Vec direction = player.getPosition().direction().normalize().mul(30);
SnowballProjectile snowball = new SnowballProjectile(player);
snowball.setInstance(player.getInstance(), playerPosition);
@ -158,7 +153,20 @@ public class MiscEvents {
// Cancel the default death message
event.setDeathText(Component.text("You were eliminated!"));
event.setChatMessage(null);
if (GameManager.isPlayerInGame(event.getPlayer())) {
GameManager.getPlayerGame(event.getPlayer()).eliminate(event.getPlayer());
}
});
MinecraftServer.getSchedulerManager().buildTask(() -> {
for (Player player : MinecraftServer.getConnectionManager().getOnlinePlayers()) {
if (GameManager.isPlayerInGame(player)
&& !(GameManager.getPlayerGame(player).getPhase() == Phase.GRAY)
&& player.getHealth() != 20) {
player.setHealth(player.getHealth()+1);
}
}
}).repeat(TaskSchedule.seconds(2)).schedule();
}
private static void applyKnockback(Player attacker, Player target) {

View file

@ -53,7 +53,8 @@ public class StartEvents {
if (event.isFirstSpawn()) {
player.sendMessage(
Component.text("Use §e/about game §rto read the rules.", NamedTextColor.GRAY)
Component.text("Use §e/about game §rto read the rules.\n", NamedTextColor.GRAY)
.append(Component.text("Use §e/credits and /about us §rto know who made the game.\n", NamedTextColor.GRAY))
.append(Component.text("§ePunch §rthe Minestom NPC to §ajoin the queue!", NamedTextColor.GRAY)));
}
});