Olympe Engine 2.0
2D Game Engine with ECS Architecture
Loading...
Searching...
No Matches
system_utils.h
Go to the documentation of this file.
1#pragma once
2
3// "system_utils.h" -> simplified logging implementation
4// Centralized logger that outputs to std::cout, file (olympe.log),
5// and to the UI log window. Use:
6// Logging::InitLogger();
7// SYSTEM_LOG << "Hello" << std::endl;
8
9#include <streambuf>
10#include <ostream>
11#include <vector>
12#include <memory>
13#include <fstream>
14#include <mutex>
15#include <iostream>
16#include <string>
17#include <sstream>
18#include "system_consts.h"
19#include "log_sink.h"
20
21//-------------------------------------------------------------
22// Convenience macro (keeps existing code using SYSTEM_LOG)
23#define SYSTEM_LOG ::Logging::Logger()
24
25namespace Logging
26{
27 // Simple line-buffering logger with operator<< overloads
28 // Outputs to: std::cout (console), olympe.log (file), and UI panel
29 class Log
30 {
31 public:
33
34 // Initialize file logging (optional). Safe to call multiple times.
35 bool Init(const std::string& filename = "olympe.log")
36 {
37 std::lock_guard<std::mutex> lock(m_);
38 if (file_open_) return true;
39 file_.open(filename.c_str(), std::ios::app);
40 if (file_.is_open())
41 {
42 file_open_ = true;
43 }
44 // ensure panel sink exists (log_sink handles buffering until UI attached)
45 return true;
46 }
47
48 void Shutdown()
49 {
50 std::lock_guard<std::mutex> lock(m_);
51 if (file_.is_open()) { file_.flush(); file_.close(); }
52 file_open_ = false;
53 }
54
55 // Generic stream insertion
56 template<typename T>
57 auto operator<<(const T& v) -> decltype(std::declval<std::ostringstream&>() << v, std::declval<Log&>())
58 {
59 {
60 std::lock_guard<std::mutex> lock(m_);
61 buffer_ << v;
62 }
64 return *this;
65 }
66
67 // Manipulators like std::endl
68 using Manip = std::ostream& (*)(std::ostream&);
70 {
71 if (m == static_cast<Manip>(&std::endl))
72 {
73 // endl inserts newline and flushes
74 {
75 std::lock_guard<std::mutex> lock(m_);
76 buffer_ << m;
77 }
80 }
81 else if (m == static_cast<Manip>(&std::flush))
82 {
84 }
85 else
86 {
87 // other manipulators forward into buffer
88 std::lock_guard<std::mutex> lock(m_);
89 buffer_ << m;
90 }
91 return *this;
92 }
93
94 private:
95 void writeToOutputs(const std::string& s)
96 {
97 // Always write to console (stdout)
98 std::cout << s;
99 std::cout.flush();
100
101 // Write to file if initialized
102 if (file_open_) {
103 file_ << s;
104 file_.flush();
105 }
106
107 // Send to UI log sink (thread-safe buffered)
109 }
110
112 {
113 std::lock_guard<std::mutex> lock(m_);
114 std::string s = buffer_.str();
115 size_t pos = 0;
116 while ((pos = s.find('\n')) != std::string::npos)
117 {
118 std::string line = s.substr(0, pos + 1);
120 s.erase(0, pos + 1);
121 }
122 buffer_.str(""); buffer_.clear();
123 buffer_ << s;
124 }
125
127 {
128 std::lock_guard<std::mutex> lock(m_);
129 std::string s = buffer_.str();
130 if (!s.empty())
131 {
133 buffer_.str(""); buffer_.clear();
134 }
135 }
136
137 private:
138 mutable std::mutex m_;
139 std::ostringstream buffer_;
140 std::ofstream file_;
142 };
143
144 // Access global logger instance
145 inline Log& Logger()
146 {
147 static Log s_logger;
148 return s_logger;
149 }
150
151 // Convenience init/shutdown
152 inline bool InitLogger(const std::string& filename = "olympe.log")
153 {
154 return Logger().Init(filename);
155 }
156
157 inline void ShutdownLogger()
158 {
159 Logger().Shutdown();
160 }
161}
162
163
164//-------------------------------------------------------------
165// JSON helpers (kept here for compatibility with existing code)
166//
167static std::string escape_json_string(const std::string& s)
168{
169 std::string out;
170 out.reserve(s.size() + 4);
171 for (char c : s)
172 {
173 switch (c)
174 {
175 case '\\': out += "\\\\"; break;
176 case '"': out += "\\\""; break;
177 case '\b': out += "\\b"; break;
178 case '\f': out += "\\f"; break;
179 case '\n': out += "\\n"; break;
180 case '\r': out += "\\r"; break;
181 case '\t': out += "\\t"; break;
182 default: out += c; break;
183 }
184 }
185 return out;
186}
187//-------------------------------------------------------------
188static bool extract_json_string(const std::string& json, const std::string& key, std::string& out)
189{
190 size_t pos = json.find('"' + key + '"');
191 if (pos == std::string::npos) pos = json.find(key);
192 if (pos == std::string::npos) return false;
193 pos = json.find(':', pos);
194 if (pos == std::string::npos) return false;
195 ++pos;
196 while (pos < json.size() && isspace(static_cast<unsigned char>(json[pos]))) ++pos;
197 if (pos < json.size() && json[pos] == '"') ++pos;
198 size_t start = pos;
199 while (pos < json.size() && json[pos] != '"' && json[pos] != '\n' && json[pos] != '\r') ++pos;
200 if (pos <= start) return false;
201 out = json.substr(start, pos - start);
202 return true;
203}
204//-------------------------------------------------------------
205static bool extract_json_double(const std::string& json, const std::string& key, double& out)
206{
207 size_t pos = json.find('"' + key + '"');
208 if (pos == std::string::npos) pos = json.find(key);
209 if (pos == std::string::npos) return false;
210 pos = json.find(':', pos);
211 if (pos == std::string::npos) return false;
212 ++pos;
213 while (pos < json.size() && isspace(static_cast<unsigned char>(json[pos]))) ++pos;
214 size_t start = pos;
215 while (pos < json.size() && (isdigit(static_cast<unsigned char>(json[pos])) || json[pos] == '+' || json[pos] == '-' || json[pos] == '.' || json[pos] == 'e' || json[pos] == 'E')) ++pos;
216 if (pos <= start) return false;
217 try { out = std::stod(json.substr(start, pos - start)); return true; }
218 catch (...) { return false; }
219}
220//-------------------------------------------------------------
221static bool extract_json_int(const std::string& json, const std::string& key, int& out)
222{
223 double d;
224 if (!extract_json_double(json, key, d)) return false;
225 out = static_cast<int>(d);
226 return true;
227}
228//-------------------------------------------------------------
229static bool extract_json_bool(const std::string& json, const std::string& key, bool& out)
230{
231 size_t pos = json.find('"' + key + '"');
232 if (pos == std::string::npos) pos = json.find(key);
233 if (pos == std::string::npos) return false;
234 pos = json.find(':', pos);
235 if (pos == std::string::npos) return false;
236 ++pos;
237 while (pos < json.size() && isspace(static_cast<unsigned char>(json[pos]))) ++pos;
238 if (json.compare(pos, 4, "true") == 0) { out = true; return true; }
239 if (json.compare(pos, 5, "false") == 0) { out = false; return true; }
240 return false;
241}
242
243//-------------------------------------------------------------
244// Load configuration from JSON file (keeps previous behavior)
245void LoadOlympeConfig(const char* filename);
246//-------------------------------------------------------------
247
248//-------------------------------------------------------------
249// Path resolution for resource files (Phase 24 - Condition Presets)
250// Resolves relative paths to absolute paths based on executable location.
251// This ensures resources can be found in both IDE debug mode (working dir = solution subdir)
252// and in built executable mode (working dir = parent dir).
253std::string ResolveResourcePath(const std::string& relativePath);
254//-------------------------------------------------------------
255
nlohmann::json json
ComponentTypeID GetComponentTypeID_Static()
Definition ECS_Entity.h:56
std::ostream &(*)(std::ostream &) Manip
std::ostringstream buffer_
std::mutex m_
void Shutdown()
Log & operator<<(Manip m)
void flushCompleteLinesIfAny()
void writeToOutputs(const std::string &s)
auto operator<<(const T &v) -> decltype(std::declval< std::ostringstream & >()<< v, std::declval< Log & >())
bool Init(const std::string &filename="olympe.log")
void flushRemaining()
std::ofstream file_
bool InitLogger(const std::string &filename="olympe.log")
void ShutdownLogger()
Log & Logger()
void AppendToLogWindow(const std::string &text)
void LoadOlympeConfig(const char *filename)
static std::string escape_json_string(const std::string &s)
static bool extract_json_double(const std::string &json, const std::string &key, double &out)
std::string ResolveResourcePath(const std::string &relativePath)
static bool extract_json_bool(const std::string &json, const std::string &key, bool &out)
static bool extract_json_int(const std::string &json, const std::string &key, int &out)
static bool extract_json_string(const std::string &json, const std::string &key, std::string &out)