Improved Pathplanning, WIP StateMachine
Alle Prüfungen waren erfolgreich
SteamWarCI Build successful
Alle Prüfungen waren erfolgreich
SteamWarCI Build successful
Signed-off-by: Lixfel <agga-games@gmx.de>
Dieser Commit ist enthalten in:
Ursprung
71ddeb4ac8
Commit
39ccb113a8
@ -26,17 +26,14 @@ import de.steamwar.sql.SchematicNode;
|
|||||||
import de.steamwar.sql.SteamwarUser;
|
import de.steamwar.sql.SteamwarUser;
|
||||||
import org.bukkit.util.Vector;
|
import org.bukkit.util.Vector;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.Collections;
|
import java.util.function.Function;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Random;
|
|
||||||
|
|
||||||
public class LixfelAI extends AI {
|
public class LixfelAI extends AI {
|
||||||
|
|
||||||
private Random random;
|
private Random random;
|
||||||
private LixfelPathplanner pathplanner;
|
private LixfelPathplanner pathplanner;
|
||||||
private List<Cannon> cannons;
|
private Action action;
|
||||||
private List<Cannon> shootingList;
|
|
||||||
|
|
||||||
public LixfelAI(FightTeam team, String user) {
|
public LixfelAI(FightTeam team, String user) {
|
||||||
super(team, SteamwarUser.get(user));
|
super(team, SteamwarUser.get(user));
|
||||||
@ -45,8 +42,6 @@ public class LixfelAI extends AI {
|
|||||||
@Override
|
@Override
|
||||||
public SchematicNode chooseSchematic() {
|
public SchematicNode chooseSchematic() {
|
||||||
random = new Random();
|
random = new Random();
|
||||||
cannons = new ArrayList<>();
|
|
||||||
shootingList = new ArrayList<>();
|
|
||||||
|
|
||||||
List<SchematicNode> publics = SchematicNode.getAllSchematicsOfType(0, Config.SchematicType.toDB());
|
List<SchematicNode> publics = SchematicNode.getAllSchematicsOfType(0, Config.SchematicType.toDB());
|
||||||
SchematicNode schem = publics.get(random.nextInt(publics.size()));
|
SchematicNode schem = publics.get(random.nextInt(publics.size()));
|
||||||
@ -54,47 +49,194 @@ public class LixfelAI extends AI {
|
|||||||
|
|
||||||
pathplanner = new LixfelPathplanner(schem);
|
pathplanner = new LixfelPathplanner(schem);
|
||||||
|
|
||||||
cannons.add(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));
|
action = new BlockAction(Collections.emptyList(), Collections.singletonList(new Vector(25, 15, 25)),
|
||||||
cannons.add(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 MoveToRangeAction(new Vector(21, 15, 24),
|
||||||
cannons.add(new Cannon(new Vector(12,18,11), 13,17,15, 13,17,16, 13,18,16, 13,18,14, 14,18,14, 14,17,15, 14,17,16, 14,18,16, 13,17,14, 14,17,14, 13,18,15, 14,18,15));
|
new FunctionAction(ai -> {
|
||||||
cannons.add(new Cannon(new Vector(38,18,11), 37,18,14, 36,18,14, 36,17,15, 37,17,15, 37,18,15, 36,18,15, 36,17,14, 37,17,14, 36,17,16, 37,17,16, 36,18,16, 37,18,16));
|
setReady();
|
||||||
cannons.add(new Cannon(new Vector(8,9,16), 10,11,17, 10,8,19, 10,8,17, 11,8,19, 11,8,15, 10,8,15, 12,8,15, 10,10,15, 12,7,19, 11,10,15, 12,8,19, 12,7,15, 11,7,15, 10,9,17, 11,9,19, 12,9,19, 10,9,19, 10,7,17, 11,7,19, 10,7,15, 10,7,19, 10,10,17, 12,9,15, 10,9,15, 11,9,15, 12,10,19, 11,10,19, 12,10,15, 10,6,17, 10,10,19));
|
return FightState.getFightState() == FightState.PRE_RUNNING;
|
||||||
//cannons.add(new Cannon(null, 23,5,9, 23,6,9, 23,7,9, 23,8,9));
|
},
|
||||||
//cannons.add(new Cannon(null, 27,5,9, 27,6,9, 27,7,9, 27,8,9));
|
new WaitAction(420,
|
||||||
cannons.add(new Cannon(null, 23,5,9, 23,6,9, 23,7,9, 23,8,9, 27,5,9, 27,6,9, 27,7,9, 27,8,9, 23,5,9, 23,6,9, 23,7,9, 23,8,9, 27,5,9, 27,6,9, 27,7,9, 27,8,9, 23,5,9, 23,6,9, 23,7,9, 23,8,9, 27,5,9, 27,6,9, 27,7,9, 27,8,9, 23,5,9, 23,6,9, 23,7,9, 23,8,9, 27,5,9, 27,6,9, 27,7,9, 27,8,9));
|
new BlockAction(Collections.emptyList(), Collections.singletonList(new Vector(21, 15, 24)),
|
||||||
Collections.shuffle(cannons);
|
new FunctionAction(ai -> FightState.getFightState() == FightState.RUNNING,
|
||||||
|
new ChooseCannonAction(
|
||||||
|
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(12,18,11), 13,17,15, 13,17,16, 13,18,16, 13,18,14, 14,18,14, 14,17,15, 14,17,16, 14,18,16, 13,17,14, 14,17,14, 13,18,15, 14,18,15),
|
||||||
|
new Cannon(new Vector(38,18,11), 37,18,14, 36,18,14, 36,17,15, 37,17,15, 37,18,15, 36,18,15, 36,17,14, 37,17,14, 36,17,16, 37,17,16, 36,18,16, 37,18,16),
|
||||||
|
new Cannon(new Vector(8,9,16), 10,11,17, 10,8,19, 10,8,17, 11,8,19, 11,8,15, 10,8,15, 12,8,15, 10,10,15, 12,7,19, 11,10,15, 12,8,19, 12,7,15, 11,7,15, 10,9,17, 11,9,19, 12,9,19, 10,9,19, 10,7,17, 11,7,19, 10,7,15, 10,7,19, 10,10,17, 12,9,15, 10,9,15, 11,9,15, 12,10,19, 11,10,19, 12,10,15, 10,6,17, 10,10,19),
|
||||||
|
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)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
return schem;
|
return schem;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
LixfelPathplanner getPathplanner() {
|
||||||
protected void plan() {
|
return pathplanner;
|
||||||
setReady();
|
|
||||||
if(shootingList.isEmpty())
|
|
||||||
shootingList.addAll(cannons);
|
|
||||||
|
|
||||||
if(shootingList.isEmpty() || FightState.getFightState() != FightState.RUNNING) {
|
|
||||||
moveTo(pathplanner.getWalkable().get(random.nextInt(pathplanner.getWalkable().size())));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Cannon cannon = shootingList.remove(0);
|
|
||||||
cannon.shoot();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean moveTo(Vector destination) {
|
void setAction(Action action) {
|
||||||
List<Vector> path = pathplanner.plan(getPosition(), destination);
|
this.action = action;
|
||||||
if(path.isEmpty())
|
}
|
||||||
return false;
|
|
||||||
|
|
||||||
path.forEach(this::move);
|
@Override
|
||||||
return true;
|
protected void plan() {
|
||||||
|
action.plan(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
private abstract static class Action {
|
||||||
|
private Action next;
|
||||||
|
|
||||||
|
public Action(Action next) {
|
||||||
|
this.next = next;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract void plan(LixfelAI ai);
|
||||||
|
|
||||||
|
public void setNext(Action followup) {
|
||||||
|
this.next = followup;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void next(LixfelAI ai) {
|
||||||
|
ai.setAction(next);
|
||||||
|
next.plan(ai);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class FunctionAction extends Action {
|
||||||
|
|
||||||
|
private final Function<LixfelAI, Boolean> action;
|
||||||
|
public FunctionAction(Function<LixfelAI, Boolean> action, Action followup) {
|
||||||
|
super(followup);
|
||||||
|
this.action = action;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void plan(LixfelAI ai) {
|
||||||
|
if(action.apply(ai))
|
||||||
|
next(ai);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class WaitAction extends Action {
|
||||||
|
|
||||||
|
private int remaining;
|
||||||
|
public WaitAction(int ticks, Action followup) {
|
||||||
|
super(followup);
|
||||||
|
this.remaining = ticks;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void plan(LixfelAI ai) {
|
||||||
|
if(--remaining == 0)
|
||||||
|
next(ai);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class MoveToRangeAction extends Action {
|
||||||
|
|
||||||
|
private final Vector target;
|
||||||
|
public MoveToRangeAction(Vector target, Action next) {
|
||||||
|
super(next);
|
||||||
|
this.target = target;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void plan(LixfelAI ai) {
|
||||||
|
Vector position = ai.getPosition();
|
||||||
|
Vector eyePosition = new Vector(0, ai.getEntity().getEyeHeight(), 0).add(position);
|
||||||
|
|
||||||
|
if(eyePosition.distance(target) > 5) {
|
||||||
|
List<Vector> path = new ArrayList<>(ai.getPathplanner().planToRange(position, target, 5.0));
|
||||||
|
if(path.isEmpty())
|
||||||
|
path.add(new Vector(0, 1, 0).add(position));
|
||||||
|
|
||||||
|
ai.move(path.get(0));
|
||||||
|
} else {
|
||||||
|
next(ai);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class BlockAction extends Action {
|
||||||
|
private final List<Vector> tntToPlace;
|
||||||
|
private final List<Vector> interactables;
|
||||||
|
|
||||||
|
public BlockAction(List<Vector> tntToPlace, List<Vector> interactables, Action followup) {
|
||||||
|
super(followup);
|
||||||
|
this.tntToPlace = new ArrayList<>(tntToPlace);
|
||||||
|
this.interactables = new ArrayList<>(interactables);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void plan(LixfelAI ai) {
|
||||||
|
if(!tntToPlace.isEmpty()) {
|
||||||
|
if(outOfRange(ai, tntToPlace.get(0)))
|
||||||
|
return;
|
||||||
|
|
||||||
|
ai.setTNT(tntToPlace.remove(0));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!interactables.isEmpty()) {
|
||||||
|
if(outOfRange(ai, interactables.get(0)))
|
||||||
|
return;
|
||||||
|
|
||||||
|
ai.interact(interactables.remove(0));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
next(ai);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean outOfRange(LixfelAI ai, Vector location) {
|
||||||
|
Vector position = ai.getPosition();
|
||||||
|
Vector eyePosition = new Vector(0, ai.getEntity().getEyeHeight(), 0).add(position);
|
||||||
|
boolean outOfRange = eyePosition.distance(location) > 5;
|
||||||
|
|
||||||
|
if(outOfRange) {
|
||||||
|
List<Vector> path = new ArrayList<>(ai.getPathplanner().planToRange(position, location, 5.0));
|
||||||
|
if(path.isEmpty())
|
||||||
|
path.add(new Vector(0, 1, 0).add(position));
|
||||||
|
|
||||||
|
System.out.println(ai.getEntity().getName() + ": " + position + "->" + path.get(0));
|
||||||
|
ai.move(path.get(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
return outOfRange;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class ChooseCannonAction extends Action {
|
||||||
|
|
||||||
|
private final List<Cannon> cannons;
|
||||||
|
private final List<Cannon> shootingList = new ArrayList<>();
|
||||||
|
|
||||||
|
public ChooseCannonAction(Cannon... cannons) {
|
||||||
|
super(null);
|
||||||
|
this.cannons = Arrays.asList(cannons);
|
||||||
|
Collections.shuffle(this.cannons);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void plan(LixfelAI ai) {
|
||||||
|
if(shootingList.isEmpty())
|
||||||
|
shootingList.addAll(cannons);
|
||||||
|
|
||||||
|
setNext(shootingList.remove(0).toAction(this));
|
||||||
|
next(ai);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class Cannon {
|
private class Cannon {
|
||||||
private final Vector activator;
|
private final Vector activator;
|
||||||
private final List<Vector> tnt = new ArrayList<>();
|
private final List<Vector> tnt = new ArrayList<>();
|
||||||
private final Vector entityLocation;
|
|
||||||
|
|
||||||
public Cannon(Vector activator, int... tntpos) {
|
public Cannon(Vector activator, int... tntpos) {
|
||||||
this.activator = activator;
|
this.activator = activator;
|
||||||
@ -102,25 +244,10 @@ public class LixfelAI extends AI {
|
|||||||
for(int i = 0; i < tntpos.length; i+=3) {
|
for(int i = 0; i < tntpos.length; i+=3) {
|
||||||
tnt.add(new Vector(tntpos[i], tntpos[i+1], tntpos[i+2]));
|
tnt.add(new Vector(tntpos[i], tntpos[i+1], tntpos[i+2]));
|
||||||
}
|
}
|
||||||
|
|
||||||
List<Vector> locations = new ArrayList<>(tnt);
|
|
||||||
if(activator != null)
|
|
||||||
locations.add(activator);
|
|
||||||
entityLocation = pathplanner.walkableNearby(getEntity().getEyeHeight(), 5, locations);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean shoot() {
|
public BlockAction toAction(Action next) {
|
||||||
if(entityLocation == null)
|
return new BlockAction(new ArrayList<>(tnt), activator == null ? Collections.emptyList() : Collections.singletonList(activator), next);
|
||||||
return false;
|
|
||||||
|
|
||||||
if(!moveTo(entityLocation))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
tnt.forEach(LixfelAI.this::setTNT);
|
|
||||||
if(activator != null)
|
|
||||||
interact(activator);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -125,6 +125,7 @@ public class LixfelPathplanner {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
public Vector walkableNearby(double eyeHeight, double distance, List<Vector> nearby) {
|
public Vector walkableNearby(double eyeHeight, double distance, List<Vector> nearby) {
|
||||||
List<Vector> moddedNearby = nearby.stream().map(n -> n.clone().subtract(new Vector(0, eyeHeight, 0))).collect(Collectors.toList());
|
List<Vector> moddedNearby = nearby.stream().map(n -> n.clone().subtract(new Vector(0, eyeHeight, 0))).collect(Collectors.toList());
|
||||||
return walkable.stream()
|
return walkable.stream()
|
||||||
@ -145,12 +146,21 @@ public class LixfelPathplanner {
|
|||||||
return plan;
|
return plan;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<Vector> planToRange(Vector start, Vector destination, double range) {
|
||||||
|
return plan(start, walkable.stream().filter(vector -> vector.distance(destination) <= range).collect(Collectors.toList()));
|
||||||
|
}
|
||||||
|
|
||||||
public List<Vector> plan(Vector start, Vector destination) {
|
public List<Vector> plan(Vector start, Vector destination) {
|
||||||
if(neighbouring(start, destination))
|
return plan(start, Collections.singletonList(destination));
|
||||||
return Collections.singletonList(destination);
|
}
|
||||||
|
|
||||||
|
public List<Vector> plan(Vector start, List<Vector> destinations) {
|
||||||
|
for(Vector destination : destinations)
|
||||||
|
if(neighbouring(start, destination))
|
||||||
|
return Collections.singletonList(destination);
|
||||||
|
|
||||||
Map<Vector, Vector> approach = new HashMap<>();
|
Map<Vector, Vector> approach = new HashMap<>();
|
||||||
Set<Vector> checking = Collections.singleton(destination);
|
Set<Vector> checking = new HashSet<>(destinations);
|
||||||
|
|
||||||
while(!checking.isEmpty()) {
|
while(!checking.isEmpty()) {
|
||||||
Set<Vector> toCheck = new HashSet<>();
|
Set<Vector> toCheck = new HashSet<>();
|
||||||
@ -168,7 +178,7 @@ public class LixfelPathplanner {
|
|||||||
List<Vector> path = new ArrayList<>();
|
List<Vector> path = new ArrayList<>();
|
||||||
path.add(firstStep);
|
path.add(firstStep);
|
||||||
|
|
||||||
while(path.get(path.size()-1) != destination) {
|
while(!destinations.contains(path.get(path.size()-1))) {
|
||||||
path.add(approach.get(path.get(path.size()-1)));
|
path.add(approach.get(path.get(path.size()-1)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
In neuem Issue referenzieren
Einen Benutzer sperren