/* * This file is a part of the SteamWar software. * * Copyright (C) 2023 SteamWar.de-Serverteam * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ package de.steamwar.towerrun.game; import de.steamwar.core.CraftbukkitWrapper; import de.steamwar.sql.SteamwarUser; import de.steamwar.towerrun.TowerRun; import de.steamwar.towerrun.config.Config; import de.steamwar.towerrun.config.WorldConfig; import de.steamwar.towerrun.state.GameState; import de.steamwar.towerrun.state.GameStates; import lombok.experimental.UtilityClass; import net.minecraft.world.level.chunk.Chunk; import org.bukkit.*; import org.bukkit.craftbukkit.v1_19_R2.CraftWorld; import org.bukkit.entity.Entity; import org.bukkit.entity.EntityType; import org.bukkit.entity.Player; import org.bukkit.util.Vector; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.function.ObjIntConsumer; @UtilityClass public class TowerRunGame { public static final List PLAYERS_ALIVE = new ArrayList<>(); public static final List PLAYERS_ESCAPED = new ArrayList<>(); private static final World world = Bukkit.getWorlds().get(0); public static boolean isEscaped(TowerRunPlayer player) { return PLAYERS_ESCAPED.contains(player); } public static boolean isAlive(TowerRunPlayer player) { return PLAYERS_ALIVE.contains(player); } public static void prepareTowerOrStart() { if (GameState.getCurrentState() == GameStates.WAITING) { GameState.nextState(); if (TowerRun.getTowerGenerator() == null) { start(); return; } TowerRun.getTowerGenerator().generate(); } else { throw new IllegalStateException("Game is already running!"); } } public static void start() { if (GameState.getCurrentState() == GameStates.GENERATING_TOWER) { PLAYERS_ALIVE.forEach(p -> { p.reset(); p.player().setGameMode(GameMode.SURVIVAL); }); GameState.nextState(); generateLava(); TowerRun.getMessage().broadcast("GAME_START"); for (Location door : WorldConfig.DOORS) { door.getBlock().setType(Material.AIR); door.clone().add(0, 1, 0).getBlock().setType(Material.AIR); } } else { throw new IllegalStateException("Game is already running!"); } } private static void generateLava() { for (int x = WorldConfig.MIN_TOWER.getBlockX(); x < WorldConfig.MAX_TOWER.getBlockX(); x += WorldConfig.LAVE_SPACE) { for (int z = WorldConfig.MIN_TOWER.getBlockZ(); z < WorldConfig.MAX_TOWER.getBlockZ(); z += WorldConfig.LAVE_SPACE) { Vector pos = new Vector(x, 0, z); if (Arrays.stream(WorldConfig.REGIONS).anyMatch(region -> region.contains(pos))) { int offset = WorldConfig.LAVA_Y; if (TowerRun.getTowerGenerator() != null) { offset += TowerRun.getTowerGenerator().getHeight(); } WorldConfig.MIN_TOWER.getWorld().getBlockAt(x, offset, z).setType(Material.LAVA, true); WorldConfig.MIN_TOWER.getWorld().getBlockAt(x, offset - 1, z).setType(Material.BEDROCK, true); } } } } public static void remove(TowerRunPlayer towerRunPlayer) { PLAYERS_ALIVE.remove(towerRunPlayer); PLAYERS_ESCAPED.remove(towerRunPlayer); } public static void tie() { Bukkit.getOnlinePlayers().forEach(player -> player.setGameMode(GameMode.SPECTATOR)); PLAYERS_ALIVE.clear(); Bukkit.getOnlinePlayers().forEach(player -> player.sendTitle(TowerRun.getMessage().parse("GAME_TIE", player), "", 10, 70, 20)); GameState.nextState(); if (Config.event()) { Config.EVENT_FIGHT.setErgebnis(3); } } public static void win(TowerRunPlayer tPlayer) { Bukkit.getOnlinePlayers().forEach(player -> player.setGameMode(GameMode.SPECTATOR)); PLAYERS_ALIVE.clear(); tPlayer.player().setGameMode(GameMode.SPECTATOR); TowerRun.getMessage().broadcast("GAME_WIN", tPlayer.player().getName()); Bukkit.getOnlinePlayers().forEach(player -> { player.sendTitle(TowerRun.getMessage().parse("GAME_WIN", player, tPlayer.player().getName()), "", 10, 70, 20); player.playSound(player.getLocation(), Sound.ENTITY_ENDER_DRAGON_DEATH, 1, 1); }); GameState.nextState(); if (Config.event()) { Config.EVENT_FIGHT.setErgebnis(SteamwarUser.get(tPlayer.player().getUniqueId()).getTeam() == Config.EVENT_TEAM_BLUE_ID ? 1 : 2); } } public static void reset() { PLAYERS_ALIVE.clear(); PLAYERS_ESCAPED.clear(); resetWorld(); GameState.reset(); Bukkit.getOnlinePlayers().forEach(player -> { if (TowerRun.getTowerGenerator() != null) { player.setGameMode(GameMode.SPECTATOR); } else { player.setGameMode(GameMode.SURVIVAL); } player.teleport(WorldConfig.SPAWN); PLAYERS_ALIVE.add(TowerRunPlayer.get(player)); }); } private static double posToChunk(int pos) { return pos / 16.0; } private static int getMinChunkX() { return (int) Math.floor(posToChunk(WorldConfig.MAP_MIN_X)); } private static int getMaxChunkX() { return (int) Math.ceil(posToChunk(WorldConfig.MAP_MAX_X)); } private static int getMinChunkZ() { return (int) Math.floor(posToChunk(WorldConfig.MAP_MIN_Z)); } private static int getMaxChunkZ() { return (int) Math.ceil(posToChunk(WorldConfig.MAP_MAX_Z)); } private static void forEachChunk(ObjIntConsumer executor) { for (int x = getMinChunkX(); x <= getMaxChunkX(); x++) for (int z = getMinChunkZ(); z <= getMaxChunkZ(); z++) executor.accept(x, z); } private static void resetWorld() { world.getEntities().stream().filter(entity -> entity.getType() != EntityType.PLAYER).forEach(Entity::remove); World backup = new WorldCreator(world.getName() + "/backup").createWorld(); assert backup != null; forEachChunk((x, z) -> resetChunk(backup, x, z)); Bukkit.unloadWorld(backup, false); } private static void resetChunk(World backup, int x, int z) { Chunk chunk = ((CraftWorld) world).getHandle().d(x, z); Chunk backupChunk = ((CraftWorld) backup).getHandle().d(x, z); System.arraycopy(backupChunk.d(), 0, chunk.d(), 0, chunk.d().length); for (Player p : Bukkit.getOnlinePlayers()) CraftbukkitWrapper.impl.sendChunk(p, x, z); } }