Package: vassal-python
VASSAL PythonTools for manipulating VASSAL module files using python.This python module is aimed at developers of VASSAL game modules. It's purpose to automate repetive module upgrades (e.g. adding or removing a new trait to all pieces of a certain type based on some number printed on the piece's physical counter).Implemented using jpypeThe successor to VASSAL::PerlCore ComponentsThe package implements the following modules for working with VASSAL game modules. These are the essential packages most useful to developers.ManagerThe class that wraps a headless version of the VASSAL so that it is possible to call all the module loading, parsing, and saving features without a Swing GUI. It is important to know that it is manager.py that actually calls jpype.startJVM() - so modules need to make sure they import Managerbeforeimporting any VASSAL java modules - or they will get a runtime error.fromvassal.managerimportManagermanager=Manager()gameModule=manager.open_module("./test.vmod")# change some stuff...manager.save(gameModule)print("Success!!")WalkerThe class that enables recursive descent into the Buildables hierarchy of a game module and enables printing or actions on pieces and components.fromvassal.managerimportManagerfromvassal.walkerimportWalkermanager=Manager()gameModule=manager.open_module("./test.vmod")walker=Walker(gameModule)walker.print_game_module_pieces()Helper modulesThese modules are included to automate certain tasks and to hide some of the Java-ism of the VASSAL code structure.UtilThis includes helper methods that are useful for grabbing pieces from piece windows in your module. Arguably, most are too low-level and will be moved into Walker or other module in the future.fromvassal.utilimportis_piece_widget,is_piece_window,is_named_window,piece_has_prototype,get_all_pieces_with_prototypefromvassal.walkerimportWalkerfromvassal.managerimportManagermanager=Manager()game_module=manager.open_module("test.vmod")walker=Walker(game_module)pws=walker.get_piece_windows()pieces=walker.get_all_module_pieces()leaders=[]forpinpieces:ifpiece_has_prototype(p,"Leader"):leaders.append(p)jackson_pw=Noneforpwinpws:ifis_named_window(pw,"Jackson Division")usa_pw=pwbreakjackson_pieces=walker.get_all_module_pieces(jackson_pw)csa_arty=get_all_pieces_with_prototype(pieces,"CSA Artillery")# These two are *pretty* low level and probably not generally usefulifis_piece_window(jackson_pw):print("Found!")pieces=[]ifis_piece_widget(jackson_pw):pieces.append(list(walker.get_all_module_pieces(pw)))GBACWThis module is specific to the GBACW (Great Battles of the American Civil War) series of modules. It might serve as an example for other module authors.Some examples:fromvassal.GBACWimportget_piece_window_by_namefromvassal.walkerimportWalkerfromvassal.managerimportManagermanager=Manager()game_module=manager.open_module("test.vmod")walker=Walker(game_module)pws=walker.get_piece_windows()usa_inf=get_piece_window_by_name(pws,"USA Infantry")usa_cav=get_piece_window_by_name(pws,"USA Cavalry")Loading the JVMvassal-python requires the VASSAL classes (which live in the Venginge.jar file) in order to run. vassal-python is shipped with the latest version of the 3.6.x classes. There is also an interface Java class:VASSAL.tools.python.Helperwhich is required to fake a 'headless' version of VASSAL (no Swing windows or dialogs) and to interact with certain Java-specific VASSAL methods.Jpype needs the JVM started before it can begin loading the Java classes. This is handled inside manager.py during the module loading. The JVM needs to find bothVengine.jarandHelper.classin the classpath. One easy way to do that is to configure the classpath using jpype.addClassPath before loading manager.py.importjpypeimportjpype.importsjpype.addClassPath("./lib/java/Vengine.jar")jpype.addClassPath("lib/java")# Helper.classfromvassal.managerimportManagerAnother method is to set the CLASSPATH environment variable before invoking application:exportCLASSPATH="$CLASSPATH:${VASSALPYTHON_HOME}/lib/java/Vengine.jar"exportCLASSPATH="$CLASSPATH:${VASSALPYTHON_HOME}/lib/javapython${VASSALPYTHON_HOME}/app/module-print.py --mod${VASSALPYTHON_HOME}/tmp/test.vmodExample ApplicationsThe package includes a few example tools created using this package. They illustrate how to interact with the VASSAL GameModule and it's data fromimage-scrape.pyInteractively scrape numbers from counter images and save it in a .csv file
The image scraper will ask for confirmation if it doesn't have sufficient confidence in the guess. It will pop up an image window showing what it scraped and what it's best guess of the number is. Click on the image window and hitenterto make it go away and then back in the shell window, hitenterto use the default value or type in a new value and hitenterto continue.$python3image-scrape.py--image-dir./images--names-filenames.txt--ss-filestart-str.txt
Readingimage:14IN_front.png
Foundstrength:9Readingimage:14INa_front.png
Foundstrength:5Readingimage:14INb_front.png
Foundstrength:4Readingimage:8OH_front.png
Foundstrength:14Readingimage:8OHa_front.png
ss_10:7,ss_8:NONE>>7...[SNIP:interactivelypromptsuserforconfirmation]entercorrectstrength:>>7:Foundstrength:7...[SNIP:moreoutput]Success!add-starting-strengths.pyCompares the name of each piece in the module to the names in the .csv file from image-scrape, and if found, creates a new "StartingStrength" trait on the piece and sets the value to that listed in the file$python3add-starting-strengths.py--modfile.vmod--ssfilestarting-strengths.txt
VASSAL:initGameModule:start[SNIP:vassal-pytonstartupmessages]VASSAL:initGameModule:end
Piece:34MA_8_front.pngFoundSSforpiece:34MA_8_front.png,strength:8Piece:5NY_HA_12_front.pngFoundSSforpiece:5NY_HA_12_front.png,strength:12Piece:116OH_10_front.pngFoundSSforpiece:116OH_10_front.png,strength:10Piece:123OH_10_front.pngFoundSSforpiece:123OH_10_front.png,strength:10Piece:170OH_front.pngFoundSSforpiece:170OH_front.png,strength:8Piece:Ely_front.png
Piece:1WV_2_1_AWV_front.pngFoundSSforpiece:1WV_2_1_AWV_front.png,strength:8Piece:4WV_front.pngFoundSSforpiece:4WV_front.png,strength:8Piece:12WV_2_1_AWV_front.pngFoundSSforpiece:12WV_2_1_AWV_front.png,strength:8Piece:18CT_2_1_AWV_front.pngFoundSSforpiece:18CT_2_1_AWV_front.png,strength:8Piece:2MD_ES_front.pngFoundSSforpiece:2MD_ES_front.png,strength:8Piece:Young's_PB_front.pngFound SS for piece: Young's_PB_front.png,strength:8[SNIP:moreoutput]Success!module-print.pyRecursively prints the names of all the piece windows and the pieces in each window$python3module-print.pl--modtest.vmod
VASSAL:initGameModule:start
...[SNIP:vassal-pytonstartupmessages]VASSAL:initGameModule:end
USA
UnionArmyofWestVirginiaCommanderCrook,AWVThoburn's Division, 1/AWVThoburn'sDivision,1/AWVThoburn1/AWV1/AWVBrigadesWells,1/1/AWVWells1/1/AWVWellsRgmt1WellsRgmt2WellsRgmt3WellsRgmt4WellsRgmt5Ely,2/1/AWV[SNIP:moreoutput]Success!piece-edit.py - (GBACW-specific)Uses the GBACW module included in this package to find game pieces based on prototype. For example, find all "Leaders" on the side "USA" and create four new global properties using that leader's name as the basis for the property name.Known ProblemsHere is a list of things I already know are not working as planned.Applications hang on exitCurrently, VASSAL does not close all it's running threads on System.exit() - so python apps will be left hanging after they have completed. (Probably something in how Helper.class needs to fake Swing into thinking it's not running headless when it really is. Probably, VASSAL is trying to pop-up a dialog asking if we want to save.)They need to be killed to force a shutdown:$python3module-print.pl--modtest.vmod
...someoutput
Success!!(hangs)^Z[1]+Stoppedpythonapp/module-print.py--modtest.vmod
$kill%1[1]+Exit143pythonapp/module-print.py--modtest.vmod
$Not graceful, but hey! It works...I will check to see if it is possible to set a flag so VASSAL doesn't ask for a save.