Initialer Upload neues Unity-Projekt

This commit is contained in:
Daniel Ocks
2025-07-03 11:02:29 +02:00
commit 27d6b94b7c
8167 changed files with 1116569 additions and 0 deletions

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: b390e5b7c8d51a44fa4f560d93e8067f
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,53 @@
using System;
using UnityEngine;
using UnityEngine.Events;
namespace Convai.Scripts.Narrative_Design.Models
{
/// <summary>
/// Data class for Section Change Events
/// </summary>
[Serializable]
public class SectionChangeEventsData
{
[SerializeField] public string id;
[SerializeField] public UnityEvent onSectionStart;
[SerializeField] public UnityEvent onSectionEnd;
private NarrativeDesignManager _manager;
private string SectionName
{
get
{
if (_manager == null) return string.Empty;
SectionData sectionData = _manager.sectionDataList.Find(s => s.sectionId == id);
return sectionData?.sectionName ?? "Unknown Section";
}
}
/// <summary>
/// Initialize the Section Change Events
/// </summary>
/// <param name="manager"> The Narrative Design Manager </param>
public void Initialize(NarrativeDesignManager manager)
{
_manager = manager;
onSectionStart.RemoveListener(LogSectionStart);
onSectionStart.AddListener(LogSectionStart);
onSectionEnd.RemoveListener(LogSectionEnd);
onSectionEnd.AddListener(LogSectionEnd);
}
private void LogSectionStart()
{
Debug.Log($"Section {SectionName} started");
}
private void LogSectionEnd()
{
Debug.Log($"Section {SectionName} ended");
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 32b4f9b2242945c19917f76c7ceb0a71
timeCreated: 1707390195

View File

@ -0,0 +1,37 @@
using System;
using Newtonsoft.Json;
using UnityEngine;
namespace Convai.Scripts.Narrative_Design.Models
{
/// <summary>
/// Data class for Section Data
/// </summary>
[Serializable]
public class SectionData
{
[JsonProperty("section_id")] [ReadOnly] [SerializeField]
public string sectionId;
[JsonProperty("section_name")] [ReadOnly] [SerializeField]
public string sectionName;
[JsonProperty("bt_constants")] [HideInInspector] [SerializeField]
public string behaviorTreeConstants;
[JsonProperty("objective")] [ReadOnly] [SerializeField]
public string objective;
[JsonProperty("character_id")] [ReadOnly] [HideInInspector] [SerializeField]
public string characterId;
[JsonProperty("decisions")] [ReadOnly] public object Decisions;
[JsonProperty("parents")] [ReadOnly] public object Parents;
[JsonProperty("triggers")] [ReadOnly] public object Triggers;
[JsonProperty("updated_character_data")] [ReadOnly]
public object UpdatedCharacterData;
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 98ee0e1dea8bb8c4ba9fe2daf30e9960
timeCreated: 1706764030

View File

@ -0,0 +1,25 @@
using System;
using Newtonsoft.Json;
using UnityEngine;
namespace Convai.Scripts.Narrative_Design.Models
{
[Serializable]
public class TriggerData
{
[JsonProperty("trigger_id")] [ReadOnly] [SerializeField]
public string triggerId;
[JsonProperty("trigger_name")] [ReadOnly] [SerializeField]
public string triggerName;
[JsonProperty("trigger_message")] [ReadOnly] [SerializeField]
public string triggerMessage;
[JsonProperty("destination_section")] [ReadOnly] [SerializeField]
public string destinationSection;
[JsonProperty("character_id")] [HideInInspector] [SerializeField]
public string characterId;
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: ed95a107485d00746a551222f53d0950
timeCreated: 1706764014

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: ecfb3b2eea944946a1d2336205b5eaad
timeCreated: 1706853590

View File

@ -0,0 +1,150 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;
using Convai.Scripts.Runtime.Utils;
using Newtonsoft.Json;
using UnityEngine;
/// <summary>
/// API client for the Narrative Design API.
/// </summary>
public class NarrativeDesignAPI
{
private const string BASE_URL = "https://api.convai.com/character/narrative/";
private readonly HttpClient _httpClient;
/// <summary>
/// Initializes a new instance of the <see cref="NarrativeDesignAPI" /> class.
/// </summary>
public NarrativeDesignAPI()
{
_httpClient = new HttpClient
{
// Set a default request timeout if needed
Timeout = TimeSpan.FromSeconds(30) // Example: 30 seconds
};
// Get the API key from the ConvaiAPIKeySetup object
if (ConvaiAPIKeySetup.GetAPIKey(out string apiKey))
{
// Set default request headers here
_httpClient.DefaultRequestHeaders.Add("CONVAI-API-KEY", apiKey);
// Set default headers like Accept to expect a JSON response
_httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
}
}
public async Task<string> CreateSectionAsync(string characterId, string objective, string sectionName, string behaviorTreeCode = null, string btConstants = null)
{
string endpoint = "create-section";
HttpContent content = CreateHttpContent(new Dictionary<string, object>
{
{ "character_id", characterId },
{ "objective", objective },
{ "section_name", sectionName },
{ "behavior_tree_code", behaviorTreeCode },
{ "bt_constants", btConstants }
});
return await SendPostRequestAsync(endpoint, content);
}
public async Task<string> GetSectionAsync(string characterId, string sectionId)
{
string endpoint = "get-section";
HttpContent content = CreateHttpContent(new Dictionary<string, object>
{
{ "character_id", characterId },
{ "section_id", sectionId }
});
return await SendPostRequestAsync(endpoint, content);
}
/// <summary>
/// Get a list of sections for a character.
/// </summary>
/// <param name="characterId"> The character ID. </param>
/// <returns> A JSON string containing the list of sections. </returns>
public async Task<string> ListSectionsAsync(string characterId)
{
string endpoint = "list-sections";
HttpContent content = CreateHttpContent(new Dictionary<string, object>
{
{ "character_id", characterId }
});
return await SendPostRequestAsync(endpoint, content);
}
public async Task<string> CreateTriggerAsync(string characterId, string triggerName, string triggerMessage = null, string destinationSection = null)
{
string endpoint = "create-trigger";
HttpContent content = CreateHttpContent(new Dictionary<string, object>
{
{ "character_id", characterId },
{ "trigger_message", triggerMessage },
{ "destination_section", destinationSection }
});
return await SendPostRequestAsync(endpoint, content);
}
public async Task<string> GetTriggerAsync(string characterId, string triggerId)
{
string endpoint = "get-trigger";
HttpContent content = CreateHttpContent(new Dictionary<string, object>
{
{ "character_id", characterId },
{ "trigger_id", triggerId }
});
return await SendPostRequestAsync(endpoint, content);
}
/// <summary>
/// Get a list of triggers for a character.
/// </summary>
/// <param name="characterId"> The character ID. </param>
/// <returns> A JSON string containing the list of triggers. </returns>
public async Task<string> GetTriggerListAsync(string characterId)
{
string endpoint = "list-triggers";
HttpContent content = CreateHttpContent(new Dictionary<string, object>
{
{ "character_id", characterId }
});
return await SendPostRequestAsync(endpoint, content);
}
private static HttpContent CreateHttpContent(Dictionary<string, object> data)
{
//Dictionary where all values are not null
Dictionary<string, object> dataToSend =
data.Where(keyValuePair => keyValuePair.Value != null).ToDictionary(keyValuePair => keyValuePair.Key, keyValuePair => keyValuePair.Value);
// Serialize the dictionary to JSON
string json = JsonConvert.SerializeObject(dataToSend);
// Convert JSON to HttpContent
return new StringContent(json, Encoding.UTF8, "application/json");
}
private async Task<string> SendPostRequestAsync(string endpoint, HttpContent content)
{
try
{
HttpResponseMessage response = await _httpClient.PostAsync(BASE_URL + endpoint, content);
response.EnsureSuccessStatusCode();
return await response.Content.ReadAsStringAsync();
}
catch (HttpRequestException e)
{
Debug.LogError($"Request to {endpoint} failed: {e.Message}");
return null;
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 13850aaec3d742c2867a15ab2273a1e0
timeCreated: 1706546525

View File

@ -0,0 +1,140 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Convai.Scripts;
using Convai.Scripts.Narrative_Design.Models;
using Newtonsoft.Json;
using UnityEngine;
using Logger = Convai.Scripts.Utils.Logger;
/// <summary>
/// Manages the narrative design for a ConvaiNPC.
/// </summary>
[RequireComponent(typeof(ConvaiNPC))]
public class NarrativeDesignManager : MonoBehaviour
{
public List<SectionChangeEventsData> sectionChangeEventsDataList = new();
public List<SectionData> sectionDataList = new();
public List<TriggerData> triggerDataList = new();
private ConvaiNPC _convaiNpc;
private string _currentSectionID;
private NarrativeDesignAPI _narrativeDesignAPI;
private NarrativeDesignAPI NarrativeDesignAPI => _narrativeDesignAPI ??= new NarrativeDesignAPI();
private ConvaiNPC ConvaiNpc => _convaiNpc ??= GetComponent<ConvaiNPC>();
private string CharacterID => ConvaiNpc.characterID;
private async void Awake()
{
_convaiNpc = GetComponent<ConvaiNPC>();
await Task.WhenAll(UpdateSectionListAsync(), UpdateTriggerListAsync());
}
private async void Reset() => await Task.WhenAll(UpdateSectionListAsync(), UpdateTriggerListAsync());
/// <summary>
/// Updates the section list from the server.
/// </summary>
public async Task UpdateSectionListAsync()
{
List<SectionData> updatedSectionList = await GetSectionListFromServerAsync();
UpdateSectionDataList(updatedSectionList);
}
/// <summary>
/// Updates the trigger list from the server.
/// </summary>
public async Task UpdateTriggerListAsync() => await ListTriggersAsync(CharacterID);
/// <summary>
/// Invoked when the section event list changes.
/// </summary>
public void OnSectionEventListChange()
{
foreach (SectionChangeEventsData sectionChangeEventsData in sectionChangeEventsDataList) sectionChangeEventsData.Initialize(this);
}
private async Task<List<SectionData>> GetSectionListFromServerAsync()
{
try
{
string sections = await NarrativeDesignAPI.ListSectionsAsync(CharacterID);
return JsonConvert.DeserializeObject<List<SectionData>>(sections);
}
catch (Exception e)
{
Logger.Error($"Please setup API Key properly. FormatException occurred: {e.Message}", Logger.LogCategory.Character);
throw;
}
}
private async Task ListTriggersAsync(string characterId)
{
try
{
string triggers = await NarrativeDesignAPI.GetTriggerListAsync(characterId);
triggerDataList = JsonConvert.DeserializeObject<List<TriggerData>>(triggers);
}
catch (FormatException e)
{
Debug.LogError($"Format Exception occurred: {e.Message}");
throw;
}
}
/// <summary>
/// Updates the current section.
/// </summary>
/// <param name="sectionID"> The section ID to update to. </param>
public void UpdateCurrentSection(string sectionID)
{
if (string.IsNullOrEmpty(_currentSectionID))
{
_currentSectionID = sectionID;
InvokeSectionEvent(_currentSectionID, true);
return;
}
if (_currentSectionID.Equals(sectionID))
return;
InvokeSectionEvent(_currentSectionID, false);
_currentSectionID = sectionID;
InvokeSectionEvent(_currentSectionID, true);
}
private void InvokeSectionEvent(string id, bool isStarting)
{
SectionChangeEventsData sectionChangeEventsData = sectionChangeEventsDataList.Find(x => x.id == id);
if (sectionChangeEventsData == null)
{
Logger.Info($"No Section Change Events have been created for sectionID: {id}", Logger.LogCategory.Actions);
return;
}
if (isStarting)
sectionChangeEventsData.onSectionStart?.Invoke();
else
sectionChangeEventsData.onSectionEnd?.Invoke();
}
private void UpdateSectionDataList(List<SectionData> updatedSectionList)
{
Dictionary<string, SectionData> updatedSectionDictionary = updatedSectionList.ToDictionary(s => s.sectionId);
foreach (SectionData currentSection in sectionDataList)
if (updatedSectionDictionary.TryGetValue(currentSection.sectionId, out SectionData updatedSection))
{
currentSection.sectionName = updatedSection.sectionName;
currentSection.objective = updatedSection.objective;
updatedSectionDictionary.Remove(currentSection.sectionId);
}
foreach (SectionData newSection in updatedSectionDictionary.Values) sectionDataList.Add(newSection);
foreach (SectionChangeEventsData sectionChangeEvent in sectionChangeEventsDataList) sectionChangeEvent.Initialize(this);
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 3d56bc33052944e0aba5a0fe7073c3ab
timeCreated: 1706546743

View File

@ -0,0 +1,51 @@
using System.Collections.Generic;
using System.Linq;
using Convai.Scripts.Utils;
using UnityEngine;
using UnityEngine.Events;
namespace Convai.Scripts.Narrative_Design
{
public class NarrativeDesignTrigger : MonoBehaviour
{
public ConvaiNPC convaiNPC;
[HideInInspector] public int selectedTriggerIndex;
[HideInInspector] public List<string> availableTriggers;
public UnityEvent onTriggerEvent;
private void Awake()
{
onTriggerEvent.AddListener(InvokeSelectedTrigger);
}
private void OnTriggerEnter(Collider other)
{
if (other.CompareTag("Player")) InvokeSelectedTrigger();
}
private void OnValidate()
{
availableTriggers = null;
if (convaiNPC != null)
{
NarrativeDesignManager narrativeDesignManager = convaiNPC.GetComponent<NarrativeDesignManager>();
if (narrativeDesignManager != null) availableTriggers = narrativeDesignManager.triggerDataList.Select(trigger => trigger.triggerName).ToList();
}
}
/// <summary>
/// Invokes the selected trigger.
/// </summary>
public void InvokeSelectedTrigger()
{
if (convaiNPC != null && availableTriggers != null && selectedTriggerIndex >= 0 && selectedTriggerIndex < availableTriggers.Count)
{
string selectedTriggerName = availableTriggers[selectedTriggerIndex];
ConvaiNPCManager.Instance.SetActiveConvaiNPC(convaiNPC);
convaiNPC.TriggerEvent(selectedTriggerName);
}
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 1c783ed73e64a204ebf38b93c054b566
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: