<!--
Auto-generated by: https://github.com/threlte/threlte/tree/main/packages/gltf
Command: npx @threlte/gltf@3.0.0-next.9 Barbarian-transformed.glb -t
-->

<script lang="ts">
  import * 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'

  let {
    fallback,
    error,
    children,
    ref = $bindable(),
    currentAction = "Idle",
    transitionDuration = 1.0,
    leftHand = "none",
    rightHand = "none",
    flatShading = false,
    ...props
  }: Props<THREE.Group> & {
    ref?: THREE.Group
    children?: Snippet<[{ ref: THREE.Group }]>
    fallback?: Snippet
    error?: Snippet<[{ error: Error }]>
    currentAction?: ActionName | undefined
    transitionDuration?: number
    leftHand?: LeftHandProps
    rightHand?: RightHandProps
    flatShading?: boolean
  } = $props()

  ref = new Group()

  type ActionName =
    | '1H_Melee_Attack_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'
    | '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'
    | '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_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'
    | 'Spellcast_Long'
    | 'Spellcast_Raise'
    | 'Spellcast_Shoot'
    | 'Spellcasting'
    | 'T-Pose'
    | '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'
  type GLTFResult = {
    nodes: {
      ['1H_Axe_Offhand']: THREE.Mesh
      Barbarian_Round_Shield: THREE.Mesh
      ['1H_Axe']: THREE.Mesh
      ['2H_Axe']: THREE.Mesh
      Mug: THREE.Mesh
      Barbarian_Hat: THREE.Mesh
      Barbarian_Cape: THREE.Mesh
      Barbarian_ArmLeft: THREE.SkinnedMesh
      Barbarian_ArmRight: THREE.SkinnedMesh
      Barbarian_Body: THREE.SkinnedMesh
      Barbarian_Head: THREE.SkinnedMesh
      Barbarian_LegLeft: THREE.SkinnedMesh
      Barbarian_LegRight: THREE.SkinnedMesh
      root: THREE.Bone
    }
    materials: {
      barbarian_texture: THREE.MeshStandardMaterial
    }
  }

  const gltf = useGltf<GLTFResult>('/Barbarian.glb')

  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];
			if (action) 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();
	};

	type LeftHandProps = 'Shield' | 'Weapon' | 'none';

	type RightHandProps = 'Mug' | 'Weapon' | 'WeaponBig' | 'none';

  $effect(() => {
	if (leftHand && $gltf?.nodes) {
		let hand = ref.getObjectByName('handslotl');
		if (hand) {
			hand.children.forEach((child) => {
				child.visible = false;

				if (child instanceof THREE.Mesh) {
					child.material.flatShading = flatShading;
					child.material.roughness = 1.0;

					child.castShadow = true;
					child.receiveShadow = true;
				}

				if (leftHand === 'Shield' && child.name === 'Barbarian_Round_Shield') {
					child.visible = true;
				} else if (leftHand === 'Weapon' && child.name === '1H_Axe_Offhand') {
					child.visible = true;
				}
			});
		}
	}

	if (rightHand && $gltf?.nodes) {
		let hand = ref.getObjectByName('handslotr');
		if (hand) {
			hand.children.forEach((child) => {
				child.visible = false;

				if (child instanceof THREE.Mesh) {
					child.material.flatShading = flatShading;
					child.material.roughness = 1.0;

					child.castShadow = true;
					child.receiveShadow = true;
				}

				if (rightHand === 'Mug' && child.name === 'Mug') {
					child.visible = true;
				} else if (rightHand === 'Weapon' && child.name === '1H_Axe') {
					child.visible = true;
				} else if (rightHand === 'WeaponBig' && child.name === '2H_Axe') {
					child.visible = true;
				}
			});
		}
	}

	if ($gltf?.nodes) {
		// find Barbarian_Cape
		let cape = ref.getObjectByName('Barbarian_Cape');
		if (cape) cape.visible = false;
	}
});
</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="Barbarian_ArmLeft"
          geometry={gltf.nodes.Barbarian_ArmLeft.geometry}
          material={gltf.materials.barbarian_texture}
          skeleton={gltf.nodes.Barbarian_ArmLeft.skeleton}
        />
        <T.SkinnedMesh
          name="Barbarian_ArmRight"
          geometry={gltf.nodes.Barbarian_ArmRight.geometry}
          material={gltf.materials.barbarian_texture}
          skeleton={gltf.nodes.Barbarian_ArmRight.skeleton}
        />
        <T.SkinnedMesh
          name="Barbarian_Body"
          geometry={gltf.nodes.Barbarian_Body.geometry}
          material={gltf.materials.barbarian_texture}
          skeleton={gltf.nodes.Barbarian_Body.skeleton}
        />
        <T.SkinnedMesh
          name="Barbarian_Head"
          geometry={gltf.nodes.Barbarian_Head.geometry}
          material={gltf.materials.barbarian_texture}
          skeleton={gltf.nodes.Barbarian_Head.skeleton}
        />
        <T.SkinnedMesh
          name="Barbarian_LegLeft"
          geometry={gltf.nodes.Barbarian_LegLeft.geometry}
          material={gltf.materials.barbarian_texture}
          skeleton={gltf.nodes.Barbarian_LegLeft.skeleton}
        />
        <T.SkinnedMesh
          name="Barbarian_LegRight"
          geometry={gltf.nodes.Barbarian_LegRight.geometry}
          material={gltf.materials.barbarian_texture}
          skeleton={gltf.nodes.Barbarian_LegRight.skeleton}
        />
      </T.Group>
    </T.Group>
  {:catch err}
    {@render error?.({ error: err })}
  {/await}

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