fix: various improvements

This commit is contained in:
Calum H.
2025-06-15 20:57:20 +01:00
parent 1b4b2a9394
commit cb39fe6f24
2 changed files with 99 additions and 14 deletions

View File

@@ -22,7 +22,7 @@ import { computed, inject, onMounted, onUnmounted, ref, useTemplateRef, watch }
import EditSkinModal from '@/components/ui/skin/EditSkinModal.vue'
import SelectCapeModal from '@/components/ui/skin/SelectCapeModal.vue'
import UploadSkinModal from '@/components/ui/skin/UploadSkinModal.vue'
import { handleError } from '@/store/notifications'
import { handleError, useNotifications } from '@/store/notifications'
import type { Cape, Skin } from '@/helpers/skins.ts'
import {
normalize_skin_texture,
@@ -48,6 +48,8 @@ const editSkinModal = useTemplateRef('editSkinModal')
const selectCapeModal = useTemplateRef('selectCapeModal')
const uploadSkinModal = useTemplateRef('uploadSkinModal')
const notifications = useNotifications()
const settings = ref(await getSettings())
const skins = ref<Skin[]>([])
const capes = ref<Cape[]>([])
@@ -149,7 +151,16 @@ async function changeSkin(newSkin: Skin) {
} catch (error) {
selectedSkin.value = previousSkin
skins.value = previousSkinsList
handleError(error)
if ((error as { message?: string })?.message?.includes('429 Too Many Requests')) {
notifications.addNotification({
type: 'error',
title: 'Slow down!',
text: "You're changing your skin too frequently. Mojang's servers have temporarily blocked further requests. Please wait a moment before trying again.",
})
} else {
handleError(error)
}
}
}
@@ -169,7 +180,16 @@ async function handleCapeSelected(cape: Cape | undefined) {
} catch (error) {
defaultCape.value = previousDefaultCape
capes.value = previousCapesList
handleError(error)
if ((error as { message?: string })?.message?.includes('429 Too Many Requests')) {
notifications.addNotification({
type: 'error',
title: 'Slow down!',
text: "You're changing your cape too frequently. Mojang's servers have temporarily blocked further requests. Please wait a moment before trying again.",
})
} else {
handleError(error)
}
}
}

View File

@@ -150,7 +150,7 @@ const props = withDefaults(
baseAnimation: 'idle',
randomAnimations: ['idle_sub_1', 'idle_sub_2', 'idle_sub_3'],
randomAnimationInterval: 8000,
transitionDuration: 0.5,
transitionDuration: 0.2,
}),
},
)
@@ -204,11 +204,14 @@ function initializeAnimations(loadedScene: THREE.Object3D, clips: THREE.Animatio
clips.forEach((clip) => {
const action = mixer.value!.clipAction(clip)
action.setLoop(THREE.LoopOnce, 1)
action.clampWhenFinished = true
actions.value[clip.name] = action
console.log(`Loaded animation: ${clip.name}`)
})
if (baseAnimation.value && actions.value[baseAnimation.value]) {
actions.value[baseAnimation.value].setLoop(THREE.LoopRepeat, Infinity)
playAnimation(baseAnimation.value)
setupRandomAnimationLoop()
} else {
@@ -216,7 +219,7 @@ function initializeAnimations(loadedScene: THREE.Object3D, clips: THREE.Animatio
const firstAnimationName = Object.keys(actions.value)[0]
if (firstAnimationName) {
console.log(`Playing first available animation: ${firstAnimationName}`)
actions.value[firstAnimationName].setLoop(THREE.LoopRepeat, Infinity)
playAnimation(firstAnimationName)
}
}
@@ -229,6 +232,12 @@ function playAnimation(name: string) {
}
const action = actions.value[name]
if (currentAnimation.value === name && action.isRunning() && name !== baseAnimation.value) {
console.log(`Animation "${name}" is already running, ignoring request`)
return false
}
const transitionDuration = props.animationConfig.transitionDuration || 0.3
Object.entries(actions.value).forEach(([actionName, actionInstance]) => {
@@ -238,12 +247,35 @@ function playAnimation(name: string) {
})
action.reset()
action.setLoop(THREE.LoopRepeat, Infinity)
if (name === baseAnimation.value) {
action.setLoop(THREE.LoopRepeat, Infinity)
} else {
action.setLoop(THREE.LoopOnce, 1)
action.clampWhenFinished = true
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const onFinished = (event: any) => {
if (event.action === action) {
mixer.value?.removeEventListener('finished', onFinished)
if (currentAnimation.value === name && baseAnimation.value) {
action.fadeOut(transitionDuration)
const baseAction = actions.value[baseAnimation.value]
baseAction.reset()
baseAction.fadeIn(transitionDuration)
baseAction.play()
currentAnimation.value = baseAnimation.value
}
}
}
mixer.value.addEventListener('finished', onFinished)
}
action.fadeIn(transitionDuration)
action.play()
currentAnimation.value = name
console.log(`Playing animation: ${name}`)
return true
}
@@ -265,15 +297,48 @@ function setupRandomAnimationLoop() {
}
function playRandomAnimation(name: string) {
if (!playAnimation(name)) return
if (!mixer.value || !actions.value[name]) {
console.warn(`Animation "${name}" not found!`)
return
}
const animationDuration = actions.value[name].getClip().duration * 1000
const action = actions.value[name]
setTimeout(() => {
if (currentAnimation.value === name && baseAnimation.value) {
playAnimation(baseAnimation.value)
if (currentAnimation.value === name && action.isRunning()) {
console.log(`Animation "${name}" is already running, ignoring request`)
return
}
const transitionDuration = props.animationConfig.transitionDuration || 0.3
if (baseAnimation.value && actions.value[baseAnimation.value].isRunning()) {
actions.value[baseAnimation.value].fadeOut(transitionDuration)
}
action.reset()
action.setLoop(THREE.LoopOnce, 1)
action.clampWhenFinished = true
action.fadeIn(transitionDuration)
action.play()
currentAnimation.value = name
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const onFinished = (event: any) => {
if (event.action === action) {
mixer.value?.removeEventListener('finished', onFinished)
if (currentAnimation.value === name && baseAnimation.value) {
action.fadeOut(transitionDuration)
const baseAction = actions.value[baseAnimation.value]
baseAction.reset()
baseAction.fadeIn(transitionDuration)
baseAction.play()
currentAnimation.value = baseAnimation.value
}
}
}, animationDuration + 500)
}
mixer.value.addEventListener('finished', onFinished)
}
function stopAnimations() {