Change file structure of Acedia

Improves grouping of some files in project's directories.
This commit is contained in:
Anton Tarasenko 2020-04-09 14:43:45 +07:00
commit 97569f9568
21 changed files with 0 additions and 0 deletions

View file

@ -0,0 +1,142 @@
/**
* Event generator for events, related to broadcasting messages
* through standard Unreal Script means:
* 1. text messages, typed by a player;
* 2. localized messages, identified by a LocalMessage class and id.
* Allows to make decisions whether or not to propagate certain messages.
* Copyright 2020 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 BroadcastEvents extends Events
abstract;
struct LocalizedMessage
{
// Every localized message is described by a class and id.
// For example, consider 'KFMod.WaitingMessage':
// if passed 'id' is '1',
// then it's supposed to be a message about new wave,
// but if passed 'id' is '2',
// then it's about completing the wave.
var class<LocalMessage> class;
var int id;
// Localized messages in unreal script can be passed along with
// optional arguments, described by variables below.
var PlayerReplicationInfo relatedPRI1;
var PlayerReplicationInfo relatedPRI2;
var Object relatedObject;
};
static function bool CallCanBroadcast(Actor broadcaster, int recentSentTextSize)
{
local int i;
local bool result;
local array< class<Listener> > listeners;
listeners = GetListeners();
for (i = 0;i < listeners.length;i += 1)
{
result = class<BroadcastListenerBase>(listeners[i])
.static.CanBroadcast(broadcaster, recentSentTextSize);
if (!result) return false;
}
return true;
}
static function bool CallHandleText
(
Actor sender,
out string message,
name messageType
)
{
local int i;
local bool result;
local array< class<Listener> > listeners;
listeners = GetListeners();
for (i = 0;i < listeners.length;i += 1)
{
result = class<BroadcastListenerBase>(listeners[i])
.static.HandleText(sender, message, messageType);
if (!result) return false;
}
return true;
}
static function bool CallHandleTextFor
(
PlayerController receiver,
Actor sender,
out string message,
name messageType
)
{
local int i;
local bool result;
local array< class<Listener> > listeners;
listeners = GetListeners();
for (i = 0;i < listeners.length;i += 1)
{
result = class<BroadcastListenerBase>(listeners[i])
.static.HandleTextFor(receiver, sender, message, messageType);
if (!result) return false;
}
return true;
}
static function bool CallHandleLocalized
(
Actor sender,
LocalizedMessage message
)
{
local int i;
local bool result;
local array< class<Listener> > listeners;
listeners = GetListeners();
for (i = 0;i < listeners.length;i += 1)
{
result = class<BroadcastListenerBase>(listeners[i])
.static.HandleLocalized(sender, message);
if (!result) return false;
}
return true;
}
static function bool CallHandleLocalizedFor
(
PlayerController receiver,
Actor sender,
LocalizedMessage message
)
{
local int i;
local bool result;
local array< class<Listener> > listeners;
listeners = GetListeners();
for (i = 0;i < listeners.length;i += 1)
{
result = class<BroadcastListenerBase>(listeners[i])
.static.HandleLocalizedFor(receiver, sender, message);
if (!result) return false;
}
return true;
}
defaultproperties
{
relatedListener = class'BroadcastListenerBase'
}

View file

@ -0,0 +1,197 @@
/**
* 'BroadcastHandler' class that used by Acedia to catch
* broadcasting events. For Acedia to work properly it needs to be added to
* the very beginning of the broadcast handlers' chain.
* Copyright 2020 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/>.
*/
// TODO: make it work from any place in the chain.
class BroadcastHandler extends Engine.BroadcastHandler
dependson(BroadcastEvents);
// The way vanilla 'BroadcastHandler' works - it can check if broadcast is
// possible for any actor, but for actually sending the text messages it will
// try to extract player's data from it
// and will simply pass 'none' if it can't.
// We remember senders in this array in order to pass real ones to our events.
// Array instead of variable is to account for folded calls
// (when handling of broadcast events leads to another message generation).
var private array<Actor> storedSenders;
// We want to insert our code in some of the functions between
// 'AllowsBroadcast' check and actual broadcasting,
// so we can't just use a 'super.AllowsBroadcast()' call.
// Instead we first manually do this check, then perform our logic and then
// make a super call, but with 'blockAllowsBroadcast' flag set to 'true',
// which causes overloaded 'AllowsBroadcast()' to omit actual checks.
var private bool blockAllowsBroadcast;
// Functions below simply reroute vanilla's broadcast events to
// Acedia's 'BroadcastEvents', while keeping original senders
// and blocking 'AllowsBroadcast()' as described in comments for
// 'storedSenders' and 'blockAllowsBroadcast'.
public function bool HandlerAllowsBroadcast(Actor broadcaster, int sentTextNum)
{
local bool canBroadcast;
// Check listeners
canBroadcast = class'BroadcastEvents'.static
.CallCanBroadcast(broadcaster, sentTextNum);
// Check other broadcast handlers (if present)
if (canBroadcast && nextBroadcastHandler != none)
{
canBroadcast = nextBroadcastHandler
.HandlerAllowsBroadcast(broadcaster, sentTextNum);
}
return canBroadcast;
}
function Broadcast(Actor sender, coerce string message, optional name type)
{
local bool canTryToBroadcast;
if (!AllowsBroadcast(sender, Len(message)))
return;
canTryToBroadcast = class'BroadcastEvents'.static
.CallHandleText(sender, message, type);
if (canTryToBroadcast)
{
storedSenders[storedSenders.length] = sender;
blockAllowsBroadcast = true;
super.Broadcast(sender, message, type);
blockAllowsBroadcast = false;
storedSenders.length = storedSenders.length - 1;
}
}
function BroadcastTeam
(
Controller sender,
coerce string message,
optional name type
)
{
local bool canTryToBroadcast;
if (!AllowsBroadcast(sender, Len(message)))
return;
canTryToBroadcast = class'BroadcastEvents'.static
.CallHandleText(sender, message, type);
if (canTryToBroadcast)
{
storedSenders[storedSenders.length] = sender;
blockAllowsBroadcast = true;
super.BroadcastTeam(sender, message, type);
blockAllowsBroadcast = false;
storedSenders.length = storedSenders.length - 1;
}
}
event AllowBroadcastLocalized
(
Actor sender,
class<LocalMessage> message,
optional int switch,
optional PlayerReplicationInfo relatedPRI1,
optional PlayerReplicationInfo relatedPRI2,
optional Object optionalObject
)
{
local bool canTryToBroadcast;
local BroadcastEvents.LocalizedMessage packedMessage;
if (!AllowsBroadcast(sender, Len(message)))
return;
packedMessage.class = message;
packedMessage.id = switch;
packedMessage.relatedPRI1 = relatedPRI1;
packedMessage.relatedPRI2 = relatedPRI2;
packedMessage.relatedObject = optionalObject;
canTryToBroadcast = class'BroadcastEvents'.static
.CallHandleLocalized(sender, packedMessage);
if (canTryToBroadcast)
{
super.AllowBroadcastLocalized( sender, message, switch,
relatedPRI1, relatedPRI2,
optionalObject);
}
}
function bool AllowsBroadcast(actor broadcaster, int len)
{
if (blockAllowsBroadcast)
return true;
return super.AllowsBroadcast(broadcaster, len);
}
function bool AcceptBroadcastText
(
PlayerController receiver,
PlayerReplicationInfo senderPRI,
out string message,
optional name type
)
{
local bool canBroadcast;
local Actor sender;
if (senderPRI != none)
{
sender = PlayerController(senderPRI.owner);
}
if (sender == none && storedSenders.length > 0)
{
sender = storedSenders[storedSenders.length - 1];
}
canBroadcast = class'BroadcastEvents'.static
.CallHandleTextFor(receiver, sender, message, type);
if (!canBroadcast)
{
return false;
}
return super.AcceptBroadcastText(receiver, senderPRI, message, type);
}
function bool AcceptBroadcastLocalized
(
PlayerController receiver,
Actor sender,
class<LocalMessage> message,
optional int switch,
optional PlayerReplicationInfo relatedPRI1,
optional PlayerReplicationInfo relatedPRI2,
optional Object obj
)
{
local bool canBroadcast;
local BroadcastEvents.LocalizedMessage packedMessage;
packedMessage.class = message;
packedMessage.id = switch;
packedMessage.relatedPRI1 = relatedPRI1;
packedMessage.relatedPRI2 = relatedPRI2;
packedMessage.relatedObject = obj;
canBroadcast = class'BroadcastEvents'.static
.CallHandleLocalizedFor(receiver, sender, packedMessage);
if (!canBroadcast)
{
return false;
}
return super.AcceptBroadcastLocalized( receiver, sender, message, switch,
relatedPRI1, relatedPRI2, obj);
}
defaultproperties
{
blockAllowsBroadcast = false
}

