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