refactor(all-in-one): clean up

This commit is contained in:
Walid 2023-04-23 20:12:45 +01:00
parent 01adee763f
commit bdcf825de7
Signed by: Walidoux
GPG Key ID: CCF21881FE8BEBAF
18 changed files with 26 additions and 593 deletions

View File

@ -1,27 +0,0 @@
import classNames from 'classnames'
interface ButtonProps extends React.ComponentPropsWithoutRef<'button'> {
icon: JSX.Element
value: string
className?: string
handler?: () => void
}
export const Button: React.FC<ButtonProps> = ({
icon,
value,
className,
handler
}) => {
return (
<button
onClick={handler}
className={classNames(
className,
'flex items-center justify-center gap-x-5'
)}>
{icon}
<span className='uppercase'>{value}</span>
</button>
)
}

View File

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

View File

@ -1,68 +0,0 @@
import classNames from 'classnames'
import { AnimatePresence, motion } from 'framer-motion'
import { useState } from 'react'
export interface IDownloaderContent {
title: string
features: string[]
}
interface DownloaderProps {
className?: string
children: React.ReactNode
content: IDownloaderContent
}
export const Downloader: React.FC<DownloaderProps> = ({
className,
children,
content
}) => {
const [activeContent, setActiveContent] = useState(false)
const handleActiveContent = (): void => {
return setActiveContent(!activeContent)
}
return (
<li
className={classNames(
className,
'relative rounded-xl shadow-red-500 hover:shadow-2xl'
)}
onMouseEnter={handleActiveContent}
onMouseLeave={handleActiveContent}>
{children}
<AnimatePresence>
{activeContent && (
<motion.ul
initial={{ opacity: 0 }}
animate={{ opacity: 1, transition: { staggerChildren: 0.5 } }}
exit={{ opacity: 0 }}
className='pointer-events-none text-center absolute left-0 top-0 flex h-full w-full flex-col items-center justify-center rounded-xl bg-black/70 pb-5 text-[12px] text-white'>
<motion.h1
initial={{ opacity: 0, y: -20 }}
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0, y: -20 }}
className='mb-3 text-[16px]'>
{content.title}
</motion.h1>
{content.features.map((feature) => {
return (
<motion.span
initial={{ opacity: 0, y: 50, scale: 0.75 }}
animate={{ opacity: 1, y: 0, scale: 1 }}
exit={{ opacity: 0, y: 50, scale: 0.75 }}
key={feature}>
{feature}
</motion.span>
)
})}
</motion.ul>
)}
</AnimatePresence>
</li>
)
}

View File

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

View File

@ -1,19 +0,0 @@
import classNames from 'classnames'
interface ImageProps extends React.ComponentPropsWithoutRef<'img'> {
size?: number
icon?: boolean
}
export const Image: React.FC<ImageProps> = ({ size, icon, ...rest }) => {
return (
<img
{...rest}
draggable={false}
style={{ imageRendering: Boolean(icon) ? 'pixelated' : 'unset' }}
className={classNames(rest.className, 'select-none')}
height={size ?? rest.height}
width={size ?? rest.width}
/>
)
}

View File

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

View File

@ -1,40 +0,0 @@
import { Maximize, Minus, X } from 'react-feather'
import { appWindow } from '@tauri-apps/api/window'
import { Image } from '../Image'
export const TitleBar: React.FC = () => {
return (
<nav className='flex w-full h-[40px] items-center justify-between bg-[#1f1f1f] text-white'>
<div
className='w-full select-none'
onMouseDown={async () => {
return await appWindow.startDragging()
}}>
<Image src='/Logo.svg' size={60} className='ml-3 p-1' />
</div>
<ul className='flex h-full'>
<li
className='grid h-full w-14 cursor-pointer place-items-center transition-colors duration-[10ms] hover:bg-[#2a2a2a]'
onClick={async () => {
return await appWindow.minimize()
}}>
<Minus />
</li>
<li className='grid h-full w-14 place-items-center cursor-not-allowed opacity-40'>
<Maximize size={20} />
</li>
<li
className='grid h-full w-14 cursor-pointer place-items-center transition-colors duration-[10ms] hover:bg-red-500'
onClick={async () => {
return await appWindow.close()
}}>
<X />
</li>
</ul>
</nav>
)
}

