fr.jeanf.universal.player 0.8.40 → 0.8.43
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -3,86 +3,227 @@ using System.Collections.Generic;
|
|
|
3
3
|
using jeanf.EventSystem;
|
|
4
4
|
using UnityEngine;
|
|
5
5
|
|
|
6
|
-
public class FunctionTimer
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
6
|
+
public class FunctionTimer
|
|
7
|
+
{
|
|
8
|
+
private static List<FunctionTimer> activeTimerList;
|
|
9
|
+
private static MonoBehaviourHook timerManager;
|
|
10
|
+
|
|
11
|
+
private static Stack<FunctionTimer> timerPool = new Stack<FunctionTimer>(32);
|
|
12
|
+
private const int INITIAL_POOL_SIZE = 16;
|
|
13
|
+
|
|
14
|
+
private static void InitIfNeeded()
|
|
15
|
+
{
|
|
16
|
+
if (timerManager == null)
|
|
17
|
+
{
|
|
18
|
+
GameObject initGameObject = new GameObject("FunctionTimer_Manager");
|
|
19
|
+
UnityEngine.Object.DontDestroyOnLoad(initGameObject);
|
|
20
|
+
|
|
21
|
+
timerManager = initGameObject.AddComponent<MonoBehaviourHook>();
|
|
22
|
+
activeTimerList = new List<FunctionTimer>(32);
|
|
23
|
+
|
|
24
|
+
for (int i = 0; i < INITIAL_POOL_SIZE; i++)
|
|
25
|
+
{
|
|
26
|
+
timerPool.Push(new FunctionTimer());
|
|
14
27
|
}
|
|
15
28
|
}
|
|
29
|
+
}
|
|
16
30
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
31
|
+
private static FunctionTimer GetFromPool()
|
|
32
|
+
{
|
|
33
|
+
if (timerPool.Count > 0)
|
|
34
|
+
{
|
|
35
|
+
return timerPool.Pop();
|
|
36
|
+
}
|
|
37
|
+
return new FunctionTimer();
|
|
38
|
+
}
|
|
20
39
|
|
|
21
|
-
|
|
40
|
+
private static void ReturnToPool(FunctionTimer timer)
|
|
41
|
+
{
|
|
42
|
+
timer.Reset();
|
|
43
|
+
timerPool.Push(timer);
|
|
44
|
+
}
|
|
22
45
|
|
|
23
|
-
|
|
46
|
+
public static FunctionTimer Create(Action action, float timer, string timerName = null)
|
|
47
|
+
{
|
|
48
|
+
InitIfNeeded();
|
|
49
|
+
|
|
50
|
+
FunctionTimer functionTimer = GetFromPool();
|
|
51
|
+
functionTimer.Initialize(action, timer, timerName);
|
|
24
52
|
|
|
25
|
-
|
|
53
|
+
activeTimerList.Add(functionTimer);
|
|
26
54
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
private static void RemoveTimer(FunctionTimer functionTimer) {
|
|
30
|
-
InitIfNeeded();
|
|
31
|
-
activeTimerList.Remove(functionTimer);
|
|
32
|
-
}
|
|
55
|
+
return functionTimer;
|
|
56
|
+
}
|
|
33
57
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
58
|
+
private static void RemoveTimer(FunctionTimer functionTimer)
|
|
59
|
+
{
|
|
60
|
+
if (activeTimerList == null) return;
|
|
61
|
+
|
|
62
|
+
activeTimerList.Remove(functionTimer);
|
|
63
|
+
|
|
64
|
+
ReturnToPool(functionTimer);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
public static void StopTimer(string timerName)
|
|
68
|
+
{
|
|
69
|
+
if (activeTimerList == null || timerName == null) return;
|
|
70
|
+
|
|
71
|
+
for (int i = activeTimerList.Count - 1; i >= 0; i--)
|
|
72
|
+
{
|
|
73
|
+
if (activeTimerList[i].timerName == timerName)
|
|
38
74
|
{
|
|
39
|
-
if (activeTimerList[i].timerName != timerName) continue;
|
|
40
|
-
// Stop this timer
|
|
41
75
|
activeTimerList[i].DestroySelf();
|
|
42
|
-
i--;
|
|
43
76
|
}
|
|
44
77
|
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
private static void CleanupDestroyedTimers()
|
|
81
|
+
{
|
|
82
|
+
if (activeTimerList == null) return;
|
|
83
|
+
|
|
84
|
+
activeTimerList.RemoveAll(t => t.isDestroyed);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
public static void StopAllTimers()
|
|
88
|
+
{
|
|
89
|
+
if (activeTimerList == null) return;
|
|
90
|
+
|
|
91
|
+
for (int i = activeTimerList.Count - 1; i >= 0; i--)
|
|
92
|
+
{
|
|
93
|
+
activeTimerList[i].DestroySelf();
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
activeTimerList.Clear();
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
private class MonoBehaviourHook : MonoBehaviour
|
|
100
|
+
{
|
|
101
|
+
private int frameCounter = 0;
|
|
102
|
+
private const int CLEANUP_INTERVAL = 60;
|
|
45
103
|
|
|
104
|
+
private void Update()
|
|
105
|
+
{
|
|
106
|
+
if (activeTimerList == null || activeTimerList.Count == 0) return;
|
|
46
107
|
|
|
108
|
+
float deltaTime = Time.deltaTime;
|
|
47
109
|
|
|
48
|
-
|
|
49
|
-
private class MonoBehaviourHook : MonoBehaviour {
|
|
50
|
-
public Action onUpdate;
|
|
51
|
-
private void Update()
|
|
110
|
+
for (int i = activeTimerList.Count - 1; i >= 0; i--)
|
|
52
111
|
{
|
|
53
|
-
|
|
112
|
+
if (i >= activeTimerList.Count) continue;
|
|
113
|
+
|
|
114
|
+
FunctionTimer timer = activeTimerList[i];
|
|
115
|
+
|
|
116
|
+
if (timer.isDestroyed) continue;
|
|
117
|
+
|
|
118
|
+
timer.timer -= deltaTime;
|
|
119
|
+
|
|
120
|
+
if (timer.timer <= 0f)
|
|
121
|
+
{
|
|
122
|
+
try
|
|
123
|
+
{
|
|
124
|
+
timer.action?.Invoke();
|
|
125
|
+
}
|
|
126
|
+
catch (Exception e)
|
|
127
|
+
{
|
|
128
|
+
Debug.LogError($"[FunctionTimer] Error in timer '{timer.timerName}': {e.Message}");
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
timer.DestroySelf();
|
|
132
|
+
}
|
|
54
133
|
}
|
|
55
134
|
}
|
|
56
135
|
|
|
57
|
-
private
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
136
|
+
private void OnDestroy()
|
|
137
|
+
{
|
|
138
|
+
StopAllTimers();
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
private Action action;
|
|
143
|
+
private float timer;
|
|
144
|
+
private string timerName;
|
|
145
|
+
private bool isDestroyed;
|
|
146
|
+
private FloatEventChannelSO validationChannel;
|
|
147
|
+
private float remainingTime;
|
|
148
|
+
|
|
149
|
+
private FunctionTimer()
|
|
150
|
+
{
|
|
151
|
+
isDestroyed = true;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
private void Initialize(Action action, float timer, string timerName)
|
|
155
|
+
{
|
|
156
|
+
this.action = action;
|
|
157
|
+
this.timer = timer;
|
|
158
|
+
this.timerName = timerName;
|
|
159
|
+
this.isDestroyed = false;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
private void Reset()
|
|
163
|
+
{
|
|
164
|
+
this.action = null;
|
|
165
|
+
this.timer = 0f;
|
|
166
|
+
this.timerName = null;
|
|
167
|
+
this.isDestroyed = true;
|
|
168
|
+
this.validationChannel = null;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
private void DestroySelf()
|
|
172
|
+
{
|
|
173
|
+
if (isDestroyed) return;
|
|
174
|
+
|
|
175
|
+
isDestroyed = true;
|
|
176
|
+
|
|
177
|
+
RemoveTimer(this);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
public float RemainingTime => isDestroyed ? 0f : timer;
|
|
181
|
+
public bool IsActive => !isDestroyed;
|
|
182
|
+
public string Name => timerName;
|
|
183
|
+
|
|
184
|
+
public void AddTime(float additionalTime)
|
|
185
|
+
{
|
|
186
|
+
if (!isDestroyed)
|
|
187
|
+
{
|
|
188
|
+
timer += additionalTime;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
public void SetTime(float newTime)
|
|
193
|
+
{
|
|
194
|
+
if (!isDestroyed)
|
|
195
|
+
{
|
|
196
|
+
timer = newTime;
|
|
71
197
|
}
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
#if UNITY_EDITOR
|
|
202
|
+
public static class FunctionTimerDebug
|
|
203
|
+
{
|
|
204
|
+
[UnityEditor.MenuItem("Tools/Function Timer/Show Active Timers")]
|
|
205
|
+
private static void ShowActiveTimers()
|
|
206
|
+
{
|
|
207
|
+
var timers = typeof(FunctionTimer)
|
|
208
|
+
.GetField("activeTimerList", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic)
|
|
209
|
+
?.GetValue(null) as List<FunctionTimer>;
|
|
72
210
|
|
|
73
|
-
|
|
211
|
+
if (timers == null || timers.Count == 0)
|
|
74
212
|
{
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
if (!(timer < 0)) return;
|
|
78
|
-
// Trigger the action
|
|
79
|
-
action();
|
|
80
|
-
DestroySelf();
|
|
213
|
+
Debug.Log("[FunctionTimer] No active timers");
|
|
214
|
+
return;
|
|
81
215
|
}
|
|
82
216
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
RemoveTimer(this);
|
|
217
|
+
for (int i = 0; i < timers.Count; i++)
|
|
218
|
+
{
|
|
219
|
+
var timer = timers[i];
|
|
87
220
|
}
|
|
88
221
|
}
|
|
222
|
+
|
|
223
|
+
[UnityEditor.MenuItem("Tools/Function Timer/Stop All Timers")]
|
|
224
|
+
private static void StopAllTimersMenu()
|
|
225
|
+
{
|
|
226
|
+
FunctionTimer.StopAllTimers();
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
#endif
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
using System;
|
|
2
|
+
using UnityEngine;
|
|
3
|
+
using System.Collections.Generic;
|
|
4
|
+
using System.Reflection;
|
|
5
|
+
|
|
6
|
+
/// <summary>
|
|
7
|
+
/// Script helper pour débugger les problèmes de FunctionTimer
|
|
8
|
+
/// Attache ce script à un GameObject dans ta scène pour voir les timers actifs
|
|
9
|
+
/// </summary>
|
|
10
|
+
public class FunctionTimerDebugger : MonoBehaviour
|
|
11
|
+
{
|
|
12
|
+
[Header("Debug Settings")]
|
|
13
|
+
[SerializeField] private bool showDebugLogs = true;
|
|
14
|
+
[SerializeField] private bool showGuiOverlay = true;
|
|
15
|
+
[SerializeField] private float updateInterval = 0.5f;
|
|
16
|
+
|
|
17
|
+
private float nextUpdateTime;
|
|
18
|
+
private List<TimerInfo> cachedTimerInfos = new List<TimerInfo>();
|
|
19
|
+
|
|
20
|
+
private struct TimerInfo
|
|
21
|
+
{
|
|
22
|
+
public string name;
|
|
23
|
+
public float remainingTime;
|
|
24
|
+
public bool isActive;
|
|
25
|
+
public bool isDestroyed;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
private void Update()
|
|
29
|
+
{
|
|
30
|
+
if (Time.time >= nextUpdateTime)
|
|
31
|
+
{
|
|
32
|
+
nextUpdateTime = Time.time + updateInterval;
|
|
33
|
+
UpdateTimerInfos();
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
private void UpdateTimerInfos()
|
|
38
|
+
{
|
|
39
|
+
cachedTimerInfos.Clear();
|
|
40
|
+
|
|
41
|
+
// Utiliser reflection pour accéder à la liste privée
|
|
42
|
+
var activeTimerListField = typeof(FunctionTimer).GetField("activeTimerList",
|
|
43
|
+
BindingFlags.Static | BindingFlags.NonPublic);
|
|
44
|
+
|
|
45
|
+
if (activeTimerListField == null)
|
|
46
|
+
{
|
|
47
|
+
if (showDebugLogs)
|
|
48
|
+
Debug.LogWarning("[FunctionTimerDebugger] Cannot access activeTimerList");
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
var activeTimers = activeTimerListField.GetValue(null) as List<FunctionTimer>;
|
|
53
|
+
|
|
54
|
+
if (activeTimers == null)
|
|
55
|
+
{
|
|
56
|
+
if (showDebugLogs)
|
|
57
|
+
Debug.Log("[FunctionTimerDebugger] No timer list initialized");
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (showDebugLogs)
|
|
62
|
+
Debug.Log($"[FunctionTimerDebugger] Active timers count: {activeTimers.Count}");
|
|
63
|
+
|
|
64
|
+
// Récupérer les infos de chaque timer
|
|
65
|
+
for (int i = 0; i < activeTimers.Count; i++)
|
|
66
|
+
{
|
|
67
|
+
var timer = activeTimers[i];
|
|
68
|
+
|
|
69
|
+
var info = new TimerInfo
|
|
70
|
+
{
|
|
71
|
+
name = GetTimerName(timer),
|
|
72
|
+
remainingTime = GetRemainingTime(timer),
|
|
73
|
+
isActive = GetIsActive(timer),
|
|
74
|
+
isDestroyed = GetIsDestroyed(timer)
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
cachedTimerInfos.Add(info);
|
|
78
|
+
|
|
79
|
+
if (showDebugLogs)
|
|
80
|
+
{
|
|
81
|
+
Debug.Log($" Timer [{i}]: Name='{info.name}', " +
|
|
82
|
+
$"Remaining={info.remainingTime:F2}s, " +
|
|
83
|
+
$"Active={info.isActive}, " +
|
|
84
|
+
$"Destroyed={info.isDestroyed}");
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
private string GetTimerName(FunctionTimer timer)
|
|
90
|
+
{
|
|
91
|
+
var field = typeof(FunctionTimer).GetField("timerName",
|
|
92
|
+
BindingFlags.Instance | BindingFlags.NonPublic);
|
|
93
|
+
return (field?.GetValue(timer) as string) ?? "unnamed";
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
private float GetRemainingTime(FunctionTimer timer)
|
|
97
|
+
{
|
|
98
|
+
var field = typeof(FunctionTimer).GetField("timer",
|
|
99
|
+
BindingFlags.Instance | BindingFlags.NonPublic);
|
|
100
|
+
return field != null ? (float)field.GetValue(timer) : 0f;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
private bool GetIsActive(FunctionTimer timer)
|
|
104
|
+
{
|
|
105
|
+
var prop = typeof(FunctionTimer).GetProperty("IsActive");
|
|
106
|
+
return prop != null ? (bool)prop.GetValue(timer) : false;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
private bool GetIsDestroyed(FunctionTimer timer)
|
|
110
|
+
{
|
|
111
|
+
var field = typeof(FunctionTimer).GetField("isDestroyed",
|
|
112
|
+
BindingFlags.Instance | BindingFlags.NonPublic);
|
|
113
|
+
return field != null ? (bool)field.GetValue(timer) : true;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
private void OnGUI()
|
|
117
|
+
{
|
|
118
|
+
if (!showGuiOverlay) return;
|
|
119
|
+
|
|
120
|
+
GUILayout.BeginArea(new Rect(10, 10, 400, Screen.height - 20));
|
|
121
|
+
GUILayout.BeginVertical("box");
|
|
122
|
+
|
|
123
|
+
GUILayout.Label($"<b>FunctionTimer Debug</b> ({cachedTimerInfos.Count} timers)",
|
|
124
|
+
new GUIStyle(GUI.skin.label) { richText = true, fontSize = 14 });
|
|
125
|
+
|
|
126
|
+
GUILayout.Space(10);
|
|
127
|
+
|
|
128
|
+
if (cachedTimerInfos.Count == 0)
|
|
129
|
+
{
|
|
130
|
+
GUILayout.Label("No active timers");
|
|
131
|
+
}
|
|
132
|
+
else
|
|
133
|
+
{
|
|
134
|
+
for (int i = 0; i < cachedTimerInfos.Count; i++)
|
|
135
|
+
{
|
|
136
|
+
var info = cachedTimerInfos[i];
|
|
137
|
+
|
|
138
|
+
Color color = info.isDestroyed ? Color.red :
|
|
139
|
+
info.isActive ? Color.green : Color.yellow;
|
|
140
|
+
|
|
141
|
+
GUI.color = color;
|
|
142
|
+
GUILayout.Label($"[{i}] {info.name}: {info.remainingTime:F2}s " +
|
|
143
|
+
$"(Active: {info.isActive}, Destroyed: {info.isDestroyed})");
|
|
144
|
+
GUI.color = Color.white;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
GUILayout.Space(10);
|
|
149
|
+
|
|
150
|
+
if (GUILayout.Button("Refresh Now"))
|
|
151
|
+
{
|
|
152
|
+
UpdateTimerInfos();
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
if (GUILayout.Button("Stop All Timers"))
|
|
156
|
+
{
|
|
157
|
+
FunctionTimer.StopAllTimers();
|
|
158
|
+
UpdateTimerInfos();
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
GUILayout.EndVertical();
|
|
162
|
+
GUILayout.EndArea();
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/// <summary>
|
|
167
|
+
/// Extension pour faciliter le debug dans ton code
|
|
168
|
+
/// </summary>
|
|
169
|
+
public static class FunctionTimerDebugExtensions
|
|
170
|
+
{
|
|
171
|
+
/// <summary>
|
|
172
|
+
/// Crée un timer avec logging automatique
|
|
173
|
+
/// </summary>
|
|
174
|
+
public static FunctionTimer CreateDebug(Action action, float time, string name, GameObject caller = null)
|
|
175
|
+
{
|
|
176
|
+
string callerName = caller != null ? caller.name : "Unknown";
|
|
177
|
+
string fullName = $"{name} (from {callerName})";
|
|
178
|
+
|
|
179
|
+
Debug.Log($"[FunctionTimer] Creating timer '{fullName}' for {time}s");
|
|
180
|
+
|
|
181
|
+
return FunctionTimer.Create(() =>
|
|
182
|
+
{
|
|
183
|
+
Debug.Log($"[FunctionTimer] Timer '{fullName}' completed!");
|
|
184
|
+
action?.Invoke();
|
|
185
|
+
}, time, fullName);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/// <summary>
|
|
189
|
+
/// Stop avec logging
|
|
190
|
+
/// </summary>
|
|
191
|
+
public static void StopTimerDebug(string timerName)
|
|
192
|
+
{
|
|
193
|
+
Debug.Log($"[FunctionTimer] Stopping timer '{timerName}'");
|
|
194
|
+
FunctionTimer.StopTimer(timerName);
|
|
195
|
+
}
|
|
196
|
+
}
|