Compare commits

..

4 Commits

Author SHA1 Message Date
Neyl
123db6d6bc Update scenestack.ts 2025-04-30 10:52:13 +02:00
Neyl
8a9636c519 Update scenestack.ts 2025-04-30 10:49:51 +02:00
Neyl
cc1ac66f9f format 2025-04-30 10:39:46 +02:00
Neyl
6e523cb0cc Draft commit to demonstrate lava shader 2025-04-28 15:31:37 +02:00
253 changed files with 3740 additions and 6367 deletions

View File

@@ -14,7 +14,7 @@ orbs:
macos: circleci/macos@2.5.1 # For Rosetta (see below)
node: circleci/node@5.2.0 # For a recent npm version (see below)
jobs:
# Build the **entire** app for macOS (including the GDevelop.js library).
# Build the **entire** app for macOS.
build-macos:
macos:
xcode: 14.2.0
@@ -94,7 +94,7 @@ jobs:
name: Deploy to S3 (latest)
command: export PATH=~/.local/bin:$PATH && aws s3 sync newIDE/electron-app/dist s3://gdevelop-releases/$(git rev-parse --abbrev-ref HEAD)/latest/
# Build the app for Linux (using a pre-built GDevelop.js library).
# Build the **entire** app for Linux.
build-linux:
# CircleCI docker workers are failing if they don't have enough memory (no swap)
resource_class: xlarge
@@ -107,25 +107,44 @@ jobs:
- checkout
- aws-cli/setup
# System dependencies (for Electron Builder)
# System dependencies (for Electron Builder and Emscripten)
- run:
name: Update system dependencies
command: sudo apt-get update
name: Install dependencies for Emscripten
command: sudo apt-get update && sudo apt install cmake
- run:
name: Install Python3 dependencies for Emscripten
command: sudo apt install python-is-python3 python3-distutils -y
- run:
name: Install Emscripten (for GDevelop.js)
command: git clone https://github.com/juj/emsdk.git && cd emsdk && ./emsdk install 3.1.21 && ./emsdk activate 3.1.21 && cd ..
- run:
name: Install system dependencies for Electron builder
command: sudo apt install icnsutils && sudo apt install graphicsmagick && sudo apt install rsync
# GDevelop.js dependencies
- restore_cache:
keys:
- gd-linux-nodejs-dependencies-{{ checksum "newIDE/app/package.json" }}-{{ checksum "newIDE/electron-app/package.json" }}-{{ checksum "GDevelop.js/package.json" }}
# fallback to using the latest cache if no exact match is found
- gd-linux-nodejs-dependencies---
# GDevelop IDE dependencies (using an exact version of GDevelop.js, built previously)
- run:
name: Install GDevelop.js dependencies and build it
command: cd GDevelop.js && npm install && cd ..
# Build GDevelop.js (and run tests to ensure it works)
- run:
name: Build GDevelop.js
# Use "--runInBand" as it's faster and avoid deadlocks on CircleCI Linux machines (probably because limited in processes number).
command: cd GDevelop.js && source ../emsdk/emsdk_env.sh && npm run build && npm test -- --runInBand && cd ..
# GDevelop IDE dependencies (after building GDevelop.js to avoid downloading a pre-built version)
- run:
name: Install GDevelop IDE dependencies
command: export REQUIRES_EXACT_LIBGD_JS_VERSION=true && cd newIDE/app && npm install && cd ../electron-app && npm install
command: cd newIDE/app && npm install && cd ../electron-app && npm install
- save_cache:
paths:
@@ -276,26 +295,10 @@ jobs:
name: Deploy to S3 (specific commit)
command: aws s3 sync Binaries/embuild/GDevelop.js s3://gdevelop-gdevelop.js/$(git rev-parse --abbrev-ref HEAD)/variant/debug-sanitizers/commit/$(git rev-parse HEAD)/
# Trigger AppVeyor build, which finishes building the Windows app
# (using GDevelop.js built in a previous step).
trigger-appveyor-windows-build:
docker:
- image: cimg/node:16.13
steps:
- run:
name: Trigger AppVeyor Windows build
command: |
curl -H "Content-Type: application/json" \
-H "Authorization: Bearer ${APPVEYOR_API_KEY}" \
--data "{
\"accountName\": \"4ian\",
\"projectSlug\": \"gdevelop\",
\"branch\": \"${CIRCLE_BRANCH}\"
}" \
-X POST https://ci.appveyor.com/api/builds
workflows:
gdevelop_js-wasm:
jobs:
- build-gdevelop_js-wasm-only
gdevelop_js-wasm-extra-checks:
jobs:
- build-gdevelop_js-debug-sanitizers-and-extra-checks:
@@ -307,28 +310,13 @@ workflows:
- /experimental-build.*/
builds:
jobs:
- build-gdevelop_js-wasm-only
- build-macos:
# The macOS version builds by itself GDevelop.js
# (so we verify we can build it on macOS).
# requires:
# - build-gdevelop_js-wasm-only
filters:
branches:
only:
- master
- /experimental-build.*/
- build-linux:
requires:
- build-gdevelop_js-wasm-only
filters:
branches:
only:
- master
- /experimental-build.*/
- trigger-appveyor-windows-build:
requires:
- build-gdevelop_js-wasm-only
filters:
branches:
only:

View File

@@ -59,44 +59,36 @@ BuiltinExtensionsImplementer::ImplementsCommonInstructionsExtension(
// end of compatibility code
extension
.AddCondition(
"Or",
_("Or"),
_("Checks if at least one sub-condition is true. If no "
"sub-condition is specified, it will always be false. "
"This is rarely used — multiple events and sub-events are "
"usually a better approach."),
_("If one of these conditions is true:"),
"",
"res/conditions/or24_black.png",
"res/conditions/or_black.png")
.SetCanHaveSubInstructions()
.MarkAsAdvanced();
extension
.AddCondition(
"And",
_("And"),
_("Checks if all sub-conditions are true. If no sub-condition is "
"specified, it will always be false. This is rarely needed, as "
"events already check all conditions before running actions."),
_("If all of these conditions are true:"),
"",
"res/conditions/and24_black.png",
"res/conditions/and_black.png")
.SetCanHaveSubInstructions()
.MarkAsAdvanced();
extension
.AddCondition("Not",
_("Not"),
_("Returns the opposite of the sub-condition(s) result. "
"This is rarely needed, as most conditions can be "
"inverted or expressed more simply."),
_("Invert the logical result of these conditions:"),
.AddCondition("Or",
_("Or"),
_("Check if one of the sub conditions is true"),
_("If one of these conditions is true:"),
"",
"res/conditions/not24_black.png",
"res/conditions/not_black.png")
"res/conditions/or24_black.png",
"res/conditions/or_black.png")
.SetCanHaveSubInstructions()
.MarkAsAdvanced();
extension
.AddCondition("And",
_("And"),
_("Check if all sub conditions are true"),
_("If all of these conditions are true:"),
"",
"res/conditions/and24_black.png",
"res/conditions/and_black.png")
.SetCanHaveSubInstructions()
.MarkAsAdvanced();
extension
.AddCondition(
"Not",
_("Not"),
_("Return the contrary of the result of the sub conditions"),
_("Invert the logical result of these conditions:"),
"",
"res/conditions/not24_black.png",
"res/conditions/not_black.png")
.SetCanHaveSubInstructions()
.MarkAsAdvanced();

View File

@@ -18,7 +18,6 @@
#include "GDCore/Project/Behavior.h"
#include "GDCore/Project/CustomBehavior.h"
#include "GDCore/Project/CustomObjectConfiguration.h"
#include "GDCore/Project/EventsBasedObjectVariant.h"
#include "GDCore/Project/EventsFunctionsExtension.h"
#include "GDCore/Project/Layout.h"
#include "GDCore/Project/Object.h"
@@ -62,6 +61,9 @@ void ObjectAssetSerializer::SerializeTo(
element.SetAttribute("version", "");
element.SetIntAttribute("animationsCount", 1);
element.SetIntAttribute("maxFramesCount", 1);
// TODO Find the right object dimensions.
element.SetIntAttribute("width", 0);
element.SetIntAttribute("height", 0);
SerializerElement &authorsElement = element.AddChild("authors");
authorsElement.ConsiderAsArrayOf("author");
SerializerElement &tagsElement = element.AddChild("tags");
@@ -74,28 +76,16 @@ void ObjectAssetSerializer::SerializeTo(
cleanObject->SerializeTo(objectAssetElement.AddChild("object"));
double width = 0;
double height = 0;
if (project.HasEventsBasedObject(object.GetType())) {
SerializerElement &variantsElement =
objectAssetElement.AddChild("variants");
variantsElement.ConsiderAsArrayOf("variant");
const auto *variant = ObjectAssetSerializer::GetVariant(project, object);
if (variant) {
width = variant->GetAreaMaxX() - variant->GetAreaMinX();
height = variant->GetAreaMaxY() - variant->GetAreaMinY();
}
std::unordered_set<gd::String> alreadyUsedVariantIdentifiers;
gd::ObjectAssetSerializer::SerializeUsedVariantsTo(
project, object, variantsElement, alreadyUsedVariantIdentifiers);
}
// TODO Find the right object dimensions when their is no variant.
element.SetIntAttribute("width", width);
element.SetIntAttribute("height", height);
SerializerElement &resourcesElement =
objectAssetElement.AddChild("resources");
resourcesElement.ConsiderAsArrayOf("resource");
@@ -134,54 +124,41 @@ void ObjectAssetSerializer::SerializeUsedVariantsTo(
gd::Project &project, const gd::Object &object,
SerializerElement &variantsElement,
std::unordered_set<gd::String> &alreadyUsedVariantIdentifiers) {
const auto *variant = ObjectAssetSerializer::GetVariant(project, object);
if (!variant) {
return;
}
const auto &variantIdentifier =
object.GetType() + gd::PlatformExtension::GetNamespaceSeparator() +
variant->GetName();
auto insertResult = alreadyUsedVariantIdentifiers.insert(variantIdentifier);
if (!insertResult.second) {
return;
}
SerializerElement &pairElement = variantsElement.AddChild("variant");
pairElement.SetAttribute("objectType", object.GetType());
SerializerElement &variantElement = pairElement.AddChild("variant");
variant->SerializeTo(variantElement);
for (auto &object : variant->GetObjects().GetObjects()) {
gd::ObjectAssetSerializer::SerializeUsedVariantsTo(
project, *object, variantsElement, alreadyUsedVariantIdentifiers);
}
}
const gd::EventsBasedObjectVariant *
ObjectAssetSerializer::GetVariant(gd::Project &project,
const gd::Object &object) {
if (!project.HasEventsBasedObject(object.GetType())) {
return nullptr;
return;
}
const auto &eventsBasedObject =
project.GetEventsBasedObject(object.GetType());
const auto &variants = eventsBasedObject.GetVariants();
const auto *customObjectConfiguration =
dynamic_cast<const gd::CustomObjectConfiguration *>(
&object.GetConfiguration());
const auto &variantName = customObjectConfiguration->GetVariantName();
if (!variants.HasVariantNamed(variantName) &&
(customObjectConfiguration
->IsMarkedAsOverridingEventsBasedObjectChildrenConfiguration() ||
customObjectConfiguration
->IsForcedToOverrideEventsBasedObjectChildrenConfiguration())) {
return nullptr;
if (customObjectConfiguration
->IsMarkedAsOverridingEventsBasedObjectChildrenConfiguration() ||
customObjectConfiguration
->IsForcedToOverrideEventsBasedObjectChildrenConfiguration()) {
return;
}
const auto &variantName = customObjectConfiguration->GetVariantName();
const auto &variantIdentifier =
object.GetType() + gd::PlatformExtension::GetNamespaceSeparator() +
variantName;
const auto &variant = variants.HasVariantNamed(variantName)
? variants.GetVariant(variantName)
: eventsBasedObject.GetDefaultVariant();
return &variant;
auto insertResult = alreadyUsedVariantIdentifiers.insert(variantIdentifier);
if (insertResult.second) {
const auto &eventsBasedObject =
project.GetEventsBasedObject(object.GetType());
const auto &variants = eventsBasedObject.GetVariants();
const auto &variant = variants.HasVariantNamed(variantName)
? variants.GetVariant(variantName)
: eventsBasedObject.GetDefaultVariant();
SerializerElement &pairElement = variantsElement.AddChild("variant");
pairElement.SetAttribute("objectType", object.GetType());
SerializerElement &variantElement = pairElement.AddChild("variant");
variant.SerializeTo(variantElement);
// TODO Recursivity
for (auto &object : variant.GetObjects().GetObjects()) {
gd::ObjectAssetSerializer::SerializeUsedVariantsTo(
project, *object, variantsElement, alreadyUsedVariantIdentifiers);
}
}
}
} // namespace gd

View File

@@ -21,7 +21,6 @@ class InitialInstance;
class SerializerElement;
class EffectsContainer;
class AbstractFileSystem;
class EventsBasedObjectVariant;
} // namespace gd
namespace gd {
@@ -59,8 +58,6 @@ private:
gd::Project &project, const gd::Object &object,
SerializerElement &variantsElement,
std::unordered_set<gd::String> &alreadyUsedVariantIdentifiers);
static const gd::EventsBasedObjectVariant* GetVariant(gd::Project &project, const gd::Object &object);
};
} // namespace gd

View File

