Fix scaling issues

This commit is contained in:
Bill 2022-04-08 01:39:35 -04:00
parent a5a73ba1fb
commit ce623859df
20 changed files with 264 additions and 252 deletions

View File

@ -1,5 +1,5 @@
import { ConfigurationEvent, HabboWebTools, LegacyExternalInterface, Nitro, NitroCommunicationDemoEvent, NitroEvent, NitroLocalizationEvent, NitroVersion, RoomEngineEvent, WebGL } from '@nitrots/nitro-renderer';
import { FC, useCallback, useState } from 'react';
import { FC, useCallback, useEffect, useState } from 'react';
import { GetCommunication, GetConfiguration, GetNitroInstance, GetUIVersion } from './api';
import { Base, TransitionAnimation, TransitionAnimationTypes } from './common';
import { LoadingView } from './components/loading/LoadingView';
@ -16,12 +16,13 @@ export const App: FC<{}> = props =>
const [ isError, setIsError ] = useState(false);
const [ message, setMessage ] = useState('Getting Ready');
const [ percent, setPercent ] = useState(0);
//@ts-ignore
if(!NitroConfig) throw new Error('NitroConfig is not defined!');
const [ imageRendering, setImageRendering ] = useState<boolean>(true);
if(!GetNitroInstance())
{
//@ts-ignore
if(!NitroConfig) throw new Error('NitroConfig is not defined!');
Nitro.bootstrap();
const worker = new WorkerBuilder(IntervalWebWorker);
@ -29,28 +30,13 @@ export const App: FC<{}> = props =>
Nitro.instance.setWorker(worker);
}
const getPreloadAssetUrls = useCallback(() =>
{
const urls: string[] = [];
const assetUrls = GetConfiguration<string[]>('preload.assets.urls');
if(assetUrls && assetUrls.length)
{
for(const url of assetUrls) urls.push(GetNitroInstance().core.configuration.interpolate(url));
}
return urls;
}, []);
const loadPercent = useCallback(() => setPercent(prevValue => (prevValue + 20)), []);
const handler = useCallback((event: NitroEvent) =>
{
switch(event.type)
{
case ConfigurationEvent.LOADED:
GetNitroInstance().localization.init();
loadPercent();
setPercent(prevValue => (prevValue + 20));
return;
case ConfigurationEvent.FAILED:
setIsError(true);
@ -67,14 +53,14 @@ export const App: FC<{}> = props =>
setTimeout(() => window.location.reload(), 1500);
return;
case NitroCommunicationDemoEvent.CONNECTION_HANDSHAKING:
loadPercent();
setPercent(prevValue => (prevValue + 20));
return;
case NitroCommunicationDemoEvent.CONNECTION_HANDSHAKE_FAILED:
setIsError(true);
setMessage('Handshake Failed');
return;
case NitroCommunicationDemoEvent.CONNECTION_AUTHENTICATED:
loadPercent();
setPercent(prevValue => (prevValue + 20));
GetNitroInstance().init();
@ -85,26 +71,30 @@ export const App: FC<{}> = props =>
setMessage('Connection Error');
return;
case NitroCommunicationDemoEvent.CONNECTION_CLOSED:
//if(GetNitroInstance().roomEngine) GetNitroInstance().roomEngine.dispose();
//if(GetNitroInstance().roomEngine) GetNitroInstance().roomEngine.dispose();
//setIsError(true);
setMessage('Connection Error');
HabboWebTools.send(-1, 'client.init.handshake.fail');
return;
case RoomEngineEvent.ENGINE_INITIALIZED:
loadPercent();
setPercent(prevValue => (prevValue + 20));
setTimeout(() => setIsReady(true), 300);
return;
case NitroLocalizationEvent.LOADED:
GetNitroInstance().core.asset.downloadAssets(getPreloadAssetUrls(), (status: boolean) =>
case NitroLocalizationEvent.LOADED: {
const assetUrls = GetConfiguration<string[]>('preload.assets.urls');
const urls: string[] = [];
if(assetUrls && assetUrls.length) for(const url of assetUrls) urls.push(GetNitroInstance().core.configuration.interpolate(url));
GetNitroInstance().core.asset.downloadAssets(urls, (status: boolean) =>
{
if(status)
{
GetCommunication().init();
loadPercent();
setPercent(prevValue => (prevValue + 20))
}
else
{
@ -113,8 +103,9 @@ export const App: FC<{}> = props =>
}
});
return;
}
}
}, [ getPreloadAssetUrls,loadPercent ]);
}, []);
UseMainEvent(Nitro.WEBGL_UNAVAILABLE, handler);
UseMainEvent(Nitro.WEBGL_CONTEXT_LOST, handler);
@ -128,17 +119,31 @@ export const App: FC<{}> = props =>
UseConfigurationEvent(ConfigurationEvent.LOADED, handler);
UseConfigurationEvent(ConfigurationEvent.FAILED, handler);
if(!WebGL.isWebGLAvailable())
useEffect(() =>
{
DispatchUiEvent(new NitroEvent(Nitro.WEBGL_UNAVAILABLE));
}
else
{
GetNitroInstance().core.configuration.init();
}
if(!WebGL.isWebGLAvailable())
{
DispatchUiEvent(new NitroEvent(Nitro.WEBGL_UNAVAILABLE));
}
else
{
GetNitroInstance().core.configuration.init();
}
const resize = (event: UIEvent) => setImageRendering(!(window.devicePixelRatio % 1));
window.addEventListener('resize', resize);
resize(null);
return () =>
{
window.removeEventListener('resize', resize);
}
}, []);
return (
<Base fit overflow="hidden">
<Base fit overflow="hidden" className={ imageRendering && 'image-rendering-pixelated' }>
{ (!isReady || isError) &&
<LoadingView isError={ isError } message={ message } percent={ percent } /> }
<TransitionAnimation type={ TransitionAnimationTypes.FADE_IN } inProp={ (isReady) }>

View File

@ -7,8 +7,8 @@ let clickCount = 0;
export const DispatchMouseEvent = (event: MouseEvent, canvasId: number = 1) =>
{
const x = (event.clientX * window.devicePixelRatio);
const y = (event.clientY * window.devicePixelRatio);
const x = event.clientX;
const y = event.clientY;
let eventType = event.type;

View File

@ -51,9 +51,6 @@ export const DispatchTouchEvent = (event: TouchEvent, canvasId: number = 1, long
y = event.changedTouches[0].clientY;
}
x = Math.round(x / (1 / window.devicePixelRatio));
y = Math.round(y / (1 / window.devicePixelRatio));
switch(eventType)
{
case MouseEventType.MOUSE_CLICK:

View File

@ -6,11 +6,8 @@ export const GetRoomObjectBounds = (roomId: number, objectId: number, category:
if(!rectangle) return null;
if(window.devicePixelRatio !== 1)
{
rectangle.x = Math.round(rectangle.x / window.devicePixelRatio);
rectangle.y = Math.round(rectangle.y / window.devicePixelRatio);
}
rectangle.x = Math.round(rectangle.x);
rectangle.y = Math.round(rectangle.y);
return rectangle;
}

View File

@ -6,11 +6,8 @@ export const GetRoomObjectScreenLocation = (roomId: number, objectId: number, ca
if(!point) return null;
if(window.devicePixelRatio !== 1)
{
point.x = Math.round(point.x / window.devicePixelRatio);
point.y = Math.round(point.y / window.devicePixelRatio);
}
point.x = Math.round(point.x);
point.y = Math.round(point.y);
return point;
}

View File

@ -16,7 +16,7 @@
cursor: not-allowed;
img {
opacity: .5;
opacity: 0.5;
filter: grayscale(1);
}
}
@ -30,9 +30,8 @@
}
&.has-highlight {
&:after {
content: '';
content: "";
z-index: 2;
position: absolute;
top: 0;
@ -48,7 +47,7 @@
.nitro-room-thumbnail-camera {
width: 132px;
height: 192px;
background-image: url('../assets/images/room-widgets/thumbnail-widget/thumbnail-camera-spritesheet.png');
background-image: url("../assets/images/room-widgets/thumbnail-widget/thumbnail-camera-spritesheet.png");
.camera-frame {
position: absolute;
@ -65,10 +64,10 @@
height: 173px;
color: black;
pointer-events: all;
background-position: 0px 0px;
background-image: url('../assets/images/room-widgets/trophy-widget/trophy-spritesheet.png');
background-image: url("../assets/images/room-widgets/trophy-widget/trophy-spritesheet.png");
&.trophy-2 {
background-position: 0px 173px;
}
@ -103,7 +102,7 @@
.nitro-gift-card {
width: 306px;
height: 159px;
background: url('../assets/images/gift/gift_tag.png') center no-repeat;
background: url("../assets/images/gift/gift_tag.png") center no-repeat;
.gift-face {
width: 65px;
@ -111,7 +110,8 @@
.gift-incognito {
width: 37px;
height: 48px;
background: url('../assets/images/gift/incognito.png') center no-repeat;
background: url("../assets/images/gift/incognito.png") center
no-repeat;
}
.gift-avatar {
@ -168,17 +168,26 @@
}
@-webkit-keyframes sk-bouncedelay {
0%, 80%, 100% { -webkit-transform: scale(0) }
40% { -webkit-transform: scale(1.0) }
0%,
80%,
100% {
-webkit-transform: scale(0);
}
40% {
-webkit-transform: scale(1);
}
}
@keyframes sk-bouncedelay {
0%, 80%, 100% {
-webkit-transform: scale(0);
transform: scale(0);
} 40% {
-webkit-transform: scale(1.0);
transform: scale(1.0);
0%,
80%,
100% {
-webkit-transform: scale(0);
transform: scale(0);
}
40% {
-webkit-transform: scale(1);
transform: scale(1);
}
}
@ -186,8 +195,9 @@
position: relative;
width: 110px;
height: 110px;
background: url('../assets/images/navigator/thumbnail_placeholder.png') no-repeat center;
background-color: rgba($black, .125);
background: url("../assets/images/navigator/thumbnail_placeholder.png")
no-repeat center;
background-color: rgba($black, 0.125);
}
#draggable-windows-container {
@ -223,7 +233,7 @@
top: 2px;
right: 2px;
font-size: 9.5px;
padding:2px 3px;
padding: 2px 3px;
z-index: 1;
}
@ -234,16 +244,6 @@
background-repeat: no-repeat;
background-position: center;
&.group-badge {
width: 39px;
height: 39px;
&.scale-2 {
width: 80px;
height: 80px;
}
}
.badge-information {
display: none;
}
@ -263,10 +263,10 @@
background: $white;
left: -220px;
z-index: 100;
&:before {
position: absolute;
content: ' ';
content: " ";
width: 0;
height: 0;
border-left: 10px solid $white;
@ -289,7 +289,7 @@
.nitro-rarity-level {
width: 36px;
height: 28px;
background: url('../assets/images/infostand/rarity-level.png');
background: url("../assets/images/infostand/rarity-level.png");
div {
line-height: 28px;
@ -306,12 +306,6 @@
background-repeat: no-repeat;
background-position: center -8px;
pointer-events: none;
image-rendering: pixelated;
&.scale-0-5,
&.scale-0-75 {
image-rendering: -webkit-optimize-contrast;
}
}
.pet-image {
@ -337,7 +331,7 @@
background-repeat: no-repeat;
background-position: center;
overflow: hidden;
&.border-0 {
&::after {
content: none;
@ -346,7 +340,7 @@
&::after {
position: absolute;
content: '';
content: "";
top: 0;
bottom: 0;
left: 0;
@ -354,13 +348,13 @@
border-radius: $border-radius;
border-bottom: 2px solid white;
border-right: 2px solid white;
box-shadow: -2px -2px rgba(0, 0, 0, .4), inset 3px 3px rgba(0, 0, 0, .2);
box-shadow: -2px -2px rgba(0, 0, 0, 0.4),
inset 3px 3px rgba(0, 0, 0, 0.2);
}
}
}
.unique-item {
.unique-bg-override {
background-position: center;
background-repeat: no-repeat;
@ -369,26 +363,28 @@
&:before {
position: absolute;
content: '';
content: "";
width: 100%;
height: 100%;
background: url('../assets/images/unique/grid-bg.png') center no-repeat;
background: url("../assets/images/unique/grid-bg.png") center no-repeat;
z-index: 1;
}
&:after {
position: absolute;
content: '';
content: "";
width: 100%;
height: 100%;
background: url('../assets/images/unique/grid-bg-glass.png') center no-repeat;
background: url("../assets/images/unique/grid-bg-glass.png") center
no-repeat;
bottom: 0;
z-index: 4;
}
&.sold-out:after {
background: url('../assets/images/unique/grid-bg-sold-out.png') center no-repeat,
url('../assets/images/unique/grid-bg-glass.png') center no-repeat;
background: url("../assets/images/unique/grid-bg-sold-out.png") center
no-repeat,
url("../assets/images/unique/grid-bg-glass.png") center no-repeat;
}
.unique-item-counter {
@ -399,7 +395,8 @@
bottom: 1px;
width: 100%;
height: 9px;
background: url('../assets/images/unique/grid-count-bg.png') center no-repeat;
background: url("../assets/images/unique/grid-count-bg.png") center
no-repeat;
z-index: 3;
}
}
@ -407,7 +404,7 @@
.unique-sold-out-blocker {
width: 364px;
height: 30px;
background: url('../assets/images/unique/catalog-info-sold-out.png');
background: url("../assets/images/unique/catalog-info-sold-out.png");
div {
float: right;
@ -428,7 +425,7 @@
right: 16px;
width: 34px;
height: 37px;
background: url('../assets/images/unique/inventory-info-amount-bg.png');
background: url("../assets/images/unique/inventory-info-amount-bg.png");
div {
display: flex;
@ -441,7 +438,8 @@
.unique-complete-plate {
width: 170px;
height: 29px;
background: url('../assets/images/unique/catalog-info-amount-bg.png') no-repeat center;
background: url("../assets/images/unique/catalog-info-amount-bg.png")
no-repeat center;
z-index: 1;
padding-top: 3px;
@ -462,7 +460,7 @@
outline: 0;
height: 5px;
margin-right: 1px;
background-image: url('../assets/images/unique/numbers.png');
background-image: url("../assets/images/unique/numbers.png");
background-repeat: no-repeat;
&:last-child {
@ -537,7 +535,12 @@
z-index: 1;
transition: all 1s;
border-radius: calc(#{$border-radius} / 2);
background: repeating-linear-gradient($tertiary, $tertiary 50%, $quaternary 50%, $quaternary 100%);
background: repeating-linear-gradient(
$tertiary,
$tertiary 50%,
$quaternary 50%,
$quaternary 100%
);
}
.nitro-progress-bar-text {
@ -546,4 +549,4 @@
}
}
@import './card/NitroCardView';
@import "./card/NitroCardView";

View File

@ -23,29 +23,10 @@ export const LayoutAvatarImageView: FC<LayoutAvatarImageViewProps> = props =>
{
const newClassNames: string[] = [ 'avatar-image' ];
switch(scale)
{
case .5:
newClassNames.push('scale-0-5');
break;
case .75:
newClassNames.push('scale-0-75');
break;
case 1.25:
newClassNames.push('scale-1-25');
break;
case 1.50:
newClassNames.push('scale-1-50');
break;
default:
newClassNames.push(`scale-${ scale }`);
break;
}
if(classNames.length) newClassNames.push(...classNames);
return newClassNames;
}, [ scale, classNames ]);
}, [ classNames ]);
const getStyle = useMemo(() =>
{
@ -53,10 +34,17 @@ export const LayoutAvatarImageView: FC<LayoutAvatarImageViewProps> = props =>
if(avatarUrl && avatarUrl.length) newStyle.backgroundImage = `url('${ avatarUrl }')`;
if(scale !== 1)
{
newStyle.transform = `scale(${ scale })`;
if(!(scale % 1)) newStyle.imageRendering = 'pixelated';
}
if(Object.keys(style).length) newStyle = { ...newStyle, ...style };
return newStyle;
}, [ avatarUrl, style ]);
}, [ avatarUrl, scale, style ]);
useEffect(() =>
{

View File

@ -16,22 +16,7 @@ export interface LayoutBadgeImageViewProps extends BaseProps<HTMLDivElement>
export const LayoutBadgeImageView: FC<LayoutBadgeImageViewProps> = props =>
{
const { badgeCode = null, isGroup = false, showInfo = false, customTitle = null, isGrayscale = false, scale = 1, classNames = [], style = {}, children = null, ...rest } = props;
const [ badgeUrl, setBadgeUrl ] = useState<string>('');
const getScaleClass = useMemo(() =>
{
let scaleName = scale.toString();
if(scale === .5) scaleName = '0-5';
else if(scale === .75) scaleName = '0-75';
else if(scale === 1.25) scaleName = '1-25';
else if(scale === 1.50) scaleName = '1-50';
return `scale-${ scaleName }`;
}, [ scale ]);
const [ imageElement, setImageElement ] = useState<HTMLImageElement>(null);
const getClassNames = useMemo(() =>
{
@ -41,23 +26,36 @@ export const LayoutBadgeImageView: FC<LayoutBadgeImageViewProps> = props =>
if(isGrayscale) newClassNames.push('grayscale');
if((scale !== 1) && getScaleClass.length) newClassNames.push(getScaleClass);
if(classNames.length) newClassNames.push(...classNames);
return newClassNames;
}, [ classNames, isGroup, isGrayscale, scale, getScaleClass ]);
}, [ classNames, isGroup, isGrayscale ]);
const getStyle = useMemo(() =>
{
let newStyle: CSSProperties = {};
if(badgeUrl && badgeUrl.length) newStyle.backgroundImage = `url(${ badgeUrl })`;
if(imageElement)
{
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';
newStyle.width = (imageElement.width * scale);
newStyle.height = (imageElement.height * scale);
}
}
if(Object.keys(style).length) newStyle = { ...newStyle, ...style };
return newStyle;
}, [ style, badgeUrl ]);
}, [ imageElement, scale, style ]);
useEffect(() =>
{
@ -69,7 +67,9 @@ export const LayoutBadgeImageView: FC<LayoutBadgeImageViewProps> = props =>
{
if(event.badgeId !== badgeCode) return;
setBadgeUrl(TextureUtils.generateImageUrl(new NitroSprite(event.image)));
const element = TextureUtils.generateImage(new NitroSprite(event.image));
element.onload = () => setImageElement(element);
didSetBadge = true;
@ -80,29 +80,23 @@ export const LayoutBadgeImageView: FC<LayoutBadgeImageViewProps> = props =>
const texture = isGroup ? GetSessionDataManager().getGroupBadgeImage(badgeCode) : GetSessionDataManager().getBadgeImage(badgeCode);
if(texture && !didSetBadge) setBadgeUrl(TextureUtils.generateImageUrl(new NitroSprite(texture)));
if(texture && !didSetBadge)
{
const element = TextureUtils.generateImage(new NitroSprite(texture));
element.onload = () => setImageElement(element);
}
return () => GetSessionDataManager().events.removeEventListener(BadgeImageReadyEvent.IMAGE_READY, onBadgeImageReadyEvent);
}, [ badgeCode, isGroup ]);
const BadgeInformationView = (props: { title: string, description: string }) =>
{
const { title = null, description = null } = props;
if(!GetConfiguration('badge.descriptions.enabled', true)) return null;
return (
<Base className="badge-information text-black py-1 px-2 small">
<div className="fw-bold mb-1">{ title }</div>
<div>{ description }</div>
</Base>
);
};
return (
<Base classNames={ getClassNames } style={ getStyle } { ...rest }>
{ showInfo &&
<BadgeInformationView title={ isGroup ? customTitle : LocalizeBadgeName(badgeCode) } description={ isGroup ? LocalizeText('group.badgepopup.body') : LocalizeBadgeDescription(badgeCode) } /> }
{ (showInfo && GetConfiguration<boolean>('badge.descriptions.enabled', true)) &&
<Base className="badge-information text-black py-1 px-2 small">
<div className="fw-bold mb-1">{ isGroup ? customTitle : LocalizeBadgeName(badgeCode) }</div>
<div>{ isGroup ? LocalizeText('group.badgepopup.body') : LocalizeBadgeDescription(badgeCode) }</div>
</Base> }
{ children }
</Base>
);

View File

@ -1,9 +1,10 @@
import { IGetImageListener, ImageResult, TextureUtils, Vector3d } from '@nitrots/nitro-renderer';
import { FC, useCallback, useEffect, useState } from 'react';
import { CSSProperties, FC, useCallback, useEffect, useMemo, useState } from 'react';
import { BaseProps } from '..';
import { GetRoomEngine, ProductTypeEnum } from '../../api';
import { Base } from '../Base';
interface LayoutFurniImageViewProps
interface LayoutFurniImageViewProps extends BaseProps<HTMLDivElement>
{
productType: string;
productClassId: number;
@ -14,9 +15,32 @@ interface LayoutFurniImageViewProps
export const LayoutFurniImageView: FC<LayoutFurniImageViewProps> = props =>
{
const { productType = 's', productClassId = -1, direction = 0, extraData = '', scale = 1 } = props;
const { productType = 's', productClassId = -1, direction = 2, extraData = '', scale = 1, style = {}, ...rest } = props;
const [ imageElement, setImageElement ] = useState<HTMLImageElement>(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 ]);
const buildImage = useCallback(() =>
{
let imageResult: ImageResult = null;
@ -59,7 +83,5 @@ export const LayoutFurniImageView: FC<LayoutFurniImageViewProps> = props =>
if(!imageElement) return null;
const imageUrl = `url('${ imageElement.src }')`;
return <Base classNames={ [ 'furni-image', `scale-${ scale }` ] } style={ { backgroundImage: imageUrl, width: imageElement.width, height: imageElement.height } } />;
return <Base classNames={ [ 'furni-image' ] } style={ getStyle } { ...rest } />;
}

View File

@ -1,13 +1,14 @@
import { PetCustomPart, PetFigureData, TextureUtils, Vector3d } from '@nitrots/nitro-renderer';
import { FC, useEffect, useRef, useState } from 'react';
import { CSSProperties, FC, useEffect, useMemo, useRef, useState } from 'react';
import { GetRoomEngine } from '../../api';
import { Base, BaseProps } from '../Base';
interface LayoutPetImageViewProps
interface LayoutPetImageViewProps extends BaseProps<HTMLDivElement>
{
figure?: string;
typeId?: number;
paletteId?: number;
color?: number;
petColor?: number;
customParts?: PetCustomPart[];
posture?: string;
headOnly?: boolean;
@ -17,17 +18,35 @@ interface LayoutPetImageViewProps
export const LayoutPetImageView: FC<LayoutPetImageViewProps> = props =>
{
const { figure = '', typeId = -1, paletteId = -1, color = 0xFFFFFF, customParts = [], posture = 'std', headOnly = false, direction = 0, scale = 1 } = props;
const { figure = '', typeId = -1, paletteId = -1, petColor = 0xFFFFFF, customParts = [], posture = 'std', headOnly = false, direction = 0, scale = 1, style = {}, ...rest } = props;
const [ petUrl, setPetUrl ] = useState<string>(null);
const isDisposed = useRef(false);
const getStyle = useMemo(() =>
{
let newStyle: CSSProperties = {};
if(petUrl && petUrl.length) newStyle.backgroundImage = `url(${ petUrl })`;
if(scale !== 1)
{
newStyle.transform = `scale(${ scale })`;
if(!(scale % 1)) newStyle.imageRendering = 'pixelated';
}
if(Object.keys(style).length) newStyle = { ...newStyle, ...style };
return newStyle;
}, [ petUrl, scale, style ]);
useEffect(() =>
{
let url = null;
let petTypeId = typeId;
let petPaletteId = paletteId;
let petColor = color;
let petColor1 = petColor;
let petCustomParts = customParts;
let petHeadOnly = headOnly;
@ -37,13 +56,13 @@ export const LayoutPetImageView: FC<LayoutPetImageViewProps> = props =>
petTypeId = petFigureData.typeId;
petPaletteId = petFigureData.paletteId;
petColor = petFigureData.color;
petColor1 = petFigureData.color;
petCustomParts = petFigureData.customParts;
}
if(petTypeId === 16) petHeadOnly = false;
const imageResult = GetRoomEngine().getRoomObjectPetImage(petTypeId, petPaletteId, petColor, new Vector3d((direction * 45)), 64, {
const imageResult = GetRoomEngine().getRoomObjectPetImage(petTypeId, petPaletteId, petColor1, new Vector3d((direction * 45)), 64, {
imageReady: (id, texture, image) =>
{
if(isDisposed.current) return;
@ -65,7 +84,7 @@ export const LayoutPetImageView: FC<LayoutPetImageViewProps> = props =>
}
}, [ figure, typeId, paletteId, color, customParts, posture, headOnly, direction ]);
}, [ figure, typeId, paletteId, petColor, customParts, posture, headOnly, direction ]);
useEffect(() =>
{
@ -78,6 +97,6 @@ export const LayoutPetImageView: FC<LayoutPetImageViewProps> = props =>
}, []);
const url = `url('${ petUrl }')`;
return <div className={ 'pet-image scale-' + scale.toString().replace('.', '-') } style={ (petUrl && url.length) ? { backgroundImage: url } : {} }></div>;
return <Base classNames={ [ 'pet-image' ] } style={ getStyle } { ...rest } />;
}

View File

@ -7,15 +7,20 @@
border-radius: $border-radius;
box-shadow: 0 0 0 1.5px $white;
border: 2px solid #921911;
background: repeating-linear-gradient(rgba(245,80,65,1), rgba(245,80,65,1) 50%, rgba(194,48,39,1) 50%, rgba(194,48,39,1) 100%);
background: repeating-linear-gradient(
rgba(245, 80, 65, 1),
rgba(245, 80, 65, 1) 50%,
rgba(194, 48, 39, 1) 50%,
rgba(194, 48, 39, 1) 100%
);
cursor: pointer;
line-height: 1;
padding: 1px 3px;
&:hover {
filter: brightness(1.2);
}
&:active {
filter: brightness(0.8);
}
@ -28,42 +33,41 @@
width: 320px;
height: 320px;
}
.camera-canvas {
position: relative;
width: 340px;
height: 462px;
background-image: url('../../assets/images/room-widgets/camera-widget/camera-spritesheet.png');
background-image: url("../../assets/images/room-widgets/camera-widget/camera-spritesheet.png");
background-position: -1px -1px;
z-index: 2;
.camera-button {
width: 94px;
height: 94px;
cursor: pointer;
margin-top: 362px;
background-image: url('../../assets/images/room-widgets/camera-widget/camera-spritesheet.png');
background-image: url("../../assets/images/room-widgets/camera-widget/camera-spritesheet.png");
background-position: -343px -321px;
&:hover {
background-position: -535px -321px;
}
&:active {
background-position: -439px -321px;
}
}
.camera-view-finder {
background-image: url('../../assets/images/room-widgets/camera-widget/camera-spritesheet.png');
background-image: url("../../assets/images/room-widgets/camera-widget/camera-spritesheet.png");
background-position: -343px -1px;
}
.camera-frame {
.camera-frame-preview-actions {
background: rgba(0, 0, 0, .5);
background: rgba(0, 0, 0, 0.5);
}
}
}
@ -80,6 +84,8 @@
width: 56px;
height: 56px;
border: 1px solid black;
object-fit: contain;
image-rendering: initial;
}
}
}
@ -87,7 +93,7 @@
.nitro-camera-editor {
width: $camera-editor-width;
height: $camera-editor-height;
.picture-preview {
width: 320px;
height: 320px;
@ -99,7 +105,6 @@
}
.effect-thumbnail-image {
img {
width: 50px;
height: 50px;

View File

@ -1,6 +1,6 @@
import { IRoomCameraWidgetEffect, IRoomCameraWidgetSelectedEffect } from '@nitrots/nitro-renderer';
import { FC } from 'react';
import { AutoGrid } from '../../../../../common/AutoGrid';
import { Grid } from '../../../../../common';
import { CameraPictureThumbnail } from '../../../common/CameraPictureThumbnail';
import { CameraWidgetEffectListItemView } from './CameraWidgetEffectListItemView';
@ -18,7 +18,7 @@ export const CameraWidgetEffectListView: FC<CameraWidgetEffectListViewProps> = p
const { myLevel = 0, selectedEffects = [], effects = [], thumbnails = [], processAction = null } = props;
return (
<AutoGrid columnCount={ 2 } columnMinHeight={ 60 }>
<Grid columnCount={ 3 } overflow="auto">
{ effects && (effects.length > 0) && effects.map((effect, index) =>
{
const thumbnailUrl = (thumbnails.find(thumbnail => (thumbnail.effectName === effect.name)));
@ -26,6 +26,6 @@ export const CameraWidgetEffectListView: FC<CameraWidgetEffectListViewProps> = p
return <CameraWidgetEffectListItemView key={ index } effect={ effect } thumbnailUrl={ ((thumbnailUrl && thumbnailUrl.thumbnailUrl) || null) } isActive={ isActive } isLocked={ (effect.minLevel > myLevel) } selectEffect={ () => processAction('select_effect', effect.name) } removeEffect={ () => processAction('remove_effect', effect.name) } />
}) }
</AutoGrid>
</Grid>
);
}

View File

@ -109,7 +109,7 @@ export const RoomColorView: FC<{}> = props =>
{
if(!roomSession) return;
const canvas = GetRoomEngine().getRoomInstanceRenderingCanvas(GetRoomEngine().activeRoomId, 1);
const canvas = GetRoomEngine().getRoomInstanceRenderingCanvas(roomSession.roomId, 1);
if(!canvas) return;

View File

@ -88,9 +88,7 @@ export const RoomView: FC<{}> = props =>
const roomEngine = GetRoomEngine();
const roomId = roomSession.roomId;
const canvasId = 1;
const displayObject = roomEngine.getRoomInstanceDisplay(roomId, canvasId, (window.innerWidth * window.devicePixelRatio), (window.innerHeight * window.devicePixelRatio), RoomGeometry.SCALE_ZOOMED_IN);
if((window.devicePixelRatio !== 1) && ((window.devicePixelRatio % 1) === 0)) roomEngine.setRoomInstanceRenderingCanvasScale(roomId, canvasId, window.devicePixelRatio);
const displayObject = roomEngine.getRoomInstanceDisplay(roomId, canvasId, window.innerWidth, window.innerHeight, RoomGeometry.SCALE_ZOOMED_IN);
if(!displayObject) return;
@ -141,25 +139,20 @@ export const RoomView: FC<{}> = props =>
canvas.ontouchend = event => DispatchTouchEvent(event);
canvas.ontouchcancel = event => DispatchTouchEvent(event);
if(window.devicePixelRatio !== 1)
{
let scaleValue = (1 / window.devicePixelRatio);
canvas.style.transform = `scale(${ scaleValue })`;
canvas.style.transformOrigin = 'top left';
canvas.style.width = `${ (100 * window.devicePixelRatio) }%`;
canvas.style.height = `${ (100 * window.devicePixelRatio) }%`;
}
canvas.style.width = `${ Math.floor(window.innerWidth) }px`;
canvas.style.height = `${ Math.floor(window.innerHeight) }px`;
const resize = (event: UIEvent) =>
{
canvas.style.width = `${ Math.floor(window.innerWidth) }px`;
canvas.style.height = `${ Math.floor(window.innerHeight) }px`;
const nitroInstance = GetNitroInstance();
const width = (window.innerWidth * window.devicePixelRatio);
const height = (window.innerHeight * window.devicePixelRatio);
nitroInstance.renderer.resize(width, height);
nitroInstance.renderer.resolution = window.devicePixelRatio;
nitroInstance.renderer.resize(window.innerWidth, window.innerHeight);
InitializeRoomInstanceRenderingCanvas(width, height, 1);
InitializeRoomInstanceRenderingCanvas(window.innerWidth, window.innerHeight, 1);
nitroInstance.render();
}
@ -180,8 +173,7 @@ export const RoomView: FC<{}> = props =>
return (
<RoomContextProvider value={ { roomSession, eventDispatcher: (widgetHandler && widgetHandler.eventDispatcher), widgetHandler } }>
<Base fit className={ (!roomSession && 'd-none') }>
<Base innerRef={ elementRef } />
<Base fit innerRef={ elementRef } className={ (!roomSession && 'd-none') }>
{ (roomSession && widgetHandler) &&
<>
<RoomColorView />

View File

@ -69,7 +69,7 @@ export const AvatarInfoUseProductConfirmView: FC<AvatarInfoUseProductConfirmView
}
}
return <LayoutPetImageView typeId={ petFigureData.typeId } paletteId={ paletteId } color={ petFigureData.color } customParts={ petFigureData.customParts } direction={ 2 } />
return <LayoutPetImageView typeId={ petFigureData.typeId } paletteId={ paletteId } petColor={ petFigureData.color } customParts={ petFigureData.customParts } direction={ 2 } />
}
case FurniCategory.PET_CUSTOM_PART: {
if(customParts.length < 4) return null;
@ -96,7 +96,7 @@ export const AvatarInfoUseProductConfirmView: FC<AvatarInfoUseProductConfirmView
_local_10++;
}
return <LayoutPetImageView typeId={ petFigureData.typeId } paletteId={ petFigureData.paletteId } color={ petFigureData.color } customParts={ newCustomParts } direction={ 2 } />;
return <LayoutPetImageView typeId={ petFigureData.typeId } paletteId={ petFigureData.paletteId } petColor={ petFigureData.color } customParts={ newCustomParts } direction={ 2 } />;
}
case FurniCategory.PET_CUSTOM_PART_SHAMPOO: {
if(customParts.length < 3) return null;
@ -122,7 +122,7 @@ export const AvatarInfoUseProductConfirmView: FC<AvatarInfoUseProductConfirmView
_local_10++;
}
return <LayoutPetImageView typeId={ petFigureData.typeId } paletteId={ petFigureData.paletteId } color={ petFigureData.color } customParts={ newCustomParts } direction={ 2 } />;
return <LayoutPetImageView typeId={ petFigureData.typeId } paletteId={ petFigureData.paletteId } petColor={ petFigureData.color } customParts={ newCustomParts } direction={ 2 } />;
}
case FurniCategory.PET_SADDLE: {
if(customParts.length < 4) return null;
@ -150,7 +150,7 @@ export const AvatarInfoUseProductConfirmView: FC<AvatarInfoUseProductConfirmView
}
}
return <LayoutPetImageView typeId={ petFigureData.typeId } paletteId={ petFigureData.paletteId } color={ petFigureData.color } customParts={ newCustomParts } direction={ 2 } />;
return <LayoutPetImageView typeId={ petFigureData.typeId } paletteId={ petFigureData.paletteId } petColor={ petFigureData.color } customParts={ newCustomParts } direction={ 2 } />;
}
case FurniCategory.MONSTERPLANT_REBREED:
case FurniCategory.MONSTERPLANT_REVIVAL:
@ -172,7 +172,7 @@ export const AvatarInfoUseProductConfirmView: FC<AvatarInfoUseProductConfirmView
}
}
return <LayoutPetImageView typeId={ petFigureData.typeId } paletteId={ petFigureData.paletteId } color={ petFigureData.color } customParts={ petFigureData.customParts } posture={ posture } direction={ 2 } />;
return <LayoutPetImageView typeId={ petFigureData.typeId } paletteId={ petFigureData.paletteId } petColor={ petFigureData.color } customParts={ petFigureData.customParts } posture={ posture } direction={ 2 } />;
}
}
}, [ petData, furniData, roomSession ]);

