1using System.Diagnostics;
2using System.Numerics;
3using System.Reflection;
4using Fjord.Graphics;
5using Fjord.Input;
6using Fjord.Scenes;
7using Fjord.Ui;
8using static Fjord.Helpers;
9using static SDL2.SDL;
10
11namespace Fjord.Scenes;
12
13public class Export : Attribute
14{
15 public float sliderMin = 0;
16 public float sliderMax = 200;
17
18 public Export(float min, float max) {
19 this.sliderMin = min;
20 this.sliderMax = max;
21 }
22
23 public Export() {
24
25 }
26}
27
28public struct DebugLog
29{
30 public string time;
31 public string sender;
32 public string message;
33 public LogLevel level;
34 public int repeat;
35 public bool hideInfo;
36
37 public override bool Equals(object? obj)
38 {
39 return obj is DebugLog log &&
40 sender == log.sender &&
41 message == log.message &&
42 level == log.level &&
43 hideInfo == log.hideInfo;
44 }
45
46 public override int GetHashCode()
47 {
48 return HashCode.Combine(time, sender, message, level, repeat, hideInfo);
49 }
50}
51
52public enum LogLevel
53{
54 User,
55 Message,
56 Warning,
57 Error,
58}
59
60public static class Debug {
61
62 public static List<DebugLog> Logs = new List<DebugLog>();
63
64
65 public static Dictionary<string, Action<object[]>> commands = new Dictionary<string, Action<object[]>>();
66
67 public static void RegisterCommand(string id, Action<object[]> callback) {
68 if (commands.ContainsKey(id))
69 {
70 commands.Remove(id);
71 }
72 commands.Add(id, callback);
73 }
74 public static void RegisterCommand(string[] ids, Action<object[]> callback)
75 {
76 foreach (string id in ids)
77 RegisterCommand(id, callback);
78 }
79
80 public static void Initialize()
81 {
82 SceneHandler.Register(new InspectorScene((int)(Game.Window.Width * 0.201), 1080)
83 .SetAllowWindowResize(false)
84 .SetAlwaysRebuildTexture(true)
85 .SetRelativeWindowSize(0.8f, 0f, 1.0001f, 1f));
86
87 SceneHandler.Register(new ConsoleScene((int)(Game.Window.Width * 0.2), (int)(Game.Window.Height * 0.4))
88 .SetAllowWindowResize(true)
89 .SetRelativeWindowSize(0.1f, 0.1f, 0.4f, 0.6f)
90 .SetAlwaysRebuildTexture(true));
91
92 SceneHandler.Register(new PerformanceScene((int)(Game.Window.Width * 0.2), (int)(Game.Window.Height * 0.4))
93 .SetRelativeWindowSize(0f, 0.89f, 0.10f, 1.001f)
94 .SetAlwaysRebuildTexture(true));
95
96 SceneHandler.Register(new NotificationScene(0, 0)
97 .SetRelativeWindowSize(0f, 0f, 0.5f, 1.001f)
98 .SetAlwaysRebuildTexture(true));
99 SceneHandler.Load<NotificationScene>();
100
101 //SceneHandler.Load("Performance");
102 // SceneHandler.Load("Console");
103 // SceneHandler.Load("Inspector");
104
105 RegisterCommand("clear", (args) =>
106 {
107 Logs = new();
108 });
109
110 RegisterCommand("showfps", (args) =>
111 {
112 if (args.Length < 1)
113 {
114 Debug.Log(SceneHandler.IsLoaded<PerformanceScene>());
115 return;
116 }
117
118 if (args[0].GetType() != typeof(bool))
119 {
120 Debug.Log("Argument 1 is not of type bool");
121 return;
122 }
123
124 if ((bool)args[0])
125 {
126 SceneHandler.Load<PerformanceScene>();
127 }
128 else
129 {
130 SceneHandler.Unload<PerformanceScene>();
131 }
132 });
133
134 RegisterCommand("maxfps", (args) => {
135 if(args.Length > 0) {
136 if(args[0].GetType() == typeof(float)) {
137 Debug.Log(args[0].GetType());
138 Game.FPSMax = (double)((float)args[0]);
139 } else {
140 Debug.Log(LogLevel.Warning, $"Argument must be number");
141 }
142 } else {
143 Debug.Log(LogLevel.Error, $"No argument provided");
144 }
145 });
146
147
148 RegisterCommand("commands", (args) => {
149 foreach(string command in commands.Keys.ToList())
150 {
151 Debug.Log(command);
152 }
153 });
154
155 RegisterCommand(new string[3] { "q", "quit", "exit" }, (args) =>
156 {
157 Game.Stop();
158 });
159
160 RegisterCommand("debug_selectscene", (args) => {
161 if(args.Length > 0) {
162 if(SceneHandler.Scenes.ContainsKey((string)args[0])) {
163 SceneHandler.Get<InspectorScene>().SelectedScene = (string)args[0];
164 Debug.Log(LogLevel.Message, $"{(string)args[0]} is now selected");
165 } else {
166 Debug.Log(LogLevel.Warning, $"No scene named {(string)args[0]}");
167 }
168 } else {
169 Debug.Log(LogLevel.Error, $"No argument provided");
170 }
171 });
172 }
173
174 public static void SendNotification(string message)
175 {
176 SceneHandler.Get<NotificationScene>().Notifications.Add(new(message, 100));
177 }
178
179 public static SDL_FRect DebugWindowOffset = new()
180 {
181 x = 0f,
182 y = 0f,
183 w = 0.2f,
184 h = 0f
185 };
186
187 public static void Log(object message)
188 {
189 Log(LogLevel.Message, message);
190 }
191
192 public static void Log(LogLevel level, object message)
193 {
194 var words = message.ToString()?.Split();
195 // List<string> messageSplit = message.ToString().SplitInParts(60).ToList();
196
197 if(level == LogLevel.Error)
198 {
199 SendNotification(message.ToString()!);
200 }
201
202 var lines = new List<string> { words![0] };
203 var lineNum = 0;
204 for(int i = 1; i < words.Length; i++)
205 {
206 if(lines[lineNum].Length + words[i].Length + 1 <= 120)
207 lines[lineNum] += " " + words[i];
208 else
209 {
210 lines.Add(words[i]);
211 lineNum++;
212 }
213 }
214
215 StackTrace stackTrace = new StackTrace();
216 StackFrame? stackFrame = stackTrace.GetFrame(1);
217
218 int idx = -1;
219 foreach(string i in lines) {
220 idx++;
221 if(stackFrame is not null) {
222 System.Reflection.MethodBase? methodBase = stackFrame.GetMethod();
223 if(methodBase is not null) {
224 var names = methodBase.DeclaringType;
225 if (names is not null) {
226 var logtmp = new DebugLog() {
227 level = level,
228 time = DateTime.Now.ToString("hh:mm:ss"),
229 sender = names.Name,
230 message = i,
231 hideInfo = idx != 0
232 };
233
234 Logs.Add(logtmp);
235 }
236 }
237 }
238 }
239 }
240
241 public static void PerformCommand(string command, object[] args) {
242 if(commands.TryGetValue(command, out var command1)) {
243 try {
244 command1(args);
245 } catch(Exception e) {
246 Debug.Log(LogLevel.Error, e.ToString());
247 }
248 } else {
249 Debug.Log(LogLevel.Error, $"Unknown Command: {command}");
250 }
251 }
252}