/* * GDevelop Core * Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights * reserved. Copyright 2016 Victor Levasseur (victorlevasseur52@gmail.com) This * project is released under the MIT License. */ #pragma once #include #include #include #include "GDCore/CommonTools.h" #include "GDCore/Extensions/Metadata/BehaviorMetadata.h" #include "GDCore/Extensions/Metadata/DependencyMetadata.h" #include "GDCore/Extensions/Metadata/EffectMetadata.h" #include "GDCore/Extensions/Metadata/EventMetadata.h" #include "GDCore/Extensions/Metadata/InstructionOrExpressionGroupMetadata.h" #include "GDCore/Extensions/Metadata/ObjectMetadata.h" #include "GDCore/Extensions/Metadata/SourceFileMetadata.h" #include "GDCore/Project/PropertyDescriptor.h" #include "GDCore/String.h" #include "GDCore/Tools/VersionPriv.h" namespace gd { class Instruction; class InstructionMetadata; class MultipleInstructionMetadata; class ExpressionMetadata; class ObjectMetadata; class BehaviorMetadata; class EffectMetadata; class DependencyMetadata; class BaseEvent; class EventMetadata; class EventCodeGenerator; class ArbitraryResourceWorker; class BehaviorsSharedData; class Behavior; class Object; class ObjectConfiguration; } // namespace gd typedef std::function()> CreateFunPtr; namespace gd { /** * \brief Class used by gd::PlatformExtension to ensure that an extension is * compiled against the right versions of libraries. */ class GD_CORE_API CompilationInfo { public: CompilationInfo() {}; virtual ~CompilationInfo() {}; bool informationCompleted = false; bool runtimeOnly = false; ///< True if the extension was compiled for a ///< runtime use only #if defined(__GNUC__) int gccMajorVersion = 0; int gccMinorVersion = 0; int gccPatchLevel = 0; #endif int sfmlMajorVersion = 0; int sfmlMinorVersion = 0; gd::String gdCoreVersion; int sizeOfpInt = 0; }; struct GD_CORE_API DuplicatedInstructionOptions { bool unscoped; }; /** * \brief Base class for implementing platform's extensions. * * \ingroup PlatformDefinition */ class GD_CORE_API PlatformExtension { public: CompilationInfo compilationInfo; PlatformExtension(); virtual ~PlatformExtension(); /** \name Extension setup * Common setup for all extensions */ ///@{ /** * \brief Must be called to declare the main information about the extension. */ PlatformExtension& SetExtensionInformation(const gd::String& name_, const gd::String& fullname_, const gd::String& description_, const gd::String& author_, const gd::String& license_); /** * \brief Set the URL of the extension icon. */ PlatformExtension& SetIconUrl(const gd::String& iconUrl_) { iconUrl = iconUrl_; return *this; } /** * \brief Set a short description for the extension, used by AI/LLM agents. */ PlatformExtension& SetShortDescription(const gd::String& shortDescription_) { shortDescription = shortDescription_; return *this; } /** * \brief Set the dimension of the extension ("2D", "3D", "2D/3D" or empty). */ PlatformExtension& SetDimension(const gd::String& dimension_) { dimension = dimension_; return *this; } /** * \brief Set the category of the extension. */ PlatformExtension& SetCategory(const gd::String& category_) { category = category_; return *this; } /** * \brief Set the path to the help, relative to the GDevelop documentation * root. For example, "/all-features/collisions" for * "https://wiki.gdevelop.io/gdevelop5/all-features/collisions". * * The instructions, objects and behaviors will have this help path set by * default, unless you call SetHelpPath on them. */ PlatformExtension& SetExtensionHelpPath(const gd::String& helpPath_) { helpPath = helpPath_; return *this; } /** * \brief Mark this extension as deprecated: the IDE will hide it from the * user. */ void MarkAsDeprecated() { deprecated = true; } ///@} /** \name Features declaration * Declare features provided by the extension */ ///@{ /** * \brief Declare a new condition as being part of the extension. */ gd::InstructionMetadata& AddCondition(const gd::String& name_, const gd::String& fullname_, const gd::String& description_, const gd::String& sentence_, const gd::String& group_, const gd::String& icon_, const gd::String& smallicon_); /** * \brief Declare a new action as being part of the extension. */ gd::InstructionMetadata& AddAction(const gd::String& name_, const gd::String& fullname_, const gd::String& description_, const gd::String& sentence_, const gd::String& group_, const gd::String& icon_, const gd::String& smallicon_); /** * \brief Declare a new expression as being part of the extension. */ gd::ExpressionMetadata& AddExpression(const gd::String& name_, const gd::String& fullname_, const gd::String& description_, const gd::String& group_, const gd::String& smallicon_); /** * \brief Declare a new string expression as being part of the extension. */ gd::ExpressionMetadata& AddStrExpression(const gd::String& name_, const gd::String& fullname_, const gd::String& description_, const gd::String& group_, const gd::String& smallicon_); /** * \brief Declare a new expression and condition as being part of the * extension. * \note It's recommended to use this function to avoid declaring twice a * similar expression/condition. */ gd::MultipleInstructionMetadata AddExpressionAndCondition( const gd::String& type, const gd::String& name, const gd::String& fullname, const gd::String& description, const gd::String& sentenceName, const gd::String& group, const gd::String& icon); /** * \brief Declare a new expression, condition and action as being part of the * extension. * \note The action name is prefixed by "Set" (and the namespace, as the * condition and the expression). * \note It's recommended to use this function to avoid declaring 3 times a * similar expression/condition/action. */ gd::MultipleInstructionMetadata AddExpressionAndConditionAndAction( const gd::String& type, const gd::String& name, const gd::String& fullname, const gd::String& description, const gd::String& sentenceName, const gd::String& group, const gd::String& icon); gd::DependencyMetadata& AddDependency(); gd::SourceFileMetadata& AddSourceFile(); /** * \brief Declare a new object as being part of the extension. * \tparam T the declared class inherited from *gd::Object* * \param name The name of the object. * \param fullname The user friendly name of the object. * \param description The user friendly description of the object. * \param icon The icon of the object. */ template gd::ObjectMetadata& AddObject(const gd::String& name_, const gd::String& fullname_, const gd::String& description_, const gd::String& icon_); /** * \brief Declare a new object as being part of the extension. * \param name The name of the object * \param fullname The user friendly name of the object * \param description The user friendly description of the object * \param icon The icon of the object. * \param instance The "blueprint" object to be copied when a new object is asked for. */ gd::ObjectMetadata& AddObject( const gd::String& name_, const gd::String& fullname_, const gd::String& description_, const gd::String& icon_, std::shared_ptr instance); /** * \brief Declare a new events based object as being part of the extension. * * \param name The name of the object * \param fullname The user friendly name of the object * \param description The user friendly description of the object * \param icon The icon of the object. */ gd::ObjectMetadata& AddEventsBasedObject(const gd::String& name_, const gd::String& fullname_, const gd::String& description_, const gd::String& icon_); /** * \brief Declare a new behavior as being part of the extension. * * \param name The name of the behavior * \param fullname The user friendly name of the behavior * \param defaultName The default name of behavior instances * \param description The user friendly description of the behavior * \param group The behavior category label * \param icon The icon of the behavior. * \param className The name of the class implementing the behavior * \param instance An instance of the behavior that * will be used to create the behavior * \param sharedDatasInstance Optional * instance of the data shared by the behaviors having the same name. */ gd::BehaviorMetadata& AddBehavior( const gd::String& name_, const gd::String& fullname_, const gd::String& defaultName_, const gd::String& description_, const gd::String& group_, const gd::String& icon_, const gd::String& className_, std::shared_ptr instance, std::shared_ptr sharedDatasInstance); /** * \brief Declare a new effect as being part of the extension. * \param name The internal name of the effect (also called effect type). */ gd::EffectMetadata& AddEffect(const gd::String& name_); /** * \brief Declare a new event as being part of the extension. */ gd::EventMetadata& AddEvent(const gd::String& name_, const gd::String& fullname_, const gd::String& description_, const gd::String& group_, const gd::String& smallicon_, std::shared_ptr instance); /** * \brief Create a new action which is the duplicate of the specified one. * * Useful for handling a deprecated action that is just a "copy" of the new * one. */ gd::InstructionMetadata& AddDuplicatedAction( const gd::String& newActionName, const gd::String& copiedActionName); /** * \brief Create a new condition which is the duplicate of the specified one. * * Useful for handling a deprecated condition that is just a "copy" of the new * one. */ gd::InstructionMetadata& AddDuplicatedCondition( const gd::String& newConditionName, const gd::String& copiedConditionName, gd::DuplicatedInstructionOptions options = {.unscoped = false}); /** * \brief Create a new expression which is the duplicate of the specified one. * * Useful for handling a deprecated expression that is just a "copy" of the * new one. */ gd::ExpressionMetadata& AddDuplicatedExpression( const gd::String& newExpressionName, const gd::String& copiedExpressionName); /** * \brief Create a new string expression which is the duplicate of the * specified one. * * Useful for handling a deprecated string expression that is just a "copy" of * the new one. */ gd::ExpressionMetadata& AddDuplicatedStrExpression( const gd::String& newExpressionName, const gd::String& copiedExpressionName); /** * \brief Adds a property to the extension. */ gd::PropertyDescriptor& RegisterProperty(const gd::String& name) { return extensionPropertiesMetadata[name]; }; /** * \brief Add some metadata (icon, etc...) for a group used for instructions * or expressions. */ InstructionOrExpressionGroupMetadata& AddInstructionOrExpressionGroupMetadata( const gd::String& name) { return instructionOrExpressionGroupMetadata[name]; } /** * \brief Delete all instructions having no function name or custom code * generator. */ void StripUnimplementedInstructionsAndExpressions(); /** * \brief Declare a new resource to be used in the in-game editor. */ InGameEditorResourceMetadata& AddInGameEditorResource() { InGameEditorResourceMetadata newInGameEditorResource; inGameEditorResources.push_back(newInGameEditorResource); return inGameEditorResources.back(); } ///@} /** \name Extension accessors * Accessors to read the information and content of the extension. */ ///@{ /** * \brief Return the name extension user friendly name. */ const gd::String& GetFullName() const { return fullname; } /** * \brief Return the name of the extension */ const gd::String& GetName() const { return name; } /** * \brief Return the category of the extension */ const gd::String& GetCategory() const { return category; } /** * \brief Return a description of the extension */ const gd::String& GetDescription() const { return informations; } /** * \brief Return a short description of the extension, used by AI/LLM agents. */ const gd::String& GetShortDescription() const { return shortDescription; } /** * \brief Return the dimension of the extension ("2D", "3D", "2D/3D" or empty). */ const gd::String& GetDimension() const { return dimension; } /** * \brief Return the name of the extension developer */ const gd::String& GetAuthor() const { return author; } /** * \brief Return the name of extension license */ const gd::String& GetLicense() const { return license; } /** * \brief Return the help path of extension, relative to the * GDevelop documentation root. */ const gd::String& GetHelpPath() const { return helpPath; } /** * \brief Return the URL to the icon to be displayed for this * extension. */ const gd::String& GetIconUrl() const { return iconUrl; } /** * \brief Return keywords that help search engines find this extension. */ const std::vector& GetTags() const { return tags; } /** * \brief Set keywords that help search engines find this extension. */ PlatformExtension& SetTags(const gd::String& csvTags) { tags.clear(); tags = csvTags.Split(','); for (size_t i = 0; i < tags.size(); i++) { tags[i] = tags[i].Trim().LowerCase(); } return *this; } /** * \brief Add a keyword that help search engines find this extension. */ PlatformExtension& AddTag(const gd::String& tag) { tags.push_back(tag); return *this; } /** * \brief Check if the extension is flagged as being deprecated. */ bool IsDeprecated() const { return deprecated; } /** * \brief Get the namespace of the extension. * \note The namespace is simply the name of the extension concatenated with * "::" at the end. */ const gd::String& GetNameSpace() { return nameSpace; }; /** * \brief Return a vector containing all the object types provided by the * extension */ std::vector GetExtensionObjectsTypes() const; /** * \brief Return a vector containing all the behavior types provided by the * extension */ std::vector GetBehaviorsTypes() const; /** * \brief Return a function to create the object if the type is handled by the * extension */ CreateFunPtr GetObjectCreationFunctionPtr(const gd::String& objectType) const; /** * \brief Return a vector containing all the effect types provided by the * extension. */ std::vector GetExtensionEffectTypes() const; /** * \brief Create a custom event. * * Return an empty pointer if \a eventType is not provided by the extension. */ std::shared_ptr CreateEvent(const gd::String& eventType) const; /** * \brief Get the gd::Behavior handling the given behavior type. * * Return nullptr if \a behaviorType is not provided by the extension. */ gd::Behavior* GetBehavior(const gd::String& behaviorType) const; /** * \brief Get the gd::BehaviorsSharedData handling the given behavior shared * data. * * Return nullptr if \a behaviorType is not provided by the extension. */ gd::BehaviorsSharedData* GetBehaviorSharedDatas( const gd::String& behaviorType) const; /** * \brief Return a reference to the ObjectMetadata object associated to \a * objectType */ ObjectMetadata& GetObjectMetadata(const gd::String& objectType); /** * \brief Return a reference to the BehaviorMetadata object associated to \a * behaviorType */ BehaviorMetadata& GetBehaviorMetadata(const gd::String& behaviorType); /** * \brief Return true if the extension contains a behavior associated to \a * behaviorType */ bool HasBehavior(const gd::String& behaviorType) const; /** * \brief Return the metadata for the effect with the given name. */ EffectMetadata& GetEffectMetadata(const gd::String& effectName); /** * \brief Return a map containing all the events provided by the extension */ std::map& GetAllEvents(); /** * \brief Return a reference to a map containing the names of the actions * (as keys) and the metadata associated with (as values). */ std::map& GetAllActions(); /** * \see gd::PlatformExtension::GetAllActions */ std::map& GetAllConditions(); /** * \see gd::PlatformExtension::GetAllActions */ std::map& GetAllExpressions(); /** * \see gd::PlatformExtension::GetAllActions */ std::map& GetAllStrExpressions(); /** * \brief Return a reference to a vector containing the metadata of all the * dependencies of the extension. */ std::vector& GetAllDependencies(); /** * \brief Return a reference to a vector containing the metadata of all the * dependencies of the extension. */ const std::vector& GetAllDependencies() const; /** * \brief Return a reference to a vector containing the metadata of all the * dependencies of the extension. */ std::vector& GetAllSourceFiles(); /** * \brief Return a reference to a vector containing the metadata of all the * dependencies of the extension. */ const std::vector& GetAllSourceFiles() const; /** * \brief Return a reference to a map containing the names of the actions, * related to the object type, and the metadata associated with. */ std::map& GetAllActionsForObject( gd::String objectType); /** * \see gd::PlatformExtension::GetAllActionsForObject */ std::map& GetAllConditionsForObject( gd::String objectType); /** * \see gd::PlatformExtension::GetAllActionsForObject */ std::map& GetAllExpressionsForObject( gd::String objectType); /** * \see gd::PlatformExtension::GetAllActionsForObject */ std::map& GetAllStrExpressionsForObject( gd::String objectType); /** * \see gd::PlatformExtension::GetAllActionsForObject */ std::map& GetAllActionsForBehavior( gd::String autoType); /** * \see gd::PlatformExtension::GetAllActionsForObject */ std::map& GetAllConditionsForBehavior( gd::String autoType); /** * \see gd::PlatformExtension::GetAllActionsForObject */ std::map& GetAllExpressionsForBehavior( gd::String autoType); /** * \see gd::PlatformExtension::GetAllActionsForObject */ std::map& GetAllStrExpressionsForBehavior( gd::String autoType); /** * \brief Get all the properties of the extension. Properties * are shown in the game properties in the editor, and are exported in the * project data. */ std::map& GetAllProperties() { return extensionPropertiesMetadata; } /** * \brief Get the metadata (icon, etc...) for groups used for instructions * or expressions. */ const std::map& GetAllInstructionOrExpressionGroupMetadata() const { return instructionOrExpressionGroupMetadata; } const std::vector& GetInGameEditorResources() const { return inGameEditorResources; } ///@} /** * \brief Get the string used to separate the name of the * instruction/expression and the extension. */ static gd::String GetNamespaceSeparator() { return "::"; } static gd::String GetEventsFunctionFullType(const gd::String& extensionName, const gd::String& functionName); static gd::String GetBehaviorEventsFunctionFullType( const gd::String& extensionName, const gd::String& behaviorName, const gd::String& functionName); static gd::String GetBehaviorFullType(const gd::String& extensionName, const gd::String& behaviorName); static gd::String GetExtensionFromFullBehaviorType(const gd::String& type); static gd::String GetBehaviorNameFromFullBehaviorType(const gd::String& type); static gd::String GetObjectEventsFunctionFullType( const gd::String& extensionName, const gd::String& objectName, const gd::String& functionName); static gd::String GetObjectFullType(const gd::String& extensionName, const gd::String& objectName); static gd::String GetVariantFullType(const gd::String& extensionName, const gd::String& objectName, const gd::String& variantName); static gd::String GetExtensionFromFullObjectType(const gd::String& type); static gd::String GetObjectNameFromFullObjectType(const gd::String& type); /** * \brief Get the instruction name from a full type * (e.g. "MyExtension::DoSomething" -> "DoSomething"). * * If no namespace separator is found or the name after the separator is * empty, the full type is returned as-is. */ static gd::String GetInstructionNameFromFullType(const gd::String& type); private: /** * Set the namespace (the string all actions/conditions/expressions start * with). */ void SetNameSpace(gd::String nameSpace_); gd::String name; ///< Name identifying the extension gd::String nameSpace; ///< Automatically set from the name of the extension, and ///< added to every ///< actions/conditions/expressions/objects/behavior/event. gd::String fullname; ///< Name displayed to users in the editor. gd::String informations; ///< Description displayed to users in the editor. gd::String shortDescription; ///< Short description for AI/LLM agents. gd::String dimension; ///< "2D", "3D", "2D/3D" or empty. gd::String category; gd::String author; ///< Author displayed to users in the editor. gd::String license; ///< License name displayed to users in the editor. bool deprecated; ///< true if the extension is deprecated and shouldn't be ///< shown in IDE. gd::String helpPath; ///< The relative path to the help for this extension in ///< the documentation. gd::String iconUrl; ///< The URL to the icon to be shown for this extension. std::vector tags; std::map objectsInfos; std::map behaviorsInfo; std::map effectsMetadata; std::map conditionsInfos; std::map actionsInfos; std::map expressionsInfos; std::map strExpressionsInfos; std::vector extensionDependenciesMetadata; std::vector extensionSourceFilesMetadata; std::map eventsInfos; std::map extensionPropertiesMetadata; std::map instructionOrExpressionGroupMetadata; std::vector inGameEditorResources; ObjectMetadata badObjectMetadata; BehaviorMetadata badBehaviorMetadata; EffectMetadata badEffectMetadata; static std::map badConditionsMetadata; ///< Used when a condition is not found in the ///< extension static std::map badActionsMetadata; ///< Used when an action is not found in the ///< extension static std::map badExpressionsMetadata; ///< Used when an expression is not found in the ///< extension }; } // namespace gd /** \brief Macro used by extensions in their constructor to declare how they * have been compiled. \see gd::CompilationInfo */ #define GD_COMPLETE_EXTENSION_COMPILATION_INFORMATION() \ compilationInfo.runtimeOnly = false; \ compilationInfo.sfmlMajorVersion = 2; \ compilationInfo.sfmlMinorVersion = 0; \ compilationInfo.gdCoreVersion = GD_VERSION_STRING; \ compilationInfo.sizeOfpInt = sizeof(int*); \ compilationInfo.gccMajorVersion = __GNUC__; \ compilationInfo.gccMinorVersion = __GNUC_MINOR__; \ compilationInfo.gccPatchLevel = __GNUC_PATCHLEVEL__; \ compilationInfo.informationCompleted = true; #include "GDCore/Extensions/PlatformExtension.inl"