137 lines
4.3 KiB
C#
137 lines
4.3 KiB
C#
using System.Collections.Generic;
|
|
using System.Text.Json;
|
|
using Godot;
|
|
using Mr.BrickAdventures.scripts;
|
|
using Mr.BrickAdventures.scripts.State;
|
|
|
|
namespace Mr.BrickAdventures.Autoloads;
|
|
|
|
public partial class GhostManager : Node
|
|
{
|
|
public static GhostManager Instance { get; private set; }
|
|
|
|
[Export] private PackedScene GhostPlayerScene { get; set; }
|
|
|
|
public override void _Ready() => Instance = this;
|
|
public override void _ExitTree() { if (Instance == this) Instance = null; }
|
|
|
|
public bool IsRecording { get; private set; } = false;
|
|
public bool IsPlaybackEnabled { get; private set; } = true;
|
|
|
|
private List<GhostFrame> _currentRecording = [];
|
|
private double _startTime = 0.0;
|
|
private int _currentLevelIndex = -1;
|
|
|
|
public void StartRecording(int levelIndex)
|
|
{
|
|
if (!IsPlaybackEnabled) return;
|
|
|
|
_currentLevelIndex = levelIndex;
|
|
_currentRecording.Clear();
|
|
_startTime = Time.GetTicksMsec() / 1000.0;
|
|
IsRecording = true;
|
|
GD.Print("Ghost recording started.");
|
|
}
|
|
|
|
public void StopRecording(bool levelCompleted, double finalTime)
|
|
{
|
|
if (!IsRecording) return;
|
|
IsRecording = false;
|
|
|
|
if (levelCompleted)
|
|
{
|
|
var bestTime = LoadBestTime(_currentLevelIndex);
|
|
if (finalTime < bestTime)
|
|
{
|
|
SaveGhostData(_currentLevelIndex, finalTime);
|
|
GD.Print($"New best ghost saved for level {_currentLevelIndex}. Time: {finalTime}");
|
|
}
|
|
}
|
|
_currentRecording.Clear();
|
|
}
|
|
|
|
public void RecordFrame(Vector2 position)
|
|
{
|
|
if (!IsRecording) return;
|
|
|
|
_currentRecording.Add(new GhostFrame
|
|
{
|
|
Timestamp = (Time.GetTicksMsec() / 1000.0) - _startTime,
|
|
Position = position
|
|
});
|
|
}
|
|
|
|
public void SpawnGhostPlayer(int levelIndex, Node parent)
|
|
{
|
|
if (!IsPlaybackEnabled || GhostPlayerScene == null) return;
|
|
|
|
var ghostData = LoadGhostData(levelIndex);
|
|
if (ghostData.Count > 0)
|
|
{
|
|
var ghostPlayer = GhostPlayerScene.Instantiate<GhostPlayer>();
|
|
parent.AddChild(ghostPlayer);
|
|
ghostPlayer.StartPlayback(ghostData);
|
|
GD.Print($"Ghost player spawned for level {levelIndex}.");
|
|
}
|
|
}
|
|
|
|
private void SaveGhostData(int levelIndex, double time)
|
|
{
|
|
var path = $"user://ghost_level_{levelIndex}.json";
|
|
var saveData = new GhostSaveData { BestTime = time };
|
|
foreach (var frame in _currentRecording)
|
|
saveData.Frames.Add(new GhostFrameDto { Timestamp = frame.Timestamp, X = frame.Position.X, Y = frame.Position.Y });
|
|
|
|
try
|
|
{
|
|
var json = JsonSerializer.Serialize(saveData, SaveSystem.JsonOptions);
|
|
using var file = FileAccess.Open(path, FileAccess.ModeFlags.Write);
|
|
file.StoreString(json);
|
|
}
|
|
catch (System.Exception e)
|
|
{
|
|
GD.PrintErr($"GhostManager: Failed to save ghost data: {e.Message}");
|
|
}
|
|
}
|
|
|
|
private List<GhostFrame> LoadGhostData(int levelIndex)
|
|
{
|
|
var path = $"user://ghost_level_{levelIndex}.json";
|
|
if (!FileAccess.FileExists(path)) return [];
|
|
|
|
try
|
|
{
|
|
using var file = FileAccess.Open(path, FileAccess.ModeFlags.Read);
|
|
var saveData = JsonSerializer.Deserialize<GhostSaveData>(file.GetAsText(), SaveSystem.JsonOptions);
|
|
if (saveData == null) return [];
|
|
|
|
var frames = new List<GhostFrame>();
|
|
foreach (var dto in saveData.Frames)
|
|
frames.Add(new GhostFrame { Timestamp = dto.Timestamp, Position = new Vector2(dto.X, dto.Y) });
|
|
return frames;
|
|
}
|
|
catch (System.Exception e)
|
|
{
|
|
GD.PrintErr($"GhostManager: Failed to load ghost data: {e.Message}");
|
|
return [];
|
|
}
|
|
}
|
|
|
|
private double LoadBestTime(int levelIndex)
|
|
{
|
|
var path = $"user://ghost_level_{levelIndex}.json";
|
|
if (!FileAccess.FileExists(path)) return double.MaxValue;
|
|
|
|
try
|
|
{
|
|
using var file = FileAccess.Open(path, FileAccess.ModeFlags.Read);
|
|
var saveData = JsonSerializer.Deserialize<GhostSaveData>(file.GetAsText(), SaveSystem.JsonOptions);
|
|
return saveData?.BestTime ?? double.MaxValue;
|
|
}
|
|
catch
|
|
{
|
|
return double.MaxValue;
|
|
}
|
|
}
|
|
}
|