Compare commits

..

50 Commits

Author SHA1 Message Date
Florian Rival
ec16740520 Add descriptions of instances to simplified project 2025-06-13 12:41:09 +02:00
Florian Rival
e26e239b1c Merge branch 'master' into feat/commands 2025-06-12 15:37:52 +02:00
Florian Rival
0e48539a99 Adapt styling of AI chat 2025-06-12 13:42:49 +02:00
Florian Rival
d8a8e759a0 Add support for project specific extension summaries for AI requests 2025-06-11 01:31:09 +02:00
Florian Rival
36c03a054e Merge branch 'master' into feat/commands 2025-06-09 14:44:09 +02:00
Florian Rival
313d60a315 Improve Ask AI UI and fix platformer behavior default controls boolean 2025-06-08 01:10:42 +02:00
Florian Rival
5dd2f85796 Update wording 2025-06-06 00:45:28 +02:00
Florian Rival
7e844ae539 Fix crash when switching to events editor after changes outside of it and allow undo/redo AI changes in events 2025-06-05 16:59:16 +02:00
Florian Rival
78da8185e5 Ensure behavior shared data are updated when a new behavior is added from an editor function call 2025-06-05 12:44:08 +02:00
Florian Rival
6de8b5503d Make property change non case sensitive in editor function calls 2025-06-04 16:11:36 +02:00
Florian Rival
ea4c9ff3fa Merge branch 'master' into feat/commands 2025-06-04 00:21:09 +02:00
Florian Rival
2762415729 Add support for AI editing array variables 2025-06-02 19:42:43 +02:00
Florian Rival
90a34bd7d7 Merge branch 'master' into feat/commands 2025-05-30 17:20:03 +02:00
Florian Rival
31364bc487 Add support for automatically declaring object variables in AI generated events 2025-05-30 16:33:44 +02:00
Florian Rival
42b23f0d29 Add support for object group variables in simplified project + add support for result message in events generation 2025-05-30 12:07:16 +02:00
Florian Rival
b485bd0007 Ensure required behavior created when new behavior added from a editor function call, add property values and fix useless change in newly created object names 2025-05-29 21:49:13 +02:00
Florian Rival
c7a1883e1b Merge branch 'master' into feat/commands 2025-05-29 18:33:05 +02:00
Florian Rival
701b1d54e4 Add display of AI generated event details, render existing events always in English 2025-05-27 12:10:58 +02:00
Florian Rival
95864b41d8 Add support for sending object groups to the AI agent and add undeclared variables in generated events 2025-05-24 16:23:41 +02:00
Florian Rival
14a1a5d746 Add listing of properties when adding an object or behavior 2025-05-22 16:52:08 +02:00
Florian Rival
eb5acecb84 Add listing of behaviors when inspecting object in editor functions 2025-05-22 15:41:59 +02:00
Florian Rival
04b1309f50 Add support for background color in editor function calls 2025-05-22 00:32:45 +02:00
Florian Rival
babf0153a1 Add asset store support to AI agent 2025-05-21 23:15:43 +02:00
Florian Rival
a7b27b4d2d Fix past function calls wrongly displayed when a new result for same call_id arrives 2025-05-19 15:11:49 +02:00
Florian Rival
78c4f4b7a5 Add proper display of failed and ignored function calls 2025-05-18 18:17:09 +02:00
Florian Rival
96206aac29 Refactor events generation and AI chat messages display 2025-05-18 17:09:23 +02:00
Florian Rival
95a938d93b Merge branch 'master' into feat/commands 2025-05-16 10:24:28 +02:00
Florian Rival
0286ecd139 Add user friendly rendering of AI function calls 2025-05-15 18:32:28 +02:00
Florian Rival
297be166cd Install extension from generated events 2025-05-14 17:07:31 +02:00
Florian Rival
e626acdd21 Allow to choose between agent or chat for AI requests 2025-05-14 15:29:23 +02:00
Florian Rival
bf1f33b57a Adapt to updated endpoints 2025-05-13 13:42:42 +02:00
Florian Rival
890719b292 Add support for placement hint and new changes format for generated events 2025-05-09 16:47:56 +02:00
Florian Rival
e4815a1cb6 Merge branch 'master' into feat/commands 2025-05-08 12:28:04 +02:00
Florian Rival
d51cc42a64 Improve messaging of capabilities 2025-05-08 12:27:53 +02:00
Florian Rival
39a41e486d Implement insertion/replacement of events 2025-05-07 17:52:33 +02:00
Florian Rival
6e857629bf Implement existingEventsAsText for ai events generation 2025-05-06 19:17:51 +02:00
Florian Rival
67a81549d1 Add text renderer for events 2025-05-04 17:48:24 +02:00
Florian Rival
5f1c879b4c Refactor 2025-05-04 16:09:29 +02:00
Florian Rival
521cfe2f97 Allow to continue after pausing the AI agent 2025-05-03 18:20:09 +02:00
Florian Rival
e4cc5023f8 Improve display of banner for working AI 2025-05-03 17:30:26 +02:00
Florian Rival
5f983bef1c Refactor function calls and ensure extension is installed when adding a behavior 2025-05-03 14:40:22 +02:00
Florian Rival
3878e99d4f Improve styling 2025-05-03 12:40:20 +02:00
Florian Rival
c9086554e2 Add function to add/edit variable 2025-05-01 19:52:20 +02:00
Florian Rival
69e207fab4 WIP
- Auto process
- Improve behavior type not correct should send an error message
2025-04-30 16:26:06 +02:00
Florian Rival
bdc674eda3 Hide hidden properties from function calls 2025-04-29 18:01:31 +02:00
Florian Rival
d28b0c650d Merge branch 'master' into feat/commands 2025-04-29 10:48:16 +02:00
Florian Rival
78681eaba2 Add support for ignoring function calls 2025-04-29 09:11:39 +02:00
Florian Rival
48fa608c17 WIP: UI for function calls + events generation + rework AI requests UI to support multiple in parallels properly 2025-04-26 15:00:18 +02:00
Florian Rival
6acecae77d WIP: prototype function calls 2025-04-24 17:05:33 +02:00
Florian Rival
0a30e1e870 Extract SafeExtractor as a separate file 2025-04-13 14:40:56 +02:00
519 changed files with 9217 additions and 36452 deletions

View File

@@ -18,13 +18,13 @@ jobs:
# Build the **entire** app for macOS (including the GDevelop.js library).
build-macos:
macos:
xcode: 16.4.0
resource_class: m4pro.medium
xcode: 14.2.0
resource_class: macos.m1.large.gen1
steps:
- checkout
# Install Rosetta for AWS CLI and disable TSO to speed up S3 uploads (https://support.circleci.com/hc/en-us/articles/19334402064027-Troubleshooting-slow-uploads-to-S3-for-jobs-using-an-m1-macOS-resource-class)
- macos/install-rosetta
# - run: sudo sysctl net.inet.tcp.tso=0
- run: sudo sysctl net.inet.tcp.tso=0
# Install a recent version of npm to workaround a notarization issue because of a symlink made by npm: https://github.com/electron-userland/electron-builder/issues/7755
# Node.js v20.14.0 comes with npm v10.7.0.
@@ -88,35 +88,13 @@ jobs:
- store_artifacts:
path: newIDE/electron-app/dist
# Upload artifacts (AWS)
- run:
name: Deploy to S3 (specific commit)
command: |
export PATH=~/.local/bin:$PATH
for i in 1 2 3 4 5 6 7; do
aws s3 sync newIDE/electron-app/dist s3://gdevelop-releases/$(git rev-parse --abbrev-ref HEAD)/commit/$(git rev-parse HEAD)/ && break
echo "Retry $i failed... retrying in 10 seconds"
sleep 10
done
if [ $i -eq 7 ]; then
echo "All retries for deployment failed!" >&2
exit 1
fi
command: export PATH=~/.local/bin:$PATH && aws s3 sync newIDE/electron-app/dist s3://gdevelop-releases/$(git rev-parse --abbrev-ref HEAD)/commit/$(git rev-parse HEAD)/
- run:
name: Deploy to S3 (latest)
command: |
export PATH=~/.local/bin:$PATH
for i in 1 2 3 4 5 6 7; do
aws s3 sync newIDE/electron-app/dist s3://gdevelop-releases/$(git rev-parse --abbrev-ref HEAD)/latest/ && break
echo "Retry $i failed... retrying in 10 seconds"
sleep 10
done
if [ $i -eq 7 ]; then
echo "All retries for deployment failed!" >&2
exit 1
fi
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-linux:
@@ -390,7 +368,7 @@ jobs:
npm -v
Remove-Item package-lock.json
$Env:REQUIRES_EXACT_LIBGD_JS_VERSION = "true"
npm install
@@ -447,10 +425,10 @@ jobs:
$Env:GD_SIGNTOOL_THUMBPRINT = ''
$Env:GD_SIGNTOOL_SUBJECT_NAME = ''
$Env:GD_SIGNTOOL_SUBJECT_NAME = ''
$Env:CSC_LINK = ''
$Env:CSC_KEY_PASSWORD = ''
node scripts/build.js --skip-app-build --win appx --publish=never
@@ -467,16 +445,16 @@ jobs:
name: Install AWS CLI
command: |
# Install the CLI for the current user
pip install --quiet --upgrade --user awscli
# Add the user-Scripts dir to PATH for this step and the next.
$binDir = (python -m site --user-base) + "\Scripts"
$Env:Path += ";$binDir"
# Sanity check:
aws --version
aws --version
# Upload artifacts (S3)
- run:

1
.gitignore vendored
View File

@@ -33,4 +33,3 @@
.Spotlight-V100
.Trashes
Thumbs.db
.claude

3
.vscode/tasks.json vendored
View File

