Programming

From Vassal
(Redirected from Faq programming)

Programming VASSAL

A collection of queries, tips and code fragments that might be useful.

PLEASE NOTE: The code examples are fragments to illustrate the point and are incomplete and displayed out of context.

I want to help with VASSAL programming. How do I go about this?

Our main page under Engine Development has our most up-to-date information on what we're up to, what needs doing, and how to get involved.

Meanwhile here are some things you can do to get started:

  • Install git and use it to obtain the VASSAL source code. Our guide to using git with VASSAL is here.
  • Install a Java Development Environment (Look here).
  • Register at the GitHub site. Look at the issues list. The latest "pull requests" (PRs) list shows what has been happening.
  • Start studying! Use the debugger in your IDE to see what makes VASSAL tick!
  • Have a look at the Developer's Corner page.
  • Read the programming tutorials.
  • Ask questions! Don't be afraid to ask for help, VASSAL is a complex, but brilliantly engineered piece of software - the learning curve is steep!

Where can I find out more about Java?

The online Java Tutorial from Sun is ESSENTIAL reading!

It covers

  • Java language.
  • Swing - The display mechanism used by VASSAL.
  • Utility classes provided by the Java SDK.
  • Much, Much more.


What version of Java should I be using for development?

All of our code as of late 2021 currently targets Java 17.


I have created a new custom counter Trait, but it keeps dissappearing from my counters!

Make sure you have created a custom CommandEncoder that overrides createDecorator() to create your new trait (See here). Unless you do this, you custom traits will dissappear from your counters each time you load a game.

What's the difference between State and Type?

Type data is defined at Module creation time and is stored in the buildfile in the module. Type data will generally not change while a game is in progress and is not saved in the game savefile. The type data for a component is maintained using the AbstractConfigurable interface. The type data for a Counter Trait is maintained by a user written PieceEditor class returned by the EditablePiece.getEditor() call.

State data is the data that changes as a game is in progress and represents the current state of components. State data is saved either in the game savefile or logfile (for shared state data), or in User Preferences (for local state data).


How do I retrieve and zoom an Image from the Module Zip file?

 protected Image image = null;
 protected String imageName = "test.png";
 protected Rectangle imageBounds = null;
 protected double zoom = 0.75;
 try {
   image = GameModule.getGameModule().getDataArchive().getCachedImage(imageName);
   imageBounds = DataArchive.getImageBounds(image);
 }
 catch (IOException e) {
   image = null;
 }
 Image scaledImage = GameModule.getGameModule().getDataArchive().getScaledImage(image, zoom);

How do I make a Dialog or Window stay on top?

Create the window or dialog with the VASSAL main frame as the owner:

JDialog dialog = new JDialog(GameModule.getGameModule().getFrame());
JWindow window = new JWindow(GameModule.getGameModule().getFrame());

What is an easy way to display an Image?

Create an ImageIcon and use a JLabel:

 ImageIcon icon = new ImageIcon(image);
 Jlabel label = new JLabel();
 label.setIcon(icon);
 myDialog.add(label);

Can I subclass a VASSAL component?

Yes, as long as it is a component defined in the buildfile and any instance variables you need to access are either protected or have protected or public getters and setters.

To activate your new component, you will need to edit the buildFile of your module. e.g. Change:

<VASSAL.build.module.map.boardPicker.Board ...other stuff...>
to
<BattleTech.BattleTechBoard ...other stuff...>

How do I use preferences?

Preferences record state information that is local to a single user. Preferences are stored on each players PC and are accessed from the File -> Edit Preferences menu option. Preferences are automatically saved to disk.

Preferences are added by first creating an appropriate Configurer, and then adding it to the appropriate Preferences tab. The following code creates a preference tab name "VSQL Preferences" if it does not already exist and adds a String preference with a key of "ruleLevel" and value of 3:
. The example requires import of VASSAL.configure.StringConfigurer.

    final String VSQL = "VSQL Preferences";
    final String RULE_LEVEL = "ruleLevel";
    int ruleLevel = 3;
    final StringConfigurer ruleLevelCfg = new StringConfigurer(RULE_LEVEL, "Rule Level", ruleLevel);
    GameModule.getGameModule().getPrefs().addOption(VSQL, ruleLevelCfg);

You would typically place this code in the addTo() method of a component. Use

    GameModule.getGameModule().getPrefs().setValue(RULE_LEVEL, level);

to just set the value. To read this preference use: int level = GameModule.getGameModule().getPrefs().getValueString(RULE_LEVEL); See VASSAL.preference.prefs.java for more details.

Eclipse cannot find my main class org.vassalengine.main?

Couple of things to check in the Run... or Debug... setup (as opposed to the the VASSAL project properties setup):

1. Main Tab

Make sure the main class is
org.vassalengine.Main
exactly...not org.vassalengine.main
Make sure you have 'Include external jars when searching for a main class' clicked on.

2. Classpath Tab

Make sure VASSAL.jar is included here.

How do I process every piece on a board?

Use Map.getPieces() to get an array of all GamePieces on the board. Each GamePiece in the array will be either a Stack or an individual piece. Process the pieces using the PieceVisitor pattern. For a good example on how to do this, see see GlobalCommand.java.

Alternatively, you can do something quick and nasty like:

   GamePiece pieces[] = map.getPieces();
   for (int i = 0; i < pieces.length; i++) {
     doSomething(pieces[i]);
   }
 protected void doSomething(GamePiece piece) {
   if (piece instanceof Stack) {
     Stack s = (Stack) piece;
     for (int i = 0; i < s.getPieceCount(); i++) {
       doSomething(s.getPieceAt(i));
     }
   }
   else {
     /* Do Something here
   }
 }