View File

@ -697,15 +697,15 @@
.user-image {
position: absolute;
top: -48px;
left: -32.5px;
width: 90px;
height: 130px;
top: -15px;
left: -9.25px;
width: 45px;
height: 65px;
background-repeat: no-repeat;
background-position: center;
transform: scale(0.5);
overflow: hidden;
image-rendering: -webkit-optimize-contrast;
image-rendering: initial;
}
}

View File

@ -145,7 +145,7 @@ export const ChatWidgetView: FC<{}> = props =>
{
if(!chatMessages.length || (event.roomId !== roomSession.roomId)) return;
const offsetX = (event.offsetX / window.devicePixelRatio);
const offsetX = event.offsetX;
chatMessages.forEach(chat => (chat.elementRef && (chat.left += offsetX)));
}, [ roomSession, chatMessages ]);
@ -200,7 +200,7 @@ export const ChatWidgetView: FC<{}> = props =>
if(!elementRef || !elementRef.current) return;
const currentHeight = elementRef.current.offsetHeight;
const newHeight = (document.body.offsetHeight * GetConfiguration<number>('chat.viewer.height.percentage'));
const newHeight = Math.round(document.body.offsetHeight * GetConfiguration<number>('chat.viewer.height.percentage'));
elementRef.current.style.height = `${ newHeight }px`;
@ -208,17 +208,7 @@ export const ChatWidgetView: FC<{}> = props =>
{
if(prevValue)
{
prevValue.forEach(chat =>
{
if(chat.skipMovement)
{
chat.skipMovement = false;
return;
}
chat.top -= (currentHeight - newHeight);
});
prevValue.forEach(chat => (chat.top -= (currentHeight - newHeight)));
}
return prevValue;

View File

@ -27,9 +27,10 @@ export const RoomToolsWidgetView: FC<{}> = props =>
case 'zoom':
setIsZoomedIn(prevValue =>
{
let scale = ((window.devicePixelRatio !== 1) && ((window.devicePixelRatio % 1) === 0)) ? window.devicePixelRatio : 1;
let scale = GetRoomEngine().getRoomInstanceRenderingCanvasScale(roomSession.roomId, 1);
if(!prevValue) scale /= 2;
else scale *= 2;
GetRoomEngine().setRoomInstanceRenderingCanvasScale(roomSession.roomId, 1, scale);

View File

@ -78,7 +78,7 @@ export const ToolbarView: FC<{ isInRoom: boolean }> = props =>
<Flex gap={ 2 } alignItems="center">
<Flex alignItems="center" gap={ 2 }>
<Flex center pointer className={ 'navigation-item item-avatar ' + (isMeExpanded ? 'active ' : '') } onClick={ event => setMeExpanded(!isMeExpanded) }>
<LayoutAvatarImageView figure={ userFigure } direction={ 2 } />
<LayoutAvatarImageView figure={ userFigure } direction={ 2 } position="absolute" />
{ (getTotalUnseen > 0) &&
<LayoutItemCountView count={ getTotalUnseen } /> }
</Flex>

View File

@ -1,5 +1,4 @@
@import './assets/styles';
@import "./assets/styles";
html,
body {
@ -8,10 +7,13 @@ body {
height: 100%;
overflow: hidden;
user-select: none;
image-rendering: pixelated;
image-rendering: -moz-crisp-edges;
scrollbar-width: thin;
.image-rendering-pixelated {
image-rendering: pixelated;
image-rendering: -moz-crisp-edges;
}
* {
-webkit-font-smoothing: antialiased;
}
@ -21,4 +23,4 @@ img {
object-fit: none;
}
@import './App';
@import "./App";