Browse Source

Add tracing methods to the world component

pull/8/head
Anton Tarasenko 2 years ago
parent
commit
f56616f5b7
  1. 50
      sources/Gameplay/BaseClasses/Frontend/World/AWorldComponent.uc
  2. 108
      sources/Gameplay/BaseClasses/Frontend/World/TracingIterator.uc
  3. 2
      sources/Gameplay/KF1Frontend/BaseImplementation/EKFPawn.uc
  4. 125
      sources/Gameplay/KF1Frontend/BaseImplementation/EKFUnknownPlaceable.uc
  5. 195
      sources/Gameplay/KF1Frontend/World/KF1_TracingIterator.uc
  6. 90
      sources/Gameplay/KF1Frontend/World/KF1_WorldComponent.uc

50
sources/Gameplay/BaseClasses/Frontend/World/AWorldComponent.uc

@ -21,6 +21,56 @@
class AWorldComponent extends AcediaObject
abstract;
/**
* Traces world for entities starting from `start` point and continuing into
* the direction `direction` for a "far distance". What is considered
* a "far distance" depends on the implementation (can potentially be infinite
* distance).
*
* @param start Point from which to start tracing.
* @param direction Direction alongside which to trace.
* @return `TracingIterator` that will iterate among `EPlaceable` interfaces
* for traced entities. Iteration is done in order from the entity closest
* to `start` point.
*/
public function TracingIterator Trace(Vector start, Rotator direction);
/**
* Traces world for entities starting from `start` point and until `end` point.
*
* @param start Point from which to start tracing.
* @param end Point at which to stop tracing.
* @return `TracingIterator` that will iterate among `EPlaceable` interfaces
* for traced entities. Iteration is done in order from the entity closest
* to `start` point.
*/
public function TracingIterator TraceBetween(Vector start, Vector end);
/**
* Traces world for entities starting from the `player`'s camera position and
* along the direction of his sight.
*
* This method works for both players with and without pawns. For player with
* a pawn it produce identical results to `TraceSight()` method.
*
* @param player Player alongside whos sight method is supposed to trace.
* @return `TracingIterator` that will iterate among `EPlaceable` interfaces
* for traced entities. Iteration is done in order from the entity closest
* to `player`'s camera location.
*/
public function TracingIterator TracePlayerSight(EPlayer player);
/**
* Traces world for entities starting from the `pawn`'s camera position and
* along the direction of his sight.
*
* @param pawn Pawn alongside whos sight method is supposed to trace.
* @return `TracingIterator` that will iterate among `EPlaceable` interfaces
* for traced entities. Iteration is done in order from the entity closest
* to `pawn`'s eyes location.
*/
public function TracingIterator TraceSight(EPawn pawn);
defaultproperties
{
}

108
sources/Gameplay/BaseClasses/Frontend/World/TracingIterator.uc

@ -0,0 +1,108 @@
/**
* Iterator for tracing 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 <https://www.gnu.org/licenses/>.
*/
class TracingIterator extends Iter
abstract;
/**
* Returns only `EPlaceable` interfaces for traced 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 hit location for the `EPlaceable` that `TracingIterator` is
* currently at.
*
* @return Hit location for the `EPlaceable` that `TracingIterator` is
* currently at. Origin vector (with all coordinates set to `0.0`) if
* iteration has already finished.
*/
public function Vector GetHitLocation()
{
if (!initialized) {
return Vect(0.0f, 0.0f, 0.0f);
}
TryTracing();
if (HasFinished()) {
return Vect(0.0f, 0.0f, 0.0f);
}
return hitLocations[currentIndex];
}
/**
* Returns hit normal for the `EPlaceable` that `TracingIterator` is
* currently at.
*
* @return Hit normal for the `EPlaceable` that `TracingIterator` is
* currently at. Origin vector (with all coordinates set to `0.0`) if
* iteration has already finished.
*/
public function Vector GetHitNormal()
{
if (!initialized) {
return Vect(0.0f, 0.0f, 0.0f);
}
TryTracing();
if (HasFinished()) {
return Vect(0.0f, 0.0f, 0.0f);
}
return hitNormals[currentIndex];
}
/**
* Returns `EPlaceable` caller `TracingIterator` 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 `TracingIterator` is currently at.
*/
public function EPlaceable GetPlaceable()
{
// We only create `EPlaceable` child classes in this class
return EPlaceable(Get());
}
/**
* Returns `EPlaceable` caller `TracingIterator` 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 `TracingIterator` to allow for method chaining.
*/
public function TracingIterator LeaveOnlyPawns();
defaultproperties
{
}