View file

@ -0,0 +1,120 @@
/**
* Listener for events, related to broadcasting messages
* through standard Unreal Script means:
* 1. text messages, typed by a player;
* 2. localized messages, identified by a LocalMessage class and id.
* Allows to make decisions whether or not to propagate certain messages.
* Copyright 2020 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 BroadcastListenerBase extends Listener
abstract;
static final function PlayerController GetController(Actor sender)
{
local Pawn senderPawn;
senderPawn = Pawn(sender);
if (senderPawn != none) return PlayerController(senderPawn.controller);
return PlayerController(sender);
}
// This event is called whenever registered broadcast handlers are asked if
// they'd allow given actor ('broadcaster') to broadcast a text message,
// given that none so far rejected it and he recently already broadcasted
// or tried to broadcast 'recentSentTextSize' symbols of text
// (that value is periodically reset in 'GameInfo',
// by default should be each second).
// NOTE: this function is ONLY called when someone tries to
// broadcast TEXT messages.
// If one of the listeners returns 'false', -
// it will be treated just like one of broadcasters returning 'false'
// in 'AllowsBroadcast' and this method won't be called for remaining
// active listeners.
static function bool CanBroadcast(Actor broadcaster, int recentSentTextSize)
{
return true;
}
// This event is called whenever a someone is trying to broadcast
// a text message (typically the typed by a player).
// This function is called once per message and allows you to change it
// (by changing 'message' argument) before any of the players receive it.
// Return 'true' to allow the message through.
// If one of the listeners returns 'false', -
// it will be treated just like one of broadcasters returning 'false'
// in 'AcceptBroadcastText' and this method won't be called for remaining
// active listeners.
static function bool HandleText
(
Actor sender,
out string message,
optional name messageType
)
{
return true;
}
// This event is similar to 'HandleText', but is called for every player
// the message is sent to.
// If allows you to alter the message, but the changes are accumulated
// as events go through the players.
static function bool HandleTextFor
(
PlayerController receiver,
Actor sender,
out string message,
optional name messageType
)
{
return true;
}
// This event is called whenever a localized message is trying to
// get broadcasted to a certain player ('receiver').
// Return 'true' to allow the message through.
// If one of the listeners returns 'false', -
// it will be treated just like one of broadcasters returning 'false'
// in 'AcceptBroadcastText' and this method won't be called for remaining
// active listeners.
static function bool HandleLocalized
(
Actor sender,
BroadcastEvents.LocalizedMessage message
)
{
return true;
}
// This event is similar to 'HandleLocalized', but is called for
// every player the message is sent to.
static function bool HandleLocalizedFor
(
PlayerController receiver,
Actor sender,
BroadcastEvents.LocalizedMessage message
)
{
return true;
}
defaultproperties
{
relatedEvents = class'BroadcastEvents'
}
// Text messages can (optionally) have their type specified.
// Examples of it are names 'Say' and 'CriticalEvent'.

View file

@ -0,0 +1,133 @@
/**
* One of the two classes that make up a core of event system in Acedia.
*
* 'Events' (or it's child) class shouldn't be instantiated.
* Usually module would provide '...Events' class that defines
* certain set of static functions that can generate event calls to
* all it's active listeners.
* If you're simply using modules someone made, -
* you don't need to bother yourself with further specifics.
* If you wish to create your own event generator,
* then first create a '...ListenerBase' object
* (more about it in the description of 'Listener' class)
* and set 'relatedListener' variable to point to it's class.
* Then for each event create a caller function in your 'Event' class,
* following this template:
* ____________________________________________________________________________
* | static function CallEVENT_NAME(<ARGUMENTS>)
* | {
* | local int i;
* | local array< class<Listener> > listeners;
* | listeners = GetListeners();
* | for (i = 0; i < listeners.length; i += 1)
* | {
* | class<...ListenerBase>(listeners[i])
* | .static.EVENT_NAME(<ARGUMENTS>);
* | }
* | }
* |___________________________________________________________________________
* If each listener must indicate whether it gives it's permission for
* something to happen, then use this template:
* ____________________________________________________________________________
* | static function CallEVENT_NAME(<ARGUMENTS>)
* | {
* | local int i;
* | local bool result;
* | local array< class<Listener> > listeners;
* | listeners = GetListeners();
* | for (i = 0; i < listeners.length; i += 1)
* | {
* | result = class<...ListenerBase>(listeners[i])
* | .static.EVENT_NAME(<ARGUMENTS>);
* | if (!result) return false;
* | }
* | return true;
* | }
* |___________________________________________________________________________
* For concrete example look at
* 'MutatorEvents' and 'MutatorListenerBase'.
* Copyright 2020 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 Events extends Object
abstract;
var private array< class<Listener> > listeners;
var public const class<Listener> relatedListener;
static public final function array< class<Listener> > GetListeners()
{
return default.listeners;
}
// Make given listener active.
// If listener was already activated also returns 'false'.
static public final function bool ActivateListener(class<Listener> newListener)
{
local int i;
if (newListener == none) return false;
if (!ClassIsChildOf(newListener, default.relatedListener)) return false;
for (i = 0;i < default.listeners.length;i += 1)
{
if (default.listeners[i] == newListener)
{
return false;
}
}
default.listeners[default.listeners.length] = newListener;
return true;
}
// Make given listener inactive.
// If listener wasn't active returns 'false'.
static public final function bool DeactivateListener(class<Listener> listener)
{
local int i;
if (listener == none) return false;
for (i = 0; i < default.listeners.length; i += 1)
{
if (default.listeners[i] == listener)
{
default.listeners.Remove(i, 1);
return true;
}
}
return false;
}
static public final function bool IsActiveListener(class<Listener> listener)
{
local int i;
if (listener == none) return false;
for (i = 0; i < default.listeners.length; i += 1)
{
if (default.listeners[i] == listener)
{
return true;
}
}
return false;
}
defaultproperties
{
relatedListener = class'Listener'
}

View file

@ -0,0 +1,59 @@
/**
* One of the two classes that make up a core of event system in Acedia.
*
* 'Listener' (or it's child) class shouldn't be instantiated.
* Usually module would provide '...ListenerBase' class that defines
* certain set of static functions, corresponding to events it can listen to.
* In order to handle those events you must create it's child class and
* override said functions. But they will only be called if
* 'SetActive(true)' is called for that child class.
* To create you own '...ListenerBase' class you need to define
* a static function for each event you wish it to catch and
* set 'relatedEvents' variable to point at the 'Events' class
* that will generate your events.
* For concrete example look at
* 'ConnectionEvents' and 'ConnectionListenerBase'.
* Copyright 2019 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 Listener extends Object
abstract;
var public const class<Events> relatedEvents;
static public final function SetActive(bool active)
{
if (active)
{
default.relatedEvents.static.ActivateListener(default.class);
}
else
{
default.relatedEvents.static.DeactivateListener(default.class);
}
}
static public final function IsActive(bool active)
{
default.relatedEvents.static.IsActiveListener(default.class);
}
defaultproperties
{
relatedEvents = class'Events'
}

View file

@ -0,0 +1,56 @@
/**
* Event generator that repeats events of a mutator.
* Copyright 2019 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 MutatorEvents extends Events
abstract;
static function bool CallCheckReplacement(Actor other, out byte isSuperRelevant)
{
local int i;
local bool result;
local array< class<Listener> > listeners;
listeners = GetListeners();
for (i = 0; i < listeners.length; i += 1)
{
result = class<MutatorListenerBase>(listeners[i])
.static.CheckReplacement(other, isSuperRelevant);
if (!result) return false;
}
return true;
}
static function bool CallMutate(string command, PlayerController sendingPlayer)
{
local int i;
local bool result;
local array< class<Listener> > listeners;
listeners = GetListeners();
for (i = 0; i < listeners.length;i += 1)
{
result = class<MutatorListenerBase>(listeners[i])
.static.Mutate(command, sendingPlayer);
if (!result) return false;
}
return true;
}
defaultproperties
{
relatedListener = class'MutatorListenerBase'
}

View file

@ -0,0 +1,47 @@
/**
* Listener for events, normally propagated by mutators.
* Copyright 2019 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 MutatorListenerBase extends Listener
abstract;
// This event is called whenever 'CheckReplacement'
// check is propagated through mutators.
// If one of the listeners returns 'false', -
// it will be treated just like a mutator returning 'false'
// in 'CheckReplacement' and
// this method won't be called for remaining active listeners.
static function bool CheckReplacement(Actor other, out byte isSuperRelevant)
{
return true;
}
// This event is called whenever 'Mutate' is propagated through mutators.
// If one of the listeners returns 'false', -
// this method won't be called for remaining active listeners or mutators.
// If all listeners return 'true', -
// mutate command will be further propagated to the rest of the mutators.
static function bool Mutate(string command, PlayerController sendingPlayer)
{
return true;
}
defaultproperties
{
relatedEvents = class'MutatorEvents'
}