Signed-off-by: Lixfel <agga-games@gmx.de>
Dieser Commit ist enthalten in:
Ursprung
f104ccc49a
Commit
6fa873204b
@ -22,7 +22,7 @@ package de.steamwar.fightsystem;
|
|||||||
import com.comphenix.tinyprotocol.TinyProtocol;
|
import com.comphenix.tinyprotocol.TinyProtocol;
|
||||||
import de.steamwar.core.Core;
|
import de.steamwar.core.Core;
|
||||||
import de.steamwar.fightsystem.ai.DummyAI;
|
import de.steamwar.fightsystem.ai.DummyAI;
|
||||||
import de.steamwar.fightsystem.ai.LixfelAI;
|
import de.steamwar.fightsystem.ai.lixfel.LixfelAI;
|
||||||
import de.steamwar.fightsystem.commands.*;
|
import de.steamwar.fightsystem.commands.*;
|
||||||
import de.steamwar.fightsystem.countdown.*;
|
import de.steamwar.fightsystem.countdown.*;
|
||||||
import de.steamwar.fightsystem.event.HellsBells;
|
import de.steamwar.fightsystem.event.HellsBells;
|
||||||
|
@ -296,8 +296,14 @@ public abstract class AI {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void run() {
|
private void run() {
|
||||||
if(queue.isEmpty())
|
if(queue.isEmpty()) {
|
||||||
plan();
|
try {
|
||||||
|
plan();
|
||||||
|
} catch (Throwable t) {
|
||||||
|
stop();
|
||||||
|
throw t;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if(!queue.isEmpty() && --queue.peek().delay == 0)
|
if(!queue.isEmpty() && --queue.peek().delay == 0)
|
||||||
queue.poll().run();
|
queue.poll().run();
|
||||||
|
@ -22,7 +22,7 @@ package de.steamwar.fightsystem.ai.chaos;
|
|||||||
import com.sk89q.worldedit.extent.clipboard.Clipboard;
|
import com.sk89q.worldedit.extent.clipboard.Clipboard;
|
||||||
import de.steamwar.fightsystem.FightSystem;
|
import de.steamwar.fightsystem.FightSystem;
|
||||||
import de.steamwar.fightsystem.ai.AI;
|
import de.steamwar.fightsystem.ai.AI;
|
||||||
import de.steamwar.fightsystem.ai.LixfelPathplanner;
|
import de.steamwar.fightsystem.ai.lixfel.LixfelPathplanner;
|
||||||
import de.steamwar.fightsystem.fight.FightTeam;
|
import de.steamwar.fightsystem.fight.FightTeam;
|
||||||
import de.steamwar.fightsystem.states.FightState;
|
import de.steamwar.fightsystem.states.FightState;
|
||||||
import de.steamwar.sql.SchematicData;
|
import de.steamwar.sql.SchematicData;
|
||||||
@ -78,7 +78,7 @@ public class ChaosAI extends AI {
|
|||||||
throw new IllegalStateException(e);
|
throw new IllegalStateException(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
pathplanner = new LixfelPathplanner(clipboard);
|
pathplanner = new LixfelPathplanner(this, clipboard);
|
||||||
return schem;
|
return schem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* This file is a part of the SteamWar software.
|
* This file is a part of the SteamWar software.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2023 SteamWar.de-Serverteam
|
* Copyright (C) 2024 SteamWar.de-Serverteam
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
@ -17,20 +17,19 @@
|
|||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package de.steamwar.fightsystem.ai;
|
package de.steamwar.fightsystem.ai.lixfel;
|
||||||
|
|
||||||
import com.sk89q.worldedit.extent.clipboard.Clipboard;
|
import com.sk89q.worldedit.extent.clipboard.Clipboard;
|
||||||
import com.sk89q.worldedit.registry.state.Property;
|
import com.sk89q.worldedit.registry.state.Property;
|
||||||
import com.sk89q.worldedit.world.block.BlockState;
|
import com.sk89q.worldedit.world.block.BlockState;
|
||||||
import de.steamwar.fightsystem.Config;
|
import de.steamwar.fightsystem.Config;
|
||||||
import de.steamwar.fightsystem.ai.lixfel.PlanResult;
|
import de.steamwar.fightsystem.ai.AI;
|
||||||
import de.steamwar.fightsystem.fight.FightTeam;
|
import de.steamwar.fightsystem.fight.FightTeam;
|
||||||
import de.steamwar.fightsystem.states.FightState;
|
import de.steamwar.fightsystem.states.FightState;
|
||||||
import de.steamwar.sql.SchematicData;
|
import de.steamwar.sql.SchematicData;
|
||||||
import de.steamwar.sql.SchematicNode;
|
import de.steamwar.sql.SchematicNode;
|
||||||
import de.steamwar.sql.SteamwarUser;
|
import de.steamwar.sql.SteamwarUser;
|
||||||
import org.bukkit.Material;
|
import org.bukkit.Material;
|
||||||
import org.bukkit.Particle;
|
|
||||||
import org.bukkit.block.data.BlockData;
|
import org.bukkit.block.data.BlockData;
|
||||||
import org.bukkit.block.data.Waterlogged;
|
import org.bukkit.block.data.Waterlogged;
|
||||||
import org.bukkit.util.Vector;
|
import org.bukkit.util.Vector;
|
||||||
@ -42,10 +41,10 @@ import java.util.function.Supplier;
|
|||||||
public class LixfelAI extends AI {
|
public class LixfelAI extends AI {
|
||||||
|
|
||||||
private final Random random = new Random();
|
private final Random random = new Random();
|
||||||
private final List<Supplier<PlanResult>> plans = new ArrayList<>();
|
|
||||||
|
|
||||||
|
private List<Supplier<PlanResult>> plans;
|
||||||
private LixfelPathplanner pathplanner;
|
private LixfelPathplanner pathplanner;
|
||||||
private Vector plannedPosition;
|
private MovementEmergency movementEmergency;
|
||||||
|
|
||||||
public LixfelAI(FightTeam team, String user) {
|
public LixfelAI(FightTeam team, String user) {
|
||||||
super(team, SteamwarUser.get(user));
|
super(team, SteamwarUser.get(user));
|
||||||
@ -62,13 +61,16 @@ public class LixfelAI extends AI {
|
|||||||
throw new IllegalStateException(e);
|
throw new IllegalStateException(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
pathplanner = new LixfelPathplanner(clipboard);
|
pathplanner = new LixfelPathplanner(this, clipboard);
|
||||||
|
movementEmergency = new MovementEmergency();
|
||||||
|
|
||||||
plans.clear();
|
//TODO low priority plan to reconnect split walkable grid
|
||||||
plans.add(new MovementEmergency());
|
plans = new ArrayList<>();
|
||||||
|
plans.add(movementEmergency);
|
||||||
plans.add(new ReadyPlan());
|
plans.add(new ReadyPlan());
|
||||||
plans.add(new TimedInteraction(200.0, -1, new Vector(25, 15, 25)));
|
plans.add(new TimedInteraction(200.0, -1, new Vector(25, 15, 25)));
|
||||||
plans.add(new TimedInteraction(210.0, 420, new Vector(21, 15, 24)));
|
plans.add(new TimedInteraction(210.0, 420, new Vector(21, 15, 24)));
|
||||||
|
|
||||||
List<Cannon> cannons = new ArrayList<>(Arrays.asList(
|
List<Cannon> cannons = new ArrayList<>(Arrays.asList(
|
||||||
new Cannon(new Vector(11,25,11), 10,23,14, 12,23,14, 10,23,12, 12,23,12, 12,24,15, 10,24,14, 12,23,15, 12,24,14, 11,24,12, 10,24,15, 12,24,12, 10,23,15, 10,24,12),
|
new Cannon(new Vector(11,25,11), 10,23,14, 12,23,14, 10,23,12, 12,23,12, 12,24,15, 10,24,14, 12,23,15, 12,24,14, 11,24,12, 10,24,15, 12,24,12, 10,23,15, 10,24,12),
|
||||||
new Cannon(new Vector(39,25,11), 38,24,15, 38,23,12, 40,23,14, 40,24,12, 40,23,15, 40,24,14, 39,24,12, 38,23,14, 40,24,15, 40,23,12, 38,23,15, 38,24,12, 38,24,14),
|
new Cannon(new Vector(39,25,11), 38,24,15, 38,23,12, 40,23,14, 40,24,12, 40,23,15, 40,24,14, 39,24,12, 38,23,14, 40,24,15, 40,23,12, 38,23,15, 38,24,12, 38,24,14),
|
||||||
@ -86,7 +88,7 @@ public class LixfelAI extends AI {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void move(Vector pos) {
|
public void move(Vector pos) {
|
||||||
plannedPosition = pos;
|
movementEmergency.setPlannedPosition(pos);
|
||||||
super.move(pos);
|
super.move(pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -109,26 +111,6 @@ public class LixfelAI extends AI {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private PlanResult inRange(double rating, Vector target, Supplier<PlanResult> plan) {
|
|
||||||
return inRangeAndTime(rating, 0, target, plan);
|
|
||||||
}
|
|
||||||
|
|
||||||
private PlanResult inRangeAndTime(double rating, int time, Vector target, Supplier<PlanResult> plan) {
|
|
||||||
Vector position = getPosition();
|
|
||||||
boolean inRange = new Vector(0, getEntity().getEyeHeight(), 0).add(position).distance(target) <= AI.INTERACTION_RANGE;
|
|
||||||
if(inRange)
|
|
||||||
return time <= 0 ? plan.get() : PlanResult.EMPTY;
|
|
||||||
|
|
||||||
List<Vector> path = new ArrayList<>(pathplanner.planToRange(position, new Vector(0, -getEntity().getEyeHeight(), 0).add(target), 5.0));
|
|
||||||
for(Vector v : path)
|
|
||||||
Config.world.spawnParticle(Particle.DRIP_LAVA, translate(v, false), 1);
|
|
||||||
|
|
||||||
if(path.isEmpty() || time > path.size()*AI.MOVEMENT_DELAY)
|
|
||||||
return PlanResult.EMPTY;
|
|
||||||
|
|
||||||
return new PlanResult(rating, () -> move(path.get(0)));
|
|
||||||
}
|
|
||||||
|
|
||||||
private class ReadyPlan implements Supplier<PlanResult> {
|
private class ReadyPlan implements Supplier<PlanResult> {
|
||||||
@Override
|
@Override
|
||||||
public PlanResult get() {
|
public PlanResult get() {
|
||||||
@ -140,23 +122,43 @@ public class LixfelAI extends AI {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private class MovementEmergency implements Supplier<PlanResult> {
|
private class MovementEmergency implements Supplier<PlanResult> {
|
||||||
|
private Vector plannedPosition;
|
||||||
|
|
||||||
|
public void setPlannedPosition(Vector plannedPosition) {
|
||||||
|
this.plannedPosition = plannedPosition;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PlanResult get() {
|
public PlanResult get() {
|
||||||
//TODO defunct ladder
|
if(plannedPosition == null)
|
||||||
if(plannedPosition == null || getPosition().equals(plannedPosition) || pathplanner.getLadders().contains(plannedPosition))
|
|
||||||
return PlanResult.EMPTY;
|
return PlanResult.EMPTY;
|
||||||
|
|
||||||
pathplanner.getWalkable().remove(plannedPosition); //TODO neighbour-table update
|
Vector position = getPosition();
|
||||||
if(getEntity().getVelocity().getY() < 0) {
|
if(position.getY() == plannedPosition.getY())
|
||||||
return new PlanResult(1000.0, () -> setTNT(getPosition().subtract(new Vector(0, 1.0, 0))));
|
return PlanResult.EMPTY;
|
||||||
} else {
|
|
||||||
pathplanner.getWalkable().add(getPosition()); //TODO idealized position, neighbour-table update
|
|
||||||
//TODO handle offgrid location
|
|
||||||
//TODO update grid
|
|
||||||
return new PlanResult(10.0, () -> {
|
|
||||||
|
|
||||||
});
|
boolean falling = getEntity().getVelocity().getY() < 0;
|
||||||
|
if(position.getY() > plannedPosition.getY()) {
|
||||||
|
if(!falling) { //Update grid accordingly
|
||||||
|
pathplanner.removePosition(plannedPosition);
|
||||||
|
position.setX(position.getBlockX() + 0.5);
|
||||||
|
position.setZ(position.getBlockZ() + 0.5);
|
||||||
|
pathplanner.addPosition(position);
|
||||||
|
}
|
||||||
|
return PlanResult.EMPTY;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(pathplanner.isLadder(plannedPosition) && getEntity().getVelocity().getY() >= -0.23) //alternative measure: falling speed
|
||||||
|
return PlanResult.EMPTY;
|
||||||
|
|
||||||
|
pathplanner.removePosition(plannedPosition); //obviously not walkable anymore
|
||||||
|
if(falling) {
|
||||||
|
return new PlanResult(1000.0, () -> setTNT(position.subtract(new Vector(0, 1.0, 0))));
|
||||||
|
} else {
|
||||||
|
position.setX(position.getBlockX() + 0.5);
|
||||||
|
position.setZ(position.getBlockZ() + 0.5);
|
||||||
|
pathplanner.addPosition(position);
|
||||||
|
return PlanResult.EMPTY;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -180,7 +182,7 @@ public class LixfelAI extends AI {
|
|||||||
timeReference = getEntity().getTicksLived();
|
timeReference = getEntity().getTicksLived();
|
||||||
|
|
||||||
int timeRemaining = time - (getEntity().getTicksLived() - timeReference);
|
int timeRemaining = time - (getEntity().getTicksLived() - timeReference);
|
||||||
return inRangeAndTime(rating, timeRemaining, vector, () -> new PlanResult(rating, () -> {
|
return pathplanner.inRangeAndTime(rating, timeRemaining, vector, () -> new PlanResult(rating, () -> {
|
||||||
interact(vector);
|
interact(vector);
|
||||||
plans.remove(this);
|
plans.remove(this);
|
||||||
}));
|
}));
|
||||||
@ -234,7 +236,7 @@ public class LixfelAI extends AI {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return tnt.entrySet().stream().filter(entry -> !entry.getValue()).map(entry -> inRangeAndTime(90.0, FightState.infight() ? 0 : 1, entry.getKey(), () -> new PlanResult(100.0, () -> {
|
return tnt.entrySet().stream().filter(entry -> !entry.getValue()).map(entry -> pathplanner.inRangeAndTime(90.0, FightState.infight() ? 0 : 20*Config.PreFightDuration/AI.MOVEMENT_DELAY, entry.getKey(), () -> new PlanResult(100.0, () -> {
|
||||||
setTNT(entry.getKey());
|
setTNT(entry.getKey());
|
||||||
entry.setValue(true);
|
entry.setValue(true);
|
||||||
|
|
||||||
@ -244,7 +246,7 @@ public class LixfelAI extends AI {
|
|||||||
if(activator == null)
|
if(activator == null)
|
||||||
return PlanResult.EMPTY;
|
return PlanResult.EMPTY;
|
||||||
|
|
||||||
return inRange(110.0, activator, () -> new PlanResult(120.0, () -> {
|
return pathplanner.inRange(110.0, activator, () -> new PlanResult(120.0, () -> {
|
||||||
interact(activator);
|
interact(activator);
|
||||||
fired();
|
fired();
|
||||||
}));
|
}));
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* This file is a part of the SteamWar software.
|
* This file is a part of the SteamWar software.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2023 SteamWar.de-Serverteam
|
* Copyright (C) 2024 SteamWar.de-Serverteam
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
@ -17,13 +17,14 @@
|
|||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package de.steamwar.fightsystem.ai;
|
package de.steamwar.fightsystem.ai.lixfel;
|
||||||
|
|
||||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||||
import com.sk89q.worldedit.extent.clipboard.Clipboard;
|
import com.sk89q.worldedit.extent.clipboard.Clipboard;
|
||||||
import com.sk89q.worldedit.math.BlockVector3;
|
import com.sk89q.worldedit.math.BlockVector3;
|
||||||
import com.sk89q.worldedit.regions.Region;
|
import com.sk89q.worldedit.regions.Region;
|
||||||
import de.steamwar.fightsystem.Config;
|
import de.steamwar.fightsystem.Config;
|
||||||
|
import de.steamwar.fightsystem.ai.AI;
|
||||||
import de.steamwar.fightsystem.utils.WorldeditWrapper;
|
import de.steamwar.fightsystem.utils.WorldeditWrapper;
|
||||||
import org.bukkit.Material;
|
import org.bukkit.Material;
|
||||||
import org.bukkit.block.Banner;
|
import org.bukkit.block.Banner;
|
||||||
@ -32,6 +33,7 @@ import org.bukkit.block.data.type.*;
|
|||||||
import org.bukkit.util.Vector;
|
import org.bukkit.util.Vector;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import java.util.function.Supplier;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
public class LixfelPathplanner {
|
public class LixfelPathplanner {
|
||||||
@ -76,14 +78,15 @@ public class LixfelPathplanner {
|
|||||||
return new Vector(vector.getX() + offset, vector.getY() + height, vector.getZ() + offset);
|
return new Vector(vector.getX() + offset, vector.getY() + height, vector.getZ() + offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
private final Vector clipboardToSchem;
|
private final AI ai;
|
||||||
private final BlockVector3 diff;
|
private final BlockVector3 diff;
|
||||||
private final List<Vector> ladders = new ArrayList<>();
|
private final Set<Vector> ladders = new HashSet<>();
|
||||||
private final List<Vector> walkable = new ArrayList<>();
|
|
||||||
private final Map<Vector, Vector[]> neighbours = new HashMap<>();
|
private final Map<Vector, Vector[]> neighbours = new HashMap<>();
|
||||||
|
|
||||||
public LixfelPathplanner(Clipboard clipboard) {
|
public LixfelPathplanner(AI ai, Clipboard clipboard) {
|
||||||
clipboardToSchem = new Vector(Config.BluePasteRegion.getSizeX(), Config.BluePasteRegion.getSizeY(), Config.BluePasteRegion.getSizeZ())
|
this.ai = ai;
|
||||||
|
|
||||||
|
Vector clipboardToSchem = new Vector(Config.BluePasteRegion.getSizeX(), Config.BluePasteRegion.getSizeY(), Config.BluePasteRegion.getSizeZ())
|
||||||
.subtract(WorldeditWrapper.impl.getDimensions(clipboard))
|
.subtract(WorldeditWrapper.impl.getDimensions(clipboard))
|
||||||
.multiply(0.5)
|
.multiply(0.5)
|
||||||
.add(new Vector(Config.PreperationArea, 0, Config.PreperationArea));
|
.add(new Vector(Config.PreperationArea, 0, Config.PreperationArea));
|
||||||
@ -92,18 +95,8 @@ public class LixfelPathplanner {
|
|||||||
fillWalkable(clipboard);
|
fillWalkable(clipboard);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Vector clipboardToSchem(BlockVector3 vector) {
|
|
||||||
return toBukkit(vector.subtract(diff), 0.0, 0.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<Vector> getLadders() {
|
|
||||||
return ladders;
|
|
||||||
}
|
|
||||||
public List<Vector> getWalkable() {
|
|
||||||
return walkable;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void fillWalkable(Clipboard clipboard) {
|
private void fillWalkable(Clipboard clipboard) {
|
||||||
|
List<Vector> walkable = new ArrayList<>();
|
||||||
Region region = clipboard.getRegion();
|
Region region = clipboard.getRegion();
|
||||||
clipboard.getRegion().forEach(vector -> {
|
clipboard.getRegion().forEach(vector -> {
|
||||||
BlockVector3 below = vector.subtract(0, 1, 0);
|
BlockVector3 below = vector.subtract(0, 1, 0);
|
||||||
@ -132,36 +125,82 @@ public class LixfelPathplanner {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Deprecated
|
public Vector clipboardToSchem(BlockVector3 vector) {
|
||||||
public Vector walkableNearby(double eyeHeight, double distance, List<Vector> nearby) {
|
return toBukkit(vector.subtract(diff), 0.0, 0.0);
|
||||||
List<Vector> moddedNearby = nearby.stream().map(n -> n.clone().subtract(new Vector(0, eyeHeight, 0))).collect(Collectors.toList());
|
}
|
||||||
return walkable.stream()
|
|
||||||
.filter(vector -> moddedNearby.stream()
|
public boolean isLadder(Vector vector) {
|
||||||
.allMatch(n -> n.distance(vector) <= distance && !neighbouring(n, vector)))
|
return ladders.contains(vector);
|
||||||
.findAny().orElse(null);
|
}
|
||||||
|
|
||||||
|
public void addPosition(Vector vector) {
|
||||||
|
Vector[] n = neighbours.keySet().stream().filter(neighbour -> neighbouring(neighbour, vector)).toArray(Vector[]::new);
|
||||||
|
neighbours.put(vector, n);
|
||||||
|
|
||||||
|
for(Vector neighbour : n) {
|
||||||
|
neighbours.computeIfPresent(neighbour, (neighBour, array) -> {
|
||||||
|
array = Arrays.copyOf(array, array.length+1);
|
||||||
|
array[array.length-1] = vector;
|
||||||
|
return array;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removePosition(Vector vector) {
|
||||||
|
ladders.remove(vector);
|
||||||
|
Vector[] n = neighbours.remove(vector);
|
||||||
|
if(n == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for(Vector neighbour : n) {
|
||||||
|
neighbours.computeIfPresent(neighbour, (neighBour, array) -> {
|
||||||
|
for(int i = 0; i < array.length; i++) {
|
||||||
|
if(array[i] == vector) {
|
||||||
|
Vector[] newArray = Arrays.copyOf(array, array.length-1);
|
||||||
|
System.arraycopy(array, i+1, newArray, i, newArray.length-i);
|
||||||
|
return newArray;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new IllegalStateException();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public PlanResult inRange(double rating, Vector target, Supplier<PlanResult> plan) {
|
||||||
|
return inRangeAndTime(rating, 0, target, plan);
|
||||||
|
}
|
||||||
|
|
||||||
|
public PlanResult inRangeAndTime(double rating, int time, Vector target, Supplier<PlanResult> plan) {
|
||||||
|
Vector position = ai.getPosition();
|
||||||
|
double eyeHeight = ai.getEntity().getEyeHeight();
|
||||||
|
boolean inRange = new Vector(0, eyeHeight, 0).add(position).distance(target) <= AI.INTERACTION_RANGE;
|
||||||
|
if(inRange)
|
||||||
|
return time <= 0 ? plan.get() : PlanResult.EMPTY;
|
||||||
|
|
||||||
|
List<Vector> path = new ArrayList<>(planToRange(position, new Vector(0, -eyeHeight, 0).add(target), 5.0));
|
||||||
|
if(path.isEmpty() || time > path.size()*AI.MOVEMENT_DELAY)
|
||||||
|
return PlanResult.EMPTY;
|
||||||
|
|
||||||
|
return new PlanResult(rating, () -> ai.move(path.get(0)));
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Vector> planToAnywhere(Vector start, Vector destination) {
|
public List<Vector> planToAnywhere(Vector start, Vector destination) {
|
||||||
Vector intermediate = walkable.stream().filter(vector -> neighbouring(vector, destination)).findAny().orElse(null);
|
Vector intermediate = neighbours.keySet().stream().filter(vector -> neighbouring(vector, destination)).findAny().orElse(null);
|
||||||
|
|
||||||
if(intermediate == null)
|
if(intermediate == null)
|
||||||
return Collections.emptyList();
|
return Collections.emptyList();
|
||||||
|
|
||||||
List<Vector> plan = new ArrayList<>(plan(start, intermediate));
|
List<Vector> plan = new ArrayList<>(plan(start, Collections.singletonList(intermediate)));
|
||||||
plan.add(destination);
|
plan.add(destination);
|
||||||
|
|
||||||
return plan;
|
return plan;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Vector> planToRange(Vector start, Vector destination, double range) {
|
public List<Vector> planToRange(Vector start, Vector destination, double range) {
|
||||||
return plan(start, walkable.stream().filter(vector -> vector.distance(destination) <= range).collect(Collectors.toList()));
|
return plan(start, neighbours.keySet().stream().filter(vector -> vector.distance(destination) <= range).collect(Collectors.toList()));
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Vector> plan(Vector start, Vector destination) {
|
private List<Vector> plan(Vector start, List<Vector> destinations) {
|
||||||
return plan(start, Collections.singletonList(destination));
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<Vector> plan(Vector start, List<Vector> destinations) {
|
|
||||||
for(Vector destination : destinations)
|
for(Vector destination : destinations)
|
||||||
if(neighbouring(start, destination))
|
if(neighbouring(start, destination))
|
||||||
return Collections.singletonList(destination);
|
return Collections.singletonList(destination);
|
In neuem Issue referenzieren
Einen Benutzer sperren