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 de.steamwar.core.Core;
|
||||
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.countdown.*;
|
||||
import de.steamwar.fightsystem.event.HellsBells;
|
||||
|
@ -296,8 +296,14 @@ public abstract class AI {
|
||||
}
|
||||
|
||||
private void run() {
|
||||
if(queue.isEmpty())
|
||||
if(queue.isEmpty()) {
|
||||
try {
|
||||
plan();
|
||||
} catch (Throwable t) {
|
||||
stop();
|
||||
throw t;
|
||||
}
|
||||
}
|
||||
|
||||
if(!queue.isEmpty() && --queue.peek().delay == 0)
|
||||
queue.poll().run();
|
||||
|
@ -22,7 +22,7 @@ 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.ai.lixfel.LixfelPathplanner;
|
||||
import de.steamwar.fightsystem.fight.FightTeam;
|
||||
import de.steamwar.fightsystem.states.FightState;
|
||||
import de.steamwar.sql.SchematicData;
|
||||
@ -78,7 +78,7 @@ public class ChaosAI extends AI {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
|
||||
pathplanner = new LixfelPathplanner(clipboard);
|
||||
pathplanner = new LixfelPathplanner(this, clipboard);
|
||||
return schem;
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* 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
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
package de.steamwar.fightsystem.ai;
|
||||
package de.steamwar.fightsystem.ai.lixfel;
|
||||
|
||||
import com.sk89q.worldedit.extent.clipboard.Clipboard;
|
||||
import com.sk89q.worldedit.registry.state.Property;
|
||||
import com.sk89q.worldedit.world.block.BlockState;
|
||||
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.states.FightState;
|
||||
import de.steamwar.sql.SchematicData;
|
||||
import de.steamwar.sql.SchematicNode;
|
||||
import de.steamwar.sql.SteamwarUser;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.Particle;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
import org.bukkit.block.data.Waterlogged;
|
||||
import org.bukkit.util.Vector;
|
||||
@ -42,10 +41,10 @@ import java.util.function.Supplier;
|
||||
public class LixfelAI extends AI {
|
||||
|
||||
private final Random random = new Random();
|
||||
private final List<Supplier<PlanResult>> plans = new ArrayList<>();
|
||||
|
||||
private List<Supplier<PlanResult>> plans;
|
||||
private LixfelPathplanner pathplanner;
|
||||
private Vector plannedPosition;
|
||||
private MovementEmergency movementEmergency;
|
||||
|
||||
public LixfelAI(FightTeam team, String user) {
|
||||
super(team, SteamwarUser.get(user));
|
||||
@ -62,13 +61,16 @@ public class LixfelAI extends AI {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
|
||||
pathplanner = new LixfelPathplanner(clipboard);
|
||||
pathplanner = new LixfelPathplanner(this, clipboard);
|
||||
movementEmergency = new MovementEmergency();
|
||||
|
||||
plans.clear();
|
||||
plans.add(new MovementEmergency());
|
||||
//TODO low priority plan to reconnect split walkable grid
|
||||
plans = new ArrayList<>();
|
||||
plans.add(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(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
|
||||
public void move(Vector pos) {
|
||||
plannedPosition = pos;
|
||||
movementEmergency.setPlannedPosition(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> {
|
||||
@Override
|
||||
public PlanResult get() {
|
||||
@ -140,23 +122,43 @@ public class LixfelAI extends AI {
|
||||
}
|
||||
|
||||
private class MovementEmergency implements Supplier<PlanResult> {
|
||||
private Vector plannedPosition;
|
||||
|
||||
public void setPlannedPosition(Vector plannedPosition) {
|
||||
this.plannedPosition = plannedPosition;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PlanResult get() {
|
||||
//TODO defunct ladder
|
||||
if(plannedPosition == null || getPosition().equals(plannedPosition) || pathplanner.getLadders().contains(plannedPosition))
|
||||
if(plannedPosition == null)
|
||||
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 {
|
||||
pathplanner.getWalkable().add(getPosition()); //TODO idealized position, neighbour-table update
|
||||
//TODO handle offgrid location
|
||||
//TODO update grid
|
||||
return new PlanResult(10.0, () -> {
|
||||
Vector position = getPosition();
|
||||
if(position.getY() == plannedPosition.getY())
|
||||
return PlanResult.EMPTY;
|
||||
|
||||
});
|
||||
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();
|
||||
|
||||
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);
|
||||
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());
|
||||
entry.setValue(true);
|
||||
|
||||
@ -244,7 +246,7 @@ public class LixfelAI extends AI {
|
||||
if(activator == null)
|
||||
return PlanResult.EMPTY;
|
||||
|
||||
return inRange(110.0, activator, () -> new PlanResult(120.0, () -> {
|
||||
return pathplanner.inRange(110.0, activator, () -> new PlanResult(120.0, () -> {
|
||||
interact(activator);
|
||||
fired();
|
||||
}));
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* 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
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
package de.steamwar.fightsystem.ai;
|
||||
package de.steamwar.fightsystem.ai.lixfel;
|
||||
|
||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||
import com.sk89q.worldedit.extent.clipboard.Clipboard;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.regions.Region;
|
||||
import de.steamwar.fightsystem.Config;
|
||||
import de.steamwar.fightsystem.ai.AI;
|
||||
import de.steamwar.fightsystem.utils.WorldeditWrapper;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.block.Banner;
|
||||
@ -32,6 +33,7 @@ import org.bukkit.block.data.type.*;
|
||||
import org.bukkit.util.Vector;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class LixfelPathplanner {
|
||||
@ -76,14 +78,15 @@ public class LixfelPathplanner {
|
||||
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 List<Vector> ladders = new ArrayList<>();
|
||||
private final List<Vector> walkable = new ArrayList<>();
|
||||
private final Set<Vector> ladders = new HashSet<>();
|
||||
private final Map<Vector, Vector[]> neighbours = new HashMap<>();
|
||||
|
||||
public LixfelPathplanner(Clipboard clipboard) {
|
||||
clipboardToSchem = new Vector(Config.BluePasteRegion.getSizeX(), Config.BluePasteRegion.getSizeY(), Config.BluePasteRegion.getSizeZ())
|
||||
public LixfelPathplanner(AI ai, Clipboard clipboard) {
|
||||
this.ai = ai;
|
||||
|
||||
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));
|
||||
@ -92,18 +95,8 @@ public class LixfelPathplanner {
|
||||
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) {
|
||||
List<Vector> walkable = new ArrayList<>();
|
||||
Region region = clipboard.getRegion();
|
||||
clipboard.getRegion().forEach(vector -> {
|
||||
BlockVector3 below = vector.subtract(0, 1, 0);
|
||||
@ -132,36 +125,82 @@ public class LixfelPathplanner {
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
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());
|
||||
return walkable.stream()
|
||||
.filter(vector -> moddedNearby.stream()
|
||||
.allMatch(n -> n.distance(vector) <= distance && !neighbouring(n, vector)))
|
||||
.findAny().orElse(null);
|
||||
public Vector clipboardToSchem(BlockVector3 vector) {
|
||||
return toBukkit(vector.subtract(diff), 0.0, 0.0);
|
||||
}
|
||||
|
||||
public boolean isLadder(Vector vector) {
|
||||
return ladders.contains(vector);
|
||||
}
|
||||
|
||||
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) {
|
||||
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)
|
||||
return Collections.emptyList();
|
||||
|
||||
List<Vector> plan = new ArrayList<>(plan(start, intermediate));
|
||||
List<Vector> plan = new ArrayList<>(plan(start, Collections.singletonList(intermediate)));
|
||||
plan.add(destination);
|
||||
|
||||
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()));
|
||||
return plan(start, neighbours.keySet().stream().filter(vector -> vector.distance(destination) <= range).collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
public List<Vector> plan(Vector start, Vector destination) {
|
||||
return plan(start, Collections.singletonList(destination));
|
||||
}
|
||||
|
||||
public List<Vector> plan(Vector start, List<Vector> destinations) {
|
||||
private List<Vector> plan(Vector start, List<Vector> destinations) {
|
||||
for(Vector destination : destinations)
|
||||
if(neighbouring(start, destination))
|
||||
return Collections.singletonList(destination);
|
In neuem Issue referenzieren
Einen Benutzer sperren