using System; using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.SceneManagement; using GeoSus.Client; namespace Subsystems { /// /// Round-robin task-to-minigame assignment, proximity detection, additive scene launch. /// public class GameManager_Tasks { private class TaskEntry { public GeoSus.Client.GameTask ServerTask; public string MinigameScene; public bool Completed; } private GameClient _gameClient; private string[] _minigameScenes; private MonoBehaviour _host; // GameManager MonoBehaviour for coroutines private List _tasks = new List(); private bool _minigameOpen; private string _loadedMinigameScene; // Proximity state (checked every frame in UpdateProximity) public GeoSus.Client.GameTask NearbyTask { get; private set; } private const float ProximityRadius = 5f; // metres / Unity units public GameManager_Tasks(GameClient gameClient, string[] minigameScenes, MonoBehaviour host) { _gameClient = gameClient; _minigameScenes = minigameScenes ?? new string[0]; _host = host; } /// Called by Network subsystem when RoleAssigned fires. public void Initialize(List serverTasks) { _tasks.Clear(); if (_minigameScenes.Length == 0) return; for (int i = 0; i < serverTasks.Count; i++) { _tasks.Add(new TaskEntry { ServerTask = serverTasks[i], MinigameScene = _minigameScenes[i % _minigameScenes.Length], Completed = false }); } // Create map markers GameManager.Instance?.mapSubsystem?.CreateTaskMarkers(serverTasks); Debug.Log($"[Tasks] Initialized {_tasks.Count} tasks."); } /// Called every frame from GameManager.Update(). public void UpdateProximity() { if (_minigameOpen) return; NearbyTask = null; var myPos = _gameClient.MyPosition; if (myPos.Lat == 0 && myPos.Lon == 0) return; foreach (var entry in _tasks) { if (entry.Completed) continue; double dist = myPos.DistanceTo(entry.ServerTask.Location); if (dist <= ProximityRadius) { NearbyTask = entry.ServerTask; break; } } // Drive the action button in UI var ui = GameManager.Instance?.uiSubsystem; if (ui == null || ui.IsPlayerDead) return; bool isImpostor = _gameClient.MyRole == GeoSus.Client.PlayerRole.Impostor; if (!isImpostor && NearbyTask != null) { ui.SetActionButton("USE", true, () => GameManager.Instance?.PerformAction()); return; } // Check body proximity if (!ui.IsCommsBlackout) { var body = _gameClient.FindNearbyBody(ProximityRadius); if (body != null) { ui.SetActionButton("REPORT", true, () => GameManager.Instance?.PerformAction()); return; } // Emergency meeting proximity if (_gameClient.CurrentLobbyState?.MapData != null) { double dist = myPos.DistanceTo(_gameClient.CurrentLobbyState.MapData.Center); if (dist <= ProximityRadius) { ui.SetActionButton("EMERGENCY", true, () => GameManager.Instance?.PerformAction()); return; } } } // Impostor kill if (isImpostor) { var target = _gameClient.FindNearbyPlayer(ProximityRadius); if (!string.IsNullOrEmpty(target)) { ui.SetActionButton("KILL", true, () => GameManager.Instance?.PerformAction()); return; } } // Nothing nearby ui.SetActionButton("", false); } /// Called externally (e.g., GameManager.PerformAction) to launch the nearby task. public void TriggerNearbyTask() { OnUsePressed(); } private void OnUsePressed() { if (NearbyTask == null || _minigameOpen) return; var entry = _tasks.Find(t => t.ServerTask.TaskId == NearbyTask.TaskId); if (entry != null) _host.StartCoroutine(LaunchMinigame(entry)); } private IEnumerator LaunchMinigame(TaskEntry entry) { _minigameOpen = true; Debug.Log($"[Tasks] Launching minigame '{entry.MinigameScene}' for task '{entry.ServerTask.Name}'"); // Inform server that task started _gameClient.Send(new TaskStart { TaskId = entry.ServerTask.TaskId }); var op = SceneManager.LoadSceneAsync(entry.MinigameScene, LoadSceneMode.Additive); yield return op; _loadedMinigameScene = entry.MinigameScene; // Find the ITask component in the newly loaded scene Scene scene = SceneManager.GetSceneByName(entry.MinigameScene); ITask taskComponent = null; foreach (var root in scene.GetRootGameObjects()) { taskComponent = root.GetComponentInChildren(); if (taskComponent != null) break; } if (taskComponent == null) { Debug.LogWarning($"[Tasks] No ITask found in '{entry.MinigameScene}'. Auto-completing."); yield return FinishMinigame(entry, true); yield break; } // Set task metadata taskComponent.TaskID = entry.ServerTask.TaskId; taskComponent.TaskName = entry.ServerTask.Name; taskComponent.TaskLocation = (entry.ServerTask.Location.Lat, entry.ServerTask.Location.Lon); bool done = false; taskComponent.Initialize(t => { done = true; }); // Wait for completion or exit yield return new WaitUntil(() => done); yield return FinishMinigame(entry, done); } private IEnumerator FinishMinigame(TaskEntry entry, bool completed) { if (completed) { entry.Completed = true; _gameClient.CompleteTask(entry.ServerTask.TaskId); Debug.Log($"[Tasks] Task '{entry.ServerTask.Name}' completed."); } else { Debug.Log($"[Tasks] Task '{entry.ServerTask.Name}' exited without completion."); } // Unload minigame scene if (!string.IsNullOrEmpty(_loadedMinigameScene)) { var unload = SceneManager.UnloadSceneAsync(_loadedMinigameScene); yield return unload; _loadedMinigameScene = null; } _minigameOpen = false; } } }