/**
* Author: dkanus
* Home repo: https://www.insultplayers.ru/git/AcediaFramework/AcediaCore
* License: GPL
* Copyright 2022-2023 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 ChatApi extends AcediaObject;
var protected bool connectedToBroadcastAPI;
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'));
}
protected function Finalizer() {
_.memory.Free(onMessageSignal);
_.memory.Free(onMessageForSignal);
onMessageSignal = none;
onMessageForSignal = none;
_server.unreal.broadcasts.OnHandleText(self).Disconnect();
_server.unreal.broadcasts.OnHandleTextFor(self).Disconnect();
connectedToBroadcastAPI = false;
}
private final function TryConnectingBroadcastSignals() {
if (connectedToBroadcastAPI) {
return;
}
connectedToBroadcastAPI = true;
_server.unreal.broadcasts.OnHandleText(self).connect = HandleText;
_server.unreal.broadcasts.OnHandleTextFor(self).connect = HandleTextFor;
}
/// 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.
///
/// # Slot description
///
/// bool (EPlayer sender, MutableText message, bool teamMessage)
///
/// ## Parameters
///
/// * [`sender`]: `EPlayer` that has sent the message.
/// * [`message`]: Message that `sender` has sent.
/// This is a mutable variable and can be modified from message will be sent.
/// * [`teamMessage`]: Is this a team message (to be sent only to players on the same team)?
///
/// ## Returns
///
/// 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`.
public /*signal*/ function ChatAPI_OnMessage_Slot OnMessage(AcediaObject receiver) {
TryConnectingBroadcastSignals();
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.
///
/// # Slot description
///
/// bool (EPlayer receiver, EPlayer sender, BaseText message)
///
/// ## Parameters
///
/// * [`receiver`]: `EPlayer` that will receive the message.
/// * [`sender`]: `EPlayer` that has sent the message.
/// * [`message`]: Message that `sender` has sent. This is an immutable variable and cannot
/// be changed at this point. Use `OnMessage()` signal function for that.
///
/// ## Returns
///
/// 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.
public /*signal*/ function ChatAPI_OnMessageFor_Slot OnMessageFor(AcediaObject receiver) {
TryConnectingBroadcastSignals();
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();
// To correctly display chat messages we want to drop default color tag
// at the beginning (the one `ToColoredString()` adds if first character
// has no defined color).
// This is a compatibility consideration with vanilla UI that expects
// uncolored text. Not removing initial color tag will make chat text
// appear black.
if (!messageAsText.GetFormatting(0).isColored) {
message = Mid(message, 4);
}
_.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 {
}