Browse Source

Add client-side `UnrealAPI`

pull/8/head
Anton Tarasenko 2 years ago
parent
commit
c92e3d0435
  1. 137
      sources/ClientRealm/API/Unreal/ClientUnrealAPI.uc
  2. 35
      sources/ClientRealm/API/Unreal/ClientUnrealAPIBase.uc
  3. 30
      sources/ClientRealm/ClientAcediaAdapter.uc
  4. 32
      sources/ClientRealm/ClientGlobal.uc
  5. 10
      sources/ClientRealm/ClientLevelCore.uc
  6. 0
      sources/CoreRealm/API/UnrealAPI/ActorService.uc
  7. 133
      sources/CoreRealm/API/UnrealAPI/UnrealAPIBase.uc
  8. 31
      sources/CoreRealm/LevelCore.uc
  9. 36
      sources/ServerRealm/API/Unreal/BroadcastsAPI/BroadcastAPI.uc
  10. 2
      sources/ServerRealm/API/Unreal/BroadcastsAPI/BroadcastEventsObserver.uc
  11. 2
      sources/ServerRealm/API/Unreal/GameRulesAPI/AcediaGameRules.uc
  12. 54
      sources/ServerRealm/API/Unreal/GameRulesAPI/GameRulesAPI.uc
  13. 18
      sources/ServerRealm/API/Unreal/MutatorsAPI/MutatorAPI.uc
  14. 21
      sources/ServerRealm/API/Unreal/ServerUnrealAPI.uc
  15. 120
      sources/ServerRealm/API/Unreal/ServerUnrealAPIBase.uc
  16. 2
      sources/ServerRealm/API/Unreal/ServerUnrealService.uc

137
sources/ClientRealm/API/Unreal/ClientUnrealAPI.uc

@ -0,0 +1,137 @@
/**
* Acedia's default implementation for `ClientUnrealAPIBase`.
* Copyright 2021-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 ClientUnrealAPI extends ClientUnrealAPIBase;
var private LoggerAPI.Definition fatalNoStalker;
protected function Constructor()
{
_.environment.OnShutDownSystem(self).connect = HandleShutdown;
}
protected function HandleShutdown()
{
local ServerUnrealService service;
service = ServerUnrealService(
class'ServerUnrealService'.static.GetInstance());
// This has to clean up anything we've added
if (service != none) {
service.Destroy();
}
}
/* SIGNAL */
public function Unreal_OnTick_Slot OnTick(
AcediaObject receiver)
{
local Signal signal;
local ServerUnrealService service;
service = ServerUnrealService(class'ServerUnrealService'.static.Require());
signal = service.GetSignal(class'Unreal_OnTick_Signal');
return Unreal_OnTick_Slot(signal.NewSlot(receiver));
}
/* SIGNAL */
public function SimpleSlot OnDestructionFor(
AcediaObject receiver,
Actor targetToStalk)
{
local ActorStalker stalker;
if (receiver == none) return none;
if (targetToStalk == none) return none;
// Failing to spawn this actor without any collision flags is considered
// completely unexpected and grounds for fatal failure on Acedia' part
stalker = ActorStalker(class'ClientLevelCore'.static
.GetInstance()
.Allocate(class'ActorStalker'));
if (stalker == none)
{
_.logger.Auto(fatalNoStalker);
return none;
}
// This will not fail, since we have already ensured that
// `targetToStalk == none`
stalker.Initialize(targetToStalk);
return stalker.OnActorDestruction(receiver);
}
public function LevelInfo GetLevel()
{
return class'ClientLevelCore'.static.GetInstance().level;
}
public function GameReplicationInfo GetGameRI()
{
return class'ClientLevelCore'.static.GetInstance().level.GRI;
}
public function KFGameReplicationInfo GetKFGameRI()
{
return KFGameReplicationInfo(GetGameRI());
}
public function GameInfo GetGameType()
{
return class'ClientLevelCore'.static.GetInstance().level.game;
}
public function KFGameType GetKFGameType()
{
return KFGameType(GetGameType());
}
public function Actor FindActorInstance(class<Actor> classToFind)
{
local Actor result;
local LevelCore core;
core = class'ClientLevelCore'.static.GetInstance();
foreach core.AllActors(classToFind, result)
{
if (result != none) {
break;
}
}
return result;
}
public function PlayerController GetLocalPlayer()
{
return class'ClientLevelCore'.static.GetInstance().level
.GetLocalPlayerController();
}
public function NativeActorRef ActorRef(optional Actor value)
{
local NativeActorRef ref;
ref = NativeActorRef(_.memory.Allocate(class'NativeActorRef'));
ref.Set(value);
return ref;
}
defaultproperties
{
fatalNoStalker = (l=LOG_Fatal,m="Cannot spawn `PawnStalker`")
}

35
sources/ClientRealm/API/Unreal/ClientUnrealAPIBase.uc