@@ -38,7 +38,8 @@
"presentation": {
"reveal": "silent"
},
"isBackground": true
"isBackground": true,
"runOptions": { "instanceLimit": 1, "runOn": "folderOpen" }
},
{
"type": "npm",

View File

@@ -37,8 +37,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
.SetIcon("res/actions/position24_black.png");
extension.AddInstructionOrExpressionGroupMetadata(_("Angle"))
.SetIcon("res/actions/direction24_black.png");
extension.AddInstructionOrExpressionGroupMetadata(_("Size")).SetIcon(
"res/actions/scale24_black.png");
extension.AddInstructionOrExpressionGroupMetadata(_("Size"))
.SetIcon("res/actions/scale24_black.png");
gd::ObjectMetadata& obj = extension.AddObject<gd::ObjectConfiguration>(
"", _("Base object"), _("Base object"), "res/objeticon24.png");
@@ -235,8 +235,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
obj.AddAction("SetAngle",
_("Angle"),
_("Change the angle of rotation of an object (in degrees). For "
"3D objects, this is the rotation around the Z axis."),
_("Change the angle of rotation of an object (in degrees)."),
_("the angle"),
_("Angle"),
"res/actions/direction24_black.png",
@@ -251,8 +250,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
obj.AddAction("Rotate",
_("Rotate"),
_("Rotate an object, clockwise if the speed is positive, "
"counterclockwise otherwise. For 3D objects, this is the "
"rotation around the Z axis."),
"counterclockwise otherwise."),
_("Rotate _PARAM0_ at speed _PARAM1_ deg/second"),
_("Angle"),
"res/actions/rotate24_black.png",
@@ -636,8 +634,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
obj.AddCondition("Angle",
_("Angle"),
_("Compare the angle, in degrees, of the specified object. "
"For 3D objects, this is the angle around the Z axis."),
_("Compare the angle of the specified object."),
_("the angle (in degrees)"),
_("Angle"),
"res/conditions/direction24_black.png",
@@ -838,13 +835,14 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
.MarkAsAdvanced()
.SetRelevantForLayoutEventsOnly();
obj.AddAction("PushBooleanToObjectVariable",
_("Add value to object array variable"),
_("Adds a boolean to the end of an object array variable."),
_("Add value _PARAM2_ to array variable _PARAM1_ of _PARAM0_"),
_("Variables Arrays and structures"),
"res/actions/var24.png",
"res/actions/var.png")
obj.AddAction(
"PushBooleanToObjectVariable",
_("Add value to object array variable"),
_("Adds a boolean to the end of an object array variable."),
_("Add value _PARAM2_ to array variable _PARAM1_ of _PARAM0_"),
_("Variables Arrays and structures"),
"res/actions/var24.png",
"res/actions/var.png")
.AddParameter("object", _("Object"))
.AddParameter("objectvar", _("Array variable"))
.AddParameter("trueorfalse", _("Boolean to add"))
@@ -1270,8 +1268,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
obj.AddExpression("Angle",
_("Angle"),
_("Current angle, in degrees, of the object. For 3D "
"objects, this is the angle around the Z axis."),
_("Current angle, in degrees, of the object"),
_("Angle"),
"res/actions/direction_black.png")
.AddParameter("object", _("Object"));
@@ -1574,9 +1571,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
extension
.AddAction("Create",
_("Create an object"),
_("Create an instance of the object at the specified position."
"The created object instance will be available for the next "
"actions and sub-events."),
_("Create an object at specified position"),
_("Create object _PARAM1_ at position _PARAM2_;_PARAM3_ "
"(layer: _PARAM4_)"),
"",

View File

@@ -72,8 +72,7 @@ BuiltinExtensionsImplementer::ImplementsMathematicalToolsExtension(
extension
.AddExpression("normalize",
_("Normalize a value between `min` and `max` to a value "
"between 0 and 1."),
_("Normalize a value between `min` and `max` to a value between 0 and 1."),
_("Remap a value between 0 and 1."),
"",
"res/mathfunction.png")
@@ -125,8 +124,7 @@ BuiltinExtensionsImplementer::ImplementsMathematicalToolsExtension(
extension
.AddExpression("mod",
_("Modulo"),
_("Compute \"x mod y\". GDevelop does NOT support the \% "
"operator. Use this mod(x, y) function instead."),
_("x mod y"),
"",
"res/mathfunction.png")
.AddParameter("expression", _("x (as in x mod y)"))
@@ -186,8 +184,11 @@ BuiltinExtensionsImplementer::ImplementsMathematicalToolsExtension(
.AddParameter("expression", _("Expression"));
extension
.AddExpression(
"asinh", _("Arcsine"), _("Arcsine"), "", "res/mathfunction.png")
.AddExpression("asinh",
_("Arcsine"),
_("Arcsine"),
"",
"res/mathfunction.png")
.AddParameter("expression", _("Expression"));
extension
@@ -217,8 +218,11 @@ BuiltinExtensionsImplementer::ImplementsMathematicalToolsExtension(
.AddParameter("expression", _("Expression"));
extension
.AddExpression(
"cbrt", _("Cube root"), _("Cube root"), "", "res/mathfunction.png")
.AddExpression("cbrt",
_("Cube root"),
_("Cube root"),
"",
"res/mathfunction.png")
.AddParameter("expression", _("Expression"));
extension
@@ -256,13 +260,12 @@ BuiltinExtensionsImplementer::ImplementsMathematicalToolsExtension(
.AddParameter("expression", _("Expression"), "", true);
extension
.AddExpression(
"cos",
_("Cosine"),
_("Cosine of an angle (in radian). "
"If you want to use degrees, use`ToRad`: `sin(ToRad(45))`."),
"",
"res/mathfunction.png")
.AddExpression("cos",
_("Cosine"),
_("Cosine of an angle (in radian). "
"If you want to use degrees, use`ToRad`: `sin(ToRad(45))`."),
"",
"res/mathfunction.png")
.AddParameter("expression", _("Expression"));
extension
@@ -290,20 +293,29 @@ BuiltinExtensionsImplementer::ImplementsMathematicalToolsExtension(
.AddParameter("expression", _("Expression"));
extension
.AddExpression(
"int", _("Round"), _("Round a number"), "", "res/mathfunction.png")
.AddExpression("int",
_("Round"),
_("Round a number"),
"",
"res/mathfunction.png")
.SetHidden()
.AddParameter("expression", _("Expression"));
extension
.AddExpression(
"rint", _("Round"), _("Round a number"), "", "res/mathfunction.png")
.AddExpression("rint",
_("Round"),
_("Round a number"),
"",
"res/mathfunction.png")
.SetHidden()
.AddParameter("expression", _("Expression"));
extension
.AddExpression(
"round", _("Round"), _("Round a number"), "", "res/mathfunction.png")
.AddExpression("round",
_("Round"),
_("Round a number"),
"",
"res/mathfunction.png")
.AddParameter("expression", _("Expression"));
extension
@@ -312,8 +324,8 @@ BuiltinExtensionsImplementer::ImplementsMathematicalToolsExtension(
_("Round a number to the Nth decimal place"),
"",
"res/mathfunction.png")
.AddParameter("expression", _("Number to Round"))
.AddParameter("expression", _("Decimal Places"), "", true);
.AddParameter("expression", _("Expression"))
.AddParameter("expression", _("Expression"), "", true);
extension
.AddExpression("exp",
@@ -324,13 +336,19 @@ BuiltinExtensionsImplementer::ImplementsMathematicalToolsExtension(
.AddParameter("expression", _("Expression"));
extension
.AddExpression(
"log", _("Logarithm"), _("Logarithm"), "", "res/mathfunction.png")
.AddExpression("log",
_("Logarithm"),
_("Logarithm"),
"",
"res/mathfunction.png")
.AddParameter("expression", _("Expression"));
extension
.AddExpression(
"ln", _("Logarithm"), _("Logarithm"), "", "res/mathfunction.png")
.AddExpression("ln",
_("Logarithm"),
_("Logarithm"),
"",
"res/mathfunction.png")
.SetHidden()
.AddParameter("expression", _("Expression"));
@@ -369,8 +387,11 @@ BuiltinExtensionsImplementer::ImplementsMathematicalToolsExtension(
.AddParameter("expression", _("The exponent (n in x^n)"));
extension
.AddExpression(
"sec", _("Secant"), _("Secant"), "", "res/mathfunction.png")
.AddExpression("sec",
_("Secant"),
_("Secant"),
"",
"res/mathfunction.png")
.AddParameter("expression", _("Expression"));
extension
@@ -382,13 +403,12 @@ BuiltinExtensionsImplementer::ImplementsMathematicalToolsExtension(
.AddParameter("expression", _("Expression"));
extension
.AddExpression(
"sin",
_("Sine"),
_("Sine of an angle (in radian). "
"If you want to use degrees, use`ToRad`: `sin(ToRad(45))`."),
"",
"res/mathfunction.png")
.AddExpression("sin",
_("Sine"),
_("Sine of an angle (in radian). "
"If you want to use degrees, use`ToRad`: `sin(ToRad(45))`."),
"",
"res/mathfunction.png")
.AddParameter("expression", _("Expression"));
extension
@@ -408,13 +428,12 @@ BuiltinExtensionsImplementer::ImplementsMathematicalToolsExtension(
.AddParameter("expression", _("Expression"));
extension
.AddExpression(
"tan",
_("Tangent"),
_("Tangent of an angle (in radian). "
"If you want to use degrees, use`ToRad`: `tan(ToRad(45))`."),
"",
"res/mathfunction.png")
.AddExpression("tan",
_("Tangent"),
_("Tangent of an angle (in radian). "
"If you want to use degrees, use`ToRad`: `tan(ToRad(45))`."),
"",
"res/mathfunction.png")
.AddParameter("expression", _("Expression"));
extension
@@ -444,28 +463,26 @@ BuiltinExtensionsImplementer::ImplementsMathematicalToolsExtension(
.AddParameter("expression", _("x (in a+(b-a)*x)"));
extension
.AddExpression(
"XFromAngleAndDistance",
_("X position from angle and distance"),
_("Compute the X position when given an angle and distance "
"relative to the origin (0;0). This is also known as "
"getting the cartesian coordinates of a 2D vector, using "
"its polar coordinates."),
"",
"res/mathfunction.png")
.AddExpression("XFromAngleAndDistance",
_("X position from angle and distance"),
_("Compute the X position when given an angle and distance "
"relative to the origin (0;0). This is also known as "
"getting the cartesian coordinates of a 2D vector, using "
"its polar coordinates."),
"",
"res/mathfunction.png")
.AddParameter("expression", _("Angle, in degrees"))
.AddParameter("expression", _("Distance"));
extension
.AddExpression(
"YFromAngleAndDistance",
_("Y position from angle and distance"),
_("Compute the Y position when given an angle and distance "
"relative to the origin (0;0). This is also known as "
"getting the cartesian coordinates of a 2D vector, using "
"its polar coordinates."),
"",
"res/mathfunction.png")
.AddExpression("YFromAngleAndDistance",
_("Y position from angle and distance"),
_("Compute the Y position when given an angle and distance "
"relative to the origin (0;0). This is also known as "
"getting the cartesian coordinates of a 2D vector, using "
"its polar coordinates."),
"",
"res/mathfunction.png")
.AddParameter("expression", _("Angle, in degrees"))
.AddParameter("expression", _("Distance"));
@@ -480,8 +497,7 @@ BuiltinExtensionsImplementer::ImplementsMathematicalToolsExtension(
extension
.AddExpression("lerpAngle",
_("Lerp (Linear interpolation) between two angles"),
_("Linearly interpolates between two angles (in degrees) "
"by taking the shortest direction around the circle."),
_("Linearly interpolates between two angles (in degrees) by taking the shortest direction around the circle."),
"",
"res/mathfunction.png")
.AddParameter("expression", _("Starting angle, in degrees"))

View File

@@ -63,6 +63,7 @@ void EventsBasedObjectVariantHelper::ComplyVariantsToEventsBasedObject(
}
// Copy missing behaviors
auto &behaviors = object.GetAllBehaviorContents();
for (const auto &pair : defaultBehaviors) {
const auto &behaviorName = pair.first;
const auto &defaultBehavior = pair.second;
@@ -81,9 +82,11 @@ void EventsBasedObjectVariantHelper::ComplyVariantsToEventsBasedObject(
}
}
// Delete extra behaviors
for (auto &behaviorName : object.GetAllBehaviorNames()) {
for (auto it = behaviors.begin(); it != behaviors.end(); ++it) {
const auto &behaviorName = it->first;
if (!defaultObject->HasBehaviorNamed(behaviorName)) {
object.RemoveBehavior(behaviorName);
--it;
}
}

View File

@@ -250,28 +250,25 @@ void CustomObjectConfiguration::ExposeResources(gd::ArbitraryResourceWorker& wor
}
const auto &eventsBasedObject = project->GetEventsBasedObject(GetType());
if (IsForcedToOverrideEventsBasedObjectChildrenConfiguration()) {
for (auto &childObject : eventsBasedObject.GetObjects().GetObjects()) {
auto &configuration = GetChildObjectConfiguration(childObject->GetName());
configuration.ExposeResources(worker);
}
}
else if (eventsBasedObject.GetVariants().HasVariantNamed(variantName)) {
for (auto &childObject : eventsBasedObject.GetVariants()
.GetVariant(variantName)
.GetObjects()
.GetObjects()) {
childObject->GetConfiguration().ExposeResources(worker);
}
} else if (isMarkedAsOverridingEventsBasedObjectChildrenConfiguration) {
if (isMarkedAsOverridingEventsBasedObjectChildrenConfiguration) {
for (auto &childObject : eventsBasedObject.GetObjects().GetObjects()) {
auto &configuration = GetChildObjectConfiguration(childObject->GetName());
configuration.ExposeResources(worker);
}
} else {
for (auto &childObject :
eventsBasedObject.GetDefaultVariant().GetObjects().GetObjects()) {
childObject->GetConfiguration().ExposeResources(worker);
if (variantName.empty() ||
!eventsBasedObject.GetVariants().HasVariantNamed(variantName)) {
for (auto &childObject :
eventsBasedObject.GetDefaultVariant().GetObjects().GetObjects()) {
childObject->GetConfiguration().ExposeResources(worker);
}
} else {
for (auto &childObject : eventsBasedObject.GetVariants()
.GetVariant(variantName)
.GetObjects()
.GetObjects()) {
childObject->GetConfiguration().ExposeResources(worker);
}
}
}
}

View File

@@ -78,15 +78,6 @@ public:
variantName = variantName_;
}
/**
* Legacy events-based objects don't have any instance in their default
* variant since there wasn't a graphical editor at the time. In this case,
* the editor doesn't allow to choose a variant, but a variant may have stayed
* after a user rolled back the extension. This variant must be ignored.
*
* @return true when its events-based object doesn't have any initial
* instance.
*/
bool IsForcedToOverrideEventsBasedObjectChildrenConfiguration() const;
bool IsMarkedAsOverridingEventsBasedObjectChildrenConfiguration() const {

View File

@@ -8,8 +8,6 @@
#include "GDCore/Serialization/SerializerElement.h"
namespace gd {
gd::String Effect::badStringParameterValue;
void Effect::SerializeTo(SerializerElement& element) const {
element.SetAttribute("name", GetName());

View File

@@ -3,7 +3,8 @@
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#pragma once
#ifndef GDCORE_EFFECT_H
#define GDCORE_EFFECT_H
#include <map>
namespace gd {
class SerializerElement;
@@ -34,43 +35,28 @@ class GD_CORE_API Effect {
void SetFolded(bool fold = true) { folded = fold; }
bool IsFolded() const { return folded; }
void SetDoubleParameter(const gd::String &name, double value) {
void SetDoubleParameter(const gd::String& name, double value) {
doubleParameters[name] = value;
}
double GetDoubleParameter(const gd::String &name) const {
auto itr = doubleParameters.find(name);
return itr == doubleParameters.end() ? 0 : itr->second;
double GetDoubleParameter(const gd::String& name) {
return doubleParameters[name];
}
bool HasDoubleParameter(const gd::String &name) const {
return doubleParameters.find(name) != doubleParameters.end();
}
void SetStringParameter(const gd::String &name, const gd::String &value) {
void SetStringParameter(const gd::String& name, const gd::String& value) {
stringParameters[name] = value;
}
const gd::String &GetStringParameter(const gd::String &name) const {
auto itr = stringParameters.find(name);
return itr == stringParameters.end() ? badStringParameterValue : itr->second;
const gd::String& GetStringParameter(const gd::String& name) {
return stringParameters[name];
}
bool HasStringParameter(const gd::String &name) const {
return stringParameters.find(name) != stringParameters.end();
}
void SetBooleanParameter(const gd::String &name, bool value) {
void SetBooleanParameter(const gd::String& name, bool value) {
booleanParameters[name] = value;
}
bool GetBooleanParameter(const gd::String &name) const {
auto itr = booleanParameters.find(name);
return itr == booleanParameters.end() ? false : itr->second;
}
bool HasBooleanParameter(const gd::String &name) const {
return booleanParameters.find(name) != booleanParameters.end();
bool GetBooleanParameter(const gd::String& name) {
return booleanParameters[name];
}
const std::map<gd::String, double>& GetAllDoubleParameters() const {
@@ -108,9 +94,7 @@ class GD_CORE_API Effect {
std::map<gd::String, double> doubleParameters; ///< Values of parameters being doubles, keyed by names.
std::map<gd::String, gd::String> stringParameters; ///< Values of parameters being strings, keyed by names.
std::map<gd::String, bool> booleanParameters; ///< Values of parameters being booleans, keyed by names.
static gd::String badStringParameterValue; ///< Empty string returned by
///< GeStringParameter
};
} // namespace gd
#endif

View File

@@ -365,8 +365,6 @@ class GD_CORE_API InitialInstance {
* the same initial instance between serialization.
*/
InitialInstance& ResetPersistentUuid();
const gd::String& GetPersistentUuid() const { return persistentUuid; }
///@}
private:

View File

@@ -36,7 +36,7 @@ namespace gd {
gd::BehaviorsSharedData Layout::badBehaviorSharedData("", "");
Layout::Layout(const Layout& other)
Layout::Layout(const Layout &other)
: objectsContainer(gd::ObjectsContainer::SourceType::Scene) {
Init(other);
}
@@ -54,8 +54,6 @@ Layout::Layout()
backgroundColorG(209),
backgroundColorB(209),
stopSoundsOnStartup(true),
resourcesPreloading("inherit"),
resourcesUnloading("inherit"),
standardSortMethod(true),
disableInputWhenNotFocused(true),
variables(gd::VariablesContainer::SourceType::Scene),
@@ -246,10 +244,6 @@ void Layout::SerializeTo(SerializerElement& element) const {
element.SetAttribute("title", GetWindowDefaultTitle());
element.SetAttribute("standardSortMethod", standardSortMethod);
element.SetAttribute("stopSoundsOnStartup", stopSoundsOnStartup);
if (resourcesPreloading != "inherit")
element.SetAttribute("resourcesPreloading", resourcesPreloading);
if (resourcesUnloading != "inherit")
element.SetAttribute("resourcesUnloading", resourcesUnloading);
element.SetAttribute("disableInputWhenNotFocused",
disableInputWhenNotFocused);
@@ -310,10 +304,6 @@ void Layout::UnserializeFrom(gd::Project& project,
element.GetStringAttribute("title", "(No title)", "titre"));
standardSortMethod = element.GetBoolAttribute("standardSortMethod");
stopSoundsOnStartup = element.GetBoolAttribute("stopSoundsOnStartup");
resourcesPreloading =
element.GetStringAttribute("resourcesPreloading", "inherit");
resourcesUnloading =
element.GetStringAttribute("resourcesUnloading", "inherit");
disableInputWhenNotFocused =
element.GetBoolAttribute("disableInputWhenNotFocused");
@@ -401,8 +391,6 @@ void Layout::Init(const Layout& other) {
standardSortMethod = other.standardSortMethod;
title = other.title;
stopSoundsOnStartup = other.stopSoundsOnStartup;
resourcesPreloading = other.resourcesPreloading;
resourcesUnloading = other.resourcesUnloading;
disableInputWhenNotFocused = other.disableInputWhenNotFocused;
initialInstances = other.initialInstances;
layers = other.layers;

View File

@@ -349,36 +349,6 @@ class GD_CORE_API Layout {
* launched
*/
bool StopSoundsOnStartup() const { return stopSoundsOnStartup; }
/**
* Set when the scene must preload its resources: `at-startup`, `never` or
* `inherit` (default).
*/
void SetResourcesPreloading(gd::String resourcesPreloading_) {
resourcesPreloading = resourcesPreloading_;
}
/**
* Get when the scene must preload its resources: `at-startup`, `never` or
* `inherit` (default).
*/
const gd::String& GetResourcesPreloading() const {
return resourcesPreloading;
}
/**
* Set when the scene must unload its resources: `at-scene-exit`, `never` or
* `inherit` (default).
*/
void SetResourcesUnloading(gd::String resourcesUnloading_) {
resourcesUnloading = resourcesUnloading_;
}
/**
* Get when the scene must unload its resources: `at-scene-exit`, `never` or
* `inherit` (default).
*/
const gd::String& GetResourcesUnloading() const { return resourcesUnloading; }
///@}
/** \name Saving and loading
@@ -411,10 +381,6 @@ class GD_CORE_API Layout {
behaviorsSharedData; ///< Initial shared datas of behaviors
bool stopSoundsOnStartup = true; ///< True to make the scene stop all sounds at
///< startup.
gd::String
resourcesPreloading; ///< `at-startup`, `never` or `inherit` (default).
gd::String
resourcesUnloading; ///< `at-scene-exit`, `never` or `inherit` (default).
bool standardSortMethod = true; ///< True to sort objects using standard sort.
bool disableInputWhenNotFocused = true; /// If set to true, the input must be
/// disabled when the window do not have the

View File

@@ -74,9 +74,7 @@ Project::Project()
gdMinorVersion(gd::VersionWrapper::Minor()),
gdBuildVersion(gd::VersionWrapper::Build()),
variables(gd::VariablesContainer::SourceType::Global),
objectsContainer(gd::ObjectsContainer::SourceType::Global),
sceneResourcesPreloading("at-startup"),
sceneResourcesUnloading("never") {}
objectsContainer(gd::ObjectsContainer::SourceType::Global) {}
Project::~Project() {}
@@ -1168,13 +1166,6 @@ void Project::SerializeTo(SerializerElement& element) const {
else
std::cout << "ERROR: The project current platform is NULL.";
if (sceneResourcesPreloading != "at-startup") {
propElement.SetAttribute("sceneResourcesPreloading", sceneResourcesPreloading);
}
if (sceneResourcesUnloading != "never") {
propElement.SetAttribute("sceneResourcesUnloading", sceneResourcesUnloading);
}
resourcesManager.SerializeTo(element.AddChild("resources"));
objectsContainer.SerializeObjectsTo(element.AddChild("objects"));
objectsContainer.SerializeFoldersTo(element.AddChild("objectsFolderStructure"));
@@ -1316,9 +1307,6 @@ void Project::Init(const gd::Project& game) {
variables = game.GetVariables();
projectFile = game.GetProjectFile();
sceneResourcesPreloading = game.sceneResourcesPreloading;
sceneResourcesUnloading = game.sceneResourcesUnloading;
}
} // namespace gd

View File

@@ -964,37 +964,6 @@ class GD_CORE_API Project {
*/
ResourcesManager& GetResourcesManager() { return resourcesManager; }
/**
* Set when the scenes must preload their resources: `at-startup`, `never`
* (default).
*/
void SetSceneResourcesPreloading(gd::String sceneResourcesPreloading_) {
sceneResourcesPreloading = sceneResourcesPreloading_;
}
/**
* Get when the scenes must preload their resources: `at-startup`, `never`
* (default).
*/
const gd::String& GetSceneResourcesPreloading() const {
return sceneResourcesPreloading;
}
/**
* Set when the scenes must unload their resources: `at-scene-exit`, `never`
* (default).
*/
void SetSceneResourcesUnloading(gd::String sceneResourcesUnloading_) {
sceneResourcesUnloading = sceneResourcesUnloading_;
}
/**
* Get when the scenes must unload their resources: `at-scene-exit`, `never`
* (default).
*/
const gd::String& GetSceneResourcesUnloading() const {
return sceneResourcesUnloading;
}
///@}
/** \name Variable management
@@ -1152,10 +1121,6 @@ class GD_CORE_API Project {
ExtensionProperties
extensionProperties; ///< The properties of the extensions.
gd::WholeProjectDiagnosticReport wholeProjectDiagnosticReport;
gd::String sceneResourcesPreloading; ///< `at-startup` or `never`
///< (default: `at-startup`).
gd::String sceneResourcesUnloading; ///< `at-scene-exit` or `never`
///< (default: `never`).
mutable unsigned int gdMajorVersion =
0; ///< The GD major version used the last
///< time the project was saved.

View File

@@ -7,9 +7,9 @@
#define GDCORE_PROPERTYDESCRIPTOR
#include <vector>
#include "GDCore/String.h"
#include "GDCore/Project/MeasurementUnit.h"
#include "GDCore/Project/QuickCustomization.h"
#include "GDCore/String.h"
namespace gd {
class SerializerElement;
@@ -17,19 +17,6 @@ class SerializerElement;
namespace gd {
class GD_CORE_API PropertyDescriptorChoice {
public:
PropertyDescriptorChoice(const gd::String& value, const gd::String& label)
: value(value), label(label) {}
const gd::String& GetValue() const { return value; }
const gd::String& GetLabel() const { return label; }
private:
gd::String value;
gd::String label;
};
/**
* \brief Used to describe a property shown in a property grid.
* \see gd::Object
@@ -44,12 +31,8 @@ class GD_CORE_API PropertyDescriptor {
* \param propertyValue The value of the property.
*/
PropertyDescriptor(gd::String propertyValue)
: currentValue(propertyValue),
type("string"),
label(""),
hidden(false),
deprecated(false),
advanced(false),
: currentValue(propertyValue), type("string"), label(""), hidden(false),
deprecated(false), advanced(false),
hasImpactOnOtherProperties(false),
measurementUnit(gd::MeasurementUnit::GetUndefined()),
quickCustomizationVisibility(QuickCustomization::Visibility::Default) {}
@@ -58,13 +41,10 @@ class GD_CORE_API PropertyDescriptor {
* \brief Empty constructor creating an empty property to be displayed.
*/
PropertyDescriptor()
: hidden(false),
deprecated(false),
advanced(false),
: hidden(false), deprecated(false), advanced(false),
hasImpactOnOtherProperties(false),
measurementUnit(gd::MeasurementUnit::GetUndefined()),
quickCustomizationVisibility(QuickCustomization::Visibility::Default) {
};
quickCustomizationVisibility(QuickCustomization::Visibility::Default){};
/**
* \brief Destructor
@@ -108,20 +88,13 @@ class GD_CORE_API PropertyDescriptor {
}
/**
* \brief Change the group where this property is displayed to the user, if
* any.
* \brief Change the group where this property is displayed to the user, if any.
*/
PropertyDescriptor& SetGroup(gd::String group_) {
group = group_;
return *this;
}
PropertyDescriptor& AddChoice(const gd::String& value,
const gd::String& label) {
choices.push_back(PropertyDescriptorChoice(value, label));
return *this;
}
/**
* \brief Set and replace the additional information for the property.
*/
@@ -145,8 +118,7 @@ class GD_CORE_API PropertyDescriptor {
/**
* \brief Change the unit of measurement of the property value.
*/
PropertyDescriptor& SetMeasurementUnit(
const gd::MeasurementUnit& measurementUnit_) {
PropertyDescriptor& SetMeasurementUnit(const gd::MeasurementUnit &measurementUnit_) {
measurementUnit = measurementUnit_;
return *this;
}
@@ -156,18 +128,14 @@ class GD_CORE_API PropertyDescriptor {
const gd::String& GetLabel() const { return label; }
const gd::String& GetDescription() const { return description; }
const gd::String& GetGroup() const { return group; }
const gd::MeasurementUnit& GetMeasurementUnit() const {
return measurementUnit;
}
const gd::MeasurementUnit& GetMeasurementUnit() const { return measurementUnit; }
const std::vector<gd::String>& GetExtraInfo() const {
return extraInformation;
}
std::vector<gd::String>& GetExtraInfo() { return extraInformation; }
const std::vector<PropertyDescriptorChoice>& GetChoices() const {
return choices;
std::vector<gd::String>& GetExtraInfo() {
return extraInformation;
}
/**
@@ -210,26 +178,23 @@ class GD_CORE_API PropertyDescriptor {
bool IsAdvanced() const { return advanced; }
/**
* \brief Check if the property has impact on other properties - which means a
* change must re-render other properties.
* \brief Check if the property has impact on other properties - which means a change
* must re-render other properties.
*/
bool HasImpactOnOtherProperties() const { return hasImpactOnOtherProperties; }
/**
* \brief Set if the property has impact on other properties - which means a
* change must re-render other properties.
* \brief Set if the property has impact on other properties - which means a change
* must re-render other properties.
*/
PropertyDescriptor& SetHasImpactOnOtherProperties(bool enable) {
hasImpactOnOtherProperties = enable;
return *this;
}
QuickCustomization::Visibility GetQuickCustomizationVisibility() const {
return quickCustomizationVisibility;
}
QuickCustomization::Visibility GetQuickCustomizationVisibility() const { return quickCustomizationVisibility; }
PropertyDescriptor& SetQuickCustomizationVisibility(
QuickCustomization::Visibility visibility) {
PropertyDescriptor& SetQuickCustomizationVisibility(QuickCustomization::Visibility visibility) {
quickCustomizationVisibility = visibility;
return *this;
}
@@ -266,17 +231,15 @@ class GD_CORE_API PropertyDescriptor {
gd::String label; //< The user-friendly property name
gd::String description; //< The user-friendly property description
gd::String group; //< The user-friendly property group
std::vector<PropertyDescriptorChoice>
choices; //< The optional choices for the property.
std::vector<gd::String>
extraInformation; ///< Can be used to store an additional information
///< like an object type.
extraInformation; ///< Can be used to store for example the available
///< choices, if a property is a displayed as a combo
///< box.
bool hidden;
bool deprecated;
bool advanced;
bool hasImpactOnOtherProperties;
gd::MeasurementUnit
measurementUnit; //< The unit of measurement of the property vale.
gd::MeasurementUnit measurementUnit; //< The unit of measurement of the property vale.
QuickCustomization::Visibility quickCustomizationVisibility;
};

View File

@@ -5,6 +5,8 @@ namespace gdjs {
type Object3DNetworkSyncDataType = {
// z is position on the Z axis, different from zo, which is Z order
z: number;
w: number;
h: number;
d: number;
rx: number;
ry: number;
@@ -114,6 +116,8 @@ namespace gdjs {
return {
...super.getNetworkSyncData(),
z: this.getZ(),
w: this.getWidth(),
h: this.getHeight(),
d: this.getDepth(),
rx: this.getRotationX(),
ry: this.getRotationY(),
@@ -126,6 +130,8 @@ namespace gdjs {
updateFromNetworkSyncData(networkSyncData: Object3DNetworkSyncData) {
super.updateFromNetworkSyncData(networkSyncData);
if (networkSyncData.z !== undefined) this.setZ(networkSyncData.z);
if (networkSyncData.w !== undefined) this.setWidth(networkSyncData.w);
if (networkSyncData.h !== undefined) this.setHeight(networkSyncData.h);
if (networkSyncData.d !== undefined) this.setDepth(networkSyncData.d);
if (networkSyncData.rx !== undefined)
this.setRotationX(networkSyncData.rx);

View File

@@ -25,8 +25,6 @@ namespace gdjs {
topFaceVisible: boolean;
bottomFaceVisible: boolean;
tint: string | undefined;
isCastingShadow: boolean;
isReceivingShadow: boolean;
materialType: 'Basic' | 'StandardWithoutMetalness';
};
}
@@ -73,10 +71,8 @@ namespace gdjs {
string,
];
_materialType: gdjs.Cube3DRuntimeObject.MaterialType =
gdjs.Cube3DRuntimeObject.MaterialType.StandardWithoutMetalness;
gdjs.Cube3DRuntimeObject.MaterialType.Basic;
_tint: string;
_isCastingShadow: boolean = true;
_isReceivingShadow: boolean = true;
constructor(
instanceContainer: gdjs.RuntimeInstanceContainer,
@@ -125,8 +121,6 @@ namespace gdjs {
];
this._tint = objectData.content.tint || '255;255;255';
this._isCastingShadow = objectData.content.isCastingShadow || false;
this._isReceivingShadow = objectData.content.isReceivingShadow || false;
this._materialType = this._convertMaterialType(
objectData.content.materialType
@@ -436,18 +430,6 @@ namespace gdjs {
) {
this.setMaterialType(newObjectData.content.materialType);
}
if (
oldObjectData.content.isCastingShadow !==
newObjectData.content.isCastingShadow
) {
this.updateShadowCasting(newObjectData.content.isCastingShadow);
}
if (
oldObjectData.content.isReceivingShadow !==
newObjectData.content.isReceivingShadow
) {
this.updateShadowReceiving(newObjectData.content.isReceivingShadow);
}
return true;
}
@@ -549,14 +531,6 @@ namespace gdjs {
this._materialType = newMaterialType;
this._renderer._updateMaterials();
}
updateShadowCasting(value: boolean) {
this._isCastingShadow = value;
this._renderer.updateShadowCasting();
}
updateShadowReceiving(value: boolean) {
this._isReceivingShadow = value;
this._renderer.updateShadowReceiving();
}
}
export namespace Cube3DRuntimeObject {

View File

@@ -81,14 +81,13 @@ namespace gdjs {
.map((_, index) =>
getFaceMaterial(runtimeObject, materialIndexToFaceIndex[index])
);
const boxMesh = new THREE.Mesh(geometry, materials);
super(runtimeObject, instanceContainer, boxMesh);
this._boxMesh = boxMesh;
this._cube3DRuntimeObject = runtimeObject;
boxMesh.receiveShadow = this._cube3DRuntimeObject._isReceivingShadow;
boxMesh.castShadow = this._cube3DRuntimeObject._isCastingShadow;
this.updateSize();
this.updatePosition();
this.updateRotation();
@@ -115,13 +114,6 @@ namespace gdjs {
new THREE.BufferAttribute(new Float32Array(tints), 3)
);
}
updateShadowCasting() {
this._boxMesh.castShadow = this._cube3DRuntimeObject._isCastingShadow;
}
updateShadowReceiving() {
this._boxMesh.receiveShadow =
this._cube3DRuntimeObject._isReceivingShadow;
}
updateFace(faceIndex: integer) {
const materialIndex = faceIndexToMaterialIndex[faceIndex];

View File

@@ -1,12 +1,4 @@
namespace gdjs {
type CustomObject3DNetworkSyncDataType = CustomObjectNetworkSyncDataType & {
z: float;
d: float;
rx: float;
ry: float;
ifz: boolean;
};
/**
* Base class for 3D custom objects.
*/
@@ -42,6 +34,7 @@ namespace gdjs {
objectData: gdjs.Object3DData & gdjs.CustomObjectConfiguration
) {
super(parent, objectData);
this._renderer.reinitialize(this, parent);
}
protected override _createRender() {
@@ -85,30 +78,6 @@ namespace gdjs {
}
}
getNetworkSyncData(): CustomObject3DNetworkSyncDataType {
return {
...super.getNetworkSyncData(),
z: this.getZ(),
d: this.getDepth(),
rx: this.getRotationX(),
ry: this.getRotationY(),
ifz: this.isFlippedZ(),
};
}
updateFromNetworkSyncData(
networkSyncData: CustomObject3DNetworkSyncDataType
): void {
super.updateFromNetworkSyncData(networkSyncData);
if (networkSyncData.z !== undefined) this.setZ(networkSyncData.z);
if (networkSyncData.d !== undefined) this.setDepth(networkSyncData.d);
if (networkSyncData.rx !== undefined)
this.setRotationX(networkSyncData.rx);
if (networkSyncData.ry !== undefined)
this.setRotationY(networkSyncData.ry);
if (networkSyncData.ifz !== undefined) this.flipZ(networkSyncData.ifz);
}
/**
* Set the object position on the Z axis.
*/

View File

@@ -44,7 +44,10 @@ namespace gdjs {
) {
this._object = object;
this._isContainerDirty = true;
this._threeGroup.clear();
const layer = parent.getLayer('');
if (layer) {
layer.getRenderer().add3DRendererObject(this._threeGroup);
}
}
_updateThreeGroup() {

View File

@@ -6,7 +6,6 @@ namespace gdjs {
r: number;
t: string;
}
const shadowHelper = false;
gdjs.PixiFiltersTools.registerFilterCreator(
'Scene3D::DirectionalLight',
new (class implements gdjs.PixiFiltersTools.FilterCreator {
@@ -18,63 +17,19 @@ namespace gdjs {
return new gdjs.PixiFiltersTools.EmptyFilter();
}
return new (class implements gdjs.PixiFiltersTools.Filter {
private _top: string = 'Z+';
private _elevation: float = 45;
private _rotation: float = 0;
private _shadowMapSize: float = 1024;
private _minimumShadowBias: float = 0;
private _distanceFromCamera: float = 1500;
private _frustumSize: float = 4000;
private _isEnabled: boolean = false;
private _light: THREE.DirectionalLight;
private _shadowMapDirty = true;
private _shadowCameraDirty = true;
private _shadowCameraHelper: THREE.CameraHelper | null;
light: THREE.DirectionalLight;
rotationObject: THREE.Group;
_isEnabled: boolean = false;
top: string = 'Y-';
elevation: float = 45;
rotation: float = 0;
constructor() {
this._light = new THREE.DirectionalLight();
if (shadowHelper) {
this._shadowCameraHelper = new THREE.CameraHelper(
this._light.shadow.camera
);
} else {
this._shadowCameraHelper = null;
}
this._light.shadow.camera.updateProjectionMatrix();
}
private _updateShadowCamera(): void {
if (!this._shadowCameraDirty) {
return;
}
this._shadowCameraDirty = false;
this._light.shadow.camera.near = 1;
this._light.shadow.camera.far = this._distanceFromCamera + 10000;
this._light.shadow.camera.right = this._frustumSize / 2;
this._light.shadow.camera.left = -this._frustumSize / 2;
this._light.shadow.camera.top = this._frustumSize / 2;
this._light.shadow.camera.bottom = -this._frustumSize / 2;
}
private _updateShadowMapSize(): void {
if (!this._shadowMapDirty) {
return;
}
this._shadowMapDirty = false;
this._light.shadow.mapSize.set(
this._shadowMapSize,
this._shadowMapSize
);
// Force the recreation of the shadow map texture:
this._light.shadow.map?.dispose();
this._light.shadow.map = null;
this._light.shadow.needsUpdate = true;
this.light = new THREE.DirectionalLight();
this.light.position.set(1, 0, 0);
this.rotationObject = new THREE.Group();
this.rotationObject.add(this.light);
this.updateRotation();
}
isEnabled(target: EffectsTarget): boolean {
@@ -98,12 +53,7 @@ namespace gdjs {
if (!scene) {
return false;
}
scene.add(this._light);
scene.add(this._light.target);
if (this._shadowCameraHelper) {
scene.add(this._shadowCameraHelper);
}
scene.add(this.rotationObject);
this._isEnabled = true;
return true;
}
@@ -115,164 +65,82 @@ namespace gdjs {
if (!scene) {
return false;
}
scene.remove(this._light);
scene.remove(this._light.target);
if (this._shadowCameraHelper) {
scene.remove(this._shadowCameraHelper);
}
scene.remove(this.rotationObject);
this._isEnabled = false;
return true;
}
updatePreRender(target: gdjs.EffectsTarget): any {
// Apply any update to the camera or shadow map size.
this._updateShadowCamera();
this._updateShadowMapSize();
// Avoid shadow acne due to depth buffer precision.
const biasMultiplier =
this._shadowMapSize < 1024
? 2
: this._shadowMapSize < 2048
? 1.25
: 1;
this._light.shadow.bias = -this._minimumShadowBias * biasMultiplier;
// Apply update to the light position and its target.
// By doing this, the shadows are "following" the GDevelop camera.
if (!target.getRuntimeLayer) {
return;
}
const layer = target.getRuntimeLayer();
const x = layer.getCameraX();
const y = layer.getCameraY();
const z = layer.getCameraZ(layer.getInitialCamera3DFieldOfView());
const roundedX = Math.floor(x / 100) * 100;
const roundedY = Math.floor(y / 100) * 100;
const roundedZ = Math.floor(z / 100) * 100;
if (this._top === 'Y-') {
const posLightX =
roundedX +
this._distanceFromCamera *
Math.cos(gdjs.toRad(-this._rotation + 90)) *
Math.cos(gdjs.toRad(this._elevation));
const posLightY =
roundedY -
this._distanceFromCamera *
Math.sin(gdjs.toRad(this._elevation));
const posLightZ =
roundedZ +
this._distanceFromCamera *
Math.sin(gdjs.toRad(-this._rotation + 90)) *
Math.cos(gdjs.toRad(this._elevation));
this._light.position.set(posLightX, posLightY, posLightZ);
this._light.target.position.set(roundedX, roundedY, roundedZ);
} else {
const posLightX =
roundedX +
this._distanceFromCamera *
Math.cos(gdjs.toRad(this._rotation)) *
Math.cos(gdjs.toRad(this._elevation));
const posLightY =
roundedY +
this._distanceFromCamera *
Math.sin(gdjs.toRad(this._rotation)) *
Math.cos(gdjs.toRad(this._elevation));
const posLightZ =
roundedZ +
this._distanceFromCamera *
Math.sin(gdjs.toRad(this._elevation));
this._light.position.set(posLightX, posLightY, posLightZ);
this._light.target.position.set(roundedX, roundedY, roundedZ);
}
}
updatePreRender(target: gdjs.EffectsTarget): any {}
updateDoubleParameter(parameterName: string, value: number): void {
if (parameterName === 'intensity') {
this._light.intensity = value;
this.light.intensity = value;
} else if (parameterName === 'elevation') {
this._elevation = value;
this.elevation = value;
this.updateRotation();
} else if (parameterName === 'rotation') {
this._rotation = value;
} else if (parameterName === 'distanceFromCamera') {
this._distanceFromCamera = value;
} else if (parameterName === 'frustumSize') {
this._frustumSize = value;
} else if (parameterName === 'minimumShadowBias') {
this._minimumShadowBias = value;
this.rotation = value;
this.updateRotation();
}
}
getDoubleParameter(parameterName: string): number {
if (parameterName === 'intensity') {
return this._light.intensity;
return this.light.intensity;
} else if (parameterName === 'elevation') {
return this._elevation;
return this.elevation;
} else if (parameterName === 'rotation') {
return this._rotation;
} else if (parameterName === 'distanceFromCamera') {
return this._distanceFromCamera;
} else if (parameterName === 'frustumSize') {
return this._frustumSize;
} else if (parameterName === 'minimumShadowBias') {
return this._minimumShadowBias;
return this.rotation;
}
return 0;
}
updateStringParameter(parameterName: string, value: string): void {
if (parameterName === 'color') {
this._light.color = new THREE.Color(
this.light.color = new THREE.Color(
gdjs.rgbOrHexStringToNumber(value)
);
}
if (parameterName === 'top') {
this._top = value;
}
if (parameterName === 'shadowQuality') {
if (value === 'low' && this._shadowMapSize !== 512) {
this._shadowMapSize = 512;
this._shadowMapDirty = true;
}
if (value === 'medium' && this._shadowMapSize !== 1024) {
this._shadowMapSize = 1024;
this._shadowMapDirty = true;
}
if (value === 'high' && this._shadowMapSize !== 2048) {
this._shadowMapSize = 2048;
this._shadowMapDirty = true;
}
this.top = value;
this.updateRotation();
}
}
updateColorParameter(parameterName: string, value: number): void {
if (parameterName === 'color') {
this._light.color.setHex(value);
this.light.color.setHex(value);
}
}
getColorParameter(parameterName: string): number {
if (parameterName === 'color') {
return this._light.color.getHex();
return this.light.color.getHex();
}
return 0;
}
updateBooleanParameter(parameterName: string, value: boolean): void {
if (parameterName === 'isCastingShadow') {
this._light.castShadow = value;
updateBooleanParameter(parameterName: string, value: boolean): void {}
updateRotation() {
if (this.top === 'Z+') {
// 0° is a light from the right of the screen.
this.rotationObject.rotation.z = gdjs.toRad(this.rotation);
this.rotationObject.rotation.y = -gdjs.toRad(this.elevation);
} else {
// 0° becomes a light from Z+.
this.rotationObject.rotation.y = gdjs.toRad(this.rotation - 90);
this.rotationObject.rotation.z = -gdjs.toRad(this.elevation);
}
}
getNetworkSyncData(): DirectionalLightFilterNetworkSyncData {
return {
i: this._light.intensity,
c: this._light.color.getHex(),
e: this._elevation,
r: this._rotation,
t: this._top,
i: this.light.intensity,
c: this.light.color.getHex(),
e: this.elevation,
r: this.rotation,
t: this.top,
};
}
updateFromNetworkSyncData(syncData: any): void {
this._light.intensity = syncData.i;
this._light.color.setHex(syncData.c);
this._elevation = syncData.e;
this._rotation = syncData.r;
this._top = syncData.t;
this.light.intensity = syncData.i;
this.light.color.setHex(syncData.c);
this.elevation = syncData.e;
this.rotation = syncData.r;
this.top = syncData.t;
this.updateRotation();
}
})();
}

View File

@@ -18,15 +18,18 @@ namespace gdjs {
return new gdjs.PixiFiltersTools.EmptyFilter();
}
return new (class implements gdjs.PixiFiltersTools.Filter {
_top: string = 'Z+';
_elevation: float = 90;
_rotation: float = 0;
light: THREE.HemisphereLight;
rotationObject: THREE.Group;
_isEnabled: boolean = false;
_light: THREE.HemisphereLight;
top: string = 'Y-';
elevation: float = 45;
rotation: float = 0;
constructor() {
this._light = new THREE.HemisphereLight();
this.light = new THREE.HemisphereLight();
this.light.position.set(1, 0, 0);
this.rotationObject = new THREE.Group();
this.rotationObject.add(this.light);
this.updateRotation();
}
@@ -51,7 +54,7 @@ namespace gdjs {
if (!scene) {
return false;
}
scene.add(this._light);
scene.add(this.rotationObject);
this._isEnabled = true;
return true;
}
@@ -63,106 +66,96 @@ namespace gdjs {
if (!scene) {
return false;
}
scene.remove(this._light);
scene.remove(this.rotationObject);
this._isEnabled = false;
return true;
}
updatePreRender(target: gdjs.EffectsTarget): any {}
updateDoubleParameter(parameterName: string, value: number): void {
if (parameterName === 'intensity') {
this._light.intensity = value;
this.light.intensity = value;
} else if (parameterName === 'elevation') {
this._elevation = value;
this.elevation = value;
this.updateRotation();
} else if (parameterName === 'rotation') {
this._rotation = value;
this.rotation = value;
this.updateRotation();
}
}
getDoubleParameter(parameterName: string): number {
if (parameterName === 'intensity') {
return this._light.intensity;
return this.light.intensity;
} else if (parameterName === 'elevation') {
return this._elevation;
return this.elevation;
} else if (parameterName === 'rotation') {
return this._rotation;
return this.rotation;
}
return 0;
}
updateStringParameter(parameterName: string, value: string): void {
if (parameterName === 'skyColor') {
this._light.color = new THREE.Color(
this.light.color = new THREE.Color(
gdjs.rgbOrHexStringToNumber(value)
);
}
if (parameterName === 'groundColor') {
this._light.groundColor = new THREE.Color(
this.light.groundColor = new THREE.Color(
gdjs.rgbOrHexStringToNumber(value)
);
}
if (parameterName === 'top') {
this._top = value;
this.top = value;
this.updateRotation();
}
}
updateColorParameter(parameterName: string, value: number): void {
if (parameterName === 'skyColor') {
this._light.color.setHex(value);
this.light.color.setHex(value);
}
if (parameterName === 'groundColor') {
this._light.groundColor.setHex(value);
this.light.groundColor.setHex(value);
}
}
getColorParameter(parameterName: string): number {
if (parameterName === 'skyColor') {
return this._light.color.getHex();
return this.light.color.getHex();
}
if (parameterName === 'groundColor') {
return this._light.groundColor.getHex();
return this.light.groundColor.getHex();
}
return 0;
}
updateBooleanParameter(parameterName: string, value: boolean): void {}
updateRotation() {
if (this._top === 'Y-') {
// `rotation` at 0° becomes a light from Z+.
this._light.position.set(
Math.cos(gdjs.toRad(-this._rotation + 90)) *
Math.cos(gdjs.toRad(this._elevation)),
-Math.sin(gdjs.toRad(this._elevation)),
Math.sin(gdjs.toRad(-this._rotation + 90)) *
Math.cos(gdjs.toRad(this._elevation))
);
if (this.top === 'Z+') {
// 0° is a light from the right of the screen.
this.rotationObject.rotation.z = gdjs.toRad(this.rotation);
this.rotationObject.rotation.y = -gdjs.toRad(this.elevation);
} else {
// `rotation` at 0° is a light from the right of the screen.
this._light.position.set(
Math.cos(gdjs.toRad(this._rotation)) *
Math.cos(gdjs.toRad(this._elevation)),
Math.sin(gdjs.toRad(this._rotation)) *
Math.cos(gdjs.toRad(this._elevation)),
Math.sin(gdjs.toRad(this._elevation))
);
// 0° becomes a light from Z+.
this.rotationObject.rotation.y = gdjs.toRad(this.rotation - 90);
this.rotationObject.rotation.z = -gdjs.toRad(this.elevation);
}
}
getNetworkSyncData(): HemisphereLightFilterNetworkSyncData {
return {
i: this._light.intensity,
sc: this._light.color.getHex(),
gc: this._light.groundColor.getHex(),
e: this._elevation,
r: this._rotation,
t: this._top,
i: this.light.intensity,
sc: this.light.color.getHex(),
gc: this.light.groundColor.getHex(),
e: this.elevation,
r: this.rotation,
t: this.top,
};
}
updateFromNetworkSyncData(
syncData: HemisphereLightFilterNetworkSyncData
): void {
this._light.intensity = syncData.i;
this._light.color.setHex(syncData.sc);
this._light.groundColor.setHex(syncData.gc);
this._elevation = syncData.e;
this._rotation = syncData.r;
this._top = syncData.t;
this.light.intensity = syncData.i;
this.light.color.setHex(syncData.sc);
this.light.groundColor.setHex(syncData.gc);
this.elevation = syncData.e;
this.rotation = syncData.r;
this.top = syncData.t;
this.updateRotation();
}
})();

View File

@@ -859,9 +859,7 @@ module.exports = {
propertyName === 'rightFaceResourceRepeat' ||
propertyName === 'topFaceResourceRepeat' ||
propertyName === 'bottomFaceResourceRepeat' ||
propertyName === 'enableTextureTransparency' ||
propertyName === 'isCastingShadow' ||
propertyName === 'isReceivingShadow'
propertyName === 'enableTextureTransparency'
) {
objectContent[propertyName] = newValue === '1';
return true;
@@ -889,8 +887,8 @@ module.exports = {
.getOrCreate('facesOrientation')
.setValue(objectContent.facesOrientation || 'Y')
.setType('choice')
.addChoice('Y', 'Y')
.addChoice('Z', 'Z')
.addExtraInfo('Y')
.addExtraInfo('Z')
.setLabel(_('Faces orientation'))
.setDescription(
_(
@@ -950,8 +948,8 @@ module.exports = {
.getOrCreate('backFaceUpThroughWhichAxisRotation')
.setValue(objectContent.backFaceUpThroughWhichAxisRotation || 'X')
.setType('choice')
.addChoice('X', 'X')
.addChoice('Y', 'Y')
.addExtraInfo('X')
.addExtraInfo('Y')
.setLabel(_('Back face orientation'))
.setDescription(
_(
@@ -1085,29 +1083,11 @@ module.exports = {
objectProperties
.getOrCreate('materialType')
.setValue(objectContent.materialType || 'StandardWithoutMetalness')
.setValue(objectContent.materialType || 'Basic')
.setType('choice')
.addChoice('Basic', _('Basic (no lighting, no shadows)'))
.addChoice(
'StandardWithoutMetalness',
_('Standard (without metalness)')
)
.setLabel(_('Material type'))
.setGroup(_('Lighting'));
objectProperties
.getOrCreate('isCastingShadow')
.setValue(objectContent.isCastingShadow ? 'true' : 'false')
.setType('boolean')
.setLabel(_('Shadow casting'))
.setGroup(_('Lighting'));
objectProperties
.getOrCreate('isReceivingShadow')
.setValue(objectContent.isReceivingShadow ? 'true' : 'false')
.setType('boolean')
.setLabel(_('Shadow receiving'))
.setGroup(_('Lighting'));
.addExtraInfo('Basic')
.addExtraInfo('StandardWithoutMetalness')
.setLabel(_('Material type'));
return objectProperties;
};
@@ -1125,7 +1105,7 @@ module.exports = {
topFaceResourceName: '',
bottomFaceResourceName: '',
frontFaceVisible: true,
backFaceVisible: true,
backFaceVisible: false,
leftFaceVisible: true,
rightFaceVisible: true,
topFaceVisible: true,
@@ -1136,10 +1116,8 @@ module.exports = {
rightFaceResourceRepeat: false,
topFaceResourceRepeat: false,
bottomFaceResourceRepeat: false,
materialType: 'StandardWithoutMetalness',
materialType: 'Basic',
tint: '255;255;255',
isCastingShadow: true,
isReceivingShadow: true,
};
Cube3DObject.updateInitialInstanceProperty = function (
@@ -1916,11 +1894,11 @@ module.exports = {
.setType('number');
properties
.getOrCreate('top')
.setValue('Z+')
.setValue('Y-')
.setLabel(_('3D world top'))
.setType('choice')
.addExtraInfo('Z+')
.addExtraInfo('Y-')
.addExtraInfo('Z+')
.setGroup(_('Orientation'));
properties
.getOrCreate('elevation')
@@ -1935,47 +1913,6 @@ module.exports = {
.setLabel(_('Rotation (in degrees)'))
.setType('number')
.setGroup(_('Orientation'));
properties
.getOrCreate('isCastingShadow')
.setValue('false')
.setLabel(_('Shadow casting'))
.setType('boolean')
.setGroup(_('Shadows'));
properties
.getOrCreate('shadowQuality')
.setValue('medium')
.addChoice('low', _('Low quality'))
.addChoice('medium', _('Medium quality'))
.addChoice('high', _('High quality'))
.setLabel(_('Shadow quality'))
.setType('choice')
.setGroup(_('Shadows'));
properties
.getOrCreate('minimumShadowBias')
.setValue('0')
.setLabel(_('Shadow bias'))
.setDescription(
_(
'Use this to avoid "shadow acne" due to depth buffer precision. Choose a value small enough like 0.001 to avoid creating distance between shadows and objects but not too small to avoid shadow glitches on low/medium quality. This value is used for high quality, and multiplied by 1.25 for medium quality and 2 for low quality.'
)
)
.setType('number')
.setGroup(_('Shadows'))
.setAdvanced(true);
properties
.getOrCreate('frustumSize')
.setValue('4000')
.setLabel(_('Shadow frustum size'))
.setType('number')
.setGroup(_('Shadows'))
.setAdvanced(true);
properties
.getOrCreate('distanceFromCamera')
.setValue('1500')
.setLabel(_("Distance from layer's camera"))
.setType('number')
.setGroup(_('Shadows'))
.setAdvanced(true);
}
{
const effect = extension
@@ -2007,11 +1944,11 @@ module.exports = {
.setType('number');
properties
.getOrCreate('top')
.setValue('Z+')
.setValue('Y-')
.setLabel(_('3D world top'))
.setType('choice')
.addExtraInfo('Z+')
.addExtraInfo('Y-')
.addExtraInfo('Z+')
.setGroup(_('Orientation'));
properties
.getOrCreate('elevation')
@@ -3273,8 +3210,6 @@ module.exports = {
this._threeObject = new THREE.Group();
this._threeObject.rotation.order = 'ZYX';
this._threeObject.castShadow = true;
this._threeObject.receiveShadow = true;
this._threeGroup.add(this._threeObject);
}

View File

@@ -23,7 +23,7 @@ Model3DObjectConfiguration::Model3DObjectConfiguration()
: width(100), height(100), depth(100), rotationX(0), rotationY(0),
rotationZ(0), modelResourceName(""), materialType("StandardWithoutMetalness"),
originLocation("ModelOrigin"), centerLocation("ModelOrigin"),
keepAspectRatio(true), crossfadeDuration(0.1f), isCastingShadow(true), isReceivingShadow(true) {}
keepAspectRatio(true), crossfadeDuration(0.1f) {}
bool Model3DObjectConfiguration::UpdateProperty(const gd::String &propertyName,
const gd::String &newValue) {
@@ -75,16 +75,6 @@ bool Model3DObjectConfiguration::UpdateProperty(const gd::String &propertyName,
crossfadeDuration = newValue.To<double>();
return true;
}
if(propertyName == "isCastingShadow")
{
isCastingShadow = newValue == "1";
return true;
}
if(propertyName == "isReceivingShadow")
{
isReceivingShadow = newValue == "1";
return true;
}
return false;
}
@@ -153,20 +143,19 @@ Model3DObjectConfiguration::GetProperties() const {
objectProperties["materialType"]
.SetValue(materialType.empty() ? "Basic" : materialType)
.SetType("choice")
.AddChoice("Basic", _("Basic (no lighting, no shadows)"))
.AddChoice("StandardWithoutMetalness", _("Standard (without metalness)"))
.AddChoice("KeepOriginal", _("Keep original"))
.SetLabel(_("Material"))
.SetGroup(_("Lighting"));
.AddExtraInfo("Basic")
.AddExtraInfo("StandardWithoutMetalness")
.AddExtraInfo("KeepOriginal")
.SetLabel(_("Material"));
objectProperties["originLocation"]
.SetValue(originLocation.empty() ? "TopLeft" : originLocation)
.SetType("choice")
.AddChoice("ModelOrigin", _("Model origin"))
.AddChoice("TopLeft", _("Top left"))
.AddChoice("ObjectCenter", _("Object center"))
.AddChoice("BottomCenterZ", _("Bottom center (Z)"))
.AddChoice("BottomCenterY", _("Bottom center (Y)"))
.AddExtraInfo("ModelOrigin")
.AddExtraInfo("TopLeft")
.AddExtraInfo("ObjectCenter")
.AddExtraInfo("BottomCenterZ")
.AddExtraInfo("BottomCenterY")
.SetLabel(_("Origin point"))
.SetGroup(_("Points"))
.SetAdvanced(true);
@@ -174,10 +163,10 @@ Model3DObjectConfiguration::GetProperties() const {
objectProperties["centerLocation"]
.SetValue(centerLocation.empty() ? "ObjectCenter" : centerLocation)
.SetType("choice")
.AddChoice("ModelOrigin", _("Model origin"))
.AddChoice("ObjectCenter", _("Object center"))
.AddChoice("BottomCenterZ", _("Bottom center (Z)"))
.AddChoice("BottomCenterY", _("Bottom center (Y)"))
.AddExtraInfo("ModelOrigin")
.AddExtraInfo("ObjectCenter")
.AddExtraInfo("BottomCenterZ")
.AddExtraInfo("BottomCenterY")
.SetLabel(_("Center point"))
.SetGroup(_("Points"))
.SetAdvanced(true);
@@ -189,20 +178,6 @@ Model3DObjectConfiguration::GetProperties() const {
.SetGroup(_("Animations"))
.SetMeasurementUnit(gd::MeasurementUnit::GetSecond());
objectProperties["isCastingShadow"]
.SetValue(isCastingShadow ? "true" : "false")
.SetType("boolean")
.SetLabel(_("Shadow casting"))
.SetGroup(_("Lighting"));
objectProperties["isReceivingShadow"]
.SetValue(isReceivingShadow ? "true" : "false")
.SetType("boolean")
.SetLabel(_("Shadow receiving"))
.SetGroup(_("Lighting"));
return objectProperties;
}
@@ -235,8 +210,6 @@ void Model3DObjectConfiguration::DoUnserializeFrom(
centerLocation = content.GetStringAttribute("centerLocation");
keepAspectRatio = content.GetBoolAttribute("keepAspectRatio");
crossfadeDuration = content.GetDoubleAttribute("crossfadeDuration");
isCastingShadow = content.GetBoolAttribute("isCastingShadow");
isReceivingShadow = content.GetBoolAttribute("isReceivingShadow");
RemoveAllAnimations();
auto &animationsElement = content.GetChild("animations");
@@ -266,8 +239,6 @@ void Model3DObjectConfiguration::DoSerializeTo(
content.SetAttribute("centerLocation", centerLocation);
content.SetAttribute("keepAspectRatio", keepAspectRatio);
content.SetAttribute("crossfadeDuration", crossfadeDuration);
content.SetAttribute("isCastingShadow", isCastingShadow);
content.SetAttribute("isReceivingShadow", isReceivingShadow);
auto &animationsElement = content.AddChild("animations");
animationsElement.ConsiderAsArrayOf("animation");

View File

@@ -160,8 +160,6 @@ public:
const gd::String& GetCenterLocation() const { return centerLocation; };
bool shouldKeepAspectRatio() const { return keepAspectRatio; };
bool shouldCastShadow() const { return isCastingShadow; };
bool shouldReceiveShadow() const { return isReceivingShadow; };
///@}
protected:
@@ -184,8 +182,6 @@ private:
gd::String centerLocation;
bool keepAspectRatio;
bool isCastingShadow;
bool isReceivingShadow;
std::vector<Model3DAnimation> animations;
static Model3DAnimation badAnimation; //< Bad animation when an out of bound

View File

@@ -38,8 +38,6 @@ namespace gdjs {
| 'BottomCenterY';
animations: Model3DAnimation[];
crossfadeDuration: float;
isCastingShadow: boolean;
isReceivingShadow: boolean;
};
}
@@ -103,8 +101,6 @@ namespace gdjs {
_animationSpeedScale: float = 1;
_animationPaused: boolean = false;
_crossfadeDuration: float = 0;
_isCastingShadow: boolean = true;
_isReceivingShadow: boolean = true;
constructor(
instanceContainer: gdjs.RuntimeInstanceContainer,
@@ -127,8 +123,6 @@ namespace gdjs {
objectData.content.materialType
);
this.setIsCastingShadow(objectData.content.isCastingShadow);
this.setIsReceivingShadow(objectData.content.isReceivingShadow);
this.onModelChanged(objectData);
this._crossfadeDuration = objectData.content.crossfadeDuration || 0;
@@ -201,18 +195,6 @@ namespace gdjs {
newObjectData.content.centerLocation
);
}
if (
oldObjectData.content.isCastingShadow !==
newObjectData.content.isCastingShadow
) {
this.setIsCastingShadow(newObjectData.content.isCastingShadow);
}
if (
oldObjectData.content.isReceivingShadow !==
newObjectData.content.isReceivingShadow
) {
this.setIsReceivingShadow(newObjectData.content.isReceivingShadow);
}
return true;
}
@@ -376,16 +358,6 @@ namespace gdjs {
return this._renderer.hasAnimationEnded();
}
setIsCastingShadow(value: boolean): void {
this._isCastingShadow = value;
this._renderer._updateShadow();
}
setIsReceivingShadow(value: boolean): void {
this._isReceivingShadow = value;
this._renderer._updateShadow();
}
setCrossfadeDuration(duration: number): void {
if (this._crossfadeDuration === duration) return;
this._crossfadeDuration = duration;

View File

@@ -286,7 +286,6 @@ namespace gdjs {
this.get3DRendererObject().remove(this._threeObject);
this.get3DRendererObject().add(threeObject);
this._threeObject = threeObject;
this._updateShadow();
// Start the current animation on the new 3D object.
this._animationMixer = new THREE.AnimationMixer(root);
@@ -324,13 +323,6 @@ namespace gdjs {
return this._originalModel.animations[animationIndex].name;
}
_updateShadow() {
this._threeObject.traverse((child) => {
child.castShadow = this._model3DRuntimeObject._isCastingShadow;
child.receiveShadow = this._model3DRuntimeObject._isReceivingShadow;
});
}
/**
* Return true if animation has ended.
* The animation had ended if:

View File

@@ -14,7 +14,6 @@ describe('gdjs.AnchorRuntimeBehavior', () => {
effects: [],
content: {},
childrenContent: {},
isInnerAreaFollowingParentSize: false,
});
runtimeScene.addObject(customObject);
customObject.setPosition(500, 250);

View File

@@ -75,9 +75,9 @@ module.exports = {
.getOrCreate('align')
.setValue(objectContent.align)
.setType('choice')
.addChoice('left', _('Left'))
.addChoice('center', _('Center'))
.addChoice('right', _('Right'))
.addExtraInfo('left')
.addExtraInfo('center')
.addExtraInfo('right')
.setLabel(_('Base alignment'))
.setGroup(_('Appearance'));
@@ -88,9 +88,9 @@ module.exports = {
.getOrCreate('verticalTextAlignment')
.setValue(objectContent.verticalTextAlignment)
.setType('choice')
.addChoice('top', _('Top'))
.addChoice('center', _('Center'))
.addChoice('bottom', _('Bottom'))
.addExtraInfo('top')
.addExtraInfo('center')
.addExtraInfo('bottom')
.setLabel(_('Vertical alignment'))
.setGroup(_('Appearance'));
@@ -508,7 +508,7 @@ module.exports = {
associatedObjectConfiguration,
pixiContainer,
pixiResourcesLoader,
getPropertyOverridings
propertyOverridings
) {
super(
project,
@@ -516,7 +516,7 @@ module.exports = {
associatedObjectConfiguration,
pixiContainer,
pixiResourcesLoader,
getPropertyOverridings
propertyOverridings
);
const bbTextStyles = {
@@ -555,11 +555,9 @@ module.exports = {
gd.ObjectJsImplementation
);
const propertyOverridings = this.getPropertyOverridings();
const rawText =
propertyOverridings && propertyOverridings.has('Text')
? propertyOverridings.get('Text')
: object.content.text;
const rawText = this._propertyOverridings.has('Text')
? this._propertyOverridings.get('Text')
: object.content.text;
if (rawText !== this._pixiObject.text) {
this._pixiObject.text = rawText;
}

View File

@@ -61,9 +61,9 @@ module.exports = {
.getOrCreate('align')
.setValue(objectContent.align)
.setType('choice')
.addChoice('left', _('Left'))
.addChoice('center', _('Center'))
.addChoice('right', _('Right'))
.addExtraInfo('left')
.addExtraInfo('center')
.addExtraInfo('right')
.setLabel(_('Alignment'))
.setGroup(_('Appearance'));
@@ -74,9 +74,9 @@ module.exports = {
.getOrCreate('verticalTextAlignment')
.setValue(objectContent.verticalTextAlignment)
.setType('choice')
.addChoice('top', _('Top'))
.addChoice('center', _('Center'))
.addChoice('bottom', _('Bottom'))
.addExtraInfo('top')
.addExtraInfo('center')
.addExtraInfo('bottom')
.setLabel(_('Vertical alignment'))
.setGroup(_('Appearance'));
@@ -631,7 +631,7 @@ module.exports = {
associatedObjectConfiguration,
pixiContainer,
pixiResourcesLoader,
getPropertyOverridings
propertyOverridings
) {
super(
project,
@@ -639,7 +639,7 @@ module.exports = {
associatedObjectConfiguration,
pixiContainer,
pixiResourcesLoader,
getPropertyOverridings
propertyOverridings
);
// We'll track changes of the font to trigger the loading of the new font.
@@ -665,11 +665,9 @@ module.exports = {
// Update the rendered text properties (note: Pixi is only
// applying changes if there were changed).
const propertyOverridings = this.getPropertyOverridings();
this._pixiObject.text =
propertyOverridings && propertyOverridings.has('Text')
? propertyOverridings.get('Text')
: object.content.text;
this._pixiObject.text = this._propertyOverridings.has('Text')
? this._propertyOverridings.get('Text')
: object.content.text;
const align = object.content.align;
this._pixiObject.align = align;

View File

@@ -12,7 +12,7 @@ This project is released under the MIT License.
#include "GDCore/Tools/Localization.h"
void DestroyOutsideBehavior::InitializeContent(gd::SerializerElement& content) {
content.SetAttribute("extraBorder", 300);
content.SetAttribute("extraBorder", 0);
}
#if defined(GD_IDE_ONLY)

View File

@@ -35,32 +35,25 @@ void DeclareDraggableBehaviorExtension(gd::PlatformExtension& extension) {
std::make_shared<DraggableBehavior>(),
std::shared_ptr<gd::BehaviorsSharedData>());
aut.AddCondition(
"Dragged",
_("Being dragged"),
_("Check if the object is being dragged. This means the mouse button "
"or touch is pressed on it. When the mouse button or touch is "
"released, the object is no longer being considered dragged (use "
"the condition \"Was just dropped\" to check when the dragging is "
"ending)."),
_("_PARAM0_ is being dragged"),
_("Draggable"),
"CppPlatform/Extensions/draggableicon24.png",
"CppPlatform/Extensions/draggableicon16.png")
aut.AddCondition("Dragged",
_("Being dragged"),
_("Check if the object is being dragged."),
_("_PARAM0_ is being dragged"),
_("Draggable"),
"CppPlatform/Extensions/draggableicon24.png",
"CppPlatform/Extensions/draggableicon16.png")
.AddParameter("object", _("Object"))
.AddParameter("behavior", _("Behavior"), "Draggable")
.SetFunctionName("IsDragged");
aut.AddCondition(
"Dropped",
_("Was just dropped"),
_("Check if the object was just dropped after being dragged (the "
"mouse button or touch was just released this frame)."),
_("_PARAM0_ was just dropped"),
_("Draggable"),
"CppPlatform/Extensions/draggableicon24.png",
"CppPlatform/Extensions/draggableicon16.png")
aut.AddCondition("Dropped",
_("Was just dropped"),
_("Check if the object was just dropped after being dragged."),
_("_PARAM0_ was just dropped"),
_("Draggable"),
"CppPlatform/Extensions/draggableicon24.png",
"CppPlatform/Extensions/draggableicon16.png")
.AddParameter("object", _("Object"))
.AddParameter("behavior", _("Behavior"), "Draggable")

View File

@@ -27,7 +27,7 @@ class RenderedInstance {
associatedObjectConfiguration: gdObjectConfiguration,
pixiContainer: PIXI.Container,
pixiResourcesLoader: Class<PixiResourcesLoader>,
getPropertyOverridings: (() => Map<string, string>) | null = null
propertyOverridings: Map<string, string> = new Map<string, string>()
);
/**
@@ -80,8 +80,6 @@ class RenderedInstance {
getDefaultHeight(): number;
getDefaultDepth(): number;
getPropertyOverridings(): Map<string, string> | null;
}
/**
@@ -109,8 +107,7 @@ class Rendered3DInstance {
associatedObjectConfiguration: gdObjectConfiguration,
pixiContainer: PIXI.Container,
threeGroup: THREE.Group,
pixiResourcesLoader: Class<PixiResourcesLoader>,
getPropertyOverridings: (() => Map<string, string>) | null = null
pixiResourcesLoader: Class<PixiResourcesLoader>
);
/**
@@ -177,8 +174,6 @@ class Rendered3DInstance {
* Return the depth of the instance when the instance doesn't have a custom size.
*/
getDefaultDepth(): number;
getPropertyOverridings(): Map<string, string> | null;
}
declare type ObjectsRenderingService = {

View File

@@ -30,12 +30,6 @@ module.exports = {
.addInstructionOrExpressionGroupMetadata(_('Leaderboards'))
.setIcon('JsPlatform/Extensions/leaderboard.svg');
extension
.addDependency()
.setName('Safari View Controller Cordova plugin')
.setDependencyType('cordova')
.setExportName('@gdevelop/cordova-plugin-safariviewcontroller');
extension
.addAction(
'SavePlayerScore',

View File

@@ -31,79 +31,6 @@ module.exports = {
.addInstructionOrExpressionGroupMetadata(_('Multiplayer'))
.setIcon('JsPlatform/Extensions/multiplayer.svg');
extension
.addDependency()
.setName('Safari View Controller Cordova plugin')
.setDependencyType('cordova')
.setExportName('@gdevelop/cordova-plugin-safariviewcontroller');
extension
.addStrExpression(
'CurrentLobbyID',
_('Current lobby ID'),
_('Returns current lobby ID.'),
_('Lobbies'),
'JsPlatform/Extensions/multiplayer.svg'
)
.getCodeExtraInformation()
.setIncludeFile('Extensions/Multiplayer/peer.js')
.addIncludeFile('Extensions/Multiplayer/peerJsHelper.js')
.addIncludeFile(
'Extensions/PlayerAuthentication/playerauthenticationcomponents.js'
)
.addIncludeFile(
'Extensions/PlayerAuthentication/playerauthenticationtools.js'
)
.addIncludeFile('Extensions/Multiplayer/multiplayercomponents.js')
.addIncludeFile('Extensions/Multiplayer/messageManager.js')
.addIncludeFile('Extensions/Multiplayer/multiplayerVariablesManager.js')
.addIncludeFile('Extensions/Multiplayer/multiplayertools.js')
.setFunctionName('gdjs.multiplayer.getLobbyID');
extension
.addAction(
'QuickJoinWithLobbyID',
_('Join a specific lobby by its ID'),
_(
'Join a specific lobby. The player will join the game instantly if this is possible.'
),
_('Join a specific lobby by its ID _PARAM1_'),
_('Lobbies'),
'JsPlatform/Extensions/multiplayer.svg',
'JsPlatform/Extensions/multiplayer.svg'
)
.addCodeOnlyParameter('currentScene', '')
.addParameter('string', _('Lobby ID'), '', false)
.addParameter(
'yesorno',
_('Display loader while joining a lobby.'),
'',
true
)
.setDefaultValue('yes')
.addParameter(
'yesorno',
_('Display game lobbies if unable to join a specific one.'),
'',
true
)
.setDefaultValue('yes')
.setHelpPath('/all-features/multiplayer')
.getCodeExtraInformation()
.setIncludeFile('Extensions/Multiplayer/peer.js')
.addIncludeFile('Extensions/Multiplayer/peerJsHelper.js')
.addIncludeFile(
'Extensions/PlayerAuthentication/playerauthenticationcomponents.js'
)
.addIncludeFile(
'Extensions/PlayerAuthentication/playerauthenticationtools.js'
)
.addIncludeFile('Extensions/Multiplayer/multiplayercomponents.js')
.addIncludeFile('Extensions/Multiplayer/messageManager.js')
.addIncludeFile('Extensions/Multiplayer/multiplayerVariablesManager.js')
.addIncludeFile('Extensions/Multiplayer/multiplayertools.js')
.setFunctionName('gdjs.multiplayer.authenticateAndQuickJoinWithLobbyID');
extension
.addAction(
'QuickJoinLobby',

View File

@@ -293,8 +293,6 @@ namespace gdjs {
x: objectNetworkSyncData.x,
y: objectNetworkSyncData.y,
z: objectNetworkSyncData.z,
w: objectNetworkSyncData.w,
h: objectNetworkSyncData.h,
zo: objectNetworkSyncData.zo,
a: objectNetworkSyncData.a,
hid: objectNetworkSyncData.hid,
@@ -371,9 +369,6 @@ namespace gdjs {
this._lastSentBasicObjectSyncData = {
x: objectNetworkSyncData.x,
y: objectNetworkSyncData.y,
z: objectNetworkSyncData.z,
w: objectNetworkSyncData.w,
h: objectNetworkSyncData.h,
zo: objectNetworkSyncData.zo,
a: objectNetworkSyncData.a,
hid: objectNetworkSyncData.hid,

View File

@@ -17,29 +17,9 @@ namespace gdjs {
}[];
};
type LobbyStatus =
| 'waiting'
| 'starting'
| 'playing'
| 'migrating'
| 'migrated';
type LobbyConnectionStatus = 'waiting' | 'ready' | 'connected';
type InGamePlayerStatus = 'playing' | 'left';
type PlayerStatus = LobbyConnectionStatus | InGamePlayerStatus;
type LobbyPlayer = {
playerId: string;
status: PlayerStatus;
playerNumber: number;
};
type Lobby = {
id: string;
minPlayers: number;
maxPlayers: number;
canJoinAfterStart: boolean;
players: LobbyPlayer[];
status: LobbyStatus;
status: 'waiting' | 'starting' | 'playing' | 'migrating' | 'migrated';
};
type QuickJoinLobbyResponse =
@@ -125,7 +105,6 @@ namespace gdjs {
let _quickJoinLobbyFailureReason:
| 'FULL'
| 'NOT_ENOUGH_PLAYERS'
| 'DOES_NOT_EXIST'
| 'UNKNOWN'
| null = null;
let _lobbyId: string | null = null;
@@ -1718,87 +1697,11 @@ namespace gdjs {
}
};
export const getLobbyID = (): string => {
return _lobbyId || '';
};
const quickJoinWithLobbyID = async (
export const authenticateAndQuickJoinLobby = async (
runtimeScene: gdjs.RuntimeScene,
lobbyID: string,
displayLoader: boolean,
openLobbiesPageIfFailure: boolean
) => {
if (_isQuickJoiningOrStartingAGame) return;
const _gameId = gdjs.projectData.properties.projectUuid;
if (!_gameId) {
logger.error(
'The game ID is missing, the quick join lobby action cannot continue.'
);
return;
}
_quickJoinLobbyFailureReason = null;
_isQuickJoiningOrStartingAGame = true;
if (displayLoader) {
gdjs.multiplayerComponents.displayLoader(runtimeScene, true);
}
const quickJoinWithLobbyIDRelativeUrl = `/play/game/${_gameId}/public-lobby/${lobbyID}`;
try {
const lobby: Lobby = await gdjs.evtTools.network.retryIfFailed(
{ times: 2 },
() =>
fetchAsPlayer({
relativeUrl: quickJoinWithLobbyIDRelativeUrl,
method: 'GET',
dev: isUsingGDevelopDevelopmentEnvironment,
})
);
const isFull = lobby.players.length === lobby.maxPlayers;
if (isFull) {
logger.error('Lobby is full - cannot quick join it.');
_quickJoinLobbyJustFailed = true;
_quickJoinLobbyFailureReason = 'FULL';
onLobbyQuickJoinFinished(runtimeScene);
if (openLobbiesPageIfFailure) {
openLobbiesWindow(runtimeScene);
}
return;
}
if (lobby.status === 'playing') {
_actionAfterJoiningLobby = 'JOIN_GAME';
} else if (lobby.status === 'waiting') {
if (lobby.players.length === 0) {
_actionAfterJoiningLobby = 'START_GAME';
} else {
_actionAfterJoiningLobby = 'OPEN_LOBBY_PAGE';
}
} else {
throw new Error(`Lobby in wrong status: ${lobby.status}`);
}
handleJoinLobbyEvent(runtimeScene, lobbyID);
} catch (error) {
const errorCode = parseInt(error.message.match(/\d{3}/)?.[0]);
if (errorCode === 404) {
logger.error('Lobby does not exist.');
_quickJoinLobbyFailureReason = 'DOES_NOT_EXIST';
} else {
logger.error('An error occurred while joining a lobby:', error);
_quickJoinLobbyFailureReason = 'UNKNOWN';
}
_quickJoinLobbyJustFailed = true;
onLobbyQuickJoinFinished(runtimeScene);
if (openLobbiesPageIfFailure) {
openLobbiesWindow(runtimeScene);
}
}
};
const isQuickJoiningTooFast = () => {
const requestDoneAt = Date.now();
if (_lastQuickJoinRequestDoneAt) {
if (requestDoneAt - _lastQuickJoinRequestDoneAt < 500) {
@@ -1806,18 +1709,12 @@ namespace gdjs {
logger.warn(
'Last request to quick join a lobby was sent too little time ago. Ignoring this one.'
);
return true;
return;
}
} else {
_lastQuickJoinRequestDoneAt = requestDoneAt;
}
return false;
};
const isNotCorrectlyAuthenticatedForQuickJoin = async (
runtimeScene: RuntimeScene
) => {
const playerId = gdjs.playerAuthentication.getUserId();
const playerToken = gdjs.playerAuthentication.getUserToken();
if (!playerId || !playerToken) {
@@ -1827,43 +1724,14 @@ namespace gdjs {
.promise;
_isWaitingForLogin = false;
if (status !== 'logged') {
return true;
if (status === 'logged') {
await quickJoinLobby(
runtimeScene,
displayLoader,
openLobbiesPageIfFailure
);
}
}
return false;
};
export const authenticateAndQuickJoinWithLobbyID = async (
runtimeScene: gdjs.RuntimeScene,
lobbyID: string,
displayLoader: boolean,
openLobbiesPageIfFailure: boolean
) => {
if (isQuickJoiningTooFast()) {
return;
}
if (await isNotCorrectlyAuthenticatedForQuickJoin(runtimeScene)) {
return;
}
await quickJoinWithLobbyID(
runtimeScene,
lobbyID,
displayLoader,
openLobbiesPageIfFailure
);
};
export const authenticateAndQuickJoinLobby = async (
runtimeScene: gdjs.RuntimeScene,
displayLoader: boolean,
openLobbiesPageIfFailure: boolean
) => {
if (isQuickJoiningTooFast()) {
return;
}
if (await isNotCorrectlyAuthenticatedForQuickJoin(runtimeScene)) {
return;
}
await quickJoinLobby(

View File

@@ -25,6 +25,8 @@ namespace gdjs {
export type PanelSpriteObjectData = ObjectData & PanelSpriteObjectDataType;
export type PanelSpriteNetworkSyncDataType = {
wid: number;
hei: number;
op: number;
color: string;
};
@@ -122,6 +124,8 @@ namespace gdjs {
getNetworkSyncData(): PanelSpriteNetworkSyncData {
return {
...super.getNetworkSyncData(),
wid: this.getWidth(),
hei: this.getHeight(),
op: this.getOpacity(),
color: this.getColor(),
};
@@ -134,6 +138,12 @@ namespace gdjs {
// Texture is not synchronized, see if this is asked or not.
if (networkSyncData.wid !== undefined) {
this.setWidth(networkSyncData.wid);
}
if (networkSyncData.hei !== undefined) {
this.setHeight(networkSyncData.hei);
}
if (networkSyncData.op !== undefined) {
this.setOpacity(networkSyncData.op);
}

View File

@@ -194,9 +194,9 @@ ParticleEmitterObject::GetProperties() const {
: GetRendererType() == Line ? "Line"
: "Image")
.SetType("choice")
.AddChoice("Circle", _("Circle"))
.AddChoice("Line", _("Line"))
.AddChoice("Image", _("Image"))
.AddExtraInfo("Circle")
.AddExtraInfo("Line")
.AddExtraInfo("Image")
.SetLabel(_("Particle type"))
.SetHasImpactOnOtherProperties(true);

View File

@@ -818,7 +818,7 @@ module.exports = {
)
.addParameter('object', _('Object'), '', false)
.addParameter('behavior', _('Behavior'), 'Physics2Behavior')
.addParameter('yesorno', _('Treat as bullet'), '', false)
.addParameter('yesorno', _('Treat as bullet?'), '', false)
.setDefaultValue('false')
.getCodeExtraInformation()
.setFunctionName('setBullet');
@@ -852,7 +852,7 @@ module.exports = {
)
.addParameter('object', _('Object'), '', false)
.addParameter('behavior', _('Behavior'), 'Physics2Behavior')
.addParameter('yesorno', _('Fixed rotation'), '', false)
.addParameter('yesorno', _('Fixed rotation?'), '', false)
.setDefaultValue('false')
.getCodeExtraInformation()
.setFunctionName('setFixedRotation');
@@ -886,7 +886,7 @@ module.exports = {
)
.addParameter('object', _('Object'), '', false)
.addParameter('behavior', _('Behavior'), 'Physics2Behavior')
.addParameter('yesorno', _('Can sleep'), '', false)
.addParameter('yesorno', _('Can sleep?'), '', false)
.setDefaultValue('true')
.getCodeExtraInformation()
.setFunctionName('setSleepingAllowed');
@@ -1296,7 +1296,7 @@ module.exports = {
.addParameter('object', _('Object'), '', false)
.addParameter('behavior', _('Behavior'), 'Physics2Behavior')
.addParameter('expression', _('Layer (1 - 16)'))
.addParameter('yesorno', _('Enable'), '', false)
.addParameter('yesorno', _('Enable?'), '', false)
.setDefaultValue('true')
.getCodeExtraInformation()
.setFunctionName('enableLayer');
@@ -1332,7 +1332,7 @@ module.exports = {
.addParameter('object', _('Object'), '', false)
.addParameter('behavior', _('Behavior'), 'Physics2Behavior')
.addParameter('expression', _('Mask (1 - 16)'))
.addParameter('yesorno', _('Enable'), '', false)
.addParameter('yesorno', _('Enable?'), '', false)
.setDefaultValue('true')
.getCodeExtraInformation()
.setFunctionName('enableMask');
@@ -2409,7 +2409,7 @@ module.exports = {
.addParameter('object', _('Object'), '', false)
.addParameter('behavior', _('Behavior'), 'Physics2Behavior')
.addParameter('expression', _('Joint ID'))
.addParameter('yesorno', _('Enable'))
.addParameter('yesorno', _('Enable?'))
.getCodeExtraInformation()
.setFunctionName('enableRevoluteJointLimits');
@@ -2488,7 +2488,7 @@ module.exports = {
.addParameter('object', _('Object'), '', false)
.addParameter('behavior', _('Behavior'), 'Physics2Behavior')
.addParameter('expression', _('Joint ID'))
.addParameter('yesorno', _('Enable'))
.addParameter('yesorno', _('Enable?'))
.getCodeExtraInformation()
.setFunctionName('enableRevoluteJointMotor');
@@ -2727,7 +2727,7 @@ module.exports = {
.addParameter('object', _('Object'), '', false)
.addParameter('behavior', _('Behavior'), 'Physics2Behavior')
.addParameter('expression', _('Joint ID'))
.addParameter('yesorno', _('Enable'))
.addParameter('yesorno', _('Enable?'))
.getCodeExtraInformation()
.setFunctionName('enablePrismaticJointLimits');
@@ -2806,7 +2806,7 @@ module.exports = {
.addParameter('object', _('Object'), '', false)
.addParameter('behavior', _('Behavior'), 'Physics2Behavior')
.addParameter('expression', _('Joint ID'))
.addParameter('yesorno', _('Enable'))
.addParameter('yesorno', _('Enable?'))
.getCodeExtraInformation()
.setFunctionName('enablePrismaticJointMotor');
@@ -3486,7 +3486,7 @@ module.exports = {
.addParameter('object', _('Object'), '', false)
.addParameter('behavior', _('Behavior'), 'Physics2Behavior')
.addParameter('expression', _('Joint ID'))
.addParameter('yesorno', _('Enable'))
.addParameter('yesorno', _('Enable?'))
.getCodeExtraInformation()
.setFunctionName('enableWheelJointMotor');

View File

@@ -274,7 +274,7 @@ module.exports = {
.setLabel('Fixed Rotation')
.setDescription(
_(
"If enabled, the object won't rotate and will stay at the same angle."
"If enabled, the object won't rotate and will stay at the same angle. Useful for characters for example."
)
)
.setGroup(_('Movement'));
@@ -845,7 +845,7 @@ module.exports = {
)
.addParameter('object', _('Object'), '', false)
.addParameter('behavior', _('Behavior'), 'Physics3DBehavior')
.addParameter('yesorno', _('Treat as bullet'), '', false)
.addParameter('yesorno', _('Treat as bullet?'), '', false)
.setDefaultValue('false')
.getCodeExtraInformation()
.setFunctionName('setBullet');
@@ -870,7 +870,7 @@ module.exports = {
'SetFixedRotation',
_('Fixed rotation'),
_(
"Enable or disable an object fixed rotation. If enabled the object won't be able to rotate. This action has no effect on characters."
"Enable or disable an object fixed rotation. If enabled the object won't be able to rotate."
),
_('Set _PARAM0_ fixed rotation: _PARAM2_'),
_('Dynamics'),
@@ -879,7 +879,7 @@ module.exports = {
)
.addParameter('object', _('Object'), '', false)
.addParameter('behavior', _('Behavior'), 'Physics3DBehavior')
.addParameter('yesorno', _('Fixed rotation'), '', false)
.addParameter('yesorno', _('Fixed rotation?'), '', false)
.setDefaultValue('false')
.getCodeExtraInformation()
.setFunctionName('setFixedRotation');
@@ -927,54 +927,6 @@ module.exports = {
.setFunctionName('setDensity')
.setGetter('getDensity');
aut
.addExpressionAndConditionAndAction(
'number',
'ShapeOffsetX',
_('Shape offset X'),
_('the object shape offset on X.'),
_('the shape offset on X'),
_('Body settings'),
'JsPlatform/Extensions/physics3d.svg'
)
.addParameter('object', _('Object'), '', false)
.addParameter('behavior', _('Behavior'), 'Physics3DBehavior')
.useStandardParameters('number', gd.ParameterOptions.makeNewOptions())
.setFunctionName('setShapeOffsetX')
.setGetter('getShapeOffsetX');
aut
.addExpressionAndConditionAndAction(
'number',
'ShapeOffsetY',
_('Shape offset Y'),
_('the object shape offset on Y.'),
_('the shape offset on Y'),
_('Body settings'),
'JsPlatform/Extensions/physics3d.svg'
)
.addParameter('object', _('Object'), '', false)
.addParameter('behavior', _('Behavior'), 'Physics3DBehavior')
.useStandardParameters('number', gd.ParameterOptions.makeNewOptions())
.setFunctionName('setShapeOffsetY')
.setGetter('getShapeOffsetY');
aut
.addExpressionAndConditionAndAction(
'number',
'ShapeOffsetZ',
_('Shape offset Z'),
_('the object shape offset on Z.'),
_('the shape offset on Z'),
_('Body settings'),
'JsPlatform/Extensions/physics3d.svg'
)
.addParameter('object', _('Object'), '', false)
.addParameter('behavior', _('Behavior'), 'Physics3DBehavior')
.useStandardParameters('number', gd.ParameterOptions.makeNewOptions())
.setFunctionName('setShapeOffsetZ')
.setGetter('getShapeOffsetZ');
aut
.addExpressionAndConditionAndAction(
'number',
@@ -1102,7 +1054,7 @@ module.exports = {
.addParameter('object', _('Object'), '', false)
.addParameter('behavior', _('Behavior'), 'Physics3DBehavior')
.addParameter('expression', _('Layer (1 - 8)'))
.addParameter('yesorno', _('Enable'), '', false)
.addParameter('yesorno', _('Enable?'), '', false)
.setDefaultValue('true')
.getCodeExtraInformation()
.setFunctionName('enableLayer');
@@ -1138,7 +1090,7 @@ module.exports = {
.addParameter('object', _('Object'), '', false)
.addParameter('behavior', _('Behavior'), 'Physics3DBehavior')
.addParameter('expression', _('Mask (1 - 8)'))
.addParameter('yesorno', _('Enable'), '', false)
.addParameter('yesorno', _('Enable?'), '', false)
.setDefaultValue('true')
.getCodeExtraInformation()
.setFunctionName('enableMask');
@@ -1318,7 +1270,7 @@ module.exports = {
.addParameter('expression', _('Application point on Z axis'))
.setParameterLongDescription(
_(
'Use `MassCenterX`, `MassCenterY` and `MassCenterZ` expressions to avoid any rotation.'
'Use `MassCenterX` and `MassCenterY` expressions to avoid any rotation.'
)
)
.getCodeExtraInformation()
@@ -1592,19 +1544,6 @@ module.exports = {
.addParameter('behavior', _('Behavior'), 'Physics3DBehavior')
.getCodeExtraInformation()
.setFunctionName('getMassCenterY');
aut
.addExpression(
'MassCenterZ',
_('Mass center Z'),
_('Mass center Z'),
'',
'JsPlatform/Extensions/physics3d.svg'
)
.addParameter('object', _('Object'), '', false)
.addParameter('behavior', _('Behavior'), 'Physics3DBehavior')
.getCodeExtraInformation()
.setFunctionName('getMassCenterZ');
}
// Collision
extension

View File

@@ -630,34 +630,24 @@ namespace gdjs {
override onDeActivate() {
this._sharedData.removeFromBehaviorsList(this);
this._destroyBody();
}
override onActivate() {
this._sharedData.addToBehaviorsList(this);
}
override onDestroy() {
this._destroyedDuringFrameLogic = true;
this.onDeActivate();
}
_destroyBody() {
this.bodyUpdater.destroyBody();
this._contactsEndedThisFrame.length = 0;
this._contactsStartedThisFrame.length = 0;
this._currentContacts.length = 0;
}
resetToDefaultBodyUpdater() {
this.bodyUpdater = new gdjs.Physics3DRuntimeBehavior.DefaultBodyUpdater(
this
);
override onActivate() {
this._sharedData.addToBehaviorsList(this);
this._contactsEndedThisFrame.length = 0;
this._contactsStartedThisFrame.length = 0;
this._currentContacts.length = 0;
this.updateBodyFromObject();
}
resetToDefaultCollisionChecker() {
this.collisionChecker =
new gdjs.Physics3DRuntimeBehavior.DefaultCollisionChecker(this);
override onDestroy() {
this._destroyedDuringFrameLogic = true;
this.onDeActivate();
}
createShape(): Jolt.Shape {
@@ -937,7 +927,9 @@ namespace gdjs {
const angularVelocityY = angularVelocity.GetY();
const angularVelocityZ = angularVelocity.GetZ();
this.bodyUpdater.destroyBody();
let bodyID = this._body.GetID();
bodyInterface.RemoveBody(bodyID);
bodyInterface.DestroyBody(bodyID);
this._contactsEndedThisFrame.length = 0;
this._contactsStartedThisFrame.length = 0;
this._currentContacts.length = 0;
@@ -946,7 +938,7 @@ namespace gdjs {
if (!this._body) {
return;
}
const bodyID = this._body.GetID();
bodyID = this._body.GetID();
bodyInterface.SetLinearVelocity(
bodyID,
this.getVec3(linearVelocityX, linearVelocityY, linearVelocityZ)
@@ -1186,33 +1178,6 @@ namespace gdjs {
this._needToRecreateBody = true;
}
getShapeOffsetX(): float {
return this.shapeOffsetX;
}
setShapeOffsetX(shapeOffsetX: float): void {
this.shapeOffsetX = shapeOffsetX;
this._needToRecreateShape = true;
}
getShapeOffsetY(): float {
return this.shapeOffsetY;
}
setShapeOffsetY(shapeOffsetY: float): void {
this.shapeOffsetY = shapeOffsetY;
this._needToRecreateShape = true;
}
getShapeOffsetZ(): float {
return this.shapeOffsetZ;
}
setShapeOffsetZ(shapeOffsetZ: float): void {
this.shapeOffsetZ = shapeOffsetZ;
this._needToRecreateShape = true;
}
getFriction(): float {
return this.friction;
}
@@ -1577,9 +1542,9 @@ namespace gdjs {
}
const body = this._body!;
const deltaX = towardX - this.owner3D.getX();
const deltaY = towardY - this.owner3D.getY();
const deltaZ = towardZ - this.owner3D.getZ();
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) {
return;
@@ -1637,16 +1602,19 @@ namespace gdjs {
length: float,
towardX: float,
towardY: float,
towardZ: float
towardZ: float,
originX: float,
originY: float,
originZ: float
): void {
if (this._body === null) {
if (!this._createBody()) return;
}
const body = this._body!;
const deltaX = towardX - this.owner3D.getX();
const deltaY = towardY - this.owner3D.getY();
const deltaZ = towardZ - this.owner3D.getZ();
const deltaX = towardX - originX;
const deltaY = towardY - originY;
const deltaZ = towardZ - originZ;
const distanceSq = deltaX * deltaX + deltaY * deltaY + deltaZ * deltaZ;
if (distanceSq === 0) {
return;
@@ -1655,7 +1623,12 @@ namespace gdjs {
this._sharedData.bodyInterface.AddImpulse(
body.GetID(),
this.getVec3(deltaX * ratio, deltaY * ratio, deltaZ * ratio)
this.getVec3(deltaX * ratio, deltaY * ratio, deltaZ * ratio),
this.getRVec3(
originX * this._sharedData.worldInvScale,
originY * this._sharedData.worldInvScale,
originZ * this._sharedData.worldInvScale
)
);
}

View File

@@ -29,7 +29,6 @@ namespace gdjs {
owner3D: gdjs.RuntimeObject3D;
private _physics3DBehaviorName: string;
private _physics3D: Physics3D | null = null;
private _isHookedToPhysicsStep = false;
_vehicleController: Jolt.WheeledVehicleController | null = null;
_stepListener: Jolt.VehicleConstraintStepListener | null = null;
_vehicleCollisionTester: Jolt.VehicleCollisionTesterCastCylinder | null =
@@ -154,19 +153,13 @@ namespace gdjs {
const behavior = this.owner.getBehavior(
this._physics3DBehaviorName
) as gdjs.Physics3DRuntimeBehavior;
if (!behavior.activated()) {
return null;
}
const sharedData = behavior._sharedData;
this._physics3D = {
behavior,
};
if (!this._isHookedToPhysicsStep) {
sharedData.registerHook(this);
this._isHookedToPhysicsStep = true;
}
sharedData.registerHook(this);
behavior.bodyUpdater =
new gdjs.PhysicsCar3DRuntimeBehavior.VehicleBodyUpdater(
@@ -337,33 +330,25 @@ namespace gdjs {
}
override onDeActivate() {
if (!this._physics3D) {
return;
if (this._stepListener) {
this._sharedData.physicsSystem.RemoveStepListener(this._stepListener);
}
this._destroyBody();
}
override onActivate() {
const behavior = this.owner.getBehavior(
this._physics3DBehaviorName
) as gdjs.Physics3DRuntimeBehavior;
if (!behavior) {
return;
if (this._stepListener) {
this._sharedData.physicsSystem.AddStepListener(this._stepListener);
}
behavior._destroyBody();
}
override onDestroy() {
this._destroyedDuringFrameLogic = true;
this._destroyBody();
}
_destroyBody() {
if (!this._vehicleController) {
return;
}
this._destroyedDuringFrameLogic = true;
this.onDeActivate();
if (this._stepListener) {
this._sharedData.physicsSystem.RemoveStepListener(this._stepListener);
// stepListener is removed by onDeActivate
Jolt.destroy(this._stepListener);
this._stepListener = null;
}
@@ -375,8 +360,6 @@ namespace gdjs {
// It is destroyed with the constraint.
this._vehicleCollisionTester = null;
if (this._physics3D) {
const { behavior } = this._physics3D;
behavior.resetToDefaultBodyUpdater();
this._physics3D = null;
}
}
@@ -750,7 +733,7 @@ namespace gdjs {
}
setWheelOffsetZ(wheelOffsetZ: float): void {
this._wheelOffsetZ = wheelOffsetZ;
this._wheelOffsetY = wheelOffsetZ;
this._updateWheels();
}
@@ -800,11 +783,11 @@ namespace gdjs {
}
hasFrontWheelDrive(): boolean {
return this._hasFrontWheelDrive;
return this._hasBackWheelDrive;
}
setFrontWheelDrive(hasFrontWheelDrive: boolean): void {
this._hasFrontWheelDrive = hasFrontWheelDrive;
this._hasBackWheelDrive = hasFrontWheelDrive;
this.invalidateShape();
}
@@ -1127,7 +1110,7 @@ namespace gdjs {
}
destroyBody() {
this.carBehavior._destroyBody();
this.carBehavior.onDestroy();
this.physicsBodyUpdater.destroyBody();
}
}

View File

@@ -41,7 +41,6 @@ namespace gdjs {
owner3D: gdjs.RuntimeObject3D;
private _physics3DBehaviorName: string;
private _physics3D: Physics3D | null = null;
private _isHookedToPhysicsStep = false;
character: Jolt.CharacterVirtual | null = null;
/**
* sharedData is a reference to the shared data of the scene, that registers
@@ -170,15 +169,10 @@ namespace gdjs {
if (this._physics3D) {
return this._physics3D;
}
if (!this.activated()) {
return null;
}
const behavior = this.owner.getBehavior(
this._physics3DBehaviorName
) as gdjs.Physics3DRuntimeBehavior;
if (!behavior.activated()) {
return null;
}
const sharedData = behavior._sharedData;
const jolt = sharedData.jolt;
const extendedUpdateSettings = new Jolt.ExtendedUpdateSettings();
@@ -202,10 +196,7 @@ namespace gdjs {
shapeFilter,
};
this.setStairHeightMax(this._stairHeightMax);
if (!this._isHookedToPhysicsStep) {
sharedData.registerHook(this);
this._isHookedToPhysicsStep = true;
}
sharedData.registerHook(this);
behavior.bodyUpdater =
new gdjs.PhysicsCharacter3DRuntimeBehavior.CharacterBodyUpdater(this);
@@ -399,48 +390,36 @@ namespace gdjs {
}
override onDeActivate() {
if (!this._physics3D) {
return;
}
this._destroyBody();
this.collisionChecker.clearContacts();
}
override onActivate() {
const behavior = this.owner.getBehavior(
this._physics3DBehaviorName
) as gdjs.Physics3DRuntimeBehavior;
if (!behavior) {
return;
}
behavior._destroyBody();
}
override onActivate() {}
override onDestroy() {
this._destroyedDuringFrameLogic = true;
this.onDeActivate();
this._destroyCharacter();
}
/**
* Remove the character and its body from the physics engine.
* This method is called when:
* - The Physics3D behavior is deactivated
* - This behavior is deactivated
* - The object is destroyed
*
* Only deactivating the character behavior won't destroy the character.
* Indeed, deactivated characters don't move as characters but still have collisions.
*/
_destroyBody() {
_destroyCharacter() {
if (this.character) {
if (this._canBePushed) {
this.charactersManager.removeCharacter(this.character);
Jolt.destroy(this.character.GetListener());
}
this.collisionChecker.clearContacts();
// The body is destroyed with the character.
Jolt.destroy(this.character);
this.character = null;
if (this._physics3D) {
const { behavior } = this._physics3D;
behavior.resetToDefaultBodyUpdater();
behavior.resetToDefaultCollisionChecker();
this._physics3D.behavior._body = null;
const {
extendedUpdateSettings,
@@ -1801,7 +1780,7 @@ namespace gdjs {
}
destroyBody() {
this.characterBehavior._destroyBody();
this.characterBehavior._destroyCharacter();
}
}

View File

@@ -486,16 +486,7 @@ namespace gdjs {
this._state.beforeMovingX();
//Ensure the object is not stuck
const hasPopOutOfPlatform = this._separateFromPlatforms(
this._potentialCollidingObjects,
true
);
if (hasPopOutOfPlatform && !this._jumpKey) {
// TODO This is probably unnecessary because `_canJump` is already set
// to true when entering the `OnFloor` state.
// This is wrongly allowing double jumps when characters are flipped
// with an offset center.
if (this._separateFromPlatforms(this._potentialCollidingObjects, true)) {
//After being unstuck, the object must be able to jump again.
this._canJump = true;
}

View File

@@ -35,7 +35,7 @@ module.exports = {
.addDependency()
.setName('Safari View Controller Cordova plugin')
.setDependencyType('cordova')
.setExportName('@gdevelop/cordova-plugin-safariviewcontroller');
.setExportName('cordova-plugin-safariviewcontroller');
extension
.addAction(

View File

@@ -834,51 +834,34 @@ namespace gdjs {
authWindowOptions,
});
if (typeof SafariViewController === 'undefined') {
logger.error(
'Cordova plugin SafariViewController is not installed.'
);
resolve('errored');
return;
}
SafariViewController.isAvailable(function (available: boolean) {
if (!available) {
logger.error(
'Cordova plugin SafariViewController is installed but not available'
);
resolve('errored');
return;
}
logger.info(
'Opening authentication window for Cordova with SafariViewController.'
);
SafariViewController.show(
{
url: targetUrl,
hidden: false,
animated: true,
transition: 'slide',
enterReaderModeIfAvailable: false,
barColor: '#000000',
tintColor: '#ffffff',
controlTintColor: '#ffffff',
},
function (result: any) {
// Other events are `opened` and `loaded`.
if (result.event === 'closed') {
resolve('dismissed');
if (available) {
SafariViewController.show(
{
url: targetUrl,
hidden: false,
animated: true,
transition: 'slide',
enterReaderModeIfAvailable: false,
barColor: '#000000',
tintColor: '#ffffff',
controlTintColor: '#ffffff',
},
function (result: any) {
// Other events are `opened` and `loaded`.
if (result.event === 'closed') {
resolve('dismissed');
}
},
function (error: any) {
logger.log('Error opening webview: ' + JSON.stringify(error));
resolve('errored');
}
},
function (error: any) {
logger.log(
'Error opening authentication window: ' +
JSON.stringify(error)
);
resolve('errored');
}
);
);
} else {
logger.error('Plugin SafariViewController is not available');
resolve('errored');
}
});
}
);

View File

@@ -246,10 +246,10 @@ std::map<gd::String, gd::PropertyDescriptor> ShapePainterObject::GetProperties()
objectProperties["antialiasing"]
.SetValue(GetAntialiasing())
.SetType("choice")
.AddChoice("none", _("None"))
.AddChoice("low", _("Low quality"))
.AddChoice("medium", _("Medium quality"))
.AddChoice("high", _("High quality"))
.AddExtraInfo("none")
.AddExtraInfo("low")
.AddExtraInfo("medium")
.AddExtraInfo("high")
.SetGroup(_("Drawing"))
.SetLabel(_("Antialiasing"))
.SetDescription(_("Antialiasing mode"));

View File

@@ -195,35 +195,11 @@ namespace gdjs {
}
/**
* To be called when the game is disposed.
* Clear the Spine atlases loaded in this manager.
* Clear the Spine Atlases loaded in this manager.
*/
dispose(): void {
this._loadedSpineAtlases.clear();
this._loadingSpineAtlases.clear();
}
/**
* Unload the specified list of resources:
* this clears the Spine atlases loaded in this manager.
*
* Usually called when scene resoures are unloaded.
*
* @param resourcesList The list of specific resources
*/
unloadResourcesList(resourcesList: ResourceData[]): void {
resourcesList.forEach((resourceData) => {
const loadedSpineAtlas = this._loadedSpineAtlases.get(resourceData);
if (loadedSpineAtlas) {
loadedSpineAtlas.dispose();
this._loadedSpineAtlases.delete(resourceData);
}
const loadingSpineAtlas = this._loadingSpineAtlases.get(resourceData);
if (loadingSpineAtlas) {
loadingSpineAtlas.then((atl) => atl.dispose());
this._loadingSpineAtlases.delete(resourceData);
}
});
}
}
}

View File

@@ -126,22 +126,5 @@ namespace gdjs {
dispose(): void {
this._loadedSpines.clear();
}
/**
* Unload the specified list of resources:
* this clears the Spine skeleton data loaded in this manager.
*
* Usually called when scene resoures are unloaded.
*
* @param resourcesList The list of specific resources
*/
unloadResourcesList(resourcesList: ResourceData[]): void {
resourcesList.forEach((resourceData) => {
const loadedSpine = this._loadedSpines.get(resourceData);
if (loadedSpine) {
this._loadedSpines.delete(resourceData);
}
});
}
}
}

View File

@@ -14,6 +14,8 @@ namespace gdjs {
export type SpineNetworkSyncDataType = {
opa: float;
wid: float;
hei: float;
scaX: float;
scaY: float;
flipX: boolean;
@@ -115,6 +117,8 @@ namespace gdjs {
return {
...super.getNetworkSyncData(),
opa: this._opacity,
wid: this.getWidth(),
hei: this.getHeight(),
scaX: this.getScaleX(),
scaY: this.getScaleY(),
flipX: this.isFlippedX(),
@@ -133,6 +137,12 @@ namespace gdjs {
if (syncData.opa !== undefined && syncData.opa !== this._opacity) {
this.setOpacity(syncData.opa);
}
if (syncData.wid !== undefined && syncData.wid !== this.getWidth()) {
this.setWidth(syncData.wid);
}
if (syncData.hei !== undefined && syncData.hei !== this.getHeight()) {
this.setHeight(syncData.hei);
}
if (syncData.scaX !== undefined && syncData.scaX !== this.getScaleX()) {
this.setScaleX(syncData.scaX);
}

View File

@@ -78,9 +78,6 @@ module.exports = {
} else if (propertyName === 'disabled') {
objectContent.disabled = newValue === '1';
return true;
} else if (propertyName === 'spellCheck') {
objectContent.spellCheck = newValue === '1';
return true;
} else if (propertyName === 'maxLength') {
objectContent.maxLength = newValue;
return true;
@@ -134,14 +131,14 @@ module.exports = {
.getOrCreate('inputType')
.setValue(objectContent.inputType || '')
.setType('choice')
.addChoice('text', _('Text'))
.addChoice('text area', _('Text area'))
.addChoice('email', _('Email'))
.addChoice('password', _('Password'))
.addChoice('number', _('Number'))
.addChoice('telephone number', _('Telephone number'))
.addChoice('url', _('URL'))
.addChoice('search', _('Search'))
.addExtraInfo('text')
.addExtraInfo('text area')
.addExtraInfo('email')
.addExtraInfo('password')
.addExtraInfo('number')
.addExtraInfo('telephone number')
.addExtraInfo('url')
.addExtraInfo('search')
.setLabel(_('Input type'))
.setDescription(
_(
@@ -163,13 +160,6 @@ module.exports = {
.setLabel(_('Disabled'))
.setGroup(_('Field'));
objectProperties
.getOrCreate('spellCheck')
.setValue(objectContent.spellCheck ? 'true' : 'false')
.setType('boolean')
.setLabel(_('Enable spell check'))
.setGroup(_('Field'));
objectProperties
.getOrCreate('textColor')
.setValue(objectContent.textColor || '0;0;0')
@@ -260,9 +250,9 @@ module.exports = {
.getOrCreate('textAlign')
.setValue(objectContent.textAlign || 'left')
.setType('choice')
.addChoice('left', _('Left'))
.addChoice('center', _('Center'))
.addChoice('right', _('Right'))
.addExtraInfo('left')
.addExtraInfo('center')
.addExtraInfo('right')
.setLabel(_('Text alignment'))
.setGroup(_('Field appearance'));
@@ -282,7 +272,6 @@ module.exports = {
borderWidth: 1,
readOnly: false,
disabled: false,
spellCheck: false,
paddingX: 2,
paddingY: 1,
textAlign: 'left',
@@ -603,21 +592,6 @@ module.exports = {
.setFunctionName('setDisabled')
.setGetter('isDisabled');
object
.addExpressionAndConditionAndAction(
'boolean',
'SpellCheck',
_('Spell check enabled'),
_('spell check is enabled'),
_('spell check enabled'),
'',
'res/conditions/text24_black.png'
)
.addParameter('object', _('Text input'), 'TextInputObject', false)
.useStandardParameters('boolean', gd.ParameterOptions.makeNewOptions())
.setFunctionName('setSpellCheck')
.setGetter('isSpellCheckEnabled');
// Other expressions/conditions/actions:
// Deprecated

View File

@@ -106,7 +106,6 @@ namespace gdjs {
this.updateBorderWidth();
this.updateDisabled();
this.updateReadOnly();
this.updateSpellCheck();
this.updateTextAlign();
this.updateMaxLength();
this.updatePadding();
@@ -343,12 +342,6 @@ namespace gdjs {
this._input.readOnly = this._object.isReadOnly();
}
updateSpellCheck() {
if (!this._input) return;
this._input.spellcheck = this._object.isSpellCheckEnabled();
}
updateMaxLength() {
const input = this._input;
if (!input) return;

View File

@@ -54,7 +54,6 @@ namespace gdjs {
disabled: boolean;
readOnly: boolean;
// ---- Values can be undefined because of support for these feature was added in v5.5.222.
spellCheck?: boolean;
paddingX?: float;
paddingY?: float;
textAlign?: SupportedTextAlign;
@@ -65,6 +64,8 @@ namespace gdjs {
export type TextInputNetworkSyncDataType = {
opa: float;
wid: float;
hei: float;
txt: string;
frn: string;
fs: number;
@@ -78,7 +79,6 @@ namespace gdjs {
bw: float;
dis: boolean;
ro: boolean;
sc: boolean;
};
export type TextInputNetworkSyncData = ObjectNetworkSyncData &
@@ -118,7 +118,6 @@ namespace gdjs {
private _borderWidth: float;
private _disabled: boolean;
private _readOnly: boolean;
private _spellCheck: boolean;
private _isSubmitted: boolean;
_renderer: TextInputRuntimeObjectRenderer;
@@ -143,10 +142,6 @@ namespace gdjs {
this._borderWidth = objectData.content.borderWidth;
this._disabled = objectData.content.disabled;
this._readOnly = objectData.content.readOnly;
this._spellCheck =
objectData.content.spellCheck !== undefined
? objectData.content.spellCheck
: false;
this._textAlign = parseTextAlign(objectData.content.textAlign);
this._maxLength = objectData.content.maxLength || 0;
this._paddingX =
@@ -233,12 +228,6 @@ namespace gdjs {
if (oldObjectData.content.readOnly !== newObjectData.content.readOnly) {
this.setReadOnly(newObjectData.content.readOnly);
}
if (
newObjectData.content.spellCheck !== undefined &&
oldObjectData.content.spellCheck !== newObjectData.content.spellCheck
) {
this.setSpellCheck(newObjectData.content.spellCheck);
}
if (
newObjectData.content.maxLength !== undefined &&
oldObjectData.content.maxLength !== newObjectData.content.maxLength
@@ -271,6 +260,8 @@ namespace gdjs {
return {
...super.getNetworkSyncData(),
opa: this.getOpacity(),
wid: this.getWidth(),
hei: this.getHeight(),
txt: this.getText(),
frn: this.getFontResourceName(),
fs: this.getFontSize(),
@@ -284,7 +275,6 @@ namespace gdjs {
bw: this.getBorderWidth(),
dis: this.isDisabled(),
ro: this.isReadOnly(),
sc: this.isSpellCheckEnabled(),
};
}
@@ -292,6 +282,8 @@ namespace gdjs {
super.updateFromNetworkSyncData(syncData);
if (syncData.opa !== undefined) this.setOpacity(syncData.opa);
if (syncData.wid !== undefined) this.setWidth(syncData.wid);
if (syncData.hei !== undefined) this.setHeight(syncData.hei);
if (syncData.txt !== undefined) this.setText(syncData.txt);
if (syncData.frn !== undefined) this.setFontResourceName(syncData.frn);
if (syncData.fs !== undefined) this.setFontSize(syncData.fs);
@@ -305,7 +297,6 @@ namespace gdjs {
if (syncData.bw !== undefined) this.setBorderWidth(syncData.bw);
if (syncData.dis !== undefined) this.setDisabled(syncData.dis);
if (syncData.ro !== undefined) this.setReadOnly(syncData.ro);
if (syncData.sc !== undefined) this.setSpellCheck(syncData.sc);
}
updatePreRender(instanceContainer: RuntimeInstanceContainer): void {
@@ -578,15 +569,6 @@ namespace gdjs {
return this._readOnly;
}
setSpellCheck(value: boolean) {
this._spellCheck = value;
this._renderer.updateSpellCheck();
}
isSpellCheckEnabled(): boolean {
return this._spellCheck;
}
isFocused(): boolean {
return this._renderer.isFocused();
}

View File

@@ -160,9 +160,9 @@ std::map<gd::String, gd::PropertyDescriptor> TextObject::GetProperties() const {
objectProperties["textAlignment"]
.SetValue(textAlignment)
.SetType("choice")
.AddChoice("left", _("Left"))
.AddChoice("center", _("Center"))
.AddChoice("right", _("Right"))
.AddExtraInfo("left")
.AddExtraInfo("center")
.AddExtraInfo("right")
.SetLabel(_("Alignment"))
.SetDescription(_("Alignment of the text when multiple lines are displayed"))
.SetGroup(_("Font"))
@@ -171,9 +171,9 @@ std::map<gd::String, gd::PropertyDescriptor> TextObject::GetProperties() const {
objectProperties["verticalTextAlignment"]
.SetValue(verticalTextAlignment)
.SetType("choice")
.AddChoice("top", _("Top"))
.AddChoice("center", _("Center"))
.AddChoice("bottom", _("Bottom"))
.AddExtraInfo("top")
.AddExtraInfo("center")
.AddExtraInfo("bottom")
.SetLabel(_("Vertical alignment"))
.SetGroup(_("Font"))
.SetQuickCustomizationVisibility(gd::QuickCustomization::Hidden);

View File

@@ -102,9 +102,9 @@ const defineTileMap = function (extension, _, gd) {
'displayMode',
new gd.PropertyDescriptor(objectContent.displayMode)
.setType('choice')
.addChoice('visible', _('Visible layers'))
.addChoice('all', _('All layers'))
.addChoice('index', _('Only the layer with the specified index'))
.addExtraInfo('visible')
.addExtraInfo('all')
.addExtraInfo('index')
.setLabel(_('Display mode'))
.setGroup(_('Appearance'))
);

View File

@@ -17,6 +17,8 @@ namespace gdjs {
export type SimpleTileMapNetworkSyncDataType = {
op: number;
ai: string;
wid: number;
hei: number;
// TODO: Support tilemap synchronization. Find an efficient way to send tiles changes.
};
@@ -168,6 +170,8 @@ namespace gdjs {
...super.getNetworkSyncData(),
op: this._opacity,
ai: this._atlasImage,
wid: this.getWidth(),
hei: this.getHeight(),
};
}
@@ -182,6 +186,18 @@ namespace gdjs {
) {
this.setOpacity(networkSyncData.op);
}
if (
networkSyncData.wid !== undefined &&
networkSyncData.wid !== this.getWidth()
) {
this.setWidth(networkSyncData.wid);
}
if (
networkSyncData.hei !== undefined &&
networkSyncData.hei !== this.getHeight()
) {
this.setHeight(networkSyncData.hei);
}
if (networkSyncData.ai !== undefined) {
// TODO: support changing the atlas texture
}

View File

@@ -26,6 +26,8 @@ namespace gdjs {
os: float;
fo: float;
oo: float;
wid: float;
hei: float;
};
export type TilemapCollisionMaskNetworkSyncData = ObjectNetworkSyncData &
@@ -200,6 +202,8 @@ namespace gdjs {
os: this.getOutlineSize(),
fo: this.getFillOpacity(),
oo: this.getOutlineOpacity(),
wid: this.getWidth(),
hei: this.getHeight(),
};
}
@@ -232,6 +236,12 @@ namespace gdjs {
if (networkSyncData.oo !== undefined) {
this.setOutlineOpacity(networkSyncData.oo);
}
if (networkSyncData.wid !== undefined) {
this.setWidth(networkSyncData.wid);
}
if (networkSyncData.hei !== undefined) {
this.setHeight(networkSyncData.hei);
}
}
extraInitializationFromInitialInstance(initialInstanceData): void {

View File

@@ -25,6 +25,8 @@ namespace gdjs {
lai: number;
lei: number;
asps: number;
wid: number;
hei: number;
};
export type TilemapNetworkSyncData = ObjectNetworkSyncData &
@@ -156,6 +158,8 @@ namespace gdjs {
lai: this._layerIndex,
lei: this._levelIndex,
asps: this._animationSpeedScale,
wid: this.getWidth(),
hei: this.getHeight(),
};
}
@@ -186,6 +190,12 @@ namespace gdjs {
if (networkSyncData.asps !== undefined) {
this.setAnimationSpeedScale(networkSyncData.asps);
}
if (networkSyncData.wid !== undefined) {
this.setWidth(networkSyncData.wid);
}
if (networkSyncData.hei !== undefined) {
this.setHeight(networkSyncData.hei);
}
}
extraInitializationFromInitialInstance(initialInstanceData): void {

View File

@@ -15,6 +15,8 @@ namespace gdjs {
export type TiledSpriteObjectData = ObjectData & TiledSpriteObjectDataType;
export type TiledSpriteNetworkSyncDataType = {
wid: number;
hei: number;
xo: number;
yo: number;
op: number;
@@ -81,6 +83,8 @@ namespace gdjs {
getNetworkSyncData(): TiledSpriteNetworkSyncData {
return {
...super.getNetworkSyncData(),
wid: this.getWidth(),
hei: this.getHeight(),
xo: this.getXOffset(),
yo: this.getYOffset(),
op: this.getOpacity(),
@@ -95,6 +99,12 @@ namespace gdjs {
// Texture is not synchronized, see if this is asked or not.
if (networkSyncData.wid !== undefined) {
this.setWidth(networkSyncData.wid);
}
if (networkSyncData.hei !== undefined) {
this.setHeight(networkSyncData.hei);
}
if (networkSyncData.xo !== undefined) {
this.setXOffset(networkSyncData.xo);
}

View File

@@ -90,11 +90,10 @@ TopDownMovementBehavior::GetProperties(
.SetValue(
gd::String::From(behaviorContent.GetDoubleAttribute("angleOffset")));
properties["IgnoreDefaultControls"]
.SetLabel(_("Disable default keyboard controls"))
.SetQuickCustomizationVisibility(gd::QuickCustomization::Hidden)
.SetLabel(_("Default controls"))
.SetValue(behaviorContent.GetBoolAttribute("ignoreDefaultControls")
? "true"
: "false")
? "false"
: "true")
.SetType("Boolean");
properties["UseLegacyTurnBack"]
.SetLabel(_("Only use acceleration to turn back "
@@ -156,7 +155,7 @@ bool TopDownMovementBehavior::UpdateProperty(
const gd::String& name,
const gd::String& value) {
if (name == "IgnoreDefaultControls") {
behaviorContent.SetAttribute("ignoreDefaultControls", (value == "1"));
behaviorContent.SetAttribute("ignoreDefaultControls", (value == "0"));
return true;
}
if (name == "AllowDiagonals") {

View File

@@ -507,6 +507,10 @@ namespace gdjs {
cos = 0;
}
const getAcceleratedSpeed = this._useLegacyTurnBack
? TopDownMovementRuntimeBehavior.getLegacyAcceleratedSpeed
: TopDownMovementRuntimeBehavior.getAcceleratedSpeed;
let currentSpeed = Math.hypot(this._xVelocity, this._yVelocity);
const dotProduct = this._xVelocity * cos + this._yVelocity * sin;
if (dotProduct < 0) {
@@ -514,14 +518,13 @@ namespace gdjs {
// Keep the negative velocity projected on the new direction.
currentSpeed = dotProduct;
}
const speed = TopDownMovementRuntimeBehavior.getAcceleratedSpeed(
const speed = getAcceleratedSpeed(
currentSpeed,
targetedSpeed,
this._maxSpeed,
this._acceleration,
this._deceleration,
timeDelta,
this._useLegacyTurnBack
timeDelta
);
this._xVelocity = speed * cos;
this._yVelocity = speed * sin;
@@ -596,13 +599,10 @@ namespace gdjs {
speedMax: float,
acceleration: float,
deceleration: float,
timeDelta: float,
useLegacyTurnBack: boolean = false
timeDelta: float
): float {
let newSpeed = currentSpeed;
const turningBackAcceleration = useLegacyTurnBack
? acceleration
: Math.max(acceleration, deceleration);
const turningBackAcceleration = Math.max(acceleration, deceleration);
if (targetedSpeed < 0) {
if (currentSpeed <= targetedSpeed) {
// Reduce the speed to match the stick force.
@@ -652,6 +652,62 @@ namespace gdjs {
return newSpeed;
}
private static getLegacyAcceleratedSpeed(
currentSpeed: float,
targetedSpeed: float,
speedMax: float,
acceleration: float,
deceleration: float,
timeDelta: float
): float {
let newSpeed = currentSpeed;
if (targetedSpeed < 0) {
if (currentSpeed <= targetedSpeed) {
// Reduce the speed to match the stick force.
newSpeed = Math.min(
targetedSpeed,
currentSpeed + deceleration * timeDelta
);
} else if (currentSpeed <= 0) {
// Accelerate
newSpeed -= Math.max(-speedMax, acceleration * timeDelta);
} else {
newSpeed = Math.max(
targetedSpeed,
currentSpeed - deceleration * timeDelta
);
}
} else if (targetedSpeed > 0) {
if (currentSpeed >= targetedSpeed) {
// Reduce the speed to match the stick force.
newSpeed = Math.max(
targetedSpeed,
currentSpeed - deceleration * timeDelta
);
} else if (currentSpeed >= 0) {
// Accelerate
newSpeed = Math.min(
speedMax,
currentSpeed + acceleration * timeDelta
);
} else {
newSpeed = Math.min(
targetedSpeed,
currentSpeed + deceleration * timeDelta
);
}
} else {
// Decelerate and stop.
if (currentSpeed < 0) {
newSpeed = Math.min(currentSpeed + deceleration * timeDelta, 0);
}
if (currentSpeed > 0) {
newSpeed = Math.max(currentSpeed - deceleration * timeDelta, 0);
}
}
return newSpeed;
}
simulateControl(input: string) {
if (input === 'Left') {
this._leftKey = true;

View File

@@ -18,6 +18,8 @@ namespace gdjs {
export type VideoNetworkSyncDataType = {
op: float;
wid: float;
hei: float;
// We don't sync volume, as it's probably a user setting?
pla: boolean;
loop: boolean;
@@ -103,6 +105,8 @@ namespace gdjs {
return {
...super.getNetworkSyncData(),
op: this._opacity,
wid: this.getWidth(),
hei: this.getHeight(),
pla: this.isPlayed(),
loop: this.isLooped(),
ct: this.getCurrentTime(),
@@ -116,6 +120,12 @@ namespace gdjs {
if (this._opacity !== undefined && this._opacity && syncData.op) {
this.setOpacity(syncData.op);
}
if (this.getWidth() !== undefined && this.getWidth() !== syncData.wid) {
this.setWidth(syncData.wid);
}
if (this.getHeight() !== undefined && this.getHeight() !== syncData.hei) {
this.setHeight(syncData.hei);
}
if (syncData.pla !== undefined && this.isPlayed() !== syncData.pla) {
syncData.pla ? this.play() : this.pause();
}

View File

@@ -43,10 +43,6 @@ StringInstructionsExtension::StringInstructionsExtension() {
"gdjs.evtTools.string.strFindLastFrom");
GetAllExpressions()["StrFindLastFrom"].SetFunctionName(
"gdjs.evtTools.string.strFindLastFrom");
GetAllStrExpressions()["StrReplaceOne"].SetFunctionName(
"gdjs.evtTools.string.strReplaceOne");
GetAllStrExpressions()["StrReplaceAll"].SetFunctionName(
"gdjs.evtTools.string.strReplaceAll");
StripUnimplementedInstructionsAndExpressions();
}

View File

@@ -14,12 +14,6 @@ namespace gdjs {
animatable?: SpriteAnimationData[];
variant: string;
childrenContent: { [objectName: string]: ObjectConfiguration & any };
isInnerAreaFollowingParentSize: boolean;
};
export type CustomObjectNetworkSyncDataType = ObjectNetworkSyncData & {
ifx: boolean;
ify: boolean;
};
/**
@@ -117,19 +111,9 @@ namespace gdjs {
name: '',
};
}
// Legacy events-based objects don't have any instance in their default
// variant since there wasn't a graphical editor at the time.
// In this case, the editor doesn't allow to choose a variant, but a
// variant may have stayed after a user rolled back the extension.
// This variant must be ignored to match what the editor shows.
const isForcedToOverrideEventsBasedObjectChildrenConfiguration =
eventsBasedObjectData.defaultVariant.instances.length == 0;
let usedVariantData: EventsBasedObjectVariantData =
eventsBasedObjectData.defaultVariant;
if (
customObjectData.variant &&
!isForcedToOverrideEventsBasedObjectChildrenConfiguration
) {
if (customObjectData.variant) {
for (
let variantIndex = 0;
variantIndex < eventsBasedObjectData.variants.length;
@@ -170,12 +154,10 @@ namespace gdjs {
override reinitialize(objectData: ObjectData & CustomObjectConfiguration) {
super.reinitialize(objectData);
this._reinitializeRenderer();
this._initializeFromObjectData(objectData);
this._reinitializeRenderer();
// When changing the variant, the instance is like a new instance.
// We call again `onCreated` at the end, like done by the constructor
// the first time it's created.
// The generated code calls the onCreated super implementation at the end.
this.onCreated();
}
@@ -190,57 +172,9 @@ namespace gdjs {
newObjectData.animatable || []
);
}
if (oldObjectData.variant !== newObjectData.variant) {
const width = this.getWidth();
const height = this.getHeight();
const hasInnerAreaChanged =
oldObjectData.isInnerAreaFollowingParentSize &&
this._instanceContainer._initialInnerArea &&
this._innerArea &&
(this._instanceContainer._initialInnerArea.min[0] !==
this._innerArea.min[0] ||
this._instanceContainer._initialInnerArea.min[1] !==
this._innerArea.min[1] ||
this._instanceContainer._initialInnerArea.max[0] !==
this._innerArea.max[0] ||
this._instanceContainer._initialInnerArea.max[1] !==
this._innerArea.max[1]);
this._reinitializeRenderer();
this._initializeFromObjectData(newObjectData);
// The generated code calls the onCreated super implementation at the end.
this.onCreated();
// Keep the custom size
if (hasInnerAreaChanged) {
this.setWidth(width);
this.setHeight(height);
}
}
return true;
}
getNetworkSyncData(): CustomObjectNetworkSyncDataType {
return {
...super.getNetworkSyncData(),
ifx: this.isFlippedX(),
ify: this.isFlippedY(),
};
}
updateFromNetworkSyncData(
networkSyncData: CustomObjectNetworkSyncDataType
) {
super.updateFromNetworkSyncData(networkSyncData);
if (networkSyncData.ifx !== undefined) {
this.flipX(networkSyncData.ifx);
}
if (networkSyncData.ify !== undefined) {
this.flipY(networkSyncData.ify);
}
}
override extraInitializationFromInitialInstance(
initialInstanceData: InstanceData
) {
@@ -278,12 +212,7 @@ namespace gdjs {
// Let behaviors do something before the object is destroyed.
super.onDeletedFromScene();
// Destroy the children.
this._instanceContainer.onDeletedFromScene(this._runtimeScene);
}
override onDestroyed(): void {
this._instanceContainer._destroy();
super.onDestroyed();
this._instanceContainer.onDestroyFromScene(this._runtimeScene);
}
override update(parent: gdjs.RuntimeInstanceContainer): void {
@@ -306,8 +235,6 @@ namespace gdjs {
/**
* This method is called when the preview is being hot-reloaded.
*
* Custom objects implement this method with code generated from events.
*/
onHotReloading(parent: gdjs.RuntimeInstanceContainer) {}
@@ -316,8 +243,6 @@ namespace gdjs {
/**
* This method is called each tick after events are done.
*
* Custom objects implement this method with code generated from events.
* @param parent The instanceContainer owning the object
*/
doStepPostEvents(parent: gdjs.RuntimeInstanceContainer) {}
@@ -325,8 +250,6 @@ namespace gdjs {
/**
* This method is called when the object is being removed from its parent
* container and is about to be destroyed/reused later.
*
* Custom objects implement this method with code generated from events.
*/
onDestroy(parent: gdjs.RuntimeInstanceContainer) {}

View File

@@ -8,6 +8,7 @@ namespace gdjs {
objectData: ObjectData & CustomObjectConfiguration
) {
super(parent, objectData);
this.getRenderer().reinitialize(this, parent);
}
protected override _createRender(): gdjs.CustomRuntimeObject2DRenderer {

View File

@@ -24,7 +24,7 @@ namespace gdjs {
*
* @see gdjs.CustomRuntimeObject._innerArea
**/
_initialInnerArea: {
private _initialInnerArea: {
min: [float, float, float];
max: [float, float, float];
} | null = null;
@@ -47,9 +47,6 @@ namespace gdjs {
}
addLayer(layerData: LayerData) {
if (this._layers.containsKey(layerData.name)) {
return;
}
const layer = new gdjs.RuntimeCustomObjectLayer(layerData, this);
this._layers.put(layerData.name, layer);
this._orderedLayers.push(layer);
@@ -71,13 +68,9 @@ namespace gdjs {
eventsBasedObjectVariantData: EventsBasedObjectVariantData
) {
if (this._isLoaded) {
this.onDeletedFromScene(this._parent);
this.onDestroyFromScene(this._parent);
}
const isForcedToOverrideEventsBasedObjectChildrenConfiguration =
!eventsBasedObjectVariantData.name &&
eventsBasedObjectVariantData.instances.length == 0;
this._setOriginalInnerArea(eventsBasedObjectVariantData);
// Registering objects
@@ -90,8 +83,7 @@ namespace gdjs {
// The children configuration override only applies to the default variant.
if (
customObjectData.childrenContent &&
(!eventsBasedObjectVariantData.name ||
isForcedToOverrideEventsBasedObjectChildrenConfiguration)
!eventsBasedObjectVariantData.name
) {
this.registerObject({
...childObjectData,
@@ -186,25 +178,26 @@ namespace gdjs {
*
* @param instanceContainer The container owning the object.
*/
onDeletedFromScene(instanceContainer: gdjs.RuntimeInstanceContainer): void {
onDestroyFromScene(instanceContainer: gdjs.RuntimeInstanceContainer): void {
if (!this._isLoaded) {
return;
}
// Notify the objects they are being destroyed
const allInstancesList = this.getAdhocListOfAllInstances();
for (let i = 0, len = allInstancesList.length; i < len; ++i) {
const object = allInstancesList[i];
object.onDeletedFromScene();
// The object can free all its resource directly...
object.onDestroyed();
}
// ...as its container cache `_instancesRemoved` is also destroy.
this._destroy();
this._isLoaded = false;
}
override _destroy() {
const allInstancesList = this.getAdhocListOfAllInstances();
for (let i = 0, len = allInstancesList.length; i < len; ++i) {
const object = allInstancesList[i];
object.onDestroyed();
}
_destroy() {
// It should not be necessary to reset these variables, but this help
// ensuring that all memory related to the container is released immediately.
super._destroy();
@@ -382,9 +375,11 @@ namespace gdjs {
): FloatPoint {
const position = result || [0, 0];
this._customObject.applyObjectTransformation(sceneX, sceneY, position);
return this._parent
.getLayer(this._customObject.getLayer())
.convertInverseCoords(position[0], position[1], 0, position);
return this._parent.convertInverseCoords(
position[0],
position[1],
position
);
}
/**

View File

@@ -162,29 +162,5 @@ namespace gdjs {
this._invalidModel.scene.clear();
}
}
/**
* Unload the specified list of resources:
* this clears the models, resources loaded and destroy 3D models loaders in this manager.
*
* Usually called when scene resoures are unloaded.
*
* @param resourcesList The list of specific resources
*/
unloadResourcesList(resourcesList: ResourceData[]): void {
resourcesList.forEach((resourceData) => {
const loadedThreeModel = this._loadedThreeModels.get(resourceData);
if (loadedThreeModel) {
loadedThreeModel.scene.clear();
this._loadedThreeModels.delete(resourceData);
}
const downloadedArrayBuffer =
this._downloadedArrayBuffers.get(resourceData);
if (downloadedArrayBuffer) {
this._downloadedArrayBuffers.delete(resourceData);
}
});
}
}
}

View File

@@ -5,7 +5,6 @@
*/
namespace gdjs {
const logger = new gdjs.Logger('ResourceLoader');
const debugLogger = new gdjs.Logger('ResourceLoader - debug').enable(false);
const addSearchParameterToUrl = (
url: string,
@@ -97,15 +96,17 @@ namespace gdjs {
*/
private _globalResources: Array<string>;
/**
* Resources and the loading state of each scene, indexed by scene name.
* Resources by scene names.
*/
private _sceneLoadingStates: Map<
string,
{
resourceNames: Array<string>;
status: 'not-loaded' | 'loaded' | 'ready';
}
> = new Map();
private _sceneResources: Map<string, Array<string>>;
/**
* Keep track of which scene whose resources has already be pre-loaded.
*/
private _sceneNamesToLoad: Set<string>;
/**
* Keep track of which scene whose resources has already be loaded.
*/
private _sceneNamesToMakeReady: Set<string>;
/**
* A queue of scenes whose resources are still to be pre-loaded.
*/
@@ -126,12 +127,11 @@ namespace gdjs {
private _spineManager: SpineManager | null = null;
/**
* The name of the scene for which resources are currently being loaded.
* Only used by events.
*/
private currentLoadingSceneName: string = '';
/**
* The progress, between 0 and 1, of the loading of the resource, for the
* scene that is being loaded (see `currentLoadingSceneName`).
* Only used by events.
*/
private currentSceneLoadingProgress: float = 0;
/**
@@ -144,8 +144,8 @@ namespace gdjs {
/**
* @param runtimeGame The game.
* @param resourceDataArray The resources data of the game.
* @param globalResources The resources needed for any scene.
* @param layoutDataArray The resources used by each scene.
* @param globalResources The resources needed for any layer.
* @param layoutDataArray The resources used by each layer.
*/
constructor(
runtimeGame: RuntimeGame,
@@ -158,6 +158,9 @@ namespace gdjs {
this._globalResources = globalResources;
// These 3 attributes are filled by `setResources`.
this._sceneResources = new Map<string, Array<string>>();
this._sceneNamesToLoad = new Set<string>();
this._sceneNamesToMakeReady = new Set<string>();
this.setResources(resourceDataArray, globalResources, layoutDataArray);
this._imageManager = new gdjs.ImageManager(this);
@@ -221,31 +224,23 @@ namespace gdjs {
): void {
this._globalResources = globalResources;
this._sceneLoadingStates.clear();
this._sceneResources.clear();
this._sceneNamesToLoad.clear();
this._sceneNamesToMakeReady.clear();
for (const layoutData of layoutDataArray) {
this._sceneLoadingStates.set(layoutData.name, {
resourceNames: layoutData.usedResources.map(
(resource) => resource.name
),
status: 'not-loaded',
});
this._sceneResources.set(
layoutData.name,
layoutData.usedResources.map((resource) => resource.name)
);
this._sceneNamesToLoad.add(layoutData.name);
this._sceneNamesToMakeReady.add(layoutData.name);
}
// TODO Clearing the queue doesn't abort the running task, but it should
// not matter as resource loading is really fast in preview mode.
this._sceneToLoadQueue.length = 0;
for (let index = layoutDataArray.length - 1; index >= 0; index--) {
const layoutData = layoutDataArray[index];
const resourcesPreloading = layoutData.resourcesPreloading || 'inherit';
const resolvedResourcesPreloading =
resourcesPreloading === 'inherit'
? this._runtimeGame.getSceneResourcesPreloading()
: resourcesPreloading;
if (resolvedResourcesPreloading === 'at-startup') {
this._sceneToLoadQueue.push(new SceneLoadingTask(layoutData.name));
}
this._sceneToLoadQueue.push(new SceneLoadingTask(layoutData.name));
}
this._resources.clear();
@@ -276,10 +271,8 @@ namespace gdjs {
onProgress(loadedCount, this._resources.size);
}
);
for (const sceneLoadingState of this._sceneLoadingStates.values()) {
sceneLoadingState.status = 'ready';
}
this._sceneNamesToLoad.clear();
this._sceneNamesToMakeReady.clear();
}
/**
@@ -289,21 +282,17 @@ namespace gdjs {
firstSceneName: string,
onProgress: (count: number, total: number) => void
): Promise<void> {
const firstSceneState = this._sceneLoadingStates.get(firstSceneName);
if (!firstSceneState) {
const sceneResources = this._sceneResources.get(firstSceneName);
if (!sceneResources) {
logger.warn(
'Can\'t load resource for unknown scene: "' + firstSceneName + '".'
);
return;
}
let loadedCount = 0;
const resourceNames = [
...this._globalResources,
...firstSceneState.resourceNames,
];
const resources = [...this._globalResources, ...sceneResources.values()];
await processAndRetryIfNeededWithPromisePool(
resourceNames,
resources,
maxForegroundConcurrency,
maxAttempt,
async (resourceName) => {
@@ -315,11 +304,11 @@ namespace gdjs {
await this._loadResource(resource);
await this._processResource(resource);
loadedCount++;
onProgress(loadedCount, resourceNames.length);
onProgress(loadedCount, resources.length);
}
);
firstSceneState.status = 'ready';
this._setSceneAssetsLoaded(firstSceneName);
this._setSceneAssetsReady(firstSceneName);
}
/**
@@ -329,32 +318,17 @@ namespace gdjs {
* scenes.
*/
async loadAllSceneInBackground(): Promise<void> {
if (this.currentLoadingSceneName) {
return;
}
debugLogger.log('Loading all scene resources, in background.');
while (this._sceneToLoadQueue.length > 0) {
debugLogger.log(
`Still resources of ${this._sceneToLoadQueue.length} scene(s) to load: ${this._sceneToLoadQueue.map((task) => task.sceneName).join(', ')}`
);
const task = this._sceneToLoadQueue[this._sceneToLoadQueue.length - 1];
if (task === undefined) {
continue;
}
this.currentLoadingSceneName = task.sceneName;
if (!this.areSceneAssetsLoaded(task.sceneName)) {
debugLogger.log(
`Loading (but not processing) resources for scene ${task.sceneName}.`
);
await this._doLoadSceneResources(
task.sceneName,
async (count, total) => task.onProgress(count, total)
);
debugLogger.log(
`Done loading (but not processing) resources for scene ${task.sceneName}.`
);
// A scene may have been moved last while awaiting resources to be
// downloaded (see _prioritizeScene).
this._sceneToLoadQueue.splice(
@@ -366,7 +340,6 @@ namespace gdjs {
this._sceneToLoadQueue.pop();
}
}
debugLogger.log(`Scene resources loading finished.`);
this.currentLoadingSceneName = '';
}
@@ -374,17 +347,16 @@ namespace gdjs {
sceneName: string,
onProgress?: (count: number, total: number) => Promise<void>
): Promise<void> {
const sceneState = this._sceneLoadingStates.get(sceneName);
if (!sceneState) {
const sceneResources = this._sceneResources.get(sceneName);
if (!sceneResources) {
logger.warn(
'Can\'t load resource for unknown scene: "' + sceneName + '".'
);
return;
}
let loadedCount = 0;
await processAndRetryIfNeededWithPromisePool(
sceneState.resourceNames,
[...sceneResources.values()],
this._isLoadingInForeground
? maxForegroundConcurrency
: maxBackgroundConcurrency,
@@ -397,13 +369,11 @@ namespace gdjs {
}
await this._loadResource(resource);
loadedCount++;
this.currentSceneLoadingProgress =
loadedCount / sceneState.resourceNames.length;
onProgress &&
(await onProgress(loadedCount, sceneState.resourceNames.length));
this.currentSceneLoadingProgress = loadedCount / this._resources.size;
onProgress && (await onProgress(loadedCount, this._resources.size));
}
);
sceneState.status = 'loaded';
this._setSceneAssetsLoaded(sceneName);
}
private async _loadResource(resource: ResourceData): Promise<void> {
@@ -435,8 +405,8 @@ namespace gdjs {
}
await this.loadSceneResources(sceneName, onProgress);
const sceneState = this._sceneLoadingStates.get(sceneName);
if (!sceneState) {
const sceneResources = this._sceneResources.get(sceneName);
if (!sceneResources) {
logger.warn(
'Can\'t load resource for unknown scene: "' + sceneName + '".'
);
@@ -444,7 +414,7 @@ namespace gdjs {
}
let parsedCount = 0;
for (const resourceName of sceneState.resourceNames) {
for (const resourceName of sceneResources) {
const resource = this._resources.get(resourceName);
if (!resource) {
logger.warn('Unable to find resource "' + resourceName + '".');
@@ -452,10 +422,9 @@ namespace gdjs {
}
await this._processResource(resource);
parsedCount++;
onProgress &&
(await onProgress(parsedCount, sceneState.resourceNames.length));
onProgress && (await onProgress(parsedCount, sceneResources.length));
}
sceneState.status = 'ready';
this._setSceneAssetsReady(sceneName);
}
/**
@@ -469,25 +438,15 @@ namespace gdjs {
sceneName: string,
onProgress?: (count: number, total: number) => void
): Promise<void> {
debugLogger.log(
`Prioritization of loading of resources for scene ${sceneName} was requested.`
);
this._isLoadingInForeground = true;
const task = this._prioritizeScene(sceneName);
return new Promise<void>((resolve, reject) => {
if (!task) {
this._isLoadingInForeground = false;
debugLogger.log(
`Loading of resources for scene ${sceneName} was immediately resolved.`
);
resolve();
return;
}
task.registerCallback(() => {
debugLogger.log(
`Loading of resources for scene ${sceneName} just finished.`
);
this._isLoadingInForeground = false;
resolve();
}, onProgress);
@@ -504,51 +463,6 @@ namespace gdjs {
}
}
/**
* To be called when a scene is unloaded.
*/
unloadSceneResources({
unloadedSceneName,
newSceneName,
}: {
unloadedSceneName: string;
newSceneName: string | null;
}): void {
if (!unloadedSceneName) return;
debugLogger.log(
`Unloading of resources for scene ${unloadedSceneName} was requested.`
);
const sceneUniqueResourcesByKindMap =
this._getResourcesByKindOnlyUsedInUnloadedScene({
unloadedSceneName,
newSceneName,
});
for (const [kindResourceManager, resourceManager] of this
._resourceManagersMap) {
const resources =
sceneUniqueResourcesByKindMap.get(kindResourceManager);
if (resources) {
debugLogger.log(
`Unloading of resources of kind ${kindResourceManager} for scene ${unloadedSceneName}: `,
resources.map((resource) => resource.name).join(', ')
);
resourceManager.unloadResourcesList(resources);
}
}
debugLogger.log(
`Unloading of resources for scene ${unloadedSceneName} finished.`
);
const sceneState = this._sceneLoadingStates.get(unloadedSceneName);
if (sceneState) {
sceneState.status = 'not-loaded';
}
// TODO: mark the scene as unloaded so it's not automatically loaded again eagerly.
}
/**
* Put a given scene at the end of the queue.
*
@@ -556,41 +470,16 @@ namespace gdjs {
* this scene will be the next to be loaded.
*/
private _prioritizeScene(sceneName: string): SceneLoadingTask | null {
const sceneState = this._sceneLoadingStates.get(sceneName);
if (!sceneState) return null;
if (sceneState.status === 'loaded' || sceneState.status === 'ready') {
debugLogger.log(
`Scene ${sceneName} is already loaded. Skipping prioritization.`
);
// The scene is already loaded, nothing to do.
return null;
}
// The scene is not loaded: either prioritize it or add it to the loading queue.
const taskIndex = this._sceneToLoadQueue.findIndex(
(task) => task.sceneName === sceneName
);
let task: SceneLoadingTask;
if (taskIndex !== -1) {
// There is already a task for this scene in the queue.
// Move it so that it's loaded first.
task = this._sceneToLoadQueue[taskIndex];
this._sceneToLoadQueue.splice(taskIndex, 1);
this._sceneToLoadQueue.push(task);
} else {
// There is no task for this scene in the queue.
// It might be because the scene was unloaded or never loaded.
// In this case, we need to add a new task to the queue.
task = new SceneLoadingTask(sceneName);
this._sceneToLoadQueue.push(task);
if (taskIndex < 0) {
// The scene is already loaded.
return null;
}
// Re-start the loading process in the background. While at the beginning of the game
// it's not needed because already launched, a scene might be unloaded. This means
// that we then need to relaunch the loading process.
this.loadAllSceneInBackground();
const task = this._sceneToLoadQueue[taskIndex];
this._sceneToLoadQueue.splice(taskIndex, 1);
this._sceneToLoadQueue.push(task);
return task;
}
@@ -622,10 +511,7 @@ namespace gdjs {
* (but maybe not parsed).
*/
areSceneAssetsLoaded(sceneName: string): boolean {
const sceneState = this._sceneLoadingStates.get(sceneName);
if (!sceneState) return false;
return sceneState.status === 'loaded' || sceneState.status === 'ready';
return !this._sceneNamesToLoad.has(sceneName);
}
/**
@@ -633,10 +519,15 @@ namespace gdjs {
* parsed.
*/
areSceneAssetsReady(sceneName: string): boolean {
const sceneState = this._sceneLoadingStates.get(sceneName);
if (!sceneState) return false;
return !this._sceneNamesToMakeReady.has(sceneName);
}
return sceneState.status === 'ready';
private _setSceneAssetsLoaded(sceneName: string): void {
this._sceneNamesToLoad.delete(sceneName);
}
private _setSceneAssetsReady(sceneName: string): void {
this._sceneNamesToMakeReady.delete(sceneName);
}
getResource(resourceName: string): ResourceData | null {
@@ -745,70 +636,6 @@ namespace gdjs {
getSpineAtlasManager(): gdjs.SpineAtlasManager | null {
return this._spineAtlasManager;
}
injectMockResourceManagerForTesting(
resourceKind: ResourceKind,
resourceManager: ResourceManager
) {
this._resourceManagersMap.set(resourceKind, resourceManager);
}
/**
* Get the map of resources that are only used in the scene that is being unloaded,
* and that are not used in any other loaded scene (or the scene that is coming next).
*/
private _getResourcesByKindOnlyUsedInUnloadedScene({
unloadedSceneName,
newSceneName,
}: {
unloadedSceneName: string;
newSceneName: string | null;
}): Map<ResourceKind, ResourceData[]> {
const unloadedSceneState =
this._sceneLoadingStates.get(unloadedSceneName);
if (!unloadedSceneState) {
return new Map<ResourceKind, ResourceData[]>();
}
// Construct the set of all resources to unload. These are the resources
// used in the scene that is being unloaded minus all the resources used
// by the other scenes that are loaded (and the possible scene that is coming next).
const resourceNamesToUnload = new Set<string>(
unloadedSceneState.resourceNames
);
for (const [
sceneName,
sceneState,
] of this._sceneLoadingStates.entries()) {
if (sceneName === unloadedSceneName) continue;
if (
sceneName === newSceneName ||
sceneState.status === 'loaded' ||
sceneState.status === 'ready'
) {
sceneState.resourceNames.forEach((resourceName) => {
resourceNamesToUnload.delete(resourceName);
});
}
}
const result = new Map<ResourceKind, ResourceData[]>();
resourceNamesToUnload.forEach((resourceName) => {
const resourceData = this._resources.get(resourceName);
if (!resourceData) return;
const kind = resourceData.kind;
const resources = result.get(kind);
if (resources) {
resources.push(resourceData);
} else {
result.set(kind, [resourceData]);
}
});
return result;
}
}
type PromiseError<T> = { item: T; error: Error };

View File

@@ -35,15 +35,5 @@ namespace gdjs {
* Using the manager after calling this method is undefined behavior.
*/
dispose(): void;
/**
* Should clear all specified resources data and anything stored by this manager
* for these resources.
*
* Usually called when scene resoures are unloaded.
*
* @param resourcesList The list of specific resources that need to be clear
*/
unloadResourcesList(resourcesList: ResourceData[]): void;
}
}

View File

@@ -811,8 +811,6 @@ namespace gdjs {
this._objectsCtor = new Hashtable();
this._allInstancesList = [];
this._instancesRemoved = [];
this._layersCameraCoordinates = {};
this._initialBehaviorSharedData = new Hashtable();
}
}
}

View File

@@ -116,9 +116,6 @@ namespace gdjs {
}
}
getRuntimeLayer(): gdjs.RuntimeLayer {
return this;
}
getRenderer(): gdjs.LayerRenderer {
return this._renderer;
}

View File

@@ -222,9 +222,7 @@ namespace gdjs {
kind: 'fatal',
message:
'Unexpected error happened while hot-reloading: ' +
error.message +
'\n' +
error.stack,
error.message,
});
}
})
@@ -474,24 +472,13 @@ namespace gdjs {
newExternalLayoutData.associatedLayout
);
const oldObjectDataList =
HotReloader.resolveCustomObjectConfigurations(
oldProjectData,
oldLayoutData ? oldLayoutData.objects : []
);
const newObjectDataList =
HotReloader.resolveCustomObjectConfigurations(
newProjectData,
newLayoutData ? newLayoutData.objects : []
);
sceneStack._stack.forEach((runtimeScene) => {
this._hotReloadRuntimeSceneInstances(
oldProjectData,
newProjectData,
changedRuntimeBehaviors,
oldObjectDataList,
newObjectDataList,
oldLayoutData ? oldLayoutData.objects : [],
newLayoutData ? newLayoutData.objects : [],
oldExternalLayoutData.instances,
newExternalLayoutData.instances,
runtimeScene
@@ -738,6 +725,7 @@ namespace gdjs {
// scene (see `_hotReloadRuntimeInstanceContainer` call from
// `_hotReloadRuntimeSceneInstances`).
objects: mergedChildObjectDataList,
childrenContent: mergedChildObjectDataList,
};
return mergedObjectConfiguration;
});

View File

@@ -380,8 +380,11 @@ namespace gdjs {
.isMouseInsideCanvas();
};
const _cursorIsOnObject = function (obj: gdjs.RuntimeObject) {
return obj.cursorOnObject();
const _cursorIsOnObject = function (
obj: gdjs.RuntimeObject,
instanceContainer: gdjs.RuntimeInstanceContainer
) {
return obj.cursorOnObject(instanceContainer);
};
export const cursorOnObject = function (
@@ -394,7 +397,7 @@ namespace gdjs {
_cursorIsOnObject,
objectsLists,
inverted,
null
instanceContainer
);
};

View File

@@ -362,7 +362,8 @@ namespace gdjs {
if (objectsLists.items.hasOwnProperty(name)) {
const allObjects = objectsContext.getObjects(name);
const objectsList = objectsLists.items[name];
gdjs.copyArray(allObjects, objectsList);
objectsList.length = 0;
objectsList.push.apply(objectsList, allObjects);
}
}
return true;

View File

@@ -205,28 +205,6 @@ namespace gdjs {
this._loadedFontFamily.clear();
this._loadedFontFamilySet.clear();
}
/**
* Unload the specified list of resources:
* this clears the caches of loaded font families.
*
* Usually called when scene resoures are unloaded.
*
* @param resourcesList The list of specific resources
*/
unloadResourcesList(resourcesList: ResourceData[]): void {
resourcesList.forEach((resourceData) => {
const resource = this._loadedFontFamily.get(resourceData);
if (resource) {
this._loadedFontFamily.delete(resourceData);
}
const fontName = this._getFontFamilyFromFilename(resourceData);
if (fontName) {
this._loadedFontFamilySet.delete(fontName);
}
});
}
}
//Register the class to let the engine use it.

View File

@@ -939,28 +939,6 @@ namespace gdjs {
dispose(): void {
this.unloadAll();
}
/**
* Unload the specified list of resources:
* this unloads all audio from the specified resources from memory.
*
* Usually called when scene resoures are unloaded.
*
* @param resourcesList The list of specific resources
*/
unloadResourcesList(resourcesList: ResourceData[]): void {
resourcesList.forEach((resourceData) => {
const musicRes = this._loadedMusics.get(resourceData);
if (musicRes) {
this.unloadAudio(resourceData.name, true);
}
const soundRes = this._loadedSounds.get(resourceData);
if (soundRes) {
this.unloadAudio(resourceData.name, false);
}
});
}
}
// Register the class to let the engine use it.

View File

@@ -208,26 +208,5 @@ namespace gdjs {
this._loadedJsons.clear();
this._callbacks.clear();
}
/**
* Unload the specified list of resources:
* this clears the JSONs loaded in this manager.
*
* Usually called when scene resoures are unloaded.
* @param resourcesList The list of specific resources
*/
unloadResourcesList(resourcesList: ResourceData[]): void {
resourcesList.forEach((resourceData) => {
const loadedJson = this._loadedJsons.get(resourceData);
if (loadedJson) {
this._loadedJsons.delete(resourceData);
}
const callback = this._callbacks.get(resourceData);
if (callback) {
this._callbacks.delete(resourceData);
}
});
}
}
}

View File

@@ -66,7 +66,6 @@ namespace gdjs {
*/
export class Logger {
private readonly group: string;
private enabled: boolean = true;
/**
* Create a new logger with the given group name.
@@ -77,30 +76,21 @@ namespace gdjs {
}
log(...messages: any[]): void {
if (!this.enabled) return;
loggerOutput.log(this.group, objectsToString(messages), 'info');
}
info(...messages: any[]): void {
if (!this.enabled) return;
loggerOutput.log(this.group, objectsToString(messages), 'info');
}
warn(...messages: any[]): void {
if (!this.enabled) return;
loggerOutput.log(this.group, objectsToString(messages), 'warning');
}
error(...messages: any[]): void {
if (!this.enabled) return;
loggerOutput.log(this.group, objectsToString(messages), 'error');
}
enable(enabled: boolean): gdjs.Logger {
this.enabled = enabled;
return this;
}
/**
* Give access to the console output used by default by the logger.
* This can be useful to restore the default log method if you overrode it

View File

@@ -50,7 +50,12 @@ namespace gdjs {
) {
this._object = object;
this._isContainerDirty = true;
this._pixiContainer.removeChildren();
const layer = parent.getLayer('');
if (layer) {
layer
.getRenderer()
.addRendererObject(this._pixiContainer, object.getZOrder());
}
}
getRendererObject() {

View File

@@ -307,34 +307,6 @@ namespace gdjs {
this._pixiBitmapFontsToUninstall.length = 0;
this._loadedFontsData.clear();
}
/**
* Unload the specified list of resources:
* this uninstalls fonts from memory and clear cache of loaded fonts.
*
* Usually called when scene resoures are unloaded.
*
* @param resourcesList The list of specific resources
*/
unloadResourcesList(resourcesList: ResourceData[]): void {
resourcesList.forEach((resourceData) => {
const loadedFont = this._loadedFontsData.get(resourceData);
if (loadedFont) {
this._loadedFontsData.delete(resourceData);
}
for (const bitmapFontInstallKey in this._pixiBitmapFontsInUse) {
if (bitmapFontInstallKey.endsWith(resourceData.file))
PIXI.BitmapFont.uninstall(bitmapFontInstallKey);
}
for (const bitmapFontInstallKey of this._pixiBitmapFontsToUninstall) {
if (bitmapFontInstallKey.endsWith(resourceData.file))
PIXI.BitmapFont.uninstall(bitmapFontInstallKey);
}
});
}
}
// Register the class to let the engine use it.

View File

@@ -17,7 +17,6 @@ namespace gdjs {
getName: () => string;
getRendererObject: () => RendererObjectInterface | null | undefined;
get3DRendererObject: () => THREE.Object3D | null | undefined;
getRuntimeLayer?: () => gdjs.RuntimeLayer;
}
/**

View File

@@ -519,37 +519,6 @@ namespace gdjs {
}
this._scaledTextures.clear();
}
/**
* Unload the specified list of resources:
* this clears the cache of loaded textures associated to these resources.
*
* Usually called when scene resoures are unloaded.
*
* @param resourcesList The list of specific resources
*/
unloadResourcesList(resourcesList: ResourceData[]): void {
resourcesList.forEach((resourceData) => {
const resourceName = resourceData.name;
const resource = this._loadedTextures.get(resourceData);
if (resource) {
resource.destroy(true);
this._loadedTextures.delete(resourceData);
}
const threeTexture = this._loadedThreeTextures.get(resourceName);
if (threeTexture) {
threeTexture.dispose();
this._loadedThreeTextures.remove(resourceName);
}
const threeMaterials = this._loadedThreeMaterials.get(resourceName);
if (threeMaterials) {
threeMaterials.dispose();
this._loadedThreeMaterials.remove(resourceName);
}
});
}
}
//Register the class to let the engine use it.

View File

@@ -97,8 +97,6 @@ namespace gdjs {
!gdjs.evtTools.common.isMobile()),
preserveDrawingBuffer: true, // Keep to true to allow screenshots.
});
this._threeRenderer.shadowMap.enabled = true;
this._threeRenderer.shadowMap.type = THREE.PCFSoftShadowMap;
this._threeRenderer.useLegacyLights = true;
this._threeRenderer.autoClear = false;
this._threeRenderer.setSize(

View File

@@ -184,9 +184,6 @@ namespace gdjs {
*/
_embeddedResourcesMappings: Map<string, Record<string, string>>;
_sceneResourcesPreloading: 'at-startup' | 'never';
_sceneResourcesUnloading: 'at-scene-exit' | 'never';
/**
* Optional client to connect to a debugger server.
*/
@@ -226,11 +223,6 @@ namespace gdjs {
this._data = data;
this._updateSceneAndExtensionsData();
this._sceneResourcesPreloading =
this._data.properties.sceneResourcesPreloading || 'at-startup';
this._sceneResourcesUnloading =
this._data.properties.sceneResourcesUnloading || 'never';
this._resourcesLoader = new gdjs.ResourceLoader(
this,
data.resources.resources,
@@ -253,7 +245,6 @@ namespace gdjs {
this._antialiasingMode = this._data.properties.antialiasingMode;
this._isAntialisingEnabledOnMobile =
this._data.properties.antialisingEnabledOnMobile;
this._renderer = new gdjs.RuntimeGameRenderer(
this,
this._options.forceFullscreen || false
@@ -372,14 +363,6 @@ namespace gdjs {
return this._variablesByExtensionName.get(extensionName) || null;
}
/**
* Get the gdjs.ResourceLoader of the RuntimeGame.
* @return The resource loader.
*/
getResourceLoader(): gdjs.ResourceLoader {
return this._resourcesLoader;
}
/**
* Get the gdjs.SoundManager of the RuntimeGame.
* @return The sound manager.
@@ -781,22 +764,6 @@ namespace gdjs {
return this._resourcesLoader.areSceneAssetsReady(sceneName);
}
/**
* Returns the scene resources preloading mode.
* It can be overriden by each scene.
*/
getSceneResourcesPreloading(): 'at-startup' | 'never' {
return this._sceneResourcesPreloading;
}
/**
* Returns the scene resources unloading mode.
* It can be overriden by each scene.
*/
getSceneResourcesUnloading(): 'at-scene-exit' | 'never' {
return this._sceneResourcesUnloading;
}
/**
* Load all assets needed to display the 1st scene, displaying progress in
* renderer.

View File

@@ -292,7 +292,7 @@ namespace gdjs {
/**
* Called to reset the object to its default state. This is used for objects that are
* "recycled": they are dismissed (at which point `onDeletedFromScene` is called) but still
* "recycled": they are dismissed (at which point `onDestroyFromScene` is called) but still
* stored in a cache to be reused next time an object must be created. At this point,
* `reinitialize` will be called. The object must then work as if it was a newly constructed
* object.
@@ -484,8 +484,6 @@ namespace gdjs {
return {
x: this.x,
y: this.y,
w: this.getWidth(),
h: this.getHeight(),
zo: this.zOrder,
a: this.angle,
hid: this.hidden,
@@ -514,12 +512,6 @@ namespace gdjs {
if (networkSyncData.y !== undefined) {
this.setY(networkSyncData.y);
}
if (networkSyncData.w !== undefined) {
this.setWidth(networkSyncData.w);
}
if (networkSyncData.h !== undefined) {
this.setHeight(networkSyncData.h);
}
if (networkSyncData.zo !== undefined) {
this.setZOrder(networkSyncData.zo);
}
@@ -604,7 +596,7 @@ namespace gdjs {
/**
* Remove an object from a scene.
*
* Do not change/redefine this method. Instead, redefine the onDeletedFromScene method.
* Do not change/redefine this method. Instead, redefine the onDestroyFromScene method.
*/
deleteFromScene(): void {
if (this._livingOnScene) {
@@ -622,12 +614,9 @@ namespace gdjs {
}
/**
* Called when the object is deleted (because it is removed from a scene or
* the scene is being unloaded). The object is not actually destroyed and
* can still be used by events.
*
* If you redefine this function, **make sure to call the original method**
* (`super.onDeletedFromScene();`).
* 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);`).
*/
onDeletedFromScene(): void {
const theLayer = this._runtimeScene.getLayer(this.layer);
@@ -646,10 +635,6 @@ namespace gdjs {
this.clearEffects();
}
/**
* Called on deleted objects after all events has been executed for the
* current frame and the object can be safely destroyed.
*/
onDestroyed(): void {}
/**
@@ -2729,12 +2714,11 @@ namespace gdjs {
*
* @return true if the cursor, or any touch, is on the object.
*/
cursorOnObject(): boolean {
cursorOnObject(instanceContainer: gdjs.RuntimeInstanceContainer): boolean {
const workingPoint: FloatPoint = gdjs.staticArray(
RuntimeObject.prototype.cursorOnObject
) as FloatPoint;
workingPoint.length = 2;
const instanceContainer = this.getInstanceContainer();
const inputManager = instanceContainer.getGame().getInputManager();
const layer = instanceContainer.getLayer(this.layer);
const mousePos = layer.convertCoords(

View File

@@ -23,7 +23,6 @@ namespace gdjs {
_timeManager: TimeManager;
_gameStopRequested: boolean = false;
_requestedScene: string = '';
_resourcesUnloading: 'at-scene-exit' | 'never' | 'inherit' = 'inherit';
private _asyncTasksManager = new gdjs.AsyncTasksManager();
/** True if loadFromScene was called and the scene is being played. */
@@ -142,7 +141,6 @@ namespace gdjs {
this._runtimeGame.getRenderer().setWindowTitle(sceneData.title);
}
this._name = sceneData.name;
this._resourcesUnloading = sceneData.resourcesUnloading || 'inherit';
this.setBackgroundColor(sceneData.r, sceneData.v, sceneData.b);
//Load layers
@@ -308,7 +306,7 @@ namespace gdjs {
this.onGameResolutionResized();
}
override _destroy() {
_destroy() {
// It should not be necessary to reset these variables, but this help
// ensuring that all memory related to the RuntimeScene is released immediately.
super._destroy();
@@ -580,13 +578,6 @@ namespace gdjs {
return this._name;
}
/**
* Get the strategy to unload resources of this scene.
*/
getResourcesUnloading(): 'at-scene-exit' | 'never' | 'inherit' {
return this._resourcesUnloading;
}
/**
* Create an identifier for a new object of the scene.
*/

View File

@@ -63,14 +63,10 @@ namespace gdjs {
this.pop();
} else if (request === gdjs.SceneChangeRequest.PUSH_SCENE) {
this.push(currentScene.getRequestedScene());
} else if (
request === gdjs.SceneChangeRequest.REPLACE_SCENE ||
request === gdjs.SceneChangeRequest.CLEAR_SCENES
) {
this.replace(
currentScene.getRequestedScene(),
request === gdjs.SceneChangeRequest.CLEAR_SCENES
);
} else if (request === gdjs.SceneChangeRequest.REPLACE_SCENE) {
this.replace(currentScene.getRequestedScene());
} else if (request === gdjs.SceneChangeRequest.CLEAR_SCENES) {
this.replace(currentScene.getRequestedScene(), true);
} else {
logger.error('Unrecognized change in scene stack: ' + request);
}
@@ -105,10 +101,7 @@ namespace gdjs {
if (!scene) {
return;
}
this._unloadSceneAndPossiblyResources({
scene,
newSceneName: null,
});
scene.unloadScene();
}
// Tell the new current scene it's being resumed
@@ -147,7 +140,6 @@ namespace gdjs {
this._loadNewScene(newSceneName);
this._isNextLayoutLoading = false;
});
return null;
}
@@ -194,7 +186,7 @@ namespace gdjs {
while (this._stack.length !== 0) {
let scene = this._stack.pop();
if (scene) {
this._unloadSceneAndPossiblyResources({ scene, newSceneName });
scene.unloadScene();
}
}
} else {
@@ -202,7 +194,7 @@ namespace gdjs {
if (this._stack.length !== 0) {
let scene = this._stack.pop();
if (scene) {
this._unloadSceneAndPossiblyResources({ scene, newSceneName });
scene.unloadScene();
}
}
}
@@ -380,52 +372,14 @@ namespace gdjs {
* Unload all the scenes and clear the stack.
*/
dispose(): void {
while (this._stack.length > 0) {
const scene = this._stack.pop();
if (scene) {
this._unloadSceneAndPossiblyResources({
scene,
newSceneName: null,
});
}
for (const item of this._stack) {
item.unloadScene();
}
this._stack.length = 0;
this._wasDisposed = true;
}
private _unloadSceneAndPossiblyResources({
scene,
newSceneName,
}: {
scene: gdjs.RuntimeScene;
newSceneName: string | null;
}): void {
const unloadedSceneName = scene.getName();
const resourcesUnloading = scene.getResourcesUnloading();
const resolvedResourcesUnloading =
resourcesUnloading === 'inherit'
? this._runtimeGame.getSceneResourcesUnloading()
: resourcesUnloading;
const shouldUnloadResources =
resolvedResourcesUnloading === 'at-scene-exit' &&
// Unload resources only if it's the last scene with this name in the stack.
newSceneName !== scene.getName() &&
this._stack.every((scene) => scene.getName() !== unloadedSceneName);
scene.unloadScene();
// After this point, `scene` is no longer valid and should not be used anymore.
// It was "disposed".
if (shouldUnloadResources) {
this._runtimeGame.getResourceLoader().unloadSceneResources({
unloadedSceneName,
newSceneName,
});
}
}
private _throwIfDisposed(): void {
if (this._wasDisposed) {
throw 'The scene stack has been disposed and should not be used anymore.';

View File

@@ -52,10 +52,6 @@ declare type BasicObjectNetworkSyncData = {
y: number;
/** The position of the instance on the Z axis. Defined only for 3D games */
z?: number;
/** The width of the instance */
w: number;
/** The height of the instance */
h: number;
/** Z order of the instance */
zo: number;
/** The angle of the instance. */
@@ -173,8 +169,6 @@ declare interface LayoutData extends InstanceContainerData {
title: string;
behaviorsSharedData: BehaviorSharedData[];
usedResources: ResourceReference[];
resourcesPreloading?: 'at-startup' | 'never' | 'inherit';
resourcesUnloading?: 'at-scene-exit' | 'never' | 'inherit';
}
declare interface LayoutNetworkSyncData {
@@ -235,7 +229,7 @@ declare interface EventsBasedObjectVariantData extends InstanceContainerData {
/**
* A value shared by every object instances.
*
* @see gdjs.CustomRuntimeObjectInstanceContainer._initialInnerArea
* @see gdjs.CustomRuntimeObjectInstanceContainer._originalInnerArea
**/
_initialInnerArea: {
min: [float, float, float];
@@ -376,8 +370,6 @@ declare interface ProjectPropertiesData {
extensionProperties: Array<ExtensionProperty>;
useDeprecatedZeroAsDefaultZOrder?: boolean;
projectUuid?: string;
sceneResourcesPreloading?: 'at-startup' | 'never';
sceneResourcesUnloading?: 'at-scene-exit' | 'never';
}
declare interface ExtensionProperty {
@@ -445,5 +437,4 @@ declare type ResourceKind =
| 'bitmapFont'
| 'model3D'
| 'atlas'
| 'spine'
| 'fake-resource-kind-for-testing-only';
| 'spine';

View File

@@ -225,7 +225,7 @@ const identifyClassNames = (code) => {
.replace(/( hide\w*\(.*\))(: any)? {/g, '$1: void {')
.replace(/( reset\w*\(.*\))(: any)? {/g, '$1: void {')
.replace(/( deleteFromScene\w*\(.*\))(: any)? {/g, '$1: void {')
.replace(/( onDeletedFromScene\w*\(.*\))(: any)? {/g, '$1: void {')
.replace(/( onDestroyFromScene\w*\(.*\))(: any)? {/g, '$1: void {')
.replace(/( enable\w*\(.*\))(: any)? {/g, '$1: void {')
// Members:
.replace(/(\w*): any = (\d)/g, '$1: number = $2')

Binary file not shown.

Before

Width:  |  Height:  |  Size: 277 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 202 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 654 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 926 B

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