Add Tutorial

This commit is contained in:
Nadine Ganz 2025-07-15 14:44:28 +02:00
parent fbff36f195
commit a3263aae60
11 changed files with 2288 additions and 418863 deletions

View File

@ -0,0 +1,342 @@
Tree("Root") {
Composite(Sequence) {
BTC.InitializeSpeechManager()
Composite(Race) {
Composite(Sequence) {
// Error in Speech Service: Cancel BTC Trees
BTC.SpeechErrorOccured()
BTC.SetBool("error")
}
Composite(Sequence) {
BTC.SetVoiceName("de-DE-SeraphinaMultilingualNeural")
BTC.FadeIn("FadeScene.XRInteractionHandsSetup.Black")
RunTree("05_Tutorial")
}
}
Composite(Sequence) {
BTC.CompareBool("error")
// Error Handling
BTC.AbortSpeechEventListener()
BTC.StopSpeechIntentRecognition()
BTC.ClearPossbileSpeechIntents()
BTC.Show("GO.HANDMENU.SpeechButton")
BTC.Set("TextMeshPro.HANDMENU.Option1Button", "text", "Restart")
BTC.Show("GO.HANDMENU.Option1Button")
BTC.Run("NamedEventTrigger.HANDMENU.Option1Button")
BTC.Hide("GO.HANDMENU.Option1Button")
BTC.Hide("GO.HANDMENU.SpeechButton")
BTC.Hide("GO.HANDMENU.SpeechOptions")
}
}
}
Tree("05_Tutorial") {
// --- Zugabteil - Tutorial ---
Composite(Sequence) {
BTC.SynthesizeText("Willkommen auf unserer Reise in die italienischsprachige Schweiz! Bevor wir loslegen, lass uns ein paar Dinge ausprobieren.")
BTC.SpeechOutputEnded()
BTC.SynthesizeText("Falls dir zu irgendeinem Zeitpunkt unwohl wird, schliesse die Augen und setze die VR-Brille ab.")
BTC.SpeechOutputEnded()
BTC.SynthesizeText("Vergewissere dich, dass Du sicher und bequem sitzt. Es wird Teile in der App geben, wo Du auch stehst. Für den Anfang kannst Du sitzen.")
BTC.SpeechOutputEnded()
BTC.SynthesizeText("Schau dich um. Beweg deinen Kopf, um die Umgebung zu entdecken.")
BTC.SpeechOutputEnded()
BTC.DetectRotationAtLeast("GO.XRInteractionHandsSetup.MainCamera", 30.0)
BTC.Wait(3)
BTC.SynthesizeText("Super! Lehne dich nun nach vorne, dann wieder zurück, lehne dich dann auf eine und dann auf die andere Seite. Dann wieder zurück.")
BTC.SpeechOutputEnded()
BTC.DetectPositionAtLeast("GO.XRInteractionHandsSetup.MainCamera", 0.2)
BTC.SynthesizeText("Gut so!")
BTC.SpeechOutputEnded()
BTC.Wait(2)
BTC.SynthesizeText("Du steuerst alles per Sprache.")
BTC.SpeechOutputEnded()
BTC.SynthesizeText("Gut, jetzt testen wir aber mal dein Mikrofon. Wie heisst du eigentlich?")
BTC.SpeechOutputEnded()
BTC.AddPossbileSpeechIntent("Zugabteil-Tutorial-U-8")
BTC.StartSpeechIntentRecognition()
Composite(Race) {
// -- Race 1: User sagt etwas
Composite(Sequence) {
BTC.UserStartedSpeechInput()
Composite(Selector) {
// -- Selector 1: Intent erkannt
Composite(Sequence) {
BTC.SpeechIntentRecognized()
BTC.ClearPossbileSpeechIntents()
}
// -- Selector 2: Intent nicht erkannt
Composite(Sequence) {
BTC.ClearPossbileSpeechIntents()
}
}
BTC.SynthesizeText("Schön dich kennenzulernen!")
BTC.SpeechOutputEnded()
}
// -- Race 2: User sagt nichts
Composite(Sequence) {
BTC.Wait(10)
BTC.CompareUserSpeechInputStarted(false)
BTC.AbortSpeechEventListener()
BTC.StopSpeechIntentRecognition()
BTC.SynthesizeText("Ich habe dich nicht verstanden. Sprich bitte deutlicher.")
BTC.SpeechOutputEnded()
BTC.StartSpeechIntentRecognition()
Composite(Race) {
// -- Race 1: User sagt etwas
Composite(Sequence) {
BTC.UserStartedSpeechInput()
Composite(Selector) {
// -- Selector 1: Intent erkannt
Composite(Sequence) {
BTC.SpeechIntentRecognized()
BTC.ClearPossbileSpeechIntents()
}
// -- Selector 2: Intent nicht erkannt
Composite(Sequence) {
BTC.ClearPossbileSpeechIntents()
}
}
BTC.SynthesizeText("Schön dich kennenzulernen!")
BTC.SpeechOutputEnded()
}
// -- Race 2: User sagt nichts
Composite(Sequence) {
BTC.Wait(10)
BTC.CompareUserSpeechInputStarted(false)
BTC.AbortSpeechEventListener()
BTC.StopSpeechIntentRecognition()
BTC.ClearPossbileSpeechIntents()
BTC.SynthesizeText("Schön dich kennenzulernen!")
BTC.SpeechOutputEnded()
}
}
}
}
BTC.SynthesizeText("Ab jetzt werden wir dir Fragen nur noch auf Italienisch stellen und Du musst auch auf Italienisch antworten. Aber keine Sorge, Du wirst nicht bewertet. Du darfst einfach ausprobieren ohne Angst vor Fehlern.")
BTC.SpeechOutputEnded()
BTC.SynthesizeText("Zusätzlich hast Du in deiner Hand ein Smartphone. Siehst Du es? Es kann dir bei Antworten helfen, wenn Du nicht weiter weisst. Und Du kannst damit auch die Übungen wechseln (und das Programm beenden).")
BTC.SpeechOutputEnded()
BTC.SynthesizeText("Also jetzt geht es los. Bereit?")
BTC.SpeechOutputEnded()
BTC.SetSpeechRecognitionLanguage("it-IT")
BTC.SetVoiceName("it-IT-FabiolaNeural")
BTC.SynthesizeText("Cosa ti piace di più? Spaghetti, pizza o risotto?")
BTC.SpeechOutputEnded()
BTC.AddPossbileSpeechIntent("Zugabteil-Tutorial-U-15")
BTC.AddPossbileSpeechIntent("Zugabteil-Tutorial-U-16")
BTC.AddPossbileSpeechIntent("Zugabteil-Tutorial-U-17")
BTC.StartSpeechIntentRecognition()
Composite(Race) {
// -- Race 1: User sagt etwas
Composite(Sequence) {
BTC.UserStartedSpeechInput()
Composite(Selector) {
// -- Selector 1: Intent erkannt
Composite(Sequence) {
BTC.SpeechIntentRecognized()
// Intent erkannt
Composite(Race) {
Composite(Sequence) {
BTC.CompareIntentID("Zugabteil-Tutorial-U-15")
BTC.ClearPossbileSpeechIntents()
BTC.SynthesizeText("Ah, Spaghetti mag ich auch!")
BTC.SpeechOutputEnded()
}
Composite(Sequence) {
BTC.CompareIntentID("Zugabteil-Tutorial-U-16")
BTC.ClearPossbileSpeechIntents()
BTC.SynthesizeText("Ah, Pizza mag ich auch!")
BTC.SpeechOutputEnded()
}
Composite(Sequence) {
BTC.CompareIntentID("Zugabteil-Tutorial-U-17")
BTC.ClearPossbileSpeechIntents()
BTC.SynthesizeText("Ah, Risotto mag ich auch!")
BTC.SpeechOutputEnded()
}
}
}
// Selector 2: Fallback Button
Composite(Sequence) {
Composite(Marathon) {
BTC.Show("GO.HANDMENU.SpeechButton")
BTC.Set("TextMeshPro.HANDMENU.Option1Button", "text", "Spaghetti")
BTC.Show("GO.HANDMENU.Option1Button")
BTC.Set("TextMeshPro.HANDMENU.Option2Button", "text", "Pizza")
BTC.Show("GO.HANDMENU.Option2Button")
BTC.Set("TextMeshPro.HANDMENU.Option3Button", "text", "Risotto")
BTC.Show("GO.HANDMENU.Option3Button")
}
Composite(Race) {
Composite(Sequence) {
// Spaghetti
BTC.Run("NamedEventTrigger.HANDMENU.Option1Button")
BTC.AbortEventListener("NamedEventTrigger.HANDMENU.Option2Button")
BTC.AbortEventListener("NamedEventTrigger.HANDMENU.Option3Button")
BTC.Hide("GO.HANDMENU.Option1Button")
BTC.Hide("GO.HANDMENU.Option2Button")
BTC.Hide("GO.HANDMENU.Option3Button")
BTC.Hide("GO.HANDMENU.SpeechButton")
BTC.Hide("GO.HANDMENU.SpeechOptions")
BTC.SynthesizeText("Ah, Spaghetti mag ich auch!")
BTC.SpeechOutputEnded()
}
Composite(Sequence) {
// Pizza
BTC.Run("NamedEventTrigger.HANDMENU.Option2Button")
BTC.AbortEventListener("NamedEventTrigger.HANDMENU.Option1Button")
BTC.AbortEventListener("NamedEventTrigger.HANDMENU.Option3Button")
BTC.Hide("GO.HANDMENU.Option1Button")
BTC.Hide("GO.HANDMENU.Option2Button")
BTC.Hide("GO.HANDMENU.Option3Button")
BTC.Hide("GO.HANDMENU.SpeechButton")
BTC.Hide("GO.HANDMENU.SpeechOptions")
BTC.SynthesizeText("Ah, Pizza mag ich auch!")
BTC.SpeechOutputEnded()
}
Composite(Sequence) {
// Risotto
BTC.Run("NamedEventTrigger.HANDMENU.Option3Button")
BTC.AbortEventListener("NamedEventTrigger.HANDMENU.Option1Button")
BTC.AbortEventListener("NamedEventTrigger.HANDMENU.Option2Button")
BTC.Hide("GO.HANDMENU.Option1Button")
BTC.Hide("GO.HANDMENU.Option2Button")
BTC.Hide("GO.HANDMENU.Option3Button")
BTC.Hide("GO.HANDMENU.SpeechButton")
BTC.Hide("GO.HANDMENU.SpeechOptions")
BTC.SynthesizeText("Ah, Risotto mag ich auch!")
BTC.SpeechOutputEnded()
}
}
BTC.ClearPossbileSpeechIntents()
}
}
}
// -- Race 2: User sagt nichts
Composite(Sequence) {
BTC.Wait(10)
BTC.CompareUserSpeechInputStarted(false)
BTC.AbortSpeechEventListener()
BTC.StopSpeechIntentRecognition()
BTC.ClearPossbileSpeechIntents()
Composite(Sequence) {
Composite(Marathon) {
BTC.Show("GO.HANDMENU.SpeechButton")
BTC.Set("TextMeshPro.HANDMENU.Option1Button", "text", "Spaghetti")
BTC.Show("GO.HANDMENU.Option1Button")
BTC.Set("TextMeshPro.HANDMENU.Option2Button", "text", "Pizza")
BTC.Show("GO.HANDMENU.Option2Button")
BTC.Set("TextMeshPro.HANDMENU.Option3Button", "text", "Risotto")
BTC.Show("GO.HANDMENU.Option3Button")
}
Composite(Race) {
Composite(Sequence) {
// Spaghetti
BTC.Run("NamedEventTrigger.HANDMENU.Option1Button")
BTC.AbortEventListener("NamedEventTrigger.HANDMENU.Option2Button")
BTC.AbortEventListener("NamedEventTrigger.HANDMENU.Option3Button")
BTC.Hide("GO.HANDMENU.Option1Button")
BTC.Hide("GO.HANDMENU.Option2Button")
BTC.Hide("GO.HANDMENU.Option3Button")
BTC.Hide("GO.HANDMENU.SpeechButton")
BTC.Hide("GO.HANDMENU.SpeechOptions")
BTC.SynthesizeText("Ah, Spaghetti mag ich auch!")
BTC.SpeechOutputEnded()
}
Composite(Sequence) {
// Pizza
BTC.Run("NamedEventTrigger.HANDMENU.Option2Button")
BTC.AbortEventListener("NamedEventTrigger.HANDMENU.Option1Button")
BTC.AbortEventListener("NamedEventTrigger.HANDMENU.Option3Button")
BTC.Hide("GO.HANDMENU.Option1Button")
BTC.Hide("GO.HANDMENU.Option2Button")
BTC.Hide("GO.HANDMENU.Option3Button")
BTC.Hide("GO.HANDMENU.SpeechButton")
BTC.Hide("GO.HANDMENU.SpeechOptions")
BTC.SynthesizeText("Ah, Pizza mag ich auch!")
BTC.SpeechOutputEnded()
}
Composite(Sequence) {
// Risotto
BTC.Run("NamedEventTrigger.HANDMENU.Option3Button")
BTC.AbortEventListener("NamedEventTrigger.HANDMENU.Option1Button")
BTC.AbortEventListener("NamedEventTrigger.HANDMENU.Option2Button")
BTC.Hide("GO.HANDMENU.Option1Button")
BTC.Hide("GO.HANDMENU.Option2Button")
BTC.Hide("GO.HANDMENU.Option3Button")
BTC.Hide("GO.HANDMENU.SpeechButton")
BTC.Hide("GO.HANDMENU.SpeechOptions")
BTC.SynthesizeText("Ah, Risotto mag ich auch!")
BTC.SpeechOutputEnded()
}
}
BTC.ClearPossbileSpeechIntents()
}
}
}
BTC.SynthesizeText("Okay. Versuche, deinen Rucksack vom Tisch hochzuheben. Strecke dazu deine Hand aus und greife nach dem Rucksack, wie Du es auch sonst tun würdest.")
BTC.SpeechOutputEnded()
// Rucksack greifen
BTC.Run("NamedGrabEvent.INTERACTABLES.Rucksack")
BTC.SynthesizeText("Stelle den Rucksack nun auf die markierte Stelle auf den Sitz rechts von Dir.")
BTC.SpeechOutputEnded()
// Rucksack ins Socket
BTC.Show("GO/NamedSocketEvent.SOCKETS.RucksackUser")
BTC.Run("GO/NamedSocketEvent.SOCKETS.RucksackUser")
BTC.Wait(1)
BTC.Hide("GO/NamedSocketEvent.SOCKETS.RucksackUser")
BTC.SynthesizeText("Perfekt! Du hast gelernt dich zu bewegen, zu sprechen und mit Objekten zu interagieren. Dann geht es jetzt los!")
BTC.SpeechOutputEnded()
BTC.SynthesizeText("Francesca ist deine Begleiterin. Sie kommt gleich. Gute Reise!")
BTC.SpeechOutputEnded()
BTC.FadeOut("FadeScene.XRInteractionHandsSetup.Black")
BTC.Run("LoadScene.NEXT.10SBB")
}
}

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 7e7dfa1df75fc4996ad15d2810cc1d31
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -303,6 +303,30 @@ public class BTC : MonoBehaviour {
} }
} }
[Task]
public void DetectRotationAtLeast(string objectName, float minRotation)
{
List<ComponentHandler> handlers = GetHandlers(objectName);
handlers.ForEach(handler => handler.DetectRotationAtLeast(Task.getState, minRotation));
if (handlers.Count == 0)
{
Debug.LogWarning($"BTC.DetectRotationAtLeast: no components under the name '{objectName}'");
Task.SetSucceeded();
}
}
[Task]
public void DetectPositionAtLeast(string objectName, float minDistance)
{
List<ComponentHandler> handlers = GetHandlers(objectName);
handlers.ForEach(handler => handler.DetectPositionAtLeast(Task.getState, minDistance));
if (handlers.Count == 0)
{
Debug.LogWarning($"BTC.DetectPositionAtLeast: no components under the name '{objectName}'");
Task.SetSucceeded();
}
}
[Task] [Task]
public void AbortEventListener(string objectName) public void AbortEventListener(string objectName)
{ {

View File

@ -221,6 +221,22 @@ public class ComponentHandler : MonoBehaviour {
} }
} }
public virtual void DetectRotationAtLeast(MyBT.NodeState nodeState, float minRotation)
{
if (Task.isDebugging)
{
Debug.LogWarning($"ComponentHandler.DetectRotationAtLeast: not implemented for {this.GetType()}");
}
}
public virtual void DetectPositionAtLeast(MyBT.NodeState nodeState, float minDistance)
{
if (Task.isDebugging)
{
Debug.LogWarning($"ComponentHandler.DetectPositionAtLeast not implemented for {this.GetType()}");
}
}
public virtual void AbortEventListener(MyBT.NodeState nodeState) public virtual void AbortEventListener(MyBT.NodeState nodeState)
{ {
if (Task.isDebugging) if (Task.isDebugging)

View File

@ -101,6 +101,40 @@ public class NamedGameObject : ComponentHandler {
} }
} }
public override void DetectRotationAtLeast(NodeState nodeState, float minRotation)
{
if (nodeState == NodeState.FirstRun)
{
_startQuaternion = gameObject.transform.rotation;
}
else if (nodeState == NodeState.Running)
{
float angleOffset = Quaternion.Angle(_startQuaternion, gameObject.transform.rotation);
if (angleOffset > minRotation)
{
Task.SetSucceeded();
}
}
}
public override void DetectPositionAtLeast(NodeState nodeState, float minDistance)
{
if (nodeState == NodeState.FirstRun)
{
_initialPosition = gameObject.transform.position;
}
else if (nodeState == NodeState.Running)
{
float movedDistance = Vector3.Distance(_initialPosition, gameObject.transform.position);
if (movedDistance > minDistance)
{
Task.SetSucceeded();
}
}
}
public GameObject go; public GameObject go;
public string objName = "GoXY"; public string objName = "GoXY";
Quaternion _startQuaternion;
Vector3 _initialPosition;
} }

