Easy way to get Map numPieces property for trigger?

In several modules I have used _numPieces, numPieces in game inventory windows, and elaborate piece tracking systems to update global properties, and the game inventory allows for calculating totals of marker properties on a map, but I don’t think I’ve ever successfully used a _numPieces property, or some other total of a marker property on a map.

All the information seems to be accessible (to the game inventory window, in particular), so it should be easy.

How can I count pieces or marker values for a Trigger on a piece on a different map, without going through the whole rigmarole of tracking every piece moving to and from a map? (detailed piece tracking is prone to desynchronisation bugs)

Using standard Vassal functionality, I think your best bet would be to set a Global Property to 0, then send a GKC to all the pieces you want to count that causes them to increment that Global Property by 1.

This is an inherently inefficient process and while fine for counting stuff now and then (when a button is clicked for example), you would not want this firing off all the time.

:laughing:

Thanks, that confirms I wasn’t overlooking something.

What sort of facility would you be looking for?

A Beanshell function?

{CountPieces(“Main Map”, “Army==“German” && Type == “Infantry””}

Or something easier to use?

This approach has issues. The syntax is difficult because of the embedded double quotes and Vassal can’t check validity of the Property Match expression until it is executed, so will be frustrating to get working properly. However, it would be the simplest way.

Something like that, I guess? If there were a property “Main Map_numPieces” that would be sufficient, or “Main Map_sum_Infantry_Level” would be better. I understand now that no such property exists, so I guess some kind of Beanshell function is necessary. I’m no programmer though, so I have no idea what syntax would be required, or how it would work in practice.

As you noted, I can achieve the desired effect by resetting a GP to zero, then using a GKC to trigger all qualifying pieces to increment the GP.

It would be nice if I could just set the GP or a Dynamic property to the piece/marker count directly.

The problem with the Property approach is that every single game is different, with different counters that need to be included or excluded from the count.

Possibly we need something like a Global-Level Calculated Property. It would need a Timer to prevent it from re-calculating too often, but combined with a unit/property counting function(s) might make life easier.

Actually, something to prevent the current Calculated Properties from re-calculating too quickly is probably a good idea. Could have a significant impact on modules that used Layer traits that follow Calculated properties.

I’ve definitely wished that I could count a location (mainly Region or Zone, but I guess Map too) using a filter expression – something more convenient (and preferably faster) than setting up a bunch of stuff and then sending a GKC etc.

And I wish SumStack let me count the number of things that “have” a particular Marker/Property (i.e. MyMarker != “” ) rather than having to make a marker with a value of 1 so that they can add.

These are relatively simple things to add in. I think combined with Global level calculate properties would make a lot of things far easier.

The problem is though, that counting pieces and checking matching properties is inherently inefficient. It would be easy to absolutely kill module response time as the module spends all it’s time doing counting.

I can certainly imagine global calculated properties being super-useful in some instances.

No question map-wide counting would be slow, but I be it could be faster than the GKC version – in other words, still an at-own-risk type of thing, but the situations where one ends up having to do it anyway mean that any improvement might be useful.

Something that might be super awesome, albeit more pain to implement would be maintaining linked lists (or some equivalent) at every “Region” and “Zone”, meaning it would suddenly become much quicker to count things (or “region-key-command” or “zone-key-command” things). At the module end I could do some super-snazzy stuff if we had that. Having implemented (and debugged) more or less that for Civ2 I’m certainly aware that the effort would be real though.

Yes, but linked lists of what? How would you specify that.

Even just keeping a list of GamePieces in each area accurate would be difficult as there are no pre-defined ‘entrance’ and ‘exit’ points in the code for units coming into and out of maps, zones, regions etc.

Unlikely. For what they do, GKC’s are actually pretty efficient. They just have too much to do.

Currently, to comprehensively track movement of a piece from one map or zone to another, I have to:

Trigger setting of GPs for old zone and current zone (because using the actual properties of OldZone and CurrentZone is unreliable)
Trigger an increase GKC targeting a counting piece in a zone that matches the current zone GP
Trigger a decrease GKC targeting a counting piece in a zone that matches the old zone GP
Have the counting pieces increase/decrease GPs corresponding to their zones

This causes significant slowdown, especially if moving more than one piece at a time. I find it hard to imagine that counting commands would be less efficient, but as I said, I’m no programmer.

Hi Benkyo - couple things –
(1) OldZone and CurrentZone should reliably have the right information when the piece has just been moved, and in my experience it always has. In other words, if you’re responding to the apply-on-move key from the map when the piece moves, those properties will have correct information. The one exception is after an UNDO – it’s a known bug that after an Undo the piece will not have its OldZone/CurrentZone (etc) information properly “undone”.
(2) Rather than using a counting piece for every zone, and therefore having to fire GKC’s to update them (each of which must scan through every piece in your game to find the single right one – this is where most of the performance problems come from), instead I suggest having Global Properties for each zone (e.g. for my upcoming All Bridges Burning module I have things like “Senate_Cells_Helsinki”, “Reds_Cells_Helsinki”, “Reds_Bases_Helsinki”, “Helsinki Control”, “Helsinki Population”, etc, and the same things for every province. And so when a piece moves, it can directly compute the proper Global Properties e.g. { Side + “" + Type + "” + CurrentZone } and increment it w/o having to use a GKC to talk to a “counting piece”, and likewise decrement { Side + “" + Type + "” + OldZone }. Obviously I have plenty of Global Properties, these have never caused me any performance problems.

Hope some of that is useful.

Brian

  1. IIRC, OldZone and CurrentZone have issues when sendto commands are used, or maybe when sendto $CurrentZone$ is used. Anyway, not sufficiently reliable.

  2. The GKCs are targeted to zone, so much faster than untargeted GKCs. Of course a GP for each zone is also necessary by my method. That said, the main difference appears to be that your solution also relies on CurrentZone and OldZone being reliable, which I have found is not the case.

If you can find and demonstrate a reproducible case, please by all means file a bug report so we can get it fixed. It’s the kind of bug that would be worth fixing.

But even “targeted” GKC’s have to check the whole list of pieces to filter them by zone. You’re right that it at least avoids checking every individual trigger trait inside the pieces it filters out. But still, bad performanc.

If you have a GP for every zone anyway, I’d definitely get rid of the “counting pieces”, as those are guaranteed making your stuff run much slower than a pure GP solution.

I can think of two known bottlenecks through which all pieces must move: they either get moved through PieceMover.movePieces() or else they get moved with SendToLocation, right? So if in both of those places we put a call to a “do the to-from list maintenance” method, that would be sufficient to guarantee coverage. It would go right before executing the “apply-on-move” keystroke.

Then there’s piece creation which would of course need to be dealt with - but again, finite-number-of-places.

I’m not saying it’s without some work and care required, but it would be doable. Clearly this is a “Vassal 4” type thing not a 3.3 type thing anyway – and in V4 there may also be opportunities to channel the flow of these things better (e.g. perhaps SendToLocation and PieceMover will end up using the same ultimate code to move pieces).

Just some thoughts. Because I know that e.g. “Zone Key Commands” and “Location Key Commands” that were faster than regular GKC’s would be super-useful.

Brian

PieceMover.movePieces() or else they get moved with SendToLocation, 

Or Move Fixed Distance
Or Return To Deck
Or Pivot
Or Delete
Or Clone
Or Place Marker
Or Replace with Other

But, yes, I agree with your reasoning.

I am jus polishing off a fix for a bug with the Old… properties. The Current… properties are fine, they are just interrogating the pieces current state which will be correct.

The Old… properties, however, where only being set on the piece of the user that generated them and was not being encoded into a Command and not being saved into the GamePiece state. This meant that anything to do with Old… properties would appear to work for the person moving the piece, but any changes to Old… property values would

  • Not be saved in a log file
  • Not be sent to other connected online clients
  • Not be saved in a save file
  • Not be backed up to a previous value when Undo was clicked.

So, seemingly working, but in face totally broken.

The co-ordinates for Back command in Send to Location are not quite as bad. They where saved in the Game State, so got saved/loaded in save files, but value changes where not being transmitted, so transmission to log file, other clients and Undo was broken for these as well.

Any automation based on Old… or Back was broken after Undo, or if a different client tried to use values set by your client.

Hoooo boy! Well that’s definitely worth fixing, glad you did. 3.3 is starting to look like a pretty important update even leaving aside the java version upgrade.

So… please correct me if I’m wrong, here. Based on what I know of the way the architecture works, as long as my use of an “Old” property fits the following paradigm, it should still be safe: if I’m directly responding to an apply-on-move trigger, and I check one of the “Old” properties (e.g. OldZone) and either (a) save its value into a Global Property or Dynamic Property of my own for use later, or (b) use its value during the processing of the apply-on-move command to make various decisions… then THOSE two types of uses should reliably work, because other clients merely see the downstream gamestate changes those things made, they aren’t actually “processing the apply-on-move trigger”, they’re just getting results.

But anything that uses an e.g. OldZone value outside the context of processing apply-on-move… would be unsafe!

This would explain why OldZone etc have always worked correctly to me including in extended multiplayer, since I have exclusively used them during apply-on-moves. But other may have experienced wonkiness if they use them e.g. in a trait activated by right+click, etc.

Brian

Brian,

Yes, there are reasons why this bug has only been hinted at and not causing failure all over the place.

Your analysis is correct, the downstream clients are protected from the direct effects of the bug in the case you lay out because they are executing Commands generated by the source client which is not affected by the bug.

However, it is more complex than that.

Using the Old… properties outside of the single-movement case will also work fine as long as one source client does all the work and generates all the Commands that uses the Old…properties for a given Gampiece. Things will only fall apart when a) the source client does an Undo or b) one of the downstream clients tries to do something assuming the Old… property values from the source have been transmitted to their client.

So if each side only moves their own pieces and don’t use undo, every thing seems to work fine. Until the game is save and reloaded at least.

The Command idiom in Vassal and how they transmit behaviours between clients was the hardest concept I found to wrap my head around. The bugs caused by Command issues are insidious and devious and I still find myself making mistakes.

True. True. Every multiplayer model I’ve ever worked with professionally has been some form of parallel-execution model – e.g. imagine in Vassal if when I dragged my pieces somewhere that the only thing sent down the wire was “pieces dragged from here to here” and then every client processed the movement and apply-on-move commands in parallel, with synched random number generators, etc.

Mostly just a different flavor of bugs though – there are certainly some huge advantages Vassal reaps from the way it does things.