//======= Copyright (c) Valve Corporation, All rights reserved. ===============
//
// Purpose: Handles the spawning and returning of the ItemPackage
//
//=============================================================================
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using UnityEngine.Events;
#if UNITY_EDITOR
using UnityEditor;
#endif
namespace Valve.VR.InteractionSystem
{
//-------------------------------------------------------------------------
[RequireComponent( typeof( Interactable ) )]
public class ItemPackageSpawner : MonoBehaviour
{
public ItemPackage itemPackage
{
get
{
return _itemPackage;
}
set
{
CreatePreviewObject();
}
}
public ItemPackage _itemPackage;
private bool useItemPackagePreview = true;
private bool useFadedPreview = false;
private GameObject previewObject;
public bool requireGrabActionToTake = false;
public bool requireReleaseActionToReturn = false;
public bool showTriggerHint = false;
[EnumFlags]
public Hand.AttachmentFlags attachmentFlags = Hand.defaultAttachmentFlags;
public bool takeBackItem = false; // if a hand enters this trigger and has the item this spawner dispenses at the top of the stack, remove it from the stack
public bool acceptDifferentItems = false;
private GameObject spawnedItem;
private bool itemIsSpawned = false;
public UnityEvent pickupEvent;
public UnityEvent dropEvent;
public bool justPickedUpItem = false;
//-------------------------------------------------
private void CreatePreviewObject()
{
if ( !useItemPackagePreview )
{
return;
}
ClearPreview();
if ( useItemPackagePreview )
{
if ( itemPackage == null )
{
return;
}
if ( useFadedPreview == false ) // if we don't have a spawned item out there, use the regular preview
{
if ( itemPackage.previewPrefab != null )
{
previewObject = Instantiate( itemPackage.previewPrefab, transform.position, Quaternion.identity ) as GameObject;
previewObject.transform.parent = transform;
previewObject.transform.localRotation = Quaternion.identity;
}
}
else // there's a spawned item out there. Use the faded preview
{
if ( itemPackage.fadedPreviewPrefab != null )
{
previewObject = Instantiate( itemPackage.fadedPreviewPrefab, transform.position, Quaternion.identity ) as GameObject;
previewObject.transform.parent = transform;
previewObject.transform.localRotation = Quaternion.identity;
}
}
}
}
//-------------------------------------------------
void Start()
{
VerifyItemPackage();
}
//-------------------------------------------------
private void VerifyItemPackage()
{
if ( itemPackage == null )
{
ItemPackageNotValid();
}
if ( itemPackage.itemPrefab == null )
{
ItemPackageNotValid();
}
}
//-------------------------------------------------
private void ItemPackageNotValid()
{
Debug.LogError("[SteamVR Interaction] ItemPackage assigned to " + gameObject.name + " is not valid. Destroying this game object." );
Destroy( gameObject );
}
//-------------------------------------------------
private void ClearPreview()
{
foreach ( Transform child in transform )
{
if ( Time.time > 0 )
{
GameObject.Destroy( child.gameObject );
}
else
{
GameObject.DestroyImmediate( child.gameObject );
}
}
}
//-------------------------------------------------
void Update()
{
if ( ( itemIsSpawned == true ) && ( spawnedItem == null ) )
{
itemIsSpawned = false;
useFadedPreview = false;
dropEvent.Invoke();
CreatePreviewObject();
}
}
//-------------------------------------------------
private void OnHandHoverBegin( Hand hand )
{
ItemPackage currentAttachedItemPackage = GetAttachedItemPackage( hand );
if ( currentAttachedItemPackage == itemPackage ) // the item at the top of the hand's stack has an associated ItemPackage
{
if ( takeBackItem && !requireReleaseActionToReturn ) // if we want to take back matching items and aren't waiting for a trigger press
{
TakeBackItem( hand );
}
}
if (!requireGrabActionToTake) // we don't require trigger press for pickup. Spawn and attach object.
{
SpawnAndAttachObject( hand, GrabTypes.Scripted );
}
if (requireGrabActionToTake && showTriggerHint )
{
hand.ShowGrabHint("PickUp");
}
}
//-------------------------------------------------
private void TakeBackItem( Hand hand )
{
RemoveMatchingItemsFromHandStack( itemPackage, hand );
if ( itemPackage.packageType == ItemPackage.ItemPackageType.TwoHanded )
{
RemoveMatchingItemsFromHandStack( itemPackage, hand.otherHand );
}
}
//-------------------------------------------------
private ItemPackage GetAttachedItemPackage( Hand hand )
{
GameObject currentAttachedObject = hand.currentAttachedObject;
if ( currentAttachedObject == null ) // verify the hand is holding something
{
return null;
}
ItemPackageReference packageReference = hand.currentAttachedObject.GetComponent();
if ( packageReference == null ) // verify the item in the hand is matchable
{
return null;
}
ItemPackage attachedItemPackage = packageReference.itemPackage; // return the ItemPackage reference we find.
return attachedItemPackage;
}
//-------------------------------------------------
private void HandHoverUpdate( Hand hand )
{
if ( takeBackItem && requireReleaseActionToReturn )
{
if (hand.isActive)
{
ItemPackage currentAttachedItemPackage = GetAttachedItemPackage( hand );
if (currentAttachedItemPackage == itemPackage && hand.IsGrabEnding(currentAttachedItemPackage.gameObject))
{
TakeBackItem( hand );
return; // So that we don't pick up an ItemPackage the same frame that we return it
}
}
}
if ( requireGrabActionToTake )
{
GrabTypes startingGrab = hand.GetGrabStarting();
if (startingGrab != GrabTypes.None)
{
SpawnAndAttachObject( hand, GrabTypes.Scripted);
}
}
}
//-------------------------------------------------
private void OnHandHoverEnd( Hand hand )
{
if ( !justPickedUpItem && requireGrabActionToTake && showTriggerHint )
{
hand.HideGrabHint();
}
justPickedUpItem = false;
}
//-------------------------------------------------
private void RemoveMatchingItemsFromHandStack( ItemPackage package, Hand hand )
{
if (hand == null)
return;
for ( int i = 0; i < hand.AttachedObjects.Count; i++ )
{
ItemPackageReference packageReference = hand.AttachedObjects[i].attachedObject.GetComponent();
if ( packageReference != null )
{
ItemPackage attachedObjectItemPackage = packageReference.itemPackage;
if ( ( attachedObjectItemPackage != null ) && ( attachedObjectItemPackage == package ) )
{
GameObject detachedItem = hand.AttachedObjects[i].attachedObject;
hand.DetachObject( detachedItem );
}
}
}
}
//-------------------------------------------------
private void RemoveMatchingItemTypesFromHand( ItemPackage.ItemPackageType packageType, Hand hand )
{
for ( int i = 0; i < hand.AttachedObjects.Count; i++ )
{
ItemPackageReference packageReference = hand.AttachedObjects[i].attachedObject.GetComponent();
if ( packageReference != null )
{
if ( packageReference.itemPackage.packageType == packageType )
{
GameObject detachedItem = hand.AttachedObjects[i].attachedObject;
hand.DetachObject( detachedItem );
}
}
}
}
//-------------------------------------------------
private void SpawnAndAttachObject( Hand hand, GrabTypes grabType )
{
if ( hand.otherHand != null )
{
//If the other hand has this item package, take it back from the other hand
ItemPackage otherHandItemPackage = GetAttachedItemPackage( hand.otherHand );
if ( otherHandItemPackage == itemPackage )
{
TakeBackItem( hand.otherHand );
}
}
if ( showTriggerHint )
{
hand.HideGrabHint();
}
if ( itemPackage.otherHandItemPrefab != null )
{
if ( hand.otherHand.hoverLocked )
{
Debug.Log( "[SteamVR Interaction] Not attaching objects because other hand is hoverlocked and we can't deliver both items." );
return;
}
}
// if we're trying to spawn a one-handed item, remove one and two-handed items from this hand and two-handed items from both hands
if ( itemPackage.packageType == ItemPackage.ItemPackageType.OneHanded )
{
RemoveMatchingItemTypesFromHand( ItemPackage.ItemPackageType.OneHanded, hand );
RemoveMatchingItemTypesFromHand( ItemPackage.ItemPackageType.TwoHanded, hand );
RemoveMatchingItemTypesFromHand( ItemPackage.ItemPackageType.TwoHanded, hand.otherHand );
}
// if we're trying to spawn a two-handed item, remove one and two-handed items from both hands
if ( itemPackage.packageType == ItemPackage.ItemPackageType.TwoHanded )
{
RemoveMatchingItemTypesFromHand( ItemPackage.ItemPackageType.OneHanded, hand );
RemoveMatchingItemTypesFromHand( ItemPackage.ItemPackageType.OneHanded, hand.otherHand );
RemoveMatchingItemTypesFromHand( ItemPackage.ItemPackageType.TwoHanded, hand );
RemoveMatchingItemTypesFromHand( ItemPackage.ItemPackageType.TwoHanded, hand.otherHand );
}
spawnedItem = GameObject.Instantiate( itemPackage.itemPrefab );
spawnedItem.SetActive( true );
hand.AttachObject( spawnedItem, grabType, attachmentFlags );
if ( ( itemPackage.otherHandItemPrefab != null ) && ( hand.otherHand.isActive ) )
{
GameObject otherHandObjectToAttach = GameObject.Instantiate( itemPackage.otherHandItemPrefab );
otherHandObjectToAttach.SetActive( true );
hand.otherHand.AttachObject( otherHandObjectToAttach, grabType, attachmentFlags );
}
itemIsSpawned = true;
justPickedUpItem = true;
if ( takeBackItem )
{
useFadedPreview = true;
pickupEvent.Invoke();
CreatePreviewObject();
}
}
}
}