@ -0,0 +1,35 @@
/**
* Low-level API that provides set of utility methods for working with
* unreal script classes on the clients.
* 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 ClientUnrealAPIBase extends UnrealAPIBase
abstract;
/**
* Returns current local player's `Controller`. Useful because `level`
* is not accessible inside objects.
*
* @return `PlayerController` instance for the local player. `none` iff run on
* dedicated servers.
*/
public function PlayerController GetLocalPlayer();
defaultproperties
{
}

30
sources/ClientRealm/ClientAcediaAdapter.uc

@ -0,0 +1,30 @@
/**
* Base class for objects that will provide an access to a Acedia's client- and
* server-specific functionality by giving a reference to this object to all
* Acedia's objects and actors, emulating a global API namespace.
* 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 ClientAcediaAdapter extends AcediaAdapter
abstract;
var public const class<ClientUnrealAPIBase> clientUnrealAPIClass;
defaultproperties
{
clientUnrealAPIClass = class'ClientUnrealAPI'
}

32
sources/ClientRealm/ClientGlobal.uc

@ -25,6 +25,10 @@ class ClientGlobal extends CoreGlobal;
// main instance in this variable's default value. // main instance in this variable's default value.
var protected ClientGlobal myself; var protected ClientGlobal myself;
var public ClientUnrealAPIBase unreal;
var private LoggerAPI.Definition fatBadAdapterClass;
public final static function ClientGlobal GetInstance() public final static function ClientGlobal GetInstance()
{ {
if (default.myself == none) if (default.myself == none)
@ -38,13 +42,41 @@ public final static function ClientGlobal GetInstance()
protected function Initialize() protected function Initialize()
{ {
local Global _;
local class<ClientAcediaAdapter> clientAdapterClass;
if (initialized) { if (initialized) {
return; return;
} }
super.Initialize(); super.Initialize();
initialized = true; initialized = true;
clientAdapterClass = class<ClientAcediaAdapter>(adapterClass);
if (adapterClass != none && clientAdapterClass == none)
{
class'Global'.static.GetInstance().logger
.Auto(fatBadAdapterClass)
.ArgClass(self.class);
return;
}
if (clientAdapterClass == none) {
return;
}
_ = class'Global'.static.GetInstance();
unreal = ClientUnrealAPIBase(
_.memory.Allocate(clientAdapterClass.default.clientUnrealAPIClass));
}
public final function bool ConnectClientLevelCore()
{
if (class'ClientLevelCore'.static.GetInstance() == none) {
return false;
}
Initialize();
return true;
} }
defaultproperties defaultproperties
{ {
adapterClass = class'ClientAcediaAdapter'
fatBadAdapterClass = (l=LOG_Fatal,m="non-`ClientAcediaAdapter` class was specified as an adapter for `%1` level core class. This should not have happened. AcediaCore cannot properly function.")
} }

10
sources/ClientLevelCore.uc → sources/ClientRealm/ClientLevelCore.uc

@ -18,12 +18,18 @@
*/ */
class ClientLevelCore extends LevelCore; class ClientLevelCore extends LevelCore;
public static function LevelCore CreateLevelCore(Actor source) public simulated static function LevelCore CreateLevelCore(Actor source)
{ {
local LevelCore newCore;
if (source == none) return none; if (source == none) return none;
if (source.level.netMode == NM_DedicatedServer) return none; if (source.level.netMode == NM_DedicatedServer) return none;
return super.CreateLevelCore(source); newCore = super.CreateLevelCore(source);
if (newCore != none) {
__client().ConnectClientLevelCore();
}
return newCore;
} }
defaultproperties defaultproperties

0
sources/Types/ActorService.uc → sources/CoreRealm/API/UnrealAPI/ActorService.uc

133
sources/CoreRealm/API/UnrealAPI/UnrealAPIBase.uc

