diff --git a/README.md b/README.md index e7c2910..d354da3 100644 --- a/README.md +++ b/README.md @@ -3,23 +3,21 @@ An example bot implemented in Java ## Video Guide -https://youtu.be/mPfYqKe_KRs +https://youtu.be/mPfYqKe_KRs (slightly outdated because it uses the old GUI) ## Usage Instructions: -1. Make sure you've installed Python 3.6.5 or newer. Here's [Python 3.7 64 bit](https://www.python.org/ftp/python/3.7.0/python-3.7.0-amd64.exe). Some older versions like 3.6.0 will not work. During installation: - - Select "Add Python to PATH" - - Make sure pip is included in the installation 1. Make sure you've installed the Java 8 JDK or newer. Here's the [Java 8 JDK](https://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html). 1. Make sure you've [set the JAVA_HOME environment variable](https://javatutorial.net/set-java-home-windows-10). 1. Download this repository 1. Double click on run-bot.bat and leave it running. It's supposed to stay open and it's OK if it says something like "75%". -1. Double click on run-gui.bat -1. Click the 'Run' button + - Alternatively you can launch the bot from inside an IDE +1. Get RLBotGUI (see https://youtu.be/lPkID_IH88U for instructions). +1. Use Add -> Load folder in RLBotGUI on the current directory. This bot should appear in the list. +1. In RLBotGUI, put the bot on a team and start the match. - Bot behavior is controlled by `src/main/java/rlbotexample/SampleBot.java` -- Bot appearance is controlled by `src/main/python/javaExampleAppearance.cfg` See the [wiki](https://github.com/RLBot/RLBotJavaExample/wiki) for tips to improve your programming experience. diff --git a/build.gradle b/build.gradle index 0124827..e4bda5e 100644 --- a/build.gradle +++ b/build.gradle @@ -7,7 +7,7 @@ apply plugin: 'application' sourceCompatibility = 1.8 repositories { - jcenter() + mavenCentral() } mainClassName = 'rlbotexample.JavaExample' @@ -19,54 +19,18 @@ applicationDefaultJvmArgs = ["-Djna.library.path=" + dllDirectory] dependencies { // Fetch the framework jar file - compile 'org.rlbot.commons:framework:1.+' + compile 'org.rlbot.commons:framework:2.+' // This is makes it easy to find the dll when running in intellij, where JVM args don't get passed from gradle. runtime files(dllDirectory) } -task checkPipUpgradeSafety { - doLast { - new ByteArrayOutputStream().withStream { os -> - def exitValue = exec { - commandLine "python", "-c", "from rlbot.utils import public_utils; print(public_utils.is_safe_to_upgrade());" - standardOutput = os - ignoreExitValue = true - }.exitValue - - // If the exit value is nonzero, the command probably failed because rlbot is not installed at all. - ext.isSafe = exitValue != 0 || os.toString().trim() == "True" - } - } -} - - -// Uses pip (the python package manager) to install all the python packages needed for this bot, as defined -// in requirements.txt. -task pipInstallRequirements { - dependsOn 'checkPipUpgradeSafety' - - doLast { - if (checkPipUpgradeSafety.isSafe) { - exec { - commandLine "python", "-m", "pip", "install", "-r", "requirements.txt", "--upgrade" - } - } else { - println 'Skipping upgrade attempt because files are in use.' - } - } -} task createDllDirectory { mkdir dllDirectory } -// Installs or updates RLBot. Empty task for now. It still does stuff because it "dependsOn" tasks that do things. -task updateRLBot { - dependsOn 'pipInstallRequirements' - dependsOn 'createDllDirectory' -} -updateRLBot.dependsOn pipInstallRequirements +run.dependsOn createDllDirectory applicationDistribution.exclude(dllDirectory) diff --git a/rlbot.cfg b/rlbot.cfg index 80411c4..7944055 100644 --- a/rlbot.cfg +++ b/rlbot.cfg @@ -5,10 +5,13 @@ # Visit https://github.com/RLBot/RLBot/wiki/Config-File-Documentation to see what you can put here. [Match Configuration] -# Number of bots/players which will be spawned. We support up to max 10. +# Visit https://github.com/RLBot/RLBot/wiki/Config-File-Documentation to see what you can put here. +# Number of bots/players which will be spawned. We support up to max 64. num_participants = 2 game_mode = Soccer game_map = Mannfield +enable_rendering = True +enable_state_setting = True [Mutator Configuration] # Visit https://github.com/RLBot/RLBot/wiki/Config-File-Documentation to see what you can put here. diff --git a/run-bot.bat b/run-bot.bat index 4508712..fd7a00b 100644 --- a/run-bot.bat +++ b/run-bot.bat @@ -1,12 +1,6 @@ @rem Change the working directory to the location of this file so that relative paths will work cd /D "%~dp0" -@rem Make sure the environment variables are up-to-date. This is useful if the user installed python a moment ago. -call ./RefreshEnv.cmd - -@rem Install or update rlbot and related python packages. -call ./gradlew.bat --no-daemon updateRLBot - @rem Start running the bot. call ./gradlew.bat --no-daemon run diff --git a/run-gui.bat b/run-gui.bat deleted file mode 100644 index a1c00d9..0000000 --- a/run-gui.bat +++ /dev/null @@ -1,11 +0,0 @@ -@echo off - -@rem Change the working directory to the location of this file so that relative paths will work -cd /D "%~dp0" - -@rem Make sure the environment variables are up-to-date. This is useful if the user installed python a moment ago. -call ./RefreshEnv.cmd - -python run.py gui - -pause diff --git a/run.py b/run.py index 89b5a0e..23ea98a 100644 --- a/run.py +++ b/run.py @@ -1,37 +1,32 @@ -# https://stackoverflow.com/a/51704613 -try: - from pip import main as pipmain -except ImportError: - from pip._internal import main as pipmain +import subprocess +import sys +DEFAULT_LOGGER = 'rlbot' -# https://stackoverflow.com/a/24773951 -def install_and_import(package): - import importlib +if __name__ == '__main__': try: - importlib.import_module(package) - except ImportError: - pipmain(['install', package]) - finally: - globals()[package] = importlib.import_module(package) + from rlbot.utils import public_utils, logging_utils + logger = logging_utils.get_logger(DEFAULT_LOGGER) + if not public_utils.have_internet(): + logger.log(logging_utils.logging_level, + 'Skipping upgrade check for now since it looks like you have no internet') + elif public_utils.is_safe_to_upgrade(): + subprocess.call([sys.executable, "-m", "pip", "install", '-r', 'requirements.txt']) + subprocess.call([sys.executable, "-m", "pip", "install", 'rlbot', '--upgrade']) -if __name__ == '__main__': - install_and_import('rlbot') - from rlbot.utils import public_utils + # https://stackoverflow.com/a/44401013 + rlbots = [module for module in sys.modules if module.startswith('rlbot')] + for rlbot_module in rlbots: + sys.modules.pop(rlbot_module) - if public_utils.is_safe_to_upgrade(): - pipmain(['install', '-r', 'requirements.txt', '--upgrade', '--upgrade-strategy=eager']) + except ImportError: + subprocess.call([sys.executable, "-m", "pip", "install", '-r', 'requirements.txt', '--upgrade', '--upgrade-strategy=eager']) try: - import sys - if len(sys.argv) > 1 and sys.argv[1] == 'gui': - from rlbot.gui.qt_root import RLBotQTGui - RLBotQTGui.main() - else: - from rlbot import runner - runner.main() + from rlbot import runner + runner.main() except Exception as e: print("Encountered exception: ", e) print("Press enter to close.") diff --git a/src/main/java/rlbotexample/JavaExample.java b/src/main/java/rlbotexample/JavaExample.java index c188933..d3d7230 100644 --- a/src/main/java/rlbotexample/JavaExample.java +++ b/src/main/java/rlbotexample/JavaExample.java @@ -18,12 +18,12 @@ */ public class JavaExample { - private static final Integer DEFAULT_PORT = 17357; + private static final int DEFAULT_PORT = 17357; public static void main(String[] args) { BotManager botManager = new BotManager(); - Integer port = PortReader.readPortFromArgs(args).orElseGet(() -> { + int port = PortReader.readPortFromArgs(args).orElseGet(() -> { System.out.println("Could not read port from args, using default!"); return DEFAULT_PORT; }); @@ -31,6 +31,10 @@ public static void main(String[] args) { SamplePythonInterface pythonInterface = new SamplePythonInterface(port, botManager); new Thread(pythonInterface::start).start(); + displayWindow(botManager, port); + } + + private static void displayWindow(BotManager botManager, int port) { JFrame frame = new JFrame("Java Bot"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); diff --git a/src/main/java/rlbotexample/SampleBot.java b/src/main/java/rlbotexample/SampleBot.java index 1639980..0a82f17 100644 --- a/src/main/java/rlbotexample/SampleBot.java +++ b/src/main/java/rlbotexample/SampleBot.java @@ -10,8 +10,8 @@ import rlbot.manager.BotLoopRenderer; import rlbot.render.Renderer; import rlbotexample.boost.BoostManager; -import rlbotexample.input.CarData; import rlbotexample.input.DataPacket; +import rlbotexample.input.car.CarData; import rlbotexample.output.ControlsOutput; import rlbotexample.prediction.BallPredictionHelper; import rlbotexample.vector.Vector2; @@ -75,6 +75,12 @@ private void drawDebugLines(DataPacket input, CarData myCar, boolean goLeft) { renderer.drawString3d(goLeft ? "left" : "right", Color.WHITE, myCar.position, 2, 2); + if(input.ball.hasBeenTouched) { + float lastTouchTime = myCar.elapsedSeconds - input.ball.latestTouch.gameSeconds; + Color touchColor = input.ball.latestTouch.team == 0 ? Color.BLUE : Color.ORANGE; + renderer.drawString3d((int)lastTouchTime + "s", touchColor, input.ball.position, 2, 2); + } + try { // Draw 3 seconds of ball prediction BallPrediction ballPrediction = RLBotDll.getBallPrediction(); @@ -115,6 +121,7 @@ public ControllerState processInput(GameTickPacket packet) { return controlsOutput; } + @Override public void retire() { System.out.println("Retiring sample bot " + playerIndex); } diff --git a/src/main/java/rlbotexample/SamplePythonInterface.java b/src/main/java/rlbotexample/SamplePythonInterface.java index 829aa93..aa679bc 100644 --- a/src/main/java/rlbotexample/SamplePythonInterface.java +++ b/src/main/java/rlbotexample/SamplePythonInterface.java @@ -10,6 +10,7 @@ public SamplePythonInterface(int port, BotManager botManager) { super(port, botManager); } + @Override protected Bot initBot(int index, String botType, int team) { return new SampleBot(index); } diff --git a/src/main/java/rlbotexample/boost/BoostManager.java b/src/main/java/rlbotexample/boost/BoostManager.java index a9fa1bf..b93d7a6 100644 --- a/src/main/java/rlbotexample/boost/BoostManager.java +++ b/src/main/java/rlbotexample/boost/BoostManager.java @@ -8,6 +8,7 @@ import java.io.IOException; import java.util.ArrayList; +import java.util.List; /** * Information about where boost pads are located on the field and what status they have. @@ -17,15 +18,15 @@ */ public class BoostManager { - private static final ArrayList orderedBoosts = new ArrayList<>(); - private static final ArrayList fullBoosts = new ArrayList<>(); - private static final ArrayList smallBoosts = new ArrayList<>(); + private static final List orderedBoosts = new ArrayList<>(); + private static final List fullBoosts = new ArrayList<>(); + private static final List smallBoosts = new ArrayList<>(); - public static ArrayList getFullBoosts() { + public static List getFullBoosts() { return fullBoosts; } - public static ArrayList getSmallBoosts() { + public static List getSmallBoosts() { return smallBoosts; } diff --git a/src/main/java/rlbotexample/input/DataPacket.java b/src/main/java/rlbotexample/input/DataPacket.java index 7001897..a61b69c 100644 --- a/src/main/java/rlbotexample/input/DataPacket.java +++ b/src/main/java/rlbotexample/input/DataPacket.java @@ -1,6 +1,8 @@ package rlbotexample.input; import rlbot.flat.GameTickPacket; +import rlbotexample.input.ball.BallData; +import rlbotexample.input.car.CarData; import java.util.ArrayList; import java.util.List; diff --git a/src/main/java/rlbotexample/input/BallData.java b/src/main/java/rlbotexample/input/ball/BallData.java similarity index 70% rename from src/main/java/rlbotexample/input/BallData.java rename to src/main/java/rlbotexample/input/ball/BallData.java index c7f042f..8dffab4 100644 --- a/src/main/java/rlbotexample/input/BallData.java +++ b/src/main/java/rlbotexample/input/ball/BallData.java @@ -1,4 +1,4 @@ -package rlbotexample.input; +package rlbotexample.input.ball; import rlbot.flat.BallInfo; @@ -14,10 +14,14 @@ public class BallData { public final Vector3 position; public final Vector3 velocity; public final Vector3 spin; + public final BallTouch latestTouch; + public final boolean hasBeenTouched; public BallData(final BallInfo ball) { this.position = new Vector3(ball.physics().location()); this.velocity = new Vector3(ball.physics().velocity()); this.spin = new Vector3(ball.physics().angularVelocity()); + this.hasBeenTouched = ball.latestTouch() != null; + this.latestTouch = this.hasBeenTouched ? new BallTouch(ball.latestTouch()) : null; } } diff --git a/src/main/java/rlbotexample/input/ball/BallTouch.java b/src/main/java/rlbotexample/input/ball/BallTouch.java new file mode 100644 index 0000000..d0af1bb --- /dev/null +++ b/src/main/java/rlbotexample/input/ball/BallTouch.java @@ -0,0 +1,29 @@ +package rlbotexample.input.ball; + + +import rlbot.flat.Touch; +import rlbotexample.vector.Vector3; + +/** + * Basic information about the ball's latest touch. + * + * This class is here for your convenience, it is NOT part of the framework. You can change it as much + * as you want, or delete it. + */ +public class BallTouch { + public final Vector3 position; + public final Vector3 normal; + public final String playerName; + public final float gameSeconds; + public final int playerIndex; + public final int team; + + public BallTouch(final Touch touch) { + this.position = new Vector3(touch.location()); + this.normal = new Vector3(touch.normal()); + this.playerName = touch.playerName(); + this.gameSeconds = touch.gameSeconds(); + this.playerIndex = touch.playerIndex(); + this.team = touch.team(); + } +} diff --git a/src/main/java/rlbotexample/input/CarData.java b/src/main/java/rlbotexample/input/car/CarData.java similarity index 98% rename from src/main/java/rlbotexample/input/CarData.java rename to src/main/java/rlbotexample/input/car/CarData.java index 87fbfa9..1023e73 100644 --- a/src/main/java/rlbotexample/input/CarData.java +++ b/src/main/java/rlbotexample/input/car/CarData.java @@ -1,4 +1,4 @@ -package rlbotexample.input; +package rlbotexample.input.car; import rlbotexample.vector.Vector3; diff --git a/src/main/java/rlbotexample/input/CarOrientation.java b/src/main/java/rlbotexample/input/car/CarOrientation.java similarity index 98% rename from src/main/java/rlbotexample/input/CarOrientation.java rename to src/main/java/rlbotexample/input/car/CarOrientation.java index 84a0fa3..68370ec 100644 --- a/src/main/java/rlbotexample/input/CarOrientation.java +++ b/src/main/java/rlbotexample/input/car/CarOrientation.java @@ -1,4 +1,4 @@ -package rlbotexample.input; +package rlbotexample.input.car; import rlbot.flat.PlayerInfo; diff --git a/src/main/java/rlbotexample/output/ControlsOutput.java b/src/main/java/rlbotexample/output/ControlsOutput.java index ace5d65..9cdbd2b 100644 --- a/src/main/java/rlbotexample/output/ControlsOutput.java +++ b/src/main/java/rlbotexample/output/ControlsOutput.java @@ -146,4 +146,4 @@ public boolean holdHandbrake() { public boolean holdUseItem() { return useItemDepressed; } -} +} \ No newline at end of file diff --git a/src/main/java/rlbotexample/vector/Vector2.java b/src/main/java/rlbotexample/vector/Vector2.java index 2197505..dad1633 100644 --- a/src/main/java/rlbotexample/vector/Vector2.java +++ b/src/main/java/rlbotexample/vector/Vector2.java @@ -98,4 +98,9 @@ public double correctionAngle(Vector2 ideal) { public static double angle(Vector2 a, Vector2 b) { return Math.abs(a.correctionAngle(b)); } + + @Override + public String toString() { + return String.format("(%s, %s)", x, y); + } } diff --git a/src/main/java/rlbotexample/vector/Vector3.java b/src/main/java/rlbotexample/vector/Vector3.java index b359c52..506ab21 100644 --- a/src/main/java/rlbotexample/vector/Vector3.java +++ b/src/main/java/rlbotexample/vector/Vector3.java @@ -99,4 +99,9 @@ public Vector3 crossProduct(Vector3 v) { double tz = x * v.y - y * v.x; return new Vector3(tx, ty, tz); } + + @Override + public String toString() { + return String.format("(%s, %s, %s)", x, y, z); + } }