VASSAL Automation

Yeah - I had a couple end users throw hissy fits. One procliamed he would never play again, which was really disheartening considering the countless hours it took to automate everything.

The proverbial straw that broke the camel’s back for me was the accidental discovery a few months ago that Vassal 3 has no way to prevent near simultaneous actions by different players. i.e. if both players click eliminate unit at approximately the same time, it will execute the command twice, which utterly breaks all of my GPs that track unit locations and area control. Any GP that changes whenever a Piece is created, deleted, or moved must have absolutely flawless code, otherwise, once an error is introduced, its going to absolutely wreak havoc on all future calculations that rely on it. I have pulling my hair out for months chasing down what I concluded were spurious error reports as I looked for months and hours upon hours for a bug in my code that didn’t exist. Finally, by chance one day I noticed a double report of a unit deletion in a log, then verified the behavior. I’m waiting on Vassal 4 because this is not something the developers can fix in V3…

I also successfully imported terrain.TerrainDefinitions in the most recently linked module.

I guess this means we can’t replicate the problem you began with. Can you still replicate the problem?

I believe I know what is wrong. I have that module saved in two different spots on my computer, and I believe I was trying to edit the wrong one. I shall give it another try.

I actually had the darn thing saved in three different locations on my computer!, and only one of the three was the one I had edited. So, I deleted the other two and now it works. So, now I am back on track!

1 Like

Tip: as soon as you start working on a new version, change the version number and save as a new file. Also, in the Module Manager, go to File/Preferences/General and enable “Show developer information in Module Manger window”…this will make it even easier to tell similar but different versions apart.

1 Like

A few years ago, I tried to bring a module to a high level of automation, without resorting to custom java codes. The problem that arose was not the difficulty in preparing the necessary procedures, but the progressive slowdown of the system.

I did several tests to try to identify the causes of the slowdown and I found basically two: the calculated properties and GKCs. The calculated properties should be used very sparingly and it is preferable to use global or dynamic properties at their pore, as needed. Calculated properties are the main cause of slowdowns. The second is the GKCs. Unfortunately, while it is possible to replace the calculated properties with the other two types of properties, it is not possible to renounce the use of the GKCs.

The tests carried out showed that what slows down the behavior of the GKCs is the number of prototypes that a given type of unit has and not, as I thought at the beginning, the number of units in the map or the dimensions of the map itself. With all the prototypes enabled and only one unit on the map, the execution of only a GKC took place after about 90 seconds, a delay that a player will hardly find acceptable.

Disabling all the prototypes, the execution of the GKC was practically instantaneous; as the prototypes were rehabilitated, execution became slower and slower.

At that point I gave up and kept only the prototypes that I considered really essential.

Maybe Version V.4 will helps on this.

Be well.

Panther 2010

:upside_down_face:

1 Like

Thanks for the information, Panther.

I hope this is not quite right as Prototypes are a boon for keeping module development organised and consistent. I think the question has been asked before and came back that Prototypes don’t operate in this way. I wonder what you did in the test.

GKCs and Calculated Properties, yes, they can have a high cost. Closely related to CPs are beanshell expressions placed in Text Labels and Layers (Using Expression Values). Similar to the search part of a GKC are the Beanshell Count() and Sum() functions that may have to evaluate many pieces. I use all of these a lot; I do notice sluggish performance to some degree but something measured in seconds would be exceptional, perhaps I am not using enough pieces. Sometimes I find I can improve it too, with a bit of thought about where the bottleneck might be.

One area that did cause me a problem turned out to be due to large lists of Restrict Command traits. Prior to v3.5.8 this was a cause of significant delay to card drawing ops in a module that I was developing. The start draw of multiple hands was 15-20+ seconds depending on the speed of the computer were the draw was initiated from. Then happily @Cattlesquat came across a Vassal performance flaw which he fixed… the draw time went to below 5 seconds.

Also from Brian’s arsenal, a while ago GKCs searches got “Fast Search”, potentially a 20% improvement to search time. In my experience, if a GKC is capturing more pieces than necessary (ie passing its command to pieces that subsequently ignore it), there is a greater potential improvement just by narrowing the search criteria.

2 Likes

I concur with Mark. I use about 5-10 Prototypes per unit and have never experienced any lag whatsoever. I’d be shocked if they are indeed a resource hog.

