added base for the FileSystem module in the AngelScript

This commit is contained in:
faraphel 2024-08-24 13:25:25 +02:00
parent 03a9833d21
commit 747c60aa22
26 changed files with 203 additions and 194 deletions

View file

@ -37,6 +37,12 @@ add_executable(Atlas-Launcher
source/script/module/filesystem/File.hpp
source/utils/file/openMode.cpp
source/utils/file/openMode.hpp
source/script/module/filesystem/FileSystem.cpp
source/script/module/filesystem/FileSystem.hpp
source/utils/angelscript/MixinAsReferenceCount.cpp
source/utils/angelscript/MixinAsReferenceCount.hpp
source/script/module/test/_load.cpp
source/script/module/test/_load.hpp
)
target_include_directories(Atlas-Launcher PRIVATE
# AngelScript

View file

@ -15,7 +15,7 @@ public:
explicit VirtualFileSystem();
~VirtualFileSystem();
std::filesystem::path getWorkingDirectory() const;
[[nodiscard]] std::filesystem::path getWorkingDirectory() const;
void setWorkingDirectory(const std::filesystem::path& virtualPath);
@ -37,7 +37,7 @@ public:
* @param virtualPath the virtual path
* @return the real path
*/
std::filesystem::path resolve(const std::filesystem::path& virtualPath) const;
[[nodiscard]] std::filesystem::path resolve(const std::filesystem::path& virtualPath) const;
private:
/// the internal temporary directory

View file

@ -1,15 +0,0 @@
#include "FsJsModule.hpp"
#include "object/FileJsObject.hpp"
#include "object/PathJsObject.hpp"
FsJsModule::FsJsModule(AtlasJsEngine* engine) : BaseJsModule(engine) {}
QJSValue FsJsModule::newPath(const QString& virtualPath) const {
// TODO(Faraphel): risk of memory leak ?
return this->engine->newQObject(new PathJsObject(
this->engine,
std::filesystem::path(virtualPath.toStdString())
));
}

View file

@ -1,23 +0,0 @@
#pragma once
#include <VirtualFileSystem.hpp>
#include "../_base/BaseJsModule.hpp"
class FsJsModule : public BaseJsModule {
Q_OBJECT
public:
explicit FsJsModule(AtlasJsEngine* engine);
// TODO(Faraphel): can a property "Path" redirect to the type directly ?
/**
* Create a new path object
* @param virtualPath the path as a String
* @return the path as a JavaScript object
*/
Q_INVOKABLE QJSValue newPath(const QString& virtualPath) const;
};

View file

@ -1,24 +0,0 @@
# Submodule "FileSystem"
> NOTE : This module is in an elaboration stage. Everything is subject to change !
This module allow the developer to access the game file to interact with them,
and additionally a temporary folder to store important data that might be reused
to speed up the patch process.
For security reason, you can only access file inside the virtual file system.
Here is an example of the virtual file system structure :
```tree
/
| game/
| | sys/
| | files/
| | ...
| assets/
| | my-texture.png
| | ...
| tmp/
| | patched-texture.tpl
```

View file

@ -1,11 +0,0 @@
#include "ImageJsModule.hpp"
#include "object/ImageJsObject.hpp"
ImageJsModule::ImageJsModule(AtlasJsEngine* engine) : BaseJsModule(engine) {}
QJSValue ImageJsModule::load(const QString& path) {
// TODO(Faraphel): can the new lead to a memory leak ?
return this->engine->newQObject(new ImageJsObject(path));
}

View file

@ -1,22 +0,0 @@
#pragma once
#include <QJSValue>
#include "../_base/BaseJsModule.hpp"
/**
* A module to manipulate image file
*/
class ImageJsModule : public BaseJsModule {
Q_OBJECT
public:
explicit ImageJsModule(AtlasJsEngine* engine);
/**
* Load an image file
* @param
*/
Q_INVOKABLE QJSValue load(const QString& path);
};

View file

@ -1,20 +0,0 @@
#include "ImageJsObject.hpp"
#include <QImage>
ImageJsObject::ImageJsObject(const QString& path) {
this->_internal = std::make_unique<QImage>(path);
}
std::size_t ImageJsObject::getWidth() {
return this->_internal->width();
}
std::size_t ImageJsObject::getHeight() {
return this->_internal->height();
}
QSize ImageJsObject::getSize() {
return this->_internal->size();
}

View file

@ -1,22 +0,0 @@
#pragma once
#include <QObject>
#include <QImage>
class ImageJsObject : public QObject {
Q_OBJECT
public:
explicit ImageJsObject(const QString& path);
Q_INVOKABLE std::size_t getWidth();
Q_INVOKABLE std::size_t getHeight();
Q_INVOKABLE QSize getSize();
// TODO(Faraphel): implement copy / paste, fill, shapes, mirror, resize, expand, shrink, crop, map...
private:
std::unique_ptr<QImage> _internal;
};

View file

@ -1,7 +0,0 @@
# Submodule "Web"
> This module will allow the developer to access data on the web.
> It shall be very careful about the security and will require a
> special authorisation by the user to access any url.
> As of right now, it is in a stage of idea.

View file

@ -9,18 +9,20 @@
#include "script/engine/Engine.hpp"
#include "script/module/debug/_load.hpp"
#include "script/module/filesystem/_load.hpp"
#include "script/module/test/_load.hpp"
int main_AngelScript(int argc, char* argv[]) {
int error;
// engine
const auto atlasEngine = std::make_unique<atlas::script::engine::Engine>();
const auto* atlasEngine = new atlas::script::engine::Engine();
auto* asEngine = atlasEngine->getAsEngine();
// functions
atlas::script::module::debug::load(atlasEngine.get());
atlas::script::module::filesystem::load(atlasEngine.get());
// atlas::script::module::test::load(atlasEngine);
atlas::script::module::debug::load(atlasEngine);
atlas::script::module::filesystem::load(atlasEngine);
// script
CScriptBuilder builder;
@ -59,6 +61,8 @@ int main_AngelScript(int argc, char* argv[]) {
// clean up
context->Release();
delete atlasEngine;
return error;
}

View file

@ -40,7 +40,14 @@ Engine::Engine() {
RegisterScriptMath(this->asEngine);
// Virtual file system
this->fileSystem = std::make_unique<vfs::VirtualFileSystem>();
this->fileSystem = new vfs::VirtualFileSystem();
}
Engine::~Engine() {
// release the engine
this->asEngine->ShutDownAndRelease();
// free the file system
delete this->fileSystem;
}
void Engine::asCallback(const asSMessageInfo *message, void *args) {
@ -73,16 +80,11 @@ void Engine::asCallback(const asSMessageInfo *message, void *args) {
) << std::endl;
}
Engine::~Engine() {
// release the engine
this->asEngine->ShutDownAndRelease();
}
asIScriptEngine* Engine::getAsEngine() const {
return this->asEngine;
}
std::shared_ptr<vfs::VirtualFileSystem> Engine::getFileSystem() const {
vfs::VirtualFileSystem* Engine::getFileSystem() const {
return this->fileSystem;
}

View file

@ -32,11 +32,11 @@ public:
* get the file system
* @return the file system
*/
[[nodiscard]] std::shared_ptr<vfs::VirtualFileSystem> getFileSystem() const;
[[nodiscard]] vfs::VirtualFileSystem* getFileSystem() const;
private:
asIScriptEngine* asEngine;
std::shared_ptr<vfs::VirtualFileSystem> fileSystem;
vfs::VirtualFileSystem* fileSystem;
};
}

View file

@ -3,8 +3,8 @@
#include "utils/file/openMode.hpp"
File::File(const atlas::script::engine::Engine* engine, const std::filesystem::path& virtualPath) {
this->engine = engine;
File::File(const vfs::VirtualFileSystem* fileSystem, const std::filesystem::path& virtualPath) {
this->fileSystem = fileSystem;
this->virtualPath = virtualPath;
}
@ -60,6 +60,6 @@ void File::close() {
std::filesystem::path File::getRealPath() const {
// get the real path from the internal virtual path
return this->engine->getFileSystem()->resolve(this->virtualPath);
return this->fileSystem->resolve(this->virtualPath);
}

View file

@ -6,16 +6,16 @@
#include <fstream>
#include "script/engine/Engine.hpp"
#include "utils/angelscript/MixinAsReferenceCount.hpp"
/**
* Represent a JavaScript file.
* This is a wrapper around `QFile`
* Represent a file in the Atlas engine
*/
class File {
class File : public atlas::utils::angelscript::MixinAsReferenceCount {
public:
explicit File(const atlas::script::engine::Engine* engine, const std::filesystem::path& virtualPath);
explicit File(const vfs::VirtualFileSystem* fileSystem, const std::filesystem::path& virtualPath);
/**
* Open the file to access its content.
@ -61,7 +61,7 @@ private:
std::filesystem::path virtualPath;
/// the Atlas engine
const atlas::script::engine::Engine* engine;
const vfs::VirtualFileSystem* fileSystem;
/// the internal file streamer
std::fstream stream;
};

View file

@ -0,0 +1,13 @@
#include "FileSystem.hpp"
namespace atlas::script::module::filesystem {
FileSystem::FileSystem(const vfs::VirtualFileSystem* fileSystem) {
this->fileSystem = fileSystem;
}
Path* FileSystem::getPath(const std::string &virtualPath) const {
return new Path(this->fileSystem, virtualPath);
}
}

View file

@ -0,0 +1,19 @@
#pragma once
#include "Path.hpp"
namespace atlas::script::module::filesystem {
/**
* Represent a File System in the Atlas engine
*/
class FileSystem : public utils::angelscript::MixinAsReferenceCount {
public:
explicit FileSystem(const vfs::VirtualFileSystem* fileSystem);
[[nodiscard]] Path* getPath(const std::string& virtualPath) const;
private:
const vfs::VirtualFileSystem* fileSystem;
};
}

View file

@ -5,15 +5,15 @@
#include "exception/FileNotFoundException.hpp"
Path::Path(const atlas::script::engine::Engine* engine, const std::filesystem::path& virtualPath) {
this->engine = engine;
Path::Path(const vfs::VirtualFileSystem* fileSystem, const std::filesystem::path& virtualPath) {
this->fileSystem = fileSystem;
this->virtualPath = virtualPath;
}
Path Path::getParent() const {
// return the parent directory
return Path(
this->engine,
this->fileSystem,
this->virtualPath.parent_path()
);
}
@ -40,7 +40,7 @@ std::vector<std::shared_ptr<Path>> Path::getChildrens(const bool recursive, cons
std::filesystem::path childVirtualPath = this->virtualPath / childRealPath.filename();
// add it to the list of childrens
auto path = std::make_shared<Path>(
this->engine,
this->fileSystem,
childVirtualPath
);
childsPath.push_back(path);
@ -64,7 +64,7 @@ bool Path::isDirectory() const {
std::shared_ptr<File> Path::open(const std::string& mode, const std::string& encoding) {
// create a new file object
auto file = std::make_shared<File>(
this->engine,
this->fileSystem,
this->virtualPath
);
// open it with the given mode
@ -127,5 +127,5 @@ std::vector<std::string> Path::getComponents() const {
}
std::filesystem::path Path::getRealPath() const {
return this->engine->getFileSystem()->resolve(this->virtualPath);
return this->fileSystem->resolve(this->virtualPath);
}

View file

@ -5,16 +5,17 @@
#include "File.hpp"
#include "script/engine/Engine.hpp"
#include "utils/angelscript/MixinAsReferenceCount.hpp"
/**
* Represent a virtual file system path
* Represent a virtual file system path in the Atlas engine
* Similar to the pathlib library in Python
*/
class Path {
class Path : public atlas::utils::angelscript::MixinAsReferenceCount {
public:
explicit Path(const atlas::script::engine::Engine* engine, const std::filesystem::path& virtualPath);
explicit Path(const vfs::VirtualFileSystem* fileSystem, const std::filesystem::path& virtualPath);
// browse
@ -101,7 +102,7 @@ public:
private:
/// the JavaScript engine
const atlas::script::engine::Engine* engine;
const vfs::VirtualFileSystem* fileSystem;
/// the virtual path
std::filesystem::path virtualPath;

View file

@ -1,38 +1,45 @@
#include "_load.hpp"
#include <stdexcept>
#include <cassert>
#include "Path.hpp"
#include "FileSystem.hpp"
namespace atlas::script::module::filesystem {
Path* pathFactory(const engine::Engine* atlasEngine, const std::string& virtualPath) {
return new Path(atlasEngine, virtualPath);
};
void load(const engine::Engine* atlasEngine) {
asIScriptEngine* asEngine = atlasEngine->getAsEngine();
auto fileSystem = atlasEngine->getFileSystem();
auto* fileSystem = new FileSystem(atlasEngine->getFileSystem());
int error;
// start namespace
error = asEngine->SetDefaultNamespace("atlas::filesystem");
if (error < 0)
throw std::runtime_error("Could not enter the \"atlas::filesystem\" namespace.");
error = asEngine->SetDefaultNamespace("atlas::filesystem"); assert(error >= 0);
// TODO(Faraphel): register the Path and File types
error = asEngine->RegisterGlobalProperty("int Path::FileSystem", fileSystem.get());
// file type
error = asEngine->RegisterObjectType("File", 0, asOBJ_REF); assert(error >= 0);
error = asEngine->RegisterObjectBehaviour("File", asBEHAVE_ADDREF, "void f()", asMETHOD(File, asAddReference), asCALL_THISCALL); assert(error >= 0);
error = asEngine->RegisterObjectBehaviour("File", asBEHAVE_RELEASE, "void f()", asMETHOD(File, asRelease), asCALL_THISCALL); assert(error >= 0);
// error = asEngine->RegisterObjectType("Path", 0, asOBJ_REF);
// error = asEngine->RegisterObjectBehaviour("Path", asBEHAVE_FACTORY, "Path@ f(const string& in)", asFUNCTION(pathFactory), asCALL_CDECL);
// error = asEngine->RegisterObjectMethod("Path", "Path@ getParent() const", asMETHOD(Path, getParent), asCALL_THISCALL);
// error = asEngine->RegisterObjectMethod("Path", "bool exists() const", asMETHOD(Path, exists), asCALL_THISCALL);
// path type
error = asEngine->RegisterObjectType("Path", 0, asOBJ_REF); assert(error >= 0);
error = asEngine->RegisterObjectBehaviour("Path", asBEHAVE_ADDREF, "void f()", asMETHOD(Path, asAddReference), asCALL_THISCALL); assert(error >= 0);
error = asEngine->RegisterObjectBehaviour("Path", asBEHAVE_RELEASE, "void f()", asMETHOD(Path, asRelease), asCALL_THISCALL); assert(error >= 0);
error = asEngine->RegisterObjectMethod("Path", "Path@ getParent() const", asMETHOD(Path, getParent), asCALL_THISCALL); assert(error >= 0);
error = asEngine->RegisterObjectMethod("Path", "bool exists() const", asMETHOD(Path, exists), asCALL_THISCALL); assert(error >= 0);
// file system type
error = asEngine->RegisterObjectType("FileSystem", 0, asOBJ_REF); assert(error >= 0);
error = asEngine->RegisterObjectBehaviour("FileSystem", asBEHAVE_ADDREF, "void f()", asMETHOD(FileSystem, asAddReference), asCALL_THISCALL); assert(error >= 0);
error = asEngine->RegisterObjectBehaviour("FileSystem", asBEHAVE_RELEASE, "void f()", asMETHOD(FileSystem, asRelease), asCALL_THISCALL); assert(error >= 0);
error = asEngine->RegisterObjectMethod("FileSystem", "Path@ getPath(const string& in) const", asMETHOD(FileSystem, getPath), asCALL_THISCALL); assert(error >= 0);
// file system singleton
error = asEngine->RegisterGlobalProperty("const FileSystem fileSystem", fileSystem); assert(error >= 0);
// end namespace
error = asEngine->SetDefaultNamespace("");
if (error < 0)
throw std::runtime_error("Could not reset the namespace.");
error = asEngine->SetDefaultNamespace(""); assert(error >= 0);
}
}

View file

@ -0,0 +1,24 @@
#include "_load.hpp"
namespace atlas::script::module::test {
void Test::test() {
std::cout << "test" << std::endl;
}
Test* testFactory() {
return new Test();
}
void load(const engine::Engine* engine) {
auto* asEngine = engine->getAsEngine();
asEngine->RegisterObjectType("Test", 0, asOBJ_REF);
asEngine->RegisterObjectBehaviour("Test", asBEHAVE_FACTORY, "Test@ f()", asFUNCTION(testFactory), asCALL_CDECL);
asEngine->RegisterObjectBehaviour("Test", asBEHAVE_ADDREF, "void f()", asMETHOD(Test, asAddReference), asCALL_THISCALL);
asEngine->RegisterObjectBehaviour("Test", asBEHAVE_RELEASE, "void f()", asMETHOD(Test, asRelease), asCALL_THISCALL);
asEngine->RegisterObjectMethod("Test", "void test()", asMETHOD(Test, test), asCALL_THISCALL);
}
}

View file

@ -0,0 +1,20 @@
#pragma once
#include <iostream>
#include "script/engine/Engine.hpp"
#include "utils/angelscript/MixinAsReferenceCount.hpp"
namespace atlas::script::module::test {
class Test : public utils::angelscript::MixinAsReferenceCount {
public:
void test();
};
Test* testFactory();
void load(const engine::Engine* engine);
}

View file

@ -0,0 +1,23 @@
//
// Created by faraphel on 23/08/24.
//
#include "MixinAsReferenceCount.hpp"
namespace atlas::utils::angelscript {
MixinAsReferenceCount::MixinAsReferenceCount() {
this->referenceCount = 1;
}
void MixinAsReferenceCount::asAddReference() {
this->referenceCount++;
}
void MixinAsReferenceCount::asRelease() {
if (--this->referenceCount <= 0)
delete this;
}
}

View file

@ -0,0 +1,34 @@
#pragma once
#include <cstddef>
namespace atlas::utils::angelscript {
/**
* A Mixin class to automatically implement the reference counting mechanism
* required for the AngelScript interpreter to run the garbage collector
*/
class MixinAsReferenceCount {
public:
MixinAsReferenceCount();
/**
* Called when the object is used in another reference.
*/
void asAddReference();
/**
* Called when the object shall be freed.
*/
void asRelease();
private:
/** the reference count of the object.
* once it reaches zero, this imply object is no longuer used
* and should be destroyed.
*/
std::size_t referenceCount;
};
}