diff --git a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/ai/AI.java b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/ai/AI.java index 3c8b6e6d..bab0830f 100644 --- a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/ai/AI.java +++ b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/ai/AI.java @@ -23,14 +23,12 @@ import com.sk89q.worldedit.extent.clipboard.Clipboard; import de.steamwar.fightsystem.ArenaMode; import de.steamwar.fightsystem.Config; import de.steamwar.fightsystem.FightSystem; -import de.steamwar.fightsystem.fight.Fight; import de.steamwar.fightsystem.fight.FightTeam; import de.steamwar.fightsystem.fight.JoinRequest; import de.steamwar.fightsystem.listener.Chat; import de.steamwar.fightsystem.record.GlobalRecorder; import de.steamwar.fightsystem.states.FightState; import de.steamwar.fightsystem.states.OneShotStateDependent; -import de.steamwar.fightsystem.utils.Region; import de.steamwar.sql.SchematicNode; import de.steamwar.sql.SteamwarUser; import lombok.Getter; @@ -54,7 +52,6 @@ import org.bukkit.entity.LivingEntity; import org.bukkit.entity.Villager; import org.bukkit.event.player.PlayerTeleportEvent; import org.bukkit.scheduler.BukkitTask; -import org.bukkit.util.Vector; import java.util.*; import java.util.logging.Level; @@ -87,6 +84,8 @@ public abstract class AI { private final BukkitTask task; private final Queue queue = new ArrayDeque<>(); + protected final NavMesh navMesh; + protected AI(FightTeam team, SteamwarUser user) { this.team = team; @@ -98,6 +97,8 @@ public abstract class AI { ais.put(entity.getUniqueId(), this); team.addMember(entity, user); + navMesh = new NavMesh(team); + if(FightState.Schem.contains(FightState.getFightState())) Bukkit.getScheduler().runTask(FightSystem.getPlugin(), () -> schematic(team.getClipboard())); } @@ -134,45 +135,40 @@ public abstract class AI { Chat.broadcastChat("PARTICIPANT_CHAT", team.getColoredName(), entity.getName(), message); } - public Vector getPosition() { - Location location = entity.getLocation(); - return untranslate(location.toVector()); + public LocalCoordinate getPosition() { + return WorldCoordinate.from(entity.getLocation()).toLocal(team); } - public Vector untranslate(Vector vector) { - Region extend = team.getExtendRegion(); - if(Fight.getUnrotated() == team) - return new Vector( - vector.getX() - extend.getMinX(), - vector.getY() - team.getSchemRegion().getMinY(), - vector.getZ() - extend.getMinZ() - ); - else - return new Vector( - extend.getMaxX() - vector.getX(), - vector.getY() - team.getSchemRegion().getMinY(), - extend.getMaxZ() - vector.getZ() - ); + public Material getBlock(WorldCoordinate pos) { + return getBlock(pos.toLocal(team)); } - public Material getBlock(Vector pos) { + public Material getBlock(LocalCoordinate pos) { queue.add(new Action(1)); - return translate(pos).getBlock().getType(); + return pos.toWorld(team).toLocation(Config.world).getBlock().getType(); } - public BlockData getBlockData(Vector pos) { + public BlockData getBlockData(WorldCoordinate pos) { + return getBlockData(pos.toLocal(team)); + } + + public BlockData getBlockData(LocalCoordinate pos) { queue.add(new Action(1)); - return translate(pos).getBlock().getBlockData(); + return pos.toWorld(team).toLocation(Config.world).getBlock().getBlockData(); } - public void setTNT(Vector pos) { + public void setTNT(WorldCoordinate pos) { + setTNT(pos.toLocal(team)); + } + + public void setTNT(LocalCoordinate pos) { queue.add(new Action(1) { @Override public void run() { if(FightState.getFightState() != FightState.RUNNING) return; - Location location = translate(pos); + Location location = pos.toWorld(team).toLocation(Config.world); if(interactionDistanceViolation(location)) { chat("InteractionDistanceViolation: setTNT"); return; @@ -185,11 +181,15 @@ public abstract class AI { }); } - public void interact(Vector pos) { + public void interact(WorldCoordinate pos) { + interact(pos.toLocal(team)); + } + + public void interact(LocalCoordinate pos) { queue.add(new Action(1) { @Override public void run() { - Location location = translate(pos); + Location location = pos.toWorld(team).toLocation(Config.world); if(interactionDistanceViolation(location)) { chat("InteractionDistanceViolation: interact"); return; @@ -200,11 +200,15 @@ public abstract class AI { }); } - public void interact(Vector pos, int n) { + public void interact(WorldCoordinate pos, int n) { + interact(pos.toLocal(team), n); + } + + public void interact(LocalCoordinate pos, int n) { queue.add(new Action(1) { @Override public void run() { - Location location = translate(pos); + Location location = pos.toWorld(team).toLocation(Config.world); if (interactionDistanceViolation(location)) return; Block block = location.getBlock(); @@ -221,24 +225,54 @@ public abstract class AI { }); } - public void move(Vector pos) { + public MoveResult checkMove(WorldCoordinate target) { + Location location = entity.getLocation(); + if(!entity.isOnGround() && location.getBlock().getType() != Material.LADDER) { + return MoveResult.FALLING; + } + + if(Math.abs(location.getX() - target.getX()) > 1.5 || Math.abs(location.getY() - target.getY()) > 1.5 || Math.abs(location.getZ() - target.getZ()) > 1.5) { + return MoveResult.OVERDISTANCE; + } + + if(!team.getFightPlayer(entity).canEntern() && !team.getExtendRegion().inRegion(target.toLocation(null))) + return MoveResult.OUT_OF_BORDER; + return MoveResult.OK; + } + + public enum MoveResult { + FALLING, + OVERDISTANCE, + OUT_OF_BORDER, + OK, + } + + public void move(WorldCoordinate pos) { queue.add(new Action(MOVEMENT_DELAY) { @Override public void run() { - Location location = entity.getLocation(); - if(!entity.isOnGround() && location.getBlock().getType() != Material.LADDER) { - FightSystem.getPlugin().getLogger().log(Level.INFO, "Entity falling"); - return; + MoveResult moveResult = checkMove(pos); + switch (moveResult) { + case FALLING: + FightSystem.getPlugin().getLogger().log(Level.INFO, "Entity falling"); + return; + case OVERDISTANCE: + FightSystem.getPlugin().getLogger().log(Level.INFO, () -> entity.getName() + ": Overdistance movement " + entity.getLocation().toVector() + " " + pos); + return; + case OUT_OF_BORDER: + return; + default: + break; } - Location target = translate(pos); - if(Math.abs(location.getX() - target.getX()) > 1.5 || Math.abs(location.getY() - target.getY()) > 1.5 || Math.abs(location.getZ() - target.getZ()) > 1.5) { - FightSystem.getPlugin().getLogger().log(Level.INFO, () -> entity.getName() + ": Overdistance movement " + location.toVector() + " " + target.toVector()); - return; + Location currentLocation = entity.getLocation(); + Location target = pos.toLocation(Config.world); + if (currentLocation.getBlockX() != target.getBlockX() || currentLocation.getBlockY() != target.getBlockY() || currentLocation.getBlockZ() != target.getBlockZ()) { + target.setDirection(target.toVector().subtract(currentLocation.toVector())); + } + if (currentLocation.getBlockX() == target.getBlockX() && currentLocation.getBlockZ() == target.getBlockZ()) { + target.setYaw(currentLocation.getYaw()); } - - if(!team.getFightPlayer(entity).canEntern() && !team.getExtendRegion().inRegion(target)) - return; if(!entity.teleport(target, PlayerTeleportEvent.TeleportCause.PLUGIN)) FightSystem.getPlugin().getLogger().log(Level.INFO, "Entity not teleported: " + entity.isValid()); @@ -248,6 +282,10 @@ public abstract class AI { }); } + public void move(LocalCoordinate pos) { + move(pos.toWorld(team)); + } + private boolean interactionDistanceViolation(Location location) { return location.distance(entity.getEyeLocation()) > INTERACTION_RANGE; } @@ -312,6 +350,7 @@ public abstract class AI { private void run() { if(queue.isEmpty()) { try { + navMesh.update(getPosition().toWorld(team)); plan(); } catch (Throwable t) { stop(); @@ -323,24 +362,6 @@ public abstract class AI { queue.poll().run(); } - public Location translate(Vector pos) { - Region extend = team.getExtendRegion(); - if(Fight.getUnrotated() == team) - return new Location( - Config.world, - pos.getX() + extend.getMinX(), - pos.getY() + team.getSchemRegion().getMinY(), - pos.getZ() + extend.getMinZ() - ); - else - return new Location( - Config.world, - extend.getMaxX() - pos.getX(), - pos.getY() + team.getSchemRegion().getMinY(), - extend.getMaxZ() - pos.getZ() - ); - } - private static class Action { private int delay; public Action(int delay) { diff --git a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/ai/Action.java b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/ai/Action.java new file mode 100644 index 00000000..b0a5f0e2 --- /dev/null +++ b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/ai/Action.java @@ -0,0 +1,101 @@ +/* + * This file is a part of the SteamWar software. + * + * Copyright (C) 2026 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.fightsystem.ai; + +import java.util.List; + +public interface Action { + boolean isCompletable(); + Result step(AI ai); + + enum Result { + ONGOING, + FINISHED, + FAILED, + ; + } + + class MoveAction implements Action { + + private final WorldCoordinate destination; + private List path; + private int overDistanceCounter = 0; + + public MoveAction(AI ai, LocalCoordinate destination) { + this(ai, destination.toWorld(ai.team)); + } + + public MoveAction(AI ai, WorldCoordinate destination) { + this.destination = destination; + this.path = ai.navMesh.pathToNearest(ai.getPosition().toWorld(ai.team), destination); + } + + @Override + public boolean isCompletable() { + return !path.isEmpty(); + } + + @Override + public Result step(AI ai) { + if (this.path.isEmpty()) return Result.FAILED; + WorldCoordinate coordinate = path.get(0); + + if (!ai.navMesh.isWalkable(coordinate)) { + path = ai.navMesh.pathToNearest(ai.getPosition().toWorld(ai.team), destination); + if (path.isEmpty()) return Result.FAILED; + coordinate = path.get(0); + } + + AI.MoveResult moveResult = ai.checkMove(coordinate); + if (moveResult == AI.MoveResult.OVERDISTANCE && overDistanceCounter++ > 5) { + return Result.FAILED; + } + + if (moveResult == AI.MoveResult.FALLING) { + return Result.ONGOING; + } + + if (moveResult == AI.MoveResult.OK) { + path.remove(0); + ai.move(coordinate); + } + return path.isEmpty() ? Result.FINISHED : Result.ONGOING; + } + } + + class InteractAction implements Action { + private final LocalCoordinate destination; + + public InteractAction(LocalCoordinate destination) { + this.destination = destination; + } + + @Override + public boolean isCompletable() { + return true; + } + + @Override + public Result step(AI ai) { + ai.interact(destination); + return Result.FINISHED; + } + } +} diff --git a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/ai/LocalCoordinate.java b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/ai/LocalCoordinate.java new file mode 100644 index 00000000..334d8afe --- /dev/null +++ b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/ai/LocalCoordinate.java @@ -0,0 +1,87 @@ +/* + * This file is a part of the SteamWar software. + * + * Copyright (C) 2026 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.fightsystem.ai; + +import de.steamwar.fightsystem.fight.Fight; +import de.steamwar.fightsystem.fight.FightTeam; +import de.steamwar.fightsystem.utils.Region; +import lombok.AllArgsConstructor; +import lombok.Getter; +import org.bukkit.util.NumberConversions; + +@Getter +@AllArgsConstructor +public class LocalCoordinate { + private double x; + private double y; + private double z; + + public int getBlockX() { + return NumberConversions.floor(x); + } + + public int getBlockY() { + return NumberConversions.floor(y); + } + + public int getBlockZ() { + return NumberConversions.floor(z); + } + + public double distanceSquared(LocalCoordinate coordinate) { + return NumberConversions.square(x - coordinate.x) + NumberConversions.square(y - coordinate.y) + NumberConversions.square(z - coordinate.z); + } + + public WorldCoordinate toWorld(FightTeam team) { + Region extend = team.getExtendRegion(); + if(Fight.getUnrotated() == team) { + return new WorldCoordinate( + x + extend.getMinX(), + y + team.getSchemRegion().getMinY(), + z + extend.getMinZ() + ); + } else { + return new WorldCoordinate( + extend.getMaxX() - x, + y + team.getSchemRegion().getMinY(), + extend.getMaxZ() - z + ); + } + } + + public LocalCoordinate add(LocalCoordinate localCoordinate) { + this.x += localCoordinate.x; + this.y += localCoordinate.y; + this.z += localCoordinate.z; + return this; + } + + public LocalCoordinate add(double x, double y, double z) { + this.x += x; + this.y += y; + this.z += z; + return this; + } + + @Override + public String toString() { + return "Local{" + x + "," + y + "," + z + "}"; + } +} diff --git a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/ai/NavMesh.java b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/ai/NavMesh.java index 8531b41e..16b7e2bd 100644 --- a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/ai/NavMesh.java +++ b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/ai/NavMesh.java @@ -34,6 +34,7 @@ import org.bukkit.Bukkit; import org.bukkit.Material; import org.bukkit.World; import org.bukkit.block.Block; +import org.bukkit.block.data.BlockData; import org.bukkit.util.BoundingBox; import org.bukkit.util.Transformation; import org.bukkit.util.Vector; @@ -54,8 +55,7 @@ public class NavMesh { private static final Cuboid PLAYER_SHADOW = new Cuboid(0.2, 0, 0.2, 0.6, 1, 0.6); private static final Set RELATIVE_BLOCKS = new HashSet<>(); - protected static final org.bukkit.block.data.BlockData PATH_BLOCK = Material.LIME_STAINED_GLASS.createBlockData(); - protected static final Vector MIDDLE_VECTOR = new Vector(0.5, 0, 0.5); + protected static final BlockData PATH_BLOCK = Material.LIME_STAINED_GLASS.createBlockData(); static { for (int y = (int) -Math.ceil(PLAYER_FALL_DISTANCE); y <= Math.ceil(PLAYER_JUMP_HEIGHT); y++) { @@ -93,8 +93,6 @@ public class NavMesh { walkable.values().forEach(this::checkNeighbouring); - System.out.println("NavMesh2: " + walkable.size() + " " + connections.size()); - System.out.println("NavMesh initialized in " + (System.currentTimeMillis() - time) + " ms"); ready = true; }, 20); @@ -165,8 +163,8 @@ public class NavMesh { return new Pos(x + pos.x, y + pos.y, z + pos.z); } - public Vector toVector() { - return new Vector(x, y + floor, z); + public WorldCoordinate toWorld() { + return new WorldCoordinate(x, y + floor, z); } public double floorPosition() { @@ -245,8 +243,8 @@ public class NavMesh { } } - public void update(Vector posVector) { - Pos pos = toPos(posVector); + public void update(WorldCoordinate coordinate) { + Pos pos = toPos(coordinate); if (pos == null) return; for (int x = -2; x <= 2; x++) { @@ -274,47 +272,57 @@ public class NavMesh { Block thisBlock = WORLD.getBlockAt(pos.x, pos.y, pos.z); Block otherBlock = WORLD.getBlockAt(other.x, other.y, other.z); - // TODO: Ladder connections! - if (thisBlock.getType() != Material.LADDER && otherBlock.getType() == Material.LADDER && pos.y > other.y) continue; - - // Check if jumpable vertical distance - if (otherBlock.getType() != Material.LADDER && other.floorPosition() - pos.floorPosition() > PLAYER_JUMP_HEIGHT) continue; - // Check if Ceiling is high enough for player walking down! - if (other.ceilingPosition() < pos.floorPosition() + PLAYER_HEIGHT) continue; + if (thisBlock.getType() != Material.LADDER && otherBlock.getType() == Material.LADDER) { + if ((relative.x != 0 || relative.z != 0) && pos.y != other.y) continue; + } else { + // Check if jumpable vertical distance + if (other.floorPosition() - pos.floorPosition() > PLAYER_JUMP_HEIGHT) continue; + // Check if Ceiling is high enough for player walking down! + if (other.ceilingPosition() < pos.floorPosition() + PLAYER_HEIGHT) continue; + } connections.computeIfAbsent(other, __ -> new LinkedHashSet<>()).add(pos); } } - private Pos toPos(Vector vector) { - Pos pos = new Pos(vector.getBlockX(), vector.getBlockY(), vector.getBlockZ()); + private Pos toPos(WorldCoordinate coordinate) { + Pos pos = new Pos(coordinate.getBlockX(), coordinate.getBlockY(), coordinate.getBlockZ()); if (walkable.containsKey(pos)) return walkable.get(pos); pos = new Pos(pos.x, pos.y - 1, pos.z); if (walkable.containsKey(pos)) return walkable.get(pos); return null; } - public List walkable() { - return walkable.values().stream().map(Pos::toVector).collect(Collectors.toList()); + public boolean isWalkable(WorldCoordinate coordinate) { + Pos pos = new Pos(coordinate.getBlockX(), coordinate.getBlockY(), coordinate.getBlockZ()); + return walkable.containsKey(pos); } - public List pathToNearest(Vector fromVector, Vector toVector) { - Pos to = toPos(toVector); - if (walkable.containsKey(to)) return path(fromVector, toVector); + public List walkable() { + return walkable.values().stream().map(Pos::toWorld).collect(Collectors.toList()); + } + + public List pathToNearest(WorldCoordinate fromCoordinate, WorldCoordinate toCoordinate) { + Pos to = toPos(toCoordinate); + if (walkable.containsKey(to)) return path(toPos(fromCoordinate), to); Pos nearestPos = walkable.values() .stream() - .min(Comparator.comparingDouble(pos -> pos.toVector().distanceSquared(toVector))) + .min(Comparator.comparingDouble(pos -> pos.toWorld().distanceSquared(toCoordinate))) .orElse(null); if (nearestPos == null) return Collections.emptyList(); - return path(fromVector, nearestPos.toVector()); + return path(toPos(fromCoordinate), nearestPos); } - public List path(Vector fromVector, Vector toVector) { + public List path(WorldCoordinate fromCoordinate, WorldCoordinate toCoordinate) { + Pos from = toPos(fromCoordinate); + Pos to = toPos(toCoordinate); + return path(from, to); + } + + private List path(Pos from, Pos to) { server.getEntities().forEach(REntity::die); - Pos from = toPos(fromVector); - Pos to = toPos(toVector); if (from == null || to == null) { return Collections.emptyList(); } @@ -366,15 +374,15 @@ public class NavMesh { i++; } - List vectors = path.stream().skip(1).map(Pos::toVector).collect(Collectors.toList()); - vectors.forEach(vector -> { - RBlockDisplay block = new RBlockDisplay(server, vector.toLocation(WORLD)); + List coordinates = path.stream().skip(1).map(Pos::toWorld).collect(Collectors.toList()); + coordinates.forEach(coordinate -> { + RBlockDisplay block = new RBlockDisplay(server, coordinate.toLocation(WORLD)); block.setBlock(PATH_BLOCK); block.setTransform(new Transformation(new Vector3f(0, 0, 0), new AxisAngle4f(0, 0, 0, 0), new Vector3f(1, 0.001F, 1), new AxisAngle4f(0, 0, 0, 0))); }); - vectors.forEach(vector -> vector.add(MIDDLE_VECTOR)); - return vectors; + coordinates.forEach(vector -> vector.add(0.5, 0, 0.5)); + return coordinates; } } diff --git a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/ai/WorldCoordinate.java b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/ai/WorldCoordinate.java new file mode 100644 index 00000000..4cd7026c --- /dev/null +++ b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/ai/WorldCoordinate.java @@ -0,0 +1,106 @@ +/* + * This file is a part of the SteamWar software. + * + * Copyright (C) 2026 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.fightsystem.ai; + +import de.steamwar.fightsystem.fight.Fight; +import de.steamwar.fightsystem.fight.FightTeam; +import de.steamwar.fightsystem.utils.Region; +import lombok.AllArgsConstructor; +import lombok.Getter; +import org.bukkit.Location; +import org.bukkit.World; +import org.bukkit.util.NumberConversions; +import org.bukkit.util.Vector; + +@Getter +@AllArgsConstructor +public class WorldCoordinate { + private double x; + private double y; + private double z; + + public static WorldCoordinate from(Location location) { + return new WorldCoordinate(location.getX(), location.getY(), location.getZ()); + } + + public static WorldCoordinate from(Vector vector) { + return new WorldCoordinate(vector.getX(), vector.getY(), vector.getZ()); + } + + public int getBlockX() { + return NumberConversions.floor(x); + } + + public int getBlockY() { + return NumberConversions.floor(y); + } + + public int getBlockZ() { + return NumberConversions.floor(z); + } + + public double distanceSquared(WorldCoordinate coordinate) { + return NumberConversions.square(x - coordinate.x) + NumberConversions.square(y - coordinate.y) + NumberConversions.square(z - coordinate.z); + } + + public LocalCoordinate toLocal(FightTeam team) { + Region extend = team.getExtendRegion(); + if (Fight.getUnrotated() == team) { + return new LocalCoordinate( + x - extend.getMinX(), + y - team.getSchemRegion().getMinY(), + z - extend.getMinZ() + ); + } else { + return new LocalCoordinate( + extend.getMaxX() - x, + y - team.getSchemRegion().getMinY(), + extend.getMaxZ() - z + ); + } + } + + public WorldCoordinate add(WorldCoordinate worldCoordinate) { + this.x += worldCoordinate.x; + this.y += worldCoordinate.y; + this.z += worldCoordinate.z; + return this; + } + + public WorldCoordinate add(double x, double y, double z) { + this.x += x; + this.y += y; + this.z += z; + return this; + } + + public Vector toVector() { + return new Vector(x, y, z); + } + + public Location toLocation(World world) { + return new Location(world, x, y, z); + } + + @Override + public String toString() { + return "World{" + x + "," + y + "," + z + "}"; + } +} diff --git a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/ai/yoyonow/YoyoNowAI.java b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/ai/yoyonow/YoyoNowAI.java index 2cc6186b..e6d4196c 100644 --- a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/ai/yoyonow/YoyoNowAI.java +++ b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/ai/yoyonow/YoyoNowAI.java @@ -20,22 +20,18 @@ package de.steamwar.fightsystem.ai.yoyonow; import com.sk89q.worldedit.extent.clipboard.Clipboard; -import de.steamwar.entity.REntityServer; -import de.steamwar.fightsystem.ArenaMode; import de.steamwar.fightsystem.ai.AI; -import de.steamwar.fightsystem.ai.NavMesh; +import de.steamwar.fightsystem.ai.Action; +import de.steamwar.fightsystem.ai.WorldCoordinate; import de.steamwar.fightsystem.ai.schematic.WarMachine; import de.steamwar.fightsystem.ai.schematic.impl.MiniWarGear20; import de.steamwar.fightsystem.fight.FightTeam; -import de.steamwar.fightsystem.states.FightState; -import de.steamwar.fightsystem.states.OneShotStateDependent; import de.steamwar.sql.SchematicNode; import de.steamwar.sql.SteamwarUser; import org.bukkit.Bukkit; -import org.bukkit.Location; import org.bukkit.World; -import org.bukkit.util.Vector; +import java.util.ArrayList; import java.util.List; import java.util.Random; @@ -45,17 +41,9 @@ public class YoyoNowAI extends AI { private WarMachine selectedSchematic; - private final REntityServer entityServer = new REntityServer(); - private final NavMesh navMesh; - protected YoyoNowAI(FightTeam team) { super(team, SteamwarUser.get("YoyoNow.AI")); getEntity().setGlowing(true); - navMesh = new NavMesh(team); - - new OneShotStateDependent(ArenaMode.All, FightState.PostSchemSetup, () -> { - Bukkit.getOnlinePlayers().forEach(entityServer::addPlayer); - }); } @Override @@ -70,33 +58,30 @@ public class YoyoNowAI extends AI { } private Random random = new Random(); - private Vector destination = null; + private List actions = new ArrayList<>(); @Override protected void plan() { if (!navMesh.isReady()) return; - navMesh.update(getEntity().getLocation().toVector()); - - if (this.destination == null) { - List walkable = navMesh.walkable(); - Vector destination = walkable.get(random.nextInt(walkable.size())); - List path = navMesh.pathToNearest(getEntity().getLocation().toVector(), destination); - if (path.isEmpty()) return; - this.destination = untranslate(path.getLast()); + if (!actions.isEmpty()) { + Action.Result result = actions.get(0).step(this); + if (result == Action.Result.FAILED) { + actions.clear(); + return; + } + if (result == Action.Result.FINISHED) { + actions.remove(0); + return; + } return; } - Location location = translate(destination); - List path = navMesh.pathToNearest(getEntity().getLocation().toVector(), location.toVector()); - - if (path.isEmpty()) { - destination = null; - return; - } - move(untranslate(path.get(0))); - if (path.get(0).equals(destination)) { - destination = null; - } + List walkable = navMesh.walkable(); + WorldCoordinate destination = walkable.get(random.nextInt(walkable.size())); + Action action = new Action.MoveAction(this, destination); + if (!action.isCompletable()) return; + chat("Now moving to: " + destination); + actions.add(action); } }