[ AmberSkyNet VR ]Из трёх переменных в разделе [Path] ini-файла DataPath, PluginsPath, LogPath на сегодняшний момент в движке не используется только одна - DataPath. А это значит - пора делать класс виртуальной файловой системы. IFileSystemДля начала - составим интерфейс:
class IFileSystem {
public:
// добавить путь к файлам
virtual bool AddPath(const std::string& Path, bool Recursive)=0;
// получить файл
virtual IFile *GetFile(const std::string& FileName)=0;
// добавляем источник файлов
// если FileSource=NULL - загружаем через систему плагинов
// иначе просто запоминаем с именем FileSourceName
virtual bool AddFileSource (const std::string& FileSourceName,IFileSource *FileSource)=0;
};
Функция AddPath добавляет путь к папке, в которой могут находиться
файлы, получаемые из файловой системы при выполнении функции GetFile. IFileSourceИнтерфейс IFileSource предназначен для реализации различных источников данных - файлы, хранящиеся напрямую в файловой системе, в архивах, в сети. Для каждого типа источника можно будет написать свой интерфейс и работа с ним будет одинакова в пределах видимости виртуальной файловой системы, а значит, и движка. class IFileSource {
public:
virtual IFile *LoadFile(const std::string& FileName)=0;
virtual void AddPath(const std::string& PathName, bool Recursive)=0;
};
IFileПри выполнении команды GetFile менеджера файловой системы мы получаем указатель на экземпляр класса, скрывающегося за интерфейсом IFile. Из-за наличия сетевого режима файл может быть в нескольких состояниях, например- не только на диске или в памяти, но и в процессе загрузки с сервера, причём на сервере его может не оказаться, но движок не может ждать пока сервер перешлёт все требуемые файлы на клиента, а должен отрисовывать то, что уже есть в наличии в локальной директории кэша. Отсюда возможные состояния файла несколько специфичны: enum asn_File_State{
ASN_FILE_NONE, //состояния нет (файл закрыт)
ASN_FILE_NOT_FOUND, //файл не найден (например, на сервере)
ASN_FILE_DISK_OPEN, //файл открыт на диске
ASN_FILE_DISK_IN_MEM, //файл загружен в память и закрыт на диске
ASN_FILE_WAIT, //файл ожидает загрузки
ASN_FILE_LOADING, //файл в процессе загрузки
};
А сам интерфейс класса файл выглядит следующим образом:
class IFile{
public:
//имя файла
virtual std::string GetName();
//состояние файла
virtual asn_File_State GetState()=0;
// открыть файл
virtual asn_File_State FileOpen()=0;
// закрыть файл
virtual void FileClose()=0;
// загрузить файл в память, на выходе - указатель на область
virtual void *LoadInMem()=0;
// освободить память
virtual void FreeMem()=0;
// передвинуть на позицию
virtual void Seek(unsigned int Position, int From)=0;
// получить размер файла в байтах;
virtual unsigned int GetSizeInBytes()=0;
// прочитать часть файла в буфер
virtual void ReadBuf(void *buf, unsigned int size)=0;
};
Мы может узнать состояние файла при помощи функции GetState(), а изменять состояния файла выполнением функций FileOpen,FileClose,LoadInMem.Вообще мне не очень нравится, конечно, что функционал как бы оказался размазаным по классам IFile и IFileSystem, однако я стремился сделать файлы более автономными и внешне не зависящими от файловой системы - иначе бы с появлением в IFileSystem функций наподобие CloseFile пришлось бы делать поиск по всем открытым файлам для нахождения нужного файла, который бы следовало закрыть. CFileSystemРеализация CFileSystem при создании читает переменную окружения [Paths]DataPath
и запоминает её у себя под именем SandBox :) Все данные, которые доступны
для чтения файловой системой располагаются не выше указанной папки.
Далее в переменных окружения находится переменная [FileManager]DataReader,
в которой перечислены через запятую все источники файлов (т.е. менеджеры загрузки
файлов из локального диска и архивов, например), используемые
при данном запуске системы. Пытаемся загрузить их при помощи системы
плагинов, после чего посылаем туда значение локальной перменной SandBox. CFileSystemASNКласс-надстройка над CFileSystem, добавляющая небольшой функционал - прежде начала поиска файла по всем известным путям он ищется в папке common. Это позволит нам использовать одни и те же ресурсы для разных миров, например - текстуры, звуки. Ах да, я же забыл вас ознакомить со структурой папки data. Так вот:
Менеджеры миров (которые на данный момент еще не реализованы) обращаясь к файловой системе будут использовать имена начинающиеся
с типа менеджера (local/net) и имени мира (например, HOME).
Скажем, если менеджер локального мира HOME захочет взять файл start.lua из своих
ресурсов он обратится к файловой системе с запросом GetGile("local/HOME/start.lua"); CFileSource, CFileКласс источника файлов CFileSource реализует возможность чтения файлов напрямую из физической файловой системы. При вызове функции LoadFile мы пытаемся найти и открыть файл по всем путям из списка, который формируется при выполнении функции AddPath. Если такой файл не найден - возвращем NULL, если найдет - создаём файл CFile, заполняем все необходимые в нём значения и возвращем указатель на него. Класс CFileSource "видит" все приватные переменные класса CFile, т.к. он является дружественным классу CFile. Класс файла CFile предоставляет доступ к файлу физической файловой системы и выполняет некоторые дисковые операции над ним - чтение из файла, загрузка в память. CFileSourceZIP, CFileZIPКласс источника файлов CFileSourceZIP реализует возможность чтения файлов
из архивов формата ZIP. При выполнении функции AddPath мы перебираем
все имеющиеся в указанной директории файлы и пытаеся загрузить их как ZIP-архив.
В случае удачи - читаем список файлов, хранящихся в данном архиве и запоминаем
его. При вызове функции LoadFile проводится поиск в списке известных
нам хранящихся в архиве файлов и в случае если такой файл найден - создаём
экземпляр класса CFileZIP, устанавливаем в нём необходимые переменные и
отправляем указатель на него. Взаимодействие с менеджером файловой системыEngine после разбора ini-файла читает значение переменной [Modules]FileManager и пытается загрузить через систему плагинов менеджер файловой системы с таким именем. Полученный указатель запоминается в указателях окружения с именем FileManager, получить извне доступ к нему можно например вот так: (IFileSystem*)ENGINE->GetPtrParam("FileManager");
или воспользоваться макросами, определёнными в файле IFileSystem.h
IFile *myFile=FILER->GetFile("test.txt");
Только нужно не забывать, что даже если мы получили экземпляр класса
IFile, он может быть в состоянии ASN_FILE_NOT_FOUND или
в состояниях отложенной загрузки - ASN_FILE_WAIT, ASN_FILE_LOADING.
Поэтому после получения указателя на файл неплохо было бы проверять
его состояние функцией GetState().
В дальнейшем, если в движке появятся менеджеры миров, функционал классов файловой системы будет возможно изменен, чтобы поиск происходил только среди общих ресурсов и ресурсов текущего мира.
Изменения в исходникахinclude/: Добавлен интерфейсы IFile.h, IFileSource.h, IFileSystem.h src/asnMain/: демонстрация работы менеджера файловой системы src/asnEngine/: добавлена инициализация менеджера файловой системы src/asnFileSystem/: Новый плагин - менеджер файловой системы. Чтение с диска, из архивов ZIP. Исходники этого шага выложены в SVN. Скачать их можно набрав команду: svn co https://svn.sourceforge.net/svnroot/ambernet/tags/AmberSkyNet-0.6 ambernet_0.6 |