Although the code was made to compile cleanly on Linux, there is still a runtime issue finding assets.
$ ./OPHD
Initializing Filesystem... done.
File 'fonts.dat' does not exist as specified.
File 'maps.dat' does not exist as specified.
File 'planets.dat' does not exist as specified.
File 'robots.dat' does not exist as specified.
File 'sfx.dat' does not exist as specified.
File 'structures.dat' does not exist as specified.
File 'sys.dat' does not exist as specified.
File 'ui.dat' does not exist as specified.
Initializing Configuration... done.
Initializing Mixer... done.
Starting OpenGL Renderer:
- OpenGL System Info -
Vendor: Intel Open Source Technology Center
Renderer: Mesa DRI Intel(R) Bay Trail
Driver Version: 3.0 Mesa 17.0.7
GLSL Version: 1.30
Unable to load 'ui/pointers/normal.png'. No such file or directory.
OGL_Renderer::addCursor(): 'OpenGL Renderer' is empty.
Unable to load 'ui/pointers/place_tile.png'. No such file or directory.
OGL_Renderer::addCursor(): 'OpenGL Renderer' is empty.
Unable to load 'ui/pointers/inspect.png'. No such file or directory.
OGL_Renderer::addCursor(): 'OpenGL Renderer' is empty.
Unable to load 'sfx/cc_no_bulldoze_m.ogg'. No such file or directory.
Unable to load 'sfx/insufficient_resources_m.ogg'. No such file or directory.
Unable to load 'sfx/invalid_digger_placement_m.ogg'. No such file or directory.
Unable to load 'sfx/invalid_miner_placement_m.ogg'. No such file or directory.
Unable to load 'sfx/invalid_structure_placement_m.ogg'. No such file or directory.
Unable to load 'sfx/invalid_tube_placement_m.ogg'. No such file or directory.
Unable to load 'sfx/ni.ogg'. No such file or directory.
Unable to load 'sfx/location_not_bulldozed_m.ogg'. No such file or directory.
Unable to load 'sfx/max_dig_depth_m.ogg'. No such file or directory.
Unable to load 'sfx/no_tube_connection_m.ogg'. No such file or directory.
Unable to load 'sfx/ni.ogg'. No such file or directory.
Unable to load 'sfx/unsuitable_landing_site_m.ogg'. No such file or directory.
Unable to load 'sfx/ni.ogg'. No such file or directory.
Unable to load 'sfx/ni.ogg'. No such file or directory.
Unable to load 'sfx/cc_no_bulldoze_f.ogg'. No such file or directory.
Unable to load 'sfx/insufficient_resources_f.ogg'. No such file or directory.
Unable to load 'sfx/invalid_digger_placement_f.ogg'. No such file or directory.
Unable to load 'sfx/invalid_miner_placement_f.ogg'. No such file or directory.
Unable to load 'sfx/invalid_structure_placement_f.ogg'. No such file or directory.
Unable to load 'sfx/invalid_tube_placement_f.ogg'. No such file or directory.
Unable to load 'sfx/ni.ogg'. No such file or directory.
Unable to load 'sfx/location_not_bulldozed_f.ogg'. No such file or directory.
Unable to load 'sfx/max_dig_depth_f.ogg'. No such file or directory.
Unable to load 'sfx/no_tube_connection_f.ogg'. No such file or directory.
Unable to load 'sfx/ni.ogg'. No such file or directory.
Unable to load 'sfx/unsuitable_landing_site_f.ogg'. No such file or directory.
Unable to load 'sfx/ni.ogg'. No such file or directory.
Unable to load 'sfx/ni.ogg'. No such file or directory.
Unable to load 'sys/lairworks-logo.png'. No such file or directory.
Image::load(): 'sys/lairworks-logo.png' is empty.
Unable to load 'sys/nas2d_logo.png'. No such file or directory.
Image::load(): 'sys/nas2d_logo.png' is empty.
Unable to load 'sys/ophd_large.png'. No such file or directory.
Image::load(): 'sys/ophd_large.png' is empty.
Unable to load 'music/splash.ogg'. No such file or directory.
Unable to load 'fonts/opensans.ttf'. No such file or directory.
Unable to load 'fonts/opensans-bold.ttf'. No such file or directory.
Unable to load 'fonts/opensans.ttf'. No such file or directory.
Unable to load 'sys/bg1.png'. No such file or directory.
Image::load(): 'sys/bg1.png' is empty.
Unable to load 'sys/flare_1.png'. No such file or directory.
Image::load(): 'sys/flare_1.png' is empty.
Unable to load 'sys/flare_2.png'. No such file or directory.
Image::load(): 'sys/flare_2.png' is empty.
Unable to load 'sys/flare_3.png'. No such file or directory.
Image::load(): 'sys/flare_3.png' is empty.
Unable to load 'sys/cloud_1.png'. No such file or directory.
Image::load(): 'sys/cloud_1.png' is empty.
Unable to load 'sys/cloud_2.png'. No such file or directory.
Image::load(): 'sys/cloud_2.png' is empty.
Unable to load 'music/menu.ogg'. No such file or directory.
Unable to load 'sfx/click.ogg'. No such file or directory.
Unable to load 'sfx/menu4.ogg'. No such file or directory.
Unable to load 'ui/skin/button_top_left.png'. No such file or directory.
Image::load(): 'ui/skin/button_top_left.png' is empty.
Font 'fonts/opensans.ttf_10pt' was not found in the resource management.
Font 'fonts/opensans-bold.ttf_14pt' was not found in the resource management.
Font 'fonts/opensans.ttf_14pt' was not found in the resource management.
Attempted to copy an Image in an invalid load state.
I believe this is related to the platform guard found in NAS2D in src/Filesystem.cpp, in method:
void Filesystem::init(const std::string& argv_0, const std::string& startPath)
Simply removing the #if/#else/#endif guards allows the game to work. Though there are still error messages about the fonts:
$ ./OPHD
Initializing Filesystem... done.
File 'fonts.dat' does not exist as specified.
File 'maps.dat' does not exist as specified.
File 'planets.dat' does not exist as specified.
File 'robots.dat' does not exist as specified.
File 'sfx.dat' does not exist as specified.
File 'structures.dat' does not exist as specified.
File 'sys.dat' does not exist as specified.
File 'ui.dat' does not exist as specified.
Initializing Configuration... done.
Initializing Mixer... done.
Starting OpenGL Renderer:
- OpenGL System Info -
Vendor: Intel Open Source Technology Center
Renderer: Mesa DRI Intel(R) Bay Trail
Driver Version: 3.0 Mesa 17.0.7
GLSL Version: 1.30
This is also the function that contains the embedded ".lom" string, which probably shouldn't be in NAS2D. It might make more sense to either pass in that string, or to somehow base it off the executable filename.
Also, while testing this, I found another more recent error in the outposthd repository. In src/ProductPool.h, I needed to add some extra braces to get this line to compile:
ProductTypeCount mProducts = {{ 0 }};
I assume you meant apt get, in which case, thank you. :P
I think I know enough about the function now to take a stab at the changes myself.
Edit: Still had a few things to learn. Out of curiosity, I thought I'd see how hard a source install of PhysFS 3.0 would be. Turned out to be fairly easy.
wget https://icculus.org/physfs/downloads/physfs-3.0.0.tar.bz2
tar -jxvf physfs-3.0.0.tar.bz2
cd physfs-3.0.0/
cmake
make
sudo make install
It only takes a few seconds to run. Maybe build commands could be added to the make file. It would mean running the source install steps each time a TravisCI test was run. Though NAS2D has also been relatively stable after the initial Linux porting work.
The new functions are indeed very tempting to use. Plus the older functions have been deprecated. According to PHYSFS_getUserDir() (https://icculus.org/physfs/docs/html/physfs_8h.html#a9d86fca7a5cbbc53f5425ff7539b1426), the change was made in version 2.1, earlier than I originally thought.
On debian/ubuntu, you should replace `sudo make install` by `sudo checkinstall` so that the package is tracked by the packet manager and you don't end up with random files spread around your filesystem :)
Thank you for that! I'm wondering now if this can be used to speed up the TravisCI tests. A lot of the time is spent on the SDL2 compiling. Though the .deb packages would need to be hosted somewhere and downloaded by the test VM to install from. Not sure how appropriate it is to put them in the repo itself.
... enough, at least, to google them.
That's all that really matters ;)
But yeah, that's the big glaring thing in the Filesystem code that's been bugging me for awhile.
I've been finding myself hesitant to make changes to your code. I think this will be a breaking change, in terms of source code interface compatibility. It's got me wondering about intent, and what your design goals are. It seems like PhysFS handles the default common case well. Could just delegate stuff to PhysFS without much change in semantics or complicated wrapping. Not sure if you're trying to build any restrictions or abstractions on top of it.
I think the PHYSFS_setSaneConfig (https://icculus.org/physfs/docs/html/physfs_8h.html#afef8700f714b6800ff688372c540bfe2) does exactly what you want. It sets a read path where the executable is installed, allowing you to load game assets, and a read/write path in an appropriate subdirectory of the user's home directory, for things like saved games, or user specific config.
The one difference I think I see, is you seem to be adding subpaths to where the executable is installed, whereas the default is the parent folder containing the executable. I think perhaps the default config makes a lot of sense, and path to assets can be adjusted to include the subfolder.
Oh, and the setSaneConfig method can also search the read folder for archives with a given extension, and automatically add them. That can save you from manually specifying archives to load, and also eliminate error messages from adding archives you haven't created yet.
If a game doesn't want the default config, maybe the initialization of PHYSFS and the config of folders should be split into separate methods. Or maybe the default can run, but can be cleared or undone later. Or maybe you just want to disallow that, and say the default config should be good enough for any game likely to be created using NAS2D. Which might actually be very true. I'm thinking just stick with what setSaneConfig provides and not worry about it.
I was thinking the Filesystem::init could be something like this:
void Filesystem::init(const std::string& argv_0, const std::string& organizationName, const std::string& appName, const std::string& archiveExt)
{
if (FILESYSTEM_INITIALIZED) { throw filesystem_already_initialized(); }
std::cout << "Initializing Filesystem... ";
if (PHYSFS_init(argv_0.c_str()) == 0)
{
throw filesystem_backend_init_failure(PHYSFS_getLastError());
}
if (PHYSFS_setSaneConfig(organizationName, appName, archiveExt, false, false) == 0)
{
std::cout << std::endl << PHYSFS_getLastError() << std::endl;
}
FILESYSTEM_INITIALIZED = true;
std::cout << "done." << std::endl;
}
Was also thinking some of those messages might be more appropriate for cerr rather than cout. Not that it much matters for a graphical application.