Browse Source

Add `ChatAPI`

pull/8/head
Anton Tarasenko 3 years ago
parent
commit
3addd1fc13
  1. 156
      sources/Chat/ChatAPI.uc
  2. 46
      sources/Chat/Events/ChatAPI_OnMessageFor_Signal.uc
  3. 41
      sources/Chat/Events/ChatAPI_OnMessageFor_Slot.uc
  4. 49
      sources/Chat/Events/ChatAPI_OnMessage_Signal.uc
  5. 44
      sources/Chat/Events/ChatAPI_OnMessage_Slot.uc
  6. 33
      sources/Commands/Commands_Feature.uc
  7. 3
      sources/Global.uc

156
sources/Chat/ChatAPI.uc

@ -0,0 +1,156 @@
/**
* API that provides functions for working with chat.
* 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 ChatAPI extends AcediaObject;
var protected ChatAPI_OnMessage_Signal onMessageSignal;
var protected ChatAPI_OnMessageFor_Signal onMessageForSignal;
protected function Constructor()
{
onMessageSignal = ChatAPI_OnMessage_Signal(
_.memory.Allocate(class'ChatAPI_OnMessage_Signal'));
onMessageForSignal = ChatAPI_OnMessageFor_Signal(
_.memory.Allocate(class'ChatAPI_OnMessageFor_Signal'));
_.unreal.broadcasts.OnHandleText(self).connect = HandleText;
_.unreal.broadcasts.OnHandleTextFor(self).connect = HandleTextFor;
}
protected function Finalizer()
{
_.memory.Free(onMessageSignal);
_.memory.Free(onMessageForSignal);
onMessageSignal = none;
onMessageForSignal = none;
_.unreal.broadcasts.OnHandleText(self).Disconnect();
_.unreal.broadcasts.OnHandleTextFor(self).Disconnect();
}
/**
* Signal that will be emitted when a player sends a message into the chat.
* Allows to modify message before sending it, as well as prevent it from
* being sent at all.
*
* Return `false` to prevent message from being sent.
* If `false` is returned, signal propagation to the remaining handlers will
* also be interrupted.
*
* [Signature]
* bool <slot>(EPlayer sender, MutableText message, bool teamMessage)
*
* @param sender `EPlayer` that has sent the message.
* @param message Message that `sender` has sent. This is a mutable
* variable and can be modified from message will be sent.
* @param teamMessage Is this a team message
* (to be sent only to players on the same team)?
* @return Return `false` to prevent this message from being sent at all
* and `true` otherwise. Message will be sent only if all handlers will
* return `true`.
*/
/* SIGNAL */
public function ChatAPI_OnMessage_Slot OnMessage(
AcediaObject receiver)
{
return ChatAPI_OnMessage_Slot(onMessageSignal.NewSlot(receiver));
}
/**
* Signal that will be emitted when a player sends a message into the chat.
* Allows to modify message before sending it, as well as prevent it from
* being sent at all.
*
* Return `false` to prevent message from being sent to a specific player.
* If `false` is returned, signal propagation to the remaining handlers will
* also be interrupted.
*
* [Signature]
* bool <slot>(EPlayer receiver, EPlayer sender, Text message)
*
* @param receiver `EPlayer` that will receive the message.
* @param sender `EPlayer` that has sent the message.
* @param message Message that `sender` has sent. This is an immutable
* variable and cannot be changed at this point. Use `OnMessage()`
* signal function for that.
* @return Return `false` to prevent this message from being sent to
* a particular player and `true` otherwise. Message will be sent only if
* all handlers will return `true`.
* However decision whether to send message or not is made for
* every player separately.
*/
/* SIGNAL */
public function ChatAPI_OnMessageFor_Slot OnMessageFor(
AcediaObject receiver)
{
return ChatAPI_OnMessageFor_Slot(onMessageForSignal.NewSlot(receiver));
}
private function bool HandleText(
Actor sender,
out string message,
name messageType,
bool teamMessage)
{
local bool result;
local MutableText messageAsText;
local EPlayer senderPlayer;
// We only want to catch chat messages from a player
if (messageType != 'Say' && messageType != 'TeamSay') return true;
senderPlayer = _.players.FromController(PlayerController(sender));
if (senderPlayer == none) return true;
messageAsText = __().text.FromColoredStringM(message);
result = onMessageSignal.Emit(senderPlayer, messageAsText, teamMessage);
message = messageAsText.ToColoredString();
_.memory.Free(messageAsText);
_.memory.Free(senderPlayer);
return result;
}
private function bool HandleTextFor(
PlayerController receiver,
Actor sender,
out string message,
name messageType)
{
local bool result;
local Text messageAsText;
local EPlayer senderPlayer, receiverPlayer;
// We only want to catch chat messages from another player
if (messageType != 'Say' && messageType != 'TeamSay') return true;
senderPlayer = _.players.FromController(PlayerController(sender));
if (senderPlayer == none) return true;
receiverPlayer = _.players.FromController(receiver);
if (receiverPlayer == none)
{
_.memory.Free(senderPlayer);
return true;
}
messageAsText = __().text.FromColoredString(message);
result = onMessageForSignal.Emit( receiverPlayer, senderPlayer,
messageAsText);
_.memory.Free(messageAsText);
_.memory.Free(senderPlayer);
_.memory.Free(receiverPlayer);
return result;
}
defaultproperties
{
}

