Compare commits

...

21 Commits

Author SHA1 Message Date
Florian Rival
5193b617b3 Improve create new project dialog
TODO: disable button if no prompt entered
2024-03-25 13:55:56 +01:00
Clément Pasteau
1bb473b0b0 Display questions when canceling a subscription (#6471) 2024-03-22 14:07:59 +01:00
Florian Rival
4376b4f36e Improve first screen layouts (#6468) 2024-03-22 10:33:42 +01:00
Florian Rival
6ecbae9c35 Display the coordinates of the center point of a Sprite even when set automatically
Fix #6472
2024-03-22 10:33:05 +01:00
D8H
93e9fc6aed Fix missing expressions for text object (#6470) 2024-03-21 10:30:25 +01:00
Clément Pasteau
7c0a7a4152 Game templates in changelog (#6458)
Do not show in changelog
2024-03-14 16:42:38 +01:00
Clément Pasteau
d4cdb3ff83 Bump to 5.3.195 (#6455) 2024-03-14 16:20:15 +01:00
AlexandreS
a7cac91e45 Fix warning about end of subscription (#6456)
Do not show in changelog
2024-03-14 15:49:09 +01:00
D8H
6a6d72cd9a Fix games from crashing when a scene contains a wrapped text object with a big font size (#6453) 2024-03-14 15:36:34 +01:00
github-actions[bot]
11d74b3ea5 Update translations [skip ci] (#6442)
Co-authored-by: ClementPasteau <4895034+ClementPasteau@users.noreply.github.com>
2024-03-14 15:31:27 +01:00
Clément Pasteau
5b65cf84eb Fix survey mobile (#6454)
Do not show in changelog
2024-03-14 15:00:57 +01:00
Clément Pasteau
6b7af0474f Improve Guided lessons (#6446)
* Lessons have been slightly reworked overall
* Most languages are now supported
* A new option allows to fill a value automatically with a button, speeding up the typing part
2024-03-14 14:40:12 +01:00
D8H
99f7e55044 Fix the object effect color tween action (#6452) 2024-03-14 14:13:28 +01:00
AlexandreS
6b522b1c31 Add support for game sessions achievements notifications (#6449) 2024-03-14 12:18:42 +01:00
D8H
0f35e48690 Allow to change text of custom objects like any text object (#6450) 2024-03-14 11:50:55 +01:00
D8H
53d19dd628 Fix custom object capability changes to be applied right away (#6447) 2024-03-14 10:49:33 +01:00
Florian Rival
155dc1bec8 Display redesigned subscription plans (#6440)
Don't show in changelog
2024-03-14 10:45:29 +01:00
D8H
be26e39eae Fix 3D custom objects CenterZ expression and condition (#6448) 2024-03-13 14:07:24 +01:00
TRP
90fa5ea8e8 Add action to draw a fillet rectangle with Shape painter (rounded rectangle with inverted corners) (#6433) 2024-03-12 16:11:02 +01:00
Florian Rival
4845251f78 Fix broken editor panels drag'n'drop (#6444) 2024-03-11 11:34:27 +01:00
Arthur Pacaud (arthuro555)
31ef3fec58 Add TypeScript type checking to JsExtension.js files (#6321) 2024-03-09 17:22:12 +01:00
204 changed files with 5516 additions and 4069 deletions

View File

@@ -56,6 +56,7 @@ blocks:
- name: GDJS typing and documentation generation
commands:
- checkout
- cache restore newIDE-app-node_modules-$SEMAPHORE_GIT_BRANCH-revision-$(checksum newIDE/app/package-lock.json)
- cache restore GDJS-node_modules-$SEMAPHORE_GIT_BRANCH-revision-$(checksum GDJS/package-lock.json)
- cache restore GDJS-tests-node_modules-$SEMAPHORE_GIT_BRANCH-revision-$(checksum GDJS/tests/package-lock.json)
- cd GDJS

1
.vscode/tasks.json vendored
View File

@@ -8,6 +8,7 @@
"group": "build",
"label": "Start development server",
"detail": "Starts the GDevelop development server.",
"options": { "env": { "NODE_OPTIONS": "--max-old-space-size=8192" } },
"problemMatcher": [
{
"owner": "cra",

View File

@@ -14,7 +14,8 @@ EventsBasedObject::EventsBasedObject()
"MyObject",
gd::EventsFunctionsContainer::FunctionOwner::Object),
ObjectsContainer(),
isRenderedIn3D(false) {
isRenderedIn3D(false),
isTextContainer(false) {
}
EventsBasedObject::~EventsBasedObject() {}
@@ -31,6 +32,9 @@ void EventsBasedObject::SerializeTo(SerializerElement& element) const {
if (isRenderedIn3D) {
element.SetBoolAttribute("is3D", true);
}
if (isTextContainer) {
element.SetBoolAttribute("isTextContainer", true);
}
AbstractEventsBasedEntity::SerializeTo(element);
SerializeObjectsTo(element.AddChild("objects"));
@@ -41,6 +45,7 @@ void EventsBasedObject::UnserializeFrom(gd::Project& project,
const SerializerElement& element) {
defaultName = element.GetStringAttribute("defaultName");
isRenderedIn3D = element.GetBoolAttribute("is3D", false);
isTextContainer = element.GetBoolAttribute("isTextContainer", false);
AbstractEventsBasedEntity::UnserializeFrom(project, element);
UnserializeObjectsFrom(project, element.GetChild("objects"));

View File

@@ -85,6 +85,19 @@ class GD_CORE_API EventsBasedObject: public AbstractEventsBasedEntity, public Ob
*/
bool IsRenderedIn3D() const { return isRenderedIn3D; }
/**
* \brief Declare a TextContainer capability.
*/
EventsBasedObject& MarkAsTextContainer(bool isTextContainer_) {
isTextContainer = isTextContainer_;
return *this;
}
/**
* \brief Return true if the object needs a TextContainer capability.
*/
bool IsTextContainer() const { return isTextContainer; }
void SerializeTo(SerializerElement& element) const override;
void UnserializeFrom(gd::Project& project,
@@ -93,6 +106,7 @@ class GD_CORE_API EventsBasedObject: public AbstractEventsBasedEntity, public Ob
private:
gd::String defaultName;
bool isRenderedIn3D;
bool isTextContainer;
};
} // namespace gd

View File

@@ -102,30 +102,19 @@ std::unique_ptr<gd::Object> Project::CreateObject(
behavior->SetDefaultBehavior(true);
};
if (project.HasEventsBasedObject(objectType)) {
// During project deserialization, event-based object metadata are not yet
// generated.
addDefaultBehavior("EffectCapability::EffectBehavior");
addDefaultBehavior("ResizableCapability::ResizableBehavior");
addDefaultBehavior("ScalableCapability::ScalableBehavior");
addDefaultBehavior("FlippableCapability::FlippableBehavior");
auto& eventBasedObject = project.GetEventsBasedObject(objectType);
if (eventBasedObject.IsRenderedIn3D()) {
addDefaultBehavior("Scene3D::Base3DBehavior");
}
else {
addDefaultBehavior("OpacityCapability::OpacityBehavior");
}
} else {
auto& objectMetadata =
gd::MetadataProvider::GetObjectMetadata(platform, objectType);
if (MetadataProvider::IsBadObjectMetadata(objectMetadata)) {
gd::LogWarning("Object: " + name + " has an unknown type: " + objectType);
}
for (auto& behaviorType : objectMetadata.GetDefaultBehaviors()) {
auto &objectMetadata =
gd::MetadataProvider::GetObjectMetadata(platform, objectType);
if (!MetadataProvider::IsBadObjectMetadata(objectMetadata)) {
for (auto &behaviorType : objectMetadata.GetDefaultBehaviors()) {
addDefaultBehavior(behaviorType);
}
}
// During project deserialization, event-based object metadata are not yet
// generated. Default behaviors will be added by
// MetadataDeclarationHelper::UpdateCustomObjectDefaultBehaviors
else if (!project.HasEventsBasedObject(objectType)) {
gd::LogWarning("Object: " + name + " has an unknown type: " + objectType);
}
return std::move(object);
}

View File

@@ -105,7 +105,7 @@ namespace gdjs {
if (this._isUntransformedHitBoxesDirty) {
this._updateUntransformedHitBoxes();
}
return this._minZ;
return this._z + this._minZ;
}
/**

View File

@@ -80,7 +80,7 @@ namespace gdjs {
threeObject3D.visible = !this._object.hidden;
this._isContainerDirty = true;
this._isContainerDirty = false;
}
/**

View File

@@ -1,4 +1,5 @@
// @flow
//@ts-check
/// <reference path="../JsExtensionTypes.d.ts" />
/**
* This is a declaration of an extension for GDevelop 5.
*
@@ -12,18 +13,9 @@
* More information on https://github.com/4ian/GDevelop/blob/master/newIDE/README-extensions.md
*/
/*::
// Import types to allow Flow to do static type checking on this file.
// Extensions declaration are typed using Flow (like the editor), but the files
// for the game engine are checked with TypeScript annotations.
import { type ObjectsRenderingService, type ObjectsEditorService } from '../JsExtensionTypes.flow.js'
*/
/** @type {ExtensionModule} */
module.exports = {
createExtension: function (
_ /*: (string) => string */,
gd /*: libGDevelop */
) {
createExtension: function (_, gd) {
const extension = new gd.PlatformExtension();
extension
.setExtensionInformation(
@@ -811,7 +803,6 @@ module.exports = {
}
const Cube3DObject = new gd.ObjectJsImplementation();
// $FlowExpectedError - ignore Flow warning as we're creating an object
Cube3DObject.updateProperty = function (
objectContent,
propertyName,
@@ -860,7 +851,6 @@ module.exports = {
return false;
};
// $FlowExpectedError - ignore Flow warning as we're creating an object
Cube3DObject.getProperties = function (objectContent) {
const objectProperties = new gd.MapStringPropertyDescriptor();
@@ -1100,7 +1090,6 @@ module.exports = {
})
);
// $FlowExpectedError
Cube3DObject.updateInitialInstanceProperty = function (
objectContent,
instance,
@@ -1112,7 +1101,6 @@ module.exports = {
return false;
};
// $FlowExpectedError
Cube3DObject.getInitialInstanceProperties = function (
content,
instance,
@@ -1665,7 +1653,7 @@ module.exports = {
'Change the camera rotation to look at an object. The camera top always face the screen.'
),
_('Change the camera rotation of _PARAM2_ to look at _PARAM1_'),
_("Layers and cameras"),
_('Layers and cameras'),
'res/conditions/3d_box.svg',
'res/conditions/3d_box.svg'
)
@@ -1943,11 +1931,7 @@ module.exports = {
const effect = extension
.addEffect('HueAndSaturation')
.setFullName(_('Hue and saturation'))
.setDescription(
_(
'Adjust hue and saturation.'
)
)
.setDescription(_('Adjust hue and saturation.'))
.markAsNotWorkingForObjects()
.markAsOnlyWorkingFor3D()
.addIncludeFile('Extensions/3D/HueAndSaturationEffect.js');
@@ -1967,11 +1951,7 @@ module.exports = {
const effect = extension
.addEffect('Exposure')
.setFullName(_('Exposure'))
.setDescription(
_(
'Adjust exposure.'
)
)
.setDescription(_('Adjust exposure.'))
.markAsNotWorkingForObjects()
.markAsOnlyWorkingFor3D()
.addIncludeFile('Extensions/3D/ExposureEffect.js');
@@ -1986,11 +1966,7 @@ module.exports = {
const effect = extension
.addEffect('Bloom')
.setFullName(_('Bloom'))
.setDescription(
_(
'Apply a bloom effect.'
)
)
.setDescription(_('Apply a bloom effect.'))
.markAsNotWorkingForObjects()
.markAsOnlyWorkingFor3D()
.addIncludeFile('Extensions/3D/BloomEffect.js');
@@ -2014,12 +1990,8 @@ module.exports = {
{
const effect = extension
.addEffect('BrightnessAndContrast')
.setFullName(_('Brightness and contrast'))
.setDescription(
_(
'Adjust brightness and contrast.'
)
)
.setFullName(_('Brightness and contrast.'))
.setDescription(_('Adjust brightness and contrast.'))
.markAsNotWorkingForObjects()
.markAsOnlyWorkingFor3D()
.addIncludeFile('Extensions/3D/BrightnessAndContrastEffect.js');
@@ -2050,10 +2022,7 @@ module.exports = {
* But it is recommended to create tests for the behaviors/objects properties you created
* to avoid mistakes.
*/
runExtensionSanityTests: function (
gd /*: libGDevelop */,
extension /*: gdPlatformExtension*/
) {
runExtensionSanityTests: function (gd, extension) {
return [];
},
/**
@@ -2061,17 +2030,13 @@ module.exports = {
*
* Run `node import-GDJS-Runtime.js` (in newIDE/app/scripts) if you make any change.
*/
registerEditorConfigurations: function (
objectsEditorService /*: ObjectsEditorService */
) {},
registerEditorConfigurations: function (objectsEditorService) {},
/**
* Register renderers for instance of objects on the scene editor.
*
* Run `node import-GDJS-Runtime.js` (in newIDE/app/scripts) if you make any change.
*/
registerInstanceRenderers: function (
objectsRenderingService /*: ObjectsRenderingService */
) {
registerInstanceRenderers: function (objectsRenderingService) {
const RenderedInstance = objectsRenderingService.RenderedInstance;
const Rendered3DInstance = objectsRenderingService.Rendered3DInstance;
const PIXI = objectsRenderingService.PIXI;
@@ -2079,39 +2044,25 @@ module.exports = {
const THREE_ADDONS = objectsRenderingService.THREE_ADDONS;
const materialIndexToFaceIndex = {
// $FlowFixMe
0: 3,
// $FlowFixMe
1: 2,
// $FlowFixMe
2: 5,
// $FlowFixMe
3: 4,
// $FlowFixMe
4: 0,
// $FlowFixMe
5: 1,
};
const noRepeatTextureVertexIndexToUvMapping = {
// $FlowFixMe
0: [0, 0],
// $FlowFixMe
1: [1, 0],
// $FlowFixMe
2: [0, 1],
// $FlowFixMe
3: [1, 1],
};
const noRepeatTextureVertexIndexToUvMappingForLeftAndRightFacesTowardsZ = {
// $FlowFixMe
0: [0, 1],
// $FlowFixMe
1: [0, 0],
// $FlowFixMe
2: [1, 1],
// $FlowFixMe
3: [1, 0],
};
@@ -2157,6 +2108,11 @@ module.exports = {
};
class RenderedCube3DObject2DInstance extends RenderedInstance {
/** @type {number} */
_centerX = 0;
/** @type {number} */
_centerY = 0;
constructor(
project,
layout,
@@ -2173,10 +2129,9 @@ module.exports = {
pixiContainer,
pixiResourcesLoader
);
/**
* Name of the resource that is rendered.
* If no face is visible, this will be null.
*/
// Name of the resource that is rendered.
// If no face is visible, this will be null.
this._renderedResourceName = undefined;
const properties = associatedObjectConfiguration.getProperties();
this._defaultWidth = parseFloat(properties.get('width').getValue());
@@ -2206,12 +2161,9 @@ module.exports = {
}
static getThumbnail(project, resourcesLoader, objectConfiguration) {
const instance = this._instance;
const textureResourceName =
RenderedCube3DObject2DInstance._getResourceNameToDisplay(
objectConfiguration
);
const textureResourceName = RenderedCube3DObject2DInstance._getResourceNameToDisplay(
objectConfiguration
);
if (textureResourceName) {
return resourcesLoader.getResourceFullUrl(
project,
@@ -2223,20 +2175,18 @@ module.exports = {
}
updateTextureIfNeeded() {
const textureName =
RenderedCube3DObject2DInstance._getResourceNameToDisplay(
this._associatedObjectConfiguration
);
const textureName = RenderedCube3DObject2DInstance._getResourceNameToDisplay(
this._associatedObjectConfiguration
);
if (textureName === this._renderedResourceName) return;
this.updateTexture();
}
updateTexture() {
const textureName =
RenderedCube3DObject2DInstance._getResourceNameToDisplay(
this._associatedObjectConfiguration
);
const textureName = RenderedCube3DObject2DInstance._getResourceNameToDisplay(
this._associatedObjectConfiguration
);
if (!textureName) {
this._renderFallbackObject = true;
@@ -2494,10 +2444,9 @@ module.exports = {
continue;
}
const shouldRepeatTexture =
this._shouldRepeatTextureOnFace[
materialIndexToFaceIndex[materialIndex]
];
const shouldRepeatTexture = this._shouldRepeatTextureOnFace[
materialIndexToFaceIndex[materialIndex]
];
const shouldOrientateFacesTowardsY = this._facesOrientation === 'Y';
@@ -2532,13 +2481,16 @@ module.exports = {
}
} else {
if (shouldOrientateFacesTowardsY) {
[x, y] =
noRepeatTextureVertexIndexToUvMapping[vertexIndex % 4];
[x, y] = noRepeatTextureVertexIndexToUvMapping[
vertexIndex % 4
];
} else {
[x, y] =
noRepeatTextureVertexIndexToUvMappingForLeftAndRightFacesTowardsZ[
vertexIndex % 4
];
[
x,
y,
] = noRepeatTextureVertexIndexToUvMappingForLeftAndRightFacesTowardsZ[
vertexIndex % 4
];
}
}
break;
@@ -2568,13 +2520,16 @@ module.exports = {
}
} else {
if (shouldOrientateFacesTowardsY) {
[x, y] =
noRepeatTextureVertexIndexToUvMapping[vertexIndex % 4];
[x, y] = noRepeatTextureVertexIndexToUvMapping[
vertexIndex % 4
];
} else {
[x, y] =
noRepeatTextureVertexIndexToUvMappingForLeftAndRightFacesTowardsZ[
vertexIndex % 4
];
[
x,
y,
] = noRepeatTextureVertexIndexToUvMappingForLeftAndRightFacesTowardsZ[
vertexIndex % 4
];
x = -x;
y = -y;
}
@@ -3111,7 +3066,7 @@ module.exports = {
);
threeObject.updateMatrixWorld(true);
const boundingBox = new THREE.Box3().setFromObject(threeObject);
const shouldKeepModelOrigin = !this._originPoint;
if (shouldKeepModelOrigin) {
// Keep the origin as part of the model.

View File

@@ -1,4 +1,5 @@
// @flow
//@ts-check
/// <reference path="../JsExtensionTypes.d.ts" />
/**
* This is a declaration of an extension for GDevelop 5.
*
@@ -12,18 +13,9 @@
* More information on https://github.com/4ian/GDevelop/blob/master/newIDE/README-extensions.md
*/
/*::
// Import types to allow Flow to do static type checking on this file.
// Extensions declaration are typed using Flow (like the editor), but the files
// for the game engine are checked with TypeScript annotations.
import { type ObjectsRenderingService, type ObjectsEditorService } from '../JsExtensionTypes.flow.js'
*/
/** @type {ExtensionModule} */
module.exports = {
createExtension: function (
_ /*: (string) => string */,
gd /*: libGDevelop */
) {
createExtension: function (_, gd) {
const extension = new gd.PlatformExtension();
extension
.setExtensionInformation(
@@ -789,10 +781,7 @@ module.exports = {
return extension;
},
runExtensionSanityTests: function (
gd /*: libGDevelop */,
extension /*: gdPlatformExtension*/
) {
runExtensionSanityTests: function (gd, extension) {
return [];
},
};

View File

@@ -1,4 +1,5 @@
// @flow
//@ts-check
/// <reference path="../JsExtensionTypes.d.ts" />
/**
* This is a declaration of an extension for GDevelop 5.
*
@@ -12,11 +13,9 @@
* More information on https://github.com/4ian/GDevelop/blob/master/newIDE/README-extensions.md
*/
/** @type {ExtensionModule} */
module.exports = {
createExtension: function (
_ /*: (string) => string */,
gd /*: libGDevelop */
) {
createExtension: function (_, gd) {
const extension = new gd.PlatformExtension();
extension
.setExtensionInformation(
@@ -710,10 +709,7 @@ module.exports = {
return extension;
},
runExtensionSanityTests: function (
gd /*: libGDevelop */,
extension /*: gdPlatformExtension*/
) {
runExtensionSanityTests: function (gd, extension) {
return [];
},
};

View File

@@ -1,4 +1,5 @@
// @flow
//@ts-check
/// <reference path="../JsExtensionTypes.d.ts" />
/**
* This is a declaration of an extension for GDevelop 5.
*
@@ -12,20 +13,11 @@
* More information on https://github.com/4ian/GDevelop/blob/master/newIDE/README-extensions.md
*/
/*::
// Import types to allow Flow to do static type checking on this file.
// Extensions declaration are typed using Flow (like the editor), but the files
// for the game engine are checked with TypeScript annotations.
import { type ObjectsRenderingService, type ObjectsEditorService } from '../JsExtensionTypes.flow.js'
*/
const stringifyOptions = (options) => '["' + options.join('","') + '"]';
/** @type {ExtensionModule} */
module.exports = {
createExtension: function (
_ /*: (string) => string */,
gd /*: libGDevelop */
) {
createExtension: function (_, gd) {
const extension = new gd.PlatformExtension();
extension
.setExtensionInformation(
@@ -42,7 +34,6 @@ module.exports = {
.setIcon('JsPlatform/Extensions/bbcode32.png');
var objectBBText = new gd.ObjectJsImplementation();
// $FlowExpectedError
objectBBText.updateProperty = function (
objectContent,
propertyName,
@@ -59,7 +50,6 @@ module.exports = {
return false;
};
// $FlowExpectedError
objectBBText.getProperties = function (objectContent) {
const objectProperties = new gd.MapStringPropertyDescriptor();
@@ -126,7 +116,8 @@ module.exports = {
};
objectBBText.setRawJSONContent(
JSON.stringify({
text: '[b]bold[/b] [i]italic[/i] [size=15]smaller[/size] [font=times]times[/font] font\n[spacing=12]spaced out[/spacing]\n[outline=yellow]outlined[/outline] [shadow=red]DropShadow[/shadow] ',
text:
'[b]bold[/b] [i]italic[/i] [size=15]smaller[/size] [font=times]times[/font] font\n[spacing=12]spaced out[/spacing]\n[outline=yellow]outlined[/outline] [shadow=red]DropShadow[/shadow] ',
opacity: 255,
fontSize: 20,
visible: true,
@@ -137,7 +128,6 @@ module.exports = {
})
);
// $FlowExpectedError
objectBBText.updateInitialInstanceProperty = function (
objectContent,
instance,
@@ -148,7 +138,6 @@ module.exports = {
) {
return false;
};
// $FlowExpectedError
objectBBText.getInitialInstanceProperties = function (
content,
instance,
@@ -223,10 +212,9 @@ module.exports = {
parameterType === 'string' ||
parameterType === 'stringWithSelector'
) {
const parameterOptions =
gd.ParameterOptions.makeNewOptions().setDescription(
property.paramLabel
);
const parameterOptions = gd.ParameterOptions.makeNewOptions().setDescription(
property.paramLabel
);
if (property.options) {
parameterOptions.setTypeExtraInfo(
stringifyOptions(property.options)
@@ -276,10 +264,9 @@ module.exports = {
parameterType === 'number' ||
parameterType === 'stringWithSelector'
) {
const parameterOptions =
gd.ParameterOptions.makeNewOptions().setDescription(
property.paramLabel
);
const parameterOptions = gd.ParameterOptions.makeNewOptions().setDescription(
property.paramLabel
);
if (property.options) {
parameterOptions.setTypeExtraInfo(
stringifyOptions(property.options)
@@ -475,10 +462,7 @@ module.exports = {
* But it is recommended to create tests for the behaviors/objects properties you created
* to avoid mistakes.
*/
runExtensionSanityTests: function (
gd /*: libGDevelop */,
extension /*: gdPlatformExtension*/
) {
runExtensionSanityTests: function (gd, extension) {
return [];
},
/**
@@ -486,9 +470,7 @@ module.exports = {
*
* Run `node import-GDJS-Runtime.js` (in newIDE/app/scripts) if you make any change.
*/
registerEditorConfigurations: function (
objectsEditorService /*: ObjectsEditorService */
) {
registerEditorConfigurations: function (objectsEditorService) {
objectsEditorService.registerEditorConfiguration(
'BBText::BBText',
objectsEditorService.getDefaultObjectJsImplementationPropertiesEditor({
@@ -501,11 +483,8 @@ module.exports = {
*
* Run `node import-GDJS-Runtime.js` (in newIDE/app/scripts) if you make any change.
*/
registerInstanceRenderers: function (
objectsRenderingService /*: ObjectsRenderingService */
) {
registerInstanceRenderers: function (objectsRenderingService) {
const RenderedInstance = objectsRenderingService.RenderedInstance;
const PIXI = objectsRenderingService.PIXI;
const MultiStyleText = objectsRenderingService.requireModule(
__dirname,
'pixi-multistyle-text/dist/pixi-multistyle-text.umd'
@@ -514,150 +493,145 @@ module.exports = {
/**
* Renderer for instances of BBText inside the IDE.
*
* @extends RenderedBBTextInstance
* @extends RenderedInstance
* @class RenderedBBTextInstance
* @constructor
*/
function RenderedBBTextInstance(
project,
layout,
instance,
associatedObjectConfiguration,
pixiContainer,
pixiResourcesLoader
) {
RenderedInstance.call(
this,
class RenderedBBTextInstance extends RenderedInstance {
constructor(
project,
layout,
instance,
associatedObjectConfiguration,
pixiContainer,
pixiResourcesLoader
);
) {
super(
project,
layout,
instance,
associatedObjectConfiguration,
pixiContainer,
pixiResourcesLoader
);
const bbTextStyles = {
default: {
// Use a default font family the time for the resource font to be loaded.
fontFamily: 'Arial',
fontSize: '24px',
fill: '#cccccc',
tagStyle: 'bbcode',
wordWrap: true,
wordWrapWidth: 250, // This value is the default wrapping width of the runtime object.
align: 'left',
},
};
const bbTextStyles = {
default: {
// Use a default font family the time for the resource font to be loaded.
fontFamily: 'Arial',
fontSize: '24px',
fill: '#cccccc',
tagStyle: 'bbcode',
wordWrap: true,
wordWrapWidth: 250, // This value is the default wrapping width of the runtime object.
align: 'left',
},
};
this._pixiObject = new MultiStyleText('', bbTextStyles);
this._pixiObject = new MultiStyleText('', bbTextStyles);
this._pixiObject.anchor.x = 0.5;
this._pixiObject.anchor.y = 0.5;
this._pixiContainer.addChild(this._pixiObject);
this.update();
}
RenderedBBTextInstance.prototype = Object.create(
RenderedInstance.prototype
);
/**
* Return the path to the thumbnail of the specified object.
*/
RenderedBBTextInstance.getThumbnail = function (
project,
resourcesLoader,
objectConfiguration
) {
return 'JsPlatform/Extensions/bbcode24.png';
};
/**
* This is called to update the PIXI object on the scene editor
*/
RenderedBBTextInstance.prototype.update = function () {
const properties = this._associatedObjectConfiguration.getProperties();
const rawText = properties.get('text').getValue();
if (rawText !== this._pixiObject.text) {
this._pixiObject.text = rawText;
this._pixiObject.anchor.x = 0.5;
this._pixiObject.anchor.y = 0.5;
this._pixiContainer.addChild(this._pixiObject);
this.update();
}
const opacity = properties.get('opacity').getValue();
this._pixiObject.alpha = opacity / 255;
const color = properties.get('color').getValue();
this._pixiObject.textStyles.default.fill =
objectsRenderingService.rgbOrHexToHexNumber(color);
const fontSize = properties.get('fontSize').getValue();
this._pixiObject.textStyles.default.fontSize = `${fontSize}px`;
const fontResourceName = properties.get('fontFamily').getValue();
if (this._fontResourceName !== fontResourceName) {
this._fontResourceName = fontResourceName;
this._pixiResourcesLoader
.loadFontFamily(this._project, fontResourceName)
.then((fontFamily) => {
// Once the font is loaded, we can use the given fontFamily.
this._pixiObject.textStyles.default.fontFamily = fontFamily;
this._pixiObject.dirty = true;
})
.catch((err) => {
// Ignore errors
console.warn(
'Unable to load font family for RenderedBBTextInstance',
err
);
});
/**
* Return the path to the thumbnail of the specified object.
*/
static getThumbnail(project, resourcesLoader, objectConfiguration) {
return 'JsPlatform/Extensions/bbcode24.png';
}
const wordWrap = properties.get('wordWrap').getValue() === 'true';
if (wordWrap !== this._pixiObject._style.wordWrap) {
this._pixiObject._style.wordWrap = wordWrap;
this._pixiObject.dirty = true;
}
/**
* This is called to update the PIXI object on the scene editor
*/
update() {
const properties = this._associatedObjectConfiguration.getProperties();
const align = properties.get('align').getValue();
if (align !== this._pixiObject._style.align) {
this._pixiObject._style.align = align;
this._pixiObject.dirty = true;
}
const rawText = properties.get('text').getValue();
if (rawText !== this._pixiObject.text) {
this._pixiObject.text = rawText;
}
this._pixiObject.position.x =
this._instance.getX() + this._pixiObject.width / 2;
this._pixiObject.position.y =
this._instance.getY() + this._pixiObject.height / 2;
this._pixiObject.rotation = RenderedInstance.toRad(
this._instance.getAngle()
);
const opacity = +properties.get('opacity').getValue();
this._pixiObject.alpha = opacity / 255;
if (this._instance.hasCustomSize() && this._pixiObject) {
const customWidth = this.getCustomWidth();
if (
this._pixiObject &&
this._pixiObject._style.wordWrapWidth !== customWidth
) {
this._pixiObject._style.wordWrapWidth = customWidth;
const color = properties.get('color').getValue();
this._pixiObject.textStyles.default.fill = objectsRenderingService.rgbOrHexToHexNumber(
color
);
const fontSize = properties.get('fontSize').getValue();
this._pixiObject.textStyles.default.fontSize = `${fontSize}px`;
const fontResourceName = properties.get('fontFamily').getValue();
if (this._fontResourceName !== fontResourceName) {
this._fontResourceName = fontResourceName;
this._pixiResourcesLoader
.loadFontFamily(this._project, fontResourceName)
.then((fontFamily) => {
// Once the font is loaded, we can use the given fontFamily.
this._pixiObject.textStyles.default.fontFamily = fontFamily;
this._pixiObject.dirty = true;
})
.catch((err) => {
// Ignore errors
console.warn(
'Unable to load font family for RenderedBBTextInstance',
err
);
});
}
const wordWrap = properties.get('wordWrap').getValue() === 'true';
if (wordWrap !== this._pixiObject._style.wordWrap) {
this._pixiObject._style.wordWrap = wordWrap;
this._pixiObject.dirty = true;
}
const align = properties.get('align').getValue();
if (align !== this._pixiObject._style.align) {
this._pixiObject._style.align = align;
this._pixiObject.dirty = true;
}
this._pixiObject.position.x =
this._instance.getX() + this._pixiObject.width / 2;
this._pixiObject.position.y =
this._instance.getY() + this._pixiObject.height / 2;
this._pixiObject.rotation = RenderedInstance.toRad(
this._instance.getAngle()
);
if (this._instance.hasCustomSize() && this._pixiObject) {
const customWidth = this.getCustomWidth();
if (
this._pixiObject &&
this._pixiObject._style.wordWrapWidth !== customWidth
) {
this._pixiObject._style.wordWrapWidth = customWidth;
this._pixiObject.dirty = true;
}
}
}
};
/**
* Return the width of the instance, when it's not resized.
*/
RenderedBBTextInstance.prototype.getDefaultWidth = function () {
return this._pixiObject.width;
};
/**
* Return the width of the instance, when it's not resized.
*/
getDefaultWidth() {
return this._pixiObject.width;
}
/**
* Return the height of the instance, when it's not resized.
*/
RenderedBBTextInstance.prototype.getDefaultHeight = function () {
return this._pixiObject.height;
};
/**
* Return the height of the instance, when it's not resized.
*/
getDefaultHeight() {
return this._pixiObject.height;
}
}
objectsRenderingService.registerInstanceRenderer(
'BBText::BBText',

View File

@@ -1,4 +1,5 @@
// @flow
//@ts-check
/// <reference path="../JsExtensionTypes.d.ts" />
/**
* This is a declaration of an extension for GDevelop 5.
*
@@ -12,18 +13,9 @@
* More information on https://github.com/4ian/GDevelop/blob/master/newIDE/README-extensions.md
*/
/*::
// Import types to allow Flow to do static type checking on this file.
// Extensions declaration are typed using Flow (like the editor), but the files
// for the game engine are checked with TypeScript annotations.
import { type ObjectsRenderingService, type ObjectsEditorService } from '../JsExtensionTypes.flow.js'
*/
/** @type {ExtensionModule} */
module.exports = {
createExtension: function (
_ /*: (string) => string */,
gd /*: libGDevelop */
) {
createExtension: function (_, gd) {
const extension = new gd.PlatformExtension();
extension
.setExtensionInformation(
@@ -42,7 +34,6 @@ module.exports = {
.setIcon('JsPlatform/Extensions/bitmapfont32.png');
const bitmapTextObject = new gd.ObjectJsImplementation();
// $FlowExpectedError
bitmapTextObject.updateProperty = function (
objectContent,
propertyName,
@@ -59,7 +50,6 @@ module.exports = {
return false;
};
// $FlowExpectedError
bitmapTextObject.getProperties = function (objectContent) {
const objectProperties = new gd.MapStringPropertyDescriptor();
@@ -127,7 +117,8 @@ module.exports = {
};
bitmapTextObject.setRawJSONContent(
JSON.stringify({
text: 'This text use the default bitmap font.\nUse a custom Bitmap Font to create your own texts.',
text:
'This text use the default bitmap font.\nUse a custom Bitmap Font to create your own texts.',
opacity: 255,
scale: 1,
fontSize: 20,
@@ -139,7 +130,6 @@ module.exports = {
})
);
// $FlowExpectedError
bitmapTextObject.updateInitialInstanceProperty = function (
objectContent,
instance,
@@ -150,7 +140,6 @@ module.exports = {
) {
return false;
};
// $FlowExpectedError
bitmapTextObject.getInitialInstanceProperties = function (
content,
instance,
@@ -176,7 +165,7 @@ module.exports = {
'Extensions/BitmapText/bitmaptextruntimeobject-pixi-renderer.js'
)
.setCategoryFullName(_('Text'))
.addDefaultBehavior("TextContainerCapability::TextContainerBehavior")
.addDefaultBehavior('TextContainerCapability::TextContainerBehavior')
.addDefaultBehavior('EffectCapability::EffectBehavior')
.addDefaultBehavior('OpacityCapability::OpacityBehavior')
.addDefaultBehavior('ScalableCapability::ScalableBehavior');
@@ -327,33 +316,33 @@ module.exports = {
.getCodeExtraInformation()
.setFunctionName('setBitmapFontAndTextureAtlasResourceName');
object
.addAction(
'SetBitmapFontAndTextureAtlasResourceName2',
_('Bitmap files resources'),
_('Change the Bitmap Font and/or the atlas image used by the object.'),
_(
'Set the bitmap font of _PARAM0_ to _PARAM1_ and the atlas to _PARAM2_'
),
'',
'res/actions/font24.png',
'res/actions/font.png'
)
.addParameter('object', _('Bitmap text'), 'BitmapTextObject', false)
.addParameter(
'bitmapFontResource',
_('Bitmap font resource name'),
'',
false
)
.addParameter(
'imageResource',
_('Texture atlas resource name'),
'',
false
)
.getCodeExtraInformation()
.setFunctionName('setBitmapFontAndTextureAtlasResourceName');
object
.addAction(
'SetBitmapFontAndTextureAtlasResourceName2',
_('Bitmap files resources'),
_('Change the Bitmap Font and/or the atlas image used by the object.'),
_(
'Set the bitmap font of _PARAM0_ to _PARAM1_ and the atlas to _PARAM2_'
),
'',
'res/actions/font24.png',
'res/actions/font.png'
)
.addParameter('object', _('Bitmap text'), 'BitmapTextObject', false)
.addParameter(
'bitmapFontResource',
_('Bitmap font resource name'),
'',
false
)
.addParameter(
'imageResource',
_('Texture atlas resource name'),
'',
false
)
.getCodeExtraInformation()
.setFunctionName('setBitmapFontAndTextureAtlasResourceName');
object
.addExpressionAndCondition(
@@ -451,10 +440,7 @@ module.exports = {
* But it is recommended to create tests for the behaviors/objects properties you created
* to avoid mistakes.
*/
runExtensionSanityTests: function (
gd /*: libGDevelop */,
extension /*: gdPlatformExtension*/
) {
runExtensionSanityTests: function (gd, extension) {
return [];
},
/**
@@ -462,9 +448,7 @@ module.exports = {
*
* Run `node import-GDJS-Runtime.js` (in newIDE/app/scripts) if you make any change.
*/
registerEditorConfigurations: function (
objectsEditorService /*: ObjectsEditorService */
) {
registerEditorConfigurations: function (objectsEditorService) {
objectsEditorService.registerEditorConfiguration(
'BitmapText::BitmapTextObject',
objectsEditorService.getDefaultObjectJsImplementationPropertiesEditor({
@@ -477,9 +461,7 @@ module.exports = {
*
* Run `node import-GDJS-Runtime.js` (in newIDE/app/scripts) if you make any change.
*/
registerInstanceRenderers: function (
objectsRenderingService /*: ObjectsRenderingService */
) {
registerInstanceRenderers: function (objectsRenderingService) {
const RenderedInstance = objectsRenderingService.RenderedInstance;
const PIXI = objectsRenderingService.PIXI;
@@ -649,156 +631,144 @@ module.exports = {
};
/**
* Renderer for instances of BitmapText inside the IDE.
*
* @extends RenderedBitmapTextInstance
* @class RenderedBitmapTextInstance
* @constructor
* Return the path to the thumbnail of the specified object.
* This is called to update the PIXI object on the scene editor
*/
function RenderedBitmapTextInstance(
project,
layout,
instance,
associatedObjectConfiguration,
pixiContainer,
pixiResourcesLoader
) {
RenderedInstance.call(
this,
class RenderedBitmapTextInstance extends RenderedInstance {
static getThumbnail(project, resourcesLoader, objectConfiguration) {
return 'JsPlatform/Extensions/bitmapfont24.png';
}
constructor(
project,
layout,
instance,
associatedObjectConfiguration,
pixiContainer,
pixiResourcesLoader
);
// We'll track changes of the font to trigger the loading of the new font.
this._currentBitmapFontResourceName = '';
this._currentTextureAtlasResourceName = '';
this._pixiObject = new PIXI.BitmapText('', {
// Use a default font. The proper font will be loaded in `update` method.
fontName: getDefaultBitmapFont().font,
});
this._pixiObject.anchor.x = 0.5;
this._pixiObject.anchor.y = 0.5;
this._pixiContainer.addChild(this._pixiObject);
this.update();
}
RenderedBitmapTextInstance.prototype = Object.create(
RenderedInstance.prototype
);
/**
* Return the path to the thumbnail of the specified object.
*/
RenderedBitmapTextInstance.getThumbnail = function (
project,
resourcesLoader,
objectConfiguration
) {
return 'JsPlatform/Extensions/bitmapfont24.png';
};
// This is called to update the PIXI object on the scene editor
RenderedBitmapTextInstance.prototype.update = function () {
const properties = this._associatedObjectConfiguration.getProperties();
// Update the rendered text properties (note: Pixi is only
// applying changes if there were changed).
const rawText = properties.get('text').getValue();
this._pixiObject.text = rawText;
const opacity = properties.get('opacity').getValue();
this._pixiObject.alpha = opacity / 255;
const align = properties.get('align').getValue();
this._pixiObject.align = align;
const color = properties.get('tint').getValue();
this._pixiObject.tint =
objectsRenderingService.rgbOrHexToHexNumber(color);
const scale = properties.get('scale').getValue() || 1;
this._pixiObject.scale.set(scale);
// Track the changes in font to load the new requested font.
const bitmapFontResourceName = properties
.get('bitmapFontResourceName')
.getValue();
const textureAtlasResourceName = properties
.get('textureAtlasResourceName')
.getValue();
if (
this._currentBitmapFontResourceName !== bitmapFontResourceName ||
this._currentTextureAtlasResourceName !== textureAtlasResourceName
) {
// Release the old font (if it was installed).
releaseBitmapFont(this._pixiObject.fontName);
super(
project,
layout,
instance,
associatedObjectConfiguration,
pixiContainer,
pixiResourcesLoader
);
// Temporarily go back to the default font, as the PIXI.BitmapText
// object does not support being displayed with a font not installed at all.
// It will be replaced as soon as the proper font is loaded.
this._pixiObject.fontName = getDefaultBitmapFont().font;
// We'll track changes of the font to trigger the loading of the new font.
this._currentBitmapFontResourceName = '';
this._currentTextureAtlasResourceName = '';
this._currentBitmapFontResourceName = bitmapFontResourceName;
this._currentTextureAtlasResourceName = textureAtlasResourceName;
obtainBitmapFont(
this._pixiResourcesLoader,
this._project,
this._currentBitmapFontResourceName,
this._currentTextureAtlasResourceName
).then((bitmapFont) => {
this._pixiObject.fontName = bitmapFont.font;
this._pixiObject.fontSize = bitmapFont.size;
this._pixiObject.dirty = true;
this._pixiObject = new PIXI.BitmapText('', {
// Use a default font. The proper font will be loaded in `update` method.
fontName: getDefaultBitmapFont().font,
});
this._pixiObject.anchor.x = 0.5;
this._pixiObject.anchor.y = 0.5;
this._pixiContainer.addChild(this._pixiObject);
this.update();
}
// Set up the wrapping width if enabled.
const wordWrap = properties.get('wordWrap').getValue() === 'true';
if (wordWrap && this._instance.hasCustomSize()) {
this._pixiObject.maxWidth =
this.getCustomWidth() / this._pixiObject.scale.x;
this._pixiObject.dirty = true;
} else {
this._pixiObject.maxWidth = 0;
this._pixiObject.dirty = true;
update() {
const properties = this._associatedObjectConfiguration.getProperties();
// Update the rendered text properties (note: Pixi is only
// applying changes if there were changed).
const rawText = properties.get('text').getValue();
this._pixiObject.text = rawText;
const opacity = +properties.get('opacity').getValue();
this._pixiObject.alpha = opacity / 255;
const align = properties.get('align').getValue();
this._pixiObject.align = align;
const color = properties.get('tint').getValue();
this._pixiObject.tint = objectsRenderingService.rgbOrHexToHexNumber(
color
);
const scale = +(properties.get('scale').getValue() || 1);
this._pixiObject.scale.set(scale);
// Track the changes in font to load the new requested font.
const bitmapFontResourceName = properties
.get('bitmapFontResourceName')
.getValue();
const textureAtlasResourceName = properties
.get('textureAtlasResourceName')
.getValue();
if (
this._currentBitmapFontResourceName !== bitmapFontResourceName ||
this._currentTextureAtlasResourceName !== textureAtlasResourceName
) {
// Release the old font (if it was installed).
releaseBitmapFont(this._pixiObject.fontName);
// Temporarily go back to the default font, as the PIXI.BitmapText
// object does not support being displayed with a font not installed at all.
// It will be replaced as soon as the proper font is loaded.
this._pixiObject.fontName = getDefaultBitmapFont().font;
this._currentBitmapFontResourceName = bitmapFontResourceName;
this._currentTextureAtlasResourceName = textureAtlasResourceName;
obtainBitmapFont(
this._pixiResourcesLoader,
this._project,
this._currentBitmapFontResourceName,
this._currentTextureAtlasResourceName
).then((bitmapFont) => {
this._pixiObject.fontName = bitmapFont.font;
this._pixiObject.fontSize = bitmapFont.size;
this._pixiObject.dirty = true;
});
}
// Set up the wrapping width if enabled.
const wordWrap = properties.get('wordWrap').getValue() === 'true';
if (wordWrap && this._instance.hasCustomSize()) {
this._pixiObject.maxWidth =
this.getCustomWidth() / this._pixiObject.scale.x;
this._pixiObject.dirty = true;
} else {
this._pixiObject.maxWidth = 0;
this._pixiObject.dirty = true;
}
this._pixiObject.position.x =
this._instance.getX() + (this._pixiObject.textWidth * scale) / 2;
this._pixiObject.position.y =
this._instance.getY() + (this._pixiObject.textHeight * scale) / 2;
this._pixiObject.rotation = RenderedInstance.toRad(
this._instance.getAngle()
);
}
this._pixiObject.position.x =
this._instance.getX() + (this._pixiObject.textWidth * scale) / 2;
this._pixiObject.position.y =
this._instance.getY() + (this._pixiObject.textHeight * scale) / 2;
this._pixiObject.rotation = RenderedInstance.toRad(
this._instance.getAngle()
);
};
onRemovedFromScene() {
RenderedInstance.prototype.onRemovedFromScene.call(this);
RenderedBitmapTextInstance.prototype.onRemovedFromScene = function () {
RenderedInstance.prototype.onRemovedFromScene.call(this);
const fontName = this._pixiObject.fontName;
this._pixiObject.destroy();
releaseBitmapFont(fontName);
}
const fontName = this._pixiObject.fontName;
this._pixiObject.destroy();
releaseBitmapFont(fontName);
};
/**
* Return the width of the instance, when it's not resized.
*/
getDefaultWidth() {
return this._pixiObject.width;
}
/**
* Return the width of the instance, when it's not resized.
*/
RenderedBitmapTextInstance.prototype.getDefaultWidth = function () {
return this._pixiObject.width;
};
/**
* Return the height of the instance, when it's not resized.
*/
RenderedBitmapTextInstance.prototype.getDefaultHeight = function () {
return this._pixiObject.height;
};
/**
* Return the height of the instance, when it's not resized.
*/
getDefaultHeight() {
return this._pixiObject.height;
}
}
objectsRenderingService.registerInstanceRenderer(
'BitmapText::BitmapTextObject',

View File

@@ -1,4 +1,5 @@
// @flow
//@ts-check
/// <reference path="../JsExtensionTypes.d.ts" />
/**
* This is a declaration of an extension for GDevelop 5.
*
@@ -12,18 +13,9 @@
* More information on https://github.com/4ian/GDevelop/blob/master/newIDE/README-extensions.md
*/
/*::
// Import types to allow Flow to do static type checking on this file.
// Extensions declaration are typed using Flow (like the editor), but the files
// for the game engine are checked with TypeScript annotations.
import { type ObjectsRenderingService, type ObjectsEditorService } from '../JsExtensionTypes.flow.js'
*/
/** @type {ExtensionModule} */
module.exports = {
createExtension: function (
_ /*: (string) => string */,
gd /*: libGDevelop */
) {
createExtension: function (_, gd) {
const extension = new gd.PlatformExtension();
extension
.setExtensionInformation(
@@ -114,10 +106,7 @@ module.exports = {
return extension;
},
runExtensionSanityTests: function (
gd /*: libGDevelop */,
extension /*: gdPlatformExtension*/
) {
runExtensionSanityTests: function (gd, extension) {
return [];
},
};

View File

@@ -1,4 +1,5 @@
// @flow
//@ts-check
/// <reference path="../JsExtensionTypes.d.ts" />
/**
* This is a declaration of an extension for GDevelop 5.
*
@@ -12,450 +13,389 @@
* More information on https://github.com/4ian/GDevelop/blob/master/newIDE/README-extensions.md
*/
/*::
// Import types to allow Flow to do static type checking on this file.
// Extensions declaration are typed using Flow (like the editor), but the files
// for the game engine are checked with TypeScript annotations.
import { type ObjectsRenderingService, type ObjectsEditorService } from '../JsExtensionTypes.flow.js'
*/
/** @type {ExtensionModule} */
module.exports = {
createExtension: function(_/*: (string) => string */, gd/*: libGDevelop */) {
createExtension: function (_, gd) {
const extension = new gd.PlatformExtension();
extension.setExtensionInformation(
"DeviceSensors",
_("Device sensors"),
_(
"Allow the game to access the sensors of a mobile device."
),
"Matthias Meike",
"Open source (MIT License)"
).setExtensionHelpPath("/all-features/device-sensors")
.setCategory('Input');
extension.addInstructionOrExpressionGroupMetadata(_("Device sensors"))
.setIcon("JsPlatform/Extensions/orientation_active32.png");
extension
.setExtensionInformation(
'DeviceSensors',
_('Device sensors'),
_('Allow the game to access the sensors of a mobile device.'),
'Matthias Meike',
'Open source (MIT License)'
)
.setExtensionHelpPath('/all-features/device-sensors')
.setCategory('Input');
extension
.addInstructionOrExpressionGroupMetadata(_('Device sensors'))
.setIcon('JsPlatform/Extensions/orientation_active32.png');
extension
.addCondition(
"OrientationSensorActive",
_("Sensor active"),
'OrientationSensorActive',
_('Sensor active'),
_(
"The condition is true if the device orientation sensor is currently active"
'The condition is true if the device orientation sensor is currently active'
),
_("Orientation sensor is active"),
_("Orientation"),
"JsPlatform/Extensions/orientation_active32.png",
"JsPlatform/Extensions/orientation_active32.png"
_('Orientation sensor is active'),
_('Orientation'),
'JsPlatform/Extensions/orientation_active32.png',
'JsPlatform/Extensions/orientation_active32.png'
)
.getCodeExtraInformation()
.setIncludeFile(
"Extensions/DeviceSensors/devicesensortools.js"
)
.setFunctionName("gdjs.deviceSensors.orientation.isActive");
.setIncludeFile('Extensions/DeviceSensors/devicesensortools.js')
.setFunctionName('gdjs.deviceSensors.orientation.isActive');
extension
extension
.addCondition(
"OrientationAlpha",
_("Compare the value of orientation alpha"),
_(
"Compare the value of orientation alpha. (Range: 0 to 360°)"
),
_("the orientation alpha"),
_("Orientation"),
"JsPlatform/Extensions/orientation_alpha32.png",
"JsPlatform/Extensions/orientation_alpha32.png"
'OrientationAlpha',
_('Compare the value of orientation alpha'),
_('Compare the value of orientation alpha. (Range: 0 to 360°)'),
_('the orientation alpha'),
_('Orientation'),
'JsPlatform/Extensions/orientation_alpha32.png',
'JsPlatform/Extensions/orientation_alpha32.png'
)
.addParameter("relationalOperator", _("Sign of the test"), "number")
.addParameter("expression", _("Value"))
.addParameter('relationalOperator', _('Sign of the test'), 'number')
.addParameter('expression', _('Value'))
.getCodeExtraInformation()
.setIncludeFile(
"Extensions/DeviceSensors/devicesensortools.js"
)
.setFunctionName("gdjs.deviceSensors.orientation.getOrientationAlpha");
.setIncludeFile('Extensions/DeviceSensors/devicesensortools.js')
.setFunctionName('gdjs.deviceSensors.orientation.getOrientationAlpha');
extension
extension
.addCondition(
"OrientationBeta",
_("Compare the value of orientation beta"),
_(
"Compare the value of orientation beta. (Range: -180 to 180°)"
),
_("the orientation beta"),
_("Orientation"),
"JsPlatform/Extensions/orientation_beta32.png",
"JsPlatform/Extensions/orientation_beta32.png"
'OrientationBeta',
_('Compare the value of orientation beta'),
_('Compare the value of orientation beta. (Range: -180 to 180°)'),
_('the orientation beta'),
_('Orientation'),
'JsPlatform/Extensions/orientation_beta32.png',
'JsPlatform/Extensions/orientation_beta32.png'
)
.addParameter("relationalOperator", _("Sign of the test"), "number")
.addParameter("expression", _("Value"))
.addParameter('relationalOperator', _('Sign of the test'), 'number')
.addParameter('expression', _('Value'))
.getCodeExtraInformation()
.setIncludeFile(
"Extensions/DeviceSensors/devicesensortools.js"
)
.setFunctionName("gdjs.deviceSensors.orientation.getOrientationBeta");
.setIncludeFile('Extensions/DeviceSensors/devicesensortools.js')
.setFunctionName('gdjs.deviceSensors.orientation.getOrientationBeta');
extension
extension
.addCondition(
"OrientationGamma",
_("Compare the value of orientation gamma"),
_(
"Compare the value of orientation gamma. (Range: -90 to 90°)"
),
_("the orientation gamma"),
_("Orientation"),
"JsPlatform/Extensions/orientation_gamma32.png",
"JsPlatform/Extensions/orientation_gamma32.png"
'OrientationGamma',
_('Compare the value of orientation gamma'),
_('Compare the value of orientation gamma. (Range: -90 to 90°)'),
_('the orientation gamma'),
_('Orientation'),
'JsPlatform/Extensions/orientation_gamma32.png',
'JsPlatform/Extensions/orientation_gamma32.png'
)
.addParameter("relationalOperator", _("Sign of the test"), "number")
.addParameter("expression", _("Value"))
.addParameter('relationalOperator', _('Sign of the test'), 'number')
.addParameter('expression', _('Value'))
.getCodeExtraInformation()
.setIncludeFile(
"Extensions/DeviceSensors/devicesensortools.js"
)
.setFunctionName("gdjs.deviceSensors.orientation.getOrientationGamma");
.setIncludeFile('Extensions/DeviceSensors/devicesensortools.js')
.setFunctionName('gdjs.deviceSensors.orientation.getOrientationGamma');
extension
.addAction(
"ActivateOrientationListener",
_("Activate orientation sensor"),
_("Activate the orientation sensor. (remember to turn it off again)"),
_("Activate the orientation sensor."),
_("Orientation"),
"JsPlatform/Extensions/orientation_active32.png",
"JsPlatform/Extensions/orientation_active32.png"
'ActivateOrientationListener',
_('Activate orientation sensor'),
_('Activate the orientation sensor. (remember to turn it off again)'),
_('Activate the orientation sensor.'),
_('Orientation'),
'JsPlatform/Extensions/orientation_active32.png',
'JsPlatform/Extensions/orientation_active32.png'
)
.getCodeExtraInformation()
.setIncludeFile(
"Extensions/DeviceSensors/devicesensortools.js"
)
.setFunctionName("gdjs.deviceSensors.orientation.activateOrientationSensor");
.getCodeExtraInformation()
.setIncludeFile('Extensions/DeviceSensors/devicesensortools.js')
.setFunctionName(
'gdjs.deviceSensors.orientation.activateOrientationSensor'
);
extension
.addAction(
"DeactivateOrientationListener",
_("Deactivate orientation sensor"),
_("Deactivate the orientation sensor."),
_("Deactivate the orientation sensor."),
_("Orientation"),
"JsPlatform/Extensions/orientation_inactive32.png",
"JsPlatform/Extensions/orientation_inactive32.png"
'DeactivateOrientationListener',
_('Deactivate orientation sensor'),
_('Deactivate the orientation sensor.'),
_('Deactivate the orientation sensor.'),
_('Orientation'),
'JsPlatform/Extensions/orientation_inactive32.png',
'JsPlatform/Extensions/orientation_inactive32.png'
)
.getCodeExtraInformation()
.setIncludeFile(
"Extensions/DeviceSensors/devicesensortools.js"
)
.setFunctionName("gdjs.deviceSensors.orientation.deactivateOrientationSensor");
.getCodeExtraInformation()
.setIncludeFile('Extensions/DeviceSensors/devicesensortools.js')
.setFunctionName(
'gdjs.deviceSensors.orientation.deactivateOrientationSensor'
);
extension
.addExpression(
"OrientationAbsolute",
_("Is Absolute"),
_("Get if the devices orientation is absolute and not relative"),
_("Orientation"),
"JsPlatform/Extensions/orientation_absolute16.png"
'OrientationAbsolute',
_('Is Absolute'),
_('Get if the devices orientation is absolute and not relative'),
_('Orientation'),
'JsPlatform/Extensions/orientation_absolute16.png'
)
.getCodeExtraInformation()
.setIncludeFile(
"Extensions/DeviceSensors/devicesensortools.js"
)
.setFunctionName("gdjs.deviceSensors.orientation.getOrientationAbsolute");
.setIncludeFile('Extensions/DeviceSensors/devicesensortools.js')
.setFunctionName('gdjs.deviceSensors.orientation.getOrientationAbsolute');
extension
.addExpression(
"OrientationAlpha",
_("Alpha value"),
_("Get the devices orientation Alpha (compass)"),
_("Orientation"),
"JsPlatform/Extensions/orientation_alpha16.png"
'OrientationAlpha',
_('Alpha value'),
_('Get the devices orientation Alpha (compass)'),
_('Orientation'),
'JsPlatform/Extensions/orientation_alpha16.png'
)
.getCodeExtraInformation()
.setIncludeFile(
"Extensions/DeviceSensors/devicesensortools.js"
)
.setFunctionName("gdjs.deviceSensors.orientation.getOrientationAlpha");
.setIncludeFile('Extensions/DeviceSensors/devicesensortools.js')
.setFunctionName('gdjs.deviceSensors.orientation.getOrientationAlpha');
extension
.addExpression(
"OrientationBeta",
_("Beta value"),
_("Get the devices orientation Beta"),
_("Orientation"),
"JsPlatform/Extensions/orientation_beta16.png"
'OrientationBeta',
_('Beta value'),
_('Get the devices orientation Beta'),
_('Orientation'),
'JsPlatform/Extensions/orientation_beta16.png'
)
.getCodeExtraInformation()
.setIncludeFile(
"Extensions/DeviceSensors/devicesensortools.js"
)
.setFunctionName("gdjs.deviceSensors.orientation.getOrientationBeta");
.setIncludeFile('Extensions/DeviceSensors/devicesensortools.js')
.setFunctionName('gdjs.deviceSensors.orientation.getOrientationBeta');
extension
.addExpression(
"OrientationGamma",
_("Gamma value"),
_("Get the devices orientation Gamma value"),
_("Orientation"),
"JsPlatform/Extensions/orientation_gamma16.png"
'OrientationGamma',
_('Gamma value'),
_('Get the devices orientation Gamma value'),
_('Orientation'),
'JsPlatform/Extensions/orientation_gamma16.png'
)
.getCodeExtraInformation()
.setIncludeFile(
"Extensions/DeviceSensors/devicesensortools.js"
)
.setFunctionName("gdjs.deviceSensors.orientation.getOrientationGamma");
.setIncludeFile('Extensions/DeviceSensors/devicesensortools.js')
.setFunctionName('gdjs.deviceSensors.orientation.getOrientationGamma');
extension
extension
.addCondition(
"MotionSensorActive",
_("Sensor active"),
'MotionSensorActive',
_('Sensor active'),
_(
"The condition is true if the device motion sensor is currently active"
'The condition is true if the device motion sensor is currently active'
),
_("Motion sensor is active"),
_("Motion"),
"JsPlatform/Extensions/motion_active32.png",
"JsPlatform/Extensions/motion_active32.png"
_('Motion sensor is active'),
_('Motion'),
'JsPlatform/Extensions/motion_active32.png',
'JsPlatform/Extensions/motion_active32.png'
)
.getCodeExtraInformation()
.setIncludeFile(
"Extensions/DeviceSensors/devicesensortools.js"
)
.setFunctionName("gdjs.deviceSensors.motion.isActive");
.setIncludeFile('Extensions/DeviceSensors/devicesensortools.js')
.setFunctionName('gdjs.deviceSensors.motion.isActive');
extension
extension
.addCondition(
"RotationAlpha",
_("Compare the value of rotation alpha"),
'RotationAlpha',
_('Compare the value of rotation alpha'),
_(
"Compare the value of rotation alpha. (Note: few devices support this sensor)"
'Compare the value of rotation alpha. (Note: few devices support this sensor)'
),
_("the rotation alpha"),
_("Motion"),
"JsPlatform/Extensions/motion_rotation_alpha32.png",
"JsPlatform/Extensions/motion_rotation_alpha32.png"
_('the rotation alpha'),
_('Motion'),
'JsPlatform/Extensions/motion_rotation_alpha32.png',
'JsPlatform/Extensions/motion_rotation_alpha32.png'
)
.addParameter("relationalOperator", _("Sign of the test"), "number")
.addParameter("expression", _("Value (m/s²)"))
.addParameter('relationalOperator', _('Sign of the test'), 'number')
.addParameter('expression', _('Value (m/s²)'))
.getCodeExtraInformation()
.setIncludeFile(
"Extensions/DeviceSensors/devicesensortools.js"
)
.setFunctionName("gdjs.deviceSensors.motion.getRotationAlpha");
.setIncludeFile('Extensions/DeviceSensors/devicesensortools.js')
.setFunctionName('gdjs.deviceSensors.motion.getRotationAlpha');
extension
extension
.addCondition(
"RotationBeta",
_("Compare the value of rotation beta"),
'RotationBeta',
_('Compare the value of rotation beta'),
_(
"Compare the value of rotation beta. (Note: few devices support this sensor)"
'Compare the value of rotation beta. (Note: few devices support this sensor)'
),
_("the rotation beta"),
_("Motion"),
"JsPlatform/Extensions/motion_rotation_beta32.png",
"JsPlatform/Extensions/motion_rotation_beta32.png"
_('the rotation beta'),
_('Motion'),
'JsPlatform/Extensions/motion_rotation_beta32.png',
'JsPlatform/Extensions/motion_rotation_beta32.png'
)
.addParameter("relationalOperator", _("Sign of the test"), "number")
.addParameter("expression", _("Value (m/s²)"))
.addParameter('relationalOperator', _('Sign of the test'), 'number')
.addParameter('expression', _('Value (m/s²)'))
.getCodeExtraInformation()
.setIncludeFile(
"Extensions/DeviceSensors/devicesensortools.js"
)
.setFunctionName("gdjs.deviceSensors.motion.getRotationBeta");
.setIncludeFile('Extensions/DeviceSensors/devicesensortools.js')
.setFunctionName('gdjs.deviceSensors.motion.getRotationBeta');
extension
extension
.addCondition(
"RotationGamma",
_("Compare the value of rotation gamma"),
'RotationGamma',
_('Compare the value of rotation gamma'),
_(
"Compare the value of rotation gamma. (Note: few devices support this sensor)"
'Compare the value of rotation gamma. (Note: few devices support this sensor)'
),
_("the rotation gamma"),
_("Motion"),
"JsPlatform/Extensions/motion_rotation_gamma32.png",
"JsPlatform/Extensions/motion_rotation_gamma32.png"
_('the rotation gamma'),
_('Motion'),
'JsPlatform/Extensions/motion_rotation_gamma32.png',
'JsPlatform/Extensions/motion_rotation_gamma32.png'
)
.addParameter("relationalOperator", _("Sign of the test"), "number")
.addParameter("expression", _("Value (m/s²)"))
.addParameter('relationalOperator', _('Sign of the test'), 'number')
.addParameter('expression', _('Value (m/s²)'))
.getCodeExtraInformation()
.setIncludeFile(
"Extensions/DeviceSensors/devicesensortools.js"
)
.setFunctionName("gdjs.deviceSensors.motion.getRotationGamma");
.setIncludeFile('Extensions/DeviceSensors/devicesensortools.js')
.setFunctionName('gdjs.deviceSensors.motion.getRotationGamma');
extension
extension
.addCondition(
"AccelerationX",
_("Compare the value of acceleration on X-axis"),
_(
"Compare the value of acceleration on the X-axis (m/s²)."
),
_("the acceleration X"),
_("Motion"),
"JsPlatform/Extensions/motion_acceleration_x32.png",
"JsPlatform/Extensions/motion_acceleration_x32.png"
'AccelerationX',
_('Compare the value of acceleration on X-axis'),
_('Compare the value of acceleration on the X-axis (m/s²).'),
_('the acceleration X'),
_('Motion'),
'JsPlatform/Extensions/motion_acceleration_x32.png',
'JsPlatform/Extensions/motion_acceleration_x32.png'
)
.addParameter("relationalOperator", _("Sign of the test"), "number")
.addParameter("expression", _("Value (m/s²)"))
.addParameter('relationalOperator', _('Sign of the test'), 'number')
.addParameter('expression', _('Value (m/s²)'))
.getCodeExtraInformation()
.setIncludeFile(
"Extensions/DeviceSensors/devicesensortools.js"
)
.setFunctionName("gdjs.deviceSensors.motion.getAccelerationX");
.setIncludeFile('Extensions/DeviceSensors/devicesensortools.js')
.setFunctionName('gdjs.deviceSensors.motion.getAccelerationX');
extension
extension
.addCondition(
"AccelerationY",
_("Compare the value of acceleration on Y-axis"),
_(
"Compare the value of acceleration on the Y-axis (m/s²)."
),
_("the acceleration Y"),
_("Motion"),
"JsPlatform/Extensions/motion_acceleration_y32.png",
"JsPlatform/Extensions/motion_acceleration_y32.png"
'AccelerationY',
_('Compare the value of acceleration on Y-axis'),
_('Compare the value of acceleration on the Y-axis (m/s²).'),
_('the acceleration Y'),
_('Motion'),
'JsPlatform/Extensions/motion_acceleration_y32.png',
'JsPlatform/Extensions/motion_acceleration_y32.png'
)
.addParameter("relationalOperator", _("Sign of the test"), "number")
.addParameter("expression", _("Value (m/s²)"))
.addParameter('relationalOperator', _('Sign of the test'), 'number')
.addParameter('expression', _('Value (m/s²)'))
.getCodeExtraInformation()
.setIncludeFile(
"Extensions/DeviceSensors/devicesensortools.js"
)
.setFunctionName("gdjs.deviceSensors.motion.getAccelerationY");
.setIncludeFile('Extensions/DeviceSensors/devicesensortools.js')
.setFunctionName('gdjs.deviceSensors.motion.getAccelerationY');
extension
extension
.addCondition(
"AccelerationZ",
_("Compare the value of acceleration on Z-axis"),
_(
"Compare the value of acceleration on the Z-axis (m/s²)."
),
_("the acceleration Z"),
_("Motion"),
"JsPlatform/Extensions/motion_acceleration_z32.png",
"JsPlatform/Extensions/motion_acceleration_z32.png"
'AccelerationZ',
_('Compare the value of acceleration on Z-axis'),
_('Compare the value of acceleration on the Z-axis (m/s²).'),
_('the acceleration Z'),
_('Motion'),
'JsPlatform/Extensions/motion_acceleration_z32.png',
'JsPlatform/Extensions/motion_acceleration_z32.png'
)
.addParameter("relationalOperator", _("Sign of the test"), "number")
.addParameter("expression", _("Value (m/s²)"))
.addParameter('relationalOperator', _('Sign of the test'), 'number')
.addParameter('expression', _('Value (m/s²)'))
.getCodeExtraInformation()
.setIncludeFile(
"Extensions/DeviceSensors/devicesensortools.js"
)
.setFunctionName("gdjs.deviceSensors.motion.getAccelerationZ");
.setIncludeFile('Extensions/DeviceSensors/devicesensortools.js')
.setFunctionName('gdjs.deviceSensors.motion.getAccelerationZ');
extension
.addAction(
"ActivateMotionListener",
_("Activate motion sensor"),
_("Activate the motion sensor. (remember to turn it off again)"),
_("Activate the motion sensor."),
_("Motion"),
"JsPlatform/Extensions/motion_active32.png",
"JsPlatform/Extensions/motion_active32.png"
'ActivateMotionListener',
_('Activate motion sensor'),
_('Activate the motion sensor. (remember to turn it off again)'),
_('Activate the motion sensor.'),
_('Motion'),
'JsPlatform/Extensions/motion_active32.png',
'JsPlatform/Extensions/motion_active32.png'
)
.getCodeExtraInformation()
.setIncludeFile(
"Extensions/DeviceSensors/devicesensortools.js"
)
.setFunctionName("gdjs.deviceSensors.motion.activateMotionSensor");
.getCodeExtraInformation()
.setIncludeFile('Extensions/DeviceSensors/devicesensortools.js')
.setFunctionName('gdjs.deviceSensors.motion.activateMotionSensor');
extension
.addAction(
"DeactivateMotionListener",
_("Deactivate motion sensor"),
_("Deactivate the motion sensor."),
_("Deactivate the motion sensor."),
_("Motion"),
"JsPlatform/Extensions/motion_inactive32.png",
"JsPlatform/Extensions/motion_inactive32.png"
'DeactivateMotionListener',
_('Deactivate motion sensor'),
_('Deactivate the motion sensor.'),
_('Deactivate the motion sensor.'),
_('Motion'),
'JsPlatform/Extensions/motion_inactive32.png',
'JsPlatform/Extensions/motion_inactive32.png'
)
.getCodeExtraInformation()
.setIncludeFile(
"Extensions/DeviceSensors/devicesensortools.js"
)
.setFunctionName("gdjs.deviceSensors.motion.deactivateMotionSensor");
.getCodeExtraInformation()
.setIncludeFile('Extensions/DeviceSensors/devicesensortools.js')
.setFunctionName('gdjs.deviceSensors.motion.deactivateMotionSensor');
extension
.addExpression(
"RotationAlpha",
_("Alpha value"),
_("Get the devices rotation Alpha"),
_("Motion"),
"JsPlatform/Extensions/motion_rotation_alpha16.png"
'RotationAlpha',
_('Alpha value'),
_('Get the devices rotation Alpha'),
_('Motion'),
'JsPlatform/Extensions/motion_rotation_alpha16.png'
)
.getCodeExtraInformation()
.setIncludeFile(
"Extensions/DeviceSensors/devicesensortools.js"
)
.setFunctionName("gdjs.deviceSensors.motion.getRotationAlpha");
.setIncludeFile('Extensions/DeviceSensors/devicesensortools.js')
.setFunctionName('gdjs.deviceSensors.motion.getRotationAlpha');
extension
.addExpression(
"RotationBeta",
_("Beta value"),
_("Get the devices rotation Beta"),
_("Motion"),
"JsPlatform/Extensions/motion_rotation_beta16.png"
'RotationBeta',
_('Beta value'),
_('Get the devices rotation Beta'),
_('Motion'),
'JsPlatform/Extensions/motion_rotation_beta16.png'
)
.getCodeExtraInformation()
.setIncludeFile(
"Extensions/DeviceSensors/devicesensortools.js"
)
.setFunctionName("gdjs.deviceSensors.motion.getRotationBeta");
.setIncludeFile('Extensions/DeviceSensors/devicesensortools.js')
.setFunctionName('gdjs.deviceSensors.motion.getRotationBeta');
extension
.addExpression(
"RotationGamma",
_("Gamma value"),
_("Get the devices rotation Gamma"),
_("Motion"),
"JsPlatform/Extensions/motion_rotation_gamma16.png"
'RotationGamma',
_('Gamma value'),
_('Get the devices rotation Gamma'),
_('Motion'),
'JsPlatform/Extensions/motion_rotation_gamma16.png'
)
.getCodeExtraInformation()
.setIncludeFile(
"Extensions/DeviceSensors/devicesensortools.js"
)
.setFunctionName("gdjs.deviceSensors.motion.getRotationGamma");
.setIncludeFile('Extensions/DeviceSensors/devicesensortools.js')
.setFunctionName('gdjs.deviceSensors.motion.getRotationGamma');
extension
extension
.addExpression(
"AccelerationX",
_("Acceleration X value"),
_("Get the devices acceleration on the X-axis (m/s²)"),
_("Motion"),
"JsPlatform/Extensions/motion_acceleration_x16.png"
'AccelerationX',
_('Acceleration X value'),
_('Get the devices acceleration on the X-axis (m/s²)'),
_('Motion'),
'JsPlatform/Extensions/motion_acceleration_x16.png'
)
.getCodeExtraInformation()
.setIncludeFile(
"Extensions/DeviceSensors/devicesensortools.js"
)
.setFunctionName("gdjs.deviceSensors.motion.getAccelerationX");
.setIncludeFile('Extensions/DeviceSensors/devicesensortools.js')
.setFunctionName('gdjs.deviceSensors.motion.getAccelerationX');
extension
extension
.addExpression(
"AccelerationY",
_("Acceleration Y value"),
_("Get the devices acceleration on the Y-axis (m/s²)"),
_("Motion"),
"JsPlatform/Extensions/motion_acceleration_y16.png"
'AccelerationY',
_('Acceleration Y value'),
_('Get the devices acceleration on the Y-axis (m/s²)'),
_('Motion'),
'JsPlatform/Extensions/motion_acceleration_y16.png'
)
.getCodeExtraInformation()
.setIncludeFile(
"Extensions/DeviceSensors/devicesensortools.js"
)
.setFunctionName("gdjs.deviceSensors.motion.getAccelerationY");
.setIncludeFile('Extensions/DeviceSensors/devicesensortools.js')
.setFunctionName('gdjs.deviceSensors.motion.getAccelerationY');
extension
extension
.addExpression(
"AccelerationZ",
_("Acceleration Z value"),
_("Get the devices acceleration on the Z-axis (m/s²)"),
_("Motion"),
"JsPlatform/Extensions/motion_acceleration_z16.png"
'AccelerationZ',
_('Acceleration Z value'),
_('Get the devices acceleration on the Z-axis (m/s²)'),
_('Motion'),
'JsPlatform/Extensions/motion_acceleration_z16.png'
)
.getCodeExtraInformation()
.setIncludeFile(
"Extensions/DeviceSensors/devicesensortools.js"
)
.setFunctionName("gdjs.deviceSensors.motion.getAccelerationZ");
.setIncludeFile('Extensions/DeviceSensors/devicesensortools.js')
.setFunctionName('gdjs.deviceSensors.motion.getAccelerationZ');
return extension;
},
runExtensionSanityTests: function(gd /*: libGDevelop */, extension /*: gdPlatformExtension*/) { return []; },
runExtensionSanityTests: function (gd, extension) {
return [];
},
};

View File

@@ -1,4 +1,5 @@
// @flow
//@ts-check
/// <reference path="../JsExtensionTypes.d.ts" />
/**
* This is a declaration of an extension for GDevelop 5.
*
@@ -12,18 +13,9 @@
* More information on https://github.com/4ian/GDevelop/blob/master/newIDE/README-extensions.md
*/
/*::
// Import types to allow Flow to do static type checking on this file.
// Extensions declaration are typed using Flow (like the editor), but the files
// for the game engine are checked with TypeScript annotations.
import { type ObjectsRenderingService, type ObjectsEditorService } from '../JsExtensionTypes.flow.js'
*/
/** @type {ExtensionModule} */
module.exports = {
createExtension: function (
_ /*: (string) => string */,
gd /*: libGDevelop */
) {
createExtension: function (_, gd) {
const extension = new gd.PlatformExtension();
extension
.setExtensionInformation(
@@ -36,8 +28,9 @@ module.exports = {
)
.setExtensionHelpPath('/all-features/device-vibration')
.setCategory('User interface');
extension.addInstructionOrExpressionGroupMetadata(_("Device vibration"))
.setIcon("JsPlatform/Extensions/vibration_start32.png");
extension
.addInstructionOrExpressionGroupMetadata(_('Device vibration'))
.setIcon('JsPlatform/Extensions/vibration_start32.png');
extension
.addDependency()
@@ -99,10 +92,7 @@ module.exports = {
return extension;
},
runExtensionSanityTests: function (
gd /*: libGDevelop */,
extension /*: gdPlatformExtension*/
) {
runExtensionSanityTests: function (gd, extension) {
return [];
},
};

View File

@@ -1,4 +1,5 @@
// @flow
//@ts-check
/// <reference path="../JsExtensionTypes.d.ts" />
/**
* This is a declaration of an extension for GDevelop 5.
*
@@ -12,18 +13,9 @@
* More information on https://github.com/4ian/GDevelop/blob/master/newIDE/README-extensions.md
*/
/*::
// Import types to allow Flow to do static type checking on this file.
// Extensions declaration are typed using Flow (like the editor), but the files
// for the game engine are checked with TypeScript annotations.
import { type ObjectsRenderingService, type ObjectsEditorService } from '../JsExtensionTypes.flow.js'
*/
/** @type {ExtensionModule} */
module.exports = {
createExtension: function (
_ /*: (string) => string */,
gd /*: libGDevelop */
) {
createExtension: function (_, gd) {
const extension = new gd.PlatformExtension();
extension
.setExtensionInformation(
@@ -721,10 +713,7 @@ module.exports = {
return extension;
},
runExtensionSanityTests: function (
gd /*: libGDevelop */,
extension /*: gdPlatformExtension*/
) {
runExtensionSanityTests: function (gd, extension) {
return [];
},
};

View File

@@ -1,4 +1,5 @@
// @flow
//@ts-check
/// <reference path="../JsExtensionTypes.d.ts" />
/**
* This is a declaration of an extension for GDevelop 5.
*
@@ -12,28 +13,20 @@
* More information on https://github.com/4ian/GDevelop/blob/master/newIDE/README-extensions.md
*/
/*::
// Import types to allow Flow to do static type checking on this file.
// Extensions declaration are typed using Flow (like the editor), but the files
// for the game engine are checked with TypeScript annotations.
import { type ObjectsRenderingService, type ObjectsEditorService } from '../JsExtensionTypes.flow.js'
*/
/** @type {ExtensionModule} */
module.exports = {
createExtension: function (
_ /*: (string) => string */,
gd /*: libGDevelop */
) {
createExtension: function (_, gd) {
const extension = new gd.PlatformExtension();
extension.setExtensionInformation(
'Effects',
'Effects',
'Lots of different effects to be used in your game.',
'Various contributors from PixiJS, PixiJS filters and GDevelop',
'MIT'
)
.setCategory('Visual effect')
.setExtensionHelpPath('/interface/scene-editor/layer-effects');
extension
.setExtensionInformation(
'Effects',
'Effects',
'Lots of different effects to be used in your game.',
'Various contributors from PixiJS, PixiJS filters and GDevelop',
'MIT'
)
.setCategory('Visual effect')
.setExtensionHelpPath('/interface/scene-editor/layer-effects');
// You can declare an effect here. Please order the effects by alphabetical order.
// This file is for common effects that are well-known/"battle-tested". If you have an
@@ -230,7 +223,11 @@ module.exports = {
const blurEffect = extension
.addEffect('Blur')
.setFullName(_('Blur (Gaussian, slow - prefer to use Kawase blur)'))
.setDescription(_('Blur the rendered image. This is slow, so prefer to use Kawase blur in most cases.'))
.setDescription(
_(
'Blur the rendered image. This is slow, so prefer to use Kawase blur in most cases.'
)
)
.markAsOnlyWorkingFor2D()
.addIncludeFile('Extensions/Effects/blur-pixi-filter.js');
const blurProperties = blurEffect.getProperties();
@@ -728,13 +725,11 @@ module.exports = {
const hslAdjustmentEffect = extension
.addEffect('HslAdjustment')
.setFullName(_('HSL Adjustment'))
.setDescription(
_(
'Adjust hue, saturation and lightness.'
)
)
.setDescription(_('Adjust hue, saturation and lightness.'))
.markAsOnlyWorkingFor2D()
.addIncludeFile('Extensions/Effects/pixi-filters/filter-hsl-adjustment.js')
.addIncludeFile(
'Extensions/Effects/pixi-filters/filter-hsl-adjustment.js'
)
.addIncludeFile('Extensions/Effects/hsl-adjustment-pixi-filter.js');
const hslAdjustmentProperties = hslAdjustmentEffect.getProperties();
hslAdjustmentProperties
@@ -767,7 +762,9 @@ module.exports = {
.addEffect('KawaseBlur')
.setFullName(_('Blur (Kawase, fast)'))
.setDescription(
_('Blur the rendered image, with much better performance than Gaussian blur.')
_(
'Blur the rendered image, with much better performance than Gaussian blur.'
)
)
.markAsOnlyWorkingFor2D()
.addIncludeFile('Extensions/Effects/pixi-filters/filter-kawase-blur.js')
@@ -816,9 +813,7 @@ module.exports = {
const motionBlurEffect = extension
.addEffect('MotionBlur')
.setFullName(_('Motion Blur'))
.setDescription(
_('Blur the rendered image to give a feeling of speed.')
)
.setDescription(_('Blur the rendered image to give a feeling of speed.'))
.markAsOnlyWorkingFor2D()
.addIncludeFile('Extensions/Effects/pixi-filters/filter-motion-blur.js')
.addIncludeFile('Extensions/Effects/motion-blur-pixi-filter.js');
@@ -1174,7 +1169,9 @@ module.exports = {
.setValue('0')
.setLabel(_('Elapsed time'))
.setType('number')
.setDescription('It can be set back to 0 to play the shockwave animation again.');
.setDescription(
'It can be set back to 0 to play the shockwave animation again.'
);
shockwaveEffectProperties
.getOrCreate('speed')
.setValue('500')
@@ -1311,10 +1308,7 @@ module.exports = {
return extension;
},
runExtensionSanityTests: function (
gd /*: libGDevelop */,
extension /*: gdPlatformExtension*/
) {
runExtensionSanityTests: function (gd, extension) {
return [];
},
};

View File

@@ -1,4 +1,5 @@
// @flow
//@ts-check
/// <reference path="../JsExtensionTypes.d.ts" />
/**
* This is a declaration of an extension for GDevelop 5.
*
@@ -12,18 +13,9 @@
* More information on https://github.com/4ian/GDevelop/blob/master/newIDE/README-extensions.md
*/
/*::
// Import types to allow Flow to do static type checking on this file.
// Extensions declaration are typed using Flow (like the editor), but the files
// for the game engine are checked with TypeScript annotations.
import { type ObjectsRenderingService, type ObjectsEditorService } from '../JsExtensionTypes.flow.js'
*/
/** @type {ExtensionModule} */
module.exports = {
createExtension: function (
_ /*: (string) => string */,
gd /*: libGDevelop */
) {
createExtension: function (_, gd) {
const extension = new gd.PlatformExtension();
extension.setExtensionInformation(
'MyDummyExtension',
@@ -153,7 +145,6 @@ module.exports = {
// Everything that is stored inside the behavior is in "behaviorContent" and is automatically
// saved/loaded to JSON.
var dummyBehavior = new gd.BehaviorJsImplementation();
// $FlowExpectedError - ignore Flow warning as we're creating a behavior
dummyBehavior.updateProperty = function (
behaviorContent,
propertyName,
@@ -170,7 +161,6 @@ module.exports = {
return false;
};
// $FlowExpectedError - ignore Flow warning as we're creating a behavior
dummyBehavior.getProperties = function (behaviorContent) {
var behaviorProperties = new gd.MapStringPropertyDescriptor();
@@ -187,7 +177,6 @@ module.exports = {
return behaviorProperties;
};
// $FlowExpectedError - ignore Flow warning as we're creating a behavior
dummyBehavior.initializeContent = function (behaviorContent) {
behaviorContent.setStringAttribute('property1', 'Initial value 1');
behaviorContent.setBoolAttribute('property2', true);
@@ -201,6 +190,7 @@ module.exports = {
'',
'CppPlatform/Extensions/topdownmovementicon.png',
'DummyBehavior',
//@ts-ignore The class hierarchy is incorrect leading to a type error, but this is valid.
dummyBehavior,
new gd.BehaviorsSharedData()
)
@@ -215,7 +205,6 @@ module.exports = {
// Create a new gd.BehaviorSharedDataJsImplementation object and implement the methods
// that are called to get and set the properties of the shared data.
var dummyBehaviorWithSharedData = new gd.BehaviorJsImplementation();
// $FlowExpectedError - ignore Flow warning as we're creating a behavior
dummyBehaviorWithSharedData.updateProperty = function (
behaviorContent,
propertyName,
@@ -228,7 +217,6 @@ module.exports = {
return false;
};
// $FlowExpectedError - ignore Flow warning as we're creating a behavior
dummyBehaviorWithSharedData.getProperties = function (behaviorContent) {
var behaviorProperties = new gd.MapStringPropertyDescriptor();
@@ -238,13 +226,11 @@ module.exports = {
return behaviorProperties;
};
// $FlowExpectedError - ignore Flow warning as we're creating a behavior
dummyBehaviorWithSharedData.initializeContent = function (behaviorContent) {
behaviorContent.setStringAttribute('property1', 'Initial value 1');
};
var sharedData = new gd.BehaviorSharedDataJsImplementation();
// $FlowExpectedError - ignore Flow warning as we're creating a behavior
sharedData.updateProperty = function (
sharedContent,
propertyName,
@@ -257,7 +243,6 @@ module.exports = {
return false;
};
// $FlowExpectedError - ignore Flow warning as we're creating a behavior
sharedData.getProperties = function (sharedContent) {
var sharedProperties = new gd.MapStringPropertyDescriptor();
@@ -267,7 +252,6 @@ module.exports = {
return sharedProperties;
};
// $FlowExpectedError - ignore Flow warning as we're creating a behavior
sharedData.initializeContent = function (behaviorContent) {
behaviorContent.setStringAttribute(
'sharedProperty1',
@@ -284,6 +268,7 @@ module.exports = {
'',
'CppPlatform/Extensions/topdownmovementicon.png',
'DummyBehaviorWithSharedData',
//@ts-ignore The class hierarchy is incorrect leading to a type error, but this is valid.
dummyBehaviorWithSharedData,
sharedData
)
@@ -302,7 +287,6 @@ module.exports = {
// Everything that is stored inside the object is in "content" and is automatically
// saved/loaded to JSON.
var dummyObject = new gd.ObjectJsImplementation();
// $FlowExpectedError - ignore Flow warning as we're creating an object
dummyObject.updateProperty = function (
objectContent,
propertyName,
@@ -327,7 +311,6 @@ module.exports = {
return false;
};
// $FlowExpectedError - ignore Flow warning as we're creating an object
dummyObject.getProperties = function (objectContent) {
var objectProperties = new gd.MapStringPropertyDescriptor();
@@ -362,7 +345,6 @@ module.exports = {
})
);
// $FlowExpectedError - ignore Flow warning as we're creating an object
dummyObject.updateInitialInstanceProperty = function (
objectContent,
instance,
@@ -382,7 +364,6 @@ module.exports = {
return false;
};
// $FlowExpectedError - ignore Flow warning as we're creating an object
dummyObject.getInitialInstanceProperties = function (
content,
instance,
@@ -446,10 +427,7 @@ module.exports = {
* But it is recommended to create tests for the behaviors/objects properties you created
* to avoid mistakes.
*/
runExtensionSanityTests: function (
gd /*: libGDevelop */,
extension /*: gdPlatformExtension*/
) {
runExtensionSanityTests: function (gd, extension) {
const dummyBehavior = extension
.getBehaviorMetadata('MyDummyExtension::DummyBehavior')
.get();
@@ -474,9 +452,7 @@ module.exports = {
*
* Run `node import-GDJS-Runtime.js` (in newIDE/app/scripts) if you make any change.
*/
registerEditorConfigurations: function (
objectsEditorService /*: ObjectsEditorService */
) {
registerEditorConfigurations: function (objectsEditorService) {
objectsEditorService.registerEditorConfiguration(
'MyDummyExtension::DummyObject',
objectsEditorService.getDefaultObjectJsImplementationPropertiesEditor({
@@ -489,9 +465,7 @@ module.exports = {
*
* Run `node import-GDJS-Runtime.js` (in newIDE/app/scripts) if you make any change.
*/
registerInstanceRenderers: function (
objectsRenderingService /*: ObjectsRenderingService */
) {
registerInstanceRenderers: function (objectsRenderingService) {
const RenderedInstance = objectsRenderingService.RenderedInstance;
const PIXI = objectsRenderingService.PIXI;

View File

@@ -1,4 +1,5 @@
// @flow
//@ts-check
/// <reference path="../JsExtensionTypes.d.ts" />
/**
* This is a declaration of an extension for GDevelop 5.
*
@@ -12,368 +13,414 @@
* More information on https://github.com/4ian/GDevelop/blob/master/newIDE/README-extensions.md
*/
/*::
// Import types to allow Flow to do static type checking on this file.
// Extensions declaration are typed using Flow (like the editor), but the files
// for the game engine are checked with TypeScript annotations.
import { type ObjectsRenderingService, type ObjectsEditorService } from '../JsExtensionTypes.flow.js'
*/
/** @type {ExtensionModule} */
module.exports = {
createExtension: function(_/*: (string) => string */, gd/*: libGDevelop */) {
createExtension: function (_, gd) {
const extension = new gd.PlatformExtension();
extension
.setExtensionInformation(
"FacebookInstantGames",
_("Facebook Instant Games"),
'FacebookInstantGames',
_('Facebook Instant Games'),
_(
"Allow your game to send scores and interact with the Facebook Instant Games platform."
'Allow your game to send scores and interact with the Facebook Instant Games platform.'
),
"Florian Rival",
"Open source (MIT License)"
'Florian Rival',
'Open source (MIT License)'
)
.setExtensionHelpPath("/publishing/publishing-to-facebook-instant-games")
.setExtensionHelpPath('/publishing/publishing-to-facebook-instant-games')
.setCategory('Third-party');
extension.addInstructionOrExpressionGroupMetadata(_("Facebook Instant Games"))
.setIcon("JsPlatform/Extensions/facebookicon32.png");
extension
.addInstructionOrExpressionGroupMetadata(_('Facebook Instant Games'))
.setIcon('JsPlatform/Extensions/facebookicon32.png');
extension
.addAction(
"SavePlayerData",
_("Save player data"),
'SavePlayerData',
_('Save player data'),
_(
"Save the content of the given scene variable in the player data, stored on Facebook Instant Games servers"
'Save the content of the given scene variable in the player data, stored on Facebook Instant Games servers'
),
_(
"Save the content of _PARAM1_ in key _PARAM0_ of player data (store success message in _PARAM2_ or error in _PARAM3_)"
'Save the content of _PARAM1_ in key _PARAM0_ of player data (store success message in _PARAM2_ or error in _PARAM3_)'
),
_("Player data"),
"JsPlatform/Extensions/facebookicon32.png",
"JsPlatform/Extensions/facebookicon32.png"
_('Player data'),
'JsPlatform/Extensions/facebookicon32.png',
'JsPlatform/Extensions/facebookicon32.png'
)
.addParameter("string", 'Data key name (e.g: "Lives")', "", false)
.addParameter("scenevar", "Scene variable with the content to save", "", false)
.addParameter('string', 'Data key name (e.g: "Lives")', '', false)
.addParameter(
"scenevar",
_("Variable where to store the success message (optional)"),
"",
true
)
.addParameter(
"scenevar",
_("Variable where to store the error message (optional, if an error occurs)"),
"",
true
)
.getCodeExtraInformation()
.setIncludeFile(
"Extensions/FacebookInstantGames/facebookinstantgamestools.js"
)
.setFunctionName("gdjs.evtTools.facebookInstantGames.setPlayerData");
extension
.addAction(
"LoadPlayerData",
_("Load player data"),
_("Load the player data with the given key in a variable"),
_(
"Load player data with key _PARAM0_ in _PARAM1_ (or error in _PARAM2_)"
),
_("Player data"),
"JsPlatform/Extensions/facebookicon32.png",
"JsPlatform/Extensions/facebookicon32.png"
)
.addParameter("string", _('Data key name (e.g: "Lives")'), "", false)
.addParameter(
"scenevar",
_("Variable where to store loaded data"),
"",
'scenevar',
'Scene variable with the content to save',
'',
false
)
.addParameter(
"scenevar",
_("Variable where to store the error message (optional, if an error occurs)"),
"",
'scenevar',
_('Variable where to store the success message (optional)'),
'',
true
)
.addParameter(
'scenevar',
_(
'Variable where to store the error message (optional, if an error occurs)'
),
'',
true
)
.getCodeExtraInformation()
.setIncludeFile(
"Extensions/FacebookInstantGames/facebookinstantgamestools.js"
'Extensions/FacebookInstantGames/facebookinstantgamestools.js'
)
.setFunctionName("gdjs.evtTools.facebookInstantGames.loadPlayerData");
.setFunctionName('gdjs.evtTools.facebookInstantGames.setPlayerData');
extension
.addAction(
"SavePlayerScore",
_("Save player score"),
'LoadPlayerData',
_('Load player data'),
_('Load the player data with the given key in a variable'),
_(
"Save the score, and optionally the content of the given variable in the player score, for the given metadata."
'Load player data with key _PARAM0_ in _PARAM1_ (or error in _PARAM2_)'
),
_(
"In leaderboard _PARAM0_, save score _PARAM1_ for the player and extra data from _PARAM2_ (store success message in _PARAM3_ or error in _PARAM4_)"
),
_("Leaderboards"),
"JsPlatform/Extensions/facebookicon32.png",
"JsPlatform/Extensions/facebookicon32.png"
_('Player data'),
'JsPlatform/Extensions/facebookicon32.png',
'JsPlatform/Extensions/facebookicon32.png'
)
.addParameter('string', _('Data key name (e.g: "Lives")'), '', false)
.addParameter(
'scenevar',
_('Variable where to store loaded data'),
'',
false
)
.addParameter(
"string",
'scenevar',
_(
'Variable where to store the error message (optional, if an error occurs)'
),
'',
true
)
.getCodeExtraInformation()
.setIncludeFile(
'Extensions/FacebookInstantGames/facebookinstantgamestools.js'
)
.setFunctionName('gdjs.evtTools.facebookInstantGames.loadPlayerData');
extension
.addAction(
'SavePlayerScore',
_('Save player score'),
_(
'Save the score, and optionally the content of the given variable in the player score, for the given metadata.'
),
_(
'In leaderboard _PARAM0_, save score _PARAM1_ for the player and extra data from _PARAM2_ (store success message in _PARAM3_ or error in _PARAM4_)'
),
_('Leaderboards'),
'JsPlatform/Extensions/facebookicon32.png',
'JsPlatform/Extensions/facebookicon32.png'
)
.addParameter(
'string',
'Leaderboard name (e.g: "PlayersBestTimes")',
"",
'',
false
)
.addParameter("expression", "Score to register for the player", "", false)
.addParameter('expression', 'Score to register for the player', '', false)
.addParameter(
"scenevar",
_("Optional variable with metadata to save"),
"",
'scenevar',
_('Optional variable with metadata to save'),
'',
true
)
.addParameter(
"scenevar",
_("Variable where to store the success message (optional)"),
"",
'scenevar',
_('Variable where to store the success message (optional)'),
'',
true
)
.addParameter(
"scenevar",
_("Variable where to store the error message (optional, if an error occurs)"),
"",
true
)
.getCodeExtraInformation()
.setIncludeFile(
"Extensions/FacebookInstantGames/facebookinstantgamestools.js"
)
.setFunctionName("gdjs.evtTools.facebookInstantGames.setPlayerScore");
extension
.addAction(
"LoadPlayerEntry",
_("Load player entry"),
_("Load the player entry in the given leaderboard"),
'scenevar',
_(
"Load player entry from leaderboard _PARAM0_. Set rank in _PARAM1_, score in _PARAM2_ (extra data if any in _PARAM3_ and error in _PARAM4_)"
'Variable where to store the error message (optional, if an error occurs)'
),
_("Leaderboards"),
"JsPlatform/Extensions/facebookicon32.png",
"JsPlatform/Extensions/facebookicon32.png"
'',
true
)
.getCodeExtraInformation()
.setIncludeFile(
'Extensions/FacebookInstantGames/facebookinstantgamestools.js'
)
.setFunctionName('gdjs.evtTools.facebookInstantGames.setPlayerScore');
extension
.addAction(
'LoadPlayerEntry',
_('Load player entry'),
_('Load the player entry in the given leaderboard'),
_(
'Load player entry from leaderboard _PARAM0_. Set rank in _PARAM1_, score in _PARAM2_ (extra data if any in _PARAM3_ and error in _PARAM4_)'
),
_('Leaderboards'),
'JsPlatform/Extensions/facebookicon32.png',
'JsPlatform/Extensions/facebookicon32.png'
)
.addParameter(
"string",
'string',
_('Leaderboard name (e.g: "PlayersBestTimes")'),
"",
'',
false
)
.addParameter(
"scenevar",
_("Variable where to store the player rank (of -1 if not ranked)"),
"",
'scenevar',
_('Variable where to store the player rank (of -1 if not ranked)'),
'',
true
)
.addParameter(
"scenevar",
_("Variable where to store the player score (of -1 if no score)"),
"",
'scenevar',
_('Variable where to store the player score (of -1 if no score)'),
'',
true
)
.addParameter(
"scenevar",
_("Variable where to store extra data (if any)"),
"",
'scenevar',
_('Variable where to store extra data (if any)'),
'',
true
)
.addParameter(
"scenevar",
_("Variable where to store the error message (optional, if an error occurs)"),
"",
'scenevar',
_(
'Variable where to store the error message (optional, if an error occurs)'
),
'',
true
)
.getCodeExtraInformation()
.setIncludeFile(
"Extensions/FacebookInstantGames/facebookinstantgamestools.js"
'Extensions/FacebookInstantGames/facebookinstantgamestools.js'
)
.setFunctionName("gdjs.evtTools.facebookInstantGames.getPlayerEntry");
.setFunctionName('gdjs.evtTools.facebookInstantGames.getPlayerEntry');
extension
.addCondition(
"AreAdsSupported",
_("Check if ads are supported"),
_("Check if showing ads is supported on this device (only mobile phones can show ads)"),
_("Ads can be shown on this device"),
_("Ads"),
"JsPlatform/Extensions/facebookicon32.png",
"JsPlatform/Extensions/facebookicon32.png"
'AreAdsSupported',
_('Check if ads are supported'),
_(
'Check if showing ads is supported on this device (only mobile phones can show ads)'
),
_('Ads can be shown on this device'),
_('Ads'),
'JsPlatform/Extensions/facebookicon32.png',
'JsPlatform/Extensions/facebookicon32.png'
)
.getCodeExtraInformation()
.setIncludeFile(
"Extensions/FacebookInstantGames/facebookinstantgamestools.js"
'Extensions/FacebookInstantGames/facebookinstantgamestools.js'
)
.setFunctionName("gdjs.evtTools.facebookInstantGames.areAdsSupported");
.setFunctionName('gdjs.evtTools.facebookInstantGames.areAdsSupported');
extension
.addCondition(
"IsInterstitialAdReady",
_("Is the interstitial ad ready"),
_("Check if the interstitial ad requested from Facebook is loaded and ready to be shown."),
_("The interstitial ad is loaded and ready to be shown"),
_("Ads"),
"JsPlatform/Extensions/facebookicon32.png",
"JsPlatform/Extensions/facebookicon32.png"
'IsInterstitialAdReady',
_('Is the interstitial ad ready'),
_(
'Check if the interstitial ad requested from Facebook is loaded and ready to be shown.'
),
_('The interstitial ad is loaded and ready to be shown'),
_('Ads'),
'JsPlatform/Extensions/facebookicon32.png',
'JsPlatform/Extensions/facebookicon32.png'
)
.getCodeExtraInformation()
.setIncludeFile(
"Extensions/FacebookInstantGames/facebookinstantgamestools.js"
'Extensions/FacebookInstantGames/facebookinstantgamestools.js'
)
.setFunctionName("gdjs.evtTools.facebookInstantGames.isInterstitialAdReady");
.setFunctionName(
'gdjs.evtTools.facebookInstantGames.isInterstitialAdReady'
);
extension
.addAction(
"LoadInterstitialAd",
_("Load and prepare an interstitial ad"),
_("Request and load an interstitial ad from Facebook, so that it is ready to be shown."),
_("Request and load an interstitial ad from Facebook (ad placement id: _PARAM0_, error in _PARAM1_)"),
_("Ads"),
"JsPlatform/Extensions/facebookicon32.png",
"JsPlatform/Extensions/facebookicon32.png"
'LoadInterstitialAd',
_('Load and prepare an interstitial ad'),
_(
'Request and load an interstitial ad from Facebook, so that it is ready to be shown.'
),
_(
'Request and load an interstitial ad from Facebook (ad placement id: _PARAM0_, error in _PARAM1_)'
),
_('Ads'),
'JsPlatform/Extensions/facebookicon32.png',
'JsPlatform/Extensions/facebookicon32.png'
)
.addParameter(
"string",
_("The Ad Placement id (can be found while setting up the ad on Facebook)"),
"",
'string',
_(
'The Ad Placement id (can be found while setting up the ad on Facebook)'
),
'',
false
)
.addParameter(
"scenevar",
_("Variable where to store the error message (optional, if an error occurs)"),
"",
'scenevar',
_(
'Variable where to store the error message (optional, if an error occurs)'
),
'',
true
)
.getCodeExtraInformation()
.setIncludeFile(
"Extensions/FacebookInstantGames/facebookinstantgamestools.js"
'Extensions/FacebookInstantGames/facebookinstantgamestools.js'
)
.setFunctionName("gdjs.evtTools.facebookInstantGames.loadInterstitialAd");
.setFunctionName('gdjs.evtTools.facebookInstantGames.loadInterstitialAd');
extension
.addAction(
"ShowInterstitialAd",
_("Show the loaded interstitial ad"),
_("Show the interstitial ad previously loaded in memory. This won't work if you did not load the interstitial before."),
_("Show the interstitial ad previously loaded in memory (if any error, store it in _PARAM0_)"),
_("Ads"),
"JsPlatform/Extensions/facebookicon32.png",
"JsPlatform/Extensions/facebookicon32.png"
'ShowInterstitialAd',
_('Show the loaded interstitial ad'),
_(
"Show the interstitial ad previously loaded in memory. This won't work if you did not load the interstitial before."
),
_(
'Show the interstitial ad previously loaded in memory (if any error, store it in _PARAM0_)'
),
_('Ads'),
'JsPlatform/Extensions/facebookicon32.png',
'JsPlatform/Extensions/facebookicon32.png'
)
.addParameter(
"scenevar",
_("Variable where to store the error message (optional, if an error occurs)"),
"",
'scenevar',
_(
'Variable where to store the error message (optional, if an error occurs)'
),
'',
true
)
.getCodeExtraInformation()
.setIncludeFile(
"Extensions/FacebookInstantGames/facebookinstantgamestools.js"
'Extensions/FacebookInstantGames/facebookinstantgamestools.js'
)
.setFunctionName("gdjs.evtTools.facebookInstantGames.showInterstitialAd");
.setFunctionName('gdjs.evtTools.facebookInstantGames.showInterstitialAd');
extension
.addCondition(
"IsRewardedVideoReady",
_("Is the rewarded video ready"),
_("Check if the rewarded video requested from Facebook is loaded and ready to be shown."),
_("The rewarded video is loaded and ready to be shown"),
_("Ads"),
"JsPlatform/Extensions/facebookicon32.png",
"JsPlatform/Extensions/facebookicon32.png"
'IsRewardedVideoReady',
_('Is the rewarded video ready'),
_(
'Check if the rewarded video requested from Facebook is loaded and ready to be shown.'
),
_('The rewarded video is loaded and ready to be shown'),
_('Ads'),
'JsPlatform/Extensions/facebookicon32.png',
'JsPlatform/Extensions/facebookicon32.png'
)
.getCodeExtraInformation()
.setIncludeFile(
"Extensions/FacebookInstantGames/facebookinstantgamestools.js"
'Extensions/FacebookInstantGames/facebookinstantgamestools.js'
)
.setFunctionName("gdjs.evtTools.facebookInstantGames.isRewardedVideoReady");
.setFunctionName(
'gdjs.evtTools.facebookInstantGames.isRewardedVideoReady'
);
extension
.addAction(
"LoadRewardedVideo",
_("Load and prepare a rewarded video"),
_("Request and load a rewarded video from Facebook, so that it is ready to be shown."),
_("Request and load a rewarded video from Facebook (ad placement id: _PARAM0_, error in _PARAM1_)"),
_("Ads"),
"JsPlatform/Extensions/facebookicon32.png",
"JsPlatform/Extensions/facebookicon32.png"
'LoadRewardedVideo',
_('Load and prepare a rewarded video'),
_(
'Request and load a rewarded video from Facebook, so that it is ready to be shown.'
),
_(
'Request and load a rewarded video from Facebook (ad placement id: _PARAM0_, error in _PARAM1_)'
),
_('Ads'),
'JsPlatform/Extensions/facebookicon32.png',
'JsPlatform/Extensions/facebookicon32.png'
)
.addParameter(
"string",
_("The Ad Placement id (can be found while setting up the ad on Facebook)"),
"",
'string',
_(
'The Ad Placement id (can be found while setting up the ad on Facebook)'
),
'',
false
)
.addParameter(
"scenevar",
_("Variable where to store the error message (optional, if an error occurs)"),
"",
'scenevar',
_(
'Variable where to store the error message (optional, if an error occurs)'
),
'',
true
)
.getCodeExtraInformation()
.setIncludeFile(
"Extensions/FacebookInstantGames/facebookinstantgamestools.js"
'Extensions/FacebookInstantGames/facebookinstantgamestools.js'
)
.setFunctionName("gdjs.evtTools.facebookInstantGames.loadRewardedVideo");
.setFunctionName('gdjs.evtTools.facebookInstantGames.loadRewardedVideo');
extension
.addAction(
"ShowRewardedVideo",
_("Show the loaded rewarded video"),
_("Show the rewarded video previously loaded in memory. This won't work if you did not load the video before."),
_("Show the rewarded video previously loaded in memory (if any error, store it in _PARAM0_)"),
_("Ads"),
"JsPlatform/Extensions/facebookicon32.png",
"JsPlatform/Extensions/facebookicon32.png"
'ShowRewardedVideo',
_('Show the loaded rewarded video'),
_(
"Show the rewarded video previously loaded in memory. This won't work if you did not load the video before."
),
_(
'Show the rewarded video previously loaded in memory (if any error, store it in _PARAM0_)'
),
_('Ads'),
'JsPlatform/Extensions/facebookicon32.png',
'JsPlatform/Extensions/facebookicon32.png'
)
.addParameter(
"scenevar",
_("Variable where to store the error message (optional, if an error occurs)"),
"",
'scenevar',
_(
'Variable where to store the error message (optional, if an error occurs)'
),
'',
true
)
.getCodeExtraInformation()
.setIncludeFile(
"Extensions/FacebookInstantGames/facebookinstantgamestools.js"
'Extensions/FacebookInstantGames/facebookinstantgamestools.js'
)
.setFunctionName("gdjs.evtTools.facebookInstantGames.showRewardedVideo");
.setFunctionName('gdjs.evtTools.facebookInstantGames.showRewardedVideo');
extension
.addStrExpression(
"PlayerId",
_("Player identifier"),
_("Get the player unique identifier"),
'PlayerId',
_('Player identifier'),
_('Get the player unique identifier'),
'',
"JsPlatform/Extensions/facebookicon32.png"
'JsPlatform/Extensions/facebookicon32.png'
)
.getCodeExtraInformation()
.setIncludeFile(
"Extensions/FacebookInstantGames/facebookinstantgamestools.js"
'Extensions/FacebookInstantGames/facebookinstantgamestools.js'
)
.setFunctionName("gdjs.evtTools.facebookInstantGames.getPlayerId");
.setFunctionName('gdjs.evtTools.facebookInstantGames.getPlayerId');
extension
.addStrExpression(
"PlayerName",
_("Player name"),
_("Get the player name"),
'PlayerName',
_('Player name'),
_('Get the player name'),
'',
"JsPlatform/Extensions/facebookicon32.png"
'JsPlatform/Extensions/facebookicon32.png'
)
.getCodeExtraInformation()
.setIncludeFile(
"Extensions/FacebookInstantGames/facebookinstantgamestools.js"
'Extensions/FacebookInstantGames/facebookinstantgamestools.js'
)
.setFunctionName("gdjs.evtTools.facebookInstantGames.getPlayerName");
.setFunctionName('gdjs.evtTools.facebookInstantGames.getPlayerName');
return extension;
},
runExtensionSanityTests: function(gd /*: libGDevelop */, extension /*: gdPlatformExtension*/) {
runExtensionSanityTests: function (gd, extension) {
return [];
}
},
};

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,5 @@
// @flow
//@ts-check
/// <reference path="../JsExtensionTypes.d.ts" />
/**
* This is a declaration of an extension for GDevelop 5.
*
@@ -11,11 +12,10 @@
*
* More information on https://github.com/4ian/GDevelop/blob/master/newIDE/README-extensions.md
*/
/** @type {ExtensionModule} */
module.exports = {
createExtension: function (
_ /*: (string) => string */,
gd /*: libGDevelop */
) {
createExtension: function (_, gd) {
const extension = new gd.PlatformExtension();
extension
@@ -2314,10 +2314,7 @@ module.exports = {
return extension;
},
runExtensionSanityTests: function (
gd /*: libGDevelop */,
extension /*: gdPlatformExtension */
) {
runExtensionSanityTests: function (gd, extension) {
return [];
},
};

225
Extensions/JsExtensionTypes.d.ts vendored Normal file
View File

@@ -0,0 +1,225 @@
type GDNamespace = typeof import('../GDevelop.js/types');
// This is necessary for typescript to interpret the identifier PIXI as a namespace
// in this file and merge it with the other namespace declarations.
declare namespace PIXI {}
/**
* RenderedInstance is the base class used for creating 2D renderers of instances,
* which display on the scene editor, using Pixi.js, the instance of an object (see InstancesEditor).
*/
class RenderedInstance {
_project: gd.Project;
_layout: gd.Layout;
_instance: gd.InitialInstance;
_associatedObjectConfiguration: gd.ObjectConfiguration;
_pixiContainer: PIXI.Container;
_pixiResourcesLoader: Class<PixiResourcesLoader>;
_pixiObject: PIXI.DisplayObject;
wasUsed: boolean;
constructor(
project: gdProject,
layout: gdLayout,
instance: gdInitialInstance,
associatedObjectConfiguration: gdObjectConfiguration,
pixiContainer: PIXI.Container,
pixiResourcesLoader: Class<PixiResourcesLoader>
);
/**
* Convert an angle from degrees to radians.
*/
static toRad(angleInDegrees: number): number;
/**
* Called when the scene editor is rendered.
*/
update(): void;
getPixiObject(): PIXI.DisplayObject | null;
getInstance(): gd.InitialInstance;
/**
* Called to notify the instance renderer that its associated instance was removed from
* the scene. The PIXI object should probably be removed from the container: This is what
* the default implementation of the method does.
*/
onRemovedFromScene(): void;
getOriginX(): number;
getOriginY(): number;
getCenterX(): number;
getCenterY(): number;
getCustomWidth(): number;
getCustomHeight(): number;
getWidth(): number;
getHeight(): number;
getDepth(): number;
/**
* Return the width of the instance when the instance doesn't have a custom size.
*/
getDefaultWidth(): number;
/**
* Return the height of the instance when the instance doesn't have a custom size.
*/
getDefaultHeight(): number;
getDefaultDepth(): number;
}
/**
* Rendered3DInstance is the base class used for creating 3D renderers of instances,
* which display on the scene editor, using Three.js, the instance of an object (see InstancesEditor).
* It can also display 2D artifacts on Pixi 2D plane (3D object shadow projected on the plane for instance).
*/
class Rendered3DInstance {
_project: gdProject;
_layout: gdLayout;
_instance: gdInitialInstance;
_associatedObjectConfiguration: gdObjectConfiguration;
_pixiContainer: PIXI.Container;
_threeGroup: THREE.Group;
_pixiResourcesLoader: Class<PixiResourcesLoader>;
_pixiObject: PIXI.DisplayObject;
_threeObject: THREE.Object3D | null;
wasUsed: boolean;
constructor(
project: gdProject,
layout: gdLayout,
instance: gdInitialInstance,
associatedObjectConfiguration: gdObjectConfiguration,
pixiContainer: PIXI.Container,
threeGroup: THREE.Group,
pixiResourcesLoader: Class<PixiResourcesLoader>
);
/**
* Convert an angle from degrees to radians.
*/
static toRad(angleInDegrees: number): number;
/**
* Called when the scene editor is rendered.
*/
update(): void;
getPixiObject(): PIXI.DisplayObject;
getThreeObject(): THREE.Object3D;
getInstance(): gd.InitialInstance;
/**
* Called to notify the instance renderer that its associated instance was removed from
* the scene. The PIXI object should probably be removed from the container: This is what
* the default implementation of the method does.
*/
onRemovedFromScene(): void;
getOriginX(): number;
getOriginY(): number;
getCenterX(): number;
getCenterY(): number;
getWidth(): number;
getHeight(): number;
getDepth(): number;
/**
* Return the width of the instance when the instance doesn't have a custom size.
*/
getDefaultWidth(): number;
/**
* Return the height of the instance when the instance doesn't have a custom size.
*/
getDefaultHeight(): number;
/**
* Return the depth of the instance when the instance doesn't have a custom size.
*/
getDefaultDepth(): number;
}
declare type ObjectsRenderingService = {
gd: GDNamespace;
PIXI: PIXI;
THREE: typeof import('../newIDE/app/node_modules/three');
THREE_ADDONS: { SkeletonUtils: any };
RenderedInstance: typeof RenderedInstance;
Rendered3DInstance: typeof Rendered3DInstance;
registerInstanceRenderer: (objectType: string, renderer: any) => void;
registerInstance3DRenderer: (objectType: string, renderer: any) => void;
requireModule: (dirname: string, moduleName: string) => any;
getThumbnail: (
project: gd.Project,
objectConfiguration: gd.ObjectConfiguration
) => string;
rgbOrHexToHexNumber: (value: string) => number;
registerClearCache: (clearCache: (_: any) => void) => void;
};
declare type ObjectsEditorService = {
registerEditorConfiguration: (
objectType: string,
editorConfiguration: any
) => void;
getDefaultObjectJsImplementationPropertiesEditor: ({
helpPagePath: string,
}) => any;
};
declare type ExtensionModule = {
createExtension: (
_: (string) => string,
gd: GDNamespace
) => gd.PlatformExtension;
/**
* You can optionally add sanity tests that will check the basic working
* of your extension behaviors/objects by instantiating behaviors/objects
* and setting the property to a given value.
*
* If you don't have any tests, you can simply return an empty array.
*
* But it is recommended to create tests for the behaviors/objects properties you created
* to avoid mistakes.
*/
runExtensionSanityTests: (
gd: GDNamespace,
extension: gd.PlatformExtension
) => string[];
/**
* Register editors for objects.
*
* Run `node import-GDJS-Runtime.js` (in newIDE/app/scripts) if you make any change.
*/
registerEditorConfigurations?: (
objectsEditorService: ObjectsEditorService
) => void;
/**
* Register renderers for instance of objects on the scene editor.
*
* Run `node import-GDJS-Runtime.js` (in newIDE/app/scripts) if you make any change.
*/
registerInstanceRenderers?: (
objectsRenderingService: ObjectsRenderingService
) => void;
};

View File

@@ -1,35 +0,0 @@
// @flow
/**
* @file This file contains the (Flow) types that are used in the JavaScript
* extensions declaration (i.e: JsExtension.js files).
* Extension runtime files are in TypeScript (ts files) and not using Flow.
*
* If you do changes here, run `node import-GDJS-Runtime.js` (in newIDE/app/scripts),
* and be sure that the types declared here are reflecting the types exposed by the editor.
*
* Note that Flow comments are used to avoid having to preprocess this file and the
* JsExtension.js files through Babel. This allows to keep plain JS files, while allowing
* Flow static type checking to be run on them when integrated in the editor.
*/
/*::
export type ObjectsRenderingService = {
gd: libGDevelop,
PIXI: any,
THREE: any,
THREE_ADDONS: {SkeletonUtils: any},
RenderedInstance: any,
Rendered3DInstance: any,
registerInstanceRenderer: (objectType: string, renderer: any) => void,
registerInstance3DRenderer: (objectType: string, renderer: any) => void,
requireModule: (dirname: string, moduleName: string) => any,
getThumbnail: (project: gdProject, objectConfiguration: gdObjectConfiguration) => string,
rgbOrHexToHexNumber: (value: string) => number,
registerClearCache: (clearCache: any => void) => void,
};
export type ObjectsEditorService = {
registerEditorConfiguration: (objectType: string, editorConfiguration: any) => void,
getDefaultObjectJsImplementationPropertiesEditor: ({| helpPagePath: string |}) => any,
};
*/

View File

@@ -1,4 +1,5 @@
// @flow
//@ts-check
/// <reference path="../JsExtensionTypes.d.ts" />
/**
* This is a declaration of an extension for GDevelop 5.
*
@@ -12,18 +13,9 @@
* More information on https://github.com/4ian/GDevelop/blob/master/newIDE/README-extensions.md
*/
/*::
// Import types to allow Flow to do static type checking on this file.
// Extensions declaration are typed using Flow (like the editor), but the files
// for the game engine are checked with TypeScript annotations.
import { type ObjectsRenderingService, type ObjectsEditorService } from '../JsExtensionTypes.flow.js'
*/
/** @type {ExtensionModule} */
module.exports = {
createExtension: function (
_ /*: (string) => string */,
gd /*: libGDevelop */
) {
createExtension: function (_, gd) {
const extension = new gd.PlatformExtension();
extension
.setExtensionInformation(
@@ -96,7 +88,9 @@ module.exports = {
.setIncludeFile('Extensions/Leaderboards/sha256.js')
.addIncludeFile('Extensions/Leaderboards/leaderboardstools.js')
.setFunctionName('gdjs.evtTools.leaderboards.saveConnectedPlayerScore')
.setAsyncFunctionName('gdjs.evtTools.leaderboards.saveConnectedPlayerScore');
.setAsyncFunctionName(
'gdjs.evtTools.leaderboards.saveConnectedPlayerScore'
);
extension
.addCondition(
@@ -299,10 +293,7 @@ module.exports = {
return extension;
},
runExtensionSanityTests: function (
gd /*: libGDevelop */,
extension /*: gdPlatformExtension*/
) {
runExtensionSanityTests: function (gd, extension) {
return [];
},
};

View File

@@ -1,4 +1,5 @@
// @flow
//@ts-check
/// <reference path="../JsExtensionTypes.d.ts" />
/**
* This is a declaration of an extension for GDevelop 5.
*
@@ -12,32 +13,23 @@
* More information on https://github.com/4ian/GDevelop/blob/master/newIDE/README-extensions.md
*/
/*::
// Import types to allow Flow to do static type checking on this file.
// Extensions declaration are typed using Flow (like the editor), but the files
// for the game engine are checked with TypeScript annotations.
import { type ObjectsRenderingService, type ObjectsEditorService } from '../JsExtensionTypes.flow.js'
*/
/** @type {ExtensionModule} */
module.exports = {
createExtension: function (
_ /*: (string) => string */,
gd /*: libGDevelop */
) {
createExtension: function (_, gd) {
const extension = new gd.PlatformExtension();
extension.setExtensionInformation(
'Lighting',
_('Lights'),
extension
.setExtensionInformation(
'Lighting',
_('Lights'),
'This provides a light object, and a behavior to mark other objects as being obstacles for the lights. This is a great way to create a special atmosphere to your game, along with effects, make it more realistic or to create gameplays based on lights.',
'Harsimran Virk',
'MIT'
)
.setCategory('Visual effect')
.setTags("light");
'This provides a light object, and a behavior to mark other objects as being obstacles for the lights. This is a great way to create a special atmosphere to your game, along with effects, make it more realistic or to create gameplays based on lights.',
'Harsimran Virk',
'MIT'
)
.setCategory('Visual effect')
.setTags('light');
const lightObstacleBehavior = new gd.BehaviorJsImplementation();
// $FlowExpectedError - ignore Flow warning as we're creating a behavior
lightObstacleBehavior.updateProperty = function (
behaviorContent,
propertyName,
@@ -46,14 +38,12 @@ module.exports = {
return false;
};
// $FlowExpectedError - ignore Flow warning as we're creating a behavior
lightObstacleBehavior.getProperties = function (behaviorContent) {
const behaviorProperties = new gd.MapStringPropertyDescriptor();
return behaviorProperties;
};
// $FlowExpectedError - ignore Flow warning as we're creating a behavior
lightObstacleBehavior.initializeContent = function (behaviorContent) {};
extension
.addBehavior(
@@ -66,6 +56,7 @@ module.exports = {
'',
'CppPlatform/Extensions/lightObstacleIcon32.png',
'LightObstacleBehavior',
//@ts-ignore The class hierarchy is incorrect leading to a type error, but this is valid.
lightObstacleBehavior,
new gd.BehaviorsSharedData()
)
@@ -77,7 +68,6 @@ module.exports = {
const lightObject = new gd.ObjectJsImplementation();
// $FlowExpectedError - ignore Flow warning as we're creating an object.
lightObject.updateProperty = function (
objectContent,
propertyName,
@@ -106,7 +96,6 @@ module.exports = {
return false;
};
// $FlowExpectedError - ignore Flow warning as we're creating an object.
lightObject.getProperties = function (objectContent) {
const objectProperties = new gd.MapStringPropertyDescriptor();
@@ -160,7 +149,6 @@ module.exports = {
})
);
// $FlowExpectedError - ignore Flow warning as we're creating an object.
lightObject.updateInitialInstanceProperty = function (
objectContent,
instance,
@@ -172,7 +160,6 @@ module.exports = {
return false;
};
// $FlowExpectedError - ignore Flow warning as we're creating an object.
lightObject.getInitialInstanceProperties = function (
content,
instance,
@@ -233,16 +220,11 @@ module.exports = {
return extension;
},
runExtensionSanityTests: function (
gd /*: libGDevelop */,
extension /*: gdPlatformExtension*/
) {
runExtensionSanityTests: function (gd, extension) {
return [];
},
registerEditorConfigurations: function (
objectsEditorService /*: ObjectsEditorService */
) {
registerEditorConfigurations: function (objectsEditorService) {
objectsEditorService.registerEditorConfiguration(
'Lighting::LightObject',
objectsEditorService.getDefaultObjectJsImplementationPropertiesEditor({
@@ -255,9 +237,7 @@ module.exports = {
*
* Run `node import-GDJS-Runtime.js` (in newIDE/app/scripts) if you make any change.
*/
registerInstanceRenderers: function (
objectsRenderingService /*: ObjectsRenderingService */
) {
registerInstanceRenderers: function (objectsRenderingService) {
const RenderedInstance = objectsRenderingService.RenderedInstance;
const PIXI = objectsRenderingService.PIXI;
@@ -283,32 +263,34 @@ module.exports = {
);
this._radius = parseFloat(
this._associatedObjectConfiguration
.getProperties(this.project)
.getProperties()
.get('radius')
.getValue()
);
if (this._radius <= 0) this._radius = 1;
const color = objectsRenderingService.rgbOrHexToHexNumber(
this._associatedObjectConfiguration
.getProperties(this.project)
.getProperties()
.get('color')
.getValue()
);
// The icon in the middle.
const lightIconSprite = new PIXI.Sprite(PIXI.Texture.from('CppPlatform/Extensions/lightIcon32.png'));
const lightIconSprite = new PIXI.Sprite(
PIXI.Texture.from('CppPlatform/Extensions/lightIcon32.png')
);
lightIconSprite.anchor.x = 0.5;
lightIconSprite.anchor.y = 0.5;
// The circle to show the radius of the light.
const radiusBorderWidth = 2;
const radiusGraphics = new PIXI.Graphics();
radiusGraphics.lineStyle(
radiusBorderWidth,
color,
0.8
radiusGraphics.lineStyle(radiusBorderWidth, color, 0.8);
radiusGraphics.drawCircle(
0,
0,
Math.max(1, this._radius - radiusBorderWidth)
);
radiusGraphics.drawCircle(0, 0, Math.max(1, this._radius - radiusBorderWidth));
this._pixiObject = new PIXI.Container();
this._pixiObject.addChild(lightIconSprite);
@@ -326,11 +308,7 @@ module.exports = {
/**
* Return the path to the thumbnail of the specified object.
*/
static getThumbnail(
project,
resourcesLoader,
objectConfiguration
) {
static getThumbnail(project, resourcesLoader, objectConfiguration) {
return 'CppPlatform/Extensions/lightIcon32.png';
}

View File

@@ -1,4 +1,5 @@
// @flow
//@ts-check
/// <reference path="../JsExtensionTypes.d.ts" />
/**
* This is a declaration of an extension for GDevelop 5.
*
@@ -12,18 +13,9 @@
* More information on https://github.com/4ian/GDevelop/blob/master/newIDE/README-extensions.md
*/
/*::
// Import types to allow Flow to do static type checking on this file.
// Extensions declaration are typed using Flow (like the editor), but the files
// for the game engine are checked with TypeScript annotations.
import { type ObjectsRenderingService, type ObjectsEditorService } from '../JsExtensionTypes.flow.js'
*/
/** @type {ExtensionModule} */
module.exports = {
createExtension: function (
_ /*: (string) => string */,
gd /*: libGDevelop */
) {
createExtension: function (_, gd) {
const extension /*: gdPlatformExtension */ = new gd.PlatformExtension();
extension
.setExtensionInformation(
@@ -474,10 +466,7 @@ module.exports = {
return extension;
},
runExtensionSanityTests: function (
gd /*: libGDevelop */,
extension /*: gdPlatformExtension*/
) {
runExtensionSanityTests: function (gd, extension) {
return [];
},
};

View File

@@ -1,4 +1,5 @@
// @flow
//@ts-check
/// <reference path="../JsExtensionTypes.d.ts" />
/**
* This is a declaration of an extension for GDevelop 5.
*
@@ -12,18 +13,9 @@
* More information on https://github.com/4ian/GDevelop/blob/master/newIDE/README-extensions.md
*/
/*::
// Import types to allow Flow to do static type checking on this file.
// Extensions declaration are typed using Flow (like the editor), but the files
// for the game engine are checked with TypeScript annotations.
import { type ObjectsRenderingService, type ObjectsEditorService } from '../JsExtensionTypes.flow.js'
*/
/** @type {ExtensionModule} */
module.exports = {
createExtension: function (
_ /*: (string) => string */,
gd /*: libGDevelop */
) {
createExtension: function (_, gd) {
const extension = new gd.PlatformExtension();
extension
.setExtensionInformation(
@@ -35,13 +27,12 @@ module.exports = {
)
.setExtensionHelpPath('/behaviors/physics2')
.setCategory('Movement')
.setTags("physics, gravity, obstacle, collision");
.setTags('physics, gravity, obstacle, collision');
extension
.addInstructionOrExpressionGroupMetadata(_('Physics Engine 2.0'))
.setIcon('res/physics32.png');
var physics2Behavior = new gd.BehaviorJsImplementation();
// $FlowExpectedError - ignore Flow warning as we're creating a behavior
physics2Behavior.updateProperty = function (
behaviorContent,
propertyName,
@@ -51,104 +42,138 @@ module.exports = {
behaviorContent.getChild('bodyType').setStringValue(newValue);
return true;
}
if (propertyName === 'bullet') {
behaviorContent.getChild('bullet').setBoolValue(newValue === '1');
return true;
}
if (propertyName === 'fixedRotation') {
behaviorContent
.getChild('fixedRotation')
.setBoolValue(newValue === '1');
return true;
}
if (propertyName === 'canSleep') {
behaviorContent.getChild('canSleep').setBoolValue(newValue === '1');
return true;
}
if (propertyName === 'shape') {
behaviorContent.getChild('shape').setStringValue(newValue);
return true;
}
if (propertyName === 'shapeDimensionA') {
newValue = parseFloat(newValue);
if (newValue !== newValue) return false;
behaviorContent.getChild('shapeDimensionA').setDoubleValue(newValue);
const newValueAsNumber = parseFloat(newValue);
if (newValueAsNumber !== newValueAsNumber) return false;
behaviorContent
.getChild('shapeDimensionA')
.setDoubleValue(newValueAsNumber);
return true;
}
if (propertyName === 'shapeDimensionB') {
newValue = parseFloat(newValue);
if (newValue !== newValue) return false;
behaviorContent.getChild('shapeDimensionB').setDoubleValue(newValue);
const newValueAsNumber = parseFloat(newValue);
if (newValueAsNumber !== newValueAsNumber) return false;
behaviorContent
.getChild('shapeDimensionB')
.setDoubleValue(newValueAsNumber);
return true;
}
if (propertyName === 'shapeOffsetX') {
newValue = parseFloat(newValue);
if (newValue !== newValue) return false;
behaviorContent.getChild('shapeOffsetX').setDoubleValue(newValue);
const newValueAsNumber = parseFloat(newValue);
if (newValueAsNumber !== newValueAsNumber) return false;
behaviorContent
.getChild('shapeOffsetX')
.setDoubleValue(newValueAsNumber);
return true;
}
if (propertyName === 'shapeOffsetY') {
newValue = parseFloat(newValue);
if (newValue !== newValue) return false;
behaviorContent.getChild('shapeOffsetY').setDoubleValue(newValue);
const newValueAsNumber = parseFloat(newValue);
if (newValueAsNumber !== newValueAsNumber) return false;
behaviorContent
.getChild('shapeOffsetY')
.setDoubleValue(newValueAsNumber);
return true;
}
if (propertyName === 'polygonOrigin') {
behaviorContent.addChild('polygonOrigin').setStringValue(newValue);
return true;
}
if (propertyName === 'vertices') {
behaviorContent.addChild('vertices');
// $FlowFixMe
behaviorContent.setChild('vertices', gd.Serializer.fromJSON(newValue));
return true;
}
if (propertyName === 'density') {
behaviorContent
.getChild('density')
.setDoubleValue(parseFloat(newValue));
return true;
}
if (propertyName === 'friction') {
newValue = parseFloat(newValue);
if (newValue !== newValue) return false;
behaviorContent.getChild('friction').setDoubleValue(newValue);
const newValueAsNumber = parseFloat(newValue);
if (newValueAsNumber !== newValueAsNumber) return false;
behaviorContent.getChild('friction').setDoubleValue(newValueAsNumber);
return true;
}
if (propertyName === 'restitution') {
newValue = parseFloat(newValue);
if (newValue !== newValue) return false;
behaviorContent.getChild('restitution').setDoubleValue(newValue);
const newValueAsNumber = parseFloat(newValue);
if (newValueAsNumber !== newValueAsNumber) return false;
behaviorContent
.getChild('restitution')
.setDoubleValue(newValueAsNumber);
return true;
}
if (propertyName === 'linearDamping') {
newValue = parseFloat(newValue);
if (newValue !== newValue) return false;
behaviorContent.getChild('linearDamping').setDoubleValue(newValue);
const newValueAsNumber = parseFloat(newValue);
if (newValueAsNumber !== newValueAsNumber) return false;
behaviorContent
.getChild('linearDamping')
.setDoubleValue(newValueAsNumber);
return true;
}
if (propertyName === 'angularDamping') {
newValue = parseFloat(newValue);
if (newValue !== newValue) return false;
behaviorContent.getChild('angularDamping').setDoubleValue(newValue);
const newValueAsNumber = parseFloat(newValue);
if (newValueAsNumber !== newValueAsNumber) return false;
behaviorContent
.getChild('angularDamping')
.setDoubleValue(newValueAsNumber);
return true;
}
if (propertyName === 'gravityScale') {
newValue = parseFloat(newValue);
if (newValue !== newValue) return false;
behaviorContent.getChild('gravityScale').setDoubleValue(newValue);
const newValueAsNumber = parseFloat(newValue);
if (newValueAsNumber !== newValueAsNumber) return false;
behaviorContent
.getChild('gravityScale')
.setDoubleValue(newValueAsNumber);
return true;
}
if (propertyName === 'layers') {
behaviorContent.getChild('layers').setIntValue(parseInt(newValue, 10));
return true;
}
if (propertyName === 'masks') {
behaviorContent.getChild('masks').setIntValue(parseInt(newValue, 10));
return true;
}
return false;
};
// $FlowExpectedError - ignore Flow warning as we're creating a behavior
physics2Behavior.getProperties = function (behaviorContent) {
var behaviorProperties = new gd.MapStringPropertyDescriptor();
@@ -312,7 +337,6 @@ module.exports = {
return behaviorProperties;
};
// $FlowExpectedError - ignore Flow warning as we're creating a behavior
physics2Behavior.initializeContent = function (behaviorContent) {
behaviorContent.addChild('bodyType').setStringValue('Dynamic');
behaviorContent.addChild('bullet').setBoolValue(false);
@@ -336,40 +360,41 @@ module.exports = {
};
var sharedData = new gd.BehaviorSharedDataJsImplementation();
// $FlowExpectedError - ignore Flow warning as we're creating a behavior
sharedData.updateProperty = function (
sharedContent,
propertyName,
newValue
) {
if (propertyName === 'gravityX') {
newValue = parseFloat(newValue);
if (newValue !== newValue) return false;
sharedContent.getChild('gravityX').setDoubleValue(newValue);
const newValueAsNumber = parseFloat(newValue);
if (newValueAsNumber !== newValueAsNumber) return false;
sharedContent.getChild('gravityX').setDoubleValue(newValueAsNumber);
return true;
}
if (propertyName === 'gravityY') {
newValue = parseFloat(newValue);
if (newValue !== newValue) return false;
sharedContent.getChild('gravityY').setDoubleValue(newValue);
const newValueAsNumber = parseFloat(newValue);
if (newValueAsNumber !== newValueAsNumber) return false;
sharedContent.getChild('gravityY').setDoubleValue(newValueAsNumber);
return true;
}
if (propertyName === 'scaleX') {
newValue = parseInt(newValue, 10);
if (newValue !== newValue) return false;
sharedContent.getChild('scaleX').setDoubleValue(newValue);
const newValueAsNumber = parseInt(newValue, 10);
if (newValueAsNumber !== newValueAsNumber) return false;
sharedContent.getChild('scaleX').setDoubleValue(newValueAsNumber);
return true;
}
if (propertyName === 'scaleY') {
newValue = parseInt(newValue, 10);
if (newValue !== newValue) return false;
sharedContent.getChild('scaleY').setDoubleValue(newValue);
const newValueAsNumber = parseInt(newValue, 10);
if (newValueAsNumber !== newValueAsNumber) return false;
sharedContent.getChild('scaleY').setDoubleValue(newValueAsNumber);
return true;
}
return false;
};
// $FlowExpectedError - ignore Flow warning as we're creating a behavior
sharedData.getProperties = function (sharedContent) {
var sharedProperties = new gd.MapStringPropertyDescriptor();
@@ -402,7 +427,6 @@ module.exports = {
return sharedProperties;
};
// $FlowExpectedError - ignore Flow warning as we're creating a behavior
sharedData.initializeContent = function (behaviorContent) {
behaviorContent.addChild('gravityX').setDoubleValue(0);
behaviorContent.addChild('gravityY').setDoubleValue(9.8);
@@ -422,6 +446,7 @@ module.exports = {
'',
'res/physics32.png',
'Physics2Behavior',
//@ts-ignore The class hierarchy is incorrect leading to a type error, but this is valid.
physics2Behavior,
sharedData
)
@@ -775,10 +800,10 @@ module.exports = {
.setDefaultValue('true')
.getCodeExtraInformation()
.setFunctionName('setSleepingAllowed');
// Deprecated action (fixed typo):
aut
.addDuplicatedAction("SetSleepingaAllowed", "SetSleepingAllowed")
.addDuplicatedAction('SetSleepingaAllowed', 'SetSleepingAllowed')
.setHidden();
aut
@@ -1476,10 +1501,16 @@ module.exports = {
.addParameter('behavior', _('Behavior'), 'Physics2Behavior')
.addParameter('expression', _('X component (N)'))
.addParameter('expression', _('Y component (N)'))
.setParameterLongDescription(_('A force is like an acceleration but depends on the mass.'))
.setParameterLongDescription(
_('A force is like an acceleration but depends on the mass.')
)
.addParameter('expression', _('Application point on X axis'))
.addParameter('expression', _('Application point on Y axis'))
.setParameterLongDescription(_('Use `MassCenterX` and `MassCenterY` expressions to avoid any rotation.'))
.setParameterLongDescription(
_(
'Use `MassCenterX` and `MassCenterY` expressions to avoid any rotation.'
)
)
.getCodeExtraInformation()
.setFunctionName('applyForce');
@@ -1499,10 +1530,16 @@ module.exports = {
.addParameter('behavior', _('Behavior'), 'Physics2Behavior')
.addParameter('expression', _('Angle'))
.addParameter('expression', _('Length (N)'))
.setParameterLongDescription(_('A force is like an acceleration but depends on the mass.'))
.setParameterLongDescription(
_('A force is like an acceleration but depends on the mass.')
)
.addParameter('expression', _('Application point on X axis'))
.addParameter('expression', _('Application point on Y axis'))
.setParameterLongDescription(_('Use `MassCenterX` and `MassCenterY` expressions to avoid any rotation.'))
.setParameterLongDescription(
_(
'Use `MassCenterX` and `MassCenterY` expressions to avoid any rotation.'
)
)
.getCodeExtraInformation()
.setFunctionName('applyPolarForce');
@@ -1523,12 +1560,18 @@ module.exports = {
.addParameter('object', _('Object'), '', false)
.addParameter('behavior', _('Behavior'), 'Physics2Behavior')
.addParameter('expression', _('Length (N)'))
.setParameterLongDescription(_('A force is like an acceleration but depends on the mass.'))
.setParameterLongDescription(
_('A force is like an acceleration but depends on the mass.')
)
.addParameter('expression', _('X position'))
.addParameter('expression', _('Y position'))
.addParameter('expression', _('Application point on X axis'))
.addParameter('expression', _('Application point on Y axis'))
.setParameterLongDescription(_('Use `MassCenterX` and `MassCenterY` expressions to avoid any rotation.'))
.setParameterLongDescription(
_(
'Use `MassCenterX` and `MassCenterY` expressions to avoid any rotation.'
)
)
.getCodeExtraInformation()
.setFunctionName('applyForceTowardPosition');
@@ -1546,18 +1589,18 @@ module.exports = {
)
.addParameter('object', _('Object'), '', false)
.addParameter('behavior', _('Behavior'), 'Physics2Behavior')
.addParameter(
'expression',
_('X component (N·s or kg·m·s⁻¹)')
.addParameter('expression', _('X component (N·s or kg·m·s⁻¹)'))
.addParameter('expression', _('Y component (N·s or kg·m·s⁻¹)'))
.setParameterLongDescription(
_('An impulse is like a speed addition but depends on the mass.')
)
.addParameter(
'expression',
_('Y component (N·s or kg·m·s⁻¹)')
)
.setParameterLongDescription(_('An impulse is like a speed addition but depends on the mass.'))
.addParameter('expression', _('Application point on X axis'))
.addParameter('expression', _('Application point on Y axis'))
.setParameterLongDescription(_('Use `MassCenterX` and `MassCenterY` expressions to avoid any rotation.'))
.setParameterLongDescription(
_(
'Use `MassCenterX` and `MassCenterY` expressions to avoid any rotation.'
)
)
.getCodeExtraInformation()
.setFunctionName('applyImpulse');
@@ -1578,14 +1621,17 @@ module.exports = {
.addParameter('object', _('Object'), '', false)
.addParameter('behavior', _('Behavior'), 'Physics2Behavior')
.addParameter('expression', _('Angle'))
.addParameter(
'expression',
_('Length (N·s or kg·m·s⁻¹)')
.addParameter('expression', _('Length (N·s or kg·m·s⁻¹)'))
.setParameterLongDescription(
_('An impulse is like a speed addition but depends on the mass.')
)
.setParameterLongDescription(_('An impulse is like a speed addition but depends on the mass.'))
.addParameter('expression', _('Application point on X axis'))
.addParameter('expression', _('Application point on Y axis'))
.setParameterLongDescription(_('Use `MassCenterX` and `MassCenterY` expressions to avoid any rotation.'))
.setParameterLongDescription(
_(
'Use `MassCenterX` and `MassCenterY` expressions to avoid any rotation.'
)
)
.getCodeExtraInformation()
.setFunctionName('applyPolarImpulse');
@@ -1605,16 +1651,19 @@ module.exports = {
)
.addParameter('object', _('Object'), '', false)
.addParameter('behavior', _('Behavior'), 'Physics2Behavior')
.addParameter(
'expression',
_('Length (N·s or kg·m·s⁻¹)')
.addParameter('expression', _('Length (N·s or kg·m·s⁻¹)'))
.setParameterLongDescription(
_('An impulse is like a speed addition but depends on the mass.')
)
.setParameterLongDescription(_('An impulse is like a speed addition but depends on the mass.'))
.addParameter('expression', _('X position'))
.addParameter('expression', _('Y position'))
.addParameter('expression', _('Application point on X axis'))
.addParameter('expression', _('Application point on Y axis'))
.setParameterLongDescription(_('Use `MassCenterX` and `MassCenterY` expressions to avoid any rotation.'))
.setParameterLongDescription(
_(
'Use `MassCenterX` and `MassCenterY` expressions to avoid any rotation.'
)
)
.getCodeExtraInformation()
.setFunctionName('applyImpulseTowardPosition');
@@ -1633,7 +1682,9 @@ module.exports = {
.addParameter('object', _('Object'), '', false)
.addParameter('behavior', _('Behavior'), 'Physics2Behavior')
.addParameter('expression', _('Torque (N·m)'))
.setParameterLongDescription(_('A torque is like a rotation acceleration but depends on the mass.'))
.setParameterLongDescription(
_('A torque is like a rotation acceleration but depends on the mass.')
)
.getCodeExtraInformation()
.setFunctionName('applyTorque');
@@ -1652,7 +1703,11 @@ module.exports = {
.addParameter('object', _('Object'), '', false)
.addParameter('behavior', _('Behavior'), 'Physics2Behavior')
.addParameter('expression', _('Angular impulse (N·m·s'))
.setParameterLongDescription(_('An impulse is like a rotation speed addition but depends on the mass.'))
.setParameterLongDescription(
_(
'An impulse is like a rotation speed addition but depends on the mass.'
)
)
.getCodeExtraInformation()
.setFunctionName('applyAngularImpulse');
@@ -4061,10 +4116,7 @@ module.exports = {
return extension;
},
runExtensionSanityTests: function (
gd /*: libGDevelop */,
extension /*: gdPlatformExtension*/
) {
runExtensionSanityTests: function (gd, extension) {
const dummyBehavior = extension
.getBehaviorMetadata('Physics2::Physics2Behavior')
.get();

View File

@@ -1,4 +1,5 @@
// @flow
//@ts-check
/// <reference path="../JsExtensionTypes.d.ts" />
/**
* This is a declaration of an extension for GDevelop 5.
*
@@ -12,18 +13,9 @@
* More information on https://github.com/4ian/GDevelop/blob/master/newIDE/README-extensions.md
*/
/*::
// Import types to allow Flow to do static type checking on this file.
// Extensions declaration are typed using Flow (like the editor), but the files
// for the game engine are checked with TypeScript annotations.
import { type ObjectsRenderingService, type ObjectsEditorService } from '../JsExtensionTypes.flow.js'
*/
/** @type {ExtensionModule} */
module.exports = {
createExtension: function (
_ /*: (string) => string */,
gd /*: libGDevelop */
) {
createExtension: function (_, gd) {
const extension = new gd.PlatformExtension();
extension
.setExtensionInformation(
@@ -72,9 +64,7 @@ module.exports = {
.addAction(
'HideAuthenticationBanner',
_('Hide authentication banner'),
_(
'Hide the authentication banner from the top of the game screen.'
),
_('Hide the authentication banner from the top of the game screen.'),
_('Hide the authentication banner'),
'',
'JsPlatform/Extensions/authentication.svg',
@@ -226,10 +216,7 @@ module.exports = {
return extension;
},
runExtensionSanityTests: function (
gd /*: libGDevelop */,
extension /*: gdPlatformExtension*/
) {
runExtensionSanityTests: function (gd, extension) {
return [];
},
};

View File

@@ -124,6 +124,25 @@ void DeclarePrimitiveDrawingExtension(gd::PlatformExtension& extension) {
.AddParameter("expression", _("The height of the ellipse"))
.SetFunctionName("DrawEllipse");
obj.AddAction("FilletRectangle",
_("Fillet Rectangle"),
_("Draw a fillet rectangle on screen"),
_("Draw from _PARAM1_;_PARAM2_ to _PARAM3_;_PARAM4_ a fillet "
"rectangle (fillet: _PARAM5_)"
"with _PARAM0_"),
_("Drawing"),
"res/actions/filletRectangle24.png",
"res/actions/filletRectangle.png")
.AddParameter("object", _("Shape Painter object"), "Drawer")
.AddParameter("expression", _("Left X position"))
.AddParameter("expression", _("Top Y position"))
.AddParameter("expression", _("Right X position"))
.AddParameter("expression", _("Bottom Y position"))
.AddParameter("expression", _("Fillet (in pixels)"))
.SetFunctionName("DrawFilletRectangle");
obj.AddAction("RoundedRectangle",
_("Rounded rectangle"),
_("Draw a rounded rectangle on screen"),

View File

@@ -47,6 +47,11 @@ class PrimitiveDrawingJsExtension : public gd::PlatformExtension {
GetAllActionsForObject(
"PrimitiveDrawing::Drawer")["PrimitiveDrawing::Ellipse"]
.SetFunctionName("drawEllipse");
GetAllActionsForObject(
"PrimitiveDrawing::Drawer")["PrimitiveDrawing::FilletRectangle"]
.SetFunctionName("drawFilletRectangle");
GetAllActionsForObject(
"PrimitiveDrawing::Drawer")["PrimitiveDrawing::RoundedRectangle"]
.SetFunctionName("drawRoundedRectangle");

View File

@@ -136,6 +136,25 @@ namespace gdjs {
this.invalidateBounds();
}
drawFilletRectangle(
x1: float,
y1: float,
x2: float,
y2: float,
fillet: float
) {
this.updateOutline();
this._graphics.beginFill(
this._object._fillColor,
this._object._fillOpacity / 255
);
//@ts-ignore from @pixi/graphics-extras
this._graphics.drawFilletRect(x1, y1, x2 - x1, y2 - y1, fillet);
this._graphics.closePath();
this._graphics.endFill();
this.invalidateBounds();
}
drawChamferRectangle(
x1: float,
y1: float,

View File

@@ -210,6 +210,22 @@ namespace gdjs {
this._renderer.drawEllipse(centerX, centerY, width, height);
}
drawFilletRectangle(
startX1: float,
startY1: float,
endX2: float,
endY2: float,
fillet: float
) {
this._renderer.drawFilletRectangle(
startX1,
startY1,
endX2,
endY2,
fillet
);
}
drawRoundedRectangle(
startX1: float,
startY1: float,

View File

@@ -1,4 +1,5 @@
// @flow
//@ts-check
/// <reference path="../JsExtensionTypes.d.ts" />
/**
* This is a declaration of an extension for GDevelop 5.
*
@@ -12,18 +13,9 @@
* More information on https://github.com/4ian/GDevelop/blob/master/newIDE/README-extensions.md
*/
/*::
// Import types to allow Flow to do static type checking on this file.
// Extensions declaration are typed using Flow (like the editor), but the files
// for the game engine are checked with TypeScript annotations.
import { type ObjectsRenderingService, type ObjectsEditorService } from '../JsExtensionTypes.flow.js'
*/
/** @type {ExtensionModule} */
module.exports = {
createExtension: function (
_ /*: (string) => string */,
gd /*: libGDevelop */
) {
createExtension: function (_, gd) {
const extension = new gd.PlatformExtension();
extension
.setExtensionInformation(
@@ -59,10 +51,7 @@ module.exports = {
return extension;
},
runExtensionSanityTests: function (
gd /*: libGDevelop */,
extension /*: gdPlatformExtension*/
) {
runExtensionSanityTests: function (gd, extension) {
return [];
},
};

View File

@@ -1,4 +1,5 @@
// @flow
//@ts-check
/// <reference path="../JsExtensionTypes.d.ts" />
/**
* This is a declaration of an extension for GDevelop 5.
*
@@ -12,18 +13,9 @@
* More information on https://github.com/4ian/GDevelop/blob/master/newIDE/README-extensions.md
*/
/*::
// Import types to allow Flow to do static type checking on this file.
// Extensions declaration are typed using Flow (like the editor), but the files
// for the game engine are checked with TypeScript annotations.
import { type ObjectsRenderingService, type ObjectsEditorService } from '../JsExtensionTypes.flow.js'
*/
/** @type {ExtensionModule} */
module.exports = {
createExtension: function (
_ /*: (string) => string */,
gd /*: libGDevelop */
) {
createExtension: function (_, gd) {
const extension = new gd.PlatformExtension();
extension
.setExtensionInformation(
@@ -83,10 +75,7 @@ module.exports = {
return extension;
},
runExtensionSanityTests: function (
gd /*: libGDevelop */,
extension /*: gdPlatformExtension*/
) {
runExtensionSanityTests: function (gd, extension) {
return [];
},
};

View File

@@ -1,4 +1,5 @@
// @flow
// @ts-check
/// <reference path="../JsExtensionTypes.d.ts" />
/**
* This is a declaration of an extension for GDevelop 5.
*
@@ -12,18 +13,9 @@
* More information on https://github.com/4ian/GDevelop/blob/master/newIDE/README-extensions.md
*/
/*::
// Import types to allow Flow to do static type checking on this file.
// Extensions declaration are typed using Flow (like the editor), but the files
// for the game engine are checked with TypeScript annotations.
import { type ObjectsRenderingService, type ObjectsEditorService } from '../JsExtensionTypes.flow.js'
*/
/** @type {ExtensionModule} */
module.exports = {
createExtension: function (
_ /*: (string) => string */,
gd /*: libGDevelop */
) {
createExtension: function (_, gd) {
const extension = new gd.PlatformExtension();
extension
@@ -94,10 +86,7 @@ module.exports = {
* But it is recommended to create tests for the behaviors/objects properties you created
* to avoid mistakes.
*/
runExtensionSanityTests: function (
gd /*: libGDevelop */,
extension /*: gdPlatformExtension*/
) {
runExtensionSanityTests: function (gd, extension) {
return [];
},
/**
@@ -105,17 +94,13 @@ module.exports = {
*
* Run `node import-GDJS-Runtime.js` (in newIDE/app/scripts) if you make any change.
*/
registerEditorConfigurations: function (
objectsEditorService /*: ObjectsEditorService */
) {},
registerEditorConfigurations: function (objectsEditorService) {},
/**
* Register renderers for instance of objects on the scene editor.
*
* Run `node import-GDJS-Runtime.js` (in newIDE/app/scripts) if you make any change.
*/
registerInstanceRenderers: function (
objectsRenderingService /*: ObjectsRenderingService */
) {
registerInstanceRenderers: function (objectsRenderingService) {
const { PIXI, RenderedInstance, gd } = objectsRenderingService;
class RenderedSpineInstance extends RenderedInstance {
@@ -228,7 +213,6 @@ module.exports = {
const animation = configuration.getAnimation(index);
const source = animation.getSource();
const shouldLoop = animation.shouldLoop();
const scale = this.getScale();
// reset scale to track new animation range
// if custom size is set it will be reinitialized in update method

View File

@@ -1,4 +1,5 @@
// @flow
//@ts-check
/// <reference path="../JsExtensionTypes.d.ts" />
/**
* This is a declaration of an extension for GDevelop 5.
*
@@ -12,18 +13,9 @@
* More information on https://github.com/4ian/GDevelop/blob/master/newIDE/README-extensions.md
*/
/*::
// Import types to allow Flow to do static type checking on this file.
// Extensions declaration are typed using Flow (like the editor), but the files
// for the game engine are checked with TypeScript annotations.
import { type ObjectsRenderingService, type ObjectsEditorService } from '../JsExtensionTypes.flow.js'
*/
/** @type {ExtensionModule} */
module.exports = {
createExtension: function (
_ /*: (string) => string */,
gd /*: libGDevelop */
) {
createExtension: function (_, gd) {
const extension = new gd.PlatformExtension();
extension
.setExtensionInformation(
@@ -1243,10 +1235,7 @@ module.exports = {
return extension;
},
runExtensionSanityTests: function (
gd /*: libGDevelop */,
extension /*: gdPlatformExtension*/
) {
runExtensionSanityTests: function (gd, extension) {
return [];
},
};

View File

@@ -1,4 +1,5 @@
// @flow
//@ts-check
/// <reference path="../JsExtensionTypes.d.ts" />
/**
* This is a declaration of an extension for GDevelop 5.
*
@@ -12,18 +13,9 @@
* More information on https://github.com/4ian/GDevelop/blob/master/newIDE/README-extensions.md
*/
/*::
// Import types to allow Flow to do static type checking on this file.
// Extensions declaration are typed using Flow (like the editor), but the files
// for the game engine are checked with TypeScript annotations.
import { type ObjectsRenderingService, type ObjectsEditorService } from '../JsExtensionTypes.flow.js'
*/
/** @type {ExtensionModule} */
module.exports = {
createExtension: function (
_ /*: (string) => string */,
gd /*: libGDevelop */
) {
createExtension: function (_, gd) {
const extension = new gd.PlatformExtension();
extension
.setExtensionInformation(
@@ -39,7 +31,6 @@ module.exports = {
.setIcon('JsPlatform/Extensions/text_input.svg');
const textInputObject = new gd.ObjectJsImplementation();
// $FlowExpectedError - ignore Flow warning as we're creating an object
textInputObject.updateProperty = function (
objectContent,
propertyName,
@@ -94,7 +85,6 @@ module.exports = {
return false;
};
// $FlowExpectedError - ignore Flow warning as we're creating an object
textInputObject.getProperties = function (objectContent) {
const objectProperties = new gd.MapStringPropertyDescriptor();
@@ -232,7 +222,6 @@ module.exports = {
})
);
// $FlowExpectedError - ignore Flow warning as we're creating an object
textInputObject.updateInitialInstanceProperty = function (
objectContent,
instance,
@@ -251,7 +240,6 @@ module.exports = {
return false;
};
// $FlowExpectedError - ignore Flow warning as we're creating an object
textInputObject.getInitialInstanceProperties = function (
content,
instance,
@@ -288,7 +276,7 @@ module.exports = {
.addIncludeFile(
'Extensions/TextInput/textinputruntimeobject-pixi-renderer.js'
)
.addDefaultBehavior("TextContainerCapability::TextContainerBehavior")
.addDefaultBehavior('TextContainerCapability::TextContainerBehavior')
.addDefaultBehavior('ResizableCapability::ResizableBehavior')
.addDefaultBehavior('OpacityCapability::OpacityBehavior');
@@ -599,7 +587,9 @@ module.exports = {
.addScopedAction(
'Focus',
_('Focus'),
_('Focus the input so that text can be entered (like if it was touched/clicked).'),
_(
'Focus the input so that text can be entered (like if it was touched/clicked).'
),
_('Focus _PARAM0_'),
_(''),
'res/conditions/surObjet24.png',
@@ -621,10 +611,7 @@ module.exports = {
* But it is recommended to create tests for the behaviors/objects properties you created
* to avoid mistakes.
*/
runExtensionSanityTests: function (
gd /*: libGDevelop */,
extension /*: gdPlatformExtension*/
) {
runExtensionSanityTests: function (gd, extension) {
return [];
},
/**
@@ -632,9 +619,7 @@ module.exports = {
*
* Run `node import-GDJS-Runtime.js` (in newIDE/app/scripts) if you make any change.
*/
registerEditorConfigurations: function (
objectsEditorService /*: ObjectsEditorService */
) {
registerEditorConfigurations: function (objectsEditorService) {
objectsEditorService.registerEditorConfiguration(
'TextInput::TextInputObject',
objectsEditorService.getDefaultObjectJsImplementationPropertiesEditor({
@@ -647,9 +632,7 @@ module.exports = {
*
* Run `node import-GDJS-Runtime.js` (in newIDE/app/scripts) if you make any change.
*/
registerInstanceRenderers: function (
objectsRenderingService /*: ObjectsRenderingService */
) {
registerInstanceRenderers: function (objectsRenderingService) {
const RenderedInstance = objectsRenderingService.RenderedInstance;
const PIXI = objectsRenderingService.PIXI;

View File

@@ -40,38 +40,6 @@ void DeclareTextObjectExtension(gd::PlatformExtension& extension) {
.AddDefaultBehavior("ScalableCapability::ScalableBehavior")
.AddDefaultBehavior("OpacityCapability::OpacityBehavior");
// Deprecated
obj.AddAction("String",
_("Modify the text"),
_("Modify the text of a Text object."),
_("the text"),
"",
"res/actions/text24_black.png",
"res/actions/text_black.png")
.SetHidden()
.AddParameter("object", _("Object"), "Text")
.UseStandardOperatorParameters(
"string",
gd::ParameterOptions::MakeNewOptions().SetDescription(_("Text")))
.SetFunctionName("SetString")
.SetGetter("GetString");
// Deprecated
obj.AddCondition("String",
_("Compare the text"),
_("Compare the text of a Text object."),
_("the text"),
"",
"res/conditions/text24_black.png",
"res/conditions/text_black.png")
.SetHidden()
.AddParameter("object", _("Object"), "Text")
.UseStandardRelationalOperatorParameters(
"string",
gd::ParameterOptions::MakeNewOptions().SetDescription(
_("Text to compare to")))
.SetFunctionName("GetString");
obj.AddAction("Font",
_("Font"),
_("Change the font of the text."),
@@ -84,94 +52,6 @@ void DeclareTextObjectExtension(gd::PlatformExtension& extension) {
.AddParameter("police", _("Font"))
.SetFunctionName("ChangeFont");
// Deprecated
obj.AddCondition("ScaleX",
_("Scale on X axis"),
_("Compare the scale of the text on the X axis"),
_("the scale on the X axis"),
"Scale",
"res/conditions/scaleWidth24_black.png",
"res/conditions/scaleWidth_black.png")
.AddParameter("object", _("Object"), "Text")
.UseStandardRelationalOperatorParameters(
"number",
gd::ParameterOptions::MakeNewOptions().SetDescription(
_("Scale to compare to (1 by default)")))
.SetHidden()
.SetFunctionName("GetScaleX");
// Deprecated
obj.AddAction(
"ScaleX",
_("Scale on X axis"),
_("Modify the scale of the text on the X axis (default scale is 1)"),
_("the scale on the X axis"),
_("Scale"),
"res/actions/scaleWidth24_black.png",
"res/actions/scaleWidth_black.png")
.AddParameter("object", _("Object"), "Text")
.UseStandardOperatorParameters(
"number",
gd::ParameterOptions::MakeNewOptions().SetDescription(
_("Scale (1 by default)")))
.SetHidden()
.SetFunctionName("SetScaleX");
// Deprecated
obj.AddCondition("ScaleY",
_("Scale on Y axis"),
_("Compare the scale of the text on the Y axis"),
_("the scale on the Y axis"),
"Scale",
"res/conditions/scaleHeight24_black.png",
"res/conditions/scaleHeight_black.png")
.AddParameter("object", _("Object"), "Text")
.UseStandardRelationalOperatorParameters(
"number",
gd::ParameterOptions::MakeNewOptions().SetDescription(
_("Scale to compare to (1 by default)")))
.SetHidden()
.SetFunctionName("GetScaleY");
// Deprecated
obj.AddAction(
"ScaleY",
_("Scale on Y axis"),
_("Modify the scale of the text on the Y axis (default scale is 1)"),
_("the scale on the Y axis"),
_("Scale"),
"res/actions/scaleHeight24_black.png",
"res/actions/scaleHeight_black.png")
.AddParameter("object", _("Object"), "Text")
.UseStandardOperatorParameters(
"number",
gd::ParameterOptions::MakeNewOptions().SetDescription(
_("Scale (1 by default)")))
.SetHidden()
.SetFunctionName("SetScaleY");
// Deprecated
obj.AddAction(
"Scale",
_("Scale"),
_("Modify the scale of the specified object (default scale is 1)"),
_("the scale"),
_("Scale"),
"res/actions/scale24_black.png",
"res/actions/scale_black.png")
.AddParameter("object", _("Object"), "Text")
.UseStandardOperatorParameters(
"number",
gd::ParameterOptions::MakeNewOptions().SetDescription(
_("Scale (1 by default)")))
.SetHidden()
.SetFunctionName("SetScale");
obj.AddAction(
"ChangeColor",
_("Color"),
@@ -355,43 +235,6 @@ void DeclareTextObjectExtension(gd::PlatformExtension& extension) {
gd::ParameterOptions::MakeNewOptions().SetDescription(
_("Blur radius")));
// Deprecated
obj.AddAction("Opacity",
_("Text opacity"),
_("Change the opacity of a Text. 0 is fully transparent, 255 "
"is opaque (default)."),
_("the opacity"),
"",
"res/actions/opacity24.png",
"res/actions/opacity.png")
.AddParameter("object", _("Object"), "Text")
.UseStandardOperatorParameters(
"number",
gd::ParameterOptions::MakeNewOptions().SetDescription(
_("Opacity (0-255)")))
.SetFunctionName("SetOpacity")
.SetGetter("GetOpacity")
.SetHidden();
// Deprecated
obj.AddCondition("Opacity",
_("Opacity"),
_("Compare the opacity of a Text object, between 0 (fully "
"transparent) to 255 (opaque)."),
_("the opacity"),
"",
"res/conditions/opacity24.png",
"res/conditions/opacity.png")
.AddParameter("object", _("Object"), "Text")
.UseStandardRelationalOperatorParameters(
"number",
gd::ParameterOptions::MakeNewOptions().SetDescription(
_("Opacity to compare to (0-255)")))
.SetFunctionName("GetOpacity")
.SetHidden();
obj.AddAction("SetSmooth",
_("Smoothing"),
_("Activate or deactivate text smoothing."),
@@ -484,37 +327,6 @@ void DeclareTextObjectExtension(gd::PlatformExtension& extension) {
.AddParameter("object", _("Object"), "Text")
.SetFunctionName("IsUnderlined");
obj.AddAction("Angle",
_("Angle"),
_("Modify the angle of a Text object."),
_("the angle"),
_("Rotation"),
"res/actions/rotate24_black.png",
"res/actions/rotate_black.png")
.AddParameter("object", _("Object"), "Text")
.UseStandardOperatorParameters(
"number",
gd::ParameterOptions::MakeNewOptions().SetDescription(
_("Angle (in degrees)")))
.SetFunctionName("SetAngle")
.SetGetter("GetAngle");
obj.AddCondition("Angle",
_("Angle"),
_("Compare the value of the angle of a Text object."),
_("the angle"),
_("Rotation"),
"res/conditions/rotate24_black.png",
"res/conditions/rotate_black.png")
.AddParameter("object", _("Object"), "Text")
.UseStandardRelationalOperatorParameters(
"number",
gd::ParameterOptions::MakeNewOptions().SetDescription(
_("Angle to compare to (in degrees)")))
.SetFunctionName("GetAngle");
obj.AddCondition("Padding",
_("Padding"),
_("Compare the number of pixels around a text object. If "
@@ -628,6 +440,143 @@ void DeclareTextObjectExtension(gd::PlatformExtension& extension) {
"res/actions/textPadding_black.png")
.AddParameter("object", _("Object"), "Text");
obj.AddExpressionAndConditionAndAction("number",
"FontSize",
_("Font size"),
_("the font size of a text object"),
_("the font size"),
"",
"res/conditions/characterSize24.png")
.AddParameter("object", _("Object"), "Text")
.UseStandardParameters("number", gd::ParameterOptions::MakeNewOptions());
// Support for deprecated "Size" actions/conditions:
obj.AddDuplicatedAction("Size", "Text::SetFontSize").SetHidden();
obj.AddDuplicatedCondition("Size", "Text::FontSize").SetHidden();
// Deprecated
obj.AddAction("Angle",
_("Angle"),
_("Modify the angle of a Text object."),
_("the angle"),
_("Rotation"),
"res/actions/rotate24_black.png",
"res/actions/rotate_black.png")
.AddParameter("object", _("Object"), "Text")
.UseStandardOperatorParameters(
"number",
gd::ParameterOptions::MakeNewOptions().SetDescription(
_("Angle (in degrees)")))
.SetHidden()
.SetFunctionName("SetAngle")
.SetGetter("GetAngle");
// Deprecated
obj.AddCondition("Angle",
_("Angle"),
_("Compare the value of the angle of a Text object."),
_("the angle"),
_("Rotation"),
"res/conditions/rotate24_black.png",
"res/conditions/rotate_black.png")
.AddParameter("object", _("Object"), "Text")
.UseStandardRelationalOperatorParameters(
"number",
gd::ParameterOptions::MakeNewOptions().SetDescription(
_("Angle to compare to (in degrees)")))
.SetHidden()
.SetFunctionName("GetAngle");
// Deprecated
obj.AddCondition("ScaleX",
_("Scale on X axis"),
_("Compare the scale of the text on the X axis"),
_("the scale on the X axis"),
"Scale",
"res/conditions/scaleWidth24_black.png",
"res/conditions/scaleWidth_black.png")
.AddParameter("object", _("Object"), "Text")
.UseStandardRelationalOperatorParameters(
"number",
gd::ParameterOptions::MakeNewOptions().SetDescription(
_("Scale to compare to (1 by default)")))
.SetHidden()
.SetFunctionName("GetScaleX");
// Deprecated
obj.AddAction(
"ScaleX",
_("Scale on X axis"),
_("Modify the scale of the text on the X axis (default scale is 1)"),
_("the scale on the X axis"),
_("Scale"),
"res/actions/scaleWidth24_black.png",
"res/actions/scaleWidth_black.png")
.AddParameter("object", _("Object"), "Text")
.UseStandardOperatorParameters(
"number",
gd::ParameterOptions::MakeNewOptions().SetDescription(
_("Scale (1 by default)")))
.SetHidden()
.SetFunctionName("SetScaleX");
// Deprecated
obj.AddCondition("ScaleY",
_("Scale on Y axis"),
_("Compare the scale of the text on the Y axis"),
_("the scale on the Y axis"),
"Scale",
"res/conditions/scaleHeight24_black.png",
"res/conditions/scaleHeight_black.png")
.AddParameter("object", _("Object"), "Text")
.UseStandardRelationalOperatorParameters(
"number",
gd::ParameterOptions::MakeNewOptions().SetDescription(
_("Scale to compare to (1 by default)")))
.SetHidden()
.SetFunctionName("GetScaleY");
// Deprecated
obj.AddAction(
"ScaleY",
_("Scale on Y axis"),
_("Modify the scale of the text on the Y axis (default scale is 1)"),
_("the scale on the Y axis"),
_("Scale"),
"res/actions/scaleHeight24_black.png",
"res/actions/scaleHeight_black.png")
.AddParameter("object", _("Object"), "Text")
.UseStandardOperatorParameters(
"number",
gd::ParameterOptions::MakeNewOptions().SetDescription(
_("Scale (1 by default)")))
.SetHidden()
.SetFunctionName("SetScaleY");
// Deprecated
obj.AddAction(
"Scale",
_("Scale"),
_("Modify the scale of the specified object (default scale is 1)"),
_("the scale"),
_("Scale"),
"res/actions/scale24_black.png",
"res/actions/scale_black.png")
.AddParameter("object", _("Object"), "Text")
.UseStandardOperatorParameters(
"number",
gd::ParameterOptions::MakeNewOptions().SetDescription(
_("Scale (1 by default)")))
.SetHidden()
.SetFunctionName("SetScale");
// Deprecated
obj.AddExpression("ScaleX",
_("X Scale of a Text object"),
@@ -648,6 +597,43 @@ void DeclareTextObjectExtension(gd::PlatformExtension& extension) {
.SetHidden()
.SetFunctionName("GetScaleY");
// Deprecated
obj.AddAction("Opacity",
_("Text opacity"),
_("Change the opacity of a Text. 0 is fully transparent, 255 "
"is opaque (default)."),
_("the opacity"),
"",
"res/actions/opacity24.png",
"res/actions/opacity.png")
.AddParameter("object", _("Object"), "Text")
.UseStandardOperatorParameters(
"number",
gd::ParameterOptions::MakeNewOptions().SetDescription(
_("Opacity (0-255)")))
.SetFunctionName("SetOpacity")
.SetGetter("GetOpacity")
.SetHidden();
// Deprecated
obj.AddCondition("Opacity",
_("Opacity"),
_("Compare the opacity of a Text object, between 0 (fully "
"transparent) to 255 (opaque)."),
_("the opacity"),
"",
"res/conditions/opacity24.png",
"res/conditions/opacity.png")
.AddParameter("object", _("Object"), "Text")
.UseStandardRelationalOperatorParameters(
"number",
gd::ParameterOptions::MakeNewOptions().SetDescription(
_("Opacity to compare to (0-255)")))
.SetFunctionName("GetOpacity")
.SetHidden();
// Deprecated
obj.AddExpression("Opacity",
_("Opacity of a Text object"),
@@ -658,30 +644,52 @@ void DeclareTextObjectExtension(gd::PlatformExtension& extension) {
.SetFunctionName("GetOpacity")
.SetHidden();
// Deprecated
obj.AddExpression("Angle",
_("Angle"),
_("Angle"),
_("Rotation"),
"res/actions/rotate_black.png")
.AddParameter("object", _("Object"), "Text")
.SetHidden()
.SetFunctionName("GetAngle");
obj.AddExpressionAndConditionAndAction("number",
"FontSize",
_("Font size"),
_("the font size of a text object"),
_("the font size"),
"",
"res/conditions/characterSize24.png")
// Deprecated
obj.AddAction("String",
_("Modify the text"),
_("Modify the text of a Text object."),
_("the text"),
"",
"res/actions/text24_black.png",
"res/actions/text_black.png")
.SetHidden()
.AddParameter("object", _("Object"), "Text")
.UseStandardParameters("number", gd::ParameterOptions::MakeNewOptions());
.UseStandardOperatorParameters(
"string",
gd::ParameterOptions::MakeNewOptions().SetDescription(_("Text")))
.SetFunctionName("SetString")
.SetGetter("GetString");
// Support for deprecated "Size" actions/conditions:
obj.AddDuplicatedAction("Size", "Text::SetFontSize").SetHidden();
obj.AddDuplicatedCondition("Size", "Text::FontSize").SetHidden();
// Deprecated
obj.AddCondition("String",
_("Compare the text"),
_("Compare the text of a Text object."),
_("the text"),
"",
"res/conditions/text24_black.png",
"res/conditions/text_black.png")
.SetHidden()
.AddParameter("object", _("Object"), "Text")
.UseStandardRelationalOperatorParameters(
"string",
gd::ParameterOptions::MakeNewOptions().SetDescription(
_("Text to compare to")))
.SetFunctionName("GetString");
// Deprecated
obj.AddStrExpression(
"String", _("Text"), _("Text"), _("Text"), "res/texteicon.png")
.AddParameter("object", _("Object"), "Text")
.SetHidden()
.SetFunctionName("GetString");
}

View File

@@ -29,24 +29,6 @@ class TextObjectJsExtension : public gd::PlatformExtension {
.SetIncludeFile("Extensions/TextObject/textruntimeobject.js")
.AddIncludeFile(
"Extensions/TextObject/textruntimeobject-pixi-renderer.js");
GetAllActionsForObject("TextObject::Text")["TextObject::Scale"]
.SetFunctionName("setScale")
.SetGetter("getScaleMean");
GetAllActionsForObject("TextObject::Text")["TextObject::ScaleX"]
.SetFunctionName("setScaleX")
.SetGetter("getScaleX");
GetAllConditionsForObject("TextObject::Text")["TextObject::ScaleX"]
.SetFunctionName("getScaleX");
GetAllActionsForObject("TextObject::Text")["TextObject::ScaleY"]
.SetFunctionName("setScaleY")
.SetGetter("getScaleY");
GetAllConditionsForObject("TextObject::Text")["TextObject::ScaleY"]
.SetFunctionName("getScaleY");
GetAllActionsForObject("TextObject::Text")["TextObject::String"]
.SetFunctionName("setString")
.SetGetter("getString");
GetAllConditionsForObject("TextObject::Text")["TextObject::String"]
.SetFunctionName("getString");
GetAllActionsForObject("TextObject::Text")["TextObject::Text::SetFontSize"]
.SetFunctionName("setCharacterSize")
@@ -56,24 +38,6 @@ class TextObjectJsExtension : public gd::PlatformExtension {
GetAllExpressionsForObject("TextObject::Text")["FontSize"]
.SetFunctionName("getCharacterSize");
// Deprecated actions/conditions (use "FontSize"/"SetFontSize" instead):
GetAllActionsForObject("TextObject::Text")["TextObject::Size"]
.SetFunctionName("setCharacterSize")
.SetGetter("getCharacterSize");
GetAllConditionsForObject("TextObject::Text")["TextObject::Size"]
.SetFunctionName("getCharacterSize");
GetAllActionsForObject("TextObject::Text")["TextObject::Angle"]
.SetFunctionName("setAngle")
.SetGetter("getAngle");
GetAllConditionsForObject("TextObject::Text")["TextObject::Angle"]
.SetFunctionName("getAngle");
GetAllActionsForObject("TextObject::Text")["TextObject::Opacity"]
.SetFunctionName("setOpacity")
.SetGetter("getOpacity");
GetAllConditionsForObject("TextObject::Text")["TextObject::Opacity"]
.SetFunctionName("getOpacity");
GetAllActionsForObject("TextObject::Text")["TextObject::SetBold"]
.SetFunctionName("setBold");
GetAllConditionsForObject("TextObject::Text")["TextObject::IsBold"]
@@ -108,16 +72,6 @@ class TextObjectJsExtension : public gd::PlatformExtension {
GetAllExpressionsForObject("TextObject::Text")["Padding"]
.SetFunctionName("getPadding");
GetAllExpressionsForObject("TextObject::Text")["ScaleX"]
.SetFunctionName("getScaleX");
GetAllExpressionsForObject("TextObject::Text")["ScaleY"]
.SetFunctionName("getScaleY");
GetAllExpressionsForObject("TextObject::Text")["Opacity"]
.SetFunctionName("getOpacity");
GetAllExpressionsForObject("TextObject::Text")["Angle"]
.SetFunctionName("getAngle");
GetAllStrExpressionsForObject("TextObject::Text")["String"]
.SetFunctionName("getString");
GetAllActionsForObject("TextObject::Text")["TextObject::ChangeColor"]
.SetFunctionName("setColor");
@@ -125,15 +79,13 @@ class TextObjectJsExtension : public gd::PlatformExtension {
GetAllActionsForObject("TextObject::Text")["TextObject::SetGradient"]
.SetFunctionName("setGradient");
GetAllActionsForObject("TextObject::Text")["TextObject::SetOutline"]
.SetFunctionName("setOutline");
GetAllActionsForObject("TextObject::Text")["TextObject::Text::SetOutlineEnabled"]
.SetFunctionName("setOutlineEnabled");
GetAllConditionsForObject("TextObject::Text")["TextObject::Text::IsOutlineEnabled"]
.SetFunctionName("isOutlineEnabled");
GetAllActionsForObject("TextObject::Text")["TextObject::Text::SetOutlineColor"]
.SetFunctionName("setOutlineColor");
GetAllExpressionsForObject("TextObject::Text")["TextObject::Text::OutlineThickness"]
GetAllExpressionsForObject("TextObject::Text")["OutlineThickness"]
.SetFunctionName("getOutlineThickness");
GetAllConditionsForObject("TextObject::Text")["TextObject::Text::OutlineThickness"]
.SetFunctionName("getOutlineThickness");
@@ -141,8 +93,6 @@ class TextObjectJsExtension : public gd::PlatformExtension {
.SetFunctionName("setOutlineThickness")
.SetGetter("getOutlineThickness");
GetAllActionsForObject("TextObject::Text")["TextObject::SetShadow"]
.SetFunctionName("setShadow");
GetAllActionsForObject("TextObject::Text")["TextObject::ShowShadow"]
.SetFunctionName("showShadow");
GetAllConditionsForObject("TextObject::Text")["TextObject::Text::IsShadowEnabled"]
@@ -150,7 +100,7 @@ class TextObjectJsExtension : public gd::PlatformExtension {
GetAllActionsForObject("TextObject::Text")["TextObject::Text::SetShadowColor"]
.SetFunctionName("setShadowColor");
GetAllExpressionsForObject("TextObject::Text")["TextObject::Text::ShadowOpacity"]
GetAllExpressionsForObject("TextObject::Text")["ShadowOpacity"]
.SetFunctionName("getShadowOpacity");
GetAllConditionsForObject("TextObject::Text")["TextObject::Text::ShadowOpacity"]
.SetFunctionName("getShadowOpacity");
@@ -158,7 +108,7 @@ class TextObjectJsExtension : public gd::PlatformExtension {
.SetFunctionName("setShadowOpacity")
.SetGetter("getShadowOpacity");
GetAllExpressionsForObject("TextObject::Text")["TextObject::Text::ShadowDistance"]
GetAllExpressionsForObject("TextObject::Text")["ShadowDistance"]
.SetFunctionName("getShadowDistance");
GetAllConditionsForObject("TextObject::Text")["TextObject::Text::ShadowDistance"]
.SetFunctionName("getShadowDistance");
@@ -166,7 +116,7 @@ class TextObjectJsExtension : public gd::PlatformExtension {
.SetFunctionName("setShadowDistance")
.SetGetter("getShadowDistance");
GetAllExpressionsForObject("TextObject::Text")["TextObject::Text::ShadowAngle"]
GetAllExpressionsForObject("TextObject::Text")["ShadowAngle"]
.SetFunctionName("getShadowAngle");
GetAllConditionsForObject("TextObject::Text")["TextObject::Text::ShadowAngle"]
.SetFunctionName("getShadowAngle");
@@ -174,7 +124,7 @@ class TextObjectJsExtension : public gd::PlatformExtension {
.SetFunctionName("setShadowAngle")
.SetGetter("getShadowAngle");
GetAllExpressionsForObject("TextObject::Text")["TextObject::Text::ShadowBlurRadius"]
GetAllExpressionsForObject("TextObject::Text")["ShadowBlurRadius"]
.SetFunctionName("getShadowBlurRadius");
GetAllConditionsForObject("TextObject::Text")["TextObject::Text::ShadowBlurRadius"]
.SetFunctionName("getShadowBlurRadius");
@@ -182,6 +132,61 @@ class TextObjectJsExtension : public gd::PlatformExtension {
.SetFunctionName("setShadowBlurRadius")
.SetGetter("getShadowBlurRadius");
// Deprecated actions/conditions (use "FontSize"/"SetFontSize" instead):
GetAllActionsForObject("TextObject::Text")["TextObject::Size"]
.SetFunctionName("setCharacterSize")
.SetGetter("getCharacterSize");
GetAllConditionsForObject("TextObject::Text")["TextObject::Size"]
.SetFunctionName("getCharacterSize");
// Deprecated: now available for all objects.
GetAllActionsForObject("TextObject::Text")["TextObject::Angle"]
.SetFunctionName("setAngle")
.SetGetter("getAngle");
GetAllConditionsForObject("TextObject::Text")["TextObject::Angle"]
.SetFunctionName("getAngle");
GetAllExpressionsForObject("TextObject::Text")["Angle"]
.SetFunctionName("getAngle");
// Deprecated: available through capabilities.
GetAllActionsForObject("TextObject::Text")["TextObject::Scale"]
.SetFunctionName("setScale")
.SetGetter("getScaleMean");
GetAllActionsForObject("TextObject::Text")["TextObject::ScaleX"]
.SetFunctionName("setScaleX")
.SetGetter("getScaleX");
GetAllConditionsForObject("TextObject::Text")["TextObject::ScaleX"]
.SetFunctionName("getScaleX");
GetAllActionsForObject("TextObject::Text")["TextObject::ScaleY"]
.SetFunctionName("setScaleY")
.SetGetter("getScaleY");
GetAllConditionsForObject("TextObject::Text")["TextObject::ScaleY"]
.SetFunctionName("getScaleY");
GetAllExpressionsForObject("TextObject::Text")["ScaleX"]
.SetFunctionName("getScaleX");
GetAllExpressionsForObject("TextObject::Text")["ScaleY"]
.SetFunctionName("getScaleY");
GetAllActionsForObject("TextObject::Text")["TextObject::String"]
.SetFunctionName("setString")
.SetGetter("getString");
GetAllStrExpressionsForObject("TextObject::Text")["String"]
.SetFunctionName("getString");
GetAllConditionsForObject("TextObject::Text")["TextObject::String"]
.SetFunctionName("getString");
GetAllExpressionsForObject("TextObject::Text")["Opacity"]
.SetFunctionName("getOpacity");
GetAllActionsForObject("TextObject::Text")["TextObject::Opacity"]
.SetFunctionName("setOpacity")
.SetGetter("getOpacity");
GetAllConditionsForObject("TextObject::Text")["TextObject::Opacity"]
.SetFunctionName("getOpacity");
// Deprecated: split into several instructions.
GetAllActionsForObject("TextObject::Text")["TextObject::SetOutline"]
.SetFunctionName("setOutline");
GetAllActionsForObject("TextObject::Text")["TextObject::SetShadow"]
.SetFunctionName("setShadow");
// Unimplemented actions and conditions:
GetAllActionsForObject("TextObject::Text")["TextObject::Font"]
.SetFunctionName("");

View File

@@ -56,7 +56,8 @@ namespace gdjs {
opacity: float = 255;
_textAlign: string = 'left';
_wrapping: boolean = false;
_wrappingWidth: float = 1;
// A wrapping of 1 makes games crash on Firefox
_wrappingWidth: float = 100;
_isOutlineEnabled: boolean;
_outlineThickness: float;
@@ -194,8 +195,8 @@ namespace gdjs {
*/
extraInitializationFromInitialInstance(initialInstanceData: InstanceData) {
if (initialInstanceData.customSize) {
this.setWrapping(true);
this.setWrappingWidth(initialInstanceData.width);
this.setWrapping(true);
} else {
this.setWrapping(false);
}
@@ -513,11 +514,15 @@ namespace gdjs {
if (width <= 1) {
width = 1;
}
if (this._wrappingWidth === width) return;
if (this._wrappingWidth === width) {
return;
}
this._wrappingWidth = width;
this._renderer.updateStyle();
this.invalidateHitboxes();
if (this._wrapping) {
this._renderer.updateStyle();
this.invalidateHitboxes();
}
}
/**

View File

@@ -1,5 +1,5 @@
// @flow
//@ts-check
/// <reference path="../JsExtensionTypes.d.ts" />
/// <reference path="helper/TileMapHelper.d.ts" />
/**
@@ -15,20 +15,13 @@
* More information on https://github.com/4ian/GDevelop/blob/master/newIDE/README-extensions.md
*/
/*::
// Import types to allow Flow to do static type checking on this file.
// Extensions declaration are typed using Flow (like the editor), but the files
// for the game engine are checked with TypeScript annotations.
import { type ObjectsRenderingService, type ObjectsEditorService } from '../JsExtensionTypes.flow.js'
*/
const defineTileMap = function (
extension,
_ /*: (string) => string */,
gd /*: libGDevelop */
) {
/**
* @param {gd.PlatformExtension} extension
* @param {(translationSource: string) => string} _
* @param {GDNamespace} gd
*/
const defineTileMap = function (extension, _, gd) {
var objectTileMap = new gd.ObjectJsImplementation();
// $FlowExpectedError - ignore Flow warning as we're creating an object
objectTileMap.updateProperty = function (
objectContent,
propertyName,
@@ -69,7 +62,6 @@ const defineTileMap = function (
return false;
};
// $FlowExpectedError - ignore Flow warning as we're creating an object
objectTileMap.getProperties = function (objectContent) {
var objectProperties = new gd.MapStringPropertyDescriptor();
@@ -168,7 +160,6 @@ const defineTileMap = function (
})
);
// $FlowExpectedError - ignore Flow warning as we're creating an object
objectTileMap.updateInitialInstanceProperty = function (
objectContent,
instance,
@@ -179,7 +170,6 @@ const defineTileMap = function (
) {
return false;
};
// $FlowExpectedError - ignore Flow warning as we're creating an object
objectTileMap.getInitialInstanceProperties = function (
content,
instance,
@@ -608,13 +598,13 @@ const defineTileMap = function (
.setFunctionName('setHeight');
};
const defineCollisionMask = function (
extension,
_ /*: (string) => string */,
gd /*: libGDevelop */
) {
/**
* @param {gd.PlatformExtension} extension
* @param {(translationSource: string) => string} _
* @param {GDNamespace} gd
*/
const defineCollisionMask = function (extension, _, gd) {
var collisionMaskObject = new gd.ObjectJsImplementation();
// $FlowExpectedError - ignore Flow warning as we're creating an object
collisionMaskObject.updateProperty = function (
objectContent,
propertyName,
@@ -659,7 +649,6 @@ const defineCollisionMask = function (
return false;
};
// $FlowExpectedError - ignore Flow warning as we're creating an object
collisionMaskObject.getProperties = function (objectContent) {
var objectProperties = new gd.MapStringPropertyDescriptor();
@@ -768,7 +757,6 @@ const defineCollisionMask = function (
})
);
// $FlowExpectedError - ignore Flow warning as we're creating an object
collisionMaskObject.updateInitialInstanceProperty = function (
objectContent,
instance,
@@ -779,7 +767,6 @@ const defineCollisionMask = function (
) {
return false;
};
// $FlowExpectedError - ignore Flow warning as we're creating an object
collisionMaskObject.getInitialInstanceProperties = function (
content,
instance,
@@ -1033,6 +1020,7 @@ const defineCollisionMask = function (
.setFunctionName('setHeight');
};
/** @type {ExtensionModule} */
module.exports = {
createExtension: function (
_ /*: (string) => string */,
@@ -1093,10 +1081,7 @@ module.exports = {
* But it is recommended to create tests for the behaviors/objects properties you created
* to avoid mistakes.
*/
runExtensionSanityTests: function (
gd /*: libGDevelop */,
extension /*: gdPlatformExtension*/
) {
runExtensionSanityTests: function (gd, extension) {
return [];
},
/**
@@ -1104,9 +1089,7 @@ module.exports = {
*
* Run `node import-GDJS-Runtime.js` (in newIDE/app/scripts) if you make any change.
*/
registerEditorConfigurations: function (
objectsEditorService /*: ObjectsEditorService */
) {
registerEditorConfigurations: function (objectsEditorService) {
objectsEditorService.registerEditorConfiguration(
'TileMap::TileMap',
objectsEditorService.getDefaultObjectJsImplementationPropertiesEditor({
@@ -1125,9 +1108,7 @@ module.exports = {
*
* Run `node import-GDJS-Runtime.js` (in newIDE/app/scripts) if you make any change.
*/
registerInstanceRenderers: function (
objectsRenderingService /*: ObjectsRenderingService */
) {
registerInstanceRenderers: function (objectsRenderingService) {
const RenderedInstance = objectsRenderingService.RenderedInstance;
const PIXI = objectsRenderingService.PIXI;
@@ -1238,33 +1219,33 @@ module.exports = {
updateTileMap() {
// Get the tileset resource to use
const tilemapAtlasImage = this._associatedObjectConfiguration
.getProperties(this.project)
.getProperties()
.get('tilemapAtlasImage')
.getValue();
const tilemapJsonFile = this._associatedObjectConfiguration
.getProperties(this.project)
.getProperties()
.get('tilemapJsonFile')
.getValue();
const tilesetJsonFile = this._associatedObjectConfiguration
.getProperties(this.project)
.getProperties()
.get('tilesetJsonFile')
.getValue();
const layerIndex = parseInt(
this._associatedObjectConfiguration
.getProperties(this.project)
.getProperties()
.get('layerIndex')
.getValue(),
10
);
const levelIndex = parseInt(
this._associatedObjectConfiguration
.getProperties(this.project)
.getProperties()
.get('levelIndex')
.getValue(),
10
);
const displayMode = this._associatedObjectConfiguration
.getProperties(this.project)
.getProperties()
.get('displayMode')
.getValue();
@@ -1306,7 +1287,7 @@ module.exports = {
}
/** @type {TileMapHelper.TileTextureCache} */
const textureCache = manager.getOrLoadTextureCache(
manager.getOrLoadTextureCache(
this._loadTileMapWithCallback.bind(this),
(textureName) =>
this._pixiResourcesLoader.getPIXITexture(
@@ -1357,14 +1338,14 @@ module.exports = {
async _loadTileMap(tilemapJsonFile, tilesetJsonFile) {
try {
const tileMapJsonData =
await this._pixiResourcesLoader.getResourceJsonData(
this._project,
tilemapJsonFile
);
const tileMapJsonData = await this._pixiResourcesLoader.getResourceJsonData(
this._project,
tilemapJsonFile
);
const tileMap =
TilemapHelper.TileMapManager.identify(tileMapJsonData);
const tileMap = TilemapHelper.TileMapManager.identify(
tileMapJsonData
);
if (tileMap.kind === 'tiled') {
const tilesetJsonData = tilesetJsonFile
@@ -1521,43 +1502,45 @@ module.exports = {
* This is used to reload the Tilemap
*/
updateTileMap() {
// Get the tileset resource to use
// This might become useful in the future
/*
const tilemapAtlasImage = this._associatedObjectConfiguration
.getProperties(this.project)
.get('tilemapAtlasImage')
.getValue();
*/
const tilemapJsonFile = this._associatedObjectConfiguration
.getProperties(this.project)
.getProperties()
.get('tilemapJsonFile')
.getValue();
const tilesetJsonFile = this._associatedObjectConfiguration
.getProperties(this.project)
.getProperties()
.get('tilesetJsonFile')
.getValue();
const collisionMaskTag = this._associatedObjectConfiguration
.getProperties(this.project)
.getProperties()
.get('collisionMaskTag')
.getValue();
const outlineColor = objectsRenderingService.rgbOrHexToHexNumber(
this._associatedObjectConfiguration
.getProperties(this.project)
.getProperties()
.get('outlineColor')
.getValue()
);
const fillColor = objectsRenderingService.rgbOrHexToHexNumber(
this._associatedObjectConfiguration
.getProperties(this.project)
.getProperties()
.get('fillColor')
.getValue()
);
const outlineOpacity =
this._associatedObjectConfiguration
.getProperties(this.project)
+this._associatedObjectConfiguration
.getProperties()
.get('outlineOpacity')
.getValue() / 255;
const fillOpacity =
this._associatedObjectConfiguration
.getProperties(this.project)
+this._associatedObjectConfiguration
.getProperties()
.get('fillOpacity')
.getValue() / 255;
const outlineSize = 1;
@@ -1601,14 +1584,14 @@ module.exports = {
async _loadTileMap(tilemapJsonFile, tilesetJsonFile) {
try {
const tileMapJsonData =
await this._pixiResourcesLoader.getResourceJsonData(
this._project,
tilemapJsonFile
);
const tileMapJsonData = await this._pixiResourcesLoader.getResourceJsonData(
this._project,
tilemapJsonFile
);
const tileMap =
TilemapHelper.TileMapManager.identify(tileMapJsonData);
const tileMap = TilemapHelper.TileMapManager.identify(
tileMapJsonData
);
if (tileMap.kind === 'tiled') {
const tilesetJsonData = tilesetJsonFile

View File

@@ -1,5 +1,5 @@
declare namespace PIXI {
namespace tilemap {
export namespace tilemap {
/**
* The renderer plugin for canvas. It isn't registered by default.
*

View File

@@ -1,4 +1,5 @@
// @flow
//@ts-check
/// <reference path="../JsExtensionTypes.d.ts" />
/**
* This is a declaration of an extension for GDevelop 5.
*
@@ -12,13 +13,6 @@
* More information on https://github.com/4ian/GDevelop/blob/master/newIDE/README-extensions.md
*/
/*::
// Import types to allow Flow to do static type checking on this file.
// Extensions declaration are typed using Flow (like the editor), but the files
// for the game engine are checked with TypeScript annotations.
import { type ObjectsRenderingService, type ObjectsEditorService } from '../JsExtensionTypes.flow.js'
*/
const easingChoices = JSON.stringify([
'linear',
'easeInQuad',
@@ -57,11 +51,9 @@ const easingChoices = JSON.stringify([
'easeTo',
]);
/** @type {ExtensionModule} */
module.exports = {
createExtension: function (
_ /*: (string) => string */,
gd /*: libGDevelop */
) {
createExtension: function (_, gd) {
const extension = new gd.PlatformExtension();
extension
.setExtensionInformation(
@@ -387,57 +379,61 @@ module.exports = {
.addIncludeFile('Extensions/TweenBehavior/tweentools.js')
.setFunctionName('gdjs.evtTools.tween.tweenCameraRotation2');
extension
.addAction(
'TweenNumberEffectPropertyTween',
_('Tween number effect property'),
_('Tweens a number effect property from its current value to a new one.'),
_(
'Tween the property _PARAM5_ for effect _PARAM4_ of _PARAM3_ to _PARAM2_ with easing _PARAM6_ over _PARAM7_ seconds as _PARAM1_'
),
_('Scene Tweens'),
'JsPlatform/Extensions/tween_behavior24.png',
'JsPlatform/Extensions/tween_behavior32.png'
)
.addCodeOnlyParameter('currentScene', '')
.addParameter('identifier', _('Tween Identifier'), 'sceneTween')
.addParameter('expression', _('To value'), '', false)
.addParameter('layer', _('Layer'), '', true)
.addParameter("layerEffectName", _("Effect name"))
.addParameter("layerEffectParameterName", _("Property name"))
.addParameter('stringWithSelector', _('Easing'), easingChoices, false)
.setDefaultValue('linear')
.addParameter('expression', _('Duration (in seconds)'), '', false)
.getCodeExtraInformation()
.setIncludeFile('Extensions/TweenBehavior/TweenManager.js')
.addIncludeFile('Extensions/TweenBehavior/tweentools.js')
.setFunctionName('gdjs.evtTools.tween.tweenNumberEffectPropertyTween');
extension
.addAction(
'TweenColorEffectPropertyTween',
_('Tween color effect property'),
_('Tweens a color effect property from its current value to a new one.'),
_(
'Tween the color property _PARAM5_ for effect _PARAM4_ of _PARAM3_ to _PARAM2_ with easing _PARAM6_ over _PARAM7_ seconds as _PARAM1_'
),
_('Scene Tweens'),
'JsPlatform/Extensions/tween_behavior24.png',
'JsPlatform/Extensions/tween_behavior32.png'
)
.addCodeOnlyParameter('currentScene', '')
.addParameter('identifier', _('Tween Identifier'), 'sceneTween')
.addParameter('color', _('To color'), '', false)
.addParameter('layer', _('Layer'), '', true)
.addParameter("layerEffectName", _("Effect name"))
.addParameter("layerEffectParameterName", _("Property name"))
.addParameter('stringWithSelector', _('Easing'), easingChoices, false)
.setDefaultValue('linear')
.addParameter('expression', _('Duration (in seconds)'), '', false)
.getCodeExtraInformation()
.setIncludeFile('Extensions/TweenBehavior/TweenManager.js')
.addIncludeFile('Extensions/TweenBehavior/tweentools.js')
.setFunctionName('gdjs.evtTools.tween.tweenColorEffectPropertyTween');
extension
.addAction(
'TweenNumberEffectPropertyTween',
_('Tween number effect property'),
_(
'Tweens a number effect property from its current value to a new one.'
),
_(
'Tween the property _PARAM5_ for effect _PARAM4_ of _PARAM3_ to _PARAM2_ with easing _PARAM6_ over _PARAM7_ seconds as _PARAM1_'
),
_('Scene Tweens'),
'JsPlatform/Extensions/tween_behavior24.png',
'JsPlatform/Extensions/tween_behavior32.png'
)
.addCodeOnlyParameter('currentScene', '')
.addParameter('identifier', _('Tween Identifier'), 'sceneTween')
.addParameter('expression', _('To value'), '', false)
.addParameter('layer', _('Layer'), '', true)
.addParameter('layerEffectName', _('Effect name'))
.addParameter('layerEffectParameterName', _('Property name'))
.addParameter('stringWithSelector', _('Easing'), easingChoices, false)
.setDefaultValue('linear')
.addParameter('expression', _('Duration (in seconds)'), '', false)
.getCodeExtraInformation()
.setIncludeFile('Extensions/TweenBehavior/TweenManager.js')
.addIncludeFile('Extensions/TweenBehavior/tweentools.js')
.setFunctionName('gdjs.evtTools.tween.tweenNumberEffectPropertyTween');
extension
.addAction(
'TweenColorEffectPropertyTween',
_('Tween color effect property'),
_(
'Tweens a color effect property from its current value to a new one.'
),
_(
'Tween the color property _PARAM5_ for effect _PARAM4_ of _PARAM3_ to _PARAM2_ with easing _PARAM6_ over _PARAM7_ seconds as _PARAM1_'
),
_('Scene Tweens'),
'JsPlatform/Extensions/tween_behavior24.png',
'JsPlatform/Extensions/tween_behavior32.png'
)
.addCodeOnlyParameter('currentScene', '')
.addParameter('identifier', _('Tween Identifier'), 'sceneTween')
.addParameter('color', _('To color'), '', false)
.addParameter('layer', _('Layer'), '', true)
.addParameter('layerEffectName', _('Effect name'))
.addParameter('layerEffectParameterName', _('Property name'))
.addParameter('stringWithSelector', _('Easing'), easingChoices, false)
.setDefaultValue('linear')
.addParameter('expression', _('Duration (in seconds)'), '', false)
.getCodeExtraInformation()
.setIncludeFile('Extensions/TweenBehavior/TweenManager.js')
.addIncludeFile('Extensions/TweenBehavior/tweentools.js')
.setFunctionName('gdjs.evtTools.tween.tweenColorEffectPropertyTween');
extension
.addCondition(
@@ -597,7 +593,6 @@ module.exports = {
const tweenBehavior = new gd.BehaviorJsImplementation();
// $FlowExpectedError - ignore Flow warning as we're creating a behavior
tweenBehavior.updateProperty = function (
behaviorContent,
propertyName,
@@ -606,13 +601,11 @@ module.exports = {
return false;
};
// $FlowExpectedError - ignore Flow warning as we're creating a behavior
tweenBehavior.getProperties = function (behaviorContent) {
var behaviorProperties = new gd.MapStringPropertyDescriptor();
return behaviorProperties;
};
// $FlowExpectedError - ignore Flow warning as we're creating a behavior
tweenBehavior.initializeContent = function (behaviorContent) {};
const behavior = extension
@@ -626,6 +619,7 @@ module.exports = {
'',
'JsPlatform/Extensions/tween_behavior32.png',
'TweenBehavior',
// @ts-ignore - TODO: Fix tweenBehavior being an BehaviorJsImplementation instead of an Behavior
tweenBehavior,
new gd.BehaviorsSharedData()
)
@@ -926,37 +920,37 @@ module.exports = {
.getCodeExtraInformation()
.setFunctionName('addObjectPositionZTween');
behavior
.addAction(
'AddObjectPositionZTween2',
_('Tween object Z position'),
_(
'Tweens an object Z position (3D objects only) from its current Z position to a new one.'
),
_(
'Tween the Z position of _PARAM0_ to _PARAM4_ with easing _PARAM5_ over _PARAM6_ seconds as _PARAM3_'
),
_('Position'),
'JsPlatform/Extensions/tween_behavior24.png',
'JsPlatform/Extensions/tween_behavior32.png'
)
.addParameter('object', _('Object'), '', false)
.addParameter('behavior', _('Behavior'), 'TweenBehavior', false)
.addParameter("behavior", _("3D capability"), "Scene3D::Base3DBehavior")
.addParameter('identifier', _('Tween Identifier'), 'objectTween')
.addParameter('expression', _('To Z'), '', false)
.addParameter('stringWithSelector', _('Easing'), easingChoices, false)
.setDefaultValue('linear')
.addParameter('expression', _('Duration (in seconds)'), '', false)
.addParameter(
'yesorno',
_('Destroy this object when tween finishes'),
'',
false
)
.setDefaultValue('no')
.getCodeExtraInformation()
.setFunctionName('addObjectPositionZTween2');
behavior
.addAction(
'AddObjectPositionZTween2',
_('Tween object Z position'),
_(
'Tweens an object Z position (3D objects only) from its current Z position to a new one.'
),
_(
'Tween the Z position of _PARAM0_ to _PARAM4_ with easing _PARAM5_ over _PARAM6_ seconds as _PARAM3_'
),
_('Position'),
'JsPlatform/Extensions/tween_behavior24.png',
'JsPlatform/Extensions/tween_behavior32.png'
)
.addParameter('object', _('Object'), '', false)
.addParameter('behavior', _('Behavior'), 'TweenBehavior', false)
.addParameter('behavior', _('3D capability'), 'Scene3D::Base3DBehavior')
.addParameter('identifier', _('Tween Identifier'), 'objectTween')
.addParameter('expression', _('To Z'), '', false)
.addParameter('stringWithSelector', _('Easing'), easingChoices, false)
.setDefaultValue('linear')
.addParameter('expression', _('Duration (in seconds)'), '', false)
.addParameter(
'yesorno',
_('Destroy this object when tween finishes'),
'',
false
)
.setDefaultValue('no')
.getCodeExtraInformation()
.setFunctionName('addObjectPositionZTween2');
// deprecated
behavior
@@ -1111,37 +1105,37 @@ module.exports = {
.getCodeExtraInformation()
.setFunctionName('addObjectDepthTween');
behavior
.addAction(
'AddObjectDepthTween2',
_('Tween object depth'),
_(
'Tweens an object depth (suitable 3D objects only) from its current depth to a new one.'
),
_(
'Tween the depth of _PARAM0_ to _PARAM4_ with easing _PARAM5_ over _PARAM6_ seconds as _PARAM3_'
),
_('Size'),
'JsPlatform/Extensions/tween_behavior24.png',
'JsPlatform/Extensions/tween_behavior32.png'
)
.addParameter('object', _('Object'), '', false)
.addParameter('behavior', _('Behavior'), 'TweenBehavior', false)
.addParameter("behavior", _("3D capability"), "Scene3D::Base3DBehavior")
.addParameter('identifier', _('Tween Identifier'), 'objectTween')
.addParameter('expression', _('To depth'), '', false)
.addParameter('stringWithSelector', _('Easing'), easingChoices, false)
.setDefaultValue('linear')
.addParameter('expression', _('Duration (in seconds)'), '', false)
.addParameter(
'yesorno',
_('Destroy this object when tween finishes'),
'',
false
)
.setDefaultValue('no')
.getCodeExtraInformation()
.setFunctionName('addObjectDepthTween2');
behavior
.addAction(
'AddObjectDepthTween2',
_('Tween object depth'),
_(
'Tweens an object depth (suitable 3D objects only) from its current depth to a new one.'
),
_(
'Tween the depth of _PARAM0_ to _PARAM4_ with easing _PARAM5_ over _PARAM6_ seconds as _PARAM3_'
),
_('Size'),
'JsPlatform/Extensions/tween_behavior24.png',
'JsPlatform/Extensions/tween_behavior32.png'
)
.addParameter('object', _('Object'), '', false)
.addParameter('behavior', _('Behavior'), 'TweenBehavior', false)
.addParameter('behavior', _('3D capability'), 'Scene3D::Base3DBehavior')
.addParameter('identifier', _('Tween Identifier'), 'objectTween')
.addParameter('expression', _('To depth'), '', false)
.addParameter('stringWithSelector', _('Easing'), easingChoices, false)
.setDefaultValue('linear')
.addParameter('expression', _('Duration (in seconds)'), '', false)
.addParameter(
'yesorno',
_('Destroy this object when tween finishes'),
'',
false
)
.setDefaultValue('no')
.getCodeExtraInformation()
.setFunctionName('addObjectDepthTween2');
// deprecated
behavior
@@ -1267,65 +1261,69 @@ module.exports = {
.getCodeExtraInformation()
.setFunctionName('addObjectAngleTween2');
behavior
.addScopedAction(
'AddObjectRotationXTween',
_('Tween object rotation on X axis'),
_('Tweens an object rotation on X axis from its current angle to a new one.'),
_(
'Tween the rotation on X axis of _PARAM0_ to _PARAM4_° with easing _PARAM5_ over _PARAM6_ seconds as _PARAM3_'
),
_('Angle'),
'JsPlatform/Extensions/tween_behavior24.png',
'JsPlatform/Extensions/tween_behavior32.png'
)
.addParameter('object', _('Object'), '', false)
.addParameter('behavior', _('Behavior'), 'TweenBehavior', false)
.addParameter("behavior", _("3D capability"), "Scene3D::Base3DBehavior")
.addParameter('identifier', _('Tween Identifier'), 'objectTween')
.addParameter('expression', _('To angle (in degrees)'), '', false)
.addParameter('stringWithSelector', _('Easing'), easingChoices, false)
.setDefaultValue('linear')
.addParameter('expression', _('Duration (in seconds)'), '', false)
.addParameter(
'yesorno',
_('Destroy this object when tween finishes'),
'',
false
)
.setDefaultValue('no')
.getCodeExtraInformation()
.setFunctionName('addObjectRotationXTween');
behavior
.addScopedAction(
'AddObjectRotationXTween',
_('Tween object rotation on X axis'),
_(
'Tweens an object rotation on X axis from its current angle to a new one.'
),
_(
'Tween the rotation on X axis of _PARAM0_ to _PARAM4_° with easing _PARAM5_ over _PARAM6_ seconds as _PARAM3_'
),
_('Angle'),
'JsPlatform/Extensions/tween_behavior24.png',
'JsPlatform/Extensions/tween_behavior32.png'
)
.addParameter('object', _('Object'), '', false)
.addParameter('behavior', _('Behavior'), 'TweenBehavior', false)
.addParameter('behavior', _('3D capability'), 'Scene3D::Base3DBehavior')
.addParameter('identifier', _('Tween Identifier'), 'objectTween')
.addParameter('expression', _('To angle (in degrees)'), '', false)
.addParameter('stringWithSelector', _('Easing'), easingChoices, false)
.setDefaultValue('linear')
.addParameter('expression', _('Duration (in seconds)'), '', false)
.addParameter(
'yesorno',
_('Destroy this object when tween finishes'),
'',
false
)
.setDefaultValue('no')
.getCodeExtraInformation()
.setFunctionName('addObjectRotationXTween');
behavior
.addScopedAction(
'AddObjectRotationYTween',
_('Tween object rotation on Y axis'),
_('Tweens an object rotation on Y axis from its current angle to a new one.'),
_(
'Tween the rotation on Y axis of _PARAM0_ to _PARAM4_° with easing _PARAM5_ over _PARAM6_ seconds as _PARAM3_'
),
_('Angle'),
'JsPlatform/Extensions/tween_behavior24.png',
'JsPlatform/Extensions/tween_behavior32.png'
)
.addParameter('object', _('Object'), '', false)
.addParameter('behavior', _('Behavior'), 'TweenBehavior', false)
.addParameter("behavior", _("3D capability"), "Scene3D::Base3DBehavior")
.addParameter('identifier', _('Tween Identifier'), 'objectTween')
.addParameter('expression', _('To angle (in degrees)'), '', false)
.addParameter('stringWithSelector', _('Easing'), easingChoices, false)
.setDefaultValue('linear')
.addParameter('expression', _('Duration (in seconds)'), '', false)
.addParameter(
'yesorno',
_('Destroy this object when tween finishes'),
'',
false
)
.setDefaultValue('no')
.getCodeExtraInformation()
.setFunctionName('addObjectRotationYTween');
behavior
.addScopedAction(
'AddObjectRotationYTween',
_('Tween object rotation on Y axis'),
_(
'Tweens an object rotation on Y axis from its current angle to a new one.'
),
_(
'Tween the rotation on Y axis of _PARAM0_ to _PARAM4_° with easing _PARAM5_ over _PARAM6_ seconds as _PARAM3_'
),
_('Angle'),
'JsPlatform/Extensions/tween_behavior24.png',
'JsPlatform/Extensions/tween_behavior32.png'
)
.addParameter('object', _('Object'), '', false)
.addParameter('behavior', _('Behavior'), 'TweenBehavior', false)
.addParameter('behavior', _('3D capability'), 'Scene3D::Base3DBehavior')
.addParameter('identifier', _('Tween Identifier'), 'objectTween')
.addParameter('expression', _('To angle (in degrees)'), '', false)
.addParameter('stringWithSelector', _('Easing'), easingChoices, false)
.setDefaultValue('linear')
.addParameter('expression', _('Duration (in seconds)'), '', false)
.addParameter(
'yesorno',
_('Destroy this object when tween finishes'),
'',
false
)
.setDefaultValue('no')
.getCodeExtraInformation()
.setFunctionName('addObjectRotationYTween');
// deprecated
behavior
@@ -1700,7 +1698,9 @@ module.exports = {
.addScopedAction(
'AddNumberEffectPropertyTween',
_('Tween number effect property'),
_('Tweens a number effect property from its current value to a new one.'),
_(
'Tweens a number effect property from its current value to a new one.'
),
_(
'Tween the property _PARAM6_ for effect _PARAM5_ of _PARAM0_ to _PARAM4_ with easing _PARAM7_ over _PARAM8_ seconds as _PARAM3_'
),
@@ -1710,11 +1710,15 @@ module.exports = {
)
.addParameter('object', _('Object'), '', false)
.addParameter('behavior', _('Behavior'), 'TweenBehavior', false)
.addParameter("behavior", _("Effect capability"), "EffectCapability::EffectBehavior")
.addParameter(
'behavior',
_('Effect capability'),
'EffectCapability::EffectBehavior'
)
.addParameter('identifier', _('Tween Identifier'), 'objectTween')
.addParameter('expression', _('To value'), '', false)
.addParameter("objectEffectName", _("Effect name"))
.addParameter("objectEffectParameterName", _("Property name"))
.addParameter('objectEffectName', _('Effect name'))
.addParameter('objectEffectParameterName', _('Property name'))
.addParameter('stringWithSelector', _('Easing'), easingChoices, false)
.setDefaultValue('linear')
.addParameter('expression', _('Duration (in seconds)'), '', false)
@@ -1732,7 +1736,9 @@ module.exports = {
.addScopedAction(
'AddColorEffectPropertyTween',
_('Tween color effect property'),
_('Tweens a color effect property from its current value to a new one.'),
_(
'Tweens a color effect property from its current value to a new one.'
),
_(
'Tween the color property _PARAM6_ for effect _PARAM5_ of _PARAM0_ to _PARAM4_ with easing _PARAM7_ over _PARAM8_ seconds as _PARAM3_'
),
@@ -1742,11 +1748,15 @@ module.exports = {
)
.addParameter('object', _('Object'), '', false)
.addParameter('behavior', _('Behavior'), 'TweenBehavior', false)
.addParameter("behavior", _("Effect capability"), "EffectCapability::EffectBehavior")
.addParameter(
'behavior',
_('Effect capability'),
'EffectCapability::EffectBehavior'
)
.addParameter('identifier', _('Tween Identifier'), 'objectTween')
.addParameter('color', _('To color'), '', false)
.addParameter("objectEffectName", _("Effect name"))
.addParameter("objectEffectParameterName", _("Property name"))
.addParameter('objectEffectName', _('Effect name'))
.addParameter('objectEffectParameterName', _('Property name'))
.addParameter('stringWithSelector', _('Easing'), easingChoices, false)
.setDefaultValue('linear')
.addParameter('expression', _('Duration (in seconds)'), '', false)
@@ -1758,7 +1768,7 @@ module.exports = {
)
.setDefaultValue('no')
.getCodeExtraInformation()
.setFunctionName('addNumberEffectPropertyTween');
.setFunctionName('addColorEffectPropertyTween');
// deprecated
behavior
@@ -2088,10 +2098,7 @@ module.exports = {
return extension;
},
runExtensionSanityTests: function (
gd /*: libGDevelop */,
extension /*: gdPlatformExtension*/
) {
runExtensionSanityTests: function (gd, extension) {
return [];
},
};

View File

@@ -1,4 +1,6 @@
// @flow
//@ts-check
/// <reference path="../JsExtensionTypes.d.ts" />
/**
* This is a declaration of an extension for GDevelop 5.
*
@@ -12,34 +14,27 @@
* More information on https://github.com/4ian/GDevelop/blob/master/newIDE/README-extensions.md
*/
/*::
// Import types to allow Flow to do static type checking on this file.
// Extensions declaration are typed using Flow (like the editor), but the files
// for the game engine are checked with TypeScript annotations.
import { type ObjectsRenderingService, type ObjectsEditorService } from '../JsExtensionTypes.flow.js'
*/
/** @type {ExtensionModule} */
module.exports = {
createExtension: function (
_ /*: (string) => string */,
gd /*: libGDevelop */
) {
createExtension: function (_, gd) {
const extension = new gd.PlatformExtension();
extension
.setExtensionInformation(
'Video',
_('Video'),
_('Provides an object to display a video on the scene. The recommended file format is MPEG4, with H264 video codec and AAC audio codec, to maximize the support of the video on different platform and browsers.'),
_(
'Provides an object to display a video on the scene. The recommended file format is MPEG4, with H264 video codec and AAC audio codec, to maximize the support of the video on different platform and browsers.'
),
'Aurélien Vivet',
'Open source (MIT License)'
)
.setCategory('User interface')
.setExtensionHelpPath('/objects/video');
extension.addInstructionOrExpressionGroupMetadata(_("Video"))
.setIcon("JsPlatform/Extensions/videoicon16.png");
extension
.addInstructionOrExpressionGroupMetadata(_('Video'))
.setIcon('JsPlatform/Extensions/videoicon16.png');
var videoObject = new gd.ObjectJsImplementation();
// $FlowExpectedError - ignore Flow warning as we're creating an object
videoObject.updateProperty = function (
objectContent,
propertyName,
@@ -64,7 +59,6 @@ module.exports = {
return false;
};
// $FlowExpectedError - ignore Flow warning as we're creating an object
videoObject.getProperties = function (objectContent) {
var objectProperties = new gd.MapStringPropertyDescriptor();
@@ -104,7 +98,6 @@ module.exports = {
})
);
// $FlowExpectedError - ignore Flow warning as we're creating an object
videoObject.updateInitialInstanceProperty = function (
objectContent,
instance,
@@ -115,7 +108,6 @@ module.exports = {
) {
return false;
};
// $FlowExpectedError - ignore Flow warning as we're creating an object
videoObject.getInitialInstanceProperties = function (
content,
instance,
@@ -132,13 +124,14 @@ module.exports = {
_('Video'),
_('Displays a video.'),
'JsPlatform/Extensions/videoicon32.png',
// @ts-ignore - TODO: Fix videoObject being an ObjectJsImplementation instead of an ObjectConfiguration
videoObject
)
.setIncludeFile('Extensions/Video/videoruntimeobject.js')
.addIncludeFile('Extensions/Video/videoruntimeobject-pixi-renderer.js')
.setCategoryFullName(_('User interface'))
.addDefaultBehavior('EffectCapability::EffectBehavior')
.addDefaultBehavior("OpacityCapability::OpacityBehavior");
.addDefaultBehavior('OpacityCapability::OpacityBehavior');
object
.addAction(
@@ -533,10 +526,7 @@ module.exports = {
* But it is recommended to create tests for the behaviors/objects properties you created
* to avoid mistakes.
*/
runExtensionSanityTests: function (
gd /*: libGDevelop */,
extension /*: gdPlatformExtension*/
) {
runExtensionSanityTests: function (gd, extension) {
return [];
},
/**
@@ -545,9 +535,7 @@ module.exports = {
* Run `node import-GDJS-Runtime.js` (in newIDE/app/scripts) if you make any change.
*/
registerEditorConfigurations: function (
objectsEditorService /*: ObjectsEditorService */
) {
registerEditorConfigurations: function (objectsEditorService) {
objectsEditorService.registerEditorConfiguration(
'Video::VideoObject',
objectsEditorService.getDefaultObjectJsImplementationPropertiesEditor({
@@ -560,9 +548,7 @@ module.exports = {
*
* Run `node import-GDJS-Runtime.js` (in newIDE/app/scripts) if you make any change.
*/
registerInstanceRenderers: function (
objectsRenderingService /*: ObjectsRenderingService */
) {
registerInstanceRenderers: function (objectsRenderingService) {
const RenderedInstance = objectsRenderingService.RenderedInstance;
const PIXI = objectsRenderingService.PIXI;
@@ -570,7 +556,7 @@ module.exports = {
* Renderer for instances of VideoObject inside the IDE.
*/
class RenderedVideoObjectInstance extends RenderedInstance {
constructor (
constructor(
project,
layout,
instance,
@@ -606,11 +592,7 @@ module.exports = {
/**
* Return the path to the thumbnail of the specified object.
*/
static getThumbnail(
project,
resourcesLoader,
objectConfiguration
) {
static getThumbnail(project, resourcesLoader, objectConfiguration) {
return 'JsPlatform/Extensions/videoicon24.png';
}
@@ -647,14 +629,13 @@ module.exports = {
that._pixiObject.texture.on('error', function () {
that._pixiObject.texture.off('error', this);
that._pixiObject.texture =
that._pixiResourcesLoader.getInvalidPIXITexture();
that._pixiObject.texture = that._pixiResourcesLoader.getInvalidPIXITexture();
});
}
}
// Update opacity
const opacity = this._associatedObjectConfiguration
const opacity = +this._associatedObjectConfiguration
.getProperties()
.get('Opacity')
.getValue();

View File

@@ -7,7 +7,11 @@
#include "GDCore/CommonTools.h"
#include "GDCore/Events/Tools/EventsCodeNameMangler.h"
#include "GDCore/Extensions/Metadata/MultipleInstructionMetadata.h"
#include "GDCore/Extensions/Metadata/MetadataProvider.h"
#include "GDCore/Extensions/Metadata/ObjectMetadata.h"
#include "GDCore/Extensions/PlatformExtension.h"
#include "GDCore/IDE/Project/ArbitraryObjectsWorker.h"
#include "GDCore/IDE/WholeProjectBrowser.h"
#include "GDCore/Project/CustomBehavior.h"
#include "GDCore/Project/CustomBehaviorsSharedData.h"
#include "GDCore/Project/EventsBasedObject.h"
@@ -125,8 +129,6 @@ gd::ObjectMetadata &MetadataDeclarationHelper::DeclareObjectMetadata(
// Note: EventsFunctionsExtension should be used instead of
// PlatformExtension but this line will be removed soon.
.SetCategoryFullName(extension.GetCategory())
// Update Project::CreateObject when default behaviors are added.
.AddDefaultBehavior("EffectCapability::EffectBehavior")
.AddDefaultBehavior("ResizableCapability::ResizableBehavior")
.AddDefaultBehavior("ScalableCapability::ScalableBehavior")
.AddDefaultBehavior("FlippableCapability::FlippableBehavior");
@@ -136,8 +138,13 @@ gd::ObjectMetadata &MetadataDeclarationHelper::DeclareObjectMetadata(
.AddDefaultBehavior("Scene3D::Base3DBehavior");
}
else {
objectMetadata.AddDefaultBehavior("EffectCapability::EffectBehavior");
objectMetadata.AddDefaultBehavior("OpacityCapability::OpacityBehavior");
}
if (eventsBasedObject.IsTextContainer()) {
objectMetadata
.AddDefaultBehavior("TextContainerCapability::TextContainerBehavior");
}
// TODO EBO Use full type to identify object to avoid collision.
// Objects are identified by their name alone.
@@ -1510,7 +1517,7 @@ gd::BehaviorMetadata &MetadataDeclarationHelper::GenerateBehaviorMetadata(
}
gd::ObjectMetadata &MetadataDeclarationHelper::GenerateObjectMetadata(
const gd::Project &project, gd::PlatformExtension &extension,
gd::Project &project, gd::PlatformExtension &extension,
const gd::EventsFunctionsExtension &eventsFunctionsExtension,
const gd::EventsBasedObject &eventsBasedObject,
std::map<gd::String, gd::String> &objectMethodMangledNames) {
@@ -1545,7 +1552,58 @@ gd::ObjectMetadata &MetadataDeclarationHelper::GenerateObjectMetadata(
instructionOrExpression.SetPrivate();
}
UpdateCustomObjectDefaultBehaviors(project, objectMetadata);
return objectMetadata;
}
class DefaultBehaviorUpdater : public gd::ArbitraryObjectsWorker {
public:
DefaultBehaviorUpdater(const gd::Project &project_,
const gd::ObjectMetadata &objectMetadata_)
: project(project_), objectMetadata(objectMetadata_){};
virtual ~DefaultBehaviorUpdater(){};
private:
void DoVisitObject(gd::Object &object) override {
if (object.GetType() != objectMetadata.GetName()) {
return;
}
auto &defaultBehaviorTypes = objectMetadata.GetDefaultBehaviors();
for (const gd::String &behaviorName : object.GetAllBehaviorNames()) {
const auto &behavior = object.GetBehavior(behaviorName);
if (behavior.IsDefaultBehavior()) {
object.RemoveBehavior(behaviorName);
}
}
auto &platform = project.GetCurrentPlatform();
for (const gd::String &behaviorType : defaultBehaviorTypes) {
auto &behaviorMetadata =
gd::MetadataProvider::GetBehaviorMetadata(platform, behaviorType);
if (MetadataProvider::IsBadBehaviorMetadata(behaviorMetadata)) {
gd::LogWarning("Object: " + object.GetType() +
" has an unknown default behavior: " + behaviorType);
continue;
}
const gd::String &behaviorName = behaviorMetadata.GetDefaultName();
auto *behavior =
object.AddNewBehavior(project, behaviorType, behaviorName);
behavior->SetDefaultBehavior(true);
}
}
const gd::Project &project;
const gd::ObjectMetadata &objectMetadata;
};
void MetadataDeclarationHelper::UpdateCustomObjectDefaultBehaviors(
gd::Project &project, const gd::ObjectMetadata &objectMetadata) {
gd::WholeProjectBrowser projectBrowser;
auto defaultBehaviorUpdater = DefaultBehaviorUpdater(project, objectMetadata);
projectBrowser.ExposeObjects(project, defaultBehaviorUpdater);
}
} // namespace gdjs

View File

@@ -61,7 +61,7 @@ public:
std::map<gd::String, gd::String> &behaviorMethodMangledNames);
static gd::ObjectMetadata &GenerateObjectMetadata(
const gd::Project &project, gd::PlatformExtension &extension,
gd::Project &project, gd::PlatformExtension &extension,
const gd::EventsFunctionsExtension &eventsFunctionsExtension,
const gd::EventsBasedObject &eventsBasedObject,
std::map<gd::String, gd::String> &objectMethodMangledNames);
@@ -313,6 +313,10 @@ private:
gd::MultipleInstructionMetadata &multipleInstructionMetadata,
const int userDefinedFirstParameterIndex);
static void
UpdateCustomObjectDefaultBehaviors(gd::Project &project,
const gd::ObjectMetadata &objectMetadata);
static gd::String RemoveTrailingDot(const gd::String &description);
static gd::String

View File

@@ -109,6 +109,19 @@ gd::String ObjectCodeGenerator::GenerateRuntimeObjectCompleteCode(
}
return updateFromObjectCode;
},
// generateTextContainerCode
[&]() {
return gd::String(R"jscode_template(
// gdjs.TextContainer interface implementation
_text = '';
getText() {
return this._text;
}
setText(text) {
this._text = text;
}
)jscode_template");
});
}
@@ -119,7 +132,8 @@ gd::String ObjectCodeGenerator::GenerateRuntimeObjectTemplateCode(
std::function<gd::String()> generateInitializePropertiesCode,
std::function<gd::String()> generatePropertiesCode,
std::function<gd::String()> generateMethodsCode,
std::function<gd::String()> generateUpdateFromObjectDataCode) {
std::function<gd::String()> generateUpdateFromObjectDataCode,
std::function<gd::String()> generateTextContainerCode) {
return gd::String(R"jscode_template(
CODE_NAMESPACE = CODE_NAMESPACE || {};
@@ -149,6 +163,8 @@ CODE_NAMESPACE.RUNTIME_OBJECT_CLASSNAME = class RUNTIME_OBJECT_CLASSNAME extends
// Properties:
PROPERTIES_CODE
TEXT_CONTAINER_CODE
}
// Methods:
@@ -168,6 +184,7 @@ gdjs.registerObject("EXTENSION_NAME::OBJECT_NAME", CODE_NAMESPACE.RUNTIME_OBJECT
generateInitializePropertiesCode())
.FindAndReplace("UPDATE_FROM_OBJECT_DATA_CODE", generateUpdateFromObjectDataCode())
.FindAndReplace("PROPERTIES_CODE", generatePropertiesCode())
.FindAndReplace("TEXT_CONTAINER_CODE", eventsBasedObject.IsTextContainer() ? generateTextContainerCode() : "")
.FindAndReplace("METHODS_CODE", generateMethodsCode());
;
}

View File

@@ -74,7 +74,8 @@ class ObjectCodeGenerator {
std::function<gd::String()> generateInitializePropertiesCode,
std::function<gd::String()> generateMethodsCode,
std::function<gd::String()> generatePropertiesCode,
std::function<gd::String()> generateUpdateFromObjectDataCode);
std::function<gd::String()> generateUpdateFromObjectDataCode,
std::function<gd::String()> generateTextContainerCode);
gd::String GenerateRuntimeObjectPropertyTemplateCode(
const gd::EventsBasedObject& eventsBasedObject,

View File

@@ -18,7 +18,7 @@ namespace gdjs {
}
/**
* A behavior that forwards the Animatable interface to its object.
* A behavior that forwards the TextContainer interface to its object.
*/
export class TextContainerBehavior
extends gdjs.RuntimeBehavior

View File

@@ -29,8 +29,8 @@
"check-types": "tsc",
"build": "node scripts/build.js",
"test": "cd tests && npm run test-benchmark",
"format": "prettier --write \"Runtime/**/*.ts\" \"../Extensions/**/*.ts\" \"../Extensions/**/*.spec.js\"",
"check-format": "prettier --list-different \"Runtime/**/*.ts\" \"../Extensions/**/*.ts\" \"../Extensions/**/*.spec.js\"",
"format": "prettier --write \"Runtime/**/*.ts\" \"../Extensions/**/*.ts\" \"../Extensions/**/JsExtension.js\" \"../Extensions/**/*.spec.js\"",
"check-format": "prettier --list-different \"Runtime/**/*.ts\" \"../Extensions/**/*.ts\" \"../Extensions/**/JsExtension.js\" \"../Extensions/**/*.spec.js\"",
"generate-doc": "typedoc --options docs/typedoc.json"
}
}

View File

@@ -1386,8 +1386,8 @@ interface ParameterOptions {
interface AbstractFunctionMetadata {
[Ref] AbstractFunctionMetadata AddParameter([Const] DOMString type,
[Const] DOMString description,
[Const] DOMString optionalObjectType,
boolean parameterIsOptional);
[Const] optional DOMString optionalObjectType,
optional boolean parameterIsOptional);
[Ref] AbstractFunctionMetadata AddCodeOnlyParameter(
[Const] DOMString type, [Const] DOMString supplementaryInformation);
[Ref] AbstractFunctionMetadata SetDefaultValue([Const] DOMString defaultValue);
@@ -1437,8 +1437,8 @@ interface InstructionMetadata {
[Ref] InstructionMetadata SetRelevantForCustomObjectEventsOnly();
[Ref] InstructionMetadata AddParameter([Const] DOMString type,
[Const] DOMString description,
[Const] DOMString optionalObjectType,
boolean parameterIsOptional);
[Const] optional DOMString optionalObjectType,
optional boolean parameterIsOptional);
[Ref] InstructionMetadata AddCodeOnlyParameter(
[Const] DOMString type, [Const] DOMString supplementaryInformation);
[Ref] InstructionMetadata SetDefaultValue([Const] DOMString defaultValue);
@@ -1502,8 +1502,8 @@ interface ExpressionMetadata {
[Ref] ExpressionMetadata AddParameter(
[Const] DOMString type,
[Const] DOMString description,
[Const] DOMString optionalObjectType,
boolean parameterIsOptional);
[Const] optional DOMString optionalObjectType,
optional boolean parameterIsOptional);
[Ref] ExpressionMetadata AddCodeOnlyParameter(
[Const] DOMString type, [Const] DOMString supplementaryInformation);
[Ref] ExpressionMetadata SetDefaultValue([Const] DOMString defaultValue);
@@ -1524,8 +1524,8 @@ ExpressionMetadata implements AbstractFunctionMetadata;
interface MultipleInstructionMetadata {
[Ref] MultipleInstructionMetadata AddParameter([Const] DOMString type,
[Const] DOMString description,
[Const] DOMString optionalObjectType,
boolean parameterIsOptional);
[Const] optional DOMString optionalObjectType,
optional boolean parameterIsOptional);
[Ref] MultipleInstructionMetadata AddCodeOnlyParameter(
[Const] DOMString type, [Const] DOMString supplementaryInformation);
[Ref] MultipleInstructionMetadata SetDefaultValue([Const] DOMString defaultValue);
@@ -2790,6 +2790,8 @@ interface EventsBasedObject {
[Ref] EventsBasedObject MarkAsRenderedIn3D(boolean isRenderedIn3D);
boolean IsRenderedIn3D();
[Ref] EventsBasedObject MarkAsTextContainer(boolean isTextContainer);
boolean IsTextContainer();
[Const, Value] DOMString STATIC_GetPropertyActionName([Const] DOMString propertyName);
[Const, Value] DOMString STATIC_GetPropertyConditionName([Const] DOMString propertyName);
@@ -3608,7 +3610,7 @@ interface MetadataDeclarationHelper {
[Ref] MapStringString behaviorMethodMangledNames);
[Ref] ObjectMetadata STATIC_GenerateObjectMetadata(
[Const, Ref] Project project,
[Ref] Project project,
[Ref] PlatformExtension extension,
[Const, Ref] EventsFunctionsExtension eventsFunctionsExtension,
[Const, Ref] EventsBasedObject eventsBasedObject,

View File

@@ -81,6 +81,7 @@ target_link_libraries(GD "-s MODULARIZE=1")
target_link_libraries(GD "-s EXPORT_NAME=\"initializeGDevelopJs\"") # Global function name for browsers
target_link_libraries(GD "-s TOTAL_MEMORY=48MB") # Get some initial memory size that is a bit bigger than the default.
target_link_libraries(GD "-s ALLOW_MEMORY_GROWTH=1")
target_link_libraries(GD "-s NODEJS_CATCH_EXIT=0") # Don't print the entire GDCore code on error when running in node
target_link_libraries(GD "-s ERROR_ON_UNDEFINED_SYMBOLS=0")
target_link_libraries(GD "-s \"EXPORTED_FUNCTIONS=['_free']\"")

View File

@@ -1022,7 +1022,7 @@ describe('MetadataDeclarationHelper', () => {
},
});
it('can create metadata for custom object default instructions and expressions', () => {
it('can create metadata for custom object default capabilities', () => {
const extension = new gd.PlatformExtension();
const project = new gd.Project();
@@ -1048,11 +1048,22 @@ describe('MetadataDeclarationHelper', () => {
expect(extension.getExtensionObjectsTypes().at(0)).toBe('MyObject');
const objectMetadata = extension.getObjectMetadata('MyObject');
// The capabilities replaced the deprecated instructions below.
expectArray(
objectMetadata.getDefaultBehaviors().toNewVectorString().toJSArray()
).toContainAll([
"ResizableCapability::ResizableBehavior",
"ScalableCapability::ScalableBehavior",
"FlippableCapability::FlippableBehavior",
"OpacityCapability::OpacityBehavior",
"EffectCapability::EffectBehavior",
]);
expectArray(objectMetadata.getAllActions().keys().toJSArray()).toContainAll(
[
// Private
'MyObject::SetRotationCenter',
// Public
// Deprecated
'MyObject::Width',
'Width',
'MyObject::Height',
@@ -1078,6 +1089,7 @@ describe('MetadataDeclarationHelper', () => {
expectArray(
objectMetadata.getAllConditions().keys().toJSArray()
).toContainAll([
// Deprecated
'MyObject::ScaleX',
'MyObject::ScaleY',
'MyObject::FlippedX',
@@ -1089,7 +1101,9 @@ describe('MetadataDeclarationHelper', () => {
expectArray(
objectMetadata.getAllExpressions().keys().toJSArray()
).toContainAll(['ScaleX', 'ScaleY', 'Opacity']);
).toContainAll([
// Deprecated
'ScaleX', 'ScaleY', 'Opacity']);
expectArray(
objectMetadata.getAllStrExpressions().keys().toJSArray()
@@ -1099,6 +1113,53 @@ describe('MetadataDeclarationHelper', () => {
project.delete();
});
it('can create metadata for custom object with all capabilities', () => {
const extension = new gd.PlatformExtension();
const project = new gd.Project();
const eventExtension = project.insertNewEventsFunctionsExtension(
'MyExtension',
0
);
const eventsBasedObject = eventExtension
.getEventsBasedObjects()
.insertNew('MyObject', 0);
eventsBasedObject.markAsRenderedIn3D(true);
// TODO Uncomment when the feature is done.
// eventsBasedObject.markAsAnimatable(true);
eventsBasedObject.markAsTextContainer(true);
const objectMethodMangledNames = new gd.MapStringString();
gd.MetadataDeclarationHelper.generateObjectMetadata(
project,
extension,
eventExtension,
eventsBasedObject,
objectMethodMangledNames
);
objectMethodMangledNames.delete();
expect(extension.getExtensionObjectsTypes().size()).toBe(1);
expect(extension.getExtensionObjectsTypes().at(0)).toBe('MyObject');
const objectMetadata = extension.getObjectMetadata('MyObject');
expectArray(
objectMetadata.getDefaultBehaviors().toNewVectorString().toJSArray()
).toContainAll([
"ResizableCapability::ResizableBehavior",
"ScalableCapability::ScalableBehavior",
"FlippableCapability::FlippableBehavior",
// No effect nor opacity capabilities for 3D objects.
"Scene3D::Base3DBehavior",
// TODO Uncomment when the feature is done.
// "AnimatableCapability::AnimatableBehavior",
"TextContainerCapability::TextContainerBehavior",
]);
extension.delete();
project.delete();
});
it('can create metadata for object actions', () => {
const extension = new gd.PlatformExtension();
const project = new gd.Project();

View File

@@ -8,9 +8,6 @@
"name": "GDevelop.js",
"version": "0.0.1",
"license": "MIT",
"dependencies": {
"prettier": "^2.1.2"
},
"devDependencies": {
"@types/node": "^20.3.1",
"extend": "^2.0.1",
@@ -25,6 +22,7 @@
"grunt-shell": "^2.1.0",
"grunt-string-replace": "^1.3.1",
"jest": "^29.7.0",
"prettier": "^3.2.2",
"shelljs": "^0.8.4",
"webidl-tools": "github:4ian/webidl-tools#348f9c03afc9d8f278efccdd74543e265a41fd11"
}
@@ -7545,14 +7543,18 @@
}
},
"node_modules/prettier": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.1.2.tgz",
"integrity": "sha512-16c7K+x4qVlJg9rEbXl7HEGmQyZlG4R9AgP+oHKRMsMsuk8s+ATStlf1NpDqyBI1HpVyfjLOeMhH2LvuNvV5Vg==",
"version": "3.2.2",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.2.2.tgz",
"integrity": "sha512-HTByuKZzw7utPiDO523Tt2pLtEyK7OibUD9suEJQrPUCYQqrHr74GGX6VidMrovbf/I50mPqr8j/II6oBAuc5A==",
"dev": true,
"bin": {
"prettier": "bin-prettier.js"
"prettier": "bin/prettier.cjs"
},
"engines": {
"node": ">=10.13.0"
"node": ">=14"
},
"funding": {
"url": "https://github.com/prettier/prettier?sponsor=1"
}
},
"node_modules/pretty-bytes": {

View File

@@ -33,6 +33,7 @@
"grunt-shell": "^2.1.0",
"grunt-string-replace": "^1.3.1",
"jest": "^29.7.0",
"prettier": "^3.2.2",
"shelljs": "^0.8.4",
"webidl-tools": "github:4ian/webidl-tools#348f9c03afc9d8f278efccdd74543e265a41fd11"
},
@@ -45,8 +46,5 @@
"<rootDir>/emsdk/",
"<rootDir>/node_modules/"
]
},
"dependencies": {
"prettier": "^2.1.2"
}
}

View File

@@ -1,7 +1,7 @@
// @ts-check
import { readFileSync, writeFileSync } from 'fs';
import { dirname } from 'path';
import { fileURLToPath } from 'url';
import { readFileSync, writeFileSync } from 'node:fs';
import { dirname } from 'node:path';
import { fileURLToPath } from 'node:url';
const __dirname = dirname(fileURLToPath(import.meta.url));
const bindingsFile = readFileSync(
@@ -9,6 +9,69 @@ const bindingsFile = readFileSync(
'utf-8'
);
/** @type {Record<string, {returnType: string, inputType?: string}>} */
const castFunctions = {
StandardEvent: { inputType: 'Event', returnType: 'StandardEvent' },
RepeatEvent: { inputType: 'Event', returnType: 'RepeatEvent' },
WhileEvent: { inputType: 'Event', returnType: 'WhileEvent' },
ForEachEvent: { inputType: 'Event', returnType: 'ForEachEvent' },
ForEachChildVariableEvent: {
inputType: 'Event',
returnType: 'ForEachChildVariableEvent',
},
CommentEvent: { inputType: 'Event', returnType: 'CommentEvent' },
GroupEvent: { inputType: 'Event', returnType: 'GroupEvent' },
LinkEvent: { inputType: 'Event', returnType: 'LinkEvent' },
JsCodeEvent: { inputType: 'Event', returnType: 'JsCodeEvent' },
Platform: { inputType: 'JsPlatform', returnType: 'Platform' },
SpriteConfiguration: {
inputType: 'ObjectConfiguration',
returnType: 'SpriteObject',
},
TiledSpriteConfiguration: {
inputType: 'ObjectConfiguration',
returnType: 'TiledSpriteObject',
},
PanelSpriteConfiguration: {
inputType: 'ObjectConfiguration',
returnType: 'PanelSpriteObject',
},
TextObjectConfiguration: {
inputType: 'ObjectConfiguration',
returnType: 'TextObject',
},
ShapePainterConfiguration: {
inputType: 'ObjectConfiguration',
returnType: 'ShapePainterObject',
},
TextEntryObject: {
inputType: 'ObjectConfiguration',
returnType: 'TextEntryObject',
},
ParticleEmitterConfiguration: {
inputType: 'ObjectConfiguration',
returnType: 'ParticleEmitterObject',
},
CustomObjectConfiguration: {
inputType: 'ObjectConfiguration',
returnType: 'CustomObjectConfiguration',
},
Model3DConfiguration: {
inputType: 'ObjectConfiguration',
returnType: 'Model3DObjectConfiguration',
},
SpineConfiguration: {
inputType: 'ObjectConfiguration',
returnType: 'SpineObjectConfiguration',
},
ObjectJsImplementation: { returnType: 'ObjectJsImplementation' },
ImageResource: { inputType: 'Resource', returnType: 'ImageResource' },
};
const PrimitiveTypes = new Map([
['DOMString', 'string'],
['long', 'number'],
@@ -69,6 +132,8 @@ class Parser {
static readUntil(thisCharacter, skipOverIt = true) {
let token = '';
while (this.currentCharacter !== thisCharacter) {
if (this.isDone)
throw new Error(`Never reached character '${thisCharacter}'!`);
token += this.currentCharacter;
this.parserPosition++;
}
@@ -83,17 +148,23 @@ class Parser {
Parser.skipWhitespaces();
// Read the type
let type = Parser.readUntil(' ');
/** @type {string} */
let type;
let optional = false;
if (type === 'optional') optional = true;
while (type === 'unsigned' || type === 'optional') {
// Re-read the type since unsigned is an unnecessary prefix for typescript
let attribute = false;
do {
Parser.skipWhitespaces();
type = Parser.readUntil(' ');
}
if (type === 'optional') optional = true;
if (type === 'attribute') attribute = true;
} while (
type === 'unsigned' ||
type === 'optional' ||
type === 'attribute'
);
Parser.skipWhitespaces();
return { type, optional };
return { type, optional, attribute };
}
static readIdentifier() {
@@ -137,29 +208,58 @@ for (const [_, enumName, enumCode] of bindingsFile.matchAll(
members.push(` ${memberName} = ${i++},`);
}
enums.push(
`enum ${enumName} {
`export enum ${enumName} {
${members.join('\n')}
}`
);
}
const interfaces = [];
for (const [_, interfaceName, interfaceCode] of bindingsFile.matchAll(
/interface\s+([a-zA-Z]+)\s+{\r?\n?([^}]*)\r?\n}/gm
const freeFunctions = [];
for (const [
_,
implementationName,
interfaceName,
interfaceCode,
] of bindingsFile.matchAll(
/(?:\[JSImplementation=([a-zA-Z0-9]+)\]\r?\n?)?interface\s+([a-zA-Z0-9]+)\s+{(?:}|(?:\r?\n?([^}]*)\r?\n}))/gm
)) {
if (!interfaceCode) {
interfaces.push(
`export class ${interfaceName} extends EmscriptenObject {}`
);
continue;
}
const methods = [];
const attributes = [];
Parser.setSource(interfaceCode);
while (!Parser.isDone) {
const { type: returnType, optional: optionalReturn } = Parser.readType();
const {
type: returnType,
optional: optionalReturn,
attribute: isAttribute,
} = Parser.readType();
if (isAttribute) {
const attributeName = Parser.readUntil(';');
attributes.push(
`${attributeName}${optionalReturn ? '?' : ''}: ${returnType};`
);
continue;
}
let methodName = Parser.readUntil('(');
const isStatic = methodName.includes('STATIC_');
const isFree = methodName.includes('FREE_');
const isConstructor = returnType === 'void' && methodName === interfaceName;
// Remove prefixes which are not part of the actual function name
methodName = methodName
.replace('WRAPPED_', '')
.replace('MAP_', '')
.replace('FREE_', '')
.replace('CLONE_', '')
.replace('STATIC_', '');
// Convert PascalCase to camelCase
methodName = methodName[0].toLowerCase() + methodName.slice(1);
@@ -195,34 +295,50 @@ for (const [_, interfaceName, interfaceCode] of bindingsFile.matchAll(
Parser.parserPosition++;
Parser.skipWhitespaces();
methods.push(
`${isStatic ? 'static ' : ''}${
isConstructor ? `constructor` : methodName
}(${parameters
.map(
({ name, type, optional, defaultValue }) =>
`${name}${optional ? '?' : ''}: ${
PrimitiveTypes.has(type) ? PrimitiveTypes.get(type) : type
}${defaultValue !== none ? ` = ${defaultValue}` : ''}`
)
.join(', ')}): ${
PrimitiveTypes.has(returnType)
? PrimitiveTypes.get(returnType)
: returnType
};`
);
const method = `${isStatic ? 'static ' : ''}${
isConstructor ? `constructor` : methodName
}(${parameters
.map(
({ name, type, optional, defaultValue }) =>
`${name}${optional ? '?' : ''}: ${
PrimitiveTypes.has(type) ? PrimitiveTypes.get(type) : type
}`
)
.join(', ')})${
isConstructor
? ''
: `: ${
PrimitiveTypes.has(returnType)
? PrimitiveTypes.get(returnType)
: returnType
}`
};`;
if (isFree) freeFunctions.push(`export function ${method}`);
methods.push(method);
}
const explicitlyInheritedClass = bindingsFile.match(
new RegExp(`(?<![a-zA-Z0-9])${interfaceName} implements ([a-zA-Z0-9]+)`)
);
const inheritedClass =
implementationName ||
(!!explicitlyInheritedClass && explicitlyInheritedClass[1]);
interfaces.push(
`export class ${interfaceName} extends EmscriptenObject {
${methods.join('\n ')}
`export class ${interfaceName} extends ${
inheritedClass ? inheritedClass : 'EmscriptenObject'
} {${methods.length ? '\n ' + methods.join('\n ') : ''}${
attributes.length ? '\n ' + attributes.join('\n ') : ''
}
}`
);
}
const dts = `// Automatically generated by GDevelop.js/scripts/generate-dts.js
type float = number;
class EmscriptenObject {
declare class EmscriptenObject {
/** The object's index in the WASM memory, and thus its unique identifier. */
ptr: number;
@@ -237,14 +353,91 @@ class EmscriptenObject {
* If the object is owned by your code, you should still call this method when adequate, as
* otherwise the memory will never be freed, causing a memory leak, which is to be avoided.
*/
destroy(): void;
delete(): void;
}
${enums.join('\n\n')}
${interfaces.join('\n\n')}
${freeFunctions.join('\n\n')}
${Object.entries(castFunctions)
.map(
([interfaceName, { returnType, inputType = 'EmscriptenObject' }]) => `
export function as${interfaceName}(object: ${inputType}): ${returnType};
`
)
.join('')}
export const Object: typeof gdObject;
/**
* Initialises the Platforms included in the build (currently, only the JsPlatform),
* and loads all built-in extensions into the platform.
* To be called once when the library is first loaded.
*/
export const initializePlatforms: typeof ProjectHelper.initializePlatforms;
/**
* Returns the pointer in WASM memory to an object. It is a number that uniquely
* represents that instance of the object.
*
* @see {@link wrapPointer} to convert a pointer back to an object.
*/
export function getPointer(object: EmscriptenObject): number;
type ClassConstructor<T> = {
new (...args: any[]): T;
};
/**
* Wraps a pointer with a wrapper class, allowing to use the object located at the
* pointer's destination as an instance of that class.
*
* @see {@link getPointer} to get a pointer from an object.
*/
export function wrapPointer<T extends EmscriptenObject>(ptr: number, objectClass: ClassConstructor<T>): T;
/**
* Casts an object to another class type.
*
* **Careful** - this is not a conversion function.
* This only changes the class type and functions exposed, not the underlying memory.
* Only cast to another class if you are certain that the underlying memory is of that type!
*/
export function castObject<T extends EmscriptenObject>(object: EmscriptenObject, objectClass: ClassConstructor<T>): T;
/**
* Checks whether two objects are pointing to the same underlying memory.
* A reference to the object itself is not trustworthy, since there may be multiple
* wrapper objects (which allow to call C++ function on C++ memory) for a single
* pointer ("real object").
*
* This function must be therefore used to check for referential equality instead of
* JavaScript's standard equality operators when handling Emscripten objects.
*/
export function compare<T extends EmscriptenObject>(object1: T, object2: T): boolean;
/**
* Call this to free the object's underlying memory. It may not be used afterwards.
*
* **Call with care** - if the object owns some other objects, those will also be destroyed,
* or if this object is owned by another object that does not expect it to be externally deleted
* (e.g. it is a child of a map), objects will be put in an invalid state that will most likely
* crash the app.
*
* If the object is owned by your code, you should still call this method when adequate, as
* otherwise the memory will never be freed, causing a memory leak, which is to be avoided.
*
* The alias {@link EmscriptenObject.delete} is recommended instead, for readability.
*/
export function destroy(object: EmscriptenObject): void;
export as namespace gd;
declare global {
const gd: typeof gd;
}
`;
writeFileSync(__dirname + '/../types.d.ts', dts);

581
GDevelop.js/types.d.ts vendored

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
// Automatically generated by GDevelop.js/scripts/generate-types.js
declare class gdAbstractFunctionMetadata {
addParameter(type: string, description: string, optionalObjectType: string, parameterIsOptional: boolean): gdAbstractFunctionMetadata;
addParameter(type: string, description: string, optionalObjectType?: string, parameterIsOptional?: boolean): gdAbstractFunctionMetadata;
addCodeOnlyParameter(type: string, supplementaryInformation: string): gdAbstractFunctionMetadata;
setDefaultValue(defaultValue: string): gdAbstractFunctionMetadata;
setParameterLongDescription(longDescription: string): gdAbstractFunctionMetadata;

View File

@@ -11,6 +11,8 @@ declare class gdEventsBasedObject extends gdAbstractEventsBasedEntity {
getDefaultName(): string;
markAsRenderedIn3D(isRenderedIn3D: boolean): gdEventsBasedObject;
isRenderedIn3D(): boolean;
markAsTextContainer(isTextContainer: boolean): gdEventsBasedObject;
isTextContainer(): boolean;
static getPropertyActionName(propertyName: string): string;
static getPropertyConditionName(propertyName: string): string;
static getPropertyExpressionName(propertyName: string): string;

View File

@@ -15,7 +15,7 @@ function getAtlasTexture(
return atlasTextures[tilesetId];
}
let texture = null;
let texture: Texture | null = null;
const tileset = tilesetCache[tilesetId];
if (tileset?.relPath) {

View File

@@ -21,11 +21,6 @@
# JSS triggers a Flow error
<PROJECT_ROOT>/node_modules/jss/src/index.js
[include]
# Type check the declarations of the JavaScript extensions (i.e: JsExtension.js files) with Flow
# (and actually any file in Extensions containing `// @flow`).
../../Extensions
[libs]
../../GDevelop.js/types

Binary file not shown.

After

Width:  |  Height:  |  Size: 731 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 848 B

View File

@@ -341,8 +341,9 @@
"description": {
"messageByLocale": {
"en": "Let's choose an **object** from the asset store",
"fr": "Nous allons choisir un objet dans le **magasin de ressources**.",
"fr": "Nous allons choisir un **objet** dans le magasin de ressources.",
"es": "Vamos a elegir un **objeto** de la tienda de recursos.",
"pt": "Vamos escolher um objeto da loja de recursos.",
"th": "เลือก **วัตถุ** จาก ร้านค้า asset",
"ar": "هيّا نقوم باختيار **كائن** من متجر العناصر"
}
@@ -2180,6 +2181,7 @@
"en": "Add a few $(obstacle) to the **scene** to protect $(target).",
"fr": "Ajoutez quelques $(obstacle) à la **scène** pour protéger $(target).",
"es": "Agrega algunos $(obstacle) a la **escena** para proteger a $(target).",
"pt": "Adicione alguns $(obstacle) à **cena** para proteger $(target).",
"th": "เพิ่ม $(obstacle) ปริมาณนิดหน่อยลงใน **scene** เพื่อป้องกัน $(target)",
"ar": "إضافة بضعة $(obstacle) إلى **المشهد** لحماية $(target)."
}

View File

@@ -2,7 +2,24 @@
{
"id": "cameraParallax",
"contentUrl": "https://resources.gdevelop-app.com/in-app-tutorials/cameraParallax.json",
"availableLocales": ["en", "fr", "es", "pt", "th", "ar"],
"availableLocales": [
"en",
"fr",
"ar",
"de",
"es",
"it",
"ja",
"ko",
"pl",
"pt",
"th",
"ru",
"sl",
"sq",
"uk",
"zh"
],
"initialTemplateUrl": "https://resources.gdevelop-app.com/in-app-tutorials/templates/cameraParallax/game.json",
"initialProjectData": {
"cameraScene": "CameraScene",
@@ -19,14 +36,48 @@
{
"id": "healthBar",
"contentUrl": "https://resources.gdevelop-app.com/in-app-tutorials/healthBar.json",
"availableLocales": ["en", "fr", "es", "pt", "th", "ar"],
"availableLocales": [
"en",
"fr",
"ar",
"de",
"es",
"it",
"ja",
"ko",
"pl",
"pt",
"th",
"ru",
"sl",
"sq",
"uk",
"zh"
],
"initialTemplateUrl": "https://resources.gdevelop-app.com/in-app-tutorials/templates/healthBar/game.json",
"initialProjectData": { "level": "Level", "player": "Player" }
},
{
"id": "joystick",
"contentUrl": "https://resources.gdevelop-app.com/in-app-tutorials/joystick.json",
"availableLocales": ["en", "fr", "es", "pt", "th", "ar", "sq"],
"availableLocales": [
"en",
"fr",
"ar",
"de",
"es",
"it",
"ja",
"ko",
"pl",
"pt",
"th",
"ru",
"sl",
"sq",
"uk",
"zh"
],
"initialTemplateUrl": "https://resources.gdevelop-app.com/in-app-tutorials/templates/joystick/game.json",
"initialProjectData": {
"gameScene": "GameScene",
@@ -36,14 +87,48 @@
{
"id": "object3d",
"contentUrl": "https://resources.gdevelop-app.com/in-app-tutorials/object3d.json",
"availableLocales": ["en", "fr", "es", "pt", "th", "ar"],
"availableLocales": [
"en",
"fr",
"ar",
"de",
"es",
"it",
"ja",
"ko",
"pl",
"pt",
"th",
"ru",
"sl",
"sq",
"uk",
"zh"
],
"initialTemplateUrl": "https://resources.gdevelop-app.com/in-app-tutorials/templates/object3d/game.json",
"initialProjectData": { "gameScene": "GameScene" }
"initialProjectData": { "gameScene": "GameScene", "platform": "Platform" }
},
{
"id": "plinkoMultiplier",
"contentUrl": "https://resources.gdevelop-app.com/in-app-tutorials/plinkoMultiplier.json",
"availableLocales": ["en", "fr", "es", "pt", "th", "ar"],
"availableLocales": [
"en",
"fr",
"ar",
"de",
"es",
"it",
"ja",
"ko",
"pl",
"pt",
"th",
"ru",
"sl",
"sq",
"uk",
"zh"
],
"initialTemplateUrl": "https://resources.gdevelop-app.com/in-app-tutorials/templates/plinkoMultiplier/game.json",
"initialProjectData": {
"gameScene": "GameScene",
@@ -56,7 +141,24 @@
{
"id": "timer",
"contentUrl": "https://resources.gdevelop-app.com/in-app-tutorials/timer.json",
"availableLocales": ["en", "fr", "es", "pt", "th", "ar"],
"availableLocales": [
"en",
"fr",
"ar",
"de",
"es",
"it",
"ja",
"ko",
"pl",
"pt",
"th",
"ru",
"sl",
"sq",
"uk",
"zh"
],
"initialTemplateUrl": "https://resources.gdevelop-app.com/in-app-tutorials/templates/timer/game.json",
"initialProjectData": { "gameScene": "GameScene" }
}

View File

@@ -61,6 +61,13 @@ if (!args['examplesGitPath']) {
}
const examplesGitPath = args['examplesGitPath'];
if (!args['templatesGitPath']) {
shell.echo(
'⚠️ You should pass --templatesGitPath pointing to the git directory of GDevelop-game-templates.'
);
}
const templatesGitPath = args['templatesGitPath'];
/** @typedef {{sha: string, message: string, authorEmail: string}} GitRawCommitInfo */
/** @typedef {{
message: string,
@@ -321,6 +328,7 @@ const formatHiddenCommitMessage = commit => {
* extensionsCommits: GitEnrichedCommitInfo[] | null,
* assetsCommits: GitEnrichedCommitInfo[] | null,
* examplesCommits: GitEnrichedCommitInfo[] | null,
* templatesCommits: GitEnrichedCommitInfo[] | null
* }} commits
*/
const outputChangelog = ({
@@ -331,6 +339,7 @@ const outputChangelog = ({
extensionsCommits,
assetsCommits,
examplesCommits,
templatesCommits,
}) => {
shell.echo(
` Hidden these commits: \n${hiddenCommits
@@ -378,6 +387,14 @@ const outputChangelog = ({
.join('\n')
: 'TODO: Add examples commits here.'
);
shell.echo('\n## 🕹 Premium Game Templates\n');
shell.echo(
templatesCommits
? templatesCommits
.map(commit => formatCommitMessage({ commit, includeAuthor: false }))
.join('\n')
: 'TODO: Add game templates commits here.'
);
if (devCommits.length > 0) {
shell.echo(`\n### 🛠 Internal changes (for developers)\n`);
@@ -446,6 +463,17 @@ const outputChangelog = ({
);
}
let templatesCommits = null;
if (templatesGitPath) {
const templatesRepoGitTools = getGitTools(templatesGitPath);
const templatesRawCommits = templatesRepoGitTools.extractCommitsSinceDate(
lastTagDate
);
templatesCommits = enrichCommits(templatesRawCommits).filter(
commit => !commit.hidden
);
}
outputChangelog({
hiddenCommits,
improvementsCommits,
@@ -454,5 +482,6 @@ const outputChangelog = ({
extensionsCommits,
assetsCommits,
examplesCommits,
templatesCommits,
});
})();

View File

@@ -26,6 +26,8 @@ import {
PrivateGameTemplateTile,
} from './ShopTiles';
import { useDebounce } from '../Utils/UseDebounce';
import PromotionsSlideshow from '../Promotions/PromotionsSlideshow';
import { ColumnStackLayout } from '../UI/Layout';
const cellSpacing = 2;
@@ -157,6 +159,7 @@ type Props = {|
onCategorySelection: string => void,
openedShopCategory: string | null,
hideGameTemplates?: boolean,
displayPromotions?: boolean,
|};
export const AssetsHome = React.forwardRef<Props, AssetsHomeInterface>(
@@ -171,6 +174,7 @@ export const AssetsHome = React.forwardRef<Props, AssetsHomeInterface>(
onCategorySelection,
openedShopCategory,
hideGameTemplates,
displayPromotions,
}: Props,
ref
) => {
@@ -383,6 +387,15 @@ export const AssetsHome = React.forwardRef<Props, AssetsHomeInterface>(
</GridList>
</>
)}
{displayPromotions ? (
<ColumnStackLayout>
<Text size="block-title">
<Trans>Promotions</Trans>
</Text>
<PromotionsSlideshow />
</ColumnStackLayout>
) : null}
{allBundleTiles.length ? (
<>
<Column>

View File

@@ -17,7 +17,9 @@ export type ExampleStoreDialogProps = {|
onSelectPrivateGameTemplateListingData: (
privateGameTemplateListingData: ?PrivateGameTemplateListingData
) => void,
onOpenNewProjectSetupDialog: () => void,
onOpenNewProjectSetupDialog: (
initialTab: 'from-scratch' | 'ai' | 'example'
) => void,
isProjectOpening: boolean,
|};
@@ -44,7 +46,7 @@ const ExampleStoreDialog = ({
id="create-blank-project-button"
label={<Trans>Create a blank project</Trans>}
primary
onClick={onOpenNewProjectSetupDialog}
onClick={() => onOpenNewProjectSetupDialog('from-scratch')}
/>,
],
[onClose, onOpenNewProjectSetupDialog]
@@ -59,7 +61,7 @@ const ExampleStoreDialog = ({
title={<Trans>Create a new project</Trans>}
actions={actions}
onRequestClose={onClose}
onApply={onOpenNewProjectSetupDialog}
onApply={() => onOpenNewProjectSetupDialog('from-scratch')}
open={open}
fullHeight
flexColumnBody
@@ -67,7 +69,9 @@ const ExampleStoreDialog = ({
<ExampleStore
focusOnMount
isOpening={isProjectOpening}
onOpenNewProjectSetupDialog={onOpenNewProjectSetupDialog}
onOpenNewProjectSetupDialog={() =>
onOpenNewProjectSetupDialog('example')
}
onSelectExampleShortHeader={onSelectExampleShortHeader}
onSelectPrivateGameTemplateListingData={
onSelectPrivateGameTemplateListingData

View File

@@ -93,7 +93,6 @@ export const CustomObjectPackResults = ({
<TextButton
icon={<ChevronArrowLeft />}
label={<Trans>Back</Trans>}
primary={false}
onClick={onBack}
disabled={isAssetBeingInstalled}
/>

View File

@@ -59,6 +59,7 @@ import { PrivateGameTemplateStoreContext } from './PrivateGameTemplates/PrivateG
type Props = {|
hideGameTemplates?: boolean, // TODO: if we add more options, use an array instead.
displayPromotions?: boolean,
onOpenPrivateGameTemplateListingData?: (
privateGameTemplateListingData: PrivateGameTemplateListingData
) => void,
@@ -94,7 +95,14 @@ const identifyAssetPackKind = ({
};
export const AssetStore = React.forwardRef<Props, AssetStoreInterface>(
({ hideGameTemplates, onOpenPrivateGameTemplateListingData }: Props, ref) => {
(
{
hideGameTemplates,
displayPromotions,
onOpenPrivateGameTemplateListingData,
}: Props,
ref
) => {
const {
assetShortHeadersSearchResults,
publicAssetPacksSearchResults,
@@ -652,7 +660,6 @@ export const AssetStore = React.forwardRef<Props, AssetStoreInterface>(
<TextButton
icon={<ChevronArrowLeft />}
label={<Trans>Back</Trans>}
primary={false}
onClick={async () => {
const page = shopNavigationState.backToPreviousPage();
const isUpdatingSearchtext = reApplySearchTextIfNeeded(
@@ -738,6 +745,7 @@ export const AssetStore = React.forwardRef<Props, AssetStoreInterface>(
onCategorySelection={selectShopCategory}
openedShopCategory={openedShopCategory}
hideGameTemplates={hideGameTemplates}
displayPromotions={displayPromotions}
/>
) : (
<PlaceholderLoader />

View File

@@ -43,6 +43,7 @@ import useAlertDialog from '../UI/Alert/useAlertDialog';
import PasteIcon from '../UI/CustomSvgIcons/Clipboard';
import CopyIcon from '../UI/CustomSvgIcons/Copy';
import ResponsiveFlatButton from '../UI/ResponsiveFlatButton';
import { useResponsiveWindowSize } from '../UI/Responsive/ResponsiveWindowMeasurer';
const gd: libGDevelop = global.gd;
@@ -281,6 +282,7 @@ type Props = {|
|};
const BehaviorsEditor = (props: Props) => {
const { isMobile } = useResponsiveWindowSize();
const scrollView = React.useRef<?ScrollViewInterface>(null);
const [
justAddedBehaviorName,
@@ -598,7 +600,9 @@ const BehaviorsEditor = (props: Props) => {
helpPagePath="/behaviors"
tutorialId="intro-behaviors-and-functions"
actionButtonId="add-behavior-button"
actionLabel={<Trans>Add a behavior</Trans>}
actionLabel={
isMobile ? <Trans>Add</Trans> : <Trans>Add a behavior</Trans>
}
onAction={() => setNewBehaviorDialogOpen(true)}
secondaryActionIcon={<PasteIcon />}
secondaryActionLabel={
@@ -645,7 +649,13 @@ const BehaviorsEditor = (props: Props) => {
<ResponsiveFlatButton
key={'copy-all-behaviors'}
leftIcon={<CopyIcon />}
label={<Trans>Copy all behaviors</Trans>}
label={
isMobile ? (
<Trans>Copy all</Trans>
) : (
<Trans>Copy all behaviors</Trans>
)
}
onClick={() => {
copyAllBehaviors();
}}
@@ -663,7 +673,13 @@ const BehaviorsEditor = (props: Props) => {
<LineStackLayout justifyContent="flex-end" expand>
<RaisedButton
key="add-behavior-line"
label={<Trans>Add a behavior</Trans>}
label={
isMobile ? (
<Trans>Add</Trans>
) : (
<Trans>Add a behavior</Trans>
)
}
primary
onClick={() => setNewBehaviorDialogOpen(true)}
icon={<Add />}

View File

@@ -106,6 +106,14 @@ export default function EventsBasedObjectEditor({
onChange();
}}
/>
<Checkbox
label={<Trans>Contains text</Trans>}
checked={eventsBasedObject.isTextContainer()}
onCheck={(e, checked) => {
eventsBasedObject.markAsTextContainer(checked);
onChange();
}}
/>
{eventsBasedObject.getEventsFunctions().getEventsFunctionsCount() ===
0 && (
<DismissableAlertMessage

View File

@@ -370,7 +370,6 @@ const PublishHome = ({
<TextButton
icon={<ChevronArrowLeft />}
label={<Trans>Back</Trans>}
primary={false}
onClick={onBack}
disabled={isNavigationDisabled}
/>

View File

@@ -1039,20 +1039,20 @@ const InAppTutorialOrchestrator = React.forwardRef<
let formattedStepTrigger;
const stepTrigger = currentStep.nextStepTrigger;
if (stepTrigger) {
if (stepTrigger.clickOnTooltipButton) {
const formattedButtonLabel = translateAndInterpolateText({
text: stepTrigger.clickOnTooltipButton,
data,
i18n,
project,
});
formattedStepTrigger = formattedButtonLabel
? {
clickOnTooltipButton: formattedButtonLabel,
}
: undefined;
}
if (stepTrigger && stepTrigger.clickOnTooltipButton) {
const formattedButtonLabel = translateAndInterpolateText({
text: stepTrigger.clickOnTooltipButton,
data,
i18n,
project,
});
formattedStepTrigger = formattedButtonLabel
? {
clickOnTooltipButton: formattedButtonLabel,
}
: undefined;
} else {
formattedStepTrigger = stepTrigger;
}
const formattedStep: InAppTutorialFlowFormattedStep = {
...currentStep,

View File

@@ -100,7 +100,10 @@ const getWrongEditorTooltip = (
export const queryElementOrItsMostVisuallySignificantParent = (
elementToHighlightId: string
) => {
): {|
elementToHighlight: ?HTMLElement,
elementWithId: ?HTMLElement,
|} => {
let foundElement = document.querySelector(elementToHighlightId);
if (foundElement instanceof HTMLTextAreaElement) {
// In this case, the element to highlight is a Material UI multiline text field
@@ -108,7 +111,7 @@ export const queryElementOrItsMostVisuallySignificantParent = (
// to highlight the parent div.
const parentDiv = foundElement.closest('div');
if (parentDiv instanceof HTMLElement && isElementAMuiInput(parentDiv)) {
foundElement = parentDiv;
return { elementToHighlight: parentDiv, elementWithId: foundElement };
}
} else if (
foundElement instanceof HTMLInputElement &&
@@ -116,10 +119,13 @@ export const queryElementOrItsMostVisuallySignificantParent = (
) {
const containerDiv = foundElement.closest('div[data-search-bar-container]');
if (containerDiv instanceof HTMLElement) {
foundElement = containerDiv;
return { elementToHighlight: containerDiv, elementWithId: foundElement };
}
}
return foundElement;
return {
elementToHighlight: foundElement,
elementWithId: foundElement,
};
};
type Props = {|
@@ -149,6 +155,7 @@ function InAppTutorialStepDisplayer({
elementToHighlight,
setElementToHighlight,
] = React.useState<?HTMLElement>(null);
const [elementWithId, setElementWithId] = React.useState<?HTMLElement>(null);
const [
hideBehindOtherDialog,
setHideBehindOtherDialog,
@@ -169,9 +176,12 @@ function InAppTutorialStepDisplayer({
() => {
if (!elementToHighlightId) return;
setElementToHighlight(
queryElementOrItsMostVisuallySignificantParent(elementToHighlightId)
);
const {
elementToHighlight,
elementWithId,
} = queryElementOrItsMostVisuallySignificantParent(elementToHighlightId);
setElementToHighlight(elementToHighlight);
setElementWithId(elementWithId);
},
[elementToHighlightId]
);
@@ -262,6 +272,36 @@ function InAppTutorialStepDisplayer({
);
};
const getFillAutomaticallyFunction = React.useCallback(
() => {
if (!nextStepTrigger || !nextStepTrigger.valueEquals) {
return undefined;
}
if (
!(elementWithId instanceof HTMLInputElement) &&
!(elementWithId instanceof HTMLTextAreaElement)
) {
return undefined;
}
const valuePropertyDescriptor = Object.getOwnPropertyDescriptor(
elementWithId.constructor.prototype,
'value'
);
if (!valuePropertyDescriptor) return undefined;
const valueSetter = valuePropertyDescriptor.set;
if (!valueSetter) return undefined;
return () => {
valueSetter.call(elementWithId, nextStepTrigger.valueEquals);
// Trigger blur to make sure the value is taken into account
// by the React input.
elementWithId.dispatchEvent(new Event('blur', { bubbles: true }));
};
},
[nextStepTrigger, elementWithId]
);
const renderTooltip = (i18n: I18nType) => {
if (tooltip && !expectedEditor) {
const anchorElement = tooltip.standalone
@@ -281,6 +321,7 @@ function InAppTutorialStepDisplayer({
? nextStepTrigger.clickOnTooltipButton
: undefined
}
fillAutomatically={getFillAutomaticallyFunction()}
/>
);
}
@@ -290,7 +331,7 @@ function InAppTutorialStepDisplayer({
return (
<InAppTutorialTooltipDisplayer
endTutorial={endTutorial}
showQuitButton={!isOnClosableDialog}
showQuitButton // Always show the quit button when the user is on the wrong editor
anchorElement={assistantImage}
tooltip={wrongEditorTooltip}
progress={progress}

View File

@@ -21,6 +21,7 @@ import { LineStackLayout } from '../UI/Layout';
import ChevronArrowTop from '../UI/CustomSvgIcons/ChevronArrowTop';
import { textEllipsisStyle } from '../UI/TextEllipsis';
import { useResponsiveWindowSize } from '../UI/Responsive/ResponsiveWindowMeasurer';
import TextButton from '../UI/TextButton';
const themeColors = {
grey10: '#EBEBED',
@@ -129,12 +130,14 @@ type TooltipBodyProps = {|
tooltip: InAppTutorialFormattedTooltip,
buttonLabel?: string,
goToNextStep: () => void,
fillAutomatically?: () => void,
|};
const TooltipBody = ({
tooltip,
buttonLabel,
goToNextStep,
fillAutomatically,
}: TooltipBodyProps) => {
const { isMobile } = useResponsiveWindowSize();
const titleAndDescription = (
@@ -182,10 +185,18 @@ const TooltipBody = ({
</Column>
);
const fillAutomaticallyButton = fillAutomatically && (
<TextButton
onClick={fillAutomatically}
label={<Trans>Fill automatically</Trans>}
primary
/>
);
return (
<Column noMargin>
{titleAndDescription}
{imageAndButton}
{fillAutomaticallyButton}
</Column>
);
};
@@ -287,6 +298,7 @@ type Props = {|
progress: number,
endTutorial: () => void,
goToNextStep: () => void,
fillAutomatically?: () => void,
|};
const InAppTutorialTooltipDisplayer = ({
@@ -297,6 +309,7 @@ const InAppTutorialTooltipDisplayer = ({
progress,
endTutorial,
goToNextStep,
fillAutomatically,
}: Props) => {
const { isMobile } = useResponsiveWindowSize();
const {
@@ -388,6 +401,7 @@ const InAppTutorialTooltipDisplayer = ({
tooltip={tooltip}
buttonLabel={buttonLabel}
goToNextStep={goToNextStep}
fillAutomatically={fillAutomatically}
/>
)}
</Column>

View File

@@ -98,7 +98,9 @@ export type RenderEditorContainerProps = {|
canInstallPrivateAsset: () => boolean,
// Project creation
onOpenNewProjectSetupDialog: () => void,
onOpenNewProjectSetupDialog: (
initialTab: 'from-scratch' | 'ai' | 'example'
) => void,
// Project save
onSave: () => Promise<void>,

View File

@@ -63,6 +63,7 @@ import ContextMenu, {
type ContextMenuInterface,
} from '../../../../UI/Menu/ContextMenu';
import type { ClientCoordinates } from '../../../../Utils/UseLongTouch';
import PromotionsSlideshow from '../../../../Promotions/PromotionsSlideshow';
const electron = optionalRequire('electron');
const path = optionalRequire('path');
@@ -107,7 +108,7 @@ type Props = {|
canOpen: boolean,
onChooseProject: () => void,
onOpenRecentFile: (file: FileMetadataAndStorageProviderName) => Promise<void>,
onOpenNewProjectSetupDialog: () => void,
onOpenNewProjectSetupDialog: (initialTab: 'ai' | 'from-scratch') => void,
onSelectExampleShortHeader: (exampleShortHeader: ExampleShortHeader) => void,
onSelectPrivateGameTemplateListingData: (
privateGameTemplateListingData: PrivateGameTemplateListingData
@@ -178,6 +179,8 @@ const BuildSection = ({
setLastModifiedInfoByProjectId,
] = React.useState({});
const isMediumOrSmallScreen =
windowSize === 'small' || windowSize === 'medium';
const columnsCount = getItemsColumns(windowSize, isLandscape);
const allGameTemplatesAndExamplesFlaggedAsGameCount = React.useMemo(
@@ -419,7 +422,7 @@ const BuildSection = ({
) : (
<SectionContainer
title={<Trans>My projects</Trans>}
showAnnouncementsAndPromotions
showUrgentAnnouncements
renderFooter={
limits && hasTooManyCloudProjects
? () => (
@@ -452,6 +455,10 @@ const BuildSection = ({
roundedImages
displayArrowsOnDesktop
/>
<Spacer />
<Column noMargin>
<PromotionsSlideshow />
</Column>
</SectionRow>
<SectionRow>
<ResponsiveLineStackLayout
@@ -483,34 +490,41 @@ const BuildSection = ({
primary
fullWidth={!canOpen}
label={
isMobile ? (
isMediumOrSmallScreen ? (
<Trans>Create</Trans>
) : (
<Trans>Create a project</Trans>
)
}
onClick={onOpenNewProjectSetupDialog}
onClick={() => onOpenNewProjectSetupDialog('from-scratch')}
icon={<Add fontSize="small" />}
id="home-create-project-button"
/>
<RaisedButton
primary
fullWidth={!canOpen}
label={
isMediumOrSmallScreen ? (
<Trans> AI prototype</Trans>
) : (
<Trans> Prototype with AI</Trans>
)
}
onClick={() => onOpenNewProjectSetupDialog('ai')}
id="home-create-project-button"
/>
{canOpen && (
<>
<Text>
<Trans>or</Trans>
</Text>
<Spacer />
<TextButton
primary
label={
isMobile ? (
<Trans>Open</Trans>
) : (
<Trans>Open a project</Trans>
)
}
onClick={onChooseProject}
/>
</>
<TextButton
secondary
label={
isMediumOrSmallScreen ? (
<Trans>Import</Trans>
) : (
<Trans>Import a project</Trans>
)
}
onClick={onChooseProject}
/>
)}
</LineStackLayout>
</Column>

View File

@@ -17,6 +17,7 @@ import List from '@material-ui/core/List';
import ErrorBoundary from '../../../UI/ErrorBoundary';
import { AnnouncementsFeed } from '../../../AnnouncementsFeed';
import { AnnouncementsFeedContext } from '../../../AnnouncementsFeed/AnnouncementsFeedContext';
import PromotionsSlideshow from '../../../Promotions/PromotionsSlideshow';
const styles = {
list: {
@@ -71,10 +72,7 @@ const CommunitySection = () => {
announcements && announcements.length > 0;
return (
<SectionContainer
title={<Trans>Community</Trans>}
showAnnouncementsAndPromotions
>
<SectionContainer title={<Trans>Community</Trans>} showUrgentAnnouncements>
<SectionRow>
<ColumnStackLayout noMargin expand>
{shouldDisplayAnnouncementsTitle && (
@@ -82,6 +80,7 @@ const CommunitySection = () => {
<Trans>News and announcements</Trans>
</Text>
)}
<PromotionsSlideshow />
<AnnouncementsFeed canClose={false} level="normal" />
<Text size="title">
<Trans>Join the conversation</Trans>

View File

@@ -18,7 +18,7 @@ import {
type WindowSizeType,
} from '../../../../UI/Responsive/ResponsiveWindowMeasurer';
import Text from '../../../../UI/Text';
import { Column } from '../../../../UI/Grid';
import { Column, Spacer } from '../../../../UI/Grid';
import { type Tutorial } from '../../../../Utils/GDevelopServices/Tutorial';
import { type SubscriptionPlanWithPricingSystems } from '../../../../Utils/GDevelopServices/Usage';
import { CardWidget } from '../CardWidget';
@@ -32,6 +32,7 @@ import PreferencesContext from '../../../Preferences/PreferencesContext';
import PlanRecommendationRow from './PlanRecommendationRow';
import { SurveyCard } from './SurveyCard';
import PlaceholderLoader from '../../../../UI/PlaceholderLoader';
import PromotionsSlideshow from '../../../../Promotions/PromotionsSlideshow';
const styles = {
textTutorialContent: {
@@ -300,6 +301,16 @@ const RecommendationList = ({
</SectionRow>
);
items.push(
<SectionRow key="promotions">
<Text size="section-title" noMargin>
<Trans>Discover the ecosystem</Trans>
</Text>
<Spacer />
<PromotionsSlideshow />
</SectionRow>
);
if (recommendedTextTutorials.length) {
items.push(
<SectionRow key="texts">

View File

@@ -4,7 +4,10 @@ import GDevelopThemeContext from '../../../../UI/Theme/GDevelopThemeContext';
import RaisedButton from '../../../../UI/RaisedButton';
import { Trans } from '@lingui/macro';
import { Line, Spacer } from '../../../../UI/Grid';
import { ColumnStackLayout } from '../../../../UI/Layout';
import {
ColumnStackLayout,
ResponsiveLineStackLayout,
} from '../../../../UI/Layout';
import Text from '../../../../UI/Text';
const styles = {
@@ -38,37 +41,43 @@ export const SurveyCard = ({
return (
<div style={subscriptionContainerStyle}>
<img src="res/start-survey.svg" style={styles.surveyIcon} alt="Survey" />
<Line noMargin expand>
<ColumnStackLayout alignItems="flex-start" expand>
<Text noMargin size="block-title">
{hasFilledSurveyAlready ? (
<Trans>Have you changed your usage of GDevelop?</Trans>
) : (
<Trans>Personalize your suggested content</Trans>
)}
</Text>
<Text noMargin size="body">
<Trans>
Answer a 1-minute survey to personalize your Get started
content.
</Trans>
</Text>
<Spacer />
<RaisedButton
label={
hasFilledSurveyAlready ? (
<Trans>Redo the survey</Trans>
<ResponsiveLineStackLayout noMargin>
<img
src="res/start-survey.svg"
style={styles.surveyIcon}
alt="Survey"
/>
<Line noMargin expand>
<ColumnStackLayout alignItems="flex-start" expand>
<Text noMargin size="block-title">
{hasFilledSurveyAlready ? (
<Trans>Have you changed your usage of GDevelop?</Trans>
) : (
<Trans>Start the survey!</Trans>
)
}
primary
onClick={onStartSurvey}
/>
<Spacer />
</ColumnStackLayout>
</Line>
<Trans>Personalize your suggested content</Trans>
)}
</Text>
<Text noMargin size="body">
<Trans>
Answer a 1-minute survey to personalize your Get started
content.
</Trans>
</Text>
<Spacer />
<RaisedButton
label={
hasFilledSurveyAlready ? (
<Trans>Redo the survey</Trans>
) : (
<Trans>Start the survey!</Trans>
)
}
primary
onClick={onStartSurvey}
/>
<Spacer />
</ColumnStackLayout>
</Line>
</ResponsiveLineStackLayout>
</div>
);
};

View File

@@ -628,16 +628,10 @@ const GetStartedSection = ({
return (
<>
<SectionContainer
title={
profile && profile.username ? (
<Trans>Hello {profile.username}!</Trans>
) : (
<Trans>Hello!</Trans>
)
}
title={<Trans>Start making games</Trans>}
renderSubtitle={renderSubtitle}
flexBody
showAnnouncementsAndPromotions
showUrgentAnnouncements
>
<RecommendationList
authenticatedUser={authenticatedUser}

View File

@@ -11,11 +11,11 @@ import ProjectManagerIcon from '../../../UI/CustomSvgIcons/ProjectManager';
import FloppyIcon from '../../../UI/CustomSvgIcons/Floppy';
import Window from '../../../Utils/Window';
import optionalRequire from '../../../Utils/OptionalRequire';
import { useResponsiveWindowSize } from '../../../UI/Responsive/ResponsiveWindowMeasurer';
import TextButton from '../../../UI/TextButton';
import IconButton from '../../../UI/IconButton';
import { isNativeMobileApp } from '../../../Utils/Platform';
import NotificationChip from '../../../UI/User/NotificationChip';
import { useResponsiveWindowSize } from '../../../UI/Responsive/ResponsiveWindowMeasurer';
const electron = optionalRequire('electron');
type Props = {|
@@ -36,6 +36,7 @@ export const HomePageHeader = ({
canSave,
}: Props) => {
const { isMobile } = useResponsiveWindowSize();
return (
<I18n>
{({ i18n }) => (
@@ -73,9 +74,9 @@ export const HomePageHeader = ({
</Column>
<Column>
<LineStackLayout noMargin alignItems="center">
{!electron && !isNativeMobileApp() && !isMobile && (
{!electron && !isNativeMobileApp() && (
<FlatButton
label={<Trans>Download desktop app</Trans>}
label={<Trans>Get the app</Trans>}
onClick={() =>
Window.openExternalURL('https://gdevelop.io/download')
}
@@ -83,11 +84,17 @@ export const HomePageHeader = ({
)}
<UserChip onOpenProfile={onOpenProfile} />
<NotificationChip />
<TextButton
label={i18n.language.toUpperCase()}
onClick={onOpenLanguageDialog}
icon={<TranslateIcon fontSize="small" />}
/>
{isMobile ? (
<IconButton size="small" onClick={onOpenLanguageDialog}>
<TranslateIcon fontSize="small" />
</IconButton>
) : (
<TextButton
label={i18n.language.toUpperCase()}
onClick={onOpenLanguageDialog}
icon={<TranslateIcon fontSize="small" />}
/>
)}
</LineStackLayout>
</Column>
</LineStackLayout>

View File

@@ -79,7 +79,7 @@ const HomePageMenuBar = ({
const theme = React.useContext(GDevelopThemeContext);
const { profile } = React.useContext(AuthenticatedUserContext);
const tabsToDisplay = getTabsToDisplay({ profile });
const buttons: {
const largeScreenOnlyButtons: {
label: React.Node,
getIcon: GetIconFunction,
id: string,
@@ -139,29 +139,6 @@ const HomePageMenuBar = ({
</IconButton>
);
})}
<span
style={{
width: 1,
backgroundColor: theme.home.separator.color,
height: '70%',
margin: '0 3px',
}}
/>
{buttons.map(({ label, onClick, getIcon, id }) => (
<IconButton
color="default"
key={id}
disableRipple
disableFocusRipple
style={styles.mobileButton}
onClick={onClick}
id={id}
>
<span style={styles.buttonLabel}>
{getIcon({ color: 'secondary', fontSize: 'inherit' })}
</span>
</IconButton>
))}
</ToolbarGroup>
</Toolbar>
</Paper>
@@ -198,7 +175,7 @@ const HomePageMenuBar = ({
<div style={styles.bottomButtonsContainer}>
<Column>
{buttons.map(({ label, getIcon, onClick, id }) => (
{largeScreenOnlyButtons.map(({ label, getIcon, onClick, id }) => (
<VerticalTabButton
key={id}
label={label}

View File

@@ -99,85 +99,63 @@ const GuidedLessons = ({ selectInAppTutorial, lessonsIds }: Props) => {
return tutorialProgress.progress[0]; // guided lessons only have one part.
};
const lessonsCompleted = guidedLessonsIds.reduce((acc, tutorialId) => {
const tutorialProgress = getTutorialPartProgress({ tutorialId }) || 0;
return tutorialProgress === 100 ? acc + 1 : acc;
}, 0);
const displayedGuidedLessonsIds = lessonsIds || guidedLessonsIds;
const lessonsCompleted = displayedGuidedLessonsIds.reduce(
(acc, tutorialId) => {
const tutorialProgress = getTutorialPartProgress({ tutorialId }) || 0;
return tutorialProgress === 100 ? acc + 1 : acc;
},
0
);
const lessonsProgress = Math.round(
(lessonsCompleted / guidedLessonsIds.length) * 100
(lessonsCompleted / displayedGuidedLessonsIds.length) * 100
);
const guidedLessonCards = [
{
id: JOYSTICK_IN_APP_TUTORIAL_ID,
title: t`Add Joystick controls`,
title: t`Joystick controls`,
description: t`Learn how to add a joystick to control the player.`,
keyPoints: [
t`Add a layer`,
t`Download and use a prefab`,
t`Use a behavior`,
],
durationInMinutes: 1,
renderImage: props => <Joystick {...props} />,
},
{
id: HEALTH_BAR_IN_APP_TUTORIAL_ID,
title: t`Display a Health bar for the player`,
title: t`Health bar`,
description: t`Learn how to display the health of a player on the foreground.`,
keyPoints: [t`Add a layer`, t`Download and use a prefab`],
durationInMinutes: 2,
renderImage: props => <HealthBar {...props} />,
},
{
id: OBJECT_3D_IN_APP_TUTORIAL_ID,
title: t`Add a 3D object`,
description: t`Learn how to add a 3D object to your game.`,
keyPoints: [
t`Add a 3D box`,
t`Add a behavior`,
t`Update the elevation of a 3D box`,
],
title: t`3D box`,
description: t`Learn how to add a 3D box to your game.`,
durationInMinutes: 2,
renderImage: props => <Object3D {...props} />,
},
{
id: CAMERA_PARALLAX_IN_APP_TUTORIAL_ID,
title: t`Improve background and camera`,
title: t`Background`,
description: t`Learn how to create a parallax background as well as a camera that follows the player.`,
keyPoints: [
t`Add an extension`,
t`Add a layer`,
t`Use a tiled sprite`,
t`Control the camera`,
],
durationInMinutes: 2,
renderImage: props => <Parallax {...props} />,
},
{
id: TIMER_IN_APP_TUTORIAL_ID,
title: t`Use a timer`,
title: t`Timer`,
description: t`Learn how to use a timer to count a score.`,
keyPoints: [
t`Create and use a timer`,
t`Create and modify a text`,
t`Build an expression`,
],
durationInMinutes: 2,
renderImage: props => <Timer {...props} />,
},
{
id: PLINKO_MULTIPLIER_IN_APP_TUTORIAL_ID,
title: t`Add score multiplier`,
title: t`Score multiplier`,
description: t`Learn how to manipulate a score by adding collectibles.`,
keyPoints: [
t`Create a variable`,
t`Use & manipulate a variable`,
t`Build an expression`,
],
durationInMinutes: 3,
renderImage: props => <MultiplierScore {...props} />,
},
].filter(item => (lessonsIds ? lessonsIds.includes(item.id) : true));
].filter(item => displayedGuidedLessonsIds.includes(item.id));
return (
<Line>
@@ -191,20 +169,18 @@ const GuidedLessons = ({ selectInAppTutorial, lessonsIds }: Props) => {
</PlaceholderError>
) : (
<ColumnStackLayout noMargin>
{!lessonsIds && (
<Column>
<LineStackLayout alignItems="center">
{lessonsProgress !== 100 ? (
<Text displayInlineAsSpan noMargin size="body2">
{lessonsProgress}%
</Text>
) : (
<Trophy />
)}
<ColoredLinearProgress value={lessonsProgress} />
</LineStackLayout>
</Column>
)}
<Column>
<LineStackLayout alignItems="center">
{lessonsProgress !== 100 ? (
<Text displayInlineAsSpan noMargin size="body2">
{lessonsProgress}%
</Text>
) : (
<Trophy />
)}
<ColoredLinearProgress value={lessonsProgress} />
</LineStackLayout>
</Column>
<GridList
cols={getColumnsFromWindowSize(windowSize, isLandscape)}
style={styles.grid}
@@ -217,7 +193,6 @@ const GuidedLessons = ({ selectInAppTutorial, lessonsIds }: Props) => {
title={item.title}
description={item.description}
durationInMinutes={item.durationInMinutes}
keyPoints={item.keyPoints}
renderImage={item.renderImage}
progress={getTutorialPartProgress({ tutorialId: item.id })}
onClick={() => selectInAppTutorial(item.id)}

View File

@@ -4,10 +4,8 @@ import { Trans } from '@lingui/macro';
import * as React from 'react';
import Dialog, { DialogPrimaryButton } from '../../../../UI/Dialog';
import FlatButton from '../../../../UI/FlatButton';
import { Line, Column } from '../../../../UI/Grid';
import { Line } from '../../../../UI/Grid';
import { ColumnStackLayout } from '../../../../UI/Layout';
import InAppTutorialContext from '../../../../InAppTutorial/InAppTutorialContext';
import { getLanguageLabelForLocale } from '../../../../Utils/i18n/MessageByLocale';
import Text from '../../../../UI/Text';
import {
FLING_GAME_IN_APP_TUTORIAL_ID,
@@ -26,15 +24,6 @@ const styles = {
},
};
type Props = {|
open: boolean,
tutorialId: string,
onClose: () => void,
tutorialCompletionStatus: 'notStarted' | 'started' | 'complete',
isProjectOpened?: boolean,
startTutorial: (scenario: 'resume' | 'startOver' | 'start') => Promise<void>,
|};
const getGuidedLessonContent = ({
learningKeys,
}: {
@@ -44,12 +33,6 @@ const getGuidedLessonContent = ({
<Text>
<Trans>You're about to start this guided lesson.</Trans>
</Text>
<Text>
<Trans>
A new project will be opened, so before beginning please ensure you have
closed and saved your current project.
</Trans>
</Text>
<Text>
<Trans>In this tutorial you will learn:</Trans>
</Text>
@@ -105,7 +88,6 @@ const titleAndContentByKey = {
content: getGuidedLessonContent({
learningKeys: [
<Trans>Add a background with parallax effect</Trans>,
<Trans>Add a new layer</Trans>,
<Trans>Add an extension</Trans>,
<Trans>Use basic camera movements to follow the player</Trans>,
],
@@ -117,8 +99,8 @@ const titleAndContentByKey = {
),
content: getGuidedLessonContent({
learningKeys: [
<Trans>Add a new layer</Trans>,
<Trans>Use a prefab to display the player's health bar</Trans>,
<Trans>Use a prefab for a health bar</Trans>,
<Trans>Update the health bar based on the player's health</Trans>,
],
}),
},
@@ -126,7 +108,6 @@ const titleAndContentByKey = {
title: <Trans>Let's add mobile controls to our game</Trans>,
content: getGuidedLessonContent({
learningKeys: [
<Trans>Add a new layer</Trans>,
<Trans>Add a joystick prefab</Trans>,
<Trans>Add a behavior</Trans>,
],
@@ -138,12 +119,21 @@ const titleAndContentByKey = {
learningKeys: [
<Trans>Add a 3D Box</Trans>,
<Trans>Add a behavior</Trans>,
<Trans>Update the elevation of a 3D box</Trans>,
],
}),
},
};
type Props = {|
open: boolean,
tutorialId: string,
onClose: () => void,
tutorialCompletionStatus: 'notStarted' | 'started' | 'complete',
isProjectOpened?: boolean,
isProjectOpening: boolean,
startTutorial: (scenario: 'resume' | 'startOver' | 'start') => Promise<void>,
|};
const StartInAppTutorialDialog = ({
open,
tutorialId,
@@ -151,33 +141,16 @@ const StartInAppTutorialDialog = ({
tutorialCompletionStatus,
isProjectOpened,
startTutorial,
isProjectOpening,
}: Props) => {
const resumeTutorial = () => startTutorial('resume');
const startOverTutorial = () => startTutorial('startOver');
const startTutorialForFirstTime = () => startTutorial('start');
const { getInAppTutorialShortHeader } = React.useContext(
InAppTutorialContext
);
const selectedInAppTutorialShortHeader = getInAppTutorialShortHeader(
tutorialId
);
const availableLocales = selectedInAppTutorialShortHeader
? selectedInAppTutorialShortHeader.availableLocales
: null;
const dialogContentByCompletionStatus = {
notStarted: {
title: titleAndContentByKey[tutorialId].title,
content: titleAndContentByKey[tutorialId].content,
availableLocalesLabels: availableLocales
? availableLocales.map(locale => [
locale,
getLanguageLabelForLocale(locale),
])
: null,
primaryAction: {
label: <Trans>Yes</Trans>,
onClick: startTutorialForFirstTime,
@@ -248,12 +221,14 @@ const StartInAppTutorialDialog = ({
key="close"
label={secondaryAction.label}
onClick={secondaryAction.onClick}
disabled={isProjectOpening}
/>,
<DialogPrimaryButton
key="start"
label={primaryAction.label}
primary
onClick={primaryAction.onClick}
disabled={isProjectOpening}
/>,
];
const secondaryActions = tertiaryAction
@@ -262,6 +237,7 @@ const StartInAppTutorialDialog = ({
key="other"
label={tertiaryAction.label}
onClick={tertiaryAction.onClick}
disabled={isProjectOpening}
/>,
]
: undefined;
@@ -284,20 +260,6 @@ const StartInAppTutorialDialog = ({
</div>
</Line>
{content}
{dialogContent.availableLocalesLabels ? (
<Column noMargin>
<Text>
<Trans>
This tutorial is available in the following languages:
</Trans>
</Text>
{dialogContent.availableLocalesLabels.map(([locale, label]) => (
<Text displayAsListItem noMargin key={locale}>
{label}
</Text>
))}
</Column>
) : null}
<Text>
<Trans>Are you ready?</Trans>
</Text>

View File

@@ -162,9 +162,6 @@ const MainPage = ({
return (
<SectionContainer title={<Trans>Help and guides</Trans>}>
<SectionRow>
<Text>
<Trans>Quick search</Trans>
</Text>
<WikiSearchBar />
</SectionRow>
<SectionRow>

View File

@@ -9,7 +9,6 @@ import { Trans } from '@lingui/macro';
import Paper from '../../../UI/Paper';
import { LineStackLayout } from '../../../UI/Layout';
import { AnnouncementsFeed } from '../../../AnnouncementsFeed';
import PromotionsSlideshow from '../../../Promotions/PromotionsSlideshow';
import { AnnouncementsFeedContext } from '../../../AnnouncementsFeed/AnnouncementsFeedContext';
export const SECTION_PADDING = 30;
@@ -58,7 +57,7 @@ type Props = {|
flexBody?: boolean,
renderFooter?: () => React.Node,
noScroll?: boolean,
showAnnouncementsAndPromotions?: boolean,
showUrgentAnnouncements?: boolean,
|};
const SectionContainer = ({
@@ -71,7 +70,7 @@ const SectionContainer = ({
flexBody,
renderFooter,
noScroll,
showAnnouncementsAndPromotions,
showUrgentAnnouncements,
}: Props) => {
const { isMobile } = useResponsiveWindowSize();
const { announcements } = React.useContext(AnnouncementsFeedContext);
@@ -94,14 +93,10 @@ const SectionContainer = ({
<Column useFullHeight noMargin expand>
<Paper style={paperStyle} square background="dark">
<Column noOverflowParent expand>
{showAnnouncementsAndPromotions && (
{showUrgentAnnouncements && (
<>
<AnnouncementsFeed canClose level="urgent" hideLoader />
{announcements && announcements.length > 0 && <Spacer />}
<Column noMargin>
<PromotionsSlideshow />
</Column>
<Spacer />
</>
)}
{backAction && (

View File

@@ -83,6 +83,7 @@ const StoreSection = ({
onOpenPrivateGameTemplateListingData={
onOpenPrivateGameTemplateListingData
}
displayPromotions
/>
{(openedAssetPack || openedAssetShortHeader) && (
<Line justifyContent="flex-end">

View File

@@ -114,7 +114,9 @@ type Props = {|
onOpenAbout: () => void,
// Project creation
onOpenNewProjectSetupDialog: () => void,
onOpenNewProjectSetupDialog: (
initialTab: 'from-scratch' | 'ai' | 'example'
) => void,
// Project save
onSave: () => Promise<void>,

View File

@@ -54,6 +54,13 @@ html {
padding-left: env(safe-area-inset-left);
}
/* Helper for avoiding the soft keyboard. See also `getAvoidSoftKeyboardStyle`. */
.avoid-soft-keyboard {
transform: translateY(calc(-1 * var(--softKeyboardBottomOffset)));
transition: transform 0.2s linear;
will-change: transform;
}
/* Disable selections and web-ish cursors */
:not(input):not(textarea):not(canvas):not(code),
:not(input):not(textarea):not(canvas):not(code)::after,

View File

@@ -12,7 +12,9 @@ import AuthenticatedUserContext from '../Profile/AuthenticatedUserContext';
type Props = {|
isProjectOpening: boolean,
onOpenNewProjectSetupDialog: () => void,
onOpenNewProjectSetupDialog: (
initialTab: 'from-scratch' | 'ai' | 'example'
) => void,
|};
const useExampleOrGameTemplateDialogs = ({
@@ -137,7 +139,7 @@ const useExampleOrGameTemplateDialogs = ({
<ExampleDialog
isOpening={isProjectOpening}
exampleShortHeader={selectedExampleShortHeader}
onOpen={onOpenNewProjectSetupDialog}
onOpen={() => onOpenNewProjectSetupDialog('example')}
onClose={() => setSelectedExampleShortHeader(null)}
/>
)}
@@ -148,7 +150,9 @@ const useExampleOrGameTemplateDialogs = ({
selectedPrivateGameTemplate.privateGameTemplateListingData
}
isPurchaseDialogOpen={!!purchasingGameTemplateListingData}
onCreateWithGameTemplate={onOpenNewProjectSetupDialog}
onCreateWithGameTemplate={() =>
onOpenNewProjectSetupDialog('example')
}
onGameTemplateOpen={privateGameTemplateListingData =>
setSelectedPrivateGameTemplate({
privateGameTemplateListingData,

View File

@@ -359,9 +359,9 @@ const MainFrame = (props: Props) => {
openPreferencesDialog,
] = React.useState<boolean>(false);
const [
newProjectSetupDialogOpen,
setNewProjectSetupDialogOpen,
] = React.useState<boolean>(false);
newProjectSetupDialogInitialTab,
setNewProjectSetupDialogInitialTab,
] = React.useState<null | 'from-scratch' | 'ai' | 'example'>(null);
const [isProjectOpening, setIsProjectOpening] = React.useState<boolean>(
false
@@ -498,7 +498,7 @@ const MainFrame = (props: Props) => {
openExampleStoreDialog,
} = useExampleOrGameTemplateDialogs({
isProjectOpening,
onOpenNewProjectSetupDialog: () => setNewProjectSetupDialogOpen(true),
onOpenNewProjectSetupDialog: setNewProjectSetupDialogInitialTab,
});
/**
@@ -1144,7 +1144,7 @@ const MainFrame = (props: Props) => {
},
getStorageProviderOperations,
afterCreatingProject: async ({ project, editorTabs, oldProjectId }) => {
setNewProjectSetupDialogOpen(false);
setNewProjectSetupDialogInitialTab(null);
closeExampleStoreDialog({ deselectExampleAndGameTemplate: true });
findLeaderboardsToReplace(project, oldProjectId);
openSceneOrProjectManager({
@@ -2960,7 +2960,7 @@ const MainFrame = (props: Props) => {
onLaunchDebugPreview: launchDebuggerAndPreview,
onLaunchNetworkPreview: launchNetworkPreview,
onOpenHomePage: openHomePage,
onCreateBlank: () => setNewProjectSetupDialogOpen(true),
onCreateBlank: () => setNewProjectSetupDialogInitialTab('from-scratch'),
onOpenProject: () => openOpenFromStorageProviderDialog(),
onSaveProject: saveProject,
onSaveProjectAs: saveProjectAs,
@@ -3020,7 +3020,7 @@ const MainFrame = (props: Props) => {
onExportProject: () => openShareDialog('publish'),
onInviteCollaborators: () => openShareDialog('invite'),
onCreateProject: openExampleStoreDialog,
onCreateBlank: () => setNewProjectSetupDialogOpen(true),
onCreateBlank: () => setNewProjectSetupDialogInitialTab('from-scratch'),
onOpenProjectManager: () => openProjectManager(true),
onOpenHomePage: openHomePage,
onOpenDebugger: openDebugger,
@@ -3224,9 +3224,7 @@ const MainFrame = (props: Props) => {
canInstallPrivateAsset,
onChooseProject: () => openOpenFromStorageProviderDialog(),
onOpenRecentFile: openFromFileMetadataWithStorageProvider,
onOpenNewProjectSetupDialog: () => {
setNewProjectSetupDialogOpen(true);
},
onOpenNewProjectSetupDialog: setNewProjectSetupDialogInitialTab,
onOpenProjectManager: () => openProjectManager(true),
onCloseProject: () => askToCloseProject(),
onOpenExampleStore: openExampleStoreDialog,
@@ -3241,7 +3239,7 @@ const MainFrame = (props: Props) => {
privateGameTemplateListingData,
openDialog: false,
});
setNewProjectSetupDialogOpen(true);
setNewProjectSetupDialogInitialTab('example');
},
onOpenProfile: () => openProfileDialog(true),
onOpenLanguageDialog: () => openLanguageDialog(true),
@@ -3366,11 +3364,12 @@ const MainFrame = (props: Props) => {
}}
/>
)}
{newProjectSetupDialogOpen && (
{newProjectSetupDialogInitialTab && (
<NewProjectSetupDialog
initialTab={newProjectSetupDialogInitialTab}
authenticatedUser={authenticatedUser}
isOpeningProject={isProjectOpening}
onClose={() => setNewProjectSetupDialogOpen(false)}
onClose={() => setNewProjectSetupDialogInitialTab(null)}
onCreateEmptyProject={createEmptyProject}
onCreateFromExample={createProjectFromExample}
onCreateProjectFromPrivateGameTemplate={
@@ -3480,6 +3479,7 @@ const MainFrame = (props: Props) => {
onClose={() => {
setSelectedInAppTutorialInfo(null);
}}
isProjectOpening={isProjectOpening}
/>
)}
{state.gdjsDevelopmentWatcherEnabled &&

View File

@@ -201,15 +201,13 @@ type PolygonsListProps = {|
// Sprite size is useful to make sure polygon vertices
// are not put outside the sprite bounding box, which is not supported:
spriteWidth: number,
spriteHeight: number,
spriteSize: [number, number],
|};
const PolygonsList = (props: PolygonsListProps) => {
const {
polygons,
spriteHeight,
spriteWidth,
spriteSize,
onPolygonsUpdated,
onSetFullImageCollisionMask,
onSetAutomaticallyAdaptCollisionMasks,
@@ -218,6 +216,7 @@ const PolygonsList = (props: PolygonsListProps) => {
selectedVerticePtr,
} = props;
const [spriteWidth, spriteHeight] = spriteSize;
const addCollisionMask = React.useCallback(
() => {
const newPolygon = gd.Polygon2d.createRectangle(

View File

@@ -83,8 +83,9 @@ const CollisionMasksEditor = ({
null
);
const [spriteWidth, setSpriteWidth] = React.useState(0);
const [spriteHeight, setSpriteHeight] = React.useState(0);
const [currentSpriteSize, setCurrentSpriteSize] = React.useState<
[number, number]
>([0, 0]);
const forceUpdate = useForceUpdate();
const { showConfirmation } = useAlertDialog();
@@ -245,11 +246,6 @@ const CollisionMasksEditor = ({
[sameCollisionMasksForAnimations, updateCollisionMasks, showConfirmation]
);
const setCurrentSpriteSize = (spriteWidth: number, spriteHeight: number) => {
setSpriteWidth(spriteWidth);
setSpriteHeight(spriteHeight);
};
const onSetAutomaticallyAdaptCollisionMasks = React.useCallback(
async value => {
// If enabling automatic while custom was selected, then ask for confirmation.
@@ -334,7 +330,7 @@ const CollisionMasksEditor = ({
project,
resourceName
)}
onSize={setCurrentSpriteSize}
onImageSize={setCurrentSpriteSize}
renderOverlay={overlayProps =>
sprite && (
<CollisionMasksPreview
@@ -410,8 +406,7 @@ const CollisionMasksEditor = ({
onHoverVertice={setHighlightedVerticePtr}
onClickVertice={setSelectedVerticePtr}
selectedVerticePtr={selectedVerticePtr}
spriteWidth={spriteWidth}
spriteHeight={spriteHeight}
spriteSize={currentSpriteSize}
/>
</React.Fragment>
)}

View File

@@ -1,10 +1,8 @@
// @flow
import { Trans } from '@lingui/macro';
import * as React from 'react';
import { TableRow, TableRowColumn } from '../../../../UI/Table';
import IconButton from '../../../../UI/IconButton';
import SemiControlledTextField from '../../../../UI/SemiControlledTextField';
import Text from '../../../../UI/Text';
import { roundTo } from '../../../../Utils/Mathematics';
import { Column } from '../../../../UI/Grid';
import GDevelopThemeContext from '../../../../UI/Theme/GDevelopThemeContext';
@@ -63,64 +61,50 @@ const PointRow = ({ pointX, pointY, ...props }: Props) => {
</TableRowColumn>
<TableRowColumn style={styles.coordinateColumn} padding="none">
<Column>
{!props.isAutomatic ? (
<SemiControlledTextField
margin="none"
inputStyle={
props.selected
? { color: gdevelopTheme.listItem.selectedTextColor }
: undefined
}
value={roundTo(pointX, POINT_COORDINATE_PRECISION).toString()}
type="number"
step={0.5}
id="point-x"
onChange={value => {
const valueAsNumber = parseFloat(value);
if (!isNaN(valueAsNumber)) props.onChangePointX(valueAsNumber);
}}
onBlur={event => {
props.onChangePointX(
parseFloat(event.currentTarget.value) || 0
);
}}
/>
) : (
<Text noMargin>
<Trans>(auto)</Trans>
</Text>
)}
<SemiControlledTextField
margin="none"
inputStyle={
props.selected
? { color: gdevelopTheme.listItem.selectedTextColor }
: undefined
}
value={roundTo(pointX, POINT_COORDINATE_PRECISION).toString()}
type="number"
step={0.5}
id="point-x"
onChange={value => {
const valueAsNumber = parseFloat(value);
if (!isNaN(valueAsNumber)) props.onChangePointX(valueAsNumber);
}}
onBlur={event => {
props.onChangePointX(parseFloat(event.currentTarget.value) || 0);
}}
disabled={props.isAutomatic}
/>
</Column>
</TableRowColumn>
<TableRowColumn style={styles.coordinateColumn} padding="none">
<Column>
{!props.isAutomatic ? (
<SemiControlledTextField
margin="none"
inputStyle={
props.selected
? { color: gdevelopTheme.listItem.selectedTextColor }
: undefined
}
value={roundTo(pointY, POINT_COORDINATE_PRECISION).toString()}
type="number"
step={0.5}
id="point-y"
onChange={value => {
const valueAsNumber = parseFloat(value);
if (!isNaN(valueAsNumber)) props.onChangePointY(valueAsNumber);
}}
onBlur={event => {
props.onChangePointY(
parseFloat(event.currentTarget.value) || 0
);
}}
/>
) : (
<Text noMargin>
<Trans>(auto)</Trans>
</Text>
)}
<SemiControlledTextField
margin="none"
inputStyle={
props.selected
? { color: gdevelopTheme.listItem.selectedTextColor }
: undefined
}
value={roundTo(pointY, POINT_COORDINATE_PRECISION).toString()}
type="number"
step={0.5}
id="point-y"
onChange={value => {
const valueAsNumber = parseFloat(value);
if (!isNaN(valueAsNumber)) props.onChangePointY(valueAsNumber);
}}
onBlur={event => {
props.onChangePointY(parseFloat(event.currentTarget.value) || 0);
}}
disabled={props.isAutomatic}
/>
</Column>
</TableRowColumn>
<TableRowColumn style={styles.toolColumn}>

View File

@@ -26,6 +26,7 @@ type PointsListBodyProps = {|
onSelectPoint: (pointName: string) => void,
onRenamedPoint: (oldName: string, newName: string) => void,
selectedPointName: ?string,
spriteSize: [number, number],
|};
const PointsListBody = (props: PointsListBodyProps) => {
@@ -138,13 +139,19 @@ const PointsListBody = (props: PointsListBodyProps) => {
selected={'Origin' === props.selectedPointName}
/>
);
const isDefaultCenterPoint = pointsContainer.isDefaultCenterPoint();
const centerRow = (
<PointRow
key={'center-point-row'}
pointName="Center"
isAutomatic={pointsContainer.isDefaultCenterPoint()}
pointX={centerPoint.getX()}
pointY={centerPoint.getY()}
isAutomatic={isDefaultCenterPoint}
pointX={
isDefaultCenterPoint ? props.spriteSize[0] / 2 : centerPoint.getX()
}
pointY={
isDefaultCenterPoint ? props.spriteSize[1] / 2 : centerPoint.getY()
}
onChangePointX={updateCenterPointX}
onChangePointY={updateCenterPointY}
onPointerEnter={props.onHoverPoint}
@@ -180,6 +187,7 @@ type PointsListProps = {|
onSelectPoint: (pointName: ?string) => void,
onRenamedPoint: (oldName: string, newName: string) => void,
selectedPointName: ?string,
spriteSize: [number, number],
|};
const PointsList = (props: PointsListProps) => {
@@ -207,6 +215,7 @@ const PointsList = (props: PointsListProps) => {
selectedPointName={props.selectedPointName}
onPointsUpdated={props.onPointsUpdated}
onRenamedPoint={props.onRenamedPoint}
spriteSize={props.spriteSize}
/>
</Table>
<Spacer />

View File

@@ -79,6 +79,10 @@ const PointsEditor = ({
setHighlightedPointName,
] = React.useState<?string>(null);
const [currentSpriteSize, setCurrentSpriteSize] = React.useState<
[number, number]
>([0, 0]);
const forceUpdate = useForceUpdate();
const { showConfirmation } = useAlertDialog();
@@ -224,6 +228,7 @@ const PointsEditor = ({
project,
resourceName
)}
onImageSize={setCurrentSpriteSize}
renderOverlay={overlayProps =>
sprite && (
<PointsPreview
@@ -289,6 +294,7 @@ const PointsEditor = ({
onHoverPoint={setHighlightedPointName}
onSelectPoint={setSelectedPointName}
onRenamedPoint={onRenamedPoint}
spriteSize={currentSpriteSize}
/>
)}
{!sprite && (

View File

@@ -269,7 +269,6 @@ const EditProfileDialog = ({
label={<Trans>Delete my account</Trans>}
disabled={actionInProgress}
key="delete"
primary={false}
onClick={onDeleteAccount}
/>,
];

View File

@@ -0,0 +1,279 @@
// @flow
import { Trans, t } from '@lingui/macro';
import { I18n } from '@lingui/react';
import * as React from 'react';
import Dialog, { DialogPrimaryButton } from '../../UI/Dialog';
import AuthenticatedUserContext from '../AuthenticatedUserContext';
import { changeUserSubscription } from '../../Utils/GDevelopServices/Usage';
import { ColumnStackLayout, LineStackLayout } from '../../UI/Layout';
import useAlertDialog from '../../UI/Alert/useAlertDialog';
import GDevelopGLogo from '../../UI/CustomSvgIcons/GDevelopGLogo';
import Form from '../../UI/Form';
import Text from '../../UI/Text';
import { Spacer } from '../../UI/Grid';
import TextField from '../../UI/TextField';
import Checkbox from '../../UI/Checkbox';
import FlatButton from '../../UI/FlatButton';
import StarIcon from '../../UI/CustomSvgIcons/Star';
type Props = {|
onClose: () => void,
onCloseAfterSuccess: () => void,
|};
const CancelReasonDialog = ({ onClose, onCloseAfterSuccess }: Props) => {
const [isCancelingSubscription, setIsCancelingSubscription] = React.useState(
false
);
const [hasCanceledSubscription, setHasCanceledSubscription] = React.useState(
false
);
const [
stoppedMakingGamesChecked,
setStoppedMakingGamesChecked,
] = React.useState(false);
const [strugglingChecked, setStrugglingChecked] = React.useState(false);
const [
preferFreeVersionChecked,
setPreferFreeVersionChecked,
] = React.useState(false);
const [missingFeatureChecked, setMissingFeatureChecked] = React.useState(
false
);
const [qualityIssuesChecked, setQualityIssuesChecked] = React.useState(false);
const [otherChecked, setOtherChecked] = React.useState(false);
const [freeText, setFreeText] = React.useState('');
const authenticatedUser = React.useContext(AuthenticatedUserContext);
const { showAlert } = useAlertDialog();
const canSubmit =
(stoppedMakingGamesChecked ||
strugglingChecked ||
preferFreeVersionChecked ||
qualityIssuesChecked ||
missingFeatureChecked ||
otherChecked) &&
((!missingFeatureChecked && !otherChecked) || freeText.trim().length > 0);
const cancelPlan = React.useCallback(
async () => {
if (isCancelingSubscription || !canSubmit) return;
const {
getAuthorizationHeader,
subscription,
profile,
} = authenticatedUser;
if (!profile || !subscription) return;
setIsCancelingSubscription(true);
try {
await changeUserSubscription(
getAuthorizationHeader,
profile.id,
{
planId: null,
},
{
cancelImmediately: false,
cancelReasons: {
'stopped-making-games': stoppedMakingGamesChecked,
'struggling-with-gdevelop': strugglingChecked,
'prefer-free-version': preferFreeVersionChecked,
'missing-feature': missingFeatureChecked,
'quality-issues': qualityIssuesChecked,
other: otherChecked,
freeText: freeText,
},
}
);
await authenticatedUser.onRefreshSubscription();
setHasCanceledSubscription(true);
} catch (rawError) {
await authenticatedUser.onRefreshSubscription();
console.error('Error while canceling subscription:', rawError);
showAlert({
title: t`Could not cancel your subscription`,
message: t`There was an error while canceling your subscription. Verify your internet connection or try again later.`,
});
} finally {
setIsCancelingSubscription(false);
}
},
[
authenticatedUser,
showAlert,
isCancelingSubscription,
canSubmit,
freeText,
stoppedMakingGamesChecked,
strugglingChecked,
preferFreeVersionChecked,
qualityIssuesChecked,
missingFeatureChecked,
otherChecked,
]
);
const isLoading =
!authenticatedUser.subscription ||
!authenticatedUser.profile ||
isCancelingSubscription;
const actions = hasCanceledSubscription
? [
<DialogPrimaryButton
label={<Trans>Close</Trans>}
key="close"
onClick={onCloseAfterSuccess}
primary
/>,
]
: [
<DialogPrimaryButton
label={<Trans>Submit and cancel</Trans>}
key="submit"
onClick={cancelPlan}
disabled={!canSubmit || isLoading}
primary
/>,
];
const secondaryActions = hasCanceledSubscription
? []
: [
<FlatButton
label={<Trans>Back</Trans>}
key="back"
onClick={onClose}
disabled={isLoading}
/>,
];
return (
<I18n>
{({ i18n }) => (
<Dialog
title={null}
actions={actions}
secondaryActions={secondaryActions}
open
cannotBeDismissed
onApply={cancelPlan}
maxWidth="sm"
>
{hasCanceledSubscription ? (
<ColumnStackLayout
expand
justifyContent="center"
alignItems="center"
>
<GDevelopGLogo fontSize="large" />
<Text size="block-title" align="center">
<Trans>Your subscription has been canceled</Trans>
</Text>
<LineStackLayout noMargin alignItems="center">
<StarIcon />
<Text size="sub-title" align="center">
<Trans>Thank you for your feedback</Trans>
</Text>
</LineStackLayout>
</ColumnStackLayout>
) : (
<ColumnStackLayout
expand
justifyContent="center"
alignItems="center"
>
<GDevelopGLogo fontSize="large" />
<Text size="block-title" align="center">
<Trans>Before you go...</Trans>
</Text>
<Text size="body2" noMargin align="center">
<Trans>
Your feedback is valuable to help us improve our premium
services. Why are you canceling your subscription?
</Trans>
</Text>
<Spacer />
<Form
onSubmit={cancelPlan}
autoComplete="off"
name="cancel"
fullWidth
>
<ColumnStackLayout noMargin expand>
<Checkbox
label={<Trans>I've stopped using GDevelop</Trans>}
checked={stoppedMakingGamesChecked}
onCheck={(e, checked) =>
setStoppedMakingGamesChecked(checked)
}
disabled={isLoading}
/>
<Checkbox
label={<Trans>I'm struggling to create what I want</Trans>}
checked={strugglingChecked}
onCheck={(e, checked) => setStrugglingChecked(checked)}
disabled={isLoading}
/>
<Checkbox
label={<Trans>The free version is enough for me</Trans>}
checked={preferFreeVersionChecked}
onCheck={(e, checked) =>
setPreferFreeVersionChecked(checked)
}
disabled={isLoading}
/>
<Checkbox
label={
<Trans>It's missing a feature (please specify)</Trans>
}
checked={missingFeatureChecked}
onCheck={(e, checked) => setMissingFeatureChecked(checked)}
disabled={isLoading}
/>
<Checkbox
label={
<Trans>
I have encountered bugs or performance problems
</Trans>
}
checked={qualityIssuesChecked}
onCheck={(e, checked) => setQualityIssuesChecked(checked)}
disabled={isLoading}
/>
<Checkbox
label={<Trans>Other reason (please specify)</Trans>}
checked={otherChecked}
onCheck={(e, checked) => setOtherChecked(checked)}
disabled={isLoading}
/>
<Spacer />
<TextField
autoFocus="desktop"
value={freeText}
multiline
translatableHintText={t`Please tell us more`}
floatingLabelText={<Trans>Details</Trans>}
floatingLabelFixed
onChange={(e, value) => {
setFreeText(value);
}}
onBlur={event => {
setFreeText(event.currentTarget.value.trim());
}}
fullWidth
disabled={isLoading}
rows={4}
/>
</ColumnStackLayout>
</Form>
</ColumnStackLayout>
)}
</Dialog>
)}
</I18n>
);
};
export default CancelReasonDialog;

Some files were not shown because too many files have changed in this diff Show More