mirror of
https://github.com/4ian/GDevelop.git
synced 2025-10-15 10:19:04 +00:00
Compare commits
154 Commits
experiment
...
function-s
Author | SHA1 | Date | |
---|---|---|---|
![]() |
1e8debf722 | ||
![]() |
b66c2d5d6d | ||
![]() |
aedd6981a0 | ||
![]() |
862b2d637f | ||
![]() |
7405fb75d0 | ||
![]() |
5a9c35657a | ||
![]() |
64ad0931c4 | ||
![]() |
e237fc4b21 | ||
![]() |
18892f97f3 | ||
![]() |
0ec0654032 | ||
![]() |
8e29c723e8 | ||
![]() |
6acde2865a | ||
![]() |
49e176a98f | ||
![]() |
71c2a0be01 | ||
![]() |
4ad1a0dd68 | ||
![]() |
a556690307 | ||
![]() |
6950f323b3 | ||
![]() |
de129f6cc4 | ||
![]() |
b3b88a0445 | ||
![]() |
8e8f3a7d55 | ||
![]() |
cc6b4a283a | ||
![]() |
f393f36bad | ||
![]() |
5261f5a431 | ||
![]() |
1a6cf8d69a | ||
![]() |
e93b38fee4 | ||
![]() |
22c7215071 | ||
![]() |
a221990c57 | ||
![]() |
85f6e74a5c | ||
![]() |
6577432b27 | ||
![]() |
16d94b5e38 | ||
![]() |
88a2060364 | ||
![]() |
2d0ffee102 | ||
![]() |
aa30f3c465 | ||
![]() |
cfcb4b557f | ||
![]() |
d8db679a1d | ||
![]() |
01503d46c1 | ||
![]() |
02d44bbba4 | ||
![]() |
b6d8170a00 | ||
![]() |
554c4c8f58 | ||
![]() |
9e29146841 | ||
![]() |
189e971cd2 | ||
![]() |
deab962081 | ||
![]() |
e2281dfd82 | ||
![]() |
44daf709e4 | ||
![]() |
c9e5272367 | ||
![]() |
63584d171f | ||
![]() |
092efbe462 | ||
![]() |
fc86b4e2dd | ||
![]() |
3415626552 | ||
![]() |
fd2e87cc5c | ||
![]() |
ecc8c3176d | ||
![]() |
1c855226a8 | ||
![]() |
558d3a869c | ||
![]() |
c22f8afaf1 | ||
![]() |
7ece6c6759 | ||
![]() |
f1ac388c46 | ||
![]() |
8a0045b3b0 | ||
![]() |
4bcac31489 | ||
![]() |
ff1086ce3b | ||
![]() |
e5d77da357 | ||
![]() |
536b0d5c38 | ||
![]() |
ada7dba959 | ||
![]() |
1b0c088f71 | ||
![]() |
b9b09c1fef | ||
![]() |
066c8cd387 | ||
![]() |
a06ef20011 | ||
![]() |
2052db6a39 | ||
![]() |
35fd7e972b | ||
![]() |
d110e83f6f | ||
![]() |
13bdfa4379 | ||
![]() |
689bc014f3 | ||
![]() |
a4f7aa6c43 | ||
![]() |
39690d6a02 | ||
![]() |
3260b285af | ||
![]() |
8743f70aaf | ||
![]() |
eae75bdc72 | ||
![]() |
825cff7ba3 | ||
![]() |
aa12248d86 | ||
![]() |
d0f3abc38d | ||
![]() |
e111706a27 | ||
![]() |
e4f3db71c5 | ||
![]() |
08a7949056 | ||
![]() |
1912916778 | ||
![]() |
59685bc4c4 | ||
![]() |
717948c558 | ||
![]() |
a81c45f91a | ||
![]() |
76eaa747c9 | ||
![]() |
26c95d1745 | ||
![]() |
e0c72fd113 | ||
![]() |
2a6e98c27f | ||
![]() |
5f01ce8701 | ||
![]() |
6ed0e8e4cc | ||
![]() |
fbea483609 | ||
![]() |
90004e3f83 | ||
![]() |
e6343dfe18 | ||
![]() |
ac6b64ba9b | ||
![]() |
44b18cb111 | ||
![]() |
c5fc7e08f5 | ||
![]() |
9eada905f9 | ||
![]() |
13aab9a8e8 | ||
![]() |
dda85cf630 | ||
![]() |
0f81e4c088 | ||
![]() |
5419493349 | ||
![]() |
272766c705 | ||
![]() |
a06138b31e | ||
![]() |
74a7ba5a09 | ||
![]() |
3914d0377f | ||
![]() |
092b29fa0e | ||
![]() |
16762960dc | ||
![]() |
33101ead64 | ||
![]() |
de73d617b0 | ||
![]() |
446b0db05f | ||
![]() |
66ab7abab7 | ||
![]() |
a80b540f06 | ||
![]() |
38761aeec1 | ||
![]() |
602dc9d791 | ||
![]() |
162a70316a | ||
![]() |
10e8094375 | ||
![]() |
82af8dd7f3 | ||
![]() |
8cf739aa78 | ||
![]() |
f3f3d24706 | ||
![]() |
83f80b2350 | ||
![]() |
1172326ae0 | ||
![]() |
aed09d86b3 | ||
![]() |
c2d03050b8 | ||
![]() |
2e941c5afc | ||
![]() |
a3f80f2607 | ||
![]() |
3497eb2945 | ||
![]() |
b9a1f50d13 | ||
![]() |
52d239b60c | ||
![]() |
c549e277a7 | ||
![]() |
afed5d57f7 | ||
![]() |
a3f7176c42 | ||
![]() |
223268554b | ||
![]() |
43ef037a07 | ||
![]() |
20d2e06fc6 | ||
![]() |
9f795c405a | ||
![]() |
0155344ec3 | ||
![]() |
71d6d6a165 | ||
![]() |
edd14b5f8b | ||
![]() |
77d60b699b | ||
![]() |
5bc80537b7 | ||
![]() |
f93b850382 | ||
![]() |
da7cae08a1 | ||
![]() |
0ae68877b7 | ||
![]() |
32c4e040e0 | ||
![]() |
74034a0ac1 | ||
![]() |
1b41225822 | ||
![]() |
c620ed75b3 | ||
![]() |
edc577067b | ||
![]() |
e00a85909d | ||
![]() |
70e6fc7f7f | ||
![]() |
b9a899f82e | ||
![]() |
c38d14ca83 |
1
.gitattributes
vendored
1
.gitattributes
vendored
@@ -3,6 +3,7 @@ Extensions/ParticleSystem/SPARK/* linguist-vendored
|
||||
Extensions/PhysicsBehavior/Box2D/* linguist-vendored
|
||||
Extensions/PhysicsBehavior/box2djs/* linguist-vendored
|
||||
Extensions/Physics2Behavior/box2d.js linguist-vendored
|
||||
Extensions/Physics3DBehavior/*.wasm-compat.js linguist-vendored
|
||||
Extensions/BBText/pixi-multistyle-text/* linguist-vendored
|
||||
Extensions/P2P/A_peer.js linguist-vendored
|
||||
Extensions/Multiplayer/peer.js linguist-vendored
|
||||
|
22
.github/workflows/gdcore-tools-hook.yml
vendored
Normal file
22
.github/workflows/gdcore-tools-hook.yml
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
# This worflow notifies arthuro555's gdcore-tools repository when a new release is published.
|
||||
#
|
||||
# This is used to allow gdcore-tools, a library to use GDCore outside of GDevelop,
|
||||
# to attempt to automatically build, test, and publish a release for the new
|
||||
# GDevelop version.
|
||||
name: Trigger gdcore-tools pipeline
|
||||
|
||||
on:
|
||||
release:
|
||||
types: [published]
|
||||
|
||||
jobs:
|
||||
dispatch-event:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Repository Dispatch
|
||||
uses: peter-evans/repository-dispatch@v3
|
||||
with:
|
||||
token: ${{ secrets.GDCORE_TOOLS_PAT }}
|
||||
repository: arthuro555/gdcore-tools
|
||||
event-type: gdevelop-release
|
||||
client-payload: '{"release": ${{ toJson(github.event.release) }}}'
|
@@ -18,8 +18,6 @@ namespace gd {
|
||||
|
||||
EventsList BaseEvent::badSubEvents;
|
||||
VariablesContainer BaseEvent::badLocalVariables;
|
||||
std::vector<gd::String> BaseEvent::emptyDependencies;
|
||||
gd::String BaseEvent::emptySourceFile;
|
||||
|
||||
BaseEvent::BaseEvent()
|
||||
: totalTimeDuringLastSession(0),
|
||||
|
@@ -175,26 +175,6 @@ class GD_CORE_API BaseEvent {
|
||||
noExpr;
|
||||
return noExpr;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Returns the dependencies on source files of the project.
|
||||
* \note Default implementation returns an empty list of dependencies. This is
|
||||
* fine for most events that are not related to adding custom user source
|
||||
* code.
|
||||
*/
|
||||
virtual const std::vector<gd::String>& GetSourceFileDependencies() const {
|
||||
return emptyDependencies;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Returns the name of the source file associated with the event
|
||||
* \note Default implementation returns an empty string. This is fine for most
|
||||
* events that are not related to adding custom user source code.
|
||||
*/
|
||||
virtual const gd::String& GetAssociatedGDManagedSourceFile(
|
||||
gd::Project& project) const {
|
||||
return emptySourceFile;
|
||||
};
|
||||
///@}
|
||||
|
||||
/** \name Code generation
|
||||
@@ -327,8 +307,6 @@ class GD_CORE_API BaseEvent {
|
||||
|
||||
static gd::EventsList badSubEvents;
|
||||
static gd::VariablesContainer badLocalVariables;
|
||||
static std::vector<gd::String> emptyDependencies;
|
||||
static gd::String emptySourceFile;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@@ -272,7 +272,7 @@ class GD_CORE_API BehaviorMetadata : public InstructionOrExpressionContainerMeta
|
||||
* Check if the behavior is private - it can't be used outside of its
|
||||
* extension.
|
||||
*/
|
||||
bool IsPrivate() const { return isPrivate; }
|
||||
bool IsPrivate() const override { return isPrivate; }
|
||||
|
||||
/**
|
||||
* Set that the behavior is private - it can't be used outside of its
|
||||
|
@@ -174,6 +174,7 @@ public:
|
||||
virtual const gd::String &GetFullName() const = 0;
|
||||
virtual const gd::String &GetDescription() const = 0;
|
||||
virtual const gd::String &GetIconFilename() const = 0;
|
||||
virtual bool IsPrivate() const = 0;
|
||||
|
||||
/**
|
||||
* \brief Return a reference to a map containing the names of the actions
|
||||
|
@@ -54,7 +54,7 @@ ObjectMetadata::ObjectMetadata(const gd::String& extensionNamespace_,
|
||||
[]() -> std::unique_ptr<gd::ObjectConfiguration> {
|
||||
gd::LogFatalError(
|
||||
"Error: Event-based objects don't have blueprint. "
|
||||
"This method should not never be called.");
|
||||
"This method should never be called.");
|
||||
return nullptr;
|
||||
}) {}
|
||||
|
||||
|
@@ -246,6 +246,11 @@ class GD_CORE_API ObjectMetadata : public InstructionOrExpressionContainerMetada
|
||||
return *this;
|
||||
}
|
||||
|
||||
ObjectMetadata& ResetDefaultBehaviorsJustForTesting() {
|
||||
defaultBehaviorTypes.clear();
|
||||
return *this;
|
||||
}
|
||||
|
||||
const gd::String& GetName() const override { return name; }
|
||||
const gd::String& GetFullName() const override { return fullname; }
|
||||
const gd::String& GetCategoryFullName() const { return categoryFullName; }
|
||||
@@ -295,6 +300,22 @@ class GD_CORE_API ObjectMetadata : public InstructionOrExpressionContainerMetada
|
||||
*/
|
||||
std::map<gd::String, gd::ExpressionMetadata>& GetAllStrExpressions() override { return strExpressionsInfos; };
|
||||
|
||||
|
||||
/**
|
||||
* Check if the behavior is private - it can't be used outside of its
|
||||
* extension.
|
||||
*/
|
||||
bool IsPrivate() const override { return isPrivate; }
|
||||
|
||||
/**
|
||||
* Set that the behavior is private - it can't be used outside of its
|
||||
* extension.
|
||||
*/
|
||||
ObjectMetadata &SetPrivate() {
|
||||
isPrivate = true;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Set the object to be hidden in the IDE.
|
||||
*
|
||||
@@ -351,6 +372,7 @@ class GD_CORE_API ObjectMetadata : public InstructionOrExpressionContainerMetada
|
||||
gd::String iconFilename;
|
||||
gd::String categoryFullName;
|
||||
std::set<gd::String> defaultBehaviorTypes;
|
||||
bool isPrivate = false;
|
||||
bool hidden = false;
|
||||
bool isRenderedIn3D = false;
|
||||
gd::String openFullEditorLabel;
|
||||
|
@@ -6,6 +6,8 @@
|
||||
#include "ParameterMetadataTools.h"
|
||||
|
||||
#include "GDCore/Events/Expression.h"
|
||||
#include "GDCore/Events/Parsers/ExpressionParser2.h"
|
||||
#include "GDCore/Events/Parsers/ExpressionParser2NodePrinter.h"
|
||||
#include "GDCore/Project/Object.h"
|
||||
#include "GDCore/Project/ObjectsContainer.h"
|
||||
#include "GDCore/Project/ObjectsContainersList.h"
|
||||
@@ -13,8 +15,6 @@
|
||||
#include "GDCore/Project/Project.h"
|
||||
#include "GDCore/String.h"
|
||||
#include "InstructionMetadata.h"
|
||||
#include "GDCore/Events/Parsers/ExpressionParser2.h"
|
||||
#include "GDCore/Events/Parsers/ExpressionParser2NodePrinter.h"
|
||||
|
||||
namespace gd {
|
||||
const ParameterMetadata ParameterMetadataTools::badParameterMetadata;
|
||||
@@ -23,7 +23,10 @@ void ParameterMetadataTools::ParametersToObjectsContainer(
|
||||
const gd::Project& project,
|
||||
const ParameterMetadataContainer& parameters,
|
||||
gd::ObjectsContainer& outputObjectsContainer) {
|
||||
outputObjectsContainer.GetObjects().clear();
|
||||
// Keep track of all objects and their behaviors names, so we can remove
|
||||
// those who are in the container but not in the parameters anymore.
|
||||
std::set<gd::String> allObjectNames;
|
||||
std::map<gd::String, std::set<gd::String>> allObjectNonDefaultBehaviorNames;
|
||||
|
||||
gd::String lastObjectName;
|
||||
for (std::size_t i = 0; i < parameters.GetParametersCount(); ++i) {
|
||||
@@ -31,34 +34,97 @@ void ParameterMetadataTools::ParametersToObjectsContainer(
|
||||
if (parameter.GetName().empty()) continue;
|
||||
|
||||
if (gd::ParameterMetadata::IsObject(parameter.GetType())) {
|
||||
outputObjectsContainer.InsertNewObject(
|
||||
project,
|
||||
parameter.GetExtraInfo(),
|
||||
parameter.GetName(),
|
||||
outputObjectsContainer.GetObjectsCount());
|
||||
const gd::String& objectName = parameter.GetName();
|
||||
const gd::String& objectType = parameter.GetExtraInfo();
|
||||
allObjectNames.insert(objectName);
|
||||
|
||||
// Check if we can keep the existing object.
|
||||
if (outputObjectsContainer.HasObjectNamed(objectName)) {
|
||||
const gd::Object& object = outputObjectsContainer.GetObject(objectName);
|
||||
|
||||
if (object.GetType() != objectType) {
|
||||
// Object type has changed, remove it so it is re-created.
|
||||
outputObjectsContainer.RemoveObject(objectName);
|
||||
}
|
||||
}
|
||||
|
||||
if (outputObjectsContainer.HasObjectNamed(objectName)) {
|
||||
// Keep the existing object, ensure the default behaviors
|
||||
// are all present (and no more than required by the object type).
|
||||
// Non default behaviors coming from parameters will be added or removed later.
|
||||
project.EnsureObjectDefaultBehaviors(outputObjectsContainer.GetObject(objectName));
|
||||
} else {
|
||||
// Create a new object (and its default behaviors) if needed.
|
||||
outputObjectsContainer.InsertNewObject(
|
||||
project,
|
||||
objectType,
|
||||
objectName,
|
||||
outputObjectsContainer.GetObjectsCount());
|
||||
}
|
||||
|
||||
// Memorize the last object name. By convention, parameters that require
|
||||
// an object (mainly, "objectvar" and "behavior") should be placed after
|
||||
// the object in the list of parameters (if possible, just after).
|
||||
// Search "lastObjectName" in the codebase for other place where this
|
||||
// convention is enforced.
|
||||
lastObjectName = parameter.GetName();
|
||||
lastObjectName = objectName;
|
||||
} else if (gd::ParameterMetadata::IsBehavior(parameter.GetType())) {
|
||||
if (!lastObjectName.empty()) {
|
||||
if (outputObjectsContainer.HasObjectNamed(lastObjectName)) {
|
||||
const gd::Object& object =
|
||||
outputObjectsContainer.GetObject(lastObjectName);
|
||||
gd::String behaviorName = parameter.GetName();
|
||||
const gd::String& behaviorName = parameter.GetName();
|
||||
const gd::String& behaviorType = parameter.GetExtraInfo();
|
||||
|
||||
gd::Object& object = outputObjectsContainer.GetObject(lastObjectName);
|
||||
allObjectNonDefaultBehaviorNames[lastObjectName].insert(behaviorName);
|
||||
|
||||
// Check if we can keep the existing behavior.
|
||||
if (object.HasBehaviorNamed(behaviorName)) {
|
||||
if (object.GetBehavior(behaviorName).GetTypeName() !=
|
||||
behaviorType) {
|
||||
// Behavior type has changed, remove it so it is re-created.
|
||||
object.RemoveBehavior(behaviorName);
|
||||
}
|
||||
}
|
||||
|
||||
if (!object.HasBehaviorNamed(behaviorName)) {
|
||||
outputObjectsContainer.GetObject(lastObjectName)
|
||||
.AddNewBehavior(
|
||||
project, parameter.GetExtraInfo(), behaviorName);
|
||||
object.AddNewBehavior(
|
||||
project, parameter.GetExtraInfo(), behaviorName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Remove objects that are not in the parameters anymore.
|
||||
std::set<gd::String> objectNamesInContainer =
|
||||
outputObjectsContainer.GetAllObjectNames();
|
||||
for (const auto& objectName : objectNamesInContainer) {
|
||||
if (allObjectNames.find(objectName) == allObjectNames.end()) {
|
||||
outputObjectsContainer.RemoveObject(objectName);
|
||||
}
|
||||
}
|
||||
|
||||
// Remove behaviors of objects that are not in the parameters anymore.
|
||||
for (const auto& objectName : allObjectNames) {
|
||||
if (!outputObjectsContainer.HasObjectNamed(objectName)) {
|
||||
// Should not happen.
|
||||
continue;
|
||||
}
|
||||
|
||||
auto& object = outputObjectsContainer.GetObject(objectName);
|
||||
const auto& allBehaviorNames = allObjectNonDefaultBehaviorNames[objectName];
|
||||
for (const auto& behaviorName : object.GetAllBehaviorNames()) {
|
||||
if (object.GetBehavior(behaviorName).IsDefaultBehavior()) {
|
||||
// Default behaviors are already ensured to be all present
|
||||
// (and no more than required by the object type).
|
||||
continue;
|
||||
}
|
||||
|
||||
if (allBehaviorNames.find(behaviorName) == allBehaviorNames.end()) {
|
||||
object.RemoveBehavior(behaviorName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ParameterMetadataTools::ForEachParameterMatchingSearch(
|
||||
|
56
Core/GDCore/Extensions/Metadata/SourceFileMetadata.h
Normal file
56
Core/GDCore/Extensions/Metadata/SourceFileMetadata.h
Normal file
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* GDevelop Core
|
||||
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#pragma once
|
||||
#include "GDCore/String.h"
|
||||
#include "GDCore/Serialization/SerializerElement.h"
|
||||
|
||||
namespace gd {
|
||||
/**
|
||||
* \brief Contains information about a source file that must be included
|
||||
* when an extension is used.
|
||||
*/
|
||||
class GD_CORE_API SourceFileMetadata {
|
||||
public:
|
||||
/**
|
||||
* Construct a new dependency metadata, though you probably want to call
|
||||
* `AddSourceFile` on gd::PlatformExtension.
|
||||
*
|
||||
* \see gd::PlatformExtension
|
||||
*/
|
||||
SourceFileMetadata() {};
|
||||
|
||||
SourceFileMetadata& SetResourceName(const gd::String& resourceName_) {
|
||||
resourceName = resourceName_;
|
||||
return *this;
|
||||
};
|
||||
|
||||
SourceFileMetadata& SetIncludePosition(const gd::String& includePosition_) {
|
||||
includePosition = includePosition_;
|
||||
return *this;
|
||||
};
|
||||
|
||||
const gd::String& GetResourceName() const { return resourceName; };
|
||||
|
||||
gd::String& GetResourceName() { return resourceName; };
|
||||
|
||||
const gd::String& GetIncludePosition() const { return includePosition; };
|
||||
|
||||
void SerializeTo(SerializerElement& element) const {
|
||||
element.AddChild("resourceName").SetStringValue(resourceName);
|
||||
element.AddChild("includePosition").SetStringValue(includePosition);
|
||||
}
|
||||
|
||||
void UnserializeFrom(const SerializerElement& element) {
|
||||
resourceName = element.GetStringAttribute("resourceName");
|
||||
includePosition = element.GetStringAttribute("includePosition", "last");
|
||||
}
|
||||
|
||||
private:
|
||||
gd::String resourceName; ///< The name of the resource in the project.
|
||||
gd::String includePosition = "last"; ///< "first" or "last".
|
||||
};
|
||||
|
||||
} // namespace gd
|
@@ -135,7 +135,17 @@ class GD_CORE_API ValueTypeMetadata {
|
||||
* and ExpressionAutocompletion) and in the EventsCodeGenerator.
|
||||
*/
|
||||
bool IsVariable() const {
|
||||
return gd::ValueTypeMetadata::GetPrimitiveValueType(name) == "variable";
|
||||
return gd::ValueTypeMetadata::IsVariable(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Return true if the type of the parameter is a variable.
|
||||
* \note If you had a new type of parameter, also add it in the IDE (
|
||||
* see EventsFunctionParametersEditor, ParameterRenderingService
|
||||
* and ExpressionAutocompletion) and in the EventsCodeGenerator.
|
||||
*/
|
||||
static bool IsVariable(const gd::String &type) {
|
||||
return gd::ValueTypeMetadata::GetPrimitiveValueType(type) == "variable";
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -215,6 +215,11 @@ gd::DependencyMetadata& PlatformExtension::AddDependency() {
|
||||
return extensionDependenciesMetadata.back();
|
||||
}
|
||||
|
||||
gd::SourceFileMetadata& PlatformExtension::AddSourceFile() {
|
||||
extensionSourceFilesMetadata.push_back(SourceFileMetadata());
|
||||
return extensionSourceFilesMetadata.back();
|
||||
}
|
||||
|
||||
gd::ObjectMetadata& PlatformExtension::AddObject(
|
||||
const gd::String& name,
|
||||
const gd::String& fullname,
|
||||
@@ -463,10 +468,22 @@ PlatformExtension::GetAllStrExpressions() {
|
||||
return strExpressionsInfos;
|
||||
}
|
||||
|
||||
const std::vector<gd::DependencyMetadata>& PlatformExtension::GetAllDependencies() const {
|
||||
return extensionDependenciesMetadata;
|
||||
}
|
||||
|
||||
std::vector<gd::DependencyMetadata>& PlatformExtension::GetAllDependencies() {
|
||||
return extensionDependenciesMetadata;
|
||||
}
|
||||
|
||||
const std::vector<gd::SourceFileMetadata>& PlatformExtension::GetAllSourceFiles() const {
|
||||
return extensionSourceFilesMetadata;
|
||||
}
|
||||
|
||||
std::vector<gd::SourceFileMetadata>& PlatformExtension::GetAllSourceFiles() {
|
||||
return extensionSourceFilesMetadata;
|
||||
}
|
||||
|
||||
std::map<gd::String, gd::EventMetadata>& PlatformExtension::GetAllEvents() {
|
||||
return eventsInfos;
|
||||
}
|
||||
|
@@ -13,6 +13,7 @@
|
||||
#include "GDCore/CommonTools.h"
|
||||
#include "GDCore/Extensions/Metadata/BehaviorMetadata.h"
|
||||
#include "GDCore/Extensions/Metadata/DependencyMetadata.h"
|
||||
#include "GDCore/Extensions/Metadata/SourceFileMetadata.h"
|
||||
#include "GDCore/Extensions/Metadata/EffectMetadata.h"
|
||||
#include "GDCore/Extensions/Metadata/EventMetadata.h"
|
||||
#include "GDCore/Extensions/Metadata/InstructionOrExpressionGroupMetadata.h"
|
||||
@@ -214,6 +215,7 @@ class GD_CORE_API PlatformExtension {
|
||||
const gd::String& icon);
|
||||
|
||||
gd::DependencyMetadata& AddDependency();
|
||||
gd::SourceFileMetadata& AddSourceFile();
|
||||
|
||||
/**
|
||||
* \brief Declare a new object as being part of the extension.
|
||||
@@ -552,6 +554,24 @@ class GD_CORE_API PlatformExtension {
|
||||
*/
|
||||
std::vector<gd::DependencyMetadata>& GetAllDependencies();
|
||||
|
||||
/**
|
||||
* \brief Return a reference to a vector containing the metadata of all the
|
||||
* dependencies of the extension.
|
||||
*/
|
||||
const std::vector<gd::DependencyMetadata>& GetAllDependencies() const;
|
||||
|
||||
/**
|
||||
* \brief Return a reference to a vector containing the metadata of all the
|
||||
* dependencies of the extension.
|
||||
*/
|
||||
std::vector<gd::SourceFileMetadata>& GetAllSourceFiles();
|
||||
|
||||
/**
|
||||
* \brief Return a reference to a vector containing the metadata of all the
|
||||
* dependencies of the extension.
|
||||
*/
|
||||
const std::vector<gd::SourceFileMetadata>& GetAllSourceFiles() const;
|
||||
|
||||
/**
|
||||
* \brief Return a reference to a map containing the names of the actions,
|
||||
* related to the object type, and the metadata associated with.
|
||||
@@ -687,6 +707,7 @@ class GD_CORE_API PlatformExtension {
|
||||
std::map<gd::String, gd::ExpressionMetadata> expressionsInfos;
|
||||
std::map<gd::String, gd::ExpressionMetadata> strExpressionsInfos;
|
||||
std::vector<gd::DependencyMetadata> extensionDependenciesMetadata;
|
||||
std::vector<gd::SourceFileMetadata> extensionSourceFilesMetadata;
|
||||
std::map<gd::String, gd::EventMetadata> eventsInfos;
|
||||
std::map<gd::String, gd::PropertyDescriptor> extensionPropertiesMetadata;
|
||||
std::map<gd::String, InstructionOrExpressionGroupMetadata>
|
||||
|
18
Core/GDCore/IDE/CaptureOptions.cpp
Normal file
18
Core/GDCore/IDE/CaptureOptions.cpp
Normal file
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
* GDevelop Core
|
||||
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#include "GDCore/IDE/CaptureOptions.h"
|
||||
|
||||
#include "GDCore/String.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace gd {
|
||||
|
||||
Screenshot::Screenshot() {}
|
||||
|
||||
CaptureOptions::CaptureOptions() {}
|
||||
|
||||
} // namespace gd
|
50
Core/GDCore/IDE/CaptureOptions.h
Normal file
50
Core/GDCore/IDE/CaptureOptions.h
Normal file
@@ -0,0 +1,50 @@
|
||||
#pragma once
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "GDCore/String.h"
|
||||
|
||||
namespace gd {
|
||||
|
||||
class GD_CORE_API Screenshot {
|
||||
public:
|
||||
Screenshot();
|
||||
virtual ~Screenshot() {};
|
||||
|
||||
void SetDelayTimeInSeconds(int delayTimeInMs_) {
|
||||
delayTimeInMs = delayTimeInMs_;
|
||||
}
|
||||
int GetDelayTimeInSeconds() const { return delayTimeInMs; }
|
||||
|
||||
void SetSignedUrl(const gd::String& signedUrl_) { signedUrl = signedUrl_; }
|
||||
const gd::String& GetSignedUrl() const { return signedUrl; }
|
||||
|
||||
void SetPublicUrl(const gd::String& publicUrl_) { publicUrl = publicUrl_; }
|
||||
const gd::String& GetPublicUrl() const { return publicUrl; }
|
||||
|
||||
private:
|
||||
int delayTimeInMs = 0;
|
||||
gd::String signedUrl;
|
||||
gd::String publicUrl;
|
||||
};
|
||||
|
||||
class GD_CORE_API CaptureOptions {
|
||||
public:
|
||||
CaptureOptions();
|
||||
virtual ~CaptureOptions() {};
|
||||
|
||||
bool IsEmpty() const { return screenshots.empty(); }
|
||||
|
||||
void AddScreenshot(const Screenshot& screenshot) {
|
||||
screenshots.push_back(screenshot);
|
||||
}
|
||||
|
||||
const std::vector<Screenshot>& GetScreenshots() const { return screenshots; }
|
||||
|
||||
void ClearScreenshots() { screenshots.clear(); }
|
||||
|
||||
private:
|
||||
std::vector<Screenshot> screenshots;
|
||||
};
|
||||
|
||||
} // namespace gd
|
@@ -12,7 +12,6 @@
|
||||
#include "GDCore/Project/ExternalEvents.h"
|
||||
#include "GDCore/Project/Layout.h"
|
||||
#include "GDCore/Project/Project.h"
|
||||
#include "GDCore/Project/SourceFile.h"
|
||||
|
||||
DependenciesAnalyzer::DependenciesAnalyzer(const gd::Project& project_,
|
||||
const gd::Layout& layout_)
|
||||
@@ -74,16 +73,6 @@ bool DependenciesAnalyzer::Analyze(const gd::EventsList& events) {
|
||||
}
|
||||
}
|
||||
|
||||
// Search for source files dependencies
|
||||
std::vector<gd::String> dependencies =
|
||||
events[i].GetSourceFileDependencies();
|
||||
sourceFilesDependencies.insert(dependencies.begin(), dependencies.end());
|
||||
|
||||
const gd::String& associatedSourceFile =
|
||||
events[i].GetAssociatedGDManagedSourceFile(const_cast<gd::Project&>(project));
|
||||
if (!associatedSourceFile.empty())
|
||||
sourceFilesDependencies.insert(associatedSourceFile);
|
||||
|
||||
// Analyze sub events dependencies
|
||||
if (events[i].CanHaveSubEvents()) {
|
||||
if (!Analyze(events[i].GetSubEvents())) return false;
|
||||
|
@@ -71,14 +71,6 @@ class GD_CORE_API DependenciesAnalyzer {
|
||||
return externalEventsDependencies;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Return the source files being dependencies of the scene or external
|
||||
* events passed in the constructor.
|
||||
*/
|
||||
const std::set<gd::String>& GetSourceFilesDependencies() const {
|
||||
return sourceFilesDependencies;
|
||||
};
|
||||
|
||||
private:
|
||||
/**
|
||||
* \brief Analyze the dependencies of the events.
|
||||
@@ -92,7 +84,6 @@ class GD_CORE_API DependenciesAnalyzer {
|
||||
|
||||
std::set<gd::String> scenesDependencies;
|
||||
std::set<gd::String> externalEventsDependencies;
|
||||
std::set<gd::String> sourceFilesDependencies;
|
||||
std::vector<gd::String>
|
||||
parentScenes; ///< Used to check for circular dependencies.
|
||||
std::vector<gd::String>
|
||||
|
@@ -1,51 +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 "GDCore/IDE/Events/EventsLeaderboardsLister.h"
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "GDCore/Events/Event.h"
|
||||
#include "GDCore/Events/EventsList.h"
|
||||
#include "GDCore/Extensions/Metadata/InstructionMetadata.h"
|
||||
#include "GDCore/Extensions/Metadata/MetadataProvider.h"
|
||||
#include "GDCore/Project/Layout.h"
|
||||
#include "GDCore/Project/Project.h"
|
||||
#include "GDCore/String.h"
|
||||
|
||||
namespace gd {
|
||||
|
||||
bool EventsLeaderboardsLister::DoVisitInstruction(gd::Instruction& instruction,
|
||||
bool isCondition) {
|
||||
const gd::InstructionMetadata& instrInfo =
|
||||
isCondition ? MetadataProvider::GetConditionMetadata(
|
||||
project.GetCurrentPlatform(), instruction.GetType())
|
||||
: MetadataProvider::GetActionMetadata(
|
||||
project.GetCurrentPlatform(), instruction.GetType());
|
||||
|
||||
for (int i = 0; i < instruction.GetParametersCount() &&
|
||||
i < instrInfo.GetParametersCount();
|
||||
++i) {
|
||||
if (instrInfo.GetParameter(i).GetType() != "leaderboardId") {
|
||||
continue;
|
||||
}
|
||||
const gd::String leaderboardIdExpression =
|
||||
instruction.GetParameter(i).GetPlainString();
|
||||
if (leaderboardIdExpression[0] != '"' ||
|
||||
leaderboardIdExpression[leaderboardIdExpression.size() - 1] != '"') {
|
||||
continue;
|
||||
}
|
||||
const gd::String leaderboardId =
|
||||
leaderboardIdExpression.substr(1, leaderboardIdExpression.size() - 2);
|
||||
leaderboardIds.insert(leaderboardId);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
EventsLeaderboardsLister::~EventsLeaderboardsLister() {}
|
||||
|
||||
} // namespace gd
|
@@ -1,48 +0,0 @@
|
||||
/*
|
||||
* GDevelop Core
|
||||
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#ifndef EventsLeaderboardsLister_H
|
||||
#define EventsLeaderboardsLister_H
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
|
||||
#include "GDCore/IDE/Events/ArbitraryEventsWorker.h"
|
||||
#include "GDCore/String.h"
|
||||
namespace gd {
|
||||
class BaseEvent;
|
||||
class Project;
|
||||
class EventsList;
|
||||
}
|
||||
|
||||
namespace gd {
|
||||
|
||||
/**
|
||||
* \brief List the leaderboard ids in the instructions.
|
||||
*
|
||||
* \ingroup IDE
|
||||
*/
|
||||
class GD_CORE_API EventsLeaderboardsLister : public ArbitraryEventsWorker {
|
||||
public:
|
||||
EventsLeaderboardsLister(gd::Project& project_) : project(project_){};
|
||||
virtual ~EventsLeaderboardsLister();
|
||||
|
||||
/**
|
||||
* Return the values of all leaderboardIds found in the events.
|
||||
*/
|
||||
const std::set<gd::String>& GetLeaderboardIds() { return leaderboardIds; }
|
||||
|
||||
private:
|
||||
virtual bool DoVisitInstruction(gd::Instruction& instruction,
|
||||
bool isCondition);
|
||||
|
||||
std::set<gd::String> leaderboardIds;
|
||||
gd::Project& project;
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
|
||||
#endif // EventsLeaderboardsLister_H
|
@@ -1,57 +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 "GDCore/IDE/Events/EventsLeaderboardsRenamer.h"
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "GDCore/Events/Event.h"
|
||||
#include "GDCore/Events/EventsList.h"
|
||||
#include "GDCore/Extensions/Metadata/InstructionMetadata.h"
|
||||
#include "GDCore/Extensions/Metadata/MetadataProvider.h"
|
||||
#include "GDCore/Project/Layout.h"
|
||||
#include "GDCore/Project/Project.h"
|
||||
#include "GDCore/String.h"
|
||||
|
||||
namespace gd {
|
||||
|
||||
bool EventsLeaderboardsRenamer::DoVisitInstruction(gd::Instruction &instruction,
|
||||
bool isCondition) {
|
||||
const gd::InstructionMetadata &instrInfo =
|
||||
isCondition
|
||||
? MetadataProvider::GetConditionMetadata(project.GetCurrentPlatform(),
|
||||
instruction.GetType())
|
||||
: MetadataProvider::GetActionMetadata(project.GetCurrentPlatform(),
|
||||
instruction.GetType());
|
||||
|
||||
for (int i = 0; i < instruction.GetParametersCount() &&
|
||||
i < instrInfo.GetParametersCount();
|
||||
++i) {
|
||||
const gd::ParameterMetadata parameter = instrInfo.GetParameter(i);
|
||||
|
||||
if (parameter.GetType() != "leaderboardId") {
|
||||
continue;
|
||||
}
|
||||
const gd::String leaderboardIdExpression =
|
||||
instruction.GetParameter(i).GetPlainString();
|
||||
if (leaderboardIdExpression[0] != '"' ||
|
||||
leaderboardIdExpression[leaderboardIdExpression.size() - 1] != '"') {
|
||||
continue;
|
||||
}
|
||||
const gd::String leaderboardId =
|
||||
leaderboardIdExpression.substr(1, leaderboardIdExpression.size() - 2);
|
||||
if (leaderboardIdMap.find(leaderboardId) != leaderboardIdMap.end()) {
|
||||
instruction.SetParameter(i,
|
||||
"\"" + leaderboardIdMap[leaderboardId] + "\"");
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
EventsLeaderboardsRenamer::~EventsLeaderboardsRenamer() {}
|
||||
|
||||
} // namespace gd
|
@@ -1,44 +0,0 @@
|
||||
/*
|
||||
* GDevelop Core
|
||||
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
|
||||
#include "GDCore/IDE/Events/ArbitraryEventsWorker.h"
|
||||
#include "GDCore/String.h"
|
||||
namespace gd {
|
||||
class BaseEvent;
|
||||
class Project;
|
||||
class EventsList;
|
||||
}
|
||||
|
||||
namespace gd {
|
||||
|
||||
/**
|
||||
* \brief Replace the leaderboard ids in the instructions.
|
||||
*
|
||||
* \ingroup IDE
|
||||
*/
|
||||
class GD_CORE_API EventsLeaderboardsRenamer : public ArbitraryEventsWorker {
|
||||
public:
|
||||
EventsLeaderboardsRenamer(
|
||||
gd::Project& project_,
|
||||
const std::map<gd::String, gd::String>& leaderboardIdMap_)
|
||||
: project(project_), leaderboardIdMap(leaderboardIdMap_){};
|
||||
virtual ~EventsLeaderboardsRenamer();
|
||||
|
||||
private:
|
||||
virtual bool DoVisitInstruction(gd::Instruction& instruction,
|
||||
bool isCondition);
|
||||
|
||||
std::map<gd::String, gd::String> leaderboardIdMap;
|
||||
gd::Project& project;
|
||||
};
|
||||
|
||||
} // namespace gd
|
243
Core/GDCore/IDE/Events/EventsParameterReplacer.cpp
Normal file
243
Core/GDCore/IDE/Events/EventsParameterReplacer.cpp
Normal file
@@ -0,0 +1,243 @@
|
||||
/*
|
||||
* GDevelop Core
|
||||
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#include "GDCore/IDE/Events/EventsParameterReplacer.h"
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
#include "GDCore/Events/Event.h"
|
||||
#include "GDCore/Events/EventsList.h"
|
||||
#include "GDCore/Events/Parsers/ExpressionParser2NodePrinter.h"
|
||||
#include "GDCore/Events/Parsers/ExpressionParser2NodeWorker.h"
|
||||
#include "GDCore/Extensions/Metadata/MetadataProvider.h"
|
||||
#include "GDCore/Extensions/Metadata/ParameterMetadata.h"
|
||||
#include "GDCore/Extensions/Metadata/ParameterMetadataTools.h"
|
||||
#include "GDCore/IDE/Events/ExpressionValidator.h"
|
||||
#include "GDCore/Project/Layout.h"
|
||||
#include "GDCore/Project/Project.h"
|
||||
#include "GDCore/Project/ProjectScopedContainers.h"
|
||||
#include "GDCore/Project/PropertiesContainer.h"
|
||||
#include "GDCore/String.h"
|
||||
#include "GDCore/Tools/Log.h"
|
||||
|
||||
namespace gd {
|
||||
|
||||
/**
|
||||
* \brief Go through the nodes and rename parameters.
|
||||
*
|
||||
* \see gd::ExpressionParser2
|
||||
*/
|
||||
class GD_CORE_API ExpressionParameterReplacer
|
||||
: public ExpressionParser2NodeWorker {
|
||||
public:
|
||||
ExpressionParameterReplacer(
|
||||
const gd::Platform& platform_,
|
||||
const gd::ProjectScopedContainers& projectScopedContainers_,
|
||||
bool isParentTypeAVariable_,
|
||||
const std::unordered_map<gd::String, gd::String>& oldToNewPropertyNames_)
|
||||
: hasDoneRenaming(false),
|
||||
platform(platform_),
|
||||
projectScopedContainers(projectScopedContainers_),
|
||||
isParentTypeAVariable(isParentTypeAVariable_),
|
||||
oldToNewPropertyNames(oldToNewPropertyNames_){};
|
||||
virtual ~ExpressionParameterReplacer(){};
|
||||
|
||||
bool HasDoneRenaming() const { return hasDoneRenaming; }
|
||||
|
||||
protected:
|
||||
void OnVisitSubExpressionNode(SubExpressionNode& node) override {
|
||||
node.expression->Visit(*this);
|
||||
}
|
||||
void OnVisitOperatorNode(OperatorNode& node) override {
|
||||
node.leftHandSide->Visit(*this);
|
||||
node.rightHandSide->Visit(*this);
|
||||
}
|
||||
void OnVisitUnaryOperatorNode(UnaryOperatorNode& node) override {
|
||||
node.factor->Visit(*this);
|
||||
}
|
||||
void OnVisitNumberNode(NumberNode& node) override {}
|
||||
void OnVisitTextNode(TextNode& node) override {}
|
||||
void OnVisitVariableNode(VariableNode& node) override {
|
||||
if (isParentTypeAVariable) {
|
||||
// Do nothing, it's a variable.
|
||||
if (node.child) node.child->Visit(*this);
|
||||
return;
|
||||
}
|
||||
|
||||
// The node represents a variable or an object name on which a variable
|
||||
// will be accessed, or a property with a child.
|
||||
|
||||
projectScopedContainers.MatchIdentifierWithName<void>(
|
||||
// The property name is changed after the refactor operation.
|
||||
node.name,
|
||||
[&]() {
|
||||
// Do nothing, it's an object variable.
|
||||
if (node.child) node.child->Visit(*this);
|
||||
}, [&]() {
|
||||
// Do nothing, it's a variable.
|
||||
if (node.child) node.child->Visit(*this);
|
||||
}, [&]() {
|
||||
// Do nothing, it's a property.
|
||||
if (node.child) node.child->Visit(*this);
|
||||
}, [&]() {
|
||||
// This is a parameter
|
||||
RenameParameter(node.name);
|
||||
if (node.child) node.child->Visit(*this);
|
||||
}, [&]() {
|
||||
// Do nothing, it's something else.
|
||||
if (node.child) node.child->Visit(*this);
|
||||
});
|
||||
}
|
||||
void OnVisitVariableAccessorNode(VariableAccessorNode& node) override {
|
||||
if (node.child) node.child->Visit(*this);
|
||||
}
|
||||
void OnVisitVariableBracketAccessorNode(
|
||||
VariableBracketAccessorNode& node) override {
|
||||
bool isGrandParentTypeAVariable = isParentTypeAVariable;
|
||||
isParentTypeAVariable = false;
|
||||
node.expression->Visit(*this);
|
||||
isParentTypeAVariable = isGrandParentTypeAVariable;
|
||||
if (node.child) node.child->Visit(*this);
|
||||
}
|
||||
void OnVisitIdentifierNode(IdentifierNode& node) override {
|
||||
if (isParentTypeAVariable) {
|
||||
// Do nothing, it's a variable.
|
||||
return;
|
||||
}
|
||||
projectScopedContainers.MatchIdentifierWithName<void>(
|
||||
// The property name is changed after the refactor operation
|
||||
node.identifierName,
|
||||
[&]() {
|
||||
// Do nothing, it's an object variable.
|
||||
}, [&]() {
|
||||
// Do nothing, it's a variable.
|
||||
}, [&]() {
|
||||
// Do nothing, it's a property.
|
||||
}, [&]() {
|
||||
// This is a parameter.
|
||||
RenameParameter(node.identifierName);
|
||||
}, [&]() {
|
||||
// Do nothing, it's something else.
|
||||
});
|
||||
}
|
||||
void OnVisitObjectFunctionNameNode(ObjectFunctionNameNode& node) override {}
|
||||
void OnVisitFunctionCallNode(FunctionCallNode &node) override {
|
||||
bool isGrandParentTypeAVariable = isParentTypeAVariable;
|
||||
for (auto ¶meter : node.parameters) {
|
||||
const auto ¶meterMetadata =
|
||||
gd::MetadataProvider::GetFunctionCallParameterMetadata(
|
||||
platform, projectScopedContainers.GetObjectsContainersList(),
|
||||
node, *parameter);
|
||||
if (!parameterMetadata) {
|
||||
continue;
|
||||
}
|
||||
const auto ¶meterTypeMetadata =
|
||||
parameterMetadata->GetValueTypeMetadata();
|
||||
if (gd::EventsParameterReplacer::CanContainParameter(
|
||||
parameterTypeMetadata)) {
|
||||
isParentTypeAVariable = parameterTypeMetadata.IsVariable();
|
||||
parameter->Visit(*this);
|
||||
}
|
||||
}
|
||||
isParentTypeAVariable = isGrandParentTypeAVariable;
|
||||
}
|
||||
void OnVisitEmptyNode(EmptyNode& node) override {}
|
||||
|
||||
private:
|
||||
bool hasDoneRenaming;
|
||||
|
||||
bool RenameParameter(
|
||||
gd::String& name) {
|
||||
if (oldToNewPropertyNames.count(name) >= 1) {
|
||||
name = oldToNewPropertyNames.find(name)->second;
|
||||
hasDoneRenaming = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false; // Nothing was changed or done.
|
||||
}
|
||||
|
||||
// Scope:
|
||||
const gd::Platform& platform;
|
||||
const gd::ProjectScopedContainers& projectScopedContainers;
|
||||
|
||||
// Renaming to do
|
||||
const std::unordered_map<gd::String, gd::String>& oldToNewPropertyNames;
|
||||
|
||||
gd::String objectNameToUseForVariableAccessor;
|
||||
bool isParentTypeAVariable;
|
||||
};
|
||||
|
||||
bool EventsParameterReplacer::DoVisitInstruction(gd::Instruction& instruction,
|
||||
bool isCondition) {
|
||||
const auto& metadata = isCondition
|
||||
? gd::MetadataProvider::GetConditionMetadata(
|
||||
platform, instruction.GetType())
|
||||
: gd::MetadataProvider::GetActionMetadata(
|
||||
platform, instruction.GetType());
|
||||
|
||||
gd::ParameterMetadataTools::IterateOverParametersWithIndex(
|
||||
instruction.GetParameters(),
|
||||
metadata.GetParameters(),
|
||||
[&](const gd::ParameterMetadata& parameterMetadata,
|
||||
const gd::Expression& parameterValue,
|
||||
size_t parameterIndex,
|
||||
const gd::String& lastObjectName) {
|
||||
if (!gd::EventsParameterReplacer::CanContainParameter(
|
||||
parameterMetadata.GetValueTypeMetadata())) {
|
||||
return;
|
||||
}
|
||||
auto node = parameterValue.GetRootNode();
|
||||
if (node) {
|
||||
ExpressionParameterReplacer renamer(
|
||||
platform, GetProjectScopedContainers(),
|
||||
parameterMetadata.GetValueTypeMetadata().IsVariable(),
|
||||
oldToNewPropertyNames);
|
||||
node->Visit(renamer);
|
||||
|
||||
if (renamer.HasDoneRenaming()) {
|
||||
instruction.SetParameter(
|
||||
parameterIndex, ExpressionParser2NodePrinter::PrintNode(*node));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool EventsParameterReplacer::DoVisitEventExpression(
|
||||
gd::Expression& expression, const gd::ParameterMetadata& metadata) {
|
||||
if (!gd::EventsParameterReplacer::CanContainParameter(
|
||||
metadata.GetValueTypeMetadata())) {
|
||||
return false;
|
||||
}
|
||||
auto node = expression.GetRootNode();
|
||||
if (node) {
|
||||
ExpressionParameterReplacer renamer(
|
||||
platform, GetProjectScopedContainers(),
|
||||
metadata.GetValueTypeMetadata().IsVariable(), oldToNewPropertyNames);
|
||||
node->Visit(renamer);
|
||||
|
||||
if (renamer.HasDoneRenaming()) {
|
||||
expression = ExpressionParser2NodePrinter::PrintNode(*node);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool EventsParameterReplacer::CanContainParameter(
|
||||
const gd::ValueTypeMetadata &valueTypeMetadata) {
|
||||
return valueTypeMetadata.IsVariable() || valueTypeMetadata.IsNumber() ||
|
||||
valueTypeMetadata.IsString();
|
||||
}
|
||||
|
||||
EventsParameterReplacer::~EventsParameterReplacer() {}
|
||||
|
||||
} // namespace gd
|
52
Core/GDCore/IDE/Events/EventsParameterReplacer.h
Normal file
52
Core/GDCore/IDE/Events/EventsParameterReplacer.h
Normal file
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* GDevelop Core
|
||||
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
#include "GDCore/IDE/Events/ArbitraryEventsWorker.h"
|
||||
#include "GDCore/String.h"
|
||||
namespace gd {
|
||||
class BaseEvent;
|
||||
class PropertiesContainer;
|
||||
class EventsList;
|
||||
class Platform;
|
||||
} // namespace gd
|
||||
|
||||
namespace gd {
|
||||
/**
|
||||
* \brief Replace in expressions and in parameters of actions or conditions,
|
||||
* references to the name of a parameter by another.
|
||||
*
|
||||
* \ingroup IDE
|
||||
*/
|
||||
class GD_CORE_API EventsParameterReplacer
|
||||
: public ArbitraryEventsWorkerWithContext {
|
||||
public:
|
||||
EventsParameterReplacer(
|
||||
const gd::Platform &platform_,
|
||||
const std::unordered_map<gd::String, gd::String> &oldToNewPropertyNames_)
|
||||
: platform(platform_),
|
||||
oldToNewPropertyNames(oldToNewPropertyNames_){};
|
||||
virtual ~EventsParameterReplacer();
|
||||
|
||||
static bool CanContainParameter(const gd::ValueTypeMetadata &valueTypeMetadata);
|
||||
|
||||
private:
|
||||
bool DoVisitInstruction(gd::Instruction &instruction,
|
||||
bool isCondition) override;
|
||||
bool DoVisitEventExpression(gd::Expression &expression,
|
||||
const gd::ParameterMetadata &metadata) override;
|
||||
|
||||
const gd::Platform &platform;
|
||||
const std::unordered_map<gd::String, gd::String> &oldToNewPropertyNames;
|
||||
};
|
||||
|
||||
} // namespace gd
|
@@ -41,6 +41,7 @@ class GD_CORE_API ExpressionPropertyReplacer
|
||||
const gd::Platform& platform_,
|
||||
const gd::ProjectScopedContainers& projectScopedContainers_,
|
||||
const gd::PropertiesContainer& targetPropertiesContainer_,
|
||||
bool isParentTypeAVariable_,
|
||||
const std::unordered_map<gd::String, gd::String>& oldToNewPropertyNames_,
|
||||
const std::unordered_set<gd::String>& removedPropertyNames_)
|
||||
: hasDoneRenaming(false),
|
||||
@@ -48,6 +49,7 @@ class GD_CORE_API ExpressionPropertyReplacer
|
||||
platform(platform_),
|
||||
projectScopedContainers(projectScopedContainers_),
|
||||
targetPropertiesContainer(targetPropertiesContainer_),
|
||||
isParentTypeAVariable(isParentTypeAVariable_),
|
||||
oldToNewPropertyNames(oldToNewPropertyNames_),
|
||||
removedPropertyNames(removedPropertyNames_){};
|
||||
virtual ~ExpressionPropertyReplacer(){};
|
||||
@@ -69,16 +71,21 @@ class GD_CORE_API ExpressionPropertyReplacer
|
||||
void OnVisitNumberNode(NumberNode& node) override {}
|
||||
void OnVisitTextNode(TextNode& node) override {}
|
||||
void OnVisitVariableNode(VariableNode& node) override {
|
||||
if (isParentTypeAVariable) {
|
||||
// Do nothing, it's a variable.
|
||||
if (node.child) node.child->Visit(*this);
|
||||
return;
|
||||
}
|
||||
|
||||
auto& propertiesContainersList =
|
||||
projectScopedContainers.GetPropertiesContainersList();
|
||||
|
||||
// The node represents a variable or an object name on which a variable
|
||||
// will be accessed, or a property with a child.
|
||||
|
||||
// Match the potential *new* name of the property, because refactorings are
|
||||
// done after changes in the variables container.
|
||||
projectScopedContainers.MatchIdentifierWithName<void>(
|
||||
GetPotentialNewName(node.name),
|
||||
// The property name is changed after the refactor operation.
|
||||
node.name,
|
||||
[&]() {
|
||||
// Do nothing, it's an object variable.
|
||||
if (node.child) node.child->Visit(*this);
|
||||
@@ -100,16 +107,7 @@ class GD_CORE_API ExpressionPropertyReplacer
|
||||
// Do nothing, it's a parameter.
|
||||
if (node.child) node.child->Visit(*this);
|
||||
}, [&]() {
|
||||
// This is something else - potentially a deleted property.
|
||||
// Check if it's coming from the target container with
|
||||
// properties to replace.
|
||||
if (propertiesContainersList.HasPropertiesContainer(
|
||||
targetPropertiesContainer)) {
|
||||
// The node represents a property, that can come from the target
|
||||
// (because the target is in the scope), replace or remove it:
|
||||
RenameOrRemovePropertyOfTargetPropertyContainer(node.name);
|
||||
}
|
||||
|
||||
// Do nothing, it's something else.
|
||||
if (node.child) node.child->Visit(*this);
|
||||
});
|
||||
}
|
||||
@@ -118,17 +116,24 @@ class GD_CORE_API ExpressionPropertyReplacer
|
||||
}
|
||||
void OnVisitVariableBracketAccessorNode(
|
||||
VariableBracketAccessorNode& node) override {
|
||||
bool isGrandParentTypeAVariable = isParentTypeAVariable;
|
||||
isParentTypeAVariable = false;
|
||||
node.expression->Visit(*this);
|
||||
isParentTypeAVariable = isGrandParentTypeAVariable;
|
||||
if (node.child) node.child->Visit(*this);
|
||||
}
|
||||
void OnVisitIdentifierNode(IdentifierNode& node) override {
|
||||
if (isParentTypeAVariable) {
|
||||
// Do nothing, it's a variable.
|
||||
return;
|
||||
}
|
||||
|
||||
auto& propertiesContainersList =
|
||||
projectScopedContainers.GetPropertiesContainersList();
|
||||
|
||||
// Match the potential *new* name of the property, because refactorings are
|
||||
// done after changes in the variables container.
|
||||
projectScopedContainers.MatchIdentifierWithName<void>(
|
||||
GetPotentialNewName(node.identifierName),
|
||||
// The property name is changed after the refactor operation
|
||||
node.identifierName,
|
||||
[&]() {
|
||||
// Do nothing, it's an object variable.
|
||||
}, [&]() {
|
||||
@@ -145,22 +150,29 @@ class GD_CORE_API ExpressionPropertyReplacer
|
||||
}, [&]() {
|
||||
// Do nothing, it's a parameter.
|
||||
}, [&]() {
|
||||
// This is something else - potentially a deleted property.
|
||||
// Check if it's coming from the target container with
|
||||
// properties to replace.
|
||||
if (propertiesContainersList.HasPropertiesContainer(
|
||||
targetPropertiesContainer)) {
|
||||
// The node represents a property, that can come from the target
|
||||
// (because the target is in the scope), replace or remove it:
|
||||
RenameOrRemovePropertyOfTargetPropertyContainer(node.identifierName);
|
||||
}
|
||||
// Do nothing, it's something else.
|
||||
});
|
||||
}
|
||||
void OnVisitObjectFunctionNameNode(ObjectFunctionNameNode& node) override {}
|
||||
void OnVisitFunctionCallNode(FunctionCallNode& node) override {
|
||||
for (auto& parameter : node.parameters) {
|
||||
parameter->Visit(*this);
|
||||
void OnVisitFunctionCallNode(FunctionCallNode &node) override {
|
||||
bool isGrandParentTypeAVariable = isParentTypeAVariable;
|
||||
for (auto ¶meter : node.parameters) {
|
||||
const auto ¶meterMetadata =
|
||||
gd::MetadataProvider::GetFunctionCallParameterMetadata(
|
||||
platform, projectScopedContainers.GetObjectsContainersList(),
|
||||
node, *parameter);
|
||||
if (!parameterMetadata) {
|
||||
continue;
|
||||
}
|
||||
const auto ¶meterTypeMetadata =
|
||||
parameterMetadata->GetValueTypeMetadata();
|
||||
if (gd::EventsPropertyReplacer::CanContainProperty(
|
||||
parameterTypeMetadata)) {
|
||||
isParentTypeAVariable = parameterTypeMetadata.IsVariable();
|
||||
parameter->Visit(*this);
|
||||
}
|
||||
}
|
||||
isParentTypeAVariable = isGrandParentTypeAVariable;
|
||||
}
|
||||
void OnVisitEmptyNode(EmptyNode& node) override {}
|
||||
|
||||
@@ -168,12 +180,6 @@ class GD_CORE_API ExpressionPropertyReplacer
|
||||
bool hasDoneRenaming;
|
||||
bool removedPropertyUsed;
|
||||
|
||||
const gd::String& GetPotentialNewName(const gd::String& oldName) {
|
||||
return oldToNewPropertyNames.count(oldName) >= 1
|
||||
? oldToNewPropertyNames.find(oldName)->second
|
||||
: oldName;
|
||||
}
|
||||
|
||||
bool RenameOrRemovePropertyOfTargetPropertyContainer(
|
||||
gd::String& propertyName) {
|
||||
if (oldToNewPropertyNames.count(propertyName) >= 1) {
|
||||
@@ -198,6 +204,7 @@ class GD_CORE_API ExpressionPropertyReplacer
|
||||
const std::unordered_set<gd::String>& removedPropertyNames;
|
||||
|
||||
gd::String objectNameToUseForVariableAccessor;
|
||||
bool isParentTypeAVariable;
|
||||
};
|
||||
|
||||
bool EventsPropertyReplacer::DoVisitInstruction(gd::Instruction& instruction,
|
||||
@@ -216,20 +223,16 @@ bool EventsPropertyReplacer::DoVisitInstruction(gd::Instruction& instruction,
|
||||
const gd::Expression& parameterValue,
|
||||
size_t parameterIndex,
|
||||
const gd::String& lastObjectName) {
|
||||
const gd::String& type = parameterMetadata.GetType();
|
||||
|
||||
if (!gd::ParameterMetadata::IsExpression("variable", type) &&
|
||||
!gd::ParameterMetadata::IsExpression("number", type) &&
|
||||
!gd::ParameterMetadata::IsExpression("string", type))
|
||||
return; // Not an expression that can contain properties.
|
||||
|
||||
if (!gd::EventsPropertyReplacer::CanContainProperty(
|
||||
parameterMetadata.GetValueTypeMetadata())) {
|
||||
return;
|
||||
}
|
||||
auto node = parameterValue.GetRootNode();
|
||||
if (node) {
|
||||
ExpressionPropertyReplacer renamer(platform,
|
||||
GetProjectScopedContainers(),
|
||||
targetPropertiesContainer,
|
||||
oldToNewPropertyNames,
|
||||
removedPropertyNames);
|
||||
ExpressionPropertyReplacer renamer(
|
||||
platform, GetProjectScopedContainers(), targetPropertiesContainer,
|
||||
parameterMetadata.GetValueTypeMetadata().IsVariable(),
|
||||
oldToNewPropertyNames, removedPropertyNames);
|
||||
node->Visit(renamer);
|
||||
|
||||
if (renamer.IsRemovedPropertyUsed()) {
|
||||
@@ -246,20 +249,16 @@ bool EventsPropertyReplacer::DoVisitInstruction(gd::Instruction& instruction,
|
||||
|
||||
bool EventsPropertyReplacer::DoVisitEventExpression(
|
||||
gd::Expression& expression, const gd::ParameterMetadata& metadata) {
|
||||
const gd::String& type = metadata.GetType();
|
||||
|
||||
if (!gd::ParameterMetadata::IsExpression("variable", type) &&
|
||||
!gd::ParameterMetadata::IsExpression("number", type) &&
|
||||
!gd::ParameterMetadata::IsExpression("string", type))
|
||||
return false; // Not an expression that can contain properties.
|
||||
|
||||
if (!gd::EventsPropertyReplacer::CanContainProperty(
|
||||
metadata.GetValueTypeMetadata())) {
|
||||
return false;
|
||||
}
|
||||
auto node = expression.GetRootNode();
|
||||
if (node) {
|
||||
ExpressionPropertyReplacer renamer(platform,
|
||||
GetProjectScopedContainers(),
|
||||
targetPropertiesContainer,
|
||||
oldToNewPropertyNames,
|
||||
removedPropertyNames);
|
||||
ExpressionPropertyReplacer renamer(
|
||||
platform, GetProjectScopedContainers(), targetPropertiesContainer,
|
||||
metadata.GetValueTypeMetadata().IsVariable(), oldToNewPropertyNames,
|
||||
removedPropertyNames);
|
||||
node->Visit(renamer);
|
||||
|
||||
if (renamer.IsRemovedPropertyUsed()) {
|
||||
@@ -272,6 +271,12 @@ bool EventsPropertyReplacer::DoVisitEventExpression(
|
||||
return false;
|
||||
}
|
||||
|
||||
bool EventsPropertyReplacer::CanContainProperty(
|
||||
const gd::ValueTypeMetadata &valueTypeMetadata) {
|
||||
return valueTypeMetadata.IsVariable() || valueTypeMetadata.IsNumber() ||
|
||||
valueTypeMetadata.IsString();
|
||||
}
|
||||
|
||||
EventsPropertyReplacer::~EventsPropertyReplacer() {}
|
||||
|
||||
} // namespace gd
|
||||
|
@@ -4,6 +4,7 @@
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
@@ -41,6 +42,8 @@ class GD_CORE_API EventsPropertyReplacer
|
||||
removedPropertyNames(removedPropertyNames_){};
|
||||
virtual ~EventsPropertyReplacer();
|
||||
|
||||
static bool CanContainProperty(const gd::ValueTypeMetadata &valueTypeMetadata);
|
||||
|
||||
private:
|
||||
bool DoVisitInstruction(gd::Instruction &instruction,
|
||||
bool isCondition) override;
|
||||
|
@@ -22,6 +22,7 @@
|
||||
#include "GDCore/Project/EventsBasedObject.h"
|
||||
#include "GDCore/Project/ProjectScopedContainers.h"
|
||||
#include "GDCore/IDE/Events/ExpressionTypeFinder.h"
|
||||
#include "GDCore/IDE/Events/ArbitraryEventsWorker.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
@@ -51,17 +52,17 @@ class GD_CORE_API ExpressionObjectRenamer : public ExpressionParser2NodeWorker {
|
||||
|
||||
static bool Rename(const gd::Platform &platform,
|
||||
const gd::ProjectScopedContainers &projectScopedContainers,
|
||||
const gd::String &rootType,
|
||||
gd::ExpressionNode& node,
|
||||
const gd::String& objectName,
|
||||
const gd::String& objectNewName) {
|
||||
if (gd::ExpressionValidator::HasNoErrors(platform, projectScopedContainers, rootType, node)) {
|
||||
ExpressionObjectRenamer renamer(platform, projectScopedContainers, rootType, objectName, objectNewName);
|
||||
const gd::String &rootType, gd::ExpressionNode &node,
|
||||
const gd::String &objectName,
|
||||
const gd::String &objectNewName) {
|
||||
if (gd::ExpressionValidator::HasNoErrors(platform, projectScopedContainers,
|
||||
rootType, node)) {
|
||||
ExpressionObjectRenamer renamer(platform, projectScopedContainers,
|
||||
rootType, objectName, objectNewName);
|
||||
node.Visit(renamer);
|
||||
|
||||
return renamer.HasDoneRenaming();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -83,7 +84,7 @@ class GD_CORE_API ExpressionObjectRenamer : public ExpressionParser2NodeWorker {
|
||||
void OnVisitVariableNode(VariableNode& node) override {
|
||||
auto type = gd::ExpressionTypeFinder::GetType(platform, projectScopedContainers, rootType, node);
|
||||
|
||||
if (gd::ValueTypeMetadata::IsTypeLegacyPreScopedVariable(type)) {
|
||||
if (gd::ValueTypeMetadata::IsVariable(type)) {
|
||||
// Nothing to do (this can't reference an object)
|
||||
} else {
|
||||
if (node.name == objectName) {
|
||||
@@ -119,7 +120,7 @@ class GD_CORE_API ExpressionObjectRenamer : public ExpressionParser2NodeWorker {
|
||||
node.identifierName == objectName) {
|
||||
hasDoneRenaming = true;
|
||||
node.identifierName = objectNewName;
|
||||
} else if (gd::ValueTypeMetadata::IsTypeLegacyPreScopedVariable(type)) {
|
||||
} else if (gd::ValueTypeMetadata::IsVariable(type)) {
|
||||
// Nothing to do (this can't reference an object)
|
||||
} else {
|
||||
if (node.identifierName == objectName) {
|
||||
@@ -295,183 +296,114 @@ class GD_CORE_API ExpressionObjectFinder : public ExpressionParser2NodeWorker {
|
||||
const gd::String rootType;
|
||||
};
|
||||
|
||||
bool EventsRefactorer::RenameObjectInActions(const gd::Platform& platform,
|
||||
const gd::ProjectScopedContainers& projectScopedContainers,
|
||||
gd::InstructionsList& actions,
|
||||
gd::String oldName,
|
||||
gd::String newName) {
|
||||
bool somethingModified = false;
|
||||
/**
|
||||
* \brief Replace in expressions and in parameters of actions or conditions,
|
||||
* references to the name of an object by another.
|
||||
*
|
||||
* \ingroup IDE
|
||||
*/
|
||||
class GD_CORE_API EventsObjectReplacer
|
||||
: public ArbitraryEventsWorkerWithContext {
|
||||
public:
|
||||
EventsObjectReplacer(const gd::Platform &platform_,
|
||||
const gd::ObjectsContainer &targetedObjectsContainer_,
|
||||
const gd::String &oldObjectName_,
|
||||
const gd::String &newObjectName_)
|
||||
: platform(platform_),
|
||||
targetedObjectsContainer(targetedObjectsContainer_),
|
||||
oldObjectName(oldObjectName_), newObjectName(newObjectName_){};
|
||||
|
||||
for (std::size_t aId = 0; aId < actions.size(); ++aId) {
|
||||
const gd::InstructionMetadata& instrInfos =
|
||||
MetadataProvider::GetActionMetadata(platform, actions[aId].GetType());
|
||||
for (std::size_t pNb = 0; pNb < instrInfos.parameters.GetParametersCount(); ++pNb) {
|
||||
// Replace object's name in parameters
|
||||
if (gd::ParameterMetadata::IsObject(instrInfos.parameters.GetParameter(pNb).GetType()) &&
|
||||
actions[aId].GetParameter(pNb).GetPlainString() == oldName)
|
||||
actions[aId].SetParameter(pNb, gd::Expression(newName));
|
||||
// Replace object's name in expressions
|
||||
else if (ParameterMetadata::IsExpression(
|
||||
"number", instrInfos.parameters.GetParameter(pNb).GetType())) {
|
||||
auto node = actions[aId].GetParameter(pNb).GetRootNode();
|
||||
virtual ~EventsObjectReplacer() {}
|
||||
|
||||
if (ExpressionObjectRenamer::Rename(platform, projectScopedContainers, "number", *node, oldName, newName)) {
|
||||
actions[aId].SetParameter(
|
||||
pNb, ExpressionParser2NodePrinter::PrintNode(*node));
|
||||
}
|
||||
}
|
||||
// Replace object's name in text expressions
|
||||
else if (ParameterMetadata::IsExpression(
|
||||
"string", instrInfos.parameters.GetParameter(pNb).GetType())) {
|
||||
auto node = actions[aId].GetParameter(pNb).GetRootNode();
|
||||
|
||||
if (ExpressionObjectRenamer::Rename(platform, projectScopedContainers, "string", *node, oldName, newName)) {
|
||||
actions[aId].SetParameter(
|
||||
pNb, ExpressionParser2NodePrinter::PrintNode(*node));
|
||||
}
|
||||
}
|
||||
private:
|
||||
bool DoVisitInstruction(gd::Instruction &instruction,
|
||||
bool isCondition) override {
|
||||
if (&targetedObjectsContainer !=
|
||||
GetProjectScopedContainers()
|
||||
.GetObjectsContainersList()
|
||||
.GetObjectsContainerFromObjectName(oldObjectName)) {
|
||||
return false;
|
||||
}
|
||||
const auto &metadata = isCondition
|
||||
? gd::MetadataProvider::GetConditionMetadata(
|
||||
platform, instruction.GetType())
|
||||
: gd::MetadataProvider::GetActionMetadata(
|
||||
platform, instruction.GetType());
|
||||
|
||||
if (!actions[aId].GetSubInstructions().empty())
|
||||
somethingModified =
|
||||
RenameObjectInActions(platform,
|
||||
projectScopedContainers,
|
||||
actions[aId].GetSubInstructions(),
|
||||
oldName,
|
||||
newName) ||
|
||||
somethingModified;
|
||||
gd::ParameterMetadataTools::IterateOverParametersWithIndex(
|
||||
instruction.GetParameters(), metadata.GetParameters(),
|
||||
[&](const gd::ParameterMetadata ¶meterMetadata,
|
||||
const gd::Expression ¶meterValue, size_t parameterIndex,
|
||||
const gd::String &lastObjectName) {
|
||||
if (!gd::EventsObjectReplacer::CanContainObject(
|
||||
parameterMetadata.GetValueTypeMetadata())) {
|
||||
return;
|
||||
}
|
||||
auto node = parameterValue.GetRootNode();
|
||||
if (node) {
|
||||
ExpressionObjectRenamer renamer(
|
||||
platform, GetProjectScopedContainers(),
|
||||
parameterMetadata.GetValueTypeMetadata().GetName(),
|
||||
oldObjectName, newObjectName);
|
||||
node->Visit(renamer);
|
||||
|
||||
if (renamer.HasDoneRenaming()) {
|
||||
instruction.SetParameter(
|
||||
parameterIndex,
|
||||
ExpressionParser2NodePrinter::PrintNode(*node));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return somethingModified;
|
||||
}
|
||||
|
||||
bool EventsRefactorer::RenameObjectInConditions(
|
||||
const gd::Platform& platform,
|
||||
const gd::ProjectScopedContainers& projectScopedContainers,
|
||||
gd::InstructionsList& conditions,
|
||||
gd::String oldName,
|
||||
gd::String newName) {
|
||||
bool somethingModified = false;
|
||||
|
||||
for (std::size_t cId = 0; cId < conditions.size(); ++cId) {
|
||||
const gd::InstructionMetadata& instrInfos =
|
||||
MetadataProvider::GetConditionMetadata(platform,
|
||||
conditions[cId].GetType());
|
||||
for (std::size_t pNb = 0; pNb < instrInfos.parameters.GetParametersCount(); ++pNb) {
|
||||
// Replace object's name in parameters
|
||||
if (gd::ParameterMetadata::IsObject(instrInfos.parameters.GetParameter(pNb).GetType()) &&
|
||||
conditions[cId].GetParameter(pNb).GetPlainString() == oldName)
|
||||
conditions[cId].SetParameter(pNb, gd::Expression(newName));
|
||||
// Replace object's name in expressions
|
||||
else if (ParameterMetadata::IsExpression(
|
||||
"number", instrInfos.parameters.GetParameter(pNb).GetType())) {
|
||||
auto node = conditions[cId].GetParameter(pNb).GetRootNode();
|
||||
|
||||
if (ExpressionObjectRenamer::Rename(platform, projectScopedContainers, "number", *node, oldName, newName)) {
|
||||
conditions[cId].SetParameter(
|
||||
pNb, ExpressionParser2NodePrinter::PrintNode(*node));
|
||||
}
|
||||
}
|
||||
// Replace object's name in text expressions
|
||||
else if (ParameterMetadata::IsExpression(
|
||||
"string", instrInfos.parameters.GetParameter(pNb).GetType())) {
|
||||
auto node = conditions[cId].GetParameter(pNb).GetRootNode();
|
||||
|
||||
if (ExpressionObjectRenamer::Rename(platform, projectScopedContainers, "string", *node, oldName, newName)) {
|
||||
conditions[cId].SetParameter(
|
||||
pNb, ExpressionParser2NodePrinter::PrintNode(*node));
|
||||
}
|
||||
}
|
||||
bool DoVisitEventExpression(gd::Expression &expression,
|
||||
const gd::ParameterMetadata &metadata) override {
|
||||
if (&targetedObjectsContainer !=
|
||||
GetProjectScopedContainers()
|
||||
.GetObjectsContainersList()
|
||||
.GetObjectsContainerFromObjectName(oldObjectName)) {
|
||||
return false;
|
||||
}
|
||||
if (!gd::EventsObjectReplacer::CanContainObject(
|
||||
metadata.GetValueTypeMetadata())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!conditions[cId].GetSubInstructions().empty())
|
||||
somethingModified =
|
||||
RenameObjectInConditions(platform,
|
||||
projectScopedContainers,
|
||||
conditions[cId].GetSubInstructions(),
|
||||
oldName,
|
||||
newName) ||
|
||||
somethingModified;
|
||||
}
|
||||
|
||||
return somethingModified;
|
||||
}
|
||||
|
||||
bool EventsRefactorer::RenameObjectInEventParameters(
|
||||
const gd::Platform& platform,
|
||||
const gd::ProjectScopedContainers& projectScopedContainers,
|
||||
gd::Expression& expression,
|
||||
gd::ParameterMetadata parameterMetadata,
|
||||
gd::String oldName,
|
||||
gd::String newName) {
|
||||
bool somethingModified = false;
|
||||
|
||||
if (gd::ParameterMetadata::IsObject(parameterMetadata.GetType()) &&
|
||||
expression.GetPlainString() == oldName)
|
||||
expression = gd::Expression(newName);
|
||||
// Replace object's name in expressions
|
||||
else if (ParameterMetadata::IsExpression("number",
|
||||
parameterMetadata.GetType())) {
|
||||
auto node = expression.GetRootNode();
|
||||
if (node) {
|
||||
ExpressionObjectRenamer renamer(platform, GetProjectScopedContainers(),
|
||||
metadata.GetValueTypeMetadata().GetName(),
|
||||
oldObjectName, newObjectName);
|
||||
node->Visit(renamer);
|
||||
|
||||
if (ExpressionObjectRenamer::Rename(platform, projectScopedContainers, "number", *node, oldName, newName)) {
|
||||
expression = ExpressionParser2NodePrinter::PrintNode(*node);
|
||||
if (renamer.HasDoneRenaming()) {
|
||||
expression = ExpressionParser2NodePrinter::PrintNode(*node);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Replace object's name in text expressions
|
||||
else if (ParameterMetadata::IsExpression("string",
|
||||
parameterMetadata.GetType())) {
|
||||
auto node = expression.GetRootNode();
|
||||
|
||||
if (ExpressionObjectRenamer::Rename(platform, projectScopedContainers, "string", *node, oldName, newName)) {
|
||||
expression = ExpressionParser2NodePrinter::PrintNode(*node);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
return somethingModified;
|
||||
}
|
||||
bool CanContainObject(const gd::ValueTypeMetadata &valueTypeMetadata) {
|
||||
return valueTypeMetadata.IsObject() || valueTypeMetadata.IsVariable() ||
|
||||
valueTypeMetadata.IsNumber() || valueTypeMetadata.IsString();
|
||||
}
|
||||
|
||||
const gd::Platform &platform;
|
||||
const gd::ObjectsContainer &targetedObjectsContainer;
|
||||
const gd::String &oldObjectName;
|
||||
const gd::String &newObjectName;
|
||||
};
|
||||
|
||||
void EventsRefactorer::RenameObjectInEvents(const gd::Platform& platform,
|
||||
const gd::ProjectScopedContainers& projectScopedContainers,
|
||||
gd::EventsList& events,
|
||||
const gd::ObjectsContainer &targetedObjectsContainer,
|
||||
gd::String oldName,
|
||||
gd::String newName) {
|
||||
for (std::size_t i = 0; i < events.size(); ++i) {
|
||||
vector<gd::InstructionsList*> conditionsVectors =
|
||||
events[i].GetAllConditionsVectors();
|
||||
for (std::size_t j = 0; j < conditionsVectors.size(); ++j) {
|
||||
bool somethingModified = RenameObjectInConditions(
|
||||
platform, projectScopedContainers, *conditionsVectors[j], oldName, newName);
|
||||
}
|
||||
|
||||
vector<gd::InstructionsList*> actionsVectors =
|
||||
events[i].GetAllActionsVectors();
|
||||
for (std::size_t j = 0; j < actionsVectors.size(); ++j) {
|
||||
bool somethingModified = RenameObjectInActions(
|
||||
platform, projectScopedContainers, *actionsVectors[j], oldName, newName);
|
||||
}
|
||||
|
||||
vector<pair<gd::Expression*, gd::ParameterMetadata>>
|
||||
expressionsWithMetadata = events[i].GetAllExpressionsWithMetadata();
|
||||
for (std::size_t j = 0; j < expressionsWithMetadata.size(); ++j) {
|
||||
gd::Expression* expression = expressionsWithMetadata[j].first;
|
||||
gd::ParameterMetadata parameterMetadata =
|
||||
expressionsWithMetadata[j].second;
|
||||
bool somethingModified = RenameObjectInEventParameters(platform,
|
||||
projectScopedContainers,
|
||||
*expression,
|
||||
parameterMetadata,
|
||||
oldName,
|
||||
newName);
|
||||
}
|
||||
|
||||
if (events[i].CanHaveSubEvents())
|
||||
RenameObjectInEvents(platform,
|
||||
projectScopedContainers,
|
||||
events[i].GetSubEvents(),
|
||||
oldName,
|
||||
newName);
|
||||
}
|
||||
gd::EventsObjectReplacer eventsParameterReplacer(platform, targetedObjectsContainer, oldName, newName);
|
||||
eventsParameterReplacer.Launch(events, projectScopedContainers);
|
||||
}
|
||||
|
||||
bool EventsRefactorer::RemoveObjectInActions(const gd::Platform& platform,
|
||||
|
@@ -83,6 +83,7 @@ class GD_CORE_API EventsRefactorer {
|
||||
static void RenameObjectInEvents(const gd::Platform& platform,
|
||||
const gd::ProjectScopedContainers& projectScopedContainers,
|
||||
gd::EventsList& events,
|
||||
const gd::ObjectsContainer &targetedObjectsContainer,
|
||||
gd::String oldName,
|
||||
gd::String newName);
|
||||
|
||||
@@ -121,44 +122,6 @@ class GD_CORE_API EventsRefactorer {
|
||||
virtual ~EventsRefactorer(){};
|
||||
|
||||
private:
|
||||
/**
|
||||
* Replace all occurrences of an object name by another name in an action
|
||||
* ( include : objects in parameters and in math/text expressions ).
|
||||
*
|
||||
* \return true if something was modified.
|
||||
*/
|
||||
static bool RenameObjectInActions(const gd::Platform& platform,
|
||||
const gd::ProjectScopedContainers& projectScopedContainers,
|
||||
gd::InstructionsList& instructions,
|
||||
gd::String oldName,
|
||||
gd::String newName);
|
||||
|
||||
/**
|
||||
* Replace all occurrences of an object name by another name in a condition
|
||||
* ( include : objects in parameters and in math/text expressions ).
|
||||
*
|
||||
* \return true if something was modified.
|
||||
*/
|
||||
static bool RenameObjectInConditions(const gd::Platform& platform,
|
||||
const gd::ProjectScopedContainers& projectScopedContainers,
|
||||
gd::InstructionsList& instructions,
|
||||
gd::String oldName,
|
||||
gd::String newName);
|
||||
/**
|
||||
* Replace all occurrences of an object name by another name in an expression
|
||||
* with the specified metadata
|
||||
* ( include : objects or objects in math/text expressions ).
|
||||
*
|
||||
* \return true if something was modified.
|
||||
*/
|
||||
static bool RenameObjectInEventParameters(
|
||||
const gd::Platform& platform,
|
||||
const gd::ProjectScopedContainers& projectScopedContainers,
|
||||
gd::Expression& expression,
|
||||
gd::ParameterMetadata parameterMetadata,
|
||||
gd::String oldName,
|
||||
gd::String newName);
|
||||
|
||||
/**
|
||||
* Remove all conditions of the list using an object
|
||||
*
|
||||
|
@@ -68,19 +68,26 @@ size_t GetMaximumParametersNumber(
|
||||
|
||||
bool ExpressionValidator::ValidateObjectVariableOrVariableOrProperty(
|
||||
const gd::IdentifierNode& identifier) {
|
||||
return ValidateObjectVariableOrVariableOrProperty(identifier.identifierName, identifier.identifierNameLocation, identifier.childIdentifierName, identifier.childIdentifierNameLocation);
|
||||
}
|
||||
|
||||
bool ExpressionValidator::ValidateObjectVariableOrVariableOrProperty(
|
||||
const gd::String &identifierName,
|
||||
const gd::ExpressionParserLocation identifierNameLocation,
|
||||
const gd::String &childIdentifierName,
|
||||
const gd::ExpressionParserLocation childIdentifierNameLocation) {
|
||||
auto validateVariableTypeForExpression =
|
||||
[this, &identifier](gd::Variable::Type type) {
|
||||
[this, &identifierNameLocation](gd::Variable::Type type) {
|
||||
// Collections type can't be used directly in expressions, a child
|
||||
// must be accessed.
|
||||
if (type == Variable::Structure) {
|
||||
RaiseTypeError(_("You need to specify the name of the child variable "
|
||||
"to access. For example: `MyVariable.child`."),
|
||||
identifier.identifierNameLocation);
|
||||
identifierNameLocation);
|
||||
} else if (type == Variable::Array) {
|
||||
RaiseTypeError(_("You need to specify the name of the child variable "
|
||||
"to access. For example: `MyVariable[0]`."),
|
||||
identifier.identifierNameLocation);
|
||||
|
||||
identifierNameLocation);
|
||||
} else {
|
||||
// Number, string or boolean variables can be used in expressions.
|
||||
return;
|
||||
@@ -96,38 +103,41 @@ bool ExpressionValidator::ValidateObjectVariableOrVariableOrProperty(
|
||||
// we consider this node will be of the type required by the parent.
|
||||
childType = parentType;
|
||||
|
||||
return projectScopedContainers.MatchIdentifierWithName<bool>(identifier.identifierName,
|
||||
return projectScopedContainers.MatchIdentifierWithName<bool>(identifierName,
|
||||
[&]() {
|
||||
// This represents an object.
|
||||
if (identifier.childIdentifierName.empty()) {
|
||||
if (childIdentifierName.empty()) {
|
||||
RaiseTypeError(_("An object variable or expression should be entered."),
|
||||
identifier.identifierNameLocation);
|
||||
identifierNameLocation);
|
||||
|
||||
return true; // We should have found a variable.
|
||||
}
|
||||
|
||||
auto variableExistence = objectsContainersList.HasObjectOrGroupWithVariableNamed(identifier.identifierName, identifier.childIdentifierName);
|
||||
auto variableExistence =
|
||||
objectsContainersList.HasObjectOrGroupWithVariableNamed(
|
||||
identifierName, childIdentifierName);
|
||||
|
||||
if (variableExistence == gd::ObjectsContainersList::DoesNotExist) {
|
||||
RaiseUndeclaredVariableError(_("This variable does not exist on this object or group."),
|
||||
identifier.childIdentifierNameLocation, identifier.childIdentifierName, identifier.identifierName);
|
||||
childIdentifierNameLocation, childIdentifierName, identifierName);
|
||||
|
||||
return true; // We should have found a variable.
|
||||
}
|
||||
else if (variableExistence == gd::ObjectsContainersList::ExistsOnlyOnSomeObjectsOfTheGroup) {
|
||||
RaiseUndeclaredVariableError(_("This variable only exists on some objects of the group. It must be declared for all objects."),
|
||||
identifier.childIdentifierNameLocation, identifier.childIdentifierName, identifier.identifierName);
|
||||
childIdentifierNameLocation, childIdentifierName, identifierName);
|
||||
|
||||
return true; // We should have found a variable.
|
||||
}
|
||||
else if (variableExistence == gd::ObjectsContainersList::GroupIsEmpty) {
|
||||
RaiseUndeclaredVariableError(_("This group is empty. Add an object to this group first."),
|
||||
identifier.identifierNameLocation, identifier.childIdentifierName, identifier.identifierName);
|
||||
identifierNameLocation, childIdentifierName, identifierName);
|
||||
|
||||
return true; // We should have found a variable.
|
||||
}
|
||||
|
||||
auto variableType = objectsContainersList.GetTypeOfObjectOrGroupVariable(identifier.identifierName, identifier.childIdentifierName);
|
||||
auto variableType = objectsContainersList.GetTypeOfObjectOrGroupVariable(
|
||||
identifierName, childIdentifierName);
|
||||
ReadChildTypeFromVariable(variableType);
|
||||
|
||||
return true; // We found a variable.
|
||||
@@ -137,9 +147,9 @@ bool ExpressionValidator::ValidateObjectVariableOrVariableOrProperty(
|
||||
// Try to identify a declared variable with the name (and maybe the child
|
||||
// variable).
|
||||
const gd::Variable& variable =
|
||||
variablesContainersList.Get(identifier.identifierName);
|
||||
variablesContainersList.Get(identifierName);
|
||||
|
||||
if (identifier.childIdentifierName.empty()) {
|
||||
if (childIdentifierName.empty()) {
|
||||
// Just the root variable is accessed, check it can be used in an
|
||||
// expression.
|
||||
validateVariableTypeForExpression(variable.GetType());
|
||||
@@ -148,29 +158,29 @@ bool ExpressionValidator::ValidateObjectVariableOrVariableOrProperty(
|
||||
return true; // We found a variable.
|
||||
} else {
|
||||
// A child variable is accessed, check it can be used in an expression.
|
||||
if (!variable.HasChild(identifier.childIdentifierName)) {
|
||||
if (!variable.HasChild(childIdentifierName)) {
|
||||
RaiseTypeError(_("No child variable with this name found."),
|
||||
identifier.childIdentifierNameLocation);
|
||||
childIdentifierNameLocation);
|
||||
|
||||
return true; // We should have found a variable.
|
||||
}
|
||||
|
||||
const gd::Variable& childVariable =
|
||||
variable.GetChild(identifier.childIdentifierName);
|
||||
variable.GetChild(childIdentifierName);
|
||||
ReadChildTypeFromVariable(childVariable.GetType());
|
||||
return true; // We found a variable.
|
||||
}
|
||||
}, [&]() {
|
||||
// This is a property.
|
||||
if (!identifier.childIdentifierName.empty()) {
|
||||
if (!childIdentifierName.empty()) {
|
||||
RaiseTypeError(_("Accessing a child variable of a property is not possible - just write the property name."),
|
||||
identifier.childIdentifierNameLocation);
|
||||
childIdentifierNameLocation);
|
||||
|
||||
return true; // We found a property, even if the child is not allowed.
|
||||
}
|
||||
|
||||
const gd::NamedPropertyDescriptor &property =
|
||||
propertiesContainersList.Get(identifier.identifierName).second;
|
||||
propertiesContainersList.Get(identifierName).second;
|
||||
|
||||
if (property.GetType() == "Number") {
|
||||
childType = Type::Number;
|
||||
@@ -179,7 +189,7 @@ bool ExpressionValidator::ValidateObjectVariableOrVariableOrProperty(
|
||||
// or as a number)
|
||||
} else if (property.GetType() == "Behavior") {
|
||||
RaiseTypeError(_("Behaviors can't be used as a value in expressions."),
|
||||
identifier.identifierNameLocation);
|
||||
identifierNameLocation);
|
||||
} else {
|
||||
// Assume type is String or equivalent.
|
||||
childType = Type::String;
|
||||
@@ -188,14 +198,14 @@ bool ExpressionValidator::ValidateObjectVariableOrVariableOrProperty(
|
||||
return true; // We found a property.
|
||||
}, [&]() {
|
||||
// This is a parameter.
|
||||
if (!identifier.childIdentifierName.empty()) {
|
||||
if (!childIdentifierName.empty()) {
|
||||
RaiseTypeError(_("Accessing a child variable of a parameter is not possible - just write the parameter name."),
|
||||
identifier.childIdentifierNameLocation);
|
||||
childIdentifierNameLocation);
|
||||
|
||||
return true; // We found a parameter, even if the child is not allowed.
|
||||
}
|
||||
|
||||
const auto& parameter = gd::ParameterMetadataTools::Get(parametersVectorsList, identifier.identifierName);
|
||||
const auto& parameter = gd::ParameterMetadataTools::Get(parametersVectorsList, identifierName);
|
||||
const auto& valueTypeMetadata = parameter.GetValueTypeMetadata();
|
||||
if (valueTypeMetadata.IsNumber()) {
|
||||
childType = Type::Number;
|
||||
@@ -205,7 +215,7 @@ bool ExpressionValidator::ValidateObjectVariableOrVariableOrProperty(
|
||||
// Nothing - we don't know the precise type (this could be used as a string or as a number).
|
||||
} else {
|
||||
RaiseTypeError(_("This parameter is not a string, number or boolean - it can't be used in an expression."),
|
||||
identifier.identifierNameLocation);
|
||||
identifierNameLocation);
|
||||
|
||||
return true; // We found a parameter, even though the type is incompatible.
|
||||
}
|
||||
|
@@ -14,6 +14,7 @@
|
||||
#include "GDCore/Extensions/Metadata/ExpressionMetadata.h"
|
||||
#include "GDCore/Project/ProjectScopedContainers.h"
|
||||
#include "GDCore/Project/VariablesContainersList.h"
|
||||
#include "GDCore/Project/VariablesContainer.h"
|
||||
|
||||
namespace gd {
|
||||
class Expression;
|
||||
@@ -45,7 +46,9 @@ class GD_CORE_API ExpressionValidator : public ExpressionParser2NodeWorker {
|
||||
parentType(StringToType(gd::ValueTypeMetadata::GetExpressionPrimitiveValueType(rootType_))),
|
||||
childType(Type::Unknown),
|
||||
forbidsUsageOfBracketsBecauseParentIsObject(false),
|
||||
currentParameterExtraInfo(&extraInfo_) {};
|
||||
currentParameterExtraInfo(&extraInfo_),
|
||||
variableObjectName(),
|
||||
variableObjectNameLocation() {};
|
||||
virtual ~ExpressionValidator(){};
|
||||
|
||||
/**
|
||||
@@ -225,7 +228,8 @@ class GD_CORE_API ExpressionValidator : public ExpressionParser2NodeWorker {
|
||||
projectScopedContainers.MatchIdentifierWithName<void>(node.name,
|
||||
[&]() {
|
||||
// This represents an object.
|
||||
|
||||
variableObjectName = node.name;
|
||||
variableObjectNameLocation = node.nameLocation;
|
||||
// While understood by the parser, it's forbidden to use the bracket notation just after
|
||||
// an object name (`MyObject["MyVariable"]`).
|
||||
forbidsUsageOfBracketsBecauseParentIsObject = true;
|
||||
@@ -264,7 +268,13 @@ class GD_CORE_API ExpressionValidator : public ExpressionParser2NodeWorker {
|
||||
}
|
||||
void OnVisitVariableAccessorNode(VariableAccessorNode& node) override {
|
||||
ReportAnyError(node);
|
||||
|
||||
// TODO Also check child-variables existence on a path with only VariableAccessor to raise non-fatal errors.
|
||||
if (!variableObjectName.empty()) {
|
||||
ValidateObjectVariableOrVariableOrProperty(variableObjectName,
|
||||
variableObjectNameLocation,
|
||||
node.name, node.nameLocation);
|
||||
variableObjectName = "";
|
||||
}
|
||||
// In the case we accessed an object variable (`MyObject.MyVariable`),
|
||||
// brackets can now be used (`MyObject.MyVariable["MyChildVariable"]` is now valid).
|
||||
forbidsUsageOfBracketsBecauseParentIsObject = false;
|
||||
@@ -277,6 +287,7 @@ class GD_CORE_API ExpressionValidator : public ExpressionParser2NodeWorker {
|
||||
VariableBracketAccessorNode& node) override {
|
||||
ReportAnyError(node);
|
||||
|
||||
variableObjectName = "";
|
||||
if (forbidsUsageOfBracketsBecauseParentIsObject) {
|
||||
RaiseError(gd::ExpressionParserError::ErrorType::BracketsNotAllowedForObjects,
|
||||
_("You can't use the brackets to access an object variable. "
|
||||
@@ -369,6 +380,11 @@ class GD_CORE_API ExpressionValidator : public ExpressionParser2NodeWorker {
|
||||
enum Type {Unknown = 0, Number, String, NumberOrString, Variable, LegacyVariable, Object, Empty};
|
||||
Type ValidateFunction(const gd::FunctionCallNode& function);
|
||||
bool ValidateObjectVariableOrVariableOrProperty(const gd::IdentifierNode& identifier);
|
||||
bool ValidateObjectVariableOrVariableOrProperty(
|
||||
const gd::String &identifierName,
|
||||
const gd::ExpressionParserLocation identifierNameLocation,
|
||||
const gd::String &childIdentifierName,
|
||||
const gd::ExpressionParserLocation childIdentifierNameLocation);
|
||||
|
||||
void CheckVariableExistence(const ExpressionParserLocation &location, const gd::String& name) {
|
||||
if (!currentParameterExtraInfo || *currentParameterExtraInfo != "AllowUndeclaredVariable") {
|
||||
@@ -505,6 +521,8 @@ class GD_CORE_API ExpressionValidator : public ExpressionParser2NodeWorker {
|
||||
Type childType; ///< The type "discovered" down the tree and passed up.
|
||||
Type parentType; ///< The type "required" by the top of the tree.
|
||||
bool forbidsUsageOfBracketsBecauseParentIsObject;
|
||||
gd::String variableObjectName;
|
||||
gd::ExpressionParserLocation variableObjectNameLocation;
|
||||
const gd::String *currentParameterExtraInfo;
|
||||
const gd::Platform &platform;
|
||||
const gd::ProjectScopedContainers &projectScopedContainers;
|
||||
|
@@ -1,8 +1,19 @@
|
||||
#include "LeaderboardIdRenamer.h"
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "GDCore/Events/Event.h"
|
||||
#include "GDCore/Events/EventsList.h"
|
||||
#include "GDCore/Extensions/Metadata/InstructionMetadata.h"
|
||||
#include "GDCore/Extensions/Metadata/MetadataProvider.h"
|
||||
#include "GDCore/Project/Behavior.h"
|
||||
#include "GDCore/Project/Layout.h"
|
||||
#include "GDCore/Project/Object.h"
|
||||
#include "GDCore/Project/Project.h"
|
||||
#include "GDCore/Project/PropertyDescriptor.h"
|
||||
#include "GDCore/String.h"
|
||||
|
||||
namespace gd {
|
||||
|
||||
@@ -12,15 +23,54 @@ void LeaderboardIdRenamer::DoVisitObject(gd::Object &object) {
|
||||
auto &property = pair.second;
|
||||
if (property.GetType() == "LeaderboardId") {
|
||||
auto &leaderboardId = property.GetValue();
|
||||
|
||||
allLeaderboardIds.insert(leaderboardId);
|
||||
|
||||
if (leaderboardIdMap.find(leaderboardId) != leaderboardIdMap.end()) {
|
||||
object.GetConfiguration().UpdateProperty(propertyName, leaderboardIdMap[leaderboardId]);
|
||||
object.GetConfiguration().UpdateProperty(
|
||||
propertyName, leaderboardIdMap[leaderboardId]);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void LeaderboardIdRenamer::DoVisitBehavior(gd::Behavior &behavior){};
|
||||
void LeaderboardIdRenamer::DoVisitBehavior(gd::Behavior &behavior) {};
|
||||
|
||||
bool LeaderboardIdRenamer::DoVisitInstruction(gd::Instruction &instruction,
|
||||
bool isCondition) {
|
||||
const gd::InstructionMetadata &instrInfo =
|
||||
isCondition ? MetadataProvider::GetConditionMetadata(
|
||||
project.GetCurrentPlatform(), instruction.GetType())
|
||||
: MetadataProvider::GetActionMetadata(
|
||||
project.GetCurrentPlatform(), instruction.GetType());
|
||||
|
||||
for (int i = 0; i < instruction.GetParametersCount() &&
|
||||
i < instrInfo.GetParametersCount();
|
||||
++i) {
|
||||
const gd::ParameterMetadata parameter = instrInfo.GetParameter(i);
|
||||
|
||||
if (parameter.GetType() != "leaderboardId") {
|
||||
continue;
|
||||
}
|
||||
const gd::String leaderboardIdExpression =
|
||||
instruction.GetParameter(i).GetPlainString();
|
||||
if (leaderboardIdExpression[0] != '"' ||
|
||||
leaderboardIdExpression[leaderboardIdExpression.size() - 1] != '"') {
|
||||
continue;
|
||||
}
|
||||
const gd::String leaderboardId =
|
||||
leaderboardIdExpression.substr(1, leaderboardIdExpression.size() - 2);
|
||||
|
||||
allLeaderboardIds.insert(leaderboardId);
|
||||
|
||||
if (leaderboardIdMap.find(leaderboardId) != leaderboardIdMap.end()) {
|
||||
instruction.SetParameter(i,
|
||||
"\"" + leaderboardIdMap[leaderboardId] + "\"");
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
LeaderboardIdRenamer::~LeaderboardIdRenamer() {}
|
||||
|
||||
} // namespace gd
|
||||
} // namespace gd
|
||||
|
@@ -8,6 +8,7 @@
|
||||
#include <map>
|
||||
|
||||
#include "GDCore/IDE/Project/ArbitraryObjectsWorker.h"
|
||||
#include "GDCore/IDE/Events/ArbitraryEventsWorker.h"
|
||||
#include "GDCore/String.h"
|
||||
|
||||
namespace gd {
|
||||
@@ -17,18 +18,33 @@ class Behavior;
|
||||
|
||||
namespace gd {
|
||||
|
||||
class GD_CORE_API LeaderboardIdRenamer : public ArbitraryObjectsWorker {
|
||||
class GD_CORE_API LeaderboardIdRenamer : public ArbitraryObjectsWorker, public ArbitraryEventsWorker {
|
||||
public:
|
||||
LeaderboardIdRenamer(
|
||||
const std::map<gd::String, gd::String>& leaderboardIdMap_)
|
||||
: leaderboardIdMap(leaderboardIdMap_){};
|
||||
LeaderboardIdRenamer(gd::Project& project_): project(project_) {};
|
||||
virtual ~LeaderboardIdRenamer();
|
||||
|
||||
/**
|
||||
* Set the leaderboard identifiers to be replaced.
|
||||
*/
|
||||
void SetLeaderboardIdsToReplace(const std::map<gd::String, gd::String>& leaderboardIdMap_) {
|
||||
leaderboardIdMap = leaderboardIdMap_;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the all the leaderboard identifiers found in the project.
|
||||
*/
|
||||
const std::set<gd::String>& GetAllLeaderboardIds() const {
|
||||
return allLeaderboardIds;
|
||||
}
|
||||
|
||||
private:
|
||||
bool DoVisitInstruction(gd::Instruction& instruction, bool isCondition) override;
|
||||
void DoVisitObject(gd::Object& object) override;
|
||||
void DoVisitBehavior(gd::Behavior& behavior) override;
|
||||
|
||||
std::map<gd::String, gd::String> leaderboardIdMap;
|
||||
std::set<gd::String> allLeaderboardIds;
|
||||
gd::Project& project;
|
||||
};
|
||||
|
||||
}; // namespace gd
|
||||
|
@@ -13,6 +13,18 @@
|
||||
|
||||
namespace gd {
|
||||
|
||||
void UsedExtensionsResult::AddUsedExtension(const gd::PlatformExtension& extension) {
|
||||
usedExtensions.insert(extension.GetName());
|
||||
|
||||
usedSourceFiles.insert(usedSourceFiles.end(),
|
||||
extension.GetAllSourceFiles().begin(),
|
||||
extension.GetAllSourceFiles().end());
|
||||
}
|
||||
|
||||
void UsedExtensionsResult::AddUsedBuiltinExtension(const gd::String& extensionName) {
|
||||
usedExtensions.insert(extensionName);
|
||||
}
|
||||
|
||||
const UsedExtensionsResult UsedExtensionsFinder::ScanProject(gd::Project& project) {
|
||||
UsedExtensionsFinder worker(project);
|
||||
gd::ProjectBrowserHelper::ExposeProjectObjects(project, worker);
|
||||
@@ -28,9 +40,9 @@ void UsedExtensionsFinder::DoVisitObject(gd::Object &object) {
|
||||
if (metadata.GetMetadata().IsRenderedIn3D()) {
|
||||
result.MarkAsHaving3DObjects();
|
||||
}
|
||||
result.GetUsedExtensions().insert(metadata.GetExtension().GetName());
|
||||
result.AddUsedExtension(metadata.GetExtension());
|
||||
for (auto &&includeFile : metadata.GetMetadata().includeFiles) {
|
||||
result.GetUsedIncludeFiles().insert(includeFile);
|
||||
result.AddUsedIncludeFiles(includeFile);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -39,12 +51,12 @@ void UsedExtensionsFinder::DoVisitObject(gd::Object &object) {
|
||||
void UsedExtensionsFinder::DoVisitBehavior(gd::Behavior &behavior) {
|
||||
auto metadata = gd::MetadataProvider::GetExtensionAndBehaviorMetadata(
|
||||
project.GetCurrentPlatform(), behavior.GetTypeName());
|
||||
result.GetUsedExtensions().insert(metadata.GetExtension().GetName());
|
||||
result.AddUsedExtension(metadata.GetExtension());
|
||||
for (auto &&includeFile : metadata.GetMetadata().includeFiles) {
|
||||
result.GetUsedIncludeFiles().insert(includeFile);
|
||||
result.AddUsedIncludeFiles(includeFile);
|
||||
}
|
||||
for (auto &&includeFile : metadata.GetMetadata().requiredFiles) {
|
||||
result.GetUsedRequiredFiles().insert(includeFile);
|
||||
result.AddUsedRequiredFiles(includeFile);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -57,9 +69,9 @@ bool UsedExtensionsFinder::DoVisitInstruction(gd::Instruction& instruction,
|
||||
project.GetCurrentPlatform(), instruction.GetType())
|
||||
: gd::MetadataProvider::GetExtensionAndActionMetadata(
|
||||
project.GetCurrentPlatform(), instruction.GetType());
|
||||
result.GetUsedExtensions().insert(metadata.GetExtension().GetName());
|
||||
result.AddUsedExtension(metadata.GetExtension());
|
||||
for (auto&& includeFile : metadata.GetMetadata().GetIncludeFiles()) {
|
||||
result.GetUsedIncludeFiles().insert(includeFile);
|
||||
result.AddUsedIncludeFiles(includeFile);
|
||||
}
|
||||
|
||||
gd::ParameterMetadataTools::IterateOverParameters(
|
||||
@@ -77,7 +89,7 @@ bool UsedExtensionsFinder::DoVisitInstruction(gd::Instruction& instruction,
|
||||
rootType = "number";
|
||||
parameterValue.GetRootNode()->Visit(*this);
|
||||
} else if (gd::ParameterMetadata::IsExpression("variable", parameterType))
|
||||
result.GetUsedExtensions().insert("BuiltinVariables");
|
||||
result.AddUsedBuiltinExtension("BuiltinVariables");
|
||||
});
|
||||
|
||||
return false;
|
||||
@@ -110,7 +122,7 @@ void UsedExtensionsFinder::OnVisitUnaryOperatorNode(UnaryOperatorNode& node) {
|
||||
|
||||
// Add variable extension and visit sub-expressions on variable nodes
|
||||
void UsedExtensionsFinder::OnVisitVariableNode(VariableNode& node) {
|
||||
result.GetUsedExtensions().insert("BuiltinVariables");
|
||||
result.AddUsedBuiltinExtension("BuiltinVariables");
|
||||
|
||||
auto type = gd::ExpressionTypeFinder::GetType(
|
||||
project.GetCurrentPlatform(), GetProjectScopedContainers(), rootType, node);
|
||||
@@ -123,9 +135,9 @@ void UsedExtensionsFinder::OnVisitVariableNode(VariableNode& node) {
|
||||
// This represents an object.
|
||||
auto metadata = gd::MetadataProvider::GetExtensionAndObjectMetadata(
|
||||
project.GetCurrentPlatform(), node.name);
|
||||
result.GetUsedExtensions().insert(metadata.GetExtension().GetName());
|
||||
result.AddUsedExtension(metadata.GetExtension());
|
||||
for (auto &&includeFile : metadata.GetMetadata().includeFiles) {
|
||||
result.GetUsedIncludeFiles().insert(includeFile);
|
||||
result.AddUsedIncludeFiles(includeFile);
|
||||
}
|
||||
}, [&]() {
|
||||
// This is a variable.
|
||||
@@ -143,13 +155,13 @@ void UsedExtensionsFinder::OnVisitVariableNode(VariableNode& node) {
|
||||
|
||||
void UsedExtensionsFinder::OnVisitVariableAccessorNode(
|
||||
VariableAccessorNode& node) {
|
||||
result.GetUsedExtensions().insert("BuiltinVariables");
|
||||
result.AddUsedBuiltinExtension("BuiltinVariables");
|
||||
if (node.child) node.child->Visit(*this);
|
||||
};
|
||||
|
||||
void UsedExtensionsFinder::OnVisitVariableBracketAccessorNode(
|
||||
VariableBracketAccessorNode& node) {
|
||||
result.GetUsedExtensions().insert("BuiltinVariables");
|
||||
result.AddUsedBuiltinExtension("BuiltinVariables");
|
||||
node.expression->Visit(*this);
|
||||
if (node.child) node.child->Visit(*this);
|
||||
};
|
||||
@@ -163,9 +175,9 @@ void UsedExtensionsFinder::OnVisitIdentifierNode(IdentifierNode &node) {
|
||||
// An object or object variable is used.
|
||||
auto metadata = gd::MetadataProvider::GetExtensionAndObjectMetadata(
|
||||
project.GetCurrentPlatform(), node.identifierName);
|
||||
result.GetUsedExtensions().insert(metadata.GetExtension().GetName());
|
||||
result.AddUsedExtension(metadata.GetExtension());
|
||||
for (auto &&includeFile : metadata.GetMetadata().includeFiles) {
|
||||
result.GetUsedIncludeFiles().insert(includeFile);
|
||||
result.AddUsedIncludeFiles(includeFile);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -187,9 +199,9 @@ void UsedExtensionsFinder::OnVisitFunctionCallNode(FunctionCallNode& node) {
|
||||
return;
|
||||
}
|
||||
|
||||
result.GetUsedExtensions().insert(metadata.GetExtension().GetName());
|
||||
result.AddUsedExtension(metadata.GetExtension());
|
||||
for (auto&& includeFile : metadata.GetMetadata().GetIncludeFiles()) {
|
||||
result.GetUsedIncludeFiles().insert(includeFile);
|
||||
result.AddUsedIncludeFiles(includeFile);
|
||||
}
|
||||
};
|
||||
|
||||
|
@@ -9,6 +9,8 @@
|
||||
#include <set>
|
||||
|
||||
#include "GDCore/Events/Parsers/ExpressionParser2NodeWorker.h"
|
||||
#include "GDCore/Extensions/Metadata/SourceFileMetadata.h"
|
||||
#include "GDCore/Extensions/PlatformExtension.h"
|
||||
#include "GDCore/IDE/Events/ArbitraryEventsWorker.h"
|
||||
#include "GDCore/IDE/Project/ArbitraryObjectsWorker.h"
|
||||
#include "GDCore/String.h"
|
||||
@@ -44,6 +46,10 @@ public:
|
||||
return usedRequiredFiles;
|
||||
}
|
||||
|
||||
const std::vector<gd::SourceFileMetadata>& GetUsedSourceFiles() const {
|
||||
return usedSourceFiles;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Return true when at least 1 object uses the 3D renderer.
|
||||
*/
|
||||
@@ -51,20 +57,10 @@ public:
|
||||
return has3DObjects;
|
||||
}
|
||||
|
||||
/**
|
||||
* The extensions used by the project (or part of it).
|
||||
*/
|
||||
std::set<gd::String> &GetUsedExtensions() { return usedExtensions; }
|
||||
|
||||
/**
|
||||
* The include files used at runtime by the project (or part of it).
|
||||
*/
|
||||
std::set<gd::String> &GetUsedIncludeFiles() { return usedIncludeFiles; }
|
||||
|
||||
/**
|
||||
* The additional files required at runtime by the project (or part of it).
|
||||
*/
|
||||
std::set<gd::String> &GetUsedRequiredFiles() { return usedRequiredFiles; }
|
||||
void AddUsedExtension(const gd::PlatformExtension& extension);
|
||||
void AddUsedBuiltinExtension(const gd::String& extensionName);
|
||||
void AddUsedIncludeFiles(const gd::String& includeFile) { usedIncludeFiles.insert(includeFile); }
|
||||
void AddUsedRequiredFiles(const gd::String& requiredFile) { usedRequiredFiles.insert(requiredFile); }
|
||||
|
||||
void MarkAsHaving3DObjects() {
|
||||
has3DObjects = true;
|
||||
@@ -74,6 +70,7 @@ private:
|
||||
std::set<gd::String> usedExtensions;
|
||||
std::set<gd::String> usedIncludeFiles;
|
||||
std::set<gd::String> usedRequiredFiles;
|
||||
std::vector<gd::SourceFileMetadata> usedSourceFiles;
|
||||
bool has3DObjects = false;
|
||||
};
|
||||
|
||||
|
@@ -24,15 +24,16 @@ void EventsFunctionTools::FreeEventsFunctionToObjectsContainer(
|
||||
const gd::EventsFunction& eventsFunction,
|
||||
gd::ObjectsContainer& outputObjectsContainer) {
|
||||
// Functions scope for objects is defined according
|
||||
// to parameters
|
||||
outputObjectsContainer.GetObjects().clear();
|
||||
outputObjectsContainer.GetObjectGroups().Clear();
|
||||
|
||||
// to parameters.
|
||||
auto ¶meters = eventsFunction.GetParametersForEvents(functionContainer);
|
||||
gd::ParameterMetadataTools::ParametersToObjectsContainer(
|
||||
project,
|
||||
parameters,
|
||||
outputObjectsContainer);
|
||||
|
||||
// TODO: in theory we should ensure stability of the groups across calls
|
||||
// to this function. BUT groups in functions should probably have never been
|
||||
// supported, so we're phasing this out in the UI.
|
||||
outputObjectsContainer.GetObjectGroups() = eventsFunction.GetObjectGroups();
|
||||
}
|
||||
|
||||
@@ -97,26 +98,6 @@ void EventsFunctionTools::ObjectEventsFunctionToObjectsContainer(
|
||||
"for the parent. ");
|
||||
return;
|
||||
}
|
||||
|
||||
gd::EventsFunctionTools::CopyEventsBasedObjectChildrenToObjectsContainer(
|
||||
eventsBasedObject, outputObjectsContainer);
|
||||
}
|
||||
|
||||
void EventsFunctionTools::CopyEventsBasedObjectChildrenToObjectsContainer(
|
||||
const gd::EventsBasedObject& eventsBasedObject,
|
||||
gd::ObjectsContainer& outputObjectsContainer) {
|
||||
auto &children = eventsBasedObject.GetObjects().GetObjects();
|
||||
for (auto &childObject : children) {
|
||||
auto child = childObject.get();
|
||||
outputObjectsContainer.InsertObject(
|
||||
*child, outputObjectsContainer.GetObjectsCount());
|
||||
}
|
||||
auto &childrenGroups = eventsBasedObject.GetObjects().GetObjectGroups();
|
||||
for (size_t index = 0; index < childrenGroups.Count(); ++index) {
|
||||
auto &childGroup = childrenGroups.Get(index);
|
||||
outputObjectsContainer.GetObjectGroups().Insert(
|
||||
childGroup, outputObjectsContainer.GetObjectGroups().Count());
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace gd
|
||||
|
@@ -68,9 +68,5 @@ class GD_CORE_API EventsFunctionTools {
|
||||
const gd::EventsBasedObject& eventsBasedObject,
|
||||
const gd::EventsFunction& eventsFunction,
|
||||
gd::ObjectsContainer& outputObjectsContainer);
|
||||
|
||||
static void CopyEventsBasedObjectChildrenToObjectsContainer(
|
||||
const gd::EventsBasedObject &eventsBasedObject,
|
||||
gd::ObjectsContainer &outputObjectsContainer);
|
||||
};
|
||||
} // namespace gd
|
||||
|
@@ -62,6 +62,11 @@ void ArbitraryResourceWorker::ExposeSpine(gd::String& resourceName){
|
||||
// do.
|
||||
};
|
||||
|
||||
void ArbitraryResourceWorker::ExposeJavaScript(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.
|
||||
@@ -195,6 +200,10 @@ void ArbitraryResourceWorker::ExposeResourceWithType(
|
||||
ExposeSpine(resourceName);
|
||||
return;
|
||||
}
|
||||
if (resourceType == "javascript") {
|
||||
ExposeJavaScript(resourceName);
|
||||
return;
|
||||
}
|
||||
gd::LogError("Unexpected resource type: " + resourceType + " for: " + resourceName);
|
||||
return;
|
||||
}
|
||||
|
@@ -96,7 +96,7 @@ 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.
|
||||
*/
|
||||
@@ -112,6 +112,11 @@ public:
|
||||
*/
|
||||
virtual void ExposeVideo(gd::String &videoName);
|
||||
|
||||
/**
|
||||
* \brief Expose a JavaScript file, which is always a reference to a "javascript" resource.
|
||||
*/
|
||||
virtual void ExposeJavaScript(gd::String &javaScriptName);
|
||||
|
||||
/**
|
||||
* \brief Expose a bitmap font, which is always a reference to a "bitmapFont" resource.
|
||||
*/
|
||||
|
@@ -38,6 +38,10 @@ void AssetResourcePathCleaner::ExposeVideo(gd::String &videoName) {
|
||||
ExposeResourceAsFile(videoName);
|
||||
}
|
||||
|
||||
void AssetResourcePathCleaner::ExposeJavaScript(gd::String &javaScriptResourceName) {
|
||||
ExposeResourceAsFile(javaScriptResourceName);
|
||||
}
|
||||
|
||||
void AssetResourcePathCleaner::ExposeBitmapFont(gd::String &bitmapFontName) {
|
||||
ExposeResourceAsFile(bitmapFontName);
|
||||
}
|
||||
|
@@ -46,6 +46,7 @@ public:
|
||||
void ExposeTileset(gd::String &tilesetName) override;
|
||||
void ExposeVideo(gd::String &videoName) override;
|
||||
void ExposeBitmapFont(gd::String &bitmapFontName) override;
|
||||
void ExposeJavaScript(gd::String &javaScriptResourceName) override;
|
||||
void ExposeFile(gd::String &resource) override;
|
||||
|
||||
protected:
|
||||
|
@@ -73,6 +73,9 @@ public:
|
||||
virtual void ExposeVideo(gd::String& otherResourceName) override {
|
||||
MatchResourceName(otherResourceName);
|
||||
};
|
||||
virtual void ExposeJavaScript(gd::String& otherResourceName) override {
|
||||
MatchResourceName(otherResourceName);
|
||||
};
|
||||
virtual void ExposeBitmapFont(gd::String& otherResourceName) override {
|
||||
MatchResourceName(otherResourceName);
|
||||
};
|
||||
|
@@ -60,6 +60,7 @@ public:
|
||||
if (resourceType == "model3D") return allModel3Ds;
|
||||
if (resourceType == "atlas") return allAtlases;
|
||||
if (resourceType == "spine") return allSpines;
|
||||
if (resourceType == "javascript") return allJavaScripts;
|
||||
|
||||
return emptyResources;
|
||||
};
|
||||
@@ -88,6 +89,9 @@ public:
|
||||
virtual void ExposeVideo(gd::String& resourceName) override {
|
||||
allVideos.insert(resourceName);
|
||||
};
|
||||
virtual void ExposeJavaScript(gd::String& resourceName) override {
|
||||
allJavaScripts.insert(resourceName);
|
||||
};
|
||||
virtual void ExposeBitmapFont(gd::String& resourceName) override {
|
||||
allBitmapFonts.insert(resourceName);
|
||||
};
|
||||
@@ -114,6 +118,7 @@ public:
|
||||
std::set<gd::String> allModel3Ds;
|
||||
std::set<gd::String> allAtlases;
|
||||
std::set<gd::String> allSpines;
|
||||
std::set<gd::String> allJavaScripts;
|
||||
std::set<gd::String> emptyResources;
|
||||
|
||||
static const std::vector<gd::String> resourceTypes;
|
||||
|
@@ -59,6 +59,9 @@ class ResourcesRenamer : public gd::ArbitraryResourceWorker {
|
||||
virtual void ExposeVideo(gd::String& videoResourceName) override {
|
||||
RenameIfNeeded(videoResourceName);
|
||||
};
|
||||
virtual void ExposeJavaScript(gd::String& javaScriptResourceName) override {
|
||||
RenameIfNeeded(javaScriptResourceName);
|
||||
};
|
||||
virtual void ExposeBitmapFont(gd::String& bitmapFontName) override {
|
||||
RenameIfNeeded(bitmapFontName);
|
||||
};
|
||||
|
@@ -74,6 +74,9 @@ private:
|
||||
void ExposeVideo(gd::String &videoResourceName) override {
|
||||
AddUsedResource(videoResourceName);
|
||||
};
|
||||
void ExposeJavaScript(gd::String &javaScriptResourceName) override {
|
||||
AddUsedResource(javaScriptResourceName);
|
||||
};
|
||||
void ExposeBitmapFont(gd::String &bitmapFontName) override {
|
||||
AddUsedResource(bitmapFontName);
|
||||
};
|
||||
|
@@ -26,8 +26,8 @@ namespace gd {
|
||||
|
||||
void ProjectBrowserHelper::ExposeProjectEvents(
|
||||
gd::Project &project, gd::ArbitraryEventsWorker &worker) {
|
||||
// See also gd::Project::ExposeResources for a method that traverses the whole
|
||||
// project (this time for resources).
|
||||
// See also gd::ResourceExposer::ExposeWholeProjectResources
|
||||
// for a method that traverses the whole project (this time for resources).
|
||||
|
||||
ExposeProjectEventsWithoutExtensions(project, worker);
|
||||
|
||||
@@ -106,16 +106,16 @@ void ProjectBrowserHelper::ExposeLayoutEventsAndDependencies(
|
||||
}
|
||||
for (const gd::String& sceneName : dependenciesAnalyzer.GetScenesDependencies()) {
|
||||
gd::Layout& dependencyLayout = project.GetLayout(sceneName);
|
||||
|
||||
|
||||
worker.Launch(dependencyLayout.GetEvents());
|
||||
}
|
||||
}
|
||||
|
||||
void ProjectBrowserHelper::ExposeProjectEvents(
|
||||
gd::Project &project, gd::ArbitraryEventsWorkerWithContext &worker) {
|
||||
// See also gd::Project::ExposeResources for a method that traverse the whole
|
||||
// project (this time for resources) and ExposeProjectEffects (this time for
|
||||
// effects).
|
||||
// See also gd::ResourceExposer::ExposeWholeProjectResources
|
||||
// for a method that traverses the whole project (this time for resources)
|
||||
// and ExposeProjectEffects (this time for effects).
|
||||
|
||||
// Add layouts events
|
||||
for (std::size_t s = 0; s < project.GetLayoutsCount(); s++) {
|
||||
@@ -170,7 +170,8 @@ void ProjectBrowserHelper::ExposeEventsFunctionsExtensionEvents(
|
||||
gd::ArbitraryEventsWorkerWithContext &worker) {
|
||||
// Add (free) events functions
|
||||
for (auto &&eventsFunction : eventsFunctionsExtension.GetInternalVector()) {
|
||||
gd::ObjectsContainer parameterObjectsContainer;
|
||||
gd::ObjectsContainer parameterObjectsContainer(
|
||||
gd::ObjectsContainer::SourceType::Function);
|
||||
auto projectScopedContainers = gd::ProjectScopedContainers::
|
||||
MakeNewProjectScopedContainersForFreeEventsFunction(
|
||||
project, eventsFunctionsExtension, *eventsFunction,
|
||||
@@ -209,7 +210,8 @@ void ProjectBrowserHelper::ExposeEventsBasedBehaviorEvents(
|
||||
auto &behaviorEventsFunctions = eventsBasedBehavior.GetEventsFunctions();
|
||||
for (auto &&eventsFunction : behaviorEventsFunctions.GetInternalVector()) {
|
||||
|
||||
gd::ObjectsContainer parameterObjectsContainers;
|
||||
gd::ObjectsContainer parameterObjectsContainers(
|
||||
gd::ObjectsContainer::SourceType::Function);
|
||||
auto projectScopedContainers = gd::ProjectScopedContainers::
|
||||
MakeNewProjectScopedContainersForBehaviorEventsFunction(
|
||||
project, eventsFunctionsExtension, eventsBasedBehavior,
|
||||
@@ -236,7 +238,8 @@ void ProjectBrowserHelper::ExposeEventsBasedObjectEvents(
|
||||
auto &objectEventsFunctions = eventsBasedObject.GetEventsFunctions();
|
||||
for (auto &&eventsFunction : objectEventsFunctions.GetInternalVector()) {
|
||||
|
||||
gd::ObjectsContainer parameterObjectsContainers;
|
||||
gd::ObjectsContainer parameterObjectsContainers(
|
||||
gd::ObjectsContainer::SourceType::Function);
|
||||
auto projectScopedContainers = gd::ProjectScopedContainers::
|
||||
MakeNewProjectScopedContainersForObjectEventsFunction(
|
||||
project, eventsFunctionsExtension, eventsBasedObject,
|
||||
|
@@ -5,21 +5,22 @@
|
||||
*/
|
||||
#include "ResourceExposer.h"
|
||||
|
||||
#include "GDCore/Extensions/Metadata/EffectMetadata.h"
|
||||
#include "GDCore/Extensions/Metadata/MetadataProvider.h"
|
||||
#include "GDCore/Extensions/Platform.h"
|
||||
#include "GDCore/IDE/Events/ArbitraryEventsWorker.h"
|
||||
#include "GDCore/IDE/Project/ArbitraryResourceWorker.h"
|
||||
#include "GDCore/IDE/ProjectBrowserHelper.h"
|
||||
#include "GDCore/Project/Effect.h"
|
||||
#include "GDCore/Project/EventsFunctionsExtension.h"
|
||||
#include "GDCore/Project/Layout.h"
|
||||
#include "GDCore/Project/Project.h"
|
||||
#include "GDCore/Project/Effect.h"
|
||||
#include "GDCore/String.h"
|
||||
#include "GDCore/Extensions/Platform.h"
|
||||
#include "GDCore/Extensions/Metadata/MetadataProvider.h"
|
||||
#include "GDCore/Extensions/Metadata/EffectMetadata.h"
|
||||
|
||||
namespace gd {
|
||||
|
||||
void ResourceExposer::ExposeWholeProjectResources(gd::Project& project, gd::ArbitraryResourceWorker& worker) {
|
||||
void ResourceExposer::ExposeWholeProjectResources(
|
||||
gd::Project &project, gd::ArbitraryResourceWorker &worker) {
|
||||
// See also gd::ProjectBrowserHelper::ExposeProjectEvents for a method that
|
||||
// traverse the whole project (this time for events) and ExposeProjectEffects
|
||||
// (this time for effects).
|
||||
@@ -31,13 +32,11 @@ void ResourceExposer::ExposeWholeProjectResources(gd::Project& project, gd::Arbi
|
||||
|
||||
// Expose event resources
|
||||
auto eventWorker = gd::GetResourceWorkerOnEvents(project, worker);
|
||||
gd::ProjectBrowserHelper::ExposeProjectEvents(
|
||||
project, eventWorker);
|
||||
gd::ProjectBrowserHelper::ExposeProjectEvents(project, eventWorker);
|
||||
|
||||
// Expose object configuration resources
|
||||
auto objectWorker = gd::GetResourceWorkerOnObjects(project, worker);
|
||||
gd::ProjectBrowserHelper::ExposeProjectObjects(
|
||||
project, objectWorker);
|
||||
gd::ProjectBrowserHelper::ExposeProjectObjects(project, objectWorker);
|
||||
|
||||
// Expose layer effect resources
|
||||
for (std::size_t layoutIndex = 0; layoutIndex < project.GetLayoutsCount();
|
||||
@@ -52,28 +51,36 @@ void ResourceExposer::ExposeWholeProjectResources(gd::Project& project, gd::Arbi
|
||||
for (size_t effectIndex = 0; effectIndex < effects.GetEffectsCount();
|
||||
effectIndex++) {
|
||||
auto &effect = effects.GetEffect(effectIndex);
|
||||
gd::ResourceExposer::ExposeEffectResources(project.GetCurrentPlatform(),
|
||||
effect, worker);
|
||||
gd::ResourceExposer::ExposeEffectResources(
|
||||
project.GetCurrentPlatform(), effect, worker);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Expose loading screen background image if present
|
||||
auto& loadingScreen = project.GetLoadingScreen();
|
||||
auto &loadingScreen = project.GetLoadingScreen();
|
||||
if (loadingScreen.GetBackgroundImageResourceName() != "")
|
||||
worker.ExposeImage(loadingScreen.GetBackgroundImageResourceName());
|
||||
|
||||
// Expose extension source files
|
||||
for (std::size_t e = 0; e < project.GetEventsFunctionsExtensionsCount();
|
||||
e++) {
|
||||
auto &eventsFunctionsExtension = project.GetEventsFunctionsExtension(e);
|
||||
ExposeExtensionResources(eventsFunctionsExtension, worker);
|
||||
}
|
||||
}
|
||||
|
||||
void ResourceExposer::ExposeProjectResources(gd::Project& project, gd::ArbitraryResourceWorker& worker) {
|
||||
void ResourceExposer::ExposeProjectResources(
|
||||
gd::Project &project, gd::ArbitraryResourceWorker &worker) {
|
||||
// Expose global objects configuration resources
|
||||
auto objectWorker = gd::GetResourceWorkerOnObjects(project, worker);
|
||||
objectWorker.Launch(project.GetObjects());
|
||||
}
|
||||
|
||||
void ResourceExposer::ExposeLayoutResources(
|
||||
gd::Project &project, gd::Layout &layout,
|
||||
gd::Project &project,
|
||||
gd::Layout &layout,
|
||||
gd::ArbitraryResourceWorker &worker) {
|
||||
|
||||
// Expose object configuration resources
|
||||
auto objectWorker = gd::GetResourceWorkerOnObjects(project, worker);
|
||||
gd::ProjectBrowserHelper::ExposeLayoutObjects(layout, objectWorker);
|
||||
@@ -87,15 +94,15 @@ void ResourceExposer::ExposeLayoutResources(
|
||||
for (size_t effectIndex = 0; effectIndex < effects.GetEffectsCount();
|
||||
effectIndex++) {
|
||||
auto &effect = effects.GetEffect(effectIndex);
|
||||
gd::ResourceExposer::ExposeEffectResources(project.GetCurrentPlatform(),
|
||||
effect, worker);
|
||||
gd::ResourceExposer::ExposeEffectResources(
|
||||
project.GetCurrentPlatform(), effect, worker);
|
||||
}
|
||||
}
|
||||
|
||||
// Expose event resources
|
||||
auto eventWorker = gd::GetResourceWorkerOnEvents(project, worker);
|
||||
gd::ProjectBrowserHelper::ExposeLayoutEventsAndDependencies(project, layout,
|
||||
eventWorker);
|
||||
gd::ProjectBrowserHelper::ExposeLayoutEventsAndDependencies(
|
||||
project, layout, eventWorker);
|
||||
|
||||
// Exposed extension event resources
|
||||
// Note that using resources in extensions is very unlikely and probably not
|
||||
@@ -103,12 +110,14 @@ void ResourceExposer::ExposeLayoutResources(
|
||||
for (std::size_t e = 0; e < project.GetEventsFunctionsExtensionsCount();
|
||||
e++) {
|
||||
auto &eventsFunctionsExtension = project.GetEventsFunctionsExtension(e);
|
||||
gd::ProjectBrowserHelper::ExposeEventsFunctionsExtensionEvents(project, eventsFunctionsExtension, eventWorker);
|
||||
gd::ProjectBrowserHelper::ExposeEventsFunctionsExtensionEvents(
|
||||
project, eventsFunctionsExtension, eventWorker);
|
||||
}
|
||||
}
|
||||
|
||||
void ResourceExposer::ExposeEffectResources(
|
||||
gd::Platform &platform, gd::Effect &effect,
|
||||
gd::Platform &platform,
|
||||
gd::Effect &effect,
|
||||
gd::ArbitraryResourceWorker &worker) {
|
||||
auto &effectMetadata =
|
||||
MetadataProvider::GetEffectMetadata(platform, effect.GetEffectType());
|
||||
@@ -127,11 +136,20 @@ void ResourceExposer::ExposeEffectResources(
|
||||
worker.ExposeResourceWithType(resourceType,
|
||||
potentiallyUpdatedResourceName);
|
||||
if (potentiallyUpdatedResourceName != resourceName) {
|
||||
effect.SetStringParameter(propertyName, potentiallyUpdatedResourceName);
|
||||
effect.SetStringParameter(propertyName,
|
||||
potentiallyUpdatedResourceName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace gd
|
||||
void ResourceExposer::ExposeExtensionResources(
|
||||
gd::EventsFunctionsExtension &extension,
|
||||
gd::ArbitraryResourceWorker &worker) {
|
||||
for (auto &sourceFile : extension.GetAllSourceFiles()) {
|
||||
worker.ExposeJavaScript(sourceFile.GetResourceName());
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace gd
|
||||
|
@@ -9,9 +9,10 @@ namespace gd {
|
||||
class Platform;
|
||||
class Project;
|
||||
class ArbitraryResourceWorker;
|
||||
class EventsFunctionsExtension;
|
||||
class Effect;
|
||||
class Layout;
|
||||
} // namespace gd
|
||||
} // namespace gd
|
||||
|
||||
namespace gd {
|
||||
|
||||
@@ -19,7 +20,7 @@ namespace gd {
|
||||
* \brief
|
||||
*/
|
||||
class GD_CORE_API ResourceExposer {
|
||||
public:
|
||||
public:
|
||||
/**
|
||||
* \brief Called ( e.g. during compilation ) so as to inventory internal
|
||||
* resources, sometimes update their filename or any other work or resources.
|
||||
@@ -34,7 +35,7 @@ public:
|
||||
|
||||
/**
|
||||
* @brief Expose only the resources used globally on a project.
|
||||
*
|
||||
*
|
||||
* It doesn't include resources used in layouts.
|
||||
*/
|
||||
static void ExposeProjectResources(gd::Project &project,
|
||||
@@ -42,17 +43,25 @@ public:
|
||||
|
||||
/**
|
||||
* @brief Expose the resources used in a given layout.
|
||||
*
|
||||
*
|
||||
* It doesn't include resources used globally.
|
||||
*/
|
||||
static void ExposeLayoutResources(gd::Project &project, gd::Layout &layout,
|
||||
gd::ArbitraryResourceWorker &worker);
|
||||
static void ExposeLayoutResources(gd::Project &project,
|
||||
gd::Layout &layout,
|
||||
gd::ArbitraryResourceWorker &worker);
|
||||
|
||||
/**
|
||||
* @brief Expose the resources used in a given effect.
|
||||
*/
|
||||
static void ExposeEffectResources(gd::Platform &platform, gd::Effect &effect,
|
||||
static void ExposeEffectResources(gd::Platform &platform,
|
||||
gd::Effect &effect,
|
||||
gd::ArbitraryResourceWorker &worker);
|
||||
|
||||
/**
|
||||
* @brief Expose the resources used in an extension.
|
||||
*/
|
||||
static void ExposeExtensionResources(gd::EventsFunctionsExtension &extension,
|
||||
gd::ArbitraryResourceWorker &worker);
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
} // namespace gd
|
||||
|
@@ -19,7 +19,7 @@
|
||||
#include "GDCore/IDE/Events/BehaviorTypeRenamer.h"
|
||||
#include "GDCore/IDE/Events/CustomObjectTypeRenamer.h"
|
||||
#include "GDCore/IDE/Events/EventsBehaviorRenamer.h"
|
||||
#include "GDCore/IDE/Events/EventsLeaderboardsRenamer.h"
|
||||
#include "GDCore/IDE/Events/EventsParameterReplacer.h"
|
||||
#include "GDCore/IDE/Events/EventsPropertyReplacer.h"
|
||||
#include "GDCore/IDE/Events/EventsRefactorer.h"
|
||||
#include "GDCore/IDE/Events/EventsVariableInstructionTypeSwitcher.h"
|
||||
@@ -817,6 +817,51 @@ void WholeProjectRefactorer::RenameObjectEventsFunction(
|
||||
}
|
||||
}
|
||||
|
||||
void WholeProjectRefactorer::RenameParameter(
|
||||
gd::Project &project, gd::ProjectScopedContainers &projectScopedContainers,
|
||||
gd::EventsFunction &eventsFunction,
|
||||
const gd::ObjectsContainer ¶meterObjectsContainer,
|
||||
const gd::String &oldParameterName, const gd::String &newParameterName) {
|
||||
auto ¶meters = eventsFunction.GetParameters();
|
||||
if (!parameters.HasParameterNamed(oldParameterName))
|
||||
return;
|
||||
auto ¶meter = parameters.GetParameter(oldParameterName);
|
||||
if (parameter.GetValueTypeMetadata().IsObject()) {
|
||||
gd::WholeProjectRefactorer::ObjectOrGroupRenamedInEventsFunction(
|
||||
project, projectScopedContainers, eventsFunction,
|
||||
parameterObjectsContainer, oldParameterName, newParameterName, false);
|
||||
} else if (parameter.GetValueTypeMetadata().IsBehavior()) {
|
||||
size_t behaviorParameterIndex = parameters.GetParameterPosition(parameter);
|
||||
size_t objectParameterIndex =
|
||||
gd::ParameterMetadataTools::GetObjectParameterIndexFor(
|
||||
parameters, behaviorParameterIndex);
|
||||
if (objectParameterIndex == gd::String::npos) {
|
||||
return;
|
||||
}
|
||||
const gd::String &objectName =
|
||||
parameters.GetParameter(objectParameterIndex).GetName();
|
||||
gd::EventsBehaviorRenamer behaviorRenamer(project.GetCurrentPlatform(),
|
||||
objectName, oldParameterName,
|
||||
newParameterName);
|
||||
behaviorRenamer.Launch(eventsFunction.GetEvents(), projectScopedContainers);
|
||||
} else {
|
||||
// Rename parameter names directly used as an identifier.
|
||||
std::unordered_map<gd::String, gd::String> oldToNewParameterNames = {
|
||||
{oldParameterName, newParameterName}};
|
||||
gd::EventsParameterReplacer eventsParameterReplacer(
|
||||
project.GetCurrentPlatform(), oldToNewParameterNames);
|
||||
eventsParameterReplacer.Launch(eventsFunction.GetEvents(),
|
||||
projectScopedContainers);
|
||||
|
||||
// Rename parameter names in legacy expressions and instructions
|
||||
gd::ProjectElementRenamer projectElementRenamer(
|
||||
project.GetCurrentPlatform(), "functionParameterName", oldParameterName,
|
||||
newParameterName);
|
||||
projectElementRenamer.Launch(eventsFunction.GetEvents(),
|
||||
projectScopedContainers);
|
||||
}
|
||||
}
|
||||
|
||||
void WholeProjectRefactorer::MoveEventsFunctionParameter(
|
||||
gd::Project &project,
|
||||
const gd::EventsFunctionsExtension &eventsFunctionsExtension,
|
||||
@@ -951,6 +996,8 @@ void WholeProjectRefactorer::RenameEventsBasedBehaviorProperty(
|
||||
// Order is important: we first rename the expressions then the
|
||||
// instructions, to avoid being unable to fetch the metadata (the types of
|
||||
// parameters) of instructions after they are renamed.
|
||||
|
||||
// Rename legacy expressions like: Object.Behavior::PropertyMyPropertyName()
|
||||
gd::ExpressionsRenamer expressionRenamer =
|
||||
gd::ExpressionsRenamer(project.GetCurrentPlatform());
|
||||
expressionRenamer.SetReplacedBehaviorExpression(
|
||||
@@ -960,14 +1007,16 @@ void WholeProjectRefactorer::RenameEventsBasedBehaviorProperty(
|
||||
EventsBasedBehavior::GetPropertyExpressionName(newPropertyName));
|
||||
gd::ProjectBrowserHelper::ExposeProjectEvents(project, expressionRenamer);
|
||||
|
||||
// Rename property names directly used as an identifier.
|
||||
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);
|
||||
gd::ProjectBrowserHelper::ExposeEventsBasedBehaviorEvents(
|
||||
project, eventsFunctionsExtension, eventsBasedBehavior,
|
||||
eventsPropertyReplacer);
|
||||
|
||||
gd::InstructionsTypeRenamer actionRenamer = gd::InstructionsTypeRenamer(
|
||||
project,
|
||||
@@ -1022,6 +1071,8 @@ void WholeProjectRefactorer::RenameEventsBasedBehaviorSharedProperty(
|
||||
// Order is important: we first rename the expressions then the
|
||||
// instructions, to avoid being unable to fetch the metadata (the types of
|
||||
// parameters) of instructions after they are renamed.
|
||||
|
||||
// Rename legacy expressions like: Object.Behavior::SharedPropertyMyPropertyName()
|
||||
gd::ExpressionsRenamer expressionRenamer =
|
||||
gd::ExpressionsRenamer(project.GetCurrentPlatform());
|
||||
expressionRenamer.SetReplacedBehaviorExpression(
|
||||
@@ -1031,14 +1082,16 @@ void WholeProjectRefactorer::RenameEventsBasedBehaviorSharedProperty(
|
||||
EventsBasedBehavior::GetSharedPropertyExpressionName(newPropertyName));
|
||||
gd::ProjectBrowserHelper::ExposeProjectEvents(project, expressionRenamer);
|
||||
|
||||
// Rename property names directly used as an identifier.
|
||||
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);
|
||||
gd::ProjectBrowserHelper::ExposeEventsBasedBehaviorEvents(
|
||||
project, eventsFunctionsExtension, eventsBasedBehavior,
|
||||
eventsPropertyReplacer);
|
||||
|
||||
gd::InstructionsTypeRenamer actionRenamer = gd::InstructionsTypeRenamer(
|
||||
project,
|
||||
@@ -1079,6 +1132,8 @@ void WholeProjectRefactorer::RenameEventsBasedObjectProperty(
|
||||
// Order is important: we first rename the expressions then the
|
||||
// instructions, to avoid being unable to fetch the metadata (the types of
|
||||
// parameters) of instructions after they are renamed.
|
||||
|
||||
// Rename legacy expressions like: Object.PropertyMyPropertyName()
|
||||
gd::ExpressionsRenamer expressionRenamer =
|
||||
gd::ExpressionsRenamer(project.GetCurrentPlatform());
|
||||
expressionRenamer.SetReplacedObjectExpression(
|
||||
@@ -1088,14 +1143,16 @@ void WholeProjectRefactorer::RenameEventsBasedObjectProperty(
|
||||
EventsBasedObject::GetPropertyExpressionName(newPropertyName));
|
||||
gd::ProjectBrowserHelper::ExposeProjectEvents(project, expressionRenamer);
|
||||
|
||||
// Rename property names directly used as an identifier.
|
||||
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);
|
||||
gd::ProjectBrowserHelper::ExposeEventsBasedObjectEvents(
|
||||
project, eventsFunctionsExtension, eventsBasedObject,
|
||||
eventsPropertyReplacer);
|
||||
|
||||
gd::InstructionsTypeRenamer actionRenamer = gd::InstructionsTypeRenamer(
|
||||
project,
|
||||
@@ -1694,6 +1751,15 @@ void WholeProjectRefactorer::BehaviorsAddedToObjectInScene(
|
||||
void WholeProjectRefactorer::ObjectOrGroupRenamedInScene(
|
||||
gd::Project &project, gd::Layout &layout, const gd::String &oldName,
|
||||
const gd::String &newName, bool isObjectGroup) {
|
||||
gd::WholeProjectRefactorer::ObjectOrGroupRenamedInScene(
|
||||
project, layout, layout.GetObjects(), oldName, newName, isObjectGroup);
|
||||
}
|
||||
|
||||
void WholeProjectRefactorer::ObjectOrGroupRenamedInScene(
|
||||
gd::Project &project, gd::Layout &layout,
|
||||
const gd::ObjectsContainer &targetedObjectsContainer,
|
||||
const gd::String &oldName, const gd::String &newName, bool isObjectGroup) {
|
||||
|
||||
if (oldName == newName || newName.empty() || oldName.empty())
|
||||
return;
|
||||
|
||||
@@ -1703,7 +1769,7 @@ void WholeProjectRefactorer::ObjectOrGroupRenamedInScene(
|
||||
// Rename object in the current layout
|
||||
gd::EventsRefactorer::RenameObjectInEvents(
|
||||
project.GetCurrentPlatform(), projectScopedContainers, layout.GetEvents(),
|
||||
oldName, newName);
|
||||
layout.GetObjects(), oldName, newName);
|
||||
|
||||
// Object groups can't have instances or be in other groups
|
||||
if (!isObjectGroup) {
|
||||
@@ -1720,7 +1786,7 @@ void WholeProjectRefactorer::ObjectOrGroupRenamedInScene(
|
||||
auto &externalEvents = project.GetExternalEvents(externalEventsName);
|
||||
gd::EventsRefactorer::RenameObjectInEvents(
|
||||
project.GetCurrentPlatform(), projectScopedContainers,
|
||||
externalEvents.GetEvents(), oldName, newName);
|
||||
externalEvents.GetEvents(), layout.GetObjects(), oldName, newName);
|
||||
}
|
||||
|
||||
// Rename object in external layouts
|
||||
@@ -1966,8 +2032,8 @@ void WholeProjectRefactorer::ObjectOrGroupRenamedInEventsBasedObject(
|
||||
eventsBasedObject.GetEventsFunctions().GetInternalVector()) {
|
||||
auto *function = functionUniquePtr.get();
|
||||
WholeProjectRefactorer::ObjectOrGroupRenamedInEventsFunction(
|
||||
project, projectScopedContainers, *function, oldName, newName,
|
||||
isObjectGroup);
|
||||
project, projectScopedContainers, *function,
|
||||
eventsBasedObject.GetObjects(), oldName, newName, isObjectGroup);
|
||||
}
|
||||
|
||||
// Object groups can't have instances or be in other groups
|
||||
@@ -1984,11 +2050,12 @@ void WholeProjectRefactorer::ObjectOrGroupRenamedInEventsBasedObject(
|
||||
void WholeProjectRefactorer::ObjectOrGroupRenamedInEventsFunction(
|
||||
gd::Project &project,
|
||||
const gd::ProjectScopedContainers &projectScopedContainers,
|
||||
gd::EventsFunction &eventsFunction, const gd::String &oldName,
|
||||
const gd::String &newName, bool isObjectGroup) {
|
||||
gd::EventsFunction &eventsFunction,
|
||||
const gd::ObjectsContainer &targetedObjectsContainer,
|
||||
const gd::String &oldName, const gd::String &newName, bool isObjectGroup) {
|
||||
gd::EventsRefactorer::RenameObjectInEvents(
|
||||
project.GetCurrentPlatform(), projectScopedContainers,
|
||||
eventsFunction.GetEvents(), oldName, newName);
|
||||
eventsFunction.GetEvents(), targetedObjectsContainer, oldName, newName);
|
||||
|
||||
// Object groups can't be in other groups
|
||||
if (!isObjectGroup) {
|
||||
@@ -2014,7 +2081,7 @@ void WholeProjectRefactorer::GlobalObjectOrGroupRenamed(
|
||||
if (layout.GetObjects().HasObjectNamed(oldName))
|
||||
continue;
|
||||
|
||||
ObjectOrGroupRenamedInScene(project, layout, oldName, newName,
|
||||
ObjectOrGroupRenamedInScene(project, layout, project.GetObjects(), oldName, newName,
|
||||
isObjectGroup);
|
||||
}
|
||||
}
|
||||
@@ -2149,13 +2216,20 @@ std::vector<gd::String> WholeProjectRefactorer::GetAssociatedExternalEvents(
|
||||
void WholeProjectRefactorer::RenameLeaderboards(
|
||||
gd::Project &project,
|
||||
const std::map<gd::String, gd::String> &leaderboardIdMap) {
|
||||
gd::EventsLeaderboardsRenamer eventsLeaderboardReplacer(project,
|
||||
leaderboardIdMap);
|
||||
gd::ProjectBrowserHelper::ExposeProjectEvents(project,
|
||||
eventsLeaderboardReplacer);
|
||||
|
||||
gd::LeaderboardIdRenamer leaderboardIdRenamer(leaderboardIdMap);
|
||||
gd::LeaderboardIdRenamer leaderboardIdRenamer(project);
|
||||
leaderboardIdRenamer.SetLeaderboardIdsToReplace(leaderboardIdMap);
|
||||
|
||||
gd::ProjectBrowserHelper::ExposeProjectEvents(project, leaderboardIdRenamer);
|
||||
gd::ProjectBrowserHelper::ExposeProjectObjects(project, leaderboardIdRenamer);
|
||||
}
|
||||
|
||||
std::set<gd::String> WholeProjectRefactorer::FindAllLeaderboardIds(gd::Project &project) {
|
||||
gd::LeaderboardIdRenamer leaderboardIdRenamer(project);
|
||||
|
||||
gd::ProjectBrowserHelper::ExposeProjectEvents(project, leaderboardIdRenamer);
|
||||
gd::ProjectBrowserHelper::ExposeProjectObjects(project, leaderboardIdRenamer);
|
||||
|
||||
return leaderboardIdRenamer.GetAllLeaderboardIds();
|
||||
}
|
||||
|
||||
} // namespace gd
|
||||
|
@@ -176,6 +176,21 @@ class GD_CORE_API WholeProjectRefactorer {
|
||||
const gd::String& oldFunctionName,
|
||||
const gd::String& newFunctionName);
|
||||
|
||||
/**
|
||||
* \brief Refactor the function **before** a parameter is renamed.
|
||||
*
|
||||
* \warning Do the renaming of the specified parameter after calling this.
|
||||
* This is because the function is expected to have its old name for the
|
||||
* refactoring.
|
||||
*/
|
||||
static void
|
||||
RenameParameter(gd::Project &project,
|
||||
gd::ProjectScopedContainers &projectScopedContainers,
|
||||
gd::EventsFunction &eventsFunction,
|
||||
const gd::ObjectsContainer ¶meterObjectsContainer,
|
||||
const gd::String &oldParameterName,
|
||||
const gd::String &newParameterName);
|
||||
|
||||
/**
|
||||
* \brief Refactor the project **before** an events function parameter
|
||||
* is moved.
|
||||
@@ -529,6 +544,7 @@ class GD_CORE_API WholeProjectRefactorer {
|
||||
gd::Project& project,
|
||||
const gd::ProjectScopedContainers &projectScopedContainers,
|
||||
gd::EventsFunction& eventsFunction,
|
||||
const gd::ObjectsContainer &targetedObjectsContainer,
|
||||
const gd::String& oldName,
|
||||
const gd::String& newName,
|
||||
bool isObjectGroup);
|
||||
@@ -628,12 +644,17 @@ class GD_CORE_API WholeProjectRefactorer {
|
||||
const gd::String &targetLayerName);
|
||||
|
||||
/**
|
||||
* \brief Replace the leaderboard ids in events and object configurations.
|
||||
* \brief Replace the leaderboard ids in the whole project.
|
||||
*/
|
||||
static void
|
||||
RenameLeaderboards(gd::Project &project,
|
||||
const std::map<gd::String, gd::String> &leaderboardIdMap);
|
||||
|
||||
/**
|
||||
* \brief Find all the leaderboard identifiers in the whole project.
|
||||
*/
|
||||
static std::set<gd::String> FindAllLeaderboardIds(gd::Project &project);
|
||||
|
||||
/**
|
||||
* \brief Return the number of instances on the layer named \a layerName and
|
||||
* all its associated layouts.
|
||||
@@ -644,6 +665,12 @@ class GD_CORE_API WholeProjectRefactorer {
|
||||
virtual ~WholeProjectRefactorer(){};
|
||||
|
||||
private:
|
||||
static void ObjectOrGroupRenamedInScene(gd::Project &project,
|
||||
gd::Layout &scene,
|
||||
const gd::ObjectsContainer &targetedObjectsContainer,
|
||||
const gd::String &oldName,
|
||||
const gd::String &newName,
|
||||
bool isObjectGroup);
|
||||
static std::vector<gd::String> GetAssociatedExternalLayouts(
|
||||
gd::Project& project, gd::Layout& layout);
|
||||
static std::vector<gd::String>
|
||||
|
@@ -23,6 +23,9 @@ void AbstractEventsBasedEntity::SerializeTo(SerializerElement& element) const {
|
||||
element.SetAttribute("description", description);
|
||||
element.SetAttribute("name", name);
|
||||
element.SetAttribute("fullName", fullName);
|
||||
if (isPrivate) {
|
||||
element.SetBoolAttribute("private", isPrivate);
|
||||
}
|
||||
|
||||
gd::SerializerElement& eventsFunctionsElement =
|
||||
element.AddChild("eventsFunctions");
|
||||
@@ -36,6 +39,7 @@ void AbstractEventsBasedEntity::UnserializeFrom(
|
||||
description = element.GetStringAttribute("description");
|
||||
name = element.GetStringAttribute("name");
|
||||
fullName = element.GetStringAttribute("fullName");
|
||||
isPrivate = element.GetBoolAttribute("private");
|
||||
|
||||
const gd::SerializerElement& eventsFunctionsElement =
|
||||
element.GetChild("eventsFunctions");
|
||||
|
@@ -3,8 +3,7 @@
|
||||
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#ifndef GDCORE_ABSTRACTEVENTSBASEDENTITY_H
|
||||
#define GDCORE_ABSTRACTEVENTSBASEDENTITY_H
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include "GDCore/Project/NamedPropertyDescriptor.h"
|
||||
@@ -40,6 +39,21 @@ class GD_CORE_API AbstractEventsBasedEntity {
|
||||
*/
|
||||
AbstractEventsBasedEntity* Clone() const { return new AbstractEventsBasedEntity(*this); };
|
||||
|
||||
/**
|
||||
* \brief Check if the behavior or object is private - it can't be used outside of its
|
||||
* extension.
|
||||
*/
|
||||
bool IsPrivate() const { return isPrivate; }
|
||||
|
||||
/**
|
||||
* \brief Set that the behavior or object is private - it can't be used outside of its
|
||||
* extension.
|
||||
*/
|
||||
AbstractEventsBasedEntity& SetPrivate(bool isPrivate_) {
|
||||
isPrivate = isPrivate_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Get the description of the behavior or object, that is displayed in the
|
||||
* editor.
|
||||
@@ -151,8 +165,7 @@ class GD_CORE_API AbstractEventsBasedEntity {
|
||||
gd::EventsFunctionsContainer eventsFunctionsContainer;
|
||||
gd::PropertiesContainer propertyDescriptors;
|
||||
gd::String extensionName;
|
||||
bool isPrivate = false;
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
|
||||
#endif // GDCORE_ABSTRACTEVENTSBASEDENTITY_H
|
||||
|
@@ -21,9 +21,6 @@ EventsBasedBehavior::EventsBasedBehavior()
|
||||
void EventsBasedBehavior::SerializeTo(SerializerElement& element) const {
|
||||
AbstractEventsBasedEntity::SerializeTo(element);
|
||||
element.SetAttribute("objectType", objectType);
|
||||
if (isPrivate) {
|
||||
element.SetBoolAttribute("private", isPrivate);
|
||||
}
|
||||
sharedPropertyDescriptors.SerializeElementsTo(
|
||||
"propertyDescriptor", element.AddChild("sharedPropertyDescriptors"));
|
||||
if (quickCustomizationVisibility != QuickCustomization::Visibility::Default) {
|
||||
@@ -39,7 +36,6 @@ void EventsBasedBehavior::UnserializeFrom(gd::Project& project,
|
||||
const SerializerElement& element) {
|
||||
AbstractEventsBasedEntity::UnserializeFrom(project, element);
|
||||
objectType = element.GetStringAttribute("objectType");
|
||||
isPrivate = element.GetBoolAttribute("private");
|
||||
sharedPropertyDescriptors.UnserializeElementsFrom(
|
||||
"propertyDescriptor", element.GetChild("sharedPropertyDescriptors"));
|
||||
if (element.HasChild("quickCustomizationVisibility")) {
|
||||
|
@@ -3,8 +3,7 @@
|
||||
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#ifndef GDCORE_EVENTSBASEDBEHAVIOR_H
|
||||
#define GDCORE_EVENTSBASEDBEHAVIOR_H
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include "GDCore/Project/AbstractEventsBasedEntity.h"
|
||||
@@ -75,17 +74,11 @@ class GD_CORE_API EventsBasedBehavior: public AbstractEventsBasedEntity {
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Check if the behavior is private - it can't be used outside of its
|
||||
* \brief Set that the behavior or object is private - it can't be used outside of its
|
||||
* extension.
|
||||
*/
|
||||
bool IsPrivate() const { return isPrivate; }
|
||||
|
||||
/**
|
||||
* \brief Set that the behavior is private - it can't be used outside of its
|
||||
* extension.
|
||||
*/
|
||||
EventsBasedBehavior& SetPrivate(bool _isPrivate) {
|
||||
isPrivate = _isPrivate;
|
||||
EventsBasedBehavior& SetPrivate(bool isPrivate) {
|
||||
AbstractEventsBasedEntity::SetPrivate(isPrivate);
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -149,11 +142,8 @@ class GD_CORE_API EventsBasedBehavior: public AbstractEventsBasedEntity {
|
||||
|
||||
private:
|
||||
gd::String objectType;
|
||||
bool isPrivate = false;
|
||||
gd::PropertiesContainer sharedPropertyDescriptors;
|
||||
QuickCustomization::Visibility quickCustomizationVisibility;
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
|
||||
#endif // GDCORE_EVENTSBASEDBEHAVIOR_H
|
||||
|
@@ -23,7 +23,8 @@ EventsBasedObject::EventsBasedObject()
|
||||
areaMinZ(0),
|
||||
areaMaxX(64),
|
||||
areaMaxY(64),
|
||||
areaMaxZ(64) {
|
||||
areaMaxZ(64),
|
||||
objectsContainer(gd::ObjectsContainer::SourceType::Object) {
|
||||
}
|
||||
|
||||
EventsBasedObject::~EventsBasedObject() {}
|
||||
@@ -90,7 +91,7 @@ void EventsBasedObject::UnserializeFrom(gd::Project& project,
|
||||
}
|
||||
|
||||
initialInstances.UnserializeFrom(element.GetChild("instances"));
|
||||
if (element.HasAttribute("isUsingLegacyInstancesRenderer")) {
|
||||
if (element.HasChild("isUsingLegacyInstancesRenderer")) {
|
||||
isUsingLegacyInstancesRenderer =
|
||||
element.GetBoolAttribute("isUsingLegacyInstancesRenderer", false);
|
||||
}
|
||||
|
@@ -72,6 +72,15 @@ class GD_CORE_API EventsBasedObject: public AbstractEventsBasedEntity {
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Set that the object is private - it can't be used outside of its
|
||||
* extension.
|
||||
*/
|
||||
EventsBasedObject& SetPrivate(bool isPrivate) {
|
||||
AbstractEventsBasedEntity::SetPrivate(isPrivate);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Declare a usage of the 3D renderer.
|
||||
*/
|
||||
|
@@ -87,6 +87,13 @@ void EventsFunctionsExtension::SerializeTo(SerializerElement& element) const {
|
||||
for (auto& dependency : dependencies)
|
||||
SerializeDependencyTo(dependency, dependenciesElement.AddChild(""));
|
||||
|
||||
if (!sourceFiles.empty()) {
|
||||
auto& sourceFilesElement = element.AddChild("sourceFiles");
|
||||
sourceFilesElement.ConsiderAsArray();
|
||||
for (auto& sourceFile : sourceFiles)
|
||||
sourceFile.SerializeTo(sourceFilesElement.AddChild(""));
|
||||
}
|
||||
|
||||
GetGlobalVariables().SerializeTo(element.AddChild("globalVariables"));
|
||||
GetSceneVariables().SerializeTo(element.AddChild("sceneVariables"));
|
||||
|
||||
@@ -159,6 +166,17 @@ void EventsFunctionsExtension::UnserializeExtensionDeclarationFrom(
|
||||
dependencies.push_back(
|
||||
UnserializeDependencyFrom(dependenciesElement.GetChild(i)));
|
||||
|
||||
sourceFiles.clear();
|
||||
if (element.HasChild("sourceFiles")) {
|
||||
const auto& sourceFilesElement = element.GetChild("sourceFiles");
|
||||
sourceFilesElement.ConsiderAsArray();
|
||||
for (size_t i = 0; i < sourceFilesElement.GetChildrenCount(); ++i) {
|
||||
SourceFileMetadata sourceFile;
|
||||
sourceFile.UnserializeFrom(sourceFilesElement.GetChild(i));
|
||||
sourceFiles.push_back(sourceFile);
|
||||
}
|
||||
}
|
||||
|
||||
globalVariables.UnserializeFrom(element.GetChild("globalVariables"));
|
||||
sceneVariables.UnserializeFrom(element.GetChild("sceneVariables"));
|
||||
|
||||
|
@@ -8,6 +8,7 @@
|
||||
#include <vector>
|
||||
|
||||
#include "GDCore/Extensions/Metadata/DependencyMetadata.h"
|
||||
#include "GDCore/Extensions/Metadata/SourceFileMetadata.h"
|
||||
#include "GDCore/Project/EventsBasedBehavior.h"
|
||||
#include "GDCore/Project/EventsBasedObject.h"
|
||||
#include "GDCore/Project/EventsFunctionsContainer.h"
|
||||
@@ -289,6 +290,42 @@ class GD_CORE_API EventsFunctionsExtension : public EventsFunctionsContainer {
|
||||
const gd::String& eventsFunctionName);
|
||||
///@}
|
||||
|
||||
/** \name Source files
|
||||
*/
|
||||
///@{
|
||||
|
||||
/**
|
||||
* \brief Adds a new source file.
|
||||
*/
|
||||
gd::SourceFileMetadata& AddSourceFile() {
|
||||
gd::SourceFileMetadata sourceFile;
|
||||
sourceFiles.push_back(sourceFile);
|
||||
return sourceFiles.back();
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Removes a source file.
|
||||
*/
|
||||
void RemoveSourceFileAt(size_t index) {
|
||||
sourceFiles.erase(sourceFiles.begin() + index);
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Returns the list of source files.
|
||||
*/
|
||||
std::vector<gd::SourceFileMetadata>& GetAllSourceFiles() {
|
||||
return sourceFiles;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Returns the list of source files.
|
||||
*/
|
||||
const std::vector<gd::SourceFileMetadata>& GetAllSourceFiles() const {
|
||||
return sourceFiles;
|
||||
};
|
||||
|
||||
///@}
|
||||
|
||||
private:
|
||||
/**
|
||||
* Initialize object using another object. Used by copy-ctor and assign-op.
|
||||
@@ -336,7 +373,8 @@ class GD_CORE_API EventsFunctionsExtension : public EventsFunctionsContainer {
|
||||
gd::SerializableWithNameList<EventsBasedBehavior> eventsBasedBehaviors;
|
||||
gd::SerializableWithNameList<EventsBasedObject> eventsBasedObjects;
|
||||
std::vector<gd::DependencyMetadata> dependencies;
|
||||
|
||||
std::vector<gd::SourceFileMetadata> sourceFiles;
|
||||
|
||||
gd::VariablesContainer globalVariables;
|
||||
gd::VariablesContainer sceneVariables;
|
||||
};
|
||||
|
@@ -15,6 +15,7 @@ Camera Layer::badCamera;
|
||||
|
||||
Layer::Layer()
|
||||
: renderingType(""),
|
||||
defaultCameraBehavior("top-left-anchored-if-never-moved"),
|
||||
isVisible(true),
|
||||
isLocked(false),
|
||||
isLightingLayer(false),
|
||||
@@ -40,6 +41,9 @@ void Layer::SerializeTo(SerializerElement& element) const {
|
||||
element.SetAttribute("name", GetName());
|
||||
element.SetAttribute("renderingType", GetRenderingType());
|
||||
element.SetAttribute("cameraType", GetCameraType());
|
||||
if (GetDefaultCameraBehavior() != "top-left-anchored-if-never-moved") {
|
||||
element.SetAttribute("defaultCameraBehavior", GetDefaultCameraBehavior());
|
||||
}
|
||||
element.SetAttribute("visibility", GetVisibility());
|
||||
element.SetAttribute("isLocked", IsLocked());
|
||||
element.SetAttribute("isLightingLayer", IsLightingLayer());
|
||||
@@ -80,6 +84,7 @@ void Layer::UnserializeFrom(const SerializerElement& element) {
|
||||
SetName(element.GetStringAttribute("name", "", "Name"));
|
||||
SetRenderingType(element.GetStringAttribute("renderingType", ""));
|
||||
SetCameraType(element.GetStringAttribute("cameraType", "perspective"));
|
||||
SetDefaultCameraBehavior(element.GetStringAttribute("defaultCameraBehavior", "top-left-anchored-if-never-moved"));
|
||||
SetVisibility(element.GetBoolAttribute("visibility", true, "Visibility"));
|
||||
SetLocked(element.GetBoolAttribute("isLocked", false));
|
||||
SetLightingLayer(element.GetBoolAttribute("isLightingLayer", false));
|
||||
|
@@ -109,6 +109,12 @@ class GD_CORE_API Layer {
|
||||
renderingType = renderingType_;
|
||||
}
|
||||
|
||||
const gd::String& GetDefaultCameraBehavior() const { return defaultCameraBehavior; }
|
||||
|
||||
void SetDefaultCameraBehavior(const gd::String& defaultCameraBehavior_) {
|
||||
defaultCameraBehavior = defaultCameraBehavior_;
|
||||
}
|
||||
|
||||
const gd::String& GetCameraType() const { return cameraType; }
|
||||
|
||||
void SetCameraType(const gd::String& cameraType_) {
|
||||
@@ -275,6 +281,7 @@ 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 defaultCameraBehavior;
|
||||
gd::String cameraType;
|
||||
bool isVisible; ///< True if the layer is visible
|
||||
bool isLocked; ///< True if the layer is locked
|
||||
|
@@ -36,7 +36,10 @@ namespace gd {
|
||||
|
||||
gd::BehaviorsSharedData Layout::badBehaviorSharedData("", "");
|
||||
|
||||
Layout::Layout(const Layout& other) { Init(other); }
|
||||
Layout::Layout(const Layout &other)
|
||||
: objectsContainer(gd::ObjectsContainer::SourceType::Scene) {
|
||||
Init(other);
|
||||
}
|
||||
|
||||
Layout& Layout::operator=(const Layout& other) {
|
||||
if (this != &other) Init(other);
|
||||
@@ -53,7 +56,8 @@ Layout::Layout()
|
||||
stopSoundsOnStartup(true),
|
||||
standardSortMethod(true),
|
||||
disableInputWhenNotFocused(true),
|
||||
variables(gd::VariablesContainer::SourceType::Scene) {}
|
||||
variables(gd::VariablesContainer::SourceType::Scene),
|
||||
objectsContainer(gd::ObjectsContainer::SourceType::Scene) {}
|
||||
|
||||
void Layout::SetName(const gd::String& name_) {
|
||||
name = name_;
|
||||
|
@@ -20,8 +20,8 @@ namespace gd {
|
||||
/**
|
||||
* \brief Represents an object group.
|
||||
*
|
||||
* Objects groups do not really contains objects : They are just used in events,
|
||||
* so as to create events which can be applied to several objects.
|
||||
* Objects groups do not really contains objects: they are just used in events,
|
||||
* to create events which can be applied to several objects.
|
||||
*
|
||||
* \ingroup PlatformDefinition
|
||||
*/
|
||||
|
@@ -16,7 +16,9 @@
|
||||
|
||||
namespace gd {
|
||||
|
||||
ObjectsContainer::ObjectsContainer() {
|
||||
ObjectsContainer::ObjectsContainer(
|
||||
const ObjectsContainer::SourceType sourceType_)
|
||||
: sourceType(sourceType_) {
|
||||
rootFolder = gd::make_unique<gd::ObjectFolderOrObject>("__ROOT");
|
||||
}
|
||||
|
||||
@@ -34,6 +36,7 @@ ObjectsContainer& ObjectsContainer::operator=(
|
||||
}
|
||||
|
||||
void ObjectsContainer::Init(const gd::ObjectsContainer& other) {
|
||||
sourceType = other.sourceType;
|
||||
initialObjects = gd::Clone(other.initialObjects);
|
||||
objectGroups = other.objectGroups;
|
||||
// The objects folders are not copied.
|
||||
@@ -205,6 +208,14 @@ void ObjectsContainer::MoveObjectFolderOrObjectToAnotherContainerInFolder(
|
||||
objectFolderOrObject, newParentFolder, newPosition);
|
||||
}
|
||||
|
||||
std::set<gd::String> ObjectsContainer::GetAllObjectNames() const {
|
||||
std::set<gd::String> names;
|
||||
for (const auto& object : initialObjects) {
|
||||
names.insert(object->GetName());
|
||||
}
|
||||
return names;
|
||||
}
|
||||
|
||||
std::vector<const ObjectFolderOrObject*>
|
||||
ObjectsContainer::GetAllObjectFolderOrObjects() const {
|
||||
std::vector<const ObjectFolderOrObject*> results;
|
||||
|
@@ -3,10 +3,11 @@
|
||||
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#ifndef GDCORE_OBJECTSCONTAINER_H
|
||||
#define GDCORE_OBJECTSCONTAINER_H
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <set>
|
||||
#include "GDCore/String.h"
|
||||
#include "GDCore/Project/ObjectGroupsContainer.h"
|
||||
#include "GDCore/Project/ObjectFolderOrObject.h"
|
||||
@@ -35,15 +36,25 @@ namespace gd {
|
||||
*/
|
||||
class GD_CORE_API ObjectsContainer {
|
||||
public:
|
||||
enum SourceType {
|
||||
Unknown,
|
||||
Global,
|
||||
Scene,
|
||||
Object,
|
||||
Function,
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Default constructor creating a container without any objects.
|
||||
* \brief Constructor creating a container without any objects.
|
||||
*/
|
||||
ObjectsContainer();
|
||||
ObjectsContainer(const SourceType sourceType);
|
||||
virtual ~ObjectsContainer();
|
||||
|
||||
|
||||
ObjectsContainer(const ObjectsContainer&);
|
||||
ObjectsContainer& operator=(const ObjectsContainer& rhs);
|
||||
|
||||
SourceType GetSourceType() const { return sourceType; }
|
||||
|
||||
/** \name Objects management
|
||||
* Members functions related to objects management.
|
||||
*/
|
||||
@@ -57,7 +68,7 @@ class GD_CORE_API ObjectsContainer {
|
||||
/**
|
||||
* \brief Return a reference to the object called \a name.
|
||||
*/
|
||||
Object& GetObject(const gd::String& name);
|
||||
gd::Object& GetObject(const gd::String& name);
|
||||
|
||||
/**
|
||||
* \brief Return a reference to the object called \a name.
|
||||
@@ -68,7 +79,7 @@ class GD_CORE_API ObjectsContainer {
|
||||
* \brief Return a reference to the object at position \a index in the objects
|
||||
* list
|
||||
*/
|
||||
Object& GetObject(std::size_t index);
|
||||
gd::Object& GetObject(std::size_t index);
|
||||
|
||||
/**
|
||||
* \brief Return a reference to the object at position \a index in the objects
|
||||
@@ -168,6 +179,8 @@ class GD_CORE_API ObjectsContainer {
|
||||
const std::vector<std::unique_ptr<gd::Object> >& GetObjects() const {
|
||||
return initialObjects;
|
||||
}
|
||||
|
||||
std::set<gd::String> GetAllObjectNames() const;
|
||||
///@}
|
||||
|
||||
/**
|
||||
@@ -232,6 +245,7 @@ class GD_CORE_API ObjectsContainer {
|
||||
gd::ObjectGroupsContainer objectGroups;
|
||||
|
||||
private:
|
||||
SourceType sourceType = Unknown;
|
||||
std::unique_ptr<gd::ObjectFolderOrObject> rootFolder;
|
||||
|
||||
/**
|
||||
@@ -242,5 +256,3 @@ class GD_CORE_API ObjectsContainer {
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
|
||||
#endif // GDCORE_OBJECTSCONTAINER_H
|
||||
|
@@ -416,7 +416,8 @@ gd::String ObjectsContainersList::GetTypeOfObject(
|
||||
return "";
|
||||
}
|
||||
if (objectsContainers.size() == 1) {
|
||||
gd::ObjectsContainer emptyObjectsContainer;
|
||||
gd::ObjectsContainer emptyObjectsContainer(
|
||||
gd::ObjectsContainer::SourceType::Unknown);
|
||||
return gd::GetTypeOfObject(emptyObjectsContainer, *objectsContainers[0],
|
||||
objectName, true);
|
||||
}
|
||||
@@ -439,7 +440,8 @@ bool ObjectsContainersList::HasBehaviorInObjectOrGroup(
|
||||
return false;
|
||||
}
|
||||
if (objectsContainers.size() == 1) {
|
||||
gd::ObjectsContainer emptyObjectsContainer;
|
||||
gd::ObjectsContainer emptyObjectsContainer(
|
||||
gd::ObjectsContainer::SourceType::Unknown);
|
||||
return gd::HasBehaviorInObjectOrGroup(
|
||||
emptyObjectsContainer, *objectsContainers[0], objectOrGroupName,
|
||||
behaviorName, true);
|
||||
@@ -468,7 +470,8 @@ gd::String ObjectsContainersList::GetTypeOfBehaviorInObjectOrGroup(
|
||||
return "";
|
||||
}
|
||||
if (objectsContainers.size() == 1) {
|
||||
gd::ObjectsContainer emptyObjectsContainer;
|
||||
gd::ObjectsContainer emptyObjectsContainer(
|
||||
gd::ObjectsContainer::SourceType::Unknown);
|
||||
return gd::GetTypeOfBehaviorInObjectOrGroup(
|
||||
emptyObjectsContainer, *objectsContainers[0], objectOrGroupName,
|
||||
behaviorName, searchInGroups);
|
||||
@@ -495,7 +498,8 @@ gd::String ObjectsContainersList::GetTypeOfBehavior(
|
||||
return "";
|
||||
}
|
||||
if (objectsContainers.size() == 1) {
|
||||
gd::ObjectsContainer emptyObjectsContainer;
|
||||
gd::ObjectsContainer emptyObjectsContainer(
|
||||
gd::ObjectsContainer::SourceType::Unknown);
|
||||
return gd::GetTypeOfBehavior(emptyObjectsContainer, *objectsContainers[0],
|
||||
behaviorName, searchInGroups);
|
||||
}
|
||||
@@ -521,7 +525,8 @@ std::vector<gd::String> ObjectsContainersList::GetBehaviorsOfObject(
|
||||
return behaviors;
|
||||
}
|
||||
if (objectsContainers.size() == 1) {
|
||||
gd::ObjectsContainer emptyObjectsContainer;
|
||||
gd::ObjectsContainer emptyObjectsContainer(
|
||||
gd::ObjectsContainer::SourceType::Unknown);
|
||||
return gd::GetBehaviorsOfObject(emptyObjectsContainer,
|
||||
*objectsContainers[0], objectName,
|
||||
searchInGroups);
|
||||
@@ -546,7 +551,8 @@ std::vector<gd::String> ObjectsContainersList::GetBehaviorNamesInObjectOrGroup(
|
||||
return behaviors;
|
||||
}
|
||||
if (objectsContainers.size() == 1) {
|
||||
gd::ObjectsContainer emptyObjectsContainer;
|
||||
gd::ObjectsContainer emptyObjectsContainer(
|
||||
gd::ObjectsContainer::SourceType::Unknown);
|
||||
return gd::GetBehaviorNamesInObjectOrGroup(emptyObjectsContainer,
|
||||
*objectsContainers[0], objectOrGroupName, behaviorType,
|
||||
searchInGroups);
|
||||
@@ -615,6 +621,28 @@ std::vector<gd::String> ObjectsContainersList::GetAnimationNamesOfObject(
|
||||
return animationNames;
|
||||
}
|
||||
|
||||
const ObjectsContainer *
|
||||
ObjectsContainersList::GetObjectsContainerFromObjectName(
|
||||
const gd::String &objectOrGroupName) const {
|
||||
for (auto it = objectsContainers.rbegin(); it != objectsContainers.rend();
|
||||
++it) {
|
||||
if ((*it)->HasObjectNamed(objectOrGroupName) ||
|
||||
(*it)->GetObjectGroups().Has(objectOrGroupName)) {
|
||||
return *it;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const gd::ObjectsContainer::SourceType
|
||||
ObjectsContainersList::GetObjectsContainerSourceType(
|
||||
const gd::String &objectOrGroupName) const {
|
||||
const auto *objectsContainer =
|
||||
GetObjectsContainerFromObjectName(objectOrGroupName);
|
||||
return objectsContainer ? objectsContainer->GetSourceType()
|
||||
: gd::ObjectsContainer::SourceType::Unknown;
|
||||
}
|
||||
|
||||
const gd::ObjectsContainer &
|
||||
ObjectsContainersList::GetObjectsContainer(std::size_t index) const {
|
||||
return *objectsContainers[index];
|
||||
|
@@ -2,12 +2,12 @@
|
||||
#include <vector>
|
||||
|
||||
#include "Variable.h"
|
||||
#include "GDCore/Project/ObjectsContainer.h"
|
||||
|
||||
namespace gd {
|
||||
class String;
|
||||
class Project;
|
||||
class Layout;
|
||||
class ObjectsContainer;
|
||||
class VariablesContainer;
|
||||
class Object;
|
||||
class ObjectConfiguration;
|
||||
@@ -190,8 +190,28 @@ class GD_CORE_API ObjectsContainersList {
|
||||
std::function<void(const gd::String& variableName,
|
||||
const gd::Variable& variable)> fn) const;
|
||||
|
||||
/**
|
||||
* \brief Return the source type of the container for the specified object or
|
||||
* group of objects.
|
||||
*/
|
||||
const gd::ObjectsContainer::SourceType GetObjectsContainerSourceType(
|
||||
const gd::String& objectOrGroupName) const;
|
||||
|
||||
/**
|
||||
* Get the objects container for for the specified object or group of objects.
|
||||
*/
|
||||
const ObjectsContainer *
|
||||
GetObjectsContainerFromObjectName(const gd::String &objectOrGroupName) const;
|
||||
|
||||
/**
|
||||
* \brief Return a the objects container at position \a index.
|
||||
*
|
||||
* \warning The returned `ObjectsContainer` may contain cloned objects (in the case of
|
||||
* `ProjectScopedContainers::MakeNewProjectScopedContainersForEventsBasedObject`)
|
||||
* or "fake" objects used by events like parameters. They must not be used to
|
||||
* edit the objects.
|
||||
* Search for "ProjectScopedContainers wrongly containing temporary objects containers or objects"
|
||||
* in the codebase.
|
||||
*/
|
||||
const gd::ObjectsContainer &GetObjectsContainer(std::size_t index) const;
|
||||
|
||||
|
@@ -30,7 +30,6 @@
|
||||
#include "GDCore/Project/ObjectConfiguration.h"
|
||||
#include "GDCore/Project/ObjectGroupsContainer.h"
|
||||
#include "GDCore/Project/ResourcesManager.h"
|
||||
#include "GDCore/Project/SourceFile.h"
|
||||
#include "GDCore/Serialization/Serializer.h"
|
||||
#include "GDCore/Serialization/SerializerElement.h"
|
||||
#include "GDCore/String.h"
|
||||
@@ -67,7 +66,6 @@ Project::Project()
|
||||
isAntialisingEnabledOnMobile(false),
|
||||
projectUuid(""),
|
||||
useDeprecatedZeroAsDefaultZOrder(false),
|
||||
useExternalSourceFiles(false),
|
||||
isPlayableWithKeyboard(false),
|
||||
isPlayableWithGamepad(false),
|
||||
isPlayableWithMobile(false),
|
||||
@@ -75,19 +73,18 @@ Project::Project()
|
||||
gdMajorVersion(gd::VersionWrapper::Major()),
|
||||
gdMinorVersion(gd::VersionWrapper::Minor()),
|
||||
gdBuildVersion(gd::VersionWrapper::Build()),
|
||||
variables(gd::VariablesContainer::SourceType::Global) {}
|
||||
variables(gd::VariablesContainer::SourceType::Global),
|
||||
objectsContainer(gd::ObjectsContainer::SourceType::Global) {}
|
||||
|
||||
Project::~Project() {}
|
||||
|
||||
void Project::ResetProjectUuid() { projectUuid = UUID::MakeUuid4(); }
|
||||
|
||||
std::unique_ptr<gd::Object> Project::CreateObject(
|
||||
const gd::String& objectType, const gd::String& name) const {
|
||||
std::unique_ptr<gd::Object> object = gd::make_unique<Object>(
|
||||
name, objectType, CreateObjectConfiguration(objectType));
|
||||
|
||||
void Project::EnsureObjectDefaultBehaviors(gd::Object& object) const {
|
||||
auto& platform = GetCurrentPlatform();
|
||||
auto& project = *this;
|
||||
auto& objectType = object.GetType();
|
||||
|
||||
auto addDefaultBehavior = [&platform, &project, &object, &objectType](
|
||||
const gd::String& behaviorType) {
|
||||
auto& behaviorMetadata =
|
||||
@@ -97,17 +94,47 @@ std::unique_ptr<gd::Object> Project::CreateObject(
|
||||
" has an unknown default behavior: " + behaviorType);
|
||||
return;
|
||||
}
|
||||
auto* behavior = object->AddNewBehavior(
|
||||
project, behaviorType, behaviorMetadata.GetDefaultName());
|
||||
behavior->SetDefaultBehavior(true);
|
||||
|
||||
const gd::String& behaviorName = behaviorMetadata.GetDefaultName();
|
||||
|
||||
// Check if we can keep a behavior that would have been already set up on the object.
|
||||
if (object.HasBehaviorNamed(behaviorName)) {
|
||||
const auto& behavior = object.GetBehavior(behaviorName);
|
||||
|
||||
if (!behavior.IsDefaultBehavior() || behavior.GetTypeName() != behaviorType) {
|
||||
// Behavior type has changed, remove it so it is re-created.
|
||||
object.RemoveBehavior(behaviorName);
|
||||
}
|
||||
}
|
||||
|
||||
if (!object.HasBehaviorNamed(behaviorName)) {
|
||||
auto* behavior = object.AddNewBehavior(
|
||||
project, behaviorType, behaviorName);
|
||||
behavior->SetDefaultBehavior(true);
|
||||
}
|
||||
};
|
||||
|
||||
auto &objectMetadata =
|
||||
gd::MetadataProvider::GetObjectMetadata(platform, objectType);
|
||||
if (!MetadataProvider::IsBadObjectMetadata(objectMetadata)) {
|
||||
for (auto &behaviorType : objectMetadata.GetDefaultBehaviors()) {
|
||||
// Add all default behaviors.
|
||||
const auto& defaultBehaviorTypes = objectMetadata.GetDefaultBehaviors();
|
||||
for (auto &behaviorType : defaultBehaviorTypes) {
|
||||
addDefaultBehavior(behaviorType);
|
||||
}
|
||||
|
||||
// Ensure there are no default behaviors that would not be required left on the object.
|
||||
for (const auto& behaviorName : object.GetAllBehaviorNames()) {
|
||||
auto& behavior = object.GetBehavior(behaviorName);
|
||||
if (!behavior.IsDefaultBehavior()) {
|
||||
// Non default behaviors are not handled by this function.
|
||||
continue;
|
||||
}
|
||||
|
||||
if (defaultBehaviorTypes.find(behavior.GetTypeName()) == defaultBehaviorTypes.end()) {
|
||||
object.RemoveBehavior(behaviorName);
|
||||
}
|
||||
}
|
||||
}
|
||||
// During project deserialization, event-based object metadata are not yet
|
||||
// generated. Default behaviors will be added by
|
||||
@@ -115,6 +142,14 @@ std::unique_ptr<gd::Object> Project::CreateObject(
|
||||
else if (!project.HasEventsBasedObject(objectType)) {
|
||||
gd::LogWarning("Object: " + name + " has an unknown type: " + objectType);
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<gd::Object> Project::CreateObject(
|
||||
const gd::String& objectType, const gd::String& name) const {
|
||||
std::unique_ptr<gd::Object> object = gd::make_unique<Object>(
|
||||
name, objectType, CreateObjectConfiguration(objectType));
|
||||
|
||||
EnsureObjectDefaultBehaviors(*object);
|
||||
|
||||
return std::move(object);
|
||||
}
|
||||
@@ -705,9 +740,6 @@ void Project::UnserializeFrom(const SerializerElement& element) {
|
||||
loadingScreen.UnserializeFrom(propElement.GetChild("loadingScreen"));
|
||||
watermark.UnserializeFrom(propElement.GetChild("watermark"));
|
||||
|
||||
useExternalSourceFiles =
|
||||
propElement.GetBoolAttribute("useExternalSourceFiles");
|
||||
|
||||
authorIds.clear();
|
||||
auto& authorIdsElement = propElement.GetChild("authorIds");
|
||||
authorIdsElement.ConsiderAsArray();
|
||||
@@ -827,36 +859,7 @@ void Project::UnserializeFrom(const SerializerElement& element) {
|
||||
eventsFunctionsExtensions.clear();
|
||||
const SerializerElement& eventsFunctionsExtensionsElement =
|
||||
element.GetChild("eventsFunctionsExtensions");
|
||||
eventsFunctionsExtensionsElement.ConsiderAsArrayOf(
|
||||
"eventsFunctionsExtension");
|
||||
// First, only unserialize behaviors and objects names.
|
||||
// As event based objects can contains custom behaviors and custom objects,
|
||||
// this allows them to reference EventBasedBehavior and EventBasedObject
|
||||
// respectively.
|
||||
for (std::size_t i = 0;
|
||||
i < eventsFunctionsExtensionsElement.GetChildrenCount();
|
||||
++i) {
|
||||
const SerializerElement& eventsFunctionsExtensionElement =
|
||||
eventsFunctionsExtensionsElement.GetChild(i);
|
||||
|
||||
gd::EventsFunctionsExtension& newEventsFunctionsExtension =
|
||||
InsertNewEventsFunctionsExtension("",
|
||||
GetEventsFunctionsExtensionsCount());
|
||||
newEventsFunctionsExtension.UnserializeExtensionDeclarationFrom(
|
||||
*this, eventsFunctionsExtensionElement);
|
||||
}
|
||||
|
||||
// Then unserialize functions, behaviors and objects content.
|
||||
for (gd::String &extensionName :
|
||||
GetUnserializingOrderExtensionNames(eventsFunctionsExtensionsElement)) {
|
||||
size_t extensionIndex = GetEventsFunctionsExtensionPosition(extensionName);
|
||||
const SerializerElement &eventsFunctionsExtensionElement =
|
||||
eventsFunctionsExtensionsElement.GetChild(extensionIndex);
|
||||
|
||||
eventsFunctionsExtensions.at(extensionIndex)
|
||||
->UnserializeExtensionImplementationFrom(
|
||||
*this, eventsFunctionsExtensionElement);
|
||||
}
|
||||
UnserializeAndInsertExtensionsFrom(eventsFunctionsExtensionsElement);
|
||||
|
||||
objectsContainer.GetObjectGroups().UnserializeFrom(
|
||||
element.GetChild("objectsGroups", 0, "ObjectGroups"));
|
||||
@@ -909,36 +912,86 @@ void Project::UnserializeFrom(const SerializerElement& element) {
|
||||
InsertNewExternalLayout("", GetExternalLayoutsCount());
|
||||
newExternalLayout.UnserializeFrom(externalLayoutElement);
|
||||
}
|
||||
}
|
||||
|
||||
externalSourceFiles.clear();
|
||||
const SerializerElement& externalSourceFilesElement =
|
||||
element.GetChild("externalSourceFiles", 0, "ExternalSourceFiles");
|
||||
externalSourceFilesElement.ConsiderAsArrayOf("sourceFile", "SourceFile");
|
||||
for (std::size_t i = 0; i < externalSourceFilesElement.GetChildrenCount();
|
||||
void Project::UnserializeAndInsertExtensionsFrom(
|
||||
const gd::SerializerElement &eventsFunctionsExtensionsElement) {
|
||||
eventsFunctionsExtensionsElement.ConsiderAsArrayOf(
|
||||
"eventsFunctionsExtension");
|
||||
|
||||
std::map<gd::String, size_t> extensionNameToElementIndex;
|
||||
|
||||
// First, only unserialize behaviors and objects names.
|
||||
// As event based objects can contains custom behaviors and custom objects,
|
||||
// this allows them to reference EventBasedBehavior and EventBasedObject
|
||||
// respectively.
|
||||
for (std::size_t i = 0;
|
||||
i < eventsFunctionsExtensionsElement.GetChildrenCount();
|
||||
++i) {
|
||||
const SerializerElement& sourceFileElement =
|
||||
externalSourceFilesElement.GetChild(i);
|
||||
const SerializerElement& eventsFunctionsExtensionElement =
|
||||
eventsFunctionsExtensionsElement.GetChild(i);
|
||||
const gd::String& name = eventsFunctionsExtensionElement.GetStringAttribute("name");
|
||||
extensionNameToElementIndex[name] = i;
|
||||
|
||||
gd::SourceFile& newSourceFile = InsertNewSourceFile("", "");
|
||||
newSourceFile.UnserializeFrom(sourceFileElement);
|
||||
gd::EventsFunctionsExtension& eventsFunctionsExtension =
|
||||
HasEventsFunctionsExtensionNamed(name)
|
||||
? GetEventsFunctionsExtension(name)
|
||||
: InsertNewEventsFunctionsExtension(
|
||||
name, GetEventsFunctionsExtensionsCount());
|
||||
eventsFunctionsExtension.UnserializeExtensionDeclarationFrom(
|
||||
*this, eventsFunctionsExtensionElement);
|
||||
}
|
||||
|
||||
// Then unserialize functions, behaviors and objects content.
|
||||
for (gd::String &extensionName :
|
||||
GetUnserializingOrderExtensionNames(eventsFunctionsExtensionsElement)) {
|
||||
|
||||
size_t extensionIndex = GetEventsFunctionsExtensionPosition(extensionName);
|
||||
if (extensionIndex == gd::String::npos) {
|
||||
// Should never happen because the extension was added in the first pass.
|
||||
gd::LogError("Can't find extension " + extensionName + " in the list of extensions in second pass of unserialization.");
|
||||
continue;
|
||||
}
|
||||
auto& partiallyLoadedExtension = eventsFunctionsExtensions.at(extensionIndex);
|
||||
|
||||
if (extensionNameToElementIndex.find(extensionName) == extensionNameToElementIndex.end()) {
|
||||
// Should never happen because the extension element is present.
|
||||
gd::LogError("Can't find extension element to unserialize for " + extensionName + " in second pass of unserialization.");
|
||||
continue;
|
||||
}
|
||||
size_t elementIndex = extensionNameToElementIndex[extensionName];
|
||||
const SerializerElement &eventsFunctionsExtensionElement =
|
||||
eventsFunctionsExtensionsElement.GetChild(elementIndex);
|
||||
|
||||
partiallyLoadedExtension
|
||||
->UnserializeExtensionImplementationFrom(
|
||||
*this, eventsFunctionsExtensionElement);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<gd::String> Project::GetUnserializingOrderExtensionNames(
|
||||
const gd::SerializerElement &eventsFunctionsExtensionsElement) {
|
||||
|
||||
// Some extension have custom objects, which have child objects coming from other extension.
|
||||
eventsFunctionsExtensionsElement.ConsiderAsArrayOf(
|
||||
"eventsFunctionsExtension");
|
||||
|
||||
// Some extension have custom objects, which have child objects coming from other extension.
|
||||
// These child objects must be loaded completely before the parent custom obejct can be unserialized.
|
||||
// This implies: an order on the extension unserialization (and no cycles).
|
||||
|
||||
// At the beginning, everything is yet to be loaded.
|
||||
std::map<gd::String, size_t> extensionNameToElementIndex;
|
||||
std::vector<gd::String> remainingExtensionNames(
|
||||
eventsFunctionsExtensions.size());
|
||||
for (std::size_t i = 0; i < eventsFunctionsExtensions.size(); ++i) {
|
||||
remainingExtensionNames[i] = eventsFunctionsExtensions.at(i)->GetName();
|
||||
eventsFunctionsExtensionsElement.GetChildrenCount());
|
||||
for (std::size_t i = 0; i < eventsFunctionsExtensionsElement.GetChildrenCount(); ++i) {
|
||||
const SerializerElement& eventsFunctionsExtensionElement =
|
||||
eventsFunctionsExtensionsElement.GetChild(i);
|
||||
const gd::String& name = eventsFunctionsExtensionElement.GetStringAttribute("name");
|
||||
|
||||
remainingExtensionNames[i] = name;
|
||||
extensionNameToElementIndex[name] = i;
|
||||
}
|
||||
|
||||
// Helper allowing to find if an extension has an object that depends on
|
||||
|
||||
// Helper allowing to find if an extension has an object that depends on
|
||||
// at least one other object from another extension that is not loaded yet.
|
||||
auto isDependentFromRemainingExtensions =
|
||||
[&remainingExtensionNames](
|
||||
@@ -984,10 +1037,10 @@ std::vector<gd::String> Project::GetUnserializingOrderExtensionNames(
|
||||
foundAnyExtension = false;
|
||||
for (std::size_t i = 0; i < remainingExtensionNames.size(); ++i) {
|
||||
auto extensionName = remainingExtensionNames[i];
|
||||
size_t extensionIndex =
|
||||
GetEventsFunctionsExtensionPosition(extensionName);
|
||||
|
||||
size_t elementIndex = extensionNameToElementIndex[extensionName];
|
||||
const SerializerElement &eventsFunctionsExtensionElement =
|
||||
eventsFunctionsExtensionsElement.GetChild(extensionIndex);
|
||||
eventsFunctionsExtensionsElement.GetChild(elementIndex);
|
||||
|
||||
if (!isDependentFromRemainingExtensions(
|
||||
eventsFunctionsExtensionElement)) {
|
||||
@@ -1038,7 +1091,6 @@ void Project::SerializeTo(SerializerElement& element) const {
|
||||
propElement.AddChild("platformSpecificAssets"));
|
||||
loadingScreen.SerializeTo(propElement.AddChild("loadingScreen"));
|
||||
watermark.SerializeTo(propElement.AddChild("watermark"));
|
||||
propElement.SetAttribute("useExternalSourceFiles", useExternalSourceFiles);
|
||||
|
||||
auto& authorIdsElement = propElement.AddChild("authorIds");
|
||||
authorIdsElement.ConsiderAsArray();
|
||||
@@ -1126,13 +1178,6 @@ void Project::SerializeTo(SerializerElement& element) const {
|
||||
for (std::size_t i = 0; i < externalLayouts.size(); ++i)
|
||||
externalLayouts[i]->SerializeTo(
|
||||
externalLayoutsElement.AddChild("externalLayout"));
|
||||
|
||||
SerializerElement& externalSourceFilesElement =
|
||||
element.AddChild("externalSourceFiles");
|
||||
externalSourceFilesElement.ConsiderAsArrayOf("sourceFile");
|
||||
for (std::size_t i = 0; i < externalSourceFiles.size(); ++i)
|
||||
externalSourceFiles[i]->SerializeTo(
|
||||
externalSourceFilesElement.AddChild("sourceFile"));
|
||||
}
|
||||
|
||||
bool Project::IsNameSafe(const gd::String& name) {
|
||||
@@ -1173,65 +1218,11 @@ gd::String Project::GetSafeName(const gd::String& name) {
|
||||
return newName;
|
||||
}
|
||||
|
||||
bool Project::HasSourceFile(gd::String name, gd::String language) const {
|
||||
vector<std::unique_ptr<SourceFile> >::const_iterator sourceFile =
|
||||
find_if(externalSourceFiles.begin(),
|
||||
externalSourceFiles.end(),
|
||||
[&name](const std::unique_ptr<SourceFile>& sourceFile) {
|
||||
return sourceFile->GetFileName() == name;
|
||||
});
|
||||
|
||||
if (sourceFile == externalSourceFiles.end()) return false;
|
||||
|
||||
return language.empty() || (*sourceFile)->GetLanguage() == language;
|
||||
Project::Project(const Project &other)
|
||||
: objectsContainer(gd::ObjectsContainer::SourceType::Global) {
|
||||
Init(other);
|
||||
}
|
||||
|
||||
gd::SourceFile& Project::GetSourceFile(const gd::String& name) {
|
||||
return *(*find_if(externalSourceFiles.begin(),
|
||||
externalSourceFiles.end(),
|
||||
[&name](const std::unique_ptr<SourceFile>& sourceFile) {
|
||||
return sourceFile->GetFileName() == name;
|
||||
}));
|
||||
}
|
||||
|
||||
const gd::SourceFile& Project::GetSourceFile(const gd::String& name) const {
|
||||
return *(*find_if(externalSourceFiles.begin(),
|
||||
externalSourceFiles.end(),
|
||||
[&name](const std::unique_ptr<SourceFile>& sourceFile) {
|
||||
return sourceFile->GetFileName() == name;
|
||||
}));
|
||||
}
|
||||
|
||||
void Project::RemoveSourceFile(const gd::String& name) {
|
||||
std::vector<std::unique_ptr<gd::SourceFile> >::iterator sourceFile =
|
||||
find_if(externalSourceFiles.begin(),
|
||||
externalSourceFiles.end(),
|
||||
[&name](const std::unique_ptr<SourceFile>& sourceFile) {
|
||||
return sourceFile->GetFileName() == name;
|
||||
});
|
||||
if (sourceFile == externalSourceFiles.end()) return;
|
||||
|
||||
externalSourceFiles.erase(sourceFile);
|
||||
}
|
||||
|
||||
gd::SourceFile& Project::InsertNewSourceFile(const gd::String& name,
|
||||
const gd::String& language,
|
||||
std::size_t position) {
|
||||
if (HasSourceFile(name, language)) return GetSourceFile(name);
|
||||
|
||||
gd::SourceFile& newlyInsertedSourceFile = *(
|
||||
*(externalSourceFiles.emplace(position < externalSourceFiles.size()
|
||||
? externalSourceFiles.begin() + position
|
||||
: externalSourceFiles.end(),
|
||||
new SourceFile())));
|
||||
newlyInsertedSourceFile.SetLanguage(language);
|
||||
newlyInsertedSourceFile.SetFileName(name);
|
||||
|
||||
return newlyInsertedSourceFile;
|
||||
}
|
||||
|
||||
Project::Project(const Project& other) { Init(other); }
|
||||
|
||||
Project& Project::operator=(const Project& other) {
|
||||
if (this != &other) Init(other);
|
||||
|
||||
@@ -1293,10 +1284,6 @@ void Project::Init(const gd::Project& game) {
|
||||
externalLayouts = gd::Clone(game.externalLayouts);
|
||||
eventsFunctionsExtensions = gd::Clone(game.eventsFunctionsExtensions);
|
||||
|
||||
useExternalSourceFiles = game.useExternalSourceFiles;
|
||||
|
||||
externalSourceFiles = gd::Clone(game.externalSourceFiles);
|
||||
|
||||
variables = game.GetVariables();
|
||||
|
||||
projectFile = game.GetProjectFile();
|
||||
|
@@ -32,7 +32,6 @@ class Object;
|
||||
class ObjectConfiguration;
|
||||
class VariablesContainer;
|
||||
class ArbitraryResourceWorker;
|
||||
class SourceFile;
|
||||
class Behavior;
|
||||
class BehaviorsSharedData;
|
||||
class BaseEvent;
|
||||
@@ -523,13 +522,7 @@ class GD_CORE_API Project {
|
||||
std::unique_ptr<gd::Object> CreateObject(const gd::String& type,
|
||||
const gd::String& name) const;
|
||||
|
||||
/**
|
||||
* Create an object configuration of the given type.
|
||||
*
|
||||
* \param type The type of the object
|
||||
*/
|
||||
std::unique_ptr<gd::ObjectConfiguration> CreateObjectConfiguration(
|
||||
const gd::String& type) const;
|
||||
void EnsureObjectDefaultBehaviors(gd::Object& object) const;
|
||||
|
||||
/**
|
||||
* Create an event of the given type.
|
||||
@@ -899,6 +892,16 @@ class GD_CORE_API Project {
|
||||
const EventsFunctionsExtension& eventsFunctionExtension,
|
||||
std::size_t position);
|
||||
|
||||
/**
|
||||
* \brief Unserialize and insert in the project the extensions.
|
||||
*
|
||||
* Unserialization is done in two passe to allow dependencies between extensions.
|
||||
*
|
||||
* \note If an extension with the same name already exists, it will be overwritten.
|
||||
*/
|
||||
void UnserializeAndInsertExtensionsFrom(
|
||||
const gd::SerializerElement& eventsFunctionsExtensionsElement);
|
||||
|
||||
/**
|
||||
* \brief Delete the events functions extension named "name".
|
||||
*/
|
||||
@@ -1015,60 +1018,22 @@ class GD_CORE_API Project {
|
||||
static gd::String GetSafeName(const gd::String& name);
|
||||
///@}
|
||||
|
||||
/** \name External source files
|
||||
* To manage external C++ or Javascript source files used by the game
|
||||
*/
|
||||
///@{
|
||||
/**
|
||||
* \brief Return true if the game activated the use of external source files.
|
||||
*/
|
||||
bool UseExternalSourceFiles() const { return useExternalSourceFiles; }
|
||||
|
||||
/**
|
||||
* \brief Return a const reference to the vector containing all the source
|
||||
* files used by the game.
|
||||
*/
|
||||
const std::vector<std::unique_ptr<gd::SourceFile> >& GetAllSourceFiles()
|
||||
const {
|
||||
return externalSourceFiles;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Return true if the source file with the specified name is used by
|
||||
* the game. \param name The filename of the source file. \param language
|
||||
* Optional. If specified, check that the source file that exists is in this
|
||||
* language.
|
||||
*/
|
||||
bool HasSourceFile(gd::String name, gd::String language = "") const;
|
||||
|
||||
/**
|
||||
* Return a reference to the external source file with the given name.
|
||||
*/
|
||||
SourceFile& GetSourceFile(const gd::String& name);
|
||||
|
||||
/**
|
||||
* Return a reference to the external source file with the given name.
|
||||
*/
|
||||
const SourceFile& GetSourceFile(const gd::String& name) const;
|
||||
|
||||
/**
|
||||
* Remove the specified source file.
|
||||
*/
|
||||
void RemoveSourceFile(const gd::String& name);
|
||||
|
||||
/**
|
||||
* Add a new source file the specified position in the external source files
|
||||
* list.
|
||||
*/
|
||||
gd::SourceFile& InsertNewSourceFile(const gd::String& name,
|
||||
const gd::String& language,
|
||||
std::size_t position = -1);
|
||||
///@}
|
||||
|
||||
gd::WholeProjectDiagnosticReport& GetWholeProjectDiagnosticReport() {
|
||||
return wholeProjectDiagnosticReport;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the project extensions names in the order they have to be
|
||||
* unserialized.
|
||||
*
|
||||
* Child-objects need the event-based objects they use to be loaded completely
|
||||
* before they are unserialized.
|
||||
*
|
||||
* \warning This is only public to allow testing - don't use it in the editor.
|
||||
*/
|
||||
static std::vector<gd::String> GetUnserializingOrderExtensionNames(
|
||||
const gd::SerializerElement& eventsFunctionsExtensionsElement);
|
||||
|
||||
private:
|
||||
/**
|
||||
* Initialize from another game. Used by copy-ctor and assign-op.
|
||||
@@ -1077,12 +1042,12 @@ class GD_CORE_API Project {
|
||||
void Init(const gd::Project& project);
|
||||
|
||||
/**
|
||||
* @brief Get the project extensions names in the order they have to be unserialized.
|
||||
*
|
||||
* Child-objects need the event-based objects they use to be loaded completely
|
||||
* before they are unserialized.
|
||||
* Create an object configuration of the given type.
|
||||
*
|
||||
* \param type The type of the object
|
||||
*/
|
||||
std::vector<gd::String> GetUnserializingOrderExtensionNames(const gd::SerializerElement &eventsFunctionsExtensionsElement);
|
||||
std::unique_ptr<gd::ObjectConfiguration> CreateObjectConfiguration(
|
||||
const gd::String& type) const;
|
||||
|
||||
gd::String name; ///< Game name
|
||||
gd::String description; ///< Game description
|
||||
@@ -1125,10 +1090,6 @@ class GD_CORE_API Project {
|
||||
std::vector<gd::Platform*>
|
||||
platforms; ///< Pointers to the platforms this project supports.
|
||||
gd::String firstLayout;
|
||||
bool useExternalSourceFiles =
|
||||
false; ///< True if game used external source files.
|
||||
std::vector<std::unique_ptr<gd::SourceFile> >
|
||||
externalSourceFiles; ///< List of external source files used.
|
||||
gd::String author; ///< Game author name, for publishing purpose.
|
||||
std::vector<gd::String>
|
||||
authorIds; ///< Game author ids, from GDevelop users DB.
|
||||
|
@@ -4,12 +4,55 @@
|
||||
#include "GDCore/Project/EventsFunctionsExtension.h"
|
||||
#include "GDCore/Project/EventsBasedBehavior.h"
|
||||
#include "GDCore/Project/EventsBasedObject.h"
|
||||
#include "GDCore/Project/Layout.h"
|
||||
#include "GDCore/Project/ObjectsContainer.h"
|
||||
#include "GDCore/Project/Project.h"
|
||||
#include "GDCore/Events/Event.h"
|
||||
#include "GDCore/Extensions/PlatformExtension.h"
|
||||
|
||||
namespace gd {
|
||||
|
||||
ProjectScopedContainers
|
||||
ProjectScopedContainers::MakeNewProjectScopedContainersForProjectAndLayout(
|
||||
const gd::Project &project, const gd::Layout &layout) {
|
||||
ProjectScopedContainers projectScopedContainers(
|
||||
ObjectsContainersList::MakeNewObjectsContainersListForProjectAndLayout(
|
||||
project, layout),
|
||||
VariablesContainersList::
|
||||
MakeNewVariablesContainersListForProjectAndLayout(project, layout),
|
||||
&project.GetVariables(), &layout.GetVariables(),
|
||||
PropertiesContainersList::MakeNewEmptyPropertiesContainersList());
|
||||
|
||||
return projectScopedContainers;
|
||||
}
|
||||
|
||||
ProjectScopedContainers
|
||||
ProjectScopedContainers::MakeNewProjectScopedContainersForProject(
|
||||
const gd::Project &project) {
|
||||
ProjectScopedContainers projectScopedContainers(
|
||||
ObjectsContainersList::MakeNewObjectsContainersListForProject(project),
|
||||
VariablesContainersList::MakeNewVariablesContainersListForProject(
|
||||
project),
|
||||
&project.GetVariables(), nullptr,
|
||||
PropertiesContainersList::MakeNewEmptyPropertiesContainersList());
|
||||
|
||||
return projectScopedContainers;
|
||||
}
|
||||
|
||||
ProjectScopedContainers
|
||||
ProjectScopedContainers::MakeNewProjectScopedContainersFor(
|
||||
const gd::ObjectsContainer &globalObjectsContainers,
|
||||
const gd::ObjectsContainer &objectsContainers) {
|
||||
ProjectScopedContainers projectScopedContainers(
|
||||
ObjectsContainersList::MakeNewObjectsContainersListForContainers(
|
||||
globalObjectsContainers, objectsContainers),
|
||||
VariablesContainersList::MakeNewEmptyVariablesContainersList(),
|
||||
nullptr, nullptr,
|
||||
PropertiesContainersList::MakeNewEmptyPropertiesContainersList());
|
||||
|
||||
return projectScopedContainers;
|
||||
};
|
||||
|
||||
ProjectScopedContainers
|
||||
ProjectScopedContainers::MakeNewProjectScopedContainersForEventsFunctionsExtension(
|
||||
const gd::Project &project, const gd::EventsFunctionsExtension &eventsFunctionsExtension) {
|
||||
@@ -18,6 +61,8 @@ ProjectScopedContainers::MakeNewProjectScopedContainersForEventsFunctionsExtensi
|
||||
ObjectsContainersList::MakeNewEmptyObjectsContainersList(),
|
||||
VariablesContainersList::
|
||||
MakeNewVariablesContainersListForEventsFunctionsExtension(eventsFunctionsExtension),
|
||||
&eventsFunctionsExtension.GetGlobalVariables(),
|
||||
&eventsFunctionsExtension.GetSceneVariables(),
|
||||
PropertiesContainersList::MakeNewEmptyPropertiesContainersList());
|
||||
|
||||
return projectScopedContainers;
|
||||
@@ -37,6 +82,8 @@ ProjectScopedContainers::MakeNewProjectScopedContainersForFreeEventsFunction(
|
||||
parameterObjectsContainer),
|
||||
VariablesContainersList::
|
||||
MakeNewVariablesContainersListForEventsFunctionsExtension(eventsFunctionsExtension),
|
||||
&eventsFunctionsExtension.GetGlobalVariables(),
|
||||
&eventsFunctionsExtension.GetSceneVariables(),
|
||||
PropertiesContainersList::MakeNewEmptyPropertiesContainersList());
|
||||
|
||||
projectScopedContainers.AddParameters(
|
||||
@@ -63,6 +110,8 @@ ProjectScopedContainers::MakeNewProjectScopedContainersForBehaviorEventsFunction
|
||||
parameterObjectsContainer),
|
||||
VariablesContainersList::
|
||||
MakeNewVariablesContainersListForEventsFunctionsExtension(eventsFunctionsExtension),
|
||||
&eventsFunctionsExtension.GetGlobalVariables(),
|
||||
&eventsFunctionsExtension.GetSceneVariables(),
|
||||
PropertiesContainersList::MakeNewEmptyPropertiesContainersList());
|
||||
|
||||
projectScopedContainers.AddPropertiesContainer(
|
||||
@@ -87,11 +136,14 @@ ProjectScopedContainers::MakeNewProjectScopedContainersForObjectEventsFunction(
|
||||
project, eventsBasedObject, eventsFunction, parameterObjectsContainer);
|
||||
|
||||
ProjectScopedContainers projectScopedContainers(
|
||||
ObjectsContainersList::MakeNewObjectsContainersListForContainer(
|
||||
ObjectsContainersList::MakeNewObjectsContainersListForContainers(
|
||||
eventsBasedObject.GetObjects(),
|
||||
parameterObjectsContainer),
|
||||
VariablesContainersList::
|
||||
MakeNewVariablesContainersListForEventsFunctionsExtension(
|
||||
eventsFunctionsExtension),
|
||||
&eventsFunctionsExtension.GetGlobalVariables(),
|
||||
&eventsFunctionsExtension.GetSceneVariables(),
|
||||
PropertiesContainersList::MakeNewEmptyPropertiesContainersList());
|
||||
|
||||
projectScopedContainers.AddPropertiesContainer(
|
||||
@@ -109,22 +161,34 @@ ProjectScopedContainers::MakeNewProjectScopedContainersForEventsBasedObject(
|
||||
const gd::EventsBasedObject &eventsBasedObject,
|
||||
gd::ObjectsContainer &outputObjectsContainer) {
|
||||
|
||||
// TODO: We should avoid to use a single `outputObjectsContainer` and instead
|
||||
// use multiple, stable objects container pointed by the `ProjectScopedContainers`
|
||||
// created below.
|
||||
// Search for "ProjectScopedContainers wrongly containing temporary objects containers or objects"
|
||||
// in the codebase.
|
||||
outputObjectsContainer.GetObjects().clear();
|
||||
outputObjectsContainer.GetObjectGroups().Clear();
|
||||
|
||||
// This object named "Object" represents the parent and is used by events.
|
||||
// TODO: Use a dedicated `ObjectsContainer` with only this "Object" and check in
|
||||
// the codebase that this container is not assumed as a
|
||||
// "globalObjectsContainer".
|
||||
// Search for "ProjectScopedContainers wrongly containing temporary objects containers or objects"
|
||||
// in the codebase.
|
||||
outputObjectsContainer.InsertNewObject(
|
||||
project,
|
||||
gd::PlatformExtension::GetObjectFullType(
|
||||
eventsFunctionsExtension.GetName(), eventsBasedObject.GetName()),
|
||||
"Object", outputObjectsContainer.GetObjectsCount());
|
||||
gd::EventsFunctionTools::CopyEventsBasedObjectChildrenToObjectsContainer(
|
||||
eventsBasedObject, outputObjectsContainer);
|
||||
|
||||
ProjectScopedContainers projectScopedContainers(
|
||||
ObjectsContainersList::MakeNewObjectsContainersListForContainer(
|
||||
outputObjectsContainer),
|
||||
ObjectsContainersList::MakeNewObjectsContainersListForContainers(
|
||||
eventsBasedObject.GetObjects(), outputObjectsContainer),
|
||||
VariablesContainersList::
|
||||
MakeNewVariablesContainersListForEventsFunctionsExtension(
|
||||
eventsFunctionsExtension),
|
||||
&eventsFunctionsExtension.GetGlobalVariables(),
|
||||
&eventsFunctionsExtension.GetSceneVariables(),
|
||||
PropertiesContainersList::MakeNewEmptyPropertiesContainersList());
|
||||
|
||||
projectScopedContainers.AddPropertiesContainer(
|
||||
|
@@ -5,13 +5,11 @@
|
||||
#include "ObjectsContainersList.h"
|
||||
#include "PropertiesContainersList.h"
|
||||
#include "VariablesContainersList.h"
|
||||
#include "VariablesContainer.h"
|
||||
|
||||
namespace gd {
|
||||
class Project;
|
||||
class ObjectsContainer;
|
||||
class ObjectsContainersList;
|
||||
class VariablesContainersList;
|
||||
class PropertiesContainersList;
|
||||
class NamedPropertyDescriptor;
|
||||
class ParameterMetadataContainer;
|
||||
class BaseEvent;
|
||||
@@ -19,7 +17,7 @@ class EventsFunctionsExtension;
|
||||
class EventsFunction;
|
||||
class EventsBasedBehavior;
|
||||
class EventsBasedObject;
|
||||
} // namespace gd
|
||||
} // namespace gd
|
||||
|
||||
namespace gd {
|
||||
|
||||
@@ -38,51 +36,29 @@ class ProjectScopedContainers {
|
||||
ProjectScopedContainers(
|
||||
const gd::ObjectsContainersList &objectsContainersList_,
|
||||
const gd::VariablesContainersList &variablesContainersList_,
|
||||
const gd::VariablesContainer *legacyGlobalVariables_,
|
||||
const gd::VariablesContainer *legacySceneVariables_,
|
||||
const gd::PropertiesContainersList &propertiesContainersList_)
|
||||
: objectsContainersList(objectsContainersList_),
|
||||
variablesContainersList(variablesContainersList_),
|
||||
legacyGlobalVariables(legacyGlobalVariables_),
|
||||
legacySceneVariables(legacySceneVariables_),
|
||||
propertiesContainersList(propertiesContainersList_){};
|
||||
virtual ~ProjectScopedContainers(){};
|
||||
|
||||
static ProjectScopedContainers
|
||||
MakeNewProjectScopedContainersForProjectAndLayout(const gd::Project &project,
|
||||
const gd::Layout &layout) {
|
||||
ProjectScopedContainers projectScopedContainers(
|
||||
ObjectsContainersList::MakeNewObjectsContainersListForProjectAndLayout(
|
||||
project, layout),
|
||||
VariablesContainersList::
|
||||
MakeNewVariablesContainersListForProjectAndLayout(project, layout),
|
||||
PropertiesContainersList::MakeNewEmptyPropertiesContainersList());
|
||||
|
||||
return projectScopedContainers;
|
||||
}
|
||||
const gd::Layout &layout);
|
||||
|
||||
static ProjectScopedContainers
|
||||
MakeNewProjectScopedContainersForProject(const gd::Project &project) {
|
||||
ProjectScopedContainers projectScopedContainers(
|
||||
ObjectsContainersList::MakeNewObjectsContainersListForProject(
|
||||
project),
|
||||
VariablesContainersList::
|
||||
MakeNewVariablesContainersListForProject(project),
|
||||
PropertiesContainersList::MakeNewEmptyPropertiesContainersList());
|
||||
|
||||
return projectScopedContainers;
|
||||
}
|
||||
MakeNewProjectScopedContainersForProject(const gd::Project &project);
|
||||
|
||||
/**
|
||||
* @deprecated Use another method for an explicit context instead.
|
||||
*/
|
||||
static ProjectScopedContainers MakeNewProjectScopedContainersFor(
|
||||
const gd::ObjectsContainer &globalObjectsContainers,
|
||||
const gd::ObjectsContainer &objectsContainers) {
|
||||
ProjectScopedContainers projectScopedContainers(
|
||||
ObjectsContainersList::MakeNewObjectsContainersListForContainers(
|
||||
globalObjectsContainers, objectsContainers),
|
||||
VariablesContainersList::MakeNewEmptyVariablesContainersList(),
|
||||
PropertiesContainersList::MakeNewEmptyPropertiesContainersList());
|
||||
|
||||
return projectScopedContainers;
|
||||
};
|
||||
const gd::ObjectsContainer &objectsContainers);
|
||||
|
||||
static ProjectScopedContainers
|
||||
MakeNewProjectScopedContainersForEventsFunctionsExtension(
|
||||
@@ -221,6 +197,24 @@ class ProjectScopedContainers {
|
||||
return variablesContainersList;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Return the global variables of the current scene or the current
|
||||
* extension. It allows legacy "globalvar" parameters to accept extension
|
||||
* variables.
|
||||
*/
|
||||
const gd::VariablesContainer *GetLegacyGlobalVariables() const {
|
||||
return legacyGlobalVariables;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Return the scene variables of the current scene or the current
|
||||
* extension. It allows legacy "scenevar" parameters to accept extension
|
||||
* variables.
|
||||
*/
|
||||
const gd::VariablesContainer *GetLegacySceneVariables() const {
|
||||
return legacySceneVariables;
|
||||
};
|
||||
|
||||
const gd::PropertiesContainersList &GetPropertiesContainersList() const {
|
||||
return propertiesContainersList;
|
||||
};
|
||||
@@ -231,11 +225,14 @@ class ProjectScopedContainers {
|
||||
|
||||
/** Do not use - should be private but accessible to let Emscripten create a
|
||||
* temporary. */
|
||||
ProjectScopedContainers(){};
|
||||
ProjectScopedContainers()
|
||||
: legacyGlobalVariables(nullptr), legacySceneVariables(nullptr){};
|
||||
|
||||
private:
|
||||
private:
|
||||
gd::ObjectsContainersList objectsContainersList;
|
||||
gd::VariablesContainersList variablesContainersList;
|
||||
const gd::VariablesContainer *legacyGlobalVariables;
|
||||
const gd::VariablesContainer *legacySceneVariables;
|
||||
gd::PropertiesContainersList propertiesContainersList;
|
||||
std::vector<const ParameterMetadataContainer *> parametersVectorsList;
|
||||
};
|
||||
|
@@ -97,6 +97,8 @@ std::shared_ptr<Resource> ResourcesManager::CreateResource(
|
||||
return std::make_shared<AtlasResource>();
|
||||
else if (kind == "spine")
|
||||
return std::make_shared<SpineResource>();
|
||||
else if (kind == "javascript")
|
||||
return std::make_shared<JavaScriptResource>();
|
||||
|
||||
std::cout << "Bad resource created (type: " << kind << ")" << std::endl;
|
||||
return std::make_shared<Resource>();
|
||||
@@ -173,9 +175,6 @@ std::map<gd::String, gd::PropertyDescriptor> ImageResource::GetProperties()
|
||||
properties[_("Smooth the image")]
|
||||
.SetValue(smooth ? "true" : "false")
|
||||
.SetType("Boolean");
|
||||
properties[_("Always loaded in memory")]
|
||||
.SetValue(alwaysLoaded ? "true" : "false")
|
||||
.SetType("Boolean");
|
||||
|
||||
return properties;
|
||||
}
|
||||
@@ -184,8 +183,6 @@ bool ImageResource::UpdateProperty(const gd::String& name,
|
||||
const gd::String& value) {
|
||||
if (name == _("Smooth the image"))
|
||||
smooth = value == "1";
|
||||
else if (name == _("Always loaded in memory"))
|
||||
alwaysLoaded = value == "1";
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -569,14 +566,12 @@ void ImageResource::SetFile(const gd::String& newFile) {
|
||||
}
|
||||
|
||||
void ImageResource::UnserializeFrom(const SerializerElement& element) {
|
||||
alwaysLoaded = element.GetBoolAttribute("alwaysLoaded");
|
||||
smooth = element.GetBoolAttribute("smoothed");
|
||||
SetUserAdded(element.GetBoolAttribute("userAdded"));
|
||||
SetFile(element.GetStringAttribute("file"));
|
||||
}
|
||||
|
||||
void ImageResource::SerializeTo(SerializerElement& element) const {
|
||||
element.SetAttribute("alwaysLoaded", alwaysLoaded);
|
||||
element.SetAttribute("smoothed", smooth);
|
||||
element.SetAttribute("userAdded", IsUserAdded());
|
||||
element.SetAttribute("file", GetFile());
|
||||
@@ -774,6 +769,20 @@ void AtlasResource::SerializeTo(SerializerElement& element) const {
|
||||
element.SetAttribute("file", GetFile());
|
||||
}
|
||||
|
||||
void JavaScriptResource::SetFile(const gd::String& newFile) {
|
||||
file = NormalizePathSeparator(newFile);
|
||||
}
|
||||
|
||||
void JavaScriptResource::UnserializeFrom(const SerializerElement& element) {
|
||||
SetUserAdded(element.GetBoolAttribute("userAdded"));
|
||||
SetFile(element.GetStringAttribute("file"));
|
||||
}
|
||||
|
||||
void JavaScriptResource::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) {
|
||||
|
@@ -166,7 +166,7 @@ class GD_CORE_API Resource {
|
||||
*/
|
||||
class GD_CORE_API ImageResource : public Resource {
|
||||
public:
|
||||
ImageResource() : Resource(), smooth(true), alwaysLoaded(false) {
|
||||
ImageResource() : Resource(), smooth(true) {
|
||||
SetKind("image");
|
||||
};
|
||||
virtual ~ImageResource(){};
|
||||
@@ -210,7 +210,6 @@ class GD_CORE_API ImageResource : public Resource {
|
||||
void SetSmooth(bool enable = true) { smooth = enable; }
|
||||
|
||||
bool smooth; ///< True if smoothing filter is applied
|
||||
bool alwaysLoaded; ///< True if the image must always be loaded in memory.
|
||||
private:
|
||||
gd::String file;
|
||||
};
|
||||
@@ -548,6 +547,32 @@ class GD_CORE_API AtlasResource : public Resource {
|
||||
gd::String file;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Describe a video file used by a project.
|
||||
*
|
||||
* \see Resource
|
||||
* \ingroup ResourcesManagement
|
||||
*/
|
||||
class GD_CORE_API JavaScriptResource : public Resource {
|
||||
public:
|
||||
JavaScriptResource() : Resource() { SetKind("javascript"); };
|
||||
virtual ~JavaScriptResource(){};
|
||||
virtual JavaScriptResource* Clone() const override {
|
||||
return new JavaScriptResource(*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
|
||||
*
|
||||
|
@@ -1,36 +0,0 @@
|
||||
/*
|
||||
* GDevelop Core
|
||||
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
|
||||
#if defined(GD_IDE_ONLY)
|
||||
#include "GDCore/Project/SourceFile.h"
|
||||
#include "GDCore/CommonTools.h"
|
||||
#include "GDCore/Serialization/SerializerElement.h"
|
||||
|
||||
namespace gd {
|
||||
|
||||
SourceFile::SourceFile() : gdManaged(false) {
|
||||
// ctor
|
||||
}
|
||||
|
||||
SourceFile::~SourceFile() {
|
||||
// dtor
|
||||
}
|
||||
|
||||
void SourceFile::SerializeTo(SerializerElement& element) const {
|
||||
element.SetAttribute("filename", filename);
|
||||
element.SetAttribute("language", language);
|
||||
element.SetAttribute("gdManaged", gdManaged);
|
||||
}
|
||||
|
||||
void SourceFile::UnserializeFrom(const SerializerElement& element) {
|
||||
filename = element.GetStringAttribute("filename");
|
||||
language = element.GetStringAttribute("language", "C++");
|
||||
gdManaged = element.GetBoolAttribute("gdManaged");
|
||||
}
|
||||
|
||||
} // namespace gd
|
||||
|
||||
#endif
|
@@ -1,92 +0,0 @@
|
||||
/*
|
||||
* GDevelop Core
|
||||
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#ifndef SOURCEFILE_H
|
||||
#define SOURCEFILE_H
|
||||
#include <ctime>
|
||||
#include <memory>
|
||||
#include "GDCore/String.h"
|
||||
namespace gd {
|
||||
class SerializerElement;
|
||||
}
|
||||
class BaseEvent;
|
||||
|
||||
namespace gd {
|
||||
|
||||
/**
|
||||
* \brief Represents a "physical" source file.
|
||||
*
|
||||
* Source file can be compiled (or just integrated to the exported project)
|
||||
* by platforms. Most of the time, special events are provided to use functions
|
||||
* created in such files.
|
||||
*/
|
||||
class GD_CORE_API SourceFile {
|
||||
public:
|
||||
SourceFile();
|
||||
virtual ~SourceFile();
|
||||
|
||||
/**
|
||||
* \brief Return a pointer to a new SourceFile constructed from this one.
|
||||
*/
|
||||
SourceFile* Clone() const { return new SourceFile(*this); };
|
||||
|
||||
/**
|
||||
* \brief Get the filename
|
||||
*/
|
||||
gd::String GetFileName() const { return filename; };
|
||||
|
||||
/**
|
||||
* \brief Change the filename
|
||||
*/
|
||||
void SetFileName(gd::String filename_) { filename = filename_; };
|
||||
|
||||
/**
|
||||
* \brief Serialize the source file.
|
||||
*/
|
||||
void SerializeTo(SerializerElement& element) const;
|
||||
|
||||
/**
|
||||
* \brief Unserialize the source file.
|
||||
*/
|
||||
void UnserializeFrom(const SerializerElement& element);
|
||||
|
||||
/**
|
||||
* \brief Set if the file is hidden from the user point of view and is only
|
||||
* managed by GDevelop
|
||||
*/
|
||||
void SetGDManaged(bool gdManaged_) { gdManaged = gdManaged_; };
|
||||
|
||||
/**
|
||||
* \brief Return true if the file is hidden from the user point of view and is
|
||||
* only managed by GDevelop
|
||||
*/
|
||||
bool IsGDManaged() const { return gdManaged; };
|
||||
|
||||
/**
|
||||
* \brief Change the language of the source file
|
||||
*/
|
||||
void SetLanguage(gd::String lang) { language = lang; }
|
||||
|
||||
/**
|
||||
* \brief Get the language of the source file
|
||||
*/
|
||||
const gd::String& GetLanguage() const { return language; }
|
||||
|
||||
private:
|
||||
gd::String filename; ///< Filename
|
||||
bool gdManaged; ///< True if the source file is hidden from the user point of
|
||||
///< view and is managed only by GDevelop.
|
||||
gd::String language; ///< String identifying the language of this source file
|
||||
///< (typically "C++ or "Javascript").
|
||||
std::weak_ptr<BaseEvent>
|
||||
associatedGdEvent; ///< When a source file is GD-managed, it is usually
|
||||
///< created for a specific event. This member is not
|
||||
///< saved: It is the event responsibility to call
|
||||
///< SetAssociatedEvent.
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
|
||||
#endif // SOURCEFILE_H
|
@@ -32,7 +32,6 @@ TEST_CASE("DependenciesAnalyzer", "[common]") {
|
||||
REQUIRE(analyzer.GetScenesDependencies().find("Layout2") !=
|
||||
analyzer.GetScenesDependencies().end());
|
||||
REQUIRE(analyzer.GetExternalEventsDependencies().size() == 0);
|
||||
REQUIRE(analyzer.GetSourceFilesDependencies().size() == 0);
|
||||
}
|
||||
|
||||
SECTION("Can detect a simple external events dependency") {
|
||||
@@ -55,7 +54,6 @@ TEST_CASE("DependenciesAnalyzer", "[common]") {
|
||||
REQUIRE(analyzer.GetExternalEventsDependencies().size() == 1);
|
||||
REQUIRE(analyzer.GetExternalEventsDependencies().find("ExternalEvents1") !=
|
||||
analyzer.GetExternalEventsDependencies().end());
|
||||
REQUIRE(analyzer.GetSourceFilesDependencies().size() == 0);
|
||||
}
|
||||
|
||||
SECTION("Can detect a transitive scene and external events dependency") {
|
||||
@@ -87,7 +85,6 @@ TEST_CASE("DependenciesAnalyzer", "[common]") {
|
||||
REQUIRE(analyzer.GetExternalEventsDependencies().size() == 1);
|
||||
REQUIRE(analyzer.GetExternalEventsDependencies().find("ExternalEvents1") !=
|
||||
analyzer.GetExternalEventsDependencies().end());
|
||||
REQUIRE(analyzer.GetSourceFilesDependencies().size() == 0);
|
||||
}
|
||||
|
||||
SECTION("Can detect a (nested) circular dependency with scenes") {
|
||||
|
@@ -265,9 +265,9 @@ void SetupProjectWithDummyPlatform(gd::Project& project,
|
||||
|
||||
extension
|
||||
->AddAction("SetNumberVariable",
|
||||
"Do something with number variables",
|
||||
"This does something with variables",
|
||||
"Do something with variables",
|
||||
"Change variable value",
|
||||
"Modify the number value of a variable.",
|
||||
"the variable _PARAM0_",
|
||||
"",
|
||||
"",
|
||||
"")
|
||||
@@ -278,9 +278,9 @@ void SetupProjectWithDummyPlatform(gd::Project& project,
|
||||
|
||||
extension
|
||||
->AddAction("SetStringVariable",
|
||||
"Do something with string variables",
|
||||
"This does something with variables",
|
||||
"Do something with variables",
|
||||
"Change text variable",
|
||||
"Modify the text (string) of a variable.",
|
||||
"the variable _PARAM0_",
|
||||
"",
|
||||
"",
|
||||
"")
|
||||
@@ -291,9 +291,9 @@ void SetupProjectWithDummyPlatform(gd::Project& project,
|
||||
|
||||
extension
|
||||
->AddAction("SetBooleanVariable",
|
||||
"Do something with boolean variables",
|
||||
"This does something with variables",
|
||||
"Do something with variables",
|
||||
"Change boolean variable",
|
||||
"Modify the boolean value of a variable.",
|
||||
"Change the variable _PARAM0_: _PARAM1_",
|
||||
"",
|
||||
"",
|
||||
"")
|
||||
@@ -340,8 +340,8 @@ void SetupProjectWithDummyPlatform(gd::Project& project,
|
||||
"",
|
||||
"",
|
||||
"")
|
||||
.AddParameter("object", _("Object 1 parameter"))
|
||||
.AddParameter("object", _("Object 2 parameter"))
|
||||
.AddParameter("object", "Object 1 parameter")
|
||||
.AddParameter("object", "Object 2 parameter")
|
||||
.SetFunctionName("doSomethingWithObjects");
|
||||
|
||||
extension
|
||||
@@ -358,6 +358,17 @@ void SetupProjectWithDummyPlatform(gd::Project& project,
|
||||
.AddParameter("soundfile", "Parameter 3 (an audio resource)")
|
||||
.SetFunctionName("doSomethingWithResources");
|
||||
|
||||
extension
|
||||
->AddAction("DoSomethingWithAnyVariable",
|
||||
"Do something with variables",
|
||||
"This does something with variables",
|
||||
"Do something with variables please",
|
||||
"",
|
||||
"",
|
||||
"")
|
||||
.AddParameter("variable", "Any variable")
|
||||
.SetFunctionName("doSomethingWithAnyVariable");
|
||||
|
||||
extension
|
||||
->AddAction("DoSomethingWithLegacyPreScopedVariables",
|
||||
"Do something with variables",
|
||||
|
@@ -1737,10 +1737,12 @@ TEST_CASE("ExpressionParser2", "[common][events]") {
|
||||
|
||||
gd::ExpressionValidator validator(platform, projectScopedContainers, "number|string");
|
||||
node->Visit(validator);
|
||||
REQUIRE(validator.GetFatalErrors().size() == 2);
|
||||
REQUIRE(validator.GetFatalErrors().size() == 3);
|
||||
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.");
|
||||
REQUIRE(validator.GetFatalErrors()[2]->GetMessage() ==
|
||||
"A name should be entered after the dot.");
|
||||
}
|
||||
}
|
||||
@@ -1817,6 +1819,19 @@ TEST_CASE("ExpressionParser2", "[common][events]") {
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("Invalid object variables (non existing variable with child)") {
|
||||
{
|
||||
auto node =
|
||||
parser.ParseExpression("MySpriteObject.MyNonExistingVariable.MyNonExistingChild");
|
||||
|
||||
gd::ExpressionValidator validator(platform, projectScopedContainers, "number|string");
|
||||
node->Visit(validator);
|
||||
REQUIRE(validator.GetFatalErrors().size() == 1);
|
||||
REQUIRE(validator.GetFatalErrors()[0]->GetMessage() ==
|
||||
"This variable does not exist on this object or group.");
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("Invalid object (object entered without any variable)") {
|
||||
{
|
||||
auto node =
|
||||
@@ -2376,10 +2391,12 @@ TEST_CASE("ExpressionParser2", "[common][events]") {
|
||||
|
||||
gd::ExpressionValidator validator(platform, projectScopedContainers, "number");
|
||||
node->Visit(validator);
|
||||
REQUIRE(validator.GetFatalErrors().size() == 2);
|
||||
REQUIRE(validator.GetFatalErrors().size() == 3);
|
||||
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.");
|
||||
REQUIRE(validator.GetFatalErrors()[2]->GetMessage() ==
|
||||
"A name should be entered after the dot.");
|
||||
}
|
||||
|
||||
|
74
Core/tests/Project-EnsureObjectDefaultBehaviors.cpp
Normal file
74
Core/tests/Project-EnsureObjectDefaultBehaviors.cpp
Normal file
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* 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/Project/Project.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "DummyPlatform.h"
|
||||
#include "GDCore/Extensions/Metadata/MetadataProvider.h"
|
||||
#include "GDCore/Extensions/Platform.h"
|
||||
#include "GDCore/Extensions/PlatformExtension.h"
|
||||
#include "GDCore/Project/Object.h"
|
||||
#include "GDCore/String.h"
|
||||
#include "catch.hpp"
|
||||
|
||||
TEST_CASE("Project::EnsureObjectDefaultBehaviors", "[common]") {
|
||||
SECTION("Check that default behaviors are added to an object") {
|
||||
gd::Platform platform;
|
||||
gd::Project project;
|
||||
SetupProjectWithDummyPlatform(project, platform);
|
||||
|
||||
auto myObject = project.CreateObject("MyExtension::Sprite", "MyObject");
|
||||
REQUIRE(myObject->GetType() == "MyExtension::Sprite");
|
||||
REQUIRE(myObject->GetAllBehaviorNames().size() == 0);
|
||||
|
||||
project.EnsureObjectDefaultBehaviors(*myObject);
|
||||
REQUIRE(myObject->GetAllBehaviorNames().size() == 0);
|
||||
|
||||
// Modify the "Sprite" extension to add a default behavior to the object.
|
||||
const auto& allExtensions = platform.GetAllPlatformExtensions();
|
||||
auto spriteExtensionIt = std::find_if(
|
||||
allExtensions.begin(),
|
||||
allExtensions.end(),
|
||||
[&](const std::shared_ptr<gd::PlatformExtension>& extension) {
|
||||
return extension->GetName() == "MyExtension";
|
||||
});
|
||||
REQUIRE(spriteExtensionIt != allExtensions.end());
|
||||
auto spriteExtension = *spriteExtensionIt;
|
||||
|
||||
auto& spriteObjectMetadata =
|
||||
spriteExtension->GetObjectMetadata("MyExtension::Sprite");
|
||||
REQUIRE(gd::MetadataProvider::IsBadObjectMetadata(spriteObjectMetadata) ==
|
||||
false);
|
||||
|
||||
spriteObjectMetadata.AddDefaultBehavior(
|
||||
"FlippableCapability::FlippableBehavior");
|
||||
|
||||
// Ensure the default behavior is added.
|
||||
project.EnsureObjectDefaultBehaviors(*myObject);
|
||||
REQUIRE(myObject->GetAllBehaviorNames().size() == 1);
|
||||
REQUIRE(myObject->GetAllBehaviorNames()[0] == "Flippable");
|
||||
REQUIRE(myObject->GetBehavior("Flippable").GetTypeName() == "FlippableCapability::FlippableBehavior");
|
||||
|
||||
// Ensure default behaviors are adapted if the object default behaviors are modified.
|
||||
// While this can not happen with pre-coded extensions, it can happen with custom objects.
|
||||
spriteObjectMetadata.ResetDefaultBehaviorsJustForTesting();
|
||||
spriteObjectMetadata.AddDefaultBehavior(
|
||||
"ResizableCapability::ResizableBehavior");
|
||||
spriteObjectMetadata.AddDefaultBehavior(
|
||||
"ScalableCapability::ScalableBehavior");
|
||||
|
||||
project.EnsureObjectDefaultBehaviors(*myObject);
|
||||
REQUIRE(myObject->GetAllBehaviorNames().size() == 2);
|
||||
REQUIRE(myObject->GetAllBehaviorNames()[0] == "Resizable");
|
||||
REQUIRE(myObject->GetAllBehaviorNames()[1] == "Scale");
|
||||
REQUIRE(myObject->GetBehavior("Resizable").GetTypeName() == "ResizableCapability::ResizableBehavior");
|
||||
REQUIRE(myObject->GetBehavior("Scale").GetTypeName() == "ScalableCapability::ScalableBehavior");
|
||||
}
|
||||
}
|
312
Core/tests/Project-GetUnserializingOrderExtensionNames.cpp
Normal file
312
Core/tests/Project-GetUnserializingOrderExtensionNames.cpp
Normal file
@@ -0,0 +1,312 @@
|
||||
/*
|
||||
* 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 <algorithm>
|
||||
|
||||
#include "DummyPlatform.h"
|
||||
#include "GDCore/Extensions/Metadata/MetadataProvider.h"
|
||||
#include "GDCore/Extensions/Platform.h"
|
||||
#include "GDCore/Extensions/PlatformExtension.h"
|
||||
#include "GDCore/Project/Object.h"
|
||||
#include "GDCore/Project/Project.h"
|
||||
#include "GDCore/String.h"
|
||||
#include "catch.hpp"
|
||||
|
||||
TEST_CASE("Project::GetUnserializingOrderExtensionNames", "[common]") {
|
||||
SECTION("Unserialization order is correct when nothing to load") {
|
||||
gd::SerializerElement emptyElement;
|
||||
|
||||
std::vector<gd::String> orderedNames =
|
||||
gd::Project::GetUnserializingOrderExtensionNames(emptyElement);
|
||||
REQUIRE(orderedNames.size() == 0);
|
||||
}
|
||||
SECTION("One extension with no dependencies") {
|
||||
gd::SerializerElement extensionsElement = gd::Serializer::FromJSON(
|
||||
R"([
|
||||
{
|
||||
"author": "",
|
||||
"category": "Input",
|
||||
"extensionNamespace": "",
|
||||
"fullName": "3D character keyboard mapper",
|
||||
"helpPath": "",
|
||||
"iconUrl": "fake-icon-url",
|
||||
"name": "Extension1",
|
||||
"previewIconUrl": "fake-preview-icon-url",
|
||||
"shortDescription": "3D platformer and 3D shooter keyboard controls.",
|
||||
"version": "1.0.0",
|
||||
"description": "3D platformer and 3D shooter keyboard controls.",
|
||||
"tags": [],
|
||||
"authorIds": [],
|
||||
"dependencies": [],
|
||||
"globalVariables": [],
|
||||
"sceneVariables": [],
|
||||
"eventsFunctions": [],
|
||||
"eventsBasedBehaviors": [],
|
||||
"eventsBasedObjects": []
|
||||
}
|
||||
])");
|
||||
|
||||
std::vector<gd::String> orderedNames =
|
||||
gd::Project::GetUnserializingOrderExtensionNames(extensionsElement);
|
||||
REQUIRE(orderedNames.size() == 1);
|
||||
REQUIRE(orderedNames[0] == "Extension1");
|
||||
}
|
||||
|
||||
SECTION("One extension with a dependency outside the loaded extensions") {
|
||||
gd::SerializerElement extensionsElement = gd::Serializer::FromJSON(
|
||||
R"([
|
||||
{
|
||||
"author": "",
|
||||
"category": "Input",
|
||||
"extensionNamespace": "",
|
||||
"fullName": "3D character keyboard mapper",
|
||||
"helpPath": "",
|
||||
"iconUrl": "fake-icon-url",
|
||||
"name": "Extension1DependsOtherExtension",
|
||||
"previewIconUrl": "fake-preview-icon-url",
|
||||
"shortDescription": "3D platformer and 3D shooter keyboard controls.",
|
||||
"version": "1.0.0",
|
||||
"description": "3D platformer and 3D shooter keyboard controls.",
|
||||
"tags": [],
|
||||
"authorIds": [],
|
||||
"dependencies": [],
|
||||
"globalVariables": [],
|
||||
"sceneVariables": [],
|
||||
"eventsFunctions": [],
|
||||
"eventsBasedBehaviors": [],
|
||||
"eventsBasedObjects": [
|
||||
{
|
||||
"areaMaxX": 64,
|
||||
"areaMaxY": 64,
|
||||
"areaMaxZ": 64,
|
||||
"areaMinX": 0,
|
||||
"areaMinY": 0,
|
||||
"areaMinZ": 0,
|
||||
"defaultName": "Joystick",
|
||||
"description": "Joystick for touchscreens.",
|
||||
"fullName": "Multitouch Joystick",
|
||||
"name": "SpriteMultitouchJoystick",
|
||||
"eventsFunctions": [],
|
||||
"propertyDescriptors": [],
|
||||
"objects": [
|
||||
{
|
||||
"name": "Thumb",
|
||||
"type": "OtherExtension::Whatever"
|
||||
}
|
||||
],
|
||||
"objectsFolderStructure": {
|
||||
"folderName": "__ROOT",
|
||||
"children": []
|
||||
},
|
||||
"objectsGroups": [],
|
||||
"layers": [],
|
||||
"instances": []
|
||||
}
|
||||
]
|
||||
}
|
||||
])");
|
||||
|
||||
std::vector<gd::String> orderedNames =
|
||||
gd::Project::GetUnserializingOrderExtensionNames(extensionsElement);
|
||||
REQUIRE(orderedNames.size() == 1);
|
||||
REQUIRE(orderedNames[0] == "Extension1DependsOtherExtension");
|
||||
}
|
||||
|
||||
SECTION("4 extensions with dependencies on each others") {
|
||||
gd::SerializerElement extensionsElement = gd::Serializer::FromJSON(
|
||||
R"([
|
||||
{
|
||||
"author": "",
|
||||
"category": "Input",
|
||||
"extensionNamespace": "",
|
||||
"fullName": "3D character keyboard mapper",
|
||||
"helpPath": "",
|
||||
"iconUrl": "fake-icon-url",
|
||||
"name": "Extension4DependsOn1And3",
|
||||
"previewIconUrl": "fake-preview-icon-url",
|
||||
"shortDescription": "3D platformer and 3D shooter keyboard controls.",
|
||||
"version": "1.0.0",
|
||||
"description": "3D platformer and 3D shooter keyboard controls.",
|
||||
"tags": [],
|
||||
"authorIds": [],
|
||||
"dependencies": [],
|
||||
"globalVariables": [],
|
||||
"sceneVariables": [],
|
||||
"eventsFunctions": [],
|
||||
"eventsBasedBehaviors": [],
|
||||
"eventsBasedObjects": [
|
||||
{
|
||||
"areaMaxX": 64,
|
||||
"areaMaxY": 64,
|
||||
"areaMaxZ": 64,
|
||||
"areaMinX": 0,
|
||||
"areaMinY": 0,
|
||||
"areaMinZ": 0,
|
||||
"defaultName": "Joystick",
|
||||
"description": "Joystick for touchscreens.",
|
||||
"fullName": "Multitouch Joystick",
|
||||
"name": "SpriteMultitouchJoystick",
|
||||
"eventsFunctions": [],
|
||||
"propertyDescriptors": [],
|
||||
"objects": [
|
||||
{
|
||||
"name": "Thumb",
|
||||
"type": "OtherExtension::Whatever"
|
||||
},
|
||||
{
|
||||
"name": "Thumb2",
|
||||
"type": "Extension1DependsNothing::Whatever"
|
||||
}
|
||||
],
|
||||
"objectsFolderStructure": {
|
||||
"folderName": "__ROOT",
|
||||
"children": []
|
||||
},
|
||||
"objectsGroups": [],
|
||||
"layers": [],
|
||||
"instances": []
|
||||
},
|
||||
{
|
||||
"areaMaxX": 64,
|
||||
"areaMaxY": 64,
|
||||
"areaMaxZ": 64,
|
||||
"areaMinX": 0,
|
||||
"areaMinY": 0,
|
||||
"areaMinZ": 0,
|
||||
"defaultName": "Joystick",
|
||||
"description": "Joystick for touchscreens.",
|
||||
"fullName": "Multitouch Joystick",
|
||||
"name": "SpriteMultitouchJoystick",
|
||||
"eventsFunctions": [],
|
||||
"propertyDescriptors": [],
|
||||
"objects": [
|
||||
{
|
||||
"name": "Thumb",
|
||||
"type": "OtherExtension::Whatever"
|
||||
},
|
||||
{
|
||||
"name": "Thumb2",
|
||||
"type": "Extension3DependingOn2::Whatever"
|
||||
}
|
||||
],
|
||||
"objectsFolderStructure": {
|
||||
"folderName": "__ROOT",
|
||||
"children": []
|
||||
},
|
||||
"objectsGroups": [],
|
||||
"layers": [],
|
||||
"instances": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"author": "",
|
||||
"category": "Input",
|
||||
"extensionNamespace": "",
|
||||
"fullName": "3D character keyboard mapper",
|
||||
"helpPath": "",
|
||||
"iconUrl": "fake-icon-url",
|
||||
"name": "Extension3DependingOn2",
|
||||
"previewIconUrl": "fake-preview-icon-url",
|
||||
"shortDescription": "3D platformer and 3D shooter keyboard controls.",
|
||||
"version": "1.0.0",
|
||||
"description": "3D platformer and 3D shooter keyboard controls.",
|
||||
"tags": [],
|
||||
"authorIds": [],
|
||||
"dependencies": [],
|
||||
"globalVariables": [],
|
||||
"sceneVariables": [],
|
||||
"eventsFunctions": [],
|
||||
"eventsBasedBehaviors": [],
|
||||
"eventsBasedObjects": [
|
||||
{
|
||||
"areaMaxX": 64,
|
||||
"areaMaxY": 64,
|
||||
"areaMaxZ": 64,
|
||||
"areaMinX": 0,
|
||||
"areaMinY": 0,
|
||||
"areaMinZ": 0,
|
||||
"defaultName": "Joystick",
|
||||
"description": "Joystick for touchscreens.",
|
||||
"fullName": "Multitouch Joystick",
|
||||
"name": "SpriteMultitouchJoystick",
|
||||
"eventsFunctions": [],
|
||||
"propertyDescriptors": [],
|
||||
"objects": [
|
||||
{
|
||||
"name": "Thumb",
|
||||
"type": "OtherExtension::Whatever"
|
||||
},
|
||||
{
|
||||
"name": "Thumb2",
|
||||
"type": "Extension2DependsNothing::Whatever"
|
||||
}
|
||||
],
|
||||
"objectsFolderStructure": {
|
||||
"folderName": "__ROOT",
|
||||
"children": []
|
||||
},
|
||||
"objectsGroups": [],
|
||||
"layers": [],
|
||||
"instances": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"author": "",
|
||||
"category": "Input",
|
||||
"extensionNamespace": "",
|
||||
"fullName": "3D character keyboard mapper",
|
||||
"helpPath": "",
|
||||
"iconUrl": "fake-icon-url",
|
||||
"name": "Extension2DependsNothing",
|
||||
"previewIconUrl": "fake-preview-icon-url",
|
||||
"shortDescription": "3D platformer and 3D shooter keyboard controls.",
|
||||
"version": "1.0.0",
|
||||
"description": "3D platformer and 3D shooter keyboard controls.",
|
||||
"tags": [],
|
||||
"authorIds": [],
|
||||
"dependencies": [],
|
||||
"globalVariables": [],
|
||||
"sceneVariables": [],
|
||||
"eventsFunctions": [],
|
||||
"eventsBasedBehaviors": [],
|
||||
"eventsBasedObjects": []
|
||||
},
|
||||
{
|
||||
"author": "",
|
||||
"category": "Input",
|
||||
"extensionNamespace": "",
|
||||
"fullName": "3D character keyboard mapper",
|
||||
"helpPath": "",
|
||||
"iconUrl": "fake-icon-url",
|
||||
"name": "Extension1DependsNothing",
|
||||
"previewIconUrl": "fake-preview-icon-url",
|
||||
"shortDescription": "3D platformer and 3D shooter keyboard controls.",
|
||||
"version": "1.0.0",
|
||||
"description": "3D platformer and 3D shooter keyboard controls.",
|
||||
"tags": [],
|
||||
"authorIds": [],
|
||||
"dependencies": [],
|
||||
"globalVariables": [],
|
||||
"sceneVariables": [],
|
||||
"eventsFunctions": [],
|
||||
"eventsBasedBehaviors": [],
|
||||
"eventsBasedObjects": []
|
||||
}
|
||||
])");
|
||||
|
||||
std::vector<gd::String> orderedNames =
|
||||
gd::Project::GetUnserializingOrderExtensionNames(extensionsElement);
|
||||
REQUIRE(orderedNames.size() == 4);
|
||||
REQUIRE(orderedNames[0] == "Extension2DependsNothing");
|
||||
REQUIRE(orderedNames[1] == "Extension1DependsNothing");
|
||||
REQUIRE(orderedNames[2] == "Extension3DependingOn2");
|
||||
REQUIRE(orderedNames[3] == "Extension4DependsOn1And3");
|
||||
}
|
||||
}
|
@@ -1,30 +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/CommonTools.h"
|
||||
#include "GDCore/Project/Project.h"
|
||||
#include "GDCore/Project/SourceFile.h"
|
||||
#include "catch.hpp"
|
||||
|
||||
TEST_CASE("SourceFile", "[common]") {
|
||||
SECTION("Basics") {
|
||||
gd::Project project;
|
||||
project.InsertNewSourceFile("test.cpp", "C++");
|
||||
project.InsertNewSourceFile("test.js", "Javascript");
|
||||
REQUIRE(project.HasSourceFile("test.cpp", "C++") == true);
|
||||
REQUIRE(project.HasSourceFile("test.cpp", "JS") == false);
|
||||
REQUIRE(project.HasSourceFile("test.cpp") == true);
|
||||
gd::SourceFile& cppSourceFile = project.GetSourceFile("test.cpp");
|
||||
REQUIRE(cppSourceFile.GetFileName() == "test.cpp");
|
||||
REQUIRE(cppSourceFile.GetLanguage() == "C++");
|
||||
|
||||
project.RemoveSourceFile("test.cpp");
|
||||
REQUIRE(project.HasSourceFile("test.cpp") == false);
|
||||
REQUIRE(project.HasSourceFile("test.js") == true);
|
||||
}
|
||||
}
|
@@ -77,6 +77,65 @@ const gd::String &GetEventFirstActionType(const gd::BaseEvent &event) {
|
||||
return actions.Get(0).GetType();
|
||||
}
|
||||
|
||||
const gd::Instruction &
|
||||
CreateInstructionWithNumberParameter(gd::Project &project,
|
||||
gd::EventsList &events,
|
||||
const gd::String &expression) {
|
||||
gd::StandardEvent &event = dynamic_cast<gd::StandardEvent &>(
|
||||
events.InsertNewEvent(project, "BuiltinCommonInstructions::Standard"));
|
||||
|
||||
gd::Instruction instruction;
|
||||
instruction.SetType("MyExtension::DoSomething");
|
||||
instruction.SetParametersCount(1);
|
||||
instruction.SetParameter(0, expression);
|
||||
return event.GetActions().Insert(instruction);
|
||||
}
|
||||
|
||||
const gd::Instruction &
|
||||
CreateInstructionWithObjectParameter(gd::Project &project,
|
||||
gd::EventsList &events,
|
||||
const gd::String &objectName) {
|
||||
gd::StandardEvent &event = dynamic_cast<gd::StandardEvent &>(
|
||||
events.InsertNewEvent(project, "BuiltinCommonInstructions::Standard"));
|
||||
|
||||
gd::Instruction instruction;
|
||||
instruction.SetType("MyExtension::DoSomethingWithObjects");
|
||||
instruction.SetParametersCount(2);
|
||||
instruction.SetParameter(0, objectName);
|
||||
instruction.SetParameter(1, "");
|
||||
return event.GetActions().Insert(instruction);
|
||||
}
|
||||
|
||||
const gd::Instruction &
|
||||
CreateInstructionWithBehaviorParameter(gd::Project &project,
|
||||
gd::EventsList &events,
|
||||
const gd::String &objectName,
|
||||
const gd::String &behaviorName) {
|
||||
gd::StandardEvent &event = dynamic_cast<gd::StandardEvent &>(
|
||||
events.InsertNewEvent(project, "BuiltinCommonInstructions::Standard"));
|
||||
|
||||
gd::Instruction instruction;
|
||||
instruction.SetType("MyExtension::BehaviorDoSomething");
|
||||
instruction.SetParametersCount(2);
|
||||
instruction.SetParameter(0, objectName);
|
||||
instruction.SetParameter(1, behaviorName);
|
||||
return event.GetActions().Insert(instruction);
|
||||
}
|
||||
|
||||
const gd::Instruction &
|
||||
CreateInstructionWithVariableParameter(gd::Project &project,
|
||||
gd::EventsList &events,
|
||||
const gd::String &expression) {
|
||||
gd::StandardEvent &event = dynamic_cast<gd::StandardEvent &>(
|
||||
events.InsertNewEvent(project, "BuiltinCommonInstructions::Standard"));
|
||||
|
||||
gd::Instruction instruction;
|
||||
instruction.SetType("MyExtension::DoSomethingWithAnyVariable");
|
||||
instruction.SetParametersCount(1);
|
||||
instruction.SetParameter(0, expression);
|
||||
return event.GetActions().Insert(instruction);
|
||||
}
|
||||
|
||||
enum TestEvent {
|
||||
FreeFunctionAction,
|
||||
FreeFunctionWithExpression,
|
||||
@@ -1433,7 +1492,7 @@ TEST_CASE("WholeProjectRefactorer", "[common]") {
|
||||
|
||||
auto &layout = project.GetLayout("Scene");
|
||||
|
||||
// Trigger the refactoring after the renaming of an object
|
||||
// Trigger the refactoring before the renaming of an object
|
||||
gd::WholeProjectRefactorer::ObjectOrGroupRenamedInScene(
|
||||
project, layout, "ObjectWithMyBehavior",
|
||||
"RenamedObjectWithMyBehavior",
|
||||
@@ -1461,7 +1520,7 @@ TEST_CASE("WholeProjectRefactorer", "[common]") {
|
||||
|
||||
auto &layout = project.GetLayout("Scene");
|
||||
|
||||
// Trigger the refactoring after the renaming of a group
|
||||
// Trigger the refactoring before the renaming of a group
|
||||
gd::WholeProjectRefactorer::ObjectOrGroupRenamedInScene(
|
||||
project, layout, "GroupWithMyBehavior", "RenamedGroupWithMyBehavior",
|
||||
/* isObjectGroup=*/true);
|
||||
@@ -1533,16 +1592,17 @@ TEST_CASE("WholeProjectRefactorer", "[common]") {
|
||||
// events in this test.
|
||||
|
||||
// Create the objects container for the events function
|
||||
gd::ObjectsContainer parametersObjectsContainer;
|
||||
gd::ObjectsContainer parametersObjectsContainer(
|
||||
gd::ObjectsContainer::SourceType::Function);
|
||||
auto projectScopedContainers = gd::ProjectScopedContainers::
|
||||
MakeNewProjectScopedContainersForFreeEventsFunction(
|
||||
project, eventsExtension, eventsFunction,
|
||||
parametersObjectsContainer);
|
||||
|
||||
// Trigger the refactoring after the renaming of an object
|
||||
// Trigger the refactoring before the renaming of an object
|
||||
gd::WholeProjectRefactorer::ObjectOrGroupRenamedInEventsFunction(
|
||||
project, projectScopedContainers, eventsFunction,
|
||||
"Object1", "RenamedObject1",
|
||||
parametersObjectsContainer, "Object1", "RenamedObject1",
|
||||
/* isObjectGroup=*/false);
|
||||
|
||||
REQUIRE(objectGroup.Find("Object1") == false);
|
||||
@@ -1561,7 +1621,8 @@ TEST_CASE("WholeProjectRefactorer", "[common]") {
|
||||
eventsExtension.GetEventsFunction("MyOtherEventsFunction");
|
||||
|
||||
// Create the objects container for the events function
|
||||
gd::ObjectsContainer parametersObjectsContainer;
|
||||
gd::ObjectsContainer parametersObjectsContainer(
|
||||
gd::ObjectsContainer::SourceType::Function);
|
||||
auto projectScopedContainers = gd::ProjectScopedContainers::
|
||||
MakeNewProjectScopedContainersForFreeEventsFunction(
|
||||
project, eventsExtension, eventsFunction,
|
||||
@@ -1573,10 +1634,11 @@ TEST_CASE("WholeProjectRefactorer", "[common]") {
|
||||
objectWithMyBehavior.GetVariables().InsertNew("MyVariable");
|
||||
objectWithMyBehavior.GetVariables().InsertNew("MyStructureVariable").CastTo(gd::Variable::Structure);
|
||||
|
||||
// Trigger the refactoring after the renaming of an object
|
||||
// Trigger the refactoring before the renaming of an object
|
||||
gd::WholeProjectRefactorer::ObjectOrGroupRenamedInEventsFunction(
|
||||
project, projectScopedContainers, eventsFunction,
|
||||
"ObjectWithMyBehavior", "RenamedObjectWithMyBehavior",
|
||||
parametersObjectsContainer, "ObjectWithMyBehavior",
|
||||
"RenamedObjectWithMyBehavior",
|
||||
/* isObjectGroup=*/false);
|
||||
|
||||
// Check object name has been renamed in action parameters.
|
||||
@@ -1616,7 +1678,8 @@ TEST_CASE("WholeProjectRefactorer", "[common]") {
|
||||
project, "MyExtension::Sprite", "Object2", 0);
|
||||
|
||||
// Create the objects container for the events function
|
||||
gd::ObjectsContainer parametersObjectsContainer;
|
||||
gd::ObjectsContainer parametersObjectsContainer(
|
||||
gd::ObjectsContainer::SourceType::Function);
|
||||
auto projectScopedContainers = gd::ProjectScopedContainers::
|
||||
MakeNewProjectScopedContainersForEventsBasedObject(
|
||||
project, eventsExtension, eventsBasedObject,
|
||||
@@ -1657,7 +1720,8 @@ TEST_CASE("WholeProjectRefactorer", "[common]") {
|
||||
eventsBasedObject.GetInitialInstances().InsertInitialInstance(instance2);
|
||||
|
||||
// Create the objects container for the events function
|
||||
gd::ObjectsContainer parametersObjectsContainer;
|
||||
gd::ObjectsContainer parametersObjectsContainer(
|
||||
gd::ObjectsContainer::SourceType::Function);
|
||||
auto projectScopedContainers = gd::ProjectScopedContainers::
|
||||
MakeNewProjectScopedContainersForEventsBasedObject(
|
||||
project, eventsExtension, eventsBasedObject,
|
||||
@@ -1683,13 +1747,14 @@ TEST_CASE("WholeProjectRefactorer", "[common]") {
|
||||
.Get("MyOtherEventsBasedObject");
|
||||
|
||||
// Create the objects container for the events function
|
||||
gd::ObjectsContainer parametersObjectsContainer;
|
||||
gd::ObjectsContainer parametersObjectsContainer(
|
||||
gd::ObjectsContainer::SourceType::Function);
|
||||
auto projectScopedContainers = gd::ProjectScopedContainers::
|
||||
MakeNewProjectScopedContainersForEventsBasedObject(
|
||||
project, eventsExtension, eventsBasedObject,
|
||||
parametersObjectsContainer);
|
||||
|
||||
// Trigger the refactoring after the renaming of an object
|
||||
// Trigger the refactoring before the renaming of an object
|
||||
gd::WholeProjectRefactorer::ObjectOrGroupRenamedInEventsBasedObject(
|
||||
project, projectScopedContainers, eventsBasedObject,
|
||||
"ObjectWithMyBehavior", "RenamedObjectWithMyBehavior",
|
||||
@@ -1738,7 +1803,8 @@ TEST_CASE("WholeProjectRefactorer", "[common]") {
|
||||
project, "MyExtension::Sprite", "Object2", 0);
|
||||
|
||||
// Create the objects container for the events function
|
||||
gd::ObjectsContainer parametersObjectsContainer;
|
||||
gd::ObjectsContainer parametersObjectsContainer(
|
||||
gd::ObjectsContainer::SourceType::Function);
|
||||
auto projectScopedContainers = gd::ProjectScopedContainers::
|
||||
MakeNewProjectScopedContainersForEventsBasedObject(
|
||||
project, eventsExtension, eventsBasedObject,
|
||||
@@ -1778,7 +1844,8 @@ TEST_CASE("WholeProjectRefactorer", "[common]") {
|
||||
eventsBasedObject.GetInitialInstances().InsertInitialInstance(instance2);
|
||||
|
||||
// Create the objects container for the events function
|
||||
gd::ObjectsContainer parametersObjectsContainer;
|
||||
gd::ObjectsContainer parametersObjectsContainer(
|
||||
gd::ObjectsContainer::SourceType::Function);
|
||||
auto projectScopedContainers = gd::ProjectScopedContainers::
|
||||
MakeNewProjectScopedContainersForEventsBasedObject(
|
||||
project, eventsExtension, eventsBasedObject,
|
||||
@@ -2206,7 +2273,7 @@ TEST_CASE("WholeProjectRefactorer", "[common]") {
|
||||
.GetObjectType() == "MyRenamedExtension::MyEventsBasedObject");
|
||||
}
|
||||
|
||||
SECTION("(Free) events action renamed") {
|
||||
SECTION("(Free function) events action renamed") {
|
||||
gd::Project project;
|
||||
gd::Platform platform;
|
||||
SetupProjectWithDummyPlatform(project, platform);
|
||||
@@ -2224,7 +2291,7 @@ TEST_CASE("WholeProjectRefactorer", "[common]") {
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("(Free) events expression renamed") {
|
||||
SECTION("(Free function) events expression renamed") {
|
||||
gd::Project project;
|
||||
gd::Platform platform;
|
||||
SetupProjectWithDummyPlatform(project, platform);
|
||||
@@ -2242,7 +2309,7 @@ TEST_CASE("WholeProjectRefactorer", "[common]") {
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("(Free) events expression and condition renamed") {
|
||||
SECTION("(Free function) events expression and condition renamed") {
|
||||
gd::Project project;
|
||||
gd::Platform platform;
|
||||
SetupProjectWithDummyPlatform(project, platform);
|
||||
@@ -2271,7 +2338,239 @@ TEST_CASE("WholeProjectRefactorer", "[common]") {
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("(Free) events action parameter moved") {
|
||||
SECTION("(Free function) number parameter renamed (in expressions)") {
|
||||
gd::Project project;
|
||||
gd::Platform platform;
|
||||
SetupProjectWithDummyPlatform(project, platform);
|
||||
auto &eventsExtension = SetupProjectWithEventsFunctionExtension(project);
|
||||
|
||||
auto &eventsFunction =
|
||||
eventsExtension.InsertNewEventsFunction("MyFreeEventsFunction", 0);
|
||||
eventsFunction.GetParameters()
|
||||
.AddNewParameter("MyParameter")
|
||||
.GetValueTypeMetadata()
|
||||
.SetName("number");
|
||||
auto &instruction = CreateInstructionWithNumberParameter(
|
||||
project, eventsFunction.GetEvents(), "MyParameter");
|
||||
auto &instruction2 = CreateInstructionWithNumberParameter(
|
||||
project, eventsFunction.GetEvents(),
|
||||
"MyExtension::GetVariableAsNumber(MyVariable.MyChild[MyParameter])");
|
||||
|
||||
gd::ObjectsContainer parametersObjectsContainer(
|
||||
gd::ObjectsContainer::SourceType::Function);
|
||||
auto projectScopedContainers = gd::ProjectScopedContainers::
|
||||
MakeNewProjectScopedContainersForFreeEventsFunction(
|
||||
project, eventsExtension, eventsFunction,
|
||||
parametersObjectsContainer);
|
||||
gd::WholeProjectRefactorer::RenameParameter(
|
||||
project, projectScopedContainers, eventsFunction,
|
||||
parametersObjectsContainer, "MyParameter", "MyRenamedParameter");
|
||||
|
||||
REQUIRE(instruction.GetParameter(0).GetPlainString() ==
|
||||
"MyRenamedParameter");
|
||||
REQUIRE(instruction2.GetParameter(0).GetPlainString() ==
|
||||
"MyExtension::GetVariableAsNumber(MyVariable.MyChild[MyRenamedParameter])");
|
||||
}
|
||||
|
||||
SECTION("(Free function) number parameter not renamed (in variable parameter)") {
|
||||
gd::Project project;
|
||||
gd::Platform platform;
|
||||
SetupProjectWithDummyPlatform(project, platform);
|
||||
auto &eventsExtension = SetupProjectWithEventsFunctionExtension(project);
|
||||
|
||||
auto &eventsFunction =
|
||||
eventsExtension.InsertNewEventsFunction("MyFreeEventsFunction", 0);
|
||||
eventsFunction.GetParameters()
|
||||
.AddNewParameter("MyParameter")
|
||||
.GetValueTypeMetadata()
|
||||
.SetName("number");
|
||||
// Parameters can't actually be used in "variable" parameters.
|
||||
auto &instruction = CreateInstructionWithVariableParameter(
|
||||
project, eventsFunction.GetEvents(), "MyParameter");
|
||||
auto &instruction2 = CreateInstructionWithNumberParameter(
|
||||
project, eventsFunction.GetEvents(),
|
||||
"MyExtension::GetVariableAsNumber(MyParameter)");
|
||||
|
||||
gd::ObjectsContainer parametersObjectsContainer(
|
||||
gd::ObjectsContainer::SourceType::Function);
|
||||
auto projectScopedContainers = gd::ProjectScopedContainers::
|
||||
MakeNewProjectScopedContainersForFreeEventsFunction(
|
||||
project, eventsExtension, eventsFunction,
|
||||
parametersObjectsContainer);
|
||||
gd::WholeProjectRefactorer::RenameParameter(
|
||||
project, projectScopedContainers, eventsFunction,
|
||||
parametersObjectsContainer, "MyParameter", "MyRenamedParameter");
|
||||
|
||||
// "variable" parameters are left untouched.
|
||||
REQUIRE(instruction.GetParameter(0).GetPlainString() ==
|
||||
"MyParameter");
|
||||
REQUIRE(instruction2.GetParameter(0).GetPlainString() ==
|
||||
"MyExtension::GetVariableAsNumber(MyParameter)");
|
||||
}
|
||||
|
||||
SECTION("(Free function) object parameter renamed (in expressions)") {
|
||||
gd::Project project;
|
||||
gd::Platform platform;
|
||||
SetupProjectWithDummyPlatform(project, platform);
|
||||
auto &eventsExtension = SetupProjectWithEventsFunctionExtension(project);
|
||||
|
||||
auto &eventsFunction =
|
||||
eventsExtension.InsertNewEventsFunction("MyFreeEventsFunction", 0);
|
||||
eventsFunction.GetParameters()
|
||||
.AddNewParameter("MyObject")
|
||||
.GetValueTypeMetadata()
|
||||
.SetName("objectList")
|
||||
.SetExtraInfo("MyExtension::Sprite");
|
||||
auto &instruction = CreateInstructionWithObjectParameter(
|
||||
project, eventsFunction.GetEvents(), "MyObject");
|
||||
auto &instruction2 = CreateInstructionWithNumberParameter(
|
||||
project, eventsFunction.GetEvents(), "MyObject.GetObjectStringWith1Param(0)");
|
||||
auto &instruction3 = CreateInstructionWithNumberParameter(
|
||||
project, eventsFunction.GetEvents(),
|
||||
"MyExtension::GetVariableAsNumber(MyVariable.MyChild[MyObject.GetObjectStringWith1Param(0)])");
|
||||
|
||||
gd::ObjectsContainer parametersObjectsContainer(
|
||||
gd::ObjectsContainer::SourceType::Function);
|
||||
auto projectScopedContainers = gd::ProjectScopedContainers::
|
||||
MakeNewProjectScopedContainersForFreeEventsFunction(
|
||||
project, eventsExtension, eventsFunction,
|
||||
parametersObjectsContainer);
|
||||
gd::WholeProjectRefactorer::RenameParameter(
|
||||
project, projectScopedContainers, eventsFunction,
|
||||
parametersObjectsContainer, "MyObject", "MyRenamedObject");
|
||||
|
||||
REQUIRE(instruction.GetParameter(0).GetPlainString() ==
|
||||
"MyRenamedObject");
|
||||
REQUIRE(instruction2.GetParameter(0).GetPlainString() ==
|
||||
"MyRenamedObject.GetObjectStringWith1Param(0)");
|
||||
REQUIRE(instruction3.GetParameter(0).GetPlainString() ==
|
||||
"MyExtension::GetVariableAsNumber(MyVariable.MyChild[MyRenamedObject.GetObjectStringWith1Param(0)])");
|
||||
}
|
||||
|
||||
SECTION("(Free function) object parameter not renamed (in variable parameter)") {
|
||||
gd::Project project;
|
||||
gd::Platform platform;
|
||||
SetupProjectWithDummyPlatform(project, platform);
|
||||
auto &eventsExtension = SetupProjectWithEventsFunctionExtension(project);
|
||||
|
||||
auto &eventsFunction =
|
||||
eventsExtension.InsertNewEventsFunction("MyFreeEventsFunction", 0);
|
||||
eventsFunction.GetParameters()
|
||||
.AddNewParameter("MyObject")
|
||||
.GetValueTypeMetadata()
|
||||
.SetName("objectList")
|
||||
.SetExtraInfo("MyExtension::Sprite");
|
||||
// Parameters can't actually be used in "variable" parameters.
|
||||
auto &instruction = CreateInstructionWithVariableParameter(
|
||||
project, eventsFunction.GetEvents(), "MyObject");
|
||||
auto &instruction2 = CreateInstructionWithNumberParameter(
|
||||
project, eventsFunction.GetEvents(),
|
||||
"MyExtension::GetVariableAsNumber(MyObject)");
|
||||
|
||||
gd::ObjectsContainer parametersObjectsContainer(
|
||||
gd::ObjectsContainer::SourceType::Function);
|
||||
auto projectScopedContainers = gd::ProjectScopedContainers::
|
||||
MakeNewProjectScopedContainersForFreeEventsFunction(
|
||||
project, eventsExtension, eventsFunction,
|
||||
parametersObjectsContainer);
|
||||
gd::WholeProjectRefactorer::RenameParameter(
|
||||
project, projectScopedContainers, eventsFunction,
|
||||
parametersObjectsContainer, "MyObject", "MyRenamedObject");
|
||||
|
||||
// "variable" parameters are left untouched.
|
||||
REQUIRE(instruction.GetParameter(0).GetPlainString() ==
|
||||
"MyObject");
|
||||
REQUIRE(instruction2.GetParameter(0).GetPlainString() ==
|
||||
"MyExtension::GetVariableAsNumber(MyObject)");
|
||||
}
|
||||
|
||||
SECTION("(Free function) behavior parameter renamed (in expressions)") {
|
||||
gd::Project project;
|
||||
gd::Platform platform;
|
||||
SetupProjectWithDummyPlatform(project, platform);
|
||||
auto &eventsExtension = SetupProjectWithEventsFunctionExtension(project);
|
||||
|
||||
auto &eventsFunction =
|
||||
eventsExtension.InsertNewEventsFunction("MyFreeEventsFunction", 0);
|
||||
eventsFunction.GetParameters()
|
||||
.AddNewParameter("MyObject")
|
||||
.GetValueTypeMetadata()
|
||||
.SetName("objectList")
|
||||
.SetExtraInfo("MyExtension::Sprite");
|
||||
eventsFunction.GetParameters()
|
||||
.AddNewParameter("MyBehavior")
|
||||
.GetValueTypeMetadata()
|
||||
.SetName("behavior")
|
||||
.SetExtraInfo("MyExtension::MyBehavior");
|
||||
auto &instruction = CreateInstructionWithBehaviorParameter(
|
||||
project, eventsFunction.GetEvents(), "MyObject", "MyBehavior");
|
||||
auto &instruction2 = CreateInstructionWithNumberParameter(
|
||||
project, eventsFunction.GetEvents(), "MyObject.MyBehavior::GetBehaviorStringWith1Param(0)");
|
||||
auto &instruction3 = CreateInstructionWithNumberParameter(
|
||||
project, eventsFunction.GetEvents(),
|
||||
"MyExtension::GetVariableAsNumber(MyVariable.MyChild[MyObject.MyBehavior::GetBehaviorStringWith1Param(0)])");
|
||||
|
||||
gd::ObjectsContainer parametersObjectsContainer(
|
||||
gd::ObjectsContainer::SourceType::Function);
|
||||
auto projectScopedContainers = gd::ProjectScopedContainers::
|
||||
MakeNewProjectScopedContainersForFreeEventsFunction(
|
||||
project, eventsExtension, eventsFunction,
|
||||
parametersObjectsContainer);
|
||||
gd::WholeProjectRefactorer::RenameParameter(
|
||||
project, projectScopedContainers, eventsFunction,
|
||||
parametersObjectsContainer, "MyBehavior", "MyRenamedBehavior");
|
||||
|
||||
REQUIRE(instruction.GetParameter(1).GetPlainString() ==
|
||||
"MyRenamedBehavior");
|
||||
REQUIRE(instruction2.GetParameter(0).GetPlainString() ==
|
||||
"MyObject.MyRenamedBehavior::GetBehaviorStringWith1Param(0)");
|
||||
REQUIRE(instruction3.GetParameter(0).GetPlainString() ==
|
||||
"MyExtension::GetVariableAsNumber(MyVariable.MyChild[MyObject.MyRenamedBehavior::GetBehaviorStringWith1Param(0)])");
|
||||
}
|
||||
|
||||
SECTION("(Free function) behavior parameter not renamed (in variable parameter)") {
|
||||
gd::Project project;
|
||||
gd::Platform platform;
|
||||
SetupProjectWithDummyPlatform(project, platform);
|
||||
auto &eventsExtension = SetupProjectWithEventsFunctionExtension(project);
|
||||
|
||||
auto &eventsFunction =
|
||||
eventsExtension.InsertNewEventsFunction("MyFreeEventsFunction", 0);
|
||||
eventsFunction.GetParameters()
|
||||
.AddNewParameter("MyObject")
|
||||
.GetValueTypeMetadata()
|
||||
.SetName("objectList")
|
||||
.SetExtraInfo("MyExtension::Sprite");
|
||||
eventsFunction.GetParameters()
|
||||
.AddNewParameter("MyBehavior")
|
||||
.GetValueTypeMetadata()
|
||||
.SetName("behavior")
|
||||
.SetExtraInfo("MyExtension::MyBehavior");
|
||||
// Parameters can't actually be used in "variable" parameters.
|
||||
auto &instruction = CreateInstructionWithVariableParameter(
|
||||
project, eventsFunction.GetEvents(), "MyBehavior");
|
||||
auto &instruction2 = CreateInstructionWithNumberParameter(
|
||||
project, eventsFunction.GetEvents(),
|
||||
"MyExtension::GetVariableAsNumber(MyBehavior)");
|
||||
|
||||
gd::ObjectsContainer parametersObjectsContainer(
|
||||
gd::ObjectsContainer::SourceType::Function);
|
||||
auto projectScopedContainers = gd::ProjectScopedContainers::
|
||||
MakeNewProjectScopedContainersForFreeEventsFunction(
|
||||
project, eventsExtension, eventsFunction,
|
||||
parametersObjectsContainer);
|
||||
gd::WholeProjectRefactorer::RenameParameter(
|
||||
project, projectScopedContainers, eventsFunction,
|
||||
parametersObjectsContainer, "MyBehavior", "MyRenamedBehavior");
|
||||
|
||||
// "variable" parameters are left untouched.
|
||||
REQUIRE(instruction.GetParameter(0).GetPlainString() ==
|
||||
"MyBehavior");
|
||||
REQUIRE(instruction2.GetParameter(0).GetPlainString() ==
|
||||
"MyExtension::GetVariableAsNumber(MyBehavior)");
|
||||
}
|
||||
|
||||
SECTION("(Free function) events action parameter moved") {
|
||||
gd::Project project;
|
||||
gd::Platform platform;
|
||||
SetupProjectWithDummyPlatform(project, platform);
|
||||
@@ -2293,7 +2592,7 @@ TEST_CASE("WholeProjectRefactorer", "[common]") {
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("(Free) events expression parameter moved") {
|
||||
SECTION("(Free function) events expression parameter moved") {
|
||||
gd::Project project;
|
||||
gd::Platform platform;
|
||||
SetupProjectWithDummyPlatform(project, platform);
|
||||
@@ -2311,7 +2610,7 @@ TEST_CASE("WholeProjectRefactorer", "[common]") {
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("(Free) events expression and condition parameter moved") {
|
||||
SECTION("(Free function) events expression and condition parameter moved") {
|
||||
gd::Project project;
|
||||
gd::Platform platform;
|
||||
SetupProjectWithDummyPlatform(project, platform);
|
||||
@@ -3038,6 +3337,66 @@ TEST_CASE("WholeProjectRefactorer", "[common]") {
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("(Events based behavior) property renamed (in expressions)") {
|
||||
gd::Project project;
|
||||
gd::Platform platform;
|
||||
SetupProjectWithDummyPlatform(project, platform);
|
||||
auto &eventsExtension = SetupProjectWithEventsFunctionExtension(project);
|
||||
auto &eventsBasedBehavior =
|
||||
eventsExtension.GetEventsBasedBehaviors().Get("MyEventsBasedBehavior");
|
||||
|
||||
auto &behaviorAction =
|
||||
eventsBasedBehavior.GetEventsFunctions().InsertNewEventsFunction(
|
||||
"MyBehaviorEventsFunction", 0);
|
||||
gd::WholeProjectRefactorer::EnsureBehaviorEventsFunctionsProperParameters(
|
||||
eventsExtension, eventsBasedBehavior);
|
||||
auto &instruction = CreateInstructionWithNumberParameter(
|
||||
project, behaviorAction.GetEvents(), "MyProperty");
|
||||
auto &instruction2 = CreateInstructionWithNumberParameter(
|
||||
project, behaviorAction.GetEvents(),
|
||||
"MyExtension::GetVariableAsNumber(MyVariable.MyChild[MyProperty])");
|
||||
|
||||
gd::WholeProjectRefactorer::RenameEventsBasedBehaviorProperty(
|
||||
project, eventsExtension, eventsBasedBehavior, "MyProperty",
|
||||
"MyRenamedProperty");
|
||||
|
||||
REQUIRE(instruction.GetParameter(0).GetPlainString() ==
|
||||
"MyRenamedProperty");
|
||||
REQUIRE(instruction2.GetParameter(0).GetPlainString() ==
|
||||
"MyExtension::GetVariableAsNumber(MyVariable.MyChild[MyRenamedProperty])");
|
||||
}
|
||||
|
||||
SECTION("(Events based behavior) property not renamed (in variable parameter)") {
|
||||
gd::Project project;
|
||||
gd::Platform platform;
|
||||
SetupProjectWithDummyPlatform(project, platform);
|
||||
auto &eventsExtension = SetupProjectWithEventsFunctionExtension(project);
|
||||
auto &eventsBasedBehavior =
|
||||
eventsExtension.GetEventsBasedBehaviors().Get("MyEventsBasedBehavior");
|
||||
|
||||
auto &behaviorAction =
|
||||
eventsBasedBehavior.GetEventsFunctions().InsertNewEventsFunction(
|
||||
"MyBehaviorEventsFunction", 0);
|
||||
gd::WholeProjectRefactorer::EnsureBehaviorEventsFunctionsProperParameters(
|
||||
eventsExtension, eventsBasedBehavior);
|
||||
// Properties can't actually be used in "variable" parameters.
|
||||
auto &instruction = CreateInstructionWithVariableParameter(
|
||||
project, behaviorAction.GetEvents(), "MyProperty");
|
||||
auto &instruction2 = CreateInstructionWithNumberParameter(
|
||||
project, behaviorAction.GetEvents(),
|
||||
"MyExtension::GetVariableAsNumber(MyProperty)");
|
||||
|
||||
gd::WholeProjectRefactorer::RenameEventsBasedBehaviorProperty(
|
||||
project, eventsExtension, eventsBasedBehavior, "MyProperty",
|
||||
"MyRenamedProperty");
|
||||
|
||||
// "variable" parameters are left untouched.
|
||||
REQUIRE(instruction.GetParameter(0).GetPlainString() ==
|
||||
"MyProperty");
|
||||
REQUIRE(instruction2.GetParameter(0).GetPlainString() ==
|
||||
"MyExtension::GetVariableAsNumber(MyProperty)");
|
||||
}
|
||||
|
||||
SECTION("(Events based behavior) shared property renamed") {
|
||||
gd::Project project;
|
||||
gd::Platform platform;
|
||||
@@ -3089,6 +3448,35 @@ TEST_CASE("WholeProjectRefactorer", "[common]") {
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("(Events based behavior) shared property renamed (in expressions)") {
|
||||
gd::Project project;
|
||||
gd::Platform platform;
|
||||
SetupProjectWithDummyPlatform(project, platform);
|
||||
auto &eventsExtension = SetupProjectWithEventsFunctionExtension(project);
|
||||
auto &eventsBasedBehavior =
|
||||
eventsExtension.GetEventsBasedBehaviors().Get("MyEventsBasedBehavior");
|
||||
|
||||
auto &behaviorAction =
|
||||
eventsBasedBehavior.GetEventsFunctions().InsertNewEventsFunction(
|
||||
"MyBehaviorEventsFunction", 0);
|
||||
gd::WholeProjectRefactorer::EnsureBehaviorEventsFunctionsProperParameters(
|
||||
eventsExtension, eventsBasedBehavior);
|
||||
auto &instruction = CreateInstructionWithNumberParameter(
|
||||
project, behaviorAction.GetEvents(), "MySharedProperty");
|
||||
auto &instruction2 = CreateInstructionWithNumberParameter(
|
||||
project, behaviorAction.GetEvents(),
|
||||
"MyExtension::GetVariableAsNumber(MyVariable.MyChild[MySharedProperty])");
|
||||
|
||||
gd::WholeProjectRefactorer::RenameEventsBasedBehaviorSharedProperty(
|
||||
project, eventsExtension, eventsBasedBehavior, "MySharedProperty",
|
||||
"MyRenamedSharedProperty");
|
||||
|
||||
REQUIRE(instruction.GetParameter(0).GetPlainString() ==
|
||||
"MyRenamedSharedProperty");
|
||||
REQUIRE(instruction2.GetParameter(0).GetPlainString() ==
|
||||
"MyExtension::GetVariableAsNumber(MyVariable.MyChild[MyRenamedSharedProperty])");
|
||||
}
|
||||
|
||||
SECTION("(Events based object) property renamed") {
|
||||
gd::Project project;
|
||||
gd::Platform platform;
|
||||
@@ -3118,6 +3506,66 @@ TEST_CASE("WholeProjectRefactorer", "[common]") {
|
||||
"MyCustomObject.PropertyMyRenamedProperty()");
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("(Events based object) property renamed (in expressions)") {
|
||||
gd::Project project;
|
||||
gd::Platform platform;
|
||||
SetupProjectWithDummyPlatform(project, platform);
|
||||
auto &eventsExtension = SetupProjectWithEventsFunctionExtension(project);
|
||||
auto &eventsBasedObject =
|
||||
eventsExtension.GetEventsBasedObjects().Get("MyEventsBasedObject");
|
||||
|
||||
auto &behaviorAction =
|
||||
eventsBasedObject.GetEventsFunctions().InsertNewEventsFunction(
|
||||
"MyObjectEventsFunction", 0);
|
||||
gd::WholeProjectRefactorer::EnsureObjectEventsFunctionsProperParameters(
|
||||
eventsExtension, eventsBasedObject);
|
||||
auto &instruction = CreateInstructionWithNumberParameter(
|
||||
project, behaviorAction.GetEvents(), "MyProperty");
|
||||
auto &instruction2 = CreateInstructionWithNumberParameter(
|
||||
project, behaviorAction.GetEvents(),
|
||||
"MyExtension::GetVariableAsNumber(MyVariable.MyChild[MyProperty])");
|
||||
|
||||
gd::WholeProjectRefactorer::RenameEventsBasedObjectProperty(
|
||||
project, eventsExtension, eventsBasedObject, "MyProperty",
|
||||
"MyRenamedProperty");
|
||||
|
||||
REQUIRE(instruction.GetParameter(0).GetPlainString() ==
|
||||
"MyRenamedProperty");
|
||||
REQUIRE(instruction2.GetParameter(0).GetPlainString() ==
|
||||
"MyExtension::GetVariableAsNumber(MyVariable.MyChild[MyRenamedProperty])");
|
||||
}
|
||||
|
||||
SECTION("(Events based object) property not renamed (in variable parameter)") {
|
||||
gd::Project project;
|
||||
gd::Platform platform;
|
||||
SetupProjectWithDummyPlatform(project, platform);
|
||||
auto &eventsExtension = SetupProjectWithEventsFunctionExtension(project);
|
||||
auto &eventsBasedObject =
|
||||
eventsExtension.GetEventsBasedObjects().Get("MyEventsBasedObject");
|
||||
|
||||
auto &behaviorAction =
|
||||
eventsBasedObject.GetEventsFunctions().InsertNewEventsFunction(
|
||||
"MyObjectEventsFunction", 0);
|
||||
gd::WholeProjectRefactorer::EnsureObjectEventsFunctionsProperParameters(
|
||||
eventsExtension, eventsBasedObject);
|
||||
// Properties can't actually be used in "variable" parameters.
|
||||
auto &instruction = CreateInstructionWithVariableParameter(
|
||||
project, behaviorAction.GetEvents(), "MyProperty");
|
||||
auto &instruction2 = CreateInstructionWithNumberParameter(
|
||||
project, behaviorAction.GetEvents(),
|
||||
"MyExtension::GetVariableAsNumber(MyProperty)");
|
||||
|
||||
gd::WholeProjectRefactorer::RenameEventsBasedObjectProperty(
|
||||
project, eventsExtension, eventsBasedObject, "MyProperty",
|
||||
"MyRenamedProperty");
|
||||
|
||||
// "variable" parameters are left untouched.
|
||||
REQUIRE(instruction.GetParameter(0).GetPlainString() ==
|
||||
"MyProperty");
|
||||
REQUIRE(instruction2.GetParameter(0).GetPlainString() ==
|
||||
"MyExtension::GetVariableAsNumber(MyProperty)");
|
||||
}
|
||||
}
|
||||
// TODO: Check that this works when behaviors are attached to a child-object.
|
||||
TEST_CASE("WholeProjectRefactorer (FindInvalidRequiredBehaviorProperties)",
|
||||
@@ -4452,13 +4900,14 @@ TEST_CASE("MergeLayers", "[common]") {
|
||||
REQUIRE(initialInstances.GetLayerInstancesCount("My other layer") == 1);
|
||||
}
|
||||
|
||||
// TODO: ideally, a test should also cover objects having `leaderboardId` as property.
|
||||
SECTION("Can rename a leaderboard in scene events") {
|
||||
gd::Project project;
|
||||
gd::Platform platform;
|
||||
SetupProjectWithDummyPlatform(project, platform);
|
||||
|
||||
auto &layout = project.InsertNewLayout("My layout", 0);
|
||||
|
||||
|
||||
gd::StandardEvent &event = dynamic_cast<gd::StandardEvent &>(
|
||||
layout.GetEvents().InsertNewEvent(project, "BuiltinCommonInstructions::Standard"));
|
||||
|
||||
@@ -4468,6 +4917,10 @@ TEST_CASE("MergeLayers", "[common]") {
|
||||
action.SetParameter(0, gd::Expression("\"12345678-9abc-def0-1234-56789abcdef0\""));
|
||||
event.GetActions().Insert(action);
|
||||
|
||||
std::set<gd::String> allLeaderboardIds = gd::WholeProjectRefactorer::FindAllLeaderboardIds(project);
|
||||
REQUIRE(allLeaderboardIds.size() == 1);
|
||||
REQUIRE(allLeaderboardIds.count("12345678-9abc-def0-1234-56789abcdef0") == 1);
|
||||
|
||||
std::map<gd::String, gd::String> leaderboardIdMap;
|
||||
leaderboardIdMap["12345678-9abc-def0-1234-56789abcdef0"] = "87654321-9abc-def0-1234-56789abcdef0";
|
||||
gd::WholeProjectRefactorer::RenameLeaderboards(project, leaderboardIdMap);
|
||||
|
@@ -112,10 +112,25 @@ namespace gdjs {
|
||||
* @return The Z position of the rendered object.
|
||||
*/
|
||||
getDrawableZ(): float {
|
||||
if (this._isUntransformedHitBoxesDirty) {
|
||||
this._updateUntransformedHitBoxes();
|
||||
let minZ = 0;
|
||||
if (this._innerArea) {
|
||||
minZ = this._innerArea.min[2];
|
||||
} else {
|
||||
if (this._isUntransformedHitBoxesDirty) {
|
||||
this._updateUntransformedHitBoxes();
|
||||
}
|
||||
minZ = this._minZ;
|
||||
}
|
||||
const absScaleZ = this.getScaleZ();
|
||||
if (!this._flippedZ) {
|
||||
return this._z + minZ * absScaleZ;
|
||||
} else {
|
||||
return (
|
||||
this._z +
|
||||
(-minZ - this.getUnscaledDepth() + 2 * this.getUnscaledCenterZ()) *
|
||||
absScaleZ
|
||||
);
|
||||
}
|
||||
return this._z + this._minZ;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -238,10 +253,39 @@ namespace gdjs {
|
||||
this.setAngle(gdjs.toDegrees(mesh.rotation.z));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the internal top bound of the object according to its children.
|
||||
*/
|
||||
getInnerAreaMinZ(): number {
|
||||
if (this._innerArea) {
|
||||
return this._innerArea.min[2];
|
||||
}
|
||||
if (this._isUntransformedHitBoxesDirty) {
|
||||
this._updateUntransformedHitBoxes();
|
||||
}
|
||||
return this._minZ;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the internal bottom bound of the object according to its children.
|
||||
*/
|
||||
getInnerAreaMaxZ(): number {
|
||||
if (this._innerArea) {
|
||||
return this._innerArea.max[2];
|
||||
}
|
||||
if (this._isUntransformedHitBoxesDirty) {
|
||||
this._updateUntransformedHitBoxes();
|
||||
}
|
||||
return this._maxZ;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the internal width of the object according to its children.
|
||||
*/
|
||||
getUnscaledDepth(): float {
|
||||
if (this._innerArea) {
|
||||
return this._innerArea.max[2] - this._innerArea.min[2];
|
||||
}
|
||||
if (this._isUntransformedHitBoxesDirty) {
|
||||
this._updateUntransformedHitBoxes();
|
||||
}
|
||||
@@ -280,6 +324,9 @@ namespace gdjs {
|
||||
if (this.hasCustomRotationCenter()) {
|
||||
return this._customCenterZ;
|
||||
}
|
||||
if (this._innerArea) {
|
||||
return (this._innerArea.min[2] + this._innerArea.max[2]) / 2;
|
||||
}
|
||||
if (this._isUntransformedHitBoxesDirty) {
|
||||
this._updateUntransformedHitBoxes();
|
||||
}
|
||||
|
@@ -3231,9 +3231,9 @@ module.exports = {
|
||||
: this._originalDepth / modelDepth;
|
||||
const minScaleRatio = Math.min(widthRatio, heightRatio, depthRatio);
|
||||
if (!Number.isFinite(minScaleRatio)) {
|
||||
this._defaultWidth = modelWidth;
|
||||
this._defaultHeight = modelHeight;
|
||||
this._defaultDepth = modelDepth;
|
||||
this._defaultWidth = this._originalWidth;
|
||||
this._defaultHeight = this._originalHeight;
|
||||
this._defaultDepth = this._originalDepth;
|
||||
} else {
|
||||
if (widthRatio === minScaleRatio) {
|
||||
this._defaultWidth = this._originalWidth;
|
||||
@@ -3274,6 +3274,10 @@ module.exports = {
|
||||
this._defaultDepth = this._originalDepth;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
this._defaultWidth = this._originalWidth;
|
||||
this._defaultHeight = this._originalHeight;
|
||||
this._defaultDepth = this._originalDepth;
|
||||
}
|
||||
|
||||
this._threeObject.add(this._threeModelGroup);
|
||||
|
@@ -110,13 +110,15 @@ namespace gdjs {
|
||||
}
|
||||
|
||||
//Calculate the distances from the window's bounds.
|
||||
const topLeftPixel = this._convertCoords(
|
||||
instanceContainer,
|
||||
layer,
|
||||
this.owner.getDrawableX(),
|
||||
this.owner.getDrawableY(),
|
||||
workingPoint
|
||||
);
|
||||
const topLeftPixel = this._relativeToOriginalWindowSize
|
||||
? [this.owner.getDrawableX(), this.owner.getDrawableY()]
|
||||
: this._convertInverseCoords(
|
||||
instanceContainer,
|
||||
layer,
|
||||
this.owner.getDrawableX(),
|
||||
this.owner.getDrawableY(),
|
||||
workingPoint
|
||||
);
|
||||
|
||||
// Left edge
|
||||
if (this._leftEdgeAnchor === HorizontalAnchor.WindowLeft) {
|
||||
@@ -141,13 +143,18 @@ namespace gdjs {
|
||||
}
|
||||
|
||||
// It's fine to reuse workingPoint as topLeftPixel is no longer used.
|
||||
const bottomRightPixel = this._convertCoords(
|
||||
instanceContainer,
|
||||
layer,
|
||||
this.owner.getDrawableX() + this.owner.getWidth(),
|
||||
this.owner.getDrawableY() + this.owner.getHeight(),
|
||||
workingPoint
|
||||
);
|
||||
const bottomRightPixel = this._relativeToOriginalWindowSize
|
||||
? [
|
||||
this.owner.getDrawableX() + this.owner.getWidth(),
|
||||
this.owner.getDrawableY() + this.owner.getHeight(),
|
||||
]
|
||||
: this._convertInverseCoords(
|
||||
instanceContainer,
|
||||
layer,
|
||||
this.owner.getDrawableX() + this.owner.getWidth(),
|
||||
this.owner.getDrawableY() + this.owner.getHeight(),
|
||||
workingPoint
|
||||
);
|
||||
|
||||
// Right edge
|
||||
if (this._rightEdgeAnchor === HorizontalAnchor.WindowLeft) {
|
||||
@@ -226,17 +233,17 @@ namespace gdjs {
|
||||
}
|
||||
|
||||
// It's fine to reuse workingPoint as topLeftPixel is no longer used.
|
||||
const topLeftCoord = this._convertInverseCoords(
|
||||
const topLeftCoord = this._convertCoords(
|
||||
instanceContainer,
|
||||
layer,
|
||||
leftPixel,
|
||||
topPixel,
|
||||
workingPoint
|
||||
);
|
||||
const left = topLeftCoord[0];
|
||||
const top = topLeftCoord[1];
|
||||
let left = topLeftCoord[0];
|
||||
let top = topLeftCoord[1];
|
||||
|
||||
const bottomRightCoord = this._convertInverseCoords(
|
||||
const bottomRightCoord = this._convertCoords(
|
||||
instanceContainer,
|
||||
layer,
|
||||
rightPixel,
|
||||
|
@@ -34,18 +34,18 @@ module.exports = {
|
||||
extension
|
||||
.addAction(
|
||||
'LoadDialogueFromSceneVariable',
|
||||
_('Load dialogue Tree from a scene variable'),
|
||||
_('Load dialogue tree from a scene variable'),
|
||||
_(
|
||||
'Load a dialogue data object - Yarn json format, stored in a scene variable. Use this command to load all the Dialogue data at the beginning of the game.'
|
||||
'Load a dialogue data object - Yarn JSON format, stored in a scene variable. Use this command to load all the Dialogue data at the beginning of the game.'
|
||||
),
|
||||
_('Load dialogue data from Scene variable _PARAM0_'),
|
||||
_('Load dialogue data from scene variable _PARAM0_'),
|
||||
'',
|
||||
'JsPlatform/Extensions/yarn32.png',
|
||||
'JsPlatform/Extensions/yarn32.png'
|
||||
)
|
||||
.addParameter(
|
||||
'scenevar',
|
||||
_('Scene variable that holds the Yarn Json data'),
|
||||
_('Scene variable that holds the Yarn JSON data'),
|
||||
'',
|
||||
false
|
||||
)
|
||||
@@ -57,11 +57,11 @@ module.exports = {
|
||||
extension
|
||||
.addAction(
|
||||
'LoadDialogueFromJsonFile',
|
||||
_('Load dialogue Tree from a Json File'),
|
||||
_('Load dialogue tree from a JSON file'),
|
||||
_(
|
||||
'Load a dialogue data object - Yarn json format, stored in a Json file. Use this command to load all the Dialogue data at the beginning of the game.'
|
||||
'Load a dialogue data object - Yarn JSON format, stored in a JSON file. Use this command to load all the Dialogue data at the beginning of the game.'
|
||||
),
|
||||
_('Load dialogue data from json file _PARAM1_'),
|
||||
_('Load dialogue data from JSON file _PARAM1_'),
|
||||
'',
|
||||
'JsPlatform/Extensions/yarn32.png',
|
||||
'JsPlatform/Extensions/yarn32.png'
|
||||
@@ -69,7 +69,7 @@ module.exports = {
|
||||
.addCodeOnlyParameter('currentScene', '')
|
||||
.addParameter(
|
||||
'jsonResource',
|
||||
_('Json file that holds the Yarn Json data'),
|
||||
_('JSON file that holds the Yarn JSON data'),
|
||||
'',
|
||||
false
|
||||
)
|
||||
@@ -125,11 +125,11 @@ module.exports = {
|
||||
extension
|
||||
.addAction(
|
||||
'ConfirmSelectOption',
|
||||
_('Confirm selected Option'),
|
||||
_('Confirm selected option'),
|
||||
_(
|
||||
'Set the selected option as confirmed, which will validate it and go forward to the next node. Use other actions to select options (see "select next option" and "Select previous option").'
|
||||
),
|
||||
_('Confirm selected Option'),
|
||||
_('Confirm selected option'),
|
||||
'',
|
||||
'JsPlatform/Extensions/yarn32.png',
|
||||
'JsPlatform/Extensions/yarn32.png'
|
||||
@@ -140,11 +140,11 @@ module.exports = {
|
||||
extension
|
||||
.addAction(
|
||||
'SelectNextOption',
|
||||
_('Select next Option'),
|
||||
_('Select next option'),
|
||||
_(
|
||||
'Select next Option (add 1 to selected option number). Use this when the dialogue line is of type "options" and the player has pressed a button to change selected option.'
|
||||
'Select next option (add 1 to selected option number). Use this when the dialogue line is of type "options" and the player has pressed a button to change selected option.'
|
||||
),
|
||||
_('Select next Option'),
|
||||
_('Select next option'),
|
||||
'',
|
||||
'JsPlatform/Extensions/yarn32.png',
|
||||
'JsPlatform/Extensions/yarn32.png'
|
||||
@@ -155,11 +155,11 @@ module.exports = {
|
||||
extension
|
||||
.addAction(
|
||||
'SelectPreviousOption',
|
||||
_('Select previous Option'),
|
||||
_('Select previous option'),
|
||||
_(
|
||||
'Select previous Option (subtract 1 from selected option number). Use this when the dialogue line is of type "options" and the player has pressed a button to change selected option.'
|
||||
'Select previous option (subtract 1 from selected option number). Use this when the dialogue line is of type "options" and the player has pressed a button to change selected option.'
|
||||
),
|
||||
_('Select previous Option'),
|
||||
_('Select previous option'),
|
||||
'',
|
||||
'JsPlatform/Extensions/yarn32.png',
|
||||
'JsPlatform/Extensions/yarn32.png'
|
||||
@@ -225,8 +225,8 @@ module.exports = {
|
||||
'JsPlatform/Extensions/yarn32.png',
|
||||
'JsPlatform/Extensions/yarn32.png'
|
||||
)
|
||||
.addParameter('string', _('State Variable Name'), '', false)
|
||||
.addParameter('string', _('Variable string value'), '', false)
|
||||
.addParameter('string', _('State variable name'), '', false)
|
||||
.addParameter('string', _('New value'), '', false)
|
||||
.getCodeExtraInformation()
|
||||
.setFunctionName('gdjs.dialogueTree.setVariable');
|
||||
|
||||
@@ -242,8 +242,8 @@ module.exports = {
|
||||
'JsPlatform/Extensions/yarn32.png',
|
||||
'JsPlatform/Extensions/yarn32.png'
|
||||
)
|
||||
.addParameter('string', _('State Variable Name'), '', false)
|
||||
.addParameter('expression', _('Variable number value'), '', true)
|
||||
.addParameter('string', _('State variable name'), '', false)
|
||||
.addParameter('expression', _('New value'), '', true)
|
||||
.getCodeExtraInformation()
|
||||
.setFunctionName('gdjs.dialogueTree.setVariable');
|
||||
|
||||
@@ -259,8 +259,8 @@ module.exports = {
|
||||
'JsPlatform/Extensions/yarn32.png',
|
||||
'JsPlatform/Extensions/yarn32.png'
|
||||
)
|
||||
.addParameter('string', _('State Variable Name'), '', false)
|
||||
.addParameter('trueorfalse', _('Variable boolean value'), '', false)
|
||||
.addParameter('string', _('State variable name'), '', false)
|
||||
.addParameter('trueorfalse', _('New value'), '', false)
|
||||
.getCodeExtraInformation()
|
||||
.setFunctionName('gdjs.dialogueTree.setVariable');
|
||||
|
||||
@@ -336,9 +336,9 @@ module.exports = {
|
||||
extension
|
||||
.addStrExpression(
|
||||
'Option',
|
||||
_('Get the text of an option from an Options line type'),
|
||||
_('Get the text of an option from an options line type'),
|
||||
_(
|
||||
"Get the text of an option from an Options line type, using the option's Number. The numbers start from 0."
|
||||
"Get the text of an option from an options line type, using the option's Number. The numbers start from 0."
|
||||
),
|
||||
'',
|
||||
'JsPlatform/Extensions/yarn32.png'
|
||||
@@ -350,9 +350,9 @@ module.exports = {
|
||||
extension
|
||||
.addStrExpression(
|
||||
'HorizontalOptionsList',
|
||||
_('Get a Horizontal list of options from the Options line type'),
|
||||
_('Get a Horizontal list of options from the options line type'),
|
||||
_(
|
||||
"Get the text of all available options from an Options line type as a horizontal list. You can also pass the selected option's cursor string, which by default is ->"
|
||||
"Get the text of all available options from an options line type as a horizontal list. You can also pass the selected option's cursor string, which by default is ->"
|
||||
),
|
||||
'',
|
||||
'JsPlatform/Extensions/yarn32.png'
|
||||
@@ -365,9 +365,9 @@ module.exports = {
|
||||
extension
|
||||
.addStrExpression(
|
||||
'VerticalOptionsList',
|
||||
_('Get a Vertical list of options from the Options line type'),
|
||||
_('Get a Vertical list of options from the options line type'),
|
||||
_(
|
||||
"Get the text of all available options from an Options line type as a vertical list. You can also pass the selected option's cursor string, which by default is ->"
|
||||
"Get the text of all available options from an options line type as a vertical list. You can also pass the selected option's cursor string, which by default is ->"
|
||||
),
|
||||
'',
|
||||
'JsPlatform/Extensions/yarn32.png'
|
||||
@@ -507,14 +507,26 @@ module.exports = {
|
||||
extension
|
||||
.addExpression(
|
||||
'Variable',
|
||||
_('Get dialogue state value'),
|
||||
_('Get dialogue state value'),
|
||||
_('Get the number stored in a dialogue state variable'),
|
||||
_('Get the number stored in a dialogue state variable'),
|
||||
'',
|
||||
'JsPlatform/Extensions/yarn32.png'
|
||||
)
|
||||
.addParameter('string', _('Variable Name'), '', false)
|
||||
.addParameter('string', _('Dialogue state variable name'), '', false)
|
||||
.getCodeExtraInformation()
|
||||
.setFunctionName('gdjs.dialogueTree.getVariable');
|
||||
.setFunctionName('gdjs.dialogueTree.getVariableAsNumber');
|
||||
|
||||
extension
|
||||
.addStrExpression(
|
||||
'VariableString',
|
||||
_('Get the string stored in a dialogue state variable'),
|
||||
_('Get the string stored in a dialogue state variable'),
|
||||
'',
|
||||
'JsPlatform/Extensions/yarn32.png'
|
||||
)
|
||||
.addParameter('string', _('Dialogue state variable name'), '', false)
|
||||
.getCodeExtraInformation()
|
||||
.setFunctionName('gdjs.dialogueTree.getVariableAsString');
|
||||
|
||||
extension
|
||||
.addCondition(
|
||||
|
39
Extensions/DialogueTree/bondage.js/dist/bondage.d.ts
vendored
Normal file
39
Extensions/DialogueTree/bondage.js/dist/bondage.d.ts
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
declare namespace bondage {
|
||||
export class Runner {
|
||||
yarnNodes: any;
|
||||
variables: any;
|
||||
functions: any;
|
||||
visited: any;
|
||||
load(data: any[]): void;
|
||||
setVariableStorage(storage: any): void;
|
||||
registerFunction(name: string, func): void;
|
||||
run(startNode: string): any;
|
||||
evalNodes(nodes: any[], yarnNodeData: any): any;
|
||||
handleSelections(selections: any[]): any;
|
||||
evaluateAssignment(node: any): any;
|
||||
evaluateConditional(node: any): any;
|
||||
evaluateExpressionOrLiteral(node): any;
|
||||
}
|
||||
|
||||
export class Result {}
|
||||
|
||||
export class TextResult extends Result {
|
||||
text: string;
|
||||
data: any;
|
||||
lineNum: number;
|
||||
}
|
||||
|
||||
export class CommandResult extends Result {
|
||||
text: string;
|
||||
data: any;
|
||||
lineNum: number;
|
||||
}
|
||||
|
||||
export class OptionsResult extends Result {
|
||||
options: string[];
|
||||
lineNum: number[];
|
||||
selected: number;
|
||||
|
||||
select(index: number): void;
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@@ -917,12 +917,12 @@ namespace gdjs {
|
||||
// As we are the host, we do not cancel the message if it times out.
|
||||
shouldCancelMessageIfTimesOut: false,
|
||||
});
|
||||
for (const peerId of otherPeerIds) {
|
||||
debugLogger.info(
|
||||
`Relaying ownership change of variable with Id ${variableNetworkId} to ${peerId}.`
|
||||
);
|
||||
sendDataTo(otherPeerIds, messageName, messageData);
|
||||
}
|
||||
debugLogger.info(
|
||||
`Relaying ownership change of variable with Id ${variableNetworkId} to ${otherPeerIds.join(
|
||||
', '
|
||||
)}.`
|
||||
);
|
||||
sendDataTo(otherPeerIds, messageName, messageData);
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -1361,6 +1361,11 @@ namespace gdjs {
|
||||
// As we are the host, we do not cancel the message if it times out.
|
||||
shouldCancelMessageIfTimesOut: false,
|
||||
});
|
||||
debugLogger.info(
|
||||
`Relaying instance destroyed message for object ${objectName} with instance network ID ${instanceNetworkId} to ${otherPeerIds.join(
|
||||
', '
|
||||
)}.`
|
||||
);
|
||||
sendDataTo(otherPeerIds, messageName, messageData);
|
||||
}
|
||||
});
|
||||
|
@@ -254,6 +254,7 @@ namespace gdjs {
|
||||
// If game is running and the object belongs to a player who is not connected, destroy the object.
|
||||
// As the game may create objects before the lobby game starts, we don't want to destroy them if it's not running.
|
||||
if (
|
||||
this.actionOnPlayerDisconnect !== 'DoNothing' && // Should not delete if flagged as such.
|
||||
this.playerNumber !== 0 && // Host is always connected.
|
||||
!gdjs.multiplayerMessageManager.isPlayerConnected(this.playerNumber)
|
||||
) {
|
||||
|
@@ -340,7 +340,8 @@ module.exports = {
|
||||
_(
|
||||
'The friction applied when touching other objects. The higher the value, the more friction.'
|
||||
)
|
||||
);
|
||||
)
|
||||
.setGroup(_('Movement'));
|
||||
behaviorProperties
|
||||
.getOrCreate('restitution')
|
||||
.setValue(
|
||||
@@ -352,7 +353,8 @@ module.exports = {
|
||||
_(
|
||||
'The "bounciness" of the object. The higher the value, the more other objects will bounce against it.'
|
||||
)
|
||||
);
|
||||
)
|
||||
.setGroup(_('Movement'));
|
||||
behaviorProperties
|
||||
.getOrCreate('linearDamping')
|
||||
.setValue(
|
||||
@@ -695,7 +697,7 @@ module.exports = {
|
||||
.addCondition(
|
||||
'IsDynamic',
|
||||
_('Is dynamic'),
|
||||
_('Test if an object is dynamic.'),
|
||||
_('Check if an object is dynamic.'),
|
||||
_('_PARAM0_ is dynamic'),
|
||||
_('Dynamics'),
|
||||
'res/physics32.png',
|
||||
@@ -727,7 +729,7 @@ module.exports = {
|
||||
.addCondition(
|
||||
'IsStatic',
|
||||
_('Is static'),
|
||||
_('Test if an object is static.'),
|
||||
_('Check if an object is static.'),
|
||||
_('_PARAM0_ is static'),
|
||||
_('Dynamics'),
|
||||
'res/physics32.png',
|
||||
@@ -759,7 +761,7 @@ module.exports = {
|
||||
.addCondition(
|
||||
'IsKinematic',
|
||||
_('Is kinematic'),
|
||||
_('Test if an object is kinematic.'),
|
||||
_('Check if an object is kinematic.'),
|
||||
_('_PARAM0_ is kinematic'),
|
||||
_('Dynamics'),
|
||||
'res/physics32.png',
|
||||
@@ -790,9 +792,9 @@ module.exports = {
|
||||
aut
|
||||
.addCondition(
|
||||
'IsBullet',
|
||||
_('Is treat as bullet'),
|
||||
_('Test if an object is being treat as a bullet.'),
|
||||
_('_PARAM0_ is bullet'),
|
||||
_('Is treated as a bullet'),
|
||||
_('Check if the object is being treated as a bullet.'),
|
||||
_('_PARAM0_ is treated as a bullet'),
|
||||
_('Dynamics'),
|
||||
'res/physics32.png',
|
||||
'res/physics32.png'
|
||||
@@ -825,7 +827,7 @@ module.exports = {
|
||||
.addCondition(
|
||||
'HasFixedRotation',
|
||||
_('Has fixed rotation'),
|
||||
_('Test if an object has fixed rotation.'),
|
||||
_('Check if an object has fixed rotation.'),
|
||||
_('_PARAM0_ has fixed rotation'),
|
||||
_('Dynamics'),
|
||||
'res/physics32.png',
|
||||
@@ -859,7 +861,7 @@ module.exports = {
|
||||
.addCondition(
|
||||
'IsSleepingAllowed',
|
||||
_('Is sleeping allowed'),
|
||||
_('Test if an object can sleep.'),
|
||||
_('Check if an object can sleep.'),
|
||||
_('_PARAM0_ can sleep'),
|
||||
_('Dynamics'),
|
||||
'res/physics32.png',
|
||||
@@ -898,7 +900,7 @@ module.exports = {
|
||||
.addCondition(
|
||||
'IsSleeping',
|
||||
_('Is sleeping'),
|
||||
_('Test if an object is sleeping.'),
|
||||
_('Check if an object is sleeping.'),
|
||||
_('_PARAM0_ is sleeping'),
|
||||
_('Dynamics'),
|
||||
'res/physics32.png',
|
||||
@@ -1267,7 +1269,7 @@ module.exports = {
|
||||
.addCondition(
|
||||
'LayerEnabled',
|
||||
_('Layer enabled'),
|
||||
_('Test if an object has a specific layer enabled.'),
|
||||
_('Check if an object has a specific layer enabled.'),
|
||||
_('_PARAM0_ has layer _PARAM2_ enabled'),
|
||||
_('Filtering'),
|
||||
'res/physics32.png',
|
||||
@@ -1303,7 +1305,7 @@ module.exports = {
|
||||
.addCondition(
|
||||
'MaskEnabled',
|
||||
_('Mask enabled'),
|
||||
_('Test if an object has a specific mask enabled.'),
|
||||
_('Check if an object has a specific mask enabled.'),
|
||||
_('_PARAM0_ has mask _PARAM2_ enabled'),
|
||||
_('Filtering'),
|
||||
'res/physics32.png',
|
||||
@@ -1897,7 +1899,7 @@ module.exports = {
|
||||
.addCondition(
|
||||
'JointFirstObject',
|
||||
_('Joint first object'),
|
||||
_('Test if an object is the first object on a joint.'),
|
||||
_('Check if an object is the first object on a joint.'),
|
||||
_('_PARAM0_ is the first object for joint _PARAM2_'),
|
||||
_('Joints'),
|
||||
'res/physics32.png',
|
||||
@@ -1913,7 +1915,7 @@ module.exports = {
|
||||
.addCondition(
|
||||
'JointSecondObject',
|
||||
_('Joint second object'),
|
||||
_('Test if an object is the second object on a joint.'),
|
||||
_('Check if an object is the second object on a joint.'),
|
||||
_('_PARAM0_ is the second object for joint _PARAM2_'),
|
||||
_('Joints'),
|
||||
'res/physics32.png',
|
||||
@@ -2382,7 +2384,7 @@ module.exports = {
|
||||
.addCondition(
|
||||
'RevoluteJointLimitsEnabled',
|
||||
_('Revolute joint limits enabled'),
|
||||
_('Test if a revolute joint limits are enabled.'),
|
||||
_('Check if a revolute joint limits are enabled.'),
|
||||
_('Limits for revolute joint _PARAM2_ are enabled'),
|
||||
_('Joints/Revolute'),
|
||||
'JsPlatform/Extensions/revolute_joint24.png',
|
||||
@@ -2461,7 +2463,7 @@ module.exports = {
|
||||
.addCondition(
|
||||
'RevoluteJointMotorEnabled',
|
||||
_('Revolute joint motor enabled'),
|
||||
_('Test if a revolute joint motor is enabled.'),
|
||||
_('Check if a revolute joint motor is enabled.'),
|
||||
_('Motor of revolute joint _PARAM2_ is enabled'),
|
||||
_('Joints/Revolute'),
|
||||
'JsPlatform/Extensions/revolute_joint24.png',
|
||||
@@ -2700,7 +2702,7 @@ module.exports = {
|
||||
.addCondition(
|
||||
'PrismaticJointLimitsEnabled',
|
||||
_('Prismatic joint limits enabled'),
|
||||
_('Test if a prismatic joint limits are enabled.'),
|
||||
_('Check if a prismatic joint limits are enabled.'),
|
||||
_('Limits for prismatic joint _PARAM2_ are enabled'),
|
||||
_('Joints/Prismatic'),
|
||||
'JsPlatform/Extensions/prismatic_joint24.png',
|
||||
@@ -2779,7 +2781,7 @@ module.exports = {
|
||||
.addCondition(
|
||||
'PrismaticJointMotorEnabled',
|
||||
_('Prismatic joint motor enabled'),
|
||||
_('Test if a prismatic joint motor is enabled.'),
|
||||
_('Check if a prismatic joint motor is enabled.'),
|
||||
_('Motor for prismatic joint _PARAM2_ is enabled'),
|
||||
_('Joints/Prismatic'),
|
||||
'JsPlatform/Extensions/prismatic_joint24.png',
|
||||
@@ -3459,7 +3461,7 @@ module.exports = {
|
||||
.addCondition(
|
||||
'WheelJointMotorEnabled',
|
||||
_('Wheel joint motor enabled'),
|
||||
_('Test if a wheel joint motor is enabled.'),
|
||||
_('Check if a wheel joint motor is enabled.'),
|
||||
_('Motor for wheel joint _PARAM2_ is enabled'),
|
||||
_('Joints/Wheel'),
|
||||
'JsPlatform/Extensions/wheel_joint24.png',
|
||||
@@ -4203,7 +4205,7 @@ module.exports = {
|
||||
.getCodeExtraInformation()
|
||||
.addIncludeFile('Extensions/Physics2Behavior/physics2tools.js')
|
||||
.addIncludeFile('Extensions/Physics2Behavior/physics2runtimebehavior.js')
|
||||
.setFunctionName('gdjs.physics2.objectsCollide');
|
||||
.setFunctionName('gdjs.physics2.areObjectsColliding');
|
||||
|
||||
extension
|
||||
.addCondition(
|
||||
|
@@ -35,19 +35,23 @@ namespace gdjs {
|
||||
invScaleX: float;
|
||||
/** @deprecated Use `worldInvScale` instead */
|
||||
invScaleY: float;
|
||||
|
||||
timeStep: float;
|
||||
frameTime: float = 0;
|
||||
stepped: boolean = false;
|
||||
timeScale: float = 1;
|
||||
|
||||
world: Box2D.b2World;
|
||||
staticBody: Box2D.b2Body;
|
||||
|
||||
/** Contact listener to keep track of current collisions */
|
||||
contactListener: Box2D.JSContactListener;
|
||||
_nextJointId: number = 1;
|
||||
|
||||
/** Start with 1 so the user is safe from default variables value (0) */
|
||||
joints: { [key: string]: Box2D.b2Joint } = {};
|
||||
/** Avoid creating new vectors all the time */
|
||||
_tempb2Vec2 = new Box2D.b2Vec2(0, 0);
|
||||
/** Sometimes two vectors are needed on the same function call */
|
||||
_tempb2Vec2Sec = new Box2D.b2Vec2(0, 0);
|
||||
|
||||
/**
|
||||
* List of physics behavior in the runtimeScene. It should be updated
|
||||
@@ -68,9 +72,7 @@ namespace gdjs {
|
||||
sharedData.worldScale || Math.sqrt(this.scaleX * this.scaleY);
|
||||
this.worldInvScale = 1 / this.worldScale;
|
||||
this.timeStep = 1 / 60;
|
||||
this.world = new Box2D.b2World(
|
||||
new Box2D.b2Vec2(this.gravityX, this.gravityY)
|
||||
);
|
||||
this.world = new Box2D.b2World(this.b2Vec2(this.gravityX, this.gravityY));
|
||||
this.world.SetAutoClearForces(false);
|
||||
this.staticBody = this.world.CreateBody(new Box2D.b2BodyDef());
|
||||
this.contactListener = new Box2D.JSContactListener();
|
||||
@@ -135,6 +137,13 @@ namespace gdjs {
|
||||
this.world.SetContactListener(this.contactListener);
|
||||
}
|
||||
|
||||
b2Vec2(x: float, y: float): Box2D.b2Vec2 {
|
||||
const tempb2Vec2 = this._tempb2Vec2;
|
||||
tempb2Vec2.set_x(x);
|
||||
tempb2Vec2.set_y(y);
|
||||
return tempb2Vec2;
|
||||
}
|
||||
|
||||
// (string)jointId -> (b2Joint)b2Joint
|
||||
static getSharedData(
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
@@ -169,27 +178,16 @@ namespace gdjs {
|
||||
this._registeredBehaviors.delete(physicsBehavior);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset all contactsStartedThisFrame and contactsEndedThisFrame of all
|
||||
* registered physics behavior.
|
||||
*/
|
||||
resetStartedAndEndedCollisions(): void {
|
||||
step(deltaTime: float): void {
|
||||
// Reset started and ended contacts array for all physics instances.
|
||||
for (const physicsBehavior of this._registeredBehaviors) {
|
||||
physicsBehavior.contactsStartedThisFrame.length = 0;
|
||||
physicsBehavior.contactsEndedThisFrame.length = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update all registered body.
|
||||
*/
|
||||
updateBodiesFromObjects(): void {
|
||||
for (const physicsBehavior of this._registeredBehaviors) {
|
||||
physicsBehavior.updateBodyFromObject();
|
||||
}
|
||||
}
|
||||
|
||||
step(deltaTime: float): void {
|
||||
this.frameTime += deltaTime;
|
||||
// `frameTime` can take negative values.
|
||||
// It's better to be a bit early rather than skipping a frame and being
|
||||
@@ -207,6 +205,13 @@ namespace gdjs {
|
||||
}
|
||||
this.world.ClearForces();
|
||||
this.stepped = true;
|
||||
|
||||
// It's important that updateBodyFromObject and updateObjectFromBody are
|
||||
// called at the same time because other behavior may move the object in
|
||||
// their doStepPreEvents.
|
||||
for (const physicsBehavior of this._registeredBehaviors) {
|
||||
physicsBehavior.updateObjectFromBody();
|
||||
}
|
||||
}
|
||||
|
||||
clearBodyJoints(body: Box2D.b2Body): void {
|
||||
@@ -300,14 +305,11 @@ namespace gdjs {
|
||||
}
|
||||
}
|
||||
gdjs.registerRuntimeSceneUnloadedCallback(function (runtimeScene) {
|
||||
if (
|
||||
// @ts-ignore
|
||||
runtimeScene.physics2SharedData &&
|
||||
// @ts-ignore
|
||||
runtimeScene.physics2SharedData.world
|
||||
) {
|
||||
// @ts-ignore
|
||||
Box2D.destroy(runtimeScene.physics2SharedData.world);
|
||||
const physics2SharedData = runtimeScene.physics2SharedData;
|
||||
if (physics2SharedData && physics2SharedData.world) {
|
||||
Box2D.destroy(physics2SharedData.world);
|
||||
Box2D.destroy(physics2SharedData._tempb2Vec2);
|
||||
Box2D.destroy(physics2SharedData._tempb2Vec2Sec);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -358,8 +360,6 @@ namespace gdjs {
|
||||
currentContacts: Array<Physics2RuntimeBehavior>;
|
||||
destroyedDuringFrameLogic: boolean;
|
||||
_body: Box2D.b2Body | null = null;
|
||||
/** Avoid creating new vectors all the time */
|
||||
_tempb2Vec2: Box2D.b2Vec2;
|
||||
|
||||
/**
|
||||
* sharedData is a reference to the shared data of the scene, that registers
|
||||
@@ -367,8 +367,6 @@ namespace gdjs {
|
||||
* before stepping the world.
|
||||
*/
|
||||
_sharedData: Physics2SharedData;
|
||||
/** Sometimes two vectors are needed on the same function call */
|
||||
_tempb2Vec2Sec: Box2D.b2Vec2;
|
||||
|
||||
_objectOldX: number = 0;
|
||||
_objectOldY: number = 0;
|
||||
@@ -414,22 +412,22 @@ namespace gdjs {
|
||||
instanceContainer.getScene(),
|
||||
behaviorData.name
|
||||
);
|
||||
this._tempb2Vec2 = new Box2D.b2Vec2();
|
||||
this._tempb2Vec2Sec = new Box2D.b2Vec2();
|
||||
this._sharedData.addToBehaviorsList(this);
|
||||
}
|
||||
|
||||
// Stores a Box2D pointer of created vertices
|
||||
b2Vec2(x: float, y: float): Box2D.b2Vec2 {
|
||||
this._tempb2Vec2.set_x(x);
|
||||
this._tempb2Vec2.set_y(y);
|
||||
return this._tempb2Vec2;
|
||||
const tempb2Vec2 = this._sharedData._tempb2Vec2;
|
||||
tempb2Vec2.set_x(x);
|
||||
tempb2Vec2.set_y(y);
|
||||
return tempb2Vec2;
|
||||
}
|
||||
|
||||
b2Vec2Sec(x: float, y: float): Box2D.b2Vec2 {
|
||||
this._tempb2Vec2Sec.set_x(x);
|
||||
this._tempb2Vec2Sec.set_y(y);
|
||||
return this._tempb2Vec2Sec;
|
||||
const tempb2Vec2Sec = this._sharedData._tempb2Vec2Sec;
|
||||
tempb2Vec2Sec.set_x(x);
|
||||
tempb2Vec2Sec.set_y(y);
|
||||
return tempb2Vec2Sec;
|
||||
}
|
||||
|
||||
updateFromBehaviorData(oldBehaviorData, newBehaviorData): boolean {
|
||||
@@ -678,16 +676,18 @@ namespace gdjs {
|
||||
// Average radius from width and height
|
||||
if (this.shapeDimensionA > 0) {
|
||||
shape.set_m_radius(
|
||||
this.shapeDimensionA *
|
||||
Math.max(0.1, this.shapeDimensionA) *
|
||||
this.shapeScale *
|
||||
this._sharedData.worldInvScale
|
||||
);
|
||||
} else {
|
||||
const radius =
|
||||
(this.owner.getWidth() * this._sharedData.worldInvScale +
|
||||
this.owner.getHeight() * this._sharedData.worldInvScale) /
|
||||
(Math.max(0.1, this.owner.getWidth()) *
|
||||
this._sharedData.worldInvScale +
|
||||
Math.max(0.1, this.owner.getHeight()) *
|
||||
this._sharedData.worldInvScale) /
|
||||
4;
|
||||
shape.set_m_radius(radius > 0 ? radius : 1);
|
||||
shape.set_m_radius(radius);
|
||||
}
|
||||
|
||||
// Set the offset
|
||||
@@ -701,11 +701,11 @@ namespace gdjs {
|
||||
!this.polygon ||
|
||||
!Physics2RuntimeBehavior.isPolygonConvex(this.polygon)
|
||||
) {
|
||||
let width =
|
||||
(this.owner.getWidth() > 0 ? this.owner.getWidth() : 1) *
|
||||
const width =
|
||||
Math.max(0.1, this.owner.getWidth()) *
|
||||
this._sharedData.worldInvScale;
|
||||
let height =
|
||||
(this.owner.getHeight() > 0 ? this.owner.getHeight() : 1) *
|
||||
const height =
|
||||
Math.max(0.1, this.owner.getHeight()) *
|
||||
this._sharedData.worldInvScale;
|
||||
|
||||
// Set the shape box
|
||||
@@ -775,14 +775,12 @@ namespace gdjs {
|
||||
// Length from the custom dimension or from the object width
|
||||
const length =
|
||||
(this.shapeDimensionA > 0
|
||||
? this.shapeDimensionA * this.shapeScale
|
||||
: this.owner.getWidth() > 0
|
||||
? this.owner.getWidth()
|
||||
: 1) * this._sharedData.worldInvScale;
|
||||
let height =
|
||||
this.owner.getHeight() > 0
|
||||
? this.owner.getHeight() * this._sharedData.worldInvScale
|
||||
: 0;
|
||||
? Math.max(0.1, this.shapeDimensionA * this.shapeScale)
|
||||
: Math.max(0.1, this.owner.getWidth())) *
|
||||
this._sharedData.worldInvScale;
|
||||
const height =
|
||||
Math.max(0.1, this.owner.getHeight()) *
|
||||
this._sharedData.worldInvScale;
|
||||
|
||||
// Angle from custom dimension, otherwise is 0
|
||||
const angle = this.shapeDimensionB
|
||||
@@ -805,18 +803,16 @@ namespace gdjs {
|
||||
shape = new Box2D.b2PolygonShape();
|
||||
|
||||
// Width and height from custom dimensions or object size
|
||||
let width =
|
||||
const width =
|
||||
(this.shapeDimensionA > 0
|
||||
? this.shapeDimensionA * this.shapeScale
|
||||
: this.owner.getWidth() > 0
|
||||
? this.owner.getWidth()
|
||||
: 1) * this._sharedData.worldInvScale;
|
||||
let height =
|
||||
? Math.max(0.1, this.shapeDimensionA * this.shapeScale)
|
||||
: Math.max(0.1, this.owner.getWidth())) *
|
||||
this._sharedData.worldInvScale;
|
||||
const height =
|
||||
(this.shapeDimensionB > 0
|
||||
? this.shapeDimensionB * this.shapeScale
|
||||
: this.owner.getHeight() > 0
|
||||
? this.owner.getHeight()
|
||||
: 1) * this._sharedData.worldInvScale;
|
||||
? Math.max(0.1, this.shapeDimensionB * this.shapeScale)
|
||||
: Math.max(0.1, this.owner.getHeight())) *
|
||||
this._sharedData.worldInvScale;
|
||||
|
||||
// Set the shape box, the offset must be added here too
|
||||
shape.SetAsBox(
|
||||
@@ -946,20 +942,28 @@ namespace gdjs {
|
||||
!this._sharedData.stepped &&
|
||||
!instanceContainer.getScene().getTimeManager().isFirstFrame()
|
||||
) {
|
||||
// Reset started and ended contacts array for all physics instances.
|
||||
this._sharedData.resetStartedAndEndedCollisions();
|
||||
this._sharedData.updateBodiesFromObjects();
|
||||
this._sharedData.step(
|
||||
instanceContainer.getScene().getTimeManager().getElapsedTime() /
|
||||
1000.0
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
doStepPostEvents(instanceContainer: gdjs.RuntimeInstanceContainer) {
|
||||
// Reset world step to update next frame
|
||||
this._sharedData.stepped = false;
|
||||
}
|
||||
|
||||
onObjectHotReloaded() {
|
||||
this.updateBodyFromObject();
|
||||
}
|
||||
|
||||
updateObjectFromBody() {
|
||||
// Copy transform from body to the GD object.
|
||||
// It's possible the behavior was either deactivated or the object deleted
|
||||
// just before this doStepPreEvents (for example, another behavior deleted
|
||||
// the object during its own doStepPreEvents). If the body is null, we just
|
||||
// don't do anything (but still run the physics simulation - this is independent).
|
||||
// The body is null when the behavior was either deactivated or the object deleted.
|
||||
// It would be useless to try to recreate it as updateBodyFromObject already does it.
|
||||
// If the body is null, we just don't do anything
|
||||
// (but still run the physics simulation - this is independent).
|
||||
if (this._body !== null) {
|
||||
this.owner.setX(
|
||||
this._body.GetPosition().get_x() * this._sharedData.worldScale -
|
||||
@@ -982,15 +986,6 @@ namespace gdjs {
|
||||
this._objectOldAngle = this.owner.getAngle();
|
||||
}
|
||||
|
||||
doStepPostEvents(instanceContainer: gdjs.RuntimeInstanceContainer) {
|
||||
// Reset world step to update next frame
|
||||
this._sharedData.stepped = false;
|
||||
}
|
||||
|
||||
onObjectHotReloaded() {
|
||||
this.updateBodyFromObject();
|
||||
}
|
||||
|
||||
updateBodyFromObject() {
|
||||
// If there is no body, set a new one
|
||||
if (this._body === null) {
|
||||
|
@@ -1,6 +1,6 @@
|
||||
namespace gdjs {
|
||||
export namespace physics2 {
|
||||
export const objectsCollide = function (
|
||||
export const areObjectsColliding = function (
|
||||
objectsLists1: Hashtable<Array<gdjs.RuntimeObject>>,
|
||||
behaviorName: string,
|
||||
objectsLists2: Hashtable<Array<gdjs.RuntimeObject>>,
|
||||
|
2472
Extensions/Physics3DBehavior/JsExtension.js
Normal file
2472
Extensions/Physics3DBehavior/JsExtension.js
Normal file
File diff suppressed because it is too large
Load Diff
1903
Extensions/Physics3DBehavior/Physics3DRuntimeBehavior.ts
Normal file
1903
Extensions/Physics3DBehavior/Physics3DRuntimeBehavior.ts
Normal file
File diff suppressed because it is too large
Load Diff
90
Extensions/Physics3DBehavior/Physics3DTools.ts
Normal file
90
Extensions/Physics3DBehavior/Physics3DTools.ts
Normal file
@@ -0,0 +1,90 @@
|
||||
namespace gdjs {
|
||||
export namespace physics3d {
|
||||
export const areObjectsColliding = function (
|
||||
objectsLists1: Hashtable<Array<gdjs.RuntimeObject>>,
|
||||
behaviorName: string,
|
||||
objectsLists2: Hashtable<Array<gdjs.RuntimeObject>>,
|
||||
behaviorName2: string,
|
||||
inverted: boolean
|
||||
) {
|
||||
return gdjs.evtTools.object.twoListsTest(
|
||||
gdjs.Physics3DRuntimeBehavior.areObjectsColliding,
|
||||
objectsLists1,
|
||||
objectsLists2,
|
||||
inverted,
|
||||
behaviorName
|
||||
);
|
||||
};
|
||||
|
||||
export const haveObjectsStartedColliding = function (
|
||||
objectsLists1: Hashtable<Array<gdjs.RuntimeObject>>,
|
||||
behaviorName: string,
|
||||
objectsLists2: Hashtable<Array<gdjs.RuntimeObject>>,
|
||||
behaviorName2: string,
|
||||
inverted: boolean
|
||||
) {
|
||||
return gdjs.evtTools.object.twoListsTest(
|
||||
gdjs.Physics3DRuntimeBehavior.hasCollisionStartedBetween,
|
||||
objectsLists1,
|
||||
objectsLists2,
|
||||
inverted,
|
||||
behaviorName
|
||||
);
|
||||
};
|
||||
|
||||
export const haveObjectsStoppedColliding = function (
|
||||
objectsLists1: Hashtable<Array<gdjs.RuntimeObject>>,
|
||||
behaviorName: string,
|
||||
objectsLists2: Hashtable<Array<gdjs.RuntimeObject>>,
|
||||
behaviorName2: string,
|
||||
inverted: boolean
|
||||
) {
|
||||
return gdjs.evtTools.object.twoListsTest(
|
||||
gdjs.Physics3DRuntimeBehavior.hasCollisionStoppedBetween,
|
||||
objectsLists1,
|
||||
objectsLists2,
|
||||
inverted,
|
||||
behaviorName
|
||||
);
|
||||
};
|
||||
|
||||
type BehaviorNamePair = { character: string; physics: string };
|
||||
|
||||
const isOnPlatformAdapter = (
|
||||
characterObject: gdjs.RuntimeObject,
|
||||
physicsObject: gdjs.RuntimeObject,
|
||||
behaviorNamePair: BehaviorNamePair
|
||||
): boolean => {
|
||||
const characterBehavior = characterObject.getBehavior(
|
||||
behaviorNamePair.character
|
||||
) as gdjs.PhysicsCharacter3DRuntimeBehavior;
|
||||
const physicsBehavior = physicsObject.getBehavior(
|
||||
behaviorNamePair.physics
|
||||
) as gdjs.Physics3DRuntimeBehavior;
|
||||
if (!characterBehavior || !physicsBehavior) {
|
||||
return false;
|
||||
}
|
||||
return characterBehavior.isOnFloorObject(physicsBehavior);
|
||||
};
|
||||
|
||||
const behaviorNamePair: BehaviorNamePair = { character: '', physics: '' };
|
||||
|
||||
export const isOnPlatform = (
|
||||
characterObjectsLists: Hashtable<Array<gdjs.RuntimeObject>>,
|
||||
characterBehaviorName: string,
|
||||
physicsObjectsLists: Hashtable<Array<gdjs.RuntimeObject>>,
|
||||
physicsBehaviorName: string,
|
||||
inverted: boolean
|
||||
) => {
|
||||
behaviorNamePair.character = characterBehaviorName;
|
||||
behaviorNamePair.physics = physicsBehaviorName;
|
||||
return gdjs.evtTools.object.twoListsTest(
|
||||
isOnPlatformAdapter,
|
||||
characterObjectsLists,
|
||||
physicsObjectsLists,
|
||||
inverted,
|
||||
behaviorNamePair
|
||||
);
|
||||
};
|
||||
}
|
||||
}
|
1550
Extensions/Physics3DBehavior/PhysicsCharacter3DRuntimeBehavior.ts
Normal file
1550
Extensions/Physics3DBehavior/PhysicsCharacter3DRuntimeBehavior.ts
Normal file
File diff suppressed because it is too large
Load Diff
3
Extensions/Physics3DBehavior/README.md
Normal file
3
Extensions/Physics3DBehavior/README.md
Normal file
@@ -0,0 +1,3 @@
|
||||
## Physics 3D Behaviors for GDevelop
|
||||
|
||||
This is the 3D physics engine for GDevelop, based on [Jolt Physics](https://github.com/jrouwe/JoltPhysics.js/) (WebAssembly, version 0.30.0).
|
5152
Extensions/Physics3DBehavior/jolt-physics.d.ts
vendored
Normal file
5152
Extensions/Physics3DBehavior/jolt-physics.d.ts
vendored
Normal file
File diff suppressed because it is too large
Load Diff
2514
Extensions/Physics3DBehavior/jolt-physics.wasm.js
Normal file
2514
Extensions/Physics3DBehavior/jolt-physics.wasm.js
Normal file
File diff suppressed because it is too large
Load Diff
BIN
Extensions/Physics3DBehavior/jolt-physics.wasm.wasm
Normal file
BIN
Extensions/Physics3DBehavior/jolt-physics.wasm.wasm
Normal file
Binary file not shown.
@@ -0,0 +1 @@
|
||||
describe('Physics3DRuntimeBehavior', () => {});
|
@@ -231,9 +231,13 @@ namespace gdjs {
|
||||
...super.getNetworkSyncData(),
|
||||
props: {
|
||||
cs: this._currentSpeed,
|
||||
|
||||
// TODO Try to remove these 3 fields from the synch
|
||||
// They are reset every frame and are not part of the state.
|
||||
rdx: this._requestedDeltaX,
|
||||
rdy: this._requestedDeltaY,
|
||||
ldy: this._lastDeltaY,
|
||||
|
||||
cfs: this._currentFallSpeed,
|
||||
cj: this._canJump,
|
||||
ldl: this._lastDirectionIsLeft,
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user