Alright!
I see what's up.
We've got the sloppiest player transport code being transferred from old Fighters into the new RX's and SLV.
The modder has two choices:
- Let the player touch objects directly, use Move() instead of SetLocation().
- Transfer touch/bump events from the carrier into the player, use SetLocation and disable all player collision.
Both mod and XC_Engine are at fault here, now given that SetLocation is what is being used... it's safe to assume that the 'Hash' query used is 'Encroachment'.
My 'gridded octree' is open sourced, everyone can check it out.
These are the queries inherited from FCollisionHashBase type into FCollisionCacus.
Code: Select all
FCheckResult* ActorLineCheck( FMemStack& Mem, FVector End, FVector Start, FVector Extent, BYTE ExtraNodeFlags );
FCheckResult* ActorPointCheck( FMemStack& Mem, FVector Location, FVector Extent, DWORD ExtraNodeFlags );
FCheckResult* ActorRadiusCheck( FMemStack& Mem, FVector Location, FLOAT Radius, DWORD ExtraNodeFlags );
FCheckResult* ActorEncroachmentCheck( FMemStack& Mem, AActor* Actor, FVector Location, FRotator Rotation, DWORD ExtraNodeFlags );
Movement code does ActorLineCheck with an extent, then ActorEncroachmentCheck in most cases to process overlapping.
Strangely enough, teleporting doesn't use preemptive ActorPointCheck against other actors, but goes straight to ActorEncroachmentCheck. Makes sense, because if ActorPointCheck was used, then it would be impossible to teleport into other players using a translocator (players would be solid and negate ability to occupy said space).
I added a lot of conditionals to my variation of ActorEncroachmentCheck to speed it up, because some of UT's default methods were very CPU inefficient, I may have overdone it...
Let's take a look:
Code: Select all
FCheckResult* FCollisionCacus::ActorEncroachmentCheck( FMemStack& Mem, AActor* Actor, FVector Location, FRotator Rotation, DWORD ExtraNodeFlags )
{
if ( BrushMover(Actor) )
{
Exchange( Actor->Location, Location);
FBox Box = Actor->Brush->GetCollisionBoundingBox( Actor);
FCheckResult* Result = MEncroachQuery( Mem, Actor, Box);
Exchange( Actor->Location, Location);
return Result;
}
else if ( Actor->bBlockPlayers || Actor->bBlockActors )
{
const FBox ActorBox( Location-Actor->GetCylinderExtent(), Location+Actor->GetCylinderExtent() );
if ( Actor->bIsPawn && Actor->GetPlayerPawn() )
return PEncroachQuery( Mem, Actor, Location, ActorBox);
return AEncroachQuery( Mem, Actor, Location, ActorBox);
}
return NULL;
}
I assume SLV and RX don't remove the bBlockPlayers and bBlockActors from player, but I could totally be wrong.
PEncroachQuery looks like the type of query we'd be using...
Code: Select all
//Recursive actor iteration
//Obtains actors touching a player (future loc)
FCheckResult* FCollisionOctree::PEncroachQuery( FMemStack& Mem, AActor* Actor, const FVector& Location, const FBox& ActorBox, FCheckResult* PrevLink)
{
for ( INT i=0 ; i<Actors.Num() ; i++ )
{
if ( !Actors(i).Actor->bBlockPlayers || !BoxBoxIntersect( ActorBox, Actors(i).Box) ) //Quick box rejects, we don't need to perform Z check later
continue;
AActor* TestActor = Actors(i).Actor;
if ( Actor == TestActor )
continue;
if ( (FVector(Location.X-Actors(i).Location.X,Location.Y-Actors(i).Location.Y,0.f).SizeSquared2D() < Square( Actor->CollisionRadius+TestActor->CollisionRadius)) )
{
PrevLink = new(Mem)FCheckResult( 0.f, PrevLink);
PrevLink->Actor = TestActor;
PrevLink->Location = Actors(i).Location;
}
}
for ( i=0 ; i<ChildCount ; i++ )
if ( BoxBoxIntersect( ActorBox, ReducedChildren[i]->BoundingBox) )
PrevLink = ReducedChildren[i]->PEncroachQuery( Mem, Actor, Location, ActorBox, PrevLink);
return PrevLink;
}
Ok here we have it, the target actors also require to have bBlockPlayers.
This means that my octree is completely ignoring touch-on-teleport when the target actor isn't blocking the source actor.
This also means that UT is using EncroachmentQuery for both encroachment and touch-on-teleport events, very different things by the same function... which isn't supposed to do the latter anyways (ActorPointCheck should do this).
The solution will be to simply consider all non-blocking target actors as encroachment candidates.