Faster ForEach iterators without dependancy

Discussions about Coding and Scripting

Faster ForEach iterators without dependancy

Postby Higor » 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:
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;

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'
Code: Select all
ForEach ChildActors( class'Actor', A)
    {...}


Find actors belonging to other actors
Code: Select all
local Actor B;
if ( B != None )
    ForEach B.ChildActors( class'Actor', A)
        {...}

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.
Code: Select all
native(3542) final iterator function InventoryActors( class<Inventory> InvClass, out Inventory Inv, optional bool bSubclasses, optional Actor StartFrom);


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.
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)$"]");
}
Higor
Godlike
 
Posts: 1716
Joined: Sun Mar 04, 2012 6:47 pm

Return to Coding, Scripting

Who is online

Users browsing this forum: No registered users and 2 guests