View File

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

View File

@ -1,19 +0,0 @@
import { Fragment } from 'react'
import { TitleBar } from '../TitleBar/TitleBar'
interface WindowProps {
children: React.ReactNode
}
export const Window: React.FC<WindowProps> = ({ children }) => {
return (
<Fragment>
<TitleBar />
<main className='flex items-center justify-center py-20 h-full w-screen flex-col bg-[#242424]'>
{children}
</main>
</Fragment>
)
}

View File

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

View File

@ -1,4 +0,0 @@
export * from './Window'
export * from './Image'
export * from './Button'
export * from './Downloader'

View File

@ -1,62 +0,0 @@
import { getClient, ResponseType } from '@tauri-apps/api/http'
import type { DomainTypes, GameEndPointsTypes } from '../types'
const PROD_VERSION_REGEX = /(production-[^/]+)/im
const STABLE_PROD_VERSION = 'PRODUCTION-202303282207-162719871'
export let PROD_VERSION: string | undefined
const HABBO_URL = (domain: DomainTypes): string => {
return `https://www.habbo.${domain}`
}
const HABBO_IMAGES = `https://images.habbo.com/gordon/${
PROD_VERSION ?? STABLE_PROD_VERSION
}`
export const client = await getClient()
await client
.get(`${HABBO_URL('com')}/gamedata/external_variables/0`, {
responseType: ResponseType.Text
})
.then(({ data }) => {
return (PROD_VERSION = (data as string).match(PROD_VERSION_REGEX)?.[0])
})
export const GAME_ENDPOINTS = (domain: DomainTypes): GameEndPointsTypes => {
return [
{
src: `${HABBO_URL(domain)}/gamedata/figuredata/0`,
convert: 'XML',
fileName: 'FigureData'
},
{
src: `${HABBO_IMAGES}/figuremap.xml`,
convert: 'XML',
fileName: 'FigureMap'
},
{
src: `${HABBO_URL(domain)}/gamedata/furnidata_json/0`,
fileName: 'FurniData'
},
{
src: `${HABBO_URL(domain)}/gamedata/productdata_json/0`,
fileName: 'ProductData'
},
{
src: `${HABBO_IMAGES}/effectmap.xml`,
convert: 'XML',
fileName: 'EffectMap'
},
{
src: `${HABBO_URL(domain)}/gamedata/external_flash_texts/0`,
convert: 'TXT',
fileName: 'ExternalTexts'
}
]
}
export const ASSETS_ENDPOINTS = (domain: DomainTypes): string[] => {
return [`${HABBO_URL(domain)}/`]
}

View File

@ -1,54 +0,0 @@
import { parseData } from '../utils/parseData'
interface IBadge {
code: string
name?: string
description?: string
}
const badgePattern = /^badge_(?:name|desc)_([^=]+)/gim
const descriptionPattern = /^badge_desc_(\s*\w+)/
const namePattern = /^badge_name_(\s*\w+)/
export const convertTXT = async (data: string): Promise<void> => {
const badges: IBadge[] = []
const lines = data.split(/\r?\n/)
for (const line of lines) {
const [key, value] = line.split('=')
const badge = key.match(badgePattern)
if (badge != null) {
if (key.match(namePattern) != null) {
const badgeCode = key.match(namePattern)?.[1] as string
const existingBadge = badges.filter((badge) => {
return badge.code === badgeCode
})[0]
if (Boolean(existingBadge)) {
const index = badges.indexOf(existingBadge)
badges[index].name = value
} else {
badges.push({ code: badgeCode, name: value })
}
} else if (key.match(descriptionPattern) != null) {
const badgeCode = key.match(descriptionPattern)?.[1] as string
const existingBadge = badges.filter((badge) => {
return badge.code === badgeCode
})[0]
if (Boolean(existingBadge)) {
const index = badges.indexOf(existingBadge)
badges[index].description = value
} else {
badges.push({ code: badgeCode, description: value })
}
}
lines.splice(lines.indexOf(line), 1)
}
}
return await parseData('Badges', badges)
}