2
sources/Gameplay/KF1Frontend/BaseImplementation/EKFPawn.uc

@ -30,7 +30,7 @@ protected function Finalizer()
}
/**
* Creates new `EKFPawn` that refers to the `pawnInstance` weapon.
* Creates new `EKFPawn` that refers to the `pawnInstance` pawn.
*
* @param pawnInstance Native pawn class that new `EKFPawn` will represent.
* @return New `EKFPawn` that represents given `pawnInstance`.

125
sources/Gameplay/KF1Frontend/BaseImplementation/EKFUnknownPlaceable.uc

@ -0,0 +1,125 @@
/**
* Dummy implementation for `EPlaceable` interface that can wrap around
* `Actor` instances that Acedia does not know about - including the ones
* added by any other mods.
* 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 <https://www.gnu.org/licenses/>.
*/
class EKFUnknownPlaceable extends EPlaceable;
var private NativeActorRef actorReference;
protected function Finalizer()
{
_.memory.Free(actorReference);
actorReference = none;
}
/**
* Creates new `EKFUnknownPlaceable` that refers to the `actorInstance` actor.
*
* @param actorInstance Native `Actor` class that new `EKFUnknownPlaceable`
* will represent.
* @return New `EKFUnknownPlaceable` that represents given `actorInstance`.
*/
public final static /*unreal*/ function EKFUnknownPlaceable Wrap(
Actor actorInstance)
{
local EKFUnknownPlaceable newReference;
if (actorInstance == none) {
return none;
}
newReference = EKFUnknownPlaceable(
__().memory.Allocate(class'EKFUnknownPlaceable'));
newReference.actorReference = __().unreal.ActorRef(actorInstance);
return newReference;
}
/**
* Returns `Actor` instance represented by the caller `EKFUnknownPlaceable`.
*
* @return `Actor` instance represented by the caller `EKFUnknownPlaceable`.
*/
public final /*unreal*/ function Actor GetNativeInstance()
{
if (actorReference != none) {
return actorReference.Get();
}
return none;
}
public function EInterface Copy()
{
local Actor actorInstance;
actorInstance = GetNativeInstance();
return Wrap(actorInstance);
}
public function bool Supports(class<EInterface> newInterfaceClass)
{
if (newInterfaceClass == none) return false;
if (newInterfaceClass == class'EPlaceable') return true;
if (newInterfaceClass == class'EKFUnknownPlaceable') return true;
return false;
}
public function EInterface As(class<EInterface> newInterfaceClass)
{
if (!IsExistent()) {
return none;
}
if ( newInterfaceClass == class'EPlaceable'
|| newInterfaceClass == class'EKFUnknownPlaceable')
{
return Copy();
}
return none;
}
public function bool IsExistent()
{
return (GetNativeInstance() != none);
}
public function bool SameAs(EInterface other)
{
local EKFUnknownPlaceable otherUnknown;
otherUnknown = EKFUnknownPlaceable(other);
if (otherUnknown == none) {
return false;
}
return (GetNativeInstance() == otherUnknown.GetNativeInstance());
}
public function Vector GetLocation()
{
local Actor actorInstance;
actorInstance = GetNativeInstance();
if (actorInstance != none) {
return actorInstance.location;
}
return Vect(0.0, 0.0, 0.0);
}
defaultproperties
{
}

195
sources/Gameplay/KF1Frontend/World/KF1_TracingIterator.uc

