diff --git a/CMakeLists.txt b/CMakeLists.txt index 33c4056..55faded 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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 diff --git a/external/vfs/include/VirtualFileSystem.hpp b/external/vfs/include/VirtualFileSystem.hpp index 38d68ab..063a27d 100644 --- a/external/vfs/include/VirtualFileSystem.hpp +++ b/external/vfs/include/VirtualFileSystem.hpp @@ -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 diff --git a/source/javascript/module/file_system/FsJsModule.cpp b/source/javascript/module/file_system/FsJsModule.cpp deleted file mode 100644 index 7d7f823..0000000 --- a/source/javascript/module/file_system/FsJsModule.cpp +++ /dev/null @@ -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()) - )); -} diff --git a/source/javascript/module/file_system/FsJsModule.hpp b/source/javascript/module/file_system/FsJsModule.hpp deleted file mode 100644 index 5a8d8bc..0000000 --- a/source/javascript/module/file_system/FsJsModule.hpp +++ /dev/null @@ -1,23 +0,0 @@ -#pragma once - - -#include - -#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; - -}; diff --git a/source/javascript/module/file_system/README.md b/source/javascript/module/file_system/README.md deleted file mode 100644 index 8d30969..0000000 --- a/source/javascript/module/file_system/README.md +++ /dev/null @@ -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 -``` diff --git a/source/javascript/module/image/ImageJsModule.cpp b/source/javascript/module/image/ImageJsModule.cpp deleted file mode 100644 index 0d03068..0000000 --- a/source/javascript/module/image/ImageJsModule.cpp +++ /dev/null @@ -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)); -} diff --git a/source/javascript/module/image/ImageJsModule.hpp b/source/javascript/module/image/ImageJsModule.hpp deleted file mode 100644 index 61e0d9c..0000000 --- a/source/javascript/module/image/ImageJsModule.hpp +++ /dev/null @@ -1,22 +0,0 @@ -#pragma once - -#include - -#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); -}; diff --git a/source/javascript/module/image/object/ImageJsObject.cpp b/source/javascript/module/image/object/ImageJsObject.cpp deleted file mode 100644 index 7fc55b3..0000000 --- a/source/javascript/module/image/object/ImageJsObject.cpp +++ /dev/null @@ -1,20 +0,0 @@ -#include "ImageJsObject.hpp" - -#include - - -ImageJsObject::ImageJsObject(const QString& path) { - this->_internal = std::make_unique(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(); -} diff --git a/source/javascript/module/image/object/ImageJsObject.hpp b/source/javascript/module/image/object/ImageJsObject.hpp deleted file mode 100644 index 71ab820..0000000 --- a/source/javascript/module/image/object/ImageJsObject.hpp +++ /dev/null @@ -1,22 +0,0 @@ -#pragma once - -#include -#include - - -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 _internal; -}; - diff --git a/source/javascript/module/szs/.gitkeep b/source/javascript/module/szs/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/source/javascript/module/web/README.md b/source/javascript/module/web/README.md deleted file mode 100644 index 0ad8744..0000000 --- a/source/javascript/module/web/README.md +++ /dev/null @@ -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. - diff --git a/source/javascript/module/wit/.gitkeep b/source/javascript/module/wit/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/source/main.cpp b/source/main.cpp index 9f54d5d..b1e3b92 100644 --- a/source/main.cpp +++ b/source/main.cpp @@ -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(); + 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; } diff --git a/source/script/engine/Engine.cpp b/source/script/engine/Engine.cpp index ff9d9ce..1cb2fca 100644 --- a/source/script/engine/Engine.cpp +++ b/source/script/engine/Engine.cpp @@ -40,7 +40,14 @@ Engine::Engine() { RegisterScriptMath(this->asEngine); // Virtual file system - this->fileSystem = std::make_unique(); + 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 Engine::getFileSystem() const { +vfs::VirtualFileSystem* Engine::getFileSystem() const { return this->fileSystem; } diff --git a/source/script/engine/Engine.hpp b/source/script/engine/Engine.hpp index 507c772..6eb6381 100644 --- a/source/script/engine/Engine.hpp +++ b/source/script/engine/Engine.hpp @@ -32,11 +32,11 @@ public: * get the file system * @return the file system */ - [[nodiscard]] std::shared_ptr getFileSystem() const; + [[nodiscard]] vfs::VirtualFileSystem* getFileSystem() const; private: asIScriptEngine* asEngine; - std::shared_ptr fileSystem; + vfs::VirtualFileSystem* fileSystem; }; } diff --git a/source/script/module/filesystem/File.cpp b/source/script/module/filesystem/File.cpp index 65aa550..31fef29 100644 --- a/source/script/module/filesystem/File.cpp +++ b/source/script/module/filesystem/File.cpp @@ -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); } diff --git a/source/script/module/filesystem/File.hpp b/source/script/module/filesystem/File.hpp index e8a10ca..b96d075 100644 --- a/source/script/module/filesystem/File.hpp +++ b/source/script/module/filesystem/File.hpp @@ -6,16 +6,16 @@ #include #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; }; diff --git a/source/script/module/filesystem/FileSystem.cpp b/source/script/module/filesystem/FileSystem.cpp new file mode 100644 index 0000000..7d3fc5a --- /dev/null +++ b/source/script/module/filesystem/FileSystem.cpp @@ -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); +} + +} \ No newline at end of file diff --git a/source/script/module/filesystem/FileSystem.hpp b/source/script/module/filesystem/FileSystem.hpp new file mode 100644 index 0000000..4617173 --- /dev/null +++ b/source/script/module/filesystem/FileSystem.hpp @@ -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; +}; + +} diff --git a/source/script/module/filesystem/Path.cpp b/source/script/module/filesystem/Path.cpp index 61286ea..5102090 100644 --- a/source/script/module/filesystem/Path.cpp +++ b/source/script/module/filesystem/Path.cpp @@ -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> 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( - this->engine, + this->fileSystem, childVirtualPath ); childsPath.push_back(path); @@ -64,7 +64,7 @@ bool Path::isDirectory() const { std::shared_ptr Path::open(const std::string& mode, const std::string& encoding) { // create a new file object auto file = std::make_shared( - this->engine, + this->fileSystem, this->virtualPath ); // open it with the given mode @@ -127,5 +127,5 @@ std::vector Path::getComponents() const { } std::filesystem::path Path::getRealPath() const { - return this->engine->getFileSystem()->resolve(this->virtualPath); + return this->fileSystem->resolve(this->virtualPath); } \ No newline at end of file diff --git a/source/script/module/filesystem/Path.hpp b/source/script/module/filesystem/Path.hpp index b03b14d..7b17b4c 100644 --- a/source/script/module/filesystem/Path.hpp +++ b/source/script/module/filesystem/Path.hpp @@ -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; diff --git a/source/script/module/filesystem/_load.cpp b/source/script/module/filesystem/_load.cpp index b8f9538..fa5d527 100644 --- a/source/script/module/filesystem/_load.cpp +++ b/source/script/module/filesystem/_load.cpp @@ -1,38 +1,45 @@ #include "_load.hpp" -#include +#include #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); } } diff --git a/source/script/module/test/_load.cpp b/source/script/module/test/_load.cpp new file mode 100644 index 0000000..5ceccdd --- /dev/null +++ b/source/script/module/test/_load.cpp @@ -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); +} + +} \ No newline at end of file diff --git a/source/script/module/test/_load.hpp b/source/script/module/test/_load.hpp new file mode 100644 index 0000000..3005ec1 --- /dev/null +++ b/source/script/module/test/_load.hpp @@ -0,0 +1,20 @@ +#pragma once +#include + +#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); + +} \ No newline at end of file diff --git a/source/utils/angelscript/MixinAsReferenceCount.cpp b/source/utils/angelscript/MixinAsReferenceCount.cpp new file mode 100644 index 0000000..a0ab360 --- /dev/null +++ b/source/utils/angelscript/MixinAsReferenceCount.cpp @@ -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; +} + +} \ No newline at end of file diff --git a/source/utils/angelscript/MixinAsReferenceCount.hpp b/source/utils/angelscript/MixinAsReferenceCount.hpp new file mode 100644 index 0000000..5e8711d --- /dev/null +++ b/source/utils/angelscript/MixinAsReferenceCount.hpp @@ -0,0 +1,34 @@ +#pragma once + +#include + + +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; +}; + +} \ No newline at end of file