Files
Ajedrez_Purgatorio/Assets/Editor/SpeakerDatabaseSetup.cs
T
jimmyabv f7d56066c0 feat: Purgatory Final duel vs La Muerte + SFX wiring + runtime options menu
- Duel flow: mating piece vs boss while board collapses (PurgatoryDuelManager/Rules/UI/MuerteQuotes)
- GameState.PurgatoryDuel + CampaignManager rescue/restart hooks + SquareClick routing
- Dice-based rescue of most valuable dead identity; final defeat restarts Chapter 1
- 6 SFX clips wired in Ch1/2/3 via AudioClipAssigner
- OptionsMenuController runtime audio/graphics panel, wired to MainMenu
- Tests migrated to Assets/Tests/EditMode subfolders + PurgatoryDuelRulesTests (200 total)
- Editor tools: DiagAssign, SpeakerDatabaseSetup, PurgatoryCanvasMaintenance
2026-08-24 19:39:52 -03:00

167 lines
6.3 KiB
C#

using System.Linq;
using UnityEditor;
using UnityEditor.SceneManagement;
using UnityEngine;
using UnityEngine.SceneManagement;
namespace AjedrezPurgatorio.EditorTools
{
/// <summary>
/// Puebla el SpeakerDatabase.asset con los retratos existentes y asigna el
/// asset a todos los DialogueUI de las escenas. Guarda los cambios.
/// Ejecutar con:
/// Unity -batchmode -projectPath . -executeMethod
/// AjedrezPurgatorio.EditorTools.SpeakerDatabaseSetup.PopulateAndAssign
///
/// Nota: 'muerte' y 'ricardo' no tienen PNG de retrato todavía; se registran
/// con portrait nulo para evitar warnings y facilitar añadir arte después.
/// </summary>
public static class SpeakerDatabaseSetup
{
private const string DatabasePath = "Assets/Game/Data/Resources/SpeakerDatabase.asset";
private const string PortraitsFolder = "Assets/Game/Data/Resources/Portraits";
private static readonly (string speaker, string portrait)[] Entries =
{
("narrator", "narrator"),
("muerte", null),
("ricardo", null),
("alfil", "alfil"),
("caballo", "caballo"),
("peon", "peon"),
("reina", "reina"),
("torre", "torre"),
("espejo", "espejo"),
("coleccionista", "coleccionista"),
("enemigo", "enemigo"),
("voz_nino", "voz_nino"),
};
private static readonly string[] SceneNames =
{
"MainMenu", "Chapter1", "Chapter2", "Chapter3",
};
public static void PopulateAndAssign()
{
try
{
int populated = PopulateDatabase();
int assigned = AssignToScenes();
Debug.Log($"[SpeakerDatabaseSetup] COMPLETO: {populated} speakers poblados, {assigned} DialogueUI actualizados.");
EditorApplication.Exit(0);
}
catch (System.Exception ex)
{
Debug.LogError($"[SpeakerDatabaseSetup] FALLÓ: {ex}");
EditorApplication.Exit(1);
}
}
private static int PopulateDatabase()
{
var db = AssetDatabase.LoadAssetAtPath<SpeakerDatabase>(DatabasePath);
if (db == null)
throw new System.IO.FileNotFoundException($"No se encontró {DatabasePath}");
// Los PNG de Portraits pueden no estar importados en la AssetDatabase
// (p.ej. Library regenerada). Importar explícitamente sin Refresh global.
int imported = 0;
foreach (var (_, portraitFile) in Entries)
{
if (string.IsNullOrEmpty(portraitFile))
continue;
string path = $"{PortraitsFolder}/{portraitFile}.png";
if (!System.IO.File.Exists(path))
{
Debug.LogError($"[SpeakerDatabaseSetup] No existe en disco: {path}");
continue;
}
try
{
AssetDatabase.ImportAsset(path, ImportAssetOptions.ForceUpdate);
imported++;
}
catch (System.Exception ex)
{
Debug.LogError($"[SpeakerDatabaseSetup] Fallo importando {path}: {ex.Message}");
}
}
Debug.Log($"[SpeakerDatabaseSetup] {imported} retratos re-importados.");
var so = new SerializedObject(db);
SerializedProperty list = so.FindProperty("_speakers");
if (list == null)
throw new System.MissingMemberException("_speakers no encontrado en SpeakerDatabase.");
list.ClearArray();
int count = 0;
foreach (var (speaker, portraitFile) in Entries)
{
list.InsertArrayElementAtIndex(list.arraySize);
SerializedProperty element = list.GetArrayElementAtIndex(list.arraySize - 1);
element.FindPropertyRelative("speakerName").stringValue = speaker;
Sprite sprite = null;
if (!string.IsNullOrEmpty(portraitFile))
sprite = AssetDatabase.LoadAssetAtPath<Sprite>($"{PortraitsFolder}/{portraitFile}.png");
if (!string.IsNullOrEmpty(portraitFile) && sprite == null)
Debug.LogWarning($"[SpeakerDatabaseSetup] Portrait no encontrado para '{speaker}': {portraitFile}.png");
element.FindPropertyRelative("portrait").objectReferenceValue = sprite;
count++;
}
so.ApplyModifiedPropertiesWithoutUndo();
EditorUtility.SetDirty(db);
AssetDatabase.SaveAssets();
return count;
}
private static int AssignToScenes()
{
var db = AssetDatabase.LoadAssetAtPath<SpeakerDatabase>(DatabasePath);
int assignedTotal = 0;
// Nota: SerializedObject.ApplyModifiedProperties* no persiste este
// cambio en este proyecto (probado: el valor se pierde incluso en
// memoria tras Apply). Reflexión directa + SetDirty sí funciona.
var field = typeof(DialogueUI).GetField("_speakerDatabase",
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
foreach (string sceneName in SceneNames)
{
Scene scene = EditorSceneManager.OpenScene(
$"Assets/Scenes/{sceneName}.unity", OpenSceneMode.Single);
bool dirty = false;
foreach (DialogueUI ui in Object.FindObjectsByType<DialogueUI>(
FindObjectsInactive.Include, FindObjectsSortMode.None))
{
if (ui == null || field.GetValue(ui) as SpeakerDatabase != null)
continue;
field.SetValue(ui, db);
EditorUtility.SetDirty(ui);
assignedTotal++;
dirty = true;
}
if (dirty)
EditorSceneManager.MarkSceneDirty(scene);
EditorSceneManager.SaveScene(scene);
}
return assignedTotal;
}
}
}