diff --git a/README.md b/README.md
index 40c3f0a..4da7c60 100644
--- a/README.md
+++ b/README.md
@@ -40,6 +40,9 @@ public class ExampleBot {
@Override
public void onFrame() {
+ // this object is ONLY valid while Mirror.startGame is running
+ // (which is fine 99% of the time, it just means you should only
+ // use it within code that is invoked from these listener methods)
Game game = mirror.getGame();
Player self = game.self();
@@ -47,12 +50,16 @@ public class ExampleBot {
}
});
- // blocks indefinitely
- mirror.startGame();
+ // if you pass true, blocks indefinitely and keeps Broodwar instance
+ // connection to keep playing subsequent matches.
+ // if you pass false, startGame will return after a single match and
+ // disconnects from the Broodwar instance. you can call startGame as
+ // many times as you wish in this case.
+ mirror.startGame(true);
}
public static void main(String... args) {
- new TestBot().run();
+ new ExampleBot().run();
}
}
```
diff --git a/bwmirror/pom.xml b/bwmirror/pom.xml
index ded09bb..e209a52 100644
--- a/bwmirror/pom.xml
+++ b/bwmirror/pom.xml
@@ -4,7 +4,7 @@
com.github.gered
bwmirror
- 2.6
+ 2.7
jar
BWMirror
diff --git a/bwmirror/src/test/java/bwmirror/TestBot.java b/bwmirror/src/test/java/bwmirror/TestBot.java
index 7d6d57a..4b6f370 100644
--- a/bwmirror/src/test/java/bwmirror/TestBot.java
+++ b/bwmirror/src/test/java/bwmirror/TestBot.java
@@ -138,7 +138,7 @@ public class TestBot {
}
});
*/
- mirror.startGame();
+ mirror.startGame(false);
System.out.println("It's over");
}
diff --git a/generator/src/main/java/bwmirror/generator/c/Bind.java b/generator/src/main/java/bwmirror/generator/c/Bind.java
index 33c9a90..e81bdd7 100644
--- a/generator/src/main/java/bwmirror/generator/c/Bind.java
+++ b/generator/src/main/java/bwmirror/generator/c/Bind.java
@@ -30,165 +30,152 @@ public class Bind {
this.context = context;
}
- private void implementConnectionRoutine() {
- out.println("\t\t\t\tprintln(\"Waiting...\");\n" +
- "while ( !Broodwar->isInGame() )\n" +
- " {\n" +
- " BWAPI::BWAPIClient.update();\n" +
- " if (!BWAPI::BWAPIClient.isConnected())\n" +
- " {\n" +
- " println(\"Reconnecting...\");\n" +
- " reconnect();\n" +
- " }\n" +
- " }");
- }
-
-
- private void implementGameStart() {
- out.println("println(\"Connecting to Broodwar...\");\n" +
- "\t\treconnect();\n" +
- "\t\tprintln(\"Connection successful, starting match...\");\n" +
- "\n" +
- "\t\tcls = env->GetObjectClass(obj);\n" +
- "\t\tjclass gamecls = env->FindClass(\"L" + context.getPackageName() + "/Game;\");\n" +
- "\t\tjclass unitCls = env->FindClass(\"L" + context.getPackageName() + "/Unit;\");\n" +
- "\t\tjclass playerCls = env->FindClass(\"L" + context.getPackageName() + "/Player;\");\n" +
- "\t\tjclass posCls = env->FindClass(\"L" + context.getPackageName() + "/Position;\");\n" +
- "\t\tjobject moduleObj = env->GetObjectField(obj, env->GetFieldID(cls, \"module\", \"L" + context.getPackageName() + "/AIModule;\"));\n" +
- "\t\tjclass moduleCls = env->GetObjectClass(moduleObj);\n" +
- "\t\tenv->SetObjectField(obj, env->GetFieldID(cls, \"game\", \"L" + context.getPackageName() + "/Game;\"), " +
- "env->CallStaticObjectMethod(gamecls, env->GetStaticMethodID(gamecls, \"get\", \"(J)L" + context.getPackageName() + "/Game;\"), (long)BroodwarPtr));\n" +
- "\n" +
- "\t\tjmethodID updateMethodID = env->GetMethodID(env->GetObjectClass(obj), \"update\", \"()V\");");
-
- out.println("\t\tjmethodID matchStartCallback = env->GetMethodID(moduleCls, \"onStart\", \"()V\");\n" +
- "\t\tjmethodID matchEndCallback = env->GetMethodID(moduleCls, \"onEnd\", \"(Z)V\");\n" +
- "\t\tjmethodID matchFrameCallback = env->GetMethodID(moduleCls, \"onFrame\", \"()V\");\n" +
- "\t\tjmethodID sendTextCallback = env->GetMethodID(moduleCls, \"onSendText\", \"(Ljava/lang/String;)V\");\n" +
- "\t\tjmethodID receiveTextCallback = env->GetMethodID(moduleCls, \"onReceiveText\", \"(L" + context.getPackageName() + "/Player;Ljava/lang/String;)V\");\n" +
- "\t\tjmethodID playerLeftCallback = env->GetMethodID(moduleCls, \"onPlayerLeft\", \"(L" + context.getPackageName() + "/Player;)V\");\n" +
- "\t\tjmethodID nukeDetectCallback = env->GetMethodID(moduleCls, \"onNukeDetect\", \"(L" + context.getPackageName() + "/Position;)V\");\n" +
- "\t\tjmethodID unitDiscoverCallback = env->GetMethodID(moduleCls, \"onUnitDiscover\", \"(L" + context.getPackageName() + "/Unit;)V\");\n" +
- "\t\tjmethodID unitEvadeCallback = env->GetMethodID(moduleCls, \"onUnitEvade\", \"(L" + context.getPackageName() + "/Unit;)V\");\n" +
- "\t\tjmethodID unitShowCallback = env->GetMethodID(moduleCls, \"onUnitShow\", \"(L" + context.getPackageName() + "/Unit;)V\");\n" +
- "\t\tjmethodID unitHideCallback = env->GetMethodID(moduleCls, \"onUnitHide\", \"(L" + context.getPackageName() + "/Unit;)V\");\n" +
- "\t\tjmethodID unitCreateCallback = env->GetMethodID(moduleCls, \"onUnitCreate\", \"(L" + context.getPackageName() + "/Unit;)V\");\n" +
- "\t\tjmethodID unitDestroyCallback = env->GetMethodID(moduleCls, \"onUnitDestroy\", \"(L" + context.getPackageName() + "/Unit;)V\");\n" +
- "\t\tjmethodID unitMorphCallback = env->GetMethodID(moduleCls, \"onUnitMorph\", \"(L" + context.getPackageName() + "/Unit;)V\");\n" +
- "\t\tjmethodID unitRenegadeCallback = env->GetMethodID(moduleCls, \"onUnitRenegade\", \"(L" + context.getPackageName() + "/Unit;)V\");\n" +
- "\t\tjmethodID saveGameCallback = env->GetMethodID(moduleCls, \"onSaveGame\", \"(Ljava/lang/String;)V\");\n" +
- "\t\tjmethodID unitCompleteCallback = env->GetMethodID(moduleCls, \"onUnitComplete\", \"(L" + context.getPackageName() + "/Unit;)V\");\n" +
- "\t\tjmethodID playerDroppedCallback = env->GetMethodID(moduleCls, \"onPlayerDropped\", \"(L" + context.getPackageName() + "/Player;)V\");");
-
- out.println("\t\twhile (true) {\n");
- implementConnectionRoutine();
- out.println("\t\t\tprintln(\"Game ready!!!\");\n" +
- "\n" +
- "\t\t\twhile (Broodwar->isInGame()) {\n" +
- "\t\t\t\t\n" +
- "\t\t\t\tenv->CallVoidMethod(obj, updateMethodID);\n");
- out.println("\n" +
- "\t\t\t\tfor(std::list::const_iterator it = Broodwar->getEvents().begin(); it!=Broodwar->getEvents().end(); it++)\n" +
- "\t\t\t\t {\n" +
- "\t\t\t\t\t switch (it->getType()) {\n" +
-
- "\t\t\t\t\t\t case EventType::MatchStart:\n" +
- "\t\t\t\t\t\t\t env->CallVoidMethod(moduleObj, matchStartCallback);\n" +
- "\t\t\t\t\t\t break;\n" +
- "\t\t\t\t\t\t case EventType::MatchEnd:\n" +
- "\t\t\t\t\t\t\t env->CallVoidMethod(moduleObj, matchEndCallback, it->isWinner());\n" +
- "\t\t\t\t\t\t break;\n" +
- "\t\t\t\t\t\t case EventType::MatchFrame:\n" +
- "\t\t\t\t\t\t\t env->CallVoidMethod(moduleObj, matchFrameCallback);\n" +
- "\t\t\t\t\t\t break;\n" +
- "\t\t\t\t\t\t case EventType::SendText:\n" +
- "\t\t\t\t\t\t\t env->CallVoidMethod(moduleObj, sendTextCallback, env->NewStringUTF(it->getText().c_str()));\n" +
- "\t\t\t\t\t\t break;\n" +
- "\t\t\t\t\t\t case EventType::ReceiveText:\n" +
- "\t\t\t\t\t\t\t env->CallVoidMethod(moduleObj, receiveTextCallback, env->CallStaticObjectMethod(playerCls, env->GetStaticMethodID(playerCls, \"get\", \"(J)L" + context.getPackageName() + "/Player;\"), (jlong)it->getPlayer()), env->NewStringUTF(it->getText().c_str()));\n" +
- "\t\t\t\t\t\t break;\n" +
- "\t\t\t\t\t\t case EventType::PlayerLeft:\n" +
- "\t\t\t\t\t\t\t env->CallVoidMethod(moduleObj, playerLeftCallback, env->CallStaticObjectMethod(playerCls, env->GetStaticMethodID(playerCls, \"get\", \"(J)L" + context.getPackageName() + "/Player;\"), (jlong)it->getPlayer()));\n" +
- "\t\t\t\t\t\t break;\n" +
- "\t\t\t\t\t\t case EventType::NukeDetect:\n" +
- "\t\t\t\t\t\t\t env->CallVoidMethod(moduleObj, nukeDetectCallback, env->NewObject(posCls, env->GetMethodID(posCls,\"\", \"(II)V\"), it->getPosition().x, it->getPosition().y));\n" +
- "\t\t\t\t\t\t break;\n" +
- "\t\t\t\t\t\t case EventType::UnitDiscover:\n" +
- "\t\t\t\t\t\t\t env->CallVoidMethod(moduleObj, unitDiscoverCallback, env->CallStaticObjectMethod(unitCls, env->GetStaticMethodID(unitCls, \"get\", \"(J)L" + context.getPackageName() + "/Unit;\"), (jlong)it->getUnit()));\n" +
- "\t\t\t\t\t\t break;\n" +
- "\t\t\t\t\t\t case EventType::UnitEvade:\n" +
- "\t\t\t\t\t\t\t env->CallVoidMethod(moduleObj, unitEvadeCallback, env->CallStaticObjectMethod(unitCls, env->GetStaticMethodID(unitCls, \"get\", \"(J)L" + context.getPackageName() + "/Unit;\"), (jlong)it->getUnit()));\n" +
- "\t\t\t\t\t\t break;\n" +
- "\t\t\t\t\t\t case EventType::UnitShow:\n" +
- "\t\t\t\t\t\t\t env->CallVoidMethod(moduleObj, unitShowCallback, env->CallStaticObjectMethod(unitCls, env->GetStaticMethodID(unitCls, \"get\", \"(J)L" + context.getPackageName() + "/Unit;\"), (jlong)it->getUnit()));\n" +
- "\t\t\t\t\t\t break;\n" +
- "\t\t\t\t\t\t case EventType::UnitHide:\n" +
- "\t\t\t\t\t\t\t env->CallVoidMethod(moduleObj, unitHideCallback, env->CallStaticObjectMethod(unitCls, env->GetStaticMethodID(unitCls, \"get\", \"(J)L" + context.getPackageName() + "/Unit;\"), (jlong)it->getUnit()));\n" +
- "\t\t\t\t\t\t break;\n" +
- "\t\t\t\t\t\t case EventType::UnitCreate:\n" +
- "\t\t\t\t\t\t\t env->CallVoidMethod(moduleObj, unitCreateCallback, env->CallStaticObjectMethod(unitCls, env->GetStaticMethodID(unitCls, \"get\", \"(J)L" + context.getPackageName() + "/Unit;\"), (jlong)it->getUnit()));\n" +
- "\t\t\t\t\t\t break;\n" +
- "\t\t\t\t\t\t case EventType::UnitDestroy:\n" +
- "\t\t\t\t\t\t\t env->CallVoidMethod(moduleObj, unitDestroyCallback, env->CallStaticObjectMethod(unitCls, env->GetStaticMethodID(unitCls, \"get\", \"(J)L" + context.getPackageName() + "/Unit;\"), (jlong)it->getUnit()));\n" +
- "\t\t\t\t\t\t break;\n" +
- "\t\t\t\t\t\t case EventType::UnitMorph:\n" +
- "\t\t\t\t\t\t\t env->CallVoidMethod(moduleObj, unitMorphCallback, env->CallStaticObjectMethod(unitCls, env->GetStaticMethodID(unitCls, \"get\", \"(J)L" + context.getPackageName() + "/Unit;\"), (jlong)it->getUnit()));\n" +
- "\t\t\t\t\t\t break;\n" +
- "\t\t\t\t\t\t case EventType::UnitRenegade:\n" +
- "\t\t\t\t\t\t\t env->CallVoidMethod(moduleObj, unitRenegadeCallback, env->CallStaticObjectMethod(unitCls, env->GetStaticMethodID(unitCls, \"get\", \"(J)L" + context.getPackageName() + "/Unit;\"), (jlong)it->getUnit()));\n" +
- "\t\t\t\t\t\t break;\n" +
- "\t\t\t\t\t\t case EventType::SaveGame:\n" +
- "\t\t\t\t\t\t\t env->CallVoidMethod(moduleObj, saveGameCallback, env->NewStringUTF(it->getText().c_str()));\n" +
- "\t\t\t\t\t\t break;\n" +
- "\t\t\t\t\t\t case EventType::UnitComplete:\n" +
- "\t\t\t\t\t\t\t env->CallVoidMethod(moduleObj, unitCompleteCallback, env->CallStaticObjectMethod(unitCls, env->GetStaticMethodID(unitCls, \"get\", \"(J)L" + context.getPackageName() + "/Unit;\"), (jlong)it->getUnit()));\n" +
- "\t\t\t\t\t\t break;\n" +
- "\n" +
- "\t\t\t\t\t }\n" +
- "\t\t\t\t }");
- out.println(
- "\t\t\t\tBWAPIClient.update();\n" +
- "\t\t\t\tif (!BWAPI::BWAPIClient.isConnected()) {\n" +
- "\t\t\t\t\t\tprintln(\"Reconnecting...\");\n" +
- "\t\t\t\t\t\treconnect();\n" +
- "\t\t\t\t}\n" +
- "\t\t\t}\n" +
- "println(\"Match ended.\");" +
- "\t\t}");
- }
-
private void implementHelpers() {
- out.println("void reconnect()\n" +
- "{\n" +
- "\twhile (!BWAPIClient.connect()) {\n" +
- " std::this_thread::sleep_for(std::chrono::milliseconds{ 1000 });\n" +
- " }\n" +
- "}\n" +
- "\n" +
- "\n");
-
out.println(
"void flushPrint(const char * text){\n" +
- "\tprintf(text);\n" +
- "\tfflush(stdout); \n" +
- "}\n" +
- "\n" +
- "void println(const char * text){\n" +
- "\tprintf(text);\n" +
- "\tflushPrint(\"\\n\");\n" +
- "}\n");
+ " printf(text);\n" +
+ " fflush(stdout); \n" +
+ "}\n" +
+ "\n" +
+ "void println(const char * text){\n" +
+ " printf(text);\n" +
+ " flushPrint(\"\\n\");\n" +
+ "}\n"
+ );
+ out.println();
}
- private void implementMirrorInit(List declarationList) {
- implementHelpers();
- out.println("JNIEXPORT void JNICALL Java_" + context.getPackageName() + "_Mirror_startGame(JNIEnv * env, jobject obj){");
+ private void implementMirror_initTables(List declarationList) {
+ out.println("JNIEXPORT void JNICALL Java_" + context.getPackageName() + "_Mirror_initTables(JNIEnv * env, jclass jclz){");
+ out.println(" println(\"Initializing constants tables\");");
implementVariablesBind(declarationList);
- implementGameStart();
out.println("}");
out.println();
}
+ private void implementMirror_getInternalGame() {
+ out.println(
+ "JNIEXPORT jobject JNICALL Java_" + context.getPackageName() + "_Mirror_getInternalGame(JNIEnv * env, jobject obj){\n" +
+ " jclass gamecls = env->FindClass(\"Lbwapi/Game;\");\n" +
+ " jmethodID getMethodID = env->GetStaticMethodID(gamecls, \"get\", \"(J)Lbwapi/Game;\");\n" +
+ " return env->CallStaticObjectMethod(gamecls, getMethodID, (long)BroodwarPtr);\n" +
+ "}\n"
+ );
+ out.println();
+ }
+
+ private void implementMirror_processGameEvents() {
+ out.println(
+ "JNIEXPORT void JNICALL Java_" + context.getPackageName() + "_Mirror_processGameEvents(JNIEnv * env, jobject obj){\n" +
+ " jclass cls = env->GetObjectClass(obj);\n" +
+ " jobject moduleObj = env->GetObjectField(obj, env->GetFieldID(cls, \"module\", \"Lbwapi/AIModule;\"));\n" +
+ " jclass moduleCls = env->GetObjectClass(moduleObj);\n" +
+ "\n" +
+ " jclass unitCls = env->FindClass(\"Lbwapi/Unit;\");\n" +
+ " jclass playerCls = env->FindClass(\"Lbwapi/Player;\");\n" +
+ " jclass posCls = env->FindClass(\"Lbwapi/Position;\");\n" +
+ "\n" +
+ " jmethodID matchStartCallback = env->GetMethodID(moduleCls, \"onStart\", \"()V\");\n" +
+ " jmethodID matchEndCallback = env->GetMethodID(moduleCls, \"onEnd\", \"(Z)V\");\n" +
+ " jmethodID matchFrameCallback = env->GetMethodID(moduleCls, \"onFrame\", \"()V\");\n" +
+ " jmethodID sendTextCallback = env->GetMethodID(moduleCls, \"onSendText\", \"(Ljava/lang/String;)V\");\n" +
+ " jmethodID receiveTextCallback = env->GetMethodID(moduleCls, \"onReceiveText\", \"(Lbwapi/Player;Ljava/lang/String;)V\");\n" +
+ " jmethodID playerLeftCallback = env->GetMethodID(moduleCls, \"onPlayerLeft\", \"(Lbwapi/Player;)V\");\n" +
+ " jmethodID nukeDetectCallback = env->GetMethodID(moduleCls, \"onNukeDetect\", \"(Lbwapi/Position;)V\");\n" +
+ " jmethodID unitDiscoverCallback = env->GetMethodID(moduleCls, \"onUnitDiscover\", \"(Lbwapi/Unit;)V\");\n" +
+ " jmethodID unitEvadeCallback = env->GetMethodID(moduleCls, \"onUnitEvade\", \"(Lbwapi/Unit;)V\");\n" +
+ " jmethodID unitShowCallback = env->GetMethodID(moduleCls, \"onUnitShow\", \"(Lbwapi/Unit;)V\");\n" +
+ " jmethodID unitHideCallback = env->GetMethodID(moduleCls, \"onUnitHide\", \"(Lbwapi/Unit;)V\");\n" +
+ " jmethodID unitCreateCallback = env->GetMethodID(moduleCls, \"onUnitCreate\", \"(Lbwapi/Unit;)V\");\n" +
+ " jmethodID unitDestroyCallback = env->GetMethodID(moduleCls, \"onUnitDestroy\", \"(Lbwapi/Unit;)V\");\n" +
+ " jmethodID unitMorphCallback = env->GetMethodID(moduleCls, \"onUnitMorph\", \"(Lbwapi/Unit;)V\");\n" +
+ " jmethodID unitRenegadeCallback = env->GetMethodID(moduleCls, \"onUnitRenegade\", \"(Lbwapi/Unit;)V\");\n" +
+ " jmethodID saveGameCallback = env->GetMethodID(moduleCls, \"onSaveGame\", \"(Ljava/lang/String;)V\");\n" +
+ " jmethodID unitCompleteCallback = env->GetMethodID(moduleCls, \"onUnitComplete\", \"(Lbwapi/Unit;)V\");\n" +
+ "\n" +
+ " for (std::list::const_iterator it = Broodwar->getEvents().begin(); it != Broodwar->getEvents().end(); it++)\n" +
+ " {\n" +
+ " switch (it->getType()) {\n" +
+ " case EventType::MatchStart:\n" +
+ " env->CallVoidMethod(moduleObj, matchStartCallback);\n" +
+ " break;\n" +
+ " case EventType::MatchEnd:\n" +
+ " env->CallVoidMethod(moduleObj, matchEndCallback, it->isWinner());\n" +
+ " break;\n" +
+ " case EventType::MatchFrame:\n" +
+ " env->CallVoidMethod(moduleObj, matchFrameCallback);\n" +
+ " break;\n" +
+ " case EventType::SendText:\n" +
+ " env->CallVoidMethod(moduleObj, sendTextCallback, env->NewStringUTF(it->getText().c_str()));\n" +
+ " break;\n" +
+ " case EventType::ReceiveText:\n" +
+ " env->CallVoidMethod(moduleObj, receiveTextCallback, env->CallStaticObjectMethod(playerCls, env->GetStaticMethodID(playerCls, \"get\", \"(J)Lbwapi/Player;\"), (jlong)it->getPlayer()), env->NewStringUTF(it->getText().c_str()));\n" +
+ " break;\n" +
+ " case EventType::PlayerLeft:\n" +
+ " env->CallVoidMethod(moduleObj, playerLeftCallback, env->CallStaticObjectMethod(playerCls, env->GetStaticMethodID(playerCls, \"get\", \"(J)Lbwapi/Player;\"), (jlong)it->getPlayer()));\n" +
+ " break;\n" +
+ " case EventType::NukeDetect:\n" +
+ " env->CallVoidMethod(moduleObj, nukeDetectCallback, env->NewObject(posCls, env->GetMethodID(posCls, \"\", \"(II)V\"), it->getPosition().x, it->getPosition().y));\n" +
+ " break;\n" +
+ " case EventType::UnitDiscover:\n" +
+ " env->CallVoidMethod(moduleObj, unitDiscoverCallback, env->CallStaticObjectMethod(unitCls, env->GetStaticMethodID(unitCls, \"get\", \"(J)Lbwapi/Unit;\"), (jlong)it->getUnit()));\n" +
+ " break;\n" +
+ " case EventType::UnitEvade:\n" +
+ " env->CallVoidMethod(moduleObj, unitEvadeCallback, env->CallStaticObjectMethod(unitCls, env->GetStaticMethodID(unitCls, \"get\", \"(J)Lbwapi/Unit;\"), (jlong)it->getUnit()));\n" +
+ " break;\n" +
+ " case EventType::UnitShow:\n" +
+ " env->CallVoidMethod(moduleObj, unitShowCallback, env->CallStaticObjectMethod(unitCls, env->GetStaticMethodID(unitCls, \"get\", \"(J)Lbwapi/Unit;\"), (jlong)it->getUnit()));\n" +
+ " break;\n" +
+ " case EventType::UnitHide:\n" +
+ " env->CallVoidMethod(moduleObj, unitHideCallback, env->CallStaticObjectMethod(unitCls, env->GetStaticMethodID(unitCls, \"get\", \"(J)Lbwapi/Unit;\"), (jlong)it->getUnit()));\n" +
+ " break;\n" +
+ " case EventType::UnitCreate:\n" +
+ " env->CallVoidMethod(moduleObj, unitCreateCallback, env->CallStaticObjectMethod(unitCls, env->GetStaticMethodID(unitCls, \"get\", \"(J)Lbwapi/Unit;\"), (jlong)it->getUnit()));\n" +
+ " break;\n" +
+ " case EventType::UnitDestroy:\n" +
+ " env->CallVoidMethod(moduleObj, unitDestroyCallback, env->CallStaticObjectMethod(unitCls, env->GetStaticMethodID(unitCls, \"get\", \"(J)Lbwapi/Unit;\"), (jlong)it->getUnit()));\n" +
+ " break;\n" +
+ " case EventType::UnitMorph:\n" +
+ " env->CallVoidMethod(moduleObj, unitMorphCallback, env->CallStaticObjectMethod(unitCls, env->GetStaticMethodID(unitCls, \"get\", \"(J)Lbwapi/Unit;\"), (jlong)it->getUnit()));\n" +
+ " break;\n" +
+ " case EventType::UnitRenegade:\n" +
+ " env->CallVoidMethod(moduleObj, unitRenegadeCallback, env->CallStaticObjectMethod(unitCls, env->GetStaticMethodID(unitCls, \"get\", \"(J)Lbwapi/Unit;\"), (jlong)it->getUnit()));\n" +
+ " break;\n" +
+ " case EventType::SaveGame:\n" +
+ " env->CallVoidMethod(moduleObj, saveGameCallback, env->NewStringUTF(it->getText().c_str()));\n" +
+ " break;\n" +
+ " case EventType::UnitComplete:\n" +
+ " env->CallVoidMethod(moduleObj, unitCompleteCallback, env->CallStaticObjectMethod(unitCls, env->GetStaticMethodID(unitCls, \"get\", \"(J)Lbwapi/Unit;\"), (jlong)it->getUnit()));\n" +
+ " break;\n" +
+ " }\n" +
+ " }\n" +
+ "}\n"
+ );
+ out.println();
+ }
+
+ private void implementMirror_BWAPIClientGetters() {
+ out.println(
+ "JNIEXPORT jboolean JNICALL Java_bwapi_Mirror_isConnected(JNIEnv * env, jclass jclz){\n" +
+ " return BWAPI::BWAPIClient.isConnected();\n" +
+ "}\n" +
+ "\n" +
+ "JNIEXPORT jboolean JNICALL Java_bwapi_Mirror_connect(JNIEnv * env, jclass jclz){\n" +
+ " return BWAPI::BWAPIClient.connect();\n" +
+ "}\n" +
+ "\n" +
+ "JNIEXPORT void JNICALL Java_bwapi_Mirror_disconnect(JNIEnv * env, jclass jclz){\n" +
+ " BWAPI::BWAPIClient.disconnect();\n" +
+ "}\n" +
+ "\n" +
+ "JNIEXPORT void JNICALL Java_bwapi_Mirror_update(JNIEnv * env, jclass jclz){\n" +
+ " BWAPI::BWAPIClient.update();\n" +
+ "}\n"
+ );
+ out.println();
+ }
+
private void implementVariablesBind(List declarationList) {
out.println("jclass cls;");
out.println("jmethodID getId;");
@@ -251,7 +238,12 @@ public class Bind {
}
public void implementBind(List declarationList) {
- implementMirrorInit(declarationList);
+ implementHelpers();
+ implementMirror_initTables(declarationList);
+ implementMirror_getInternalGame();
+ implementMirror_processGameEvents();
+ implementMirror_BWAPIClientGetters();
+
}
}
diff --git a/manual-bwapi-src/Mirror.java b/manual-bwapi-src/Mirror.java
index b311b5a..165469d 100644
--- a/manual-bwapi-src/Mirror.java
+++ b/manual-bwapi-src/Mirror.java
@@ -1,15 +1,11 @@
package bwapi;
-import bwapi.AIModule;
-import bwapi.BWEventListener;
-
import java.io.*;
import java.io.File;
import java.lang.Exception;
import java.lang.UnsupportedOperationException;
import java.util.*;
import java.util.regex.Pattern;
-import java.util.zip.*;
public class Mirror {
@@ -17,10 +13,6 @@ public class Mirror {
private AIModule module = new AIModule();
- private FrameCallback frameCallback;
-
- private static final boolean EXTRACT_JAR = true;
-
private static void extractResourceFile(String resourceFilename, String outputFilename) throws Exception {
InputStream in = Thread.currentThread().getContextClassLoader().getResourceAsStream(resourceFilename);
if (in == null)
@@ -94,6 +86,8 @@ public class Mirror {
System.exit(1);
if (!extractBwtaDataFiles())
System.exit(1);
+
+ initTables();
}
public Game getGame() {
@@ -105,26 +99,90 @@ public class Mirror {
}
/**
- * Starts the API, initializes all constants ( {@link UnitType}, {@link WeaponType} ) and the {@link Game} object.
- * This method blocks until the end of game.
+ * Initializes all BWAPI constant lookup tables.
*/
- public native void startGame();
+ private static native void initTables();
- private void update() {
- if (frameCallback != null) {
- frameCallback.update();
+ /**
+ * Initializes a connection to Broodwar, initializes the a {@link Game} object, and dispatches
+ * events to your listener as long as Broodwar is in a game. If this method is called before
+ * Broodwar is running, it will keep retrying until an initial connection can be established.
+ *
+ * The {@link Game} instance returned by {@link #getGame()} is only valid while this method
+ * is running. If your code holds a copy of this object anywhere else, do not try to use it
+ * again after this method returns.
+ *
+ * @param autoReconnect
+ * If true, will run an infinite loop allowing you to keep your bot running as many
+ * subsequent matches as desired. Will automatically reconnect to a Broodwar instance
+ * if the connection is interrupted.
+ * If false, will disconnect from Broodwar and return after the first match ends
+ * (regardless of how it ended). Will not attempt to reconnect to Broodwar if the
+ * connection is interrupted once the first match has been started. You can call
+ * {@link #startGame} again to run another match as needed.
+ */
+ public void startGame(boolean autoReconnect) {
+ try
+ {
+ System.out.println("Connecting to Broodwar...");
+ reconnect();
+ System.out.println("Connection successful, starting match...");
+
+ game = getInternalGame();
+
+ do {
+ System.out.println("Waiting...");
+ while (!game.isInGame()) {
+ update();
+ if (!isConnected()) {
+ System.out.println("Reconnecting...");
+ reconnect();
+ }
+ }
+
+ System.out.println("Game ready!!!");
+
+ while (game.isInGame()) {
+ processGameEvents();
+
+ update();
+ if (!isConnected()) {
+ System.out.println("Reconnecting...");
+ reconnect();
+ }
+ }
+
+ System.out.println("Match ended.");
+ } while(autoReconnect);
+
+ System.out.println("Finished. Disconnecting from Broodwar...");
+ } catch (InterruptedException e) {
+ System.out.println("Interrupted. Disconnecting from Broodwar...");
+ }
+ if (isConnected())
+ disconnect();
+
+ game = null;
+ }
+
+ private void reconnect() throws InterruptedException {
+ while (!connect()) {
+ Thread.sleep(1000);
}
}
- /*public void setFrameCallback(bwapi.Mirror.FrameCallback frameCallback) {
- this.frameCallback = frameCallback;
- } */
+ /**
+ * Returns the current connection state to a running Broodwar instance.
+ */
+ public static native boolean isConnected();
- /**
- * The simplest interface to receive update event from Broodwar. The {@link #update()} method is called once each frame.
- * For a simple bot and implementation of this interface is enough, to receive all in game events, implement {@link BWEventListener}.
- */
- /*public*/ private interface FrameCallback {
- public void update();
- }
-}
\ No newline at end of file
+ private static native boolean connect();
+
+ private static native void disconnect();
+
+ private static native void update();
+
+ private native Game getInternalGame();
+
+ private native void processGameEvents();
+}