en:toolworks:docs:apparatus:iterating

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
en:toolworks:docs:apparatus:iterating [2021/08/28 23:52] vladiusen:toolworks:docs:apparatus:iterating [2022/06/05 15:26] (current) – Пофиксил ссылки, чтобы они указывали на существующую страницу. jispar
Line 1: Line 1:
 ====== Iterating ====== ====== Iterating ======
  
-In order to implement your actual Mechanic logic you have to be able to process all of the [[en:toolworks:docs:apparatus:filter|Filter]]-matching Subjects (and Subjectives, which are in turn - Subjects). For the purpose of effectiveness and consistency this is not done directly but via [[en:toolworks:docs:apparatus:enchaining|Chains]]. You iterate those Chains iterating all the Subjects and Subjectives inside them.+In order to implement your actual Mechanic logic you have to be able to process all of the [[en:toolworks:docs:apparatus:filter|Filter]]-matching Subjects (and Subjectives, which are in turn - Subjects). For the purpose of effectiveness (and consistencythis is mainly done through [[en:toolworks:docs:apparatus:enchaining|Chains]]. You iterate those Chains by iterating through all the Subjects and Subjectives inside them.
  
-Chains are iterated with the help of Cursors. Those are very much like container iterators. Multiple Cursors are available but this is more of a multi-threading future-proofing. For now, you should really use a single default Cursor only.+Chains are iterated with the help of Cursors. Those are very much like container iterators. /* TODO update: Multiple Cursors are available but this is more of a multi-threading future-proofing. For now, you should really use a single default Cursor only. */
  
 ===== C++ Workflow ===== ===== C++ Workflow =====
 +
 +Iterating a Chain is done through a special type of object called //Cursor//.
 +You can have as many of those, but usually one is enough:
 +
 +<code cpp>
 +FChain::FCursor Cursor = Chain->Iterate();
 +</code>
 +
 +The solid-variant would logically be like so:
 +
 +<code cpp>
 +FSolidChain::FCursor SolidCursor = SolidChain->Iterate();
 +</code>
 +
 +When you got the Cursor needed, you can construct a simple while loop like so:
 +
 +<code cpp>
 +while (Cursor.Provide())
 +{
 +  auto Trait = Cursor.GetTrait<FMyTrait>();
 +  ...
 +}
 +</code>
 +
 +The ''[[appi>struct_t_chain_1_1_f_cursor.html#a4d4c891b529d09be7a57791cd886587b|Provide()]]'' method prepares the needed state and would return ''false'' when there
 +are no more slots available (''true'', otherwise).
 +
 +With a solid Cursor you can also get a direct (copy-free) reference to a Trait (with a ''[[appi>struct_t_chain_1_1_f_cursor.html#acf92a6a5684871a0c24f1e7360314ada|GetTraitRef()]]'' method):
 +
 +<code cpp>
 +while (SolidCursor.Provide())
 +{
 +  auto& Trait = SolidCursor.GetTraitRef<FMyTrait>();
 +  ...
 +}
 +</code>
 +
 +Please note, that the Chain gets disposed automatically when all
 +of the iterating Cursors have finished providing (iterating) the slots.
 +To suppress this behavior use explicit ''[[appi>struct_t_chain.html#abdde97a57f62214dff4e643287eb2fae|Retain()]]''/''[[appi>struct_t_chain.html#a665154da00eac2bcc7760851583db281|Release()]]'' calls
 +for a custom lifetime organization:
 +
 +<code cpp>
 +Chain->Retain(); // Grab the chain.
 +FChain::FCursor Cursor = Chain->Iterate();
 +while (Cursor.Provide())
 +{
 +  ...
 +}
 +// Do some other stuff with the chain.
 +// It's now guaranteed to not be disposed.
 +...
 +Chain->Release(); // Free the chain.
 +</code>
  
 ==== Embedded Cursors ==== ==== Embedded Cursors ====
  
-Apparatus provides a way to iterate the chains via embedded (self-allocated) cursors also.+Apparatus provides a way to iterate the chains via embedded (self-allocated) cursors
 +This is mainly utilized internally, by the Blueprints and generally should be 
 +avoided within your C++ code.
  
 Your basic loop is quite simple. It's just a ''while'' statement with a single condition:<code cpp> Your basic loop is quite simple. It's just a ''while'' statement with a single condition:<code cpp>
Line 36: Line 92:
 When the Chain Cursor is gone past the last available Subject/Subjective the Chain becomes disposed and the previously locked Chunks and Belts become unlocked again, applying all the pending changes (if there are any). When the Chain Cursor is gone past the last available Subject/Subjective the Chain becomes disposed and the previously locked Chunks and Belts become unlocked again, applying all the pending changes (if there are any).
  
 +==== Direct Iterating ====
 +
 +If you want to iterate the Chunks directly you can utilize the Chunks Proxies.
 +You will basically need to iterate all of the Proxies collected
 +through the corresponding [[appi>class_a_mechanism.html#ae72188d973bed3d8484dc5ab87e5e1e1|Enchain]] method and
 +within each Chunk iterate all of its Subjects-containing Slots.
 +
 +An example is as such:<code cpp>
 +TArray<TChunkProxy<FSolidSubjectHandle, FJumpingTrait>> ChunkProxies;
 +Mechanism->Enchain(TFilter<FJumpingTrait>(), ChunkProxies);
 +for (int32 i = 0; i < ChunkProxies.Num(); ++i) // Iterate through all of the matching Chunks...
 +{
 + auto& ChunkProxy = ChunkProxies[i];
 + for (int32 j = 0; j < ChunkProxy.Num(); ++j) // Iterate through all of the Chunk's Slots...
 + {
 + // Perform the necessary logic...
 + ChunkProxy.TraitRefAt<FJumpingTrait>(j).Position += FVector::UpVector * DeltaTime;
 + }
 +}
 +</code>
 +
 +Please note however, that this approach is totally manual, and doesn't perform any Iterating-time logic checks like the [[en:toolworks:docs:apparatus:flagmark|Flagmark]]-matching.
 +
 +If you're also performing some topology-changing logic within your loops your Subjects can change their Chunks and Slots in an arbitrary way, so perhaps you also have to be checking for Slots to be (non-)stale.
 +
 +You would do it like so:<code cpp>
 +for (int32 j = 0; j < ChunkProxy.Num(); ++j) // Iterate through all of the Chunk's Slots...
 +{
 + if (ChunkProxy.IsStaleAt(j)) continue; // Skip the Subject if it's either moved or despawned...
 + ChunkProxy.SubjectAt(j).SetTrait(FSpeedBoostTrait{10.0f});
 +}
 +</code>
  
 +Iterating the Chunks directly (via Proxies) can introduce a certain performance boost as compared to normal iterating and [[en:toolworks:docs:apparatus:operating|Operating]]. That's mainly due to being able to control every aspect of the Iterating by hand and exclude all of the checks unnecessary for your logic. You just have to know exactly what you're doing and trying to achieve as this way is a bit less secure.
  • en/toolworks/docs/apparatus/iterating.1630183956.txt.gz
  • Last modified: 2021/08/28 23:52
  • by vladius