1
0
forked from cgvr/DeltaVR
Files
DeltaVR3DModelGeneration/Assets/_PROJECT/Scripts/ModeGeneration/NPCs/CafeWaiterNPC.cs

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