FosterFramework / Foster

A small C# game framework
MIT License
450 stars 37 forks source link

Content / UserStorage APIs #37

Closed NoelFB closed 8 months ago

NoelFB commented 11 months ago

Consoles often require very specific mounting for file access and save data. I think there should be 2 utility classes that can be used to simplify this. Obviously if the user doesn't care about non-desktop portability they can just ignore these:

The Content class lets the user enumerate and read files from a Content directory. I think the App should create a default one. On Desktop platforms this would find files beside the .exe location, for example new Content("Assets") would work over files in the Assets directory adjacent to the YourGame.exe.

public class Content
{
    public Content(string directory);

    public IEnumerator<string> EnumerateFiles(string relativePath, string searchPattern, bool recursive);
    public IEnumerator<string> EnumerateDirectories(string relativePath, string searchPattern, bool recursive);

    public bool FileExists(string relativePath);
    public bool DirectoryExists(string relativePath);
    public Stream OpenRead(string relativePath);
}

User Storage is simpler and should be a singleton... it just reads / writes data to user files and can see if they exist. On Desktop this would use App.UserPath. I don't think there's any need to enumerate files here.

public class UserStorage
{
    public static bool Exists(string path);
    public static byte[] Read(string path);
    public static void Write(string path, byte[] data);
}
MrBrixican commented 11 months ago

I think there is some utility in being able to list user storage files. Specifically, in relation to game saves. Many games rely on enumeration of some some shared save location that allows players to drop in saves as needed without having to modify some shared save directory file.

Additionally, being able to use streams (OpenRead, OpenWrite) would be beneficial here for larger/more complex save files.

All this is dependent on whether consoles even allow enumeration/streams/support for big enough files to warrant them, which I wouldn't know or be able to find out.

Also, is this going to be incorporated with all of the current api methods that load files? Or would a user be expected to get a stream using this new api and use it with existing ones (I recommend the latter).

Finally, if this is a purely optional component of Foster, maybe keeping it in its own namespace (Foster.Framework.Storage) would be beneficial, seeing as storage methodologies/implementations can be highly opinionated and vary greatly depending on project requirements.

NoelFB commented 11 months ago

I think there is some utility in being able to list user storage files.

Yeah, I think you're right. In general I just do a hacky thing where I check "does 'fileN' exists", incrementing N until none are found. But it'd be better to actually return a list of existing files.

Additionally, being able to use streams (OpenRead, OpenWrite) would be beneficial here for larger/more complex save files.

Yeah, I agree with this in general. My concern is that it may make the Platform side more complicated because it would need to better handle mounting/opening/closing around the stream - but if the Stream is a custom class we make that handles it, then it should be fine.

Also, is this going to be incorporated with all of the current api methods that load files?

I don't want to change any methods that load files as long as they take a Stream. I agree don't want weird Content-specific load methods - I think they'd be confusing and redundant.

Finally, if this is a purely optional component of Foster, maybe keeping it in its own namespace

Definitely agree. My intention with this is just to have some way to handle content/user data generically across platforms, but like other things I don't think it should be mandatory and if someone wants to write their own better one for their use cases it should be easy to ignore the default one.

NoelFB commented 8 months ago

I think the current implementation is "good enough" for now. If/once actual porting to non-desktop applications happens new issues can be created.