From 910c578f9934d1e575ac84dfad18561bf017eb65 Mon Sep 17 00:00:00 2001
From: YuTian <2953516620@qq.com>
Date: Fri, 5 Jul 2024 00:07:50 +0800
Subject: [PATCH] =?UTF-8?q?=E7=AC=AC=E4=B8=80=E6=AC=A1=E6=8F=90=E4=BA=A4?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.gitignore | 3 +
pom.xml | 84 ++++
.../yutian/colorblindwar/ColorblindWar.java | 86 ++++
.../colorblindwar/game/DirectionPoint.java | 84 ++++
.../io/yutian/colorblindwar/game/Game.java | 359 +++++++++++++++
.../yutian/colorblindwar/game/GameConfig.java | 91 ++++
.../io/yutian/colorblindwar/game/Point.java | 106 +++++
.../io/yutian/colorblindwar/game/Region.java | 51 +++
.../listener/PlayerListener.java | 85 ++++
.../colorblindwar/util/BossBarUtil.java | 17 +
.../colorblindwar/util/BuildSpawner.java | 415 ++++++++++++++++++
.../yutian/colorblindwar/util/ColorUtil.java | 77 ++++
.../yutian/colorblindwar/util/MathUtil.java | 29 ++
.../yutian/colorblindwar/util/RandomUtil.java | 45 ++
src/main/resources/config.yml | 2 +
src/main/resources/plugin.yml | 9 +
16 files changed, 1543 insertions(+)
create mode 100644 .gitignore
create mode 100644 pom.xml
create mode 100644 src/main/java/com/io/yutian/colorblindwar/ColorblindWar.java
create mode 100644 src/main/java/com/io/yutian/colorblindwar/game/DirectionPoint.java
create mode 100644 src/main/java/com/io/yutian/colorblindwar/game/Game.java
create mode 100644 src/main/java/com/io/yutian/colorblindwar/game/GameConfig.java
create mode 100644 src/main/java/com/io/yutian/colorblindwar/game/Point.java
create mode 100644 src/main/java/com/io/yutian/colorblindwar/game/Region.java
create mode 100644 src/main/java/com/io/yutian/colorblindwar/listener/PlayerListener.java
create mode 100644 src/main/java/com/io/yutian/colorblindwar/util/BossBarUtil.java
create mode 100644 src/main/java/com/io/yutian/colorblindwar/util/BuildSpawner.java
create mode 100644 src/main/java/com/io/yutian/colorblindwar/util/ColorUtil.java
create mode 100644 src/main/java/com/io/yutian/colorblindwar/util/MathUtil.java
create mode 100644 src/main/java/com/io/yutian/colorblindwar/util/RandomUtil.java
create mode 100644 src/main/resources/config.yml
create mode 100644 src/main/resources/plugin.yml
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..16e8794
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,3 @@
+/ColorblindWar.iml
+/.idea/
+/target/
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..046248a
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,84 @@
+
+
+ 4.0.0
+
+ com.io.yutian
+ ColorblindWar
+ 1.0-SNAPSHOT
+ jar
+
+ ColorblindWar
+
+
+ 1.8
+ UTF-8
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ 3.8.1
+
+
+ ${java.version}
+
+
+
+ org.apache.maven.plugins
+ maven-shade-plugin
+ 3.2.4
+
+
+ package
+
+ shade
+
+
+ false
+
+
+
+
+
+
+
+ src/main/resources
+ true
+
+
+
+
+
+
+ papermc-repo
+ https://repo.papermc.io/repository/maven-public/
+
+
+ sonatype
+ https://oss.sonatype.org/content/groups/public/
+
+
+ public
+ http://111.230.48.153:18081/repository/public/
+
+
+
+
+
+ io.papermc.paper
+ paper-api
+ 1.18.2-R0.1-SNAPSHOT
+ provided
+
+
+ com.fastasyncworldedit.bukkit
+ FastAsyncWorldEdit
+ 2.9.1
+ 660
+
+
+
diff --git a/src/main/java/com/io/yutian/colorblindwar/ColorblindWar.java b/src/main/java/com/io/yutian/colorblindwar/ColorblindWar.java
new file mode 100644
index 0000000..bb6f3d4
--- /dev/null
+++ b/src/main/java/com/io/yutian/colorblindwar/ColorblindWar.java
@@ -0,0 +1,86 @@
+package com.io.yutian.colorblindwar;
+
+import com.io.yutian.colorblindwar.game.DirectionPoint;
+import com.io.yutian.colorblindwar.game.Game;
+import com.io.yutian.colorblindwar.listener.PlayerListener;
+import org.bukkit.Bukkit;
+import org.bukkit.command.Command;
+import org.bukkit.command.CommandSender;
+import org.bukkit.entity.Player;
+import org.bukkit.plugin.java.JavaPlugin;
+
+public final class ColorblindWar extends JavaPlugin {
+
+ private static ColorblindWar instance;
+ private static Game game;
+
+ @Override
+ public void onEnable() {
+ instance = this;
+ game = new Game();
+ Bukkit.getPluginManager().registerEvents(new PlayerListener(), this);
+ }
+
+ @Override
+ public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
+ if (args.length == 0) {
+ sender.sendMessage("/cw create - 创建游戏");
+ sender.sendMessage("/cw start - 开始游戏");
+ sender.sendMessage("/cw stop - 结束游戏");
+ sender.sendMessage("/gw reload - 重载");
+ return true;
+ } else {
+ String subCommand = args[0];
+ if (subCommand.equalsIgnoreCase("create")) {
+ if (!(sender instanceof Player)) {
+ sender.sendMessage("非玩家无法创建游戏");
+ return true;
+ }
+ Player player = (Player) sender;
+ game.setWorld(player.getWorld());
+ game.setSpawnPoint(DirectionPoint.of(player.getLocation()));
+ game.reload();
+ player.sendMessage("成功创建游戏");
+ } else if (subCommand.equalsIgnoreCase("start")) {
+ if (!(sender instanceof Player)) {
+ sender.sendMessage("非玩家无法开始游戏");
+ return true;
+ }
+ if (game.isStarted()) {
+ sender.sendMessage("游戏已开始");
+ return true;
+ }
+ Player player = (Player) sender;
+ game.start(player);
+ } else if (subCommand.equalsIgnoreCase("stop")) {
+ if (!game.isStarted()) {
+ sender.sendMessage("游戏未开始");
+ return true;
+ }
+ Player player = (Player) sender;
+ game.stop(false);
+ } else if (subCommand.equalsIgnoreCase("reload")) {
+ game.reload();
+ sender.sendMessage("重载成功");
+ } else if (subCommand.equalsIgnoreCase("test")) {
+ if (args[1].equalsIgnoreCase("spawn")) {
+ game.spawnBuild();
+ } else if (args[1].equalsIgnoreCase("clear")) {
+ game.clearBlock();
+ } else if (args[1].equalsIgnoreCase("v")) {
+ game.vanishBlock();
+ }
+ }
+ }
+ return true;
+ }
+
+ public static ColorblindWar inst() {
+ return instance;
+ }
+
+ public static Game getGame() {
+ return game;
+ }
+
+}
diff --git a/src/main/java/com/io/yutian/colorblindwar/game/DirectionPoint.java b/src/main/java/com/io/yutian/colorblindwar/game/DirectionPoint.java
new file mode 100644
index 0000000..2ebb655
--- /dev/null
+++ b/src/main/java/com/io/yutian/colorblindwar/game/DirectionPoint.java
@@ -0,0 +1,84 @@
+package com.io.yutian.colorblindwar.game;
+
+import org.bukkit.Location;
+import org.bukkit.World;
+import org.bukkit.configuration.ConfigurationSection;
+
+import java.util.Objects;
+
+public class DirectionPoint extends Point {
+
+ private float yaw;
+ private float pitch;
+
+ public DirectionPoint(int x, int y, int z, float yaw, float pitch) {
+ super(x, y, z);
+ this.yaw = yaw;
+ this.pitch = pitch;
+ }
+
+ public DirectionPoint(double x, double y, double z) {
+ this(x, y, z, 0f, 0f);
+ }
+
+ public DirectionPoint(double x, double y, double z, float yaw, float pitch) {
+ super(x, y, z);
+ this.yaw = yaw;
+ this.pitch = pitch;
+ }
+
+ public float getPitch() {
+ return pitch;
+ }
+
+ public float getYaw() {
+ return yaw;
+ }
+
+ public void setYaw(float yaw) {
+ this.yaw = yaw;
+ }
+
+ public void setPitch(float pitch) {
+ this.pitch = pitch;
+ }
+
+ @Override
+ public Location toLocation(World world) {
+ return new Location(world, getX(), getY(), getZ(), yaw, pitch);
+ }
+
+ public static DirectionPoint of(Location location) {
+ return new DirectionPoint(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch());
+ }
+
+ @Override
+ public String toString() {
+ return "DirectionPoint{" +
+ "x=" + getX() +
+ ", y=" + getY() +
+ ", z=" + getZ() +
+ ", yaw=" + yaw +
+ ", pitch=" + pitch +
+ '}';
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ if (!super.equals(o)) return false;
+ DirectionPoint that = (DirectionPoint) o;
+ return super.equals(o) && Float.compare(that.yaw, yaw) == 0 && Float.compare(that.pitch, pitch) == 0;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(super.hashCode(), yaw, pitch);
+ }
+
+ public static DirectionPoint deserialize(ConfigurationSection section) {
+ return new DirectionPoint(section.getDouble("x"), section.getDouble("y"), section.getDouble("z"), (float) section.getDouble("yaw"), (float) section.getDouble("pitch"));
+ }
+
+}
diff --git a/src/main/java/com/io/yutian/colorblindwar/game/Game.java b/src/main/java/com/io/yutian/colorblindwar/game/Game.java
new file mode 100644
index 0000000..b1db256
--- /dev/null
+++ b/src/main/java/com/io/yutian/colorblindwar/game/Game.java
@@ -0,0 +1,359 @@
+package com.io.yutian.colorblindwar.game;
+
+import com.io.yutian.colorblindwar.ColorblindWar;
+import com.io.yutian.colorblindwar.util.*;
+import com.sk89q.worldedit.EditSession;
+import com.sk89q.worldedit.WorldEdit;
+import com.sk89q.worldedit.bukkit.BukkitAdapter;
+import com.sk89q.worldedit.function.mask.BlockTypeMask;
+import com.sk89q.worldedit.function.mask.InverseSingleBlockTypeMask;
+import com.sk89q.worldedit.function.mask.Mask;
+import com.sk89q.worldedit.function.operation.Operations;
+import com.sk89q.worldedit.math.BlockVector3;
+import com.sk89q.worldedit.regions.CuboidRegion;
+import com.sk89q.worldedit.world.block.BlockTypes;
+import net.kyori.adventure.text.Component;
+import net.kyori.adventure.text.TextComponent;
+import net.kyori.adventure.text.format.TextColor;
+import org.bukkit.*;
+import org.bukkit.boss.BarColor;
+import org.bukkit.boss.BarStyle;
+import org.bukkit.boss.BossBar;
+import org.bukkit.configuration.ConfigurationSection;
+import org.bukkit.configuration.file.FileConfiguration;
+import org.bukkit.entity.Entity;
+import org.bukkit.entity.Firework;
+import org.bukkit.entity.Player;
+import org.bukkit.inventory.ItemStack;
+import org.bukkit.inventory.meta.FireworkMeta;
+import org.bukkit.inventory.meta.ItemMeta;
+import org.bukkit.scheduler.BukkitRunnable;
+import org.bukkit.scheduler.BukkitTask;
+
+import java.util.*;
+
+public class Game {
+
+ private static final List MATERIAL_LIST = Arrays.asList(Material.WHITE_WOOL, Material.BLACK_WOOL, Material.BROWN_WOOL, Material.BLUE_WOOL, Material.GREEN_WOOL, Material.RED_WOOL, Material.YELLOW_WOOL, Material.PURPLE_WOOL, Material.ORANGE_WOOL, Material.PINK_WOOL, Material.LIGHT_BLUE_WOOL, Material.LIME_WOOL);
+
+
+ private World world;
+ private DirectionPoint spawnPoint;
+
+ private Player player;
+
+ private BossBar bossBar1;
+ private BossBar bossBar2;
+ private BossBar bossBar3;
+ private BossBar bossBar4;
+
+ private List tasks = new ArrayList<>();
+ private List entities = new ArrayList<>();
+
+ private int challengeAmount = 0;
+ private int vanishCountdown = 0;
+ private int vanishCooldown = 0;
+ private Material vanishMaterial = Material.AIR;
+
+ private boolean started = false;
+
+ private GameConfig gameConfig;
+ private BuildSpawner buildSpawner;
+
+ public Game() {
+ reload();
+ this.bossBar1 = Bukkit.createBossBar("今日挑战进度", BarColor.WHITE, BarStyle.SEGMENTED_10);
+ this.bossBar2 = Bukkit.createBossBar("爬塔进度", BarColor.WHITE, BarStyle.SEGMENTED_20);
+ this.bossBar3 = Bukkit.createBossBar("方块消失倒计时", BarColor.WHITE, BarStyle.SOLID);
+ this.bossBar4 = Bukkit.createBossBar("方块出现倒计时", BarColor.WHITE, BarStyle.SOLID);
+ }
+
+ public void reload() {
+ ColorblindWar.inst().saveDefaultConfig();
+ ColorblindWar.inst().reloadConfig();
+ FileConfiguration config = ColorblindWar.inst().getConfig();
+ if (config.contains("world")) {
+ this.world = Bukkit.getWorld(config.getString("world"));
+ }
+ if (config.contains("spawnPoint") && config.isConfigurationSection("spawnPoint")) {
+ this.spawnPoint = DirectionPoint.deserialize(config.getConfigurationSection("spawnPoint"));
+ }
+ if (world == null || spawnPoint == null) {
+ return;
+ }
+ BuildSpawner.Direction initialDirection = BuildSpawner.Direction.NORTH;
+ int chunkWight = 2;
+ int chunkLength = 2;
+ int ladderLength = 3;
+ int ladderAmount = 5;
+ int platformWidth = 3;
+ int platformLength = 7;
+ int levelAmount = 10;
+ BuildSpawner.SpawnMode spawnMode = BuildSpawner.SpawnMode.MODE_2;
+ int completeAmount = config.getInt("completeAmount", 10);
+ int countdownTime = config.getInt("countdownTime", 15);
+ this.gameConfig = new GameConfig(initialDirection, chunkWight, chunkLength, ladderLength, ladderAmount, platformWidth, platformLength, levelAmount, spawnMode, MATERIAL_LIST, completeAmount, countdownTime);
+ this.buildSpawner = gameConfig.getSpawner(world, spawnPoint);
+ this.vanishCountdown = gameConfig.getCountdownTime() * 20;
+ }
+
+ public void start(Player player) {
+ if (started) {
+ return;
+ }
+ if (world == null || spawnPoint == null) {
+ return;
+ }
+ this.started = true;
+ this.player = player;
+ this.challengeAmount = 0;
+ this.vanishCountdown = gameConfig.getCountdownTime() * 20;
+ initWorld();
+ updateBossBar();
+ this.bossBar1.addPlayer(player);
+ this.bossBar2.addPlayer(player);
+ this.bossBar3.addPlayer(player);
+ this.bossBar4.addPlayer(player);
+ spawnBuild();
+ changeVanishMaterial();
+ player.teleport(spawnPoint.toLocation(world));
+ this.tasks.add(new BukkitRunnable() {
+ @Override
+ public void run() {
+ updateBossBar();
+ }
+ }.runTaskTimer(ColorblindWar.inst(), 0L, 10L));
+ this.tasks.add(new BukkitRunnable() {
+ @Override
+ public void run() {
+ updateVanishCountdown();
+ }
+ }.runTaskTimer(ColorblindWar.inst(), 0L, 1L));
+ }
+
+ private void initWorld() {
+ this.world.setGameRule(GameRule.DO_DAYLIGHT_CYCLE, false);
+ this.world.setGameRule(GameRule.DO_WEATHER_CYCLE, false);
+ this.world.setGameRule(GameRule.DO_MOB_SPAWNING, false);
+ this.world.setGameRule(GameRule.DO_MOB_LOOT, false);
+ this.world.setGameRule(GameRule.MOB_GRIEFING, false);
+ this.world.setTime(6000);
+ }
+
+ public void stop(boolean win) {
+ if (!started) {
+ return;
+ }
+ this.started = false;
+ for (Entity entity : entities) {
+ entity.remove();
+ }
+ this.bossBar1.removeAll();
+ this.bossBar2.removeAll();
+ this.bossBar3.removeAll();
+ this.bossBar4.removeAll();
+ this.player.getInventory().clear();
+ this.player.teleport(spawnPoint.toLocation(world));
+ this.entities.clear();
+ if (win) {
+ new BukkitRunnable() {
+ private int i = 0;
+ @Override
+ public void run() {
+ if (i >= 20) {
+ cancel();
+ return;
+ }
+ player.getWorld().spawn(player.getLocation(), Firework.class, (firework -> {
+ FireworkMeta fireworkMeta = firework.getFireworkMeta();
+ fireworkMeta.addEffect(FireworkEffect.builder().withColor(Color.TEAL, Color.RED, Color.GREEN, Color.YELLOW, Color.LIME).trail(true).build());
+ Random random = new Random();
+ for (int i = 0; i < RandomUtil.getRandomInt(1, 2); i++) {
+ FireworkEffect effect = FireworkEffect.builder().flicker(random.nextBoolean()).withColor(Color.fromRGB(RandomUtil.getRandomInt(100, 255), RandomUtil.getRandomInt(100, 255), RandomUtil.getRandomInt(100, 255))).withFade(Color.fromRGB(RandomUtil.getRandomInt(100, 255), RandomUtil.getRandomInt(100, 255), RandomUtil.getRandomInt(100, 255))).with(FireworkEffect.Type.values()[random.nextInt(FireworkEffect.Type.values().length)]).trail(random.nextBoolean()).build();
+ fireworkMeta.addEffect(effect);
+ }
+ fireworkMeta.setPower(random.nextInt(2));
+ firework.setFireworkMeta(fireworkMeta);
+ }));
+ i++;
+ }
+ }.runTaskTimer(ColorblindWar.inst(), 0L, 5L);
+ player.sendMessage("§c[系统]§ a今日挑战已完成! 恭喜你!");
+ start(player);
+ } else {
+ player.sendMessage("§c[系统] §a游戏已被强制结束!");
+ }
+ tasks.forEach(task -> {
+ if (!task.isCancelled()) {
+ task.cancel();
+ }
+ });
+ }
+
+ private void updateBossBar() {
+ int completeAmount = gameConfig.getCompleteAmount();
+ double d = (double) challengeAmount / (double) completeAmount;
+ bossBar1.setTitle("§6今日挑战进度: §f"+challengeAmount+"/"+completeAmount);
+ if (d < 0) {
+ d = 0;
+ }
+ bossBar1.setProgress(d);
+ bossBar1.setColor(BossBarUtil.getBarColor(d));
+ int maxHeight = spawnPoint.getBlockY() + buildSpawner.getHeight();
+ int nowHeight = player.getLocation().getBlockY();
+ int c1 = nowHeight - spawnPoint.getBlockY();
+ c1 = Math.max(c1, 0);
+ double d1 = (double) c1 / (double) buildSpawner.getHeight();
+ d1 = Math.min(d1, 1.0);
+ double d2 = MathUtil.round(d1 * 100, 2);
+ bossBar2.setTitle("§6爬塔进度: §f"+c1+"/"+buildSpawner.getHeight()+" §b("+d2+"%)");
+ bossBar2.setProgress(d1);
+ bossBar2.setColor(BossBarUtil.getBarColor(d1));
+ sendActionBar();
+ }
+
+ private void updateVanishCountdown() {
+ if (vanishCooldown > 0) {
+ vanishCooldown--;
+ if (bossBar3.isVisible()) {
+ bossBar3.setVisible(false);
+ }
+ if (!bossBar4.isVisible()) {
+ bossBar4.setVisible(true);
+ }
+ bossBar4.setTitle("§6方块出现倒计时: §f"+ MathUtil.round(vanishCooldown / (double) 20, 1) +"s");
+ double p = vanishCooldown / (double) 60;
+ bossBar4.setProgress(p);
+ bossBar4.setColor(BossBarUtil.getBarColor(p));
+ if (vanishCooldown == 0) {
+ bossBar4.setVisible(false);
+ startVanishCountdown();
+ return;
+ }
+ return;
+ } else {
+ if (!bossBar3.isVisible()) {
+ bossBar3.setVisible(true);
+ }
+ if (bossBar4.isVisible()) {
+ bossBar4.setVisible(false);
+ }
+ }
+ if (vanishCountdown > 0) {
+ vanishCountdown--;
+ if (vanishCountdown <= 100 && vanishCountdown % 20 == 0) {
+ player.playSound(player.getLocation(), Sound.BLOCK_NOTE_BLOCK_GUITAR, 1.0F, 1.0F);
+ }
+ bossBar3.setTitle("§6方块消失倒计时: §f"+ MathUtil.round(vanishCountdown / (double) 20, 1) +"s");
+ double p = vanishCountdown / (double) (gameConfig.getCountdownTime() * 20);
+ bossBar3.setProgress(p);
+ bossBar3.setColor(BossBarUtil.getBarColor(p));
+ } else {
+ vanishBlock();
+ for (int i = 0; i < 9; i++) {
+ player.getInventory().setItem(i, null);
+ }
+ vanishCooldown = 60;
+ bossBar3.setVisible(false);
+ }
+ }
+
+ private void startVanishCountdown() {
+ vanishCountdown = gameConfig.getCountdownTime() * 20;
+ spawnBuild();
+ changeVanishMaterial();
+ }
+
+ private void changeVanishMaterial() {
+ vanishMaterial = buildSpawner.getRandomMaterial();
+ ItemStack itemStack = new ItemStack(vanishMaterial);
+ ItemMeta itemMeta = itemStack.getItemMeta();
+ itemMeta.setDisplayName("");
+ itemStack.setItemMeta(itemMeta);
+ for (int i = 0; i < 9; i++) {
+ player.getInventory().setItem(i, itemStack);
+ }
+ }
+
+ private void sendActionBar() {
+ Component message = Component.text("§l"+ ColorUtil.getColorName(vanishMaterial))
+ .color(TextColor.fromHexString(ColorUtil.getColorHex(vanishMaterial)));
+ player.sendActionBar(message);
+ }
+
+ public void spawnBuild() {
+ buildSpawner.spawn();
+ }
+
+ public void vanishBlock() {
+ Material material = vanishMaterial;
+ Region region = buildSpawner.getEffectiveRegion(world);
+ Point minPoint = region.getMin();
+ Point maxPoint = region.getMax();
+ BlockVector3 newVector1 = BlockVector3.at(minPoint.getX(), minPoint.getY(), minPoint.getZ());
+ BlockVector3 newVector2 = BlockVector3.at(maxPoint.getX(), maxPoint.getY(), maxPoint.getZ());
+ CuboidRegion cuboidRegion = new CuboidRegion(BukkitAdapter.adapt(region.getWorld()),newVector1,newVector2);
+ try (EditSession editSession = WorldEdit.getInstance().newEditSession(BukkitAdapter.adapt(region.getWorld()))) {
+ Mask mask = new InverseSingleBlockTypeMask(editSession, BukkitAdapter.asBlockType(material));
+ editSession.replaceBlocks(cuboidRegion, mask, BlockTypes.AIR.getDefaultState());
+ Operations.complete(editSession.commit());
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ public void clearBlock() {
+ Region region = buildSpawner.getEffectiveRegion(world);
+ Point minPoint = region.getMin();
+ Point maxPoint = region.getMax();
+ BlockVector3 newVector1 = BlockVector3.at(minPoint.getX(), minPoint.getY(), minPoint.getZ());
+ BlockVector3 newVector2 = BlockVector3.at(maxPoint.getX(), maxPoint.getY(), maxPoint.getZ());
+ CuboidRegion cuboidRegion = new CuboidRegion(BukkitAdapter.adapt(region.getWorld()),newVector1,newVector2);
+ try (EditSession editSession = WorldEdit.getInstance().newEditSession(BukkitAdapter.adapt(region.getWorld()))) {
+ editSession.setBlocks((com.sk89q.worldedit.regions.Region) cuboidRegion, BlockTypes.AIR.getDefaultState());
+ Operations.complete(editSession.commit());
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ public void setWorld(World world) {
+ this.world = world;
+ FileConfiguration config = ColorblindWar.inst().getConfig();
+ config.set("world", world.getName());
+ ColorblindWar.inst().saveConfig();
+ }
+
+ public void setSpawnPoint(DirectionPoint spawnPoint) {
+ this.spawnPoint = spawnPoint;
+ FileConfiguration config = ColorblindWar.inst().getConfig();
+ ConfigurationSection section1 = config.getConfigurationSection("spawnPoint");
+ section1.set("x", spawnPoint.getX());
+ section1.set("y", spawnPoint.getY());
+ section1.set("z", spawnPoint.getZ());
+ section1.set("yaw", spawnPoint.getYaw());
+ section1.set("pitch", spawnPoint.getPitch());
+ ColorblindWar.inst().saveConfig();
+ }
+
+ public boolean isStarted() {
+ return started;
+ }
+
+ public World getWorld() {
+ return world;
+ }
+
+ public Point getSpawnPoint() {
+ return spawnPoint;
+ }
+
+ public GameConfig getGameConfig() {
+ return gameConfig;
+ }
+
+ public BuildSpawner getBuildSpawner() {
+ return buildSpawner;
+ }
+
+}
diff --git a/src/main/java/com/io/yutian/colorblindwar/game/GameConfig.java b/src/main/java/com/io/yutian/colorblindwar/game/GameConfig.java
new file mode 100644
index 0000000..8426c72
--- /dev/null
+++ b/src/main/java/com/io/yutian/colorblindwar/game/GameConfig.java
@@ -0,0 +1,91 @@
+package com.io.yutian.colorblindwar.game;
+
+import com.io.yutian.colorblindwar.util.BuildSpawner;
+import org.bukkit.Material;
+import org.bukkit.World;
+
+import java.util.List;
+
+public class GameConfig {
+
+ private BuildSpawner.Direction initialDirection;
+ private int chunkWight;
+ private int chunkHeight;
+ private int ladderLength;
+ private int ladderAmount;
+ private int platformWidth;
+ private int platformLength;
+ private int levelAmount;
+ private BuildSpawner.SpawnMode spawnMode;
+ private List materials;
+
+ private int completeAmount = 10;
+ private int countdownTime = 15;
+
+ public GameConfig(BuildSpawner.Direction initialDirection, int chunkWight, int chunkHeight, int ladderLength, int ladderAmount, int platformWidth, int platformLength, int levelAmount, BuildSpawner.SpawnMode spawnMode, List materials, int completeAmount, int countdownTime) {
+ this.initialDirection = initialDirection;
+ this.chunkWight = chunkWight;
+ this.chunkHeight = chunkHeight;
+ this.ladderLength = ladderLength;
+ this.ladderAmount = ladderAmount;
+ this.platformWidth = platformWidth;
+ this.platformLength = platformLength;
+ this.levelAmount = levelAmount;
+ this.spawnMode = spawnMode;
+ this.materials = materials;
+ this.completeAmount = completeAmount;
+ this.countdownTime = countdownTime;
+ }
+
+ public BuildSpawner.Direction getInitialDirection() {
+ return initialDirection;
+ }
+
+ public int getChunkWight() {
+ return chunkWight;
+ }
+
+ public int getChunkHeight() {
+ return chunkHeight;
+ }
+
+ public int getLadderLength() {
+ return ladderLength;
+ }
+
+ public int getLadderAmount() {
+ return ladderAmount;
+ }
+
+ public int getPlatformWidth() {
+ return platformWidth;
+ }
+
+ public int getPlatformLength() {
+ return platformLength;
+ }
+
+ public int getLevelAmount() {
+ return levelAmount;
+ }
+
+ public BuildSpawner.SpawnMode getSpawnMode() {
+ return spawnMode;
+ }
+
+ public List getMaterials() {
+ return materials;
+ }
+
+ public int getCompleteAmount() {
+ return completeAmount;
+ }
+
+ public int getCountdownTime() {
+ return countdownTime;
+ }
+
+ public BuildSpawner getSpawner(World world, Point point) {
+ return new BuildSpawner(world, initialDirection, point.getBlockX(), point.getBlockY() - 1, point.getBlockZ(), chunkWight, chunkHeight, ladderLength, ladderAmount, platformWidth, platformLength, levelAmount, spawnMode, materials);
+ }
+}
diff --git a/src/main/java/com/io/yutian/colorblindwar/game/Point.java b/src/main/java/com/io/yutian/colorblindwar/game/Point.java
new file mode 100644
index 0000000..fbe0158
--- /dev/null
+++ b/src/main/java/com/io/yutian/colorblindwar/game/Point.java
@@ -0,0 +1,106 @@
+package com.io.yutian.colorblindwar.game;
+
+import com.sk89q.worldedit.math.BlockVector3;
+import org.bukkit.Location;
+import org.bukkit.World;
+import org.bukkit.configuration.ConfigurationSection;
+
+import java.util.Objects;
+
+public class Point {
+
+ private double x;
+ private double y;
+ private double z;
+
+ public Point(int x, int y, int z) {
+ this.x = x;
+ this.y = y;
+ this.z = z;
+ }
+
+ public Point(double x, double y, double z) {
+ this.x = x;
+ this.y = y;
+ this.z = z;
+ }
+
+ public int getBlockX() {
+ return (int) Math.floor(x);
+ }
+
+ public int getBlockY() {
+ return (int) Math.floor(y);
+ }
+
+ public int getBlockZ() {
+ return (int) Math.floor(z);
+ }
+
+ public double getX() {
+ return x;
+ }
+
+ public double getY() {
+ return y;
+ }
+
+ public double getZ() {
+ return z;
+ }
+
+ public void setX(double x) {
+ this.x = x;
+ }
+
+ public void setY(double y) {
+ this.y = y;
+ }
+
+ public void setZ(double z) {
+ this.z = z;
+ }
+
+ public Point clone() {
+ return new Point(x, y, z);
+ }
+
+ public Location toLocation(World world) {
+ return new Location(world, x, y, z, 0, 0);
+ }
+
+ public static Point of(Location location) {
+ return new Point(location.getX(), location.getY(), location.getZ());
+ }
+
+ public static Point deserialize(ConfigurationSection section) {
+ return new Point(section.getDouble("x"), section.getDouble("y"), section.getDouble("z"));
+ }
+
+ public BlockVector3 toBlockVector3() {
+ return BlockVector3.at(x, y, z);
+ }
+
+ @Override
+ public String toString() {
+ return "Point{" +
+ "x=" + x +
+ ", y=" + y +
+ ", z=" + z +
+ '}';
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ Point point = (Point) o;
+ return Double.compare(point.x, x) == 0 && Double.compare(point.y, y) == 0 && Double.compare(point.z, z) == 0;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(x, y, z);
+ }
+
+}
diff --git a/src/main/java/com/io/yutian/colorblindwar/game/Region.java b/src/main/java/com/io/yutian/colorblindwar/game/Region.java
new file mode 100644
index 0000000..700ed64
--- /dev/null
+++ b/src/main/java/com/io/yutian/colorblindwar/game/Region.java
@@ -0,0 +1,51 @@
+package com.io.yutian.colorblindwar.game;
+
+import org.bukkit.Bukkit;
+import org.bukkit.Location;
+import org.bukkit.World;
+import org.bukkit.configuration.ConfigurationSection;
+
+public class Region {
+
+ private World world;
+ private Point min;
+ private Point max;
+
+ public Region(World world, Point min, Point max) {
+ this.world = world;
+ this.min = min;
+ this.max = max;
+ }
+
+ public World getWorld() {
+ return world;
+ }
+
+ public Point getMin() {
+ return min;
+ }
+
+ public Point getMax() {
+ return max;
+ }
+
+ public static Region deserialize(ConfigurationSection section) {
+ World world1 = Bukkit.getWorld(section.getString("world"));
+ Point point1 = Point.deserialize(section.getConfigurationSection("min"));
+ Point point2 = Point.deserialize(section.getConfigurationSection("max"));
+ return new Region(world1, point1, point2);
+ }
+
+ public boolean isInRegion(Location location) {
+ if (!location.getWorld().getName().equalsIgnoreCase(world.getName())) {
+ return false;
+ }
+ return (location.getBlockX() >= this.min.getX()
+ && location.getBlockX() <= this.max.getX()
+ && location.getBlockY() >= this.min.getY()
+ && location.getBlockY() <= this.max.getY()
+ && location.getBlockZ() >= this.min.getZ()
+ && location.getBlockZ() <= this.max.getZ());
+ }
+
+}
diff --git a/src/main/java/com/io/yutian/colorblindwar/listener/PlayerListener.java b/src/main/java/com/io/yutian/colorblindwar/listener/PlayerListener.java
new file mode 100644
index 0000000..b2e21ae
--- /dev/null
+++ b/src/main/java/com/io/yutian/colorblindwar/listener/PlayerListener.java
@@ -0,0 +1,85 @@
+package com.io.yutian.colorblindwar.listener;
+
+import com.io.yutian.colorblindwar.ColorblindWar;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.Listener;
+import org.bukkit.event.block.*;
+import org.bukkit.event.entity.EntityExplodeEvent;
+import org.bukkit.event.inventory.InventoryClickEvent;
+import org.bukkit.event.player.PlayerDropItemEvent;
+import org.bukkit.event.player.PlayerQuitEvent;
+import org.bukkit.event.weather.WeatherChangeEvent;
+
+public class PlayerListener implements Listener {
+
+ @EventHandler
+ public void onPlayerQuit(PlayerQuitEvent event) {
+ if (ColorblindWar.getGame().isStarted()) {
+ ColorblindWar.getGame().stop(false);
+ }
+ }
+
+ @EventHandler
+ public void onPlayerDropItem(PlayerDropItemEvent event) {
+ if (ColorblindWar.getGame().isStarted()) {
+ event.setCancelled(true);
+ }
+ }
+
+ @EventHandler
+ public void onInventoryClick(InventoryClickEvent event) {
+ if (ColorblindWar.getGame().isStarted()) {
+ event.setCancelled(true);
+ }
+ }
+
+ @EventHandler
+ public void onBlockBreak(BlockBreakEvent event) {
+ if (ColorblindWar.getGame().isStarted()) {
+ event.setCancelled(true);
+ }
+ }
+
+ @EventHandler
+ public void onBlockPlace(BlockPlaceEvent event) {
+ if (ColorblindWar.getGame().isStarted()) {
+ event.setCancelled(true);
+ }
+ }
+
+ @EventHandler
+ public void onEntityExplode(EntityExplodeEvent event) {
+ if (ColorblindWar.getGame().isStarted()) {
+ event.blockList().clear();
+ }
+ }
+
+ @EventHandler
+ public void onBlockExplode(BlockExplodeEvent event) {
+ if (ColorblindWar.getGame().isStarted()) {
+ event.blockList().clear();
+ }
+ }
+
+ @EventHandler
+ public void onWeatherChange(WeatherChangeEvent event) {
+ if (ColorblindWar.getGame().isStarted()) {
+ event.setCancelled(true);
+ }
+ }
+
+ @EventHandler
+ public void onBlockFire(BlockBurnEvent event) {
+ if (ColorblindWar.getGame().isStarted()) {
+ event.setCancelled(true);
+ }
+ }
+
+ @EventHandler
+ public void onBlockIgnite(BlockIgniteEvent event) {
+ if (ColorblindWar.getGame().isStarted()) {
+ event.setCancelled(true);
+ }
+ }
+
+}
diff --git a/src/main/java/com/io/yutian/colorblindwar/util/BossBarUtil.java b/src/main/java/com/io/yutian/colorblindwar/util/BossBarUtil.java
new file mode 100644
index 0000000..09dee61
--- /dev/null
+++ b/src/main/java/com/io/yutian/colorblindwar/util/BossBarUtil.java
@@ -0,0 +1,17 @@
+package com.io.yutian.colorblindwar.util;
+
+import org.bukkit.boss.BarColor;
+
+public class BossBarUtil {
+
+ public static BarColor getBarColor(double d) {
+ if (d >= 0 && d <= 0.3333) {
+ return BarColor.RED;
+ } else if (d <= 0.6666) {
+ return BarColor.YELLOW;
+ } else {
+ return BarColor.GREEN;
+ }
+ }
+
+}
diff --git a/src/main/java/com/io/yutian/colorblindwar/util/BuildSpawner.java b/src/main/java/com/io/yutian/colorblindwar/util/BuildSpawner.java
new file mode 100644
index 0000000..1f8d356
--- /dev/null
+++ b/src/main/java/com/io/yutian/colorblindwar/util/BuildSpawner.java
@@ -0,0 +1,415 @@
+package com.io.yutian.colorblindwar.util;
+
+import com.io.yutian.colorblindwar.game.Point;
+import com.io.yutian.colorblindwar.game.Region;
+import org.bukkit.Material;
+import org.bukkit.World;
+import org.bukkit.util.Vector;
+
+import java.util.List;
+
+public class BuildSpawner {
+
+ private World world;
+ private Direction initialDirection;
+ private int originX;
+ private int originY;
+ private int originZ;
+ private int chunkWight;
+ private int chunkLength;
+ private int ladderLength;
+ private int ladderAmount;
+ private int platformWidth;
+ private int platformLength;
+ private int levelAmount;
+ private SpawnMode spawnMode;
+
+ private int nowX;
+ private int nowY;
+ private int nowZ;
+ private Direction nowDirection;
+
+ private List materials;
+
+ protected ISpawnModeHander spawnModeHander;
+
+ public BuildSpawner(World world, Direction initialDirection, int originX, int originY, int originZ, int chunkWight, int chunkLength, int ladderLength, int ladderAmount, int platformWidth, int platformLength, int levelAmount, SpawnMode spawnMode, List materials) {
+ this.world = world;
+ this.initialDirection = initialDirection;
+ this.originX = originX;
+ this.originY = originY;
+ this.originZ = originZ;
+ this.chunkWight = chunkWight;
+ this.chunkLength = chunkLength;
+ this.ladderLength = ladderLength;
+ this.ladderAmount = ladderAmount;
+ this.platformWidth = platformWidth;
+ this.platformLength = platformLength;
+ this.levelAmount = levelAmount;
+ this.spawnMode = spawnMode;
+ this.materials = materials;
+
+ nowX = originX;
+ nowY = originY;
+ nowZ = originZ;
+ nowDirection = initialDirection;
+ if (spawnMode == SpawnMode.MODE_1) {
+ spawnModeHander = new SpawnModeHandler_1();
+ } else if (spawnMode == SpawnMode.MODE_2) {
+ spawnModeHander = new SpawnModeHandler_2();
+ }
+ }
+
+ public void spawn() {
+ nowX = originX;
+ nowY = originY;
+ nowZ = originZ;
+ nowDirection = initialDirection;
+ if (spawnModeHander != null) {
+ spawnModeHander.spawn();
+ }
+ }
+
+ private void spawnPlatform(int x, int y, int z, Direction direction) {
+ if (direction == Direction.EAST || direction == Direction.WEST) {
+ for (int i = 0; i < platformLength; i++) {
+ for (int j = 0; j < platformWidth; j++) {
+ int x1 = x + (i * chunkWight) * direction.getPlatformVector().getBlockX();
+ int z1 = z + (j * chunkLength) * direction.getPlatformVector().getBlockZ();
+ spawnPlatformChunk(x1, y, z1, direction);
+ }
+ }
+ } else if (direction == Direction.NORTH || direction == Direction.SOUTH) {
+ for (int i = 0; i < platformLength; i++) {
+ for (int j = 0; j < platformWidth; j++) {
+ int x1 = x + (j * chunkLength) * direction.getPlatformVector().getBlockX();
+ int z1 = z + (i * chunkWight) * direction.getPlatformVector().getBlockZ();
+ spawnPlatformChunk(x1, y, z1, direction);
+ }
+ }
+ }
+ }
+
+ private void spawnLadder(int x, int y, int z, Direction direction) {
+ for (int i = 0; i < ladderAmount; i++) {
+ for (int j = 0; j < ladderLength; j++) {
+ int x1 = getLadderX(i, j, x, z, direction);
+ int z1 = getLadderZ(i, j, x, z, direction);
+ spawnLadderChunk(x1, y + i + 1, z1, direction);
+ }
+ }
+ }
+
+ private int getLadderX(int i, int j, int x, int z, Direction direction) {
+ switch (direction) {
+ case EAST:
+ case WEST:
+ return x + (i * chunkWight) * direction.getLadderVector().getBlockX();
+ case SOUTH:
+ case NORTH:
+ return x + (j * chunkLength) * direction.getLadderVector().getBlockX();
+ }
+ return x;
+ }
+
+ private int getLadderZ(int i, int j, int x, int z, Direction direction) {
+ switch (direction) {
+ case EAST:
+ case WEST:
+ return z + (j * chunkLength) * direction.getLadderVector().getBlockZ();
+ case SOUTH:
+ case NORTH:
+ return z + (i * chunkWight) * direction.getLadderVector().getBlockZ();
+ }
+ return z;
+ }
+
+ private void spawnPlatformChunk(int x, int y, int z, Direction direction) {
+ Material material = getRandomMaterial();
+ if (direction == Direction.EAST || direction == Direction.WEST) {
+ for (int i = 0; i < chunkWight; i++) {
+ for (int j = 0; j < chunkLength; j++) {
+ int x1 = x + i * direction.getPlatformVector().getBlockX();
+ int z1 = z + j * direction.getPlatformVector().getBlockZ();
+ world.getBlockAt(x1, y, z1).setType(material);
+ }
+ }
+ } else if (direction == Direction.NORTH || direction == Direction.SOUTH) {
+ for (int i = 0; i < chunkWight; i++) {
+ for (int j = 0; j < chunkLength; j++) {
+ int x1 = x + j * direction.getPlatformVector().getBlockX();
+ int z1 = z + i * direction.getPlatformVector().getBlockZ();
+ world.getBlockAt(x1, y, z1).setType(material);
+ }
+ }
+ }
+ }
+
+ private void spawnLadderChunk(int x, int y, int z, Direction direction) {
+ Material material = getRandomMaterial();
+ if (direction == Direction.EAST || direction == Direction.WEST) {
+ for (int i = 0; i < chunkWight; i++) {
+ for (int j = 0; j < chunkLength; j++) {
+ int x1 = x + i * direction.getLadderVector().getBlockX();
+ int z1 = z + j * direction.getLadderVector().getBlockZ();
+ world.getBlockAt(x1, y, z1).setType(material);
+ }
+ }
+ } else if (direction == Direction.NORTH || direction == Direction.SOUTH) {
+ for (int i = 0; i < chunkLength; i++) {
+ for (int j = 0; j < chunkWight; j++) {
+ int x1 = x + i * direction.getLadderVector().getBlockX();
+ int z1 = z + j * direction.getLadderVector().getBlockZ();
+ world.getBlockAt(x1, y, z1).setType(material);
+ }
+ }
+ }
+ }
+
+ private void transformDirection() {
+ nowDirection = nowDirection.getRightDirection();
+ }
+
+ private enum TransformType {
+ PLATFORM,
+ LADDER
+ }
+
+ public enum Direction {
+
+ NORTH(new Vector(1.0, 1.0, -1.0), new Vector(-1.0, 1.0, -1.0), new Vector(1.0, 1.0, -1.0)),
+ EAST(new Vector(1.0, 1.0, 1.0), new Vector(1.0, 1.0, -1.0), new Vector(1.0, 1.0, 1.0)),
+ SOUTH(new Vector(-1.0, 1.0, 1.0), new Vector(1.0, 1.0, 1.0), new Vector(-1.0, 1.0, 1.0)),
+ WEST(new Vector(-1.0, 1.0, -1.0), new Vector(-1.0, 1.0, 1.0), new Vector(-1.0, 1.0, -1.0));
+
+ private final Vector vector;
+ private final Vector platformVector;
+ private final Vector ladderVector;
+
+ Direction(Vector vector, Vector platformVector, Vector ladderVector) {
+ this.vector = vector;
+ this.platformVector = platformVector;
+ this.ladderVector = ladderVector;
+ }
+
+ public Vector getVector() {
+ return vector;
+ }
+
+ public Vector getPlatformVector() {
+ return platformVector;
+ }
+
+ public Vector getLadderVector() {
+ return ladderVector;
+ }
+
+ public Direction getRightDirection() {
+ switch (this) {
+ case NORTH:
+ return EAST;
+ case EAST:
+ return SOUTH;
+ case SOUTH:
+ return WEST;
+ case WEST:
+ return NORTH;
+ }
+ return null;
+ }
+
+ }
+
+ public Region getEffectiveRegion(World world) {
+ return spawnModeHander.getEffectiveRegion(world);
+ }
+
+ public int getHeight() {
+ return spawnModeHander.getHeight();
+ }
+
+ public enum SpawnMode {
+
+ MODE_1,
+ MODE_2;
+
+ }
+
+ private class SpawnModeHandler_1 implements ISpawnModeHander {
+ @Override
+ public void spawn() {
+ for (int i = 0; i < levelAmount; i++) {
+ spawnPlatform(nowX, nowY, nowZ, nowDirection);
+ transformXYZ(TransformType.PLATFORM, nowDirection);
+ transformDirection();
+ spawnLadder(nowX, nowY, nowZ, nowDirection);
+ transformXYZ(TransformType.LADDER, nowDirection);
+ transformDirection();
+ }
+ spawnPlatform(nowX, nowY, nowZ, nowDirection);
+ }
+
+ @Override
+ public Region getEffectiveRegion(World world) {
+ if (initialDirection == Direction.NORTH || initialDirection == Direction.SOUTH) {
+ int minX = originX + (platformWidth * chunkWight) * initialDirection.getPlatformVector().getBlockX();
+ int minY = originY;
+ int minZ = originZ;
+ int maxX = originX + ladderAmount * ladderLength * chunkLength * initialDirection.getLadderVector().getBlockX() + (platformWidth * chunkWight) * initialDirection.getPlatformVector().getBlockX() + 1;
+ int maxY = originY + levelAmount * 5 + 1;
+ int maxZ = originZ + (platformLength * chunkLength) * initialDirection.getPlatformVector().getBlockZ() + 1;
+ return new Region(world, new Point(minX, minY, minZ), new Point(maxX, maxY, maxZ));
+ } else if (initialDirection == Direction.EAST || initialDirection == Direction.WEST) {
+ int minX = originX;
+ int minY = originY;
+ int minZ = originZ + (platformWidth * chunkWight) * initialDirection.getPlatformVector().getBlockZ();
+ int maxX = originX + (platformLength * chunkLength) * initialDirection.getPlatformVector().getBlockX() + 1;
+ int maxY = originY + levelAmount * 5 + 1;
+ int maxZ = originZ + ladderAmount * ladderLength * chunkLength * initialDirection.getLadderVector().getBlockX() + (platformWidth * chunkWight) * initialDirection.getPlatformVector().getBlockZ() + 1;
+ return new Region(world, new Point(minX, minY, minZ), new Point(maxX, maxY, maxZ));
+ }
+ return null;
+ }
+
+ @Override
+ public int getHeight() {
+ return levelAmount * 5;
+ }
+
+ private void transformXYZ(TransformType transformType, Direction direction) {
+ if (transformType == TransformType.PLATFORM) {
+ if (direction == Direction.EAST || direction == Direction.WEST) {
+ nowX += (platformLength * chunkWight - 1) * direction.getPlatformVector().getX();
+ } else if (direction == Direction.NORTH || direction == Direction.SOUTH) {
+ nowZ += (platformLength * chunkWight - 1) * direction.getPlatformVector().getZ();
+ }
+ switch (nowDirection) {
+ case EAST:
+ nowZ += 1;
+ break;
+ case SOUTH:
+ nowX -= 1;
+ break;
+ case WEST:
+ nowZ -= 1;
+ break;
+ case NORTH:
+ nowX += 1;
+ break;
+ }
+ } else if (transformType == TransformType.LADDER) {
+ nowY += ladderAmount;
+ if (direction == Direction.EAST || direction == Direction.WEST) {
+ nowX += (ladderAmount * chunkWight) * direction.getLadderVector().getBlockX();
+ } else if (direction == Direction.NORTH || direction == Direction.SOUTH) {
+ nowZ += (ladderAmount * chunkWight) * direction.getLadderVector().getBlockZ();
+ }
+ }
+ }
+ }
+
+ private class SpawnModeHandler_2 implements ISpawnModeHander {
+
+ @Override
+ public void spawn() {
+ for (int i = 0; i < levelAmount; i++) {
+ spawnPlatform(nowX, nowY, nowZ, nowDirection);
+ transformXYZ(TransformType.PLATFORM, nowDirection, 0);
+ spawnLadder(nowX, nowY, nowZ, nowDirection);
+ transformXYZ(TransformType.LADDER, nowDirection, 0);
+ transformDirection();
+ }
+ spawnPlatform(nowX, nowY, nowZ, nowDirection);
+ }
+
+ @Override
+ public Region getEffectiveRegion(World world) {
+ if (initialDirection == Direction.NORTH || initialDirection == Direction.SOUTH) {
+ int minX = originX + (platformWidth * chunkWight) * initialDirection.getPlatformVector().getBlockX();
+ int minZ = originZ;
+ minZ += (platformLength * chunkLength) * initialDirection.getPlatformVector().getBlockZ();
+ minZ += (ladderAmount * chunkLength) * initialDirection.getLadderVector().getBlockZ();
+ minZ += (platformWidth * chunkWight) * initialDirection.getRightDirection().getPlatformVector().getBlockZ();
+ int maxX = originX + ladderAmount * ladderLength * chunkLength * initialDirection.getLadderVector().getBlockX() + (platformWidth * chunkWight) * initialDirection.getPlatformVector().getBlockX()+ 1;
+ int maxZ = originZ;
+ int maxY = originY + levelAmount * 5 + 1;
+ return new Region(world, new Point(minX, originY, minZ), new Point(maxX, maxY, maxZ));
+ } else if (initialDirection == Direction.EAST || initialDirection == Direction.WEST) {
+ int minX = originX;
+ int minZ = originZ + (platformWidth * chunkWight) * initialDirection.getPlatformVector().getBlockZ();
+ minX += (platformLength * chunkLength) * initialDirection.getPlatformVector().getBlockX();
+ minX += (ladderAmount * chunkLength) * initialDirection.getLadderVector().getBlockX();
+ minX += (platformWidth * chunkWight) * initialDirection.getRightDirection().getPlatformVector().getBlockX();
+ int maxX = originX;
+ int maxZ = originZ + ladderAmount * ladderLength * chunkLength * initialDirection.getLadderVector().getBlockZ() + (platformWidth * chunkWight) * initialDirection.getPlatformVector().getBlockZ()+ 1;
+ int maxY = originY + levelAmount * 5 + 1;
+ return new Region(world, new Point(minX, originY, minZ), new Point(maxX, maxY, maxZ));
+ }
+ return null;
+ }
+
+ @Override
+ public int getHeight() {
+ return levelAmount * 5;
+ }
+
+ private void transformXYZ(TransformType transformType, Direction direction, int type) {
+ if (transformType == TransformType.PLATFORM) {
+ if (type == 0) {
+ if (direction == Direction.EAST || direction == Direction.WEST) {
+ nowX += (platformLength * chunkWight) * direction.getPlatformVector().getX();
+ nowZ += (platformWidth * chunkLength - 1) * direction.getPlatformVector().getZ();
+ } else if (direction == Direction.NORTH || direction == Direction.SOUTH) {
+ nowX += (platformWidth * chunkLength - 1) * direction.getPlatformVector().getX();
+ nowZ += (platformLength * chunkWight) * direction.getPlatformVector().getZ();
+ }
+ } else if (type == 1) {
+ if (direction == Direction.EAST || direction == Direction.WEST) {
+ nowX += (platformLength * chunkWight - 1) * direction.getPlatformVector().getX();
+ } else if (direction == Direction.NORTH || direction == Direction.SOUTH) {
+ nowZ += (platformLength * chunkWight - 1) * direction.getPlatformVector().getZ();
+ }
+ switch (nowDirection) {
+ case EAST:
+ nowZ += 1;
+ break;
+ case SOUTH:
+ nowX -= 1;
+ break;
+ case WEST:
+ nowZ -= 1;
+ break;
+ case NORTH:
+ nowX += 1;
+ break;
+ }
+ }
+ } else if (transformType == TransformType.LADDER) {
+ nowY += ladderAmount;
+ if (direction == Direction.EAST || direction == Direction.WEST) {
+ nowX += (ladderAmount * chunkWight) * direction.getLadderVector().getBlockX();
+ } else if (direction == Direction.NORTH || direction == Direction.SOUTH) {
+ nowZ += (ladderAmount * chunkWight) * direction.getLadderVector().getBlockZ();
+ }
+ }
+ }
+
+ }
+
+ public void setInitialDirection(Direction initialDirection) {
+ this.initialDirection = initialDirection;
+ }
+
+ private interface ISpawnModeHander {
+ void spawn();
+
+ Region getEffectiveRegion(World world);
+
+ int getHeight();
+ }
+
+ public Material getRandomMaterial() {
+ return materials.get(RandomUtil.getRandomInt(0, materials.size() - 1));
+ }
+
+}
diff --git a/src/main/java/com/io/yutian/colorblindwar/util/ColorUtil.java b/src/main/java/com/io/yutian/colorblindwar/util/ColorUtil.java
new file mode 100644
index 0000000..3ed0268
--- /dev/null
+++ b/src/main/java/com/io/yutian/colorblindwar/util/ColorUtil.java
@@ -0,0 +1,77 @@
+package com.io.yutian.colorblindwar.util;
+
+import org.bukkit.Material;
+
+public class ColorUtil {
+
+ public static String getColorName(Material material) {
+ switch (material) {
+ case WHITE_WOOL:
+ return "白色";
+ case BLACK_WOOL:
+ return "黑色";
+ case BROWN_WOOL:
+ return "棕色";
+ case BLUE_WOOL:
+ return "蓝色";
+ case GREEN_WOOL:
+ return "绿色";
+ case RED_WOOL:
+ return "红色";
+ case YELLOW_WOOL:
+ return "黄色";
+ case PURPLE_WOOL:
+ return "紫色";
+ case ORANGE_WOOL:
+ return "橙色";
+ case PINK_WOOL:
+ return "粉色";
+ case LIGHT_BLUE_WOOL:
+ return "淡蓝色";
+ case LIME_WOOL:
+ return "黄绿色";
+ default:
+ return "未知";
+ }
+ }
+
+ public static String getColorHex(Material material) {
+ switch (material) {
+ case WHITE_WOOL:
+ return "#DDDDDD";
+ case ORANGE_WOOL:
+ return "#DB7D3E";
+ case MAGENTA_WOOL:
+ return "#B350BC";
+ case LIGHT_BLUE_WOOL:
+ return "#6B8AC9";
+ case YELLOW_WOOL:
+ return "#E0C240";
+ case LIME_WOOL:
+ return "#41AE38";
+ case PINK_WOOL:
+ return "#D08499";
+ case GRAY_WOOL:
+ return "#404040";
+ case LIGHT_GRAY_WOOL:
+ return "#9A9A9A";
+ case CYAN_WOOL:
+ return "#2E6E89";
+ case PURPLE_WOOL:
+ return "#7E3DB5";
+ case BLUE_WOOL:
+ return "#2E388D";
+ case BROWN_WOOL:
+ return "#4F321F";
+ case GREEN_WOOL:
+ return "#35461B";
+ case RED_WOOL:
+ return "#C05A5A";
+ case BLACK_WOOL:
+ return "#191616";
+ default:
+ return "#000000";
+ }
+ }
+
+}
diff --git a/src/main/java/com/io/yutian/colorblindwar/util/MathUtil.java b/src/main/java/com/io/yutian/colorblindwar/util/MathUtil.java
new file mode 100644
index 0000000..f59f303
--- /dev/null
+++ b/src/main/java/com/io/yutian/colorblindwar/util/MathUtil.java
@@ -0,0 +1,29 @@
+package com.io.yutian.colorblindwar.util;
+
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+
+public class MathUtil {
+
+ public static double round(double d) {
+ return new BigDecimal(Double.toString(d)).setScale(2, RoundingMode.HALF_UP).doubleValue();
+ }
+
+ public static double round(double d, int scale) {
+ return new BigDecimal(Double.toString(d)).setScale(scale, RoundingMode.HALF_UP).doubleValue();
+ }
+
+ public static int clamp(int value, int min, int max) {
+ return Math.max(min, Math.min(max, value));
+ }
+
+ public static double clamp(double value, double min, double max) {
+ return Math.max(min, Math.min(max, value));
+ }
+
+ public static float clamp(float value, float min, float max) {
+ return Math.max(min, Math.min(max, value));
+ }
+
+
+}
diff --git a/src/main/java/com/io/yutian/colorblindwar/util/RandomUtil.java b/src/main/java/com/io/yutian/colorblindwar/util/RandomUtil.java
new file mode 100644
index 0000000..0643cff
--- /dev/null
+++ b/src/main/java/com/io/yutian/colorblindwar/util/RandomUtil.java
@@ -0,0 +1,45 @@
+package com.io.yutian.colorblindwar.util;
+
+import com.io.yutian.colorblindwar.game.Point;
+import com.io.yutian.colorblindwar.game.Region;
+import org.bukkit.Location;
+import org.bukkit.World;
+
+import java.util.Random;
+
+public class RandomUtil {
+
+ public static Location getRandomLocation(Region region) {
+ Point min = region.getMin();
+ Point max = region.getMax();
+ return getRandomLocation(region.getWorld(), min.getX(), max.getX(), min.getY(), max.getY(), min.getZ(), max.getZ());
+ }
+
+ public static boolean random(double d) {
+ return d >= new Random().nextFloat();
+ }
+
+ public static int getRandomInt(int min, int max) {
+ if (min == max) {
+ return max;
+ }
+ Random r = new Random();
+ int i = min < max ? min : max;
+ int a = min < max ? max : min;
+ return r.nextInt(a - i + 1) + i;
+ }
+
+ public static double getRandomDouble(double min, double max, int scl) {
+ int pow = (int) Math.pow(10, scl);
+ return Math.floor((Math.random() * (max - min) + min) * pow) / pow;
+ }
+
+ public static Location getRandomLocation(World world, double minX, double maxX, double minY, double maxY, double minZ, double maxZ) {
+ double rx = getRandomDouble(minX, maxX, 3);
+ double ry = getRandomDouble(minY, maxY, 3);
+ double rz = getRandomDouble(minZ, maxZ, 3);
+ Location location = new Location(world, rx, ry, rz);
+ return location;
+ }
+
+}
diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml
new file mode 100644
index 0000000..bfc5249
--- /dev/null
+++ b/src/main/resources/config.yml
@@ -0,0 +1,2 @@
+completeAmount: 10
+countdownTime: 10
\ No newline at end of file
diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml
new file mode 100644
index 0000000..86a43e5
--- /dev/null
+++ b/src/main/resources/plugin.yml
@@ -0,0 +1,9 @@
+name: ColorblindWar
+version: '${project.version}'
+main: com.io.yutian.colorblindwar.ColorblindWar
+api-version: '1.18'
+depend:
+ - WorldEdit
+commands:
+ colorblindwar:
+ aliases: [cw]
\ No newline at end of file