Signed-off-by: Lixfel <agga-games@gmx.de>
Dieser Commit ist enthalten in:
Ursprung
97a9acdf53
Commit
f104ccc49a
@ -47,6 +47,6 @@ dependencies {
|
|||||||
compileOnly 'io.netty:netty-all:4.1.68.Final'
|
compileOnly 'io.netty:netty-all:4.1.68.Final'
|
||||||
compileOnly 'com.mojang:authlib:1.5.25'
|
compileOnly 'com.mojang:authlib:1.5.25'
|
||||||
|
|
||||||
compileOnly swdep("FastAsyncWorldEdit-1.18")
|
compileOnly swdep("WorldEdit-1.15")
|
||||||
compileOnly swdep("SpigotCore")
|
compileOnly swdep("SpigotCore")
|
||||||
}
|
}
|
||||||
|
@ -58,6 +58,7 @@ import java.util.logging.Level;
|
|||||||
|
|
||||||
public abstract class AI {
|
public abstract class AI {
|
||||||
|
|
||||||
|
public static final int MOVEMENT_DELAY = 4;
|
||||||
public static final double INTERACTION_RANGE = 5.0;
|
public static final double INTERACTION_RANGE = 5.0;
|
||||||
|
|
||||||
private static final Map<UUID, AI> ais = new HashMap<>();
|
private static final Map<UUID, AI> ais = new HashMap<>();
|
||||||
@ -209,7 +210,7 @@ public abstract class AI {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void move(Vector pos) {
|
public void move(Vector pos) {
|
||||||
queue.add(new Action(4) {
|
queue.add(new Action(MOVEMENT_DELAY) {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
Location location = entity.getLocation();
|
Location location = entity.getLocation();
|
||||||
|
@ -20,51 +20,41 @@
|
|||||||
package de.steamwar.fightsystem.ai;
|
package de.steamwar.fightsystem.ai;
|
||||||
|
|
||||||
import com.sk89q.worldedit.extent.clipboard.Clipboard;
|
import com.sk89q.worldedit.extent.clipboard.Clipboard;
|
||||||
import com.sk89q.worldedit.registry.state.BooleanProperty;
|
import com.sk89q.worldedit.registry.state.Property;
|
||||||
import com.sk89q.worldedit.world.block.BaseBlock;
|
import com.sk89q.worldedit.world.block.BlockState;
|
||||||
import de.steamwar.fightsystem.Config;
|
import de.steamwar.fightsystem.Config;
|
||||||
import de.steamwar.fightsystem.FightSystem;
|
import de.steamwar.fightsystem.ai.lixfel.PlanResult;
|
||||||
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.Bukkit;
|
|
||||||
import org.bukkit.Material;
|
import org.bukkit.Material;
|
||||||
import org.bukkit.Particle;
|
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.scheduler.BukkitTask;
|
|
||||||
import org.bukkit.util.Vector;
|
import org.bukkit.util.Vector;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Supplier;
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
public class LixfelAI extends AI {
|
public class LixfelAI extends AI {
|
||||||
|
|
||||||
private static final Random random = new Random();
|
private final Random random = new Random();
|
||||||
|
private final List<Supplier<PlanResult>> plans = new ArrayList<>();
|
||||||
|
|
||||||
private final BukkitTask timerTask;
|
|
||||||
private int currentTime;
|
|
||||||
private LixfelPathplanner pathplanner;
|
private LixfelPathplanner pathplanner;
|
||||||
private List<Vector> setup;
|
private Vector plannedPosition;
|
||||||
private int preRunningStart;
|
|
||||||
private List<TimedVector> timedStart;
|
|
||||||
private List<Cannon> cannons;
|
|
||||||
private Cannon currentCannon;
|
|
||||||
|
|
||||||
public LixfelAI(FightTeam team, String user) {
|
public LixfelAI(FightTeam team, String user) {
|
||||||
super(team, SteamwarUser.get(user));
|
super(team, SteamwarUser.get(user));
|
||||||
timerTask = Bukkit.getScheduler().runTaskTimer(FightSystem.getPlugin(), () -> currentTime++, 1, 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SchematicNode chooseSchematic() {
|
public SchematicNode chooseSchematic() {
|
||||||
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.stream().filter(s -> s.getName().equals("TheUnderground")).findAny().orElseGet(() -> publics.get(random.nextInt(publics.size())));
|
||||||
schem = publics.stream().filter(s -> s.getName().equals("TheUnderground")).findAny().orElse(schem);
|
|
||||||
Clipboard clipboard;
|
Clipboard clipboard;
|
||||||
try {
|
try {
|
||||||
clipboard = new SchematicData(schem).load();
|
clipboard = new SchematicData(schem).load();
|
||||||
@ -73,9 +63,13 @@ public class LixfelAI extends AI {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pathplanner = new LixfelPathplanner(clipboard);
|
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))));
|
plans.clear();
|
||||||
cannons = new ArrayList<>(Arrays.asList(
|
plans.add(new MovementEmergency());
|
||||||
|
plans.add(new ReadyPlan());
|
||||||
|
plans.add(new TimedInteraction(200.0, -1, new Vector(25, 15, 25)));
|
||||||
|
plans.add(new TimedInteraction(210.0, 420, new Vector(21, 15, 24)));
|
||||||
|
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),
|
||||||
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(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),
|
||||||
@ -84,125 +78,120 @@ public class LixfelAI extends AI {
|
|||||||
new Cannon(null, 23,5,9, 23,6,9, 23,7,9, 23,8,9),
|
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)
|
new Cannon(null, 27,5,9, 27,6,9, 27,7,9, 27,8,9)
|
||||||
));
|
));
|
||||||
assignWater(clipboard);
|
assignWater(cannons, clipboard);
|
||||||
chooseCannon();
|
plans.addAll(cannons);
|
||||||
|
|
||||||
return schem;
|
return schem;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void plan() {
|
public void move(Vector pos) {
|
||||||
switch (FightState.getFightState()) {
|
plannedPosition = pos;
|
||||||
case POST_SCHEM_SETUP:
|
super.move(pos);
|
||||||
if(prepareSchem() && scanEnemy())
|
|
||||||
setReady();
|
|
||||||
break;
|
|
||||||
case PRE_RUNNING:
|
|
||||||
if(start() && scanEnemy())
|
|
||||||
ensureInRange(currentCannon.tnt.keySet().iterator().next());
|
|
||||||
break;
|
|
||||||
case RUNNING:
|
|
||||||
while(currentCannon.shoot() && chooseCannon() && scanEnemy()) {}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void stop() {
|
protected void plan() {
|
||||||
if(!timerTask.isCancelled())
|
plans.stream().map(Supplier::get).filter(result -> result != PlanResult.EMPTY).max(Comparator.comparingDouble(PlanResult::getRating)).ifPresent(PlanResult::act);
|
||||||
timerTask.cancel();
|
|
||||||
|
|
||||||
super.stop();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void assignWater(Clipboard clipboard) {
|
private void assignWater(List<Cannon> cannons, Clipboard clipboard) {
|
||||||
BooleanProperty waterlogged = new BooleanProperty("waterlogged", Arrays.asList(false, true));
|
|
||||||
|
|
||||||
List<Vector> waterSources = new ArrayList<>();
|
List<Vector> waterSources = new ArrayList<>();
|
||||||
clipboard.getRegion().forEach(block -> {
|
clipboard.getRegion().forEach(block -> {
|
||||||
BaseBlock state = clipboard.getFullBlock(block);
|
BlockState state = clipboard.getBlock(block);
|
||||||
if(state.getBlockType().getMaterial().isLiquid() || Boolean.TRUE.equals(state.getState(waterlogged)))
|
Property<?> waterlogged = state.getBlockType().getPropertyMap().get("waterlogged");
|
||||||
|
if(state.getBlockType().getMaterial().isLiquid() || (waterlogged != null && Boolean.TRUE.equals(state.getState(waterlogged))))
|
||||||
waterSources.add(pathplanner.clipboardToSchem(block));
|
waterSources.add(pathplanner.clipboardToSchem(block));
|
||||||
});
|
});
|
||||||
|
|
||||||
for(Vector water : waterSources) {
|
for(Vector water : waterSources) {
|
||||||
cannons.stream().min(Comparator.comparingDouble(c -> c.waterDistance(water))).ifPresent(cannon -> cannon.addWater(water));
|
cannons.stream().filter(cannon -> cannon.getTNTMinY() >= water.getBlockY()).min(Comparator.comparingDouble(c -> c.waterDistance(water))).ifPresent(cannon -> cannon.addWater(water));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean prepareSchem() {
|
private PlanResult inRange(double rating, Vector target, Supplier<PlanResult> plan) {
|
||||||
return doWith(setup, this::interact);
|
return inRangeAndTime(rating, 0, target, plan);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean scanEnemy() {
|
private PlanResult inRangeAndTime(double rating, int time, Vector target, Supplier<PlanResult> plan) {
|
||||||
//TODO
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean start() {
|
|
||||||
if(preRunningStart == 0)
|
|
||||||
preRunningStart = currentTime;
|
|
||||||
|
|
||||||
if(timedStart.isEmpty())
|
|
||||||
return true;
|
|
||||||
|
|
||||||
long time = currentTime - preRunningStart;
|
|
||||||
TimedVector vector = timedStart.get(0);
|
|
||||||
if(!ensureInRange(vector.vector))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if(time >= vector.getTime()) {
|
|
||||||
interact(timedStart.remove(0).vector);
|
|
||||||
} else {
|
|
||||||
scanEnemy();
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean chooseCannon() {
|
|
||||||
List<Cannon> 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<Vector> targets, Consumer<Vector> method) {
|
|
||||||
if(targets.isEmpty())
|
|
||||||
return true;
|
|
||||||
|
|
||||||
if(ensureInRange(targets.get(0)))
|
|
||||||
method.accept(targets.remove(0));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean ensureInRange(Vector target) {
|
|
||||||
Vector position = getPosition();
|
Vector position = getPosition();
|
||||||
boolean inRange = new Vector(0, getEntity().getEyeHeight(), 0).add(position).distance(target) <= 5;
|
boolean inRange = new Vector(0, getEntity().getEyeHeight(), 0).add(position).distance(target) <= AI.INTERACTION_RANGE;
|
||||||
if(inRange)
|
if(inRange)
|
||||||
return true;
|
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));
|
List<Vector> path = new ArrayList<>(pathplanner.planToRange(position, new Vector(0, -getEntity().getEyeHeight(), 0).add(target), 5.0));
|
||||||
for(Vector v : path)
|
for(Vector v : path)
|
||||||
Config.world.spawnParticle(Particle.DRIP_LAVA, translate(v, false), 1);
|
Config.world.spawnParticle(Particle.DRIP_LAVA, translate(v, false), 1);
|
||||||
|
|
||||||
if(path.isEmpty()) {
|
if(path.isEmpty() || time > path.size()*AI.MOVEMENT_DELAY)
|
||||||
move(new Vector(0, 1.2, 0).add(position));
|
return PlanResult.EMPTY;
|
||||||
setTNT(position);
|
|
||||||
|
return new PlanResult(rating, () -> move(path.get(0)));
|
||||||
|
}
|
||||||
|
|
||||||
|
private class ReadyPlan implements Supplier<PlanResult> {
|
||||||
|
@Override
|
||||||
|
public PlanResult get() {
|
||||||
|
return new PlanResult(Double.MIN_VALUE, () -> {
|
||||||
|
setReady();
|
||||||
|
plans.remove(this);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class MovementEmergency implements Supplier<PlanResult> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PlanResult get() {
|
||||||
|
//TODO defunct ladder
|
||||||
|
if(plannedPosition == null || getPosition().equals(plannedPosition) || pathplanner.getLadders().contains(plannedPosition))
|
||||||
|
return PlanResult.EMPTY;
|
||||||
|
|
||||||
|
pathplanner.getWalkable().remove(plannedPosition); //TODO neighbour-table update
|
||||||
|
if(getEntity().getVelocity().getY() < 0) {
|
||||||
|
return new PlanResult(1000.0, () -> setTNT(getPosition().subtract(new Vector(0, 1.0, 0))));
|
||||||
} else {
|
} else {
|
||||||
move(path.get(0));
|
pathplanner.getWalkable().add(getPosition()); //TODO idealized position, neighbour-table update
|
||||||
|
//TODO handle offgrid location
|
||||||
|
//TODO update grid
|
||||||
|
return new PlanResult(10.0, () -> {
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
private class TimedInteraction implements Supplier<PlanResult> {
|
||||||
|
|
||||||
|
private final double rating;
|
||||||
|
private final int time;
|
||||||
|
private final Vector vector;
|
||||||
|
|
||||||
|
private int timeReference = 0;
|
||||||
|
public TimedInteraction(double rating, int time, Vector vector) {
|
||||||
|
this.rating = rating;
|
||||||
|
this.vector = vector;
|
||||||
|
this.time = time;
|
||||||
}
|
}
|
||||||
|
|
||||||
private class Cannon {
|
@Override
|
||||||
|
public PlanResult get() {
|
||||||
|
if(!FightState.ingame())
|
||||||
|
timeReference = getEntity().getTicksLived();
|
||||||
|
|
||||||
|
int timeRemaining = time - (getEntity().getTicksLived() - timeReference);
|
||||||
|
return inRangeAndTime(rating, timeRemaining, vector, () -> new PlanResult(rating, () -> {
|
||||||
|
interact(vector);
|
||||||
|
plans.remove(this);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class Cannon implements Supplier<PlanResult> {
|
||||||
private final List<Vector> water = new ArrayList<>();
|
private final List<Vector> water = new ArrayList<>();
|
||||||
private final Vector activator;
|
private final Vector activator;
|
||||||
private final Map<Vector, Boolean> tnt = new HashMap<>();
|
private final Map<Vector, Boolean> tnt = new HashMap<>();
|
||||||
|
private final int minY;
|
||||||
private int freeAt;
|
private int freeAt;
|
||||||
private int lastCannonCheck = -1;
|
private int lastCannonCheck = -1;
|
||||||
|
|
||||||
@ -212,6 +201,12 @@ public class LixfelAI extends AI {
|
|||||||
for(int i = 0; i < tntpos.length; i+=3) {
|
for(int i = 0; i < tntpos.length; i+=3) {
|
||||||
tnt.put(new Vector(tntpos[i], tntpos[i+1], tntpos[i+2]), false);
|
tnt.put(new Vector(tntpos[i], tntpos[i+1], tntpos[i+2]), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
minY = tnt.keySet().stream().min(Comparator.comparingInt(Vector::getBlockY)).orElse(new Vector()).getBlockY();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getTNTMinY() {
|
||||||
|
return minY;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addWater(Vector vector) {
|
public void addWater(Vector vector) {
|
||||||
@ -219,75 +214,47 @@ public class LixfelAI extends AI {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public double waterDistance(Vector vector) {
|
public double waterDistance(Vector vector) {
|
||||||
return tnt.keySet().stream().mapToDouble(t -> {
|
return tnt.keySet().stream().mapToDouble(t -> t.distance(vector)).min().orElse(Double.MAX_VALUE);
|
||||||
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() {
|
@Override
|
||||||
return currentTime >= freeAt && !water.isEmpty();
|
public PlanResult get() {
|
||||||
}
|
//TODO smarter ratings
|
||||||
|
if(getEntity().getTicksLived() < freeAt || water.isEmpty())
|
||||||
public boolean shoot() {
|
return PlanResult.EMPTY;
|
||||||
for(Vector w : water)
|
|
||||||
Config.world.spawnParticle(Particle.VILLAGER_HAPPY, translate(w, true).add(0.5, 0.5, 0.5), 1);
|
|
||||||
|
|
||||||
if(currentTime < freeAt || water.isEmpty())
|
|
||||||
return true;
|
|
||||||
|
|
||||||
if(lastCannonCheck < freeAt) {
|
if(lastCannonCheck < freeAt) {
|
||||||
|
return new PlanResult(80.0, () -> {
|
||||||
Vector w = water.get(random.nextInt(water.size()));
|
Vector w = water.get(random.nextInt(water.size()));
|
||||||
BlockData data = getBlockData(w);
|
BlockData data = getBlockData(w);
|
||||||
if(data.getMaterial() == Material.WATER || (data instanceof Waterlogged && ((Waterlogged)data).isWaterlogged()))
|
if(data.getMaterial() == Material.WATER || (data instanceof Waterlogged && ((Waterlogged)data).isWaterlogged()))
|
||||||
lastCannonCheck = freeAt;
|
lastCannonCheck = freeAt;
|
||||||
else
|
else
|
||||||
water.remove(w);
|
water.remove(w);
|
||||||
return false;
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
for(Map.Entry<Vector, Boolean> entry : tnt.entrySet()) {
|
return tnt.entrySet().stream().filter(entry -> !entry.getValue()).map(entry -> inRangeAndTime(90.0, FightState.infight() ? 0 : 1, entry.getKey(), () -> new PlanResult(100.0, () -> {
|
||||||
if(!entry.getValue()) {
|
|
||||||
if(ensureInRange(entry.getKey())) {
|
|
||||||
setTNT(entry.getKey());
|
setTNT(entry.getKey());
|
||||||
entry.setValue(true);
|
entry.setValue(true);
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(activator != null) {
|
if(activator == null && tnt.values().stream().allMatch(b -> b))
|
||||||
if(!ensureInRange(activator))
|
fired();
|
||||||
return false;
|
}))).max(Comparator.comparingDouble(PlanResult::getRating)).orElseGet(() -> {
|
||||||
|
if(activator == null)
|
||||||
|
return PlanResult.EMPTY;
|
||||||
|
|
||||||
|
return inRange(110.0, activator, () -> new PlanResult(120.0, () -> {
|
||||||
interact(activator);
|
interact(activator);
|
||||||
|
fired();
|
||||||
|
}));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
freeAt = currentTime + 80;
|
private void fired() {
|
||||||
|
freeAt = getEntity().getTicksLived() + 80;
|
||||||
for(Map.Entry<Vector, Boolean> entry : tnt.entrySet())
|
for(Map.Entry<Vector, Boolean> entry : tnt.entrySet())
|
||||||
entry.setValue(false);
|
entry.setValue(false);
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class TimedVector {
|
|
||||||
private final long time;
|
|
||||||
private final Vector vector;
|
|
||||||
|
|
||||||
public TimedVector(long time, Vector vector) {
|
|
||||||
this.time = time;
|
|
||||||
this.vector = vector;
|
|
||||||
}
|
|
||||||
|
|
||||||
public long getTime() {
|
|
||||||
return time;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Vector getVector() {
|
|
||||||
return vector;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -78,6 +78,7 @@ public class LixfelPathplanner {
|
|||||||
|
|
||||||
private final Vector clipboardToSchem;
|
private final Vector clipboardToSchem;
|
||||||
private final BlockVector3 diff;
|
private final BlockVector3 diff;
|
||||||
|
private final List<Vector> ladders = new ArrayList<>();
|
||||||
private final List<Vector> walkable = new ArrayList<>();
|
private final List<Vector> walkable = new ArrayList<>();
|
||||||
private final Map<Vector, Vector[]> neighbours = new HashMap<>();
|
private final Map<Vector, Vector[]> neighbours = new HashMap<>();
|
||||||
|
|
||||||
@ -95,6 +96,9 @@ public class LixfelPathplanner {
|
|||||||
return toBukkit(vector.subtract(diff), 0.0, 0.0);
|
return toBukkit(vector.subtract(diff), 0.0, 0.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<Vector> getLadders() {
|
||||||
|
return ladders;
|
||||||
|
}
|
||||||
public List<Vector> getWalkable() {
|
public List<Vector> getWalkable() {
|
||||||
return walkable;
|
return walkable;
|
||||||
}
|
}
|
||||||
@ -117,10 +121,10 @@ public class LixfelPathplanner {
|
|||||||
if(height >= 1.0 && region.contains(above))
|
if(height >= 1.0 && region.contains(above))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
Vector block = toBukkit(vector.subtract(diff), 0.5, Math.max(height, 0.0));
|
||||||
|
walkable.add(block);
|
||||||
if(height < 0.0)
|
if(height < 0.0)
|
||||||
height = 0.0;
|
ladders.add(block);
|
||||||
|
|
||||||
walkable.add(toBukkit(vector.subtract(diff), 0.5, height));
|
|
||||||
});
|
});
|
||||||
|
|
||||||
for(Vector vector : walkable) {
|
for(Vector vector : walkable) {
|
||||||
|
@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
* This file is a part of the SteamWar software.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2024 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package de.steamwar.fightsystem.ai.lixfel;
|
||||||
|
|
||||||
|
|
||||||
|
public class PlanResult {
|
||||||
|
public static final PlanResult EMPTY = new PlanResult(Double.NEGATIVE_INFINITY, () -> {});
|
||||||
|
|
||||||
|
private final double rating;
|
||||||
|
private final Runnable action;
|
||||||
|
|
||||||
|
public PlanResult(double rating, Runnable action) {
|
||||||
|
this.rating = rating;
|
||||||
|
this.action = action;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getRating() {
|
||||||
|
return rating;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void act() {
|
||||||
|
action.run();
|
||||||
|
}
|
||||||
|
}
|
In neuem Issue referenzieren
Einen Benutzer sperren