forked from cgvr/DeltaVR
166 lines
5.2 KiB
C#
166 lines
5.2 KiB
C#
using DG.Tweening;
|
|
using System;
|
|
using TMPro;
|
|
using UnityEngine;
|
|
using UnityEngine.XR.Interaction.Toolkit;
|
|
|
|
public class CafeWaiterNPC : NPCController
|
|
{
|
|
public FMODWhisperBridge fmodWhisperBridge;
|
|
public TextMeshProUGUI notepadText;
|
|
public GameObject notepad;
|
|
|
|
public Transform backRoom;
|
|
public Transform plate;
|
|
public float backRoomMovingTime = 5f;
|
|
|
|
public int ignorePlayerCollisionLayer = 2;
|
|
|
|
private Vector3 notepadOriginalRotation;
|
|
private Vector3 notepadFlippedRotation;
|
|
private Vector3 startingPosition;
|
|
|
|
// states:
|
|
// 0 - idle
|
|
// 1 - waiting for player order
|
|
// 2 - waiting for player to answer "is this correct?"
|
|
// 3 - bringing food
|
|
// 4 - waiting for player to go away
|
|
private int state;
|
|
private float lastPlayerVoiceUpdateTime;
|
|
|
|
private void Awake()
|
|
{
|
|
state = 0;
|
|
lastPlayerVoiceUpdateTime = Time.time;
|
|
startingPosition = transform.position;
|
|
}
|
|
|
|
private void Start()
|
|
{
|
|
notepadOriginalRotation = notepad.transform.localRotation.eulerAngles;
|
|
notepadFlippedRotation = notepadOriginalRotation + new Vector3(0, 180, 0);
|
|
notepad.SetActive(false);
|
|
}
|
|
|
|
protected override void OnPlayerApproach()
|
|
{
|
|
if (state == 0)
|
|
{
|
|
SpeakVoiceLine(0);
|
|
|
|
fmodWhisperBridge.OnWhisperSegmentUpdated += OnPlayerSpeechUpdate;
|
|
fmodWhisperBridge.OnWhisperSegmentFinished += OnPlayerSpeechFinished;
|
|
fmodWhisperBridge.ActivateRecording();
|
|
|
|
notepad.SetActive(true);
|
|
|
|
state = 1;
|
|
}
|
|
}
|
|
|
|
protected override void OnPlayerLeave()
|
|
{
|
|
fmodWhisperBridge.OnWhisperSegmentUpdated -= OnPlayerSpeechUpdate;
|
|
fmodWhisperBridge.OnWhisperSegmentFinished -= OnPlayerSpeechFinished;
|
|
fmodWhisperBridge.DeactivateRecording();
|
|
|
|
// If currently not bringing food and the player leaves, then go back to idle state
|
|
if (state != 3)
|
|
{
|
|
state = 0;
|
|
}
|
|
}
|
|
|
|
private void OnPlayerSpeechFinished(string playerText)
|
|
{
|
|
if (Time.time < lastPlayerVoiceUpdateTime + 0.5f)
|
|
{
|
|
Debug.Log("voiceline: player said '" + playerText + "' but not enough time passed");
|
|
return;
|
|
}
|
|
if (string.IsNullOrEmpty(playerText) || playerText.Contains("BLANK_AUDIO"))
|
|
{
|
|
Debug.Log("player speech event but result empty");
|
|
return;
|
|
}
|
|
lastPlayerVoiceUpdateTime = Time.time;
|
|
Debug.Log("state = " + state.ToString() + ", voiceline: player text: " + playerText);
|
|
|
|
if (state == 1)
|
|
{
|
|
// Show transcription and ask whether it is correct
|
|
notepadText.text = playerText;
|
|
notepad.transform.DOLocalRotate(notepadFlippedRotation, 0.5f);
|
|
SpeakVoiceLine(1);
|
|
state = 2;
|
|
} else if (state == 2)
|
|
{
|
|
// Flip notepad back
|
|
notepad.transform.DOLocalRotate(notepadOriginalRotation, 0.5f);
|
|
// if player answered positively, bring food, otherwise ask again
|
|
if (playerText.ToLower().Contains("yes"))
|
|
{
|
|
SpeakVoiceLine(2);
|
|
Invoke("BringFood", 1f);
|
|
state = 3;
|
|
} else
|
|
{
|
|
SpeakVoiceLine(3);
|
|
state = 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
private void OnPlayerSpeechUpdate(string playerText)
|
|
{
|
|
if (string.IsNullOrEmpty(playerText) || playerText.Contains("BLANK_AUDIO"))
|
|
{
|
|
return;
|
|
}
|
|
// Only update notepad text when currently listening to player order
|
|
if (state == 1)
|
|
{
|
|
notepadText.text = playerText;
|
|
}
|
|
}
|
|
|
|
private async void BringFood()
|
|
{
|
|
notepad.SetActive(false);
|
|
transform.DOMove(backRoom.position, backRoomMovingTime);
|
|
|
|
byte[] imageBytes = await InvokeAiClient.Instance.GenerateImage(notepadText.text);
|
|
Texture2D GeneratedTexture = ModelGenerationUtils.CreateTexture(imageBytes);
|
|
Sprite sprite = ModelGenerationUtils.CreateSprite(GeneratedTexture);
|
|
string encodedTexture = Convert.ToBase64String(GeneratedTexture.EncodeToJPG());
|
|
byte[] encodedModel = await TrellisClient.Instance.GenerateModel(encodedTexture);
|
|
GameObject spawnedObject = await ModelGenerationUtils.Instance.SpawnModel(encodedModel);
|
|
|
|
// Come back
|
|
transform.DOMove(startingPosition, backRoomMovingTime).OnComplete(() =>
|
|
{
|
|
spawnedObject.transform.position = plate.position + new Vector3(0, 1f, 0);
|
|
InitializeSpawnedObject(spawnedObject);
|
|
|
|
SpeakVoiceLine(4);
|
|
|
|
state = 4;
|
|
});
|
|
}
|
|
|
|
private void InitializeSpawnedObject(GameObject spawnedObject)
|
|
{
|
|
Rigidbody rigidbody = spawnedObject.AddComponent<Rigidbody>();
|
|
|
|
//spawnedObject.AddComponent<NetworkObject>();
|
|
//spawnedObject.AddComponent<NetworkTransform>();
|
|
|
|
MeshCollider spawnedObjectCollider = spawnedObject.GetComponent<MeshCollider>();
|
|
spawnedObjectCollider.convex = true;
|
|
spawnedObject.layer = ignorePlayerCollisionLayer;
|
|
|
|
spawnedObject.AddComponent<XRGrabInteractable>();
|
|
}
|
|
}
|