Merge branch 'dev' into feature/hotelview

This commit is contained in:
Layne 2021-07-25 03:04:51 -04:00
commit d900891b10
99 changed files with 1228 additions and 484 deletions

View File

@ -1,6 +1,6 @@
import { ConfigurationEvent, LegacyExternalInterface, Nitro, NitroCommunicationDemoEvent, NitroEvent, NitroLocalizationEvent, RoomEngineEvent, WebGL } from 'nitro-renderer';
import { FC, useCallback, useState } from 'react';
import { GetConfiguration } from './api';
import { GetCommunication, GetConfiguration, GetNitroInstance } from './api';
import { useConfigurationEvent } from './hooks/events/core/configuration/configuration-event';
import { useLocalizationEvent } from './hooks/events/nitro/localization/localization-event';
import { dispatchMainEvent, useMainEvent } from './hooks/events/nitro/main-event';
@ -19,7 +19,7 @@ export const App: FC<{}> = props =>
//@ts-ignore
if(!NitroConfig) throw new Error('NitroConfig is not defined!');
if(!Nitro.instance) Nitro.bootstrap();
if(!GetNitroInstance()) Nitro.bootstrap();
const getPreloadAssetUrls = useCallback(() =>
{
@ -28,7 +28,7 @@ export const App: FC<{}> = props =>
if(assetUrls && assetUrls.length)
{
for(const url of assetUrls) urls.push(Nitro.instance.core.configuration.interpolate(url));
for(const url of assetUrls) urls.push(GetNitroInstance().core.configuration.interpolate(url));
}
return urls;
@ -39,7 +39,7 @@ export const App: FC<{}> = props =>
switch(event.type)
{
case ConfigurationEvent.LOADED:
Nitro.instance.localization.init();
GetNitroInstance().localization.init();
return;
case ConfigurationEvent.FAILED:
setIsError(true);
@ -73,14 +73,14 @@ export const App: FC<{}> = props =>
case NitroCommunicationDemoEvent.CONNECTION_AUTHENTICATED:
setMessage('Finishing Up');
Nitro.instance.init();
GetNitroInstance().init();
return;
case NitroCommunicationDemoEvent.CONNECTION_ERROR:
setIsError(true);
setMessage('Connection Error');
return;
case NitroCommunicationDemoEvent.CONNECTION_CLOSED:
if(Nitro.instance.roomEngine) Nitro.instance.roomEngine.dispose();
if(GetNitroInstance().roomEngine) GetNitroInstance().roomEngine.dispose();
setIsError(true);
setMessage('Connection Error');
@ -91,13 +91,13 @@ export const App: FC<{}> = props =>
setIsReady(true);
return;
case NitroLocalizationEvent.LOADED:
Nitro.instance.core.asset.downloadAssets(getPreloadAssetUrls(), (status: boolean) =>
GetNitroInstance().core.asset.downloadAssets(getPreloadAssetUrls(), (status: boolean) =>
{
if(status)
{
setMessage('Connecting');
Nitro.instance.communication.init();
GetCommunication().init();
}
else
{
@ -127,7 +127,7 @@ export const App: FC<{}> = props =>
}
else
{
Nitro.instance.core.configuration.init();
GetNitroInstance().core.configuration.init();
}
return (

View File

@ -1,6 +0,0 @@
import { CatalogPageComposer } from 'nitro-renderer';
export function GetCatalogPageComposer(...args: ConstructorParameters<typeof CatalogPageComposer>): CatalogPageComposer
{
return new CatalogPageComposer(...args);
}

View File

@ -0,0 +1,7 @@
import { IConfigurationManager } from 'nitro-renderer';
import { GetNitroCore } from './GetNitroCore';
export function GetConfigurationManager(): IConfigurationManager
{
return GetNitroCore().configuration;
}

View File

@ -0,0 +1,7 @@
import { INitroCore } from 'nitro-renderer';
import { GetNitroInstance } from '../nitro';
export function GetNitroCore(): INitroCore
{
return GetNitroInstance().core;
}

2
src/api/core/index.ts Normal file
View File

@ -0,0 +1,2 @@
export * from './GetConfigurationManager';
export * from './GetNitroCore';

View File

@ -1 +1,2 @@
export * from './core';
export * from './nitro';

View File

@ -0,0 +1,7 @@
import { ILinkEventTracker } from 'nitro-renderer';
import { GetNitroInstance } from './GetNitroInstance';
export function AddEventLinkTracker(tracker: ILinkEventTracker): void
{
GetNitroInstance().addLinkEventTracker(tracker);
}

View File

@ -0,0 +1,7 @@
import { INitroCommunicationManager } from 'nitro-renderer';
import { GetNitroInstance } from './GetNitroInstance';
export function GetCommunication(): INitroCommunicationManager
{
return GetNitroInstance().communication;
}

View File

@ -1,6 +1,6 @@
import { Nitro } from 'nitro-renderer';
import { GetNitroInstance } from './GetNitroInstance';
export function GetConfiguration<T>(key: string, value: T = null): T
{
return Nitro.instance.getConfiguration(key, value);
return GetNitroInstance().getConfiguration(key, value);
}

View File

@ -1,6 +1,7 @@
import { IConnection, Nitro } from 'nitro-renderer';
import { IConnection } from 'nitro-renderer';
import { GetCommunication } from './GetCommunication';
export function GetConnection(): IConnection
{
return Nitro.instance.communication.connection;
return GetCommunication().connection;
}

View File

@ -0,0 +1,6 @@
import { INitro, Nitro } from 'nitro-renderer';
export function GetNitroInstance(): INitro
{
return Nitro.instance;
}

View File

@ -1,6 +1,6 @@
import { Nitro } from 'nitro-renderer';
import { GetNitroInstance } from './GetNitroInstance';
export function GetTicker()
{
return Nitro.instance.ticker;
return GetNitroInstance().ticker;
}

View File

@ -0,0 +1,7 @@
import { ILinkEventTracker } from 'nitro-renderer';
import { GetNitroInstance } from './GetNitroInstance';
export function RemoveLinkEventTracker(tracker: ILinkEventTracker): void
{
GetNitroInstance().removeLinkEventTracker(tracker);
}

View File

@ -1,6 +1,7 @@
import { IAvatarRenderManager, Nitro } from 'nitro-renderer';
import { IAvatarRenderManager } from 'nitro-renderer';
import { GetNitroInstance } from '../GetNitroInstance';
export function GetAvatarRenderManager(): IAvatarRenderManager
{
return Nitro.instance.avatar;
return GetNitroInstance().avatar;
}

View File

@ -1,7 +1,7 @@
import { Nitro } from 'nitro-renderer';
import { IRoomCameraWidgetManager } from 'nitro-renderer/src/nitro/camera/IRoomCameraWidgetManager';
import { GetNitroInstance } from '../GetNitroInstance';
export function GetRoomCameraWidgetManager(): IRoomCameraWidgetManager
{
return Nitro.instance.cameraManager;
return GetNitroInstance().cameraManager;
}

View File

@ -1,7 +1,11 @@
export * from './AddLinkEventTracker';
export * from './avatar';
export * from './camera';
export * from './GetCommunication';
export * from './GetConfiguration';
export * from './GetConnection';
export * from './GetNitroInstance';
export * from './GetTicker';
export * from './RemoveLinkEventTracker';
export * from './room';
export * from './session';

View File

@ -1,6 +1,7 @@
import { IRoomEngine, Nitro } from 'nitro-renderer';
import { IRoomEngine } from 'nitro-renderer';
import { GetNitroInstance } from '../GetNitroInstance';
export function GetRoomEngine(): IRoomEngine
{
return Nitro.instance.roomEngine;
return GetNitroInstance().roomEngine;
}

View File

@ -1,6 +1,7 @@
import { IRoomSessionManager, Nitro } from 'nitro-renderer';
import { IRoomSessionManager } from 'nitro-renderer';
import { GetNitroInstance } from '../GetNitroInstance';
export function GetRoomSessionManager(): IRoomSessionManager
{
return Nitro.instance.roomSessionManager;
return GetNitroInstance().roomSessionManager;
}

View File

@ -1,6 +1,7 @@
import { ISessionDataManager, Nitro } from 'nitro-renderer';
import { ISessionDataManager } from 'nitro-renderer';
import { GetNitroInstance } from '../GetNitroInstance';
export function GetSessionDataManager(): ISessionDataManager
{
return Nitro.instance.sessionDataManager;
return GetNitroInstance().sessionDataManager;
}

View File

@ -81,7 +81,8 @@ $cello-dark: #1e465e !default;
$pale-sky: #677181 !default;
$oslo-gray: #8F9297 !default;
$gainsboro: #d9d9d9 !default;
$ghost: #c8cad0 !default;
$gray-chateau: #a3a7b1 !default;
$success: $green !default;
$info: $cyan !default;
$warning: $yellow !default;

View File

@ -0,0 +1,6 @@
import { NitroEvent } from 'nitro-renderer';
export class InventoryBadgesRequestEvent extends NitroEvent
{
public static REQUEST_BADGES: string = 'IBRE_REQUEST_BADGES';
}

View File

@ -0,0 +1,20 @@
import { NitroEvent } from 'nitro-renderer';
export class InventoryBadgesUpdatedEvent extends NitroEvent
{
public static BADGES_UPDATED: string = 'IBUE_BADGES_UPDATED';
private _badges: string[] = [];
constructor(type: string, badges: string[] = [])
{
super(type);
this._badges = badges;
}
public get badges(): string[]
{
return this._badges;
}
}

View File

@ -1,3 +1,4 @@
export * from './InventoryBadgesUpdatedEvent';
export * from './InventoryEvent';
export * from './InventoryTradeRequestEvent';
export * from './InventoryTradeStartEvent';

View File

@ -1,8 +1,8 @@
import { NitroEvent } from 'nitro-renderer';
import { Nitro } from 'nitro-renderer/src/nitro/Nitro';
import { GetCommunication } from '../../../../api';
import { CreateEventDispatcherHook } from '../../event-dispatcher.base';
export function useCommunicationEvent(type: string, handler: (event: NitroEvent) => void): void
{
CreateEventDispatcherHook(type, Nitro.instance.communication.events, handler);
CreateEventDispatcherHook(type, GetCommunication().events, handler);
}

View File

@ -1,8 +1,8 @@
import { NitroEvent } from 'nitro-renderer';
import { Nitro } from 'nitro-renderer/src/nitro/Nitro';
import { GetConfigurationManager } from '../../../../api';
import { CreateEventDispatcherHook } from '../../event-dispatcher.base';
export function useConfigurationEvent(type: string, handler: (event: NitroEvent) => void): void
{
CreateEventDispatcherHook(type, Nitro.instance.core.configuration.events, handler);
CreateEventDispatcherHook(type, GetConfigurationManager().events, handler);
}

View File

@ -1 +1,2 @@
export * from './communication';
export * from './configuration';

View File

@ -1,8 +1,8 @@
import { NitroEvent } from 'nitro-renderer';
import { Nitro } from 'nitro-renderer/src/nitro/Nitro';
import { GetAvatarRenderManager } from '../../../../api';
import { CreateEventDispatcherHook } from '../../event-dispatcher.base';
export function useAvatarEvent(type: string, handler: (event: NitroEvent) => void): void
{
CreateEventDispatcherHook(type, Nitro.instance.avatar.events, handler);
CreateEventDispatcherHook(type, GetAvatarRenderManager().events, handler);
}

View File

@ -1,8 +1,8 @@
import { NitroEvent } from 'nitro-renderer';
import { Nitro } from 'nitro-renderer/src/nitro/Nitro';
import { GetNitroInstance } from '../../../../api';
import { CreateEventDispatcherHook } from '../../event-dispatcher.base';
export function useCameraEvent(type: string, handler: (event: NitroEvent) => void): void
{
CreateEventDispatcherHook(type, Nitro.instance.cameraManager.events, handler);
CreateEventDispatcherHook(type, GetNitroInstance().cameraManager.events, handler);
}

View File

@ -1,6 +1,5 @@
export * from './avatar';
export * from './camera';
export * from './communication';
export * from './localization';
export * from './main-event';
export * from './room';

View File

@ -1,8 +1,8 @@
import { NitroEvent } from 'nitro-renderer';
import { Nitro } from 'nitro-renderer/src/nitro/Nitro';
import { GetNitroInstance } from '../../../../api';
import { CreateEventDispatcherHook } from '../../event-dispatcher.base';
export function useLocalizationEvent(type: string, handler: (event: NitroEvent) => void): void
{
CreateEventDispatcherHook(type, Nitro.instance.localization.events, handler);
CreateEventDispatcherHook(type, GetNitroInstance().localization.events, handler);
}

View File

@ -1,12 +1,13 @@
import { Nitro, NitroEvent } from 'nitro-renderer';
import { NitroEvent } from 'nitro-renderer';
import { GetNitroInstance } from '../../../api';
import { CreateEventDispatcherHook, DispatchEventHook } from '../event-dispatcher.base';
export function useMainEvent(type: string, handler: (event: NitroEvent) => void): void
{
CreateEventDispatcherHook(type, Nitro.instance.events, handler);
CreateEventDispatcherHook(type, GetNitroInstance().events, handler);
}
export function dispatchMainEvent(event: NitroEvent): void
{
DispatchEventHook(Nitro.instance.events, event);
DispatchEventHook(GetNitroInstance().events, event);
}

View File

@ -1,8 +1,8 @@
import { NitroEvent } from 'nitro-renderer';
import { Nitro } from 'nitro-renderer/src/nitro/Nitro';
import { GetRoomEngine } from '../../../../api';
import { CreateEventDispatcherHook } from '../../event-dispatcher.base';
export function useRoomEngineEvent(type: string, handler: (event: NitroEvent) => void): void
{
CreateEventDispatcherHook(type, Nitro.instance.roomEngine.events, handler);
CreateEventDispatcherHook(type, GetRoomEngine().events, handler);
}

View File

@ -1,7 +1,8 @@
import { Nitro, NitroEvent } from 'nitro-renderer';
import { NitroEvent } from 'nitro-renderer';
import { GetRoomSessionManager } from '../../../../api';
import { CreateEventDispatcherHook } from '../../event-dispatcher.base';
export function useRoomSessionManagerEvent(type: string, handler: (event: NitroEvent) => void): void
{
CreateEventDispatcherHook(type, Nitro.instance.roomSessionManager.events, handler);
CreateEventDispatcherHook(type, GetRoomSessionManager().events, handler);
}

View File

@ -1,13 +1,6 @@
export * from './events';
export * from './events/core';
export * from './events/core/configuration';
export * from './events/nitro';
export * from './events/nitro/avatar';
export * from './events/nitro/camera';
export * from './events/nitro/communication';
export * from './events/nitro/localization';
export * from './events/nitro/room';
export * from './events/nitro/session';
export * from './events/ui';
export * from './messages';
export * from './UseMountEffect';

View File

@ -1,6 +1,6 @@
import { IMessageComposer, IMessageEvent, MessageEvent } from 'nitro-renderer';
import { Nitro } from 'nitro-renderer/src/nitro/Nitro';
import { useEffect } from 'react';
import { GetCommunication, GetConnection } from '../../api';
export function CreateMessageHook(eventType: typeof MessageEvent, handler: (event: IMessageEvent) => void): void
{
@ -9,13 +9,13 @@ export function CreateMessageHook(eventType: typeof MessageEvent, handler: (even
//@ts-ignore
const event = new eventType(handler);
Nitro.instance.communication.registerMessageEvent(event);
GetCommunication().registerMessageEvent(event);
return () => Nitro.instance.communication.removeMessageEvent(event);
return () => GetCommunication().removeMessageEvent(event);
}, [ eventType, handler ]);
}
export function SendMessageHook(event: IMessageComposer<unknown[]>): void
{
Nitro.instance.communication.connection.send(event);
GetConnection().send(event);
}

View File

@ -64,11 +64,9 @@
}
.avatar-image {
width: 100% !important;
height: 100% !important;
background-position: center;
background-repeat: no-repeat;
background-position-y: -32px !important;
background-position-y: 12px !important;
}
.trade-button {

View File

@ -1,6 +1,6 @@
import { Nitro } from 'nitro-renderer';
import { GetNitroInstance } from '../api';
export function LocalizeBadgeName(key: string): string
{
return Nitro.instance.localization.getBadgeName(key);
return GetNitroInstance().localization.getBadgeName(key);
}

View File

@ -1,6 +1,6 @@
import { Nitro } from 'nitro-renderer';
import { GetNitroInstance } from '../api';
export function LocalizeText(key: string, parameters: string[] = null, replacements: string[] = null): string
{
return Nitro.instance.getLocalizationWithParameters(key, parameters, replacements);
return GetNitroInstance().getLocalizationWithParameters(key, parameters, replacements);
}

View File

@ -83,8 +83,36 @@
.wardrobe-grid {
.grid-item-container {
height: 100% !important;
max-height: 100% !important;
height: 142px !important;
max-height: 142px !important;
.grid-item {
background-color: $ghost;
.avatar-image {
position: absolute;
bottom: 0;
background-position-y: -23px !important;
z-index: 3;
}
.figure-button-container {
background-color: $gray-chateau;
z-index: 2;
}
&:after {
position: absolute;
content: '';
height: 50%;
bottom: 0;
left: 0;
right: 0;
background-color: $gray-chateau;
box-shadow: 0 0 8px 2px rgba($white,.6);
z-index: 1;
}
}
}
}
}

View File

@ -79,12 +79,20 @@ export const AvatarEditorView: FC<AvatarEditorViewProps> = props =>
const onUserWardrobePageEvent = useCallback((event: UserWardrobePageEvent) =>
{
const parser = event.getParser();
const savedFigures: [ string, string ][] = [];
const savedFigures: [ string, string ][] = new Array(MAX_SAVED_FIGURES);
let i = 0;
for(const value of parser.looks.values())
while(i < MAX_SAVED_FIGURES)
{
console.log(value);
savedFigures.push([ null, null ]);
i++;
}
for(let [ index, value ] of parser.looks.entries())
{
savedFigures[(index - 1)] = [ value[0], value[1] ];
}
setSavedFigures(savedFigures)
@ -280,7 +288,7 @@ export const AvatarEditorView: FC<AvatarEditorViewProps> = props =>
<div className="row h-100">
<div className="col-9 d-flex flex-column h-100">
{ (activeCategory && !isWardrobeVisible) && <AvatarEditorModelView model={ activeCategory } gender={ figureData.gender } setGender={ setGender } /> }
{ isWardrobeVisible && <AvatarEditorWardrobeView figures={ savedFigures } /> }
{ isWardrobeVisible && <AvatarEditorWardrobeView figureData={ figureData } savedFigures={ savedFigures } setSavedFigures={ setSavedFigures } loadAvatarInEditor={ loadAvatarInEditor } /> }
</div>
<div className="col-3 d-flex flex-column h-100">
<div className="figure-preview-container">

View File

@ -162,7 +162,7 @@ export class AvatarEditorUtilities
partItems.sort(this.clubItemsFirst ? this.clubSorter : this.noobSorter);
// if(this._forceSellableClothingVisibility || Nitro.instance.getConfiguration<boolean>("avatareditor.support.sellablefurni", false))
// if(this._forceSellableClothingVisibility || GetNitroInstance().getConfiguration<boolean>("avatareditor.support.sellablefurni", false))
// {
// _local_31 = (this._manager.windowManager.assets.getAssetByName("camera_zoom_in") as BitmapDataAsset);
// _local_32 = (_local_31.content as BitmapData).clone();

View File

@ -206,7 +206,7 @@ export class FigureData
{
const colors = this._colors.get(setType);
if(colors === undefined) continue;
if(!colors) continue;
let setId = this._data.get(setType);

View File

@ -1,4 +1,7 @@
import { FC, useMemo } from 'react';
import { UserWardrobeSaveComposer } from 'nitro-renderer';
import { FC, useCallback, useMemo } from 'react';
import { Button } from 'react-bootstrap';
import { SendMessageHook } from '../../../../hooks';
import { NitroCardGridItemView } from '../../../../layout/card/grid/item/NitroCardGridItemView';
import { NitroCardGridView } from '../../../../layout/card/grid/NitroCardGridView';
import { NitroCardGridThemes } from '../../../../layout/card/grid/NitroCardGridView.types';
@ -7,48 +10,68 @@ import { AvatarEditorWardrobeViewProps } from './AvatarEditorWardrobeView.types'
export const AvatarEditorWardrobeView: FC<AvatarEditorWardrobeViewProps> = props =>
{
const { figures = [] } = props;
const { figureData = null, savedFigures = [], setSavedFigures = null, loadAvatarInEditor = null } = props;
const savedFigures = useMemo(() =>
const wearFigureAtIndex = useCallback((index: number) =>
{
if(!figures) return [];
if((index >= savedFigures.length) || (index < 0)) return;
let i = 0;
const [ figure, gender ] = savedFigures[index];
loadAvatarInEditor(figure, gender);
}, [ savedFigures, loadAvatarInEditor ]);
const saveFigureAtWardrobeIndex = useCallback((index: number) =>
{
if(!figureData || (index >= savedFigures.length) || (index < 0)) return;
const newFigures = [ ...savedFigures ];
const figure = figureData.getFigureString();
const gender = figureData.gender;
newFigures[index] = [ figure, gender ];
setSavedFigures(newFigures);
SendMessageHook(new UserWardrobeSaveComposer((index + 1), figure, gender));
}, [ figureData, savedFigures, setSavedFigures ]);
const figures = useMemo(() =>
{
if(!savedFigures) return [];
const items: JSX.Element[] = [];
while(i < figures.length)
{
const figure = figures[i];
let figureString = null;
let gender = null;
if(figure)
savedFigures.forEach((figure, index) =>
{
figureString = (figure[0] || null);
gender = (figure[1] || null);
}
let figureString = null;
let gender = null;
items.push(
<NitroCardGridItemView key={ i } columns={ 2 }>
<AvatarImageView figure={ figureString } gender={ gender } />
</NitroCardGridItemView>
);
i++
}
if(figure)
{
figureString = (figure[0] || null);
gender = (figure[1] || null);
}
items.push(
<NitroCardGridItemView key={ index } className="flex-column justify-content-end">
{ figureString && <AvatarImageView figure={ figureString } gender={ gender } direction={ 2 } /> }
<div className="d-flex w-100 figure-button-container p-1">
<Button variant="link" size="sm" className="w-100" onClick={ event => saveFigureAtWardrobeIndex(index) }>Save</Button>
{ figureString && <Button variant="link" size="sm" className="w-100" onClick={ event => wearFigureAtIndex(index) }>Use</Button> }
</div>
</NitroCardGridItemView>
);
});
return items;
}, [ figures ]);
console.log(figures.length);
}, [ savedFigures, saveFigureAtWardrobeIndex, wearFigureAtIndex ]);
return (
<div className="row h-100">
<div className="col-12 d-flex h-100">
<NitroCardGridView className="wardrobe-grid" columns={ 12 } theme={ NitroCardGridThemes.THEME_DEFAULT }>
{ savedFigures }
<NitroCardGridView className="wardrobe-grid" columns={ 5 } theme={ NitroCardGridThemes.THEME_DEFAULT }>
{ figures }
</NitroCardGridView>
</div>
</div>

View File

@ -1,4 +1,10 @@
import { Dispatch, SetStateAction } from 'react';
import { FigureData } from '../../common/FigureData';
export interface AvatarEditorWardrobeViewProps
{
figures: [ string, string ][];
figureData: FigureData;
savedFigures: [ string, string ][];
setSavedFigures: Dispatch<SetStateAction<[ string, string][]>>;
loadAvatarInEditor: (figure: string, gender: string, reset?: boolean) => void;
}

View File

@ -127,11 +127,11 @@ export const CatalogMessageHandler: FC<CatalogMessageHandlerProps> = props =>
type: CatalogActions.SET_SUBSCRIPTION_INFO,
payload: {
subscriptionInfo: new SubscriptionInfo(
Math.max(0, parser.days),
Math.max(0, parser.months),
Math.max(0, parser.daysToPeriodEnd),
Math.max(0, parser.periodsSubscribedAhead),
parser.isVip,
parser.pastClubDays,
parser.pastVIPDays
parser.pastVipDays
)
}
});
@ -149,8 +149,6 @@ export const CatalogMessageHandler: FC<CatalogMessageHandlerProps> = props =>
{
const parser = event.getParser();
console.log(parser);
dispatchCatalogState({
type: CatalogActions.SET_GIFT_CONFIGURATION,
payload: {

View File

@ -1,7 +1,6 @@
import { CatalogModeComposer, CatalogRequestGiftConfigurationComposer, ICatalogPageData, RoomPreviewer } from 'nitro-renderer';
import { CatalogModeComposer, CatalogPageComposer, CatalogRequestGiftConfigurationComposer, ICatalogPageData, ILinkEventTracker, RoomPreviewer } from 'nitro-renderer';
import { FC, useCallback, useEffect, useReducer, useState } from 'react';
import { GetRoomEngine } from '../../api';
import { GetCatalogPageComposer } from '../../api/catalog/GetCatalogPageComposer';
import { AddEventLinkTracker, GetRoomEngine, RemoveLinkEventTracker } from '../../api';
import { CatalogEvent } from '../../events';
import { useUiEvent } from '../../hooks/events/ui/ui-event';
import { SendMessageHook } from '../../hooks/messages/message-event';
@ -9,6 +8,7 @@ import { NitroCardContentView, NitroCardHeaderView, NitroCardTabsItemView, Nitro
import { LocalizeText } from '../../utils/LocalizeText';
import { CatalogMessageHandler } from './CatalogMessageHandler';
import { CatalogMode, CatalogViewProps } from './CatalogView.types';
import { GetCatalogPageTree } from './common/CatalogUtilities';
import { CatalogContextProvider } from './context/CatalogContext';
import { CatalogActions, CatalogReducer, initialCatalog } from './reducers/CatalogReducer';
import { CatalogNavigationView } from './views/navigation/CatalogNavigationView';
@ -18,8 +18,10 @@ export const CatalogView: FC<CatalogViewProps> = props =>
{
const [ isVisible, setIsVisible ] = useState(false);
const [ roomPreviewer, setRoomPreviewer ] = useState<RoomPreviewer>(null);
const [ pendingPageId, setPendingPageId ] = useState(-1);
const [ pendingTree, setPendingTree ] = useState<ICatalogPageData[]>(null);
const [ catalogState, dispatchCatalogState ] = useReducer(CatalogReducer, initialCatalog);
const { root = null, currentTab = null, pageParser = null, activeOffer = null, searchResult = null } = catalogState;
const { root = null, currentTab = null, pageParser = null, activeOffer = null, searchResult = null} = catalogState;
const onCatalogEvent = useCallback((event: CatalogEvent) =>
{
@ -42,22 +44,99 @@ export const CatalogView: FC<CatalogViewProps> = props =>
useUiEvent(CatalogEvent.TOGGLE_CATALOG, onCatalogEvent);
useUiEvent(CatalogEvent.CATALOG_RESET, onCatalogEvent);
const setCurrentTab = useCallback((page: ICatalogPageData) =>
{
dispatchCatalogState({
type: CatalogActions.SET_CATALOG_CURRENT_TAB,
payload: {
currentTab: page
}
});
}, [ dispatchCatalogState ]);
const buildCatalogPageTree = useCallback((page: ICatalogPageData, targetPageId: number) =>
{
const pageTree: ICatalogPageData[] = [];
GetCatalogPageTree(page, targetPageId, pageTree);
if(pageTree.length) pageTree.reverse();
return pageTree;
}, []);
const linkReceived = useCallback((url: string) =>
{
const parts = url.split('/');
if(parts.length < 2) return;
switch(parts[1])
{
case 'open':
if(parts.length > 2)
{
dispatchCatalogState({
type: CatalogActions.SET_PENDING_PAGE_ID,
payload: {
pendingPageId: parseInt(parts[2])
}
});
}
else
{
setIsVisible(true);
}
return;
}
}, [ dispatchCatalogState ]);
useEffect(() =>
{
if(!isVisible) return;
if(!catalogState.root)
const linkTracker: ILinkEventTracker = {
linkReceived,
eventUrlPrefix: 'catalog/'
};
AddEventLinkTracker(linkTracker);
return () => RemoveLinkEventTracker(linkTracker);
}, [ linkReceived]);
useEffect(() =>
{
const loadCatalog = (((pendingPageId > -1) && !catalogState.root) || (isVisible && !catalogState.root));
if(loadCatalog)
{
SendMessageHook(new CatalogModeComposer(CatalogMode.MODE_NORMAL));
SendMessageHook(new CatalogRequestGiftConfigurationComposer());
}
}, [ isVisible, catalogState.root ]);
if(catalogState.root)
{
if(!isVisible && (pendingPageId > -1))
{
setIsVisible(true);
return;
}
if(pendingPageId > -1)
{
const tree = buildCatalogPageTree(catalogState.root, pendingPageId);
setCurrentTab(tree.shift());
setPendingTree(tree);
}
}
}, [ isVisible, pendingPageId, catalogState.root, buildCatalogPageTree, setCurrentTab ]);
useEffect(() =>
{
if(!currentTab) return;
SendMessageHook(GetCatalogPageComposer(currentTab.pageId, -1, CatalogMode.MODE_NORMAL));
SendMessageHook(new CatalogPageComposer(currentTab.pageId, -1, CatalogMode.MODE_NORMAL));
}, [ currentTab ]);
useEffect(() =>
@ -75,16 +154,6 @@ export const CatalogView: FC<CatalogViewProps> = props =>
}
}, []);
const setCurrentTab = useCallback((page: ICatalogPageData) =>
{
dispatchCatalogState({
type: CatalogActions.SET_CATALOG_CURRENT_TAB,
payload: {
currentTab: page
}
});
}, [ dispatchCatalogState ]);
const currentNavigationPage = ((searchResult && searchResult.page) || currentTab);
return (
@ -105,7 +174,7 @@ export const CatalogView: FC<CatalogViewProps> = props =>
</NitroCardTabsView>
<NitroCardContentView>
<div className="row h-100">
{ pageParser && !pageParser.frontPageItems.length &&
{ (!pageParser || (pageParser && !pageParser.frontPageItems.length)) &&
<div className="col-3 d-flex flex-column h-100">
<CatalogNavigationView page={ currentNavigationPage } />
</div> }

View File

@ -149,3 +149,20 @@ export function GetPetAvailableColors(petIndex: number, palettes: SellablePetPal
}
}
}
export function GetCatalogPageTree(page: ICatalogPageData, targetPageId: number, tree: ICatalogPageData[])
{
if(page.pageId === targetPageId) return page;
for(const pageData of page.children)
{
const foundPageData = GetCatalogPageTree(pageData, targetPageId, tree);
if(foundPageData)
{
tree.push(pageData);
return pageData;
}
}
}

View File

@ -1,4 +1,4 @@
import { Nitro } from 'nitro-renderer';
import { GetNitroInstance } from '../../../api';
import { IPurse } from './IPurse';
export class Purse implements IPurse
@ -22,7 +22,7 @@ export class Purse implements IPurse
public set credits(k: number)
{
this._lastUpdated = Nitro.instance.time;
this._lastUpdated = GetNitroInstance().time;
this._credits = k;
}
@ -33,7 +33,7 @@ export class Purse implements IPurse
public set clubDays(k: number)
{
this._lastUpdated = Nitro.instance.time;
this._lastUpdated = GetNitroInstance().time;
this._clubDays = k;
}
@ -44,7 +44,7 @@ export class Purse implements IPurse
public set clubPeriods(k: number)
{
this._lastUpdated = Nitro.instance.time;
this._lastUpdated = GetNitroInstance().time;
this._clubPeriods = k;
}
@ -80,7 +80,7 @@ export class Purse implements IPurse
public set _Str_6288(k: number)
{
this._lastUpdated = Nitro.instance.time;
this._lastUpdated = GetNitroInstance().time;
this._pastClubDays = k;
}
@ -91,7 +91,7 @@ export class Purse implements IPurse
public set _Str_4605(k: number)
{
this._lastUpdated = Nitro.instance.time;
this._lastUpdated = GetNitroInstance().time;
this._pastVipDays = k;
}
@ -102,7 +102,7 @@ export class Purse implements IPurse
public set _Str_18527(k: Map<number, number>)
{
this._lastUpdated = Nitro.instance.time;
this._lastUpdated = GetNitroInstance().time;
this._activityPoints = k;
}
@ -113,14 +113,14 @@ export class Purse implements IPurse
public set _Str_4458(k: number)
{
this._lastUpdated = Nitro.instance.time;
this._lastUpdated = GetNitroInstance().time;
this._minutesUntilExpiration = k;
}
public get _Str_4458(): number
{
const k = ((Nitro.instance.time - this._lastUpdated) / (1000 * 60));
const k = ((GetNitroInstance().time - this._lastUpdated) / (1000 * 60));
const _local_2 = (this._minutesUntilExpiration - k);
return (_local_2 > 0) ? _local_2 : 0;
@ -128,7 +128,7 @@ export class Purse implements IPurse
public set _Str_6312(k: number)
{
this._lastUpdated = Nitro.instance.time;
this._lastUpdated = GetNitroInstance().time;
this._minutesSinceLastModified = k;
}

View File

@ -19,6 +19,7 @@ export interface ICatalogState
clubOffers: CatalogClubOfferData[];
subscriptionInfo: SubscriptionInfo;
giftConfiguration: GiftWrappingConfiguration;
pendingPageId: number;
}
export interface ICatalogAction
@ -37,6 +38,7 @@ export interface ICatalogAction
clubOffers?: CatalogClubOfferData[];
subscriptionInfo?: SubscriptionInfo;
giftConfiguration?: CatalogGiftConfigurationParser;
pendingPageId?: number;
}
}
@ -54,6 +56,7 @@ export class CatalogActions
public static SET_SEARCH_RESULT: string = 'CA_SET_SEARCH_RESULT';
public static SET_SUBSCRIPTION_INFO: string = 'CA_SET_SUBSCRIPTION_INFO';
public static SET_GIFT_CONFIGURATION: string = 'CA_SET_GIFT_CONFIGURATION';
public static SET_PENDING_PAGE_ID: string = 'CA_SET_PENDING_PAGE_ID';
}
export const initialCatalog: ICatalogState = {
@ -68,7 +71,8 @@ export const initialCatalog: ICatalogState = {
petPalettes: [],
clubOffers: null,
subscriptionInfo: new SubscriptionInfo(),
giftConfiguration: null
giftConfiguration: null,
pendingPageId: -1
}
export const CatalogReducer: Reducer<ICatalogState, ICatalogAction> = (state, action) =>
@ -168,6 +172,11 @@ export const CatalogReducer: Reducer<ICatalogState, ICatalogAction> = (state, ac
return { ...state, giftConfiguration };
}
case CatalogActions.SET_PENDING_PAGE_ID: {
const pendingPageId = (action.payload.pendingPageId || -1);
return { ...state, pendingPageId };
}
default:
return state;
}

View File

@ -1,7 +1,8 @@
import { CatalogPageComposer, ICatalogPageData } from 'nitro-renderer';
import { FC, useCallback, useEffect, useState } from 'react';
import { GetCatalogPageComposer } from '../../../../../api/catalog/GetCatalogPageComposer';
import { SendMessageHook } from '../../../../../hooks/messages/message-event';
import { CatalogMode } from '../../../CatalogView.types';
import { useCatalogContext } from '../../../context/CatalogContext';
import { CatalogIconView } from '../../catalog-icon/CatalogIconView';
import { CatalogNavigationSetView } from '../set/CatalogNavigationSetView';
import { CatalogNavigationItemViewProps } from './CatalogNavigationItemView.types';
@ -10,42 +11,46 @@ export const CatalogNavigationItemView: FC<CatalogNavigationItemViewProps> = pro
{
const { page = null, isActive = false, setActiveChild = null } = props;
const [ isExpanded, setIsExpanded ] = useState(false);
const [ myTree, setMyTree ] = useState<ICatalogPageData[]>(null);
const { dispatchCatalogState = null } = useCatalogContext();
useEffect(() =>
const select = useCallback((selectPage: ICatalogPageData) =>
{
if(!isActive || !page) return;
setIsExpanded(true);
SendMessageHook(GetCatalogPageComposer(page.pageId, -1, CatalogMode.MODE_NORMAL));
}, [ isActive, page ]);
const select = useCallback(() =>
{
if(!page) return;
if(!selectPage) return;
setActiveChild(prevValue =>
{
if(prevValue === page)
if(prevValue === selectPage)
{
SendMessageHook(GetCatalogPageComposer(page.pageId, -1, CatalogMode.MODE_NORMAL));
SendMessageHook(new CatalogPageComposer(selectPage.pageId, -1, CatalogMode.MODE_NORMAL));
}
return page;
return selectPage;
});
if(page.children && page.children.length)
if(selectPage.children && selectPage.children.length)
{
setIsExpanded(prevValue =>
{
return !prevValue;
});
}
}, [ page, setActiveChild ]);
}, [ setActiveChild ]);
useEffect(() =>
{
if(!isActive || !page) return;
setIsExpanded(true);
SendMessageHook(new CatalogPageComposer(page.pageId, -1, CatalogMode.MODE_NORMAL));
}, [ isActive, page, select, dispatchCatalogState ]);
if(!page.visible) return null;
return (
<div className="col pb-1 catalog-navigation-item-container">
<div className={ 'd-flex align-items-center cursor-pointer catalog-navigation-item ' + (isActive ? 'active ': '') } onClick={ select }>
<div className={ 'd-flex align-items-center cursor-pointer catalog-navigation-item ' + (isActive ? 'active ': '') } onClick={ event => select(page) }>
<CatalogIconView icon={ page.icon } />
<div className="flex-grow-1 text-black text-truncate px-1">{ page.localization }</div>
{ (page.children.length > 0) && <i className={ 'fas fa-caret-' + (isExpanded ? 'up' : 'down') } /> }

View File

@ -1,3 +1,4 @@
@import './badge-display/CatalogLayoutBadgeDisplayView';
@import './default/CatalogLayoutDefaultView';
@import './frontpage4/CatalogLayoutFrontpage4View';
@import './pets/CatalogLayoutPetView';

View File

@ -1,4 +1,5 @@
import { ICatalogPageParser, RoomPreviewer } from 'nitro-renderer';
import { CatalogLayoutBadgeDisplayView } from './badge-display/CatalogLayoutBadgeDisplayView';
import { CatalogLayoutDefaultView } from './default/CatalogLayoutDefaultView';
import { CatalogLayoutFrontpage4View } from './frontpage4/CatalogLayoutFrontpage4View';
import { CatalogLayouGuildCustomFurniView } from './guild-custom-furni/CatalogLayoutGuildCustomFurniView';
@ -47,9 +48,11 @@ export const GetCatalogLayout = (pageParser: ICatalogPageParser, roomPreviewer:
case 'spaces_new':
return <CatalogLayoutSpacesView roomPreviewer={ roomPreviewer } pageParser={ pageParser } />;
case 'trophies':
return <CatalogLayoutTrophiesView roomPreviewer={roomPreviewer} pageParser={pageParser} />;
return <CatalogLayoutTrophiesView roomPreviewer={roomPreviewer} pageParser={ pageParser } />;
case 'info_loyalty':
return <CatalogLayoutInfoLoyaltyView roomPreviewer={ roomPreviewer } pageParser={ pageParser } />;
case 'badge_display':
return <CatalogLayoutBadgeDisplayView roomPreviewer={roomPreviewer} pageParser={ pageParser } />;
case 'bots':
case 'default_3x3':
default:

View File

@ -0,0 +1,7 @@
.nitro-catalog-layout-badge-display {
.inventory-badge-grid {
height: 200px;
max-height: 200px;
}
}

View File

@ -0,0 +1,80 @@
import { StringDataType } from 'nitro-renderer';
import { FC, useCallback, useEffect, useMemo, useState } from 'react';
import { InventoryBadgesUpdatedEvent } from '../../../../../../events';
import { InventoryBadgesRequestEvent } from '../../../../../../events/inventory/InventoryBadgesRequestEvent';
import { dispatchUiEvent, useUiEvent } from '../../../../../../hooks';
import { NitroCardGridItemView } from '../../../../../../layout/card/grid/item/NitroCardGridItemView';
import { NitroCardGridView } from '../../../../../../layout/card/grid/NitroCardGridView';
import { BadgeImageView } from '../../../../../shared/badge-image/BadgeImageView';
import { GetOfferName } from '../../../../common/CatalogUtilities';
import { useCatalogContext } from '../../../../context/CatalogContext';
import { CatalogRoomPreviewerView } from '../../../catalog-room-previewer/CatalogRoomPreviewerView';
import { CatalogPageOffersView } from '../../offers/CatalogPageOffersView';
import { CatalogPurchaseView } from '../../purchase/CatalogPurchaseView';
import { CatalogLayoutBadgeDisplayViewProps } from './CatalogLayoutBadgeDisplayView.types';
export const CatalogLayoutBadgeDisplayView: FC<CatalogLayoutBadgeDisplayViewProps> = props =>
{
const { roomPreviewer = null, pageParser = null } = props;
const { catalogState = null, dispatchCatalogState = null } = useCatalogContext();
const { activeOffer = null } = catalogState;
const [ currentBadge, setCurrentBadge ] = useState<string>(null);
const [ badges, setBadges ] = useState<string[]>([]);
const product = ((activeOffer && activeOffer.products[0]) || null);
const onInventoryBadgesUpdatedEvent = useCallback((event: InventoryBadgesUpdatedEvent) =>
{
console.log(event);
setBadges(event.badges);
}, []);
useUiEvent(InventoryBadgesUpdatedEvent.BADGES_UPDATED, onInventoryBadgesUpdatedEvent);
const badgeElements = useMemo(() =>
{
return badges.map(code =>
{
return (
<NitroCardGridItemView key={ code } itemActive={ (currentBadge === code) } onMouseDown={ event => setCurrentBadge(code) }>
<BadgeImageView badgeCode={ code } />
</NitroCardGridItemView>
);
});
}, [ badges, currentBadge ]);
useEffect(() =>
{
dispatchUiEvent(new InventoryBadgesRequestEvent(InventoryBadgesRequestEvent.REQUEST_BADGES));
}, []);
useEffect(() =>
{
if(!currentBadge || !activeOffer) return;
const stuffData = new StringDataType();
stuffData.setValue([ null, currentBadge ]);
roomPreviewer.updateObjectStuffData(stuffData);
}, [ currentBadge, activeOffer, roomPreviewer ]);
return (
<div className="row h-100 nitro-catalog-layout-badge-display">
<div className="d-flex flex-column col-7 h-100">
<CatalogPageOffersView offers={ pageParser.offers } />
<div className="d-flex mt-2">
<NitroCardGridView className="inventory-badge-grid">
{ badgeElements }
</NitroCardGridView>
</div>
</div>
{ product &&
<div className="position-relative d-flex flex-column col">
<CatalogRoomPreviewerView roomPreviewer={ roomPreviewer } height={ 140 } />
<div className="fs-6 text-black mt-1 overflow-hidden">{ GetOfferName(activeOffer) }</div>
<CatalogPurchaseView offer={ activeOffer } pageId={ pageParser.pageId } extra={ 'Bill 22-7-2021 ADM' } />
</div> }
</div>
);
}

View File

@ -0,0 +1,6 @@
import { CatalogLayoutProps } from '../CatalogLayout.types';
export interface CatalogLayoutBadgeDisplayViewProps extends CatalogLayoutProps
{
}

View File

@ -1,7 +1,10 @@
.nitro-catalog-layout-vip-buy {
.catalog-offer-item-container {
height: 60px !important;
max-height: 60px !important;
.vip-buy-grid {
.grid-item-container {
height: 70px !important;
max-height: 70px !important;
}
}
}

View File

@ -1,7 +1,11 @@
import { CatalogClubOfferData, CatalogRequestVipOffersComposer } from 'nitro-renderer';
import { FC, useCallback, useEffect, useMemo } from 'react';
import { CatalogClubOfferData, CatalogPurchaseComposer, CatalogRequestVipOffersComposer } from 'nitro-renderer';
import { FC, useCallback, useEffect, useMemo, useState } from 'react';
import { Button } from 'react-bootstrap';
import { SendMessageHook } from '../../../../../../hooks/messages/message-event';
import { NitroCardGridItemView } from '../../../../../../layout/card/grid/item/NitroCardGridItemView';
import { NitroCardGridView } from '../../../../../../layout/card/grid/NitroCardGridView';
import { LocalizeText } from '../../../../../../utils/LocalizeText';
import { GLOBAL_PURSE } from '../../../../../purse/PurseView';
import { CurrencyIcon } from '../../../../../shared/currency-icon/CurrencyIcon';
import { GetCatalogPageImage } from '../../../../common/CatalogUtilities';
import { useCatalogContext } from '../../../../context/CatalogContext';
@ -11,16 +15,7 @@ export const CatalogLayoutVipBuyView: FC<CatalogLayoutVipBuyViewProps> = props =
{
const { catalogState = null } = useCatalogContext();
const { pageParser = null, clubOffers = null, subscriptionInfo = null } = catalogState;
useEffect(() =>
{
if(clubOffers === null)
{
SendMessageHook(new CatalogRequestVipOffersComposer(1));
return;
}
}, [ clubOffers ]);
const [ pendingOffer, setPendingOffer ] = useState<CatalogClubOfferData>(null);
const getOfferText = useCallback((offer: CatalogClubOfferData) =>
{
@ -41,6 +36,31 @@ export const CatalogLayoutVipBuyView: FC<CatalogLayoutVipBuyViewProps> = props =
return offerText;
}, []);
const getPurchaseHeader = useCallback(() =>
{
const purse = GLOBAL_PURSE;
if(!purse) return '';
const extensionOrSubscription = (purse.clubDays > 0 || purse.clubPeriods > 0) ? 'extension.' : 'subscription.';
const daysOrMonths = ((pendingOffer.months === 0) ? 'days' : 'months');
const daysOrMonthsText = ((pendingOffer.months === 0) ? pendingOffer.extraDays : pendingOffer.months);
const locale = LocalizeText('catalog.vip.buy.confirm.' + extensionOrSubscription + daysOrMonths);
return locale.replace('%NUM_' + daysOrMonths.toUpperCase() + '%', daysOrMonthsText.toString());
}, [ pendingOffer ]);
const getPurchaseValidUntil = useCallback(() =>
{
let locale = LocalizeText('catalog.vip.buy.confirm.end_date');
locale = locale.replace('%month%', pendingOffer.month.toString());
locale = locale.replace('%day%', pendingOffer.day.toString());
locale = locale.replace('%year%', pendingOffer.year.toString());
return locale;
}, [ pendingOffer ]);
const getSubscriptionDetails = useMemo(() =>
{
if(!subscriptionInfo) return '';
@ -52,41 +72,100 @@ export const CatalogLayoutVipBuyView: FC<CatalogLayoutVipBuyViewProps> = props =
return LocalizeText('catalog.vip.extend.info', [ 'days' ], [ totalDays.toString() ]);
}, [ subscriptionInfo ]);
const purchaseSubscription = useCallback(() =>
{
if(!pendingOffer) return;
SendMessageHook(new CatalogPurchaseComposer(pageParser.pageId, pendingOffer.offerId, null, 1));
}, [ pendingOffer, pageParser ])
useEffect(() =>
{
if(clubOffers === null)
{
SendMessageHook(new CatalogRequestVipOffersComposer(1));
return;
}
}, [ clubOffers ]);
return (
<div className="row h-100 nitro-catalog-layout-vip-buy">
<div className="col-7 h-100">
<div className="row row-cols-1 align-content-start g-0 mb-n1 w-100 catalog-offers-container h-100 overflow-auto">
{ clubOffers && (clubOffers.length > 0) && clubOffers.map((offer, index) =>
{
return <div key={ index } className="col pe-1 pb-1 catalog-offer-item-container">
<div className="position-relative border border-2 rounded catalog-offer-item">
<div className="d-flex align-items-center text-black text-small m-1">
<i className="icon icon-catalogue-hc_small me-1"></i>
{ getOfferText(offer) }
</div>
<div className="d-flex">
{ (offer.priceCredits > 0) &&
<div className="d-flex align-items-center justify-content-end">
<span className="text-black ms-1">{ offer.priceCredits }</span>
<CurrencyIcon type={ -1 } />
</div> }
{ (offer.priceActivityPoints > 0) &&
<div className="d-flex align-items-center justify-content-end">
<span className="text-black ms-1">{ offer.priceActivityPoints }</span>
<CurrencyIcon type={ offer.priceActivityPointsType } />
<>
<div className="row h-100 nitro-catalog-layout-vip-buy">
<div className="col-7 h-100">
<NitroCardGridView columns={ 1 } className="vip-buy-grid">
{ clubOffers && (clubOffers.length > 0) && clubOffers.map((offer, index) =>
{
return (
<NitroCardGridItemView key={ index } className="justify-content-between p-1">
{ (pendingOffer === offer) &&
<div className="d-flex flex-column justify-content-center align-items-center w-100">
<div className="text-black text-small">{ getPurchaseHeader() }</div>
<div className="text-black text-small">{ getPurchaseValidUntil() }</div>
<Button variant="primary" size="sm" onClick={ purchaseSubscription }>{ LocalizeText('buy') }</Button>
</div> }
{ (pendingOffer !== offer) &&
<>
<div className="d-flex flex-column text-black text-small m-1">
<div>
<i className="icon icon-catalogue-hc_small me-1"></i>
{ getOfferText(offer) }
</div>
<div className="d-flex">
{ (offer.priceCredits > 0) &&
<div className="d-flex align-items-center justify-content-end">
<span className="text-black ms-1">{ offer.priceCredits }</span>
<CurrencyIcon type={ -1 } />
</div> }
{ (offer.priceActivityPoints > 0) &&
<div className="d-flex align-items-center justify-content-end">
<span className="text-black ms-1">{ offer.priceActivityPoints }</span>
<CurrencyIcon type={ offer.priceActivityPointsType } />
</div> }
</div>
</div>
<Button variant="primary" size="sm" onClick={ event => setPendingOffer(offer) }>{ LocalizeText('buy') }</Button>
</> }
</NitroCardGridItemView>
);
}) }
</NitroCardGridView>
{/* <div className="row row-cols-1 align-content-start g-0 mb-n1 w-100 catalog-offers-container h-100 overflow-auto">
{ clubOffers && (clubOffers.length > 0) && clubOffers.map((offer, index) =>
{
return (
<div key={ index } className="col pe-1 pb-1 catalog-offer-item-container">
<div className="position-relative border border-2 rounded catalog-offer-item">
<div className="d-flex align-items-center text-black text-small m-1">
<i className="icon icon-catalogue-hc_small me-1"></i>
{ getOfferText(offer) }
</div>
<div className="d-flex">
{ (offer.priceCredits > 0) &&
<div className="d-flex align-items-center justify-content-end">
<span className="text-black ms-1">{ offer.priceCredits }</span>
<CurrencyIcon type={ -1 } />
</div> }
{ (offer.priceActivityPoints > 0) &&
<div className="d-flex align-items-center justify-content-end">
<span className="text-black ms-1">{ offer.priceActivityPoints }</span>
<CurrencyIcon type={ offer.priceActivityPointsType } />
</div> }
</div>
<Button variant="primary" size="sm" onClick={ event => setPendingOffer(offer) } />
</div>
</div>
</div>
</div>;
})}
);
}) }
</div> */}
</div>
<div className="position-relative d-flex flex-column col-5 justify-content-center align-items-center">
<div className="d-block mb-2">
<img alt="" src={ GetCatalogPageImage(pageParser, 1) } />
</div>
<div className="fs-6 text-center text-black lh-sm overflow-hidden" dangerouslySetInnerHTML={ {__html: getSubscriptionDetails } }></div>
</div>
</div>
<div className="position-relative d-flex flex-column col-5 justify-content-center align-items-center">
<div className="d-block mb-2">
<img alt="" src={ GetCatalogPageImage(pageParser, 1) } />
</div>
<div className="fs-6 text-center text-black lh-sm overflow-hidden" dangerouslySetInnerHTML={ {__html: getSubscriptionDetails } }></div>
</div>
</div>
</>
);
}

View File

@ -1,6 +1,6 @@
import { Nitro, RoomSessionEvent } from 'nitro-renderer';
import { RoomSessionEvent } from 'nitro-renderer';
import { FC, useCallback, useState } from 'react';
import { GetConfiguration } from '../../api';
import { GetConfiguration, GetConfigurationManager } from '../../api';
import { useRoomSessionManagerEvent } from '../../hooks/events/nitro/session/room-session-manager-event';
import { HotelViewProps } from './HotelView.types';
import { WidgetSlotView } from './views/widget-slot/WidgetSlotView';
@ -29,12 +29,12 @@ export const HotelView: FC<HotelViewProps> = props =>
if (!isVisible) return null;
const backgroundColor = GetConfiguration('hotelview')['images']['background.colour'];
const background = Nitro.instance.core.configuration.interpolate(GetConfiguration('hotelview')['images']['background']);
const sun = Nitro.instance.core.configuration.interpolate(GetConfiguration('hotelview')['images']['sun']);
const drape = Nitro.instance.core.configuration.interpolate(GetConfiguration('hotelview')['images']['drape']);
const left = Nitro.instance.core.configuration.interpolate(GetConfiguration('hotelview')['images']['left']);
const rightRepeat = Nitro.instance.core.configuration.interpolate(GetConfiguration('hotelview')['images']['right.repeat']);
const right = Nitro.instance.core.configuration.interpolate(GetConfiguration('hotelview')['images']['right']);
const background = GetConfigurationManager().interpolate(GetConfiguration('hotelview')['images']['background']);
const sun = GetConfigurationManager().interpolate(GetConfiguration('hotelview')['images']['sun']);
const drape = GetConfigurationManager().interpolate(GetConfiguration('hotelview')['images']['drape']);
const left = GetConfigurationManager().interpolate(GetConfiguration('hotelview')['images']['left']);
const rightRepeat = GetConfigurationManager().interpolate(GetConfiguration('hotelview')['images']['right.repeat']);
const right = GetConfigurationManager().interpolate(GetConfiguration('hotelview')['images']['right']);
return (
<div className="nitro-hotel-view" style={(backgroundColor && backgroundColor) ? { background: backgroundColor } : {}}>

View File

@ -1,7 +1,10 @@
import { AdvancedMap, BadgesEvent, BotAddedToInventoryEvent, BotInventoryMessageEvent, BotRemovedFromInventoryEvent, FurnitureListAddOrUpdateEvent, FurnitureListEvent, FurnitureListInvalidateEvent, FurnitureListItemParser, FurnitureListRemovedEvent, FurniturePostItPlacedEvent, PetAddedToInventoryEvent, PetData, PetInventoryEvent, PetRemovedFromInventory, TradingAcceptEvent, TradingCloseEvent, TradingCompletedEvent, TradingConfirmationEvent, TradingListItemEvent, TradingNotOpenEvent, TradingOpenEvent, TradingOpenFailedEvent, TradingOtherNotAllowedEvent, TradingYouAreNotAllowedEvent, UnseenItemsEvent } from 'nitro-renderer';
import { AdvancedMap, BadgeReceivedEvent, BadgesEvent, BotAddedToInventoryEvent, BotInventoryMessageEvent, BotRemovedFromInventoryEvent, FurnitureListAddOrUpdateEvent, FurnitureListEvent, FurnitureListInvalidateEvent, FurnitureListItemParser, FurnitureListRemovedEvent, FurniturePostItPlacedEvent, PetAddedToInventoryEvent, PetData, PetInventoryEvent, PetRemovedFromInventory, RequestBadgesComposer, TradingAcceptEvent, TradingCloseEvent, TradingCompletedEvent, TradingConfirmationEvent, TradingListItemEvent, TradingNotOpenEvent, TradingOpenEvent, TradingOpenFailedEvent, TradingOtherNotAllowedEvent, TradingYouAreNotAllowedEvent, UnseenItemsEvent } from 'nitro-renderer';
import { FC, useCallback } from 'react';
import { GetRoomSession, GetSessionDataManager } from '../../api';
import { CreateMessageHook } from '../../hooks/messages/message-event';
import { InventoryBadgesUpdatedEvent } from '../../events';
import { InventoryBadgesRequestEvent } from '../../events/inventory/InventoryBadgesRequestEvent';
import { dispatchUiEvent, useUiEvent } from '../../hooks';
import { CreateMessageHook, SendMessageHook } from '../../hooks/messages/message-event';
import { mergeFurniFragments } from './common/FurnitureUtilities';
import { mergePetFragments } from './common/PetUtilities';
import { TradeState } from './common/TradeState';
@ -17,7 +20,7 @@ let petMsgFragments: Map<number, PetData>[] = null;
export const InventoryMessageHandler: FC<InventoryMessageHandlerProps> = props =>
{
const { dispatchFurnitureState = null, dispatchBotState = null, dispatchPetState = null, dispatchBadgeState = null, unseenTracker = null } = useInventoryContext();
const { dispatchFurnitureState = null, dispatchBotState = null, dispatchPetState = null, badgeState = null, dispatchBadgeState = null, unseenTracker = null } = useInventoryContext();
const onFurnitureListAddOrUpdateEvent = useCallback((event: FurnitureListAddOrUpdateEvent) =>
{
@ -163,6 +166,18 @@ export const InventoryMessageHandler: FC<InventoryMessageHandlerProps> = props =
});
}, [ dispatchBadgeState ]);
const onBadgeReceivedEvent = useCallback((event: BadgeReceivedEvent) =>
{
const parser = event.getParser();
dispatchBadgeState({
type: InventoryBadgeActions.ADD_BADGE,
payload: {
badgeCode: parser.badgeCode
}
});
}, [ dispatchBadgeState ]);
const onTradingAcceptEvent = useCallback((event: TradingAcceptEvent) =>
{
const parser = event.getParser();
@ -318,6 +333,7 @@ export const InventoryMessageHandler: FC<InventoryMessageHandlerProps> = props =
CreateMessageHook(PetRemovedFromInventory, onPetRemovedFromInventory);
CreateMessageHook(PetAddedToInventoryEvent, onPetAddedToInventoryEvent);
CreateMessageHook(BadgesEvent, onBadgesEvent);
CreateMessageHook(BadgeReceivedEvent, onBadgeReceivedEvent);
CreateMessageHook(TradingAcceptEvent, onTradingAcceptEvent);
CreateMessageHook(TradingCloseEvent, onTradingCloseEvent);
CreateMessageHook(TradingCompletedEvent, onTradingCompletedEvent);
@ -330,5 +346,19 @@ export const InventoryMessageHandler: FC<InventoryMessageHandlerProps> = props =
CreateMessageHook(TradingYouAreNotAllowedEvent, onTradingYouAreNotAllowedEvent);
CreateMessageHook(UnseenItemsEvent, onUnseenItemsEvent);
const onInventoryBadgesRequestEvent = useCallback((event: InventoryBadgesRequestEvent) =>
{
if(badgeState.needsBadgeUpdate)
{
SendMessageHook(new RequestBadgesComposer());
return;
}
dispatchUiEvent(new InventoryBadgesUpdatedEvent(InventoryBadgesUpdatedEvent.BADGES_UPDATED, badgeState.badges));
}, [ badgeState ])
useUiEvent(InventoryBadgesRequestEvent.REQUEST_BADGES, onInventoryBadgesRequestEvent);
return null;
}

View File

@ -1,10 +1,10 @@
import { IRoomSession, RoomEngineObjectEvent, RoomEngineObjectPlacedEvent, RoomPreviewer, RoomSessionEvent, TradingCancelComposer, TradingCloseComposer, TradingOpenComposer } from 'nitro-renderer';
import { FC, useCallback, useEffect, useReducer, useState } from 'react';
import { GetRoomEngine } from '../../api';
import { InventoryEvent, InventoryTradeRequestEvent } from '../../events';
import { InventoryBadgesUpdatedEvent, InventoryEvent, InventoryTradeRequestEvent } from '../../events';
import { useRoomEngineEvent } from '../../hooks/events/nitro/room/room-engine-event';
import { useRoomSessionManagerEvent } from '../../hooks/events/nitro/session/room-session-manager-event';
import { useUiEvent } from '../../hooks/events/ui/ui-event';
import { dispatchUiEvent, useUiEvent } from '../../hooks/events/ui/ui-event';
import { SendMessageHook } from '../../hooks/messages';
import { NitroCardContentView, NitroCardHeaderView, NitroCardTabsItemView, NitroCardTabsView, NitroCardView } from '../../layout';
import { LocalizeText } from '../../utils/LocalizeText';
@ -186,6 +186,13 @@ export const InventoryView: FC<InventoryViewProps> = props =>
}
}, [ furnitureState.tradeData, isVisible ]);
useEffect(() =>
{
if(!badgeState.badges) return;
dispatchUiEvent(new InventoryBadgesUpdatedEvent(InventoryBadgesUpdatedEvent.BADGES_UPDATED, badgeState.badges));
}, [ badgeState.badges ]);
return (
<InventoryContextProvider value={ { furnitureState, dispatchFurnitureState, botState, dispatchBotState, petState, dispatchPetState, badgeState, dispatchBadgeState, unseenTracker } }>
<InventoryMessageHandler />

View File

@ -1,4 +1,5 @@
import { IFurnitureItemData, IObjectData, Nitro } from 'nitro-renderer';
import { IFurnitureItemData, IObjectData } from 'nitro-renderer';
import { GetNitroInstance } from '../../../api';
import { IFurnitureItem } from './IFurnitureItem';
export class FurnitureItem implements IFurnitureItem
@ -122,7 +123,7 @@ export class FurnitureItem implements IFurnitureItem
if(this._hasRentPeriodStarted)
{
time = (this._secondsToExpiration - ((Nitro.instance.time - this._expirationTimeStamp) / 1000));
time = (this._secondsToExpiration - ((GetNitroInstance().time - this._expirationTimeStamp) / 1000));
if(time < 0) time = 0;
}

View File

@ -23,11 +23,12 @@ export interface IInventoryBadgeAction
export class InventoryBadgeActions
{
public static SET_NEEDS_UPDATE: string = 'IBDA_SET_NEEDS_UPDATE';
public static SET_BADGE: string = 'IBDA_SET_BADGE';
public static SET_BADGES: string = 'IBDA_SET_BADGES';
public static ADD_ACTIVE_BADGE: string = 'IBDA_ADD_ACTIVE_BADGE';
public static REMOVE_ACTIVE_BADGE: string = 'IBDA_REMOVE_ACTIVE_BADGE';
public static SET_NEEDS_UPDATE: string = 'IBA_SET_NEEDS_UPDATE';
public static SET_BADGE: string = 'IBA_SET_BADGE';
public static SET_BADGES: string = 'IBA_SET_BADGES';
public static ADD_BADGE: string = 'IBA_ADD_BADGE';
public static ADD_ACTIVE_BADGE: string = 'IBA_ADD_ACTIVE_BADGE';
public static REMOVE_ACTIVE_BADGE: string = 'IBA_REMOVE_ACTIVE_BADGE';
}
export const initialInventoryBadge: IInventoryBadgeState = {
@ -77,6 +78,14 @@ export const InventoryBadgeReducer: Reducer<IInventoryBadgeState, IInventoryBadg
return { ...state, badges, activeBadges };
}
case InventoryBadgeActions.ADD_BADGE: {
const badges = [ ...state.badges ];
const badge = (action.payload.badgeCode);
if(badges.indexOf(badge) === -1) badges.push(badge);
return { ...state, badges };
}
case InventoryBadgeActions.ADD_ACTIVE_BADGE: {
const badgeCode = action.payload.badgeCode;

View File

@ -19,6 +19,7 @@ export const InventoryBadgeView: FC<InventoryBadgeViewProps> = props =>
{
if(needsBadgeUpdate)
{
console.log('yee')
dispatchBadgeState({
type: InventoryBadgeActions.SET_NEEDS_UPDATE,
payload: {

View File

@ -1,5 +1,6 @@
import { Nitro, RoomSessionEvent } from 'nitro-renderer';
import { RoomSessionEvent } from 'nitro-renderer';
import { FC, useCallback, useEffect, useState } from 'react';
import { GetCommunication } from '../../api';
import { useRoomSessionManagerEvent } from '../../hooks/events/nitro/session/room-session-manager-event';
import { AchievementsView } from '../achievements/AchievementsView';
import { AvatarEditorView } from '../avatar-editor/AvatarEditorView';
@ -41,7 +42,7 @@ export const MainView: FC<MainViewProps> = props =>
{
setIsReady(true);
Nitro.instance.communication.connection.onReady();
GetCommunication().connection.onReady();
}, []);
return (

View File

@ -1,5 +1,7 @@
import { NavigatorInitComposer, NavigatorSearchComposer, RoomSessionEvent } from 'nitro-renderer';
import { ILinkEventTracker, NavigatorInitComposer, NavigatorSearchComposer, RoomSessionEvent } from 'nitro-renderer';
import { FC, useCallback, useEffect, useReducer, useState } from 'react';
import { AddEventLinkTracker, RemoveLinkEventTracker } from '../../api';
import { TryVisitRoom } from '../../api/navigator/TryVisitRoom';
import { NavigatorEvent } from '../../events';
import { useRoomSessionManagerEvent } from '../../hooks/events/nitro/session/room-session-manager-event';
import { useUiEvent } from '../../hooks/events/ui/ui-event';
@ -73,6 +75,45 @@ export const NavigatorView: FC<NavigatorViewProps> = props =>
SendMessageHook(new NavigatorSearchComposer(contextCode, searchValue));
}, []);
const linkReceived = useCallback((url: string) =>
{
const parts = url.split('/');
if(parts.length < 2) return;
switch(parts[1])
{
case 'goto':
if(parts.length > 2)
{
switch(parts[2])
{
case 'home':
//goToHomeRoom();
break;
default: {
const roomId = parseInt(parts[2]);
TryVisitRoom(roomId);
}
}
}
return;
}
}, []);
useEffect(() =>
{
const linkTracker: ILinkEventTracker = {
linkReceived,
eventUrlPrefix: 'navigator/'
};
AddEventLinkTracker(linkTracker);
return () => RemoveLinkEventTracker(linkTracker);
}, [ linkReceived]);
useEffect(() =>
{
if(!isVisible || !needsNavigatorUpdate) return;

View File

@ -1,6 +1,5 @@
import { Nitro } from 'nitro-renderer';
import { FC, useCallback, useEffect, useRef, useState } from 'react';
import { GetConfiguration } from '../../../../api';
import { GetConfiguration, GetNitroInstance } from '../../../../api';
import { NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../../../layout';
import { LocalizeText } from '../../../../utils/LocalizeText';
import { useNavigatorContext } from '../../context/NavigatorContext';
@ -26,7 +25,7 @@ export const NavigatorRoomLinkView: FC<NavigatorRoomLinkViewProps> = props =>
setRoomThumbnail(GetConfiguration<string>('image.library.url') + roomInfoData.enteredGuestRoom.officialRoomPicRef);
}
const roomLinkRaw = Nitro.instance.core.configuration.interpolate(LocalizeText('navigator.embed.src', ['roomId'], [roomInfoData.enteredGuestRoom.roomId.toString()]));
const roomLinkRaw = GetNitroInstance().core.configuration.interpolate(LocalizeText('navigator.embed.src', ['roomId'], [roomInfoData.enteredGuestRoom.roomId.toString()]));
setRoomLink(roomLinkRaw);
}, [ roomInfoData ]);

View File

@ -3,6 +3,7 @@
.content-area {
min-height: 125px;
max-height: 300px;
}
}

View File

@ -1,69 +1,59 @@
import { UserCreditsEvent, UserCurrencyEvent, UserCurrencyUpdateEvent, UserSubscriptionEvent } from 'nitro-renderer';
import { UserCreditsEvent, UserCurrencyEvent, UserCurrencyUpdateEvent, UserSubscriptionEvent, UserSubscriptionParser } from 'nitro-renderer';
import { FC, useCallback } from 'react';
import { CreateMessageHook } from '../../hooks/messages/message-event';
import { Currency } from './common/Currency';
import { usePurseContext } from './context/PurseContext';
import { PurseMessageHandlerProps } from './PurseMessageHandler.types';
import { PurseActions } from './reducers/PurseReducer';
export const PurseMessageHandler: FC<PurseMessageHandlerProps> = props =>
{
const { dispatchPurseState = null } = usePurseContext();
const { purse = null } = usePurseContext();
const onUserCreditsEvent = useCallback((event: UserCreditsEvent) =>
{
const parser = event.getParser();
dispatchPurseState({
type: PurseActions.SET_CURRENCY,
payload: {
currency: { type: -1, amount: parseFloat(parser.credits) }
}
});
}, [ dispatchPurseState ]);
purse.credits = parseFloat(parser.credits);
purse.notify();
}, [ purse ]);
const onUserCurrencyEvent = useCallback((event: UserCurrencyEvent) =>
{
const parser = event.getParser();
const currencies: Currency[] = [];
purse.activityPoints = parser.currencies;
for(const [ key, value ] of parser.currencies.entries()) currencies.push({ type: key, amount: value });
dispatchPurseState({
type: PurseActions.SET_CURRENCIES,
payload: { currencies }
});
}, [ dispatchPurseState ]);
purse.notify();
}, [ purse ]);
const onUserCurrencyUpdateEvent = useCallback((event: UserCurrencyUpdateEvent) =>
{
const parser = event.getParser();
dispatchPurseState({
type: PurseActions.SET_CURRENCY,
payload: {
currency: { type: parser.type, amount: parser.amount }
}
});
}, [ dispatchPurseState ]);
purse.activityPoints.set(parser.type, parser.amount);
purse.notify();
}, [ purse ]);
const onUserSubscriptionEvent = useCallback((event: UserSubscriptionEvent) =>
{
const parser = event.getParser();
switch(parser.name)
{
case 'habbo_club':
dispatchPurseState({
type: PurseActions.SET_CLUB_SUBSCRIPTION,
payload: {
clubSubscription: parser
}
});
return;
}
}, [ dispatchPurseState ]);
const productName = parser.productName;
if((productName !== 'club_habbo') && (productName !== 'habbo_club')) return;
purse.clubDays = Math.max(0, parser.daysToPeriodEnd);
purse.clubPeriods = Math.max(0, parser.periodsSubscribedAhead);
purse.isVip = parser.isVip;
purse.pastClubDays = parser.pastClubDays;
purse.pastVipDays = parser.pastVipDays;
purse.isExpiring = ((parser.responseType === UserSubscriptionParser.RESPONSE_TYPE_DISCOUNT_AVAILABLE) ? true : false);
purse.minutesUntilExpiration = parser.minutesUntilExpiration;
purse.minutesSinceLastModified = parser.minutesSinceLastModified;
purse.notify();
}, [ purse ]);
CreateMessageHook(UserCreditsEvent, onUserCreditsEvent);
CreateMessageHook(UserCurrencyEvent, onUserCurrencyEvent);

View File

@ -1,15 +1,37 @@
.nitro-purse {
background: rgba($dark,.95);
border: 1px solid lighten($dark,8.3);
box-shadow: inset 0px 3px lighten(rgba($dark,.6),2.5), inset 0 -2px darken(rgba($dark,.6),4);
font-weight: bolder;
padding: 2px;
background-color: #1c323f;
border: 2px solid rgba($white, 0.5);
border-top: 0;
font-size: $font-size-sm;
pointer-events: all;
margin-bottom:5px;
.notification-button {
color:lighten($dark,20);
cursor: pointer;
font-size: 0.9rem;
pointer-events: all;
display: none
}
.nitro-purse-hc {
background-color: #3d5f6e;
margin:0 2px;
}
.nitro-purse-button {
background: $bg-mirage-split-background;
&:not(:first-child) {
margin-top:2px;
}
&:hover {
background: $bg-cello-split-background;
}
}
}
@import './currency/CurrencyView';
@import './views';

View File

@ -1,52 +1,144 @@
import { UserCurrencyComposer } from 'nitro-renderer';
import { FC, useCallback, useEffect, useMemo, useReducer } from 'react';
import { FriendlyTime, HabboClubLevelEnum, UserCurrencyComposer, UserSubscriptionComposer } from 'nitro-renderer';
import { FC, useCallback, useEffect, useMemo, useState } from 'react';
import { GetConfiguration } from '../../api';
import { NotificationCenterEvent } from '../../events';
import { dispatchUiEvent } from '../../hooks/events';
import { SendMessageHook } from '../../hooks/messages/message-event';
import { SetLastCurrencies } from './common/CurrencyHelper';
import { LocalizeText } from '../../utils/LocalizeText';
import { CurrencyIcon } from '../shared/currency-icon/CurrencyIcon';
import { IPurse } from './common/IPurse';
import { Purse } from './common/Purse';
import { PurseContextProvider } from './context/PurseContext';
import { CurrencyView } from './currency/CurrencyView';
import { PurseMessageHandler } from './PurseMessageHandler';
import { PurseViewProps } from './PurseView.types';
import { initialPurse, PurseReducer } from './reducers/PurseReducer';
import { CurrencyView } from './views/currency/CurrencyView';
import { SeasonalView } from './views/seasonal/SeasonalView';
export const PurseView: FC<PurseViewProps> = props =>
export let GLOBAL_PURSE: IPurse = null;
export const PurseView: FC<{}> = props =>
{
const [ purseState, dispatchPurseState ] = useReducer(PurseReducer, initialPurse);
const { currencies = [] } = purseState;
const [ purse, setPurse ] = useState<IPurse>(new Purse());
const [ updateId, setUpdateId ] = useState(-1);
const displayedCurrencies = useMemo(() =>
{
return GetConfiguration<number[]>('system.currency.types', []);
}, []);
const getCurrencyElements = useCallback((offset: number, limit: number = -1, seasonal: boolean = false) =>
{
if(!purse.activityPoints.size) return null;
const types = Array.from(purse.activityPoints.keys()).filter(type => (displayedCurrencies.indexOf(type) >= 0));
let count = 0;
while(count < offset)
{
types.shift();
count++;
}
count = 0;
const elements: JSX.Element[] = [];
for(const type of types)
{
if((limit > -1) && (count === limit)) break;
if(seasonal) elements.push(<SeasonalView key={ type } type={ type } amount={ purse.activityPoints.get(type) } />);
else elements.push(<CurrencyView key={ type } type={ type } amount={ purse.activityPoints.get(type) } />);
count++;
}
return elements;
}, [ purse, displayedCurrencies ]);
const getClubText = useCallback(() =>
{
const totalDays = ((purse.clubPeriods * 31) + purse.clubDays);
const minutesUntilExpiration = purse.minutesUntilExpiration;
if(purse.clubLevel === HabboClubLevelEnum.NO_CLUB)
{
return LocalizeText('purse.clubdays.zero.amount.text');
}
else if((minutesUntilExpiration > -1) && (minutesUntilExpiration < (60 * 24)))
{
return FriendlyTime.shortFormat(minutesUntilExpiration * 60);
}
else
{
return FriendlyTime.shortFormat(totalDays * 86400);
}
}, [ purse ]);
useEffect(() =>
{
SendMessageHook(new UserCurrencyComposer());
const purse = new Purse();
GLOBAL_PURSE = purse;
purse.notifier = () => setUpdateId(prevValue => (prevValue + 1));
setPurse(purse);
return () => (purse.notifier = null);
}, []);
SetLastCurrencies(currencies);
const toggleNotificationCenter = useCallback(() =>
useEffect(() =>
{
dispatchUiEvent(new NotificationCenterEvent(NotificationCenterEvent.TOGGLE_NOTIFICATION_CENTER));
}, []);
if(!purse) return;
SendMessageHook(new UserCurrencyComposer());
}, [ purse ]);
useEffect(() =>
{
SendMessageHook(new UserSubscriptionComposer('habbo_club'));
const interval = setInterval(() =>
{
SendMessageHook(new UserSubscriptionComposer('habbo_club'));
}, 50000);
return () => clearInterval(interval);
}, [ purse ]);
if(!purse) return null;
return (
<PurseContextProvider value={ { purseState, dispatchPurseState }}>
<PurseContextProvider value={ { purse } }>
<PurseMessageHandler />
<div className="nitro-purse rounded d-flex flex-row py-1 justify-content-between">
{ currencies && currencies.map(currency =>
{
if(displayedCurrencies.indexOf(currency.type) === -1) return null;
return <CurrencyView key={ currency.type } currency={ currency } />;
}) }
<div className="notification-button px-2" onClick={ toggleNotificationCenter }>
<div className="nitro-purse rounded-bottom d-flex flex-row justify-content-between">
<div className="row mx-0 w-100">
<div className="col-6 px-0">
<div className="d-flex flex-column nitro-currencies">
<CurrencyView type={ -1 } amount={ purse.credits } />
{ getCurrencyElements(0, 2) }
</div>
</div>
<div className="col-4 px-0">
<div className="nitro-purse-hc p-1 d-flex flex-column justify-content-center align-items-center h-100">
<CurrencyIcon className="flex-shrink-0" type="hc" />
<span>{ getClubText() }</span>
</div>
</div>
<div className="col-2 px-0">
<div className="d-flex flex-column nitro-purse-buttons h-100 justify-content-center">
<div className="nitro-purse-button text-white h-100 text-center d-flex align-items-center justify-content-center"><i className="fas fa-life-ring"/></div>
<div className="nitro-purse-button text-white h-100 text-center d-flex align-items-center justify-content-center"><i className="fas fa-cogs"/></div>
</div>
</div>
</div>
{/*<div className="notification-button px-2" onClick={toggleNotificationCenter}>
<i className="fas fa-bars" />
</div>
</div>*/}
</div>
{ getCurrencyElements(2, -1, true) }
</PurseContextProvider>
);
}

View File

@ -1,4 +0,0 @@
export interface PurseViewProps
{
}

View File

@ -1,19 +1,16 @@
import { Currency } from './Currency';
let lastCurrencies: Currency[] = [];
export function SetLastCurrencies(currencies: Currency[]): void
{
lastCurrencies = currencies;
}
import { GLOBAL_PURSE } from '../PurseView';
export function GetCurrencyAmount(type: number): number
{
for(const currency of lastCurrencies)
{
if(currency.type !== type) continue;
const purse = GLOBAL_PURSE;
return currency.amount;
if(type === -1) return purse.credits;
for(const [ key, value ] of purse.activityPoints.entries())
{
if(key !== type) continue;
return value;
}
return 0;

View File

@ -0,0 +1,17 @@
export interface IPurse
{
credits: number;
activityPoints: Map<number, number>;
clubDays: number;
clubPeriods: number;
_Str_13571: boolean;
isVip: boolean;
pastClubDays: number;
pastVipDays: number;
isExpiring: boolean;
minutesUntilExpiration: number;
minutesSinceLastModified: number;
clubLevel: number;
notifier: () => void
notify(): void;
}

View File

@ -0,0 +1,163 @@
import { HabboClubLevelEnum } from 'nitro-renderer';
import { GetNitroInstance } from '../../../api';
import { IPurse } from './IPurse';
export class Purse implements IPurse
{
private _credits: number = 0;
private _activityPoints: Map<number, number> = new Map();
private _clubDays: number = 0;
private _clubPeriods: number = 0;
private _isVIP: boolean = false;
private _pastClubDays: number = 0;
private _pastVipDays: number = 0;
private _isExpiring: boolean = false;
private _minutesUntilExpiration: number = 0;
private _minutesSinceLastModified: number;
private _lastUpdated: number;
private _notifier: () => void;
public get credits(): number
{
return this._credits;
}
public set credits(credits: number)
{
this._lastUpdated = GetNitroInstance().time;
this._credits = credits;
}
public get activityPoints(): Map<number, number>
{
return this._activityPoints;
}
public set activityPoints(k: Map<number, number>)
{
this._lastUpdated = GetNitroInstance().time;
this._activityPoints = k;
}
public get clubDays(): number
{
return this._clubDays;
}
public set clubDays(k: number)
{
this._lastUpdated = GetNitroInstance().time;
this._clubDays = k;
}
public get clubPeriods(): number
{
return this._clubPeriods;
}
public set clubPeriods(k: number)
{
this._lastUpdated = GetNitroInstance().time;
this._clubPeriods = k;
}
public get _Str_13571(): boolean
{
return (this._clubDays > 0) || (this._clubPeriods > 0);
}
public get isVip(): boolean
{
return this._isVIP;
}
public set isVip(k: boolean)
{
this._isVIP = k;
}
public get pastClubDays(): number
{
return this._pastClubDays;
}
public set pastClubDays(k: number)
{
this._lastUpdated = GetNitroInstance().time;
this._pastClubDays = k;
}
public get pastVipDays(): number
{
return this._pastVipDays;
}
public set pastVipDays(k: number)
{
this._lastUpdated = GetNitroInstance().time;
this._pastVipDays = k;
}
public get isExpiring(): boolean
{
return this._isExpiring;
}
public set isExpiring(k: boolean)
{
this._isExpiring = k;
}
public get minutesUntilExpiration(): number
{
var k: number = ((GetNitroInstance().time - this._lastUpdated) / (1000 * 60));
var _local_2: number = (this._minutesUntilExpiration - k);
return (_local_2 > 0) ? _local_2 : 0;
}
public set minutesUntilExpiration(k: number)
{
this._lastUpdated = GetNitroInstance().time;
this._minutesUntilExpiration = k;
}
public get minutesSinceLastModified(): number
{
return this._minutesSinceLastModified;
}
public set minutesSinceLastModified(k: number)
{
this._lastUpdated = GetNitroInstance().time;
this._minutesSinceLastModified = k;
}
public get lastUpdated(): number
{
return this._lastUpdated;
}
public get notifier(): () => void
{
return this._notifier;
}
public set notifier(notifier: () => void)
{
this._notifier = notifier;
}
public get clubLevel(): number
{
if(((this.clubDays === 0) && (this.clubPeriods === 0))) return HabboClubLevelEnum.NO_CLUB;
if (this.isVip) return HabboClubLevelEnum.VIP;
return HabboClubLevelEnum.CLUB;
}
public notify(): void
{
if(this._notifier) this._notifier();
}
}

View File

@ -2,8 +2,7 @@ import { createContext, FC, useContext } from 'react';
import { IPurseContext, PurseContextProps } from './PurseContext.types';
const PurseContext = createContext<IPurseContext>({
purseState: null,
dispatchPurseState: null
purse: null
});
export const PurseContextProvider: FC<PurseContextProps> = props =>

View File

@ -1,10 +1,9 @@
import { Dispatch, ProviderProps } from 'react';
import { IPurseAction, IPurseState } from '../reducers/PurseReducer';
import { ProviderProps } from 'react';
import { IPurse } from '../common/IPurse';
export interface IPurseContext
{
purseState: IPurseState;
dispatchPurseState: Dispatch<IPurseAction>;
purse: IPurse;
}
export interface PurseContextProps extends ProviderProps<IPurseContext>

View File

@ -1,10 +0,0 @@
.nitro-currency {
pointer-events: all;
.nitro-currency-text {
max-width: 60px;
}
&:not(:last-child) {
border-right:1px solid #000;
box-shadow: 1px 0 lighten($dark,8.3)
}
}

View File

@ -1,27 +0,0 @@
import { FC } from 'react';
import { OverlayTrigger, Tooltip } from 'react-bootstrap';
import { LocalizeShortNumber } from '../../../utils/LocalizeShortNumber';
import { CurrencyIcon } from '../../shared/currency-icon/CurrencyIcon';
import { CurrencyViewProps } from './CurrencyView.types';
export const CurrencyView: FC<CurrencyViewProps> = props =>
{
const { currency = null } = props;
return (
<OverlayTrigger
placement="left"
overlay={
<Tooltip id={`tooltip-${currency.type}`}>
{ currency.amount }
</Tooltip>
}>
<div className="nitro-currency px-1 d-flex">
<div className="px-1 text-end text-truncate nitro-currency-text">{LocalizeShortNumber(currency.amount)}</div>
<div className="icon">
<CurrencyIcon type={ currency.type } />
</div>
</div>
</OverlayTrigger>
);
}

View File

@ -1,6 +0,0 @@
import { Currency } from '../common/Currency';
export interface CurrencyViewProps
{
currency: Currency;
}

View File

@ -1,77 +0,0 @@
import { UserSubscriptionParser } from 'nitro-renderer';
import { Reducer } from 'react';
import { Currency } from '../common/Currency';
export interface IPurseState
{
currencies: Currency[];
clubSubscription: UserSubscriptionParser;
}
export interface IPurseAction
{
type: string;
payload: {
currency?: Currency;
currencies?: Currency[];
clubSubscription?: UserSubscriptionParser;
}
}
export class PurseActions
{
public static SET_CURRENCY: string = 'PA_SET_CURRENCY';
public static SET_CURRENCIES: string = 'PA_SET_CURRENCIES';
public static SET_CLUB_SUBSCRIPTION: string = 'PA_SET_CLUB_SUBSCRIPTION';
}
export const initialPurse: IPurseState = {
currencies: [],
clubSubscription: null
}
export const PurseReducer: Reducer<IPurseState, IPurseAction> = (state, action) =>
{
switch(action.type)
{
case PurseActions.SET_CURRENCY: {
const updated = action.payload.currency;
let didSet = false;
const currencies = state.currencies.map(existing =>
{
if(existing.type !== updated.type) return existing;
didSet = true;
return { ...updated };
});
if(!didSet) currencies.push({ ...updated });
return { ...state, currencies };
}
case PurseActions.SET_CURRENCIES: {
const updated = action.payload.currencies;
const currencies = state.currencies.filter(existing =>
{
if(existing.type !== -1) return null;
return existing;
});
if(updated && updated.length) currencies.push(...updated);
return { ...state, currencies };
}
case PurseActions.SET_CLUB_SUBSCRIPTION: {
const clubSubscription = action.payload.clubSubscription;
return { ...state, clubSubscription };
}
default:
return state;
}
}

View File

@ -0,0 +1,9 @@
.nitro-currency {
pointer-events: all;
background: $bg-mirage-split-background;
position: relative;
&:not(:first-of-type) {
margin-top:2px;
}
}

View File

@ -0,0 +1,25 @@
import { FC } from 'react';
import { OverlayTrigger, Tooltip } from 'react-bootstrap';
import { LocalizeShortNumber } from '../../../../utils/LocalizeShortNumber';
import { CurrencyIcon } from '../../../shared/currency-icon/CurrencyIcon';
import { CurrencyViewProps } from './CurrencyView.types';
export const CurrencyView: FC<CurrencyViewProps> = props =>
{
const { type = -1, amount = -1 } = props;
return (
<OverlayTrigger
placement="left"
overlay={
<Tooltip id={`tooltip-${ type }`}>
{ amount }
</Tooltip>
}>
<div className="nitro-currency d-flex justify-content-end nitro-purse-button">
<div className="px-1 text-end text-truncate nitro-currency-text align-self-center">{LocalizeShortNumber(amount)}</div>
<CurrencyIcon className="flex-shrink-0" type={ type } />
</div>
</OverlayTrigger>
);
}

View File

@ -1,4 +1,4 @@
export interface Currency
export interface CurrencyViewProps
{
type: number;
amount: number;

View File

@ -0,0 +1,2 @@
@import './currency/CurrencyView';
@import './seasonal/SeasonalView';

View File

@ -0,0 +1,16 @@
.nitro-seasonal-currency {
pointer-events: all;
padding: 2px;
background-color: #1c323f;
border: 2px solid rgba($white, 0.5);
font-size: $font-size-sm;
margin-bottom: 5px;
.nitro-currency-text {
background: $bg-mirage-split-background;
}
.nitro-seasonal-icon {
background-color: #3d5f6e
}
}

View File

@ -0,0 +1,22 @@
import { FC } from 'react';
import { LocalizeShortNumber } from '../../../../utils/LocalizeShortNumber';
import { LocalizeText } from '../../../../utils/LocalizeText';
import { CurrencyIcon } from '../../../shared/currency-icon/CurrencyIcon';
import { SeasonalViewProps } from './SeasonalView.types';
export const SeasonalView: FC<SeasonalViewProps> = props =>
{
const { type = -1, amount = -1 } = props;
return (
<div className="nitro-seasonal-currency rounded d-flex justify-content-end">
<div className="nitro-currency-text w-100 px-1 d-flex justify-content-between">
<span>{ LocalizeText(`purse.seasonal.currency.${ type }`) }</span>
<span>{ LocalizeShortNumber(amount) }</span>
</div>
<div className="nitro-seasonal-icon">
<CurrencyIcon type={ type } />
</div>
</div>
);
}

View File

@ -0,0 +1,6 @@
export interface SeasonalViewProps
{
type: number;
amount: number;
}

View File

@ -1,6 +1,6 @@
.nitro-right-side {
position: absolute;
top: 10px;
top: 0px;
right: 10px;
min-width: 200px;
max-width: 400px;

View File

@ -1,6 +1,6 @@
import { ColorConverter, Nitro, NitroAdjustmentFilter, NitroContainer, NitroSprite, NitroTexture, RoomBackgroundColorEvent, RoomEngineEvent, RoomId, RoomObjectHSLColorEnabledEvent } from 'nitro-renderer';
import { ColorConverter, NitroAdjustmentFilter, NitroContainer, NitroSprite, NitroTexture, RoomBackgroundColorEvent, RoomEngineEvent, RoomId, RoomObjectHSLColorEnabledEvent } from 'nitro-renderer';
import { FC, useCallback, useState } from 'react';
import { GetRoomEngine } from '../../api';
import { GetNitroInstance, GetRoomEngine } from '../../api';
import { UseMountEffect } from '../../hooks';
import { CreateEventDispatcherHook, useRoomEngineEvent } from '../../hooks/events';
import { useRoomContext } from './context/RoomContext';
@ -48,8 +48,8 @@ export const RoomColorView: FC<{}> = props =>
if(color === undefined) color = 0x000000;
background.tint = color;
background.width = Nitro.instance.width;
background.height = Nitro.instance.height;
background.width = GetNitroInstance().width;
background.height = GetNitroInstance().height;
}, [ getRoomBackground ]);
const updateRoomBackgroundColor = useCallback((hue: number, saturation: number, lightness: number, original: boolean = false) =>

View File

@ -1,7 +1,7 @@
import { EventDispatcher, Nitro, NitroRectangle, RoomGeometry, RoomVariableEnum, Vector3d } from 'nitro-renderer';
import { EventDispatcher, NitroRectangle, RoomGeometry, RoomVariableEnum, Vector3d } from 'nitro-renderer';
import { FC, useEffect, useState } from 'react';
import { createPortal } from 'react-dom';
import { InitializeRoomInstanceRenderingCanvas } from '../../api';
import { GetNitroInstance, InitializeRoomInstanceRenderingCanvas } from '../../api';
import { DispatchMouseEvent } from '../../api/nitro/room/DispatchMouseEvent';
import { DispatchTouchEvent } from '../../api/nitro/room/DispatchTouchEvent';
import { GetRoomEngine } from '../../api/nitro/room/GetRoomEngine';
@ -47,11 +47,11 @@ export const RoomView: FC<RoomViewProps> = props =>
setWidgetHandler(widgetHandlerManager);
Nitro.instance.renderer.resize(window.innerWidth, window.innerHeight);
GetNitroInstance().renderer.resize(window.innerWidth, window.innerHeight);
const canvasId = 1;
const displayObject = GetRoomEngine().getRoomInstanceDisplay(roomSession.roomId, canvasId, Nitro.instance.width, Nitro.instance.height, RoomGeometry.SCALE_ZOOMED_IN);
const displayObject = GetRoomEngine().getRoomInstanceDisplay(roomSession.roomId, canvasId, GetNitroInstance().width, GetNitroInstance().height, RoomGeometry.SCALE_ZOOMED_IN);
if(!displayObject) return;
@ -77,13 +77,13 @@ export const RoomView: FC<RoomViewProps> = props =>
geometry.location = new Vector3d(x, y, z);
}
const stage = Nitro.instance.stage;
const stage = GetNitroInstance().stage;
if(!stage) return;
stage.addChild(displayObject);
const canvas = Nitro.instance.renderer.view;
const canvas = GetNitroInstance().renderer.view;
if(!canvas) return;
@ -99,16 +99,16 @@ export const RoomView: FC<RoomViewProps> = props =>
window.onresize = () =>
{
Nitro.instance.renderer.resize(window.innerWidth, window.innerHeight);
GetNitroInstance().renderer.resize(window.innerWidth, window.innerHeight);
InitializeRoomInstanceRenderingCanvas(roomSession.roomId, canvasId, Nitro.instance.width, Nitro.instance.height);
InitializeRoomInstanceRenderingCanvas(roomSession.roomId, canvasId, GetNitroInstance().width, GetNitroInstance().height);
const bounds = canvas.getBoundingClientRect();
const rectangle = new NitroRectangle((bounds.x || 0), (bounds.y || 0), (bounds.width || 0), (bounds.height || 0));
widgetHandlerManager.eventDispatcher.dispatchEvent(new RoomWidgetUpdateRoomViewEvent(RoomWidgetUpdateRoomViewEvent.SIZE_CHANGED, rectangle));
Nitro.instance.render();
GetNitroInstance().render();
}
setRoomCanvas(canvas);

View File

@ -30,4 +30,6 @@ export class RoomWidgetUpdateInfostandFurniEvent extends RoomWidgetUpdateInfosta
public purchaseCouldBeUsedForBuyout: boolean = false;
public rentCouldBeUsedForBuyout: boolean = false;
public availableForBuildersClub: boolean = false;
public tileSizeX: number = 1;
public tileSizeY: number = 1;
}

View File

@ -1,5 +1,5 @@
import { IFurnitureData, Nitro, NitroEvent, ObjectDataFactory, PetFigureData, PetRespectComposer, PetSupplementComposer, PetType, RoomAdsUpdateComposer, RoomControllerLevel, RoomModerationSettings, RoomObjectCategory, RoomObjectOperationType, RoomObjectType, RoomObjectVariable, RoomSessionPetInfoUpdateEvent, RoomSessionUserBadgesEvent, RoomTradingLevelEnum, RoomUnitDropHandItemComposer, RoomUnitGiveHandItemComposer, RoomUnitGiveHandItemPetComposer, RoomUserData, RoomWidgetEnum, RoomWidgetEnumItemExtradataParameter, SecurityLevel, Vector3d } from 'nitro-renderer';
import { GetRoomEngine, GetSessionDataManager, IsOwnerOfFurniture } from '../../../api';
import { IFurnitureData, NitroEvent, ObjectDataFactory, PetFigureData, PetRespectComposer, PetSupplementComposer, PetType, RoomAdsUpdateComposer, RoomControllerLevel, RoomModerationSettings, RoomObjectCategory, RoomObjectOperationType, RoomObjectType, RoomObjectVariable, RoomSessionPetInfoUpdateEvent, RoomSessionUserBadgesEvent, RoomTradingLevelEnum, RoomUnitDropHandItemComposer, RoomUnitGiveHandItemComposer, RoomUnitGiveHandItemPetComposer, RoomUserData, RoomWidgetEnum, RoomWidgetEnumItemExtradataParameter, SecurityLevel, Vector3d } from 'nitro-renderer';
import { GetNitroInstance, GetRoomEngine, GetSessionDataManager, IsOwnerOfFurniture } from '../../../api';
import { InventoryTradeRequestEvent, WiredSelectObjectEvent } from '../../../events';
import { FriendListSendFriendRequestEvent } from '../../../events/friend-list/FriendListSendFriendRequestEvent';
import { dispatchUiEvent } from '../../../hooks/events';
@ -390,6 +390,8 @@ export class RoomWidgetInfostandHandler extends RoomWidgetHandler
event.rentOfferId = furnitureData.rentOfferId;
event.rentCouldBeUsedForBuyout = furnitureData.rentCouldBeUsedForBuyout;
event.availableForBuildersClub = furnitureData.availableForBuildersClub;
event.tileSizeX = furnitureData.tileSizeX;
event.tileSizeY = furnitureData.tileSizeY;
dispatchUiEvent(new WiredSelectObjectEvent(event.id, event.category));
}
@ -400,7 +402,7 @@ export class RoomWidgetInfostandHandler extends RoomWidgetHandler
const expiryTime = model.getValue<number>(RoomObjectVariable.FURNITURE_EXPIRY_TIME);
const expiryTimestamp = model.getValue<number>(RoomObjectVariable.FURNITURE_EXPIRTY_TIMESTAMP);
event.expiration = ((expiryTime < 0) ? expiryTime : Math.max(0, (expiryTime - ((Nitro.instance.time - expiryTimestamp) / 1000))));
event.expiration = ((expiryTime < 0) ? expiryTime : Math.max(0, (expiryTime - ((GetNitroInstance().time - expiryTimestamp) / 1000))));
let roomObjectImage = GetRoomEngine().getRoomObjectImage(roomId, message.id, message.category, new Vector3d(180), 64, null);

View File

@ -1,6 +1,8 @@
import { AvatarAction, AvatarExpressionEnum, RoomObjectCategory } from 'nitro-renderer';
import { FC, useCallback, useState } from 'react';
import { GetCanStandUp, GetCanUseExpression, GetOwnPosture, HasHabboClub, HasHabboVip, IsRidingHorse } from '../../../../../../api';
import { AvatarEditorEvent } from '../../../../../../events';
import { dispatchUiEvent } from '../../../../../../hooks';
import { LocalizeText } from '../../../../../../utils/LocalizeText';
import { CurrencyIcon } from '../../../../../shared/currency-icon/CurrencyIcon';
import { useRoomContext } from '../../../../context/RoomContext';
@ -43,6 +45,7 @@ export const AvatarInfoWidgetOwnAvatarView: FC<AvatarInfoWidgetOwnAvatarViewProp
setIsDecorating(true);
break;
case 'change_looks':
dispatchUiEvent(new AvatarEditorEvent(AvatarEditorEvent.SHOW_EDITOR));
break;
case 'expressions':
hideMenu = false;

View File

@ -1,5 +1,6 @@
import { BotCommandConfigurationEvent, BotRemoveComposer, BotSkillSaveComposer, Nitro, RequestBotCommandConfigurationComposer, RoomObjectCategory, RoomObjectType } from 'nitro-renderer';
import { BotCommandConfigurationEvent, BotRemoveComposer, BotSkillSaveComposer, RequestBotCommandConfigurationComposer, RoomObjectCategory, RoomObjectType } from 'nitro-renderer';
import { FC, useCallback, useEffect, useState } from 'react';
import { GetNitroInstance } from '../../../../../../api';
import { CreateMessageHook, SendMessageHook } from '../../../../../../hooks/messages';
import { LocalizeText } from '../../../../../../utils/LocalizeText';
import { useRoomContext } from '../../../../context/RoomContext';
@ -119,7 +120,7 @@ export const AvatarInfoWidgetRentableBotView: FC<AvatarInfoWidgetRentableBotView
SendMessageHook(new BotSkillSaveComposer(rentableBotData.webID, BotSkillsEnum.DANCE, ''));
break;
case 'nux_take_tour':
Nitro.instance.createLinkEvent('help/tour');
GetNitroInstance().createLinkEvent('help/tour');
SendMessageHook(new BotSkillSaveComposer(rentableBotData.webID, BotSkillsEnum.NUX_TAKE_TOUR, ''));
break;
case 'pick':

View File

@ -1,6 +1,6 @@
import { FixedSizeStack, Nitro, NitroPoint, NitroRectangle, RoomObjectType } from 'nitro-renderer';
import { FixedSizeStack, NitroPoint, NitroRectangle, RoomObjectType } from 'nitro-renderer';
import { FC, useCallback, useEffect, useRef, useState } from 'react';
import { GetRoomEngine, GetRoomObjectBounds, GetRoomSession, GetTicker } from '../../../../api';
import { GetNitroInstance, GetRoomEngine, GetRoomObjectBounds, GetRoomSession, GetTicker } from '../../../../api';
import { ContextMenuViewProps } from './ContextMenuView.types';
const LOCATION_STACK_SIZE: number = 25;
@ -83,8 +83,8 @@ export const ContextMenuView: FC<ContextMenuViewProps> = props =>
let x = (location.x - (elementRef.current.offsetWidth / 2));
let y = (deltaY + offset);
const maxLeft = ((Nitro.instance.width - elementRef.current.offsetWidth) - SPACE_AROUND_EDGES);
const maxTop = ((Nitro.instance.height - elementRef.current.offsetHeight) - SPACE_AROUND_EDGES);
const maxLeft = ((GetNitroInstance().width - elementRef.current.offsetWidth) - SPACE_AROUND_EDGES);
const maxTop = ((GetNitroInstance().height - elementRef.current.offsetHeight) - SPACE_AROUND_EDGES);
if(x < SPACE_AROUND_EDGES) x = SPACE_AROUND_EDGES;
else if(x > maxLeft) x = maxLeft;

View File

@ -1,5 +1,6 @@
import { AvatarFigurePartType, FurnitureMannequinSaveLookComposer, FurnitureMannequinSaveNameComposer, FurnitureMultiStateComposer, IAvatarFigureContainer, Nitro, NitroEvent, RoomEngineTriggerWidgetEvent, RoomObjectVariable } from 'nitro-renderer';
import { AvatarFigurePartType, FurnitureMannequinSaveLookComposer, FurnitureMannequinSaveNameComposer, FurnitureMultiStateComposer, IAvatarFigureContainer, NitroEvent, RoomEngineTriggerWidgetEvent, RoomObjectVariable } from 'nitro-renderer';
import { FC, KeyboardEvent, useCallback, useEffect, useState } from 'react';
import { GetNitroInstance } from '../../../../../api';
import { GetRoomEngine } from '../../../../../api/nitro/room/GetRoomEngine';
import { GetRoomSession } from '../../../../../api/nitro/session/GetRoomSession';
import { GetSessionDataManager } from '../../../../../api/nitro/session/GetSessionDataManager';
@ -49,7 +50,7 @@ export const FurnitureMannequinView: FC<{}> = props =>
{
if(mannequinData && !mannequinData.renderedFigure)
{
const figureContainer = Nitro.instance.avatar.createFigureContainer(mannequinData.figure);
const figureContainer = GetNitroInstance().avatar.createFigureContainer(mannequinData.figure);
loadMannequinFigure(figureContainer);
}
}, [loadMannequinFigure, mannequinData]);
@ -59,8 +60,8 @@ export const FurnitureMannequinView: FC<{}> = props =>
if(!mannequinData) return;
const userCanEdit = (GetRoomSession().isRoomOwner || GetSessionDataManager().isModerator);
const userGender = Nitro.instance.sessionDataManager.gender;
const userClubLevel = Nitro.instance.sessionDataManager.clubLevel;
const userGender = GetNitroInstance().sessionDataManager.gender;
const userClubLevel = GetNitroInstance().sessionDataManager.clubLevel;
if(userCanEdit)
{
@ -100,8 +101,8 @@ export const FurnitureMannequinView: FC<{}> = props =>
const gender = roomObject.model.getValue<string>(RoomObjectVariable.FURNITURE_MANNEQUIN_GENDER);
const name = roomObject.model.getValue<string>(RoomObjectVariable.FURNITURE_MANNEQUIN_NAME);
const figureContainer = Nitro.instance.avatar.createFigureContainer(figure);
const clubLevel = Nitro.instance.avatar.getFigureClubLevel(figureContainer, gender, parts);
const figureContainer = GetNitroInstance().avatar.createFigureContainer(figure);
const clubLevel = GetNitroInstance().avatar.getFigureClubLevel(figureContainer, gender, parts);
const mannequinData = new FurnitureMannequinData(widgetEvent.objectId, widgetEvent.category, name, figure, gender, clubLevel);
@ -137,11 +138,11 @@ export const FurnitureMannequinView: FC<{}> = props =>
setMannequinData(mannequinData => new FurnitureMannequinData(mannequinData.objectId, mannequinData.category, value, mannequinData.figure, mannequinData.gender, mannequinData.clubLevel, mannequinData.renderedFigure));
return;
case 'load_figure':
loadMannequinFigure(Nitro.instance.avatar.createFigureContainer(Nitro.instance.sessionDataManager.figure));
loadMannequinFigure(GetNitroInstance().avatar.createFigureContainer(GetNitroInstance().sessionDataManager.figure));
setViewMode(MannequinViewMode.SAVE);
return;
case 'back':
loadMannequinFigure(Nitro.instance.avatar.createFigureContainer(mannequinData.figure));
loadMannequinFigure(GetNitroInstance().avatar.createFigureContainer(mannequinData.figure));
setViewMode(MannequinViewMode.EDIT);
return;
case 'save_name':

View File

@ -1,6 +1,5 @@
import { Nitro } from 'nitro-renderer';
import { FC, useCallback, useEffect, useRef, useState } from 'react';
import { GetRoomEngine, GetRoomSession } from '../../../../api';
import { GetNitroInstance, GetRoomEngine, GetRoomSession } from '../../../../api';
import { ObjectLocationViewProps } from './ObjectLocationView.types';
export const ObjectLocationView: FC<ObjectLocationViewProps> = props =>
@ -41,12 +40,12 @@ export const ObjectLocationView: FC<ObjectLocationViewProps> = props =>
{
remove = true;
Nitro.instance.ticker.add(updatePosition);
GetNitroInstance().ticker.add(updatePosition);
}
return () =>
{
if(remove) Nitro.instance.ticker.remove(updatePosition);
if(remove) GetNitroInstance().ticker.remove(updatePosition);
}
}, [ updatePosition, noFollow ]);

View File

@ -1,5 +1,6 @@
import { ColorConverter, IRoomRenderingCanvas, Nitro, TextureUtils } from 'nitro-renderer';
import { ColorConverter, IRoomRenderingCanvas, TextureUtils } from 'nitro-renderer';
import { FC, useCallback, useEffect, useRef, useState } from 'react';
import { GetNitroInstance } from '../../../api';
import { RoomPreviewerViewProps } from './RoomPreviewerView.types';
export const RoomPreviewerView: FC<RoomPreviewerViewProps> = props =>
@ -56,7 +57,7 @@ export const RoomPreviewerView: FC<RoomPreviewerViewProps> = props =>
if(!renderingCanvas) setupPreviewer();
Nitro.instance.ticker.add(update);
GetNitroInstance().ticker.add(update);
function resize(): void
{
@ -76,7 +77,7 @@ export const RoomPreviewerView: FC<RoomPreviewerViewProps> = props =>
return () =>
{
Nitro.instance.ticker.remove(update);
GetNitroInstance().ticker.remove(update);
window.removeEventListener('resize', resize);
}