<!--
Auto-generated by: https://github.com/threlte/threlte/tree/main/packages/gltf
Command: npx @threlte/gltf@3.0.1 static/new-characters/Witch.glb -t -s
-->

<script lang="ts">
	import type * as THREE from 'three';
	import { Group } from 'three';
	import type { Snippet } from 'svelte';
	import { T, type Props } from '@threlte/core';
	import { useGltf, useGltfAnimations } from '@threlte/extras';
	import { base } from '$app/paths';

	let {
		fallback,
		error,
		children,
		ref = $bindable(),
		currentAction = 'Idle',
		transitionDuration = 0.3,
		...props
	}: Props<THREE.Group> & {
		ref?: THREE.Group;
		children?: Snippet<[{ ref: THREE.Group }]>;
		fallback?: Snippet;
		error?: Snippet<[{ error: Error }]>;
		currentAction: ActionName | undefined;
		transitionDuration?: number;
	} = $props();

	ref = new Group();

	type ActionName =
		| '1H_Melee_Attack_Chop'
		| '1H_Melee_Attack_Jump_Chop'
		| '1H_Melee_Attack_Slice_Diagonal'
		| '1H_Melee_Attack_Slice_Horizontal'
		| '1H_Melee_Attack_Stab'
		| '1H_Ranged_Aiming'
		| '1H_Ranged_Reload'
		| '1H_Ranged_Shoot'
		| '1H_Ranged_Shooting'
		| '2H_Melee_Attack_Chop'
		| '2H_Melee_Attack_Slice'
		| '2H_Melee_Attack_Spin'
		| '2H_Melee_Attack_Spinning'
		| '2H_Melee_Attack_Stab'
		| '2H_Melee_Idle'
		| '2H_Ranged_Aiming'
		| '2H_Ranged_Reload'
		| '2H_Ranged_Shoot'
		| '2H_Ranged_Shooting'
		| 'Block'
		| 'Block_Attack'
		| 'Block_Hit'
		| 'Blocking'
		| 'Cheer'
		| 'Death_A'
		| 'Death_A_Pose'
		| 'Death_B'
		| 'Death_B_Pose'
		| 'Death_C_Pose'
		| 'Death_C_Skeletons'
		| 'Death_C_Skeletons_Resurrect'
		| 'Dodge_Backward'
		| 'Dodge_Forward'
		| 'Dodge_Left'
		| 'Dodge_Right'
		| 'Dualwield_Melee_Attack_Chop'
		| 'Dualwield_Melee_Attack_Slice'
		| 'Dualwield_Melee_Attack_Stab'
		| 'Hit_A'
		| 'Hit_B'
		| 'Idle'
		| 'Idle_B'
		| 'Idle_Combat'
		| 'Interact'
		| 'Jump_Full_Long'
		| 'Jump_Full_Short'
		| 'Jump_Idle'
		| 'Jump_Land'
		| 'Jump_Start'
		| 'Lie_Down'
		| 'Lie_Idle'
		| 'Lie_Pose'
		| 'Lie_StandUp'
		| 'PickUp'
		| 'Running_A'
		| 'Running_B'
		| 'Running_C'
		| 'Running_Strafe_Left'
		| 'Running_Strafe_Right'
		| 'Sit_Chair_Down'
		| 'Sit_Chair_Idle'
		| 'Sit_Chair_Pose'
		| 'Sit_Chair_StandUp'
		| 'Sit_Floor_Down'
		| 'Sit_Floor_Idle'
		| 'Sit_Floor_Pose'
		| 'Sit_Floor_StandUp'
		| 'Skeleton_Inactive_Standing_Pose'
		| 'Skeletons_Awaken_Floor'
		| 'Skeletons_Awaken_Floor_Long'
		| 'Skeletons_Awaken_Standing'
		| 'Skeletons_Inactive_Floor_Pose'
		| 'Spawn_Air'
		| 'Spawn_Ground'
		| 'Spawn_Ground_Skeletons'
		| 'Spellcast_Long'
		| 'Spellcast_Raise'
		| 'Spellcast_Shoot'
		| 'Spellcast_Summon'
		| 'Spellcasting'
		| 'T-Pose'
		| 'Taunt'
		| 'Taunt_Longer'
		| 'Throw'
		| 'Unarmed_Idle'
		| 'Unarmed_Melee_Attack_Kick'
		| 'Unarmed_Melee_Attack_Punch_A'
		| 'Unarmed_Melee_Attack_Punch_B'
		| 'Unarmed_Pose'
		| 'Use_Item'
		| 'Walking_A'
		| 'Walking_B'
		| 'Walking_Backwards'
		| 'Walking_C'
		| 'Walking_D_Skeletons';
	type GLTFResult = {
		nodes: {
			Witch_ArmLeft: THREE.SkinnedMesh;
			Witch_ArmRight: THREE.SkinnedMesh;
			Witch_Body: THREE.SkinnedMesh;
			Witch_Glasses_1: THREE.SkinnedMesh;
			Witch_Glasses_2: THREE.SkinnedMesh;
			Witch_Hat: THREE.SkinnedMesh;
			Witch_Head: THREE.SkinnedMesh;
			Witch_LegLeft: THREE.SkinnedMesh;
			Witch_LegRight: THREE.SkinnedMesh;
			root: THREE.Bone;
		};
		materials: {
			witch: THREE.MeshStandardMaterial;
			glass: THREE.MeshStandardMaterial;
		};
	};

	const gltf = useGltf<GLTFResult>(
		base + '/new-characters/Witch.glb' + '?r=' + Math.random().toFixed(4)
	);

	export const { actions, mixer } = useGltfAnimations<ActionName>(gltf, ref);

	let lastAction: ActionName | undefined = $state(undefined);

	$effect(() => {
		if (currentAction && $actions[currentAction] && lastAction !== currentAction) {
			if (!lastAction) {
				let action = $actions[currentAction];
				action?.play();
			} else {
				transitionTo(currentAction);
			}
			lastAction = currentAction;
		}
	});

	const transitionTo = (nextActionKey: ActionName, duration = transitionDuration) => {
		if (!lastAction) return;
		const action = $actions[lastAction];
		const nextAction = $actions[nextActionKey];

		if (!nextAction || action === nextAction) return;

		nextAction.enabled = true;
		if (action) {
			action.crossFadeTo(nextAction, duration, true);
		}
		nextAction.play();
	};
