galaxy 1.0.0
Real-Time C++23 Game Programming Framework. Built on data-driven design principles and agile software engineering.
Loading...
Searching...
No Matches
VirtualFileSystem.cpp
Go to the documentation of this file.
1
7
8#include <entt/locator/locator.hpp>
9#include <mimalloc.h>
10#include <physfs.h>
11#include <tinyfiledialogs.h>
12#include <zip.h>
13
19
20#include "VirtualFileSystem.hpp"
21
22#ifdef GALAXY_WIN_PLATFORM
26#endif
27
28namespace galaxy
29{
30 namespace fs
31 {
33 {
34 // Create data directories.
35 std::filesystem::create_directories(settings::root_dir() / settings::assets_dir());
36 std::filesystem::create_directories(settings::root_dir() / settings::editor_dir());
37
38 // Set up allocators for physfs.
39 PHYSFS_Allocator a = {};
40 a.Init = nullptr;
41 a.Deinit = nullptr;
42 a.Free = mi_free;
43 a.Malloc = mi_malloc;
44 a.Realloc = mi_realloc;
45 logging::physfs_check(PHYSFS_setAllocator(&a));
46
47 // Set up vfs.
48 if (logging::physfs_check(PHYSFS_init(nullptr)))
49 {
50 PHYSFS_permitSymbolicLinks(false);
51
52 auto write_dir = settings::root_dir() / settings::assets_dir();
53 write_dir.make_preferred();
54 logging::physfs_check(PHYSFS_setWriteDir(write_dir.string().c_str()));
55
56 auto read_dir = settings::root_dir() / settings::asset_pack();
57 read_dir.make_preferred();
58
60 {
73
74 read_dir = write_dir;
75 }
76
77 logging::physfs_check(PHYSFS_mount(read_dir.string().c_str(), nullptr, true));
78
79 const auto merged = settings::root_dir() / settings::editor_dir();
80 logging::physfs_check(PHYSFS_mount(merged.string().c_str(), nullptr, true));
81 }
82 }
83
88
89 std::string VirtualFileSystem::read(const std::string& file)
90 {
91 PHYSFS_File* f = PHYSFS_openRead(file.c_str());
93 {
94 const auto len = PHYSFS_fileLength(f);
95
96 if (logging::physfs_check(len))
97 {
98 std::string buffer;
99 buffer.resize(len);
100
101 if (logging::physfs_check(PHYSFS_readBytes(f, buffer.data(), buffer.size())))
102 {
103 return buffer;
104 }
105 else
106 {
107 GALAXY_LOG(GALAXY_ERROR, "Failed to read '{0}'.", file);
108 }
109 }
110 else
111 {
112 GALAXY_LOG(GALAXY_ERROR, "Failed to check file length for '{0}'.", file);
113 }
114
115 logging::physfs_check(PHYSFS_close(f));
116 }
117 else
118 {
119 GALAXY_LOG(GALAXY_ERROR, "Failed to read '{0}'.", file);
120 }
121
122 return {};
123 }
124
125 std::vector<std::uint8_t> VirtualFileSystem::read_binary(const std::string& file)
126 {
127 PHYSFS_File* f = PHYSFS_openRead(file.c_str());
129 {
130 const auto len = PHYSFS_fileLength(f);
131
132 if (logging::physfs_check(len))
133 {
134 std::vector<std::uint8_t> buffer;
135 buffer.resize(len);
136
137 if (logging::physfs_check(PHYSFS_readBytes(f, &buffer[0], buffer.size())))
138 {
139 return buffer;
140 }
141 else
142 {
143 GALAXY_LOG(GALAXY_ERROR, "Failed to read '{0}'.", file);
144 }
145 }
146 else
147 {
148 GALAXY_LOG(GALAXY_ERROR, "Failed to check file length for '{0}'.", file);
149 }
150
151 logging::physfs_check(PHYSFS_close(f));
152 }
153 else
154 {
155 GALAXY_LOG(GALAXY_ERROR, "Failed to read '{0}'.", file);
156 }
157
158 return {};
159 }
160
161 bool VirtualFileSystem::write(const std::string& data, const std::string& file)
162 {
163 return write_raw(data.data(), data.size() * sizeof(char), file);
164 }
165
166 bool VirtualFileSystem::write_binary(std::span<std::uint8_t> data, const std::string& file)
167 {
168 return write_raw(data.data(), data.size_bytes(), file);
169 }
170
171 bool VirtualFileSystem::write_raw(const void* data, const std::size_t size, const std::string& file)
172 {
173 auto path = std::filesystem::path(file);
174 if (path.is_absolute())
175 {
176 path = path.filename();
177 }
178
179 PHYSFS_File* f = PHYSFS_openWrite(path.string().c_str());
181 {
182 const auto len = PHYSFS_fileLength(f);
183
184 if (logging::physfs_check(PHYSFS_writeBytes(f, data, size)))
185 {
186 return true;
187 }
188 else
189 {
190 GALAXY_LOG(GALAXY_ERROR, "Failed to read '{0}'.", path.string());
191 }
192
193 logging::physfs_check(PHYSFS_close(f));
194 }
195 else
196 {
197 GALAXY_LOG(GALAXY_ERROR, "Failed to read '{0}'.", path.string());
198 }
199
200 return false;
201 }
202
203 void VirtualFileSystem::mkdir(const std::string& dir) noexcept
204 {
205 if (!exists(dir))
206 {
207 logging::physfs_check(PHYSFS_mkdir(dir.c_str()));
208 }
209 }
210
211 void VirtualFileSystem::remove(const std::string& path) noexcept
212 {
213 logging::physfs_check(PHYSFS_delete(path.c_str()));
214 }
215
216 bool VirtualFileSystem::exists(const std::string& file) noexcept
217 {
218 return PHYSFS_exists(file.c_str());
219 }
220
221 bool VirtualFileSystem::is_dir(const std::string& path) noexcept
222 {
223 return PHYSFS_isDirectory(path.c_str());
224 }
225
226 std::vector<std::string> VirtualFileSystem::list(const std::string& dir)
227 {
228 std::vector<std::string> list;
229
230 logging::physfs_check(PHYSFS_enumerate(
231 dir.c_str(),
232 [](void* data, const char* origdir, const char* fname) -> PHYSFS_EnumerateCallbackResult {
233 if (data != nullptr && fname != nullptr)
234 {
235 std::string o = origdir;
236 std::string f = fname;
237
238 auto* my_list = static_cast<std::vector<std::string>*>(data);
239 my_list->emplace_back(o + f);
240 }
241
242 return PHYSFS_ENUM_OK;
243 },
244 &list
245 ));
246
247 return list;
248 }
249
250 void VirtualFileSystem::alert() noexcept
251 {
252 tinyfd_beep();
253 }
254
255 void VirtualFileSystem::notification(const std::string& title, const std::string& msg, const DialogIcon icon) noexcept
256 {
257 std::string tinyfd_icon {magic_enum::enum_name(icon)};
258 tinyfd_notifyPopup(title.c_str(), msg.c_str(), tinyfd_icon.c_str());
259 }
260
261 int VirtualFileSystem::message_box(const std::string& title, const std::string& msg, const DialogType type, const DialogIcon icon, const DialogButton btn) noexcept
262 {
263 std::string tinyfd_type {magic_enum::enum_name(type)};
264 std::string tinyfd_icon {magic_enum::enum_name(icon)};
265
266 return tinyfd_messageBox(title.c_str(), msg.c_str(), tinyfd_type.c_str(), tinyfd_icon.c_str(), static_cast<int>(btn));
267 }
268
269 std::string VirtualFileSystem::input_box(const std::string& title, const std::string& msg, const std::string& default_text, const bool password) noexcept
270 {
271 const char* dt = password ? nullptr : default_text.c_str();
272 return tinyfd_inputBox(title.c_str(), msg.c_str(), dt);
273 }
274
275 std::string VirtualFileSystem::open_save_dialog(const std::string& default_filename, const std::vector<const char*>& filters)
276 {
277 const char* const* filter_patterns = (filters.size() > 0) ? filters.data() : nullptr;
278 const char* result = tinyfd_saveFileDialog("Save file", default_filename.c_str(), static_cast<int>(filters.size()), filter_patterns, nullptr);
279
280 if (result != nullptr)
281 {
282 return {result};
283 }
284 else
285 {
286 return {};
287 }
288 }
289
290 std::string VirtualFileSystem::open_file_dialog(const std::vector<const char*>& filters, const std::string& def_path)
291 {
292 const auto default_path = (settings::root_dir() / def_path).string();
293
294 const char* const* filter_patterns = (filters.size() > 0) ? filters.data() : nullptr;
295 const char* result = tinyfd_openFileDialog("Open file", default_path.c_str(), static_cast<int>(filters.size()), filter_patterns, "Select a file", false);
296
297 if (result != nullptr)
298 {
299 return {result};
300 }
301 else
302 {
303 return {};
304 }
305 }
306
307 std::string VirtualFileSystem::select_folder_dialog(const std::string& def_path)
308 {
309 const auto default_path = (settings::root_dir() / def_path).string();
310 const char* result = tinyfd_selectFolderDialog("Select folder", default_path.c_str());
311
312 if (result != nullptr)
313 {
314 return {result};
315 }
316 else
317 {
318 return {};
319 }
320 }
321
322 std::string VirtualFileSystem::get_file_extension(const std::string& file_name) noexcept
323 {
324 const auto path = std::filesystem::path(file_name);
325 if (path.has_extension())
326 {
327 return path.extension().string();
328 }
329 else
330 {
331 return {};
332 }
333 }
334 } // namespace fs
335} // namespace galaxy
336
337#ifdef GALAXY_WIN_PLATFORM
339#endif
#define GALAXY_LOG(level, msg,...)
Definition Log.hpp:29
#define GALAXY_ERROR
Definition Log.hpp:25
#define GALAXY_DISABLE_WARNING_POP
Definition Pragma.hpp:44
#define GALAXY_DISABLE_WARNING(x)
Definition Pragma.hpp:45
#define GALAXY_DISABLE_WARNING_PUSH
Pragma.hpp galaxy.
Definition Pragma.hpp:43
bool is_dir(const std::string &path) noexcept
Checks if a file is a folder.
bool exists(const std::string &file) noexcept
Does the file exist in the vfs.
std::vector< std::uint8_t > read_binary(const std::string &file)
Read a binary file.
void mkdir(const std::string &dir) noexcept
Creates an empty folder in the filesystem relative to the root.
bool write_raw(const void *data, const std::size_t size, const std::string &file)
Raw data writing.
bool write(const std::string &data, const std::string &file)
Writes a file to disk.
std::vector< std::string > list(const std::string &dir)
Get assets in an asset folder.
bool write_binary(std::span< std::uint8_t > data, const std::string &file)
Writes a binary file to disk.
std::string read(const std::string &file)
Read a file.
void remove(const std::string &path) noexcept
Delete a file or folder.
DialogIcon
Type of native system icon to display on file dialogs.
DialogType
Type of dialog box for use with tinyfd.
DialogButton
Type of button for tinyfd boxes.
bool physfs_check(const int code) noexcept
Call a physfs function with error handling and logs a message for you.
Timer.hpp galaxy.
Definition Async.hpp:17
static auto assets_dir_video() noexcept -> const std::string &
Video asset location.
Definition Settings.cpp:247
static auto assets_dir_voice() noexcept -> const std::string &
Voice asset location.
Definition Settings.cpp:207
static auto assets_dir_script() noexcept -> const std::string &
Scripts asset location.
Definition Settings.cpp:217
static auto asset_pack() noexcept -> const std::string &
Name of packed assets file.
Definition Settings.cpp:187
static auto root_dir() noexcept -> std::filesystem::path
Current root directory of application, unless it has been changed.
Definition Settings.cpp:172
static auto assets_dir_prefabs() noexcept -> const std::string &
Prefab asset location.
Definition Settings.cpp:237
static auto assets_dir_shaders() noexcept -> const std::string &
Shaders asset location.
Definition Settings.cpp:222
static auto assets_dir_animation() noexcept -> const std::string &
Animation data location.
Definition Settings.cpp:227
static auto editor_dir() noexcept -> std::filesystem::path
Directory for editor specific stuff.
Definition Settings.cpp:182
static auto assets_dir_font() noexcept -> const std::string &
Font asset location.
Definition Settings.cpp:212
static auto assets_dir_maps() noexcept -> const std::string &
Maps asset location.
Definition Settings.cpp:242
static auto assets_dir() noexcept -> std::filesystem::path
Main data directory.
Definition Settings.cpp:177
static auto assets_dir_texture() noexcept -> const std::string &
Textures asset location.
Definition Settings.cpp:232
static auto use_loose_assets() noexcept -> bool
Should asset data be read from pack or assets dir.
Definition Settings.cpp:192
static auto assets_dir_music() noexcept -> const std::string &
Music asset location.
Definition Settings.cpp:197
static auto assets_dir_sfx() noexcept -> const std::string &
SFX asset location.
Definition Settings.cpp:202
static auto assets_dir_ui() noexcept -> const std::string &
UI asset location.
Definition Settings.cpp:252