SteamWar/FightSystem
Archiviert
13
1

Commits vergleichen

...
Dieses Repository wurde am 2024-08-05 archiviert. Du kannst Dateien ansehen und es klonen, aber nicht pushen oder Issues/Pull-Requests öffnen.

18 Commits

Autor SHA1 Nachricht Datum
7b26b7bf91 Found Something
Einige Prüfungen sind fehlgeschlagen
SteamWarCI Build failed
2023-12-03 16:47:36 +01:00
Chaoscaot
ab08f5c131
Merge remote-tracking branch 'origin/AINavMesh' into chaos-ai
Einige Prüfungen sind fehlgeschlagen
SteamWarCI Build failed
# Conflicts:
#	FightSystem_Core/src/de/steamwar/fightsystem/ai/AI.java
#	FightSystem_Core/src/de/steamwar/fightsystem/ai/LixfelAI.java
2023-09-05 20:56:03 +02:00
yoyosource
cffa60e43d Fix NavMesh
Alle Prüfungen waren erfolgreich
SteamWarCI Build successful
2023-09-05 20:55:05 +02:00
yoyosource
578c0056cd Add TODO line
Alle Prüfungen waren erfolgreich
SteamWarCI Build successful
2023-09-04 21:42:51 +02:00
yoyosource
f10238cae2 Update NavMesh and implement some kind of update
Alle Prüfungen waren erfolgreich
SteamWarCI Build successful
2023-09-04 21:30:51 +02:00
yoyosource
69a0e02ab9 Update and Fix some NavMesh stuff
Alle Prüfungen waren erfolgreich
SteamWarCI Build successful
2023-09-04 18:38:05 +02:00
yoyosource
45fd36907c Add some more TODOS
Alle Prüfungen waren erfolgreich
SteamWarCI Build successful
2023-09-03 22:06:11 +02:00
yoyosource
c3e39296b5 Add Neighbour Navigation calculation
Alle Prüfungen waren erfolgreich
SteamWarCI Build successful
2023-09-03 21:50:06 +02:00
yoyosource
2452d72f2c Add NavMesh
Alle Prüfungen waren erfolgreich
SteamWarCI Build successful
2023-09-03 18:16:39 +02:00
39ccb113a8 Improved Pathplanning, WIP StateMachine
Alle Prüfungen waren erfolgreich
SteamWarCI Build successful
Signed-off-by: Lixfel <agga-games@gmx.de>
2023-09-03 13:39:38 +02:00
Chaoscaot
71ddeb4ac8
Upgrades, Leude, Upgrades!
Alle Prüfungen waren erfolgreich
SteamWarCI Build successful
2023-09-03 00:44:33 +02:00
Chaoscaot
c507e7ec97
Merge remote-tracking branch 'origin/lixfel-ai-v1' into chaos-ai 2023-09-02 23:19:43 +02:00
efb2537097 Improved Pathplanning (less suffocating)
Alle Prüfungen waren erfolgreich
SteamWarCI Build successful
Signed-off-by: Lixfel <agga-games@gmx.de>
2023-09-02 23:19:07 +02:00
Chaoscaot
8e963bffef
Merge remote-tracking branch 'origin/lixfel-ai-v1' into chaos-ai 2023-09-02 22:18:36 +02:00
5a0614974e Fix planToAnywhere
Alle Prüfungen waren erfolgreich
SteamWarCI Build successful
Signed-off-by: Lixfel <agga-games@gmx.de>
2023-09-02 22:18:13 +02:00
Chaoscaot
2151134dcc
Revert FightSystem
Alle Prüfungen waren erfolgreich
SteamWarCI Build successful
2023-09-02 22:13:51 +02:00
Chaoscaot
fc7b8b6233
Basics™
Alle Prüfungen waren erfolgreich
SteamWarCI Build successful
2023-09-02 22:12:18 +02:00
78ae119719 Fix Button press, Lixfel AI v1
Alle Prüfungen waren erfolgreich
SteamWarCI Build successful
Signed-off-by: Lixfel <agga-games@gmx.de>
2023-09-02 21:51:05 +02:00
13 geänderte Dateien mit 1555 neuen und 52 gelöschten Zeilen

Datei anzeigen

@ -22,6 +22,8 @@ package de.steamwar.fightsystem;
import com.comphenix.tinyprotocol.TinyProtocol;
import de.steamwar.core.Core;
import de.steamwar.fightsystem.ai.LixfelAI;
import de.steamwar.fightsystem.ai.navmesh.NavMesh;
import de.steamwar.fightsystem.ai.chaos.ChaosAI;
import de.steamwar.fightsystem.commands.*;
import de.steamwar.fightsystem.countdown.*;
import de.steamwar.fightsystem.event.HellsBells;
@ -42,6 +44,7 @@ import de.steamwar.fightsystem.utils.*;
import de.steamwar.fightsystem.winconditions.*;
import de.steamwar.message.Message;
import de.steamwar.sql.SchematicNode;
import de.steamwar.sql.SteamwarUser;
import org.bukkit.Bukkit;
import org.bukkit.plugin.java.JavaPlugin;
@ -167,6 +170,13 @@ public class FightSystem extends JavaPlugin {
}else if(Config.mode == ArenaMode.PREPARE) {
Fight.getUnrotated().setSchem(SchematicNode.getSchematicNode(Config.PrepareSchemID));
}
FightStatistics.unrank();
Bukkit.getScheduler().runTask(getPlugin(), () -> {
new ChaosAI(Fight.getBlueTeam());
new LixfelAI(Fight.getRedTeam(), SteamwarUser.get(-1));
});
}
@Override

Datei anzeigen

