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:
292
breakpilot-drive/UnityScripts/Core/DifficultyManager.cs
Normal file
292
breakpilot-drive/UnityScripts/Core/DifficultyManager.cs
Normal file
@@ -0,0 +1,292 @@
|
||||
// ==============================================
|
||||
// DifficultyManager.cs - Schwierigkeits-Steuerung
|
||||
// ==============================================
|
||||
// Passt die Spielschwierigkeit dynamisch an
|
||||
// basierend auf Lernniveau und Spielerleistung.
|
||||
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
namespace BreakpilotDrive
|
||||
{
|
||||
public class DifficultyManager : MonoBehaviour
|
||||
{
|
||||
public static DifficultyManager Instance { get; private set; }
|
||||
|
||||
[Header("Schwierigkeits-Bereich")]
|
||||
[SerializeField] private int minDifficulty = 1;
|
||||
[SerializeField] private int maxDifficulty = 5;
|
||||
|
||||
[Header("Dynamische Anpassung")]
|
||||
[SerializeField] private bool enableDynamicDifficulty = true;
|
||||
[SerializeField] private int questionsForEvaluation = 5;
|
||||
[SerializeField] private float accuracyToIncrease = 0.8f; // 80% richtig = schwerer
|
||||
[SerializeField] private float accuracyToDecrease = 0.4f; // 40% richtig = leichter
|
||||
|
||||
[Header("Geschwindigkeits-Steigerung")]
|
||||
[SerializeField] private bool enableSpeedIncrease = true;
|
||||
[SerializeField] private float speedIncreaseInterval = 30f; // Alle X Sekunden
|
||||
[SerializeField] private float speedIncreaseAmount = 0.5f; // Um X erhoehen
|
||||
|
||||
// Aktueller Zustand
|
||||
private int currentDifficulty = 3;
|
||||
private GameDifficulty currentSettings;
|
||||
private float timeSinceLastSpeedIncrease = 0f;
|
||||
|
||||
// Statistik fuer dynamische Anpassung
|
||||
private int recentQuestionsAnswered = 0;
|
||||
private int recentQuestionsCorrect = 0;
|
||||
|
||||
// Events
|
||||
public event Action<int> OnDifficultyChanged;
|
||||
public event Action<GameDifficulty> OnSettingsUpdated;
|
||||
|
||||
// Properties
|
||||
public int CurrentDifficulty => currentDifficulty;
|
||||
public GameDifficulty CurrentSettings => currentSettings;
|
||||
|
||||
void Awake()
|
||||
{
|
||||
if (Instance == null)
|
||||
{
|
||||
Instance = this;
|
||||
}
|
||||
else
|
||||
{
|
||||
Destroy(gameObject);
|
||||
}
|
||||
}
|
||||
|
||||
void Start()
|
||||
{
|
||||
// Quiz-Events abonnieren
|
||||
if (QuizManager.Instance != null)
|
||||
{
|
||||
QuizManager.Instance.OnQuestionAnswered += OnQuestionAnswered;
|
||||
}
|
||||
|
||||
// Initiale Schwierigkeit laden
|
||||
LoadDifficulty(currentDifficulty);
|
||||
}
|
||||
|
||||
void OnDestroy()
|
||||
{
|
||||
if (QuizManager.Instance != null)
|
||||
{
|
||||
QuizManager.Instance.OnQuestionAnswered -= OnQuestionAnswered;
|
||||
}
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
if (GameManager.Instance?.CurrentState != GameState.Playing)
|
||||
return;
|
||||
|
||||
// Geschwindigkeit graduell erhoehen
|
||||
if (enableSpeedIncrease)
|
||||
{
|
||||
timeSinceLastSpeedIncrease += Time.deltaTime;
|
||||
|
||||
if (timeSinceLastSpeedIncrease >= speedIncreaseInterval)
|
||||
{
|
||||
timeSinceLastSpeedIncrease = 0f;
|
||||
IncreaseSpeed();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ==============================================
|
||||
// Schwierigkeit laden
|
||||
// ==============================================
|
||||
public void LoadDifficulty(int level)
|
||||
{
|
||||
currentDifficulty = Mathf.Clamp(level, minDifficulty, maxDifficulty);
|
||||
|
||||
if (BreakpilotAPI.Instance != null)
|
||||
{
|
||||
StartCoroutine(BreakpilotAPI.Instance.GetDifficulty(currentDifficulty,
|
||||
onSuccess: (settings) =>
|
||||
{
|
||||
currentSettings = settings;
|
||||
ApplySettings(settings);
|
||||
OnSettingsUpdated?.Invoke(settings);
|
||||
Debug.Log($"Schwierigkeit {currentDifficulty} geladen");
|
||||
},
|
||||
onError: (error) =>
|
||||
{
|
||||
Debug.LogWarning($"Konnte Schwierigkeit nicht laden: {error}");
|
||||
// Fallback zu Default-Werten
|
||||
currentSettings = GetDefaultSettings(currentDifficulty);
|
||||
ApplySettings(currentSettings);
|
||||
}
|
||||
));
|
||||
}
|
||||
else
|
||||
{
|
||||
currentSettings = GetDefaultSettings(currentDifficulty);
|
||||
ApplySettings(currentSettings);
|
||||
}
|
||||
|
||||
OnDifficultyChanged?.Invoke(currentDifficulty);
|
||||
}
|
||||
|
||||
private void ApplySettings(GameDifficulty settings)
|
||||
{
|
||||
// Geschwindigkeit anwenden
|
||||
if (TrackGenerator.Instance != null)
|
||||
{
|
||||
TrackGenerator.Instance.SetSpeed(settings.lane_speed);
|
||||
}
|
||||
|
||||
if (PlayerController.Instance != null)
|
||||
{
|
||||
PlayerController.Instance.SetSpeed(settings.lane_speed);
|
||||
}
|
||||
|
||||
// Hindernis-Frequenz anwenden
|
||||
// ObstacleSpawner liest die Settings direkt aus GameManager
|
||||
|
||||
Debug.Log($"Settings angewendet: Speed={settings.lane_speed}, " +
|
||||
$"Obstacles={settings.obstacle_frequency}, " +
|
||||
$"Hints={settings.hints_enabled}");
|
||||
}
|
||||
|
||||
// ==============================================
|
||||
// Dynamische Anpassung
|
||||
// ==============================================
|
||||
private void OnQuestionAnswered(bool correct, int points)
|
||||
{
|
||||
if (!enableDynamicDifficulty) return;
|
||||
|
||||
recentQuestionsAnswered++;
|
||||
if (correct) recentQuestionsCorrect++;
|
||||
|
||||
// Evaluation nach X Fragen
|
||||
if (recentQuestionsAnswered >= questionsForEvaluation)
|
||||
{
|
||||
EvaluateAndAdjust();
|
||||
}
|
||||
}
|
||||
|
||||
private void EvaluateAndAdjust()
|
||||
{
|
||||
float accuracy = (float)recentQuestionsCorrect / recentQuestionsAnswered;
|
||||
|
||||
Debug.Log($"Quiz-Evaluation: {recentQuestionsCorrect}/{recentQuestionsAnswered} " +
|
||||
$"= {accuracy:P0}");
|
||||
|
||||
if (accuracy >= accuracyToIncrease && currentDifficulty < maxDifficulty)
|
||||
{
|
||||
// Spieler ist gut - Schwierigkeit erhoehen
|
||||
IncreaseDifficulty();
|
||||
}
|
||||
else if (accuracy <= accuracyToDecrease && currentDifficulty > minDifficulty)
|
||||
{
|
||||
// Spieler hat Probleme - Schwierigkeit verringern
|
||||
DecreaseDifficulty();
|
||||
}
|
||||
|
||||
// Reset fuer naechste Evaluation
|
||||
recentQuestionsAnswered = 0;
|
||||
recentQuestionsCorrect = 0;
|
||||
}
|
||||
|
||||
public void IncreaseDifficulty()
|
||||
{
|
||||
if (currentDifficulty < maxDifficulty)
|
||||
{
|
||||
LoadDifficulty(currentDifficulty + 1);
|
||||
Debug.Log($"Schwierigkeit erhoeht auf {currentDifficulty}");
|
||||
}
|
||||
}
|
||||
|
||||
public void DecreaseDifficulty()
|
||||
{
|
||||
if (currentDifficulty > minDifficulty)
|
||||
{
|
||||
LoadDifficulty(currentDifficulty - 1);
|
||||
Debug.Log($"Schwierigkeit verringert auf {currentDifficulty}");
|
||||
}
|
||||
}
|
||||
|
||||
// ==============================================
|
||||
// Geschwindigkeits-Steigerung
|
||||
// ==============================================
|
||||
private void IncreaseSpeed()
|
||||
{
|
||||
if (currentSettings == null) return;
|
||||
|
||||
float newSpeed = currentSettings.lane_speed + speedIncreaseAmount;
|
||||
|
||||
// Maximal-Geschwindigkeit basierend auf Difficulty
|
||||
float maxSpeed = 5f + (currentDifficulty * 2f);
|
||||
newSpeed = Mathf.Min(newSpeed, maxSpeed);
|
||||
|
||||
currentSettings.lane_speed = newSpeed;
|
||||
|
||||
if (TrackGenerator.Instance != null)
|
||||
{
|
||||
TrackGenerator.Instance.SetSpeed(newSpeed);
|
||||
}
|
||||
|
||||
Debug.Log($"Geschwindigkeit erhoeht auf {newSpeed:F1}");
|
||||
}
|
||||
|
||||
// ==============================================
|
||||
// Default-Werte (Fallback)
|
||||
// ==============================================
|
||||
private GameDifficulty GetDefaultSettings(int level)
|
||||
{
|
||||
return new GameDifficulty
|
||||
{
|
||||
lane_speed = 4f + level,
|
||||
obstacle_frequency = 0.3f + (level * 0.1f),
|
||||
power_up_chance = 0.4f - (level * 0.05f),
|
||||
question_complexity = level,
|
||||
answer_time = 15 - (level * 2),
|
||||
hints_enabled = level <= 2,
|
||||
speech_speed = 0.8f + (level * 0.1f)
|
||||
};
|
||||
}
|
||||
|
||||
// ==============================================
|
||||
// Oeffentliche Methoden
|
||||
// ==============================================
|
||||
public void SetDifficulty(int level)
|
||||
{
|
||||
LoadDifficulty(level);
|
||||
}
|
||||
|
||||
public void ResetForNewGame()
|
||||
{
|
||||
recentQuestionsAnswered = 0;
|
||||
recentQuestionsCorrect = 0;
|
||||
timeSinceLastSpeedIncrease = 0f;
|
||||
|
||||
// Schwierigkeit von User-Level laden
|
||||
if (BreakpilotAPI.Instance != null)
|
||||
{
|
||||
var cachedLevel = BreakpilotAPI.Instance.GetCachedLevel();
|
||||
if (cachedLevel != null)
|
||||
{
|
||||
LoadDifficulty(cachedLevel.overall_level);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public float GetCurrentSpeed()
|
||||
{
|
||||
return currentSettings?.lane_speed ?? 5f;
|
||||
}
|
||||
|
||||
public bool AreHintsEnabled()
|
||||
{
|
||||
return currentSettings?.hints_enabled ?? false;
|
||||
}
|
||||
|
||||
public int GetAnswerTime()
|
||||
{
|
||||
return currentSettings?.answer_time ?? 10;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user