diff --git a/sources/Gameplay/BaseClasses/Frontend/World/AWorldComponent.uc b/sources/Gameplay/BaseClasses/Frontend/World/AWorldComponent.uc
index b0bf565..2a153d3 100644
--- a/sources/Gameplay/BaseClasses/Frontend/World/AWorldComponent.uc
+++ b/sources/Gameplay/BaseClasses/Frontend/World/AWorldComponent.uc
@@ -89,6 +89,13 @@ public function EPlaceable Spawn(
optional Vector location,
optional Rotator direction);
+/**
+ * Returns iterator for going through all entities in the game world.
+ *
+ * @return `EntityIterator` that will iterate through world entities.
+ */
+public function EntityIterator Entities();
+
defaultproperties
{
}
\ No newline at end of file
diff --git a/sources/Gameplay/BaseClasses/Frontend/World/EntityIterator.uc b/sources/Gameplay/BaseClasses/Frontend/World/EntityIterator.uc
new file mode 100644
index 0000000..1f8826e
--- /dev/null
+++ b/sources/Gameplay/BaseClasses/Frontend/World/EntityIterator.uc
@@ -0,0 +1,80 @@
+/**
+ * Iterator for going through all the entities inside the game world.
+ * Copyright 2022 Anton Tarasenko
+ *------------------------------------------------------------------------------
+ * This file is part of Acedia.
+ *
+ * Acedia is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Acedia is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Acedia. If not, see .
+ */
+class EntityIterator extends Iter
+ abstract;
+
+/**
+ * Returns only `EPlaceable` interfaces for world entities.
+ *
+ * Resulting `EPlaceable` can refer to now non-existing entities if they were
+ * destroyed after the start of iteration.
+ */
+public function AcediaObject Get() { return none; }
+
+/**
+ * Returns `EPlaceable` caller `EntityIterator` is currently at.
+ * Guaranteed to be not `none` as long as iteration hasn't finished.
+ *
+ * Resulting `EPlaceable` can refer to now non-existing entities if they were
+ * destroyed after the start of iteration.
+ *
+ * @return `EPlaceable` caller `EntityIterator` is currently at.
+ */
+public function EPlaceable GetPlaceable();
+
+/**
+ * Returns `EPlaceable` caller `EntityIterator` is currently at as `EPawn`,
+ * assuming that its entity support that interface.
+ *
+ * Resulting `EPawn` can refer to now non-existing entities if they were
+ * destroyed after the start of iteration.
+ *
+ * @return `EPawn` interface for `EPlaceable` that `Get()` would have returned.
+ * If `EPawn` is not supported by that `EPlaceable` - returns `none`.
+ */
+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();
+
+/**
+ * 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 LeaveOnlyPlaceables();
+
+/**
+ * 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();
+
+defaultproperties
+{
+}
\ No newline at end of file
diff --git a/sources/Gameplay/KF1Frontend/World/KF1_EntityIterator.uc b/sources/Gameplay/KF1Frontend/World/KF1_EntityIterator.uc
new file mode 100644
index 0000000..287c373
--- /dev/null
+++ b/sources/Gameplay/KF1Frontend/World/KF1_EntityIterator.uc
@@ -0,0 +1,184 @@
+/**
+ * `EntityIterator` implementation for `KF1_Frontend`.
+ * Copyright 2022 Anton Tarasenko
+ *------------------------------------------------------------------------------
+ * This file is part of Acedia.
+ *
+ * Acedia is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Acedia is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Acedia. If not, see .
+ */
+class KF1_EntityIterator extends EntityIterator;
+
+var private bool initialized;
+
+var private int currentIndex;
+// Simply store all traced `Actor`s here at the moment of user first
+// interacting with iterator's items: when either `Next()` or one of
+// the `Get...()` methods were called.
+var private array foundActors;
+// Did we already perform iteration through actors?
+var private bool iterated;
+
+// Iterator filters
+var private bool onlyPawns;
+var private bool onlyPlaceables;
+var private bool onlyVisible;
+
+protected function Finalizer()
+{
+ _.memory.FreeMany(foundActors);
+ foundActors.length = 0;
+ initialized = false;
+}
+
+/**
+ * Initializes `TracingIterator` that traces entities between `start` and
+ * `end` positions, in order starting from the `start`
+ */
+public final function Initialize()
+{
+ initialized = true;
+}
+
+private final function bool IsActorVisible(Actor actorToCheck)
+{
+ if (actorToCheck == none) return false;
+ if (actorToCheck.bHidden && !actorToCheck.bWorldGeometry) return false;
+ if (actorToCheck.drawType == DT_None) return false;
+
+ return true;
+}
+
+// Does actual tracing, but only once per iterator's lifecycle.
+// Assumes `initialized` is `true`.
+private final function TryIterating()
+{
+ local Pawn nextPawn;
+ local Actor nextActor;
+ local class targetClass;
+ local ServerLevelCore core;
+
+ // Checking `initialized` flag is already done by every method that
+ // calls `TryTracing()`
+ if (iterated) {
+ return;
+ }
+ currentIndex = 0;
+ if (onlyPawns) {
+ targetClass = class'Pawn';
+ }
+ else {
+ targetClass = class'Actor';
+ }
+ core = ServerLevelCore(class'ServerLevelCore'.static.GetInstance());
+ // TODO: We should not always use slow `AllActors()` method
+ foreach core.AllActors(targetClass, nextActor)
+ {
+ if (onlyVisible && !IsActorVisible(nextActor)) {
+ continue;
+ }
+ nextPawn = Pawn(nextActor);
+ if (nextPawn != none)
+ {
+ foundActors[foundActors.length] =
+ class'EKFPawn'.static.Wrap(nextPawn);
+ }
+ else {
+ foundActors[foundActors.length] =
+ class'EKFUnknownPlaceable'.static.Wrap(nextActor);
+ }
+ }
+ iterated = true;
+}
+
+public function Iter Next(optional bool skipNone)
+{
+ if (!initialized) {
+ return self;
+ }
+ TryIterating();
+ currentIndex += 1;
+ return self;
+}
+
+public function AcediaObject Get()
+{
+ if (!initialized) {
+ return none;
+ }
+ TryIterating();
+ if (HasFinished()) {
+ return none;
+ }
+ return foundActors[currentIndex].NewRef();
+}
+
+public function EPlaceable GetPlaceable()
+{
+ // We only create `EPlaceable` child classes in this class
+ return EPlaceable(Get());
+}
+
+public function EPawn GetPawn()
+{
+ local AcediaObject result;
+ local EPawn pawnResult;
+
+ if (!initialized) {
+ return none;
+ }
+ result = Get();
+ pawnResult = EPawn(result);
+ if (pawnResult == none) {
+ _.memory.Free(result);
+ }
+ return pawnResult;
+}
+
+public function bool HasFinished()
+{
+ TryIterating();
+ return (currentIndex >= foundActors.length);
+}
+
+public function Iter LeaveOnlyNotNone()
+{
+ // We cannot tracer `none` actors, so no need to do anything
+ return self;
+}
+
+public function EntityIterator LeaveOnlyPawns()
+{
+ if (initialized && !iterated) {
+ onlyPawns = true;
+ }
+ return self;
+}
+
+public function EntityIterator LeaveOnlyPlaceables() {
+ // Doesn't do anything for now
+ // TODO: make it actually do something
+ return self;
+}
+
+public function EntityIterator LeaveOnlyVisible()
+{
+ if (initialized && !iterated) {
+ onlyVisible = true;
+ }
+ return self;
+}
+
+defaultproperties
+{
+}
\ No newline at end of file