View File

@ -422,10 +422,18 @@ PrefabInstance:
propertyPath: m_RotationAction.m_Reference propertyPath: m_RotationAction.m_Reference
value: value:
objectReference: {fileID: 7384354444432909072, guid: c348712bda248c246b8c49b3db54643f, type: 3} objectReference: {fileID: 7384354444432909072, guid: c348712bda248c246b8c49b3db54643f, type: 3}
- target: {fileID: 8574486981646720036, guid: d6878e1999eb4b44a9f5a263af86c185, type: 3}
propertyPath: m_InteractionLayers.m_Bits
value: 4294967295
objectReference: {fileID: 0}
- target: {fileID: 8775677614826887028, guid: d6878e1999eb4b44a9f5a263af86c185, type: 3} - target: {fileID: 8775677614826887028, guid: d6878e1999eb4b44a9f5a263af86c185, type: 3}
propertyPath: m_IsActive propertyPath: m_IsActive
value: 0 value: 0
objectReference: {fileID: 0} objectReference: {fileID: 0}
- target: {fileID: 9034274667510444962, guid: d6878e1999eb4b44a9f5a263af86c185, type: 3}
propertyPath: m_InteractionLayers.m_Bits
value: 4294967295
objectReference: {fileID: 0}
m_RemovedComponents: [] m_RemovedComponents: []
m_RemovedGameObjects: m_RemovedGameObjects:
- {fileID: 927309121262695183, guid: d6878e1999eb4b44a9f5a263af86c185, type: 3} - {fileID: 927309121262695183, guid: d6878e1999eb4b44a9f5a263af86c185, type: 3}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,292 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
using UnityEngine.Networking;
public class InternetVolumeLogger : MonoBehaviour
{
[Header("Logging Settings")]
public float logInterval = 5f; // Intervall in Sekunden
public string logFileName = "internet_volume_log.txt";
public bool enableLogging = true;
[Header("Display Settings")]
public bool showInConsole = true;
private long lastBytesReceived = 0;
private long lastBytesSent = 0;
private long totalBytesReceived = 0;
private long totalBytesSent = 0;
private float sessionStartTime;
private string logFilePath;
private void Start()
{
sessionStartTime = Time.time;
// Android-spezifischer Pfad für externe Speicherung
if (Application.platform == RuntimePlatform.Android)
{
logFilePath = Path.Combine(Application.persistentDataPath, logFileName);
}
else
{
logFilePath = Path.Combine(Application.persistentDataPath, logFileName);
}
Debug.Log($"Log-Datei wird gespeichert unter: {logFilePath}");
// Initialisiere die Baseline-Werte
InitializeBaseline();
// Starte das Logging
if (enableLogging)
{
StartCoroutine(LogInternetVolume());
}
// Schreibe Header in die Log-Datei
WriteLogHeader();
}
private void InitializeBaseline()
{
// Setze die Startwerte für die Messung
lastBytesReceived = GetTotalBytesReceived();
lastBytesSent = GetTotalBytesSent();
totalBytesReceived = 0;
totalBytesSent = 0;
}
private long GetTotalBytesReceived()
{
// Android-optimierte Netzwerk-Statistiken
if (Application.platform == RuntimePlatform.Android)
{
try
{
using (AndroidJavaClass unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer"))
using (AndroidJavaObject activity = unityPlayer.GetStatic<AndroidJavaObject>("currentActivity"))
using (AndroidJavaClass trafficStats = new AndroidJavaClass("android.net.TrafficStats"))
{
// Verwende Android TrafficStats für präzise Netzwerk-Messung
long totalRx = trafficStats.CallStatic<long>("getTotalRxBytes");
return totalRx;
}
}
catch (Exception e)
{
Debug.LogWarning($"Android TrafficStats nicht verfügbar: {e.Message}");
return 0;
}
}
return GC.GetTotalMemory(false);
}
private long GetTotalBytesSent()
{
// Android-optimierte Netzwerk-Statistiken
if (Application.platform == RuntimePlatform.Android)
{
try
{
using (AndroidJavaClass unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer"))
using (AndroidJavaObject activity = unityPlayer.GetStatic<AndroidJavaObject>("currentActivity"))
using (AndroidJavaClass trafficStats = new AndroidJavaClass("android.net.TrafficStats"))
{
// Verwende Android TrafficStats für präzise Netzwerk-Messung
long totalTx = trafficStats.CallStatic<long>("getTotalTxBytes");
return totalTx;
}
}
catch (Exception e)
{
Debug.LogWarning($"Android TrafficStats nicht verfügbar: {e.Message}");
return 0;
}
}
return GC.GetTotalMemory(false);
}
private IEnumerator LogInternetVolume()
{
while (enableLogging)
{
yield return new WaitForSeconds(logInterval);
// Aktuelle Netzwerk-Statistiken abrufen
long currentBytesReceived = GetTotalBytesReceived();
long currentBytesSent = GetTotalBytesSent();
// Berechne die Differenz seit der letzten Messung
long deltaReceived = currentBytesReceived - lastBytesReceived;
long deltaSent = currentBytesSent - lastBytesSent;
// Addiere zur Gesamtsumme
totalBytesReceived += deltaReceived;
totalBytesSent += deltaSent;
// Aktualisiere die letzten Werte
lastBytesReceived = currentBytesReceived;
lastBytesSent = currentBytesSent;
// Erstelle Log-Eintrag
LogEntry logEntry = new LogEntry
{
timestamp = DateTime.Now,
sessionTime = Time.time - sessionStartTime,
bytesReceivedDelta = deltaReceived,
bytesSentDelta = deltaSent,
totalBytesReceived = totalBytesReceived,
totalBytesSent = totalBytesSent,
totalBytes = totalBytesReceived + totalBytesSent
};
// Logge die Daten
LogData(logEntry);
}
}
private void LogData(LogEntry entry)
{
string logLine = FormatLogEntry(entry);
// Console Log
if (showInConsole)
{
Debug.Log($"[Internet Volume] {logLine}");
}
// Datei Log
WriteToFile(logLine);
}
private string FormatLogEntry(LogEntry entry)
{
return $"{entry.timestamp:yyyy-MM-dd HH:mm:ss} | " +
$"Session: {entry.sessionTime:F1}s | " +
$"Δ↓: {FormatBytes(entry.bytesReceivedDelta)} | " +
$"Δ↑: {FormatBytes(entry.bytesSentDelta)} | " +
$"Total↓: {FormatBytes(entry.totalBytesReceived)} | " +
$"Total↑: {FormatBytes(entry.totalBytesSent)} | " +
$"Total: {FormatBytes(entry.totalBytes)}";
}
private string FormatBytes(double bytes)
{
string[] suffixes = { "B", "KB", "MB", "GB", "TB" };
int suffixIndex = 0;
while (bytes >= 1024 && suffixIndex < suffixes.Length - 1)
{
bytes /= 1024;
suffixIndex++;
}
return $"{bytes:F2} {suffixes[suffixIndex]}";
}
private void WriteLogHeader()
{
string header = $"=== Internet Volume Log gestartet am {DateTime.Now:yyyy-MM-dd HH:mm:ss} ===\n" +
$"App: {Application.productName} v{Application.version}\n" +
$"Platform: {Application.platform}\n" +
$"Log Intervall: {logInterval}s\n" +
$"{'=',-80}\n";
WriteToFile(header);
}
private void WriteToFile(string content)
{
try
{
// Stelle sicher, dass das Verzeichnis existiert
string directory = Path.GetDirectoryName(logFilePath);
if (!Directory.Exists(directory))
{
Directory.CreateDirectory(directory);
}
using (StreamWriter writer = new StreamWriter(logFilePath, true))
{
writer.WriteLine(content);
}
}
catch (Exception e)
{
Debug.LogError($"Fehler beim Schreiben in Log-Datei: {e.Message}");
}
}
private void OnApplicationPause(bool pauseStatus)
{
if (pauseStatus)
{
WriteToFile($"App pausiert um {DateTime.Now:HH:mm:ss}");
}
else
{
WriteToFile($"App fortgesetzt um {DateTime.Now:HH:mm:ss}");
}
}
private void OnApplicationQuit()
{
WriteToFile($"=== Session beendet um {DateTime.Now:yyyy-MM-dd HH:mm:ss} ===");
WriteToFile($"Gesamte Session-Dauer: {(Time.time - sessionStartTime):F1}s");
WriteToFile($"Gesamt empfangen: {FormatBytes(totalBytesReceived)}");
WriteToFile($"Gesamt gesendet: {FormatBytes(totalBytesSent)}");
WriteToFile($"Gesamt-Volumen: {FormatBytes(totalBytesReceived + totalBytesSent)}");
}
// Öffentliche Methoden für externe Aufrufe
public void StartLogging()
{
if (!enableLogging)
{
enableLogging = true;
StartCoroutine(LogInternetVolume());
}
}
public void StopLogging()
{
enableLogging = false;
}
public void ResetStats()
{
totalBytesReceived = 0;
totalBytesSent = 0;
InitializeBaseline();
WriteToFile($"Statistiken zurückgesetzt um {DateTime.Now:HH:mm:ss}");
}
public long GetTotalVolume()
{
return totalBytesReceived + totalBytesSent;
}
public string GetLogFilePath()
{
return logFilePath;
}
}
[System.Serializable]
public class LogEntry
{
public DateTime timestamp;
public float sessionTime;
public long bytesReceivedDelta;
public long bytesSentDelta;
public long totalBytesReceived;
public long totalBytesSent;
public long totalBytes;
}

View File

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

View File

@ -1,5 +1,34 @@
{ {
"intents": [ "intents": [
{
"intentID": "Zugabteil-Tutorial-U-8",
"intentSentences": [
"Ich heisse xy.",
"Mein Name ist xy.",
"Ich bin xy."
]
},
{
"intentID": "Zugabteil-Tutorial-U-15",
"intentSentences": [
"Mi piace di pi\u00f9 gli spaghetti.",
"Spaghetti."
]
},
{
"intentID": "Zugabteil-Tutorial-U-16",
"intentSentences": [
"Mi piace di pi\u00f9 una pizza.",
"Pizza."
]
},
{
"intentID": "Zugabteil-Tutorial-U-17",
"intentSentences": [
"Mi piace di pi\u00f9 il risotto.",
"Risotto."
]
},
{ {
"intentID": "Zugabteil.Szenenwahl.3", "intentID": "Zugabteil.Szenenwahl.3",
"intentSentences": [ "intentSentences": [