Merge branch 'dev' into 'main'

Release 2.1.0

Closes #176 and #177

See merge request nitro/nitro-react!62
This commit is contained in:
Bill 2022-08-04 02:19:16 +00:00
commit 2fa3662860
998 changed files with 22767 additions and 28256 deletions

View File

@ -1,86 +0,0 @@
module.exports = {
'extends': [
'react-app',
'react-app/jest'
],
'rules': {
'linebreak-style': [
'off'
],
'quotes': [
'error',
'single'
],
'brace-style': [
'error',
'allman',
{
'allowSingleLine': true
}
],
'object-curly-spacing': [
'error',
'always'
],
'keyword-spacing': [
'error',
{
'overrides': {
'if': {
'after': false
},
'for': {
'after': false
},
'while': {
'after': false
},
'switch': {
'after': false
}
}
}
],
'@typescript-eslint/no-explicit-any': [
'off'
],
'@typescript-eslint/ban-ts-comment': [
'off'
],
'@typescript-eslint/no-empty-function': [
'error',
{
'allow': [
'functions',
'arrowFunctions',
'generatorFunctions',
'methods',
'generatorMethods',
'constructors'
]
}
],
'@typescript-eslint/no-unused-vars': [
'off'
],
'@typescript-eslint/ban-types': [
'error',
{
'types': {
'String': true,
'Boolean': true,
'Number': true,
'Symbol': true,
'{}': false,
'Object': false,
'object': false,
'Function': false
},
'extendDefaults': true
}
],
'no-switch-case-fall-through': [
'off'
]
}
}

67
.eslintrc.json Normal file
View File

@ -0,0 +1,67 @@
{
"root": true,
"settings": {
"react": {
"pragma": "React",
"version": "18.0.0"
}
},
"env": {
"browser": true,
"es2021": true
},
"extends": [
"plugin:react/recommended",
"plugin:react/jsx-runtime",
"plugin:react-hooks/recommended"
],
"parser": "@typescript-eslint/parser",
"parserOptions": {
"ecmaFeatures": {
"jsx": true
},
"ecmaVersion": "latest",
"sourceType": "module"
},
"plugins": [
"react",
"@typescript-eslint"
],
"rules": {
"linebreak-style": [ "off" ],
"quotes": [ "error", "single" ],
"@typescript-eslint/indent": [ "error", 4, { "SwitchCase": 1 } ],
"array-bracket-spacing": [ "error", "always" ],
"brace-style": [ "error", "allman" ],
"template-curly-spacing": [ "error", "always" ],
"no-multi-spaces": [ "error" ],
"jsx-quotes": [ "error" ],
"react/prop-types": [ "off" ],
"react/jsx-curly-spacing": [ "error", { "when": "always", "children": true } ],
"react/jsx-equals-spacing": [ "error" ],
"react/jsx-newline": [ "error", { "prevent": true } ],
"@typescript-eslint/object-curly-spacing": [ "error", "always",
{
"arraysInObjects": true,
"objectsInObjects": false
}
],
"@typescript-eslint/ban-types": [
"error",
{
"types": {
"String": true,
"Boolean": true,
"Number": true,
"Symbol": true,
"{}": false,
"Object": false,
"object": false,
"Function": false
},
"extendDefaults": true
}
],
"no-switch-case-fall-through": [ "off" ]
}
}

View File

@ -1,34 +0,0 @@
name: Build
on:
push:
branches: [dev]
jobs:
build:
runs-on: dedicated-server
strategy:
matrix:
node-version: [16.x]
steps:
- name: Checkout Repository
uses: actions/checkout@v2
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v2
with:
node-version: ${{ matrix.node-version }}
cache: "yarn"
- name: Install dependencies
run: |
yarn remove @nitrots/nitro-renderer
yarn add git+https://git@git.krews.org/nitro/nitro-renderer#dev
yarn install
- name: Build Nitro
run: |
yarn build
- name: Archive Artifacts
uses: actions/upload-artifact@v2
with:
path: |
build

View File

@ -1 +0,0 @@
*.scss

18
.vscode/settings.json vendored
View File

@ -4,14 +4,24 @@
"typescript.preferences.quoteStyle": "single", "typescript.preferences.quoteStyle": "single",
"typescript.format.placeOpenBraceOnNewLineForControlBlocks": true, "typescript.format.placeOpenBraceOnNewLineForControlBlocks": true,
"typescript.format.placeOpenBraceOnNewLineForFunctions": true, "typescript.format.placeOpenBraceOnNewLineForFunctions": true,
"typescript.format.enable": false,
"editor.codeActionsOnSave": { "editor.codeActionsOnSave": {
"source.fixAll": true, "source.fixAll.eslint": true,
"source.fixAll.sortJSON": false,
"source.organizeImports": true "source.organizeImports": true
}, },
"git.ignoreLimitWarning": true, "git.ignoreLimitWarning": true,
"files.eol": "\n", "files.eol": "\n",
"files.insertFinalNewline": true, "files.insertFinalNewline": true,
"files.trimFinalNewlines": true, "files.trimFinalNewlines": true,
"editor.wordWrap": "on" "editor.wordWrap": "on",
"emmet.showExpandedAbbreviation": "never",
"eslint.validate": [
"javascript",
"javascriptreact",
"html",
"typescriptreact"
],
"eslint.workingDirectories": [
"./src"
]
} }

View File

