VEX Engine
Retro looking game engine made in vulkan mostly because i wanted to understand it better.
Loading...
Searching...
No Matches
main.cpp
1#define CR_HOST
2
3#include <cr.h>
4#include <filesystem>
5#include <iostream>
6#include <thread>
7#include <atomic>
8#include <string>
9#include <cstdio>
10#include <vector>
11
12#ifdef _WIN32
13#include <windows.h>
14#include <shellapi.h>
15#else
16#include <dlfcn.h>
17#include <unistd.h>
18#include <limits.h>
19#endif
20
21#include "Engine.hpp"
22#include "Editor.hpp"
23#include "DialogWindow.hpp"
24#include "BasicDialog.hpp"
25#include "Execute.hpp"
26
27#include "components/ErrorUtils.hpp"
29
30std::filesystem::path getSelfPath() {
31#ifdef _WIN32
32 char path[MAX_PATH];
33 if (GetModuleFileNameA(NULL, path, MAX_PATH) == 0) return "";
34 return std::filesystem::path(path);
35#else
36 char path[PATH_MAX];
37 ssize_t count = readlink("/proc/self/exe", path, PATH_MAX);
38 if (count == -1) return "";
39 return std::filesystem::path(std::string(path, count));
40#endif
41}
42
43void restartApplication(int argc, char* argv[]) {
44 vex::log(">> Restarting Application...");
45 std::filesystem::path exePath = getSelfPath();
46 if (exePath.empty()) exit(1);
47
48#ifdef _WIN32
49 std::string params = "";
50 for (int i = 1; i < argc; i++) params += "\"" + std::string(argv[i]) + "\" ";
51 ShellExecuteA(NULL, "open", exePath.string().c_str(), params.c_str(), NULL, SW_SHOWDEFAULT);
52 exit(0);
53#else
54 execv(exePath.c_str(), argv);
55 exit(1);
56#endif
57}
58
59void checkHashAndExit(const std::string& path) {
60 std::string hash = "0";
61#ifdef _WIN32
62 HMODULE lib = LoadLibraryExA(path.c_str(), NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
63 if (lib) {
64 typedef const char* (*FuncType)();
65 FuncType func = (FuncType)GetProcAddress(lib, "VexModule_GetExpectedHash");
66 if (func) {
67 hash = func();
68 } else {
69 std::cerr << ">> [Warning] GameModule is missing hash export (VexModule_GetExpectedHash).\n"
70 << " This usually means it was built with an older Engine version.\n";
71 }
72 FreeLibrary(lib);
73 }
74#else
75 void* lib = dlopen(path.c_str(), RTLD_LAZY | RTLD_LOCAL);
76 if (lib) {
77 typedef const char* (*FuncType)();
78 FuncType func = (FuncType)dlsym(lib, "VexModule_GetExpectedHash");
79 if (func) {
80 hash = func();
81 } else {
82 std::cerr << ">> [Warning] GameModule is missing hash export (VexModule_GetExpectedHash).\n"
83 << " This usually means it was built with an older Engine version.\n";
84 }
85 }
86#endif
87 std::cout << hash << std::flush;
88 std::quick_exit(0);
89}
90
91std::string getModuleHash(const std::string& libPath) {
92 std::filesystem::path exe = getSelfPath();
93 if (exe.empty()) return "0";
94
95 #ifdef _WIN32
96 std::string cmd = "\"\"" + exe.string() + "\" --check-hash \"" + libPath + "\"\"";
97 #else
98 std::string cmd = "\"" + exe.string() + "\" --check-hash \"" + libPath + "\"";
99 #endif
100 std::string result = "0";
101
102#ifdef _WIN32
103 FILE* pipe = _popen(cmd.c_str(), "r");
104#else
105 FILE* pipe = popen(cmd.c_str(), "r");
106#endif
107
108 if (!pipe) {
109 vex::log("Failed to spawn hash checker process.");
110 return "0";
111 }
112
113 char buffer[128];
114 if (fgets(buffer, sizeof(buffer), pipe) != nullptr) {
115 result = buffer;
116 result.erase(std::remove(result.begin(), result.end(), '\n'), result.end());
117 result.erase(std::remove(result.begin(), result.end(), '\r'), result.end());
118 }
119
120#ifdef _WIN32
121 _pclose(pipe);
122#else
123 pclose(pipe);
124#endif
125
126 return result;
127}
128
129void rebuildProject(const std::filesystem::path& projectPath, vex::GameInfo& info, bool clean) {
130 vex::DialogWindow dialogWindow(clean ? "Engine Updated - Clean Rebuilding..." : "Building Project...", info);
131
132 std::string command;
133 std::string cleanFlag = clean ? " -clean" : "";
134
135 #ifdef _WIN32
136 command = "..\\..\\BuildTools\\build\\ProjectBuilder.exe \"" + projectPath.string() + "\" -d" + cleanFlag;
137 #else
138 command = "../../BuildTools/build/ProjectBuilder \"" + projectPath.string() + "\" -d" + cleanFlag;
139 #endif
140
141 std::thread buildThread([&]() {
142 std::string outputLog;
143 executeCommandRealTime(command, [&](const std::string& line) {
144 outputLog += line;
145 std::cout << line;
146 dialogWindow.setDialogContent(outputLog);
147 });
148
149 dialogWindow.stop();
150 });
151
152 dialogWindow.run();
153 buildThread.join();
154}
155
156int main(int argc, char* argv[]) {
157 if (argc == 3 && std::string(argv[1]) == "--check-hash") {
158 checkHashAndExit(argv[2]);
159 return 0;
160 }
161
162 if (argc < 2) {
163 std::cerr << "Error: Missing argument.\n";
164 std::cout << "Usage: " << argv[0] << " <path_to_project>\n";
165 return 1;
166 }
167
168 //vex::GameInfo dialogGameInfo("Dialog Window", vex::Engine::GetVersionMajor(), vex::Engine::GetVersionMinor(), vex::Engine::GetVersionPatch());
169 vex::GameInfo dialogGameInfo("Dialog Window", static_cast<uint16_t>(vex::Engine::GetVersionMajor()), static_cast<uint16_t>(vex::Engine::GetVersionMinor()), static_cast<uint16_t>(vex::Engine::GetVersionPatch()));
170 SDL_SetAppMetadata("Vex Engine", vex::Engine::GetVersionString(), "VexEngine");
171
172 std::filesystem::path projectPath = argv[1];
173 std::filesystem::path modulePath = projectPath / "Build" / "Debug";
174
175 #ifdef __linux__
176 std::string libPath = (modulePath / "libGameModule.so").string();
177 #else
178 std::string libPath = (modulePath / "GameModule.dll").string();
179 #endif
180
181 if (!std::filesystem::exists(projectPath / "VexProject.json")) {
182 createBasicDialog("Error", "No valid vex project file in path:\n" + projectPath.string(), dialogGameInfo);
183 vex::log(vex::LogLevel::ERROR, "No valid vex project file in path: %s", projectPath.string().c_str());
184 return 1;
185 }
186
187 if (!std::filesystem::exists(libPath)) {
188 vex::log("Game Module missing. Building...");
189 rebuildProject(projectPath, dialogGameInfo, false);
190 }
191
192 std::string engineHash = vex::Engine::GetBuildHash();
193 std::string moduleHash = getModuleHash(libPath);
194
195 if (moduleHash.empty() || moduleHash == "0" || moduleHash != engineHash) {
196 vex::log(">> ABI Mismatch Detected!");
197 vex::log(" Engine Hash: %s", engineHash.c_str());
198 vex::log(" Module Hash: %s", moduleHash.c_str());
199
200 rebuildProject(projectPath, dialogGameInfo, true);
201 restartApplication(argc, argv);
202 return 0;
203 }
204
205 cr_plugin ctx = {};
206
207 vex::log("Attempting to load game module from: %s", libPath.c_str());
208
209 if (!cr_plugin_open(ctx, libPath.c_str())) {
210 createBasicDialog("Critical Error", "Failed to load Game Module! Check path and file permissions.\nAlternativly try clean building you project manually.", dialogGameInfo);
211 vex::log(vex::LogLevel::CRITICAL, "Failed to load Game Module! Check path and file permissions.");
212 return 1;
213 }
214
215 //vex::GameInfo gInfo{"VEX Editor", vex::Engine::GetVersionMajor(), vex::Engine::GetVersionMinor(), vex::Engine::GetVersionPatch()};
216 vex::GameInfo gInfo{
217 "VEX Editor",
218 static_cast<uint16_t>(vex::Engine::GetVersionMajor()),
219 static_cast<uint16_t>(vex::Engine::GetVersionMinor()),
220 static_cast<uint16_t>(vex::Engine::GetVersionPatch())
221 };
222 vex::Editor engine("VEX Editor", 1280, 720, gInfo, projectPath.string());
223 ctx.userdata = &engine;
224
226
227 vex::log("Starting Engine Loop with Hot Reload...");
228
229 engine.run([&]() {
230 try {
231 unsigned int oldVersion = ctx.version;
232 int result = cr_plugin_update(ctx);
233
234 if (result != 0) {
235 vex::throw_error("Hot Reload Update Failed");
236 }
237
238 if (ctx.version != oldVersion) {
239 engine.OnHotReload();
240 }
241 } catch (const std::exception& e) {
243 }
244 });
245
246 std::quick_exit(0);
247 return 0;
248}
A specialized Engine class for creating and managing modal dialog windows.
The main Editor class, inheriting from Engine and providing editor-specific functionality and UI.
Contains main Engine class.
This file defines struct GameInfo.
A specialized Engine class for creating and managing modal dialog windows.
The main Editor class, inheriting from Engine and providing editor-specific functionality and UI.
Definition Editor.hpp:32
static int GetVersionMinor()
Returns the minor version of the engine.
Definition Engine.cpp:34
static const char * GetVersionString()
Returns the version string of the engine.
Definition Engine.cpp:42
static const char * GetBuildHash()
returns engine hash generated during build process.
Definition Engine.cpp:98
static int GetVersionPatch()
Returns the patch version of the engine.
Definition Engine.cpp:38
static int GetVersionMajor()
Returns the major version of the engine.
Definition Engine.cpp:30
void VEX_EXPORT InitCrashHandler()
Initializes the low-level crash handler.
void VEX_EXPORT throw_error(const std::string &msg)
Throws an error or terminates the application.
void VEX_EXPORT log(const char *fmt,...)
Logs a formatted message.
void VEX_EXPORT handle_critical_exception(const std::exception &e)
Handles a critical exception, forcing termination.
this struct contains information about the game. like project name and version.
Definition GameInfo.hpp:15