@ -0,0 +1,133 @@
/**
* Low-level API that provides set of utility methods for working with
* unreal script classes.
* Copyright 2021-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 UnrealAPIBase extends AcediaObject
abstract;
/**
* Signal that will be emitted every tick.
*
* [Signature]
* void <slot>(float delta, float dilationCoefficient)
*
* @param delta In-game time in seconds that has passed since
* the last tick. To obtain real time passed from the last tick divide
* `delta` by `dilationCoefficient`.
* @param dilationCoefficient How fast is in-game time flow compared to
* the real world's one? `2` means twice as fast and
* `0.5` means twice as slow.
*/
/* SIGNAL */
public function Unreal_OnTick_Slot OnTick(AcediaObject receiver);
/**
* Signal that will be emitted when a passed `targetToStalk` is destroyed.
*
* Passed parameter `targetToStalk` cannot be `none`, otherwise `none` will be
* returned instead of a valid slot.
*
* @param receiver Specify a receiver like for any other signal.
* @param targetToStalk Actor whose destruction we want to detect.
*
* [Signature]
* void <slot>()
*/
/* SIGNAL */
public function SimpleSlot OnDestructionFor(
AcediaObject receiver,
Actor targetToStalk);
/**
* Returns current game's `LevelInfo`. Useful because `level` variable
* is not defined inside objects.
*
* @return `LevelInfo` instance for the current game. Guaranteed to
* not be `none`.
*/
public function LevelInfo GetLevel();
/**
* Returns current game's `GameReplicationInfo`. Useful because `level.game`
* is not accessible inside objects.
*
* @return `GameReplicationInfo` instance for the current game. Guaranteed to
* not be `none`.
*/
public function GameReplicationInfo GetGameRI();
/**
* Returns current game's `GameReplicationInfo` as `KFGameReplicationInfo`.
* Useful because `level.game` is not accessible inside objects and because it
* auto converts game replication info type to `KFGameReplicationInfo`, which
* virtually all mods for killing floor use (by itself or as a base class).
*
* @return `KFGameReplicationInfo` instance for the current game.
* Can be `none` only if game was modded to run a `KFGameReplicationInfo`
* not derived from `KFGameType`.
*/
public function KFGameReplicationInfo GetKFGameRI();
/**
* Returns current game's `GameInfo`. Useful because `level.game` is not
* accessible inside objects.
*
* @return `GameInfo` instance for the current game. Guaranteed to
* not be `none`.
*/
public function GameInfo GetGameType();
/**
* Returns current game's `GameInfo` as `KFGameType`. Useful because
* `level.game` is not accessible inside objects and because it auto converts
* game type to `KFGameType`, which virtually all mods for killing floor use
* (by itself or as a base class).
*
* @return `KFGameType` instance for the current game. Can be `none` only if
* game was modded to run a `GameInfo` not derived from `KFGameType`.
*/
public function KFGameType GetKFGameType();
/**
* Searches all `Actor`s on the level for an instance of specific class and
* returns it.
*
* @param classToFind Class we want to find an instance of.
* @result A pre-existing instance of class `classToFind`, `none` if
* no instances exist at the moment of this method's call.
*/
public function Actor FindActorInstance(class<Actor> classToFind);
/**
* Creates reference object to store a `Actor` value.
*
* Such references are necessary, since `Actor` references aren't safe to store
* inside non-actor `Object`s. To allow that Acedia uses a round about way of
* storing all `Actor` references in a special `Actor`, while allowing to refer
* to them via `NativeActorRef` (also `ActorRef` for `AcediaActor`s
* specifically).
*
* @param value Initial value to store in reference.
* @return `NativeActorRef`, containing `value`.
*/
public function NativeActorRef ActorRef(optional Actor value);
defaultproperties
{
}

31
sources/CoreRealm/LevelCore.uc

