212 lines
7.3 KiB
C#
212 lines
7.3 KiB
C#
using System;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using UnityEngine;
|
|
using UnityEngine.SceneManagement;
|
|
using GeoSus.Client;
|
|
|
|
namespace Subsystems
|
|
{
|
|
/// <summary>
|
|
/// Round-robin task-to-minigame assignment, proximity detection, additive scene launch.
|
|
/// </summary>
|
|
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<TaskEntry> _tasks = new List<TaskEntry>();
|
|
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;
|
|
}
|
|
|
|
/// <summary>Called by Network subsystem when RoleAssigned fires.</summary>
|
|
public void Initialize(List<GeoSus.Client.GameTask> 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.");
|
|
}
|
|
|
|
/// <summary>Called every frame from GameManager.Update().</summary>
|
|
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);
|
|
}
|
|
|
|
/// <summary>Called externally (e.g., GameManager.PerformAction) to launch the nearby task.</summary>
|
|
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<ITask>();
|
|
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;
|
|
}
|
|
}
|
|
}
|