# Creating Custom Classes

**URL:** <https://forum.vassalengine.org/t/creating-custom-classes/84963>\
**Category:** Documentation\
**Tags:** tutorial\
**Created:** [April 9, 2025, 7:00pm UTC](https://forum.vassalengine.org/t/creating-custom-classes/84963 "2025-04-09T19:00:04Z")\
**Posts on this page:** 1\
**Showing post:** 1

<div class="post-metadata">

**Author:** ![marktb1961](https://forum.vassalengine.org/user_avatar/forum.vassalengine.org/marktb1961/32/231_2.png) [@marktb1961](https://forum.vassalengine.org/u/marktb1961)\
**Post date:** [April 9, 2025, 7:00pm UTC](https://forum.vassalengine.org/t/creating-custom-classes/84963/1 "2025-04-09T19:00:04Z")

</div>

# 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](https://gitlab.com/wargames_tex/afrikakorps_tex/-/blob/master/ak/ObliqueHexGridNumbering.java?ref_type=head), to a larger collection of classes that touch almost every aspects of VASSAL e.g., [VASL](https://github.com/vasl-developers/vasl).

For simple custom code, a [simplified workflow](#simple-workflow) can be used, while for a larger collection, a [full workflow](#full-workflow) is more appropriate.

## Assumptions

The below assumes that you are

- Familiar with [Java](https://java.com) and development with Java.
- Familiar with running programs from the command line. See also [here](https://forum.vassalengine.org/t/how-to-convert-to-a-module-from-other-tools-to-vassal/84940).
- 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](https://gitlab.com/wargames_tex/afrikakorps_tex/-/blob/master/ak/ObliqueHexGridNumbering.java?ref_type=heads) - 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

- 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 VASSAL](https://vassalengine.org/download.html)

- A [Java](https://java.com) compiler, version 17 or later

- An internet connection so you can look at the [VASSAL source code](https://github.com/vassalengine/vassal) at GitHub.

[\*](#footnote-java) 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](https://github.com/vassalengine/vassal-module-template).

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

```Shell
$ javac --release 17 -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](#include-class).

See also [here](https://forum.vassalengine.org/t/how-to-convert-to-a-module-from-other-tools-to-vassal/84940) 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

```Shell
$ javac --release 17 -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`

```Shell
$ javac --release 17 -cp "C:\Program Files\VASSAL\lib\Vengine.jar" A.java B.java

```

![debian](https://forum.vassalengine.org/uploads/default/original/2X/6/6a99d88a27284e1728eedc25c9de3fd8b00df8da.png) If you installed the [Debian](https://forum.vassalengine.org/t/installation-instructions/85146#Debian) package of Vassal, then the JAR file is in `/usr/share/java/Vengine.jar`.

![redhat](https://forum.vassalengine.org/uploads/default/original/2X/8/8f4dec2204e54c851dc1fbfa49633bd2420c7dc7.png) If you installed the [RedHat](https://forum.vassalengine.org/t/installation-instructions/85146#RedHat) package of Vassal, then the JAR file is in `/usr/share/java/Vengine.jar`.

![macosx](https://forum.vassalengine.org/uploads/default/original/2X/c/c24d21f1dbd9387b7973e19633ee3e5e1f63f213.png) On MacOS, the JAR file is in `/Applications/VASSAL.app/Content/Resources/Java/Vengine.jar`.

![windows](https://forum.vassalengine.org/uploads/default/original/2X/6/6493154fc0bdf2bbf13fe4264cfbd26389f67e37.png) On Windows, the JAR file is typically in `C:\Program Files\VASSAL\<version>\lib\Vengine.jar`.

## Full Workflow

In order to get started creating a custom class, you should first:

- Be familiar with [Git](https://git.org), and obtain a copy of the VASSAL code (see [Using Git to contribute to VASSAL development](https://forum.vassalengine.org/t/using-git-to-contribute-to-vassal-development/79286/1))
- Install the [IntelliJ](https://www.jetbrains.com/idea/) Integrated Development Environment and make sure you can build the VASSAL code (see [Getting started with Intellij](https://forum.vassalengine.org/t/getting-started-with-intellij-in-progress/79379/1))

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.

```Shell
$ mkdir MyCustomClasses
$ cd MyCustomClasses
$ git init

```

Then, clone the VASSAL [custom code template](https://github.com/vassalengine/vassal-module-template):

```Shell
$ 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](https://www.jetbrains.com/help/idea/run-for-the-first-time.html)
- From the **File** menu, select **Open…**
- Browse to your `MyCustomClasses` folder, and inside the `vassal-module-template` sub-directory, open the `pom.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`](https://github.com/vassalengine/vassal-module-template/blob/master/src/main/java/my_custom_component/MyChatter.java) 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](#instal-classes).

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`](https://github.com/vassalengine/vassal-module-template/blob/master/src/main/java/my_custom_component/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.

- Find the `.class` files that you have compiled, and add them to the archive.

- When you have added your `.class` files, close the ZIP file manager.

#### Using the command line

The utility `zip` available on all platforms can update a ZIP archive with files. Suppose our compiled code lives in the subdirectory `ak` and we want to add it to the module `AfrikaKorps.vmod`, then we can simply do

```auto
$ zip -u -r AfrikaKorps.vmod ak

```

That will add all the files in `ak` to the module file in the “subdirectory” `ak`.

### Use the custom class in the VASSAL Editor

- Right-click the element to which you want to add a custom 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.

- 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.

- Find the element you want to add your custom code to.

- Add the custom element to that element.

- Save the `buildFile.xml`.

## Walk-through of an example

Let us walk through `ObliqueHexGridNumbering.java` mentioned a couple of times above.

To start

```Java
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.

```Java
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`](https://github.com/vassalengine/vassal/blob/master/vassal-app/src/main/java/VASSAL/build/module/map/boardPicker/board/mapgrid/HexGridNumbering.java) numbering class. Thus we import that too.

```auto
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.

```Java
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

```Java
    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`

```Java
    @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

```Java
    @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

```Java
    @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`](https://github.com/vassalengine/vassal/blob/master/vassal-app/src/main/java/VASSAL/build/module/map/boardPicker/board/mapgrid/HexGridNumbering.java#L323), 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.

```Java
}

```

Pretty simple, eh!?

## Some examples of custom code

- [`ObliqueHexGridNumbering`](https://gitlab.com/wargames_tex/vassal_my_contrib/-/tree/master/oblique?ref_type=heads)
- [For _A Victory Lost_](https://github.com/morvael/vsql-morvael-avl/tree/main)
- [For _Red Star Rising_](https://github.com/morvael/vsql-morvael-rsr)
- [For _Squad Leader_](https://github.com/uckelman/vsql/tree/master)
- [For _Trouble in the East_ and _Operational Combat Series_](https://github.com/uckelman/tite-ocs)
- [For _Advanced Squad Leader_](https://github.com/vasl-developers/vasl)
- [`MyChatter`](https://github.com/vassalengine/vassal-module-template)
- [Animated symbolic dice](https://gitlab.com/wargames_tex/vassal_my_contrib/-/tree/master/animdice?ref_type=heads)
- [`PieceMover` that allows more flexibility for restricting movement](https://gitlab.com/wargames_tex/vassal_my_contrib/-/tree/master/piecemover?ref_type=heads)

---

_[View the full topic](https://forum.vassalengine.org/t/creating-custom-classes/84963)._
