using SFML.Audio;
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
namespace Otter {
///
/// Manages files used for game assets. Can use a packed data file of paths and byte arrays.
/// The game will attempt to use local files before the packed data file.
/// Packed data is expected as:
/// bool: true to continue reading, false to stop
/// string: the path of the file that was packed
/// int32: the size of the file that was packed
/// bytes: the actual data from the file
///
public class Files {
///
/// The unpacked data from a packed data file. File paths mapped to byte arrays.
///
public static Dictionary Data = new Dictionary();
///
/// The root folder that assets can be found in when loading data.
///
public static string AssetsFolderPrefix = "Assets/";
///
/// Reads data from a uncompressed packed file
///
/// The path to the packed data file.
public static void LoadPackedData(string path) {
if (!File.Exists(path)) throw new FileNotFoundException("Cannot find packed data file " + path);
Data.Clear();
var bytes = new BinaryReader(File.Open(path, FileMode.Open));
int length = (int)bytes.BaseStream.Length;
var reading = bytes.ReadBoolean();
while (reading) {
var filepath = bytes.ReadString();
var fileSize = bytes.ReadInt32();
var data = bytes.ReadBytes(fileSize);
Data.Add(filepath, data);
//Console.WriteLine("Reading data {0}", filepath);
reading = bytes.ReadBoolean();
}
}
///
/// Check if a file exists, or if it has been loaded from the packed data.
///
/// The path to check.
/// True if the file exists or if it has been loaded from the packed data.
public static bool FileExists(string path) {
if (File.Exists(path)) return true;
if (File.Exists(AssetsFolderPrefix + path)) return true;
if (Data.ContainsKey(path)) return true;
return false;
}
///
/// Load a file as a memory stream from local files or packed data.
/// Probably don't use this a lot it probably is memory leak city.
///
/// The path to load from.
/// The stream.
public static Stream LoadFileStream(string path) {
if (FileExists(path)) {
return new MemoryStream(LoadFileBytes(path));
}
return null;
}
///
/// Load a file as a byte array from local files or packed data.
///
/// The path to load from.
/// The byte array of the data from the file.
public static byte[] LoadFileBytes(string path) {
if (File.Exists(path)) {
return File.ReadAllBytes(path);
}
if (File.Exists(AssetsFolderPrefix + path)) {
return File.ReadAllBytes(AssetsFolderPrefix + path);
}
if (Data.ContainsKey(path)) {
return Data[path];
}
return null;
}
///
/// Check if a file is being loaded from a local file or the packed data.
/// Note that the game will attempt to load from local files before packed data.
///
/// The path to check.
/// True if the data is coming from the packed file.
public static bool IsUsingDataPack(string path) {
if (File.Exists(path)) return false;
if (File.Exists(AssetsFolderPrefix + path)) return false;
return Data.ContainsKey(path);
}
}
#region Sounds
///
/// Class that manages the cache of sounds.
///
class Sounds {
static Dictionary sounds = new Dictionary();
public static SoundBuffer Load(string path) {
//if (!File.Exists(source)) throw new FileNotFoundException(source + " not found.");
if (!Files.FileExists(path)) throw new FileNotFoundException(path + " not found.");
if (sounds.ContainsKey(path)) {
return sounds[path];
}
sounds.Add(path, new SoundBuffer(Files.LoadFileBytes(path)));
return sounds[path];
}
}
#endregion
#region Fonts
///
/// Class that manages the cache of fonts.
///
class Fonts {
static Dictionary fonts = new Dictionary();
static Dictionary fontsStreamed = new Dictionary();
public static SFML.Graphics.Font DefaultFont {
get {
if (defaultFont == null) {
defaultFont = Load(System.Reflection.Assembly.GetExecutingAssembly().GetManifestResourceStream("Otter.CONSOLA.TTF"));
}
return defaultFont;
}
}
static SFML.Graphics.Font defaultFont;
internal static SFML.Graphics.Font Load(string path) {
//if (!File.Exists(source)) throw new FileNotFoundException(source + " not found.");
if (!Files.FileExists(path)) throw new FileNotFoundException(path + " not found.");
if (fonts.ContainsKey(path)) {
//return new SFML.Graphics.Font(Files.LoadFileBytes(path));
return fonts[path];
}
if (Files.IsUsingDataPack(path)) {
var stream = new MemoryStream(Files.LoadFileBytes(path));
fonts.Add(path, new SFML.Graphics.Font(stream)); // SFML fix? Might be memory leaking when you have a lot of fonts.
//stream.Close();
//fonts.Add(path, new SFML.Graphics.Font(Files.LoadFileBytes(path))); // SFML fix?
}
else {
if (File.Exists(path)) {
fonts.Add(path, new SFML.Graphics.Font(path)); // Cant load font with bytes from path?
}
else { // This should work because we already checked FileExists above
fonts.Add(path, new SFML.Graphics.Font(Files.AssetsFolderPrefix + path)); // Cant load font with bytes from path?
}
}
return fonts[path];
}
internal static SFML.Graphics.Font Load(Stream stream) {
if (fontsStreamed.ContainsKey(stream)) {
return fontsStreamed[stream];
}
fontsStreamed.Add(stream, new SFML.Graphics.Font(stream));
return Load(stream);
}
}
#endregion
///
/// Class that manages the cache of Textures.
///
public class Textures {
#region Static Fields
static Dictionary textures = new Dictionary();
static Dictionary texturesStreamed = new Dictionary();
#endregion
#region Static Methods
///
/// This doesn't really work right now. Textures in images wont update
/// if you do this.
///
///
public static void Reload(string path) {
textures.Remove(path);
Load(path);
}
///
/// This doesn't work right now. Textures in images wont update if you
/// do this.
///
public static void ReloadAll() {
var keys = textures.Keys;
textures.Clear();
foreach (var k in keys) {
Load(k);
}
}
#endregion
#region Internal
internal static SFML.Graphics.Texture Load(string path) {
//if (!File.Exists(source)) throw new FileNotFoundException("Texture path " + source + " not found.");
if (!Files.FileExists(path)) throw new FileNotFoundException("Texture path " + path + " not found.");
if (textures.ContainsKey(path)) {
return textures[path];
}
textures.Add(path, new SFML.Graphics.Texture(Files.LoadFileBytes(path)));
return textures[path];
}
internal static SFML.Graphics.Texture Load(Stream stream) {
if (texturesStreamed.ContainsKey(stream)) {
return texturesStreamed[stream];
}
texturesStreamed.Add(stream, new SFML.Graphics.Texture(stream));
return texturesStreamed[stream];
}
#endregion
}
}