intelligence pvp thing done

This commit is contained in:
batchprogrammer314
2021-07-24 23:34:07 -05:00
parent 8dc4dcf8c9
commit d86a42eab6
22 changed files with 1045 additions and 117 deletions

View File

@@ -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.*;
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.event.BotDamageByPlayerEvent;
import net.nuggetmc.ai.bot.event.BotFallDamageEvent;
import net.nuggetmc.ai.bot.event.BotKilledByPlayerEvent;
import net.nuggetmc.ai.utils.*;
import org.bukkit.Material;
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.entity.Damageable;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.scheduler.BukkitScheduler;
import org.bukkit.util.Vector;
@@ -33,6 +36,7 @@ public class Bot extends EntityPlayer {
private final TerminatorPlus plugin;
private final BukkitScheduler scheduler;
private final Agent agent;
private NeuralNetwork network;
@@ -48,7 +52,7 @@ public class Bot extends EntityPlayer {
return network != null;
}
public boolean item; // eventually make this not garbage lol
public ItemStack defaultItem;
private boolean shield;
private boolean blocking;
@@ -57,9 +61,11 @@ public class Bot extends EntityPlayer {
private Vector velocity;
private Vector oldVelocity;
private final boolean removeOnDeath;
private boolean removeOnDeath;
private int aliveTicks;
private int kills;
private byte aliveTicks;
private byte fireTicks;
private byte groundTicks;
private byte jumpTicks;
@@ -72,6 +78,8 @@ public class Bot extends EntityPlayer {
this.plugin = TerminatorPlus.getInstance();
this.scheduler = Bukkit.getScheduler();
this.agent = plugin.getManager().getAgent();
this.defaultItem = new ItemStack(Material.AIR);
this.velocity = new Vector(0, 0, 0);
this.oldVelocity = velocity.clone();
this.noFallTicks = 60;
@@ -139,6 +147,10 @@ public class Bot extends EntityPlayer {
};
}
public void setDefaultItem(ItemStack item) {
this.defaultItem = item;
}
public Vector getOffset() {
return offset;
}
@@ -160,6 +172,10 @@ public class Bot extends EntityPlayer {
velocity.add(vector);
}
public int getAliveTicks() {
return aliveTicks;
}
public boolean tickDelay(int i) {
return aliveTicks % i == 0;
}
@@ -385,7 +401,7 @@ public class Bot extends EntityPlayer {
punch();
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);
}
public void despawn() {
getBukkitEntity().remove();
}
public void removeVisually() {
this.removeTab();
this.setDead();
@@ -455,6 +467,10 @@ public class Bot extends EntityPlayer {
sendPacket(new PacketPlayOutPlayerInfo(PacketPlayOutPlayerInfo.EnumPlayerInfoAction.REMOVE_PLAYER, this));
}
public void setRemoveOnDeath(boolean enabled) {
this.removeOnDeath = enabled;
}
private void setDead() {
this.dead = true;
this.defaultContainer.b(this);
@@ -523,11 +539,16 @@ public class Bot extends EntityPlayer {
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()) {
return false;
@@ -535,6 +556,7 @@ public class Bot extends EntityPlayer {
damage = event.getDamage();
} else {
killer = null;
damage = f;
}
@@ -545,6 +567,10 @@ public class Bot extends EntityPlayer {
}
if (damaged && attacker != null) {
if (playerInstance && !isAlive()) {
agent.onBotKilledByPlayer(new BotKilledByPlayerEvent(this, killer));
}
kb(getLocation(), attacker.getBukkitEntity().getLocation());
}
@@ -559,6 +585,14 @@ public class Bot extends EntityPlayer {
velocity = vel;
}
public int getKills() {
return kills;
}
public void incrementKills() {
kills++;
}
public Location getLocation() {
return getBukkitEntity().getLocation();
}
@@ -615,8 +649,8 @@ public class Bot extends EntityPlayer {
setItem(item, EnumItemSlot.OFFHAND);
}
public 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);
private void setItem(org.bukkit.inventory.ItemStack item, EnumItemSlot slot) {
if (item == null) item = defaultItem;
if (slot == EnumItemSlot.MAINHAND) {
getBukkitEntity().getInventory().setItemInMainHand(item);

View File

@@ -3,22 +3,22 @@ package net.nuggetmc.ai.bot;
import net.minecraft.server.v1_16_R3.PlayerConnection;
import net.nuggetmc.ai.bot.agent.Agent;
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.event.BotDeathEvent;
import net.nuggetmc.ai.utils.MojangAPI;
import org.bukkit.*;
import org.bukkit.craftbukkit.v1_16_R3.entity.CraftPlayer;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
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.inventory.ItemStack;
import org.bukkit.util.Vector;
import java.text.NumberFormat;
import java.util.HashSet;
import java.util.Locale;
import java.util.Set;
import java.util.*;
import java.util.stream.Collectors;
public class BotManager implements Listener {
@@ -27,7 +27,6 @@ public class BotManager implements Listener {
private final NumberFormat numberFormat;
public boolean joinMessages = false;
public boolean removeOnDeath = true;
public BotManager() {
this.agent = new LegacyAgent(this);
@@ -57,6 +56,10 @@ public class BotManager implements Listener {
return null;
}
public List<String> fetchNames() {
return bots.stream().map(Bot::getName).collect(Collectors.toList());
}
public Agent getAgent() {
return agent;
}
@@ -65,44 +68,73 @@ public class BotManager implements Listener {
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();
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")
+ " 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)
+ ChatColor.RESET + "...");
skinName = skinName == null ? name : skinName;
double f = n < 100 ? .004 * n : .4;
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);
createBots(sender.getLocation(), name, MojangAPI.getSkin(skinName), n, network);
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) {
bots.remove(bot);
}
@@ -111,6 +143,23 @@ public class BotManager implements Listener {
bots.forEach(Bot::removeVisually);
bots.clear(); // Not always necessary, but a good security measure
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
@@ -120,11 +169,12 @@ public class BotManager implements Listener {
}
@EventHandler
public void onEntityDamage(EntityDamageByEntityEvent event) {
if (!(event.getEntity() instanceof Player)) return;
if (!(event.getDamager() instanceof Player)) return;
public void onDeath(PlayerDeathEvent event) {
Player player = event.getEntity();
Bot bot = getBot(player);
Player player = (Player) event.getEntity();
Player damager = (Player) event.getDamager();
if (bot != null) {
agent.onBotDeath(new BotDeathEvent(event, bot));
}
}
}

View File

@@ -1,10 +1,14 @@
package net.nuggetmc.ai.bot.agent;
import net.nuggetmc.ai.TerminatorPlus;
import net.nuggetmc.ai.bot.Bot;
import net.nuggetmc.ai.bot.BotManager;
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.BotKilledByPlayerEvent;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.scheduler.BukkitRunnable;
import org.bukkit.scheduler.BukkitScheduler;
@@ -23,6 +27,8 @@ public abstract class Agent {
protected boolean enabled;
protected int taskID;
protected boolean drops;
public Agent(BotManager manager) {
this.plugin = TerminatorPlus.getInstance();
this.manager = manager;
@@ -53,9 +59,27 @@ public abstract class Agent {
taskList.clear();
}
public void setDrops(boolean enabled) {
this.drops = enabled;
}
protected abstract void tick();
public void onFallDamage(BotFallDamageEvent 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();
}
});
}
}

View File

@@ -5,6 +5,7 @@ public enum EnumTargetGoal { // TODO USE ORDINAL!!!!!
NEAREST_REAL_PLAYER,
NEAREST_BOT_DIFFER,
NEAREST_BOT,
NEAREST_BOT_DIFFER_ALPHA,
NONE;
public static EnumTargetGoal of(int n) {
@@ -23,6 +24,9 @@ public enum EnumTargetGoal { // TODO USE ORDINAL!!!!!
case 4:
return NEAREST_BOT;
case 5:
return NEAREST_BOT_DIFFER_ALPHA;
}
}
}

View File

@@ -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.NeuralNetwork;
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.BotKilledByPlayerEvent;
import net.nuggetmc.ai.utils.MathUtils;
import net.nuggetmc.ai.utils.PlayerUtils;
import org.bukkit.*;
@@ -234,30 +236,58 @@ public class LegacyAgent extends Agent {
if (ai) {
NeuralNetwork network = bot.getNeuralNetwork();
boolean left = network.check(BotNode.LEFT);
boolean right = network.check(BotNode.RIGHT);
if (network.dynamicLR()) {
if (bot.isBlocking()) {
vel.multiply(0.6);
}
if (bot.isBlocking()) {
vel.multiply(0.6);
if (distance <= 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) {
if (left) {
vel.rotateAroundY(Math.PI / 4);
else {
boolean left = network.check(BotNode.LEFT);
boolean right = network.check(BotNode.RIGHT);
if (bot.isBlocking()) {
vel.multiply(0.6);
}
if (right) {
vel.rotateAroundY(-Math.PI / 4);
}
if (left != right && distance <= 6) {
if (network.check(BotNode.JUMP)) {
bot.jump(vel);
} else {
bot.walk(vel.clone().setY(0));
scheduler.runTaskLater(plugin, () -> bot.jump(vel), 10);
}
if (left) {
vel.rotateAroundY(Math.PI / 4);
}
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
public void onPlayerDamage(BotDamageByPlayerEvent event) {
Bot bot = event.getBot();
@@ -1023,9 +1060,9 @@ public class LegacyAgent extends Agent {
Vector vector = targetLoc.toVector().subtract(bot.getLocation().toVector()).normalize();
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();
move.multiply(0.75);
move.multiply(0.5);
move.setY(0.42);
bot.setVelocity(move);
@@ -1104,6 +1141,9 @@ public class LegacyAgent extends Agent {
case NEAREST_BOT_DIFFER:
return nearestBotDiffer(bot, loc);
case NEAREST_BOT_DIFFER_ALPHA:
return nearestBotDifferAlpha(bot, loc);
case NEAREST_BOT:
return nearestBot(bot, loc);
@@ -1116,7 +1156,7 @@ public class LegacyAgent extends Agent {
Player result = null;
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())) {
result = player;
@@ -1130,7 +1170,7 @@ public class LegacyAgent extends Agent {
Player result = null;
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())) {
result = player;
@@ -1148,7 +1188,7 @@ public class LegacyAgent extends Agent {
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())) {
result = player;
@@ -1167,7 +1207,27 @@ public class LegacyAgent extends Agent {
Player player = otherBot.getBukkitEntity();
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())) {
result = player;

View File

@@ -2,6 +2,7 @@ package net.nuggetmc.ai.bot.agent.legacyagent;
import net.nuggetmc.ai.TerminatorPlus;
import net.nuggetmc.ai.bot.Bot;
import net.nuggetmc.ai.utils.Debugger;
import org.bukkit.*;
import org.bukkit.block.Block;
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);
bot.setItem(new ItemStack(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, () -> {
placeFinal(bot, player, block.getLocation());
}, 2);
}/* else {
placeFinal(player, block.getLocation());
return;
}*/
}
Set<Block> face = new HashSet<>(Arrays.asList(loc.clone().add(1, 0, 0).getBlock(),
loc.clone().add(-1, 0, 0).getBlock(),

View File

@@ -0,0 +1,9 @@
package net.nuggetmc.ai.bot.agent.legacyagent.ai;
public enum ActivationType {
TANH,
SIN_X,
SIN_X2,
COS_X,
COS_X2
}

View File

@@ -1,8 +1,18 @@
package net.nuggetmc.ai.bot.agent.legacyagent.ai;
public enum BotDataType {
CRITICAL_HEALTH,
DISTANCE_XZ,
DISTANCE_Y,
ENEMY_BLOCKING
CRITICAL_HEALTH("h"),
DISTANCE_XZ("xz"),
DISTANCE_Y("y"),
ENEMY_BLOCKING("b");
private final String shorthand;
BotDataType(String shorthand) {
this.shorthand = shorthand;
}
public String getShorthand() {
return shorthand;
}
}

View File

@@ -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();
}
}

View File

@@ -1,5 +0,0 @@
package net.nuggetmc.ai.bot.agent.legacyagent.ai;
public enum NetworkType {
RANDOM
}

View File

@@ -14,16 +14,31 @@ public class NeuralNetwork {
// randomize the blocking length and cooldown
// 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 NeuralNetwork(BotNode... nodes) {
this.nodes = new HashMap<>();
private final boolean dynamicLR;
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() {
return new NeuralNetwork(BotNode.values());
return new NeuralNetwork(null);
}
public NodeConnections fetch(BotNode node) {
@@ -34,33 +49,46 @@ public class NeuralNetwork {
return nodes.get(node).check();
}
public double value(BotNode node) {
return nodes.get(node).value();
}
public void feed(BotData 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() {
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
public String toString() {
return generateString(true);
}
private String generateString(boolean values) {
List<String> strings = new ArrayList<>();
if (values) {
nodes.forEach((type, node) -> {
double value = node.value();
strings.add(type.name().toLowerCase() + "=" + (value >= 0.5 ? StringUtilities.ON : StringUtilities.OFF) + MathUtils.round2Dec(value) + ChatColor.RESET);
});
} else {
nodes.forEach((type, node) -> strings.add(type.name().toLowerCase() + "=" + (node.check() ? StringUtilities.ON + "1" : StringUtilities.OFF + "0") + ChatColor.RESET));
}
nodes.forEach((nodeType, node) -> {
List<String> values = new ArrayList<>();
values.add("name=\"" + nodeType.name().toLowerCase() + "\"");
node.getValues().forEach((dataType, value) -> values.add(dataType.getShorthand() + "=" + MathUtils.round2Dec(value)));
strings.add("{" + StringUtils.join(values, ",") + "}");
});
Collections.sort(strings);
return "[" + StringUtils.join(strings, ", ") + "]";
return "NeuralNetwork{nodes:[" + StringUtils.join(strings, ",") + "]}";
}
}

View File

@@ -25,6 +25,10 @@ public class NodeConnections {
Arrays.stream(BotDataType.values()).forEach(type -> connections.put(type, generateValue()));
}
public NodeConnections(Map<BotDataType, Double> values) {
this.connections = values;
}
private double generateValue() {
return Math.random() * 20 - 10;
}
@@ -37,6 +41,10 @@ public class NodeConnections {
return value;
}
public Map<BotDataType, Double> getValues() {
return connections;
}
public double getValue(BotDataType dataType) {
return connections.get(dataType);
}

View 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;
}
}

View File

@@ -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;
}
}