diff --git a/src/api/avatar/AvatarEditorGridPartItem.ts b/src/api/avatar/AvatarEditorGridPartItem.ts index a3b16616..740d93f5 100644 --- a/src/api/avatar/AvatarEditorGridPartItem.ts +++ b/src/api/avatar/AvatarEditorGridPartItem.ts @@ -189,7 +189,7 @@ export class AvatarEditorGridPartItem implements IAvatarImageListener return container; } - private updateThumbVisualization(): void + private async updateThumbVisualization(): Promise { if(!this._isInitalized) return; @@ -212,7 +212,7 @@ export class AvatarEditorGridPartItem implements IAvatarImageListener if(this._isDisabled) this.setAlpha(container, 0.2); - this._imageUrl = TextureUtils.generateImageUrl(container); + this._imageUrl = await TextureUtils.generateImageUrl(container); if(this.notify) this.notify(); } diff --git a/src/api/room/widgets/AvatarInfoFurni.ts b/src/api/room/widgets/AvatarInfoFurni.ts index 3380282a..47743e97 100644 --- a/src/api/room/widgets/AvatarInfoFurni.ts +++ b/src/api/room/widgets/AvatarInfoFurni.ts @@ -9,7 +9,6 @@ export class AvatarInfoFurni implements IAvatarInfo public category: number = 0; public name: string = ''; public description: string = ''; - public image: HTMLImageElement = null; public isWallItem: boolean = false; public isStickie: boolean = false; public isRoomOwner: boolean = false; diff --git a/src/api/room/widgets/AvatarInfoUtilities.ts b/src/api/room/widgets/AvatarInfoUtilities.ts index 7c489448..a084aca9 100644 --- a/src/api/room/widgets/AvatarInfoUtilities.ts +++ b/src/api/room/widgets/AvatarInfoUtilities.ts @@ -1,4 +1,4 @@ -import { GetTickerTime, IFurnitureData, IRoomModerationSettings, IRoomPetData, IRoomUserData, ObjectDataFactory, PetFigureData, PetType, RoomControllerLevel, RoomModerationSettings, RoomObjectCategory, RoomObjectType, RoomObjectVariable, RoomTradingLevelEnum, RoomWidgetEnumItemExtradataParameter, Vector3d } from '@nitrots/nitro-renderer'; +import { GetTickerTime, IFurnitureData, IRoomModerationSettings, IRoomPetData, IRoomUserData, ObjectDataFactory, PetFigureData, PetType, RoomControllerLevel, RoomModerationSettings, RoomObjectCategory, RoomObjectType, RoomObjectVariable, RoomTradingLevelEnum, RoomWidgetEnumItemExtradataParameter } from '@nitrots/nitro-renderer'; import { GetRoomEngine, GetRoomSession, GetSessionDataManager, IsOwnerOfFurniture } from '../../nitro'; import { LocalizeText } from '../../utils'; import { AvatarInfoFurni } from './AvatarInfoFurni'; @@ -72,24 +72,20 @@ export class AvatarInfoUtilities public static getFurniInfo(objectId: number, category: number): AvatarInfoFurni { const roomSession = GetRoomSession(); + const roomObject = GetRoomEngine().getRoomObject(roomSession.roomId, objectId, category); + + if(!roomObject) return null; + const furniInfo = new AvatarInfoFurni(AvatarInfoFurni.FURNI); furniInfo.id = objectId; furniInfo.category = category; - const roomObject = GetRoomEngine().getRoomObject(roomSession.roomId, objectId, category); - - if(!roomObject) return; - const model = roomObject.model; - if(model.getValue(RoomWidgetEnumItemExtradataParameter.INFOSTAND_EXTRA_PARAM)) - { - furniInfo.extraParam = model.getValue(RoomWidgetEnumItemExtradataParameter.INFOSTAND_EXTRA_PARAM); - } + if(model.getValue(RoomWidgetEnumItemExtradataParameter.INFOSTAND_EXTRA_PARAM)) furniInfo.extraParam = model.getValue(RoomWidgetEnumItemExtradataParameter.INFOSTAND_EXTRA_PARAM); - const dataFormat = model.getValue(RoomObjectVariable.FURNITURE_DATA_FORMAT); - const objectData = ObjectDataFactory.getData(dataFormat); + const objectData = ObjectDataFactory.getData(model.getValue(RoomObjectVariable.FURNITURE_DATA_FORMAT)); objectData.initializeFromRoomObjectModel(model); @@ -141,14 +137,14 @@ export class AvatarInfoUtilities furniInfo.expiration = ((expiryTime < 0) ? expiryTime : Math.max(0, (expiryTime - ((GetTickerTime() - expiryTimestamp) / 1000)))); - let roomObjectImage = GetRoomEngine().getRoomObjectImage(roomSession.roomId, objectId, category, new Vector3d(180), 64, null); + /* let roomObjectImage = GetRoomEngine().getRoomObjectImage(roomSession.roomId, objectId, category, new Vector3d(180), 64, null); if(!roomObjectImage.data || (roomObjectImage.data.width > 140) || (roomObjectImage.data.height > 200)) { roomObjectImage = GetRoomEngine().getRoomObjectImage(roomSession.roomId, objectId, category, new Vector3d(180), 1, null); } - furniInfo.image = roomObjectImage.getImage(); + furniInfo.image = roomObjectImage.getImage(); */ furniInfo.isWallItem = (category === RoomObjectCategory.WALL); furniInfo.isRoomOwner = roomSession.isRoomOwner; furniInfo.roomControllerLevel = roomSession.controllerLevel; @@ -159,11 +155,7 @@ export class AvatarInfoUtilities const guildId = model.getValue(RoomObjectVariable.FURNITURE_GUILD_CUSTOMIZED_GUILD_ID); - if(guildId !== 0) - { - furniInfo.groupId = guildId; - //this.container.connection.send(new GroupInformationComposer(guildId, false)); - } + if(guildId !== 0) furniInfo.groupId = guildId; if(IsOwnerOfFurniture(roomObject)) furniInfo.isOwner = true; @@ -174,11 +166,7 @@ export class AvatarInfoUtilities { const roomSession = GetRoomSession(); - let userInfoType = AvatarInfoUser.OWN_USER; - - if(userData.webID !== GetSessionDataManager().userId) userInfoType = AvatarInfoUser.PEER; - - const userInfo = new AvatarInfoUser(userInfoType); + const userInfo = new AvatarInfoUser((userData.webID === GetSessionDataManager().userId) ? AvatarInfoUser.OWN_USER : AvatarInfoUser.PEER); userInfo.isSpectatorMode = roomSession.isSpectator; userInfo.name = userData.name; @@ -192,7 +180,7 @@ export class AvatarInfoUtilities if(roomObject) userInfo.carryItem = (roomObject.model.getValue(RoomObjectVariable.FIGURE_CARRY_OBJECT) || 0); - if(userInfoType === AvatarInfoUser.OWN_USER) userInfo.allowNameChange = GetSessionDataManager().canChangeName; + if(userInfo.type === AvatarInfoUser.OWN_USER) userInfo.allowNameChange = GetSessionDataManager().canChangeName; userInfo.amIOwner = roomSession.isRoomOwner; userInfo.isGuildRoom = roomSession.isGuildRoom; @@ -200,14 +188,11 @@ export class AvatarInfoUtilities userInfo.amIAnyRoomController = GetSessionDataManager().isModerator; userInfo.isAmbassador = GetSessionDataManager().isAmbassador; - if(userInfoType === AvatarInfoUser.PEER) + if(userInfo.type === AvatarInfoUser.PEER) { if(roomObject) { - const flatControl = roomObject.model.getValue(RoomObjectVariable.FIGURE_FLAT_CONTROL); - - if(flatControl !== null) userInfo.targetRoomControllerLevel = flatControl; - + userInfo.targetRoomControllerLevel = roomObject.model.getValue(RoomObjectVariable.FIGURE_FLAT_CONTROL); userInfo.canBeMuted = this.canBeMuted(userInfo); userInfo.canBeKicked = this.canBeKicked(userInfo); userInfo.canBeBanned = this.canBeBanned(userInfo); @@ -234,7 +219,7 @@ export class AvatarInfoUtilities userInfo.canTrade = (roomController || targetController); break; } - case RoomTradingLevelEnum.NO_TRADING: + case RoomTradingLevelEnum.FREE_TRADING: userInfo.canTrade = true; break; default: diff --git a/src/api/room/widgets/ChatBubbleUtilities.ts b/src/api/room/widgets/ChatBubbleUtilities.ts new file mode 100644 index 00000000..f12ae07d --- /dev/null +++ b/src/api/room/widgets/ChatBubbleUtilities.ts @@ -0,0 +1,70 @@ +import { AvatarFigurePartType, AvatarScaleType, AvatarSetType, PetFigureData, TextureUtils, Vector3d } from '@nitrots/nitro-renderer'; +import { GetAvatarRenderManager, GetRoomEngine } from '../../nitro'; + +export class ChatBubbleUtilities +{ + public static AVATAR_COLOR_CACHE: Map = new Map(); + public static AVATAR_IMAGE_CACHE: Map = new Map(); + public static PET_IMAGE_CACHE: Map = new Map(); + + private static placeHolderImageUrl: string = ''; + + public static async setFigureImage(figure: string): Promise + { + const avatarImage = GetAvatarRenderManager().createAvatarImage(figure, AvatarScaleType.LARGE, null, { + resetFigure: figure => this.setFigureImage(figure), + dispose: () => + {}, + disposed: false + }); + + if(!avatarImage) return null; + + const isPlaceholder = avatarImage.isPlaceholder(); + + if(isPlaceholder && this.placeHolderImageUrl?.length) return this.placeHolderImageUrl; + + figure = avatarImage.getFigure().getFigureString(); + + const image = await avatarImage.getCroppedImage(AvatarSetType.HEAD); + const color = avatarImage.getPartColor(AvatarFigurePartType.CHEST); + + if(isPlaceholder) this.placeHolderImageUrl = image.src; + + this.AVATAR_COLOR_CACHE.set(figure, ((color && color.rgb) || 16777215)); + this.AVATAR_IMAGE_CACHE.set(figure, image.src); + + avatarImage.dispose(); + + return image.src; + } + + public static async getUserImage(figure: string): Promise + { + let existing = this.AVATAR_IMAGE_CACHE.get(figure); + + if(!existing) existing = await this.setFigureImage(figure); + + return existing; + } + + public static async getPetImage(figure: string, direction: number, _arg_3: boolean, scale: number = 64, posture: string = null) + { + let existing = this.PET_IMAGE_CACHE.get((figure + posture)); + + if(existing) return existing; + + const figureData = new PetFigureData(figure); + const typeId = figureData.typeId; + const image = GetRoomEngine().getRoomObjectPetImage(typeId, figureData.paletteId, figureData.color, new Vector3d((direction * 45)), scale, null, false, 0, figureData.customParts, posture); + + if(image) + { + existing = await TextureUtils.generateImageUrl(image.data); + + this.PET_IMAGE_CACHE.set((figure + posture), existing); + } + + return existing; + } +} diff --git a/src/api/room/widgets/index.ts b/src/api/room/widgets/index.ts index c43d6aaa..6c50c838 100644 --- a/src/api/room/widgets/index.ts +++ b/src/api/room/widgets/index.ts @@ -6,6 +6,7 @@ export * from './AvatarInfoUser'; export * from './AvatarInfoUtilities'; export * from './BotSkillsEnum'; export * from './ChatBubbleMessage'; +export * from './ChatBubbleUtilities'; export * from './ChatMessageTypeEnum'; export * from './DimmerFurnitureWidgetPresetItem'; export * from './DoChatsOverlap'; diff --git a/src/common/index.scss b/src/common/index.scss index bc4a01b0..8539aa53 100644 --- a/src/common/index.scss +++ b/src/common/index.scss @@ -280,7 +280,8 @@ } } -.furni-image { +.furni-image, +.room-object-image { position: relative; width: 100%; height: 100%; diff --git a/src/common/layout/LayoutAvatarImageView.tsx b/src/common/layout/LayoutAvatarImageView.tsx index d127bd99..3dd49822 100644 --- a/src/common/layout/LayoutAvatarImageView.tsx +++ b/src/common/layout/LayoutAvatarImageView.tsx @@ -68,11 +68,14 @@ export const LayoutAvatarImageView: FC = props => avatarImage.setDirection(setType, direction); - const image = avatarImage.getCroppedImage(setType); + (async () => + { + const image = await avatarImage.getCroppedImage(setType); - if(image) setAvatarUrl(image.src); + if(image) setAvatarUrl(image.src); - avatarImage.dispose(); + avatarImage.dispose(); + })(); }, [ figure, gender, direction, headOnly, randomValue ]); useEffect(() => diff --git a/src/common/layout/LayoutBadgeImageView.tsx b/src/common/layout/LayoutBadgeImageView.tsx index a469429b..e68db326 100644 --- a/src/common/layout/LayoutBadgeImageView.tsx +++ b/src/common/layout/LayoutBadgeImageView.tsx @@ -37,7 +37,7 @@ export const LayoutBadgeImageView: FC = props => if(imageElement) { - newStyle.backgroundImage = `url(${ (isGroup) ? imageElement.src : GetConfiguration('badge.asset.url').replace('%badgename%', badgeCode.toString())})`; + newStyle.backgroundImage = `url(${ (isGroup) ? imageElement.src : GetConfiguration('badge.asset.url').replace('%badgename%', badgeCode.toString()) })`; newStyle.width = imageElement.width; newStyle.height = imageElement.height; @@ -55,7 +55,7 @@ export const LayoutBadgeImageView: FC = props => if(Object.keys(style).length) newStyle = { ...newStyle, ...style }; return newStyle; - }, [ imageElement, scale, style ]); + }, [ badgeCode, isGroup, imageElement, scale, style ]); useEffect(() => { @@ -63,11 +63,11 @@ export const LayoutBadgeImageView: FC = props => let didSetBadge = false; - const onBadgeImageReadyEvent = (event: BadgeImageReadyEvent) => + const onBadgeImageReadyEvent = async (event: BadgeImageReadyEvent) => { if(event.badgeId !== badgeCode) return; - const element = TextureUtils.generateImage(new NitroSprite(event.image)); + const element = await TextureUtils.generateImage(new NitroSprite(event.image)); element.onload = () => setImageElement(element); @@ -82,9 +82,12 @@ export const LayoutBadgeImageView: FC = props => if(texture && !didSetBadge) { - const element = TextureUtils.generateImage(new NitroSprite(texture)); + (async () => + { + const element = await TextureUtils.generateImage(new NitroSprite(texture)); - element.onload = () => setImageElement(element); + element.onload = () => setImageElement(element); + })(); } return () => GetSessionDataManager().events.removeEventListener(BadgeImageReadyEvent.IMAGE_READY, onBadgeImageReadyEvent); diff --git a/src/common/layout/LayoutFurniImageView.tsx b/src/common/layout/LayoutFurniImageView.tsx index ef8696c5..708d6d67 100644 --- a/src/common/layout/LayoutFurniImageView.tsx +++ b/src/common/layout/LayoutFurniImageView.tsx @@ -46,15 +46,7 @@ export const LayoutFurniImageView: FC = props => let imageResult: ImageResult = null; const listener: IGetImageListener = { - imageReady: (id, texture, image) => - { - if(!image && texture) - { - image = TextureUtils.generateImage(texture); - } - - image.onload = () => setImageElement(image); - }, + imageReady: async (id, texture, image) => setImageElement(await TextureUtils.generateImage(texture)), imageFailed: null }; @@ -68,12 +60,9 @@ export const LayoutFurniImageView: FC = props => break; } - if(imageResult) - { - const image = imageResult.getImage(); + if(!imageResult) return; - image.onload = () => setImageElement(image); - } + (async () => setImageElement(await TextureUtils.generateImage(imageResult.data)))(); }, [ productType, productClassId, direction, extraData ]); if(!imageElement) return null; diff --git a/src/common/layout/LayoutMiniCameraView.tsx b/src/common/layout/LayoutMiniCameraView.tsx index 31b361c7..8dfbd7b8 100644 --- a/src/common/layout/LayoutMiniCameraView.tsx +++ b/src/common/layout/LayoutMiniCameraView.tsx @@ -6,7 +6,7 @@ import { DraggableWindow } from '../draggable-window'; interface LayoutMiniCameraViewProps { roomId: number; - textureReceiver: (texture: NitroRenderTexture) => void; + textureReceiver: (texture: NitroRenderTexture) => Promise; onClose: () => void; } diff --git a/src/common/layout/LayoutPetImageView.tsx b/src/common/layout/LayoutPetImageView.tsx index 27d43ded..69fe6afd 100644 --- a/src/common/layout/LayoutPetImageView.tsx +++ b/src/common/layout/LayoutPetImageView.tsx @@ -68,7 +68,7 @@ export const LayoutPetImageView: FC = props => if(petTypeId === 16) petHeadOnly = false; const imageResult = GetRoomEngine().getRoomObjectPetImage(petTypeId, petPaletteId, petColor1, new Vector3d((direction * 45)), 64, { - imageReady: (id, texture, image) => + imageReady: async (id, texture, image) => { if(isDisposed.current) return; @@ -81,7 +81,7 @@ export const LayoutPetImageView: FC = props => else if(texture) { - setPetUrl(TextureUtils.generateImageUrl(texture)); + setPetUrl(await TextureUtils.generateImageUrl(texture)); setWidth(texture.width); setHeight(texture.height); } @@ -94,14 +94,17 @@ export const LayoutPetImageView: FC = props => if(imageResult) { - const image = imageResult.getImage(); - - if(image) + (async () => { - setPetUrl(image.src); - setWidth(image.width); - setHeight(image.height); - } + const image = await imageResult.getImage(); + + if(image) + { + setPetUrl(image.src); + setWidth(image.width); + setHeight(image.height); + } + })(); } }, [ figure, typeId, paletteId, petColor, customParts, posture, headOnly, direction ]); diff --git a/src/common/layout/LayoutRoomObjectImageView.tsx b/src/common/layout/LayoutRoomObjectImageView.tsx new file mode 100644 index 00000000..083a9efc --- /dev/null +++ b/src/common/layout/LayoutRoomObjectImageView.tsx @@ -0,0 +1,61 @@ +import { TextureUtils, Vector3d } from '@nitrots/nitro-renderer'; +import { CSSProperties, FC, useEffect, useMemo, useState } from 'react'; +import { BaseProps } from '..'; +import { GetRoomEngine } from '../../api'; +import { Base } from '../Base'; + +interface LayoutRoomObjectImageViewProps extends BaseProps +{ + roomId: number; + objectId: number; + category: number; + direction?: number; + scale?: number; +} + +export const LayoutRoomObjectImageView: FC = props => +{ + const { roomId = -1, objectId = 1, category = -1, direction = 2, scale = 1, style = {}, ...rest } = props; + const [ imageElement, setImageElement ] = useState(null); + + const getStyle = useMemo(() => + { + let newStyle: CSSProperties = {}; + + if(imageElement?.src?.length) + { + newStyle.backgroundImage = `url('${ imageElement.src }')`; + newStyle.width = imageElement.width; + newStyle.height = imageElement.height; + } + + if(scale !== 1) + { + newStyle.transform = `scale(${ scale })`; + + if(!(scale % 1)) newStyle.imageRendering = 'pixelated'; + } + + if(Object.keys(style).length) newStyle = { ...newStyle, ...style }; + + return newStyle; + }, [ imageElement, scale, style ]); + + useEffect(() => + { + const imageResult = GetRoomEngine().getRoomObjectImage(roomId, objectId, category, new Vector3d(direction * 45), 64, { + imageReady: async (id, texture, image) => setImageElement(await TextureUtils.generateImage(texture)), + imageFailed: null + }); + + // needs (roomObjectImage.data.width > 140) || (roomObjectImage.data.height > 200) scale 1 + + if(!imageResult) return; + + (async () => setImageElement(await TextureUtils.generateImage(imageResult.data)))(); + }, [ roomId, objectId, category, direction, scale ]); + + if(!imageElement) return null; + + return ; +} diff --git a/src/common/layout/LayoutRoomPreviewerView.tsx b/src/common/layout/LayoutRoomPreviewerView.tsx index 69fbea84..023e53aa 100644 --- a/src/common/layout/LayoutRoomPreviewerView.tsx +++ b/src/common/layout/LayoutRoomPreviewerView.tsx @@ -26,7 +26,7 @@ export const LayoutRoomPreviewerView: FC = props = { if(!roomPreviewer) return; - const update = (time: number) => + const update = async (time: number) => { if(!roomPreviewer || !renderingCanvas || !elementRef.current) return; @@ -34,7 +34,7 @@ export const LayoutRoomPreviewerView: FC = props = if(!renderingCanvas.canvasUpdated) return; - elementRef.current.style.backgroundImage = `url(${ TextureUtils.generateImageUrl(renderingCanvas.master) })`; + elementRef.current.style.backgroundImage = `url(${ await TextureUtils.generateImageUrl(renderingCanvas.master) })`; } if(!renderingCanvas) diff --git a/src/common/layout/index.ts b/src/common/layout/index.ts index 3c4238e1..cbb05685 100644 --- a/src/common/layout/index.ts +++ b/src/common/layout/index.ts @@ -16,8 +16,9 @@ export * from './LayoutNotificationBubbleView'; export * from './LayoutPetImageView'; export * from './LayoutProgressBar'; export * from './LayoutRarityLevelView'; +export * from './LayoutRoomObjectImageView'; export * from './LayoutRoomPreviewerView'; export * from './LayoutRoomThumbnailView'; export * from './LayoutTrophyView'; -export * from './limited-edition'; export * from './UserProfileIconView'; +export * from './limited-edition'; diff --git a/src/components/camera/views/CameraWidgetCaptureView.tsx b/src/components/camera/views/CameraWidgetCaptureView.tsx index 308bb830..75aeaae6 100644 --- a/src/components/camera/views/CameraWidgetCaptureView.tsx +++ b/src/components/camera/views/CameraWidgetCaptureView.tsx @@ -32,7 +32,7 @@ export const CameraWidgetCaptureView: FC = props = return new NitroRectangle(Math.floor(frameBounds.x), Math.floor(frameBounds.y), Math.floor(frameBounds.width), Math.floor(frameBounds.height)); } - const takePicture = () => + const takePicture = async () => { if(selectedPictureIndex > -1) { @@ -52,7 +52,7 @@ export const CameraWidgetCaptureView: FC = props = } PlaySound(SoundNames.CAMERA_SHUTTER); - clone.push(new CameraPicture(texture, TextureUtils.generateImageUrl(texture))); + clone.push(new CameraPicture(texture, await TextureUtils.generateImageUrl(texture))); setCameraRoll(clone); } diff --git a/src/components/camera/views/editor/CameraWidgetEditorView.tsx b/src/components/camera/views/editor/CameraWidgetEditorView.tsx index d7dfbf7a..fd085b77 100644 --- a/src/components/camera/views/editor/CameraWidgetEditorView.tsx +++ b/src/components/camera/views/editor/CameraWidgetEditorView.tsx @@ -26,6 +26,7 @@ export const CameraWidgetEditorView: FC = props => const [ selectedEffects, setSelectedEffects ] = useState([]); const [ effectsThumbnails, setEffectsThumbnails ] = useState([]); const [ isZoomed, setIsZoomed ] = useState(false); + const [ currentPictureUrl, setCurrentPictureUrl ] = useState(''); const getColorMatrixEffects = useMemo(() => { @@ -83,11 +84,6 @@ export const CameraWidgetEditorView: FC = props => }); }, [ getCurrentEffectIndex, setSelectedEffects ]); - const getCurrentPictureUrl = useMemo(() => - { - return GetRoomCameraWidgetManager().applyEffects(picture.texture, selectedEffects, isZoomed).src; - }, [ picture, selectedEffects, isZoomed ]); - const processAction = useCallback((type: string, effectName: string = null) => { switch(type) @@ -99,7 +95,7 @@ export const CameraWidgetEditorView: FC = props => onCancel(); return; case 'checkout': - onCheckout(getCurrentPictureUrl); + onCheckout(currentPictureUrl); return; case 'change_tab': setCurrentTab(String(effectName)); @@ -143,32 +139,50 @@ export const CameraWidgetEditorView: FC = props => setSelectedEffects([]); return; case 'download': { - const image = new Image(); + (async () => + { + const image = new Image(); - image.src = getCurrentPictureUrl - - const newWindow = window.open(''); - newWindow.document.write(image.outerHTML); + image.src = currentPictureUrl + + const newWindow = window.open(''); + newWindow.document.write(image.outerHTML); + })(); return; } case 'zoom': setIsZoomed(!isZoomed); return; } - }, [ isZoomed, availableEffects, selectedEffectName, getCurrentPictureUrl, getSelectedEffectIndex, onCancel, onCheckout, onClose, setIsZoomed, setSelectedEffects ]); + }, [ isZoomed, availableEffects, selectedEffectName, currentPictureUrl, getSelectedEffectIndex, onCancel, onCheckout, onClose, setIsZoomed, setSelectedEffects ]); useEffect(() => { - const thumbnails: CameraPictureThumbnail[] = []; - - for(const effect of availableEffects) + (async () => { - thumbnails.push(new CameraPictureThumbnail(effect.name, GetRoomCameraWidgetManager().applyEffects(picture.texture, [ new RoomCameraWidgetSelectedEffect(effect, 1) ], false).src)); - } + const thumbnails: CameraPictureThumbnail[] = []; + + for await (const effect of availableEffects) + { + const image = await GetRoomCameraWidgetManager().applyEffects(picture.texture, [ new RoomCameraWidgetSelectedEffect(effect, 1) ], false); - setEffectsThumbnails(thumbnails); + thumbnails.push(new CameraPictureThumbnail(effect.name, image.src)); + } + + setEffectsThumbnails(thumbnails); + })(); }, [ picture, availableEffects ]); + useEffect(() => + { + (async () => + { + const imageUrl = await GetRoomCameraWidgetManager().applyEffects(picture.texture, selectedEffects, isZoomed); + + setCurrentPictureUrl(imageUrl.src); + })(); + }, [ picture, selectedEffects, isZoomed ]); + return ( processAction('close') } /> @@ -185,7 +199,7 @@ export const CameraWidgetEditorView: FC = props => - + { selectedEffectName && { LocalizeText('camera.effect.name.' + selectedEffectName) } diff --git a/src/components/room/widgets/avatar-info/infostand/InfoStandWidgetFurniView.tsx b/src/components/room/widgets/avatar-info/infostand/InfoStandWidgetFurniView.tsx index aa4b388c..3de161d4 100644 --- a/src/components/room/widgets/avatar-info/infostand/InfoStandWidgetFurniView.tsx +++ b/src/components/room/widgets/avatar-info/infostand/InfoStandWidgetFurniView.tsx @@ -2,7 +2,7 @@ import { CrackableDataType, GroupInformationComposer, GroupInformationEvent, Now import { FC, useCallback, useEffect, useState } from 'react'; import { FaTimes } from 'react-icons/fa'; import { AvatarInfoFurni, CreateLinkEvent, GetGroupInformation, GetNitroInstance, GetRoomEngine, LocalizeText, SendMessageComposer } from '../../../../../api'; -import { Base, Button, Column, Flex, LayoutBadgeImageView, LayoutLimitedEditionCompactPlateView, LayoutRarityLevelView, Text, UserProfileIconView } from '../../../../../common'; +import { Base, Button, Column, Flex, LayoutBadgeImageView, LayoutLimitedEditionCompactPlateView, LayoutRarityLevelView, LayoutRoomObjectImageView, Text, UserProfileIconView } from '../../../../../common'; import { useMessageEvent, useRoom, useSoundEvent } from '../../../../../hooks'; interface InfoStandWidgetFurniViewProps @@ -347,8 +347,9 @@ export const InfoStandWidgetFurniView: FC = props
} - { avatarInfo.image && avatarInfo.image.src.length && - } + + +
diff --git a/src/components/room/widgets/room-thumbnail/RoomThumbnailWidgetView.tsx b/src/components/room/widgets/room-thumbnail/RoomThumbnailWidgetView.tsx index 055e7341..5476de6d 100644 --- a/src/components/room/widgets/room-thumbnail/RoomThumbnailWidgetView.tsx +++ b/src/components/room/widgets/room-thumbnail/RoomThumbnailWidgetView.tsx @@ -29,9 +29,9 @@ export const RoomThumbnailWidgetView: FC<{}> = props => } }); - const receiveTexture = (texture: NitroRenderTexture) => + const receiveTexture = async (texture: NitroRenderTexture) => { - GetRoomEngine().saveTextureAsScreenshot(texture, true); + await GetRoomEngine().saveTextureAsScreenshot(texture, true); setIsVisible(false); } diff --git a/src/hooks/notification/useNotification.ts b/src/hooks/notification/useNotification.ts index 0089b867..7818d85d 100644 --- a/src/hooks/notification/useNotification.ts +++ b/src/hooks/notification/useNotification.ts @@ -258,7 +258,7 @@ const useNotificationState = () => simpleAlert( LocalizeText(('opening.hours.' + (parser.userThrowOutAtClose ? 'disconnected' : 'closed')), [ 'h', 'm' ], [ getTimeZeroPadded(parser.openHour), getTimeZeroPadded(parser.openMinute) ]), NotificationAlertType.DEFAULT, null, null, LocalizeText('opening.hours.title')); }); - useMessageEvent(PetReceivedMessageEvent, event => + useMessageEvent(PetReceivedMessageEvent, async event => { const parser = event.getParser(); @@ -268,7 +268,7 @@ const useNotificationState = () => const imageResult = GetRoomEngine().getRoomObjectPetImage(parser.pet.typeId, parser.pet.paletteId, parseInt(parser.pet.color, 16), new Vector3d(45 * 3), 64, null, true); - if(imageResult) imageUrl = imageResult.getImage().src; + if(imageResult) imageUrl = (await imageResult.getImage())?.src; showSingleBubble(text, NotificationBubbleType.PETLEVEL, imageUrl); }); @@ -284,7 +284,7 @@ const useNotificationState = () => setAlerts(prevValue => [ alertItem, ...prevValue ]); }); - useMessageEvent(PetLevelNotificationEvent, event => + useMessageEvent(PetLevelNotificationEvent, async event => { const parser = event.getParser(); @@ -292,7 +292,7 @@ const useNotificationState = () => const imageResult = GetRoomEngine().getRoomObjectPetImage(parser.figureData.typeId, parser.figureData.paletteId, parseInt(parser.figureData.color, 16), new Vector3d(45 * 3), 64, null, true); - if(imageResult) imageUrl = imageResult.getImage().src; + if(imageResult) imageUrl = (await imageResult.getImage())?.src; showSingleBubble(LocalizeText('notifications.text.petlevel', [ 'pet_name', 'level' ], [ parser.petName, parser.level.toString() ]), NotificationBubbleType.PETLEVEL, imageUrl); }); diff --git a/src/hooks/rooms/widgets/useChatWidget.ts b/src/hooks/rooms/widgets/useChatWidget.ts index 0edfb5f0..c24b8bfd 100644 --- a/src/hooks/rooms/widgets/useChatWidget.ts +++ b/src/hooks/rooms/widgets/useChatWidget.ts @@ -1,14 +1,10 @@ -import { AvatarFigurePartType, AvatarScaleType, AvatarSetType, GetGuestRoomResultEvent, NitroPoint, PetFigureData, RoomChatSettings, RoomChatSettingsEvent, RoomDragEvent, RoomObjectCategory, RoomObjectType, RoomObjectVariable, RoomSessionChatEvent, RoomUserData, SystemChatStyleEnum, TextureUtils, Vector3d } from '@nitrots/nitro-renderer'; +import { GetGuestRoomResultEvent, NitroPoint, PetFigureData, RoomChatSettings, RoomChatSettingsEvent, RoomDragEvent, RoomObjectCategory, RoomObjectType, RoomObjectVariable, RoomSessionChatEvent, RoomUserData, SystemChatStyleEnum } from '@nitrots/nitro-renderer'; import { useEffect, useMemo, useRef, useState } from 'react'; -import { ChatBubbleMessage, ChatEntryType, ChatHistoryCurrentDate, GetAvatarRenderManager, GetConfiguration, GetRoomEngine, GetRoomObjectScreenLocation, IRoomChatSettings, LocalizeText, PlaySound, RoomChatFormatter } from '../../../api'; +import { ChatBubbleMessage, ChatBubbleUtilities, ChatEntryType, ChatHistoryCurrentDate, GetConfiguration, GetRoomEngine, GetRoomObjectScreenLocation, IRoomChatSettings, LocalizeText, PlaySound, RoomChatFormatter } from '../../../api'; import { useMessageEvent, useRoomEngineEvent, useRoomSessionManagerEvent } from '../../events'; import { useRoom } from '../useRoom'; import { useChatHistory } from './../../chat-history'; -const avatarColorCache: Map = new Map(); -const avatarImageCache: Map = new Map(); -const petImageCache: Map = new Map(); - const useChatWidgetState = () => { const [ chatMessages, setChatMessages ] = useState([]); @@ -38,64 +34,7 @@ const useChatWidgetState = () => } }, [ chatSettings ]); - const setFigureImage = (figure: string) => - { - const avatarImage = GetAvatarRenderManager().createAvatarImage(figure, AvatarScaleType.LARGE, null, { - resetFigure: figure => - { - if(isDisposed.current) return; - - setFigureImage(figure); - }, - dispose: () => - {}, - disposed: false - }); - - if(!avatarImage) return; - - const image = avatarImage.getCroppedImage(AvatarSetType.HEAD); - const color = avatarImage.getPartColor(AvatarFigurePartType.CHEST); - - avatarColorCache.set(figure, ((color && color.rgb) || 16777215)); - - avatarImage.dispose(); - - avatarImageCache.set(figure, image.src); - - return image.src; - } - - const getUserImage = (figure: string) => - { - let existing = avatarImageCache.get(figure); - - if(!existing) existing = setFigureImage(figure); - - return existing; - } - - const getPetImage = (figure: string, direction: number, _arg_3: boolean, scale: number = 64, posture: string = null) => - { - let existing = petImageCache.get((figure + posture)); - - if(existing) return existing; - - const figureData = new PetFigureData(figure); - const typeId = figureData.typeId; - const image = GetRoomEngine().getRoomObjectPetImage(typeId, figureData.paletteId, figureData.color, new Vector3d((direction * 45)), scale, null, false, 0, figureData.customParts, posture); - - if(image) - { - existing = TextureUtils.generateImageUrl(image.data); - - petImageCache.set((figure + posture), existing); - } - - return existing; - } - - useRoomSessionManagerEvent(RoomSessionChatEvent.CHAT_EVENT, event => + useRoomSessionManagerEvent(RoomSessionChatEvent.CHAT_EVENT, async event => { const roomObject = GetRoomEngine().getRoomObject(roomSession.roomId, event.objectId, RoomObjectCategory.UNIT); const bubbleLocation = roomObject ? GetRoomObjectScreenLocation(roomSession.roomId, roomObject?.id, RoomObjectCategory.UNIT) : new NitroPoint(); @@ -119,11 +58,11 @@ const useChatWidgetState = () => switch(userType) { case RoomObjectType.PET: - imageUrl = getPetImage(figure, 2, true, 64, roomObject.model.getValue(RoomObjectVariable.FIGURE_POSTURE)); + imageUrl = await ChatBubbleUtilities.getPetImage(figure, 2, true, 64, roomObject.model.getValue(RoomObjectVariable.FIGURE_POSTURE)); petType = new PetFigureData(figure).typeId; break; case RoomObjectType.USER: - imageUrl = getUserImage(figure); + imageUrl = await ChatBubbleUtilities.getUserImage(figure); break; case RoomObjectType.RENTABLE_BOT: case RoomObjectType.BOT: @@ -131,7 +70,7 @@ const useChatWidgetState = () => break; } - avatarColor = avatarColorCache.get(figure); + avatarColor = ChatBubbleUtilities.AVATAR_COLOR_CACHE.get(figure); username = userData.name; }