Why is this tick movement framerate dependent?

Ahh so you are running both clients on the same pc :stuck_out_tongue:

Donā€™t worry you canā€™t have both running at full speed. You would need to have physically a different pc

This is the option that allows it in editor, but I donā€™t think it carries over to packed projects.

Itā€™s just that your pc is juggling two games at the same time.

Maybe GPU scheduling could help

You could also try turning on ā€œgame modeā€ in windows

1 Like

This is good to know. I can play around with these settings.

Itā€™s just weird because prior to making those original frame rate dependency changes you all recommended I wasnt having this issue. After I added the ā€˜leftover frameā€™ logic and the batchupdating logic this issue started showing up.

Could it be floating point errors causing this?

if leftover frame is taxing then it should show up in the insights recording.
The loop over gathering the instances transform one by one could be slow

Perhaps you could gather them via

GetNavigationPerInstanceTransforms ( const FBox& AreaBox,
TArray< FTransform >& InstanceData)

in one call?

1 Like

Is it only happening when some have reached the end and been removed? When you remove an instance from an ISM the indexes all change from that index on - rather than remove the instance in line 108 change it move Z to -500,000 or something to test

1 Like

Perhaps it would be more beneficial to gather the instances needed for removal and call
RemoveInstances() passing in a full array?

Maybe this will work like batch update of transforms where the cleanup / rebuild will only happen once after all instances are removed?

1 Like

I had this thought earlier that maybe my index alignment lines were having issues syncing between these arrays: ISMComponentTransforms, the actual ISM component itself, InstanceDataArray, and RemainingDeltaTimeArray, but these instances are freezing prior to any instance reaching the goal point. Iā€™ll try your recommendation and see

I think my logic to align all indexes across the 4 arrays is right, but maybe you can find a flaw in it.

My end goal was to pool instances and not delete them anyways so this is a good road to travel down

@RecourseDesign
UPDATE: So I now keep all information and donā€™t remove any instances and Iā€™m still seeing instances sticking before the first instance arrives at the goal.

The other thing that Iā€™m wondering is in this stress test im basically creating 2000 instances in 30 seconds. I wonder if the addinstance function is trampling over instance data somehow.

Yea, Iā€™m going to try these 2 optimizations to see if that fixes anything.

I wouldnā€™t have thought add instances would interfere with existing indexes, and your code for adjusting the indexes looks solid - but good to remove it from the equation anyway.

Maybe a good way to visualize whatā€™s going on is to add 3 per-instance custom floats to the ISMCs and make a material that uses them as the color - then plug in the normalized Direction?

1 Like

AddInstance does trigger a navigation update, maybe that is the also causing some performance drops?

	if (bNavigationRelevant && IsRegistered())
	{
		// If its the first instance, register the component to the navigation system
		// since it was skipped because IsNavigationRelevant() requires at least one instance.
		if (GetInstanceCount() == 1)
		{
			FNavigationSystem::RegisterComponent(*this);
		}

		if (SupportsPartialNavigationUpdate())
		{
			PartialNavigationUpdate(InstanceIndex);
		}
		else
		{
			FullNavigationUpdate();
		}
	}

another optimization would be to add the instances in bulk.

TArray<int32> UInstancedStaticMeshComponent::AddInstances(const TArray<FTransform>& InstanceTransforms, bool bShouldReturnIndices, bool bWorldSpace, bool bUpdateNavigation)

Just like the bulk update of transforms it does the update on nav just once at the end or even skip it if nav data update is not needed.

1 Like

Yea, this is interesting. So I was looking at your earlier suggestion. Iā€™m not quite understanding this.

void UInstancedStaticMeshComponent::GetNavigationPerInstanceTransforms(const FBox& AreaBox, TArray<FTransform>& InstanceData) const
{
	for (const auto& InstancedData : PerInstanceSMData)
	{
		//TODO: Is it worth doing per instance bounds check here ?
		const FTransform InstanceToComponent(InstancedData.Transform);
		if (!InstanceToComponent.GetScale3D().IsZero())
		{
			InstanceData.Add(InstanceToComponent*GetComponentTransform());
		}
	}
}

Iā€™m not clear how to generate the Tarray argument, and im not sure in what order the FBox would collect transforms.

As far as adding in bulk, im not sure thats possible. the players will be creating units in real time at unpredictable speeds/timings

Itā€™s not that important in the larger scope of things. I was hoping for an easier way to get many instances. A simple function call from a lib can do the same (as the function just loops over the instances anyway)

void UISMFunctionLibrary::GetTransforms(UInstancedStaticMeshComponent* ISM, int StartIndex, int EndIndex, TArray<FTransform> &out)
{
	out.Empty();
	for (int i = StartIndex; i < EndIndex; i++) {		
		if (ISM->PerInstanceSMData.IsValidIndex(i)) {
			out.Add(FTransform(ISM->PerInstanceSMData[i].Transform));
		}
	}	
}
1 Like

I believe the new problem may be due to the next waypoint only being set in the partial update branch. While the tests you are doing for that branch might look like this shouldnā€™t be possible, those tests are inconsistent with the outer if (DirectionLength > KINDA_SMALL_NUMBER), and a full step ((Step.SizeSquared() < DirectionLength * DirectionLength)) may bring us within KINDA_SMALL_NUMBER, where it will then be stuck forever.

Side note: You already calculated the direction magnitude exactly, so the SizeSquared() call can be removed and the test replaced with (MaxStepSize < DirectionLength).

As to fixing, you could move the next waypoint setting code after the branch (and wrap in an appropriate distance check), or perhaps easier would be to make the test conditions consistent, by changing if (Step.SizeSquared() < DirectionLength * DirectionLength) to if (DirectionLength - MaxStepSize > KINDA_SMALL_NUMBER).

1 Like

That was it! Youā€™ve got a good eye. Did you just visually check my code or did you run tests so solve the issue? If you ran test Iā€™m curious which

Alright, Iā€™m going to close out this discussion! Thank you so much to everyone that took the time to contribute. Much appreciated. You guys really got me out of a frustrating bind. Iā€™m going to continue work on some of the other optimization ideas you had throughout the chain

@3dRaven @RecourseDesign @silnarm

1 Like

You can call it a visual check, I ran no tests. That said, where the amount of problematic code allows (as was the case here) I do ā€˜runā€™ the code in a kind of virtual machine, in my head :wink:

While new to Unreal and not a game dev, I have been programming for many years now, and logic errors like these are common; so you get good at looking for edge cases.

1 Like

haha yea I figured. Thanks for your help.

1 Like

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.