I definitely rely on GPs and DPs to do the heavy lifting for automation. I have over 2000 GPs defined in one module and zero lag. It usually takes a little longer to program than with CPs or GKCs, but the UX payoff is tremendous.

CPs also can have almost no lag if used judiciously. It helps to experiment a little with a test module, but in general, if you avoid CPs that affect text labels or graphics/layers, you will encounter very little lag.

GKCs are a last resort as they definitely create a noticeable lag in almost all situations - especially games with a large piece count. The trick to keeping them bearable is sending the command to as few pieces as possible using expression to filter. I often create DPs for pieces just for filtering GKCs. I personally saw no speed increase from the Fast Search, but I didn’t have any GKCs that were taking longer than about 1-2 seconds. A GKC that takes 90-seconds sounds nuts!

2 Likes

Hello, marktb1961

I agree: I have been using prototypes for a long time as they are very practical in organizing the structure of a module. I’ll try to better explain what I was able to see in the testing phase.

The aim I set myself was to replace an active layer with another as soon as the turn tracker reached a given phase. To do this I used a pair of Global Hotkeys (turn) and a Global Key Command that replaced the layer for those units in which it was activated. The search condition was: layername_Active = true.

During the test on the map there were 10 units of which 4 had active the layer. The waiting time was over 45 seconds. To understand the real cause of this delay, I ran a test by deactivating the GKC and using the same GH (turn) to change the value of a Global Property.

The execution was instantaneous and therefore the problem necessarily lay in the Global Key Command. I then deactivated all prototypes of the units in question except the one I was testing and the waiting time dropped to about 15 seconds. By reactivating the different prototypes one at a time, the waiting time returned to about 45 seconds.

Now I don’t know exactly where and when Vassal allocates in memory the different prototypes that a given unit has, but it seems that they are all simultaneously loaded into memory, even when not in use and this could be a possible explanation for the delay.

In any case, the real cause of the delay certainly lies in the GKCs. In another module that I am developing I have automated the resolution of combats and everything went smoothly without any delay until a GKC came into action that had to activate a command on all the units that met a given condition and then in waiting it was better to go for a beer.

It seems that the search is running in circles and this even if the units on the map that meet the search conditions are few.

In your opinion what could be the cause of this?

Panther_2010

I just assumed a Prototype functions like a programming subroutine, in which case, a module that uses Prototypes extensively would run faster, not slower. I never really looked into it though because they have never given me performance issues.

I wonder if the issue relates to overall piece count. My largest module only has about 1000 unique pieces and typically 200-300 are in play at any given time. Was your module significantly larger?

By active layer, I assume you mean an active layer within each piece, not an entire layer containing map and pieces. I was able to get working what I “think” you described but without an appreciable delay. For instance, I have a Russian Winter phase that activates an “out of supply” layer for every Axis unit on the map, then deactivates it each Spring Thaw. Presumably the GKC scans all 200-300 pieces then activates about 50 or so on average. The delay is not noticeable.

I’d be willing to take a peek at your test module if you still have it and are willing to share.

1 Like

This sounds like there is something deeper going on. The primary factor affecting GKC execution speed is the number of pieces on the Map.

A secondary factor affecting GKC execution speed will be the number of traits that the GKC has to search from the top of each piece down until it finds the values of the properties referenced in the GKC match expression. This is multiplied by the number of properties referenced in the GKC Match expression.

Another secondary factor will be the complexity of the GKC match expression itself that needs to be evaluated on each piece. There is a known problem if you use the If() beanshell function and nested more that a handful of times in any expression. This is compounded if the GKC is referencing Calculated properties that may themselves contain If() functions. Extremely complex test expressions reference many properties, or referencing complex Calculated Properties in the pieces can also be a problem.

The execution of a GKC execution on a single piece taking 90 seconds is EXTREMELY unusual and worthy of more investigation. It is not something I have heard of before.

How many total traits where we talking about? The count of prototypes themselves is irrelevant, the count of the traits introduced by those protoypes is the issue. Unless we are talking about 100’s of traits, I can’t see numbers of traits per se being the problem.

There is a practical limit to how complex you can make the automation in a module. Technically, Vassal is essentially an interpreted system (Vassal traits) running on top of an interpreted scripting language (Beanshell) running on top of a semi-interpreted language (Java).