@ -0,0 +1,195 @@
/**
* `TracingIterator` 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 <https://www.gnu.org/licenses/>.
*/
class KF1_TracingIterator extends TracingIterator;
var private bool initialized;
var private Vector startPosition, endPosition;
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<EPlaceable> tracedActors;
// Store information about hit location and normal in the other arrays,
// alongside `tracedActors`.
var private array<Vector> hitLocations, hitNormals;
// Did we already perform tracing?
var private bool traced;
// Iterator filters
var private bool onlyPawns;
protected function Finalizer()
{
_.memory.FreeMany(tracedActors);
tracedActors.length = 0;
initialized = false;
}
/**
* Initializes `TracingIterator` that traces entities between `start` and
* `end` positions, in order starting from the `start`
*/
public final function Initialize(Vector start, Vector end)
{
if (initialized) {
return;
}
startPosition = start;
endPosition = end;
initialized = true;
}
// Does actual tracing, but only once per iterator's lifecycle.
// Assumes `initialized` is `true`.
private final function TryTracing()
{
local Pawn nextPawn;
local Actor nextActor;
local class<Actor> targetClass;
local ServerLevelCore core;
local Vector nextHitLocation, nextHitNormal;
// Checking `initialized` flag is already done by every method that
// calls `TryTracing()`
if (traced) {
return;
}
currentIndex = 0;
if (onlyPawns) {
targetClass = class'Pawn';
}
else {
targetClass = class'Actor';
}
core = ServerLevelCore(class'ServerLevelCore'.static.GetInstance());
foreach core.TraceActors(class'Actor',
nextActor,
nextHitLocation,
nextHitNormal,
endPosition,
startPosition)
{
hitLocations[hitLocations.length] = nextHitLocation;
hitNormals[hitNormals.length] = nextHitNormal;
nextPawn = Pawn(nextActor);
if (nextPawn != none)
{
tracedActors[tracedActors.length] =
class'EKFPawn'.static.Wrap(nextPawn);
}
else {
tracedActors[tracedActors.length] =
class'EKFUnknownPlaceable'.static.Wrap(nextActor);
}
}
traced = true;
}
public function Iter Next(optional bool skipNone)
{
if (!initialized) {
return self;
}
TryTracing();
currentIndex += 1;
return self;
}
public function AcediaObject Get()
{
if (!initialized) {
return none;
}
TryTracing();
if (HasFinished()) {
return none;
}
return tracedActors[currentIndex].NewRef();
}
public function Vector GetHitLocation()
{
if (!initialized) {
return Vect(0.0f, 0.0f, 0.0f);
}
TryTracing();
if (HasFinished()) {
return Vect(0.0f, 0.0f, 0.0f);
}
return hitLocations[currentIndex];
}
public function Vector GetHitNormal()
{
if (!initialized) {
return Vect(0.0f, 0.0f, 0.0f);
}
TryTracing();
if (HasFinished()) {
return Vect(0.0f, 0.0f, 0.0f);
}
return hitNormals[currentIndex];
}
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()
{
return (currentIndex >= tracedActors.length);
}
public function Iter LeaveOnlyNotNone()
{
// We cannot tracer `none` actors, so no need to do anything
return self;
}
public function TracingIterator LeaveOnlyPawns()
{
if (initialized && !traced) {
onlyPawns = true;
}
return self;
}
defaultproperties
{
}

90
sources/Gameplay/KF1Frontend/World/KF1_WorldComponent.uc

@ -0,0 +1,90 @@
/**
* `AWorldComponent`'s 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 <https://www.gnu.org/licenses/>.
*/
class KF1_WorldComponent extends AWorldComponent
abstract;
var private const float tracingDistance;
public function TracingIterator Trace(Vector start, Rotator direction)
{
local Vector end;
end = start + tracingDistance * Vector(direction);
return TraceBetween(start, end);
}
public function TracingIterator TraceBetween(Vector start, Vector end)
{
local KF1_TracingIterator newIterator;
newIterator = KF1_TracingIterator(
_.memory.Allocate(class'KF1_TracingIterator'));
newIterator.Initialize(start, end);
return newIterator;
}
public function TracingIterator TracePlayerSight(EPlayer player)
{
local Vector start;
local Rotator direction;
local Actor dummy;
local EPawn pawn;
local PlayerController controller;
local TracingIterator pawnTracingIterator;
if (player == none) {
return none;
}
pawn = player.GetPawn();
if (pawn != none)
{
pawnTracingIterator = TraceSight(pawn);
_.memory.Free(pawn);
return pawnTracingIterator;
}
controller = player.GetController();
if (controller != none)
{
controller.PlayerCalcView(dummy, start, direction);
return Trace(start, direction);
}
return none;
}
public function TracingIterator TraceSight(EPawn pawn)
{
local EKFPawn kfPawn;
local Pawn nativePawn;
local Vector start, end;
kfPawn = EKFPawn(pawn);
if (kfPawn == none) return none;
nativePawn = kfPawn.GetNativeInstance();
if (nativePawn == none) return none;
start = nativePawn.location + nativePawn.EyePosition();
end = start + tracingDistance * Vector(nativePawn.rotation);
return TraceBetween(start, end);
}
defaultproperties
{
tracingDistance = 10000
}
Loading…
Cancel
Save