@ -78,7 +78,7 @@ public final function SimpleSlot OnShutdown(AcediaObject receiver)
return SimpleSlot(onShutdownSignal.NewSlot(receiver)); return SimpleSlot(onShutdownSignal.NewSlot(receiver));
} }
public static function LevelCore CreateLevelCore(Actor source) public simulated static function LevelCore CreateLevelCore(Actor source)
{ {
if (GetInstance() != none) return none; if (GetInstance() != none) return none;
if (source == none) return none; if (source == none) return none;
@ -89,6 +89,35 @@ public static function LevelCore CreateLevelCore(Actor source)
return default.activeInstance; return default.activeInstance;
} }
/**
* Creates new `Actor` in the level as the caller `LevelCore`.
*
* For `AcediaActor`s calls their constructors.
*
* @param classToAllocate Class of the `Object` that this method will
* create. Must not be subclass of `Actor`.
* @return Newly created object.
* Will only be `none` if `classToAllocate` is `none` or `classToAllocate`
* is abstract.
*/
public final function Actor Allocate(class<Actor> classToAllocate)
{
local Actor allocatedActor;
local class<AcediaActor> acediaClassToAllocate;
if (classToAllocate == none) {
return none;
}
acediaClassToAllocate = class<AcediaActor>(classToAllocate);
allocatedActor = Spawn(classToAllocate);
// Call constructor here, just in case, to make sure constructor is called
// as soon as possible
if (acediaClassToAllocate != none) {
AcediaActor(allocatedActor)._constructor();
}
return allocatedActor;
}
public final static function LevelCore GetInstance() public final static function LevelCore GetInstance()
{ {
local bool instanceExists; local bool instanceExists;

36
sources/ServerRealm/API/Unreal/BroadcastsAPI/BroadcastAPI.uc

@ -31,10 +31,10 @@ var private LoggerAPI.Definition errBroadcasthandlerUnknown;
public function Broadcast_OnBroadcastCheck_Slot OnBroadcastCheck( public function Broadcast_OnBroadcastCheck_Slot OnBroadcastCheck(
AcediaObject receiver) AcediaObject receiver)
{ {
local Signal signal; local Signal signal;
local UnrealService service; local ServerUnrealService service;
service = UnrealService(class'UnrealService'.static.Require()); service = ServerUnrealService(class'ServerUnrealService'.static.Require());
TryInjectBroadcastHandler(service); TryInjectBroadcastHandler(service);
signal = service.GetSignal(class'Broadcast_OnBroadcastCheck_Signal'); signal = service.GetSignal(class'Broadcast_OnBroadcastCheck_Signal');
return Broadcast_OnBroadcastCheck_Slot(signal.NewSlot(receiver)); return Broadcast_OnBroadcastCheck_Slot(signal.NewSlot(receiver));
@ -44,10 +44,10 @@ public function Broadcast_OnBroadcastCheck_Slot OnBroadcastCheck(
public function Broadcast_OnHandleText_Slot OnHandleText( public function Broadcast_OnHandleText_Slot OnHandleText(
AcediaObject receiver) AcediaObject receiver)
{ {
local Signal signal; local Signal signal;
local UnrealService service; local ServerUnrealService service;
service = UnrealService(class'UnrealService'.static.Require()); service = ServerUnrealService(class'ServerUnrealService'.static.Require());
TryInjectBroadcastHandler(service); TryInjectBroadcastHandler(service);
signal = service.GetSignal(class'Broadcast_OnHandleText_Signal'); signal = service.GetSignal(class'Broadcast_OnHandleText_Signal');
return Broadcast_OnHandleText_Slot(signal.NewSlot(receiver)); return Broadcast_OnHandleText_Slot(signal.NewSlot(receiver));
@ -57,10 +57,10 @@ public function Broadcast_OnHandleText_Slot OnHandleText(
public function Broadcast_OnHandleTextFor_Slot OnHandleTextFor( public function Broadcast_OnHandleTextFor_Slot OnHandleTextFor(
AcediaObject receiver) AcediaObject receiver)
{ {
local Signal signal; local Signal signal;
local UnrealService service; local ServerUnrealService service;
service = UnrealService(class'UnrealService'.static.Require()); service = ServerUnrealService(class'ServerUnrealService'.static.Require());
TryInjectBroadcastHandler(service); TryInjectBroadcastHandler(service);
signal = service.GetSignal(class'Broadcast_OnHandleTextFor_Signal'); signal = service.GetSignal(class'Broadcast_OnHandleTextFor_Signal');
return Broadcast_OnHandleTextFor_Slot(signal.NewSlot(receiver)); return Broadcast_OnHandleTextFor_Slot(signal.NewSlot(receiver));
@ -70,10 +70,10 @@ public function Broadcast_OnHandleTextFor_Slot OnHandleTextFor(
public function Broadcast_OnHandleLocalized_Slot OnHandleLocalized( public function Broadcast_OnHandleLocalized_Slot OnHandleLocalized(
AcediaObject receiver) AcediaObject receiver)
{ {
local Signal signal; local Signal signal;
local UnrealService service; local ServerUnrealService service;
service = UnrealService(class'UnrealService'.static.Require()); service = ServerUnrealService(class'ServerUnrealService'.static.Require());
TryInjectBroadcastHandler(service); TryInjectBroadcastHandler(service);
signal = service.GetSignal(class'Broadcast_OnHandleLocalized_Signal'); signal = service.GetSignal(class'Broadcast_OnHandleLocalized_Signal');
return Broadcast_OnHandleLocalized_Slot(signal.NewSlot(receiver)); return Broadcast_OnHandleLocalized_Slot(signal.NewSlot(receiver));
@ -83,10 +83,10 @@ public function Broadcast_OnHandleLocalized_Slot OnHandleLocalized(
public function Broadcast_OnHandleLocalizedFor_Slot OnHandleLocalizedFor( public function Broadcast_OnHandleLocalizedFor_Slot OnHandleLocalizedFor(
AcediaObject receiver) AcediaObject receiver)
{ {
local Signal signal; local Signal signal;
local UnrealService service; local ServerUnrealService service;
service = UnrealService(class'UnrealService'.static.Require()); service = ServerUnrealService(class'ServerUnrealService'.static.Require());
TryInjectBroadcastHandler(service); TryInjectBroadcastHandler(service);
signal = service.GetSignal(class'Broadcast_OnHandleLocalizedFor_Signal'); signal = service.GetSignal(class'Broadcast_OnHandleLocalizedFor_Signal');
return Broadcast_OnHandleLocalizedFor_Slot(signal.NewSlot(receiver)); return Broadcast_OnHandleLocalizedFor_Slot(signal.NewSlot(receiver));
@ -96,10 +96,10 @@ public function Broadcast_OnHandleLocalizedFor_Slot OnHandleLocalizedFor(
* Method that attempts to inject Acedia's `BroadcastEventObserver`, while * Method that attempts to inject Acedia's `BroadcastEventObserver`, while
* respecting settings inside `class'SideEffects'`. * respecting settings inside `class'SideEffects'`.
* *
* @param service Reference to `UnrealService` to exchange signal and slots * @param service Reference to `ServerUnrealService` to exchange signal and
* classes with. * slots classes with.
*/ */
protected final function TryInjectBroadcastHandler(UnrealService service) protected final function TryInjectBroadcastHandler(ServerUnrealService service)
{ {
local InjectionLevel usedLevel; local InjectionLevel usedLevel;
local BroadcastSideEffect sideEffect; local BroadcastSideEffect sideEffect;

2
sources/ServerRealm/API/Unreal/BroadcastsAPI/BroadcastEventsObserver.uc

@ -204,7 +204,7 @@ var private Broadcast_OnHandleLocalizedFor_Signal onHandleLocalizedFor;
var private Broadcast_OnHandleText_Signal onHandleText; var private Broadcast_OnHandleText_Signal onHandleText;
var private Broadcast_OnHandleTextFor_Signal onHandleTextFor; var private Broadcast_OnHandleTextFor_Signal onHandleTextFor;
public final function Initialize(UnrealService service) public final function Initialize(ServerUnrealService service)
{ {
usedInjectionLevel = usedInjectionLevel =
class'SideEffects'.default.broadcastHandlerInjectionLevel; class'SideEffects'.default.broadcastHandlerInjectionLevel;

2
sources/ServerRealm/API/Unreal/GameRulesAPI/AcediaGameRules.uc

@ -29,7 +29,7 @@ var private GameRules_OnNetDamage_Signal onNetDamage;
var private GameRules_OnPreventDeath_Signal onPreventDeath; var private GameRules_OnPreventDeath_Signal onPreventDeath;
var private GameRules_OnScoreKill_Signal onScoreKill; var private GameRules_OnScoreKill_Signal onScoreKill;
public final function Initialize(UnrealService service) public final function Initialize(ServerUnrealService service)
{ {
if (service == none) { if (service == none) {
return; return;

54
sources/ServerRealm/API/Unreal/GameRulesAPI/GameRulesAPI.uc

@ -31,10 +31,10 @@ var private LoggerAPI.Definition errGameRulesUnknown;
public function GameRules_OnFindPlayerStart_Slot OnFindPlayerStart( public function GameRules_OnFindPlayerStart_Slot OnFindPlayerStart(
AcediaObject receiver) AcediaObject receiver)
{ {
local Signal signal; local Signal signal;
local UnrealService service; local ServerUnrealService service;
service = UnrealService(class'UnrealService'.static.Require()); service = ServerUnrealService(class'ServerUnrealService'.static.Require());
TryAddingGameRules(service); TryAddingGameRules(service);
signal = service.GetSignal(class'GameRules_OnFindPlayerStart_Signal'); signal = service.GetSignal(class'GameRules_OnFindPlayerStart_Signal');
return GameRules_OnFindPlayerStart_Slot(signal.NewSlot(receiver)); return GameRules_OnFindPlayerStart_Slot(signal.NewSlot(receiver));
@ -44,10 +44,10 @@ public function GameRules_OnFindPlayerStart_Slot OnFindPlayerStart(
public function GameRules_OnHandleRestartGame_Slot OnHandleRestartGame( public function GameRules_OnHandleRestartGame_Slot OnHandleRestartGame(
AcediaObject receiver) AcediaObject receiver)
{ {
local Signal signal; local Signal signal;
local UnrealService service; local ServerUnrealService service;
service = UnrealService(class'UnrealService'.static.Require()); service = ServerUnrealService(class'ServerUnrealService'.static.Require());
TryAddingGameRules(service); TryAddingGameRules(service);
signal = service.GetSignal(class'GameRules_OnHandleRestartGame_Signal'); signal = service.GetSignal(class'GameRules_OnHandleRestartGame_Signal');
return GameRules_OnHandleRestartGame_Slot(signal.NewSlot(receiver)); return GameRules_OnHandleRestartGame_Slot(signal.NewSlot(receiver));
@ -57,10 +57,10 @@ public function GameRules_OnHandleRestartGame_Slot OnHandleRestartGame(
public function GameRules_OnCheckEndGame_Slot OnCheckEndGame( public function GameRules_OnCheckEndGame_Slot OnCheckEndGame(
AcediaObject receiver) AcediaObject receiver)
{ {
local Signal signal; local Signal signal;
local UnrealService service; local ServerUnrealService service;
service = UnrealService(class'UnrealService'.static.Require()); service = ServerUnrealService(class'ServerUnrealService'.static.Require());
TryAddingGameRules(service); TryAddingGameRules(service);
signal = service.GetSignal(class'GameRules_OnCheckEndGame_Signal'); signal = service.GetSignal(class'GameRules_OnCheckEndGame_Signal');
return GameRules_OnCheckEndGame_Slot(signal.NewSlot(receiver)); return GameRules_OnCheckEndGame_Slot(signal.NewSlot(receiver));
@ -70,10 +70,10 @@ public function GameRules_OnCheckEndGame_Slot OnCheckEndGame(
public function GameRules_OnCheckScore_Slot OnCheckScore( public function GameRules_OnCheckScore_Slot OnCheckScore(
AcediaObject receiver) AcediaObject receiver)
{ {
local Signal signal; local Signal signal;
local UnrealService service; local ServerUnrealService service;
service = UnrealService(class'UnrealService'.static.Require()); service = ServerUnrealService(class'ServerUnrealService'.static.Require());
TryAddingGameRules(service); TryAddingGameRules(service);
signal = service.GetSignal(class'GameRules_OnCheckScore_Signal'); signal = service.GetSignal(class'GameRules_OnCheckScore_Signal');
return GameRules_OnCheckScore_Slot(signal.NewSlot(receiver)); return GameRules_OnCheckScore_Slot(signal.NewSlot(receiver));
@ -83,10 +83,10 @@ public function GameRules_OnCheckScore_Slot OnCheckScore(
public function GameRules_OnOverridePickupQuery_Slot public function GameRules_OnOverridePickupQuery_Slot
OnOverridePickupQuery(AcediaObject receiver) OnOverridePickupQuery(AcediaObject receiver)
{ {
local Signal signal; local Signal signal;
local UnrealService service; local ServerUnrealService service;
service = UnrealService(class'UnrealService'.static.Require()); service = ServerUnrealService(class'ServerUnrealService'.static.Require());
TryAddingGameRules(service); TryAddingGameRules(service);
signal = service.GetSignal(class'GameRules_OnOverridePickupQuery_Signal'); signal = service.GetSignal(class'GameRules_OnOverridePickupQuery_Signal');
return GameRules_OnOverridePickupQuery_Slot(signal.NewSlot(receiver)); return GameRules_OnOverridePickupQuery_Slot(signal.NewSlot(receiver));
@ -95,10 +95,10 @@ public function GameRules_OnOverridePickupQuery_Slot
/* SIGNAL */ /* SIGNAL */
public function GameRules_OnNetDamage_Slot OnNetDamage(AcediaObject receiver) public function GameRules_OnNetDamage_Slot OnNetDamage(AcediaObject receiver)
{ {
local Signal signal; local Signal signal;
local UnrealService service; local ServerUnrealService service;
service = UnrealService(class'UnrealService'.static.Require()); service = ServerUnrealService(class'ServerUnrealService'.static.Require());
TryAddingGameRules(service); TryAddingGameRules(service);
signal = service.GetSignal(class'GameRules_OnNetDamage_Signal'); signal = service.GetSignal(class'GameRules_OnNetDamage_Signal');
return GameRules_OnNetDamage_Slot(signal.NewSlot(receiver)); return GameRules_OnNetDamage_Slot(signal.NewSlot(receiver));
@ -108,10 +108,10 @@ public function GameRules_OnNetDamage_Slot OnNetDamage(AcediaObject receiver)
public function GameRules_OnPreventDeath_Slot OnPreventDeath( public function GameRules_OnPreventDeath_Slot OnPreventDeath(
AcediaObject receiver) AcediaObject receiver)
{ {
local Signal signal; local Signal signal;
local UnrealService service; local ServerUnrealService service;
service = UnrealService(class'UnrealService'.static.Require()); service = ServerUnrealService(class'ServerUnrealService'.static.Require());
TryAddingGameRules(service); TryAddingGameRules(service);
signal = service.GetSignal(class'GameRules_OnPreventDeath_Signal'); signal = service.GetSignal(class'GameRules_OnPreventDeath_Signal');
return GameRules_OnPreventDeath_Slot(signal.NewSlot(receiver)); return GameRules_OnPreventDeath_Slot(signal.NewSlot(receiver));
@ -121,10 +121,10 @@ public function GameRules_OnPreventDeath_Slot OnPreventDeath(
public function GameRules_OnScoreKill_Slot OnScoreKill( public function GameRules_OnScoreKill_Slot OnScoreKill(
AcediaObject receiver) AcediaObject receiver)
{ {
local Signal signal; local Signal signal;
local UnrealService service; local ServerUnrealService service;
service = UnrealService(class'UnrealService'.static.Require()); service = ServerUnrealService(class'ServerUnrealService'.static.Require());
TryAddingGameRules(service); TryAddingGameRules(service);
signal = service.GetSignal(class'GameRules_OnScoreKill_Signal'); signal = service.GetSignal(class'GameRules_OnScoreKill_Signal');
return GameRules_OnScoreKill_Slot(signal.NewSlot(receiver)); return GameRules_OnScoreKill_Slot(signal.NewSlot(receiver));
@ -134,10 +134,10 @@ public function GameRules_OnScoreKill_Slot OnScoreKill(
* Method that attempts to inject Acedia's `AcediaGameRules`, while * Method that attempts to inject Acedia's `AcediaGameRules`, while
* respecting settings inside `class'SideEffects'`. * respecting settings inside `class'SideEffects'`.
* *
* @param service Reference to `UnrealService` to exchange signal and slots * @param service Reference to `ServerUnrealService` to exchange signal and
* classes with. * slots classes with.
*/ */
protected function TryAddingGameRules(UnrealService service) protected function TryAddingGameRules(ServerUnrealService service)
{ {
local AcediaGameRules gameRules; local AcediaGameRules gameRules;
local GameRulesSideEffect sideEffect; local GameRulesSideEffect sideEffect;

18
sources/ServerRealm/API/Unreal/MutatorsAPI/MutatorAPI.uc

@ -23,10 +23,10 @@ class MutatorAPI extends MutatorAPIBase;
public function Mutator_OnCheckReplacement_Slot OnCheckReplacement( public function Mutator_OnCheckReplacement_Slot OnCheckReplacement(
AcediaObject receiver) AcediaObject receiver)
{ {
local Signal signal; local Signal signal;
local UnrealService service; local ServerUnrealService service;
service = UnrealService(class'UnrealService'.static.Require()); service = ServerUnrealService(class'ServerUnrealService'.static.Require());
signal = service.GetSignal(class'Mutator_OnCheckReplacement_Signal'); signal = service.GetSignal(class'Mutator_OnCheckReplacement_Signal');
return Mutator_OnCheckReplacement_Slot(signal.NewSlot(receiver)); return Mutator_OnCheckReplacement_Slot(signal.NewSlot(receiver));
} }
@ -35,10 +35,10 @@ public function Mutator_OnCheckReplacement_Slot OnCheckReplacement(
public function Mutator_OnMutate_Slot OnMutate( public function Mutator_OnMutate_Slot OnMutate(
AcediaObject receiver) AcediaObject receiver)
{ {
local Signal signal; local Signal signal;
local UnrealService service; local ServerUnrealService service;
service = UnrealService(class'UnrealService'.static.Require()); service = ServerUnrealService(class'ServerUnrealService'.static.Require());
signal = service.GetSignal(class'Mutator_OnMutate_Signal'); signal = service.GetSignal(class'Mutator_OnMutate_Signal');
return Mutator_OnMutate_Slot(signal.NewSlot(receiver)); return Mutator_OnMutate_Slot(signal.NewSlot(receiver));
} }
@ -47,10 +47,10 @@ public function Mutator_OnMutate_Slot OnMutate(
public function Mutator_OnModifyLogin_Slot OnModifyLogin( public function Mutator_OnModifyLogin_Slot OnModifyLogin(
AcediaObject receiver) AcediaObject receiver)
{ {
local Signal signal; local Signal signal;
local UnrealService service; local ServerUnrealService service;
service = UnrealService(class'UnrealService'.static.Require()); service = ServerUnrealService(class'ServerUnrealService'.static.Require());
signal = service.GetSignal(class'Mutator_OnModifyLogin_Signal'); signal = service.GetSignal(class'Mutator_OnModifyLogin_Signal');
return Mutator_OnModifyLogin_Slot(signal.NewSlot(receiver)); return Mutator_OnModifyLogin_Slot(signal.NewSlot(receiver));
} }

21
sources/ServerRealm/API/Unreal/ServerUnrealAPI.uc

@ -28,9 +28,10 @@ protected function Constructor()
protected function HandleShutdown() protected function HandleShutdown()
{ {
local UnrealService service; local ServerUnrealService service;
service = UnrealService(class'UnrealService'.static.GetInstance()); service =
ServerUnrealService(class'ServerUnrealService'.static.GetInstance());
// This has to clean up anything we've added // This has to clean up anything we've added
if (service != none) { if (service != none) {
service.Destroy(); service.Destroy();
@ -41,10 +42,10 @@ protected function HandleShutdown()
public function Unreal_OnTick_Slot OnTick( public function Unreal_OnTick_Slot OnTick(
AcediaObject receiver) AcediaObject receiver)
{ {
local Signal signal; local Signal signal;
local UnrealService service; local ServerUnrealService service;
service = UnrealService(class'UnrealService'.static.Require()); service = ServerUnrealService(class'ServerUnrealService'.static.Require());
signal = service.GetSignal(class'Unreal_OnTick_Signal'); signal = service.GetSignal(class'Unreal_OnTick_Signal');
return Unreal_OnTick_Slot(signal.NewSlot(receiver)); return Unreal_OnTick_Slot(signal.NewSlot(receiver));
} }
@ -61,7 +62,9 @@ public function SimpleSlot OnDestructionFor(
// Failing to spawn this actor without any collision flags is considered // Failing to spawn this actor without any collision flags is considered
// completely unexpected and grounds for fatal failure on Acedia' part // completely unexpected and grounds for fatal failure on Acedia' part
stalker = ActorStalker(_.memory.Allocate(class'ActorStalker')); stalker = ActorStalker(class'ServerLevelCore'.static
.GetInstance()
.Allocate(class'ActorStalker'));
if (stalker == none) if (stalker == none)
{ {
_.logger.Auto(fatalNoStalker); _.logger.Auto(fatalNoStalker);
@ -113,12 +116,6 @@ public function Actor FindActorInstance(class<Actor> classToFind)
return result; return result;
} }
public function PlayerController GetLocalPlayer()
{
return class'ServerLevelCore'.static.GetInstance().level
.GetLocalPlayerController();
}
public function NativeActorRef ActorRef(optional Actor value) public function NativeActorRef ActorRef(optional Actor value)
{ {
local NativeActorRef ref; local NativeActorRef ref;

120
sources/ServerRealm/API/Unreal/ServerUnrealAPIBase.uc

@ -1,7 +1,7 @@
/** /**
* Low-level API that provides set of utility methods for working with * Low-level API that provides set of utility methods for working with
* unreal script classes. * unreal script classes.
* Copyright 2021-2022 Anton Tarasenko * Copyright 2022 Anton Tarasenko
*------------------------------------------------------------------------------ *------------------------------------------------------------------------------
* This file is part of Acedia. * This file is part of Acedia.
* *
@ -18,7 +18,7 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with Acedia. If not, see <https://www.gnu.org/licenses/>. * along with Acedia. If not, see <https://www.gnu.org/licenses/>.
*/ */
class ServerUnrealAPIBase extends AcediaObject class ServerUnrealAPIBase extends UnrealAPIBase
abstract; abstract;
var protected bool initialized; var protected bool initialized;
@ -47,122 +47,6 @@ public function Initialize(class<ServerAcediaAdapter> adapterClass)
adapterClass.default.serverInventoryAPIClass)); adapterClass.default.serverInventoryAPIClass));
} }
/**
* Signal that will be emitted every tick.
*
* [Signature]
* void <slot>(float delta, float dilationCoefficient)
*
* @param delta In-game time in seconds that has passed since
* the last tick. To obtain real time passed from the last tick divide
* `delta` by `dilationCoefficient`.
* @param dilationCoefficient How fast is in-game time flow compared to
* the real world's one? `2` means twice as fast and
* `0.5` means twice as slow.
*/
/* SIGNAL */
public function Unreal_OnTick_Slot OnTick(AcediaObject receiver);
/**
* Signal that will be emitted when a passed `targetToStalk` is destroyed.
*
* Passed parameter `targetToStalk` cannot be `none`, otherwise `none` will be
* returned instead of a valid slot.
*
* @param receiver Specify a receiver like for any other signal.
* @param targetToStalk Actor whose destruction we want to detect.
*
* [Signature]
* void <slot>()
*/
/* SIGNAL */
public function SimpleSlot OnDestructionFor(
AcediaObject receiver,
Actor targetToStalk);
/**
* Returns current game's `LevelInfo`. Useful because `level` variable
* is not defined inside objects.
*
* @return `LevelInfo` instance for the current game. Guaranteed to
* not be `none`.
*/
public function LevelInfo GetLevel();
/**
* Returns current game's `GameReplicationInfo`. Useful because `level.game`
* is not accessible inside objects.
*
* @return `GameReplicationInfo` instance for the current game. Guaranteed to
* not be `none`.
*/
public function GameReplicationInfo GetGameRI();
/**
* Returns current game's `GameReplicationInfo` as `KFGameReplicationInfo`.
* Useful because `level.game` is not accessible inside objects and because it
* auto converts game replication info type to `KFGameReplicationInfo`, which
* virtually all mods for killing floor use (by itself or as a base class).
*
* @return `KFGameReplicationInfo` instance for the current game.
* Can be `none` only if game was modded to run a `KFGameReplicationInfo`
* not derived from `KFGameType`.
*/
public function KFGameReplicationInfo GetKFGameRI();
/**
* Returns current game's `GameInfo`. Useful because `level.game` is not
* accessible inside objects.
*
* @return `GameInfo` instance for the current game. Guaranteed to
* not be `none`.
*/
public function GameInfo GetGameType();
/**
* Returns current game's `GameInfo` as `KFGameType`. Useful because
* `level.game` is not accessible inside objects and because it auto converts
* game type to `KFGameType`, which virtually all mods for killing floor use
* (by itself or as a base class).
*
* @return `KFGameType` instance for the current game. Can be `none` only if
* game was modded to run a `GameInfo` not derived from `KFGameType`.
*/
public function KFGameType GetKFGameType();
/**
* Searches all `Actor`s on the level for an instance of specific class and
* returns it.
*
* @param classToFind Class we want to find an instance of.
* @result A pre-existing instance of class `classToFind`, `none` if
* no instances exist at the moment of this method's call.
*/
public function Actor FindActorInstance(class<Actor> classToFind);
/**
* Returns current local player's `Controller`. Useful because `level`
* is not accessible inside objects.
*
* @return `PlayerController` instance for the local player. `none` iff run on
* dedicated servers.
*/
public function PlayerController GetLocalPlayer();
/**
* Creates reference object to store a `Actor` value.
*
* Such references are necessary, since `Actor` references aren't safe to store
* inside non-actor `Object`s. To allow that Acedia uses a round about way of
* storing all `Actor` references in a special `Actor`, while allowing to refer
* to them via `NativeActorRef` (also `ActorRef` for `AcediaActor`s
* specifically).
*
* @param value Initial value to store in reference.
* @return `NativeActorRef`, containing `value`.
*/
public function NativeActorRef ActorRef(optional Actor value);
defaultproperties defaultproperties
{ {
} }

2
sources/ServerRealm/API/Unreal/UnrealService.uc → sources/ServerRealm/API/Unreal/ServerUnrealService.uc

@ -18,7 +18,7 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with Acedia. If not, see <https://www.gnu.org/licenses/>. * along with Acedia. If not, see <https://www.gnu.org/licenses/>.
*/ */
class UnrealService extends Service; class ServerUnrealService extends Service;
struct SignalRecord struct SignalRecord
{ {
Loading…
Cancel
Save