mirror of
https://github.com/4ian/GDevelop.git
synced 2025-10-15 10:19:04 +00:00
When renaming or removing an object, only refactor associated external events (#5155)
* The editor used to refactor every events that were used in the object layout even if they were associated to another layout which could result to errors.
This commit is contained in:
@@ -1382,25 +1382,12 @@ void WholeProjectRefactorer::ObjectOrGroupRemovedInLayout(
|
||||
|
||||
// Remove object in external events
|
||||
if (removeEventsAndGroups) {
|
||||
DependenciesAnalyzer analyzer(project, layout);
|
||||
if (analyzer.Analyze()) {
|
||||
for (auto& externalEventsName :
|
||||
analyzer.GetExternalEventsDependencies()) {
|
||||
auto& externalEvents = project.GetExternalEvents(externalEventsName);
|
||||
gd::EventsRefactorer::RemoveObjectInEvents(project.GetCurrentPlatform(),
|
||||
project,
|
||||
layout,
|
||||
externalEvents.GetEvents(),
|
||||
objectName);
|
||||
}
|
||||
for (auto& layoutName : analyzer.GetScenesDependencies()) {
|
||||
auto& layout = project.GetLayout(layoutName);
|
||||
gd::EventsRefactorer::RemoveObjectInEvents(project.GetCurrentPlatform(),
|
||||
project,
|
||||
layout,
|
||||
layout.GetEvents(),
|
||||
objectName);
|
||||
}
|
||||
for (auto &externalEventsName :
|
||||
GetAssociatedExternalEvents(project, layout.GetName())) {
|
||||
auto &externalEvents = project.GetExternalEvents(externalEventsName);
|
||||
gd::EventsRefactorer::RemoveObjectInEvents(
|
||||
project.GetCurrentPlatform(), project, layout,
|
||||
externalEvents.GetEvents(), objectName);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1439,26 +1426,12 @@ void WholeProjectRefactorer::ObjectOrGroupRenamedInLayout(
|
||||
}
|
||||
|
||||
// Rename object in external events
|
||||
DependenciesAnalyzer analyzer(project, layout);
|
||||
if (analyzer.Analyze()) {
|
||||
for (auto& externalEventsName : analyzer.GetExternalEventsDependencies()) {
|
||||
auto& externalEvents = project.GetExternalEvents(externalEventsName);
|
||||
gd::EventsRefactorer::RenameObjectInEvents(project.GetCurrentPlatform(),
|
||||
project,
|
||||
layout,
|
||||
externalEvents.GetEvents(),
|
||||
oldName,
|
||||
newName);
|
||||
}
|
||||
for (auto& layoutName : analyzer.GetScenesDependencies()) {
|
||||
auto& layout = project.GetLayout(layoutName);
|
||||
gd::EventsRefactorer::RenameObjectInEvents(project.GetCurrentPlatform(),
|
||||
project,
|
||||
layout,
|
||||
layout.GetEvents(),
|
||||
oldName,
|
||||
newName);
|
||||
}
|
||||
for (auto &externalEventsName :
|
||||
GetAssociatedExternalEvents(project, layout.GetName())) {
|
||||
auto &externalEvents = project.GetExternalEvents(externalEventsName);
|
||||
gd::EventsRefactorer::RenameObjectInEvents(
|
||||
project.GetCurrentPlatform(), project, layout,
|
||||
externalEvents.GetEvents(), oldName, newName);
|
||||
}
|
||||
|
||||
// Rename object in external layouts
|
||||
|
@@ -325,7 +325,7 @@ class GD_CORE_API WholeProjectRefactorer {
|
||||
* \brief Refactor the project after an object is renamed in a layout
|
||||
*
|
||||
* This will update the layout, all external layouts associated with it
|
||||
* and all external events used by the layout.
|
||||
* and all external events associated with it.
|
||||
*/
|
||||
static void ObjectOrGroupRenamedInLayout(gd::Project& project,
|
||||
gd::Layout& layout,
|
||||
@@ -337,7 +337,7 @@ class GD_CORE_API WholeProjectRefactorer {
|
||||
* \brief Refactor the project after an object is removed in a layout
|
||||
*
|
||||
* This will update the layout, all external layouts associated with it
|
||||
* and all external events used by the layout.
|
||||
* and all external events associated with it.
|
||||
*/
|
||||
static void ObjectOrGroupRemovedInLayout(gd::Project& project,
|
||||
gd::Layout& layout,
|
||||
|
@@ -56,6 +56,12 @@ GetEventFirstActionFirstParameterString(const gd::BaseEvent &event) {
|
||||
return actions.Get(0).GetParameter(0).GetPlainString();
|
||||
}
|
||||
|
||||
bool
|
||||
AreActionsEmpty(const gd::BaseEvent &event) {
|
||||
auto &actions = EnsureStandardEvent(event).GetActions();
|
||||
return actions.IsEmpty();
|
||||
}
|
||||
|
||||
const gd::String &GetEventFirstConditionType(const gd::BaseEvent &event) {
|
||||
auto &conditions = EnsureStandardEvent(event).GetConditions();
|
||||
REQUIRE(conditions.IsEmpty() == false);
|
||||
@@ -78,6 +84,8 @@ enum TestEvent {
|
||||
FreeActionWithOperator,
|
||||
FreeFunctionWithObjects,
|
||||
FreeFunctionWithObjectExpression,
|
||||
FreeFunctionWithGroup,
|
||||
FreeFunctionWithObjectExpressionOnGroup,
|
||||
|
||||
BehaviorAction,
|
||||
BehaviorPropertyAction,
|
||||
@@ -107,11 +115,18 @@ enum TestEvent {
|
||||
ObjectActionWithOperator,
|
||||
};
|
||||
|
||||
const std::vector<const gd::EventsList *> GetEventsLists(gd::Project &project) {
|
||||
const std::vector<const gd::EventsList *> GetEventsListsAssociatedToScene(gd::Project &project) {
|
||||
std::vector<const gd::EventsList *> eventLists;
|
||||
auto &scene = project.GetLayout("Scene").GetEvents();
|
||||
auto &externalEvents =
|
||||
project.GetExternalEvents("ExternalEvents").GetEvents();
|
||||
eventLists.push_back(&scene);
|
||||
eventLists.push_back(&externalEvents);
|
||||
return eventLists;
|
||||
}
|
||||
|
||||
const std::vector<const gd::EventsList *> GetEventsListsNotAssociatedToScene(gd::Project &project) {
|
||||
std::vector<const gd::EventsList *> eventLists;
|
||||
auto &eventsExtension = project.GetEventsFunctionsExtension("MyEventsExtension");
|
||||
auto &objectFunctionEvents =
|
||||
eventsExtension
|
||||
@@ -128,14 +143,24 @@ const std::vector<const gd::EventsList *> GetEventsLists(gd::Project &project) {
|
||||
.GetEvents();
|
||||
auto &freeFunctionEvents =
|
||||
eventsExtension.GetEventsFunction("MyOtherEventsFunction").GetEvents();
|
||||
eventLists.push_back(&scene);
|
||||
eventLists.push_back(&externalEvents);
|
||||
eventLists.push_back(&objectFunctionEvents);
|
||||
eventLists.push_back(&behaviorFunctionEvents);
|
||||
eventLists.push_back(&freeFunctionEvents);
|
||||
return eventLists;
|
||||
}
|
||||
|
||||
const std::vector<const gd::EventsList *> GetEventsLists(gd::Project &project) {
|
||||
std::vector<const gd::EventsList *> eventLists;
|
||||
|
||||
for (auto *eventsList : GetEventsListsAssociatedToScene(project)) {
|
||||
eventLists.push_back(eventsList);
|
||||
}
|
||||
for (auto *eventsList : GetEventsListsNotAssociatedToScene(project)) {
|
||||
eventLists.push_back(eventsList);
|
||||
}
|
||||
return eventLists;
|
||||
}
|
||||
|
||||
const void SetupEvents(gd::EventsList &eventList) {
|
||||
|
||||
// Add some free functions usages in events
|
||||
@@ -285,6 +310,38 @@ const void SetupEvents(gd::EventsList &eventList) {
|
||||
event.GetActions().Insert(action);
|
||||
eventList.InsertEvent(event);
|
||||
}
|
||||
|
||||
if (eventList.GetEventsCount() != FreeFunctionWithGroup) {
|
||||
throw std::logic_error("Invalid events setup: " + std::to_string(eventList.GetEventsCount()));
|
||||
}
|
||||
// Create an event referring to a group.
|
||||
{
|
||||
gd::StandardEvent event;
|
||||
gd::Instruction action;
|
||||
action.SetType("MyExtension::DoSomethingWithObjects");
|
||||
action.SetParametersCount(2);
|
||||
action.SetParameter(0, gd::Expression("GroupWithMyBehavior"));
|
||||
action.SetParameter(1, gd::Expression("MyCustomObject"));
|
||||
event.GetActions().Insert(action);
|
||||
eventList.InsertEvent(event);
|
||||
}
|
||||
|
||||
if (eventList.GetEventsCount() != FreeFunctionWithObjectExpressionOnGroup) {
|
||||
throw std::logic_error("Invalid events setup: " + std::to_string(eventList.GetEventsCount()));
|
||||
}
|
||||
// Create an event referring to a group in an expression.
|
||||
{
|
||||
gd::StandardEvent event;
|
||||
gd::Instruction action;
|
||||
action.SetType("MyExtension::DoSomething");
|
||||
action.SetParametersCount(1);
|
||||
action.SetParameter(
|
||||
0,
|
||||
gd::Expression(
|
||||
"GroupWithMyBehavior.GetObjectNumber()"));
|
||||
event.GetActions().Insert(action);
|
||||
eventList.InsertEvent(event);
|
||||
}
|
||||
}
|
||||
|
||||
// Add some events based behavior usages in events
|
||||
@@ -821,7 +878,7 @@ SetupProjectWithEventsFunctionExtension(gd::Project &project) {
|
||||
.SetExtraInfo("MyEventsExtension::MyEventsBasedBehavior"));
|
||||
behaviorAction.GetParameters().push_back(
|
||||
gd::ParameterMetadata()
|
||||
.SetName("OtherObject")
|
||||
.SetName("ObjectWithMyBehavior")
|
||||
.SetType("object")
|
||||
.SetExtraInfo("MyEventsExtension::MyEventsBasedObject"));
|
||||
behaviorAction.GetParameters().push_back(
|
||||
@@ -829,6 +886,8 @@ SetupProjectWithEventsFunctionExtension(gd::Project &project) {
|
||||
.SetName("OtherBehavior")
|
||||
.SetType("behavior")
|
||||
.SetExtraInfo("MyEventsExtension::MyEventsBasedBehavior"));
|
||||
auto &group = behaviorAction.GetObjectGroups().InsertNew("GroupWithMyBehavior");
|
||||
group.AddObject("ObjectWithMyBehavior");
|
||||
|
||||
auto &behaviorExpression =
|
||||
behaviorEventsFunctions
|
||||
@@ -1009,6 +1068,8 @@ SetupProjectWithEventsFunctionExtension(gd::Project &project) {
|
||||
auto &childObject = eventsBasedObject.InsertNewObject(
|
||||
project, "MyExtension::Sprite", "ObjectWithMyBehavior", 0);
|
||||
childObject.AddNewBehavior(project, "MyEventsExtension::MyEventsBasedBehavior", "MyBehavior");
|
||||
auto &group = eventsBasedObject.GetObjectGroups().InsertNew("GroupWithMyBehavior");
|
||||
group.AddObject(childObject.GetName());
|
||||
|
||||
eventsBasedObject.InsertNewObject(
|
||||
project, "MyEventsExtension::MyEventsBasedObject", "MyCustomObject", 1);
|
||||
@@ -1079,6 +1140,8 @@ SetupProjectWithEventsFunctionExtension(gd::Project &project) {
|
||||
.SetName("MyCustomObject")
|
||||
.SetType("object")
|
||||
.SetExtraInfo("MyEventsExtension::MyEventsBasedObject"));
|
||||
auto &group = action.GetObjectGroups().InsertNew("GroupWithMyBehavior");
|
||||
group.AddObject("ObjectWithMyBehavior");
|
||||
}
|
||||
|
||||
// Add some usages in events
|
||||
@@ -1091,6 +1154,8 @@ SetupProjectWithEventsFunctionExtension(gd::Project &project) {
|
||||
auto &object = layout.InsertNewObject(project, "MyExtension::Sprite",
|
||||
"ObjectWithMyBehavior", 0);
|
||||
object.AddNewBehavior(project, "MyEventsExtension::MyEventsBasedBehavior", "MyBehavior");
|
||||
auto &group = layout.GetObjectGroups().InsertNew("GroupWithMyBehavior", 0);
|
||||
group.AddObject("ObjectWithMyBehavior");
|
||||
|
||||
auto &globalObject = project.InsertNewObject(
|
||||
project, "MyExtension::Sprite", "GlobalObjectWithMyBehavior", 0);
|
||||
@@ -1229,6 +1294,29 @@ TEST_CASE("WholeProjectRefactorer", "[common]") {
|
||||
REQUIRE(externalLayout2.GetInitialInstances().HasInstancesOfObject(
|
||||
"GlobalObject1") == false);
|
||||
}
|
||||
|
||||
SECTION("Events") {
|
||||
gd::Project project;
|
||||
gd::Platform platform;
|
||||
SetupProjectWithDummyPlatform(project, platform);
|
||||
auto &eventsExtension = SetupProjectWithEventsFunctionExtension(project);
|
||||
|
||||
auto &layout = project.GetLayout("Scene");
|
||||
|
||||
// Trigger the refactoring after removing an object
|
||||
gd::WholeProjectRefactorer::ObjectOrGroupRemovedInLayout(
|
||||
project, layout, "ObjectWithMyBehavior", /* isObjectGroup=*/false);
|
||||
|
||||
for (auto *eventsList : GetEventsListsAssociatedToScene(project)) {
|
||||
// Check actions with the object in parameters have been removed.
|
||||
REQUIRE(
|
||||
AreActionsEmpty(eventsList->GetEvent(FreeFunctionWithObjects)));
|
||||
|
||||
// Check actions with the object in expressions have been removed.
|
||||
REQUIRE(AreActionsEmpty(
|
||||
eventsList->GetEvent(FreeFunctionWithObjectExpression)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("Object renamed (in layout)") {
|
||||
@@ -1347,7 +1435,7 @@ TEST_CASE("WholeProjectRefactorer", "[common]") {
|
||||
REQUIRE(externalLayout2.GetInitialInstances().HasInstancesOfObject(
|
||||
"GlobalObject3") == true);
|
||||
}
|
||||
|
||||
|
||||
SECTION("Events") {
|
||||
gd::Project project;
|
||||
gd::Platform platform;
|
||||
@@ -1358,57 +1446,145 @@ TEST_CASE("WholeProjectRefactorer", "[common]") {
|
||||
|
||||
// Trigger the refactoring after the renaming of an object
|
||||
gd::WholeProjectRefactorer::ObjectOrGroupRenamedInLayout(
|
||||
project, layout, "ObjectWithMyBehavior", "RenamedObjectWithMyBehavior",
|
||||
project, layout, "ObjectWithMyBehavior",
|
||||
"RenamedObjectWithMyBehavior",
|
||||
/* isObjectGroup=*/false);
|
||||
|
||||
// Check object name has been renamed in action parameters.
|
||||
REQUIRE(GetEventFirstActionFirstParameterString(
|
||||
layout.GetEvents().GetEvent(FreeFunctionWithObjects)) ==
|
||||
"RenamedObjectWithMyBehavior");
|
||||
for (auto *eventsList : GetEventsListsAssociatedToScene(project)) {
|
||||
// Check object name has been renamed in action parameters.
|
||||
REQUIRE(GetEventFirstActionFirstParameterString(eventsList->GetEvent(
|
||||
FreeFunctionWithObjects)) == "RenamedObjectWithMyBehavior");
|
||||
|
||||
// Check object name has been renamed in expressions.
|
||||
REQUIRE(GetEventFirstActionFirstParameterString(
|
||||
layout.GetEvents().GetEvent(FreeFunctionWithObjectExpression)) ==
|
||||
// Check object name has been renamed in expressions.
|
||||
REQUIRE(GetEventFirstActionFirstParameterString(
|
||||
eventsList->GetEvent(FreeFunctionWithObjectExpression)) ==
|
||||
"RenamedObjectWithMyBehavior.GetObjectNumber()");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("Group deleted (in layout)") {
|
||||
SECTION("Events") {
|
||||
gd::Project project;
|
||||
gd::Platform platform;
|
||||
SetupProjectWithDummyPlatform(project, platform);
|
||||
auto &eventsExtension = SetupProjectWithEventsFunctionExtension(project);
|
||||
|
||||
auto &layout = project.GetLayout("Scene");
|
||||
|
||||
// Trigger the refactoring after removing a group
|
||||
gd::WholeProjectRefactorer::ObjectOrGroupRemovedInLayout(
|
||||
project, layout, "GroupWithMyBehavior", /* isObjectGroup=*/true);
|
||||
|
||||
for (auto *eventsList : GetEventsListsAssociatedToScene(project)) {
|
||||
// Check actions with the group in parameters have been removed.
|
||||
REQUIRE(AreActionsEmpty(eventsList->GetEvent(FreeFunctionWithGroup)));
|
||||
|
||||
// Check actions with the group in expressions have been removed.
|
||||
REQUIRE(AreActionsEmpty(
|
||||
eventsList->GetEvent(FreeFunctionWithObjectExpressionOnGroup)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("Group renamed (in layout)") {
|
||||
SECTION("Events") {
|
||||
gd::Project project;
|
||||
gd::Platform platform;
|
||||
SetupProjectWithDummyPlatform(project, platform);
|
||||
auto &eventsExtension = SetupProjectWithEventsFunctionExtension(project);
|
||||
|
||||
auto &layout = project.GetLayout("Scene");
|
||||
|
||||
// Trigger the refactoring after the renaming of a group
|
||||
gd::WholeProjectRefactorer::ObjectOrGroupRenamedInLayout(
|
||||
project, layout, "GroupWithMyBehavior", "RenamedGroupWithMyBehavior",
|
||||
/* isObjectGroup=*/true);
|
||||
|
||||
for (auto *eventsList : GetEventsListsAssociatedToScene(project)) {
|
||||
// Check group name has been renamed in action parameters.
|
||||
REQUIRE(GetEventFirstActionFirstParameterString(eventsList->GetEvent(
|
||||
FreeFunctionWithGroup)) == "RenamedGroupWithMyBehavior");
|
||||
|
||||
// Check group name has been renamed in expressions.
|
||||
REQUIRE(GetEventFirstActionFirstParameterString(eventsList->GetEvent(
|
||||
FreeFunctionWithObjectExpressionOnGroup)) ==
|
||||
"RenamedGroupWithMyBehavior.GetObjectNumber()");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("Object renamed (in events function)") {
|
||||
gd::Project project;
|
||||
gd::Platform platform;
|
||||
SetupProjectWithDummyPlatform(project, platform);
|
||||
auto &eventsExtension =
|
||||
project.InsertNewEventsFunctionsExtension("MyEventsExtension", 0);
|
||||
SECTION("Group") {
|
||||
gd::Project project;
|
||||
gd::Platform platform;
|
||||
SetupProjectWithDummyPlatform(project, platform);
|
||||
auto &eventsExtension =
|
||||
project.InsertNewEventsFunctionsExtension("MyEventsExtension", 0);
|
||||
|
||||
// Add a (free) function with an object group
|
||||
gd::EventsFunction &eventsFunction =
|
||||
eventsExtension.InsertNewEventsFunction("MyEventsFunction", 0);
|
||||
gd::ObjectGroup &objectGroup =
|
||||
eventsFunction.GetObjectGroups().InsertNew("MyGroup", 0);
|
||||
objectGroup.AddObject("Object1");
|
||||
objectGroup.AddObject("Object2");
|
||||
// In theory, we would add the object parameters, but we're not testing
|
||||
// events in this test.
|
||||
// Add a (free) function with an object group
|
||||
gd::EventsFunction &eventsFunction =
|
||||
eventsExtension.InsertNewEventsFunction("MyEventsFunction", 0);
|
||||
gd::ObjectGroup &objectGroup =
|
||||
eventsFunction.GetObjectGroups().InsertNew("MyGroup", 0);
|
||||
objectGroup.AddObject("Object1");
|
||||
objectGroup.AddObject("Object2");
|
||||
// In theory, we would add the object parameters, but we're not testing
|
||||
// events in this test.
|
||||
|
||||
// Create the objects container for the events function
|
||||
gd::ObjectsContainer globalObjectsContainer;
|
||||
gd::ObjectsContainer objectsContainer;
|
||||
gd::ParameterMetadataTools::ParametersToObjectsContainer(
|
||||
project, eventsFunction.GetParameters(), objectsContainer);
|
||||
// (this is strictly not necessary because we're not testing events in this
|
||||
// test)
|
||||
// Create the objects container for the events function
|
||||
gd::ObjectsContainer globalObjectsContainer;
|
||||
gd::ObjectsContainer objectsContainer;
|
||||
gd::ParameterMetadataTools::ParametersToObjectsContainer(
|
||||
project, eventsFunction.GetParameters(), objectsContainer);
|
||||
// (this is strictly not necessary because we're not testing events in
|
||||
// this test)
|
||||
|
||||
// Trigger the refactoring after the renaming of an object
|
||||
gd::WholeProjectRefactorer::ObjectOrGroupRenamedInEventsFunction(
|
||||
project, eventsFunction, globalObjectsContainer, objectsContainer,
|
||||
"Object1", "RenamedObject1",
|
||||
/* isObjectGroup=*/false);
|
||||
// Trigger the refactoring after the renaming of an object
|
||||
gd::WholeProjectRefactorer::ObjectOrGroupRenamedInEventsFunction(
|
||||
project, eventsFunction, globalObjectsContainer, objectsContainer,
|
||||
"Object1", "RenamedObject1",
|
||||
/* isObjectGroup=*/false);
|
||||
|
||||
REQUIRE(objectGroup.Find("Object1") == false);
|
||||
REQUIRE(objectGroup.Find("RenamedObject1") == true);
|
||||
REQUIRE(objectGroup.Find("Object2") == true);
|
||||
REQUIRE(objectGroup.Find("Object1") == false);
|
||||
REQUIRE(objectGroup.Find("RenamedObject1") == true);
|
||||
REQUIRE(objectGroup.Find("Object2") == true);
|
||||
|
||||
// Events are not tested
|
||||
// Events are not tested
|
||||
}
|
||||
|
||||
SECTION("Events") {
|
||||
gd::Project project;
|
||||
gd::Platform platform;
|
||||
SetupProjectWithDummyPlatform(project, platform);
|
||||
auto &eventsExtension = SetupProjectWithEventsFunctionExtension(project);
|
||||
auto &eventsFunction =
|
||||
eventsExtension.GetEventsFunction("MyOtherEventsFunction");
|
||||
|
||||
// Create the objects container for the events function
|
||||
gd::ObjectsContainer globalObjectsContainer;
|
||||
gd::ObjectsContainer objectsContainer;
|
||||
gd::ParameterMetadataTools::ParametersToObjectsContainer(
|
||||
project, eventsFunction.GetParameters(), objectsContainer);
|
||||
|
||||
// Trigger the refactoring after the renaming of an object
|
||||
gd::WholeProjectRefactorer::ObjectOrGroupRenamedInEventsFunction(
|
||||
project, eventsFunction, globalObjectsContainer, objectsContainer,
|
||||
"ObjectWithMyBehavior", "RenamedObjectWithMyBehavior",
|
||||
/* isObjectGroup=*/false);
|
||||
|
||||
// Check object name has been renamed in action parameters.
|
||||
REQUIRE(
|
||||
GetEventFirstActionFirstParameterString(
|
||||
eventsFunction.GetEvents().GetEvent(FreeFunctionWithObjects)) ==
|
||||
"RenamedObjectWithMyBehavior");
|
||||
|
||||
// Check object name has been renamed in expressions.
|
||||
REQUIRE(GetEventFirstActionFirstParameterString(
|
||||
eventsFunction.GetEvents().GetEvent(
|
||||
FreeFunctionWithObjectExpression)) ==
|
||||
"RenamedObjectWithMyBehavior.GetObjectNumber()");
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("Object renamed (in events-based object)") {
|
||||
|
Reference in New Issue
Block a user