intelligence pvp thing done
This commit is contained in:
@@ -13,6 +13,7 @@ public class TerminatorPlus extends JavaPlugin {
|
|||||||
private static String version;
|
private static String version;
|
||||||
|
|
||||||
private BotManager manager;
|
private BotManager manager;
|
||||||
|
private CommandHandler handler;
|
||||||
|
|
||||||
public static TerminatorPlus getInstance() {
|
public static TerminatorPlus getInstance() {
|
||||||
return instance;
|
return instance;
|
||||||
@@ -26,6 +27,10 @@ public class TerminatorPlus extends JavaPlugin {
|
|||||||
return manager;
|
return manager;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public CommandHandler getHandler() {
|
||||||
|
return handler;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onEnable() {
|
public void onEnable() {
|
||||||
instance = this;
|
instance = this;
|
||||||
@@ -33,7 +38,7 @@ public class TerminatorPlus extends JavaPlugin {
|
|||||||
|
|
||||||
// Create Instances
|
// Create Instances
|
||||||
this.manager = new BotManager();
|
this.manager = new BotManager();
|
||||||
new CommandHandler(this);
|
this.handler = new CommandHandler(this);
|
||||||
|
|
||||||
// Register event listeners
|
// Register event listeners
|
||||||
this.registerEvents(manager);
|
this.registerEvents(manager);
|
||||||
|
|||||||
@@ -5,9 +5,11 @@ import com.mojang.datafixers.util.Pair;
|
|||||||
import net.minecraft.server.v1_16_R3.Chunk;
|
import net.minecraft.server.v1_16_R3.Chunk;
|
||||||
import net.minecraft.server.v1_16_R3.*;
|
import net.minecraft.server.v1_16_R3.*;
|
||||||
import net.nuggetmc.ai.TerminatorPlus;
|
import net.nuggetmc.ai.TerminatorPlus;
|
||||||
|
import net.nuggetmc.ai.bot.agent.Agent;
|
||||||
import net.nuggetmc.ai.bot.agent.legacyagent.ai.NeuralNetwork;
|
import net.nuggetmc.ai.bot.agent.legacyagent.ai.NeuralNetwork;
|
||||||
import net.nuggetmc.ai.bot.event.BotDamageByPlayerEvent;
|
import net.nuggetmc.ai.bot.event.BotDamageByPlayerEvent;
|
||||||
import net.nuggetmc.ai.bot.event.BotFallDamageEvent;
|
import net.nuggetmc.ai.bot.event.BotFallDamageEvent;
|
||||||
|
import net.nuggetmc.ai.bot.event.BotKilledByPlayerEvent;
|
||||||
import net.nuggetmc.ai.utils.*;
|
import net.nuggetmc.ai.utils.*;
|
||||||
import org.bukkit.Material;
|
import org.bukkit.Material;
|
||||||
import org.bukkit.SoundCategory;
|
import org.bukkit.SoundCategory;
|
||||||
@@ -21,6 +23,7 @@ import org.bukkit.craftbukkit.v1_16_R3.entity.CraftPlayer;
|
|||||||
import org.bukkit.craftbukkit.v1_16_R3.inventory.CraftItemStack;
|
import org.bukkit.craftbukkit.v1_16_R3.inventory.CraftItemStack;
|
||||||
import org.bukkit.entity.Damageable;
|
import org.bukkit.entity.Damageable;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
import org.bukkit.scheduler.BukkitScheduler;
|
import org.bukkit.scheduler.BukkitScheduler;
|
||||||
import org.bukkit.util.Vector;
|
import org.bukkit.util.Vector;
|
||||||
|
|
||||||
@@ -33,6 +36,7 @@ public class Bot extends EntityPlayer {
|
|||||||
|
|
||||||
private final TerminatorPlus plugin;
|
private final TerminatorPlus plugin;
|
||||||
private final BukkitScheduler scheduler;
|
private final BukkitScheduler scheduler;
|
||||||
|
private final Agent agent;
|
||||||
|
|
||||||
private NeuralNetwork network;
|
private NeuralNetwork network;
|
||||||
|
|
||||||
@@ -48,7 +52,7 @@ public class Bot extends EntityPlayer {
|
|||||||
return network != null;
|
return network != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean item; // eventually make this not garbage lol
|
public ItemStack defaultItem;
|
||||||
|
|
||||||
private boolean shield;
|
private boolean shield;
|
||||||
private boolean blocking;
|
private boolean blocking;
|
||||||
@@ -57,9 +61,11 @@ public class Bot extends EntityPlayer {
|
|||||||
private Vector velocity;
|
private Vector velocity;
|
||||||
private Vector oldVelocity;
|
private Vector oldVelocity;
|
||||||
|
|
||||||
private final boolean removeOnDeath;
|
private boolean removeOnDeath;
|
||||||
|
|
||||||
|
private int aliveTicks;
|
||||||
|
private int kills;
|
||||||
|
|
||||||
private byte aliveTicks;
|
|
||||||
private byte fireTicks;
|
private byte fireTicks;
|
||||||
private byte groundTicks;
|
private byte groundTicks;
|
||||||
private byte jumpTicks;
|
private byte jumpTicks;
|
||||||
@@ -72,6 +78,8 @@ public class Bot extends EntityPlayer {
|
|||||||
|
|
||||||
this.plugin = TerminatorPlus.getInstance();
|
this.plugin = TerminatorPlus.getInstance();
|
||||||
this.scheduler = Bukkit.getScheduler();
|
this.scheduler = Bukkit.getScheduler();
|
||||||
|
this.agent = plugin.getManager().getAgent();
|
||||||
|
this.defaultItem = new ItemStack(Material.AIR);
|
||||||
this.velocity = new Vector(0, 0, 0);
|
this.velocity = new Vector(0, 0, 0);
|
||||||
this.oldVelocity = velocity.clone();
|
this.oldVelocity = velocity.clone();
|
||||||
this.noFallTicks = 60;
|
this.noFallTicks = 60;
|
||||||
@@ -139,6 +147,10 @@ public class Bot extends EntityPlayer {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setDefaultItem(ItemStack item) {
|
||||||
|
this.defaultItem = item;
|
||||||
|
}
|
||||||
|
|
||||||
public Vector getOffset() {
|
public Vector getOffset() {
|
||||||
return offset;
|
return offset;
|
||||||
}
|
}
|
||||||
@@ -160,6 +172,10 @@ public class Bot extends EntityPlayer {
|
|||||||
velocity.add(vector);
|
velocity.add(vector);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getAliveTicks() {
|
||||||
|
return aliveTicks;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean tickDelay(int i) {
|
public boolean tickDelay(int i) {
|
||||||
return aliveTicks % i == 0;
|
return aliveTicks % i == 0;
|
||||||
}
|
}
|
||||||
@@ -385,7 +401,7 @@ public class Bot extends EntityPlayer {
|
|||||||
punch();
|
punch();
|
||||||
|
|
||||||
if (entity instanceof Damageable) {
|
if (entity instanceof Damageable) {
|
||||||
((Damageable) entity).damage(item ? 2.5 : 0.25, getBukkitEntity()); // fist damage is 0.25
|
((Damageable) entity).damage(ItemUtils.getLegacyAttackDamage(defaultItem), getBukkitEntity());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -442,10 +458,6 @@ public class Bot extends EntityPlayer {
|
|||||||
velocity.setZ(Math.abs(z) < frictionMin ? 0 : z * factor);
|
velocity.setZ(Math.abs(z) < frictionMin ? 0 : z * factor);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void despawn() {
|
|
||||||
getBukkitEntity().remove();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void removeVisually() {
|
public void removeVisually() {
|
||||||
this.removeTab();
|
this.removeTab();
|
||||||
this.setDead();
|
this.setDead();
|
||||||
@@ -455,6 +467,10 @@ public class Bot extends EntityPlayer {
|
|||||||
sendPacket(new PacketPlayOutPlayerInfo(PacketPlayOutPlayerInfo.EnumPlayerInfoAction.REMOVE_PLAYER, this));
|
sendPacket(new PacketPlayOutPlayerInfo(PacketPlayOutPlayerInfo.EnumPlayerInfoAction.REMOVE_PLAYER, this));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setRemoveOnDeath(boolean enabled) {
|
||||||
|
this.removeOnDeath = enabled;
|
||||||
|
}
|
||||||
|
|
||||||
private void setDead() {
|
private void setDead() {
|
||||||
this.dead = true;
|
this.dead = true;
|
||||||
this.defaultContainer.b(this);
|
this.defaultContainer.b(this);
|
||||||
@@ -523,11 +539,16 @@ public class Bot extends EntityPlayer {
|
|||||||
|
|
||||||
float damage;
|
float damage;
|
||||||
|
|
||||||
if (attacker instanceof EntityPlayer) {
|
boolean playerInstance = attacker instanceof EntityPlayer;
|
||||||
|
|
||||||
BotDamageByPlayerEvent event = new BotDamageByPlayerEvent(this, ((EntityPlayer) attacker).getBukkitEntity(), f);
|
Player killer;
|
||||||
|
|
||||||
plugin.getManager().getAgent().onPlayerDamage(event);
|
if (playerInstance) {
|
||||||
|
killer = ((EntityPlayer) attacker).getBukkitEntity();
|
||||||
|
|
||||||
|
BotDamageByPlayerEvent event = new BotDamageByPlayerEvent(this, killer, f);
|
||||||
|
|
||||||
|
agent.onPlayerDamage(event);
|
||||||
|
|
||||||
if (event.isCancelled()) {
|
if (event.isCancelled()) {
|
||||||
return false;
|
return false;
|
||||||
@@ -535,6 +556,7 @@ public class Bot extends EntityPlayer {
|
|||||||
|
|
||||||
damage = event.getDamage();
|
damage = event.getDamage();
|
||||||
} else {
|
} else {
|
||||||
|
killer = null;
|
||||||
damage = f;
|
damage = f;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -545,6 +567,10 @@ public class Bot extends EntityPlayer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (damaged && attacker != null) {
|
if (damaged && attacker != null) {
|
||||||
|
if (playerInstance && !isAlive()) {
|
||||||
|
agent.onBotKilledByPlayer(new BotKilledByPlayerEvent(this, killer));
|
||||||
|
}
|
||||||
|
|
||||||
kb(getLocation(), attacker.getBukkitEntity().getLocation());
|
kb(getLocation(), attacker.getBukkitEntity().getLocation());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -559,6 +585,14 @@ public class Bot extends EntityPlayer {
|
|||||||
velocity = vel;
|
velocity = vel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getKills() {
|
||||||
|
return kills;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void incrementKills() {
|
||||||
|
kills++;
|
||||||
|
}
|
||||||
|
|
||||||
public Location getLocation() {
|
public Location getLocation() {
|
||||||
return getBukkitEntity().getLocation();
|
return getBukkitEntity().getLocation();
|
||||||
}
|
}
|
||||||
@@ -615,8 +649,8 @@ public class Bot extends EntityPlayer {
|
|||||||
setItem(item, EnumItemSlot.OFFHAND);
|
setItem(item, EnumItemSlot.OFFHAND);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setItem(org.bukkit.inventory.ItemStack item, EnumItemSlot slot) {
|
private void setItem(org.bukkit.inventory.ItemStack item, EnumItemSlot slot) {
|
||||||
if (item == null) item = new org.bukkit.inventory.ItemStack(this.item ? Material.WOODEN_SHOVEL : Material.AIR);
|
if (item == null) item = defaultItem;
|
||||||
|
|
||||||
if (slot == EnumItemSlot.MAINHAND) {
|
if (slot == EnumItemSlot.MAINHAND) {
|
||||||
getBukkitEntity().getInventory().setItemInMainHand(item);
|
getBukkitEntity().getInventory().setItemInMainHand(item);
|
||||||
|
|||||||
@@ -3,22 +3,22 @@ package net.nuggetmc.ai.bot;
|
|||||||
import net.minecraft.server.v1_16_R3.PlayerConnection;
|
import net.minecraft.server.v1_16_R3.PlayerConnection;
|
||||||
import net.nuggetmc.ai.bot.agent.Agent;
|
import net.nuggetmc.ai.bot.agent.Agent;
|
||||||
import net.nuggetmc.ai.bot.agent.legacyagent.LegacyAgent;
|
import net.nuggetmc.ai.bot.agent.legacyagent.LegacyAgent;
|
||||||
import net.nuggetmc.ai.bot.agent.legacyagent.ai.NetworkType;
|
|
||||||
import net.nuggetmc.ai.bot.agent.legacyagent.ai.NeuralNetwork;
|
import net.nuggetmc.ai.bot.agent.legacyagent.ai.NeuralNetwork;
|
||||||
|
import net.nuggetmc.ai.bot.event.BotDeathEvent;
|
||||||
import net.nuggetmc.ai.utils.MojangAPI;
|
import net.nuggetmc.ai.utils.MojangAPI;
|
||||||
import org.bukkit.*;
|
import org.bukkit.*;
|
||||||
import org.bukkit.craftbukkit.v1_16_R3.entity.CraftPlayer;
|
import org.bukkit.craftbukkit.v1_16_R3.entity.CraftPlayer;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.event.EventHandler;
|
import org.bukkit.event.EventHandler;
|
||||||
import org.bukkit.event.Listener;
|
import org.bukkit.event.Listener;
|
||||||
import org.bukkit.event.entity.EntityDamageByEntityEvent;
|
import org.bukkit.event.entity.PlayerDeathEvent;
|
||||||
import org.bukkit.event.player.PlayerJoinEvent;
|
import org.bukkit.event.player.PlayerJoinEvent;
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
import org.bukkit.util.Vector;
|
import org.bukkit.util.Vector;
|
||||||
|
|
||||||
import java.text.NumberFormat;
|
import java.text.NumberFormat;
|
||||||
import java.util.HashSet;
|
import java.util.*;
|
||||||
import java.util.Locale;
|
import java.util.stream.Collectors;
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
public class BotManager implements Listener {
|
public class BotManager implements Listener {
|
||||||
|
|
||||||
@@ -27,7 +27,6 @@ public class BotManager implements Listener {
|
|||||||
private final NumberFormat numberFormat;
|
private final NumberFormat numberFormat;
|
||||||
|
|
||||||
public boolean joinMessages = false;
|
public boolean joinMessages = false;
|
||||||
public boolean removeOnDeath = true;
|
|
||||||
|
|
||||||
public BotManager() {
|
public BotManager() {
|
||||||
this.agent = new LegacyAgent(this);
|
this.agent = new LegacyAgent(this);
|
||||||
@@ -57,6 +56,10 @@ public class BotManager implements Listener {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<String> fetchNames() {
|
||||||
|
return bots.stream().map(Bot::getName).collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
public Agent getAgent() {
|
public Agent getAgent() {
|
||||||
return agent;
|
return agent;
|
||||||
}
|
}
|
||||||
@@ -65,44 +68,73 @@ public class BotManager implements Listener {
|
|||||||
createBots(sender, name, skinName, n, null);
|
createBots(sender, name, skinName, n, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void createBots(Player sender, String name, String skinName, int n, NetworkType type) {
|
public void createBots(Player sender, String name, String skinName, int n, NeuralNetwork network) {
|
||||||
long timestamp = System.currentTimeMillis();
|
long timestamp = System.currentTimeMillis();
|
||||||
|
|
||||||
if (n < 1) n = 1;
|
if (n < 1) n = 1;
|
||||||
|
|
||||||
World world = sender.getWorld();
|
|
||||||
Location loc = sender.getLocation();
|
|
||||||
|
|
||||||
sender.sendMessage("Creating " + (n == 1 ? "new bot" : ChatColor.RED + numberFormat.format(n) + ChatColor.RESET + " new bots")
|
sender.sendMessage("Creating " + (n == 1 ? "new bot" : ChatColor.RED + numberFormat.format(n) + ChatColor.RESET + " new bots")
|
||||||
+ " with name " + ChatColor.GREEN + name
|
+ " with name " + ChatColor.GREEN + name.replace("%", ChatColor.LIGHT_PURPLE + "%" + ChatColor.RESET)
|
||||||
+ (skinName == null ? "" : ChatColor.RESET + " and skin " + ChatColor.GREEN + skinName)
|
+ (skinName == null ? "" : ChatColor.RESET + " and skin " + ChatColor.GREEN + skinName)
|
||||||
+ ChatColor.RESET + "...");
|
+ ChatColor.RESET + "...");
|
||||||
|
|
||||||
skinName = skinName == null ? name : skinName;
|
skinName = skinName == null ? name : skinName;
|
||||||
|
|
||||||
double f = n < 100 ? .004 * n : .4;
|
createBots(sender.getLocation(), name, MojangAPI.getSkin(skinName), n, network);
|
||||||
|
|
||||||
String[] skin = MojangAPI.getSkin(skinName);
|
|
||||||
|
|
||||||
for (int i = 1; i <= n; i++) {
|
|
||||||
Bot bot = Bot.createBot(loc, name.replace("%", String.valueOf(i)), skin);
|
|
||||||
|
|
||||||
if (i > 1) {
|
|
||||||
bot.setVelocity(new Vector(Math.random() - 0.5, 0.5, Math.random() - 0.5).normalize().multiply(f));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (type == NetworkType.RANDOM) {
|
|
||||||
bot.setNeuralNetwork(NeuralNetwork.generateRandomNetwork());
|
|
||||||
bot.setShield(true);
|
|
||||||
bot.item = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
world.spawnParticle(Particle.CLOUD, loc, 100, 1, 1, 1, 0.5);
|
|
||||||
|
|
||||||
sender.sendMessage("Process completed (" + ChatColor.RED + ((System.currentTimeMillis() - timestamp) / 1000D) + "s" + ChatColor.RESET + ").");
|
sender.sendMessage("Process completed (" + ChatColor.RED + ((System.currentTimeMillis() - timestamp) / 1000D) + "s" + ChatColor.RESET + ").");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Set<Bot> createBots(Location loc, String name, String[] skin, int n, NeuralNetwork network) {
|
||||||
|
List<NeuralNetwork> networks = new ArrayList<>();
|
||||||
|
|
||||||
|
for (int i = 0; i < n; i++) {
|
||||||
|
networks.add(network);
|
||||||
|
}
|
||||||
|
|
||||||
|
return createBots(loc, name, skin, networks);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<Bot> createBots(Location loc, String name, String[] skin, List<NeuralNetwork> networks) {
|
||||||
|
Set<Bot> bots = new HashSet<>();
|
||||||
|
World world = loc.getWorld();
|
||||||
|
|
||||||
|
int n = networks.size();
|
||||||
|
int i = 1;
|
||||||
|
|
||||||
|
double f = n < 100 ? .004 * n : .4;
|
||||||
|
|
||||||
|
for (NeuralNetwork network : networks) {
|
||||||
|
Bot bot = Bot.createBot(loc, name.replace("%", String.valueOf(i)), skin);
|
||||||
|
|
||||||
|
if (network != null) {
|
||||||
|
bot.setNeuralNetwork(network == NeuralNetwork.RANDOM ? NeuralNetwork.generateRandomNetwork() : network);
|
||||||
|
bot.setShield(true);
|
||||||
|
bot.setDefaultItem(new ItemStack(Material.WOODEN_AXE));
|
||||||
|
bot.setRemoveOnDeath(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (network != null) {
|
||||||
|
bot.setVelocity(randomVelocity());
|
||||||
|
} else if (i > 1) {
|
||||||
|
bot.setVelocity(randomVelocity().multiply(f));
|
||||||
|
}
|
||||||
|
|
||||||
|
bots.add(bot);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (world != null) {
|
||||||
|
world.spawnParticle(Particle.CLOUD, loc, 100, 1, 1, 1, 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
return bots;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Vector randomVelocity() {
|
||||||
|
return new Vector(Math.random() - 0.5, 0.5, Math.random() - 0.5).normalize();
|
||||||
|
}
|
||||||
|
|
||||||
public void remove(Bot bot) {
|
public void remove(Bot bot) {
|
||||||
bots.remove(bot);
|
bots.remove(bot);
|
||||||
}
|
}
|
||||||
@@ -111,6 +143,23 @@ public class BotManager implements Listener {
|
|||||||
bots.forEach(Bot::removeVisually);
|
bots.forEach(Bot::removeVisually);
|
||||||
bots.clear(); // Not always necessary, but a good security measure
|
bots.clear(); // Not always necessary, but a good security measure
|
||||||
agent.stopAllTasks();
|
agent.stopAllTasks();
|
||||||
|
|
||||||
|
System.gc();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Bot getBot(Player player) { // potentially memory intensive
|
||||||
|
Bot bot = null;
|
||||||
|
|
||||||
|
int id = player.getEntityId();
|
||||||
|
|
||||||
|
for (Bot b : bots) {
|
||||||
|
if (id == b.getId()) {
|
||||||
|
bot = b;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return bot;
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
@@ -120,11 +169,12 @@ public class BotManager implements Listener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
public void onEntityDamage(EntityDamageByEntityEvent event) {
|
public void onDeath(PlayerDeathEvent event) {
|
||||||
if (!(event.getEntity() instanceof Player)) return;
|
Player player = event.getEntity();
|
||||||
if (!(event.getDamager() instanceof Player)) return;
|
Bot bot = getBot(player);
|
||||||
|
|
||||||
Player player = (Player) event.getEntity();
|
if (bot != null) {
|
||||||
Player damager = (Player) event.getDamager();
|
agent.onBotDeath(new BotDeathEvent(event, bot));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,14 @@
|
|||||||
package net.nuggetmc.ai.bot.agent;
|
package net.nuggetmc.ai.bot.agent;
|
||||||
|
|
||||||
import net.nuggetmc.ai.TerminatorPlus;
|
import net.nuggetmc.ai.TerminatorPlus;
|
||||||
|
import net.nuggetmc.ai.bot.Bot;
|
||||||
import net.nuggetmc.ai.bot.BotManager;
|
import net.nuggetmc.ai.bot.BotManager;
|
||||||
import net.nuggetmc.ai.bot.event.BotDamageByPlayerEvent;
|
import net.nuggetmc.ai.bot.event.BotDamageByPlayerEvent;
|
||||||
|
import net.nuggetmc.ai.bot.event.BotDeathEvent;
|
||||||
import net.nuggetmc.ai.bot.event.BotFallDamageEvent;
|
import net.nuggetmc.ai.bot.event.BotFallDamageEvent;
|
||||||
|
import net.nuggetmc.ai.bot.event.BotKilledByPlayerEvent;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.scheduler.BukkitRunnable;
|
import org.bukkit.scheduler.BukkitRunnable;
|
||||||
import org.bukkit.scheduler.BukkitScheduler;
|
import org.bukkit.scheduler.BukkitScheduler;
|
||||||
|
|
||||||
@@ -23,6 +27,8 @@ public abstract class Agent {
|
|||||||
protected boolean enabled;
|
protected boolean enabled;
|
||||||
protected int taskID;
|
protected int taskID;
|
||||||
|
|
||||||
|
protected boolean drops;
|
||||||
|
|
||||||
public Agent(BotManager manager) {
|
public Agent(BotManager manager) {
|
||||||
this.plugin = TerminatorPlus.getInstance();
|
this.plugin = TerminatorPlus.getInstance();
|
||||||
this.manager = manager;
|
this.manager = manager;
|
||||||
@@ -53,9 +59,27 @@ public abstract class Agent {
|
|||||||
taskList.clear();
|
taskList.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setDrops(boolean enabled) {
|
||||||
|
this.drops = enabled;
|
||||||
|
}
|
||||||
|
|
||||||
protected abstract void tick();
|
protected abstract void tick();
|
||||||
|
|
||||||
public void onFallDamage(BotFallDamageEvent event) { }
|
public void onFallDamage(BotFallDamageEvent event) { }
|
||||||
|
|
||||||
public void onPlayerDamage(BotDamageByPlayerEvent event) { }
|
public void onPlayerDamage(BotDamageByPlayerEvent event) { }
|
||||||
|
|
||||||
|
public void onBotDeath(BotDeathEvent event) { }
|
||||||
|
|
||||||
|
public void onBotKilledByPlayer(BotKilledByPlayerEvent event) {
|
||||||
|
Player player = event.getPlayer();
|
||||||
|
|
||||||
|
scheduler.runTaskAsynchronously(plugin, () -> {
|
||||||
|
Bot bot = manager.getBot(player);
|
||||||
|
|
||||||
|
if (bot != null) {
|
||||||
|
bot.incrementKills();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ public enum EnumTargetGoal { // TODO USE ORDINAL!!!!!
|
|||||||
NEAREST_REAL_PLAYER,
|
NEAREST_REAL_PLAYER,
|
||||||
NEAREST_BOT_DIFFER,
|
NEAREST_BOT_DIFFER,
|
||||||
NEAREST_BOT,
|
NEAREST_BOT,
|
||||||
|
NEAREST_BOT_DIFFER_ALPHA,
|
||||||
NONE;
|
NONE;
|
||||||
|
|
||||||
public static EnumTargetGoal of(int n) {
|
public static EnumTargetGoal of(int n) {
|
||||||
@@ -23,6 +24,9 @@ public enum EnumTargetGoal { // TODO USE ORDINAL!!!!!
|
|||||||
|
|
||||||
case 4:
|
case 4:
|
||||||
return NEAREST_BOT;
|
return NEAREST_BOT;
|
||||||
|
|
||||||
|
case 5:
|
||||||
|
return NEAREST_BOT_DIFFER_ALPHA;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,9 @@ import net.nuggetmc.ai.bot.agent.legacyagent.ai.BotData;
|
|||||||
import net.nuggetmc.ai.bot.agent.legacyagent.ai.BotNode;
|
import net.nuggetmc.ai.bot.agent.legacyagent.ai.BotNode;
|
||||||
import net.nuggetmc.ai.bot.agent.legacyagent.ai.NeuralNetwork;
|
import net.nuggetmc.ai.bot.agent.legacyagent.ai.NeuralNetwork;
|
||||||
import net.nuggetmc.ai.bot.event.BotDamageByPlayerEvent;
|
import net.nuggetmc.ai.bot.event.BotDamageByPlayerEvent;
|
||||||
|
import net.nuggetmc.ai.bot.event.BotDeathEvent;
|
||||||
import net.nuggetmc.ai.bot.event.BotFallDamageEvent;
|
import net.nuggetmc.ai.bot.event.BotFallDamageEvent;
|
||||||
|
import net.nuggetmc.ai.bot.event.BotKilledByPlayerEvent;
|
||||||
import net.nuggetmc.ai.utils.MathUtils;
|
import net.nuggetmc.ai.utils.MathUtils;
|
||||||
import net.nuggetmc.ai.utils.PlayerUtils;
|
import net.nuggetmc.ai.utils.PlayerUtils;
|
||||||
import org.bukkit.*;
|
import org.bukkit.*;
|
||||||
@@ -234,30 +236,58 @@ public class LegacyAgent extends Agent {
|
|||||||
if (ai) {
|
if (ai) {
|
||||||
NeuralNetwork network = bot.getNeuralNetwork();
|
NeuralNetwork network = bot.getNeuralNetwork();
|
||||||
|
|
||||||
boolean left = network.check(BotNode.LEFT);
|
if (network.dynamicLR()) {
|
||||||
boolean right = network.check(BotNode.RIGHT);
|
if (bot.isBlocking()) {
|
||||||
|
vel.multiply(0.6);
|
||||||
|
}
|
||||||
|
|
||||||
if (bot.isBlocking()) {
|
if (distance <= 6) {
|
||||||
vel.multiply(0.6);
|
|
||||||
|
// positive y rotation means left, negative means right
|
||||||
|
// if left > right, value will be positive
|
||||||
|
|
||||||
|
double value = network.value(BotNode.LEFT) - network.value(BotNode.RIGHT);
|
||||||
|
|
||||||
|
vel.rotateAroundY(value * Math.PI / 8);
|
||||||
|
|
||||||
|
if (network.check(BotNode.JUMP)) {
|
||||||
|
bot.jump(vel);
|
||||||
|
} else {
|
||||||
|
bot.walk(vel.clone().setY(0));
|
||||||
|
scheduler.runTaskLater(plugin, () -> bot.jump(vel), 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (left != right && distance <= 6) {
|
else {
|
||||||
if (left) {
|
boolean left = network.check(BotNode.LEFT);
|
||||||
vel.rotateAroundY(Math.PI / 4);
|
boolean right = network.check(BotNode.RIGHT);
|
||||||
|
|
||||||
|
if (bot.isBlocking()) {
|
||||||
|
vel.multiply(0.6);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (right) {
|
if (left != right && distance <= 6) {
|
||||||
vel.rotateAroundY(-Math.PI / 4);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (network.check(BotNode.JUMP)) {
|
if (left) {
|
||||||
bot.jump(vel);
|
vel.rotateAroundY(Math.PI / 4);
|
||||||
} else {
|
}
|
||||||
bot.walk(vel.clone().setY(0));
|
|
||||||
scheduler.runTaskLater(plugin, () -> bot.jump(vel), 10);
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
if (right) {
|
||||||
|
vel.rotateAroundY(-Math.PI / 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (network.check(BotNode.JUMP)) {
|
||||||
|
bot.jump(vel);
|
||||||
|
} else {
|
||||||
|
bot.walk(vel.clone().setY(0));
|
||||||
|
scheduler.runTaskLater(plugin, () -> bot.jump(vel), 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -280,6 +310,13 @@ public class LegacyAgent extends Agent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBotDeath(BotDeathEvent event) {
|
||||||
|
if (!drops) {
|
||||||
|
event.getDrops().clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPlayerDamage(BotDamageByPlayerEvent event) {
|
public void onPlayerDamage(BotDamageByPlayerEvent event) {
|
||||||
Bot bot = event.getBot();
|
Bot bot = event.getBot();
|
||||||
@@ -1023,9 +1060,9 @@ public class LegacyAgent extends Agent {
|
|||||||
Vector vector = targetLoc.toVector().subtract(bot.getLocation().toVector()).normalize();
|
Vector vector = targetLoc.toVector().subtract(bot.getLocation().toVector()).normalize();
|
||||||
vector.multiply(0.8);
|
vector.multiply(0.8);
|
||||||
|
|
||||||
Vector move = bot.getVelocity().add(vector);
|
Vector move = bot.getVelocity().add(vector).setY(0);
|
||||||
if (move.length() > 1) move = move.normalize();
|
if (move.length() > 1) move = move.normalize();
|
||||||
move.multiply(0.75);
|
move.multiply(0.5);
|
||||||
move.setY(0.42);
|
move.setY(0.42);
|
||||||
bot.setVelocity(move);
|
bot.setVelocity(move);
|
||||||
|
|
||||||
@@ -1104,6 +1141,9 @@ public class LegacyAgent extends Agent {
|
|||||||
case NEAREST_BOT_DIFFER:
|
case NEAREST_BOT_DIFFER:
|
||||||
return nearestBotDiffer(bot, loc);
|
return nearestBotDiffer(bot, loc);
|
||||||
|
|
||||||
|
case NEAREST_BOT_DIFFER_ALPHA:
|
||||||
|
return nearestBotDifferAlpha(bot, loc);
|
||||||
|
|
||||||
case NEAREST_BOT:
|
case NEAREST_BOT:
|
||||||
return nearestBot(bot, loc);
|
return nearestBot(bot, loc);
|
||||||
|
|
||||||
@@ -1116,7 +1156,7 @@ public class LegacyAgent extends Agent {
|
|||||||
Player result = null;
|
Player result = null;
|
||||||
|
|
||||||
for (Player player : Bukkit.getOnlinePlayers()) {
|
for (Player player : Bukkit.getOnlinePlayers()) {
|
||||||
if (loc.getWorld() != player.getWorld()) continue;
|
if (loc.getWorld() != player.getWorld() || player.isDead()) continue;
|
||||||
|
|
||||||
if (result == null || loc.distance(player.getLocation()) < loc.distance(result.getLocation())) {
|
if (result == null || loc.distance(player.getLocation()) < loc.distance(result.getLocation())) {
|
||||||
result = player;
|
result = player;
|
||||||
@@ -1130,7 +1170,7 @@ public class LegacyAgent extends Agent {
|
|||||||
Player result = null;
|
Player result = null;
|
||||||
|
|
||||||
for (Player player : Bukkit.getOnlinePlayers()) {
|
for (Player player : Bukkit.getOnlinePlayers()) {
|
||||||
if (PlayerUtils.isInvincible(player.getGameMode()) || loc.getWorld() != player.getWorld()) continue;
|
if (PlayerUtils.isInvincible(player.getGameMode()) || loc.getWorld() != player.getWorld() || player.isDead()) continue;
|
||||||
|
|
||||||
if (result == null || loc.distance(player.getLocation()) < loc.distance(result.getLocation())) {
|
if (result == null || loc.distance(player.getLocation()) < loc.distance(result.getLocation())) {
|
||||||
result = player;
|
result = player;
|
||||||
@@ -1148,7 +1188,7 @@ public class LegacyAgent extends Agent {
|
|||||||
|
|
||||||
Player player = otherBot.getBukkitEntity();
|
Player player = otherBot.getBukkitEntity();
|
||||||
|
|
||||||
if (loc.getWorld() != player.getWorld()) continue;
|
if (loc.getWorld() != player.getWorld() || player.isDead()) continue;
|
||||||
|
|
||||||
if (result == null || loc.distance(player.getLocation()) < loc.distance(result.getLocation())) {
|
if (result == null || loc.distance(player.getLocation()) < loc.distance(result.getLocation())) {
|
||||||
result = player;
|
result = player;
|
||||||
@@ -1167,7 +1207,27 @@ public class LegacyAgent extends Agent {
|
|||||||
Player player = otherBot.getBukkitEntity();
|
Player player = otherBot.getBukkitEntity();
|
||||||
|
|
||||||
if (!bot.getName().equals(otherBot.getName())) {
|
if (!bot.getName().equals(otherBot.getName())) {
|
||||||
if (loc.getWorld() != player.getWorld()) continue;
|
if (loc.getWorld() != player.getWorld() || player.isDead()) continue;
|
||||||
|
|
||||||
|
if (result == null || loc.distance(player.getLocation()) < loc.distance(result.getLocation())) {
|
||||||
|
result = player;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Player nearestBotDifferAlpha(Bot bot, Location loc) {
|
||||||
|
Player result = null;
|
||||||
|
|
||||||
|
for (Bot otherBot : manager.fetch()) {
|
||||||
|
if (bot == otherBot) continue;
|
||||||
|
|
||||||
|
Player player = otherBot.getBukkitEntity();
|
||||||
|
|
||||||
|
if (!bot.getName().replaceAll("[^A-Za-z]+", "").equals(otherBot.getName().replaceAll("[^A-Za-z]+", ""))) {
|
||||||
|
if (loc.getWorld() != player.getWorld() || player.isDead()) continue;
|
||||||
|
|
||||||
if (result == null || loc.distance(player.getLocation()) < loc.distance(result.getLocation())) {
|
if (result == null || loc.distance(player.getLocation()) < loc.distance(result.getLocation())) {
|
||||||
result = player;
|
result = player;
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package net.nuggetmc.ai.bot.agent.legacyagent;
|
|||||||
|
|
||||||
import net.nuggetmc.ai.TerminatorPlus;
|
import net.nuggetmc.ai.TerminatorPlus;
|
||||||
import net.nuggetmc.ai.bot.Bot;
|
import net.nuggetmc.ai.bot.Bot;
|
||||||
|
import net.nuggetmc.ai.utils.Debugger;
|
||||||
import org.bukkit.*;
|
import org.bukkit.*;
|
||||||
import org.bukkit.block.Block;
|
import org.bukkit.block.Block;
|
||||||
import org.bukkit.block.BlockFace;
|
import org.bukkit.block.BlockFace;
|
||||||
@@ -27,6 +28,11 @@ public class LegacyBlockCheck {
|
|||||||
for (Player all : Bukkit.getOnlinePlayers()) all.playSound(loc, Sound.BLOCK_STONE_PLACE, SoundCategory.BLOCKS, 1, 1);
|
for (Player all : Bukkit.getOnlinePlayers()) all.playSound(loc, Sound.BLOCK_STONE_PLACE, SoundCategory.BLOCKS, 1, 1);
|
||||||
bot.setItem(new ItemStack(Material.COBBLESTONE));
|
bot.setItem(new ItemStack(Material.COBBLESTONE));
|
||||||
loc.getBlock().setType(Material.COBBLESTONE);
|
loc.getBlock().setType(Material.COBBLESTONE);
|
||||||
|
|
||||||
|
Block under = loc.clone().add(0, -1, 0).getBlock();
|
||||||
|
if (under.getType() == Material.LAVA) {
|
||||||
|
under.setType(Material.COBBLESTONE);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -41,10 +47,7 @@ public class LegacyBlockCheck {
|
|||||||
Bukkit.getScheduler().runTaskLater(plugin, () -> {
|
Bukkit.getScheduler().runTaskLater(plugin, () -> {
|
||||||
placeFinal(bot, player, block.getLocation());
|
placeFinal(bot, player, block.getLocation());
|
||||||
}, 2);
|
}, 2);
|
||||||
}/* else {
|
}
|
||||||
placeFinal(player, block.getLocation());
|
|
||||||
return;
|
|
||||||
}*/
|
|
||||||
|
|
||||||
Set<Block> face = new HashSet<>(Arrays.asList(loc.clone().add(1, 0, 0).getBlock(),
|
Set<Block> face = new HashSet<>(Arrays.asList(loc.clone().add(1, 0, 0).getBlock(),
|
||||||
loc.clone().add(-1, 0, 0).getBlock(),
|
loc.clone().add(-1, 0, 0).getBlock(),
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package net.nuggetmc.ai.bot.agent.legacyagent.ai;
|
||||||
|
|
||||||
|
public enum ActivationType {
|
||||||
|
TANH,
|
||||||
|
SIN_X,
|
||||||
|
SIN_X2,
|
||||||
|
COS_X,
|
||||||
|
COS_X2
|
||||||
|
}
|
||||||
@@ -1,8 +1,18 @@
|
|||||||
package net.nuggetmc.ai.bot.agent.legacyagent.ai;
|
package net.nuggetmc.ai.bot.agent.legacyagent.ai;
|
||||||
|
|
||||||
public enum BotDataType {
|
public enum BotDataType {
|
||||||
CRITICAL_HEALTH,
|
CRITICAL_HEALTH("h"),
|
||||||
DISTANCE_XZ,
|
DISTANCE_XZ("xz"),
|
||||||
DISTANCE_Y,
|
DISTANCE_Y("y"),
|
||||||
ENEMY_BLOCKING
|
ENEMY_BLOCKING("b");
|
||||||
|
|
||||||
|
private final String shorthand;
|
||||||
|
|
||||||
|
BotDataType(String shorthand) {
|
||||||
|
this.shorthand = shorthand;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getShorthand() {
|
||||||
|
return shorthand;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,335 @@
|
|||||||
|
package net.nuggetmc.ai.bot.agent.legacyagent.ai;
|
||||||
|
|
||||||
|
import com.jonahseguin.drink.utils.ChatUtils;
|
||||||
|
import net.minecraft.server.v1_16_R3.EntityLiving;
|
||||||
|
import net.nuggetmc.ai.TerminatorPlus;
|
||||||
|
import net.nuggetmc.ai.bot.Bot;
|
||||||
|
import net.nuggetmc.ai.bot.BotManager;
|
||||||
|
import net.nuggetmc.ai.bot.agent.legacyagent.EnumTargetGoal;
|
||||||
|
import net.nuggetmc.ai.bot.agent.legacyagent.LegacyAgent;
|
||||||
|
import net.nuggetmc.ai.command.commands.AICommand;
|
||||||
|
import net.nuggetmc.ai.utils.MathUtils;
|
||||||
|
import net.nuggetmc.ai.utils.MojangAPI;
|
||||||
|
import net.nuggetmc.ai.utils.PlayerUtils;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.ChatColor;
|
||||||
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.scheduler.BukkitScheduler;
|
||||||
|
|
||||||
|
import java.text.NumberFormat;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
public class IntelligenceAgent {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* export all agent data to the plugin folder as separate folder things
|
||||||
|
* commands /ai stop and /ai pause
|
||||||
|
* if a session with name already exists keep adding underscores
|
||||||
|
* /ai conclude or /ai finish
|
||||||
|
*/
|
||||||
|
|
||||||
|
private final TerminatorPlus plugin;
|
||||||
|
private final BotManager manager;
|
||||||
|
private final AICommand aiManager;
|
||||||
|
private final BukkitScheduler scheduler;
|
||||||
|
|
||||||
|
private LegacyAgent agent;
|
||||||
|
private Thread thread;
|
||||||
|
private boolean active;
|
||||||
|
|
||||||
|
private final String name;
|
||||||
|
|
||||||
|
private final String botName;
|
||||||
|
private final String botSkin;
|
||||||
|
private final int cutoff;
|
||||||
|
|
||||||
|
private final Map<String, Bot> bots;
|
||||||
|
|
||||||
|
private int populationSize;
|
||||||
|
private int generation;
|
||||||
|
|
||||||
|
private Player primary;
|
||||||
|
|
||||||
|
private final Set<CommandSender> users;
|
||||||
|
|
||||||
|
private final Map<Integer, Set<Map<BotNode, Map<BotDataType, Double>>>> genProfiles;
|
||||||
|
|
||||||
|
public IntelligenceAgent(AICommand aiManager, int populationSize, String name, String skin) {
|
||||||
|
this.plugin = TerminatorPlus.getInstance();
|
||||||
|
this.manager = plugin.getManager();
|
||||||
|
this.aiManager = aiManager;
|
||||||
|
this.scheduler = Bukkit.getScheduler();
|
||||||
|
this.name = new SimpleDateFormat("yyyy-MM-dd HH-mm-ss").format(Calendar.getInstance().getTime());
|
||||||
|
this.botName = name;
|
||||||
|
this.botSkin = skin;
|
||||||
|
this.bots = new HashMap<>();
|
||||||
|
this.users = new HashSet<>(Collections.singletonList(Bukkit.getConsoleSender()));
|
||||||
|
this.cutoff = 5;
|
||||||
|
this.genProfiles = new HashMap<>();
|
||||||
|
this.populationSize = populationSize;
|
||||||
|
this.active = true;
|
||||||
|
|
||||||
|
scheduler.runTaskAsynchronously(plugin, () -> {
|
||||||
|
thread = Thread.currentThread();
|
||||||
|
|
||||||
|
try {
|
||||||
|
task();
|
||||||
|
} catch (Exception e) {
|
||||||
|
print(e);
|
||||||
|
print("The thread has been interrupted.");
|
||||||
|
print("The session will now close.");
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void task() throws InterruptedException {
|
||||||
|
setup();
|
||||||
|
sleep(1000);
|
||||||
|
|
||||||
|
while (active) {
|
||||||
|
runGeneration();
|
||||||
|
}
|
||||||
|
|
||||||
|
sleep(5000);
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void runGeneration() throws InterruptedException {
|
||||||
|
generation++;
|
||||||
|
|
||||||
|
print("Starting generation " + ChatColor.RED + generation + ChatColor.RESET + "...");
|
||||||
|
|
||||||
|
sleep(2000);
|
||||||
|
|
||||||
|
String skinName = botSkin == null ? this.botName : botSkin;
|
||||||
|
|
||||||
|
print("Fetching skin data for " + ChatColor.GREEN + skinName + ChatColor.RESET + "...");
|
||||||
|
|
||||||
|
String[] skinData = MojangAPI.getSkin(skinName);
|
||||||
|
|
||||||
|
String botName = this.botName.endsWith("%") ? this.botName : this.botName + "%";
|
||||||
|
|
||||||
|
print("Creating " + (populationSize == 1 ? "new bot" : ChatColor.RED + NumberFormat.getInstance(Locale.US).format(populationSize) + ChatColor.RESET + " new bots")
|
||||||
|
+ " with name " + ChatColor.GREEN + botName.replace("%", ChatColor.LIGHT_PURPLE + "%" + ChatColor.RESET)
|
||||||
|
+ (botSkin == null ? "" : ChatColor.RESET + " and skin " + ChatColor.GREEN + botSkin)
|
||||||
|
+ ChatColor.RESET + "...");
|
||||||
|
|
||||||
|
Set<Map<BotNode, Map<BotDataType, Double>>> loadedProfiles = genProfiles.get(generation);
|
||||||
|
Location loc = PlayerUtils.findAbove(primary.getLocation(), 20);
|
||||||
|
|
||||||
|
scheduler.runTask(plugin, () -> {
|
||||||
|
Set<Bot> bots;
|
||||||
|
|
||||||
|
if (loadedProfiles == null) {
|
||||||
|
bots = manager.createBots(loc, botName, skinData, populationSize, NeuralNetwork.RANDOM);
|
||||||
|
} else {
|
||||||
|
List<NeuralNetwork> networks = new ArrayList<>();
|
||||||
|
loadedProfiles.forEach(profile -> networks.add(NeuralNetwork.createNetworkFromProfile(profile)));
|
||||||
|
|
||||||
|
if (populationSize != networks.size()) {
|
||||||
|
print("An exception has occured.");
|
||||||
|
print("The stored population size differs from the size of the stored networks.");
|
||||||
|
close();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bots = manager.createBots(loc, botName, skinData, networks);
|
||||||
|
}
|
||||||
|
|
||||||
|
bots.forEach(bot -> {
|
||||||
|
String name = bot.getName();
|
||||||
|
|
||||||
|
while (this.bots.containsKey(name)) {
|
||||||
|
name += "_";
|
||||||
|
}
|
||||||
|
|
||||||
|
this.bots.put(name, bot);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
while (bots.size() != populationSize) {
|
||||||
|
sleep(1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
sleep(2000);
|
||||||
|
print("The bots will now attack each other.");
|
||||||
|
|
||||||
|
agent.setTargetType(EnumTargetGoal.NEAREST_BOT);
|
||||||
|
|
||||||
|
while (aliveCount() > 1) {
|
||||||
|
sleep(1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
print("Generation " + ChatColor.RED + generation + ChatColor.RESET + " has ended.");
|
||||||
|
|
||||||
|
HashMap<Bot, Integer> values = new HashMap<>();
|
||||||
|
|
||||||
|
for (Bot bot : bots.values()) {
|
||||||
|
values.put(bot, bot.getAliveTicks());
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Map.Entry<Bot, Integer>> sorted = MathUtils.sortByValue(values);
|
||||||
|
Set<Bot> winners = new HashSet<>();
|
||||||
|
|
||||||
|
int i = 1;
|
||||||
|
|
||||||
|
for (Map.Entry<Bot, Integer> entry : sorted) {
|
||||||
|
Bot bot = entry.getKey();
|
||||||
|
boolean check = i <= cutoff;
|
||||||
|
if (check) {
|
||||||
|
print(ChatColor.GRAY + "[" + ChatColor.YELLOW + "#" + i + ChatColor.GRAY + "] " + ChatColor.GREEN + bot.getName()
|
||||||
|
+ ChatUtils.BULLET_FORMATTED + ChatColor.RED + bot.getKills() + " kills");
|
||||||
|
winners.add(bot);
|
||||||
|
}
|
||||||
|
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
sleep(3000);
|
||||||
|
|
||||||
|
Map<BotNode, Map<BotDataType, List<Double>>> lists = new HashMap<>();
|
||||||
|
|
||||||
|
winners.forEach(bot -> {
|
||||||
|
Map<BotNode, Map<BotDataType, Double>> data = bot.getNeuralNetwork().values();
|
||||||
|
|
||||||
|
data.forEach((nodeType, node) -> {
|
||||||
|
if (!lists.containsKey(nodeType)) {
|
||||||
|
lists.put(nodeType, new HashMap<>());
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<BotDataType, List<Double>> nodeValues = lists.get(nodeType);
|
||||||
|
|
||||||
|
node.forEach((dataType, value) -> {
|
||||||
|
if (!nodeValues.containsKey(dataType)) {
|
||||||
|
nodeValues.put(dataType, new ArrayList<>());
|
||||||
|
}
|
||||||
|
|
||||||
|
nodeValues.get(dataType).add(value);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
Set<Map<BotNode, Map<BotDataType, Double>>> profiles = new HashSet<>();
|
||||||
|
|
||||||
|
double mutationSize = MathUtils.getMutationSize(generation);
|
||||||
|
|
||||||
|
for (int j = 0; j < populationSize; j++) {
|
||||||
|
Map<BotNode, Map<BotDataType, Double>> profile = new HashMap<>();
|
||||||
|
|
||||||
|
lists.forEach((nodeType, map) -> {
|
||||||
|
Map<BotDataType, Double> points = new HashMap<>();
|
||||||
|
|
||||||
|
map.forEach((dataType, dataPoints) -> {
|
||||||
|
double value = ((int) (10 * MathUtils.generateConnectionValue(dataPoints, mutationSize))) / 10D;
|
||||||
|
|
||||||
|
points.put(dataType, value);
|
||||||
|
});
|
||||||
|
|
||||||
|
profile.put(nodeType, points);
|
||||||
|
});
|
||||||
|
|
||||||
|
profiles.add(profile);
|
||||||
|
}
|
||||||
|
|
||||||
|
genProfiles.put(generation + 1, profiles);
|
||||||
|
|
||||||
|
sleep(2000);
|
||||||
|
|
||||||
|
clearBots();
|
||||||
|
|
||||||
|
agent.setTargetType(EnumTargetGoal.NONE);
|
||||||
|
}
|
||||||
|
|
||||||
|
private int aliveCount() {
|
||||||
|
return (int) bots.values().stream().filter(EntityLiving::isAlive).count();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void close() {
|
||||||
|
aiManager.clearSession();
|
||||||
|
stop(); // safety call
|
||||||
|
}
|
||||||
|
|
||||||
|
public void stop() {
|
||||||
|
if (this.active) {
|
||||||
|
this.active = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!thread.isInterrupted()) {
|
||||||
|
this.thread.interrupt();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sleep(long millis) throws InterruptedException {
|
||||||
|
Thread.sleep(millis);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addUser(CommandSender sender) {
|
||||||
|
users.add(sender);
|
||||||
|
print(sender.getName() + " has been added to the userlist.");
|
||||||
|
|
||||||
|
if (primary == null && sender instanceof Player) {
|
||||||
|
setPrimary((Player) sender);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPrimary(Player player) {
|
||||||
|
this.primary = player;
|
||||||
|
print(player.getName() + " has been set as the primary user.");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void print(Object... objects) {
|
||||||
|
String message = ChatColor.DARK_GREEN + "[REINFORCEMENT] " + ChatColor.RESET + String.join(" ", Arrays.stream(objects).map(String::valueOf).toArray(String[]::new));
|
||||||
|
users.forEach(u -> u.sendMessage(message));
|
||||||
|
// log -> ChatColor.stripColor(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setup() {
|
||||||
|
clearBots();
|
||||||
|
|
||||||
|
if (populationSize < cutoff) {
|
||||||
|
populationSize = cutoff;
|
||||||
|
print("The input value for the population size is lower than the cutoff (" + ChatColor.RED + cutoff + ChatColor.RESET + ")!"
|
||||||
|
+ " The new population size is " + ChatColor.RED + populationSize + ChatColor.RESET + ".");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(manager.getAgent() instanceof LegacyAgent)) {
|
||||||
|
print("The AI manager currently only supports " + ChatColor.AQUA + "LegacyAgent" + ChatColor.RESET + ".");
|
||||||
|
close();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
agent = (LegacyAgent) manager.getAgent();
|
||||||
|
agent.setTargetType(EnumTargetGoal.NONE);
|
||||||
|
|
||||||
|
print("The bot target goal has been set to " + ChatColor.YELLOW + EnumTargetGoal.NONE.name() + ChatColor.RESET + ".");
|
||||||
|
print("Disabling target offsets...");
|
||||||
|
|
||||||
|
agent.offsets = false;
|
||||||
|
|
||||||
|
print("Disabling bot drops...");
|
||||||
|
|
||||||
|
agent.setDrops(false);
|
||||||
|
|
||||||
|
print(ChatColor.GREEN + "Setup is now complete.");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void clearBots() {
|
||||||
|
print("Removing all current bots...");
|
||||||
|
|
||||||
|
int size = manager.fetch().size();
|
||||||
|
manager.reset();
|
||||||
|
|
||||||
|
String formatted = NumberFormat.getNumberInstance(Locale.US).format(size);
|
||||||
|
print("Removed " + ChatColor.RED + formatted + ChatColor.RESET + " entit" + (size == 1 ? "y" : "ies") + ".");
|
||||||
|
|
||||||
|
bots.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
package net.nuggetmc.ai.bot.agent.legacyagent.ai;
|
|
||||||
|
|
||||||
public enum NetworkType {
|
|
||||||
RANDOM
|
|
||||||
}
|
|
||||||
@@ -14,16 +14,31 @@ public class NeuralNetwork {
|
|||||||
// randomize the blocking length and cooldown
|
// randomize the blocking length and cooldown
|
||||||
// also the XZ offset randomizers!! (or maybe just turn them off entirely, that works too)
|
// also the XZ offset randomizers!! (or maybe just turn them off entirely, that works too)
|
||||||
|
|
||||||
|
// b, j, l, r, ox, oz, av, bl, bc, dlr
|
||||||
|
|
||||||
private final Map<BotNode, NodeConnections> nodes;
|
private final Map<BotNode, NodeConnections> nodes;
|
||||||
|
|
||||||
private NeuralNetwork(BotNode... nodes) {
|
private final boolean dynamicLR;
|
||||||
this.nodes = new HashMap<>();
|
|
||||||
|
|
||||||
Arrays.stream(nodes).forEach(n -> this.nodes.put(n, new NodeConnections()));
|
public static final NeuralNetwork RANDOM = new NeuralNetwork(new HashMap<>());
|
||||||
|
|
||||||
|
private NeuralNetwork(Map<BotNode, Map<BotDataType, Double>> profile) {
|
||||||
|
this.nodes = new HashMap<>();
|
||||||
|
this.dynamicLR = true;
|
||||||
|
|
||||||
|
if (profile == null) {
|
||||||
|
Arrays.stream(BotNode.values()).forEach(n -> this.nodes.put(n, new NodeConnections()));
|
||||||
|
} else {
|
||||||
|
profile.forEach((nodeType, map) -> nodes.put(nodeType, new NodeConnections(map)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static NeuralNetwork createNetworkFromProfile(Map<BotNode, Map<BotDataType, Double>> profile) {
|
||||||
|
return new NeuralNetwork(profile);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static NeuralNetwork generateRandomNetwork() {
|
public static NeuralNetwork generateRandomNetwork() {
|
||||||
return new NeuralNetwork(BotNode.values());
|
return new NeuralNetwork(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public NodeConnections fetch(BotNode node) {
|
public NodeConnections fetch(BotNode node) {
|
||||||
@@ -34,33 +49,46 @@ public class NeuralNetwork {
|
|||||||
return nodes.get(node).check();
|
return nodes.get(node).check();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public double value(BotNode node) {
|
||||||
|
return nodes.get(node).value();
|
||||||
|
}
|
||||||
|
|
||||||
public void feed(BotData data) {
|
public void feed(BotData data) {
|
||||||
nodes.values().forEach(n -> n.test(data));
|
nodes.values().forEach(n -> n.test(data));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Map<BotNode, NodeConnections> nodes() {
|
||||||
|
return nodes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean dynamicLR() {
|
||||||
|
return dynamicLR;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<BotNode, Map<BotDataType, Double>> values() {
|
||||||
|
Map<BotNode, Map<BotDataType, Double>> output = new HashMap<>();
|
||||||
|
nodes.forEach((nodeType, node) -> output.put(nodeType, node.getValues()));
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
public String output() {
|
public String output() {
|
||||||
return generateString(false);
|
List<String> strings = new ArrayList<>();
|
||||||
|
nodes.forEach((type, node) -> strings.add(type.name().toLowerCase() + "=" + (node.check() ? StringUtilities.ON + "1" : StringUtilities.OFF + "0") + ChatColor.RESET));
|
||||||
|
Collections.sort(strings);
|
||||||
|
return "[" + StringUtils.join(strings, ", ") + "]";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return generateString(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
private String generateString(boolean values) {
|
|
||||||
List<String> strings = new ArrayList<>();
|
List<String> strings = new ArrayList<>();
|
||||||
|
|
||||||
if (values) {
|
nodes.forEach((nodeType, node) -> {
|
||||||
nodes.forEach((type, node) -> {
|
List<String> values = new ArrayList<>();
|
||||||
double value = node.value();
|
values.add("name=\"" + nodeType.name().toLowerCase() + "\"");
|
||||||
strings.add(type.name().toLowerCase() + "=" + (value >= 0.5 ? StringUtilities.ON : StringUtilities.OFF) + MathUtils.round2Dec(value) + ChatColor.RESET);
|
node.getValues().forEach((dataType, value) -> values.add(dataType.getShorthand() + "=" + MathUtils.round2Dec(value)));
|
||||||
});
|
strings.add("{" + StringUtils.join(values, ",") + "}");
|
||||||
} else {
|
});
|
||||||
nodes.forEach((type, node) -> strings.add(type.name().toLowerCase() + "=" + (node.check() ? StringUtilities.ON + "1" : StringUtilities.OFF + "0") + ChatColor.RESET));
|
|
||||||
}
|
|
||||||
|
|
||||||
Collections.sort(strings);
|
return "NeuralNetwork{nodes:[" + StringUtils.join(strings, ",") + "]}";
|
||||||
|
|
||||||
return "[" + StringUtils.join(strings, ", ") + "]";
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,6 +25,10 @@ public class NodeConnections {
|
|||||||
Arrays.stream(BotDataType.values()).forEach(type -> connections.put(type, generateValue()));
|
Arrays.stream(BotDataType.values()).forEach(type -> connections.put(type, generateValue()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public NodeConnections(Map<BotDataType, Double> values) {
|
||||||
|
this.connections = values;
|
||||||
|
}
|
||||||
|
|
||||||
private double generateValue() {
|
private double generateValue() {
|
||||||
return Math.random() * 20 - 10;
|
return Math.random() * 20 - 10;
|
||||||
}
|
}
|
||||||
@@ -37,6 +41,10 @@ public class NodeConnections {
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Map<BotDataType, Double> getValues() {
|
||||||
|
return connections;
|
||||||
|
}
|
||||||
|
|
||||||
public double getValue(BotDataType dataType) {
|
public double getValue(BotDataType dataType) {
|
||||||
return connections.get(dataType);
|
return connections.get(dataType);
|
||||||
}
|
}
|
||||||
|
|||||||
18
src/main/java/net/nuggetmc/ai/bot/event/BotDeathEvent.java
Normal file
18
src/main/java/net/nuggetmc/ai/bot/event/BotDeathEvent.java
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
package net.nuggetmc.ai.bot.event;
|
||||||
|
|
||||||
|
import net.nuggetmc.ai.bot.Bot;
|
||||||
|
import org.bukkit.event.entity.PlayerDeathEvent;
|
||||||
|
|
||||||
|
public class BotDeathEvent extends PlayerDeathEvent {
|
||||||
|
|
||||||
|
private final Bot bot;
|
||||||
|
|
||||||
|
public BotDeathEvent(PlayerDeathEvent event, Bot bot) {
|
||||||
|
super(event.getEntity(), event.getDrops(), event.getDroppedExp(), event.getDeathMessage());
|
||||||
|
this.bot = bot;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Bot getBot() {
|
||||||
|
return bot;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
package net.nuggetmc.ai.bot.event;
|
||||||
|
|
||||||
|
import net.nuggetmc.ai.bot.Bot;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
public class BotKilledByPlayerEvent {
|
||||||
|
|
||||||
|
// eventually also call this event for deaths from other damage causes within combat time
|
||||||
|
// (like hitting the ground too hard)
|
||||||
|
|
||||||
|
private final Bot bot;
|
||||||
|
private final Player player;
|
||||||
|
|
||||||
|
public BotKilledByPlayerEvent(Bot bot, Player player) {
|
||||||
|
this.bot = bot;
|
||||||
|
this.player = player;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Bot getBot() {
|
||||||
|
return bot;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Player getPlayer() {
|
||||||
|
return player;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -28,11 +28,13 @@ public class CommandHandler {
|
|||||||
|
|
||||||
private final DrinkCommandService drink;
|
private final DrinkCommandService drink;
|
||||||
private final Map<Class<? extends CommandInstance>, List<String>> help;
|
private final Map<Class<? extends CommandInstance>, List<String>> help;
|
||||||
|
private final Map<String, CommandInstance> commandMap;
|
||||||
|
|
||||||
public CommandHandler(TerminatorPlus plugin) {
|
public CommandHandler(TerminatorPlus plugin) {
|
||||||
this.plugin = plugin;
|
this.plugin = plugin;
|
||||||
this.drink = (DrinkCommandService) Drink.get(plugin);
|
this.drink = (DrinkCommandService) Drink.get(plugin);
|
||||||
this.help = new HashMap<>();
|
this.help = new HashMap<>();
|
||||||
|
this.commandMap = new HashMap<>();
|
||||||
this.registerCommands();
|
this.registerCommands();
|
||||||
this.drink.registerCommands();
|
this.drink.registerCommands();
|
||||||
}
|
}
|
||||||
@@ -45,10 +47,15 @@ public class CommandHandler {
|
|||||||
|
|
||||||
private void registerCommand(@Nonnull CommandInstance handler, @Nonnull String name, @Nullable String... aliases) {
|
private void registerCommand(@Nonnull CommandInstance handler, @Nonnull String name, @Nullable String... aliases) {
|
||||||
handler.setName(name);
|
handler.setName(name);
|
||||||
|
commandMap.put(name, handler);
|
||||||
drink.register(handler, MANAGE_PERMISSION, name, aliases);
|
drink.register(handler, MANAGE_PERMISSION, name, aliases);
|
||||||
setHelp(handler.getClass());
|
setHelp(handler.getClass());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public CommandInstance getComand(String name) {
|
||||||
|
return commandMap.get(name);
|
||||||
|
}
|
||||||
|
|
||||||
public void sendRootInfo(CommandInstance commandInstance, CommandSender sender) {
|
public void sendRootInfo(CommandInstance commandInstance, CommandSender sender) {
|
||||||
sender.sendMessage(ChatUtils.LINE);
|
sender.sendMessage(ChatUtils.LINE);
|
||||||
sender.sendMessage(ChatColor.GOLD + plugin.getName() + ChatUtils.BULLET_FORMATTED + ChatColor.GRAY
|
sender.sendMessage(ChatColor.GOLD + plugin.getName() + ChatUtils.BULLET_FORMATTED + ChatColor.GRAY
|
||||||
|
|||||||
@@ -3,25 +3,44 @@ package net.nuggetmc.ai.command.commands;
|
|||||||
import com.jonahseguin.drink.annotation.Command;
|
import com.jonahseguin.drink.annotation.Command;
|
||||||
import com.jonahseguin.drink.annotation.OptArg;
|
import com.jonahseguin.drink.annotation.OptArg;
|
||||||
import com.jonahseguin.drink.annotation.Sender;
|
import com.jonahseguin.drink.annotation.Sender;
|
||||||
|
import com.jonahseguin.drink.utils.ChatUtils;
|
||||||
import net.nuggetmc.ai.TerminatorPlus;
|
import net.nuggetmc.ai.TerminatorPlus;
|
||||||
|
import net.nuggetmc.ai.bot.Bot;
|
||||||
import net.nuggetmc.ai.bot.BotManager;
|
import net.nuggetmc.ai.bot.BotManager;
|
||||||
import net.nuggetmc.ai.bot.agent.Agent;
|
import net.nuggetmc.ai.bot.agent.legacyagent.ai.IntelligenceAgent;
|
||||||
import net.nuggetmc.ai.bot.agent.legacyagent.ai.NetworkType;
|
import net.nuggetmc.ai.bot.agent.legacyagent.ai.NeuralNetwork;
|
||||||
import net.nuggetmc.ai.command.CommandHandler;
|
import net.nuggetmc.ai.command.CommandHandler;
|
||||||
import net.nuggetmc.ai.command.CommandInstance;
|
import net.nuggetmc.ai.command.CommandInstance;
|
||||||
|
import net.nuggetmc.ai.utils.MathUtils;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.ChatColor;
|
||||||
import org.bukkit.command.CommandSender;
|
import org.bukkit.command.CommandSender;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.scheduler.BukkitScheduler;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
public class AICommand extends CommandInstance {
|
public class AICommand extends CommandInstance {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ideas
|
||||||
|
* ability to export neural network data to a text file, and also load from them
|
||||||
|
* maybe also have a custom extension like .tplus and encrypt it in base64
|
||||||
|
*/
|
||||||
|
|
||||||
|
private final TerminatorPlus plugin;
|
||||||
private final BotManager manager;
|
private final BotManager manager;
|
||||||
private final Agent agent;
|
private final BukkitScheduler scheduler;
|
||||||
|
|
||||||
|
private IntelligenceAgent agent;
|
||||||
|
|
||||||
public AICommand(CommandHandler commandHandler) {
|
public AICommand(CommandHandler commandHandler) {
|
||||||
super(commandHandler);
|
super(commandHandler);
|
||||||
|
|
||||||
this.manager = TerminatorPlus.getInstance().getManager();
|
this.plugin = TerminatorPlus.getInstance();
|
||||||
this.agent = manager.getAgent();
|
this.manager = plugin.getManager();
|
||||||
|
this.scheduler = Bukkit.getScheduler();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Command(
|
@Command(
|
||||||
@@ -37,6 +56,112 @@ public class AICommand extends CommandInstance {
|
|||||||
usage = "<amount> <name> [skin]"
|
usage = "<amount> <name> [skin]"
|
||||||
)
|
)
|
||||||
public void random(@Sender Player sender, int n, String name, @OptArg String skin) {
|
public void random(@Sender Player sender, int n, String name, @OptArg String skin) {
|
||||||
manager.createBots(sender, name, skin, n, NetworkType.RANDOM);
|
manager.createBots(sender, name, skin, n, NeuralNetwork.RANDOM);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Command(
|
||||||
|
name = "reinforcement",
|
||||||
|
desc = "Begin an AI training session.",
|
||||||
|
usage = "<population-size> <name> [skin]"
|
||||||
|
)
|
||||||
|
public void reinforcement(@Sender Player sender, int populationSize, String name, @OptArg String skin) {
|
||||||
|
// automatically do the -% thing, store values in map
|
||||||
|
// for now only 1 session at a time, have a set of commandsenders to see output, including console
|
||||||
|
// automatically reset all existing bots at the start, set targets towards each other
|
||||||
|
// also in the future make this a subcommand, with /ai reinforcement defaults, /ai reinforcement begin/start
|
||||||
|
// or just make /ai defaults with reinforcement options
|
||||||
|
|
||||||
|
if (agent != null) {
|
||||||
|
sender.sendMessage("A session is already active.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
sender.sendMessage("Starting a new session...");
|
||||||
|
|
||||||
|
agent = new IntelligenceAgent(this, populationSize, name, skin);
|
||||||
|
agent.addUser(sender);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Command(
|
||||||
|
name = "stop",
|
||||||
|
desc = "End a currently running AI training session."
|
||||||
|
)
|
||||||
|
public void stop(@Sender CommandSender sender) {
|
||||||
|
if (agent == null) {
|
||||||
|
sender.sendMessage("No session is currently active.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
sender.sendMessage("Stopping the current session...");
|
||||||
|
String name = agent.getName();
|
||||||
|
clearSession();
|
||||||
|
|
||||||
|
scheduler.runTaskLater(plugin, () -> sender.sendMessage("The session " + ChatColor.YELLOW + name + ChatColor.RESET + " has been closed."), 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clearSession() {
|
||||||
|
if (agent != null) {
|
||||||
|
agent.stop();
|
||||||
|
agent = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasActiveSession() {
|
||||||
|
return agent != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Command(
|
||||||
|
name = "info",
|
||||||
|
desc = "Display neural network information about a bot.",
|
||||||
|
usage = "<name>",
|
||||||
|
autofill = "infoAutofill"
|
||||||
|
)
|
||||||
|
public void info(@Sender CommandSender sender, String name) {
|
||||||
|
sender.sendMessage("Processing request...");
|
||||||
|
|
||||||
|
scheduler.runTaskAsynchronously(plugin, () -> {
|
||||||
|
try {
|
||||||
|
Bot bot = manager.getFirst(name);
|
||||||
|
|
||||||
|
if (bot == null) {
|
||||||
|
sender.sendMessage("Could not find bot " + ChatColor.GREEN + name + ChatColor.RESET + "!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!bot.hasNeuralNetwork()) {
|
||||||
|
sender.sendMessage("The bot " + ChatColor.GREEN + name + ChatColor.RESET + " does not have a neural network!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
NeuralNetwork network = bot.getNeuralNetwork();
|
||||||
|
List<String> strings = new ArrayList<>();
|
||||||
|
|
||||||
|
network.nodes().forEach((nodeType, node) -> {
|
||||||
|
strings.add("");
|
||||||
|
strings.add(ChatColor.YELLOW + "\"" + nodeType.name().toLowerCase() + "\"" + ChatColor.RESET + ":");
|
||||||
|
List<String> values = new ArrayList<>();
|
||||||
|
node.getValues().forEach((dataType, value) -> values.add(ChatUtils.BULLET_FORMATTED + "node"
|
||||||
|
+ dataType.getShorthand().toUpperCase() + ": " + ChatColor.RED + MathUtils.round2Dec(value)));
|
||||||
|
strings.addAll(values);
|
||||||
|
});
|
||||||
|
|
||||||
|
sender.sendMessage(ChatUtils.LINE);
|
||||||
|
sender.sendMessage(ChatColor.DARK_GREEN + "NeuralNetwork" + ChatUtils.BULLET_FORMATTED + ChatColor.GRAY + "[" + ChatColor.GREEN + name + ChatColor.GRAY + "]");
|
||||||
|
strings.forEach(sender::sendMessage);
|
||||||
|
sender.sendMessage(ChatUtils.LINE);
|
||||||
|
}
|
||||||
|
|
||||||
|
catch (Exception e) {
|
||||||
|
sender.sendMessage(ChatUtils.EXCEPTION_MESSAGE);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> infoAutofill(CommandSender sender, String[] args) {
|
||||||
|
if (args.length == 2) {
|
||||||
|
return manager.fetchNames();
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,6 +32,8 @@ public class BotCommand extends CommandInstance {
|
|||||||
private final BukkitScheduler scheduler;
|
private final BukkitScheduler scheduler;
|
||||||
private final DecimalFormat formatter;
|
private final DecimalFormat formatter;
|
||||||
|
|
||||||
|
private AICommand aiManager;
|
||||||
|
|
||||||
public BotCommand(CommandHandler commandHandler) {
|
public BotCommand(CommandHandler commandHandler) {
|
||||||
super(commandHandler);
|
super(commandHandler);
|
||||||
|
|
||||||
@@ -39,6 +41,8 @@ public class BotCommand extends CommandInstance {
|
|||||||
this.manager = plugin.getManager();
|
this.manager = plugin.getManager();
|
||||||
this.scheduler = Bukkit.getScheduler();
|
this.scheduler = Bukkit.getScheduler();
|
||||||
this.formatter = new DecimalFormat("0.##");
|
this.formatter = new DecimalFormat("0.##");
|
||||||
|
|
||||||
|
scheduler.runTask(plugin, () -> aiManager = (AICommand) plugin.getHandler().getComand("ai"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Command(
|
@Command(
|
||||||
@@ -69,7 +73,8 @@ public class BotCommand extends CommandInstance {
|
|||||||
@Command(
|
@Command(
|
||||||
name = "info",
|
name = "info",
|
||||||
desc = "Information about loaded bots.",
|
desc = "Information about loaded bots.",
|
||||||
usage = "[name]"
|
usage = "[name]",
|
||||||
|
autofill = "infoAutofill"
|
||||||
)
|
)
|
||||||
public void info(@Sender CommandSender sender, @OptArg String name) {
|
public void info(@Sender CommandSender sender, @OptArg String name) {
|
||||||
if (name == null) {
|
if (name == null) {
|
||||||
@@ -115,11 +120,19 @@ public class BotCommand extends CommandInstance {
|
|||||||
}
|
}
|
||||||
|
|
||||||
catch (Exception e) {
|
catch (Exception e) {
|
||||||
sender.sendMessage(ChatColor.RED + "An exception has occured. Please try again.");
|
sender.sendMessage(ChatUtils.EXCEPTION_MESSAGE);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<String> infoAutofill(CommandSender sender, String[] args) {
|
||||||
|
if (args.length == 2) {
|
||||||
|
return manager.fetchNames();
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Command(
|
@Command(
|
||||||
name = "reset",
|
name = "reset",
|
||||||
desc = "Remove all loaded bots."
|
desc = "Remove all loaded bots."
|
||||||
@@ -132,6 +145,10 @@ public class BotCommand extends CommandInstance {
|
|||||||
|
|
||||||
String formatted = NumberFormat.getNumberInstance(Locale.US).format(size);
|
String formatted = NumberFormat.getNumberInstance(Locale.US).format(size);
|
||||||
sender.sendMessage("Removed " + ChatColor.RED + formatted + ChatColor.RESET + " entit" + (size == 1 ? "y" : "ies") + ".");
|
sender.sendMessage("Removed " + ChatColor.RED + formatted + ChatColor.RESET + " entit" + (size == 1 ? "y" : "ies") + ".");
|
||||||
|
|
||||||
|
if (aiManager.hasActiveSession()) {
|
||||||
|
Bukkit.dispatchCommand(sender, "ai stop");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Command(
|
@Command(
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package net.nuggetmc.ai.utils;
|
package net.nuggetmc.ai.utils;
|
||||||
|
|
||||||
|
import net.minecraft.server.v1_16_R3.EntityLiving;
|
||||||
import net.nuggetmc.ai.TerminatorPlus;
|
import net.nuggetmc.ai.TerminatorPlus;
|
||||||
import net.nuggetmc.ai.bot.Bot;
|
import net.nuggetmc.ai.bot.Bot;
|
||||||
import net.nuggetmc.ai.bot.agent.Agent;
|
import net.nuggetmc.ai.bot.agent.Agent;
|
||||||
@@ -10,11 +11,13 @@ import org.bukkit.command.CommandSender;
|
|||||||
import org.bukkit.entity.ArmorStand;
|
import org.bukkit.entity.ArmorStand;
|
||||||
import org.bukkit.entity.EntityType;
|
import org.bukkit.entity.EntityType;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
import org.bukkit.permissions.ServerOperator;
|
import org.bukkit.permissions.ServerOperator;
|
||||||
import org.bukkit.util.Vector;
|
import org.bukkit.util.Vector;
|
||||||
|
|
||||||
import java.beans.Statement;
|
import java.beans.Statement;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
public class Debugger {
|
public class Debugger {
|
||||||
|
|
||||||
@@ -191,7 +194,7 @@ public class Debugger {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void item() {
|
public void item() {
|
||||||
TerminatorPlus.getInstance().getManager().fetch().forEach(b -> b.item = true);
|
TerminatorPlus.getInstance().getManager().fetch().forEach(b -> b.setDefaultItem(new ItemStack(Material.IRON_SWORD)));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void j(boolean b) {
|
public void j(boolean b) {
|
||||||
@@ -215,7 +218,7 @@ public class Debugger {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void tp() {
|
public void tp() {
|
||||||
Bot bot = MathUtils.getRandomSetElement(TerminatorPlus.getInstance().getManager().fetch());
|
Bot bot = MathUtils.getRandomSetElement(TerminatorPlus.getInstance().getManager().fetch().stream().filter(EntityLiving::isAlive).collect(Collectors.toSet()));
|
||||||
|
|
||||||
if (bot == null) {
|
if (bot == null) {
|
||||||
print("Failed to locate a bot.");
|
print("Failed to locate a bot.");
|
||||||
|
|||||||
59
src/main/java/net/nuggetmc/ai/utils/ItemUtils.java
Normal file
59
src/main/java/net/nuggetmc/ai/utils/ItemUtils.java
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
package net.nuggetmc.ai.utils;
|
||||||
|
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
|
||||||
|
public class ItemUtils {
|
||||||
|
|
||||||
|
public static double getLegacyAttackDamage(ItemStack item) {
|
||||||
|
switch (item.getType()) {
|
||||||
|
default:
|
||||||
|
return 0.25;
|
||||||
|
|
||||||
|
case WOODEN_SHOVEL:
|
||||||
|
case GOLDEN_SHOVEL:
|
||||||
|
case WOODEN_HOE:
|
||||||
|
case GOLDEN_HOE:
|
||||||
|
case STONE_HOE:
|
||||||
|
case IRON_HOE:
|
||||||
|
case DIAMOND_HOE:
|
||||||
|
case NETHERITE_HOE:
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
case WOODEN_PICKAXE:
|
||||||
|
case GOLDEN_PICKAXE:
|
||||||
|
case STONE_SHOVEL:
|
||||||
|
return 2;
|
||||||
|
|
||||||
|
case WOODEN_AXE:
|
||||||
|
case GOLDEN_AXE:
|
||||||
|
case STONE_PICKAXE:
|
||||||
|
case IRON_SHOVEL:
|
||||||
|
return 3;
|
||||||
|
|
||||||
|
case WOODEN_SWORD:
|
||||||
|
case GOLDEN_SWORD:
|
||||||
|
case STONE_AXE:
|
||||||
|
case IRON_PICKAXE:
|
||||||
|
case DIAMOND_SHOVEL:
|
||||||
|
return 4;
|
||||||
|
|
||||||
|
case STONE_SWORD:
|
||||||
|
case IRON_AXE:
|
||||||
|
case DIAMOND_PICKAXE:
|
||||||
|
case NETHERITE_SHOVEL:
|
||||||
|
return 5;
|
||||||
|
|
||||||
|
case IRON_SWORD:
|
||||||
|
case DIAMOND_AXE:
|
||||||
|
case NETHERITE_PICKAXE:
|
||||||
|
return 6;
|
||||||
|
|
||||||
|
case DIAMOND_SWORD:
|
||||||
|
case NETHERITE_AXE:
|
||||||
|
return 7;
|
||||||
|
|
||||||
|
case NETHERITE_SWORD:
|
||||||
|
return 8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,11 +1,12 @@
|
|||||||
package net.nuggetmc.ai.utils;
|
package net.nuggetmc.ai.utils;
|
||||||
|
|
||||||
|
import net.nuggetmc.ai.bot.Bot;
|
||||||
import org.bukkit.util.NumberConversions;
|
import org.bukkit.util.NumberConversions;
|
||||||
import org.bukkit.util.Vector;
|
import org.bukkit.util.Vector;
|
||||||
|
|
||||||
import java.text.DecimalFormat;
|
import java.text.DecimalFormat;
|
||||||
import java.util.Random;
|
import java.util.*;
|
||||||
import java.util.Set;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
public class MathUtils {
|
public class MathUtils {
|
||||||
|
|
||||||
@@ -90,4 +91,93 @@ public class MathUtils {
|
|||||||
public static String round2Dec(double n) {
|
public static String round2Dec(double n) {
|
||||||
return FORMATTER_2.format(n);
|
return FORMATTER_2.format(n);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static List<Map.Entry<Bot, Integer>> sortByValue(HashMap<Bot, Integer> hm) {
|
||||||
|
List<Map.Entry<Bot, Integer>> list = new LinkedList<>(hm.entrySet());
|
||||||
|
list.sort(Map.Entry.comparingByValue());
|
||||||
|
Collections.reverse(list);
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double generateConnectionValue(List<Double> list, double mutationSize) {
|
||||||
|
double[] bounds = getBounds(list, mutationSize);
|
||||||
|
return random(bounds[0], bounds[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double generateConnectionValue(List<Double> list) {
|
||||||
|
return generateConnectionValue(list, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double random(double low, double high) {
|
||||||
|
return Math.random() * (high - low) + low;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double sum(List<Double> list) {
|
||||||
|
return list.stream().mapToDouble(n -> n).sum();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double min(List<Double> list) {
|
||||||
|
if (list.isEmpty()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
double min = Double.MAX_VALUE;
|
||||||
|
|
||||||
|
for (double n : list) {
|
||||||
|
if (n < min) {
|
||||||
|
min = n;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return min;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double max(List<Double> list) {
|
||||||
|
if (list.isEmpty()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
double max = 0;
|
||||||
|
|
||||||
|
for (double n : list) {
|
||||||
|
if (n > max) {
|
||||||
|
max = n;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return max;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double getMidValue(List<Double> list) {
|
||||||
|
return (min(list) + max(list)) / 2D;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double distribution(List<Double> list, double mid) {
|
||||||
|
return Math.sqrt(sum(list.stream().map(n -> Math.pow(n - mid, 2)).collect(Collectors.toList())) / list.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double[] getBounds(List<Double> list, double mutationSize) {
|
||||||
|
double mid = getMidValue(list);
|
||||||
|
double dist = distribution(list, mid);
|
||||||
|
double p = mutationSize * dist / Math.sqrt(list.size());
|
||||||
|
|
||||||
|
return new double[] {
|
||||||
|
mid - p,
|
||||||
|
mid + p
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double getMutationSize(int generation) {
|
||||||
|
int shift = 4;
|
||||||
|
|
||||||
|
if (generation <= shift + 1) {
|
||||||
|
return 7.38905609893;
|
||||||
|
}
|
||||||
|
|
||||||
|
double a = 0.8;
|
||||||
|
double b = -8.5 - shift;
|
||||||
|
double c = 2;
|
||||||
|
|
||||||
|
return Math.pow(a, generation + b) + c;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package net.nuggetmc.ai.utils;
|
|||||||
|
|
||||||
import net.nuggetmc.ai.TerminatorPlus;
|
import net.nuggetmc.ai.TerminatorPlus;
|
||||||
import org.bukkit.GameMode;
|
import org.bukkit.GameMode;
|
||||||
|
import org.bukkit.Location;
|
||||||
import org.json.simple.JSONArray;
|
import org.json.simple.JSONArray;
|
||||||
import org.json.simple.JSONObject;
|
import org.json.simple.JSONObject;
|
||||||
import org.json.simple.parser.JSONParser;
|
import org.json.simple.parser.JSONParser;
|
||||||
@@ -49,4 +50,21 @@ public class PlayerUtils {
|
|||||||
Debugger.log("Failed to fetch from the usercache.");
|
Debugger.log("Failed to fetch from the usercache.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Location findAbove(Location loc, int amount) {
|
||||||
|
boolean check = false;
|
||||||
|
|
||||||
|
for (int i = 0; i <= amount; i++) {
|
||||||
|
if (loc.clone().add(0, i, 0).getBlock().getType().isSolid()) {
|
||||||
|
check = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (check) {
|
||||||
|
return loc;
|
||||||
|
} else {
|
||||||
|
return loc.clone().add(0, amount, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user