From 645a0a2eacc65569e81f01f6a7cf761450c9db31 Mon Sep 17 00:00:00 2001 From: Andcool-Systems Date: Wed, 1 Jan 2025 21:48:01 +0300 Subject: [PATCH] refactored bandage rendering code --- src/app/modules/utils/apiManager.ts | 7 +- src/app/workshop/[id]/bandage_engine.ts | 125 +++++++----------- src/app/workshop/[id]/client.tsx | 57 ++++---- src/app/workshop/[id]/components/skinLoad.tsx | 14 +- src/app/workshop/create/page.tsx | 9 +- 5 files changed, 80 insertions(+), 132 deletions(-) diff --git a/src/app/modules/utils/apiManager.ts b/src/app/modules/utils/apiManager.ts index 0b1c573..6d4809e 100644 --- a/src/app/modules/utils/apiManager.ts +++ b/src/app/modules/utils/apiManager.ts @@ -4,6 +4,7 @@ import axios, { AxiosResponse, Method } from "axios"; import { Query } from "../components/Header"; import { SettingsResponse } from "@/app/me/settings/page"; import { SearchResponse } from "../components/NickSearch"; +import { SkinResponse } from "@/app/workshop/[id]/bandage_engine"; type RequestProps = { url: string, @@ -235,11 +236,11 @@ class ApiManager { } /* Get Minecraft skin */ - static async getSkin(nickname: string): Promise { + static async getSkin(nickname: string): Promise { return (await this.doRequestSimple({ - url: `/minecraft/skin/${nickname}?cape=true`, + url: `/minecraft/skin/${nickname}`, method: 'GET' - })); + })).data; } /* Get sessions */ diff --git a/src/app/workshop/[id]/bandage_engine.ts b/src/app/workshop/[id]/bandage_engine.ts index b06db46..65165e6 100644 --- a/src/app/workshop/[id]/bandage_engine.ts +++ b/src/app/workshop/[id]/bandage_engine.ts @@ -1,7 +1,7 @@ import asyncImage, { base64Encode } from '@/app/modules/utils/asyncImage'; import ApiManager from '@/app/modules/utils/apiManager'; -interface SkinResponse { +export interface SkinResponse { data: { skin: { data: string, @@ -32,7 +32,6 @@ interface Settings { class Client { skin: string = ""; cape: string = ""; - listeners: { [key: string]: Function } = {}; original_canvas: HTMLCanvasElement = null; pepe_canvas: HTMLCanvasElement = null; @@ -52,14 +51,18 @@ class Client { colorable: boolean = false; split_types: boolean = false; + onRendered: ({ skin, cape, slim }: { skin: string, cape: string, slim: boolean }) => void = undefined; + onInit: () => void = undefined; + private main_bandage: HTMLCanvasElement = null; loadBase() { - asyncImage('/static/workshop_base.png').then(skin => { - const context = this.original_canvas.getContext("2d"); - context?.drawImage(skin, 0, 0); - this.triggerEvent("init"); - }); + asyncImage('/static/workshop_base.png') + .then(skin => { + const context = this.original_canvas.getContext("2d"); + context!.drawImage(skin, 0, 0); + !!this.onInit && this.onInit(); + }); } constructor() { @@ -72,79 +75,45 @@ class Client { color_picker?.addEventListener("input", () => this.rerender()); } - addEventListener(property: string, func: Function) { - this.listeners[property] = func; - } - - removeEventListener(property: string) { - delete this.listeners[property]; - } - async loadSkin(nickname: string): Promise { if (!nickname) return; - const response = await ApiManager.getSkin(nickname); - - const data = response.data as SkinResponse; + const data = await ApiManager.getSkin(nickname); this.slim = data.data.skin.slim; - this.addEventListener("onload", () => { - + this.setOriginalCanvas(b64Prefix + data.data.skin.data, () => { this.skin = b64Prefix + data.data.skin; this.cape = b64Prefix + data.data.cape; this.rerender(); - this.removeEventListener("onload"); }); - - this.setOriginalCanvas(b64Prefix + data.data.skin.data); } loadSkinUrl(url: string) { asyncImage(url) .then(img => { const base64 = base64Encode(img); - this.addEventListener("onload", () => { + this.setOriginalCanvas(base64, () => { this.skin = base64; this.rerender(); - this.removeEventListener("onload"); }); - - this.setOriginalCanvas(base64); }) .catch(console.error); } - triggerEvent(property: string) { - if (property === 'rerender' || this.listeners[property]) { - switch (property) { - case "skin_changed": - this.listeners[property]({ skin: this.skin, cape: this.cape }); - break; - case "rerender": - this.rerender(); - break; - default: - this.listeners[property](); - break; - } - } - } - - private setOriginalCanvas(b64: string) { + private setOriginalCanvas(b64: string, callback: () => void) { const context = this.original_canvas.getContext('2d'); if (!context) { return; } - asyncImage(b64).then((img) => { - if (img.width != 64 || img.height != 64) { - return; - } - context.clearRect(0, 0, 64, 64); - context.drawImage(img, 0, 0, img.width, img.height); - this.triggerEvent("onload"); - }); + asyncImage(b64) + .then(img => { + if (img.width != 64 || img.height != 64) return; + context.clearRect(0, 0, 64, 64); + context.drawImage(img, 0, 0, img.width, img.height); + callback(); + }); } //---------------------bandage_manager------------------- @@ -163,8 +132,14 @@ class Client { context_pepe.drawImage(img, 0, 0, 16, height, 0, 0, 16, height); context_lining.drawImage(img, 0, height, 16, height, 0, 0, 16, height); - !slim ? this.pepe_canvas = pepe_canvas : this.pepe_canvas_slim = pepe_canvas; - !slim ? this.lining_canvas = lining_canvas : this.lining_canvas_slim = lining_canvas; + + if (slim) { + this.pepe_canvas_slim = pepe_canvas; + this.lining_canvas_slim = lining_canvas; + } else { + this.pepe_canvas = pepe_canvas; + this.lining_canvas = lining_canvas; + } this.position = 6 - Math.floor(height / 2); this.rerender(); @@ -176,37 +151,25 @@ class Client { } changeSkin(skin: string, slim?: boolean, cape?: string) { - if (slim != undefined) this.slim = slim; - this.addEventListener("onload", () => { + if (slim !== undefined) this.slim = slim; + this.setOriginalCanvas(skin, () => { this.skin = skin; this.cape = cape; this.rerender(); - this.removeEventListener("onload"); }); - this.setOriginalCanvas(skin); } - setParams({ - body_part, - position, - clear_pix, - first_layer, - second_layer, - layers, - color, - colorable, - split_types - }: Settings) { - if (body_part != undefined) this.body_part = body_part; - if (position != undefined) this.position = position; - if (clear_pix != undefined) this.clear_pix = clear_pix; - if (first_layer != undefined) this.first_layer = first_layer; - if (second_layer != undefined) this.second_layer = second_layer; - if (layers != undefined) this.layers = layers; - if (color != undefined) this.color = color; - if (colorable != undefined) this.colorable = colorable; - if (split_types != undefined) this.split_types = split_types; + setParams(props: Settings) { + if (props.body_part != undefined) this.body_part = props.body_part; + if (props.position != undefined) this.position = props.position; + if (props.clear_pix != undefined) this.clear_pix = props.clear_pix; + if (props.first_layer != undefined) this.first_layer = props.first_layer; + if (props.second_layer != undefined) this.second_layer = props.second_layer; + if (props.layers != undefined) this.layers = props.layers; + if (props.color != undefined) this.color = props.color; + if (props.colorable != undefined) this.colorable = props.colorable; + if (props.split_types != undefined) this.split_types = props.split_types; this.rerender(); } @@ -282,7 +245,11 @@ class Client { if (!download) { this.skin = canvas.toDataURL(); - this.triggerEvent("skin_changed"); + !!this.onRendered && this.onRendered({ + skin: this.skin, + cape: this.cape, + slim: this.slim + }); } else { this.download(canvas.toDataURL()); } diff --git a/src/app/workshop/[id]/client.tsx b/src/app/workshop/[id]/client.tsx index 930f62a..bbd47ad 100644 --- a/src/app/workshop/[id]/client.tsx +++ b/src/app/workshop/[id]/client.tsx @@ -125,7 +125,6 @@ export default function Home({ data, referrer }: { data: Interfaces.Bandage, ref selector.value = rgbToHex(~~color.r, ~~color.g, ~~color.b); client.current.setParams({ color: selector.value }); - client.current.rerender(); } useEffect(() => { @@ -138,48 +137,38 @@ export default function Home({ data, referrer }: { data: Interfaces.Bandage, ref } client.current = new Client(); - client.current.addEventListener('skin_changed', (event: { skin: string, cape: string }) => { + client.current.onRendered = (event) => { setSkin(event.skin); setCape(event.cape); - setSlim(client.current.slim); - }); + setSlim(event.slim); + }; - client.current.addEventListener('init', () => { + client.current.onInit = () => { if (data.me_profile) client.current.loadSkin(data.me_profile.uuid); - asyncImage(b64Prefix + data.base64).then(bandage => { - const height = bandage.height / 2; - const pepe_canvas = document.createElement('canvas') as HTMLCanvasElement; - const context_pepe = pepe_canvas.getContext('2d'); - pepe_canvas.width = 16; - pepe_canvas.height = height; - - const lining_canvas = document.createElement('canvas') as HTMLCanvasElement; - const context_lining = lining_canvas.getContext('2d'); - lining_canvas.width = 16; - lining_canvas.height = height; - - context_pepe.drawImage(bandage, 0, 0, 16, height, 0, 0, 16, height); - context_lining.drawImage(bandage, 0, height, 16, height, 0, 0, 16, height); - client.current.pepe_canvas = pepe_canvas; - client.current.lining_canvas = lining_canvas; - client.current.position = 6 - Math.floor(height / 2); - setRangeProps({ value: client.current.position, max: (12 - client.current.pepe_canvas.height) }); - client.current.colorable = data.categories.some(val => val.colorable); - const randomColor = getRandomColor(); - setRandomColor(randomColor); - client.current.setParams({ color: randomColor }); - client.current.rerender(); - setLoaded(true); - }); + asyncImage(b64Prefix + data.base64) + .then(bandage => { + client.current.loadFromImage(bandage); + + setRangeProps({ + value: client.current.position, + max: (12 - client.current.pepe_canvas.height) + }); + + client.current.colorable = data.categories.some(val => val.colorable); + if (client.current.colorable) { + const randomColor = getRandomColor(); + setRandomColor(randomColor); + client.current.setParams({ color: randomColor }); + } + setLoaded(true); + }); if (data.split_type) { client.current.setParams({ split_types: true }); - asyncImage(b64Prefix + data.base64_slim).then(img => { - client.current.loadFromImage(img, true) - }); + asyncImage(b64Prefix + data.base64_slim).then(img => client.current.loadFromImage(img, true)); } - }); + }; scrollTo(0, 0); }, []); diff --git a/src/app/workshop/[id]/components/skinLoad.tsx b/src/app/workshop/[id]/components/skinLoad.tsx index 65b5d8a..533a216 100644 --- a/src/app/workshop/[id]/components/skinLoad.tsx +++ b/src/app/workshop/[id]/components/skinLoad.tsx @@ -8,6 +8,7 @@ import Searcher from "@/app/modules/components/NickSearch"; import ApiManager from "@/app/modules/utils/apiManager"; import { CSSTransition } from "react-transition-group"; import axios, { AxiosError } from "axios"; +import { SkinResponse } from "../bandage_engine"; const b64Prefix = "data:image/png;base64,"; @@ -16,16 +17,6 @@ interface SkinLoadProps { expanded: boolean } -interface SkinResponse { - data: { - skin: { - data: string, - slim: boolean - }, - cape: string - } -} - const SkinLoad = ({ expanded, onChange }: SkinLoadProps) => { const [data, setData] = useState<{ data: string; slim: boolean; cape?: string }>(null); const [loaded, setLoaded] = useState(false); @@ -48,8 +39,7 @@ const SkinLoad = ({ expanded, onChange }: SkinLoadProps) => { if (!nickname) return; ApiManager.getSkin(nickname) - .then(response => { - const data = response.data as SkinResponse; + .then(data => { setData({ data: b64Prefix + data.data.skin.data, slim: data.data.skin.slim, diff --git a/src/app/workshop/create/page.tsx b/src/app/workshop/create/page.tsx index 913419e..39bcf21 100644 --- a/src/app/workshop/create/page.tsx +++ b/src/app/workshop/create/page.tsx @@ -51,10 +51,10 @@ export default function Home() { useEffect(() => { client.current = new Client(); - client.current.addEventListener('skin_changed', (event: { skin: string, cape: string }) => { + client.current.onRendered = (event) => { setSKIN(event.skin); - setSlim(client.current.slim); - }); + setSlim(event.slim); + }; client.current.loadSkinUrl("/static/workshop_base.png"); window.addEventListener('beforeunload', beforeUnload); @@ -70,7 +70,8 @@ export default function Home() {