diff --git a/FightSystem_Core/src/de/steamwar/fightsystem/FightSystem.java b/FightSystem_Core/src/de/steamwar/fightsystem/FightSystem.java index ff07546..09500a9 100644 --- a/FightSystem_Core/src/de/steamwar/fightsystem/FightSystem.java +++ b/FightSystem_Core/src/de/steamwar/fightsystem/FightSystem.java @@ -21,6 +21,7 @@ package de.steamwar.fightsystem; import com.comphenix.tinyprotocol.TinyProtocol; import de.steamwar.core.Core; +import de.steamwar.fightsystem.ai.LixfelAI; import de.steamwar.fightsystem.commands.*; import de.steamwar.fightsystem.countdown.*; import de.steamwar.fightsystem.event.HellsBells; @@ -105,7 +106,7 @@ public class FightSystem extends JavaPlugin { techHider = new TechHiderWrapper(); new FightWorld(); new FightUI(); - new FightStatistics(); + //new FightStatistics(); new BungeeFightInfo(); new WinconditionAllDead(); @@ -163,6 +164,8 @@ public class FightSystem extends JavaPlugin { }else if(Config.mode == ArenaMode.PREPARE) { Fight.getUnrotated().setSchem(SchematicNode.getSchematicNode(Config.PrepareSchemID)); } + + new LixfelAI(Fight.getBlueTeam()); } @Override diff --git a/FightSystem_Core/src/de/steamwar/fightsystem/ai/AI.java b/FightSystem_Core/src/de/steamwar/fightsystem/ai/AI.java new file mode 100644 index 0000000..33aafdc --- /dev/null +++ b/FightSystem_Core/src/de/steamwar/fightsystem/ai/AI.java @@ -0,0 +1,127 @@ +/* + * 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 . + */ + +package de.steamwar.fightsystem.ai; + +import com.comphenix.tinyprotocol.Reflection; +import de.steamwar.fightsystem.Config; +import de.steamwar.fightsystem.FightSystem; +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.Material; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; +import org.bukkit.entity.Villager; +import org.bukkit.scheduler.BukkitTask; +import org.bukkit.util.Vector; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +public abstract class AI { + + private static final Map ais = new HashMap<>(); + + public static AI getAI(UUID uuid) { + return ais.get(uuid); + } + + private final FightTeam team; + private final LivingEntity entity; + private final BukkitTask task; + private int cooldown; + + private static final Reflection.MethodInvoker getHandle = Reflection.getMethod("{obc}.entity.CraftEntity", "getHandle"); + private static final Reflection.FieldAccessor entityUUID = Reflection.getField("{nms.world.entity}.Entity", UUID.class, 0); + protected AI(FightTeam team, SteamwarUser user) { + this.team = team; + + entity = Config.world.spawn(Config.SpecSpawn, Villager.class, entity -> entityUUID.set(getHandle.invoke(entity), user.getUUID())); + entity.setCustomName(user.getUserName()); + entity.setAI(false); + + task = Bukkit.getScheduler().runTaskTimer(FightSystem.getPlugin(), this::run, 1, 1); + ais.put(user.getUUID(), this); + team.addMember(entity); + } + + public abstract SchematicNode chooseSchematic(); + + public boolean acceptJoinRequest(Player player, FightTeam team) { + return true; + } + + protected abstract void plan(); + + public void cleanup() { + ais.remove(entity.getUniqueId()); + task.cancel(); + } + + public LivingEntity getEntity() { + return entity; + } + + protected void setReady() { + if(FightState.getFightState() != FightState.POST_SCHEM_SETUP) + return; + + if(team.getLeader().getEntity() != entity) + return; + + team.setReady(true); + } + + protected Material getBlock(Vector pos) { + //TODO position translation + cooldown++; + return pos.toLocation(Config.world).getBlock().getType(); + } + + protected void setTNT(Vector pos) { + //TODO position translation + //TODO Check position + //TODO Check AIR is there + cooldown++; + pos.toLocation(Config.world).getBlock().setType(Material.TNT); + } + + protected void move(Vector pos) { + //TODO position translation + //TODO Check position + //TODO falling check + //TODO pathfinding + cooldown += 5; + entity.teleport(pos.toLocation(Config.world)); + } + + private void run() { + if(cooldown > 0) + cooldown--; + + if(cooldown > 0) + return; + + plan(); + } +} diff --git a/FightSystem_Core/src/de/steamwar/fightsystem/ai/AIPlayer.java b/FightSystem_Core/src/de/steamwar/fightsystem/ai/LixfelAI.java similarity index 54% rename from FightSystem_Core/src/de/steamwar/fightsystem/ai/AIPlayer.java rename to FightSystem_Core/src/de/steamwar/fightsystem/ai/LixfelAI.java index 1730174..fcc834b 100644 --- a/FightSystem_Core/src/de/steamwar/fightsystem/ai/AIPlayer.java +++ b/FightSystem_Core/src/de/steamwar/fightsystem/ai/LixfelAI.java @@ -19,27 +19,28 @@ package de.steamwar.fightsystem.ai; -import com.comphenix.tinyprotocol.Reflection; import de.steamwar.fightsystem.Config; +import de.steamwar.fightsystem.fight.FightTeam; +import de.steamwar.sql.SchematicNode; import de.steamwar.sql.SteamwarUser; -import org.bukkit.entity.LivingEntity; -import org.bukkit.entity.Villager; -import java.util.UUID; +import java.util.List; +import java.util.Random; -public class AIPlayer { - private static final Reflection.MethodInvoker getHandle = Reflection.getMethod("{obc}.entity.CraftEntity", "getHandle"); - private static final Reflection.FieldAccessor entityUUID = Reflection.getField("{nms.world.entity}.Entity", UUID.class, 0); - - private final LivingEntity player; - - public AIPlayer(SteamwarUser user) { - player = Config.world.spawn(Config.SpecSpawn, Villager.class, entity -> entityUUID.set(getHandle.invoke(entity), user.getUUID())); - player.setCustomName(user.getUserName()); - player.setAI(false); +public class LixfelAI extends AI { + public LixfelAI(FightTeam team) { + super(team, SteamwarUser.get("public")); } - public LivingEntity getEntity() { - return player; + @Override + public SchematicNode chooseSchematic() { + List publics = SchematicNode.getAllSchematicsOfType(0, Config.SchematicType.toDB()); + return publics.get(new Random().nextInt(publics.size())); + } + + @Override + protected void plan() { + setReady(); + getEntity().setAI(true); } } diff --git a/FightSystem_Core/src/de/steamwar/fightsystem/fight/FightPlayer.java b/FightSystem_Core/src/de/steamwar/fightsystem/fight/FightPlayer.java index ec89b25..41735a7 100644 --- a/FightSystem_Core/src/de/steamwar/fightsystem/fight/FightPlayer.java +++ b/FightSystem_Core/src/de/steamwar/fightsystem/fight/FightPlayer.java @@ -20,6 +20,7 @@ package de.steamwar.fightsystem.fight; import de.steamwar.fightsystem.Config; +import de.steamwar.fightsystem.ai.AI; import de.steamwar.fightsystem.countdown.EnternCountdown; import de.steamwar.sql.PersonalKit; import de.steamwar.sql.SteamwarUser; @@ -62,6 +63,7 @@ public class FightPlayer { public void setOut() { isOut = true; stopEnternCountdown(); + ifAI(AI::cleanup); } public void startEnternCountdown() { @@ -83,6 +85,11 @@ public class FightPlayer { return entity; } + public void ifAI(Consumer function) { + if(!(entity instanceof Player)) + function.accept(AI.getAI(uuid)); + } + public void ifPlayer(Consumer function) { if(entity instanceof Player) function.accept((Player) entity); diff --git a/FightSystem_Core/src/de/steamwar/fightsystem/fight/FightTeam.java b/FightSystem_Core/src/de/steamwar/fightsystem/fight/FightTeam.java index 1184916..03726d3 100644 --- a/FightSystem_Core/src/de/steamwar/fightsystem/fight/FightTeam.java +++ b/FightSystem_Core/src/de/steamwar/fightsystem/fight/FightTeam.java @@ -372,6 +372,8 @@ public class FightTeam { if(FightState.getFightState() == FightState.PRE_LEADER_SETUP && !Fight.getOpposite(this).isLeaderless()){ FightState.setFightState(FightState.PRE_SCHEM_SETUP); } + + leader.ifAI(ai -> setSchem(ai.chooseSchematic())); } public Collection getPlayers() { diff --git a/FightSystem_Core/src/de/steamwar/fightsystem/fight/JoinRequest.java b/FightSystem_Core/src/de/steamwar/fightsystem/fight/JoinRequest.java index 9bdfe27..4f80744 100644 --- a/FightSystem_Core/src/de/steamwar/fightsystem/fight/JoinRequest.java +++ b/FightSystem_Core/src/de/steamwar/fightsystem/fight/JoinRequest.java @@ -63,6 +63,8 @@ public class JoinRequest { this.player = player; this.team = team; this.waitOnApproval = new HashSet<>(FightState.ingame() ? Fight.teams() : Collections.singleton(team)); + + activeRequests.put(player, this); for(FightTeam t : waitOnApproval) { FightPlayer leader = t.getLeader(); if(leader == null) @@ -72,9 +74,12 @@ public class JoinRequest { continue; leader.ifPlayer(leaderPlayer -> FightSystem.getMessage().sendPrefixless("JOIN_REQUEST_NOTIFICATION", leaderPlayer, "REQUESTS", new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/requests"), player.getName(), team.getColoredName())); + leader.ifAI(ai -> { + if(ai.acceptJoinRequest(player, team)) + accept(t); + }); } - activeRequests.put(player, this); FightSystem.getMessage().sendPrefixless("JOIN_REQUEST_CONFIRMATION", player, ChatMessageType.ACTION_BAR); } diff --git a/FightSystem_Core/src/de/steamwar/fightsystem/listener/NormalJoin.java b/FightSystem_Core/src/de/steamwar/fightsystem/listener/NormalJoin.java index 931f0b7..371ae75 100644 --- a/FightSystem_Core/src/de/steamwar/fightsystem/listener/NormalJoin.java +++ b/FightSystem_Core/src/de/steamwar/fightsystem/listener/NormalJoin.java @@ -20,14 +20,10 @@ package de.steamwar.fightsystem.listener; import de.steamwar.fightsystem.ArenaMode; -import de.steamwar.fightsystem.FightSystem; -import de.steamwar.fightsystem.ai.AIPlayer; import de.steamwar.fightsystem.fight.Fight; import de.steamwar.fightsystem.fight.FightTeam; import de.steamwar.fightsystem.states.FightState; import de.steamwar.fightsystem.states.StateDependentListener; -import de.steamwar.sql.SteamwarUser; -import org.bukkit.Bukkit; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; @@ -47,15 +43,7 @@ public class NormalJoin implements Listener { FightTeam team = Fight.teams().stream().filter(t -> player.getUniqueId().equals(t.getDesignatedLeader())).findAny( // Player is designated leader of a team ).orElse(Fight.teams().stream().filter(t -> t.canbeLeader(player)).findAny().orElse(null)); // Else search empty team - if(team != null) { + if(team != null) team.addMember(player); - FightTeam aiTeam = Fight.getOpposite(team); - AIPlayer aiPlayer = new AIPlayer(SteamwarUser.get(0)); - aiTeam.addMember(aiPlayer.getEntity()); - Bukkit.getScheduler().runTaskLater(FightSystem.getPlugin(), () -> { - FightState.setFightState(FightState.POST_SCHEM_SETUP); - aiTeam.setReady(true); - }, 1); - } } }