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

@@ -13,6 +13,7 @@ public class TerminatorPlus extends JavaPlugin {
private static String version;
private BotManager manager;
private CommandHandler handler;
public static TerminatorPlus getInstance() {
return instance;
@@ -26,6 +27,10 @@ public class TerminatorPlus extends JavaPlugin {
return manager;
}
public CommandHandler getHandler() {
return handler;
}
@Override
public void onEnable() {
instance = this;
@@ -33,7 +38,7 @@ public class TerminatorPlus extends JavaPlugin {
// Create Instances
this.manager = new BotManager();
new CommandHandler(this);
this.handler = new CommandHandler(this);
// Register event listeners
this.registerEvents(manager);

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

View File

@@ -28,11 +28,13 @@ public class CommandHandler {
private final DrinkCommandService drink;
private final Map<Class<? extends CommandInstance>, List<String>> help;
private final Map<String, CommandInstance> commandMap;
public CommandHandler(TerminatorPlus plugin) {
this.plugin = plugin;
this.drink = (DrinkCommandService) Drink.get(plugin);
this.help = new HashMap<>();
this.commandMap = new HashMap<>();
this.registerCommands();
this.drink.registerCommands();
}
@@ -45,10 +47,15 @@ public class CommandHandler {
private void registerCommand(@Nonnull CommandInstance handler, @Nonnull String name, @Nullable String... aliases) {
handler.setName(name);
commandMap.put(name, handler);
drink.register(handler, MANAGE_PERMISSION, name, aliases);
setHelp(handler.getClass());
}
public CommandInstance getComand(String name) {
return commandMap.get(name);
}
public void sendRootInfo(CommandInstance commandInstance, CommandSender sender) {
sender.sendMessage(ChatUtils.LINE);
sender.sendMessage(ChatColor.GOLD + plugin.getName() + ChatUtils.BULLET_FORMATTED + ChatColor.GRAY

View File

@@ -3,25 +3,44 @@ package net.nuggetmc.ai.command.commands;
import com.jonahseguin.drink.annotation.Command;
import com.jonahseguin.drink.annotation.OptArg;
import com.jonahseguin.drink.annotation.Sender;
import com.jonahseguin.drink.utils.ChatUtils;
import net.nuggetmc.ai.TerminatorPlus;
import net.nuggetmc.ai.bot.Bot;
import net.nuggetmc.ai.bot.BotManager;
import net.nuggetmc.ai.bot.agent.Agent;
import net.nuggetmc.ai.bot.agent.legacyagent.ai.NetworkType;
import net.nuggetmc.ai.bot.agent.legacyagent.ai.IntelligenceAgent;
import net.nuggetmc.ai.bot.agent.legacyagent.ai.NeuralNetwork;
import net.nuggetmc.ai.command.CommandHandler;
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.entity.Player;
import org.bukkit.scheduler.BukkitScheduler;
import java.util.ArrayList;
import java.util.List;
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 Agent agent;
private final BukkitScheduler scheduler;
private IntelligenceAgent agent;
public AICommand(CommandHandler commandHandler) {
super(commandHandler);
this.manager = TerminatorPlus.getInstance().getManager();
this.agent = manager.getAgent();
this.plugin = TerminatorPlus.getInstance();
this.manager = plugin.getManager();
this.scheduler = Bukkit.getScheduler();
}
@Command(
@@ -37,6 +56,112 @@ public class AICommand extends CommandInstance {
usage = "<amount> <name> [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;
}
}
}

View File

@@ -32,6 +32,8 @@ public class BotCommand extends CommandInstance {
private final BukkitScheduler scheduler;
private final DecimalFormat formatter;
private AICommand aiManager;
public BotCommand(CommandHandler commandHandler) {
super(commandHandler);
@@ -39,6 +41,8 @@ public class BotCommand extends CommandInstance {
this.manager = plugin.getManager();
this.scheduler = Bukkit.getScheduler();
this.formatter = new DecimalFormat("0.##");
scheduler.runTask(plugin, () -> aiManager = (AICommand) plugin.getHandler().getComand("ai"));
}
@Command(
@@ -69,7 +73,8 @@ public class BotCommand extends CommandInstance {
@Command(
name = "info",
desc = "Information about loaded bots.",
usage = "[name]"
usage = "[name]",
autofill = "infoAutofill"
)
public void info(@Sender CommandSender sender, @OptArg String name) {
if (name == null) {
@@ -115,11 +120,19 @@ public class BotCommand extends CommandInstance {
}
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(
name = "reset",
desc = "Remove all loaded bots."
@@ -132,6 +145,10 @@ public class BotCommand extends CommandInstance {
String formatted = NumberFormat.getNumberInstance(Locale.US).format(size);
sender.sendMessage("Removed " + ChatColor.RED + formatted + ChatColor.RESET + " entit" + (size == 1 ? "y" : "ies") + ".");
if (aiManager.hasActiveSession()) {
Bukkit.dispatchCommand(sender, "ai stop");
}
}
@Command(

View File

@@ -1,5 +1,6 @@
package net.nuggetmc.ai.utils;
import net.minecraft.server.v1_16_R3.EntityLiving;
import net.nuggetmc.ai.TerminatorPlus;
import net.nuggetmc.ai.bot.Bot;
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.EntityType;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.permissions.ServerOperator;
import org.bukkit.util.Vector;
import java.beans.Statement;
import java.util.*;
import java.util.stream.Collectors;
public class Debugger {
@@ -191,7 +194,7 @@ public class Debugger {
}
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) {
@@ -215,7 +218,7 @@ public class Debugger {
}
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) {
print("Failed to locate a bot.");

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

View File

@@ -1,11 +1,12 @@
package net.nuggetmc.ai.utils;
import net.nuggetmc.ai.bot.Bot;
import org.bukkit.util.NumberConversions;
import org.bukkit.util.Vector;
import java.text.DecimalFormat;
import java.util.Random;
import java.util.Set;
import java.util.*;
import java.util.stream.Collectors;
public class MathUtils {
@@ -90,4 +91,93 @@ public class MathUtils {
public static String round2Dec(double 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;
}
}

View File

@@ -2,6 +2,7 @@ package net.nuggetmc.ai.utils;
import net.nuggetmc.ai.TerminatorPlus;
import org.bukkit.GameMode;
import org.bukkit.Location;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
@@ -49,4 +50,21 @@ public class PlayerUtils {
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);
}
}
}