mirror of
https://gitgud.io/BondageProjects/Bondage-College.git
synced 2025-04-14 12:29:15 +00:00
Merge branch 'feature/message-replies' into 'master'
Added the ability to reply to whispers, actions and chat messages See merge request BondageProjects/Bondage-College!5486
This commit is contained in:
commit
31123d58e3
9 changed files with 323 additions and 49 deletions
BondageClub
CSS
Screens/Online/ChatRoom
Scripts
|
@ -342,3 +342,7 @@ select:invalid:not(:disabled):not(:read-only) {
|
|||
scrollbar-color: rgb(149, 149, 149) rgb(0, 0, 0, 0.7);
|
||||
}
|
||||
}
|
||||
|
||||
.hidden {
|
||||
display: none;
|
||||
}
|
|
@ -98,7 +98,25 @@
|
|||
border-left: min(0.2vh, 0.1vw) inset black;
|
||||
justify-self: center;
|
||||
}
|
||||
|
||||
#chat-room-reply-indicator-text {
|
||||
color: var(--base-font-color);
|
||||
text-overflow: ellipsis;
|
||||
text-wrap: nowrap;
|
||||
overflow: hidden;
|
||||
flex: 1;
|
||||
line-height: 1.6em;
|
||||
border: min(0.2vh, 0.1vw) solid black;
|
||||
border-right: none;
|
||||
user-select: none
|
||||
}
|
||||
#chat-room-reply-indicator:not(.hidden) {
|
||||
background-color: var(--base-color, #eee);
|
||||
position: absolute;
|
||||
transform: translateY(-105%);
|
||||
width: 100%;
|
||||
display: flex;
|
||||
height: 1.6em;
|
||||
}
|
||||
#InputChat {
|
||||
grid-area: chat-input;
|
||||
min-height: var(--button-size);
|
||||
|
@ -110,7 +128,15 @@
|
|||
border: unset;
|
||||
outline: unset;
|
||||
}
|
||||
|
||||
#chat-room-reply-indicator-close::before {
|
||||
content: "❌";
|
||||
}
|
||||
#chat-room-reply-indicator-close {
|
||||
background-color: var(--base-color, #eee);
|
||||
border: min(0.2vh, 0.1vw) solid black;
|
||||
cursor: pointer;
|
||||
aspect-ratio: 1;
|
||||
}
|
||||
#InputChat:focus {
|
||||
scrollbar-width: auto;
|
||||
}
|
||||
|
@ -237,7 +263,18 @@
|
|||
|
||||
background-color: var(--base-color);
|
||||
}
|
||||
|
||||
.chat-room-message-reply::before {
|
||||
content: "↱";
|
||||
position: relative;
|
||||
top: 4px
|
||||
}
|
||||
.chat-room-message-reply {
|
||||
display: block;
|
||||
color: gray;
|
||||
width: 100%;
|
||||
font-size: 0.75em;
|
||||
text-align: left;
|
||||
}
|
||||
.ChatMessageName {
|
||||
text-shadow: 0.05em 0.05em black;
|
||||
color: var(--label-color);
|
||||
|
@ -272,11 +309,15 @@
|
|||
#TextAreaChatLog[data-colortheme="dark2"] {
|
||||
background-color: #111;
|
||||
color: #eee;
|
||||
--base-color: #111;
|
||||
--base-font-color: #eee;
|
||||
}
|
||||
|
||||
#TextAreaChatLog[data-colortheme="dark"]~#chat-room-bot,
|
||||
#TextAreaChatLog[data-colortheme="dark2"]~#chat-room-bot {
|
||||
--button-color: #eee;
|
||||
--base-color: #111;
|
||||
--base-font-color: #eee;
|
||||
background-color: #111;
|
||||
border-color: rgba(0, 0, 0, 0.25);
|
||||
color: #eee;
|
||||
|
@ -284,6 +325,7 @@
|
|||
|
||||
#TextAreaChatLog[data-colortheme="dark"]~#chat-room-buttons-div,
|
||||
#TextAreaChatLog[data-colortheme="dark2"]~#chat-room-buttons-div {
|
||||
|
||||
border-left: min(0.2vh, 0.1vw) inset rgba(0, 0, 0, 0.25);
|
||||
}
|
||||
|
||||
|
|
|
@ -1124,6 +1124,19 @@ function ChatRoomCreateElement() {
|
|||
tag: "div",
|
||||
attributes: { id: "chat-room-bot" },
|
||||
children: [
|
||||
{
|
||||
tag: "div",
|
||||
attributes: {id: "chat-room-reply-indicator"},
|
||||
classList: ["hidden"],
|
||||
children: [
|
||||
{ tag: "span", attributes: { id: "chat-room-reply-indicator-text" }, children: [TextGet("ChatRoomReply")] },
|
||||
ElementButton.Create(
|
||||
"chat-room-reply-indicator-close",
|
||||
ChatRoomMessageReplyStop,
|
||||
{ noStyling: true },
|
||||
),
|
||||
],
|
||||
},
|
||||
{
|
||||
tag: "textarea",
|
||||
attributes: {
|
||||
|
@ -1135,7 +1148,7 @@ function ChatRoomCreateElement() {
|
|||
},
|
||||
eventListeners: {
|
||||
input: ChatRoomChatInputChangeHandler,
|
||||
keyup: ChatRoomStatusUpdateTalk,
|
||||
keyup: (key) => {ChatRoomStatusUpdateTalk(key); ChatRoomStopReplyOnEscape(key);},
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -1972,6 +1985,15 @@ let ChatRoomStatusDeadKeys = [
|
|||
"ArrowLeft", "ArrowRight", "ArrowUp", "ArrowDown",
|
||||
];
|
||||
|
||||
/**
|
||||
* Stops the reply when the escape key is pressed
|
||||
* @param {KeyboardEvent} key
|
||||
*/
|
||||
function ChatRoomStopReplyOnEscape(key) {
|
||||
if (key.key == "Escape") {
|
||||
ChatRoomMessageReplyStop();
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Sends the "Talk" status to other players if the player typed in the text box and there's a value in it
|
||||
* @param {KeyboardEvent} Key
|
||||
|
@ -3066,40 +3088,45 @@ function ChatRoomSendChat() {
|
|||
* This function automatically formats and sends the message with all the information
|
||||
* needed to reconstruct it on the receiver.
|
||||
*
|
||||
* @param {"Chat"|"Whisper"} type
|
||||
* @param {"Chat"|"Whisper"|"Emote"} type
|
||||
* @param {string} msg
|
||||
* @param {string} [replyId]
|
||||
* @return {ServerChatRoomMessage}
|
||||
*/
|
||||
function ChatRoomGenerateChatRoomChatMessage(type, msg) {
|
||||
// Ensure the last OOC content range is closed with a )
|
||||
const lastRange = SpeechGetOOCRanges(msg).pop();
|
||||
if (
|
||||
Player.ChatSettings.OOCAutoClose
|
||||
&& lastRange !== undefined
|
||||
&& msg.charAt(lastRange.start + lastRange.length - 1) !== ")"
|
||||
&& lastRange.start + lastRange.length === msg.length
|
||||
&& lastRange.length !== 1) {
|
||||
msg += ")";
|
||||
function ChatRoomGenerateChatRoomChatMessage(type, msg, replyId) {
|
||||
/** @type {ChatMessageDictionary} */
|
||||
const Dictionary = [];
|
||||
if (type === "Chat" || type === "Whisper") {
|
||||
// Ensure the last OOC content range is closed with a )
|
||||
const lastRange = SpeechGetOOCRanges(msg).pop();
|
||||
if (
|
||||
Player.ChatSettings.OOCAutoClose
|
||||
&& lastRange !== undefined
|
||||
&& msg.charAt(lastRange.start + lastRange.length - 1) !== ")"
|
||||
&& lastRange.start + lastRange.length === msg.length
|
||||
&& lastRange.length !== 1) {
|
||||
msg += ")";
|
||||
}
|
||||
|
||||
// Chat messages are always garbled, unless the no speech restriction is lifted
|
||||
let process = {
|
||||
effects: [],
|
||||
text: msg,
|
||||
};
|
||||
|
||||
process = SpeechTransformProcess(Player, msg, SpeechTransformSenderEffects);
|
||||
|
||||
// We always garble, but if "no speech garbling" is enabled,
|
||||
// we also send down the ungarbled message if it's different
|
||||
const originalMsg = Player.RestrictionSettings.NoSpeechGarble && msg !== process.text ? msg : undefined;
|
||||
Dictionary.push({ Effects: process.effects, Original: originalMsg });
|
||||
}
|
||||
|
||||
// Chat messages are always garbled, unless the no speech restriction is lifted
|
||||
let process = {
|
||||
effects: [],
|
||||
text: msg,
|
||||
};
|
||||
|
||||
process = SpeechTransformProcess(Player, msg, SpeechTransformSenderEffects);
|
||||
|
||||
// We always garble, but if "no speech garbling" is enabled,
|
||||
// we also send down the ungarbled message if it's different
|
||||
const originalMsg = Player.RestrictionSettings.NoSpeechGarble && msg !== process.text ? msg : undefined;
|
||||
|
||||
/** @type {ChatMessageDictionary} */
|
||||
let Dictionary = [
|
||||
{ Effects: process.effects, Original: originalMsg },
|
||||
];
|
||||
|
||||
return { Content: process.text, Type: type, Dictionary };
|
||||
if (replyId) {
|
||||
Dictionary.push({ ReplyId: replyId, Tag: "ReplyId" });
|
||||
ChatRoomMessageReplyStop();
|
||||
}
|
||||
return { Content: msg, Type: type, Dictionary };
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -3111,8 +3138,8 @@ function ChatRoomSendChatMessage(msg) {
|
|||
// Regular chat can be prevented with an owner presence rule, also validates for forbidden words
|
||||
if (ChatRoomOwnerPresenceRule("BlockTalk", null)) return false;
|
||||
if (!ChatRoomOwnerForbiddenWordCheck(msg)) return false;
|
||||
|
||||
const data = ChatRoomGenerateChatRoomChatMessage("Chat", msg);
|
||||
const replyId = ChatRoomMessageGetReplyId();
|
||||
const data = ChatRoomGenerateChatRoomChatMessage("Chat", msg, replyId);
|
||||
ServerSend("ChatRoomChat", data);
|
||||
|
||||
ChatRoomStimulationMessage("Talk");
|
||||
|
@ -3133,7 +3160,8 @@ function ChatRoomSendWhisper(targetNumber, msg) {
|
|||
return "target-out-of-range";
|
||||
}
|
||||
|
||||
const data = ChatRoomGenerateChatRoomChatMessage("Whisper", msg);
|
||||
const replyId = ChatRoomMessageGetReplyId();
|
||||
const data = ChatRoomGenerateChatRoomChatMessage("Whisper", msg, replyId);
|
||||
data.Target = targetNumber;
|
||||
ServerSend("ChatRoomChat", data);
|
||||
|
||||
|
@ -3176,7 +3204,10 @@ function ChatRoomSendEmote(msg) {
|
|||
if (msg.startsWith(CommandsKey + "action ")) msg = msg.replace(CommandsKey + "action ", "*");
|
||||
}
|
||||
msg = msg.trim();
|
||||
if (msg != "" && msg != "*") ServerSend("ChatRoomChat", { Content: msg, Type: "Emote" });
|
||||
if (msg == "" || msg == "*") return;
|
||||
const replyId = ChatRoomMessageGetReplyId();
|
||||
const data = ChatRoomGenerateChatRoomChatMessage("Emote", msg, replyId);
|
||||
ServerSend("ChatRoomChat", data);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -3205,8 +3236,9 @@ function ChatRoomSendAttemptEmote(msg) {
|
|||
msg += attemptSucceeded ? ": ✔" : ": ❌";
|
||||
msg += " (" + chance + "%)";
|
||||
|
||||
ServerSend("ChatRoomChat", { Content: msg, Type: "Emote" });
|
||||
|
||||
const replyId = ChatRoomMessageGetReplyId();
|
||||
const data = ChatRoomGenerateChatRoomChatMessage("Emote", msg, replyId);
|
||||
ServerSend("ChatRoomChat", data);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -3940,6 +3972,10 @@ function ChatRoomMessageDefaultMetadataExtractor(data, SenderCharacter) {
|
|||
text = text.toLowerCase();
|
||||
}
|
||||
substitutions.push([entry.Tag, text]);
|
||||
} else if (IsMsgIdDictionaryEntry(entry)) {
|
||||
meta.MsgId = entry.MsgId;
|
||||
} else if (IsReplyIdDictionaryEntry(entry)) {
|
||||
meta.ReplyId = entry.ReplyId;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4254,6 +4290,127 @@ function ChatRoomMessageNameClick() {
|
|||
chatInput.value = `/whisper ${memberNumber} ${chatInput.value.replace(/\/whisper\s*\d+ ?/u, "")}`;
|
||||
chatInput.focus();
|
||||
}
|
||||
// ----- Replies
|
||||
/**
|
||||
* Returns the HTML element for the message with the given ID
|
||||
* @param {string} id
|
||||
* @returns {HTMLElement | null}
|
||||
*/
|
||||
function ChatRoomMessageGetById(id) {
|
||||
const chatLog = document.getElementById("TextAreaChatLog");
|
||||
if (!chatLog) return null;
|
||||
return chatLog.querySelector(`[msgid="${id}"]`)?.parentElement;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the ID of the message that this message is a reply to
|
||||
* @returns {string | null}
|
||||
*/
|
||||
function ChatRoomMessageGetReplyId() {
|
||||
const chatInput = /** @type {null | HTMLTextAreaElement} */(document.getElementById("InputChat"));
|
||||
if (!chatInput) return;
|
||||
return chatInput.getAttribute("reply-id");
|
||||
}
|
||||
/**
|
||||
* Returns the name of the character that this message is a reply to.
|
||||
* We get the wrong name when replying to reply that's what this is for.
|
||||
* @param {string} msgId
|
||||
* @param {boolean} isWhisper
|
||||
* @returns {string | null}
|
||||
*/
|
||||
function ChatRoomMessageGetReplyName(msgId, isWhisper=false) {
|
||||
const message = ChatRoomMessageGetById(msgId);
|
||||
if (message) {
|
||||
if (isWhisper) {
|
||||
const sender = Number(message.getAttribute("data-sender"));
|
||||
return CharacterNickname(ChatRoomCharacter.find(C => C.MemberNumber === sender));
|
||||
}
|
||||
const names = message.querySelectorAll(".ChatMessageName");
|
||||
const name = names[names.length - 1];
|
||||
return name?.textContent;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
/**
|
||||
* @param {string} msgId
|
||||
* @returns {string | null}
|
||||
*/
|
||||
function ChatRoomMessageGetReplyContent(msgId) {
|
||||
const message = ChatRoomMessageGetById(msgId);
|
||||
if (message) {
|
||||
const contents = message.querySelectorAll(".chat-room-message-content");
|
||||
const content = contents[contents.length - 1];
|
||||
return content.textContent;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Figures out the type of the message with the given ID
|
||||
* @param {string} msgId
|
||||
* @returns {"Chat" | "Whisper"}
|
||||
*/
|
||||
function ChatRoomMessageGetType(msgId) {
|
||||
if (!msgId) return "Chat";
|
||||
if (ChatRoomMessageGetById(msgId)?.classList?.contains("ChatMessageWhisper")) return "Whisper";
|
||||
return "Chat";
|
||||
}
|
||||
/**
|
||||
* Closes the reply.
|
||||
*/
|
||||
function ChatRoomMessageReplyStop() {
|
||||
const chatInput = /** @type {null | HTMLTextAreaElement} */(document.getElementById("InputChat"));
|
||||
const replyIndicator = document.getElementById("chat-room-reply-indicator");
|
||||
chatInput.removeAttribute("reply-id");
|
||||
replyIndicator.classList.add("hidden");
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the reply to the message with the given ID
|
||||
* @param {string} msgId
|
||||
*/
|
||||
function ChatRoomMessageSetReply(msgId) {
|
||||
const chatInput = /** @type {null | HTMLTextAreaElement} */(document.getElementById("InputChat"));
|
||||
chatInput.setAttribute("reply-id", msgId);
|
||||
const replyMessage = ChatRoomMessageGetById(msgId);
|
||||
const type = ChatRoomMessageGetType(msgId);
|
||||
const isWhisper = type === "Whisper";
|
||||
if (isWhisper) {
|
||||
const receiver = Number(replyMessage.getAttribute("data-sender")) === Player.MemberNumber ? Number(replyMessage.getAttribute("data-target")) : Number(replyMessage.getAttribute("data-sender"));
|
||||
chatInput.value = `/whisper ${receiver} ${chatInput.value.replace(/\/whisper\s*\d+ ?/u, "")}`;
|
||||
}
|
||||
const replyIndicator = document.getElementById("chat-room-reply-indicator");
|
||||
const replyIndicatorText = document.getElementById("chat-room-reply-indicator-text");
|
||||
const replyName = ChatRoomMessageGetReplyName(msgId, isWhisper);
|
||||
replyIndicatorText.textContent = `${TextGet("ChatRoomReply")}: ${replyName && `${replyName}` || "a message"}`;
|
||||
replyIndicator.classList.remove("hidden");
|
||||
chatInput.focus();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the HTML element for a reply message
|
||||
* @param {string} msgId
|
||||
* @param {string} displayMessage
|
||||
* @returns {HTMLSpanElement | string}
|
||||
*/
|
||||
function ChatRoomMessageCreateReplyMessageElement(msgId, displayMessage) {
|
||||
if (!msgId) {
|
||||
return displayMessage;
|
||||
}
|
||||
return ElementCreate({
|
||||
tag: "span",
|
||||
classList: ["chat-room-message-content"],
|
||||
attributes: { "tabindex": -1, "msgid": msgId },
|
||||
children: [displayMessage],
|
||||
eventListeners: {
|
||||
click: (e) => {
|
||||
ChatRoomMessageSetReply(msgId);
|
||||
e.stopPropagation();
|
||||
},
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the Chat log with the recieved message
|
||||
|
@ -4274,9 +4431,27 @@ function ChatRoomMessageDisplay(data, msg, SenderCharacter, metadata) {
|
|||
const divChildren = [];
|
||||
/** @type {undefined | string} */
|
||||
let innerHTML = undefined;
|
||||
let reply = undefined;
|
||||
if (metadata.ReplyId) {
|
||||
const replyMessage = ChatRoomMessageGetById(metadata.ReplyId);
|
||||
const type = ChatRoomMessageGetType(metadata.ReplyId);
|
||||
const isWhisper = type === "Whisper";
|
||||
reply = ElementButton.Create(
|
||||
null, () => {if (replyMessage) replyMessage.scrollIntoView();}, { noStyling: true },
|
||||
{
|
||||
button: {
|
||||
classList: ["chat-room-message-reply", "truncated-text"],
|
||||
attributes: { "tabindex": -1 },
|
||||
style: { "--label-color": SenderCharacter.LabelColor },
|
||||
children: replyMessage ? [ChatRoomMessageGetReplyName(metadata.ReplyId, isWhisper), ": ", ChatRoomMessageGetReplyContent(metadata.ReplyId)] : [TextGet("ChatRoomNoMessageFound")],
|
||||
},
|
||||
},
|
||||
);
|
||||
}
|
||||
switch (data.Type) {
|
||||
case "Chat":
|
||||
divChildren.push(
|
||||
reply,
|
||||
ElementButton.Create(
|
||||
null, ChatRoomMessageNameClick, { noStyling: true },
|
||||
{
|
||||
|
@ -4289,12 +4464,13 @@ function ChatRoomMessageDisplay(data, msg, SenderCharacter, metadata) {
|
|||
},
|
||||
),
|
||||
": ",
|
||||
displayMessage,
|
||||
ChatRoomMessageCreateReplyMessageElement(metadata.MsgId,displayMessage)
|
||||
);
|
||||
break;
|
||||
case "Whisper": {
|
||||
const whisperTarget = SenderCharacter.IsPlayer() ? ChatRoomCharacter.find(c => c.MemberNumber == data.Target) : SenderCharacter;
|
||||
divChildren.push(
|
||||
reply,
|
||||
ElementButton.Create(
|
||||
null, ChatRoomMessageNameClick, { noStyling: true },
|
||||
{ button: { classList: ["ReplyButton"], children: ["\u21a9\ufe0f"] } },
|
||||
|
@ -4313,7 +4489,7 @@ function ChatRoomMessageDisplay(data, msg, SenderCharacter, metadata) {
|
|||
},
|
||||
),
|
||||
": ",
|
||||
displayMessage,
|
||||
ChatRoomMessageCreateReplyMessageElement(metadata.MsgId,displayMessage)
|
||||
);
|
||||
|
||||
if (!whisperTarget.IsPlayer()) {
|
||||
|
@ -4327,7 +4503,7 @@ function ChatRoomMessageDisplay(data, msg, SenderCharacter, metadata) {
|
|||
|
||||
case "Action":
|
||||
case "Activity":
|
||||
divChildren.push(`(${displayMessage})`);
|
||||
divChildren.push(reply,ChatRoomMessageCreateReplyMessageElement(metadata.MsgId,`(${displayMessage})`));
|
||||
break;
|
||||
|
||||
case "ServerMessage":
|
||||
|
@ -4340,7 +4516,7 @@ function ChatRoomMessageDisplay(data, msg, SenderCharacter, metadata) {
|
|||
break;
|
||||
|
||||
case "Emote":
|
||||
divChildren.push(`*${displayMessage}*`);
|
||||
divChildren.push(reply,ChatRoomMessageCreateReplyMessageElement(metadata.MsgId,`*${displayMessage}*`));
|
||||
break;
|
||||
|
||||
default:
|
||||
|
|
|
@ -34,6 +34,8 @@ ChatRoomStruggleLoosening,Loosening...
|
|||
ChatRoomStruggleImpossible,Impossible!
|
||||
ChatRoomStruggleLoosen,Loosen
|
||||
ChatRoomStruggleGiveUp,Give up
|
||||
ChatRoomReply,Replying to
|
||||
ChatRoomNoMessageFound,Message could not be found.
|
||||
CommandHelp,<strong>Help: KeyWord</strong>
|
||||
CommandNoSuchCommand,command: no such command
|
||||
CommandPrerequisiteFailed,command: prerequisite check failed
|
||||
|
|
|
|
@ -604,6 +604,13 @@ function CommonStringShuffle(string) {
|
|||
return parts.join('');
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a unique ID
|
||||
* @returns {string}
|
||||
*/
|
||||
function CommonGenerateUniqueID() {
|
||||
return Math.random().toString(36).substring(2);
|
||||
}
|
||||
/**
|
||||
* Converts an array to a string separated by commas (equivalent of .join(","))
|
||||
* @param {readonly any[]} Arr - Array to convert to a joined string
|
||||
|
|
|
@ -439,3 +439,19 @@ function IsMessageEffectDictionaryEntry(entry) {
|
|||
&& !!entry.Effects && CommonIsArray(entry.Effects)
|
||||
&& (!entry.Original || typeof entry.Original === "string");
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ChatMessageDictionaryEntry} entry
|
||||
* @returns {entry is ReplyIdDictionaryEntry}
|
||||
*/
|
||||
function IsReplyIdDictionaryEntry(entry) {
|
||||
return CommonIsObject(entry) && typeof entry.ReplyId === "string";
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ChatMessageDictionaryEntry} entry
|
||||
* @returns {entry is MsgIdDictionaryEntry}
|
||||
*/
|
||||
function IsMsgIdDictionaryEntry(entry) {
|
||||
return CommonIsObject(entry) && typeof entry.MsgId === "string";
|
||||
}
|
||||
|
|
19
BondageClub/Scripts/Messages.d.ts
vendored
19
BondageClub/Scripts/Messages.d.ts
vendored
|
@ -750,6 +750,20 @@ interface ActivityNameDictionaryEntry {
|
|||
ActivityName: ActivityName;
|
||||
}
|
||||
|
||||
/**
|
||||
* A dictionary entry indicating the ID of a message being replied to.
|
||||
*/
|
||||
interface ReplyIdDictionaryEntry {
|
||||
ReplyId: string;
|
||||
Tag: "ReplyId";
|
||||
}
|
||||
/**
|
||||
* A dictionary entry indicating the ID of a message.
|
||||
*/
|
||||
interface MsgIdDictionaryEntry {
|
||||
MsgId: string;
|
||||
Tag: "MsgId";
|
||||
}
|
||||
/**
|
||||
* A dictionary entry with metadata about the chat message transmitted.
|
||||
*
|
||||
|
@ -777,7 +791,10 @@ type ChatMessageDictionaryEntry =
|
|||
| ActivityCounterDictionaryEntry
|
||||
| AssetGroupNameDictionaryEntry
|
||||
| ActivityNameDictionaryEntry
|
||||
| MessageEffectEntry;
|
||||
| MessageEffectEntry
|
||||
| MsgIdDictionaryEntry
|
||||
| ReplyIdDictionaryEntry ;
|
||||
|
||||
|
||||
type ChatMessageDictionary = ChatMessageDictionaryEntry[];
|
||||
|
||||
|
|
|
@ -285,8 +285,6 @@ var ServerSendRateLimitInterval = 1200;
|
|||
/**
|
||||
* Queued messages waiting to be sent
|
||||
*
|
||||
* @typedef {{ Message: ClientEvent, args: ClientEventParams<ClientEvent>}} SendRateLimitQueueItem
|
||||
*
|
||||
* @type {SendRateLimitQueueItem[]}
|
||||
*/
|
||||
const ServerSendRateLimitQueue = [];
|
||||
|
@ -302,8 +300,8 @@ let ServerSendRateLimitTimes = [];
|
|||
*/
|
||||
function ServerSend(Message, ...args) {
|
||||
if (!ServerIsLoggedIn() && !["AccountCreate", "AccountLogin", "PasswordReset", "PasswordResetProcess"].includes(Message)) return; // We're not logged in
|
||||
|
||||
ServerSendRateLimitQueue.push({ Message, args });
|
||||
const queueItem = /** @type {SendRateLimitQueueItem} */({ Message, args });
|
||||
ServerSendRateLimitQueue.push(queueItem);
|
||||
|
||||
// Pump the queue manually to fight back against background tab throttling
|
||||
ServerSendQueueProcess();
|
||||
|
@ -323,6 +321,11 @@ function ServerSendQueueProcess() {
|
|||
) {
|
||||
const item = ServerSendRateLimitQueue.shift();
|
||||
if (item) {
|
||||
if (item.Message === "ChatRoomChat") {
|
||||
const [data] = item.args;
|
||||
data[0].Dictionary = data[0].Dictionary ?? [];
|
||||
data[0].Dictionary.push({ Tag: "MsgId", MsgId: CommonGenerateUniqueID() });
|
||||
}
|
||||
ServerSocket.emit(item.Message, ...item.args);
|
||||
ServerSendRateLimitTimes.push(Date.now());
|
||||
}
|
||||
|
|
9
BondageClub/Scripts/Typedef.d.ts
vendored
9
BondageClub/Scripts/Typedef.d.ts
vendored
|
@ -8,7 +8,8 @@ declare function io(serv: string): SocketIO.Socket;
|
|||
|
||||
type ClientEvent = import("@socket.io/component-emitter").EventNames<ClientToServerEvents>;
|
||||
type ClientEventParams<Ev extends ClientEvent> = import("@socket.io/component-emitter").EventParams<ClientToServerEvents, Ev>;
|
||||
|
||||
type _SendRateLimitQueueItem<T extends ClientEvent> = T extends ClientEvent ? { Message: T, args: ClientEventParams<T>} : never;
|
||||
type SendRateLimitQueueItem = _SendRateLimitQueueItem<ClientEvent>;
|
||||
interface String {
|
||||
replaceAt(index: number, character: string): string;
|
||||
}
|
||||
|
@ -810,6 +811,12 @@ interface IChatRoomMessageMetadata {
|
|||
ChatRoomName?: string;
|
||||
/** The original, ungarbled message, if provided by the sender */
|
||||
OriginalMsg?: string;
|
||||
/** The ID of the message being replied to */
|
||||
ReplyId?: string;
|
||||
/** The ID of the message */
|
||||
MsgId?: string;
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
Loading…
Add table
Reference in a new issue