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