Compare commits
27 Commits
hud_unific
...
7307971748
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7307971748 | ||
|
|
9a6914b9bd | ||
| 0aa2270e1a | |||
|
|
c4d356886f | ||
|
|
64d7f19b83 | ||
| ce21e8b02e | |||
| f44f8c5171 | |||
| 9772206362 | |||
|
|
3ebbecc277 | ||
|
|
c99aad49f3 | ||
| 3fe4c6afd9 | |||
| 9c61065947 | |||
|
|
7c09db641a | ||
|
|
e369660a8f | ||
| a6e3413499 | |||
| 7bb992acb8 | |||
|
|
cefa488a92 | ||
| 9344f06886 | |||
| af7e081c9a | |||
|
|
4a6ac7281f | ||
| 861797ba41 | |||
| 98883bd382 | |||
| 474941f421 | |||
|
|
75cd70a18a | ||
| e82ec90723 | |||
|
|
252cb99884 | ||
| 3f548c3ed4 |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -104,3 +104,6 @@ InitTestScene*.unity*
|
|||||||
.vscode/launch.json
|
.vscode/launch.json
|
||||||
.vscode/settings.json
|
.vscode/settings.json
|
||||||
.idea/.idea.AppleHillsProduction/.idea/indexLayout.xml
|
.idea/.idea.AppleHillsProduction/.idea/indexLayout.xml
|
||||||
|
|
||||||
|
# WIP docs
|
||||||
|
/docs/wip/
|
||||||
|
|||||||
@@ -71,7 +71,6 @@ namespace AppleHills.Editor
|
|||||||
{
|
{
|
||||||
CardSystemManager.Instance.OnBoosterOpened += OnBoosterOpened;
|
CardSystemManager.Instance.OnBoosterOpened += OnBoosterOpened;
|
||||||
CardSystemManager.Instance.OnCardCollected += OnCardCollected;
|
CardSystemManager.Instance.OnCardCollected += OnCardCollected;
|
||||||
CardSystemManager.Instance.OnCardRarityUpgraded += OnCardRarityUpgraded;
|
|
||||||
CardSystemManager.Instance.OnBoosterCountChanged += OnBoosterCountChanged;
|
CardSystemManager.Instance.OnBoosterCountChanged += OnBoosterCountChanged;
|
||||||
|
|
||||||
isSubscribed = true;
|
isSubscribed = true;
|
||||||
@@ -87,7 +86,6 @@ namespace AppleHills.Editor
|
|||||||
{
|
{
|
||||||
CardSystemManager.Instance.OnBoosterOpened -= OnBoosterOpened;
|
CardSystemManager.Instance.OnBoosterOpened -= OnBoosterOpened;
|
||||||
CardSystemManager.Instance.OnCardCollected -= OnCardCollected;
|
CardSystemManager.Instance.OnCardCollected -= OnCardCollected;
|
||||||
CardSystemManager.Instance.OnCardRarityUpgraded -= OnCardRarityUpgraded;
|
|
||||||
CardSystemManager.Instance.OnBoosterCountChanged -= OnBoosterCountChanged;
|
CardSystemManager.Instance.OnBoosterCountChanged -= OnBoosterCountChanged;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -109,13 +107,6 @@ namespace AppleHills.Editor
|
|||||||
Repaint();
|
Repaint();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnCardRarityUpgraded(CardData card)
|
|
||||||
{
|
|
||||||
lastEventMessage = $"Card upgraded: {card.Name} → {card.Rarity}!";
|
|
||||||
RefreshData();
|
|
||||||
Repaint();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnBoosterCountChanged(int count)
|
private void OnBoosterCountChanged(int count)
|
||||||
{
|
{
|
||||||
boosterCount = count;
|
boosterCount = count;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityEditor;
|
using UnityEditor;
|
||||||
|
|
||||||
namespace Interactions
|
namespace Interactions
|
||||||
|
|||||||
829
Assets/Editor/CustomLogWindow.cs
Normal file
829
Assets/Editor/CustomLogWindow.cs
Normal file
@@ -0,0 +1,829 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using UnityEditor;
|
||||||
|
using UnityEngine;
|
||||||
|
using Core;
|
||||||
|
|
||||||
|
namespace Editor
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Custom dockable log window with advanced filtering capabilities.
|
||||||
|
/// Supports filtering by class, method, log level, time range, and text search.
|
||||||
|
/// Multiple instances can be opened with independent filter states.
|
||||||
|
///
|
||||||
|
/// PERFORMANCE NOTE: For large log counts (10,000+), consider implementing virtualized scrolling.
|
||||||
|
/// Only render visible entries within the scroll view to avoid GUI overhead.
|
||||||
|
/// See DrawLogEntries() method for potential optimization location.
|
||||||
|
/// </summary>
|
||||||
|
public class CustomLogWindow : EditorWindow
|
||||||
|
{
|
||||||
|
#region Window State
|
||||||
|
|
||||||
|
private Vector2 scrollPosition;
|
||||||
|
private readonly List<LogEntry> allLogs = new List<LogEntry>();
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Filter State
|
||||||
|
|
||||||
|
private HashSet<string> activeClassTags = new HashSet<string>();
|
||||||
|
private HashSet<string> activeMethodTags = new HashSet<string>();
|
||||||
|
private HashSet<string> selectedClassFilters = new HashSet<string>();
|
||||||
|
private HashSet<string> selectedMethodFilters = new HashSet<string>();
|
||||||
|
private HashSet<LogLevel> selectedLevelFilters = new HashSet<LogLevel>
|
||||||
|
{
|
||||||
|
LogLevel.Debug, LogLevel.Info, LogLevel.Warning, LogLevel.Error
|
||||||
|
};
|
||||||
|
private string searchText = "";
|
||||||
|
private bool autoScroll = true;
|
||||||
|
|
||||||
|
// Time range filtering
|
||||||
|
private bool enableTimeFilter = false;
|
||||||
|
private float minTimestamp = 0;
|
||||||
|
private float maxTimestamp = 0;
|
||||||
|
private float currentMaxTimestamp = 0;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region UI State
|
||||||
|
|
||||||
|
// Colors for log levels
|
||||||
|
private readonly Color debugColor = Color.white;
|
||||||
|
private readonly Color infoColor = Color.white;
|
||||||
|
private readonly Color warningColor = Color.yellow;
|
||||||
|
private readonly Color errorColor = new Color(1f, 0.3f, 0.3f);
|
||||||
|
|
||||||
|
// Alternating row background colors
|
||||||
|
private readonly Color evenRowColor = new Color(0.22f, 0.22f, 0.22f);
|
||||||
|
private readonly Color oddRowColor = new Color(0.26f, 0.26f, 0.26f);
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Menu Items
|
||||||
|
|
||||||
|
[MenuItem("AppleHills/Custom Log Console")]
|
||||||
|
public static void ShowWindow()
|
||||||
|
{
|
||||||
|
var window = GetWindow<CustomLogWindow>("Custom Log");
|
||||||
|
window.Show();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Unity Lifecycle
|
||||||
|
|
||||||
|
private void OnEnable()
|
||||||
|
{
|
||||||
|
// Subscribe to new log events
|
||||||
|
Logging.OnLogEntryAdded += OnLogAdded;
|
||||||
|
|
||||||
|
// Load existing logs
|
||||||
|
allLogs.AddRange(Logging.GetRecentLogs());
|
||||||
|
|
||||||
|
// Build initial tag lists
|
||||||
|
RebuildTagLists();
|
||||||
|
|
||||||
|
// Initialize time range
|
||||||
|
UpdateTimeRange();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnDisable()
|
||||||
|
{
|
||||||
|
Logging.OnLogEntryAdded -= OnLogAdded;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnLogAdded(LogEntry entry)
|
||||||
|
{
|
||||||
|
allLogs.Add(entry);
|
||||||
|
|
||||||
|
// Update active tags
|
||||||
|
activeClassTags.Add(entry.ClassName);
|
||||||
|
activeMethodTags.Add(entry.MethodName);
|
||||||
|
|
||||||
|
// Update time range
|
||||||
|
UpdateTimeRange();
|
||||||
|
|
||||||
|
if (autoScroll)
|
||||||
|
scrollPosition.y = float.MaxValue;
|
||||||
|
|
||||||
|
Repaint(); // Redraw window
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region GUI Drawing
|
||||||
|
|
||||||
|
private void OnGUI()
|
||||||
|
{
|
||||||
|
DrawToolbar();
|
||||||
|
DrawLogEntries();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DrawToolbar()
|
||||||
|
{
|
||||||
|
EditorGUILayout.BeginHorizontal(EditorStyles.toolbar);
|
||||||
|
|
||||||
|
// Clear button
|
||||||
|
if (GUILayout.Button("Clear", EditorStyles.toolbarButton, GUILayout.Width(50)))
|
||||||
|
{
|
||||||
|
allLogs.Clear();
|
||||||
|
activeClassTags.Clear();
|
||||||
|
activeMethodTags.Clear();
|
||||||
|
Logging.ClearLogs();
|
||||||
|
Repaint();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Auto-scroll toggle
|
||||||
|
autoScroll = GUILayout.Toggle(autoScroll, "Auto-scroll", EditorStyles.toolbarButton, GUILayout.Width(80));
|
||||||
|
|
||||||
|
GUILayout.Space(10);
|
||||||
|
|
||||||
|
// Class Filter Button
|
||||||
|
string classLabel = selectedClassFilters.Count == 0 ? "Classes: All" :
|
||||||
|
selectedClassFilters.Count == activeClassTags.Count ? "Classes: All" :
|
||||||
|
$"Classes: {selectedClassFilters.Count}";
|
||||||
|
if (GUILayout.Button(new GUIContent(classLabel, "Filter by class"), EditorStyles.toolbarDropDown, GUILayout.Width(100)))
|
||||||
|
{
|
||||||
|
ShowClassFilterMenu();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Method Filter Button
|
||||||
|
string methodLabel = selectedMethodFilters.Count == 0 ? "Methods: All" :
|
||||||
|
selectedMethodFilters.Count == activeMethodTags.Count ? "Methods: All" :
|
||||||
|
$"Methods: {selectedMethodFilters.Count}";
|
||||||
|
if (GUILayout.Button(new GUIContent(methodLabel, "Filter by method"), EditorStyles.toolbarDropDown, GUILayout.Width(110)))
|
||||||
|
{
|
||||||
|
ShowMethodFilterMenu();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Log Level Filter Button
|
||||||
|
string levelLabel = selectedLevelFilters.Count == 4 ? "Levels: All" :
|
||||||
|
selectedLevelFilters.Count == 0 ? "Levels: None" :
|
||||||
|
$"Levels: {selectedLevelFilters.Count}";
|
||||||
|
if (GUILayout.Button(new GUIContent(levelLabel, "Filter by log level"), EditorStyles.toolbarDropDown, GUILayout.Width(90)))
|
||||||
|
{
|
||||||
|
ShowLevelFilterMenu();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Time Range Filter Button
|
||||||
|
if (GUILayout.Button(new GUIContent("⏱", "Time range filter"), EditorStyles.toolbarButton, GUILayout.Width(25)))
|
||||||
|
{
|
||||||
|
ShowTimeRangeWindow();
|
||||||
|
}
|
||||||
|
|
||||||
|
GUILayout.FlexibleSpace();
|
||||||
|
|
||||||
|
// Search box
|
||||||
|
GUILayout.Label("Search:", GUILayout.Width(50));
|
||||||
|
searchText = GUILayout.TextField(searchText, EditorStyles.toolbarSearchField, GUILayout.Width(150));
|
||||||
|
|
||||||
|
GUILayout.Space(10);
|
||||||
|
|
||||||
|
// Export button
|
||||||
|
if (GUILayout.Button("Export", EditorStyles.toolbarButton, GUILayout.Width(60)))
|
||||||
|
{
|
||||||
|
ExportLogs();
|
||||||
|
}
|
||||||
|
|
||||||
|
GUILayout.Space(5);
|
||||||
|
|
||||||
|
// Log count
|
||||||
|
var filteredCount = GetFilteredLogs().Count();
|
||||||
|
GUILayout.Label($"{filteredCount}/{allLogs.Count}", GUILayout.Width(80));
|
||||||
|
|
||||||
|
EditorGUILayout.EndHorizontal();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ShowClassFilterMenu()
|
||||||
|
{
|
||||||
|
ClassFilterWindow.ShowWindow(this, activeClassTags, selectedClassFilters,
|
||||||
|
(newSelection) =>
|
||||||
|
{
|
||||||
|
selectedClassFilters = newSelection;
|
||||||
|
Repaint();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ShowMethodFilterMenu()
|
||||||
|
{
|
||||||
|
MethodFilterWindow.ShowWindow(this, activeMethodTags, selectedMethodFilters,
|
||||||
|
(newSelection) =>
|
||||||
|
{
|
||||||
|
selectedMethodFilters = newSelection;
|
||||||
|
Repaint();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ShowLevelFilterMenu()
|
||||||
|
{
|
||||||
|
LevelFilterWindow.ShowWindow(this, selectedLevelFilters,
|
||||||
|
(newSelection) =>
|
||||||
|
{
|
||||||
|
selectedLevelFilters = newSelection;
|
||||||
|
Repaint();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ShowTimeRangeWindow()
|
||||||
|
{
|
||||||
|
TimeRangeFilterWindow.ShowWindow(this, enableTimeFilter, minTimestamp, maxTimestamp, currentMaxTimestamp,
|
||||||
|
(enabled, min, max) =>
|
||||||
|
{
|
||||||
|
enableTimeFilter = enabled;
|
||||||
|
minTimestamp = min;
|
||||||
|
maxTimestamp = max;
|
||||||
|
Repaint();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DrawLogEntries()
|
||||||
|
{
|
||||||
|
// PERFORMANCE NOTE: For 10,000+ logs, consider virtualized scrolling here.
|
||||||
|
// Only render entries visible within the scroll view rect.
|
||||||
|
// Current implementation renders all filtered logs which may cause GUI slowdown.
|
||||||
|
|
||||||
|
scrollPosition = EditorGUILayout.BeginScrollView(scrollPosition);
|
||||||
|
|
||||||
|
var filteredLogs = GetFilteredLogs().ToList();
|
||||||
|
|
||||||
|
for (int i = 0; i < filteredLogs.Count; i++)
|
||||||
|
{
|
||||||
|
DrawLogEntry(filteredLogs[i], i);
|
||||||
|
}
|
||||||
|
|
||||||
|
EditorGUILayout.EndScrollView();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DrawLogEntry(LogEntry entry, int index)
|
||||||
|
{
|
||||||
|
// Draw alternating row background
|
||||||
|
Color bgColor = (index % 2 == 0) ? evenRowColor : oddRowColor;
|
||||||
|
Rect rowRect = EditorGUILayout.BeginHorizontal();
|
||||||
|
EditorGUI.DrawRect(rowRect, bgColor);
|
||||||
|
|
||||||
|
// Color-code by log level
|
||||||
|
Color color = GetColorForLevel(entry.Level);
|
||||||
|
var originalColor = GUI.contentColor;
|
||||||
|
GUI.contentColor = color;
|
||||||
|
|
||||||
|
// Timestamp
|
||||||
|
GUILayout.Label($"[{entry.Timestamp:F2}s]", GUILayout.Width(80));
|
||||||
|
|
||||||
|
// Level
|
||||||
|
GUILayout.Label($"[{entry.Level}]", GUILayout.Width(70));
|
||||||
|
|
||||||
|
// Class
|
||||||
|
GUILayout.Label($"[{entry.ClassName}]", GUILayout.Width(150));
|
||||||
|
|
||||||
|
// Method
|
||||||
|
GUILayout.Label($"[{entry.MethodName}]", GUILayout.Width(150));
|
||||||
|
|
||||||
|
// Message
|
||||||
|
GUILayout.Label(entry.Message, GUILayout.ExpandWidth(true));
|
||||||
|
|
||||||
|
EditorGUILayout.EndHorizontal();
|
||||||
|
|
||||||
|
GUI.contentColor = originalColor;
|
||||||
|
|
||||||
|
// Right-click context menu
|
||||||
|
if (Event.current.type == EventType.ContextClick && rowRect.Contains(Event.current.mousePosition))
|
||||||
|
{
|
||||||
|
GenericMenu menu = new GenericMenu();
|
||||||
|
|
||||||
|
menu.AddItem(new GUIContent("Copy Full Message"), false, () =>
|
||||||
|
{
|
||||||
|
EditorGUIUtility.systemCopyBuffer = entry.FullFormattedMessage;
|
||||||
|
});
|
||||||
|
|
||||||
|
menu.AddItem(new GUIContent("Copy Message Only"), false, () =>
|
||||||
|
{
|
||||||
|
EditorGUIUtility.systemCopyBuffer = entry.Message;
|
||||||
|
});
|
||||||
|
|
||||||
|
menu.AddSeparator("");
|
||||||
|
|
||||||
|
menu.AddItem(new GUIContent("Filter to this Class"), false, () =>
|
||||||
|
{
|
||||||
|
selectedClassFilters.Clear();
|
||||||
|
selectedClassFilters.Add(entry.ClassName);
|
||||||
|
Repaint();
|
||||||
|
});
|
||||||
|
|
||||||
|
menu.AddItem(new GUIContent("Filter to this Method"), false, () =>
|
||||||
|
{
|
||||||
|
selectedMethodFilters.Clear();
|
||||||
|
selectedMethodFilters.Add(entry.MethodName);
|
||||||
|
Repaint();
|
||||||
|
});
|
||||||
|
|
||||||
|
menu.AddItem(new GUIContent("Filter to this Class + Method"), false, () =>
|
||||||
|
{
|
||||||
|
selectedClassFilters.Clear();
|
||||||
|
selectedClassFilters.Add(entry.ClassName);
|
||||||
|
selectedMethodFilters.Clear();
|
||||||
|
selectedMethodFilters.Add(entry.MethodName);
|
||||||
|
Repaint();
|
||||||
|
});
|
||||||
|
|
||||||
|
menu.AddSeparator("");
|
||||||
|
|
||||||
|
menu.AddItem(new GUIContent("Filter to this Log Level"), false, () =>
|
||||||
|
{
|
||||||
|
selectedLevelFilters.Clear();
|
||||||
|
selectedLevelFilters.Add(entry.Level);
|
||||||
|
Repaint();
|
||||||
|
});
|
||||||
|
|
||||||
|
menu.ShowAsContext();
|
||||||
|
Event.current.Use();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Filtering Logic
|
||||||
|
|
||||||
|
private IEnumerable<LogEntry> GetFilteredLogs()
|
||||||
|
{
|
||||||
|
return allLogs.Where(entry =>
|
||||||
|
{
|
||||||
|
// Filter by class (if any selected)
|
||||||
|
if (selectedClassFilters.Count > 0 && !selectedClassFilters.Contains(entry.ClassName))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Filter by method (if any selected)
|
||||||
|
if (selectedMethodFilters.Count > 0 && !selectedMethodFilters.Contains(entry.MethodName))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Filter by log level
|
||||||
|
if (!selectedLevelFilters.Contains(entry.Level))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Filter by time range
|
||||||
|
if (enableTimeFilter)
|
||||||
|
{
|
||||||
|
if (entry.Timestamp < minTimestamp || entry.Timestamp > maxTimestamp)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Filter by search text
|
||||||
|
if (!string.IsNullOrEmpty(searchText))
|
||||||
|
{
|
||||||
|
bool matchesSearch =
|
||||||
|
entry.ClassName.Contains(searchText, StringComparison.OrdinalIgnoreCase) ||
|
||||||
|
entry.MethodName.Contains(searchText, StringComparison.OrdinalIgnoreCase) ||
|
||||||
|
entry.Message.Contains(searchText, StringComparison.OrdinalIgnoreCase);
|
||||||
|
|
||||||
|
if (!matchesSearch)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Helper Methods
|
||||||
|
|
||||||
|
private Color GetColorForLevel(LogLevel level)
|
||||||
|
{
|
||||||
|
return level switch
|
||||||
|
{
|
||||||
|
LogLevel.Debug => debugColor,
|
||||||
|
LogLevel.Info => infoColor,
|
||||||
|
LogLevel.Warning => warningColor,
|
||||||
|
LogLevel.Error => errorColor,
|
||||||
|
_ => infoColor
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RebuildTagLists()
|
||||||
|
{
|
||||||
|
activeClassTags.Clear();
|
||||||
|
activeMethodTags.Clear();
|
||||||
|
|
||||||
|
foreach (var log in allLogs)
|
||||||
|
{
|
||||||
|
activeClassTags.Add(log.ClassName);
|
||||||
|
activeMethodTags.Add(log.MethodName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateTimeRange()
|
||||||
|
{
|
||||||
|
if (allLogs.Count > 0)
|
||||||
|
{
|
||||||
|
currentMaxTimestamp = allLogs.Max(l => l.Timestamp);
|
||||||
|
|
||||||
|
// Initialize time range on first log
|
||||||
|
if (maxTimestamp == 0)
|
||||||
|
{
|
||||||
|
maxTimestamp = currentMaxTimestamp;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Auto-expand max range as new logs come in
|
||||||
|
maxTimestamp = currentMaxTimestamp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ExportLogs()
|
||||||
|
{
|
||||||
|
string defaultFileName = $"logs_{DateTime.Now:yyyy-MM-dd_HH-mm-ss}.txt";
|
||||||
|
string path = EditorUtility.SaveFilePanel("Export Logs", "", defaultFileName, "txt");
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(path))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var filteredLogs = GetFilteredLogs().ToList();
|
||||||
|
var lines = filteredLogs.Select(e => e.FullFormattedMessage);
|
||||||
|
File.WriteAllLines(path, lines);
|
||||||
|
|
||||||
|
EditorUtility.DisplayDialog("Export Successful",
|
||||||
|
$"Exported {filteredLogs.Count} log entries to:\n{path}", "OK");
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
EditorUtility.DisplayDialog("Export Failed",
|
||||||
|
$"Failed to export logs:\n{ex.Message}", "OK");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Persistent popup window for class filtering with multi-selection support
|
||||||
|
/// </summary>
|
||||||
|
public class ClassFilterWindow : EditorWindow
|
||||||
|
{
|
||||||
|
private HashSet<string> availableTags;
|
||||||
|
private HashSet<string> selectedTags;
|
||||||
|
private System.Action<HashSet<string>> onApply;
|
||||||
|
private Vector2 scrollPosition;
|
||||||
|
private string searchFilter = "";
|
||||||
|
|
||||||
|
public static void ShowWindow(CustomLogWindow parent, HashSet<string> available, HashSet<string> selected,
|
||||||
|
System.Action<HashSet<string>> applyCallback)
|
||||||
|
{
|
||||||
|
var window = CreateInstance<ClassFilterWindow>();
|
||||||
|
window.titleContent = new GUIContent("Class Filter");
|
||||||
|
window.availableTags = available;
|
||||||
|
window.selectedTags = new HashSet<string>(selected);
|
||||||
|
window.onApply = applyCallback;
|
||||||
|
|
||||||
|
var parentRect = parent.position;
|
||||||
|
window.position = new Rect(parentRect.x + 50, parentRect.y + 50, 300, 400);
|
||||||
|
window.ShowUtility();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnGUI()
|
||||||
|
{
|
||||||
|
EditorGUILayout.Space(5);
|
||||||
|
|
||||||
|
// Control buttons
|
||||||
|
EditorGUILayout.BeginHorizontal();
|
||||||
|
if (GUILayout.Button("All", GUILayout.Width(60)))
|
||||||
|
{
|
||||||
|
if (availableTags != null)
|
||||||
|
selectedTags = new HashSet<string>(availableTags);
|
||||||
|
}
|
||||||
|
if (GUILayout.Button("None", GUILayout.Width(60)))
|
||||||
|
{
|
||||||
|
selectedTags.Clear();
|
||||||
|
}
|
||||||
|
GUILayout.FlexibleSpace();
|
||||||
|
searchFilter = EditorGUILayout.TextField(searchFilter, EditorStyles.toolbarSearchField, GUILayout.Width(150));
|
||||||
|
EditorGUILayout.EndHorizontal();
|
||||||
|
|
||||||
|
EditorGUILayout.Space(5);
|
||||||
|
|
||||||
|
// Scrollable list of toggles
|
||||||
|
scrollPosition = EditorGUILayout.BeginScrollView(scrollPosition);
|
||||||
|
|
||||||
|
if (availableTags != null && availableTags.Count > 0)
|
||||||
|
{
|
||||||
|
var filteredTags = string.IsNullOrEmpty(searchFilter)
|
||||||
|
? availableTags.OrderBy(t => t)
|
||||||
|
: availableTags.Where(t => t.Contains(searchFilter, StringComparison.OrdinalIgnoreCase)).OrderBy(t => t);
|
||||||
|
|
||||||
|
foreach (var tag in filteredTags)
|
||||||
|
{
|
||||||
|
bool isSelected = selectedTags.Contains(tag);
|
||||||
|
bool newSelection = EditorGUILayout.ToggleLeft(tag, isSelected);
|
||||||
|
|
||||||
|
if (newSelection != isSelected)
|
||||||
|
{
|
||||||
|
if (newSelection)
|
||||||
|
selectedTags.Add(tag);
|
||||||
|
else
|
||||||
|
selectedTags.Remove(tag);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
EditorGUILayout.HelpBox("No classes available", MessageType.Info);
|
||||||
|
}
|
||||||
|
|
||||||
|
EditorGUILayout.EndScrollView();
|
||||||
|
|
||||||
|
EditorGUILayout.Space(5);
|
||||||
|
|
||||||
|
// Apply/Close buttons
|
||||||
|
EditorGUILayout.BeginHorizontal();
|
||||||
|
GUILayout.FlexibleSpace();
|
||||||
|
|
||||||
|
if (GUILayout.Button("Apply", GUILayout.Width(80)))
|
||||||
|
{
|
||||||
|
onApply?.Invoke(selectedTags);
|
||||||
|
Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GUILayout.Button("Close", GUILayout.Width(80)))
|
||||||
|
{
|
||||||
|
Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
GUILayout.FlexibleSpace();
|
||||||
|
EditorGUILayout.EndHorizontal();
|
||||||
|
|
||||||
|
EditorGUILayout.Space(5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Persistent popup window for method filtering with multi-selection support
|
||||||
|
/// </summary>
|
||||||
|
public class MethodFilterWindow : EditorWindow
|
||||||
|
{
|
||||||
|
private HashSet<string> availableTags;
|
||||||
|
private HashSet<string> selectedTags;
|
||||||
|
private System.Action<HashSet<string>> onApply;
|
||||||
|
private Vector2 scrollPosition;
|
||||||
|
private string searchFilter = "";
|
||||||
|
|
||||||
|
public static void ShowWindow(CustomLogWindow parent, HashSet<string> available, HashSet<string> selected,
|
||||||
|
System.Action<HashSet<string>> applyCallback)
|
||||||
|
{
|
||||||
|
var window = CreateInstance<MethodFilterWindow>();
|
||||||
|
window.titleContent = new GUIContent("Method Filter");
|
||||||
|
window.availableTags = available;
|
||||||
|
window.selectedTags = new HashSet<string>(selected);
|
||||||
|
window.onApply = applyCallback;
|
||||||
|
|
||||||
|
var parentRect = parent.position;
|
||||||
|
window.position = new Rect(parentRect.x + 50, parentRect.y + 50, 300, 400);
|
||||||
|
window.ShowUtility();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnGUI()
|
||||||
|
{
|
||||||
|
EditorGUILayout.Space(5);
|
||||||
|
|
||||||
|
// Control buttons
|
||||||
|
EditorGUILayout.BeginHorizontal();
|
||||||
|
if (GUILayout.Button("All", GUILayout.Width(60)))
|
||||||
|
{
|
||||||
|
if (availableTags != null)
|
||||||
|
selectedTags = new HashSet<string>(availableTags);
|
||||||
|
}
|
||||||
|
if (GUILayout.Button("None", GUILayout.Width(60)))
|
||||||
|
{
|
||||||
|
selectedTags.Clear();
|
||||||
|
}
|
||||||
|
GUILayout.FlexibleSpace();
|
||||||
|
searchFilter = EditorGUILayout.TextField(searchFilter, EditorStyles.toolbarSearchField, GUILayout.Width(150));
|
||||||
|
EditorGUILayout.EndHorizontal();
|
||||||
|
|
||||||
|
EditorGUILayout.Space(5);
|
||||||
|
|
||||||
|
// Scrollable list of toggles
|
||||||
|
scrollPosition = EditorGUILayout.BeginScrollView(scrollPosition);
|
||||||
|
|
||||||
|
if (availableTags != null && availableTags.Count > 0)
|
||||||
|
{
|
||||||
|
var filteredTags = string.IsNullOrEmpty(searchFilter)
|
||||||
|
? availableTags.OrderBy(t => t)
|
||||||
|
: availableTags.Where(t => t.Contains(searchFilter, StringComparison.OrdinalIgnoreCase)).OrderBy(t => t);
|
||||||
|
|
||||||
|
foreach (var tag in filteredTags)
|
||||||
|
{
|
||||||
|
bool isSelected = selectedTags.Contains(tag);
|
||||||
|
bool newSelection = EditorGUILayout.ToggleLeft(tag, isSelected);
|
||||||
|
|
||||||
|
if (newSelection != isSelected)
|
||||||
|
{
|
||||||
|
if (newSelection)
|
||||||
|
selectedTags.Add(tag);
|
||||||
|
else
|
||||||
|
selectedTags.Remove(tag);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
EditorGUILayout.HelpBox("No methods available", MessageType.Info);
|
||||||
|
}
|
||||||
|
|
||||||
|
EditorGUILayout.EndScrollView();
|
||||||
|
|
||||||
|
EditorGUILayout.Space(5);
|
||||||
|
|
||||||
|
// Apply/Close buttons
|
||||||
|
EditorGUILayout.BeginHorizontal();
|
||||||
|
GUILayout.FlexibleSpace();
|
||||||
|
|
||||||
|
if (GUILayout.Button("Apply", GUILayout.Width(80)))
|
||||||
|
{
|
||||||
|
onApply?.Invoke(selectedTags);
|
||||||
|
Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GUILayout.Button("Close", GUILayout.Width(80)))
|
||||||
|
{
|
||||||
|
Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
GUILayout.FlexibleSpace();
|
||||||
|
EditorGUILayout.EndHorizontal();
|
||||||
|
|
||||||
|
EditorGUILayout.Space(5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Persistent popup window for log level filtering with multi-selection support
|
||||||
|
/// </summary>
|
||||||
|
public class LevelFilterWindow : EditorWindow
|
||||||
|
{
|
||||||
|
private HashSet<LogLevel> selectedLevels;
|
||||||
|
private System.Action<HashSet<LogLevel>> onApply;
|
||||||
|
|
||||||
|
public static void ShowWindow(CustomLogWindow parent, HashSet<LogLevel> selected,
|
||||||
|
System.Action<HashSet<LogLevel>> applyCallback)
|
||||||
|
{
|
||||||
|
var window = CreateInstance<LevelFilterWindow>();
|
||||||
|
window.titleContent = new GUIContent("Log Level Filter");
|
||||||
|
window.selectedLevels = new HashSet<LogLevel>(selected);
|
||||||
|
window.onApply = applyCallback;
|
||||||
|
|
||||||
|
var parentRect = parent.position;
|
||||||
|
window.position = new Rect(parentRect.x + 50, parentRect.y + 50, 250, 180);
|
||||||
|
window.ShowUtility();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnGUI()
|
||||||
|
{
|
||||||
|
EditorGUILayout.Space(5);
|
||||||
|
|
||||||
|
// Control buttons
|
||||||
|
EditorGUILayout.BeginHorizontal();
|
||||||
|
if (GUILayout.Button("All", GUILayout.Width(60)))
|
||||||
|
{
|
||||||
|
selectedLevels = new HashSet<LogLevel>
|
||||||
|
{
|
||||||
|
LogLevel.Debug, LogLevel.Info, LogLevel.Warning, LogLevel.Error
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (GUILayout.Button("None", GUILayout.Width(60)))
|
||||||
|
{
|
||||||
|
selectedLevels.Clear();
|
||||||
|
}
|
||||||
|
EditorGUILayout.EndHorizontal();
|
||||||
|
|
||||||
|
EditorGUILayout.Space(10);
|
||||||
|
|
||||||
|
// Log level toggles
|
||||||
|
foreach (LogLevel level in Enum.GetValues(typeof(LogLevel)))
|
||||||
|
{
|
||||||
|
bool isSelected = selectedLevels.Contains(level);
|
||||||
|
bool newSelection = EditorGUILayout.ToggleLeft(level.ToString(), isSelected);
|
||||||
|
|
||||||
|
if (newSelection != isSelected)
|
||||||
|
{
|
||||||
|
if (newSelection)
|
||||||
|
selectedLevels.Add(level);
|
||||||
|
else
|
||||||
|
selectedLevels.Remove(level);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
EditorGUILayout.Space(10);
|
||||||
|
|
||||||
|
// Apply/Close buttons
|
||||||
|
EditorGUILayout.BeginHorizontal();
|
||||||
|
GUILayout.FlexibleSpace();
|
||||||
|
|
||||||
|
if (GUILayout.Button("Apply", GUILayout.Width(80)))
|
||||||
|
{
|
||||||
|
onApply?.Invoke(selectedLevels);
|
||||||
|
Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GUILayout.Button("Close", GUILayout.Width(80)))
|
||||||
|
{
|
||||||
|
Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
GUILayout.FlexibleSpace();
|
||||||
|
EditorGUILayout.EndHorizontal();
|
||||||
|
|
||||||
|
EditorGUILayout.Space(5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Popup window for configuring time range filters
|
||||||
|
/// </summary>
|
||||||
|
public class TimeRangeFilterWindow : EditorWindow
|
||||||
|
{
|
||||||
|
private bool enableTimeFilter;
|
||||||
|
private float minTimestamp;
|
||||||
|
private float maxTimestamp;
|
||||||
|
private float currentMaxTimestamp;
|
||||||
|
private System.Action<bool, float, float> onApply;
|
||||||
|
|
||||||
|
public static void ShowWindow(CustomLogWindow parent, bool enabled, float min, float max, float currentMax,
|
||||||
|
System.Action<bool, float, float> applyCallback)
|
||||||
|
{
|
||||||
|
var window = CreateInstance<TimeRangeFilterWindow>();
|
||||||
|
window.titleContent = new GUIContent("Time Range Filter");
|
||||||
|
window.enableTimeFilter = enabled;
|
||||||
|
window.minTimestamp = min;
|
||||||
|
window.maxTimestamp = max;
|
||||||
|
window.currentMaxTimestamp = currentMax;
|
||||||
|
window.onApply = applyCallback;
|
||||||
|
|
||||||
|
// Position near the parent window
|
||||||
|
var parentRect = parent.position;
|
||||||
|
window.position = new Rect(parentRect.x + 100, parentRect.y + 100, 350, 120);
|
||||||
|
|
||||||
|
window.ShowUtility();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnGUI()
|
||||||
|
{
|
||||||
|
EditorGUILayout.Space(10);
|
||||||
|
|
||||||
|
enableTimeFilter = EditorGUILayout.Toggle("Enable Time Filter", enableTimeFilter);
|
||||||
|
|
||||||
|
EditorGUILayout.Space(5);
|
||||||
|
|
||||||
|
if (enableTimeFilter && currentMaxTimestamp > 0)
|
||||||
|
{
|
||||||
|
EditorGUILayout.BeginHorizontal();
|
||||||
|
EditorGUILayout.LabelField($"Min: {minTimestamp:F2}s", GUILayout.Width(100));
|
||||||
|
EditorGUILayout.LabelField($"Max: {maxTimestamp:F2}s", GUILayout.Width(100));
|
||||||
|
EditorGUILayout.EndHorizontal();
|
||||||
|
|
||||||
|
EditorGUILayout.MinMaxSlider(
|
||||||
|
ref minTimestamp,
|
||||||
|
ref maxTimestamp,
|
||||||
|
0,
|
||||||
|
currentMaxTimestamp);
|
||||||
|
|
||||||
|
EditorGUILayout.Space(5);
|
||||||
|
|
||||||
|
EditorGUILayout.BeginHorizontal();
|
||||||
|
if (GUILayout.Button("Reset Range"))
|
||||||
|
{
|
||||||
|
minTimestamp = 0;
|
||||||
|
maxTimestamp = currentMaxTimestamp;
|
||||||
|
}
|
||||||
|
EditorGUILayout.EndHorizontal();
|
||||||
|
}
|
||||||
|
else if (enableTimeFilter)
|
||||||
|
{
|
||||||
|
EditorGUILayout.HelpBox("No logs available for time filtering", MessageType.Info);
|
||||||
|
}
|
||||||
|
|
||||||
|
EditorGUILayout.Space(10);
|
||||||
|
|
||||||
|
EditorGUILayout.BeginHorizontal();
|
||||||
|
GUILayout.FlexibleSpace();
|
||||||
|
|
||||||
|
if (GUILayout.Button("Apply", GUILayout.Width(80)))
|
||||||
|
{
|
||||||
|
onApply?.Invoke(enableTimeFilter, minTimestamp, maxTimestamp);
|
||||||
|
Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GUILayout.Button("Cancel", GUILayout.Width(80)))
|
||||||
|
{
|
||||||
|
Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
GUILayout.FlexibleSpace();
|
||||||
|
EditorGUILayout.EndHorizontal();
|
||||||
|
|
||||||
|
EditorGUILayout.Space(10);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
3
Assets/Editor/CustomLogWindow.cs.meta
Normal file
3
Assets/Editor/CustomLogWindow.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 60a300585fef4ac990c963c8b37c3887
|
||||||
|
timeCreated: 1762814971
|
||||||
@@ -181,7 +181,7 @@ namespace Editor
|
|||||||
string scenePath = AssetDatabase.GUIDToAssetPath(guid);
|
string scenePath = AssetDatabase.GUIDToAssetPath(guid);
|
||||||
var scene = EditorSceneManager.OpenScene(scenePath, OpenSceneMode.Additive);
|
var scene = EditorSceneManager.OpenScene(scenePath, OpenSceneMode.Additive);
|
||||||
|
|
||||||
var allComponents = GameObject.FindObjectsOfType<Component>(true);
|
var allComponents = GameObject.FindObjectsByType<Component>(FindObjectsInactive.Include, FindObjectsSortMode.None);
|
||||||
foreach (var component in allComponents)
|
foreach (var component in allComponents)
|
||||||
{
|
{
|
||||||
if (component == null || component.gameObject.scene != scene) continue;
|
if (component == null || component.gameObject.scene != scene) continue;
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ namespace Editor.Lifecycle
|
|||||||
/// Editor-only bootstrap that ensures OnSceneReady is triggered when playing directly from a scene in Unity Editor.
|
/// Editor-only bootstrap that ensures OnSceneReady is triggered when playing directly from a scene in Unity Editor.
|
||||||
///
|
///
|
||||||
/// PROBLEM: When you press Play in the editor without going through the scene manager:
|
/// PROBLEM: When you press Play in the editor without going through the scene manager:
|
||||||
/// - CustomBoot runs and triggers OnBootCompletionTriggered (which broadcasts OnManagedAwake)
|
/// - CustomBoot runs and triggers OnBootCompletionTriggered (which broadcasts OnManagedStart)
|
||||||
/// - But BroadcastSceneReady is NEVER called for the initial scene
|
/// - But BroadcastSceneReady is NEVER called for the initial scene
|
||||||
/// - Components in the scene never receive their OnSceneReady() callback
|
/// - Components in the scene never receive their OnSceneReady() callback
|
||||||
///
|
///
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
using UnityEditor;
|
using UnityEditor;
|
||||||
using AppleHills.Core.Settings;
|
using AppleHills.Core.Settings;
|
||||||
using Core;
|
using Core;
|
||||||
using UnityEngine;
|
|
||||||
using UnityEngine.Rendering.VirtualTexturing;
|
|
||||||
|
|
||||||
namespace AppleHills.Editor
|
namespace AppleHills.Editor
|
||||||
{
|
{
|
||||||
@@ -65,7 +63,7 @@ namespace AppleHills.Editor
|
|||||||
GetPuzzlePromptRange
|
GetPuzzlePromptRange
|
||||||
);
|
);
|
||||||
|
|
||||||
LogDebugMessage("Editor settings loaded for Scene View use");
|
Logging.Debug("Editor settings loaded for Scene View use");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void RefreshSceneViews()
|
public static void RefreshSceneViews()
|
||||||
@@ -102,14 +100,5 @@ namespace AppleHills.Editor
|
|||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void LogDebugMessage(string message)
|
|
||||||
{
|
|
||||||
if (Application.isPlaying &&
|
|
||||||
DeveloperSettingsProvider.Instance.GetSettings<DebugSettings>().settingsLogVerbosity <= LogVerbosity.Debug)
|
|
||||||
{
|
|
||||||
Logging.Debug($"[EditorSettingsProvider] {message}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,153 +0,0 @@
|
|||||||
using Interactions;
|
|
||||||
using PuzzleS;
|
|
||||||
using UnityEditor;
|
|
||||||
using UnityEngine;
|
|
||||||
|
|
||||||
namespace Editor
|
|
||||||
{
|
|
||||||
public class ItemPrefabEditorWindow : EditorWindow
|
|
||||||
{
|
|
||||||
private GameObject _selectedGameObject;
|
|
||||||
private InteractableBase _interactable;
|
|
||||||
private PickupItemData _pickupData;
|
|
||||||
private PuzzleStepSO _objectiveData;
|
|
||||||
private UnityEditor.Editor _soEditor;
|
|
||||||
private string _pickupSoFolderPath = "Assets/Data/Items";
|
|
||||||
private string _puzzleSoFolderPath = "Assets/Data/Puzzles";
|
|
||||||
|
|
||||||
private enum ItemType { None, Pickup, ItemSlot }
|
|
||||||
private ItemType _itemType = ItemType.None;
|
|
||||||
|
|
||||||
[MenuItem("AppleHills/Item Prefab Editor")]
|
|
||||||
public static void ShowWindow()
|
|
||||||
{
|
|
||||||
var window = GetWindow<ItemPrefabEditorWindow>("Item Prefab Editor");
|
|
||||||
window.minSize = new Vector2(400, 400);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnEnable()
|
|
||||||
{
|
|
||||||
Selection.selectionChanged += Repaint;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnDisable()
|
|
||||||
{
|
|
||||||
Selection.selectionChanged -= Repaint;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnGUI()
|
|
||||||
{
|
|
||||||
_selectedGameObject = null;
|
|
||||||
_interactable = null;
|
|
||||||
if (Selection.activeGameObject != null)
|
|
||||||
{
|
|
||||||
_selectedGameObject = Selection.activeGameObject;
|
|
||||||
_interactable = _selectedGameObject.GetComponent<InteractableBase>();
|
|
||||||
}
|
|
||||||
else if (Selection.activeObject is GameObject go)
|
|
||||||
{
|
|
||||||
_selectedGameObject = go;
|
|
||||||
_interactable = go.GetComponent<InteractableBase>();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_selectedGameObject == null || _interactable == null)
|
|
||||||
{
|
|
||||||
EditorGUILayout.HelpBox("Select a GameObject or prefab with an InteractableBase component to edit.", MessageType.Info);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
EditorGUILayout.LabelField("Editing: ", _selectedGameObject.name, EditorStyles.boldLabel);
|
|
||||||
EditorGUILayout.Space();
|
|
||||||
|
|
||||||
// Determine current type
|
|
||||||
bool hasPickup = _selectedGameObject.GetComponent<Pickup>() != null;
|
|
||||||
bool hasSlot = _selectedGameObject.GetComponent<ItemSlot>() != null;
|
|
||||||
if (hasSlot) _itemType = ItemType.ItemSlot;
|
|
||||||
else if (hasPickup) _itemType = ItemType.Pickup;
|
|
||||||
else _itemType = ItemType.None;
|
|
||||||
|
|
||||||
// Item type selection
|
|
||||||
var newType = (ItemType)EditorGUILayout.EnumPopup("Item Type", _itemType);
|
|
||||||
if (newType != _itemType)
|
|
||||||
{
|
|
||||||
// Remove both, then add selected
|
|
||||||
PrefabEditorUtility.RemoveComponent<Pickup>(_selectedGameObject);
|
|
||||||
PrefabEditorUtility.RemoveComponent<ItemSlot>(_selectedGameObject);
|
|
||||||
if (newType == ItemType.Pickup)
|
|
||||||
PrefabEditorUtility.AddOrGetComponent<Pickup>(_selectedGameObject);
|
|
||||||
else if (newType == ItemType.ItemSlot)
|
|
||||||
PrefabEditorUtility.AddOrGetComponent<ItemSlot>(_selectedGameObject);
|
|
||||||
_itemType = newType;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ObjectiveStepBehaviour
|
|
||||||
bool hasObjective = _selectedGameObject.GetComponent<ObjectiveStepBehaviour>() != null;
|
|
||||||
bool addObjective = EditorGUILayout.Toggle("ObjectiveStepBehaviour", hasObjective);
|
|
||||||
if (addObjective && !hasObjective)
|
|
||||||
{
|
|
||||||
PrefabEditorUtility.AddOrGetComponent<ObjectiveStepBehaviour>(_selectedGameObject);
|
|
||||||
}
|
|
||||||
else if (!addObjective && hasObjective)
|
|
||||||
{
|
|
||||||
PrefabEditorUtility.RemoveComponent<ObjectiveStepBehaviour>(_selectedGameObject);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Pickup Data (for Pickup or ItemSlot)
|
|
||||||
if (_itemType == ItemType.Pickup || _itemType == ItemType.ItemSlot)
|
|
||||||
{
|
|
||||||
var pickup = _selectedGameObject.GetComponent<Pickup>();
|
|
||||||
_pickupData = pickup.itemData;
|
|
||||||
EditorGUILayout.LabelField("Pickup Data:", EditorStyles.boldLabel);
|
|
||||||
_pickupData = (PickupItemData)EditorGUILayout.ObjectField("PickupItemData", _pickupData, typeof(PickupItemData), false);
|
|
||||||
EditorGUILayout.BeginHorizontal();
|
|
||||||
EditorGUILayout.PrefixLabel("Save To");
|
|
||||||
EditorGUILayout.SelectableLabel(_pickupSoFolderPath, EditorStyles.textField, GUILayout.Height(EditorGUIUtility.singleLineHeight));
|
|
||||||
if (GUILayout.Button("Select...", GUILayout.Width(80)))
|
|
||||||
{
|
|
||||||
_pickupSoFolderPath = PrefabEditorUtility.SelectFolder(_pickupSoFolderPath, "Data/Items");
|
|
||||||
}
|
|
||||||
EditorGUILayout.EndHorizontal();
|
|
||||||
if (_pickupData == null && GUILayout.Button("Create New PickupItemData"))
|
|
||||||
{
|
|
||||||
_pickupData = PrefabEditorUtility.CreateScriptableAsset<PickupItemData>(_selectedGameObject.name + "_pickup", _pickupSoFolderPath);
|
|
||||||
}
|
|
||||||
if (_pickupData != null)
|
|
||||||
{
|
|
||||||
PrefabEditorUtility.DrawScriptableObjectEditor(ref _soEditor, _pickupData);
|
|
||||||
pickup.itemData = _pickupData;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Objective Data
|
|
||||||
if (addObjective)
|
|
||||||
{
|
|
||||||
var obj = _selectedGameObject.GetComponent<ObjectiveStepBehaviour>();
|
|
||||||
_objectiveData = obj.stepData;
|
|
||||||
EditorGUILayout.LabelField("Objective Data:", EditorStyles.boldLabel);
|
|
||||||
_objectiveData = (PuzzleStepSO)EditorGUILayout.ObjectField("PuzzleStepSO", _objectiveData, typeof(PuzzleStepSO), false);
|
|
||||||
EditorGUILayout.BeginHorizontal();
|
|
||||||
EditorGUILayout.PrefixLabel("Save To");
|
|
||||||
EditorGUILayout.SelectableLabel(_puzzleSoFolderPath, EditorStyles.textField, GUILayout.Height(EditorGUIUtility.singleLineHeight));
|
|
||||||
if (GUILayout.Button("Select...", GUILayout.Width(80)))
|
|
||||||
{
|
|
||||||
_puzzleSoFolderPath = PrefabEditorUtility.SelectFolder(_puzzleSoFolderPath, "Data/Puzzles");
|
|
||||||
}
|
|
||||||
EditorGUILayout.EndHorizontal();
|
|
||||||
if (_objectiveData == null && GUILayout.Button("Create New PuzzleStepSO"))
|
|
||||||
{
|
|
||||||
_objectiveData = PrefabEditorUtility.CreateScriptableAsset<PuzzleStepSO>(_selectedGameObject.name + "_puzzle", _puzzleSoFolderPath);
|
|
||||||
}
|
|
||||||
if (_objectiveData != null)
|
|
||||||
{
|
|
||||||
PrefabEditorUtility.DrawScriptableObjectEditor(ref _soEditor, _objectiveData);
|
|
||||||
obj.stepData = _objectiveData;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (GUI.changed)
|
|
||||||
{
|
|
||||||
EditorUtility.SetDirty(_selectedGameObject);
|
|
||||||
PrefabUtility.RecordPrefabInstancePropertyModifications(_selectedGameObject);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 943b203cde5343c68a6278c111fce2ed
|
|
||||||
timeCreated: 1757508162
|
|
||||||
@@ -1,168 +0,0 @@
|
|||||||
using UnityEditor;
|
|
||||||
using UnityEngine;
|
|
||||||
using System.IO;
|
|
||||||
using Interactions;
|
|
||||||
using PuzzleS;
|
|
||||||
|
|
||||||
namespace Editor
|
|
||||||
{
|
|
||||||
public class PrefabCreatorWindow : EditorWindow
|
|
||||||
{
|
|
||||||
private string _prefabName = "NewPrefab";
|
|
||||||
private string _saveFolderPath = "Assets/Prefabs/Items";
|
|
||||||
private string _pickupSoFolderPath = "Assets/Data/Items";
|
|
||||||
private string _puzzleSoFolderPath = "Assets/Data/Puzzles";
|
|
||||||
private bool _addObjective;
|
|
||||||
|
|
||||||
private PickupItemData _pickupData;
|
|
||||||
private PuzzleStepSO _objectiveData;
|
|
||||||
private UnityEditor.Editor _soEditor;
|
|
||||||
|
|
||||||
private enum ItemType { None, Pickup, ItemSlot }
|
|
||||||
private ItemType _itemType = ItemType.None;
|
|
||||||
|
|
||||||
private bool _createNext = false;
|
|
||||||
|
|
||||||
[MenuItem("AppleHills/Item Prefab Creator")]
|
|
||||||
public static void ShowWindow()
|
|
||||||
{
|
|
||||||
var window = GetWindow<PrefabCreatorWindow>("Prefab Creator");
|
|
||||||
window.minSize = new Vector2(400, 400);
|
|
||||||
// Set default paths if not already set
|
|
||||||
if (string.IsNullOrEmpty(window._saveFolderPath))
|
|
||||||
window._saveFolderPath = "Assets/Prefabs/Items";
|
|
||||||
if (string.IsNullOrEmpty(window._pickupSoFolderPath))
|
|
||||||
window._pickupSoFolderPath = "Assets/Data/Items";
|
|
||||||
if (string.IsNullOrEmpty(window._puzzleSoFolderPath))
|
|
||||||
window._puzzleSoFolderPath = "Assets/Data/Puzzles";
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnGUI()
|
|
||||||
{
|
|
||||||
EditorGUILayout.LabelField("Prefab Creator", EditorStyles.boldLabel);
|
|
||||||
_prefabName = EditorGUILayout.TextField("Prefab Name", _prefabName);
|
|
||||||
// Prefab save folder
|
|
||||||
EditorGUILayout.BeginHorizontal();
|
|
||||||
EditorGUILayout.PrefixLabel("Save Folder");
|
|
||||||
EditorGUILayout.SelectableLabel(_saveFolderPath, EditorStyles.textField, GUILayout.Height(EditorGUIUtility.singleLineHeight));
|
|
||||||
if (GUILayout.Button("Select...", GUILayout.Width(80)))
|
|
||||||
{
|
|
||||||
_saveFolderPath = PrefabEditorUtility.SelectFolder(_saveFolderPath, "Prefabs/Items");
|
|
||||||
}
|
|
||||||
EditorGUILayout.EndHorizontal();
|
|
||||||
EditorGUILayout.Space();
|
|
||||||
EditorGUILayout.LabelField("Add Components:", EditorStyles.boldLabel);
|
|
||||||
|
|
||||||
// Item type selection
|
|
||||||
var newType = (ItemType)EditorGUILayout.EnumPopup("Item Type", _itemType);
|
|
||||||
if (newType != _itemType)
|
|
||||||
{
|
|
||||||
_itemType = newType;
|
|
||||||
}
|
|
||||||
bool addObjective = EditorGUILayout.Toggle("ObjectiveStepBehaviour", _addObjective);
|
|
||||||
_addObjective = addObjective;
|
|
||||||
EditorGUILayout.Space();
|
|
||||||
|
|
||||||
// Pickup Data (for Pickup or ItemSlot)
|
|
||||||
if (_itemType == ItemType.Pickup || _itemType == ItemType.ItemSlot)
|
|
||||||
{
|
|
||||||
EditorGUILayout.LabelField("Pickup Data:", EditorStyles.boldLabel);
|
|
||||||
_pickupData = (PickupItemData)EditorGUILayout.ObjectField("PickupItemData", _pickupData, typeof(PickupItemData), false);
|
|
||||||
// Pickup SO save folder
|
|
||||||
EditorGUILayout.BeginHorizontal();
|
|
||||||
EditorGUILayout.PrefixLabel("Save To");
|
|
||||||
EditorGUILayout.SelectableLabel(_pickupSoFolderPath, EditorStyles.textField, GUILayout.Height(EditorGUIUtility.singleLineHeight));
|
|
||||||
if (GUILayout.Button("Select...", GUILayout.Width(80)))
|
|
||||||
{
|
|
||||||
_pickupSoFolderPath = PrefabEditorUtility.SelectFolder(_pickupSoFolderPath, "Data/Items");
|
|
||||||
}
|
|
||||||
EditorGUILayout.EndHorizontal();
|
|
||||||
if (_pickupData == null && GUILayout.Button("Create New PickupItemData"))
|
|
||||||
{
|
|
||||||
_pickupData = PrefabEditorUtility.CreateScriptableAsset<PickupItemData>(_prefabName + "_pickup", _pickupSoFolderPath);
|
|
||||||
}
|
|
||||||
if (_pickupData != null)
|
|
||||||
{
|
|
||||||
PrefabEditorUtility.DrawScriptableObjectEditor(ref _soEditor, _pickupData);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Objective Data
|
|
||||||
if (_addObjective)
|
|
||||||
{
|
|
||||||
EditorGUILayout.LabelField("Objective Data:", EditorStyles.boldLabel);
|
|
||||||
_objectiveData = (PuzzleStepSO)EditorGUILayout.ObjectField("PuzzleStepSO", _objectiveData, typeof(PuzzleStepSO), false);
|
|
||||||
// Puzzle SO save folder
|
|
||||||
EditorGUILayout.BeginHorizontal();
|
|
||||||
EditorGUILayout.PrefixLabel("Save To");
|
|
||||||
EditorGUILayout.SelectableLabel(_puzzleSoFolderPath, EditorStyles.textField, GUILayout.Height(EditorGUIUtility.singleLineHeight));
|
|
||||||
if (GUILayout.Button("Select...", GUILayout.Width(80)))
|
|
||||||
{
|
|
||||||
_puzzleSoFolderPath = PrefabEditorUtility.SelectFolder(_puzzleSoFolderPath, "Data/Puzzles");
|
|
||||||
}
|
|
||||||
EditorGUILayout.EndHorizontal();
|
|
||||||
if (_objectiveData == null && GUILayout.Button("Create New PuzzleStepSO"))
|
|
||||||
{
|
|
||||||
_objectiveData = PrefabEditorUtility.CreateScriptableAsset<PuzzleStepSO>(_prefabName + "_puzzle", _puzzleSoFolderPath);
|
|
||||||
}
|
|
||||||
if (_objectiveData != null)
|
|
||||||
{
|
|
||||||
PrefabEditorUtility.DrawScriptableObjectEditor(ref _soEditor, _objectiveData);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
GUILayout.FlexibleSpace();
|
|
||||||
EditorGUILayout.BeginHorizontal();
|
|
||||||
GUI.enabled = !string.IsNullOrEmpty(_prefabName) && !string.IsNullOrEmpty(_saveFolderPath);
|
|
||||||
if (GUILayout.Button("Create Prefab", GUILayout.Height(28)))
|
|
||||||
{
|
|
||||||
CreatePrefab();
|
|
||||||
}
|
|
||||||
_createNext = GUILayout.Toggle(_createNext, "Create Next", GUILayout.Width(100), GUILayout.Height(28));
|
|
||||||
GUI.enabled = true;
|
|
||||||
EditorGUILayout.EndHorizontal();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void CreatePrefab()
|
|
||||||
{
|
|
||||||
var go = new GameObject(_prefabName);
|
|
||||||
// Note: No need to add InteractableBase separately - Pickup and ItemSlot inherit from it
|
|
||||||
go.AddComponent<BoxCollider>();
|
|
||||||
int interactableLayer = LayerMask.NameToLayer("Interactable");
|
|
||||||
if (interactableLayer != -1)
|
|
||||||
go.layer = interactableLayer;
|
|
||||||
go.AddComponent<SpriteRenderer>();
|
|
||||||
if (_itemType == ItemType.Pickup)
|
|
||||||
{
|
|
||||||
var pickup = go.AddComponent<Pickup>();
|
|
||||||
pickup.itemData = _pickupData;
|
|
||||||
}
|
|
||||||
else if (_itemType == ItemType.ItemSlot)
|
|
||||||
{
|
|
||||||
var slot = go.AddComponent<ItemSlot>();
|
|
||||||
slot.itemData = _pickupData;
|
|
||||||
}
|
|
||||||
if (_addObjective)
|
|
||||||
{
|
|
||||||
var obj = go.AddComponent<ObjectiveStepBehaviour>();
|
|
||||||
obj.stepData = _objectiveData;
|
|
||||||
}
|
|
||||||
string prefabPath = Path.Combine(_saveFolderPath, _prefabName + ".prefab").Replace("\\", "/");
|
|
||||||
var prefab = PrefabUtility.SaveAsPrefabAsset(go, prefabPath);
|
|
||||||
DestroyImmediate(go);
|
|
||||||
AssetDatabase.Refresh();
|
|
||||||
Selection.activeObject = prefab;
|
|
||||||
EditorGUIUtility.PingObject(prefab);
|
|
||||||
EditorUtility.DisplayDialog("Prefab Created", $"Prefab saved to {prefabPath}", "OK");
|
|
||||||
if (_createNext)
|
|
||||||
{
|
|
||||||
_prefabName = "NewPrefab";
|
|
||||||
_pickupData = null;
|
|
||||||
_objectiveData = null;
|
|
||||||
_itemType = ItemType.None;
|
|
||||||
_addObjective = false;
|
|
||||||
_soEditor = null;
|
|
||||||
GUI.FocusControl(null);
|
|
||||||
Repaint();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: f67e06e997f642509ba61ea12b0f793e
|
|
||||||
timeCreated: 1757503955
|
|
||||||
@@ -248,7 +248,9 @@ MonoBehaviour:
|
|||||||
m_Script: {fileID: 11500000, guid: 2bd397a60643eed45b586961ae6e3453, type: 3}
|
m_Script: {fileID: 11500000, guid: 2bd397a60643eed45b586961ae6e3453, type: 3}
|
||||||
m_Name:
|
m_Name:
|
||||||
m_EditorClassIdentifier: AppleHillsScripts::PulverAudioController
|
m_EditorClassIdentifier: AppleHillsScripts::PulverAudioController
|
||||||
|
audioSource: {fileID: 887004370483616855}
|
||||||
combineAudio: {fileID: 8300000, guid: 768a16f348fe1d94c9cc267dc7ecf3b5, type: 3}
|
combineAudio: {fileID: 8300000, guid: 768a16f348fe1d94c9cc267dc7ecf3b5, type: 3}
|
||||||
|
itemManager: {fileID: 0}
|
||||||
--- !u!82 &4467608046243604209
|
--- !u!82 &4467608046243604209
|
||||||
AudioSource:
|
AudioSource:
|
||||||
m_ObjectHideFlags: 0
|
m_ObjectHideFlags: 0
|
||||||
|
|||||||
@@ -1185,6 +1185,7 @@ MonoBehaviour:
|
|||||||
CinematicBackground: {fileID: 1256355336041814197}
|
CinematicBackground: {fileID: 1256355336041814197}
|
||||||
eagleEye: {fileID: 8093509920149135307}
|
eagleEye: {fileID: 8093509920149135307}
|
||||||
ramaSjangButton: {fileID: 4599222264323240281}
|
ramaSjangButton: {fileID: 4599222264323240281}
|
||||||
|
scrabBookButton: {fileID: 2880351836456325619}
|
||||||
cinematicSprites: {fileID: 0}
|
cinematicSprites: {fileID: 0}
|
||||||
cinematicBackgroundSprites: {fileID: 0}
|
cinematicBackgroundSprites: {fileID: 0}
|
||||||
currentCinematicPlayer: {fileID: 0}
|
currentCinematicPlayer: {fileID: 0}
|
||||||
|
|||||||
@@ -614,6 +614,7 @@ GameObject:
|
|||||||
- component: {fileID: 768265498311662326}
|
- component: {fileID: 768265498311662326}
|
||||||
- component: {fileID: 6338084184716153992}
|
- component: {fileID: 6338084184716153992}
|
||||||
- component: {fileID: 253472492358066383}
|
- component: {fileID: 253472492358066383}
|
||||||
|
- component: {fileID: 7628818949793551399}
|
||||||
m_Layer: 10
|
m_Layer: 10
|
||||||
m_Name: FakeChoco
|
m_Name: FakeChoco
|
||||||
m_TagString: Untagged
|
m_TagString: Untagged
|
||||||
@@ -633,7 +634,8 @@ Transform:
|
|||||||
m_LocalPosition: {x: -6.784, y: -2.901, z: 0}
|
m_LocalPosition: {x: -6.784, y: -2.901, z: 0}
|
||||||
m_LocalScale: {x: 0.7, y: 0.7, z: 0.7}
|
m_LocalScale: {x: 0.7, y: 0.7, z: 0.7}
|
||||||
m_ConstrainProportionsScale: 1
|
m_ConstrainProportionsScale: 1
|
||||||
m_Children: []
|
m_Children:
|
||||||
|
- {fileID: 2205893234949555645}
|
||||||
m_Father: {fileID: 1509867968154593713}
|
m_Father: {fileID: 1509867968154593713}
|
||||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
--- !u!212 &6338084184716153992
|
--- !u!212 &6338084184716153992
|
||||||
@@ -740,6 +742,45 @@ BoxCollider2D:
|
|||||||
m_AutoTiling: 0
|
m_AutoTiling: 0
|
||||||
m_Size: {x: 6, y: 6}
|
m_Size: {x: 6, y: 6}
|
||||||
m_EdgeRadius: 0
|
m_EdgeRadius: 0
|
||||||
|
--- !u!114 &7628818949793551399
|
||||||
|
MonoBehaviour:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 2391935521422290070}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: 11500000, guid: 833a4ccef651449e973e623d9107bef5, type: 3}
|
||||||
|
m_Name:
|
||||||
|
m_EditorClassIdentifier: AppleHillsScripts::Interactions.OneClickInteraction
|
||||||
|
isOneTime: 0
|
||||||
|
cooldown: -1
|
||||||
|
characterToInteract: 2
|
||||||
|
interactionStarted:
|
||||||
|
m_PersistentCalls:
|
||||||
|
m_Calls: []
|
||||||
|
interactionInterrupted:
|
||||||
|
m_PersistentCalls:
|
||||||
|
m_Calls: []
|
||||||
|
characterArrived:
|
||||||
|
m_PersistentCalls:
|
||||||
|
m_Calls:
|
||||||
|
- m_Target: {fileID: 5762733430166618195}
|
||||||
|
m_TargetAssemblyTypeName: PicnicBehaviour, AppleHillsScripts
|
||||||
|
m_MethodName: triedToStealChocolate
|
||||||
|
m_Mode: 1
|
||||||
|
m_Arguments:
|
||||||
|
m_ObjectArgument: {fileID: 0}
|
||||||
|
m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine
|
||||||
|
m_IntArgument: 0
|
||||||
|
m_FloatArgument: 0
|
||||||
|
m_StringArgument:
|
||||||
|
m_BoolArgument: 0
|
||||||
|
m_CallState: 2
|
||||||
|
interactionComplete:
|
||||||
|
m_PersistentCalls:
|
||||||
|
m_Calls: []
|
||||||
--- !u!1 &2728537141134591410
|
--- !u!1 &2728537141134591410
|
||||||
GameObject:
|
GameObject:
|
||||||
m_ObjectHideFlags: 0
|
m_ObjectHideFlags: 0
|
||||||
@@ -1322,6 +1363,104 @@ GameObject:
|
|||||||
m_CorrespondingSourceObject: {fileID: 5383276844808284485, guid: afbb486e5456a20479aee4cf8bc949b6, type: 3}
|
m_CorrespondingSourceObject: {fileID: 5383276844808284485, guid: afbb486e5456a20479aee4cf8bc949b6, type: 3}
|
||||||
m_PrefabInstance: {fileID: 3750141998400252915}
|
m_PrefabInstance: {fileID: 3750141998400252915}
|
||||||
m_PrefabAsset: {fileID: 0}
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
--- !u!1001 &7365721869475958115
|
||||||
|
PrefabInstance:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
serializedVersion: 2
|
||||||
|
m_Modification:
|
||||||
|
serializedVersion: 3
|
||||||
|
m_TransformParent: {fileID: 768265498311662326}
|
||||||
|
m_Modifications:
|
||||||
|
- target: {fileID: 2991221189157356317, guid: f21581740b83b624cac5e6a8fa4d0f47, type: 3}
|
||||||
|
propertyPath: m_LocalScale.x
|
||||||
|
value: 0.3
|
||||||
|
objectReference: {fileID: 0}
|
||||||
|
- target: {fileID: 2991221189157356317, guid: f21581740b83b624cac5e6a8fa4d0f47, type: 3}
|
||||||
|
propertyPath: m_LocalScale.y
|
||||||
|
value: 0.3
|
||||||
|
objectReference: {fileID: 0}
|
||||||
|
- target: {fileID: 2991221189157356317, guid: f21581740b83b624cac5e6a8fa4d0f47, type: 3}
|
||||||
|
propertyPath: m_LocalScale.z
|
||||||
|
value: 0.3
|
||||||
|
objectReference: {fileID: 0}
|
||||||
|
- target: {fileID: 8506461915049351794, guid: f21581740b83b624cac5e6a8fa4d0f47, type: 3}
|
||||||
|
propertyPath: m_Name
|
||||||
|
value: HighlightEffect
|
||||||
|
objectReference: {fileID: 0}
|
||||||
|
- target: {fileID: 8506461915049351794, guid: f21581740b83b624cac5e6a8fa4d0f47, type: 3}
|
||||||
|
propertyPath: m_IsActive
|
||||||
|
value: 1
|
||||||
|
objectReference: {fileID: 0}
|
||||||
|
- target: {fileID: 8693254833721559262, guid: f21581740b83b624cac5e6a8fa4d0f47, type: 3}
|
||||||
|
propertyPath: m_LocalScale.x
|
||||||
|
value: 0.5
|
||||||
|
objectReference: {fileID: 0}
|
||||||
|
- target: {fileID: 8693254833721559262, guid: f21581740b83b624cac5e6a8fa4d0f47, type: 3}
|
||||||
|
propertyPath: m_LocalScale.y
|
||||||
|
value: 0.5
|
||||||
|
objectReference: {fileID: 0}
|
||||||
|
- target: {fileID: 8693254833721559262, guid: f21581740b83b624cac5e6a8fa4d0f47, type: 3}
|
||||||
|
propertyPath: m_LocalScale.z
|
||||||
|
value: 0.5
|
||||||
|
objectReference: {fileID: 0}
|
||||||
|
- target: {fileID: 8693254833721559262, guid: f21581740b83b624cac5e6a8fa4d0f47, type: 3}
|
||||||
|
propertyPath: m_LocalPosition.x
|
||||||
|
value: 0
|
||||||
|
objectReference: {fileID: 0}
|
||||||
|
- target: {fileID: 8693254833721559262, guid: f21581740b83b624cac5e6a8fa4d0f47, type: 3}
|
||||||
|
propertyPath: m_LocalPosition.y
|
||||||
|
value: 0
|
||||||
|
objectReference: {fileID: 0}
|
||||||
|
- target: {fileID: 8693254833721559262, guid: f21581740b83b624cac5e6a8fa4d0f47, type: 3}
|
||||||
|
propertyPath: m_LocalPosition.z
|
||||||
|
value: 0
|
||||||
|
objectReference: {fileID: 0}
|
||||||
|
- target: {fileID: 8693254833721559262, guid: f21581740b83b624cac5e6a8fa4d0f47, type: 3}
|
||||||
|
propertyPath: m_LocalRotation.w
|
||||||
|
value: 1
|
||||||
|
objectReference: {fileID: 0}
|
||||||
|
- target: {fileID: 8693254833721559262, guid: f21581740b83b624cac5e6a8fa4d0f47, type: 3}
|
||||||
|
propertyPath: m_LocalRotation.x
|
||||||
|
value: -0
|
||||||
|
objectReference: {fileID: 0}
|
||||||
|
- target: {fileID: 8693254833721559262, guid: f21581740b83b624cac5e6a8fa4d0f47, type: 3}
|
||||||
|
propertyPath: m_LocalRotation.y
|
||||||
|
value: -0
|
||||||
|
objectReference: {fileID: 0}
|
||||||
|
- target: {fileID: 8693254833721559262, guid: f21581740b83b624cac5e6a8fa4d0f47, type: 3}
|
||||||
|
propertyPath: m_LocalRotation.z
|
||||||
|
value: -0
|
||||||
|
objectReference: {fileID: 0}
|
||||||
|
- target: {fileID: 8693254833721559262, guid: f21581740b83b624cac5e6a8fa4d0f47, type: 3}
|
||||||
|
propertyPath: m_LocalEulerAnglesHint.x
|
||||||
|
value: 0
|
||||||
|
objectReference: {fileID: 0}
|
||||||
|
- target: {fileID: 8693254833721559262, guid: f21581740b83b624cac5e6a8fa4d0f47, type: 3}
|
||||||
|
propertyPath: m_LocalEulerAnglesHint.y
|
||||||
|
value: 0
|
||||||
|
objectReference: {fileID: 0}
|
||||||
|
- target: {fileID: 8693254833721559262, guid: f21581740b83b624cac5e6a8fa4d0f47, type: 3}
|
||||||
|
propertyPath: m_LocalEulerAnglesHint.z
|
||||||
|
value: 0
|
||||||
|
objectReference: {fileID: 0}
|
||||||
|
- target: {fileID: 8693254833721559262, guid: f21581740b83b624cac5e6a8fa4d0f47, type: 3}
|
||||||
|
propertyPath: m_ConstrainProportionsScale
|
||||||
|
value: 1
|
||||||
|
objectReference: {fileID: 0}
|
||||||
|
- target: {fileID: 8998003315986923927, guid: f21581740b83b624cac5e6a8fa4d0f47, type: 3}
|
||||||
|
propertyPath: m_SortingOrder
|
||||||
|
value: 1
|
||||||
|
objectReference: {fileID: 0}
|
||||||
|
m_RemovedComponents: []
|
||||||
|
m_RemovedGameObjects: []
|
||||||
|
m_AddedGameObjects: []
|
||||||
|
m_AddedComponents: []
|
||||||
|
m_SourcePrefab: {fileID: 100100000, guid: f21581740b83b624cac5e6a8fa4d0f47, type: 3}
|
||||||
|
--- !u!4 &2205893234949555645 stripped
|
||||||
|
Transform:
|
||||||
|
m_CorrespondingSourceObject: {fileID: 8693254833721559262, guid: f21581740b83b624cac5e6a8fa4d0f47, type: 3}
|
||||||
|
m_PrefabInstance: {fileID: 7365721869475958115}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
--- !u!1001 &7995402114015427944
|
--- !u!1001 &7995402114015427944
|
||||||
PrefabInstance:
|
PrefabInstance:
|
||||||
m_ObjectHideFlags: 0
|
m_ObjectHideFlags: 0
|
||||||
@@ -1362,6 +1501,34 @@ PrefabInstance:
|
|||||||
propertyPath: m_SortingOrder
|
propertyPath: m_SortingOrder
|
||||||
value: 1
|
value: 1
|
||||||
objectReference: {fileID: 0}
|
objectReference: {fileID: 0}
|
||||||
|
- target: {fileID: 2846246689251721816, guid: b3fc964bec385174f85a143f2fcff121, type: 3}
|
||||||
|
propertyPath: interactionComplete.m_PersistentCalls.m_Calls.Array.size
|
||||||
|
value: 1
|
||||||
|
objectReference: {fileID: 0}
|
||||||
|
- target: {fileID: 2846246689251721816, guid: b3fc964bec385174f85a143f2fcff121, type: 3}
|
||||||
|
propertyPath: interactionComplete.m_PersistentCalls.m_Calls.Array.data[0].m_Mode
|
||||||
|
value: 1
|
||||||
|
objectReference: {fileID: 0}
|
||||||
|
- target: {fileID: 2846246689251721816, guid: b3fc964bec385174f85a143f2fcff121, type: 3}
|
||||||
|
propertyPath: interactionComplete.m_PersistentCalls.m_Calls.Array.data[0].m_Target
|
||||||
|
value:
|
||||||
|
objectReference: {fileID: 5762733430166618195}
|
||||||
|
- target: {fileID: 2846246689251721816, guid: b3fc964bec385174f85a143f2fcff121, type: 3}
|
||||||
|
propertyPath: interactionComplete.m_PersistentCalls.m_Calls.Array.data[0].m_CallState
|
||||||
|
value: 2
|
||||||
|
objectReference: {fileID: 0}
|
||||||
|
- target: {fileID: 2846246689251721816, guid: b3fc964bec385174f85a143f2fcff121, type: 3}
|
||||||
|
propertyPath: interactionComplete.m_PersistentCalls.m_Calls.Array.data[0].m_MethodName
|
||||||
|
value: destroyFakeChocolate
|
||||||
|
objectReference: {fileID: 0}
|
||||||
|
- target: {fileID: 2846246689251721816, guid: b3fc964bec385174f85a143f2fcff121, type: 3}
|
||||||
|
propertyPath: interactionComplete.m_PersistentCalls.m_Calls.Array.data[0].m_TargetAssemblyTypeName
|
||||||
|
value: PicnicBehaviour, AppleHillsScripts
|
||||||
|
objectReference: {fileID: 0}
|
||||||
|
- target: {fileID: 2846246689251721816, guid: b3fc964bec385174f85a143f2fcff121, type: 3}
|
||||||
|
propertyPath: interactionComplete.m_PersistentCalls.m_Calls.Array.data[0].m_Arguments.m_ObjectArgumentAssemblyTypeName
|
||||||
|
value: UnityEngine.Object, UnityEngine
|
||||||
|
objectReference: {fileID: 0}
|
||||||
- target: {fileID: 3984039030829909690, guid: b3fc964bec385174f85a143f2fcff121, type: 3}
|
- target: {fileID: 3984039030829909690, guid: b3fc964bec385174f85a143f2fcff121, type: 3}
|
||||||
propertyPath: m_LocalScale.x
|
propertyPath: m_LocalScale.x
|
||||||
value: 0.7
|
value: 0.7
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -285,8 +285,8 @@ RectTransform:
|
|||||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
m_AnchorMin: {x: 0.5, y: 1}
|
m_AnchorMin: {x: 0.5, y: 1}
|
||||||
m_AnchorMax: {x: 0.5, y: 1}
|
m_AnchorMax: {x: 0.5, y: 1}
|
||||||
m_AnchoredPosition: {x: 0, y: 173}
|
m_AnchoredPosition: {x: 0, y: 125}
|
||||||
m_SizeDelta: {x: 600, y: 150}
|
m_SizeDelta: {x: 600, y: 120}
|
||||||
m_Pivot: {x: 0.5, y: 1}
|
m_Pivot: {x: 0.5, y: 1}
|
||||||
--- !u!222 &5545241165728741220
|
--- !u!222 &5545241165728741220
|
||||||
CanvasRenderer:
|
CanvasRenderer:
|
||||||
@@ -343,8 +343,8 @@ MonoBehaviour:
|
|||||||
m_faceColor:
|
m_faceColor:
|
||||||
serializedVersion: 2
|
serializedVersion: 2
|
||||||
rgba: 4294967295
|
rgba: 4294967295
|
||||||
m_fontSize: 150
|
m_fontSize: 125
|
||||||
m_fontSizeBase: 150
|
m_fontSizeBase: 125
|
||||||
m_fontWeight: 400
|
m_fontWeight: 400
|
||||||
m_enableAutoSizing: 0
|
m_enableAutoSizing: 0
|
||||||
m_fontSizeMin: 18
|
m_fontSizeMin: 18
|
||||||
@@ -1053,6 +1053,10 @@ PrefabInstance:
|
|||||||
propertyPath: m_SizeDelta.x
|
propertyPath: m_SizeDelta.x
|
||||||
value: 0
|
value: 0
|
||||||
objectReference: {fileID: 0}
|
objectReference: {fileID: 0}
|
||||||
|
- target: {fileID: 4925415087786595420, guid: 1d8cc8d9238eec34b8e600e7050e2979, type: 3}
|
||||||
|
propertyPath: m_fontSize
|
||||||
|
value: 54.45
|
||||||
|
objectReference: {fileID: 0}
|
||||||
- target: {fileID: 5378230129755544441, guid: 1d8cc8d9238eec34b8e600e7050e2979, type: 3}
|
- target: {fileID: 5378230129755544441, guid: 1d8cc8d9238eec34b8e600e7050e2979, type: 3}
|
||||||
propertyPath: m_AnchorMax.x
|
propertyPath: m_AnchorMax.x
|
||||||
value: 0
|
value: 0
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
@@ -453761,6 +453761,10 @@ PrefabInstance:
|
|||||||
propertyPath: m_PlayOnAwake
|
propertyPath: m_PlayOnAwake
|
||||||
value: 0
|
value: 0
|
||||||
objectReference: {fileID: 0}
|
objectReference: {fileID: 0}
|
||||||
|
- target: {fileID: 8545106365577783398, guid: ead4e790fa3a1924ebd1586c93cd5479, type: 3}
|
||||||
|
propertyPath: isOneTime
|
||||||
|
value: 1
|
||||||
|
objectReference: {fileID: 0}
|
||||||
m_RemovedComponents: []
|
m_RemovedComponents: []
|
||||||
m_RemovedGameObjects: []
|
m_RemovedGameObjects: []
|
||||||
m_AddedGameObjects: []
|
m_AddedGameObjects: []
|
||||||
|
|||||||
@@ -1562,7 +1562,7 @@ AudioSource:
|
|||||||
OutputAudioMixerGroup: {fileID: 3533147658878909314, guid: 727a7e4b6df4b0d47897f7d8ee7fa323, type: 2}
|
OutputAudioMixerGroup: {fileID: 3533147658878909314, guid: 727a7e4b6df4b0d47897f7d8ee7fa323, type: 2}
|
||||||
m_audioClip: {fileID: 0}
|
m_audioClip: {fileID: 0}
|
||||||
m_Resource: {fileID: 0}
|
m_Resource: {fileID: 0}
|
||||||
m_PlayOnAwake: 1
|
m_PlayOnAwake: 0
|
||||||
m_Volume: 1
|
m_Volume: 1
|
||||||
m_Pitch: 1
|
m_Pitch: 1
|
||||||
Loop: 0
|
Loop: 0
|
||||||
@@ -3633,6 +3633,18 @@ PrefabInstance:
|
|||||||
propertyPath: m_Name
|
propertyPath: m_Name
|
||||||
value: Tutorial
|
value: Tutorial
|
||||||
objectReference: {fileID: 0}
|
objectReference: {fileID: 0}
|
||||||
|
- target: {fileID: 4267886887244421663, guid: a4dd78ff48942854ebb4c65025a8dc36, type: 3}
|
||||||
|
propertyPath: introVO
|
||||||
|
value:
|
||||||
|
objectReference: {fileID: 8300000, guid: fca641cdc8dcd074483fad3db1cbe24c, type: 3}
|
||||||
|
- target: {fileID: 4267886887244421663, guid: a4dd78ff48942854ebb4c65025a8dc36, type: 3}
|
||||||
|
propertyPath: playTutorial
|
||||||
|
value: 1
|
||||||
|
objectReference: {fileID: 0}
|
||||||
|
- target: {fileID: 4267886887244421663, guid: a4dd78ff48942854ebb4c65025a8dc36, type: 3}
|
||||||
|
propertyPath: bottleAudioPlayer
|
||||||
|
value:
|
||||||
|
objectReference: {fileID: 747976408}
|
||||||
- target: {fileID: 8452897808363562605, guid: a4dd78ff48942854ebb4c65025a8dc36, type: 3}
|
- target: {fileID: 8452897808363562605, guid: a4dd78ff48942854ebb4c65025a8dc36, type: 3}
|
||||||
propertyPath: m_Sprite
|
propertyPath: m_Sprite
|
||||||
value:
|
value:
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -56,7 +56,7 @@ public class BirdEyesBehavior : ManagedBehaviour
|
|||||||
_statemachine.ChangeState("BirdSpawned");
|
_statemachine.ChangeState("BirdSpawned");
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnSceneRestoreRequested(string serializedData)
|
internal override void OnSceneRestoreRequested(string serializedData)
|
||||||
{
|
{
|
||||||
base.OnSceneRestoreRequested(serializedData);
|
base.OnSceneRestoreRequested(serializedData);
|
||||||
|
|
||||||
@@ -75,7 +75,7 @@ public class BirdEyesBehavior : ManagedBehaviour
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override string OnSceneSaveRequested()
|
internal override string OnSceneSaveRequested()
|
||||||
{
|
{
|
||||||
return _wolterisoutTriggered.ToString();
|
return _wolterisoutTriggered.ToString();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using AppleHills.Core.Settings;
|
using AppleHills.Core.Settings;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using Core;
|
using Core;
|
||||||
@@ -30,14 +30,10 @@ namespace Bootstrap
|
|||||||
private float _sceneLoadingProgress = 0f;
|
private float _sceneLoadingProgress = 0f;
|
||||||
private LogVerbosity _logVerbosity = LogVerbosity.Warning;
|
private LogVerbosity _logVerbosity = LogVerbosity.Warning;
|
||||||
|
|
||||||
// Run very early - need to set up loading screen before other systems initialize
|
|
||||||
public override int ManagedAwakePriority => 5;
|
|
||||||
|
|
||||||
protected override void Awake()
|
internal override void OnManagedAwake()
|
||||||
{
|
{
|
||||||
base.Awake(); // Register with LifecycleManager
|
Logging.Debug("BootSceneController.Awake() - Initializing loading screen DURING bootstrap");
|
||||||
|
|
||||||
LogDebugMessage("BootSceneController.Awake() - Initializing loading screen DURING bootstrap");
|
|
||||||
|
|
||||||
// Validate loading screen exists
|
// Validate loading screen exists
|
||||||
if (initialLoadingScreen == null)
|
if (initialLoadingScreen == null)
|
||||||
@@ -71,11 +67,11 @@ namespace Bootstrap
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnManagedAwake()
|
internal override void OnManagedStart()
|
||||||
{
|
{
|
||||||
LogDebugMessage("BootSceneController.OnManagedAwake() - Boot is GUARANTEED complete, starting scene loading");
|
Logging.Debug("BootSceneController.OnManagedStart() - Boot is GUARANTEED complete, starting scene loading");
|
||||||
|
|
||||||
// Boot is GUARANTEED complete at this point - that's the whole point of OnManagedAwake!
|
// Boot is GUARANTEED complete at this point - that's the whole point of OnManagedStart!
|
||||||
// No need to subscribe to OnBootCompleted or check CustomBoot.Initialised
|
// No need to subscribe to OnBootCompleted or check CustomBoot.Initialised
|
||||||
_bootComplete = true;
|
_bootComplete = true;
|
||||||
_currentPhase = LoadingPhase.SceneLoading;
|
_currentPhase = LoadingPhase.SceneLoading;
|
||||||
@@ -85,10 +81,8 @@ namespace Bootstrap
|
|||||||
Invoke(nameof(StartLoadingMainMenu), minDelayAfterBoot);
|
Invoke(nameof(StartLoadingMainMenu), minDelayAfterBoot);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnDestroy()
|
internal override void OnManagedDestroy()
|
||||||
{
|
{
|
||||||
base.OnDestroy();
|
|
||||||
|
|
||||||
// Manual cleanup for events
|
// Manual cleanup for events
|
||||||
if (initialLoadingScreen != null)
|
if (initialLoadingScreen != null)
|
||||||
{
|
{
|
||||||
@@ -102,12 +96,12 @@ namespace Bootstrap
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private void OnInitialLoadingComplete()
|
private void OnInitialLoadingComplete()
|
||||||
{
|
{
|
||||||
LogDebugMessage("Initial loading screen fully hidden, boot sequence completed");
|
Logging.Debug("Initial loading screen fully hidden, boot sequence completed");
|
||||||
|
|
||||||
// Play the intro cinematic if available
|
// Play the intro cinematic if available
|
||||||
if (CinematicsManager.Instance != null)
|
if (CinematicsManager.Instance != null)
|
||||||
{
|
{
|
||||||
LogDebugMessage("Attempting to play intro cinematic");
|
Logging.Debug("Attempting to play intro cinematic");
|
||||||
|
|
||||||
// Use LoadAndPlayCinematic to play the intro sequence
|
// Use LoadAndPlayCinematic to play the intro sequence
|
||||||
CinematicsManager.Instance.LoadAndPlayCinematic("IntroSequence", false);
|
CinematicsManager.Instance.LoadAndPlayCinematic("IntroSequence", false);
|
||||||
@@ -149,13 +143,13 @@ namespace Bootstrap
|
|||||||
{
|
{
|
||||||
if (debugMode)
|
if (debugMode)
|
||||||
{
|
{
|
||||||
LogDebugMessage($"Bootstrap progress: {progress:P0}, Combined: {GetCombinedProgress():P0}");
|
Logging.Debug($"Bootstrap progress: {progress:P0}, Combined: {GetCombinedProgress():P0}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void LogDebugInfo()
|
private void LogDebugInfo()
|
||||||
{
|
{
|
||||||
LogDebugMessage($"Debug - Phase: {_currentPhase}, Bootstrap: {CustomBoot.CurrentProgress:P0}, " +
|
Logging.Debug($"Debug - Phase: {_currentPhase}, Bootstrap: {CustomBoot.CurrentProgress:P0}, " +
|
||||||
$"Scene: {_sceneLoadingProgress:P0}, Combined: {GetCombinedProgress():P0}, Boot Complete: {_bootComplete}");
|
$"Scene: {_sceneLoadingProgress:P0}, Combined: {GetCombinedProgress():P0}, Boot Complete: {_bootComplete}");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -172,7 +166,7 @@ namespace Bootstrap
|
|||||||
|
|
||||||
private async void LoadMainScene()
|
private async void LoadMainScene()
|
||||||
{
|
{
|
||||||
LogDebugMessage($"Loading main menu scene: {mainSceneName}");
|
Logging.Debug($"Loading main menu scene: {mainSceneName}");
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -186,7 +180,7 @@ namespace Bootstrap
|
|||||||
|
|
||||||
if (debugMode)
|
if (debugMode)
|
||||||
{
|
{
|
||||||
LogDebugMessage($"Scene loading raw: {value:P0}, Combined: {GetCombinedProgress():P0}");
|
Logging.Debug($"Scene loading raw: {value:P0}, Combined: {GetCombinedProgress():P0}");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -210,13 +204,13 @@ namespace Bootstrap
|
|||||||
_sceneLoadingProgress = 1f;
|
_sceneLoadingProgress = 1f;
|
||||||
|
|
||||||
// CRITICAL: Broadcast lifecycle events so components get their OnSceneReady callbacks
|
// CRITICAL: Broadcast lifecycle events so components get their OnSceneReady callbacks
|
||||||
LogDebugMessage($"Broadcasting OnSceneReady for: {mainSceneName}");
|
Logging.Debug($"Broadcasting OnSceneReady for: {mainSceneName}");
|
||||||
LifecycleManager.Instance?.BroadcastSceneReady(mainSceneName);
|
LifecycleManager.Instance?.BroadcastSceneReady(mainSceneName);
|
||||||
|
|
||||||
// Restore scene data for the main menu
|
// Restore scene data for the main menu
|
||||||
if (SaveLoadManager.Instance != null)
|
if (SaveLoadManager.Instance != null)
|
||||||
{
|
{
|
||||||
LogDebugMessage($"Restoring scene data for: {mainSceneName}");
|
Logging.Debug($"Restoring scene data for: {mainSceneName}");
|
||||||
SaveLoadManager.Instance.RestoreSceneData();
|
SaveLoadManager.Instance.RestoreSceneData();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -246,7 +240,7 @@ namespace Bootstrap
|
|||||||
Scene currentScene = SceneManager.GetActiveScene();
|
Scene currentScene = SceneManager.GetActiveScene();
|
||||||
string startingSceneName = currentScene.name;
|
string startingSceneName = currentScene.name;
|
||||||
|
|
||||||
LogDebugMessage($"Unloading StartingScene: {startingSceneName}");
|
Logging.Debug($"Unloading StartingScene: {startingSceneName}");
|
||||||
|
|
||||||
// Unload the StartingScene
|
// Unload the StartingScene
|
||||||
await SceneManager.UnloadSceneAsync(startingSceneName);
|
await SceneManager.UnloadSceneAsync(startingSceneName);
|
||||||
@@ -255,14 +249,14 @@ namespace Bootstrap
|
|||||||
Scene mainMenuScene = SceneManager.GetSceneByName(mainSceneName);
|
Scene mainMenuScene = SceneManager.GetSceneByName(mainSceneName);
|
||||||
SceneManager.SetActiveScene(mainMenuScene);
|
SceneManager.SetActiveScene(mainMenuScene);
|
||||||
|
|
||||||
LogDebugMessage($"Transition complete: {startingSceneName} unloaded, {mainSceneName} is now active");
|
Logging.Debug($"Transition complete: {startingSceneName} unloaded, {mainSceneName} is now active");
|
||||||
|
|
||||||
// Destroy the boot scene controller since its job is done
|
// Destroy the boot scene controller since its job is done
|
||||||
Destroy(gameObject);
|
Destroy(gameObject);
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
Logging.Warning($"[BootSceneController] Error unloading StartingScene: {e.Message}");
|
Logging.Warning($"Error unloading StartingScene: {e.Message}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -283,13 +277,5 @@ namespace Bootstrap
|
|||||||
_progressAction?.Invoke(value);
|
_progressAction?.Invoke(value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void LogDebugMessage(string message)
|
|
||||||
{
|
|
||||||
if ( _logVerbosity <= LogVerbosity.Debug)
|
|
||||||
{
|
|
||||||
Logging.Debug($"[BootSceneController] {message}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using AppleHills.Core.Settings;
|
|
||||||
using Core;
|
using Core;
|
||||||
using Core.Lifecycle;
|
using Core.Lifecycle;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
@@ -105,7 +104,7 @@ namespace Bootstrap
|
|||||||
// Notify the LifecycleManager that boot is complete
|
// Notify the LifecycleManager that boot is complete
|
||||||
if (Application.isPlaying)
|
if (Application.isPlaying)
|
||||||
{
|
{
|
||||||
LogDebugMessage("Calling LifecycleManager.OnBootCompletionTriggered()");
|
Logging.Debug("Calling LifecycleManager.OnBootCompletionTriggered()");
|
||||||
if (LifecycleManager.Instance != null)
|
if (LifecycleManager.Instance != null)
|
||||||
{
|
{
|
||||||
LifecycleManager.Instance.OnBootCompletionTriggered();
|
LifecycleManager.Instance.OnBootCompletionTriggered();
|
||||||
@@ -127,7 +126,7 @@ namespace Bootstrap
|
|||||||
// Notify the LifecycleManager that boot is complete
|
// Notify the LifecycleManager that boot is complete
|
||||||
if (Application.isPlaying)
|
if (Application.isPlaying)
|
||||||
{
|
{
|
||||||
LogDebugMessage("Calling LifecycleManager.OnBootCompletionTriggered()");
|
Logging.Debug("Calling LifecycleManager.OnBootCompletionTriggered()");
|
||||||
if (LifecycleManager.Instance != null)
|
if (LifecycleManager.Instance != null)
|
||||||
{
|
{
|
||||||
LifecycleManager.Instance.OnBootCompletionTriggered();
|
LifecycleManager.Instance.OnBootCompletionTriggered();
|
||||||
@@ -238,16 +237,7 @@ namespace Bootstrap
|
|||||||
{
|
{
|
||||||
CurrentProgress = Mathf.Clamp01(progress);
|
CurrentProgress = Mathf.Clamp01(progress);
|
||||||
OnBootProgressChanged?.Invoke(CurrentProgress);
|
OnBootProgressChanged?.Invoke(CurrentProgress);
|
||||||
LogDebugMessage($"Progress: {CurrentProgress:P0}");
|
Logging.Debug($"Progress: {CurrentProgress:P0}");
|
||||||
}
|
|
||||||
|
|
||||||
private static void LogDebugMessage(string message)
|
|
||||||
{
|
|
||||||
if (DeveloperSettingsProvider.Instance.GetSettings<DebugSettings>().bootstrapLogVerbosity <=
|
|
||||||
LogVerbosity.Debug)
|
|
||||||
{
|
|
||||||
Logging.Debug($"[CustomBoot] {message}");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -138,7 +138,7 @@ namespace Bootstrap
|
|||||||
float displayProgress = Mathf.Min(steadyProgress, actualProgress);
|
float displayProgress = Mathf.Min(steadyProgress, actualProgress);
|
||||||
|
|
||||||
// Log the progress values for debugging
|
// Log the progress values for debugging
|
||||||
LogDebugMessage($"Progress - Default: {steadyProgress:F2}, Actual: {actualProgress:F2}, Display: {displayProgress:F2}");
|
Logging.Debug($"Progress - Default: {steadyProgress:F2}, Actual: {actualProgress:F2}, Display: {displayProgress:F2}");
|
||||||
|
|
||||||
// Directly set the progress bar fill amount without smoothing
|
// Directly set the progress bar fill amount without smoothing
|
||||||
if (progressBarImage != null)
|
if (progressBarImage != null)
|
||||||
@@ -151,7 +151,7 @@ namespace Bootstrap
|
|||||||
if (steadyProgress >= 1.0f && displayProgress >= 1.0f)
|
if (steadyProgress >= 1.0f && displayProgress >= 1.0f)
|
||||||
{
|
{
|
||||||
_animationComplete = true;
|
_animationComplete = true;
|
||||||
LogDebugMessage("Animation complete");
|
Logging.Debug("Animation complete");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -163,7 +163,7 @@ namespace Bootstrap
|
|||||||
if (progressBarImage != null)
|
if (progressBarImage != null)
|
||||||
{
|
{
|
||||||
progressBarImage.fillAmount = 1.0f;
|
progressBarImage.fillAmount = 1.0f;
|
||||||
LogDebugMessage("Final progress set to 1.0");
|
Logging.Debug("Final progress set to 1.0");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hide the screen if loading is also complete
|
// Hide the screen if loading is also complete
|
||||||
@@ -172,7 +172,7 @@ namespace Bootstrap
|
|||||||
if (loadingScreenContainer != null)
|
if (loadingScreenContainer != null)
|
||||||
{
|
{
|
||||||
loadingScreenContainer.SetActive(false);
|
loadingScreenContainer.SetActive(false);
|
||||||
LogDebugMessage("Animation AND loading complete, hiding screen");
|
Logging.Debug("Animation AND loading complete, hiding screen");
|
||||||
|
|
||||||
// Invoke the callback when fully hidden
|
// Invoke the callback when fully hidden
|
||||||
_onLoadingScreenFullyHidden?.Invoke();
|
_onLoadingScreenFullyHidden?.Invoke();
|
||||||
@@ -189,7 +189,7 @@ namespace Bootstrap
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public void HideLoadingScreen()
|
public void HideLoadingScreen()
|
||||||
{
|
{
|
||||||
LogDebugMessage("Loading complete, marking loading as finished");
|
Logging.Debug("Loading complete, marking loading as finished");
|
||||||
|
|
||||||
// Mark that loading is complete
|
// Mark that loading is complete
|
||||||
_loadingComplete = true;
|
_loadingComplete = true;
|
||||||
@@ -200,7 +200,7 @@ namespace Bootstrap
|
|||||||
if (loadingScreenContainer != null)
|
if (loadingScreenContainer != null)
|
||||||
{
|
{
|
||||||
loadingScreenContainer.SetActive(false);
|
loadingScreenContainer.SetActive(false);
|
||||||
LogDebugMessage("Animation already complete, hiding screen immediately");
|
Logging.Debug("Animation already complete, hiding screen immediately");
|
||||||
|
|
||||||
// Invoke the callback when fully hidden
|
// Invoke the callback when fully hidden
|
||||||
_onLoadingScreenFullyHidden?.Invoke();
|
_onLoadingScreenFullyHidden?.Invoke();
|
||||||
@@ -210,7 +210,7 @@ namespace Bootstrap
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
LogDebugMessage("Animation still in progress, waiting for it to complete");
|
Logging.Debug("Animation still in progress, waiting for it to complete");
|
||||||
// The coroutine will handle hiding when animation completes
|
// The coroutine will handle hiding when animation completes
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -244,13 +244,5 @@ namespace Bootstrap
|
|||||||
|
|
||||||
return tcs.Task;
|
return tcs.Task;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void LogDebugMessage(string message)
|
|
||||||
{
|
|
||||||
if ( _logVerbosity <= LogVerbosity.Debug)
|
|
||||||
{
|
|
||||||
Logging.Debug($"[InitialLoadingScreen] {message}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,17 +37,13 @@ namespace Cinematics
|
|||||||
|
|
||||||
public PlayableDirector playableDirector;
|
public PlayableDirector playableDirector;
|
||||||
|
|
||||||
public override int ManagedAwakePriority => 170; // Cinematic systems
|
internal override void OnManagedAwake()
|
||||||
|
|
||||||
private new void Awake()
|
|
||||||
{
|
{
|
||||||
base.Awake(); // CRITICAL: Register with LifecycleManager!
|
// Set instance immediately (early initialization)
|
||||||
|
|
||||||
// Set instance immediately so it's available before OnManagedAwake() is called
|
|
||||||
_instance = this;
|
_instance = this;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnManagedAwake()
|
internal override void OnManagedStart()
|
||||||
{
|
{
|
||||||
Logging.Debug("[CinematicsManager] Initialized");
|
Logging.Debug("[CinematicsManager] Initialized");
|
||||||
}
|
}
|
||||||
@@ -86,7 +82,7 @@ namespace Cinematics
|
|||||||
// If still null, try to add the component
|
// If still null, try to add the component
|
||||||
if (playableDirector == null)
|
if (playableDirector == null)
|
||||||
{
|
{
|
||||||
Debug.Log("[CinematicsManager] Could not find Playable Director on the PlayerHudManager");
|
Logging.Debug("[CinematicsManager] Could not find Playable Director on the PlayerHudManager");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -99,7 +95,7 @@ namespace Cinematics
|
|||||||
// If still null, return error
|
// If still null, return error
|
||||||
if (_cinematicSprites == null)
|
if (_cinematicSprites == null)
|
||||||
{
|
{
|
||||||
Debug.LogWarning("[CinematicsManager] No Image found for cinematics display. Cinematics may not display correctly.");
|
Logging.Warning("[CinematicsManager] No Image found for cinematics display. Cinematics may not display correctly.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,11 +15,8 @@ namespace Cinematics
|
|||||||
private float _holdStartTime;
|
private float _holdStartTime;
|
||||||
private bool _isHolding;
|
private bool _isHolding;
|
||||||
private bool _skipPerformed;
|
private bool _skipPerformed;
|
||||||
private bool _initialized = false;
|
|
||||||
|
|
||||||
public override int ManagedAwakePriority => 180; // Cinematic UI
|
|
||||||
|
|
||||||
protected override void OnManagedAwake()
|
internal override void OnManagedStart()
|
||||||
{
|
{
|
||||||
// Reset the progress bar
|
// Reset the progress bar
|
||||||
if (radialProgressBar != null)
|
if (radialProgressBar != null)
|
||||||
@@ -33,10 +30,8 @@ namespace Cinematics
|
|||||||
Logging.Debug("[SkipCinematic] Initialized");
|
Logging.Debug("[SkipCinematic] Initialized");
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnDestroy()
|
internal override void OnManagedDestroy()
|
||||||
{
|
{
|
||||||
base.OnDestroy();
|
|
||||||
|
|
||||||
// Clean up subscriptions
|
// Clean up subscriptions
|
||||||
UnsubscribeFromCinematicsEvents();
|
UnsubscribeFromCinematicsEvents();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,17 +34,13 @@ namespace Core
|
|||||||
public event Action OnGamePaused;
|
public event Action OnGamePaused;
|
||||||
public event Action OnGameResumed;
|
public event Action OnGameResumed;
|
||||||
|
|
||||||
// ManagedBehaviour configuration
|
|
||||||
public override int ManagedAwakePriority => 10; // Core infrastructure - runs early
|
|
||||||
|
|
||||||
private new void Awake()
|
internal override void OnManagedAwake()
|
||||||
{
|
{
|
||||||
base.Awake(); // CRITICAL: Register with LifecycleManager!
|
// Set instance immediately (early initialization)
|
||||||
|
|
||||||
// Set instance immediately so it's available before OnManagedAwake() is called
|
|
||||||
_instance = this;
|
_instance = this;
|
||||||
|
|
||||||
// Create settings providers - must happen in Awake so other managers can access settings in their ManagedAwake
|
// Create settings providers - must happen in OnManagedAwake so other managers can access settings in their ManagedStart
|
||||||
SettingsProvider.Instance.gameObject.name = "Settings Provider";
|
SettingsProvider.Instance.gameObject.name = "Settings Provider";
|
||||||
DeveloperSettingsProvider.Instance.gameObject.name = "Developer Settings Provider";
|
DeveloperSettingsProvider.Instance.gameObject.name = "Developer Settings Provider";
|
||||||
|
|
||||||
@@ -57,9 +53,9 @@ namespace Core
|
|||||||
_managerLogVerbosity = DeveloperSettingsProvider.Instance.GetSettings<DebugSettings>().gameManagerLogVerbosity;
|
_managerLogVerbosity = DeveloperSettingsProvider.Instance.GetSettings<DebugSettings>().gameManagerLogVerbosity;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnManagedAwake()
|
internal override void OnManagedStart()
|
||||||
{
|
{
|
||||||
// Settings are already initialized in Awake()
|
// Settings are already initialized in OnManagedAwake()
|
||||||
// This is available for future initialization that depends on other managers
|
// This is available for future initialization that depends on other managers
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -79,7 +75,7 @@ namespace Core
|
|||||||
component.Pause();
|
component.Pause();
|
||||||
}
|
}
|
||||||
|
|
||||||
LogDebugMessage($"Registered pausable component: {(component as MonoBehaviour)?.name ?? "Unknown"}");
|
Logging.Debug($"Registered pausable component: {(component as MonoBehaviour)?.name ?? "Unknown"}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -92,7 +88,7 @@ namespace Core
|
|||||||
if (component != null && _pausableComponents.Contains(component))
|
if (component != null && _pausableComponents.Contains(component))
|
||||||
{
|
{
|
||||||
_pausableComponents.Remove(component);
|
_pausableComponents.Remove(component);
|
||||||
LogDebugMessage($"Unregistered pausable component: {(component as MonoBehaviour)?.name ?? "Unknown"}");
|
Logging.Debug($"Unregistered pausable component: {(component as MonoBehaviour)?.name ?? "Unknown"}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -108,7 +104,7 @@ namespace Core
|
|||||||
ApplyPause(true);
|
ApplyPause(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
LogDebugMessage($"Pause requested by {requester?.ToString() ?? "Unknown"}. pauseCount = {_pauseCount}");
|
Logging.Debug($"Pause requested by {requester?.ToString() ?? "Unknown"}. pauseCount = {_pauseCount}");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -123,7 +119,7 @@ namespace Core
|
|||||||
ApplyPause(false);
|
ApplyPause(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
LogDebugMessage($"Pause released by {requester?.ToString() ?? "Unknown"}. pauseCount = {_pauseCount}");
|
Logging.Debug($"Pause released by {requester?.ToString() ?? "Unknown"}. pauseCount = {_pauseCount}");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -162,12 +158,12 @@ namespace Core
|
|||||||
OnGameResumed?.Invoke();
|
OnGameResumed?.Invoke();
|
||||||
}
|
}
|
||||||
|
|
||||||
LogDebugMessage($"Game {(shouldPause ? "paused" : "resumed")}. Paused {_pausableComponents.Count} components.");
|
Logging.Debug($"Game {(shouldPause ? "paused" : "resumed")}. Paused {_pausableComponents.Count} components.");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void InitializeSettings()
|
private void InitializeSettings()
|
||||||
{
|
{
|
||||||
LogDebugMessage("Starting settings initialization...", "SettingsInitialization", _settingsLogVerbosity);
|
Logging.Debug("Starting settings initialization...");
|
||||||
|
|
||||||
// Load settings synchronously
|
// Load settings synchronously
|
||||||
var playerSettings = SettingsProvider.Instance.LoadSettingsSynchronous<PlayerFollowerSettings>();
|
var playerSettings = SettingsProvider.Instance.LoadSettingsSynchronous<PlayerFollowerSettings>();
|
||||||
@@ -178,7 +174,7 @@ namespace Core
|
|||||||
if (playerSettings != null)
|
if (playerSettings != null)
|
||||||
{
|
{
|
||||||
ServiceLocator.Register<IPlayerFollowerSettings>(playerSettings);
|
ServiceLocator.Register<IPlayerFollowerSettings>(playerSettings);
|
||||||
LogDebugMessage("PlayerFollowerSettings registered successfully", "SettingsInitialization", _settingsLogVerbosity);
|
Logging.Debug("PlayerFollowerSettings registered successfully");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -188,7 +184,7 @@ namespace Core
|
|||||||
if (interactionSettings != null)
|
if (interactionSettings != null)
|
||||||
{
|
{
|
||||||
ServiceLocator.Register<IInteractionSettings>(interactionSettings);
|
ServiceLocator.Register<IInteractionSettings>(interactionSettings);
|
||||||
LogDebugMessage("InteractionSettings registered successfully", "SettingsInitialization", _settingsLogVerbosity);
|
Logging.Debug("InteractionSettings registered successfully");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -198,7 +194,7 @@ namespace Core
|
|||||||
if (minigameSettings != null)
|
if (minigameSettings != null)
|
||||||
{
|
{
|
||||||
ServiceLocator.Register<IDivingMinigameSettings>(minigameSettings);
|
ServiceLocator.Register<IDivingMinigameSettings>(minigameSettings);
|
||||||
LogDebugMessage("MinigameSettings registered successfully", "SettingsInitialization", _settingsLogVerbosity);
|
Logging.Debug("MinigameSettings registered successfully");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -209,7 +205,7 @@ namespace Core
|
|||||||
_settingsLoaded = playerSettings != null && interactionSettings != null && minigameSettings != null;
|
_settingsLoaded = playerSettings != null && interactionSettings != null && minigameSettings != null;
|
||||||
if (_settingsLoaded)
|
if (_settingsLoaded)
|
||||||
{
|
{
|
||||||
LogDebugMessage("All settings loaded and registered with ServiceLocator", "SettingsInitialization", _settingsLogVerbosity);
|
Logging.Debug("All settings loaded and registered with ServiceLocator");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -222,7 +218,7 @@ namespace Core
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private void InitializeDeveloperSettings()
|
private void InitializeDeveloperSettings()
|
||||||
{
|
{
|
||||||
LogDebugMessage("Starting developer settings initialization...", "SettingsInitialization", _settingsLogVerbosity);
|
Logging.Debug("Starting developer settings initialization...");
|
||||||
|
|
||||||
// Load developer settings
|
// Load developer settings
|
||||||
var divingDevSettings = DeveloperSettingsProvider.Instance.GetSettings<DivingDeveloperSettings>();
|
var divingDevSettings = DeveloperSettingsProvider.Instance.GetSettings<DivingDeveloperSettings>();
|
||||||
@@ -232,7 +228,7 @@ namespace Core
|
|||||||
|
|
||||||
if (_developerSettingsLoaded)
|
if (_developerSettingsLoaded)
|
||||||
{
|
{
|
||||||
LogDebugMessage("All developer settings loaded successfully", "SettingsInitialization", _settingsLogVerbosity);
|
Logging.Debug("All developer settings loaded successfully");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -266,19 +262,6 @@ namespace Core
|
|||||||
{
|
{
|
||||||
return DeveloperSettingsProvider.Instance?.GetSettings<T>();
|
return DeveloperSettingsProvider.Instance?.GetSettings<T>();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void LogDebugMessage(string message, string prefix = "GameManager", LogVerbosity verbosity = LogVerbosity.None)
|
|
||||||
{
|
|
||||||
if (verbosity == LogVerbosity.None)
|
|
||||||
{
|
|
||||||
verbosity = _managerLogVerbosity;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( verbosity <= LogVerbosity.Debug)
|
|
||||||
{
|
|
||||||
Logging.Debug($"[{prefix}] {message}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// LEFTOVER LEGACY SETTINGS
|
// LEFTOVER LEGACY SETTINGS
|
||||||
public float PlayerStopDistance => GetSettings<IInteractionSettings>()?.PlayerStopDistance ?? 6.0f;
|
public float PlayerStopDistance => GetSettings<IInteractionSettings>()?.PlayerStopDistance ?? 6.0f;
|
||||||
|
|||||||
@@ -47,32 +47,26 @@ namespace Core
|
|||||||
// Broadcasts when any two items are successfully combined
|
// Broadcasts when any two items are successfully combined
|
||||||
// Args: first item data, second item data, result item data
|
// Args: first item data, second item data, result item data
|
||||||
public event Action<PickupItemData, PickupItemData, PickupItemData> OnItemsCombined;
|
public event Action<PickupItemData, PickupItemData, PickupItemData> OnItemsCombined;
|
||||||
|
|
||||||
public override int ManagedAwakePriority => 75; // Item registry
|
|
||||||
|
|
||||||
private new void Awake()
|
internal override void OnManagedAwake()
|
||||||
{
|
{
|
||||||
base.Awake(); // CRITICAL: Register with LifecycleManager!
|
// Set instance immediately (early initialization)
|
||||||
|
|
||||||
// Set instance immediately so it's available before OnManagedAwake() is called
|
|
||||||
_instance = this;
|
_instance = this;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnManagedAwake()
|
internal override void OnManagedStart()
|
||||||
{
|
{
|
||||||
Logging.Debug("[ItemManager] Initialized");
|
Logging.Debug("[ItemManager] Initialized");
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnSceneReady()
|
internal override void OnSceneReady()
|
||||||
{
|
{
|
||||||
// Replaces SceneLoadStarted subscription for clearing registrations
|
// Replaces SceneLoadStarted subscription for clearing registrations
|
||||||
ClearAllRegistrations();
|
ClearAllRegistrations();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnDestroy()
|
internal override void OnManagedDestroy()
|
||||||
{
|
{
|
||||||
base.OnDestroy();
|
|
||||||
|
|
||||||
// Ensure we clean up any subscriptions from registered items when the manager is destroyed
|
// Ensure we clean up any subscriptions from registered items when the manager is destroyed
|
||||||
ClearAllRegistrations();
|
ClearAllRegistrations();
|
||||||
}
|
}
|
||||||
@@ -144,7 +138,6 @@ namespace Core
|
|||||||
{
|
{
|
||||||
s.OnCorrectItemSlotted -= ItemSlot_OnCorrectItemSlotted;
|
s.OnCorrectItemSlotted -= ItemSlot_OnCorrectItemSlotted;
|
||||||
s.OnIncorrectItemSlotted -= ItemSlot_OnIncorrectItemSlotted;
|
s.OnIncorrectItemSlotted -= ItemSlot_OnIncorrectItemSlotted;
|
||||||
s.OnForbiddenItemSlotted -= ItemSlot_OnForbiddenItemSlotted;
|
|
||||||
s.OnItemSlotRemoved -= ItemSlot_OnItemSlotRemoved;
|
s.OnItemSlotRemoved -= ItemSlot_OnItemSlotRemoved;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -191,7 +184,6 @@ namespace Core
|
|||||||
// Subscribe to all slot events
|
// Subscribe to all slot events
|
||||||
slot.OnCorrectItemSlotted += ItemSlot_OnCorrectItemSlotted;
|
slot.OnCorrectItemSlotted += ItemSlot_OnCorrectItemSlotted;
|
||||||
slot.OnIncorrectItemSlotted += ItemSlot_OnIncorrectItemSlotted;
|
slot.OnIncorrectItemSlotted += ItemSlot_OnIncorrectItemSlotted;
|
||||||
slot.OnForbiddenItemSlotted += ItemSlot_OnForbiddenItemSlotted;
|
|
||||||
slot.OnItemSlotRemoved += ItemSlot_OnItemSlotRemoved;
|
slot.OnItemSlotRemoved += ItemSlot_OnItemSlotRemoved;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -204,7 +196,6 @@ namespace Core
|
|||||||
// Unsubscribe from all slot events
|
// Unsubscribe from all slot events
|
||||||
slot.OnCorrectItemSlotted -= ItemSlot_OnCorrectItemSlotted;
|
slot.OnCorrectItemSlotted -= ItemSlot_OnCorrectItemSlotted;
|
||||||
slot.OnIncorrectItemSlotted -= ItemSlot_OnIncorrectItemSlotted;
|
slot.OnIncorrectItemSlotted -= ItemSlot_OnIncorrectItemSlotted;
|
||||||
slot.OnForbiddenItemSlotted -= ItemSlot_OnForbiddenItemSlotted;
|
|
||||||
slot.OnItemSlotRemoved -= ItemSlot_OnItemSlotRemoved;
|
slot.OnItemSlotRemoved -= ItemSlot_OnItemSlotRemoved;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,12 +6,19 @@
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public enum LifecyclePhase
|
public enum LifecyclePhase
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Called immediately during registration (during Awake).
|
||||||
|
/// Use for early initialization such as setting singleton instances.
|
||||||
|
/// NOT ordered - fires whenever Unity calls this component's Awake().
|
||||||
|
/// </summary>
|
||||||
|
ManagedAwake,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Called once per component after bootstrap completes.
|
/// Called once per component after bootstrap completes.
|
||||||
/// Guaranteed to be called after all bootstrap resources are loaded.
|
/// Guaranteed to be called after all bootstrap resources are loaded.
|
||||||
/// For late-registered components, called immediately upon registration.
|
/// For late-registered components, called immediately upon registration.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
ManagedAwake,
|
ManagedStart,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Called before a scene is unloaded.
|
/// Called before a scene is unloaded.
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
|
||||||
@@ -27,7 +27,7 @@ namespace Core.Lifecycle
|
|||||||
{
|
{
|
||||||
if (_instance != null)
|
if (_instance != null)
|
||||||
{
|
{
|
||||||
Debug.LogWarning("[LifecycleManager] Instance already exists");
|
Logging.Warning("[LifecycleManager] Instance already exists");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -35,7 +35,7 @@ namespace Core.Lifecycle
|
|||||||
_instance = go.AddComponent<LifecycleManager>();
|
_instance = go.AddComponent<LifecycleManager>();
|
||||||
DontDestroyOnLoad(go);
|
DontDestroyOnLoad(go);
|
||||||
|
|
||||||
Debug.Log("[LifecycleManager] Instance created");
|
Logging.Debug("[LifecycleManager] Instance created");
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
@@ -59,11 +59,11 @@ namespace Core.Lifecycle
|
|||||||
|
|
||||||
#region State Flags
|
#region State Flags
|
||||||
|
|
||||||
private bool isBootComplete = false;
|
private bool isBootComplete;
|
||||||
private string currentSceneReady = "";
|
private string currentSceneReady = "";
|
||||||
|
|
||||||
// Scene loading state tracking
|
// Scene loading state tracking
|
||||||
private bool isLoadingScene = false;
|
private bool isLoadingScene;
|
||||||
private string sceneBeingLoaded = "";
|
private string sceneBeingLoaded = "";
|
||||||
private List<ManagedBehaviour> pendingSceneComponents = new List<ManagedBehaviour>();
|
private List<ManagedBehaviour> pendingSceneComponents = new List<ManagedBehaviour>();
|
||||||
|
|
||||||
@@ -85,7 +85,7 @@ namespace Core.Lifecycle
|
|||||||
}
|
}
|
||||||
else if (_instance != this)
|
else if (_instance != this)
|
||||||
{
|
{
|
||||||
Debug.LogWarning("[LifecycleManager] Duplicate instance detected. Destroying.");
|
Logging.Warning("[LifecycleManager] Duplicate instance detected. Destroying.");
|
||||||
Destroy(gameObject);
|
Destroy(gameObject);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -111,7 +111,7 @@ namespace Core.Lifecycle
|
|||||||
{
|
{
|
||||||
if (component == null)
|
if (component == null)
|
||||||
{
|
{
|
||||||
Debug.LogWarning("[LifecycleManager] Attempted to register null component");
|
Logging.Warning("[LifecycleManager] Attempted to register null component");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -120,43 +120,49 @@ namespace Core.Lifecycle
|
|||||||
// Track which scene this component belongs to
|
// Track which scene this component belongs to
|
||||||
componentScenes[component] = sceneName;
|
componentScenes[component] = sceneName;
|
||||||
|
|
||||||
// ALWAYS add to managedAwakeList - this is the master list used for save/load
|
// Add to all lifecycle lists (order of registration determines execution order)
|
||||||
InsertSorted(managedAwakeList, component, component.ManagedAwakePriority);
|
managedAwakeList.Add(component);
|
||||||
|
sceneUnloadingList.Add(component);
|
||||||
|
sceneReadyList.Add(component);
|
||||||
|
saveRequestedList.Add(component);
|
||||||
|
restoreRequestedList.Add(component);
|
||||||
|
destroyList.Add(component);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
component.OnManagedAwake();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Debug.LogError($"[LifecycleManager] Error in OnManagedAwake for {component.gameObject.name}: {ex}");
|
||||||
|
}
|
||||||
|
|
||||||
// Handle ManagedAwake timing based on boot state
|
// Handle OnManagedStart timing based on boot state
|
||||||
if (isBootComplete)
|
if (isBootComplete)
|
||||||
{
|
{
|
||||||
// Check if we're currently loading a scene
|
// Check if we're currently loading a scene
|
||||||
if (isLoadingScene && sceneName == sceneBeingLoaded)
|
if (isLoadingScene && sceneName == sceneBeingLoaded)
|
||||||
{
|
{
|
||||||
// Batch this component - will be processed in priority order when scene load completes
|
// Batch this component - will be processed when scene load completes
|
||||||
pendingSceneComponents.Add(component);
|
pendingSceneComponents.Add(component);
|
||||||
LogDebug($"Batched component for scene load: {component.gameObject.name} (Scene: {sceneName})");
|
LogDebug($"Batched component for scene load: {component.gameObject.name} (Scene: {sceneName})");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Truly late registration (component enabled after scene is ready)
|
// Truly late registration (component enabled after scene is ready)
|
||||||
// Call OnManagedAwake immediately since boot already completed
|
// Call OnManagedStart immediately since boot already completed
|
||||||
LogDebug($"Late registration: Calling OnManagedAwake immediately for {component.gameObject.name}");
|
LogDebug($"Late registration: Calling OnManagedStart immediately for {component.gameObject.name}");
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
component.InvokeManagedAwake();
|
component.OnManagedStart();
|
||||||
HandleAutoRegistrations(component);
|
HandleAutoRegistrations(component);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Debug.LogError($"[LifecycleManager] Error in OnManagedAwake for {component.gameObject.name}: {ex}");
|
Debug.LogError($"[LifecycleManager] Error in OnManagedStart for {component.gameObject.name}: {ex}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// If boot not complete, component stays in list and will be processed by BroadcastManagedAwake()
|
// If boot not complete, component stays in list and will be processed by BroadcastManagedStart()
|
||||||
|
|
||||||
// Register for all scene lifecycle hooks
|
|
||||||
InsertSorted(sceneUnloadingList, component, component.SceneUnloadingPriority);
|
|
||||||
InsertSorted(sceneReadyList, component, component.SceneReadyPriority);
|
|
||||||
InsertSorted(saveRequestedList, component, component.SavePriority);
|
|
||||||
InsertSorted(restoreRequestedList, component, component.RestorePriority);
|
|
||||||
InsertSorted(destroyList, component, component.DestroyPriority);
|
|
||||||
|
|
||||||
// If this scene is already ready (and we're not in loading mode), call OnSceneReady immediately
|
// If this scene is already ready (and we're not in loading mode), call OnSceneReady immediately
|
||||||
if (!isLoadingScene && currentSceneReady == sceneName)
|
if (!isLoadingScene && currentSceneReady == sceneName)
|
||||||
@@ -164,7 +170,7 @@ namespace Core.Lifecycle
|
|||||||
LogDebug($"Late registration: Calling OnSceneReady immediately for {component.gameObject.name}");
|
LogDebug($"Late registration: Calling OnSceneReady immediately for {component.gameObject.name}");
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
component.InvokeSceneReady();
|
component.OnSceneReady();
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -202,7 +208,7 @@ namespace Core.Lifecycle
|
|||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Called by CustomBoot when boot completes.
|
/// Called by CustomBoot when boot completes.
|
||||||
/// Broadcasts ManagedAwake to all registered components.
|
/// Broadcasts ManagedStart to all registered components.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void OnBootCompletionTriggered()
|
public void OnBootCompletionTriggered()
|
||||||
{
|
{
|
||||||
@@ -210,16 +216,16 @@ namespace Core.Lifecycle
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
LogDebug("=== Boot Completion Triggered ===");
|
LogDebug("=== Boot Completion Triggered ===");
|
||||||
BroadcastManagedAwake();
|
BroadcastManagedStart();
|
||||||
isBootComplete = true;
|
isBootComplete = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Broadcast OnManagedAwake to all registered components (priority ordered).
|
/// Broadcast OnManagedStart to all registered components (priority ordered).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private void BroadcastManagedAwake()
|
private void BroadcastManagedStart()
|
||||||
{
|
{
|
||||||
LogDebug($"Broadcasting ManagedAwake to {managedAwakeList.Count} components");
|
LogDebug($"Broadcasting ManagedStart to {managedAwakeList.Count} components");
|
||||||
|
|
||||||
// Create a copy to avoid collection modification during iteration
|
// Create a copy to avoid collection modification during iteration
|
||||||
var componentsCopy = new List<ManagedBehaviour>(managedAwakeList);
|
var componentsCopy = new List<ManagedBehaviour>(managedAwakeList);
|
||||||
@@ -230,12 +236,12 @@ namespace Core.Lifecycle
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
component.InvokeManagedAwake();
|
component.OnManagedStart();
|
||||||
HandleAutoRegistrations(component);
|
HandleAutoRegistrations(component);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Debug.LogError($"[LifecycleManager] Error in OnManagedAwake for {component.gameObject.name}: {ex}");
|
Debug.LogError($"[LifecycleManager] Error in OnManagedStart for {component.gameObject.name}: {ex}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -272,23 +278,20 @@ namespace Core.Lifecycle
|
|||||||
|
|
||||||
LogDebug($"Processing {pendingSceneComponents.Count} batched components for scene: {sceneBeingLoaded}");
|
LogDebug($"Processing {pendingSceneComponents.Count} batched components for scene: {sceneBeingLoaded}");
|
||||||
|
|
||||||
// Sort by ManagedAwake priority (lower values first)
|
// Call OnManagedStart in registration order
|
||||||
pendingSceneComponents.Sort((a, b) => a.ManagedAwakePriority.CompareTo(b.ManagedAwakePriority));
|
|
||||||
|
|
||||||
// Call OnManagedAwake in priority order
|
|
||||||
foreach (var component in pendingSceneComponents)
|
foreach (var component in pendingSceneComponents)
|
||||||
{
|
{
|
||||||
if (component == null) continue;
|
if (component == null) continue;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
component.InvokeManagedAwake();
|
component.OnManagedStart();
|
||||||
HandleAutoRegistrations(component);
|
HandleAutoRegistrations(component);
|
||||||
LogDebug($"Processed batched component: {component.gameObject.name} (Priority: {component.ManagedAwakePriority})");
|
LogDebug($"Processed batched component: {component.gameObject.name}");
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Debug.LogError($"[LifecycleManager] Error in OnManagedAwake for batched component {component.gameObject.name}: {ex}");
|
Debug.LogError($"[LifecycleManager] Error in OnManagedStart for batched component {component.gameObject.name}: {ex}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -299,7 +302,7 @@ namespace Core.Lifecycle
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Broadcast OnSceneUnloading to components in the specified scene (reverse priority order).
|
/// Broadcast OnSceneUnloading to components in the specified scene.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void BroadcastSceneUnloading(string sceneName)
|
public void BroadcastSceneUnloading(string sceneName)
|
||||||
{
|
{
|
||||||
@@ -315,7 +318,7 @@ namespace Core.Lifecycle
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
component.InvokeSceneUnloading();
|
component.OnSceneUnloading();
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -326,8 +329,8 @@ namespace Core.Lifecycle
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Broadcast OnSceneReady to components in the specified scene (priority order).
|
/// Broadcast OnSceneReady to components in the specified scene.
|
||||||
/// If scene loading mode is active, processes batched components first.
|
/// Processes batched components first, then calls OnSceneReady on all components in that scene.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void BroadcastSceneReady(string sceneName)
|
public void BroadcastSceneReady(string sceneName)
|
||||||
{
|
{
|
||||||
@@ -351,7 +354,7 @@ namespace Core.Lifecycle
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
component.InvokeSceneReady();
|
component.OnSceneReady();
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -379,7 +382,7 @@ namespace Core.Lifecycle
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
string serializedData = component.InvokeSceneSaveRequested();
|
string serializedData = component.OnSceneSaveRequested();
|
||||||
if (!string.IsNullOrEmpty(serializedData))
|
if (!string.IsNullOrEmpty(serializedData))
|
||||||
{
|
{
|
||||||
string saveId = component.SaveId;
|
string saveId = component.SaveId;
|
||||||
@@ -415,7 +418,7 @@ namespace Core.Lifecycle
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
string serializedData = component.InvokeGlobalSaveRequested();
|
string serializedData = component.OnGlobalSaveRequested();
|
||||||
if (!string.IsNullOrEmpty(serializedData))
|
if (!string.IsNullOrEmpty(serializedData))
|
||||||
{
|
{
|
||||||
saveData[component.SaveId] = serializedData;
|
saveData[component.SaveId] = serializedData;
|
||||||
@@ -455,7 +458,7 @@ namespace Core.Lifecycle
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
component.InvokeSceneRestoreRequested(serializedData);
|
component.OnSceneRestoreRequested(serializedData);
|
||||||
restoredCount++;
|
restoredCount++;
|
||||||
LogDebug($"Restored scene data to: {component.SaveId}");
|
LogDebug($"Restored scene data to: {component.SaveId}");
|
||||||
}
|
}
|
||||||
@@ -469,6 +472,34 @@ namespace Core.Lifecycle
|
|||||||
LogDebug($"Restored scene data to {restoredCount} components");
|
LogDebug($"Restored scene data to {restoredCount} components");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Broadcasts scene restore completed event to all registered components.
|
||||||
|
/// Called AFTER all OnSceneRestoreRequested calls complete.
|
||||||
|
/// </summary>
|
||||||
|
public void BroadcastSceneRestoreCompleted()
|
||||||
|
{
|
||||||
|
LogDebug("Broadcasting SceneRestoreCompleted");
|
||||||
|
|
||||||
|
// Create a copy to avoid collection modification during iteration
|
||||||
|
var componentsCopy = new List<ManagedBehaviour>(managedAwakeList);
|
||||||
|
|
||||||
|
foreach (var component in componentsCopy)
|
||||||
|
{
|
||||||
|
if (component == null) continue;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
component.OnSceneRestoreCompleted();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Debug.LogError($"[LifecycleManager] Exception during scene restore completed for {component.SaveId}: {ex}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LogDebug("SceneRestoreCompleted broadcast complete");
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Broadcasts global restore request to all registered components that opt-in.
|
/// Broadcasts global restore request to all registered components that opt-in.
|
||||||
/// Distributes serialized data to matching components by SaveId.
|
/// Distributes serialized data to matching components by SaveId.
|
||||||
@@ -491,7 +522,7 @@ namespace Core.Lifecycle
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
component.InvokeGlobalRestoreRequested(serializedData);
|
component.OnGlobalRestoreRequested(serializedData);
|
||||||
restoredCount++;
|
restoredCount++;
|
||||||
LogDebug($"Restored global data to: {component.SaveId}");
|
LogDebug($"Restored global data to: {component.SaveId}");
|
||||||
}
|
}
|
||||||
@@ -523,7 +554,7 @@ namespace Core.Lifecycle
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
component.InvokeGlobalLoadCompleted();
|
component.OnGlobalLoadCompleted();
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -550,7 +581,7 @@ namespace Core.Lifecycle
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
component.InvokeGlobalSaveStarted();
|
component.OnGlobalSaveStarted();
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -583,42 +614,6 @@ namespace Core.Lifecycle
|
|||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Helper Methods
|
#region Helper Methods
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Insert component into list maintaining sorted order by priority.
|
|
||||||
/// Uses binary search for efficient insertion.
|
|
||||||
/// </summary>
|
|
||||||
private void InsertSorted(List<ManagedBehaviour> list, ManagedBehaviour component, int priority)
|
|
||||||
{
|
|
||||||
// Simple linear insertion for now (can optimize with binary search later if needed)
|
|
||||||
int index = 0;
|
|
||||||
for (int i = 0; i < list.Count; i++)
|
|
||||||
{
|
|
||||||
int existingPriority = GetPriorityForList(list[i], list);
|
|
||||||
if (priority < existingPriority)
|
|
||||||
{
|
|
||||||
index = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
index = i + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
list.Insert(index, component);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Get the priority value for a component based on which list it's in.
|
|
||||||
/// </summary>
|
|
||||||
private int GetPriorityForList(ManagedBehaviour component, List<ManagedBehaviour> list)
|
|
||||||
{
|
|
||||||
if (list == managedAwakeList) return component.ManagedAwakePriority;
|
|
||||||
if (list == sceneUnloadingList) return component.SceneUnloadingPriority;
|
|
||||||
if (list == sceneReadyList) return component.SceneReadyPriority;
|
|
||||||
if (list == saveRequestedList) return component.SavePriority;
|
|
||||||
if (list == restoreRequestedList) return component.RestorePriority;
|
|
||||||
if (list == destroyList) return component.DestroyPriority;
|
|
||||||
return 100;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Log debug message if debug logging is enabled.
|
/// Log debug message if debug logging is enabled.
|
||||||
@@ -627,7 +622,7 @@ namespace Core.Lifecycle
|
|||||||
{
|
{
|
||||||
if (enableDebugLogging)
|
if (enableDebugLogging)
|
||||||
{
|
{
|
||||||
Debug.Log($"[LifecycleManager] {message}");
|
Logging.Debug($"[LifecycleManager] {message}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
using System;
|
using UnityEngine;
|
||||||
using UnityEngine;
|
|
||||||
|
|
||||||
namespace Core.Lifecycle
|
namespace Core.Lifecycle
|
||||||
{
|
{
|
||||||
@@ -9,46 +8,6 @@ namespace Core.Lifecycle
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public abstract class ManagedBehaviour : MonoBehaviour
|
public abstract class ManagedBehaviour : MonoBehaviour
|
||||||
{
|
{
|
||||||
#region Priority Properties
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Priority for OnManagedAwake (lower values execute first).
|
|
||||||
/// Default: 100
|
|
||||||
/// </summary>
|
|
||||||
public virtual int ManagedAwakePriority => 100;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Priority for OnSceneUnloading (executed in reverse: higher values execute first).
|
|
||||||
/// Default: 100
|
|
||||||
/// </summary>
|
|
||||||
public virtual int SceneUnloadingPriority => 100;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Priority for OnSceneReady (lower values execute first).
|
|
||||||
/// Default: 100
|
|
||||||
/// </summary>
|
|
||||||
public virtual int SceneReadyPriority => 100;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Priority for OnSaveRequested (executed in reverse: higher values execute first).
|
|
||||||
/// Default: 100
|
|
||||||
/// </summary>
|
|
||||||
public virtual int SavePriority => 100;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Priority for OnRestoreRequested (lower values execute first).
|
|
||||||
/// Default: 100
|
|
||||||
/// </summary>
|
|
||||||
public virtual int RestorePriority => 100;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Priority for OnManagedDestroy (executed in reverse: higher values execute first).
|
|
||||||
/// Default: 100
|
|
||||||
/// </summary>
|
|
||||||
public virtual int DestroyPriority => 100;
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Configuration Properties
|
#region Configuration Properties
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -68,38 +27,28 @@ namespace Core.Lifecycle
|
|||||||
/// Unique identifier for this component in the save system.
|
/// Unique identifier for this component in the save system.
|
||||||
/// Default: "SceneName/GameObjectName/ComponentType"
|
/// Default: "SceneName/GameObjectName/ComponentType"
|
||||||
/// Override ONLY for special cases (e.g., singletons like "PlayerController", or custom IDs).
|
/// Override ONLY for special cases (e.g., singletons like "PlayerController", or custom IDs).
|
||||||
|
/// Cached on first access to avoid runtime allocation.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public virtual string SaveId
|
public virtual string SaveId
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
string sceneName = gameObject.scene.IsValid() ? gameObject.scene.name : "UnknownScene";
|
if (_cachedSaveId == null)
|
||||||
string componentType = GetType().Name;
|
{
|
||||||
return $"{sceneName}/{gameObject.name}/{componentType}";
|
string sceneName = gameObject.scene.IsValid() ? gameObject.scene.name : "UnknownScene";
|
||||||
|
string componentType = GetType().Name;
|
||||||
|
_cachedSaveId = $"{sceneName}/{gameObject.name}/{componentType}";
|
||||||
|
}
|
||||||
|
return _cachedSaveId;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Public Accessors (for LifecycleManager)
|
|
||||||
|
|
||||||
// Public wrappers to invoke protected lifecycle methods
|
|
||||||
public void InvokeManagedAwake() => OnManagedAwake();
|
|
||||||
public void InvokeSceneUnloading() => OnSceneUnloading();
|
|
||||||
public void InvokeSceneReady() => OnSceneReady();
|
|
||||||
public string InvokeSceneSaveRequested() => OnSceneSaveRequested();
|
|
||||||
public void InvokeSceneRestoreRequested(string data) => OnSceneRestoreRequested(data);
|
|
||||||
public string InvokeGlobalSaveRequested() => OnGlobalSaveRequested();
|
|
||||||
public void InvokeGlobalRestoreRequested(string data) => OnGlobalRestoreRequested(data);
|
|
||||||
public void InvokeManagedDestroy() => OnManagedDestroy();
|
|
||||||
public void InvokeGlobalLoadCompleted() => OnGlobalLoadCompleted();
|
|
||||||
public void InvokeGlobalSaveStarted() => OnGlobalSaveStarted();
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Private Fields
|
#region Private Fields
|
||||||
|
|
||||||
private bool _isRegistered;
|
private bool _isRegistered;
|
||||||
|
private string _cachedSaveId;
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
@@ -107,9 +56,9 @@ namespace Core.Lifecycle
|
|||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Unity Awake - automatically registers with LifecycleManager.
|
/// Unity Awake - automatically registers with LifecycleManager.
|
||||||
/// IMPORTANT: Derived classes that override Awake MUST call base.Awake()
|
/// SEALED: Cannot be overridden. Use OnManagedAwake() for early initialization or OnManagedStart() for late initialization.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected virtual void Awake()
|
private void Awake()
|
||||||
{
|
{
|
||||||
if (LifecycleManager.Instance != null)
|
if (LifecycleManager.Instance != null)
|
||||||
{
|
{
|
||||||
@@ -118,19 +67,22 @@ namespace Core.Lifecycle
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Debug.LogWarning($"[ManagedBehaviour] LifecycleManager not found for {gameObject.name}. Component will not receive lifecycle callbacks.");
|
Logging.Warning($"[ManagedBehaviour] LifecycleManager not found for {gameObject.name}. Component will not receive lifecycle callbacks.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Unity OnDestroy - automatically unregisters and cleans up.
|
/// Unity OnDestroy - automatically unregisters and cleans up.
|
||||||
/// IMPORTANT: Derived classes that override OnDestroy MUST call base.OnDestroy()
|
/// SEALED: Cannot be overridden. Use OnManagedDestroy() for custom cleanup logic.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected virtual void OnDestroy()
|
private void OnDestroy()
|
||||||
{
|
{
|
||||||
if (!_isRegistered)
|
if (!_isRegistered)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
// Call managed destroy hook
|
||||||
|
OnManagedDestroy();
|
||||||
|
|
||||||
// Unregister from LifecycleManager
|
// Unregister from LifecycleManager
|
||||||
if (LifecycleManager.Instance != null)
|
if (LifecycleManager.Instance != null)
|
||||||
{
|
{
|
||||||
@@ -151,34 +103,47 @@ namespace Core.Lifecycle
|
|||||||
|
|
||||||
#region Managed Lifecycle Hooks
|
#region Managed Lifecycle Hooks
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Called immediately during registration (during Awake).
|
||||||
|
/// Use for early initialization such as setting singleton instances.
|
||||||
|
/// TIMING: Fires during component's Awake(), no execution order guarantees between components.
|
||||||
|
/// NOT priority-ordered - fires whenever Unity calls this component's Awake().
|
||||||
|
/// NOTE: Internal visibility allows LifecycleManager to call directly. Override in derived classes.
|
||||||
|
/// </summary>
|
||||||
|
internal virtual void OnManagedAwake()
|
||||||
|
{
|
||||||
|
// Override in derived classes
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Called once per component after bootstrap completes.
|
/// Called once per component after bootstrap completes.
|
||||||
/// GUARANTEE: Bootstrap resources are available, all managers are initialized.
|
/// GUARANTEE: Bootstrap resources are available, all managers are initialized.
|
||||||
/// For boot-time components: Called during LifecycleManager.BroadcastManagedAwake (priority ordered).
|
/// For boot-time components: Called during LifecycleManager.BroadcastManagedStart (registration order).
|
||||||
/// For late-registered components: Called immediately upon registration (bootstrap already complete).
|
/// For late-registered components: Called immediately upon registration (bootstrap already complete).
|
||||||
/// Replaces the old Awake + InitializePostBoot pattern.
|
/// Use for initialization that depends on other systems.
|
||||||
|
/// NOTE: Internal visibility allows LifecycleManager to call directly. Override in derived classes.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected virtual void OnManagedAwake()
|
internal virtual void OnManagedStart()
|
||||||
{
|
{
|
||||||
// Override in derived classes
|
// Override in derived classes
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Called before the scene this component belongs to is unloaded.
|
/// Called before the scene this component belongs to is unloaded.
|
||||||
/// Called in REVERSE priority order (higher values execute first).
|
|
||||||
/// Use for scene-specific cleanup.
|
/// Use for scene-specific cleanup.
|
||||||
|
/// NOTE: Internal visibility allows LifecycleManager to call directly. Override in derived classes.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected virtual void OnSceneUnloading()
|
internal virtual void OnSceneUnloading()
|
||||||
{
|
{
|
||||||
// Override in derived classes
|
// Override in derived classes
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Called after the scene this component belongs to has finished loading.
|
/// Called after the scene this component belongs to has finished loading.
|
||||||
/// Called in priority order (lower values execute first).
|
|
||||||
/// Use for scene-specific initialization.
|
/// Use for scene-specific initialization.
|
||||||
|
/// NOTE: Internal visibility allows LifecycleManager to call directly. Override in derived classes.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected virtual void OnSceneReady()
|
internal virtual void OnSceneReady()
|
||||||
{
|
{
|
||||||
// Override in derived classes
|
// Override in derived classes
|
||||||
}
|
}
|
||||||
@@ -192,8 +157,10 @@ namespace Core.Lifecycle
|
|||||||
/// - Called BEFORE scene unload during scene transitions
|
/// - Called BEFORE scene unload during scene transitions
|
||||||
/// - Frequency: Every scene transition
|
/// - Frequency: Every scene transition
|
||||||
/// - Use for: Level progress, object positions, puzzle states
|
/// - Use for: Level progress, object positions, puzzle states
|
||||||
|
///
|
||||||
|
/// NOTE: Internal visibility allows LifecycleManager to call directly. Override in derived classes.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected virtual string OnSceneSaveRequested()
|
internal virtual string OnSceneSaveRequested()
|
||||||
{
|
{
|
||||||
return null; // Default: no data to save
|
return null; // Default: no data to save
|
||||||
}
|
}
|
||||||
@@ -202,12 +169,43 @@ namespace Core.Lifecycle
|
|||||||
/// Called during scene transitions to restore scene-specific state.
|
/// Called during scene transitions to restore scene-specific state.
|
||||||
/// Receives previously serialized data (from OnSceneSaveRequested).
|
/// Receives previously serialized data (from OnSceneSaveRequested).
|
||||||
///
|
///
|
||||||
|
/// IMPORTANT: This method MUST be synchronous. Do not use coroutines or async/await.
|
||||||
|
/// OnSceneRestoreCompleted is called immediately after all restore calls complete,
|
||||||
|
/// so any async operations would still be running when it fires.
|
||||||
|
///
|
||||||
/// TIMING:
|
/// TIMING:
|
||||||
/// - Called AFTER scene load, during OnSceneReady phase
|
/// - Called AFTER scene load, during OnSceneReady phase
|
||||||
/// - Frequency: Every scene transition
|
/// - Frequency: Every scene transition
|
||||||
/// - Use for: Restoring level progress, object positions, puzzle states
|
/// - Use for: Restoring level progress, object positions, puzzle states
|
||||||
|
///
|
||||||
|
/// NOTE: Internal visibility allows LifecycleManager to call directly. Override in derived classes.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected virtual void OnSceneRestoreRequested(string serializedData)
|
internal virtual void OnSceneRestoreRequested(string serializedData)
|
||||||
|
{
|
||||||
|
// Default: no-op
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Called after all scene restore operations complete.
|
||||||
|
/// Does NOT receive data - use OnSceneRestoreRequested for that.
|
||||||
|
///
|
||||||
|
/// GUARANTEE:
|
||||||
|
/// - ALWAYS called after scene load, whether there's save data or not
|
||||||
|
/// - All OnSceneRestoreRequested() calls have RETURNED (but async operations may still be running)
|
||||||
|
/// - Safe for synchronous restore operations (JSON deserialization, setting fields, etc.)
|
||||||
|
///
|
||||||
|
/// TIMING:
|
||||||
|
/// - Called AFTER all OnSceneRestoreRequested calls complete (or immediately if no save data exists)
|
||||||
|
/// - Frequency: Every scene transition
|
||||||
|
/// - Use for: Post-restore initialization, first-time initialization, triggering events after state is restored
|
||||||
|
///
|
||||||
|
/// COMMON PATTERN:
|
||||||
|
/// Use this to perform actions that depend on whether data was restored or not.
|
||||||
|
/// Example: Play one-time audio only if it hasn't been played before (_hasPlayed == false).
|
||||||
|
///
|
||||||
|
/// NOTE: Internal visibility allows LifecycleManager to call directly. Override in derived classes.
|
||||||
|
/// </summary>
|
||||||
|
internal virtual void OnSceneRestoreCompleted()
|
||||||
{
|
{
|
||||||
// Default: no-op
|
// Default: no-op
|
||||||
}
|
}
|
||||||
@@ -220,8 +218,10 @@ namespace Core.Lifecycle
|
|||||||
/// - Called ONCE on game boot after save file is read
|
/// - Called ONCE on game boot after save file is read
|
||||||
/// - NOT called during scene transitions
|
/// - NOT called during scene transitions
|
||||||
/// - Use for: Player inventory, unlocked features, card collections
|
/// - Use for: Player inventory, unlocked features, card collections
|
||||||
|
///
|
||||||
|
/// NOTE: Internal visibility allows LifecycleManager to call directly. Override in derived classes.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected virtual void OnGlobalRestoreRequested(string serializedData)
|
internal virtual void OnGlobalRestoreRequested(string serializedData)
|
||||||
{
|
{
|
||||||
// Default: no-op
|
// Default: no-op
|
||||||
}
|
}
|
||||||
@@ -235,8 +235,10 @@ namespace Core.Lifecycle
|
|||||||
/// - Called ONCE before save file is written (on quit, manual save, etc.)
|
/// - Called ONCE before save file is written (on quit, manual save, etc.)
|
||||||
/// - NOT called during scene transitions
|
/// - NOT called during scene transitions
|
||||||
/// - Use for: Player inventory, unlocked features, card collections
|
/// - Use for: Player inventory, unlocked features, card collections
|
||||||
|
///
|
||||||
|
/// NOTE: Internal visibility allows LifecycleManager to call directly. Override in derived classes.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected virtual string OnGlobalSaveRequested()
|
internal virtual string OnGlobalSaveRequested()
|
||||||
{
|
{
|
||||||
return null; // Default: no data to save
|
return null; // Default: no data to save
|
||||||
}
|
}
|
||||||
@@ -250,8 +252,10 @@ namespace Core.Lifecycle
|
|||||||
/// - Called ONCE on game boot after all restore operations complete
|
/// - Called ONCE on game boot after all restore operations complete
|
||||||
/// - NOT called during scene transitions
|
/// - NOT called during scene transitions
|
||||||
/// - Use for: Triggering UI updates, broadcasting load events
|
/// - Use for: Triggering UI updates, broadcasting load events
|
||||||
|
///
|
||||||
|
/// NOTE: Internal visibility allows LifecycleManager to call directly. Override in derived classes.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected virtual void OnGlobalLoadCompleted()
|
internal virtual void OnGlobalLoadCompleted()
|
||||||
{
|
{
|
||||||
// Default: no-op
|
// Default: no-op
|
||||||
}
|
}
|
||||||
@@ -265,19 +269,21 @@ namespace Core.Lifecycle
|
|||||||
/// - Called ONCE before save file is written
|
/// - Called ONCE before save file is written
|
||||||
/// - NOT called during scene transitions
|
/// - NOT called during scene transitions
|
||||||
/// - Use for: Final validation, cleanup operations
|
/// - Use for: Final validation, cleanup operations
|
||||||
|
///
|
||||||
|
/// NOTE: Internal visibility allows LifecycleManager to call directly. Override in derived classes.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected virtual void OnGlobalSaveStarted()
|
internal virtual void OnGlobalSaveStarted()
|
||||||
{
|
{
|
||||||
// Default: no-op
|
// Default: no-op
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Called during OnDestroy before component is destroyed.
|
/// Called during OnDestroy before component is destroyed.
|
||||||
/// Called in REVERSE priority order (higher values execute first).
|
|
||||||
/// NOTE: Most cleanup is automatic (managed events, auto-registrations).
|
/// NOTE: Most cleanup is automatic (managed events, auto-registrations).
|
||||||
/// Only override if you need custom cleanup logic.
|
/// Only override if you need custom cleanup logic.
|
||||||
|
/// Internal visibility allows LifecycleManager to call directly. Override in derived classes.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected virtual void OnManagedDestroy()
|
internal virtual void OnManagedDestroy()
|
||||||
{
|
{
|
||||||
// Override in derived classes
|
// Override in derived classes
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,17 +1,144 @@
|
|||||||
namespace Core
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace Core
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Centralized logging system with automatic class/method tagging and editor integration.
|
||||||
|
/// Broadcasts log entries to custom editor windows for filtering and analysis.
|
||||||
|
/// </summary>
|
||||||
public static class Logging
|
public static class Logging
|
||||||
{
|
{
|
||||||
[System.Diagnostics.Conditional("ENABLE_LOG")]
|
/// <summary>
|
||||||
public static void Debug(object message)
|
/// Event fired when a new log entry is added. Subscribe to this in editor windows.
|
||||||
|
/// </summary>
|
||||||
|
public static event Action<LogEntry> OnLogEntryAdded;
|
||||||
|
|
||||||
|
// Store recent logs for late-subscriber editor windows (e.g., windows opened after play mode started)
|
||||||
|
private static readonly List<LogEntry> RecentLogs = new List<LogEntry>();
|
||||||
|
private const int MaxStoredLogs = 5000; // Prevent memory bloat
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get all recent logs. Used by editor windows when they first open.
|
||||||
|
/// </summary>
|
||||||
|
public static IReadOnlyList<LogEntry> GetRecentLogs() => RecentLogs;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Clear all stored logs. Useful for editor windows "Clear" button.
|
||||||
|
/// </summary>
|
||||||
|
public static void ClearLogs()
|
||||||
{
|
{
|
||||||
UnityEngine.Debug.Log(message);
|
RecentLogs.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
[System.Diagnostics.Conditional("ENABLE_LOG")]
|
[System.Diagnostics.Conditional("ENABLE_LOG")]
|
||||||
public static void Warning(object message)
|
public static void Debug(string message,
|
||||||
|
[CallerFilePath] string filePath = "",
|
||||||
|
[CallerMemberName] string memberName = "")
|
||||||
{
|
{
|
||||||
UnityEngine.Debug.LogWarning(message);
|
LogInternal(LogLevel.Debug, message, filePath, memberName);
|
||||||
|
}
|
||||||
|
|
||||||
|
[System.Diagnostics.Conditional("ENABLE_LOG")]
|
||||||
|
public static void Info(string message,
|
||||||
|
[CallerFilePath] string filePath = "",
|
||||||
|
[CallerMemberName] string memberName = "")
|
||||||
|
{
|
||||||
|
LogInternal(LogLevel.Info, message, filePath, memberName);
|
||||||
|
}
|
||||||
|
|
||||||
|
[System.Diagnostics.Conditional("ENABLE_LOG")]
|
||||||
|
public static void Warning(string message,
|
||||||
|
[CallerFilePath] string filePath = "",
|
||||||
|
[CallerMemberName] string memberName = "")
|
||||||
|
{
|
||||||
|
LogInternal(LogLevel.Warning, message, filePath, memberName);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Error(string message,
|
||||||
|
[CallerFilePath] string filePath = "",
|
||||||
|
[CallerMemberName] string memberName = "")
|
||||||
|
{
|
||||||
|
LogInternal(LogLevel.Error, message, filePath, memberName);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void LogInternal(LogLevel level, string message, string filePath, string memberName)
|
||||||
|
{
|
||||||
|
string className = Path.GetFileNameWithoutExtension(filePath);
|
||||||
|
string formattedMessage = $"[{className}][{memberName}] {message}";
|
||||||
|
|
||||||
|
// Create log entry
|
||||||
|
var entry = new LogEntry(className, memberName, message, level, Time.realtimeSinceStartup);
|
||||||
|
|
||||||
|
// Store for late subscribers
|
||||||
|
RecentLogs.Add(entry);
|
||||||
|
if (RecentLogs.Count > MaxStoredLogs)
|
||||||
|
RecentLogs.RemoveAt(0);
|
||||||
|
|
||||||
|
// Broadcast to editor windows (editor-only, won't fire in builds)
|
||||||
|
OnLogEntryAdded?.Invoke(entry);
|
||||||
|
|
||||||
|
// Also log to Unity console
|
||||||
|
switch (level)
|
||||||
|
{
|
||||||
|
case LogLevel.Debug:
|
||||||
|
case LogLevel.Info:
|
||||||
|
UnityEngine.Debug.Log(formattedMessage);
|
||||||
|
break;
|
||||||
|
case LogLevel.Warning:
|
||||||
|
UnityEngine.Debug.LogWarning(formattedMessage);
|
||||||
|
break;
|
||||||
|
case LogLevel.Error:
|
||||||
|
UnityEngine.Debug.LogError(formattedMessage);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a single log entry with class, method, message, level, and timestamp.
|
||||||
|
/// </summary>
|
||||||
|
public class LogEntry
|
||||||
|
{
|
||||||
|
public string ClassName { get; }
|
||||||
|
public string MethodName { get; }
|
||||||
|
public string Message { get; }
|
||||||
|
public LogLevel Level { get; }
|
||||||
|
public float Timestamp { get; }
|
||||||
|
|
||||||
|
public LogEntry(string className, string methodName, string message, LogLevel level, float timestamp)
|
||||||
|
{
|
||||||
|
ClassName = className;
|
||||||
|
MethodName = methodName;
|
||||||
|
Message = message;
|
||||||
|
Level = level;
|
||||||
|
Timestamp = timestamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Formatted message with class and method tags.
|
||||||
|
/// Format: [ClassName][MethodName] Message
|
||||||
|
/// </summary>
|
||||||
|
public string FormattedMessage => $"[{ClassName}][{MethodName}] {Message}";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Full formatted message with timestamp and level.
|
||||||
|
/// Format: [12.34s][Debug][ClassName][MethodName] Message
|
||||||
|
/// </summary>
|
||||||
|
public string FullFormattedMessage => $"[{Timestamp:F2}s][{Level}]{FormattedMessage}";
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Log severity levels.
|
||||||
|
/// </summary>
|
||||||
|
public enum LogLevel
|
||||||
|
{
|
||||||
|
Debug,
|
||||||
|
Info,
|
||||||
|
Warning,
|
||||||
|
Error
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -24,9 +24,6 @@ namespace AppleHills.Core
|
|||||||
|
|
||||||
#endregion Singleton Setup
|
#endregion Singleton Setup
|
||||||
|
|
||||||
// Very early initialization - QuickAccess should be available immediately
|
|
||||||
public override int ManagedAwakePriority => 5;
|
|
||||||
|
|
||||||
#region Manager Instances
|
#region Manager Instances
|
||||||
|
|
||||||
// Core Managers
|
// Core Managers
|
||||||
@@ -129,20 +126,18 @@ namespace AppleHills.Core
|
|||||||
|
|
||||||
#region Lifecycle Methods
|
#region Lifecycle Methods
|
||||||
|
|
||||||
private new void Awake()
|
internal override void OnManagedAwake()
|
||||||
{
|
{
|
||||||
base.Awake(); // CRITICAL: Register with LifecycleManager!
|
// Set instance immediately (early initialization)
|
||||||
|
|
||||||
// Set instance immediately so it's available before OnManagedAwake() is called
|
|
||||||
_instance = this;
|
_instance = this;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnManagedAwake()
|
internal override void OnManagedStart()
|
||||||
{
|
{
|
||||||
// QuickAccess has minimal initialization
|
// QuickAccess has minimal initialization
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnSceneUnloading()
|
internal override void OnSceneUnloading()
|
||||||
{
|
{
|
||||||
// Clear references BEFORE scene unloads for better cleanup timing
|
// Clear references BEFORE scene unloads for better cleanup timing
|
||||||
ClearReferences();
|
ClearReferences();
|
||||||
|
|||||||
@@ -88,7 +88,7 @@ namespace Core.SaveLoad
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Debug.LogWarning($"[AppleMachine] SaveLoadManager not available for '{name}'", this);
|
Logging.Warning($"[AppleMachine] SaveLoadManager not available for '{name}'");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -98,7 +98,7 @@ namespace Core.SaveLoad
|
|||||||
// Optional: Log the auto-generated ID in verbose mode
|
// Optional: Log the auto-generated ID in verbose mode
|
||||||
if (verbose && string.IsNullOrEmpty(customSaveId))
|
if (verbose && string.IsNullOrEmpty(customSaveId))
|
||||||
{
|
{
|
||||||
Debug.Log($"[SaveableStateMachine] '{name}' will use auto-generated Save ID: {GetSaveId()}", this);
|
Logging.Debug($"[SaveableStateMachine] '{name}' will use auto-generated Save ID: {GetSaveId()}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -158,7 +158,7 @@ namespace Core.SaveLoad
|
|||||||
{
|
{
|
||||||
if (verbose)
|
if (verbose)
|
||||||
{
|
{
|
||||||
Debug.LogWarning($"[SaveableStateMachine] No data to restore for '{name}'", this);
|
Logging.Warning($"[SaveableStateMachine] No data to restore for '{name}'");
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -171,7 +171,7 @@ namespace Core.SaveLoad
|
|||||||
{
|
{
|
||||||
if (verbose)
|
if (verbose)
|
||||||
{
|
{
|
||||||
Debug.LogWarning($"[SaveableStateMachine] No state name in save data for '{name}'", this);
|
Logging.Warning($"[SaveableStateMachine] No state name in save data for '{name}'");
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -197,7 +197,7 @@ namespace Core.SaveLoad
|
|||||||
|
|
||||||
if (verbose)
|
if (verbose)
|
||||||
{
|
{
|
||||||
Debug.Log($"[SaveableStateMachine] Restored '{name}' to state: {saveData.stateName}", this);
|
Logging.Debug($"[SaveableStateMachine] Restored '{name}' to state: {saveData.stateName}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (System.Exception ex)
|
catch (System.Exception ex)
|
||||||
@@ -215,14 +215,14 @@ namespace Core.SaveLoad
|
|||||||
[ContextMenu("Log Save ID")]
|
[ContextMenu("Log Save ID")]
|
||||||
private void LogSaveId()
|
private void LogSaveId()
|
||||||
{
|
{
|
||||||
Debug.Log($"Save ID: {GetSaveId()}", this);
|
Logging.Debug($"Save ID: {GetSaveId()}");
|
||||||
}
|
}
|
||||||
|
|
||||||
[ContextMenu("Test Serialize")]
|
[ContextMenu("Test Serialize")]
|
||||||
private void TestSerialize()
|
private void TestSerialize()
|
||||||
{
|
{
|
||||||
string serialized = SerializeState();
|
string serialized = SerializeState();
|
||||||
Debug.Log($"Serialized state: {serialized}", this);
|
Logging.Debug($"Serialized state: {serialized}");
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -43,14 +43,10 @@ namespace Core.SaveLoad
|
|||||||
public event Action<string> OnLoadCompleted;
|
public event Action<string> OnLoadCompleted;
|
||||||
public event Action OnParticipantStatesRestored;
|
public event Action OnParticipantStatesRestored;
|
||||||
|
|
||||||
// ManagedBehaviour configuration
|
|
||||||
public override int ManagedAwakePriority => 20; // After GameManager and SceneManagerService
|
|
||||||
|
|
||||||
private new void Awake()
|
internal override void OnManagedAwake()
|
||||||
{
|
{
|
||||||
base.Awake(); // CRITICAL: Register with LifecycleManager!
|
// Set instance immediately (early initialization)
|
||||||
|
|
||||||
// Set instance immediately so it's available before OnManagedAwake() is called
|
|
||||||
_instance = this;
|
_instance = this;
|
||||||
|
|
||||||
// Initialize critical state immediately
|
// Initialize critical state immediately
|
||||||
@@ -58,7 +54,7 @@ namespace Core.SaveLoad
|
|||||||
IsRestoringState = false;
|
IsRestoringState = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnManagedAwake()
|
internal override void OnManagedStart()
|
||||||
{
|
{
|
||||||
Logging.Debug("[SaveLoadManager] Initialized");
|
Logging.Debug("[SaveLoadManager] Initialized");
|
||||||
|
|
||||||
@@ -69,19 +65,19 @@ namespace Core.SaveLoad
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnSceneReady()
|
internal override void OnSceneReady()
|
||||||
{
|
{
|
||||||
// SaveableInteractables now auto-register via ManagedBehaviour lifecycle
|
// SaveableInteractables now auto-register via ManagedBehaviour lifecycle
|
||||||
// No need to discover and register them manually
|
// No need to discover and register them manually
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override string OnSceneSaveRequested()
|
internal override string OnSceneSaveRequested()
|
||||||
{
|
{
|
||||||
// SaveLoadManager orchestrates saves, doesn't participate in them
|
// SaveLoadManager orchestrates saves, doesn't participate in them
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override string OnGlobalSaveRequested()
|
internal override string OnGlobalSaveRequested()
|
||||||
{
|
{
|
||||||
// SaveLoadManager orchestrates saves, doesn't participate in them
|
// SaveLoadManager orchestrates saves, doesn't participate in them
|
||||||
return null;
|
return null;
|
||||||
@@ -97,10 +93,8 @@ namespace Core.SaveLoad
|
|||||||
|
|
||||||
// ...existing code...
|
// ...existing code...
|
||||||
|
|
||||||
protected override void OnDestroy()
|
internal override void OnManagedDestroy()
|
||||||
{
|
{
|
||||||
base.OnDestroy(); // Important: call base to unregister from LifecycleManager
|
|
||||||
|
|
||||||
if (_instance == this)
|
if (_instance == this)
|
||||||
{
|
{
|
||||||
_instance = null;
|
_instance = null;
|
||||||
@@ -504,9 +498,19 @@ namespace Core.SaveLoad
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public void RestoreSceneData()
|
public void RestoreSceneData()
|
||||||
{
|
{
|
||||||
|
if (Lifecycle.LifecycleManager.Instance == null)
|
||||||
|
{
|
||||||
|
Logging.Warning("[SaveLoadManager] LifecycleManager not available for scene restore");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (currentSaveData == null || currentSaveData.participantStates == null)
|
if (currentSaveData == null || currentSaveData.participantStates == null)
|
||||||
{
|
{
|
||||||
Logging.Debug("[SaveLoadManager] No scene data to restore");
|
Logging.Debug("[SaveLoadManager] No scene data to restore (first visit or no save data)");
|
||||||
|
|
||||||
|
// Still broadcast restore completed so components can initialize properly
|
||||||
|
Lifecycle.LifecycleManager.Instance.BroadcastSceneRestoreCompleted();
|
||||||
|
Logging.Debug($"[SaveLoadManager] Scene restore completed (no data)");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -520,11 +524,12 @@ namespace Core.SaveLoad
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Restore scene data via LifecycleManager
|
// Restore scene data via LifecycleManager
|
||||||
if (Lifecycle.LifecycleManager.Instance != null)
|
Lifecycle.LifecycleManager.Instance.BroadcastSceneRestoreRequested(saveDataDict);
|
||||||
{
|
Logging.Debug($"[SaveLoadManager] Broadcast scene restore to LifecycleManager");
|
||||||
Lifecycle.LifecycleManager.Instance.BroadcastSceneRestoreRequested(saveDataDict);
|
|
||||||
Logging.Debug($"[SaveLoadManager] Broadcast scene restore to LifecycleManager");
|
// Broadcast scene restore completed - ALWAYS called, whether there's data or not
|
||||||
}
|
Lifecycle.LifecycleManager.Instance.BroadcastSceneRestoreCompleted();
|
||||||
|
Logging.Debug($"[SaveLoadManager] Scene restore completed");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -706,7 +711,7 @@ namespace Core.SaveLoad
|
|||||||
{
|
{
|
||||||
IsSaving = false;
|
IsSaving = false;
|
||||||
OnSaveCompleted?.Invoke(slot);
|
OnSaveCompleted?.Invoke(slot);
|
||||||
Debug.Log($"[SaveLoadManager] Save completed for slot '{slot}'");
|
Logging.Debug($"[SaveLoadManager] Save completed for slot '{slot}'");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -30,9 +30,9 @@ namespace Core
|
|||||||
// Enable save/load participation
|
// Enable save/load participation
|
||||||
public override bool AutoRegisterForSave => true;
|
public override bool AutoRegisterForSave => true;
|
||||||
|
|
||||||
protected override void Awake()
|
internal override void OnManagedAwake()
|
||||||
{
|
{
|
||||||
base.Awake();
|
base.OnManagedAwake();
|
||||||
|
|
||||||
_director = GetComponent<PlayableDirector>();
|
_director = GetComponent<PlayableDirector>();
|
||||||
if (_director != null)
|
if (_director != null)
|
||||||
@@ -42,10 +42,8 @@ namespace Core
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnDestroy()
|
internal override void OnManagedDestroy()
|
||||||
{
|
{
|
||||||
base.OnDestroy();
|
|
||||||
|
|
||||||
if (_director != null)
|
if (_director != null)
|
||||||
{
|
{
|
||||||
_director.stopped -= OnDirectorStopped;
|
_director.stopped -= OnDirectorStopped;
|
||||||
@@ -65,7 +63,7 @@ namespace Core
|
|||||||
|
|
||||||
#region Save/Load Implementation
|
#region Save/Load Implementation
|
||||||
|
|
||||||
protected override string OnSceneSaveRequested()
|
internal override string OnSceneSaveRequested()
|
||||||
{
|
{
|
||||||
var saveData = new PlayableDirectorSaveData
|
var saveData = new PlayableDirectorSaveData
|
||||||
{
|
{
|
||||||
@@ -77,11 +75,11 @@ namespace Core
|
|||||||
return JsonUtility.ToJson(saveData);
|
return JsonUtility.ToJson(saveData);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnSceneRestoreRequested(string serializedData)
|
internal override void OnSceneRestoreRequested(string serializedData)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(serializedData))
|
if (string.IsNullOrEmpty(serializedData))
|
||||||
{
|
{
|
||||||
Debug.LogWarning($"[SaveablePlayableDirector] No save data to restore for {gameObject.name}");
|
Logging.Warning($"[SaveablePlayableDirector] No save data to restore for {gameObject.name}");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -99,7 +97,7 @@ namespace Core
|
|||||||
_director.time = _director.duration;
|
_director.time = _director.duration;
|
||||||
_director.Evaluate(); // Force evaluation to apply the state
|
_director.Evaluate(); // Force evaluation to apply the state
|
||||||
|
|
||||||
Debug.Log($"[SaveablePlayableDirector] Restored completed timeline '{gameObject.name}' - seeked to end");
|
Logging.Debug($"[SaveablePlayableDirector] Restored completed timeline '{gameObject.name}' - seeked to end");
|
||||||
}
|
}
|
||||||
else if (_hasPlayed && saveData.playbackTime > 0)
|
else if (_hasPlayed && saveData.playbackTime > 0)
|
||||||
{
|
{
|
||||||
@@ -107,7 +105,7 @@ namespace Core
|
|||||||
_director.time = saveData.playbackTime;
|
_director.time = saveData.playbackTime;
|
||||||
_director.Evaluate();
|
_director.Evaluate();
|
||||||
|
|
||||||
Debug.Log($"[SaveablePlayableDirector] Restored timeline '{gameObject.name}' at time {saveData.playbackTime}");
|
Logging.Debug($"[SaveablePlayableDirector] Restored timeline '{gameObject.name}' at time {saveData.playbackTime}");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -115,7 +113,7 @@ namespace Core
|
|||||||
_director.time = 0;
|
_director.time = 0;
|
||||||
_director.Evaluate();
|
_director.Evaluate();
|
||||||
|
|
||||||
Debug.Log($"[SaveablePlayableDirector] Timeline '{gameObject.name}' not yet played - at start");
|
Logging.Debug($"[SaveablePlayableDirector] Timeline '{gameObject.name}' not yet played - at start");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -44,14 +44,10 @@ namespace Core
|
|||||||
private LogVerbosity _logVerbosity = LogVerbosity.Debug;
|
private LogVerbosity _logVerbosity = LogVerbosity.Debug;
|
||||||
private const string BootstrapSceneName = "BootstrapScene";
|
private const string BootstrapSceneName = "BootstrapScene";
|
||||||
|
|
||||||
// ManagedBehaviour configuration
|
|
||||||
public override int ManagedAwakePriority => 15; // Core infrastructure, after GameManager
|
|
||||||
|
|
||||||
private new void Awake()
|
internal override void OnManagedAwake()
|
||||||
{
|
{
|
||||||
base.Awake(); // CRITICAL: Register with LifecycleManager!
|
// Set instance immediately (early initialization)
|
||||||
|
|
||||||
// Set instance immediately so it's available before OnManagedAwake() is called
|
|
||||||
_instance = this;
|
_instance = this;
|
||||||
|
|
||||||
// Initialize current scene tracking - critical for scene management
|
// Initialize current scene tracking - critical for scene management
|
||||||
@@ -65,17 +61,17 @@ namespace Core
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnManagedAwake()
|
internal override void OnManagedStart()
|
||||||
{
|
{
|
||||||
// Set up loading screen reference and events
|
// Set up loading screen reference and events
|
||||||
// This must happen in ManagedAwake because LoadingScreenController instance needs to be set first
|
// This must happen in ManagedStart because LoadingScreenController instance needs to be set first
|
||||||
_loadingScreen = LoadingScreenController.Instance;
|
_loadingScreen = LoadingScreenController.Instance;
|
||||||
SetupLoadingScreenEvents();
|
SetupLoadingScreenEvents();
|
||||||
|
|
||||||
// Load verbosity settings
|
// Load verbosity settings
|
||||||
_logVerbosity = DeveloperSettingsProvider.Instance.GetSettings<DebugSettings>().sceneLogVerbosity;
|
_logVerbosity = DeveloperSettingsProvider.Instance.GetSettings<DebugSettings>().sceneLogVerbosity;
|
||||||
|
|
||||||
LogDebugMessage($"SceneManagerService initialized, current scene is: {CurrentGameplayScene}");
|
Logging.Debug($"SceneManagerService initialized, current scene is: {CurrentGameplayScene}");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -93,19 +89,19 @@ namespace Core
|
|||||||
if (activeScene.name != BootstrapSceneName)
|
if (activeScene.name != BootstrapSceneName)
|
||||||
{
|
{
|
||||||
CurrentGameplayScene = activeScene.name;
|
CurrentGameplayScene = activeScene.name;
|
||||||
LogDebugMessage($"Initialized with current scene: {CurrentGameplayScene}");
|
Logging.Debug($"Initialized with current scene: {CurrentGameplayScene}");
|
||||||
}
|
}
|
||||||
// Otherwise default to MainMenu
|
// Otherwise default to MainMenu
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
CurrentGameplayScene = "AppleHillsOverworld";
|
CurrentGameplayScene = "AppleHillsOverworld";
|
||||||
LogDebugMessage($"Initialized with default scene: {CurrentGameplayScene}");
|
Logging.Debug($"Initialized with default scene: {CurrentGameplayScene}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
CurrentGameplayScene = "AppleHillsOverworld";
|
CurrentGameplayScene = "AppleHillsOverworld";
|
||||||
LogDebugMessage($"No valid active scene, defaulting to: {CurrentGameplayScene}");
|
Logging.Debug($"No valid active scene, defaulting to: {CurrentGameplayScene}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -307,7 +303,7 @@ namespace Core
|
|||||||
}
|
}
|
||||||
|
|
||||||
// PHASE 2: Broadcast scene unloading - notify components to cleanup
|
// PHASE 2: Broadcast scene unloading - notify components to cleanup
|
||||||
LogDebugMessage($"Broadcasting OnSceneUnloading for: {oldSceneName}");
|
Logging.Debug($"Broadcasting OnSceneUnloading for: {oldSceneName}");
|
||||||
LifecycleManager.Instance?.BroadcastSceneUnloading(oldSceneName);
|
LifecycleManager.Instance?.BroadcastSceneUnloading(oldSceneName);
|
||||||
|
|
||||||
// PHASE 3: Save scene-specific data via SaveLoadManager (unless skipSave is true)
|
// PHASE 3: Save scene-specific data via SaveLoadManager (unless skipSave is true)
|
||||||
@@ -316,19 +312,19 @@ namespace Core
|
|||||||
var debugSettings = DeveloperSettingsProvider.Instance.GetSettings<DebugSettings>();
|
var debugSettings = DeveloperSettingsProvider.Instance.GetSettings<DebugSettings>();
|
||||||
if (debugSettings.useSaveLoadSystem)
|
if (debugSettings.useSaveLoadSystem)
|
||||||
{
|
{
|
||||||
LogDebugMessage($"Saving scene data for: {oldSceneName}");
|
Logging.Debug($"Saving scene data for: {oldSceneName}");
|
||||||
SaveLoadManager.Instance.SaveSceneData();
|
SaveLoadManager.Instance.SaveSceneData();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (skipSave)
|
else if (skipSave)
|
||||||
{
|
{
|
||||||
LogDebugMessage($"Skipping save for: {oldSceneName} (skipSave=true)");
|
Logging.Debug($"Skipping save for: {oldSceneName} (skipSave=true)");
|
||||||
}
|
}
|
||||||
|
|
||||||
// PHASE 4: Clear PuzzleManager state before scene transition
|
// PHASE 4: Clear PuzzleManager state before scene transition
|
||||||
if (PuzzleS.PuzzleManager.Instance != null)
|
if (PuzzleS.PuzzleManager.Instance != null)
|
||||||
{
|
{
|
||||||
LogDebugMessage($"Clearing puzzle state before scene transition");
|
Logging.Debug($"Clearing puzzle state before scene transition");
|
||||||
PuzzleS.PuzzleManager.Instance.ClearPuzzleState();
|
PuzzleS.PuzzleManager.Instance.ClearPuzzleState();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -352,7 +348,7 @@ namespace Core
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Logging.Warning($"[SceneManagerService] Previous scene '{oldSceneName}' is not loaded, skipping unload.");
|
Logging.Warning($"Previous scene '{oldSceneName}' is not loaded, skipping unload.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -364,15 +360,15 @@ namespace Core
|
|||||||
}
|
}
|
||||||
|
|
||||||
// PHASE 8: Begin scene loading mode - enables priority-ordered component initialization
|
// PHASE 8: Begin scene loading mode - enables priority-ordered component initialization
|
||||||
LogDebugMessage($"Beginning scene load for: {newSceneName}");
|
Logging.Debug($"Beginning scene load for: {newSceneName}");
|
||||||
LifecycleManager.Instance?.BeginSceneLoad(newSceneName);
|
LifecycleManager.Instance?.BeginSceneLoad(newSceneName);
|
||||||
|
|
||||||
// PHASE 9: Load new gameplay scene
|
// PHASE 9: Load new gameplay scene
|
||||||
await LoadSceneAsync(newSceneName, progress);
|
await LoadSceneAsync(newSceneName, progress);
|
||||||
CurrentGameplayScene = newSceneName;
|
CurrentGameplayScene = newSceneName;
|
||||||
|
|
||||||
// PHASE 10: Broadcast scene ready - processes batched components in priority order, then calls OnSceneReady
|
// PHASE 10: Broadcast scene ready - processes batched components, then calls OnSceneReady
|
||||||
LogDebugMessage($"Broadcasting OnSceneReady for: {newSceneName}");
|
Logging.Debug($"Broadcasting OnSceneReady for: {newSceneName}");
|
||||||
LifecycleManager.Instance?.BroadcastSceneReady(newSceneName);
|
LifecycleManager.Instance?.BroadcastSceneReady(newSceneName);
|
||||||
|
|
||||||
// PHASE 11: Restore scene-specific data via SaveLoadManager
|
// PHASE 11: Restore scene-specific data via SaveLoadManager
|
||||||
@@ -381,13 +377,14 @@ namespace Core
|
|||||||
var debugSettings = DeveloperSettingsProvider.Instance.GetSettings<DebugSettings>();
|
var debugSettings = DeveloperSettingsProvider.Instance.GetSettings<DebugSettings>();
|
||||||
if (debugSettings.useSaveLoadSystem)
|
if (debugSettings.useSaveLoadSystem)
|
||||||
{
|
{
|
||||||
LogDebugMessage($"Restoring scene data for: {newSceneName}");
|
Logging.Debug($"Restoring scene data for: {newSceneName}");
|
||||||
SaveLoadManager.Instance.RestoreSceneData();
|
SaveLoadManager.Instance.RestoreSceneData();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (skipSave)
|
else if (skipSave)
|
||||||
{
|
{
|
||||||
LogDebugMessage($"Skipping restore for: {newSceneName} (skipSave=true)");
|
SaveLoadManager.Instance.RestoreSceneData();
|
||||||
|
Logging.Debug($"Skipping restore for: {newSceneName} (skipSave=true)");
|
||||||
}
|
}
|
||||||
|
|
||||||
// PHASE 12: Only hide the loading screen if autoHideLoadingScreen is true
|
// PHASE 12: Only hide the loading screen if autoHideLoadingScreen is true
|
||||||
@@ -396,13 +393,5 @@ namespace Core
|
|||||||
_loadingScreen.HideLoadingScreen();
|
_loadingScreen.HideLoadingScreen();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void LogDebugMessage(string message)
|
|
||||||
{
|
|
||||||
if (_logVerbosity <= LogVerbosity.Debug)
|
|
||||||
{
|
|
||||||
Logging.Debug($"[SceneManagerService] {message}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,23 +18,18 @@ namespace Core
|
|||||||
public GameObject orientationPromptPrefab;
|
public GameObject orientationPromptPrefab;
|
||||||
private LogVerbosity _logVerbosity = LogVerbosity.Warning;
|
private LogVerbosity _logVerbosity = LogVerbosity.Warning;
|
||||||
|
|
||||||
// ManagedBehaviour configuration
|
internal override void OnManagedAwake()
|
||||||
public override int ManagedAwakePriority => 70; // Platform-specific utility
|
|
||||||
|
|
||||||
private new void Awake()
|
|
||||||
{
|
{
|
||||||
base.Awake(); // CRITICAL: Register with LifecycleManager!
|
// Set instance immediately (early initialization)
|
||||||
|
|
||||||
// Set instance immediately so it's available before OnManagedAwake() is called
|
|
||||||
_instance = this;
|
_instance = this;
|
||||||
|
|
||||||
// Load verbosity settings early (GameManager sets up settings in its Awake)
|
// Load verbosity settings early (GameManager sets up settings in its OnManagedAwake)
|
||||||
_logVerbosity = DeveloperSettingsProvider.Instance.GetSettings<DebugSettings>().sceneLogVerbosity;
|
_logVerbosity = DeveloperSettingsProvider.Instance.GetSettings<DebugSettings>().sceneLogVerbosity;
|
||||||
|
|
||||||
LogDebugMessage("Initialized");
|
Logging.Debug("Initialized");
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnManagedAwake()
|
internal override void OnManagedStart()
|
||||||
{
|
{
|
||||||
// Subscribe to SceneManagerService to enforce orientation on every scene load
|
// Subscribe to SceneManagerService to enforce orientation on every scene load
|
||||||
if (SceneManagerService.Instance != null)
|
if (SceneManagerService.Instance != null)
|
||||||
@@ -51,7 +46,7 @@ namespace Core
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnSceneReady()
|
internal override void OnSceneReady()
|
||||||
{
|
{
|
||||||
// Handle orientation when scene is ready (initial scene)
|
// Handle orientation when scene is ready (initial scene)
|
||||||
// Note: This fires for the scene that just loaded, LifecycleManager tracks which scene
|
// Note: This fires for the scene that just loaded, LifecycleManager tracks which scene
|
||||||
@@ -73,7 +68,7 @@ namespace Core
|
|||||||
if (sceneName.ToLower().Contains("bootstrap"))
|
if (sceneName.ToLower().Contains("bootstrap"))
|
||||||
{
|
{
|
||||||
// Bootstrap being loaded additively, don't do anything
|
// Bootstrap being loaded additively, don't do anything
|
||||||
LogDebugMessage($"Detected bootstrapped scene: '{sceneName}'. Skipping orientation enforcement.");
|
Logging.Debug($"Detected bootstrapped scene: '{sceneName}'. Skipping orientation enforcement.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -83,37 +78,35 @@ namespace Core
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
LogDebugMessage($"No orientationConfig assigned. Defaulting to Landscape for scene '{sceneName}'");
|
Logging.Debug($"No orientationConfig assigned. Defaulting to Landscape for scene '{sceneName}'");
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (requirement)
|
switch (requirement)
|
||||||
{
|
{
|
||||||
case ScreenOrientationRequirement.Portrait:
|
case ScreenOrientationRequirement.Portrait:
|
||||||
LogDebugMessage($"Forcing Portrait for scene '{sceneName}'");
|
Logging.Debug($"Forcing Portrait for scene '{sceneName}'");
|
||||||
StartCoroutine(ForcePortrait());
|
StartCoroutine(ForcePortrait());
|
||||||
break;
|
break;
|
||||||
case ScreenOrientationRequirement.Landscape:
|
case ScreenOrientationRequirement.Landscape:
|
||||||
LogDebugMessage($"Forcing Landscape for scene '{sceneName}'");
|
Logging.Debug($"Forcing Landscape for scene '{sceneName}'");
|
||||||
StartCoroutine(ForceLandscape());
|
StartCoroutine(ForceLandscape());
|
||||||
break;
|
break;
|
||||||
case ScreenOrientationRequirement.NotApplicable:
|
case ScreenOrientationRequirement.NotApplicable:
|
||||||
default:
|
default:
|
||||||
// Default to landscape when no specific requirement is found
|
// Default to landscape when no specific requirement is found
|
||||||
LogDebugMessage($"No specific orientation for scene '{sceneName}'. Defaulting to Landscape");
|
Logging.Debug($"No specific orientation for scene '{sceneName}'. Defaulting to Landscape");
|
||||||
StartCoroutine(ForceLandscape());
|
StartCoroutine(ForceLandscape());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnDestroy()
|
internal override void OnManagedDestroy()
|
||||||
{
|
{
|
||||||
// Unsubscribe from events to prevent memory leaks
|
// Unsubscribe from events to prevent memory leaks
|
||||||
if (SceneManagerService.Instance != null)
|
if (SceneManagerService.Instance != null)
|
||||||
{
|
{
|
||||||
SceneManagerService.Instance.SceneLoadCompleted -= OnSceneLoadCompleted;
|
SceneManagerService.Instance.SceneLoadCompleted -= OnSceneLoadCompleted;
|
||||||
}
|
}
|
||||||
|
|
||||||
base.OnDestroy(); // Important: call base
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -127,12 +120,12 @@ namespace Core
|
|||||||
if (!currentlyLandscape)
|
if (!currentlyLandscape)
|
||||||
{
|
{
|
||||||
// Lock it to portrait and allow the device to orient itself
|
// Lock it to portrait and allow the device to orient itself
|
||||||
LogDebugMessage($"Actually forcing Portrait from previous: {Screen.orientation}");
|
Logging.Debug($"Actually forcing Portrait from previous: {Screen.orientation}");
|
||||||
Screen.orientation = ScreenOrientation.LandscapeRight;
|
Screen.orientation = ScreenOrientation.LandscapeRight;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
LogDebugMessage($"Skipping Landscape enforcement, device already in: {Screen.orientation}");
|
Logging.Debug($"Skipping Landscape enforcement, device already in: {Screen.orientation}");
|
||||||
}
|
}
|
||||||
|
|
||||||
yield return null;
|
yield return null;
|
||||||
@@ -160,12 +153,12 @@ namespace Core
|
|||||||
if (!currentlyPortrait)
|
if (!currentlyPortrait)
|
||||||
{
|
{
|
||||||
// Lock it to portrait and allow the device to orient itself
|
// Lock it to portrait and allow the device to orient itself
|
||||||
LogDebugMessage($"Actually forcing Portrait from previous: {Screen.orientation}");
|
Logging.Debug($"Actually forcing Portrait from previous: {Screen.orientation}");
|
||||||
Screen.orientation = ScreenOrientation.PortraitUpsideDown;
|
Screen.orientation = ScreenOrientation.PortraitUpsideDown;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
LogDebugMessage($"Skipping Portrait enforcement, device already in: {Screen.orientation}");
|
Logging.Debug($"Skipping Portrait enforcement, device already in: {Screen.orientation}");
|
||||||
}
|
}
|
||||||
|
|
||||||
yield return null;
|
yield return null;
|
||||||
@@ -181,13 +174,5 @@ namespace Core
|
|||||||
// Allow device to auto-rotate to correct portrait orientation
|
// Allow device to auto-rotate to correct portrait orientation
|
||||||
Screen.orientation = ScreenOrientation.AutoRotation;
|
Screen.orientation = ScreenOrientation.AutoRotation;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void LogDebugMessage(string message)
|
|
||||||
{
|
|
||||||
if (_logVerbosity <= LogVerbosity.Debug)
|
|
||||||
{
|
|
||||||
Logging.Debug($"[SceneOrientationEnforcer] {message}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using AppleHills.Core.Settings;
|
|
||||||
using UnityEngine;
|
|
||||||
|
|
||||||
namespace Core.Settings
|
namespace Core.Settings
|
||||||
{
|
{
|
||||||
@@ -21,7 +19,7 @@ namespace Core.Settings
|
|||||||
public static void Register<T>(T service) where T : class
|
public static void Register<T>(T service) where T : class
|
||||||
{
|
{
|
||||||
Services[typeof(T)] = service;
|
Services[typeof(T)] = service;
|
||||||
LogDebugMessage($"Service registered: {typeof(T).Name}");
|
Logging.Debug($"Service registered: {typeof(T).Name}");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -36,7 +34,7 @@ namespace Core.Settings
|
|||||||
return service as T;
|
return service as T;
|
||||||
}
|
}
|
||||||
|
|
||||||
Logging.Warning($"[ServiceLocator] Service of type {typeof(T).Name} not found!");
|
Logging.Warning($"Service of type {typeof(T).Name} not found!");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -46,16 +44,7 @@ namespace Core.Settings
|
|||||||
public static void Clear()
|
public static void Clear()
|
||||||
{
|
{
|
||||||
Services.Clear();
|
Services.Clear();
|
||||||
LogDebugMessage("All services cleared");
|
Logging.Debug("All services cleared");
|
||||||
}
|
|
||||||
|
|
||||||
private static void LogDebugMessage(string message)
|
|
||||||
{
|
|
||||||
if (DeveloperSettingsProvider.Instance.GetSettings<DebugSettings>().settingsLogVerbosity <=
|
|
||||||
LogVerbosity.Debug)
|
|
||||||
{
|
|
||||||
Logging.Debug($"[ServiceLocator] {message}");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using Pixelplacement;
|
using System;
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
using Core;
|
using Core;
|
||||||
|
using Core.Lifecycle;
|
||||||
using Core.SaveLoad;
|
using Core.SaveLoad;
|
||||||
using UnityEngine.Audio;
|
using UnityEngine.Audio;
|
||||||
|
|
||||||
public class PicnicBehaviour : MonoBehaviour
|
public class PicnicBehaviour : ManagedBehaviour
|
||||||
{
|
{
|
||||||
[Header("Random Call Settings")]
|
[Header("Random Call Settings")]
|
||||||
public float getDistractedMin = 2f;
|
public float getDistractedMin = 2f;
|
||||||
@@ -17,7 +18,8 @@ public class PicnicBehaviour : MonoBehaviour
|
|||||||
private Animator animator;
|
private Animator animator;
|
||||||
|
|
||||||
[Header("The FakeChocolate to destroy!")]
|
[Header("The FakeChocolate to destroy!")]
|
||||||
[SerializeField] private GameObject fakeChocolate; // Assign in Inspector
|
[SerializeField] private GameObject fakeChocolate;
|
||||||
|
[SerializeField] private GameObject realChocolate;
|
||||||
|
|
||||||
private AppleAudioSource _audioSource;
|
private AppleAudioSource _audioSource;
|
||||||
public AudioResource distractedAudioClips;
|
public AudioResource distractedAudioClips;
|
||||||
@@ -25,32 +27,44 @@ public class PicnicBehaviour : MonoBehaviour
|
|||||||
public AudioResource feederClips;
|
public AudioResource feederClips;
|
||||||
public AudioResource moanerClips;
|
public AudioResource moanerClips;
|
||||||
|
|
||||||
// Start is called once before the first execution of Update after the MonoBehaviour is created
|
// Save system configuration
|
||||||
void Start()
|
public override bool AutoRegisterForSave => true;
|
||||||
{
|
|
||||||
StartCoroutine(StateCycleRoutine());
|
|
||||||
}
|
|
||||||
|
|
||||||
void Awake()
|
// Runtime state tracking
|
||||||
|
private bool _fakeChocolateDestroyed;
|
||||||
|
|
||||||
|
internal override void OnManagedAwake()
|
||||||
{
|
{
|
||||||
stateMachine = GetComponent<AppleMachine>();
|
stateMachine = GetComponent<AppleMachine>();
|
||||||
animator = GetComponent<Animator>();
|
animator = GetComponent<Animator>();
|
||||||
_audioSource = GetComponent<AppleAudioSource>();
|
_audioSource = GetComponent<AppleAudioSource>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal override void OnSceneRestoreCompleted()
|
||||||
|
{
|
||||||
|
if (_fakeChocolateDestroyed)
|
||||||
|
{
|
||||||
|
DestroyChocolateObjects();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
StartCoroutine(StateCycleRoutine());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private IEnumerator StateCycleRoutine()
|
private IEnumerator StateCycleRoutine()
|
||||||
{
|
{
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
// Distracted state
|
// Distracted state
|
||||||
float distractedWait = Random.Range(getDistractedMin, getDistractedMax);
|
float distractedWait = UnityEngine.Random.Range(getDistractedMin, getDistractedMax);
|
||||||
stateMachine.ChangeState("Picnic PPL Distracted");
|
stateMachine.ChangeState("Picnic PPL Distracted");
|
||||||
animator.SetBool("theyDistracted", true);
|
animator.SetBool("theyDistracted", true);
|
||||||
_audioSource.Stop();
|
_audioSource.Stop();
|
||||||
yield return new WaitForSeconds(distractedWait);
|
yield return new WaitForSeconds(distractedWait);
|
||||||
|
|
||||||
// Chilling state
|
// Chilling state
|
||||||
float chillingWait = Random.Range(getFlirtyMin, getFlirtyMax);
|
float chillingWait = UnityEngine.Random.Range(getFlirtyMin, getFlirtyMax);
|
||||||
stateMachine.ChangeState("Picnic PPL Chilling");
|
stateMachine.ChangeState("Picnic PPL Chilling");
|
||||||
animator.SetBool("theyDistracted", false);
|
animator.SetBool("theyDistracted", false);
|
||||||
_audioSource.Stop();
|
_audioSource.Stop();
|
||||||
@@ -58,27 +72,33 @@ public class PicnicBehaviour : MonoBehaviour
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void StopAudio()
|
|
||||||
{
|
|
||||||
_audioSource.Stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void triedToStealChocolate()
|
public void triedToStealChocolate()
|
||||||
{
|
{
|
||||||
_audioSource.Stop();
|
_audioSource.Stop();
|
||||||
animator.SetTrigger("theyAngry");
|
animator.SetTrigger("theyAngry");
|
||||||
//stateMachine.ChangeState("Picnic PPL Angry");
|
|
||||||
Logging.Debug("Hey! Don't steal my chocolate!");
|
Logging.Debug("Hey! Don't steal my chocolate!");
|
||||||
_audioSource.audioSource.resource = angryAudioClips;
|
_audioSource.audioSource.resource = angryAudioClips;
|
||||||
_audioSource.Play(0);
|
_audioSource.Play(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void destroyFakeChocolate()
|
public void destroyFakeChocolate()
|
||||||
|
{
|
||||||
|
_fakeChocolateDestroyed = true;
|
||||||
|
Destroy(fakeChocolate);
|
||||||
|
Destroy(realChocolate);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DestroyChocolateObjects()
|
||||||
{
|
{
|
||||||
if (fakeChocolate != null)
|
if (fakeChocolate != null)
|
||||||
{
|
{
|
||||||
Destroy(fakeChocolate);
|
Destroy(fakeChocolate);
|
||||||
fakeChocolate = null; // Optional: clear reference
|
fakeChocolate = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (realChocolate != null)
|
||||||
|
{
|
||||||
|
realChocolate.SetActive(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -100,5 +120,33 @@ public class PicnicBehaviour : MonoBehaviour
|
|||||||
_audioSource.Play(0);
|
_audioSource.Play(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal override string OnSceneSaveRequested()
|
||||||
|
{
|
||||||
|
var state = new PicnicBehaviourState { fakeChocolateDestroyed = _fakeChocolateDestroyed };
|
||||||
|
return JsonUtility.ToJson(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal override void OnSceneRestoreRequested(string serializedData)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(serializedData)) return;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var state = JsonUtility.FromJson<PicnicBehaviourState>(serializedData);
|
||||||
|
if (state != null)
|
||||||
|
{
|
||||||
|
_fakeChocolateDestroyed = state.fakeChocolateDestroyed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Debug.LogWarning($"[PicnicBehaviour] Failed to restore state: {ex.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Serializable]
|
||||||
|
public class PicnicBehaviourState
|
||||||
|
{
|
||||||
|
public bool fakeChocolateDestroyed;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
using Core;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using Core.Lifecycle;
|
using Core.Lifecycle;
|
||||||
|
|
||||||
@@ -21,7 +22,7 @@ public class soundBird_CanFly : ManagedBehaviour
|
|||||||
|
|
||||||
#region Save/Load Implementation
|
#region Save/Load Implementation
|
||||||
|
|
||||||
protected override string OnSceneSaveRequested()
|
internal override string OnSceneSaveRequested()
|
||||||
{
|
{
|
||||||
var saveData = new SoundBirdSaveData
|
var saveData = new SoundBirdSaveData
|
||||||
{
|
{
|
||||||
@@ -31,11 +32,11 @@ public class soundBird_CanFly : ManagedBehaviour
|
|||||||
return JsonUtility.ToJson(saveData);
|
return JsonUtility.ToJson(saveData);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnSceneRestoreRequested(string serializedData)
|
internal override void OnSceneRestoreRequested(string serializedData)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(serializedData))
|
if (string.IsNullOrEmpty(serializedData))
|
||||||
{
|
{
|
||||||
Debug.LogWarning($"[soundBird_CanFly] No save data to restore for {gameObject.name}");
|
Logging.Warning($"[soundBird_CanFly] No save data to restore for {gameObject.name}");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -43,7 +44,7 @@ public class soundBird_CanFly : ManagedBehaviour
|
|||||||
if (saveData != null)
|
if (saveData != null)
|
||||||
{
|
{
|
||||||
canFly = saveData.canFly;
|
canFly = saveData.canFly;
|
||||||
Debug.Log($"[soundBird_CanFly] Restored canFly state: {canFly}");
|
Logging.Debug($"[soundBird_CanFly] Restored canFly state: {canFly}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -95,6 +95,7 @@ namespace AppleHills.Data.CardSystem
|
|||||||
|
|
||||||
public enum CardZone
|
public enum CardZone
|
||||||
{
|
{
|
||||||
|
NotApplicable,
|
||||||
AppleHills,
|
AppleHills,
|
||||||
Quarry,
|
Quarry,
|
||||||
CementFactory,
|
CementFactory,
|
||||||
|
|||||||
@@ -40,25 +40,20 @@ namespace Data.CardSystem
|
|||||||
// Event callbacks using System.Action
|
// Event callbacks using System.Action
|
||||||
public event Action<List<CardData>> OnBoosterOpened;
|
public event Action<List<CardData>> OnBoosterOpened;
|
||||||
public event Action<CardData> OnCardCollected;
|
public event Action<CardData> OnCardCollected;
|
||||||
public event Action<CardData> OnCardRarityUpgraded;
|
|
||||||
public event Action<int> OnBoosterCountChanged;
|
public event Action<int> OnBoosterCountChanged;
|
||||||
public event Action<CardData> OnPendingCardAdded;
|
public event Action<CardData> OnPendingCardAdded;
|
||||||
public event Action<CardData> OnCardPlacedInAlbum;
|
public event Action<CardData> OnCardPlacedInAlbum;
|
||||||
|
|
||||||
public override int ManagedAwakePriority => 60; // Data systems
|
|
||||||
|
|
||||||
private new void Awake()
|
internal override void OnManagedAwake()
|
||||||
{
|
{
|
||||||
base.Awake(); // CRITICAL: Register with LifecycleManager!
|
// Set instance immediately (early initialization)
|
||||||
|
|
||||||
// Set instance immediately so it's available before OnManagedAwake() is called
|
|
||||||
_instance = this;
|
_instance = this;
|
||||||
|
|
||||||
// Load card definitions from Addressables, then register with save system
|
// Load card definitions from Addressables, then register with save system
|
||||||
LoadCardDefinitionsFromAddressables();
|
LoadCardDefinitionsFromAddressables();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnManagedAwake()
|
internal override void OnManagedStart()
|
||||||
{
|
{
|
||||||
Logging.Debug("[CardSystemManager] Initialized");
|
Logging.Debug("[CardSystemManager] Initialized");
|
||||||
}
|
}
|
||||||
@@ -720,13 +715,13 @@ namespace Data.CardSystem
|
|||||||
|
|
||||||
#region Save/Load Lifecycle Hooks
|
#region Save/Load Lifecycle Hooks
|
||||||
|
|
||||||
protected override string OnGlobalSaveRequested()
|
internal override string OnGlobalSaveRequested()
|
||||||
{
|
{
|
||||||
var state = ExportCardCollectionState();
|
var state = ExportCardCollectionState();
|
||||||
return JsonUtility.ToJson(state);
|
return JsonUtility.ToJson(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnGlobalRestoreRequested(string serializedData)
|
internal override void OnGlobalRestoreRequested(string serializedData)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(serializedData))
|
if (string.IsNullOrEmpty(serializedData))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
using System;
|
using System.Collections.Generic;
|
||||||
using System.Collections;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using Core;
|
using Core;
|
||||||
using Core.Lifecycle;
|
using Core.Lifecycle;
|
||||||
using Interactions;
|
using Interactions;
|
||||||
@@ -34,10 +32,7 @@ namespace Dialogue
|
|||||||
public bool IsCompleted { get; private set; }
|
public bool IsCompleted { get; private set; }
|
||||||
public string CurrentSpeakerName => dialogueGraph?.speakerName;
|
public string CurrentSpeakerName => dialogueGraph?.speakerName;
|
||||||
|
|
||||||
|
internal override void OnManagedStart()
|
||||||
public override int ManagedAwakePriority => 150; // Dialogue systems
|
|
||||||
|
|
||||||
protected override void OnManagedAwake()
|
|
||||||
{
|
{
|
||||||
// Get required components
|
// Get required components
|
||||||
appleAudioSource = GetComponent<AppleAudioSource>();
|
appleAudioSource = GetComponent<AppleAudioSource>();
|
||||||
@@ -186,7 +181,7 @@ namespace Dialogue
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnDestroy()
|
internal override void OnManagedDestroy()
|
||||||
{
|
{
|
||||||
// Unregister from events
|
// Unregister from events
|
||||||
if (PuzzleManager.Instance != null)
|
if (PuzzleManager.Instance != null)
|
||||||
|
|||||||
@@ -49,14 +49,10 @@ namespace Input
|
|||||||
private ITouchInputConsumer defaultConsumer;
|
private ITouchInputConsumer defaultConsumer;
|
||||||
private bool isHoldActive;
|
private bool isHoldActive;
|
||||||
private LogVerbosity _logVerbosity = LogVerbosity.Warning;
|
private LogVerbosity _logVerbosity = LogVerbosity.Warning;
|
||||||
|
|
||||||
public override int ManagedAwakePriority => 25; // Input infrastructure
|
|
||||||
|
|
||||||
private new void Awake()
|
internal override void OnManagedAwake()
|
||||||
{
|
{
|
||||||
base.Awake(); // CRITICAL: Register with LifecycleManager!
|
// Set instance immediately (early initialization)
|
||||||
|
|
||||||
// Set instance immediately so it's available before OnManagedAwake() is called
|
|
||||||
_instance = this;
|
_instance = this;
|
||||||
|
|
||||||
// Load verbosity settings early
|
// Load verbosity settings early
|
||||||
@@ -89,10 +85,10 @@ namespace Input
|
|||||||
SwitchInputOnSceneLoaded(SceneManager.GetActiveScene().name);
|
SwitchInputOnSceneLoaded(SceneManager.GetActiveScene().name);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnManagedAwake()
|
internal override void OnManagedStart()
|
||||||
{
|
{
|
||||||
// Subscribe to scene load events from SceneManagerService
|
// Subscribe to scene load events from SceneManagerService
|
||||||
// This must happen in ManagedAwake because SceneManagerService instance needs to be set first
|
// This must happen in ManagedStart because SceneManagerService instance needs to be set first
|
||||||
if (SceneManagerService.Instance != null)
|
if (SceneManagerService.Instance != null)
|
||||||
{
|
{
|
||||||
SceneManagerService.Instance.SceneLoadCompleted += OnSceneLoadCompleted;
|
SceneManagerService.Instance.SceneLoadCompleted += OnSceneLoadCompleted;
|
||||||
@@ -104,11 +100,11 @@ namespace Input
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private void OnSceneLoadCompleted(string sceneName)
|
private void OnSceneLoadCompleted(string sceneName)
|
||||||
{
|
{
|
||||||
LogDebugMessage($"Scene loaded: {sceneName}, restoring input mode");
|
Logging.Debug($"Scene loaded: {sceneName}, restoring input mode");
|
||||||
SwitchInputOnSceneLoaded(sceneName);
|
SwitchInputOnSceneLoaded(sceneName);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnDestroy()
|
internal override void OnManagedDestroy()
|
||||||
{
|
{
|
||||||
// Unsubscribe from SceneManagerService events
|
// Unsubscribe from SceneManagerService events
|
||||||
if (SceneManagerService.Instance != null)
|
if (SceneManagerService.Instance != null)
|
||||||
@@ -116,7 +112,6 @@ namespace Input
|
|||||||
SceneManagerService.Instance.SceneLoadCompleted -= OnSceneLoadCompleted;
|
SceneManagerService.Instance.SceneLoadCompleted -= OnSceneLoadCompleted;
|
||||||
}
|
}
|
||||||
|
|
||||||
base.OnDestroy();
|
|
||||||
// Input action cleanup happens automatically
|
// Input action cleanup happens automatically
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -182,24 +177,24 @@ namespace Input
|
|||||||
Vector2 screenPos = positionAction.ReadValue<Vector2>();
|
Vector2 screenPos = positionAction.ReadValue<Vector2>();
|
||||||
Vector3 worldPos = Camera.main.ScreenToWorldPoint(screenPos);
|
Vector3 worldPos = Camera.main.ScreenToWorldPoint(screenPos);
|
||||||
Vector2 worldPos2D = new Vector2(worldPos.x, worldPos.y);
|
Vector2 worldPos2D = new Vector2(worldPos.x, worldPos.y);
|
||||||
LogDebugMessage($"TapMove performed at {worldPos2D}");
|
Logging.Debug($"TapMove performed at {worldPos2D}");
|
||||||
|
|
||||||
// First try to delegate to an override consumer if available
|
// First try to delegate to an override consumer if available
|
||||||
if (TryDelegateToOverrideConsumer(screenPos, worldPos2D))
|
if (TryDelegateToOverrideConsumer(screenPos, worldPos2D))
|
||||||
{
|
{
|
||||||
LogDebugMessage("Tap delegated to override consumer");
|
Logging.Debug("Tap delegated to override consumer");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Then try to delegate to any ITouchInputConsumer (UI or world interactable)
|
// Then try to delegate to any ITouchInputConsumer (UI or world interactable)
|
||||||
if (!TryDelegateToAnyInputConsumer(screenPos, worldPos2D))
|
if (!TryDelegateToAnyInputConsumer(screenPos, worldPos2D))
|
||||||
{
|
{
|
||||||
LogDebugMessage("No input consumer found, forwarding tap to default consumer");
|
Logging.Debug("No input consumer found, forwarding tap to default consumer");
|
||||||
defaultConsumer?.OnTap(worldPos2D);
|
defaultConsumer?.OnTap(worldPos2D);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
LogDebugMessage("Tap delegated to input consumer");
|
Logging.Debug("Tap delegated to input consumer");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -212,13 +207,13 @@ namespace Input
|
|||||||
Vector2 screenPos = positionAction.ReadValue<Vector2>();
|
Vector2 screenPos = positionAction.ReadValue<Vector2>();
|
||||||
Vector3 worldPos = Camera.main.ScreenToWorldPoint(screenPos);
|
Vector3 worldPos = Camera.main.ScreenToWorldPoint(screenPos);
|
||||||
Vector2 worldPos2D = new Vector2(worldPos.x, worldPos.y);
|
Vector2 worldPos2D = new Vector2(worldPos.x, worldPos.y);
|
||||||
LogDebugMessage($"HoldMove started at {worldPos2D}");
|
Logging.Debug($"HoldMove started at {worldPos2D}");
|
||||||
|
|
||||||
// First check for override consumers
|
// First check for override consumers
|
||||||
if (_overrideConsumers.Count > 0)
|
if (_overrideConsumers.Count > 0)
|
||||||
{
|
{
|
||||||
_activeHoldConsumer = _overrideConsumers[_overrideConsumers.Count - 1];
|
_activeHoldConsumer = _overrideConsumers[_overrideConsumers.Count - 1];
|
||||||
LogDebugMessage($"Hold delegated to override consumer: {_activeHoldConsumer}");
|
Logging.Debug($"Hold delegated to override consumer: {_activeHoldConsumer}");
|
||||||
_activeHoldConsumer.OnHoldStart(worldPos2D);
|
_activeHoldConsumer.OnHoldStart(worldPos2D);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -238,7 +233,7 @@ namespace Input
|
|||||||
Vector2 screenPos = positionAction.ReadValue<Vector2>();
|
Vector2 screenPos = positionAction.ReadValue<Vector2>();
|
||||||
Vector3 worldPos = Camera.main.ScreenToWorldPoint(screenPos);
|
Vector3 worldPos = Camera.main.ScreenToWorldPoint(screenPos);
|
||||||
Vector2 worldPos2D = new Vector2(worldPos.x, worldPos.y);
|
Vector2 worldPos2D = new Vector2(worldPos.x, worldPos.y);
|
||||||
LogDebugMessage($"HoldMove canceled at {worldPos2D}");
|
Logging.Debug($"HoldMove canceled at {worldPos2D}");
|
||||||
|
|
||||||
// Notify the active hold consumer that the hold has ended
|
// Notify the active hold consumer that the hold has ended
|
||||||
_activeHoldConsumer?.OnHoldEnd(worldPos2D);
|
_activeHoldConsumer?.OnHoldEnd(worldPos2D);
|
||||||
@@ -302,7 +297,7 @@ namespace Input
|
|||||||
}
|
}
|
||||||
if (consumer != null)
|
if (consumer != null)
|
||||||
{
|
{
|
||||||
LogDebugMessage($"Delegating tap to UI consumer at {screenPos} (GameObject: {result.gameObject.name})");
|
Logging.Debug($"Delegating tap to UI consumer at {screenPos} (GameObject: {result.gameObject.name})");
|
||||||
consumer.OnTap(screenPos);
|
consumer.OnTap(screenPos);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -331,7 +326,7 @@ namespace Input
|
|||||||
}
|
}
|
||||||
if (consumer != null)
|
if (consumer != null)
|
||||||
{
|
{
|
||||||
LogDebugMessage($"Delegating tap to consumer at {worldPos} (GameObject: {hitWithMask.gameObject.name})");
|
Logging.Debug($"Delegating tap to consumer at {worldPos} (GameObject: {hitWithMask.gameObject.name})");
|
||||||
consumer.OnTap(worldPos);
|
consumer.OnTap(worldPos);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -345,15 +340,15 @@ namespace Input
|
|||||||
var consumer = hit.GetComponent<ITouchInputConsumer>();
|
var consumer = hit.GetComponent<ITouchInputConsumer>();
|
||||||
if (consumer != null)
|
if (consumer != null)
|
||||||
{
|
{
|
||||||
LogDebugMessage($"Delegating tap to consumer at {worldPos} (GameObject: {hit.gameObject.name})");
|
Logging.Debug($"Delegating tap to consumer at {worldPos} (GameObject: {hit.gameObject.name})");
|
||||||
consumer.OnTap(worldPos);
|
consumer.OnTap(worldPos);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
LogDebugMessage($"Collider2D hit at {worldPos} (GameObject: {hit.gameObject.name}), but no ITouchInputConsumer found.");
|
Logging.Debug($"Collider2D hit at {worldPos} (GameObject: {hit.gameObject.name}), but no ITouchInputConsumer found.");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
LogDebugMessage($"No Collider2D found at {worldPos} for interactable delegation.");
|
Logging.Debug($"No Collider2D found at {worldPos} for interactable delegation.");
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -368,7 +363,7 @@ namespace Input
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
_overrideConsumers.Add(consumer);
|
_overrideConsumers.Add(consumer);
|
||||||
LogDebugMessage($"Override consumer registered: {consumer}");
|
Logging.Debug($"Override consumer registered: {consumer}");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -386,7 +381,7 @@ namespace Input
|
|||||||
}
|
}
|
||||||
|
|
||||||
_overrideConsumers.Remove(consumer);
|
_overrideConsumers.Remove(consumer);
|
||||||
LogDebugMessage($"Override consumer unregistered: {consumer}");
|
Logging.Debug($"Override consumer unregistered: {consumer}");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -396,7 +391,7 @@ namespace Input
|
|||||||
{
|
{
|
||||||
_activeHoldConsumer = null;
|
_activeHoldConsumer = null;
|
||||||
_overrideConsumers.Clear();
|
_overrideConsumers.Clear();
|
||||||
LogDebugMessage("All override consumers cleared.");
|
Logging.Debug("All override consumers cleared.");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -409,17 +404,9 @@ namespace Input
|
|||||||
|
|
||||||
// Get the topmost override consumer (last registered)
|
// Get the topmost override consumer (last registered)
|
||||||
var consumer = _overrideConsumers[_overrideConsumers.Count - 1];
|
var consumer = _overrideConsumers[_overrideConsumers.Count - 1];
|
||||||
LogDebugMessage($"Delegating tap to override consumer at {worldPos} (GameObject: {consumer})");
|
Logging.Debug($"Delegating tap to override consumer at {worldPos} (GameObject: {consumer})");
|
||||||
consumer.OnTap(worldPos);
|
consumer.OnTap(worldPos);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void LogDebugMessage(string message)
|
|
||||||
{
|
|
||||||
if (_logVerbosity <= LogVerbosity.Debug)
|
|
||||||
{
|
|
||||||
Logging.Debug($"[InputManager] {message}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ using Pathfinding;
|
|||||||
using AppleHills.Core.Settings;
|
using AppleHills.Core.Settings;
|
||||||
using Core;
|
using Core;
|
||||||
using Core.Lifecycle;
|
using Core.Lifecycle;
|
||||||
using Core.SaveLoad;
|
|
||||||
|
|
||||||
namespace Input
|
namespace Input
|
||||||
{
|
{
|
||||||
@@ -71,9 +70,8 @@ namespace Input
|
|||||||
public override bool AutoRegisterForSave => true;
|
public override bool AutoRegisterForSave => true;
|
||||||
// Scene-specific SaveId - each level has its own player state
|
// Scene-specific SaveId - each level has its own player state
|
||||||
public override string SaveId => $"{gameObject.scene.name}/PlayerController";
|
public override string SaveId => $"{gameObject.scene.name}/PlayerController";
|
||||||
public override int ManagedAwakePriority => 100; // Player controller
|
|
||||||
|
|
||||||
protected override void OnManagedAwake()
|
internal override void OnManagedStart()
|
||||||
{
|
{
|
||||||
aiPath = GetComponent<AIPath>();
|
aiPath = GetComponent<AIPath>();
|
||||||
artTransform = transform.Find("CharacterArt");
|
artTransform = transform.Find("CharacterArt");
|
||||||
@@ -103,7 +101,7 @@ namespace Input
|
|||||||
public void OnTap(Vector2 worldPosition)
|
public void OnTap(Vector2 worldPosition)
|
||||||
{
|
{
|
||||||
InterruptMoveTo();
|
InterruptMoveTo();
|
||||||
LogDebugMessage($"OnTap at {worldPosition}");
|
Logging.Debug($"OnTap at {worldPosition}");
|
||||||
if (aiPath != null)
|
if (aiPath != null)
|
||||||
{
|
{
|
||||||
aiPath.enabled = true;
|
aiPath.enabled = true;
|
||||||
@@ -122,7 +120,7 @@ namespace Input
|
|||||||
public void OnHoldStart(Vector2 worldPosition)
|
public void OnHoldStart(Vector2 worldPosition)
|
||||||
{
|
{
|
||||||
InterruptMoveTo();
|
InterruptMoveTo();
|
||||||
LogDebugMessage($"OnHoldStart at {worldPosition}");
|
Logging.Debug($"OnHoldStart at {worldPosition}");
|
||||||
lastHoldPosition = worldPosition;
|
lastHoldPosition = worldPosition;
|
||||||
isHolding = true;
|
isHolding = true;
|
||||||
if (_settings.DefaultHoldMovementMode == HoldMovementMode.Pathfinding &&
|
if (_settings.DefaultHoldMovementMode == HoldMovementMode.Pathfinding &&
|
||||||
@@ -159,7 +157,7 @@ namespace Input
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public void OnHoldEnd(Vector2 worldPosition)
|
public void OnHoldEnd(Vector2 worldPosition)
|
||||||
{
|
{
|
||||||
LogDebugMessage($"OnHoldEnd at {worldPosition}");
|
Logging.Debug($"OnHoldEnd at {worldPosition}");
|
||||||
isHolding = false;
|
isHolding = false;
|
||||||
directMoveVelocity = Vector3.zero;
|
directMoveVelocity = Vector3.zero;
|
||||||
if (aiPath != null && _settings.DefaultHoldMovementMode ==
|
if (aiPath != null && _settings.DefaultHoldMovementMode ==
|
||||||
@@ -335,13 +333,13 @@ namespace Input
|
|||||||
{
|
{
|
||||||
_isMoving = true;
|
_isMoving = true;
|
||||||
OnMovementStarted?.Invoke();
|
OnMovementStarted?.Invoke();
|
||||||
LogDebugMessage("Movement started");
|
Logging.Debug("Movement started");
|
||||||
}
|
}
|
||||||
else if (!isCurrentlyMoving && _isMoving)
|
else if (!isCurrentlyMoving && _isMoving)
|
||||||
{
|
{
|
||||||
_isMoving = false;
|
_isMoving = false;
|
||||||
OnMovementStopped?.Invoke();
|
OnMovementStopped?.Invoke();
|
||||||
LogDebugMessage("Movement stopped");
|
Logging.Debug("Movement stopped");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -424,18 +422,10 @@ namespace Input
|
|||||||
OnArrivedAtTarget?.Invoke();
|
OnArrivedAtTarget?.Invoke();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void LogDebugMessage(string message)
|
|
||||||
{
|
|
||||||
if (_logVerbosity <= LogVerbosity.Debug)
|
|
||||||
{
|
|
||||||
Logging.Debug($"[PlayerTouchController] {message}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#region Save/Load Lifecycle Hooks
|
#region Save/Load Lifecycle Hooks
|
||||||
|
|
||||||
protected override string OnSceneSaveRequested()
|
internal override string OnSceneSaveRequested()
|
||||||
{
|
{
|
||||||
var saveData = new PlayerSaveData
|
var saveData = new PlayerSaveData
|
||||||
{
|
{
|
||||||
@@ -445,7 +435,7 @@ namespace Input
|
|||||||
return JsonUtility.ToJson(saveData);
|
return JsonUtility.ToJson(saveData);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnSceneRestoreRequested(string serializedData)
|
internal override void OnSceneRestoreRequested(string serializedData)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(serializedData))
|
if (string.IsNullOrEmpty(serializedData))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -41,9 +41,6 @@ namespace Interactions
|
|||||||
// Action component system
|
// Action component system
|
||||||
private List<InteractionActionBase> _registeredActions = new List<InteractionActionBase>();
|
private List<InteractionActionBase> _registeredActions = new List<InteractionActionBase>();
|
||||||
|
|
||||||
// ManagedBehaviour configuration
|
|
||||||
public override int ManagedAwakePriority => 100; // Gameplay base classes
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Register an action component with this interactable
|
/// Register an action component with this interactable
|
||||||
@@ -190,7 +187,7 @@ namespace Interactions
|
|||||||
/// <returns>True if interaction succeeded, false otherwise</returns>
|
/// <returns>True if interaction succeeded, false otherwise</returns>
|
||||||
protected virtual bool DoInteraction()
|
protected virtual bool DoInteraction()
|
||||||
{
|
{
|
||||||
Debug.LogWarning($"[Interactable] DoInteraction not implemented for {GetType().Name}");
|
Logging.Warning($"[Interactable] DoInteraction not implemented for {GetType().Name}");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -68,8 +68,6 @@ namespace Interactions
|
|||||||
public event Action<PickupItemData, PickupItemData> OnIncorrectItemSlotted;
|
public event Action<PickupItemData, PickupItemData> OnIncorrectItemSlotted;
|
||||||
|
|
||||||
public UnityEvent onForbiddenItemSlotted;
|
public UnityEvent onForbiddenItemSlotted;
|
||||||
// Native C# event alternative for code-only subscribers
|
|
||||||
public event Action<PickupItemData, PickupItemData> OnForbiddenItemSlotted;
|
|
||||||
|
|
||||||
public GameObject GetSlottedObject()
|
public GameObject GetSlottedObject()
|
||||||
{
|
{
|
||||||
@@ -85,9 +83,9 @@ namespace Interactions
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Awake()
|
internal override void OnManagedAwake()
|
||||||
{
|
{
|
||||||
base.Awake(); // SaveableInteractable registration
|
base.OnManagedAwake(); // SaveableInteractable registration
|
||||||
|
|
||||||
// Setup visuals
|
// Setup visuals
|
||||||
if (iconRenderer == null)
|
if (iconRenderer == null)
|
||||||
@@ -289,10 +287,8 @@ namespace Interactions
|
|||||||
ItemManager.Instance?.RegisterItemSlot(this);
|
ItemManager.Instance?.RegisterItemSlot(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnDestroy()
|
internal override void OnManagedDestroy()
|
||||||
{
|
{
|
||||||
base.OnDestroy();
|
|
||||||
|
|
||||||
// Unregister from slot manager
|
// Unregister from slot manager
|
||||||
ItemManager.Instance?.UnregisterItemSlot(this);
|
ItemManager.Instance?.UnregisterItemSlot(this);
|
||||||
}
|
}
|
||||||
@@ -333,7 +329,7 @@ namespace Interactions
|
|||||||
ItemSlotSaveData data = JsonUtility.FromJson<ItemSlotSaveData>(serializedData);
|
ItemSlotSaveData data = JsonUtility.FromJson<ItemSlotSaveData>(serializedData);
|
||||||
if (data == null)
|
if (data == null)
|
||||||
{
|
{
|
||||||
Debug.LogWarning($"[ItemSlot] Failed to deserialize save data for {gameObject.name}");
|
Logging.Warning($"[ItemSlot] Failed to deserialize save data for {gameObject.name}");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -343,7 +339,7 @@ namespace Interactions
|
|||||||
// Restore slotted item if there was one
|
// Restore slotted item if there was one
|
||||||
if (!string.IsNullOrEmpty(data.slottedItemSaveId))
|
if (!string.IsNullOrEmpty(data.slottedItemSaveId))
|
||||||
{
|
{
|
||||||
Debug.Log($"[ItemSlot] Restoring slotted item: {data.slottedItemSaveId} (itemId: {data.slottedItemDataId})");
|
Logging.Debug($"[ItemSlot] Restoring slotted item: {data.slottedItemSaveId} (itemId: {data.slottedItemDataId})");
|
||||||
RestoreSlottedItem(data.slottedItemSaveId, data.slottedItemDataId);
|
RestoreSlottedItem(data.slottedItemSaveId, data.slottedItemDataId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -361,7 +357,7 @@ namespace Interactions
|
|||||||
{
|
{
|
||||||
// Item not found in scene - it might be a dynamically spawned combined item
|
// Item not found in scene - it might be a dynamically spawned combined item
|
||||||
// Try to spawn it from the itemDataId
|
// Try to spawn it from the itemDataId
|
||||||
Debug.Log($"[ItemSlot] Slotted item not found in scene: {slottedItemSaveId}, attempting to spawn from itemId: {expectedItemDataId}");
|
Logging.Debug($"[ItemSlot] Slotted item not found in scene: {slottedItemSaveId}, attempting to spawn from itemId: {expectedItemDataId}");
|
||||||
|
|
||||||
GameObject prefab = interactionSettings?.FindPickupPrefabByItemId(expectedItemDataId);
|
GameObject prefab = interactionSettings?.FindPickupPrefabByItemId(expectedItemDataId);
|
||||||
if (prefab != null)
|
if (prefab != null)
|
||||||
@@ -369,17 +365,17 @@ namespace Interactions
|
|||||||
// Spawn the item (inactive, since it will be slotted)
|
// Spawn the item (inactive, since it will be slotted)
|
||||||
slottedObject = Instantiate(prefab, transform.position, Quaternion.identity);
|
slottedObject = Instantiate(prefab, transform.position, Quaternion.identity);
|
||||||
slottedObject.SetActive(false);
|
slottedObject.SetActive(false);
|
||||||
Debug.Log($"[ItemSlot] Successfully spawned combined item for slot: {expectedItemDataId}");
|
Logging.Debug($"[ItemSlot] Successfully spawned combined item for slot: {expectedItemDataId}");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Debug.LogWarning($"[ItemSlot] Could not find prefab for itemId: {expectedItemDataId}");
|
Logging.Warning($"[ItemSlot] Could not find prefab for itemId: {expectedItemDataId}");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (slottedObject == null)
|
else if (slottedObject == null)
|
||||||
{
|
{
|
||||||
Debug.LogWarning($"[ItemSlot] Could not find slotted item with save ID: {slottedItemSaveId}");
|
Logging.Warning($"[ItemSlot] Could not find slotted item with save ID: {slottedItemSaveId}");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -395,13 +391,13 @@ namespace Interactions
|
|||||||
{
|
{
|
||||||
if (slottedData.itemId != expectedItemDataId)
|
if (slottedData.itemId != expectedItemDataId)
|
||||||
{
|
{
|
||||||
Debug.LogWarning($"[ItemSlot] ItemId mismatch! Pickup has '{slottedData.itemId}' but expected '{expectedItemDataId}'");
|
Logging.Warning($"[ItemSlot] ItemId mismatch! Pickup has '{slottedData.itemId}' but expected '{expectedItemDataId}'");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (slottedData == null)
|
if (slottedData == null)
|
||||||
{
|
{
|
||||||
Debug.LogWarning($"[ItemSlot] Pickup {pickup.gameObject.name} has null itemData! Expected itemId: {expectedItemDataId}");
|
Logging.Warning($"[ItemSlot] Pickup {pickup.gameObject.name} has null itemData! Expected itemId: {expectedItemDataId}");
|
||||||
if (slottedObject != null)
|
if (slottedObject != null)
|
||||||
Destroy(slottedObject);
|
Destroy(slottedObject);
|
||||||
return;
|
return;
|
||||||
@@ -409,7 +405,7 @@ namespace Interactions
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Debug.LogWarning($"[ItemSlot] Slotted object has no Pickup component: {slottedObject.name}");
|
Logging.Warning($"[ItemSlot] Slotted object has no Pickup component: {slottedObject.name}");
|
||||||
if (slottedObject != null)
|
if (slottedObject != null)
|
||||||
Destroy(slottedObject);
|
Destroy(slottedObject);
|
||||||
return;
|
return;
|
||||||
@@ -419,7 +415,7 @@ namespace Interactions
|
|||||||
// Follower state is managed separately during save/load restoration
|
// Follower state is managed separately during save/load restoration
|
||||||
ApplySlottedItemState(slottedObject, slottedData, triggerEvents: false);
|
ApplySlottedItemState(slottedObject, slottedData, triggerEvents: false);
|
||||||
|
|
||||||
Debug.Log($"[ItemSlot] Successfully restored slotted item: {slottedData.itemName} (itemId: {slottedData.itemId})");
|
Logging.Debug($"[ItemSlot] Successfully restored slotted item: {slottedData.itemName} (itemId: {slottedData.itemId})");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -526,7 +522,7 @@ namespace Interactions
|
|||||||
// If slot already has an item, reject the claim
|
// If slot already has an item, reject the claim
|
||||||
if (currentlySlottedItemObject != null)
|
if (currentlySlottedItemObject != null)
|
||||||
{
|
{
|
||||||
Debug.LogWarning($"[ItemSlot] Already has a slotted item, rejecting claim from {pickup.gameObject.name}");
|
Logging.Warning($"[ItemSlot] Already has a slotted item, rejecting claim from {pickup.gameObject.name}");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -537,7 +533,7 @@ namespace Interactions
|
|||||||
// Claim the pickup
|
// Claim the pickup
|
||||||
ApplySlottedItemState(pickup.gameObject, pickup.itemData, triggerEvents: false);
|
ApplySlottedItemState(pickup.gameObject, pickup.itemData, triggerEvents: false);
|
||||||
|
|
||||||
Debug.Log($"[ItemSlot] Successfully claimed slotted item: {pickup.itemData?.itemName}");
|
Logging.Debug($"[ItemSlot] Successfully claimed slotted item: {pickup.itemData?.itemName}");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -32,9 +32,9 @@ namespace Interactions
|
|||||||
public event Action<PickupItemData> OnItemPickedUp;
|
public event Action<PickupItemData> OnItemPickedUp;
|
||||||
public event Action<PickupItemData, PickupItemData, PickupItemData> OnItemsCombined;
|
public event Action<PickupItemData, PickupItemData, PickupItemData> OnItemsCombined;
|
||||||
|
|
||||||
protected override void Awake()
|
internal override void OnManagedAwake()
|
||||||
{
|
{
|
||||||
base.Awake(); // Register with save system
|
base.OnManagedAwake(); // Register with save system
|
||||||
|
|
||||||
if (iconRenderer == null)
|
if (iconRenderer == null)
|
||||||
iconRenderer = GetComponent<SpriteRenderer>();
|
iconRenderer = GetComponent<SpriteRenderer>();
|
||||||
@@ -44,15 +44,14 @@ namespace Interactions
|
|||||||
|
|
||||||
// Always register with ItemManager, even if picked up
|
// Always register with ItemManager, even if picked up
|
||||||
// This allows the save/load system to find held items when restoring state
|
// This allows the save/load system to find held items when restoring state
|
||||||
protected override void OnManagedAwake()
|
internal override void OnManagedStart()
|
||||||
{
|
{
|
||||||
|
base.OnManagedStart();
|
||||||
ItemManager.Instance?.RegisterPickup(this);
|
ItemManager.Instance?.RegisterPickup(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnDestroy()
|
internal override void OnManagedDestroy()
|
||||||
{
|
{
|
||||||
base.OnDestroy();
|
|
||||||
|
|
||||||
// Unregister from ItemManager
|
// Unregister from ItemManager
|
||||||
ItemManager.Instance?.UnregisterPickup(this);
|
ItemManager.Instance?.UnregisterPickup(this);
|
||||||
}
|
}
|
||||||
@@ -166,7 +165,7 @@ namespace Interactions
|
|||||||
PickupSaveData data = JsonUtility.FromJson<PickupSaveData>(serializedData);
|
PickupSaveData data = JsonUtility.FromJson<PickupSaveData>(serializedData);
|
||||||
if (data == null)
|
if (data == null)
|
||||||
{
|
{
|
||||||
Debug.LogWarning($"[Pickup] Failed to deserialize save data for {gameObject.name}");
|
Logging.Warning($"[Pickup] Failed to deserialize save data for {gameObject.name}");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -200,7 +199,7 @@ namespace Interactions
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Debug.LogWarning($"[Pickup] Could not find slot with SaveId: {data.slotSaveId}");
|
Logging.Warning($"[Pickup] Could not find slot with SaveId: {data.slotSaveId}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using UnityEngine;
|
using Core;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
namespace Interactions
|
namespace Interactions
|
||||||
{
|
{
|
||||||
@@ -23,7 +24,7 @@ namespace Interactions
|
|||||||
|
|
||||||
#region Save/Load Lifecycle Hooks
|
#region Save/Load Lifecycle Hooks
|
||||||
|
|
||||||
protected override string OnSceneSaveRequested()
|
internal override string OnSceneSaveRequested()
|
||||||
{
|
{
|
||||||
object stateData = GetSerializableState();
|
object stateData = GetSerializableState();
|
||||||
if (stateData == null)
|
if (stateData == null)
|
||||||
@@ -34,11 +35,11 @@ namespace Interactions
|
|||||||
return JsonUtility.ToJson(stateData);
|
return JsonUtility.ToJson(stateData);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnSceneRestoreRequested(string serializedData)
|
internal override void OnSceneRestoreRequested(string serializedData)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(serializedData))
|
if (string.IsNullOrEmpty(serializedData))
|
||||||
{
|
{
|
||||||
Debug.LogWarning($"[SaveableInteractable] Empty save data for {SaveId}");
|
Logging.Warning($"[SaveableInteractable] Empty save data for {SaveId}");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -85,17 +86,17 @@ namespace Interactions
|
|||||||
[ContextMenu("Log Save ID")]
|
[ContextMenu("Log Save ID")]
|
||||||
private void LogSaveId()
|
private void LogSaveId()
|
||||||
{
|
{
|
||||||
Debug.Log($"Save ID: {SaveId}");
|
Logging.Debug($"Save ID: {SaveId}");
|
||||||
}
|
}
|
||||||
|
|
||||||
[ContextMenu("Test Serialize/Deserialize")]
|
[ContextMenu("Test Serialize/Deserialize")]
|
||||||
private void TestSerializeDeserialize()
|
private void TestSerializeDeserialize()
|
||||||
{
|
{
|
||||||
string serialized = OnSceneSaveRequested();
|
string serialized = OnSceneSaveRequested();
|
||||||
Debug.Log($"Serialized state: {serialized}");
|
Logging.Debug($"Serialized state: {serialized}");
|
||||||
|
|
||||||
OnSceneRestoreRequested(serialized);
|
OnSceneRestoreRequested(serialized);
|
||||||
Debug.Log("Deserialization test complete");
|
Logging.Debug("Deserialization test complete");
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -21,11 +21,11 @@ namespace Levels
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Unity Awake callback. Sets up icon, interactable, and event handlers.
|
/// Unity Awake callback. Sets up icon, interactable, and event handlers.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected override void Awake()
|
internal override void OnManagedAwake()
|
||||||
{
|
{
|
||||||
base.Awake();
|
base.OnManagedAwake();
|
||||||
|
|
||||||
Debug.Log($"[LevelSwitch] Awake called for {gameObject.name} in scene {gameObject.scene.name}");
|
Logging.Debug($"[LevelSwitch] Awake called for {gameObject.name} in scene {gameObject.scene.name}");
|
||||||
|
|
||||||
if (_iconRenderer == null)
|
if (_iconRenderer == null)
|
||||||
_iconRenderer = GetComponent<SpriteRenderer>();
|
_iconRenderer = GetComponent<SpriteRenderer>();
|
||||||
@@ -36,14 +36,14 @@ namespace Levels
|
|||||||
ApplySwitchData();
|
ApplySwitchData();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnManagedAwake()
|
internal override void OnManagedStart()
|
||||||
{
|
{
|
||||||
Debug.Log($"[LevelSwitch] OnManagedAwake called for {gameObject.name}");
|
Logging.Debug($"[LevelSwitch] OnManagedStart called for {gameObject.name}");
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnSceneReady()
|
internal override void OnSceneReady()
|
||||||
{
|
{
|
||||||
Debug.Log($"[LevelSwitch] OnSceneReady called for {gameObject.name}");
|
Logging.Debug($"[LevelSwitch] OnSceneReady called for {gameObject.name}");
|
||||||
}
|
}
|
||||||
|
|
||||||
#if UNITY_EDITOR
|
#if UNITY_EDITOR
|
||||||
@@ -79,7 +79,7 @@ namespace Levels
|
|||||||
{
|
{
|
||||||
if (switchData == null || string.IsNullOrEmpty(switchData.targetLevelSceneName))
|
if (switchData == null || string.IsNullOrEmpty(switchData.targetLevelSceneName))
|
||||||
{
|
{
|
||||||
Debug.LogWarning("LevelSwitch has no valid switchData!");
|
Logging.Warning("LevelSwitch has no valid switchData!");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -35,21 +35,16 @@ namespace Levels
|
|||||||
[SerializeField] private bool startUnlocked = false;
|
[SerializeField] private bool startUnlocked = false;
|
||||||
|
|
||||||
private SpriteRenderer iconRenderer;
|
private SpriteRenderer iconRenderer;
|
||||||
|
|
||||||
// Settings reference
|
|
||||||
private IInteractionSettings interactionSettings;
|
private IInteractionSettings interactionSettings;
|
||||||
|
|
||||||
private bool switchActive = true;
|
|
||||||
private bool isUnlocked;
|
private bool isUnlocked;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Unity Awake callback. Sets up icon, interactable, and event handlers.
|
/// Unity Awake callback. Sets up icon, interactable, and event handlers.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected override void Awake()
|
internal override void OnManagedAwake()
|
||||||
{
|
{
|
||||||
base.Awake();
|
base.OnManagedAwake();
|
||||||
|
|
||||||
switchActive = true;
|
|
||||||
if (iconRenderer == null)
|
if (iconRenderer == null)
|
||||||
iconRenderer = GetComponent<SpriteRenderer>();
|
iconRenderer = GetComponent<SpriteRenderer>();
|
||||||
|
|
||||||
@@ -64,10 +59,9 @@ namespace Levels
|
|||||||
ApplySwitchData();
|
ApplySwitchData();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnManagedAwake()
|
internal override void OnManagedStart()
|
||||||
{
|
{
|
||||||
base.OnManagedAwake();
|
base.OnManagedStart();
|
||||||
|
|
||||||
// If startUnlocked is true, always start active
|
// If startUnlocked is true, always start active
|
||||||
if (startUnlocked)
|
if (startUnlocked)
|
||||||
{
|
{
|
||||||
@@ -86,10 +80,8 @@ namespace Levels
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnDestroy()
|
internal override void OnManagedDestroy()
|
||||||
{
|
{
|
||||||
base.OnDestroy();
|
|
||||||
|
|
||||||
if (PuzzleManager.Instance != null)
|
if (PuzzleManager.Instance != null)
|
||||||
{
|
{
|
||||||
PuzzleManager.Instance.OnAllPuzzlesComplete -= HandleAllPuzzlesComplete;
|
PuzzleManager.Instance.OnAllPuzzlesComplete -= HandleAllPuzzlesComplete;
|
||||||
@@ -144,15 +136,7 @@ namespace Levels
|
|||||||
{
|
{
|
||||||
return base.CanBeClicked() && isUnlocked;
|
return base.CanBeClicked() && isUnlocked;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Setup: Prevent re-entry while interaction is in progress.
|
|
||||||
/// </summary>
|
|
||||||
protected override void OnInteractionStarted()
|
|
||||||
{
|
|
||||||
switchActive = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Main interaction logic: Spawn menu and switch input mode.
|
/// Main interaction logic: Spawn menu and switch input mode.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -160,7 +144,7 @@ namespace Levels
|
|||||||
{
|
{
|
||||||
if (switchData == null || string.IsNullOrEmpty(switchData.targetLevelSceneName))
|
if (switchData == null || string.IsNullOrEmpty(switchData.targetLevelSceneName))
|
||||||
{
|
{
|
||||||
Debug.LogWarning("MinigameSwitch has no valid switchData!");
|
Logging.Warning("MinigameSwitch has no valid switchData!");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -203,7 +187,7 @@ namespace Levels
|
|||||||
|
|
||||||
private void OnMenuCancel()
|
private void OnMenuCancel()
|
||||||
{
|
{
|
||||||
switchActive = true; // Allow interaction again if cancelled
|
|
||||||
InputManager.Instance.SetInputMode(InputMode.GameAndUI);
|
InputManager.Instance.SetInputMode(InputMode.GameAndUI);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -231,7 +215,7 @@ namespace Levels
|
|||||||
MinigameSwitchSaveData data = JsonUtility.FromJson<MinigameSwitchSaveData>(serializedData);
|
MinigameSwitchSaveData data = JsonUtility.FromJson<MinigameSwitchSaveData>(serializedData);
|
||||||
if (data == null)
|
if (data == null)
|
||||||
{
|
{
|
||||||
Debug.LogWarning($"[MinigameSwitch] Failed to deserialize save data for {gameObject.name}");
|
Logging.Warning($"[MinigameSwitch] Failed to deserialize save data for {gameObject.name}");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -104,13 +104,10 @@ namespace Minigames.DivingForPictures
|
|||||||
|
|
||||||
public static DivingGameManager Instance => _instance;
|
public static DivingGameManager Instance => _instance;
|
||||||
|
|
||||||
public override int ManagedAwakePriority => 190;
|
|
||||||
public override bool AutoRegisterPausable => true; // Automatic GameManager registration
|
public override bool AutoRegisterPausable => true; // Automatic GameManager registration
|
||||||
|
|
||||||
protected override void Awake()
|
internal override void OnManagedAwake()
|
||||||
{
|
{
|
||||||
base.Awake();
|
|
||||||
|
|
||||||
if (_instance == null)
|
if (_instance == null)
|
||||||
{
|
{
|
||||||
_instance = this;
|
_instance = this;
|
||||||
@@ -121,7 +118,7 @@ namespace Minigames.DivingForPictures
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnManagedAwake()
|
internal override void OnManagedStart()
|
||||||
{
|
{
|
||||||
_settings = GameManager.GetSettingsObject<IDivingMinigameSettings>();
|
_settings = GameManager.GetSettingsObject<IDivingMinigameSettings>();
|
||||||
_currentSpawnProbability = _settings?.BaseSpawnProbability ?? 0.2f;
|
_currentSpawnProbability = _settings?.BaseSpawnProbability ?? 0.2f;
|
||||||
@@ -132,7 +129,7 @@ namespace Minigames.DivingForPictures
|
|||||||
Logging.Debug("[DivingGameManager] Initialized");
|
Logging.Debug("[DivingGameManager] Initialized");
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnSceneReady()
|
internal override void OnSceneReady()
|
||||||
{
|
{
|
||||||
InitializeGame();
|
InitializeGame();
|
||||||
|
|
||||||
@@ -164,10 +161,8 @@ namespace Minigames.DivingForPictures
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnDestroy()
|
internal override void OnManagedDestroy()
|
||||||
{
|
{
|
||||||
base.OnDestroy(); // Handles auto-unregister from GameManager
|
|
||||||
|
|
||||||
// Unsubscribe from events when the manager is destroyed
|
// Unsubscribe from events when the manager is destroyed
|
||||||
PlayerCollisionBehavior.OnDamageTaken -= OnPlayerDamageTaken;
|
PlayerCollisionBehavior.OnDamageTaken -= OnPlayerDamageTaken;
|
||||||
OnMonsterSpawned -= DoMonsterSpawned;
|
OnMonsterSpawned -= DoMonsterSpawned;
|
||||||
|
|||||||
@@ -106,9 +106,7 @@ public class FollowerController : ManagedBehaviour
|
|||||||
private bool _hasRestoredHeldItem; // Track if held item restoration completed
|
private bool _hasRestoredHeldItem; // Track if held item restoration completed
|
||||||
private string _expectedHeldItemSaveId; // Expected saveId during restoration
|
private string _expectedHeldItemSaveId; // Expected saveId during restoration
|
||||||
|
|
||||||
public override int ManagedAwakePriority => 110; // Follower after player
|
internal override void OnManagedStart()
|
||||||
|
|
||||||
protected override void OnManagedAwake()
|
|
||||||
{
|
{
|
||||||
_aiPath = GetComponent<AIPath>();
|
_aiPath = GetComponent<AIPath>();
|
||||||
// Find art prefab and animator
|
// Find art prefab and animator
|
||||||
@@ -129,7 +127,7 @@ public class FollowerController : ManagedBehaviour
|
|||||||
_interactionSettings = GameManager.GetSettingsObject<IInteractionSettings>();
|
_interactionSettings = GameManager.GetSettingsObject<IInteractionSettings>();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnSceneReady()
|
internal override void OnSceneReady()
|
||||||
{
|
{
|
||||||
// Find player reference when scene is ready (called for every scene load)
|
// Find player reference when scene is ready (called for every scene load)
|
||||||
FindPlayerReference();
|
FindPlayerReference();
|
||||||
@@ -727,7 +725,7 @@ public class FollowerController : ManagedBehaviour
|
|||||||
|
|
||||||
#region Save/Load Lifecycle Hooks
|
#region Save/Load Lifecycle Hooks
|
||||||
|
|
||||||
protected override string OnSceneSaveRequested()
|
internal override string OnSceneSaveRequested()
|
||||||
{
|
{
|
||||||
var saveData = new FollowerSaveData
|
var saveData = new FollowerSaveData
|
||||||
{
|
{
|
||||||
@@ -754,7 +752,7 @@ public class FollowerController : ManagedBehaviour
|
|||||||
return JsonUtility.ToJson(saveData);
|
return JsonUtility.ToJson(saveData);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnSceneRestoreRequested(string serializedData)
|
internal override void OnSceneRestoreRequested(string serializedData)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(serializedData))
|
if (string.IsNullOrEmpty(serializedData))
|
||||||
{
|
{
|
||||||
@@ -914,7 +912,7 @@ public class FollowerController : ManagedBehaviour
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public static FollowerController FindInstance()
|
public static FollowerController FindInstance()
|
||||||
{
|
{
|
||||||
return FindObjectOfType<FollowerController>();
|
return FindFirstObjectByType<FollowerController>();
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion Save/Load Lifecycle Hooks
|
#endregion Save/Load Lifecycle Hooks
|
||||||
|
|||||||
@@ -1,19 +1,74 @@
|
|||||||
|
using System;
|
||||||
|
using Core;
|
||||||
|
using Core.Lifecycle;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
|
||||||
public class BirdGameStats : MonoBehaviour
|
namespace PuzzleS
|
||||||
{
|
{
|
||||||
public int birdsFoundInLevel;
|
/// <summary>
|
||||||
|
/// Tracks bird discovery progress in the bird finding minigame.
|
||||||
// Start is called once before the first execution of Update after the MonoBehaviour is created
|
/// Saves scene-specific progress using the ManagedBehaviour lifecycle system.
|
||||||
void Start()
|
/// </summary>
|
||||||
|
public class BirdGameStats : ManagedBehaviour
|
||||||
{
|
{
|
||||||
|
public int birdsFoundInLevel;
|
||||||
|
|
||||||
|
// Save system configuration
|
||||||
|
public override bool AutoRegisterForSave => true;
|
||||||
|
|
||||||
|
internal override void OnManagedStart()
|
||||||
|
{
|
||||||
|
// Initialize after all managers are ready
|
||||||
|
}
|
||||||
|
|
||||||
|
public void BirdFound()
|
||||||
|
{
|
||||||
|
birdsFoundInLevel += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Save/Load Lifecycle Hooks
|
||||||
|
|
||||||
|
internal override string OnSceneSaveRequested()
|
||||||
|
{
|
||||||
|
// Save scene-specific progress
|
||||||
|
var state = new BirdGameState
|
||||||
|
{
|
||||||
|
birdsFoundInLevel = this.birdsFoundInLevel
|
||||||
|
};
|
||||||
|
return JsonUtility.ToJson(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal override void OnSceneRestoreRequested(string serializedData)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(serializedData))
|
||||||
|
{
|
||||||
|
// No saved data, keep default values
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var state = JsonUtility.FromJson<BirdGameState>(serializedData);
|
||||||
|
if (state != null)
|
||||||
|
{
|
||||||
|
birdsFoundInLevel = state.birdsFoundInLevel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logging.Warning($"[BirdGameStats] Failed to restore state: {ex.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
}
|
}
|
||||||
|
|
||||||
public void BirdFound()
|
/// <summary>
|
||||||
|
/// Serializable state for bird game progress
|
||||||
|
/// </summary>
|
||||||
|
[Serializable]
|
||||||
|
public class BirdGameState
|
||||||
{
|
{
|
||||||
birdsFoundInLevel += 1;
|
public int birdsFoundInLevel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ namespace PuzzleS
|
|||||||
// Enum for tracking proximity state (simplified to just Close and Far)
|
// Enum for tracking proximity state (simplified to just Close and Far)
|
||||||
public enum ProximityState { Close, Far }
|
public enum ProximityState { Close, Far }
|
||||||
|
|
||||||
protected override void Awake()
|
internal override void OnManagedAwake()
|
||||||
{
|
{
|
||||||
_interactable = GetComponent<InteractableBase>();
|
_interactable = GetComponent<InteractableBase>();
|
||||||
|
|
||||||
@@ -56,14 +56,10 @@ namespace PuzzleS
|
|||||||
Logging.Warning($"[Puzzles] Indicator prefab for {stepData?.stepId} does not implement IPuzzlePrompt");
|
Logging.Warning($"[Puzzles] Indicator prefab for {stepData?.stepId} does not implement IPuzzlePrompt");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
base.Awake();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnManagedAwake()
|
internal override void OnManagedStart()
|
||||||
{
|
{
|
||||||
base.OnManagedAwake();
|
|
||||||
|
|
||||||
// Register with PuzzleManager - safe to access .Instance here
|
// Register with PuzzleManager - safe to access .Instance here
|
||||||
if (stepData != null && PuzzleManager.Instance != null)
|
if (stepData != null && PuzzleManager.Instance != null)
|
||||||
{
|
{
|
||||||
@@ -87,10 +83,8 @@ namespace PuzzleS
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnDestroy()
|
internal override void OnManagedDestroy()
|
||||||
{
|
{
|
||||||
base.OnDestroy();
|
|
||||||
|
|
||||||
if (PuzzleManager.Instance != null && stepData != null)
|
if (PuzzleManager.Instance != null && stepData != null)
|
||||||
{
|
{
|
||||||
PuzzleManager.Instance.UnregisterStepBehaviour(this);
|
PuzzleManager.Instance.UnregisterStepBehaviour(this);
|
||||||
|
|||||||
@@ -93,18 +93,14 @@ namespace PuzzleS
|
|||||||
|
|
||||||
// Track pending unlocks for steps that were unlocked before their behavior registered
|
// Track pending unlocks for steps that were unlocked before their behavior registered
|
||||||
private HashSet<string> _pendingUnlocks = new HashSet<string>();
|
private HashSet<string> _pendingUnlocks = new HashSet<string>();
|
||||||
|
|
||||||
public override int ManagedAwakePriority => 80; // Puzzle systems
|
|
||||||
|
|
||||||
private new void Awake()
|
internal override void OnManagedAwake()
|
||||||
{
|
{
|
||||||
base.Awake(); // CRITICAL: Register with LifecycleManager!
|
// Set instance immediately (early initialization)
|
||||||
|
|
||||||
// Set instance immediately so it's available before OnManagedAwake() is called
|
|
||||||
_instance = this;
|
_instance = this;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnManagedAwake()
|
internal override void OnManagedStart()
|
||||||
{
|
{
|
||||||
// Initialize settings reference
|
// Initialize settings reference
|
||||||
_interactionSettings = GameManager.GetSettingsObject<IInteractionSettings>();
|
_interactionSettings = GameManager.GetSettingsObject<IInteractionSettings>();
|
||||||
@@ -140,10 +136,8 @@ namespace PuzzleS
|
|||||||
LoadPuzzlesForScene(sceneName);
|
LoadPuzzlesForScene(sceneName);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnDestroy()
|
internal override void OnManagedDestroy()
|
||||||
{
|
{
|
||||||
base.OnDestroy();
|
|
||||||
|
|
||||||
// Unsubscribe from SceneManagerService events
|
// Unsubscribe from SceneManagerService events
|
||||||
if (SceneManagerService.Instance != null)
|
if (SceneManagerService.Instance != null)
|
||||||
{
|
{
|
||||||
@@ -591,7 +585,7 @@ namespace PuzzleS
|
|||||||
|
|
||||||
#region Save/Load Lifecycle Hooks
|
#region Save/Load Lifecycle Hooks
|
||||||
|
|
||||||
protected override string OnSceneSaveRequested()
|
internal override string OnSceneSaveRequested()
|
||||||
{
|
{
|
||||||
if (_currentLevelData == null)
|
if (_currentLevelData == null)
|
||||||
{
|
{
|
||||||
@@ -611,9 +605,9 @@ namespace PuzzleS
|
|||||||
return json;
|
return json;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnSceneRestoreRequested(string data)
|
internal override void OnSceneRestoreRequested(string data)
|
||||||
{
|
{
|
||||||
Debug.Log("[XAXA] PuzzleManager loading with data: " + data);
|
Logging.Debug("[XAXA] PuzzleManager loading with data: " + data);
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(data) || data == "{}")
|
if (string.IsNullOrEmpty(data) || data == "{}")
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -3,12 +3,14 @@ using System;
|
|||||||
using System.Diagnostics.Tracing;
|
using System.Diagnostics.Tracing;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityEngine.Audio;
|
using UnityEngine.Audio;
|
||||||
|
using Core;
|
||||||
|
using Core.Lifecycle;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// We automatically add the AudioSource component here so we can control it. Do not add it manually!
|
/// We automatically add the AudioSource component here so we can control it. Do not add it manually!
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[RequireComponent(typeof(AudioSource))]
|
[RequireComponent(typeof(AudioSource))]
|
||||||
public class AppleAudioSource : MonoBehaviour
|
public class AppleAudioSource : ManagedBehaviour
|
||||||
{
|
{
|
||||||
public enum AudioSourceType{CriticalVO,VO,Ambience,SFX,Music}
|
public enum AudioSourceType{CriticalVO,VO,Ambience,SFX,Music}
|
||||||
public AudioSourceType audioSourceType;
|
public AudioSourceType audioSourceType;
|
||||||
@@ -17,10 +19,14 @@ public class AppleAudioSource : MonoBehaviour
|
|||||||
[HideInInspector ] public int clipPriority;
|
[HideInInspector ] public int clipPriority;
|
||||||
public int sourcePriority;
|
public int sourcePriority;
|
||||||
|
|
||||||
// Start is called once before the first execution of Update after the MonoBehaviour is created
|
|
||||||
void OnEnable()
|
internal override void OnManagedAwake()
|
||||||
{
|
{
|
||||||
audioSource = GetComponent<AudioSource>();
|
audioSource = GetComponent<AudioSource>();
|
||||||
|
}
|
||||||
|
|
||||||
|
internal override void OnManagedStart()
|
||||||
|
{
|
||||||
AudioManager.Instance.RegisterNewAudioSource(this);
|
AudioManager.Instance.RegisterNewAudioSource(this);
|
||||||
_audioMixer = AudioManager.Instance.audioMixer;
|
_audioMixer = AudioManager.Instance.audioMixer;
|
||||||
InitializeAudioSource();
|
InitializeAudioSource();
|
||||||
@@ -54,6 +60,10 @@ public class AppleAudioSource : MonoBehaviour
|
|||||||
|
|
||||||
public void Play(int requestedClipPriority)
|
public void Play(int requestedClipPriority)
|
||||||
{
|
{
|
||||||
|
if (audioSource == null)
|
||||||
|
{
|
||||||
|
audioSource = GetComponent<AudioSource>();
|
||||||
|
}
|
||||||
clipPriority = requestedClipPriority;
|
clipPriority = requestedClipPriority;
|
||||||
if (audioSourceType == AudioSourceType.CriticalVO || audioSourceType == AudioSourceType.VO)
|
if (audioSourceType == AudioSourceType.CriticalVO || audioSourceType == AudioSourceType.VO)
|
||||||
{
|
{
|
||||||
@@ -63,7 +73,7 @@ public class AppleAudioSource : MonoBehaviour
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Debug.Log("[AUDIOMANAGER] AppleAudioSource " + name + " was suppressed because something more important is playing");
|
Logging.Debug("[AUDIOMANAGER] AppleAudioSource " + name + " was suppressed because something more important is playing");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ using AppleHills.Core.Interfaces;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using AudioSourceEvents;
|
using AudioSourceEvents;
|
||||||
using System;
|
using System;
|
||||||
|
using Core;
|
||||||
using Core.Lifecycle;
|
using Core.Lifecycle;
|
||||||
|
|
||||||
public class AudioManager : ManagedBehaviour, IPausable
|
public class AudioManager : ManagedBehaviour, IPausable
|
||||||
@@ -39,19 +40,15 @@ public class AudioManager : ManagedBehaviour, IPausable
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public static AudioManager Instance => _instance;
|
public static AudioManager Instance => _instance;
|
||||||
|
|
||||||
// ManagedBehaviour configuration
|
|
||||||
public override int ManagedAwakePriority => 30; // Audio infrastructure
|
|
||||||
public override bool AutoRegisterPausable => true; // Auto-register as IPausable
|
public override bool AutoRegisterPausable => true; // Auto-register as IPausable
|
||||||
|
|
||||||
private new void Awake()
|
internal override void OnManagedAwake()
|
||||||
{
|
{
|
||||||
base.Awake(); // CRITICAL: Register with LifecycleManager!
|
// Set instance immediately (early initialization)
|
||||||
|
|
||||||
// Set instance immediately so it's available before OnManagedAwake() is called
|
|
||||||
_instance = this;
|
_instance = this;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnManagedAwake()
|
internal override void OnManagedStart()
|
||||||
{
|
{
|
||||||
// Initialize lists if they were not set in inspector
|
// Initialize lists if they were not set in inspector
|
||||||
criticalVOSources = criticalVOSources ?? new List<AppleAudioSource>();
|
criticalVOSources = criticalVOSources ?? new List<AppleAudioSource>();
|
||||||
@@ -71,16 +68,14 @@ public class AudioManager : ManagedBehaviour, IPausable
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Debug.LogWarning("[AudioManager] QuickAccess.Instance is null during OnManagedAwake. Some audio references may remain unset.");
|
Logging.Warning("[AudioManager] QuickAccess.Instance is null during OnManagedStart. Some audio references may remain unset.");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Diagnostic
|
// Diagnostic
|
||||||
foreach (AppleAudioSource _audioSource in criticalVOSources)
|
foreach (AppleAudioSource _audioSource in criticalVOSources)
|
||||||
{
|
{
|
||||||
Debug.Log("Found source: " + _audioSource.name);
|
Logging.Debug("Found source: " + _audioSource.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
Debug.Log("[AudioManager] OnManagedAwake completed");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetAudioPauseBehavior(PauseBehavior newPauseBehavior)
|
public void SetAudioPauseBehavior(PauseBehavior newPauseBehavior)
|
||||||
@@ -104,15 +99,15 @@ public class AudioManager : ManagedBehaviour, IPausable
|
|||||||
|
|
||||||
public LevelAudioObject GetCurrentLevelAudioObject()
|
public LevelAudioObject GetCurrentLevelAudioObject()
|
||||||
{
|
{
|
||||||
Debug.Log("Audio objects: " + FindObjectsByType<LevelAudioObject>(FindObjectsInactive.Include, FindObjectsSortMode.None).Length);
|
Logging.Debug("Audio objects: " + FindObjectsByType<LevelAudioObject>(FindObjectsInactive.Include, FindObjectsSortMode.None).Length);
|
||||||
if (FindObjectsByType<LevelAudioObject>(FindObjectsInactive.Include, FindObjectsSortMode.None).Length > 1)
|
if (FindObjectsByType<LevelAudioObject>(FindObjectsInactive.Include, FindObjectsSortMode.None).Length > 1)
|
||||||
{
|
{
|
||||||
Debug.LogWarning("Warning! More than one LevelAudioObject in the level! Using the first one found");
|
Logging.Warning("Warning! More than one LevelAudioObject in the level! Using the first one found");
|
||||||
return FindObjectsByType<LevelAudioObject>(FindObjectsInactive.Include, FindObjectsSortMode.None)[0];
|
return FindObjectsByType<LevelAudioObject>(FindObjectsInactive.Include, FindObjectsSortMode.None)[0];
|
||||||
}
|
}
|
||||||
if (FindObjectsByType<LevelAudioObject>(FindObjectsInactive.Include, FindObjectsSortMode.None).Length == 0)
|
if (FindObjectsByType<LevelAudioObject>(FindObjectsInactive.Include, FindObjectsSortMode.None).Length == 0)
|
||||||
{
|
{
|
||||||
Debug.LogWarning("Error! No LevelAudioObject found, AudioManager might not function properly!");
|
Logging.Warning("Error! No LevelAudioObject found, AudioManager might not function properly!");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -158,12 +153,10 @@ public class AudioManager : ManagedBehaviour, IPausable
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public bool RequestPlayVO(AppleAudioSource requestedAudioSource)
|
public bool RequestPlayVO(AppleAudioSource requestedAudioSource)
|
||||||
{
|
{
|
||||||
//Debug.Log($"[AUDIOMANAGER] CurrentVO source prio: {currentlyPlayingVO.sourcePriority}, clip prio: {currentlyPlayingVO.clipPriority} requested VO prio: {requestedAudioSource.sourcePriority}, clip prio: {clipPriority}");
|
|
||||||
// If nothing is playing, let the requested audio source play
|
// If nothing is playing, let the requested audio source play
|
||||||
if (currentlyPlayingVO == null)
|
if (currentlyPlayingVO == null)
|
||||||
{
|
{
|
||||||
SetupNewAudioSource(requestedAudioSource);
|
SetupNewAudioSource(requestedAudioSource);
|
||||||
Debug.Log($"[AUDIOMANAGER] Playing {currentlyPlayingVO.name} as nothing is currently playing.");
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -177,7 +170,6 @@ public class AudioManager : ManagedBehaviour, IPausable
|
|||||||
{
|
{
|
||||||
InterruptAudioSource(requestedAudioSource);
|
InterruptAudioSource(requestedAudioSource);
|
||||||
SetupNewAudioSource(requestedAudioSource);
|
SetupNewAudioSource(requestedAudioSource);
|
||||||
Debug.Log($"[AUDIOMANAGER] {currentlyPlayingVO.name} is the same as {requestedAudioSource.name}. Triggering it again.");
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -187,7 +179,6 @@ public class AudioManager : ManagedBehaviour, IPausable
|
|||||||
|
|
||||||
InterruptAudioSource(requestedAudioSource);
|
InterruptAudioSource(requestedAudioSource);
|
||||||
SetupNewAudioSource(requestedAudioSource);
|
SetupNewAudioSource(requestedAudioSource);
|
||||||
Debug.Log($"[AUDIOMANAGER] {currentlyPlayingVO.name} is not critical. Playing {requestedAudioSource.name} instead because it is critical.");
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
// If the requested audio source has the same priority as currently playing source, check the priority of the requested clip
|
// If the requested audio source has the same priority as currently playing source, check the priority of the requested clip
|
||||||
@@ -197,8 +188,6 @@ public class AudioManager : ManagedBehaviour, IPausable
|
|||||||
{
|
{
|
||||||
InterruptAudioSource(requestedAudioSource);
|
InterruptAudioSource(requestedAudioSource);
|
||||||
SetupNewAudioSource(requestedAudioSource);
|
SetupNewAudioSource(requestedAudioSource);
|
||||||
Debug.Log($"[AUDIOMANAGER] Interrupted {currentlyPlayingVO.name} because it has same priority as {requestedAudioSource.name} but the requested clip has higher priority");
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -210,7 +199,6 @@ public class AudioManager : ManagedBehaviour, IPausable
|
|||||||
if (currentlyPlayingVO.audioSourceType == AppleAudioSource.AudioSourceType.CriticalVO && currentlyPlayingVO.sourcePriority > requestedAudioSource.sourcePriority)
|
if (currentlyPlayingVO.audioSourceType == AppleAudioSource.AudioSourceType.CriticalVO && currentlyPlayingVO.sourcePriority > requestedAudioSource.sourcePriority)
|
||||||
{
|
{
|
||||||
currentlyPlayingVO.InterruptAudio(requestedAudioSource.name);
|
currentlyPlayingVO.InterruptAudio(requestedAudioSource.name);
|
||||||
Debug.Log($"[AUDIOMANAGER] Interrupted {currentlyPlayingVO.name} because {requestedAudioSource.name} has higher priority");
|
|
||||||
InterruptAudioSource(requestedAudioSource);
|
InterruptAudioSource(requestedAudioSource);
|
||||||
SetupNewAudioSource(requestedAudioSource);
|
SetupNewAudioSource(requestedAudioSource);
|
||||||
return true;
|
return true;
|
||||||
@@ -218,7 +206,6 @@ public class AudioManager : ManagedBehaviour, IPausable
|
|||||||
// If the requested audio source didn't clear any of the above cases, tell it to get rekt.
|
// If the requested audio source didn't clear any of the above cases, tell it to get rekt.
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Debug.Log($"[AUDIOMANAGER] {currentlyPlayingVO.name} is still playing. {requestedAudioSource.name} has lower priority");
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -232,7 +219,6 @@ public class AudioManager : ManagedBehaviour, IPausable
|
|||||||
{
|
{
|
||||||
if (audioSource.audioSource.resource == null)
|
if (audioSource.audioSource.resource == null)
|
||||||
{
|
{
|
||||||
Debug.Log($"[AUDIOMANAGER] Faled to setup {audioSource.name}. Invalid resource");
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -281,7 +267,15 @@ public class AudioManager : ManagedBehaviour, IPausable
|
|||||||
{
|
{
|
||||||
foreach (AppleAudioSource source in criticalVOSources)
|
foreach (AppleAudioSource source in criticalVOSources)
|
||||||
{
|
{
|
||||||
source.InterruptAudio("GlobalInterrupt");
|
if (source == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
source.InterruptAudio("GlobalInterrupt");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
foreach (AppleAudioSource source in VOSources)
|
foreach (AppleAudioSource source in VOSources)
|
||||||
|
|||||||
@@ -4,8 +4,11 @@ using System;
|
|||||||
using System.Diagnostics.Tracing;
|
using System.Diagnostics.Tracing;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityEngine.Audio;
|
using UnityEngine.Audio;
|
||||||
|
using Core;
|
||||||
|
using Core.Lifecycle;
|
||||||
|
using PuzzleS;
|
||||||
|
|
||||||
public class BushAudioController : MonoBehaviour
|
public class BushAudioController : ManagedBehaviour
|
||||||
{
|
{
|
||||||
private IAudioEventSource _eventSource;
|
private IAudioEventSource _eventSource;
|
||||||
public AppleAudioSource VOPlayer;
|
public AppleAudioSource VOPlayer;
|
||||||
@@ -20,7 +23,7 @@ public class BushAudioController : MonoBehaviour
|
|||||||
|
|
||||||
|
|
||||||
// Start is called once before the first execution of Update after the MonoBehaviour is created
|
// Start is called once before the first execution of Update after the MonoBehaviour is created
|
||||||
void Start()
|
internal override void OnManagedStart()
|
||||||
{
|
{
|
||||||
_eventSource = VOPlayer.audioSource.RequestEventHandlers();
|
_eventSource = VOPlayer.audioSource.RequestEventHandlers();
|
||||||
_eventSource.AudioStopped += PlayBirdCounter;
|
_eventSource.AudioStopped += PlayBirdCounter;
|
||||||
@@ -48,9 +51,9 @@ public class BushAudioController : MonoBehaviour
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnDisable()
|
//public void OnDisable()
|
||||||
{
|
//{
|
||||||
// Unsubscribe from events when disabled
|
// // Unsubscribe from events when disabled
|
||||||
_eventSource.AudioStopped -= PlayBirdCounter;
|
// _eventSource.AudioStopped -= PlayBirdCounter;
|
||||||
}
|
//}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,22 +1,81 @@
|
|||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityEngine.Audio;
|
using UnityEngine.Audio;
|
||||||
using System;
|
using System;
|
||||||
|
using Core;
|
||||||
|
using Core.Lifecycle;
|
||||||
|
|
||||||
public class LevelAudioObject : MonoBehaviour
|
[Serializable]
|
||||||
|
public class LevelAudioObjectSaveData
|
||||||
{
|
{
|
||||||
|
public bool hasPlayed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class LevelAudioObject : ManagedBehaviour
|
||||||
|
{
|
||||||
|
[Header("Audio Settings")]
|
||||||
public AppleAudioSource narratorAudioSource;
|
public AppleAudioSource narratorAudioSource;
|
||||||
public AudioResource firstNarration;
|
public AudioResource firstNarration;
|
||||||
|
|
||||||
|
[Header("Playback Settings")]
|
||||||
|
[Tooltip("If true, the audio will only play once and never again after being played")]
|
||||||
|
public bool isOneTime;
|
||||||
|
|
||||||
// Start is called once before the first execution of Update after the MonoBehaviour is created
|
private bool _hasPlayed;
|
||||||
void Start()
|
|
||||||
|
#region ManagedBehaviour Overrides
|
||||||
|
|
||||||
|
public override bool AutoRegisterForSave => isOneTime; // Only save if one-time audio
|
||||||
|
|
||||||
|
internal override string OnSceneSaveRequested()
|
||||||
{
|
{
|
||||||
PlayNarrationAudio();
|
if (!isOneTime)
|
||||||
|
return null; // No need to save if not one-time
|
||||||
|
|
||||||
|
LevelAudioObjectSaveData saveData = new LevelAudioObjectSaveData
|
||||||
|
{
|
||||||
|
hasPlayed = _hasPlayed
|
||||||
|
};
|
||||||
|
|
||||||
|
return JsonUtility.ToJson(saveData);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlayNarrationAudio()
|
internal override void OnSceneRestoreRequested(string serializedData)
|
||||||
{
|
{
|
||||||
|
if (!isOneTime || string.IsNullOrEmpty(serializedData))
|
||||||
|
return;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
LevelAudioObjectSaveData saveData = JsonUtility.FromJson<LevelAudioObjectSaveData>(serializedData);
|
||||||
|
_hasPlayed = saveData.hasPlayed;
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Logging.Warning($"[LevelAudioObject] Failed to restore audio state: {e.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal override void OnSceneRestoreCompleted()
|
||||||
|
{
|
||||||
|
if (isOneTime && !_hasPlayed)
|
||||||
|
{
|
||||||
|
PlayNarrationAudio();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
private void PlayNarrationAudio()
|
||||||
|
{
|
||||||
|
if (narratorAudioSource == null || firstNarration == null)
|
||||||
|
{
|
||||||
|
Logging.Warning($"[LevelAudioObject] Missing audio source or narration resource on {gameObject.name}");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
narratorAudioSource.audioSource.resource = firstNarration;
|
narratorAudioSource.audioSource.resource = firstNarration;
|
||||||
narratorAudioSource.Play(0);
|
narratorAudioSource.Play(0);
|
||||||
|
|
||||||
|
_hasPlayed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
using Core;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
|
||||||
public class ProximitySoundReaction : MonoBehaviour
|
public class ProximitySoundReaction : MonoBehaviour
|
||||||
@@ -12,13 +13,13 @@ public class ProximitySoundReaction : MonoBehaviour
|
|||||||
|
|
||||||
private void OnCollisionEnter2D(Collision2D collision)
|
private void OnCollisionEnter2D(Collision2D collision)
|
||||||
{
|
{
|
||||||
Debug.Log("overlap!");
|
Logging.Debug("overlap!");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnTriggerEnter2D(Collider2D collision)
|
private void OnTriggerEnter2D(Collider2D collision)
|
||||||
{
|
{
|
||||||
Debug.Log("Wolter triggered!");
|
Logging.Debug("Wolter triggered!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,18 +1,17 @@
|
|||||||
using Core;
|
using Core;
|
||||||
|
using Core.Lifecycle;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityEngine.Audio;
|
using UnityEngine.Audio;
|
||||||
|
|
||||||
public class PulverAudioController : MonoBehaviour
|
public class PulverAudioController : ManagedBehaviour
|
||||||
{
|
{
|
||||||
private AppleAudioSource audioSource;
|
public AppleAudioSource audioSource;
|
||||||
public AudioResource combineAudio;
|
public AudioResource combineAudio;
|
||||||
private FollowerController followerController;
|
private FollowerController followerController;
|
||||||
public ItemManager itemManager;
|
public ItemManager itemManager;
|
||||||
|
|
||||||
// Start is called once before the first execution of Update after the MonoBehaviour is created
|
internal override void OnManagedStart()
|
||||||
void Start()
|
|
||||||
{
|
{
|
||||||
audioSource = GetComponent<AppleAudioSource>();
|
|
||||||
followerController = GetComponent<FollowerController>();
|
followerController = GetComponent<FollowerController>();
|
||||||
followerController.PulverIsCombining.AddListener(PulverIsCombining);
|
followerController.PulverIsCombining.AddListener(PulverIsCombining);
|
||||||
|
|
||||||
|
|||||||
@@ -25,10 +25,10 @@ public class AppSwitcher : UIPage
|
|||||||
private TweenBase slideInTween;
|
private TweenBase slideInTween;
|
||||||
private TweenBase slideOutTween;
|
private TweenBase slideOutTween;
|
||||||
|
|
||||||
protected override void OnManagedAwake()
|
internal override void OnManagedAwake()
|
||||||
{
|
{
|
||||||
base.OnManagedAwake();
|
base.OnManagedAwake();
|
||||||
|
|
||||||
PageName = "AppSwitcher";
|
PageName = "AppSwitcher";
|
||||||
rainbowInPlayer = rainbowIn.GetComponent<SkottiePlayerV2>();
|
rainbowInPlayer = rainbowIn.GetComponent<SkottiePlayerV2>();
|
||||||
rainbowOutPlayer = rainbowOut.GetComponent<SkottiePlayerV2>();
|
rainbowOutPlayer = rainbowOut.GetComponent<SkottiePlayerV2>();
|
||||||
@@ -110,10 +110,8 @@ public class AppSwitcher : UIPage
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnDestroy()
|
internal override void OnManagedDestroy()
|
||||||
{
|
{
|
||||||
base.OnDestroy();
|
|
||||||
|
|
||||||
// Clean up tweens
|
// Clean up tweens
|
||||||
slideInTween?.Stop();
|
slideInTween?.Stop();
|
||||||
slideOutTween?.Stop();
|
slideOutTween?.Stop();
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using AppleHills.Data.CardSystem;
|
using AppleHills.Data.CardSystem;
|
||||||
|
using Core;
|
||||||
using Pixelplacement;
|
using Pixelplacement;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityEngine.EventSystems;
|
using UnityEngine.EventSystems;
|
||||||
@@ -82,37 +83,37 @@ namespace UI.CardSystem
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public void OnPointerClick(PointerEventData eventData)
|
public void OnPointerClick(PointerEventData eventData)
|
||||||
{
|
{
|
||||||
Debug.Log($"[CLICK-TRACE-ALBUMCARD] OnPointerClick on {name}, _parentSlot={((_parentSlot != null) ? _parentSlot.name : "NULL")}, _isEnlarged={_isEnlarged}, position={eventData.position}");
|
Logging.Debug($"[CLICK-TRACE-ALBUMCARD] OnPointerClick on {name}, _parentSlot={((_parentSlot != null) ? _parentSlot.name : "NULL")}, _isEnlarged={_isEnlarged}, position={eventData.position}");
|
||||||
|
|
||||||
// During reveal flow (before placed in slot), forward clicks to parent FlippableCard
|
// During reveal flow (before placed in slot), forward clicks to parent FlippableCard
|
||||||
if (_parentSlot == null)
|
if (_parentSlot == null)
|
||||||
{
|
{
|
||||||
Debug.Log($"[CLICK-TRACE-ALBUMCARD] {name} - No parent slot, forwarding click to parent FlippableCard");
|
Logging.Debug($"[CLICK-TRACE-ALBUMCARD] {name} - No parent slot, forwarding click to parent FlippableCard");
|
||||||
|
|
||||||
// Find parent FlippableCard and forward the click
|
// Find parent FlippableCard and forward the click
|
||||||
FlippableCard parentFlippable = GetComponentInParent<FlippableCard>();
|
FlippableCard parentFlippable = GetComponentInParent<FlippableCard>();
|
||||||
if (parentFlippable != null)
|
if (parentFlippable != null)
|
||||||
{
|
{
|
||||||
Debug.Log($"[CLICK-TRACE-ALBUMCARD] {name} - Found parent FlippableCard, calling OnPointerClick");
|
Logging.Debug($"[CLICK-TRACE-ALBUMCARD] {name} - Found parent FlippableCard, calling OnPointerClick");
|
||||||
parentFlippable.OnPointerClick(eventData);
|
parentFlippable.OnPointerClick(eventData);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Debug.LogWarning($"[CLICK-TRACE-ALBUMCARD] {name} - No parent FlippableCard found!");
|
Logging.Warning($"[CLICK-TRACE-ALBUMCARD] {name} - No parent FlippableCard found!");
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Debug.Log($"[CLICK-TRACE-ALBUMCARD] {name} - Has parent slot, processing click");
|
Logging.Debug($"[CLICK-TRACE-ALBUMCARD] {name} - Has parent slot, processing click");
|
||||||
|
|
||||||
if (_isEnlarged)
|
if (_isEnlarged)
|
||||||
{
|
{
|
||||||
Debug.Log($"[CLICK-TRACE-ALBUMCARD] {name} - Is enlarged, requesting shrink");
|
Logging.Debug($"[CLICK-TRACE-ALBUMCARD] {name} - Is enlarged, requesting shrink");
|
||||||
OnShrinkRequested?.Invoke(this);
|
OnShrinkRequested?.Invoke(this);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Debug.Log($"[CLICK-TRACE-ALBUMCARD] {name} - Is normal size, requesting enlarge");
|
Logging.Debug($"[CLICK-TRACE-ALBUMCARD] {name} - Is normal size, requesting enlarge");
|
||||||
OnEnlargeRequested?.Invoke(this);
|
OnEnlargeRequested?.Invoke(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,7 +24,9 @@ namespace UI.CardSystem
|
|||||||
[SerializeField] private BookCurlPro.BookPro book;
|
[SerializeField] private BookCurlPro.BookPro book;
|
||||||
|
|
||||||
[Header("Zone Navigation")]
|
[Header("Zone Navigation")]
|
||||||
[SerializeField] private BookTabButton[] zoneTabs; // All zone tab buttons
|
[SerializeField] private Transform tabContainer; // Container holding all BookTabButton children
|
||||||
|
|
||||||
|
private BookTabButton[] zoneTabs; // Discovered zone tab buttons
|
||||||
|
|
||||||
[Header("Album Card Reveal")]
|
[Header("Album Card Reveal")]
|
||||||
[SerializeField] private SlotContainer bottomRightSlots;
|
[SerializeField] private SlotContainer bottomRightSlots;
|
||||||
@@ -42,9 +44,10 @@ namespace UI.CardSystem
|
|||||||
private List<AlbumCardPlacementDraggable> _activeCards = new List<AlbumCardPlacementDraggable>();
|
private List<AlbumCardPlacementDraggable> _activeCards = new List<AlbumCardPlacementDraggable>();
|
||||||
private const int MAX_VISIBLE_CARDS = 3;
|
private const int MAX_VISIBLE_CARDS = 3;
|
||||||
|
|
||||||
protected override void OnManagedAwake()
|
internal override void OnManagedStart()
|
||||||
{
|
{
|
||||||
base.OnManagedAwake();
|
// Discover zone tabs from container
|
||||||
|
DiscoverZoneTabs();
|
||||||
|
|
||||||
// Make sure we have a CanvasGroup for transitions
|
// Make sure we have a CanvasGroup for transitions
|
||||||
if (canvasGroup == null)
|
if (canvasGroup == null)
|
||||||
@@ -67,6 +70,17 @@ namespace UI.CardSystem
|
|||||||
// Set up booster pack button listeners
|
// Set up booster pack button listeners
|
||||||
SetupBoosterButtonListeners();
|
SetupBoosterButtonListeners();
|
||||||
|
|
||||||
|
// Subscribe to book page flip events
|
||||||
|
if (book != null)
|
||||||
|
{
|
||||||
|
book.OnFlip.AddListener(OnPageFlipped);
|
||||||
|
Logging.Debug("[AlbumViewPage] Subscribed to book.OnFlip event");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Logging.Warning("[AlbumViewPage] Book reference is null, cannot subscribe to OnFlip event!");
|
||||||
|
}
|
||||||
|
|
||||||
// Subscribe to CardSystemManager events (managers are guaranteed to be initialized)
|
// Subscribe to CardSystemManager events (managers are guaranteed to be initialized)
|
||||||
if (CardSystemManager.Instance != null)
|
if (CardSystemManager.Instance != null)
|
||||||
{
|
{
|
||||||
@@ -83,6 +97,36 @@ namespace UI.CardSystem
|
|||||||
gameObject.SetActive(false);
|
gameObject.SetActive(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Discover all BookTabButton components from the tab container
|
||||||
|
/// </summary>
|
||||||
|
private void DiscoverZoneTabs()
|
||||||
|
{
|
||||||
|
if (tabContainer == null)
|
||||||
|
{
|
||||||
|
Debug.LogError("[AlbumViewPage] Tab container is not assigned! Cannot discover zone tabs.");
|
||||||
|
zoneTabs = new BookTabButton[0];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get all BookTabButton components from children
|
||||||
|
zoneTabs = tabContainer.GetComponentsInChildren<BookTabButton>(includeInactive: false);
|
||||||
|
|
||||||
|
if (zoneTabs == null || zoneTabs.Length == 0)
|
||||||
|
{
|
||||||
|
Logging.Warning($"[AlbumViewPage] No BookTabButton components found in tab container '{tabContainer.name}'!");
|
||||||
|
zoneTabs = new BookTabButton[0];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Logging.Debug($"[AlbumViewPage] Discovered {zoneTabs.Length} zone tabs from container '{tabContainer.name}'");
|
||||||
|
foreach (var tab in zoneTabs)
|
||||||
|
{
|
||||||
|
Logging.Debug($" - Tab: {tab.name}, Zone: {tab.Zone}, TargetPage: {tab.TargetPage}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void SetupBoosterButtonListeners()
|
private void SetupBoosterButtonListeners()
|
||||||
{
|
{
|
||||||
if (boosterPackButtons == null) return;
|
if (boosterPackButtons == null) return;
|
||||||
@@ -90,6 +134,12 @@ namespace UI.CardSystem
|
|||||||
for (int i = 0; i < boosterPackButtons.Length; i++)
|
for (int i = 0; i < boosterPackButtons.Length; i++)
|
||||||
{
|
{
|
||||||
if (boosterPackButtons[i] == null) continue;
|
if (boosterPackButtons[i] == null) continue;
|
||||||
|
// Unsubscribe from book events
|
||||||
|
if (book != null)
|
||||||
|
{
|
||||||
|
book.OnFlip.RemoveListener(OnPageFlipped);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Button button = boosterPackButtons[i].GetComponent<Button>();
|
Button button = boosterPackButtons[i].GetComponent<Button>();
|
||||||
if (button != null)
|
if (button != null)
|
||||||
@@ -99,7 +149,7 @@ namespace UI.CardSystem
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnDestroy()
|
internal override void OnManagedDestroy()
|
||||||
{
|
{
|
||||||
// Unsubscribe from CardSystemManager
|
// Unsubscribe from CardSystemManager
|
||||||
if (CardSystemManager.Instance != null)
|
if (CardSystemManager.Instance != null)
|
||||||
@@ -131,9 +181,6 @@ namespace UI.CardSystem
|
|||||||
|
|
||||||
// Clean up active cards
|
// Clean up active cards
|
||||||
CleanupActiveCards();
|
CleanupActiveCards();
|
||||||
|
|
||||||
// Call base implementation
|
|
||||||
base.OnDestroy();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnExitButtonClicked()
|
private void OnExitButtonClicked()
|
||||||
@@ -157,7 +204,7 @@ namespace UI.CardSystem
|
|||||||
if (Input.InputManager.Instance != null)
|
if (Input.InputManager.Instance != null)
|
||||||
{
|
{
|
||||||
Input.InputManager.Instance.SetInputMode(_previousInputMode);
|
Input.InputManager.Instance.SetInputMode(_previousInputMode);
|
||||||
Debug.Log($"[AlbumViewPage] Restored input mode to {_previousInputMode} on exit");
|
Logging.Debug($"[AlbumViewPage] Restored input mode to {_previousInputMode} on exit");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (UIPageController.Instance != null)
|
if (UIPageController.Instance != null)
|
||||||
@@ -208,7 +255,7 @@ namespace UI.CardSystem
|
|||||||
// Store the current input mode before switching
|
// Store the current input mode before switching
|
||||||
_previousInputMode = Input.InputMode.GameAndUI;
|
_previousInputMode = Input.InputMode.GameAndUI;
|
||||||
Input.InputManager.Instance.SetInputMode(Input.InputMode.UI);
|
Input.InputManager.Instance.SetInputMode(Input.InputMode.UI);
|
||||||
Debug.Log("[AlbumViewPage] Switched to UI-only input mode on first entry");
|
Logging.Debug("[AlbumViewPage] Switched to UI-only input mode on first entry");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Subscribe to pending card events while page is active
|
// Subscribe to pending card events while page is active
|
||||||
@@ -217,8 +264,16 @@ namespace UI.CardSystem
|
|||||||
CardSystemManager.Instance.OnPendingCardAdded += OnPendingCardAdded;
|
CardSystemManager.Instance.OnPendingCardAdded += OnPendingCardAdded;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Spawn pending cards when opening album
|
// Only spawn pending cards if we're already on an album page (not the menu)
|
||||||
SpawnPendingCards();
|
if (IsInAlbumProper())
|
||||||
|
{
|
||||||
|
Logging.Debug("[AlbumViewPage] Opening directly to album page - spawning cards immediately");
|
||||||
|
SpawnPendingCards();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Logging.Debug("[AlbumViewPage] Opening to menu page - cards will spawn when entering album");
|
||||||
|
}
|
||||||
|
|
||||||
base.TransitionIn();
|
base.TransitionIn();
|
||||||
}
|
}
|
||||||
@@ -231,6 +286,9 @@ namespace UI.CardSystem
|
|||||||
CardSystemManager.Instance.OnPendingCardAdded -= OnPendingCardAdded;
|
CardSystemManager.Instance.OnPendingCardAdded -= OnPendingCardAdded;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Clean up active pending cards to prevent duplicates on next opening
|
||||||
|
CleanupActiveCards();
|
||||||
|
|
||||||
// Don't restore input mode here - only restore when actually exiting (in OnExitButtonClicked)
|
// Don't restore input mode here - only restore when actually exiting (in OnExitButtonClicked)
|
||||||
base.TransitionOut();
|
base.TransitionOut();
|
||||||
}
|
}
|
||||||
@@ -304,6 +362,46 @@ namespace UI.CardSystem
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Check if we're currently viewing the album proper (not the menu page)
|
||||||
|
/// </summary>
|
||||||
|
private bool IsInAlbumProper()
|
||||||
|
{
|
||||||
|
if (book == null)
|
||||||
|
{
|
||||||
|
Logging.Warning("[AlbumViewPage] Book reference is null in IsInAlbumProper check");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Page 1 is the menu/cover, page 2+ are album pages with card slots
|
||||||
|
bool inAlbum = book.CurrentPaper > 1;
|
||||||
|
return inAlbum;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Called when book page flips - show/hide pending cards based on whether we're in the album proper
|
||||||
|
/// </summary>
|
||||||
|
private void OnPageFlipped()
|
||||||
|
{
|
||||||
|
bool isInAlbum = IsInAlbumProper();
|
||||||
|
if (isInAlbum && _activeCards.Count == 0)
|
||||||
|
{
|
||||||
|
// Entering album proper and no cards spawned yet - spawn them with animation
|
||||||
|
Logging.Debug("[AlbumViewPage] Entering album proper - spawning pending cards with animation");
|
||||||
|
SpawnPendingCards();
|
||||||
|
}
|
||||||
|
else if (!isInAlbum && _activeCards.Count > 0)
|
||||||
|
{
|
||||||
|
// Returning to menu page - cleanup cards
|
||||||
|
Logging.Debug("[AlbumViewPage] Returning to menu page - cleaning up pending cards");
|
||||||
|
CleanupActiveCards();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Logging.Debug($"[AlbumViewPage] Page flipped but no card state change needed (already in correct state)");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#region Album Card Reveal System
|
#region Album Card Reveal System
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -327,7 +425,7 @@ namespace UI.CardSystem
|
|||||||
|
|
||||||
int spawnCount = Mathf.Min(uniquePending.Count, MAX_VISIBLE_CARDS);
|
int spawnCount = Mathf.Min(uniquePending.Count, MAX_VISIBLE_CARDS);
|
||||||
|
|
||||||
Debug.Log($"[AlbumViewPage] Spawning {spawnCount} unique pending cards (total pending: {pending.Count})");
|
Logging.Debug($"[AlbumViewPage] Spawning {spawnCount} unique pending cards (total pending: {pending.Count})");
|
||||||
|
|
||||||
for (int i = 0; i < spawnCount; i++)
|
for (int i = 0; i < spawnCount; i++)
|
||||||
{
|
{
|
||||||
@@ -343,14 +441,14 @@ namespace UI.CardSystem
|
|||||||
// Guard: Don't spawn cards with zero copies
|
// Guard: Don't spawn cards with zero copies
|
||||||
if (cardData.CopiesOwned <= 0)
|
if (cardData.CopiesOwned <= 0)
|
||||||
{
|
{
|
||||||
Debug.LogWarning($"[AlbumViewPage] Skipping spawn of card '{cardData.Name}' with {cardData.CopiesOwned} copies");
|
Logging.Warning($"[AlbumViewPage] Skipping spawn of card '{cardData.Name}' with {cardData.CopiesOwned} copies");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
DraggableSlot slot = FindSlotByIndex(slotIndex);
|
DraggableSlot slot = FindSlotByIndex(slotIndex);
|
||||||
if (slot == null)
|
if (slot == null)
|
||||||
{
|
{
|
||||||
Debug.LogWarning($"[AlbumViewPage] Could not find slot with SlotIndex {slotIndex}");
|
Logging.Warning($"[AlbumViewPage] Could not find slot with SlotIndex {slotIndex}");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -377,11 +475,11 @@ namespace UI.CardSystem
|
|||||||
// Track it
|
// Track it
|
||||||
_activeCards.Add(cardPlacement);
|
_activeCards.Add(cardPlacement);
|
||||||
|
|
||||||
Debug.Log($"[AlbumViewPage] Spawned card '{cardData.Name}' (CopiesOwned: {cardData.CopiesOwned}) in slot {slotIndex}");
|
Logging.Debug($"[AlbumViewPage] Spawned card '{cardData.Name}' (CopiesOwned: {cardData.CopiesOwned}) in slot {slotIndex}");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Debug.LogWarning($"[AlbumViewPage] Spawned card has no AlbumCardDraggable component!");
|
Logging.Warning($"[AlbumViewPage] Spawned card has no AlbumCardDraggable component!");
|
||||||
Destroy(cardObj);
|
Destroy(cardObj);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -395,7 +493,7 @@ namespace UI.CardSystem
|
|||||||
// Guard: Don't spawn cards with zero copies
|
// Guard: Don't spawn cards with zero copies
|
||||||
if (card.CopiesOwned <= 0)
|
if (card.CopiesOwned <= 0)
|
||||||
{
|
{
|
||||||
Debug.LogWarning($"[AlbumViewPage] Ignoring pending card '{card.Name}' with {card.CopiesOwned} copies");
|
Logging.Warning($"[AlbumViewPage] Ignoring pending card '{card.Name}' with {card.CopiesOwned} copies");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -406,7 +504,7 @@ namespace UI.CardSystem
|
|||||||
|
|
||||||
if (alreadySpawned)
|
if (alreadySpawned)
|
||||||
{
|
{
|
||||||
Debug.Log($"[AlbumViewPage] Card '{card.Name}' already spawned, skipping duplicate spawn");
|
Logging.Debug($"[AlbumViewPage] Card '{card.Name}' already spawned, skipping duplicate spawn");
|
||||||
return; // Don't spawn duplicates
|
return; // Don't spawn duplicates
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -423,13 +521,13 @@ namespace UI.CardSystem
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private void OnCardRevealed(AlbumCardPlacementDraggable cardPlacement, CardData cardData)
|
private void OnCardRevealed(AlbumCardPlacementDraggable cardPlacement, CardData cardData)
|
||||||
{
|
{
|
||||||
Debug.Log($"[AlbumViewPage] Card revealed: {cardData.Name} (Zone: {cardData.Zone}, CopiesOwned: {cardData.CopiesOwned})");
|
Logging.Debug($"[AlbumViewPage] Card revealed: {cardData.Name} (Zone: {cardData.Zone}, CopiesOwned: {cardData.CopiesOwned})");
|
||||||
|
|
||||||
// IMMEDIATELY move card from pending to inventory upon reveal
|
// IMMEDIATELY move card from pending to inventory upon reveal
|
||||||
if (CardSystemManager.Instance != null)
|
if (CardSystemManager.Instance != null)
|
||||||
{
|
{
|
||||||
CardSystemManager.Instance.MarkCardAsPlaced(cardData);
|
CardSystemManager.Instance.MarkCardAsPlaced(cardData);
|
||||||
Debug.Log($"[AlbumViewPage] Moved card '{cardData.Name}' from pending to inventory on reveal");
|
Logging.Debug($"[AlbumViewPage] Moved card '{cardData.Name}' from pending to inventory on reveal");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove this card from active cards list
|
// Remove this card from active cards list
|
||||||
@@ -441,12 +539,12 @@ namespace UI.CardSystem
|
|||||||
if (currentZone != cardData.Zone)
|
if (currentZone != cardData.Zone)
|
||||||
{
|
{
|
||||||
// Card is from a different zone - navigate to its zone
|
// Card is from a different zone - navigate to its zone
|
||||||
Debug.Log($"[AlbumViewPage] Card zone ({cardData.Zone}) doesn't match current zone ({currentZone}). Navigating to card's zone...");
|
Logging.Debug($"[AlbumViewPage] Card zone ({cardData.Zone}) doesn't match current zone ({currentZone}). Navigating to card's zone...");
|
||||||
NavigateToZone(cardData.Zone);
|
NavigateToZone(cardData.Zone);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Debug.Log($"[AlbumViewPage] Card zone ({cardData.Zone}) matches current zone - no navigation needed.");
|
Logging.Debug($"[AlbumViewPage] Card zone ({cardData.Zone}) matches current zone - no navigation needed.");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Shuffle remaining cards to front and spawn next unique card
|
// Shuffle remaining cards to front and spawn next unique card
|
||||||
@@ -461,7 +559,7 @@ namespace UI.CardSystem
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private void OnCardPlacedInAlbum(AlbumCardPlacementDraggable cardPlacement, CardData cardData)
|
private void OnCardPlacedInAlbum(AlbumCardPlacementDraggable cardPlacement, CardData cardData)
|
||||||
{
|
{
|
||||||
Debug.Log($"[AlbumViewPage] Card placed in album slot: {cardData.Name}");
|
Logging.Debug($"[AlbumViewPage] Card placed in album slot: {cardData.Name}");
|
||||||
|
|
||||||
// Unsubscribe from events (card is now static in album)
|
// Unsubscribe from events (card is now static in album)
|
||||||
cardPlacement.OnCardRevealed -= OnCardRevealed;
|
cardPlacement.OnCardRevealed -= OnCardRevealed;
|
||||||
@@ -545,7 +643,9 @@ namespace UI.CardSystem
|
|||||||
public CardZone GetCurrentZone()
|
public CardZone GetCurrentZone()
|
||||||
{
|
{
|
||||||
if (book == null || zoneTabs == null || zoneTabs.Length == 0)
|
if (book == null || zoneTabs == null || zoneTabs.Length == 0)
|
||||||
|
{
|
||||||
return CardZone.AppleHills; // Default
|
return CardZone.AppleHills; // Default
|
||||||
|
}
|
||||||
|
|
||||||
int currentPage = book.CurrentPaper;
|
int currentPage = book.CurrentPaper;
|
||||||
|
|
||||||
@@ -557,9 +657,8 @@ namespace UI.CardSystem
|
|||||||
return tab.Zone;
|
return tab.Zone;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fallback to first zone
|
// Fallback to first zone
|
||||||
return zoneTabs[0].Zone;
|
return CardZone.NotApplicable;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -567,16 +666,20 @@ namespace UI.CardSystem
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public BookTabButton GetTabForZone(CardZone zone)
|
public BookTabButton GetTabForZone(CardZone zone)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (zoneTabs == null)
|
if (zoneTabs == null)
|
||||||
|
{
|
||||||
return null;
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
foreach (var tab in zoneTabs)
|
foreach (var tab in zoneTabs)
|
||||||
{
|
{
|
||||||
if (tab.Zone == zone)
|
if (tab.Zone == zone)
|
||||||
{
|
{
|
||||||
return tab;
|
return tab;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -643,7 +746,7 @@ namespace UI.CardSystem
|
|||||||
{
|
{
|
||||||
if (card == null) return;
|
if (card == null) return;
|
||||||
|
|
||||||
Debug.Log($"[AlbumViewPage] OnCardEnlargeRequested called for card: {card.name}, current parent: {card.transform.parent.name}");
|
Logging.Debug($"[AlbumViewPage] OnCardEnlargeRequested called for card: {card.name}, current parent: {card.transform.parent.name}");
|
||||||
|
|
||||||
// IMPORTANT: Call EnlargeCard FIRST to store original parent (the slot)
|
// IMPORTANT: Call EnlargeCard FIRST to store original parent (the slot)
|
||||||
// BEFORE reparenting to the enlarged container
|
// BEFORE reparenting to the enlarged container
|
||||||
@@ -653,7 +756,7 @@ namespace UI.CardSystem
|
|||||||
if (cardEnlargedBackdrop != null)
|
if (cardEnlargedBackdrop != null)
|
||||||
{
|
{
|
||||||
cardEnlargedBackdrop.SetActive(true);
|
cardEnlargedBackdrop.SetActive(true);
|
||||||
Debug.Log($"[AlbumViewPage] Backdrop shown");
|
Logging.Debug($"[AlbumViewPage] Backdrop shown");
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOW reparent card to enlarged container (above backdrop)
|
// NOW reparent card to enlarged container (above backdrop)
|
||||||
@@ -661,10 +764,10 @@ namespace UI.CardSystem
|
|||||||
{
|
{
|
||||||
card.transform.SetParent(cardEnlargedContainer, true);
|
card.transform.SetParent(cardEnlargedContainer, true);
|
||||||
card.transform.SetAsLastSibling(); // Ensure on top
|
card.transform.SetAsLastSibling(); // Ensure on top
|
||||||
Debug.Log($"[AlbumViewPage] Card reparented to enlarged container");
|
Logging.Debug($"[AlbumViewPage] Card reparented to enlarged container");
|
||||||
}
|
}
|
||||||
|
|
||||||
Debug.Log($"[AlbumViewPage] Card enlarged: {card.GetCardData()?.Name}");
|
Logging.Debug($"[AlbumViewPage] Card enlarged: {card.GetCardData()?.Name}");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -692,7 +795,7 @@ namespace UI.CardSystem
|
|||||||
card.transform.localRotation = card.GetOriginalLocalRotation();
|
card.transform.localRotation = card.GetOriginalLocalRotation();
|
||||||
}
|
}
|
||||||
|
|
||||||
Debug.Log($"[AlbumViewPage] Card shrunk: {card.GetCardData()?.Name}");
|
Logging.Debug($"[AlbumViewPage] Card shrunk: {card.GetCardData()?.Name}");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -703,7 +806,7 @@ namespace UI.CardSystem
|
|||||||
if (previewCardTransform == null)
|
if (previewCardTransform == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Debug.Log($"[AlbumViewPage] ShowSlotPreview called for slot: {slot.name}");
|
Logging.Debug($"[AlbumViewPage] ShowSlotPreview called for slot: {slot.name}");
|
||||||
|
|
||||||
// Show backdrop
|
// Show backdrop
|
||||||
if (cardEnlargedBackdrop != null)
|
if (cardEnlargedBackdrop != null)
|
||||||
@@ -727,7 +830,7 @@ namespace UI.CardSystem
|
|||||||
if (previewCardTransform == null)
|
if (previewCardTransform == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Debug.Log($"[AlbumViewPage] HideSlotPreview called for slot: {slot.name}");
|
Logging.Debug($"[AlbumViewPage] HideSlotPreview called for slot: {slot.name}");
|
||||||
|
|
||||||
// Hide backdrop
|
// Hide backdrop
|
||||||
if (cardEnlargedBackdrop != null)
|
if (cardEnlargedBackdrop != null)
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using AppleHills.Data.CardSystem;
|
using AppleHills.Data.CardSystem;
|
||||||
using BookCurlPro;
|
using BookCurlPro;
|
||||||
|
using Core;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityEngine.UI;
|
using UnityEngine.UI;
|
||||||
using Tween = Pixelplacement.Tween;
|
using Tween = Pixelplacement.Tween;
|
||||||
@@ -69,7 +70,7 @@ namespace UI.CardSystem
|
|||||||
{
|
{
|
||||||
if (book == null)
|
if (book == null)
|
||||||
{
|
{
|
||||||
Debug.LogWarning($"[BookTabButton] No BookPro reference assigned on {gameObject.name}");
|
Logging.Warning($"[BookTabButton] No BookPro reference assigned on {gameObject.name}");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -40,10 +40,8 @@ namespace UI.CardSystem
|
|||||||
|
|
||||||
private TweenBase _activeTween;
|
private TweenBase _activeTween;
|
||||||
|
|
||||||
protected override void OnManagedAwake()
|
internal override void OnManagedStart()
|
||||||
{
|
{
|
||||||
base.OnManagedAwake();
|
|
||||||
|
|
||||||
// Store original scale for pulse animation
|
// Store original scale for pulse animation
|
||||||
if (dotBackground != null)
|
if (dotBackground != null)
|
||||||
{
|
{
|
||||||
@@ -72,16 +70,13 @@ namespace UI.CardSystem
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnDestroy()
|
internal override void OnManagedDestroy()
|
||||||
{
|
{
|
||||||
// Unsubscribe from CardSystemManager events to prevent memory leaks
|
// Unsubscribe from CardSystemManager events to prevent memory leaks
|
||||||
if (CardSystemManager.Instance != null)
|
if (CardSystemManager.Instance != null)
|
||||||
{
|
{
|
||||||
CardSystemManager.Instance.OnBoosterCountChanged -= OnBoosterCountChanged;
|
CardSystemManager.Instance.OnBoosterCountChanged -= OnBoosterCountChanged;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Call base implementation
|
|
||||||
base.OnDestroy();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using AppleHills.Data.CardSystem;
|
using AppleHills.Data.CardSystem;
|
||||||
|
using Core;
|
||||||
using Data.CardSystem;
|
using Data.CardSystem;
|
||||||
using Pixelplacement;
|
using Pixelplacement;
|
||||||
using UI.Core;
|
using UI.Core;
|
||||||
@@ -33,7 +34,6 @@ namespace UI.CardSystem
|
|||||||
[SerializeField] private float cardSpacing = 150f;
|
[SerializeField] private float cardSpacing = 150f;
|
||||||
|
|
||||||
[Header("Settings")]
|
[Header("Settings")]
|
||||||
[SerializeField] private float cardRevealDelay = 0.5f;
|
|
||||||
[SerializeField] private float boosterDisappearDuration = 0.5f;
|
[SerializeField] private float boosterDisappearDuration = 0.5f;
|
||||||
[SerializeField] private CinemachineImpulseSource impulseSource;
|
[SerializeField] private CinemachineImpulseSource impulseSource;
|
||||||
[SerializeField] private ParticleSystem openingParticleSystem;
|
[SerializeField] private ParticleSystem openingParticleSystem;
|
||||||
@@ -68,7 +68,7 @@ namespace UI.CardSystem
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Debug.LogWarning("[BoosterOpeningPage] albumIcon does not have a Button component!");
|
Logging.Warning("[BoosterOpeningPage] albumIcon does not have a Button component!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -76,7 +76,7 @@ namespace UI.CardSystem
|
|||||||
gameObject.SetActive(false);
|
gameObject.SetActive(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnDestroy()
|
internal override void OnManagedDestroy()
|
||||||
{
|
{
|
||||||
// Unsubscribe from dismiss button
|
// Unsubscribe from dismiss button
|
||||||
if (_dismissButton != null)
|
if (_dismissButton != null)
|
||||||
@@ -111,13 +111,20 @@ namespace UI.CardSystem
|
|||||||
if (UIPageController.Instance != null)
|
if (UIPageController.Instance != null)
|
||||||
{
|
{
|
||||||
UIPageController.Instance.PopPage();
|
UIPageController.Instance.PopPage();
|
||||||
Debug.Log("[BoosterOpeningPage] Dismiss button clicked, popping page from stack");
|
Logging.Debug("[BoosterOpeningPage] Dismiss button clicked, popping page from stack");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void TransitionIn()
|
public override void TransitionIn()
|
||||||
{
|
{
|
||||||
base.TransitionIn();
|
base.TransitionIn();
|
||||||
|
|
||||||
|
// Ensure album icon is visible when page opens
|
||||||
|
if (albumIcon != null)
|
||||||
|
{
|
||||||
|
albumIcon.SetActive(true);
|
||||||
|
}
|
||||||
|
|
||||||
InitializeBoosterDisplay();
|
InitializeBoosterDisplay();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -132,17 +139,17 @@ namespace UI.CardSystem
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private void InitializeBoosterDisplay()
|
private void InitializeBoosterDisplay()
|
||||||
{
|
{
|
||||||
Debug.Log($"[BoosterOpeningPage] InitializeBoosterDisplay called with {_availableBoosterCount} boosters available");
|
Logging.Debug($"[BoosterOpeningPage] InitializeBoosterDisplay called with {_availableBoosterCount} boosters available");
|
||||||
|
|
||||||
if (boosterPackPrefab == null)
|
if (boosterPackPrefab == null)
|
||||||
{
|
{
|
||||||
Debug.LogWarning("BoosterOpeningPage: No booster pack prefab assigned!");
|
Logging.Warning("BoosterOpeningPage: No booster pack prefab assigned!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bottomRightSlots == null || bottomRightSlots.SlotCount == 0)
|
if (bottomRightSlots == null || bottomRightSlots.SlotCount == 0)
|
||||||
{
|
{
|
||||||
Debug.LogWarning("BoosterOpeningPage: No slots available!");
|
Logging.Warning("BoosterOpeningPage: No slots available!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -152,7 +159,7 @@ namespace UI.CardSystem
|
|||||||
// Calculate how many boosters to show (max 3, or available count, whichever is lower)
|
// Calculate how many boosters to show (max 3, or available count, whichever is lower)
|
||||||
int visibleCount = Mathf.Min(_availableBoosterCount, MAX_VISIBLE_BOOSTERS);
|
int visibleCount = Mathf.Min(_availableBoosterCount, MAX_VISIBLE_BOOSTERS);
|
||||||
|
|
||||||
Debug.Log($"[BoosterOpeningPage] Will spawn {visibleCount} boosters");
|
Logging.Debug($"[BoosterOpeningPage] Will spawn {visibleCount} boosters");
|
||||||
|
|
||||||
// Spawn boosters and assign to slots
|
// Spawn boosters and assign to slots
|
||||||
for (int i = 0; i < visibleCount; i++)
|
for (int i = 0; i < visibleCount; i++)
|
||||||
@@ -165,11 +172,11 @@ namespace UI.CardSystem
|
|||||||
{
|
{
|
||||||
centerOpeningSlot.OnOccupied += OnBoosterPlacedInCenter;
|
centerOpeningSlot.OnOccupied += OnBoosterPlacedInCenter;
|
||||||
centerOpeningSlot.OnVacated += OnBoosterRemovedFromCenter;
|
centerOpeningSlot.OnVacated += OnBoosterRemovedFromCenter;
|
||||||
Debug.Log($"[BoosterOpeningPage] Subscribed to center slot events");
|
Logging.Debug($"[BoosterOpeningPage] Subscribed to center slot events");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Debug.LogWarning("[BoosterOpeningPage] centerOpeningSlot is null!");
|
Logging.Warning("[BoosterOpeningPage] centerOpeningSlot is null!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -181,7 +188,7 @@ namespace UI.CardSystem
|
|||||||
DraggableSlot slot = FindSlotByIndex(slotIndex);
|
DraggableSlot slot = FindSlotByIndex(slotIndex);
|
||||||
if (slot == null)
|
if (slot == null)
|
||||||
{
|
{
|
||||||
Debug.LogWarning($"[BoosterOpeningPage] Could not find slot with SlotIndex {slotIndex}!");
|
Logging.Warning($"[BoosterOpeningPage] Could not find slot with SlotIndex {slotIndex}!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -204,11 +211,11 @@ namespace UI.CardSystem
|
|||||||
// Track it
|
// Track it
|
||||||
_activeBoostersInSlots.Add(booster);
|
_activeBoostersInSlots.Add(booster);
|
||||||
|
|
||||||
Debug.Log($"[BoosterOpeningPage] Spawned booster in slot with SlotIndex {slotIndex}");
|
Logging.Debug($"[BoosterOpeningPage] Spawned booster in slot with SlotIndex {slotIndex}");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Debug.LogWarning($"[BoosterOpeningPage] Spawned booster has no BoosterPackDraggable component!");
|
Logging.Warning($"[BoosterOpeningPage] Spawned booster has no BoosterPackDraggable component!");
|
||||||
Destroy(boosterObj);
|
Destroy(boosterObj);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -244,7 +251,7 @@ namespace UI.CardSystem
|
|||||||
booster.CurrentSlot.Vacate();
|
booster.CurrentSlot.Vacate();
|
||||||
}
|
}
|
||||||
|
|
||||||
Debug.Log($"[BoosterOpeningPage] Removed booster from slot {slotIndex}");
|
Logging.Debug($"[BoosterOpeningPage] Removed booster from slot {slotIndex}");
|
||||||
}
|
}
|
||||||
|
|
||||||
_activeBoostersInSlots.RemoveAt(slotIndex);
|
_activeBoostersInSlots.RemoveAt(slotIndex);
|
||||||
@@ -264,7 +271,7 @@ namespace UI.CardSystem
|
|||||||
RemoveBoosterFromSlot(lastIndex);
|
RemoveBoosterFromSlot(lastIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
Debug.Log($"[BoosterOpeningPage] Updated visible boosters: {_activeBoostersInSlots.Count}/{targetCount}");
|
Logging.Debug($"[BoosterOpeningPage] Updated visible boosters: {_activeBoostersInSlots.Count}/{targetCount}");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -274,7 +281,7 @@ namespace UI.CardSystem
|
|||||||
{
|
{
|
||||||
if (_activeBoostersInSlots.Count == 0) return;
|
if (_activeBoostersInSlots.Count == 0) return;
|
||||||
|
|
||||||
Debug.Log($"[BoosterOpeningPage] Shuffling {_activeBoostersInSlots.Count} boosters to front slots");
|
Logging.Debug($"[BoosterOpeningPage] Shuffling {_activeBoostersInSlots.Count} boosters to front slots");
|
||||||
|
|
||||||
// Unassign all boosters from their current slots
|
// Unassign all boosters from their current slots
|
||||||
foreach (var booster in _activeBoostersInSlots)
|
foreach (var booster in _activeBoostersInSlots)
|
||||||
@@ -294,12 +301,12 @@ namespace UI.CardSystem
|
|||||||
|
|
||||||
if (targetSlot != null)
|
if (targetSlot != null)
|
||||||
{
|
{
|
||||||
Debug.Log($"[BoosterOpeningPage] Assigning booster to slot with SlotIndex {i} {targetSlot.name}");
|
Logging.Debug($"[BoosterOpeningPage] Assigning booster to slot with SlotIndex {i} {targetSlot.name}");
|
||||||
booster.AssignToSlot(targetSlot, true); // Animate the move
|
booster.AssignToSlot(targetSlot, true); // Animate the move
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Debug.LogWarning($"[BoosterOpeningPage] Could not find slot with SlotIndex {i} {targetSlot.name}");
|
Logging.Warning($"[BoosterOpeningPage] Could not find slot with SlotIndex {i} {targetSlot.name}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -344,7 +351,7 @@ namespace UI.CardSystem
|
|||||||
if (slot != null && !slot.IsOccupied)
|
if (slot != null && !slot.IsOccupied)
|
||||||
{
|
{
|
||||||
SpawnBoosterInSlot(i);
|
SpawnBoosterInSlot(i);
|
||||||
Debug.Log($"[BoosterOpeningPage] Spawned new booster in slot with SlotIndex {i}");
|
Logging.Debug($"[BoosterOpeningPage] Spawned new booster in slot with SlotIndex {i}");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -363,13 +370,20 @@ namespace UI.CardSystem
|
|||||||
// Remove from active slots list
|
// Remove from active slots list
|
||||||
_activeBoostersInSlots.Remove(booster);
|
_activeBoostersInSlots.Remove(booster);
|
||||||
|
|
||||||
|
// Hide album icon when booster is placed in center
|
||||||
|
if (albumIcon != null)
|
||||||
|
{
|
||||||
|
albumIcon.SetActive(false);
|
||||||
|
Logging.Debug($"[BoosterOpeningPage] Album icon hidden");
|
||||||
|
}
|
||||||
|
|
||||||
// Lock the slot so it can't be dragged out
|
// Lock the slot so it can't be dragged out
|
||||||
Debug.Log($"[BoosterOpeningPage] Locking center slot. IsLocked before: {centerOpeningSlot.IsLocked}");
|
Logging.Debug($"[BoosterOpeningPage] Locking center slot. IsLocked before: {centerOpeningSlot.IsLocked}");
|
||||||
centerOpeningSlot.SetLocked(true);
|
centerOpeningSlot.SetLocked(true);
|
||||||
Debug.Log($"[BoosterOpeningPage] IsLocked after: {centerOpeningSlot.IsLocked}");
|
Logging.Debug($"[BoosterOpeningPage] IsLocked after: {centerOpeningSlot.IsLocked}");
|
||||||
|
|
||||||
// Configure booster for opening (disables drag, enables tapping, resets tap count)
|
// Configure booster for opening (disables drag, enables tapping, resets tap count)
|
||||||
Debug.Log($"[BoosterOpeningPage] Calling SetInOpeningSlot(true) on booster");
|
Logging.Debug($"[BoosterOpeningPage] Calling SetInOpeningSlot(true) on booster");
|
||||||
booster.SetInOpeningSlot(true);
|
booster.SetInOpeningSlot(true);
|
||||||
|
|
||||||
// Subscribe to tap events for visual feedback
|
// Subscribe to tap events for visual feedback
|
||||||
@@ -384,7 +398,7 @@ namespace UI.CardSystem
|
|||||||
// Shuffle remaining boosters to occupy the first slots
|
// Shuffle remaining boosters to occupy the first slots
|
||||||
ShuffleBoostersToFront();
|
ShuffleBoostersToFront();
|
||||||
|
|
||||||
Debug.Log($"[BoosterOpeningPage] Booster placed in center, ready for taps. Active boosters in slots: {_activeBoostersInSlots.Count}");
|
Logging.Debug($"[BoosterOpeningPage] Booster placed in center, ready for taps. Active boosters in slots: {_activeBoostersInSlots.Count}");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -403,12 +417,12 @@ namespace UI.CardSystem
|
|||||||
}
|
}
|
||||||
|
|
||||||
_currentBoosterInCenter = null;
|
_currentBoosterInCenter = null;
|
||||||
Debug.Log($"[BoosterOpeningPage] Booster removed from center");
|
Logging.Debug($"[BoosterOpeningPage] Booster removed from center");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnBoosterTapped(BoosterPackDraggable booster, int currentTaps, int maxTaps)
|
private void OnBoosterTapped(BoosterPackDraggable booster, int currentTaps, int maxTaps)
|
||||||
{
|
{
|
||||||
Debug.Log($"[BoosterOpeningPage] Booster tapped: {currentTaps}/{maxTaps}");
|
Logging.Debug($"[BoosterOpeningPage] Booster tapped: {currentTaps}/{maxTaps}");
|
||||||
|
|
||||||
// Fire Cinemachine impulse with random velocity (excluding Z)
|
// Fire Cinemachine impulse with random velocity (excluding Z)
|
||||||
if (impulseSource != null)
|
if (impulseSource != null)
|
||||||
@@ -433,7 +447,7 @@ namespace UI.CardSystem
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private void OnBoosterOpened(BoosterPackDraggable booster)
|
private void OnBoosterOpened(BoosterPackDraggable booster)
|
||||||
{
|
{
|
||||||
Debug.Log($"[BoosterOpeningPage] Booster opened, playing particle effect");
|
Logging.Debug($"[BoosterOpeningPage] Booster opened, playing particle effect");
|
||||||
|
|
||||||
// Reset and play particle system
|
// Reset and play particle system
|
||||||
if (openingParticleSystem != null)
|
if (openingParticleSystem != null)
|
||||||
@@ -471,7 +485,7 @@ namespace UI.CardSystem
|
|||||||
{
|
{
|
||||||
if (_isProcessingOpening) return;
|
if (_isProcessingOpening) return;
|
||||||
|
|
||||||
Debug.Log($"[BoosterOpeningPage] Booster ready to open!");
|
Logging.Debug($"[BoosterOpeningPage] Booster ready to open!");
|
||||||
|
|
||||||
// Trigger the actual opening sequence
|
// Trigger the actual opening sequence
|
||||||
booster.TriggerOpen();
|
booster.TriggerOpen();
|
||||||
@@ -514,7 +528,7 @@ namespace UI.CardSystem
|
|||||||
// WaitForCardReveals already includes: 0.5s wait + (cardCount * 0.5s stagger) + 0.5s animation + 0.5s final
|
// WaitForCardReveals already includes: 0.5s wait + (cardCount * 0.5s stagger) + 0.5s animation + 0.5s final
|
||||||
// Total is: 1.5s + (cardCount * 0.5s)
|
// Total is: 1.5s + (cardCount * 0.5s)
|
||||||
// For 5 cards that's 4 seconds total, which should be enough
|
// For 5 cards that's 4 seconds total, which should be enough
|
||||||
Debug.Log("[BoosterOpeningPage] Last booster opened, auto-transitioning to album main page");
|
Logging.Debug("[BoosterOpeningPage] Last booster opened, auto-transitioning to album main page");
|
||||||
if (UIPageController.Instance != null)
|
if (UIPageController.Instance != null)
|
||||||
{
|
{
|
||||||
UIPageController.Instance.PopPage();
|
UIPageController.Instance.PopPage();
|
||||||
@@ -561,7 +575,7 @@ namespace UI.CardSystem
|
|||||||
{
|
{
|
||||||
if (flippableCardPrefab == null || cardDisplayContainer == null)
|
if (flippableCardPrefab == null || cardDisplayContainer == null)
|
||||||
{
|
{
|
||||||
Debug.LogWarning("BoosterOpeningPage: Missing card prefab or container!");
|
Logging.Warning("BoosterOpeningPage: Missing card prefab or container!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -605,7 +619,7 @@ namespace UI.CardSystem
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Debug.LogWarning($"[BoosterOpeningPage] FlippableCard component not found on card {i}!");
|
Logging.Warning($"[BoosterOpeningPage] FlippableCard component not found on card {i}!");
|
||||||
}
|
}
|
||||||
|
|
||||||
_currentRevealedCards.Add(cardObj);
|
_currentRevealedCards.Add(cardObj);
|
||||||
@@ -621,7 +635,7 @@ namespace UI.CardSystem
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private void OnCardFlipStarted(FlippableCard flippingCard)
|
private void OnCardFlipStarted(FlippableCard flippingCard)
|
||||||
{
|
{
|
||||||
Debug.Log($"[BoosterOpeningPage] Card flip started, disabling all other cards.");
|
Logging.Debug($"[BoosterOpeningPage] Card flip started, disabling all other cards.");
|
||||||
|
|
||||||
// Disable ALL cards immediately to prevent multi-flip
|
// Disable ALL cards immediately to prevent multi-flip
|
||||||
foreach (GameObject cardObj in _currentRevealedCards)
|
foreach (GameObject cardObj in _currentRevealedCards)
|
||||||
@@ -639,14 +653,14 @@ namespace UI.CardSystem
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private void OnCardRevealed(int cardIndex)
|
private void OnCardRevealed(int cardIndex)
|
||||||
{
|
{
|
||||||
Debug.Log($"[BoosterOpeningPage] Card {cardIndex} revealed!");
|
Logging.Debug($"[BoosterOpeningPage] Card {cardIndex} revealed!");
|
||||||
_revealedCardCount++;
|
_revealedCardCount++;
|
||||||
|
|
||||||
// Get the flippable card and card data
|
// Get the flippable card and card data
|
||||||
FlippableCard flippableCard = _currentRevealedCards[cardIndex].GetComponent<FlippableCard>();
|
FlippableCard flippableCard = _currentRevealedCards[cardIndex].GetComponent<FlippableCard>();
|
||||||
if (flippableCard == null)
|
if (flippableCard == null)
|
||||||
{
|
{
|
||||||
Debug.LogWarning($"[BoosterOpeningPage] FlippableCard not found for card {cardIndex}!");
|
Logging.Warning($"[BoosterOpeningPage] FlippableCard not found for card {cardIndex}!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -657,7 +671,7 @@ namespace UI.CardSystem
|
|||||||
|
|
||||||
if (isNew)
|
if (isNew)
|
||||||
{
|
{
|
||||||
Debug.Log($"[BoosterOpeningPage] Card '{cardData.Name}' is NEW!");
|
Logging.Debug($"[BoosterOpeningPage] Card '{cardData.Name}' is NEW!");
|
||||||
flippableCard.ShowAsNew();
|
flippableCard.ShowAsNew();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -665,7 +679,7 @@ namespace UI.CardSystem
|
|||||||
// Check if card is already Legendary - if so, skip progress bar and auto-progress
|
// Check if card is already Legendary - if so, skip progress bar and auto-progress
|
||||||
if (existingCard.Rarity == AppleHills.Data.CardSystem.CardRarity.Legendary)
|
if (existingCard.Rarity == AppleHills.Data.CardSystem.CardRarity.Legendary)
|
||||||
{
|
{
|
||||||
Debug.Log($"[BoosterOpeningPage] Card '{cardData.Name}' is LEGENDARY - auto-progressing!");
|
Logging.Debug($"[BoosterOpeningPage] Card '{cardData.Name}' is LEGENDARY - auto-progressing!");
|
||||||
// Add to inventory immediately and move to next card
|
// Add to inventory immediately and move to next card
|
||||||
Data.CardSystem.CardSystemManager.Instance.AddCardToInventoryDelayed(cardData);
|
Data.CardSystem.CardSystemManager.Instance.AddCardToInventoryDelayed(cardData);
|
||||||
_cardsCompletedInteraction++;
|
_cardsCompletedInteraction++;
|
||||||
@@ -675,14 +689,14 @@ namespace UI.CardSystem
|
|||||||
}
|
}
|
||||||
|
|
||||||
int ownedCount = existingCard.CopiesOwned;
|
int ownedCount = existingCard.CopiesOwned;
|
||||||
Debug.Log($"[BoosterOpeningPage] Card '{cardData.Name}' is a REPEAT! Owned: {ownedCount}");
|
Logging.Debug($"[BoosterOpeningPage] Card '{cardData.Name}' is a REPEAT! Owned: {ownedCount}");
|
||||||
|
|
||||||
// Check if this card will trigger an upgrade (ownedCount + 1 >= threshold)
|
// Check if this card will trigger an upgrade (ownedCount + 1 >= threshold)
|
||||||
bool willUpgrade = (ownedCount + 1) >= flippableCard.CardsToUpgrade && existingCard.Rarity < AppleHills.Data.CardSystem.CardRarity.Legendary;
|
bool willUpgrade = (ownedCount + 1) >= flippableCard.CardsToUpgrade && existingCard.Rarity < AppleHills.Data.CardSystem.CardRarity.Legendary;
|
||||||
|
|
||||||
if (willUpgrade)
|
if (willUpgrade)
|
||||||
{
|
{
|
||||||
Debug.Log($"[BoosterOpeningPage] This card will trigger upgrade! ({ownedCount + 1}/{flippableCard.CardsToUpgrade})");
|
Logging.Debug($"[BoosterOpeningPage] This card will trigger upgrade! ({ownedCount + 1}/{flippableCard.CardsToUpgrade})");
|
||||||
// Show as repeat - progress bar will fill and auto-trigger upgrade
|
// Show as repeat - progress bar will fill and auto-trigger upgrade
|
||||||
flippableCard.ShowAsRepeatWithUpgrade(ownedCount, existingCard);
|
flippableCard.ShowAsRepeatWithUpgrade(ownedCount, existingCard);
|
||||||
}
|
}
|
||||||
@@ -705,7 +719,7 @@ namespace UI.CardSystem
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private void OnCardCompletedInteraction(FlippableCard card, int cardIndex)
|
private void OnCardCompletedInteraction(FlippableCard card, int cardIndex)
|
||||||
{
|
{
|
||||||
Debug.Log($"[BoosterOpeningPage] Card {cardIndex} interaction complete!");
|
Logging.Debug($"[BoosterOpeningPage] Card {cardIndex} interaction complete!");
|
||||||
|
|
||||||
// Add card to inventory NOW (after player saw it)
|
// Add card to inventory NOW (after player saw it)
|
||||||
Data.CardSystem.CardSystemManager.Instance.AddCardToInventoryDelayed(card.CardData);
|
Data.CardSystem.CardSystemManager.Instance.AddCardToInventoryDelayed(card.CardData);
|
||||||
@@ -722,7 +736,7 @@ namespace UI.CardSystem
|
|||||||
// Re-enable all unrevealed cards (they can be flipped now)
|
// Re-enable all unrevealed cards (they can be flipped now)
|
||||||
EnableUnrevealedCards();
|
EnableUnrevealedCards();
|
||||||
|
|
||||||
Debug.Log($"[BoosterOpeningPage] Cards completed interaction: {_cardsCompletedInteraction}/{_currentCardData.Length}");
|
Logging.Debug($"[BoosterOpeningPage] Cards completed interaction: {_cardsCompletedInteraction}/{_currentCardData.Length}");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -743,7 +757,7 @@ namespace UI.CardSystem
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Debug.Log($"[BoosterOpeningPage] Set active card. Only one card is now clickable.");
|
Logging.Debug($"[BoosterOpeningPage] Set active card. Only one card is now clickable.");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -760,7 +774,7 @@ namespace UI.CardSystem
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Debug.Log($"[BoosterOpeningPage] Re-enabled unrevealed cards for flipping.");
|
Logging.Debug($"[BoosterOpeningPage] Re-enabled unrevealed cards for flipping.");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -768,7 +782,7 @@ namespace UI.CardSystem
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private void OnCardClickedWhileInactive(FlippableCard inactiveCard)
|
private void OnCardClickedWhileInactive(FlippableCard inactiveCard)
|
||||||
{
|
{
|
||||||
Debug.Log($"[BoosterOpeningPage] Inactive card clicked, jiggling active card.");
|
Logging.Debug($"[BoosterOpeningPage] Inactive card clicked, jiggling active card.");
|
||||||
|
|
||||||
if (_currentActiveCard != null)
|
if (_currentActiveCard != null)
|
||||||
{
|
{
|
||||||
@@ -787,7 +801,7 @@ namespace UI.CardSystem
|
|||||||
yield return null;
|
yield return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
Debug.Log($"[BoosterOpeningPage] All cards revealed! Waiting for interactions...");
|
Logging.Debug($"[BoosterOpeningPage] All cards revealed! Waiting for interactions...");
|
||||||
|
|
||||||
// Wait until all cards have completed their new/repeat interaction
|
// Wait until all cards have completed their new/repeat interaction
|
||||||
while (_cardsCompletedInteraction < _currentCardData.Length)
|
while (_cardsCompletedInteraction < _currentCardData.Length)
|
||||||
@@ -795,11 +809,18 @@ namespace UI.CardSystem
|
|||||||
yield return null;
|
yield return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
Debug.Log($"[BoosterOpeningPage] All interactions complete! Animating cards to album...");
|
Logging.Debug($"[BoosterOpeningPage] All interactions complete! Animating cards to album...");
|
||||||
|
|
||||||
// All cards revealed and interacted with, wait a moment
|
// All cards revealed and interacted with, wait a moment
|
||||||
yield return new WaitForSeconds(0.5f);
|
yield return new WaitForSeconds(0.5f);
|
||||||
|
|
||||||
|
// Show album icon before cards start tweening to it
|
||||||
|
if (albumIcon != null)
|
||||||
|
{
|
||||||
|
albumIcon.SetActive(true);
|
||||||
|
Logging.Debug($"[BoosterOpeningPage] Album icon shown for card tween target");
|
||||||
|
}
|
||||||
|
|
||||||
// Animate cards to album icon (or center if no icon assigned) with staggered delays
|
// Animate cards to album icon (or center if no icon assigned) with staggered delays
|
||||||
Vector3 targetPosition = albumIcon != null ? albumIcon.transform.position : Vector3.zero;
|
Vector3 targetPosition = albumIcon != null ? albumIcon.transform.position : Vector3.zero;
|
||||||
|
|
||||||
@@ -828,6 +849,8 @@ namespace UI.CardSystem
|
|||||||
_currentRevealedCards.Clear();
|
_currentRevealedCards.Clear();
|
||||||
|
|
||||||
yield return new WaitForSeconds(totalAnimationTime);
|
yield return new WaitForSeconds(totalAnimationTime);
|
||||||
|
|
||||||
|
// Album icon stays visible for next booster (will be hidden when next booster is placed)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using System.Collections;
|
using System.Collections;
|
||||||
|
using Core;
|
||||||
using Data.CardSystem;
|
using Data.CardSystem;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityEngine.Events;
|
using UnityEngine.Events;
|
||||||
@@ -58,7 +59,7 @@ namespace UI.CardSystem
|
|||||||
{
|
{
|
||||||
if (Instance != null && Instance != this)
|
if (Instance != null && Instance != this)
|
||||||
{
|
{
|
||||||
Debug.LogWarning("[BoosterPackGiver] Duplicate instance detected. Destroying this component.");
|
Logging.Warning("[BoosterPackGiver] Duplicate instance detected. Destroying this component.");
|
||||||
Destroy(this);
|
Destroy(this);
|
||||||
yield break;
|
yield break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using UI.Core;
|
using Core;
|
||||||
|
using UI.Core;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityEngine.UI;
|
using UnityEngine.UI;
|
||||||
|
|
||||||
@@ -46,7 +47,7 @@ namespace UI.CardSystem
|
|||||||
openAlbumButton.onClick.RemoveListener(OnOpenAlbumClicked);
|
openAlbumButton.onClick.RemoveListener(OnOpenAlbumClicked);
|
||||||
}
|
}
|
||||||
|
|
||||||
Debug.Log("ALBUM: CardAlbumDestroyed");
|
Logging.Debug("ALBUM: CardAlbumDestroyed");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnOpenAlbumClicked()
|
private void OnOpenAlbumClicked()
|
||||||
|
|||||||
@@ -335,7 +335,7 @@ namespace UI.CardSystem
|
|||||||
{
|
{
|
||||||
if (editorCardDefinition == null)
|
if (editorCardDefinition == null)
|
||||||
{
|
{
|
||||||
UnityEngine.Debug.LogWarning("[CardDisplay] No Card Definition assigned in Editor Tools.");
|
Debug.LogWarning("[CardDisplay] No Card Definition assigned in Editor Tools.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
using AppleHills.Data.CardSystem;
|
using AppleHills.Data.CardSystem;
|
||||||
|
using Core;
|
||||||
using Data.CardSystem;
|
using Data.CardSystem;
|
||||||
using Pixelplacement;
|
using Pixelplacement;
|
||||||
using UI.DragAndDrop.Core;
|
using UI.DragAndDrop.Core;
|
||||||
@@ -63,15 +64,15 @@ namespace UI.CardSystem
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public void RevealCard()
|
public void RevealCard()
|
||||||
{
|
{
|
||||||
if (_isRevealed) return;
|
if (_isRevealed)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
_isRevealed = true;
|
_isRevealed = true;
|
||||||
|
|
||||||
if (flippableCard != null)
|
if (flippableCard != null)
|
||||||
{
|
{
|
||||||
flippableCard.FlipToReveal();
|
flippableCard.FlipToReveal();
|
||||||
}
|
}
|
||||||
|
|
||||||
OnCardRevealed?.Invoke(this, _cardData);
|
OnCardRevealed?.Invoke(this, _cardData);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -82,7 +83,7 @@ namespace UI.CardSystem
|
|||||||
{
|
{
|
||||||
if (_cardData == null)
|
if (_cardData == null)
|
||||||
{
|
{
|
||||||
Debug.LogWarning("[AlbumCardPlacementDraggable] Cannot snap to slot - no card data assigned.");
|
Logging.Warning("[AlbumCardPlacementDraggable] Cannot snap to slot - no card data assigned.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -117,7 +118,7 @@ namespace UI.CardSystem
|
|||||||
TweenExtractedCardToSlot(extractedCard, () =>
|
TweenExtractedCardToSlot(extractedCard, () =>
|
||||||
{
|
{
|
||||||
// After animation completes
|
// After animation completes
|
||||||
Debug.Log($"[AlbumCardPlacementDraggable] Card placement animation complete for {_cardData.Name}");
|
Logging.Debug($"[AlbumCardPlacementDraggable] Card placement animation complete for {_cardData.Name}");
|
||||||
|
|
||||||
// Notify that card was placed
|
// Notify that card was placed
|
||||||
OnCardPlacedInAlbum?.Invoke(this, _cardData);
|
OnCardPlacedInAlbum?.Invoke(this, _cardData);
|
||||||
@@ -128,13 +129,13 @@ namespace UI.CardSystem
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Debug.LogWarning("[AlbumCardPlacementDraggable] Failed to extract AlbumCard from wrapper!");
|
Logging.Warning("[AlbumCardPlacementDraggable] Failed to extract AlbumCard from wrapper!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Debug.LogWarning($"[AlbumCardPlacementDraggable] Could not find matching slot for card '{_cardData.Name}' (Zone: {_cardData.Zone}, Index: {_cardData.CollectionIndex})");
|
Logging.Warning($"[AlbumCardPlacementDraggable] Could not find matching slot for card '{_cardData.Name}' (Zone: {_cardData.Zone}, Index: {_cardData.CollectionIndex})");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -162,7 +163,7 @@ namespace UI.CardSystem
|
|||||||
Tween.LocalRotation(cardTransform, Quaternion.identity, snapDuration, 0f, Tween.EaseOutBack,
|
Tween.LocalRotation(cardTransform, Quaternion.identity, snapDuration, 0f, Tween.EaseOutBack,
|
||||||
completeCallback: () =>
|
completeCallback: () =>
|
||||||
{
|
{
|
||||||
Debug.Log($"[AlbumCardPlacementDraggable] Tween complete for extracted card {card.name}, final height: {cardRect.sizeDelta.y}");
|
Logging.Debug($"[AlbumCardPlacementDraggable] Tween complete for extracted card {card.name}, final height: {cardRect.sizeDelta.y}");
|
||||||
onComplete?.Invoke();
|
onComplete?.Invoke();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -191,9 +192,6 @@ namespace UI.CardSystem
|
|||||||
protected override void OnPointerUpHook(bool longPress)
|
protected override void OnPointerUpHook(bool longPress)
|
||||||
{
|
{
|
||||||
base.OnPointerUpHook(longPress);
|
base.OnPointerUpHook(longPress);
|
||||||
|
|
||||||
Debug.Log($"[CLICK-TRACE-PLACEMENT] OnPointerUpHook on {name}, _wasDragged={_wasDragged}, _isRevealed={_isRevealed}, _waitingForPlacementTap={_waitingForPlacementTap}, longPress={longPress}");
|
|
||||||
|
|
||||||
_isHolding = false;
|
_isHolding = false;
|
||||||
|
|
||||||
// Cancel hold timer if running
|
// Cancel hold timer if running
|
||||||
@@ -202,40 +200,35 @@ namespace UI.CardSystem
|
|||||||
StopCoroutine(_holdRevealCoroutine);
|
StopCoroutine(_holdRevealCoroutine);
|
||||||
_holdRevealCoroutine = null;
|
_holdRevealCoroutine = null;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
// Handle tap (not dragged)
|
// Handle tap (not dragged)
|
||||||
if (!_wasDragged)
|
if (!_wasDragged)
|
||||||
{
|
{
|
||||||
if (!_isRevealed)
|
if (!_isRevealed)
|
||||||
{
|
{
|
||||||
Debug.Log($"[CLICK-TRACE-PLACEMENT] {name} - First tap, revealing card");
|
|
||||||
// First tap: reveal the card
|
// First tap: reveal the card
|
||||||
RevealCard();
|
RevealCard();
|
||||||
_waitingForPlacementTap = true;
|
_waitingForPlacementTap = true;
|
||||||
}
|
}
|
||||||
else if (_waitingForPlacementTap)
|
else if (_waitingForPlacementTap)
|
||||||
{
|
{
|
||||||
Debug.Log($"[CLICK-TRACE-PLACEMENT] {name} - Second tap, snapping to slot");
|
|
||||||
// Second tap: snap to slot
|
// Second tap: snap to slot
|
||||||
_waitingForPlacementTap = false;
|
_waitingForPlacementTap = false;
|
||||||
SnapToAlbumSlot();
|
SnapToAlbumSlot();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Debug.Log($"[CLICK-TRACE-PLACEMENT] {name} - Tap after reveal but not waiting for placement tap");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (_isDragRevealing)
|
else if (_isDragRevealing)
|
||||||
{
|
{
|
||||||
Debug.Log($"[CLICK-TRACE-PLACEMENT] {name} - Was drag-revealed, auto-snapping");
|
|
||||||
// Was drag-revealed, auto-snap on release
|
// Was drag-revealed, auto-snap on release
|
||||||
_isDragRevealing = false;
|
_isDragRevealing = false;
|
||||||
SnapToAlbumSlot();
|
SnapToAlbumSlot();
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
Debug.Log($"[CLICK-TRACE-PLACEMENT] {name} - Was dragged but no special handling");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -250,7 +243,6 @@ namespace UI.CardSystem
|
|||||||
{
|
{
|
||||||
RevealCard();
|
RevealCard();
|
||||||
_isDragRevealing = true;
|
_isDragRevealing = true;
|
||||||
Debug.Log("[AlbumCardDraggable] Card revealed via hold");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_holdRevealCoroutine = null;
|
_holdRevealCoroutine = null;
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using AppleHills.Data.CardSystem;
|
using AppleHills.Data.CardSystem;
|
||||||
|
using Core;
|
||||||
using Data.CardSystem;
|
using Data.CardSystem;
|
||||||
using UI.DragAndDrop.Core;
|
using UI.DragAndDrop.Core;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
@@ -72,7 +73,7 @@ namespace UI.CardSystem
|
|||||||
albumCard.SetParentSlot(this);
|
albumCard.SetParentSlot(this);
|
||||||
|
|
||||||
// Register with AlbumViewPage for enlarge/shrink handling
|
// Register with AlbumViewPage for enlarge/shrink handling
|
||||||
AlbumViewPage albumPage = FindObjectOfType<AlbumViewPage>();
|
AlbumViewPage albumPage = FindFirstObjectByType<AlbumViewPage>();
|
||||||
if (albumPage != null)
|
if (albumPage != null)
|
||||||
{
|
{
|
||||||
albumPage.RegisterAlbumCard(albumCard);
|
albumPage.RegisterAlbumCard(albumCard);
|
||||||
@@ -133,7 +134,7 @@ namespace UI.CardSystem
|
|||||||
// Keep preview hidden - it'll show when user taps to enlarge
|
// Keep preview hidden - it'll show when user taps to enlarge
|
||||||
previewCardDisplay.gameObject.SetActive(false);
|
previewCardDisplay.gameObject.SetActive(false);
|
||||||
|
|
||||||
Debug.Log($"[AlbumCardSlot] Setup preview card for {targetCardDefinition.Name} (hidden until tap)");
|
Logging.Debug($"[AlbumCardSlot] Setup preview card for {targetCardDefinition.Name} (hidden until tap)");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -152,7 +153,7 @@ namespace UI.CardSystem
|
|||||||
// Guard: need prefab to spawn
|
// Guard: need prefab to spawn
|
||||||
if (albumCardPrefab == null)
|
if (albumCardPrefab == null)
|
||||||
{
|
{
|
||||||
Debug.LogWarning($"[AlbumCardSlot] No albumCardPrefab assigned for slot targeting {targetCardDefinition.name}");
|
Logging.Warning($"[AlbumCardSlot] No albumCardPrefab assigned for slot targeting {targetCardDefinition.name}");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -207,17 +208,17 @@ namespace UI.CardSystem
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Register with AlbumViewPage for enlarge/shrink handling
|
// Register with AlbumViewPage for enlarge/shrink handling
|
||||||
AlbumViewPage albumPage = FindObjectOfType<AlbumViewPage>();
|
AlbumViewPage albumPage = FindFirstObjectByType<AlbumViewPage>();
|
||||||
if (albumPage != null)
|
if (albumPage != null)
|
||||||
{
|
{
|
||||||
albumPage.RegisterAlbumCard(albumCard);
|
albumPage.RegisterAlbumCard(albumCard);
|
||||||
}
|
}
|
||||||
|
|
||||||
Debug.Log($"[AlbumCardSlot] Spawned owned card '{cardData.Name}' ({cardData.Rarity}) in slot");
|
Logging.Debug($"[AlbumCardSlot] Spawned owned card '{cardData.Name}' ({cardData.Rarity}) in slot");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Debug.LogWarning($"[AlbumCardSlot] Spawned prefab has no AlbumCard component!");
|
Logging.Warning($"[AlbumCardSlot] Spawned prefab has no AlbumCard component!");
|
||||||
Destroy(cardObj);
|
Destroy(cardObj);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -235,30 +236,30 @@ namespace UI.CardSystem
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public void OnPointerClick(PointerEventData eventData)
|
public void OnPointerClick(PointerEventData eventData)
|
||||||
{
|
{
|
||||||
Debug.Log($"[CLICK-TRACE-SLOT] OnPointerClick on {name}, _isOccupiedPermanently={_isOccupiedPermanently}, _placedCard={((_placedCard != null) ? _placedCard.name : "NULL")}, _isPreviewShowing={_isPreviewShowing}, position={eventData.position}");
|
Logging.Debug($"[CLICK-TRACE-SLOT] OnPointerClick on {name}, _isOccupiedPermanently={_isOccupiedPermanently}, _placedCard={((_placedCard != null) ? _placedCard.name : "NULL")}, _isPreviewShowing={_isPreviewShowing}, position={eventData.position}");
|
||||||
|
|
||||||
// Only handle clicks if slot is empty
|
// Only handle clicks if slot is empty
|
||||||
if (_isOccupiedPermanently || _placedCard != null)
|
if (_isOccupiedPermanently || _placedCard != null)
|
||||||
{
|
{
|
||||||
Debug.Log($"[CLICK-TRACE-SLOT] {name} - Slot is occupied, ignoring");
|
Logging.Debug($"[CLICK-TRACE-SLOT] {name} - Slot is occupied, ignoring");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only handle if we have a preview card setup
|
// Only handle if we have a preview card setup
|
||||||
if (previewCardDisplay == null || targetCardDefinition == null)
|
if (previewCardDisplay == null || targetCardDefinition == null)
|
||||||
{
|
{
|
||||||
Debug.Log($"[CLICK-TRACE-SLOT] {name} - No preview setup, ignoring");
|
Logging.Debug($"[CLICK-TRACE-SLOT] {name} - No preview setup, ignoring");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_isPreviewShowing)
|
if (_isPreviewShowing)
|
||||||
{
|
{
|
||||||
Debug.Log($"[CLICK-TRACE-SLOT] {name} - Preview is showing, hiding it");
|
Logging.Debug($"[CLICK-TRACE-SLOT] {name} - Preview is showing, hiding it");
|
||||||
HidePreview();
|
HidePreview();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Debug.Log($"[CLICK-TRACE-SLOT] {name} - Preview is hidden, showing it");
|
Logging.Debug($"[CLICK-TRACE-SLOT] {name} - Preview is hidden, showing it");
|
||||||
ShowPreview();
|
ShowPreview();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -283,7 +284,7 @@ namespace UI.CardSystem
|
|||||||
previewCardDisplay.transform.localScale = _previewOriginalScale;
|
previewCardDisplay.transform.localScale = _previewOriginalScale;
|
||||||
|
|
||||||
// Get AlbumViewPage to show backdrop and reparent
|
// Get AlbumViewPage to show backdrop and reparent
|
||||||
AlbumViewPage albumPage = FindObjectOfType<AlbumViewPage>();
|
AlbumViewPage albumPage = FindFirstObjectByType<AlbumViewPage>();
|
||||||
if (albumPage != null)
|
if (albumPage != null)
|
||||||
{
|
{
|
||||||
albumPage.ShowSlotPreview(this, previewCardDisplay.transform);
|
albumPage.ShowSlotPreview(this, previewCardDisplay.transform);
|
||||||
@@ -293,7 +294,7 @@ namespace UI.CardSystem
|
|||||||
Pixelplacement.Tween.LocalScale(previewCardDisplay.transform, _previewOriginalScale * previewEnlargedScale,
|
Pixelplacement.Tween.LocalScale(previewCardDisplay.transform, _previewOriginalScale * previewEnlargedScale,
|
||||||
previewScaleDuration, 0f, Pixelplacement.Tween.EaseOutBack);
|
previewScaleDuration, 0f, Pixelplacement.Tween.EaseOutBack);
|
||||||
|
|
||||||
Debug.Log($"[AlbumCardSlot] Showing preview for {targetCardDefinition.Name}");
|
Logging.Debug($"[AlbumCardSlot] Showing preview for {targetCardDefinition.Name}");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -310,7 +311,7 @@ namespace UI.CardSystem
|
|||||||
previewCardDisplay.SetPreviewMode(false, null);
|
previewCardDisplay.SetPreviewMode(false, null);
|
||||||
|
|
||||||
// Get AlbumViewPage to hide backdrop
|
// Get AlbumViewPage to hide backdrop
|
||||||
AlbumViewPage albumPage = FindObjectOfType<AlbumViewPage>();
|
AlbumViewPage albumPage = FindFirstObjectByType<AlbumViewPage>();
|
||||||
if (albumPage != null)
|
if (albumPage != null)
|
||||||
{
|
{
|
||||||
albumPage.HideSlotPreview(this, previewCardDisplay.transform, () =>
|
albumPage.HideSlotPreview(this, previewCardDisplay.transform, () =>
|
||||||
@@ -340,11 +341,11 @@ namespace UI.CardSystem
|
|||||||
// Hide the preview card after returning to slot
|
// Hide the preview card after returning to slot
|
||||||
previewCardDisplay.gameObject.SetActive(false);
|
previewCardDisplay.gameObject.SetActive(false);
|
||||||
|
|
||||||
Debug.Log($"[AlbumCardSlot] Preview hidden and reset for {targetCardDefinition.Name}");
|
Logging.Debug($"[AlbumCardSlot] Preview hidden and reset for {targetCardDefinition.Name}");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Debug.Log($"[AlbumCardSlot] Hiding preview for {targetCardDefinition.Name}");
|
Logging.Debug($"[AlbumCardSlot] Hiding preview for {targetCardDefinition.Name}");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -352,7 +353,7 @@ namespace UI.CardSystem
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public void DismissPreview()
|
public void DismissPreview()
|
||||||
{
|
{
|
||||||
Debug.Log($"[CLICK-TRACE-SLOT] DismissPreview called on {name}");
|
Logging.Debug($"[CLICK-TRACE-SLOT] DismissPreview called on {name}");
|
||||||
HidePreview();
|
HidePreview();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using UI.DragAndDrop.Core;
|
using Core;
|
||||||
|
using UI.DragAndDrop.Core;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
|
||||||
namespace UI.CardSystem.DragDrop
|
namespace UI.CardSystem.DragDrop
|
||||||
@@ -127,10 +128,10 @@ namespace UI.CardSystem.DragDrop
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public void SetInOpeningSlot(bool inSlot)
|
public void SetInOpeningSlot(bool inSlot)
|
||||||
{
|
{
|
||||||
Debug.Log($"[BoosterPackDraggable] SetInOpeningSlot({inSlot}) called on {name}");
|
Logging.Debug($"[BoosterPackDraggable] SetInOpeningSlot({inSlot}) called on {name}");
|
||||||
|
|
||||||
SetDraggingEnabled(!inSlot); // Disable dragging when in opening slot
|
SetDraggingEnabled(!inSlot); // Disable dragging when in opening slot
|
||||||
Debug.Log($"[BoosterPackDraggable] SetDraggingEnabled({!inSlot}) called");
|
Logging.Debug($"[BoosterPackDraggable] SetDraggingEnabled({!inSlot}) called");
|
||||||
|
|
||||||
canTapToOpen = inSlot; // Enable tap-to-open when in opening slot
|
canTapToOpen = inSlot; // Enable tap-to-open when in opening slot
|
||||||
|
|
||||||
|
|||||||
@@ -308,10 +308,8 @@ namespace UI.CardSystem.DragDrop
|
|||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
protected override void OnDestroy()
|
private void OnDestroy()
|
||||||
{
|
{
|
||||||
base.OnDestroy();
|
|
||||||
|
|
||||||
if (_boosterDraggable != null)
|
if (_boosterDraggable != null)
|
||||||
{
|
{
|
||||||
_boosterDraggable.OnBoosterOpened -= HandleBoosterOpened;
|
_boosterDraggable.OnBoosterOpened -= HandleBoosterOpened;
|
||||||
|
|||||||
@@ -107,10 +107,8 @@ namespace UI.CardSystem.DragDrop
|
|||||||
// Card-specific visual effects when dragging ends
|
// Card-specific visual effects when dragging ends
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnDestroy()
|
private void OnDestroy()
|
||||||
{
|
{
|
||||||
base.OnDestroy();
|
|
||||||
|
|
||||||
if (_cardDraggable != null)
|
if (_cardDraggable != null)
|
||||||
{
|
{
|
||||||
_cardDraggable.OnCardDataChanged -= HandleCardDataChanged;
|
_cardDraggable.OnCardDataChanged -= HandleCardDataChanged;
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using AppleHills.Data.CardSystem;
|
using AppleHills.Data.CardSystem;
|
||||||
|
using Core;
|
||||||
using Pixelplacement;
|
using Pixelplacement;
|
||||||
using Pixelplacement.TweenSystem;
|
using Pixelplacement.TweenSystem;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
@@ -40,7 +41,6 @@ namespace UI.CardSystem
|
|||||||
// State
|
// State
|
||||||
private bool _isFlipped = false;
|
private bool _isFlipped = false;
|
||||||
private bool _isFlipping = false;
|
private bool _isFlipping = false;
|
||||||
private bool _isHovering = false;
|
|
||||||
private TweenBase _idleHoverTween;
|
private TweenBase _idleHoverTween;
|
||||||
private CardData _cardData;
|
private CardData _cardData;
|
||||||
private Vector2 _originalPosition; // Track original spawn position
|
private Vector2 _originalPosition; // Track original spawn position
|
||||||
@@ -241,8 +241,6 @@ namespace UI.CardSystem
|
|||||||
if (_isFlipped || _isFlipping)
|
if (_isFlipped || _isFlipping)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
_isHovering = true;
|
|
||||||
|
|
||||||
// Scale up slightly on hover
|
// Scale up slightly on hover
|
||||||
Tween.LocalScale(transform, Vector3.one * hoverScaleMultiplier, 0.2f, 0f, Tween.EaseOutBack);
|
Tween.LocalScale(transform, Vector3.one * hoverScaleMultiplier, 0.2f, 0f, Tween.EaseOutBack);
|
||||||
}
|
}
|
||||||
@@ -252,20 +250,18 @@ namespace UI.CardSystem
|
|||||||
if (_isFlipped || _isFlipping)
|
if (_isFlipped || _isFlipping)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
_isHovering = false;
|
|
||||||
|
|
||||||
// Scale back to normal
|
// Scale back to normal
|
||||||
Tween.LocalScale(transform, Vector3.one, 0.2f, 0f, Tween.EaseOutBack);
|
Tween.LocalScale(transform, Vector3.one, 0.2f, 0f, Tween.EaseOutBack);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnPointerClick(PointerEventData eventData)
|
public void OnPointerClick(PointerEventData eventData)
|
||||||
{
|
{
|
||||||
Debug.Log($"[CLICK-TRACE-FLIPPABLE] OnPointerClick on {name}, _isClickable={_isClickable}, _isWaitingForTap={_isWaitingForTap}, _isFlipped={_isFlipped}, position={eventData.position}");
|
Logging.Debug($"[CLICK-TRACE-FLIPPABLE] OnPointerClick on {name}, _isClickable={_isClickable}, _isWaitingForTap={_isWaitingForTap}, _isFlipped={_isFlipped}, position={eventData.position}");
|
||||||
|
|
||||||
// If not clickable, notify and return
|
// If not clickable, notify and return
|
||||||
if (!_isClickable)
|
if (!_isClickable)
|
||||||
{
|
{
|
||||||
Debug.Log($"[CLICK-TRACE-FLIPPABLE] {name} - Not clickable, firing OnClickedWhileInactive");
|
Logging.Debug($"[CLICK-TRACE-FLIPPABLE] {name} - Not clickable, firing OnClickedWhileInactive");
|
||||||
OnClickedWhileInactive?.Invoke(this);
|
OnClickedWhileInactive?.Invoke(this);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -273,7 +269,7 @@ namespace UI.CardSystem
|
|||||||
// If waiting for tap after reveal, handle that
|
// If waiting for tap after reveal, handle that
|
||||||
if (_isWaitingForTap)
|
if (_isWaitingForTap)
|
||||||
{
|
{
|
||||||
Debug.Log($"[CLICK-TRACE-FLIPPABLE] {name} - Waiting for tap, dismissing enlarged state");
|
Logging.Debug($"[CLICK-TRACE-FLIPPABLE] {name} - Waiting for tap, dismissing enlarged state");
|
||||||
OnCardTappedAfterReveal?.Invoke(this);
|
OnCardTappedAfterReveal?.Invoke(this);
|
||||||
_isWaitingForTap = false;
|
_isWaitingForTap = false;
|
||||||
return;
|
return;
|
||||||
@@ -281,11 +277,11 @@ namespace UI.CardSystem
|
|||||||
|
|
||||||
if (_isFlipped || _isFlipping)
|
if (_isFlipped || _isFlipping)
|
||||||
{
|
{
|
||||||
Debug.Log($"[CLICK-TRACE-FLIPPABLE] {name} - Ignoring click (flipped={_isFlipped}, flipping={_isFlipping})");
|
Logging.Debug($"[CLICK-TRACE-FLIPPABLE] {name} - Ignoring click (flipped={_isFlipped}, flipping={_isFlipping})");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Debug.Log($"[CLICK-TRACE-FLIPPABLE] {name} - Processing click, starting flip");
|
Logging.Debug($"[CLICK-TRACE-FLIPPABLE] {name} - Processing click, starting flip");
|
||||||
// Flip on click
|
// Flip on click
|
||||||
FlipToReveal();
|
FlipToReveal();
|
||||||
}
|
}
|
||||||
@@ -341,7 +337,7 @@ namespace UI.CardSystem
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private void TriggerUpgradeTransition(AppleHills.Data.CardSystem.CardData lowerRarityCard)
|
private void TriggerUpgradeTransition(AppleHills.Data.CardSystem.CardData lowerRarityCard)
|
||||||
{
|
{
|
||||||
Debug.Log($"[FlippableCard] Triggering upgrade transition from {lowerRarityCard.Rarity}!");
|
Logging.Debug($"[FlippableCard] Triggering upgrade transition from {lowerRarityCard.Rarity}!");
|
||||||
|
|
||||||
AppleHills.Data.CardSystem.CardRarity oldRarity = lowerRarityCard.Rarity;
|
AppleHills.Data.CardSystem.CardRarity oldRarity = lowerRarityCard.Rarity;
|
||||||
AppleHills.Data.CardSystem.CardRarity newRarity = oldRarity + 1;
|
AppleHills.Data.CardSystem.CardRarity newRarity = oldRarity + 1;
|
||||||
@@ -429,7 +425,7 @@ namespace UI.CardSystem
|
|||||||
if (newCardText != null)
|
if (newCardText != null)
|
||||||
newCardText.SetActive(true);
|
newCardText.SetActive(true);
|
||||||
|
|
||||||
Debug.Log($"[FlippableCard] Card upgraded from {oldRarity} to {newRarity}! Showing as NEW.");
|
Logging.Debug($"[FlippableCard] Card upgraded from {oldRarity} to {newRarity}! Showing as NEW.");
|
||||||
|
|
||||||
// Card is already enlarged from the repeat display, so no need to enlarge again
|
// Card is already enlarged from the repeat display, so no need to enlarge again
|
||||||
}
|
}
|
||||||
@@ -457,7 +453,7 @@ namespace UI.CardSystem
|
|||||||
TransitionToNewCardView(newRarity);
|
TransitionToNewCardView(newRarity);
|
||||||
});
|
});
|
||||||
|
|
||||||
Debug.Log($"[FlippableCard] Card upgraded from {oldRarity} to {newRarity}! Showing progress {ownedAtNewRarity}/5");
|
Logging.Debug($"[FlippableCard] Card upgraded from {oldRarity} to {newRarity}! Showing progress {ownedAtNewRarity}/5");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -465,7 +461,7 @@ namespace UI.CardSystem
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private void TransitionToNewCardView(AppleHills.Data.CardSystem.CardRarity newRarity)
|
private void TransitionToNewCardView(AppleHills.Data.CardSystem.CardRarity newRarity)
|
||||||
{
|
{
|
||||||
Debug.Log($"[FlippableCard] Transitioning to NEW CARD view at {newRarity} rarity");
|
Logging.Debug($"[FlippableCard] Transitioning to NEW CARD view at {newRarity} rarity");
|
||||||
|
|
||||||
// Update the CardDisplay to show new rarity
|
// Update the CardDisplay to show new rarity
|
||||||
if (cardDisplay != null && _cardData != null)
|
if (cardDisplay != null && _cardData != null)
|
||||||
@@ -488,7 +484,7 @@ namespace UI.CardSystem
|
|||||||
_isNew = true;
|
_isNew = true;
|
||||||
_isWaitingForTap = true;
|
_isWaitingForTap = true;
|
||||||
|
|
||||||
Debug.Log($"[FlippableCard] Now showing as NEW CARD at {newRarity}, waiting for tap");
|
Logging.Debug($"[FlippableCard] Now showing as NEW CARD at {newRarity}, waiting for tap");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -538,7 +534,7 @@ namespace UI.CardSystem
|
|||||||
// Check if we have the required number of elements (should match cardsToUpgrade)
|
// Check if we have the required number of elements (should match cardsToUpgrade)
|
||||||
if (progressElements.Length < cardsToUpgrade)
|
if (progressElements.Length < cardsToUpgrade)
|
||||||
{
|
{
|
||||||
Debug.LogWarning($"[FlippableCard] Not enough Image components in progress bar! Expected {cardsToUpgrade}, found {progressElements.Length}");
|
Logging.Warning($"[FlippableCard] Not enough Image components in progress bar! Expected {cardsToUpgrade}, found {progressElements.Length}");
|
||||||
onComplete?.Invoke();
|
onComplete?.Invoke();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -647,7 +643,7 @@ namespace UI.CardSystem
|
|||||||
{
|
{
|
||||||
if (albumCard == null)
|
if (albumCard == null)
|
||||||
{
|
{
|
||||||
Debug.LogWarning("[FlippableCard] Cannot extract AlbumCard - none found!");
|
Logging.Warning("[FlippableCard] Cannot extract AlbumCard - none found!");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -661,7 +657,7 @@ namespace UI.CardSystem
|
|||||||
albumCard.SetupCard(_cardData);
|
albumCard.SetupCard(_cardData);
|
||||||
}
|
}
|
||||||
|
|
||||||
Debug.Log($"[FlippableCard] Extracted AlbumCard '{_cardData?.Name}' to {newParent.name} - ready for tween");
|
Logging.Debug($"[FlippableCard] Extracted AlbumCard '{_cardData?.Name}' to {newParent.name} - ready for tween");
|
||||||
|
|
||||||
return albumCard;
|
return albumCard;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
|
using Core;
|
||||||
using Data.CardSystem;
|
using Data.CardSystem;
|
||||||
using Pixelplacement;
|
using Pixelplacement;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
@@ -10,7 +11,8 @@ namespace UI.CardSystem
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Singleton UI component for granting booster packs from minigames.
|
/// Singleton UI component for granting booster packs from minigames.
|
||||||
/// Displays a booster pack with glow effect, waits for user to click continue,
|
/// Displays a booster pack with glow effect, waits for user to click continue,
|
||||||
/// then animates the pack flying to bottom-left corner before granting the reward.
|
/// then shows the scrapbook button and animates the pack flying to it before granting the reward.
|
||||||
|
/// The scrapbook button is automatically hidden after the animation completes.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class MinigameBoosterGiver : MonoBehaviour
|
public class MinigameBoosterGiver : MonoBehaviour
|
||||||
{
|
{
|
||||||
@@ -25,7 +27,6 @@ namespace UI.CardSystem
|
|||||||
[Header("Animation Settings")]
|
[Header("Animation Settings")]
|
||||||
[SerializeField] private float hoverAmount = 20f;
|
[SerializeField] private float hoverAmount = 20f;
|
||||||
[SerializeField] private float hoverDuration = 1.5f;
|
[SerializeField] private float hoverDuration = 1.5f;
|
||||||
[SerializeField] private float glowPulseMin = 0.9f;
|
|
||||||
[SerializeField] private float glowPulseMax = 1.1f;
|
[SerializeField] private float glowPulseMax = 1.1f;
|
||||||
[SerializeField] private float glowPulseDuration = 1.2f;
|
[SerializeField] private float glowPulseDuration = 1.2f;
|
||||||
|
|
||||||
@@ -45,7 +46,7 @@ namespace UI.CardSystem
|
|||||||
// Singleton pattern
|
// Singleton pattern
|
||||||
if (Instance != null && Instance != this)
|
if (Instance != null && Instance != this)
|
||||||
{
|
{
|
||||||
Debug.LogWarning("[MinigameBoosterGiver] Duplicate instance found. Destroying.");
|
Logging.Warning("[MinigameBoosterGiver] Duplicate instance found. Destroying.");
|
||||||
Destroy(gameObject);
|
Destroy(gameObject);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -98,7 +99,7 @@ namespace UI.CardSystem
|
|||||||
{
|
{
|
||||||
if (_currentSequence != null)
|
if (_currentSequence != null)
|
||||||
{
|
{
|
||||||
Debug.LogWarning("[MinigameBoosterGiver] Already running a sequence. Ignoring new request.");
|
Logging.Warning("[MinigameBoosterGiver] Already running a sequence. Ignoring new request.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -187,23 +188,61 @@ namespace UI.CardSystem
|
|||||||
yield break;
|
yield break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate bottom-left corner position in local space
|
// Show scrapbook button temporarily using HUD visibility context
|
||||||
RectTransform canvasRect = GetComponentInParent<Canvas>()?.GetComponent<RectTransform>();
|
PlayerHudManager.HudVisibilityContext hudContext = null;
|
||||||
Vector3 targetPosition;
|
GameObject scrapbookButton = null;
|
||||||
|
|
||||||
if (canvasRect != null)
|
scrapbookButton = PlayerHudManager.Instance.GetScrabookButton();
|
||||||
|
if (scrapbookButton != null)
|
||||||
{
|
{
|
||||||
// Convert bottom-left corner with offset to local position
|
hudContext = PlayerHudManager.Instance.ShowElementTemporarily(scrapbookButton);
|
||||||
Vector2 bottomLeft = new Vector2(-canvasRect.rect.width / 2f, -canvasRect.rect.height / 2f);
|
|
||||||
targetPosition = bottomLeft + targetBottomLeftOffset;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Fallback if no canvas found
|
Logging.Warning("[MinigameBoosterGiver] Scrapbook button not found in PlayerHudManager.");
|
||||||
targetPosition = _boosterInitialPosition + new Vector3(-500f, -500f, 0f);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tween to bottom-left corner
|
// Calculate target position - use scrapbook button position if available
|
||||||
|
Vector3 targetPosition;
|
||||||
|
|
||||||
|
if (scrapbookButton != null)
|
||||||
|
{
|
||||||
|
// Get the scrapbook button's position in the same coordinate space as boosterImage
|
||||||
|
RectTransform scrapbookRect = scrapbookButton.GetComponent<RectTransform>();
|
||||||
|
if (scrapbookRect != null)
|
||||||
|
{
|
||||||
|
// Convert scrapbook button's world position to local position relative to boosterImage's parent
|
||||||
|
Canvas canvas = GetComponentInParent<Canvas>();
|
||||||
|
if (canvas != null && canvas.renderMode == RenderMode.ScreenSpaceOverlay)
|
||||||
|
{
|
||||||
|
// For overlay canvas, convert screen position to local position
|
||||||
|
Vector2 screenPos = RectTransformUtility.WorldToScreenPoint(null, scrapbookRect.position);
|
||||||
|
RectTransformUtility.ScreenPointToLocalPointInRectangle(
|
||||||
|
boosterImage.parent as RectTransform,
|
||||||
|
screenPos,
|
||||||
|
null,
|
||||||
|
out Vector2 localPoint);
|
||||||
|
targetPosition = localPoint;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// For world space or camera canvas
|
||||||
|
targetPosition = boosterImage.parent.InverseTransformPoint(scrapbookRect.position);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Logging.Warning("[MinigameBoosterGiver] Scrapbook button has no RectTransform, using fallback position.");
|
||||||
|
targetPosition = GetFallbackPosition();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Fallback to bottom-left corner
|
||||||
|
targetPosition = GetFallbackPosition();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tween to scrapbook button position
|
||||||
Tween.LocalPosition(boosterImage, targetPosition, disappearDuration, 0f, Tween.EaseInBack);
|
Tween.LocalPosition(boosterImage, targetPosition, disappearDuration, 0f, Tween.EaseInBack);
|
||||||
|
|
||||||
// Scale down
|
// Scale down
|
||||||
@@ -217,13 +256,16 @@ namespace UI.CardSystem
|
|||||||
if (CardSystemManager.Instance != null)
|
if (CardSystemManager.Instance != null)
|
||||||
{
|
{
|
||||||
CardSystemManager.Instance.AddBoosterPack(1);
|
CardSystemManager.Instance.AddBoosterPack(1);
|
||||||
Debug.Log("[MinigameBoosterGiver] Booster pack granted!");
|
Logging.Debug("[MinigameBoosterGiver] Booster pack granted!");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Debug.LogWarning("[MinigameBoosterGiver] CardSystemManager not found, cannot grant booster pack.");
|
Logging.Warning("[MinigameBoosterGiver] CardSystemManager not found, cannot grant booster pack.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Hide scrapbook button by disposing the context
|
||||||
|
hudContext?.Dispose();
|
||||||
|
|
||||||
// Hide the visual
|
// Hide the visual
|
||||||
if (visualContainer != null)
|
if (visualContainer != null)
|
||||||
{
|
{
|
||||||
@@ -237,6 +279,22 @@ namespace UI.CardSystem
|
|||||||
// Clear sequence reference
|
// Clear sequence reference
|
||||||
_currentSequence = null;
|
_currentSequence = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Vector3 GetFallbackPosition()
|
||||||
|
{
|
||||||
|
RectTransform canvasRect = GetComponentInParent<Canvas>()?.GetComponent<RectTransform>();
|
||||||
|
if (canvasRect != null)
|
||||||
|
{
|
||||||
|
// Convert bottom-left corner with offset to local position
|
||||||
|
Vector2 bottomLeft = new Vector2(-canvasRect.rect.width / 2f, -canvasRect.rect.height / 2f);
|
||||||
|
return bottomLeft + targetBottomLeftOffset;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Ultimate fallback if no canvas found
|
||||||
|
return _boosterInitialPosition + new Vector3(-500f, -500f, 0f);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using UI.DragAndDrop.Core;
|
using Core;
|
||||||
|
using UI.DragAndDrop.Core;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
|
||||||
namespace UI.CardSystem
|
namespace UI.CardSystem
|
||||||
@@ -22,7 +23,7 @@ namespace UI.CardSystem
|
|||||||
if (container == null || objects == null || objects.Count == 0)
|
if (container == null || objects == null || objects.Count == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Debug.Log($"[SlotContainerHelper] Shuffling {objects.Count} objects to front slots");
|
Logging.Debug($"[SlotContainerHelper] Shuffling {objects.Count} objects to front slots");
|
||||||
|
|
||||||
// Unassign all objects from their current slots
|
// Unassign all objects from their current slots
|
||||||
foreach (var obj in objects)
|
foreach (var obj in objects)
|
||||||
@@ -41,12 +42,12 @@ namespace UI.CardSystem
|
|||||||
|
|
||||||
if (targetSlot != null)
|
if (targetSlot != null)
|
||||||
{
|
{
|
||||||
Debug.Log($"[SlotContainerHelper] Assigning object to slot with SlotIndex {i}");
|
Logging.Debug($"[SlotContainerHelper] Assigning object to slot with SlotIndex {i}");
|
||||||
obj.AssignToSlot(targetSlot, animate);
|
obj.AssignToSlot(targetSlot, animate);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Debug.LogWarning($"[SlotContainerHelper] Could not find slot with SlotIndex {i}");
|
Logging.Warning($"[SlotContainerHelper] Could not find slot with SlotIndex {i}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,9 +15,6 @@ namespace UI.Core
|
|||||||
[Header("Page Settings")]
|
[Header("Page Settings")]
|
||||||
public string PageName;
|
public string PageName;
|
||||||
|
|
||||||
// UI pages load after UI infrastructure (UIPageController is priority 50)
|
|
||||||
public override int ManagedAwakePriority => 200;
|
|
||||||
|
|
||||||
// Events using System.Action instead of UnityEvents
|
// Events using System.Action instead of UnityEvents
|
||||||
public event Action OnTransitionInStarted;
|
public event Action OnTransitionInStarted;
|
||||||
public event Action OnTransitionInCompleted;
|
public event Action OnTransitionInCompleted;
|
||||||
|
|||||||
@@ -37,25 +37,19 @@ namespace UI.Core
|
|||||||
private PlayerInput _playerInput;
|
private PlayerInput _playerInput;
|
||||||
private InputAction _cancelAction;
|
private InputAction _cancelAction;
|
||||||
|
|
||||||
public override int ManagedAwakePriority => 50; // UI infrastructure
|
internal override void OnManagedAwake()
|
||||||
|
|
||||||
private new void Awake()
|
|
||||||
{
|
{
|
||||||
base.Awake(); // CRITICAL: Register with LifecycleManager!
|
// Set instance immediately (early initialization)
|
||||||
|
|
||||||
// Set instance immediately so it's available before OnManagedAwake() is called
|
|
||||||
_instance = this;
|
_instance = this;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnManagedAwake()
|
internal override void OnManagedStart()
|
||||||
{
|
{
|
||||||
Logging.Debug("[UIPageController] Initialized");
|
Logging.Debug("[UIPageController] Initialized");
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnDestroy()
|
internal override void OnManagedDestroy()
|
||||||
{
|
{
|
||||||
base.OnDestroy();
|
|
||||||
|
|
||||||
// Clean up cached instances
|
// Clean up cached instances
|
||||||
foreach (var cachedPage in _prefabInstanceCache.Values)
|
foreach (var cachedPage in _prefabInstanceCache.Values)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
|
using Core;
|
||||||
using Pixelplacement;
|
using Pixelplacement;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityEngine.EventSystems;
|
using UnityEngine.EventSystems;
|
||||||
@@ -79,10 +80,10 @@ namespace UI.DragAndDrop.Core
|
|||||||
|
|
||||||
protected virtual void Initialize()
|
protected virtual void Initialize()
|
||||||
{
|
{
|
||||||
Debug.Log($"[DraggableObject] Initializing {name} at world pos {transform.position}, local pos {transform.localPosition}, parent: {(transform.parent != null ? transform.parent.name : "NULL")}");
|
Logging.Debug($"[DraggableObject] Initializing {name} at world pos {transform.position}, local pos {transform.localPosition}, parent: {(transform.parent != null ? transform.parent.name : "NULL")}");
|
||||||
|
|
||||||
_canvas = GetComponentInParent<Canvas>();
|
_canvas = GetComponentInParent<Canvas>();
|
||||||
Debug.Log($"[DraggableObject] {name} found canvas: {(_canvas != null ? _canvas.name : "NULL")}, canvas pos: {(_canvas != null ? _canvas.transform.position.ToString() : "N/A")}");
|
Logging.Debug($"[DraggableObject] {name} found canvas: {(_canvas != null ? _canvas.name : "NULL")}, canvas pos: {(_canvas != null ? _canvas.transform.position.ToString() : "N/A")}");
|
||||||
|
|
||||||
_imageComponent = GetComponent<Image>();
|
_imageComponent = GetComponent<Image>();
|
||||||
_canvasGroup = GetComponent<CanvasGroup>();
|
_canvasGroup = GetComponent<CanvasGroup>();
|
||||||
@@ -95,7 +96,7 @@ namespace UI.DragAndDrop.Core
|
|||||||
_imageComponent = gameObject.AddComponent<Image>();
|
_imageComponent = gameObject.AddComponent<Image>();
|
||||||
_imageComponent.color = new Color(1, 1, 1, 0.01f); // Nearly transparent (0 doesn't work)
|
_imageComponent.color = new Color(1, 1, 1, 0.01f); // Nearly transparent (0 doesn't work)
|
||||||
_imageComponent.raycastTarget = true;
|
_imageComponent.raycastTarget = true;
|
||||||
Debug.Log($"[DraggableObject] Added invisible Image to {name} for raycast detection");
|
Logging.Debug($"[DraggableObject] Added invisible Image to {name} for raycast detection");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use assigned visual, or find in children recursively if not assigned
|
// Use assigned visual, or find in children recursively if not assigned
|
||||||
@@ -190,19 +191,19 @@ namespace UI.DragAndDrop.Core
|
|||||||
if (eventData.button != PointerEventData.InputButton.Left)
|
if (eventData.button != PointerEventData.InputButton.Left)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Debug.Log($"[DraggableObject] OnBeginDrag called on {name}. _isDraggingEnabled={_isDraggingEnabled}");
|
Logging.Debug($"[DraggableObject] OnBeginDrag called on {name}. _isDraggingEnabled={_isDraggingEnabled}");
|
||||||
|
|
||||||
// Check if dragging is enabled BEFORE setting any state
|
// Check if dragging is enabled BEFORE setting any state
|
||||||
if (!_isDraggingEnabled)
|
if (!_isDraggingEnabled)
|
||||||
{
|
{
|
||||||
Debug.Log($"[DraggableObject] OnBeginDrag blocked - dragging disabled on {name}");
|
Logging.Debug($"[DraggableObject] OnBeginDrag blocked - dragging disabled on {name}");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_isDragging = true;
|
_isDragging = true;
|
||||||
_wasDragged = true;
|
_wasDragged = true;
|
||||||
|
|
||||||
Debug.Log($"[DraggableObject] Drag started on {name}");
|
Logging.Debug($"[DraggableObject] Drag started on {name}");
|
||||||
|
|
||||||
// ...existing code...
|
// ...existing code...
|
||||||
if (_canvas != null && _canvas.renderMode == RenderMode.ScreenSpaceOverlay && RectTransform != null)
|
if (_canvas != null && _canvas.renderMode == RenderMode.ScreenSpaceOverlay && RectTransform != null)
|
||||||
@@ -345,7 +346,7 @@ namespace UI.DragAndDrop.Core
|
|||||||
|
|
||||||
protected virtual void FindAndSnapToSlot()
|
protected virtual void FindAndSnapToSlot()
|
||||||
{
|
{
|
||||||
SlotContainer[] containers = FindObjectsOfType<SlotContainer>();
|
SlotContainer[] containers = FindObjectsByType<SlotContainer>(FindObjectsSortMode.None);
|
||||||
DraggableSlot closestSlot = null;
|
DraggableSlot closestSlot = null;
|
||||||
float closestDistance = float.MaxValue;
|
float closestDistance = float.MaxValue;
|
||||||
|
|
||||||
@@ -413,7 +414,7 @@ namespace UI.DragAndDrop.Core
|
|||||||
if (slot == null)
|
if (slot == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Debug.Log($"[DraggableObject] Assigning {name} to slot {slot.name}, animate={animate}, current pos={transform.position}, slot pos={slot.transform.position}");
|
Logging.Debug($"[DraggableObject] Assigning {name} to slot {slot.name}, animate={animate}, current pos={transform.position}, slot pos={slot.transform.position}");
|
||||||
|
|
||||||
DraggableSlot previousSlot = _currentSlot;
|
DraggableSlot previousSlot = _currentSlot;
|
||||||
_currentSlot = slot;
|
_currentSlot = slot;
|
||||||
@@ -429,7 +430,7 @@ namespace UI.DragAndDrop.Core
|
|||||||
transform.SetParent(slot.transform);
|
transform.SetParent(slot.transform);
|
||||||
transform.localPosition = _isSelected ? new Vector3(0, selectionOffset, 0) : Vector3.zero;
|
transform.localPosition = _isSelected ? new Vector3(0, selectionOffset, 0) : Vector3.zero;
|
||||||
transform.localRotation = Quaternion.identity;
|
transform.localRotation = Quaternion.identity;
|
||||||
Debug.Log($"[DraggableObject] {name} assigned to slot {slot.name}, new world pos={transform.position}, local pos={transform.localPosition}");
|
Logging.Debug($"[DraggableObject] {name} assigned to slot {slot.name}, new world pos={transform.position}, local pos={transform.localPosition}");
|
||||||
}
|
}
|
||||||
|
|
||||||
OnSlotChanged?.Invoke(this, slot);
|
OnSlotChanged?.Invoke(this, slot);
|
||||||
@@ -510,14 +511,14 @@ namespace UI.DragAndDrop.Core
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public virtual void SetDraggingEnabled(bool enabled)
|
public virtual void SetDraggingEnabled(bool enabled)
|
||||||
{
|
{
|
||||||
Debug.Log($"[DraggableObject] SetDraggingEnabled({enabled}) called on {name}. _isDragging={_isDragging}, _isDraggingEnabled={_isDraggingEnabled}");
|
Logging.Debug($"[DraggableObject] SetDraggingEnabled({enabled}) called on {name}. _isDragging={_isDragging}, _isDraggingEnabled={_isDraggingEnabled}");
|
||||||
|
|
||||||
_isDraggingEnabled = enabled;
|
_isDraggingEnabled = enabled;
|
||||||
|
|
||||||
// If disabling dragging while actively dragging, stop the drag
|
// If disabling dragging while actively dragging, stop the drag
|
||||||
if (!enabled && _isDragging)
|
if (!enabled && _isDragging)
|
||||||
{
|
{
|
||||||
Debug.Log($"[DraggableObject] Stopping active drag on {name}");
|
Logging.Debug($"[DraggableObject] Stopping active drag on {name}");
|
||||||
_isDragging = false;
|
_isDragging = false;
|
||||||
|
|
||||||
// Re-enable raycasting
|
// Re-enable raycasting
|
||||||
@@ -529,7 +530,7 @@ namespace UI.DragAndDrop.Core
|
|||||||
_canvasGroup.blocksRaycasts = true;
|
_canvasGroup.blocksRaycasts = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Debug.Log($"[DraggableObject] After SetDraggingEnabled: _isDragging={_isDragging}, _isDraggingEnabled={_isDraggingEnabled}");
|
Logging.Debug($"[DraggableObject] After SetDraggingEnabled: _isDragging={_isDragging}, _isDraggingEnabled={_isDraggingEnabled}");
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using Pixelplacement;
|
using Core;
|
||||||
|
using Pixelplacement;
|
||||||
using Pixelplacement.TweenSystem;
|
using Pixelplacement.TweenSystem;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityEngine.InputSystem; // Added for new Input System
|
using UnityEngine.InputSystem; // Added for new Input System
|
||||||
@@ -67,14 +68,14 @@ namespace UI.DragAndDrop.Core
|
|||||||
_parentDraggable = parent;
|
_parentDraggable = parent;
|
||||||
|
|
||||||
Canvas parentCanvas = parent.GetComponentInParent<Canvas>();
|
Canvas parentCanvas = parent.GetComponentInParent<Canvas>();
|
||||||
Debug.Log($"[DraggableVisual] Initializing visual for {parent.name} at world pos {parent.transform.position}, parent canvas: {(parentCanvas != null ? parentCanvas.name + " (renderMode: " + parentCanvas.renderMode + ")" : "NULL")}");
|
Logging.Debug($"[DraggableVisual] Initializing visual for {parent.name} at world pos {parent.transform.position}, parent canvas: {(parentCanvas != null ? parentCanvas.name + " (renderMode: " + parentCanvas.renderMode + ")" : "NULL")}");
|
||||||
|
|
||||||
// CRITICAL: Reparent visual to canvas (not base) so it can move independently
|
// CRITICAL: Reparent visual to canvas (not base) so it can move independently
|
||||||
// This enables the delayed follow effect
|
// This enables the delayed follow effect
|
||||||
if (parentCanvas != null)
|
if (parentCanvas != null)
|
||||||
{
|
{
|
||||||
transform.SetParent(parentCanvas.transform, true); // worldPositionStays = true
|
transform.SetParent(parentCanvas.transform, true); // worldPositionStays = true
|
||||||
Debug.Log($"[DraggableVisual] Reparented visual {name} to canvas {parentCanvas.name} for independent movement");
|
Logging.Debug($"[DraggableVisual] Reparented visual {name} to canvas {parentCanvas.name} for independent movement");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get components if assigned (don't auto-create Canvas to avoid Unity's auto-reparenting)
|
// Get components if assigned (don't auto-create Canvas to avoid Unity's auto-reparenting)
|
||||||
@@ -106,7 +107,7 @@ namespace UI.DragAndDrop.Core
|
|||||||
tiltParent.localRotation = Quaternion.identity;
|
tiltParent.localRotation = Quaternion.identity;
|
||||||
}
|
}
|
||||||
|
|
||||||
Debug.Log($"[DraggableVisual] Visual {name} initialized at world pos {transform.position}, local pos {transform.localPosition}, local rotation {transform.localRotation.eulerAngles}, parent at world pos {parent.transform.position}, local pos {parent.transform.localPosition}, rotation {parent.transform.rotation.eulerAngles}");
|
Logging.Debug($"[DraggableVisual] Visual {name} initialized at world pos {transform.position}, local pos {transform.localPosition}, local rotation {transform.localRotation.eulerAngles}, parent at world pos {parent.transform.position}, local pos {parent.transform.localPosition}, rotation {parent.transform.rotation.eulerAngles}");
|
||||||
|
|
||||||
_isInitialized = true;
|
_isInitialized = true;
|
||||||
|
|
||||||
@@ -202,7 +203,7 @@ namespace UI.DragAndDrop.Core
|
|||||||
float distance = Vector3.Distance(currentPosition, targetPosition);
|
float distance = Vector3.Distance(currentPosition, targetPosition);
|
||||||
if (distance > 500f)
|
if (distance > 500f)
|
||||||
{
|
{
|
||||||
Debug.LogWarning($"[DraggableVisual] Large position delta detected! Visual {name} at {currentPosition}, target {targetPosition}, parent {_parentDraggable.name}, distance: {distance}");
|
Logging.Warning($"[DraggableVisual] Large position delta detected! Visual {name} at {currentPosition}, target {targetPosition}, parent {_parentDraggable.name}, distance: {distance}");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply follow logic with snappy easing
|
// Apply follow logic with snappy easing
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using UI.Core;
|
using Core;
|
||||||
|
using UI.Core;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityEngine.UI;
|
using UnityEngine.UI;
|
||||||
|
|
||||||
@@ -53,7 +54,7 @@ namespace UI
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Debug.Log($"[HudMenuButton] {buttonName} opening page from prefab: {pagePrefab.name}");
|
Logging.Debug($"[HudMenuButton] {buttonName} opening page from prefab: {pagePrefab.name}");
|
||||||
UIPageController.Instance.PushPageFromPrefab(pagePrefab);
|
UIPageController.Instance.PushPageFromPrefab(pagePrefab);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -52,15 +52,10 @@ namespace UI
|
|||||||
/// Singleton instance of the LoadingScreenController. No longer creates an instance if one doesn't exist.
|
/// Singleton instance of the LoadingScreenController. No longer creates an instance if one doesn't exist.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static LoadingScreenController Instance => _instance;
|
public static LoadingScreenController Instance => _instance;
|
||||||
|
|
||||||
// ManagedBehaviour configuration
|
|
||||||
public override int ManagedAwakePriority => 45; // UI infrastructure, before UIPageController
|
|
||||||
|
|
||||||
private new void Awake()
|
internal override void OnManagedAwake()
|
||||||
{
|
{
|
||||||
base.Awake(); // CRITICAL: Register with LifecycleManager!
|
// Set instance immediately (early initialization)
|
||||||
|
|
||||||
// Set instance immediately so it's available before OnManagedAwake() is called
|
|
||||||
_instance = this;
|
_instance = this;
|
||||||
|
|
||||||
// Set up container reference early
|
// Set up container reference early
|
||||||
@@ -74,7 +69,7 @@ namespace UI
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnManagedAwake()
|
internal override void OnManagedStart()
|
||||||
{
|
{
|
||||||
Logging.Debug("[LoadingScreenController] Initialized");
|
Logging.Debug("[LoadingScreenController] Initialized");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,15 +27,10 @@ namespace UI
|
|||||||
[SerializeField] private UnityEngine.UI.Button devOptionsButton;
|
[SerializeField] private UnityEngine.UI.Button devOptionsButton;
|
||||||
[SerializeField] private GameObject mainOptionsContainer;
|
[SerializeField] private GameObject mainOptionsContainer;
|
||||||
[SerializeField] private GameObject devOptionsContainer;
|
[SerializeField] private GameObject devOptionsContainer;
|
||||||
|
|
||||||
// After UIPageController (50)
|
|
||||||
public override int ManagedAwakePriority => 55;
|
|
||||||
|
|
||||||
private new void Awake()
|
internal override void OnManagedAwake()
|
||||||
{
|
{
|
||||||
base.Awake(); // CRITICAL: Register with LifecycleManager!
|
// Set instance immediately (early initialization)
|
||||||
|
|
||||||
// Set instance immediately so it's available before OnManagedAwake() is called
|
|
||||||
_instance = this;
|
_instance = this;
|
||||||
|
|
||||||
// Ensure we have a CanvasGroup for transitions
|
// Ensure we have a CanvasGroup for transitions
|
||||||
@@ -51,9 +46,9 @@ namespace UI
|
|||||||
gameObject.SetActive(false);
|
gameObject.SetActive(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnManagedAwake()
|
internal override void OnManagedStart()
|
||||||
{
|
{
|
||||||
// Subscribe to scene-dependent events - must be in OnManagedAwake, not OnSceneReady
|
// Subscribe to scene-dependent events - must be in OnManagedStart, not OnSceneReady
|
||||||
// because PauseMenu is in DontDestroyOnLoad and OnSceneReady only fires once
|
// because PauseMenu is in DontDestroyOnLoad and OnSceneReady only fires once
|
||||||
if (SceneManagerService.Instance != null)
|
if (SceneManagerService.Instance != null)
|
||||||
{
|
{
|
||||||
@@ -73,15 +68,13 @@ namespace UI
|
|||||||
Logging.Debug("[PauseMenu] Subscribed to SceneManagerService events");
|
Logging.Debug("[PauseMenu] Subscribed to SceneManagerService events");
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnSceneReady()
|
internal override void OnSceneReady()
|
||||||
{
|
{
|
||||||
// This only fires once for DontDestroyOnLoad objects, so we handle scene loads in OnManagedAwake
|
// This only fires once for DontDestroyOnLoad objects, so we handle scene loads in OnManagedAwake
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnDestroy()
|
internal override void OnManagedDestroy()
|
||||||
{
|
{
|
||||||
base.OnDestroy();
|
|
||||||
|
|
||||||
// Unsubscribe when destroyed
|
// Unsubscribe when destroyed
|
||||||
if (SceneManagerService.Instance != null)
|
if (SceneManagerService.Instance != null)
|
||||||
{
|
{
|
||||||
@@ -421,6 +414,7 @@ namespace UI
|
|||||||
{
|
{
|
||||||
SaveLoadManager.Instance.currentSaveData.participantStates.Clear();
|
SaveLoadManager.Instance.currentSaveData.participantStates.Clear();
|
||||||
SaveLoadManager.Instance.currentSaveData.unlockedMinigames.Clear();
|
SaveLoadManager.Instance.currentSaveData.unlockedMinigames.Clear();
|
||||||
|
SaveLoadManager.Instance.currentSaveData.playedDivingTutorial = false;
|
||||||
Logging.Debug("[PauseMenu] Cleared all save data from memory");
|
Logging.Debug("[PauseMenu] Cleared all save data from memory");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ using UnityEngine.Playables;
|
|||||||
using UnityEngine.UI;
|
using UnityEngine.UI;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System;
|
||||||
|
|
||||||
namespace UI
|
namespace UI
|
||||||
{
|
{
|
||||||
@@ -19,6 +20,73 @@ namespace UI
|
|||||||
{
|
{
|
||||||
public enum UIMode { Overworld, Puzzle, Minigame, HideAll };
|
public enum UIMode { Overworld, Puzzle, Minigame, HideAll };
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Context object for managing temporary HUD element visibility.
|
||||||
|
/// Automatically restores previous visibility state when disposed.
|
||||||
|
/// Usage: using (var ctx = PlayerHudManager.Instance.ShowElementTemporarily(myButton)) { ... }
|
||||||
|
/// </summary>
|
||||||
|
public class HudVisibilityContext : IDisposable
|
||||||
|
{
|
||||||
|
private readonly GameObject _element;
|
||||||
|
private readonly bool _previousState;
|
||||||
|
private bool _disposed;
|
||||||
|
|
||||||
|
internal HudVisibilityContext(GameObject element, bool show)
|
||||||
|
{
|
||||||
|
_element = element;
|
||||||
|
_previousState = element.activeSelf;
|
||||||
|
_element.SetActive(show);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
if (_disposed) return;
|
||||||
|
_disposed = true;
|
||||||
|
|
||||||
|
if (_element != null)
|
||||||
|
{
|
||||||
|
_element.SetActive(_previousState);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Multi-element visibility context for managing multiple HUD elements at once.
|
||||||
|
/// Automatically restores previous visibility states when disposed.
|
||||||
|
/// </summary>
|
||||||
|
public class MultiHudVisibilityContext : IDisposable
|
||||||
|
{
|
||||||
|
private readonly List<(GameObject element, bool previousState)> _elements;
|
||||||
|
private bool _disposed;
|
||||||
|
|
||||||
|
internal MultiHudVisibilityContext(IEnumerable<GameObject> elements, bool show)
|
||||||
|
{
|
||||||
|
_elements = new List<(GameObject, bool)>();
|
||||||
|
foreach (var element in elements)
|
||||||
|
{
|
||||||
|
if (element != null)
|
||||||
|
{
|
||||||
|
_elements.Add((element, element.activeSelf));
|
||||||
|
element.SetActive(show);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
if (_disposed) return;
|
||||||
|
_disposed = true;
|
||||||
|
|
||||||
|
foreach (var (element, previousState) in _elements)
|
||||||
|
{
|
||||||
|
if (element != null)
|
||||||
|
{
|
||||||
|
element.SetActive(previousState);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public UIMode currentUIMode;
|
public UIMode currentUIMode;
|
||||||
|
|
||||||
[Header("HUD Management")]
|
[Header("HUD Management")]
|
||||||
@@ -33,6 +101,7 @@ namespace UI
|
|||||||
[Header("HUD Elements")]
|
[Header("HUD Elements")]
|
||||||
public GameObject eagleEye;
|
public GameObject eagleEye;
|
||||||
public GameObject ramaSjangButton;
|
public GameObject ramaSjangButton;
|
||||||
|
public GameObject scrabBookButton;
|
||||||
|
|
||||||
[HideInInspector] public Image cinematicSprites;
|
[HideInInspector] public Image cinematicSprites;
|
||||||
[HideInInspector] public Image cinematicBackgroundSprites;
|
[HideInInspector] public Image cinematicBackgroundSprites;
|
||||||
@@ -46,14 +115,14 @@ namespace UI
|
|||||||
private UIPageController _uiPageController;
|
private UIPageController _uiPageController;
|
||||||
private AppSwitcher _appSwitcherComponent;
|
private AppSwitcher _appSwitcherComponent;
|
||||||
|
|
||||||
private new void Awake()
|
internal override void OnManagedAwake()
|
||||||
{
|
{
|
||||||
base.Awake();
|
|
||||||
if (Instance != null)
|
if (Instance != null)
|
||||||
{
|
{
|
||||||
Destroy(this);
|
Destroy(this);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
// Set instance immediately (early initialization)
|
||||||
_instance = this;
|
_instance = this;
|
||||||
|
|
||||||
// Get UIPageController on same GameObject
|
// Get UIPageController on same GameObject
|
||||||
@@ -66,7 +135,7 @@ namespace UI
|
|||||||
InitializeReferences();
|
InitializeReferences();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnManagedAwake()
|
internal override void OnManagedStart()
|
||||||
{
|
{
|
||||||
// Subscribe to UIPageController page changes for auto HUD management
|
// Subscribe to UIPageController page changes for auto HUD management
|
||||||
if (_uiPageController != null)
|
if (_uiPageController != null)
|
||||||
@@ -103,10 +172,8 @@ namespace UI
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnDestroy()
|
internal override void OnManagedDestroy()
|
||||||
{
|
{
|
||||||
base.OnDestroy();
|
|
||||||
|
|
||||||
// Unsubscribe from events
|
// Unsubscribe from events
|
||||||
if (_uiPageController != null)
|
if (_uiPageController != null)
|
||||||
{
|
{
|
||||||
@@ -254,6 +321,9 @@ namespace UI
|
|||||||
if (visible)
|
if (visible)
|
||||||
{
|
{
|
||||||
eagleEye.SetActive(false);
|
eagleEye.SetActive(false);
|
||||||
|
ramaSjangButton.SetActive(false);
|
||||||
|
scrabBookButton.SetActive(false);
|
||||||
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case UIMode.HideAll:
|
case UIMode.HideAll:
|
||||||
@@ -318,6 +388,64 @@ namespace UI
|
|||||||
UnityEngine.Debug.LogError("[PlayerHudManager] Cannot push page - UIPageController not found!");
|
UnityEngine.Debug.LogError("[PlayerHudManager] Cannot push page - UIPageController not found!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#region HUD Element Getters
|
||||||
|
|
||||||
|
public GameObject GetEagleEye() => eagleEye;
|
||||||
|
public GameObject GetRamaSjangButton() => ramaSjangButton;
|
||||||
|
public GameObject GetScrabookButton() => scrabBookButton;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Context-Based Visibility Management
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Temporarily shows a HUD element. Returns a context object that restores the previous state when disposed.
|
||||||
|
/// Usage: using (var ctx = PlayerHudManager.Instance.ShowElementTemporarily(myButton)) { /* element is visible */ }
|
||||||
|
/// </summary>
|
||||||
|
public HudVisibilityContext ShowElementTemporarily(GameObject element)
|
||||||
|
{
|
||||||
|
if (element == null)
|
||||||
|
{
|
||||||
|
Logging.Warning("[PlayerHudManager] Attempted to show null element");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return new HudVisibilityContext(element, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Temporarily hides a HUD element. Returns a context object that restores the previous state when disposed.
|
||||||
|
/// Usage: using (var ctx = PlayerHudManager.Instance.HideElementTemporarily(myButton)) { /* element is hidden */ }
|
||||||
|
/// </summary>
|
||||||
|
public HudVisibilityContext HideElementTemporarily(GameObject element)
|
||||||
|
{
|
||||||
|
if (element == null)
|
||||||
|
{
|
||||||
|
Logging.Warning("[PlayerHudManager] Attempted to hide null element");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return new HudVisibilityContext(element, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Temporarily shows multiple HUD elements. Returns a context object that restores all previous states when disposed.
|
||||||
|
/// Usage: using (var ctx = PlayerHudManager.Instance.ShowElementsTemporarily(button1, button2, button3)) { /* elements are visible */ }
|
||||||
|
/// </summary>
|
||||||
|
public MultiHudVisibilityContext ShowElementsTemporarily(params GameObject[] elements)
|
||||||
|
{
|
||||||
|
return new MultiHudVisibilityContext(elements, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Temporarily hides multiple HUD elements. Returns a context object that restores all previous states when disposed.
|
||||||
|
/// Usage: using (var ctx = PlayerHudManager.Instance.HideElementsTemporarily(button1, button2, button3)) { /* elements are hidden */ }
|
||||||
|
/// </summary>
|
||||||
|
public MultiHudVisibilityContext HideElementsTemporarily(params GameObject[] elements)
|
||||||
|
{
|
||||||
|
return new MultiHudVisibilityContext(elements, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,6 @@ public class ScrapbookController : MonoBehaviour
|
|||||||
|
|
||||||
public void DebugClick()
|
public void DebugClick()
|
||||||
{
|
{
|
||||||
// Debug.Log("Yey I was clicked!");
|
// Logging.Debug("Yey I was clicked!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ using Input;
|
|||||||
using Pixelplacement;
|
using Pixelplacement;
|
||||||
using UI.Core;
|
using UI.Core;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
using UnityEngine.Audio;
|
||||||
|
|
||||||
namespace UI.Tutorial
|
namespace UI.Tutorial
|
||||||
{
|
{
|
||||||
@@ -19,6 +20,8 @@ namespace UI.Tutorial
|
|||||||
|
|
||||||
private StateMachine _stateMachine;
|
private StateMachine _stateMachine;
|
||||||
public bool playTutorial;
|
public bool playTutorial;
|
||||||
|
public AudioSource bottleAudioPlayer;
|
||||||
|
public AudioResource introVO;
|
||||||
[SerializeField] private ProgressType progressType = ProgressType.Auto;
|
[SerializeField] private ProgressType progressType = ProgressType.Auto;
|
||||||
|
|
||||||
// gating for input until current state's animation finishes first loop
|
// gating for input until current state's animation finishes first loop
|
||||||
@@ -27,9 +30,8 @@ namespace UI.Tutorial
|
|||||||
private bool _canAcceptInput;
|
private bool _canAcceptInput;
|
||||||
private Coroutine _waitLoopCoroutine;
|
private Coroutine _waitLoopCoroutine;
|
||||||
|
|
||||||
public override int ManagedAwakePriority => 200; // Tutorial runs late, after other systems
|
|
||||||
|
|
||||||
protected override void OnManagedAwake()
|
internal override void OnManagedStart()
|
||||||
{
|
{
|
||||||
// Ensure prompt is hidden initially (even before tutorial initialization)
|
// Ensure prompt is hidden initially (even before tutorial initialization)
|
||||||
if (tapPrompt != null)
|
if (tapPrompt != null)
|
||||||
@@ -59,7 +61,7 @@ namespace UI.Tutorial
|
|||||||
|
|
||||||
void RemoveTutorial()
|
void RemoveTutorial()
|
||||||
{
|
{
|
||||||
Debug.Log("Remove me!");
|
Logging.Debug("Remove me!");
|
||||||
if (_waitLoopCoroutine != null)
|
if (_waitLoopCoroutine != null)
|
||||||
{
|
{
|
||||||
StopCoroutine(_waitLoopCoroutine);
|
StopCoroutine(_waitLoopCoroutine);
|
||||||
@@ -76,6 +78,8 @@ namespace UI.Tutorial
|
|||||||
tapPrompt.SetActive(false);
|
tapPrompt.SetActive(false);
|
||||||
|
|
||||||
Destroy(gameObject);
|
Destroy(gameObject);
|
||||||
|
bottleAudioPlayer.resource = introVO;
|
||||||
|
bottleAudioPlayer.Play();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnTap(Vector2 position)
|
public void OnTap(Vector2 position)
|
||||||
|
|||||||
@@ -101,7 +101,7 @@ namespace Utils
|
|||||||
}
|
}
|
||||||
catch (System.Exception ex)
|
catch (System.Exception ex)
|
||||||
{
|
{
|
||||||
Debug.LogWarning($"[AppleHillsUtils] Error checking addressable key existence: {ex.Message}");
|
Logging.Warning($"[AppleHillsUtils] Error checking addressable key existence: {ex.Message}");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
8
Assets/Settings/Build Profiles.meta
Normal file
8
Assets/Settings/Build Profiles.meta
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 53ec386bba82c1748886a5beb8468ecf
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
48
Assets/Settings/Build Profiles/iOS.asset
Normal file
48
Assets/Settings/Build Profiles/iOS.asset
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
%YAML 1.1
|
||||||
|
%TAG !u! tag:unity3d.com,2011:
|
||||||
|
--- !u!114 &11400000
|
||||||
|
MonoBehaviour:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 0}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: 15003, guid: 0000000000000000e000000000000000, type: 0}
|
||||||
|
m_Name: iOS
|
||||||
|
m_EditorClassIdentifier: UnityEditor.dll::UnityEditor.Build.Profile.BuildProfile
|
||||||
|
m_AssetVersion: 1
|
||||||
|
m_BuildTarget: 9
|
||||||
|
m_Subtarget: 0
|
||||||
|
m_PlatformId: ad48d16a66894befa4d8181998c3cb09
|
||||||
|
m_PlatformBuildProfile:
|
||||||
|
rid: 3475452038477774988
|
||||||
|
m_OverrideGlobalSceneList: 0
|
||||||
|
m_Scenes: []
|
||||||
|
m_ScriptingDefines: []
|
||||||
|
m_PlayerSettingsYaml:
|
||||||
|
m_Settings: []
|
||||||
|
references:
|
||||||
|
version: 2
|
||||||
|
RefIds:
|
||||||
|
- rid: 3475452038477774988
|
||||||
|
type: {class: iOSPlatformSettings, ns: UnityEditor.iOS, asm: UnityEditor.iOS.Extensions}
|
||||||
|
data:
|
||||||
|
m_Development: 0
|
||||||
|
m_ConnectProfiler: 0
|
||||||
|
m_BuildWithDeepProfilingSupport: 0
|
||||||
|
m_AllowDebugging: 0
|
||||||
|
m_WaitForManagedDebugger: 0
|
||||||
|
m_ManagedDebuggerFixedPort: 0
|
||||||
|
m_ExplicitNullChecks: 0
|
||||||
|
m_ExplicitDivideByZeroChecks: 0
|
||||||
|
m_ExplicitArrayBoundsChecks: 0
|
||||||
|
m_CompressionType: -1
|
||||||
|
m_InstallInBuildFolder: 0
|
||||||
|
m_InsightsSettingsContainer:
|
||||||
|
m_BuildProfileEngineDiagnosticsState: 2
|
||||||
|
m_iOSXcodeBuildConfig: 1
|
||||||
|
m_SymlinkSources: 0
|
||||||
|
m_PreferredXcode:
|
||||||
|
m_SymlinkTrampoline: 0
|
||||||
8
Assets/Settings/Build Profiles/iOS.asset.meta
Normal file
8
Assets/Settings/Build Profiles/iOS.asset.meta
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 110a4eabb37dbaa428e55c751696cd1e
|
||||||
|
NativeFormatImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
mainObjectFileID: 11400000
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
120
docs/custom_log_console.md
Normal file
120
docs/custom_log_console.md
Normal file
@@ -0,0 +1,120 @@
|
|||||||
|
# Custom Log Console
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
A centralized logging system with an advanced filtering console that automatically tags log entries with class and method names. Provides powerful filtering capabilities beyond Unity's default console, including multi-select filters, text search, time-range filtering, and log export.
|
||||||
|
|
||||||
|
## Using the Logging System in Code
|
||||||
|
|
||||||
|
All logging automatically captures the calling class and method name using `CallerMemberName` and `CallerFilePath` attributes. Simply call the static logging methods:
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
using Core;
|
||||||
|
|
||||||
|
public class MyClass : ManagedBehaviour
|
||||||
|
{
|
||||||
|
internal override void OnManagedStart()
|
||||||
|
{
|
||||||
|
Logging.Debug("Initialization complete");
|
||||||
|
Logging.Info("Player spawned at position");
|
||||||
|
Logging.Warning("Missing configuration, using defaults");
|
||||||
|
Logging.Error("Failed to load required asset");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Output format:**
|
||||||
|
```
|
||||||
|
[ClassName][MethodName] Your message
|
||||||
|
```
|
||||||
|
|
||||||
|
**Available methods:**
|
||||||
|
- `Logging.Debug(string message)` - Detailed diagnostic information
|
||||||
|
- `Logging.Info(string message)` - General informational messages
|
||||||
|
- `Logging.Warning(string message)` - Non-critical issues
|
||||||
|
- `Logging.Error(string message)` - Critical errors
|
||||||
|
|
||||||
|
**Note:** All logs are broadcast via the `Logging.OnLogEntryAdded` event and stored in a central buffer accessible via `Logging.GetRecentLogs()`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Opening the Console Window
|
||||||
|
|
||||||
|
**Menu:** `AppleHills > Custom Log Console`
|
||||||
|
|
||||||
|
You can open multiple independent console instances with different filter configurations to monitor separate systems simultaneously
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Console Interface
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
### Toolbar Controls
|
||||||
|
|
||||||
|
#### 🔵 Basic Controls (Blue outline)
|
||||||
|
- **Clear** - Clears all log entries and resets tag lists
|
||||||
|
- **Auto-scroll** - Automatically scrolls to newest entries when enabled
|
||||||
|
|
||||||
|
#### Filter Buttons (Persistent Popups)
|
||||||
|
|
||||||
|
All filter buttons open persistent popup windows that remain open during multi-selection. Changes apply when you click "Apply" or dismiss with "Close".
|
||||||
|
|
||||||
|
- **🔴 Classes Filter (Red outline)**
|
||||||
|
- Multi-select which classes to display
|
||||||
|
- Includes search box for quick filtering
|
||||||
|
- All/None quick actions
|
||||||
|
|
||||||
|
- **🟢 Methods Filter (Green outline)**
|
||||||
|
- Multi-select which methods to display
|
||||||
|
- Includes search box for quick filtering
|
||||||
|
- All/None quick actions
|
||||||
|
|
||||||
|
- **🟡 Levels Filter (Yellow outline)**
|
||||||
|
- Toggle Debug, Info, Warning, Error levels
|
||||||
|
- All/None quick actions
|
||||||
|
|
||||||
|
- **⏱ Time Filter**
|
||||||
|
- Opens utility window with MinMaxSlider
|
||||||
|
- Filter logs by timestamp range
|
||||||
|
- Enable/disable toggle with reset option
|
||||||
|
|
||||||
|
#### Search & Export
|
||||||
|
- **Search** - Full-text search across class names, method names, and message content
|
||||||
|
- **Export** - Save filtered logs to .txt file with timestamp
|
||||||
|
- **Count** - Shows `filtered/total` log count
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Visual Indicators
|
||||||
|
|
||||||
|
**Color Coding:**
|
||||||
|
- White: Debug/Info (normal operation)
|
||||||
|
- Yellow: Warning (non-critical issues)
|
||||||
|
- Red: Error (critical failures)
|
||||||
|
|
||||||
|
**Alternating Rows:** Light/dark grey backgrounds improve readability for dense log output.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Technical Details
|
||||||
|
|
||||||
|
**Event Broadcasting:**
|
||||||
|
```csharp
|
||||||
|
Logging.OnLogEntryAdded += (LogEntry entry) => { /* handle */ };
|
||||||
|
```
|
||||||
|
|
||||||
|
**Manual Log Retrieval:**
|
||||||
|
```csharp
|
||||||
|
List<LogEntry> recentLogs = Logging.GetRecentLogs();
|
||||||
|
```
|
||||||
|
|
||||||
|
**LogEntry Structure:**
|
||||||
|
- `ClassName` - Captured from calling file path
|
||||||
|
- `MethodName` - Captured from `CallerMemberName`
|
||||||
|
- `Message` - User-provided message text
|
||||||
|
- `Level` - Debug/Info/Warning/Error enum
|
||||||
|
- `Timestamp` - Time.realtimeSinceStartup
|
||||||
|
- `FullFormattedMessage` - Complete formatted string
|
||||||
|
|
||||||
|
---
|
||||||
93
docs/managed_behavior/architecture_overview.md
Normal file
93
docs/managed_behavior/architecture_overview.md
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
# ManagedBehaviour System - Architecture Overview
|
||||||
|
|
||||||
|
**Version:** 2.0 <br>
|
||||||
|
**Updated:** 11.11.2025
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## What is the ManagedBehaviour System?
|
||||||
|
|
||||||
|
Lifecycle orchestration framework that provides guaranteed execution order and deterministic lifecycle management for Unity components.
|
||||||
|
|
||||||
|
### Problems Solved
|
||||||
|
|
||||||
|
We've had quite a few things shoe-stringed together in various ways and dependant on references to each other.
|
||||||
|
Due to undefined initialization order - null references during access to yet uninitialized resources was becoming a problem.
|
||||||
|
|
||||||
|
### What You Get
|
||||||
|
|
||||||
|
- **Guaranteed Initialization Order** - Managers ready before components that depend on them
|
||||||
|
- **Deterministic Lifecycle Hooks** - Predictable callbacks at key moments
|
||||||
|
- **Automatic Registration** - No boilerplate for wiring up systems
|
||||||
|
- **Scene Lifecycle Events** - Built-in hooks for scene load/unload
|
||||||
|
- **Save/Load Coordination** - Centralized collection of save data
|
||||||
|
- **Bootstrap Integration** - Components know when bootstrap completes
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Architecture Principles
|
||||||
|
|
||||||
|
### 1. Centralized Orchestration
|
||||||
|
|
||||||
|
Single `LifecycleManager` singleton coordinates all lifecycle events. Components auto-register and receive callbacks at appropriate times.
|
||||||
|
|
||||||
|
### 2. Sealed Framework Methods
|
||||||
|
|
||||||
|
`Awake()` and `OnDestroy()` are sealed. Use `OnManagedAwake()` and `OnManagedDestroy()` instead. Prevents forgetting to call `base.Awake()`.
|
||||||
|
|
||||||
|
### 3. Two-Phase Initialization
|
||||||
|
|
||||||
|
- **Early (`OnManagedAwake()`)**: During Unity's Awake, before bootstrap. Use for singleton setup.
|
||||||
|
- **Late (`OnManagedStart()`)**: After bootstrap completes. All managers guaranteed ready.
|
||||||
|
|
||||||
|
### 4. Registration Order Execution
|
||||||
|
|
||||||
|
Execution follows Unity's natural Awake order. No priority numbers to manage.
|
||||||
|
|
||||||
|
### 5. Automatic Cleanup
|
||||||
|
|
||||||
|
Framework handles unregistration automatically. Override `OnManagedDestroy()` only if you need custom cleanup.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Lifecycle Flow Diagrams
|
||||||
|
|
||||||
|
### Boot Sequence
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
### Scene Transition Flow
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
### Component Lifecycle (Individual Component)
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Class Diagram
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
---
|
||||||
|
## Key Guarantees
|
||||||
|
|
||||||
|
### Guaranteed
|
||||||
|
|
||||||
|
1. **Bootstrap Completion** - `OnManagedStart()` always fires after bootstrap completes
|
||||||
|
2. **Manager Availability** - All manager singletons exist when `OnManagedStart()` is called
|
||||||
|
3. **Scene Lifecycle** - `OnSceneReady()` fires after scene load, `OnSceneUnloading()` before unload
|
||||||
|
4. **Automatic Registration** - Can't forget to register (Awake is sealed)
|
||||||
|
5. **Automatic Cleanup** - Can't forget to unregister (OnDestroy is sealed)
|
||||||
|
6. **Save/Load Coordination** - All save participants called in one pass
|
||||||
|
|
||||||
|
### Not Guaranteed
|
||||||
|
|
||||||
|
1. **Initialization Order Between Components** - `OnManagedAwake()` follows Unity's unpredictable Awake order
|
||||||
|
2. **Thread Safety** - All methods must run on main thread
|
||||||
|
3. **Performance** - Broadcasting to 1000+ components may have overhead
|
||||||
|
4. **SaveId Uniqueness** - Developer responsible for unique SaveIds
|
||||||
|
|
||||||
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user