View File

@ -1,194 +0,0 @@
import type {
IEffectMap,
IEffectMapLibrary,
IFigureData,
IFigureDataColor,
IFigureDataHiddenLayer,
IFigureDataPalette,
IFigureDataPart,
IFigureDataSet,
IFigureDataSetType,
IFigureMap,
IFigureMapLibrary,
IFigureMapLibraryPart
} from '../types'
export const convertXML = (
XML: any,
url: string
): IFigureData | IFigureMap | IEffectMap => {
if (url.includes('figuredata')) {
const output: IFigureData = { palettes: [], setTypes: [] }
for (const paletteXML of XML.figuredata.colors.palette) {
const palette: IFigureDataPalette = { id: 0, color: [] }
if (paletteXML.id !== undefined) palette.id = paletteXML.id
if (paletteXML.color !== undefined) {
for (const colorXML of paletteXML.color) {
const color: IFigureDataColor = {
id: 0,
index: 0,
club: 0,
selectable: false,
hexCode: ''
}
const hexColor = String(colorXML['#text' as keyof IFigureDataColor])
if (colorXML.id !== undefined) color.id = colorXML.id
if (colorXML.index !== undefined) color.index = colorXML.index
if (colorXML.club !== undefined) color.club = colorXML.club
if (colorXML.selectable !== undefined)
color.selectable = colorXML.selectable === 0 ? true : false
if (hexColor !== undefined) color.hexCode = hexColor
palette.color.push(color)
}
}
output.palettes.push(palette)
}
for (const setTypeXML of XML.figuredata.sets.settype) {
const settype: IFigureDataSetType = {
type: '',
paletteId: 0,
mandatoryF0: false,
mandatoryF1: false,
mandatoryM0: false,
mandatoryM1: false,
sets: []
}
if (setTypeXML.type !== undefined) settype.type = setTypeXML.type
if (setTypeXML.paletteId !== undefined)
settype.paletteId = setTypeXML.paletteId
if (setTypeXML.mandatoryF0 !== undefined)
settype.mandatoryF0 = setTypeXML.mandatoryF0
if (setTypeXML.mandatoryF1 !== undefined)
settype.mandatoryF1 = setTypeXML.mandatoryF1
if (setTypeXML.mandatoryM0 !== undefined)
settype.mandatoryM0 = setTypeXML.mandatoryM0
if (setTypeXML.mandatoryM1 !== undefined)
settype.mandatoryM1 = setTypeXML.mandatoryM1
if (setTypeXML.sets !== undefined) {
for (const setXML of setTypeXML.sets) {
const setType: IFigureDataSet = {
id: 0,
gender: 'U',
club: 0,
colorable: false,
selectable: false,
preselectable: false,
sellable: false,
parts: [],
hiddenLayers: []
}
if (setXML.id !== undefined) setType.id = setXML.id
if (setXML.gender !== undefined) setType.gender = setXML.gender
if (setXML.club !== undefined) setType.club = setXML.club
if (setXML.colorable !== undefined)
setType.colorable = setXML.colorable === 0 ? true : false
if (setXML.selectable !== undefined)
setType.selectable = setXML.selectable
if (setXML.preselectable !== undefined)
setType.preselectable = setXML.preselectable
if (setXML.sellable !== undefined) setType.sellable = setXML.sellable
if (setXML.parts !== undefined) {
for (const partXML of setXML.parts) {
const part: IFigureDataPart = {
id: 0,
type: '',
colorable: false,
index: 0,
colorindex: 0
}
if (partXML.id !== undefined) part.id = partXML.id
if (partXML.type !== undefined) part.type = partXML.type
if (partXML.colorable !== undefined)
part.colorable = partXML.colorable
if (partXML.index !== undefined) part.index = partXML.index
if (partXML.colorindex !== undefined)
part.colorindex = partXML.colorindex
setType.parts.push(part)
}
}
if (setXML.hiddenLayers !== undefined) {
for (const hiddenLayerXML of setXML.hiddenLayers) {
const hiddenLayer: IFigureDataHiddenLayer = { partType: '' }
if (hiddenLayerXML.partType !== undefined)
hiddenLayer.partType = hiddenLayerXML.partType
setType.hiddenLayers?.push(hiddenLayer)
}
}
settype.sets.push(setType)
}
}
output.setTypes.push(setTypeXML)
}
return output
} else if (url.includes('figuremap')) {
const output: IFigureMap = { libraries: [] }
for (const libraryXML of XML.map.lib as IFigureMapLibrary[]) {
const library: IFigureMapLibrary = { id: '', revision: 0, part: [] }
if (libraryXML.id !== undefined) library.id = libraryXML.id
if (libraryXML.revision !== undefined)
library.revision = libraryXML.revision
if (Array.isArray(libraryXML.part)) {
for (const libraryPart of libraryXML.part) {
const libraryPartXML: IFigureMapLibraryPart = { id: 0, type: '' }
if (libraryPart.id !== undefined) libraryPartXML.id = libraryPart.id
if (libraryPart.type !== undefined)
libraryPartXML.type = libraryPart.type
library.part.push(libraryPartXML)
}
} else {
const libraryPart = libraryXML.part as unknown as IFigureMapLibraryPart
library.part.push({ id: libraryPart.id, type: libraryPart.type })
}
output.libraries.push(library)
}
return output
} else {
const output: IEffectMap = { effects: [] }
for (const libraryXML of XML.map.effect as IEffectMapLibrary[]) {
const library: IEffectMapLibrary = {
id: 0,
lib: '',
type: '',
revision: 0
}
if (libraryXML.id !== undefined) library.id = libraryXML.id
if (libraryXML.lib !== undefined) library.lib = libraryXML.lib
if (libraryXML.type !== undefined) library.type = libraryXML.type
if (libraryXML.revision !== undefined)
library.revision = libraryXML.revision
output.effects.push(library)
}
return output
}
}

