|
|
@ -1,8 +1,6 @@ |
|
|
|
/** |
|
|
|
/** |
|
|
|
* Author: dkanus |
|
|
|
* API that provides functions for working with chat. |
|
|
|
* Home repo: https://www.insultplayers.ru/git/AcediaFramework/AcediaCore |
|
|
|
* Copyright 2022 Anton Tarasenko |
|
|
|
* License: GPL |
|
|
|
|
|
|
|
* Copyright 2022-2023 Anton Tarasenko |
|
|
|
|
|
|
|
*------------------------------------------------------------------------------ |
|
|
|
*------------------------------------------------------------------------------ |
|
|
|
* This file is part of Acedia. |
|
|
|
* This file is part of Acedia. |
|
|
|
* |
|
|
|
* |
|
|
@ -19,323 +17,34 @@ |
|
|
|
* You should have received a copy of the GNU General Public License |
|
|
|
* You should have received a copy of the GNU General Public License |
|
|
|
* along with Acedia. If not, see <https://www.gnu.org/licenses/>. |
|
|
|
* along with Acedia. If not, see <https://www.gnu.org/licenses/>. |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
class ChatApi extends AcediaObject; |
|
|
|
class ChatAPI extends AcediaObject; |
|
|
|
|
|
|
|
|
|
|
|
///! API for accessing chat-related events. |
|
|
|
|
|
|
|
///! |
|
|
|
|
|
|
|
///! # Implementation |
|
|
|
|
|
|
|
///! |
|
|
|
|
|
|
|
///! Signal functions that track text chat messages `OnMessage()` and `OnMessageFor()` simply |
|
|
|
|
|
|
|
///! hook into [`BroadcastApi`] the first time such signal is requested. |
|
|
|
|
|
|
|
///! |
|
|
|
|
|
|
|
///! Signal function [`OnVoiceMessage()`] for tracking voice replaces a function in |
|
|
|
|
|
|
|
///! [`KFPlayerController`] to track when they are replicated. |
|
|
|
|
|
|
|
///! Then replaced function informs [`ChatApi`] about new voice message transmissions via |
|
|
|
|
|
|
|
///! internal [`_EmitOnVoiceMessage()`] method. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Lists voice messages built-in in the game. |
|
|
|
|
|
|
|
enum BuiltInVoiceMessage { |
|
|
|
|
|
|
|
// Support |
|
|
|
|
|
|
|
BIVM_SupportMedic, |
|
|
|
|
|
|
|
BIVM_SupportHelp, |
|
|
|
|
|
|
|
BIVM_SupportAskForMoney, |
|
|
|
|
|
|
|
BIVM_SupportAskForWeapon, |
|
|
|
|
|
|
|
// Acknowledgements |
|
|
|
|
|
|
|
BIVM_AckYes, |
|
|
|
|
|
|
|
BIVM_AckNo, |
|
|
|
|
|
|
|
BIVM_AckThanks, |
|
|
|
|
|
|
|
BIVM_AckSorry, |
|
|
|
|
|
|
|
// Alert |
|
|
|
|
|
|
|
BIVM_AlretLookOut, |
|
|
|
|
|
|
|
BIVM_AlretRun, |
|
|
|
|
|
|
|
BIVM_AlretWaitForMe, |
|
|
|
|
|
|
|
BIVM_AlretWeldTheDoors, |
|
|
|
|
|
|
|
BIVM_AlretLetsHoleUpHere, |
|
|
|
|
|
|
|
BIVM_AlretFollowMe, |
|
|
|
|
|
|
|
// Direction |
|
|
|
|
|
|
|
BIVM_DirectionGetToTheTrader, |
|
|
|
|
|
|
|
BIVM_DirectionGoUpstairs, |
|
|
|
|
|
|
|
BIVM_DirectionGoDownstairs, |
|
|
|
|
|
|
|
BIVM_DirectionGetOutside, |
|
|
|
|
|
|
|
BIVM_DirectionGetInside, |
|
|
|
|
|
|
|
// Insult |
|
|
|
|
|
|
|
BIVM_InsultSpecimens, |
|
|
|
|
|
|
|
BIVM_InsultPlayers, |
|
|
|
|
|
|
|
// Trader |
|
|
|
|
|
|
|
BIVM_TraderCheckWhereTheShopIs, |
|
|
|
|
|
|
|
BIVM_TraderGetClose, |
|
|
|
|
|
|
|
BIVM_TraderShopOpen, |
|
|
|
|
|
|
|
BIVM_TraderShopOpenFinal, |
|
|
|
|
|
|
|
BIVM_Trader30SecondsUntilShopCloses, |
|
|
|
|
|
|
|
BIVM_TraderShopClosed, |
|
|
|
|
|
|
|
BIVM_TraderCompliment, |
|
|
|
|
|
|
|
BIVM_TraderNotEnoughMoney, |
|
|
|
|
|
|
|
BIVM_TraderCannotCarry, |
|
|
|
|
|
|
|
BIVM_TraderHurryUp1, |
|
|
|
|
|
|
|
BIVM_TraderHurryUp2, |
|
|
|
|
|
|
|
// Auto |
|
|
|
|
|
|
|
BIVM_AutoWelding, |
|
|
|
|
|
|
|
BIVM_AutoUnwelding, |
|
|
|
|
|
|
|
BIVM_AutoReload, |
|
|
|
|
|
|
|
BIVM_AutoOutOfAmmo, |
|
|
|
|
|
|
|
BIVM_AutoDosh, |
|
|
|
|
|
|
|
BIVM_AutoStandStillTryingToHealYou, |
|
|
|
|
|
|
|
BIVM_AutoLowOnHealth, |
|
|
|
|
|
|
|
BIVM_AutoBloatAcid, |
|
|
|
|
|
|
|
BIVM_AutoPatriarchCloack, |
|
|
|
|
|
|
|
BIVM_AutoPatriarchMinigun, |
|
|
|
|
|
|
|
BIVM_AutoPatriarchRocketLauncher, |
|
|
|
|
|
|
|
BIVM_AutoGrabbedByClot, |
|
|
|
|
|
|
|
BIVM_AutoFleshpoundSpotted, |
|
|
|
|
|
|
|
BIVM_AutoGorefastSpotted, |
|
|
|
|
|
|
|
BIVM_AutoScrakeSpotted, |
|
|
|
|
|
|
|
BIVM_AutoSirenSpotten, |
|
|
|
|
|
|
|
BIVM_AutoSirenScream, |
|
|
|
|
|
|
|
BIVM_AutoStalkerSpotted, |
|
|
|
|
|
|
|
BIVM_AutoCrawlertSpotted, |
|
|
|
|
|
|
|
BIVM_AutoMeleeKilledAStalker, |
|
|
|
|
|
|
|
BIVM_AutoUsingFlamethrower, |
|
|
|
|
|
|
|
BIVM_AutoEquipHuntingShotgun, |
|
|
|
|
|
|
|
BIVM_AutoEquipHandcannons, |
|
|
|
|
|
|
|
BIVM_AutoEquipLAW, |
|
|
|
|
|
|
|
BIVM_AutoEquipFireaxe, |
|
|
|
|
|
|
|
// Fallback |
|
|
|
|
|
|
|
BIVM_Unknown |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Killing Floor's native voice message is defined by `name` and `byte` pair. |
|
|
|
|
|
|
|
/// This struct is added to allow returning them as a pair. |
|
|
|
|
|
|
|
struct NativeVoiceMessage { |
|
|
|
|
|
|
|
var name type; |
|
|
|
|
|
|
|
var byte index; |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Tracks whether we've already connected to broadcast signals. |
|
|
|
|
|
|
|
var protected bool connectedToBroadcastAPI; |
|
|
|
var protected bool connectedToBroadcastAPI; |
|
|
|
/// Tracks whether we've already replaced a function that allows us to catch voice messages. |
|
|
|
|
|
|
|
var private bool replacedSendVoiceMessage; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Auxiliary constants that store amount of values in [`BuiltInVoiceMessage`] before |
|
|
|
var protected ChatAPI_OnMessage_Signal onMessageSignal; |
|
|
|
/// a certain group. |
|
|
|
var protected ChatAPI_OnMessageFor_Signal onMessageForSignal; |
|
|
|
/// Used for conversion between native voice messages and [`BuiltInVoiceMessage`] |
|
|
|
|
|
|
|
var private const int VOICE_MESSAGES_BEFORE_ACKNOWLEDGEMENTS; |
|
|
|
|
|
|
|
var private const int VOICE_MESSAGES_BEFORE_ALERTS; |
|
|
|
|
|
|
|
var private const int VOICE_MESSAGES_BEFORE_DIRECTIONS; |
|
|
|
|
|
|
|
var private const int VOICE_MESSAGES_BEFORE_INSULTS; |
|
|
|
|
|
|
|
var private const int VOICE_MESSAGES_BEFORE_TRADER; |
|
|
|
|
|
|
|
var private const int VOICE_MESSAGES_BEFORE_AUTO; |
|
|
|
|
|
|
|
var private const int VOICE_MESSAGES_TOTAL; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var protected ChatAPI_OnMessage_Signal onMessageSignal; |
|
|
|
protected function Constructor() |
|
|
|
var protected ChatAPI_OnMessageFor_Signal onMessageForSignal; |
|
|
|
{ |
|
|
|
var protected ChatAPI_OnVoiceMessage_Signal onVoiceMessageSignal; |
|
|
|
onMessageSignal = ChatAPI_OnMessage_Signal( |
|
|
|
|
|
|
|
_.memory.Allocate(class'ChatAPI_OnMessage_Signal')); |
|
|
|
protected function Constructor() { |
|
|
|
onMessageForSignal = ChatAPI_OnMessageFor_Signal( |
|
|
|
onMessageSignal = ChatAPI_OnMessage_Signal(_.memory.Allocate(class'ChatAPI_OnMessage_Signal')); |
|
|
|
_.memory.Allocate(class'ChatAPI_OnMessageFor_Signal')); |
|
|
|
onMessageForSignal = |
|
|
|
|
|
|
|
ChatAPI_OnMessageFor_Signal(_.memory.Allocate(class'ChatAPI_OnMessageFor_Signal')); |
|
|
|
|
|
|
|
onVoiceMessageSignal = |
|
|
|
|
|
|
|
ChatAPI_OnVoiceMessage_Signal(_.memory.Allocate(class'ChatAPI_OnVoiceMessage_Signal')); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
protected function Finalizer() { |
|
|
|
protected function Finalizer() |
|
|
|
|
|
|
|
{ |
|
|
|
_.memory.Free(onMessageSignal); |
|
|
|
_.memory.Free(onMessageSignal); |
|
|
|
_.memory.Free(onMessageForSignal); |
|
|
|
_.memory.Free(onMessageForSignal); |
|
|
|
_.memory.Free(onVoiceMessageSignal); |
|
|
|
onMessageSignal = none; |
|
|
|
onMessageSignal = none; |
|
|
|
onMessageForSignal = none; |
|
|
|
onMessageForSignal = none; |
|
|
|
|
|
|
|
onVoiceMessageSignal = none; |
|
|
|
|
|
|
|
_server.unreal.broadcasts.OnHandleText(self).Disconnect(); |
|
|
|
_server.unreal.broadcasts.OnHandleText(self).Disconnect(); |
|
|
|
_server.unreal.broadcasts.OnHandleTextFor(self).Disconnect(); |
|
|
|
_server.unreal.broadcasts.OnHandleTextFor(self).Disconnect(); |
|
|
|
connectedToBroadcastAPI = false; |
|
|
|
connectedToBroadcastAPI = false; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/// Signal that will be emitted when a player sends a message into the chat. |
|
|
|
private final function TryConnectingBroadcastSignals() |
|
|
|
/// |
|
|
|
{ |
|
|
|
/// 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 <slot>(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 <slot>(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)); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Signal that will be emitted when a player sends a voice message. |
|
|
|
|
|
|
|
/// |
|
|
|
|
|
|
|
/// # Slot description |
|
|
|
|
|
|
|
/// |
|
|
|
|
|
|
|
/// bool <slot>(EPlayer sender, ChatApi.BuiltInVoiceMessage message) |
|
|
|
|
|
|
|
/// |
|
|
|
|
|
|
|
/// ## Parameters |
|
|
|
|
|
|
|
/// |
|
|
|
|
|
|
|
/// * [`sender`]: `EPlayer` that has sent the voice message. |
|
|
|
|
|
|
|
/// * [`message`]: Message that `sender` has sent. |
|
|
|
|
|
|
|
public /*signal*/ function ChatAPI_OnVoiceMessage_Slot OnVoiceMessage(AcediaObject receiver) { |
|
|
|
|
|
|
|
if (!replacedSendVoiceMessage) { |
|
|
|
|
|
|
|
_.unflect.ReplaceFunction_S( |
|
|
|
|
|
|
|
"KFMod.KFPlayerController.SendVoiceMessage", |
|
|
|
|
|
|
|
"AcediaCore.Unflect_ChatApi_Controller.SendVoiceMessage", |
|
|
|
|
|
|
|
"`ChatApi` was required to catch voice messages"); |
|
|
|
|
|
|
|
replacedSendVoiceMessage = true; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return ChatAPI_OnVoiceMessage_Slot(onVoiceMessageSignal.NewSlot(receiver)); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public /*internal*/ function NativeVoiceMessage _enumIntoNativeVoiceMessage( |
|
|
|
|
|
|
|
BuiltInVoiceMessage voiceMessage |
|
|
|
|
|
|
|
) { |
|
|
|
|
|
|
|
local int enumValue; |
|
|
|
|
|
|
|
local NativeVoiceMessage result; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
enumValue = int(voiceMessage); |
|
|
|
|
|
|
|
if (enumValue < VOICE_MESSAGES_BEFORE_ACKNOWLEDGEMENTS) { |
|
|
|
|
|
|
|
result.type = 'SUPPORT'; |
|
|
|
|
|
|
|
result.index = enumValue; |
|
|
|
|
|
|
|
} else if (enumValue < VOICE_MESSAGES_BEFORE_ALERTS) { |
|
|
|
|
|
|
|
result.type = 'ACK'; |
|
|
|
|
|
|
|
result.index = enumValue - VOICE_MESSAGES_BEFORE_ACKNOWLEDGEMENTS; |
|
|
|
|
|
|
|
} else if (enumValue < VOICE_MESSAGES_BEFORE_DIRECTIONS) { |
|
|
|
|
|
|
|
result.type = 'ALERT'; |
|
|
|
|
|
|
|
result.index = enumValue - VOICE_MESSAGES_BEFORE_ALERTS; |
|
|
|
|
|
|
|
} else if (enumValue < VOICE_MESSAGES_BEFORE_INSULTS) { |
|
|
|
|
|
|
|
result.type = 'DIRECTION'; |
|
|
|
|
|
|
|
result.index = enumValue - VOICE_MESSAGES_BEFORE_DIRECTIONS; |
|
|
|
|
|
|
|
} else if (enumValue < VOICE_MESSAGES_BEFORE_TRADER) { |
|
|
|
|
|
|
|
result.type = 'INSULT'; |
|
|
|
|
|
|
|
result.index = enumValue - VOICE_MESSAGES_BEFORE_INSULTS; |
|
|
|
|
|
|
|
} else if (enumValue < VOICE_MESSAGES_BEFORE_AUTO) { |
|
|
|
|
|
|
|
result.type = 'TRADER'; |
|
|
|
|
|
|
|
result.index = enumValue - VOICE_MESSAGES_BEFORE_TRADER; |
|
|
|
|
|
|
|
if (result.index >= 5) { |
|
|
|
|
|
|
|
result.index += 1; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} else if (enumValue < VOICE_MESSAGES_TOTAL) { |
|
|
|
|
|
|
|
result.type = 'AUTO'; |
|
|
|
|
|
|
|
result.index = enumValue - VOICE_MESSAGES_BEFORE_AUTO; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return result; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public /*internal*/ function BuiltInVoiceMessage _nativeVoiceMessageIntoEnum( |
|
|
|
|
|
|
|
NativeVoiceMessage voiceMessage |
|
|
|
|
|
|
|
) { |
|
|
|
|
|
|
|
switch (voiceMessage.type) { |
|
|
|
|
|
|
|
case 'SUPPORT': |
|
|
|
|
|
|
|
if (voiceMessage.index < 4) { |
|
|
|
|
|
|
|
return BuiltInVoiceMessage(voiceMessage.index); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case 'ACK': |
|
|
|
|
|
|
|
if (voiceMessage.index < 4) { |
|
|
|
|
|
|
|
return BuiltInVoiceMessage( |
|
|
|
|
|
|
|
VOICE_MESSAGES_BEFORE_ACKNOWLEDGEMENTS + voiceMessage.index); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case 'ALERT': |
|
|
|
|
|
|
|
if (voiceMessage.index < 6) { |
|
|
|
|
|
|
|
return BuiltInVoiceMessage(VOICE_MESSAGES_BEFORE_ALERTS + voiceMessage.index); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case 'DIRECTION': |
|
|
|
|
|
|
|
if (voiceMessage.index < 5) { |
|
|
|
|
|
|
|
return BuiltInVoiceMessage(VOICE_MESSAGES_BEFORE_DIRECTIONS + voiceMessage.index); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case 'INSULT': |
|
|
|
|
|
|
|
if (voiceMessage.index < 2) { |
|
|
|
|
|
|
|
return BuiltInVoiceMessage(VOICE_MESSAGES_BEFORE_INSULTS + voiceMessage.index); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case 'TRADER': |
|
|
|
|
|
|
|
if (voiceMessage.index < 12) { |
|
|
|
|
|
|
|
if (voiceMessage.index < 5) { |
|
|
|
|
|
|
|
return BuiltInVoiceMessage(VOICE_MESSAGES_BEFORE_TRADER + voiceMessage.index); |
|
|
|
|
|
|
|
} else if (voiceMessage.index > 5) { |
|
|
|
|
|
|
|
return BuiltInVoiceMessage( |
|
|
|
|
|
|
|
VOICE_MESSAGES_BEFORE_TRADER + voiceMessage.index - 1); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case 'AUTO': |
|
|
|
|
|
|
|
if (voiceMessage.index < 25) { |
|
|
|
|
|
|
|
return BuiltInVoiceMessage(VOICE_MESSAGES_BEFORE_AUTO + voiceMessage.index); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
default: |
|
|
|
|
|
|
|
return BIVM_Unknown; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return BIVM_Unknown; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public final /*internal*/ /*native*/ function _EmitOnVoiceMessage( |
|
|
|
|
|
|
|
PlayerController sender, |
|
|
|
|
|
|
|
name messageType, |
|
|
|
|
|
|
|
byte messageID |
|
|
|
|
|
|
|
) { |
|
|
|
|
|
|
|
local EPlayer wrapper; |
|
|
|
|
|
|
|
local NativeVoiceMessage nativeVoiceMessage; |
|
|
|
|
|
|
|
local BuiltInVoiceMessage builtInVoiceMessage; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (sender == none) return; |
|
|
|
|
|
|
|
wrapper = _.players.FromController(sender); |
|
|
|
|
|
|
|
if (wrapper == none) return; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
nativeVoiceMessage.type = messageType; |
|
|
|
|
|
|
|
nativeVoiceMessage.index = messageID; |
|
|
|
|
|
|
|
builtInVoiceMessage = _nativeVoiceMessageIntoEnum(nativeVoiceMessage); |
|
|
|
|
|
|
|
if (builtInVoiceMessage != BIVM_Unknown) { |
|
|
|
|
|
|
|
onVoiceMessageSignal.Emit(wrapper, builtInVoiceMessage); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
_.memory.Free(wrapper); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private final function TryConnectingBroadcastSignals() { |
|
|
|
|
|
|
|
if (connectedToBroadcastAPI) { |
|
|
|
if (connectedToBroadcastAPI) { |
|
|
|
return; |
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
@ -344,17 +53,76 @@ private final function TryConnectingBroadcastSignals() { |
|
|
|
_server.unreal.broadcasts.OnHandleTextFor(self).connect = HandleTextFor; |
|
|
|
_server.unreal.broadcasts.OnHandleTextFor(self).connect = HandleTextFor; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private function bool HandleText( |
|
|
|
/** |
|
|
|
Actor sender, |
|
|
|
* Signal that will be emitted when a player sends a message into the chat. |
|
|
|
out string message, |
|
|
|
* Allows to modify message before sending it, as well as prevent it from |
|
|
|
name messageType, |
|
|
|
* being sent at all. |
|
|
|
bool teamMessage |
|
|
|
* |
|
|
|
) { |
|
|
|
* Return `false` to prevent message from being sent. |
|
|
|
local bool result; |
|
|
|
* If `false` is returned, signal propagation to the remaining handlers will |
|
|
|
local MutableText messageAsText; |
|
|
|
* also be interrupted. |
|
|
|
local EPlayer senderPlayer; |
|
|
|
* |
|
|
|
|
|
|
|
* [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) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
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. |
|
|
|
|
|
|
|
* |
|
|
|
|
|
|
|
* [Signature] |
|
|
|
|
|
|
|
* bool <slot>(EPlayer receiver, EPlayer sender, BaseText 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) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
TryConnectingBroadcastSignals(); |
|
|
|
|
|
|
|
return ChatAPI_OnMessageFor_Slot(onMessageForSignal.NewSlot(receiver)); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// We only want to catch chat messages from a player |
|
|
|
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; |
|
|
|
if (messageType != 'Say' && messageType != 'TeamSay') return true; |
|
|
|
senderPlayer = _.players.FromController(PlayerController(sender)); |
|
|
|
senderPlayer = _.players.FromController(PlayerController(sender)); |
|
|
|
if (senderPlayer == none) return true; |
|
|
|
if (senderPlayer == none) return true; |
|
|
@ -377,39 +145,34 @@ private function bool HandleText( |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private function bool HandleTextFor( |
|
|
|
private function bool HandleTextFor( |
|
|
|
PlayerController receiver, |
|
|
|
PlayerController receiver, |
|
|
|
Actor sender, |
|
|
|
Actor sender, |
|
|
|
out string message, |
|
|
|
out string message, |
|
|
|
name messageType |
|
|
|
name messageType) |
|
|
|
) { |
|
|
|
{ |
|
|
|
local bool result; |
|
|
|
local bool result; |
|
|
|
local Text messageAsText; |
|
|
|
local Text messageAsText; |
|
|
|
local EPlayer senderPlayer, receiverPlayer; |
|
|
|
local EPlayer senderPlayer, receiverPlayer; |
|
|
|
|
|
|
|
// We only want to catch chat messages from another player |
|
|
|
// We only want to catch chat messages from another player |
|
|
|
|
|
|
|
if (messageType != 'Say' && messageType != 'TeamSay') return true; |
|
|
|
if (messageType != 'Say' && messageType != 'TeamSay') return true; |
|
|
|
senderPlayer = _.players.FromController(PlayerController(sender)); |
|
|
|
senderPlayer = _.players.FromController(PlayerController(sender)); |
|
|
|
if (senderPlayer == none) return true; |
|
|
|
if (senderPlayer == none) return true; |
|
|
|
|
|
|
|
|
|
|
|
receiverPlayer = _.players.FromController(receiver); |
|
|
|
receiverPlayer = _.players.FromController(receiver); |
|
|
|
if (receiverPlayer == none) { |
|
|
|
if (receiverPlayer == none) |
|
|
|
|
|
|
|
{ |
|
|
|
_.memory.Free(senderPlayer); |
|
|
|
_.memory.Free(senderPlayer); |
|
|
|
return true; |
|
|
|
return true; |
|
|
|
} |
|
|
|
} |
|
|
|
messageAsText = __().text.FromColoredString(message); |
|
|
|
messageAsText = __().text.FromColoredString(message); |
|
|
|
result = onMessageForSignal.Emit(receiverPlayer, senderPlayer, messageAsText); |
|
|
|
result = onMessageForSignal.Emit( receiverPlayer, senderPlayer, |
|
|
|
|
|
|
|
messageAsText); |
|
|
|
_.memory.Free(messageAsText); |
|
|
|
_.memory.Free(messageAsText); |
|
|
|
_.memory.Free(senderPlayer); |
|
|
|
_.memory.Free(senderPlayer); |
|
|
|
_.memory.Free(receiverPlayer); |
|
|
|
_.memory.Free(receiverPlayer); |
|
|
|
return result; |
|
|
|
return result; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
defaultproperties { |
|
|
|
defaultproperties |
|
|
|
VOICE_MESSAGES_BEFORE_ACKNOWLEDGEMENTS = 4 |
|
|
|
{ |
|
|
|
VOICE_MESSAGES_BEFORE_ALERTS = 8 |
|
|
|
|
|
|
|
VOICE_MESSAGES_BEFORE_DIRECTIONS = 14 |
|
|
|
|
|
|
|
VOICE_MESSAGES_BEFORE_INSULTS = 19 |
|
|
|
|
|
|
|
VOICE_MESSAGES_BEFORE_TRADER = 21 |
|
|
|
|
|
|
|
VOICE_MESSAGES_BEFORE_AUTO = 32 |
|
|
|
|
|
|
|
VOICE_MESSAGES_TOTAL = 57 |
|
|
|
|
|
|
|
} |
|
|
|
} |