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 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 DialogType type, const DialogIcon icon, const 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:57
#define GALAXY_DISABLE_WARNING(x)
Definition Pragma.hpp:58
#define GALAXY_DISABLE_WARNING_PUSH
Macro for windows platform detection.
Definition Pragma.hpp:56
~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.
bool physfs_check(const int code) noexcept
Call a physfs function with error handling and logs a message for you.
Animated.cpp galaxy.
Definition Animated.cpp:16
DialogButton
Type of button for tinyfd boxes.
DialogType
Type of dialog box for use with tinyfd.
DialogIcon
Type of native system icon to display on file dialogs.
static auto root_dir() noexcept -> std::filesystem::path
Current root directory of application, unless it has been changed.
Definition Settings.cpp:217
static auto assets_dir_prefabs() noexcept -> const std::string &
Prefab asset location.
Definition Settings.cpp:282
static auto assets_dir_texture() noexcept -> const std::string &
Textures asset location.
Definition Settings.cpp:277
static auto assets_dir_voice() noexcept -> const std::string &
Voice asset location.
Definition Settings.cpp:252
static auto assets_dir_shaders() noexcept -> const std::string &
Shaders asset location.
Definition Settings.cpp:267
static auto assets_dir_ui() noexcept -> const std::string &
UI asset location.
Definition Settings.cpp:297
static auto use_loose_assets() noexcept -> bool
Should asset data be read from pack or assets dir.
Definition Settings.cpp:237
static auto assets_dir_animation() noexcept -> const std::string &
Animation data location.
Definition Settings.cpp:272
static auto assets_dir_script() noexcept -> const std::string &
Scripts asset location.
Definition Settings.cpp:262
static auto assets_dir_music() noexcept -> const std::string &
Music asset location.
Definition Settings.cpp:242
static auto assets_dir() noexcept -> std::filesystem::path
Main data directory.
Definition Settings.cpp:222
static auto asset_pack() noexcept -> const std::string &
Name of packed assets file.
Definition Settings.cpp:232
static auto assets_dir_sfx() noexcept -> const std::string &
SFX asset location.
Definition Settings.cpp:247
static auto assets_dir_maps() noexcept -> const std::string &
Maps asset location.
Definition Settings.cpp:287
static auto editor_dir() noexcept -> std::filesystem::path
Directory for editor specific stuff.
Definition Settings.cpp:227
static auto assets_dir_video() noexcept -> const std::string &
Video asset location.
Definition Settings.cpp:292
static auto assets_dir_font() noexcept -> const std::string &
Font asset location.
Definition Settings.cpp:257