@ -1,11 +1,11 @@
# Nitro React # Nitro React v2.1
## Prerequisites ## Prerequisites
- You must have [git](https://git-scm.com/) installed - [Git](https://git-scm.com/)
- You must have [NodeJS](https://nodejs.org/) >= 16.13 installed - [NodeJS](https://nodejs.org/) >= 18
- We recommend you use [Yarn](https://yarnpkg.com/) over [npm](https://npmjs.com/) - If using NodeJS < 18 remove `--openssl-legacy-provider` from the package.json scripts
- `npm i yarn -g` - [Yarn](https://yarnpkg.com/) `npm i yarn -g`
## Installation ## Installation

View File

@ -5,25 +5,6 @@ module.exports = {
webpack: { webpack: {
configure: (webpackConfig) => ({ configure: (webpackConfig) => ({
...webpackConfig, ...webpackConfig,
module: {
...webpackConfig.module,
rules: [
...webpackConfig.module.rules
].map(rule =>
{
if(!rule.oneOf) return rule;
return {
...rule,
oneOf: rule.oneOf.map((ruleObject) =>
{
if(!new RegExp(ruleObject.test).test('.ts') || !ruleObject.include) return ruleObject;
return { ...ruleObject, include: undefined };
})
};
})
},
optimization: { optimization: {
...webpackConfig.optimization, ...webpackConfig.optimization,
splitChunks: { splitChunks: {
@ -40,6 +21,28 @@ module.exports = {
} }
} }
} }
},
module: {
...webpackConfig.module,
rules: [
{
test: /\.mjs$/,
include: /node_modules/,
type: 'javascript/auto'
},
...webpackConfig.module.rules.map((rule) => {
if (!rule.oneOf) return rule;
return {
...rule,
oneOf: rule.oneOf.map((ruleObject) => {
if (!new RegExp(ruleObject.test).test('.ts') || !ruleObject.include) return ruleObject;
return { ...ruleObject, include: undefined };
})
};
})
]
} }
}) })
} }

View File

@ -1,41 +1,56 @@
{ {
"name": "nitro-react", "name": "nitro-react",
"version": "2.0.0", "version": "2.1.0",
"private": true, "private": true,
"scripts": { "scripts": {
"start": "cross-env BROWSER=none IMAGE_INLINE_SIZE_LIMIT=100000 craco start", "start": "cross-env SKIP_PREFLIGHT_CHECK=true BROWSER=none IMAGE_INLINE_SIZE_LIMIT=100000 craco --openssl-legacy-provider start",
"build": "cross-env GENERATE_SOURCEMAP=false IMAGE_INLINE_SIZE_LIMIT=100000 craco build", "build": "cross-env SKIP_PREFLIGHT_CHECK=true GENERATE_SOURCEMAP=false IMAGE_INLINE_SIZE_LIMIT=100000 craco --openssl-legacy-provider build",
"build:prod": "npx browserslist@latest --update-db && yarn build", "build:prod": "npx browserslist@latest --update-db && yarn build",
"test": "craco test", "test": "craco test",
"eject": "react-scripts eject" "eject": "react-scripts eject",
"eslint": "eslint src --ext .ts,.tsx"
}, },
"dependencies": { "dependencies": {
"@craco/craco": "^6.4.3", "@craco/craco": "^6.4.5",
"@fortawesome/fontawesome-svg-core": "^1.2.36", "@fortawesome/fontawesome-svg-core": "^6.1.1",
"@fortawesome/free-solid-svg-icons": "^5.15.4", "@fortawesome/free-solid-svg-icons": "^6.1.1",
"@fortawesome/react-fontawesome": "^0.1.16", "@fortawesome/react-fontawesome": "^0.2.0",
"@nitrots/nitro-renderer": "^1.1.7", "@nitrots/nitro-renderer": "^1.3.4",
"animate.css": "^4.1.1", "animate.css": "^4.1.1",
"classnames": "^2.3.1", "classnames": "^2.3.1",
"cross-env": "^7.0.3", "cross-env": "^7.0.3",
"node-sass": "^6.0.1", "emoji-toolkit": "^6.6.0",
"react": "^17.0.2", "react": "^18.2.0",
"react-bootstrap": "^2.0.0-alpha.2", "react-bootstrap": "^2.2.2",
"react-dom": "^17.0.2", "react-dom": "^18.2.0",
"react-scripts": "4.0.3", "react-scripts": "4.0.3",
"react-slider": "^1.3.1", "react-slider": "^2.0.0",
"react-transition-group": "^4.4.2", "react-transition-group": "^4.4.2",
"react-virtualized": "^9.22.3", "react-virtualized": "^9.22.3",
"react-youtube": "^7.13.1", "react-youtube": "^7.13.1",
"typescript": "^4.3.5" "sass": "^1.53.0",
"typescript": "^4.3.5",
"use-between": "^1.3.4"
},
"resolutions": {
"react-error-overlay": "6.0.9",
"@types/react": "^18.0.15",
"@types/react-dom": "^18.0.6"
}, },
"devDependencies": { "devDependencies": {
"@types/node": "^12.20.19", "@types/node": "^18.6.1",
"@types/react": "^17.0.15", "@types/react": "^18.0.15",
"@types/react-dom": "^17.0.9", "@types/react-dom": "^18.0.6",
"@types/react-slider": "^1.3.1", "@types/react-slider": "^1.3.1",
"@types/react-transition-group": "^4.4.2", "@types/react-transition-group": "^4.4.5",
"@types/react-virtualized": "^9.21.13", "@types/react-virtualized": "^9.21.21",
"@typescript-eslint/eslint-plugin": "^4.29.1" "@typescript-eslint/eslint-plugin": "^5.30.7",
"@typescript-eslint/parser": "^5.30.7",
"eslint": "^8.20.0",
"eslint-plugin-import": "^2.26.0",
"eslint-plugin-jsx-a11y": "^6.6.0",
"eslint-plugin-react": "^7.30.1",
"eslint-plugin-react-hooks": "^4.6.0",
"react-error-overlay": "6.0.9"
} }
} }

View File

@ -23,7 +23,10 @@
<script> <script>
const NitroConfig = { const NitroConfig = {
"config.urls": [ '/renderer-config.json', '/ui-config.json' ], "config.urls": [ '/renderer-config.json', '/ui-config.json' ],
"sso.ticket": (new URLSearchParams(window.location.search).get('sso') || null) "sso.ticket": (new URLSearchParams(window.location.search).get('sso') || null),
"forward.type": (new URLSearchParams(window.location.search).get('room') ? 2 : -1),
"forward.id": (new URLSearchParams(window.location.search).get('room') || 0),
"friend.id": (new URLSearchParams(window.location.search).get('friend') || 0),
}; };
</script> </script>
</body> </body>

View File

@ -1,8 +1,8 @@
{ {
"image.library.notifications.url": "${image.library.url}notifications/%image%.png", "image.library.notifications.url": "${image.library.url}notifications/%image%.png",
"achievements.images.url": "${image.library.url}Quests/%image%.png", "achievements.images.url": "${image.library.url}Quests/%image%.png",
"camera.url": "https://camera.com", "camera.url": "https://camera.url",
"thumbnails.url": "https://camera.com/thumbnail/%thumbnail%.png", "thumbnails.url": "https://camera.url/thumbnail/%thumbnail%.png",
"url.prefix": "https://website.com", "url.prefix": "https://website.com",
"habbopages.url": "${url.prefix}/", "habbopages.url": "${url.prefix}/",
"group.homepage.url": "${url.prefix}/groups/%groupid%/id", "group.homepage.url": "${url.prefix}/groups/%groupid%/id",
@ -11,32 +11,80 @@
"widget.dimmer.colorwheel": false, "widget.dimmer.colorwheel": false,
"avatar.wardrobe.max.slots": 10, "avatar.wardrobe.max.slots": 10,
"user.badges.max.slots": 5, "user.badges.max.slots": 5,
"camera.publish.disabled": false,
"hc.disabled": false, "hc.disabled": false,
"badge.descriptions.enabled": true,
"motto.max.length": 38,
"bot.name.max.length": 15,
"navigator.room.models": [
{ "clubLevel": 0, "tileSize": 104, "name": "a" },
{ "clubLevel": 0, "tileSize": 94, "name": "b" },
{ "clubLevel": 0, "tileSize": 36, "name": "c" },
{ "clubLevel": 0, "tileSize": 84, "name": "d" },
{ "clubLevel": 0, "tileSize": 80, "name": "e" },
{ "clubLevel": 0, "tileSize": 80, "name": "f" },
{ "clubLevel": 0, "tileSize": 416, "name": "i" },
{ "clubLevel": 0, "tileSize": 320, "name": "j" },
{ "clubLevel": 0, "tileSize": 448, "name": "k" },
{ "clubLevel": 0, "tileSize": 352, "name": "l" },
{ "clubLevel": 0, "tileSize": 384, "name": "m" },
{ "clubLevel": 0, "tileSize": 372, "name": "n" },
{ "clubLevel": 1, "tileSize": 80, "name": "g" },
{ "clubLevel": 1, "tileSize": 74, "name": "h" },
{ "clubLevel": 1, "tileSize": 416, "name": "o" },
{ "clubLevel": 1, "tileSize": 352, "name": "p" },
{ "clubLevel": 1, "tileSize": 304, "name": "q" },
{ "clubLevel": 1, "tileSize": 336, "name": "r" },
{ "clubLevel": 1, "tileSize": 748, "name": "u" },
{ "clubLevel": 1, "tileSize": 438, "name": "v" },
{ "clubLevel": 2, "tileSize": 540, "name": "t" },
{ "clubLevel": 2, "tileSize": 512, "name": "w" },
{ "clubLevel": 2, "tileSize": 396, "name": "x" },
{ "clubLevel": 2, "tileSize": 440, "name": "y" },
{ "clubLevel": 2, "tileSize": 456, "name": "z" },
{ "clubLevel": 2, "tileSize": 208, "name": "0" },
{ "clubLevel": 2, "tileSize": 1009, "name": "1" },
{ "clubLevel": 2, "tileSize": 1044, "name": "2" },
{ "clubLevel": 2, "tileSize": 183, "name": "3" },
{ "clubLevel": 2, "tileSize": 254, "name": "4" },
{ "clubLevel": 2, "tileSize": 1024, "name": "5" },
{ "clubLevel": 2, "tileSize": 801, "name": "6" },
{ "clubLevel": 2, "tileSize": 354, "name": "7" },
{ "clubLevel": 2, "tileSize": 888, "name": "8" },
{ "clubLevel": 2, "tileSize": 926, "name": "9" }
],
"hotelview": { "hotelview": {
"show.avatar": true,
"widgets": { "widgets": {
"slot.1.widget": "promoarticle", "slot.1.widget": "promoarticle",
"slot.1.conf": "", "slot.1.conf": {},
"slot.2.widget": "widgetcontainer", "slot.2.widget": "widgetcontainer",
"slot.2.conf": "image:${image.library.url}web_promo_small/spromo_Canal_Bundle.png,texts:2021NitroPromo,btnLink:https://google.com", "slot.2.conf": {
"image": "${image.library.url}web_promo_small/spromo_Canal_Bundle.png",
"texts": "2021NitroPromo",
"btnLink": "https://google.com"
},
"slot.3.widget": "promoarticle", "slot.3.widget": "promoarticle",
"slot.3.conf": "", "slot.3.conf": {},
"slot.4.widget": "", "slot.4.widget": "",
"slot.4.conf": "", "slot.4.conf": {},
"slot.5.widget": "", "slot.5.widget": "",
"slot.5.conf": "", "slot.5.conf": {},
"slot.6.widget": "achievementcompetition_hall_of_fame", "slot.6.widget": "achievementcompetition_hall_of_fame",
"slot.6.conf": "", "slot.6.conf": {
"campaign": "habboFameComp"
},
"slot.7.widget": "", "slot.7.widget": "",
"slot.7.conf": "" "slot.7.conf": {}
}, },
"images": { "images": {
"background": "${asset.url}images/reception/stretch_blue.png", "background": "${asset.url}/images/reception/stretch_blue.png",
"background.colour": "#6eadc8", "background.colour": "#6eadc8",
"sun": "${asset.url}images/reception/sun.png", "sun": "${asset.url}/images/reception/sun.png",
"drape": "${asset.url}images/reception/drape.png", "drape": "${asset.url}/images/reception/drape.png",
"left": "${asset.url}images/reception/ts.png", "left": "${asset.url}/images/reception/ts.png",
"right": "${asset.url}images/reception/US_right.png", "right": "${asset.url}/images/reception/US_right.png",
"right.repeat": "${asset.url}images/reception/US_top_right.png" "right.repeat": "${asset.url}/images/reception/US_top_right.png"
} }
}, },
"achievements.unseen.ignored": [ "achievements.unseen.ignored": [
@ -50,14 +98,22 @@
0, 0,
5 5
], ],
"catalog.links": {
"hc.buy_hc": "habbo_club",
"hc.hc_gifts": "club_gifts",
"pets.buy_food": "pet_food",
"pets.buy_saddle": "saddles"
},
"hc.center": { "hc.center": {
"benefits.info": true, "benefits.info": true,
"payday.info": true, "payday.info": true,
"gift.info": true, "gift.info": true,
"benefits.habbopage": "habboclub", "benefits.habbopage": "habboclub",
"payday.habbopage": "hcpayday", "payday.habbopage": "hcpayday"
"catalog.buy": "habbo_club", },
"catalog.gifts": "club_gifts" "respect.options": {
"enabled": false,
"sound": "sound_respect_received"
}, },
"currency.display.number.short": false, "currency.display.number.short": false,
"currency.asset.icon.url": "${images.url}/wallet/%type%.png", "currency.asset.icon.url": "${images.url}/wallet/%type%.png",

View File

@ -7,6 +7,7 @@ $toolbar-memenu-zindex: 60;
$roomtools-zindex: 50; $roomtools-zindex: 50;
$context-menu-zindex: 40; $context-menu-zindex: 40;
$infostand-zindex: 30; $infostand-zindex: 30;
$quiz-zindex: 21;
$chat-zindex: 20; $chat-zindex: 20;
$highscore-zindex: 19; $highscore-zindex: 19;
@ -18,7 +19,7 @@ $grid-active-border-color: $white;
$toolbar-height: 55px; $toolbar-height: 55px;
$achievement-width: 375px; $achievement-width: 375px;
$achievement-height: 425px; $achievement-height: 405px;
$avatar-editor-width: 620px; $avatar-editor-width: 620px;
$avatar-editor-height: 374px; $avatar-editor-height: 374px;
@ -29,8 +30,8 @@ $catalog-height: 400px;
$inventory-width: 528px; $inventory-width: 528px;
$inventory-height: 320px; $inventory-height: 320px;
$navigator-width: 400px; $navigator-width: 420px;
$navigator-height: 420px; $navigator-height: 440px;
$chat-input-style-selector-widget-width: 210px; $chat-input-style-selector-widget-width: 210px;
$chat-input-style-selector-widget-height: 200px; $chat-input-style-selector-widget-height: 200px;
@ -51,7 +52,7 @@ $friends-list-width: 250px;
$friends-list-height: 300px; $friends-list-height: 300px;
$help-width: 450px; $help-width: 450px;
$help-height: 250px; $help-height: 290px;
$nitropedia-width: 400px; $nitropedia-width: 400px;
$nitropedia-height: 400px; $nitropedia-height: 400px;

View File

@ -1,49 +1,42 @@
import { ConfigurationEvent, HabboWebTools, LegacyExternalInterface, Nitro, NitroCommunicationDemoEvent, NitroEvent, NitroLocalizationEvent, NitroVersion, RoomEngineEvent, WebGL } from '@nitrots/nitro-renderer'; import { ConfigurationEvent, HabboWebTools, LegacyExternalInterface, Nitro, NitroCommunicationDemoEvent, NitroEvent, NitroLocalizationEvent, NitroVersion, RoomEngineEvent, WebGL } from '@nitrots/nitro-renderer';
import { FC, useCallback, useState } from 'react'; import { FC, useCallback, useEffect, useState } from 'react';
import { GetCommunication, GetConfiguration, GetNitroInstance } from './api'; import { DispatchUiEvent, GetCommunication, GetConfiguration, GetNitroInstance, GetUIVersion } from './api';
import { Base, TransitionAnimation, TransitionAnimationTypes } from './common'; import { Base, TransitionAnimation, TransitionAnimationTypes } from './common';
import { LoadingView } from './components/loading/LoadingView'; import { LoadingView } from './components/loading/LoadingView';
import { MainView } from './components/main/MainView'; import { MainView } from './components/main/MainView';
import { DispatchUiEvent, UseConfigurationEvent, UseLocalizationEvent, UseMainEvent, UseRoomEngineEvent } from './hooks'; import { useConfigurationEvent, useLocalizationEvent, useMainEvent, useRoomEngineEvent } from './hooks';
import IntervalWebWorker from './workers/IntervalWebWorker';
import { WorkerBuilder } from './workers/WorkerBuilder';
NitroVersion.UI_VERSION = GetUIVersion();
export const App: FC<{}> = props => export const App: FC<{}> = props =>
{ {
const [ isReady, setIsReady ] = useState(false); const [ isReady, setIsReady ] = useState(false);
const [ isError, setIsError ] = useState(false); const [ isError, setIsError ] = useState(false);
const [message, setMessage] = useState('Getting Ready'); const [ message, setMessage ] = useState('Getting Ready');
const [percent, setPercent] = useState(0); const [ percent, setPercent ] = useState(0);
const [ imageRendering, setImageRendering ] = useState<boolean>(true);
//@ts-ignore
if(!NitroConfig) throw new Error('NitroConfig is not defined!');
if(!GetNitroInstance()) if(!GetNitroInstance())
{ {
NitroVersion.UI_VERSION = '2.0.0'; //@ts-ignore
if(!NitroConfig) throw new Error('NitroConfig is not defined!');
Nitro.bootstrap(); Nitro.bootstrap();
const worker = new WorkerBuilder(IntervalWebWorker);
Nitro.instance.setWorker(worker);
} }
const getPreloadAssetUrls = useCallback(() =>
{
const urls: string[] = [];
const assetUrls = GetConfiguration<string[]>('preload.assets.urls');
if(assetUrls && assetUrls.length)
{
for(const url of assetUrls) urls.push(GetNitroInstance().core.configuration.interpolate(url));
}
return urls;
}, []);
const loadPercent = useCallback(() => setPercent(prevValue => (prevValue + 20)), []);
const handler = useCallback((event: NitroEvent) => const handler = useCallback((event: NitroEvent) =>
{ {
switch(event.type) switch(event.type)
{ {
case ConfigurationEvent.LOADED: case ConfigurationEvent.LOADED:
GetNitroInstance().localization.init(); GetNitroInstance().localization.init();
loadPercent(); setPercent(prevValue => (prevValue + 20));
return; return;
case ConfigurationEvent.FAILED: case ConfigurationEvent.FAILED:
setIsError(true); setIsError(true);
@ -60,44 +53,48 @@ export const App: FC<{}> = props =>
setTimeout(() => window.location.reload(), 1500); setTimeout(() => window.location.reload(), 1500);
return; return;
case NitroCommunicationDemoEvent.CONNECTION_HANDSHAKING: case NitroCommunicationDemoEvent.CONNECTION_HANDSHAKING:
loadPercent(); setPercent(prevValue => (prevValue + 20));
return; return;
case NitroCommunicationDemoEvent.CONNECTION_HANDSHAKE_FAILED: case NitroCommunicationDemoEvent.CONNECTION_HANDSHAKE_FAILED:
setIsError(true); setIsError(true);
setMessage('Handshake Failed'); setMessage('Handshake Failed');
return; return;
case NitroCommunicationDemoEvent.CONNECTION_AUTHENTICATED: case NitroCommunicationDemoEvent.CONNECTION_AUTHENTICATED:
loadPercent(); setPercent(prevValue => (prevValue + 20));
GetNitroInstance().init(); GetNitroInstance().init();
if(LegacyExternalInterface.available) LegacyExternalInterface.call('legacyTrack', 'authentication', 'authok', []); if(LegacyExternalInterface.available) LegacyExternalInterface.call('legacyTrack', 'authentication', 'authok', []);
return; return;
case NitroCommunicationDemoEvent.CONNECTION_ERROR: case NitroCommunicationDemoEvent.CONNECTION_ERROR:
setIsError(true); setIsError(true);
setMessage('Connection Error'); setMessage('Connection Error');
return; return;
case NitroCommunicationDemoEvent.CONNECTION_CLOSED: case NitroCommunicationDemoEvent.CONNECTION_CLOSED:
//if(GetNitroInstance().roomEngine) GetNitroInstance().roomEngine.dispose(); //if(GetNitroInstance().roomEngine) GetNitroInstance().roomEngine.dispose();
//setIsError(true); //setIsError(true);
setMessage('Connection Error'); setMessage('Connection Error');
HabboWebTools.send(-1, 'client.init.handshake.fail'); HabboWebTools.send(-1, 'client.init.handshake.fail');
return; return;
case RoomEngineEvent.ENGINE_INITIALIZED: case RoomEngineEvent.ENGINE_INITIALIZED:
loadPercent(); setPercent(prevValue => (prevValue + 20));
setTimeout(() => setIsReady(true), 300); setTimeout(() => setIsReady(true), 300);
return; return;
case NitroLocalizationEvent.LOADED: case NitroLocalizationEvent.LOADED: {
GetNitroInstance().core.asset.downloadAssets(getPreloadAssetUrls(), (status: boolean) => const assetUrls = GetConfiguration<string[]>('preload.assets.urls');
const urls: string[] = [];
if(assetUrls && assetUrls.length) for(const url of assetUrls) urls.push(GetNitroInstance().core.configuration.interpolate(url));
GetNitroInstance().core.asset.downloadAssets(urls, (status: boolean) =>
{ {
if(status) if(status)
{ {
GetCommunication().init(); GetCommunication().init();
loadPercent(); setPercent(prevValue => (prevValue + 20))
} }
else else
{ {
@ -106,34 +103,49 @@ export const App: FC<{}> = props =>
} }
}); });
return; return;
}
} }
}, [ getPreloadAssetUrls,loadPercent ]); }, []);
UseMainEvent(Nitro.WEBGL_UNAVAILABLE, handler); useMainEvent(Nitro.WEBGL_UNAVAILABLE, handler);
UseMainEvent(Nitro.WEBGL_CONTEXT_LOST, handler); useMainEvent(Nitro.WEBGL_CONTEXT_LOST, handler);
UseMainEvent(NitroCommunicationDemoEvent.CONNECTION_HANDSHAKING, handler); useMainEvent(NitroCommunicationDemoEvent.CONNECTION_HANDSHAKING, handler);
UseMainEvent(NitroCommunicationDemoEvent.CONNECTION_HANDSHAKE_FAILED, handler); useMainEvent(NitroCommunicationDemoEvent.CONNECTION_HANDSHAKE_FAILED, handler);
UseMainEvent(NitroCommunicationDemoEvent.CONNECTION_AUTHENTICATED, handler); useMainEvent(NitroCommunicationDemoEvent.CONNECTION_AUTHENTICATED, handler);
UseMainEvent(NitroCommunicationDemoEvent.CONNECTION_ERROR, handler); useMainEvent(NitroCommunicationDemoEvent.CONNECTION_ERROR, handler);
UseMainEvent(NitroCommunicationDemoEvent.CONNECTION_CLOSED, handler); useMainEvent(NitroCommunicationDemoEvent.CONNECTION_CLOSED, handler);
UseRoomEngineEvent(RoomEngineEvent.ENGINE_INITIALIZED, handler); useRoomEngineEvent(RoomEngineEvent.ENGINE_INITIALIZED, handler);
UseLocalizationEvent(NitroLocalizationEvent.LOADED, handler); useLocalizationEvent(NitroLocalizationEvent.LOADED, handler);
UseConfigurationEvent(ConfigurationEvent.LOADED, handler); useConfigurationEvent(ConfigurationEvent.LOADED, handler);
UseConfigurationEvent(ConfigurationEvent.FAILED, handler); useConfigurationEvent(ConfigurationEvent.FAILED, handler);
if(!WebGL.isWebGLAvailable()) useEffect(() =>
{ {
DispatchUiEvent(new NitroEvent(Nitro.WEBGL_UNAVAILABLE)); if(!WebGL.isWebGLAvailable())
} {
else DispatchUiEvent(new NitroEvent(Nitro.WEBGL_UNAVAILABLE));
{ }
GetNitroInstance().core.configuration.init(); else
} {
GetNitroInstance().core.configuration.init();
}
const resize = (event: UIEvent) => setImageRendering(!(window.devicePixelRatio % 1));
window.addEventListener('resize', resize);
resize(null);
return () =>
{
window.removeEventListener('resize', resize);
}
}, []);
return ( return (
<Base fit overflow="hidden"> <Base fit overflow="hidden" className={ imageRendering && 'image-rendering-pixelated' }>
{ (!isReady || isError) && { (!isReady || isError) &&
<LoadingView isError={isError} message={message} percent={ percent } /> } <LoadingView isError={ isError } message={ message } percent={ percent } /> }
<TransitionAnimation type={ TransitionAnimationTypes.FADE_IN } inProp={ (isReady) }> <TransitionAnimation type={ TransitionAnimationTypes.FADE_IN } inProp={ (isReady) }>
<MainView /> <MainView />
</TransitionAnimation> </TransitionAnimation>

View File

@ -0,0 +1,3 @@
import { NitroVersion } from '@nitrots/nitro-renderer';
export const GetRendererVersion = () => NitroVersion.RENDERER_VERSION;

1
src/api/GetUIVersion.ts Normal file
View File

@ -0,0 +1 @@
export const GetUIVersion = () => '2.1.0';

View File

@ -1,6 +1,8 @@
import { AchievementData } from '@nitrots/nitro-renderer'; import { AchievementData } from '@nitrots/nitro-renderer';
import { AchievementUtilities } from './AchievementUtilities';
import { IAchievementCategory } from './IAchievementCategory';
export class AchievementCategory export class AchievementCategory implements IAchievementCategory
{ {
private _code: string; private _code: string;
private _achievements: AchievementData[]; private _achievements: AchievementData[];
@ -13,26 +15,12 @@ export class AchievementCategory
public getProgress(): number public getProgress(): number
{ {
let progress = 0; return AchievementUtilities.getAchievementCategoryProgress(this);
for(const achievement of this._achievements)
{
progress += (achievement.finalLevel ? achievement.level : (achievement.level - 1));
}
return progress;
} }
public getMaxProgress(): number public getMaxProgress(): number
{ {
let progress = 0; return AchievementUtilities.getAchievementCategoryMaxProgress(this);
for(const achievement of this._achievements)
{
progress += achievement.levelCount;
}
return progress;
} }
public get code(): string public get code(): string

View File

@ -0,0 +1,97 @@
import { AchievementData } from '@nitrots/nitro-renderer';
import { GetConfiguration, GetLocalization } from '../nitro';
import { IAchievementCategory } from './IAchievementCategory';
export class AchievementUtilities
{
public static getAchievementBadgeCode(achievement: AchievementData): string
{
if(!achievement) return null;
let badgeId = achievement.badgeId;
if(!achievement.finalLevel) badgeId = GetLocalization().getPreviousLevelBadgeId(badgeId);
return badgeId;
}
public static getAchievementCategoryImageUrl(category: IAchievementCategory, progress: number = null, icon: boolean = false): string
{
const imageUrl = GetConfiguration<string>('achievements.images.url');
let imageName = icon ? 'achicon_' : 'achcategory_';
imageName += category.code;
if(progress !== null) imageName += `_${ ((progress > 0) ? 'active' : 'inactive') }`;
return imageUrl.replace('%image%', imageName);
}
public static getAchievementCategoryMaxProgress(category: IAchievementCategory): number
{
if(!category) return 0;
let progress = 0;
for(const achievement of category.achievements)
{
progress += achievement.levelCount;
}
return progress;
}
public static getAchievementCategoryProgress(category: IAchievementCategory): number
{
if(!category) return 0;
let progress = 0;
for(const achievement of category.achievements) progress += (achievement.finalLevel ? achievement.level : (achievement.level - 1));
return progress;
}
public static getAchievementCategoryTotalUnseen(category: IAchievementCategory): number
{
if(!category) return 0;
let unseen = 0;
for(const achievement of category.achievements) ((achievement.unseen > 0) && unseen++);
return unseen;
}
public static getAchievementHasStarted(achievement: AchievementData): boolean
{
if(!achievement) return false;
if(achievement.finalLevel || ((achievement.level - 1) > 0)) return true;
return false;
}
public static getAchievementIsIgnored(achievement: AchievementData): boolean
{
if(!achievement) return false;
const ignored = GetConfiguration<string[]>('achievements.unseen.ignored');
const value = achievement.badgeId.replace(/[0-9]/g, '');
const index = ignored.indexOf(value);
if(index >= 0) return true;
return false;
}
public static getAchievementLevel(achievement: AchievementData): number
{
if(!achievement) return 0;
if(achievement.finalLevel) return achievement.level;
return (achievement.level - 1);
}
}

View File

@ -0,0 +1,7 @@
import { AchievementData } from '@nitrots/nitro-renderer';
export interface IAchievementCategory
{
code: string;
achievements: AchievementData[];
}

View File

@ -0,0 +1,3 @@
export * from './AchievementCategory';
export * from './AchievementUtilities';
export * from './IAchievementCategory';

View File

@ -1,12 +1,12 @@
import { AvatarFigurePartType, IAvatarImageListener, IAvatarRenderManager, IFigurePart, IFigurePartSet, IGraphicAsset, IPartColor, NitroAlphaFilter, NitroContainer, NitroSprite, TextureUtils } from '@nitrots/nitro-renderer'; import { AvatarFigurePartType, IAvatarImageListener, IAvatarRenderManager, IFigurePart, IFigurePartSet, IGraphicAsset, IPartColor, NitroAlphaFilter, NitroContainer, NitroSprite, TextureUtils } from '@nitrots/nitro-renderer';
import { GetAvatarRenderManager } from '../../../api'; import { GetAvatarRenderManager } from '../nitro';
import { FigureData } from './FigureData'; import { FigureData } from './FigureData';
export class AvatarEditorGridPartItem implements IAvatarImageListener export class AvatarEditorGridPartItem implements IAvatarImageListener
{ {
private static ALPHA_FILTER: NitroAlphaFilter = new NitroAlphaFilter(0.2); private static ALPHA_FILTER: NitroAlphaFilter = new NitroAlphaFilter(0.2);
private static THUMB_DIRECTIONS: number[] = [2, 6, 0, 4, 3, 1]; private static THUMB_DIRECTIONS: number[] = [ 2, 6, 0, 4, 3, 1 ];
private static DRAW_ORDER: string[] = [ private static DRAW_ORDER: string[] = [
AvatarFigurePartType.LEFT_HAND_ITEM, AvatarFigurePartType.LEFT_HAND_ITEM,
AvatarFigurePartType.LEFT_HAND, AvatarFigurePartType.LEFT_HAND,
AvatarFigurePartType.LEFT_SLEEVE, AvatarFigurePartType.LEFT_SLEEVE,
@ -201,13 +201,13 @@ export class AvatarEditorGridPartItem implements IAvatarImageListener
if(this._partSet) if(this._partSet)
{ {
this._isHC = (this._partSet.clubLevel > 0); this._isHC = (this._partSet.clubLevel > 0);
this._isSellable = this._partSet.isSellable; this._isSellable = this._partSet.isSellable;
} }
else else
{ {
this._isHC = false; this._isHC = false;
this._isSellable = false; this._isSellable = false;
} }
if(this._isDisabled) this.setAlpha(container, 0.2); if(this._isDisabled) this.setAlpha(container, 0.2);

View File

@ -1,5 +1,5 @@
import { IPartColor } from '@nitrots/nitro-renderer'; import { IPartColor } from '@nitrots/nitro-renderer';
import { GetAvatarPalette, GetAvatarRenderManager, GetAvatarSetType, GetClubMemberLevel, GetConfiguration } from '../../../api'; import { GetAvatarPalette, GetAvatarRenderManager, GetAvatarSetType, GetClubMemberLevel, GetConfiguration } from '../nitro';
import { AvatarEditorGridColorItem } from './AvatarEditorGridColorItem'; import { AvatarEditorGridColorItem } from './AvatarEditorGridColorItem';
import { AvatarEditorGridPartItem } from './AvatarEditorGridPartItem'; import { AvatarEditorGridPartItem } from './AvatarEditorGridPartItem';
import { CategoryBaseModel } from './CategoryBaseModel'; import { CategoryBaseModel } from './CategoryBaseModel';

View File

@ -1,10 +1,10 @@
import { AvatarEditorFigureCategory, AvatarScaleType, AvatarSetType, IAvatarImageListener } from '@nitrots/nitro-renderer'; import { AvatarEditorFigureCategory, AvatarScaleType, AvatarSetType } from '@nitrots/nitro-renderer';
import { GetAvatarRenderManager } from '../../../api'; import { GetAvatarRenderManager } from '../nitro';
import { AvatarEditorUtilities } from './AvatarEditorUtilities'; import { AvatarEditorUtilities } from './AvatarEditorUtilities';
import { CategoryBaseModel } from './CategoryBaseModel'; import { CategoryBaseModel } from './CategoryBaseModel';
import { FigureData } from './FigureData'; import { FigureData } from './FigureData';
export class BodyModel extends CategoryBaseModel implements IAvatarImageListener export class BodyModel extends CategoryBaseModel
{ {
private _imageCallBackHandled: boolean = false; private _imageCallBackHandled: boolean = false;
@ -43,31 +43,25 @@ export class BodyModel extends CategoryBaseModel implements IAvatarImageListener
for(const part of category.parts) for(const part of category.parts)
{ {
const figure = AvatarEditorUtilities.CURRENT_FIGURE.getFigureStringWithFace(part.id); const resetFigure = (figure: string) =>
const avatarImage = GetAvatarRenderManager().createAvatarImage(figure, AvatarScaleType.LARGE, null, this);
const sprite = avatarImage.getImageAsSprite(AvatarSetType.HEAD);
if(sprite)
{ {
sprite.y = 10; const figureString = AvatarEditorUtilities.CURRENT_FIGURE.getFigureStringWithFace(part.id);
const avatarImage = GetAvatarRenderManager().createAvatarImage(figureString, AvatarScaleType.LARGE, null, { resetFigure, dispose: null, disposed: false });
part.thumbContainer = sprite; const sprite = avatarImage.getImageAsSprite(AvatarSetType.HEAD);
setTimeout(() => avatarImage.dispose(), 0); if(sprite)
{
sprite.y = 10;
part.thumbContainer = sprite;
setTimeout(() => avatarImage.dispose(), 0);
}
} }
resetFigure(null);
} }
// if (this._Str_2271) this._Str_2271._Str_5614(k, _local_4.length);
}
public resetFigure(figure: string): void
{
if(this._imageCallBackHandled) return;
this._imageCallBackHandled = true;
this.updateSelectionsFromFigure(FigureData.FACE);
} }
public get canSetGender(): boolean public get canSetGender(): boolean

View File

@ -11,7 +11,7 @@ export class CategoryBaseModel implements IAvatarEditorCategoryModel
constructor() constructor()
{ {
this._isInitalized = false; this._isInitalized = false;
this._maxPaletteCount = 0; this._maxPaletteCount = 0;
} }

View File

@ -199,8 +199,8 @@ export class FigureData
{ {
let figureString = ''; let figureString = '';
const setTypes: string[] = [ FigureData.FACE ]; const setTypes: string[] = [ FigureData.FACE ];
const figureSets: string[] = []; const figureSets: string[] = [];
for(const setType of setTypes) for(const setType of setTypes)
{ {

View File

@ -1,6 +1,6 @@
import { AvatarFigureContainer, IFigurePartSet, IPalette, IPartColor, SetType } from '@nitrots/nitro-renderer'; import { AvatarFigureContainer, IFigurePartSet, IPalette, IPartColor, SetType } from '@nitrots/nitro-renderer';
import { GetAvatarRenderManager } from '../../../api'; import { GetAvatarRenderManager } from '../nitro';
import { Randomizer } from '../../../api/utils'; import { Randomizer } from '../utils';
import { FigureData } from './FigureData'; import { FigureData } from './FigureData';
function getTotalColors(partSet: IFigurePartSet): number function getTotalColors(partSet: IFigurePartSet): number
@ -26,11 +26,11 @@ function getRandomPartSet(setType: SetType, gender: string, clubLevel: number =
if(!setType) return null; if(!setType) return null;
const options = setType.partSets.getValues().filter(option => const options = setType.partSets.getValues().filter(option =>
{ {
if(!option.isSelectable || ((option.gender !== 'U') && (option.gender !== gender)) || (option.clubLevel > clubLevel) || (option.isSellable && (figureSetIds.indexOf(option.id) === -1))) return null; if(!option.isSelectable || ((option.gender !== 'U') && (option.gender !== gender)) || (option.clubLevel > clubLevel) || (option.isSellable && (figureSetIds.indexOf(option.id) === -1))) return null;
return option; return option;
}); });
if(!options || !options.length) return null; if(!options || !options.length) return null;
@ -42,11 +42,11 @@ function getRandomColors(palette: IPalette, partSet: IFigurePartSet, clubLevel:
if(!palette) return []; if(!palette) return [];
const options = palette.colors.getValues().filter(option => const options = palette.colors.getValues().filter(option =>
{ {
if(!option.isSelectable || (option.clubLevel > clubLevel)) return null; if(!option.isSelectable || (option.clubLevel > clubLevel)) return null;
return option; return option;
}); });
if(!options || !options.length) return null; if(!options || !options.length) return null;

13
src/api/avatar/index.ts Normal file
View File

@ -0,0 +1,13 @@
export * from './AvatarEditorAction';
export * from './AvatarEditorGridColorItem';
export * from './AvatarEditorGridPartItem';
export * from './AvatarEditorUtilities';
export * from './BodyModel';
export * from './CategoryBaseModel';
export * from './CategoryData';
export * from './FigureData';
export * from './FigureGenerator';
export * from './HeadModel';
export * from './IAvatarEditorCategoryModel';
export * from './LegModel';
export * from './TorsoModel';

View File

@ -4,5 +4,6 @@ export class CameraPicture
{ {
constructor( constructor(
public texture: NitroTexture, public texture: NitroTexture,
public imageUrl: string) {} public imageUrl: string)
{}
} }

View File

@ -2,5 +2,6 @@ export class CameraPictureThumbnail
{ {
constructor( constructor(
public effectName: string, public effectName: string,
public thumbnailUrl: string) {} public thumbnailUrl: string)
{}
} }

3
src/api/camera/index.ts Normal file
View File

@ -0,0 +1,3 @@
export * from './CameraEditorTabs';
export * from './CameraPicture';
export * from './CameraPictureThumbnail';

View File

@ -0,0 +1,30 @@
import { ICalendarItem } from './ICalendarItem';
export class CalendarItem implements ICalendarItem
{
private _productName: string;
private _customImage: string;
private _furnitureClassName: string;
constructor(productName: string, customImage: string, furnitureClassName: string)
{
this._productName = productName;
this._customImage = customImage;
this._furnitureClassName = furnitureClassName;
}
public get productName(): string
{
return this._productName;
}
public get customImage(): string
{
return this._customImage;
}
public get furnitureClassName(): string
{
return this._furnitureClassName;
}
}

View File

@ -0,0 +1,6 @@
export interface ICalendarItem
{
readonly productName: string;
readonly customImage: string;
readonly furnitureClassName: string;
}

View File

@ -0,0 +1,3 @@
export * from './CalendarItem';
export * from './CalendarItemState';
export * from './ICalendarItem';

View File

@ -0,0 +1,10 @@
export class BuilderFurniPlaceableStatus
{
public static OKAY: number = 0;
public static MISSING_OFFER: number = 1;
public static FURNI_LIMIT_REACHED: number = 2;
public static NOT_IN_ROOM: number = 3;
public static NOT_ROOM_OWNER: number = 4;
public static GUILD_ROOM: number = 5;
public static VISITORS_IN_ROOM: number = 6;
}

View File

@ -5,5 +5,6 @@ export class CatalogPetPalette
constructor( constructor(
public readonly breed: string, public readonly breed: string,
public readonly palettes: SellablePetPaletteData[] public readonly palettes: SellablePetPaletteData[]
) {} )
{}
} }

View File

@ -1,5 +1,5 @@
import { SellablePetPaletteData } from '@nitrots/nitro-renderer'; import { SellablePetPaletteData } from '@nitrots/nitro-renderer';
import { GetRoomEngine } from '../../../api'; import { GetRoomEngine } from '../nitro';
import { ICatalogNode } from './ICatalogNode'; import { ICatalogNode } from './ICatalogNode';
export const GetPixelEffectIcon = (id: number) => export const GetPixelEffectIcon = (id: number) =>
@ -85,21 +85,21 @@ export function GetPetAvailableColors(petIndex: number, palettes: SellablePetPal
switch(petIndex) switch(petIndex)
{ {
case 0: case 0:
return [[16743226], [16750435], [16764339], [0xF59500], [16498012], [16704690], [0xEDD400], [16115545], [16513201], [8694111], [11585939], [14413767], [6664599], [9553845], [12971486], [8358322], [10002885], [13292268], [10780600], [12623573], [14403561], [12418717], [14327229], [15517403], [14515069], [15764368], [16366271], [0xABABAB], [0xD4D4D4], [0xFFFFFF], [14256481], [14656129], [15848130], [14005087], [14337152], [15918540], [15118118], [15531929], [9764857], [11258085]]; return [ [ 16743226 ], [ 16750435 ], [ 16764339 ], [ 0xF59500 ], [ 16498012 ], [ 16704690 ], [ 0xEDD400 ], [ 16115545 ], [ 16513201 ], [ 8694111 ], [ 11585939 ], [ 14413767 ], [ 6664599 ], [ 9553845 ], [ 12971486 ], [ 8358322 ], [ 10002885 ], [ 13292268 ], [ 10780600 ], [ 12623573 ], [ 14403561 ], [ 12418717 ], [ 14327229 ], [ 15517403 ], [ 14515069 ], [ 15764368 ], [ 16366271 ], [ 0xABABAB ], [ 0xD4D4D4 ], [ 0xFFFFFF ], [ 14256481 ], [ 14656129 ], [ 15848130 ], [ 14005087 ], [ 14337152 ], [ 15918540 ], [ 15118118 ], [ 15531929 ], [ 9764857 ], [ 11258085 ] ];
case 1: case 1:
return [[16743226], [16750435], [16764339], [0xF59500], [16498012], [16704690], [0xEDD400], [16115545], [16513201], [8694111], [11585939], [14413767], [6664599], [9553845], [12971486], [8358322], [10002885], [13292268], [10780600], [12623573], [14403561], [12418717], [14327229], [15517403], [14515069], [15764368], [16366271], [0xABABAB], [0xD4D4D4], [0xFFFFFF], [14256481], [14656129], [15848130], [14005087], [14337152], [15918540], [15118118], [15531929], [9764857], [11258085]]; return [ [ 16743226 ], [ 16750435 ], [ 16764339 ], [ 0xF59500 ], [ 16498012 ], [ 16704690 ], [ 0xEDD400 ], [ 16115545 ], [ 16513201 ], [ 8694111 ], [ 11585939 ], [ 14413767 ], [ 6664599 ], [ 9553845 ], [ 12971486 ], [ 8358322 ], [ 10002885 ], [ 13292268 ], [ 10780600 ], [ 12623573 ], [ 14403561 ], [ 12418717 ], [ 14327229 ], [ 15517403 ], [ 14515069 ], [ 15764368 ], [ 16366271 ], [ 0xABABAB ], [ 0xD4D4D4 ], [ 0xFFFFFF ], [ 14256481 ], [ 14656129 ], [ 15848130 ], [ 14005087 ], [ 14337152 ], [ 15918540 ], [ 15118118 ], [ 15531929 ], [ 9764857 ], [ 11258085 ] ];
case 2: case 2:
return [[16579283], [15378351], [8830016], [15257125], [9340985], [8949607], [6198292], [8703620], [9889626], [8972045], [12161285], [13162269], [8620113], [12616503], [8628101], [0xD2FF00], [9764857]]; return [ [ 16579283 ], [ 15378351 ], [ 8830016 ], [ 15257125 ], [ 9340985 ], [ 8949607 ], [ 6198292 ], [ 8703620 ], [ 9889626 ], [ 8972045 ], [ 12161285 ], [ 13162269 ], [ 8620113 ], [ 12616503 ], [ 8628101 ], [ 0xD2FF00 ], [ 9764857 ] ];
case 3: case 3:
return [[0xFFFFFF], [0xEEEEEE], [0xDDDDDD]]; return [ [ 0xFFFFFF ], [ 0xEEEEEE ], [ 0xDDDDDD ] ];
case 4: case 4:
return [[0xFFFFFF], [16053490], [15464440], [16248792], [15396319], [15007487]]; return [ [ 0xFFFFFF ], [ 16053490 ], [ 15464440 ], [ 16248792 ], [ 15396319 ], [ 15007487 ] ];
case 5: case 5:
return [[0xFFFFFF], [0xEEEEEE], [0xDDDDDD]]; return [ [ 0xFFFFFF ], [ 0xEEEEEE ], [ 0xDDDDDD ] ];
case 6: case 6:
return [[0xFFFFFF], [0xEEEEEE], [0xDDDDDD], [16767177], [16770205], [16751331]]; return [ [ 0xFFFFFF ], [ 0xEEEEEE ], [ 0xDDDDDD ], [ 16767177 ], [ 16770205 ], [ 16751331 ] ];
case 7: case 7:
return [[0xCCCCCC], [0xAEAEAE], [16751331], [10149119], [16763290], [16743786]]; return [ [ 0xCCCCCC ], [ 0xAEAEAE ], [ 16751331 ], [ 10149119 ], [ 16763290 ], [ 16743786 ] ];
default: { default: {
const colors: number[][] = []; const colors: number[][] = [];

View File

@ -1,5 +1,5 @@
import { GetProductOfferComposer, IFurnitureData } from '@nitrots/nitro-renderer'; import { GetProductOfferComposer, IFurnitureData } from '@nitrots/nitro-renderer';
import { GetProductDataForLocalization, SendMessageComposer } from '../../../api'; import { GetProductDataForLocalization, SendMessageComposer } from '..';
import { ICatalogPage } from './ICatalogPage'; import { ICatalogPage } from './ICatalogPage';
import { IProduct } from './IProduct'; import { IProduct } from './IProduct';
import { IPurchasableOffer } from './IPurchasableOffer'; import { IPurchasableOffer } from './IPurchasableOffer';

View File

@ -0,0 +1,19 @@
import { GetRoomEngine } from '../nitro';
import { ProductTypeEnum } from './ProductTypeEnum';
export const GetImageIconUrlForProduct = (productType: string, productClassId: number, extraData: string = null) =>
{
let imageUrl: string = null;
switch(productType.toLocaleLowerCase())
{
case ProductTypeEnum.FLOOR:
imageUrl = GetRoomEngine().getFurnitureFloorIconUrl(productClassId);
break;
case ProductTypeEnum.WALL:
imageUrl = GetRoomEngine().getFurnitureWallIconUrl(productClassId, extraData);
break;
}
return imageUrl;
}

View File

@ -1,7 +1,6 @@
import { ClubGiftInfoParser, ClubOfferData, HabboGroupEntryData, MarketplaceConfigurationMessageParser } from '@nitrots/nitro-renderer'; import { ClubGiftInfoParser, ClubOfferData, HabboGroupEntryData, MarketplaceConfigurationMessageParser } from '@nitrots/nitro-renderer';
import { CatalogPetPalette } from './CatalogPetPalette'; import { CatalogPetPalette } from './CatalogPetPalette';
import { GiftWrappingConfiguration } from './GiftWrappingConfiguration'; import { GiftWrappingConfiguration } from './GiftWrappingConfiguration';
import { SubscriptionInfo } from './SubscriptionInfo';
export interface ICatalogOptions export interface ICatalogOptions
{ {
@ -9,7 +8,6 @@ export interface ICatalogOptions
petPalettes?: CatalogPetPalette[]; petPalettes?: CatalogPetPalette[];
clubOffers?: ClubOfferData[]; clubOffers?: ClubOfferData[];
clubGifts?: ClubGiftInfoParser; clubGifts?: ClubGiftInfoParser;
subscriptionInfo?: SubscriptionInfo;
giftConfiguration?: GiftWrappingConfiguration; giftConfiguration?: GiftWrappingConfiguration;
marketplaceConfiguration?: MarketplaceConfigurationMessageParser; marketplaceConfiguration?: MarketplaceConfigurationMessageParser;
} }

View File

@ -1,4 +1,5 @@
export interface IMarketplaceSearchOptions { export interface IMarketplaceSearchOptions
{
query: string; query: string;
type: number; type: number;
minPrice: number; minPrice: number;

View File

@ -1,9 +1,8 @@
import { GetFurnitureData, GetProductDataForLocalization, LocalizeText } from '../../../api'; import { GetFurnitureData, GetProductDataForLocalization, LocalizeText, ProductTypeEnum } from '..';
import { ICatalogPage } from './ICatalogPage'; import { ICatalogPage } from './ICatalogPage';
import { IProduct } from './IProduct'; import { IProduct } from './IProduct';
import { IPurchasableOffer } from './IPurchasableOffer'; import { IPurchasableOffer } from './IPurchasableOffer';
import { Product } from './Product'; import { Product } from './Product';
import { ProductTypeEnum } from './ProductTypeEnum';
export class Offer implements IPurchasableOffer export class Offer implements IPurchasableOffer
{ {

View File

@ -1,4 +1,4 @@
import { GetConfiguration } from '../../../api'; import { GetConfiguration } from '../nitro';
import { IPageLocalization } from './IPageLocalization'; import { IPageLocalization } from './IPageLocalization';
export class PageLocalization implements IPageLocalization export class PageLocalization implements IPageLocalization

View File

@ -0,0 +1,41 @@
import { IFurnitureData, IProductData } from '@nitrots/nitro-renderer';
import { IPurchasableOffer } from './IPurchasableOffer';
export class PlacedObjectPurchaseData
{
constructor(
public readonly roomId: number,
public readonly objectId: number,
public readonly category: number,
public readonly wallLocation: string,
public readonly x: number,
public readonly y: number,
public readonly direction: number,
public readonly offer: IPurchasableOffer)
{}
public get offerId(): number
{
return this.offer.offerId;
}
public get productClassId(): number
{
return this.offer.product.productClassId;
}
public get productData(): IProductData
{
return this.offer.product.productData;
}
public get furniData(): IFurnitureData
{
return this.offer.product.furnitureData;
}
public get extraParam(): string
{
return this.offer.product.extraParam;
}
}

View File

@ -1,5 +1,5 @@
import { IFurnitureData, IObjectData, IProductData } from '@nitrots/nitro-renderer'; import { IFurnitureData, IObjectData, IProductData } from '@nitrots/nitro-renderer';
import { GetConfiguration, GetRoomEngine, GetSessionDataManager } from '../../../api'; import { GetConfiguration, GetRoomEngine, GetSessionDataManager } from '../nitro';
import { GetPixelEffectIcon, GetSubscriptionProductIcon } from './CatalogUtilities'; import { GetPixelEffectIcon, GetSubscriptionProductIcon } from './CatalogUtilities';
import { IProduct } from './IProduct'; import { IProduct } from './IProduct';
import { IPurchasableOffer } from './IPurchasableOffer'; import { IPurchasableOffer } from './IPurchasableOffer';

View File

@ -0,0 +1,11 @@
export class ProductTypeEnum
{
public static WALL: string = 'i';
public static FLOOR: string = 's';
public static EFFECT: string = 'e';
public static HABBO_CLUB: string = 'h';
public static BADGE: string = 'b';
public static GAME_TOKEN: string = 'GAME_TOKEN';
public static PET: string = 'p';
public static ROBOT: string = 'r';
}

View File

@ -6,6 +6,6 @@ export class SearchResult
constructor( constructor(
public readonly searchValue: string, public readonly searchValue: string,
public readonly offers: IPurchasableOffer[], public readonly offers: IPurchasableOffer[],
public readonly filteredNodes: ICatalogNode[] public readonly filteredNodes: ICatalogNode[])
) {} {}
} }

29
src/api/catalog/index.ts Normal file
View File

@ -0,0 +1,29 @@
export * from './BuilderFurniPlaceableStatus';
export * from './CatalogNode';
export * from './CatalogPage';
export * from './CatalogPageName';
export * from './CatalogPetPalette';
export * from './CatalogPurchaseState';
export * from './CatalogType';
export * from './CatalogUtilities';
export * from './FurnitureOffer';
export * from './GetImageIconUrlForProduct';
export * from './GiftWrappingConfiguration';
export * from './ICatalogNode';
export * from './ICatalogOptions';
export * from './ICatalogPage';
export * from './IMarketplaceSearchOptions';
export * from './IPageLocalization';
export * from './IProduct';
export * from './IPurchasableOffer';
export * from './IPurchaseOptions';
export * from './MarketplaceOfferData';
export * from './MarketplaceOfferState';
export * from './MarketplaceSearchType';
export * from './Offer';
export * from './PageLocalization';
export * from './PlacedObjectPurchaseData';
export * from './Product';
export * from './ProductTypeEnum';
export * from './RequestedPage';
export * from './SearchResult';

View File

@ -2,4 +2,5 @@ export class ChatEntryType
{ {
public static TYPE_CHAT = 1; public static TYPE_CHAT = 1;
public static TYPE_ROOM_INFO = 2; public static TYPE_ROOM_INFO = 2;
public static TYPE_IM = 3;
} }

View File

@ -0,0 +1,6 @@
export const ChatHistoryCurrentDate = () =>
{
const currentTime = new Date();
return `${ currentTime.getHours().toString().padStart(2, '0') }:${ currentTime.getMinutes().toString().padStart(2, '0') }`;
}

View File

@ -0,0 +1,5 @@
export interface IRoomHistoryEntry
{
id: number;
name: string;
}

View File

@ -0,0 +1,6 @@
export const MessengerHistoryCurrentDate = (secondsSinceNow: number = 0) =>
{
const currentTime = secondsSinceNow ? new Date(Date.now() - secondsSinceNow * 1000) : new Date();
return `${ currentTime.getHours().toString().padStart(2, '0') }:${ currentTime.getMinutes().toString().padStart(2, '0') }`;
}

View File

@ -0,0 +1,5 @@
export * from './ChatEntryType';
export * from './ChatHistoryCurrentDate';
export * from './IChatEntry';
export * from './IRoomHistoryEntry';
export * from './MessengerHistoryCurrentDate';

View File

@ -1 +0,0 @@
export * from './ProductImageUtility';

View File

@ -0,0 +1,3 @@
import { IEventDispatcher, NitroEvent } from '@nitrots/nitro-renderer';
export const DispatchEvent = (eventDispatcher: IEventDispatcher, event: NitroEvent) => eventDispatcher.dispatchEvent(event);

View File

@ -0,0 +1,5 @@
import { NitroEvent } from '@nitrots/nitro-renderer';
import { GetNitroInstance } from '../nitro';
import { DispatchEvent } from './DispatchEvent';
export const DispatchMainEvent = (event: NitroEvent) => DispatchEvent(GetNitroInstance().events, event);

View File

@ -0,0 +1,5 @@
import { NitroEvent } from '@nitrots/nitro-renderer';
import { DispatchEvent } from './DispatchEvent';
import { UI_EVENT_DISPATCHER } from './UI_EVENT_DISPATCHER';
export const DispatchUiEvent = (event: NitroEvent) => DispatchEvent(UI_EVENT_DISPATCHER, event);

4
src/api/events/index.ts Normal file
View File

@ -0,0 +1,4 @@
export * from './DispatchEvent';
export * from './DispatchMainEvent';
export * from './DispatchUiEvent';
export * from './UI_EVENT_DISPATCHER';

View File

@ -0,0 +1,13 @@
import { IGroupChatData } from './IGroupChatData';
export const GetGroupChatData = (extraData: string) =>
{
if(!extraData || !extraData.length) return null;
const splitData = extraData.split('/');
const username = splitData[0];
const figure = splitData[1];
const userId = parseInt(splitData[2]);
return ({ username: username, figure: figure, userId: userId } as IGroupChatData);
}

View File

@ -0,0 +1,6 @@
export interface IGroupChatData
{
username: string;
figure: string;
userId: number;
}

View File

@ -2,7 +2,7 @@ import { FriendParser } from '@nitrots/nitro-renderer';
export class MessengerFriend export class MessengerFriend
{ {
public static RELATIONSHIP_NONE: number = 0; public static RELATIONSHIP_NONE: number = 0;
public static RELATIONSHIP_HEART: number = 1; public static RELATIONSHIP_HEART: number = 1;
public static RELATIONSHIP_SMILE: number = 2; public static RELATIONSHIP_SMILE: number = 2;
public static RELATIONSHIP_BOBBA: number = 3; public static RELATIONSHIP_BOBBA: number = 3;

View File

@ -1,4 +1,4 @@
export class GroupType export class MessengerGroupType
{ {
public static readonly GROUP_CHAT = 0; public static readonly GROUP_CHAT = 0;
public static readonly PRIVATE_CHAT = 1; public static readonly PRIVATE_CHAT = 1;

View File

@ -0,0 +1,6 @@
export class MessengerIconState
{
public static HIDDEN: number = 0;
public static SHOW: number = 1;
public static UNREAD: number = 2;
}

View File

@ -11,10 +11,10 @@ export class MessengerRequest
{ {
if(!data) return false; if(!data) return false;
this._id = data.requestId; this._id = data.requestId;
this._name = data.requesterName; this._name = data.requesterName;
this._figureString = data.figureString; this._figureString = data.figureString;
this._requesterUserId = data.requesterUserId; this._requesterUserId = data.requesterUserId;
return true; return true;
} }

View File

@ -6,5 +6,6 @@ export class MessengerSettings
public userFriendLimit: number = 0, public userFriendLimit: number = 0,
public normalFriendLimit: number = 0, public normalFriendLimit: number = 0,
public extendedFriendLimit: number = 0, public extendedFriendLimit: number = 0,
public categories: FriendCategoryData[] = []) {} public categories: FriendCategoryData[] = [])
{}
} }

View File

@ -1,50 +1,46 @@
import { LocalizeText } from '../../../api'; import { GetGroupChatData } from './GetGroupChatData';
import { GroupType } from './GroupType';
import { MessengerFriend } from './MessengerFriend'; import { MessengerFriend } from './MessengerFriend';
import { MessengerGroupType } from './MessengerGroupType';
import { MessengerThreadChat } from './MessengerThreadChat'; import { MessengerThreadChat } from './MessengerThreadChat';
import { MessengerThreadChatGroup } from './MessengerThreadChatGroup'; import { MessengerThreadChatGroup } from './MessengerThreadChatGroup';
import { getGroupChatData } from './Utils';
export class MessengerThread export class MessengerThread
{ {
public static MESSAGE_RECEIVED: string = 'MT_MESSAGE_RECEIVED'; public static MESSAGE_RECEIVED: string = 'MT_MESSAGE_RECEIVED';
public static THREAD_ID: number = 0;
private _threadId: number;
private _participant: MessengerFriend; private _participant: MessengerFriend;
private _groups: MessengerThreadChatGroup[]; private _groups: MessengerThreadChatGroup[];
private _lastUpdated: Date; private _lastUpdated: Date;
private _unreadCount: number; private _unreadCount: number;
constructor(participant: MessengerFriend, isNew: boolean = true) constructor(participant: MessengerFriend)
{ {
this._threadId = ++MessengerThread.THREAD_ID;
this._participant = participant; this._participant = participant;
this._groups = []; this._groups = [];
this._lastUpdated = new Date(); this._lastUpdated = new Date();
this._unreadCount = 0; this._unreadCount = 0;
if(isNew)
{
this.addMessage(null, LocalizeText('messenger.moderationinfo'), 0, null, MessengerThreadChat.SECURITY_NOTIFICATION);
this._unreadCount = 0;
}
} }
public addMessage(senderId: number, message: string, secondsSinceSent: number = 0, extraData: string = null, type: number = 0): MessengerThreadChat public addMessage(senderId: number, message: string, secondsSinceSent: number = 0, extraData: string = null, type: number = 0): MessengerThreadChat
{ {
const isGroupChat = (senderId < 0 && extraData); const isGroupChat = (senderId < 0 && extraData);
const userId = isGroupChat ? getGroupChatData(extraData).userId : senderId; const userId = isGroupChat ? GetGroupChatData(extraData).userId : senderId;
const group = this.getLastGroup(userId); const group = this.getLastGroup(userId);
if(!group) return; if(!group) return;
if(isGroupChat) group.type = GroupType.GROUP_CHAT; if(isGroupChat) group.type = MessengerGroupType.GROUP_CHAT;
const chat = new MessengerThreadChat(senderId, message, secondsSinceSent, extraData, type); const chat = new MessengerThreadChat(senderId, message, secondsSinceSent, extraData, type);
group.addChat(chat); group.addChat(chat);
this._lastUpdated = new Date(); this._lastUpdated = new Date();
this._unreadCount++; this._unreadCount++;
return chat; return chat;
@ -68,6 +64,11 @@ export class MessengerThread
this._unreadCount = 0; this._unreadCount = 0;
} }
public get threadId(): number
{
return this._threadId;
}
public get participant(): MessengerFriend public get participant(): MessengerFriend
{ {
return this._participant; return this._participant;
@ -90,6 +91,6 @@ export class MessengerThread
public get unread(): boolean public get unread(): boolean
{ {
return this._unreadCount > 0; return (this._unreadCount > 0);
} }
} }

View File

@ -1,4 +1,4 @@
import { GroupType } from './GroupType'; import { MessengerGroupType } from './MessengerGroupType';
import { MessengerThreadChat } from './MessengerThreadChat'; import { MessengerThreadChat } from './MessengerThreadChat';
export class MessengerThreadChatGroup export class MessengerThreadChatGroup
@ -7,7 +7,7 @@ export class MessengerThreadChatGroup
private _chats: MessengerThreadChat[]; private _chats: MessengerThreadChat[];
private _type: number; private _type: number;
constructor(userId: number, type = GroupType.PRIVATE_CHAT) constructor(userId: number, type = MessengerGroupType.PRIVATE_CHAT)
{ {
this._userId = userId; this._userId = userId;
this._chats = []; this._chats = [];

View File

@ -2,6 +2,6 @@ import { CreateLinkEvent } from '..';
export function OpenMessengerChat(friendId: number = 0): void export function OpenMessengerChat(friendId: number = 0): void
{ {
if(friendId === 0) CreateLinkEvent('friends/messenger/open'); if(friendId === 0) CreateLinkEvent('friends-messenger/toggle');
else CreateLinkEvent(`friends/messenger/${friendId}`); else CreateLinkEvent(`friends-messenger/${ friendId }`);
} }

View File

@ -1 +1,11 @@
export * from './GetGroupChatData';
export * from './IGroupChatData';
export * from './MessengerFriend';
export * from './MessengerGroupType';
export * from './MessengerIconState';
export * from './MessengerRequest';
export * from './MessengerSettings';
export * from './MessengerThread';
export * from './MessengerThreadChat';
export * from './MessengerThreadChatGroup';
export * from './OpenMessengerChat'; export * from './OpenMessengerChat';

View File

@ -2,5 +2,5 @@ import { CreateLinkEvent } from '..';
export function GetGroupManager(groupId: number): void export function GetGroupManager(groupId: number): void
{ {
CreateLinkEvent(`groups/manage/${groupId}`); CreateLinkEvent(`groups/manage/${ groupId }`);
} }

View File

@ -1,3 +1,4 @@
export class GroupBadgePart export class GroupBadgePart
{ {
public static BASE: string = 'b'; public static BASE: string = 'b';
@ -18,7 +19,7 @@ export class GroupBadgePart
public get code(): string public get code(): string
{ {
if(this.key === 0) return null; if((this.key === 0) && (this.type !== GroupBadgePart.BASE)) return null;
return GroupBadgePart.getCode(this.type, this.key, this.color, this.position); return GroupBadgePart.getCode(this.type, this.key, this.color, this.position);
} }

Some files were not shown because too many files have changed in this diff Show More