Faster ForEach iterators without dependancy

Discussions about Coding and Scripting
Post Reply
Higor
Godlike
Posts: 1866
Joined: Sun Mar 04, 2012 6:47 pm

Faster ForEach iterators without dependancy

Post by Higor »

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)$"]");
}
Post Reply