Add seeing mr Cement photos in the album

This commit is contained in:
Michal Pikulski
2025-12-15 15:24:17 +01:00
parent de02394198
commit f72b8f3cf5
20 changed files with 2194 additions and 230 deletions

View File

@@ -2,6 +2,7 @@
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Core;
using UnityEngine;
@@ -10,24 +11,12 @@ namespace Utils
/// <summary>
/// Generalized photo capture, storage, and retrieval manager.
/// Supports multiple capture types (minigames, screenshots, etc.) with type-based configuration.
/// Uses disk-only storage - no PlayerPrefs indexing (simplified for reliability).
/// </summary>
public static class PhotoManager
{
private const string RootCapturesFolder = "Captures";
/// <summary>
/// Photo metadata stored in PlayerPrefs
/// </summary>
[Serializable]
public class PhotoMetadata
{
public string photoId;
public CaptureType captureType;
public string timestamp;
public int genericMetadata; // Can be decoration count, score, collectibles, etc.
public long fileSizeBytes;
}
#region Plug-and-Play Coroutine
/// <summary>
@@ -189,7 +178,7 @@ namespace Utils
{
CaptureConfig config = PhotoCaptureConfigs.GetConfig(captureType);
// Generate unique photo ID
// Generate unique photo filename using timestamp
string photoId = $"{config.photoPrefix}{DateTime.Now.Ticks}";
// Get capture directory for this type
@@ -201,29 +190,12 @@ namespace Utils
Directory.CreateDirectory(captureDirectory);
}
// Save texture
// Save PNG to disk (that's it - no PlayerPrefs!)
string filePath = Path.Combine(captureDirectory, $"{photoId}.png");
byte[] pngData = photo.EncodeToPNG();
File.WriteAllBytes(filePath, pngData);
// Calculate file size
FileInfo fileInfo = new FileInfo(filePath);
long fileSize = fileInfo.Exists ? fileInfo.Length : 0;
// Save metadata
PhotoMetadata photoMetadata = new PhotoMetadata
{
photoId = photoId,
captureType = captureType,
timestamp = DateTime.Now.ToString("o"),
genericMetadata = metadata,
fileSizeBytes = fileSize
};
SaveMetadata(captureType, photoMetadata);
AddToPhotoIndex(captureType, photoId);
Logging.Debug($"[PhotoManager] Photo saved: {filePath} ({fileSize} bytes)");
Logging.Debug($"[PhotoManager] Photo saved: {filePath}");
return photoId;
}
catch (Exception e)
@@ -305,7 +277,7 @@ namespace Utils
}
/// <summary>
/// Delete photo and its metadata
/// Delete photo and its associated files
/// </summary>
public static bool DeletePhoto(CaptureType captureType, string photoId)
{
@@ -313,15 +285,19 @@ namespace Utils
try
{
// Delete main photo
string filePath = GetPhotoFilePath(captureType, photoId);
if (File.Exists(filePath))
{
File.Delete(filePath);
}
DeleteMetadata(captureType, photoId);
RemoveFromPhotoIndex(captureType, photoId);
// Delete decoration metadata if exists
string decorationPath = GetDecorationMetadataPath(captureType, photoId);
if (File.Exists(decorationPath))
{
File.Delete(decorationPath);
}
Logging.Debug($"[PhotoManager] Photo deleted: {photoId}");
return true;
@@ -338,44 +314,43 @@ namespace Utils
#region Retrieval & Queries
/// <summary>
/// Get photo IDs for a capture type (most recent first)
/// Get photo filenames sorted by newest first (scans disk)
/// </summary>
/// <param name="captureType">Type of capture</param>
/// <param name="count">Number of IDs to return (-1 = all)</param>
/// <param name="count">Number of filenames to return (-1 = all)</param>
public static List<string> GetPhotoIds(CaptureType captureType, int count = -1)
{
List<string> allIds = GetAllPhotoIds(captureType);
string directory = GetCaptureDirectory(captureType);
if (count < 0 || count >= allIds.Count)
if (!Directory.Exists(directory))
{
return allIds;
return new List<string>();
}
return allIds.GetRange(0, count);
try
{
// Get all PNG files, sorted by creation time (newest first)
var files = Directory.GetFiles(directory, "*.png")
.Select(f => new FileInfo(f))
.OrderByDescending(f => f.CreationTime)
.Select(f => Path.GetFileNameWithoutExtension(f.Name));
// Return top X or all
return (count > 0 ? files.Take(count) : files).ToList();
}
catch (Exception e)
{
Logging.Error($"[PhotoManager] Failed to scan directory {directory}: {e.Message}");
return new List<string>();
}
}
/// <summary>
/// Get all photo IDs sorted by timestamp (newest first)
/// Get all photo filenames sorted by newest first
/// </summary>
public static List<string> GetAllPhotoIds(CaptureType captureType)
{
CaptureConfig config = PhotoCaptureConfigs.GetConfig(captureType);
string indexJson = PlayerPrefs.GetString(config.indexKey, "[]");
List<string> photoIds = JsonUtility.FromJson<PhotoIdList>(WrapJsonArray(indexJson))?.ids ?? new List<string>();
// Sort by timestamp descending (newest first)
photoIds.Sort((a, b) =>
{
PhotoMetadata metaA = LoadMetadata(captureType, a);
PhotoMetadata metaB = LoadMetadata(captureType, b);
DateTime dateA = DateTime.Parse(metaA?.timestamp ?? DateTime.MinValue.ToString("o"));
DateTime dateB = DateTime.Parse(metaB?.timestamp ?? DateTime.MinValue.ToString("o"));
return dateB.CompareTo(dateA);
});
return photoIds;
return GetPhotoIds(captureType, -1);
}
/// <summary>
@@ -401,22 +376,14 @@ namespace Utils
}
/// <summary>
/// Get latest photo ID (most recent)
/// Get latest photo filename (most recent)
/// </summary>
public static string GetLatestPhotoId(CaptureType captureType)
{
List<string> allIds = GetAllPhotoIds(captureType);
List<string> allIds = GetPhotoIds(captureType, 1);
return allIds.Count > 0 ? allIds[0] : null;
}
/// <summary>
/// Load photo metadata
/// </summary>
public static PhotoMetadata GetPhotoMetadata(CaptureType captureType, string photoId)
{
return LoadMetadata(captureType, photoId);
}
#endregion
#region Utility Methods
@@ -565,68 +532,18 @@ namespace Utils
private static string GetPhotoFilePath(CaptureType captureType, string photoId)
{
return Path.Combine(GetCaptureDirectory(captureType), $"{photoId}.png");
// Ensure .png extension
if (!photoId.EndsWith(".png"))
photoId += ".png";
return Path.Combine(GetCaptureDirectory(captureType), photoId);
}
private static void SaveMetadata(CaptureType captureType, PhotoMetadata metadata)
private static string GetDecorationMetadataPath(CaptureType captureType, string photoId)
{
CaptureConfig config = PhotoCaptureConfigs.GetConfig(captureType);
string json = JsonUtility.ToJson(metadata);
PlayerPrefs.SetString(config.metadataPrefix + metadata.photoId, json);
PlayerPrefs.Save();
}
private static PhotoMetadata LoadMetadata(CaptureType captureType, string photoId)
{
CaptureConfig config = PhotoCaptureConfigs.GetConfig(captureType);
string json = PlayerPrefs.GetString(config.metadataPrefix + photoId, null);
return string.IsNullOrEmpty(json) ? null : JsonUtility.FromJson<PhotoMetadata>(json);
}
private static void DeleteMetadata(CaptureType captureType, string photoId)
{
CaptureConfig config = PhotoCaptureConfigs.GetConfig(captureType);
PlayerPrefs.DeleteKey(config.metadataPrefix + photoId);
PlayerPrefs.Save();
}
private static void AddToPhotoIndex(CaptureType captureType, string photoId)
{
List<string> photoIds = GetAllPhotoIds(captureType);
if (!photoIds.Contains(photoId))
{
photoIds.Add(photoId);
SavePhotoIndex(captureType, photoIds);
}
}
private static void RemoveFromPhotoIndex(CaptureType captureType, string photoId)
{
List<string> photoIds = GetAllPhotoIds(captureType);
if (photoIds.Remove(photoId))
{
SavePhotoIndex(captureType, photoIds);
}
}
private static void SavePhotoIndex(CaptureType captureType, List<string> photoIds)
{
CaptureConfig config = PhotoCaptureConfigs.GetConfig(captureType);
string json = JsonUtility.ToJson(new PhotoIdList { ids = photoIds });
PlayerPrefs.SetString(config.indexKey, json);
PlayerPrefs.Save();
}
private static string WrapJsonArray(string json)
{
if (json.StartsWith("[")) return "{\"ids\":" + json + "}";
return json;
}
[Serializable]
private class PhotoIdList
{
public List<string> ids = new List<string>();
// Remove .png extension if present for decoration metadata filename
string baseId = photoId.Replace(".png", "");
return Path.Combine(GetCaptureDirectory(captureType), $"{baseId}_decorations.json");
}
#endregion