feat: finish normalization impl
This commit is contained in:
committed by
Alejandro González
parent
4f70e792ad
commit
a22d90a78d
@@ -207,12 +207,7 @@ async function setupApp() {
|
||||
fetchCredentials()
|
||||
|
||||
try {
|
||||
const skins = (await get_available_skins()).map(async skin => {
|
||||
return {
|
||||
...skin,
|
||||
normalized_texture: await get_normalized_skin_texture(skin.texture)
|
||||
}
|
||||
}) ?? []
|
||||
const skins = (await get_available_skins()) ?? []
|
||||
const capes = (await get_available_capes()) ?? []
|
||||
generateSkinPreviews(skins, capes)
|
||||
} catch (error) {
|
||||
|
||||
@@ -113,12 +113,12 @@ import {
|
||||
unequip_skin,
|
||||
type Skin,
|
||||
type Cape,
|
||||
type SkinModel, normalize_skin_texture, get_normalized_skin_texture,
|
||||
type SkinModel,
|
||||
get_normalized_skin_texture,
|
||||
} from '@/helpers/skins.ts'
|
||||
import { handleError } from '@/store/notifications'
|
||||
import { UploadIcon, CheckIcon, SaveIcon, XIcon, ChevronRightIcon } from '@modrinth/assets'
|
||||
import {computedAsync} from "@vueuse/core";
|
||||
import {arrayBufferToBase64} from "@modrinth/utils";
|
||||
|
||||
const modal = useTemplateRef('modal')
|
||||
const selectCapeModal = useTemplateRef('selectCapeModal')
|
||||
@@ -126,13 +126,7 @@ const mode = ref<'new' | 'edit'>('new')
|
||||
const currentSkin = ref<Skin | null>(null)
|
||||
const shouldRestoreModal = ref(false)
|
||||
|
||||
const fileUploadTextureBlob = ref<Uint8Array | null>(null)
|
||||
const fileName = ref<string | null>(null)
|
||||
watch(fileUploadTextureBlob, () => {
|
||||
if (fileName.value === null && fileUploadTextureBlob.value) {
|
||||
fileName.value = 'New upload'
|
||||
}
|
||||
})
|
||||
const uploadedTextureUrl = ref<string | null>(null)
|
||||
|
||||
const variant = ref<SkinModel>('CLASSIC')
|
||||
const selectedCape = ref<Cape | undefined>(undefined)
|
||||
@@ -175,23 +169,16 @@ function getSortedCapeExcluding(excludeId: string): Cape | undefined {
|
||||
return sortedCapes.value.find((cape) => cape.id !== excludeId)
|
||||
}
|
||||
|
||||
const localPreviewUrl = ref<string | null>(null)
|
||||
watch(fileUploadTextureBlob, (blob, prev) => {
|
||||
if (prev && localPreviewUrl.value) URL.revokeObjectURL(localPreviewUrl.value)
|
||||
if (blob) localPreviewUrl.value = URL.createObjectURL(new Blob([blob]))
|
||||
else localPreviewUrl.value = null
|
||||
})
|
||||
const previewSkin = computedAsync(async () => {
|
||||
if (localPreviewUrl.value)
|
||||
return localPreviewUrl.value;
|
||||
if (uploadedTextureUrl.value) return uploadedTextureUrl.value
|
||||
else if (currentSkin.value) {
|
||||
return await get_normalized_skin_texture(currentSkin.value);
|
||||
return await get_normalized_skin_texture(currentSkin.value)
|
||||
} else return '/src/assets/skins/steve.png'
|
||||
})
|
||||
|
||||
const hasEdits = computed(() => {
|
||||
if (mode.value !== 'edit') return true
|
||||
if (fileUploadTextureBlob.value) return true
|
||||
if (uploadedTextureUrl.value) return true
|
||||
if (!currentSkin.value) return false
|
||||
if (variant.value !== currentSkin.value.variant) return true
|
||||
if ((selectedCape.value?.id || null) !== (currentSkin.value.cape_id || null)) return true
|
||||
@@ -200,12 +187,12 @@ const hasEdits = computed(() => {
|
||||
|
||||
const disableSave = computed(
|
||||
() =>
|
||||
(mode.value === 'new' && !fileUploadTextureBlob.value) ||
|
||||
(mode.value === 'new' && !uploadedTextureUrl.value) ||
|
||||
(mode.value === 'edit' && !hasEdits.value),
|
||||
)
|
||||
|
||||
const saveTooltip = computed(() => {
|
||||
if (mode.value === 'new' && !fileUploadTextureBlob.value) return 'Upload a skin first!'
|
||||
if (mode.value === 'new' && !uploadedTextureUrl.value) return 'Upload a skin first!'
|
||||
if (mode.value === 'edit' && !hasEdits.value) return 'Make an edit to the skin first!'
|
||||
return undefined
|
||||
})
|
||||
@@ -213,16 +200,11 @@ const saveTooltip = computed(() => {
|
||||
function resetState() {
|
||||
mode.value = 'new'
|
||||
currentSkin.value = null
|
||||
fileUploadTextureBlob.value = null
|
||||
fileName.value = null
|
||||
uploadedTextureUrl.value = null
|
||||
variant.value = 'CLASSIC'
|
||||
selectedCape.value = undefined
|
||||
visibleCapeList.value = []
|
||||
shouldRestoreModal.value = false
|
||||
if (localPreviewUrl.value) {
|
||||
URL.revokeObjectURL(localPreviewUrl.value)
|
||||
localPreviewUrl.value = null
|
||||
}
|
||||
}
|
||||
|
||||
function show(e: MouseEvent, skin?: Skin) {
|
||||
@@ -240,11 +222,10 @@ function show(e: MouseEvent, skin?: Skin) {
|
||||
modal.value?.show(e)
|
||||
}
|
||||
|
||||
function showNew(e: MouseEvent, skinTexture: Uint8Array, filename: string) {
|
||||
function showNew(e: MouseEvent, skinTextureUrl: string) {
|
||||
mode.value = 'new'
|
||||
currentSkin.value = null
|
||||
fileUploadTextureBlob.value = skinTexture
|
||||
fileName.value = filename
|
||||
uploadedTextureUrl.value = skinTextureUrl
|
||||
variant.value = 'CLASSIC'
|
||||
selectedCape.value = undefined
|
||||
visibleCapeList.value = []
|
||||
@@ -252,9 +233,8 @@ function showNew(e: MouseEvent, skinTexture: Uint8Array, filename: string) {
|
||||
modal.value?.show(e)
|
||||
}
|
||||
|
||||
function restoreWithNewTexture(skinTexture: Uint8Array, filename: string) {
|
||||
fileUploadTextureBlob.value = skinTexture
|
||||
fileName.value = filename
|
||||
function restoreWithNewTexture(skinTextureUrl: string) {
|
||||
uploadedTextureUrl.value = skinTextureUrl
|
||||
|
||||
if (shouldRestoreModal.value) {
|
||||
setTimeout(() => {
|
||||
@@ -331,23 +311,23 @@ function openUploadSkinModal(e: MouseEvent) {
|
||||
|
||||
async function save() {
|
||||
try {
|
||||
let blob: Uint8Array
|
||||
if (fileUploadTextureBlob.value) {
|
||||
blob = fileUploadTextureBlob.value
|
||||
let textureUrl: string
|
||||
|
||||
if (uploadedTextureUrl.value) {
|
||||
textureUrl = uploadedTextureUrl.value
|
||||
} else {
|
||||
const url = currentSkin.value!.texture
|
||||
const resp = await fetch(url)
|
||||
const buf = await resp.arrayBuffer()
|
||||
blob = new Uint8Array(buf)
|
||||
textureUrl = currentSkin.value!.texture
|
||||
}
|
||||
|
||||
await unequip_skin()
|
||||
|
||||
const bytes: Uint8Array = new Uint8Array(await (await fetch(textureUrl)).arrayBuffer())
|
||||
|
||||
if (mode.value === 'new') {
|
||||
await add_and_equip_custom_skin(blob, variant.value, selectedCape.value)
|
||||
await add_and_equip_custom_skin(bytes, variant.value, selectedCape.value)
|
||||
emit('saved')
|
||||
} else {
|
||||
await add_and_equip_custom_skin(blob, variant.value, selectedCape.value)
|
||||
await add_and_equip_custom_skin(bytes, variant.value, selectedCape.value)
|
||||
await remove_custom_skin(currentSkin.value!)
|
||||
emit('saved')
|
||||
}
|
||||
|
||||
@@ -145,7 +145,7 @@ export async function cleanupUnusedPreviews(skins: Skin[]): Promise<void> {
|
||||
}
|
||||
}
|
||||
|
||||
export async function generateSkinPreviews(skins: (Skin & { normalized_skin_texture: string })[], capes: Cape[]): Promise<void> {
|
||||
export async function generateSkinPreviews(skins: Skin[], capes: Cape[]): Promise<void> {
|
||||
const renderer = new BatchSkinRenderer()
|
||||
const capeModelUrl = '/src/assets/models/cape.gltf'
|
||||
|
||||
@@ -185,7 +185,7 @@ export async function generateSkinPreviews(skins: (Skin & { normalized_skin_text
|
||||
const modelUrl = getModelUrlForVariant(variant)
|
||||
const cape: Cape | undefined = capes.find((_cape) => _cape.id === skin.cape_id)
|
||||
const renderResult = await renderer.renderSkin(
|
||||
skin.normalized_skin_texture,
|
||||
await get_normalized_skin_texture(skin),
|
||||
modelUrl,
|
||||
cape?.texture,
|
||||
capeModelUrl,
|
||||
|
||||
@@ -41,6 +41,7 @@ import {generateSkinPreviews, map} from '@/helpers/rendering/batch-skin-renderer
|
||||
import {handleSevereError} from '@/store/error'
|
||||
import {trackEvent} from '@/helpers/analytics'
|
||||
import type AccountsCard from '@/components/ui/AccountsCard.vue'
|
||||
import {arrayBufferToBase64} from "@modrinth/utils";
|
||||
|
||||
const editSkinModal = useTemplateRef('editSkinModal')
|
||||
const selectCapeModal = useTemplateRef('selectCapeModal')
|
||||
@@ -177,12 +178,13 @@ function openUploadSkinModal(e: MouseEvent) {
|
||||
function onSkinFileUploaded(file: File) {
|
||||
const fakeEvent = new MouseEvent('click')
|
||||
file.arrayBuffer().then(async (buf) => {
|
||||
const skinTexture: Uint8Array = await normalize_skin_texture(new Uint8Array(buf))
|
||||
const skinTextureNormalized: Uint8Array = await normalize_skin_texture(`data:image/png;base64,` + arrayBufferToBase64(buf))
|
||||
const skinTexUrl = `data:image/png;base64,` + arrayBufferToBase64(skinTextureNormalized);
|
||||
|
||||
if (editSkinModal.value && editSkinModal.value.shouldRestoreModal) {
|
||||
editSkinModal.value.restoreWithNewTexture(skinTexture, file.name)
|
||||
editSkinModal.value.restoreWithNewTexture(skinTexUrl)
|
||||
} else {
|
||||
editSkinModal.value?.showNew(fakeEvent, skinTexture, file.name)
|
||||
editSkinModal.value?.showNew(fakeEvent, skinTexUrl)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user