/** * 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 { }