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
- private static List<FunctionTimer> activeTimerList;
8
- private static GameObject initGameObject;
9
-
10
- private static void InitIfNeeded() {
11
- if (initGameObject == null) {
12
- initGameObject = new GameObject("FunctionTimer_InitGameObject");
13
- activeTimerList = new List<FunctionTimer>();
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
- public static FunctionTimer Create(Action action, float timer, string timerName = null) {
18
- InitIfNeeded();
19
- GameObject gameObject = new GameObject("FunctionTimer", typeof(MonoBehaviourHook));
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
- FunctionTimer functionTimer = new FunctionTimer(action, timer, timerName, gameObject);
40
+ private static void ReturnToPool(FunctionTimer timer)
41
+ {
42
+ timer.Reset();
43
+ timerPool.Push(timer);
44
+ }
22
45
 
23
- gameObject.GetComponent<MonoBehaviourHook>().onUpdate = functionTimer.Update;
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
- activeTimerList.Add(functionTimer);
53
+ activeTimerList.Add(functionTimer);
26
54
 
27
- return functionTimer;
28
- }
29
- private static void RemoveTimer(FunctionTimer functionTimer) {
30
- InitIfNeeded();
31
- activeTimerList.Remove(functionTimer);
32
- }
55
+ return functionTimer;
56
+ }
33
57
 
34
- public static void StopTimer(string timerName) {
35
- if (activeTimerList == null || timerName == null) return;
36
-
37
- for (var i = 0; i < activeTimerList.Count; i++)
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
- // Dummy class to have access to MonoBehaviour functions
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
- onUpdate?.Invoke();
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 Action action;
58
- private float timer;
59
- private string timerName;
60
- private GameObject gameObject;
61
- private bool isDestroyed;
62
- private FloatEventChannelSO validationChannel;
63
- private float remainingTime;
64
-
65
- private FunctionTimer(Action action, float timer, string timerName, GameObject gameObject) {
66
- this.action = action;
67
- this.timer = timer;
68
- this.timerName = timerName;
69
- this.gameObject = gameObject;
70
- isDestroyed = false;
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
- public void Update()
211
+ if (timers == null || timers.Count == 0)
74
212
  {
75
- if (isDestroyed) return;
76
- timer -= Time.deltaTime;
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
- private void DestroySelf() {
84
- isDestroyed = true;
85
- UnityEngine.Object.Destroy(gameObject);
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
+ }
@@ -0,0 +1,2 @@
1
+ fileFormatVersion: 2
2
+ guid: 2f4a669bdeaf85342bcd6d482ec109d8
@@ -55,6 +55,7 @@ namespace jeanf.universalplayer
55
55
  activeControlScheme.RaiseEvent();
56
56
  break;
57
57
  case "XR":
58
+ playerInput.neverAutoSwitchControlSchemes = true;
58
59
  controlScheme = ControlScheme.XR;
59
60
  activeControlScheme.RaiseEvent();
60
61
  break;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "fr.jeanf.universal.player",
3
3
 
4
- "version": "0.8.40",
4
+ "version": "0.8.43",
5
5
 
6
6
  "displayName": "Universal Player",
7
7
  "description": "This package contains a universal player working in URP & HDRP for Mouse+Keyboard or VR",