AstarPath.active.UpdateGraphs resets tags

We use a grid graph in our project. The project includes a terraforming mechanic, so after a terraforming input was executed, we are rescanning the parts of the graph that may be affected. All nodes start out with Tag = 1 at the moment, so we were confused to find that after doing said rescan, all tags of the affected nodes of the rescan are reset to 0. This is the code used:

areaToUpdate = new Bounds( Vector3.zero, 10f * Vector3.one );
GraphUpdateObject graphUpdateObject = new() { bounds = areaToUpdate };
AstarPath.active.UpdateGraphs( graphUpdateObject );

I put areaToUpdate bigger than the actual gridGraph to investigate the issue further, but it happens either way.

I have also looked into the method inside the GridGraph class it is using to generate the new nodes, and it seems to just generate new nodes and never transfer the old tags into context.data.nodes, so I don’t understand where this is even supposed to happen usually.

The lines where I would have expected that were in the GridGraph file, 1806-1809.
We are using version 5.0.5.

I don’t get why, because the GraphUpdateObject specifically has modifyTags, and that is set to false, I have doublechecked. Am I misunderstanding something?

Thank you in advance for your help!

Hi

Yes, this is expected. When calling UpdateGraphs, it will recalculate all touched nodes from scratch. This includes resetting all fields to their default values.

You can set graphUpdateObject.resetPenaltyOnPhysics = false; to prevent this. Despite the name, it also affects tags.

Eventually, I want to switch from a procedural graph modification system, to a declarative one, in which it will be much easier to do these kinds of things, and in a much less roundabout way.

Thank you for your answer, I have modified the code to this:

areaToUpdate = new Bounds( Vector3.zero, 10f * Vector3.one );
GraphUpdateObject graphUpdateObject = new() { bounds = areaToUpdate };
graphUpdateObject.resetPenaltyOnPhysics = false;
AstarPath.active.UpdateGraphs( graphUpdateObject );

The result unfortunately is the same, all affected nodes still have their tags set back to 0.

Do you have an idea why this isn’t working or what I am doing wrong? @aron_granberg

That’s strange. I just tested it in my project, and it works just fine.

Are you sure you aren’t doing any other graph updates too?

I have triplechecked, it is only updating this one area at that time.

I would like to know where in the code it is supposed to copy the original tags into the new tags for the updated nodes.
I have found this line in the GridGraph script (line 1865)

newNodes.CopyFrom(context.data.nodes, graphUpdateObject != null ? graphUpdateObject.resetPenaltyOnPhysics : true, dependencyTracker);

which I think is maybe the one, but the curious thing is that I can’t find where context.data.nodes is supposed to get the original tags from. Maybe you can enlighten me about that. As far as I can see it, context.data is just newly created and nowhere are the tags ever transmitted from the GridGraph variable “graph”? Also unexpected for me: The graph variable, when looking at graph.nodes, has all the correct old tags as I would want them, but graph.nodeData doesn’t, they are all 0? Is that related to the issue?

For your information, I have fixed my issue in the GridGraph script to produce the intended behaviour as far as I can tell with the following settings on the GraphUpdateObject:

graphUpdateObject.resetPenaltyOnPhysics = false;
graphUpdateObject.updatePhysics = true;

This is what I needed to do (lines 1852 - 1871, added CHANGED: comments to where I changed something):

				if (recalculationMode == RecalculationMode.RecalculateMinimal) {
					//CHANGED: Needed to comment this back in
					 context.data.nodes = context.data.nodes.ReadFromNodesAndCopy(graph.nodes, new Slice3D(nodeArrayBounds, readBounds), nodesDependsOn, graph.nodeData.normals, graphUpdateObject != null ? graphUpdateObject.resetPenaltyOnPhysics : true, dependencyTracker);
					var newNodes = new GridGraphNodeData {
						bounds = readBounds,
						numNodes = readBounds.volume,
						layeredDataLayout = layeredDataLayout,
						allocationMethod = allocationMethod,
					};
					newNodes.AllocateBuffers(dependencyTracker);
					// If our layer count is increased, then some nodes may end up with uninitialized normals if we didn't do this memset
					newNodes.normals.MemSet(float4.zero).Schedule(dependencyTracker);
					newNodes.walkable.MemSet(false).Schedule(dependencyTracker);
					newNodes.walkableWithErosion.MemSet(false).Schedule(dependencyTracker);
					newNodes.CopyFrom(graph.nodeData, true, dependencyTracker);

					//CHANGED: Needed to toggle the resetPenaltyOnPhysics bool here
					newNodes.CopyFrom(context.data.nodes, graphUpdateObject != null ? !graphUpdateObject.resetPenaltyOnPhysics : false, dependencyTracker);
					context.data.nodes = newNodes;
				}

Maybe this helps, I would really like to know why this works, and also why it works out of the box for you but not for me.