46
sources/Chat/Events/ChatAPI_OnMessageFor_Signal.uc

@ -0,0 +1,46 @@
/**
* Signal class implementation for `ChatAPI`'s `OnMessageFor` signal.
* 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 ChatAPI_OnMessageFor_Signal extends Signal;
public final function bool Emit(EPlayer receiver, EPlayer sender, Text message)
{
local Slot nextSlot;
local bool nextReply;
StartIterating();
nextSlot = GetNextSlot();
while (nextSlot != none)
{
nextReply = ChatAPI_OnMessageFor_Slot(nextSlot)
.connect(receiver, sender, message);
if (!nextReply && !nextSlot.IsEmpty())
{
CleanEmptySlots();
return false;
}
nextSlot = GetNextSlot();
}
CleanEmptySlots();
return true;
}
defaultproperties
{
relatedSlotClass = class'ChatAPI_OnMessageFor_Slot'
}

41
sources/Chat/Events/ChatAPI_OnMessageFor_Slot.uc

@ -0,0 +1,41 @@
/**
* Slot class implementation for `CharAPI`'s `OnMessageFor` signal.
* 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 ChatAPI_OnMessageFor_Slot extends Slot;
delegate bool connect(EPlayer receiver, EPlayer sender, Text message)
{
DummyCall();
return true;
}
protected function Constructor()
{
connect = none;
}
protected function Finalizer()
{
super.Finalizer();
connect = none;
}
defaultproperties
{
}

49
sources/Chat/Events/ChatAPI_OnMessage_Signal.uc

@ -0,0 +1,49 @@
/**
* Signal class implementation for `ChatAPI`'s `OnMessage` signal.
* 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 ChatAPI_OnMessage_Signal extends Signal;
public final function bool Emit(
EPlayer sender,
MutableText message,
bool teamMessage)
{
local Slot nextSlot;
local bool nextReply;
StartIterating();
nextSlot = GetNextSlot();
while (nextSlot != none)
{
nextReply = ChatAPI_OnMessage_Slot(nextSlot)
.connect(sender, message, teamMessage);
if (!nextReply && !nextSlot.IsEmpty())
{
CleanEmptySlots();
return false;
}
nextSlot = GetNextSlot();
}
CleanEmptySlots();
return true;
}
defaultproperties
{
relatedSlotClass = class'ChatAPI_OnMessage_Slot'
}

44
sources/Chat/Events/ChatAPI_OnMessage_Slot.uc

@ -0,0 +1,44 @@
/**
* Slot class implementation for `ChatAPI`'s `OnMessage` signal.
* 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 ChatAPI_OnMessage_Slot extends Slot;
delegate bool connect(
EPlayer sender,
MutableText message,
bool teamMessage)
{
DummyCall();
return true;
}
protected function Constructor()
{
connect = none;
}
protected function Finalizer()
{
super.Finalizer();
connect = none;
}
defaultproperties
{
}

33
sources/Commands/Commands_Feature.uc

@ -38,7 +38,7 @@ protected function OnEnabled()
{ {
registeredCommands = _.collections.EmptyAssociativeArray(); registeredCommands = _.collections.EmptyAssociativeArray();
RegisterCommand(class'ACommandHelp'); RegisterCommand(class'ACommandHelp');
_.unreal.broadcasts.OnHandleText(self).connect = HandleText; _.chat.OnMessage(self).connect = HandleCommands;
// Macro selector // Macro selector
commandDelimiters[0] = P("@"); commandDelimiters[0] = P("@");
// Key selector // Key selector
@ -51,7 +51,7 @@ protected function OnEnabled()
protected function OnDisabled() protected function OnDisabled()
{ {
_.unreal.broadcasts.OnHandleText(self).Disconnect(); _.chat.OnMessage(self).Disconnect();
if (registeredCommands != none) if (registeredCommands != none)
{ {
registeredCommands.Empty(true); registeredCommands.Empty(true);
@ -221,35 +221,24 @@ public final function HandleInput(Parser parser, EPlayer callerPlayer)
} }
} }
private function bool HandleText( private function bool HandleCommands(
Actor sender, EPlayer sender,
out string message, MutableText message,
name messageType,
bool teamMessage) bool teamMessage)
{ {
local Text messageAsText; local Parser parser;
local EPlayer callerPlayer; if (!UsingChatInput()) {
local Parser parser; return true;
// We only want to catch chat messages }
// and only if `Commands` feature is active
if (messageType != 'Say') return true;
if (!UsingChatInput()) return true;
// We are only interested in messages that start with "!" // We are only interested in messages that start with "!"
parser = __().text.ParseString(message); parser = _.text.Parse(message);
if (!parser.Match(P("!")).Ok()) if (!parser.Match(P("!")).Ok())
{ {
parser.FreeSelf(); parser.FreeSelf();
// Convert color tags into colors
messageAsText = __().text.FromFormattedString(message);
message = messageAsText.ToColoredString(,, __().color.White);
messageAsText.FreeSelf();
return true; return true;
} }
// Extract `EPlayer` from the `sender`
callerPlayer = _.players.FromController(PlayerController(sender));
// Pass input to command feature // Pass input to command feature
HandleInput(parser, callerPlayer); HandleInput(parser, sender);
_.memory.Free(callerPlayer);
parser.FreeSelf(); parser.FreeSelf();
return false; return false;
} }

3
sources/Global.uc

@ -35,6 +35,7 @@ var public AliasesAPI alias;
var public TextAPI text; var public TextAPI text;
var public MemoryAPI memory; var public MemoryAPI memory;
var public ConsoleAPI console; var public ConsoleAPI console;
var public ChatAPI chat;
var public ColorAPI color; var public ColorAPI color;
var public UserAPI users; var public UserAPI users;
var public PlayersAPI players; var public PlayersAPI players;
@ -70,6 +71,7 @@ protected function Initialize()
logger = LoggerAPI(memory.Allocate(class'LoggerAPI')); logger = LoggerAPI(memory.Allocate(class'LoggerAPI'));
alias = AliasesAPI(memory.Allocate(class'AliasesAPI')); alias = AliasesAPI(memory.Allocate(class'AliasesAPI'));
console = ConsoleAPI(memory.Allocate(class'ConsoleAPI')); console = ConsoleAPI(memory.Allocate(class'ConsoleAPI'));
chat = ChatAPI(memory.Allocate(class'ChatAPI'));
color = ColorAPI(memory.Allocate(class'ColorAPI')); color = ColorAPI(memory.Allocate(class'ColorAPI'));
users = UserAPI(memory.Allocate(class'UserAPI')); users = UserAPI(memory.Allocate(class'UserAPI'));
players = PlayersAPI(memory.Allocate(class'PlayersAPI')); players = PlayersAPI(memory.Allocate(class'PlayersAPI'));
@ -99,6 +101,7 @@ public function DropCoreAPI()
logger = none; logger = none;
alias = none; alias = none;
console = none; console = none;
chat = none;
color = none; color = none;
users = none; users = none;
players = none; players = none;

Loading…
Cancel
Save