Anton Tarasenko
2 years ago
6 changed files with 569 additions and 1 deletions
@ -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 |
||||||
|
{ |
||||||
|
} |
@ -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 |
||||||
|
{ |
||||||
|
} |
@ -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 |
||||||
|
{ |
||||||
|
} |
@ -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…
Reference in new issue