diff --git a/sources/Aliases/Aliases.uc b/sources/Aliases/Aliases.uc index 2bbfb30..6519bc2 100644 --- a/sources/Aliases/Aliases.uc +++ b/sources/Aliases/Aliases.uc @@ -98,7 +98,8 @@ protected function ReadOtherSources(HashTable otherSourcesData) local HashTableIterator iter; customSource.length = 0; - iter = HashTableIterator(otherSourcesData.Iterate().LeaveOnlyNotNone()); + iter = HashTableIterator(otherSourcesData.Iterate()); + iter.LeaveOnlyNotNone(); for (iter = iter; !iter.HasFinished(); iter.Next()) { key = iter.GetKey(); diff --git a/sources/BaseRealm/Iter.uc b/sources/BaseRealm/Iter.uc index 2092e22..1055786 100644 --- a/sources/BaseRealm/Iter.uc +++ b/sources/BaseRealm/Iter.uc @@ -1,7 +1,8 @@ /** - * Base class for iterator, an auxiliary object for iterating through - * a set of objects obtained from some context-dependent source. - * Copyright 2022 Anton Tarasenko + * Author: dkanus + * Home repo: https://www.insultplayers.ru/git/AcediaFramework/AcediaCore + * License: GPL + * Copyright 2022-2023 Anton Tarasenko *------------------------------------------------------------------------------ * This file is part of Acedia. * @@ -21,56 +22,47 @@ class Iter extends AcediaObject abstract; -/** - * Iterators can filter objects they're iterating on by a presence or lack of - * a certain property, recording this choice requires 3 values, so `bool` - * isn't enough and we need to use this `enum` instead. - */ -enum IterFilter -{ - // We don't use relevant property for filtering - ITF_Nothing, - // Iterated objects must have that property - ITF_Have, - // Iterated objects must not have that property - ITF_NotHave +//! Base class for iterator, an auxiliary object for iterating through +//! a set of objects obtained from some context-dependent source. + +/// Status of the [`Iter`]'s filter regarding some specific property. +/// +/// [`Iter`]s can filter objects they're iterating on by the presence or lack of a certain property, +/// recording this choice requires 3 values (for requiring having/not having a certain property and +/// for ignoring it). +/// This enumeration is for inner purposes and is there to unify iterator implementations. +enum IterFilter { + /// We don't use relevant property for filtering + IF_Nothing, + /// Iterated objects must have that property + IF_Have, + /// Iterated objects must not have that property + IF_NotHave }; -/** - * Makes iterator pick next item. - * Use `HasFinished()` to check whether you have iterated all of them. - * - * @return Reference to caller `Iterator` to allow for method chaining. - */ -public function Iter Next(); +/// Advances iterator to the next item. +/// +/// Makes iterator refer to the next item from the source and returns `true`, as long as the source +/// of items isn't yet exhausted. +/// In case there's no more items, method has to return `false` and do nothing else. +/// [`Iter::HasFinished()`] can also be used to check whether there are more items available. +public function bool Next(); -/** - * Returns current value pointed to by an iterator. - * - * Does not advance iteration: use `Next()` to pick next value. - * - * @return Current value being iterated over. If `Iterator()` has finished - * iterating over all values or was not initialized - returns `none`. - * Note that depending on context `none` values can also be returned, - * use `LeaveOnlyNotNone()` method to prevent that. - */ +/// Returns value currently pointed to by an iterator. +/// +/// Does not advance iteration: use [`Iter::Next()`] to pick next value. +/// +/// In case iterator has already reached the end (and [`Iter::Next()``] returned `false`), this +/// method will return `none`. +/// Note that depending on context `none` values can also be returned, use +/// [`Iter::LeaveOnlyNotNone()`] method to prevent that. public function AcediaObject Get(); -/** - * Checks if caller `Iterator` has finished iterating. - * - * @return `true` if caller `Iterator` has finished iterating or - * was not initialized. `false` otherwise. - */ +/// Checks if caller [`Iter`] has finished iterating. public function bool HasFinished(); -/** - * Makes caller iterator skip any `none` items during iteration. - * - * @return Reference to caller `Iterator` to allow for method chaining. - */ -public function Iter LeaveOnlyNotNone(); +/// Makes caller iterator skip any `none` items during iteration. +public function LeaveOnlyNotNone(); -defaultproperties -{ +defaultproperties { } \ No newline at end of file diff --git a/sources/Data/Collections/ArrayListIterator.uc b/sources/Data/Collections/ArrayListIterator.uc index 233b9e0..f4279d1 100644 --- a/sources/Data/Collections/ArrayListIterator.uc +++ b/sources/Data/Collections/ArrayListIterator.uc @@ -1,6 +1,6 @@ /** * Iterator for iterating over `ArrayList`'s items. - * Copyright 2022 Anton Tarasenko + * Copyright 2022-2023 Anton Tarasenko *------------------------------------------------------------------------------ * This file is part of Acedia. * @@ -41,30 +41,29 @@ public function bool Initialize(Collection relevantArray) return true; } -public function Iter LeaveOnlyNotNone() +public function LeaveOnlyNotNone() { skipNoneReferences = true; - return self; } -public function Iter Next() +public function bool Next() { local int collectionLength; if (!skipNoneReferences) { currentIndex += 1; - return self; + return HasFinished(); } collectionLength = relevantCollection.GetLength(); while (currentIndex < collectionLength) { currentIndex += 1; if (!relevantCollection.IsNone(currentIndex)) { - return self; + return HasFinished(); } } - return self; + return HasFinished(); } public function AcediaObject Get() diff --git a/sources/Data/Collections/HashTableIterator.uc b/sources/Data/Collections/HashTableIterator.uc index 4463a44..cc85c4b 100644 --- a/sources/Data/Collections/HashTableIterator.uc +++ b/sources/Data/Collections/HashTableIterator.uc @@ -1,6 +1,6 @@ /** * Iterator for iterating over `HashTable`'s items. - * Copyright 2022 Anton Tarasenko + * Copyright 2022-2023 Anton Tarasenko *------------------------------------------------------------------------------ * This file is part of Acedia. * @@ -51,30 +51,29 @@ public function bool Initialize(Collection relevantArray) return true; } -public function Iter LeaveOnlyNotNone() +public function LeaveOnlyNotNone() { skipNoneReferences = true; - return self; } -public function Iter Next() +public function bool Next() { local int collectionLength; if (!skipNoneReferences) { hasNotFinished = relevantCollection.IncrementIndex(currentIndex); - return self; + return HasFinished(); } collectionLength = relevantCollection.GetLength(); while (hasNotFinished) { hasNotFinished = relevantCollection.IncrementIndex(currentIndex); if (relevantCollection.IsSomethingByIndex(currentIndex)) { - return self; + return HasFinished(); } } - return self; + return HasFinished(); } public function AcediaObject Get() diff --git a/sources/Data/Collections/Tests/TEST_Iterator.uc b/sources/Data/Collections/Tests/TEST_Iterator.uc index ffd79b9..5514e96 100644 --- a/sources/Data/Collections/Tests/TEST_Iterator.uc +++ b/sources/Data/Collections/Tests/TEST_Iterator.uc @@ -108,7 +108,8 @@ protected static function Test_ArrayList() Issue("Iterator for empty `ArrayList` does not return `none` as" @ "a current item."); TEST_ExpectNone(iter.Get()); - TEST_ExpectNone(iter.Next().Get()); + iter.Next(); + TEST_ExpectNone(iter.Get()); for (i = 0; i < default.items.length; i += 1) { array.AddItem(default.items[i]); @@ -142,7 +143,8 @@ protected static function Test_HashTable() Issue("Iterator for empty `HashTable` does not return `none` as" @ "a current item."); TEST_ExpectNone(iter.Get()); - TEST_ExpectNone(iter.Next().Get()); + iter.Next(); + TEST_ExpectNone(iter.Get()); for (i = 0; i < default.items.length; i += 1) { array.SetItem(__().box.int(i), default.items[i]); diff --git a/sources/Gameplay/BaseClasses/Frontend/World/EntityIterator.uc b/sources/Gameplay/BaseClasses/Frontend/World/EntityIterator.uc index 5b442d2..cb867c7 100644 --- a/sources/Gameplay/BaseClasses/Frontend/World/EntityIterator.uc +++ b/sources/Gameplay/BaseClasses/Frontend/World/EntityIterator.uc @@ -54,81 +54,61 @@ public function EPawn GetPawn(); /** * Makes caller iterator skip any entities that do not support `EPawn` * interface during iteration. - * - * @return Reference to caller `EntityIterator` to allow for method chaining. */ -public function EntityIterator LeaveOnlyPawns(); +public function LeaveOnlyPawns(); /** * Makes caller iterator skip any entities that support `EPawn` interface * during iteration. - * - * @return Reference to caller `EntityIterator` to allow for method chaining. */ -public function EntityIterator LeaveOnlyNonPawns(); +public function LeaveOnlyNonPawns(); /** * Makes caller iterator skip any entities that are placeable (support * `EPlaceable` interface) in the game. - * - * @return Reference to caller `EntityIterator` to allow for method chaining. */ -public function EntityIterator LeaveOnlyPlaceables(); +public function LeaveOnlyPlaceables(); /** * Makes caller iterator skip any entities that are not placeable (don't * support `EPlaceable` interface) into the game world. - * - * @return Reference to caller `EntityIterator` to allow for method chaining. */ -public function EntityIterator LeaveOnlyNonPlaceables(); +public function LeaveOnlyNonPlaceables(); /** * Makes caller iterator skip any entities that are not visible in the game * world. - * - * @return Reference to caller `EntityIterator` to allow for method chaining. */ -public function EntityIterator LeaveOnlyVisible(); +public function LeaveOnlyVisible(); /** * Makes caller iterator skip any entities that are visible in the game * world. - * - * @return Reference to caller `EntityIterator` to allow for method chaining. */ -public function EntityIterator LeaveOnlyInvisible(); +public function LeaveOnlyInvisible(); /** * Makes caller iterator skip any entities that are able to collide with other * entities in the game world. - * - * @return Reference to caller `EntityIterator` to allow for method chaining. */ -public function EntityIterator LeaveOnlyColliding(); +public function LeaveOnlyColliding(); /** * Makes caller iterator skip any entities that are unable to collide with * other entities in the game world. - * - * @return Reference to caller `EntityIterator` to allow for method chaining. */ -public function EntityIterator LeaveOnlyNonColliding(); +public function LeaveOnlyNonColliding(); /** * Makes caller iterator skip any non-static entities that do not change over * time, leaving only dynamic ones. - * - * @return Reference to caller `EntityIterator` to allow for method chaining. */ -public function EntityIterator LeaveOnlyStatic(); +public function LeaveOnlyStatic(); /** * Makes caller iterator skip any static entities that do not change over time. - * - * @return Reference to caller `EntityIterator` to allow for method chaining. */ -public function EntityIterator LeaveOnlyDynamic(); +public function LeaveOnlyDynamic(); /** * Leaves only placeable entities that are located no further than `radius` @@ -140,9 +120,8 @@ public function EntityIterator LeaveOnlyDynamic(); * close to. * @param radius Maximum distance that entities are allowed to be away * from `location`. - * @return Reference to caller `EntityIterator` to allow for method chaining. */ -public function EntityIterator LeaveOnlyNearby( +public function LeaveOnlyNearby( EPlaceable placeable, float radius); @@ -155,9 +134,8 @@ public function EntityIterator LeaveOnlyNearby( * @param location Location to which entities must be close to. * @param radius Maximum distance that entities are allowed to be away * from `location`. - * @return Reference to caller `EntityIterator` to allow for method chaining. */ -public function EntityIterator LeaveOnlyNearbyToLocation( +public function LeaveOnlyNearbyToLocation( Vector location, float radius); @@ -166,7 +144,7 @@ public function EntityIterator LeaveOnlyNearbyToLocation( * * `placeable` must have collisions enabled for any entity to touch it. */ -public function EntityIterator LeaveOnlyTouching(EPlaceable placeable); +public function LeaveOnlyTouching(EPlaceable placeable); defaultproperties { diff --git a/sources/Gameplay/KF1Frontend/World/KF1_TracingIterator.uc b/sources/Gameplay/KF1Frontend/World/KF1_TracingIterator.uc index a20cdc5..b5e9654 100644 --- a/sources/Gameplay/KF1Frontend/World/KF1_TracingIterator.uc +++ b/sources/Gameplay/KF1Frontend/World/KF1_TracingIterator.uc @@ -2,7 +2,7 @@ * `EntityIterator` / `TracingIterator` implementation for `KF1_Frontend`. * Both iterators do essentially the same and can be implemented with * a single class. - * Copyright 2022 Anton Tarasenko + * Copyright 2022-2023 Anton Tarasenko *------------------------------------------------------------------------------ * This file is part of Acedia. * @@ -112,11 +112,11 @@ protected function Finalizer() iterated = false; // Clear conditions // ~ Simple conditions - pawnsFilter = ITF_Nothing; - placeablesFilter = ITF_Nothing; - collidingFilter = ITF_Nothing; - visibleFilter = ITF_Nothing; - staticFilter = ITF_Nothing; + pawnsFilter = IF_Nothing; + placeablesFilter = IF_Nothing; + collidingFilter = IF_Nothing; + visibleFilter = IF_Nothing; + staticFilter = IF_Nothing; // ~ Distance conditions distanceCheck = false; _.memory.Free(shortestLimitation.placeable); @@ -162,7 +162,7 @@ public final function InitializeTracing(Vector start, Vector end) } startPosition = start; endPosition = end; - collidingFilter = ITF_Have; + collidingFilter = IF_Have; initialized = true; tracingIterator = true; } @@ -237,30 +237,30 @@ private final function bool ProcessActor( if (allowedList.length > 0 && IsAllowed(nextActor, allowedList)) { return false; } - if (staticFilter == ITF_Have && !nextActor.bStatic) { + if (staticFilter == IF_Have && !nextActor.bStatic) { return false; } - if (staticFilter == ITF_NotHave && nextActor.bStatic) { + if (staticFilter == IF_NotHave && nextActor.bStatic) { return false; } isCollidable = (nextActor.bCollideActors || (LevelInfo(nextActor) != none)); - if (collidingFilter == ITF_Have && !isCollidable) { + if (collidingFilter == IF_Have && !isCollidable) { return false; } - if (collidingFilter == ITF_NotHave && isCollidable) { + if (collidingFilter == IF_NotHave && isCollidable) { return false; } - if (placeablesFilter == ITF_Have && nextActor.bWorldGeometry) { + if (placeablesFilter == IF_Have && nextActor.bWorldGeometry) { return false; } - if (placeablesFilter == ITF_NotHave && !nextActor.bWorldGeometry) { + if (placeablesFilter == IF_NotHave && !nextActor.bWorldGeometry) { return false; } isVisible = IsActorVisible(nextActor); - if (visibleFilter == ITF_Have && !isVisible) { + if (visibleFilter == IF_Have && !isVisible) { return false; } - if (visibleFilter == ITF_NotHave && isVisible) { + if (visibleFilter == IF_NotHave && isVisible) { return false; } if (distanceCheck && !IsCloseEnough(nextActor)) { @@ -395,7 +395,7 @@ private final function TryIterating() return; } core = ServerLevelCore(class'ServerLevelCore'.static.GetInstance()); - if (pawnsFilter == ITF_Have) { + if (pawnsFilter == IF_Have) { targetClass = class'Pawn'; } else { @@ -456,7 +456,7 @@ private final function DoIterate_PickBest( // preferable, but only doable if we're also filtering by distance. if (distanceCheck) { - if (collidingFilter == ITF_Have) { + if (collidingFilter == IF_Have) { DoIterate_Colliding(core, targetClass); } else { @@ -466,7 +466,7 @@ private final function DoIterate_PickBest( return; } // If above fails - try to at least limit iteration to dynamic actors - if (staticFilter == ITF_NotHave) + if (staticFilter == IF_NotHave) { DoIterate_Dynamic(core, targetClass); return; @@ -581,14 +581,13 @@ private final function DoIterate_All( } } -public function Iter Next() +public function bool Next() { if (!initialized) { - return self; + return false; } - TryIterating(); currentIndex += 1; - return self; + return HasFinished(); } public function AcediaObject Get() @@ -655,11 +654,10 @@ public function bool HasFinished() return (currentIndex >= foundActors.length); } -public function Iter LeaveOnlyNotNone() +public function LeaveOnlyNotNone() { // We cannot iterate over `none` actors with native iterators, so this // condition is automatically satisfied - return self; } private final function UpdateFilter( @@ -669,8 +667,8 @@ private final function UpdateFilter( if (!initialized) return; if (iterated) return; - if (actualValue == ITF_Nothing) { - actualValue = ITF_Have; + if (actualValue == IF_Nothing) { + actualValue = IF_Have; } else if (actualValue != newValue) { @@ -679,65 +677,54 @@ private final function UpdateFilter( } } -public function EntityIterator LeaveOnlyPawns() +public function LeaveOnlyPawns() { - UpdateFilter(pawnsFilter, ITF_Have); - return self; + UpdateFilter(pawnsFilter, IF_Have); } -public function EntityIterator LeaveOnlyNonPawns() +public function LeaveOnlyNonPawns() { - - UpdateFilter(pawnsFilter, ITF_NotHave); - return self; + UpdateFilter(pawnsFilter, IF_NotHave); } -public function EntityIterator LeaveOnlyPlaceables() +public function LeaveOnlyPlaceables() { - UpdateFilter(placeablesFilter, ITF_Have); - return self; + UpdateFilter(placeablesFilter, IF_Have); } -public function EntityIterator LeaveOnlyNonPlaceables() +public function LeaveOnlyNonPlaceables() { - UpdateFilter(placeablesFilter, ITF_NotHave); - return self; + UpdateFilter(placeablesFilter, IF_NotHave); } -public function EntityIterator LeaveOnlyVisible() +public function LeaveOnlyVisible() { - UpdateFilter(visibleFilter, ITF_Have); - return self; + UpdateFilter(visibleFilter, IF_Have); } -public function EntityIterator LeaveOnlyInvisible() +public function LeaveOnlyInvisible() { - UpdateFilter(visibleFilter, ITF_NotHave); - return self; + UpdateFilter(visibleFilter, IF_NotHave); } -public function EntityIterator LeaveOnlyColliding() +public function LeaveOnlyColliding() { - UpdateFilter(collidingFilter, ITF_Have); - return self; + UpdateFilter(collidingFilter, IF_Have); } -public function EntityIterator LeaveOnlyNonColliding() +public function LeaveOnlyNonColliding() { - UpdateFilter(collidingFilter, ITF_NotHave); - return self; + UpdateFilter(collidingFilter, IF_NotHave); } -public function EntityIterator LeaveOnlyStatic() +public function LeaveOnlyStatic() { - UpdateFilter(staticFilter, ITF_Have); - return self; + UpdateFilter(staticFilter, IF_Have); } -public function EntityIterator LeaveOnlyDynamic() +public function LeaveOnlyDynamic() { - UpdateFilter(staticFilter, ITF_NotHave); - return self; + UpdateFilter(staticFilter, IF_NotHave); } private function AddDistanceLimitation(NearbyLimitation newLimitation) @@ -761,15 +748,15 @@ private function AddDistanceLimitation(NearbyLimitation newLimitation) } } -public function EntityIterator LeaveOnlyNearby( +public function LeaveOnlyNearby( EPlaceable placeable, float radius) { local NearbyLimitation newLimitation; - if (!initialized) return self; - if (iterated) return self; - if (placeable == none) return self; + if (!initialized) return; + if (iterated) return; + if (placeable == none) return; placeable.NewRef(); newLimitation.placeable = placeable; @@ -777,35 +764,32 @@ public function EntityIterator LeaveOnlyNearby( newLimitation.distance = radius; newLimitation.distanceSquared = radius * radius; AddDistanceLimitation(newLimitation); - return self; } -public function EntityIterator LeaveOnlyNearbyToLocation( +public function LeaveOnlyNearbyToLocation( Vector location, float radius) { local NearbyLimitation newLimitation; - if (!initialized) return self; - if (iterated) return self; + if (!initialized) return; + if (iterated) return; newLimitation.location = location; newLimitation.distance = radius; newLimitation.distanceSquared = radius * radius; AddDistanceLimitation(newLimitation); - return self; } -public function EntityIterator LeaveOnlyTouching(EPlaceable placeable) +public function LeaveOnlyTouching(EPlaceable placeable) { - if (!initialized) return self; - if (iterated) return self; - if (placeable == none) return self; + if (!initialized) return; + if (iterated) return; + if (placeable == none) return; touchingCheck = true; placeable.NewRef(); touchers[touchers.length] = placeable; - return self; } defaultproperties