Skip to content
Glen edited this page Feb 17, 2015 · 2 revisions

Modifying JNIBWAPI (C++ side)

If you run into a limitation of JNIBWAPI, such as a method in Game that is not implemented, you may want to improve JNIBWAPI by modifying the C++/Java interface. This tutorial outlines how to recompile the client-bridge DLL, and how to add a new function to the JNI interface.

Requirements

First, follow the setup guide on the getting started page.

You will also need:

Ensure the JAVA_HOME environment variable exists and is set to a Java JDK (1.7+) folder (how to set JAVA_HOME).

Setting Up Visual Studio (2012+)

Simply open src/c/client-bridge.vcxproj and try building the project (release, win32).

If you get an error about missing jni.h, make sure your JAVA_HOME is set correctly then restart Visual Studio and/or Windows.

Adding a new native method

This example will create a simple print function to allow us access to BWAPI::Game->printf(). To begin with, we will add the new method in Java. Open JNIBWAPI.java and add the following line:

public native void printText(String text);

Recompile your JNIBWAPI project.

Generating the new C++ header

Included in the JNIBWAPI distributable/repository is a simple batch file that will generate a C++ header containing the appropriate declarations. It works by reading from JNIBWAPI.java, so if you add a new native method to JNIBWAPI.java, and run the batch file, it will automatically generate the new C++ declarations for you.

This means that you must not edit the header file (jnibwapi_JNIBWAPI.h) by hand - it is supposed to be machine generated from your Java class containing the interface.

To generate the new header file, simply run src/c/GenerateJNIHeader.bat

Implementing the new function

Open up jnibwapi_JNIBWAPI.h and have a look at the interface declarations. We're interested in the one that we just added to the interface (printText). It should look like this:

/*
 * Class:     jnibwapi_JNIBWAPI.h
 * Method:    printText
 * Signature: (Ljava/lang/String;)V
 */
JNIEXPORT void JNICALL Java_jnibwapi_JNIBWAPI_printText
  (JNIEnv *, jobject, jstring);

We'll be implementing this function in client-bridge.cpp (or ExampleAIClient.cpp if you used the VS2008 method above).

JNIEXPORT void JNICALL Java_jnibwapi_JNIBWAPI_printText
  (JNIEnv * env, jobject jObj, jstring message)
{
		const char *messagechars = env->GetStringUTFChars(message, 0);
		Broodwar->printf(messagechars);
		env->ReleaseStringUTFChars(message, messagechars);
}

First, we need to convert the message string to an ASCII C-String, (java strings are unicode). That is why we make a call to the JNIEnv to convert it. Note that with integers (and I think floats and doubles too?) you will not need to make a call to the environment in order to convert them to their C++ equivalents - implicit conversion allows us to return a C++ int for a JNI function returning a jint, and use a jint in place of a C++ int in our C++ code, etc.

Secondly, we make the call to BWAPI that we wanted - printf - in order to display the string in Starcraft:Brood War. Finally, we call ReleaseStringUTFChars which just indicates to the JNI environment that the native method no longer needs the UTF-8 string returned by GetStringUTFChars, freeing up the memory allocated for string conversion.

Save, set the project output to "Release" and "Win32" (drop down box at the top of the Visual Studio window) and then build the project.

If you copied the client-bridge-x86.dll and client-bridge-amd64.dll from release/ during the Getting Started guide, copy the newly compiled ones out of the release folder to replace the older ones in the main JNIBWAPI directory.

You should now be able to use the new native method in your JNIBWAPI project simply by making a call to that method eg: bwapi.printText("Hello World!");