Allow extensions to declare dependencies (npm, cordova...) and custom properties in the project (#1717)

Only show in developer changelog
This commit is contained in:
Arthur Pacaud
2020-08-24 20:51:10 +01:00
committed by GitHub
parent 20392d6a79
commit cafa0d512f
33 changed files with 3296 additions and 2036 deletions
@@ -0,0 +1,103 @@
/*
* GDevelop Core
* Copyright 2008-2016 Florian Rival ([email protected]). All rights
* reserved. This project is released under the MIT License.
*/
#ifndef DEPENDENCYMETADATA_H
#define DEPENDENCYMETADATA_H
#include <map>
#include "GDCore/Project/PropertyDescriptor.h"
#include "GDCore/String.h"
#include "GDCore/Tools/Log.h"
namespace gd {
/**
* \brief Contains information about a dependency (library, npm/cordova
* package, or other according to the export) of an extension.
*/
class GD_CORE_API DependencyMetadata {
public:
/**
* \brief Sets the name shown to users.
*/
DependencyMetadata& SetName(const gd::String& name_) {
name = name_;
return *this;
};
/**
* \brief Sets the name written by the exporter.
* Typically, this is what is used by the dependency manager
* to find the dependency.
*
* \example
* \code
* // For depending upon the NPM package is-thirteen
* gd::DependencyMetadata dependencyMetadata = gd::DependencyMetadata();
* dependencyMetadata.setExporterName("is-thirteen");
* \endcode
*/
DependencyMetadata& SetExportName(const gd::String& exportName_) {
exportName = exportName_;
return *this;
};
/**
* \brief Set the version of the dependency to install.
* Use an empty string to use the latest version.
*/
DependencyMetadata& SetVersion(const gd::String& version_) {
version = version_;
return *this;
};
/**
* \brief Sets the type of dependecy (what will be used to install it)
*
* This can either be "npm" or "cordova" for now.
*/
DependencyMetadata& SetDependencyType(const gd::String& dependencyType_) {
dependencyType = dependencyType_;
if (dependencyType != "npm" && dependencyType != "cordova") {
gd::LogWarning("Invalid dependency type: " + dependencyType);
}
return *this;
};
/**
* \brief Sets a dependency type specific setting.
*/
DependencyMetadata& SetExtraSetting(
const gd::String& settingName,
const gd::PropertyDescriptor& settingValue) {
extraData[settingName] = settingValue;
return *this;
};
const gd::String& GetName() const { return name; };
const gd::String& GetExportName() const { return exportName; };
const gd::String& GetVersion() const { return version; };
const gd::String& GetDependencyType() const {
if(dependencyType == "") gd::LogWarning("Dependency has no type, it won't be exported.");
return dependencyType;
};
gd::PropertyDescriptor& GetExtraSetting(const gd::String& settingName) {
return extraData[settingName];
};
std::map<gd::String, gd::PropertyDescriptor>& GetAllExtraSettings() {
return extraData;
}
private:
gd::String name; ///< The name of the dependency.
gd::String exportName; ///< The name used to install the package (example: npm package name
///< for npm dependency type).
gd::String version; ///< The version of the dependency
gd::String dependencyType; ///< The tool used to install the dependency.
std::map<gd::String, gd::PropertyDescriptor>
extraData; ///< Contains dependency type specific additional parameters
///< for the dependency.
};
} // namespace gd
#endif // DEPENDENCYMETADATA_H
+16 -3
View File
@@ -4,9 +4,12 @@
* reserved. This project is released under the MIT License.
*/
#include "GDCore/Extensions/PlatformExtension.h"
#include <algorithm>
#include "GDCore/Events/Event.h"
#include "GDCore/Extensions/Metadata/BehaviorMetadata.h"
#include "GDCore/Extensions/Metadata/DependencyMetadata.h"
#include "GDCore/Extensions/Metadata/EventMetadata.h"
#include "GDCore/Extensions/Metadata/ExpressionMetadata.h"
#include "GDCore/Extensions/Metadata/InstructionMetadata.h"
@@ -117,6 +120,13 @@ gd::ExpressionMetadata& PlatformExtension::AddStrExpression(
#endif
}
#if defined(GD_IDE_ONLY)
gd::DependencyMetadata& PlatformExtension::AddDependency() {
extensionDependenciesMetadata.push_back(DependencyMetadata());
return extensionDependenciesMetadata.back();
}
#endif
gd::ObjectMetadata& PlatformExtension::AddObject(
const gd::String& name,
const gd::String& fullname,
@@ -216,8 +226,7 @@ std::vector<gd::String> PlatformExtension::GetExtensionObjectsTypes() const {
std::vector<gd::String> PlatformExtension::GetExtensionEffectTypes() const {
std::vector<gd::String> effectNames;
for (auto& it : effectsMetadata)
effectNames.push_back(it.first);
for (auto& it : effectsMetadata) effectNames.push_back(it.first);
return effectNames;
}
@@ -283,6 +292,10 @@ PlatformExtension::GetAllStrExpressions() {
return strExpressionsInfos;
}
std::vector<gd::DependencyMetadata>& PlatformExtension::GetAllDependencies() {
return extensionDependenciesMetadata;
}
std::map<gd::String, gd::EventMetadata>& PlatformExtension::GetAllEvents() {
return eventsInfos;
}
@@ -404,7 +417,7 @@ void PlatformExtension::SetNameSpace(gd::String nameSpace_) {
name == "BuiltinCommonConversions" ||
name == "BuiltinStringInstructions" ||
name == "BuiltinMathematicalTools" ||
name == "Effects" || // Well-known effects are not namespaced.
name == "Effects" || // Well-known effects are not namespaced.
name == "CommonDialogs") // New name for BuiltinInterface
{
nameSpace = "";
+49 -1
View File
@@ -10,11 +10,14 @@
#include <map>
#include <memory>
#include <vector>
#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/ObjectMetadata.h"
#include "GDCore/Extensions/Metadata/EffectMetadata.h"
#include "GDCore/Project/PropertyDescriptor.h"
#include "GDCore/String.h"
#include "GDCore/Tools/VersionPriv.h"
@@ -25,6 +28,7 @@ class ExpressionMetadata;
class ObjectMetadata;
class BehaviorMetadata;
class EffectMetadata;
class DependencyMetadata;
class BaseEvent;
class EventMetadata;
class EventCodeGenerator;
@@ -148,6 +152,8 @@ class GD_CORE_API PlatformExtension {
const gd::String& group_,
const gd::String& smallicon_);
gd::DependencyMetadata& AddDependency();
/**
* \brief Declare a new object as being part of the extension.
* \note This method does nothing when used for GD C++ runtime.
@@ -225,6 +231,33 @@ class GD_CORE_API PlatformExtension {
const gd::String& smallicon_,
std::shared_ptr<gd::BaseEvent> instance);
#if defined(GD_IDE_ONLY)
/**
* \brief Adds a property to the Extension.
* \param name The internal name of the property (to get it later).
* \param description The description of the property.
* \param type The type of the property. Supported ones are "string", "number"
* and "boolean".
*/
gd::PropertyDescriptor& RegisterProperty(const gd::String& name,
const gd::String& description,
const gd::String& type,
const gd::String& hint) {
extensionPropertiesMetadata[name]
.SetDescription(description)
.SetType(type)
.SetLabel(hint);
return extensionPropertiesMetadata[name];
};
/**
* \brief Adds a property to the Extension.
*/
gd::PropertyDescriptor& RegisterProperty(const gd::String& name) {
return extensionPropertiesMetadata[name];
};
#endif
/**
* \brief Return the name extension user friendly name.
*/
@@ -365,6 +398,12 @@ class GD_CORE_API PlatformExtension {
*/
std::map<gd::String, gd::ExpressionMetadata>& GetAllStrExpressions();
/**
* \brief Return a reference to a vector containing the metadata of all the
* dependencies of the extension.
*/
std::vector<gd::DependencyMetadata>& GetAllDependencies();
/**
* \brief Return a reference to a map containing the names of the actions,
* related to the object type, and the metadata associated with.
@@ -437,6 +476,13 @@ class GD_CORE_API PlatformExtension {
* generator.
*/
void StripUnimplementedInstructionsAndExpressions();
/**
* \brief Get all the properties of the extension
*/
std::map<gd::String, gd::PropertyDescriptor>& GetAllProperties() {
return extensionPropertiesMetadata;
}
#endif
/**
@@ -480,7 +526,9 @@ class GD_CORE_API PlatformExtension {
std::map<gd::String, gd::InstructionMetadata> actionsInfos;
std::map<gd::String, gd::ExpressionMetadata> expressionsInfos;
std::map<gd::String, gd::ExpressionMetadata> strExpressionsInfos;
std::vector<gd::DependencyMetadata> extensionDependenciesMetadata;
std::map<gd::String, gd::EventMetadata> eventsInfos;
std::map<gd::String, gd::PropertyDescriptor> extensionPropertiesMetadata;
#endif
ObjectMetadata badObjectMetadata;
@@ -0,0 +1,56 @@
#include "ExtensionProperties.h"
#include "GDCore/Extensions/Platform.h"
#include "GDCore/Extensions/PlatformExtension.h"
#include "GDCore/Project/Project.h"
#include "GDCore/Project/PropertyDescriptor.h"
namespace gd {
const gd::String ExtensionProperties::defaultValue = "";
std::map<gd::String, gd::PropertyDescriptor>
ExtensionProperties::GetAllExtensionProperties(const gd::String& extensionName,
gd::Project& project) {
// Create a copy
std::map<gd::String, gd::PropertyDescriptor> props(
project.GetCurrentPlatform()
.GetExtension(extensionName)
->GetAllProperties());
// Set values
for (std::pair<gd::String, gd::PropertyDescriptor> property : props) {
if (properties.count(extensionName) > 0 &&
properties[extensionName].count(property.first) > 0) {
props[property.first].SetValue(properties[extensionName][property.first]);
}
}
return props;
};
void ExtensionProperties::SerializeTo(SerializerElement& element) const {
element.ConsiderAsArrayOf("extensionProperties");
for (const std::pair<gd::String, std::map<gd::String, gd::String>> extension :
properties) {
for (const std::pair<gd::String, gd::String> property : extension.second) {
SerializerElement& propertyElement =
element.AddChild("extensionProperties");
propertyElement.AddChild("extension").SetStringValue(extension.first);
propertyElement.AddChild("property").SetStringValue(property.first);
propertyElement.AddChild("value").SetStringValue(property.second);
}
}
};
void ExtensionProperties::UnserializeFrom(const SerializerElement& element) {
properties.clear();
element.ConsiderAsArrayOf("extensionProperties");
for (std::pair<const gd::String, std::shared_ptr<SerializerElement>>
extensionProperties : element.GetAllChildren()) {
std::shared_ptr<SerializerElement> extensionPropertiesElement =
extensionProperties.second;
properties
[extensionPropertiesElement->GetChild("extension").GetStringValue()]
[extensionPropertiesElement->GetChild("property").GetStringValue()] =
extensionPropertiesElement->GetChild("value").GetStringValue();
}
};
}; // namespace gd
+69
View File
@@ -0,0 +1,69 @@
/*
* GDevelop Core
* Copyright 2008-2016 Florian Rival ([email protected]). All rights
* reserved. This project is released under the MIT License.
*/
#ifndef GDCORE_EXTENSIONPROPERTIES_H
#define GDCORE_EXTENSIONPROPERTIES_H
#include <map>
#include "GDCore/Serialization/SerializerElement.h"
#include "GDCore/String.h"
namespace gd {
class Project;
class PropertyDescriptor;
} // namespace gd
namespace gd {
class GD_CORE_API ExtensionProperties {
static const gd::String defaultValue;
public:
const gd::String& GetValue(const gd::String& extension,
const gd::String& property) const {
if (properties.count(extension) == 0 ||
properties.at(extension).count(property) == 0) {
return ExtensionProperties::defaultValue;
}
return properties.at(extension).at(property);
};
void SetValue(const gd::String& extension,
const gd::String& property,
const gd::String& newValue) {
properties[extension][property] = newValue;
};
bool HasProperty(const gd::String& extension, const gd::String& property) {
for (std::pair<gd::String, gd::String> propertyPair :
properties[extension]) {
if (propertyPair.first == property) {
return true;
}
}
return false;
}
std::map<gd::String, gd::PropertyDescriptor> GetAllExtensionProperties(
const gd::String& extensionName, gd::Project& project);
///@{
/**
* \brief Serialize the Extension Properties.
*/
virtual void SerializeTo(SerializerElement& element) const;
/**
* \brief Unserialize the Extension Properties.
*/
virtual void UnserializeFrom(const SerializerElement& element);
///@}
private:
std::map<gd::String, std::map<gd::String, gd::String>>
properties; ///< The properties of the project
};
} // namespace gd
#endif // EXTENSIONPROPERTIES_H
@@ -23,4 +23,14 @@ void NamedPropertyDescriptor::UnserializeFrom(
name = element.GetChild("name").GetStringValue();
}
void NamedPropertyDescriptor::SerializeValuesTo(SerializerElement& element) const {
PropertyDescriptor::SerializeValuesTo(element);
element.AddChild("name").SetStringValue(name);
}
void NamedPropertyDescriptor::UnserializeValuesFrom(const SerializerElement& element) {
PropertyDescriptor::UnserializeValuesFrom(element);
name = element.GetChild("name").GetStringValue();
}
} // namespace gd
@@ -58,6 +58,16 @@ class GD_CORE_API NamedPropertyDescriptor : public PropertyDescriptor {
* \brief Unserialize the NamedPropertyDescriptor.
*/
void UnserializeFrom(const SerializerElement& element);
/**
* \brief Serialize only the value and extra informations of the property.
*/
virtual void SerializeValuesTo(SerializerElement& element) const;
/**
* \brief Unserialize only the value and extra information of the property.
*/
virtual void UnserializeValuesFrom(const SerializerElement& element);
///@}
/**
+24 -6
View File
@@ -5,13 +5,16 @@
*/
#include "Project.h"
#include <stdio.h>
#include <stdlib.h>
#include <cctype>
#include <SFML/System/Utf.hpp>
#include <cctype>
#include <fstream>
#include <map>
#include <vector>
#include "GDCore/CommonTools.h"
#include "GDCore/Extensions/Metadata/ExpressionMetadata.h"
#include "GDCore/Extensions/Metadata/MetadataProvider.h"
@@ -51,7 +54,6 @@ Project::Project()
version("1.0.0"),
packageName("com.example.gamename"),
orientation("landscape"),
adMobAppId(""),
folderProject(false),
#endif
windowWidth(800),
@@ -596,7 +598,6 @@ void Project::UnserializeFrom(const SerializerElement& element) {
SetAuthor(propElement.GetChild("author", 0, "Auteur").GetValue().GetString());
SetPackageName(propElement.GetStringAttribute("packageName"));
SetOrientation(propElement.GetStringAttribute("orientation", "default"));
SetAdMobAppId(propElement.GetStringAttribute("adMobAppId", ""));
SetFolderProject(propElement.GetBoolAttribute("folderProject"));
SetProjectFile(propElement.GetStringAttribute("projectFile"));
SetLastCompilationDirectory(propElement
@@ -618,6 +619,20 @@ void Project::UnserializeFrom(const SerializerElement& element) {
propElement.GetStringAttribute("macExecutableFilename");
useExternalSourceFiles =
propElement.GetBoolAttribute("useExternalSourceFiles");
extensionProperties.UnserializeFrom(
propElement.GetChild("extensionProperties"));
// Compatibility with GD <= 5.0.0-beta98
// Move AdMob App ID from project property to extension property.
if (propElement.GetStringAttribute("adMobAppId", "") != "") {
extensionProperties.SetValue(
"AdMob",
"AdMobAppId",
propElement.GetStringAttribute("adMobAppId", ""));
}
// end of compatibility code
#endif
const SerializerElement& extensionsElement =
@@ -866,13 +881,13 @@ void Project::SerializeTo(SerializerElement& element) const {
propElement.AddChild("verticalSync")
.SetValue(IsVerticalSynchronizationEnabledByDefault());
propElement.SetAttribute("scaleMode", scaleMode);
propElement.SetAttribute("adaptGameResolutionAtRuntime", adaptGameResolutionAtRuntime);
propElement.SetAttribute("adaptGameResolutionAtRuntime",
adaptGameResolutionAtRuntime);
propElement.SetAttribute("sizeOnStartupMode", sizeOnStartupMode);
propElement.SetAttribute("projectFile", gameFile);
propElement.SetAttribute("folderProject", folderProject);
propElement.SetAttribute("packageName", packageName);
propElement.SetAttribute("orientation", orientation);
propElement.SetAttribute("adMobAppId", adMobAppId);
platformSpecificAssets.SerializeTo(
propElement.AddChild("platformSpecificAssets"));
loadingScreen.SerializeTo(propElement.AddChild("loadingScreen"));
@@ -882,6 +897,8 @@ void Project::SerializeTo(SerializerElement& element) const {
propElement.SetAttribute("macExecutableFilename", macExecutableFilename);
propElement.SetAttribute("useExternalSourceFiles", useExternalSourceFiles);
extensionProperties.SerializeTo(propElement.AddChild("extensionProperties"));
SerializerElement& extensionsElement = propElement.AddChild("extensions");
extensionsElement.ConsiderAsArrayOf("extension");
for (std::size_t i = 0; i < GetUsedExtensions().size(); ++i)
@@ -1071,13 +1088,14 @@ void Project::Init(const gd::Project& game) {
author = game.author;
packageName = game.packageName;
orientation = game.orientation;
adMobAppId = game.adMobAppId;
folderProject = game.folderProject;
latestCompilationDirectory = game.latestCompilationDirectory;
platformSpecificAssets = game.platformSpecificAssets;
loadingScreen = game.loadingScreen;
objectGroups = game.objectGroups;
extensionProperties = game.extensionProperties;
gdMajorVersion = game.gdMajorVersion;
gdMinorVersion = game.gdMinorVersion;
gdBuildVersion = game.gdBuildVersion;
+24 -16
View File
@@ -9,6 +9,7 @@
#include <memory>
#include <vector>
#include "GDCore/Project/ExtensionProperties.h"
#include "GDCore/Project/LoadingScreen.h"
#include "GDCore/Project/ObjectGroupsContainer.h"
#include "GDCore/Project/ObjectsContainer.h"
@@ -114,20 +115,6 @@ class GD_CORE_API Project : public ObjectsContainer {
*/
const gd::String& GetOrientation() const { return orientation; }
/**
* \brief Change the project AdMob application ID (needed
* to use the AdMob extension). This has no effect on desktop
* and web browsers.
*/
void SetAdMobAppId(const gd::String& adMobAppId_) {
adMobAppId = adMobAppId_;
};
/**
* \brief Get the project AdMob application ID.
*/
const gd::String& GetAdMobAppId() const { return adMobAppId; }
/**
* Called when project file has changed.
*/
@@ -305,6 +292,26 @@ class GD_CORE_API Project : public ObjectsContainer {
std::vector<gd::String>& GetUsedExtensions() { return extensionsUsed; };
#if defined(GD_IDE_ONLY)
/**
* \brief Get the properties set by extensions.
*
* Each extension can store arbitrary values indexed by a property name, which are
* useful to store project wide settings (AdMob id, etc...).
*/
gd::ExtensionProperties& GetExtensionProperties() {
return extensionProperties;
};
/**
* \brief Get the properties set by extensions.
*
* Each extension can store arbitrary values indexed by a property name, which are
* useful to store project wide settings (AdMob id, etc...).
*/
const gd::ExtensionProperties& GetExtensionProperties() const {
return extensionProperties;
};
/**
* Return the list of platforms used by the project.
*/
@@ -968,7 +975,6 @@ class GD_CORE_API Project : public ObjectsContainer {
gd::String packageName; ///< Game package name
gd::String orientation; ///< Lock game orientation (on mobile devices).
///< "default", "landscape" or "portrait".
gd::String adMobAppId; ///< AdMob application ID.
bool
folderProject; ///< True if folder project, false if single file project.
gd::String gameFile; ///< File of the game
@@ -978,7 +984,9 @@ class GD_CORE_API Project : public ObjectsContainer {
gd::PlatformSpecificAssets platformSpecificAssets;
gd::LoadingScreen loadingScreen;
std::vector<std::unique_ptr<gd::ExternalEvents> >
externalEvents; ///< List of all externals events
externalEvents; ///< List of all externals events
ExtensionProperties
extensionProperties; ///< The properties of the extensions.
mutable unsigned int gdMajorVersion; ///< The GD major version used the last
///< time the project was saved.
mutable unsigned int gdMinorVersion; ///< The GD minor version used the last
@@ -4,7 +4,9 @@
* reserved. This project is released under the MIT License.
*/
#include "PropertyDescriptor.h"
#include <vector>
#include "GDCore/Serialization/SerializerElement.h"
#include "GDCore/String.h"
@@ -45,4 +47,27 @@ void PropertyDescriptor::UnserializeFrom(const SerializerElement& element) {
: false;
}
void PropertyDescriptor::SerializeValuesTo(SerializerElement& element) const {
element.AddChild("value").SetStringValue(currentValue);
SerializerElement& extraInformationElement =
element.AddChild("extraInformation");
extraInformationElement.ConsiderAsArray();
for (const gd::String& information : extraInformation) {
extraInformationElement.AddChild("").SetStringValue(information);
}
}
void PropertyDescriptor::UnserializeValuesFrom(
const SerializerElement& element) {
currentValue = element.GetChild("value").GetStringValue();
extraInformation.clear();
const SerializerElement& extraInformationElement =
element.GetChild("extraInformation");
extraInformationElement.ConsiderAsArray();
for (std::size_t i = 0; i < extraInformationElement.GetChildrenCount(); ++i)
extraInformation.push_back(
extraInformationElement.GetChild(i).GetStringValue());
}
} // namespace gd
+12 -1
View File
@@ -6,6 +6,7 @@
#ifndef GDCORE_PROPERTYDESCRIPTOR
#define GDCORE_PROPERTYDESCRIPTOR
#include <vector>
#include "GDCore/String.h"
namespace gd {
class SerializerElement;
@@ -120,6 +121,16 @@ class GD_CORE_API PropertyDescriptor {
* \brief Unserialize the PropertyDescriptor.
*/
virtual void UnserializeFrom(const SerializerElement& element);
/**
* \brief Serialize only the value and extra informations.
*/
virtual void SerializeValuesTo(SerializerElement& element) const;
/**
* \brief Unserialize only the value and extra informations.
*/
virtual void UnserializeValuesFrom(const SerializerElement& element);
///@}
private:
@@ -127,7 +138,7 @@ class GD_CORE_API PropertyDescriptor {
gd::String
type; ///< The type of the property. This is arbitrary and interpreted by
///< the class responsible for updating the property grid.
gd::String label; //< The user-friendly property name
gd::String label; //< The user-friendly property name
gd::String description; //< The user-friendly property description
std::vector<gd::String>
extraInformation; ///< Can be used to store for example the available
+16
View File
@@ -32,6 +32,22 @@ module.exports = {
'MIT'
);
extension.registerProperty("AdMobAppId")
.setDescription("AdMob App ID")
.setType("string")
.setLabel("ca-app-pub-XXXXXXXXXXXXXXXX/YYYYYYYYYY");
extension.addDependency()
.setName("AdMob Cordova Extension")
.setDependencyType("cordova")
.setExportName("cordova-plugin-admob-free")
.setVersion("~0.21.0")
.setExtraSetting(
"ADMOB_APP_ID",
new gd.PropertyDescriptor("AdMobAppId")
.setType("ExtensionProperty")
);
// Banner
extension
.addCondition(
@@ -33,6 +33,29 @@ module.exports = {
'MIT'
);
// Register Properties
extension.registerProperty("DummyPropertyString")
.setDescription(_("Dummy Property Name"))
.setType("string")
.setLabel("Type in anything :)");
extension.registerProperty("DummyPropertyNumber")
.setDescription(_("Dummy Numeric Property Name"))
.setType("number")
.setLabel("Only numbers here ;)");
extension.registerProperty("DummyPropertyBoolean")
.setDescription(_("A boolean property"))
.setType("boolean");
// Register Cordova/NPM dependencies
extension
.addDependency()
.setName("Thirteen Checker")
.setDependencyType("npm")
.setExportName("is-thirteen")
.setVersion("2.0.0");
// Declare effects:
const dummyEffect = extension
.addEffect('DummyEffect')
+53 -8
View File
@@ -23,6 +23,10 @@
#include "GDCore/Project/Layout.h"
#include "GDCore/Project/Project.h"
#include "GDCore/Project/SourceFile.h"
#include "GDCore/Project/PropertyDescriptor.h"
#include "GDCore/Extensions/Platform.h"
#include "GDCore/Extensions/PlatformExtension.h"
#include "GDCore/Extensions/Metadata/DependencyMetadata.h"
#include "GDCore/Serialization/Serializer.h"
#include "GDCore/TinyXml/tinyxml.h"
#include "GDCore/Tools/Localization.h"
@@ -261,16 +265,37 @@ bool ExporterHelper::ExportCordovaFiles(const gd::Project &project,
.FindAndReplace("<!-- GDJS_ICONS_ANDROID -->", makeIconsAndroid())
.FindAndReplace("<!-- GDJS_ICONS_IOS -->", makeIconsIos());
if (!project.GetAdMobAppId().empty()) {
str = str.FindAndReplace(
"<!-- GDJS_ADMOB_PLUGIN_AND_APPLICATION_ID -->",
"<plugin name=\"cordova-plugin-admob-free\" spec=\"~0.21.0\">\n"
"\t\t<variable name=\"ADMOB_APP_ID\" value=\"" +
project.GetAdMobAppId() +
"\" />\n"
"\t</plugin>");
gd::String plugins = "";
for(std::shared_ptr<gd::PlatformExtension> extension : project.GetCurrentPlatform().GetAllPlatformExtensions()) { //TODO Add a way to select only used Extensions
for (gd::DependencyMetadata dependencies: extension->GetAllDependencies()) {
if (dependencies.GetDependencyType() == "cordova") {
plugins += "<plugin name=\"" + dependencies.GetExportName();
if(dependencies.GetVersion() != "") {
plugins += "\" spec=\"" + dependencies.GetVersion();
}
plugins += "\">\n";
// In cordova all settings are considered a plugin variable
for (std::pair<const gd::String, gd::PropertyDescriptor>& dependency : dependencies.GetAllExtraSettings()) {
if (dependency.second.GetType() == "ExtensionProperty") {
plugins += "\t\t<variable name=\"" + dependency.first + "\" value=\"" + project.GetExtensionProperties().GetValue(extension->GetName(), dependency.second.GetValue()) + "\" />\n";
} else {
plugins += "\t\t<variable name=\"" + dependency.first + "\" value=\"" + dependency.second.GetValue() + "\" />\n";
}
}
plugins += "\t</plugin>";
}
}
}
str = str.FindAndReplace(
"<!-- GDJS_EXTENSION_CORDOVA_DEPENDENCY -->",
plugins
);
if (!fs.WriteToFile(exportDir + "/config.xml", str)) {
lastError = "Unable to write Cordova config.xml file.";
return false;
@@ -421,6 +446,26 @@ bool ExporterHelper::ExportElectronFiles(const gd::Project &project,
.FindAndReplace("\"GDJS_GAME_VERSION\"", jsonVersion)
.FindAndReplace("\"GDJS_GAME_MANGLED_NAME\"", jsonMangledName);
gd::String packages = "";
for(std::shared_ptr<gd::PlatformExtension> extension : project.GetCurrentPlatform().GetAllPlatformExtensions()) { //TODO Add a way to select only used Extensions
for (gd::DependencyMetadata dependency: extension->GetAllDependencies()) {
if (dependency.GetDependencyType() == "npm") {
if(dependency.GetVersion() == "") {
gd::LogError("Latest Version not available for NPM dependencies, dependency " + dependency.GetName() + " is not exported. Please specify a version when calling addDependency.");
continue;
}
packages += "\n\t\"" + dependency.GetExportName() + "\": \"" + dependency.GetVersion() + "\",";
// For node extra settings are ignored
}
}
}
packages = packages.substr(1, packages.size()); // Remove first line break for esthetic.
packages = packages.substr(0, packages.size()-1); // Remove the , at the end as last item cannot have , in JSON.
str = str.FindAndReplace("\"GDJS_EXTENSION_NPM_DEPENDENCY\": \"0\"", packages);
if (!fs.WriteToFile(exportDir + "/package.json", str)) {
lastError = "Unable to write Electron package.json file.";
return false;
+1 -1
View File
@@ -30,5 +30,5 @@
<!-- Cordova/Phonegap version -->
<preference name="phonegap-version" value="cli-9.0.0" />
<!-- GDJS_ADMOB_PLUGIN_AND_APPLICATION_ID -->
<!-- GDJS_EXTENSION_CORDOVA_DEPENDENCY -->
</widget>
+3 -1
View File
@@ -5,7 +5,9 @@
"description": "GDJS_GAME_NAME",
"author": "GDJS_GAME_AUTHOR",
"version": "GDJS_GAME_VERSION",
"dependencies": {},
"dependencies": {
"GDJS_EXTENSION_NPM_DEPENDENCY": "0"
},
"devDependencies": {
"electron": "8.2.5"
},
+13
View File
@@ -601,3 +601,16 @@ gdjs.RuntimeGame.prototype.getSceneStack = function() {
gdjs.RuntimeGame.prototype.isPreview = function() {
return this._isPreview;
}
/**
* Gets an extension property from the project data.
* @param {string} extensionName The extension name.
* @param {string} propertyName The property name.
* @return {?string} The property value.
*/
gdjs.RuntimeGame.prototype.getExtensionProperty = function(extensionName, propertyName) {
for(let property of this._data.properties.extensionProperties) {
if(property.extension === extensionName && property.property === propertyName) return property.value;
}
return null;
}
+7
View File
@@ -145,6 +145,13 @@ export interface ProjectPropertiesData {
verticalSync: boolean;
loadingScreen: LoadingScreenData;
currentPlatform: string;
extensionProperties: Array<ExtensionProperty>;
}
export interface ExtensionProperty {
extension: string;
property: string;
value: string;
}
export interface LoadingScreenData {
+48 -2
View File
@@ -34,6 +34,11 @@ interface VectorPlatformExtension {
[Const] PlatformExtension WRAPPED_at(unsigned long index);
};
interface VectorDependencyMetadata {
unsigned long size();
[Const, Ref] DependencyMetadata at(unsigned long index);
};
interface MapStringString {
void MapStringString();
@@ -89,6 +94,13 @@ interface MapStringEventMetadata {
[Value] VectorString MAP_keys();
};
interface MapExtensionProperties {
[Ref] MapStringPropertyDescriptor MAP_get([Const] DOMString name);
void MAP_set([Const] DOMString name, [Const, Ref] MapStringPropertyDescriptor prop);
boolean MAP_has([Const] DOMString name);
[Value] VectorString MAP_keys();
};
interface SetString {
void SetString();
[Value] VectorString FREE_toNewVectorString();
@@ -288,8 +300,6 @@ interface Project {
[Const, Ref] DOMString GetPackageName();
void SetOrientation([Const] DOMString orientation);
[Const, Ref] DOMString GetOrientation();
void SetAdMobAppId([Const] DOMString adMobAppId);
[Const, Ref] DOMString GetAdMobAppId();
void SetProjectFile([Const] DOMString file);
[Const, Ref] DOMString GetProjectFile();
void SetGameResolutionSize(long width, long height);
@@ -312,6 +322,7 @@ interface Project {
[Const, Ref] DOMString GetLastCompilationDirectory();
[Const, Ref] VectorString GetUsedExtensions();
[Ref] ExtensionProperties GetExtensionProperties();
void AddPlatform([Ref] Platform platform);
[Ref] Platform GetCurrentPlatform();
@@ -384,6 +395,16 @@ interface Project {
[Ref] ObjectGroupsContainer GetObjectGroups();
};
interface ExtensionProperties {
[Const, Ref] DOMString GetValue([Const] DOMString extension, [Const] DOMString property);
void SetValue([Const] DOMString extension, [Const] DOMString property, [Const] DOMString newValue);
boolean HasProperty([Const] DOMString extension, [Const] DOMString property);
[Value] MapStringPropertyDescriptor GetAllExtensionProperties([Const] DOMString extension, [Ref] Project project);
void SerializeTo([Ref] SerializerElement element);
void UnserializeFrom([Const, Ref] SerializerElement element);
};
interface Behavior {
void Behavior();
@@ -650,6 +671,8 @@ interface PropertyDescriptor {
void SerializeTo([Ref] SerializerElement element);
void UnserializeFrom([Const, Ref] SerializerElement element);
void SerializeValuesTo([Ref] SerializerElement element);
void UnserializeValuesFrom([Const, Ref] SerializerElement element);
};
interface NamedPropertyDescriptor {
@@ -1020,6 +1043,22 @@ interface ExpressionMetadata {
[Ref] ExpressionCodeGenerationInformation GetCodeExtraInformation();
};
interface DependencyMetadata {
void DependencyMetadata();
[Const, Ref] DOMString GetName();
[Ref] DependencyMetadata SetName([Const] DOMString name_);
[Const, Ref] DOMString GetExportName();
[Ref] DependencyMetadata SetExportName([Const] DOMString exportName_);
[Const, Ref] DOMString GetVersion();
[Ref] DependencyMetadata SetVersion([Const] DOMString version_);
[Const, Ref] DOMString GetDependencyType();
[Ref] DependencyMetadata SetDependencyType([Const] DOMString dependencyType_);
[Ref] PropertyDescriptor GetExtraSetting([Const] DOMString settingName);
[Ref] DependencyMetadata SetExtraSetting([Const] DOMString settingName, [Const, Ref] PropertyDescriptor settingValue);
[Ref] MapStringPropertyDescriptor GetAllExtraSettings();
};
interface ParameterMetadata {
void ParameterMetadata();
@@ -1229,6 +1268,8 @@ interface PlatformExtension {
[Const] DOMString group,
[Const] DOMString smallicon);
[Const, Ref] DependencyMetadata AddDependency();
[Ref] BehaviorMetadata WRAPPED_AddBehavior([Const] DOMString name,
[Const] DOMString fullname,
[Const] DOMString defaultName,
@@ -1247,6 +1288,8 @@ interface PlatformExtension {
[Ref] EffectMetadata AddEffect([Const] DOMString name);
[Ref] PropertyDescriptor RegisterProperty([Const] DOMString name);
[Const, Ref] DOMString GetFullName();
[Const, Ref] DOMString GetName();
[Const, Ref] DOMString GetDescription();
@@ -1275,6 +1318,9 @@ interface PlatformExtension {
[Ref] MapStringInstructionMetadata GetAllConditionsForBehavior([Const] DOMString autoType);
[Ref] MapStringExpressionMetadata GetAllExpressionsForBehavior([Const] DOMString autoType);
[Ref] MapStringExpressionMetadata GetAllStrExpressionsForBehavior([Const] DOMString autoType);
[Ref] MapStringPropertyDescriptor GetAllProperties();
[Ref] VectorDependencyMetadata GetAllDependencies();
[Const, Value] DOMString STATIC_GetNamespaceSeparator();
};
+105 -87
View File
@@ -1,57 +1,3 @@
#include <map>
#include <set>
#include <string>
#include <utility>
#include <vector>
#include <GDCore/Extensions/Platform.h>
#include <GDCore/Project/Behavior.h>
#include <GDCore/Project/ExternalEvents.h>
#include <GDCore/Project/ExternalLayout.h>
#include <GDCore/Project/InitialInstance.h>
#include <GDCore/Project/InitialInstancesContainer.h>
#include <GDCore/Project/Layout.h>
#include <GDCore/Project/Object.h>
#include <GDCore/Project/Project.h>
#include <GDCore/Project/Variable.h>
#include <GDCore/Project/EventsBasedBehavior.h>
#include <GDCore/Project/VariablesContainer.h>
#include <GDCore/Project/Effect.h>
#include <GDCore/Serialization/Serializer.h>
#include <GDCore/Serialization/SerializerElement.h>
#include <GDCore/Events/Parsers/ExpressionParser2.h>
#include <GDCore/Events/Parsers/ExpressionParser2Node.h>
#include <GDCore/IDE/Events/ExpressionValidator.h>
#include <GDCore/Events/CodeGeneration/ExpressionCodeGenerator.h>
#include <GDCore/Extensions/Metadata/EffectMetadata.h>
#include <GDCore/Extensions/Metadata/MetadataProvider.h>
#include <GDCore/Extensions/Metadata/ParameterMetadataTools.h>
#include <GDCore/Project/EventsFunction.h>
#include <GDCore/Project/EventsFunctionsExtension.h>
#include <GDCore/IDE/AbstractFileSystem.h>
#include <GDCore/IDE/EventsFunctionTools.h>
#include <GDCore/IDE/Dialogs/LayoutEditorCanvas/LayoutEditorCanvasOptions.h>
#include <GDCore/Project/PropertyDescriptor.h>
#include <GDCore/Project/NamedPropertyDescriptor.h>
#include <GDCore/IDE/Events/ArbitraryEventsWorker.h>
#include <GDCore/IDE/Events/InstructionsTypeRenamer.h>
#include <GDCore/IDE/Events/EventsContextAnalyzer.h>
#include <GDCore/IDE/Events/EventsParametersLister.h>
#include <GDCore/IDE/Events/EventsTypesLister.h>
#include <GDCore/IDE/Events/EventsRefactorer.h>
#include <GDCore/IDE/Events/EventsRemover.h>
#include <GDCore/IDE/Events/InstructionSentenceFormatter.h>
#include <GDCore/IDE/Events/TextFormatting.h>
#include <GDCore/IDE/Events/EventsListUnfolder.h>
#include <GDCore/IDE/Events/ExpressionCompletionFinder.h>
#include <GDCore/IDE/Project/ArbitraryResourceWorker.h>
#include <GDCore/IDE/Project/ResourcesMergingHelper.h>
#include <GDCore/IDE/Project/ResourcesInUseHelper.h>
#include <GDCore/IDE/Project/ProjectResourcesAdder.h>
#include <GDCore/IDE/Project/ProjectResourcesCopier.h>
#include <GDCore/IDE/WholeProjectRefactorer.h>
#include <GDCore/Events/Builtin/CommentEvent.h>
#include <GDCore/Events/Builtin/ForEachEvent.h>
#include <GDCore/Events/Builtin/GroupEvent.h>
@@ -59,33 +5,82 @@
#include <GDCore/Events/Builtin/RepeatEvent.h>
#include <GDCore/Events/Builtin/StandardEvent.h>
#include <GDCore/Events/Builtin/WhileEvent.h>
#include <GDCore/Events/CodeGeneration/ExpressionCodeGenerator.h>
#include <GDCore/Events/Parsers/ExpressionParser2.h>
#include <GDCore/Events/Parsers/ExpressionParser2Node.h>
#include <GDCore/Extensions/Builtin/SpriteExtension/Animation.h>
#include <GDCore/Extensions/Builtin/SpriteExtension/Direction.h>
#include <GDCore/Extensions/Builtin/SpriteExtension/Sprite.h>
#include <GDCore/Extensions/Builtin/SpriteExtension/SpriteObject.h>
#include <GDCore/Extensions/Metadata/DependencyMetadata.h>
#include <GDCore/Extensions/Metadata/EffectMetadata.h>
#include <GDCore/Extensions/Metadata/MetadataProvider.h>
#include <GDCore/Extensions/Metadata/ParameterMetadataTools.h>
#include <GDCore/Extensions/Platform.h>
#include <GDCore/IDE/AbstractFileSystem.h>
#include <GDCore/IDE/Dialogs/LayoutEditorCanvas/LayoutEditorCanvasOptions.h>
#include <GDCore/IDE/Events/ArbitraryEventsWorker.h>
#include <GDCore/IDE/Events/EventsContextAnalyzer.h>
#include <GDCore/IDE/Events/EventsListUnfolder.h>
#include <GDCore/IDE/Events/EventsParametersLister.h>
#include <GDCore/IDE/Events/EventsRefactorer.h>
#include <GDCore/IDE/Events/EventsRemover.h>
#include <GDCore/IDE/Events/EventsTypesLister.h>
#include <GDCore/IDE/Events/ExpressionCompletionFinder.h>
#include <GDCore/IDE/Events/ExpressionValidator.h>
#include <GDCore/IDE/Events/InstructionSentenceFormatter.h>
#include <GDCore/IDE/Events/InstructionsTypeRenamer.h>
#include <GDCore/IDE/Events/TextFormatting.h>
#include <GDCore/IDE/EventsFunctionTools.h>
#include <GDCore/IDE/Project/ArbitraryResourceWorker.h>
#include <GDCore/IDE/Project/ProjectResourcesAdder.h>
#include <GDCore/IDE/Project/ProjectResourcesCopier.h>
#include <GDCore/IDE/Project/ResourcesInUseHelper.h>
#include <GDCore/IDE/Project/ResourcesMergingHelper.h>
#include <GDCore/IDE/WholeProjectRefactorer.h>
#include <GDCore/Project/Behavior.h>
#include <GDCore/Project/Effect.h>
#include <GDCore/Project/EventsBasedBehavior.h>
#include <GDCore/Project/EventsFunction.h>
#include <GDCore/Project/EventsFunctionsExtension.h>
#include <GDCore/Project/ExternalEvents.h>
#include <GDCore/Project/ExternalLayout.h>
#include <GDCore/Project/InitialInstance.h>
#include <GDCore/Project/InitialInstancesContainer.h>
#include <GDCore/Project/Layout.h>
#include <GDCore/Project/NamedPropertyDescriptor.h>
#include <GDCore/Project/Object.h>
#include <GDCore/Project/Project.h>
#include <GDCore/Project/PropertyDescriptor.h>
#include <GDCore/Project/Variable.h>
#include <GDCore/Project/VariablesContainer.h>
#include <GDCore/Serialization/Serializer.h>
#include <GDCore/Serialization/SerializerElement.h>
#include <GDJS/Events/Builtin/JsCodeEvent.h>
#include <GDJS/Events/CodeGeneration/BehaviorCodeGenerator.h>
#include <GDJS/Events/CodeGeneration/EventsFunctionsExtensionCodeGenerator.h>
#include <GDJS/Events/CodeGeneration/LayoutCodeGenerator.h>
#include <GDJS/IDE/Exporter.h>
#include <GDJS/IDE/ExporterHelper.h>
#include <emscripten.h>
#include <map>
#include <set>
#include <string>
#include <utility>
#include <vector>
#include "../../Extensions/PanelSpriteObject/PanelSpriteObject.h"
#include "../../Extensions/ParticleSystem/ParticleEmitterObject.h"
#include "../../Extensions/PrimitiveDrawing/ShapePainterObject.h"
#include "../../Extensions/SkeletonObject/SkeletonObject.h"
#include "../../Extensions/TextEntryObject/TextEntryObject.h"
#include "../../Extensions/TextObject/TextObject.h"
#include "../../Extensions/TiledSpriteObject/TiledSpriteObject.h"
#include "../../Extensions/SkeletonObject/SkeletonObject.h"
#include <GDJS/Events/Builtin/JsCodeEvent.h>
#include <GDJS/Events/CodeGeneration/LayoutCodeGenerator.h>
#include <GDJS/Events/CodeGeneration/BehaviorCodeGenerator.h>
#include <GDJS/Events/CodeGeneration/EventsFunctionsExtensionCodeGenerator.h>
#include <GDJS/IDE/Exporter.h>
#include <GDJS/IDE/ExporterHelper.h>
#include <emscripten.h>
#include "ProjectHelper.h"
#include "BehaviorJsImplementation.h"
#include "BehaviorSharedDataJsImplementation.h"
#include "ObjectJsImplementation.h"
#include "ProjectHelper.h"
/**
* \brief Manual binding of gd::ArbitraryResourceWorker to allow overriding
@@ -341,7 +336,8 @@ void removeFromVectorVector2f(std::vector<sf::Vector2f> &vec, size_t pos) {
vec.erase(vec.begin() + pos);
}
void removeFromVectorParameterMetadata(std::vector<gd::ParameterMetadata> &vec, size_t pos) {
void removeFromVectorParameterMetadata(std::vector<gd::ParameterMetadata> &vec,
size_t pos) {
vec.erase(vec.begin() + pos);
}
@@ -378,23 +374,33 @@ typedef std::vector<Polygon2d> VectorPolygon2d;
typedef std::vector<sf::Vector2f> VectorVector2f;
typedef std::vector<EventsSearchResult> VectorEventsSearchResult;
typedef std::vector<gd::ParameterMetadata> VectorParameterMetadata;
typedef std::vector<gd::DependencyMetadata> VectorDependencyMetadata;
typedef std::vector<gd::EventsFunction> VectorEventsFunction;
typedef gd::Object gdObject; // To avoid clashing javascript Object in glue.js
typedef ParticleEmitterObject::RendererType ParticleEmitterObject_RendererType;
typedef EventsFunction::FunctionType EventsFunction_FunctionType;
typedef std::unique_ptr<gd::Object> UniquePtrObject;
typedef std::unique_ptr<ExpressionNode> UniquePtrExpressionNode;
typedef std::vector<gd::ExpressionParserDiagnostic*> VectorExpressionParserDiagnostic;
typedef gd::SerializableWithNameList<gd::EventsBasedBehavior> EventsBasedBehaviorsList;
typedef gd::SerializableWithNameList<gd::NamedPropertyDescriptor> NamedPropertyDescriptorsList;
typedef ExpressionCompletionDescription::CompletionKind ExpressionCompletionDescription_CompletionKind;
typedef std::vector<gd::ExpressionCompletionDescription> VectorExpressionCompletionDescription;
typedef std::vector<gd::ExpressionParserDiagnostic *>
VectorExpressionParserDiagnostic;
typedef gd::SerializableWithNameList<gd::EventsBasedBehavior>
EventsBasedBehaviorsList;
typedef gd::SerializableWithNameList<gd::NamedPropertyDescriptor>
NamedPropertyDescriptorsList;
typedef ExpressionCompletionDescription::CompletionKind
ExpressionCompletionDescription_CompletionKind;
typedef std::vector<gd::ExpressionCompletionDescription>
VectorExpressionCompletionDescription;
typedef std::map<gd::String, std::map<gd::String, gd::PropertyDescriptor>>
MapExtensionProperties;
typedef ExtensionAndMetadata<BehaviorMetadata> ExtensionAndBehaviorMetadata;
typedef ExtensionAndMetadata<ObjectMetadata> ExtensionAndObjectMetadata;
typedef ExtensionAndMetadata<EffectMetadata> ExtensionAndEffectMetadata;
typedef ExtensionAndMetadata<InstructionMetadata> ExtensionAndInstructionMetadata;
typedef ExtensionAndMetadata<InstructionMetadata> ExtensionAndInstructionMetadata;
typedef ExtensionAndMetadata<InstructionMetadata>
ExtensionAndInstructionMetadata;
typedef ExtensionAndMetadata<InstructionMetadata>
ExtensionAndInstructionMetadata;
typedef ExtensionAndMetadata<ExpressionMetadata> ExtensionAndExpressionMetadata;
typedef ExtensionAndMetadata<ExpressionMetadata> ExtensionAndExpressionMetadata;
typedef ExtensionAndMetadata<ExpressionMetadata> ExtensionAndExpressionMetadata;
@@ -468,12 +474,18 @@ typedef ExtensionAndMetadata<ExpressionMetadata> ExtensionAndExpressionMetadata;
#define STATIC_GetExtensionAndEffectMetadata GetExtensionAndEffectMetadata
#define STATIC_GetExtensionAndActionMetadata GetExtensionAndActionMetadata
#define STATIC_GetExtensionAndConditionMetadata GetExtensionAndConditionMetadata
#define STATIC_GetExtensionAndExpressionMetadata GetExtensionAndExpressionMetadata
#define STATIC_GetExtensionAndObjectExpressionMetadata GetExtensionAndObjectExpressionMetadata
#define STATIC_GetExtensionAndBehaviorExpressionMetadata GetExtensionAndBehaviorExpressionMetadata
#define STATIC_GetExtensionAndStrExpressionMetadata GetExtensionAndStrExpressionMetadata
#define STATIC_GetExtensionAndObjectStrExpressionMetadata GetExtensionAndObjectStrExpressionMetadata
#define STATIC_GetExtensionAndBehaviorStrExpressionMetadata GetExtensionAndBehaviorStrExpressionMetadata
#define STATIC_GetExtensionAndExpressionMetadata \
GetExtensionAndExpressionMetadata
#define STATIC_GetExtensionAndObjectExpressionMetadata \
GetExtensionAndObjectExpressionMetadata
#define STATIC_GetExtensionAndBehaviorExpressionMetadata \
GetExtensionAndBehaviorExpressionMetadata
#define STATIC_GetExtensionAndStrExpressionMetadata \
GetExtensionAndStrExpressionMetadata
#define STATIC_GetExtensionAndObjectStrExpressionMetadata \
GetExtensionAndObjectStrExpressionMetadata
#define STATIC_GetExtensionAndBehaviorStrExpressionMetadata \
GetExtensionAndBehaviorStrExpressionMetadata
#define STATIC_HasCondition HasCondition
#define STATIC_HasAction HasAction
#define STATIC_HasObjectAction HasObjectAction
@@ -515,12 +527,16 @@ typedef ExtensionAndMetadata<ExpressionMetadata> ExtensionAndExpressionMetadata;
#define STATIC_Date Date
#define STATIC_ObjectOrGroupRenamedInLayout ObjectOrGroupRenamedInLayout
#define STATIC_ObjectOrGroupRemovedInLayout ObjectOrGroupRemovedInLayout
#define STATIC_ObjectOrGroupRemovedInEventsFunction ObjectOrGroupRemovedInEventsFunction
#define STATIC_ObjectOrGroupRenamedInEventsFunction ObjectOrGroupRenamedInEventsFunction
#define STATIC_ObjectOrGroupRemovedInEventsFunction \
ObjectOrGroupRemovedInEventsFunction
#define STATIC_ObjectOrGroupRenamedInEventsFunction \
ObjectOrGroupRenamedInEventsFunction
#define STATIC_GlobalObjectOrGroupRenamed GlobalObjectOrGroupRenamed
#define STATIC_GlobalObjectOrGroupRemoved GlobalObjectOrGroupRemoved
#define STATIC_GetAllObjectTypesUsingEventsBasedBehavior GetAllObjectTypesUsingEventsBasedBehavior
#define STATIC_EnsureBehaviorEventsFunctionsProperParameters EnsureBehaviorEventsFunctionsProperParameters
#define STATIC_GetAllObjectTypesUsingEventsBasedBehavior \
GetAllObjectTypesUsingEventsBasedBehavior
#define STATIC_EnsureBehaviorEventsFunctionsProperParameters \
EnsureBehaviorEventsFunctionsProperParameters
#define STATIC_CreateRectangle CreateRectangle
#define STATIC_SanityCheckBehaviorProperty SanityCheckBehaviorProperty
#define STATIC_SanityCheckObjectProperty SanityCheckObjectProperty
@@ -540,7 +556,8 @@ typedef ExtensionAndMetadata<ExpressionMetadata> ExtensionAndExpressionMetadata;
#define STATIC_RenameEventsFunction RenameEventsFunction
#define STATIC_RenameBehaviorEventsFunction RenameBehaviorEventsFunction
#define STATIC_MoveEventsFunctionParameter MoveEventsFunctionParameter
#define STATIC_MoveBehaviorEventsFunctionParameter MoveBehaviorEventsFunctionParameter
#define STATIC_MoveBehaviorEventsFunctionParameter \
MoveBehaviorEventsFunctionParameter
#define STATIC_RenameBehaviorProperty RenameBehaviorProperty
#define STATIC_RenameEventsBasedBehavior RenameEventsBasedBehavior
@@ -552,7 +569,8 @@ typedef ExtensionAndMetadata<ExpressionMetadata> ExtensionAndExpressionMetadata;
#define STATIC_CopyAllResourcesTo CopyAllResourcesTo
#define STATIC_IsExtensionLifecycleEventsFunction IsExtensionLifecycleEventsFunction
#define STATIC_IsExtensionLifecycleEventsFunction \
IsExtensionLifecycleEventsFunction
#define STATIC_GetCompletionDescriptionsFor GetCompletionDescriptionsFor
+17
View File
@@ -0,0 +1,17 @@
// Automatically generated by GDevelop.js/scripts/generate-types.js
declare class gdDependencyMetadata {
constructor(): void;
getName(): string;
setName(name_: string): gdDependencyMetadata;
getExportName(): string;
setExportName(exportName_: string): gdDependencyMetadata;
getVersion(): string;
setVersion(version_: string): gdDependencyMetadata;
getDependencyType(): string;
setDependencyType(dependencyType_: string): gdDependencyMetadata;
getExtraSetting(settingName: string): gdPropertyDescriptor;
setExtraSetting(settingName: string, settingValue: gdPropertyDescriptor): gdDependencyMetadata;
getAllExtraSettings(): gdMapStringPropertyDescriptor;
delete(): void;
ptr: number;
};
@@ -0,0 +1,11 @@
// Automatically generated by GDevelop.js/scripts/generate-types.js
declare class gdExtensionProperties {
getValue(extension: string, property: string): string;
setValue(extension: string, property: string, newValue: string): void;
hasProperty(extension: string, property: string): boolean;
getAllExtensionProperties(extension: string, project: gdProject): gdMapStringPropertyDescriptor;
serializeTo(element: gdSerializerElement): void;
unserializeFrom(element: gdSerializerElement): void;
delete(): void;
ptr: number;
};
@@ -0,0 +1,17 @@
// Automatically generated by GDevelop.js/scripts/generate-types.js
// Automatically generated by GDevelop.js/scripts/generate-types.js
// Automatically generated by GDevelop.js/scripts/generate-types.js
// Automatically generated by GDevelop.js/scripts/generate-types.js
// Automatically generated by GDevelop.js/scripts/generate-types.js
// Automatically generated by GDevelop.js/scripts/generate-types.js
// Automatically generated by GDevelop.js/scripts/generate-types.js
// Automatically generated by GDevelop.js/scripts/generate-types.js
// Automatically generated by GDevelop.js/scripts/generate-types.js
declare class gdExtensionPropertiesManager {
getValue(extension: string, property: string): string;
setValue(extension: string, property: string, newValue: string): void;
hasProperty(extension: string, property: string): boolean;
getAllExtensionProperties(extension: string, project: gdProject): gdMapStringPropertyDescriptor;
delete(): void;
ptr: number;
};
@@ -0,0 +1,9 @@
// Automatically generated by GDevelop.js/scripts/generate-types.js
declare class gdMapExtensionProperties {
get(name: string): gdMapStringPropertyDescriptor;
set(name: string, prop: gdMapStringPropertyDescriptor): void;
has(name: string): boolean;
keys(): gdVectorString;
delete(): void;
ptr: number;
};
+4
View File
@@ -8,9 +8,11 @@ declare class gdPlatformExtension {
addAction(name: string, fullname: string, description: string, sentence: string, group: string, icon: string, smallicon: string): gdInstructionMetadata;
addExpression(name: string, fullname: string, description: string, group: string, smallicon: string): gdExpressionMetadata;
addStrExpression(name: string, fullname: string, description: string, group: string, smallicon: string): gdExpressionMetadata;
addDependency(): gdDependencyMetadata;
addBehavior(name: string, fullname: string, defaultName: string, description: string, group: string, icon24x24: string, className: string, instance: gdBehavior, sharedDatasInstance: gdBehaviorsSharedData): gdBehaviorMetadata;
addObject(name: string, fullname: string, description: string, icon24x24: string, instance: gdObject): gdObjectMetadata;
addEffect(name: string): gdEffectMetadata;
registerProperty(name: string): gdPropertyDescriptor;
getFullName(): string;
getName(): string;
getDescription(): string;
@@ -38,6 +40,8 @@ declare class gdPlatformExtension {
getAllConditionsForBehavior(autoType: string): gdMapStringInstructionMetadata;
getAllExpressionsForBehavior(autoType: string): gdMapStringExpressionMetadata;
getAllStrExpressionsForBehavior(autoType: string): gdMapStringExpressionMetadata;
getAllProperties(): gdMapStringPropertyDescriptor;
getAllDependencies(): gdVectorDependencyMetadata;
static getNamespaceSeparator(): string;
delete(): void;
ptr: number;
+1 -2
View File
@@ -11,8 +11,6 @@ declare class gdProject extends gdObjectsContainer {
getPackageName(): string;
setOrientation(orientation: string): void;
getOrientation(): string;
setAdMobAppId(adMobAppId: string): void;
getAdMobAppId(): string;
setProjectFile(file: string): void;
getProjectFile(): string;
setGameResolutionSize(width: number, height: number): void;
@@ -33,6 +31,7 @@ declare class gdProject extends gdObjectsContainer {
setLastCompilationDirectory(path: string): void;
getLastCompilationDirectory(): string;
getUsedExtensions(): gdVectorString;
getExtensionProperties(): gdExtensionProperties;
addPlatform(platform: gdPlatform): void;
getCurrentPlatform(): gdPlatform;
getPlatformSpecificAssets(): gdPlatformSpecificAssets;
@@ -15,6 +15,8 @@ declare class gdPropertyDescriptor {
isHidden(): boolean;
serializeTo(element: gdSerializerElement): void;
unserializeFrom(element: gdSerializerElement): void;
serializeValuesTo(element: gdSerializerElement): void;
unserializeValuesFrom(element: gdSerializerElement): void;
delete(): void;
ptr: number;
};
@@ -0,0 +1,7 @@
// Automatically generated by GDevelop.js/scripts/generate-types.js
declare class gdVectorDependencyMetadata {
size(): number;
at(index: number): gdDependencyMetadata;
delete(): void;
ptr: number;
};
+4
View File
@@ -34,6 +34,7 @@ declare class libGDevelop {
VectorString: Class<gdVectorString>;
VectorPlatformExtension: Class<gdVectorPlatformExtension>;
VectorDependencyMetadata: Class<gdVectorDependencyMetadata>;
MapStringString: Class<gdMapStringString>;
MapStringBoolean: Class<gdMapStringBoolean>;
MapStringDouble: Class<gdMapStringDouble>;
@@ -41,6 +42,7 @@ declare class libGDevelop {
MapStringExpressionMetadata: Class<gdMapStringExpressionMetadata>;
MapStringInstructionMetadata: Class<gdMapStringInstructionMetadata>;
MapStringEventMetadata: Class<gdMapStringEventMetadata>;
MapExtensionProperties: Class<gdMapExtensionProperties>;
SetString: Class<gdSetString>;
ProjectHelper: Class<gdProjectHelper>;
VersionWrapper: Class<gdVersionWrapper>;
@@ -55,6 +57,7 @@ declare class libGDevelop {
LoadingScreen: Class<gdLoadingScreen>;
ObjectsContainer: Class<gdObjectsContainer>;
Project: Class<gdProject>;
ExtensionProperties: Class<gdExtensionProperties>;
Behavior: Class<gdBehavior>;
BehaviorJsImplementation: Class<gdBehaviorJsImplementation>;
BehaviorContent: Class<gdBehaviorContent>;
@@ -96,6 +99,7 @@ declare class libGDevelop {
ExpressionCodeGenerationInformation: Class<gdExpressionCodeGenerationInformation>;
InstructionMetadata: Class<gdInstructionMetadata>;
ExpressionMetadata: Class<gdExpressionMetadata>;
DependencyMetadata: Class<gdDependencyMetadata>;
ParameterMetadata: Class<gdParameterMetadata>;
VectorParameterMetadata: Class<gdVectorParameterMetadata>;
ParameterMetadataTools: Class<gdParameterMetadataTools>;
+68
View File
@@ -127,6 +127,74 @@ Add an object using [`addObject`](https://docs.gdevelop-app.com/GDCore%20Documen
> ℹ️ After doing this, you can actually see your object in GDevelop! Read the next sections to see how to add an editor and a renderer for instances on the scene editor.
#### Declare a property
A property is a global configuration value for your extension. An example would be the App ID for AdMob.
To declare one, just use `registerProperty`:
```js
// From ExampleJsExtension/JsExtension.js:
extension.registerProperty("DummyPropertyString")
.setDescription(_("Dummy Property Name"))
.setType("string")
.setLabel("Type in anything :)");
```
Once declared, you can access the property from JavaScript in the game engine using `getExtensionProperty` method of `gdjs.RuntimeGame`. Pass the extension name and the property name. This would get the AdMobAppId property of the AdMob extension for example:
```js
const appId = runtimeGame.getExtensionProperty("AdMob", "AdMobAppId");
```
If the property doesn't exist it will return null.
⚠️ Be careful, it can be non existing if the user never entered a value for that property before!
#### Declare a dependency on an external package
You can declare a dependency on an npm package or cordova plugin with `addDependency`. Example:
```js
// From ExampleJsExtension/JsExtension.js:
extension
.addDependency()
.setName("Thirteen Checker")
.setDependencyType("npm")
.setExportName("is-thirteen")
.setVersion("2.0.0");
```
On cordova you can add plugin variables as extra properties:
```js
extension.addDependency()
.setName("Some Cordova Extension")
.setDependencyType("cordova")
.setExportName("cordova-some-plugin")
.setVersion("1.0.0")
.setExtraSetting(
"VARIABLE_NAME",
new gd.PropertyDescriptor().setValue("42")
);
```
You can also use an extension property to determine the value of the plugin variable:
```js
// From AdMob/JsExtension.js:
extension.registerProperty("AdMobAppId") // Remember Property Name
.setDescription("AdMob App ID")
.setType("string")
.setLabel("ca-app-pub-XXXXXXXXXXXXXXXX/YYYYYYYYYY");
extension.addDependency()
.setName("AdMob Cordova Extension")
.setDependencyType("cordova")
.setExportName("cordova-plugin-admob-free")
.setVersion("~0.21.0")
.setExtraSetting(
"ADMOB_APP_ID",
new gd.PropertyDescriptor()
.setType("ExtensionProperty") // Tell the exporter this is an extension property...
.setValue("AdMobAppId") // ... and what property it is (name of the property).
);
```
#### Declare an object editor
To add an editor to your object, implement the function `registerEditorConfigurations` in your extension module. For now, only a default editor, displaying the object properties, is supported:
@@ -0,0 +1,70 @@
// @flow
import { Trans } from '@lingui/macro';
import * as React from 'react';
import Text from '../UI/Text';
import { ColumnStackLayout } from '../UI/Layout';
import PropertiesEditor from '../PropertiesEditor';
import propertiesMapToSchema from '../PropertiesEditor/PropertiesMapToSchema';
import { List } from '@material-ui/core';
type Props = {|
project: gdProject,
|};
function ExtensionsProperties(props: Props) {
const { project } = props;
const allExtensions = project.getCurrentPlatform().getAllPlatformExtensions();
const propertyList = [];
for (let i = 0; i < allExtensions.size(); i++) {
const extension = allExtensions.at(i);
const properties = project
.getExtensionProperties()
.getAllExtensionProperties(extension.getName(), project);
if (properties.keys().size() === 0) continue;
const propertiesSchema = propertiesMapToSchema(
properties,
instance =>
project
.getExtensionProperties()
.getAllExtensionProperties(extension.getName(), project),
(instance, propertyName, newValue) => {
if (
project
.getExtensionProperties()
.getAllExtensionProperties(extension.getName(), project)
.get(propertyName)
.getType() === 'boolean'
) {
project
.getExtensionProperties()
.setValue(
extension.getName(),
propertyName,
newValue === '1' ? 'true' : 'false'
);
} else {
project
.getExtensionProperties()
.setValue(extension.getName(), propertyName, newValue);
}
}
);
propertyList.push(
<ColumnStackLayout key={extension.getName()} noMargin>
<Text size="title">
<Trans>{extension.getFullName()}</Trans>
</Text>
<PropertiesEditor
schema={propertiesSchema}
instances={[extension.getAllProperties()]}
/>
</ColumnStackLayout>
);
}
return propertyList.length ? <List>{propertyList}</List> : null;
}
export default ExtensionsProperties;
@@ -19,6 +19,8 @@ import DismissableAlertMessage from '../UI/DismissableAlertMessage';
import HelpButton from '../UI/HelpButton';
import { ResponsiveLineStackLayout, ColumnStackLayout } from '../UI/Layout';
import Text from '../UI/Text';
import ExtensionsProperties from './ExtensionsProperties';
import { useSerializableObjectCancelableEditor } from '../Utils/SerializableObjectCancelableEditor';
type Props = {|
project: gdProject,
@@ -28,7 +30,7 @@ type Props = {|
onChangeSubscription: () => void,
|};
type State = {|
type ProjectProperties = {|
gameResolutionWidth: number,
gameResolutionHeight: number,
adaptGameResolutionAtRuntime: boolean,
@@ -37,7 +39,6 @@ type State = {|
version: string,
packageName: string,
orientation: string,
adMobAppId: string,
scaleMode: string,
sizeOnStartupMode: string,
showGDevelopSplash: boolean,
@@ -46,417 +47,402 @@ type State = {|
isFolderProject: boolean,
|};
class ProjectPropertiesDialog extends React.Component<Props, State> {
constructor(props: Props) {
super(props);
this.state = this._loadFrom(props.project);
}
_subscriptionChecker: ?SubscriptionChecker = null;
_loadFrom(project: gdProject): State {
return {
gameResolutionWidth: project.getGameResolutionWidth(),
gameResolutionHeight: project.getGameResolutionHeight(),
adaptGameResolutionAtRuntime: project.getAdaptGameResolutionAtRuntime(),
name: project.getName(),
author: project.getAuthor(),
version: project.getVersion(),
packageName: project.getPackageName(),
orientation: project.getOrientation(),
adMobAppId: project.getAdMobAppId(),
scaleMode: project.getScaleMode(),
sizeOnStartupMode: project.getSizeOnStartupMode(),
showGDevelopSplash: project.getLoadingScreen().isGDevelopSplashShown(),
minFPS: project.getMinimumFPS(),
maxFPS: project.getMaximumFPS(),
isFolderProject: project.isFolderProject(),
};
}
componentWillReceiveProps(newProps: Props) {
if (
(!this.props.open && newProps.open) ||
(newProps.open && this.props.project !== newProps.project)
) {
this.setState(this._loadFrom(newProps.project));
}
}
_onApply = () => {
const t = str => str; //TODO
const { project } = this.props;
const {
gameResolutionWidth,
gameResolutionHeight,
adaptGameResolutionAtRuntime,
name,
author,
version,
packageName,
orientation,
adMobAppId,
scaleMode,
sizeOnStartupMode,
showGDevelopSplash,
minFPS,
maxFPS,
isFolderProject,
} = this.state;
project.setGameResolutionSize(gameResolutionWidth, gameResolutionHeight);
project.setAdaptGameResolutionAtRuntime(adaptGameResolutionAtRuntime);
project.setName(name);
project.setAuthor(author);
project.setVersion(version);
project.setPackageName(packageName);
project.setOrientation(orientation);
project.setAdMobAppId(adMobAppId);
project.setScaleMode(scaleMode);
project.setSizeOnStartupMode(sizeOnStartupMode);
project.setMinimumFPS(minFPS);
project.setMaximumFPS(maxFPS);
project.getLoadingScreen().showGDevelopSplash(showGDevelopSplash);
project.setFolderProject(isFolderProject);
if (!displayProjectErrorsBox(t, getErrors(t, project))) return;
this.props.onApply();
function loadPropertiesFromProject(project: gdProject): ProjectProperties {
return {
gameResolutionWidth: project.getGameResolutionWidth(),
gameResolutionHeight: project.getGameResolutionHeight(),
adaptGameResolutionAtRuntime: project.getAdaptGameResolutionAtRuntime(),
name: project.getName(),
author: project.getAuthor(),
version: project.getVersion(),
packageName: project.getPackageName(),
orientation: project.getOrientation(),
scaleMode: project.getScaleMode(),
sizeOnStartupMode: project.getSizeOnStartupMode(),
showGDevelopSplash: project.getLoadingScreen().isGDevelopSplashShown(),
minFPS: project.getMinimumFPS(),
maxFPS: project.getMaximumFPS(),
isFolderProject: project.isFolderProject(),
};
}
render() {
const {
name,
gameResolutionWidth,
gameResolutionHeight,
adaptGameResolutionAtRuntime,
author,
version,
packageName,
orientation,
adMobAppId,
scaleMode,
sizeOnStartupMode,
showGDevelopSplash,
minFPS,
maxFPS,
isFolderProject,
} = this.state;
function applyPropertiesToProject(
project: gdProject,
newProperties: ProjectProperties
) {
const t = str => str; //TODO
const {
gameResolutionWidth,
gameResolutionHeight,
adaptGameResolutionAtRuntime,
name,
author,
version,
packageName,
orientation,
scaleMode,
sizeOnStartupMode,
showGDevelopSplash,
minFPS,
maxFPS,
isFolderProject,
} = newProperties;
project.setGameResolutionSize(gameResolutionWidth, gameResolutionHeight);
project.setAdaptGameResolutionAtRuntime(adaptGameResolutionAtRuntime);
project.setName(name);
project.setAuthor(author);
project.setVersion(version);
project.setPackageName(packageName);
project.setOrientation(orientation);
project.setScaleMode(scaleMode);
project.setSizeOnStartupMode(sizeOnStartupMode);
project.setMinimumFPS(minFPS);
project.setMaximumFPS(maxFPS);
project.getLoadingScreen().showGDevelopSplash(showGDevelopSplash);
project.setFolderProject(isFolderProject);
const defaultPackageName = 'com.example.mygame';
const admobHint = 'ca-app-pub-XXXXXXXXXXXXXXXX/YYYYYYYYYY';
const defaultVersion = '1.0.0';
return displayProjectErrorsBox(t, getErrors(t, project));
}
return (
<React.Fragment>
<Dialog
actions={[
<FlatButton
label={<Trans>Cancel</Trans>}
primary={false}
onClick={this.props.onClose}
key="cancel"
/>,
<FlatButton
label={<Trans>Apply</Trans>}
primary={true}
onClick={this._onApply}
key="apply"
/>,
]}
secondaryActions={[
<HelpButton
helpPagePath="/interface/project-manager/properties"
key="help"
/>,
]}
title={<Trans>Project properties</Trans>}
cannotBeDismissed={true}
open={this.props.open}
onRequestClose={this.props.onClose}
>
<ColumnStackLayout noMargin>
<SemiControlledTextField
floatingLabelText={<Trans>Game name</Trans>}
fullWidth
type="text"
value={name}
onChange={value => this.setState({ name: value })}
autoFocus
/>
<Checkbox
label={
<Trans>
Display GDevelop splash at startup (in exported game)
</Trans>
}
checked={showGDevelopSplash}
onCheck={(e, checked) => {
if (!checked) {
if (
this._subscriptionChecker &&
!this._subscriptionChecker.checkHasSubscription()
)
return;
}
function ProjectPropertiesDialog(props: Props) {
const { project } = props;
this.setState({
showGDevelopSplash: checked,
});
}}
/>
<SemiControlledTextField
floatingLabelText={<Trans>Version number (X.Y.Z)</Trans>}
fullWidth
hintText={defaultVersion}
type="text"
value={version}
onChange={value => this.setState({ version: value })}
/>
<SemiControlledTextField
floatingLabelText={
<Trans>Package name (for iOS and Android)</Trans>
}
fullWidth
hintText={defaultPackageName}
type="text"
value={packageName}
onChange={value => this.setState({ packageName: value })}
errorText={
validatePackageName(packageName) ? (
undefined
) : (
<Trans>
The package name is containing invalid characters or not
following the convention "xxx.yyy.zzz" (numbers allowed
after a letter only).
</Trans>
const subscriptionChecker = React.useRef<?SubscriptionChecker>(null);
const initialProperties = React.useMemo(
() => loadPropertiesFromProject(project),
[project]
);
let [name, setName] = React.useState(initialProperties.name);
let [gameResolutionWidth, setGameResolutionWidth] = React.useState(
initialProperties.gameResolutionWidth
);
let [gameResolutionHeight, setGameResolutionHeight] = React.useState(
initialProperties.gameResolutionHeight
);
let [
adaptGameResolutionAtRuntime,
setAdaptGameResolutionAtRuntime,
] = React.useState(initialProperties.adaptGameResolutionAtRuntime);
let [author, setAuthor] = React.useState(initialProperties.author);
let [version, setVersion] = React.useState(initialProperties.version);
let [packageName, setPackageName] = React.useState(
initialProperties.packageName
);
let [orientation, setOrientation] = React.useState(
initialProperties.orientation
);
let [scaleMode, setScaleMode] = React.useState(initialProperties.scaleMode);
let [sizeOnStartupMode, setSizeOnStartupMode] = React.useState(
initialProperties.sizeOnStartupMode
);
let [showGDevelopSplash, setShowGDevelopSplash] = React.useState(
initialProperties.showGDevelopSplash
);
let [minFPS, setMinFPS] = React.useState(initialProperties.minFPS);
let [maxFPS, setMaxFPS] = React.useState(initialProperties.maxFPS);
let [isFolderProject, setIsFolderProject] = React.useState(
initialProperties.isFolderProject
);
const defaultPackageName = 'com.example.mygame';
const defaultVersion = '1.0.0';
const onCancelChanges = useSerializableObjectCancelableEditor({
serializableObject: project.getExtensionProperties(),
onCancel: props.onClose,
});
return (
<React.Fragment>
<Dialog
actions={[
<FlatButton
label={<Trans>Cancel</Trans>}
primary={false}
onClick={onCancelChanges}
key="cancel"
/>,
<FlatButton
label={<Trans>Apply</Trans>}
primary={true}
onClick={() => {
if (
applyPropertiesToProject(project, {
gameResolutionWidth,
gameResolutionHeight,
adaptGameResolutionAtRuntime,
name,
author,
version,
packageName,
orientation,
scaleMode,
sizeOnStartupMode,
showGDevelopSplash,
minFPS,
maxFPS,
isFolderProject,
})
)
props.onApply();
}}
key="apply"
/>,
]}
secondaryActions={[
<HelpButton
helpPagePath="/interface/project-manager/properties"
key="help"
/>,
]}
title={<Trans>Project properties</Trans>}
cannotBeDismissed={true}
open={props.open}
onRequestClose={props.onClose}
>
<ColumnStackLayout noMargin>
<SemiControlledTextField
floatingLabelText={<Trans>Game name</Trans>}
fullWidth
type="text"
value={name}
onChange={setName}
autoFocus
/>
<Checkbox
label={
<Trans>
Display GDevelop splash at startup (in exported game)
</Trans>
}
checked={showGDevelopSplash}
onCheck={(e, checked) => {
if (!checked) {
if (
subscriptionChecker.current &&
!subscriptionChecker.current.checkHasSubscription()
)
return;
}
setShowGDevelopSplash(checked);
}}
/>
<SemiControlledTextField
floatingLabelText={<Trans>Version number (X.Y.Z)</Trans>}
fullWidth
hintText={defaultVersion}
type="text"
value={version}
onChange={setVersion}
/>
<SemiControlledTextField
floatingLabelText={
<Trans>Package name (for iOS and Android)</Trans>
}
fullWidth
hintText={defaultPackageName}
type="text"
value={packageName}
onChange={setPackageName}
errorText={
validatePackageName(packageName) ? (
undefined
) : (
<Trans>
The package name is containing invalid characters or not
following the convention "xxx.yyy.zzz" (numbers allowed after
a letter only).
</Trans>
)
}
/>
<SemiControlledTextField
floatingLabelText={<Trans>Author name</Trans>}
fullWidth
hintText={t`Your name`}
type="text"
value={author}
onChange={setAuthor}
/>
<Text size="title">
<Trans>Resolution and rendering</Trans>
</Text>
<ResponsiveLineStackLayout noMargin>
<SemiControlledTextField
floatingLabelText={<Trans>Game resolution width</Trans>}
fullWidth
type="number"
value={'' + gameResolutionWidth}
onChange={value =>
setGameResolutionWidth(Math.max(1, parseInt(value, 10)))
}
/>
<SemiControlledTextField
floatingLabelText={<Trans>Author name</Trans>}
floatingLabelText={<Trans>Game resolution height</Trans>}
fullWidth
hintText={t`Your name`}
type="text"
value={author}
onChange={value => this.setState({ author: value })}
type="number"
value={'' + gameResolutionHeight}
onChange={value =>
setGameResolutionHeight(Math.max(1, parseInt(value, 10)))
}
/>
<Text size="title">
<Trans>Resolution and rendering</Trans>
</Text>
<ResponsiveLineStackLayout noMargin>
<SemiControlledTextField
floatingLabelText={<Trans>Game resolution width</Trans>}
fullWidth
type="number"
value={'' + gameResolutionWidth}
onChange={value =>
this.setState({
gameResolutionWidth: Math.max(1, parseInt(value, 10)),
})
}
/>
<SemiControlledTextField
floatingLabelText={<Trans>Game resolution height</Trans>}
fullWidth
type="number"
value={'' + gameResolutionHeight}
onChange={value =>
this.setState({
gameResolutionHeight: Math.max(1, parseInt(value, 10)),
})
}
/>
</ResponsiveLineStackLayout>
<SelectField
fullWidth
floatingLabelText={
<Trans>
Game resolution resize mode (fullscreen or window)
</Trans>
}
value={sizeOnStartupMode}
onChange={(e, i, value: string) =>
this.setState({ sizeOnStartupMode: value })
}
>
<SelectOption
value=""
primaryText={t`No changes to the game size`}
/>
<SelectOption
value="adaptWidth"
primaryText={t`Change width to fit the screen or window size`}
/>
<SelectOption
value="adaptHeight"
primaryText={t`Change height to fit the screen or window size`}
/>
</SelectField>
<Checkbox
label={
<Trans>
Update resolution during the game to fit the screen or window
size
</Trans>
}
disabled={sizeOnStartupMode === ''}
checked={adaptGameResolutionAtRuntime}
onCheck={(e, checked) => {
this.setState({
adaptGameResolutionAtRuntime: checked,
});
}}
</ResponsiveLineStackLayout>
<SelectField
fullWidth
floatingLabelText={
<Trans>Game resolution resize mode (fullscreen or window)</Trans>
}
value={sizeOnStartupMode}
onChange={(e, i, value: string) => setSizeOnStartupMode(value)}
>
<SelectOption
value=""
primaryText={t`No changes to the game size`}
/>
<ResponsiveLineStackLayout noMargin>
<SemiControlledTextField
floatingLabelText={<Trans>Minimum FPS</Trans>}
fullWidth
type="number"
value={'' + minFPS}
onChange={value =>
this.setState({
minFPS: Math.max(0, parseInt(value, 10)),
})
}
/>
<SemiControlledTextField
floatingLabelText={<Trans>Maximum FPS (0 to disable)</Trans>}
fullWidth
type="number"
value={'' + maxFPS}
onChange={value =>
this.setState({
maxFPS: Math.max(0, parseInt(value, 10)),
})
}
/>
</ResponsiveLineStackLayout>
{maxFPS > 0 && maxFPS < 60 && (
<DismissableAlertMessage
identifier="maximum-fps-too-low"
kind="warning"
>
<Trans>
Most monitors have a refresh rate of 60 FPS. Setting a maximum
number of FPS under 60 will force the game to skip frames, and
the real number of FPS will be way below 60, making the game
laggy and impacting the gameplay negatively. Consider putting
60 or more for the maximum number or FPS, or disable it by
setting 0.
</Trans>
</DismissableAlertMessage>
)}
{minFPS < 20 && (
<DismissableAlertMessage
identifier="minimum-fps-too-low"
kind="warning"
>
<Trans>
Setting the minimum number of FPS below 20 will increase a lot
the time that is allowed between the simulation of two frames
of the game. If case of a sudden slowdown, or on slow
computers, this can create buggy behaviors like objects
passing beyond a wall. Consider setting 20 as the minimum FPS.
</Trans>
</DismissableAlertMessage>
)}
<SelectField
fullWidth
floatingLabelText={
<Trans>Device orientation (for iOS and Android)</Trans>
}
value={orientation}
onChange={(e, i, value: string) =>
this.setState({ orientation: value })
}
>
<SelectOption value="default" primaryText={t`Platform default`} />
<SelectOption value="landscape" primaryText={t`Landscape`} />
<SelectOption value="portrait" primaryText={t`Portrait`} />
</SelectField>
<SelectField
fullWidth
floatingLabelText={
<Trans>Scale mode (also called "Sampling")</Trans>
}
value={scaleMode}
onChange={(e, i, value: string) =>
this.setState({ scaleMode: value })
}
>
<SelectOption
value="linear"
primaryText={t`Linear (antialiased rendering, good for most games)`}
/>
<SelectOption
value="nearest"
primaryText={t`Nearest (no antialiasing, good for pixel perfect games)`}
/>
</SelectField>
{scaleMode === 'nearest' && (
<DismissableAlertMessage
identifier="use-non-smoothed-textures"
kind="info"
>
<Trans>
To obtain the best pixel-perfect effect possible, go in the
resources editor and disable the Smoothing for all images of
your game. It will be done automatically for new images added
from now.
</Trans>
</DismissableAlertMessage>
)}
<Text size="title">
<Trans>AdMob</Trans>
</Text>
<SelectOption
value="adaptWidth"
primaryText={t`Change width to fit the screen or window size`}
/>
<SelectOption
value="adaptHeight"
primaryText={t`Change height to fit the screen or window size`}
/>
</SelectField>
<Checkbox
label={
<Trans>
Update resolution during the game to fit the screen or window
size
</Trans>
}
disabled={sizeOnStartupMode === ''}
checked={adaptGameResolutionAtRuntime}
onCheck={(e, checked) => setAdaptGameResolutionAtRuntime(checked)}
/>
<ResponsiveLineStackLayout noMargin>
<SemiControlledTextField
floatingLabelText={
<Trans>AdMob application ID (for iOS and Android)</Trans>
}
floatingLabelText={<Trans>Minimum FPS</Trans>}
fullWidth
hintText={admobHint}
type="text"
value={adMobAppId}
onChange={value => this.setState({ adMobAppId: value })}
type="number"
value={'' + minFPS}
onChange={value => setMinFPS(Math.max(0, parseInt(value, 10)))}
/>
<Text size="title">
<Trans>Project files</Trans>
</Text>
<SelectField
<SemiControlledTextField
floatingLabelText={<Trans>Maximum FPS (0 to disable)</Trans>}
fullWidth
floatingLabelText={<Trans>Project file type</Trans>}
value={isFolderProject ? 'folder-project' : 'single-file'}
onChange={(e, i, value: string) =>
this.setState({ isFolderProject: value === 'folder-project' })
}
type="number"
value={'' + maxFPS}
onChange={value => setMaxFPS(Math.max(0, parseInt(value, 10)))}
/>
</ResponsiveLineStackLayout>
{maxFPS > 0 && maxFPS < 60 && (
<DismissableAlertMessage
identifier="maximum-fps-too-low"
kind="warning"
>
<SelectOption
value={'single-file'}
primaryText={t`Single file (default)`}
/>
<SelectOption
value={'folder-project'}
primaryText={t`Multiple files, saved in folder next to the main file`}
/>
</SelectField>
</ColumnStackLayout>
</Dialog>
<SubscriptionChecker
ref={subscriptionChecker =>
(this._subscriptionChecker = subscriptionChecker)
}
onChangeSubscription={() => {
this.props.onClose();
this.props.onChangeSubscription();
}}
mode="mandatory"
id="Disable GDevelop splash at startup"
title={<Trans>Disable GDevelop splash at startup</Trans>}
/>
</React.Fragment>
);
}
<Trans>
Most monitors have a refresh rate of 60 FPS. Setting a maximum
number of FPS under 60 will force the game to skip frames, and
the real number of FPS will be way below 60, making the game
laggy and impacting the gameplay negatively. Consider putting 60
or more for the maximum number or FPS, or disable it by setting
0.
</Trans>
</DismissableAlertMessage>
)}
{minFPS < 20 && (
<DismissableAlertMessage
identifier="minimum-fps-too-low"
kind="warning"
>
<Trans>
Setting the minimum number of FPS below 20 will increase a lot
the time that is allowed between the simulation of two frames of
the game. If case of a sudden slowdown, or on slow computers,
this can create buggy behaviors like objects passing beyond a
wall. Consider setting 20 as the minimum FPS.
</Trans>
</DismissableAlertMessage>
)}
<SelectField
fullWidth
floatingLabelText={
<Trans>Device orientation (for iOS and Android)</Trans>
}
value={orientation}
onChange={(e, i, value: string) => setOrientation(value)}
>
<SelectOption value="default" primaryText={t`Platform default`} />
<SelectOption value="landscape" primaryText={t`Landscape`} />
<SelectOption value="portrait" primaryText={t`Portrait`} />
</SelectField>
<SelectField
fullWidth
floatingLabelText={
<Trans>Scale mode (also called "Sampling")</Trans>
}
value={scaleMode}
onChange={(e, i, value: string) => setScaleMode(value)}
>
<SelectOption
value="linear"
primaryText={t`Linear (antialiased rendering, good for most games)`}
/>
<SelectOption
value="nearest"
primaryText={t`Nearest (no antialiasing, good for pixel perfect games)`}
/>
</SelectField>
{scaleMode === 'nearest' && (
<DismissableAlertMessage
identifier="use-non-smoothed-textures"
kind="info"
>
<Trans>
To obtain the best pixel-perfect effect possible, go in the
resources editor and disable the Smoothing for all images of
your game. It will be done automatically for new images added
from now.
</Trans>
</DismissableAlertMessage>
)}
<Text size="title">
<Trans>Project files</Trans>
</Text>
<SelectField
fullWidth
floatingLabelText={<Trans>Project file type</Trans>}
value={isFolderProject ? 'folder-project' : 'single-file'}
onChange={(e, i, value: string) =>
setIsFolderProject(value === 'folder-project')
}
>
<SelectOption
value={'single-file'}
primaryText={t`Single file (default)`}
/>
<SelectOption
value={'folder-project'}
primaryText={t`Multiple files, saved in folder next to the main file`}
/>
</SelectField>
</ColumnStackLayout>
<ExtensionsProperties project={project} />
</Dialog>
<SubscriptionChecker
ref={subscriptionChecker}
onChangeSubscription={() => {
props.onClose();
props.onChangeSubscription();
}}
mode="mandatory"
id="Disable GDevelop splash at startup"
title={<Trans>Disable GDevelop splash at startup</Trans>}
/>
</React.Fragment>
);
}
export default ProjectPropertiesDialog;
+2037 -1512
View File
File diff suppressed because it is too large Load Diff