Skip to content

Commit

Permalink
Merge branch 'release/v1.1.0'
Browse files Browse the repository at this point in the history
  • Loading branch information
jdonkervliet committed Oct 6, 2021
2 parents 2f21e3c + d09d702 commit f48866e
Show file tree
Hide file tree
Showing 7 changed files with 390 additions and 14 deletions.
2 changes: 1 addition & 1 deletion yardstick/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>nl.tudelft</groupId>
<artifactId>yardstick</artifactId>
<version>1.0.2</version>
<version>1.1.0</version>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,15 @@
import java.util.Scanner;
import java.util.logging.Level;
import nl.tudelft.opencraft.yardstick.experiment.Experiment;
import nl.tudelft.opencraft.yardstick.experiment.Experiment10GenerationStressTest;
import nl.tudelft.opencraft.yardstick.experiment.Experiment1SimpleJoin;
import nl.tudelft.opencraft.yardstick.experiment.Experiment2ScheduledJoin;
import nl.tudelft.opencraft.yardstick.experiment.Experiment3WalkAround;
import nl.tudelft.opencraft.yardstick.experiment.Experiment4MultiWalkAround;
import nl.tudelft.opencraft.yardstick.experiment.Experiment5SimpleWalk;
import nl.tudelft.opencraft.yardstick.experiment.Experiment6InteractWalk;
import nl.tudelft.opencraft.yardstick.experiment.Experiment8BoxWalkAround;
import nl.tudelft.opencraft.yardstick.experiment.Experiment9Spike;
import nl.tudelft.opencraft.yardstick.experiment.RemoteControlledExperiment;
import nl.tudelft.opencraft.yardstick.logging.GlobalLogger;
import nl.tudelft.opencraft.yardstick.logging.SimpleTimeFormatter;
Expand Down Expand Up @@ -163,6 +165,12 @@ public static void main(String[] args) {
case 8:
ex = new Experiment8BoxWalkAround();
break;
case 9:
ex = new Experiment9Spike();
break;
case 10:
ex = new Experiment10GenerationStressTest();
break;
default:
System.out.println("Invalid experiment: " + OPTIONS.experiment);
return;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,11 +69,21 @@ public class Bot {
* @param port the port of the Minecraft server.
*/
public Bot(MinecraftProtocol protocol, String host, int port) {
this(protocol, new Client(host, port, protocol, new TcpSessionFactory(true)));
}

/**
* Creates a new bot with the given {@link MinecraftProtocol} and {@link Client}.
*
* @param protocol the protocol.
* @param client the Minecraft client.
*/
public Bot(MinecraftProtocol protocol, Client client) {
this.name = protocol.getProfile().getName();
this.logger = GlobalLogger.getLogger().newSubLogger("Bot").newSubLogger(name);
this.protocol = protocol;
this.ticker = new BotTicker(this);
this.client = new Client(host, port, protocol, new TcpSessionFactory(true));
this.client = client;
this.client.getSession().addListener(new BotListener(this));
this.controller = new BotController(this);

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
package nl.tudelft.opencraft.yardstick.bot.ai.task;

import nl.tudelft.opencraft.yardstick.bot.Bot;
import nl.tudelft.opencraft.yardstick.bot.world.ChunkNotLoadedException;
import nl.tudelft.opencraft.yardstick.util.Vector3d;
import nl.tudelft.opencraft.yardstick.util.Vector3i;

/**
* In order to avoid obstacles, the bot first flies to the maximum altitude,
* then flies to the target (X, Z) coordinates, then descends to meet the Y target
*/
public class FlyTaskExecutor extends AbstractTaskExecutor {

public static final int maxY = 150;
private static final double speedY = 1;
private final double speedXZ;

private Vector3i target;

public FlyTaskExecutor(final Bot bot, Vector3i targetLocation, double speed) {
super(bot);

this.target = targetLocation;
if (bot.getPlayer().getLocation().intVector().equals(target)) {
logger.warning("Useless fly task. Bot and given target location equal.");
}

speedXZ = speed;
}

@Override
protected TaskStatus onTick() {
// todo: perform additional checks for flying into objects

Vector3d nextLocation = bot.getPlayer().getLocation();
Vector3i currentLocation = nextLocation.intVector();
int currX = currentLocation.getX(), currZ = currentLocation.getZ();

// check we have arrived
if (currentLocation.equals(target)) {
return TaskStatus.forSuccess();
}

// check if we have to descend
if (currX == target.getX() && currZ == target.getZ()) {
try {
int highestY = bot.getWorld().getHighestBlockAt(currX, currZ).getY();
// check we can actually descend; if not, change target
if (highestY > target.getY()) {
target = new Vector3i(currX, highestY, currZ);
}
} catch (ChunkNotLoadedException ex) {
return TaskStatus.forFailure(String.format("Chunk that contains block %s not loaded", currentLocation));
}

double toDescend = -Math.min(nextLocation.getY() - (double) target.getY(), speedY);
nextLocation = nextLocation.add(0, toDescend, 0);
} else if (currentLocation.getY() < maxY) {
// we have to ascend
double toAscend = Math.min((double) maxY - nextLocation.getY(), speedY);
nextLocation = nextLocation.add(0, toAscend, 0);
} else {
// calculate delta movement
double diffX = Math.abs((double) target.getX() - nextLocation.getX());
double diffZ = Math.abs((double) target.getZ() - nextLocation.getZ());
double moveX = Math.min(diffX, speedXZ);
double moveZ = Math.min(diffZ, speedXZ);

// adjust for angle
if (diffX < diffZ) {
moveX *= diffX / diffZ;
} else {
moveZ *= diffZ / diffX;
}

// account for direction
if (target.getX() < nextLocation.getX()) moveX *= -1;
if (target.getZ() < nextLocation.getZ()) moveZ *= -1;

nextLocation = nextLocation.add(moveX, 0, moveZ);
}

// report location to server
bot.getController().updateLocation(nextLocation);
return TaskStatus.forInProgress();
}

@Override
protected void onStop() {}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
package nl.tudelft.opencraft.yardstick.experiment;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import java.util.stream.Collectors;
import nl.tudelft.opencraft.yardstick.bot.Bot;
import nl.tudelft.opencraft.yardstick.bot.ai.task.FlyTaskExecutor;
import nl.tudelft.opencraft.yardstick.bot.ai.task.TaskExecutor;
import nl.tudelft.opencraft.yardstick.bot.ai.task.TaskStatus;
import nl.tudelft.opencraft.yardstick.util.Vector3i;

public class Experiment10GenerationStressTest extends Experiment {

private final List<Bot> botList = Collections.synchronizedList(new ArrayList<>());
private final Set<Bot> targetSet = Collections.synchronizedSet(new HashSet<>());

private double angle = 0;
private double increment;
private double targetDistance;
private double botSpeed;

private long startMillis;
private int durationInSeconds;
private int delay;

public Experiment10GenerationStressTest() {
super(9, "Bots move away from the spawn location");
}

@Override
protected void before() {
int botsTotal = Integer.parseInt(options.experimentParams.get("bots"));
this.durationInSeconds = Integer.parseInt(options.experimentParams.getOrDefault("duration", "600"));
this.delay = Integer.parseInt(options.experimentParams.getOrDefault("delay", "0")) * 1000;
this.botSpeed = Double.parseDouble(options.experimentParams.getOrDefault("speed", "0.3"));
this.startMillis = System.currentTimeMillis();
this.increment = 2 * Math.PI / botsTotal;
this.targetDistance = ((int) (1000 / TICK_MS) * durationInSeconds) * botSpeed;

// connect the bots; todo: synchronized?
for (int i = 0; i < botsTotal; i++) {
Bot bot = createBot();
Thread connector = new Thread(newBotConnector(bot));
connector.setName("Connector-" + bot.getName());
connector.setDaemon(false);
connector.start();
botList.add(bot);
}
}

@Override
protected void tick() {
if (System.currentTimeMillis() - startMillis < delay) {
return;
}

synchronized (botList) {
List<Bot> disconnectedBots = botList.stream()
.filter(Bot::hasBeenDisconnected)
.collect(Collectors.toList());
disconnectedBots.forEach(bot -> bot.disconnect("Bot is not connected"));
if (disconnectedBots.size() > 0) {
logger.warning("Bots disconnected: "
+ disconnectedBots.stream().map(Bot::getName).reduce("", (a, b) -> a + ", " + b));
botList.removeAll(disconnectedBots);
}
}

synchronized (botList) {
for (Bot bot : botList) {
botTick(bot);
}
}
}

private void botTick(Bot bot) {
if (!bot.isJoined()) {
return;
}

// calculate bot target location if not already done
if (!targetSet.contains(bot)) {
// calculate target
Vector3i startLocation = bot.getPlayer().getLocation().intVector();
int finalX = (int) Math.floor(targetDistance * Math.cos(angle)) + startLocation.getX();
int finalZ = (int) Math.floor(targetDistance * Math.sin(angle)) + startLocation.getZ();
angle += increment;
Vector3i botTarget = new Vector3i(finalX, FlyTaskExecutor.maxY, finalZ);

// move bot towards target
bot.getLogger().info(String.format("Moving bot towards final target (%d, %d)", finalX, finalZ));
bot.setTaskExecutor(new FlyTaskExecutor(bot, botTarget, botSpeed));
targetSet.add(bot);
}

// disconnect bot if arrived
TaskExecutor t = bot.getTaskExecutor();
if (t == null || t.getStatus().getType() != TaskStatus.StatusType.IN_PROGRESS) {
bot.disconnect("Arrived at destination");
}
}

private Runnable newBotConnector(Bot bot) {
return () -> {
bot.connect();
int sleep = 1000;
int tries = 3;
while (tries-- > 0 && (bot.getPlayer() == null || !bot.isJoined())) {
try {
Thread.sleep(sleep);
} catch (InterruptedException e) {
e.printStackTrace();
break;
}
}
if (!bot.isJoined()) {
logger.warning(String.format("Could not connect bot %s:%d.", options.host, options.port));
bot.disconnect("Make sure to close all connections.");
}
};
}

@Override
protected Bot createBot() {
return newBot(UUID.randomUUID().toString().substring(0, 6));
}

@Override
protected boolean isDone() {
boolean timeUp = System.currentTimeMillis() - this.startMillis > this.durationInSeconds * 1_000;
if (timeUp) {
return true;
} else if (botList.size() > 0) {
boolean allBotsDisconnected;
synchronized (botList) {
allBotsDisconnected = botList.stream().allMatch(Bot::hasBeenDisconnected);
}
if (allBotsDisconnected) {
return true;
}
}
return false;
}

@Override
protected void after() {
for (Bot bot : botList) {
bot.disconnect("disconnect");
}
}
}
Loading

0 comments on commit f48866e

Please sign in to comment.