</script>

<T is={ref} dispose={false} {...props}>
	{#await gltf}
		{@render fallback?.()}
	{:then gltf}
		<T.Group name="Scene">
			<T.Group name="Rig">
				<T is={gltf.nodes.root} />
				<T.SkinnedMesh
					name="Witch_ArmLeft"
					castShadow
					receiveShadow
					geometry={gltf.nodes.Witch_ArmLeft.geometry}
					material={gltf.materials.witch}
					skeleton={gltf.nodes.Witch_ArmLeft.skeleton}
				/>
				<T.SkinnedMesh
					name="Witch_ArmRight"
					castShadow
					receiveShadow
					geometry={gltf.nodes.Witch_ArmRight.geometry}
					material={gltf.materials.witch}
					skeleton={gltf.nodes.Witch_ArmRight.skeleton}
				/>
				<T.SkinnedMesh
					name="Witch_Body"
					castShadow
					receiveShadow
					geometry={gltf.nodes.Witch_Body.geometry}
					material={gltf.materials.witch}
					skeleton={gltf.nodes.Witch_Body.skeleton}
				/>
				<T.Group name="Witch_Glasses">
					<T.SkinnedMesh
						name="Witch_Glasses_1"
						castShadow
						receiveShadow
						geometry={gltf.nodes.Witch_Glasses_1.geometry}
						material={gltf.materials.witch}
						skeleton={gltf.nodes.Witch_Glasses_1.skeleton}
					/>
					<T.SkinnedMesh
						name="Witch_Glasses_2"
						castShadow
						receiveShadow
						geometry={gltf.nodes.Witch_Glasses_2.geometry}
						material={gltf.materials.glass}
						skeleton={gltf.nodes.Witch_Glasses_2.skeleton}
					/>
				</T.Group>
				<T.SkinnedMesh
					name="Witch_Hat"
					castShadow
					receiveShadow
					geometry={gltf.nodes.Witch_Hat.geometry}
					material={gltf.materials.witch}
					skeleton={gltf.nodes.Witch_Hat.skeleton}
				/>
				<T.SkinnedMesh
					name="Witch_Head"
					castShadow
					receiveShadow
					geometry={gltf.nodes.Witch_Head.geometry}
					material={gltf.materials.witch}
					skeleton={gltf.nodes.Witch_Head.skeleton}
				/>
				<T.SkinnedMesh
					name="Witch_LegLeft"
					castShadow
					receiveShadow
					geometry={gltf.nodes.Witch_LegLeft.geometry}
					material={gltf.materials.witch}
					skeleton={gltf.nodes.Witch_LegLeft.skeleton}
				/>
				<T.SkinnedMesh
					name="Witch_LegRight"
					castShadow
					receiveShadow
					geometry={gltf.nodes.Witch_LegRight.geometry}
					material={gltf.materials.witch}
					skeleton={gltf.nodes.Witch_LegRight.skeleton}
				/>
			</T.Group>
		</T.Group>
	{:catch err}
		{@render error?.({ error: err })}
	{/await}

	{@render children?.({ ref })}
</T>
