[ 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 |