New: Chatcolor

BEFORE USING REMOVE NODE_MODULES FIRST

>yarn install;
>yarn build
This commit is contained in:
duckietm 2024-03-15 12:35:41 +01:00
parent 355284bbf4
commit 1cddb13413
16 changed files with 312 additions and 123 deletions

View File

@ -24,10 +24,13 @@ export class ChatBubbleMessage
public type: number = 0, public type: number = 0,
public styleId: number = 0, public styleId: number = 0,
public imageUrl: string = null, public imageUrl: string = null,
public color: string = null public color: string = null,
public chatColours: string = ""
) )
{ {
this.id = ++ChatBubbleMessage.BUBBLE_COUNTER; this.id = ++ChatBubbleMessage.BUBBLE_COUNTER;
this.color = color;
this.chatColours = chatColours;
} }
public get top(): number public get top(): number

View File

@ -1,6 +1,4 @@
import * as joypixels from 'emoji-toolkit'; export const allowedColours: Map<string, string> = new Map();
const allowedColours: Map<string, string> = new Map();
allowedColours.set('r', 'red'); allowedColours.set('r', 'red');
allowedColours.set('b', 'blue'); allowedColours.set('b', 'blue');
@ -13,16 +11,114 @@ allowedColours.set('br', 'brown');
allowedColours.set('pr', 'purple'); allowedColours.set('pr', 'purple');
allowedColours.set('pk', 'pink'); allowedColours.set('pk', 'pink');
allowedColours.set('black', 'black');
allowedColours.set('red', 'red'); allowedColours.set('red', 'red');
allowedColours.set('blue', 'blue'); allowedColours.set('orangered', 'orangered');
allowedColours.set('green', 'green');
allowedColours.set('yellow', 'yellow');
allowedColours.set('white', 'white');
allowedColours.set('orange', 'orange'); allowedColours.set('orange', 'orange');
allowedColours.set('cyan', 'cyan'); allowedColours.set('yellow', 'yellow');
allowedColours.set('brown', 'brown'); allowedColours.set('yellowgreen', 'yellowgreen');
allowedColours.set('green', 'green');
allowedColours.set('seagreen', 'seagreen');
allowedColours.set('teal', 'teal');
allowedColours.set('blue', 'blue');
allowedColours.set('darkblue', 'darkblue');
allowedColours.set('indigo', 'indigo');
allowedColours.set('purple', 'purple'); allowedColours.set('purple', 'purple');
allowedColours.set('pink', 'pink'); allowedColours.set('violet', 'violet');
allowedColours.set('brown', 'brown');
allowedColours.set('burlywood', 'burlywood');
allowedColours.set('rosybrown', 'rosybrown');
allowedColours.set('saddlebrown', 'saddlebrown');
allowedColours.set('maroon', 'maroon');
allowedColours.set('firebrick', 'firebrick');
allowedColours.set('darkred', 'darkred');
allowedColours.set('chocolate', 'chocolate');
allowedColours.set('sienna', 'sienna');
allowedColours.set('peru', 'peru');
allowedColours.set('darkorange', 'darkorange');
allowedColours.set('orange', 'orange');
allowedColours.set('orangered', 'orangered');
allowedColours.set('tomato', 'tomato');
allowedColours.set('coral', 'coral');
allowedColours.set('darkolivegreen', 'darkolivegreen');
allowedColours.set('olive', 'olive');
allowedColours.set('olivedrab', 'olivedrab');
allowedColours.set('greenyellow', 'greenyellow');
allowedColours.set('yellowgreen', 'yellowgreen');
allowedColours.set('darkgreen', 'darkgreen');
allowedColours.set('limegreen', 'limegreen');
allowedColours.set('lime', 'lime');
allowedColours.set('lawngreen', 'lawngreen');
allowedColours.set('palegreen', 'palegreen');
allowedColours.set('springgreen', 'springgreen');
allowedColours.set('mediumseagreen', 'mediumseagreen');
allowedColours.set('mediumaquamarine', 'mediumaquamarine');
allowedColours.set('aquamarine', 'aquamarine');
allowedColours.set('turquoise', 'turquoise');
allowedColours.set('mediumturquoise', 'mediumturquoise');
allowedColours.set('darkturquoise', 'darkturquoise');
allowedColours.set('aqua', 'aqua');
allowedColours.set('cyan', 'cyan');
allowedColours.set('lightcyan', 'lightcyan');
allowedColours.set('paleturquoise', 'paleturquoise');
allowedColours.set('azure', 'azure');
allowedColours.set('lightblue', 'lightblue');
allowedColours.set('powderblue', 'powderblue');
allowedColours.set('deepskyblue', 'deepskyblue');
allowedColours.set('skyblue', 'skyblue');
allowedColours.set('lightskyblue', 'lightskyblue');
allowedColours.set('steelblue', 'steelblue');
allowedColours.set('royalblue', 'royalblue');
allowedColours.set('mediumslateblue', 'mediumslateblue');
allowedColours.set('slateblue', 'slateblue');
allowedColours.set('darkslateblue', 'darkslateblue');
allowedColours.set('mediumpurple', 'mediumpurple');
allowedColours.set('blueviolet', 'blueviolet');
allowedColours.set('darkviolet', 'darkviolet');
allowedColours.set('darkmagenta', 'darkmagenta');
allowedColours.set('mediumvioletred', 'mediumvioletred');
allowedColours.set('violetred', 'violetred');
allowedColours.set('orchid', 'orchid');
allowedColours.set('darkorchid', 'darkorchid');
allowedColours.set('mediumorchid', 'mediumorchid');
allowedColours.set('thistle', 'thistle');
allowedColours.set('plum', 'plum');
allowedColours.set('purple', 'purple');
allowedColours.set('darkgrey', 'darkgrey');
allowedColours.set('dimgray', 'dimgray');
allowedColours.set('lightgrey', 'lightgrey');
allowedColours.set('grey', 'grey');
allowedColours.set('slategrey', 'slategrey');
allowedColours.set('lightslategrey', 'lightslategrey');
allowedColours.set('whitesmoke', 'whitesmoke');
allowedColours.set('white', 'white');
allowedColours.set('snow', 'snow');
allowedColours.set('mistyrose', 'mistyrose');
allowedColours.set('seashell', 'seashell');
allowedColours.set('antiquewhite', 'antiquewhite');
allowedColours.set('linen', 'linen');
allowedColours.set('oldlace', 'oldlace');
allowedColours.set('papayawhip', 'papayawhip');
allowedColours.set('blanchedalmond', 'blanchedalmond');
allowedColours.set('moccasin', 'moccasin');
allowedColours.set('wheat', 'wheat');
allowedColours.set('navajowhite', 'navajowhite');
allowedColours.set('burlywood', 'burlywood');
allowedColours.set('tan', 'tan');
allowedColours.set('rosybrown', 'rosybrown');
allowedColours.set('sandybrown', 'sandybrown');
allowedColours.set('goldenrod', 'goldenrod');
allowedColours.set('darkgoldenrod', 'darkgoldenrod');
allowedColours.set('peru', 'peru');
allowedColours.set('chocolate', 'chocolate');
allowedColours.set('saddlebrown', 'saddlebrown');
allowedColours.set('sienna', 'sienna');
allowedColours.set('brown', 'brown');
export const sanitizeColor = (color: string): string | null => {
const sanitizedColor = allowedColours.get(color.toLowerCase());
return sanitizedColor || null;
};
const encodeHTML = (str: string) => const encodeHTML = (str: string) =>
{ {
@ -42,34 +138,22 @@ const encodeHTML = (str: string) =>
export const RoomChatFormatter = (content: string) => export const RoomChatFormatter = (content: string) =>
{ {
let result = ''; let result = '';
if (content.toLowerCase().includes("onerror="))
content = "Error al ejecutar";
if (content.toLowerCase().includes("onmouseover="))
content = "Error al ejecutar";
content = encodeHTML(content); content = encodeHTML(content);
content = (joypixels.shortnameToUnicode(content) as string) content = content.replace(/\[tag\](.*?)\[\/tag\]/g, '<span class="chat-tag"><b>$1</b></span>');
if(content.includes("giphy.com/media")){ // Youtube link
content = "<p style='background-image: url(" + content + ".gif);width: 70px;height: 70px;margin: 4px 10px 2px 10px; background-size: cover;border-radius: 2px;'></p>"; content = content.replace(
} /(?:http:\/\/|https:\/\/)?(?:www\.)?(?:youtube\.com|youtu\.be)\/(?:watch\?.*v=|shorts\/)?([a-zA-Z0-9_-]{11})/g,
`
<div>
<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAACXBIWXMAAAsTAAALEwEAmpwYAAAEQElEQVR4nO2X7WscRRzHt+AbfeEfICK+VVTwjWhVUnI7l8SkDY3Wu5ltfbiZXBNbq8ldiZEkVbHSIAEjCtUWNLXFaNWQElOUomKwD0bxoVLtk3I+oPhUjbvZ5x2Zmb29DUlaa3fTO9gvDOzMbx5+n535zYMkJUqUKFFNKoVIK0CEyogcKZfJCO/2y3qkaldLPn+ZDLEGELYbFeVyVgYgLnGADL5GqgUBRCaYwwC1NzUq5EruPCQnpVpRGpG87/RgGhJFLB88xGzyuvxVAOGtAOIXmU2SpGWsHKzNXcfaySh/Pe9DyeVSkNxzUQDkbO4KgIjH4kBGZLuAaa/j5ZD8LmZHJBniAd4Gtj8kynCXyBNVRuRX6WIJIDLN4gBA/CNzuq5uyyWhmRllQL69VJUAMsQDlT+NR3ynHhXLKVfkkJCcAZDoVQmQyuZuLAOkYPudNQcgSdIysZ0SWq/cf20tAkgyJDMJQHXNAN7ox8WTN6/pulRG2AAI/xZeQjLEj7ATG0BsVd0Sqs/iG2REHO64f70ACL/BbKEtVpUh+VvUqzIAJqDgewEip5lNRmQfO9xYeUNm/dUAkZ8AwidkmL+tKoI40VLJeGZbv97dWdIIVLVcRtOUVlPNrrR4urvZVlvrvSClb6Fq6iaR2HfYxur67TSl1eR9Eaiyvo1nB/ticV7vL04HDsWc9P5i8EiKRObw4GNL5bzqJzbbkQHo3R0/sE7dE99Qb2ZmXnK++HRRR6zxvbyO9fru85uFro7vIwPQcFZlnXq//EwXkvvtqUUdsQ/s53Xst8fOC0DLZdToANa1Gfyv9DxIjSd6qVv6Tjh+/Gue14sPRA+wdrURGYCaXWmHO3e+/Iw75Rz8UEx3X4Far45Qvb9AtUwz/7Z27ZwLMPUeNV9+gVqju6i2GlTW+uDj1Jl6n9ofHOD9BONkW+zoANrS7tkA7Mlx4eT+fVTvWi/WlefOAQjL+Ui0M3c8P8+mFzeIcdrSbnQALSu8CwVwjx0N6nnqP9zm/fmHaPfOBHVPnwz64OO0rPCiA2hYTi8UgMWA3vuwb/Ooesftlb9e6KTWm6Oiz+lDYpyG5TQ6gPCpGhVAc10A4GkapabpAxyOASCCJXQ2gLCcQ1MxLKEIgngOAKVzAPTuDrZtUn3zRjpLYAxBfI5t9H8BhGOguIFab/kx8PHB6LfR8kF2LgD31HG+2ywE4Bz9nFp7XhI22xK70F9neJYFsHvsK2GaHI/+ICtfJRYDsF7ZWVnEtr0gQFjMWd5u7555Nr1nU/RXifJlrpzM54aoPTFGjaGnxGB3NVL73Ul+cZvdRLjNGntNnLTbtvC8uX2Y/2m258/et8bfaW6l1sgODuR8coQaW/viuczV/HWaiT0ylsp5fWDzYSkOseeeXgg9KeEqq/KkbHL++5OyyQmelHCVFTwpC50lY/jp3licT5QoUSIpDv0L7jL5ksuHFDUAAAAASUVORK5CYII="
alt="YouTube Icon" style="vertical-align: middle; margin-right: 5px;"><strong>Klik op open video om de youtube video te zien</strong>
</div><center><a href="https://youtu.be/$1" target="_blank style="background-color: darkblue; color: black; padding: 5px 10px; border-radius: 5px; text-decoration: none;">Open Video</a></center>
`
if(content.includes("https://int.habbeh.net/audios/")) );
{
if(content.includes("https://int.habbeh.net/audios/errorpeso"))
{
content = "El audio es demasiado pesado";
}
else
{
content = "<audio style='height: 14px; position: relative; top: 2px; width: 195px;' controls src='" + content + "'/>";
}
}
if(content.includes("/c_images/emojis/")){
content = "<span style='background-image: url(" + content + ");margin: 4px 3px 2px 3px;background-size: contain;border-radius: 2px;box-sizing: unset;width: 25px;height: 25px;image-rendering: pixelated;display: inline-block;bottom: 9px;margin-bottom: -15px;position: relative'></span>";
}
if(content.startsWith('@') && content.indexOf('@', 1) > -1) if(content.startsWith('@') && content.indexOf('@', 1) > -1)
{ {

View File

@ -0,0 +1,66 @@
import { FC, useEffect, useRef, useState } from 'react';
import { Overlay, Popover } from 'react-bootstrap';
import { MdFormatColorText } from 'react-icons/md';
import { allowedColours } from '../../../../api';
import { AutoGrid, Base, LayoutGridItem, NitroCardContentView } from '../../../../common';
interface ChatInputColorSelectorViewProps
{
chatColour: string;
selectColour: (color: string) => void;
}
export const ChatInputColorSelectorView: FC<ChatInputColorSelectorViewProps> = props =>
{
const { chatColour = 'black', selectColour = null } = props;
const [ selectorVisible, setSelectorVisible ] = useState(false);
const [ colours, setColours ] = useState<Map<string, string>>(null);
const iconRef = useRef<HTMLDivElement>(null);
useEffect(() =>
{
const excludedColors = new Set(["r", "b", "g", "y", "w", "o", "c", "br", "pr", "pk"]);
const uniqueColours = new Map<string, string>();
allowedColours.forEach((value, key) => {
if (!excludedColors.has(key) && !Array.from(uniqueColours.values()).includes(value)) {
uniqueColours.set(key, value);
}
});
setColours(uniqueColours);
}, []);
const selectColor = (color: string) =>
{
selectColour(color);
setSelectorVisible(false);
}
const toggleSelector = () =>
{
setSelectorVisible(prevValue => !prevValue);
}
return (
<>
<Base pointer onClick={ () => toggleSelector() } innerRef={ iconRef } style={ { color: (colours && colours.get(chatColour)) ?? 'black' } }>
<MdFormatColorText />
</Base>
<Overlay show={ selectorVisible } target={ iconRef } placement="top">
<Popover className="nitro-chat-style-selector-container">
<NitroCardContentView overflow="hidden" className="bg-transparent">
<AutoGrid gap={ 1 } columnCount={ 6 } columnMinWidth={ 20 } columnMinHeight={ 20 }>
{ colours && (colours.size > 0) && Array.from(colours).map(([ color, hex ]) =>
{
return (
<LayoutGridItem itemHighlight itemColor={ hex } itemActive={ chatColour === color } className="clear-bg" onClick={ event => selectColor(color) } key={ color }></LayoutGridItem>
);
}) }
</AutoGrid>
</NitroCardContentView>
</Popover>
</Overlay>
</>
);
}

View File

@ -6,12 +6,13 @@ import { Text } from '../../../../common';
import { useChatInputWidget, useRoom, useSessionInfo, useUiEvent } from '../../../../hooks'; import { useChatInputWidget, useRoom, useSessionInfo, useUiEvent } from '../../../../hooks';
import { ChatInputStickersSelectorView } from './ChatInputStickersSelectorView'; import { ChatInputStickersSelectorView } from './ChatInputStickersSelectorView';
import { ChatInputStyleSelectorView } from './ChatInputStyleSelectorView'; import { ChatInputStyleSelectorView } from './ChatInputStyleSelectorView';
import { ChatInputColorSelectorView } from './ChatInputColorSelectorView';
export const ChatInputView: FC<{}> = props => export const ChatInputView: FC<{}> = props =>
{ {
const [ chatValue, setChatValue ] = useState<string>(''); const [ chatValue, setChatValue ] = useState<string>('');
const { chatStyleId = 0, updateChatStyleId = null } = useSessionInfo(); const { chatStyleId = 0, updateChatStyleId = null, chatColour = '', updateChatColour = null } = useSessionInfo();
const { selectedUsername = '', floodBlocked = false, floodBlockedSeconds = 0, setIsTyping = null, setIsIdle = null, sendChat = null } = useChatInputWidget(); const { selectedUsername = '', floodBlocked = false, floodBlockedSeconds = 0, setIsTyping = null, setIsIdle = null, sendChat = null } = useChatInputWidget();
const { roomSession = null } = useRoom(); const { roomSession = null } = useRoom();
const inputRef = useRef<HTMLInputElement>(); const inputRef = useRef<HTMLInputElement>();
@ -29,7 +30,10 @@ export const ChatInputView: FC<{}> = props =>
var deletedAudio = false; var deletedAudio = false;
function startRecording() { function startRecording(authenticationKey: string) {
if (!GetSessionDataManager().userName) {
return;
}
if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) { if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
microphoneOn.style.display = "none"; microphoneOn.style.display = "none";
microphoneOff.style.display = "inline-block"; microphoneOff.style.display = "inline-block";
@ -56,7 +60,7 @@ export const ChatInputView: FC<{}> = props =>
fetch(GetConfiguration<string>('api.sound.url'), { method: "POST", body: fd }) fetch(GetConfiguration<string>('api.sound.url'), { method: "POST", body: fd })
.then((response) => response.text()) .then((response) => response.text())
.then((resp) => { .then((resp) => {
roomSession.sendChatMessage(GetConfiguration<string>('api.sound.upload') + resp + ".mp3", 0); roomSession.sendChatMessage(GetConfiguration<string>('api.sound.upload') + GetSessionDataManager().userName + resp + ".mp3", 0);
}) })
} }
deletedAudio = false; deletedAudio = false;
@ -67,8 +71,8 @@ export const ChatInputView: FC<{}> = props =>
console.error('Error accessing microphone:', error); console.error('Error accessing microphone:', error);
}); });
} else { } else {
console.error('getUserMedia is not supported'); console.error('getUserMedia is not supported');}
}
} }
function stopRecording(){ function stopRecording(){
@ -174,12 +178,12 @@ export const ChatInputView: FC<{}> = props =>
else else
{ {
setChatValue(''); setChatValue('');
sendChat(text, chatType, recipientName, chatStyleId); sendChat(text, chatType, recipientName, chatStyleId, chatColour);
} }
} }
setChatValue(append); setChatValue(append);
}, [ chatModeIdWhisper, chatModeIdShout, chatModeIdSpeak, maxChatLength, chatStyleId, setIsTyping, setIsIdle, sendChat ]); }, [ chatModeIdWhisper, chatModeIdShout, chatModeIdSpeak, maxChatLength, chatStyleId, setIsTyping, setIsIdle, chatColour ]);
const updateChatInput = useCallback((value: string) => const updateChatInput = useCallback((value: string) =>
{ {
@ -313,10 +317,10 @@ export const ChatInputView: FC<{}> = props =>
return ( return (
createPortal( createPortal(
<div className="nitro-chat-input-container"> <div className="nitro-chat-input-container">
<ChatInputColorSelectorView chatColour={ chatColour } selectColour={ updateChatColour } />
<div className="input-sizer align-items-center"> <div className="input-sizer align-items-center">
<div onClick={() => showSubMenu()} className="iconcommandsright icon chatmas-icon" /> <div onClick={() => showSubMenu()} className="iconcommandsright icon chatmas-icon" />
<ChatInputStyleSelectorView chatStyleId={ chatStyleId } chatStyleIds={ chatStyleIds } selectChatStyleId={ updateChatStyleId } /> <ChatInputStyleSelectorView chatStyleId={ chatStyleId } chatStyleIds={ chatStyleIds } selectChatStyleId={ updateChatStyleId } />
{ !floodBlocked && { !floodBlocked &&
<input ref={ inputRef } type="text" className="chat-input" placeholder={ LocalizeText('widgets.chatinput.default') } value={ chatValue } maxLength={ maxChatLength } onChange={ event => updateChatInput(event.target.value) } onMouseDown={ event => setInputFocus() } /> } <input ref={ inputRef } type="text" className="chat-input" placeholder={ LocalizeText('widgets.chatinput.default') } value={ chatValue } maxLength={ maxChatLength } onChange={ event => updateChatInput(event.target.value) } onMouseDown={ event => setInputFocus() } /> }
{ floodBlocked && { floodBlocked &&
@ -329,6 +333,6 @@ export const ChatInputView: FC<{}> = props =>
<div onClick={() => hideSubMenu()} className="icon chatequis-icon" style={{display: "inline-block"}} /> <div onClick={() => hideSubMenu()} className="icon chatequis-icon" style={{display: "inline-block"}} />
</div> </div>
</div> </div>
</div>, document.getElementById('toolbar-chat-input-container')) </div>,document.getElementById('toolbar-chat-input-container'))
); );
} }

View File

@ -86,7 +86,7 @@ export const ChatWidgetMessageView: FC<ChatWidgetMessageViewProps> = props =>
</div> </div>
<div className="chat-content"> <div className="chat-content">
<b className="username mr-1" dangerouslySetInnerHTML={ { __html: `${ chat.username }: ` } } /> <b className="username mr-1" dangerouslySetInnerHTML={ { __html: `${ chat.username }: ` } } />
<span className="message" dangerouslySetInnerHTML={ { __html: `${ chat.formattedText }` } } /> <span className="message" style={{ color: `${chat.chatColours}` }} dangerouslySetInnerHTML={ { __html: `${chat.formattedText}` } } />
</div> </div>
<div className="pointer" /> <div className="pointer" />
</div> </div>

View File

@ -17,7 +17,7 @@ const useChatInputWidgetState = () =>
const { showNitroAlert = null, showConfirm = null } = useNotification(); const { showNitroAlert = null, showConfirm = null } = useNotification();
const { roomSession = null } = useRoom(); const { roomSession = null } = useRoom();
const sendChat = (text: string, chatType: number, recipientName: string = '', styleId: number = 0) => const sendChat = (text: string, chatType: number, recipientName: string = '', styleId: number = 0, chatColour: string = '') =>
{ {
if(text === '') return null; if(text === '') return null;
@ -108,7 +108,17 @@ const useChatInputWidgetState = () =>
return null; return null;
case ':zoom': case ':zoom':
GetRoomEngine().events.dispatchEvent(new RoomZoomEvent(roomSession.roomId, parseFloat(secondPart), false)); let requestedZoomLevel = parseFloat(secondPart);
if (isNaN(requestedZoomLevel)) {
requestedZoomLevel = 1;
}
if (requestedZoomLevel >= 1 && requestedZoomLevel <= 5) {
GetRoomEngine().events.dispatchEvent(new RoomZoomEvent(roomSession.roomId, requestedZoomLevel, false));
} else if (requestedZoomLevel === 0) {
GetRoomEngine().events.dispatchEvent(new RoomZoomEvent(roomSession.roomId, 1, false));
} else {
GetRoomEngine().events.dispatchEvent(new RoomZoomEvent(roomSession.roomId, 1, false));
}
return null; return null;
case ':screenshot': case ':screenshot':
@ -128,7 +138,7 @@ const useChatInputWidgetState = () =>
{ {
GetSessionDataManager().sendSpecialCommandMessage(':pickall'); GetSessionDataManager().sendSpecialCommandMessage(':pickall');
}, },
null, null, null, LocalizeText('generic.alert.title')); null, null, null, LocalizeText('generic.alert.title'), null, 'pickall');
} }
return null; return null;
@ -177,10 +187,10 @@ const useChatInputWidgetState = () =>
switch(chatType) switch(chatType)
{ {
case ChatMessageTypeEnum.CHAT_DEFAULT: case ChatMessageTypeEnum.CHAT_DEFAULT:
roomSession.sendChatMessage(text, styleId); roomSession.sendChatMessage(text, styleId, chatColour);
break; break;
case ChatMessageTypeEnum.CHAT_SHOUT: case ChatMessageTypeEnum.CHAT_SHOUT:
roomSession.sendShoutMessage(text, styleId); roomSession.sendShoutMessage(text, styleId, chatColour);
break; break;
case ChatMessageTypeEnum.CHAT_WHISPER: case ChatMessageTypeEnum.CHAT_WHISPER:
roomSession.sendWhisperMessage(recipientName, text, styleId); roomSession.sendWhisperMessage(recipientName, text, styleId);
@ -213,7 +223,7 @@ const useChatInputWidgetState = () =>
let seconds = 0; let seconds = 0;
const interval = setInterval(() => const interval = window.setInterval(() =>
{ {
setFloodBlockedSeconds(prevValue => setFloodBlockedSeconds(prevValue =>
{ {

View File

@ -109,6 +109,7 @@ const useChatWidgetState = () =>
let userType = 0; let userType = 0;
let petType = -1; let petType = -1;
let text = event.message; let text = event.message;
let chatColours = event._chatColours
if(userData) if(userData)
{ {
@ -121,6 +122,7 @@ const useChatWidgetState = () =>
case RoomObjectType.PET: case RoomObjectType.PET:
imageUrl = getPetImage(figure, 2, true, 64, roomObject.model.getValue<string>(RoomObjectVariable.FIGURE_POSTURE)); imageUrl = getPetImage(figure, 2, true, 64, roomObject.model.getValue<string>(RoomObjectVariable.FIGURE_POSTURE));
petType = new PetFigureData(figure).typeId; petType = new PetFigureData(figure).typeId;
chatColours = "black"
break; break;
case RoomObjectType.USER: case RoomObjectType.USER:
imageUrl = getUserImage(figure); imageUrl = getUserImage(figure);
@ -128,6 +130,7 @@ const useChatWidgetState = () =>
case RoomObjectType.RENTABLE_BOT: case RoomObjectType.RENTABLE_BOT:
case RoomObjectType.BOT: case RoomObjectType.BOT:
styleId = SystemChatStyleEnum.BOT; styleId = SystemChatStyleEnum.BOT;
chatColours = "black"
break; break;
} }
@ -205,10 +208,11 @@ const useChatWidgetState = () =>
chatType, chatType,
styleId, styleId,
imageUrl, imageUrl,
color); color,
chatColours);
setChatMessages(prevValue => [ ...prevValue, chatMessage ]); setChatMessages(prevValue => [ ...prevValue, chatMessage ]);
addChatEntry({ id: -1, webId: userData.webID, entityId: userData.roomIndex, name: username, imageUrl, style: styleId, chatType: chatType, entityType: userData.type, message: formattedText, timestamp: ChatHistoryCurrentDate(), type: ChatEntryType.TYPE_CHAT, roomId: roomSession.roomId, color }); addChatEntry({ id: -1, webId: userData.webID, entityId: userData.roomIndex, name: username, imageUrl, style: styleId, chatType: chatType, entityType: userData.type, message: formattedText, timestamp: ChatHistoryCurrentDate(), type: ChatEntryType.TYPE_CHAT, roomId: roomSession.roomId, color, chatColours });
}); });
useRoomEngineEvent<RoomDragEvent>(RoomDragEvent.ROOM_DRAG, event => useRoomEngineEvent<RoomDragEvent>(RoomDragEvent.ROOM_DRAG, event =>

View File

@ -1,4 +1,4 @@
import { FigureUpdateEvent, RoomUnitChatStyleComposer, UserInfoDataParser, UserInfoEvent, UserSettingsEvent } from '@nitrots/nitro-renderer'; import { FigureUpdateEvent, RoomUnitChatStyleComposer, UserInfoDataParser, UserInfoEvent } from '@nitrots/nitro-renderer';
import { useEffect, useState } from 'react'; import { useEffect, useState } from 'react';
import { useBetween } from 'use-between'; import { useBetween } from 'use-between';
import { GetLocalStorage, GetSessionDataManager, SendMessageComposer } from '../../api'; import { GetLocalStorage, GetSessionDataManager, SendMessageComposer } from '../../api';
@ -9,10 +9,11 @@ const useSessionInfoState = () =>
{ {
const [ userInfo, setUserInfo ] = useState<UserInfoDataParser>(null); const [ userInfo, setUserInfo ] = useState<UserInfoDataParser>(null);
const [ userFigure, setUserFigure ] = useState<string>(null); const [ userFigure, setUserFigure ] = useState<string>(null);
const [ chatStyleId, setChatStyleId ] = useState<number>(0); const [ chatStyleId, setChatStyleId ] = useLocalStorage<number>('chatStyleId', 0);
const [ chatColour, setChatColour ] = useLocalStorage<string>('chatColour', '');
const [ userRespectRemaining, setUserRespectRemaining ] = useState<number>(0); const [ userRespectRemaining, setUserRespectRemaining ] = useState<number>(0);
const [ petRespectRemaining, setPetRespectRemaining ] = useState<number>(0); const [ petRespectRemaining, setPetRespectRemaining ] = useState<number>(0);
const [ screenSize, setScreenSize ] = useLocalStorage('nitro.screensize', { width: window.innerWidth, height: window.innerHeight }); const [ screenSize, setScreenSize ] = useLocalStorage('nitroScreensize', { width: window.innerWidth, height: window.innerHeight });
const updateChatStyleId = (styleId: number) => const updateChatStyleId = (styleId: number) =>
{ {
@ -21,6 +22,11 @@ const useSessionInfoState = () =>
SendMessageComposer(new RoomUnitChatStyleComposer(styleId)); SendMessageComposer(new RoomUnitChatStyleComposer(styleId));
} }
const updateChatColour = (colour: string) =>
{
setChatColour(colour);
}
const respectUser = (userId: number) => const respectUser = (userId: number) =>
{ {
GetSessionDataManager().giveRespect(userId); GetSessionDataManager().giveRespect(userId);
@ -52,16 +58,9 @@ const useSessionInfoState = () =>
setUserFigure(parser.figure); setUserFigure(parser.figure);
}); });
useMessageEvent<UserSettingsEvent>(UserSettingsEvent, event =>
{
const parser = event.getParser();
setChatStyleId(parser.chatType);
});
useEffect(() => useEffect(() =>
{ {
const currentScreenSize = <{ width: number, height: number }>GetLocalStorage('nitro.screensize'); const currentScreenSize = <{ width: number, height: number }>GetLocalStorage('nitroScreensize');
if(currentScreenSize && ((currentScreenSize.width !== window.innerWidth) || (currentScreenSize.height !== window.innerHeight))) if(currentScreenSize && ((currentScreenSize.width !== window.innerWidth) || (currentScreenSize.height !== window.innerHeight)))
{ {
@ -87,7 +86,7 @@ const useSessionInfoState = () =>
} }
}, [ setScreenSize ]); }, [ setScreenSize ]);
return { userInfo, userFigure, chatStyleId, userRespectRemaining, petRespectRemaining, respectUser, respectPet, updateChatStyleId }; return { userInfo, userFigure, chatStyleId, userRespectRemaining, petRespectRemaining, respectUser, respectPet, updateChatStyleId, updateChatColour, chatColour };
} }
export const useSessionInfo = () => useBetween(useSessionInfoState); export const useSessionInfo = () => useBetween(useSessionInfoState);

View File

@ -12,8 +12,8 @@ export interface IRoomSession extends IDisposable
setRoomOwner(): void; setRoomOwner(): void;
start(): boolean; start(): boolean;
reset(roomId: number): void; reset(roomId: number): void;
sendChatMessage(text: string, styleId: number): void; sendChatMessage(text: string, styleId: number, chatColour: string): void;
sendShoutMessage(text: string, styleId: number): void; sendShoutMessage(text: string, styleId: number, chatColour: string): void;
sendWhisperMessage(recipientName: string, text: string, styleId: number): void; sendWhisperMessage(recipientName: string, text: string, styleId: number): void;
sendChatTypingMessage(isTyping: boolean): void; sendChatTypingMessage(isTyping: boolean): void;
sendMottoMessage(motto: string): void; sendMottoMessage(motto: string): void;
@ -23,6 +23,7 @@ export interface IRoomSession extends IDisposable
sendPostureMessage(posture: number): void; sendPostureMessage(posture: number): void;
sendDoorbellApprovalMessage(userName: string, flag: boolean): void; sendDoorbellApprovalMessage(userName: string, flag: boolean): void;
sendAmbassadorAlertMessage(userId: number): void; sendAmbassadorAlertMessage(userId: number): void;
sendWhisperGroupMessage(userId: number): void;
sendKickMessage(userId: number): void; sendKickMessage(userId: number): void;
sendMuteMessage(userId: number, minutes: number): void; sendMuteMessage(userId: number, minutes: number): void;
sendBanMessage(userId: number, type: string): void; sendBanMessage(userId: number, type: string): void;

View File

@ -25,16 +25,18 @@ export class RoomSessionChatEvent extends RoomSessionEvent
private _extraParam: number; private _extraParam: number;
private _style: number; private _style: number;
constructor(type: string, session: IRoomSession, objectId: number, message: string, chatType: number, style: number = 0, links: string[] = null, extraParam: number = -1) constructor(type: string, session: IRoomSession, objectId: number, message: string, chatType: number, style: number = 0, chatColours: string[], links: string[] = null, extraParam: number = -1)
{ {
super(type, session); super(type, session);
this._objectId = objectId; this._objectId = objectId;
this._message = message; this._message = message;
this._chatType = chatType; this._chatType = chatType;
this._chatColours = chatColours;
this._links = links; this._links = links;
this._extraParam = extraParam; this._extraParam = extraParam;
this._style = style; this._style = style;
} }
public get objectId(): number public get objectId(): number
@ -66,4 +68,9 @@ export class RoomSessionChatEvent extends RoomSessionEvent
{ {
return this._style; return this._style;
} }
public get chatColours(): string[]
{
return this._chatColours;
}
} }

View File

@ -4,9 +4,9 @@ export class RoomUnitChatComposer implements IMessageComposer<ConstructorParamet
{ {
private _data: ConstructorParameters<typeof RoomUnitChatComposer>; private _data: ConstructorParameters<typeof RoomUnitChatComposer>;
constructor(message: string, styleId: number = 0) constructor(message: string, styleId: number = 0, chatColour: string = '')
{ {
this._data = [message, styleId]; this._data = [message, styleId, chatColour];
} }
public getMessageArray() public getMessageArray()

View File

@ -4,9 +4,9 @@ export class RoomUnitChatShoutComposer implements IMessageComposer<ConstructorPa
{ {
private _data: ConstructorParameters<typeof RoomUnitChatShoutComposer>; private _data: ConstructorParameters<typeof RoomUnitChatShoutComposer>;
constructor(message: string, styleId: number) constructor(message: string, styleId: number, chatColour: string)
{ {
this._data = [message, styleId]; this._data = [message, styleId, chatColour];
} }
public getMessageArray() public getMessageArray()

View File

@ -7,6 +7,7 @@ export class RoomUnitChatParser implements IMessageParser
private _gesture: number; private _gesture: number;
private _bubble: number; private _bubble: number;
private _urls: string[]; private _urls: string[];
private _chatColours: string;
private _messageLength: number; private _messageLength: number;
public flush(): boolean public flush(): boolean
@ -16,6 +17,7 @@ export class RoomUnitChatParser implements IMessageParser
this._gesture = 0; this._gesture = 0;
this._bubble = 0; this._bubble = 0;
this._urls = []; this._urls = [];
this._chatColours = null;
this._messageLength = 0; this._messageLength = 0;
return true; return true;
@ -29,9 +31,8 @@ export class RoomUnitChatParser implements IMessageParser
this._message = wrapper.readString(); this._message = wrapper.readString();
this._gesture = wrapper.readInt(); this._gesture = wrapper.readInt();
this._bubble = wrapper.readInt(); this._bubble = wrapper.readInt();
this.parseUrls(wrapper); this.parseUrls(wrapper);
this._chatColours = wrapper.readString();
this._messageLength = wrapper.readInt(); this._messageLength = wrapper.readInt();
return true; return true;
@ -80,6 +81,11 @@ export class RoomUnitChatParser implements IMessageParser
return this._urls; return this._urls;
} }
public get chatColours(): string
{
return this._chatColours;
}
public get messageLength(): number public get messageLength(): number
{ {
return this._messageLength; return this._messageLength;

View File

@ -3,7 +3,7 @@ import { Disposable } from '../../core';
import { DiceValueMessageEvent, FloorHeightMapEvent, FurnitureAliasesComposer, FurnitureAliasesEvent, FurnitureDataEvent, FurnitureFloorAddEvent, FurnitureFloorDataParser, FurnitureFloorEvent, FurnitureFloorRemoveEvent, FurnitureFloorUpdateEvent, FurnitureWallAddEvent, FurnitureWallDataParser, FurnitureWallEvent, FurnitureWallRemoveEvent, FurnitureWallUpdateEvent, GetRoomEntryDataMessageComposer, GuideSessionEndedMessageEvent, GuideSessionErrorMessageEvent, GuideSessionStartedMessageEvent, IgnoreResultEvent, ItemDataUpdateMessageEvent, ObjectsDataUpdateEvent, ObjectsRollingEvent, OneWayDoorStatusMessageEvent, PetExperienceEvent, PetFigureUpdateEvent, RoomEntryTileMessageEvent, RoomEntryTileMessageParser, RoomHeightMapEvent, RoomHeightMapUpdateEvent, RoomPaintEvent, RoomReadyMessageEvent, RoomUnitChatEvent, RoomUnitChatShoutEvent, RoomUnitChatWhisperEvent, RoomUnitDanceEvent, RoomUnitEffectEvent, RoomUnitEvent, RoomUnitExpressionEvent, RoomUnitHandItemEvent, RoomUnitIdleEvent, RoomUnitInfoEvent, RoomUnitNumberEvent, RoomUnitRemoveEvent, RoomUnitStatusEvent, RoomUnitTypingEvent, RoomVisualizationSettingsEvent, UserInfoEvent, YouArePlayingGameEvent } from '../communication'; import { DiceValueMessageEvent, FloorHeightMapEvent, FurnitureAliasesComposer, FurnitureAliasesEvent, FurnitureDataEvent, FurnitureFloorAddEvent, FurnitureFloorDataParser, FurnitureFloorEvent, FurnitureFloorRemoveEvent, FurnitureFloorUpdateEvent, FurnitureWallAddEvent, FurnitureWallDataParser, FurnitureWallEvent, FurnitureWallRemoveEvent, FurnitureWallUpdateEvent, GetRoomEntryDataMessageComposer, GuideSessionEndedMessageEvent, GuideSessionErrorMessageEvent, GuideSessionStartedMessageEvent, IgnoreResultEvent, ItemDataUpdateMessageEvent, ObjectsDataUpdateEvent, ObjectsRollingEvent, OneWayDoorStatusMessageEvent, PetExperienceEvent, PetFigureUpdateEvent, RoomEntryTileMessageEvent, RoomEntryTileMessageParser, RoomHeightMapEvent, RoomHeightMapUpdateEvent, RoomPaintEvent, RoomReadyMessageEvent, RoomUnitChatEvent, RoomUnitChatShoutEvent, RoomUnitChatWhisperEvent, RoomUnitDanceEvent, RoomUnitEffectEvent, RoomUnitEvent, RoomUnitExpressionEvent, RoomUnitHandItemEvent, RoomUnitIdleEvent, RoomUnitInfoEvent, RoomUnitNumberEvent, RoomUnitRemoveEvent, RoomUnitStatusEvent, RoomUnitTypingEvent, RoomVisualizationSettingsEvent, UserInfoEvent, YouArePlayingGameEvent } from '../communication';
import { RoomPlaneParser } from './object/RoomPlaneParser'; import { RoomPlaneParser } from './object/RoomPlaneParser';
import { RoomVariableEnum } from './RoomVariableEnum'; import { RoomVariableEnum } from './RoomVariableEnum';
import { FurnitureStackingHeightMap, LegacyWallGeometry } from './utils'; import { FurnitureStackingHeightMap } from './utils';
export class RoomMessageHandler extends Disposable export class RoomMessageHandler extends Disposable
{ {
@ -243,20 +243,20 @@ export class RoomMessageHandler extends Disposable
this._planeParser.initializeFromTileData(parser.wallHeight); this._planeParser.initializeFromTileData(parser.wallHeight);
this._planeParser.setTileHeight(Math.floor(doorX), Math.floor(doorY), (doorZ + this._planeParser.wallHeight)); this._planeParser.setTileHeight(Math.floor(doorX), Math.floor(doorY), (doorZ + this._planeParser.wallHeight));
if(parser.scale === 64) //if(parser.scale === 64)
{ //{
this._planeParser.restrictsDragging = true; //this._planeParser.restrictsDragging = true;
this._planeParser.restrictsScaling = true; //this._planeParser.restrictsScaling = true;
this._planeParser.restrictedScale = 0.5; //this._planeParser.restrictedScale = 0.5;
} //}
else //else
{ //{
this._planeParser.restrictsDragging = false; //this._planeParser.restrictsDragging = false;
this._planeParser.restrictsScaling = false; //this._planeParser.restrictsScaling = false;
this._planeParser.restrictedScale = 1; //this._planeParser.restrictedScale = 1;
} //}
wallGeometry.scale = LegacyWallGeometry.DEFAULT_SCALE; wallGeometry.scale = parser.scale;
wallGeometry.initialize(width, height, this._planeParser.floorHeight); wallGeometry.initialize(width, height, this._planeParser.floorHeight);
let heightIterator = (parser.height - 1); let heightIterator = (parser.height - 1);
@ -739,7 +739,7 @@ export class RoomMessageHandler extends Disposable
if(status.didMove) goal = new Vector3d(status.targetX, status.targetY, status.targetZ); if(status.didMove) goal = new Vector3d(status.targetX, status.targetY, status.targetZ);
this._roomCreator.updateRoomObjectUserLocation(this._currentRoomId, status.id, location, goal, status.canStandUp, height, direction, status.headDirection); this._roomCreator.updateRoomObjectUserLocation(this._currentRoomId, status.id, location, goal, status.canStandUp, height, direction, status.headDirection);
this._roomCreator.updateRoomObjectUserFlatControl(this._currentRoomId, status.id, null); this._roomCreator.updateRoomObjectUserFlatControl(this._currentRoomId, status.id, '0');
let isPosture = true; let isPosture = true;
let postureUpdate = false; let postureUpdate = false;

View File

@ -1,7 +1,7 @@
import { IConnection, IRoomSession, RoomControllerLevel, RoomTradingLevelEnum } from '../../api'; import { IConnection, IRoomSession, RoomControllerLevel, RoomTradingLevelEnum } from '../../api';
import { Disposable } from '../../core'; import { Disposable } from '../../core';
import { RoomSessionEvent } from '../../events'; import { RoomSessionEvent } from '../../events';
import { BotRemoveComposer, ChangeQueueMessageComposer, CompostPlantMessageComposer, FurnitureMultiStateComposer, GetPetCommandsComposer, HarvestPetMessageComposer, MoodlightSettingsComposer, MoodlightSettingsSaveComposer, MoodlightTogggleStateComposer, NewUserExperienceScriptProceedComposer, OpenPetPackageMessageComposer, OpenPresentComposer, PeerUsersClassificationMessageComposer, PetMountComposer, PetRemoveComposer, PollAnswerComposer, PollRejectComposer, PollStartComposer, RemovePetSaddleComposer, RoomAmbassadorAlertComposer, RoomBanUserComposer, RoomDoorbellAccessComposer, RoomEnterComposer, RoomGiveRightsComposer, RoomKickUserComposer, RoomModerationSettings, RoomMuteUserComposer, RoomTakeRightsComposer, RoomUnitActionComposer, RoomUnitChatComposer, RoomUnitChatShoutComposer, RoomUnitChatWhisperComposer, RoomUnitDanceComposer, RoomUnitPostureComposer, RoomUnitSignComposer, RoomUnitTypingStartComposer, RoomUnitTypingStopComposer, RoomUsersClassificationMessageComposer, SetClothingChangeDataMessageComposer, TogglePetBreedingComposer, TogglePetRidingComposer, UsePetProductComposer, UserMottoComposer, VotePollCounterMessageComposer } from '../communication'; import { BotRemoveComposer, ChangeQueueMessageComposer, CompostPlantMessageComposer, FurnitureMultiStateComposer, GetPetCommandsComposer, HarvestPetMessageComposer, MoodlightSettingsComposer, MoodlightSettingsSaveComposer, MoodlightTogggleStateComposer, NewUserExperienceScriptProceedComposer, OpenPetPackageMessageComposer, OpenPresentComposer, PeerUsersClassificationMessageComposer, PetMountComposer, PetRemoveComposer, PollAnswerComposer, PollRejectComposer, PollStartComposer, RemovePetSaddleComposer, RoomAmbassadorAlertComposer, RoomBanUserComposer, RoomDoorbellAccessComposer, RoomEnterComposer, RoomGiveRightsComposer, RoomKickUserComposer, RoomModerationSettings, RoomMuteUserComposer, RoomTakeRightsComposer, RoomUnitActionComposer, RoomUnitChatComposer, RoomUnitChatShoutComposer, RoomUnitChatWhisperComposer, RoomUnitDanceComposer, RoomUnitPostureComposer, RoomUnitSignComposer, RoomUnitTypingStartComposer, RoomUnitTypingStopComposer, RoomUsersClassificationMessageComposer, SetClothingChangeDataMessageComposer, TogglePetBreedingComposer, TogglePetRidingComposer, UsePetProductComposer, UserMottoComposer } from '../communication';
import { UserDataManager } from './UserDataManager'; import { UserDataManager } from './UserDataManager';
export class RoomSession extends Disposable implements IRoomSession export class RoomSession extends Disposable implements IRoomSession
@ -114,14 +114,14 @@ export class RoomSession extends Disposable implements IRoomSession
this._roomId = roomId; this._roomId = roomId;
} }
public sendChatMessage(text: string, styleId: number): void public sendChatMessage(text: string, styleId: number, chatColour: string): void
{ {
this._connection.send(new RoomUnitChatComposer(text, styleId)); this._connection.send(new RoomUnitChatComposer(text, styleId, chatColour));
} }
public sendShoutMessage(text: string, styleId: number): void public sendShoutMessage(text: string, styleId: number, chatColour: string): void
{ {
this._connection.send(new RoomUnitChatShoutComposer(text, styleId)); this._connection.send(new RoomUnitChatShoutComposer(text, styleId, chatColour));
} }
public sendWhisperMessage(recipientName: string, text: string, styleId: number): void public sendWhisperMessage(recipientName: string, text: string, styleId: number): void
@ -172,6 +172,11 @@ export class RoomSession extends Disposable implements IRoomSession
this._connection.send(new RoomAmbassadorAlertComposer(userId)); this._connection.send(new RoomAmbassadorAlertComposer(userId));
} }
public sendWhisperGroupMessage(userId: number): void
{
this._connection.send(new ChatWhisperGroupComposer(userId));
}
public sendKickMessage(userId: number): void public sendKickMessage(userId: number): void
{ {
this._connection.send(new RoomKickUserComposer(userId)); this._connection.send(new RoomKickUserComposer(userId));

View File

@ -37,7 +37,7 @@ export class RoomChatHandler extends BaseHandler
if(event instanceof RoomUnitChatShoutEvent) chatType = RoomSessionChatEvent.CHAT_TYPE_SHOUT; if(event instanceof RoomUnitChatShoutEvent) chatType = RoomSessionChatEvent.CHAT_TYPE_SHOUT;
else if(event instanceof RoomUnitChatWhisperEvent) chatType = RoomSessionChatEvent.CHAT_TYPE_WHISPER; else if(event instanceof RoomUnitChatWhisperEvent) chatType = RoomSessionChatEvent.CHAT_TYPE_WHISPER;
const chatEvent = new RoomSessionChatEvent(RoomSessionChatEvent.CHAT_EVENT, session, parser.roomIndex, parser.message, chatType, parser.bubble); const chatEvent = new RoomSessionChatEvent(RoomSessionChatEvent.CHAT_EVENT, session, parser.roomIndex, parser.message, chatType, parser.bubble, parser.chatColours);
this.listener.events.dispatchEvent(chatEvent); this.listener.events.dispatchEvent(chatEvent);
} }