javabwapi / jbwapi Goto Github PK
View Code? Open in Web Editor NEWPure Java BWAPI Client implementation for JVM languages
License: MIT License
Pure Java BWAPI Client implementation for JVM languages
License: MIT License
As noted by @impie66
Example
Race: Protoss
Map: La Mancha
JBWAPI
TilePosition tp = game.getBuildLocation(Protoss_Pylon, game.self().getStartLocation());
game.drawBoxMap(tp.toPosition(), tp.add(new TilePosition(1, 1)).toPosition(), Purple);
BWAPI
auto tp = game->getBuildLocation(Protoss_Pylon, game->self()->getStartLocation());
game->drawBoxMap(Position{ tp }, Position{ tp + TilePosition{1, 1} }, Green);
getBuildLocation implementations
JBWAPI:
There is a bug that the command center requests twice when creating a scv.
There can only ever be 256 different "colors" - so no more objects than that should be necessary.
The constructor should be @deprecated
and new static factory methods should be added.
This is really a low priority issue, but it will allow @dgant to make beautiful ๐ s.
int minsCost = next.mineralPrice();
int gasCost = next.gasPrice();
if(game.canResearch(next) && self.minerals() >= minsCost && self.gas() >= gasCost && myUnit.isCompleted() && !myUnit.isResearching()){
myUnit.research(next);
game.sendText("Researching " + next.toString());
break;
}
Ran the following script onframe and it trigger correctly but failed to research (see discord messages video)
By Simplicity author
The output of isEnemy() returned true for the neutral player.
all I know is that on BWAPI 4.1.2 with BW Mirror that would have returned false, but after the change it returned true
return !(player.isNeutral() || isAlly(player));
should be
if (player.isNeutral()) {
return false;
}
return !isAlly(player);
Nuke doesn't have an value for energyCost
Reference
35 values, 36 TechTypes?
Just needs another value for nuke
c++ sucks leemayo
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: -1
at bwapi.Game.init(Game.java:185)
at bwapi.EventHandler.operation(EventHandler.java:21)
at bwapi.Client.update(Client.java:239)
at bwapi.BWClient.startGame(BWClient.java:43)
at bwapi.BWClient.startGame(BWClient.java:25)
at exec.ExampleBot.run(ExampleBot.java:23)
at exec.ExampleBot.main(ExampleBot.java:27)
enemy = players[gameData.getEnemy()] = -1
getBuildLocation seems to be returning the same location with different start points.
This is what i did
while(test.size() <= 4){
TilePosition build = game.getBuildLocation(UnitType.Terran_Barracks, self.getStartLocation(), 300);
if(build != null){
test.add(build);
System.out.println(build);
game.pingMinimap(build.toPosition());
}
}
I ran this multiple times on the same map with different start positions
What returned was [1000, 1001]
Stack trace:
stackTrace = {StackTraceElement[24]@6004}
0 = {StackTraceElement@6005} "bwapi.WrappedBuffer.putString(WrappedBuffer.java:80)"
1 = {StackTraceElement@6006} "bwapi.ClientData$GameData.setStrings(ClientData.java:562)"
2 = {StackTraceElement@6007} "bwapi.Client.addString(Client.java:251)"
3 = {StackTraceElement@6008} "bwapi.Game.drawText(Game.java:1738)"
4 = {StackTraceElement@6009} "bwapi.Game.drawTextScreen(Game.java:1760)"
5 = (bot code)
The input string was of length 2920:
L: PvP Jadien @ (4)Gladiator1.1.scx (PvPRobo, Fingerprint2Gate, FingerprintDragoonRange, FingerprintGatewayFirst, FingerprintMannerPylon, FingerprintProxyGateway)
W: PvP Jadien @ (3)Power Bond.scx (PvP2GateDTExpand)
W: PvP Jadien @ (2)Overwatch(n).scx (PvP2GateDTExpand, Fingerprint1GateCore, Fingerprint4GateGoon, FingerprintDragoonRange, FingerprintGatewayFirst, FingerprintMannerPylon)
L: PvP Jadien @ (4)Fighting Spirit.scx (PvPProxy2Gate, Fingerprint1GateCore, Fingerprint2Gate, FingerprintDragoonRange, FingerprintGatewayFirst, FingerprintMannerPylon)
L: TvT Atlas Wing @ (2)Overwatch(n).scx (TvT1FacFE, TvT2BaseBC, FingerprintBio)
W: TvT Epsilon Squadron @ (4)Gladiator1.1.scx (TvT2FacTanks, TvT5Fac, FingerprintBio)
W: TvT Epsilon Squadron @ (4)Fighting Spirit.scx (TvT2FacTanks, TvT5Fac, Fingerprint2Rax1113, FingerprintBio)
W: TvT Mar Sara @ (2)Tres Pass.scx (TvT2FacTanks, TvT5Fac, FingerprintBio)
W: TvT Epsilon Squadron @ (4)Fighting Spirit.scx (TvT2FacTanks, TvT5Fac, FingerprintBio)
W: TvT Antiga @ (4)CircuitBreakers1.0.scx (TvT1RaxFE, TvT5Fac, FingerprintBio)
W: TvT Epsilon Squadron @ (4)CircuitBreakers1.0.scx (TvT2FacTanks, TvT5Fac, FingerprintBio)
W: TvT Elite Guard @ (2)Overwatch(n).scx (TvT1FacFE, TvT2BaseBC, FingerprintBBS, FingerprintBio)
W: TvT Delta Squadron @ (4)Fighting Spirit.scx (TvT1RaxFE, TvT2Base2Port, TvT2BaseBC, FingerprintBBS, FingerprintBio)
W: TvT Mar Sara @ (2)Tres Pass.scx (TvT1FacPort, TvT5Fac, FingerprintBBS, FingerprintBio)
W: TvT Delta Squadron @ (3)Power Bond.scx (TvT1FacFE, TvT2Base2Port, TvT2BaseBC, FingerprintBio)
L: TvT Delta Squadron @ (2)Overwatch(n).scx (TvE1RaxSCVMarine, FingerprintBio)
W: TvT Epsilon Squadron @ (4)Fighting Spirit.scx (TvT2FacTanks, TvT5Fac, FingerprintBio)
W: TvT Cronus Wing @ (2)Overwatch(n).scx (TvT2Port, TvT2Base2Port, TvT2BaseBC, FingerprintBio)
W: TvT Epsilon Squadron @ (4)CircuitBreakers1.0.scx (TvT2FacTanks, TvT5Fac, FingerprintBio)
W: TvT Antiga @ (3)Power Bond.scx (TvT1RaxFE, TvT5Fac, FingerprintBio)
W: TvT Cronus Wing @ (4)Gladiator1.1.scx (TvT2FacTanks, TvT2Base2Port, TvT2BaseBC, FingerprintBBS, FingerprintBio)
L: TvT Kel-Morian Combine @ (4)Gladiator1.1.scx (TvT14CC, TvT5Fac)
W: TvT Cronus Wing @ (4)Fighting Spirit.scx (TvT1FacPort, TvT2Base2Port, TvT2BaseBC, FingerprintBBS, FingerprintBio)
W: TvT Cronus Wing @ (2)Overwatch(n).scx (TvT2FacTanks, TvT2Base2Port, TvT2BaseBC, FingerprintBio)
W: TvT Kel-Morian Combine @ (4)CircuitBreakers1.0.scx (TvE2RaxSCVMarine, FingerprintBio)
W: TvT Atlas Wing @ (4)Fighting Spirit.scx (TvT1FacFE, TvT2BaseBC, FingerprintBBS, FingerprintBio)
W: TvT Epsilon Squadron @ (2)Tres Pass.scx (TvT2FacTanks, TvT5Fac, FingerprintBio, FingerprintWorkerRush)
W: TvT Antiga @ (4)Gladiator1.1.scx (TvT1RaxFE, TvT5Fac, Fingerprint2Rax1113, FingerprintBio)
L: TvT Delta Squadron @ (4)CircuitBreakers1.0.scx (TvEProxyBBS)
L: TvT Cronus Wing @ (4)Fighting Spirit.scx (TvEProxyBBS, FingerprintBio)
Since a fix in BWAPI will not fix it for JBWAPI. See bwapi/bwapi#902
Fix autogenerated
Buffers.toString(sharedMemory, offset, 1);
where 1 should be a bigger value
Fix the badges in the first lines of: https://github.com/JavaBWAPI/JBWAPI/edit/develop/README.md
Travis got closed for opensource projects (Github Actions is used now).
LGTMs now also taken over by Github, so need to fix those badges too.
Map analysis problems:
It seems the top two spawns have a Player.getStartLocation() that is
not included in BWTA.getStartLocations(). It also throws the "At least
one starting location was not assigned to a base." exception from
BWTA.analyze().
check functions like topLeft etc.
There are some micro techniques that require issuing commands to a group of units simultaneously. The StarCraft engine applies special rules to these commands.
Module bots can issue grouped commands. But client bots can't, because BWAPI's server implementation doesn't support them. Full details are on the upstream BWAPI issue
There's no way to fix this on JBWAPI's end (short of embedding an in-process JVM into a module bot) until BWAPI adds support for grouped commands by client bots. So this is just documenting that the feature is absent on the JBWAPI end as well; feel free to close if clutter.
as noted by impie
Using release 1.2
I have only observed this when playing consecutive games without restarting.
cause = {IllegalStateException@5560} "java.lang.IllegalStateException: "
stackTrace = {StackTraceElement[21]@5571}
0 = {StackTraceElement@5574} "bwem.Asserter.throwIllegalStateException(Asserter.java:13)"
1 = {StackTraceElement@5575} "bwem.TerrainData.getTile(TerrainData.java:42)"
2 = {StackTraceElement@5576} "bwem.TerrainData.getTile(TerrainData.java:49)"
3 = {StackTraceElement@5577} "bwem.Neutral.putOnTiles(Neutral.java:157)"
4 = {StackTraceElement@5578} "bwem.Neutral.<init>(Neutral.java:44)"
5 = {StackTraceElement@5579} "bwem.Resource.<init>(Resource.java:22)"
6 = {StackTraceElement@5580} "bwem.Mineral.<init>(Mineral.java:23)"
7 = {StackTraceElement@5581} "bwem.NeutralData.<init>(NeutralData.java:38)"
8 = {StackTraceElement@5582} "bwem.BWMapInitializer.initializeNeutralData(BWMapInitializer.java:93)"
9 = {StackTraceElement@5583} "bwem.BWMapInitializer.initialize(BWMapInitializer.java:42)"
10 = {StackTraceElement@5584} "bwem.BWEM.initialize(BWEM.java:53)"
11 = {StackTraceElement@5585} "bwta.BWTA.analyze(BWTA.java:51)"
PurpleWave is configured to do analysis with assertions on, then to retry them with assertions off if anything goes wrong. Re-analyzing without assertions produced data that looked mostly correct.
I suspect (but haven't tested) that the issue occurs when playing a game on a map that's smaller in at least one dimension than the previous one. I noticed the error occurred at least once on a tile with X==124 on https://liquipedia.net/starcraft/Tres_Pass which is only 120 tiles wide.
Avoids java bounds checking, testing in experimental branch.
Results are promising
Even for simple retrieval of ints/bytes (NOT objects, e.g. were BWMirror is much slower)
Performance results
BWMirror - JNI
1000000 calls in : 23.5 ms
1000000 calls in : 23.28 ms
1000000 calls in : 21.68 ms
1000000 calls in : 20.78 ms
1000000 calls in : 20.5 ms
1000000 calls in : 21.33 ms
1000000 calls in : 20.35 ms
1000000 calls in : 22.86 ms
1000000 calls in : 21.34 ms
1000000 calls in : 21.3 ms
1000000 calls in : 22.61 ms
JBWAPI - Buffer
1000000 calls in : 18.11 ms
1000000 calls in : 16.92 ms
1000000 calls in : 15.82 ms
1000000 calls in : 17.54 ms
1000000 calls in : 19.19 ms
1000000 calls in : 23.89 ms
1000000 calls in : 16.63 ms
1000000 calls in : 23.32 ms
1000000 calls in : 15.7 ms
1000000 calls in : 15.77 ms
1000000 calls in : 16.62 ms
JBWAPI - Unsafe
1000000 calls in : 8.15 ms
1000000 calls in : 6.37 ms
1000000 calls in : 3.93 ms
1000000 calls in : 4.11 ms
1000000 calls in : 3.93 ms
1000000 calls in : 4.08 ms
1000000 calls in : 4.05 ms
1000000 calls in : 4.0 ms
1000000 calls in : 4.01 ms
1000000 calls in : 3.93 ms
1000000 calls in : 4.12 ms
C++ (Client) (thanks to @N00byEdge)
1000000 calls in 2.78177ms
1000000 calls in 3.05884ms
1000000 calls in 3.51817ms
1000000 calls in 2.8359ms
1000000 calls in 3.92982ms
1000000 calls in 5.74114ms
1000000 calls in 3.34673ms
1000000 calls in 3.29377ms
1000000 calls in 4.41666ms
1000000 calls in 3.73234ms
https://github.com/JavaBWAPI/JBWAPI/blob/develop/src/main/java/bwem/StaticBuilding.java#L26
https://github.com/JavaBWAPI/JBWAPI/blob/develop/src/main/java/bwem/BWMap.java#L161
These are needed for pulling in the latest version (1.15) of BWEB into JBWEB
Fixes welcome!
I have been trying to look for a unique identifier of the units of the game.
The following code gives me for the 4 initial SCVs an ID of 0 (wether it be replayID or ID)
import bwapi.BWClient;
import bwapi.DefaultBWListener;
import bwapi.Flag;
import bwapi.Game;
import bwapi.Player;
import bwapi.Unit;
public class Bot extends DefaultBWListener {
BWClient bwClient;
Game game;
@Override
public void onStart() {
game = bwClient.getGame();
game.enableFlag(Flag.UserInput);
game.enableFlag(Flag.CompleteMapInformation);
Player self = game.self();
}
@Override
public void onFrame() {
String text = "Unit ID: ";
for(Unit unit : game.getSelectedUnits()) {
text = text + unit.getID() + ',';
}
text = text.substring(0, text.length() - 1);
game.drawTextScreen(200,100, text);
String text2 = "Unit Replay ID: ";
for(Unit unit : game.getSelectedUnits()) {
text2 = text2 + unit.getReplayID() + ',';
}
text2 = text2.substring(0, text2.length() - 1);
game.drawTextScreen(300,100, text2);
}
void run() {
bwClient = new BWClient(this);
bwClient.startGame();
}
public static void main(String[] args) {
new Bot().run();
}
}
When I parse reps using screp I get an in-game identifier which is "unitTag".
I am looking for something similar through the JBWAPI, is there any unique identifier for the units (replayID or ID seem to work fine for the created units, but not for the 4 initial workers).
Cache the starcraft download
Using https://github.com/actions/cache ?
Implement the missing getLastError method in the Game API.
I have a branch that should work: https://github.com/JavaBWAPI/JBWAPI/tree/lasterror
but no capacity to test/verify, feel free to pickup this work if you want this added.
Potential "fixes":
Unsafe::allocateMemory
& Unsafe::freeMemory
Check if work
static UpgradeType[] protoss_air_no_wpnUpgrade = {Protoss_Plasma_Shields, Protoss_Air_Armor};
After the initial v1.0 is out, speed optimizations can be made
todo: fix by adding way to cleanup the memory
Training a unit when the queue is full throws Index out of Bounds Exception. Tested on dev branch w/ latcom on.
Stack Trace:
java.lang.ArrayIndexOutOfBoundsException: Index 5 out of bounds for length 5
at bwapi.CommandTemp.execute(CommandTemp.java:725)
at bwapi.CommandTemp.execute(CommandTemp.java:41)
at bwapi.Unit.issueCommand(Unit.java:2119)
For BWMirror compatibility & efficiency reasons (or Collection)
As suggested by @Bytekeeper like in the ExampleAIClient
https://github.com/bwapi/bwapi/blob/3438abd8e0222f37934ba62b2130c3933b067678/bwapi/ExampleAIClient/Source/ExampleAIClient.cpp#L203
investigate
by @Jabbo16
check if consistent with bwmirror
this.sides = new ImmutablePair<>(chokePoint.getGeometry().get(1).toPosition(), chokePoint.getGeometry().get(2).toPosition());
final int id
(and not be public, but package private)Documentation:
//public void drawTextMap(int x, int y, String string, Text... colors)
//Game.drawTextMap(Position p, String string, Text... colors)
How to add color:
string0 = "%cText Here.";
game.drawTextMap(ccPos.getX(), ccPos.getY() , string0, Text.Red);
If you want multiple colors, each %c will be replaced by follow up arguments.
use getClass & dont therefore noneed to compare scalars.
Also use ^ instead of + for hashcode
I've been having an intermittent crashing problem. It's very rare, occurring in about 1/10 or 1/20 games. I've tried to put together some information that might be helpful.
If the crash is going to occur in a game, it will always occur the first time a unit attempts to pathfind. There will be a 1-2 second lag spike, followed by the following information in the console window:
java.lang.IllegalStateException
at bwem.BWMap.breadthFirstSearch(BWMap.java:333)
at bwem.BWMap.breadthFirstSearch(BWMap.java:339)
at bwem.Graph.getNearestArea(Graph.java:79)
at bwem.Graph$Pathing.(Graph.java:697)
at bwem.Graph.getPath(Graph.java:154)
at bwem.BWMap.getPath(BWMap.java:220)
at SimplicityBot$PositionPath.autogeneratePath(SimplicityBot.java:4414)
at SimplicityBot$UnitCtrl.orders_pathfind(SimplicityBot.java:4794)
at SimplicityBot$UnitCtrl.orders_workerPremove(SimplicityBot.java:5403)
(and so on, the call stack goes back through a bunch more of my stuff.)
I have confirmed that I'm passing two valid positions to BWMap.getPath.
What caught my attention is the call from getNearestArea to breadthFirstSearch. GetNearestArea first checks if the position is in an area, and if so, it just returns that area. See Graph.java at line 92. It only calls breadthFirstSearch if the position is not located in an area. But it should be: the crash here occurred when I tried to premove a worker to my natural to build a hatchery; the start position is the worker and the end position is the base location he's headed to. Those should both be within normal areas.
I added the following testing code to my onFrame method:
int areas = bwem.getMap().getAreas().size();
if (areas == 0) printLine("BWEM areas array size 0");
The next time the crash occurred, it was only after spamming the console with hundreds of "BWEM areas array size 0." So I think that's the cause of the crash. This most recent occasion I was playing on the top-right corner of Empire of the Sun from the SSCAIT map pack.
I would like to know if I'm setting something up wrong or if there is a problem somewhere. I would greatly appreciate any help!
I'm not sure if there is a consistent setup to cause the crash. I rarely see it, maybe 1/10 games or so. One possibility is that I don't always restart Starcraft after every game. I usually leave the game up and only restart my bot. I wonder if some data from a prior game could be lingering around or causing a problem. I can't say for sure whether the crash has ever happened on a fresh instance of Starcraft. I will try testing that next.
Thank you very much!
I know BW is paletted with limited colors available, but the ones that are currently rendering are nevertheless incorrect (eg previously rendered as expected in BWMirror)
Drawing gradients along RGB and HSV spectra:
Full source:
def drawGradient(row: Int, column: Int, color: (Int, Int) => Color): Unit = {
val origin = Pixel(264 * row, 264 * column)
var i = 0
val scale = 16
while (i < 256 / scale) {
var j = 0
while (j < 256 / scale) {
val start = origin.add(scale * i, scale * j)
DrawMap.box(start, start.add(scale, scale), color(scale * i, scale * j), solid = true)
j += 1
}
i += 1
}
}
override def renderMap(): Unit = {
drawGradient(0, 0, (x, y) => new Color(x, y, 0))
drawGradient(0, 1, (x, y) => new Color(x, 0, y))
drawGradient(0, 2, (x, y) => new Color(0, x, y))
drawGradient(1, 0, (x, y) => new Color(x, y, 255))
drawGradient(1, 1, (x, y) => new Color(x, 255, y))
drawGradient(1, 2, (x, y) => new Color(255, x, y))
drawGradient(2, 0, (x, y) => Colors.hsv(x, y, 255))
drawGradient(2, 1, (x, y) => Colors.hsv(x, 255, y))
drawGradient(2, 2, (x, y) => Colors.hsv(128, x, y))
}
}```
The implementation of Unit.getInterceptors()
scales linearly with the number of units in the game, or roughly N^2 for a game with a lot of Carriers; this can be taxing late game because having a lot of Carriers means the total number of units is also likely quite high especially due to each Carrier holding 8 Interceptors.
For a sense of real-world scale: A recent PurpleWave game had getInterceptors()
using about 1% of total CPU time, called once per frame for each Carrier. About half of that looked like evaluating the loop and half was allocating the collections which hold the interceptors.
https://github.com/JavaBWAPI/JBWAPI/blob/develop/src/main/java/bwapi/Unit.java#L1202
Unit.getLarva()
works similarly and is likely subject to the same scaling: https://github.com/JavaBWAPI/JBWAPI/blob/develop/src/main/java/bwapi/Unit.java#L1228
gets rid of some external dependencies or port over the Pair from BWMirror
Not worth it
Hi, after converting MadMix from BWMirror to JBWAPI I noticed it didn't mine the same way. Looking deeper it seems isGatheringMinerals is returning false for a single frame, 2 frames after the order to gather.
Running a modified version of the LatencyListener test shows the order changing from MoveToMinerals to Harvest1 in frame 2. Running the same test in BWMirror (with older BWAPI) shows the order MoveToMinerals in frame 2.
latcom: true
latcom frames: 2
mineralsAmout: 50
FRAME: 0
Worker 0
Unit::isGathering: game.isLatComEnabled()=true self().isGathering.valid(0)=true self().isGathering.get()=true unitData.isGathering()=false
gatheringMinerals: true
order: MoveToMinerals
orderTargetId: null
FRAME: 1
Worker 0
Unit::isGathering: game.isLatComEnabled()=true self().isGathering.valid(1)=false self().isGathering.get()=true unitData.isGathering()=true
gatheringMinerals: true
order: MoveToMinerals
orderTargetId: null
FRAME: 2
Worker 0
Unit::isGathering: game.isLatComEnabled()=true self().isGathering.valid(2)=false self().isGathering.get()=true unitData.isGathering()=false
gatheringMinerals: false
order: Harvest1
orderTargetId: bwapi.Unit@b4
orderTargetType: Resource_Mineral_Field
FRAME: 3
Worker 0
Unit::isGathering: game.isLatComEnabled()=true self().isGathering.valid(3)=false self().isGathering.get()=true unitData.isGathering()=true
gatheringMinerals: true
order: MoveToMinerals
orderTargetId: bwapi.Unit@b4
orderTargetType: Resource_Mineral_Field
From what I can tell this happens with all races and on both 1.0 and develop.
This is a feature proposal which I also added to BWAPI: bwapi/bwapi#873 -- it's a quality-of-life feature that has no particular need to synchronize with mainline BWAPI though, so I've added it here separately
Real-time performance requirements in competition disincentivize bots from logging directly to disk. The incentive is instead to flush logs at the end.
However, if a client bot's pipe connection to StarCraft is broken, no further event handlers are called, leaving the bot without a last-ditch chance to flush logs.
Proposed feature: An onTermination()
handler which is always called after a game, even in event of disconnection. This handler is called with the expectation that BWAPI is no longer accessible. This would allow bots a chance to flush any logs if they haven't already.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.