@ -35,13 +35,13 @@ import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.Note;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.block.Lectern;
import org.bukkit.block.data.BlockData;
import org.bukkit.block.data.Openable;
import org.bukkit.block.data.Powerable;
import org.bukkit.block.data.*;
import org.bukkit.block.data.type.Comparator;
import org.bukkit.block.data.type.NoteBlock;
import org.bukkit.block.data.type.Repeater;
import org.bukkit.block.data.type.Switch;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
@ -68,7 +68,7 @@ public abstract class AI {
return ais.get(uuid);
}
private final FightTeam team;
protected final FightTeam team;
private final LivingEntity entity;
private final BukkitTask task;
private final Queue<Action> queue = new ArrayDeque<>();
@ -120,6 +120,22 @@ public abstract class AI {
Chat.broadcastChat("PARTICIPANT_CHAT", team.getColoredName(), entity.getName(), message);
}
protected Vector toAIPosition(Vector location) {
Region extend = team.getExtendRegion();
if(Fight.getUnrotated() == team)
return new Vector(
location.getX() - extend.getMinX(),
location.getY() - team.getSchemRegion().getMinY(),
location.getZ() - extend.getMinZ()
);
else
return new Vector(
extend.getMaxX() - location.getX(),
location.getY() - team.getSchemRegion().getMinY(),
extend.getMaxZ() - location.getZ()
);
}
protected Vector getPosition() {
Location location = entity.getLocation();
Region extend = team.getExtendRegion();
@ -155,8 +171,10 @@ public abstract class AI {
return;
Location location = translate(pos, true);
if(interactionDistanceViolation(location))
if(interactionDistanceViolation(location)) {
chat("2 smoll pepe hönds!");
return;
}
Block block = location.getBlock();
if(block.getType() == Material.AIR)
@ -170,8 +188,10 @@ public abstract class AI {
@Override
public void run() {
Location location = translate(pos, true);
if(interactionDistanceViolation(location))
if(interactionDistanceViolation(location)) {
chat("Ich komme da nicht dran!");
return;
}
interact(location.getBlock());
}
@ -205,15 +225,17 @@ public abstract class AI {
public void run() {
Location location = entity.getLocation();
Location target = translate(pos, false);
/*
if(Math.abs(location.getX() - target.getX()) > 1 || Math.abs(location.getY() - target.getY()) > 1.2 || Math.abs(location.getZ() - target.getZ()) > 1) {
FightSystem.getPlugin().getLogger().log(Level.INFO, () -> entity.getName() + ": Overdistance movement " + location.toVector() + " " + target.toVector());
return;
}
*/
if(!team.getFightPlayer(entity).canEntern() && !team.getExtendRegion().inRegion(target))
return;
entity.teleport(target, PlayerTeleportEvent.TeleportCause.COMMAND);
entity.teleport(target, PlayerTeleportEvent.TeleportCause.PLUGIN);
}
});
}
@ -249,12 +271,34 @@ public abstract class AI {
powerable.setPowered(false);
block.setBlockData(powerable);
updateButton(block);
}, type.name().endsWith("STONE_BUTTON") ? 20 : 30);
}
powerable.setPowered(!isPowered);
}
block.setBlockData(data);
if(data instanceof Switch) {
updateButton(block);
}
}
private void updateButton(Block block) {
Switch sw = (Switch) block.getBlockData();
FaceAttachable.AttachedFace face = sw.getAttachedFace();
if (face == FaceAttachable.AttachedFace.FLOOR) {
update(block.getRelative(BlockFace.DOWN));
} else if (face == FaceAttachable.AttachedFace.CEILING) {
update(block.getRelative(BlockFace.UP));
} else {
update(block.getRelative(sw.getFacing().getOppositeFace()));
}
}
private void update(Block block) {
BlockData data = block.getBlockData();
block.setType(Material.BARRIER);
block.setBlockData(data);
}
private void run() {
@ -265,7 +309,7 @@ public abstract class AI {
queue.poll().run();
}
private Location translate(Vector pos, boolean blockPos) {
public Location translate(Vector pos, boolean blockPos) {
Region extend = team.getExtendRegion();
if(Fight.getUnrotated() == team)
return new Location(

Datei anzeigen

@ -19,42 +19,102 @@
package de.steamwar.fightsystem.ai;
import de.steamwar.entity.REntityServer;
import de.steamwar.fightsystem.Config;
import de.steamwar.fightsystem.ai.navmesh.NavMesh;
import de.steamwar.fightsystem.fight.FightTeam;
import de.steamwar.sql.SchematicNode;
import de.steamwar.sql.SteamwarUser;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.util.Vector;
import java.util.List;
import java.util.Random;
import java.util.*;
public class LixfelAI extends AI {
private final Random random = new Random();
private LixfelPathplanner pathplanner;
private final REntityServer entityServer = new REntityServer();
private final FightTeam team;
private final NavMesh navMesh;
public LixfelAI(FightTeam team, String user) {
super(team, SteamwarUser.get(user));
public LixfelAI(FightTeam team, SteamwarUser user) {
super(team, user);
this.team = team;
navMesh = new NavMesh(team, entityServer);
}
@Override
public SchematicNode chooseSchematic() {
List<SchematicNode> publics = SchematicNode.getAllSchematicsOfType(0, Config.SchematicType.toDB());
SchematicNode schem = publics.get(new Random().nextInt(publics.size()));
pathplanner = new LixfelPathplanner(schem);
return schem;
if (false) {
List<SchematicNode> publics = SchematicNode.getAllSchematicsOfType(0, Config.SchematicType.toDB());
SchematicNode schem = publics.get(new Random().nextInt(publics.size()));
return schem;
}
// return SchematicNode.byIdAndUser(SteamwarUser.get(0), 111476);
return SchematicNode.byIdAndUser(SteamwarUser.get(0), 98711);
}
@Override
public boolean acceptJoinRequest(Player player, FightTeam team) {
if (team == this.team) {
entityServer.addPlayer(player);
}
return super.acceptJoinRequest(player, team);
}
private Vector source = null;
private Vector destination = null;
private int index = 0;
@Override
protected void plan() {
setReady();
Vector destination = pathplanner.getWalkable().get(random.nextInt(pathplanner.getWalkable().size()));
List<Vector> path = pathplanner.plan(getPosition(), destination);
if(!path.isEmpty())
chat("Path size: " + path.size());
for(Vector p : path) {
move(p);
if (navMesh == null) return;
if (!getEntity().isOnGround() && getEntity().getLocation().getBlock().getType() != Material.LADDER) return;
if (source == null || destination == null) {
source = getEntity().getLocation().toVector();
List<Vector> walkableBlocks = navMesh.getWalkableBlocks(source);
if (walkableBlocks.isEmpty()) return;
destination = walkableBlocks.get(random.nextInt(walkableBlocks.size()));
index = 0;
}
List<Vector> oldRoute = navMesh.path(source, destination);
navMesh.update(getEntity().getLocation().toVector());
List<Vector> path = navMesh.path(source, destination);
// TODO: New Route detection
if (path.isEmpty()) {
source = null;
destination = null;
chat("no route");
return;
}
if (!oldRoute.equals(path)) {
source = getEntity().getLocation().toVector();
index = 0;
chat("new route");
return;
}
if (index == 0) {
chat(source + " -> " + destination + " = " + path.size());
}
if (index > path.size()) {
source = null;
destination = null;
chat("route cancelled");
return;
}
Vector location = path.get(index++);
move(toAIPosition(location));
if (index == path.size()) {
source = null;
destination = null;
}
}
}

Datei anzeigen

@ -19,30 +19,60 @@
package de.steamwar.fightsystem.ai;
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 com.sk89q.worldedit.world.block.BlockType;
import com.sk89q.worldedit.world.block.BaseBlock;
import de.steamwar.fightsystem.Config;
import de.steamwar.fightsystem.utils.WorldeditWrapper;
import de.steamwar.sql.SchematicData;
import de.steamwar.sql.SchematicNode;
import org.bukkit.Material;
import org.bukkit.block.data.BlockData;
import org.bukkit.block.data.type.*;
import org.bukkit.util.Vector;
import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;
public class LixfelPathplanner {
private static BlockType getBlockType(Clipboard clipboard, BlockVector3 vector) {
return clipboard.getBlock(vector).getBlockType();
private static double blockHeight(Clipboard clipboard, BlockVector3 vector) {
BaseBlock block = clipboard.getFullBlock(vector);
if(block.getBlockType().getMaterial().isFullCube())
return 1.0;
BlockData data = BukkitAdapter.adapt(block);
Material material = data.getMaterial();
if(material.isSolid()) {
if(material.isInteractable()) {
if(data instanceof Stairs)
return 1.0;
else if(data instanceof Fence)
return 1.5;
else if(data instanceof Bed)
return 0.5625;
} else {
if(data instanceof Slab)
return ((Slab)data).getType() == Slab.Type.BOTTOM ? 0.5 : 1.0;
else if(data instanceof Wall)
return 1.5;
else if(data instanceof GlassPane || material == Material.IRON_BARS)
return 1.0;
}
} else {
if(material == Material.LADDER || material == Material.SCAFFOLDING)
return -1.0;
else if(material.name().endsWith("_CARPET"))
return 0.0625;
}
return 0.0;
}
private static boolean nonsolid(Clipboard clipboard, BlockVector3 vector) {
return !getBlockType(clipboard, vector).getMaterial().isSolid();
}
private static Vector toBukkit(BlockVector3 vector) {
return new Vector(vector.getX() + 0.5, vector.getY(), vector.getZ() + 0.5);
private static Vector toBukkit(BlockVector3 vector, double height) {
return new Vector(vector.getX() + 0.5, vector.getY() + height, vector.getZ() + 0.5);
}
private final List<Vector> walkable = new ArrayList<>();
@ -61,25 +91,33 @@ public class LixfelPathplanner {
}
private void fillWalkable(Clipboard clipboard) {
BlockVector3 min = clipboard.getRegion().getMinimumPoint().subtract(Config.PreperationArea, 0, Config.PreperationArea); //TODO assumes nonextended Schematic with maximal size
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));
BlockVector3 diff = clipboard.getRegion().getMinimumPoint().subtract(clipboardToSchem.getBlockX(), clipboardToSchem.getBlockY(), clipboardToSchem.getBlockZ());
Region region = clipboard.getRegion();
clipboard.getRegion().forEach(vector -> {
BlockVector3 below = vector.subtract(0, 1, 0);
if(!region.contains(below))
BlockVector3 above = vector.add(0, 1, 0);
double aboveHeight = region.contains(above) ? blockHeight(clipboard, above) : 0.0;
if(aboveHeight > 0.0)
return;
BlockType belowMaterial = getBlockType(clipboard, below);
BlockVector3 above = vector.add(0, 1, 0);
if(nonsolid(clipboard, vector)) {
if(
(belowMaterial.getMaterial().isSolid() || belowMaterial.getId().equals("minecraft:ladder")) &&
(!region.contains(above) || nonsolid(clipboard, above))
)
walkable.add(toBukkit(vector.subtract(min)));
} else {
if(!region.contains(above))
walkable.add(toBukkit(above.subtract(min)));
}
double belowHeight = region.contains(below) ? blockHeight(clipboard, below) : 0.0;
double height = blockHeight(clipboard, vector);
if(height == 0.0 && Math.abs(belowHeight) < 1.0)
return;
if(height >= 1.0 && region.contains(above))
return;
if(height < 0.0)
height = 0.0;
walkable.add(toBukkit(vector.subtract(diff), height));
});
for(Vector vector : walkable) {
@ -87,24 +125,42 @@ 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 List<Vector> planToAnywhere(Vector start, Vector destination) {
Vector intermediate = walkable.stream().filter(vector -> neighbouring(vector, destination)).findAny().orElse(null);
if(intermediate == null)
return Collections.emptyList();
List<Vector> plan = plan(start, intermediate);
List<Vector> plan = new ArrayList<>(plan(start, 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()));
}
public List<Vector> plan(Vector start, Vector destination) {
if(neighbouring(start, destination))
return Collections.singletonList(destination);
return plan(start, 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<>();
Set<Vector> checking = Collections.singleton(destination);
Set<Vector> checking = new HashSet<>(destinations);
while(!checking.isEmpty()) {
Set<Vector> toCheck = new HashSet<>();
@ -122,7 +178,7 @@ public class LixfelPathplanner {
List<Vector> path = new ArrayList<>();
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)));
}

Datei anzeigen

@ -0,0 +1,58 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2023 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.chaos;
import org.bukkit.util.Vector;
public class Cannon {
public final Vector[] tnt;
public final Vector button;
public final Vector load;
public final Vector escape;
public final String name;
public Cannon(String name, Vector[] tnt, Vector button, Vector load, Vector escape) {
this.tnt = tnt;
this.button = button;
this.load = load;
this.escape = escape;
this.name = name;
}
public Vector[] getTnt() {
return tnt;
}
public Vector getButton() {
return button;
}
public Vector getLoad() {
return load;
}
public Vector getEscape() {
return escape;
}
public String getName() {
return name;
}
}

Datei anzeigen

@ -0,0 +1,267 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2023 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.chaos;
import de.steamwar.entity.REntityServer;
import de.steamwar.fightsystem.FightSystem;
import de.steamwar.fightsystem.ai.AI;
import de.steamwar.fightsystem.ai.chaos.gears.Gear;
import de.steamwar.fightsystem.ai.chaos.gears.TheUnderground;
import de.steamwar.fightsystem.ai.navmesh.NavMesh;
import de.steamwar.fightsystem.fight.FightTeam;
import de.steamwar.fightsystem.states.FightState;
import de.steamwar.sql.SchematicNode;
import de.steamwar.sql.SteamwarUser;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.event.player.PlayerTeleportEvent;
import org.bukkit.util.Vector;
import java.util.*;
public class ChaosAI extends AI {
private State state = State.PRE_PREPARE;
private static final Gear gear = TheUnderground.THE_UNDERGROUND;
private Cannon currentCannon;
private boolean igniteMg = false;
private static final Random random = new Random();
public static Map<FightTeam, Boolean> onePrepares = new HashMap<>();
private boolean prepares = false;
private static final Map<FightTeam, Set<Cannon>> cannonsShot = new HashMap<>();
private final NavMesh navMesh;
private final REntityServer entityServer = new REntityServer();
private Vector source = null;
private Vector destination = null;
private int index = 0;
private State nextState = null;
public ChaosAI(FightTeam team) {
this(team, SteamwarUser.get(14533));
}
public ChaosAI(FightTeam team, SteamwarUser user) {
super(team, user);
this.navMesh = new NavMesh(team, entityServer);
if (Boolean.FALSE.equals(onePrepares.getOrDefault(team, false))) {
prepares = true;
onePrepares.put(team, true);
}
}
@Override
public SchematicNode chooseSchematic() {
return SchematicNode.getSchematicNode(gear.getSchematicId());
}
@Override
protected void plan() {
switch (state) {
case PRE_PREPARE:
Bukkit.getScheduler().runTaskLater(FightSystem.getPlugin(), () -> {
state = State.PREPARE;
}, 20 * 15);
state = State.WAIT;
break;
case PREPARE:
prepare();
break;
case PREPARE_READY:
if (prepares) {
for (Vector prepareButton : gear.getPrepareButtons()) {
interact(prepareButton);
}
}
setReady();
state = State.WAIT_TILL_START;
break;
case WAIT_TILL_START:
if (FightState.ingame()) {
state = State.IGNITE_MG;
startFight();
}
break;
case IGNITE_MG:
if(igniteMg) {
if (prepares) {
interact(gear.getMgButton());
chat("Die MG ist angezündet!");
}
state = State.WAIT;
currentCannon = randomCannon();
Bukkit.getScheduler().runTaskLater(FightSystem.getPlugin(), () -> state = State.FIGHT, 20 * 9);
}
break;
case FIGHT:
fireCannon(currentCannon);
break;
case LOAD_CANNON:
loadCannon(currentCannon);
break;
case ESCAPE:
cannonsShot.computeIfAbsent(team, fightTeam -> new HashSet<>()).remove(currentCannon);
currentCannon = randomCannon();
state = State.WAIT;
Bukkit.getScheduler().runTaskLater(FightSystem.getPlugin(), () -> state = State.FIGHT, 20 * 4);
break;
case WAIT:
break;
case WALK:
if (!getEntity().isOnGround() && getEntity().getLocation().getBlock().getType() != Material.LADDER) return;
List<Vector> oldRoute = navMesh.path(source, destination);
navMesh.update(getEntity().getLocation().toVector());
List<Vector> path = navMesh.path(source, destination);
if (path.isEmpty()) {
source = null;
destination = null;
state = nextState;
chat("no route");
return;
}
if (!oldRoute.equals(path)) {
source = getEntity().getLocation().toVector();
index = 0;
chat("new route");
return;
}
if (index == 0) {
chat(source + " -> " + destination + " = " + path.size());
}
Vector loc = path.get(index++);
move(toAIPosition(loc));
if (index == path.size()) {
source = null;
destination = null;
state = nextState;
}
break;
}
}
private void moveTo(Vector vec, State nextState) {
source = getEntity().getLocation().toVector();
Vector currentBest = null;
for (Vector vector : navMesh.getWalkableBlocks(source)) {
if (currentBest == null || vector.distanceSquared(vec) < currentBest.distanceSquared(vec)) {
currentBest = vector;
}
}
destination = currentBest;
index = 0;
state = State.WALK;
this.nextState = nextState;
}
@Override
public void stop() {
chat("gege wp eZ win 4nus");
if (currentCannon != null) {
cannonsShot.computeIfAbsent(team, fightTeam -> new HashSet<>()).remove(currentCannon);
}
super.stop();
}
@Override
public boolean acceptJoinRequest(Player player, FightTeam team) {
if (team == this.team) {
entityServer.addPlayer(player);
}
return team == this.team;
}
public void fireCannon(Cannon cannon) {
chat("Ich feuere " + cannon.name + " an!");
moveTo(cannon.load.clone().add(new Vector(0.5, 0, 0.5)), State.LOAD_CANNON);
}
private void loadCannon(Cannon cannon) {
if (cannon.button == null) {
for (int i = 0; i < 20; i++) {
for (Vector vector : cannon.tnt) {
setTNT(vector);
}
for (int j = 0; j < 30; j++) {
getBlock(gear.getMgButton());
}
}
} else {
for (Vector vector : cannon.tnt) {
setTNT(vector);
}
interact(cannon.button);
}
if (currentCannon.escape != null) {
moveTo(cannon.getEscape().clone().add(new Vector(0.5, 0, 0.5)), State.ESCAPE);
}
}
private Cannon randomCannon() {
Cannon nextCannon = gear.getCannons()[random.nextInt(gear.getCannons().length)];
while (cannonsShot.computeIfAbsent(team, fightTeam -> new HashSet<>()).contains(nextCannon)) {
nextCannon = gear.getCannons()[random.nextInt(gear.getCannons().length)];
}
cannonsShot.computeIfAbsent(team, fightTeam -> new HashSet<>()).add(nextCannon);
return nextCannon;
}
public void startFight() {
chat("gl&hf");
if (prepares) {
chat("Ich zünde die MG an!");
}
Bukkit.getScheduler().runTaskLater(FightSystem.getPlugin(), () -> {
igniteMg = true;
}, 20L * gear.getMgTime());
}
public void prepare() {
chat("Prepare your fkin 4nus");
if (prepares) {
moveTo(gear.getBridge().clone().add(new Vector(0.5, 0, 0.5)), State.PREPARE_READY);
}
}
private enum State {
PRE_PREPARE,
PREPARE,
PREPARE_READY,
WAIT_TILL_START,
IGNITE_MG,
FIGHT,
LOAD_CANNON,
ESCAPE,
WAIT,
WALK,
}
}

Datei anzeigen

@ -0,0 +1,66 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2023 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.chaos.gears;
import de.steamwar.fightsystem.ai.chaos.Cannon;
import org.bukkit.util.Vector;
public class Gear {
private final Cannon[] cannons;
private final Vector bridge;
private final Vector[] prepareButtons;
private final Vector mgButton;
private final int mgTime;
private final int schematicId;
protected Gear(Cannon[] cannons, Vector bridge, Vector[] prepareButtons, Vector mgButton, int mgTime, int schematicId) {
this.cannons = cannons;
this.bridge = bridge;
this.prepareButtons = prepareButtons;
this.mgButton = mgButton;
this.mgTime = mgTime;
this.schematicId = schematicId;
}
public Cannon[] getCannons() {
return cannons;
}
public Vector getBridge() {
return bridge;
}
public Vector[] getPrepareButtons() {
return prepareButtons;
}
public Vector getMgButton() {
return mgButton;
}
public int getMgTime() {
return mgTime;
}
public int getSchematicId() {
return schematicId;
}
}

Datei anzeigen

@ -0,0 +1,184 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2023 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.chaos.gears;
import de.steamwar.fightsystem.ai.chaos.Cannon;
import org.bukkit.util.Vector;
public class TheUnderground {
public static final Vector[] DS_LEFT_TNT = new Vector[] {
new Vector(40, 24, 12),
new Vector(39, 24, 12),
new Vector(38, 23, 12),
new Vector(38, 24, 12),
new Vector(40, 23, 15),
new Vector(40, 23, 14),
new Vector(40, 24, 15),
new Vector(40, 24, 14),
new Vector(38, 23, 15),
new Vector(38, 23, 14),
new Vector(38, 24, 15),
new Vector(38, 24, 14),
new Vector(40, 23, 12),
};
public static final Vector DS_LEFT_BUTTON = new Vector(39, 25, 11);
public static final Vector DS_LEFT_LOAD = new Vector(39, 25, 13);
public static final Vector DS_LEFT_ESCAPE = new Vector(31, 26, 13);
public static final Cannon DS_LEFT = new Cannon("Downstäb Links", DS_LEFT_TNT, DS_LEFT_BUTTON, DS_LEFT_LOAD, DS_LEFT_ESCAPE);
public static final Vector[] DS_RIGHT_TNT = new Vector[] {
new Vector(12, 24, 12),
new Vector(11, 24, 12),
new Vector(10, 23, 12),
new Vector(10, 24, 12),
new Vector(10, 23, 15),
new Vector(10, 23, 14),
new Vector(10, 24, 15),
new Vector(10, 24, 14),
new Vector(12, 23, 14),
new Vector(12, 24, 14),
new Vector(12, 23, 15),
new Vector(12, 24, 15),
new Vector(12, 23, 12),
};
public static final Vector DS_RIGHT_BUTTON = new Vector(11, 25, 11);
public static final Vector DS_RIGHT_LOAD = new Vector(11, 25, 13);
public static final Vector DS_RIGHT_ESCAPE = new Vector(19, 26, 13);
public static final Cannon DS_RIGHT = new Cannon("Downstäb Rechts", DS_RIGHT_TNT, DS_RIGHT_BUTTON, DS_RIGHT_LOAD, DS_RIGHT_ESCAPE);
public static final Vector[] STATIC_LEFT_TNT = new Vector[] {
new Vector(37, 17, 15),
new Vector(37, 17, 14),
new Vector(37, 18, 16),
new Vector(37, 18, 15),
new Vector(37, 18, 14),
new Vector(36, 17, 16),
new Vector(36, 17, 15),
new Vector(36, 17, 14),
new Vector(36, 18, 16),
new Vector(36, 18, 15),
new Vector(36, 18, 14),
new Vector(37, 17, 16),
};
public static final Vector STATIC_LEFT_BUTTON = new Vector(38, 18, 11);
public static final Vector STATIC_LEFT_LOAD = new Vector(37, 17, 12);
public static final Vector STATIC_LEFT_ESCAPE = new Vector(30, 13, 9);
public static final Cannon STATIC_LEFT = new Cannon("Lupf Links", STATIC_LEFT_TNT, STATIC_LEFT_BUTTON, STATIC_LEFT_LOAD, STATIC_LEFT_ESCAPE);
public static final Vector[] STATIC_RIGHT_TNT = new Vector[] {
new Vector(14, 17, 15),
new Vector(14, 18, 16),
new Vector(14, 18, 15),
new Vector(14, 17, 14),
new Vector(14, 18, 14),
new Vector(13, 17, 16),
new Vector(13, 17, 15),
new Vector(13, 17, 14),
new Vector(13, 18, 16),
new Vector(13, 18, 15),
new Vector(13, 18, 14),
new Vector(14, 17, 16),
};
public static final Vector STATIC_RIGHT_BUTTON = new Vector(12, 18, 11);
public static final Vector STATIC_RIGHT_LOAD = new Vector(13, 17, 12);
public static final Vector STATIC_RIGHT_ESCAPE = new Vector(20, 13, 9);
public static final Cannon STATIC_RIGHT = new Cannon("Lupf Rechts", STATIC_RIGHT_TNT, STATIC_RIGHT_BUTTON, STATIC_RIGHT_LOAD, STATIC_RIGHT_ESCAPE);
public static final Vector[] AK_TNT = new Vector[] {
new Vector(10, 7, 17),
new Vector(10, 11, 17),
new Vector(10, 10, 17),
new Vector(10, 8, 17),
new Vector(10, 9, 17),
new Vector(10, 7, 15),
new Vector(11, 7, 15),
new Vector(12, 7, 15),
new Vector(10, 10, 15),
new Vector(11, 10, 15),
new Vector(12, 10, 15),
new Vector(12, 8, 15),
new Vector(12, 9, 15),
new Vector(11, 8, 15),
new Vector(11, 9, 15),
new Vector(10, 8, 15),
new Vector(10, 9, 15),
new Vector(10, 7, 19),
new Vector(11, 7, 19),
new Vector(12, 7, 19),
new Vector(12, 8, 19),
new Vector(11, 8, 19),
new Vector(10, 8, 19),
new Vector(10, 10, 19),
new Vector(11, 10, 19),
new Vector(12, 10, 19),
new Vector(12, 9, 19),
new Vector(11, 9, 19),
new Vector(10, 9, 19),
new Vector(10, 6, 17),
};
public static final Vector AK_BUTTON = new Vector(9, 9, 16);
public static final Vector AK_LOAD = new Vector(11, 8, 17);
public static final Cannon AK = new Cannon("Arschkratzer", AK_TNT, AK_BUTTON, AK_LOAD, null);
public static final Vector[] HA_RIGHT_TNT = new Vector[] {
new Vector(23, 5, 9),
new Vector(23, 6, 9),
new Vector(23, 7, 9),
new Vector(23, 8, 9),
};
public static final Vector[] HA_LEFT_TNT = new Vector[] {
new Vector(27, 5, 9),
new Vector(27, 6, 9),
new Vector(27, 7, 9),
new Vector(27, 8, 9),
};
public static final Vector HA_RIGHT_LOAD = new Vector(23, 8, 8);
public static final Vector HA_LEFT_LOAD = new Vector(27, 8, 8);
public static final Cannon HA_LEFT = new Cannon("Halbautomatik Links", HA_LEFT_TNT, null, HA_LEFT_LOAD, null);
public static final Cannon HA_RIGHT = new Cannon("Halbautomatik Rechts", HA_RIGHT_TNT, null, HA_RIGHT_LOAD, null);
public static final Vector BRIDGE_POS = new Vector(25, 14, 24);
public static final Vector BRIDGE_SHIELDS = new Vector(25, 15, 25);
public static final Vector BRIDGE_MG = new Vector(21, 15, 24);
public static final Gear THE_UNDERGROUND = new Gear(
new Cannon[] {
DS_LEFT,
DS_RIGHT,
STATIC_LEFT,
STATIC_RIGHT,
AK,
HA_LEFT,
HA_RIGHT,
//Cannon.AK,
},
BRIDGE_POS,
new Vector[] {
BRIDGE_SHIELDS
},
BRIDGE_MG,
21,
124667
);
}

Datei anzeigen

@ -0,0 +1,25 @@
event(events.PlaceBlock, function(e)
if storage.player.get("recording") then
pos = {math.floor(e.x), math.floor(e.y) - 100, math.floor(e.z)}
storage.player.get("recordingPos")[storage.player.get("recordingCount")] = pos
storage.player.set("recordingCount", storage.player.get("recordingCount") + 1)
end
end)
command("recorder", function(args)
if storage.player.get("recording") then
storage.player.set("recording", false)
storage.player.set("recordingCount", 0)
print("private static final Vector[] positions = new Vector[] {")
for k, v in pairs(storage.player.get("recordingPos")) do
print("new Vector(" .. v[1] .. ", " .. v[2] .. ", " .. v[3] .. "),")
end
print("};")
print("Stopped recording")
else
storage.player.set("recording", true)
storage.player.set("recordingCount", 0)
storage.player.set("recordingPos", {})
print("Started recording")
end
end)

Datei anzeigen

@ -0,0 +1,343 @@
-- This file is a part of the SteamWar software.
--
-- Copyright (C) 2021 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/>.
---
--- This file contains the definitions for the SteamWar.de script API.
--- It is used by the IDE to provide code completion and type checking.
--- Created by Chaoscaot
---
inventory = {}
---@param title string
---@param size number
---@return Inventory
function inventory.create(title, size) return nil end
---@alias InventoryClick 'LEFT' | 'SHIFT_LEFT' | 'RIGHT' | 'SHIFT_RIGHT' | 'MIDDLE' | 'NUMBER_KEY'
---@class Inventory
local Inventory = {}
---@overload fun(slot: number, material: string, name: string, handler: fun(click: InventoryClick)): void
---@overload fun(slot: number, material: string, name: string, handler: fun(click: InventoryClick), lore: string[]): void
---@overload fun(slot: number, material: string, name: string, handler: fun(click: InventoryClick), lore: string[], enchanted: boolean): void
---@param slot number
---@param material string
---@param name string
---@param handler fun(click: InventoryClick): void
---@param lore string[]
---@param enchanted boolean
---@param amount number
---@return void
function Inventory.item(slot, material, name, handler, lore, enchanted, amount) end
---@param handler fun(): void
---@return void
function Inventory.setCloseHandler(handler) end
---@return void
function Inventory.open() end
player = {}
---@return string
---Get the name of the player.
function player.name() return "" end
---@return void
function player.chat(...) end
---@return void
---Send a message to the actionbar of the player.
function player.actionbar(...) end
---@overload fun(): number
---@param newX number
function player.x(newX) end
---@overload fun(): number
---@param newY number
function player.y(newY) end
---@overload fun(): number
---@param newZ number
function player.z(newZ) end
---@overload fun(): number
---@param newYaw number
function player.yaw(newYaw) end
---@overload fun(): number
---@param newPitch number
function player.pitch(newPitch) end
---@return boolean
function player.sneaking() return nil end
---@return boolean
function player.sprinting() return nil end
---@overload fun(): number
---@param newSlot number
function player.slot(newSlot) end
---@return string
function player.item() return nil end
---@return string
function player.offHandItem() return nil end
---@return void
function player.closeInventory() end
---@field nextBool fun(): boolean
random = {}
---@overload fun(): number
---@overload fun(bound: number): number
---@param origin number
---@param bound number
---@return number
function random.nextInt(origin, bound) return nil end
---@overload fun(): number
---@overload fun(bound: number): number
---@param origin number
---@param bound number
---@return number
function random.nextDouble(origin, bound) return nil end
---@return boolean
function random.nextBool() return nil end
---@alias RegionType 'wg' | 'mwg' | 'as' | 'ws' | 'ws_inner' | 'ws_rumpf' | 'ws_rahmen' | 'spawn'
---@class iregion
---@field tnt tnt
---@field trace trace
local iregion = {}
---@class region: iregion
region = {}
---@return string
function iregion.name() return nil end
---@return RegionType
function iregion.type() return nil end
---@return boolean
function iregion.fire() return nil end
---@return boolean
function iregion.freeze() return nil end
---@return boolean
function iregion.protect() return nil end
---@return string
function iregion.loader() return nil end
---@alias TNTMode 'ALLOW' | 'DENY' | 'ONLY_TB'
---@class tnt
local tnt = {}
---@return TNTMode
function tnt.mode() return nil end
---@return boolean
function tnt.enabled() return nil end
---@return boolean
function tnt.onlyTb() return nil end
---@class trace
local trace = {}
---@return boolean
function trace.active() return nil end
---@return boolean
function trace.auto() return nil end
---@return string
function trace.status() return nil end
---@return number
function trace.time() return nil end
---@param name string
---@return iregion
function region.get(name) return nil end
---@return iregion[]
function region.list() return nil end
---@class Position
---@field x number
---@field y number
---@field z number
---@class server
---@field tps tps
server = {}
---@return string
function server.time() return nil end
---@return number
function server.ticks() return nil end
---@param position Position
---@return string
function getBlockAt(position) return nil end
---@param position Position
---@param material string
---@return void
function setBlockAt(position, material) return nil end
---@class tps
local tps = {}
---@return number
function tps.oneSecond() return nil end
---@return number
function tps.tenSecond() return nil end
---@return number
function tps.oneMinute() return nil end
---@return number
function tps.fiveMinute() return nil end
---@return number
function tps.tenMinute() return nil end
---@return number
function tps.current() return nil end
---@return number
function tps.limit() return nil end
---@class storage
---@field global storageLib
---@field player storageLib
---@field region storageLib
storage = {}
---@class storageLib
local storageLib = {}
---@param key string
---@return any
function storageLib.get(key) return nil end
---@param key string
---@param value any
---@return void
function storageLib.set(key, value) end
---@param key string
---@return boolean
function storageLib.has(key) return nil end
---@param key string
---@return void
function storageLib.remove(key) end
---@param key string
---@return Accessor
function storageLib.accessor(key) return nil end
---@class Accessor
---@overload fun(): any
---@overload fun(value: any)
---@class Selection
---@field max Position
---@field min Position
---@class _worldedit
_worldedit = {}
---@overload fun(pos: Position[]): void
---@return Selection
function _worldedit.selection() return nil end
---@param msg string
---@param callback fun(value: string): void
---@return void
function input(msg, callback) end
---@param ticks number
---@param callback fun(): void
---@return void
function delayed(ticks, callback) end
---@param x number
---@param y number
---@param z number
---@return Position
function pos(x, y, z) return nil end
---@return void
function exec(...) end
---@param obj any
---@return number
function length(obj) return 0 end
---@param separator string
---@param table any[]
---@return string
function join(separator, table) return "" end
---@class EventType
---@class events
---@field DoubleSwap EventType
---@field PlaceBlock EventType
---@field BreakBlock EventType
---@field RightClick EventType
---@field LeftClick EventType
---@field TNTSpawn EventType
---@field TNTExplode EventType
---@field TNTExplodeInBuild EventType
---@field SelfJoin EventType
---@field SelfLeave EventType
---@field DropItem EventType
---@field EntityDeath EventType
events = {}
---@param id EventType
---@param handler fun(params: any): void
---@return void
function event(id, handler) end
---@param command string
---@param handler fun(params: string[]): void
---@return void
function command(command, handler) end
---@param trigger string
---@param handler fun(pressed: boolean): void
---@return void
function hotkey(trigger, handler) end

Datei anzeigen

@ -0,0 +1,386 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2023 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.navmesh;
import de.steamwar.entity.RArmorStand;
import de.steamwar.entity.REntity;
import de.steamwar.entity.REntityServer;
import de.steamwar.fightsystem.ArenaMode;
import de.steamwar.fightsystem.FightSystem;
import de.steamwar.fightsystem.fight.FightTeam;
import de.steamwar.fightsystem.states.FightState;
import de.steamwar.fightsystem.states.OneShotStateDependent;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.event.Listener;
import org.bukkit.util.BoundingBox;
import org.bukkit.util.Vector;
import org.bukkit.util.VoxelShape;
import java.util.*;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.BiConsumer;
import java.util.stream.Collectors;
public class NavMesh implements Listener {
private static final World WORLD = Bukkit.getWorlds().get(0);
private static final double PLAYER_JUMP_HEIGHT = 1.25;
private static final double PLAYER_HEIGHT = 1.8125;
private static final BoundingBox PLAYER_SHADOW = new BoundingBox(0.2, 0, 0.2, 0.8, 1, 0.8);
private static final Set<Pos> RELATIVE_BLOCKS_TO_CHECK = new HashSet<>();
static {
for (int y = -2; y <= 2; y++) {
RELATIVE_BLOCKS_TO_CHECK.add(new Pos(BlockFace.NORTH.getDirection().setY(y)));
RELATIVE_BLOCKS_TO_CHECK.add(new Pos(BlockFace.SOUTH.getDirection().setY(y)));
RELATIVE_BLOCKS_TO_CHECK.add(new Pos(BlockFace.EAST.getDirection().setY(y)));
RELATIVE_BLOCKS_TO_CHECK.add(new Pos(BlockFace.WEST.getDirection().setY(y)));
}
RELATIVE_BLOCKS_TO_CHECK.add(new Pos(BlockFace.UP.getDirection()));
RELATIVE_BLOCKS_TO_CHECK.add(new Pos(BlockFace.DOWN.getDirection()));
}
private FightTeam fightTeam;
private List<REntity> rEntities = new ArrayList<>();
private REntityServer entityServer;
public NavMesh(FightTeam fightTeam, REntityServer entityServer) {
this.fightTeam = fightTeam;
this.entityServer = entityServer;
new OneShotStateDependent(ArenaMode.All, FightState.PostSchemSetup, () -> {
Bukkit.getScheduler().runTaskLater(FightSystem.getPlugin(), () -> {
long time = System.currentTimeMillis();
fightTeam.getExtendRegion().forEach((x, y, z) -> {
if (y < fightTeam.getSchemRegion().getMinY()) return;
checkWalkable(x, y, z);
});
floorBlock.forEach(this::checkNeighbouring);
System.out.println(System.currentTimeMillis() - time + " ms");
iterateWalkableBlocks((vector, ceilingOffset) -> {
RArmorStand armorStand = new RArmorStand(entityServer, vector.toLocation(WORLD), RArmorStand.Size.MARKER);
armorStand.setNoGravity(true);
armorStand.setInvisible(true);
armorStand.setDisplayName("+" + (ceilingOffset == null ? "" : ceilingOffset));
});
}, 20);
});
new OneShotStateDependent(ArenaMode.All, FightState.Spectate, () -> {
floorBlock.clear();
});
}
private static class Pos {
private int x;
private int y;
private int z;
public Pos(int x, int y, int z) {
this.x = x;
this.y = y;
this.z = z;
}
public Pos(Vector vector) {
this.x = vector.getBlockX();
this.y = vector.getBlockY();
this.z = vector.getBlockZ();
}
@Override
public String toString() {
return x + "," + y + "," + z;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Pos)) return false;
Pos pos = (Pos) o;
return x == pos.x && y == pos.y && z == pos.z;
}
@Override
public int hashCode() {
return Objects.hash(x, y, z);
}
public Vector toVector() {
return new Vector(x, y, z);
}
public Pos add(Pos pos) {
return new Pos(x + pos.x, y + pos.y, z + pos.z);
}
public Pos subtract(Pos pos) {
return new Pos(x - pos.x, y - pos.y, z - pos.z);
}
}
private Map<Pos, Double> floorBlock = new HashMap<>();
private Map<Pos, Double> ceilingOffset = new HashMap<>();
private Map<Pos, Set<Pos>> neighbourConnections = new HashMap<>();
private Map<Pos, Set<Pos>> reverseNeighbourConnections = new HashMap<>();
private void checkWalkable(int x, int y, int z) {
Pos pos = new Pos(x, y, z);
floorBlock.remove(pos);
ceilingOffset.remove(pos);
Block block = WORLD.getBlockAt(x, y, z);
VoxelShape floor = block.getCollisionShape();
if (block.getType() != Material.LADDER && !overlaps(floor, 0, 0, 0)) return;
Double floorHeight = null;
for (BoundingBox box : floor.getBoundingBoxes()) {
double by = box.getMaxY();
if (!overlaps(floor, 0, by, 0)) {
if (floorHeight == null) {
floorHeight = by;
} else {
floorHeight = Math.min(floorHeight, by);
}
}
}
if (floorHeight == null) return;
Double ceilingOffset = null;
for (int cy = y + 1; cy < fightTeam.getExtendRegion().getMaxY(); cy++) {
VoxelShape current = WORLD.getBlockAt(x, cy, z).getCollisionShape();
if (!overlaps(current, 0, 0, 0)) continue;
Double ceilingHeight = null;
for (BoundingBox box : current.getBoundingBoxes()) {
double by = box.getMinY();
if (!overlaps(current, 0, -(1 - by), 0)) {
if (ceilingHeight == null) {
ceilingHeight = by;
} else {
ceilingHeight = Math.max(ceilingHeight, by);
}
}
}
if (ceilingHeight != null) {
ceilingOffset = cy - y + ceilingHeight - floorHeight;
}
break;
}
if (ceilingOffset != null && ceilingOffset < PLAYER_HEIGHT) return;
floorBlock.put(pos, y + floorHeight);
this.ceilingOffset.put(pos, ceilingOffset);
}
private void checkNeighbouring(Pos pos, double posFloorHeight) {
Set<Pos> connections = neighbourConnections.remove(pos);
if (connections != null) {
connections.forEach(p -> {
reverseNeighbourConnections.getOrDefault(pos.add(p), Collections.emptySet()).remove(pos);
});
}
for (Pos relativeCheck : RELATIVE_BLOCKS_TO_CHECK) {
Pos other = new Pos(pos.x + relativeCheck.x, pos.y + relativeCheck.y, pos.z + relativeCheck.z);
Double otherFloorHeight = floorBlock.get(other);
if (otherFloorHeight == null) continue;
if (otherFloorHeight > posFloorHeight && otherFloorHeight - posFloorHeight > PLAYER_JUMP_HEIGHT) continue;
// double floorDiff = Math.abs(posFloorHeight - otherFloorHeight);
// if (floorDiff > PLAYER_JUMP_HEIGHT) continue;
Double posCeilingOffset = ceilingOffset.get(pos);
Double otherCeilingOffset = ceilingOffset.get(other);
if (posCeilingOffset == null && otherCeilingOffset == null) {
neighbourConnections.computeIfAbsent(pos, __ -> new LinkedHashSet<>()).add(relativeCheck);
reverseNeighbourConnections.computeIfAbsent(pos.add(relativeCheck), __ -> new LinkedHashSet<>()).add(pos);
continue;
}
if (posCeilingOffset != null && otherCeilingOffset == null) {
if (posFloorHeight + posCeilingOffset - otherFloorHeight >= PLAYER_HEIGHT) {
neighbourConnections.computeIfAbsent(pos, __ -> new LinkedHashSet<>()).add(relativeCheck);
reverseNeighbourConnections.computeIfAbsent(pos.add(relativeCheck), __ -> new LinkedHashSet<>()).add(pos);
}
continue;
}
if (otherCeilingOffset != null && posCeilingOffset == null) {
if (otherFloorHeight + otherCeilingOffset - posFloorHeight >= PLAYER_HEIGHT) {
neighbourConnections.computeIfAbsent(pos, __ -> new LinkedHashSet<>()).add(relativeCheck);
reverseNeighbourConnections.computeIfAbsent(pos.add(relativeCheck), __ -> new LinkedHashSet<>()).add(pos);
}
continue;
}
if (posFloorHeight + posCeilingOffset - otherFloorHeight >= PLAYER_HEIGHT && otherFloorHeight + otherCeilingOffset - posFloorHeight >= PLAYER_HEIGHT) {
neighbourConnections.computeIfAbsent(pos, __ -> new LinkedHashSet<>()).add(relativeCheck);
reverseNeighbourConnections.computeIfAbsent(pos.add(relativeCheck), __ -> new LinkedHashSet<>()).add(pos);
}
}
}
private boolean overlaps(VoxelShape voxelShape, double x, double y, double z) {
PLAYER_SHADOW.shift(x, y, z);
boolean overlaps = voxelShape.overlaps(PLAYER_SHADOW);
PLAYER_SHADOW.shift(-x, -y, -z);
return overlaps;
}
private void iterateWalkableBlocks(BiConsumer<Vector, Double> consumer) {
floorBlock.forEach((pos, aDouble) -> {
Vector vector = new Vector(pos.x + 0.5, aDouble, pos.z + 0.5);
consumer.accept(vector, ceilingOffset.get(pos));
});
}
private Pos toPos(Vector vector) {
Pos pos = new Pos(vector);
if (floorBlock.containsKey(pos)) return pos;
pos = new Pos(pos.x, pos.y - 1, pos.z);
if (floorBlock.containsKey(pos)) return pos;
return null;
}
public void update(Vector posVector) {
Pos pos = toPos(posVector);
if (pos == null) return;
for (int x = -2; x <= 2; x++) {
for (int z = -2; z <= 2; z++) {
for (int y = fightTeam.getSchemRegion().getMinY(); y <= pos.y + 2; y++) {
checkWalkable(pos.x + x, y, pos.z + z);
}
}
}
floorBlock.forEach(this::checkNeighbouring);
}
public List<Vector> getAllWalkableBlocks() {
return floorBlock.keySet().stream().map(Pos::toVector).collect(Collectors.toList());
}
public List<Vector> getWalkableBlocks(Vector fromVector) {
Pos from = toPos(fromVector);
if (from == null) {
return Collections.emptyList();
}
Set<Pos> checked = new HashSet<>();
List<Pos> checking = new ArrayList<>();
checking.add(from);
while (!checking.isEmpty()) {
Pos pos = checking.remove(0);
checked.add(pos);
neighbourConnections.getOrDefault(pos, new HashSet<>()).forEach(p -> {
Pos n = pos.add(p);
if (checked.contains(n)) return;
if (checking.contains(n)) return;
checking.add(n);
});
}
return checked.stream().map(Pos::toVector).collect(Collectors.toList());
}
public List<Vector> path(Vector fromVector, Vector toVector) {
rEntities.forEach(REntity::die);
rEntities.clear();
Pos from = toPos(fromVector);
Pos to = toPos(toVector);
if (from == null || to == null) {
return Collections.emptyList();
}
if (from.equals(to)) {
return Collections.emptyList();
}
List<Pos> checking = new ArrayList<>(Arrays.asList(to));
Map<Pos, Pos> route = new HashMap<>();
while (!checking.isEmpty()) {
Set<Pos> toCheck = new HashSet<>();
for (Pos pos : checking) {
boolean foundFrom = false;
Set<Pos> successors = reverseNeighbourConnections.get(pos);
for (Pos p : successors) {
if (route.containsKey(p)) continue;
route.put(p, pos);
toCheck.add(p);
foundFrom = p.equals(from);
if (foundFrom) break;
}
if (foundFrom) {
List<Pos> path = new ArrayList<>();
path.add(from);
while (path.get(path.size() - 1) != to) {
path.add(route.get(path.get(path.size() - 1)));
}
for (int i = path.size() - 1; i > 0; i--) {
Pos current = path.get(i);
Pos last = path.get(i - 1);
if (last.y > current.y) {
path.set(i, new Pos(current.x, last.y, current.z));
}
}
List<Vector> vectors = path.stream().map(p -> {
Double floorHeight = floorBlock.get(p);
if (p.y > (floorHeight == null ? p.y : floorHeight)) floorHeight = null;
return new Vector(p.x + 0.5, floorHeight == null ? p.y : floorHeight, p.z + 0.5);
}).collect(Collectors.toList());
AtomicReference<Vector> last = new AtomicReference<>();
vectors.forEach(vector -> {
RArmorStand armorStand = new RArmorStand(entityServer, vector.toLocation(WORLD), RArmorStand.Size.MARKER);
armorStand.setInvisible(true);
armorStand.setNoGravity(true);
armorStand.setDisplayName("+");
rEntities.add(armorStand);
if (true) return;
Vector lastVector = last.getAndSet(vector);
if (lastVector == null) return;
lastVector = lastVector.clone().add(vector).divide(new Vector(2, 2, 2));
armorStand = new RArmorStand(entityServer, lastVector.toLocation(WORLD), RArmorStand.Size.MARKER);
armorStand.setInvisible(true);
armorStand.setNoGravity(true);
armorStand.setDisplayName("+");
rEntities.add(armorStand);
});
return vectors;
}
}
checking.clear();
checking.addAll(toCheck);
}
return Collections.emptyList();
}
}

Datei anzeigen

@ -76,6 +76,10 @@ public class Region {
return maxX - minX;
}
public int getSizeY() {
return maxY - minY;
}
public int getSizeZ() {
return maxZ - minZ;
}

0
gradlew vendored Ausführbare Datei → Normale Datei
Datei anzeigen