It's about generating vector field, directing to goal(s). It's strength is that we can have the same field for any number of units, moving to the same goal. It also enables further development of steering behavior and collision & obstacle avoidance, because there is no need for path recalculation each time an unit is forced to avoid something. It's more expensive to generate than A*, though.

This is my first contribution to WZ and I know maybe 1% of codebase. I have rough prototype ready, but I have trouble integrating it into existing code.

The algorithm generates both A* path and the flowfield. The path is used as approximation until flowfield is ready. Right now I only integrated the path, and droids should ignore the path as soon as flowfield is available. But WZ code seems tightly coupled to path and I don't know how to deal with it. The current direction vector from flowfield should be merged with current movement direction to make turning smooth.

The prototype has some limitations:

It does not analyze owner side of the droids (that might be problematic)

It does not care about danger/threat map (that might be easy)

It assumes FMT_BLOCK (that should be easy to change, tiles blocked by structure would go into integration field)

It does not update anything when structures are created / destroyed. (I have to write code to invalidate stuff and rebuild some, it might be tricky with already moving droids)

Included debug draw code is very hacky, as I don't know how to draw stuff on tiles correctly (current code works acceptably only on initial zoom and rotation)

I used some stuff from Qt, because I didn't know about plans to get rid of it. It's QElapsedTimer (for debug only), QThreadPool and QCache. I decided that first I would like to have it working and then to have it working good.

I haven't tested it with savegames, and probably loading a save will make all moving droids to stop.

No idea how it will behave in MP games, no code for debugSync has been made.

I have compiled it with MSVC 2017 on Windows, and this compiler is known not to conform to standards (although it gets better).

Currently there is only one goal - x,y where player has clicked. But the code can support an area of goals (for example, for preserving formation). It might have edge cases, but it is already used internally.

There is no Line-of-sight pass, as described in the article. I considered it too complicated, and not-that-much beneficial. It's about ignoring the flowfield and moving directly to goal. What is WZ already doing for VTOLs.

I hope someone can help me with integration or give some directions and explanations of code related to movement.

I was looking into doing something like this years( ) ago, and just never had the time to finish anything.

We were given the source "as is", without any documentation at all, just what you see in the source, and even then, there have been times when those docs aren't actually doing what it says it is doing.

I am not sure who last touched the code, or even knows all the in's & out's of it, so, unsure who would be the best person to point you to. Perhaps Cyp or maybe Per can answer some more detailed questions, but, I think they both did the bare minimum with that side of the source.

I am not around much these days either, busy with RL stuff, so, basically, I wish you luck, WZ is really in need of these kind of enhancements to make the game more enjoyable for all!

Haven't had a chance to look at what you are doing before I leave again, but, IIRC, there are some GPL compatible flowfield (and steering) type libraries out there, unsure if you are using that or not, but I always favor stuff that has been out for awhile to get the kinks out over something home-brewed, and it needs to be deterministic, or it will cause desync errors.

All is coded by me, except for Qt stuff. I wanted to have more control over it. I have only found some simple examples on the web so far, no libraries.
I'm not sure if the code is 100% deterministic. It is divided into tasks, computed in parallel, which might get slightly different order. That could result in different times when a part of the flowfield is available to different players. So droids might take slightly different paths (maybe). That part is still missing, so that is my guess.

I just hoped there is someone who touched the code in move.cpp, maybe fixed a few bugs and has and idea what is going there.

No idea how it will behave in MP games, no code for debugSync has been made.

The overall idea is to make the behavior entirely deterministic. Your code should not rely on wall-clock timeouts but should instead rely on timeouts formulated in terms of game frames, should not use floating-point arithmetic but should instead use integer arithmetic, should not use standard library's random values but should use the game's custom Mersenne Twister that yields the same result on all machines across the network, etc.

As far as i understand, the current pathfinder is implemented as follows:

Clients agree on the lag value L (say, "L = 2 game-frames", which amounts to 200ms) that is computed deterministically based on mutual ping values. Not sure if this value changes throughout the game.

Every order given by the player to its units is delayed by the lag value. I.e., if the order is given on frame N, units will only start moving on frame (N + L). But the pathfinder is already allowed to run in the background thread as soon as the order was given locally.

Similarly, if the order for the opponent's unit is received from the network, it is timestamped with the value (N + L) on which it starts executing, but pathfinding starts immediately. Such pathfinding is guaranteed to yield the same result on all machines due to determinism.

The lag value ensures that the game can run smoothly because whenever it has received full information about frame N, it can precisely predict the future until frame (N + L) inclusively.

If the game has displayed everything it can predict to the user but it requires more inputs to proceed, it hangs and displays the "Zzz" icon. Such inputs may include packets from other peers on the network or results of pathfinding that are received from the background thread on indeterministic moments of wall time. In particular, if a certain peer cannot finish pathfinding in time, it will keep all other peers hanging until its own pathfinding thread yields results, because only then will it be able to send information about the next game frame.

Note that the generation of the path/flow only needs to be deterministic if the same computation needs to be done on each peer. If the droid owner does the path/flow computation and then sends it to the other peers over the network, and they can follow this path/flow deterministically from a common point in the future, then that will also work. This would also likely reduce the CPU load a lot, since not everyone then needs to do all the path/flow calculations, but only their own.

Clearly missing from Makefile. I'm sure I have added it because I had linkage errors too. Could be that I haven't committed this file.

That pragma is because MSVC gave me error about nameless struct in GLM, so I had to disable it.
QT elapsed timer is only used for debug, you can safely comment out /remove it.

If you don't want to have debug view, undefine / comment out a flag named "I_AM_FLOW_FIELD_MAINTAINER_AND_WANT_TO_HAVE_MY_VIEW_OBSCURED" in flowfield.h. I haven't yet found a way to move this flag to Makefile with possibility to enable / disable it at build preparation.

Going forward, since the CMake build setup should now work on all platforms, I think the focus will be there (and the autotools / Makefile build setup, which is less flexible and more brittle, may end up going away).

If the droid owner does the path/flow computation and then sends it to the other peers over the network, and they can follow this path/flow deterministically from a common point in the future, then that will also work. This would also likely reduce the CPU load a lot, since not everyone then needs to do all the path/flow calculations, but only their own.

I would say can't do. The tanks will keep blocking each other and require recalculation. Also on a complicated map, a single tank could require 150 tiles of patfinding. That would be a lot to transfer in the netcode. Running an advanced A* with terrain difficulty wasn't a problem 5 years ago when i tried on 2.3.9 . The good maps are usually fairly open. It's not like a maze. So path finding is nearly linear.

So I have fixed more incompatibilities. Compiled with with cmake + gcc 7.3 and got no more errors.
I needed to use C++14 for make_unique<>, is that ok?

The tanks will keep blocking each other and require recalculation. Also on a complicated map, a single tank could require 150 tiles of patfinding.

This flowfield implementation uses 2 levels of pathfinding:
* waypoint-A*, which only visits "sectors" (rectangle of 16x16 tiles currently). It's a list of sectors to visit
* per-sector flowfield, for given path
So if any two droids go from A to B, they will reuse A* path, and then reuse per-sector flowfields.
If a droid wants to go from C to B and C is near A, then probably A* path will be already calculated, and reused. Also some of the flowfields on the path will probably be reused, even if a bit different A* path was calculated.