![]() |
VR-Link API Documentation for HLA 4
|
VR-Link for Java enables the development of distributed simulation applications using the VR-Link library from Java. It combines Java code with platform-specific native code, providing a bridge between Java and the supported VR-Link (C/C++) platforms. Due to its reliance on native code, VR-Link for Java is only available on platforms supported by VR-Link (C/C++), and only 64-bit native libraries are provided.
This documentation guides you through the process of building Java applications with VR-Link for Java, including setup, configuration, and usage examples. The F-18 example, located in ./java/examples, demonstrates key concepts and serves as a reference implementation. Familiarity with the Java language is assumed.
VR-Link for Java supports Windows and Linux platforms, with only 64-bit native libraries provided. Ensure you are using a supported Java version (Java 21 or later is required). Native libraries must match the architecture of your JVM (64-bit JVM with 64-bit native libraries).
Assuming you have a Java runtime installed and in your path (try the command 'java -version' to confirm), you must tell the Java Virtual Machine (JVM) two things:
Tell the JVM where the Java code is by using the CLASSPATH environment variable, or the -cp command line option. Remember that JVM command line options come before the class you want to run, and the command line options to the application come last:
Tell the vrlj Java application where the native libraries are by using the bundled native libraries, by choosing the working directory, or by using the –loadPath argument to the application.
For an example on Microsoft Windows, if your current working directory contains the jar files f18.jar and vrlj_VC15.jar (which contains bundled native libraries), you could run the F18 example like this:
Remember to use the file and path separators for your platform.
You could use the –loadPath argument to the F18 example application to locate the native libraries:
To use a relative classpath run the listen example application from the VR-Link /bin or /bin64 directory (Windows) or /lib or /lib64 directory (linux):
Or to run the talk example application using bundled native libraries on Windows (VC15):
Example using the CLASSPATH environment variable:
Set the CLASSPATH environment variable to include the Java jars and classfiles:
Now the JVM can find all the examples and the -cp option is unecessary, and the bundled native libraries are used.
You need a javac compiler that supports at least Java 21. Add the correct jar file to your Java classpath to build and to run your application.
All Java code is contained in a single JAR file. However, native code might be loaded differently depending upon configuration. The basic vrlj.jar file contains no native libraries; the location of the native libraries must be provided. Other jar files contain native library code for a single platform (64-bit native code only) depending on the name of the library.
If a jar containing native library code is used, you just need to add that jar to your Java classpath. At runtime, the native code will be loaded from the jar. Since each jar contains native code for a different platform, the jar corresponding to the execution platform must be used in the classpath at runtime. For example, vrlj_VC15.jar contains 64-bit DLLs for Microsoft Windows compiled using Visual C++ 15.0.
If the vrlj.jar file is included in the Java classpath, it contains no native code. The path to the shared libraries must be specified by calling the initializer method setLoadPath(). Since shared libraries load their dependent shared libraries automatically, it is good practice to keep all the related shared libraries in the same directory. The load path may also be set via the command line option –loadPath if the Java application uses the ExerciseConnectionInitializer to parse the command line as shown in the example applications.
If no setLoadPath() (or –loadPath) is specified, the current working directory will be used, check System.getProperty("user.dir").
The name of the shared library may be specified using setDynamicLibraryName(). The default is managedInterface. If the environment variable MAK_VRL_USE_DEBUG_FOR_CPLUSPLUS is defined, then the debug version of the native code is loaded.
To add vrlj_Xxx.jar (platform specific with bundled native libraries) to an Eclipse project, simply add that jar to the build path.
To add vrlj.jar to an Eclipse project, add the jar to the build path normally. To load the native libraries, there are several ways:
To load the VR-Link for Java example applications into your workspace, select Import... from the File menu. For the source, select Existing Projects into Workspace (under General), and then press next. Select the root directory as /java/examples directory under your VR-Link installation and eclipse should find all the examples and add them to the Projects shown. If you do not copy the examples into the workspace,the example applications should already be configured to use bundled native libraries and be ready to run.
If you make a copy of the projects in your workspace, you will need to add the vrlj.jar or vrlj_Xxx.jar to the Eclipse build path for each example project.
VR-Link applications connect to an exercise through an exercise connection. Currently only a single exercise connection may be opened at a time; attempting to open a second exercise connection concurrently will result in undefined behaviour.
Exercise connections are implementations of the Java interface ExerciseConnection. Higher level VR-Link classes use the ExerciseConnection to set and receive state information and other data. The member functions of ExerciseConnection allow an application to do the following:
ExerciseConnections are created by the ExerciseConnectionFactory class. There is one implementation.
An ExerciseConnection takes responsibility for various resources such as network sockets and managed memory. To simplify its use, ExerciseConnection implements the AutoCloseable interface introduced in Java 7.
... exConn is automatically closed at this point ...
The ExerciseInitializer class should contain all information necessary to initialize an ExerciseConnection (or use default values), and may contain additional information for user application. The method parseCmdLine(String[] args) simplifies parsing command line arguments passed to the user application, to read the configuration information.
VR-Link for Java uses the open source project jcommander to parse command line parameters. The jcommander code is bundled in the same jar as the VR-Link for Java code.
Refer to the F-18 example, to the F18Init.java file for an example of how to create a custom ExerciseInitializer.
For example, look at the markings member variable:
This tells jcommander that the command line parameter –f18Markings should be mapped into the markings member variable. When the command line usage is printed, the hint "hull markings" will be shown next to the –f18Markings option.
VR-Link for Java shares a single thread with your application; no extra threads run for background processing such as send DIS heartbeats or HLA housekeeping tasks. Each ExerciseConnection has a drainInput() method which performs background processing and must be called periodically (typically at least once per second).
VR-Link for Java methods are not thread-safe. User applications may use any threads desired, but must not call any VR-Link for Java methods simultaneously from multiple threads. Strategies such as locking or messaging could be employed to enforce this requirement.
VR-Link for Java will not access or modify simulation objects and interactions other than during the drainInput() call. So a typical way to use parallelism in a Java simulation application is to use multiple threads right after drainInput() finishes, and make sure all those threads finish (join) before the next call to drainInput() begins.
VR-Link for Java methods are not thread-safe. All calls to VR-Link methods must be serialized; do not call any VR-Link for Java methods simultaneously from multiple threads. Use synchronization or message passing to avoid concurrent access. A recommended strategy is to perform all VR-Link operations in a single thread, or to use locking mechanisms to ensure exclusive access. VR-Link for Java will not access or modify simulation objects and interactions except during the drainInput() call, so parallelism can be achieved by performing multi-threaded work after drainInput() completes and before the next call begins.
To publish an object to the network, start with a PublisherFactory obtained from an exercise connection, then get an ObjectPublisher for a particular kind of object.
Each PublisherFactory creates ObjectPublishers which publish to the same ExerciseConnection. PublisherFactory has methods to create publishers for each type of simulation object such as an Entity.
To update myEntity and publish to the network:
A common way to write simulation code is to use a time-stepped loop. The example below is taken from the talk example.
First, note that drainInput() MUST be called even though we are ignoring all input (received interactions, updates, etc.). In this example we are calling it every simulation frame, every few milliseconds (depending on the time step dt).
Also note that simply updating the time does not affect the entity position (or anything else about the entity). The entity motion, etc., must be updated by the user application. The above code uses a very simple motion model that updates the position similar to dead reckoning. Other, more detailed motion models are possible, for example a vehicle that follows roads or a ship affected by ocean currents.
A reflected object is a class used to store information about an object that has been discovered, updated and deleted by the exercise connection.
Each exercise connection tracks all reflected objects in a ReflectedObjectCollection, accessed from exConn.getReflectedCollection(). This collection implements the Map interface where the map key is some implementation ObjectIdentifier (for Entity it is an EntityName). ReflectedObjectCollection also extends the ObjectDispatcher interface, allowing registration for callbacks when objects are created, updated, or deleted.
To define a collection which is a particular subset of objects, you can define a ReflectedMap for a particular class of object, and a particular selection criteria. A selection criteria defines a test for inclusion: when the criteria is applied to an object it passes (criteria returns true) and is included in the ReflectedMap, or else it fails and is removed. Once a collection is created with a specified criteria, the criteria may not be changed. Instead, create a new collection with a different criteria. For convenience, a ReflectedMap is pre-defined for each type of object, for example, ReflectedEntityMap.
The example below shows a ReflectedEntityMap which is automatically updated and maintained by the ExerciseConnection exConn:
Alternatively, you could iterate through all objects and check which are Entity objects as follows:
Interactions are handled differently than objects. Typically, interactions are created and sent one time, then received and reacted to appropriately. An example of such interaction is the FireInteraction. The f18 example has the ability to fire at other entities, and it does so with fire interactions.
Sending an interaction is as simple as creating one, setting its data, then sending it using the exercise connection.
To illustrate receiving an interaction, consider the code fragment below from the Listen example. Note the Java 8 lambda syntax for the callback method definition.
Each Interaction class contains convenience member methods addListener and removeListener for adding and removing InteractionListener callbacks. InteractionListener defines a single method process(intr) which takes an interaction as its only argument. In the previous example, the handler method for incoming fire interactions is defined using the Java 8 lambda syntax, where 'fire' is the argument which receives the fire interaction.
The same example in older syntax using an anonymous inner class looks like this:
Native Library Loading Issues:** If you encounter errors such as UnsatisfiedLinkError, ensure that the native libraries are present in the specified load path and match your JVM architecture. Use the --loadPath argument or setLoadPath() method to specify the location of native libraries. Also verify that your CLASSPATH and PATH (or LD_LIBRARY_PATH on Linux) environment variables are set correctly.
Version Compatibility:** Make sure the VR-Link for Java JAR files and native libraries are from the same release and match your platform and compiler version.
General Tips:** Refer to the example applications and the VR-Link Developer Guide for additional troubleshooting steps and configuration details.
[Home] [Top of Page]