Faster ForEach iterators without dependancy
Posted: Thu Mar 02, 2017 10:27 pm
Sometimes you want to make something work in more than one setup/mod, and sometimes you want to avoid relatively slow code, especially when dealing with iterators.
The script compiler is hardcoded to match the variably type of parameter 2 to that of the class type of parameter 1, but you can force it to search any non-hardcoded actor type... as long as the parameter 2 corresponds to 'Actor'.
=== Both syntaxis allowed by the compiler:
Some notes on these iterators.
- With the second mechanism, if AC is none, then class'Actor' is forced internally.
- TraceActors is bugged and returns EVERY hit, for safety always do (class'Actor', A, ...) at all times.
=== Iterating with a different context:
It is possible to call these iterators using a different actor as context to modify the behaviour of the iterators, some iterators are designed for this to be explicitly done.
Find actors belonging to 'self'
Find actors belonging to other actors
Some notes on these iterators.
- If context is none, the game will crash.
- Both class/type mechanisms can be used here.
- In the case of TraceActors, parameter start will default to context's Location.
=== Non-standard iterators.
Both mechanisms also works on non-standard iterators, as long as you match the base object type the iterator wants you to input, in the following case it's Inventory.
XC_Engine's version of FindInventoryType, which originally can take ANY class type as parameter so we double check here.
The script engine doesn't verify that 'DesiredClass' is indeed a class<Inventory> type after the horrible hack I used, same happens with TraceActors when you try to get non-Actor results.
===============================
Here are a few examples of how this can be used in real life situations, mainly goes into interacting with other mods without requiring to load them.
The script compiler is hardcoded to match the variably type of parameter 2 to that of the class type of parameter 1, but you can force it to search any non-hardcoded actor type... as long as the parameter 2 corresponds to 'Actor'.
=== Both syntaxis allowed by the compiler:
Code: Select all
local info IF;
ForEach AllActors( class'Info', IF)
break;
Code: Select all
local class<Actor> AC;
local Actor A;
//Load AC
if ( AC != None )
ForEach AllActors( AC, A)
break;
- With the second mechanism, if AC is none, then class'Actor' is forced internally.
- TraceActors is bugged and returns EVERY hit, for safety always do (class'Actor', A, ...) at all times.
=== Iterating with a different context:
It is possible to call these iterators using a different actor as context to modify the behaviour of the iterators, some iterators are designed for this to be explicitly done.
Find actors belonging to 'self'
Code: Select all
ForEach ChildActors( class'Actor', A)
{...}
Code: Select all
local Actor B;
if ( B != None )
ForEach B.ChildActors( class'Actor', A)
{...}
- If context is none, the game will crash.
- Both class/type mechanisms can be used here.
- In the case of TraceActors, parameter start will default to context's Location.
=== Non-standard iterators.
Both mechanisms also works on non-standard iterators, as long as you match the base object type the iterator wants you to input, in the following case it's Inventory.
Code: Select all
native(3542) final iterator function InventoryActors( class<Inventory> InvClass, out Inventory Inv, optional bool bSubclasses, optional Actor StartFrom);
The script engine doesn't verify that 'DesiredClass' is indeed a class<Inventory> type after the horrible hack I used, same happens with TraceActors when you try to get non-Actor results.
Code: Select all
function Inventory FindInventoryType_Fast( class<Inventory> DesiredClass ) //Compiler hack, originally class<Object>, parameter still passed!!!
{
local Inventory Inv;
if ( ClassIsChildOf( DesiredClass, class'Inventory') ) //Here we do check that it's a class<Inventory> being passed
ForEach InventoryActors( DesiredClass, Inv) //Native class check occurs here, so Inv matches what we're looking for
return Inv;
}
===============================
Here are a few examples of how this can be used in real life situations, mainly goes into interacting with other mods without requiring to load them.
Code: Select all
final function class<Actor> LoadActorClass( string S)
{
return Class<Actor>( DynamicLoadObject( S, class'class', true) ); //Third parameter prevents failure output in log
}
Code: Select all
function IteratorsTest()
{
local Actor A, B, C;
local Pawn P;
local class<Actor> AClass, BClass, CClass;
AClass = LoadActorClass( "XC_Engine.XC_Engine_Actor");
BClass = LoadActorClass( "SmartCTF_4D.SmartCTFPlayerReplicationInfo");
if ( BClass == None )
BClass = LoadActorClass( "SmartCTF_4C.SmartCTFPlayerReplicationInfo");
CClass = LoadActorClass( "IACEv10.IACEActor");
if ( CClass == None )
CClass = LoadActorClass( "IACEv08c.IACEActor");
//Find XC_Engine's main actor
if ( AClass != None )
ForEach AllActors( AClass, A)
Log("XC_Engine actor: "$A.Name);
//Find SmartCTF stats
if ( BClass != None )
For ( P=Level.PawnList ; P!=None ; P=P.NextPawn )
if ( P.bIsPlayer && (P.PlayerReplicationInfo != None) )
ForEach P.ChildActors( BClass, B)
{
//Do stuff
break;
}
//Find actors spawned by ACE
if ( CClass != None )
ForEach AllActors( CClass, C)
Log("ACE actor: "$C.Name@[$string(C.Class)$"]");
}