Custom VASSAL classes and elements
Custom Classes allow you to override parts of VASSAL’s code to create your own custom features. They can range from overriding single aspects of VASSAL, such as an oblique hexagonal grid numbering, to a larger collection of classes that touch almost every aspects of VASSAL e.g., VASL.
For simple custom code, a simplified workflow can be used, while for a larger collection, a full workflow is more appropriate.
Assumptions
The below assumes that you are
- Familiar with Java and development with Java.
- Familiar with running programs from the command line. See also here.
- Familiar with extracting and updating files in a ZIP archive.
- A fair bit of patience
Simple Workflow
If you plan to override a single or a few features of VASSAL - for example to have obligue hexagonal grid numbering - you typically only need to provide a few user defined Java classes. For this kind of workflow, you need
-
A code editor. Examples are anything from a general purpose text editor, over more dedicated code editors, to fully fledge Integrated Development Environments (IDE). Some examples of editors are given below
Editor Platform Type NotePad General purpose TextEdit General purpose TextEditor General purpose Vi General purpose Emacs General purpose BlueJ Code editor Visual Studio Code Code editor XCode Code editor Kate Code editor IntelliJ IDE Eclipse IDE JDeveloper IDE Choose what you are comfortable with - not what has the most features - you don’t need them.
-
The location of the VASSAL Java class archive
Vengine.jar
. Presumably you have already installed VASSAL on your target machine, and you will therefore have that file. If not, then download and install VASSALIf VASSAL is installed in directory then you can find the file in some sub-directory of directory, often directory/lib/Vengine.jar. Some common examples are
Platform VASSAL installation Vengine.jar
locationC:\Program Files\VASSAL
C:\Program Files\VASSAL\lib\Vengine.jar
C:\Users\username\AppData\Programs\VASSAL
C:\Users\username\AppData\Programs\VASSAL\lib\Vengine.jar
/Applications/VASSAL.app/Contents/MacOS/
/Applications/VASSAL.app/Contents/Resources/Java/Vengine.jar
/home/username/Applications/VASSAL.app/Contents/MacOS/
/home/username/Applications/VASSAL.app/Contents/Resources/Java/Vengine.jar
/opt/VASSAL
/opt/VASSAL/lib/Vengine.jar
/home/username/VASSAL
/home/username/VASSAL/lib/Vengine.jar
where
username
is your local user name. -
A Java compiler.
-
An internet connection so you can look at the VASSAL source code at GitHub.
* Although VASSAL comes with a full Java Runtime Environment (JRE) on these platforms, it does not include the Java compiler.
You may also want to look at some examples and templates.
Write your custom code - say MyElement.java
- in your editor of choice. Once you have completed that, then you need to compile it into a class
$ javac -cp Vengine_file_location MyElement.java
where Vengine_file_location
is the location of Vengine.jar
as discussed above. This will create MyElement.class
which can be included into your VASSAL module.
See also here for more on how to run programs from the command line.
For example, if VASSAL is installed in /opt/VASSAL
, then the above command line will be
$ javac -cp /opt/VASSAL/lib/Vengine.jar MyElement.java
If you have more files - say A,java
and B.java
- you can compile them in one go or one at a time - e.g., with VASSAL installed in C:\Program Files\VASSAL
$ javac -cp "C:\Program Files\VASSAL\lib\Vengine.jar" A.java B.java
Full Workflow
In order to get started creating a custom class, you should first:
- Be familiar with Git, and obtain a copy of the VASSAL code (see Using Git to contribute to VASSAL development)
- Install the IntelliJ Integrated Development Environment and make sure you can build the VASSAL code (see Getting started with Intellij)
Now, make a separate folder for your custom classes project (NOT under the folder where you have VASSAL code stored, etc), and start a new git local repository there.
$ mkdir MyCustomClasses
$ cd MyCustomClasses
$ git init
Then, clone the VASSAL custom code template:
$ git clone https://github.com/vassalengine/vassal-module-template
That grabs our module template (source code for sample custom classes, and a Maven project file) from the VASSAL Git repository.
Then, perform these steps:
- Launch IntelliJ
- From the File menu, select Open…
- Browse to your
MyCustomClasses
folder, and inside thevassal-module-template
sub-directory, open thepom.xml
file. - You will be informed this is a Maven project and asked if you want to open it as a project - click Yes.
- You may need to adjust the location of your VASSAL installation in the project settings.
The project will now open, and you will see the VASSAL custom class “template”, which contains examples of how to create custom classes (e.g. a MyChatter
class to customize the Chat Log). You can build these and experiment with them if you like, and learn how to install them in your modules.
Information on how to install a particular class in your module is contained in the comments of the .java
files in the template, e.g. MyChatter.java
..java.
Once you’ve experimented with using the sample custom classes we have provided, you are ready to branch out and start customizing classes in your own way!
Install classes into a module
Add the .class
files to the module
-
Using what ever ZIP file manager you like, open up the module file (
.vmod
) in that manager.Note, some platforms - notably
Windows - associate file types with file-name endings, rather than the actual file content. On those platforms you may need to temporarily rename the module from ending in
.vmod
to.zip
. -
Find the
.class
files that you have compiled, and add them to the archive.-
If you have put your classes into a
package
or packages, you must add your classes with a corresponding directory structure rooted in the root of the ZIP archive.For example, suppose you have the class
package ak; class ObliqueHexGridNumbering ...
Then the class file
ObliqueHexGridNumbering.class
must be added to a sub-directory namedak
inside the ZIP archive.If you have multiple packages or nested packages, be sure to add your
.class
files into the correct sub-directory that corresponds to those packages.
-
-
When you have added your
.class
files, close the ZIP file manager.If you had to rename your module from ending in
.vmod
to.zip
, above, then you should rename the module file back to ending in.vmod
now.
Use the custom class in the VASSAL Editor
-
Right-click the element to which you want to add a custom element.
For example, if you want to add an oblique hexagonal grid numbering to some hexagonal grid, you should right click the
[Hex Grid]
element. -
In the context menu, select Add imported class
-
This will open a simple dialog in which you must enter the fully qualified class name.
Continuing the example above were we created the class
ObliqueHexGridNumbering
in the packageak
, the fully qualified class name isak.ObliqueHexGridNumbering
which is what should be entered into the dialog box. -
Press OK.
-
Now, you can double-click the user defined element to edit its properties.
Modifying the buildFile.xml
directly
-
Open up the module file (
.vmod
) in your favourite ZIP file manager (see above). -
Find the file
buildFile.xml
at the root of ZIP archive. -
If you ZIP file manager allows you to modify files in-place, then go a head and open the
buildFile.xml
in your favourite text editor.If the ZIP file manager cannot modify files in-place, then extract the
buildFile.xml
file to disk, and then open it up in your favourite text editor. -
Find the element you want to add your custom code to.
For example, if you are adding an oblique hexagonal grid numbering to a hex grid, find that hex grid tag
<VASSAL.build.module.map.boardPicker.board.HexGrid ...> </VASSAL.build.module.map.boardPicker.board.HexGrid>
-
Add the custom element to that element.
Continuing the above example
<VASSAL.build.module.map.boardPicker.board.HexGrid ...> <ak..ObliqueHexGridNumbering ...> </ak..ObliqueHexGridNumbering> </VASSAL.build.module.map.boardPicker.board.HexGrid>
Note that the XML tag must be the fully qualified class name.
-
Save the
buildFile.xml
.If your ZIP file manager allows you to do in-place modifications, then you should be done.
If not, then open the module in the ZIP file manager and add the updated
buildFile.xml
. Save and close the module file.
Walk-through of an example
Let us walk through ObliqueHexGridNumbering.java
mentioned a couple of times above.
To start
package ak;
We define the package we want to put the code into. Here ak
(because this code was originally written for Afrika Korps)
Next, we import some classes that we need.
import java.awt.Point;
import org.apache.commons.lang3.ArrayUtils;
import VASSAL.build.Buildable;
We want to make a new kind of hex grid numbering, so we want to create a derivative of the standard HexGridNumbering
numbering class. Thus we import that too.
import VASSAL.build.module.map.boardPicker.board.mapgrid.HexGridNumbering;
Now for our code. We will call our class ObliqueHexGridNumbering
which will be public
and derive from the standard HexGridNumbering
.
Note, we could have made the package oblique
and then called the class HexGridNumbering
, because we will use the fully qualified class names and hence there’s no problem with name collisions.
public class ObliqueHexGridNumbering extends HexGridNumbering {
We will add the attribute direction
to the other attributes of the default HexGridNumbering
. This member (a boolean
) will say whether the grid slants right or left
public boolean direction = true;
public static final String DIRECTION = "direction"; //NON-NLS
Here, we’ve also added the string constant DIRECTION
which we will use to define the editable interface.
Next up, we override the methods getAttributeDescriptions
, getAttributeNames
, getAttributeTypes
, and getAttributeValueString
to add our DIRECTION
attribute to the attributes of the default HexGridNumbering
@Override
public String[] getAttributeDescriptions() {
return ArrayUtils.add(super.getAttributeDescriptions(),
"Slanted right");
}
@Override
public String[] getAttributeNames() {
return ArrayUtils.add(super.getAttributeNames(), DIRECTION);
}
@Override
public Class<?>[] getAttributeTypes() {
return ArrayUtils.add(super.getAttributeTypes(),Boolean.class);
}
@Override
public String getAttributeValueString(String key) {
if (DIRECTION.equals(key))
return String.valueOf(direction);
else
return super.getAttributeValueString(key);
}
These four methods will alert the VASSAL editor and back-end to the existence of the DIRECTION
attribute. Next, we also need to be able to set that attribute
@Override
public void setAttribute(String key, Object value) {
if (DIRECTION.equals(key)) {
if (value instanceof String)
value = Boolean.valueOf((String) value);
direction = (Boolean) value;
}
else
super.setAttribute(key, value);
}
That’s it for the attribute.
Now for the real meat of the class. We want to change the numbering of hex rows so that it becomes oblique. This we do in the two following methods
@Override
public int getRow(Point p) {
return slantRow(super.getRow(p),super.getColumn(p));
}
public int slantRow(int row, int column)
{
return direction ?
(int)Math.floor(column/2) + row :
row - (int)Math.floor(column/2)+1;
}
The method getRow
overrides the same method from the default HexGridNumbering
, and uses the computations done by slantRow
. In that method, we calculate the new row number based on both the current row and column number.
That finishes our class.
}
Pretty simple, eh!?