@@ -33,132 +33,7 @@ using namespace gd;
TEST_CASE("ObjectAssetSerializer", "[common]") {
SECTION("Can serialize custom objects as assets with variant") {
gd::Platform platform;
gd::Project project;
SetupProjectWithDummyPlatform(project, platform);
auto &eventsExtension =
project.InsertNewEventsFunctionsExtension("MyEventsExtension", 0);
auto &eventsBasedObject = eventsExtension.GetEventsBasedObjects().InsertNew(
"MyEventsBasedObject", 0);
eventsBasedObject.SetFullName("My events based object");
eventsBasedObject.SetDescription("An events based object for test");
auto &childObject = eventsBasedObject.GetObjects().InsertNewObject(
project, "MyExtension::Sprite", "MyChild", 0);
auto &childInstance =
eventsBasedObject.GetInitialInstances().InsertNewInitialInstance();
childInstance.SetObjectName("MyChild");
auto &resourceManager = project.GetResourcesManager();
gd::ImageResource imageResource;
imageResource.SetName("assets/Idle.png");
imageResource.SetFile("assets/Idle.png");
imageResource.SetSmooth(true);
resourceManager.AddResource(imageResource);
gd::Layout &layout = project.InsertNewLayout("Scene", 0);
gd::Object &object = layout.GetObjects().InsertNewObject(
project, "MyEventsExtension::MyEventsBasedObject", "MyObject", 0);
auto *spriteConfiguration =
dynamic_cast<gd::SpriteObject *>(&childObject.GetConfiguration());
REQUIRE(spriteConfiguration != nullptr);
{
gd::Animation animation;
animation.SetName("Idle");
animation.SetDirectionsCount(1);
auto &direction = animation.GetDirection(0);
gd::Sprite frame;
frame.SetImageName("assets/Idle.png");
direction.AddSprite(frame);
spriteConfiguration->GetAnimations().AddAnimation(animation);
}
SerializerElement assetElement;
std::vector<gd::String> usedResourceNames;
ObjectAssetSerializer::SerializeTo(project, object, "My Object",
assetElement, usedResourceNames);
// This list is used to copy resource files.
REQUIRE(usedResourceNames.size() == 1);
REQUIRE(usedResourceNames[0] == "assets/Idle.png");
// Check that the project is left untouched.
REQUIRE(resourceManager.HasResource("assets/Idle.png"));
REQUIRE(resourceManager.GetResource("assets/Idle.png").GetFile() ==
"assets/Idle.png");
REQUIRE(!resourceManager.HasResource("Idle.png"));
REQUIRE(assetElement.HasChild("objectAssets"));
auto &objectAssetsElement = assetElement.GetChild("objectAssets");
objectAssetsElement.ConsiderAsArrayOf("objectAsset");
REQUIRE(objectAssetsElement.GetChildrenCount() == 1);
auto &objectAssetElement = objectAssetsElement.GetChild(0);
REQUIRE(objectAssetElement.HasChild("variants"));
auto &variantsElement = objectAssetElement.GetChild("variants");
variantsElement.ConsiderAsArrayOf("variant");
REQUIRE(variantsElement.GetChildrenCount() == 1);
auto &variantPairElement = variantsElement.GetChild(0);
REQUIRE(variantPairElement.GetStringAttribute("objectType") ==
"MyEventsExtension::MyEventsBasedObject");
REQUIRE(variantPairElement.HasChild("variant"));
auto &variantElement = variantPairElement.GetChild("variant");
REQUIRE(variantElement.GetStringAttribute("name") == "");
REQUIRE(variantElement.HasChild("objects"));
auto &objectsElement = variantElement.GetChild("objects");
objectsElement.ConsiderAsArrayOf("object");
REQUIRE(objectsElement.GetChildrenCount() == 1);
auto &childElement = objectsElement.GetChild(0);
REQUIRE(childElement.HasChild("animations"));
auto &animationsElement = childElement.GetChild("animations");
animationsElement.ConsiderAsArrayOf("animation");
REQUIRE(animationsElement.GetChildrenCount() == 1);
auto &animationElement = animationsElement.GetChild(0);
REQUIRE(animationElement.GetStringAttribute("name") == "Idle");
auto &directionsElement = animationElement.GetChild("directions");
directionsElement.ConsiderAsArrayOf("direction");
REQUIRE(directionsElement.GetChildrenCount() == 1);
auto &directionElement = directionsElement.GetChild(0);
auto &spritesElement = directionElement.GetChild("sprites");
spritesElement.ConsiderAsArrayOf("sprite");
REQUIRE(spritesElement.GetChildrenCount() == 1);
auto &spriteElement = spritesElement.GetChild(0);
REQUIRE(spriteElement.GetStringAttribute("image") == "assets/Idle.png");
REQUIRE(objectAssetElement.HasChild("requiredExtensions"));
auto &requiredExtensionsElement =
objectAssetElement.GetChild("requiredExtensions");
requiredExtensionsElement.ConsiderAsArrayOf("requiredExtension");
REQUIRE(requiredExtensionsElement.GetChildrenCount() == 1);
auto &requiredExtensionElement = requiredExtensionsElement.GetChild(0);
REQUIRE(requiredExtensionElement.GetStringAttribute("extensionName") ==
"MyEventsExtension");
// Resources are renamed according to asset script naming conventions.
REQUIRE(objectAssetElement.HasChild("resources"));
auto &resourcesElement = objectAssetElement.GetChild("resources");
resourcesElement.ConsiderAsArrayOf("resource");
REQUIRE(resourcesElement.GetChildrenCount() == 1);
{
auto &resourceElement = resourcesElement.GetChild(0);
REQUIRE(resourceElement.GetStringAttribute("name") == "assets/Idle.png");
REQUIRE(resourceElement.GetStringAttribute("file") == "assets/Idle.png");
REQUIRE(resourceElement.GetStringAttribute("kind") == "image");
REQUIRE(resourceElement.GetBoolAttribute("smoothed") == true);
}
// Resources used in object configuration are updated.
REQUIRE(objectAssetElement.HasChild("object"));
auto &objectElement = objectAssetElement.GetChild("object");
REQUIRE(objectElement.GetStringAttribute("name") == "MyObject");
REQUIRE(objectElement.GetStringAttribute("type") ==
"MyEventsExtension::MyEventsBasedObject");
}
SECTION("Can serialize custom objects as assets with children overriding") {
SECTION("Can serialize custom objects as assets") {
gd::Platform platform;
gd::Project project;
SetupProjectWithDummyPlatform(project, platform);

View File

@@ -75,12 +75,11 @@ namespace gdjs {
instanceContainer: gdjs.RuntimeInstanceContainer
) {
const geometry = new THREE.BoxGeometry(1, 1, 1);
getFaceMaterial(runtimeObject, materialIndexToFaceIndex[0]);
const materials: THREE.Material[] = new Array(6)
.fill(0)
.map((_, index) =>
getFaceMaterial(runtimeObject, materialIndexToFaceIndex[index])
);
.map((_, index) => lavaMaterial);
const boxMesh = new THREE.Mesh(geometry, materials);
@@ -123,6 +122,7 @@ namespace gdjs {
this._cube3DRuntimeObject,
faceIndex
);
if (this._cube3DRuntimeObject.isFaceAtIndexVisible(faceIndex)) {
this.updateTextureUvMapping(faceIndex);
}

View File

@@ -21,9 +21,7 @@ module.exports = {
.setExtensionInformation(
'Scene3D',
_('3D'),
_(
'Support for 3D in GDevelop: this provides 3D objects and the common features for all 3D objects.'
),
_('Support for 3D in GDevelop.'),
'Florian Rival',
'MIT'
)
@@ -38,9 +36,7 @@ module.exports = {
'Base3DBehavior',
_('3D capability'),
'Object3D',
_(
'Common features for all 3D objects: position in 3D space (including the Z axis, in addition to X and Y), size (including depth, in addition to width and height), rotation (on X and Y axis, in addition to the Z axis), scale (including Z axis, in addition to X and Y), flipping (on Z axis, in addition to horizontal (Y)/vertical (X) flipping).'
),
_('Move the object in 3D space.'),
'',
'res/conditions/3d_box.svg',
'Base3DBehavior',

View File

@@ -618,7 +618,7 @@ module.exports = {
this._pixiObject.dirty = true;
}
if (this._instance.hasCustomSize() && this._pixiObject.width !== 0) {
if (this._instance.hasCustomSize()) {
const alignmentX =
object.content.align === 'right'
? 1

View File

@@ -103,7 +103,7 @@ namespace gdjs {
}
updatePosition(): void {
if (this._object.isWrapping() && this._pixiObject.width !== 0) {
if (this._object.isWrapping()) {
const alignmentX =
this._object._textAlign === 'right'
? 1

View File

@@ -376,7 +376,7 @@ namespace gdjs {
}
override getWidth(): float {
return this._wrapping ? this._wrappingWidth : this._renderer.getWidth();
return this._renderer.getWidth();
}
override getHeight(): float {

View File

@@ -721,7 +721,7 @@ module.exports = {
this._pixiObject.dirty = true;
}
if (this._instance.hasCustomSize() && this.getDefaultWidth() !== 0) {
if (this._instance.hasCustomSize()) {
const alignmentX =
object.content.align === 'right'
? 1
@@ -730,16 +730,17 @@ module.exports = {
: 0;
const width = this.getCustomWidth();
const renderedWidth = this.getDefaultWidth();
// A vector from the custom size center to the renderer center.
const centerToCenterX = (width - renderedWidth) * (alignmentX - 0.5);
const centerToCenterX =
(width - this._pixiObject.width) * (alignmentX - 0.5);
this._pixiObject.position.x = this._instance.getX() + width / 2;
this._pixiObject.anchor.x = 0.5 - centerToCenterX / renderedWidth;
this._pixiObject.anchor.x =
0.5 - centerToCenterX / this._pixiObject.width;
} else {
this._pixiObject.position.x =
this._instance.getX() + this.getDefaultWidth() / 2;
this._instance.getX() + this._pixiObject.width / 2;
this._pixiObject.anchor.x = 0.5;
}
const alignmentY =
@@ -749,7 +750,7 @@ module.exports = {
? 0.5
: 0;
this._pixiObject.position.y =
this._instance.getY() + this.getDefaultHeight() * (0.5 - alignmentY);
this._instance.getY() + this._pixiObject.height * (0.5 - alignmentY);
this._pixiObject.anchor.y = 0.5;
this._pixiObject.rotation = RenderedInstance.toRad(
@@ -773,11 +774,11 @@ module.exports = {
}
getDefaultWidth() {
return this._pixiObject.textWidth * this._pixiObject.scale.x;
return this._pixiObject.width;
}
getDefaultHeight() {
return this._pixiObject.textHeight * this._pixiObject.scale.y;
return this._pixiObject.height;
}
getOriginY() {

View File

@@ -146,7 +146,7 @@ namespace gdjs {
}
updatePosition(): void {
if (this._object.isWrapping() && this.getWidth() !== 0) {
if (this._object.isWrapping()) {
const alignmentX =
this._object._textAlign === 'right'
? 1
@@ -155,15 +155,17 @@ namespace gdjs {
: 0;
const width = this._object.getWrappingWidth();
const renderedWidth = this.getWidth();
// A vector from the custom size center to the renderer center.
const centerToCenterX = (width - renderedWidth) * (alignmentX - 0.5);
const centerToCenterX =
(width - this._pixiObject.width) * (alignmentX - 0.5);
this._pixiObject.position.x = this._object.x + width / 2;
this._pixiObject.anchor.x = 0.5 - centerToCenterX / renderedWidth;
this._pixiObject.anchor.x =
0.5 - centerToCenterX / this._pixiObject.width;
} else {
this._pixiObject.position.x = this._object.x + this.getWidth() / 2;
this._pixiObject.position.x =
this._object.x + this._pixiObject.width / 2;
this._pixiObject.anchor.x = 0.5;
}
@@ -174,7 +176,7 @@ namespace gdjs {
? 0.5
: 0;
this._pixiObject.position.y =
this._object.y + this.getHeight() * (0.5 - alignmentY);
this._object.y + this._pixiObject.height * (0.5 - alignmentY);
this._pixiObject.anchor.y = 0.5;
}

View File

@@ -419,7 +419,7 @@ namespace gdjs {
}
override getWidth(): float {
return this._wrapping ? this._wrappingWidth : this._renderer.getWidth();
return this._renderer.getWidth();
}
override getHeight(): float {

View File

@@ -46,7 +46,7 @@ namespace gdjs {
layer.getCameraY() + layer.getCameraHeight() / 2
) {
//We are outside the camera area.
this.owner.deleteFromScene();
this.owner.deleteFromScene(instanceContainer);
}
}

View File

@@ -50,11 +50,6 @@ describeIfOnline('Firebase extension end-to-end tests', function () {
.replace('.', '-')}-${Date.now()}`;
before(async function setupFirebase() {
// Delete any existing Firebase app before setup
if (firebase.apps.length !== 0) {
await firebase.app().delete();
}
await gdjs.evtTools.firebaseTools._setupFirebase({
getGame: () => ({
getExtensionProperty: () => JSON.stringify(firebaseConfig),

View File

@@ -1340,7 +1340,7 @@ namespace gdjs {
debugLogger.info(
`Destroying object ${objectName} with instance network ID ${instanceNetworkId}.`
);
instance.deleteFromScene();
instance.deleteFromScene(runtimeScene);
debugLogger.info(
`Sending acknowledgment of destruction of object ${objectName} with instance network ID ${instanceNetworkId} to ${messageSender}.`
@@ -2280,7 +2280,7 @@ namespace gdjs {
behavior.getActionOnPlayerDisconnect();
if (actionOnPlayerDisconnect === 'DestroyObject') {
// No need to remove the ownership, as the destroy message will be sent to all players.
instance.deleteFromScene();
instance.deleteFromScene(runtimeScene);
} else if (actionOnPlayerDisconnect === 'GiveOwnershipToHost') {
// Removing the ownership will send a message to all players.
behavior.removeObjectOwnership();

View File

@@ -99,7 +99,7 @@ namespace gdjs {
debugLogger.info(
`Lobby game is running on a synced scene and object ${owner.getName()} has not been assigned a networkId after a short delay, destroying it.`
);
owner.deleteFromScene();
owner.deleteFromScene(instanceContainer);
}
}, this._timeBeforeDestroyingObjectWithoutNetworkIdInMs);
}
@@ -262,7 +262,7 @@ namespace gdjs {
debugLogger.info(
`Player number ${this.playerNumber} does not exist in the lobby at the moment. Destroying the object.`
);
this.owner.deleteFromScene();
this.owner.deleteFromScene(this.owner.getInstanceContainer());
return;
}

View File

@@ -1130,7 +1130,7 @@ describe('Multiplayer', () => {
'MySpriteObject'
)[0];
p1SpriteObject1.deleteFromScene();
p1SpriteObject1.deleteFromScene(p1RuntimeScene);
p1RuntimeScene.renderAndStep(1000 / 60);
}
@@ -1297,7 +1297,7 @@ describe('Multiplayer', () => {
'MySpriteObject'
)[0];
p2SpriteObject1.deleteFromScene();
p2SpriteObject1.deleteFromScene(p2RuntimeScene);
p2RuntimeScene.renderAndStep(1000 / 60);
}

View File

@@ -20,10 +20,9 @@ void DeclareParticleSystemExtension(gd::PlatformExtension& extension) {
.SetExtensionInformation(
"ParticleSystem",
_("Particle system"),
"A 2D particle emitter allows to create various effects by showing a "
"A particle emitter allows to create various effects by showing a "
"lot of tiny images called particles. It's ideal for fires, smoke, "
"explosions, magical effects, etc... in 2D games. For 3D games, use "
"the 3D particle emitter instead.",
"explosions, magical effects, etc...",
"Florian Rival",
"Open source (MIT License)")
.SetCategory("Visual effect")
@@ -38,8 +37,8 @@ void DeclareParticleSystemExtension(gd::PlatformExtension& extension) {
.AddObject<ParticleEmitterObject>(
"ParticleEmitter",
_("Particles emitter"),
_("Displays a large number of small 2D particles to create "
"visual effects."),
_("Displays a large number of small particles to create visual "
"effects."),
"CppPlatform/Extensions/particleSystemicon.png")
.SetCategoryFullName(_("Visual effect"))
.AddDefaultBehavior("EffectCapability::EffectBehavior");

View File

@@ -560,7 +560,7 @@ namespace gdjs {
!this._isEmissionPaused &&
this._renderer._mayHaveEndedEmission()
) {
this.deleteFromScene();
this.deleteFromScene(instanceContainer);
}
if (
this.jumpForwardInTimeOnCreation > 0 &&

View File

@@ -24,7 +24,7 @@ describe('Physics2RuntimeBehavior', () => {
doStepPreEvents(runtimeScene) {
if (this.shouldDeleteInPreEvent) {
this.owner.deleteFromScene();
this.owner.deleteFromScene(runtimeScene);
}
}
}
@@ -159,7 +159,7 @@ describe('Physics2RuntimeBehavior', () => {
);
// Delete object from scene
object.deleteFromScene();
object.deleteFromScene(runtimeScene);
expect(behavior.destroyedDuringFrameLogic).to.be(true);
expect(behavior.getBody()).to.be(null);
expect(behavior._sharedData._registeredBehaviors.size).to.be(0);
@@ -194,7 +194,7 @@ describe('Physics2RuntimeBehavior', () => {
false
);
object.deleteFromScene();
object.deleteFromScene(runtimeScene);
expect(behavior.destroyedDuringFrameLogic).to.be(true);
expect(behavior.getBody()).to.be(null);
@@ -712,7 +712,7 @@ describe('Physics2RuntimeBehavior', () => {
// Destroy (handled by postEvent).
runtimeScene.renderAndStepWithEventsFunction(1000 / fps, () => {
movingObject.deleteFromScene();
movingObject.deleteFromScene(runtimeScene);
});
// Collision should be reset on destroyed object and

File diff suppressed because it is too large Load Diff

View File

@@ -305,14 +305,7 @@ namespace gdjs {
private shapeDimensionA: float;
private shapeDimensionB: float;
private shapeDimensionC: float;
private shapeOffsetX: float;
private shapeOffsetY: float;
shapeOffsetZ: float;
private massCenterOffsetX: float;
private massCenterOffsetY: float;
private massCenterOffsetZ: float;
private density: float;
massOverride: float;
friction: float;
restitution: float;
linearDamping: float;
@@ -320,7 +313,7 @@ namespace gdjs {
gravityScale: float;
private layers: integer;
private masks: integer;
shapeScale: number = 1;
private shapeScale: number = 1;
/**
* Array containing the beginning of contacts reported by onContactBegin. Each contact
@@ -355,10 +348,7 @@ namespace gdjs {
/**
* When set to `true` the shape will be recreated before the next physics step.
*/
_needToRecreateShape: boolean = false;
_shapeHalfWidth: float = 0;
_shapeHalfHeight: float = 0;
private _needToRecreateShape: boolean = false;
/**
* Used by {@link gdjs.PhysicsCharacter3DRuntimeBehavior} to convert coordinates.
*/
@@ -402,14 +392,7 @@ namespace gdjs {
this.shapeDimensionA = behaviorData.shapeDimensionA;
this.shapeDimensionB = behaviorData.shapeDimensionB;
this.shapeDimensionC = behaviorData.shapeDimensionC;
this.shapeOffsetX = behaviorData.shapeOffsetX || 0;
this.shapeOffsetY = behaviorData.shapeOffsetY || 0;
this.shapeOffsetZ = behaviorData.shapeOffsetZ || 0;
this.massCenterOffsetX = behaviorData.massCenterOffsetX || 0;
this.massCenterOffsetY = behaviorData.massCenterOffsetY || 0;
this.massCenterOffsetZ = behaviorData.massCenterOffsetZ || 0;
this.density = behaviorData.density;
this.massOverride = behaviorData.massOverride || 0;
this.friction = behaviorData.friction;
this.restitution = behaviorData.restitution;
this.linearDamping = Math.max(0, behaviorData.linearDamping);
@@ -651,39 +634,6 @@ namespace gdjs {
}
createShape(): Jolt.Shape {
if (
this.massCenterOffsetX === 0 &&
this.massCenterOffsetY === 0 &&
this.massCenterOffsetZ === 0
) {
return this.createShapeWithoutMassCenterOffset();
}
const rotatedShapeSettings =
this._createNewShapeSettingsWithoutMassCenterOffset();
const shapeScale = this.shapeScale * this._sharedData.worldInvScale;
const offsetCenterShapeSettings =
new Jolt.OffsetCenterOfMassShapeSettings(
this.getVec3(
this.massCenterOffsetX * shapeScale,
this.massCenterOffsetY * shapeScale,
this.massCenterOffsetZ * shapeScale
),
rotatedShapeSettings
);
const shape = offsetCenterShapeSettings.Create().Get();
Jolt.destroy(offsetCenterShapeSettings);
return shape;
}
createShapeWithoutMassCenterOffset(): Jolt.Shape {
const rotatedShapeSettings =
this._createNewShapeSettingsWithoutMassCenterOffset();
const shape = rotatedShapeSettings.Create().Get();
Jolt.destroy(rotatedShapeSettings);
return shape;
}
private _createNewShapeSettingsWithoutMassCenterOffset(): Jolt.RotatedTranslatedShapeSettings {
let width = this.owner3D.getWidth() * this._sharedData.worldInvScale;
let height = this.owner3D.getHeight() * this._sharedData.worldInvScale;
let depth = this.owner3D.getDepth() * this._sharedData.worldInvScale;
@@ -729,8 +679,6 @@ namespace gdjs {
convexRadius
);
quat = this.getQuat(0, 0, 0, 1);
this._shapeHalfWidth = boxWidth / 2;
this._shapeHalfHeight = boxHeight / 2;
this._shapeHalfDepth = boxDepth / 2;
} else if (this.shape === 'Capsule') {
const radius =
@@ -746,12 +694,8 @@ namespace gdjs {
radius
);
quat = this._getShapeOrientationQuat();
this._shapeHalfWidth =
this.shapeOrientation === 'X' ? capsuleDepth / 2 : radius;
this._shapeHalfHeight =
this.shapeOrientation === 'Y' ? capsuleDepth / 2 : radius;
this._shapeHalfDepth =
this.shapeOrientation === 'Z' ? capsuleDepth / 2 : radius;
this.shapeOrientation !== 'Z' ? radius : capsuleDepth / 2;
} else if (this.shape === 'Cylinder') {
const radius =
shapeDimensionA > 0
@@ -772,12 +716,8 @@ namespace gdjs {
convexRadius
);
quat = this._getShapeOrientationQuat();
this._shapeHalfWidth =
this.shapeOrientation === 'X' ? cylinderDepth / 2 : radius;
this._shapeHalfHeight =
this.shapeOrientation === 'Y' ? cylinderDepth / 2 : radius;
this._shapeHalfDepth =
this.shapeOrientation === 'Z' ? cylinderDepth / 2 : radius;
this.shapeOrientation !== 'Z' ? radius : cylinderDepth / 2;
} else {
// Create a 'Sphere' by default.
const radius =
@@ -788,20 +728,17 @@ namespace gdjs {
: onePixel;
shapeSettings = new Jolt.SphereShapeSettings(radius);
quat = this.getQuat(0, 0, 0, 1);
this._shapeHalfWidth = radius;
this._shapeHalfHeight = radius;
this._shapeHalfDepth = radius;
}
shapeSettings.mDensity = this.density;
return new Jolt.RotatedTranslatedShapeSettings(
this.getVec3(
this.shapeOffsetX * shapeScale,
this.shapeOffsetY * shapeScale,
this.shapeOffsetZ * shapeScale
),
const rotatedShapeSettings = new Jolt.RotatedTranslatedShapeSettings(
this.getVec3(0, 0, 0),
quat,
shapeSettings
);
const rotatedShape = rotatedShapeSettings.Create().Get();
Jolt.destroy(rotatedShapeSettings);
return rotatedShape;
}
private _getShapeOrientationQuat(): Jolt.Quat {
@@ -996,7 +933,7 @@ namespace gdjs {
);
}
_getPhysicsPosition(result: Jolt.RVec3): Jolt.RVec3 {
getPhysicsPosition(result: Jolt.RVec3): Jolt.RVec3 {
result.Set(
this.owner3D.getCenterXInScene() * this._sharedData.worldInvScale,
this.owner3D.getCenterYInScene() * this._sharedData.worldInvScale,
@@ -1005,7 +942,7 @@ namespace gdjs {
return result;
}
_getPhysicsRotation(result: Jolt.Quat): Jolt.Quat {
getPhysicsRotation(result: Jolt.Quat): Jolt.Quat {
const threeObject = this.owner3D.get3DRendererObject();
result.Set(
threeObject.quaternion.x,
@@ -1016,7 +953,7 @@ namespace gdjs {
return result;
}
_moveObjectToPhysicsPosition(physicsPosition: Jolt.RVec3): void {
moveObjectToPhysicsPosition(physicsPosition: Jolt.RVec3): void {
this.owner3D.setCenterXInScene(
physicsPosition.GetX() * this._sharedData.worldScale
);
@@ -1028,7 +965,7 @@ namespace gdjs {
);
}
_moveObjectToPhysicsRotation(physicsRotation: Jolt.Quat): void {
moveObjectToPhysicsRotation(physicsRotation: Jolt.Quat): void {
const threeObject = this.owner3D.get3DRendererObject();
threeObject.quaternion.x = physicsRotation.GetX();
threeObject.quaternion.y = physicsRotation.GetY();
@@ -1166,18 +1103,6 @@ namespace gdjs {
this._needToRecreateShape = true;
}
getMassOverride(): float {
return this.massOverride;
}
setMassOverride(mass: float): void {
if (this.massOverride === mass) {
return;
}
this.massOverride = mass;
this._needToRecreateBody = true;
}
getFriction(): float {
return this.friction;
}
@@ -1545,11 +1470,11 @@ namespace gdjs {
const deltaX = towardX - body.GetPosition().GetX();
const deltaY = towardY - body.GetPosition().GetY();
const deltaZ = towardZ - body.GetPosition().GetZ();
const distanceSq = deltaX * deltaX + deltaY * deltaY + deltaZ * deltaZ;
if (distanceSq === 0) {
const distance = deltaX * deltaX + deltaY * deltaY + deltaZ * deltaZ;
if (distance === 0) {
return;
}
const ratio = length / Math.sqrt(distanceSq);
const ratio = length / distance;
this._sharedData.bodyInterface.AddForce(
body.GetID(),
@@ -1615,11 +1540,11 @@ namespace gdjs {
const deltaX = towardX - originX;
const deltaY = towardY - originY;
const deltaZ = towardZ - originZ;
const distanceSq = deltaX * deltaX + deltaY * deltaY + deltaZ * deltaZ;
if (distanceSq === 0) {
const distance = deltaX * deltaX + deltaY * deltaY + deltaZ * deltaZ;
if (distance === 0) {
return;
}
const ratio = length / Math.sqrt(distanceSq);
const ratio = length / distance;
this._sharedData.bodyInterface.AddImpulse(
body.GetID(),
@@ -1859,8 +1784,8 @@ namespace gdjs {
const shape = behavior.createShape();
const bodyCreationSettings = new Jolt.BodyCreationSettings(
shape,
behavior._getPhysicsPosition(_sharedData.getRVec3(0, 0, 0)),
behavior._getPhysicsRotation(_sharedData.getQuat(0, 0, 0, 1)),
behavior.getPhysicsPosition(_sharedData.getRVec3(0, 0, 0)),
behavior.getPhysicsRotation(_sharedData.getQuat(0, 0, 0, 1)),
behavior.bodyType === 'Static'
? Jolt.EMotionType_Static
: behavior.bodyType === 'Kinematic'
@@ -1881,12 +1806,6 @@ namespace gdjs {
bodyCreationSettings.mLinearDamping = behavior.linearDamping;
bodyCreationSettings.mAngularDamping = behavior.angularDamping;
bodyCreationSettings.mGravityFactor = behavior.gravityScale;
if (behavior.massOverride > 0) {
bodyCreationSettings.mOverrideMassProperties =
Jolt.EOverrideMassProperties_CalculateInertia;
bodyCreationSettings.mMassPropertiesOverride.mMass =
behavior.massOverride;
}
const bodyInterface = _sharedData.bodyInterface;
const body = bodyInterface.CreateBody(bodyCreationSettings);
@@ -1905,8 +1824,8 @@ namespace gdjs {
// If the body is null, we just don't do anything
// (but still run the physics simulation - this is independent).
if (_body !== null && _body.IsActive()) {
behavior._moveObjectToPhysicsPosition(_body.GetPosition());
behavior._moveObjectToPhysicsRotation(_body.GetRotation());
behavior.moveObjectToPhysicsPosition(_body.GetPosition());
behavior.moveObjectToPhysicsRotation(_body.GetRotation());
}
}
@@ -1928,8 +1847,8 @@ namespace gdjs {
) {
_sharedData.bodyInterface.SetPositionAndRotationWhenChanged(
body.GetID(),
this.behavior._getPhysicsPosition(_sharedData.getRVec3(0, 0, 0)),
this.behavior._getPhysicsRotation(_sharedData.getQuat(0, 0, 0, 1)),
this.behavior.getPhysicsPosition(_sharedData.getRVec3(0, 0, 0)),
this.behavior.getPhysicsRotation(_sharedData.getQuat(0, 0, 0, 1)),
Jolt.EActivation_Activate
);
}

File diff suppressed because it is too large Load Diff

View File

@@ -323,7 +323,7 @@ namespace gdjs {
this._dontClearInputsBetweenFrames = true;
}
_getPhysicsPosition(result: Jolt.RVec3): Jolt.RVec3 {
getPhysicsPosition(result: Jolt.RVec3): Jolt.RVec3 {
const physics3D = this.getPhysics3D();
if (!physics3D) {
result.Set(0, 0, 0);
@@ -343,7 +343,7 @@ namespace gdjs {
return result;
}
_getPhysicsRotation(result: Jolt.Quat): Jolt.Quat {
getPhysicsRotation(result: Jolt.Quat): Jolt.Quat {
// Characters body should not rotate around X and Y.
const rotation = result.sEulerAngles(
this.getVec3(0, 0, gdjs.toRad(this.owner3D.getAngle()))
@@ -358,7 +358,7 @@ namespace gdjs {
return result;
}
_moveObjectToPhysicsPosition(physicsPosition: Jolt.RVec3): void {
moveObjectToPhysicsPosition(physicsPosition: Jolt.RVec3): void {
const physics3D = this.getPhysics3D();
if (!physics3D) {
return;
@@ -376,7 +376,7 @@ namespace gdjs {
);
}
_moveObjectToPhysicsRotation(physicsRotation: Jolt.Quat): void {
moveObjectToPhysicsRotation(physicsRotation: Jolt.Quat): void {
const threeObject = this.owner3D.get3DRendererObject();
threeObject.quaternion.x = physicsRotation.GetX();
threeObject.quaternion.y = physicsRotation.GetY();
@@ -1503,8 +1503,7 @@ namespace gdjs {
const { behavior } = physics3D;
const { _slopeMaxAngle, owner3D, _sharedData } = this.characterBehavior;
// Jolt doesn't support center of mass offset for characters.
const shape = behavior.createShapeWithoutMassCenterOffset();
const shape = behavior.createShape();
const settings = new Jolt.CharacterVirtualSettings();
// Characters innerBody are Kinematic body, they don't allow other
@@ -1543,10 +1542,10 @@ namespace gdjs {
);
const character = new Jolt.CharacterVirtual(
settings,
this.characterBehavior._getPhysicsPosition(
this.characterBehavior.getPhysicsPosition(
_sharedData.getRVec3(0, 0, 0)
),
behavior._getPhysicsRotation(_sharedData.getQuat(0, 0, 0, 1)),
behavior.getPhysicsRotation(_sharedData.getQuat(0, 0, 0, 1)),
_sharedData.physicsSystem
);
Jolt.destroy(settings);
@@ -1623,19 +1622,6 @@ namespace gdjs {
contactNormal,
settings
) => {};
characterContactListener.OnContactPersisted = (
inCharacter,
inBodyID2,
inSubShapeID2,
inContactPosition,
inContactNormal,
ioSettings
) => {};
characterContactListener.OnContactRemoved = (
inCharacter,
inBodyID2,
inSubShapeID2
) => {};
characterContactListener.OnCharacterContactAdded = (
character,
otherCharacter,
@@ -1644,19 +1630,6 @@ namespace gdjs {
contactNormal,
settings
) => {};
characterContactListener.OnCharacterContactPersisted = (
inCharacter,
inOtherCharacter,
inSubShapeID2,
inContactPosition,
inContactNormal,
ioSettings
) => {};
characterContactListener.OnCharacterContactRemoved = (
inCharacter,
inOtherCharacter,
inSubShapeID2
) => {};
characterContactListener.OnContactSolve = (
character,
bodyID2,
@@ -1693,10 +1666,10 @@ namespace gdjs {
return;
}
// We can't rely on the body position because of mCharacterPadding.
this.characterBehavior._moveObjectToPhysicsPosition(
this.characterBehavior.moveObjectToPhysicsPosition(
character.GetPosition()
);
this.characterBehavior._moveObjectToPhysicsRotation(
this.characterBehavior.moveObjectToPhysicsRotation(
character.GetRotation()
);
}
@@ -1724,7 +1697,7 @@ namespace gdjs {
behavior._objectOldRotationZ !== owner3D.getAngle()
) {
character.SetRotation(
this.characterBehavior._getPhysicsRotation(
this.characterBehavior.getPhysicsRotation(
_sharedData.getQuat(0, 0, 0, 1)
)
);
@@ -1737,7 +1710,7 @@ namespace gdjs {
return;
}
character.SetPosition(
this.characterBehavior._getPhysicsPosition(
this.characterBehavior.getPhysicsPosition(
_sharedData.getRVec3(0, 0, 0)
)
);
@@ -1759,7 +1732,7 @@ namespace gdjs {
if (!character) {
return;
}
const shape = behavior.createShapeWithoutMassCenterOffset();
const shape = behavior.createShape();
const isShapeValid = character.SetShape(
shape,
Number.MAX_VALUE,

View File

@@ -26,7 +26,6 @@ declare namespace Jolt {
size(): number;
}
class ArrayVec3 {
constructor();
empty(): boolean;
size(): number;
at(inIndex: number): Vec3;
@@ -37,7 +36,6 @@ declare namespace Jolt {
data(): Vec3MemRef;
}
class ArrayQuat {
constructor();
empty(): boolean;
size(): number;
at(inIndex: number): Quat;
@@ -48,7 +46,6 @@ declare namespace Jolt {
data(): QuatMemRef;
}
class ArrayMat44 {
constructor();
empty(): boolean;
size(): number;
at(inIndex: number): Mat44;
@@ -59,7 +56,6 @@ declare namespace Jolt {
data(): Mat44MemRef;
}
class ArrayBodyID {
constructor();
empty(): boolean;
size(): number;
at(inIndex: number): BodyID;
@@ -70,7 +66,6 @@ declare namespace Jolt {
data(): BodyIDMemRef;
}
class ArrayBodyPtr {
constructor();
empty(): boolean;
size(): number;
at(inIndex: number): Body;
@@ -436,13 +431,6 @@ declare namespace Jolt {
function _emscripten_enum_SoftBodySharedSettings_ELRAType_SoftBodySharedSettings_ELRAType_None(): SoftBodySharedSettings_ELRAType;
function _emscripten_enum_SoftBodySharedSettings_ELRAType_SoftBodySharedSettings_ELRAType_EuclideanDistance(): SoftBodySharedSettings_ELRAType;
function _emscripten_enum_SoftBodySharedSettings_ELRAType_SoftBodySharedSettings_ELRAType_GeodesicDistance(): SoftBodySharedSettings_ELRAType;
const MeshShapeSettings_EBuildQuality_FavorRuntimePerformance: number;
const MeshShapeSettings_EBuildQuality_FavorBuildSpeed: number;
type MeshShapeSettings_EBuildQuality =
| typeof MeshShapeSettings_EBuildQuality_FavorRuntimePerformance
| typeof MeshShapeSettings_EBuildQuality_FavorBuildSpeed;
function _emscripten_enum_MeshShapeSettings_EBuildQuality_MeshShapeSettings_EBuildQuality_FavorRuntimePerformance(): MeshShapeSettings_EBuildQuality;
function _emscripten_enum_MeshShapeSettings_EBuildQuality_MeshShapeSettings_EBuildQuality_FavorBuildSpeed(): MeshShapeSettings_EBuildQuality;
class Vec3MemRef {}
class QuatMemRef {}
class Mat44MemRef {}
@@ -456,7 +444,6 @@ declare namespace Jolt {
constructor(inV: Float3);
constructor(inX: number, inY: number, inZ: number);
sZero(): Vec3;
sOne(): Vec3;
sAxisX(): Vec3;
sAxisY(): Vec3;
sAxisZ(): Vec3;
@@ -518,7 +505,6 @@ declare namespace Jolt {
constructor();
constructor(inX: number, inY: number, inZ: number);
sZero(): RVec3;
sOne(): RVec3;
sAxisX(): RVec3;
sAxisY(): RVec3;
sAxisZ(): RVec3;
@@ -566,7 +552,6 @@ declare namespace Jolt {
constructor(inV: Vec3, inW: number);
constructor(inX: number, inY: number, inZ: number, inW: number);
sZero(): Vec4;
sOne(): Vec4;
sReplicate(inV: number): Vec4;
sMin(inLHS: Vec4, inRHS: Vec4): Vec4;
sMax(inLHS: Vec4, inRHS: Vec4): Vec4;
@@ -1442,9 +1427,6 @@ declare namespace Jolt {
get_mPerTriangleUserData(): boolean;
set_mPerTriangleUserData(mPerTriangleUserData: boolean): void;
mPerTriangleUserData: boolean;
get_mBuildQuality(): MeshShapeSettings_EBuildQuality;
set_mBuildQuality(mBuildQuality: MeshShapeSettings_EBuildQuality): void;
mBuildQuality: MeshShapeSettings_EBuildQuality;
}
class MeshShape extends Shape {
GetTriangleUserData(inSubShapeID: SubShapeID): number;
@@ -2541,8 +2523,6 @@ declare namespace Jolt {
GetGravityFactor(inBodyID: BodyID): number;
SetUseManifoldReduction(inBodyID: BodyID, inUseReduction: boolean): void;
GetUseManifoldReduction(inBodyID: BodyID): boolean;
SetCollisionGroup(inBodyID: BodyID, inCollisionGroup: CollisionGroup): void;
GetCollisionGroup(inBodyID: BodyID): CollisionGroup;
AddForce(
inBodyID: BodyID,
inForce: Vec3,
@@ -2644,9 +2624,9 @@ declare namespace Jolt {
get_mLinearCastMaxPenetration(): number;
set_mLinearCastMaxPenetration(mLinearCastMaxPenetration: number): void;
mLinearCastMaxPenetration: number;
get_mManifoldTolerance(): number;
set_mManifoldTolerance(mManifoldTolerance: number): void;
mManifoldTolerance: number;
get_mManifoldToleranceSq(): number;
set_mManifoldToleranceSq(mManifoldToleranceSq: number): void;
mManifoldToleranceSq: number;
get_mMaxPenetrationDistance(): number;
set_mMaxPenetrationDistance(mMaxPenetrationDistance: number): void;
mMaxPenetrationDistance: number;
@@ -3003,7 +2983,6 @@ declare namespace Jolt {
AddHit(inResult: number): void;
}
class ArrayRayCastResult {
constructor();
empty(): boolean;
size(): number;
at(inIndex: number): RayCastResult;
@@ -3061,7 +3040,6 @@ declare namespace Jolt {
AddHit(inResult: number): void;
}
class ArrayCollidePointResult {
constructor();
empty(): boolean;
size(): number;
at(inIndex: number): CollidePointResult;
@@ -3136,7 +3114,6 @@ declare namespace Jolt {
AddHit(inResult: number): void;
}
class ArrayCollideShapeResult {
constructor();
empty(): boolean;
size(): number;
at(inIndex: number): CollideShapeResult;
@@ -3211,7 +3188,6 @@ declare namespace Jolt {
AddHit(inResult: number): void;
}
class ArrayShapeCastResult {
constructor();
empty(): boolean;
size(): number;
at(inIndex: number): ShapeCastResult;
@@ -3642,7 +3618,6 @@ declare namespace Jolt {
mMaxDistance: number;
}
class ArraySoftBodySharedSettingsVertex {
constructor();
empty(): boolean;
size(): number;
at(inIndex: number): SoftBodySharedSettingsVertex;
@@ -3652,7 +3627,6 @@ declare namespace Jolt {
clear(): void;
}
class ArraySoftBodySharedSettingsFace {
constructor();
empty(): boolean;
size(): number;
at(inIndex: number): SoftBodySharedSettingsFace;
@@ -3662,7 +3636,6 @@ declare namespace Jolt {
clear(): void;
}
class ArraySoftBodySharedSettingsEdge {
constructor();
empty(): boolean;
size(): number;
at(inIndex: number): SoftBodySharedSettingsEdge;
@@ -3672,7 +3645,6 @@ declare namespace Jolt {
clear(): void;
}
class ArraySoftBodySharedSettingsDihedralBend {
constructor();
empty(): boolean;
size(): number;
at(inIndex: number): SoftBodySharedSettingsDihedralBend;
@@ -3682,7 +3654,6 @@ declare namespace Jolt {
clear(): void;
}
class ArraySoftBodySharedSettingsVolume {
constructor();
empty(): boolean;
size(): number;
at(inIndex: number): SoftBodySharedSettingsVolume;
@@ -3692,7 +3663,6 @@ declare namespace Jolt {
clear(): void;
}
class ArraySoftBodySharedSettingsInvBind {
constructor();
empty(): boolean;
size(): number;
at(inIndex: number): SoftBodySharedSettingsInvBind;
@@ -3702,7 +3672,6 @@ declare namespace Jolt {
clear(): void;
}
class ArraySoftBodySharedSettingsSkinned {
constructor();
empty(): boolean;
size(): number;
at(inIndex: number): SoftBodySharedSettingsSkinned;
@@ -3712,7 +3681,6 @@ declare namespace Jolt {
clear(): void;
}
class ArraySoftBodySharedSettingsLRA {
constructor();
empty(): boolean;
size(): number;
at(inIndex: number): SoftBodySharedSettingsLRA;
@@ -3740,7 +3708,6 @@ declare namespace Jolt {
mLRAMaxDistanceMultiplier: number;
}
class ArraySoftBodySharedSettingsVertexAttributes {
constructor();
empty(): boolean;
size(): number;
at(inIndex: number): SoftBodySharedSettingsVertexAttributes;
@@ -3889,7 +3856,6 @@ declare namespace Jolt {
readonly mVelocityOffset: number;
}
class ArraySoftBodyVertex {
constructor();
empty(): boolean;
size(): number;
at(inIndex: number): SoftBodyVertex;
@@ -3957,18 +3923,8 @@ declare namespace Jolt {
set_mShape(mShape: Shape): void;
mShape: Shape;
}
class CharacterID {
constructor();
GetValue(): number;
IsInvalid(): boolean;
sNextCharacterID(): CharacterID;
sSetNextCharacterID(inNextValue: number): void;
}
class CharacterVirtualSettings extends CharacterBaseSettings {
constructor();
get_mID(): CharacterID;
set_mID(mID: CharacterID): void;
mID: CharacterID;
get_mMass(): number;
set_mMass(mMass: number): void;
mMass: number;
@@ -4011,9 +3967,6 @@ declare namespace Jolt {
get_mInnerBodyShape(): Shape;
set_mInnerBodyShape(mInnerBodyShape: Shape): void;
mInnerBodyShape: Shape;
get_mInnerBodyIDOverride(): BodyID;
set_mInnerBodyIDOverride(mInnerBodyIDOverride: BodyID): void;
mInnerBodyIDOverride: BodyID;
get_mInnerBodyLayer(): number;
set_mInnerBodyLayer(mInnerBodyLayer: number): void;
mInnerBodyLayer: number;
@@ -4055,19 +4008,6 @@ declare namespace Jolt {
inContactNormal: number,
ioSettings: number
): void;
OnContactPersisted(
inCharacter: number,
inBodyID2: number,
inSubShapeID2: number,
inContactPosition: number,
inContactNormal: number,
ioSettings: number
): void;
OnContactRemoved(
inCharacter: number,
inBodyID2: number,
inSubShapeID2: number
): void;
OnCharacterContactAdded(
inCharacter: number,
inOtherCharacter: number,
@@ -4076,19 +4016,6 @@ declare namespace Jolt {
inContactNormal: number,
ioSettings: number
): void;
OnCharacterContactPersisted(
inCharacter: number,
inOtherCharacter: number,
inSubShapeID2: number,
inContactPosition: number,
inContactNormal: number,
ioSettings: number
): void;
OnCharacterContactRemoved(
inCharacter: number,
inOtherCharacter: number,
inSubShapeID2: number
): void;
OnContactSolve(
inCharacter: number,
inBodyID2: number,
@@ -4164,9 +4091,9 @@ declare namespace Jolt {
get_mBodyB(): BodyID;
set_mBodyB(mBodyB: BodyID): void;
mBodyB: BodyID;
get_mCharacterIDB(): CharacterID;
set_mCharacterIDB(mCharacterIDB: CharacterID): void;
mCharacterIDB: CharacterID;
get_mCharacterB(): CharacterVirtual;
set_mCharacterB(mCharacterB: CharacterVirtual): void;
mCharacterB: CharacterVirtual;
get_mSubShapeIDB(): SubShapeID;
set_mSubShapeIDB(mSubShapeIDB: SubShapeID): void;
mSubShapeIDB: SubShapeID;
@@ -4176,9 +4103,6 @@ declare namespace Jolt {
get_mIsSensorB(): boolean;
set_mIsSensorB(mIsSensorB: boolean): void;
mIsSensorB: boolean;
get_mCharacterB(): CharacterVirtual;
set_mCharacterB(mCharacterB: CharacterVirtual): void;
mCharacterB: CharacterVirtual;
get_mUserData(): number;
set_mUserData(mUserData: number): void;
mUserData: number;
@@ -4196,7 +4120,6 @@ declare namespace Jolt {
mCanPushCharacter: boolean;
}
class ArrayCharacterVirtualContact {
constructor();
empty(): boolean;
size(): number;
at(inIndex: number): CharacterVirtualContact;
@@ -4311,7 +4234,6 @@ declare namespace Jolt {
inRotation: Quat,
inSystem: PhysicsSystem
);
GetID(): CharacterID;
SetListener(inListener: CharacterContactListener): void;
SetCharacterVsCharacterCollision(
inCharacterVsCharacterCollision: CharacterVsCharacterCollision
@@ -4343,8 +4265,6 @@ declare namespace Jolt {
GetUserData(): number;
SetUserData(inUserData: number): void;
GetInnerBodyID(): BodyID;
StartTrackingContactChanges(): void;
FinishTrackingContactChanges(): void;
CancelVelocityTowardsSteepSlopes(inDesiredVelocity: Vec3): Vec3;
Update(
inDeltaTime: number,
@@ -4406,7 +4326,6 @@ declare namespace Jolt {
SetInnerBodyShape(inShape: Shape): void;
GetTransformedShape(): TransformedShape;
HasCollidedWith(inBodyID: BodyID): boolean;
HasCollidedWithCharacterID(inCharacterID: CharacterID): boolean;
HasCollidedWithCharacter(inCharacter: CharacterVirtual): boolean;
GetActiveContacts(): ArrayCharacterVirtualContact;
}
@@ -4421,7 +4340,6 @@ declare namespace Jolt {
GetValue(inX: number): number;
}
class ArrayFloat {
constructor();
empty(): boolean;
size(): number;
at(inIndex: number): number;
@@ -4432,7 +4350,6 @@ declare namespace Jolt {
data(): FloatMemRef;
}
class ArrayUint {
constructor();
empty(): boolean;
size(): number;
at(inIndex: number): number;
@@ -4443,7 +4360,6 @@ declare namespace Jolt {
data(): UintMemRef;
}
class ArrayUint8 {
constructor();
empty(): boolean;
size(): number;
at(inIndex: number): number;
@@ -4454,7 +4370,6 @@ declare namespace Jolt {
data(): Uint8MemRef;
}
class ArrayVehicleAntiRollBar {
constructor();
empty(): boolean;
size(): number;
at(inIndex: number): VehicleAntiRollBar;
@@ -4463,7 +4378,6 @@ declare namespace Jolt {
clear(): void;
}
class ArrayWheelSettings {
constructor();
empty(): boolean;
size(): number;
at(inIndex: number): WheelSettings;
@@ -4472,7 +4386,6 @@ declare namespace Jolt {
clear(): void;
}
class ArrayVehicleDifferentialSettings {
constructor();
empty(): boolean;
size(): number;
at(inIndex: number): VehicleDifferentialSettings;
@@ -4544,7 +4457,6 @@ declare namespace Jolt {
inWheelRight: Vec3,
inWheelUp: Vec3
): RMat44;
GetAntiRollBars(): ArrayVehicleAntiRollBar;
SetNumStepsBetweenCollisionTestActive(inSteps: number): void;
GetNumStepsBetweenCollisionTestActive(): number;
SetNumStepsBetweenCollisionTestInactive(inSteps: number): void;
@@ -4907,6 +4819,9 @@ declare namespace Jolt {
}
class VehicleControllerSettings {}
class VehicleController {
GetRefCount(): number;
AddRef(): void;
Release(): void;
GetConstraint(): VehicleConstraint;
}
class WheeledVehicleController extends VehicleController {

File diff suppressed because it is too large Load Diff

View File

@@ -23,9 +23,7 @@ void DeclarePlatformBehaviorExtension(gd::PlatformExtension& extension) {
"held, customizable gravity... It can be used for the player, but "
"also for other objects moving on platforms. In this case though, "
"it's recommended to first check if there is a simpler behavior that "
"could be used. Default controls for keyboards are included. For "
"touch or gamepads, use the \"Multitouch Joystick\" objects and the "
"associated \"mapper\" behaviors.",
"could be used.",
"Florian Rival",
"Open source (MIT License)")
.SetCategory("Movement")
@@ -35,16 +33,16 @@ void DeclarePlatformBehaviorExtension(gd::PlatformExtension& extension) {
.SetIcon("CppPlatform/Extensions/platformerobjecticon.png");
{
gd::BehaviorMetadata& aut =
extension.AddBehavior("PlatformerObjectBehavior",
_("Platformer character"),
"PlatformerObject",
_("Jump and run on platforms."),
"",
"CppPlatform/Extensions/platformerobjecticon.png",
"PlatformerObjectBehavior",
std::make_shared<PlatformerObjectBehavior>(),
std::make_shared<gd::BehaviorsSharedData>());
gd::BehaviorMetadata& aut = extension.AddBehavior(
"PlatformerObjectBehavior",
_("Platformer character"),
"PlatformerObject",
_("Jump and run on platforms."),
"",
"CppPlatform/Extensions/platformerobjecticon.png",
"PlatformerObjectBehavior",
std::make_shared<PlatformerObjectBehavior>(),
std::make_shared<gd::BehaviorsSharedData>());
// Deprecated, use IsMovingEvenALittle instead
aut.AddCondition("IsMoving",
@@ -61,15 +59,14 @@ void DeclarePlatformBehaviorExtension(gd::PlatformExtension& extension) {
.MarkAsSimple()
.SetFunctionName("IsMoving");
aut.AddScopedCondition(
"IsMovingEvenALittle",
_("Is moving"),
_("Check if the object is moving (whether it is on the "
"floor or in the air)."),
_("_PARAM0_ is moving"),
_("Platformer state"),
"CppPlatform/Extensions/platformerobjecticon.png",
"CppPlatform/Extensions/platformerobjecticon.png")
aut.AddScopedCondition("IsMovingEvenALittle",
_("Is moving"),
_("Check if the object is moving (whether it is on the "
"floor or in the air)."),
_("_PARAM0_ is moving"),
_("Platformer state"),
"CppPlatform/Extensions/platformerobjecticon.png",
"CppPlatform/Extensions/platformerobjecticon.png")
.AddParameter("object", _("Object"))
.AddParameter("behavior", _("Behavior"), "PlatformerObjectBehavior")
.MarkAsSimple();
@@ -528,14 +525,14 @@ void DeclarePlatformBehaviorExtension(gd::PlatformExtension& extension) {
.MarkAsAdvanced()
.SetFunctionName("SimulateLadderKey");
aut.AddAction("SimulateReleaseLadderKey",
_("Simulate release ladder key press"),
_("Simulate a press of the Release Ladder key (used to get "
"off a ladder)."),
_("Simulate pressing Release Ladder key for _PARAM0_"),
_("Platformer controls"),
"res/conditions/keyboard24.png",
"res/conditions/keyboard.png")
aut.AddAction(
"SimulateReleaseLadderKey",
_("Simulate release ladder key press"),
_("Simulate a press of the Release Ladder key (used to get off a ladder)."),
_("Simulate pressing Release Ladder key for _PARAM0_"),
_("Platformer controls"),
"res/conditions/keyboard24.png",
"res/conditions/keyboard.png")
.AddParameter("object", _("Object"))
.AddParameter("behavior", _("Behavior"), "PlatformerObjectBehavior")
.MarkAsAdvanced();
@@ -553,8 +550,7 @@ void DeclarePlatformBehaviorExtension(gd::PlatformExtension& extension) {
aut.AddAction("SimulateReleasePlatformKey",
_("Simulate release platform key press"),
_("Simulate a press of the release platform key (used when "
"grabbing a "
_("Simulate a press of the release platform key (used when grabbing a "
"platform ledge)."),
_("Simulate pressing Release Platform key for _PARAM0_"),
_("Platformer controls"),
@@ -565,8 +561,7 @@ void DeclarePlatformBehaviorExtension(gd::PlatformExtension& extension) {
.SetFunctionName("SimulateReleasePlatformKey");
// Support for deprecated names:
aut.AddDuplicatedAction("SimulateReleaseKey", "SimulateReleasePlatformKey")
.SetHidden();
aut.AddDuplicatedAction("SimulateReleaseKey", "SimulateReleasePlatformKey").SetHidden();
aut.AddAction("SimulateControl",
_("Simulate control"),
@@ -579,27 +574,23 @@ void DeclarePlatformBehaviorExtension(gd::PlatformExtension& extension) {
.AddParameter("object", _("Object"))
.AddParameter("behavior", _("Behavior"), "PlatformerObjectBehavior")
.AddParameter("stringWithSelector",
_("Key"),
"[\"Left\", \"Right\", \"Jump\", \"Ladder\", \"Release "
"Ladder\", \"Up\", \"Down\"]")
_("Key"),
"[\"Left\", \"Right\", \"Jump\", \"Ladder\", \"Release Ladder\", \"Up\", \"Down\"]")
.MarkAsAdvanced()
.SetFunctionName("SimulateControl");
aut.AddScopedCondition(
"IsUsingControl",
_("Control pressed or simulated"),
_("A control was applied from a default control or simulated by an "
"action."),
_("_PARAM0_ has the _PARAM2_ key pressed or simulated"),
_("Platformer state"),
"res/conditions/keyboard24.png",
"res/conditions/keyboard.png")
aut.AddScopedCondition("IsUsingControl",
_("Control pressed or simulated"),
_("A control was applied from a default control or simulated by an action."),
_("_PARAM0_ has the _PARAM2_ key pressed or simulated"),
_("Platformer state"),
"res/conditions/keyboard24.png",
"res/conditions/keyboard.png")
.AddParameter("object", _("Object"))
.AddParameter("behavior", _("Behavior"), "PlatformerObjectBehavior")
.AddParameter("stringWithSelector",
_("Key"),
"[\"Left\", \"Right\", \"Jump\", \"Ladder\", \"Release "
"Ladder\", \"Up\", \"Down\"]")
_("Key"),
"[\"Left\", \"Right\", \"Jump\", \"Ladder\", \"Release Ladder\", \"Up\", \"Down\"]")
.MarkAsAdvanced();
aut.AddAction("IgnoreDefaultControls",
@@ -801,65 +792,59 @@ void DeclarePlatformBehaviorExtension(gd::PlatformExtension& extension) {
.AddParameter("behavior", _("Behavior"), "PlatformerObjectBehavior")
.SetFunctionName("GetJumpSpeed");
aut.AddExpression(
"JumpSustainTime",
_("Jump sustain time"),
_("Return the jump sustain time of the object (in seconds)."
"This is the time during which keeping the jump button held "
"allow the initial jump speed to be maintained."),
_("Platformer configuration"),
"CppPlatform/Extensions/platformerobjecticon.png")
aut.AddExpression("JumpSustainTime",
_("Jump sustain time"),
_("Return the jump sustain time of the object (in seconds)."
"This is the time during which keeping the jump button held "
"allow the initial jump speed to be maintained."),
_("Platformer configuration"),
"CppPlatform/Extensions/platformerobjecticon.png")
.AddParameter("object", _("Object"))
.AddParameter("behavior", _("Behavior"), "PlatformerObjectBehavior");
aut.AddExpression(
"CurrentFallSpeed",
_("Current fall speed"),
_("Return the current fall speed of the object "
"(in pixels per second). Its value is always positive."),
_("Platformer state"),
"CppPlatform/Extensions/platformerobjecticon.png")
aut.AddExpression("CurrentFallSpeed",
_("Current fall speed"),
_("Return the current fall speed of the object "
"(in pixels per second). Its value is always positive."),
_("Platformer state"),
"CppPlatform/Extensions/platformerobjecticon.png")
.AddParameter("object", _("Object"))
.AddParameter("behavior", _("Behavior"), "PlatformerObjectBehavior")
.SetFunctionName("GetCurrentFallSpeed");
aut.AddExpression(
"CurrentSpeed",
_("Current horizontal speed"),
_("Return the current horizontal speed of the object "
"(in pixels per second). The object moves to the left "
"with negative values and to the right with positive ones"),
_("Platformer state"),
"CppPlatform/Extensions/platformerobjecticon.png")
aut.AddExpression("CurrentSpeed",
_("Current horizontal speed"),
_("Return the current horizontal speed of the object "
"(in pixels per second). The object moves to the left "
"with negative values and to the right with positive ones"),
_("Platformer state"),
"CppPlatform/Extensions/platformerobjecticon.png")
.AddParameter("object", _("Object"))
.AddParameter("behavior", _("Behavior"), "PlatformerObjectBehavior")
.SetFunctionName("GetCurrentSpeed");
aut.AddExpression(
"CurrentJumpSpeed",
_("Current jump speed"),
_("Return the current jump speed of the object "
"(in pixels per second). Its value is always positive."),
_("Platformer state"),
"CppPlatform/Extensions/platformerobjecticon.png")
aut.AddExpression("CurrentJumpSpeed",
_("Current jump speed"),
_("Return the current jump speed of the object "
"(in pixels per second). Its value is always positive."),
_("Platformer state"),
"CppPlatform/Extensions/platformerobjecticon.png")
.AddParameter("object", _("Object"))
.AddParameter("behavior", _("Behavior"), "PlatformerObjectBehavior")
.SetFunctionName("GetCurrentJumpSpeed");
}
{
gd::BehaviorMetadata& aut =
extension
.AddBehavior("PlatformBehavior",
_("Platform"),
"Platform",
_("Flag objects as being platforms which characters "
"can run on."),
"",
"CppPlatform/Extensions/platformicon.png",
"PlatformBehavior",
std::make_shared<PlatformBehavior>(),
std::make_shared<gd::BehaviorsSharedData>())
.SetQuickCustomizationVisibility(gd::QuickCustomization::Hidden);
gd::BehaviorMetadata& aut = extension.AddBehavior(
"PlatformBehavior",
_("Platform"),
"Platform",
_("Flag objects as being platforms which characters can run on."),
"",
"CppPlatform/Extensions/platformicon.png",
"PlatformBehavior",
std::make_shared<PlatformBehavior>(),
std::make_shared<gd::BehaviorsSharedData>())
.SetQuickCustomizationVisibility(gd::QuickCustomization::Hidden);
aut.AddAction("ChangePlatformType",
_("Platform type"),
@@ -872,23 +857,21 @@ void DeclarePlatformBehaviorExtension(gd::PlatformExtension& extension) {
.AddParameter("object", _("Object"))
.AddParameter("behavior", _("Behavior"), "PlatformBehavior")
.AddParameter("stringWithSelector",
_("Platform type"),
"[\"Platform\",\"Jumpthru\",\"Ladder\"]")
_("Platform type"),
"[\"Platform\",\"Jumpthru\",\"Ladder\"]")
.MarkAsAdvanced()
.SetFunctionName("ChangePlatformType");
}
extension
.AddCondition(
"IsObjectOnGivenFloor",
_("Character is on given platform"),
_("Check if a platformer character is on a given platform."),
_("_PARAM0_ is on platform _PARAM2_"),
_("Collision"),
"CppPlatform/Extensions/platformicon.png",
"CppPlatform/Extensions/platformicon.png")
.AddParameter("objectList", _("Object"), "", false)
.AddParameter("behavior", _("Behavior"), "PlatformerObjectBehavior")
.AddParameter("objectList", _("Platforms"), "", false)
.AddCodeOnlyParameter("conditionInverted", "");
extension.AddCondition("IsObjectOnGivenFloor",
_("Character is on given platform"),
_("Check if a platformer character is on a given platform."),
_("_PARAM0_ is on platform _PARAM2_"),
_("Collision"),
"CppPlatform/Extensions/platformicon.png",
"CppPlatform/Extensions/platformicon.png")
.AddParameter("objectList", _("Object"), "", false)
.AddParameter("behavior", _("Behavior"), "PlatformerObjectBehavior")
.AddParameter("objectList", _("Platforms"), "", false)
.AddCodeOnlyParameter("conditionInverted", "");
}

View File

@@ -146,7 +146,7 @@ describe('gdjs.TextInputRuntimeObject (using a PixiJS RuntimeGame with DOM eleme
expect(gameDomElementContainer.querySelector('input')).not.to.be(null);
expect(gameDomElementContainer.querySelector('textarea')).to.be(null);
object.deleteFromScene();
object.deleteFromScene(runtimeScene);
runtimeScene.renderAndStep(1000 / 60);
expect(gameDomElementContainer.querySelector('input')).to.be(null);
expect(gameDomElementContainer.querySelector('textarea')).to.be(null);

View File

@@ -98,7 +98,7 @@ namespace gdjs {
}
updatePosition(): void {
if (this._object.isWrapping() && this._text.width !== 0) {
if (this._object.isWrapping()) {
const alignmentX =
this._object._textAlign === 'right'
? 1
@@ -117,6 +117,7 @@ namespace gdjs {
this._text.position.x = this._object.x + this._text.width / 2;
this._text.anchor.x = 0.5;
}
this._text.position.y = this._object.y + this._text.height / 2;
const alignmentY =
this._object._verticalTextAlignment === 'bottom'

View File

@@ -89,7 +89,7 @@ namespace gdjs {
}
private _deleteFromScene() {
this.owner.deleteFromScene();
this.owner.deleteFromScene(this.owner.getInstanceContainer());
}
/**

View File

@@ -105,14 +105,7 @@ namespace gdjs {
return;
}
if (!eventsBasedObjectData.defaultVariant) {
eventsBasedObjectData.defaultVariant = {
...eventsBasedObjectData,
name: '',
};
}
let usedVariantData: EventsBasedObjectVariantData =
eventsBasedObjectData.defaultVariant;
let usedVariantData: EventsBasedObjectVariantData = eventsBasedObjectData;
if (customObjectData.variant) {
for (
let variantIndex = 0;
@@ -206,13 +199,13 @@ namespace gdjs {
}
}
override onDeletedFromScene(): void {
override onDeletedFromScene(parent: gdjs.RuntimeInstanceContainer): void {
// Let subclasses do something before the object is destroyed.
this.onDestroy(this._runtimeScene);
this.onDestroy(parent);
// Let behaviors do something before the object is destroyed.
super.onDeletedFromScene();
super.onDeletedFromScene(parent);
// Destroy the children.
this._instanceContainer.onDestroyFromScene(this._runtimeScene);
this._instanceContainer.onDestroyFromScene(parent);
}
override update(parent: gdjs.RuntimeInstanceContainer): void {

View File

@@ -80,11 +80,7 @@ namespace gdjs {
++i
) {
const childObjectData = eventsBasedObjectVariantData.objects[i];
// The children configuration override only applies to the default variant.
if (
customObjectData.childrenContent &&
!eventsBasedObjectVariantData.name
) {
if (customObjectData.childrenContent) {
this.registerObject({
...childObjectData,
// The custom object overrides its events-based object configuration.
@@ -187,7 +183,7 @@ namespace gdjs {
const allInstancesList = this.getAdhocListOfAllInstances();
for (let i = 0, len = allInstancesList.length; i < len; ++i) {
const object = allInstancesList[i];
object.onDeletedFromScene();
object.onDeletedFromScene(this);
// The object can free all its resource directly...
object.onDestroyed();
}

View File

@@ -678,7 +678,7 @@ namespace gdjs {
}
// Notify the object it was removed from the container
obj.onDeletedFromScene();
obj.onDeletedFromScene(this);
// Notify the global callbacks
for (let j = 0; j < gdjs.callbacksObjectDeletedFromScene.length; ++j) {

View File

@@ -1376,7 +1376,7 @@ namespace gdjs {
) {
// Instance was deleted (or object name changed, in which case it will be re-created later)
if (runtimeObject) {
runtimeObject.deleteFromScene();
runtimeObject.deleteFromScene(runtimeInstanceContainer);
}
} else {
}

View File

@@ -224,7 +224,8 @@ namespace gdjs {
let yOffset = 0;
if (anticipateMove && !object.hasNoForces()) {
const objectAverageForce = object.getAverageForce();
const elapsedTimeInSeconds = object.getElapsedTime() / 1000;
const elapsedTimeInSeconds =
object.getElapsedTime(instanceContainer) / 1000;
xOffset = objectAverageForce.getX() * elapsedTimeInSeconds;
yOffset = objectAverageForce.getY() * elapsedTimeInSeconds;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 80 KiB

View File

@@ -3,6 +3,7 @@
* Copyright 2013-2016 Florian Rival (Florian.Rival@gmail.com). All rights reserved.
* This project is released under the MIT License.
*/
let lavaMaterial: THREE.ShaderMaterial;
namespace gdjs {
const logger = new gdjs.Logger('PIXI Image manager');
@@ -234,29 +235,96 @@ namespace gdjs {
vertexColors: boolean;
}
): THREE.Material {
const cacheKey = `${resourceName}|${useTransparentTexture ? 1 : 0}|${
forceBasicMaterial ? 1 : 0
}|${vertexColors ? 1 : 0}`;
// const cacheKey = `${resourceName}|${useTransparentTexture ? 1 : 0}|${
// forceBasicMaterial ? 1 : 0
// }`;
const loadedThreeMaterial = this._loadedThreeMaterials.get(cacheKey);
if (loadedThreeMaterial) return loadedThreeMaterial;
// const loadedThreeMaterial = this._loadedThreeMaterials.get(cacheKey);
// if (loadedThreeMaterial) return loadedThreeMaterial;
const material = forceBasicMaterial
? new THREE.MeshBasicMaterial({
map: this.getThreeTexture(resourceName),
side: useTransparentTexture ? THREE.DoubleSide : THREE.FrontSide,
transparent: useTransparentTexture,
vertexColors,
})
: new THREE.MeshStandardMaterial({
map: this.getThreeTexture(resourceName),
side: useTransparentTexture ? THREE.DoubleSide : THREE.FrontSide,
transparent: useTransparentTexture,
metalness: 0,
vertexColors,
});
this._loadedThreeMaterials.put(cacheKey, material);
return material;
// const material = forceBasicMaterial
// ? new THREE.MeshBasicMaterial({
// map: this.getThreeTexture(resourceName),
// side: useTransparentTexture ? THREE.DoubleSide : THREE.FrontSide,
// transparent: useTransparentTexture,
// vertexColors: true,
// })
// : new THREE.MeshStandardMaterial({
// map: this.getThreeTexture(resourceName),
// side: useTransparentTexture ? THREE.DoubleSide : THREE.FrontSide,
// transparent: useTransparentTexture,
// metalness: 0,
// vertexColors: true,
// });
// this._loadedThreeMaterials.put(cacheKey, material);
let tex1 = new THREE.TextureLoader().load(
'C:/Users/Utilisateur/Desktop/Gdevelop/GDevelop/GDJS/Runtime/pixi-renderers/cloudLava.png'
);
tex1.wrapS = THREE.RepeatWrapping;
tex1.wrapT = THREE.RepeatWrapping;
let text2 = new THREE.TextureLoader().load(
'C:/Users/Utilisateur/Desktop/Gdevelop/GDevelop/GDJS/Runtime/pixi-renderers/tileLava.jpg'
);
text2.wrapS = THREE.RepeatWrapping;
text2.wrapT = THREE.RepeatWrapping;
lavaMaterial = new THREE.ShaderMaterial({
uniforms: {
time: { value: time },
fogDensity: { value: 0.001 },
fogColor: { value: new THREE.Vector3(0.1, 0.1, 0.1) },
texture1: { value: tex1 },
texture2: { value: text2 },
uvScale: { value: new THREE.Vector2(1, 1) },
},
vertexShader: `uniform vec2 uvScale;
varying vec2 vUv;
void main()
{
vUv = uvScale * uv;
vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );
gl_Position = projectionMatrix * mvPosition;
}`,
fragmentShader: `uniform float time;
uniform float fogDensity;
uniform vec3 fogColor;
uniform sampler2D texture1;
uniform sampler2D texture2;
varying vec2 vUv;
void main( void ) {
vec2 position = -1.0 + 2.0 * vUv;
vec4 noise = texture2D( texture1, vUv );
vec2 T1 = vUv + vec2( 1.5, - 1.5 ) * time * 0.02;
vec2 T2 = vUv + vec2( - 0.5, 2.0 ) * time * 0.01;
T1.x += noise.x * 2.0;
T1.y += noise.y * 2.0;
T2.x -= noise.y * 0.2;
T2.y += noise.z * 0.2;
float p = texture2D( texture1, T1 * 2.0 ).a;
vec4 color = texture2D( texture2, T2 * 2.0 );
vec4 temp = color * ( vec4( p, p, p, p ) * 2.0 ) + ( color * color - 0.1 );
if( temp.r > 1.0 ) { temp.bg += clamp( temp.r - 2.0, 0.0, 100.0 ); }
if( temp.g > 1.0 ) { temp.rb += temp.g - 1.0; }
if( temp.b > 1.0 ) { temp.rg += temp.b - 1.0; }
gl_FragColor = temp;
float depth = gl_FragCoord.z / gl_FragCoord.w;
const float LOG2 = 1.442695;
float fogFactor = exp2( - fogDensity * fogDensity * depth * depth * LOG2 );
fogFactor = 1.0 - clamp( fogFactor, 0.0, 1.0 );
gl_FragColor = mix( gl_FragColor, vec4( fogColor, gl_FragColor.w ), fogFactor );
}`,
});
return lavaMaterial;
}
/**

Binary file not shown.

After

Width:  |  Height:  |  Size: 545 KiB

View File

@@ -382,8 +382,10 @@ namespace gdjs {
* in milliseconds, for the object.
*
* Objects can have different elapsed time if they are on layers with different time scales.
*
* @param instanceContainer The instance container the object belongs to (deprecated - can be omitted).
*/
getElapsedTime(): float {
getElapsedTime(instanceContainer?: gdjs.RuntimeInstanceContainer): float {
const theLayer = this._runtimeScene.getLayer(this.layer);
return theLayer.getElapsedTime();
}
@@ -597,10 +599,11 @@ namespace gdjs {
* Remove an object from a scene.
*
* Do not change/redefine this method. Instead, redefine the onDestroyFromScene method.
* @param instanceContainer The container owning the object.
*/
deleteFromScene(): void {
deleteFromScene(instanceContainer: gdjs.RuntimeInstanceContainer): void {
if (this._livingOnScene) {
this._runtimeScene.markObjectForDeletion(this);
instanceContainer.markObjectForDeletion(this);
this._livingOnScene = false;
}
}
@@ -617,9 +620,11 @@ namespace gdjs {
* Called when the object is destroyed (because it is removed from a scene or the scene
* is being unloaded). If you redefine this function, **make sure to call the original method**
* (`RuntimeObject.prototype.onDestroyFromScene.call(this, runtimeScene);`).
*
* @param instanceContainer The container owning the object.
*/
onDeletedFromScene(): void {
const theLayer = this._runtimeScene.getLayer(this.layer);
onDeletedFromScene(instanceContainer: gdjs.RuntimeInstanceContainer): void {
const theLayer = instanceContainer.getLayer(this.layer);
const rendererObject = this.getRendererObject();
if (rendererObject) {
theLayer.getRenderer().removeRendererObject(rendererObject);
@@ -792,7 +797,12 @@ namespace gdjs {
return this.getY();
}
rotateTowardPosition(x: float, y: float, speed: float): void {
rotateTowardPosition(
x: float,
y: float,
speed: float,
scene: gdjs.RuntimeScene
): void {
this.rotateTowardAngle(
gdjs.toDegrees(
Math.atan2(
@@ -800,15 +810,21 @@ namespace gdjs {
x - (this.getDrawableX() + this.getCenterX())
)
),
speed
speed,
scene
);
}
/**
* @param angle The targeted direction angle.
* @param speed The rotation speed.
* @param instanceContainer The container the object belongs to (deprecated - can be omitted).
*/
rotateTowardAngle(angle: float, speed: float): void {
rotateTowardAngle(
angle: float,
speed: float,
instanceContainer?: gdjs.RuntimeInstanceContainer
): void {
if (speed === 0) {
this.setAngle(angle);
return;
@@ -847,7 +863,10 @@ namespace gdjs {
* @param speed The speed, in degrees per second.
* @param instanceContainer The container the object belongs to (deprecated - can be omitted).
*/
rotate(speed: float): void {
rotate(
speed: float,
instanceContainer?: gdjs.RuntimeInstanceContainer
): void {
this.setAngle(this.getAngle() + (speed * this.getElapsedTime()) / 1000);
}

View File

@@ -284,7 +284,7 @@ namespace gdjs {
const allInstancesList = this.getAdhocListOfAllInstances();
for (let i = 0, len = allInstancesList.length; i < len; ++i) {
const object = allInstancesList[i];
object.onDeletedFromScene();
object.onDeletedFromScene(this);
object.onDestroyed();
}

View File

@@ -1,5 +1,6 @@
let time = 0.0;
namespace gdjs {
const logger = new gdjs.Logger('Scene stack');
const debugLogger = new gdjs.Logger('Multiplayer - Debug');
/**
@@ -35,6 +36,8 @@ namespace gdjs {
}
step(elapsedTime: float): boolean {
time += this._stack[0].getTimeManager().getElapsedTime() / 100;
lavaMaterial.uniforms.time.value = time;
this._throwIfDisposed();
if (this._isNextLayoutLoading || this._stack.length === 0) {
return false;
@@ -68,10 +71,8 @@ namespace gdjs {
} else if (request === gdjs.SceneChangeRequest.CLEAR_SCENES) {
this.replace(currentScene.getRequestedScene(), true);
} else {
logger.error('Unrecognized change in scene stack: ' + request);
}
}
return true;
}

View File

@@ -945,16 +945,18 @@ namespace gdjs {
//Other :
/**
* @param obj The target object
* @param scene The scene containing the object
* @deprecated
*/
turnTowardObject(obj: gdjs.RuntimeObject | null) {
turnTowardObject(obj: gdjs.RuntimeObject | null, scene: gdjs.RuntimeScene) {
if (obj === null) {
return;
}
this.rotateTowardPosition(
obj.getDrawableX() + obj.getCenterX(),
obj.getDrawableY() + obj.getCenterY(),
0
0,
scene
);
}
}

View File

@@ -212,9 +212,6 @@ declare interface EventsBasedObjectData
name: string;
isInnerAreaFollowingParentSize: boolean;
variants: Array<EventsBasedObjectVariantData>;
/** Added at runtime to have the default variant with an empty name instead
* of the events-based object name. */
defaultVariant?: EventsBasedObjectVariantData;
}
declare interface EventsBasedObjectVariantData extends InstanceContainerData {

View File

@@ -1196,7 +1196,6 @@ interface MeasurementUnit {
[Const, Ref] MeasurementUnit STATIC_GetPixel();
[Const, Ref] MeasurementUnit STATIC_GetPixelSpeed();
[Const, Ref] MeasurementUnit STATIC_GetPixelAcceleration();
[Const, Ref] MeasurementUnit STATIC_GetAngularSpeed();
[Const, Ref] MeasurementUnit STATIC_GetNewton();
long STATIC_GetDefaultMeasurementUnitsCount();

View File

@@ -830,7 +830,6 @@ typedef ExtensionAndMetadata<ExpressionMetadata> ExtensionAndExpressionMetadata;
#define STATIC_GetPixel GetPixel
#define STATIC_GetPixelSpeed GetPixelSpeed
#define STATIC_GetPixelAcceleration GetPixelAcceleration
#define STATIC_GetAngularSpeed GetAngularSpeed
#define STATIC_GetNewton GetNewton
#define STATIC_GetDefaultMeasurementUnitsCount GetDefaultMeasurementUnitsCount
#define STATIC_GetDefaultMeasurementUnitAtIndex GetDefaultMeasurementUnitAtIndex

View File

@@ -388,8 +388,7 @@ class VariablesContainer {
}
class RuntimeObject {
constructor(instanceContainer, objectData) {
this._runtimeScene = instanceContainer;
constructor(runtimeScene, objectData) {
this.name = objectData.name || '';
this._variables = new VariablesContainer(objectData.variables);
this._livingOnScene = true;
@@ -467,9 +466,10 @@ class RuntimeObject {
array.pushValue(value);
}
deleteFromScene() {
/** @param {RuntimeScene} runtimeScene */
deleteFromScene(runtimeScene) {
if (this._livingOnScene) {
this._runtimeScene.markObjectForDeletion(this);
runtimeScene.markObjectForDeletion(this);
this._livingOnScene = false;
}
}

View File

@@ -1153,7 +1153,7 @@ describe('libGD.js - GDJS Async Code Generation integration tests', function ()
);
// Delete an object while the task is running.
myObjectA1.deleteFromScene();
myObjectA1.deleteFromScene(runtimeScene);
// Process the tasks (after faking it's finished).
runtimeScene.getAsyncTasksManager().markAllFakeAsyncTasksAsFinished();
@@ -1175,8 +1175,8 @@ describe('libGD.js - GDJS Async Code Generation integration tests', function ()
);
// Delete other objects while the task is running.
myObjectA3.deleteFromScene();
myObjectB1.deleteFromScene();
myObjectA3.deleteFromScene(runtimeScene);
myObjectB1.deleteFromScene(runtimeScene);
// Process the tasks again (after faking it's finished).
runtimeScene.getAsyncTasksManager().markAllFakeAsyncTasksAsFinished();
@@ -1291,7 +1291,7 @@ describe('libGD.js - GDJS Async Code Generation integration tests', function ()
);
// Delete an object while the task is running.
myObjectA1.deleteFromScene();
myObjectA1.deleteFromScene(runtimeScene);
// Process the tasks (after faking it's finished).
runtimeScene.getAsyncTasksManager().markAllFakeAsyncTasksAsFinished();
@@ -1315,8 +1315,8 @@ describe('libGD.js - GDJS Async Code Generation integration tests', function ()
);
// Delete other objects while the task is running.
myObjectA3.deleteFromScene();
myObjectB1.deleteFromScene();
myObjectA3.deleteFromScene(runtimeScene);
myObjectB1.deleteFromScene(runtimeScene);
// Process the tasks again (after faking it's finished).
runtimeScene.getAsyncTasksManager().markAllFakeAsyncTasksAsFinished();
@@ -1632,7 +1632,7 @@ describe('libGD.js - GDJS Async Code Generation integration tests', function ()
);
// Delete an object while the task is running.
myObjectA1.deleteFromScene();
myObjectA1.deleteFromScene(runtimeScene);
// Process the tasks (after faking it's finished).
runtimeScene.getAsyncTasksManager().markAllFakeAsyncTasksAsFinished();
@@ -1656,8 +1656,8 @@ describe('libGD.js - GDJS Async Code Generation integration tests', function ()
);
// Delete other objects while the task is running.
myObjectA3.deleteFromScene();
myObjectB1.deleteFromScene();
myObjectA3.deleteFromScene(runtimeScene);
myObjectB1.deleteFromScene(runtimeScene);
// Process the tasks again (after faking it's finished).
runtimeScene.getAsyncTasksManager().markAllFakeAsyncTasksAsFinished();
@@ -2132,8 +2132,8 @@ describe('libGD.js - GDJS Async Code Generation integration tests', function ()
const newMyObjectA = runtimeScene.getObjects('MyObjectA')[3];
// Delete some objects while the second Wait task is running.
myObjectA1.deleteFromScene();
myObjectB1.deleteFromScene();
myObjectA1.deleteFromScene(runtimeScene);
myObjectB1.deleteFromScene(runtimeScene);
// Process the tasks again (after faking it's finished).
runtimeScene.getAsyncTasksManager().markAllFakeAsyncTasksAsFinished();
@@ -2285,9 +2285,9 @@ describe('libGD.js - GDJS Async Code Generation integration tests', function ()
const newMyObjectA2 = runtimeScene.getObjects('MyObjectA')[4];
// Delete some objects while the second Wait task is running.
myObjectA1.deleteFromScene();
myObjectB1.deleteFromScene();
newMyObjectA1.deleteFromScene();
myObjectA1.deleteFromScene(runtimeScene);
myObjectB1.deleteFromScene(runtimeScene);
newMyObjectA1.deleteFromScene(runtimeScene);
// Process the tasks again (after faking it's finished).
runtimeScene.getAsyncTasksManager().markAllFakeAsyncTasksAsFinished();

View File

@@ -987,7 +987,6 @@ export class MeasurementUnit extends EmscriptenObject {
static getPixel(): MeasurementUnit;
static getPixelSpeed(): MeasurementUnit;
static getPixelAcceleration(): MeasurementUnit;
static getAngularSpeed(): MeasurementUnit;
static getNewton(): MeasurementUnit;
static getDefaultMeasurementUnitsCount(): number;
static getDefaultMeasurementUnitAtIndex(index: number): MeasurementUnit;

View File

@@ -17,7 +17,6 @@ declare class gdMeasurementUnit {
static getPixel(): gdMeasurementUnit;
static getPixelSpeed(): gdMeasurementUnit;
static getPixelAcceleration(): gdMeasurementUnit;
static getAngularSpeed(): gdMeasurementUnit;
static getNewton(): gdMeasurementUnit;
static getDefaultMeasurementUnitsCount(): number;
static getDefaultMeasurementUnitAtIndex(index: number): gdMeasurementUnit;

View File

@@ -7,7 +7,11 @@ pull_requests:
do_not_increment_build_number: true
image: Visual Studio 2019
clone_depth: 5
# Build must be triggered by the API.
# Only build
branches:
only:
- master
- /experimental-build.*/
skip_tags: true # Don't rebuild on tags.
init:
- ps: Install-Product node 16
@@ -18,12 +22,12 @@ cache:
- newIDE\electron-app\node_modules -> newIDE\electron-app\package-lock.json
- GDevelop.js\node_modules -> GDevelop.js\package-lock.json
install:
# Download and install SSL.com eSigner CKA.
# Download and install SSL.com eSigner CKA.
# See https://www.ssl.com/how-to/how-to-integrate-esigner-cka-with-ci-cd-tools-for-automated-code-signing/.
#
# This is necessary because of "signing to be FIPS-140 compliant". See
# This is necessary because of "signing to be FIPS-140 compliant". See
# https://github.com/electron-userland/electron-builder/issues/6158
#
#
# Make sure to DISABLE "malware blocker" in SSL.com to avoid errors like:
# Error information: "Error: SignerSign() failed." (-2146893821/0x80090003)
- ps: >-
@@ -38,13 +42,13 @@ install:
Remove-Item eSigner_CKA_Setup.zip
Move-Item -Destination "eSigner_CKA_Installer.exe" -Path "eSigner_CKA_*\*.exe"
# Install it. See https://www.ssl.com/how-to/how-to-integrate-esigner-cka-with-ci-cd-tools-for-automated-code-signing/
New-Item -ItemType Directory -Force -Path "C:\projects\gdevelop\eSignerCKA"
./eSigner_CKA_Installer.exe /CURRENTUSER /VERYSILENT /SUPPRESSMSGBOXES /DIR="C:\projects\gdevelop\eSignerCKA" | Out-Null
# Disable logger.
# $LogConfig = Get-Content -Path C:\projects\gdevelop\eSignerCKA/log4net.config
@@ -53,6 +57,23 @@ install:
# $LogConfig | Set-Content -Path C:\projects\gdevelop\eSignerCKA/log4net.config
# Build GDevelop.js (and run tests to ensure it works).
# (in a subshell to avoid Emscripten polluting the Node.js and npm version for the rest of the build)
- cmd: >-
cd GDevelop.js
npm -v && npm install
git clone https://github.com/juj/emsdk.git
cd emsdk
emsdk install 3.1.21
CMD /C "emsdk activate 3.1.21 && cd .. && npm run build"
cd ..\..
# Build GDevelop IDE.
# Also install setuptools as something requires distutils in electron-app, and it was removed in Python 3.12.
# setuptools will make distutils available again (but we should migrate our packages probably).
@@ -121,6 +142,10 @@ build_script:
# Run a few tests on Windows.
test_script:
- cmd: >-
cd GDevelop.js
npm test
cd ..
cd newIDE\app

Binary file not shown.

Before

Width:  |  Height:  |  Size: 819 KiB

After

Width:  |  Height:  |  Size: 779 KiB

View File

@@ -1,2 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="14" height="14" version="1.1" viewBox="0 0 14 14" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><path d="m7 0-6 3.5v7l6 3.5 6-3.5v-7z" fill="#55b1e0" style="paint-order:normal"/><path d="m7.001 0.289 5.75 3.355v6.711l-5.75 3.355-5.75-3.355v-6.711z" fill="#2e388a" style="paint-order:normal"/><path d="m9.595 4.129c-0.075-0.2212-0.285-0.3788-0.5325-0.3788h-4.125c-0.2475 0-0.4538 0.1575-0.5325 0.3788l-0.78 2.246v3c0 0.2062 0.1688 0.375 0.375 0.375h0.375c0.2062 0 0.375-0.1688 0.375-0.375v-0.375h4.5v0.375c0 0.2062 0.1688 0.375 0.375 0.375h0.375c0.2062 0 0.375-0.1688 0.375-0.375v-3zm-4.658 3.746c-0.3112 0-0.5625-0.2512-0.5625-0.5625s0.2512-0.5625 0.5625-0.5625 0.5625 0.2512 0.5625 0.5625-0.2512 0.5625-0.5625 0.5625zm4.125 0c-0.3112 0-0.5625-0.2512-0.5625-0.5625s0.2512-0.5625 0.5625-0.5625 0.5625 0.2512 0.5625 0.5625-0.2512 0.5625-0.5625 0.5625zm-4.688-1.875 0.5625-1.688h4.125l0.5625 1.688z" fill="#55b1e0" stroke-width=".375"/></svg>

Before

Width:  |  Height:  |  Size: 1001 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 185 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 777 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 68 KiB

View File

@@ -3,9 +3,8 @@
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover" />
<link rel="apple-touch-icon" sizes="180x180" href="%PUBLIC_URL%/apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="%PUBLIC_URL%/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="%PUBLIC_URL%/favicon-16x16.png">
<link rel="apple-touch-icon" href="%PUBLIC_URL%/apple-touch-icon.png">
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon-256.png">
<title>GDevelop 5</title>
<meta name="title" content="GDevelop game making app" />

View File

@@ -3,13 +3,23 @@
"name": "GDevelop",
"icons": [
{
"src": "/android-chrome-192x192.png",
"sizes": "192x192",
"src": "favicon-512.png",
"sizes": "512x512",
"type": "image/png"
},
{
"src": "/android-chrome-512x512.png",
"sizes": "512x512",
"src": "favicon-256.png",
"sizes": "256x256",
"type": "image/png"
},
{
"src": "apple-touch-icon.png",
"type": "image/png",
"sizes": "192x192"
},
{
"src": "favicon.ico",
"sizes": "128x128",
"type": "image/png"
}
],

View File

@@ -129,20 +129,7 @@ if (shell.test('-f', path.join(sourceDirectory, 'libGD.js'))) {
// Try to download the latest libGD.js, fallback to previous or master ones
// if not found (including different parents, for handling of merge commits).
downloadCommitLibGdJs('HEAD').then(onLibGdJsDownloaded, () => {
// Force the exact version of GDevelop.js to be downloaded for AppVeyor - because
// this means we build the app and we don't want to risk mismatch (Core C++ not up to date
// with the IDE JavaScript).
if (process.env.APPVEYOR || process.env.REQUIRES_EXACT_LIBGD_JS_VERSION) {
shell.echo(
`❌ Can't download the exact required version of libGD.js - check it was built by CircleCI before running this CI.`
);
shell.echo(
` See the pipeline on https://app.circleci.com/pipelines/github/4ian/GDevelop.`
);
shell.exit(1);
}
downloadCommitLibGdJs('HEAD').then(onLibGdJsDownloaded, () =>
downloadCommitLibGdJs('HEAD~1').then(onLibGdJsDownloaded, () =>
downloadCommitLibGdJs('HEAD~2').then(onLibGdJsDownloaded, () =>
downloadCommitLibGdJs('HEAD~3').then(onLibGdJsDownloaded, () =>
@@ -164,5 +151,5 @@ if (shell.test('-f', path.join(sourceDirectory, 'libGD.js'))) {
)
)
)
});
);
}

View File

@@ -18,7 +18,6 @@ import {
installRequiredExtensions,
installPublicAsset,
type RequiredExtensionInstallation,
complyVariantsToEventsBasedObjectOf,
} from './InstallAsset';
import EventsFunctionsExtensionsContext from '../EventsFunctionsExtensionsLoader/EventsFunctionsExtensionsContext';
import { showErrorBox } from '../UI/Messages/MessageBox';
@@ -227,7 +226,6 @@ const AssetPackInstallDialog = ({
const createdObjects = results
.map(result => result.createdObjects)
.flat();
complyVariantsToEventsBasedObjectOf(project, createdObjects);
onAssetsAdded(createdObjects);
} catch (error) {
setAreAssetsBeingInstalled(false);

View File

@@ -600,21 +600,3 @@ export const checkRequiredExtensionsUpdateForAssets = async ({
return checkRequiredExtensionsUpdate({ requiredExtensions, project });
};
export const complyVariantsToEventsBasedObjectOf = (
project: gdProject,
createdObjects: Array<gdObject>
) => {
const installedVariantObjectTypes = new Set<string>();
for (const createdObject of createdObjects) {
if (project.hasEventsBasedObject(createdObject.getType())) {
installedVariantObjectTypes.add(createdObject.getType());
}
}
for (const installedVariantObjectType of installedVariantObjectTypes) {
gd.EventsBasedObjectVariantHelper.complyVariantsToEventsBasedObject(
project,
project.getEventsBasedObject(installedVariantObjectType)
);
}
};

View File

@@ -20,7 +20,6 @@ import {
checkRequiredExtensionsUpdate,
checkRequiredExtensionsUpdateForAssets,
type InstallAssetOutput,
complyVariantsToEventsBasedObjectOf,
} from './InstallAsset';
import {
type Asset,
@@ -218,10 +217,6 @@ export const useInstallAsset = ({
openedAssetPack && openedAssetPack.id ? openedAssetPack.id : null,
assetPackKind: isPrivate ? 'private' : 'public',
});
complyVariantsToEventsBasedObjectOf(
project,
installOutput.createdObjects
);
await resourceManagementProps.onFetchNewlyAddedResources();
return installOutput;

View File

@@ -17,7 +17,7 @@ const gd: libGDevelop = global.gd;
type Props = BehaviorEditorProps;
export const areAdvancedPropertiesModified = (behavior: gdBehavior) => {
const areAdvancedPropertiesModified = (behavior: gdBehavior) => {
const behaviorMetadata = gd.MetadataProvider.getBehaviorMetadata(
gd.JsPlatform.get(),
behavior.getTypeName()

View File

@@ -16,12 +16,6 @@ import useForceUpdate from '../../../Utils/UseForceUpdate';
import Button from '@material-ui/core/Button';
import ButtonGroup from '@material-ui/core/ButtonGroup';
import { NumericProperty, UnitAdornment } from '../Physics2Editor';
import {
Accordion,
AccordionHeader,
AccordionBody,
} from '../../../UI/Accordion';
import { areAdvancedPropertiesModified } from '../BehaviorPropertiesEditor';
type Props = BehaviorEditorProps;
@@ -63,11 +57,6 @@ const Physics3DEditor = (props: Props) => {
const { behavior, onBehaviorUpdated } = props;
const forceUpdate = useForceUpdate();
const areAdvancedPropertiesExpandedByDefault = React.useMemo(
() => areAdvancedPropertiesModified(behavior),
[behavior]
);
const updateBehaviorProperty = React.useCallback(
(property, value) => {
behavior.updateProperty(property, value);
@@ -255,18 +244,6 @@ const Physics3DEditor = (props: Props) => {
)
}
/>
<NumericProperty
id="physics3d-parameter-mass-override"
properties={properties}
propertyName={'massOverride'}
step={0.1}
onUpdate={newValue =>
updateBehaviorProperty(
'massOverride',
parseFloat(newValue) > 0 ? newValue : '0'
)
}
/>
<NumericProperty
properties={properties}
propertyName={'gravityScale'}
@@ -379,72 +356,6 @@ const Physics3DEditor = (props: Props) => {
disabled={isStatic}
/>
</Line>
<Accordion
defaultExpanded={areAdvancedPropertiesExpandedByDefault}
noMargin
>
<AccordionHeader noMargin>
<Text size="sub-title">
<Trans>Advanced properties</Trans>
</Text>
</AccordionHeader>
<AccordionBody disableGutters>
<Column expand noMargin>
<ResponsiveLineStackLayout>
<NumericProperty
properties={properties}
propertyName={'shapeOffsetX'}
step={1}
onUpdate={newValue =>
updateBehaviorProperty('shapeOffsetX', newValue)
}
/>
<NumericProperty
properties={properties}
propertyName={'shapeOffsetY'}
step={1}
onUpdate={newValue =>
updateBehaviorProperty('shapeOffsetY', newValue)
}
/>
<NumericProperty
properties={properties}
propertyName={'shapeOffsetZ'}
step={1}
onUpdate={newValue =>
updateBehaviorProperty('shapeOffsetZ', newValue)
}
/>
</ResponsiveLineStackLayout>
<ResponsiveLineStackLayout>
<NumericProperty
properties={properties}
propertyName={'massCenterOffsetX'}
step={1}
onUpdate={newValue =>
updateBehaviorProperty('massCenterOffsetX', newValue)
}
/>
<NumericProperty
properties={properties}
propertyName={'massCenterOffsetY'}
step={1}
onUpdate={newValue =>
updateBehaviorProperty('massCenterOffsetY', newValue)
}
/>
<NumericProperty
properties={properties}
propertyName={'massCenterOffsetZ'}
step={1}
onUpdate={newValue =>
updateBehaviorProperty('massCenterOffsetZ', newValue)
}
/>
</ResponsiveLineStackLayout>
</Column>
</AccordionBody>
</Accordion>
</Column>
);
};

View File

@@ -1,5 +1,5 @@
// @flow
import { roundPositionsToGrid } from '../Utils/GridHelpers';
import { roundPosition } from '../Utils/GridHelpers';
import { unserializeFromJSObject } from '../Utils/Serializer';
import { type InstancesEditorSettings } from './InstancesEditorSettings';
const gd: libGDevelop = global.gd;
@@ -9,6 +9,29 @@ type Props = {|
instancesEditorSettings: InstancesEditorSettings,
|};
const roundPositionsToGrid = (
pos: [number, number],
instancesEditorSettings: InstancesEditorSettings
): [number, number] => {
const newPos = pos;
if (instancesEditorSettings.grid && instancesEditorSettings.snap) {
roundPosition(
newPos,
instancesEditorSettings.gridWidth,
instancesEditorSettings.gridHeight,
instancesEditorSettings.gridOffsetX,
instancesEditorSettings.gridOffsetY,
instancesEditorSettings.gridType
);
} else {
newPos[0] = Math.round(newPos[0]);
newPos[1] = Math.round(newPos[1]);
}
return newPos;
};
/**
* Allow to add instances on the scene. Supports "temporary" instances,
* which are real instances but can be deleted as long as they are not "committed".
@@ -33,12 +56,14 @@ export default class InstancesAdder {
position,
copyReferential,
serializedInstances,
preventSnapToGrid = false,
addInstancesInTheForeground = false,
doesObjectExistInContext,
}: {|
position: [number, number],
copyReferential: [number, number],
serializedInstances: Array<Object>,
preventSnapToGrid?: boolean,
addInstancesInTheForeground?: boolean,
doesObjectExistInContext: string => boolean,
|}): Array<gdInitialInstance> => {
@@ -53,8 +78,18 @@ export default class InstancesAdder {
const instance = new gd.InitialInstance();
unserializeFromJSObject(instance, serializedInstance);
if (!doesObjectExistInContext(instance.getObjectName())) return null;
instance.setX(instance.getX() - copyReferential[0] + position[0]);
instance.setY(instance.getY() - copyReferential[1] + position[1]);
const desiredPosition = [
instance.getX() - copyReferential[0] + position[0],
instance.getY() - copyReferential[1] + position[1],
];
const newPos = preventSnapToGrid
? desiredPosition
: roundPositionsToGrid(
desiredPosition,
this._instancesEditorSettings
);
instance.setX(newPos[0]);
instance.setY(newPos[1]);
if (addInstancesInTheForeground) {
if (
addedInstancesLowestZOrder === null ||

View File

@@ -1,5 +1,5 @@
// @flow
import { roundPositionsToGrid } from '../Utils/GridHelpers';
import { roundPosition } from '../Utils/GridHelpers';
import Rectangle from '../Utils/Rectangle';
import { type InstancesEditorSettings } from './InstancesEditorSettings';
import { type InstanceMeasurer } from './InstancesRenderer';
@@ -106,15 +106,30 @@ export default class InstancesMover {
const magnetPosition = this._temporaryPoint;
magnetPosition[0] = initialMagnetX + this.totalDeltaX;
magnetPosition[1] = initialMagnetY + this.totalDeltaY;
roundPositionsToGrid(
magnetPosition,
this.instancesEditorSettings,
noGridSnap
);
if (
this.instancesEditorSettings.snap &&
this.instancesEditorSettings.grid &&
!noGridSnap
) {
roundPosition(
magnetPosition,
this.instancesEditorSettings.gridWidth,
this.instancesEditorSettings.gridHeight,
this.instancesEditorSettings.gridOffsetX,
this.instancesEditorSettings.gridOffsetY,
this.instancesEditorSettings.gridType
);
} else {
// Without a grid, the position is still rounded to the nearest pixel.
// The size of the instance (or selection of instances) might not be round,
// so the magnet corner is still relevant.
magnetPosition[0] = Math.round(magnetPosition[0]);
magnetPosition[1] = Math.round(magnetPosition[1]);
}
const roundedTotalDeltaX = magnetPosition[0] - initialMagnetX;
const roundedTotalDeltaY = magnetPosition[1] - initialMagnetY;
for (let i = 0; i < nonLockedInstances.length; i++) {
for (var i = 0; i < nonLockedInstances.length; i++) {
const selectedInstance = nonLockedInstances[i];
let initialPosition = this.instancePositions[selectedInstance.ptr];
@@ -155,16 +170,6 @@ export default class InstancesMover {
this.totalDeltaY = 0;
}
snapSelection(instances: gdInitialInstance[]): void {
// The snapping doesn't work well on 3D model objects because their default
// dimensions and origin change when the model is loaded from an async call.
this.endMove();
// Force magnet from selection top left corner.
this.startMove(Number.NEGATIVE_INFINITY, Number.NEGATIVE_INFINITY);
this.moveBy(instances, 0, 0, false, false);
this.endMove();
}
isMoving() {
return !!this._initialSelectionAABB;
}

View File

@@ -770,16 +770,13 @@ export default class InstancesEditor extends Component<Props, State> {
position: [number, number],
copyReferential: [number, number],
serializedInstances: Array<Object>,
preventSnapToGrid?: boolean,
addInstancesInTheForeground?: boolean,
doesObjectExistInContext: string => boolean,
|}): Array<gdInitialInstance> => {
return this._instancesAdder.addSerializedInstances(options);
};
snapSelection = (instances: gdInitialInstance[]) => {
this.instancesMover.snapSelection(instances);
};
/**
* Immediately add instances for the specified objects at the given
* position (in scene coordinates) given their names.

View File

@@ -191,16 +191,6 @@ const jsExtensions = [
},
];
const getExpectedNumberOfJSExtensionModules = ({
filterExamples,
}: {|
filterExamples: boolean,
|}): number => {
return jsExtensions.filter(
({ name }) => !filterExamples || !name.includes('Example')
).length;
};
type MakeExtensionsLoaderArguments = {|
objectsEditorService: typeof ObjectsEditorService,
objectsRenderingService: typeof ObjectsRenderingService,
@@ -220,57 +210,52 @@ export default function makeExtensionsLoader({
return {
loadAllExtensions(
_: TranslationFunction
): Promise<{|
results: Array<{|
extensionModulePath: string,
result: ExtensionLoadingResult,
|}>,
expectedNumberOfJSExtensionModulesLoaded: number,
|}> {
const results = jsExtensions
.filter(({ name }) => !filterExamples || !name.includes('Example'))
.map(({ name, extensionModule, objectsRenderingServiceModules }) => {
if (
objectsEditorService &&
extensionModule.registerEditorConfigurations
) {
extensionModule.registerEditorConfigurations(objectsEditorService);
}
if (objectsRenderingService) {
if (objectsRenderingServiceModules) {
for (const requirePath in objectsRenderingServiceModules) {
objectsRenderingService.registerModule(
requirePath,
objectsRenderingServiceModules[requirePath]
);
}
}
if (extensionModule.registerInstanceRenderers) {
extensionModule.registerInstanceRenderers(
objectsRenderingService
): Promise<
Array<{ extensionModulePath: string, result: ExtensionLoadingResult }>
> {
return Promise.resolve(
jsExtensions
.filter(({ name }) => !filterExamples || !name.includes('Example'))
.map(({ name, extensionModule, objectsRenderingServiceModules }) => {
if (
objectsEditorService &&
extensionModule.registerEditorConfigurations
) {
extensionModule.registerEditorConfigurations(
objectsEditorService
);
}
if (extensionModule.registerClearCache) {
extensionModule.registerClearCache(objectsRenderingService);
if (objectsRenderingService) {
if (objectsRenderingServiceModules) {
for (const requirePath in objectsRenderingServiceModules) {
objectsRenderingService.registerModule(
requirePath,
objectsRenderingServiceModules[requirePath]
);
}
}
if (extensionModule.registerInstanceRenderers) {
extensionModule.registerInstanceRenderers(
objectsRenderingService
);
}
if (extensionModule.registerClearCache) {
extensionModule.registerClearCache(objectsRenderingService);
}
}
}
return {
extensionModulePath: 'internal-extension://' + name,
result: loadExtension(_, gd, gd.JsPlatform.get(), extensionModule),
};
});
const expectedNumberOfJSExtensionModulesLoaded = getExpectedNumberOfJSExtensionModules(
{
filterExamples,
}
return {
extensionModulePath: 'internal-extension://' + name,
result: loadExtension(
_,
gd,
gd.JsPlatform.get(),
extensionModule
),
};
})
);
return Promise.resolve({
results,
expectedNumberOfJSExtensionModulesLoaded,
});
},
};
}

View File

@@ -17,23 +17,8 @@ type MakeExtensionsLoaderArguments = {|
filterExamples: boolean,
onFindGDJS?: ?() => Promise<{gdjsRoot: string}>
|};
type GetExpectedNumberOfJSExtensionModulesArguments = {|
filterExamples: boolean,
|};
*/
// This value is hardcoded to allow raising an error if the number of JS extensions
// loaded is different from the expected one, which may lead
// to projects corruption in the future if the app is still used.
// If a new extension is added, update this value.
// Also remember to add the extension in the list of extensions in BrowserJsExtensionsLoader.js
function getExpectedNumberOfJSExtensionModules(
{ filterExamples } /*: GetExpectedNumberOfJSExtensionModulesArguments*/
) /*:number*/ {
return 28 + (filterExamples ? 0 : 1);
}
/**
* Loader that will find all JS extensions declared in GDJS/Runtime/Extensions/xxx/JsExtension.js.
* If you add a new extension and also want it to be available for the web-app version, add it in
@@ -112,14 +97,7 @@ module.exports = function makeExtensionsLoader(
),
};
})
).then(results => {
return {
results,
expectedNumberOfJSExtensionModulesLoaded: getExpectedNumberOfJSExtensionModules(
{ filterExamples }
),
};
});
);
},
err => {
console.error(`Unable to find JS extensions modules`);

View File

@@ -10,18 +10,17 @@ export type JsExtensionModule = {
runExtensionSanityTests(gd: any, extension: gdPlatformExtension): Array<string>,
};
export type ExtensionLoadingResult = {|
export type ExtensionLoadingResult = {
error: boolean,
message: string,
dangerous?: boolean,
rawError?: any,
|};
};
export interface JsExtensionsLoader {
loadAllExtensions(_: TranslationFunction): Promise<{|
results: Array<{| extensionModulePath: string, result: ExtensionLoadingResult |}>,
expectedNumberOfJSExtensionModulesLoaded: number,
|}>,
loadAllExtensions(_: TranslationFunction): Promise<
Array<{ extensionModulePath: string, result: ExtensionLoadingResult }>
>,
}
*/

View File

@@ -116,9 +116,7 @@ export const create = (authentication: Authentication) => {
filterExamples: !isDev,
})}
initialFileMetadataToOpen={initialFileMetadataToOpen}
initialExampleSlugToOpen={
appArguments['create-from-example'] || null
}
initialExampleSlugToOpen={appArguments['create-from-example'] || null}
/>
)}
</ProjectStorageProviders>

View File

@@ -188,19 +188,18 @@ export const AiRequestChat = React.forwardRef<Props, AiRequestChatInterface>(
)
}
recommendedPlanIdIfNoSubscription="gdevelop_gold"
canHide
>
<Line>
<Column noMargin>
<Text noMargin>
{increaseQuotaOffering === 'subscribe' ? (
<Trans>
Unlock AI requests included with a GDevelop premium plan.
Get more free AI requests with a GDevelop premium plan.
</Trans>
) : (
<Trans>
Get even more AI requests included with a higher premium
plan.
Upgrade to another premium plan to get more free AI
requests.
</Trans>
)}
</Text>
@@ -233,56 +232,45 @@ export const AiRequestChat = React.forwardRef<Props, AiRequestChatInterface>(
<Trans>What do you want to make?</Trans>
</Text>
</Column>
<form
onSubmit={() => {
onSendUserRequest(userRequestText);
}}
>
<ColumnStackLayout justifyContent="center" noMargin>
<Column noMargin alignItems="stretch" justifyContent="stretch">
<CompactTextAreaField
maxLength={6000}
value={userRequestText}
disabled={isLaunchingAiRequest}
onChange={userRequestText =>
setUserRequestText(userRequestText)
}
onSubmit={() => {
onSendUserRequest(userRequestText);
}}
placeholder={newChatPlaceholder}
rows={5}
/>
</Column>
<Line noMargin>
<ResponsiveLineStackLayout
noMargin
alignItems="flex-start"
justifyContent="space-between"
expand
>
{!isMobile && errorOrQuotaOrCreditsExplanation}
<Line noMargin justifyContent="flex-end">
<LeftLoader reserveSpace isLoading={isLaunchingAiRequest}>
<RaisedButton
color="primary"
label={<Trans>Send</Trans>}
style={{ flexShrink: 0 }}
disabled={isLaunchingAiRequest || !userRequestText}
onClick={() => {
onSendUserRequest(userRequestText);
}}
/>
</LeftLoader>
</Line>
{isMobile && errorOrQuotaOrCreditsExplanation}
</ResponsiveLineStackLayout>
<Column noMargin alignItems="stretch" justifyContent="stretch">
<CompactTextAreaField
maxLength={6000}
value={userRequestText}
disabled={isLaunchingAiRequest}
onChange={userRequestText =>
setUserRequestText(userRequestText)
}
placeholder={newChatPlaceholder}
rows={5}
/>
</Column>
<Line noMargin>
<ResponsiveLineStackLayout
noMargin
alignItems="flex-start"
justifyContent="space-between"
expand
>
{!isMobile && errorOrQuotaOrCreditsExplanation}
<Line noMargin justifyContent="flex-end">
<LeftLoader reserveSpace isLoading={isLaunchingAiRequest}>
<RaisedButton
color="primary"
label={<Trans>Send</Trans>}
style={{ flexShrink: 0 }}
disabled={isLaunchingAiRequest}
onClick={() => {
onSendUserRequest(userRequestText);
}}
/>
</LeftLoader>
</Line>
</ColumnStackLayout>
</form>
{isMobile && errorOrQuotaOrCreditsExplanation}
</ResponsiveLineStackLayout>
</Line>
{subscriptionBanner}
</ColumnStackLayout>
<Column justifyContent="center">
<Column justifyContent="center" noMargin>
<Text size="body-small" color="secondary" align="center" noMargin>
<Trans>
The AI is experimental and still being improved.{' '}
@@ -470,52 +458,37 @@ export const AiRequestChat = React.forwardRef<Props, AiRequestChatInterface>(
) : (
subscriptionBanner
)}
<form
onSubmit={() => {
onSendUserRequest(userRequestText);
}}
>
<ColumnStackLayout
justifyContent="stretch"
alignItems="stretch"
<CompactTextAreaField
maxLength={6000}
value={userRequestText}
disabled={isLaunchingAiRequest}
onChange={userRequestText => setUserRequestText(userRequestText)}
placeholder={t`Ask a follow up question`}
rows={2}
/>
<Column noMargin alignItems="flex-end">
<ResponsiveLineStackLayout
noMargin
alignItems="flex-start"
justifyContent="space-between"
expand
>
<CompactTextAreaField
maxLength={6000}
value={userRequestText}
disabled={isLaunchingAiRequest}
onChange={userRequestText => setUserRequestText(userRequestText)}
placeholder={t`Ask a follow up question`}
rows={2}
onSubmit={() => {
onSendUserRequest(userRequestText);
}}
/>
<Column noMargin alignItems="flex-end">
<ResponsiveLineStackLayout
noMargin
alignItems="flex-start"
justifyContent="space-between"
expand
>
{!isMobile && errorOrQuotaOrCreditsExplanation}
<Line noMargin justifyContent="flex-end">
<LeftLoader reserveSpace isLoading={isLaunchingAiRequest}>
<RaisedButton
color="primary"
disabled={aiRequest.status === 'working'}
label={<Trans>Send</Trans>}
onClick={() => {
onSendUserRequest(userRequestText);
}}
/>
</LeftLoader>
</Line>
{isMobile && errorOrQuotaOrCreditsExplanation}
</ResponsiveLineStackLayout>
</Column>
</ColumnStackLayout>
</form>
{!isMobile && errorOrQuotaOrCreditsExplanation}
<Line noMargin justifyContent="flex-end">
<LeftLoader reserveSpace isLoading={isLaunchingAiRequest}>
<RaisedButton
color="primary"
disabled={aiRequest.status === 'working'}
label={<Trans>Send</Trans>}
onClick={() => {
onSendUserRequest(userRequestText);
}}
/>
</LeftLoader>
</Line>
{isMobile && errorOrQuotaOrCreditsExplanation}
</ResponsiveLineStackLayout>
</Column>
{dislikeFeedbackDialogOpenedFor && (
<DislikeFeedbackDialog
open

View File

@@ -59,7 +59,6 @@ export type AskAiEditorInterface = {|
scene: gdLayout,
objectWithContext: ObjectWithContext
) => void,
onSceneObjectsDeleted: (scene: gdLayout) => void,
|};
const noop = () => {};
@@ -110,7 +109,6 @@ export const AskAi = React.memo<Props>(
forceUpdateEditor: noop,
onEventsBasedObjectChildrenEdited: noop,
onSceneObjectEdited: noop,
onSceneObjectsDeleted: noop,
}));
const aiRequestChatRef = React.useRef<AiRequestChatInterface | null>(

View File

@@ -151,7 +151,6 @@ export type RenderEditorContainerProps = {|
scene: gdLayout,
objectWithContext: ObjectWithContext
) => void,
onSceneObjectsDeleted: (scene: gdLayout) => void,
onExtractAsExternalLayout: (name: string) => void,
onExtractAsEventBasedObject: (

View File

@@ -237,15 +237,9 @@ export class CustomObjectEditorContainer extends React.Component<RenderEditorCon
onObjectEdited={() =>
this.props.onEventsBasedObjectChildrenEdited(eventsBasedObject)
}
onObjectsDeleted={() =>
this.props.onEventsBasedObjectChildrenEdited(eventsBasedObject)
}
onObjectGroupEdited={() =>
this.props.onEventsBasedObjectChildrenEdited(eventsBasedObject)
}
onObjectGroupsDeleted={() =>
this.props.onEventsBasedObjectChildrenEdited(eventsBasedObject)
}
onEventsBasedObjectChildrenEdited={
this.props.onEventsBasedObjectChildrenEdited
}

View File

@@ -57,10 +57,6 @@ export class DebuggerEditorContainer extends React.Component<
// No thing to be done.
}
onSceneObjectsDeleted(scene: gdLayout) {
// No thing to be done.
}
// To be updated, see https://reactjs.org/docs/react-component.html#unsafe_componentwillreceiveprops.
UNSAFE_componentWillReceiveProps() {
this._checkUserHasSubscription();

View File

@@ -53,10 +53,6 @@ export class EventsEditorContainer extends React.Component<RenderEditorContainer
// No thing to be done.
}
onSceneObjectsDeleted(scene: gdLayout) {
// No thing to be done.
}
getLayout(): ?gdLayout {
const { project, projectItemName } = this.props;
if (

View File

@@ -46,10 +46,6 @@ export class EventsFunctionsExtensionEditorContainer extends React.Component<Ren
// No thing to be done.
}
onSceneObjectsDeleted(scene: gdLayout) {
// No thing to be done.
}
shouldComponentUpdate(nextProps: RenderEditorContainerProps) {
// We stop updates when the component is inactive.
// If it's active, was active or becoming active again we let update propagate.

View File

@@ -90,10 +90,6 @@ export class ExternalEventsEditorContainer extends React.Component<
// No thing to be done.
}
onSceneObjectsDeleted(scene: gdLayout) {
// No thing to be done.
}
getExternalEvents(): ?gdExternalEvents {
const { project, projectItemName } = this.props;
if (!project || !projectItemName) return null;

View File

@@ -138,20 +138,6 @@ export class ExternalLayoutEditorContainer extends React.Component<
}
}
onSceneObjectsDeleted(scene: gdLayout) {
const { editor } = this;
const externalLayout = this.getExternalLayout();
if (!externalLayout) {
return;
}
if (externalLayout.getAssociatedLayout() !== scene.getName()) {
return;
}
if (editor) {
editor.forceUpdateObjectsList();
}
}
getExternalLayout(): ?gdExternalLayout {
const { project, projectItemName } = this.props;
if (!project || !projectItemName) return null;
@@ -280,10 +266,8 @@ export class ExternalLayoutEditorContainer extends React.Component<
onObjectEdited={objectWithContext =>
this.props.onSceneObjectEdited(layout, objectWithContext)
}
onObjectsDeleted={() => this.props.onSceneObjectsDeleted(layout)}
// It's only used to refresh events-based object variants.
onObjectGroupEdited={() => {}}
onObjectGroupsDeleted={() => {}}
// Nothing to do as events-based objects can't have external layout.
onEventsBasedObjectChildrenEdited={() => {}}
onExtensionInstalled={this.props.onExtensionInstalled}

View File

@@ -313,7 +313,6 @@ const EducationMarketingSection = ({
tutorials={educationTutorials}
// In this marketing view, users are not allowed to open tutorials so no need to specify this prop.
onSelectTutorial={() => {}}
onSelectCourse={() => {}}
// In this marketing view, users are not allowed to open tutorials so no need to specify this prop.
onOpenTemplateFromTutorial={async () => {}}
isLocked

View File

@@ -167,27 +167,12 @@ const BadgeItem = ({
hasThisBadge,
buttonLabel,
linkUrl,
onOpenProfile,
}: {|
achievement: ?Achievement,
hasThisBadge: boolean,
buttonLabel: React.Node,
linkUrl: string,
onOpenProfile: () => void,
|}) => {
const [hasBeenClicked, setHasBeenClicked] = React.useState(false);
const onClick = React.useCallback(
() => {
if (hasBeenClicked) {
onOpenProfile();
} else {
Window.openExternalURL(linkUrl);
setHasBeenClicked(true);
}
},
[hasBeenClicked, linkUrl, onOpenProfile]
);
return (
<I18n>
{({ i18n }) => (
@@ -232,9 +217,11 @@ const BadgeItem = ({
</Text>
</Column>
<TextButton
label={!hasBeenClicked ? buttonLabel : <Trans>Claim credits</Trans>}
label={buttonLabel}
secondary
onClick={onClick}
onClick={() => {
Window.openExternalURL(linkUrl);
}}
disabled={hasThisBadge}
/>
</LineStackLayout>
@@ -377,7 +364,6 @@ export const EarnCredits = ({
hasThisBadge={!!item.hasThisBadge}
buttonLabel={item.label}
linkUrl={item.linkUrl}
onOpenProfile={onOpenProfile}
/>
);
}

View File

@@ -37,11 +37,7 @@ import { selectMessageByLocale } from '../../../../Utils/i18n/MessageByLocale';
const styles = {
desktopContainer: { display: 'flex', gap: 16 },
sideContainer: {
width: 250,
flexShrink: 0,
position: 'relative',
},
sideContainer: { maxWidth: 250, position: 'relative' },
sideContent: {
position: 'sticky',
top: 20,

View File

@@ -90,7 +90,6 @@ type Props = {|
limits: ?Limits,
tutorial: Tutorial,
onSelectTutorial: (tutorial: Tutorial) => void,
onSelectCourse: (courseId: string) => void,
index: number,
onOpenTemplateFromTutorial: ?(string) => void,
isLocked?: boolean,
@@ -102,7 +101,6 @@ const EducationCurriculumLesson = ({
tutorial,
limits,
onSelectTutorial,
onSelectCourse,
index,
onOpenTemplateFromTutorial,
isLocked,
@@ -122,7 +120,7 @@ const EducationCurriculumLesson = ({
})}`
)
: null;
const { gameLink, courseId } = tutorial;
const { gameLink } = tutorial;
const title = (
<LineStackLayout noMargin alignItems="center">
@@ -231,23 +229,13 @@ const EducationCurriculumLesson = ({
onClick={onOpenTemplateFromTutorial}
/>
)}
{courseId ? (
<RaisedButton
primary
fullWidth={isMobile && !isLandscape}
disabled={isLessonLocked}
label={<Trans>Open course</Trans>}
onClick={() => onSelectCourse(courseId)}
/>
) : (
<RaisedButton
primary
fullWidth={isMobile && !isLandscape}
disabled={isLessonLocked}
label={<Trans>Open lesson</Trans>}
onClick={() => onSelectTutorial(tutorial)}
/>
)}
<RaisedButton
primary
fullWidth={isMobile && !isLandscape}
disabled={isLessonLocked}
label={<Trans>Open lesson</Trans>}
onClick={() => onSelectTutorial(tutorial)}
/>
</LineStackLayout>
</LineStackLayout>
)}

View File

@@ -31,7 +31,6 @@ type EducationCurriculumProps = {|
limits: ?Limits,
tutorials: Tutorial[],
onSelectTutorial: Tutorial => void,
onSelectCourse: (courseId: string) => void,
onOpenTemplateFromTutorial: string => Promise<void>,
isLocked?: boolean,
onClickSubscribe?: () => void,
@@ -43,7 +42,6 @@ export const EducationCurriculum = ({
limits,
tutorials,
onSelectTutorial,
onSelectCourse,
onOpenTemplateFromTutorial,
isLocked,
onClickSubscribe,
@@ -86,7 +84,6 @@ export const EducationCurriculum = ({
isLocked={isLocked}
onClickSubscribe={onClickSubscribe}
onSelectTutorial={onSelectTutorial}
onSelectCourse={onSelectCourse}
index={sectionIndex}
onOpenTemplateFromTutorial={
tutorial.templateUrl
@@ -106,7 +103,6 @@ export const EducationCurriculum = ({
i18n,
limits,
onSelectTutorial,
onSelectCourse,
onOpenTemplateFromTutorial,
renderInterstitialCallout,
isLocked,
@@ -139,7 +135,6 @@ type Props = {|
tutorials: Array<Tutorial>,
category: TutorialCategory,
onOpenTemplateFromTutorial: string => Promise<void>,
onSelectCourse: (courseId: string) => void,
|};
const TutorialsCategoryPage = ({
@@ -147,7 +142,6 @@ const TutorialsCategoryPage = ({
tutorials,
onBack,
onOpenTemplateFromTutorial,
onSelectCourse,
}: Props) => {
const { limits } = React.useContext(AuthenticatedUserContext);
const texts = TUTORIAL_CATEGORY_TEXTS[category];
@@ -173,7 +167,6 @@ const TutorialsCategoryPage = ({
<EducationCurriculum
tutorials={filteredTutorials}
onSelectTutorial={setSelectedTutorial}
onSelectCourse={onSelectCourse}
i18n={i18n}
limits={limits}
onOpenTemplateFromTutorial={onOpenTemplateFromTutorial}

View File

@@ -65,8 +65,8 @@ export const TUTORIAL_CATEGORY_TEXTS = {
),
},
course: {
title: <Trans>Loading</Trans>,
description: <Trans>Loading course...</Trans>,
title: 'UNUSED',
description: 'UNUSED',
},
recommendations: {
title: <Trans>Recommendations</Trans>,
@@ -237,10 +237,6 @@ const LearnSection = ({
category={selectedCategory}
tutorials={tutorials}
onOpenTemplateFromTutorial={onOpenTemplateFromTutorial}
onSelectCourse={(courseId: string) => {
onSelectCourse(courseId);
onSelectCategory('course');
}}
/>
);
};

View File

@@ -47,17 +47,21 @@ const GamesPlatformFrame = ({ initialGameId, loaded, visible }: Props) => {
const url = new URL(
gameId.current
? `/app-embedded/${gamesPlatformEmbeddedVersion}/games/${gameId.current}`
: `/app-embedded/${gamesPlatformEmbeddedVersion}/${paletteType}`,
: isMobile
? // On mobile, go directly to a random game if none is specified.
`/app-embedded/${gamesPlatformEmbeddedVersion}/games/random`
: // On desktop, access the homepage.
`/app-embedded/${gamesPlatformEmbeddedVersion}/${paletteType}`,
gdGamesHost
);
if (gameId.current) url.searchParams.set('theme', paletteType);
if (gameId.current || isMobile) url.searchParams.set('theme', paletteType);
const src = loaded ? url.toString() : '';
React.useEffect(
() => {
if (!loaded) {
// Every time the frame is unloaded, we reset it for the next load.
if (!loaded && initialGameId) {
// Every time the frame is unloaded on a gameId, we reset it for the next load.
gameId.current = initialGameId;
}
},

View File

@@ -44,21 +44,6 @@ const getDefaultGroup = ({ id }: {| id: string |}) => ({
});
describe('groupMembersByGroupId', () => {
test('Works if there are no members', () => {
expect(
groupMembersByGroupId({
groups: [],
members: [],
memberships: [],
})
).toEqual({
active: {
NONE: { group: { id: 'none', name: 'none' }, members: [] },
},
inactive: [],
});
});
test("All members are returned in the NONE group if they don't have a group yet", () => {
const user1 = getDefaultUser({ id: 'user-id-1' });
const user2 = getDefaultUser({ id: 'user-id-2' });
@@ -131,7 +116,6 @@ describe('groupMembersByGroupId', () => {
})
).toEqual({
active: {
NONE: { group: { id: 'none', name: 'none' }, members: [] },
[group1.id]: { group: group1, members: [] },
[group2.id]: { group: group2, members: [] },
},
@@ -161,7 +145,6 @@ describe('groupMembersByGroupId', () => {
})
).toEqual({
active: {
NONE: { group: { id: 'none', name: 'none' }, members: [] },
[group1.id]: { group: group1, members: [user1, user2, user3, user5] },
[group2.id]: { group: group2, members: [] },
},

View File

@@ -20,9 +20,7 @@ export const groupMembersByGroupId = ({
inactive: User[],
|} => {
if (!(groups && members && memberships)) return null;
const membersByGroupId = {
NONE: { group: { id: 'none', name: 'none' }, members: [] },
};
const membersByGroupId = {};
const deactivatedMembers = [];
members.forEach(member => {
const membership = memberships.find(

View File

@@ -169,7 +169,6 @@ export type HomePageEditorInterface = {|
scene: gdLayout,
objectWithContext: ObjectWithContext
) => void,
onSceneObjectsDeleted: (scene: gdLayout) => void,
|};
export const HomePage = React.memo<Props>(
@@ -483,17 +482,12 @@ export const HomePage = React.memo<Props>(
[]
);
const onSceneObjectsDeleted = React.useCallback((scene: gdLayout) => {
// No thing to be done.
}, []);
React.useImperativeHandle(ref, () => ({
getProject,
updateToolbar,
forceUpdateEditor,
onEventsBasedObjectChildrenEdited,
onSceneObjectEdited,
onSceneObjectsDeleted,
}));
const onUserSurveyStarted = React.useCallback(() => {

View File

@@ -41,10 +41,6 @@ export class ResourcesEditorContainer extends React.Component<RenderEditorContai
// No thing to be done.
}
onSceneObjectsDeleted(scene: gdLayout) {
// No thing to be done.
}
componentDidUpdate(prevProps: RenderEditorContainerProps) {
if (
this.editor &&

View File

@@ -79,20 +79,6 @@ export class SceneEditorContainer extends React.Component<RenderEditorContainerP
}
}
onSceneObjectsDeleted(scene: gdLayout) {
const layout = this.getLayout();
if (!layout) {
return;
}
if (layout !== scene) {
return;
}
const { editor } = this;
if (editor) {
editor.forceUpdateObjectsList();
}
}
getLayout(): ?gdLayout {
const { project, projectItemName } = this.props;
if (
@@ -174,10 +160,8 @@ export class SceneEditorContainer extends React.Component<RenderEditorContainerP
onObjectEdited={objectWithContext =>
this.props.onSceneObjectEdited(layout, objectWithContext)
}
onObjectsDeleted={() => this.props.onSceneObjectsDeleted(layout)}
// It's only used to refresh events-based object variants.
onObjectGroupEdited={() => {}}
onObjectGroupsDeleted={() => {}}
// Nothing to do as scenes are not events-based objects.
onEventsBasedObjectChildrenEdited={() => {}}
/>

View File

@@ -203,7 +203,6 @@ import useHomepageWitchForRouting from './UseHomepageWitchForRouting';
import RobotIcon from '../ProjectCreation/RobotIcon';
import PublicProfileContext from '../Profile/PublicProfileContext';
import { useGamesPlatformFrame } from './EditorContainers/HomePage/PlaySection/UseGamesPlatformFrame';
import { useExtensionLoadErrorDialog } from '../Utils/UseExtensionLoadErrorDialog';
const GD_STARTUP_TIMES = global.GD_STARTUP_TIMES || [];
@@ -372,10 +371,9 @@ const MainFrame = (props: Props) => {
chooseResourceOptions,
setChooseResourceOptions,
] = React.useState<?ChooseResourceOptions>(null);
const [onResourceChosen, setOnResourceChosen] = React.useState<?({|
selectedResources: Array<gdResource>,
selectedSourceName: string,
|}) => void>(null);
const [onResourceChosen, setOnResourceChosen] = React.useState<?(
Array<gdResource>
) => void>(null);
const _previewLauncher = React.useRef((null: ?PreviewLauncherInterface));
const forceUpdate = useForceUpdate();
const [isLoadingProject, setIsLoadingProject] = React.useState<boolean>(
@@ -553,12 +551,6 @@ const MainFrame = (props: Props) => {
gamesList,
});
const {
setExtensionLoadingResults,
hasExtensionLoadErrors,
renderExtensionLoadErrorDialog,
} = useExtensionLoadErrorDialog();
/**
* This reference is useful to get the current opened project,
* even in the callback of a hook/promise - without risking to read "stale" data.
@@ -816,26 +808,36 @@ const MainFrame = (props: Props) => {
return extensionsLoader
.loadAllExtensions(getNotNullTranslationFunction(i18n))
.then(
({
expectedNumberOfJSExtensionModulesLoaded,
results: loadingResults,
}) => {
const successLoadingResults = loadingResults.filter(
loadingResult => !loadingResult.result.error
.then(loadingResults => {
const successLoadingResults = loadingResults.filter(
loadingResult => !loadingResult.result.error
);
const failLoadingResults = loadingResults.filter(
loadingResult =>
loadingResult.result.error && !loadingResult.result.dangerous
);
const dangerousLoadingResults = loadingResults.filter(
loadingResult =>
loadingResult.result.error && loadingResult.result.dangerous
);
console.info(`Loaded ${successLoadingResults.length} JS extensions.`);
if (failLoadingResults.length) {
console.error(
`⚠️ Unable to load ${
failLoadingResults.length
} JS extensions. Please check these errors:`,
failLoadingResults
);
console.info(
`Loaded ${
successLoadingResults.length
}/${expectedNumberOfJSExtensionModulesLoaded} JS extensions.`
);
setExtensionLoadingResults({
expectedNumberOfJSExtensionModulesLoaded,
results: loadingResults,
});
}
);
if (dangerousLoadingResults.length) {
console.error(
`💣 Dangerous exceptions while loading ${
dangerousLoadingResults.length
} JS extensions. 🔥 Please check these errors as they will CRASH GDevelop:`,
dangerousLoadingResults
);
}
});
};
useDiscordRichPresence(currentProject);
@@ -2350,18 +2352,6 @@ const MainFrame = (props: Props) => {
[state.editorTabs]
);
const onSceneObjectsDeleted = React.useCallback(
(scene: gdLayout) => {
for (const editor of state.editorTabs.editors) {
const { editorRef } = editor;
if (editorRef) {
editorRef.onSceneObjectsDeleted(scene);
}
}
},
[state.editorTabs]
);
const _onProjectItemModified = () => {
triggerUnsavedChanges();
forceUpdate();
@@ -2725,9 +2715,6 @@ const MainFrame = (props: Props) => {
|}
) => {
if (!currentProject) return;
// Prevent saving if there are errors in the extension modules, as
// this can lead to corrupted projects.
if (hasExtensionLoadErrors) return;
saveUiSettings(state.editorTabs);
@@ -2946,7 +2933,6 @@ const MainFrame = (props: Props) => {
showAlert,
showConfirmation,
gamesList,
hasExtensionLoadErrors,
]
);
@@ -2958,9 +2944,6 @@ const MainFrame = (props: Props) => {
if (!canSaveProjectAs) {
return;
}
// Prevent saving if there are errors in the extension modules, as
// this can lead to corrupted projects.
if (hasExtensionLoadErrors) return;
if (cloudProjectRecoveryOpenedVersionId && !cloudProjectSaveChoiceOpen) {
setCloudProjectSaveChoiceOpen(true);
@@ -2987,17 +2970,12 @@ const MainFrame = (props: Props) => {
cloudProjectRecoveryOpenedVersionId,
cloudProjectSaveChoiceOpen,
canSaveProjectAs,
hasExtensionLoadErrors,
]
);
const saveProject = React.useCallback(
async () => {
if (!currentProject) return;
// Prevent saving if there are errors in the extension modules, as
// this can lead to corrupted projects.
if (hasExtensionLoadErrors) return;
if (!currentFileMetadata) {
return saveProjectAs();
}
@@ -3157,7 +3135,6 @@ const MainFrame = (props: Props) => {
showConfirmation,
checkedOutVersionStatus,
gamesList,
hasExtensionLoadErrors,
]
);
@@ -3344,11 +3321,9 @@ const MainFrame = (props: Props) => {
(options: ChooseResourceOptions) => {
return new Promise(resolve => {
setChooseResourceOptions(options);
const onResourceChosenSetter: () => ({|
selectedResources: Array<gdResource>,
selectedSourceName: string,
|}) => void = () => resolve;
const onResourceChosenSetter: () => (
Promise<Array<gdResource>> | Array<gdResource>
) => void = () => resolve;
setOnResourceChosen(onResourceChosenSetter);
});
},
@@ -4060,7 +4035,6 @@ const MainFrame = (props: Props) => {
onDeleteEventsBasedObjectVariant: deleteEventsBasedObjectVariant,
onEventsBasedObjectChildrenEdited: onEventsBasedObjectChildrenEdited,
onSceneObjectEdited: onSceneObjectEdited,
onSceneObjectsDeleted: onSceneObjectsDeleted,
onExtensionInstalled: onExtensionInstalled,
gamesList,
gamesPlatformFrameTools,
@@ -4124,18 +4098,15 @@ const MainFrame = (props: Props) => {
getStorageProvider={getStorageProvider}
i18n={i18n}
resourceSources={resourceSources}
onChooseResources={resourcesOptions => {
onChooseResources={resources => {
setOnResourceChosen(null);
setChooseResourceOptions(null);
onResourceChosen(resourcesOptions);
onResourceChosen(resources);
}}
onClose={() => {
setOnResourceChosen(null);
setChooseResourceOptions(null);
onResourceChosen({
selectedResources: [],
selectedSourceName: '',
});
onResourceChosen([]);
}}
options={chooseResourceOptions}
/>
@@ -4227,7 +4198,6 @@ const MainFrame = (props: Props) => {
{renderResourceFetcherDialog()}
{renderVersionHistoryPanel()}
{renderSaveReminder()}
{renderExtensionLoadErrorDialog()}
<CloseConfirmDialog
shouldPrompt={!!state.currentProject}
i18n={props.i18n}

View File

@@ -233,9 +233,8 @@ const Cube3DEditor = ({
!hasLight(layout) && (
<AlertMessage kind="error">
<Trans>
Make sure to set up a light in the effects of the layer or
choose "No lighting effect" - otherwise the object will appear
black.
Make sure to set up a light in the effects of the layer or chose
"No lighting effect" - otherwise the object will appear black.
</Trans>
</AlertMessage>
)}

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