View File

@ -1,2 +0,0 @@
export * from './convertXML'
export * from './convertTXT'

View File

@ -2,35 +2,35 @@ export interface IFurni {
id: number id: number
classname: string classname: string
revision: number revision: number
category: string category?: string
defaultdir: number defaultdir: number
xdim: number xdim: number
ydim: number ydim: number
partcolors: { color: string[] } partcolors?: { color: string[] }
name: string name?: string
description: string description?: string
adurl: string adurl?: string
offerid: number offerid?: number
buyout: boolean buyout: boolean
rentofferid: number rentofferid: number
rentbuyout: boolean rentbuyout: boolean
bc: boolean bc: boolean
excludeddynamic: boolean excludeddynamic: boolean
customparams: string customparams?: string
specialtype: number specialtype: number
canstandon: boolean canstandon: boolean
cansiton: boolean cansiton: boolean
canlayon: boolean canlayon: boolean
furniline: string furniline?: string
environment: string environment?: string
rare: boolean rare: boolean
} }
export interface IFigureDataColor { export interface IFigureDataColor {
id: number id: number
index: number index: number
club: number // must be changed, either 0, 1, 2 club: number // must be changed to something, either 0, 1, 2
selectable: boolean selectable: boolean // has been changed to boolean, can be either 1, 0
hexCode: string hexCode: string
} }
@ -41,35 +41,31 @@ export interface IFigureDataPalette {
export interface IFigureDataPart { export interface IFigureDataPart {
id: number id: number
type: string // must be changed type: string // must be changed (i guess)
colorable: boolean // must be changed colorable: boolean // has been changed to boolean, can be either 1, 0
index: number index: number
colorindex: number colorindex: number
} }
export interface IFigureDataHiddenLayer {
partType: string // must be changed
}
export interface IFigureDataSet { export interface IFigureDataSet {
id: number id: number
gender: 'M' | 'F' | 'U' gender: 'M' | 'F' | 'U' // has been changed
club: number // 0, 1, 2 club: number // must be changed to something, either 0, 1, 2
colorable: boolean // must be changed colorable: boolean // has been changed to boolean, can be either 1, 0
selectable: boolean // must be changed selectable: boolean // has been changed to boolean, can be either 1, 0
preselectable: boolean // must be changed preselectable: boolean // has been changed to boolean, can be either 1, 0
sellable?: boolean // must be changed sellable?: boolean // has been changed to boolean, can be either 1, 0, null
parts: IFigureDataPart[] parts: IFigureDataPart[]
hiddenLayers?: IFigureDataHiddenLayer[] hiddenLayers: Array<{ partType: string }> // !! can be empty
} }
export interface IFigureDataSetType { export interface IFigureDataSetType {
type: string // must be changed type: string // must be changed (i guess)
paletteId: number paletteId: number
mandatoryF0: boolean // 0, 1 mandatoryF0: boolean // has been changed to boolean, can be either 1, 0
mandatoryF1: boolean // 0, 1 mandatoryF1: boolean // has been changed to boolean, can be either 1, 0
mandatoryM0: boolean // 0, 1 mandatoryM0: boolean // has been changed to boolean, can be either 1, 0
mandatoryM1: boolean // 0, 1 mandatoryM1: boolean // has been changed to boolean, can be either 1, 0
sets: IFigureDataSet[] sets: IFigureDataSet[]
} }
@ -87,7 +83,7 @@ export interface IFigureMapLibrary {
export interface IEffectMapLibrary { export interface IEffectMapLibrary {
id: number id: number
lib: string lib: string
type: string type: string // dance || fx
revision: number revision: number
} }

View File

@ -1,50 +0,0 @@
import { ResponseType } from '@tauri-apps/api/http'
import { XMLParser } from 'fast-xml-parser'
import { GAME_ENDPOINTS, client } from '../config/ENDPOINTS'
import type { DomainTypes } from '../types/Domain'
import { convertTXT, convertXML } from '../mapping'
import { parseData } from './parseData'
export const fetchGameData = async (
domain: DomainTypes,
callback: (message: string, error: boolean) => void,
assetsOption = false
): Promise<void> => {
if (!assetsOption) {
await Promise.all(
GAME_ENDPOINTS(domain).map(async (endpoint) => {
await client
.get(endpoint.src, { responseType: ResponseType.Text })
.then(async ({ data }) => {
const currentData = data as string
switch (endpoint.convert) {
case 'XML':
const convertedData = new XMLParser({
ignoreAttributes: false,
attributeNamePrefix: ''
}).parse(currentData)
const XML2JSON = convertXML(convertedData, endpoint.src)
return await parseData(endpoint.fileName, XML2JSON)
case 'TXT':
return await convertTXT(currentData)
default:
return await parseData(endpoint.fileName, currentData)
}
})
.catch((error) => {
console.error(error)
return callback(error, true)
})
})
)
} else {
/* ASSETS_ENDPOINTS(domain).map((endpoint) => {
client.get()
}) */
}
}

View File

@ -1,19 +0,0 @@
import { downloadDir } from '@tauri-apps/api/path'
import { createDir, exists, writeTextFile } from '@tauri-apps/api/fs'
import { PROD_VERSION } from '../config/ENDPOINTS'
export const parseData = async (
fileName: string,
fileContent: string | object
): Promise<void> => {
const outputDir = (await downloadDir()).concat(String(PROD_VERSION))
const fileDir = outputDir.concat(`/${fileName}.json`)
if (!(await exists(outputDir))) await createDir(outputDir)
await writeTextFile(
fileDir,
typeof fileContent === 'object' ? JSON.stringify(fileContent) : fileContent
)
}