mirror of
https://github.com/4ian/GDevelop.git
synced 2025-10-15 10:19:04 +00:00
Compare commits
29 Commits
v5.3.195
...
object-sle
Author | SHA1 | Date | |
---|---|---|---|
![]() |
327165482a | ||
![]() |
92d7ddf5f7 | ||
![]() |
d153378351 | ||
![]() |
5274f68432 | ||
![]() |
329d899b47 | ||
![]() |
72603a4c0e | ||
![]() |
38e187b110 | ||
![]() |
633071560d | ||
![]() |
66f12b848c | ||
![]() |
9d1233bb09 | ||
![]() |
daa1f305ee | ||
![]() |
0755493f94 | ||
![]() |
8c7331fc44 | ||
![]() |
0f8fcacf98 | ||
![]() |
23a39f1e2c | ||
![]() |
b7787d29f1 | ||
![]() |
ad0f1f163f | ||
![]() |
e34aedb15c | ||
![]() |
27f16a3db0 | ||
![]() |
6e6ddb9edd | ||
![]() |
fbf4baebe9 | ||
![]() |
2cdfc889a8 | ||
![]() |
7f7a13dee8 | ||
![]() |
e45ba9465d | ||
![]() |
cbae925680 | ||
![]() |
852fdd77dd | ||
![]() |
8afea382d4 | ||
![]() |
c3c0c1961b | ||
![]() |
40c5012a0e |
4
.github/workflows/update-translations.yml
vendored
4
.github/workflows/update-translations.yml
vendored
@@ -19,7 +19,7 @@ jobs:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 20
|
||||
node-version: 16
|
||||
cache: "npm"
|
||||
cache-dependency-path: "newIDE/app/package-lock.json"
|
||||
|
||||
@@ -58,7 +58,7 @@ jobs:
|
||||
working-directory: newIDE/app
|
||||
|
||||
- name: Create a Pull Request with the changes
|
||||
uses: peter-evans/create-pull-request@v6
|
||||
uses: peter-evans/create-pull-request@v5
|
||||
with:
|
||||
commit-message: Update translations [skip ci]
|
||||
branch: chore/update-translations
|
||||
|
@@ -56,7 +56,6 @@ blocks:
|
||||
- name: GDJS typing and documentation generation
|
||||
commands:
|
||||
- checkout
|
||||
- cache restore newIDE-app-node_modules-$SEMAPHORE_GIT_BRANCH-revision-$(checksum newIDE/app/package-lock.json)
|
||||
- cache restore GDJS-node_modules-$SEMAPHORE_GIT_BRANCH-revision-$(checksum GDJS/package-lock.json)
|
||||
- cache restore GDJS-tests-node_modules-$SEMAPHORE_GIT_BRANCH-revision-$(checksum GDJS/tests/package-lock.json)
|
||||
- cd GDJS
|
||||
|
1
.vscode/tasks.json
vendored
1
.vscode/tasks.json
vendored
@@ -8,7 +8,6 @@
|
||||
"group": "build",
|
||||
"label": "Start development server",
|
||||
"detail": "Starts the GDevelop development server.",
|
||||
"options": { "env": { "NODE_OPTIONS": "--max-old-space-size=8192" } },
|
||||
"problemMatcher": [
|
||||
{
|
||||
"owner": "cra",
|
||||
|
@@ -103,6 +103,11 @@ void EventsCodeGenerationContext::EmptyObjectsListNeeded(
|
||||
depthOfLastUse[objectName] = GetContextDepth();
|
||||
}
|
||||
|
||||
void EventsCodeGenerationContext::AddUsedObjectsMapNames(
|
||||
const gd::String& objectMapName) {
|
||||
usedObjectsMapNames.insert(objectMapName);
|
||||
}
|
||||
|
||||
std::set<gd::String> EventsCodeGenerationContext::GetAllObjectsToBeDeclared()
|
||||
const {
|
||||
std::set<gd::String> allObjectListsToBeDeclared(
|
||||
|
@@ -175,6 +175,12 @@ class GD_CORE_API EventsCodeGenerationContext {
|
||||
return emptyObjectsListsToBeDeclared;
|
||||
};
|
||||
|
||||
const std::set<gd::String>& GetUsedObjectsMapNames() const {
|
||||
return usedObjectsMapNames;
|
||||
};
|
||||
|
||||
void AddUsedObjectsMapNames(const gd::String& objectMapName);
|
||||
|
||||
/**
|
||||
* Return the objects lists which are already declared and can be used in the
|
||||
* current context without declaration.
|
||||
@@ -297,6 +303,8 @@ class GD_CORE_API EventsCodeGenerationContext {
|
||||
///< necessary objects can be
|
||||
///< backed up.
|
||||
|
||||
std::set<gd::String> usedObjectsMapNames;
|
||||
|
||||
std::map<gd::String, unsigned int>
|
||||
depthOfLastUse; ///< The context depth when an object was last used.
|
||||
gd::String
|
||||
|
@@ -408,6 +408,25 @@ gd::String EventsCodeGenerator::GenerateConditionCode(
|
||||
arguments, instrInfos, returnBoolean, condition.IsInverted(), context);
|
||||
}
|
||||
|
||||
// Flag the ObjectsLists as modified.
|
||||
gd::ParameterMetadataTools::IterateOverParameters(
|
||||
condition.GetParameters(), instrInfos.parameters,
|
||||
[this, &context,
|
||||
&conditionCode](const gd::ParameterMetadata ¶meterMetadata,
|
||||
const gd::Expression ¶meterValue,
|
||||
const gd::String &lastObjectName) {
|
||||
// objectListOrEmptyWithoutPicking are only used by SceneInstancesCount
|
||||
// and PickedInstancesCount conditions. They are not pass for one
|
||||
// condition to another.
|
||||
if (parameterMetadata.GetType() == "objectList" ||
|
||||
parameterMetadata.GetType() == "objectListOrEmptyIfJustDeclared") {
|
||||
// TODO FIXME What about groups using the object?
|
||||
conditionCode +=
|
||||
GetObjectMapName(parameterValue.GetPlainString(), context) +
|
||||
".isPicked = true;\n";
|
||||
}
|
||||
});
|
||||
|
||||
return conditionCode;
|
||||
}
|
||||
|
||||
@@ -714,8 +733,6 @@ gd::String EventsCodeGenerator::GenerateParameterCodes(
|
||||
metadata.GetType() == "tilesetResource" ||
|
||||
metadata.GetType() == "videoResource" ||
|
||||
metadata.GetType() == "model3DResource" ||
|
||||
metadata.GetType() == "atlasResource" ||
|
||||
metadata.GetType() == "spineResource" ||
|
||||
// Deprecated, old parameter names:
|
||||
metadata.GetType() == "password" || metadata.GetType() == "musicfile" ||
|
||||
metadata.GetType() == "soundfile" || metadata.GetType() == "police") {
|
||||
|
@@ -585,6 +585,12 @@ class GD_CORE_API EventsCodeGenerator {
|
||||
return "fakeObjectListOf_" + objectName;
|
||||
}
|
||||
|
||||
// TODO Documentation
|
||||
virtual gd::String GetObjectMapName(const gd::String &objectName,
|
||||
gd::EventsCodeGenerationContext &context) {
|
||||
return "fakeObjectListOf_" + objectName;
|
||||
}
|
||||
|
||||
virtual gd::String GeneratePropertyGetter(
|
||||
const gd::PropertiesContainer& propertiesContainer,
|
||||
const gd::NamedPropertyDescriptor& property,
|
||||
|
@@ -277,11 +277,8 @@ class GD_CORE_API ExpressionParser2 {
|
||||
|
||||
std::unique_ptr<VariableNode> Variable(const gd::String &name, gd::ExpressionParserLocation nameLocation) {
|
||||
auto variable = gd::make_unique<VariableNode>(name);
|
||||
|
||||
if (CheckIfChar(IsOpeningSquareBracket) || CheckIfChar(IsDot)) {
|
||||
variable->child = VariableAccessorOrVariableBracketAccessor();
|
||||
variable->child->parent = variable.get();
|
||||
}
|
||||
variable->child = VariableAccessorOrVariableBracketAccessor();
|
||||
variable->child->parent = variable.get();
|
||||
|
||||
variable->location = ExpressionParserLocation(
|
||||
nameLocation.GetStartPosition(), GetCurrentPosition());
|
||||
@@ -305,12 +302,8 @@ class GD_CORE_API ExpressionParser2 {
|
||||
"bracket for each opening bracket."));
|
||||
}
|
||||
SkipIfChar(IsClosingSquareBracket);
|
||||
|
||||
SkipAllWhitespaces();
|
||||
if (CheckIfChar(IsOpeningSquareBracket) || CheckIfChar(IsDot)) {
|
||||
child->child = VariableAccessorOrVariableBracketAccessor();
|
||||
child->child->parent = child.get();
|
||||
}
|
||||
child->child = VariableAccessorOrVariableBracketAccessor();
|
||||
child->child->parent = child.get();
|
||||
child->location =
|
||||
ExpressionParserLocation(childStartPosition, GetCurrentPosition());
|
||||
|
||||
@@ -322,15 +315,8 @@ class GD_CORE_API ExpressionParser2 {
|
||||
auto identifierAndLocation = ReadIdentifierName(/*allowDeprecatedSpacesInName=*/ false);
|
||||
auto child =
|
||||
gd::make_unique<VariableAccessorNode>(identifierAndLocation.name);
|
||||
if (identifierAndLocation.name.empty()) {
|
||||
child->diagnostic = RaiseSyntaxError(_("A name should be entered after the dot."));
|
||||
}
|
||||
|
||||
SkipAllWhitespaces();
|
||||
if (CheckIfChar(IsOpeningSquareBracket) || CheckIfChar(IsDot)) {
|
||||
child->child = VariableAccessorOrVariableBracketAccessor();
|
||||
child->child->parent = child.get();
|
||||
}
|
||||
child->child = VariableAccessorOrVariableBracketAccessor();
|
||||
child->child->parent = child.get();
|
||||
child->nameLocation = identifierAndLocation.location;
|
||||
child->dotLocation = dotLocation;
|
||||
child->location =
|
||||
@@ -339,11 +325,7 @@ class GD_CORE_API ExpressionParser2 {
|
||||
return std::move(child);
|
||||
}
|
||||
|
||||
// Should never happen, unless a node called this function without checking if the current character
|
||||
// was a dot or an opening bracket - this means there is an error in the grammar.
|
||||
auto unrecognisedNode = gd::make_unique<VariableAccessorOrVariableBracketAccessorNode>();
|
||||
unrecognisedNode->diagnostic = RaiseSyntaxError(_("A dot or bracket was expected here."));
|
||||
return std::move(unrecognisedNode);
|
||||
return std::move(gd::make_unique<VariableAccessorOrVariableBracketAccessorNode>());
|
||||
}
|
||||
|
||||
std::unique_ptr<FunctionCallNode> FreeFunction(
|
||||
@@ -379,24 +361,18 @@ class GD_CORE_API ExpressionParser2 {
|
||||
const auto &childIdentifierNameLocation =
|
||||
childIdentifierAndLocation.location;
|
||||
|
||||
std::unique_ptr<gd::ExpressionParserError> emptyNameError = childIdentifierName.empty() ?
|
||||
RaiseSyntaxError(_("A name should be entered after the dot.")) : nullptr;
|
||||
|
||||
SkipAllWhitespaces();
|
||||
|
||||
if (IsNamespaceSeparator()) {
|
||||
ExpressionParserLocation namespaceSeparatorLocation =
|
||||
SkipNamespaceSeparator();
|
||||
SkipAllWhitespaces();
|
||||
auto behaviorFunction = BehaviorFunction(parentIdentifier,
|
||||
return BehaviorFunction(parentIdentifier,
|
||||
childIdentifierName,
|
||||
parentIdentifierLocation,
|
||||
parentIdentifierDotLocation,
|
||||
childIdentifierNameLocation,
|
||||
namespaceSeparatorLocation);
|
||||
|
||||
if (emptyNameError) behaviorFunction->diagnostic = std::move(emptyNameError);
|
||||
return std::move(behaviorFunction);
|
||||
} else if (CheckIfChar(IsOpeningParenthesis)) {
|
||||
ExpressionParserLocation openingParenthesisLocation = SkipChar();
|
||||
|
||||
@@ -405,7 +381,7 @@ class GD_CORE_API ExpressionParser2 {
|
||||
childIdentifierName);
|
||||
auto parametersNode = Parameters(function.get(), parentIdentifier);
|
||||
function->parameters = std::move(parametersNode.parameters),
|
||||
function->diagnostic = emptyNameError ? std::move(emptyNameError) : std::move(parametersNode.diagnostic);
|
||||
function->diagnostic = std::move(parametersNode.diagnostic);
|
||||
|
||||
function->location = ExpressionParserLocation(
|
||||
parentIdentifierLocation.GetStartPosition(), GetCurrentPosition());
|
||||
@@ -418,8 +394,6 @@ class GD_CORE_API ExpressionParser2 {
|
||||
return std::move(function);
|
||||
} else if (CheckIfChar(IsDot) || CheckIfChar(IsOpeningSquareBracket)) {
|
||||
auto variable = gd::make_unique<VariableNode>(parentIdentifier);
|
||||
variable->diagnostic = std::move(emptyNameError);
|
||||
|
||||
auto child =
|
||||
gd::make_unique<VariableAccessorNode>(childIdentifierName);
|
||||
child->child = VariableAccessorOrVariableBracketAccessor();
|
||||
@@ -445,7 +419,6 @@ class GD_CORE_API ExpressionParser2 {
|
||||
node->identifierNameLocation = parentIdentifierLocation;
|
||||
node->identifierNameDotLocation = parentIdentifierDotLocation;
|
||||
node->childIdentifierNameLocation = childIdentifierNameLocation;
|
||||
node->diagnostic = std::move(emptyNameError);
|
||||
return std::move(node);
|
||||
}
|
||||
|
||||
|
@@ -8,7 +8,6 @@
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "GDCore/Events/Parsers/ExpressionParser2Node.h"
|
||||
#include "GDCore/Events/Parsers/ExpressionParser2NodeWorker.h"
|
||||
namespace gd {
|
||||
@@ -44,11 +43,6 @@ class GD_CORE_API ExpressionParser2NodePrinter
|
||||
*/
|
||||
const gd::String& GetOutput() { return output; };
|
||||
|
||||
static gd::String PrintStringLiteral(const gd::String& str) {
|
||||
return "\"" +
|
||||
str.FindAndReplace("\\", "\\\\").FindAndReplace("\"", "\\\"") + "\"";
|
||||
}
|
||||
|
||||
protected:
|
||||
void OnVisitSubExpressionNode(SubExpressionNode& node) override {
|
||||
output += "(";
|
||||
@@ -75,7 +69,10 @@ class GD_CORE_API ExpressionParser2NodePrinter
|
||||
}
|
||||
void OnVisitNumberNode(NumberNode& node) override { output += node.number; }
|
||||
void OnVisitTextNode(TextNode& node) override {
|
||||
output += PrintStringLiteral(node.text);
|
||||
output +=
|
||||
"\"" +
|
||||
node.text.FindAndReplace("\\", "\\\\").FindAndReplace("\"", "\\\"") +
|
||||
"\"";
|
||||
}
|
||||
void OnVisitVariableNode(VariableNode& node) override {
|
||||
output += node.name;
|
||||
@@ -100,8 +97,8 @@ class GD_CORE_API ExpressionParser2NodePrinter
|
||||
}
|
||||
void OnVisitObjectFunctionNameNode(ObjectFunctionNameNode& node) override {
|
||||
if (!node.behaviorFunctionName.empty()) {
|
||||
output += node.objectName + "." + node.objectFunctionOrBehaviorName +
|
||||
"::" + node.behaviorFunctionName;
|
||||
output +=
|
||||
node.objectName + "." + node.objectFunctionOrBehaviorName + "::" + node.behaviorFunctionName;
|
||||
} else {
|
||||
output += node.objectName + "." + node.objectFunctionOrBehaviorName;
|
||||
}
|
||||
|
@@ -1281,8 +1281,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
_("Enable an effect on the object"),
|
||||
_("Enable effect _PARAM1_ on _PARAM0_: _PARAM2_"),
|
||||
_("Effects"),
|
||||
"res/actions/effect_black.svg",
|
||||
"res/actions/effect_black.svg")
|
||||
"res/actions/effect24.png",
|
||||
"res/actions/effect.png")
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("objectEffectName", _("Effect name"))
|
||||
.AddParameter("yesorno", _("Enable?"))
|
||||
@@ -1297,8 +1297,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
"names) in the effects window."),
|
||||
_("Set _PARAM2_ to _PARAM3_ for effect _PARAM1_ of _PARAM0_"),
|
||||
_("Effects"),
|
||||
"res/actions/effect_black.svg",
|
||||
"res/actions/effect_black.svg")
|
||||
"res/actions/effect24.png",
|
||||
"res/actions/effect.png")
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("objectEffectName", _("Effect name"))
|
||||
.AddParameter("objectEffectParameterName", _("Property name"))
|
||||
@@ -1315,8 +1315,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
"names) in the effects window."),
|
||||
_("Set _PARAM2_ to _PARAM3_ for effect _PARAM1_ of _PARAM0_"),
|
||||
_("Effects"),
|
||||
"res/actions/effect_black.svg",
|
||||
"res/actions/effect_black.svg")
|
||||
"res/actions/effect24.png",
|
||||
"res/actions/effect.png")
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("objectEffectName", _("Effect name"))
|
||||
.AddParameter("objectEffectParameterName", _("Property name"))
|
||||
@@ -1332,8 +1332,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
"names) in the effects window."),
|
||||
_("Enable _PARAM2_ for effect _PARAM1_ of _PARAM0_: _PARAM3_"),
|
||||
_("Effects"),
|
||||
"res/actions/effect_black.svg",
|
||||
"res/actions/effect_black.svg")
|
||||
"res/actions/effect24.png",
|
||||
"res/actions/effect.png")
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("objectEffectName", _("Effect name"))
|
||||
.AddParameter("objectEffectParameterName", _("Property name"))
|
||||
@@ -1347,8 +1347,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
_("Check if the effect on an object is enabled."),
|
||||
_("Effect _PARAM1_ of _PARAM0_ is enabled"),
|
||||
_("Effects"),
|
||||
"res/actions/effect_black.svg",
|
||||
"res/actions/effect_black.svg")
|
||||
"res/actions/effect24.png",
|
||||
"res/actions/effect.png")
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("objectEffectName", _("Effect name"))
|
||||
.MarkAsSimple()
|
||||
@@ -1475,10 +1475,11 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
_("Position"),
|
||||
"res/conditions/distance24.png",
|
||||
"res/conditions/distance.png")
|
||||
.AddParameter("objectList", _("Object"))
|
||||
.AddParameter("objectList", _("Object 2"))
|
||||
.AddParameter("objectListOrEmptyIfJustDeclared", _("Object"))
|
||||
.AddParameter("objectListOrEmptyIfJustDeclared", _("Object 2"))
|
||||
.AddParameter("expression", _("Distance"))
|
||||
.AddCodeOnlyParameter("conditionInverted", "")
|
||||
.AddCodeOnlyParameter("objectsContext", "")
|
||||
.MarkAsSimple();
|
||||
|
||||
extension
|
||||
@@ -1585,10 +1586,10 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
_("Collision"),
|
||||
"res/conditions/collision24.png",
|
||||
"res/conditions/collision.png")
|
||||
.AddParameter("objectList", _("Object"))
|
||||
.AddParameter("objectList", _("Object"))
|
||||
.AddParameter("objectListOrEmptyIfJustDeclared", _("Object"))
|
||||
.AddParameter("objectListOrEmptyIfJustDeclared", _("Object"))
|
||||
.AddCodeOnlyParameter("conditionInverted", "")
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.AddCodeOnlyParameter("objectsContext", "")
|
||||
.AddParameter("yesorno",
|
||||
_("Ignore objects that are touching each other on their "
|
||||
"edges, but are not overlapping (default: no)"),
|
||||
|
@@ -27,7 +27,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsCameraExtension(
|
||||
extension.AddInstructionOrExpressionGroupMetadata(_("Layers and cameras"))
|
||||
.SetIcon("res/conditions/camera24.png");
|
||||
extension.AddInstructionOrExpressionGroupMetadata(_("Effects"))
|
||||
.SetIcon("res/actions/effect_black.svg");
|
||||
.SetIcon("res/actions/effect24.png");
|
||||
|
||||
extension
|
||||
.AddExpressionAndConditionAndAction(
|
||||
@@ -450,8 +450,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsCameraExtension(
|
||||
"names) in the effects window."),
|
||||
_("Set _PARAM3_ to _PARAM4_ for effect _PARAM2_ of layer _PARAM1_"),
|
||||
_("Effects"),
|
||||
"res/actions/effect_black.svg",
|
||||
"res/actions/effect_black.svg")
|
||||
"res/actions/effect24.png",
|
||||
"res/actions/effect.png")
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.AddParameter("layer", _("Layer"), "", true)
|
||||
.SetDefaultValue("\"\"")
|
||||
@@ -469,8 +469,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsCameraExtension(
|
||||
"names) in the effects window."),
|
||||
_("Set _PARAM3_ to _PARAM4_ for effect _PARAM2_ of layer _PARAM1_"),
|
||||
_("Effects"),
|
||||
"res/actions/effect_black.svg",
|
||||
"res/actions/effect_black.svg")
|
||||
"res/actions/effect24.png",
|
||||
"res/actions/effect.png")
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.AddParameter("layer", _("Layer"), "", true)
|
||||
.SetDefaultValue("\"\"")
|
||||
@@ -488,8 +488,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsCameraExtension(
|
||||
"names) in the effects window."),
|
||||
_("Enable _PARAM3_ for effect _PARAM2_ of layer _PARAM1_: _PARAM4_"),
|
||||
_("Effects"),
|
||||
"res/actions/effect_black.svg",
|
||||
"res/actions/effect_black.svg")
|
||||
"res/actions/effect24.png",
|
||||
"res/actions/effect.png")
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.AddParameter("layer", _("Layer"), "", true)
|
||||
.SetDefaultValue("\"\"")
|
||||
@@ -504,8 +504,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsCameraExtension(
|
||||
_("The effect on a layer is enabled"),
|
||||
_("Effect _PARAM2_ on layer _PARAM1_ is enabled"),
|
||||
_(""),
|
||||
"res/actions/effect_black.svg",
|
||||
"res/actions/effect_black.svg")
|
||||
"res/actions/effect24.png",
|
||||
"res/actions/effect.png")
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.AddParameter("layer", _("Layer"), "", true)
|
||||
.SetDefaultValue("\"\"")
|
||||
@@ -518,8 +518,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsCameraExtension(
|
||||
_("Enable an effect on a layer"),
|
||||
_("Enable effect _PARAM2_ on layer _PARAM1_: _PARAM3_"),
|
||||
_("Effects"),
|
||||
"res/actions/effect_black.svg",
|
||||
"res/actions/effect_black.svg")
|
||||
"res/actions/effect24.png",
|
||||
"res/actions/effect.png")
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.AddParameter("layer", _("Layer"), "", true)
|
||||
.SetDefaultValue("\"\"")
|
||||
|
@@ -24,7 +24,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsEffectExtension(
|
||||
"Open source (MIT License)")
|
||||
.SetExtensionHelpPath("/objects");
|
||||
extension.AddInstructionOrExpressionGroupMetadata(_("Effects"))
|
||||
.SetIcon("res/actions/effect_black.svg");
|
||||
.SetIcon("res/actions/effect24.png");
|
||||
|
||||
gd::BehaviorMetadata& aut = extension.AddBehavior(
|
||||
"EffectBehavior",
|
||||
@@ -32,7 +32,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsEffectExtension(
|
||||
"Effect",
|
||||
_("Apply visual effects to objects."),
|
||||
"",
|
||||
"res/actions/effect_black.svg",
|
||||
"res/actions/effect24.png",
|
||||
"EffectBehavior",
|
||||
std::make_shared<gd::Behavior>(),
|
||||
std::make_shared<gd::BehaviorsSharedData>())
|
||||
@@ -43,8 +43,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsEffectExtension(
|
||||
_("Enable an effect on the object"),
|
||||
_("Enable effect _PARAM2_ on _PARAM0_: _PARAM3_"),
|
||||
_("Effects"),
|
||||
"res/actions/effect_black.svg",
|
||||
"res/actions/effect_black.svg")
|
||||
"res/actions/effect24.png",
|
||||
"res/actions/effect.png")
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("behavior", _("Behavior"), "EffectBehavior")
|
||||
.AddParameter("objectEffectName", _("Effect name"))
|
||||
@@ -58,8 +58,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsEffectExtension(
|
||||
"names) in the effects window."),
|
||||
_("Set _PARAM3_ to _PARAM4_ for effect _PARAM2_ of _PARAM0_"),
|
||||
_("Effects"),
|
||||
"res/actions/effect_black.svg",
|
||||
"res/actions/effect_black.svg")
|
||||
"res/actions/effect24.png",
|
||||
"res/actions/effect.png")
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("behavior", _("Behavior"), "EffectBehavior")
|
||||
.AddParameter("objectEffectName", _("Effect name"))
|
||||
@@ -75,8 +75,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsEffectExtension(
|
||||
"names) in the effects window."),
|
||||
_("Set _PARAM3_ to _PARAM4_ for effect _PARAM2_ of _PARAM0_"),
|
||||
_("Effects"),
|
||||
"res/actions/effect_black.svg",
|
||||
"res/actions/effect_black.svg")
|
||||
"res/actions/effect24.png",
|
||||
"res/actions/effect.png")
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("behavior", _("Behavior"), "EffectBehavior")
|
||||
.AddParameter("objectEffectName", _("Effect name"))
|
||||
@@ -91,8 +91,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsEffectExtension(
|
||||
"names) in the effects window."),
|
||||
_("Enable _PARAM3_ for effect _PARAM2_ of _PARAM0_: _PARAM4_"),
|
||||
_("Effects"),
|
||||
"res/actions/effect_black.svg",
|
||||
"res/actions/effect_black.svg")
|
||||
"res/actions/effect24.png",
|
||||
"res/actions/effect.png")
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("behavior", _("Behavior"), "EffectBehavior")
|
||||
.AddParameter("objectEffectName", _("Effect name"))
|
||||
@@ -105,8 +105,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsEffectExtension(
|
||||
_("Check if the effect on an object is enabled."),
|
||||
_("Effect _PARAM2_ of _PARAM0_ is enabled"),
|
||||
_("Effects"),
|
||||
"res/actions/effect_black.svg",
|
||||
"res/actions/effect_black.svg")
|
||||
"res/actions/effect24.png",
|
||||
"res/actions/effect.png")
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("behavior", _("Behavior"), "EffectBehavior")
|
||||
.AddParameter("objectEffectName", _("Effect name"))
|
||||
|
@@ -24,7 +24,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsFlippableExtension(
|
||||
"Open source (MIT License)")
|
||||
.SetExtensionHelpPath("/objects");
|
||||
extension.AddInstructionOrExpressionGroupMetadata(_("Effects"))
|
||||
.SetIcon("res/actions/effect_black.svg");
|
||||
.SetIcon("res/actions/effect24.png");
|
||||
|
||||
gd::BehaviorMetadata& aut = extension.AddBehavior(
|
||||
"FlippableBehavior",
|
||||
|
@@ -171,8 +171,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSceneExtension(
|
||||
_("Preload a scene resources as soon as possible in background."),
|
||||
_("Preload scene _PARAM1_ in background"),
|
||||
"",
|
||||
"res/actions/hourglass_black.svg",
|
||||
"res/actions/hourglass_black.svg")
|
||||
"res/actions/replaceScene24.png",
|
||||
"res/actions/replaceScene.png")
|
||||
.SetHelpPath("/all-features/resources-loading")
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.AddParameter("sceneName", _("Name of the new scene"))
|
||||
@@ -184,7 +184,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSceneExtension(
|
||||
_("The progress of resources loading in background for a scene (between 0 and 1)."),
|
||||
_("_PARAM0_ loading progress"),
|
||||
_(""),
|
||||
"res/actions/hourglass_black.svg")
|
||||
"res/actions/replaceScene24.png")
|
||||
.SetHelpPath("/all-features/resources-loading")
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.AddParameter("sceneName", _("Scene name"))
|
||||
@@ -197,8 +197,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSceneExtension(
|
||||
_("Check if scene resources have finished to load in background."),
|
||||
_("Scene _PARAM1_ was preloaded in background"),
|
||||
"",
|
||||
"res/actions/hourglass_black.svg",
|
||||
"res/actions/hourglass_black.svg")
|
||||
"res/actions/replaceScene24.png",
|
||||
"res/actions/replaceScene.png")
|
||||
.SetHelpPath("/all-features/resources-loading")
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.AddParameter("sceneName", _("Scene name"))
|
||||
|
@@ -114,8 +114,6 @@ public:
|
||||
|
||||
/**
|
||||
* \brief Erase any existing include file and add the specified include.
|
||||
* \deprecated Use `AddIncludeFile` instead as clearing the list is more
|
||||
* error prone.
|
||||
*/
|
||||
virtual AbstractFunctionMetadata &
|
||||
SetIncludeFile(const gd::String &includeFile) = 0;
|
||||
|
@@ -13,15 +13,12 @@
|
||||
#include "GDCore/Extensions/PlatformExtension.h"
|
||||
#include "GDCore/Project/Behavior.h"
|
||||
#include "GDCore/Project/BehaviorsSharedData.h"
|
||||
#include "GDCore/Project/PropertyDescriptor.h"
|
||||
#include "GDCore/Tools/Localization.h"
|
||||
#include "GDCore/Tools/MakeUnique.h"
|
||||
#include "GDCore/Tools/Log.h"
|
||||
|
||||
namespace gd {
|
||||
|
||||
const std::map<gd::String, gd::PropertyDescriptor> BehaviorMetadata::badProperties;
|
||||
|
||||
BehaviorMetadata::BehaviorMetadata(
|
||||
const gd::String& extensionNamespace_,
|
||||
const gd::String& nameWithNamespace,
|
||||
@@ -50,14 +47,8 @@ BehaviorMetadata::BehaviorMetadata(
|
||||
"BehaviorMetadata is valid for: " + nameWithNamespace);
|
||||
}
|
||||
|
||||
if (instance) {
|
||||
instance->SetTypeName(nameWithNamespace);
|
||||
instance->InitializeContent();
|
||||
}
|
||||
if (sharedDatasInstance) {
|
||||
sharedDatasInstance->SetTypeName(nameWithNamespace);
|
||||
sharedDatasInstance->InitializeContent();
|
||||
}
|
||||
if (instance) instance->SetTypeName(nameWithNamespace);
|
||||
if (sharedDatasInstance) sharedDatasInstance->SetTypeName(nameWithNamespace);
|
||||
}
|
||||
|
||||
gd::InstructionMetadata& BehaviorMetadata::AddCondition(
|
||||
@@ -414,30 +405,10 @@ gd::Behavior& BehaviorMetadata::Get() const {
|
||||
return *instance;
|
||||
}
|
||||
|
||||
std::map<gd::String, gd::PropertyDescriptor> BehaviorMetadata::GetProperties() const {
|
||||
if (!instance) {
|
||||
return badProperties;
|
||||
}
|
||||
// TODO Properties should be declared on BehaviorMetadata directly.
|
||||
// - Add 2 `properties` members (one for shared properties)
|
||||
// - Add methods to declare new properties
|
||||
return instance->GetProperties();
|
||||
}
|
||||
|
||||
gd::BehaviorsSharedData* BehaviorMetadata::GetSharedDataInstance() const {
|
||||
return sharedDatasInstance.get();
|
||||
}
|
||||
|
||||
std::map<gd::String, gd::PropertyDescriptor> BehaviorMetadata::GetSharedProperties() const {
|
||||
if (!sharedDatasInstance) {
|
||||
return badProperties;
|
||||
}
|
||||
// TODO Properties should be declared on BehaviorMetadata directly.
|
||||
// - Add 2 `properties` members (one for shared properties)
|
||||
// - Add methods to declare new properties
|
||||
return sharedDatasInstance->GetProperties();
|
||||
}
|
||||
|
||||
const std::vector<gd::String>& BehaviorMetadata::GetRequiredBehaviorTypes() const {
|
||||
requiredBehaviors.clear();
|
||||
for (auto& property : Get().GetProperties()) {
|
||||
|
@@ -18,7 +18,6 @@ class BehaviorsSharedData;
|
||||
class MultipleInstructionMetadata;
|
||||
class InstructionMetadata;
|
||||
class ExpressionMetadata;
|
||||
class PropertyDescriptor;
|
||||
} // namespace gd
|
||||
|
||||
namespace gd {
|
||||
@@ -205,8 +204,6 @@ class GD_CORE_API BehaviorMetadata : public InstructionOrExpressionContainerMeta
|
||||
* \brief Erase any existing include file and add the specified include.
|
||||
* \note The requirement may vary depending on the platform: Most of the time,
|
||||
* the include file contains the declaration of the behavior.
|
||||
* \deprecated Use `AddIncludeFile` instead as clearing the list is more
|
||||
* error prone.
|
||||
*/
|
||||
BehaviorMetadata& SetIncludeFile(const gd::String& includeFile) override;
|
||||
|
||||
@@ -305,15 +302,6 @@ class GD_CORE_API BehaviorMetadata : public InstructionOrExpressionContainerMeta
|
||||
*/
|
||||
gd::Behavior& Get() const;
|
||||
|
||||
/**
|
||||
* \brief Called when the IDE wants to know about the custom properties of the
|
||||
* behavior.
|
||||
*
|
||||
* \return a std::map with properties names as key.
|
||||
* \see gd::PropertyDescriptor
|
||||
*/
|
||||
std::map<gd::String, gd::PropertyDescriptor> GetProperties() const;
|
||||
|
||||
/**
|
||||
* \brief Return the associated gd::BehaviorsSharedData, handling behavior
|
||||
* shared data, if any (nullptr if none).
|
||||
@@ -323,15 +311,6 @@ class GD_CORE_API BehaviorMetadata : public InstructionOrExpressionContainerMeta
|
||||
*/
|
||||
gd::BehaviorsSharedData* GetSharedDataInstance() const;
|
||||
|
||||
/**
|
||||
* \brief Called when the IDE wants to know about the custom shared properties
|
||||
* of the behavior.
|
||||
*
|
||||
* \return a std::map with properties names as key.
|
||||
* \see gd::PropertyDescriptor
|
||||
*/
|
||||
std::map<gd::String, gd::PropertyDescriptor> GetSharedProperties() const;
|
||||
|
||||
/**
|
||||
* \brief Return a reference to a map containing the names of the actions
|
||||
* (as keys) and the metadata associated with (as values).
|
||||
@@ -378,8 +357,6 @@ class GD_CORE_API BehaviorMetadata : public InstructionOrExpressionContainerMeta
|
||||
// TODO: Nitpicking: convert these to std::unique_ptr to clarify ownership.
|
||||
std::shared_ptr<gd::Behavior> instance;
|
||||
std::shared_ptr<gd::BehaviorsSharedData> sharedDatasInstance;
|
||||
|
||||
static const std::map<gd::String, gd::PropertyDescriptor> badProperties;
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
|
@@ -65,8 +65,6 @@ class GD_CORE_API EffectMetadata {
|
||||
|
||||
/**
|
||||
* \brief Clear any existing include file and add the specified include file.
|
||||
* \deprecated Use `AddIncludeFile` instead as clearing the list is more
|
||||
* error prone.
|
||||
*/
|
||||
EffectMetadata& SetIncludeFile(const gd::String& includeFile);
|
||||
|
||||
|
@@ -5,7 +5,6 @@
|
||||
*/
|
||||
#include "ExpressionMetadata.h"
|
||||
#include "GDCore/CommonTools.h"
|
||||
#include "GDCore/Extensions/PlatformExtension.h"
|
||||
#include "GDCore/String.h"
|
||||
|
||||
namespace gd {
|
||||
@@ -47,14 +46,16 @@ gd::ExpressionMetadata& ExpressionMetadata::AddParameter(
|
||||
// For objects/behavior, the supplementary information
|
||||
// parameter is an object/behavior type...
|
||||
((gd::ParameterMetadata::IsObject(type) ||
|
||||
gd::ParameterMetadata::IsBehavior(type))
|
||||
// Prefix with the namespace if it's not already there.
|
||||
&& (supplementaryInformation.find(
|
||||
PlatformExtension::GetNamespaceSeparator()) == gd::String::npos)
|
||||
? (supplementaryInformation.empty()
|
||||
? ""
|
||||
: extensionNamespace + supplementaryInformation)
|
||||
: supplementaryInformation));
|
||||
gd::ParameterMetadata::IsBehavior(type))
|
||||
// Prefix with the namespace if it's not already there.
|
||||
&& !(supplementaryInformation.rfind(extensionNamespace, 0) == 0))
|
||||
? (supplementaryInformation.empty()
|
||||
? ""
|
||||
: extensionNamespace +
|
||||
supplementaryInformation //... so prefix it with the extension
|
||||
// namespace.
|
||||
)
|
||||
: supplementaryInformation); // Otherwise don't change anything
|
||||
|
||||
// TODO: Assert against supplementaryInformation === "emsc" (when running with
|
||||
// Emscripten), and warn about a missing argument when calling addParameter.
|
||||
|
@@ -288,8 +288,6 @@ class GD_CORE_API ExpressionMetadata : public gd::AbstractFunctionMetadata {
|
||||
|
||||
/**
|
||||
* \brief Erase any existing include file and add the specified include.
|
||||
* \deprecated Use `AddIncludeFile` instead as clearing the list is more
|
||||
* error prone.
|
||||
*/
|
||||
ExpressionMetadata& SetIncludeFile(
|
||||
const gd::String& includeFile) override {
|
||||
|
@@ -8,7 +8,6 @@
|
||||
#include <algorithm>
|
||||
|
||||
#include "GDCore/CommonTools.h"
|
||||
#include "GDCore/Extensions/PlatformExtension.h"
|
||||
#include "GDCore/Serialization/SerializerElement.h"
|
||||
#include "GDCore/Tools/Localization.h"
|
||||
#include "GDCore/Tools/Log.h"
|
||||
@@ -65,14 +64,17 @@ InstructionMetadata& InstructionMetadata::AddParameter(
|
||||
// For objects/behavior, the supplementary information
|
||||
// parameter is an object/behavior type...
|
||||
((gd::ParameterMetadata::IsObject(type) ||
|
||||
gd::ParameterMetadata::IsBehavior(type))
|
||||
// Prefix with the namespace if it's not already there.
|
||||
&& (supplementaryInformation.find(
|
||||
PlatformExtension::GetNamespaceSeparator()) == gd::String::npos)
|
||||
? (supplementaryInformation.empty()
|
||||
? ""
|
||||
: extensionNamespace + supplementaryInformation)
|
||||
: supplementaryInformation));
|
||||
gd::ParameterMetadata::IsBehavior(type))
|
||||
// Prefix with the namespace if it's not already there.
|
||||
&& !(supplementaryInformation.rfind(extensionNamespace, 0) == 0))
|
||||
? (supplementaryInformation.empty()
|
||||
? ""
|
||||
: extensionNamespace +
|
||||
supplementaryInformation //... so prefix it with the
|
||||
// extension
|
||||
// namespace.
|
||||
)
|
||||
: supplementaryInformation); // Otherwise don't change anything
|
||||
|
||||
// TODO: Assert against supplementaryInformation === "emsc" (when running with
|
||||
// Emscripten), and warn about a missing argument when calling addParameter.
|
||||
@@ -188,7 +190,7 @@ InstructionMetadata::UseStandardRelationalOperatorParameters(
|
||||
gd::String templateSentence = _("<subject> of _PARAM0_ <operator> <value>");
|
||||
|
||||
sentence =
|
||||
templateSentence.FindAndReplace("<subject>", sentence.CapitalizeFirstLetter())
|
||||
templateSentence.FindAndReplace("<subject>", sentence)
|
||||
.FindAndReplace(
|
||||
"<operator>",
|
||||
"_PARAM" + gd::String::From(operatorParamIndex) + "_")
|
||||
@@ -198,7 +200,7 @@ InstructionMetadata::UseStandardRelationalOperatorParameters(
|
||||
gd::String templateSentence = _("<subject> <operator> <value>");
|
||||
|
||||
sentence =
|
||||
templateSentence.FindAndReplace("<subject>", sentence.CapitalizeFirstLetter())
|
||||
templateSentence.FindAndReplace("<subject>", sentence)
|
||||
.FindAndReplace(
|
||||
"<operator>",
|
||||
"_PARAM" + gd::String::From(operatorParamIndex) + "_")
|
||||
|
@@ -494,8 +494,6 @@ class GD_CORE_API InstructionMetadata : public gd::AbstractFunctionMetadata {
|
||||
|
||||
/**
|
||||
* \brief Erase any existing include file and add the specified include.
|
||||
* \deprecated Use `AddIncludeFile` instead as clearing the list is more
|
||||
* error prone.
|
||||
*/
|
||||
InstructionMetadata &SetIncludeFile(const gd::String &includeFile) override {
|
||||
codeExtraInformation.includeFiles.clear();
|
||||
|
@@ -142,8 +142,6 @@ public:
|
||||
* \brief Erase any existing include file and add the specified include.
|
||||
* \note The requirement may vary depending on the platform: Most of the time,
|
||||
* the include file contains the declaration of the behavior.
|
||||
* \deprecated Use `AddIncludeFile` instead as clearing the list is more
|
||||
* error prone.
|
||||
*/
|
||||
virtual InstructionOrExpressionContainerMetadata &
|
||||
SetIncludeFile(const gd::String &includeFile) = 0;
|
||||
|
@@ -150,10 +150,6 @@ class GD_CORE_API MultipleInstructionMetadata : public AbstractFunctionMetadata
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* \deprecated Use `AddIncludeFile` instead as clearing the list is more
|
||||
* error prone.
|
||||
*/
|
||||
MultipleInstructionMetadata &SetIncludeFile(const gd::String &includeFile) override {
|
||||
if (expression)
|
||||
expression->SetIncludeFile(includeFile);
|
||||
|
@@ -264,8 +264,6 @@ class GD_CORE_API ObjectMetadata : public InstructionOrExpressionContainerMetada
|
||||
* \brief Erase any existing include file and add the specified include.
|
||||
* \note The requirement may vary depending on the platform: Most of the time,
|
||||
* the include file contains the declaration of the object.
|
||||
* \deprecated Use `AddIncludeFile` instead as clearing the list is more
|
||||
* error prone.
|
||||
*/
|
||||
ObjectMetadata& SetIncludeFile(const gd::String& includeFile) override;
|
||||
|
||||
|
@@ -217,9 +217,7 @@ class GD_CORE_API ValueTypeMetadata {
|
||||
parameterType == "jsonResource" ||
|
||||
parameterType == "tilemapResource" ||
|
||||
parameterType == "tilesetResource" ||
|
||||
parameterType == "model3DResource" ||
|
||||
parameterType == "atlasResource" ||
|
||||
parameterType == "spineResource";
|
||||
parameterType == "model3DResource";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@@ -264,11 +264,8 @@ class GD_CORE_API PlatformExtension {
|
||||
*
|
||||
* \param name The name of the behavior
|
||||
* \param fullname The user friendly name of the behavior
|
||||
* \param defaultName The default name of behavior instances
|
||||
* \param description The user friendly description of the behavior
|
||||
* \param group The behavior category label
|
||||
* \param icon The icon of the behavior.
|
||||
* \param className The name of the class implementing the behavior
|
||||
* \param instance An instance of the behavior that
|
||||
* will be used to create the behavior
|
||||
* \param sharedDatasInstance Optional
|
||||
@@ -285,6 +282,21 @@ class GD_CORE_API PlatformExtension {
|
||||
std::shared_ptr<gd::Behavior> instance,
|
||||
std::shared_ptr<gd::BehaviorsSharedData> sharedDatasInstance);
|
||||
|
||||
/**
|
||||
* \brief Declare a new events based behavior as being part of the extension.
|
||||
*
|
||||
* \param name The name of the behavior
|
||||
* \param fullname The user friendly name of the behavior
|
||||
* \param description The user friendly description of the behavior
|
||||
* \param icon The icon of the behavior.
|
||||
*/
|
||||
gd::BehaviorMetadata& AddEventsBasedBehavior(
|
||||
const gd::String& name_,
|
||||
const gd::String& fullname_,
|
||||
const gd::String& description_,
|
||||
const gd::String& group_,
|
||||
const gd::String& icon_);
|
||||
|
||||
/**
|
||||
* \brief Declare a new effect as being part of the extension.
|
||||
* \param name The internal name of the effect (also called effect type).
|
||||
|
@@ -136,7 +136,7 @@ class GD_CORE_API ExpressionVariableReplacer
|
||||
auto& objectsContainersList =
|
||||
projectScopedContainers.GetObjectsContainersList();
|
||||
if (!objectNameToUseForVariableAccessor.empty()) {
|
||||
if (objectsContainersList.HasObjectOrGroupVariablesContainer(
|
||||
if (objectsContainersList.HasVariablesContainer(
|
||||
objectNameToUseForVariableAccessor, targetVariablesContainer)) {
|
||||
// The node represents an object variable, and this object variables are
|
||||
// the target. Do the replacement or removals:
|
||||
@@ -177,7 +177,7 @@ class GD_CORE_API ExpressionVariableReplacer
|
||||
GetPotentialNewName(node.identifierName),
|
||||
[&]() {
|
||||
// This represents an object.
|
||||
if (objectsContainersList.HasObjectOrGroupVariablesContainer(
|
||||
if (objectsContainersList.HasVariablesContainer(
|
||||
node.identifierName, targetVariablesContainer)) {
|
||||
// The node represents an object variable, and this object variables
|
||||
// are the target. Do the replacement or removals:
|
||||
|
@@ -11,16 +11,13 @@
|
||||
|
||||
#include "GDCore/Events/Parsers/ExpressionParser2.h"
|
||||
#include "GDCore/Events/Parsers/ExpressionParser2Node.h"
|
||||
#include "GDCore/Events/Parsers/ExpressionParser2NodePrinter.h"
|
||||
#include "GDCore/Events/Parsers/ExpressionParser2NodeWorker.h"
|
||||
#include "GDCore/Events/Parsers/GrammarTerminals.h"
|
||||
#include "GDCore/Extensions/Metadata/ExpressionMetadata.h"
|
||||
#include "GDCore/Extensions/Metadata/InstructionMetadata.h"
|
||||
#include "GDCore/Extensions/Metadata/ValueTypeMetadata.h"
|
||||
#include "GDCore/IDE/Events/ExpressionNodeLocationFinder.h"
|
||||
#include "GDCore/IDE/Events/ExpressionTypeFinder.h"
|
||||
#include "GDCore/IDE/Events/ExpressionVariableOwnerFinder.h"
|
||||
#include "GDCore/IDE/Events/ExpressionVariableParentFinder.h"
|
||||
#include "GDCore/Project/ProjectScopedContainers.h"
|
||||
#include "GDCore/Project/Variable.h"
|
||||
|
||||
@@ -489,56 +486,47 @@ class GD_CORE_API ExpressionCompletionFinder
|
||||
auto type = gd::ExpressionTypeFinder::GetType(
|
||||
platform, projectScopedContainers, rootType, node);
|
||||
|
||||
// Only attempt to complete with the children of the variable
|
||||
// if it's the last child (no more `.AnotherVariable` written after).
|
||||
bool eagerlyCompleteIfExactMatch = node.child == nullptr;
|
||||
|
||||
if (gd::ValueTypeMetadata::IsTypeLegacyPreScopedVariable(type)) {
|
||||
if (type == "globalvar" || type == "scenevar") {
|
||||
if (type == "globalvar") {
|
||||
const auto* variablesContainer =
|
||||
type == "globalvar"
|
||||
? projectScopedContainers.GetVariablesContainersList()
|
||||
.GetTopMostVariablesContainer()
|
||||
: projectScopedContainers.GetVariablesContainersList()
|
||||
.GetBottomMostVariablesContainer();
|
||||
projectScopedContainers.GetVariablesContainersList()
|
||||
.GetTopMostVariablesContainer();
|
||||
if (variablesContainer) {
|
||||
AddCompletionsForVariablesMatchingSearch(*variablesContainer,
|
||||
node.name,
|
||||
node.nameLocation,
|
||||
eagerlyCompleteIfExactMatch);
|
||||
AddCompletionsForVariablesMatchingSearch(
|
||||
*variablesContainer, node.name, node.nameLocation);
|
||||
}
|
||||
} else if (type == "scenevar") {
|
||||
const auto* variablesContainer =
|
||||
projectScopedContainers.GetVariablesContainersList()
|
||||
.GetBottomMostVariablesContainer();
|
||||
if (variablesContainer) {
|
||||
AddCompletionsForVariablesMatchingSearch(
|
||||
*variablesContainer, node.name, node.nameLocation);
|
||||
}
|
||||
} else if (type == "objectvar") {
|
||||
auto objectName = gd::ExpressionVariableOwnerFinder::GetObjectName(
|
||||
platform, objectsContainersList, rootObjectName, node);
|
||||
platform,
|
||||
objectsContainersList,
|
||||
// Variable fields doesn't use expression completion,
|
||||
// so the object will be found inside the expression itself.
|
||||
"",
|
||||
node);
|
||||
|
||||
AddCompletionsForObjectOrGroupVariablesMatchingSearch(
|
||||
objectsContainersList,
|
||||
objectName,
|
||||
node.name,
|
||||
node.nameLocation,
|
||||
eagerlyCompleteIfExactMatch);
|
||||
objectsContainersList, objectName, node.name, node.nameLocation);
|
||||
}
|
||||
} else {
|
||||
AddCompletionsForObjectsAndVariablesMatchingSearch(
|
||||
node.name, type, node.nameLocation, eagerlyCompleteIfExactMatch);
|
||||
node.name, type, node.nameLocation);
|
||||
}
|
||||
}
|
||||
void OnVisitVariableAccessorNode(VariableAccessorNode& node) override {
|
||||
VariableAndItsParent variableAndItsParent =
|
||||
gd::ExpressionVariableParentFinder::GetLastParentOfNode(
|
||||
platform, projectScopedContainers, node);
|
||||
|
||||
// If no child, we're at the end of a variable (like `GrandChild` in
|
||||
// `Something.Child.GrandChild`) so we can complete eagerly children if we
|
||||
// can.
|
||||
gd::String eagerlyCompleteForVariableName =
|
||||
node.child == nullptr ? node.name : "";
|
||||
AddCompletionsForChildrenVariablesOf(variableAndItsParent,
|
||||
node.nameLocation,
|
||||
eagerlyCompleteForVariableName);
|
||||
// No completions
|
||||
}
|
||||
void OnVisitVariableBracketAccessorNode(
|
||||
VariableBracketAccessorNode& node) override {}
|
||||
VariableBracketAccessorNode& node) override {
|
||||
// No completions
|
||||
}
|
||||
void OnVisitIdentifierNode(IdentifierNode& node) override {
|
||||
const auto& objectsContainersList =
|
||||
projectScopedContainers.GetObjectsContainersList();
|
||||
@@ -549,81 +537,45 @@ class GD_CORE_API ExpressionCompletionFinder
|
||||
AddCompletionsForObjectMatchingSearch(
|
||||
node.identifierName, type, node.location);
|
||||
} else if (gd::ValueTypeMetadata::IsTypeLegacyPreScopedVariable(type)) {
|
||||
if (type == "globalvar" || type == "scenevar") {
|
||||
if (type == "globalvar") {
|
||||
const auto* variablesContainer =
|
||||
type == "globalvar"
|
||||
? projectScopedContainers.GetVariablesContainersList()
|
||||
.GetTopMostVariablesContainer()
|
||||
: projectScopedContainers.GetVariablesContainersList()
|
||||
.GetBottomMostVariablesContainer();
|
||||
projectScopedContainers.GetVariablesContainersList()
|
||||
.GetTopMostVariablesContainer();
|
||||
if (variablesContainer) {
|
||||
if (IsCaretOn(node.identifierNameDotLocation) ||
|
||||
IsCaretOn(node.childIdentifierNameLocation)) {
|
||||
// Complete a potential child variable:
|
||||
if (variablesContainer->Has(node.identifierName)) {
|
||||
AddCompletionsForChildrenVariablesOf(
|
||||
&variablesContainer->Get(node.identifierName),
|
||||
node.childIdentifierNameLocation,
|
||||
node.childIdentifierName);
|
||||
}
|
||||
} else {
|
||||
// Complete a root variable of the scene or project.
|
||||
|
||||
// Don't attempt to complete children variables if there is
|
||||
// already a dot written (`MyVariable.`).
|
||||
bool eagerlyCompleteIfPossible =
|
||||
!node.identifierNameDotLocation.IsValid();
|
||||
AddCompletionsForVariablesMatchingSearch(
|
||||
*variablesContainer,
|
||||
node.identifierName,
|
||||
node.identifierNameLocation,
|
||||
eagerlyCompleteIfPossible);
|
||||
}
|
||||
AddCompletionsForVariablesMatchingSearch(*variablesContainer,
|
||||
node.identifierName,
|
||||
node.identifierNameLocation);
|
||||
}
|
||||
} else if (type == "scenevar") {
|
||||
const auto* variablesContainer =
|
||||
projectScopedContainers.GetVariablesContainersList()
|
||||
.GetBottomMostVariablesContainer();
|
||||
if (variablesContainer) {
|
||||
AddCompletionsForVariablesMatchingSearch(*variablesContainer,
|
||||
node.identifierName,
|
||||
node.identifierNameLocation);
|
||||
}
|
||||
} else if (type == "objectvar") {
|
||||
auto objectName = gd::ExpressionVariableOwnerFinder::GetObjectName(
|
||||
platform, objectsContainersList, rootObjectName, node);
|
||||
platform,
|
||||
objectsContainersList,
|
||||
// Variable fields doesn't use expression completion,
|
||||
// so the object will be found inside the expression itself.
|
||||
"",
|
||||
node);
|
||||
|
||||
if (IsCaretOn(node.identifierNameDotLocation) ||
|
||||
IsCaretOn(node.childIdentifierNameLocation)) {
|
||||
// Complete a potential child variable:
|
||||
const auto* variablesContainer =
|
||||
objectsContainersList.GetObjectOrGroupVariablesContainer(
|
||||
objectName);
|
||||
if (variablesContainer &&
|
||||
variablesContainer->Has(node.identifierName)) {
|
||||
AddCompletionsForChildrenVariablesOf(
|
||||
&variablesContainer->Get(node.identifierName),
|
||||
node.childIdentifierNameLocation,
|
||||
node.childIdentifierName);
|
||||
}
|
||||
} else {
|
||||
// Complete a root variable of the object.
|
||||
|
||||
// Don't attempt to complete children variables if there is
|
||||
// already a dot written (`MyVariable.`).
|
||||
bool eagerlyCompleteIfPossible =
|
||||
!node.identifierNameDotLocation.IsValid();
|
||||
AddCompletionsForObjectOrGroupVariablesMatchingSearch(
|
||||
objectsContainersList,
|
||||
objectName,
|
||||
node.identifierName,
|
||||
node.identifierNameLocation,
|
||||
eagerlyCompleteIfPossible);
|
||||
}
|
||||
AddCompletionsForObjectOrGroupVariablesMatchingSearch(
|
||||
objectsContainersList,
|
||||
objectName,
|
||||
node.identifierName,
|
||||
node.identifierNameLocation);
|
||||
}
|
||||
} else {
|
||||
// Object function, behavior name, variable, object variable.
|
||||
if (IsCaretOn(node.identifierNameLocation)) {
|
||||
// Don't attempt to complete children variables if there is
|
||||
// already a dot written (`MyVariable.`).
|
||||
bool eagerlyCompleteIfPossible =
|
||||
!node.identifierNameDotLocation.IsValid();
|
||||
// Is this the proper position?
|
||||
AddCompletionsForAllIdentifiersMatchingSearch(
|
||||
node.identifierName,
|
||||
type,
|
||||
node.identifierNameLocation,
|
||||
eagerlyCompleteIfPossible);
|
||||
node.identifierName, type, node.identifierNameLocation);
|
||||
if (!node.identifierNameDotLocation.IsValid()) {
|
||||
completions.push_back(
|
||||
ExpressionCompletionDescription::ForExpressionWithPrefix(
|
||||
@@ -634,57 +586,27 @@ class GD_CORE_API ExpressionCompletionFinder
|
||||
}
|
||||
} else if (IsCaretOn(node.identifierNameDotLocation) ||
|
||||
IsCaretOn(node.childIdentifierNameLocation)) {
|
||||
// Might be:
|
||||
// - An object variable, object behavior or object expression.
|
||||
// - Or a variable with a child.
|
||||
projectScopedContainers.MatchIdentifierWithName<void>(
|
||||
node.identifierName,
|
||||
[&]() {
|
||||
// This is an object.
|
||||
const gd::String& objectName = node.identifierName;
|
||||
AddCompletionsForObjectOrGroupVariablesMatchingSearch(
|
||||
objectsContainersList,
|
||||
objectName,
|
||||
node.childIdentifierName,
|
||||
node.childIdentifierNameLocation,
|
||||
true);
|
||||
const gd::String& objectName = node.identifierName;
|
||||
|
||||
completions.push_back(
|
||||
ExpressionCompletionDescription::ForBehaviorWithPrefix(
|
||||
node.childIdentifierName,
|
||||
node.childIdentifierNameLocation.GetStartPosition(),
|
||||
node.childIdentifierNameLocation.GetEndPosition(),
|
||||
objectName));
|
||||
completions.push_back(
|
||||
ExpressionCompletionDescription::ForExpressionWithPrefix(
|
||||
type,
|
||||
node.childIdentifierName,
|
||||
node.childIdentifierNameLocation.GetStartPosition(),
|
||||
node.childIdentifierNameLocation.GetEndPosition(),
|
||||
objectName));
|
||||
},
|
||||
[&]() {
|
||||
// This is a variable.
|
||||
VariableAndItsParent variableAndItsParent =
|
||||
gd::ExpressionVariableParentFinder::GetLastParentOfNode(
|
||||
platform, projectScopedContainers, node);
|
||||
|
||||
AddCompletionsForChildrenVariablesOf(
|
||||
variableAndItsParent,
|
||||
node.childIdentifierNameLocation,
|
||||
node.childIdentifierName);
|
||||
},
|
||||
[&]() {
|
||||
// Ignore properties here.
|
||||
// There is no support for "children" of properties.
|
||||
},
|
||||
[&]() {
|
||||
// Ignore parameters here.
|
||||
// There is no support for "children" of parameters.
|
||||
},
|
||||
[&]() {
|
||||
// Ignore unrecognised identifiers here.
|
||||
});
|
||||
// Might be an object variable, object behavior or object expression:
|
||||
AddCompletionsForObjectOrGroupVariablesMatchingSearch(
|
||||
objectsContainersList,
|
||||
objectName,
|
||||
node.childIdentifierName,
|
||||
node.childIdentifierNameLocation);
|
||||
completions.push_back(
|
||||
ExpressionCompletionDescription::ForBehaviorWithPrefix(
|
||||
node.childIdentifierName,
|
||||
node.childIdentifierNameLocation.GetStartPosition(),
|
||||
node.childIdentifierNameLocation.GetEndPosition(),
|
||||
objectName));
|
||||
completions.push_back(
|
||||
ExpressionCompletionDescription::ForExpressionWithPrefix(
|
||||
type,
|
||||
node.childIdentifierName,
|
||||
node.childIdentifierNameLocation.GetStartPosition(),
|
||||
node.childIdentifierNameLocation.GetEndPosition(),
|
||||
objectName));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -814,8 +736,7 @@ class GD_CORE_API ExpressionCompletionFinder
|
||||
auto type = gd::ExpressionTypeFinder::GetType(
|
||||
platform, projectScopedContainers, rootType, node);
|
||||
|
||||
AddCompletionsForAllIdentifiersMatchingSearch(
|
||||
node.text, type, node.location);
|
||||
AddCompletionsForAllIdentifiersMatchingSearch(node.text, type, node.location);
|
||||
completions.push_back(
|
||||
ExpressionCompletionDescription::ForExpressionWithPrefix(
|
||||
type,
|
||||
@@ -834,96 +755,10 @@ class GD_CORE_API ExpressionCompletionFinder
|
||||
(inclusive && searchedPosition <= location.GetEndPosition())));
|
||||
}
|
||||
|
||||
/**
|
||||
* A slightly less strict check than `gd::Project::IsNameSafe` as child
|
||||
* variables can be completed even if they start with a number.
|
||||
*/
|
||||
bool IsIdentifierSafe(const gd::String& name) {
|
||||
if (name.empty()) return false;
|
||||
|
||||
for (auto character : name) {
|
||||
if (!GrammarTerminals::IsAllowedInIdentifier(character)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void AddCompletionsForChildrenVariablesOf(
|
||||
VariableAndItsParent variableAndItsParent,
|
||||
const ExpressionParserLocation& location,
|
||||
gd::String eagerlyCompleteForVariableName = "") {
|
||||
if (variableAndItsParent.parentVariable) {
|
||||
AddCompletionsForChildrenVariablesOf(variableAndItsParent.parentVariable,
|
||||
location,
|
||||
eagerlyCompleteForVariableName);
|
||||
} else if (variableAndItsParent.parentVariablesContainer) {
|
||||
AddCompletionsForVariablesMatchingSearch(
|
||||
*variableAndItsParent.parentVariablesContainer, "", location);
|
||||
}
|
||||
}
|
||||
|
||||
void AddCompletionsForChildrenVariablesOf(
|
||||
const gd::Variable* variable,
|
||||
const ExpressionParserLocation& location,
|
||||
gd::String eagerlyCompleteForVariableName = "") {
|
||||
if (!variable) return;
|
||||
|
||||
if (variable->GetType() == gd::Variable::Structure) {
|
||||
for (const auto& name : variable->GetAllChildrenNames()) {
|
||||
if (!IsIdentifierSafe(name)) continue;
|
||||
|
||||
const auto& childVariable = variable->GetChild(name);
|
||||
ExpressionCompletionDescription description(
|
||||
ExpressionCompletionDescription::Variable,
|
||||
location.GetStartPosition(),
|
||||
location.GetEndPosition());
|
||||
description.SetCompletion(name);
|
||||
description.SetVariableType(childVariable.GetType());
|
||||
completions.push_back(description);
|
||||
|
||||
if (name == eagerlyCompleteForVariableName) {
|
||||
AddEagerCompletionForVariableChildren(childVariable, name, location);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// TODO: we could do a "comment only completion" to indicate that nothing
|
||||
// can/should be completed?
|
||||
}
|
||||
}
|
||||
|
||||
void AddEagerCompletionForVariableChildren(
|
||||
const gd::Variable& variable,
|
||||
const gd::String& variableName,
|
||||
const ExpressionParserLocation& location) {
|
||||
if (variable.GetType() == gd::Variable::Structure) {
|
||||
gd::String prefix = variableName + ".";
|
||||
for (const auto& name : variable.GetAllChildrenNames()) {
|
||||
gd::String completion =
|
||||
IsIdentifierSafe(name)
|
||||
? (prefix + name)
|
||||
: (variableName + "[" +
|
||||
gd::ExpressionParser2NodePrinter::PrintStringLiteral(name) +
|
||||
"]");
|
||||
|
||||
const auto& childVariable = variable.GetChild(name);
|
||||
ExpressionCompletionDescription description(
|
||||
ExpressionCompletionDescription::Variable,
|
||||
location.GetStartPosition(),
|
||||
location.GetEndPosition());
|
||||
description.SetCompletion(completion);
|
||||
description.SetVariableType(childVariable.GetType());
|
||||
completions.push_back(description);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AddCompletionsForVariablesMatchingSearch(
|
||||
const gd::VariablesContainer& variablesContainer,
|
||||
const gd::String& search,
|
||||
const ExpressionParserLocation& location,
|
||||
bool eagerlyCompleteIfExactMatch = false) {
|
||||
const ExpressionParserLocation& location) {
|
||||
variablesContainer.ForEachVariableMatchingSearch(
|
||||
search,
|
||||
[&](const gd::String& variableName, const gd::Variable& variable) {
|
||||
@@ -934,11 +769,6 @@ class GD_CORE_API ExpressionCompletionFinder
|
||||
description.SetCompletion(variableName);
|
||||
description.SetVariableType(variable.GetType());
|
||||
completions.push_back(description);
|
||||
|
||||
if (eagerlyCompleteIfExactMatch && variableName == search) {
|
||||
AddEagerCompletionForVariableChildren(
|
||||
variable, variableName, location);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -946,8 +776,7 @@ class GD_CORE_API ExpressionCompletionFinder
|
||||
const gd::ObjectsContainersList& objectsContainersList,
|
||||
const gd::String& objectOrGroupName,
|
||||
const gd::String& search,
|
||||
const ExpressionParserLocation& location,
|
||||
bool eagerlyCompleteIfExactMatch) {
|
||||
const ExpressionParserLocation& location) {
|
||||
objectsContainersList.ForEachObjectOrGroupVariableMatchingSearch(
|
||||
objectOrGroupName,
|
||||
search,
|
||||
@@ -959,11 +788,6 @@ class GD_CORE_API ExpressionCompletionFinder
|
||||
description.SetCompletion(variableName);
|
||||
description.SetVariableType(variable.GetType());
|
||||
completions.push_back(description);
|
||||
|
||||
if (eagerlyCompleteIfExactMatch && variableName == search) {
|
||||
AddEagerCompletionForVariableChildren(
|
||||
variable, variableName, location);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -971,27 +795,25 @@ class GD_CORE_API ExpressionCompletionFinder
|
||||
const gd::String& search,
|
||||
const gd::String& type,
|
||||
const ExpressionParserLocation& location) {
|
||||
projectScopedContainers.GetObjectsContainersList()
|
||||
.ForEachNameMatchingSearch(
|
||||
search,
|
||||
[&](const gd::String& name,
|
||||
const gd::ObjectConfiguration* objectConfiguration) {
|
||||
ExpressionCompletionDescription description(
|
||||
ExpressionCompletionDescription::Object,
|
||||
location.GetStartPosition(),
|
||||
location.GetEndPosition());
|
||||
description.SetObjectConfiguration(objectConfiguration);
|
||||
description.SetCompletion(name);
|
||||
description.SetType(type);
|
||||
completions.push_back(description);
|
||||
});
|
||||
projectScopedContainers.GetObjectsContainersList().ForEachNameMatchingSearch(
|
||||
search,
|
||||
[&](const gd::String& name,
|
||||
const gd::ObjectConfiguration* objectConfiguration) {
|
||||
ExpressionCompletionDescription description(
|
||||
ExpressionCompletionDescription::Object,
|
||||
location.GetStartPosition(),
|
||||
location.GetEndPosition());
|
||||
description.SetObjectConfiguration(objectConfiguration);
|
||||
description.SetCompletion(name);
|
||||
description.SetType(type);
|
||||
completions.push_back(description);
|
||||
});
|
||||
}
|
||||
|
||||
void AddCompletionsForObjectsAndVariablesMatchingSearch(
|
||||
const gd::String& search,
|
||||
const gd::String& type,
|
||||
const ExpressionParserLocation& location,
|
||||
bool eagerlyCompleteIfExactMatch) {
|
||||
const ExpressionParserLocation& location) {
|
||||
projectScopedContainers.ForEachIdentifierMatchingSearch(
|
||||
search,
|
||||
[&](const gd::String& objectName,
|
||||
@@ -1013,11 +835,6 @@ class GD_CORE_API ExpressionCompletionFinder
|
||||
description.SetCompletion(variableName);
|
||||
description.SetVariableType(variable.GetType());
|
||||
completions.push_back(description);
|
||||
|
||||
if (eagerlyCompleteIfExactMatch && variableName == search) {
|
||||
AddEagerCompletionForVariableChildren(
|
||||
variable, variableName, location);
|
||||
}
|
||||
},
|
||||
[&](const gd::NamedPropertyDescriptor& property) {
|
||||
// Ignore properties here.
|
||||
@@ -1028,7 +845,7 @@ class GD_CORE_API ExpressionCompletionFinder
|
||||
}
|
||||
|
||||
void AddCompletionsForAllIdentifiersMatchingSearch(const gd::String& search,
|
||||
const gd::String& type) {
|
||||
const gd::String& type) {
|
||||
AddCompletionsForAllIdentifiersMatchingSearch(
|
||||
search,
|
||||
type,
|
||||
@@ -1038,8 +855,7 @@ class GD_CORE_API ExpressionCompletionFinder
|
||||
void AddCompletionsForAllIdentifiersMatchingSearch(
|
||||
const gd::String& search,
|
||||
const gd::String& type,
|
||||
const ExpressionParserLocation& location,
|
||||
bool eagerlyCompleteIfExactMatch = false) {
|
||||
const ExpressionParserLocation& location) {
|
||||
projectScopedContainers.ForEachIdentifierMatchingSearch(
|
||||
search,
|
||||
[&](const gd::String& objectName,
|
||||
@@ -1061,11 +877,6 @@ class GD_CORE_API ExpressionCompletionFinder
|
||||
description.SetCompletion(variableName);
|
||||
description.SetVariableType(variable.GetType());
|
||||
completions.push_back(description);
|
||||
|
||||
if (eagerlyCompleteIfExactMatch && variableName == search) {
|
||||
AddEagerCompletionForVariableChildren(
|
||||
variable, variableName, location);
|
||||
}
|
||||
},
|
||||
[&](const gd::NamedPropertyDescriptor& property) {
|
||||
ExpressionCompletionDescription description(
|
||||
@@ -1093,14 +904,11 @@ class GD_CORE_API ExpressionCompletionFinder
|
||||
const gd::String& rootType_,
|
||||
size_t searchedPosition_,
|
||||
gd::ExpressionNode* maybeParentNodeAtLocation_)
|
||||
: searchedPosition(searchedPosition_),
|
||||
maybeParentNodeAtLocation(maybeParentNodeAtLocation_),
|
||||
platform(platform_),
|
||||
: platform(platform_),
|
||||
projectScopedContainers(projectScopedContainers_),
|
||||
rootType(rootType_),
|
||||
rootObjectName("") // Always empty, might be changed if variable fields
|
||||
// in the editor are changed to use completion.
|
||||
{};
|
||||
searchedPosition(searchedPosition_),
|
||||
maybeParentNodeAtLocation(maybeParentNodeAtLocation_){};
|
||||
|
||||
std::vector<ExpressionCompletionDescription> completions;
|
||||
size_t searchedPosition;
|
||||
@@ -1109,7 +917,6 @@ class GD_CORE_API ExpressionCompletionFinder
|
||||
const gd::Platform& platform;
|
||||
const gd::ProjectScopedContainers& projectScopedContainers;
|
||||
const gd::String rootType;
|
||||
const gd::String rootObjectName;
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
|
@@ -263,17 +263,11 @@ ExpressionValidator::Type ExpressionValidator::ValidateFunction(
|
||||
}
|
||||
|
||||
if (gd::MetadataProvider::IsBadExpressionMetadata(metadata)) {
|
||||
if (function.functionName.empty()) {
|
||||
RaiseError("invalid_function_name",
|
||||
_("Enter the name of the function to call."),
|
||||
function.location);
|
||||
} else {
|
||||
RaiseError("invalid_function_name",
|
||||
RaiseError("invalid_function_name",
|
||||
_("Cannot find an expression with this name: ") +
|
||||
function.functionName + "\n" +
|
||||
_("Double check that you've not made any typo in the name."),
|
||||
function.location);
|
||||
}
|
||||
return returnType;
|
||||
}
|
||||
|
||||
|
@@ -1,374 +0,0 @@
|
||||
/*
|
||||
* GDevelop Core
|
||||
* Copyright 2008-present Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "GDCore/Events/Parsers/ExpressionParser2Node.h"
|
||||
#include "GDCore/Events/Parsers/ExpressionParser2NodeWorker.h"
|
||||
#include "GDCore/Extensions/Metadata/ExpressionMetadata.h"
|
||||
#include "GDCore/Extensions/Metadata/MetadataProvider.h"
|
||||
#include "GDCore/Extensions/Metadata/ObjectMetadata.h"
|
||||
#include "GDCore/Extensions/Metadata/ParameterMetadata.h"
|
||||
#include "GDCore/Project/ProjectScopedContainers.h"
|
||||
#include "GDCore/Project/Variable.h"
|
||||
#include "GDCore/Tools/Localization.h"
|
||||
|
||||
namespace gd {
|
||||
class Expression;
|
||||
class ObjectsContainer;
|
||||
class Platform;
|
||||
class ParameterMetadata;
|
||||
class ExpressionMetadata;
|
||||
} // namespace gd
|
||||
|
||||
namespace gd {
|
||||
|
||||
/**
|
||||
* \brief Contains a variables container or a variable. Useful
|
||||
* to refer to the parent of a variable (which can be a VariablesContainer
|
||||
* or another Variable).
|
||||
*/
|
||||
struct VariableAndItsParent {
|
||||
const gd::VariablesContainer* parentVariablesContainer;
|
||||
const gd::Variable* parentVariable;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Find the last parent (i.e: the variables container) of a node
|
||||
* representing a variable.
|
||||
*
|
||||
* Useful for completions, to know which variables can be entered in a node.
|
||||
*
|
||||
* \see gd::ExpressionParser2
|
||||
*/
|
||||
class GD_CORE_API ExpressionVariableParentFinder
|
||||
: public ExpressionParser2NodeWorker {
|
||||
public:
|
||||
static VariableAndItsParent GetLastParentOfNode(
|
||||
const gd::Platform& platform,
|
||||
const gd::ProjectScopedContainers& projectScopedContainers,
|
||||
gd::ExpressionNode& node) {
|
||||
gd::ExpressionVariableParentFinder typeFinder(platform,
|
||||
projectScopedContainers);
|
||||
node.Visit(typeFinder);
|
||||
return typeFinder.variableAndItsParent;
|
||||
}
|
||||
|
||||
virtual ~ExpressionVariableParentFinder(){};
|
||||
|
||||
protected:
|
||||
ExpressionVariableParentFinder(
|
||||
const gd::Platform& platform_,
|
||||
const gd::ProjectScopedContainers& projectScopedContainers_)
|
||||
: platform(platform_),
|
||||
projectScopedContainers(projectScopedContainers_),
|
||||
variableNode(nullptr),
|
||||
thisIsALegacyPrescopedVariable(false),
|
||||
bailOutBecauseEmptyVariableName(false),
|
||||
legacyPrescopedVariablesContainer(nullptr),
|
||||
variableAndItsParent{} {};
|
||||
|
||||
void OnVisitSubExpressionNode(SubExpressionNode& node) override {}
|
||||
void OnVisitOperatorNode(OperatorNode& node) override {}
|
||||
void OnVisitUnaryOperatorNode(UnaryOperatorNode& node) override {}
|
||||
void OnVisitNumberNode(NumberNode& node) override {}
|
||||
void OnVisitTextNode(TextNode& node) override {}
|
||||
void OnVisitVariableNode(VariableNode& node) override {
|
||||
if (variableNode != nullptr) {
|
||||
// This is not possible
|
||||
return;
|
||||
}
|
||||
variableNode = &node;
|
||||
|
||||
// Check if the parent is a function call, in which we might be dealing
|
||||
// with a legacy pre-scoped variable parameter:
|
||||
if (node.parent) node.parent->Visit(*this);
|
||||
|
||||
if (thisIsALegacyPrescopedVariable) {
|
||||
// The node represents a variable name, and the variables container
|
||||
// containing it was identified in the FunctionCallNode.
|
||||
childVariableNames.insert(childVariableNames.begin(), node.name);
|
||||
if (legacyPrescopedVariablesContainer)
|
||||
variableAndItsParent = WalkUntilLastParent(
|
||||
*legacyPrescopedVariablesContainer, childVariableNames);
|
||||
} else {
|
||||
// Otherwise, the identifier is to be interpreted as usual:
|
||||
// it can be an object (on which a variable is accessed),
|
||||
// or a variable.
|
||||
projectScopedContainers.MatchIdentifierWithName<void>(
|
||||
node.name,
|
||||
[&]() {
|
||||
// This is an object.
|
||||
const auto* variablesContainer =
|
||||
projectScopedContainers.GetObjectsContainersList()
|
||||
.GetObjectOrGroupVariablesContainer(node.name);
|
||||
if (variablesContainer)
|
||||
variableAndItsParent =
|
||||
WalkUntilLastParent(*variablesContainer, childVariableNames);
|
||||
},
|
||||
[&]() {
|
||||
// This is a variable.
|
||||
if (projectScopedContainers.GetVariablesContainersList().Has(
|
||||
node.name)) {
|
||||
variableAndItsParent = WalkUntilLastParent(
|
||||
projectScopedContainers.GetVariablesContainersList().Get(
|
||||
node.name),
|
||||
childVariableNames);
|
||||
}
|
||||
},
|
||||
[&]() {
|
||||
// Ignore properties here.
|
||||
// There is no support for "children" of properties.
|
||||
},
|
||||
[&]() {
|
||||
// Ignore parameters here.
|
||||
// There is no support for "children" of parameters.
|
||||
},
|
||||
[&]() {
|
||||
// Ignore unrecognised identifiers here.
|
||||
});
|
||||
}
|
||||
}
|
||||
void OnVisitVariableAccessorNode(VariableAccessorNode& node) override {
|
||||
if (node.name.empty() && node.child) {
|
||||
// A variable accessor should always have a name if it has a child (i.e:
|
||||
// another accessor). While the parser may have generated an empty name,
|
||||
// flag this so we avoid finding a wrong parent (and so, run the risk of
|
||||
// giving wrong autocompletions).
|
||||
bailOutBecauseEmptyVariableName = true;
|
||||
}
|
||||
childVariableNames.insert(childVariableNames.begin(), node.name);
|
||||
if (node.parent) node.parent->Visit(*this);
|
||||
}
|
||||
void OnVisitIdentifierNode(IdentifierNode& node) override {
|
||||
if (variableNode != nullptr) {
|
||||
// This is not possible
|
||||
return;
|
||||
}
|
||||
// This node is not necessarily a variable node.
|
||||
// It will be checked when visiting the FunctionCallNode, just after.
|
||||
variableNode = &node;
|
||||
|
||||
// Check if the parent is a function call, in which we might be dealing
|
||||
// with a legacy pre-scoped variable parameter:
|
||||
if (node.parent) node.parent->Visit(*this);
|
||||
|
||||
if (thisIsALegacyPrescopedVariable) {
|
||||
// The identifier represents a variable name, and the variables container
|
||||
// containing it was identified in the FunctionCallNode.
|
||||
if (!node.childIdentifierName.empty())
|
||||
childVariableNames.insert(childVariableNames.begin(),
|
||||
node.childIdentifierName);
|
||||
childVariableNames.insert(childVariableNames.begin(),
|
||||
node.identifierName);
|
||||
|
||||
if (legacyPrescopedVariablesContainer)
|
||||
variableAndItsParent = WalkUntilLastParent(
|
||||
*legacyPrescopedVariablesContainer, childVariableNames);
|
||||
|
||||
} else {
|
||||
// Otherwise, the identifier is to be interpreted as usual:
|
||||
// it can be an object (on which a variable is accessed),
|
||||
// or a variable.
|
||||
projectScopedContainers.MatchIdentifierWithName<void>(
|
||||
node.identifierName,
|
||||
[&]() {
|
||||
// This is an object.
|
||||
if (!node.childIdentifierName.empty())
|
||||
childVariableNames.insert(childVariableNames.begin(),
|
||||
node.childIdentifierName);
|
||||
|
||||
const auto* variablesContainer =
|
||||
projectScopedContainers.GetObjectsContainersList()
|
||||
.GetObjectOrGroupVariablesContainer(node.identifierName);
|
||||
if (variablesContainer)
|
||||
variableAndItsParent =
|
||||
WalkUntilLastParent(*variablesContainer, childVariableNames);
|
||||
},
|
||||
[&]() {
|
||||
// This is a variable.
|
||||
if (!node.childIdentifierName.empty())
|
||||
childVariableNames.insert(childVariableNames.begin(),
|
||||
node.childIdentifierName);
|
||||
|
||||
if (projectScopedContainers.GetVariablesContainersList().Has(
|
||||
node.identifierName)) {
|
||||
variableAndItsParent = WalkUntilLastParent(
|
||||
projectScopedContainers.GetVariablesContainersList().Get(
|
||||
node.identifierName),
|
||||
childVariableNames);
|
||||
}
|
||||
},
|
||||
[&]() {
|
||||
// Ignore properties here.
|
||||
// There is no support for "children" of properties.
|
||||
},
|
||||
[&]() {
|
||||
// Ignore parameters here.
|
||||
// There is no support for "children" of properties.
|
||||
},
|
||||
[&]() {
|
||||
// Ignore unrecognised identifiers here.
|
||||
});
|
||||
}
|
||||
}
|
||||
void OnVisitEmptyNode(EmptyNode& node) override {}
|
||||
void OnVisitObjectFunctionNameNode(ObjectFunctionNameNode& node) override {}
|
||||
void OnVisitVariableBracketAccessorNode(
|
||||
VariableBracketAccessorNode& node) override {
|
||||
// Add a child with an empty name, which will be interpreted as
|
||||
// "take the first child/item of the structure/array".
|
||||
childVariableNames.insert(childVariableNames.begin(), "");
|
||||
if (node.parent) node.parent->Visit(*this);
|
||||
}
|
||||
void OnVisitFunctionCallNode(FunctionCallNode& functionCall) override {
|
||||
if (variableNode == nullptr) {
|
||||
return;
|
||||
}
|
||||
int parameterIndex = -1;
|
||||
for (int i = 0; i < functionCall.parameters.size(); i++) {
|
||||
if (functionCall.parameters.at(i).get() == variableNode) {
|
||||
parameterIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (parameterIndex < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto& objectsContainersList =
|
||||
projectScopedContainers.GetObjectsContainersList();
|
||||
|
||||
const gd::ParameterMetadata* parameterMetadata =
|
||||
MetadataProvider::GetFunctionCallParameterMetadata(
|
||||
platform, objectsContainersList, functionCall, parameterIndex);
|
||||
if (parameterMetadata == nullptr) return; // Unexpected
|
||||
|
||||
// Support for legacy pre-scoped variables:
|
||||
if (parameterMetadata->GetValueTypeMetadata().IsLegacyPreScopedVariable()) {
|
||||
if (parameterMetadata->GetType() == "objectvar") {
|
||||
// Legacy convention where a "objectvar"
|
||||
// parameter represents a variable of the object represented by the
|
||||
// previous "object" parameter. The object on which the function is
|
||||
// called is returned if no previous parameters are objects.
|
||||
gd::String objectName = functionCall.objectName;
|
||||
for (int previousIndex = parameterIndex - 1; previousIndex >= 0;
|
||||
previousIndex--) {
|
||||
const gd::ParameterMetadata* previousParameterMetadata =
|
||||
MetadataProvider::GetFunctionCallParameterMetadata(
|
||||
platform, objectsContainersList, functionCall, previousIndex);
|
||||
if (previousParameterMetadata != nullptr &&
|
||||
gd::ParameterMetadata::IsObject(
|
||||
previousParameterMetadata->GetType())) {
|
||||
auto previousParameterNode =
|
||||
functionCall.parameters[previousIndex].get();
|
||||
IdentifierNode* objectNode =
|
||||
dynamic_cast<IdentifierNode*>(previousParameterNode);
|
||||
objectName = objectNode->identifierName;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
legacyPrescopedVariablesContainer =
|
||||
projectScopedContainers.GetObjectsContainersList()
|
||||
.GetObjectOrGroupVariablesContainer(objectName);
|
||||
thisIsALegacyPrescopedVariable = true;
|
||||
} else if (parameterMetadata->GetType() == "scenevar") {
|
||||
legacyPrescopedVariablesContainer =
|
||||
projectScopedContainers.GetVariablesContainersList()
|
||||
.GetBottomMostVariablesContainer();
|
||||
thisIsALegacyPrescopedVariable = true;
|
||||
} else if (parameterMetadata->GetType() == "globalvar") {
|
||||
legacyPrescopedVariablesContainer =
|
||||
projectScopedContainers.GetVariablesContainersList()
|
||||
.GetTopMostVariablesContainer();
|
||||
thisIsALegacyPrescopedVariable = true;
|
||||
}
|
||||
} else {
|
||||
thisIsALegacyPrescopedVariable = false;
|
||||
legacyPrescopedVariablesContainer = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
VariableAndItsParent WalkUntilLastParent(
|
||||
const gd::Variable& variable,
|
||||
const std::vector<gd::String>& childVariableNames,
|
||||
size_t startIndex = 0) {
|
||||
if (bailOutBecauseEmptyVariableName)
|
||||
return {}; // Do not even attempt to find the parent if we had an issue
|
||||
// when visiting nodes.
|
||||
|
||||
const gd::Variable* currentVariable = &variable;
|
||||
|
||||
// Walk until size - 1 as we want the last parent.
|
||||
for (size_t index = startIndex; index + 1 < childVariableNames.size();
|
||||
++index) {
|
||||
const gd::String& childName = childVariableNames[index];
|
||||
|
||||
if (childName.empty()) {
|
||||
if (currentVariable->GetChildrenCount() == 0) {
|
||||
// The array or structure is empty, we can't walk through it - there
|
||||
// is no "parent".
|
||||
return {};
|
||||
}
|
||||
|
||||
if (currentVariable->GetType() == gd::Variable::Array) {
|
||||
currentVariable = ¤tVariable->GetAtIndex(0);
|
||||
} else {
|
||||
currentVariable =
|
||||
currentVariable->GetAllChildren().begin()->second.get();
|
||||
}
|
||||
} else {
|
||||
if (!currentVariable->HasChild(childName)) {
|
||||
// Non existing child - there is no "parent".
|
||||
return {};
|
||||
}
|
||||
|
||||
currentVariable = ¤tVariable->GetChild(childName);
|
||||
}
|
||||
}
|
||||
|
||||
// Return the last parent of the chain of variables (so not the last
|
||||
// variable but the one before it).
|
||||
return {.parentVariable = currentVariable};
|
||||
}
|
||||
|
||||
VariableAndItsParent WalkUntilLastParent(
|
||||
const gd::VariablesContainer& variablesContainer,
|
||||
const std::vector<gd::String>& childVariableNames) {
|
||||
if (bailOutBecauseEmptyVariableName)
|
||||
return {}; // Do not even attempt to find the parent if we had an issue
|
||||
// when visiting nodes.
|
||||
if (childVariableNames.empty())
|
||||
return {}; // There is no "parent" to the variables container itself.
|
||||
|
||||
const gd::String& firstChildName = *childVariableNames.begin();
|
||||
|
||||
const gd::Variable* variable = variablesContainer.Has(firstChildName)
|
||||
? &variablesContainer.Get(firstChildName)
|
||||
: nullptr;
|
||||
if (childVariableNames.size() == 1 || !variable)
|
||||
return {// Only one child: the parent is the variables container itself.
|
||||
.parentVariablesContainer = &variablesContainer};
|
||||
|
||||
return WalkUntilLastParent(*variable, childVariableNames, 1);
|
||||
}
|
||||
|
||||
gd::ExpressionNode* variableNode;
|
||||
std::vector<gd::String> childVariableNames;
|
||||
bool thisIsALegacyPrescopedVariable;
|
||||
bool bailOutBecauseEmptyVariableName;
|
||||
const gd::VariablesContainer* legacyPrescopedVariablesContainer;
|
||||
VariableAndItsParent variableAndItsParent;
|
||||
|
||||
const gd::Platform& platform;
|
||||
const gd::ProjectScopedContainers& projectScopedContainers;
|
||||
};
|
||||
|
||||
} // namespace gd
|
@@ -1,111 +0,0 @@
|
||||
/*
|
||||
* GDevelop Core
|
||||
* Copyright 2008-2023 Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#include "ObjectAssetSerializer.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "GDCore/Extensions/Builtin/SpriteExtension/SpriteObject.h"
|
||||
#include "GDCore/Extensions/Metadata/BehaviorMetadata.h"
|
||||
#include "GDCore/Extensions/Metadata/MetadataProvider.h"
|
||||
#include "GDCore/Extensions/Platform.h"
|
||||
#include "GDCore/Extensions/PlatformExtension.h"
|
||||
#include "GDCore/IDE/Project/AssetResourcePathCleaner.h"
|
||||
#include "GDCore/IDE/Project/ResourcesInUseHelper.h"
|
||||
#include "GDCore/IDE/Project/ResourcesRenamer.h"
|
||||
#include "GDCore/Project/Behavior.h"
|
||||
#include "GDCore/Project/CustomBehavior.h"
|
||||
#include "GDCore/Project/EventsFunctionsExtension.h"
|
||||
#include "GDCore/Project/Layout.h"
|
||||
#include "GDCore/Project/Object.h"
|
||||
#include "GDCore/Project/Project.h"
|
||||
#include "GDCore/Project/PropertyDescriptor.h"
|
||||
#include "GDCore/Serialization/SerializerElement.h"
|
||||
#include "GDCore/Tools/Log.h"
|
||||
|
||||
namespace gd {
|
||||
|
||||
gd::String
|
||||
ObjectAssetSerializer::GetObjectExtensionName(const gd::Object &object) {
|
||||
const gd::String &type = object.GetType();
|
||||
const auto separatorIndex =
|
||||
type.find(PlatformExtension::GetNamespaceSeparator());
|
||||
return separatorIndex != std::string::npos ? type.substr(0, separatorIndex)
|
||||
: "";
|
||||
}
|
||||
|
||||
void ObjectAssetSerializer::SerializeTo(
|
||||
gd::Project &project, const gd::Object &object,
|
||||
const gd::String &objectFullName, SerializerElement &element,
|
||||
std::vector<gd::String> &usedResourceNames) {
|
||||
auto cleanObject = object.Clone();
|
||||
cleanObject->GetVariables().Clear();
|
||||
cleanObject->GetEffects().Clear();
|
||||
for (auto &&behaviorName : cleanObject->GetAllBehaviorNames()) {
|
||||
cleanObject->RemoveBehavior(behaviorName);
|
||||
}
|
||||
|
||||
gd::String extensionName = GetObjectExtensionName(*cleanObject);
|
||||
|
||||
element.SetAttribute("id", "");
|
||||
element.SetAttribute("name", "");
|
||||
element.SetAttribute("license", "");
|
||||
if (project.HasEventsFunctionsExtensionNamed(extensionName)) {
|
||||
auto &extension = project.GetEventsFunctionsExtension(extensionName);
|
||||
element.SetAttribute("description", extension.GetShortDescription());
|
||||
}
|
||||
element.SetAttribute("gdevelopVersion", "");
|
||||
element.SetAttribute("version", "");
|
||||
element.SetIntAttribute("animationsCount", 1);
|
||||
element.SetIntAttribute("maxFramesCount", 1);
|
||||
// TODO Find the right object dimensions.
|
||||
element.SetIntAttribute("width", 0);
|
||||
element.SetIntAttribute("height", 0);
|
||||
SerializerElement &authorsElement = element.AddChild("authors");
|
||||
authorsElement.ConsiderAsArrayOf("author");
|
||||
SerializerElement &tagsElement = element.AddChild("tags");
|
||||
tagsElement.ConsiderAsArrayOf("tag");
|
||||
|
||||
SerializerElement &objectAssetsElement = element.AddChild("objectAssets");
|
||||
objectAssetsElement.ConsiderAsArrayOf("objectAsset");
|
||||
SerializerElement &objectAssetElement =
|
||||
objectAssetsElement.AddChild("objectAsset");
|
||||
|
||||
cleanObject->SerializeTo(objectAssetElement.AddChild("object"));
|
||||
|
||||
SerializerElement &resourcesElement =
|
||||
objectAssetElement.AddChild("resources");
|
||||
resourcesElement.ConsiderAsArrayOf("resource");
|
||||
auto &resourcesManager = project.GetResourcesManager();
|
||||
gd::ResourcesInUseHelper resourcesInUse(resourcesManager);
|
||||
cleanObject->GetConfiguration().ExposeResources(resourcesInUse);
|
||||
for (auto &&resourceName : resourcesInUse.GetAllResources()) {
|
||||
if (resourceName.length() == 0) {
|
||||
continue;
|
||||
}
|
||||
usedResourceNames.push_back(resourceName);
|
||||
auto &resource = resourcesManager.GetResource(resourceName);
|
||||
SerializerElement &resourceElement = resourcesElement.AddChild("resource");
|
||||
resource.SerializeTo(resourceElement);
|
||||
resourceElement.SetAttribute("kind", resource.GetKind());
|
||||
resourceElement.SetAttribute("name", resource.GetName());
|
||||
}
|
||||
|
||||
SerializerElement &requiredExtensionsElement =
|
||||
objectAssetElement.AddChild("requiredExtensions");
|
||||
requiredExtensionsElement.ConsiderAsArrayOf("requiredExtension");
|
||||
if (project.HasEventsFunctionsExtensionNamed(extensionName)) {
|
||||
SerializerElement &requiredExtensionElement =
|
||||
requiredExtensionsElement.AddChild("requiredExtension");
|
||||
requiredExtensionElement.SetAttribute("extensionName", extensionName);
|
||||
requiredExtensionElement.SetAttribute("extensionVersion", "1.0.0");
|
||||
}
|
||||
|
||||
// TODO This can be removed when the asset script no longer require it.
|
||||
SerializerElement &customizationElement =
|
||||
objectAssetElement.AddChild("customization");
|
||||
customizationElement.ConsiderAsArrayOf("empty");
|
||||
}
|
||||
} // namespace gd
|
@@ -1,57 +0,0 @@
|
||||
/*
|
||||
* GDevelop Core
|
||||
* Copyright 2008-2023 Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#pragma once
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
#include "GDCore/String.h"
|
||||
|
||||
namespace gd {
|
||||
class Object;
|
||||
class ExtensionDependency;
|
||||
class PropertyDescriptor;
|
||||
class Project;
|
||||
class Layout;
|
||||
class ArbitraryResourceWorker;
|
||||
class InitialInstance;
|
||||
class SerializerElement;
|
||||
class EffectsContainer;
|
||||
class AbstractFileSystem;
|
||||
} // namespace gd
|
||||
|
||||
namespace gd {
|
||||
|
||||
/**
|
||||
* \brief Serialize objects into an asset for the store.
|
||||
*
|
||||
* \ingroup IDE
|
||||
*/
|
||||
class GD_CORE_API ObjectAssetSerializer {
|
||||
public:
|
||||
/**
|
||||
* \brief Serialize an object into an asset.
|
||||
*
|
||||
* \param project The project that contains the object and its resources.
|
||||
* It's not actually modified.
|
||||
* \param object The object to serialize as an asset.
|
||||
* \param objectFullName The object name with spaces instead of PascalCase.
|
||||
* \param element The element where the asset is serialize.
|
||||
* \param usedResourceNames Return the names of the resources used by the asset.
|
||||
*/
|
||||
static void
|
||||
SerializeTo(gd::Project &project, const gd::Object &object,
|
||||
const gd::String &objectFullName, SerializerElement &element,
|
||||
std::vector<gd::String> &usedResourceNames);
|
||||
|
||||
~ObjectAssetSerializer(){};
|
||||
|
||||
private:
|
||||
ObjectAssetSerializer(){};
|
||||
|
||||
static gd::String GetObjectExtensionName(const gd::Object &object);
|
||||
};
|
||||
|
||||
} // namespace gd
|
@@ -52,16 +52,6 @@ void ArbitraryResourceWorker::ExposeModel3D(gd::String& resourceName){
|
||||
// do.
|
||||
};
|
||||
|
||||
void ArbitraryResourceWorker::ExposeAtlas(gd::String& resourceName){
|
||||
// Nothing to do by default - each child class can define here the action to
|
||||
// do.
|
||||
};
|
||||
|
||||
void ArbitraryResourceWorker::ExposeSpine(gd::String& resourceName){
|
||||
// Nothing to do by default - each child class can define here the action to
|
||||
// do.
|
||||
};
|
||||
|
||||
void ArbitraryResourceWorker::ExposeVideo(gd::String& videoName){
|
||||
// Nothing to do by default - each child class can define here the action to
|
||||
// do.
|
||||
@@ -73,10 +63,14 @@ void ArbitraryResourceWorker::ExposeBitmapFont(gd::String& bitmapFontName){
|
||||
};
|
||||
|
||||
void ArbitraryResourceWorker::ExposeAudio(gd::String& audioName) {
|
||||
if (resourcesManager->HasResource(audioName) &&
|
||||
resourcesManager->GetResource(audioName).GetKind() == "audio") {
|
||||
// Nothing to do, the audio is a reference to a proper resource.
|
||||
return;
|
||||
for (auto resources : GetResources()) {
|
||||
if (!resources) continue;
|
||||
|
||||
if (resources->HasResource(audioName) &&
|
||||
resources->GetResource(audioName).GetKind() == "audio") {
|
||||
// Nothing to do, the audio is a reference to a proper resource.
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// For compatibility with older projects (where events were referring to files
|
||||
@@ -86,10 +80,14 @@ void ArbitraryResourceWorker::ExposeAudio(gd::String& audioName) {
|
||||
};
|
||||
|
||||
void ArbitraryResourceWorker::ExposeFont(gd::String& fontName) {
|
||||
if (resourcesManager->HasResource(fontName) &&
|
||||
resourcesManager->GetResource(fontName).GetKind() == "font") {
|
||||
// Nothing to do, the font is a reference to a proper resource.
|
||||
return;
|
||||
for (auto resources : GetResources()) {
|
||||
if (!resources) continue;
|
||||
|
||||
if (resources->HasResource(fontName) &&
|
||||
resources->GetResource(fontName).GetKind() == "font") {
|
||||
// Nothing to do, the font is a reference to a proper resource.
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// For compatibility with older projects (where events were referring to files
|
||||
@@ -98,7 +96,12 @@ void ArbitraryResourceWorker::ExposeFont(gd::String& fontName) {
|
||||
ExposeFile(fontName);
|
||||
};
|
||||
|
||||
void ArbitraryResourceWorker::ExposeResources() {
|
||||
void ArbitraryResourceWorker::ExposeResources(
|
||||
gd::ResourcesManager* resourcesManager) {
|
||||
if (!resourcesManager) return;
|
||||
|
||||
resourcesManagers.push_back(resourcesManager);
|
||||
|
||||
std::vector<gd::String> resources = resourcesManager->GetAllResourceNames();
|
||||
for (std::size_t i = 0; i < resources.size(); i++) {
|
||||
if (resourcesManager->GetResource(resources[i]).UseFile())
|
||||
@@ -107,6 +110,9 @@ void ArbitraryResourceWorker::ExposeResources() {
|
||||
}
|
||||
|
||||
void ArbitraryResourceWorker::ExposeEmbeddeds(gd::String& resourceName) {
|
||||
if (resourcesManagers.empty()) return;
|
||||
gd::ResourcesManager* resourcesManager = resourcesManagers[0];
|
||||
|
||||
gd::Resource& resource = resourcesManager->GetResource(resourceName);
|
||||
|
||||
if (!resource.GetMetadata().empty()) {
|
||||
@@ -130,7 +136,6 @@ void ArbitraryResourceWorker::ExposeEmbeddeds(gd::String& resourceName) {
|
||||
|
||||
gd::String potentiallyUpdatedTargetResourceName = targetResourceName;
|
||||
ExposeResourceWithType(targetResource.GetKind(), potentiallyUpdatedTargetResourceName);
|
||||
ExposeEmbeddeds(potentiallyUpdatedTargetResourceName);
|
||||
|
||||
if (potentiallyUpdatedTargetResourceName != targetResourceName) {
|
||||
// The resource name was renamed. Also update the mapping.
|
||||
@@ -171,7 +176,6 @@ void ArbitraryResourceWorker::ExposeResourceWithType(
|
||||
}
|
||||
if (resourceType == "tilemap") {
|
||||
ExposeTilemap(resourceName);
|
||||
ExposeEmbeddeds(resourceName);
|
||||
return;
|
||||
}
|
||||
if (resourceType == "tileset") {
|
||||
@@ -180,21 +184,12 @@ void ArbitraryResourceWorker::ExposeResourceWithType(
|
||||
}
|
||||
if (resourceType == "json") {
|
||||
ExposeJson(resourceName);
|
||||
ExposeEmbeddeds(resourceName);
|
||||
return;
|
||||
}
|
||||
if (resourceType == "video") {
|
||||
ExposeVideo(resourceName);
|
||||
return;
|
||||
}
|
||||
if (resourceType == "atlas") {
|
||||
ExposeAtlas(resourceName);
|
||||
return;
|
||||
}
|
||||
if (resourceType == "spine") {
|
||||
ExposeSpine(resourceName);
|
||||
return;
|
||||
}
|
||||
gd::LogError("Unexpected resource type: " + resourceType + " for: " + resourceName);
|
||||
return;
|
||||
}
|
||||
@@ -248,12 +243,10 @@ bool ResourceWorkerInEventsWorker::DoVisitInstruction(gd::Instruction& instructi
|
||||
} else if (parameterMetadata.GetType() == "jsonResource") {
|
||||
gd::String updatedParameterValue = parameterValue;
|
||||
worker.ExposeJson(updatedParameterValue);
|
||||
worker.ExposeEmbeddeds(updatedParameterValue);
|
||||
instruction.SetParameter(parameterIndex, updatedParameterValue);
|
||||
} else if (parameterMetadata.GetType() == "tilemapResource") {
|
||||
gd::String updatedParameterValue = parameterValue;
|
||||
worker.ExposeTilemap(updatedParameterValue);
|
||||
worker.ExposeEmbeddeds(updatedParameterValue);
|
||||
instruction.SetParameter(parameterIndex, updatedParameterValue);
|
||||
} else if (parameterMetadata.GetType() == "tilesetResource") {
|
||||
gd::String updatedParameterValue = parameterValue;
|
||||
@@ -263,14 +256,6 @@ bool ResourceWorkerInEventsWorker::DoVisitInstruction(gd::Instruction& instructi
|
||||
gd::String updatedParameterValue = parameterValue;
|
||||
worker.ExposeModel3D(updatedParameterValue);
|
||||
instruction.SetParameter(parameterIndex, updatedParameterValue);
|
||||
} else if (parameterMetadata.GetType() == "atlasResource") {
|
||||
gd::String updatedParameterValue = parameterValue;
|
||||
worker.ExposeAtlas(updatedParameterValue);
|
||||
instruction.SetParameter(parameterIndex, updatedParameterValue);
|
||||
} else if (parameterMetadata.GetType() == "spineResource") {
|
||||
gd::String updatedParameterValue = parameterValue;
|
||||
worker.ExposeSpine(updatedParameterValue);
|
||||
instruction.SetParameter(parameterIndex, updatedParameterValue);
|
||||
}
|
||||
});
|
||||
|
||||
|
@@ -42,9 +42,8 @@ namespace gd {
|
||||
* \ingroup IDE
|
||||
*/
|
||||
class GD_CORE_API ArbitraryResourceWorker {
|
||||
public:
|
||||
ArbitraryResourceWorker(gd::ResourcesManager &resourcesManager_)
|
||||
: resourcesManager(&resourcesManager_){};
|
||||
public:
|
||||
ArbitraryResourceWorker(){};
|
||||
virtual ~ArbitraryResourceWorker();
|
||||
|
||||
/**
|
||||
@@ -53,7 +52,7 @@ public:
|
||||
* first to ensure that resources are known so that images, shaders & audio
|
||||
* can make reference to them.
|
||||
*/
|
||||
void ExposeResources();
|
||||
void ExposeResources(gd::ResourcesManager *resourcesManager);
|
||||
|
||||
/**
|
||||
* \brief Expose a resource from a given type.
|
||||
@@ -96,16 +95,6 @@ public:
|
||||
* \brief Expose a 3D model, which is always a reference to a "model3D" resource.
|
||||
*/
|
||||
virtual void ExposeModel3D(gd::String &resourceName);
|
||||
|
||||
/**
|
||||
* \brief Expose an atlas, which is always a reference to a "atlas" resource.
|
||||
*/
|
||||
virtual void ExposeAtlas(gd::String &resourceName);
|
||||
|
||||
/**
|
||||
* \brief Expose an spine, which is always a reference to a "spine" resource.
|
||||
*/
|
||||
virtual void ExposeSpine(gd::String &resourceName);
|
||||
|
||||
/**
|
||||
* \brief Expose a video, which is always a reference to a "video" resource.
|
||||
@@ -133,8 +122,10 @@ public:
|
||||
*/
|
||||
virtual void ExposeEmbeddeds(gd::String &resourceName);
|
||||
|
||||
protected:
|
||||
gd::ResourcesManager * resourcesManager;
|
||||
protected:
|
||||
const std::vector<gd::ResourcesManager *> &GetResources() {
|
||||
return resourcesManagers;
|
||||
};
|
||||
|
||||
private:
|
||||
/**
|
||||
@@ -142,6 +133,8 @@ protected:
|
||||
* exposed as file (see ExposeFile).
|
||||
*/
|
||||
void ExposeResource(gd::Resource &resource);
|
||||
|
||||
std::vector<gd::ResourcesManager *> resourcesManagers;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@@ -1,74 +0,0 @@
|
||||
/*
|
||||
* GDevelop Core
|
||||
* Copyright 2008-2023 Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
|
||||
#include "AssetResourcePathCleaner.h"
|
||||
#include "GDCore/Project/Project.h"
|
||||
#include "GDCore/Project/ResourcesManager.h"
|
||||
#include "GDCore/String.h"
|
||||
|
||||
namespace gd {
|
||||
void AssetResourcePathCleaner::ExposeImage(gd::String &imageName) {
|
||||
ExposeResourceAsFile(imageName);
|
||||
}
|
||||
|
||||
void AssetResourcePathCleaner::ExposeAudio(gd::String &audioName) {
|
||||
ExposeResourceAsFile(audioName);
|
||||
}
|
||||
|
||||
void AssetResourcePathCleaner::ExposeFont(gd::String &fontName) {
|
||||
ExposeResourceAsFile(fontName);
|
||||
}
|
||||
|
||||
void AssetResourcePathCleaner::ExposeJson(gd::String &jsonName) {
|
||||
ExposeResourceAsFile(jsonName);
|
||||
}
|
||||
|
||||
void AssetResourcePathCleaner::ExposeTilemap(gd::String &tilemapName) {
|
||||
ExposeResourceAsFile(tilemapName);
|
||||
}
|
||||
|
||||
void AssetResourcePathCleaner::ExposeTileset(gd::String &tilesetName) {
|
||||
ExposeResourceAsFile(tilesetName);
|
||||
}
|
||||
|
||||
void AssetResourcePathCleaner::ExposeVideo(gd::String &videoName) {
|
||||
ExposeResourceAsFile(videoName);
|
||||
}
|
||||
|
||||
void AssetResourcePathCleaner::ExposeBitmapFont(gd::String &bitmapFontName) {
|
||||
ExposeResourceAsFile(bitmapFontName);
|
||||
}
|
||||
|
||||
void AssetResourcePathCleaner::ExposeResourceAsFile(gd::String &resourceName) {
|
||||
|
||||
auto &resource = resourcesManager->GetResource(resourceName);
|
||||
gd::String file = resource.GetFile();
|
||||
ExposeFile(file);
|
||||
|
||||
resourcesNameReverseMap[file] = resourceName;
|
||||
resourceName = file;
|
||||
}
|
||||
|
||||
void AssetResourcePathCleaner::ExposeFile(gd::String &resourceFilePath) {
|
||||
|
||||
size_t slashPos = resourceFilePath.find_last_of("/");
|
||||
size_t antiSlashPos = resourceFilePath.find_last_of("\\");
|
||||
size_t baseNamePos =
|
||||
slashPos == String::npos
|
||||
? antiSlashPos == String::npos ? 0 : (antiSlashPos + 1)
|
||||
: antiSlashPos == String::npos ? (slashPos + 1)
|
||||
: slashPos > antiSlashPos ? (slashPos + 1)
|
||||
: (antiSlashPos + 1);
|
||||
gd::String baseName =
|
||||
baseNamePos != 0
|
||||
? resourceFilePath.substr(baseNamePos, resourceFilePath.length())
|
||||
: resourceFilePath;
|
||||
|
||||
resourcesFileNameMap[resourceFilePath] = baseName;
|
||||
resourceFilePath = baseName;
|
||||
}
|
||||
|
||||
} // namespace gd
|
@@ -1,65 +0,0 @@
|
||||
/*
|
||||
* GDevelop Core
|
||||
* Copyright 2008-2023 Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "GDCore/IDE/Project/ArbitraryResourceWorker.h"
|
||||
#include "GDCore/IDE/Project/ResourcesMergingHelper.h"
|
||||
#include "GDCore/String.h"
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
namespace gd {
|
||||
class AbstractFileSystem;
|
||||
class Project;
|
||||
} // namespace gd
|
||||
|
||||
namespace gd {
|
||||
|
||||
/**
|
||||
* \brief AssetResourcePathCleaner is used when exporting an object as an asset.
|
||||
* It removes the folder from the path.
|
||||
*
|
||||
* \see ArbitraryResourceWorker
|
||||
*
|
||||
* \ingroup IDE
|
||||
*/
|
||||
class GD_CORE_API AssetResourcePathCleaner : public ArbitraryResourceWorker {
|
||||
public:
|
||||
AssetResourcePathCleaner(
|
||||
gd::ResourcesManager &resourcesManager,
|
||||
std::map<gd::String, gd::String> &resourcesFileNameMap_,
|
||||
std::map<gd::String, gd::String> &resourcesNameReverseMap_)
|
||||
: ArbitraryResourceWorker(resourcesManager),
|
||||
resourcesFileNameMap(resourcesFileNameMap_),
|
||||
resourcesNameReverseMap(resourcesNameReverseMap_){};
|
||||
virtual ~AssetResourcePathCleaner(){};
|
||||
|
||||
void ExposeImage(gd::String &imageName) override;
|
||||
void ExposeAudio(gd::String &audioName) override;
|
||||
void ExposeFont(gd::String &fontName) override;
|
||||
void ExposeJson(gd::String &jsonName) override;
|
||||
void ExposeTilemap(gd::String &tilemapName) override;
|
||||
void ExposeTileset(gd::String &tilesetName) override;
|
||||
void ExposeVideo(gd::String &videoName) override;
|
||||
void ExposeBitmapFont(gd::String &bitmapFontName) override;
|
||||
void ExposeFile(gd::String &resource) override;
|
||||
|
||||
protected:
|
||||
void ExposeResourceAsFile(gd::String &resourceName);
|
||||
|
||||
/**
|
||||
* New file names that can be accessed by their original name.
|
||||
*/
|
||||
std::map<gd::String, gd::String> &resourcesFileNameMap;
|
||||
|
||||
/**
|
||||
* Original resource names that can be accessed by their new name.
|
||||
*/
|
||||
std::map<gd::String, gd::String> &resourcesNameReverseMap;
|
||||
};
|
||||
|
||||
} // namespace gd
|
@@ -6,7 +6,7 @@
|
||||
namespace gd {
|
||||
|
||||
void ObjectsUsingResourceCollector::DoVisitObject(gd::Object& object) {
|
||||
gd::ResourceNameMatcher resourceNameMatcher(*resourcesManager, resourceName);
|
||||
gd::ResourceNameMatcher resourceNameMatcher(resourceName);
|
||||
|
||||
object.GetConfiguration().ExposeResources(resourceNameMatcher);
|
||||
if (resourceNameMatcher.AnyResourceMatches()) {
|
||||
|
@@ -4,7 +4,8 @@
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#ifndef ProjectObjectsUsingResourceCollector_H
|
||||
#define ProjectObjectsUsingResourceCollector_H
|
||||
|
||||
#include <vector>
|
||||
|
||||
@@ -20,10 +21,9 @@ namespace gd {
|
||||
|
||||
class GD_CORE_API ObjectsUsingResourceCollector
|
||||
: public ArbitraryObjectsWorker {
|
||||
public:
|
||||
ObjectsUsingResourceCollector(gd::ResourcesManager &resourcesManager_,
|
||||
const gd::String &resourceName_)
|
||||
: resourcesManager(&resourcesManager_), resourceName(resourceName_){};
|
||||
public:
|
||||
ObjectsUsingResourceCollector(const gd::String& resourceName_)
|
||||
: resourceName(resourceName_){};
|
||||
virtual ~ObjectsUsingResourceCollector();
|
||||
|
||||
std::vector<gd::String>& GetObjectNames() { return objectNames; }
|
||||
@@ -33,16 +33,12 @@ public:
|
||||
|
||||
std::vector<gd::String> objectNames;
|
||||
gd::String resourceName;
|
||||
gd::ResourcesManager *resourcesManager;
|
||||
};
|
||||
|
||||
class GD_CORE_API ResourceNameMatcher : public ArbitraryResourceWorker {
|
||||
public:
|
||||
ResourceNameMatcher(gd::ResourcesManager &resourcesManager,
|
||||
const gd::String &resourceName_)
|
||||
: resourceName(resourceName_),
|
||||
matchesResourceName(false), gd::ArbitraryResourceWorker(
|
||||
resourcesManager){};
|
||||
public:
|
||||
ResourceNameMatcher(const gd::String& resourceName_)
|
||||
: resourceName(resourceName_), matchesResourceName(false){};
|
||||
virtual ~ResourceNameMatcher(){};
|
||||
|
||||
bool AnyResourceMatches() { return matchesResourceName; }
|
||||
@@ -79,12 +75,6 @@ public:
|
||||
virtual void ExposeModel3D(gd::String& otherResourceName) override {
|
||||
MatchResourceName(otherResourceName);
|
||||
};
|
||||
virtual void ExposeAtlas(gd::String& otherResourceName) override {
|
||||
MatchResourceName(otherResourceName);
|
||||
};
|
||||
virtual void ExposeSpine(gd::String& otherResourceName) override {
|
||||
MatchResourceName(otherResourceName);
|
||||
};
|
||||
|
||||
void MatchResourceName(gd::String& otherResourceName) {
|
||||
if (otherResourceName == resourceName) matchesResourceName = true;
|
||||
@@ -95,3 +85,5 @@ public:
|
||||
};
|
||||
|
||||
}; // namespace gd
|
||||
|
||||
#endif // ProjectObjectsUsingResourceCollector_H
|
||||
|
@@ -18,9 +18,8 @@ namespace gd {
|
||||
std::vector<gd::String> ProjectResourcesAdder::GetAllUseless(
|
||||
gd::Project& project, const gd::String& resourceType) {
|
||||
std::vector<gd::String> unusedResources;
|
||||
|
||||
// Search for resources used in the project
|
||||
gd::ResourcesInUseHelper resourcesInUse(project.GetResourcesManager());
|
||||
gd::ResourcesInUseHelper resourcesInUse;
|
||||
gd::ResourceExposer::ExposeWholeProjectResources(project, resourcesInUse);
|
||||
std::set<gd::String>& usedResources = resourcesInUse.GetAll(resourceType);
|
||||
|
||||
|
@@ -25,29 +25,8 @@ bool ProjectResourcesCopier::CopyAllResourcesTo(
|
||||
bool updateOriginalProject,
|
||||
bool preserveAbsoluteFilenames,
|
||||
bool preserveDirectoryStructure) {
|
||||
if (updateOriginalProject) {
|
||||
gd::ProjectResourcesCopier::CopyAllResourcesTo(
|
||||
originalProject, originalProject, fs, destinationDirectory,
|
||||
preserveAbsoluteFilenames, preserveDirectoryStructure);
|
||||
} else {
|
||||
gd::Project clonedProject = originalProject;
|
||||
gd::ProjectResourcesCopier::CopyAllResourcesTo(
|
||||
originalProject, clonedProject, fs, destinationDirectory,
|
||||
preserveAbsoluteFilenames, preserveDirectoryStructure);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ProjectResourcesCopier::CopyAllResourcesTo(
|
||||
gd::Project& originalProject,
|
||||
gd::Project& clonedProject,
|
||||
AbstractFileSystem& fs,
|
||||
gd::String destinationDirectory,
|
||||
bool preserveAbsoluteFilenames,
|
||||
bool preserveDirectoryStructure) {
|
||||
|
||||
// Check if there are some resources with absolute filenames
|
||||
gd::ResourcesAbsolutePathChecker absolutePathChecker(originalProject.GetResourcesManager(), fs);
|
||||
gd::ResourcesAbsolutePathChecker absolutePathChecker(fs);
|
||||
gd::ResourceExposer::ExposeWholeProjectResources(originalProject, absolutePathChecker);
|
||||
|
||||
auto projectDirectory = fs.DirNameFrom(originalProject.GetProjectFile());
|
||||
@@ -55,14 +34,19 @@ bool ProjectResourcesCopier::CopyAllResourcesTo(
|
||||
<< destinationDirectory << "..." << std::endl;
|
||||
|
||||
// Get the resources to be copied
|
||||
gd::ResourcesMergingHelper resourcesMergingHelper(
|
||||
clonedProject.GetResourcesManager(), fs);
|
||||
gd::ResourcesMergingHelper resourcesMergingHelper(fs);
|
||||
resourcesMergingHelper.SetBaseDirectory(projectDirectory);
|
||||
resourcesMergingHelper.PreserveDirectoriesStructure(
|
||||
preserveDirectoryStructure);
|
||||
resourcesMergingHelper.PreserveAbsoluteFilenames(preserveAbsoluteFilenames);
|
||||
gd::ResourceExposer::ExposeWholeProjectResources(clonedProject,
|
||||
resourcesMergingHelper);
|
||||
resourcesMergingHelper.PreserveAbsoluteFilenames(
|
||||
preserveAbsoluteFilenames);
|
||||
|
||||
if (updateOriginalProject) {
|
||||
gd::ResourceExposer::ExposeWholeProjectResources(originalProject, resourcesMergingHelper);
|
||||
} else {
|
||||
std::shared_ptr<gd::Project> project(new gd::Project(originalProject));
|
||||
gd::ResourceExposer::ExposeWholeProjectResources(*project, resourcesMergingHelper);
|
||||
}
|
||||
|
||||
// Copy resources
|
||||
map<gd::String, gd::String>& resourcesNewFilename =
|
||||
|
@@ -3,10 +3,9 @@
|
||||
* Copyright 2008-present Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#ifndef PROJECTRESOURCESCOPIER_H
|
||||
#define PROJECTRESOURCESCOPIER_H
|
||||
#include "GDCore/String.h"
|
||||
|
||||
namespace gd {
|
||||
class Project;
|
||||
class AbstractFileSystem;
|
||||
@@ -48,14 +47,8 @@ class GD_CORE_API ProjectResourcesCopier {
|
||||
bool updateOriginalProject,
|
||||
bool preserveAbsoluteFilenames = true,
|
||||
bool preserveDirectoryStructure = true);
|
||||
|
||||
private:
|
||||
static bool CopyAllResourcesTo(gd::Project& originalProject,
|
||||
gd::Project& clonedProject,
|
||||
gd::AbstractFileSystem& fs,
|
||||
gd::String destinationDirectory,
|
||||
bool preserveAbsoluteFilenames = true,
|
||||
bool preserveDirectoryStructure = true);
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
|
||||
#endif // PROJECTRESOURCESCOPIER_H
|
||||
|
@@ -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 RESOURCESABSOLUTEPATHCHECKER_H
|
||||
#define RESOURCESABSOLUTEPATHCHECKER_H
|
||||
|
||||
#include "GDCore/IDE/AbstractFileSystem.h"
|
||||
#include "GDCore/IDE/Project/ArbitraryResourceWorker.h"
|
||||
@@ -21,10 +22,10 @@ namespace gd {
|
||||
*/
|
||||
class GD_CORE_API ResourcesAbsolutePathChecker
|
||||
: public ArbitraryResourceWorker {
|
||||
public:
|
||||
ResourcesAbsolutePathChecker(gd::ResourcesManager &resourcesManager,
|
||||
AbstractFileSystem &fileSystem)
|
||||
: ArbitraryResourceWorker(resourcesManager), hasAbsoluteFilenames(false),
|
||||
public:
|
||||
ResourcesAbsolutePathChecker(AbstractFileSystem& fileSystem)
|
||||
: ArbitraryResourceWorker(),
|
||||
hasAbsoluteFilenames(false),
|
||||
fs(fileSystem){};
|
||||
virtual ~ResourcesAbsolutePathChecker(){};
|
||||
|
||||
@@ -46,3 +47,5 @@ public:
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
|
||||
#endif // RESOURCESABSOLUTEPATHCHECKER_H
|
||||
|
@@ -1,25 +0,0 @@
|
||||
/*
|
||||
* GDevelop Core
|
||||
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
|
||||
#include "ResourcesInUseHelper.h"
|
||||
|
||||
namespace gd {
|
||||
|
||||
const std::vector<gd::String> ResourcesInUseHelper::resourceTypes = {
|
||||
"image", "audio", "font", "json", "tilemap",
|
||||
"tileset", "video", "bitmapFont", "model3D"};
|
||||
|
||||
const std::vector<gd::String> &ResourcesInUseHelper::GetAllResources() {
|
||||
allResources.clear();
|
||||
for (auto &&resourceType : gd::ResourcesInUseHelper::resourceTypes) {
|
||||
for (auto &&resourceName : GetAll(resourceType)) {
|
||||
allResources.push_back(resourceName);
|
||||
}
|
||||
}
|
||||
return allResources;
|
||||
}
|
||||
|
||||
} // namespace gd
|
@@ -4,7 +4,9 @@
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#if defined(GD_IDE_ONLY)
|
||||
#ifndef IMAGESUSEDINVENTORIZER_H
|
||||
#define IMAGESUSEDINVENTORIZER_H
|
||||
|
||||
#include <set>
|
||||
#include <vector>
|
||||
@@ -31,12 +33,10 @@ std::set<gd::String> & usedImages = resourcesInUse.GetAllImages();
|
||||
* \ingroup IDE
|
||||
*/
|
||||
class ResourcesInUseHelper : public gd::ArbitraryResourceWorker {
|
||||
public:
|
||||
ResourcesInUseHelper(gd::ResourcesManager &resourcesManager)
|
||||
: gd::ArbitraryResourceWorker(resourcesManager){};
|
||||
public:
|
||||
ResourcesInUseHelper() : gd::ArbitraryResourceWorker(){};
|
||||
virtual ~ResourcesInUseHelper(){};
|
||||
|
||||
const std::vector<gd::String>& GetAllResources();
|
||||
std::set<gd::String>& GetAllImages() { return GetAll("image"); };
|
||||
std::set<gd::String>& GetAllAudios() { return GetAll("audio"); };
|
||||
std::set<gd::String>& GetAllFonts() { return GetAll("font"); };
|
||||
@@ -46,8 +46,6 @@ public:
|
||||
std::set<gd::String>& GetAllVideos() { return GetAll("video"); };
|
||||
std::set<gd::String>& GetAllBitmapFonts() { return GetAll("bitmapFont"); };
|
||||
std::set<gd::String>& GetAll3DModels() { return GetAll("model3D"); };
|
||||
std::set<gd::String>& GetAllAtlases() { return GetAll("atlas"); };
|
||||
std::set<gd::String>& GetAllSpines() { return GetAll("spine"); };
|
||||
std::set<gd::String>& GetAll(const gd::String& resourceType) {
|
||||
if (resourceType == "image") return allImages;
|
||||
if (resourceType == "audio") return allAudios;
|
||||
@@ -58,8 +56,6 @@ public:
|
||||
if (resourceType == "video") return allVideos;
|
||||
if (resourceType == "bitmapFont") return allBitmapFonts;
|
||||
if (resourceType == "model3D") return allModel3Ds;
|
||||
if (resourceType == "atlas") return allAtlases;
|
||||
if (resourceType == "spine") return allSpines;
|
||||
|
||||
return emptyResources;
|
||||
};
|
||||
@@ -67,42 +63,35 @@ public:
|
||||
virtual void ExposeFile(gd::String& resource) override{
|
||||
/*Don't care, we just list resource names*/
|
||||
};
|
||||
virtual void ExposeImage(gd::String& resourceName) override {
|
||||
allImages.insert(resourceName);
|
||||
virtual void ExposeImage(gd::String& imageResourceName) override {
|
||||
allImages.insert(imageResourceName);
|
||||
};
|
||||
virtual void ExposeAudio(gd::String& resourceName) override {
|
||||
allAudios.insert(resourceName);
|
||||
virtual void ExposeAudio(gd::String& audioResourceName) override {
|
||||
allAudios.insert(audioResourceName);
|
||||
};
|
||||
virtual void ExposeFont(gd::String& resourceName) override {
|
||||
allFonts.insert(resourceName);
|
||||
virtual void ExposeFont(gd::String& fontResourceName) override {
|
||||
allFonts.insert(fontResourceName);
|
||||
};
|
||||
virtual void ExposeJson(gd::String& resourceName) override {
|
||||
allJsons.insert(resourceName);
|
||||
virtual void ExposeJson(gd::String& jsonResourceName) override {
|
||||
allJsons.insert(jsonResourceName);
|
||||
};
|
||||
virtual void ExposeTilemap(gd::String& resourceName) override {
|
||||
allTilemaps.insert(resourceName);
|
||||
virtual void ExposeTilemap(gd::String& tilemapResourceName) override {
|
||||
allTilemaps.insert(tilemapResourceName);
|
||||
};
|
||||
virtual void ExposeTileset(gd::String& resourceName) override {
|
||||
allTilesets.insert(resourceName);
|
||||
virtual void ExposeTileset(gd::String& tilesetResourceName) override {
|
||||
allTilesets.insert(tilesetResourceName);
|
||||
};
|
||||
virtual void ExposeVideo(gd::String& resourceName) override {
|
||||
allVideos.insert(resourceName);
|
||||
virtual void ExposeVideo(gd::String& videoResourceName) override {
|
||||
allVideos.insert(videoResourceName);
|
||||
};
|
||||
virtual void ExposeBitmapFont(gd::String& resourceName) override {
|
||||
allBitmapFonts.insert(resourceName);
|
||||
virtual void ExposeBitmapFont(gd::String& bitmapFontResourceName) override {
|
||||
allBitmapFonts.insert(bitmapFontResourceName);
|
||||
};
|
||||
virtual void ExposeModel3D(gd::String& resourceName) override {
|
||||
allModel3Ds.insert(resourceName);
|
||||
};
|
||||
virtual void ExposeAtlas(gd::String& resourceName) override {
|
||||
allAtlases.insert(resourceName);
|
||||
};
|
||||
virtual void ExposeSpine(gd::String& resourceName) override {
|
||||
allSpines.insert(resourceName);
|
||||
};
|
||||
|
||||
protected:
|
||||
std::vector<gd::String> allResources;
|
||||
std::set<gd::String> allImages;
|
||||
std::set<gd::String> allAudios;
|
||||
std::set<gd::String> allFonts;
|
||||
@@ -112,11 +101,10 @@ public:
|
||||
std::set<gd::String> allVideos;
|
||||
std::set<gd::String> allBitmapFonts;
|
||||
std::set<gd::String> allModel3Ds;
|
||||
std::set<gd::String> allAtlases;
|
||||
std::set<gd::String> allSpines;
|
||||
std::set<gd::String> emptyResources;
|
||||
|
||||
static const std::vector<gd::String> resourceTypes;
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
|
||||
#endif // IMAGESUSEDINVENTORIZER_H
|
||||
#endif
|
||||
|
@@ -28,7 +28,7 @@ void ResourcesMergingHelper::ExposeFile(gd::String& resourceFilename) {
|
||||
auto stripToFilenameOnly = [&]() {
|
||||
fs.MakeAbsolute(resourceFullFilename, baseDirectory);
|
||||
SetNewFilename(resourceFullFilename, fs.FileNameFrom(resourceFullFilename));
|
||||
resourceFilename = newFilenames[resourceFullFilename];
|
||||
resourceFilename = oldFilenames[resourceFullFilename];
|
||||
};
|
||||
|
||||
// if we do not want to preserve the folders at all,
|
||||
@@ -45,7 +45,7 @@ void ResourcesMergingHelper::ExposeFile(gd::String& resourceFilename) {
|
||||
gd::String relativeFilename = resourceFullFilename;
|
||||
if (fs.MakeRelative(relativeFilename, baseDirectory)) {
|
||||
SetNewFilename(resourceFullFilename, relativeFilename);
|
||||
resourceFilename = newFilenames[resourceFullFilename];
|
||||
resourceFilename = oldFilenames[resourceFullFilename];
|
||||
} else {
|
||||
// The filename cannot be made relative. Consider that it is absolute.
|
||||
// Just strip the filename to its file part
|
||||
@@ -63,7 +63,7 @@ void ResourcesMergingHelper::ExposeFile(gd::String& resourceFilename) {
|
||||
|
||||
void ResourcesMergingHelper::SetNewFilename(gd::String oldFilename,
|
||||
gd::String newFilename) {
|
||||
if (newFilenames.find(oldFilename) != newFilenames.end()) return;
|
||||
if (oldFilenames.find(oldFilename) != oldFilenames.end()) return;
|
||||
|
||||
// Extract baseName and extension from the new filename
|
||||
size_t extensionPos = newFilename.find_last_of(".");
|
||||
@@ -80,13 +80,13 @@ void ResourcesMergingHelper::SetNewFilename(gd::String oldFilename,
|
||||
gd::NewNameGenerator::Generate(
|
||||
baseName,
|
||||
[this, extension](const gd::String& newBaseName) {
|
||||
return oldFilenames.find(newBaseName + extension) !=
|
||||
oldFilenames.end();
|
||||
return newFilenames.find(newBaseName + extension) !=
|
||||
newFilenames.end();
|
||||
}) +
|
||||
extension;
|
||||
|
||||
newFilenames[oldFilename] = finalFilename;
|
||||
oldFilenames[finalFilename] = oldFilename;
|
||||
oldFilenames[oldFilename] = finalFilename;
|
||||
newFilenames[finalFilename] = oldFilename;
|
||||
}
|
||||
|
||||
void ResourcesMergingHelper::SetBaseDirectory(
|
||||
|
@@ -28,11 +28,11 @@ namespace gd {
|
||||
* \ingroup IDE
|
||||
*/
|
||||
class GD_CORE_API ResourcesMergingHelper : public ArbitraryResourceWorker {
|
||||
public:
|
||||
ResourcesMergingHelper(gd::ResourcesManager &resourcesManager,
|
||||
gd::AbstractFileSystem &fileSystem)
|
||||
: ArbitraryResourceWorker(resourcesManager),
|
||||
preserveDirectoriesStructure(false), preserveAbsoluteFilenames(false),
|
||||
public:
|
||||
ResourcesMergingHelper(gd::AbstractFileSystem& fileSystem)
|
||||
: ArbitraryResourceWorker(),
|
||||
preserveDirectoriesStructure(false),
|
||||
preserveAbsoluteFilenames(false),
|
||||
fs(fileSystem){};
|
||||
virtual ~ResourcesMergingHelper(){};
|
||||
|
||||
@@ -64,25 +64,19 @@ public:
|
||||
* the Base Directory.
|
||||
*/
|
||||
std::map<gd::String, gd::String>& GetAllResourcesOldAndNewFilename() {
|
||||
return newFilenames;
|
||||
return oldFilenames;
|
||||
};
|
||||
|
||||
/**
|
||||
* Resources merging helper collects all resources filenames and update these
|
||||
* filenames.
|
||||
*/
|
||||
void ExposeFile(gd::String& resource) override;
|
||||
virtual void ExposeFile(gd::String& resource) override;
|
||||
|
||||
protected:
|
||||
void SetNewFilename(gd::String oldFilename, gd::String newFilename);
|
||||
|
||||
/**
|
||||
* Original file names that can be accessed by their new name.
|
||||
*/
|
||||
std::map<gd::String, gd::String> oldFilenames;
|
||||
/**
|
||||
* New file names that can be accessed by their original name.
|
||||
*/
|
||||
std::map<gd::String, gd::String> newFilenames;
|
||||
gd::String baseDirectory;
|
||||
bool preserveDirectoriesStructure; ///< If set to true, the directory
|
||||
|
@@ -22,16 +22,13 @@ namespace gd {
|
||||
*/
|
||||
class ResourcesRenamer : public gd::ArbitraryResourceWorker {
|
||||
public:
|
||||
/**
|
||||
* @brief Constructor taking the map from old name to new name.
|
||||
* @param oldToNewNames_ A map associating to a resource name the new name to
|
||||
* use.
|
||||
*/
|
||||
ResourcesRenamer(gd::ResourcesManager &resourcesManager,
|
||||
const std::map<gd::String, gd::String> &oldToNewNames_)
|
||||
: gd::ArbitraryResourceWorker(resourcesManager),
|
||||
oldToNewNames(oldToNewNames_){};
|
||||
|
||||
/**
|
||||
* @brief Constructor taking the map from old name to new name.
|
||||
* @param oldToNewNames_ A map associating to a resource name the new name to
|
||||
* use.
|
||||
*/
|
||||
ResourcesRenamer(const std::map<gd::String, gd::String>& oldToNewNames_)
|
||||
: gd::ArbitraryResourceWorker(), oldToNewNames(oldToNewNames_){};
|
||||
virtual ~ResourcesRenamer(){};
|
||||
|
||||
virtual void ExposeFile(gd::String& resourceFileName) override{
|
||||
@@ -65,12 +62,6 @@ class ResourcesRenamer : public gd::ArbitraryResourceWorker {
|
||||
virtual void ExposeModel3D(gd::String& resourceName) override {
|
||||
RenameIfNeeded(resourceName);
|
||||
};
|
||||
virtual void ExposeAtlas(gd::String& resourceName) override {
|
||||
RenameIfNeeded(resourceName);
|
||||
};
|
||||
virtual void ExposeSpine(gd::String& resourceName) override {
|
||||
RenameIfNeeded(resourceName);
|
||||
};
|
||||
|
||||
private:
|
||||
void RenameIfNeeded(gd::String& resourceName) {
|
||||
|
@@ -13,16 +13,14 @@
|
||||
namespace gd {
|
||||
|
||||
std::set<gd::String> SceneResourcesFinder::FindProjectResources(gd::Project &project) {
|
||||
gd::SceneResourcesFinder resourceWorker(project.GetResourcesManager());
|
||||
|
||||
gd::SceneResourcesFinder resourceWorker;
|
||||
gd::ResourceExposer::ExposeProjectResources(project, resourceWorker);
|
||||
return resourceWorker.resourceNames;
|
||||
}
|
||||
|
||||
std::set<gd::String> SceneResourcesFinder::FindSceneResources(gd::Project &project,
|
||||
gd::Layout &layout) {
|
||||
gd::SceneResourcesFinder resourceWorker(project.GetResourcesManager());
|
||||
|
||||
gd::SceneResourcesFinder resourceWorker;
|
||||
gd::ResourceExposer::ExposeLayoutResources(project, layout, resourceWorker);
|
||||
return resourceWorker.resourceNames;
|
||||
}
|
||||
|
@@ -44,8 +44,7 @@ public:
|
||||
virtual ~SceneResourcesFinder(){};
|
||||
|
||||
private:
|
||||
SceneResourcesFinder(gd::ResourcesManager &resourcesManager)
|
||||
: gd::ArbitraryResourceWorker(resourcesManager){};
|
||||
SceneResourcesFinder() : gd::ArbitraryResourceWorker(){};
|
||||
|
||||
void AddUsedResource(gd::String &resourceName);
|
||||
|
||||
@@ -80,12 +79,6 @@ private:
|
||||
void ExposeModel3D(gd::String &resourceName) override {
|
||||
AddUsedResource(resourceName);
|
||||
};
|
||||
void ExposeAtlas(gd::String &resourceName) override {
|
||||
AddUsedResource(resourceName);
|
||||
};
|
||||
void ExposeSpine(gd::String &resourceName) override {
|
||||
AddUsedResource(resourceName);
|
||||
};
|
||||
|
||||
std::set<gd::String> resourceNames;
|
||||
};
|
||||
|
@@ -128,7 +128,11 @@ void PropertyFunctionGenerator::GenerateGetterAndSetter(
|
||||
} else {
|
||||
gd::Instruction action;
|
||||
action.SetType("SetReturn" + numberOrString);
|
||||
action.AddParameter(property.GetName());
|
||||
gd::String receiver = isBehavior ? "Object.Behavior::" : "Object.";
|
||||
gd::String propertyPrefix =
|
||||
(isSharedProperties ? "SharedProperty" : "Property");
|
||||
action.AddParameter(receiver + propertyPrefix + property.GetName() +
|
||||
"()");
|
||||
event.GetActions().Insert(action, 0);
|
||||
}
|
||||
}
|
||||
@@ -229,13 +233,15 @@ void PropertyFunctionGenerator::GenerateGetterAndSetter(
|
||||
gd::Instruction action;
|
||||
action.SetType(setterType);
|
||||
action.AddParameter("Object");
|
||||
gd::String parameterGetterCall =
|
||||
"GetArgumentAs" + numberOrString + "(\"Value\")";
|
||||
if (isBehavior) {
|
||||
action.AddParameter("Behavior");
|
||||
action.AddParameter("=");
|
||||
action.AddParameter("Value");
|
||||
action.AddParameter(parameterGetterCall);
|
||||
} else {
|
||||
action.AddParameter("=");
|
||||
action.AddParameter("Value");
|
||||
action.AddParameter(parameterGetterCall);
|
||||
}
|
||||
event.GetActions().Insert(action, 0);
|
||||
}
|
||||
|
@@ -33,8 +33,10 @@ void ResourceExposer::ExposeWholeProjectResources(gd::Project& project, gd::Arbi
|
||||
// traverse the whole project (this time for events) and ExposeProjectEffects
|
||||
// (this time for effects).
|
||||
|
||||
gd::ResourcesManager* resourcesManager = &(project.GetResourcesManager());
|
||||
|
||||
// Expose any project resources as files.
|
||||
worker.ExposeResources();
|
||||
worker.ExposeResources(resourcesManager);
|
||||
|
||||
project.GetPlatformSpecificAssets().ExposeResources(worker);
|
||||
|
||||
|
@@ -16,8 +16,8 @@
|
||||
#include "GDCore/IDE/Events/BehaviorTypeRenamer.h"
|
||||
#include "GDCore/IDE/Events/CustomObjectTypeRenamer.h"
|
||||
#include "GDCore/IDE/Events/EventsBehaviorRenamer.h"
|
||||
#include "GDCore/IDE/Events/EventsPropertyReplacer.h"
|
||||
#include "GDCore/IDE/Events/EventsRefactorer.h"
|
||||
#include "GDCore/IDE/Events/EventsPropertyReplacer.h"
|
||||
#include "GDCore/IDE/Events/EventsVariableReplacer.h"
|
||||
#include "GDCore/IDE/Events/ExpressionsParameterMover.h"
|
||||
#include "GDCore/IDE/Events/ExpressionsRenamer.h"
|
||||
@@ -138,8 +138,7 @@ void WholeProjectRefactorer::EnsureObjectEventsFunctionsProperParameters(
|
||||
}
|
||||
}
|
||||
|
||||
VariablesChangeset
|
||||
WholeProjectRefactorer::ComputeChangesetForVariablesContainer(
|
||||
VariablesChangeset WholeProjectRefactorer::ComputeChangesetForVariablesContainer(
|
||||
gd::Project &project,
|
||||
const gd::SerializerElement &oldSerializedVariablesContainer,
|
||||
const gd::VariablesContainer &newVariablesContainer) {
|
||||
@@ -150,9 +149,9 @@ WholeProjectRefactorer::ComputeChangesetForVariablesContainer(
|
||||
|
||||
if (oldVariablesContainer.GetPersistentUuid() !=
|
||||
newVariablesContainer.GetPersistentUuid()) {
|
||||
gd::LogWarning(_(
|
||||
"Called ComputeChangesetForVariablesContainer on variables containers "
|
||||
"that are different - they can't be compared."));
|
||||
gd::LogWarning(
|
||||
_("Called ComputeChangesetForVariablesContainer on variables containers "
|
||||
"that are different - they can't be compared."));
|
||||
return changeset;
|
||||
}
|
||||
|
||||
@@ -193,11 +192,14 @@ WholeProjectRefactorer::ComputeChangesetForVariablesContainer(
|
||||
}
|
||||
|
||||
void WholeProjectRefactorer::ApplyRefactoringForVariablesContainer(
|
||||
gd::Project &project, const gd::VariablesContainer &newVariablesContainer,
|
||||
const gd::VariablesChangeset &changeset) {
|
||||
gd::Project &project,
|
||||
const gd::VariablesContainer &newVariablesContainer,
|
||||
const gd::VariablesChangeset& changeset) {
|
||||
gd::EventsVariableReplacer eventsVariableReplacer(
|
||||
project.GetCurrentPlatform(), newVariablesContainer,
|
||||
changeset.oldToNewVariableNames, changeset.removedVariableNames);
|
||||
project.GetCurrentPlatform(),
|
||||
newVariablesContainer,
|
||||
changeset.oldToNewVariableNames,
|
||||
changeset.removedVariableNames);
|
||||
gd::ProjectBrowserHelper::ExposeProjectEvents(project,
|
||||
eventsVariableReplacer);
|
||||
}
|
||||
@@ -741,14 +743,14 @@ void WholeProjectRefactorer::RenameEventsBasedBehaviorProperty(
|
||||
EventsBasedBehavior::GetPropertyExpressionName(newPropertyName));
|
||||
gd::ProjectBrowserHelper::ExposeProjectEvents(project, expressionRenamer);
|
||||
|
||||
std::unordered_map<gd::String, gd::String> oldToNewPropertyNames = {
|
||||
{oldPropertyName, newPropertyName}};
|
||||
std::unordered_map<gd::String, gd::String> oldToNewPropertyNames = {{oldPropertyName, newPropertyName}};
|
||||
std::unordered_set<gd::String> removedPropertyNames;
|
||||
gd::EventsPropertyReplacer eventsPropertyReplacer(
|
||||
project.GetCurrentPlatform(), properties, oldToNewPropertyNames,
|
||||
removedPropertyNames);
|
||||
gd::ProjectBrowserHelper::ExposeProjectEvents(project,
|
||||
eventsPropertyReplacer);
|
||||
project.GetCurrentPlatform(),
|
||||
properties,
|
||||
oldToNewPropertyNames,
|
||||
removedPropertyNames);
|
||||
gd::ProjectBrowserHelper::ExposeProjectEvents(project, eventsPropertyReplacer);
|
||||
|
||||
gd::InstructionsTypeRenamer actionRenamer = gd::InstructionsTypeRenamer(
|
||||
project,
|
||||
@@ -811,14 +813,14 @@ void WholeProjectRefactorer::RenameEventsBasedBehaviorSharedProperty(
|
||||
EventsBasedBehavior::GetSharedPropertyExpressionName(newPropertyName));
|
||||
gd::ProjectBrowserHelper::ExposeProjectEvents(project, expressionRenamer);
|
||||
|
||||
std::unordered_map<gd::String, gd::String> oldToNewPropertyNames = {
|
||||
{oldPropertyName, newPropertyName}};
|
||||
std::unordered_map<gd::String, gd::String> oldToNewPropertyNames = {{oldPropertyName, newPropertyName}};
|
||||
std::unordered_set<gd::String> removedPropertyNames;
|
||||
gd::EventsPropertyReplacer eventsPropertyReplacer(
|
||||
project.GetCurrentPlatform(), properties, oldToNewPropertyNames,
|
||||
removedPropertyNames);
|
||||
gd::ProjectBrowserHelper::ExposeProjectEvents(project,
|
||||
eventsPropertyReplacer);
|
||||
project.GetCurrentPlatform(),
|
||||
properties,
|
||||
oldToNewPropertyNames,
|
||||
removedPropertyNames);
|
||||
gd::ProjectBrowserHelper::ExposeProjectEvents(project, eventsPropertyReplacer);
|
||||
|
||||
gd::InstructionsTypeRenamer actionRenamer = gd::InstructionsTypeRenamer(
|
||||
project,
|
||||
@@ -868,14 +870,14 @@ void WholeProjectRefactorer::RenameEventsBasedObjectProperty(
|
||||
EventsBasedObject::GetPropertyExpressionName(newPropertyName));
|
||||
gd::ProjectBrowserHelper::ExposeProjectEvents(project, expressionRenamer);
|
||||
|
||||
std::unordered_map<gd::String, gd::String> oldToNewPropertyNames = {
|
||||
{oldPropertyName, newPropertyName}};
|
||||
std::unordered_map<gd::String, gd::String> oldToNewPropertyNames = {{oldPropertyName, newPropertyName}};
|
||||
std::unordered_set<gd::String> removedPropertyNames;
|
||||
gd::EventsPropertyReplacer eventsPropertyReplacer(
|
||||
project.GetCurrentPlatform(), properties, oldToNewPropertyNames,
|
||||
removedPropertyNames);
|
||||
gd::ProjectBrowserHelper::ExposeProjectEvents(project,
|
||||
eventsPropertyReplacer);
|
||||
project.GetCurrentPlatform(),
|
||||
properties,
|
||||
oldToNewPropertyNames,
|
||||
removedPropertyNames);
|
||||
gd::ProjectBrowserHelper::ExposeProjectEvents(project, eventsPropertyReplacer);
|
||||
|
||||
gd::InstructionsTypeRenamer actionRenamer = gd::InstructionsTypeRenamer(
|
||||
project,
|
||||
@@ -1349,6 +1351,7 @@ void WholeProjectRefactorer::DoRenameBehavior(
|
||||
gd::Project &project, const gd::String &oldBehaviorType,
|
||||
const gd::String &newBehaviorType,
|
||||
const gd::ProjectBrowser &projectBrowser) {
|
||||
|
||||
// Rename behavior in required behavior properties
|
||||
auto requiredBehaviorRenamer =
|
||||
gd::RequiredBehaviorRenamer(oldBehaviorType, newBehaviorType);
|
||||
@@ -1375,6 +1378,7 @@ void WholeProjectRefactorer::DoRenameBehavior(
|
||||
void WholeProjectRefactorer::DoRenameObject(
|
||||
gd::Project &project, const gd::String &oldObjectType,
|
||||
const gd::String &newObjectType, const gd::ProjectBrowser &projectBrowser) {
|
||||
|
||||
// Rename object type in objects lists.
|
||||
auto customObjectTypeRenamer =
|
||||
gd::CustomObjectTypeRenamer(oldObjectType, newObjectType);
|
||||
@@ -1394,8 +1398,7 @@ void WholeProjectRefactorer::DoRenameObject(
|
||||
void WholeProjectRefactorer::ObjectOrGroupRemovedInLayout(
|
||||
gd::Project &project, gd::Layout &layout, const gd::String &objectName,
|
||||
bool isObjectGroup, bool removeEventsAndGroups) {
|
||||
auto projectScopedContainers = gd::ProjectScopedContainers::
|
||||
MakeNewProjectScopedContainersForProjectAndLayout(project, layout);
|
||||
auto projectScopedContainers = gd::ProjectScopedContainers::MakeNewProjectScopedContainersForProjectAndLayout(project, layout);
|
||||
|
||||
// Remove object in the current layout
|
||||
if (removeEventsAndGroups) {
|
||||
@@ -1444,8 +1447,7 @@ void WholeProjectRefactorer::ObjectOrGroupRenamedInLayout(
|
||||
if (oldName == newName || newName.empty() || oldName.empty())
|
||||
return;
|
||||
|
||||
auto projectScopedContainers = gd::ProjectScopedContainers::
|
||||
MakeNewProjectScopedContainersForProjectAndLayout(project, layout);
|
||||
auto projectScopedContainers = gd::ProjectScopedContainers::MakeNewProjectScopedContainersForProjectAndLayout(project, layout);
|
||||
|
||||
// Rename object in the current layout
|
||||
gd::EventsRefactorer::RenameObjectInEvents(
|
||||
@@ -1534,19 +1536,10 @@ void WholeProjectRefactorer::RenameLayer(gd::Project &project,
|
||||
const gd::String &newName) {
|
||||
if (oldName == newName || newName.empty() || oldName.empty())
|
||||
return;
|
||||
|
||||
gd::ProjectElementRenamer projectElementRenamer(project.GetCurrentPlatform(),
|
||||
"layer", oldName, newName);
|
||||
gd::ProjectBrowserHelper::ExposeLayoutEventsAndExternalEvents(
|
||||
project, layout, projectElementRenamer);
|
||||
layout.GetInitialInstances().MoveInstancesToLayer(oldName, newName);
|
||||
|
||||
std::vector<gd::String> externalLayoutsNames =
|
||||
GetAssociatedExternalLayouts(project, layout);
|
||||
for (gd::String name : externalLayoutsNames) {
|
||||
auto &externalLayout = project.GetExternalLayout(name);
|
||||
externalLayout.GetInitialInstances().MoveInstancesToLayer(oldName, newName);
|
||||
}
|
||||
gd::ProjectBrowserHelper::ExposeLayoutEventsAndExternalEvents(project, layout,
|
||||
projectElementRenamer);
|
||||
}
|
||||
|
||||
void WholeProjectRefactorer::RenameLayerEffect(gd::Project &project,
|
||||
@@ -1559,8 +1552,8 @@ void WholeProjectRefactorer::RenameLayerEffect(gd::Project &project,
|
||||
gd::ProjectElementRenamer projectElementRenamer(
|
||||
project.GetCurrentPlatform(), "layerEffectName", oldName, newName);
|
||||
projectElementRenamer.SetLayerConstraint(layer.GetName());
|
||||
gd::ProjectBrowserHelper::ExposeLayoutEventsAndExternalEvents(
|
||||
project, layout, projectElementRenamer);
|
||||
gd::ProjectBrowserHelper::ExposeLayoutEventsAndExternalEvents(project, layout,
|
||||
projectElementRenamer);
|
||||
}
|
||||
|
||||
void WholeProjectRefactorer::RenameObjectAnimation(gd::Project &project,
|
||||
@@ -1573,8 +1566,8 @@ void WholeProjectRefactorer::RenameObjectAnimation(gd::Project &project,
|
||||
gd::ProjectElementRenamer projectElementRenamer(
|
||||
project.GetCurrentPlatform(), "objectAnimationName", oldName, newName);
|
||||
projectElementRenamer.SetObjectConstraint(object.GetName());
|
||||
gd::ProjectBrowserHelper::ExposeLayoutEventsAndExternalEvents(
|
||||
project, layout, projectElementRenamer);
|
||||
gd::ProjectBrowserHelper::ExposeLayoutEventsAndExternalEvents(project, layout,
|
||||
projectElementRenamer);
|
||||
}
|
||||
|
||||
void WholeProjectRefactorer::RenameObjectPoint(gd::Project &project,
|
||||
@@ -1587,8 +1580,8 @@ void WholeProjectRefactorer::RenameObjectPoint(gd::Project &project,
|
||||
gd::ProjectElementRenamer projectElementRenamer(
|
||||
project.GetCurrentPlatform(), "objectPointName", oldName, newName);
|
||||
projectElementRenamer.SetObjectConstraint(object.GetName());
|
||||
gd::ProjectBrowserHelper::ExposeLayoutEventsAndExternalEvents(
|
||||
project, layout, projectElementRenamer);
|
||||
gd::ProjectBrowserHelper::ExposeLayoutEventsAndExternalEvents(project, layout,
|
||||
projectElementRenamer);
|
||||
}
|
||||
|
||||
void WholeProjectRefactorer::RenameObjectEffect(gd::Project &project,
|
||||
@@ -1601,8 +1594,8 @@ void WholeProjectRefactorer::RenameObjectEffect(gd::Project &project,
|
||||
gd::ProjectElementRenamer projectElementRenamer(
|
||||
project.GetCurrentPlatform(), "objectEffectName", oldName, newName);
|
||||
projectElementRenamer.SetObjectConstraint(object.GetName());
|
||||
gd::ProjectBrowserHelper::ExposeLayoutEventsAndExternalEvents(
|
||||
project, layout, projectElementRenamer);
|
||||
gd::ProjectBrowserHelper::ExposeLayoutEventsAndExternalEvents(project, layout,
|
||||
projectElementRenamer);
|
||||
}
|
||||
|
||||
void WholeProjectRefactorer::ObjectOrGroupRemovedInEventsBasedObject(
|
||||
@@ -1624,12 +1617,9 @@ void WholeProjectRefactorer::ObjectOrGroupRemovedInEventsFunction(
|
||||
gd::ObjectsContainer &globalObjectsContainer,
|
||||
gd::ObjectsContainer &objectsContainer, const gd::String &objectName,
|
||||
bool isObjectGroup, bool removeEventsAndGroups) {
|
||||
// In theory we should pass a ProjectScopedContainers to this function so it
|
||||
// does not have to construct one. In practice, this is ok because we only
|
||||
// deal with objects.
|
||||
auto projectScopedContainers =
|
||||
gd::ProjectScopedContainers::MakeNewProjectScopedContainersFor(
|
||||
globalObjectsContainer, objectsContainer);
|
||||
// In theory we should pass a ProjectScopedContainers to this function so it does not have to construct one.
|
||||
// In practice, this is ok because we only deal with objects.
|
||||
auto projectScopedContainers = gd::ProjectScopedContainers::MakeNewProjectScopedContainersFor(globalObjectsContainer, objectsContainer);
|
||||
|
||||
if (removeEventsAndGroups) {
|
||||
gd::EventsRefactorer::RemoveObjectInEvents(
|
||||
@@ -1665,12 +1655,9 @@ void WholeProjectRefactorer::ObjectOrGroupRenamedInEventsFunction(
|
||||
gd::ObjectsContainer &globalObjectsContainer,
|
||||
gd::ObjectsContainer &objectsContainer, const gd::String &oldName,
|
||||
const gd::String &newName, bool isObjectGroup) {
|
||||
// In theory we should pass a ProjectScopedContainers to this function so it
|
||||
// does not have to construct one. In practice, this is ok because we only
|
||||
// deal with objects.
|
||||
auto projectScopedContainers =
|
||||
gd::ProjectScopedContainers::MakeNewProjectScopedContainersFor(
|
||||
globalObjectsContainer, objectsContainer);
|
||||
// In theory we should pass a ProjectScopedContainers to this function so it does not have to construct one.
|
||||
// In practice, this is ok because we only deal with objects.
|
||||
auto projectScopedContainers = gd::ProjectScopedContainers::MakeNewProjectScopedContainersFor(globalObjectsContainer, objectsContainer);
|
||||
|
||||
gd::EventsRefactorer::RenameObjectInEvents(
|
||||
project.GetCurrentPlatform(), projectScopedContainers,
|
||||
@@ -1718,7 +1705,7 @@ void WholeProjectRefactorer::GlobalObjectOrGroupRemoved(
|
||||
if (layout.HasObjectNamed(objectName))
|
||||
continue;
|
||||
|
||||
ObjectOrGroupRemovedInLayout(project, layout, objectName, isObjectGroup,
|
||||
ObjectOrGroupRemovedInLayout(project, layout, objectName, isObjectGroup,
|
||||
removeEventsAndGroups);
|
||||
}
|
||||
}
|
||||
@@ -1766,8 +1753,7 @@ size_t WholeProjectRefactorer::GetLayoutAndExternalLayoutLayerInstancesCount(
|
||||
GetAssociatedExternalLayouts(project, layout);
|
||||
for (gd::String name : externalLayoutsNames) {
|
||||
auto &externalLayout = project.GetExternalLayout(name);
|
||||
count +=
|
||||
externalLayout.GetInitialInstances().GetLayerInstancesCount(layerName);
|
||||
count += externalLayout.GetInitialInstances().GetLayerInstancesCount(layerName);
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
@@ -4,6 +4,8 @@
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#include "GDCore/Project/Behavior.h"
|
||||
#include <iostream>
|
||||
#include "GDCore/Project/PropertyDescriptor.h"
|
||||
|
||||
namespace gd {
|
||||
|
||||
|
@@ -155,10 +155,6 @@ void CustomObjectConfiguration::ExposeResources(gd::ArbitraryResourceWorker& wor
|
||||
worker.ExposeBitmapFont(newPropertyValue);
|
||||
} else if (resourceType == "model3D") {
|
||||
worker.ExposeModel3D(newPropertyValue);
|
||||
} else if (resourceType == "atlas") {
|
||||
worker.ExposeAtlas(newPropertyValue);
|
||||
} else if (resourceType == "spine") {
|
||||
worker.ExposeSpine(newPropertyValue);
|
||||
}
|
||||
|
||||
if (newPropertyValue != oldPropertyValue) {
|
||||
|
@@ -13,9 +13,7 @@ EventsBasedObject::EventsBasedObject()
|
||||
: AbstractEventsBasedEntity(
|
||||
"MyObject",
|
||||
gd::EventsFunctionsContainer::FunctionOwner::Object),
|
||||
ObjectsContainer(),
|
||||
isRenderedIn3D(false),
|
||||
isTextContainer(false) {
|
||||
ObjectsContainer() {
|
||||
}
|
||||
|
||||
EventsBasedObject::~EventsBasedObject() {}
|
||||
@@ -32,9 +30,6 @@ void EventsBasedObject::SerializeTo(SerializerElement& element) const {
|
||||
if (isRenderedIn3D) {
|
||||
element.SetBoolAttribute("is3D", true);
|
||||
}
|
||||
if (isTextContainer) {
|
||||
element.SetBoolAttribute("isTextContainer", true);
|
||||
}
|
||||
|
||||
AbstractEventsBasedEntity::SerializeTo(element);
|
||||
SerializeObjectsTo(element.AddChild("objects"));
|
||||
@@ -45,7 +40,6 @@ void EventsBasedObject::UnserializeFrom(gd::Project& project,
|
||||
const SerializerElement& element) {
|
||||
defaultName = element.GetStringAttribute("defaultName");
|
||||
isRenderedIn3D = element.GetBoolAttribute("is3D", false);
|
||||
isTextContainer = element.GetBoolAttribute("isTextContainer", false);
|
||||
|
||||
AbstractEventsBasedEntity::UnserializeFrom(project, element);
|
||||
UnserializeObjectsFrom(project, element.GetChild("objects"));
|
||||
|
@@ -85,19 +85,6 @@ class GD_CORE_API EventsBasedObject: public AbstractEventsBasedEntity, public Ob
|
||||
*/
|
||||
bool IsRenderedIn3D() const { return isRenderedIn3D; }
|
||||
|
||||
/**
|
||||
* \brief Declare a TextContainer capability.
|
||||
*/
|
||||
EventsBasedObject& MarkAsTextContainer(bool isTextContainer_) {
|
||||
isTextContainer = isTextContainer_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Return true if the object needs a TextContainer capability.
|
||||
*/
|
||||
bool IsTextContainer() const { return isTextContainer; }
|
||||
|
||||
void SerializeTo(SerializerElement& element) const override;
|
||||
|
||||
void UnserializeFrom(gd::Project& project,
|
||||
@@ -106,7 +93,6 @@ class GD_CORE_API EventsBasedObject: public AbstractEventsBasedEntity, public Ob
|
||||
private:
|
||||
gd::String defaultName;
|
||||
bool isRenderedIn3D;
|
||||
bool isTextContainer;
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
|
@@ -39,7 +39,6 @@ void Layer::SetCameraCount(std::size_t n) {
|
||||
void Layer::SerializeTo(SerializerElement& element) const {
|
||||
element.SetAttribute("name", GetName());
|
||||
element.SetAttribute("renderingType", GetRenderingType());
|
||||
element.SetAttribute("cameraType", GetCameraType());
|
||||
element.SetAttribute("visibility", GetVisibility());
|
||||
element.SetAttribute("isLocked", IsLocked());
|
||||
element.SetAttribute("isLightingLayer", IsLightingLayer());
|
||||
@@ -79,7 +78,6 @@ void Layer::SerializeTo(SerializerElement& element) const {
|
||||
void Layer::UnserializeFrom(const SerializerElement& element) {
|
||||
SetName(element.GetStringAttribute("name", "", "Name"));
|
||||
SetRenderingType(element.GetStringAttribute("renderingType", ""));
|
||||
SetCameraType(element.GetStringAttribute("cameraType", "perspective"));
|
||||
SetVisibility(element.GetBoolAttribute("visibility", true, "Visibility"));
|
||||
SetLocked(element.GetBoolAttribute("isLocked", false));
|
||||
SetLightingLayer(element.GetBoolAttribute("isLightingLayer", false));
|
||||
|
@@ -104,17 +104,10 @@ class GD_CORE_API Layer {
|
||||
const gd::String& GetName() const { return name; }
|
||||
|
||||
const gd::String& GetRenderingType() const { return renderingType; }
|
||||
|
||||
void SetRenderingType(const gd::String& renderingType_) {
|
||||
renderingType = renderingType_;
|
||||
}
|
||||
|
||||
const gd::String& GetCameraType() const { return cameraType; }
|
||||
|
||||
void SetCameraType(const gd::String& cameraType_) {
|
||||
cameraType = cameraType_;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Change if layer is displayed or not
|
||||
*/
|
||||
@@ -275,7 +268,6 @@ class GD_CORE_API Layer {
|
||||
gd::String name; ///< The name of the layer
|
||||
gd::String renderingType; ///< The rendering type: "" (empty), "2d", "3d" or
|
||||
///< "2d+3d".
|
||||
gd::String cameraType;
|
||||
bool isVisible; ///< True if the layer is visible
|
||||
bool isLocked; ///< True if the layer is locked
|
||||
bool isLightingLayer; ///< True if the layer is used to display lights and
|
||||
|
@@ -17,7 +17,7 @@ LoadingScreen::LoadingScreen()
|
||||
backgroundFadeInDuration(0.2),
|
||||
minDuration(1.5),
|
||||
logoAndProgressFadeInDuration(0.2),
|
||||
logoAndProgressLogoFadeInDelay(0),
|
||||
logoAndProgressLogoFadeInDelay(0.2),
|
||||
showProgressBar(true),
|
||||
progressBarMinWidth(40),
|
||||
progressBarMaxWidth(200),
|
||||
|
@@ -120,6 +120,9 @@ class GD_CORE_API Object {
|
||||
*/
|
||||
const gd::String& GetType() const { return configuration->GetType(); }
|
||||
|
||||
/** \brief Shortcut to check if the object is a 3D object.
|
||||
*/
|
||||
bool Is3DObject() const { return configuration->Is3DObject(); }
|
||||
///@}
|
||||
|
||||
/** \name Behaviors management
|
||||
|
@@ -5,8 +5,11 @@
|
||||
*/
|
||||
#include "GDCore/Project/ObjectConfiguration.h"
|
||||
|
||||
#include "GDCore/Extensions/Metadata/BehaviorMetadata.h"
|
||||
#include "GDCore/Extensions/Metadata/MetadataProvider.h"
|
||||
#include "GDCore/Extensions/Platform.h"
|
||||
#include "GDCore/Project/Behavior.h"
|
||||
#include "GDCore/Project/CustomBehavior.h"
|
||||
#include "GDCore/Project/Layout.h"
|
||||
#include "GDCore/Project/Project.h"
|
||||
#include "GDCore/Serialization/SerializerElement.h"
|
||||
@@ -17,7 +20,7 @@ namespace gd {
|
||||
|
||||
ObjectConfiguration::~ObjectConfiguration() {}
|
||||
|
||||
ObjectConfiguration::ObjectConfiguration() {}
|
||||
ObjectConfiguration::ObjectConfiguration(): is3DObject(false) {}
|
||||
|
||||
std::map<gd::String, gd::PropertyDescriptor> ObjectConfiguration::GetProperties() const {
|
||||
std::map<gd::String, gd::PropertyDescriptor> nothing;
|
||||
|
@@ -63,12 +63,20 @@ class GD_CORE_API ObjectConfiguration {
|
||||
*/
|
||||
void SetType(const gd::String& type_) {
|
||||
type = type_;
|
||||
|
||||
// For now, as a shortcut, consider only the objects from the built-in 3D extension
|
||||
// to be 3D object.
|
||||
is3DObject = type.find("Scene3D::") == 0;
|
||||
}
|
||||
|
||||
/** \brief Return the type of the object.
|
||||
*/
|
||||
const gd::String& GetType() const { return type; }
|
||||
|
||||
/** \brief Shortcut to check if the object is a 3D object.
|
||||
*/
|
||||
bool Is3DObject() const { return is3DObject; }
|
||||
|
||||
/** \name Object properties
|
||||
* Reading and updating object configuration properties
|
||||
*/
|
||||
@@ -172,6 +180,7 @@ class GD_CORE_API ObjectConfiguration {
|
||||
protected:
|
||||
gd::String type; ///< Which type of object is represented by this
|
||||
///< configuration.
|
||||
bool is3DObject;
|
||||
|
||||
/**
|
||||
* \brief Derived object configuration can redefine this method to load
|
||||
|
@@ -113,7 +113,7 @@ bool ObjectsContainersList::HasObjectWithVariableNamed(
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ObjectsContainersList::HasObjectOrGroupVariablesContainer(
|
||||
bool ObjectsContainersList::HasVariablesContainer(
|
||||
const gd::String& objectOrGroupName,
|
||||
const gd::VariablesContainer& variablesContainer) const {
|
||||
for (auto it = objectsContainers.rbegin(); it != objectsContainers.rend();
|
||||
@@ -123,31 +123,8 @@ bool ObjectsContainersList::HasObjectOrGroupVariablesContainer(
|
||||
&(*it)->GetObject(objectOrGroupName).GetVariables();
|
||||
}
|
||||
if ((*it)->GetObjectGroups().Has(objectOrGroupName)) {
|
||||
// For groups, we consider that the first object of the group defines the
|
||||
// variables available for this group. Note that this is slightly
|
||||
// different than other methods where a group is considered as the
|
||||
// "intersection" of all of its objects.
|
||||
const auto& objectNames =
|
||||
(*it)->GetObjectGroups().Get(objectOrGroupName).GetAllObjectsNames();
|
||||
|
||||
if (!objectNames.empty()) {
|
||||
return HasObjectVariablesContainer(objectNames[0], variablesContainer);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ObjectsContainersList::HasObjectVariablesContainer(
|
||||
const gd::String& objectName,
|
||||
const gd::VariablesContainer& variablesContainer) const {
|
||||
for (auto it = objectsContainers.rbegin(); it != objectsContainers.rend();
|
||||
++it) {
|
||||
if ((*it)->HasObjectNamed(objectName)) {
|
||||
return &variablesContainer ==
|
||||
&(*it)->GetObject(objectName).GetVariables();
|
||||
// Could be adapted if objects groups have variables in the future.
|
||||
// This would allow handling the renaming of variables of an object group.
|
||||
}
|
||||
}
|
||||
|
||||
@@ -163,30 +140,8 @@ ObjectsContainersList::GetObjectOrGroupVariablesContainer(
|
||||
return &(*it)->GetObject(objectOrGroupName).GetVariables();
|
||||
}
|
||||
if ((*it)->GetObjectGroups().Has(objectOrGroupName)) {
|
||||
// For groups, we consider that the first object of the group defines the
|
||||
// variables available for this group. Note that this is slightly
|
||||
// different than other methods where a group is considered as the
|
||||
// "intersection" of all of its objects.
|
||||
const auto& objectNames =
|
||||
(*it)->GetObjectGroups().Get(objectOrGroupName).GetAllObjectsNames();
|
||||
|
||||
if (!objectNames.empty()) {
|
||||
return GetObjectVariablesContainer(objectNames[0]);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const gd::VariablesContainer*
|
||||
ObjectsContainersList::GetObjectVariablesContainer(
|
||||
const gd::String& objectName) const {
|
||||
for (auto it = objectsContainers.rbegin(); it != objectsContainers.rend();
|
||||
++it) {
|
||||
if ((*it)->HasObjectNamed(objectName)) {
|
||||
return &(*it)->GetObject(objectName).GetVariables();
|
||||
// Could be adapted if objects groups have variables in the future.
|
||||
// This would allow handling the renaming of variables of an object group.
|
||||
}
|
||||
}
|
||||
|
||||
@@ -195,6 +150,7 @@ ObjectsContainersList::GetObjectVariablesContainer(
|
||||
|
||||
gd::Variable::Type ObjectsContainersList::GetTypeOfObjectOrGroupVariable(
|
||||
const gd::String& objectOrGroupName, const gd::String& variableName) const {
|
||||
|
||||
for (auto it = objectsContainers.rbegin(); it != objectsContainers.rend();
|
||||
++it) {
|
||||
if ((*it)->HasObjectNamed(objectOrGroupName)) {
|
||||
@@ -226,12 +182,13 @@ gd::Variable::Type ObjectsContainersList::GetTypeOfObjectOrGroupVariable(
|
||||
return Variable::Type::Number;
|
||||
}
|
||||
|
||||
gd::Variable::Type ObjectsContainersList::GetTypeOfObjectVariable(
|
||||
const gd::String& objectName, const gd::String& variableName) const {
|
||||
gd::Variable::Type ObjectsContainersList::GetTypeOfObjectVariable(const gd::String& objectName, const gd::String& variableName) const {
|
||||
|
||||
for (auto it = objectsContainers.rbegin(); it != objectsContainers.rend();
|
||||
++it) {
|
||||
if ((*it)->HasObjectNamed(objectName)) {
|
||||
const auto& variables = (*it)->GetObject(objectName).GetVariables();
|
||||
const auto& variables =
|
||||
(*it)->GetObject(objectName).GetVariables();
|
||||
|
||||
return variables.Get(variableName).GetType();
|
||||
}
|
||||
|
@@ -61,7 +61,7 @@ class GD_CORE_API ObjectsContainersList {
|
||||
* \brief Check if the specified object or group has the specified variables
|
||||
* container.
|
||||
*/
|
||||
bool HasObjectOrGroupVariablesContainer(
|
||||
bool HasVariablesContainer(
|
||||
const gd::String& objectOrGroupName,
|
||||
const gd::VariablesContainer& variablesContainer) const;
|
||||
|
||||
@@ -165,13 +165,6 @@ class GD_CORE_API ObjectsContainersList {
|
||||
bool HasObjectWithVariableNamed(const gd::String& objectName,
|
||||
const gd::String& variableName) const;
|
||||
|
||||
bool HasObjectVariablesContainer(
|
||||
const gd::String& objectName,
|
||||
const gd::VariablesContainer& variablesContainer) const;
|
||||
|
||||
const gd::VariablesContainer* GetObjectVariablesContainer(
|
||||
const gd::String& objectName) const;
|
||||
|
||||
gd::Variable::Type GetTypeOfObjectVariable(const gd::String& objectName, const gd::String& variableName) const;
|
||||
|
||||
void ForEachObjectVariableMatchingSearch(
|
||||
|
@@ -102,19 +102,21 @@ std::unique_ptr<gd::Object> Project::CreateObject(
|
||||
behavior->SetDefaultBehavior(true);
|
||||
};
|
||||
|
||||
auto &objectMetadata =
|
||||
gd::MetadataProvider::GetObjectMetadata(platform, objectType);
|
||||
if (!MetadataProvider::IsBadObjectMetadata(objectMetadata)) {
|
||||
for (auto &behaviorType : objectMetadata.GetDefaultBehaviors()) {
|
||||
if (Project::HasEventsBasedObject(objectType)) {
|
||||
addDefaultBehavior("EffectCapability::EffectBehavior");
|
||||
addDefaultBehavior("ResizableCapability::ResizableBehavior");
|
||||
addDefaultBehavior("ScalableCapability::ScalableBehavior");
|
||||
addDefaultBehavior("FlippableCapability::FlippableBehavior");
|
||||
} else {
|
||||
auto& objectMetadata =
|
||||
gd::MetadataProvider::GetObjectMetadata(platform, objectType);
|
||||
if (MetadataProvider::IsBadObjectMetadata(objectMetadata)) {
|
||||
gd::LogWarning("Object: " + name + " has an unknown type: " + objectType);
|
||||
}
|
||||
for (auto& behaviorType : objectMetadata.GetDefaultBehaviors()) {
|
||||
addDefaultBehavior(behaviorType);
|
||||
}
|
||||
}
|
||||
// During project deserialization, event-based object metadata are not yet
|
||||
// generated. Default behaviors will be added by
|
||||
// MetadataDeclarationHelper::UpdateCustomObjectDefaultBehaviors
|
||||
else if (!project.HasEventsBasedObject(objectType)) {
|
||||
gd::LogWarning("Object: " + name + " has an unknown type: " + objectType);
|
||||
}
|
||||
|
||||
return std::move(object);
|
||||
}
|
||||
|
@@ -29,15 +29,7 @@ void PropertyDescriptor::SerializeTo(SerializerElement& element) const {
|
||||
for (const gd::String& information : extraInformation) {
|
||||
extraInformationElement.AddChild("").SetStringValue(information);
|
||||
}
|
||||
if (hidden) {
|
||||
element.AddChild("hidden").SetBoolValue(hidden);
|
||||
}
|
||||
if (deprecated) {
|
||||
element.AddChild("deprecated").SetBoolValue(deprecated);
|
||||
}
|
||||
if (advanced) {
|
||||
element.AddChild("advanced").SetBoolValue(advanced);
|
||||
}
|
||||
element.AddChild("hidden").SetBoolValue(hidden);
|
||||
}
|
||||
|
||||
void PropertyDescriptor::UnserializeFrom(const SerializerElement& element) {
|
||||
@@ -66,12 +58,6 @@ void PropertyDescriptor::UnserializeFrom(const SerializerElement& element) {
|
||||
hidden = element.HasChild("hidden")
|
||||
? element.GetChild("hidden").GetBoolValue()
|
||||
: false;
|
||||
deprecated = element.HasChild("deprecated")
|
||||
? element.GetChild("deprecated").GetBoolValue()
|
||||
: false;
|
||||
advanced = element.HasChild("advanced")
|
||||
? element.GetChild("advanced").GetBoolValue()
|
||||
: false;
|
||||
}
|
||||
|
||||
void PropertyDescriptor::SerializeValuesTo(SerializerElement& element) const {
|
||||
|
@@ -30,16 +30,12 @@ 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),
|
||||
measurementUnit(gd::MeasurementUnit::GetUndefined()) {}
|
||||
: currentValue(propertyValue), type("string"), label(""), hidden(false), measurementUnit(gd::MeasurementUnit::GetUndefined()) {}
|
||||
|
||||
/**
|
||||
* \brief Empty constructor creating an empty property to be displayed.
|
||||
*/
|
||||
PropertyDescriptor()
|
||||
: hidden(false), deprecated(false), advanced(false),
|
||||
measurementUnit(gd::MeasurementUnit::GetUndefined()){};
|
||||
PropertyDescriptor() : hidden(false), measurementUnit(gd::MeasurementUnit::GetUndefined()) {};
|
||||
|
||||
/**
|
||||
* \brief Destructor
|
||||
@@ -146,32 +142,6 @@ class GD_CORE_API PropertyDescriptor {
|
||||
*/
|
||||
bool IsHidden() const { return hidden; }
|
||||
|
||||
/**
|
||||
* \brief Set if the property is deprecated.
|
||||
*/
|
||||
PropertyDescriptor& SetDeprecated(bool enable = true) {
|
||||
deprecated = enable;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Check if the property is deprecated.
|
||||
*/
|
||||
bool IsDeprecated() const { return deprecated; }
|
||||
|
||||
/**
|
||||
* \brief Set if the property is marked as advanced.
|
||||
*/
|
||||
PropertyDescriptor& SetAdvanced(bool enable = true) {
|
||||
advanced = enable;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Check if the property is marked as advanced.
|
||||
*/
|
||||
bool IsAdvanced() const { return advanced; }
|
||||
|
||||
/** \name Serialization
|
||||
*/
|
||||
///@{
|
||||
@@ -209,8 +179,6 @@ class GD_CORE_API PropertyDescriptor {
|
||||
///< choices, if a property is a displayed as a combo
|
||||
///< box.
|
||||
bool hidden;
|
||||
bool deprecated;
|
||||
bool advanced;
|
||||
gd::MeasurementUnit measurementUnit; //< The unit of measurement of the property vale.
|
||||
};
|
||||
|
||||
|
@@ -93,10 +93,6 @@ std::shared_ptr<Resource> ResourcesManager::CreateResource(
|
||||
return std::make_shared<BitmapFontResource>();
|
||||
else if (kind == "model3D")
|
||||
return std::make_shared<Model3DResource>();
|
||||
else if (kind == "atlas")
|
||||
return std::make_shared<AtlasResource>();
|
||||
else if (kind == "spine")
|
||||
return std::make_shared<SpineResource>();
|
||||
|
||||
std::cout << "Bad resource created (type: " << kind << ")" << std::endl;
|
||||
return std::make_shared<Resource>();
|
||||
@@ -760,20 +756,6 @@ void Model3DResource::SerializeTo(SerializerElement& element) const {
|
||||
element.SetAttribute("file", GetFile());
|
||||
}
|
||||
|
||||
void AtlasResource::SetFile(const gd::String& newFile) {
|
||||
file = NormalizePathSeparator(newFile);
|
||||
}
|
||||
|
||||
void AtlasResource::UnserializeFrom(const SerializerElement& element) {
|
||||
SetUserAdded(element.GetBoolAttribute("userAdded"));
|
||||
SetFile(element.GetStringAttribute("file"));
|
||||
}
|
||||
|
||||
void AtlasResource::SerializeTo(SerializerElement& element) const {
|
||||
element.SetAttribute("userAdded", IsUserAdded());
|
||||
element.SetAttribute("file", GetFile());
|
||||
}
|
||||
|
||||
ResourceFolder::ResourceFolder(const ResourceFolder& other) { Init(other); }
|
||||
|
||||
ResourceFolder& ResourceFolder::operator=(const ResourceFolder& other) {
|
||||
|
@@ -373,21 +373,6 @@ class GD_CORE_API JsonResource : public Resource {
|
||||
gd::String file;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Describe a spine json file used by a project.
|
||||
*
|
||||
* \see Resource
|
||||
* \ingroup ResourcesManagement
|
||||
*/
|
||||
class GD_CORE_API SpineResource : public JsonResource {
|
||||
public:
|
||||
SpineResource() : JsonResource() { SetKind("spine"); };
|
||||
virtual ~SpineResource(){};
|
||||
virtual SpineResource* Clone() const override {
|
||||
return new SpineResource(*this);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Describe a tilemap file used by a project.
|
||||
*
|
||||
@@ -522,32 +507,6 @@ class GD_CORE_API Model3DResource : public Resource {
|
||||
gd::String file;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Describe an atlas file used by a project.
|
||||
*
|
||||
* \see Resource
|
||||
* \ingroup ResourcesManagement
|
||||
*/
|
||||
class GD_CORE_API AtlasResource : public Resource {
|
||||
public:
|
||||
AtlasResource() : Resource() { SetKind("atlas"); };
|
||||
virtual ~AtlasResource(){};
|
||||
virtual AtlasResource* Clone() const override {
|
||||
return new AtlasResource(*this);
|
||||
}
|
||||
|
||||
virtual const gd::String& GetFile() const override { return file; };
|
||||
virtual void SetFile(const gd::String& newFile) override;
|
||||
|
||||
virtual bool UseFile() const override { return true; }
|
||||
void SerializeTo(SerializerElement& element) const override;
|
||||
|
||||
void UnserializeFrom(const SerializerElement& element) override;
|
||||
|
||||
private:
|
||||
gd::String file;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Inventory all resources used by a project
|
||||
*
|
||||
|
@@ -403,11 +403,6 @@ String String::LowerCase() const
|
||||
return lowerCasedStr;
|
||||
}
|
||||
|
||||
String String::CapitalizeFirstLetter() const
|
||||
{
|
||||
return size() < 1 ? *this : substr(0, 1).UpperCase() + substr(1);
|
||||
}
|
||||
|
||||
String String::FindAndReplace(String search, String replacement, bool all) const
|
||||
{
|
||||
gd::String result(*this);
|
||||
|
@@ -522,11 +522,6 @@ public:
|
||||
*/
|
||||
String LowerCase() const;
|
||||
|
||||
/**
|
||||
* \brief Returns the string with the first letter in upper case.
|
||||
*/
|
||||
String CapitalizeFirstLetter() const;
|
||||
|
||||
/**
|
||||
* \brief Searches a string for a specified substring and returns a new string where all occurrences of this substring is replaced.
|
||||
* \param search The string that will be replaced by the new string.
|
||||
|
@@ -29,9 +29,7 @@
|
||||
#include "GDCore/Project/ExternalEvents.h"
|
||||
|
||||
class ArbitraryResourceWorkerTest : public gd::ArbitraryResourceWorker {
|
||||
public:
|
||||
ArbitraryResourceWorkerTest(gd::ResourcesManager &resourcesManager)
|
||||
: ArbitraryResourceWorker(resourcesManager){};
|
||||
public:
|
||||
virtual void ExposeFile(gd::String& file) { files.push_back(file); };
|
||||
virtual void ExposeImage(gd::String& imageName) {
|
||||
images.push_back(imageName);
|
||||
@@ -61,7 +59,7 @@ TEST_CASE("ArbitraryResourceWorker", "[common][resources]") {
|
||||
"res3", "path/to/file3.png", "image");
|
||||
project.GetResourcesManager().AddResource(
|
||||
"res4", "path/to/file4.png", "audio");
|
||||
ArbitraryResourceWorkerTest worker(project.GetResourcesManager());
|
||||
ArbitraryResourceWorkerTest worker;
|
||||
|
||||
gd::ResourceExposer::ExposeWholeProjectResources(project, worker);
|
||||
REQUIRE(worker.files.size() == 4);
|
||||
@@ -83,7 +81,7 @@ TEST_CASE("ArbitraryResourceWorker", "[common][resources]") {
|
||||
"res3", "path/to/file3.png", "image");
|
||||
project.GetResourcesManager().AddResource(
|
||||
"res4", "path/to/file4.png", "audio");
|
||||
ArbitraryResourceWorkerTest worker(project.GetResourcesManager());
|
||||
ArbitraryResourceWorkerTest worker;
|
||||
|
||||
gd::SpriteObject spriteConfiguration;
|
||||
gd::Animation anim;
|
||||
@@ -128,7 +126,7 @@ TEST_CASE("ArbitraryResourceWorker", "[common][resources]") {
|
||||
"res3", "path/to/file3.png", "image");
|
||||
project.GetResourcesManager().AddResource(
|
||||
"res4", "path/to/file4.png", "audio");
|
||||
ArbitraryResourceWorkerTest worker(project.GetResourcesManager());
|
||||
ArbitraryResourceWorkerTest worker;
|
||||
|
||||
auto& layout = project.InsertNewLayout("Scene", 0);
|
||||
|
||||
@@ -163,7 +161,7 @@ TEST_CASE("ArbitraryResourceWorker", "[common][resources]") {
|
||||
"res3", "path/to/file3.fnt", "bitmapFont");
|
||||
project.GetResourcesManager().AddResource(
|
||||
"res4", "path/to/file4.png", "audio");
|
||||
ArbitraryResourceWorkerTest worker(project.GetResourcesManager());
|
||||
ArbitraryResourceWorkerTest worker;
|
||||
|
||||
auto& layout = project.InsertNewLayout("Scene", 0);
|
||||
|
||||
@@ -198,7 +196,7 @@ TEST_CASE("ArbitraryResourceWorker", "[common][resources]") {
|
||||
"res3", "path/to/file3.fnt", "bitmapFont");
|
||||
project.GetResourcesManager().AddResource(
|
||||
"res4", "path/to/file4.png", "audio");
|
||||
ArbitraryResourceWorkerTest worker(project.GetResourcesManager());
|
||||
ArbitraryResourceWorkerTest worker;
|
||||
|
||||
auto& externalEvents = project.InsertNewExternalEvents("MyExternalEvents", 0);
|
||||
|
||||
@@ -234,7 +232,7 @@ TEST_CASE("ArbitraryResourceWorker", "[common][resources]") {
|
||||
"res2", "path/to/file2.png", "image");
|
||||
project.GetResourcesManager().AddResource(
|
||||
"res3", "path/to/file3.png", "image");
|
||||
ArbitraryResourceWorkerTest worker(project.GetResourcesManager());
|
||||
ArbitraryResourceWorkerTest worker;
|
||||
|
||||
auto& extension = project.InsertNewEventsFunctionsExtension("MyEventExtension", 0);
|
||||
auto& function = extension.InsertNewEventsFunction("MyFreeFunction", 0);
|
||||
@@ -271,7 +269,7 @@ TEST_CASE("ArbitraryResourceWorker", "[common][resources]") {
|
||||
"res2", "path/to/file2.png", "image");
|
||||
project.GetResourcesManager().AddResource(
|
||||
"res3", "path/to/file3.png", "image");
|
||||
ArbitraryResourceWorkerTest worker(project.GetResourcesManager());
|
||||
ArbitraryResourceWorkerTest worker;
|
||||
|
||||
auto& extension = project.InsertNewEventsFunctionsExtension("MyEventExtension", 0);
|
||||
auto& behavior = extension.GetEventsBasedBehaviors().InsertNew("MyBehavior", 0);
|
||||
@@ -309,7 +307,7 @@ TEST_CASE("ArbitraryResourceWorker", "[common][resources]") {
|
||||
"res2", "path/to/file2.png", "image");
|
||||
project.GetResourcesManager().AddResource(
|
||||
"res3", "path/to/file3.png", "image");
|
||||
ArbitraryResourceWorkerTest worker(project.GetResourcesManager());
|
||||
ArbitraryResourceWorkerTest worker;
|
||||
|
||||
auto& extension = project.InsertNewEventsFunctionsExtension("MyEventExtension", 0);
|
||||
auto& object = extension.GetEventsBasedObjects().InsertNew("MyObject", 0);
|
||||
@@ -347,7 +345,7 @@ TEST_CASE("ArbitraryResourceWorker", "[common][resources]") {
|
||||
"res2", "path/to/file2.png", "image");
|
||||
project.GetResourcesManager().AddResource(
|
||||
"res3", "path/to/file3.png", "image");
|
||||
ArbitraryResourceWorkerTest worker(project.GetResourcesManager());
|
||||
ArbitraryResourceWorkerTest worker;
|
||||
|
||||
auto& layout = project.InsertNewLayout("Scene", 0);
|
||||
layout.InsertNewLayer("MyLayer", 0);
|
||||
@@ -373,7 +371,7 @@ TEST_CASE("ArbitraryResourceWorker", "[common][resources]") {
|
||||
"res2", "path/to/file2.png", "image");
|
||||
project.GetResourcesManager().AddResource(
|
||||
"res3", "path/to/file3.png", "image");
|
||||
ArbitraryResourceWorkerTest worker(project.GetResourcesManager());
|
||||
ArbitraryResourceWorkerTest worker;
|
||||
|
||||
auto& layout = project.InsertNewLayout("Scene", 0);
|
||||
layout.InsertNewLayer("MyLayer", 0);
|
||||
@@ -404,7 +402,7 @@ TEST_CASE("ArbitraryResourceWorker", "[common][resources]") {
|
||||
"res3", "path/to/file3.png", "image");
|
||||
project.GetResourcesManager().AddResource(
|
||||
"res4", "path/to/file4.png", "audio");
|
||||
ArbitraryResourceWorkerTest worker(project.GetResourcesManager());
|
||||
ArbitraryResourceWorkerTest worker;
|
||||
|
||||
auto& layout = project.InsertNewLayout("Scene", 0);
|
||||
|
||||
@@ -427,7 +425,7 @@ TEST_CASE("ArbitraryResourceWorker", "[common][resources]") {
|
||||
"res3", "path/to/file3.png", "image");
|
||||
project.GetResourcesManager().AddResource(
|
||||
"res4", "path/to/file4.png", "audio");
|
||||
ArbitraryResourceWorkerTest worker(project.GetResourcesManager());
|
||||
ArbitraryResourceWorkerTest worker;
|
||||
|
||||
auto& layout = project.InsertNewLayout("Scene", 0);
|
||||
|
||||
@@ -461,7 +459,7 @@ TEST_CASE("ArbitraryResourceWorker", "[common][resources]") {
|
||||
"res3", "path/to/file3.fnt", "bitmapFont");
|
||||
project.GetResourcesManager().AddResource(
|
||||
"res4", "path/to/file4.png", "audio");
|
||||
ArbitraryResourceWorkerTest worker(project.GetResourcesManager());
|
||||
ArbitraryResourceWorkerTest worker;
|
||||
|
||||
auto& layout = project.InsertNewLayout("Scene", 0);
|
||||
|
||||
@@ -496,7 +494,7 @@ TEST_CASE("ArbitraryResourceWorker", "[common][resources]") {
|
||||
"res3", "path/to/file3.fnt", "bitmapFont");
|
||||
project.GetResourcesManager().AddResource(
|
||||
"res4", "path/to/file4.png", "audio");
|
||||
ArbitraryResourceWorkerTest worker(project.GetResourcesManager());
|
||||
ArbitraryResourceWorkerTest worker;
|
||||
|
||||
auto& layout = project.InsertNewLayout("MyScene", 0);
|
||||
auto& externalEvents = project.InsertNewExternalEvents("MyExternalEvents", 0);
|
||||
@@ -532,7 +530,7 @@ TEST_CASE("ArbitraryResourceWorker", "[common][resources]") {
|
||||
"res3", "path/to/file3.fnt", "bitmapFont");
|
||||
project.GetResourcesManager().AddResource(
|
||||
"res4", "path/to/file4.png", "audio");
|
||||
ArbitraryResourceWorkerTest worker(project.GetResourcesManager());
|
||||
ArbitraryResourceWorkerTest worker;
|
||||
|
||||
auto& layout = project.InsertNewLayout("MyScene", 0);
|
||||
auto& externalEvents = project.InsertNewExternalEvents("MyExternalEvents", 0);
|
||||
@@ -574,7 +572,7 @@ TEST_CASE("ArbitraryResourceWorker", "[common][resources]") {
|
||||
"res3", "path/to/file3.fnt", "bitmapFont");
|
||||
project.GetResourcesManager().AddResource(
|
||||
"res4", "path/to/file4.png", "audio");
|
||||
ArbitraryResourceWorkerTest worker(project.GetResourcesManager());
|
||||
ArbitraryResourceWorkerTest worker;
|
||||
|
||||
auto& layout = project.InsertNewLayout("Scene", 0);
|
||||
auto& externalEventsA = project.InsertNewExternalEvents("MyExternalEventsA", 0);
|
||||
@@ -621,7 +619,7 @@ TEST_CASE("ArbitraryResourceWorker", "[common][resources]") {
|
||||
"res3", "path/to/file3.fnt", "bitmapFont");
|
||||
project.GetResourcesManager().AddResource(
|
||||
"res4", "path/to/file4.png", "audio");
|
||||
ArbitraryResourceWorkerTest worker(project.GetResourcesManager());
|
||||
ArbitraryResourceWorkerTest worker;
|
||||
|
||||
auto& layout = project.InsertNewLayout("MyScene", 0);
|
||||
auto& otherLayout = project.InsertNewLayout("MyOtherScene", 0);
|
||||
@@ -656,7 +654,7 @@ TEST_CASE("ArbitraryResourceWorker", "[common][resources]") {
|
||||
"res3", "path/to/file3.fnt", "bitmapFont");
|
||||
project.GetResourcesManager().AddResource(
|
||||
"res4", "path/to/file4.png", "audio");
|
||||
ArbitraryResourceWorkerTest worker(project.GetResourcesManager());
|
||||
ArbitraryResourceWorkerTest worker;
|
||||
|
||||
auto& layout = project.InsertNewLayout("MyScene", 0);
|
||||
auto& otherLayout = project.InsertNewLayout("MyOtherScene", 0);
|
||||
@@ -698,7 +696,7 @@ TEST_CASE("ArbitraryResourceWorker", "[common][resources]") {
|
||||
"res3", "path/to/file3.fnt", "bitmapFont");
|
||||
project.GetResourcesManager().AddResource(
|
||||
"res4", "path/to/file4.png", "audio");
|
||||
ArbitraryResourceWorkerTest worker(project.GetResourcesManager());
|
||||
ArbitraryResourceWorkerTest worker;
|
||||
|
||||
auto& layout = project.InsertNewLayout("MyScene", 0);
|
||||
|
||||
@@ -742,7 +740,7 @@ TEST_CASE("ArbitraryResourceWorker", "[common][resources]") {
|
||||
"res2", "path/to/file2.png", "image");
|
||||
project.GetResourcesManager().AddResource(
|
||||
"res3", "path/to/file3.png", "image");
|
||||
ArbitraryResourceWorkerTest worker(project.GetResourcesManager());
|
||||
ArbitraryResourceWorkerTest worker;
|
||||
|
||||
auto& extension = project.InsertNewEventsFunctionsExtension("MyEventExtension", 0);
|
||||
auto& function = extension.InsertNewEventsFunction("MyFreeFunction", 0);
|
||||
@@ -782,7 +780,7 @@ TEST_CASE("ArbitraryResourceWorker", "[common][resources]") {
|
||||
"res2", "path/to/file2.png", "image");
|
||||
project.GetResourcesManager().AddResource(
|
||||
"res3", "path/to/file3.png", "image");
|
||||
ArbitraryResourceWorkerTest worker(project.GetResourcesManager());
|
||||
ArbitraryResourceWorkerTest worker;
|
||||
|
||||
auto& extension = project.InsertNewEventsFunctionsExtension("MyEventExtension", 0);
|
||||
auto& behavior = extension.GetEventsBasedBehaviors().InsertNew("MyBehavior", 0);
|
||||
@@ -823,7 +821,7 @@ TEST_CASE("ArbitraryResourceWorker", "[common][resources]") {
|
||||
"res2", "path/to/file2.png", "image");
|
||||
project.GetResourcesManager().AddResource(
|
||||
"res3", "path/to/file3.png", "image");
|
||||
ArbitraryResourceWorkerTest worker(project.GetResourcesManager());
|
||||
ArbitraryResourceWorkerTest worker;
|
||||
|
||||
auto& extension = project.InsertNewEventsFunctionsExtension("MyEventExtension", 0);
|
||||
auto& object = extension.GetEventsBasedObjects().InsertNew("MyObject", 0);
|
||||
@@ -864,7 +862,7 @@ TEST_CASE("ArbitraryResourceWorker", "[common][resources]") {
|
||||
"res2", "path/to/file2.png", "image");
|
||||
project.GetResourcesManager().AddResource(
|
||||
"res3", "path/to/file3.png", "image");
|
||||
ArbitraryResourceWorkerTest worker(project.GetResourcesManager());
|
||||
ArbitraryResourceWorkerTest worker;
|
||||
|
||||
auto& layout = project.InsertNewLayout("Scene", 0);
|
||||
layout.InsertNewLayer("MyLayer", 0);
|
||||
@@ -889,7 +887,7 @@ TEST_CASE("ArbitraryResourceWorker", "[common][resources]") {
|
||||
"res2", "path/to/file2.png", "image");
|
||||
project.GetResourcesManager().AddResource(
|
||||
"res3", "path/to/file3.png", "image");
|
||||
ArbitraryResourceWorkerTest worker(project.GetResourcesManager());
|
||||
ArbitraryResourceWorkerTest worker;
|
||||
|
||||
auto& layout = project.InsertNewLayout("Scene", 0);
|
||||
layout.InsertNewLayer("MyLayer", 0);
|
||||
|
@@ -489,7 +489,7 @@ void SetupProjectWithDummyPlatform(gd::Project& project,
|
||||
"Effect",
|
||||
_("Apply visual effects to objects."),
|
||||
"",
|
||||
"res/actions/effect_black.svg", "EffectBehavior",
|
||||
"res/actions/effect24.png", "EffectBehavior",
|
||||
std::make_shared<gd::Behavior>(),
|
||||
std::make_shared<gd::BehaviorsSharedData>())
|
||||
.SetHidden();
|
||||
|
@@ -1252,49 +1252,6 @@ TEST_CASE("ExpressionCodeGenerator", "[common][events]") {
|
||||
"MySpriteObject.getObjectStringWith2ObjectParam(fakeObjectListOf_"
|
||||
"Object1, fakeObjectListOf_Object2) ?? \"\"");
|
||||
}
|
||||
SECTION("Edge cases (variables with object name in objectvar parameter)") {
|
||||
SECTION("Simple case") {
|
||||
gd::String output = gd::ExpressionCodeGenerator::GenerateExpressionCode(
|
||||
codeGenerator,
|
||||
context,
|
||||
"objectvar", // We suppose we generate an "objectvar" parameter.
|
||||
"MyOtherSpriteObject", // This "variable name" is the same as an object name (but this is valid).
|
||||
"MySpriteObject" // The object owning the variable: MySpriteObject.
|
||||
);
|
||||
|
||||
// This seems "obvious", but we had cases where MyOtherSpriteObject could have been interpreted as an object
|
||||
// when the code generation is not properly recognizing "objectvar".
|
||||
REQUIRE(output == "getVariableForObject(MySpriteObject, MyOtherSpriteObject)");
|
||||
}
|
||||
|
||||
SECTION("With child variable") {
|
||||
gd::String output = gd::ExpressionCodeGenerator::GenerateExpressionCode(
|
||||
codeGenerator,
|
||||
context,
|
||||
"objectvar", // We suppose we generate an "objectvar" parameter.
|
||||
"MyOtherSpriteObject.Child", // This "variable name" is the same as an object name (but this is valid).
|
||||
"MySpriteObject" // The object owning the variable: MySpriteObject.
|
||||
);
|
||||
|
||||
// This seems "obvious", but we had cases where MyOtherSpriteObject could have been interpreted as an object
|
||||
// when the code generation is not properly recognizing "objectvar".
|
||||
REQUIRE(output == "getVariableForObject(MySpriteObject, MyOtherSpriteObject).getChild(\"Child\")");
|
||||
}
|
||||
|
||||
SECTION("With child and grandchild variable") {
|
||||
gd::String output = gd::ExpressionCodeGenerator::GenerateExpressionCode(
|
||||
codeGenerator,
|
||||
context,
|
||||
"objectvar", // We suppose we generate an "objectvar" parameter.
|
||||
"MyOtherSpriteObject.Child.Grandchild", // This "variable name" is the same as an object name (but this is valid).
|
||||
"MySpriteObject" // The object owning the variable: MySpriteObject.
|
||||
);
|
||||
|
||||
// This seems "obvious", but we had cases where MyOtherSpriteObject could have been interpreted as an object
|
||||
// when the code generation is not properly recognizing "objectvar".
|
||||
REQUIRE(output == "getVariableForObject(MySpriteObject, MyOtherSpriteObject).getChild(\"Child\").getChild(\"Grandchild\")");
|
||||
}
|
||||
}
|
||||
SECTION("Mixed test (1)") {
|
||||
{
|
||||
auto node = parser.ParseExpression("-+-MyExtension::MouseX(,)");
|
||||
|
@@ -11,7 +11,6 @@
|
||||
#include "GDCore/IDE/Events/ExpressionValidator.h"
|
||||
#include "GDCore/IDE/Events/ExpressionTypeFinder.h"
|
||||
#include "GDCore/IDE/Events/ExpressionVariableOwnerFinder.h"
|
||||
#include "GDCore/IDE/Events/ExpressionVariableParentFinder.h"
|
||||
#include "GDCore/Project/Layout.h"
|
||||
#include "GDCore/Project/Project.h"
|
||||
#include "GDCore/Project/ProjectScopedContainers.h"
|
||||
@@ -203,23 +202,6 @@ TEST_CASE("ExpressionParser2", "[common][events]") {
|
||||
auto node = parser.ParseExpression("abcd[0]");
|
||||
REQUIRE(node != nullptr);
|
||||
|
||||
// Also check that if we try to find the last parent of node, it is not defined.
|
||||
auto lastParentOfNode = gd::ExpressionVariableParentFinder::GetLastParentOfNode(
|
||||
platform, projectScopedContainers, *node);
|
||||
REQUIRE(lastParentOfNode.parentVariable == nullptr);
|
||||
REQUIRE(lastParentOfNode.parentVariablesContainer == nullptr);
|
||||
|
||||
gd::ExpressionValidator validator(platform, projectScopedContainers, "string");
|
||||
node->Visit(validator);
|
||||
REQUIRE(validator.GetFatalErrors().size() == 1);
|
||||
REQUIRE(validator.GetFatalErrors()[0]->GetMessage() ==
|
||||
"No object, variable or property with this name found.");
|
||||
REQUIRE(validator.GetFatalErrors()[0]->GetStartPosition() == 0);
|
||||
}
|
||||
{
|
||||
auto node = parser.ParseExpression("abcd[0].efg");
|
||||
REQUIRE(node != nullptr);
|
||||
|
||||
gd::ExpressionValidator validator(platform, projectScopedContainers, "string");
|
||||
node->Visit(validator);
|
||||
REQUIRE(validator.GetFatalErrors().size() == 1);
|
||||
@@ -231,12 +213,6 @@ TEST_CASE("ExpressionParser2", "[common][events]") {
|
||||
auto node = parser.ParseExpression("abcd.efg.hij");
|
||||
REQUIRE(node != nullptr);
|
||||
|
||||
// Also check that if we try to find the last parent of node, it is not defined.
|
||||
auto lastParentOfNode = gd::ExpressionVariableParentFinder::GetLastParentOfNode(
|
||||
platform, projectScopedContainers, *node);
|
||||
REQUIRE(lastParentOfNode.parentVariable == nullptr);
|
||||
REQUIRE(lastParentOfNode.parentVariablesContainer == nullptr);
|
||||
|
||||
gd::ExpressionValidator validator(platform, projectScopedContainers, "string");
|
||||
node->Visit(validator);
|
||||
REQUIRE(validator.GetFatalErrors().size() == 1);
|
||||
@@ -785,12 +761,6 @@ TEST_CASE("ExpressionParser2", "[common][events]") {
|
||||
auto node = parser.ParseExpression("abcd.efg.hij");
|
||||
REQUIRE(node != nullptr);
|
||||
|
||||
// Also check that if we try to find the last parent of node, it is not defined.
|
||||
auto lastParentOfNode = gd::ExpressionVariableParentFinder::GetLastParentOfNode(
|
||||
platform, projectScopedContainers, *node);
|
||||
REQUIRE(lastParentOfNode.parentVariable == nullptr);
|
||||
REQUIRE(lastParentOfNode.parentVariablesContainer == nullptr);
|
||||
|
||||
gd::ExpressionValidator validator(platform, projectScopedContainers, "number");
|
||||
node->Visit(validator);
|
||||
REQUIRE(validator.GetFatalErrors().size() == 1);
|
||||
@@ -1524,12 +1494,6 @@ TEST_CASE("ExpressionParser2", "[common][events]") {
|
||||
auto node =
|
||||
parser.ParseExpression("MyNonExistingSceneVariable");
|
||||
|
||||
// Also check that if we try to find the last parent of node, it is not defined.
|
||||
auto lastParentOfNode = gd::ExpressionVariableParentFinder::GetLastParentOfNode(
|
||||
platform, projectScopedContainers, *node);
|
||||
REQUIRE(lastParentOfNode.parentVariable == nullptr);
|
||||
REQUIRE(lastParentOfNode.parentVariablesContainer == nullptr);
|
||||
|
||||
gd::ExpressionValidator validator(platform, projectScopedContainers, "number|string");
|
||||
node->Visit(validator);
|
||||
REQUIRE(validator.GetFatalErrors().size() == 1);
|
||||
@@ -1551,25 +1515,6 @@ TEST_CASE("ExpressionParser2", "[common][events]") {
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("Invalid scene variables (2 levels, variable and child do not exist)") {
|
||||
{
|
||||
auto node =
|
||||
parser.ParseExpression("MyNonExistingSceneVariable.MyNonExistingChild");
|
||||
|
||||
// Also check that if we try to find the last parent of node, it is not defined.
|
||||
auto lastParentOfNode = gd::ExpressionVariableParentFinder::GetLastParentOfNode(
|
||||
platform, projectScopedContainers, *node);
|
||||
REQUIRE(lastParentOfNode.parentVariable == nullptr);
|
||||
REQUIRE(lastParentOfNode.parentVariablesContainer == nullptr);
|
||||
|
||||
gd::ExpressionValidator validator(platform, projectScopedContainers, "number|string");
|
||||
node->Visit(validator);
|
||||
REQUIRE(validator.GetFatalErrors().size() == 1);
|
||||
REQUIRE(validator.GetFatalErrors()[0]->GetMessage() ==
|
||||
"You must enter a number or a text, wrapped inside double quotes (example: \"Hello world\"), or a variable name.");
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("Valid object variables (1 level)") {
|
||||
{
|
||||
auto node =
|
||||
@@ -1640,12 +1585,6 @@ TEST_CASE("ExpressionParser2", "[common][events]") {
|
||||
auto node =
|
||||
parser.ParseExpression("MyNonExistingSpriteObject.MyVariable");
|
||||
|
||||
// Also check that if we try to find the last parent of node, it is not defined.
|
||||
auto lastParentOfNode = gd::ExpressionVariableParentFinder::GetLastParentOfNode(
|
||||
platform, projectScopedContainers, *node);
|
||||
REQUIRE(lastParentOfNode.parentVariable == nullptr);
|
||||
REQUIRE(lastParentOfNode.parentVariablesContainer == nullptr);
|
||||
|
||||
gd::ExpressionValidator validator(platform, projectScopedContainers, "number|string");
|
||||
node->Visit(validator);
|
||||
REQUIRE(validator.GetFatalErrors().size() == 1);
|
||||
@@ -1667,21 +1606,6 @@ TEST_CASE("ExpressionParser2", "[common][events]") {
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("Invalid object variables (empty variable name, extra dot)") {
|
||||
{
|
||||
auto node =
|
||||
parser.ParseExpression("MySpriteObjects..");
|
||||
|
||||
gd::ExpressionValidator validator(platform, projectScopedContainers, "number|string");
|
||||
node->Visit(validator);
|
||||
REQUIRE(validator.GetFatalErrors().size() == 2);
|
||||
REQUIRE(validator.GetFatalErrors()[0]->GetMessage() ==
|
||||
"A name should be entered after the dot.");
|
||||
REQUIRE(validator.GetFatalErrors()[1]->GetMessage() ==
|
||||
"A name should be entered after the dot.");
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("Invalid object variables (object group, partially existing variable)") {
|
||||
{
|
||||
auto node =
|
||||
@@ -1766,42 +1690,6 @@ TEST_CASE("ExpressionParser2", "[common][events]") {
|
||||
"An object variable or expression should be entered.");
|
||||
}
|
||||
}
|
||||
SECTION("Invalid object variables (extra dot)") {
|
||||
{
|
||||
auto node =
|
||||
parser.ParseExpression("MySpriteObject.MyVariable.");
|
||||
|
||||
gd::ExpressionValidator validator(platform, projectScopedContainers, "number|string");
|
||||
node->Visit(validator);
|
||||
REQUIRE(validator.GetFatalErrors().size() == 1);
|
||||
REQUIRE(validator.GetFatalErrors()[0]->GetMessage() ==
|
||||
"A name should be entered after the dot.");
|
||||
}
|
||||
}
|
||||
SECTION("Invalid object variables (extra dot after brackets)") {
|
||||
{
|
||||
auto node =
|
||||
parser.ParseExpression("MySpriteObject.MyVariable[\"MyChild\"].");
|
||||
|
||||
gd::ExpressionValidator validator(platform, projectScopedContainers, "number|string");
|
||||
node->Visit(validator);
|
||||
REQUIRE(validator.GetFatalErrors().size() == 1);
|
||||
REQUIRE(validator.GetFatalErrors()[0]->GetMessage() ==
|
||||
"A name should be entered after the dot.");
|
||||
}
|
||||
}
|
||||
SECTION("Invalid object variables (extra dot before brackets)") {
|
||||
{
|
||||
auto node =
|
||||
parser.ParseExpression("MySpriteObject.MyVariable.[\"MyChild\"]");
|
||||
|
||||
gd::ExpressionValidator validator(platform, projectScopedContainers, "number|string");
|
||||
node->Visit(validator);
|
||||
REQUIRE(validator.GetFatalErrors().size() == 1);
|
||||
REQUIRE(validator.GetFatalErrors()[0]->GetMessage() ==
|
||||
"A name should be entered after the dot.");
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("Valid property") {
|
||||
gd::PropertiesContainer propertiesContainer(gd::EventsFunctionsContainer::Extension);
|
||||
@@ -2268,14 +2156,6 @@ TEST_CASE("ExpressionParser2", "[common][events]") {
|
||||
dynamic_cast<gd::IdentifierNode &>(*node);
|
||||
REQUIRE(identifierNode.identifierName == "MyObject");
|
||||
REQUIRE(identifierNode.childIdentifierName == "");
|
||||
|
||||
gd::ExpressionValidator validator(platform, projectScopedContainers, "number");
|
||||
node->Visit(validator);
|
||||
REQUIRE(validator.GetFatalErrors().size() == 2);
|
||||
REQUIRE(validator.GetFatalErrors()[0]->GetMessage() ==
|
||||
"A name should be entered after the dot.");
|
||||
REQUIRE(validator.GetFatalErrors()[1]->GetMessage() ==
|
||||
"An object variable or expression should be entered.");
|
||||
}
|
||||
|
||||
SECTION("Unfinished object function name of type string with parentheses") {
|
||||
@@ -2287,14 +2167,6 @@ TEST_CASE("ExpressionParser2", "[common][events]") {
|
||||
REQUIRE(objectFunctionCall.objectName == "MyObject");
|
||||
REQUIRE(objectFunctionCall.functionName == "");
|
||||
REQUIRE(type == "string");
|
||||
|
||||
gd::ExpressionValidator validator(platform, projectScopedContainers, "number");
|
||||
node->Visit(validator);
|
||||
REQUIRE(validator.GetFatalErrors().size() == 2);
|
||||
REQUIRE(validator.GetFatalErrors()[0]->GetMessage() ==
|
||||
"A name should be entered after the dot.");
|
||||
REQUIRE(validator.GetFatalErrors()[1]->GetMessage() ==
|
||||
"Enter the name of the function to call.");
|
||||
}
|
||||
|
||||
SECTION("Unfinished object function name of type number with parentheses") {
|
||||
@@ -2321,19 +2193,6 @@ TEST_CASE("ExpressionParser2", "[common][events]") {
|
||||
REQUIRE(type == "number|string");
|
||||
}
|
||||
|
||||
SECTION("Unfinished object function/variable name with multiple dots") {
|
||||
auto node = parser.ParseExpression("MyObject..");
|
||||
REQUIRE(node != nullptr);
|
||||
|
||||
gd::ExpressionValidator validator(platform, projectScopedContainers, "number");
|
||||
node->Visit(validator);
|
||||
REQUIRE(validator.GetFatalErrors().size() == 2);
|
||||
REQUIRE(validator.GetFatalErrors()[0]->GetMessage() ==
|
||||
"A name should be entered after the dot.");
|
||||
REQUIRE(validator.GetFatalErrors()[1]->GetMessage() ==
|
||||
"A name should be entered after the dot.");
|
||||
}
|
||||
|
||||
SECTION("Unfinished object behavior name") {
|
||||
auto node = parser.ParseExpression("MyObject.MyBehavior::");
|
||||
REQUIRE(node != nullptr);
|
||||
@@ -2342,12 +2201,6 @@ TEST_CASE("ExpressionParser2", "[common][events]") {
|
||||
REQUIRE(objectFunctionName.objectName == "MyObject");
|
||||
REQUIRE(objectFunctionName.objectFunctionOrBehaviorName == "MyBehavior");
|
||||
REQUIRE(objectFunctionName.behaviorFunctionName == "");
|
||||
|
||||
gd::ExpressionValidator validator(platform, projectScopedContainers, "number");
|
||||
node->Visit(validator);
|
||||
REQUIRE(validator.GetFatalErrors().size() == 1);
|
||||
REQUIRE(validator.GetFatalErrors()[0]->GetMessage() ==
|
||||
"An opening parenthesis was expected here to call a function.");
|
||||
}
|
||||
|
||||
SECTION("Unfinished object behavior name of type string with parentheses") {
|
||||
@@ -2360,12 +2213,6 @@ TEST_CASE("ExpressionParser2", "[common][events]") {
|
||||
REQUIRE(objectFunctionName.behaviorName == "MyBehavior");
|
||||
REQUIRE(objectFunctionName.functionName == "");
|
||||
REQUIRE(type == "string");
|
||||
|
||||
gd::ExpressionValidator validator(platform, projectScopedContainers, "number");
|
||||
node->Visit(validator);
|
||||
REQUIRE(validator.GetFatalErrors().size() == 1);
|
||||
REQUIRE(validator.GetFatalErrors()[0]->GetMessage() ==
|
||||
"Enter the name of the function to call.");
|
||||
}
|
||||
|
||||
SECTION("Unfinished object behavior name of type number with parentheses") {
|
||||
@@ -2651,8 +2498,10 @@ TEST_CASE("ExpressionParser2", "[common][events]") {
|
||||
node->Visit(validator);
|
||||
REQUIRE(validator.GetFatalErrors().size() == 1);
|
||||
|
||||
// TODO: The error message could be improved
|
||||
REQUIRE(validator.GetFatalErrors()[0]->GetMessage() ==
|
||||
"Enter the name of the function to call.");
|
||||
"Cannot find an expression with this name: \nDouble "
|
||||
"check that you've not made any typo in the name.");
|
||||
REQUIRE(validator.GetFatalErrors()[0]->GetStartPosition() == 0);
|
||||
REQUIRE(validator.GetFatalErrors()[0]->GetEndPosition() == 25);
|
||||
}
|
||||
@@ -2960,8 +2809,8 @@ TEST_CASE("ExpressionParser2", "[common][events]") {
|
||||
// as ExpressionVariableOwnerFinder depends on this parameter type
|
||||
// information.
|
||||
auto node = parser.ParseExpression(
|
||||
"MyExtension::GetStringWith2ObjectParamAnd2ObjectVarParam(MySpriteObject, "
|
||||
"MyVariable, MySpriteObject2, MyVariable2)");
|
||||
"MyExtension::GetStringWith2ObjectParamAnd2ObjectVarParam(MyObject1, "
|
||||
"MyVar1, MyObject2, MyVar2)");
|
||||
REQUIRE(node != nullptr);
|
||||
auto &functionNode = dynamic_cast<gd::FunctionCallNode &>(*node);
|
||||
auto &identifierObject1Node =
|
||||
@@ -2973,25 +2822,17 @@ TEST_CASE("ExpressionParser2", "[common][events]") {
|
||||
auto &variable2Node =
|
||||
dynamic_cast<gd::IdentifierNode &>(*functionNode.parameters[3]);
|
||||
|
||||
REQUIRE(identifierObject1Node.identifierName == "MySpriteObject");
|
||||
REQUIRE(identifierObject2Node.identifierName == "MySpriteObject2");
|
||||
REQUIRE(variable1Node.identifierName == "MyVariable");
|
||||
REQUIRE(variable2Node.identifierName == "MyVariable2");
|
||||
REQUIRE(identifierObject1Node.identifierName == "MyObject1");
|
||||
REQUIRE(identifierObject2Node.identifierName == "MyObject2");
|
||||
REQUIRE(variable1Node.identifierName == "MyVar1");
|
||||
REQUIRE(variable2Node.identifierName == "MyVar2");
|
||||
|
||||
auto variable1ObjectName = gd::ExpressionVariableOwnerFinder::GetObjectName(
|
||||
platform, objectsContainersList, "", variable1Node);
|
||||
REQUIRE(variable1ObjectName == "MySpriteObject");
|
||||
REQUIRE(variable1ObjectName == "MyObject1");
|
||||
auto variable2ObjectName = gd::ExpressionVariableOwnerFinder::GetObjectName(
|
||||
platform, objectsContainersList, "", variable2Node);
|
||||
REQUIRE(variable2ObjectName == "MySpriteObject2");
|
||||
|
||||
// Also check the ability to find the last parent of the variables:
|
||||
auto lastParentOfVariable1Node = gd::ExpressionVariableParentFinder::GetLastParentOfNode(
|
||||
platform, projectScopedContainers, variable1Node);
|
||||
REQUIRE(lastParentOfVariable1Node.parentVariablesContainer == &mySpriteObject.GetVariables());
|
||||
auto lastParentOfVariable2Node = gd::ExpressionVariableParentFinder::GetLastParentOfNode(
|
||||
platform, projectScopedContainers, variable2Node);
|
||||
REQUIRE(lastParentOfVariable2Node.parentVariablesContainer == &mySpriteObject2.GetVariables());
|
||||
REQUIRE(variable2ObjectName == "MyObject2");
|
||||
|
||||
gd::ExpressionValidator validator(platform, projectScopedContainers, "string");
|
||||
node->Visit(validator);
|
||||
@@ -3002,8 +2843,8 @@ TEST_CASE("ExpressionParser2", "[common][events]") {
|
||||
SECTION("Valid function call with 2 object variable from the same object") {
|
||||
{
|
||||
auto node = parser.ParseExpression(
|
||||
"MyExtension::GetStringWith1ObjectParamAnd2ObjectVarParam(MySpriteObject, "
|
||||
"MyVariable, MyVariable2)");
|
||||
"MyExtension::GetStringWith1ObjectParamAnd2ObjectVarParam(MyObject1, "
|
||||
"MyVar1, MyVar2)");
|
||||
REQUIRE(node != nullptr);
|
||||
auto &functionNode = dynamic_cast<gd::FunctionCallNode &>(*node);
|
||||
auto &identifierObject1Node =
|
||||
@@ -3013,24 +2854,16 @@ TEST_CASE("ExpressionParser2", "[common][events]") {
|
||||
auto &variable2Node =
|
||||
dynamic_cast<gd::IdentifierNode &>(*functionNode.parameters[2]);
|
||||
|
||||
REQUIRE(identifierObject1Node.identifierName == "MySpriteObject");
|
||||
REQUIRE(variable1Node.identifierName == "MyVariable");
|
||||
REQUIRE(variable2Node.identifierName == "MyVariable2");
|
||||
REQUIRE(identifierObject1Node.identifierName == "MyObject1");
|
||||
REQUIRE(variable1Node.identifierName == "MyVar1");
|
||||
REQUIRE(variable2Node.identifierName == "MyVar2");
|
||||
|
||||
auto variable1ObjectName = gd::ExpressionVariableOwnerFinder::GetObjectName(
|
||||
platform, objectsContainersList, "", variable1Node);
|
||||
REQUIRE(variable1ObjectName == "MySpriteObject");
|
||||
REQUIRE(variable1ObjectName == "MyObject1");
|
||||
auto variable2ObjectName = gd::ExpressionVariableOwnerFinder::GetObjectName(
|
||||
platform, objectsContainersList, "", variable2Node);
|
||||
REQUIRE(variable2ObjectName == "MySpriteObject");
|
||||
|
||||
// Also check the ability to find the last parent of the variables:
|
||||
auto lastParentOfVariable1Node = gd::ExpressionVariableParentFinder::GetLastParentOfNode(
|
||||
platform, projectScopedContainers, variable1Node);
|
||||
REQUIRE(lastParentOfVariable1Node.parentVariablesContainer == &mySpriteObject.GetVariables());
|
||||
auto lastParentOfVariable2Node = gd::ExpressionVariableParentFinder::GetLastParentOfNode(
|
||||
platform, projectScopedContainers, variable2Node);
|
||||
REQUIRE(lastParentOfVariable2Node.parentVariablesContainer == &mySpriteObject.GetVariables());
|
||||
REQUIRE(variable2ObjectName == "MyObject1");
|
||||
|
||||
gd::ExpressionValidator validator(platform, projectScopedContainers, "string");
|
||||
node->Visit(validator);
|
||||
@@ -3041,23 +2874,18 @@ TEST_CASE("ExpressionParser2", "[common][events]") {
|
||||
SECTION("Valid object function call with 1 object variable from the object of the function") {
|
||||
{
|
||||
auto node = parser.ParseExpression(
|
||||
"MySpriteObject.GetObjectVariableAsNumber(MyVariable)");
|
||||
"MySpriteObject.GetObjectVariableAsNumber(MyVar1)");
|
||||
REQUIRE(node != nullptr);
|
||||
auto &functionNode = dynamic_cast<gd::FunctionCallNode &>(*node);
|
||||
auto &variable1Node =
|
||||
dynamic_cast<gd::IdentifierNode &>(*functionNode.parameters[0]);
|
||||
|
||||
REQUIRE(variable1Node.identifierName == "MyVariable");
|
||||
REQUIRE(variable1Node.identifierName == "MyVar1");
|
||||
|
||||
auto variable1ObjectName = gd::ExpressionVariableOwnerFinder::GetObjectName(
|
||||
platform, objectsContainersList, "MySpriteObject", variable1Node);
|
||||
REQUIRE(variable1ObjectName == "MySpriteObject");
|
||||
|
||||
// Also check the ability to find the last parent of the variable:
|
||||
auto lastParentOfVariable1Node = gd::ExpressionVariableParentFinder::GetLastParentOfNode(
|
||||
platform, projectScopedContainers, variable1Node);
|
||||
REQUIRE(lastParentOfVariable1Node.parentVariablesContainer == &mySpriteObject.GetVariables());
|
||||
|
||||
gd::ExpressionValidator validator(platform, projectScopedContainers, "number");
|
||||
node->Visit(validator);
|
||||
REQUIRE(validator.GetFatalErrors().size() == 0);
|
||||
@@ -3067,24 +2895,19 @@ TEST_CASE("ExpressionParser2", "[common][events]") {
|
||||
SECTION("Valid object function call with 1 object variable from the object of the function with a child") {
|
||||
{
|
||||
auto node = parser.ParseExpression(
|
||||
"MySpriteObject.GetObjectVariableAsNumber(MyVariable.MyChild)");
|
||||
"MySpriteObject.GetObjectVariableAsNumber(MyVar1.MyChild)");
|
||||
REQUIRE(node != nullptr);
|
||||
auto &functionNode = dynamic_cast<gd::FunctionCallNode &>(*node);
|
||||
auto &variable1Node =
|
||||
dynamic_cast<gd::IdentifierNode &>(*functionNode.parameters[0]);
|
||||
|
||||
REQUIRE(variable1Node.identifierName == "MyVariable");
|
||||
REQUIRE(variable1Node.identifierName == "MyVar1");
|
||||
REQUIRE(variable1Node.childIdentifierName == "MyChild");
|
||||
|
||||
auto variable1ObjectName = gd::ExpressionVariableOwnerFinder::GetObjectName(
|
||||
platform, objectsContainersList, "MySpriteObject", variable1Node);
|
||||
REQUIRE(variable1ObjectName == "MySpriteObject");
|
||||
|
||||
// Also check the ability to find the last parent of the variable:
|
||||
auto lastParentOfVariable1Node = gd::ExpressionVariableParentFinder::GetLastParentOfNode(
|
||||
platform, projectScopedContainers, variable1Node);
|
||||
REQUIRE(lastParentOfVariable1Node.parentVariable == &mySpriteObject.GetVariables().Get("MyVariable"));
|
||||
|
||||
gd::ExpressionValidator validator(platform, projectScopedContainers, "number");
|
||||
node->Visit(validator);
|
||||
REQUIRE(validator.GetFatalErrors().size() == 0);
|
||||
|
@@ -1,147 +0,0 @@
|
||||
/*
|
||||
* GDevelop Core
|
||||
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
/**
|
||||
* @file Tests covering common features of GDevelop Core.
|
||||
*/
|
||||
#include "GDCore/IDE/ObjectAssetSerializer.h"
|
||||
|
||||
#include "DummyPlatform.h"
|
||||
#include "GDCore/CommonTools.h"
|
||||
#include "GDCore/Events/Builtin/StandardEvent.h"
|
||||
#include "GDCore/Events/Event.h"
|
||||
#include "GDCore/Events/EventsList.h"
|
||||
#include "GDCore/Events/Serialization.h"
|
||||
#include "GDCore/Extensions/Builtin/SpriteExtension/SpriteObject.h"
|
||||
#include "GDCore/Extensions/Platform.h"
|
||||
#include "GDCore/Project/CustomObjectConfiguration.h"
|
||||
#include "GDCore/Project/EventsFunctionsExtension.h"
|
||||
#include "GDCore/Project/Layout.h"
|
||||
#include "GDCore/Project/Object.h"
|
||||
#include "GDCore/Project/ObjectsContainer.h"
|
||||
#include "GDCore/Project/Project.h"
|
||||
#include "GDCore/Project/Variable.h"
|
||||
#include "GDCore/Serialization/Serializer.h"
|
||||
#include "GDCore/Tools/SystemStats.h"
|
||||
#include "GDCore/Tools/VersionWrapper.h"
|
||||
#include "catch.hpp"
|
||||
#include <string>
|
||||
|
||||
using namespace gd;
|
||||
|
||||
TEST_CASE("ObjectAssetSerializer", "[common]") {
|
||||
|
||||
SECTION("Can serialize custom objects as assets") {
|
||||
gd::Platform platform;
|
||||
gd::Project project;
|
||||
SetupProjectWithDummyPlatform(project, platform);
|
||||
auto &eventsExtension =
|
||||
project.InsertNewEventsFunctionsExtension("MyEventsExtension", 0);
|
||||
auto &eventsBasedObject = eventsExtension.GetEventsBasedObjects().InsertNew(
|
||||
"MyEventsBasedObject", 0);
|
||||
eventsBasedObject.SetFullName("My events based object");
|
||||
eventsBasedObject.SetDescription("An events based object for test");
|
||||
eventsBasedObject.InsertNewObject(project, "MyExtension::Sprite", "MyChild",
|
||||
0);
|
||||
|
||||
auto &resourceManager = project.GetResourcesManager();
|
||||
gd::ImageResource imageResource;
|
||||
imageResource.SetName("assets/Idle.png");
|
||||
imageResource.SetFile("assets/Idle.png");
|
||||
imageResource.SetSmooth(true);
|
||||
resourceManager.AddResource(imageResource);
|
||||
|
||||
gd::Layout &layout = project.InsertNewLayout("Scene", 0);
|
||||
gd::Object &object = layout.InsertNewObject(
|
||||
project, "MyEventsExtension::MyEventsBasedObject", "MyObject", 0);
|
||||
auto &configuration = object.GetConfiguration();
|
||||
auto *customObjectConfiguration =
|
||||
dynamic_cast<gd::CustomObjectConfiguration *>(&configuration);
|
||||
auto *spriteConfiguration = dynamic_cast<gd::SpriteObject *>(
|
||||
&customObjectConfiguration->GetChildObjectConfiguration("MyChild"));
|
||||
REQUIRE(spriteConfiguration != nullptr);
|
||||
{
|
||||
gd::Animation animation;
|
||||
animation.SetName("Idle");
|
||||
animation.SetDirectionsCount(1);
|
||||
auto &direction = animation.GetDirection(0);
|
||||
gd::Sprite frame;
|
||||
frame.SetImageName("assets/Idle.png");
|
||||
direction.AddSprite(frame);
|
||||
|
||||
spriteConfiguration->AddAnimation(animation);
|
||||
}
|
||||
|
||||
SerializerElement assetElement;
|
||||
std::vector<gd::String> usedResourceNames;
|
||||
ObjectAssetSerializer::SerializeTo(project, object, "My Object",
|
||||
assetElement, usedResourceNames);
|
||||
|
||||
// This list is used to copy resource files.
|
||||
REQUIRE(usedResourceNames.size() == 1);
|
||||
REQUIRE(usedResourceNames[0] == "assets/Idle.png");
|
||||
|
||||
// Check that the project is left untouched.
|
||||
REQUIRE(resourceManager.HasResource("assets/Idle.png"));
|
||||
REQUIRE(resourceManager.GetResource("assets/Idle.png").GetFile() ==
|
||||
"assets/Idle.png");
|
||||
REQUIRE(!resourceManager.HasResource("Idle.png"));
|
||||
|
||||
REQUIRE(assetElement.HasChild("objectAssets"));
|
||||
auto &objectAssetsElement = assetElement.GetChild("objectAssets");
|
||||
objectAssetsElement.ConsiderAsArrayOf("objectAsset");
|
||||
REQUIRE(objectAssetsElement.GetChildrenCount() == 1);
|
||||
auto &objectAssetElement = objectAssetsElement.GetChild(0);
|
||||
|
||||
REQUIRE(objectAssetElement.HasChild("requiredExtensions"));
|
||||
auto &requiredExtensionsElement =
|
||||
objectAssetElement.GetChild("requiredExtensions");
|
||||
requiredExtensionsElement.ConsiderAsArrayOf("requiredExtension");
|
||||
REQUIRE(requiredExtensionsElement.GetChildrenCount() == 1);
|
||||
auto &requiredExtensionElement = requiredExtensionsElement.GetChild(0);
|
||||
REQUIRE(requiredExtensionElement.GetStringAttribute("extensionName") ==
|
||||
"MyEventsExtension");
|
||||
|
||||
// Resources are renamed according to asset script naming conventions.
|
||||
REQUIRE(objectAssetElement.HasChild("resources"));
|
||||
auto &resourcesElement = objectAssetElement.GetChild("resources");
|
||||
resourcesElement.ConsiderAsArrayOf("resource");
|
||||
REQUIRE(resourcesElement.GetChildrenCount() == 1);
|
||||
{
|
||||
auto &resourceElement = resourcesElement.GetChild(0);
|
||||
REQUIRE(resourceElement.GetStringAttribute("name") == "assets/Idle.png");
|
||||
REQUIRE(resourceElement.GetStringAttribute("file") == "assets/Idle.png");
|
||||
REQUIRE(resourceElement.GetStringAttribute("kind") == "image");
|
||||
REQUIRE(resourceElement.GetBoolAttribute("smoothed") == true);
|
||||
}
|
||||
|
||||
// Resources used in object configuration are updated.
|
||||
REQUIRE(objectAssetElement.HasChild("object"));
|
||||
auto &objectElement = objectAssetElement.GetChild("object");
|
||||
REQUIRE(objectElement.GetStringAttribute("name") == "MyObject");
|
||||
REQUIRE(objectElement.GetStringAttribute("type") ==
|
||||
"MyEventsExtension::MyEventsBasedObject");
|
||||
auto &childrenContentElement = objectElement.GetChild("childrenContent");
|
||||
|
||||
REQUIRE(childrenContentElement.HasChild("MyChild"));
|
||||
auto &childElement = childrenContentElement.GetChild("MyChild");
|
||||
REQUIRE(childElement.HasChild("animations"));
|
||||
auto &animationsElement = childElement.GetChild("animations");
|
||||
animationsElement.ConsiderAsArrayOf("animation");
|
||||
REQUIRE(animationsElement.GetChildrenCount() == 1);
|
||||
auto &animationElement = animationsElement.GetChild(0);
|
||||
|
||||
REQUIRE(animationElement.GetStringAttribute("name") == "Idle");
|
||||
auto &directionsElement = animationElement.GetChild("directions");
|
||||
directionsElement.ConsiderAsArrayOf("direction");
|
||||
REQUIRE(directionsElement.GetChildrenCount() == 1);
|
||||
auto &directionElement = directionsElement.GetChild(0);
|
||||
auto &spritesElement = directionElement.GetChild("sprites");
|
||||
spritesElement.ConsiderAsArrayOf("sprite");
|
||||
REQUIRE(spritesElement.GetChildrenCount() == 1);
|
||||
auto &spriteElement = spritesElement.GetChild(0);
|
||||
REQUIRE(spriteElement.GetStringAttribute("image") == "assets/Idle.png");
|
||||
}
|
||||
}
|
@@ -91,7 +91,8 @@ TEST_CASE("PropertyFunctionGenerator", "[common]") {
|
||||
auto &getterAction = getterEvent.GetActions().at(0);
|
||||
REQUIRE(getterAction.GetType() == "SetReturnNumber");
|
||||
REQUIRE(getterAction.GetParametersCount() == 1);
|
||||
REQUIRE(getterAction.GetParameter(0).GetPlainString() == "MovementAngle");
|
||||
REQUIRE(getterAction.GetParameter(0).GetPlainString() ==
|
||||
"Object.Behavior::PropertyMovementAngle()");
|
||||
}
|
||||
{
|
||||
auto &setter =
|
||||
@@ -123,7 +124,8 @@ TEST_CASE("PropertyFunctionGenerator", "[common]") {
|
||||
REQUIRE(setterAction.GetParameter(0).GetPlainString() == "Object");
|
||||
REQUIRE(setterAction.GetParameter(1).GetPlainString() == "Behavior");
|
||||
REQUIRE(setterAction.GetParameter(2).GetPlainString() == "=");
|
||||
REQUIRE(setterAction.GetParameter(3).GetPlainString() == "Value");
|
||||
REQUIRE(setterAction.GetParameter(3).GetPlainString() ==
|
||||
"GetArgumentAsNumber(\"Value\")");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -341,7 +343,8 @@ TEST_CASE("PropertyFunctionGenerator", "[common]") {
|
||||
auto &getterAction = getterEvent.GetActions().at(0);
|
||||
REQUIRE(getterAction.GetType() == "SetReturnNumber");
|
||||
REQUIRE(getterAction.GetParametersCount() == 1);
|
||||
REQUIRE(getterAction.GetParameter(0).GetPlainString() == "MovementAngle");
|
||||
REQUIRE(getterAction.GetParameter(0).GetPlainString() ==
|
||||
"Object.PropertyMovementAngle()");
|
||||
}
|
||||
{
|
||||
auto &setter =
|
||||
@@ -372,7 +375,8 @@ TEST_CASE("PropertyFunctionGenerator", "[common]") {
|
||||
REQUIRE(setterAction.GetParametersCount() == 3);
|
||||
REQUIRE(setterAction.GetParameter(0).GetPlainString() == "Object");
|
||||
REQUIRE(setterAction.GetParameter(1).GetPlainString() == "=");
|
||||
REQUIRE(setterAction.GetParameter(2).GetPlainString() == "Value");
|
||||
REQUIRE(setterAction.GetParameter(2).GetPlainString() ==
|
||||
"GetArgumentAsNumber(\"Value\")");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -574,7 +578,8 @@ TEST_CASE("PropertyFunctionGenerator", "[common]") {
|
||||
auto &getterAction = getterEvent.GetActions().at(0);
|
||||
REQUIRE(getterAction.GetType() == "SetReturnNumber");
|
||||
REQUIRE(getterAction.GetParametersCount() == 1);
|
||||
REQUIRE(getterAction.GetParameter(0).GetPlainString() == "MovementAngle");
|
||||
REQUIRE(getterAction.GetParameter(0).GetPlainString() ==
|
||||
"Object.Behavior::SharedPropertyMovementAngle()");
|
||||
}
|
||||
{
|
||||
auto &setter =
|
||||
|
@@ -65,11 +65,11 @@ class MockFileSystem : public gd::AbstractFileSystem {
|
||||
|
||||
TEST_CASE("ResourcesMergingHelper", "[common]") {
|
||||
SECTION("Basics") {
|
||||
gd::Project project;
|
||||
MockFileSystem fs;
|
||||
gd::ResourcesMergingHelper resourcesMerger(project.GetResourcesManager(), fs);
|
||||
gd::ResourcesMergingHelper resourcesMerger(fs);
|
||||
resourcesMerger.SetBaseDirectory("/game/base/folder/");
|
||||
|
||||
gd::Project project;
|
||||
project.GetResourcesManager().AddResource("Image1", "/image1.png", "image");
|
||||
project.GetResourcesManager().AddResource("Image2", "image2.png", "image");
|
||||
project.GetResourcesManager().AddResource("Audio1", "audio1.png", "audio");
|
||||
@@ -90,12 +90,12 @@ TEST_CASE("ResourcesMergingHelper", "[common]") {
|
||||
"FileNameFrom(MakeAbsolute(subfolder/image3.png))");
|
||||
}
|
||||
SECTION("Can preserve directories structure") {
|
||||
gd::Project project;
|
||||
MockFileSystem fs;
|
||||
gd::ResourcesMergingHelper resourcesMerger(project.GetResourcesManager(), fs);
|
||||
gd::ResourcesMergingHelper resourcesMerger(fs);
|
||||
resourcesMerger.SetBaseDirectory("/game/base/folder/");
|
||||
resourcesMerger.PreserveDirectoriesStructure(true);
|
||||
|
||||
gd::Project project;
|
||||
project.GetResourcesManager().AddResource("Image1", "/image1.png", "image");
|
||||
project.GetResourcesManager().AddResource("Image2", "image2.png", "image");
|
||||
project.GetResourcesManager().AddResource("Audio1", "audio1.png", "audio");
|
||||
|
@@ -15,10 +15,11 @@
|
||||
|
||||
TEST_CASE("ResourcesRenamer", "[common]") {
|
||||
SECTION("It renames resources that are exposed") {
|
||||
gd::Project project;
|
||||
std::map<gd::String, gd::String> renamings = {
|
||||
{"Resource1", "RenamedResource1"}};
|
||||
gd::ResourcesRenamer resourcesRenamer(project.GetResourcesManager(), renamings);
|
||||
gd::ResourcesRenamer resourcesRenamer(renamings);
|
||||
|
||||
gd::Project project;
|
||||
|
||||
// Add "classic", plain resources.
|
||||
gd::ImageResource resource1;
|
||||
@@ -44,10 +45,11 @@ TEST_CASE("ResourcesRenamer", "[common]") {
|
||||
}
|
||||
|
||||
SECTION("It renames embedded resources") {
|
||||
gd::Project project;
|
||||
std::map<gd::String, gd::String> renamings = {
|
||||
{"Resource1", "RenamedResource1"}};
|
||||
gd::ResourcesRenamer resourcesRenamer(project.GetResourcesManager(), renamings);
|
||||
gd::ResourcesRenamer resourcesRenamer(renamings);
|
||||
|
||||
gd::Project project;
|
||||
|
||||
// Add "classic", plain resources.
|
||||
gd::ImageResource resource1;
|
||||
|
@@ -201,34 +201,39 @@ TEST_CASE("WholeProjectRefactorer::ApplyRefactoringForVariablesContainer",
|
||||
"MyRenamedGlobalStructureVariable");
|
||||
project.GetVariables().Rename("SharedVariableName",
|
||||
"RenamedGlobalVariableFromASharedName");
|
||||
auto changeset =
|
||||
gd::WholeProjectRefactorer::ComputeChangesetForVariablesContainer(
|
||||
project,
|
||||
originalSerializedProjectVariables,
|
||||
project.GetVariables());
|
||||
auto changeset = gd::WholeProjectRefactorer::ComputeChangesetForVariablesContainer(
|
||||
project,
|
||||
originalSerializedProjectVariables,
|
||||
project.GetVariables());
|
||||
gd::WholeProjectRefactorer::ApplyRefactoringForVariablesContainer(
|
||||
project, project.GetVariables(), changeset);
|
||||
project,
|
||||
project.GetVariables(),
|
||||
changeset);
|
||||
|
||||
layout1.GetVariables().Rename("MySceneVariable", "MyRenamedSceneVariable");
|
||||
layout1.GetVariables().Rename("MySceneStructureVariable",
|
||||
"MyRenamedSceneStructureVariable");
|
||||
changeset =
|
||||
gd::WholeProjectRefactorer::ComputeChangesetForVariablesContainer(
|
||||
project, originalSerializedLayoutVariables, layout1.GetVariables());
|
||||
changeset = gd::WholeProjectRefactorer::ComputeChangesetForVariablesContainer(
|
||||
project,
|
||||
originalSerializedLayoutVariables,
|
||||
layout1.GetVariables());
|
||||
gd::WholeProjectRefactorer::ApplyRefactoringForVariablesContainer(
|
||||
project, layout1.GetVariables(), changeset);
|
||||
project,
|
||||
layout1.GetVariables(),
|
||||
changeset);
|
||||
|
||||
object1.GetVariables().Rename("MyObjectVariable",
|
||||
"MyRenamedObjectVariable");
|
||||
object1.GetVariables().Rename("MyObjectStructureVariable",
|
||||
"MyRenamedObjectStructureVariable");
|
||||
changeset =
|
||||
gd::WholeProjectRefactorer::ComputeChangesetForVariablesContainer(
|
||||
project,
|
||||
originalSerializedObject1Variables,
|
||||
object1.GetVariables());
|
||||
changeset = gd::WholeProjectRefactorer::ComputeChangesetForVariablesContainer(
|
||||
project,
|
||||
originalSerializedObject1Variables,
|
||||
object1.GetVariables());
|
||||
gd::WholeProjectRefactorer::ApplyRefactoringForVariablesContainer(
|
||||
project, object1.GetVariables(), changeset);
|
||||
project,
|
||||
object1.GetVariables(),
|
||||
changeset);
|
||||
|
||||
// Check the first layout is updated.
|
||||
// clang-format off
|
||||
@@ -324,182 +329,6 @@ TEST_CASE("WholeProjectRefactorer::ApplyRefactoringForVariablesContainer",
|
||||
gd::Serializer::ToJSON(originalSerializedLayout2));
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("Variable renamed (object group)") {
|
||||
gd::Project project;
|
||||
gd::Platform platform;
|
||||
SetupProjectWithDummyPlatform(project, platform);
|
||||
auto &layout1 = project.InsertNewLayout("Layout1", 0);
|
||||
gd::StandardEvent &event =
|
||||
dynamic_cast<gd::StandardEvent &>(layout1.GetEvents().InsertNewEvent(
|
||||
project, "BuiltinCommonInstructions::Standard"));
|
||||
gd::RepeatEvent &repeatEvent =
|
||||
dynamic_cast<gd::RepeatEvent &>(layout1.GetEvents().InsertNewEvent(
|
||||
project, "BuiltinCommonInstructions::Repeat"));
|
||||
|
||||
// Declare variables in objects.
|
||||
auto &object1 =
|
||||
layout1.InsertNewObject(project, "MyExtension::Sprite", "Object1", 0);
|
||||
object1.GetVariables().InsertNew("MyObjectVariable");
|
||||
object1.GetVariables()
|
||||
.InsertNew("MyObjectStructureVariable")
|
||||
.GetChild("MyChild")
|
||||
.SetValue(123);
|
||||
auto &object2 =
|
||||
layout1.InsertNewObject(project, "MyExtension::Sprite", "Object2", 0);
|
||||
object2.GetVariables().InsertNew("MyObjectVariable");
|
||||
object2.GetVariables()
|
||||
.InsertNew("MyObjectStructureVariable")
|
||||
.GetChild("MyChild")
|
||||
.SetValue(123);
|
||||
|
||||
auto& group = layout1.GetObjectGroups().InsertNew("MyObjectGroup");
|
||||
group.AddObject("Object1");
|
||||
group.AddObject("Object2");
|
||||
|
||||
// Create an event using the variables.
|
||||
// clang-format off
|
||||
{
|
||||
gd::Instruction action;
|
||||
action.SetType("MyExtension::DoSomething");
|
||||
action.SetParametersCount(1);
|
||||
action.SetParameter(
|
||||
0,
|
||||
gd::Expression(
|
||||
"1 + "
|
||||
"Object1.MyObjectVariable + "
|
||||
"Object2.MyObjectVariable + "
|
||||
"MyObjectGroup.MyObjectVariable + "
|
||||
"Object1.MyObjectStructureVariable.MyChild + "
|
||||
"Object2.MyObjectStructureVariable.MyChild + "
|
||||
"MyObjectGroup.MyObjectStructureVariable.MyChild"));
|
||||
event.GetActions().Insert(action);
|
||||
}
|
||||
// Expressions with "old" "scenevar", "globalvar", "objectvar":
|
||||
{
|
||||
gd::Instruction action;
|
||||
action.SetType("MyExtension::DoSomething");
|
||||
action.SetParametersCount(1);
|
||||
action.SetParameter(
|
||||
0,
|
||||
gd::Expression(
|
||||
// "objectvar" (in a free expression):
|
||||
"1 + "
|
||||
"MyExtension::GetStringWith2ObjectParamAnd2ObjectVarParam(Object1, MyObjectVariable, Object2, MyObjectVariable) + "
|
||||
"MyExtension::GetStringWith2ObjectParamAnd2ObjectVarParam(MyObjectGroup, MyObjectVariable, MyObjectGroup, MyObjectVariable) + "
|
||||
"MyExtension::GetStringWith2ObjectParamAnd2ObjectVarParam(Object1, MyObjectStructureVariable.MyChild, Object2, MyObjectStructureVariable.MyChild) + "
|
||||
"MyExtension::GetStringWith2ObjectParamAnd2ObjectVarParam(MyObjectGroup, MyObjectStructureVariable.MyChild, MyObjectGroup, MyObjectStructureVariable.MyChild) + "
|
||||
// "objectvar" (using the name of the object being called):
|
||||
"Object1.GetObjectVariableAsNumber(MyObjectVariable) + "
|
||||
"Object2.GetObjectVariableAsNumber(MyObjectVariable) + "
|
||||
"MyObjectGroup.GetObjectVariableAsNumber(MyObjectVariable) + "
|
||||
"Object1.GetObjectVariableAsNumber(MyObjectStructureVariable.MyChild) + "
|
||||
"Object2.GetObjectVariableAsNumber(MyObjectStructureVariable.MyChild) + "
|
||||
"MyObjectGroup.GetObjectVariableAsNumber(MyObjectStructureVariable.MyChild) + "
|
||||
"Object1.GetObjectVariableAsNumber(MyObjectStructureVariable.MyChild.GrandChild) + "
|
||||
"Object2.GetObjectVariableAsNumber(MyObjectStructureVariable.MyChild.GrandChild) + "
|
||||
"MyObjectGroup.GetObjectVariableAsNumber(MyObjectStructureVariable.MyChild.GrandChild)"));
|
||||
event.GetActions().Insert(action);
|
||||
}
|
||||
{
|
||||
gd::Instruction action;
|
||||
action.SetType("MyExtension::DoSomethingWithLegacyPreScopedVariables");
|
||||
action.SetParametersCount(4);
|
||||
action.SetParameter(0, gd::Expression("MySceneVariable"));
|
||||
action.SetParameter(1, gd::Expression("MyGlobalVariable"));
|
||||
action.SetParameter(2, gd::Expression("MyObjectGroup"));
|
||||
action.SetParameter(3, gd::Expression("MyObjectVariable"));
|
||||
event.GetActions().Insert(action);
|
||||
}
|
||||
|
||||
repeatEvent.SetRepeatExpression("1 + Object1.MyObjectVariable + Object2.MyObjectVariable + MyObjectGroup.MyObjectVariable");
|
||||
// clang-format on
|
||||
|
||||
// Do a copy of layout1 to ensure other scene is unchanged after the
|
||||
// refactoring.
|
||||
gd::Layout layout2 = layout1;
|
||||
layout2.SetName("Layout2");
|
||||
project.InsertLayout(layout2, 1);
|
||||
gd::SerializerElement originalSerializedLayout2;
|
||||
layout2.SerializeTo(originalSerializedLayout2);
|
||||
|
||||
// Do the changes and launch the refactoring.
|
||||
project.GetVariables().ResetPersistentUuid();
|
||||
layout1.GetVariables().ResetPersistentUuid();
|
||||
object1.ResetPersistentUuid();
|
||||
gd::SerializerElement originalSerializedObject1Variables;
|
||||
object1.GetVariables().SerializeTo(originalSerializedObject1Variables);
|
||||
|
||||
object1.GetVariables().Rename("MyObjectVariable",
|
||||
"MyRenamedObjectVariable");
|
||||
object1.GetVariables().Rename("MyObjectStructureVariable",
|
||||
"MyRenamedObjectStructureVariable");
|
||||
auto changeset =
|
||||
gd::WholeProjectRefactorer::ComputeChangesetForVariablesContainer(
|
||||
project,
|
||||
originalSerializedObject1Variables,
|
||||
object1.GetVariables());
|
||||
gd::WholeProjectRefactorer::ApplyRefactoringForVariablesContainer(
|
||||
project, object1.GetVariables(), changeset);
|
||||
|
||||
// Check the first layout is updated.
|
||||
// clang-format off
|
||||
{
|
||||
// Updated direct access to variables:
|
||||
REQUIRE(event.GetActions()[0].GetParameter(0).GetPlainString() ==
|
||||
"1 + "
|
||||
"Object1.MyRenamedObjectVariable + "
|
||||
"Object2.MyObjectVariable + "
|
||||
"MyObjectGroup.MyRenamedObjectVariable + "
|
||||
"Object1.MyRenamedObjectStructureVariable.MyChild + "
|
||||
"Object2.MyObjectStructureVariable.MyChild + "
|
||||
"MyObjectGroup.MyRenamedObjectStructureVariable.MyChild"
|
||||
);
|
||||
|
||||
// Updated access to variables using the legacy "pre-scoped" "scenevar",
|
||||
// "globalvar" and "objectvar" parameters in expressions:
|
||||
REQUIRE(event.GetActions()[1].GetParameter(0).GetPlainString() ==
|
||||
"1 + "
|
||||
// Multiple "objectvar" parameters in a free function:
|
||||
"MyExtension::GetStringWith2ObjectParamAnd2ObjectVarParam(Object1, MyRenamedObjectVariable, Object2, MyObjectVariable) + "
|
||||
"MyExtension::GetStringWith2ObjectParamAnd2ObjectVarParam(MyObjectGroup, MyRenamedObjectVariable, MyObjectGroup, MyRenamedObjectVariable) + "
|
||||
// Multiple "objectvar" parameters in a free function, with child
|
||||
// variable:
|
||||
"MyExtension::GetStringWith2ObjectParamAnd2ObjectVarParam(Object1, MyRenamedObjectStructureVariable.MyChild, Object2, MyObjectStructureVariable.MyChild) + "
|
||||
"MyExtension::GetStringWith2ObjectParamAnd2ObjectVarParam(MyObjectGroup, MyRenamedObjectStructureVariable.MyChild, MyObjectGroup, MyRenamedObjectStructureVariable.MyChild) + "
|
||||
// Single "objectvar" from the object being accessed:
|
||||
"Object1.GetObjectVariableAsNumber(MyRenamedObjectVariable) + "
|
||||
"Object2.GetObjectVariableAsNumber(MyObjectVariable) + "
|
||||
"MyObjectGroup.GetObjectVariableAsNumber(MyRenamedObjectVariable) + "
|
||||
// Single "objectvar" from the object being accessed, with child
|
||||
// variales:
|
||||
"Object1.GetObjectVariableAsNumber(MyRenamedObjectStructureVariable.MyChild) + "
|
||||
"Object2.GetObjectVariableAsNumber(MyObjectStructureVariable.MyChild) + "
|
||||
"MyObjectGroup.GetObjectVariableAsNumber(MyRenamedObjectStructureVariable.MyChild) + "
|
||||
"Object1.GetObjectVariableAsNumber(MyRenamedObjectStructureVariable.MyChild.GrandChild) + "
|
||||
"Object2.GetObjectVariableAsNumber(MyObjectStructureVariable.MyChild.GrandChild) + "
|
||||
"MyObjectGroup.GetObjectVariableAsNumber(MyRenamedObjectStructureVariable.MyChild.GrandChild)");
|
||||
|
||||
// Updated "objectvar" parameters of an
|
||||
// instruction:
|
||||
REQUIRE(event.GetActions()[2].GetParameter(2).GetPlainString() ==
|
||||
"MyObjectGroup");
|
||||
REQUIRE(event.GetActions()[2].GetParameter(3).GetPlainString() ==
|
||||
"MyRenamedObjectVariable");
|
||||
}
|
||||
|
||||
REQUIRE(repeatEvent.GetRepeatExpression() == "1 + Object1.MyRenamedObjectVariable + Object2.MyObjectVariable + MyObjectGroup.MyRenamedObjectVariable");
|
||||
// clang-format on
|
||||
|
||||
// Check the other layout is untouched.
|
||||
{
|
||||
gd::SerializerElement serializedLayout2;
|
||||
layout2.SerializeTo(serializedLayout2);
|
||||
REQUIRE(gd::Serializer::ToJSON(serializedLayout2) ==
|
||||
gd::Serializer::ToJSON(originalSerializedLayout2));
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("Variable removed (project, layout, object)") {
|
||||
gd::Project project;
|
||||
gd::Platform platform;
|
||||
@@ -666,31 +495,36 @@ TEST_CASE("WholeProjectRefactorer::ApplyRefactoringForVariablesContainer",
|
||||
project.GetVariables().Remove("MyGlobalVariable");
|
||||
project.GetVariables().Remove("MyGlobalStructureVariable");
|
||||
project.GetVariables().Remove("SharedVariableName");
|
||||
auto changeset =
|
||||
gd::WholeProjectRefactorer::ComputeChangesetForVariablesContainer(
|
||||
project,
|
||||
originalSerializedProjectVariables,
|
||||
project.GetVariables());
|
||||
auto changeset = gd::WholeProjectRefactorer::ComputeChangesetForVariablesContainer(
|
||||
project,
|
||||
originalSerializedProjectVariables,
|
||||
project.GetVariables());
|
||||
gd::WholeProjectRefactorer::ApplyRefactoringForVariablesContainer(
|
||||
project, project.GetVariables(), changeset);
|
||||
project,
|
||||
project.GetVariables(),
|
||||
changeset);
|
||||
|
||||
layout1.GetVariables().Remove("MySceneVariable");
|
||||
layout1.GetVariables().Remove("MySceneStructureVariable");
|
||||
changeset =
|
||||
gd::WholeProjectRefactorer::ComputeChangesetForVariablesContainer(
|
||||
project, originalSerializedLayoutVariables, layout1.GetVariables());
|
||||
changeset = gd::WholeProjectRefactorer::ComputeChangesetForVariablesContainer(
|
||||
project,
|
||||
originalSerializedLayoutVariables,
|
||||
layout1.GetVariables());
|
||||
gd::WholeProjectRefactorer::ApplyRefactoringForVariablesContainer(
|
||||
project, layout1.GetVariables(), changeset);
|
||||
project,
|
||||
layout1.GetVariables(),
|
||||
changeset);
|
||||
|
||||
object1.GetVariables().Remove("MyObjectVariable");
|
||||
object1.GetVariables().Remove("MyObjectStructureVariable");
|
||||
changeset =
|
||||
gd::WholeProjectRefactorer::ComputeChangesetForVariablesContainer(
|
||||
project,
|
||||
originalSerializedObject1Variables,
|
||||
object1.GetVariables());
|
||||
changeset = gd::WholeProjectRefactorer::ComputeChangesetForVariablesContainer(
|
||||
project,
|
||||
originalSerializedObject1Variables,
|
||||
object1.GetVariables());
|
||||
gd::WholeProjectRefactorer::ApplyRefactoringForVariablesContainer(
|
||||
project, object1.GetVariables(), changeset);
|
||||
project,
|
||||
object1.GetVariables(),
|
||||
changeset);
|
||||
|
||||
// Check the first layout is updated.
|
||||
{
|
||||
|
@@ -3474,72 +3474,6 @@ TEST_CASE("RenameLayer", "[common]") {
|
||||
"MyExtension::CameraCenterX(\"layerA\")");
|
||||
}
|
||||
|
||||
SECTION("Renaming a layer also moves the instances on this layer and of the associated external layouts") {
|
||||
gd::Project project;
|
||||
gd::Platform platform;
|
||||
SetupProjectWithDummyPlatform(project, platform);
|
||||
|
||||
auto &layout = project.InsertNewLayout("My layout", 0);
|
||||
auto &otherLayout = project.InsertNewLayout("My other layout", 1);
|
||||
|
||||
layout.InsertNewLayer("My layer", 0);
|
||||
otherLayout.InsertNewLayer("My layer", 0);
|
||||
|
||||
auto &externalLayout =
|
||||
project.InsertNewExternalLayout("My external layout", 0);
|
||||
auto &otherExternalLayout =
|
||||
project.InsertNewExternalLayout("My other external layout", 0);
|
||||
externalLayout.SetAssociatedLayout("My layout");
|
||||
otherExternalLayout.SetAssociatedLayout("My other layout");
|
||||
|
||||
auto &initialInstances = layout.GetInitialInstances();
|
||||
auto &initialInstance1 = initialInstances.InsertNewInitialInstance();
|
||||
initialInstance1.SetLayer("My layer");
|
||||
auto &initialInstance2 = initialInstances.InsertNewInitialInstance();
|
||||
initialInstance2.SetLayer("My layer");
|
||||
auto &initialInstance3 = initialInstances.InsertNewInitialInstance();
|
||||
initialInstance3.SetLayer("");
|
||||
|
||||
auto &externalInitialInstances = externalLayout.GetInitialInstances();
|
||||
auto &externalInitialInstance1 = externalInitialInstances.InsertNewInitialInstance();
|
||||
externalInitialInstance1.SetLayer("My layer");
|
||||
auto &externalInitialInstance2 = externalInitialInstances.InsertNewInitialInstance();
|
||||
externalInitialInstance2.SetLayer("My layer");
|
||||
auto &externalInitialInstance3 = externalInitialInstances.InsertNewInitialInstance();
|
||||
externalInitialInstance3.SetLayer("");
|
||||
|
||||
auto &otherInitialInstances = otherLayout.GetInitialInstances();
|
||||
auto &otherInitialInstance1 = otherInitialInstances.InsertNewInitialInstance();
|
||||
otherInitialInstance1.SetLayer("My layer");
|
||||
|
||||
auto &otherExternalInitialInstances = otherExternalLayout.GetInitialInstances();
|
||||
auto &otherExternalInitialInstance1 = otherExternalInitialInstances.InsertNewInitialInstance();
|
||||
otherExternalInitialInstance1.SetLayer("My layer");
|
||||
|
||||
REQUIRE(initialInstance1.GetLayer() == "My layer");
|
||||
REQUIRE(initialInstance2.GetLayer() == "My layer");
|
||||
REQUIRE(initialInstance3.GetLayer() == "");
|
||||
REQUIRE(externalInitialInstance1.GetLayer() == "My layer");
|
||||
REQUIRE(externalInitialInstance2.GetLayer() == "My layer");
|
||||
REQUIRE(externalInitialInstance3.GetLayer() == "");
|
||||
REQUIRE(otherInitialInstance1.GetLayer() == "My layer");
|
||||
REQUIRE(otherExternalInitialInstance1.GetLayer() == "My layer");
|
||||
|
||||
gd::WholeProjectRefactorer::RenameLayer(project, layout, "My layer", "My new layer");
|
||||
|
||||
// Instances on the renamed layer are moved to the new layer.
|
||||
REQUIRE(initialInstance1.GetLayer() == "My new layer");
|
||||
REQUIRE(initialInstance2.GetLayer() == "My new layer");
|
||||
REQUIRE(initialInstance3.GetLayer() == "");
|
||||
// Instances on the renamed layer of external layouts are moved to the new layer.
|
||||
REQUIRE(externalInitialInstance1.GetLayer() == "My new layer");
|
||||
REQUIRE(externalInitialInstance2.GetLayer() == "My new layer");
|
||||
REQUIRE(externalInitialInstance3.GetLayer() == "");
|
||||
// Instances on the renamed layer of other layouts & external layouts are not moved.
|
||||
REQUIRE(otherInitialInstance1.GetLayer() == "My layer");
|
||||
REQUIRE(otherExternalInitialInstance1.GetLayer() == "My layer");
|
||||
}
|
||||
|
||||
SECTION("Can rename a layer when a layer parameter is empty") {
|
||||
gd::Project project;
|
||||
gd::Platform platform;
|
||||
|
@@ -154,23 +154,7 @@ namespace gdjs {
|
||||
* @return The Z position of the rendered object.
|
||||
*/
|
||||
getDrawableZ(): float {
|
||||
return this._z;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the bottom Z of the object.
|
||||
* Rotations around X and Y are not taken into account.
|
||||
*/
|
||||
getUnrotatedAABBMinZ(): number {
|
||||
return this.getDrawableZ();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the top Z of the object.
|
||||
* Rotations around X and Y are not taken into account.
|
||||
*/
|
||||
getUnrotatedAABBMaxZ(): number {
|
||||
return this.getDrawableZ() + this.getDepth();
|
||||
return this.getZ();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -24,8 +24,8 @@ namespace gdjs {
|
||||
|
||||
updatePosition() {
|
||||
this._threeObject3D.position.set(
|
||||
this._object.getX() + this._object.getWidth() / 2,
|
||||
this._object.getY() + this._object.getHeight() / 2,
|
||||
this._object.x + this._object.getWidth() / 2,
|
||||
this._object.y + this._object.getHeight() / 2,
|
||||
this._object.getZ() + this._object.getDepth() / 2
|
||||
);
|
||||
}
|
||||
|
@@ -61,30 +61,13 @@ namespace gdjs {
|
||||
this.light.intensity = value;
|
||||
}
|
||||
}
|
||||
getDoubleParameter(parameterName: string): number {
|
||||
if (parameterName === 'intensity') {
|
||||
return this.light.intensity;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
updateStringParameter(parameterName: string, value: string): void {
|
||||
if (parameterName === 'color') {
|
||||
this.light.color.setHex(
|
||||
this.light.color = new THREE.Color(
|
||||
gdjs.PixiFiltersTools.rgbOrHexToHexNumber(value)
|
||||
);
|
||||
}
|
||||
}
|
||||
updateColorParameter(parameterName: string, value: number): void {
|
||||
if (parameterName === 'color') {
|
||||
this.light.color.setHex(value);
|
||||
}
|
||||
}
|
||||
getColorParameter(parameterName: string): number {
|
||||
if (parameterName === 'color') {
|
||||
return this.light.color.getHex();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
updateBooleanParameter(parameterName: string, value: boolean): void {}
|
||||
})();
|
||||
}
|
||||
|
@@ -103,27 +103,6 @@ namespace gdjs {
|
||||
flipZ(enable: boolean): void;
|
||||
|
||||
isFlippedZ(): boolean;
|
||||
|
||||
/**
|
||||
* Return the bottom Z of the object.
|
||||
* Rotations around X and Y are not taken into account.
|
||||
*/
|
||||
getUnrotatedAABBMinZ(): number;
|
||||
|
||||
/**
|
||||
* Return the top Z of the object.
|
||||
* Rotations around X and Y are not taken into account.
|
||||
*/
|
||||
getUnrotatedAABBMaxZ(): number;
|
||||
}
|
||||
|
||||
export namespace Base3DHandler {
|
||||
export const is3D = (
|
||||
object: gdjs.RuntimeObject
|
||||
): object is gdjs.RuntimeObject & gdjs.Base3DHandler => {
|
||||
//@ts-ignore We are checking if the methods are present.
|
||||
return object.getZ && object.setZ;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -223,14 +202,6 @@ namespace gdjs {
|
||||
isFlippedZ(): boolean {
|
||||
return this.object.isFlippedZ();
|
||||
}
|
||||
|
||||
getUnrotatedAABBMinZ(): number {
|
||||
return this.object.getUnrotatedAABBMinZ();
|
||||
}
|
||||
|
||||
getUnrotatedAABBMaxZ(): number {
|
||||
return this.object.getUnrotatedAABBMaxZ();
|
||||
}
|
||||
}
|
||||
|
||||
gdjs.registerBehavior('Scene3D::Base3DBehavior', gdjs.Base3DBehavior);
|
||||
|
@@ -1,89 +0,0 @@
|
||||
namespace gdjs {
|
||||
gdjs.PixiFiltersTools.registerFilterCreator(
|
||||
'Scene3D::Bloom',
|
||||
new (class implements gdjs.PixiFiltersTools.FilterCreator {
|
||||
makeFilter(
|
||||
target: EffectsTarget,
|
||||
effectData: EffectData
|
||||
): gdjs.PixiFiltersTools.Filter {
|
||||
if (typeof THREE === 'undefined') {
|
||||
return new gdjs.PixiFiltersTools.EmptyFilter();
|
||||
}
|
||||
return new (class implements gdjs.PixiFiltersTools.Filter {
|
||||
shaderPass: THREE_ADDONS.UnrealBloomPass;
|
||||
_isEnabled: boolean;
|
||||
|
||||
constructor() {
|
||||
this.shaderPass = new THREE_ADDONS.UnrealBloomPass(
|
||||
new THREE.Vector2(256, 256),
|
||||
1,
|
||||
0,
|
||||
0
|
||||
);
|
||||
this._isEnabled = false;
|
||||
}
|
||||
|
||||
isEnabled(target: EffectsTarget): boolean {
|
||||
return this._isEnabled;
|
||||
}
|
||||
setEnabled(target: EffectsTarget, enabled: boolean): boolean {
|
||||
if (this._isEnabled === enabled) {
|
||||
return true;
|
||||
}
|
||||
if (enabled) {
|
||||
return this.applyEffect(target);
|
||||
} else {
|
||||
return this.removeEffect(target);
|
||||
}
|
||||
}
|
||||
applyEffect(target: EffectsTarget): boolean {
|
||||
if (!(target instanceof gdjs.Layer)) {
|
||||
return false;
|
||||
}
|
||||
target.getRenderer().addPostProcessingPass(this.shaderPass);
|
||||
this._isEnabled = true;
|
||||
return true;
|
||||
}
|
||||
removeEffect(target: EffectsTarget): boolean {
|
||||
if (!(target instanceof gdjs.Layer)) {
|
||||
return false;
|
||||
}
|
||||
target.getRenderer().removePostProcessingPass(this.shaderPass);
|
||||
this._isEnabled = false;
|
||||
return true;
|
||||
}
|
||||
updatePreRender(target: gdjs.EffectsTarget): any {}
|
||||
updateDoubleParameter(parameterName: string, value: number): void {
|
||||
if (parameterName === 'strength') {
|
||||
this.shaderPass.strength = value;
|
||||
}
|
||||
if (parameterName === 'radius') {
|
||||
this.shaderPass.radius = value;
|
||||
}
|
||||
if (parameterName === 'threshold') {
|
||||
this.shaderPass.threshold = value;
|
||||
}
|
||||
}
|
||||
getDoubleParameter(parameterName: string): number {
|
||||
if (parameterName === 'strength') {
|
||||
return this.shaderPass.strength;
|
||||
}
|
||||
if (parameterName === 'radius') {
|
||||
return this.shaderPass.radius;
|
||||
}
|
||||
if (parameterName === 'threshold') {
|
||||
return this.shaderPass.threshold;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
updateStringParameter(parameterName: string, value: string): void {}
|
||||
updateColorParameter(parameterName: string, value: number): void {}
|
||||
getColorParameter(parameterName: string): number {
|
||||
return 0;
|
||||
}
|
||||
updateBooleanParameter(parameterName: string, value: boolean): void {}
|
||||
})();
|
||||
}
|
||||
})()
|
||||
);
|
||||
}
|
@@ -1,80 +0,0 @@
|
||||
namespace gdjs {
|
||||
gdjs.PixiFiltersTools.registerFilterCreator(
|
||||
'Scene3D::BrightnessAndContrast',
|
||||
new (class implements gdjs.PixiFiltersTools.FilterCreator {
|
||||
makeFilter(
|
||||
target: EffectsTarget,
|
||||
effectData: EffectData
|
||||
): gdjs.PixiFiltersTools.Filter {
|
||||
if (typeof THREE === 'undefined') {
|
||||
return new gdjs.PixiFiltersTools.EmptyFilter();
|
||||
}
|
||||
return new (class implements gdjs.PixiFiltersTools.Filter {
|
||||
shaderPass: THREE_ADDONS.ShaderPass;
|
||||
_isEnabled: boolean;
|
||||
|
||||
constructor() {
|
||||
this.shaderPass = new THREE_ADDONS.ShaderPass(
|
||||
THREE_ADDONS.BrightnessContrastShader
|
||||
);
|
||||
this._isEnabled = false;
|
||||
}
|
||||
|
||||
isEnabled(target: EffectsTarget): boolean {
|
||||
return this._isEnabled;
|
||||
}
|
||||
setEnabled(target: EffectsTarget, enabled: boolean): boolean {
|
||||
if (this._isEnabled === enabled) {
|
||||
return true;
|
||||
}
|
||||
if (enabled) {
|
||||
return this.applyEffect(target);
|
||||
} else {
|
||||
return this.removeEffect(target);
|
||||
}
|
||||
}
|
||||
applyEffect(target: EffectsTarget): boolean {
|
||||
if (!(target instanceof gdjs.Layer)) {
|
||||
return false;
|
||||
}
|
||||
target.getRenderer().addPostProcessingPass(this.shaderPass);
|
||||
this._isEnabled = true;
|
||||
return true;
|
||||
}
|
||||
removeEffect(target: EffectsTarget): boolean {
|
||||
if (!(target instanceof gdjs.Layer)) {
|
||||
return false;
|
||||
}
|
||||
target.getRenderer().removePostProcessingPass(this.shaderPass);
|
||||
this._isEnabled = false;
|
||||
return true;
|
||||
}
|
||||
updatePreRender(target: gdjs.EffectsTarget): any {}
|
||||
updateDoubleParameter(parameterName: string, value: number): void {
|
||||
if (parameterName === 'brightness') {
|
||||
this.shaderPass.uniforms[parameterName].value = value;
|
||||
}
|
||||
if (parameterName === 'contrast') {
|
||||
this.shaderPass.uniforms[parameterName].value = value;
|
||||
}
|
||||
}
|
||||
getDoubleParameter(parameterName: string): number {
|
||||
if (parameterName === 'brightness') {
|
||||
return this.shaderPass.uniforms[parameterName].value;
|
||||
}
|
||||
if (parameterName === 'contrast') {
|
||||
return this.shaderPass.uniforms[parameterName].value;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
updateStringParameter(parameterName: string, value: string): void {}
|
||||
updateColorParameter(parameterName: string, value: number): void {}
|
||||
getColorParameter(parameterName: string): number {
|
||||
return 0;
|
||||
}
|
||||
updateBooleanParameter(parameterName: string, value: boolean): void {}
|
||||
})();
|
||||
}
|
||||
})()
|
||||
);
|
||||
}
|
@@ -1,373 +0,0 @@
|
||||
namespace gdjs {
|
||||
export interface Object3DDataContent {
|
||||
width: float;
|
||||
height: float;
|
||||
depth: float;
|
||||
}
|
||||
/** Base parameters for {@link gdjs.RuntimeObject3D} */
|
||||
export interface Object3DData extends ObjectData {
|
||||
/** The base parameters of the RuntimeObject3D */
|
||||
content: Object3DDataContent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Base class for 3D custom objects.
|
||||
*/
|
||||
export class CustomRuntimeObject3D
|
||||
extends gdjs.CustomRuntimeObject
|
||||
implements gdjs.Base3DHandler {
|
||||
/**
|
||||
* Position on the Z axis.
|
||||
*/
|
||||
private _z: float = 0;
|
||||
private _minZ: float = 0;
|
||||
private _maxZ: float = 0;
|
||||
private _scaleZ: float = 1;
|
||||
private _flippedZ: boolean = false;
|
||||
/**
|
||||
* Euler angle with the `ZYX` order.
|
||||
*
|
||||
* Note that `_rotationZ` is `angle` from `gdjs.RuntimeObject`.
|
||||
*/
|
||||
private _rotationX: float = 0;
|
||||
/**
|
||||
* Euler angle with the `ZYX` order.
|
||||
*
|
||||
* Note that `_rotationZ` is `angle` from `gdjs.RuntimeObject`.
|
||||
*/
|
||||
private _rotationY: float = 0;
|
||||
private _customCenterZ: float = 0;
|
||||
private static _temporaryVector = new THREE.Vector3();
|
||||
|
||||
constructor(
|
||||
parent: gdjs.RuntimeInstanceContainer,
|
||||
objectData: Object3DData & CustomObjectConfiguration
|
||||
) {
|
||||
super(parent, objectData);
|
||||
this._renderer.reinitialize(this, parent);
|
||||
}
|
||||
|
||||
protected _createRender() {
|
||||
const parent = this._runtimeScene;
|
||||
return new gdjs.CustomRuntimeObject3DRenderer(
|
||||
this,
|
||||
this._instanceContainer,
|
||||
parent
|
||||
);
|
||||
}
|
||||
|
||||
protected _reinitializeRenderer(): void {
|
||||
this.getRenderer().reinitialize(this, this.getParent());
|
||||
}
|
||||
|
||||
getRenderer(): gdjs.CustomRuntimeObject3DRenderer {
|
||||
return super.getRenderer() as gdjs.CustomRuntimeObject3DRenderer;
|
||||
}
|
||||
|
||||
get3DRendererObject() {
|
||||
// It can't be null because Three.js is always loaded
|
||||
// when a custom 3D object is used.
|
||||
return this.getRenderer().get3DRendererObject()!;
|
||||
}
|
||||
|
||||
extraInitializationFromInitialInstance(initialInstanceData: InstanceData) {
|
||||
super.extraInitializationFromInitialInstance(initialInstanceData);
|
||||
if (initialInstanceData.depth !== undefined)
|
||||
this.setDepth(initialInstanceData.depth);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the object position on the Z axis.
|
||||
*/
|
||||
setZ(z: float): void {
|
||||
if (z === this._z) return;
|
||||
this._z = z;
|
||||
this.getRenderer().updatePosition();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the object position on the Z axis.
|
||||
*/
|
||||
getZ(): float {
|
||||
return this._z;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Z position of the rendered object.
|
||||
*
|
||||
* For most objects, this will returns the same value as getZ(). But if the
|
||||
* object has an origin that is not the same as the point (0,0,0) of the
|
||||
* object displayed, getDrawableZ will differ.
|
||||
*
|
||||
* @return The Z position of the rendered object.
|
||||
*/
|
||||
getDrawableZ(): float {
|
||||
if (this._isUntransformedHitBoxesDirty) {
|
||||
this._updateUntransformedHitBoxes();
|
||||
}
|
||||
return this._z + this._minZ;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the Z position of the object center, **relative to the object Z
|
||||
* position** (`getDrawableX`).
|
||||
*
|
||||
* Use `getCenterZInScene` to get the position of the center in the scene.
|
||||
*
|
||||
* @return the Z position of the object center, relative to
|
||||
* `getDrawableZ()`.
|
||||
*/
|
||||
getCenterZ(): float {
|
||||
return this.getDepth() / 2;
|
||||
}
|
||||
|
||||
getCenterZInScene(): float {
|
||||
return this.getDrawableZ() + this.getCenterZ();
|
||||
}
|
||||
|
||||
setCenterZInScene(z: float): void {
|
||||
this.setZ(z + this._z - (this.getDrawableZ() + this.getCenterZ()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the bottom Z of the object.
|
||||
* Rotations around X and Y are not taken into account.
|
||||
*/
|
||||
getUnrotatedAABBMinZ(): number {
|
||||
return this.getDrawableZ();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the top Z of the object.
|
||||
* Rotations around X and Y are not taken into account.
|
||||
*/
|
||||
getUnrotatedAABBMaxZ(): number {
|
||||
return this.getDrawableZ() + this.getDepth();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the object rotation on the X axis.
|
||||
*
|
||||
* This is an Euler angle. Objects use the `ZYX` order.
|
||||
*/
|
||||
setRotationX(angle: float): void {
|
||||
this._rotationX = angle;
|
||||
this.getRenderer().updateRotation();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the object rotation on the Y axis.
|
||||
*
|
||||
* This is an Euler angle. Objects use the `ZYX` order.
|
||||
*/
|
||||
setRotationY(angle: float): void {
|
||||
this._rotationY = angle;
|
||||
this.getRenderer().updateRotation();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the object rotation on the X axis.
|
||||
*
|
||||
* This is an Euler angle. Objects use the `ZYX` order.
|
||||
*/
|
||||
getRotationX(): float {
|
||||
return this._rotationX;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the object rotation on the Y axis.
|
||||
*
|
||||
* This is an Euler angle. Objects use the `ZYX` order.
|
||||
*/
|
||||
getRotationY(): float {
|
||||
return this._rotationY;
|
||||
}
|
||||
|
||||
/**
|
||||
* Turn the object around the scene x axis at its center.
|
||||
* @param deltaAngle the rotation angle
|
||||
*/
|
||||
turnAroundX(deltaAngle: float): void {
|
||||
const axisX = gdjs.CustomRuntimeObject3D._temporaryVector;
|
||||
axisX.set(1, 0, 0);
|
||||
|
||||
const mesh = this.get3DRendererObject();
|
||||
mesh.rotateOnWorldAxis(axisX, gdjs.toRad(deltaAngle));
|
||||
this._rotationX = gdjs.toDegrees(mesh.rotation.x);
|
||||
this._rotationY = gdjs.toDegrees(mesh.rotation.y);
|
||||
this.setAngle(gdjs.toDegrees(mesh.rotation.z));
|
||||
}
|
||||
|
||||
/**
|
||||
* Turn the object around the scene y axis at its center.
|
||||
* @param deltaAngle the rotation angle
|
||||
*/
|
||||
turnAroundY(deltaAngle: float): void {
|
||||
const axisY = gdjs.CustomRuntimeObject3D._temporaryVector;
|
||||
axisY.set(0, 1, 0);
|
||||
|
||||
const mesh = this.get3DRendererObject();
|
||||
mesh.rotateOnWorldAxis(axisY, gdjs.toRad(deltaAngle));
|
||||
this._rotationX = gdjs.toDegrees(mesh.rotation.x);
|
||||
this._rotationY = gdjs.toDegrees(mesh.rotation.y);
|
||||
this.setAngle(gdjs.toDegrees(mesh.rotation.z));
|
||||
}
|
||||
|
||||
/**
|
||||
* Turn the object around the scene z axis at its center.
|
||||
* @param deltaAngle the rotation angle
|
||||
*/
|
||||
turnAroundZ(deltaAngle: float): void {
|
||||
const axisZ = gdjs.CustomRuntimeObject3D._temporaryVector;
|
||||
axisZ.set(0, 0, 1);
|
||||
|
||||
const mesh = this.get3DRendererObject();
|
||||
mesh.rotateOnWorldAxis(axisZ, gdjs.toRad(deltaAngle));
|
||||
this._rotationX = gdjs.toDegrees(mesh.rotation.x);
|
||||
this._rotationY = gdjs.toDegrees(mesh.rotation.y);
|
||||
this.setAngle(gdjs.toDegrees(mesh.rotation.z));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the internal width of the object according to its children.
|
||||
*/
|
||||
getUnscaledDepth(): float {
|
||||
if (this._isUntransformedHitBoxesDirty) {
|
||||
this._updateUntransformedHitBoxes();
|
||||
}
|
||||
return this._maxZ - this._minZ;
|
||||
}
|
||||
|
||||
_updateUntransformedHitBoxes(): void {
|
||||
super._updateUntransformedHitBoxes();
|
||||
|
||||
let minZ = Number.MAX_VALUE;
|
||||
let maxZ = -Number.MAX_VALUE;
|
||||
for (const childInstance of this._instanceContainer.getAdhocListOfAllInstances()) {
|
||||
if (!childInstance.isIncludedInParentCollisionMask()) {
|
||||
continue;
|
||||
}
|
||||
if (!gdjs.Base3DHandler.is3D(childInstance)) {
|
||||
continue;
|
||||
}
|
||||
minZ = Math.min(minZ, childInstance.getUnrotatedAABBMinZ());
|
||||
maxZ = Math.max(maxZ, childInstance.getUnrotatedAABBMaxZ());
|
||||
}
|
||||
if (minZ === Number.MAX_VALUE) {
|
||||
// The unscaled size can't be 0 because setWidth and setHeight wouldn't
|
||||
// have any effect.
|
||||
minZ = 0;
|
||||
maxZ = 1;
|
||||
}
|
||||
this._minZ = minZ;
|
||||
this._maxZ = maxZ;
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns the center Z from the local origin (0;0).
|
||||
*/
|
||||
getUnscaledCenterZ(): float {
|
||||
if (this.hasCustomRotationCenter()) {
|
||||
return this._customCenterZ;
|
||||
}
|
||||
if (this._isUntransformedHitBoxesDirty) {
|
||||
this._updateUntransformedHitBoxes();
|
||||
}
|
||||
return (this._minZ + this._maxZ) / 2;
|
||||
}
|
||||
|
||||
/**
|
||||
* The center of rotation is defined relatively to the origin (the object
|
||||
* position).
|
||||
* This avoids the center to move when children push the bounds.
|
||||
*
|
||||
* When no custom center is defined, it will move
|
||||
* to stay at the center of the children bounds.
|
||||
*
|
||||
* @param x coordinate of the custom center
|
||||
* @param y coordinate of the custom center
|
||||
*/
|
||||
setRotationCenter3D(x: float, y: float, z: float) {
|
||||
this._customCenterZ = z;
|
||||
this.setRotationCenter(x, y);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the object size on the Z axis (called "depth").
|
||||
*/
|
||||
getDepth(): float {
|
||||
return this.getUnscaledDepth() * this.getScaleZ();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the object size on the Z axis (called "depth").
|
||||
*/
|
||||
setDepth(depth: float): void {
|
||||
const unscaledDepth = this.getUnscaledDepth();
|
||||
if (unscaledDepth !== 0) {
|
||||
this.setScaleZ(depth / unscaledDepth);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Change the scale on X, Y and Z axis of the object.
|
||||
*
|
||||
* @param newScale The new scale (must be greater than 0).
|
||||
*/
|
||||
setScale(newScale: number): void {
|
||||
super.setScale(newScale);
|
||||
this.setScaleZ(newScale);
|
||||
}
|
||||
|
||||
/**
|
||||
* Change the scale on Z axis of the object (changing its height).
|
||||
*
|
||||
* @param newScale The new scale (must be greater than 0).
|
||||
*/
|
||||
setScaleZ(newScale: number): void {
|
||||
if (newScale < 0) {
|
||||
newScale = 0;
|
||||
}
|
||||
if (newScale === Math.abs(this._scaleZ)) {
|
||||
return;
|
||||
}
|
||||
this._scaleZ = newScale * (this._flippedZ ? -1 : 1);
|
||||
this.getRenderer().updateSize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the scale of the object (or the geometric average of X, Y and Z scale in case they are different).
|
||||
*
|
||||
* @return the scale of the object (or the geometric average of X, Y and Z scale in case they are different).
|
||||
*/
|
||||
getScale(): number {
|
||||
const scaleX = this.getScaleX();
|
||||
const scaleY = this.getScaleY();
|
||||
const scaleZ = this.getScaleZ();
|
||||
return scaleX === scaleY && scaleX === scaleZ
|
||||
? scaleX
|
||||
: Math.pow(scaleX * scaleY * scaleZ, 1 / 3);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the scale of the object on Z axis.
|
||||
*
|
||||
* @return the scale of the object on Z axis
|
||||
*/
|
||||
getScaleZ(): float {
|
||||
return Math.abs(this._scaleZ);
|
||||
}
|
||||
|
||||
flipZ(enable: boolean) {
|
||||
if (enable === this._flippedZ) {
|
||||
return;
|
||||
}
|
||||
this._flippedZ = enable;
|
||||
this.getRenderer().updateSize();
|
||||
}
|
||||
|
||||
isFlippedZ(): boolean {
|
||||
return this._flippedZ;
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,135 +0,0 @@
|
||||
namespace gdjs {
|
||||
/**
|
||||
* The renderer for a {@link gdjs.CustomRuntimeObject3D} using Three.js.
|
||||
*/
|
||||
export class CustomRuntimeObject3DRenderer
|
||||
implements gdjs.RuntimeInstanceContainerRenderer {
|
||||
_object: gdjs.CustomRuntimeObject3D;
|
||||
_instanceContainer: gdjs.CustomRuntimeObjectInstanceContainer;
|
||||
_isContainerDirty: boolean = true;
|
||||
_threeGroup: THREE.Group;
|
||||
|
||||
constructor(
|
||||
object: gdjs.CustomRuntimeObject3D,
|
||||
instanceContainer: gdjs.CustomRuntimeObjectInstanceContainer,
|
||||
parent: gdjs.RuntimeInstanceContainer
|
||||
) {
|
||||
this._object = object;
|
||||
this._instanceContainer = instanceContainer;
|
||||
|
||||
this._threeGroup = new THREE.Group();
|
||||
this._threeGroup.rotation.order = 'ZYX';
|
||||
|
||||
const layer = parent.getLayer('');
|
||||
if (layer) {
|
||||
layer.getRenderer().add3DRendererObject(this._threeGroup);
|
||||
}
|
||||
}
|
||||
|
||||
get3DRendererObject(): THREE.Object3D {
|
||||
return this._threeGroup;
|
||||
}
|
||||
|
||||
getRendererObject() {
|
||||
return null;
|
||||
}
|
||||
|
||||
reinitialize(
|
||||
object: gdjs.CustomRuntimeObject3D,
|
||||
parent: gdjs.RuntimeInstanceContainer
|
||||
) {
|
||||
this._object = object;
|
||||
this._isContainerDirty = true;
|
||||
const layer = parent.getLayer('');
|
||||
if (layer) {
|
||||
layer.getRenderer().add3DRendererObject(this._threeGroup);
|
||||
}
|
||||
}
|
||||
|
||||
_updateThreeGroup() {
|
||||
const threeObject3D = this.get3DRendererObject();
|
||||
|
||||
const scaleX = this._object.getScaleX();
|
||||
const scaleY = this._object.getScaleY();
|
||||
const scaleZ = this._object.getScaleZ();
|
||||
const pivotX = this._object.getUnscaledCenterX() * scaleX;
|
||||
const pivotY = this._object.getUnscaledCenterY() * scaleY;
|
||||
const pivotZ = this._object.getUnscaledCenterZ() * scaleZ;
|
||||
|
||||
threeObject3D.rotation.set(
|
||||
gdjs.toRad(this._object.getRotationX()),
|
||||
gdjs.toRad(this._object.getRotationY()),
|
||||
gdjs.toRad(this._object.angle)
|
||||
);
|
||||
|
||||
threeObject3D.position.set(
|
||||
this._object.isFlippedX() ? pivotX : -pivotX,
|
||||
this._object.isFlippedY() ? pivotY : -pivotY,
|
||||
this._object.isFlippedZ() ? pivotZ : -pivotZ
|
||||
);
|
||||
threeObject3D.position.applyEuler(threeObject3D.rotation);
|
||||
threeObject3D.position.x += this._object.getX() + pivotX;
|
||||
threeObject3D.position.y += this._object.getY() + pivotY;
|
||||
threeObject3D.position.z += this._object.getZ() + pivotZ;
|
||||
|
||||
threeObject3D.scale.set(
|
||||
this._object.isFlippedX() ? -scaleX : scaleX,
|
||||
this._object.isFlippedY() ? -scaleY : scaleY,
|
||||
this._object.isFlippedZ() ? -scaleZ : scaleZ
|
||||
);
|
||||
|
||||
threeObject3D.visible = !this._object.hidden;
|
||||
|
||||
this._isContainerDirty = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Call this to make sure the object is ready to be rendered.
|
||||
*/
|
||||
ensureUpToDate() {
|
||||
if (this._isContainerDirty) {
|
||||
this._updateThreeGroup();
|
||||
}
|
||||
}
|
||||
|
||||
update(): void {
|
||||
this._isContainerDirty = true;
|
||||
}
|
||||
|
||||
updateX(): void {
|
||||
this._isContainerDirty = true;
|
||||
}
|
||||
|
||||
updateY(): void {
|
||||
this._isContainerDirty = true;
|
||||
}
|
||||
|
||||
updateAngle(): void {
|
||||
this._isContainerDirty = true;
|
||||
}
|
||||
|
||||
updatePosition() {
|
||||
this._isContainerDirty = true;
|
||||
}
|
||||
|
||||
updateRotation() {
|
||||
this._isContainerDirty = true;
|
||||
}
|
||||
|
||||
updateSize() {
|
||||
this._isContainerDirty = true;
|
||||
}
|
||||
|
||||
updateVisibility(): void {
|
||||
this._threeGroup.visible = !this._object.hidden;
|
||||
}
|
||||
|
||||
updateOpacity(): void {
|
||||
// Opacity is not handled by 3D custom objects.
|
||||
}
|
||||
|
||||
setLayerIndex(layer: gdjs.RuntimeLayer, index: float): void {
|
||||
// Layers are not handled for 3D custom objects.
|
||||
}
|
||||
}
|
||||
}
|
@@ -74,16 +74,6 @@ namespace gdjs {
|
||||
this.updateRotation();
|
||||
}
|
||||
}
|
||||
getDoubleParameter(parameterName: string): number {
|
||||
if (parameterName === 'intensity') {
|
||||
return this.light.intensity;
|
||||
} else if (parameterName === 'elevation') {
|
||||
return this.elevation;
|
||||
} else if (parameterName === 'rotation') {
|
||||
return this.rotation;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
updateStringParameter(parameterName: string, value: string): void {
|
||||
if (parameterName === 'color') {
|
||||
this.light.color = new THREE.Color(
|
||||
@@ -95,17 +85,6 @@ namespace gdjs {
|
||||
this.updateRotation();
|
||||
}
|
||||
}
|
||||
updateColorParameter(parameterName: string, value: number): void {
|
||||
if (parameterName === 'color') {
|
||||
this.light.color.setHex(value);
|
||||
}
|
||||
}
|
||||
getColorParameter(parameterName: string): number {
|
||||
if (parameterName === 'color') {
|
||||
return this.light.color.getHex();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
updateBooleanParameter(parameterName: string, value: boolean): void {}
|
||||
updateRotation() {
|
||||
if (this.top === 'Z+') {
|
||||
@@ -114,7 +93,7 @@ namespace gdjs {
|
||||
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.y = gdjs.toRad(this.rotation) - 90;
|
||||
this.rotationObject.rotation.z = -gdjs.toRad(this.elevation);
|
||||
}
|
||||
}
|
||||
|
@@ -58,12 +58,6 @@ namespace gdjs {
|
||||
this.fog.density = value;
|
||||
}
|
||||
}
|
||||
getDoubleParameter(parameterName: string): number {
|
||||
if (parameterName === 'density') {
|
||||
return this.fog.density;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
updateStringParameter(parameterName: string, value: string): void {
|
||||
if (parameterName === 'color') {
|
||||
this.fog.color = new THREE.Color(
|
||||
@@ -71,17 +65,6 @@ namespace gdjs {
|
||||
);
|
||||
}
|
||||
}
|
||||
updateColorParameter(parameterName: string, value: number): void {
|
||||
if (parameterName === 'color') {
|
||||
this.fog.color.setHex(value);
|
||||
}
|
||||
}
|
||||
getColorParameter(parameterName: string): number {
|
||||
if (parameterName === 'color') {
|
||||
return this.fog.color.getHex();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
updateBooleanParameter(parameterName: string, value: boolean): void {}
|
||||
})();
|
||||
}
|
||||
|
@@ -1,74 +0,0 @@
|
||||
namespace gdjs {
|
||||
gdjs.PixiFiltersTools.registerFilterCreator(
|
||||
'Scene3D::Exposure',
|
||||
new (class implements gdjs.PixiFiltersTools.FilterCreator {
|
||||
makeFilter(
|
||||
target: EffectsTarget,
|
||||
effectData: EffectData
|
||||
): gdjs.PixiFiltersTools.Filter {
|
||||
if (typeof THREE === 'undefined') {
|
||||
return new gdjs.PixiFiltersTools.EmptyFilter();
|
||||
}
|
||||
return new (class implements gdjs.PixiFiltersTools.Filter {
|
||||
shaderPass: THREE_ADDONS.ShaderPass;
|
||||
_isEnabled: boolean;
|
||||
|
||||
constructor() {
|
||||
this.shaderPass = new THREE_ADDONS.ShaderPass(
|
||||
THREE_ADDONS.ExposureShader
|
||||
);
|
||||
this._isEnabled = false;
|
||||
}
|
||||
|
||||
isEnabled(target: EffectsTarget): boolean {
|
||||
return this._isEnabled;
|
||||
}
|
||||
setEnabled(target: EffectsTarget, enabled: boolean): boolean {
|
||||
if (this._isEnabled === enabled) {
|
||||
return true;
|
||||
}
|
||||
if (enabled) {
|
||||
return this.applyEffect(target);
|
||||
} else {
|
||||
return this.removeEffect(target);
|
||||
}
|
||||
}
|
||||
applyEffect(target: EffectsTarget): boolean {
|
||||
if (!(target instanceof gdjs.Layer)) {
|
||||
return false;
|
||||
}
|
||||
target.getRenderer().addPostProcessingPass(this.shaderPass);
|
||||
this._isEnabled = true;
|
||||
return true;
|
||||
}
|
||||
removeEffect(target: EffectsTarget): boolean {
|
||||
if (!(target instanceof gdjs.Layer)) {
|
||||
return false;
|
||||
}
|
||||
target.getRenderer().removePostProcessingPass(this.shaderPass);
|
||||
this._isEnabled = false;
|
||||
return true;
|
||||
}
|
||||
updatePreRender(target: gdjs.EffectsTarget): any {}
|
||||
updateDoubleParameter(parameterName: string, value: number): void {
|
||||
if (parameterName === 'exposure') {
|
||||
this.shaderPass.uniforms[parameterName].value = value;
|
||||
}
|
||||
}
|
||||
getDoubleParameter(parameterName: string): number {
|
||||
if (parameterName === 'exposure') {
|
||||
return this.shaderPass.uniforms[parameterName].value;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
updateStringParameter(parameterName: string, value: string): void {}
|
||||
updateColorParameter(parameterName: string, value: number): void {}
|
||||
getColorParameter(parameterName: string): number {
|
||||
return 0;
|
||||
}
|
||||
updateBooleanParameter(parameterName: string, value: boolean): void {}
|
||||
})();
|
||||
}
|
||||
})()
|
||||
);
|
||||
}
|
@@ -74,16 +74,6 @@ namespace gdjs {
|
||||
this.updateRotation();
|
||||
}
|
||||
}
|
||||
getDoubleParameter(parameterName: string): number {
|
||||
if (parameterName === 'intensity') {
|
||||
return this.light.intensity;
|
||||
} else if (parameterName === 'elevation') {
|
||||
return this.elevation;
|
||||
} else if (parameterName === 'rotation') {
|
||||
return this.rotation;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
updateStringParameter(parameterName: string, value: string): void {
|
||||
if (parameterName === 'skyColor') {
|
||||
this.light.color = new THREE.Color(
|
||||
@@ -100,23 +90,6 @@ namespace gdjs {
|
||||
this.updateRotation();
|
||||
}
|
||||
}
|
||||
updateColorParameter(parameterName: string, value: number): void {
|
||||
if (parameterName === 'skyColor') {
|
||||
this.light.color.setHex(value);
|
||||
}
|
||||
if (parameterName === 'groundColor') {
|
||||
this.light.groundColor.setHex(value);
|
||||
}
|
||||
}
|
||||
getColorParameter(parameterName: string): number {
|
||||
if (parameterName === 'skyColor') {
|
||||
return this.light.color.getHex();
|
||||
}
|
||||
if (parameterName === 'groundColor') {
|
||||
return this.light.groundColor.getHex();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
updateBooleanParameter(parameterName: string, value: boolean): void {}
|
||||
updateRotation() {
|
||||
if (this.top === 'Z+') {
|
||||
@@ -125,7 +98,7 @@ namespace gdjs {
|
||||
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.y = gdjs.toRad(this.rotation) - 90;
|
||||
this.rotationObject.rotation.z = -gdjs.toRad(this.elevation);
|
||||
}
|
||||
}
|
||||
|
@@ -1,80 +0,0 @@
|
||||
namespace gdjs {
|
||||
gdjs.PixiFiltersTools.registerFilterCreator(
|
||||
'Scene3D::HueAndSaturation',
|
||||
new (class implements gdjs.PixiFiltersTools.FilterCreator {
|
||||
makeFilter(
|
||||
target: EffectsTarget,
|
||||
effectData: EffectData
|
||||
): gdjs.PixiFiltersTools.Filter {
|
||||
if (typeof THREE === 'undefined') {
|
||||
return new gdjs.PixiFiltersTools.EmptyFilter();
|
||||
}
|
||||
return new (class implements gdjs.PixiFiltersTools.Filter {
|
||||
shaderPass: THREE_ADDONS.ShaderPass;
|
||||
_isEnabled: boolean;
|
||||
|
||||
constructor() {
|
||||
this.shaderPass = new THREE_ADDONS.ShaderPass(
|
||||
THREE_ADDONS.HueSaturationShader
|
||||
);
|
||||
this._isEnabled = false;
|
||||
}
|
||||
|
||||
isEnabled(target: EffectsTarget): boolean {
|
||||
return this._isEnabled;
|
||||
}
|
||||
setEnabled(target: EffectsTarget, enabled: boolean): boolean {
|
||||
if (this._isEnabled === enabled) {
|
||||
return true;
|
||||
}
|
||||
if (enabled) {
|
||||
return this.applyEffect(target);
|
||||
} else {
|
||||
return this.removeEffect(target);
|
||||
}
|
||||
}
|
||||
applyEffect(target: EffectsTarget): boolean {
|
||||
if (!(target instanceof gdjs.Layer)) {
|
||||
return false;
|
||||
}
|
||||
target.getRenderer().addPostProcessingPass(this.shaderPass);
|
||||
this._isEnabled = true;
|
||||
return true;
|
||||
}
|
||||
removeEffect(target: EffectsTarget): boolean {
|
||||
if (!(target instanceof gdjs.Layer)) {
|
||||
return false;
|
||||
}
|
||||
target.getRenderer().removePostProcessingPass(this.shaderPass);
|
||||
this._isEnabled = false;
|
||||
return true;
|
||||
}
|
||||
updatePreRender(target: gdjs.EffectsTarget): any {}
|
||||
updateDoubleParameter(parameterName: string, value: number): void {
|
||||
if (parameterName === 'hue') {
|
||||
this.shaderPass.uniforms[parameterName].value = value / 180;
|
||||
}
|
||||
if (parameterName === 'saturation') {
|
||||
this.shaderPass.uniforms[parameterName].value = value;
|
||||
}
|
||||
}
|
||||
getDoubleParameter(parameterName: string): number {
|
||||
if (parameterName === 'hue') {
|
||||
return this.shaderPass.uniforms[parameterName].value * 180;
|
||||
}
|
||||
if (parameterName === 'saturation') {
|
||||
return this.shaderPass.uniforms[parameterName].value;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
updateStringParameter(parameterName: string, value: string): void {}
|
||||
updateColorParameter(parameterName: string, value: number): void {}
|
||||
getColorParameter(parameterName: string): number {
|
||||
return 0;
|
||||
}
|
||||
updateBooleanParameter(parameterName: string, value: boolean): void {}
|
||||
})();
|
||||
}
|
||||
})()
|
||||
);
|
||||
}
|
@@ -1,5 +1,4 @@
|
||||
//@ts-check
|
||||
/// <reference path="../JsExtensionTypes.d.ts" />
|
||||
// @flow
|
||||
/**
|
||||
* This is a declaration of an extension for GDevelop 5.
|
||||
*
|
||||
@@ -13,9 +12,18 @@
|
||||
* More information on https://github.com/4ian/GDevelop/blob/master/newIDE/README-extensions.md
|
||||
*/
|
||||
|
||||
/** @type {ExtensionModule} */
|
||||
/*::
|
||||
// Import types to allow Flow to do static type checking on this file.
|
||||
// Extensions declaration are typed using Flow (like the editor), but the files
|
||||
// for the game engine are checked with TypeScript annotations.
|
||||
import { type ObjectsRenderingService, type ObjectsEditorService } from '../JsExtensionTypes.flow.js'
|
||||
*/
|
||||
|
||||
module.exports = {
|
||||
createExtension: function (_, gd) {
|
||||
createExtension: function (
|
||||
_ /*: (string) => string */,
|
||||
gd /*: libGDevelop */
|
||||
) {
|
||||
const extension = new gd.PlatformExtension();
|
||||
extension
|
||||
.setExtensionInformation(
|
||||
@@ -56,7 +64,7 @@ module.exports = {
|
||||
_('Position'),
|
||||
'res/conditions/3d_box.svg'
|
||||
)
|
||||
.addParameter('object', _('3D object'), '', false)
|
||||
.addParameter('object', _('3D object'))
|
||||
.addParameter('behavior', _('Behavior'), 'Base3DBehavior')
|
||||
.useStandardParameters('number', gd.ParameterOptions.makeNewOptions())
|
||||
.setFunctionName('setZ')
|
||||
@@ -72,7 +80,7 @@ module.exports = {
|
||||
_('Position/Center'),
|
||||
'res/conditions/3d_box.svg'
|
||||
)
|
||||
.addParameter('object', _('3D object'), '', false)
|
||||
.addParameter('object', _('3D object'))
|
||||
.addParameter('behavior', _('Behavior'), 'Base3DBehavior')
|
||||
.useStandardParameters('number', gd.ParameterOptions.makeNewOptions())
|
||||
.setFunctionName('setCenterZInScene')
|
||||
@@ -88,7 +96,7 @@ module.exports = {
|
||||
_('Size'),
|
||||
'res/conditions/3d_box.svg'
|
||||
)
|
||||
.addParameter('object', _('3D object'), '', false)
|
||||
.addParameter('object', _('3D object'))
|
||||
.addParameter('behavior', _('Behavior'), 'Base3DBehavior')
|
||||
.useStandardParameters('number', gd.ParameterOptions.makeNewOptions())
|
||||
.setFunctionName('setDepth')
|
||||
@@ -104,7 +112,7 @@ module.exports = {
|
||||
_('Size'),
|
||||
'res/conditions/3d_box.svg'
|
||||
)
|
||||
.addParameter('object', _('3D object'), '', false)
|
||||
.addParameter('object', _('3D object'))
|
||||
.addParameter('behavior', _('Behavior'), 'Base3DBehavior')
|
||||
.useStandardParameters(
|
||||
'number',
|
||||
@@ -126,7 +134,7 @@ module.exports = {
|
||||
'res/conditions/3d_box.svg',
|
||||
'res/conditions/3d_box.svg'
|
||||
)
|
||||
.addParameter('object', _('3D object'), '', false)
|
||||
.addParameter('object', _('3D object'))
|
||||
.addParameter('behavior', _('Behavior'), 'Base3DBehavior')
|
||||
.addParameter('yesorno', _('Activate flipping'))
|
||||
.markAsSimple()
|
||||
@@ -142,7 +150,7 @@ module.exports = {
|
||||
'res/conditions/3d_box.svg',
|
||||
'res/conditions/3d_box.svg'
|
||||
)
|
||||
.addParameter('object', _('3D object'), '', false)
|
||||
.addParameter('object', _('3D object'))
|
||||
.addParameter('behavior', _('Behavior'), 'Base3DBehavior')
|
||||
.setFunctionName('isFlippedZ');
|
||||
|
||||
@@ -156,7 +164,7 @@ module.exports = {
|
||||
_('Angle'),
|
||||
'res/conditions/3d_box.svg'
|
||||
)
|
||||
.addParameter('object', _('3D object'), '', false)
|
||||
.addParameter('object', _('3D object'))
|
||||
.addParameter('behavior', _('Behavior'), 'Base3DBehavior')
|
||||
.useStandardParameters('number', gd.ParameterOptions.makeNewOptions())
|
||||
.setFunctionName('setRotationX')
|
||||
@@ -172,7 +180,7 @@ module.exports = {
|
||||
_('Angle'),
|
||||
'res/conditions/3d_box.svg'
|
||||
)
|
||||
.addParameter('object', _('3D object'), '', false)
|
||||
.addParameter('object', _('3D object'))
|
||||
.addParameter('behavior', _('Behavior'), 'Base3DBehavior')
|
||||
.useStandardParameters('number', gd.ParameterOptions.makeNewOptions())
|
||||
.setFunctionName('setRotationY')
|
||||
@@ -190,7 +198,7 @@ module.exports = {
|
||||
'res/conditions/3d_box.svg',
|
||||
'res/conditions/3d_box.svg'
|
||||
)
|
||||
.addParameter('object', _('3D object'), '', false)
|
||||
.addParameter('object', _('3D object'))
|
||||
.addParameter('behavior', _('Behavior'), 'Base3DBehavior')
|
||||
.addParameter('number', _('Rotation angle'), '', false)
|
||||
.markAsAdvanced()
|
||||
@@ -208,7 +216,7 @@ module.exports = {
|
||||
'res/conditions/3d_box.svg',
|
||||
'res/conditions/3d_box.svg'
|
||||
)
|
||||
.addParameter('object', _('3D object'), '', false)
|
||||
.addParameter('object', _('3D object'))
|
||||
.addParameter('behavior', _('Behavior'), 'Base3DBehavior')
|
||||
.addParameter('number', _('Rotation angle'), '', false)
|
||||
.markAsAdvanced()
|
||||
@@ -226,7 +234,7 @@ module.exports = {
|
||||
'res/conditions/3d_box.svg',
|
||||
'res/conditions/3d_box.svg'
|
||||
)
|
||||
.addParameter('object', _('3D object'), '', false)
|
||||
.addParameter('object', _('3D object'))
|
||||
.addParameter('behavior', _('Behavior'), 'Base3DBehavior')
|
||||
.addParameter('number', _('Rotation angle'), '', false)
|
||||
.markAsAdvanced()
|
||||
@@ -239,7 +247,7 @@ module.exports = {
|
||||
'Model3DObject',
|
||||
_('3D Model'),
|
||||
_('An animated 3D model.'),
|
||||
'JsPlatform/Extensions/3d_model.svg',
|
||||
'JsPlatform/Extensions/3d_box.svg',
|
||||
new gd.Model3DObjectConfiguration()
|
||||
)
|
||||
.setCategoryFullName(_('General'))
|
||||
@@ -493,7 +501,7 @@ module.exports = {
|
||||
'res/actions/flipX24.png',
|
||||
'res/actions/flipX.png'
|
||||
)
|
||||
.addParameter('object', _('3D model'), 'Model3DObject', false)
|
||||
.addParameter('object', _('3D model'), 'Model3DObject')
|
||||
.addParameter('yesorno', _('Activate flipping'))
|
||||
.setHidden()
|
||||
.markAsSimple()
|
||||
@@ -510,7 +518,7 @@ module.exports = {
|
||||
'res/actions/flipY24.png',
|
||||
'res/actions/flipY.png'
|
||||
)
|
||||
.addParameter('object', _('3D model'), 'Model3DObject', false)
|
||||
.addParameter('object', _('3D model'), 'Model3DObject')
|
||||
.addParameter('yesorno', _('Activate flipping'))
|
||||
.setHidden()
|
||||
.markAsSimple()
|
||||
@@ -527,7 +535,7 @@ module.exports = {
|
||||
'res/conditions/3d_box.svg',
|
||||
'res/conditions/3d_box.svg'
|
||||
)
|
||||
.addParameter('object', _('3D model'), 'Model3DObject', false)
|
||||
.addParameter('object', _('3D model'), 'Model3DObject')
|
||||
.addParameter('yesorno', _('Activate flipping'))
|
||||
.markAsSimple()
|
||||
.setHidden()
|
||||
@@ -544,7 +552,7 @@ module.exports = {
|
||||
'res/actions/flipX24.png',
|
||||
'res/actions/flipX.png'
|
||||
)
|
||||
.addParameter('object', _('3D model'), 'Model3DObject', false)
|
||||
.addParameter('object', _('3D model'), 'Model3DObject')
|
||||
.setHidden()
|
||||
.setFunctionName('isFlippedX');
|
||||
|
||||
@@ -559,7 +567,7 @@ module.exports = {
|
||||
'res/actions/flipY24.png',
|
||||
'res/actions/flipY.png'
|
||||
)
|
||||
.addParameter('object', _('3D model'), 'Model3DObject', false)
|
||||
.addParameter('object', _('3D model'), 'Model3DObject')
|
||||
.setHidden()
|
||||
.setFunctionName('isFlippedY');
|
||||
|
||||
@@ -574,7 +582,7 @@ module.exports = {
|
||||
'res/conditions/3d_box.svg',
|
||||
'res/conditions/3d_box.svg'
|
||||
)
|
||||
.addParameter('object', _('3D model'), 'Model3DObject', false)
|
||||
.addParameter('object', _('3D model'), 'Model3DObject')
|
||||
.setHidden()
|
||||
.setFunctionName('isFlippedZ');
|
||||
|
||||
@@ -682,7 +690,7 @@ module.exports = {
|
||||
_('Animations and images'),
|
||||
'res/actions/animation24.png'
|
||||
)
|
||||
.addParameter('object', _('3D model'), 'Model3DObject', false)
|
||||
.addParameter('object', _('3D model'), 'Model3DObject')
|
||||
.useStandardParameters('number', gd.ParameterOptions.makeNewOptions())
|
||||
.markAsSimple()
|
||||
.setHidden()
|
||||
@@ -700,7 +708,7 @@ module.exports = {
|
||||
_('Animations and images'),
|
||||
'res/actions/animation24.png'
|
||||
)
|
||||
.addParameter('object', _('3D model'), 'Model3DObject', false)
|
||||
.addParameter('object', _('3D model'), 'Model3DObject')
|
||||
.useStandardParameters(
|
||||
'objectAnimationName',
|
||||
gd.ParameterOptions.makeNewOptions().setDescription(
|
||||
@@ -723,7 +731,7 @@ module.exports = {
|
||||
'res/actions/animation24.png',
|
||||
'res/actions/animation.png'
|
||||
)
|
||||
.addParameter('object', _('3D model'), 'Model3DObject', false)
|
||||
.addParameter('object', _('3D model'), 'Model3DObject')
|
||||
.markAsSimple()
|
||||
.setHidden()
|
||||
.setFunctionName('pauseAnimation');
|
||||
@@ -739,7 +747,7 @@ module.exports = {
|
||||
'res/actions/animation24.png',
|
||||
'res/actions/animation.png'
|
||||
)
|
||||
.addParameter('object', _('3D model'), 'Model3DObject', false)
|
||||
.addParameter('object', _('3D model'), 'Model3DObject')
|
||||
.markAsSimple()
|
||||
.setHidden()
|
||||
.setFunctionName('resumeAnimation');
|
||||
@@ -757,7 +765,7 @@ module.exports = {
|
||||
_('Animations and images'),
|
||||
'res/actions/animation24.png'
|
||||
)
|
||||
.addParameter('object', _('3D model'), 'Model3DObject', false)
|
||||
.addParameter('object', _('3D model'), 'Model3DObject')
|
||||
.useStandardParameters(
|
||||
'number',
|
||||
gd.ParameterOptions.makeNewOptions().setDescription(_('Speed scale'))
|
||||
@@ -778,7 +786,7 @@ module.exports = {
|
||||
'res/conditions/animation24.png',
|
||||
'res/conditions/animation.png'
|
||||
)
|
||||
.addParameter('object', _('3D model'), 'Model3DObject', false)
|
||||
.addParameter('object', _('3D model'), 'Model3DObject')
|
||||
.markAsSimple()
|
||||
.setHidden()
|
||||
.setFunctionName('isAnimationPaused');
|
||||
@@ -796,13 +804,14 @@ module.exports = {
|
||||
'res/conditions/animation24.png',
|
||||
'res/conditions/animation.png'
|
||||
)
|
||||
.addParameter('object', _('3D model'), 'Model3DObject', false)
|
||||
.addParameter('object', _('3D model'), 'Model3DObject')
|
||||
.markAsSimple()
|
||||
.setHidden()
|
||||
.setFunctionName('hasAnimationEnded');
|
||||
}
|
||||
|
||||
const Cube3DObject = new gd.ObjectJsImplementation();
|
||||
// $FlowExpectedError - ignore Flow warning as we're creating an object
|
||||
Cube3DObject.updateProperty = function (
|
||||
objectContent,
|
||||
propertyName,
|
||||
@@ -851,6 +860,7 @@ module.exports = {
|
||||
|
||||
return false;
|
||||
};
|
||||
// $FlowExpectedError - ignore Flow warning as we're creating an object
|
||||
Cube3DObject.getProperties = function (objectContent) {
|
||||
const objectProperties = new gd.MapStringPropertyDescriptor();
|
||||
|
||||
@@ -1090,6 +1100,7 @@ module.exports = {
|
||||
})
|
||||
);
|
||||
|
||||
// $FlowExpectedError
|
||||
Cube3DObject.updateInitialInstanceProperty = function (
|
||||
objectContent,
|
||||
instance,
|
||||
@@ -1101,6 +1112,7 @@ module.exports = {
|
||||
return false;
|
||||
};
|
||||
|
||||
// $FlowExpectedError
|
||||
Cube3DObject.getInitialInstanceProperties = function (
|
||||
content,
|
||||
instance,
|
||||
@@ -1352,7 +1364,7 @@ module.exports = {
|
||||
'res/actions/flipX24.png',
|
||||
'res/actions/flipX.png'
|
||||
)
|
||||
.addParameter('object', _('3D cube'), 'Cube3DObject', false)
|
||||
.addParameter('object', _('3D cube'), 'Cube3DObject')
|
||||
.addParameter('yesorno', _('Activate flipping'))
|
||||
.markAsSimple()
|
||||
.setHidden()
|
||||
@@ -1369,7 +1381,7 @@ module.exports = {
|
||||
'res/actions/flipY24.png',
|
||||
'res/actions/flipY.png'
|
||||
)
|
||||
.addParameter('object', _('3D cube'), 'Cube3DObject', false)
|
||||
.addParameter('object', _('3D cube'), 'Cube3DObject')
|
||||
.addParameter('yesorno', _('Activate flipping'))
|
||||
.markAsSimple()
|
||||
.setHidden()
|
||||
@@ -1386,7 +1398,7 @@ module.exports = {
|
||||
'res/conditions/3d_box.svg',
|
||||
'res/conditions/3d_box.svg'
|
||||
)
|
||||
.addParameter('object', _('3D cube'), 'Cube3DObject', false)
|
||||
.addParameter('object', _('3D cube'), 'Cube3DObject')
|
||||
.addParameter('yesorno', _('Activate flipping'))
|
||||
.markAsSimple()
|
||||
.setHidden()
|
||||
@@ -1403,7 +1415,7 @@ module.exports = {
|
||||
'res/actions/flipX24.png',
|
||||
'res/actions/flipX.png'
|
||||
)
|
||||
.addParameter('object', _('3D cube'), 'Cube3DObject', false)
|
||||
.addParameter('object', _('3D cube'), 'Cube3DObject')
|
||||
.setHidden()
|
||||
.setFunctionName('isFlippedX');
|
||||
|
||||
@@ -1418,7 +1430,7 @@ module.exports = {
|
||||
'res/actions/flipY24.png',
|
||||
'res/actions/flipY.png'
|
||||
)
|
||||
.addParameter('object', _('3D cube'), 'Cube3DObject', false)
|
||||
.addParameter('object', _('3D cube'), 'Cube3DObject')
|
||||
.setHidden()
|
||||
.setFunctionName('isFlippedY');
|
||||
|
||||
@@ -1433,7 +1445,7 @@ module.exports = {
|
||||
'res/conditions/3d_box.svg',
|
||||
'res/conditions/3d_box.svg'
|
||||
)
|
||||
.addParameter('object', _('3D cube'), 'Cube3DObject', false)
|
||||
.addParameter('object', _('3D cube'), 'Cube3DObject')
|
||||
.setHidden()
|
||||
.setFunctionName('isFlippedZ');
|
||||
|
||||
@@ -1653,7 +1665,7 @@ module.exports = {
|
||||
'Change the camera rotation to look at an object. The camera top always face the screen.'
|
||||
),
|
||||
_('Change the camera rotation of _PARAM2_ to look at _PARAM1_'),
|
||||
_('Layers and cameras'),
|
||||
_("Layers and cameras"),
|
||||
'res/conditions/3d_box.svg',
|
||||
'res/conditions/3d_box.svg'
|
||||
)
|
||||
@@ -1927,86 +1939,6 @@ module.exports = {
|
||||
.setType('number')
|
||||
.setGroup(_('Orientation'));
|
||||
}
|
||||
{
|
||||
const effect = extension
|
||||
.addEffect('HueAndSaturation')
|
||||
.setFullName(_('Hue and saturation'))
|
||||
.setDescription(_('Adjust hue and saturation.'))
|
||||
.markAsNotWorkingForObjects()
|
||||
.markAsOnlyWorkingFor3D()
|
||||
.addIncludeFile('Extensions/3D/HueAndSaturationEffect.js');
|
||||
const properties = effect.getProperties();
|
||||
properties
|
||||
.getOrCreate('hue')
|
||||
.setValue('0')
|
||||
.setLabel(_('Hue in degrees (between -180 and 180)'))
|
||||
.setType('number');
|
||||
properties
|
||||
.getOrCreate('saturation')
|
||||
.setValue('0')
|
||||
.setLabel(_('Saturation (between -1 and 1)'))
|
||||
.setType('number');
|
||||
}
|
||||
{
|
||||
const effect = extension
|
||||
.addEffect('Exposure')
|
||||
.setFullName(_('Exposure'))
|
||||
.setDescription(_('Adjust exposure.'))
|
||||
.markAsNotWorkingForObjects()
|
||||
.markAsOnlyWorkingFor3D()
|
||||
.addIncludeFile('Extensions/3D/ExposureEffect.js');
|
||||
const properties = effect.getProperties();
|
||||
properties
|
||||
.getOrCreate('exposure')
|
||||
.setValue('1')
|
||||
.setLabel(_('Exposure (positive value)'))
|
||||
.setType('number');
|
||||
}
|
||||
{
|
||||
const effect = extension
|
||||
.addEffect('Bloom')
|
||||
.setFullName(_('Bloom'))
|
||||
.setDescription(_('Apply a bloom effect.'))
|
||||
.markAsNotWorkingForObjects()
|
||||
.markAsOnlyWorkingFor3D()
|
||||
.addIncludeFile('Extensions/3D/BloomEffect.js');
|
||||
const properties = effect.getProperties();
|
||||
properties
|
||||
.getOrCreate('strength')
|
||||
.setValue('1')
|
||||
.setLabel(_('Strength (between 0 and 3)'))
|
||||
.setType('number');
|
||||
properties
|
||||
.getOrCreate('radius')
|
||||
.setValue('0')
|
||||
.setLabel(_('Radius (between 0 and 1)'))
|
||||
.setType('number');
|
||||
properties
|
||||
.getOrCreate('threshold')
|
||||
.setValue('0')
|
||||
.setLabel(_('Threshold (between 0 and 1)'))
|
||||
.setType('number');
|
||||
}
|
||||
{
|
||||
const effect = extension
|
||||
.addEffect('BrightnessAndContrast')
|
||||
.setFullName(_('Brightness and contrast.'))
|
||||
.setDescription(_('Adjust brightness and contrast.'))
|
||||
.markAsNotWorkingForObjects()
|
||||
.markAsOnlyWorkingFor3D()
|
||||
.addIncludeFile('Extensions/3D/BrightnessAndContrastEffect.js');
|
||||
const properties = effect.getProperties();
|
||||
properties
|
||||
.getOrCreate('brightness')
|
||||
.setValue('0')
|
||||
.setLabel(_('Brightness (between -1 and 1)'))
|
||||
.setType('number');
|
||||
properties
|
||||
.getOrCreate('contrast')
|
||||
.setValue('0')
|
||||
.setLabel(_('Contrast (between -1 and 1)'))
|
||||
.setType('number');
|
||||
}
|
||||
// Don't forget to update the alert condition in Model3DEditor.js when
|
||||
// adding a new light.
|
||||
|
||||
@@ -2022,7 +1954,10 @@ module.exports = {
|
||||
* But it is recommended to create tests for the behaviors/objects properties you created
|
||||
* to avoid mistakes.
|
||||
*/
|
||||
runExtensionSanityTests: function (gd, extension) {
|
||||
runExtensionSanityTests: function (
|
||||
gd /*: libGDevelop */,
|
||||
extension /*: gdPlatformExtension*/
|
||||
) {
|
||||
return [];
|
||||
},
|
||||
/**
|
||||
@@ -2030,13 +1965,17 @@ module.exports = {
|
||||
*
|
||||
* ℹ️ Run `node import-GDJS-Runtime.js` (in newIDE/app/scripts) if you make any change.
|
||||
*/
|
||||
registerEditorConfigurations: function (objectsEditorService) {},
|
||||
registerEditorConfigurations: function (
|
||||
objectsEditorService /*: ObjectsEditorService */
|
||||
) {},
|
||||
/**
|
||||
* Register renderers for instance of objects on the scene editor.
|
||||
*
|
||||
* ℹ️ Run `node import-GDJS-Runtime.js` (in newIDE/app/scripts) if you make any change.
|
||||
*/
|
||||
registerInstanceRenderers: function (objectsRenderingService) {
|
||||
registerInstanceRenderers: function (
|
||||
objectsRenderingService /*: ObjectsRenderingService */
|
||||
) {
|
||||
const RenderedInstance = objectsRenderingService.RenderedInstance;
|
||||
const Rendered3DInstance = objectsRenderingService.Rendered3DInstance;
|
||||
const PIXI = objectsRenderingService.PIXI;
|
||||
@@ -2044,25 +1983,39 @@ module.exports = {
|
||||
const THREE_ADDONS = objectsRenderingService.THREE_ADDONS;
|
||||
|
||||
const materialIndexToFaceIndex = {
|
||||
// $FlowFixMe
|
||||
0: 3,
|
||||
// $FlowFixMe
|
||||
1: 2,
|
||||
// $FlowFixMe
|
||||
2: 5,
|
||||
// $FlowFixMe
|
||||
3: 4,
|
||||
// $FlowFixMe
|
||||
4: 0,
|
||||
// $FlowFixMe
|
||||
5: 1,
|
||||
};
|
||||
|
||||
const noRepeatTextureVertexIndexToUvMapping = {
|
||||
// $FlowFixMe
|
||||
0: [0, 0],
|
||||
// $FlowFixMe
|
||||
1: [1, 0],
|
||||
// $FlowFixMe
|
||||
2: [0, 1],
|
||||
// $FlowFixMe
|
||||
3: [1, 1],
|
||||
};
|
||||
|
||||
const noRepeatTextureVertexIndexToUvMappingForLeftAndRightFacesTowardsZ = {
|
||||
// $FlowFixMe
|
||||
0: [0, 1],
|
||||
// $FlowFixMe
|
||||
1: [0, 0],
|
||||
// $FlowFixMe
|
||||
2: [1, 1],
|
||||
// $FlowFixMe
|
||||
3: [1, 0],
|
||||
};
|
||||
|
||||
@@ -2108,11 +2061,6 @@ module.exports = {
|
||||
};
|
||||
|
||||
class RenderedCube3DObject2DInstance extends RenderedInstance {
|
||||
/** @type {number} */
|
||||
_centerX = 0;
|
||||
/** @type {number} */
|
||||
_centerY = 0;
|
||||
|
||||
constructor(
|
||||
project,
|
||||
layout,
|
||||
@@ -2129,9 +2077,10 @@ module.exports = {
|
||||
pixiContainer,
|
||||
pixiResourcesLoader
|
||||
);
|
||||
|
||||
// Name of the resource that is rendered.
|
||||
// If no face is visible, this will be null.
|
||||
/**
|
||||
* Name of the resource that is rendered.
|
||||
* If no face is visible, this will be null.
|
||||
*/
|
||||
this._renderedResourceName = undefined;
|
||||
const properties = associatedObjectConfiguration.getProperties();
|
||||
this._defaultWidth = parseFloat(properties.get('width').getValue());
|
||||
@@ -2161,9 +2110,12 @@ module.exports = {
|
||||
}
|
||||
|
||||
static getThumbnail(project, resourcesLoader, objectConfiguration) {
|
||||
const textureResourceName = RenderedCube3DObject2DInstance._getResourceNameToDisplay(
|
||||
objectConfiguration
|
||||
);
|
||||
const instance = this._instance;
|
||||
|
||||
const textureResourceName =
|
||||
RenderedCube3DObject2DInstance._getResourceNameToDisplay(
|
||||
objectConfiguration
|
||||
);
|
||||
if (textureResourceName) {
|
||||
return resourcesLoader.getResourceFullUrl(
|
||||
project,
|
||||
@@ -2175,18 +2127,20 @@ module.exports = {
|
||||
}
|
||||
|
||||
updateTextureIfNeeded() {
|
||||
const textureName = RenderedCube3DObject2DInstance._getResourceNameToDisplay(
|
||||
this._associatedObjectConfiguration
|
||||
);
|
||||
const textureName =
|
||||
RenderedCube3DObject2DInstance._getResourceNameToDisplay(
|
||||
this._associatedObjectConfiguration
|
||||
);
|
||||
if (textureName === this._renderedResourceName) return;
|
||||
|
||||
this.updateTexture();
|
||||
}
|
||||
|
||||
updateTexture() {
|
||||
const textureName = RenderedCube3DObject2DInstance._getResourceNameToDisplay(
|
||||
this._associatedObjectConfiguration
|
||||
);
|
||||
const textureName =
|
||||
RenderedCube3DObject2DInstance._getResourceNameToDisplay(
|
||||
this._associatedObjectConfiguration
|
||||
);
|
||||
|
||||
if (!textureName) {
|
||||
this._renderFallbackObject = true;
|
||||
@@ -2444,9 +2398,10 @@ module.exports = {
|
||||
continue;
|
||||
}
|
||||
|
||||
const shouldRepeatTexture = this._shouldRepeatTextureOnFace[
|
||||
materialIndexToFaceIndex[materialIndex]
|
||||
];
|
||||
const shouldRepeatTexture =
|
||||
this._shouldRepeatTextureOnFace[
|
||||
materialIndexToFaceIndex[materialIndex]
|
||||
];
|
||||
|
||||
const shouldOrientateFacesTowardsY = this._facesOrientation === 'Y';
|
||||
|
||||
@@ -2481,16 +2436,13 @@ module.exports = {
|
||||
}
|
||||
} else {
|
||||
if (shouldOrientateFacesTowardsY) {
|
||||
[x, y] = noRepeatTextureVertexIndexToUvMapping[
|
||||
vertexIndex % 4
|
||||
];
|
||||
[x, y] =
|
||||
noRepeatTextureVertexIndexToUvMapping[vertexIndex % 4];
|
||||
} else {
|
||||
[
|
||||
x,
|
||||
y,
|
||||
] = noRepeatTextureVertexIndexToUvMappingForLeftAndRightFacesTowardsZ[
|
||||
vertexIndex % 4
|
||||
];
|
||||
[x, y] =
|
||||
noRepeatTextureVertexIndexToUvMappingForLeftAndRightFacesTowardsZ[
|
||||
vertexIndex % 4
|
||||
];
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -2520,16 +2472,13 @@ module.exports = {
|
||||
}
|
||||
} else {
|
||||
if (shouldOrientateFacesTowardsY) {
|
||||
[x, y] = noRepeatTextureVertexIndexToUvMapping[
|
||||
vertexIndex % 4
|
||||
];
|
||||
[x, y] =
|
||||
noRepeatTextureVertexIndexToUvMapping[vertexIndex % 4];
|
||||
} else {
|
||||
[
|
||||
x,
|
||||
y,
|
||||
] = noRepeatTextureVertexIndexToUvMappingForLeftAndRightFacesTowardsZ[
|
||||
vertexIndex % 4
|
||||
];
|
||||
[x, y] =
|
||||
noRepeatTextureVertexIndexToUvMappingForLeftAndRightFacesTowardsZ[
|
||||
vertexIndex % 4
|
||||
];
|
||||
x = -x;
|
||||
y = -y;
|
||||
}
|
||||
@@ -2675,8 +2624,6 @@ module.exports = {
|
||||
RenderedCube3DObject3DInstance
|
||||
);
|
||||
|
||||
const epsilon = 1 / (1 << 16);
|
||||
|
||||
class Model3DRendered2DInstance extends RenderedInstance {
|
||||
_modelOriginPoint = [0, 0, 0];
|
||||
|
||||
@@ -2748,7 +2695,7 @@ module.exports = {
|
||||
}
|
||||
|
||||
static getThumbnail(project, resourcesLoader, objectConfiguration) {
|
||||
return 'JsPlatform/Extensions/3d_model.svg';
|
||||
return 'JsPlatform/Extensions/3d_box.svg';
|
||||
}
|
||||
|
||||
getOriginX() {
|
||||
@@ -2789,9 +2736,6 @@ module.exports = {
|
||||
originalDepth,
|
||||
keepAspectRatio
|
||||
) {
|
||||
// These formulas are also used in:
|
||||
// - gdjs.Model3DRuntimeObject3DRenderer._updateDefaultTransformation
|
||||
// - Model3DEditor.modelSize
|
||||
threeObject.rotation.set(
|
||||
(rotationX * Math.PI) / 180,
|
||||
(rotationY * Math.PI) / 180,
|
||||
@@ -2799,24 +2743,13 @@ module.exports = {
|
||||
);
|
||||
threeObject.updateMatrixWorld(true);
|
||||
const boundingBox = new THREE.Box3().setFromObject(threeObject);
|
||||
const shouldKeepModelOrigin = !this._originPoint;
|
||||
if (shouldKeepModelOrigin) {
|
||||
// Keep the origin as part of the model.
|
||||
// For instance, a model can be 1 face of a cube and we want to keep the
|
||||
// inside as part of the object even if it's just void.
|
||||
// It also avoids to have the origin outside of the object box.
|
||||
boundingBox.expandByPoint(new THREE.Vector3(0, 0, 0));
|
||||
}
|
||||
|
||||
const modelWidth = boundingBox.max.x - boundingBox.min.x;
|
||||
const modelHeight = boundingBox.max.y - boundingBox.min.y;
|
||||
const modelDepth = boundingBox.max.z - boundingBox.min.z;
|
||||
this._modelOriginPoint[0] =
|
||||
modelWidth < epsilon ? 0 : -boundingBox.min.x / modelWidth;
|
||||
this._modelOriginPoint[1] =
|
||||
modelHeight < epsilon ? 0 : -boundingBox.min.y / modelHeight;
|
||||
this._modelOriginPoint[2] =
|
||||
modelDepth < epsilon ? 0 : -boundingBox.min.z / modelDepth;
|
||||
this._modelOriginPoint[0] = -boundingBox.min.x / modelWidth;
|
||||
this._modelOriginPoint[1] = -boundingBox.min.y / modelHeight;
|
||||
this._modelOriginPoint[2] = -boundingBox.min.z / modelDepth;
|
||||
|
||||
// The model is flipped on Y axis.
|
||||
this._modelOriginPoint[1] = 1 - this._modelOriginPoint[1];
|
||||
@@ -2825,10 +2758,19 @@ module.exports = {
|
||||
const centerPoint = this._centerPoint;
|
||||
if (centerPoint) {
|
||||
threeObject.position.set(
|
||||
-(boundingBox.min.x + modelWidth * centerPoint[0]),
|
||||
-(
|
||||
boundingBox.min.x +
|
||||
(boundingBox.max.x - boundingBox.min.x) * centerPoint[0]
|
||||
),
|
||||
// The model is flipped on Y axis.
|
||||
-(boundingBox.min.y + modelHeight * (1 - centerPoint[1])),
|
||||
-(boundingBox.min.z + modelDepth * centerPoint[2])
|
||||
-(
|
||||
boundingBox.min.y +
|
||||
(boundingBox.max.y - boundingBox.min.y) * (1 - centerPoint[1])
|
||||
),
|
||||
-(
|
||||
boundingBox.min.z +
|
||||
(boundingBox.max.z - boundingBox.min.z) * centerPoint[2]
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -2841,9 +2783,9 @@ module.exports = {
|
||||
);
|
||||
|
||||
// Stretch the model in a 1x1x1 cube.
|
||||
const scaleX = modelWidth < epsilon ? 1 : 1 / modelWidth;
|
||||
const scaleY = modelHeight < epsilon ? 1 : 1 / modelHeight;
|
||||
const scaleZ = modelDepth < epsilon ? 1 : 1 / modelDepth;
|
||||
const scaleX = 1 / modelWidth;
|
||||
const scaleY = 1 / modelHeight;
|
||||
const scaleZ = 1 / modelDepth;
|
||||
|
||||
const scaleMatrix = new THREE.Matrix4();
|
||||
// Flip on Y because the Y axis is on the opposite side of direct basis.
|
||||
@@ -2854,22 +2796,10 @@ module.exports = {
|
||||
|
||||
if (keepAspectRatio) {
|
||||
// Reduce the object dimensions to keep aspect ratio.
|
||||
const widthRatio =
|
||||
modelWidth < epsilon
|
||||
? Number.POSITIVE_INFINITY
|
||||
: originalWidth / modelWidth;
|
||||
const heightRatio =
|
||||
modelHeight < epsilon
|
||||
? Number.POSITIVE_INFINITY
|
||||
: originalHeight / modelHeight;
|
||||
const depthRatio =
|
||||
modelDepth < epsilon
|
||||
? Number.POSITIVE_INFINITY
|
||||
: originalDepth / modelDepth;
|
||||
let scaleRatio = Math.min(widthRatio, heightRatio, depthRatio);
|
||||
if (!Number.isFinite(scaleRatio)) {
|
||||
scaleRatio = 1;
|
||||
}
|
||||
const widthRatio = originalWidth / modelWidth;
|
||||
const heightRatio = originalHeight / modelHeight;
|
||||
const depthRatio = originalDepth / modelDepth;
|
||||
const scaleRatio = Math.min(widthRatio, heightRatio, depthRatio);
|
||||
|
||||
this._defaultWidth = scaleRatio * modelWidth;
|
||||
this._defaultHeight = scaleRatio * modelHeight;
|
||||
@@ -3021,11 +2951,6 @@ module.exports = {
|
||||
return this.getHeight() * originPoint[1];
|
||||
}
|
||||
|
||||
getOriginZ() {
|
||||
const originPoint = this.getOriginPoint();
|
||||
return this.getDepth() * originPoint[2];
|
||||
}
|
||||
|
||||
getCenterX() {
|
||||
const centerPoint = this.getCenterPoint();
|
||||
return this.getWidth() * centerPoint[0];
|
||||
@@ -3036,11 +2961,6 @@ module.exports = {
|
||||
return this.getHeight() * centerPoint[1];
|
||||
}
|
||||
|
||||
getCenterZ() {
|
||||
const centerPoint = this.getCenterPoint();
|
||||
return this.getDepth() * centerPoint[2];
|
||||
}
|
||||
|
||||
getOriginPoint() {
|
||||
return this._originPoint || this._modelOriginPoint;
|
||||
}
|
||||
@@ -3067,24 +2987,12 @@ module.exports = {
|
||||
threeObject.updateMatrixWorld(true);
|
||||
const boundingBox = new THREE.Box3().setFromObject(threeObject);
|
||||
|
||||
const shouldKeepModelOrigin = !this._originPoint;
|
||||
if (shouldKeepModelOrigin) {
|
||||
// Keep the origin as part of the model.
|
||||
// For instance, a model can be 1 face of a cube and we want to keep the
|
||||
// inside as part of the object even if it's just void.
|
||||
// It also avoids to have the origin outside of the object box.
|
||||
boundingBox.expandByPoint(new THREE.Vector3(0, 0, 0));
|
||||
}
|
||||
|
||||
const modelWidth = boundingBox.max.x - boundingBox.min.x;
|
||||
const modelHeight = boundingBox.max.y - boundingBox.min.y;
|
||||
const modelDepth = boundingBox.max.z - boundingBox.min.z;
|
||||
this._modelOriginPoint[0] =
|
||||
modelWidth < epsilon ? 0 : -boundingBox.min.x / modelWidth;
|
||||
this._modelOriginPoint[1] =
|
||||
modelHeight < epsilon ? 0 : -boundingBox.min.y / modelHeight;
|
||||
this._modelOriginPoint[2] =
|
||||
modelDepth < epsilon ? 0 : -boundingBox.min.z / modelDepth;
|
||||
this._modelOriginPoint[0] = -boundingBox.min.x / modelWidth;
|
||||
this._modelOriginPoint[1] = -boundingBox.min.y / modelHeight;
|
||||
this._modelOriginPoint[2] = -boundingBox.min.z / modelDepth;
|
||||
|
||||
// The model is flipped on Y axis.
|
||||
this._modelOriginPoint[1] = 1 - this._modelOriginPoint[1];
|
||||
@@ -3093,10 +3001,19 @@ module.exports = {
|
||||
const centerPoint = this._centerPoint;
|
||||
if (centerPoint) {
|
||||
threeObject.position.set(
|
||||
-(boundingBox.min.x + modelWidth * centerPoint[0]),
|
||||
-(
|
||||
boundingBox.min.x +
|
||||
(boundingBox.max.x - boundingBox.min.x) * centerPoint[0]
|
||||
),
|
||||
// The model is flipped on Y axis.
|
||||
-(boundingBox.min.y + modelHeight * (1 - centerPoint[1])),
|
||||
-(boundingBox.min.z + modelDepth * centerPoint[2])
|
||||
-(
|
||||
boundingBox.min.y +
|
||||
(boundingBox.max.y - boundingBox.min.y) * (1 - centerPoint[1])
|
||||
),
|
||||
-(
|
||||
boundingBox.min.z +
|
||||
(boundingBox.max.z - boundingBox.min.z) * centerPoint[2]
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -3109,9 +3026,9 @@ module.exports = {
|
||||
);
|
||||
|
||||
// Stretch the model in a 1x1x1 cube.
|
||||
const scaleX = modelWidth < epsilon ? 1 : 1 / modelWidth;
|
||||
const scaleY = modelHeight < epsilon ? 1 : 1 / modelHeight;
|
||||
const scaleZ = modelDepth < epsilon ? 1 : 1 / modelDepth;
|
||||
const scaleX = 1 / modelWidth;
|
||||
const scaleY = 1 / modelHeight;
|
||||
const scaleZ = 1 / modelDepth;
|
||||
|
||||
const scaleMatrix = new THREE.Matrix4();
|
||||
// Flip on Y because the Y axis is on the opposite side of direct basis.
|
||||
@@ -3122,22 +3039,10 @@ module.exports = {
|
||||
|
||||
if (keepAspectRatio) {
|
||||
// Reduce the object dimensions to keep aspect ratio.
|
||||
const widthRatio =
|
||||
modelWidth < epsilon
|
||||
? Number.POSITIVE_INFINITY
|
||||
: originalWidth / modelWidth;
|
||||
const heightRatio =
|
||||
modelHeight < epsilon
|
||||
? Number.POSITIVE_INFINITY
|
||||
: originalHeight / modelHeight;
|
||||
const depthRatio =
|
||||
modelDepth < epsilon
|
||||
? Number.POSITIVE_INFINITY
|
||||
: originalDepth / modelDepth;
|
||||
let scaleRatio = Math.min(widthRatio, heightRatio, depthRatio);
|
||||
if (!Number.isFinite(scaleRatio)) {
|
||||
scaleRatio = 1;
|
||||
}
|
||||
const widthRatio = originalWidth / modelWidth;
|
||||
const heightRatio = originalHeight / modelHeight;
|
||||
const depthRatio = originalDepth / modelDepth;
|
||||
const scaleRatio = Math.min(widthRatio, heightRatio, depthRatio);
|
||||
|
||||
this._defaultWidth = scaleRatio * modelWidth;
|
||||
this._defaultHeight = scaleRatio * modelHeight;
|
||||
|
@@ -60,14 +60,6 @@ namespace gdjs {
|
||||
this.fog.far = value;
|
||||
}
|
||||
}
|
||||
getDoubleParameter(parameterName: string): number {
|
||||
if (parameterName === 'near') {
|
||||
return this.fog.near;
|
||||
} else if (parameterName === 'far') {
|
||||
return this.fog.far;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
updateStringParameter(parameterName: string, value: string): void {
|
||||
if (parameterName === 'color') {
|
||||
this.fog.color = new THREE.Color(
|
||||
@@ -75,17 +67,6 @@ namespace gdjs {
|
||||
);
|
||||
}
|
||||
}
|
||||
updateColorParameter(parameterName: string, value: number): void {
|
||||
if (parameterName === 'color') {
|
||||
this.fog.color.setHex(value);
|
||||
}
|
||||
}
|
||||
getColorParameter(parameterName: string): number {
|
||||
if (parameterName === 'color') {
|
||||
return this.fog.color.getHex();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
updateBooleanParameter(parameterName: string, value: boolean): void {}
|
||||
})();
|
||||
}
|
||||
|
@@ -1,8 +1,6 @@
|
||||
namespace gdjs {
|
||||
type FloatPoint3D = [float, float, float];
|
||||
|
||||
const epsilon = 1 / (1 << 16);
|
||||
|
||||
const removeMetalness = (material: THREE.Material): void => {
|
||||
//@ts-ignore
|
||||
if (material.metalness) {
|
||||
@@ -11,7 +9,7 @@ namespace gdjs {
|
||||
}
|
||||
};
|
||||
|
||||
const removeMetalnessFromMesh = (node: THREE.Object3D) => {
|
||||
const removeMetalnessFromMesh = (node: THREE.Object3D<THREE.Event>) => {
|
||||
const mesh = node as THREE.Mesh;
|
||||
if (!mesh.material) {
|
||||
return;
|
||||
@@ -25,8 +23,9 @@ namespace gdjs {
|
||||
}
|
||||
};
|
||||
|
||||
const traverseToRemoveMetalnessFromMeshes = (node: THREE.Object3D) =>
|
||||
node.traverse(removeMetalnessFromMesh);
|
||||
const traverseToRemoveMetalnessFromMeshes = (
|
||||
node: THREE.Object3D<THREE.Event>
|
||||
) => node.traverse(removeMetalnessFromMesh);
|
||||
|
||||
const convertToBasicMaterial = (
|
||||
material: THREE.Material
|
||||
@@ -45,7 +44,7 @@ namespace gdjs {
|
||||
return basicMaterial;
|
||||
};
|
||||
|
||||
const setBasicMaterialTo = (node: THREE.Object3D): void => {
|
||||
const setBasicMaterialTo = (node: THREE.Object3D<THREE.Event>): void => {
|
||||
const mesh = node as THREE.Mesh;
|
||||
if (!mesh.material) {
|
||||
return;
|
||||
@@ -60,8 +59,9 @@ namespace gdjs {
|
||||
}
|
||||
};
|
||||
|
||||
const traverseToSetBasicMaterialFromMeshes = (node: THREE.Object3D) =>
|
||||
node.traverse(setBasicMaterialTo);
|
||||
const traverseToSetBasicMaterialFromMeshes = (
|
||||
node: THREE.Object3D<THREE.Event>
|
||||
) => node.traverse(setBasicMaterialTo);
|
||||
|
||||
class Model3DRuntimeObject3DRenderer extends gdjs.RuntimeObject3DRenderer {
|
||||
private _model3DRuntimeObject: gdjs.Model3DRuntimeObject;
|
||||
@@ -147,9 +147,6 @@ namespace gdjs {
|
||||
originalDepth: float,
|
||||
keepAspectRatio: boolean
|
||||
) {
|
||||
// These formulas are also used in:
|
||||
// - Model3DEditor.modelSize
|
||||
// - Model3DRendered2DInstance
|
||||
threeObject.rotation.set(
|
||||
gdjs.toRad(rotationX),
|
||||
gdjs.toRad(rotationY),
|
||||
@@ -158,24 +155,12 @@ namespace gdjs {
|
||||
threeObject.updateMatrixWorld(true);
|
||||
const boundingBox = new THREE.Box3().setFromObject(threeObject);
|
||||
|
||||
const shouldKeepModelOrigin = !this._model3DRuntimeObject._originPoint;
|
||||
if (shouldKeepModelOrigin) {
|
||||
// Keep the origin as part of the model.
|
||||
// For instance, a model can be 1 face of a cube and we want to keep the
|
||||
// inside as part of the object even if it's just void.
|
||||
// It also avoids to have the origin outside of the object box.
|
||||
boundingBox.expandByPoint(new THREE.Vector3(0, 0, 0));
|
||||
}
|
||||
|
||||
const modelWidth = boundingBox.max.x - boundingBox.min.x;
|
||||
const modelHeight = boundingBox.max.y - boundingBox.min.y;
|
||||
const modelDepth = boundingBox.max.z - boundingBox.min.z;
|
||||
this._modelOriginPoint[0] =
|
||||
modelWidth < epsilon ? 0 : -boundingBox.min.x / modelWidth;
|
||||
this._modelOriginPoint[1] =
|
||||
modelHeight < epsilon ? 0 : -boundingBox.min.y / modelHeight;
|
||||
this._modelOriginPoint[2] =
|
||||
modelDepth < epsilon ? 0 : -boundingBox.min.z / modelDepth;
|
||||
this._modelOriginPoint[0] = -boundingBox.min.x / modelWidth;
|
||||
this._modelOriginPoint[1] = -boundingBox.min.y / modelHeight;
|
||||
this._modelOriginPoint[2] = -boundingBox.min.z / modelDepth;
|
||||
|
||||
// The model is flipped on Y axis.
|
||||
this._modelOriginPoint[1] = 1 - this._modelOriginPoint[1];
|
||||
@@ -184,10 +169,19 @@ namespace gdjs {
|
||||
const centerPoint = this._model3DRuntimeObject._centerPoint;
|
||||
if (centerPoint) {
|
||||
threeObject.position.set(
|
||||
-(boundingBox.min.x + modelWidth * centerPoint[0]),
|
||||
-(
|
||||
boundingBox.min.x +
|
||||
(boundingBox.max.x - boundingBox.min.x) * centerPoint[0]
|
||||
),
|
||||
// The model is flipped on Y axis.
|
||||
-(boundingBox.min.y + modelHeight * (1 - centerPoint[1])),
|
||||
-(boundingBox.min.z + modelDepth * centerPoint[2])
|
||||
-(
|
||||
boundingBox.min.y +
|
||||
(boundingBox.max.y - boundingBox.min.y) * (1 - centerPoint[1])
|
||||
),
|
||||
-(
|
||||
boundingBox.min.z +
|
||||
(boundingBox.max.z - boundingBox.min.z) * centerPoint[2]
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -200,9 +194,9 @@ namespace gdjs {
|
||||
);
|
||||
|
||||
// Stretch the model in a 1x1x1 cube.
|
||||
const scaleX = modelWidth < epsilon ? 1 : 1 / modelWidth;
|
||||
const scaleY = modelHeight < epsilon ? 1 : 1 / modelHeight;
|
||||
const scaleZ = modelDepth < epsilon ? 1 : 1 / modelDepth;
|
||||
const scaleX = 1 / modelWidth;
|
||||
const scaleY = 1 / modelHeight;
|
||||
const scaleZ = 1 / modelDepth;
|
||||
|
||||
const scaleMatrix = new THREE.Matrix4();
|
||||
// Flip on Y because the Y axis is on the opposite side of direct basis.
|
||||
@@ -213,22 +207,10 @@ namespace gdjs {
|
||||
|
||||
if (keepAspectRatio) {
|
||||
// Reduce the object dimensions to keep aspect ratio.
|
||||
const widthRatio =
|
||||
modelWidth < epsilon
|
||||
? Number.POSITIVE_INFINITY
|
||||
: originalWidth / modelWidth;
|
||||
const heightRatio =
|
||||
modelHeight < epsilon
|
||||
? Number.POSITIVE_INFINITY
|
||||
: originalHeight / modelHeight;
|
||||
const depthRatio =
|
||||
modelDepth < epsilon
|
||||
? Number.POSITIVE_INFINITY
|
||||
: originalDepth / modelDepth;
|
||||
let scaleRatio = Math.min(widthRatio, heightRatio, depthRatio);
|
||||
if (!Number.isFinite(scaleRatio)) {
|
||||
scaleRatio = 1;
|
||||
}
|
||||
const widthRatio = originalWidth / modelWidth;
|
||||
const heightRatio = originalHeight / modelHeight;
|
||||
const depthRatio = originalDepth / modelDepth;
|
||||
const scaleRatio = Math.min(widthRatio, heightRatio, depthRatio);
|
||||
|
||||
this._object._setOriginalWidth(scaleRatio * modelWidth);
|
||||
this._object._setOriginalHeight(scaleRatio * modelHeight);
|
||||
|
@@ -11,11 +11,7 @@ namespace gdjs {
|
||||
const layer = runtimeScene.getLayer(layerName);
|
||||
const layerRenderer = layer.getRenderer();
|
||||
const threeCamera = layerRenderer.getThreeCamera();
|
||||
const fov = threeCamera
|
||||
? threeCamera instanceof THREE.OrthographicCamera
|
||||
? null
|
||||
: threeCamera.fov
|
||||
: assumedFovIn2D;
|
||||
const fov = threeCamera ? threeCamera.fov : assumedFovIn2D;
|
||||
return layer.getCameraZ(fov, cameraIndex);
|
||||
};
|
||||
|
||||
@@ -28,11 +24,7 @@ namespace gdjs {
|
||||
const layer = runtimeScene.getLayer(layerName);
|
||||
const layerRenderer = layer.getRenderer();
|
||||
const threeCamera = layerRenderer.getThreeCamera();
|
||||
const fov = threeCamera
|
||||
? threeCamera instanceof THREE.OrthographicCamera
|
||||
? null
|
||||
: threeCamera.fov
|
||||
: assumedFovIn2D;
|
||||
const fov = threeCamera ? threeCamera.fov : assumedFovIn2D;
|
||||
layer.setCameraZ(z, fov, cameraIndex);
|
||||
};
|
||||
|
||||
@@ -221,11 +213,8 @@ namespace gdjs {
|
||||
const layerRenderer = layer.getRenderer();
|
||||
|
||||
const threeCamera = layerRenderer.getThreeCamera();
|
||||
return threeCamera
|
||||
? threeCamera instanceof THREE.OrthographicCamera
|
||||
? 0
|
||||
: threeCamera.fov
|
||||
: assumedFovIn2D;
|
||||
if (!threeCamera) return 45;
|
||||
return threeCamera.fov;
|
||||
};
|
||||
|
||||
export const setFov = (
|
||||
@@ -238,8 +227,7 @@ namespace gdjs {
|
||||
const layerRenderer = layer.getRenderer();
|
||||
|
||||
const threeCamera = layerRenderer.getThreeCamera();
|
||||
if (!threeCamera || threeCamera instanceof THREE.OrthographicCamera)
|
||||
return;
|
||||
if (!threeCamera) return;
|
||||
|
||||
threeCamera.fov = Math.min(Math.max(angle, 0), 180);
|
||||
layerRenderer.setThreeCameraDirty(true);
|
||||
|
@@ -1,5 +1,4 @@
|
||||
//@ts-check
|
||||
/// <reference path="../JsExtensionTypes.d.ts" />
|
||||
// @flow
|
||||
/**
|
||||
* This is a declaration of an extension for GDevelop 5.
|
||||
*
|
||||
@@ -13,9 +12,18 @@
|
||||
* More information on https://github.com/4ian/GDevelop/blob/master/newIDE/README-extensions.md
|
||||
*/
|
||||
|
||||
/** @type {ExtensionModule} */
|
||||
/*::
|
||||
// Import types to allow Flow to do static type checking on this file.
|
||||
// Extensions declaration are typed using Flow (like the editor), but the files
|
||||
// for the game engine are checked with TypeScript annotations.
|
||||
import { type ObjectsRenderingService, type ObjectsEditorService } from '../JsExtensionTypes.flow.js'
|
||||
*/
|
||||
|
||||
module.exports = {
|
||||
createExtension: function (_, gd) {
|
||||
createExtension: function (
|
||||
_ /*: (string) => string */,
|
||||
gd /*: libGDevelop */
|
||||
) {
|
||||
const extension = new gd.PlatformExtension();
|
||||
extension
|
||||
.setExtensionInformation(
|
||||
@@ -781,7 +789,10 @@ module.exports = {
|
||||
|
||||
return extension;
|
||||
},
|
||||
runExtensionSanityTests: function (gd, extension) {
|
||||
runExtensionSanityTests: function (
|
||||
gd /*: libGDevelop */,
|
||||
extension /*: gdPlatformExtension*/
|
||||
) {
|
||||
return [];
|
||||
},
|
||||
};
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user