Add TowerRun module

This commit is contained in:
2024-08-05 09:02:07 +02:00
parent a760366d30
commit d4af6d9ddb
29 changed files with 2293 additions and 1 deletions
@@ -0,0 +1,184 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*/
package de.steamwar.towerrun.game;
import de.steamwar.core.CraftbukkitWrapper;
import de.steamwar.towerrun.TowerRun;
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<TowerRunPlayer> PLAYERS_ALIVE = new ArrayList<>();
public static final List<TowerRunPlayer> PLAYERS_ESCAPED = new ArrayList<>();
private static final World world = Bukkit.getWorlds().get(0);
public static boolean isAlive(TowerRunPlayer player) {
return PLAYERS_ALIVE.contains(player);
}
public static void prepareTowerOrStart() {
if (GameState.getCurrentState() == GameStates.LOBBY) {
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.addAll(TowerRunPlayer.getAll());
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();
}
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();
}
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);
});
}
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<Integer> 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);
}
}
@@ -0,0 +1,64 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*/
package de.steamwar.towerrun.game;
import de.steamwar.towerrun.TowerRun;
import de.steamwar.towerrun.config.WorldConfig;
import org.bukkit.entity.Player;
import org.bukkit.util.Vector;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
public record TowerRunPlayer(Player player) {
private static final Map<Player, TowerRunPlayer> players = new HashMap<>();
public static TowerRunPlayer get(Player player) {
return players.computeIfAbsent(player, TowerRunPlayer::new);
}
public static void remove(Player player) {
players.remove(player);
}
public static Collection<TowerRunPlayer> getAll() {
return players.values();
}
public void reset() {
player.getInventory().clear();
player.updateInventory();
player.setHealth(20);
if (TowerRun.getTowerGenerator() != null) {
player.teleport(TowerRun.getTowerGenerator().getSpawn());
} else {
player.teleport(WorldConfig.SPAWN);
}
player.setVelocity(new Vector(0, 0, 0));
}
@Override
public String toString() {
return "TowerRunPlayer{" +
"player=" + player.getName() +
'}';
}
}