diff --git a/yardstick/src/main/java/nl/tudelft/opencraft/yardstick/Yardstick.java b/yardstick/src/main/java/nl/tudelft/opencraft/yardstick/Yardstick.java index 88e49c6a..9acce421 100644 --- a/yardstick/src/main/java/nl/tudelft/opencraft/yardstick/Yardstick.java +++ b/yardstick/src/main/java/nl/tudelft/opencraft/yardstick/Yardstick.java @@ -25,13 +25,17 @@ import com.typesafe.config.ConfigFactory; import nl.tudelft.opencraft.yardstick.experiment.Experiment; import nl.tudelft.opencraft.yardstick.experiment.Experiment10GenerationStressTest; +import nl.tudelft.opencraft.yardstick.experiment.Experiment10WalkStraight; import nl.tudelft.opencraft.yardstick.experiment.Experiment11Latency; +import nl.tudelft.opencraft.yardstick.experiment.Experiment11Random; import nl.tudelft.opencraft.yardstick.experiment.Experiment12LatencyAndWalkAround; +import nl.tudelft.opencraft.yardstick.experiment.Experiment12RandomE2E; 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.Experiment9GenerationStressTest; import nl.tudelft.opencraft.yardstick.experiment.Experiment9Spike; import nl.tudelft.opencraft.yardstick.experiment.RemoteControlledExperiment; import nl.tudelft.opencraft.yardstick.game.GameArchitecture; @@ -121,6 +125,18 @@ public static void main(String[] args) { case "12": ex = new Experiment12LatencyAndWalkAround(id, game, behaviorConfig); break; + case "13": + ex = new Experiment9GenerationStressTest(); + break; + case "14": + ex = new Experiment10WalkStraight(); + break; + case "15": + ex = new Experiment11Random(); + break; + case "16": + ex = new Experiment12RandomE2E(); + break; default: System.out.println("Invalid experiment: " + behaviorName); return; diff --git a/yardstick/src/main/java/nl/tudelft/opencraft/yardstick/bot/Bot.java b/yardstick/src/main/java/nl/tudelft/opencraft/yardstick/bot/Bot.java index c13b73dc..84be34c9 100644 --- a/yardstick/src/main/java/nl/tudelft/opencraft/yardstick/bot/Bot.java +++ b/yardstick/src/main/java/nl/tudelft/opencraft/yardstick/bot/Bot.java @@ -28,6 +28,7 @@ import nl.tudelft.opencraft.yardstick.bot.world.SimpleWorldPhysics; import nl.tudelft.opencraft.yardstick.bot.world.World; import nl.tudelft.opencraft.yardstick.experiment.LoggerSessionListener; +import nl.tudelft.opencraft.yardstick.telemetry.Timer; import nl.tudelft.opencraft.yardstick.workload.WorkloadDumper; import nl.tudelft.opencraft.yardstick.workload.WorkloadSessionListener; import org.slf4j.Logger; @@ -121,14 +122,20 @@ public void addSessionListener(SessionListener... listeners) { * @throws IllegalStateException if the bot is already connected. */ public void connect() { - Session session = client.getSession(); - if (session.isConnected()) { - throw new IllegalStateException("Can not start connection. Bot already isConnected!"); - } - session.addListener(new LoggerSessionListener(logger)); - session.connect(); + Timer timer = new Timer("connect_latency"); + timer.start(); + try { + Session session = client.getSession(); + if (session.isConnected()) { + throw new IllegalStateException("Can not start connection. Bot already isConnected!"); + } + session.addListener(new LoggerSessionListener(logger)); + session.connect(); - initializeTaskTicker(); + initializeTaskTicker(); + } finally { + timer.stop(); + } } private void initializeTaskTicker() { diff --git a/yardstick/src/main/java/nl/tudelft/opencraft/yardstick/bot/BotController.java b/yardstick/src/main/java/nl/tudelft/opencraft/yardstick/bot/BotController.java index 2fccec39..95328c7d 100644 --- a/yardstick/src/main/java/nl/tudelft/opencraft/yardstick/bot/BotController.java +++ b/yardstick/src/main/java/nl/tudelft/opencraft/yardstick/bot/BotController.java @@ -28,6 +28,7 @@ import science.atlarge.opencraft.mcprotocollib.data.game.entity.metadata.Position; import science.atlarge.opencraft.mcprotocollib.data.game.entity.player.Hand; import science.atlarge.opencraft.mcprotocollib.data.game.entity.player.PlayerAction; +import science.atlarge.opencraft.mcprotocollib.packet.ingame.client.ClientChatPacket; import science.atlarge.opencraft.mcprotocollib.packet.ingame.client.player.ClientPlayerActionPacket; import science.atlarge.opencraft.mcprotocollib.packet.ingame.client.player.ClientPlayerPlaceBlockPacket; import science.atlarge.opencraft.mcprotocollib.packet.ingame.client.player.ClientPlayerPositionPacket; @@ -151,6 +152,10 @@ public void creativeInventoryAction(Material mat, int amt) { getSession().send(new ClientCreativeInventoryActionPacket(PLAYER_INVENTORY_HOTBAR_0, new ItemStack(mat.getId(), amt))); } + public void sendChatMsg(String msg) { + getSession().send(new ClientChatPacket(msg)); + } + /** * A state of breaking blocks. */ diff --git a/yardstick/src/main/java/nl/tudelft/opencraft/yardstick/bot/BotListener.java b/yardstick/src/main/java/nl/tudelft/opencraft/yardstick/bot/BotListener.java index f06ef587..eb570316 100644 --- a/yardstick/src/main/java/nl/tudelft/opencraft/yardstick/bot/BotListener.java +++ b/yardstick/src/main/java/nl/tudelft/opencraft/yardstick/bot/BotListener.java @@ -129,6 +129,8 @@ import science.atlarge.opencraft.packetlib.event.session.SessionListener; import science.atlarge.opencraft.packetlib.packet.Packet; +import java.util.ArrayList; +import java.util.List; import java.util.UUID; /** @@ -143,6 +145,9 @@ public class BotListener implements SessionListener { private Server server; private World world; + private final List unhandledRecvPkt = new ArrayList<>(); + private boolean serverJoinGame; + /** * Creates a new listener. * @@ -464,6 +469,13 @@ public void packetReceived(PacketReceivedEvent pre) { this.player = new BotPlayer(bot, p.getEntityId()); player.setGamemode(p.getGameMode()); bot.setPlayer(player); + + // Replay the unhandled packet events before receiving server join game + serverJoinGame = true; + for (PacketReceivedEvent packetReceivedEvent : unhandledRecvPkt) { + packetReceived(packetReceivedEvent); + } + unhandledRecvPkt.clear(); } else if (packet instanceof ServerMapDataPacket) { // 0x24 Map ServerMapDataPacket p = (ServerMapDataPacket) packet; @@ -512,6 +524,11 @@ public void packetReceived(PacketReceivedEvent pre) { ServerOpenTileEntityEditorPacket p = (ServerOpenTileEntityEditorPacket) packet; // TODO + } + // ServerJoinGame packet is received after a few Player packets. + // Save them to handle later + else if (!serverJoinGame) { + unhandledRecvPkt.add(pre); } else if (packet instanceof ServerPlayerAbilitiesPacket) { // 0x2B Player Abilities @@ -540,8 +557,8 @@ public void packetReceived(PacketReceivedEvent pre) { } else if (packet instanceof ServerPlayerPositionRotationPacket) { // 0x2E Player Position And Look ServerPlayerPositionRotationPacket p = (ServerPlayerPositionRotationPacket) packet; - BotPlayer player = bot.getPlayer(); + player.setLocation(new Vector3d(p.getX(), p.getY(), p.getZ())); player.setPitch(p.getPitch()); player.setYaw(p.getYaw()); @@ -549,7 +566,6 @@ public void packetReceived(PacketReceivedEvent pre) { Session session = bot.getClient().getSession(); session.send(new ClientTeleportConfirmPacket(p.getTeleportId())); - logger.info("Received new Player position: " + player.getLocation()); } else if (packet instanceof ServerPlayerUseBedPacket) { @@ -723,7 +739,7 @@ public void packetReceived(PacketReceivedEvent pre) { // TODO } else { - logger.warn("Received unhandled packet: {}", packet.getClass().getName()); + logger.debug("Received unhandled packet: {}", packet.getClass().getName()); } } diff --git a/yardstick/src/main/java/nl/tudelft/opencraft/yardstick/bot/ai/task/BreakBlocksTask.java b/yardstick/src/main/java/nl/tudelft/opencraft/yardstick/bot/ai/task/BreakBlocksTask.java index 06d7470a..eeabb4d6 100644 --- a/yardstick/src/main/java/nl/tudelft/opencraft/yardstick/bot/ai/task/BreakBlocksTask.java +++ b/yardstick/src/main/java/nl/tudelft/opencraft/yardstick/bot/ai/task/BreakBlocksTask.java @@ -18,14 +18,13 @@ package nl.tudelft.opencraft.yardstick.bot.ai.task; +import java.util.ArrayList; +import java.util.List; import nl.tudelft.opencraft.yardstick.bot.Bot; import nl.tudelft.opencraft.yardstick.bot.world.Block; import nl.tudelft.opencraft.yardstick.bot.world.ChunkNotLoadedException; import nl.tudelft.opencraft.yardstick.util.Vector3i; -import java.util.ArrayList; -import java.util.List; - public class BreakBlocksTask implements Task { private List blockLocations; diff --git a/yardstick/src/main/java/nl/tudelft/opencraft/yardstick/bot/ai/task/PlaceBlocksTask.java b/yardstick/src/main/java/nl/tudelft/opencraft/yardstick/bot/ai/task/PlaceBlocksTask.java index 4d34a0ea..034f5bef 100644 --- a/yardstick/src/main/java/nl/tudelft/opencraft/yardstick/bot/ai/task/PlaceBlocksTask.java +++ b/yardstick/src/main/java/nl/tudelft/opencraft/yardstick/bot/ai/task/PlaceBlocksTask.java @@ -18,12 +18,11 @@ package nl.tudelft.opencraft.yardstick.bot.ai.task; +import java.util.List; import nl.tudelft.opencraft.yardstick.bot.Bot; import nl.tudelft.opencraft.yardstick.bot.world.Material; import nl.tudelft.opencraft.yardstick.util.Vector3i; -import java.util.List; - public class PlaceBlocksTask implements Task { private List blockPositions; diff --git a/yardstick/src/main/java/nl/tudelft/opencraft/yardstick/bot/ai/task/RandomSquareWalkXZTask.java b/yardstick/src/main/java/nl/tudelft/opencraft/yardstick/bot/ai/task/RandomSquareWalkXZTask.java index 0504dc74..865e3686 100644 --- a/yardstick/src/main/java/nl/tudelft/opencraft/yardstick/bot/ai/task/RandomSquareWalkXZTask.java +++ b/yardstick/src/main/java/nl/tudelft/opencraft/yardstick/bot/ai/task/RandomSquareWalkXZTask.java @@ -18,6 +18,7 @@ package nl.tudelft.opencraft.yardstick.bot.ai.task; +import java.util.Random; import nl.tudelft.opencraft.yardstick.bot.Bot; import nl.tudelft.opencraft.yardstick.bot.world.ChunkNotLoadedException; import nl.tudelft.opencraft.yardstick.util.Vector2i; @@ -25,8 +26,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.util.Random; - public class RandomSquareWalkXZTask implements Task { private final Logger logger = LoggerFactory.getLogger(RandomSquareWalkXZTask.class); diff --git a/yardstick/src/main/java/nl/tudelft/opencraft/yardstick/bot/ai/task/StandExecutor.java b/yardstick/src/main/java/nl/tudelft/opencraft/yardstick/bot/ai/task/StandExecutor.java new file mode 100644 index 00000000..301edf7a --- /dev/null +++ b/yardstick/src/main/java/nl/tudelft/opencraft/yardstick/bot/ai/task/StandExecutor.java @@ -0,0 +1,33 @@ +package nl.tudelft.opencraft.yardstick.bot.ai.task; + +import nl.tudelft.opencraft.yardstick.bot.Bot; + +public class StandExecutor extends AbstractTaskExecutor { + private int timeout = 1000; + private final long startTime; + + + public StandExecutor(Bot bot) { + super(bot); + startTime = System.currentTimeMillis(); + } + + public void setTimeout(int timeout) { + this.timeout = timeout; + } + + @Override + protected TaskStatus onTick() { + long nowTime = System.currentTimeMillis(); + if (nowTime - startTime >= timeout) { + return TaskStatus.forSuccess(); + } else { + return TaskStatus.forInProgress(); + } + } + + @Override + protected void onStop() { + + } +} diff --git a/yardstick/src/main/java/nl/tudelft/opencraft/yardstick/experiment/AbstractModelExperiment.java b/yardstick/src/main/java/nl/tudelft/opencraft/yardstick/experiment/AbstractModelExperiment.java index 94dfe388..722da257 100644 --- a/yardstick/src/main/java/nl/tudelft/opencraft/yardstick/experiment/AbstractModelExperiment.java +++ b/yardstick/src/main/java/nl/tudelft/opencraft/yardstick/experiment/AbstractModelExperiment.java @@ -90,8 +90,10 @@ private void botTick(Bot bot) { private Runnable newBotConnector(Bot bot) { return () -> { + long start = System.currentTimeMillis(); bot.connect(); - int sleep = 1000; + + int sleep = 2000; int tries = 3; while (tries-- > 0 && (bot.getPlayer() == null || !bot.isJoined())) { try { @@ -101,11 +103,15 @@ private Runnable newBotConnector(Bot bot) { break; } } + if (!bot.isJoined()) { String host = bot.getClient().getHost(); int port = bot.getClient().getPort(); logger.warn("Could not connect bot {}:{}.", host, port); bot.disconnect("Make sure to close all connections."); + if (number == 10) { + Experiment10WalkStraight.currBotId -= Experiment10WalkStraight.clientCount; + } } }; } @@ -138,4 +144,8 @@ protected void after() { bot.disconnect("disconnect"); } } + + public BotModel getModel() { + return model; + } } diff --git a/yardstick/src/main/java/nl/tudelft/opencraft/yardstick/experiment/Experiment10WalkStraight.java b/yardstick/src/main/java/nl/tudelft/opencraft/yardstick/experiment/Experiment10WalkStraight.java new file mode 100644 index 00000000..c6ee195f --- /dev/null +++ b/yardstick/src/main/java/nl/tudelft/opencraft/yardstick/experiment/Experiment10WalkStraight.java @@ -0,0 +1,47 @@ +/* + * Yardstick: A Benchmark for Minecraft-like Services + * Copyright (C) 2020 AtLarge Research + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package nl.tudelft.opencraft.yardstick.experiment; + +import java.util.UUID; +import nl.tudelft.opencraft.yardstick.bot.Bot; +import nl.tudelft.opencraft.yardstick.model.StraightMovementModel; + + +public class Experiment10WalkStraight extends AbstractModelExperiment { + + public static int currBotId; + public static int clientCount; + public static double walkSpeed; + + public Experiment10WalkStraight() { + super(10, "Bots move towards different directions based on their IDs", new StraightMovementModel()); + StraightMovementModel model = (StraightMovementModel) getModel(); + currBotId = Integer.parseInt(options.experimentParams.getOrDefault("botstartid", "0")); + clientCount = Integer.parseInt(options.experimentParams.getOrDefault("clientcount", "1")); + walkSpeed = Double.parseDouble(options.experimentParams.getOrDefault("walkspeed", "0.15")); + model.setWalkSpeed(walkSpeed); + + } + + protected Bot createBot() { + Bot bot = newBot(UUID.randomUUID().toString().substring(0, 6) + "-" + (currBotId)); + currBotId += clientCount; + return bot; + } +} diff --git a/yardstick/src/main/java/nl/tudelft/opencraft/yardstick/experiment/Experiment11Random.java b/yardstick/src/main/java/nl/tudelft/opencraft/yardstick/experiment/Experiment11Random.java new file mode 100644 index 00000000..bde8c54c --- /dev/null +++ b/yardstick/src/main/java/nl/tudelft/opencraft/yardstick/experiment/Experiment11Random.java @@ -0,0 +1,31 @@ +/* + * Yardstick: A Benchmark for Minecraft-like Services + * Copyright (C) 2020 AtLarge Research + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package nl.tudelft.opencraft.yardstick.experiment; + +import nl.tudelft.opencraft.yardstick.model.RandomModel; + +public class Experiment11Random extends AbstractModelExperiment { + + public Experiment11Random() { + super(11, "Bots move around randomly and have a chance to break or place blocks", new RandomModel()); + RandomModel randomModel = (RandomModel) getModel(); + randomModel.setMovementDiameter(0); + } + +} diff --git a/yardstick/src/main/java/nl/tudelft/opencraft/yardstick/experiment/Experiment12RandomE2E.java b/yardstick/src/main/java/nl/tudelft/opencraft/yardstick/experiment/Experiment12RandomE2E.java new file mode 100644 index 00000000..5fc3aac7 --- /dev/null +++ b/yardstick/src/main/java/nl/tudelft/opencraft/yardstick/experiment/Experiment12RandomE2E.java @@ -0,0 +1,47 @@ +package nl.tudelft.opencraft.yardstick.experiment; + +import nl.tudelft.opencraft.yardstick.bot.Bot; +import nl.tudelft.opencraft.yardstick.game.GameArchitecture; +import nl.tudelft.opencraft.yardstick.model.RandomModel; +import nl.tudelft.opencraft.yardstick.statistic.ChatLatencyListener; + +import java.io.FileWriter; +import java.time.Duration; +import java.util.UUID; + +public class Experiment12RandomE2E extends AbstractModelExperiment { + public static FileWriter fw; + private boolean GMjoined; + private String GMuser; + public static long GMStartTime; + public static String GMCommand; + + public Experiment12RandomE2E(int nodeID, GameArchitecture game, Duration duration) { + super(12, nodeID, game, duration, "Bots move around randomly with one GM; log E2E latency", new RandomModel()); + try { + fw = new FileWriter("event.log"); + } catch (Exception e) { + e.printStackTrace(); + } + GMuser = options.experimentParams.get("gmuser"); + GMCommand = options.experimentParams.getOrDefault("gmcommand", "random"); + RandomModel randomModel = (RandomModel) getModel(); + randomModel.setMovementDiameter(0); + randomModel.setGMUser(GMuser); + randomModel.setGMInterval(Long.parseLong(options.experimentParams.getOrDefault("gminterval", "10"))); + } + + @Override + protected Bot createBot() { + if (!GMjoined && GMuser != null) { + GMjoined = true; + Bot bot = newBot(GMuser); + bot.addListener(new ChatLatencyListener()); + return bot; + } else { + Bot bot = newBot(UUID.randomUUID().toString().substring(0, 6)); + bot.addListener(new ChatLatencyListener()); + return bot; + } + } +} diff --git a/yardstick/src/main/java/nl/tudelft/opencraft/yardstick/experiment/Experiment9GenerationStressTest.java b/yardstick/src/main/java/nl/tudelft/opencraft/yardstick/experiment/Experiment9GenerationStressTest.java new file mode 100644 index 00000000..08e0d291 --- /dev/null +++ b/yardstick/src/main/java/nl/tudelft/opencraft/yardstick/experiment/Experiment9GenerationStressTest.java @@ -0,0 +1,154 @@ +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 Experiment9GenerationStressTest extends Experiment { + + private final List botList = Collections.synchronizedList(new ArrayList<>()); + private final Set 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 Experiment9GenerationStressTest() { + 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 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."); + } + }; + } + + 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"); + } + } +} diff --git a/yardstick/src/main/java/nl/tudelft/opencraft/yardstick/model/RandomModel.java b/yardstick/src/main/java/nl/tudelft/opencraft/yardstick/model/RandomModel.java new file mode 100644 index 00000000..3a539269 --- /dev/null +++ b/yardstick/src/main/java/nl/tudelft/opencraft/yardstick/model/RandomModel.java @@ -0,0 +1,121 @@ +package nl.tudelft.opencraft.yardstick.model; + +import java.util.ArrayList; +import java.util.Random; +import java.util.UUID; +import nl.tudelft.opencraft.yardstick.bot.Bot; +import nl.tudelft.opencraft.yardstick.bot.ai.task.StandExecutor; +import nl.tudelft.opencraft.yardstick.bot.ai.task.TaskExecutor; +import nl.tudelft.opencraft.yardstick.bot.ai.task.WalkTaskExecutor; +import nl.tudelft.opencraft.yardstick.bot.world.Material; +import nl.tudelft.opencraft.yardstick.experiment.Experiment12RandomE2E; + + +public class RandomModel implements BotModel { + private BotModel interact = new SimpleInteractionModel(); + private BotModel movement = new SimpleMovementModel(); + + private String GMuser; + private long GMInterval; + private ArrayList bannedUser = new ArrayList<>(); + + public RandomModel() { + + } + + @Override + public TaskExecutor newTask(Bot bot) { + TaskExecutor taskExecutor = null; + Random RANDOM = new Random(System.nanoTime()); + double random = RANDOM.nextDouble(); + + // GM execute command + if (bot.getName().equals(GMuser)) { + if (System.currentTimeMillis() - Experiment12RandomE2E.GMStartTime >= GMInterval * 1000) { + String command = null; + + switch (Experiment12RandomE2E.GMCommand) { + case "weather": + if (random < 1 / 2.0) { + command = "/weather clear"; + } else { + command = "/weather thunder"; + } + break; + + case "random": + default: + if (random < 1 / 2.0) { + if (RANDOM.nextDouble() < 1 / 2.0) { + String target = UUID.randomUUID().toString().substring(0, 6); + command = "/ban " + target; + bannedUser.add(target); + } else if (bannedUser.size() > 0) { + int index = RANDOM.nextInt(bannedUser.size()); + command = "/pardon " + bannedUser.get(index); + bannedUser.remove(index); + } + } else { + command = "/banlist"; + } + break; + } + + if (command != null) { + Experiment12RandomE2E.GMStartTime = System.currentTimeMillis(); + bot.getController().sendChatMsg(command); + } + } + } + + + if (random <= 0.3) { + // Interact + taskExecutor = interact.newTask(bot); + } else if (random > 0.3 && random <= 0.7) { + // Movement + taskExecutor = movement.newTask(bot); + + // random walk speed between [0.1, 0.4] + double walkSpeed = RANDOM.nextDouble() * 0.4; + if (walkSpeed < 0.1) { + walkSpeed = 0.15; + } + ((WalkTaskExecutor) taskExecutor).setSpeed(walkSpeed); + } else if (random > 0.7 && random <= 0.8) { + // send msg + if (RANDOM.nextDouble() < 0.5) { + bot.getController().sendChatMsg("hey"); + } + // get item + else { + Material mt = Material.getById(RANDOM.nextInt(187)); + if (mt != Material.UNKNOWN) { + bot.getController().creativeInventoryAction(mt, RANDOM.nextInt(9) + 1); + } + } + StandExecutor stand = new StandExecutor(bot); + stand.setTimeout(500); + return stand; + } + + // stand still + else { + return new StandExecutor(bot); + } + + return taskExecutor; + } + + public void setMovementDiameter(int dia) { + movement = new SimpleMovementModel(dia); + } + + public void setGMUser(String GMuser) { + this.GMuser = GMuser; + } + + public void setGMInterval(long GMInterval) { + this.GMInterval = GMInterval; + } +} diff --git a/yardstick/src/main/java/nl/tudelft/opencraft/yardstick/model/SimpleMovementModel.java b/yardstick/src/main/java/nl/tudelft/opencraft/yardstick/model/SimpleMovementModel.java index de6cee31..f1bc0ffe 100644 --- a/yardstick/src/main/java/nl/tudelft/opencraft/yardstick/model/SimpleMovementModel.java +++ b/yardstick/src/main/java/nl/tudelft/opencraft/yardstick/model/SimpleMovementModel.java @@ -83,6 +83,15 @@ public Vector3i newTargetLocation(Bot bot) { */ Vector3i getNewFieldLocation(Bot bot) { Vector3d originalLocation = getStartLocation(bot); + + // No bound random + if (boxDiameter == 0) { + int newX = (int) (originalLocation.getX() + RANDOM.nextInt(10) * (RANDOM.nextBoolean() ? -1 : 1) * RANDOM.nextDouble()); + int newZ = (int) (originalLocation.getZ() + RANDOM.nextInt(10) * (RANDOM.nextBoolean() ? -1 : 1) * RANDOM.nextDouble()); + return getTargetAt(bot, newX, newZ); + } + + int maxx = ((int) originalLocation.getX()) + boxDiameter / 2; int minx = ((int) originalLocation.getX()) - boxDiameter / 2; int maxz = ((int) originalLocation.getZ()) + boxDiameter / 2; diff --git a/yardstick/src/main/java/nl/tudelft/opencraft/yardstick/model/StraightMovementModel.java b/yardstick/src/main/java/nl/tudelft/opencraft/yardstick/model/StraightMovementModel.java new file mode 100644 index 00000000..c3505766 --- /dev/null +++ b/yardstick/src/main/java/nl/tudelft/opencraft/yardstick/model/StraightMovementModel.java @@ -0,0 +1,147 @@ +/* + * Yardstick: A Benchmark for Minecraft-like Services + * Copyright (C) 2020 AtLarge Research + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package nl.tudelft.opencraft.yardstick.model; + +import java.util.HashMap; +import java.util.Random; +import nl.tudelft.opencraft.yardstick.bot.Bot; +import nl.tudelft.opencraft.yardstick.bot.ai.task.TaskExecutor; +import nl.tudelft.opencraft.yardstick.bot.ai.task.WalkTaskExecutor; +import nl.tudelft.opencraft.yardstick.bot.world.Block; +import nl.tudelft.opencraft.yardstick.bot.world.BlockFace; +import nl.tudelft.opencraft.yardstick.bot.world.ChunkNotLoadedException; +import nl.tudelft.opencraft.yardstick.util.Vector3d; +import nl.tudelft.opencraft.yardstick.util.Vector3i; +import nl.tudelft.opencraft.yardstick.util.ZigZagRange; + +/** + * Represents a model which moves the bot randomly to short and long distance + * locations. + */ +public class StraightMovementModel implements BotModel { + private Random random; + public static HashMap botsTarget = new HashMap<>(); + public double walkSpeed = 0.15; + + public StraightMovementModel() { + this.random = new Random(); + } + + @Override + public TaskExecutor newTask(Bot bot) { + WalkTaskExecutor exe = new WalkTaskExecutor(bot, newTargetLocation(bot)); + if (walkSpeed != 0.15) { + exe.setSpeed(walkSpeed); + } + return exe; + } + + public Vector3i newTargetLocation(Bot bot) { + Vector3d originalLocation = bot.getPlayer().getLocation(); + int dis = 16; + + int newX = (int) originalLocation.getX(); + int newZ = (int) originalLocation.getZ(); + + int botId = Integer.parseInt(bot.getName().split("-")[1]); + + double factor = 0; + if (botId > 7) { + factor = botId / 8.0; + } + + switch (botId % 8) { + case 0: + newX += dis; + newZ += (int) factor * dis; + break; + case 1: + newZ += dis; + newX += (int) factor * dis; + break; + case 2: + newX -= dis; + newZ -= (int) factor * dis; + break; + case 3: + newZ -= dis; + newX -= (int) factor * dis; + break; + case 4: + newX += dis + (int) factor * dis; + newZ += dis + (int) factor * dis; + break; + case 5: + newX -= dis - (int) factor * dis; + newZ -= dis - (int) factor * dis; + break; + case 6: + newX += dis + (int) factor * dis; + newZ -= dis - (int) factor * dis; + break; + case 7: + newX -= dis - (int) factor * dis; + newZ += dis + (int) factor * dis; + break; + } + + Vector3i prevTarget = botsTarget.get(bot); + if (prevTarget != null && (int) prevTarget.getX() == newX && (int) prevTarget.getZ() == newZ) { + newX = (int) (originalLocation.getX() + random.nextInt(8) * (random.nextBoolean() ? -1 : 1) * random.nextDouble()); + newZ = (int) (originalLocation.getZ() + random.nextInt(8) * (random.nextBoolean() ? -1 : 1) * random.nextDouble()); + } + +// String regionFile = "r." + (newX >> 5) + "." + (newZ >> 5); +// System.out.println("BotID="+botId+",newX="+newX+",newZ="+newZ); + + Vector3i nextTarget = getTargetAt(bot, newX, newZ); + botsTarget.put(bot, nextTarget); + + return nextTarget; + } + + private Vector3i getTargetAt(Bot bot, int x, int z) { + Vector3d botLoc = bot.getPlayer().getLocation(); + + int y = -1; + try { + for (ZigZagRange it = new ZigZagRange(0, 255, (int) botLoc.getY()); it.hasNext(); ) { + y = it.next(); + Block test = bot.getWorld().getBlockAt(x, y, z); + if (test.getMaterial().isTraversable() + && !test.getRelative(BlockFace.BOTTOM).getMaterial().isTraversable()) { + break; + } + } + + if (y < 0 || y > 255) { + return botLoc.intVector(); + } + + return new Vector3i(x, y, z); + } catch (ChunkNotLoadedException ex) { + bot.getLogger().warning("Bot target not loaded: (" + x + "," + y + "," + z + ")"); + return botLoc.intVector(); + } + } + + public void setWalkSpeed(double walkSpeed) { + this.walkSpeed = walkSpeed; + } +} diff --git a/yardstick/src/main/java/nl/tudelft/opencraft/yardstick/statistic/ChatLatencyListener.java b/yardstick/src/main/java/nl/tudelft/opencraft/yardstick/statistic/ChatLatencyListener.java new file mode 100644 index 00000000..00342e0e --- /dev/null +++ b/yardstick/src/main/java/nl/tudelft/opencraft/yardstick/statistic/ChatLatencyListener.java @@ -0,0 +1,76 @@ +package nl.tudelft.opencraft.yardstick.statistic; + +import nl.tudelft.opencraft.yardstick.experiment.Experiment12RandomE2E; +import science.atlarge.opencraft.mcprotocollib.packet.ingame.server.ServerChatPacket; +import science.atlarge.opencraft.packetlib.event.session.ConnectedEvent; +import science.atlarge.opencraft.packetlib.event.session.DisconnectedEvent; +import science.atlarge.opencraft.packetlib.event.session.DisconnectingEvent; +import science.atlarge.opencraft.packetlib.event.session.PacketReceivedEvent; +import science.atlarge.opencraft.packetlib.event.session.PacketSendingEvent; +import science.atlarge.opencraft.packetlib.event.session.PacketSentEvent; +import science.atlarge.opencraft.packetlib.event.session.SessionListener; +import science.atlarge.opencraft.packetlib.packet.Packet; + +import java.io.IOException; + +public class ChatLatencyListener implements SessionListener { + @Override + public void packetReceived(PacketReceivedEvent event) { + Packet packet = event.getPacket(); + if (packet instanceof ServerChatPacket) { + ServerChatPacket p = (ServerChatPacket) packet; + // log time + long end = System.currentTimeMillis(); + + String key = null; + if (p.getMessage().getText().startsWith("There are")) { + key = "banlist"; + } + if (p.getMessage().getText().startsWith("Banned player")) { + key = "ban"; + } + if (p.getMessage().getText().startsWith("Unbanned")) { + key = "unban"; + } + if (p.getMessage().getText().startsWith("Changing to clear")) { + key = "clear"; + } + if (p.getMessage().getText().startsWith("Changing to rain and thunder")) { + key = "thunder"; + } + try { + if (key != null) { + Experiment12RandomE2E.fw.write(end + "\t" + key + "\t" + (end - Experiment12RandomE2E.GMStartTime) + "\n"); + Experiment12RandomE2E.fw.flush(); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + @Override + public void packetSending(PacketSendingEvent event) { + + } + + @Override + public void packetSent(PacketSentEvent event) { + + } + + @Override + public void connected(ConnectedEvent event) { + + } + + @Override + public void disconnecting(DisconnectingEvent event) { + + } + + @Override + public void disconnected(DisconnectedEvent event) { + + } +}