diff --git a/FightSystem_Core/src/de/steamwar/fightsystem/ai/AI.java b/FightSystem_Core/src/de/steamwar/fightsystem/ai/AI.java index ad89881..35ed111 100644 --- a/FightSystem_Core/src/de/steamwar/fightsystem/ai/AI.java +++ b/FightSystem_Core/src/de/steamwar/fightsystem/ai/AI.java @@ -144,9 +144,9 @@ public abstract class AI { return translate(pos, true).getBlock().getType(); } - public boolean isPowered(Vector pos) { + public BlockData getBlockData(Vector pos) { queue.add(new Action(1)); - return translate(pos, true).getBlock().isBlockPowered(); + return translate(pos, true).getBlock().getBlockData(); } public void setTNT(Vector pos) { @@ -219,7 +219,8 @@ public abstract class AI { if(!team.getFightPlayer(entity).canEntern() && !team.getExtendRegion().inRegion(target)) return; - entity.teleport(target, PlayerTeleportEvent.TeleportCause.PLUGIN); + if(!entity.teleport(target, PlayerTeleportEvent.TeleportCause.PLUGIN)) + FightSystem.getPlugin().getLogger().log(Level.INFO, "Entity not teleported: " + entity.isValid()); } }); } diff --git a/FightSystem_Core/src/de/steamwar/fightsystem/ai/LixfelAI.java b/FightSystem_Core/src/de/steamwar/fightsystem/ai/LixfelAI.java index a49bfec..2178059 100644 --- a/FightSystem_Core/src/de/steamwar/fightsystem/ai/LixfelAI.java +++ b/FightSystem_Core/src/de/steamwar/fightsystem/ai/LixfelAI.java @@ -19,40 +19,56 @@ package de.steamwar.fightsystem.ai; +import com.sk89q.worldedit.extent.clipboard.Clipboard; import de.steamwar.fightsystem.Config; +import de.steamwar.fightsystem.FightSystem; import de.steamwar.fightsystem.fight.FightTeam; import de.steamwar.fightsystem.states.FightState; +import de.steamwar.sql.SchematicData; import de.steamwar.sql.SchematicNode; import de.steamwar.sql.SteamwarUser; +import org.bukkit.Bukkit; +import org.bukkit.Material; +import org.bukkit.Particle; +import org.bukkit.scheduler.BukkitTask; import org.bukkit.util.Vector; +import java.io.IOException; import java.util.*; import java.util.function.Consumer; +import java.util.stream.Collectors; public class LixfelAI extends AI { - private Random random; + private static final Random random = new Random(); + private final BukkitTask timerTask; + private int currentTime; private LixfelPathplanner pathplanner; private List setup; - private long preRunningStart; + private int preRunningStart; private List timedStart; private List cannons; private Cannon currentCannon; public LixfelAI(FightTeam team, String user) { super(team, SteamwarUser.get(user)); + timerTask = Bukkit.getScheduler().runTaskTimer(FightSystem.getPlugin(), () -> currentTime++, 1, 1); } @Override public SchematicNode chooseSchematic() { - random = new Random(); - List publics = SchematicNode.getAllSchematicsOfType(0, Config.SchematicType.toDB()); SchematicNode schem = publics.get(random.nextInt(publics.size())); schem = publics.stream().filter(s -> s.getName().equals("TheUnderground")).findAny().orElse(schem); + Clipboard clipboard; + try { + clipboard = new SchematicData(schem).load(); + } catch (IOException e) { + throw new IllegalStateException(e); + } - pathplanner = new LixfelPathplanner(schem); + pathplanner = new LixfelPathplanner(clipboard); setup = new ArrayList<>(Collections.singletonList(new Vector(25, 15, 25))); timedStart = new ArrayList<>(Collections.singletonList(new TimedVector(420L, new Vector(21, 15, 24)))); cannons = new ArrayList<>(Arrays.asList( @@ -64,6 +80,7 @@ public class LixfelAI extends AI { new Cannon(null, 23,5,9, 23,6,9, 23,7,9, 23,8,9), new Cannon(null, 27,5,9, 27,6,9, 27,7,9, 27,8,9) )); + assignWater(clipboard); chooseCannon(); return schem; @@ -81,14 +98,33 @@ public class LixfelAI extends AI { ensureInRange(currentCannon.tnt.keySet().iterator().next()); break; case RUNNING: - while(currentCannon.shoot()) - chooseCannon(); //TODO prevent endless loop + while(currentCannon.shoot() && chooseCannon() && scanEnemy()) {} break; default: break; } } + @Override + public void stop() { + if(!timerTask.isCancelled()) + timerTask.cancel(); + + super.stop(); + } + + private void assignWater(Clipboard clipboard) { + List waterSources = new ArrayList<>(); + clipboard.getRegion().forEach(block -> { + if(clipboard.getBlock(block).getBlockType().getMaterial().isLiquid()) + waterSources.add(pathplanner.clipboardToSchem(block)); + }); + + for(Vector water : waterSources) { + cannons.stream().min(Comparator.comparingDouble(c -> c.waterDistance(water))).ifPresent(cannon -> cannon.addWater(water)); + } + } + private boolean prepareSchem() { return doWith(setup, this::interact); } @@ -100,12 +136,12 @@ public class LixfelAI extends AI { private boolean start() { if(preRunningStart == 0) - preRunningStart = Config.world.getFullTime(); + preRunningStart = currentTime; if(timedStart.isEmpty()) return true; - long time = Config.world.getFullTime() - preRunningStart; + long time = currentTime - preRunningStart; TimedVector vector = timedStart.get(0); if(!ensureInRange(vector.vector)) return false; @@ -118,8 +154,13 @@ public class LixfelAI extends AI { return false; } - private void chooseCannon() { - currentCannon = cannons.get(random.nextInt(cannons.size())); + private boolean chooseCannon() { + List availableCannons = cannons.stream().filter(Cannon::available).collect(Collectors.toList()); + if(availableCannons.isEmpty()) + return false; + + currentCannon = availableCannons.get(random.nextInt(availableCannons.size())); + return true; } private boolean doWith(List targets, Consumer method) { @@ -141,14 +182,19 @@ public class LixfelAI extends AI { if(path.isEmpty()) path.add(new Vector(0, 1, 0).add(position)); + for(Vector v : path) + Config.world.spawnParticle(Particle.VILLAGER_HAPPY, translate(v, false), 1); + move(path.get(0)); return false; } private class Cannon { + private final List water = new ArrayList<>(); private final Vector activator; private final Map tnt = new HashMap<>(); - private long freeAt; + private int freeAt; + private int lastCannonCheck = -1; public Cannon(Vector activator, int... tntpos) { this.activator = activator; @@ -158,10 +204,36 @@ public class LixfelAI extends AI { } } + public void addWater(Vector vector) { + water.add(vector); + } + + public double waterDistance(Vector vector) { + return tnt.keySet().stream().mapToDouble(t -> { + double distance = t.distance(vector); + if(t.getY() < vector.getY()) + distance += 10.0; //It is unlikely that TNT is loaded from below into the cannon + return distance; + }).min().orElse(Double.MAX_VALUE); + } + + public boolean available() { + return currentTime >= freeAt && !water.isEmpty(); + } + public boolean shoot() { - if(Config.world.getFullTime() < freeAt) + if(currentTime < freeAt || water.isEmpty()) return true; + if(lastCannonCheck < freeAt) { + Vector w = water.get(random.nextInt(water.size())); + if(getBlock(w) == Material.WATER) + lastCannonCheck = freeAt; + else + water.remove(w); + return false; + } + for(Map.Entry entry : tnt.entrySet()) { if(!entry.getValue()) { if(ensureInRange(entry.getKey())) { @@ -179,7 +251,7 @@ public class LixfelAI extends AI { interact(activator); } - freeAt = Config.world.getFullTime() + 80; + freeAt = currentTime + 80; for(Map.Entry entry : tnt.entrySet()) entry.setValue(false); diff --git a/FightSystem_Core/src/de/steamwar/fightsystem/ai/LixfelPathplanner.java b/FightSystem_Core/src/de/steamwar/fightsystem/ai/LixfelPathplanner.java index 93fb1ac..992c7c9 100644 --- a/FightSystem_Core/src/de/steamwar/fightsystem/ai/LixfelPathplanner.java +++ b/FightSystem_Core/src/de/steamwar/fightsystem/ai/LixfelPathplanner.java @@ -25,15 +25,12 @@ import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.regions.Region; import de.steamwar.fightsystem.Config; import de.steamwar.fightsystem.utils.WorldeditWrapper; -import de.steamwar.sql.SchematicData; -import de.steamwar.sql.SchematicNode; import org.bukkit.Material; import org.bukkit.block.Banner; import org.bukkit.block.data.BlockData; import org.bukkit.block.data.type.*; import org.bukkit.util.Vector; -import java.io.IOException; import java.util.*; import java.util.stream.Collectors; @@ -75,19 +72,27 @@ public class LixfelPathplanner { return 0.0; } - private static Vector toBukkit(BlockVector3 vector, double height) { - return new Vector(vector.getX() + 0.5, vector.getY() + height, vector.getZ() + 0.5); + private static Vector toBukkit(BlockVector3 vector, double offset, double height) { + return new Vector(vector.getX() + offset, vector.getY() + height, vector.getZ() + offset); } + private final Vector clipboardToSchem; + private final BlockVector3 diff; private final List walkable = new ArrayList<>(); private final Map neighbours = new HashMap<>(); - public LixfelPathplanner(SchematicNode schem) { - try { - fillWalkable(new SchematicData(schem).load()); - } catch (IOException e) { - throw new IllegalStateException(e); - } + public LixfelPathplanner(Clipboard clipboard) { + clipboardToSchem = new Vector(Config.BluePasteRegion.getSizeX(), Config.BluePasteRegion.getSizeY(), Config.BluePasteRegion.getSizeZ()) + .subtract(WorldeditWrapper.impl.getDimensions(clipboard)) + .multiply(0.5) + .add(new Vector(Config.PreperationArea, 0, Config.PreperationArea)); + diff = clipboard.getRegion().getMinimumPoint().subtract(clipboardToSchem.getBlockX(), clipboardToSchem.getBlockY(), clipboardToSchem.getBlockZ()); + + fillWalkable(clipboard); + } + + public Vector clipboardToSchem(BlockVector3 vector) { + return toBukkit(vector.subtract(diff), 0.0, 0.0); } public List getWalkable() { @@ -95,12 +100,6 @@ public class LixfelPathplanner { } private void fillWalkable(Clipboard clipboard) { - Vector clipboardToSchem = new Vector(Config.BluePasteRegion.getSizeX(), Config.BluePasteRegion.getSizeY(), Config.BluePasteRegion.getSizeZ()) - .subtract(WorldeditWrapper.impl.getDimensions(clipboard)) - .multiply(0.5) - .add(new Vector(Config.PreperationArea, 0, Config.PreperationArea)); - BlockVector3 diff = clipboard.getRegion().getMinimumPoint().subtract(clipboardToSchem.getBlockX(), clipboardToSchem.getBlockY(), clipboardToSchem.getBlockZ()); - Region region = clipboard.getRegion(); clipboard.getRegion().forEach(vector -> { BlockVector3 below = vector.subtract(0, 1, 0); @@ -121,7 +120,7 @@ public class LixfelPathplanner { if(height < 0.0) height = 0.0; - walkable.add(toBukkit(vector.subtract(diff), height)); + walkable.add(toBukkit(vector.subtract(diff), 0.5, height)); }); for(Vector vector : walkable) { diff --git a/FightSystem_Core/src/de/steamwar/fightsystem/ai/chaos/ChaosAI.java b/FightSystem_Core/src/de/steamwar/fightsystem/ai/chaos/ChaosAI.java index 4e665fd..b34f9b9 100644 --- a/FightSystem_Core/src/de/steamwar/fightsystem/ai/chaos/ChaosAI.java +++ b/FightSystem_Core/src/de/steamwar/fightsystem/ai/chaos/ChaosAI.java @@ -19,21 +19,24 @@ package de.steamwar.fightsystem.ai.chaos; +import com.sk89q.worldedit.extent.clipboard.Clipboard; import de.steamwar.fightsystem.FightSystem; import de.steamwar.fightsystem.ai.AI; import de.steamwar.fightsystem.ai.LixfelPathplanner; import de.steamwar.fightsystem.fight.FightTeam; import de.steamwar.fightsystem.states.FightState; +import de.steamwar.sql.SchematicData; import de.steamwar.sql.SchematicNode; import de.steamwar.sql.SteamwarUser; import org.bukkit.Bukkit; import org.bukkit.entity.Player; import org.bukkit.util.Vector; +import java.io.IOException; import java.util.*; public class ChaosAI extends AI { - private final LixfelPathplanner pathplanner = new LixfelPathplanner(chooseSchematic()); + private LixfelPathplanner pathplanner; private State state = State.PRE_PREPARE; private static final Cannon[] cannons = new Cannon[] { Cannon.DS_LEFT, @@ -67,7 +70,16 @@ public class ChaosAI extends AI { @Override public SchematicNode chooseSchematic() { - return SchematicNode.getSchematicNode(111476); + SchematicNode schem = SchematicNode.getSchematicNode(111476); + Clipboard clipboard; + try { + clipboard = new SchematicData(schem).load(); + } catch (IOException e) { + throw new IllegalStateException(e); + } + + pathplanner = new LixfelPathplanner(clipboard); + return schem; } @Override