diff --git a/sources/ClientRealm/API/Unreal/ClientUnrealAPIBase.uc b/sources/ClientRealm/API/Unreal/ClientUnrealAPIBase.uc index 1470307..5c0893d 100644 --- a/sources/ClientRealm/API/Unreal/ClientUnrealAPIBase.uc +++ b/sources/ClientRealm/API/Unreal/ClientUnrealAPIBase.uc @@ -21,6 +21,23 @@ class ClientUnrealAPIBase extends UnrealAPIBase abstract; +var protected bool initialized; + +var public InteractionAPIBase interaction; + +public function Initialize(class adapterClass) +{ + if (initialized) { + return; + } + initialized = true; + if (adapterClass == none) { + return; + } + interaction = InteractionAPIBase(_.memory.Allocate( + adapterClass.default.clientInteractionAPIClass)); +} + /** * Returns current local player's `Controller`. Useful because `level` * is not accessible inside objects. diff --git a/sources/ClientRealm/API/Unreal/InteractionAPI/Events/Interaction_OnRender_Signal.uc b/sources/ClientRealm/API/Unreal/InteractionAPI/Events/Interaction_OnRender_Signal.uc new file mode 100644 index 0000000..54b1ca3 --- /dev/null +++ b/sources/ClientRealm/API/Unreal/InteractionAPI/Events/Interaction_OnRender_Signal.uc @@ -0,0 +1,41 @@ +/** + * Signal class implementation for `InteractionAPI`'s `OnPreRender` and + * `OnPostRender` signals. + * 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 Interaction_OnRender_Signal extends Signal; + +public function bool Emit(Canvas canvas) +{ + local Slot nextSlot; + + StartIterating(); + nextSlot = GetNextSlot(); + while (nextSlot != none) + { + Interaction_OnRender_Slot(nextSlot).connect(canvas); + nextSlot = GetNextSlot(); + } + CleanEmptySlots(); + return true; +} + +defaultproperties +{ + relatedSlotClass = class'Interaction_OnRender_Slot' +} \ No newline at end of file diff --git a/sources/ClientRealm/API/Unreal/InteractionAPI/Events/Interaction_OnRender_Slot.uc b/sources/ClientRealm/API/Unreal/InteractionAPI/Events/Interaction_OnRender_Slot.uc new file mode 100644 index 0000000..64e3b13 --- /dev/null +++ b/sources/ClientRealm/API/Unreal/InteractionAPI/Events/Interaction_OnRender_Slot.uc @@ -0,0 +1,41 @@ +/** + * Signal class implementation for `InteractionAPI`'s `OnPreRender` and + * `OnPostRender` signals. + * 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 Interaction_OnRender_Slot extends Slot; + +delegate connect(Canvas canvas) +{ + DummyCall(); +} + +protected function Constructor() +{ + connect = none; +} + +protected function Finalizer() +{ + super.Finalizer(); + connect = none; +} + +defaultproperties +{ +} \ No newline at end of file diff --git a/sources/ClientRealm/API/Unreal/InteractionAPI/InteractionAPI.uc b/sources/ClientRealm/API/Unreal/InteractionAPI/InteractionAPI.uc new file mode 100644 index 0000000..9fc49ca --- /dev/null +++ b/sources/ClientRealm/API/Unreal/InteractionAPI/InteractionAPI.uc @@ -0,0 +1,79 @@ +/** + * Default Acedia implementation for `InteractionAPIBase`. + * 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 InteractionAPI extends InteractionAPIBase; + +/* SIGNAL */ +public function Interaction_OnRender_Slot OnPreRender(AcediaObject receiver) +{ + local AcediaInteraction interaction; + + // Simple redirect to `AcediaInteraction` + interaction = class'AcediaInteraction'.static.GetInstance(); + if (interaction != none) { + return interaction.OnPreRender(receiver); + } + return none; +} + +/* SIGNAL */ +public function Interaction_OnRender_Slot OnPostRender(AcediaObject receiver) +{ + local AcediaInteraction interaction; + + // Simple redirect to `AcediaInteraction` + interaction = class'AcediaInteraction'.static.GetInstance(); + if (interaction != none) { + return interaction.OnPostRender(receiver); + } + return none; +} + +public function Interaction AddInteraction(BaseText interactionClass) +{ + local string classAsString; + + if (interactionClass == none) { + return none; + } + classAsString = interactionClass.ToString(); + return AddInteraction_S(classAsString); +} + +public function Interaction AddInteraction_S(string interactionClass) +{ + local Interaction newInteraction; + local Player player; + local PlayerController localPlayerController; + + localPlayerController = _client.unreal.GetLocalPlayer(); + if (localPlayerController == none) return none; + player = localPlayerController.player; + if (player == none) return none; + if (player.interactionMaster == none) return none; + + newInteraction = player.interactionMaster.AddInteraction( + "AcediaCore.AcediaInteraction", + player); + return newInteraction; +} + +defaultproperties +{ +} \ No newline at end of file diff --git a/sources/ClientRealm/API/Unreal/InteractionAPI/InteractionAPIBase.uc b/sources/ClientRealm/API/Unreal/InteractionAPI/InteractionAPIBase.uc new file mode 100644 index 0000000..3c5e9b6 --- /dev/null +++ b/sources/ClientRealm/API/Unreal/InteractionAPI/InteractionAPIBase.uc @@ -0,0 +1,74 @@ +/** + * API that provides `Interaction` events and auxiliary methods. + * 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 InteractionAPIBase extends AcediaObject; + +/** + * Called before rendering, when `Interaction`s receive their `PreRender()` + * events + * + * [Signature] + * (Canvas canvas) + * + * @param Canvas `Actor` that attempts to broadcast next text message. + */ +/* SIGNAL */ +public function Interaction_OnRender_Slot OnPreRender(AcediaObject receiver); + +/** + * Called before rendering, when `Interaction`s receive their `PreRender()` + * events + * + * [Signature] + * (Canvas canvas) + * + * @param Canvas `Actor` that attempts to broadcast next text message. + */ +/* SIGNAL */ +public function Interaction_OnRender_Slot OnPostRender(AcediaObject receiver); + +/** + * Adds new interaction of class `interactionClass` to the local interaction + * master. + * + * @see `AddInteraction_S()` + * + * @param interactionClass Textual representation of interaction class + * to add. + * @return Newly added interaction. `none` if we've failed to add it to + * the interaction master. + */ +public function Interaction AddInteraction(BaseText interactionClass); + +/** + * Adds new interaction of class `interactionClass` to the local interaction + * master. + * + * @see `AddInteraction()` + * + * @param interactionClass Textual representation of interaction class + * to add. + * @return Newly added interaction. `none` if we've failed to add it to + * the interaction master. + */ +public function Interaction AddInteraction_S(string interactionClass); + +defaultproperties +{ +} \ No newline at end of file diff --git a/sources/ClientRealm/AcediaInteraction.uc b/sources/ClientRealm/AcediaInteraction.uc new file mode 100644 index 0000000..84d5b5b --- /dev/null +++ b/sources/ClientRealm/AcediaInteraction.uc @@ -0,0 +1,120 @@ +/** + * Acedia's interaction class that allows it access to drawing and user input. + * 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 AcediaInteraction extends Interaction; + +#exec OBJ LOAD FILE=KillingFloorHUD.utx +#exec OBJ LOAD FILE=KillingFloor2HUD.utx + +var private Global _; +var private ClientGlobal _client; +var private AcediaInteraction myself; +var Texture shield; + +var private Interaction_OnRender_Signal onPreRenderSignal; +var private Interaction_OnRender_Signal onPostRenderSignal; + +/** + * Called before rendering, when `Interaction`s receive their `PreRender()` + * events + * + * [Signature] + * (Canvas canvas) + * + * @param Canvas `Actor` that attempts to broadcast next text message. + */ +/* SIGNAL */ +public function Interaction_OnRender_Slot OnPreRender(AcediaObject receiver) +{ + return Interaction_OnRender_Slot(onPreRenderSignal.NewSlot(receiver)); +} + +/** + * Called before rendering, when `Interaction`s receive their `PreRender()` + * events + * + * [Signature] + * (Canvas canvas) + * + * @param Canvas `Actor` that attempts to broadcast next text message. + */ +/* SIGNAL */ +public function Interaction_OnRender_Slot OnPostRender(AcediaObject receiver) +{ + return Interaction_OnRender_Slot(onPostRenderSignal.NewSlot(receiver)); +} + +/** + * Initializes newly created `Interaction`. + */ +public final function InitializeInteraction() +{ + if (default.myself != none) { + return; + } + default.myself = self; + _ = class'Global'.static.GetInstance(); + _client = class'ClientGlobal'.static.GetInstance(); + onPreRenderSignal = Interaction_OnRender_Signal( + _.memory.Allocate(class'Interaction_OnRender_Signal')); + onPostRenderSignal = Interaction_OnRender_Signal( + _.memory.Allocate(class'Interaction_OnRender_Signal')); +} + +event NotifyLevelChange() +{ + _.environment.ShutDown(); + default.myself = none; + _ = none; + _client = none; + master.RemoveInteraction(self); +} + +/** + * Returns instance to the added `AcediaInteraction`'s instance. + * + * @return Instance added to interaction master. + */ +public static function AcediaInteraction GetInstance() +{ + return default.myself; +} + +public function PreRender(Canvas canvas) +{ + if (onPreRenderSignal != none) { + onPreRenderSignal.Emit(canvas); + } +} + +public function PostRender(Canvas canvas) +{ + Log("dsfsdfs"); + canvas.SetPos(500, 500); + canvas.DrawTile(shield, 16, 16, 0, 0, shield.MaterialUSize(), shield.MaterialVSize()); + if (onPostRenderSignal != none) { + onPostRenderSignal.Emit(canvas); + } +} + +defaultproperties +{ + shield = Texture'KillingFloorHUD.HUD.Hud_Shield' + bVisible = true +} \ No newline at end of file diff --git a/sources/ClientRealm/ClientAcediaAdapter.uc b/sources/ClientRealm/ClientAcediaAdapter.uc index 22a17ed..f866c2e 100644 --- a/sources/ClientRealm/ClientAcediaAdapter.uc +++ b/sources/ClientRealm/ClientAcediaAdapter.uc @@ -23,8 +23,10 @@ class ClientAcediaAdapter extends AcediaAdapter abstract; var public const class clientUnrealAPIClass; +var public const class clientInteractionAPIClass; defaultproperties { - clientUnrealAPIClass = class'ClientUnrealAPI' + clientUnrealAPIClass = class'ClientUnrealAPI' + clientInteractionAPIClass = class'InteractionAPI' } \ No newline at end of file diff --git a/sources/ClientRealm/ClientGlobal.uc b/sources/ClientRealm/ClientGlobal.uc index 2432701..37a481c 100644 --- a/sources/ClientRealm/ClientGlobal.uc +++ b/sources/ClientRealm/ClientGlobal.uc @@ -27,7 +27,7 @@ var protected ClientGlobal myself; var public ClientUnrealAPIBase unreal; -var private LoggerAPI.Definition fatBadAdapterClass; +var private LoggerAPI.Definition fatBadAdapterClass, errNoInteraction; public final static function ClientGlobal GetInstance() { @@ -43,6 +43,8 @@ public final static function ClientGlobal GetInstance() protected function Initialize() { local Global _; + local PlayerController localPlayer; + local AcediaInteraction newInteraction; local class clientAdapterClass; if (initialized) { @@ -61,9 +63,25 @@ protected function Initialize() if (clientAdapterClass == none) { return; } + // Create APIs _ = class'Global'.static.GetInstance(); unreal = ClientUnrealAPIBase( _.memory.Allocate(clientAdapterClass.default.clientUnrealAPIClass)); + unreal.Initialize(clientAdapterClass); + // Create `AcediaInteraction` + localPlayer = unreal.GetLocalPlayer(); + if (localPlayer != none) + { + newInteraction = AcediaInteraction(unreal + .interaction + .AddInteraction_S("AcediaCore.AcediaInteraction")); + if (newInteraction != none) { + newInteraction.InitializeInteraction(); + } + else { + _.logger.Auto(errNoInteraction); + } + } } public final function bool ConnectClientLevelCore() @@ -78,5 +96,6 @@ public final function bool ConnectClientLevelCore() 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.") + 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.") + errNoInteraction = (l=LOG_Error,m="Failed to create interaction \"AcediaCore.AcediaInteraction\". AcediaCore won't support most of its client-side functionality.") } \ No newline at end of file