fix: Restore all files lost during destructive rebase
A previous `git pull --rebase origin main` dropped 177 local commits,
losing 3400+ files across admin-v2, backend, studio-v2, website,
klausur-service, and many other services. The partial restore attempt
(660295e2) only recovered some files.
This commit restores all missing files from pre-rebase ref 98933f5e
while preserving post-rebase additions (night-scheduler, night-mode UI,
NightModeWidget dashboard integration).
Restored features include:
- AI Module Sidebar (FAB), OCR Labeling, OCR Compare
- GPU Dashboard, RAG Pipeline, Magic Help
- Klausur-Korrektur (8 files), Abitur-Archiv (5+ files)
- Companion, Zeugnisse-Crawler, Screen Flow
- Full backend, studio-v2, website, klausur-service
- All compliance SDKs, agent-core, voice-service
- CI/CD configs, documentation, scripts
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
290
breakpilot-drive/UnityScripts/Core/AudioManager.cs
Normal file
290
breakpilot-drive/UnityScripts/Core/AudioManager.cs
Normal file
@@ -0,0 +1,290 @@
|
||||
// ==============================================
|
||||
// AudioManager.cs - Audio-Verwaltung
|
||||
// ==============================================
|
||||
// Verwaltet Musik, Sound-Effekte und
|
||||
// Text-to-Speech fuer das Spiel.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace BreakpilotDrive
|
||||
{
|
||||
[System.Serializable]
|
||||
public class SoundEffect
|
||||
{
|
||||
public string name;
|
||||
public AudioClip clip;
|
||||
[Range(0f, 1f)]
|
||||
public float volume = 1f;
|
||||
[Range(0.5f, 1.5f)]
|
||||
public float pitch = 1f;
|
||||
public bool loop = false;
|
||||
}
|
||||
|
||||
public class AudioManager : MonoBehaviour
|
||||
{
|
||||
public static AudioManager Instance { get; private set; }
|
||||
|
||||
[Header("Audio Sources")]
|
||||
[SerializeField] private AudioSource musicSource;
|
||||
[SerializeField] private AudioSource sfxSource;
|
||||
[SerializeField] private AudioSource voiceSource;
|
||||
|
||||
[Header("Musik")]
|
||||
[SerializeField] private AudioClip menuMusic;
|
||||
[SerializeField] private AudioClip gameMusic;
|
||||
|
||||
[Header("Sound-Effekte")]
|
||||
[SerializeField] private SoundEffect[] soundEffects;
|
||||
|
||||
[Header("Lautstaerke")]
|
||||
[Range(0f, 1f)]
|
||||
[SerializeField] private float masterVolume = 1f;
|
||||
[Range(0f, 1f)]
|
||||
[SerializeField] private float musicVolume = 0.5f;
|
||||
[Range(0f, 1f)]
|
||||
[SerializeField] private float sfxVolume = 1f;
|
||||
[Range(0f, 1f)]
|
||||
[SerializeField] private float voiceVolume = 1f;
|
||||
|
||||
// Sound-Dictionary fuer schnellen Zugriff
|
||||
private Dictionary<string, SoundEffect> soundDict = new Dictionary<string, SoundEffect>();
|
||||
|
||||
void Awake()
|
||||
{
|
||||
if (Instance == null)
|
||||
{
|
||||
Instance = this;
|
||||
DontDestroyOnLoad(gameObject);
|
||||
InitializeSounds();
|
||||
LoadVolumeSettings();
|
||||
}
|
||||
else
|
||||
{
|
||||
Destroy(gameObject);
|
||||
}
|
||||
}
|
||||
|
||||
private void InitializeSounds()
|
||||
{
|
||||
soundDict.Clear();
|
||||
foreach (var sound in soundEffects)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(sound.name) && sound.clip != null)
|
||||
{
|
||||
soundDict[sound.name.ToLower()] = sound;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ==============================================
|
||||
// Musik
|
||||
// ==============================================
|
||||
public void PlayMenuMusic()
|
||||
{
|
||||
PlayMusic(menuMusic);
|
||||
}
|
||||
|
||||
public void PlayGameMusic()
|
||||
{
|
||||
PlayMusic(gameMusic);
|
||||
}
|
||||
|
||||
public void PlayMusic(AudioClip clip)
|
||||
{
|
||||
if (musicSource == null || clip == null) return;
|
||||
|
||||
if (musicSource.clip == clip && musicSource.isPlaying)
|
||||
return;
|
||||
|
||||
musicSource.clip = clip;
|
||||
musicSource.volume = musicVolume * masterVolume;
|
||||
musicSource.loop = true;
|
||||
musicSource.Play();
|
||||
}
|
||||
|
||||
public void StopMusic()
|
||||
{
|
||||
if (musicSource != null)
|
||||
{
|
||||
musicSource.Stop();
|
||||
}
|
||||
}
|
||||
|
||||
public void PauseMusic()
|
||||
{
|
||||
if (musicSource != null)
|
||||
{
|
||||
musicSource.Pause();
|
||||
}
|
||||
}
|
||||
|
||||
public void ResumeMusic()
|
||||
{
|
||||
if (musicSource != null)
|
||||
{
|
||||
musicSource.UnPause();
|
||||
}
|
||||
}
|
||||
|
||||
// ==============================================
|
||||
// Sound-Effekte
|
||||
// ==============================================
|
||||
public void PlaySound(string soundName)
|
||||
{
|
||||
if (sfxSource == null) return;
|
||||
|
||||
string key = soundName.ToLower();
|
||||
if (soundDict.TryGetValue(key, out SoundEffect sound))
|
||||
{
|
||||
sfxSource.pitch = sound.pitch;
|
||||
sfxSource.PlayOneShot(sound.clip, sound.volume * sfxVolume * masterVolume);
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogWarning($"Sound '{soundName}' nicht gefunden!");
|
||||
}
|
||||
}
|
||||
|
||||
public void PlaySound(AudioClip clip, float volume = 1f)
|
||||
{
|
||||
if (sfxSource == null || clip == null) return;
|
||||
sfxSource.PlayOneShot(clip, volume * sfxVolume * masterVolume);
|
||||
}
|
||||
|
||||
// Vordefinierte Sound-Methoden
|
||||
public void PlayCoinSound() => PlaySound("coin");
|
||||
public void PlayCrashSound() => PlaySound("crash");
|
||||
public void PlayCorrectSound() => PlaySound("correct");
|
||||
public void PlayWrongSound() => PlaySound("wrong");
|
||||
public void PlayButtonSound() => PlaySound("button");
|
||||
|
||||
// ==============================================
|
||||
// Text-to-Speech (WebGL)
|
||||
// ==============================================
|
||||
public void Speak(string text)
|
||||
{
|
||||
if (string.IsNullOrEmpty(text)) return;
|
||||
|
||||
#if UNITY_WEBGL && !UNITY_EDITOR
|
||||
SpeakWebGL(text);
|
||||
#else
|
||||
Debug.Log($"[TTS] {text}");
|
||||
#endif
|
||||
}
|
||||
|
||||
public void SpeakQuestion(QuizQuestion question)
|
||||
{
|
||||
if (question == null) return;
|
||||
|
||||
Speak(question.question_text);
|
||||
|
||||
// Optionen vorlesen (mit Verzoegerung)
|
||||
for (int i = 0; i < question.options.Length; i++)
|
||||
{
|
||||
string optionText = $"Option {i + 1}: {question.options[i]}";
|
||||
// In WebGL: Verzoegerung ueber JavaScript
|
||||
#if UNITY_WEBGL && !UNITY_EDITOR
|
||||
SpeakDelayedWebGL(optionText, 1.5f + (i * 1.5f));
|
||||
#else
|
||||
Debug.Log($"[TTS] {optionText}");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
public void SpeakFeedback(bool correct)
|
||||
{
|
||||
string message = correct ?
|
||||
"Richtig! Gut gemacht!" :
|
||||
"Nicht ganz. Versuch es nochmal!";
|
||||
Speak(message);
|
||||
}
|
||||
|
||||
public void StopSpeaking()
|
||||
{
|
||||
#if UNITY_WEBGL && !UNITY_EDITOR
|
||||
StopSpeakingWebGL();
|
||||
#endif
|
||||
}
|
||||
|
||||
// WebGL JavaScript Interop
|
||||
#if UNITY_WEBGL && !UNITY_EDITOR
|
||||
[System.Runtime.InteropServices.DllImport("__Internal")]
|
||||
private static extern void SpeakWebGL(string text);
|
||||
|
||||
[System.Runtime.InteropServices.DllImport("__Internal")]
|
||||
private static extern void SpeakDelayedWebGL(string text, float delaySeconds);
|
||||
|
||||
[System.Runtime.InteropServices.DllImport("__Internal")]
|
||||
private static extern void StopSpeakingWebGL();
|
||||
#endif
|
||||
|
||||
// ==============================================
|
||||
// Lautstaerke-Einstellungen
|
||||
// ==============================================
|
||||
public void SetMasterVolume(float volume)
|
||||
{
|
||||
masterVolume = Mathf.Clamp01(volume);
|
||||
UpdateAllVolumes();
|
||||
SaveVolumeSettings();
|
||||
}
|
||||
|
||||
public void SetMusicVolume(float volume)
|
||||
{
|
||||
musicVolume = Mathf.Clamp01(volume);
|
||||
if (musicSource != null)
|
||||
{
|
||||
musicSource.volume = musicVolume * masterVolume;
|
||||
}
|
||||
SaveVolumeSettings();
|
||||
}
|
||||
|
||||
public void SetSFXVolume(float volume)
|
||||
{
|
||||
sfxVolume = Mathf.Clamp01(volume);
|
||||
SaveVolumeSettings();
|
||||
}
|
||||
|
||||
public void SetVoiceVolume(float volume)
|
||||
{
|
||||
voiceVolume = Mathf.Clamp01(volume);
|
||||
if (voiceSource != null)
|
||||
{
|
||||
voiceSource.volume = voiceVolume * masterVolume;
|
||||
}
|
||||
SaveVolumeSettings();
|
||||
}
|
||||
|
||||
private void UpdateAllVolumes()
|
||||
{
|
||||
if (musicSource != null)
|
||||
musicSource.volume = musicVolume * masterVolume;
|
||||
if (voiceSource != null)
|
||||
voiceSource.volume = voiceVolume * masterVolume;
|
||||
}
|
||||
|
||||
private void SaveVolumeSettings()
|
||||
{
|
||||
PlayerPrefs.SetFloat("MasterVolume", masterVolume);
|
||||
PlayerPrefs.SetFloat("MusicVolume", musicVolume);
|
||||
PlayerPrefs.SetFloat("SFXVolume", sfxVolume);
|
||||
PlayerPrefs.SetFloat("VoiceVolume", voiceVolume);
|
||||
PlayerPrefs.Save();
|
||||
}
|
||||
|
||||
private void LoadVolumeSettings()
|
||||
{
|
||||
masterVolume = PlayerPrefs.GetFloat("MasterVolume", 1f);
|
||||
musicVolume = PlayerPrefs.GetFloat("MusicVolume", 0.5f);
|
||||
sfxVolume = PlayerPrefs.GetFloat("SFXVolume", 1f);
|
||||
voiceVolume = PlayerPrefs.GetFloat("VoiceVolume", 1f);
|
||||
UpdateAllVolumes();
|
||||
}
|
||||
|
||||
// Properties fuer UI-Sliders
|
||||
public float MasterVolume => masterVolume;
|
||||
public float MusicVolume => musicVolume;
|
||||
public float SFXVolume => sfxVolume;
|
||||
public float VoiceVolume => voiceVolume;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user