It is possible to get around these limitations, but requires a detailed knowledge of the Vassal architecture and how it works internally. As I alluded in my other post, it is really, really hard.

Workarounds include:

  • Simplify GKC Match Expression, number of properties referenced and change all IF() to ?:
  • Use Fast Match carefully to find a smaller set of pieces to apply the complex match to
  • Avoid referencing Calculated properties in the GKC Expressions, or in any CP’s referenced by the GKC Expression.
  • Avoid Calculated properties referencing other Calculcated Properties in general.
  • Avoid Calculated Properties in ‘Layer Follows property’ Expressions
  • If possible, Move the traits that contain the properties that are referenced by the GKC Expression down to the bottom of the trait list.
  • Avoid using the Count() and Sum() and related functions as these are essentially GKC’s.
2 Likes

Protoypes are fully expanded when a piece is created and placed on the board. Once on the board, Prototypes have no further existence.

2 Likes

I defer to @Brent_Easton’s reply which is far more comprehensive and informative than what I would have written. I add that I’ve experienced the same as you on a less extreme scale (far fewer pieces), including examples of the things that Brent warns about. e.g. (a) sending the GKC to pieces with long lists of traits, which I improved by narrowing the search, (b) over reliance on calculated properties, improved by switching to Dynamic Properties and (c) complex operations that include nests of GKCs.

One example of the later was in combat process automation where I had to do multiple calculations across several pieces, starting with a dice roll. The dice roll was noticeably slower that a normal dice roll, but just about acceptable for the benefit. This was one of the those (for me) rare GKC applications where I could use the “Range” field to limit the pieces addressed by the GKC.

1 Like

If you have a copy of the module plus a save game that reproduces this, I would be interested in profiling it using the Java tools we have and I could give you a definitive answer on what the problem is that is causing this.

2 Likes

Hi to all,

First of all, I must thank all those who very kindly took the time to try to help me understand the real cause of the anomalous delay during the execution of the GKC.

Well, I will try to apply some of the Brent’s precious suggestions; in particular:

A) All computed properties will be replaced by global properties;

B) Remove all if () where present and replace them with simpler expressions. I don’t currently know how to use “?”.

C) Avoid using the Count () and Sum () functions whenever possible.

However, it is not possible for me to further simplify the GKC Match Expression that seems the cause ofthe delay , since the only expression used in the search is “layername_Active = true” (without the quotes), where layername is the name of the active layer that the searched units must have.

I hope to at least be able to significantly reduce the current delay.

Once the appropriate changes have been made, I will redo the test with about thirty units on the map and post the result obtained.

Thanks again to everyone.

Panther_2010

:hammer_and_wrench:

2 Likes

In Java (and other C-based languages), ?: is the ternary operator, with the format <expression to test> ? <return this if true> : <return this if false>. It’s just a quicker way to do an if() function.

1 Like

Yup, so

If(a == 2, “Lo”, “Hi”)

becomes

a == 2 ? “Lo” : “Hi”

If you use this in an extended expression, you may need to add parentheses:

((a == 2) ? “Lo” : “Hi”)

It is extremely unlikely that checking layername_Active == true should be the cause of the problem, that should always execute quickly. I was more thinking that you might be using If()'s in GKC expressions.

1 Like

To get back to the OP, I have combat calculation running in OCS Reluctant Enemies. It took quite a bit of set up for map and all the terrain, adding class, strength and AT values to each unit, and all the code, but it works well and is pretty snappy.

(It uses Combat Markers, so you place the Combat ID on the defender’s hex and Combat Arrows on each attacking stack, and select Calculate Combat from the ID menu. It checks all the hex/hexside terrain, allows for DG or Strat mode, OoS, and AT levels, and even allows units to be marked as not attacking or defenders unsupplied. It works out the total factors, then uses the CRT to figure out the correct Ratio and the Line to use. The only thing left to do is identify the AR units and roll the dice.)

What it can’t do is figure out when there are multiple units under a single DG marker, and I’ve yet to find a good solution for identifying stacking order. And it adds considerably to the vsav file size.

So, yes, it can be done, and all in ‘pure Vassal’ ™. An interesting exercise, and I learned a lot, so very worthwhile.

3 Likes